Developer Documentation
connection.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 //== INCLUDES =================================================================
51 #include <QGraphicsSceneMouseEvent>
52 #include <QGraphicsScene>
53 
54 #include "elementInOut.hh"
55 #include "elementInput.hh"
56 #include "elementOutput.hh"
57 #include "connection.hh"
58 #include "connectionPoint.hh"
59 #include "graphicsScene.hh"
60 #include "elementArea.hh"
61 #include "wayfind.hh"
62 
63 //== NAMESPACES ===============================================================
64 namespace VSI {
65 
66 //=============================================================================
67 //
68 // CLASS VSI::Connection - IMPLEMENTATION
69 //
70 //=============================================================================
71 
73 Connection::Connection (ConnectionPoint *_start, QGraphicsScene *_scene) :
74  QGraphicsPathItem (dynamic_cast<GraphicsScene *>(_scene)->elementArea ()),
75  scene_ (dynamic_cast<GraphicsScene *>(_scene)),
76  p1_ (_start),
77  p2_ (0),
78  old_ (0)
79 {
80 
81  elementArea_ = scene_->elementArea ();
82 
83  QPen p = pen ();
84 
85  p.setCapStyle (Qt::RoundCap);
86  p.setColor (QColor (128, 128, 128));
87 
88  if (p1_->inOut ()->inOut ()->typeString () == "data")
89  p.setWidth (4);
90  else
91  p.setWidth (2);
92  setPen (p);
93 }
94 
96 Connection::Connection (ConnectionPoint *_start, ConnectionPoint *_end, QGraphicsScene *_scene) :
97  QGraphicsPathItem (dynamic_cast<GraphicsScene *>(_scene)->elementArea ()),
98  scene_ (dynamic_cast<GraphicsScene *>(_scene)),
99  p1_ (_start),
100  p2_ (_end)
101 {
102  elementArea_ = scene_->elementArea ();
103 
104  QPen p = pen ();
105 
106  p.setCapStyle (Qt::RoundCap);
107 
108  if (p1_->inOut ()->inOut ()->typeString () == "data")
109  p.setWidth (4);
110  else
111  p.setWidth (2);
112  setPen (p);
113 
114  if (!p1_->inOut ()->validConnection (p2_->inOut ()))
115  {
116  deleteLater ();
117  p1_ = p2_ = 0;
118  return;
119  }
120 
121  way_ = QPolygonF ();
122 
123  p.setColor (QColor (0, 0, 0));
124  setPen (p);
125 
126  p1_->inOut ()->addConnection (this);
127  p2_->inOut ()->addConnection (this);
128 }
129 
132 {
133  if (p1_)
134  p1_->inOut ()->removeConnection (this);
135  if (p2_)
136  p2_->inOut ()->removeConnection (this);
137 }
138 
139 // handle mouse movement
140 void Connection::mouseMoveEvent (QGraphicsSceneMouseEvent *_event)
141 {
142  QPen p = pen ();
143 
144  ConnectionPoint *pnt = cPointAt (_event->scenePos ());
145 
146  if (pnt)
147  { if (p1_->inOut ()->validConnection (pnt->inOut ()))
148  p.setColor (QColor (0, 255, 0));
149  else
150  p.setColor (QColor (255, 0, 0));
151  }
152  else
153  p.setColor (QColor (128, 128, 128));
154  setPen (p);
155 
156  way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), elementArea_->mapFromScene (_event->scenePos ()).toPoint ());
157  updateLine ();
158 }
159 
160 // Start new connection on mouse press
161 void Connection::mousePressEvent (QGraphicsSceneMouseEvent *_event)
162 {
163  if (p1_)
164  p1_->inOut ()->removeConnection (this);
165  if (p2_)
166  p2_->inOut ()->removeConnection (this);
167 
168  QPointF p = p1_->connectPos () - _event->scenePos ();
169  qreal d1 = (p.x () * p.x()) + (p.y () * p.y ());
170  p = p2_->connectPos () - _event->scenePos ();
171  qreal d2 = (p.x () * p.x()) + (p.y () * p.y ());
172 
173  if (d2 > d1)
174  {
175  old_ = p1_;
176  p1_ = p2_;
177  }
178 
179  way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), elementArea_->mapFromScene (_event->scenePos ()).toPoint ());
180  updateLine ();
181 }
182 
183 // make a connection on relase at a valid connection point
184 void Connection::mouseReleaseEvent (QGraphicsSceneMouseEvent *_event)
185 {
186  scene_->setActiveConnection (0);
187 
188  p2_ = cPointAt (_event->scenePos ());
189 
190  if (!p2_ || !p1_->inOut ()->validConnection (p2_->inOut ()))
191  {
192  if (old_)
193  scene_->contentChange ();
194 
195  deleteLater ();
196  p1_ = p2_ = 0;
197  return;
198  }
199 
200  way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), p2_->connectPos ().toPoint ());
201  updateLine ();
202 
203  QPen p = pen ();
204 
205  p.setColor (QColor (0, 0, 0));
206  setPen (p);
207 
208  if (old_ != p2_)
209  scene_->contentChange ();
210 
211  old_ = p2_;
212 
213  p1_->inOut ()->addConnection (this);
214  p2_->inOut ()->addConnection (this);
215 
216 }
217 
218 // helper to localize a connection point
219 ConnectionPoint *Connection::cPointAt (QPointF _pnt)
220 {
221 
222  ConnectionPoint *pnt = 0;
223 
224  foreach (QGraphicsItem *i, scene ()->items (_pnt))
225  {
226  ConnectionPoint *pt = dynamic_cast<ConnectionPoint *>(i);
227 
228  if (pt)
229  {
230  pnt = pt;
231  }
232  }
233 
234  return pnt;
235 }
236 
239 {
240  way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), p2_->connectPos ().toPoint ());
241  updateLine ();
242 }
243 
246 {
247  ElementInput *i = dynamic_cast<ElementInput *> (p1_->inOut ());
248  if (!i)
249  i = dynamic_cast<ElementInput *> (p2_->inOut ());
250  return i;
251 }
252 
255 {
256  ElementOutput *o = dynamic_cast<ElementOutput *> (p1_->inOut ());
257  if (!o && p2_)
258  o = dynamic_cast<ElementOutput *> (p2_->inOut ());
259  return o;
260 }
261 
263 const QPolygonF & VSI::Connection::way () const
264 {
265  return way_;
266 }
267 
270 {
271  way_ = QPolygonF ();
272  setPath (QPainterPath ());
273 }
274 
275 // generates a curved line out of the way polygon
276 void Connection::updateLine()
277 {
278  QPainterPath path;
279 
280  if (way_.size () <= 1)
281  {
282  setPath (path);
283  return;
284  }
285  else if (way_.size () == 2)
286  {
287  path.addPolygon(way_);
288  setPath (path);
289  return;
290  }
291 
292  path.moveTo (way_[0]);
293 
294  QPointF a,b,c;
295 
296  for (int i = 2; i < way_.size (); i++)
297  {
298  a = way_[i-2];
299  b = way_[i-1];
300  c = way_[i];
301 
302  QLineF l1 (a,b), l2 (b,c);
303 
304  int rad = qMin (40.0, qMin (l1.length() / 2, l2.length() / 2));
305 
306  if (rad > 5)
307  rad -= rad % 5;
308 
309  if (a.x () == b.x ())
310  {
311  if (a.y () > b.y ())
312  {
313  path.lineTo (b.x (), b.y () + rad);
314  if (c.x () > b.x ())
315  {
316  path.arcTo (b.x (), b.y (), 2 * rad, 2 * rad, 180, -90);
317  }
318  else
319  {
320  path.arcTo (b.x () - (rad * 2), b.y (), 2 * rad, 2 * rad, 0, 90);
321  }
322  }
323  else
324  {
325  path.lineTo (b.x (), b.y () - rad);
326  if (c.x () > b.x ())
327  {
328  path.arcTo (b.x (), b.y () - (rad * 2), 2 * rad, 2 * rad, 180, 90);
329  }
330  else
331  {
332  path.arcTo (b.x () - (rad * 2), b.y () - (rad * 2), 2 * rad, 2 * rad, 0, -90);
333  }
334  }
335  }
336  else
337  {
338  if (a.x () > b.x ())
339  {
340  path.lineTo (b.x () + rad, b.y ());
341  if (c.y () > b.y ())
342  {
343  path.arcTo (b.x (), b.y (), 2 * rad, 2 * rad, 90, 90);
344  }
345  else
346  {
347  path.arcTo (b.x (), b.y () - (rad * 2), 2 * rad, 2 * rad, 270, -90);
348  }
349  }
350  else
351  {
352  path.lineTo (b.x () - rad, b.y ());
353  if (c.y () > b.y ())
354  {
355  path.arcTo (b.x () - (rad * 2), b.y (), 2 * rad, 2 * rad, 90, -90);
356  }
357  else
358  {
359  path.arcTo (b.x () - (rad * 2), b.y () - (rad * 2), 2 * rad, 2 * rad, 270, 90);
360  }
361  }
362  }
363  }
364 
365  path.lineTo (c);
366 
367  setPath (path);
368 }
369 
370 }
QPolygonF findWay(Connection *_conn, QPoint _from, QPoint _to)
Finds a way from _from to _to ignoring any already existent connections from _conn.
Definition: wayfind.cc:101
const QPolygonF & way() const
way of the connection
Definition: connection.cc:263
QString typeString() const
Type.
Definition: inout.cc:71
ElementArea * elementArea() const
Element area.
void invalidate()
invalidate way
Definition: connection.cc:269
bool validConnection(ElementInOut *_e)
Can this input/output be connected to _e.
QPointF connectPos()
Position for connections.
virtual void addConnection(Connection *_conn)
Add the connection.
Connection(ConnectionPoint *_start, QGraphicsScene *_scene)
Constructor.
Definition: connection.cc:73
void contentChange()
handle content changes
void updatePositions()
called to update position on element movement
Definition: connection.cc:238
virtual void removeConnection(Connection *_conn)
Remove the Connection.
~Connection()
Destructor.
Definition: connection.cc:131
ElementInput * input()
Input of this connection.
Definition: connection.cc:245
InOut * inOut() const
InOut context object.
void setActiveConnection(Connection *_conn)
Sets the active connection.
ElementOutput * output()
Output of this connection.
Definition: connection.cc:254
WayFind * wayFind()
WayFind object.
ElementInOut * inOut() const
Input/output element.