1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    GNEHierarchicalElementChilds.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    Dec 2015
13 /// @version $Id$
14 ///
15 // A abstract class for representation of additional elements
16 /****************************************************************************/
17 
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21 #include <config.h>
22 
23 #include <netedit/GNENet.h>
24 #include <netedit/GNEViewNet.h>
25 #include <netedit/GNEViewParent.h>
26 #include <netedit/additionals/GNEAdditional.h>
27 #include <netedit/additionals/GNEShape.h>
28 #include <netedit/demandelements/GNEDemandElement.h>
29 #include <netedit/frames/GNESelectorFrame.h>
30 #include <netedit/netelements/GNEEdge.h>
31 #include <netedit/netelements/GNEJunction.h>
32 #include <netedit/netelements/GNELane.h>
33 #include <utils/common/StringTokenizer.h>
34 #include <utils/gui/div/GLHelper.h>
35 #include <utils/gui/div/GUIGlobalSelection.h>
36 #include <utils/gui/div/GUIParameterTableWindow.h>
37 #include <utils/gui/globjects/GLIncludes.h>
38 #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
39 #include <utils/gui/images/GUITextureSubSys.h>
40 #include <utils/options/OptionsCont.h>
41 
42 #include "GNEHierarchicalElementChilds.h"
43 
44 // ===========================================================================
45 // member method definitions
46 // ===========================================================================
47 
GNEHierarchicalElementChilds(GNEAttributeCarrier * AC,const std::vector<GNEEdge * > & edgeChilds,const std::vector<GNELane * > & laneChilds,const std::vector<GNEShape * > & shapeChilds,const std::vector<GNEAdditional * > & additionalChilds,const std::vector<GNEDemandElement * > & demandElementChilds)48 GNEHierarchicalElementChilds::GNEHierarchicalElementChilds(GNEAttributeCarrier* AC,
49         const std::vector<GNEEdge*>& edgeChilds,
50         const std::vector<GNELane*>& laneChilds,
51         const std::vector<GNEShape*>& shapeChilds,
52         const std::vector<GNEAdditional*>& additionalChilds,
53         const std::vector<GNEDemandElement*>& demandElementChilds) :
54     myChildConnections(this),
55     myEdgeChilds(edgeChilds),
56     myLaneChilds(laneChilds),
57     myShapeChilds(shapeChilds),
58     myAdditionalChilds(additionalChilds),
59     myDemandElementChilds(demandElementChilds),
60     myAC(AC) {
61 }
62 
63 
~GNEHierarchicalElementChilds()64 GNEHierarchicalElementChilds::~GNEHierarchicalElementChilds() {}
65 
66 
67 void
addAdditionalChild(GNEAdditional * additional)68 GNEHierarchicalElementChilds::addAdditionalChild(GNEAdditional* additional) {
69     // Check if additional is valid
70     if (additional == nullptr) {
71         throw InvalidArgument("Trying to add an empty additional child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
72     } else {
73         // add it in additional childs container
74         myAdditionalChilds.push_back(additional);
75         // only execute post operations if update geometry is enabled
76         if (additional->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
77             // Check if childs has to be sorted automatically
78             if (myAC->getTagProperty().canAutomaticSortChilds()) {
79                 sortAdditionalChilds();
80             }
81             // update additional parent after add additional (note: by default non-implemented)
82             updateAdditionalParent();
83             updateGeometry(true);
84         }
85     }
86 }
87 
88 
89 void
removeAdditionalChild(GNEAdditional * additional)90 GNEHierarchicalElementChilds::removeAdditionalChild(GNEAdditional* additional) {
91     // First check that additional was already inserted
92     auto it = std::find(myAdditionalChilds.begin(), myAdditionalChilds.end(), additional);
93     if (it == myAdditionalChilds.end()) {
94         throw ProcessError(additional->getTagStr() + " with ID='" + additional->getID() + "' doesn't exist in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
95     } else {
96         myAdditionalChilds.erase(it);
97         // only execute post operations if update geometry is enabled
98         if (additional->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
99             // Check if childs has to be sorted automatically
100             if (myAC->getTagProperty().canAutomaticSortChilds()) {
101                 sortAdditionalChilds();
102             }
103             // update additional parent after add additional (note: by default non-implemented)
104             updateAdditionalParent();
105             updateGeometry(true);
106         }
107     }
108 }
109 
110 
111 const std::vector<GNEAdditional*>&
getAdditionalChilds() const112 GNEHierarchicalElementChilds::getAdditionalChilds() const {
113     return myAdditionalChilds;
114 }
115 
116 
117 void
sortAdditionalChilds()118 GNEHierarchicalElementChilds::sortAdditionalChilds() {
119     if (myAC->getTagProperty().getTag() == SUMO_TAG_E3DETECTOR) {
120         // we need to sort Entry/Exits due additional.xds model
121         std::vector<GNEAdditional*> sortedEntryExits;
122         // obtain all entrys
123         for (auto i : myAdditionalChilds) {
124             if (i->getTagProperty().getTag() == SUMO_TAG_DET_ENTRY) {
125                 sortedEntryExits.push_back(i);
126             }
127         }
128         // obtain all exits
129         for (auto i : myAdditionalChilds) {
130             if (i->getTagProperty().getTag() == SUMO_TAG_DET_EXIT) {
131                 sortedEntryExits.push_back(i);
132             }
133         }
134         // change myAdditionalChilds for sortedEntryExits
135         if (sortedEntryExits.size() == myAdditionalChilds.size()) {
136             myAdditionalChilds = sortedEntryExits;
137         } else {
138             throw ProcessError("Some additional childs were lost during sorting");
139         }
140     } else if (myAC->getTagProperty().getTag() == SUMO_TAG_TAZ) {
141         // we need to sort Entry/Exits due additional.xds model
142         std::vector<GNEAdditional*> sortedTAZSourceSink;
143         // obtain all TAZSources
144         for (auto i : myAdditionalChilds) {
145             if (i->getTagProperty().getTag() == SUMO_TAG_TAZSOURCE) {
146                 sortedTAZSourceSink.push_back(i);
147             }
148         }
149         // obtain all TAZSinks
150         for (auto i : myAdditionalChilds) {
151             if (i->getTagProperty().getTag() == SUMO_TAG_TAZSINK) {
152                 sortedTAZSourceSink.push_back(i);
153             }
154         }
155         // change myAdditionalChilds for sortedEntryExits
156         if (sortedTAZSourceSink.size() == myAdditionalChilds.size()) {
157             myAdditionalChilds = sortedTAZSourceSink;
158         } else {
159             throw ProcessError("Some additional childs were lost during sorting");
160         }
161     } else {
162         // declare a vector to keep sorted childs
163         std::vector<std::pair<std::pair<double, double>, GNEAdditional*> > sortedChilds;
164         // iterate over additional childs
165         for (auto i : myAdditionalChilds) {
166             sortedChilds.push_back(std::make_pair(std::make_pair(0., 0.), i));
167             // set begin/start attribute
168             if (i->getTagProperty().hasAttribute(SUMO_ATTR_TIME) && GNEAttributeCarrier::canParse<double>(i->getAttribute(SUMO_ATTR_TIME))) {
169                 sortedChilds.back().first.first = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_TIME));
170             } else if (i->getTagProperty().hasAttribute(SUMO_ATTR_BEGIN) && GNEAttributeCarrier::canParse<double>(i->getAttribute(SUMO_ATTR_BEGIN))) {
171                 sortedChilds.back().first.first = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_BEGIN));
172             }
173             // set end attribute
174             if (i->getTagProperty().hasAttribute(SUMO_ATTR_END) && GNEAttributeCarrier::canParse<double>(i->getAttribute(SUMO_ATTR_END))) {
175                 sortedChilds.back().first.second = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_END));
176             } else {
177                 sortedChilds.back().first.second = sortedChilds.back().first.first;
178             }
179         }
180         // sort childs
181         std::sort(sortedChilds.begin(), sortedChilds.end());
182         // make sure that number of sorted childs is the same as the additional childs
183         if (sortedChilds.size() == myAdditionalChilds.size()) {
184             myAdditionalChilds.clear();
185             for (auto i : sortedChilds) {
186                 myAdditionalChilds.push_back(i.second);
187             }
188         } else {
189             throw ProcessError("Some additional childs were lost during sorting");
190         }
191     }
192 }
193 
194 
195 bool
checkAdditionalChildsOverlapping() const196 GNEHierarchicalElementChilds::checkAdditionalChildsOverlapping() const {
197     // declare a vector to keep sorted childs
198     std::vector<std::pair<std::pair<double, double>, GNEAdditional*> > sortedChilds;
199     // iterate over additional childs
200     for (auto i : myAdditionalChilds) {
201         sortedChilds.push_back(std::make_pair(std::make_pair(0., 0.), i));
202         // set begin/start attribute
203         if (i->getTagProperty().hasAttribute(SUMO_ATTR_TIME) && GNEAttributeCarrier::canParse<double>(i->getAttribute(SUMO_ATTR_TIME))) {
204             sortedChilds.back().first.first = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_TIME));
205         } else if (i->getTagProperty().hasAttribute(SUMO_ATTR_BEGIN) && GNEAttributeCarrier::canParse<double>(i->getAttribute(SUMO_ATTR_BEGIN))) {
206             sortedChilds.back().first.first = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_BEGIN));
207         }
208         // set end attribute
209         if (i->getTagProperty().hasAttribute(SUMO_ATTR_END) && GNEAttributeCarrier::canParse<double>(i->getAttribute(SUMO_ATTR_END))) {
210             sortedChilds.back().first.second = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_END));
211         } else {
212             sortedChilds.back().first.second = sortedChilds.back().first.first;
213         }
214     }
215     // sort childs
216     std::sort(sortedChilds.begin(), sortedChilds.end());
217     // make sure that number of sorted childs is the same as the additional childs
218     if (sortedChilds.size() == myAdditionalChilds.size()) {
219         if (sortedChilds.size() <= 1) {
220             return true;
221         } else {
222             // check overlapping
223             for (int i = 0; i < (int)sortedChilds.size() - 1; i++) {
224                 if (sortedChilds.at(i).first.second > sortedChilds.at(i + 1).first.first) {
225                     return false;
226                 }
227             }
228         }
229         return true;
230     } else {
231         throw ProcessError("Some additional childs were lost during sorting");
232     }
233 }
234 
235 
236 void
addDemandElementChild(GNEDemandElement * demandElement)237 GNEHierarchicalElementChilds::addDemandElementChild(GNEDemandElement* demandElement) {
238     // Check if demand element is valid
239     if (demandElement == nullptr) {
240         throw InvalidArgument("Trying to add an empty demand element child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
241     } else {
242         // add it in demandElement child container
243         myDemandElementChilds.push_back(demandElement);
244         // Check if childs has to be sorted automatically
245         if (myAC->getTagProperty().canAutomaticSortChilds()) {
246             sortDemandElementChilds();
247         }
248         // update demandElement parent after add demandElement (note: by default non-implemented)
249         updateDemandElementParent();
250         // update geometry (for set geometry of lines between Parents and Childs)
251         if (demandElement->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
252             updateGeometry(true);
253         }
254     }
255 }
256 
257 
258 void
removeDemandElementChild(GNEDemandElement * demandElement)259 GNEHierarchicalElementChilds::removeDemandElementChild(GNEDemandElement* demandElement) {
260     // First check that demandElement was already inserted
261     auto it = std::find(myDemandElementChilds.begin(), myDemandElementChilds.end(), demandElement);
262     if (it == myDemandElementChilds.end()) {
263         throw ProcessError(demandElement->getTagStr() + " with ID='" + demandElement->getID() + "' doesn't exist in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
264     } else {
265         myDemandElementChilds.erase(it);
266         // Check if childs has to be sorted automatically
267         if (myAC->getTagProperty().canAutomaticSortChilds()) {
268             sortDemandElementChilds();
269         }
270         // update demandElement parent after add demandElement (note: by default non-implemented)
271         updateDemandElementParent();
272         // update geometry (for remove geometry of lines between Parents and Childs)
273         if (demandElement->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
274             updateGeometry(true);
275         }
276     }
277 }
278 
279 
280 const std::vector<GNEDemandElement*>&
getDemandElementChilds() const281 GNEHierarchicalElementChilds::getDemandElementChilds() const {
282     return myDemandElementChilds;
283 }
284 
285 
286 void
sortDemandElementChilds()287 GNEHierarchicalElementChilds::sortDemandElementChilds() {
288     // by default empty
289 }
290 
291 
292 bool
checkDemandElementChildsOverlapping() const293 GNEHierarchicalElementChilds::checkDemandElementChildsOverlapping() const {
294     return true;
295 }
296 
297 
298 void
addEdgeChild(GNEEdge * edge)299 GNEHierarchicalElementChilds::addEdgeChild(GNEEdge* edge) {
300     // Check that edge is valid and doesn't exist previously
301     if (edge == nullptr) {
302         throw InvalidArgument("Trying to add an empty edge child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
303     } else {
304         myEdgeChilds.push_back(edge);
305         // only execute post operations if update geometry is enabled
306         if (edge->getNet()->isUpdateGeometryEnabled()) {
307             updateGeometry(true);
308         }
309     }
310 }
311 
312 
313 void
removeEdgeChild(GNEEdge * edge)314 GNEHierarchicalElementChilds::removeEdgeChild(GNEEdge* edge) {
315     // Check that edge is valid and exist previously
316     if (edge == nullptr) {
317         throw InvalidArgument("Trying to remove an empty edge child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
318     } else if (std::find(myEdgeChilds.begin(), myEdgeChilds.end(), edge) == myEdgeChilds.end()) {
319         throw InvalidArgument("Trying to remove a non previously inserted edge child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
320     } else {
321         myEdgeChilds.erase(std::find(myEdgeChilds.begin(), myEdgeChilds.end(), edge));
322         // update connections geometry
323         myChildConnections.update();
324     }
325 }
326 
327 
328 const std::vector<GNEEdge*>&
getEdgeChilds() const329 GNEHierarchicalElementChilds::getEdgeChilds() const {
330     return myEdgeChilds;
331 }
332 
333 
334 void
addLaneChild(GNELane * lane)335 GNEHierarchicalElementChilds::addLaneChild(GNELane* lane) {
336     // Check if lane is valid
337     if (lane == nullptr) {
338         throw InvalidArgument("Trying to add an empty lane child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
339     } else {
340         myLaneChilds.push_back(lane);
341         // update connections geometry
342         myChildConnections.update();
343     }
344 }
345 
346 
347 void
removeLaneChild(GNELane * lane)348 GNEHierarchicalElementChilds::removeLaneChild(GNELane* lane) {
349     // Check if lane is valid
350     if (lane == nullptr) {
351         throw InvalidArgument("Trying to remove an empty lane child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
352     } else {
353         myLaneChilds.erase(std::find(myLaneChilds.begin(), myLaneChilds.end(), lane));
354         // update connections geometry
355         myChildConnections.update();
356     }
357 }
358 
359 
360 const std::vector<GNELane*>&
getLaneChilds() const361 GNEHierarchicalElementChilds::getLaneChilds() const {
362     return myLaneChilds;
363 }
364 
365 
366 void
addShapeChild(GNEShape * shape)367 GNEHierarchicalElementChilds::addShapeChild(GNEShape* shape) {
368     // Check that shape is valid and doesn't exist previously
369     if (shape == nullptr) {
370         throw InvalidArgument("Trying to add an empty shape child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
371     } else if (std::find(myShapeChilds.begin(), myShapeChilds.end(), shape) != myShapeChilds.end()) {
372         throw InvalidArgument("Trying to add a duplicate shape child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
373     } else {
374         myShapeChilds.push_back(shape);
375         // update connections geometry
376         myChildConnections.update();
377     }
378 }
379 
380 
381 void
removeShapeChild(GNEShape * shape)382 GNEHierarchicalElementChilds::removeShapeChild(GNEShape* shape) {
383     // Check that shape is valid and exist previously
384     if (shape == nullptr) {
385         throw InvalidArgument("Trying to remove an empty shape child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
386     } else if (std::find(myShapeChilds.begin(), myShapeChilds.end(), shape) == myShapeChilds.end()) {
387         throw InvalidArgument("Trying to remove a non previously inserted shape child in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
388     } else {
389         myShapeChilds.erase(std::find(myShapeChilds.begin(), myShapeChilds.end(), shape));
390         // update connections geometry
391         myChildConnections.update();
392     }
393 }
394 
395 
396 const std::vector<GNEShape*>&
getShapeChilds() const397 GNEHierarchicalElementChilds::getShapeChilds() const {
398     return myShapeChilds;
399 }
400 
401 
402 void
updateAdditionalParent()403 GNEHierarchicalElementChilds::updateAdditionalParent() {
404     // by default nothing to do
405 }
406 
407 
408 void
updateDemandElementParent()409 GNEHierarchicalElementChilds::updateDemandElementParent() {
410     // by default nothing to do
411 }
412 
413 
414 void
changeEdgeChilds(GNEAdditional * elementChild,const std::string & newEdgeIDs)415 GNEHierarchicalElementChilds::changeEdgeChilds(GNEAdditional* elementChild, const std::string& newEdgeIDs) {
416     // remove demandElement of edge childs
417     for (const auto& i : myEdgeChilds) {
418         i->removeAdditionalParent(elementChild);
419     }
420     // obtain new child edges (note: it can be empty)
421     myEdgeChilds = GNEAttributeCarrier::parse<std::vector<GNEEdge*> >(elementChild->getViewNet()->getNet(), newEdgeIDs);
422     // add demandElement into edge parents
423     for (const auto& i : myEdgeChilds) {
424         i->addAdditionalParent(elementChild);
425     }
426     // update connections geometry
427     myChildConnections.update();
428 }
429 
430 
431 void
changeLaneChilds(GNEAdditional * elementChild,const std::string & newLaneIDs)432 GNEHierarchicalElementChilds::changeLaneChilds(GNEAdditional* elementChild, const std::string& newLaneIDs) {
433     // remove demandElement of lane childs
434     for (const auto& i : myLaneChilds) {
435         i->removeAdditionalParent(elementChild);
436     }
437     // obtain new child lanes (note: it can be empty)
438     myLaneChilds = GNEAttributeCarrier::parse<std::vector<GNELane*> >(elementChild->getViewNet()->getNet(), newLaneIDs);
439     // add demandElement into lane parents
440     for (const auto& i : myLaneChilds) {
441         i->addAdditionalParent(elementChild);
442     }
443     // update connections geometry
444     myChildConnections.update();
445 }
446 
447 // ---------------------------------------------------------------------------
448 // GNEHierarchicalElementChilds::ChildConnections - methods
449 // ---------------------------------------------------------------------------
450 
ChildConnections(GNEHierarchicalElementChilds * hierarchicalElement)451 GNEHierarchicalElementChilds::ChildConnections::ChildConnections(GNEHierarchicalElementChilds* hierarchicalElement) :
452     myHierarchicalElement(hierarchicalElement) {}
453 
454 
455 void
update()456 GNEHierarchicalElementChilds::ChildConnections::update() {
457     // first clear connection positions
458     connectionPositions.clear();
459     symbolsPositionAndRotation.clear();
460 
461     // calculate position and rotation of every simbol for every edge
462     for (const auto& i : myHierarchicalElement->myEdgeChilds) {
463         for (auto j : i->getLanes()) {
464             std::pair<Position, double> posRot;
465             // set position and lenght depending of shape's lengt
466             if (j->getShape().length() - 6 > 0) {
467                 posRot.first = j->getShape().positionAtOffset(j->getShape().length() - 6);
468                 posRot.second = j->getShape().rotationDegreeAtOffset(j->getShape().length() - 6);
469             } else {
470                 posRot.first = j->getShape().positionAtOffset(j->getShape().length());
471                 posRot.second = j->getShape().rotationDegreeAtOffset(j->getShape().length());
472             }
473             symbolsPositionAndRotation.push_back(posRot);
474         }
475     }
476 
477     // calculate position and rotation of every symbol for every lane
478     for (const auto& i : myHierarchicalElement->myLaneChilds) {
479         std::pair<Position, double> posRot;
480         // set position and lenght depending of shape's lengt
481         if (i->getShape().length() - 6 > 0) {
482             posRot.first = i->getShape().positionAtOffset(i->getShape().length() - 6);
483             posRot.second = i->getShape().rotationDegreeAtOffset(i->getShape().length() - 6);
484         } else {
485             posRot.first = i->getShape().positionAtOffset(i->getShape().length());
486             posRot.second = i->getShape().rotationDegreeAtOffset(i->getShape().length());
487         }
488         symbolsPositionAndRotation.push_back(posRot);
489     }
490 
491     // calculate position for every additional child
492     for (const auto& i : myHierarchicalElement->myAdditionalChilds) {
493         // check that position is different of position
494         if (i->getPositionInView() != myHierarchicalElement->getPositionInView()) {
495             std::vector<Position> posConnection;
496             double A = std::abs(i->getPositionInView().x() - myHierarchicalElement->getPositionInView().x());
497             double B = std::abs(i->getPositionInView().y() - myHierarchicalElement->getPositionInView().y());
498             // Set positions of connection's vertex. Connection is build from Entry to E3
499             posConnection.push_back(i->getPositionInView());
500             if (myHierarchicalElement->getPositionInView().x() > i->getPositionInView().x()) {
501                 if (myHierarchicalElement->getPositionInView().y() > i->getPositionInView().y()) {
502                     posConnection.push_back(Position(i->getPositionInView().x() + A, i->getPositionInView().y()));
503                 } else {
504                     posConnection.push_back(Position(i->getPositionInView().x(), i->getPositionInView().y() - B));
505                 }
506             } else {
507                 if (myHierarchicalElement->getPositionInView().y() > i->getPositionInView().y()) {
508                     posConnection.push_back(Position(i->getPositionInView().x(), i->getPositionInView().y() + B));
509                 } else {
510                     posConnection.push_back(Position(i->getPositionInView().x() - A, i->getPositionInView().y()));
511                 }
512             }
513             posConnection.push_back(myHierarchicalElement->getPositionInView());
514             connectionPositions.push_back(posConnection);
515         }
516     }
517 
518     // calculate geometry for connections between parent and childs
519     for (const auto& i : symbolsPositionAndRotation) {
520         std::vector<Position> posConnection;
521         double A = std::abs(i.first.x() - myHierarchicalElement->getPositionInView().x());
522         double B = std::abs(i.first.y() - myHierarchicalElement->getPositionInView().y());
523         // Set positions of connection's vertex. Connection is build from Entry to E3
524         posConnection.push_back(i.first);
525         if (myHierarchicalElement->getPositionInView().x() > i.first.x()) {
526             if (myHierarchicalElement->getPositionInView().y() > i.first.y()) {
527                 posConnection.push_back(Position(i.first.x() + A, i.first.y()));
528             } else {
529                 posConnection.push_back(Position(i.first.x(), i.first.y() - B));
530             }
531         } else {
532             if (myHierarchicalElement->getPositionInView().y() > i.first.y()) {
533                 posConnection.push_back(Position(i.first.x(), i.first.y() + B));
534             } else {
535                 posConnection.push_back(Position(i.first.x() - A, i.first.y()));
536             }
537         }
538         posConnection.push_back(myHierarchicalElement->getPositionInView());
539         connectionPositions.push_back(posConnection);
540     }
541 }
542 
543 
544 void
draw(GUIGlObjectType parentType) const545 GNEHierarchicalElementChilds::ChildConnections::draw(GUIGlObjectType parentType) const {
546     // Iterate over myConnectionPositions
547     for (const auto& i : connectionPositions) {
548         // Add a draw matrix
549         glPushMatrix();
550         // traslate in the Z axis
551         glTranslated(0, 0, parentType - 0.01);
552         // Set color of the base
553         GLHelper::setColor(RGBColor(255, 235, 0));
554         for (auto j = i.begin(); (j + 1) != i.end(); j++) {
555             // Draw Lines
556             GLHelper::drawLine((*j), (*(j + 1)));
557         }
558         // Pop draw matrix
559         glPopMatrix();
560     }
561 }
562 
563 /****************************************************************************/
564