Version: 8.3.0
SceneLinkItem.cxx
Go to the documentation of this file.
1 // Copyright (C) 2006-2016 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 #define CHRONODEF
21 #include "chrono.hxx"
22 
23 #include "SceneLinkItem.hxx"
24 #include "SceneDataPortItem.hxx"
25 #include "SceneCtrlPortItem.hxx"
27 #include "SceneHeaderNodeItem.hxx"
28 #include "Scene.hxx"
29 #include "Resource.hxx"
30 
31 #include "Menus.hxx"
32 #include <QPointF>
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 
43 SceneLinkItem::SceneLinkItem(QGraphicsScene *scene, SceneItem *parent,
44  ScenePortItem* from, ScenePortItem* to,
45  QString label, Subject *subject)
46  : SceneObserverItem(scene, parent, label, subject)
47 {
48  _from = from;
49  _to = to;
54  _level += 100;
55  setZValue(_level);
56  DEBTRACE("ZValue=" << zValue());
57  _lp.clear();
58  _directions.clear();
59  _nbPoints = 0;
60  _path = QPainterPath();
61 }
62 
64 {
65 }
66 
67 void SceneLinkItem::select(bool isSelected)
68 {
69  if (isSelected)
70  setZValue(_level+100);
71  else
72  setZValue(_level);
73  DEBTRACE("ZValue=" << zValue());
74  SceneObserverItem::select(isSelected);
75 }
76 
78 {
79  return _path.boundingRect();
80 }
81 
82 QPainterPath SceneLinkItem::shape() const
83 {
84  //DEBTRACE("SceneLinkItem::shape");
85  return _path;
86 }
87 
88 void SceneLinkItem::setShape(int thickness)
89 {
90  DEBTRACE("---");
91  _path = QPainterPath();
92  _path.setFillRule(Qt::WindingFill);
93  QPointF pfrom = start();
94  QPointF pto = goal();
97  {
98  DEBTRACE("---");
99  addArrow(pfrom, _lp[0], _RIGHT, thickness);
100  for (int k=0; k<_nbPoints-1; k++)
101  addArrow(_lp[k], _lp[k+1], _directions[k+1], thickness);
102  addArrow(_lp[_nbPoints-1], pto, _RIGHT, thickness);
103  }
104  else
105  {
106  DEBTRACE("---");
107  double d = std::sqrt((pto.x() - pfrom.x())*(pto.x() - pfrom.x()) + (pto.y() - pfrom.y())*(pto.y() - pfrom.y()));
108  double sina = (pto.y() - pfrom.y())/d;
109  double cosa = (pto.x() - pfrom.x())/d;
110  double ep=3.0*thickness/2.0 * Resource::link_thickness;
111  _path.moveTo(pfrom.x() -ep*sina, pfrom.y() +ep*cosa);
112  _path.lineTo(pto.x() -ep*sina, pto.y() +ep*cosa);
113  _path.lineTo(pto.x() +ep*sina, pto.y() -ep*cosa);
114  _path.lineTo(pfrom.x() +ep*sina, pfrom.y() -ep*cosa);
115  _path.lineTo(pfrom.x() -ep*sina, pfrom.y() -ep*cosa);
116  //arrow
117  double x=(pto.x() + pfrom.x())/2.;
118  double y=(pto.y() + pfrom.y())/2.;
119  double l=8*ep;
120  double e=4*ep;
121  _path.moveTo(x+l*cosa,y+l*sina);
122  _path.lineTo(x+e*sina,y-e*cosa);
123  _path.lineTo(x-e*sina,y+e*cosa);
124  _path.lineTo(x+l*cosa,y+l*sina);
125  }
126 }
127 
128 void SceneLinkItem::addArrow(QPointF pfrom,
129  QPointF pto,
131  int thickness)
132 {
133  qreal x, y, width, height, length;
134  double ep=thickness * Resource::link_thickness;
135  switch (dir)
136  {
137  case _UP:
138  x = pfrom.x() -ep;
139  y = pfrom.y() -ep;
140  width = 3*ep;
141  height = 2*ep + pto.y() -pfrom.y();
142  length = height;
143  break;
144  case _RIGHT:
145  x = pfrom.x() -ep;
146  y = pfrom.y() -ep;
147  width = 2*ep + pto.x() -pfrom.x();
148  height = 3*ep;
149  length = width;
150  break;
151  case _DOWN:
152  x = pto.x() -ep;
153  y = pto.y() -ep;
154  width = 3*ep;
155  height = 2*ep + pfrom.y() -pto.y();
156  length = height;
157  break;
158  case _LEFT:
159  x = pto.x() -ep;
160  y = pto.y() -ep;
161  width = 2*ep + pfrom.x() -pto.x();
162  height = 3*ep;
163  length = width;
164  break;
165  }
166  _path.addRect(x, y, width, height);
167 
168  if (length > 20)
169  {
170  int e=5*ep, h1=4*ep, h2=8*ep;
171  switch (dir)
172  {
173  case _UP:
174  x = pfrom.x();
175  y = (pto.y() + pfrom.y())/2 +h1;
176  _path.moveTo(x, y);
177  _path.lineTo(x+e, y-h2);
178  _path.lineTo(x, y-h1);
179  _path.lineTo(x-e, y-h2);
180  _path.lineTo(x, y );
181  break;
182  case _RIGHT:
183  x = (pto.x() + pfrom.x())/2 +h1;
184  y = pfrom.y();
185  _path.moveTo(x, y);
186  _path.lineTo(x-h2, y+e);
187  _path.lineTo(x-h1, y );
188  _path.lineTo(x-h2, y-e);
189  _path.lineTo(x, y );
190  break;
191  case _DOWN:
192  x = pfrom.x();
193  y = (pto.y() + pfrom.y())/2 -h1;
194  _path.moveTo(x, y);
195  _path.lineTo(x+e, y+h2);
196  _path.lineTo(x, y+h1);
197  _path.lineTo(x-e, y+h2);
198  _path.lineTo(x, y );
199  break;
200  case _LEFT:
201  x = (pto.x() + pfrom.x())/2 -h1;
202  y = pfrom.y();
203  _path.moveTo(x, y);
204  _path.lineTo(x+h2, y+e);
205  _path.lineTo(x+h1, y );
206  _path.lineTo(x+h2, y-e);
207  _path.lineTo(x, y );
208  break;
209  }
210  }
211 }
212 
213 void SceneLinkItem::paint(QPainter *painter,
214  const QStyleOptionGraphicsItem *option,
215  QWidget *widget)
216 {
217  //DEBTRACE("SceneLinkItem::paint " << _label.toStdString());
218  if (_path.isEmpty()) setShape(_emphasized+1);
219  painter->save();
220  QPen pen;
221  pen.setColor(getPenColor());
222  painter->setPen(pen);
223  painter->setBrush(getBrushColor());
224  painter->drawPath(_path);
225  painter->restore();
226 }
227 
228 void SceneLinkItem::update(GuiEvent event, int type, Subject* son)
229 {
230  DEBTRACE("SceneLinkItem::update "<< eventName(event)<<" "<<type<<" "<<son);
231  switch (event)
232  {
234  DEBTRACE("SceneObserverItem::update EMPHASIZE " << type);
235  if (type)
236  {
237  _emphasized = true;
238  setZValue(_level+100);
239  DEBTRACE("ZValue=" << zValue());
240  setShape(2);
241  }
242  else
243  {
244  _emphasized = false;
245  setZValue(_level);
246  DEBTRACE("ZValue=" << zValue());
247  setShape();
248  }
249  QGraphicsItem::update();
250  break;
252  DEBTRACE("SceneObserverItem::update SWITCHSHAPE");
254  QGraphicsItem::update();
255  break;
256  default:
257  ;
258  }
259 }
260 
261 void SceneLinkItem::popupMenu(QWidget *caller, const QPoint &globalPos)
262 {
263  LinkMenu m;
264  m.popupMenu(caller, globalPos);
265 }
266 
268 {
269  DEBTRACE("SceneLinkItem::setPath " << lp.size());
270  CHRONO(10);
271  prepareGeometryChange();
272  _nbPoints = lp.size();
273  _lp.resize(_nbPoints+1);
274  _directions.resize(_nbPoints +2);
275  std::list<linkPoint>::const_iterator it = lp.begin();
276  int k=0;
277  qreal prevx = 0;
278  qreal prevy = 0;
279  bool dirx = true;
280  bool diry = false;
281  for (; it != lp.end(); ++it)
282  {
283  QPointF p = mapFromScene(QPointF((*it).x, (*it).y));
284  DEBTRACE("p(" << p.x() << "," << p.y() << ")");
285  if (k == 0)
286  {
287  _lp[k] = p;
288  _lp[k].setY(start().y());
289  _directions[k] = _RIGHT; // --- direction from start to point k=0
290  k++;
291  }
292  else
293  {
294  bool changeDir = true;
295  if (dirx && (p.y() == prevy))
296  {
297  _lp[k-1].setX(p.x());
298  changeDir = false;
299  }
300  if (diry && (p.x() == prevx))
301  {
302  _lp[k-1].setY(p.y());
303  changeDir = false;
304  }
305  if (changeDir)
306  {
307  dirx = !dirx;
308  diry = !diry;
309  _lp[k] = p;
310  if (p.x() > prevx) _directions[k] = _RIGHT; // --- direction from k-1 to k
311  else if (p.x() < prevx) _directions[k] = _LEFT;
312  else if (p.y() > prevy) _directions[k] = _UP;
313  else if (p.y() < prevy) _directions[k] = _DOWN;
314  k++;
315  }
316  }
317  prevx = p.x();
318  prevy = p.y();
319  }
320 
321  if(k==1)
322  {
323  //link should be direct (k=0) or orthogonal k>=2
324  k=2;
325  _lp[1]=_lp[0];
326  _lp[1].setY(goal().y());
327  if (goal().y() > start().y()) _directions[1] = _UP;
328  else _directions[1] = _DOWN;
329  }
330 
331  if(k>2 && _directions[k-1]==_RIGHT)
332  {
333  //remove last point
334  k=k-1;
335  }
336 
337  _nbPoints = k;
338  _lp[k-1].setY(goal().y());
339  _directions[k] = _RIGHT; // --- direction from point k-1 to goal
340  dirx = true;
341  diry = false;
342  for (k = _nbPoints -2; k >= 0; k--)
343  {
344  if(_lp[k].y() == prevy)
345  _lp[k].setY(goal().y());
346  else
347  break;
348  }
349  CHRONOSTOP(10);
350  CHRONO(11);
352  CHRONOSTOP(11);
353  CHRONO(12);
355  for (k=0; k<_nbPoints; k++)
356  DEBTRACE("_lp[" << k << "](" << _lp[k].x() << "," << _lp[k].y() << ")");
358  SceneItem::update();
359 }
360 
366 {
367  vector<QPointF> newlp;
368  vector<Direction> newdir;
369  newlp.resize(_nbPoints);
370  newdir.resize(_nbPoints +1);
371 
372  bool modified = true;
373  while (modified)
374  {
375  modified = false;
376  Direction prevdir = _RIGHT;
377  newlp[0] = _lp[0];
378  newdir[0] = _directions[0];
379  int newk = 0;
380  for (int k = 0; k < _nbPoints; k++)
381  {
382  if (k< _nbPoints-2) // --- _nbPoints + 1 directions, look to k+3
383  if ((_directions[k] == _directions[k+2]) && (_directions[k+1] == _directions[k+3]))
384  {
385  bool kmodif = true;
386  qreal tryx;
387  qreal tryy;
388  if ((_directions[k] == _RIGHT) || (_directions[k] == _LEFT))
389  {
390  tryy = _lp[k].y();
391  tryx = _lp[k+2].x();
392  }
393  else
394  {
395  tryy = _lp[k+2].y();
396  tryx = _lp[k].x();
397  }
398 
399  qreal xtop, ytop, width, height;
400  if (_lp[k].x() < _lp[k+2].x())
401  {
402  xtop = _lp[k].x();
403  width = _lp[k+2].x() - _lp[k].x();
404  }
405  else
406  {
407  xtop = _lp[k+2].x();
408  width = _lp[k].x() - _lp[k+2].x();
409  }
410  if (_lp[k].y() < _lp[k+2].y())
411  {
412  ytop = _lp[k].y();
413  height = _lp[k+2].y() - _lp[k].y();
414  }
415  else
416  {
417  ytop = _lp[k+2].y();
418  height = _lp[k].y() - _lp[k+2].y();
419  }
420  QRectF aRect(mapToScene(QPointF(xtop, ytop)),
421  mapToScene(QPointF(xtop + width, ytop + height)));
422  QList<QGraphicsItem*> itemList = scene()->items(aRect);
423  for (int kk=0; kk<itemList.size(); kk++)
424  {
425  QGraphicsItem *item = itemList[kk];
426  if ((dynamic_cast<SceneElementaryNodeItem*>(item)) ||
427  (dynamic_cast<SceneHeaderNodeItem*>(item)))
428  {
429  kmodif = false;
430  break;
431  }}
432 
433  if (kmodif)
434  {
435  modified = true;
436  _lp[k+1] = QPointF(tryx, tryy);
437  _directions[k+1] = _directions[k];
438  _directions[k+2] = _directions[k+3];
439  }
440  }
441  if (k>0)
442  {
443  if (prevdir == _directions[k])
444  {
445  if ((prevdir == _RIGHT) || (prevdir == _LEFT))
446  newlp[newk].setX(_lp[k].x());
447  else
448  newlp[newk].setY(_lp[k].y());
449  }
450  else
451  {
452  newk++;
453  newlp[newk] = _lp[k];
454  newdir[newk] = _directions[k];
455  }
456 
457  }
458  prevdir = _directions[k];
459  }
460  DEBTRACE("modified : _nbPoints=" << _nbPoints << " newk=" << newk+1);
461  if (modified)
462  {
463 // for (int i=0; i<=newk; i++)
464 // {
465 // DEBTRACE("("<< _lp[i].x() << "," << _lp[i].y() << ") ("
466 // << newlp[i].x() << "," << newlp[i].y() << ") "
467 // << _directions[i] << "-" << newdir[i]);
468 // }
469 // for (int i=newk+1; i<_nbPoints; i++)
470 // {
471 // DEBTRACE("("<< _lp[i].x() << "," << _lp[i].y() << ") "
472 // << _directions[i]);
473 // }
474 
475  if(newdir[newk]==_RIGHT)
476  {
477  //remove last point
478  newk=newk-1;
479  }
480  _nbPoints = newk+1;
481  for (int i=0; i<_nbPoints; i++)
482  {
483  _lp[i] = newlp[i];
484  _directions[i] = newdir[i];
485  }
487  DEBTRACE("_nbPoints " << _nbPoints);
488  }
489  }
490 }
491 
493 {
494  if (_nbPoints == 1)
495  {
496  QPointF a = start();
497  QPointF b = goal();
498  if (a.y() != b.y())
499  {
500  vector<QPointF> newlp;
501  vector<Direction> newdir;
502  newlp.resize(_nbPoints+1);
503  newdir.resize(_nbPoints +2);
504  //_lp.resize(_nbPoints +1); // --- not OK : data may be lost! pre reserve enough before!
505  //_directions.resize(_nbPoints +2);
506  newlp[0] = _lp[0];
507  newlp[1] = _lp[0];
508  newlp[0].setY(a.y());
509  newlp[1].setY(b.y());
510  newdir[0] = _RIGHT;
511  newdir[2] = _RIGHT;
512  if (a.y() > b.y())
513  newdir[1] = _DOWN;
514  else
515  newdir[1] = _UP;
516  _nbPoints = 2;
517  for (int i=0; i<_nbPoints; i++)
518  {
519  _lp[i] = newlp[i];
520  _directions[i] = newdir[i];
521  }
523  }
524  }
525 }
526 
527 
529 {
530  SceneDataPortItem* dpif = dynamic_cast<SceneDataPortItem*>(_from);
531  QPointF localFrom(dpif->getWidth()*(9.5/10), dpif->getHeight()/2);
532  DEBTRACE("localFrom(" << localFrom.x() << "," << localFrom.y() << ")");
533  return mapFromItem(dpif, localFrom);
534 }
535 
537 {
538  SceneDataPortItem* dpit = dynamic_cast<SceneDataPortItem*>(_to);
539  QPointF localTo(dpit->getWidth()/20, dpit->getHeight()/2);
540  DEBTRACE("localTo(" << localTo.x() << "," << localTo.y() << ")");
541  return mapFromItem(dpit, localTo);
542 }
543 
545 {
546  prepareGeometryChange();
547  if (_nbPoints)
548  {
549  // a path has been calculated, update it
550  QPointF pfrom = start();
551  QPointF pto = goal();
552  _lp[0].setY(pfrom.y());
553  if(_lp[1].y() > _lp[0].y())_directions[1]=_UP;
554  else _directions[1]=_DOWN;
555  _lp[_nbPoints-1].setY(pto.y());
556  if(_lp[_nbPoints-1].y() > _lp[_nbPoints-2].y())_directions[_nbPoints-1]=_UP;
557  else _directions[_nbPoints-1]=_DOWN;
558  }
560 }
561 
563 {
567 }
568 
570 {
574 }
575 
576 // Get the node at the "from" place of the link
578  SceneCtrlPortItem* p = dynamic_cast<SceneCtrlPortItem*>(_from);
579  if (p) {
580  return(p->getParentNode());
581  } else {
582  return(NULL);
583  };
584 }
585 
586 // Get the node at the "to" place of the link
588  SceneCtrlPortItem* p = dynamic_cast<SceneCtrlPortItem*>(_to);
589  if (p) {
590  return(p->getParentNode());
591  } else {
592  return(NULL);
593  };
594 }