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    GNEHierarchicalElementParents.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 "GNEHierarchicalElementParents.h"
43 
44 // ===========================================================================
45 // member method definitions
46 // ===========================================================================
47 
GNEHierarchicalElementParents(GNEAttributeCarrier * AC,const std::vector<GNEEdge * > & edgeParents,const std::vector<GNELane * > & laneParents,const std::vector<GNEShape * > & shapeParents,const std::vector<GNEAdditional * > & additionalParents,const std::vector<GNEDemandElement * > & demandElementParents)48 GNEHierarchicalElementParents::GNEHierarchicalElementParents(GNEAttributeCarrier* AC,
49         const std::vector<GNEEdge*>& edgeParents,
50         const std::vector<GNELane*>& laneParents,
51         const std::vector<GNEShape*>& shapeParents,
52         const std::vector<GNEAdditional*>& additionalParents,
53         const std::vector<GNEDemandElement*>& demandElementParents) :
54     myParentConnections(this),
55     myEdgeParents(edgeParents),
56     myLaneParents(laneParents),
57     myShapeParents(shapeParents),
58     myAdditionalParents(additionalParents),
59     myDemandElementParents(demandElementParents),
60     myAC(AC) {
61 }
62 
63 
~GNEHierarchicalElementParents()64 GNEHierarchicalElementParents::~GNEHierarchicalElementParents() {}
65 
66 
67 void
addAdditionalParent(GNEAdditional * additional)68 GNEHierarchicalElementParents::addAdditionalParent(GNEAdditional* additional) {
69     // First check that additional wasn't already inserted
70     if (std::find(myAdditionalParents.begin(), myAdditionalParents.end(), additional) != myAdditionalParents.end()) {
71         throw ProcessError(additional->getTagStr() + " with ID='" + additional->getID() + "' was already inserted in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
72     } else {
73         myAdditionalParents.push_back(additional);
74         // only execute post operations if update geometry is enabled
75         if (additional->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
76             updateGeometry(true);
77         }
78     }
79 }
80 
81 
82 void
removeAdditionalParent(GNEAdditional * additional)83 GNEHierarchicalElementParents::removeAdditionalParent(GNEAdditional* additional) {
84     // First check that additional was already inserted
85     auto it = std::find(myAdditionalParents.begin(), myAdditionalParents.end(), additional);
86     if (it == myAdditionalParents.end()) {
87         throw ProcessError(additional->getTagStr() + " with ID='" + additional->getID() + "' doesn't exist in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
88     } else {
89         myAdditionalParents.erase(it);
90         // only execute post operations if update geometry is enabled
91         if (additional->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
92             updateGeometry(true);
93         }
94     }
95 }
96 
97 
98 const std::vector<GNEAdditional*>&
getAdditionalParents() const99 GNEHierarchicalElementParents::getAdditionalParents() const {
100     return myAdditionalParents;
101 }
102 
103 
104 void
addDemandElementParent(GNEDemandElement * demandElement)105 GNEHierarchicalElementParents::addDemandElementParent(GNEDemandElement* demandElement) {
106     // First check that demandElement wasn't already inserted
107     if (std::find(myDemandElementParents.begin(), myDemandElementParents.end(), demandElement) != myDemandElementParents.end()) {
108         throw ProcessError(demandElement->getTagStr() + " with ID='" + demandElement->getID() + "' was already inserted in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
109     } else {
110         myDemandElementParents.push_back(demandElement);
111         // update geometry (for set geometry of lines between Parents and Parents)
112         if (demandElement->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
113             updateGeometry(true);
114         }
115     }
116 }
117 
118 
119 void
removeDemandElementParent(GNEDemandElement * demandElement)120 GNEHierarchicalElementParents::removeDemandElementParent(GNEDemandElement* demandElement) {
121     // First check that demandElement was already inserted
122     auto it = std::find(myDemandElementParents.begin(), myDemandElementParents.end(), demandElement);
123     if (it == myDemandElementParents.end()) {
124         throw ProcessError(demandElement->getTagStr() + " with ID='" + demandElement->getID() + "' doesn't exist in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
125     } else {
126         myDemandElementParents.erase(it);
127         // update geometry (for remove geometry of lines between Parents and Parents)
128         if (demandElement->getViewNet()->getNet()->isUpdateGeometryEnabled()) {
129             updateGeometry(true);
130         }
131     }
132 }
133 
134 
135 const std::vector<GNEDemandElement*>&
getDemandElementParents() const136 GNEHierarchicalElementParents::getDemandElementParents() const {
137     return myDemandElementParents;
138 }
139 
140 
141 void
addEdgeParent(GNEEdge * edge)142 GNEHierarchicalElementParents::addEdgeParent(GNEEdge* edge) {
143     // Check that edge is valid and doesn't exist previously
144     if (edge == nullptr) {
145         throw InvalidArgument("Trying to add an empty " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
146     } else if (std::find(myEdgeParents.begin(), myEdgeParents.end(), edge) != myEdgeParents.end()) {
147         throw InvalidArgument("Trying to add a duplicate " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
148     } else {
149         myEdgeParents.push_back(edge);
150     }
151 }
152 
153 
154 void
removeEdgeParent(GNEEdge * edge)155 GNEHierarchicalElementParents::removeEdgeParent(GNEEdge* edge) {
156     // Check that edge is valid and exist previously
157     if (edge == nullptr) {
158         throw InvalidArgument("Trying to remove an empty " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
159     } else if (std::find(myEdgeParents.begin(), myEdgeParents.end(), edge) == myEdgeParents.end()) {
160         throw InvalidArgument("Trying to remove a non previously inserted " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
161     } else {
162         myEdgeParents.erase(std::find(myEdgeParents.begin(), myEdgeParents.end(), edge));
163     }
164 }
165 
166 
167 const std::vector<GNEEdge*>&
getEdgeParents() const168 GNEHierarchicalElementParents::getEdgeParents() const {
169     return myEdgeParents;
170 }
171 
172 
173 void
addLaneParent(GNELane * lane)174 GNEHierarchicalElementParents::addLaneParent(GNELane* lane) {
175     // Check that lane is valid and doesn't exist previously
176     if (lane == nullptr) {
177         throw InvalidArgument("Trying to add an empty " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
178     } else if (std::find(myLaneParents.begin(), myLaneParents.end(), lane) != myLaneParents.end()) {
179         throw InvalidArgument("Trying to add a duplicate " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
180     } else {
181         myLaneParents.push_back(lane);
182     }
183 }
184 
185 
186 void
removeLaneParent(GNELane * lane)187 GNEHierarchicalElementParents::removeLaneParent(GNELane* lane) {
188     // Check that lane is valid and exist previously
189     if (lane == nullptr) {
190         throw InvalidArgument("Trying to remove an empty " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
191     } else if (std::find(myLaneParents.begin(), myLaneParents.end(), lane) == myLaneParents.end()) {
192         throw InvalidArgument("Trying to remove a non previously inserted " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
193     } else {
194         myLaneParents.erase(std::find(myLaneParents.begin(), myLaneParents.end(), lane));
195     }
196 }
197 
198 
199 const std::vector<GNELane*>&
getLaneParents() const200 GNEHierarchicalElementParents::getLaneParents() const {
201     return myLaneParents;
202 }
203 
204 
205 void
addShapeParent(GNEShape * shape)206 GNEHierarchicalElementParents::addShapeParent(GNEShape* shape) {
207     // Check that shape is valid and doesn't exist previously
208     if (shape == nullptr) {
209         throw InvalidArgument("Trying to add an empty " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
210     } else if (std::find(myShapeParents.begin(), myShapeParents.end(), shape) != myShapeParents.end()) {
211         throw InvalidArgument("Trying to add a duplicate " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
212     } else {
213         myShapeParents.push_back(shape);
214     }
215 }
216 
217 
218 void
removeShapeParent(GNEShape * shape)219 GNEHierarchicalElementParents::removeShapeParent(GNEShape* shape) {
220     // Check that shape is valid and exist previously
221     if (shape == nullptr) {
222         throw InvalidArgument("Trying to remove an empty " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
223     } else if (std::find(myShapeParents.begin(), myShapeParents.end(), shape) == myShapeParents.end()) {
224         throw InvalidArgument("Trying to remove a non previously inserted " + toString(SUMO_TAG_EDGE) + " parent in " + myAC->getTagStr() + " with ID='" + myAC->getID() + "'");
225     } else {
226         myShapeParents.erase(std::find(myShapeParents.begin(), myShapeParents.end(), shape));
227     }
228 }
229 
230 
231 const std::vector<GNEShape*>&
getShapeParents() const232 GNEHierarchicalElementParents::getShapeParents() const {
233     return myShapeParents;
234 }
235 
236 // ---------------------------------------------------------------------------
237 // GNEHierarchicalElementParents::ParentConnections - methods
238 // ---------------------------------------------------------------------------
239 
ParentConnections(GNEHierarchicalElementParents * hierarchicalElement)240 GNEHierarchicalElementParents::ParentConnections::ParentConnections(GNEHierarchicalElementParents* hierarchicalElement) :
241     myHierarchicalElement(hierarchicalElement) {}
242 
243 
244 void
update()245 GNEHierarchicalElementParents::ParentConnections::update() {
246     // first clear connection positions
247     connectionPositions.clear();
248     symbolsPositionAndRotation.clear();
249 
250     // calculate position and rotation of every simbol for every edge
251     for (auto i : myHierarchicalElement->myEdgeParents) {
252         for (auto j : i->getLanes()) {
253             std::pair<Position, double> posRot;
254             // set position and lenght depending of shape's lengt
255             if (j->getShape().length() - 6 > 0) {
256                 posRot.first = j->getShape().positionAtOffset(j->getShape().length() - 6);
257                 posRot.second = j->getShape().rotationDegreeAtOffset(j->getShape().length() - 6);
258             } else {
259                 posRot.first = j->getShape().positionAtOffset(j->getShape().length());
260                 posRot.second = j->getShape().rotationDegreeAtOffset(j->getShape().length());
261             }
262             symbolsPositionAndRotation.push_back(posRot);
263         }
264     }
265 
266     // calculate position and rotation of every symbol for every lane
267     for (auto i : myHierarchicalElement->myLaneParents) {
268         std::pair<Position, double> posRot;
269         // set position and lenght depending of shape's lengt
270         if (i->getShape().length() - 6 > 0) {
271             posRot.first = i->getShape().positionAtOffset(i->getShape().length() - 6);
272             posRot.second = i->getShape().rotationDegreeAtOffset(i->getShape().length() - 6);
273         } else {
274             posRot.first = i->getShape().positionAtOffset(i->getShape().length());
275             posRot.second = i->getShape().rotationDegreeAtOffset(i->getShape().length());
276         }
277         symbolsPositionAndRotation.push_back(posRot);
278     }
279 
280     // calculate position for every additional parent
281     for (auto i : myHierarchicalElement->myAdditionalParents) {
282         // check that position is different of position
283         if (i->getPositionInView() != myHierarchicalElement->getPositionInView()) {
284             std::vector<Position> posConnection;
285             double A = std::abs(i->getPositionInView().x() - myHierarchicalElement->getPositionInView().x());
286             double B = std::abs(i->getPositionInView().y() - myHierarchicalElement->getPositionInView().y());
287             // Set positions of connection's vertex. Connection is build from Entry to E3
288             posConnection.push_back(i->getPositionInView());
289             if (myHierarchicalElement->getPositionInView().x() > i->getPositionInView().x()) {
290                 if (myHierarchicalElement->getPositionInView().y() > i->getPositionInView().y()) {
291                     posConnection.push_back(Position(i->getPositionInView().x() + A, i->getPositionInView().y()));
292                 } else {
293                     posConnection.push_back(Position(i->getPositionInView().x(), i->getPositionInView().y() - B));
294                 }
295             } else {
296                 if (myHierarchicalElement->getPositionInView().y() > i->getPositionInView().y()) {
297                     posConnection.push_back(Position(i->getPositionInView().x(), i->getPositionInView().y() + B));
298                 } else {
299                     posConnection.push_back(Position(i->getPositionInView().x() - A, i->getPositionInView().y()));
300                 }
301             }
302             posConnection.push_back(myHierarchicalElement->getPositionInView());
303             connectionPositions.push_back(posConnection);
304         }
305     }
306 
307     // calculate geometry for connections between parent and parents
308     for (auto i : symbolsPositionAndRotation) {
309         std::vector<Position> posConnection;
310         double A = std::abs(i.first.x() - myHierarchicalElement->getPositionInView().x());
311         double B = std::abs(i.first.y() - myHierarchicalElement->getPositionInView().y());
312         // Set positions of connection's vertex. Connection is build from Entry to E3
313         posConnection.push_back(i.first);
314         if (myHierarchicalElement->getPositionInView().x() > i.first.x()) {
315             if (myHierarchicalElement->getPositionInView().y() > i.first.y()) {
316                 posConnection.push_back(Position(i.first.x() + A, i.first.y()));
317             } else {
318                 posConnection.push_back(Position(i.first.x(), i.first.y() - B));
319             }
320         } else {
321             if (myHierarchicalElement->getPositionInView().y() > i.first.y()) {
322                 posConnection.push_back(Position(i.first.x(), i.first.y() + B));
323             } else {
324                 posConnection.push_back(Position(i.first.x() - A, i.first.y()));
325             }
326         }
327         posConnection.push_back(myHierarchicalElement->getPositionInView());
328         connectionPositions.push_back(posConnection);
329     }
330 
331 }
332 
333 
334 void
draw(GUIGlObjectType parentType) const335 GNEHierarchicalElementParents::ParentConnections::draw(GUIGlObjectType parentType) const {
336     // Iterate over myConnectionPositions
337     for (auto i : connectionPositions) {
338         // Add a draw matrix
339         glPushMatrix();
340         // traslate in the Z axis
341         glTranslated(0, 0, parentType - 0.01);
342         // Set color of the base
343         GLHelper::setColor(RGBColor(255, 235, 0));
344         for (auto j = i.begin(); (j + 1) != i.end(); j++) {
345             // Draw Lines
346             GLHelper::drawLine((*j), (*(j + 1)));
347         }
348         // Pop draw matrix
349         glPopMatrix();
350     }
351 }
352 
353 // ---------------------------------------------------------------------------
354 // GNEHierarchicalElementParents - protected methods
355 // ---------------------------------------------------------------------------
356 
357 
358 void
changeEdgeParents(GNEShape * elementChild,const std::string & newEdgeIDs)359 GNEHierarchicalElementParents::changeEdgeParents(GNEShape* elementChild, const std::string& newEdgeIDs) {
360     // remove additional of edge parents
361     for (const auto& i : myEdgeParents) {
362         i->removeShapeChild(elementChild);
363     }
364     // obtain new parent edges
365     myEdgeParents = GNEAttributeCarrier::parse<std::vector<GNEEdge*> >(elementChild->getNet(), newEdgeIDs);
366     // check that lane parets aren't empty
367     if (myEdgeParents.empty()) {
368         throw InvalidArgument("New list of edge parents cannot be empty");
369     } else {
370         // add additional into edge parents
371         for (const auto& i : myEdgeParents) {
372             i->addShapeChild(elementChild);
373         }
374     }
375 }
376 
377 
378 void
changeEdgeParents(GNEAdditional * elementChild,const std::string & newEdgeIDs)379 GNEHierarchicalElementParents::changeEdgeParents(GNEAdditional* elementChild, const std::string& newEdgeIDs) {
380     // remove additional of edge parents
381     for (const auto& i : myEdgeParents) {
382         i->removeAdditionalChild(elementChild);
383     }
384     // obtain new parent edges
385     myEdgeParents = GNEAttributeCarrier::parse<std::vector<GNEEdge*> >(elementChild->getViewNet()->getNet(), newEdgeIDs);
386     // check that lane parets aren't empty
387     if (myEdgeParents.empty()) {
388         throw InvalidArgument("New list of edge parents cannot be empty");
389     } else {
390         // add additional into edge parents
391         for (const auto& i : myEdgeParents) {
392             i->addAdditionalChild(elementChild);
393         }
394     }
395 }
396 
397 
398 void
changeEdgeParents(GNEDemandElement * elementChild,const std::string & newEdgeIDs)399 GNEHierarchicalElementParents::changeEdgeParents(GNEDemandElement* elementChild, const std::string& newEdgeIDs) {
400     // remove demandElement of edge parents
401     for (const auto& i : myEdgeParents) {
402         i->removeDemandElementChild(elementChild);
403     }
404     // obtain new parent edges
405     myEdgeParents = GNEAttributeCarrier::parse<std::vector<GNEEdge*> >(elementChild->getViewNet()->getNet(), newEdgeIDs);
406     // check that lane parets aren't empty
407     if (myEdgeParents.empty()) {
408         throw InvalidArgument("New list of edge parents cannot be empty");
409     } else {
410         // add demandElement into edge parents
411         for (const auto& i : myEdgeParents) {
412             i->addDemandElementChild(elementChild);
413         }
414     }
415 }
416 
417 
418 void
changeLaneParents(GNEAdditional * elementChild,const std::string & newLaneIDs)419 GNEHierarchicalElementParents::changeLaneParents(GNEAdditional* elementChild, const std::string& newLaneIDs) {
420     // remove additional of edge parents
421     for (const auto& i : myLaneParents) {
422         i->removeAdditionalChild(elementChild);
423     }
424     // obtain new parent edges
425     myLaneParents = GNEAttributeCarrier::parse<std::vector<GNELane*> >(elementChild->getViewNet()->getNet(), newLaneIDs);
426     // check that lane parets aren't empty
427     if (myLaneParents.empty()) {
428         throw InvalidArgument("New list of lane parents cannot be empty");
429     } else {
430         // add additional into edge parents
431         for (const auto& i : myLaneParents) {
432             i->addAdditionalChild(elementChild);
433         }
434     }
435 }
436 
437 
438 void
changeLaneParents(GNEDemandElement * elementChild,const std::string & newLaneIDs)439 GNEHierarchicalElementParents::changeLaneParents(GNEDemandElement* elementChild, const std::string& newLaneIDs) {
440     // remove demandElement of edge parents
441     for (const auto& i : myLaneParents) {
442         i->removeDemandElementChild(elementChild);
443     }
444     // obtain new parent edges
445     myLaneParents = GNEAttributeCarrier::parse<std::vector<GNELane*> >(elementChild->getViewNet()->getNet(), newLaneIDs);
446     // check that lane parets aren't empty
447     if (myLaneParents.empty()) {
448         throw InvalidArgument("New list of lane parents cannot be empty");
449     } else {
450         // add demandElement into edge parents
451         for (const auto& i : myLaneParents) {
452             i->addDemandElementChild(elementChild);
453         }
454     }
455 }
456 
457 
458 void
changeLaneParents(GNEShape * elementChild,const std::string & newLaneIDs)459 GNEHierarchicalElementParents::changeLaneParents(GNEShape* elementChild, const std::string& newLaneIDs) {
460     // remove demandElement of edge parents
461     for (const auto& i : myLaneParents) {
462         i->removeShapeChild(elementChild);
463     }
464     // obtain new parent edges
465     myLaneParents = GNEAttributeCarrier::parse<std::vector<GNELane*> >(elementChild->getNet(), newLaneIDs);
466     // check that lane parets aren't empty
467     if (myLaneParents.empty()) {
468         throw InvalidArgument("New list of lane parents cannot be empty");
469     } else {
470         // add demandElement into edge parents
471         for (const auto& i : myLaneParents) {
472             i->addShapeChild(elementChild);
473         }
474     }
475 }
476 
477 
478 void
changeAdditionalParent(GNEShape * shapeTobeChanged,const std::string & newAdditionalParentID,int additionalParentIndex)479 GNEHierarchicalElementParents::changeAdditionalParent(GNEShape* shapeTobeChanged, const std::string& newAdditionalParentID, int additionalParentIndex) {
480     if ((int)myAdditionalParents.size() < additionalParentIndex) {
481         throw InvalidArgument(myAC->getTagStr() + " with ID '" + myAC->getID() + "' doesn't have " + toString(additionalParentIndex) + " additional parents");
482     } else {
483         // remove additional of the childs of parent additional
484         myAdditionalParents.at(additionalParentIndex)->removeShapeChild(shapeTobeChanged);
485         // set new additional parent
486         myAdditionalParents.at(additionalParentIndex) = shapeTobeChanged->getNet()->retrieveAdditional(myAdditionalParents.at(additionalParentIndex)->getTagProperty().getTag(), newAdditionalParentID);
487         // add additional int the childs of parent additional
488         myAdditionalParents.at(additionalParentIndex)->addShapeChild(shapeTobeChanged);
489         // update geometry after inserting
490         updateGeometry(true);
491     }
492 }
493 
494 
495 void
changeAdditionalParent(GNEAdditional * additionalTobeChanged,const std::string & newAdditionalParentID,int additionalParentIndex)496 GNEHierarchicalElementParents::changeAdditionalParent(GNEAdditional* additionalTobeChanged, const std::string& newAdditionalParentID, int additionalParentIndex) {
497     if ((int)myAdditionalParents.size() < additionalParentIndex) {
498         throw InvalidArgument(myAC->getTagStr() + " with ID '" + myAC->getID() + "' doesn't have " + toString(additionalParentIndex) + " additional parents");
499     } else {
500         // remove additional of the childs of parent additional
501         myAdditionalParents.at(additionalParentIndex)->removeAdditionalChild(additionalTobeChanged);
502         // set new additional parent
503         myAdditionalParents.at(additionalParentIndex) = additionalTobeChanged->getViewNet()->getNet()->retrieveAdditional(myAdditionalParents.at(additionalParentIndex)->getTagProperty().getTag(), newAdditionalParentID);
504         // add additional int the childs of parent additional
505         myAdditionalParents.at(additionalParentIndex)->addAdditionalChild(additionalTobeChanged);
506         // update geometry after inserting
507         updateGeometry(true);
508     }
509 }
510 
511 
512 void
changeAdditionalParent(GNEDemandElement * demandElementTobeChanged,const std::string & newAdditionalParentID,int additionalParentIndex)513 GNEHierarchicalElementParents::changeAdditionalParent(GNEDemandElement* demandElementTobeChanged, const std::string& newAdditionalParentID, int additionalParentIndex) {
514     if ((int)myAdditionalParents.size() < additionalParentIndex) {
515         throw InvalidArgument(myAC->getTagStr() + " with ID '" + myAC->getID() + "' doesn't have " + toString(additionalParentIndex) + " additional parents");
516     } else {
517         // remove demand element of the childs of parent additional
518         myAdditionalParents.at(additionalParentIndex)->removeDemandElementChild(demandElementTobeChanged);
519         // set new demand element parent
520         myAdditionalParents.at(additionalParentIndex) = demandElementTobeChanged->getViewNet()->getNet()->retrieveAdditional(myAdditionalParents.at(additionalParentIndex)->getTagProperty().getTag(), newAdditionalParentID);
521         // add demand element int the childs of parent additional
522         myAdditionalParents.at(additionalParentIndex)->removeDemandElementChild(demandElementTobeChanged);
523         // update geometry after inserting
524         updateGeometry(true);
525     }
526 }
527 
528 
529 void
changeDemandElementParent(GNEShape * shapeTobeChanged,const std::string & newDemandElementParentID,int demandElementParentIndex)530 GNEHierarchicalElementParents::changeDemandElementParent(GNEShape* shapeTobeChanged, const std::string& newDemandElementParentID, int demandElementParentIndex) {
531     if ((int)myDemandElementParents.size() < demandElementParentIndex) {
532         throw InvalidArgument(myAC->getTagStr() + " with ID '" + myAC->getID() + "' doesn't have " + toString(demandElementParentIndex) + " demand element parents");
533     } else {
534         // remove demand element of the childs of parent additional
535         myDemandElementParents.at(demandElementParentIndex)->removeShapeChild(shapeTobeChanged);
536         // set new demand element parent
537         myDemandElementParents.at(demandElementParentIndex) = shapeTobeChanged->getNet()->retrieveDemandElement(myDemandElementParents.at(demandElementParentIndex)->getTagProperty().getTag(), newDemandElementParentID);
538         // add demand element int the childs of parent additional
539         myDemandElementParents.at(demandElementParentIndex)->addShapeChild(shapeTobeChanged);
540         // update geometry after inserting
541         updateGeometry(true);
542     }
543 }
544 
545 
546 void
changeDemandElementParent(GNEAdditional * additionalTobeChanged,const std::string & newDemandElementParentID,int demandElementParentIndex)547 GNEHierarchicalElementParents::changeDemandElementParent(GNEAdditional* additionalTobeChanged, const std::string& newDemandElementParentID, int demandElementParentIndex) {
548     if ((int)myDemandElementParents.size() < demandElementParentIndex) {
549         throw InvalidArgument(myAC->getTagStr() + " with ID '" + myAC->getID() + "' doesn't have " + toString(demandElementParentIndex) + " demand element parents");
550     } else {
551         // remove demand element of the childs of parent additional
552         myDemandElementParents.at(demandElementParentIndex)->removeAdditionalChild(additionalTobeChanged);
553         // set new demand element parent
554         myDemandElementParents.at(demandElementParentIndex) = additionalTobeChanged->getViewNet()->getNet()->retrieveDemandElement(myDemandElementParents.at(demandElementParentIndex)->getTagProperty().getTag(), newDemandElementParentID);
555         // add demand element int the childs of parent additional
556         myDemandElementParents.at(demandElementParentIndex)->addAdditionalChild(additionalTobeChanged);
557         // update geometry after inserting
558         updateGeometry(true);
559     }
560 }
561 
562 
563 void
changeDemandElementParent(GNEDemandElement * demandElementTobeChanged,const std::string & newDemandElementParentID,int demandElementParentIndex)564 GNEHierarchicalElementParents::changeDemandElementParent(GNEDemandElement* demandElementTobeChanged, const std::string& newDemandElementParentID, int demandElementParentIndex) {
565     if ((int)myDemandElementParents.size() < demandElementParentIndex) {
566         throw InvalidArgument(myAC->getTagStr() + " with ID '" + myAC->getID() + "' doesn't have " + toString(demandElementParentIndex) + " demand element parents");
567     } else {
568         // remove additional of the childs of parent additional
569         myDemandElementParents.at(demandElementParentIndex)->removeDemandElementChild(demandElementTobeChanged);
570         // set new additional parent
571         myDemandElementParents.at(demandElementParentIndex) = demandElementTobeChanged->getViewNet()->getNet()->retrieveDemandElement(myDemandElementParents.at(demandElementParentIndex)->getTagProperty().getTag(), newDemandElementParentID);
572         // add additional int the childs of parent additional
573         myDemandElementParents.at(demandElementParentIndex)->addDemandElementChild(demandElementTobeChanged);
574         // update geometry after inserting
575         updateGeometry(true);
576     }
577 }
578 
579 /****************************************************************************/
580