Salome HOME
bd3282afc009b3ed7748899b327f4c5118844894
[modules/yacs.git] / src / genericgui / LinkMatrix.cxx
1 // Copyright (C) 2006-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "LinkMatrix.hxx"
21 #include "Scene.hxx"
22 #include "SceneComposedNodeItem.hxx"
23 #include "SceneElementaryNodeItem.hxx"
24 #include "SceneHeaderItem.hxx"
25 #include "SceneHeaderNodeItem.hxx"
26 #include "SceneCtrlPortItem.hxx"
27 #include "SceneLinkItem.hxx"
28 #include "QtGuiContext.hxx"
29 #include "InPort.hxx"
30 #include "OutPort.hxx"
31 #include "Resource.hxx"
32
33 #include <cmath>
34
35 //#define _DEVDEBUG_
36 #include "YacsTrace.hxx"
37
38 using namespace std;
39 using namespace YACS::ENGINE;
40 using namespace YACS::HMI;
41
42 double LNode::distance(const LNode& o) const
43 {
44   int dx = _x -o._x;
45   int dy = _y -o._y;
46   return sqrt(double(dx*dx +dy*dy));
47 }
48
49
50 LinkMatrix::LinkMatrix(SceneComposedNodeItem *bloc): _bloc(bloc)
51 {
52   _im=0;
53   _jm=0;
54   _pas=10;
55   _sxm.clear();
56   _sym.clear();
57   _xm.clear();
58   _ym.clear();
59   _x2i.clear();
60   _y2j.clear();
61   _cost.clear();
62   _context = QtGuiContext::getQtCurrent();
63 }
64
65 LinkMatrix::~LinkMatrix()
66 {
67 }
68
69 void LinkMatrix::compute()
70 {
71   getBoundingBox(_bloc,0);
72   explore(_bloc);        // --- define the boundaries _xm[i] and _ym[j]
73   if (Scene::_addRowCols) addRowCols();
74   _im = _sxm.size();
75   _xm.resize(_im);
76   DEBTRACE("_sxm.size()=" << _im);
77   int i =0;
78   for(std::set<double>::iterator it = _sxm.begin(); it != _sxm.end(); ++it)
79     {
80       _xm[i] = *it;
81       _x2i[*it] = i;
82       DEBTRACE("_xm[" << i << "] = " << _xm[i]);
83       i++;
84     }
85   _jm = _sym.size();
86   _ym.resize(_jm);
87   DEBTRACE("_sym.size()=" << _jm);
88   i =0;
89   for(std::set<double>::iterator it = _sym.begin(); it != _sym.end(); ++it)
90     {
91       _ym[i] = *it;
92       _y2j[*it] = i;
93       DEBTRACE("_ym[" << i << "] = " << _ym[i]);
94       i++;
95     }
96   _cost.resize(_im*_jm);
97   for (int ij=0; ij < _im*_jm; ij++)
98     _cost[ij] = 1;       // --- set the _cost matrix open everywhere (no obstacles)
99   explore(_bloc, true);  // --- fill the cells cost(i,j) with obstacles
100
101   for (int j=0; j<_jm; j++)
102     {
103       char* m = new char[_im+1];
104       for (int i=0; i<_im; i++)
105         if (cost(i,j))
106           m[i] = ' ';
107         else 
108           m[i] = 'X';
109       m[_im] = 0;
110       DEBTRACE(m);
111       delete [] m;
112     }
113 }
114
115 std::pair<int,int> LinkMatrix::cellFrom(YACS::ENGINE::OutPort* outp)
116 {
117   SubjectDataPort* subDP = _context->_mapOfSubjectDataPort[outp];
118   SceneItem* item = _context->_mapOfSceneItem[subDP];
119   QRectF bb = (item->mapToScene(item->boundingRect())).boundingRect();
120   qreal xp = bb.right();
121   qreal yp = (bb.top() + bb.bottom())*0.5;
122   DEBTRACE("xp,yp:"<<xp<<","<<yp);
123   int ifrom = -1;
124   for (int i=0; i<_im-1; i++)
125     if (_xm[i+1] >= xp && xp > _xm[i])
126       {
127         ifrom = i;
128         break;
129       }
130   int jfrom = -1;
131   for (int j=0; j<_jm-1; j++)
132     if (_ym[j+1] >= yp && yp > _ym[j])
133       {
134         jfrom = j;
135         break;
136       }
137   //if ifrom or jfrom == -1 the port is outside the matrix
138   if(ifrom < 0 || jfrom < 0)return pair<int,int>(ifrom,jfrom);
139   while (ifrom < _im && !cost(ifrom,jfrom)) ifrom++;  // --- from point is inside an obstacle
140
141   return pair<int,int>(ifrom,jfrom);
142 }
143
144 std::pair<int,int> LinkMatrix::cellFrom(YACS::ENGINE::OutGate* outp)
145 {
146   SubjectNode* subNode = _context->_mapOfSubjectNode[outp->getNode()];
147   SceneNodeItem* itemNode = dynamic_cast<SceneNodeItem*>(_context->_mapOfSceneItem[subNode]);
148   YASSERT(itemNode);
149   SceneHeaderNodeItem* itemHeader = dynamic_cast<SceneHeaderNodeItem*>(itemNode->getHeader());
150   YASSERT(itemHeader);
151   SceneCtrlPortItem *item = itemHeader->getCtrlOutPortItem();
152   YASSERT(item);
153   QRectF bb = (item->mapToScene(item->boundingRect())).boundingRect();
154   qreal xp = bb.right();
155   qreal yp = (bb.top() + bb.bottom())*0.5;
156   DEBTRACE("xp,yp:"<<xp<<","<<yp);
157   int ifrom = -1;
158   for (int i=0; i<_im-1; i++)
159     if (_xm[i+1] >= xp && xp > _xm[i])
160       {
161         ifrom = i;
162         break;
163       }
164   int jfrom = -1;
165   for (int j=0; j<_jm-1; j++)
166     if (_ym[j+1] >= yp && yp > _ym[j])
167       {
168         jfrom = j;
169         break;
170       }
171   //if ifrom or jfrom == -1 the port is outside the matrix
172   if(ifrom < 0 || jfrom < 0)return pair<int,int>(ifrom,jfrom);
173   while (ifrom < _im && !cost(ifrom,jfrom)) ifrom++;  // --- from point is inside an obstacle
174
175   return pair<int,int>(ifrom,jfrom);
176 }
177
178 std::pair<int,int> LinkMatrix::cellTo(YACS::ENGINE::InPort* inp)
179 {
180   SubjectDataPort* subDP = _context->_mapOfSubjectDataPort[inp];
181   SceneItem* item = _context->_mapOfSceneItem[subDP];
182   QRectF bb = (item->mapToScene(item->boundingRect())).boundingRect();
183   qreal xp = bb.left();
184   qreal yp = (bb.top() + bb.bottom())*0.5;
185   DEBTRACE("xp,yp:"<<xp<<","<<yp);
186   int ito = -1;
187   for (int i=0; i<_im-1; i++)
188     if (_xm[i+1] >= xp && xp > _xm[i])
189       {
190         ito = i;
191         break;
192       }
193   int jto = -1;
194   for (int j=0; j<_jm-1; j++)
195     if (_ym[j+1] >= yp && yp > _ym[j])
196       {
197         jto = j;
198         break;
199       }
200   //if ito or jto == -1 the port is outside the matrix
201   if(ito < 0 || jto < 0)return pair<int,int>(ito,jto);
202   while (ito >0 && !cost(ito,jto)) ito--;  // --- to point is inside an obstacle
203
204   return pair<int,int>(ito,jto);
205 }
206
207 std::pair<int,int> LinkMatrix::cellTo(YACS::ENGINE::InGate* inp)
208 {
209   SubjectNode* subNode = _context->_mapOfSubjectNode[inp->getNode()];
210   SceneNodeItem* itemNode = dynamic_cast<SceneNodeItem*>(_context->_mapOfSceneItem[subNode]);
211   YASSERT(itemNode);
212   SceneHeaderNodeItem* itemHeader = dynamic_cast<SceneHeaderNodeItem*>(itemNode->getHeader());
213   YASSERT(itemHeader);
214   SceneCtrlPortItem *item = itemHeader->getCtrlInPortItem();
215   YASSERT(item);
216   QRectF bb = (item->mapToScene(item->boundingRect())).boundingRect();
217   qreal xp = bb.left();
218   qreal yp = (bb.top() + bb.bottom())*0.5;
219   DEBTRACE("xp,yp:"<<xp<<","<<yp);
220   int ito = -1;
221   for (int i=0; i<_im-1; i++)
222     if (_xm[i+1] >= xp && xp > _xm[i])
223       {
224         ito = i;
225         break;
226       }
227   int jto = -1;
228   for (int j=0; j<_jm-1; j++)
229     if (_ym[j+1] >= yp && yp > _ym[j])
230       {
231         jto = j;
232         break;
233       }
234   //if ito or jto == -1 the port is outside the matrix
235   if(ito < 0 || jto < 0)return pair<int,int>(ito,jto);
236   while (ito > 0 && !cost(ito,jto)) ito--;  // --- to point is inside an obstacle
237
238   return pair<int,int>(ito,jto);
239 }
240
241 std::list<linkdef> LinkMatrix::getListOfCtrlLinkDef()
242 {
243   list<linkdef> alist;
244   map<pair<Node*, Node*>, SubjectControlLink*>::const_iterator it;
245   for (it = _context->_mapOfSubjectControlLink.begin();
246        it != _context->_mapOfSubjectControlLink.end(); ++it)
247     {
248       linkdef ali;
249       pair<Node*, Node*> outin = it->first;
250       SubjectControlLink* sub = it->second;
251       ali.from = cellFrom(outin.first->getOutGate());
252       ali.to = cellTo(outin.second->getInGate());
253       ali.item = dynamic_cast<SceneLinkItem*>(_context->_mapOfSceneItem[sub]);
254       alist.push_back(ali);
255       DEBTRACE("from("<<ali.from.first<<","<<ali.from.second
256                <<") to ("<<ali.to.first<<","<<ali.to.second
257                <<") " << ali.item->getLabel().toStdString());
258     }
259   return alist;
260 }
261
262 std::list<linkdef> LinkMatrix::getListOfDataLinkDef()
263 {
264   list<linkdef> alist;
265   map<pair<OutPort*, InPort*>, SubjectLink*>::const_iterator it;
266   for (it = _context->_mapOfSubjectLink.begin();
267        it != _context->_mapOfSubjectLink.end(); ++it)
268     {
269       linkdef ali;
270       pair<OutPort*, InPort*> outin = it->first;
271       SubjectLink* sub = it->second;
272       ali.from = cellFrom(outin.first);
273       ali.to = cellTo(outin.second);
274       ali.item = dynamic_cast<SceneLinkItem*>(_context->_mapOfSceneItem[sub]);
275       alist.push_back(ali);
276       DEBTRACE("from("<<ali.from.first<<","<<ali.from.second
277                <<") to ("<<ali.to.first<<","<<ali.to.second
278                <<") " << ali.item->getLabel().toStdString());
279     }
280   return alist;
281 }
282
283 LinkPath LinkMatrix::getPath(LNodePath lnp)
284 {
285   DEBTRACE("LinkMatrix::getPath " << lnp.size());
286   LinkPath lp;
287   lp.clear();
288   int dim = lnp.size();  
289   //use a random coefficient between 0.25 and 0.75 to try to separate links
290   double coef=-0.25+rand()%101*0.005;
291   coef=0.5 + coef* Resource::link_separation_weight/10.;
292   LNodePath::const_iterator it = lnp.begin();
293   for (int k=0; k<dim; k++)
294     {
295       int i = it->getX();
296       int j = it->getY();
297       DEBTRACE("i, j: " << i << " " << j << " Xmax, Ymax: " << _im << " " << _jm);
298       linkPoint a;
299
300       if ( (i+1)==_im ) {
301         a.x = _xm[i];
302       } else {
303         a.x = coef*_xm[i] + (1.-coef)*_xm[i+1];
304       };
305
306       if ( (j+1)==_jm ) {
307         a.y = _ym[j];
308       } else {
309         a.y = coef*_ym[j] + (1.-coef)*_ym[j+1];
310       };
311
312       lp.push_back(a);
313       DEBTRACE(a.x << " " << a.y);
314       ++it;
315     }
316   return lp;
317 }
318
319 void LinkMatrix::incrementCost(LNodePath lnp)
320 {
321   int dim = lnp.size();  
322   LNodePath::const_iterator it = lnp.begin();
323   for (; it != lnp.end(); ++it)
324     {
325       int i = it->getX();
326       int j = it->getY();
327       int ij = i*_jm +j;
328       _cost[ij] += Resource::link_separation_weight; // --- big cost, because distance is x2+y2
329
330     }    
331 }
332
333
334 /*!
335  * find recursively elementary nodes and node headers and call getBoundingBox on each item.
336  * first pass with setObstacle = false stores the x and y coordinates of the mesh boundaries.
337  * second pass with setObstacle = true fills the mesh with obstacles i.e. elementary nodes or
338  * nodeHeaders.
339  */
340 void LinkMatrix::explore(AbstractSceneItem *child, bool setObstacle)
341 {
342   SceneComposedNodeItem *cnItem = dynamic_cast<SceneComposedNodeItem*>(child);
343   if (cnItem)
344     {
345       SceneHeaderItem *obstacle = cnItem->getHeader();
346       if (obstacle) getBoundingBox(obstacle, 0, setObstacle);
347       list<AbstractSceneItem*> children = cnItem->getChildren();
348       for (list<AbstractSceneItem*>::const_iterator it = children.begin(); it != children.end(); ++it)
349         explore(*it, setObstacle);
350     }
351   SceneElementaryNodeItem *ceItem = dynamic_cast<SceneElementaryNodeItem*>(child);
352   if (ceItem)
353     {
354       getBoundingBox(ceItem, 1, setObstacle);
355     }
356 }
357
358 /*!
359  * first pass with setObstacle = false stores the x and y coordinates of the mesh boundaries.
360  * second pass with setObstacle = true fills the mesh with obstacles i.e. elementary nodes or
361  * nodeHeaders. For elementary nodes, the bounding box is smaller to let a path between nodes
362  * that are stick together.
363  */
364 void LinkMatrix::getBoundingBox(SceneItem *obstacle, int margin, bool setObstacle)
365 {
366   QRectF bb = (obstacle->mapToScene(obstacle->boundingRect())).boundingRect();
367   if (setObstacle)
368     {
369       int imin = _x2i[bb.left()   + margin];
370       int imax = _x2i[bb.right()  - margin];
371       int jmin = _y2j[bb.top()    + margin];
372       int jmax = _y2j[bb.bottom() - margin];
373       DEBTRACE(bb.left() << " " << bb.right() << " " << bb.top() << " " << bb.bottom() );
374       DEBTRACE(imin << " " << imax << " " << jmin << " " << jmax);
375       for (int j=jmin; j<jmax; j++)
376         for (int i=imin; i<imax; i++)
377           {
378             int ij = i*_jm +j;
379             _cost[ij] = 0;       // --- obstacle
380           }
381     }
382   else
383     {
384       _sxm.insert(bb.left()   + margin);
385       _sxm.insert(bb.right()  - margin);
386       _sym.insert(bb.top()    + margin);
387       _sym.insert(bb.bottom() - margin);
388     }
389 }
390
391 void LinkMatrix::addRowCols()
392 {
393   {
394     set<double> sxmCpy = _sxm;
395     if (sxmCpy.empty()) return;
396     set<double>::iterator itx = sxmCpy.begin();
397     double xmin = *itx;
398     double xmax = xmin;
399     itx++;
400     for (; itx != sxmCpy.end(); ++itx)
401       {
402         xmax = *itx;
403         int nbpas = floor((xmax -xmin)/_pas);
404         
405         if (nbpas >= 2)
406           {
407             double xpas = (xmax -xmin)/nbpas;
408             for (int i=1; i<nbpas; i++)
409               _sxm.insert(xmin +i*xpas);
410           }
411         xmin = xmax;
412       }
413   }
414   {
415     set<double> symCpy = _sym;
416     if (symCpy.empty()) return;
417     set<double>::iterator ity = symCpy.begin();
418     double ymin = *ity;
419     double ymax = ymin;
420     ity++;
421     for (; ity != symCpy.end(); ++ity)
422       {
423         ymax = *ity;
424         int nbpas = floor((ymax -ymin)/_pas);
425         
426         if (nbpas >= 2)
427           {
428             double ypas = (ymax -ymin)/nbpas;
429             for (int i=1; i<nbpas; i++)
430               _sym.insert(ymin +i*ypas);
431           }
432         ymin = ymax;
433       }
434   }
435 }