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    GNEAdditionalHandler.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    Nov 2015
13 /// @version $Id$
14 ///
15 // Builds trigger objects for netedit
16 /****************************************************************************/
17 
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21 #include <config.h>
22 #include <utils/xml/XMLSubSys.h>
23 #include <netedit/changes/GNEChange_Additional.h>
24 #include <netedit/netelements/GNEEdge.h>
25 #include <netedit/netelements/GNELane.h>
26 #include <netedit/GNEViewNet.h>
27 #include <netedit/GNEUndoList.h>
28 #include <netedit/GNENet.h>
29 #include <utils/options/OptionsCont.h>
30 
31 #include "GNEAdditionalHandler.h"
32 #include "GNEBusStop.h"
33 #include "GNEAccess.h"
34 #include "GNECalibrator.h"
35 #include "GNECalibratorFlow.h"
36 #include "GNEChargingStation.h"
37 #include "GNEClosingLaneReroute.h"
38 #include "GNEClosingReroute.h"
39 #include "GNEContainerStop.h"
40 #include "GNEDestProbReroute.h"
41 #include "GNEDetectorE1.h"
42 #include "GNEDetectorE2.h"
43 #include "GNEDetectorE3.h"
44 #include "GNEDetectorEntryExit.h"
45 #include "GNEDetectorE1Instant.h"
46 #include "GNEParkingArea.h"
47 #include "GNEParkingSpace.h"
48 #include "GNERerouter.h"
49 #include "GNERerouterInterval.h"
50 #include "GNERouteProbReroute.h"
51 #include "GNEParkingAreaReroute.h"
52 #include "GNERouteProbe.h"
53 #include "GNEVaporizer.h"
54 #include "GNEVariableSpeedSign.h"
55 #include "GNEVariableSpeedSignStep.h"
56 #include "GNETAZ.h"
57 #include "GNETAZSourceSink.h"
58 
59 
60 // ===========================================================================
61 // GNEAdditionalHandler method definitions
62 // ===========================================================================
63 
GNEAdditionalHandler(const std::string & file,GNEViewNet * viewNet,bool undoAdditionals,GNEAdditional * additionalParent)64 GNEAdditionalHandler::GNEAdditionalHandler(const std::string& file, GNEViewNet* viewNet, bool undoAdditionals, GNEAdditional* additionalParent) :
65     ShapeHandler(file, *viewNet->getNet()),
66     myViewNet(viewNet),
67     myUndoAdditionals(undoAdditionals),
68     myAdditionalParent(additionalParent) {
69     // check if we're loading values of another additionals (example: Rerouter values)
70     if (additionalParent) {
71         myHierarchyInsertedAdditionals.insertElement(additionalParent->getTagProperty().getTag());
72         myHierarchyInsertedAdditionals.commitElementInsertion(additionalParent);
73     }
74     // define default values for shapes
75     setDefaults("", RGBColor::RED, Shape::DEFAULT_LAYER_POI, true);
76 }
77 
78 
~GNEAdditionalHandler()79 GNEAdditionalHandler::~GNEAdditionalHandler() {}
80 
81 
82 void
myStartElement(int element,const SUMOSAXAttributes & attrs)83 GNEAdditionalHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
84     // Obtain tag of element
85     SumoXMLTag tag = static_cast<SumoXMLTag>(element);
86     // check if we're parsing a generic parameter
87     if (tag == SUMO_TAG_PARAM) {
88         // push element int stack
89         myHierarchyInsertedAdditionals.insertElement(tag);
90         // parse generic parameter
91         parseGenericParameter(attrs);
92     } else if (tag != SUMO_TAG_NOTHING) {
93         // push element int stack
94         myHierarchyInsertedAdditionals.insertElement(tag);
95         // Call parse and build depending of tag
96         switch (tag) {
97             case SUMO_TAG_POLY:
98                 return parseAndBuildPoly(attrs);
99             case SUMO_TAG_POI:
100                 return parseAndBuildPOI(attrs);
101             default:
102                 // build additional
103                 buildAdditional(myViewNet, true, tag, attrs, &myHierarchyInsertedAdditionals);
104         }
105     }
106 }
107 
108 
109 void
myEndElement(int element)110 GNEAdditionalHandler::myEndElement(int element) {
111     // Obtain tag of element
112     SumoXMLTag tag = static_cast<SumoXMLTag>(element);
113     switch (tag) {
114         case SUMO_TAG_TAZ: {
115             GNETAZ* TAZ = dynamic_cast<GNETAZ*>(myHierarchyInsertedAdditionals.getLastInsertedAdditional());
116             if (TAZ != nullptr) {
117                 if (TAZ->getShape().size() == 0) {
118                     Boundary b;
119                     if (TAZ->getAdditionalChilds().size() > 0) {
120                         for (const auto& i : TAZ->getAdditionalChilds()) {
121                             b.add(i->getCenteringBoundary());
122                         }
123                         PositionVector boundaryShape;
124                         boundaryShape.push_back(Position(b.xmin(), b.ymin()));
125                         boundaryShape.push_back(Position(b.xmax(), b.ymin()));
126                         boundaryShape.push_back(Position(b.xmax(), b.ymax()));
127                         boundaryShape.push_back(Position(b.xmin(), b.ymax()));
128                         boundaryShape.push_back(Position(b.xmin(), b.ymin()));
129                         TAZ->setAttribute(SUMO_ATTR_SHAPE, toString(boundaryShape), myViewNet->getUndoList());
130                     }
131                 }
132             }
133             break;
134         }
135         default:
136             break;
137     }
138     // pop last inserted element
139     myHierarchyInsertedAdditionals.popElement();
140     // execute myEndElement of ShapeHandler (needed to update myLastParameterised)
141     ShapeHandler::myEndElement(element);
142 }
143 
144 
145 Position
getLanePos(const std::string & poiID,const std::string & laneID,double lanePos,double lanePosLat)146 GNEAdditionalHandler::getLanePos(const std::string& poiID, const std::string& laneID, double lanePos, double lanePosLat) {
147     std::string edgeID;
148     int laneIndex;
149     NBHelpers::interpretLaneID(laneID, edgeID, laneIndex);
150     NBEdge* edge = myViewNet->getNet()->retrieveEdge(edgeID)->getNBEdge();
151     if (edge == nullptr || laneIndex < 0 || edge->getNumLanes() <= laneIndex) {
152         WRITE_ERROR("Lane '" + laneID + "' to place poi '" + poiID + "' on is not known.");
153         return Position::INVALID;
154     }
155     if (lanePos < 0) {
156         lanePos = edge->getLength() + lanePos;
157     }
158     if (lanePos < 0 || lanePos > edge->getLength()) {
159         WRITE_WARNING("lane position " + toString(lanePos) + " for poi '" + poiID + "' is not valid.");
160     }
161     return edge->getLanes()[laneIndex].shape.positionAtOffset(lanePos, -lanePosLat);
162 }
163 
164 
165 bool
buildAdditional(GNEViewNet * viewNet,bool allowUndoRedo,SumoXMLTag tag,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)166 GNEAdditionalHandler::buildAdditional(GNEViewNet* viewNet, bool allowUndoRedo, SumoXMLTag tag, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
167     // Call parse and build depending of tag
168     switch (tag) {
169         case SUMO_TAG_BUS_STOP:
170         case SUMO_TAG_TRAIN_STOP:
171             return parseAndBuildBusStop(viewNet, allowUndoRedo, attrs, insertedAdditionals);
172         case SUMO_TAG_ACCESS:
173             return parseAndBuildAccess(viewNet, allowUndoRedo, attrs, insertedAdditionals);
174         case SUMO_TAG_CONTAINER_STOP:
175             return parseAndBuildContainerStop(viewNet, allowUndoRedo, attrs, insertedAdditionals);
176         case SUMO_TAG_CHARGING_STATION:
177             return parseAndBuildChargingStation(viewNet, allowUndoRedo, attrs, insertedAdditionals);
178         case SUMO_TAG_E1DETECTOR:
179         case SUMO_TAG_INDUCTION_LOOP:
180             return parseAndBuildDetectorE1(viewNet, allowUndoRedo, attrs, insertedAdditionals);
181         case SUMO_TAG_E2DETECTOR:
182         case SUMO_TAG_E2DETECTOR_MULTILANE:
183         case SUMO_TAG_LANE_AREA_DETECTOR:
184             return parseAndBuildDetectorE2(viewNet, allowUndoRedo, attrs, insertedAdditionals);
185         case SUMO_TAG_E3DETECTOR:
186         case SUMO_TAG_ENTRY_EXIT_DETECTOR:
187             return parseAndBuildDetectorE3(viewNet, allowUndoRedo, attrs, insertedAdditionals);
188         case SUMO_TAG_DET_ENTRY:
189             return parseAndBuildDetectorEntry(viewNet, allowUndoRedo, attrs, insertedAdditionals);
190         case SUMO_TAG_DET_EXIT:
191             return parseAndBuildDetectorExit(viewNet, allowUndoRedo, attrs, insertedAdditionals);
192         case SUMO_TAG_INSTANT_INDUCTION_LOOP:
193             return parseAndBuildDetectorE1Instant(viewNet, allowUndoRedo, attrs, insertedAdditionals);
194         case SUMO_TAG_ROUTEPROBE:
195             return parseAndBuildRouteProbe(viewNet, allowUndoRedo, attrs, insertedAdditionals);
196         case SUMO_TAG_VAPORIZER:
197             return parseAndBuildVaporizer(viewNet, allowUndoRedo, attrs, insertedAdditionals);
198         case SUMO_TAG_TAZ:
199             return parseAndBuildTAZ(viewNet, allowUndoRedo, attrs, insertedAdditionals);
200         case SUMO_TAG_TAZSOURCE:
201             return parseAndBuildTAZSource(viewNet, allowUndoRedo, attrs, insertedAdditionals);
202         case SUMO_TAG_TAZSINK:
203             return parseAndBuildTAZSink(viewNet, allowUndoRedo, attrs, insertedAdditionals);
204         case SUMO_TAG_VSS:
205             return parseAndBuildVariableSpeedSign(viewNet, allowUndoRedo, attrs, insertedAdditionals);
206         case SUMO_TAG_STEP:
207             return parseAndBuildVariableSpeedSignStep(viewNet, allowUndoRedo, attrs, insertedAdditionals);
208         case SUMO_TAG_CALIBRATOR:
209         case SUMO_TAG_LANECALIBRATOR:
210             return parseAndBuildCalibrator(viewNet, allowUndoRedo, attrs, insertedAdditionals);
211         case SUMO_TAG_PARKING_AREA:
212             return parseAndBuildParkingArea(viewNet, allowUndoRedo, attrs, insertedAdditionals);
213         case SUMO_TAG_PARKING_SPACE:
214             return parseAndBuildParkingSpace(viewNet, allowUndoRedo, attrs, insertedAdditionals);
215         case SUMO_TAG_CALIBRATORFLOW:
216             return parseAndBuildCalibratorFlow(viewNet, allowUndoRedo, attrs, insertedAdditionals);
217         case SUMO_TAG_REROUTER:
218             return parseAndBuildRerouter(viewNet, allowUndoRedo, attrs, insertedAdditionals);
219         case SUMO_TAG_INTERVAL:
220             return parseAndBuildRerouterInterval(viewNet, allowUndoRedo, attrs, insertedAdditionals);
221         case SUMO_TAG_CLOSING_LANE_REROUTE:
222             return parseAndBuildRerouterClosingLaneReroute(viewNet, allowUndoRedo, attrs, insertedAdditionals);
223         case SUMO_TAG_CLOSING_REROUTE:
224             return parseAndBuildRerouterClosingReroute(viewNet, allowUndoRedo, attrs, insertedAdditionals);
225         case SUMO_TAG_DEST_PROB_REROUTE:
226             return parseAndBuildRerouterDestProbReroute(viewNet, allowUndoRedo, attrs, insertedAdditionals);
227         case SUMO_TAG_PARKING_ZONE_REROUTE:
228             return parseAndBuildRerouterParkingAreaReroute(viewNet, allowUndoRedo, attrs, insertedAdditionals);
229         case SUMO_TAG_ROUTE_PROB_REROUTE:
230             return parseAndBuildRerouterRouteProbReroute(viewNet, allowUndoRedo, attrs, insertedAdditionals);
231         default:
232             return false;
233     }
234 }
235 
236 
237 GNEAdditional*
buildBusStop(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,const std::string & startPos,const std::string & endPos,const std::string & name,const std::vector<std::string> & lines,int personCapacity,bool friendlyPosition,bool blockMovement)238 GNEAdditionalHandler::buildBusStop(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, const std::string& startPos, const std::string& endPos, const std::string& name, const std::vector<std::string>& lines, int personCapacity, bool friendlyPosition, bool blockMovement) {
239     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_BUS_STOP, id, false) == nullptr) {
240         GNEBusStop* busStop = new GNEBusStop(id, lane, viewNet, startPos, endPos, name, lines, personCapacity, friendlyPosition, blockMovement);
241         if (allowUndoRedo) {
242             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_BUS_STOP));
243             viewNet->getUndoList()->add(new GNEChange_Additional(busStop, true), true);
244             viewNet->getUndoList()->p_end();
245         } else {
246             viewNet->getNet()->insertAdditional(busStop);
247             lane->addAdditionalChild(busStop);
248             busStop->incRef("buildBusStop");
249         }
250         return busStop;
251     } else {
252         throw ProcessError("Could not build " + toString(SUMO_TAG_BUS_STOP) + " with ID '" + id + "' in netedit; probably declared twice.");
253     }
254 }
255 
256 
257 GNEAdditional*
buildAccess(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * busStop,GNELane * lane,const std::string & pos,const std::string & length,bool friendlyPos,bool blockMovement)258 GNEAdditionalHandler::buildAccess(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* busStop, GNELane* lane, const std::string& pos, const std::string& length, bool friendlyPos, bool blockMovement) {
259     // Check if busStop parent and lane is correct
260     if (lane == nullptr) {
261         throw ProcessError("Could not build " + toString(SUMO_TAG_ACCESS) + " in netedit; " +  toString(SUMO_TAG_LANE) + " doesn't exist.");
262     } else if (busStop == nullptr) {
263         throw ProcessError("Could not build " + toString(SUMO_TAG_ACCESS) + " in netedit; " +  toString(SUMO_TAG_BUS_STOP) + " parent doesn't exist.");
264     } else if (!accessCanBeCreated(busStop, lane->getParentEdge())) {
265         throw ProcessError("Could not build " + toString(SUMO_TAG_ACCESS) + " in netedit; " +  toString(SUMO_TAG_BUS_STOP) + " parent already owns a Acces in the edge '" + lane->getParentEdge().getID() + "'");
266     } else {
267         GNEAccess* access = new GNEAccess(busStop, lane, viewNet, pos, length, friendlyPos, blockMovement);
268         if (allowUndoRedo) {
269             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_ACCESS));
270             viewNet->getUndoList()->add(new GNEChange_Additional(access, true), true);
271             viewNet->getUndoList()->p_end();
272         } else {
273             viewNet->getNet()->insertAdditional(access);
274             lane->addAdditionalChild(access);
275             busStop->addAdditionalChild(access);
276             access->incRef("buildAccess");
277         }
278         return access;
279     }
280 }
281 
282 
283 GNEAdditional*
buildContainerStop(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,const std::string & startPos,const std::string & endPos,const std::string & name,const std::vector<std::string> & lines,bool friendlyPosition,bool blockMovement)284 GNEAdditionalHandler::buildContainerStop(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, const std::string& startPos, const std::string& endPos, const std::string& name, const std::vector<std::string>& lines, bool friendlyPosition, bool blockMovement) {
285     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_CONTAINER_STOP, id, false) == nullptr) {
286         GNEContainerStop* containerStop = new GNEContainerStop(id, lane, viewNet, startPos, endPos, name, lines, friendlyPosition, blockMovement);
287         if (allowUndoRedo) {
288             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_CONTAINER_STOP));
289             viewNet->getUndoList()->add(new GNEChange_Additional(containerStop, true), true);
290             viewNet->getUndoList()->p_end();
291         } else {
292             viewNet->getNet()->insertAdditional(containerStop);
293             lane->addAdditionalChild(containerStop);
294             containerStop->incRef("buildContainerStop");
295         }
296         return containerStop;
297     } else {
298         throw ProcessError("Could not build " + toString(SUMO_TAG_CONTAINER_STOP) + " with ID '" + id + "' in netedit; probably declared twice.");
299     }
300 }
301 
302 
303 GNEAdditional*
buildChargingStation(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,const std::string & startPos,const std::string & endPos,const std::string & name,double chargingPower,double efficiency,bool chargeInTransit,double chargeDelay,bool friendlyPosition,bool blockMovement)304 GNEAdditionalHandler::buildChargingStation(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, const std::string& startPos, const std::string& endPos, const std::string& name,
305         double chargingPower, double efficiency, bool chargeInTransit, double chargeDelay, bool friendlyPosition, bool blockMovement) {
306     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_CHARGING_STATION, id, false) == nullptr) {
307         GNEChargingStation* chargingStation = new GNEChargingStation(id, lane, viewNet, startPos, endPos, name, chargingPower, efficiency, chargeInTransit, chargeDelay, friendlyPosition, blockMovement);
308         if (allowUndoRedo) {
309             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_CHARGING_STATION));
310             viewNet->getUndoList()->add(new GNEChange_Additional(chargingStation, true), true);
311             viewNet->getUndoList()->p_end();
312         } else {
313             viewNet->getNet()->insertAdditional(chargingStation);
314             lane->addAdditionalChild(chargingStation);
315             chargingStation->incRef("buildChargingStation");
316         }
317         return chargingStation;
318     } else {
319         throw ProcessError("Could not build " + toString(SUMO_TAG_CHARGING_STATION) + " with ID '" + id + "' in netedit; probably declared twice.");
320     }
321 }
322 
323 
324 GNEAdditional*
buildParkingArea(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,const std::string & startPos,const std::string & endPos,const std::string & name,bool friendlyPosition,int roadSideCapacity,bool onRoad,double width,const std::string & length,double angle,bool blockMovement)325 GNEAdditionalHandler::buildParkingArea(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, const std::string& startPos, const std::string& endPos, const std::string& name,
326                                        bool friendlyPosition, int roadSideCapacity, bool onRoad, double width, const std::string& length, double angle, bool blockMovement) {
327     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_PARKING_AREA, id, false) == nullptr) {
328         GNEParkingArea* parkingArea = new GNEParkingArea(id, lane, viewNet, startPos, endPos, name, friendlyPosition, roadSideCapacity, onRoad, width, length, angle, blockMovement);
329         if (allowUndoRedo) {
330             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_PARKING_AREA));
331             viewNet->getUndoList()->add(new GNEChange_Additional(parkingArea, true), true);
332             viewNet->getUndoList()->p_end();
333         } else {
334             viewNet->getNet()->insertAdditional(parkingArea);
335             lane->addAdditionalChild(parkingArea);
336             parkingArea->incRef("buildParkingArea");
337         }
338         return parkingArea;
339     } else {
340         throw ProcessError("Could not build " + toString(SUMO_TAG_PARKING_AREA) + " with ID '" + id + "' in netedit; probably declared twice.");
341     }
342 }
343 
344 
345 GNEAdditional*
buildParkingSpace(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * parkingAreaParent,Position pos,double width,double length,double angle,bool blockMovement)346 GNEAdditionalHandler::buildParkingSpace(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* parkingAreaParent, Position pos, double width, double length, double angle, bool blockMovement) {
347     GNEParkingSpace* parkingSpace = new GNEParkingSpace(viewNet, parkingAreaParent, pos, width, length, angle, blockMovement);
348     if (allowUndoRedo) {
349         viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_PARKING_SPACE));
350         viewNet->getUndoList()->add(new GNEChange_Additional(parkingSpace, true), true);
351         viewNet->getUndoList()->p_end();
352     } else {
353         viewNet->getNet()->insertAdditional(parkingSpace);
354         parkingAreaParent->addAdditionalChild(parkingSpace);
355         parkingSpace->incRef("buildParkingSpace");
356     }
357     return parkingSpace;
358 }
359 
360 
361 GNEAdditional*
buildDetectorE1(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,double pos,double freq,const std::string & filename,const std::string & vehicleTypes,const std::string & name,bool friendlyPos,bool blockMovement)362 GNEAdditionalHandler::buildDetectorE1(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, double pos, double freq, const std::string& filename, const std::string& vehicleTypes, const std::string& name, bool friendlyPos, bool blockMovement) {
363     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_E1DETECTOR, id, false) == nullptr) {
364         GNEDetectorE1* detectorE1 = new GNEDetectorE1(id, lane, viewNet, pos, freq, filename, vehicleTypes, name, friendlyPos, blockMovement);
365         if (allowUndoRedo) {
366             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_E1DETECTOR));
367             viewNet->getUndoList()->add(new GNEChange_Additional(detectorE1, true), true);
368             viewNet->getUndoList()->p_end();
369         } else {
370             viewNet->getNet()->insertAdditional(detectorE1);
371             lane->addAdditionalChild(detectorE1);
372             detectorE1->incRef("buildDetectorE1");
373         }
374         return detectorE1;
375     } else {
376         throw ProcessError("Could not build " + toString(SUMO_TAG_E1DETECTOR) + " with ID '" + id + "' in netedit; probably declared twice.");
377     }
378 }
379 
380 
381 GNEAdditional*
buildSingleLaneDetectorE2(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,double pos,double length,double freq,const std::string & filename,const std::string & vehicleTypes,const std::string & name,const double timeThreshold,double speedThreshold,double jamThreshold,bool friendlyPos,bool blockMovement)382 GNEAdditionalHandler::buildSingleLaneDetectorE2(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, double pos, double length, double freq, const std::string& filename,
383         const std::string& vehicleTypes, const std::string& name, const double timeThreshold, double speedThreshold, double jamThreshold, bool friendlyPos, bool blockMovement) {
384     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_E2DETECTOR, id, false) == nullptr) {
385         GNEDetectorE2* detectorE2 = new GNEDetectorE2(id, lane, viewNet, pos, length, freq, filename, vehicleTypes, name, timeThreshold, speedThreshold, jamThreshold, friendlyPos, blockMovement);
386         if (allowUndoRedo) {
387             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_E2DETECTOR));
388             viewNet->getUndoList()->add(new GNEChange_Additional(detectorE2, true), true);
389             viewNet->getUndoList()->p_end();
390         } else {
391             viewNet->getNet()->insertAdditional(detectorE2);
392             lane->addAdditionalChild(detectorE2);
393             detectorE2->incRef("buildDetectorE2");
394         }
395         return detectorE2;
396     } else {
397         throw ProcessError("Could not build " + toString(SUMO_TAG_E2DETECTOR) + " with ID '" + id + "' in netedit; probably declared twice.");
398     }
399 }
400 
401 
402 GNEAdditional*
buildMultiLaneDetectorE2(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,const std::vector<GNELane * > & lanes,double pos,double endPos,double freq,const std::string & filename,const std::string & vehicleTypes,const std::string & name,const double timeThreshold,double speedThreshold,double jamThreshold,bool friendlyPos,bool blockMovement)403 GNEAdditionalHandler::buildMultiLaneDetectorE2(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, const std::vector<GNELane*>& lanes, double pos, double endPos, double freq, const std::string& filename,
404         const std::string& vehicleTypes, const std::string& name, const double timeThreshold, double speedThreshold, double jamThreshold, bool friendlyPos, bool blockMovement) {
405     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_E2DETECTOR_MULTILANE, id, false) == nullptr) {
406         GNEDetectorE2* detectorE2 = new GNEDetectorE2(id, lanes, viewNet, pos, endPos, freq, filename, vehicleTypes, name, timeThreshold, speedThreshold, jamThreshold, friendlyPos, blockMovement);
407         if (allowUndoRedo) {
408             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_E2DETECTOR_MULTILANE));
409             viewNet->getUndoList()->add(new GNEChange_Additional(detectorE2, true), true);
410             viewNet->getUndoList()->p_end();
411         } else {
412             viewNet->getNet()->insertAdditional(detectorE2);
413             for (auto i : lanes) {
414                 i->addAdditionalChild(detectorE2);
415             }
416             detectorE2->incRef("buildDetectorE2Multilane");
417         }
418         // check E2 integrity
419         detectorE2->checkE2MultilaneIntegrity();
420         return detectorE2;
421     } else {
422         throw ProcessError("Could not build " + toString(SUMO_TAG_E2DETECTOR_MULTILANE) + " with ID '" + id + "' in netedit; probably declared twice.");
423     }
424 }
425 
426 
427 GNEAdditional*
buildDetectorE3(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,Position pos,double freq,const std::string & filename,const std::string & vehicleTypes,const std::string & name,const double timeThreshold,double speedThreshold,bool blockMovement)428 GNEAdditionalHandler::buildDetectorE3(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, Position pos, double freq, const std::string& filename, const std::string& vehicleTypes,
429                                       const std::string& name, const double timeThreshold, double speedThreshold, bool blockMovement) {
430     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_E3DETECTOR, id, false) == nullptr) {
431         GNEDetectorE3* detectorE3 = new GNEDetectorE3(id, viewNet, pos, freq, filename, vehicleTypes, name, timeThreshold, speedThreshold, blockMovement);
432         if (allowUndoRedo) {
433             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_E3DETECTOR));
434             viewNet->getUndoList()->add(new GNEChange_Additional(detectorE3, true), true);
435             viewNet->getUndoList()->p_end();
436         } else {
437             viewNet->getNet()->insertAdditional(detectorE3);
438             detectorE3->incRef("buildDetectorE3");
439         }
440         return detectorE3;
441     } else {
442         throw ProcessError("Could not build " + toString(SUMO_TAG_E3DETECTOR) + " with ID '" + id + "' in netedit; probably declared twice.");
443     }
444 }
445 
446 
447 GNEAdditional*
buildDetectorEntry(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * E3Parent,GNELane * lane,double pos,bool friendlyPos,bool blockMovement)448 GNEAdditionalHandler::buildDetectorEntry(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* E3Parent, GNELane* lane, double pos, bool friendlyPos, bool blockMovement) {
449     // Check if Detector E3 parent and lane is correct
450     if (lane == nullptr) {
451         throw ProcessError("Could not build " + toString(SUMO_TAG_DET_ENTRY) + " in netedit; " +  toString(SUMO_TAG_LANE) + " doesn't exist.");
452     } else if (E3Parent == nullptr) {
453         throw ProcessError("Could not build " + toString(SUMO_TAG_DET_ENTRY) + " in netedit; " +  toString(SUMO_TAG_E3DETECTOR) + " parent doesn't exist.");
454     } else {
455         GNEDetectorEntryExit* entry = new GNEDetectorEntryExit(SUMO_TAG_DET_ENTRY, viewNet, E3Parent, lane, pos, friendlyPos, blockMovement);
456         if (allowUndoRedo) {
457             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_DET_ENTRY));
458             viewNet->getUndoList()->add(new GNEChange_Additional(entry, true), true);
459             viewNet->getUndoList()->p_end();
460         } else {
461             viewNet->getNet()->insertAdditional(entry);
462             lane->addAdditionalChild(entry);
463             E3Parent->addAdditionalChild(entry);
464             entry->incRef("buildDetectorEntry");
465         }
466         return entry;
467     }
468 }
469 
470 
471 GNEAdditional*
buildDetectorExit(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * E3Parent,GNELane * lane,double pos,bool friendlyPos,bool blockMovement)472 GNEAdditionalHandler::buildDetectorExit(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* E3Parent, GNELane* lane, double pos, bool friendlyPos, bool blockMovement) {
473     // Check if Detector E3 parent and lane is correct
474     if (lane == nullptr) {
475         throw ProcessError("Could not build " + toString(SUMO_TAG_DET_EXIT) + " in netedit; " +  toString(SUMO_TAG_LANE) + " doesn't exist.");
476     } else if (E3Parent == nullptr) {
477         throw ProcessError("Could not build " + toString(SUMO_TAG_DET_EXIT) + " in netedit; " +  toString(SUMO_TAG_E3DETECTOR) + " parent doesn't exist.");
478     } else {
479         GNEDetectorEntryExit* exit = new GNEDetectorEntryExit(SUMO_TAG_DET_EXIT, viewNet, E3Parent, lane, pos, friendlyPos, blockMovement);
480         if (allowUndoRedo) {
481             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_DET_EXIT));
482             viewNet->getUndoList()->add(new GNEChange_Additional(exit, true), true);
483             viewNet->getUndoList()->p_end();
484         } else {
485             viewNet->getNet()->insertAdditional(exit);
486             lane->addAdditionalChild(exit);
487             E3Parent->addAdditionalChild(exit);
488             exit->incRef("buildDetectorExit");
489         }
490         return exit;
491     }
492 }
493 
494 
495 GNEAdditional*
buildDetectorE1Instant(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,double pos,const std::string & filename,const std::string & vehicleTypes,const std::string & name,bool friendlyPos,bool blockMovement)496 GNEAdditionalHandler::buildDetectorE1Instant(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, double pos, const std::string& filename, const std::string& vehicleTypes, const std::string& name, bool friendlyPos, bool blockMovement) {
497     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_INSTANT_INDUCTION_LOOP, id, false) == nullptr) {
498         GNEDetectorE1Instant* detectorE1Instant = new GNEDetectorE1Instant(id, lane, viewNet, pos, filename, vehicleTypes, name, friendlyPos, blockMovement);
499         if (allowUndoRedo) {
500             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_INSTANT_INDUCTION_LOOP));
501             viewNet->getUndoList()->add(new GNEChange_Additional(detectorE1Instant, true), true);
502             viewNet->getUndoList()->p_end();
503         } else {
504             viewNet->getNet()->insertAdditional(detectorE1Instant);
505             lane->addAdditionalChild(detectorE1Instant);
506             detectorE1Instant->incRef("buildDetectorE1Instant");
507         }
508         return detectorE1Instant;
509     } else {
510         throw ProcessError("Could not build " + toString(SUMO_TAG_INSTANT_INDUCTION_LOOP) + " with ID '" + id + "' in netedit; probably declared twice.");
511     }
512 }
513 
514 
515 GNEAdditional*
buildCalibrator(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNELane * lane,double pos,const std::string & name,const std::string & outfile,const double freq,const std::string & routeprobe)516 GNEAdditionalHandler::buildCalibrator(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNELane* lane, double pos, const std::string& name, const std::string& outfile, const double freq, const std::string& routeprobe) {
517     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_CALIBRATOR, id, false) == nullptr) {
518         GNECalibrator* calibrator = new GNECalibrator(id, viewNet, lane, pos, freq, name, outfile, routeprobe);
519         if (allowUndoRedo) {
520             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_CALIBRATOR));
521             viewNet->getUndoList()->add(new GNEChange_Additional(calibrator, true), true);
522             viewNet->getUndoList()->p_end();
523             // center after creation
524             viewNet->centerTo(calibrator->getGlID(), false);
525         } else {
526             viewNet->getNet()->insertAdditional(calibrator);
527             lane->addAdditionalChild(calibrator);
528             calibrator->incRef("buildCalibrator");
529         }
530         return calibrator;
531     } else {
532         throw ProcessError("Could not build " + toString(SUMO_TAG_CALIBRATOR) + " with ID '" + id + "' in netedit; probably declared twice.");
533     }
534 }
535 
536 
537 GNEAdditional*
buildCalibrator(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNEEdge * edge,double pos,const std::string & name,const std::string & outfile,const double freq,const std::string & routeprobe)538 GNEAdditionalHandler::buildCalibrator(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNEEdge* edge, double pos, const std::string& name, const std::string& outfile, const double freq, const std::string& routeprobe) {
539     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_CALIBRATOR, id, false) == nullptr) {
540         GNECalibrator* calibrator = new GNECalibrator(id, viewNet, edge, pos, freq, name, outfile, routeprobe);
541         if (allowUndoRedo) {
542             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_CALIBRATOR));
543             viewNet->getUndoList()->add(new GNEChange_Additional(calibrator, true), true);
544             viewNet->getUndoList()->p_end();
545             // center after creation
546             viewNet->centerTo(calibrator->getGlID(), false);
547         } else {
548             viewNet->getNet()->insertAdditional(calibrator);
549             edge->addAdditionalChild(calibrator);
550             calibrator->incRef("buildCalibrator");
551         }
552         return calibrator;
553     } else {
554         throw ProcessError("Could not build " + toString(SUMO_TAG_CALIBRATOR) + " with ID '" + id + "' in netedit; probably declared twice.");
555     }
556 }
557 
558 
559 GNEAdditional*
buildCalibratorFlow(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * calibratorParent,GNEDemandElement * route,GNEDemandElement * vType,const std::string & vehsPerHour,const std::string & speed,const RGBColor & color,const std::string & departLane,const std::string & departPos,const std::string & departSpeed,const std::string & arrivalLane,const std::string & arrivalPos,const std::string & arrivalSpeed,const std::string & line,int personNumber,int containerNumber,bool reroute,const std::string & departPosLat,const std::string & arrivalPosLat,double begin,double end)560 GNEAdditionalHandler::buildCalibratorFlow(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* calibratorParent, GNEDemandElement* route, GNEDemandElement* vType,
561         const std::string& vehsPerHour, const std::string& speed, const RGBColor& color, const std::string& departLane, const std::string& departPos,
562         const std::string& departSpeed, const std::string& arrivalLane, const std::string& arrivalPos, const std::string& arrivalSpeed, const std::string& line,
563         int personNumber, int containerNumber, bool reroute, const std::string& departPosLat, const std::string& arrivalPosLat, double begin, double end) {
564 
565     // create Flow and add it to calibrator parent
566     GNECalibratorFlow* flow = new GNECalibratorFlow(calibratorParent, vType, route, vehsPerHour, speed, color, departLane, departPos, departSpeed,
567             arrivalLane, arrivalPos, arrivalSpeed, line, personNumber, containerNumber, reroute,
568             departPosLat, arrivalPosLat, begin, end);
569     if (allowUndoRedo) {
570         viewNet->getUndoList()->p_begin("add " + flow->getTagStr());
571         viewNet->getUndoList()->add(new GNEChange_Additional(flow, true), true);
572         viewNet->getUndoList()->p_end();
573     } else {
574         calibratorParent->addAdditionalChild(flow);
575         flow->incRef("buildCalibratorFlow");
576     }
577     return flow;
578 }
579 
580 
581 GNEAdditional*
buildRerouter(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,Position pos,const std::vector<GNEEdge * > & edges,double prob,const std::string & name,const std::string & file,bool off,double timeThreshold,const std::string & vTypes,bool blockMovement)582 GNEAdditionalHandler::buildRerouter(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, Position pos, const std::vector<GNEEdge*>& edges, double prob, const std::string& name, const std::string& file, bool off, double timeThreshold, const std::string& vTypes, bool blockMovement) {
583     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_REROUTER, id, false) == nullptr) {
584         GNERerouter* rerouter = new GNERerouter(id, viewNet, pos, edges, name, file, prob, off, timeThreshold, vTypes, blockMovement);
585         if (allowUndoRedo) {
586             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_REROUTER));
587             viewNet->getUndoList()->add(new GNEChange_Additional(rerouter, true), true);
588             viewNet->getUndoList()->p_end();
589         } else {
590             viewNet->getNet()->insertAdditional(rerouter);
591             // add this rerouter as parent of all edges
592             for (auto i : edges) {
593                 i->addAdditionalParent(rerouter);
594             }
595             rerouter->incRef("buildRerouter");
596         }
597         // parse rerouter childs
598         if (!file.empty()) {
599             // we assume that rerouter values files is placed in the same folder as the additional file
600             std::string currentAdditionalFilename = FileHelpers::getFilePath(OptionsCont::getOptions().getString("additional-files"));
601             // Create additional handler for parse rerouter values
602             GNEAdditionalHandler rerouterValuesHandler(currentAdditionalFilename + file, viewNet, allowUndoRedo, rerouter);
603             // disable validation for rerouters
604             XMLSubSys::setValidation("never", "auto");
605             // Run parser
606             if (!XMLSubSys::runParser(rerouterValuesHandler, currentAdditionalFilename + file, false)) {
607                 WRITE_MESSAGE("Loading of " + file + " failed.");
608             }
609             // enable validation for rerouters
610             XMLSubSys::setValidation("auto", "auto");
611         }
612         return rerouter;
613     } else {
614         throw ProcessError("Could not build " + toString(SUMO_TAG_REROUTER) + " with ID '" + id + "' in netedit; probably declared twice.");
615     }
616 }
617 
618 
619 GNEAdditional*
buildRerouterInterval(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * rerouterParent,double begin,double end)620 GNEAdditionalHandler::buildRerouterInterval(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* rerouterParent, double begin, double end) {
621     // check if new interval will produce a overlapping
622     if (checkOverlappingRerouterIntervals(rerouterParent, begin, end)) {
623         // create rerouter interval and add it into rerouter parent
624         GNERerouterInterval* rerouterInterval = new GNERerouterInterval(rerouterParent, begin, end);
625         if (allowUndoRedo) {
626             viewNet->getUndoList()->p_begin("add " + rerouterInterval->getTagStr());
627             viewNet->getUndoList()->add(new GNEChange_Additional(rerouterInterval, true), true);
628             viewNet->getUndoList()->p_end();
629         } else {
630             rerouterParent->addAdditionalChild(rerouterInterval);
631             rerouterInterval->incRef("buildRerouterInterval");
632         }
633         return rerouterInterval;
634     } else {
635         throw ProcessError("Could not build " + toString(SUMO_TAG_INTERVAL) + " with begin '" + toString(begin) + "' and '" + toString(end) + "' in '" + rerouterParent->getID() + "' due overlapping.");
636     }
637 }
638 
639 
640 GNEAdditional*
buildClosingLaneReroute(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * rerouterIntervalParent,GNELane * closedLane,SVCPermissions permissions)641 GNEAdditionalHandler::buildClosingLaneReroute(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* rerouterIntervalParent, GNELane* closedLane, SVCPermissions permissions) {
642     // create closing lane reorute
643     GNEClosingLaneReroute* closingLaneReroute = new GNEClosingLaneReroute(rerouterIntervalParent, closedLane, permissions);
644     // add it to interval parent depending of allowUndoRedo
645     if (allowUndoRedo) {
646         viewNet->getUndoList()->p_begin("add " + closingLaneReroute->getTagStr());
647         viewNet->getUndoList()->add(new GNEChange_Additional(closingLaneReroute, true), true);
648         viewNet->getUndoList()->p_end();
649     } else {
650         rerouterIntervalParent->addAdditionalChild(closingLaneReroute);
651         closingLaneReroute->incRef("buildClosingLaneReroute");
652     }
653     return closingLaneReroute;
654 }
655 
656 
657 GNEAdditional*
buildClosingReroute(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * rerouterIntervalParent,GNEEdge * closedEdge,SVCPermissions permissions)658 GNEAdditionalHandler::buildClosingReroute(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* rerouterIntervalParent, GNEEdge* closedEdge, SVCPermissions permissions) {
659     // create closing reroute
660     GNEClosingReroute* closingReroute = new GNEClosingReroute(rerouterIntervalParent, closedEdge, permissions);
661     // add it to interval parent depending of allowUndoRedo
662     if (allowUndoRedo) {
663         viewNet->getUndoList()->p_begin("add " + closingReroute->getTagStr());
664         viewNet->getUndoList()->add(new GNEChange_Additional(closingReroute, true), true);
665         viewNet->getUndoList()->p_end();
666     } else {
667         rerouterIntervalParent->addAdditionalChild(closingReroute);
668         closingReroute->incRef("buildClosingReroute");
669     }
670     return closingReroute;
671 }
672 
673 
674 GNEAdditional*
builDestProbReroute(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * rerouterIntervalParent,GNEEdge * newEdgeDestination,double probability)675 GNEAdditionalHandler::builDestProbReroute(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* rerouterIntervalParent, GNEEdge* newEdgeDestination, double probability) {
676     // create dest probability reroute
677     GNEDestProbReroute* destProbReroute = new GNEDestProbReroute(rerouterIntervalParent, newEdgeDestination, probability);
678     // add it to interval parent depending of allowUndoRedo
679     if (allowUndoRedo) {
680         viewNet->getUndoList()->p_begin("add " + destProbReroute->getTagStr());
681         viewNet->getUndoList()->add(new GNEChange_Additional(destProbReroute, true), true);
682         viewNet->getUndoList()->p_end();
683     } else {
684         rerouterIntervalParent->addAdditionalChild(destProbReroute);
685         destProbReroute->incRef("builDestProbReroute");
686     }
687     return destProbReroute;
688 }
689 
690 
691 GNEAdditional*
builParkingAreaReroute(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * rerouterIntervalParent,GNEAdditional * newParkingArea,double probability,bool visible)692 GNEAdditionalHandler::builParkingAreaReroute(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* rerouterIntervalParent, GNEAdditional* newParkingArea, double probability, bool visible) {
693     // create dest probability reroute
694     GNEParkingAreaReroute* parkingAreaReroute = new GNEParkingAreaReroute(rerouterIntervalParent, newParkingArea, probability, visible);
695     // add it to interval parent depending of allowUndoRedo
696     if (allowUndoRedo) {
697         viewNet->getUndoList()->p_begin("add " + parkingAreaReroute->getTagStr());
698         viewNet->getUndoList()->add(new GNEChange_Additional(parkingAreaReroute, true), true);
699         viewNet->getUndoList()->p_end();
700     } else {
701         rerouterIntervalParent->addAdditionalChild(parkingAreaReroute);
702         parkingAreaReroute->incRef("builParkingAreaReroute");
703     }
704     return parkingAreaReroute;
705 }
706 
707 
708 GNEAdditional*
buildRouteProbReroute(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * rerouterIntervalParent,const std::string & newRouteId,double probability)709 GNEAdditionalHandler::buildRouteProbReroute(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* rerouterIntervalParent, const std::string& newRouteId, double probability) {
710     // create rout prob rereoute
711     GNERouteProbReroute* routeProbReroute = new GNERouteProbReroute(rerouterIntervalParent, newRouteId, probability);
712     // add it to interval parent depending of allowUndoRedo
713     if (allowUndoRedo) {
714         viewNet->getUndoList()->p_begin("add " + routeProbReroute->getTagStr());
715         viewNet->getUndoList()->add(new GNEChange_Additional(routeProbReroute, true), true);
716         viewNet->getUndoList()->p_end();
717     } else {
718         rerouterIntervalParent->addAdditionalChild(routeProbReroute);
719         routeProbReroute->incRef("buildRouteProbReroute");
720     }
721     return routeProbReroute;
722 }
723 
724 
725 GNEAdditional*
buildRouteProbe(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,GNEEdge * edge,const std::string & freq,const std::string & name,const std::string & file,double begin)726 GNEAdditionalHandler::buildRouteProbe(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, GNEEdge* edge, const std::string& freq, const std::string& name, const std::string& file, double begin) {
727     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, id, false) == nullptr) {
728         GNERouteProbe* routeProbe = new GNERouteProbe(id, viewNet, edge, freq, name, file, begin);
729         if (allowUndoRedo) {
730             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_ROUTEPROBE));
731             viewNet->getUndoList()->add(new GNEChange_Additional(routeProbe, true), true);
732             viewNet->getUndoList()->p_end();
733             // center after creation
734             viewNet->centerTo(routeProbe->getGlID(), false);
735         } else {
736             viewNet->getNet()->insertAdditional(routeProbe);
737             edge->addAdditionalChild(routeProbe);
738             routeProbe->incRef("buildRouteProbe");
739         }
740         return routeProbe;
741     } else {
742         throw ProcessError("Could not build " + toString(SUMO_TAG_ROUTEPROBE) + " with ID '" + id + "' in netedit; probably declared twice.");
743     }
744 }
745 
746 
747 GNEAdditional*
buildVariableSpeedSign(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,Position pos,const std::vector<GNELane * > & lanes,const std::string & name,bool blockMovement)748 GNEAdditionalHandler::buildVariableSpeedSign(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, Position pos, const std::vector<GNELane*>& lanes, const std::string& name, bool blockMovement) {
749     if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_VSS, id, false) == nullptr) {
750         GNEVariableSpeedSign* variableSpeedSign = new GNEVariableSpeedSign(id, viewNet, pos, lanes, name, blockMovement);
751         if (allowUndoRedo) {
752             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_VSS));
753             viewNet->getUndoList()->add(new GNEChange_Additional(variableSpeedSign, true), true);
754             viewNet->getUndoList()->p_end();
755         } else {
756             viewNet->getNet()->insertAdditional(variableSpeedSign);
757             // add this VSS as parent of all edges
758             for (auto i : lanes) {
759                 i->addAdditionalParent(variableSpeedSign);
760             }
761             variableSpeedSign->incRef("buildVariableSpeedSign");
762         }
763         return variableSpeedSign;
764     } else {
765         throw ProcessError("Could not build " + toString(SUMO_TAG_VSS) + " with ID '" + id + "' in netedit; probably declared twice.");
766     }
767 }
768 
769 
770 GNEAdditional*
buildVariableSpeedSignStep(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * VSSParent,double time,double speed)771 GNEAdditionalHandler::buildVariableSpeedSignStep(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* VSSParent, double time, double speed) {
772     // create Variable Speed Sign
773     GNEVariableSpeedSignStep* variableSpeedSignStep = new GNEVariableSpeedSignStep(VSSParent, time, speed);
774     // add it depending of allow undoRedo
775     if (allowUndoRedo) {
776         viewNet->getUndoList()->p_begin("add " + variableSpeedSignStep->getTagStr());
777         viewNet->getUndoList()->add(new GNEChange_Additional(variableSpeedSignStep, true), true);
778         viewNet->getUndoList()->p_end();
779     } else {
780         VSSParent->addAdditionalChild(variableSpeedSignStep);
781         variableSpeedSignStep->incRef("buildVariableSpeedSignStep");
782     }
783     return variableSpeedSignStep;
784 }
785 
786 
787 GNEAdditional*
buildVaporizer(GNEViewNet * viewNet,bool allowUndoRedo,GNEEdge * edge,double startTime,double end,const std::string & name)788 GNEAdditionalHandler::buildVaporizer(GNEViewNet* viewNet, bool allowUndoRedo, GNEEdge* edge, double startTime, double end, const std::string& name) {
789     GNEVaporizer* vaporizer = new GNEVaporizer(viewNet, edge, startTime, end, name);
790     if (allowUndoRedo) {
791         viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_VAPORIZER));
792         viewNet->getUndoList()->add(new GNEChange_Additional(vaporizer, true), true);
793         viewNet->getUndoList()->p_end();
794         // center after creation
795         viewNet->centerTo(vaporizer->getGlID(), false);
796     } else {
797         viewNet->getNet()->insertAdditional(vaporizer);
798         edge->addAdditionalChild(vaporizer);
799         vaporizer->incRef("buildVaporizer");
800     }
801     return vaporizer;
802 }
803 
804 
805 GNEAdditional*
buildTAZ(GNEViewNet * viewNet,bool allowUndoRedo,const std::string & id,const PositionVector & shape,const RGBColor & color,const std::vector<GNEEdge * > & edges,bool blockMovement)806 GNEAdditionalHandler::buildTAZ(GNEViewNet* viewNet, bool allowUndoRedo, const std::string& id, const PositionVector& shape, const RGBColor& color, const std::vector<GNEEdge*>& edges, bool blockMovement) {
807     GNETAZ* TAZ = new GNETAZ(id, viewNet, shape, color, blockMovement);
808     // disable updating geometry of TAZ childs during insertion (because in large nets provokes slowdowns)
809     viewNet->getNet()->disableUpdateGeometry();
810     if (allowUndoRedo) {
811         viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_TAZ));
812         viewNet->getUndoList()->add(new GNEChange_Additional(TAZ, true), true);
813         // create TAZEdges
814         for (auto i : edges) {
815             // create TAZ Source using GNEChange_Additional
816             GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, i, 1);
817             viewNet->getUndoList()->add(new GNEChange_Additional(TAZSource, true), true);
818             // create TAZ Sink using GNEChange_Additional
819             GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, i, 1);
820             viewNet->getUndoList()->add(new GNEChange_Additional(TAZSink, true), true);
821         }
822         viewNet->getUndoList()->p_end();
823     } else {
824         viewNet->getNet()->insertAdditional(TAZ);
825         TAZ->incRef("buildTAZ");
826         for (auto i : edges) {
827             // create TAZ Source
828             GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, i, 1);
829             TAZSource->incRef("buildTAZ");
830             TAZ->addAdditionalChild(TAZSource);
831             // create TAZ Sink
832             GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, i, 1);
833             TAZSink->incRef("buildTAZ");
834             TAZ->addAdditionalChild(TAZSink);
835         }
836     }
837     // enable updating geometry again and update geometry of TAZ
838     viewNet->getNet()->enableUpdateGeometry();
839     // update TAZ Frame
840     TAZ->updateGeometry(true);
841     TAZ->updateAdditionalParent();
842     return TAZ;
843 }
844 
845 
846 GNEAdditional*
buildTAZSource(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * TAZ,GNEEdge * edge,double departWeight)847 GNEAdditionalHandler::buildTAZSource(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* TAZ, GNEEdge* edge, double departWeight) {
848     GNEAdditional* TAZSink = nullptr;
849     // first check if a TAZSink in the same edge for the same TAZ
850     for (auto i : TAZ->getAdditionalChilds()) {
851         if ((i->getTagProperty().getTag() == SUMO_TAG_TAZSINK) && (i->getAttribute(SUMO_ATTR_EDGE) == edge->getID())) {
852             TAZSink = i;
853         }
854     }
855     // check if TAZSink has to be created
856     if (TAZSink == nullptr) {
857         // Create TAZ with weight 0 (default)
858         TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, 1);
859         if (allowUndoRedo) {
860             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_TAZSINK));
861             viewNet->getUndoList()->add(new GNEChange_Additional(TAZSink, true), true);
862             viewNet->getUndoList()->p_end();
863         } else {
864             viewNet->getNet()->insertAdditional(TAZSink);
865             TAZSink->incRef("buildTAZSource");
866         }
867     }
868     // now check check if TAZSource exist
869     GNEAdditional* TAZSource = nullptr;
870     // first check if a TAZSink in the same edge for the same TAZ
871     for (auto i : TAZ->getAdditionalChilds()) {
872         if ((i->getTagProperty().getTag() == SUMO_TAG_TAZSOURCE) && (i->getAttribute(SUMO_ATTR_EDGE) == edge->getID())) {
873             TAZSource = i;
874         }
875     }
876     // check if TAZSource has to be created
877     if (TAZSource == nullptr) {
878         // Create TAZ only with departWeight
879         TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, departWeight);
880         if (allowUndoRedo) {
881             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_TAZSOURCE));
882             viewNet->getUndoList()->add(new GNEChange_Additional(TAZSource, true), true);
883             viewNet->getUndoList()->p_end();
884         } else {
885             viewNet->getNet()->insertAdditional(TAZSource);
886             TAZSource->incRef("buildTAZSource");
887         }
888     } else {
889         // update TAZ Attribute
890         if (allowUndoRedo) {
891             viewNet->getUndoList()->p_begin("update " + toString(SUMO_TAG_TAZSOURCE));
892             TAZSource->setAttribute(SUMO_ATTR_WEIGHT, toString(departWeight), viewNet->getUndoList());
893             viewNet->getUndoList()->p_end();
894         } else {
895             TAZSource->setAttribute(SUMO_ATTR_WEIGHT, toString(departWeight), nullptr);
896             TAZSource->incRef("buildTAZSource");
897         }
898     }
899     return TAZSource;
900 }
901 
902 
903 GNEAdditional*
buildTAZSink(GNEViewNet * viewNet,bool allowUndoRedo,GNEAdditional * TAZ,GNEEdge * edge,double arrivalWeight)904 GNEAdditionalHandler::buildTAZSink(GNEViewNet* viewNet, bool allowUndoRedo, GNEAdditional* TAZ, GNEEdge* edge, double arrivalWeight) {
905     GNEAdditional* TAZSource = nullptr;
906     // first check if a TAZSink in the same edge for the same TAZ
907     for (auto i : TAZ->getAdditionalChilds()) {
908         if ((i->getTagProperty().getTag() == SUMO_TAG_TAZSOURCE) && (i->getAttribute(SUMO_ATTR_EDGE) == edge->getID())) {
909             TAZSource = i;
910         }
911     }
912     // check if TAZSource has to be created
913     if (TAZSource == nullptr) {
914         // Create TAZ with empty value
915         TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, 1);
916         if (allowUndoRedo) {
917             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_TAZSOURCE));
918             viewNet->getUndoList()->add(new GNEChange_Additional(TAZSource, true), true);
919             viewNet->getUndoList()->p_end();
920         } else {
921             viewNet->getNet()->insertAdditional(TAZSource);
922             TAZSource->incRef("buildTAZSink");
923         }
924     }
925     GNEAdditional* TAZSink = nullptr;
926     // first check if a TAZSink in the same edge for the same TAZ
927     for (auto i : TAZ->getAdditionalChilds()) {
928         if ((i->getTagProperty().getTag() == SUMO_TAG_TAZSINK) && (i->getAttribute(SUMO_ATTR_EDGE) == edge->getID())) {
929             TAZSink = i;
930         }
931     }
932     // check if TAZSink has to be created
933     if (TAZSink == nullptr) {
934         // Create TAZ only with arrivalWeight
935         TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, arrivalWeight);
936         if (allowUndoRedo) {
937             viewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_TAZSINK));
938             viewNet->getUndoList()->add(new GNEChange_Additional(TAZSink, true), true);
939             viewNet->getUndoList()->p_end();
940         } else {
941             viewNet->getNet()->insertAdditional(TAZSink);
942             TAZSink->incRef("buildTAZSink");
943         }
944     } else {
945         // update TAZ Attribute
946         if (allowUndoRedo) {
947             viewNet->getUndoList()->p_begin("update " + toString(SUMO_TAG_TAZSINK));
948             TAZSink->setAttribute(SUMO_ATTR_WEIGHT, toString(arrivalWeight), viewNet->getUndoList());
949             viewNet->getUndoList()->p_end();
950         } else {
951             TAZSink->setAttribute(SUMO_ATTR_WEIGHT, toString(arrivalWeight), nullptr);
952             TAZSink->incRef("buildTAZSink");
953         }
954     }
955     return TAZSink;
956 }
957 
958 
959 double
getPosition(double pos,GNELane & lane,bool friendlyPos,const std::string & additionalID)960 GNEAdditionalHandler::getPosition(double pos, GNELane& lane, bool friendlyPos, const std::string& additionalID) {
961     if (pos < 0) {
962         pos = lane.getLaneShapeLength() + pos;
963     }
964     if (pos > lane.getLaneShapeLength()) {
965         if (friendlyPos) {
966             pos = lane.getLaneShapeLength() - (double) 0.1;
967         } else {
968             WRITE_WARNING("The position of additional '" + additionalID + "' lies beyond the lane's '" + lane.getID() + "' length.");
969         }
970     }
971     return pos;
972 }
973 
974 
checkAndFixDetectorPosition(double & pos,const double laneLength,const bool friendlyPos)975 bool GNEAdditionalHandler::checkAndFixDetectorPosition(double& pos, const double laneLength, const bool friendlyPos) {
976     if (fabs(pos) > laneLength) {
977         if (!friendlyPos) {
978             return false;
979         } else if (pos < 0) {
980             pos = 0;
981         } else if (pos > laneLength) {
982             pos = laneLength - 0.01;
983         }
984     }
985     return true;
986 }
987 
988 
fixE2DetectorPosition(double & pos,double & length,const double laneLength,const bool friendlyPos)989 bool GNEAdditionalHandler::fixE2DetectorPosition(double& pos, double& length, const double laneLength, const bool friendlyPos) {
990     if ((pos < 0) || ((pos + length) > laneLength)) {
991         if (!friendlyPos) {
992             return false;
993         } else if (pos < 0) {
994             pos = 0;
995         } else if (pos > laneLength) {
996             pos = laneLength - 0.01;
997             length = 0;
998         } else if ((pos + length) > laneLength) {
999             length = laneLength - pos - 0.01;
1000         }
1001     }
1002     return true;
1003 }
1004 
1005 
1006 bool
accessCanBeCreated(GNEAdditional * busStopParent,GNEEdge & edge)1007 GNEAdditionalHandler::accessCanBeCreated(GNEAdditional* busStopParent, GNEEdge& edge) {
1008     // check that busStopParent is a busStop
1009     assert(busStopParent->getTagProperty().getTag() == SUMO_TAG_BUS_STOP);
1010     // check if exist another acces for the same busStop in the given edge
1011     for (auto i : busStopParent->getAdditionalChilds()) {
1012         for (auto j : edge.getLanes()) {
1013             if (i->getAttribute(SUMO_ATTR_LANE) == j->getID()) {
1014                 return false;
1015             }
1016         }
1017     }
1018     return true;
1019 }
1020 
1021 
1022 bool
checkOverlappingRerouterIntervals(GNEAdditional * rerouter,double newBegin,double newEnd)1023 GNEAdditionalHandler::checkOverlappingRerouterIntervals(GNEAdditional* rerouter, double newBegin, double newEnd) {
1024     // check that rerouter is correct
1025     assert(rerouter->getTagProperty().getTag() == SUMO_TAG_REROUTER);
1026     // declare a vector to keep sorted rerouter childs
1027     std::vector<std::pair<double, double>> sortedIntervals;
1028     // iterate over additional childs
1029     for (auto i : rerouter->getAdditionalChilds()) {
1030         sortedIntervals.push_back(std::make_pair(0., 0.));
1031         // set begin and end
1032         sortedIntervals.back().first = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_BEGIN));
1033         sortedIntervals.back().second = GNEAttributeCarrier::parse<double>(i->getAttribute(SUMO_ATTR_END));
1034     }
1035     // add new intervals
1036     sortedIntervals.push_back(std::make_pair(newBegin, newEnd));
1037     // sort childs
1038     std::sort(sortedIntervals.begin(), sortedIntervals.end());
1039     // check overlapping after sorting
1040     for (int i = 0; i < (int)sortedIntervals.size() - 1; i++) {
1041         if (sortedIntervals.at(i).second > sortedIntervals.at(i + 1).first) {
1042             return false;
1043         }
1044     }
1045     return true;
1046 }
1047 
1048 
1049 
1050 
1051 bool
parseAndBuildVaporizer(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1052 GNEAdditionalHandler::parseAndBuildVaporizer(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1053     bool abort = false;
1054     // parse attributes of Vaporizer
1055     const std::string edgeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_VAPORIZER, SUMO_ATTR_ID, abort);
1056     double begin = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_VAPORIZER, SUMO_ATTR_BEGIN, abort);
1057     double end = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_VAPORIZER, SUMO_ATTR_END, abort);
1058     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_VAPORIZER, SUMO_ATTR_NAME, abort);
1059     // Continue if all parameters were successfully loaded
1060     if (!abort) {
1061         // get GNEEdge
1062         GNEEdge* edge = viewNet->getNet()->retrieveEdge(edgeID, false);
1063         // check that all parameters are valid
1064         if (edge == nullptr) {
1065             WRITE_WARNING("The edge '" + edgeID + "' to use within the " + toString(SUMO_TAG_VAPORIZER) + " is not known.");
1066         } else if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_VAPORIZER, edgeID, false) != nullptr) {
1067             WRITE_WARNING("There is already a " + toString(SUMO_TAG_VAPORIZER) + " in the edge '" + edgeID + "'.");
1068         } else if (begin > end) {
1069             WRITE_WARNING("Time interval of " + toString(SUMO_TAG_VAPORIZER) + " isn't valid. Attribute '" + toString(SUMO_ATTR_BEGIN) + "' is greater than attribute '" + toString(SUMO_ATTR_END) + "'.");
1070         } else {
1071             // build vaporizer
1072             GNEAdditional* additionalCreated = buildVaporizer(viewNet, allowUndoRedo, edge, begin, end, name);
1073             // check if insertion has to be commited
1074             if (insertedAdditionals) {
1075                 insertedAdditionals->commitElementInsertion(additionalCreated);
1076             }
1077             return true;
1078         }
1079     }
1080     return false;
1081 }
1082 
1083 
1084 bool
parseAndBuildTAZ(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1085 GNEAdditionalHandler::parseAndBuildTAZ(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1086     bool abort = false;
1087     // parse attributes of Vaporizer
1088     const std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_TAZ, SUMO_ATTR_ID, abort);
1089     const PositionVector shape = GNEAttributeCarrier::parseAttributeFromXML<PositionVector>(attrs, id, SUMO_TAG_TAZ, SUMO_ATTR_SHAPE, abort);
1090     RGBColor color = GNEAttributeCarrier::parseAttributeFromXML<RGBColor>(attrs, id, SUMO_TAG_TAZ, SUMO_ATTR_COLOR, abort);
1091     // parse Netedit attributes
1092     bool blockMovement = false;
1093     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1094         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_TAZ, GNE_ATTR_BLOCK_MOVEMENT, abort);
1095     }
1096     // check edges
1097     std::vector<std::string> edgeIDs;
1098     if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
1099         std::string parsedAttribute = attrs.get<std::string>(SUMO_ATTR_EDGES, id.c_str(), abort, false);
1100         edgeIDs = GNEAttributeCarrier::parse<std::vector<std::string> >(parsedAttribute);
1101     }
1102     // check if all edge IDs are valid
1103     std::vector<GNEEdge*> edges;
1104     for (auto i : edgeIDs) {
1105         GNEEdge* edge = viewNet->getNet()->retrieveEdge(i, false);
1106         if (edge == nullptr) {
1107             WRITE_WARNING("Invalid " + toString(SUMO_TAG_EDGE) + " with ID = '" + i + "' within taz '" + id + "'.");
1108             abort = true;
1109         } else {
1110             edges.push_back(edge);
1111         }
1112     }
1113     // Continue if all parameters were successfully loaded
1114     if (!abort) {
1115         // check that all parameters are valid
1116         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_TAZ, id, false) != nullptr) {
1117             WRITE_WARNING("There is another " + toString(SUMO_TAG_TAZ) + " with the same ID='" + id + "'.");
1118         } else {
1119             // save ID of last created element
1120             GNEAdditional* additionalCreated = buildTAZ(viewNet, allowUndoRedo, id, shape, color, edges, blockMovement);
1121             // check if insertion has to be commited
1122             if (insertedAdditionals) {
1123                 insertedAdditionals->commitElementInsertion(additionalCreated);
1124             }
1125             return true;
1126         }
1127     }
1128     return false;
1129 }
1130 
1131 
1132 bool
parseAndBuildTAZSource(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1133 GNEAdditionalHandler::parseAndBuildTAZSource(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1134     bool abort = false;
1135     // parse attributes of Vaporizer
1136     const std::string edgeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_TAZSOURCE, SUMO_ATTR_ID, abort);
1137     const double departWeight = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, edgeID, SUMO_TAG_TAZSOURCE, SUMO_ATTR_WEIGHT, abort);
1138     // Continue if all parameters were successfully loaded
1139     if (!abort) {
1140         // get edge and TAZ
1141         GNEEdge* edge = viewNet->getNet()->retrieveEdge(edgeID, false);
1142         GNEAdditional* TAZ = nullptr;
1143         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1144         if (insertedAdditionals) {
1145             TAZ = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_TAZ);
1146         } else {
1147             bool ok = true;
1148             TAZ = viewNet->getNet()->retrieveAdditional(SUMO_TAG_TAZ, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1149         }
1150         // check that all parameters are valid
1151         if (edge == nullptr) {
1152             WRITE_WARNING("The edge '" + edgeID + "' to use within the " + toString(SUMO_TAG_TAZSOURCE) + " is not known.");
1153         } else if (TAZ == nullptr) {
1154             WRITE_WARNING("A " + toString(SUMO_TAG_TAZSOURCE) + " must be declared within the definition of a " + toString(SUMO_TAG_TAZ) + ".");
1155         } else {
1156             // save ID of last created element
1157             GNEAdditional* additionalCreated = buildTAZSource(viewNet, allowUndoRedo, TAZ, edge, departWeight);
1158             // check if insertion has to be commited
1159             if (insertedAdditionals) {
1160                 insertedAdditionals->commitElementInsertion(additionalCreated);
1161             }
1162             return true;
1163         }
1164     }
1165     return false;
1166 }
1167 
1168 
1169 bool
parseAndBuildTAZSink(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1170 GNEAdditionalHandler::parseAndBuildTAZSink(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1171     bool abort = false;
1172     // parse attributes of Vaporizer
1173     const std::string edgeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_TAZSINK, SUMO_ATTR_ID, abort);
1174     const double arrivalWeight = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, edgeID, SUMO_TAG_TAZSINK, SUMO_ATTR_WEIGHT, abort);
1175     // Continue if all parameters were successfully loaded
1176     if (!abort) {
1177         // get edge and TAZ
1178         GNEEdge* edge = viewNet->getNet()->retrieveEdge(edgeID, false);
1179         GNEAdditional* TAZ = nullptr;
1180         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1181         if (insertedAdditionals) {
1182             TAZ = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_TAZ);
1183         } else {
1184             bool ok = true;
1185             TAZ = viewNet->getNet()->retrieveAdditional(SUMO_TAG_TAZ, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1186         }
1187         // check that all parameters are valid
1188         if (edge == nullptr) {
1189             WRITE_WARNING("The edge '" + edgeID + "' to use within the " + toString(SUMO_TAG_TAZSINK) + " is not known.");
1190         } else if (TAZ == nullptr) {
1191             WRITE_WARNING("A " + toString(SUMO_TAG_TAZSINK) + " must be declared within the definition of a " + toString(SUMO_TAG_TAZ) + ".");
1192         } else {
1193             // save ID of last created element
1194             GNEAdditional* additionalCreated = buildTAZSink(viewNet, allowUndoRedo, TAZ, edge, arrivalWeight);
1195             // check if insertion has to be commited
1196             if (insertedAdditionals) {
1197                 insertedAdditionals->commitElementInsertion(additionalCreated);
1198             }
1199             return true;
1200         }
1201     }
1202     return false;
1203 }
1204 
1205 
1206 bool
parseAndBuildRouteProbe(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1207 GNEAdditionalHandler::parseAndBuildRouteProbe(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1208     bool abort = false;
1209     // parse attributes of RouteProbe
1210     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_ROUTEPROBE, SUMO_ATTR_ID, abort);
1211     std::string edgeId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_ROUTEPROBE, SUMO_ATTR_EDGE, abort);
1212     std::string freq = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_ROUTEPROBE, SUMO_ATTR_FREQUENCY, abort);
1213     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_ROUTEPROBE, SUMO_ATTR_NAME, abort);
1214     std::string file = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_ROUTEPROBE, SUMO_ATTR_FILE, abort);
1215     double begin = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_ROUTEPROBE, SUMO_ATTR_BEGIN, abort);
1216     // Continue if all parameters were sucesfully loaded
1217     if (!abort) {
1218         // get edge
1219         GNEEdge* edge = viewNet->getNet()->retrieveEdge(edgeId, false);
1220         // check that all elements are valid
1221         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, id, false) != nullptr) {
1222             WRITE_WARNING("There is another " + toString(SUMO_TAG_ROUTEPROBE) + " with the same ID='" + id + "'.");
1223         } else if (edge == nullptr) {
1224             // Write error if lane isn't valid
1225             WRITE_WARNING("The edge '" + edgeId + "' to use within the " + toString(SUMO_TAG_ROUTEPROBE) + " '" + id + "' is not known.");
1226         } else {
1227             // Freq needs an extra check, because it can be empty
1228             if (GNEAttributeCarrier::canParse<double>(freq)) {
1229                 if (GNEAttributeCarrier::parse<double>(freq) < 0) {
1230                     WRITE_WARNING(toString(SUMO_ATTR_FREQUENCY) + "of " + toString(SUMO_TAG_ROUTEPROBE) + "'" + id + "' cannot be negative.");
1231                     freq = "";
1232                 }
1233             } else {
1234                 if (freq.empty()) {
1235                     WRITE_WARNING(toString(SUMO_ATTR_FREQUENCY) + "of " + toString(SUMO_TAG_ROUTEPROBE) + "'" + id + "' cannot be parsed to float.");
1236                 }
1237                 freq = "";
1238             }
1239             // save ID of last created element
1240             GNEAdditional* additionalCreated = buildRouteProbe(viewNet, allowUndoRedo, id, edge, freq, name, file, begin);
1241             // check if insertion has to be commited
1242             if (insertedAdditionals) {
1243                 insertedAdditionals->commitElementInsertion(additionalCreated);
1244             }
1245             return true;
1246         }
1247     }
1248     return false;
1249 }
1250 
1251 
1252 bool
parseAndBuildCalibratorFlow(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1253 GNEAdditionalHandler::parseAndBuildCalibratorFlow(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1254     bool abort = false;
1255     // parse attributes of calibrator flows
1256     std::string vehicleTypeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_TYPE, abort);
1257     std::string routeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_ROUTE, abort);
1258     std::string vehsPerHour = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_VEHSPERHOUR, abort);
1259     std::string speed = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_SPEED, abort);
1260     RGBColor color = GNEAttributeCarrier::parseAttributeFromXML<RGBColor>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_COLOR, abort);
1261     std::string departLane = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_DEPARTLANE, abort);
1262     std::string departPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_DEPARTPOS, abort);
1263     std::string departSpeed = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_DEPARTSPEED, abort);
1264     std::string arrivalLane = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_ARRIVALLANE, abort);
1265     std::string arrivalPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_ARRIVALPOS, abort);
1266     std::string arrivalSpeed = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_ARRIVALSPEED, abort);
1267     std::string line = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_LINE, abort);
1268     int personNumber = GNEAttributeCarrier::parseAttributeFromXML<int>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_PERSON_NUMBER, abort);
1269     int containerNumber = GNEAttributeCarrier::parseAttributeFromXML<int>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_CONTAINER_NUMBER, abort);
1270     bool reroute = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_REROUTE, abort);
1271     std::string departPosLat = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_DEPARTPOS_LAT, abort);
1272     std::string arrivalPosLat = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_ARRIVALPOS_LAT, abort);
1273     double begin = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_BEGIN, abort);
1274     double end = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_CALIBRATORFLOW, SUMO_ATTR_END, abort);
1275     // Continue if all parameters were sucesfully loaded
1276     if (!abort) {
1277         // obtain route, vehicle type and calibrator parent
1278         GNEDemandElement* route = viewNet->getNet()->retrieveDemandElement(SUMO_TAG_ROUTE, routeID, false);
1279         GNEDemandElement* vtype = viewNet->getNet()->retrieveDemandElement(SUMO_TAG_VTYPE, vehicleTypeID, false);
1280         GNEAdditional* calibrator = nullptr;
1281         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1282         if (insertedAdditionals) {
1283             calibrator = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_CALIBRATOR);
1284         } else {
1285             bool ok = true;
1286             calibrator = viewNet->getNet()->retrieveAdditional(SUMO_TAG_CALIBRATOR, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1287         }
1288         // check that all elements are valid
1289         if (route == nullptr) {
1290             WRITE_WARNING(toString(SUMO_TAG_CALIBRATORFLOW) + " cannot be created; their " + toString(SUMO_TAG_ROUTE) + " with ID = '" + routeID + "' doesn't exist");
1291             abort = true;
1292         } else if (vtype == nullptr) {
1293             WRITE_WARNING(toString(SUMO_TAG_CALIBRATORFLOW) + " cannot be created; their " + toString(SUMO_TAG_VTYPE) + " with ID = '" + vehicleTypeID + "' doesn't exist");
1294             abort = true;
1295         } else if ((vehsPerHour.empty()) && (speed.empty())) {
1296             WRITE_WARNING(toString(SUMO_TAG_CALIBRATORFLOW) + " cannot be created; At least parameters " + toString(SUMO_ATTR_VEHSPERHOUR) + " or " + toString(SUMO_ATTR_SPEED) + " has to be defined");
1297             abort = true;
1298         } else if (calibrator != nullptr) {
1299             // save ID of last created element
1300             GNEAdditional* additionalCreated = buildCalibratorFlow(viewNet, allowUndoRedo, calibrator, route, vtype, vehsPerHour, speed, color, departLane, departPos, departSpeed, arrivalLane, arrivalPos, arrivalSpeed,
1301                                                line, personNumber, containerNumber, reroute, departPosLat, arrivalPosLat, begin, end);
1302             // check if insertion has to be commited
1303             if (insertedAdditionals) {
1304                 insertedAdditionals->commitElementInsertion(additionalCreated);
1305             }
1306             return true;
1307         }
1308     }
1309     return false;
1310 }
1311 
1312 
1313 void
parseAndBuildPoly(const SUMOSAXAttributes & attrs)1314 GNEAdditionalHandler::parseAndBuildPoly(const SUMOSAXAttributes& attrs) {
1315     bool abort = false;
1316     // parse attributes of polygons
1317     std::string polygonID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_POLY, SUMO_ATTR_ID, abort);
1318     PositionVector shape = GNEAttributeCarrier::parseAttributeFromXML<PositionVector>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_SHAPE, abort);
1319     double layer = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_LAYER, abort);
1320     bool fill = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_POLY, SUMO_ATTR_FILL, abort);
1321     double lineWidth = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_LINEWIDTH, abort);
1322     std::string type = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_TYPE, abort);
1323     RGBColor color = GNEAttributeCarrier::parseAttributeFromXML<RGBColor>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_COLOR, abort);
1324     double angle = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_ANGLE, abort);
1325     std::string imgFile = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_IMGFILE, abort);
1326     bool relativePath = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, polygonID, SUMO_TAG_POLY, SUMO_ATTR_RELATIVEPATH, abort);
1327     // Continue if all parameters were sucesfully loaded
1328     if (!abort) {
1329         // check if shape must be loaded as geo attribute
1330         bool geo = false;
1331         const GeoConvHelper* gch = myGeoConvHelper != nullptr ? myGeoConvHelper : &GeoConvHelper::getFinal();
1332         if (attrs.getOpt<bool>(SUMO_ATTR_GEO, polygonID.c_str(), abort, false)) {
1333             geo = true;
1334             bool success = true;
1335             for (int i = 0; i < (int)shape.size(); i++) {
1336                 success &= gch->x2cartesian_const(shape[i]);
1337             }
1338             if (!success) {
1339                 WRITE_WARNING("Unable to project coordinates for polygon '" + polygonID + "'.");
1340                 return;
1341             }
1342         }
1343         // check if img file is absolute
1344         if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
1345             imgFile = FileHelpers::getConfigurationRelative(getFileName(), imgFile);
1346         }
1347         // create polygon, or show an error if polygon already exists
1348         if (!myShapeContainer.addPolygon(polygonID, type, color, layer, angle, imgFile, relativePath, shape, geo, fill, lineWidth, false)) {
1349             WRITE_WARNING("Polygon with ID '" + polygonID + "' already exists.");
1350         } else {
1351             // update myLastParameterised with the last inserted Polygon
1352             myLastParameterised = myShapeContainer.getPolygons().get(polygonID);
1353         }
1354     }
1355 }
1356 
1357 
1358 bool
parseAndBuildVariableSpeedSign(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1359 GNEAdditionalHandler::parseAndBuildVariableSpeedSign(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1360     bool abort = false;
1361     // parse attributes of VSS
1362     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_VSS, SUMO_ATTR_ID, abort);
1363     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_VSS, SUMO_ATTR_NAME, abort);
1364     GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_VSS, SUMO_ATTR_FILE, abort); // deprecated
1365     std::string lanesIDs = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_VSS, SUMO_ATTR_LANES, abort);
1366     Position pos = GNEAttributeCarrier::parseAttributeFromXML<Position>(attrs, id, SUMO_TAG_VSS, SUMO_ATTR_POSITION, abort);
1367     // parse Netedit attributes
1368     bool blockMovement = false;
1369     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1370         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_VSS, GNE_ATTR_BLOCK_MOVEMENT, abort);
1371     }
1372     // Continue if all parameters were sucesfully loaded
1373     if (!abort) {
1374         // obtain lanes
1375         std::vector<GNELane*> lanes;
1376         if (GNEAttributeCarrier::canParse<std::vector<GNELane*> >(viewNet->getNet(), lanesIDs, true)) {
1377             lanes = GNEAttributeCarrier::parse<std::vector<GNELane*> >(viewNet->getNet(), lanesIDs);
1378         }
1379         // check that all elements are valid
1380         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_VSS, id, false) != nullptr) {
1381             WRITE_WARNING("There is another " + toString(SUMO_TAG_VSS) + " with the same ID='" + id + "'.");
1382         } else if (lanes.size() == 0) {
1383             WRITE_WARNING("A Variable Speed Sign needs at least one lane.");
1384         } else {
1385             // save ID of last created element
1386             GNEAdditional* additionalCreated = buildVariableSpeedSign(viewNet, allowUndoRedo, id, pos, lanes, name, blockMovement);
1387             // check if insertion has to be commited
1388             if (insertedAdditionals) {
1389                 insertedAdditionals->commitElementInsertion(additionalCreated);
1390             }
1391             return true;
1392         }
1393     }
1394     return false;
1395 }
1396 
1397 
1398 bool
parseAndBuildVariableSpeedSignStep(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1399 GNEAdditionalHandler::parseAndBuildVariableSpeedSignStep(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1400     bool abort = false;
1401     // Load step values
1402     double time = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_STEP, SUMO_ATTR_TIME, abort);
1403     double speed = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_STEP, SUMO_ATTR_SPEED, abort);
1404     // Continue if all parameters were sucesfully loaded
1405     if (!abort) {
1406         // get Variable Speed Signal
1407         GNEAdditional* variableSpeedSign = nullptr;
1408         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1409         if (insertedAdditionals) {
1410             variableSpeedSign = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_VSS);
1411         } else {
1412             bool ok = true;
1413             variableSpeedSign = viewNet->getNet()->retrieveAdditional(SUMO_TAG_VSS, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1414         }
1415         // check that all parameters are valid
1416         if (variableSpeedSign != nullptr) {
1417             // save ID of last created element
1418             GNEAdditional* additionalCreated = buildVariableSpeedSignStep(viewNet, allowUndoRedo, variableSpeedSign, time, speed);
1419             // check if insertion has to be commited
1420             if (insertedAdditionals) {
1421                 insertedAdditionals->commitElementInsertion(additionalCreated);
1422             }
1423             return true;
1424         }
1425     }
1426     return false;
1427 }
1428 
1429 
1430 bool
parseAndBuildRerouter(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1431 GNEAdditionalHandler::parseAndBuildRerouter(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1432     bool abort = false;
1433     // parse attributes of Rerouter
1434     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_REROUTER, SUMO_ATTR_ID, abort);
1435     std::string edgesIDs = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_REROUTER, SUMO_ATTR_EDGES, abort);
1436     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_REROUTER, SUMO_ATTR_NAME, abort);
1437     std::string file = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_REROUTER, SUMO_ATTR_FILE, abort);
1438     double probability = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_REROUTER, SUMO_ATTR_PROB, abort);
1439     bool off = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_REROUTER, SUMO_ATTR_OFF, abort);
1440     double timeThreshold = attrs.getOpt<double>(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), abort, 0);
1441     const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), abort, "");
1442     Position pos = GNEAttributeCarrier::parseAttributeFromXML<Position>(attrs, id, SUMO_TAG_REROUTER, SUMO_ATTR_POSITION, abort);
1443     // parse Netedit attributes
1444     bool blockMovement = false;
1445     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1446         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_REROUTER, GNE_ATTR_BLOCK_MOVEMENT, abort);
1447     }
1448     // Continue if all parameters were sucesfully loaded
1449     if (!abort) {
1450         // obtain edges
1451         std::vector<GNEEdge*> edges;
1452         if (GNEAttributeCarrier::canParse<std::vector<GNEEdge*> >(viewNet->getNet(), edgesIDs, true)) {
1453             edges = GNEAttributeCarrier::parse<std::vector<GNEEdge*> >(viewNet->getNet(), edgesIDs);
1454         }
1455         // check that all elements are valid
1456         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_REROUTER, id, false) != nullptr) {
1457             WRITE_WARNING("There is another " + toString(SUMO_TAG_REROUTER) + " with the same ID='" + id + "'.");
1458         } else if (edges.size() == 0) {
1459             WRITE_WARNING("A rerouter needs at least one Edge");
1460         } else {
1461             // save ID of last created element
1462             GNEAdditional* additionalCreated = buildRerouter(viewNet, allowUndoRedo, id, pos, edges, probability, name,
1463                                                file, off, timeThreshold, vTypes, blockMovement);
1464             // check if insertion has to be commited
1465             if (insertedAdditionals) {
1466                 insertedAdditionals->commitElementInsertion(additionalCreated);
1467             }
1468             return true;
1469         }
1470     }
1471     return false;
1472 }
1473 
1474 
1475 bool
parseAndBuildRerouterInterval(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1476 GNEAdditionalHandler::parseAndBuildRerouterInterval(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1477     bool abort = false;
1478     // parse attributes of Rerouter
1479     double begin = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_INTERVAL, SUMO_ATTR_BEGIN, abort);
1480     double end = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_INTERVAL, SUMO_ATTR_END, abort);
1481     // Continue if all parameters were sucesfully loaded
1482     if (!abort) {
1483         // obtain rerouter
1484         GNEAdditional* rerouter;
1485         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1486         if (insertedAdditionals) {
1487             rerouter = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_REROUTER);
1488         } else {
1489             bool ok = true;
1490             rerouter = viewNet->getNet()->retrieveAdditional(SUMO_TAG_REROUTER, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1491         }
1492         // special case for load multiple intervals in the same rerouter
1493         if (rerouter == nullptr) {
1494             GNEAdditional* lastInsertedRerouterInterval = nullptr;
1495             // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1496             if (insertedAdditionals) {
1497                 lastInsertedRerouterInterval = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_INTERVAL);
1498             } else {
1499                 bool ok = true;
1500                 lastInsertedRerouterInterval = viewNet->getNet()->retrieveAdditional(SUMO_TAG_INTERVAL, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1501             }
1502             if (lastInsertedRerouterInterval) {
1503                 rerouter = lastInsertedRerouterInterval->getAdditionalParents().at(0);
1504             }
1505         }
1506         // check that rerouterInterval can be created
1507         if (begin >= end) {
1508             WRITE_WARNING(toString(SUMO_TAG_INTERVAL) + " cannot be created; Attribute " + toString(SUMO_ATTR_END) + " must be greather than " + toString(SUMO_ATTR_BEGIN) + ".");
1509         } else if (rerouter != nullptr) {
1510             // save ID of last created element
1511             GNEAdditional* additionalCreated = buildRerouterInterval(viewNet, allowUndoRedo, rerouter, begin, end);
1512             // check if insertion has to be commited
1513             if (insertedAdditionals) {
1514                 insertedAdditionals->commitElementInsertion(additionalCreated);
1515             }
1516             return true;
1517         }
1518     }
1519     return false;
1520 }
1521 
1522 
1523 bool
parseAndBuildRerouterClosingLaneReroute(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1524 GNEAdditionalHandler::parseAndBuildRerouterClosingLaneReroute(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1525     bool abort = false;
1526     // parse attributes of Rerouter
1527     std::string laneID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CLOSING_LANE_REROUTE, SUMO_ATTR_ID, abort);
1528     std::string allow = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CLOSING_LANE_REROUTE, SUMO_ATTR_ALLOW, abort);
1529     std::string disallow = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CLOSING_LANE_REROUTE, SUMO_ATTR_DISALLOW, abort);
1530     // Continue if all parameters were sucesfully loaded
1531     if (!abort) {
1532         // obtain lane and rerouter interval
1533         GNELane* lane = viewNet->getNet()->retrieveLane(laneID, false, true);
1534         GNEAdditional* rerouterInterval = nullptr;
1535         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1536         if (insertedAdditionals) {
1537             rerouterInterval = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_INTERVAL);
1538         } else {
1539             bool ok = true;
1540             rerouterInterval = viewNet->getNet()->retrieveAdditional(SUMO_TAG_INTERVAL, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1541         }
1542         // check that all elements are valid
1543         if (lane == nullptr) {
1544             WRITE_WARNING("The lane '" + laneID + "' to use within the " + toString(SUMO_TAG_CLOSING_LANE_REROUTE) + " is not known.");
1545         } else if (rerouterInterval != nullptr) {
1546             // save ID of last created element
1547             GNEAdditional* additionalCreated = buildClosingLaneReroute(viewNet, allowUndoRedo, rerouterInterval, lane, parseVehicleClasses(allow, disallow));
1548             // check if insertion has to be commited
1549             if (insertedAdditionals) {
1550                 insertedAdditionals->commitElementInsertion(additionalCreated);
1551             }
1552             return true;
1553         }
1554     }
1555     return false;
1556 }
1557 
1558 
1559 bool
parseAndBuildRerouterClosingReroute(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1560 GNEAdditionalHandler::parseAndBuildRerouterClosingReroute(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1561     bool abort = false;
1562     // parse attributes of Rerouter
1563     std::string edgeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CLOSING_REROUTE, SUMO_ATTR_ID, abort);
1564     std::string allow = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CLOSING_REROUTE, SUMO_ATTR_ALLOW, abort);
1565     std::string disallow = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CLOSING_REROUTE, SUMO_ATTR_DISALLOW, abort);
1566     // Continue if all parameters were sucesfully loaded
1567     if (!abort) {
1568         // obtain edge and rerouter interval
1569         GNEEdge* edge = viewNet->getNet()->retrieveEdge(edgeID, false);
1570         GNEAdditional* rerouterInterval = nullptr;
1571         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1572         if (insertedAdditionals) {
1573             rerouterInterval = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_INTERVAL);
1574         } else {
1575             bool ok = true;
1576             rerouterInterval = viewNet->getNet()->retrieveAdditional(SUMO_TAG_INTERVAL, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1577         }
1578         // check that all elements are valid
1579         if (edge == nullptr) {
1580             WRITE_WARNING("The edge '" + edgeID + "' to use within the " + toString(SUMO_TAG_CLOSING_REROUTE) + " is not known.");
1581         } else if (rerouterInterval != nullptr) {
1582             // save ID of last created element
1583             GNEAdditional* additionalCreated = buildClosingReroute(viewNet, allowUndoRedo, rerouterInterval, edge, parseVehicleClasses(allow, disallow));
1584             // check if insertion has to be commited
1585             if (insertedAdditionals) {
1586                 insertedAdditionals->commitElementInsertion(additionalCreated);
1587             }
1588             return true;
1589         }
1590     }
1591     return false;
1592 }
1593 
1594 
1595 bool
parseAndBuildRerouterDestProbReroute(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1596 GNEAdditionalHandler::parseAndBuildRerouterDestProbReroute(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1597     bool abort = false;
1598     // parse attributes of Rerouter
1599     std::string edgeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_DEST_PROB_REROUTE, SUMO_ATTR_ID, abort);
1600     double probability = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_DEST_PROB_REROUTE, SUMO_ATTR_PROB, abort);
1601     // Continue if all parameters were sucesfully loaded
1602     if (!abort) {
1603         // obtain edge and rerouter interval
1604         GNEEdge* edge = viewNet->getNet()->retrieveEdge(edgeID, false);
1605         GNEAdditional* rerouterInterval = nullptr;
1606         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1607         if (insertedAdditionals) {
1608             rerouterInterval = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_INTERVAL);
1609         } else {
1610             bool ok = true;
1611             rerouterInterval = viewNet->getNet()->retrieveAdditional(SUMO_TAG_INTERVAL, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1612         }
1613         // check that all elements are valid
1614         if (edge == nullptr) {
1615             WRITE_WARNING("The edge '" + edgeID + "' to use within the " + toString(SUMO_TAG_DEST_PROB_REROUTE) + " is not known.");
1616         } else if (rerouterInterval != nullptr) {
1617             // save ID of last created element
1618             GNEAdditional* additionalCreated = builDestProbReroute(viewNet, allowUndoRedo, rerouterInterval, edge, probability);
1619             // check if insertion has to be commited
1620             if (insertedAdditionals) {
1621                 insertedAdditionals->commitElementInsertion(additionalCreated);
1622             }
1623             return true;
1624         }
1625     }
1626     return false;
1627 }
1628 
1629 
1630 bool
parseAndBuildRerouterParkingAreaReroute(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1631 GNEAdditionalHandler::parseAndBuildRerouterParkingAreaReroute(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1632     bool abort = false;
1633     // parse attributes of Rerouter
1634     std::string parkingAreaID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_PARKING_ZONE_REROUTE, SUMO_ATTR_ID, abort);
1635     double probability = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_PARKING_ZONE_REROUTE, SUMO_ATTR_PROB, abort);
1636     bool visible = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_PARKING_ZONE_REROUTE, SUMO_ATTR_VISIBLE, abort);
1637     // Continue if all parameters were sucesfully loaded
1638     if (!abort) {
1639         // obtain edge and rerouter interval
1640         GNEAdditional* parkingArea = viewNet->getNet()->retrieveAdditional(SUMO_TAG_PARKING_AREA, parkingAreaID, false);
1641         GNEAdditional* rerouterInterval = nullptr;
1642         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1643         if (insertedAdditionals) {
1644             rerouterInterval = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_INTERVAL);
1645         } else {
1646             bool ok = true;
1647             rerouterInterval = viewNet->getNet()->retrieveAdditional(SUMO_TAG_INTERVAL, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1648         }
1649         // check that all elements are valid
1650         if (parkingArea == nullptr) {
1651             WRITE_WARNING("The parkingArea '" + parkingAreaID + "' to use within the " + toString(SUMO_TAG_PARKING_ZONE_REROUTE) + " is not known.");
1652         } else if (rerouterInterval != nullptr) {
1653             // save ID of last created element
1654             GNEAdditional* additionalCreated = builParkingAreaReroute(viewNet, allowUndoRedo, rerouterInterval, parkingArea, probability, visible);
1655             // check if insertion has to be commited
1656             if (insertedAdditionals) {
1657                 insertedAdditionals->commitElementInsertion(additionalCreated);
1658             }
1659             return true;
1660         }
1661     }
1662     return false;
1663 }
1664 
1665 
1666 bool
parseAndBuildRerouterRouteProbReroute(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1667 GNEAdditionalHandler::parseAndBuildRerouterRouteProbReroute(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1668     bool abort = false;
1669     // parse attributes of Rerouter
1670     std::string routeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_ROUTE_PROB_REROUTE, SUMO_ATTR_ID, abort);
1671     double probability = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_ROUTE_PROB_REROUTE, SUMO_ATTR_PROB, abort);
1672     // Continue if all parameters were sucesfully loaded
1673     if (!abort) {
1674         // obtain rerouter interval
1675         GNEAdditional* rerouterInterval = nullptr;
1676         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1677         if (insertedAdditionals) {
1678             rerouterInterval = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_INTERVAL);
1679         } else {
1680             bool ok = true;
1681             rerouterInterval = viewNet->getNet()->retrieveAdditional(SUMO_TAG_INTERVAL, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1682         }
1683         // check that all elements are valid
1684         if (rerouterInterval != nullptr) {
1685             // save ID of last created element
1686             GNEAdditional* additionalCreated = buildRouteProbReroute(viewNet, allowUndoRedo, rerouterInterval, routeID, probability);
1687             // check if insertion has to be commited
1688             if (insertedAdditionals) {
1689                 insertedAdditionals->commitElementInsertion(additionalCreated);
1690             }
1691             return true;
1692         }
1693     }
1694     return false;
1695 }
1696 
1697 
1698 bool
parseAndBuildBusStop(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1699 GNEAdditionalHandler::parseAndBuildBusStop(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1700     bool abort = false;
1701     // parse attributes of bus stop
1702     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_BUS_STOP, SUMO_ATTR_ID, abort);
1703     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_BUS_STOP, SUMO_ATTR_LANE, abort);
1704     std::string startPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_BUS_STOP, SUMO_ATTR_STARTPOS, abort);
1705     std::string endPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_BUS_STOP, SUMO_ATTR_ENDPOS, abort);
1706     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_BUS_STOP, SUMO_ATTR_NAME, abort);
1707     std::vector<std::string> lines = GNEAttributeCarrier::parseAttributeFromXML<std::vector<std::string> >(attrs, id, SUMO_TAG_BUS_STOP, SUMO_ATTR_LINES, abort);
1708     const int personCapacity = GNEAttributeCarrier::parseAttributeFromXML<int>(attrs, id, SUMO_TAG_BUS_STOP, SUMO_ATTR_PERSON_CAPACITY, abort);
1709     bool friendlyPosition = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_BUS_STOP, SUMO_ATTR_FRIENDLY_POS, abort);
1710     // parse Netedit attributes
1711     bool blockMovement = false;
1712     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1713         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_BUS_STOP, GNE_ATTR_BLOCK_MOVEMENT, abort);
1714     }
1715     // Continue if all parameters were sucesfully loaded
1716     if (!abort) {
1717         // get pointer to lane
1718         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
1719         // check that all elements are valid
1720         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_BUS_STOP, id, false) != nullptr) {
1721             WRITE_WARNING("There is another " + toString(SUMO_TAG_BUS_STOP) + " with the same ID='" + id + "'.");
1722         } else if (lane == nullptr) {
1723             // Write error if lane isn't valid
1724             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_BUS_STOP) + " '" + id + "' is not known.");
1725         } else if (!GNEStoppingPlace::checkStoppinPlacePosition(startPos, endPos, lane->getParentEdge().getNBEdge()->getFinalLength(), friendlyPosition)) {
1726             // Write error if position isn't valid
1727             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_BUS_STOP) + " with ID = '" + id + "'.");
1728         } else {
1729             // save ID of last created element
1730             GNEAdditional* additionalCreated = buildBusStop(viewNet, allowUndoRedo, id, lane, startPos, endPos, name, lines, personCapacity, friendlyPosition, blockMovement);
1731             // check if insertion has to be commited
1732             if (insertedAdditionals) {
1733                 insertedAdditionals->commitElementInsertion(additionalCreated);
1734             }
1735             return true;
1736         }
1737     }
1738     return false;
1739 }
1740 
1741 
1742 bool
parseAndBuildContainerStop(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1743 GNEAdditionalHandler::parseAndBuildContainerStop(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1744     bool abort = false;
1745     // parse attributes of container stop
1746     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CONTAINER_STOP, SUMO_ATTR_ID, abort);
1747     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CONTAINER_STOP, SUMO_ATTR_LANE, abort);
1748     std::string startPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CONTAINER_STOP, SUMO_ATTR_STARTPOS, abort);
1749     std::string endPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CONTAINER_STOP, SUMO_ATTR_ENDPOS, abort);
1750     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CONTAINER_STOP, SUMO_ATTR_NAME, abort);
1751     std::vector<std::string> lines = GNEAttributeCarrier::parseAttributeFromXML<std::vector<std::string> >(attrs, id, SUMO_TAG_CONTAINER_STOP, SUMO_ATTR_LINES, abort);
1752     bool friendlyPosition = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_CONTAINER_STOP, SUMO_ATTR_FRIENDLY_POS, abort);
1753     // parse Netedit attributes
1754     bool blockMovement = false;
1755     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1756         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_CONTAINER_STOP, GNE_ATTR_BLOCK_MOVEMENT, abort);
1757     }
1758     // Continue if all parameters were sucesfully loaded
1759     if (!abort) {
1760         // get pointer to lane
1761         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
1762         // check that all elements are valid
1763         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_CONTAINER_STOP, id, false) != nullptr) {
1764             WRITE_WARNING("There is another " + toString(SUMO_TAG_CONTAINER_STOP) + " with the same ID='" + id + "'.");
1765         } else if (lane == nullptr) {
1766             // Write error if lane isn't valid
1767             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_CONTAINER_STOP) + " '" + id + "' is not known.");
1768         } else if (!GNEStoppingPlace::checkStoppinPlacePosition(startPos, endPos, lane->getParentEdge().getNBEdge()->getFinalLength(), friendlyPosition)) {
1769             // write error if position isn't valid
1770             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_CONTAINER_STOP) + " with ID = '" + id + "'.");
1771         } else {
1772             // save ID of last created element
1773             GNEAdditional* additionalCreated = buildContainerStop(viewNet, allowUndoRedo, id, lane, startPos, endPos, name, lines, friendlyPosition, blockMovement);
1774             // check if insertion has to be commited
1775             if (insertedAdditionals) {
1776                 insertedAdditionals->commitElementInsertion(additionalCreated);
1777             }
1778             return true;
1779         }
1780     }
1781     return false;
1782 }
1783 
1784 
1785 bool
parseAndBuildAccess(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1786 GNEAdditionalHandler::parseAndBuildAccess(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1787     bool abort = false;
1788     // parse attributes of Entry
1789     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_ACCESS, SUMO_ATTR_LANE, abort);
1790     std::string position = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_ACCESS, SUMO_ATTR_POSITION, abort);
1791     std::string length = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_ACCESS, SUMO_ATTR_LENGTH, abort);
1792     bool friendlyPos = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_ACCESS, SUMO_ATTR_FRIENDLY_POS, abort);
1793     // parse Netedit attributes
1794     bool blockMovement = false;
1795     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1796         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_ACCESS, GNE_ATTR_BLOCK_MOVEMENT, abort);
1797     }
1798     // Check if parsing of parameters was correct
1799     if (!abort) {
1800         double posDouble = GNEAttributeCarrier::parse<double>(position);
1801         // get lane and busStop parent
1802         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
1803         GNEAdditional* busStop = nullptr;
1804         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1805         if (insertedAdditionals) {
1806             busStop = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_BUS_STOP);
1807         } else {
1808             bool ok = true;
1809             busStop = viewNet->getNet()->retrieveAdditional(SUMO_TAG_BUS_STOP, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1810         }
1811         // check that all parameters are valid
1812         if (lane == nullptr) {
1813             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_ACCESS) + " is not known.");
1814         } else if (busStop == nullptr) {
1815             WRITE_WARNING("A " + toString(SUMO_TAG_ACCESS) + " must be declared within the definition of a " + toString(SUMO_TAG_BUS_STOP) + ".");
1816         } else if (!checkAndFixDetectorPosition(posDouble, lane->getLaneShapeLength(), friendlyPos)) {
1817             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_ACCESS) + ".");
1818         } else if (!accessCanBeCreated(busStop, lane->getParentEdge())) {
1819             WRITE_WARNING("Edge '" + lane->getParentEdge().getID() + "' already has an Access for busStop '" + busStop->getID() + "'");
1820         } else {
1821             // save ID of last created element
1822             GNEAdditional* additionalCreated = buildAccess(viewNet, allowUndoRedo, busStop, lane, toString(posDouble), length, friendlyPos, blockMovement);
1823             // check if insertion has to be commited
1824             if (insertedAdditionals) {
1825                 insertedAdditionals->commitElementInsertion(additionalCreated);
1826             }
1827             return true;
1828         }
1829     }
1830     return false;
1831 }
1832 
1833 
1834 bool
parseAndBuildChargingStation(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1835 GNEAdditionalHandler::parseAndBuildChargingStation(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1836     bool abort = false;
1837     // parse attributes of charging station
1838     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CHARGING_STATION, SUMO_ATTR_ID, abort);
1839     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_LANE, abort);
1840     std::string startPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_STARTPOS, abort);
1841     std::string endPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_ENDPOS, abort);
1842     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_NAME, abort);
1843     double chargingPower = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_CHARGINGPOWER, abort);
1844     double efficiency = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_EFFICIENCY, abort);
1845     bool chargeInTransit = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_CHARGEINTRANSIT, abort);
1846     double chargeDelay = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_CHARGEDELAY, abort);
1847     bool friendlyPosition = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_CHARGING_STATION, SUMO_ATTR_FRIENDLY_POS, abort);
1848     // parse Netedit attributes
1849     bool blockMovement = false;
1850     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1851         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_CHARGING_STATION, GNE_ATTR_BLOCK_MOVEMENT, abort);
1852     }
1853     // Continue if all parameters were sucesfully loaded
1854     if (!abort) {
1855         // get pointer to lane
1856         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
1857         // check that all elements are valid
1858         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_CHARGING_STATION, id, false) != nullptr) {
1859             WRITE_WARNING("There is another " + toString(SUMO_TAG_CHARGING_STATION) + " with the same ID='" + id + "'.");
1860         } else if (lane == nullptr) {
1861             // Write error if lane isn't valid
1862             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_CHARGING_STATION) + " '" + id + "' is not known.");
1863         } else if (!GNEStoppingPlace::checkStoppinPlacePosition(startPos, endPos, lane->getParentEdge().getNBEdge()->getFinalLength(), friendlyPosition)) {
1864             // write error if position isn't valid
1865             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_CHARGING_STATION) + " with ID = '" + id + "'.");
1866         } else {
1867             // save ID of last created element
1868             GNEAdditional* additionalCreated = buildChargingStation(viewNet, allowUndoRedo, id, lane, startPos, endPos, name, chargingPower,
1869                                                efficiency, chargeInTransit, chargeDelay, friendlyPosition, blockMovement);
1870             // check if insertion has to be commited
1871             if (insertedAdditionals) {
1872                 insertedAdditionals->commitElementInsertion(additionalCreated);
1873             }
1874             return true;
1875         }
1876     }
1877     return false;
1878 }
1879 
1880 
1881 bool
parseAndBuildParkingArea(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1882 GNEAdditionalHandler::parseAndBuildParkingArea(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1883     bool abort = false;
1884     // parse attributes of charging station
1885     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_PARKING_AREA, SUMO_ATTR_ID, abort);
1886     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_LANE, abort);
1887     std::string startPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_STARTPOS, abort);
1888     std::string endPos = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_ENDPOS, abort);
1889     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_NAME, abort);
1890     bool friendlyPosition = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_FRIENDLY_POS, abort);
1891     int roadSideCapacity = GNEAttributeCarrier::parseAttributeFromXML<int>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_ROADSIDE_CAPACITY, abort);
1892     bool onRoad = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_ONROAD, abort);
1893     double width = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_WIDTH, abort);
1894     std::string length = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_LENGTH, abort);
1895     double angle = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_PARKING_AREA, SUMO_ATTR_ANGLE, abort);
1896     // parse Netedit attributes
1897     bool blockMovement = false;
1898     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1899         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_PARKING_AREA, GNE_ATTR_BLOCK_MOVEMENT, abort);
1900     }
1901     // Continue if all parameters were sucesfully loaded
1902     if (!abort) {
1903         // get pointer to lane
1904         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
1905         // check that all elements are valid
1906         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_PARKING_AREA, id, false) != nullptr) {
1907             WRITE_WARNING("There is another " + toString(SUMO_TAG_PARKING_AREA) + " with the same ID='" + id + "'.");
1908         } else if (lane == nullptr) {
1909             // Write error if lane isn't valid
1910             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_PARKING_AREA) + " '" + id + "' is not known.");
1911         } else if (!GNEStoppingPlace::checkStoppinPlacePosition(startPos, endPos, lane->getParentEdge().getNBEdge()->getFinalLength(), friendlyPosition)) {
1912             // write error if position isn't valid
1913             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_PARKING_AREA) + " with ID = '" + id + "'.");
1914         } else {
1915             // save ID of last created element
1916             GNEAdditional* additionalCreated = buildParkingArea(viewNet, allowUndoRedo, id, lane, startPos, endPos, name, friendlyPosition,
1917                                                roadSideCapacity, onRoad, width, length, angle, blockMovement);
1918             // check if insertion has to be commited
1919             if (insertedAdditionals) {
1920                 insertedAdditionals->commitElementInsertion(additionalCreated);
1921             }
1922             return true;
1923         }
1924     }
1925     return false;
1926 }
1927 
1928 
1929 bool
parseAndBuildParkingSpace(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1930 GNEAdditionalHandler::parseAndBuildParkingSpace(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1931     bool abort = false;
1932     // parse attributes of Parking Spaces
1933     Position pos = GNEAttributeCarrier::parseAttributeFromXML<Position>(attrs, "", SUMO_TAG_PARKING_SPACE, SUMO_ATTR_POSITION, abort);
1934     double width = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_PARKING_SPACE, SUMO_ATTR_WIDTH, abort);
1935     double length = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_PARKING_SPACE, SUMO_ATTR_LENGTH, abort);
1936     double angle = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_PARKING_SPACE, SUMO_ATTR_ANGLE, abort);
1937     // parse Netedit attributes
1938     bool blockMovement = false;
1939     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
1940         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_PARKING_SPACE, GNE_ATTR_BLOCK_MOVEMENT, abort);
1941     }
1942     // Continue if all parameters were sucesfully loaded
1943     if (!abort) {
1944         // get Parking Area Parent
1945         GNEAdditional* parkingAreaParent = nullptr;
1946         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
1947         if (insertedAdditionals) {
1948             parkingAreaParent = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_PARKING_AREA);
1949         } else {
1950             bool ok = true;
1951             parkingAreaParent = viewNet->getNet()->retrieveAdditional(SUMO_TAG_PARKING_AREA, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
1952         }
1953         // check that Parking Area Parent exists
1954         if (parkingAreaParent != nullptr) {
1955             // save ID of last created element
1956             GNEAdditional* additionalCreated = buildParkingSpace(viewNet, allowUndoRedo, parkingAreaParent, pos, width, length, angle, blockMovement);
1957             // check if insertion has to be commited
1958             if (insertedAdditionals) {
1959                 insertedAdditionals->commitElementInsertion(additionalCreated);
1960             }
1961             return true;
1962         }
1963     }
1964     return false;
1965 }
1966 
1967 
1968 bool
parseAndBuildCalibrator(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)1969 GNEAdditionalHandler::parseAndBuildCalibrator(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
1970     bool abort = false;
1971     // due there is two differents calibrators, has to be parsed in a different way
1972     std::string edgeID, laneId, id;
1973     // change tag depending of XML parmeters
1974     if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
1975         id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_CALIBRATOR, SUMO_ATTR_ID, abort);
1976         edgeID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CALIBRATOR, SUMO_ATTR_EDGE, abort);
1977         std::string outfile = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CALIBRATOR, SUMO_ATTR_OUTPUT, abort);
1978         double position = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_CALIBRATOR, SUMO_ATTR_POSITION, abort);
1979         std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CALIBRATOR, SUMO_ATTR_NAME, abort);
1980         double freq = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_CALIBRATOR, SUMO_ATTR_FREQUENCY, abort);
1981         std::string routeProbe = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_CALIBRATOR, SUMO_ATTR_ROUTEPROBE, abort);
1982         // Continue if all parameters were sucesfully loaded
1983         if (!abort) {
1984             // get pointer and edge
1985             GNEEdge* edge = viewNet->getNet()->retrieveEdge(edgeID, false);
1986             // check that all elements are valid
1987             if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_CALIBRATOR, id, false) != nullptr) {
1988                 WRITE_WARNING("There is another " + toString(SUMO_TAG_CALIBRATOR) + " with the same ID='" + id + "'.");
1989             } else if (edge == nullptr) {
1990                 WRITE_WARNING("The  edge '" + edgeID + "' to use within the " + toString(SUMO_TAG_CALIBRATOR) + " '" + id + "' is not known.");
1991             } else {
1992                 // save ID of last created element
1993                 GNEAdditional* additionalCreated = buildCalibrator(viewNet, allowUndoRedo, id, edge, position, name, outfile, freq, routeProbe);
1994                 // check if insertion has to be commited
1995                 if (insertedAdditionals) {
1996                     insertedAdditionals->commitElementInsertion(additionalCreated);
1997                 }
1998                 return true;
1999             }
2000         }
2001     } else if (attrs.hasAttribute(SUMO_ATTR_LANE)) {
2002         id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_LANECALIBRATOR, SUMO_ATTR_ID, abort);
2003         laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_LANECALIBRATOR, SUMO_ATTR_LANE, abort);
2004         std::string outfile = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_LANECALIBRATOR, SUMO_ATTR_OUTPUT, abort);
2005         double position = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_LANECALIBRATOR, SUMO_ATTR_POSITION, abort);
2006         std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_LANECALIBRATOR, SUMO_ATTR_NAME, abort);
2007         double freq = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_LANECALIBRATOR, SUMO_ATTR_FREQUENCY, abort);
2008         std::string routeProbe = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_LANECALIBRATOR, SUMO_ATTR_ROUTEPROBE, abort);
2009         // Continue if all parameters were sucesfully loaded
2010         if (!abort) {
2011             // get pointer to lane
2012             GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
2013             // check that all elements are valid
2014             if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_LANECALIBRATOR, id, false) != nullptr) {
2015                 WRITE_WARNING("There is another " + toString(SUMO_TAG_CALIBRATOR) + " with the same ID='" + id + "'.");
2016             } else if (lane == nullptr) {
2017                 WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_CALIBRATOR) + " '" + id + "' is not known.");
2018             } else {
2019                 // save ID of last created element
2020                 GNEAdditional* additionalCreated = buildCalibrator(viewNet, allowUndoRedo, id, lane, position, name, outfile, freq, routeProbe);
2021                 // check if insertion has to be commited
2022                 if (insertedAdditionals) {
2023                     insertedAdditionals->commitElementInsertion(additionalCreated);
2024                 }
2025                 return true;
2026             }
2027         }
2028     } else {
2029         WRITE_WARNING("additional " + toString(SUMO_TAG_CALIBRATOR) + " must have either a lane or an edge attribute.");
2030     }
2031     return false;
2032 }
2033 
2034 
2035 bool
parseAndBuildDetectorE1(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)2036 GNEAdditionalHandler::parseAndBuildDetectorE1(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
2037     bool abort = false;
2038     // parse attributes of E1
2039     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_E1DETECTOR, SUMO_ATTR_ID, abort);
2040     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_E1DETECTOR, SUMO_ATTR_LANE, abort);
2041     double position = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_E1DETECTOR, SUMO_ATTR_POSITION, abort);
2042     double frequency = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_E1DETECTOR, SUMO_ATTR_FREQUENCY, abort);
2043     std::string file = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_E1DETECTOR, SUMO_ATTR_FILE, abort);
2044     std::string vehicleTypes = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_E1DETECTOR, SUMO_ATTR_VTYPES, abort);
2045     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_E1DETECTOR, SUMO_ATTR_NAME, abort);
2046     bool friendlyPos = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_E1DETECTOR, SUMO_ATTR_FRIENDLY_POS, abort);
2047     // parse Netedit attributes
2048     bool blockMovement = false;
2049     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
2050         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_E1DETECTOR, GNE_ATTR_BLOCK_MOVEMENT, abort);
2051     }
2052     // Continue if all parameters were sucesfully loaded
2053     if (!abort) {
2054         // get pointer to lane
2055         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
2056         // check that all elements are valid
2057         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_E1DETECTOR, id, false) != nullptr) {
2058             WRITE_WARNING("There is another " + toString(SUMO_TAG_E1DETECTOR) + " with the same ID='" + id + "'.");
2059         } else if (lane == nullptr) {
2060             // Write error if lane isn't valid
2061             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_E1DETECTOR) + " '" + id + "' is not known.");
2062         } else if (!checkAndFixDetectorPosition(position, lane->getLaneShapeLength(), friendlyPos)) {
2063             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_E1DETECTOR) + " with ID = '" + id + "'.");
2064         } else {
2065             // save ID of last created element
2066             GNEAdditional* additionalCreated = buildDetectorE1(viewNet, allowUndoRedo, id, lane, position, frequency, file, vehicleTypes, name, friendlyPos, blockMovement);
2067             // check if insertion has to be commited
2068             if (insertedAdditionals) {
2069                 insertedAdditionals->commitElementInsertion(additionalCreated);
2070             }
2071             return true;
2072         }
2073     }
2074     return false;
2075 }
2076 
2077 
2078 bool
parseAndBuildDetectorE2(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)2079 GNEAdditionalHandler::parseAndBuildDetectorE2(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
2080     // Tag E2 detectors can build either E2 single lanes or E2 multilanes, depending of attribute "lanes"
2081     SumoXMLTag E2Tag = attrs.hasAttribute(SUMO_ATTR_LANES) ? SUMO_TAG_E2DETECTOR_MULTILANE : SUMO_TAG_E2DETECTOR;
2082     bool abort = false;
2083     // start parsing ID
2084     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", E2Tag, SUMO_ATTR_ID, abort);
2085     // parse attributes of E2 SingleLanes
2086     std::string laneId = (E2Tag == SUMO_TAG_E2DETECTOR) ? GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, E2Tag, SUMO_ATTR_LANE, abort) : "";
2087     double length = (E2Tag == SUMO_TAG_E2DETECTOR) ? GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, E2Tag, SUMO_ATTR_LENGTH, abort) : 0;
2088     // parse attributes of E2 Multilanes
2089     std::string laneIds = (E2Tag == SUMO_TAG_E2DETECTOR_MULTILANE) ? GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, E2Tag, SUMO_ATTR_LANES, abort) : "";
2090     double endPos = (E2Tag == SUMO_TAG_E2DETECTOR_MULTILANE) ? GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, E2Tag, SUMO_ATTR_ENDPOS, abort) : 0;
2091     // parse common attributes
2092     double position = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, E2Tag, SUMO_ATTR_POSITION, abort);
2093     double frequency = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, E2Tag, SUMO_ATTR_FREQUENCY, abort);
2094     std::string file = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, E2Tag, SUMO_ATTR_FILE, abort);
2095     std::string vehicleTypes = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, E2Tag, SUMO_ATTR_VTYPES, abort);
2096     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, E2Tag, SUMO_ATTR_NAME, abort);
2097     double haltingTimeThreshold = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, E2Tag, SUMO_ATTR_HALTING_TIME_THRESHOLD, abort);
2098     double haltingSpeedThreshold = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, E2Tag, SUMO_ATTR_HALTING_SPEED_THRESHOLD, abort);
2099     double jamDistThreshold = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, E2Tag, SUMO_ATTR_JAM_DIST_THRESHOLD, abort);
2100     bool friendlyPos = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, E2Tag, SUMO_ATTR_FRIENDLY_POS, abort);
2101     // parse Netedit attributes
2102     bool blockMovement = false;
2103     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
2104         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, E2Tag, GNE_ATTR_BLOCK_MOVEMENT, abort);
2105     }
2106     // cont attribute is deprecated
2107     GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, E2Tag, SUMO_ATTR_CONT, abort);
2108     // Continue if all parameters were sucesfully loaded
2109     if (!abort) {
2110         // check if at leas lane or laneIDS are defined
2111         if (laneId.empty() && laneIds.empty()) {
2112             WRITE_WARNING("A " + toString(E2Tag) + " needs at least a lane or a list of lanes.");
2113         } else {
2114             // get pointer to lane
2115             GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
2116             // get list of lanes
2117             std::vector<GNELane*> lanes;
2118             bool laneConsecutives = true;
2119             if (GNEAttributeCarrier::canParse<std::vector<GNELane*> >(viewNet->getNet(), laneIds, false)) {
2120                 lanes = GNEAttributeCarrier::parse<std::vector<GNELane*> >(viewNet->getNet(), laneIds);
2121                 // check if lanes are consecutives
2122                 laneConsecutives = GNEAttributeCarrier::lanesConsecutives(lanes);
2123             }
2124             // check that all elements are valid
2125             if (viewNet->getNet()->retrieveAdditional(E2Tag, id, false) != nullptr) {
2126                 // write error if neither lane nor lane aren't defined
2127                 WRITE_WARNING("There is another " + toString(E2Tag) + " with the same ID='" + id + "'.");
2128             } else if (attrs.hasAttribute(SUMO_ATTR_LANE) && (lane == nullptr)) {
2129                 // Write error if lane isn't valid
2130                 WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(E2Tag) + " '" + id + "' is not known.");
2131             } else if (attrs.hasAttribute(SUMO_ATTR_LANES) && lanes.empty()) {
2132                 // Write error if lane isn't valid
2133                 WRITE_WARNING("The list of lanes cannot be empty.");
2134             } else if (attrs.hasAttribute(SUMO_ATTR_LANES) && lanes.empty()) {
2135                 // Write error if lane isn't valid
2136                 WRITE_WARNING("The list of lanes '" + laneIds + "' to use within the " + toString(E2Tag) + " '" + id + "' isn't valid.");
2137             } else if (!lanes.empty() && !laneConsecutives) {
2138                 WRITE_WARNING("The lanes '" + laneIds + "' to use within the " + toString(E2Tag) + " '" + id + "' aren't consecutives.");
2139             } else if (lane && !fixE2DetectorPosition(position, length, lane->getParentEdge().getNBEdge()->getFinalLength(), friendlyPos)) {
2140                 WRITE_WARNING("Invalid position for " + toString(E2Tag) + " with ID = '" + id + "'.");
2141             } else if (!lanes.empty() && !fixE2DetectorPosition(position, length, lanes.front()->getParentEdge().getNBEdge()->getFinalLength(), friendlyPos)) {
2142                 WRITE_WARNING("Invalid position for " + toString(E2Tag) + " with ID = '" + id + "'.");
2143             } else if (!lanes.empty() && !fixE2DetectorPosition(endPos, length, lanes.back()->getParentEdge().getNBEdge()->getFinalLength(), friendlyPos)) {
2144                 WRITE_WARNING("Invalid end position for " + toString(E2Tag) + " with ID = '" + id + "'.");
2145             } else if (lane) {
2146                 // save ID of last created element
2147                 GNEAdditional* additionalCreated = buildSingleLaneDetectorE2(viewNet, allowUndoRedo, id, lane, position, length, frequency, file, vehicleTypes,
2148                                                    name, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, friendlyPos, blockMovement);
2149                 // check if insertion has to be commited
2150                 if (insertedAdditionals) {
2151                     insertedAdditionals->commitElementInsertion(additionalCreated);
2152                 }
2153                 return true;
2154             } else {
2155                 // save ID of last created element
2156                 GNEAdditional* additionalCreated = buildMultiLaneDetectorE2(viewNet, allowUndoRedo, id, lanes, position, endPos, frequency, file, vehicleTypes,
2157                                                    name, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, friendlyPos, blockMovement);
2158                 // check if insertion has to be commited
2159                 if (insertedAdditionals) {
2160                     insertedAdditionals->commitElementInsertion(additionalCreated);
2161                 }
2162                 return true;
2163             }
2164         }
2165     }
2166     return false;
2167 }
2168 
2169 
2170 bool
parseAndBuildDetectorE3(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)2171 GNEAdditionalHandler::parseAndBuildDetectorE3(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
2172     bool abort = false;
2173     // parse attributes of E3
2174     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_E3DETECTOR, SUMO_ATTR_ID, abort);
2175     double frequency = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_E3DETECTOR, SUMO_ATTR_FREQUENCY, abort);
2176     std::string file = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_E3DETECTOR, SUMO_ATTR_FILE, abort);
2177     std::string vehicleTypes = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_E3DETECTOR, SUMO_ATTR_VTYPES, abort);
2178     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_E3DETECTOR, SUMO_ATTR_NAME, abort);
2179     double haltingTimeThreshold = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_E3DETECTOR, SUMO_ATTR_HALTING_TIME_THRESHOLD, abort);
2180     double haltingSpeedThreshold = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_E3DETECTOR, SUMO_ATTR_HALTING_SPEED_THRESHOLD, abort);
2181     Position pos = GNEAttributeCarrier::parseAttributeFromXML<Position>(attrs, id, SUMO_TAG_E3DETECTOR, SUMO_ATTR_POSITION, abort);
2182     // parse Netedit attributes
2183     bool blockMovement = false;
2184     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
2185         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_E3DETECTOR, GNE_ATTR_BLOCK_MOVEMENT, abort);
2186     }
2187     // Continue if all parameters were sucesfully loaded
2188     if (!abort) {
2189         // check that all elements are valid
2190         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_E3DETECTOR, id, false) != nullptr) {
2191             WRITE_WARNING("There is another " + toString(SUMO_TAG_E3DETECTOR) + " with the same ID='" + id + "'.");
2192         } else {
2193             // save ID of last created element
2194             GNEAdditional* additionalCreated = buildDetectorE3(viewNet, allowUndoRedo, id, pos, frequency, file, vehicleTypes, name, haltingTimeThreshold, haltingSpeedThreshold, blockMovement);
2195             // check if insertion has to be commited
2196             if (insertedAdditionals) {
2197                 insertedAdditionals->commitElementInsertion(additionalCreated);
2198             }
2199             return true;
2200         }
2201     }
2202     return false;
2203 }
2204 
2205 
2206 bool
parseAndBuildDetectorEntry(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)2207 GNEAdditionalHandler::parseAndBuildDetectorEntry(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
2208     bool abort = false;
2209     // parse attributes of Entry
2210     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_DET_ENTRY, SUMO_ATTR_LANE, abort);
2211     double position = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_DET_ENTRY, SUMO_ATTR_POSITION, abort);
2212     bool friendlyPos = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_DET_ENTRY, SUMO_ATTR_FRIENDLY_POS, abort);
2213     // parse Netedit attributes
2214     bool blockMovement = false;
2215     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
2216         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_DET_ENTRY, GNE_ATTR_BLOCK_MOVEMENT, abort);
2217     }
2218     // Check if parsing of parameters was correct
2219     if (!abort) {
2220         // get lane and E3 parent
2221         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
2222         GNEAdditional* E3Parent = nullptr;
2223         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
2224         if (insertedAdditionals) {
2225             E3Parent = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_E3DETECTOR);
2226         } else {
2227             bool ok = true;
2228             E3Parent = viewNet->getNet()->retrieveAdditional(SUMO_TAG_E3DETECTOR, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
2229         }
2230         // check that all parameters are valid
2231         if (lane == nullptr) {
2232             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_DET_ENTRY) + " is not known.");
2233         } else if (!checkAndFixDetectorPosition(position, lane->getLaneShapeLength(), friendlyPos)) {
2234             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_DET_ENTRY) + ".");
2235         } else if (E3Parent) {
2236             // save ID of last created element
2237             GNEAdditional* additionalCreated = buildDetectorEntry(viewNet, allowUndoRedo, E3Parent, lane, position, friendlyPos, blockMovement);
2238             // check if insertion has to be commited
2239             if (insertedAdditionals) {
2240                 insertedAdditionals->commitElementInsertion(additionalCreated);
2241             }
2242             return true;
2243         }
2244     }
2245     return false;
2246 }
2247 
2248 
2249 bool
parseAndBuildDetectorExit(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)2250 GNEAdditionalHandler::parseAndBuildDetectorExit(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
2251     bool abort = false;
2252     // parse attributes of Exit
2253     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_DET_EXIT, SUMO_ATTR_LANE, abort);
2254     double position = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, "", SUMO_TAG_DET_EXIT, SUMO_ATTR_POSITION, abort);
2255     bool friendlyPos = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_DET_EXIT, SUMO_ATTR_FRIENDLY_POS, abort);
2256     // parse Netedit attributes
2257     bool blockMovement = false;
2258     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
2259         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, "", SUMO_TAG_DET_EXIT, GNE_ATTR_BLOCK_MOVEMENT, abort);
2260     }
2261     // Check if parsing of parameters was correct
2262     if (!abort) {
2263         // get lane and E3 parent
2264         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
2265         GNEAdditional* E3Parent = nullptr;
2266         // obtain parent depending if we're loading or creating it using GNEAdditionalFrame
2267         if (insertedAdditionals) {
2268             E3Parent = insertedAdditionals->retrieveAdditionalParent(viewNet, SUMO_TAG_E3DETECTOR);
2269         } else {
2270             bool ok = true;
2271             E3Parent = viewNet->getNet()->retrieveAdditional(SUMO_TAG_E3DETECTOR, attrs.get<std::string>(GNE_ATTR_PARENT, "", ok));
2272         }
2273         // check that all parameters are valid
2274         if (lane == nullptr) {
2275             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_DET_EXIT) + " is not known.");
2276         } else if (!checkAndFixDetectorPosition(position, lane->getLaneShapeLength(), friendlyPos)) {
2277             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_DET_EXIT) + ".");
2278         } else if (E3Parent) {
2279             // save ID of last created element
2280             GNEAdditional* additionalCreated = buildDetectorExit(viewNet, allowUndoRedo, E3Parent, lane, position, friendlyPos, blockMovement);
2281             // check if insertion has to be commited
2282             if (insertedAdditionals) {
2283                 insertedAdditionals->commitElementInsertion(additionalCreated);
2284             }
2285             return true;
2286         }
2287     }
2288     return false;
2289 }
2290 
2291 
2292 bool
parseAndBuildDetectorE1Instant(GNEViewNet * viewNet,bool allowUndoRedo,const SUMOSAXAttributes & attrs,HierarchyInsertedAdditionals * insertedAdditionals)2293 GNEAdditionalHandler::parseAndBuildDetectorE1Instant(GNEViewNet* viewNet, bool allowUndoRedo, const SUMOSAXAttributes& attrs, HierarchyInsertedAdditionals* insertedAdditionals) {
2294     bool abort = false;
2295     // parse attributes of E1Instant
2296     std::string id = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_INSTANT_INDUCTION_LOOP, SUMO_ATTR_ID, abort);
2297     std::string laneId = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_INSTANT_INDUCTION_LOOP, SUMO_ATTR_LANE, abort);
2298     double position = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, id, SUMO_TAG_INSTANT_INDUCTION_LOOP, SUMO_ATTR_POSITION, abort);
2299     std::string file = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_INSTANT_INDUCTION_LOOP, SUMO_ATTR_FILE, abort);
2300     std::string vehicleTypes = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_INSTANT_INDUCTION_LOOP, SUMO_ATTR_VTYPES, abort);
2301     std::string name = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, id, SUMO_TAG_INSTANT_INDUCTION_LOOP, SUMO_ATTR_NAME, abort);
2302     bool friendlyPos = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_INSTANT_INDUCTION_LOOP, SUMO_ATTR_FRIENDLY_POS, abort);
2303     // parse Netedit attributes
2304     bool blockMovement = false;
2305     if (attrs.hasAttribute(GNE_ATTR_BLOCK_MOVEMENT)) {
2306         blockMovement = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, id, SUMO_TAG_INSTANT_INDUCTION_LOOP, GNE_ATTR_BLOCK_MOVEMENT, abort);
2307     }
2308     // Continue if all parameters were sucesfully loaded
2309     if (!abort) {
2310         // get pointer to lane
2311         GNELane* lane = viewNet->getNet()->retrieveLane(laneId, false, true);
2312         // check that all elements are valid
2313         if (viewNet->getNet()->retrieveAdditional(SUMO_TAG_INSTANT_INDUCTION_LOOP, id, false) != nullptr) {
2314             WRITE_WARNING("There is another " + toString(SUMO_TAG_INSTANT_INDUCTION_LOOP) + " with the same ID='" + id + "'.");
2315         } else if (lane == nullptr) {
2316             // Write error if lane isn't valid
2317             WRITE_WARNING("The lane '" + laneId + "' to use within the " + toString(SUMO_TAG_INSTANT_INDUCTION_LOOP) + " '" + id + "' is not known.");
2318         } else if (!checkAndFixDetectorPosition(position, lane->getLaneShapeLength(), friendlyPos)) {
2319             WRITE_WARNING("Invalid position for " + toString(SUMO_TAG_INSTANT_INDUCTION_LOOP) + " with ID = '" + id + "'.");
2320         } else {
2321             // save ID of last created element
2322             GNEAdditional* additionalCreated = buildDetectorE1Instant(viewNet, allowUndoRedo, id, lane, position, file, vehicleTypes, name, friendlyPos, blockMovement);
2323             // check if insertion has to be commited
2324             if (insertedAdditionals) {
2325                 insertedAdditionals->commitElementInsertion(additionalCreated);
2326             }
2327             return true;
2328         }
2329     }
2330     return false;
2331 }
2332 
2333 // ===========================================================================
2334 // private method definitions
2335 // ===========================================================================
2336 
2337 void
parseAndBuildPOI(const SUMOSAXAttributes & attrs)2338 GNEAdditionalHandler::parseAndBuildPOI(const SUMOSAXAttributes& attrs) {
2339     bool abort = false;
2340     // parse attributes of POIs
2341     std::string POIID = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, "", SUMO_TAG_POI, SUMO_ATTR_ID, abort);
2342     // POIs can be defined using a X,Y position,...
2343     Position pos = attrs.hasAttribute(SUMO_ATTR_X) ? GNEAttributeCarrier::parseAttributeFromXML<Position>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_POSITION, abort) : Position::INVALID;
2344     // ... a Lon-Lat,...
2345     double lon = attrs.hasAttribute(SUMO_ATTR_LON) ? GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_LON, abort) : GNEAttributeCarrier::INVALID_POSITION;
2346     double lat = attrs.hasAttribute(SUMO_ATTR_LAT) ? GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_LAT, abort) : GNEAttributeCarrier::INVALID_POSITION;
2347     // .. or as Lane-PosLane
2348     std::string laneID = attrs.hasAttribute(SUMO_ATTR_LANE) ? GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, POIID, SUMO_TAG_POILANE, SUMO_ATTR_LANE, abort) : "";
2349     double lanePos = attrs.hasAttribute(SUMO_ATTR_POSITION) ? GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POILANE, SUMO_ATTR_POSITION, abort) : GNEAttributeCarrier::INVALID_POSITION;
2350     double lanePosLat = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POILANE, SUMO_ATTR_POSITION_LAT, abort);
2351     // continue with common parameters
2352     double layer = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_LAYER, abort);
2353     std::string type = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_TYPE, abort);
2354     RGBColor color = GNEAttributeCarrier::parseAttributeFromXML<RGBColor>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_COLOR, abort);
2355     double angle = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_ANGLE, abort);
2356     std::string imgFile = GNEAttributeCarrier::parseAttributeFromXML<std::string>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_IMGFILE, abort);
2357     bool relativePath = GNEAttributeCarrier::parseAttributeFromXML<bool>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_RELATIVEPATH, abort);
2358     double width = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_WIDTH, abort);
2359     double height = GNEAttributeCarrier::parseAttributeFromXML<double>(attrs, POIID, SUMO_TAG_POI, SUMO_ATTR_HEIGHT, abort);
2360     // Continue if all parameters were sucesfully loaded
2361     if (!abort) {
2362         // check if img file is absolute
2363         if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
2364             imgFile = FileHelpers::getConfigurationRelative(getFileName(), imgFile);
2365         }
2366         // check if lane exist
2367         if (laneID != "" && !myViewNet->getNet()->retrieveLane(laneID, false)) {
2368             WRITE_WARNING("The lane '" + laneID + "' to use within the PoI '" + POIID + "' is not known.");
2369             return;
2370         }
2371         // check position
2372         bool useGeo = false;
2373         // if position is invalid, then is either a POILane or a GEOPoi
2374         if (pos == Position::INVALID) {
2375             // try computing x,y from lane,pos
2376             if (laneID != "") {
2377                 // if LaneID is defined, then is a POILane
2378                 pos = getLanePos(POIID, laneID, lanePos, lanePosLat);
2379             } else {
2380                 // try computing x,y from lon,lat
2381                 if (lat == GNEAttributeCarrier::INVALID_POSITION || lon == GNEAttributeCarrier::INVALID_POSITION) {
2382                     WRITE_WARNING("Either (x, y), (lon, lat) or (lane, pos) must be specified for PoI '" + POIID + "'.");
2383                     return;
2384                 } else if (!GeoConvHelper::getFinal().usingGeoProjection()) {
2385                     WRITE_WARNING("(lon, lat) is specified for PoI '" + POIID + "' but no geo-conversion is specified for the network.");
2386                     return;
2387                 }
2388                 // set GEO Position
2389                 pos.set(lon, lat);
2390                 useGeo = true;
2391                 if (!GeoConvHelper::getFinal().x2cartesian_const(pos)) {
2392                     WRITE_WARNING("Unable to project coordinates for PoI '" + POIID + "'.");
2393                     return;
2394                 }
2395             }
2396         }
2397         // create POI, or show an error if POI already exists
2398         if (!myShapeContainer.addPOI(POIID, type, color, pos, useGeo, laneID, lanePos, lanePosLat, layer, angle, imgFile, relativePath, width, height, false)) {
2399             WRITE_WARNING("POI with ID '" + POIID + "' already exists.");
2400         } else {
2401             // update myLastParameterised with the last inserted POI
2402             myLastParameterised = myShapeContainer.getPOIs().get(POIID);
2403         }
2404     }
2405 }
2406 
2407 
2408 void
parseGenericParameter(const SUMOSAXAttributes & attrs)2409 GNEAdditionalHandler::parseGenericParameter(const SUMOSAXAttributes& attrs) {
2410     // we have two cases: if we're parsing a Shape or we're parsing an Additional
2411     if (getLastParameterised()) {
2412         bool ok = true;
2413         std::string key;
2414         if (attrs.hasAttribute(SUMO_ATTR_KEY)) {
2415             // obtain key
2416             key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
2417             if (key.empty()) {
2418                 WRITE_WARNING("Error parsing key from shape generic parameter. Key cannot be empty");
2419                 ok = false;
2420             }
2421             if (!SUMOXMLDefinitions::isValidTypeID(key)) {
2422                 WRITE_WARNING("Error parsing key from shape generic parameter. Key contains invalid characters");
2423                 ok = false;
2424             }
2425         } else {
2426             WRITE_WARNING("Error parsing key from shape generic parameter. Key doesn't exist");
2427             ok = false;
2428         }
2429         // circumventing empty string test
2430         const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
2431         if (!SUMOXMLDefinitions::isValidAttribute(val)) {
2432             WRITE_WARNING("Error parsing value from shape generic parameter. Value contains invalid characters");
2433             ok = false;
2434         }
2435         // set parameter in last inserted additional
2436         if (ok) {
2437             WRITE_DEBUG("Inserting generic parameter '" + key + "|" + val + "' into shape.");
2438             getLastParameterised()->setParameter(key, val);
2439         }
2440     } else if (myHierarchyInsertedAdditionals.getLastInsertedAdditional()) {
2441         // first check if given additional supports generic parameters
2442         if (myHierarchyInsertedAdditionals.getLastInsertedAdditional()->getTagProperty().hasGenericParameters()) {
2443             bool ok = true;
2444             std::string key;
2445             if (attrs.hasAttribute(SUMO_ATTR_KEY)) {
2446                 // obtain key
2447                 key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
2448                 if (key.empty()) {
2449                     WRITE_WARNING("Error parsing key from additional generic parameter. Key cannot be empty");
2450                     ok = false;
2451                 }
2452                 if (!SUMOXMLDefinitions::isValidTypeID(key)) {
2453                     WRITE_WARNING("Error parsing key from additional generic parameter. Key contains invalid characters");
2454                     ok = false;
2455                 }
2456             } else {
2457                 WRITE_WARNING("Error parsing key from additional generic parameter. Key doesn't exist");
2458                 ok = false;
2459             }
2460             // circumventing empty string test
2461             const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
2462             if (!SUMOXMLDefinitions::isValidAttribute(val)) {
2463                 WRITE_WARNING("Error parsing value from additional generic parameter. Value contains invalid characters");
2464                 ok = false;
2465             }
2466             // set parameter in last inserted additional
2467             if (ok) {
2468                 WRITE_DEBUG("Inserting generic parameter '" + key + "|" + val + "' into additional " + myHierarchyInsertedAdditionals.getLastInsertedAdditional()->getTagStr() + ".");
2469                 myHierarchyInsertedAdditionals.getLastInsertedAdditional()->setParameter(key, val);
2470             }
2471         } else {
2472             WRITE_WARNING("Additionals of type '" + myHierarchyInsertedAdditionals.getLastInsertedAdditional()->getTagStr() + "' doesn't support Generic Parameters");
2473         }
2474     } else {
2475         WRITE_WARNING("Generic Parameters has to be declared within the definition of an additional or a shape element");
2476     }
2477 }
2478 
2479 // ===========================================================================
2480 // GNEAdditionalHandler::HierarchyInsertedAdditionals method definitions
2481 // ===========================================================================
2482 
2483 void
insertElement(SumoXMLTag tag)2484 GNEAdditionalHandler::HierarchyInsertedAdditionals::insertElement(SumoXMLTag tag) {
2485     myInsertedElements.push_back(std::make_pair(tag, nullptr));
2486 }
2487 
2488 
2489 void
commitElementInsertion(GNEAdditional * additional)2490 GNEAdditionalHandler::HierarchyInsertedAdditionals::commitElementInsertion(GNEAdditional* additional) {
2491     myInsertedElements.back().second = additional;
2492 }
2493 
2494 
2495 void
popElement()2496 GNEAdditionalHandler::HierarchyInsertedAdditionals::popElement() {
2497     if (!myInsertedElements.empty()) {
2498         myInsertedElements.pop_back();
2499     }
2500 }
2501 
2502 
2503 GNEAdditional*
retrieveAdditionalParent(GNEViewNet * viewNet,SumoXMLTag expectedTag) const2504 GNEAdditionalHandler::HierarchyInsertedAdditionals::retrieveAdditionalParent(GNEViewNet* viewNet, SumoXMLTag expectedTag) const {
2505     if (myInsertedElements.size() < 2) {
2506         // currently we're finding additional parent in the additional XML root
2507         WRITE_WARNING("A " + toString(myInsertedElements.back().first) + " must be declared within the definition of a " + toString(expectedTag) + ".");
2508         return nullptr;
2509     } else {
2510         if (myInsertedElements.size() < 2) {
2511             // additional was hierarchically bad loaded, then return nullptr
2512             return nullptr;
2513         } else if ((myInsertedElements.end() - 2)->second == nullptr) {
2514             WRITE_WARNING(toString(expectedTag) + " parent of " + toString((myInsertedElements.end() - 1)->first) + " was not loaded sucesfully.");
2515             // additional parent wasn't sucesfully loaded, then return nullptr
2516             return nullptr;
2517         }
2518         GNEAdditional* retrievedAdditional = viewNet->getNet()->retrieveAdditional((myInsertedElements.end() - 2)->first, (myInsertedElements.end() - 2)->second->getID(), false);
2519         if (retrievedAdditional == nullptr) {
2520             // additional doesn't exist
2521             WRITE_WARNING("A " + toString((myInsertedElements.end() - 1)->first) + " must be declared within the definition of a " + toString(expectedTag) + ".");
2522             return nullptr;
2523         } else if (retrievedAdditional->getTagProperty().getTag() != expectedTag) {
2524             // invalid additional parent
2525             WRITE_WARNING("A " + toString((myInsertedElements.end() - 1)->first) + " cannot be declared within the definition of a " + retrievedAdditional->getTagStr() + ".");
2526             return nullptr;
2527         } else {
2528             return retrievedAdditional;
2529         }
2530     }
2531 }
2532 
2533 
2534 GNEAdditional*
getLastInsertedAdditional() const2535 GNEAdditionalHandler::HierarchyInsertedAdditionals::getLastInsertedAdditional() const {
2536     // ierate in reverse mode over myInsertedElements to obtain last inserted additional
2537     for (std::vector<std::pair<SumoXMLTag, GNEAdditional*> >::const_reverse_iterator i = myInsertedElements.rbegin(); i != myInsertedElements.rend(); i++) {
2538         // we need to avoid Tag Param because isn't an additional
2539         if (i->first != SUMO_TAG_PARAM) {
2540             return i->second;
2541         }
2542     }
2543     return nullptr;
2544 }
2545 
2546 /****************************************************************************/
2547