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