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    GNENet.cpp
11 /// @author  Jakob Erdmann
12 /// @date    Feb 2011
13 /// @version $Id$
14 ///
15 // A visual container for GNE-network-components such as GNEEdge and GNEJunction.
16 // GNE components wrap netbuild-components and supply visualisation and editing
17 // capabilities (adapted from GUINet)
18 //
19 // Workflow (rough draft)
20 //   use NILoader to fill
21 //   do netedit stuff
22 //   call compute to save results
23 //
24 /****************************************************************************/
25 
26 
27 // ===========================================================================
28 // included modules
29 // ===========================================================================
30 #include <netbuild/NBAlgorithms.h>
31 #include <netbuild/NBNetBuilder.h>
32 #include <netedit/additionals/GNEAdditionalHandler.h>
33 #include <netedit/demandelements/GNEVehicleType.h>
34 #include <netedit/additionals/GNEAdditional.h>
35 #include <netedit/additionals/GNEPOI.h>
36 #include <netedit/additionals/GNEPoly.h>
37 #include <netedit/demandelements/GNERouteHandler.h>
38 #include <netedit/demandelements/GNEDemandElement.h>
39 #include <netedit/changes/GNEChange_Attribute.h>
40 #include <netedit/changes/GNEChange_Connection.h>
41 #include <netedit/changes/GNEChange_Crossing.h>
42 #include <netedit/changes/GNEChange_Additional.h>
43 #include <netedit/changes/GNEChange_DemandElement.h>
44 #include <netedit/changes/GNEChange_Edge.h>
45 #include <netedit/changes/GNEChange_Junction.h>
46 #include <netedit/changes/GNEChange_Lane.h>
47 #include <netedit/changes/GNEChange_Shape.h>
48 #include <netedit/dialogs/GNEDialog_FixAdditionalElements.h>
49 #include <netedit/dialogs/GNEDialog_FixDemandElements.h>
50 #include <netedit/frames/GNEAdditionalFrame.h>
51 #include <netedit/frames/GNEInspectorFrame.h>
52 #include <netedit/netelements/GNEConnection.h>
53 #include <netedit/netelements/GNECrossing.h>
54 #include <netedit/netelements/GNEEdge.h>
55 #include <netedit/netelements/GNEJunction.h>
56 #include <netedit/netelements/GNELane.h>
57 #include <netwrite/NWFrame.h>
58 #include <netwrite/NWWriter_SUMO.h>
59 #include <netwrite/NWWriter_XML.h>
60 #include <utils/gui/div/GUIGlobalSelection.h>
61 #include <utils/gui/globjects/GUIGlObjectStorage.h>
62 #include <utils/gui/div/GUIParameterTableWindow.h>
63 #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
64 #include <utils/options/OptionsCont.h>
65 #include <utils/xml/XMLSubSys.h>
66 
67 #include "GNEApplicationWindow.h"
68 #include "GNENet.h"
69 #include "GNEViewNet.h"
70 #include "GNEUndoList.h"
71 #include "GNEViewParent.h"
72 
73 
74 // ===========================================================================
75 // FOX callback mapping
76 // ===========================================================================
77 
78 FXIMPLEMENT_ABSTRACT(GNENet::GNEChange_ReplaceEdgeInTLS, GNEChange, nullptr, 0)
79 
80 // ===========================================================================
81 // static members
82 // ===========================================================================
83 
84 const double GNENet::Z_INITIALIZED = 1;
85 
86 // ===========================================================================
87 // member method definitions
88 // ===========================================================================
89 
GNENet(NBNetBuilder * netBuilder)90 GNENet::GNENet(NBNetBuilder* netBuilder) :
91     GUIGlObject(GLO_NETWORK, ""),
92     ShapeContainer(),
93     myViewNet(nullptr),
94     myNetBuilder(netBuilder),
95     myEdgeIDSupplier("gneE", netBuilder->getEdgeCont().getAllNames()),
96     myJunctionIDSupplier("gneJ", netBuilder->getNodeCont().getAllNames()),
97     myNeedRecompute(true),
98     myNetSaved(true),
99     myAdditionalsSaved(true),
100     myTLSProgramsSaved(true),
101     myDemandElementsSaved(true),
102     myUpdateGeometryEnabled(true),
103     myAllowUndoShapes(true) {
104     // set net in gIDStorage
105     GUIGlObjectStorage::gIDStorage.setNetObject(this);
106 
107     // init junction and edges
108     initJunctionsAndEdges();
109 
110     // check Z boundary
111     if (myZBoundary.ymin() != Z_INITIALIZED) {
112         myZBoundary.add(0, 0);
113     }
114 
115     // fill additionals with tags (note: this include the TAZS)
116     auto listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL, false);
117     for (auto i : listOfTags) {
118         myAttributeCarriers.additionals.insert(std::make_pair(i, std::map<std::string, GNEAdditional*>()));
119     }
120     listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_TAZ, false);
121     for (auto i : listOfTags) {
122         myAttributeCarriers.additionals.insert(std::make_pair(i, std::map<std::string, GNEAdditional*>()));
123     }
124 
125     // fill demand elements with tags
126     listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_DEMANDELEMENT, false);
127     for (auto i : listOfTags) {
128         myAttributeCarriers.demandElements.insert(std::make_pair(i, std::map<std::string, GNEDemandElement*>()));
129     }
130     listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_STOP, false);
131     for (auto i : listOfTags) {
132         myAttributeCarriers.demandElements.insert(std::make_pair(i, std::map<std::string, GNEDemandElement*>()));
133     }
134 }
135 
136 
~GNENet()137 GNENet::~GNENet() {
138     // Decrease reference of Polys (needed after volatile recomputing)
139     for (auto i : myPolygons) {
140         dynamic_cast<GNEAttributeCarrier*>(i.second)->decRef("GNENet::~GNENet");
141     }
142     // Decrease reference of POIs (needed after volatile recomputing)
143     for (auto i : myPOIs) {
144         dynamic_cast<GNEAttributeCarrier*>(i.second)->decRef("GNENet::~GNENet");
145     }
146     // Drop Edges
147     for (auto it : myAttributeCarriers.edges) {
148         it.second->decRef("GNENet::~GNENet");
149         // show extra information for tests
150         WRITE_DEBUG("Deleting unreferenced " + it.second->getTagStr() + " '" + it.second->getID() + "' in GNENet destructor");
151         delete it.second;
152     }
153     // Drop junctions
154     for (auto it : myAttributeCarriers.junctions) {
155         it.second->decRef("GNENet::~GNENet");
156         // show extra information for tests
157         WRITE_DEBUG("Deleting unreferenced " + it.second->getTagStr() + " '" + it.second->getID() + "' in GNENet destructor");
158         delete it.second;
159     }
160     // Drop Additionals (Only used for additionals that were inserted without using GNEChange_Additional)
161     for (auto it : myAttributeCarriers.additionals) {
162         for (auto j : it.second) {
163             // decrease reference manually (because it was increased manually in GNEAdditionalHandler)
164             j.second->decRef();
165             // show extra information for tests
166             WRITE_DEBUG("Deleting unreferenced " + j.second->getTagStr() + " '" + j.second->getID() + "' in GNENet destructor");
167             delete j.second;
168         }
169     }
170     // Drop demand elements (Only used for demand elements that were inserted without using GNEChange_DemandElement, for example the default VType")
171     for (auto it : myAttributeCarriers.demandElements) {
172         for (auto j : it.second) {
173             // decrease reference manually (because it was increased manually in GNERouteHandler)
174             j.second->decRef();
175             // show extra information for tests
176             WRITE_DEBUG("Deleting unreferenced " + j.second->getTagStr() + " '" + j.second->getID() + "' in GNENet destructor");
177             delete j.second;
178         }
179     }
180     // delete RouteCalculator instance of GNEDemandElement
181     GNEDemandElement::deleteRouteCalculatorInstance();
182     // show extra information for tests
183     WRITE_DEBUG("Deleting net builder in GNENet destructor");
184     delete myNetBuilder;
185 }
186 
187 
188 const Boundary&
getBoundary() const189 GNENet::getBoundary() const {
190     // SUMORTree is also a Boundary
191     return myGrid;
192 }
193 
194 
195 GUIGLObjectPopupMenu*
getPopUpMenu(GUIMainWindow & app,GUISUMOAbstractView & parent)196 GNENet::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
197     GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, *this);
198     buildPopupHeader(ret, app);
199     buildCenterPopupEntry(ret);
200     buildPositionCopyEntry(ret, false);
201     return ret;
202 }
203 
204 
205 GUIParameterTableWindow*
getParameterWindow(GUIMainWindow & app,GUISUMOAbstractView &)206 GNENet::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
207     // Nets lanes don't have attributes
208     GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this, 2);
209     // close building
210     ret->closeBuilding();
211     return ret;
212 }
213 
214 
215 void
drawGL(const GUIVisualizationSettings &) const216 GNENet::drawGL(const GUIVisualizationSettings& /*s*/) const {
217 }
218 
219 
220 bool
addPolygon(const std::string & id,const std::string & type,const RGBColor & color,double layer,double angle,const std::string & imgFile,bool relativePath,const PositionVector & shape,bool geo,bool fill,double lineWidth,bool)221 GNENet::addPolygon(const std::string& id, const std::string& type, const RGBColor& color, double layer, double angle,
222                    const std::string& imgFile, bool relativePath, const PositionVector& shape, bool geo, bool fill, double lineWidth, bool /*ignorePruning*/) {
223     // check if ID is duplicated
224     if (myPolygons.get(id) == nullptr) {
225         // create poly
226         GNEPoly* poly = new GNEPoly(this, id, type, shape, geo, fill, lineWidth, color, layer, angle, imgFile, relativePath, false, false);
227         if (myAllowUndoShapes) {
228             myViewNet->getUndoList()->p_begin("add " + toString(SUMO_TAG_POLY));
229             myViewNet->getUndoList()->add(new GNEChange_Shape(poly, true), true);
230             myViewNet->getUndoList()->p_end();
231         } else {
232             // insert shape without allowing undo/redo
233             insertShape(poly, true);
234             poly->incRef("addPolygon");
235         }
236         return true;
237     } else {
238         return false;
239     }
240 }
241 
242 
243 bool
addPOI(const std::string & id,const std::string & type,const RGBColor & color,const Position & pos,bool geo,const std::string & lane,double posOverLane,double posLat,double layer,double angle,const std::string & imgFile,bool relativePath,double width,double height,bool)244 GNENet::addPOI(const std::string& id, const std::string& type, const RGBColor& color, const Position& pos, bool geo,
245                const std::string& lane, double posOverLane, double posLat, double layer, double angle,
246                const std::string& imgFile, bool relativePath, double width, double height, bool /*ignorePruning*/) {
247     // check if ID is duplicated
248     if (myPOIs.get(id) == nullptr) {
249         // create POI or POILane depending of parameter lane
250         if (lane == "") {
251             // create POI
252             GNEPOI* poi = new GNEPOI(this, id, type, color, pos, geo, layer, angle, imgFile, relativePath, width, height, false);
253             if (myPOIs.add(poi->getID(), poi)) {
254                 if (myAllowUndoShapes) {
255                     myViewNet->getUndoList()->p_begin("add " + poi->getTagStr());
256                     myViewNet->getUndoList()->add(new GNEChange_Shape(poi, true), true);
257                     myViewNet->getUndoList()->p_end();
258                 } else {
259                     // insert shape without allowing undo/redo
260                     insertShape(poi, true);
261                     poi->incRef("addPOI");
262                 }
263                 return true;
264             } else {
265                 throw ProcessError("Error adding GNEPOI into shapeContainer");
266             }
267         } else {
268             // create POI over lane
269             GNELane* retrievedLane = retrieveLane(lane);
270             GNEPOI* poi = new GNEPOI(this, id, type, color, layer, angle, imgFile, relativePath, retrievedLane, posOverLane, posLat, width, height, false);
271             if (myPOIs.add(poi->getID(), poi)) {
272                 if (myAllowUndoShapes) {
273                     myViewNet->getUndoList()->p_begin("add " + poi->getTagStr());
274                     myViewNet->getUndoList()->add(new GNEChange_Shape(poi, true), true);
275                     myViewNet->getUndoList()->p_end();
276                 } else {
277                     // insert shape without allowing undo/redo
278                     insertShape(poi, true);
279                     poi->incRef("addPOI");
280                 }
281                 return true;
282             } else {
283                 throw ProcessError("Error adding GNEPOI over lane into shapeContainer");
284             }
285         }
286     } else {
287         return false;
288     }
289 }
290 
291 
292 Boundary
getCenteringBoundary() const293 GNENet::getCenteringBoundary() const {
294     return getBoundary();
295 }
296 
297 
298 const Boundary&
getZBoundary() const299 GNENet::getZBoundary() const {
300     return myZBoundary;
301 }
302 
303 
304 SUMORTree&
getVisualisationSpeedUp()305 GNENet::getVisualisationSpeedUp() {
306     return myGrid;
307 }
308 
309 
310 const SUMORTree&
getVisualisationSpeedUp() const311 GNENet::getVisualisationSpeedUp() const {
312     return myGrid;
313 }
314 
315 
316 GNEJunction*
createJunction(const Position & pos,GNEUndoList * undoList)317 GNENet::createJunction(const Position& pos, GNEUndoList* undoList) {
318     std::string id = myJunctionIDSupplier.getNext();
319     NBNode* nbn = new NBNode(id, pos);
320     GNEJunction* junction = new GNEJunction(*nbn, this);
321     undoList->add(new GNEChange_Junction(junction, true), true);
322     assert(myAttributeCarriers.junctions[id]);
323     return junction;
324 }
325 
326 
327 GNEEdge*
createEdge(GNEJunction * src,GNEJunction * dest,GNEEdge * tpl,GNEUndoList * undoList,const std::string & suggestedName,bool wasSplit,bool allowDuplicateGeom,bool recomputeConnections)328 GNENet::createEdge(
329     GNEJunction* src, GNEJunction* dest, GNEEdge* tpl, GNEUndoList* undoList,
330     const std::string& suggestedName,
331     bool wasSplit,
332     bool allowDuplicateGeom,
333     bool recomputeConnections) {
334     // prevent duplicate edge (same geometry)
335     const EdgeVector& outgoing = src->getNBNode()->getOutgoingEdges();
336     for (EdgeVector::const_iterator it = outgoing.begin(); it != outgoing.end(); it++) {
337         if ((*it)->getToNode() == dest->getNBNode() && (*it)->getGeometry().size() == 2) {
338             if (!allowDuplicateGeom) {
339                 return nullptr;
340             }
341         }
342     }
343 
344     std::string id;
345     if (suggestedName != "" && !retrieveEdge(suggestedName, false)) {
346         id = suggestedName;
347         reserveEdgeID(id);
348     } else {
349         id = myEdgeIDSupplier.getNext();
350     }
351 
352     GNEEdge* edge;
353     if (tpl) {
354         NBEdge* nbeTpl = tpl->getNBEdge();
355         NBEdge* nbe = new NBEdge(id, src->getNBNode(), dest->getNBNode(), nbeTpl);
356         edge = new GNEEdge(*nbe, this, wasSplit);
357     } else {
358         // default if no template is given
359         const OptionsCont& oc = OptionsCont::getOptions();
360         double defaultSpeed = oc.getFloat("default.speed");
361         std::string defaultType = "";
362         int defaultNrLanes = oc.getInt("default.lanenumber");
363         int defaultPriority = oc.getInt("default.priority");
364         double defaultWidth = NBEdge::UNSPECIFIED_WIDTH;
365         double defaultOffset = NBEdge::UNSPECIFIED_OFFSET;
366         NBEdge* nbe = new NBEdge(id, src->getNBNode(), dest->getNBNode(),
367                                  defaultType, defaultSpeed,
368                                  defaultNrLanes, defaultPriority,
369                                  defaultWidth,
370                                  defaultOffset);
371         edge = new GNEEdge(*nbe, this, wasSplit);
372     }
373     undoList->p_begin("create " + toString(SUMO_TAG_EDGE));
374     undoList->add(new GNEChange_Edge(edge, true), true);
375     if (recomputeConnections) {
376         src->setLogicValid(false, undoList);
377         dest->setLogicValid(false, undoList);
378     }
379     requireRecompute();
380     undoList->p_end();
381     assert(myAttributeCarriers.edges[id]);
382     return edge;
383 }
384 
385 
386 void
deleteJunction(GNEJunction * junction,GNEUndoList * undoList)387 GNENet::deleteJunction(GNEJunction* junction, GNEUndoList* undoList) {
388     // we have to delete all incident edges because they cannot exist without that junction
389     // all deletions must be undone/redone together so we start a new command group
390     // @todo if any of those edges are dead-ends should we remove their orphan junctions as well?
391     undoList->p_begin("delete " + toString(SUMO_TAG_JUNCTION));
392 
393     // delete all crossings vinculated with junction
394     while (junction->getGNECrossings().size() > 0) {
395         deleteCrossing(junction->getGNECrossings().front(), undoList);
396     }
397 
398     // find all crossings of neightbour junctions that shares an edge of this junction
399     std::vector<GNECrossing*> crossingsToRemove;
400     std::vector<GNEJunction*> junctionNeighbours = junction->getJunctionNeighbours();
401     for (auto i : junctionNeighbours) {
402         // iterate over crossing of neighbour juntion
403         for (auto j : i->getGNECrossings()) {
404             // if at least one of the edges of junction to remove belongs to a crossing of the neighbour junction, delete it
405             if (j->checkEdgeBelong(junction->getGNEEdges())) {
406                 crossingsToRemove.push_back(j);
407             }
408         }
409     }
410 
411     // delete crossings top remove
412     for (auto i : crossingsToRemove) {
413         deleteCrossing(i, undoList);
414     }
415 
416     // deleting edges changes in the underlying EdgeVector so we have to make a copy
417     const EdgeVector incident = junction->getNBNode()->getEdges();
418     for (auto it : incident) {
419         deleteEdge(myAttributeCarriers.edges[it->getID()], undoList, true);
420     }
421 
422     // remove any traffic lights from the traffic light container (avoids lots of warnings)
423     junction->setAttribute(SUMO_ATTR_TYPE, toString(NODETYPE_PRIORITY), undoList);
424 
425     // delete edge
426     undoList->add(new GNEChange_Junction(junction, false), true);
427     undoList->p_end();
428 }
429 
430 
431 void
deleteEdge(GNEEdge * edge,GNEUndoList * undoList,bool recomputeConnections)432 GNENet::deleteEdge(GNEEdge* edge, GNEUndoList* undoList, bool recomputeConnections) {
433     undoList->p_begin("delete " + toString(SUMO_TAG_EDGE));
434     // delete all shapes childs of edge
435     while (edge->getShapeChilds().size() > 0) {
436         deleteShape(edge->getShapeChilds().front(), undoList);
437     }
438     // delete all shapes childs of lane
439     for (auto i : edge->getLanes()) {
440         while (i->getShapeChilds().size() > 0) {
441             deleteShape(i->getShapeChilds().front(), undoList);
442         }
443     }
444     // delete all additionals childs of edge
445     while (edge->getAdditionalChilds().size() > 0) {
446         deleteAdditional(edge->getAdditionalChilds().front(), undoList);
447     }
448     // delete all additionals childs of lane
449     for (auto i : edge->getLanes()) {
450         while (i->getAdditionalChilds().size() > 0) {
451             deleteAdditional(i->getAdditionalChilds().front(), undoList);
452         }
453     }
454     // delete all demand element childs of edge
455     while (edge->getDemandElementChilds().size() > 0) {
456         deleteDemandElement(edge->getDemandElementChilds().front(), undoList);
457     }
458     // delete all demand element childs of lane
459     for (auto i : edge->getLanes()) {
460         while (i->getDemandElementChilds().size() > 0) {
461             deleteDemandElement(i->getDemandElementChilds().front(), undoList);
462         }
463     }
464     // remove edge from crossings related with this edge
465     edge->getGNEJunctionSource()->removeEdgeFromCrossings(edge, undoList);
466     edge->getGNEJunctionDestiny()->removeEdgeFromCrossings(edge, undoList);
467     // update affected connections
468     if (recomputeConnections) {
469         edge->getGNEJunctionSource()->setLogicValid(false, undoList);
470         edge->getGNEJunctionDestiny()->setLogicValid(false, undoList);
471     } else {
472         edge->getGNEJunctionSource()->removeConnectionsTo(edge, undoList, true);
473         edge->getGNEJunctionSource()->removeConnectionsFrom(edge, undoList, true);
474     }
475     // if junction source is a TLS and after deletion will have only an edge, remove TLS
476     if (edge->getGNEJunctionSource()->getNBNode()->isTLControlled() && (edge->getGNEJunctionSource()->getGNEOutgoingEdges().size() <= 1)) {
477         edge->getGNEJunctionSource()->setAttribute(SUMO_ATTR_TYPE, toString(NODETYPE_PRIORITY), undoList);
478     }
479     // if junction destiny is a TLS and after deletion will have only an edge, remove TLS
480     if (edge->getGNEJunctionDestiny()->getNBNode()->isTLControlled() && (edge->getGNEJunctionDestiny()->getGNEIncomingEdges().size() <= 1)) {
481         edge->getGNEJunctionDestiny()->setAttribute(SUMO_ATTR_TYPE, toString(NODETYPE_PRIORITY), undoList);
482     }
483     // Delete edge
484     undoList->add(new GNEChange_Edge(edge, false), true);
485     // remove edge requieres always a recompute (due geometry and connections)
486     requireRecompute();
487     // finish delete edge
488     undoList->p_end();
489 }
490 
491 
492 void
replaceIncomingEdge(GNEEdge * which,GNEEdge * by,GNEUndoList * undoList)493 GNENet::replaceIncomingEdge(GNEEdge* which, GNEEdge* by, GNEUndoList* undoList) {
494     undoList->p_begin("replace " + toString(SUMO_TAG_EDGE));
495     undoList->p_add(new GNEChange_Attribute(by, this, SUMO_ATTR_TO, which->getAttribute(SUMO_ATTR_TO)));
496     // replace in additionals childs of edge
497     while (which->getAdditionalChilds().size() > 0) {
498         undoList->p_add(new GNEChange_Attribute(which->getAdditionalChilds().front(), this, SUMO_ATTR_EDGE, by->getID()));
499     }
500     // replace in additionals childs of lane
501     for (auto i : which->getLanes()) {
502         std::vector<GNEAdditional*> copyOfLaneAdditionals = i->getAdditionalChilds();
503         for (auto j : copyOfLaneAdditionals) {
504             undoList->p_add(new GNEChange_Attribute(j, this, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(i->getIndex())));
505         }
506     }
507     // replace in demand elements childs of edge
508     while (which->getDemandElementChilds().size() > 0) {
509         undoList->p_add(new GNEChange_Attribute(which->getDemandElementChilds().front(), this, SUMO_ATTR_EDGE, by->getID()));
510     }
511     // replace in demand elements childs of lane
512     for (auto i : which->getLanes()) {
513         std::vector<GNEDemandElement*> copyOfLaneDemandElements = i->getDemandElementChilds();
514         for (auto j : copyOfLaneDemandElements) {
515             undoList->p_add(new GNEChange_Attribute(j, this, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(i->getIndex())));
516         }
517     }
518     // replace in shapes childs of lane
519     for (auto i : which->getLanes()) {
520         std::vector<GNEShape*> copyOfLaneShapes = i->getShapeChilds();
521         for (auto j : copyOfLaneShapes) {
522             undoList->p_add(new GNEChange_Attribute(j, this, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(i->getIndex())));
523         }
524     }
525     // replace in rerouters
526     for (auto rerouter : which->getAdditionalParents()) {
527         replaceInListAttribute(rerouter, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
528     }
529     // replace in crossings
530     for (auto crossing : which->getGNEJunctionDestiny()->getGNECrossings()) {
531         // if at least one of the edges of junction to remove belongs to a crossing of the source junction, delete it
532         replaceInListAttribute(crossing, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
533     }
534     // fix connections (make a copy because they will be modified
535     std::vector<NBEdge::Connection> connections = which->getNBEdge()->getConnections();
536     for (auto con : connections) {
537         undoList->add(new GNEChange_Connection(which, con, false, false), true);
538         undoList->add(new GNEChange_Connection(by, con, false, true), true);
539     }
540     undoList->add(new GNEChange_ReplaceEdgeInTLS(getTLLogicCont(), which->getNBEdge(), by->getNBEdge()), true);
541     // Delete edge
542     undoList->add(new GNEChange_Edge(which, false), true);
543     // finish replace edge
544     undoList->p_end();
545 }
546 
547 
548 void
deleteLane(GNELane * lane,GNEUndoList * undoList,bool recomputeConnections)549 GNENet::deleteLane(GNELane* lane, GNEUndoList* undoList, bool recomputeConnections) {
550     GNEEdge* edge = &lane->getParentEdge();
551     if (edge->getNBEdge()->getNumLanes() == 1) {
552         // remove the whole edge instead
553         deleteEdge(edge, undoList, recomputeConnections);
554     } else {
555         undoList->p_begin("delete " + toString(SUMO_TAG_LANE));
556         // delete additionals childs of lane
557         while (lane->getAdditionalChilds().size() > 0) {
558             deleteAdditional(lane->getAdditionalChilds().front(), undoList);
559         }
560         // delete demand element childs of lane
561         while (lane->getDemandElementChilds().size() > 0) {
562             deleteDemandElement(lane->getDemandElementChilds().front(), undoList);
563         }
564         // delete POIShapes of Lane
565         while (lane->getShapeChilds().size() > 0) {
566             undoList->add(new GNEChange_Shape(lane->getShapeChilds().front(), false), true);
567         }
568         // update affected connections
569         if (recomputeConnections) {
570             edge->getGNEJunctionSource()->setLogicValid(false, undoList);
571             edge->getGNEJunctionDestiny()->setLogicValid(false, undoList);
572         } else {
573             edge->getGNEJunctionSource()->removeConnectionsTo(edge, undoList, true, lane->getIndex());
574             edge->getGNEJunctionSource()->removeConnectionsFrom(edge, undoList, true, lane->getIndex());
575         }
576         // delete lane
577         const NBEdge::Lane& laneAttrs = edge->getNBEdge()->getLaneStruct(lane->getIndex());
578         undoList->add(new GNEChange_Lane(edge, lane, laneAttrs, false, recomputeConnections), true);
579         // remove lane requieres always a recompute (due geometry and connections)
580         requireRecompute();
581         undoList->p_end();
582     }
583 }
584 
585 
586 void
deleteConnection(GNEConnection * connection,GNEUndoList * undoList)587 GNENet::deleteConnection(GNEConnection* connection, GNEUndoList* undoList) {
588     undoList->p_begin("delete " + toString(SUMO_TAG_CONNECTION));
589     // obtain NBConnection to remove
590     NBConnection deleted = connection->getNBConnection();
591     GNEJunction* junctionDestiny = connection->getEdgeFrom()->getGNEJunctionDestiny();
592     junctionDestiny->markAsModified(undoList);
593     undoList->add(new GNEChange_Connection(connection->getEdgeFrom(), connection->getNBEdgeConnection(), connection->isAttributeCarrierSelected(), false), true);
594     junctionDestiny->invalidateTLS(undoList, deleted);
595     // remove connection requieres always a recompute (due geometry and connections)
596     requireRecompute();
597     undoList->p_end();
598 }
599 
600 
601 void
deleteCrossing(GNECrossing * crossing,GNEUndoList * undoList)602 GNENet::deleteCrossing(GNECrossing* crossing, GNEUndoList* undoList) {
603     undoList->p_begin("delete crossing");
604     // remove it using GNEChange_Crossing
605     undoList->add(new GNEChange_Crossing(crossing->getParentJunction(), crossing->getNBCrossing()->edges,
606                                          crossing->getNBCrossing()->width, crossing->getNBCrossing()->priority,
607                                          crossing->getNBCrossing()->customTLIndex,
608                                          crossing->getNBCrossing()->customTLIndex2,
609                                          crossing->getNBCrossing()->customShape,
610                                          crossing->isAttributeCarrierSelected(),
611                                          false), true);
612     // remove crossing requieres always a recompute (due geometry and connections)
613     requireRecompute();
614     undoList->p_end();
615 }
616 
617 
618 void
deleteShape(GNEShape * shape,GNEUndoList * undoList)619 GNENet::deleteShape(GNEShape* shape, GNEUndoList* undoList) {
620     undoList->p_begin("delete " + shape->getTagStr());
621     // delete shape
622     undoList->add(new GNEChange_Shape(shape, false), true);
623     undoList->p_end();
624 }
625 
626 
627 void
deleteAdditional(GNEAdditional * additional,GNEUndoList * undoList)628 GNENet::deleteAdditional(GNEAdditional* additional, GNEUndoList* undoList) {
629     undoList->p_begin("delete " + additional->getTagStr());
630     // first remove all additional childs of this additional calling this function recursively
631     while (additional->getAdditionalChilds().size() > 0) {
632         deleteAdditional(additional->getAdditionalChilds().front(), undoList);
633     }
634     // remove additional
635     undoList->add(new GNEChange_Additional(additional, false), true);
636     undoList->p_end();
637 }
638 
639 
640 void
deleteDemandElement(GNEDemandElement * demandElement,GNEUndoList * undoList)641 GNENet::deleteDemandElement(GNEDemandElement* demandElement, GNEUndoList* undoList) {
642     undoList->p_begin("delete " + demandElement->getTagStr());
643     // first remove all demand element childs of this demandElement calling this function recursively
644     while (demandElement->getDemandElementChilds().size() > 0) {
645         deleteDemandElement(demandElement->getDemandElementChilds().front(), undoList);
646     }
647     // remove demandElement
648     undoList->add(new GNEChange_DemandElement(demandElement, false), true);
649     undoList->p_end();
650 }
651 
652 
653 void
duplicateLane(GNELane * lane,GNEUndoList * undoList,bool recomputeConnections)654 GNENet::duplicateLane(GNELane* lane, GNEUndoList* undoList, bool recomputeConnections) {
655     undoList->p_begin("duplicate " + toString(SUMO_TAG_LANE));
656     GNEEdge* edge = &lane->getParentEdge();
657     const NBEdge::Lane& laneAttrs = edge->getNBEdge()->getLaneStruct(lane->getIndex());
658     if (recomputeConnections) {
659         edge->getGNEJunctionSource()->setLogicValid(false, undoList);
660         edge->getGNEJunctionSource()->setLogicValid(false, undoList);
661     }
662     GNELane* newLane = new GNELane(*edge, lane->getIndex());
663     undoList->add(new GNEChange_Lane(edge, newLane, laneAttrs, true, recomputeConnections), true);
664     requireRecompute();
665     undoList->p_end();
666 }
667 
668 
669 bool
restrictLane(SUMOVehicleClass vclass,GNELane * lane,GNEUndoList * undoList)670 GNENet::restrictLane(SUMOVehicleClass vclass, GNELane* lane, GNEUndoList* undoList) {
671     bool addRestriction = true;
672     if (vclass == SVC_PEDESTRIAN) {
673         GNEEdge& edge = lane->getParentEdge();
674         for (auto i : edge.getLanes()) {
675             if (i->isRestricted(SVC_PEDESTRIAN)) {
676                 // prevent adding a 2nd sidewalk
677                 addRestriction = false;
678             } else {
679                 // ensure that the sidewalk is used exclusively
680                 const SVCPermissions allOldWithoutPeds = edge.getNBEdge()->getPermissions(i->getIndex()) & ~SVC_PEDESTRIAN;
681                 i->setAttribute(SUMO_ATTR_ALLOW, getVehicleClassNames(allOldWithoutPeds), undoList);
682             }
683         }
684     }
685     // restrict the lane
686     if (addRestriction) {
687         const double width = (vclass == SVC_PEDESTRIAN || vclass == SVC_BICYCLE
688                               ? OptionsCont::getOptions().getFloat("default.sidewalk-width")
689                               : OptionsCont::getOptions().getFloat("default.lanewidth"));
690         lane->setAttribute(SUMO_ATTR_ALLOW, toString(vclass), undoList);
691         lane->setAttribute(SUMO_ATTR_WIDTH, toString(width), undoList);
692         return true;
693     } else {
694         return false;
695     }
696 }
697 
698 
699 bool
addRestrictedLane(SUMOVehicleClass vclass,GNEEdge & edge,int index,GNEUndoList * undoList)700 GNENet::addRestrictedLane(SUMOVehicleClass vclass, GNEEdge& edge, int index, GNEUndoList* undoList) {
701     // First check that edge don't have a restricted lane of the given vclass
702     for (auto i : edge.getLanes()) {
703         if (i->isRestricted(vclass)) {
704             return false;
705         }
706     }
707     // check that index is correct (index == size adds to the left of the leftmost lane)
708     const int numLanes = (int)edge.getLanes().size();
709     if (index > numLanes) {
710         return false;
711     }
712     if (index < 0) {
713         // guess index from vclass
714         if (vclass == SVC_PEDESTRIAN) {
715             index = 0;
716         } else if (vclass == SVC_BICYCLE) {
717             // add bikelanes to the left of an existing sidewalk
718             index = edge.getLanes()[0]->isRestricted(SVC_PEDESTRIAN) ? 1 : 0;
719         } else if (vclass == SVC_IGNORING || vclass == SVC_BUS) {
720             // add greenVerge to the left of an existing sidewalk or bikeLane
721             // add busLane to the left of an existing sidewalk, bikeLane or greenVerge
722             index = 0;
723             while (index < numLanes && (edge.getNBEdge()->getPermissions(index) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) {
724                 index++;
725             }
726         }
727     }
728     // duplicate selected lane
729     duplicateLane(edge.getLanes().at(MIN2(index, numLanes - 1)), undoList, true);
730     // transform the created lane
731     return restrictLane(vclass, edge.getLanes().at(index), undoList);
732 }
733 
734 
735 bool
removeRestrictedLane(SUMOVehicleClass vclass,GNEEdge & edge,GNEUndoList * undoList)736 GNENet::removeRestrictedLane(SUMOVehicleClass vclass, GNEEdge& edge, GNEUndoList* undoList) {
737     // iterate over lanes of edge
738     for (auto i : edge.getLanes()) {
739         if (i->isRestricted(vclass)) {
740             // Delete lane
741             deleteLane(i, undoList, true);
742             return true;
743         }
744     }
745     return false;
746 }
747 
748 
749 GNEJunction*
splitEdge(GNEEdge * edge,const Position & pos,GNEUndoList * undoList,GNEJunction * newJunction)750 GNENet::splitEdge(GNEEdge* edge, const Position& pos, GNEUndoList* undoList, GNEJunction* newJunction) {
751     undoList->p_begin("split " + toString(SUMO_TAG_EDGE));
752     if (newJunction == nullptr) {
753         newJunction = createJunction(pos, undoList);
754     }
755     // compute geometry
756     const PositionVector& oldGeom = edge->getNBEdge()->getGeometry();
757     const double linePos = oldGeom.nearest_offset_to_point2D(pos, false);
758     std::pair<PositionVector, PositionVector> newGeoms = oldGeom.splitAt(linePos);
759     const std::string shapeEnd = edge->getAttribute(GNE_ATTR_SHAPE_END);
760     // figure out the new name
761     int posBase = 0;
762     std::string baseName = edge->getMicrosimID();
763     if (edge->wasSplit()) {
764         const std::string::size_type sep_index = baseName.rfind('.');
765         if (sep_index != std::string::npos) { // edge may have been renamed in between
766             std::string posString = baseName.substr(sep_index + 1);
767             try {
768                 posBase = GNEAttributeCarrier::parse<int>(posString.c_str());
769                 baseName = baseName.substr(0, sep_index); // includes the .
770             } catch (NumberFormatException&) {
771             }
772         }
773     }
774     baseName += '.';
775     // create a new edge from the new junction to the previous destination
776     GNEEdge* secondPart = createEdge(newJunction, edge->getGNEJunctionDestiny(), edge,
777                                      undoList, baseName + toString(posBase + (int)linePos), true, false, false);
778     // fix connections from the split edge (must happen before changing SUMO_ATTR_TO)
779     edge->getGNEJunctionDestiny()->replaceIncomingConnections(edge, secondPart, undoList);
780     // remove affected crossings from junction (must happen before changing SUMO_ATTR_TO)
781     std::vector<NBNode::Crossing> affectedCrossings;
782     for (GNECrossing* crossing : edge->getGNEJunctionDestiny()->getGNECrossings()) {
783         if (crossing->checkEdgeBelong(edge)) {
784             NBNode::Crossing nbC = *crossing->getNBCrossing();
785             undoList->add(new GNEChange_Crossing(edge->getGNEJunctionDestiny(), nbC, false), true);
786             EdgeVector newEdges;
787             for (NBEdge* nbEdge : nbC.edges) {
788                 if (nbEdge == edge->getNBEdge()) {
789                     newEdges.push_back(secondPart->getNBEdge());
790                 } else {
791                     newEdges.push_back(nbEdge);
792                 }
793             }
794             nbC.edges = newEdges;
795             affectedCrossings.push_back(nbC);
796         }
797     }
798     // modify the edge so that it ends at the new junction (and all incoming connections are preserved
799     undoList->p_add(new GNEChange_Attribute(edge, this, SUMO_ATTR_TO, newJunction->getID()));
800     // fix first part of geometry
801     newGeoms.first.pop_back();
802     newGeoms.first.erase(newGeoms.first.begin());
803     edge->setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
804     edge->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.first), undoList);
805     // fix second part of geometry
806     secondPart->setAttribute(GNE_ATTR_SHAPE_END, shapeEnd, undoList);
807     newGeoms.second.pop_back();
808     newGeoms.second.erase(newGeoms.second.begin());
809     secondPart->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.second), undoList);
810     // reconnect across the split
811     for (int i = 0; i < (int)edge->getLanes().size(); ++i) {
812         undoList->add(new GNEChange_Connection(edge, NBEdge::Connection(i, secondPart->getNBEdge(), i), false, true), true);
813     }
814     // re-add modified crossings
815     for (const auto& nbC : affectedCrossings) {
816         undoList->add(new GNEChange_Crossing(secondPart->getGNEJunctionDestiny(), nbC, true), true);
817     }
818     undoList->p_end();
819     return newJunction;
820 }
821 
822 
823 void
splitEdgesBidi(GNEEdge * edge,GNEEdge * oppositeEdge,const Position & pos,GNEUndoList * undoList)824 GNENet::splitEdgesBidi(GNEEdge* edge, GNEEdge* oppositeEdge, const Position& pos, GNEUndoList* undoList) {
825     GNEJunction* newJunction = nullptr;
826     undoList->p_begin("split " + toString(SUMO_TAG_EDGE) + "s");
827     // split edge and save created junction
828     newJunction = splitEdge(edge, pos, undoList, newJunction);
829     // split second edge
830     splitEdge(oppositeEdge, pos, undoList, newJunction);
831     undoList->p_end();
832 }
833 
834 
835 void
reverseEdge(GNEEdge * edge,GNEUndoList * undoList)836 GNENet::reverseEdge(GNEEdge* edge, GNEUndoList* undoList) {
837     undoList->p_begin("reverse " + toString(SUMO_TAG_EDGE));
838     deleteEdge(edge, undoList, false); // still exists. we delete it so we can reuse the name in case of resplit
839     GNEEdge* reversed = createEdge(edge->getGNEJunctionDestiny(), edge->getGNEJunctionSource(), edge, undoList, edge->getID(), false, true);
840     assert(reversed != 0);
841     reversed->setAttribute(SUMO_ATTR_SHAPE, toString(edge->getNBEdge()->getInnerGeometry().reverse()), undoList);
842     reversed->setAttribute(GNE_ATTR_SHAPE_START, edge->getAttribute(GNE_ATTR_SHAPE_END), undoList);
843     reversed->setAttribute(GNE_ATTR_SHAPE_END, edge->getAttribute(GNE_ATTR_SHAPE_START), undoList);
844     undoList->p_end();
845 }
846 
847 
848 GNEEdge*
addReversedEdge(GNEEdge * edge,GNEUndoList * undoList)849 GNENet::addReversedEdge(GNEEdge* edge, GNEUndoList* undoList) {
850     undoList->p_begin("add reversed " + toString(SUMO_TAG_EDGE));
851     GNEEdge* reversed = nullptr;
852     if (edge->getNBEdge()->getLaneSpreadFunction() == LANESPREAD_RIGHT || isRailway(edge->getNBEdge()->getPermissions())) {
853         // for rail edges, we assume bi-directional tracks are wanted
854         reversed = createEdge(edge->getGNEJunctionDestiny(), edge->getGNEJunctionSource(), edge, undoList, "-" + edge->getID(), false, true);
855         assert(reversed != 0);
856         reversed->setAttribute(SUMO_ATTR_SHAPE, toString(edge->getNBEdge()->getInnerGeometry().reverse()), undoList);
857         reversed->setAttribute(GNE_ATTR_SHAPE_START, edge->getAttribute(GNE_ATTR_SHAPE_END), undoList);
858         reversed->setAttribute(GNE_ATTR_SHAPE_END, edge->getAttribute(GNE_ATTR_SHAPE_START), undoList);
859     } else {
860         // if the edge is centered it should probably connect somewhere else
861         // make it easy to move and reconnect it
862         PositionVector orig = edge->getNBEdge()->getGeometry();
863         PositionVector origInner = edge->getNBEdge()->getInnerGeometry();
864         const double tentativeShift = edge->getNBEdge()->getTotalWidth() + 2;
865         orig.move2side(-tentativeShift);
866         origInner.move2side(-tentativeShift);
867         GNEJunction* src = createJunction(orig.back(), undoList);
868         GNEJunction* dest = createJunction(orig.front(), undoList);
869         reversed = createEdge(src, dest, edge, undoList, "-" + edge->getID(), false, true);
870         assert(reversed != 0);
871         reversed->setAttribute(SUMO_ATTR_SHAPE, toString(origInner.reverse()), undoList);
872         reversed->setAttribute(SUMO_ATTR_SHAPE, toString(origInner.reverse()), undoList);
873         // select the new edge and its nodes
874         reversed->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
875         src->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
876         dest->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
877     }
878     undoList->p_end();
879     return reversed;
880 }
881 
882 
883 void
mergeJunctions(GNEJunction * moved,GNEJunction * target,GNEUndoList * undoList)884 GNENet::mergeJunctions(GNEJunction* moved, GNEJunction* target, GNEUndoList* undoList) {
885     undoList->p_begin("merge " + toString(SUMO_TAG_JUNCTION) + "s");
886     // place moved junction in the same position of target junction
887     moved->setAttribute(SUMO_ATTR_POSITION, target->getAttribute(SUMO_ATTR_POSITION), undoList);
888     // deleting edges changes in the underlying EdgeVector so we have to make a copy
889     const EdgeVector incoming = moved->getNBNode()->getIncomingEdges();
890     for (NBEdge* edge : incoming) {
891         // delete edges between the merged junctions
892         GNEEdge* e = myAttributeCarriers.edges[edge->getID()];
893         assert(e != 0);
894         if (e->getGNEJunctionSource() == target) {
895             deleteEdge(e, undoList, false);
896         } else {
897             undoList->p_add(new GNEChange_Attribute(e, this, SUMO_ATTR_TO, target->getID()));
898         }
899     }
900     // deleting edges changes in the underlying EdgeVector so we have to make a copy
901     const EdgeVector outgoing = moved->getNBNode()->getOutgoingEdges();
902     for (NBEdge* edge : outgoing) {
903         // delete edges between the merged junctions
904         GNEEdge* e = myAttributeCarriers.edges[edge->getID()];
905         assert(e != 0);
906         if (e->getGNEJunctionDestiny() == target) {
907             deleteEdge(e, undoList, false);
908         } else {
909             undoList->p_add(new GNEChange_Attribute(e, this, SUMO_ATTR_FROM, target->getID()));
910         }
911     }
912     // deleted moved junction
913     deleteJunction(moved, undoList);
914     undoList->p_end();
915 }
916 
917 
918 bool
checkJunctionPosition(const Position & pos)919 GNENet::checkJunctionPosition(const Position& pos) {
920     // Check that there isn't another junction in the same position as Pos
921     for (auto i : myAttributeCarriers.junctions) {
922         if (i.second->getPositionInView() == pos) {
923             return false;
924         }
925     }
926     return true;
927 }
928 
929 
930 void
requiereSaveNet(bool value)931 GNENet::requiereSaveNet(bool value) {
932     if (myNetSaved == true) {
933         WRITE_DEBUG("net has to be saved");
934         std::string additionalsSaved = (myAdditionalsSaved ? "saved" : "unsaved");
935         std::string demandElementsSaved = (myDemandElementsSaved ? "saved" : "unsaved");
936         WRITE_DEBUG("Current saving Status: net unsaved, additionals " + additionalsSaved + ", demand elements " + demandElementsSaved);
937     }
938     myNetSaved = !value;
939 }
940 
941 
942 bool
isNetSaved() const943 GNENet::isNetSaved() const {
944     return myNetSaved;
945 }
946 
947 
948 void
save(OptionsCont & oc)949 GNENet::save(OptionsCont& oc) {
950     // compute without volatile options and update network
951     computeAndUpdate(oc, false);
952     // write network
953     NWFrame::writeNetwork(oc, *myNetBuilder);
954     myNetSaved = true;
955 }
956 
957 
958 void
savePlain(OptionsCont & oc)959 GNENet::savePlain(OptionsCont& oc) {
960     // compute without volatile options
961     computeAndUpdate(oc, false);
962     NWWriter_XML::writeNetwork(oc, *myNetBuilder);
963 }
964 
965 
966 void
saveJoined(OptionsCont & oc)967 GNENet::saveJoined(OptionsCont& oc) {
968     // compute without volatile options
969     computeAndUpdate(oc, false);
970     NWWriter_XML::writeJoinedJunctions(oc, myNetBuilder->getNodeCont());
971 }
972 
973 
974 void
setViewNet(GNEViewNet * viewNet)975 GNENet::setViewNet(GNEViewNet* viewNet) {
976     myViewNet = viewNet;
977 
978     // Create default vehicle Type (it has to be created here due myViewNet was previously nullptr)
979     GNEVehicleType* defaultVehicleType = new GNEVehicleType(myViewNet, DEFAULT_VTYPE_ID, SVC_PASSENGER);
980     myAttributeCarriers.demandElements.at(defaultVehicleType->getTagProperty().getTag()).insert(std::make_pair(defaultVehicleType->getID(), defaultVehicleType));
981     defaultVehicleType->incRef("GNENet::DEFAULT_VEHTYPE");
982 
983     // Create default pedestrian Type (it has to be created here due myViewNet was previously nullptr)
984     GNEVehicleType* defaultPedestrianType = new GNEVehicleType(myViewNet, DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
985     myAttributeCarriers.demandElements.at(defaultPedestrianType->getTagProperty().getTag()).insert(std::make_pair(defaultPedestrianType->getID(), defaultPedestrianType));
986     defaultPedestrianType->incRef("GNENet::DEFAULT_PEDTYPE_ID");
987 
988     // Create default Bike Type (it has to be created here due myViewNet was previously nullptr)
989     GNEVehicleType* defaultBikeType = new GNEVehicleType(myViewNet, DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
990     myAttributeCarriers.demandElements.at(defaultBikeType->getTagProperty().getTag()).insert(std::make_pair(defaultBikeType->getID(), defaultBikeType));
991     defaultBikeType->incRef("GNENet::DEFAULT_BIKETYPE_ID");
992 
993     // create instance of RouteCalculator
994     GNEDemandElement::createRouteCalculatorInstance(this);
995 }
996 
997 
998 GNEJunction*
retrieveJunction(const std::string & id,bool failHard)999 GNENet::retrieveJunction(const std::string& id, bool failHard) {
1000     if (myAttributeCarriers.junctions.count(id)) {
1001         return myAttributeCarriers.junctions[id];
1002     } else if (failHard) {
1003         // If junction wasn't found, throw exception
1004         throw UnknownElement("Junction " + id);
1005     } else {
1006         return nullptr;
1007     }
1008 }
1009 
1010 
1011 GNEEdge*
retrieveEdge(const std::string & id,bool failHard)1012 GNENet::retrieveEdge(const std::string& id, bool failHard) {
1013     auto i = myAttributeCarriers.edges.find(id);
1014     // If edge was found
1015     if (i != myAttributeCarriers.edges.end()) {
1016         return i->second;
1017     } else if (failHard) {
1018         // If edge wasn't found, throw exception
1019         throw UnknownElement("Edge " + id);
1020     } else {
1021         return nullptr;
1022     }
1023 }
1024 
1025 
1026 GNEEdge*
retrieveEdge(GNEJunction * from,GNEJunction * to,bool failHard)1027 GNENet::retrieveEdge(GNEJunction* from, GNEJunction* to, bool failHard) {
1028     assert((from != nullptr) && (to != nullptr));
1029     // iterate over Junctions of net
1030     for (auto i : myAttributeCarriers.edges) {
1031         if ((i.second->getGNEJunctionSource() == from) && (i.second->getGNEJunctionDestiny() == to)) {
1032             return i.second;
1033         }
1034     }
1035     // if edge wasn' found, throw exception or return nullptr
1036     if (failHard) {
1037         throw UnknownElement("Edge with from='" + from->getID() + "' and to='" + to->getID() + "'");
1038     } else {
1039         return nullptr;
1040     }
1041 }
1042 
1043 
1044 GNEPoly*
retrievePolygon(const std::string & id,bool failHard) const1045 GNENet::retrievePolygon(const std::string& id, bool failHard) const {
1046     if (myPolygons.get(id) != 0) {
1047         return reinterpret_cast<GNEPoly*>(myPolygons.get(id));
1048     } else if (failHard) {
1049         // If Polygon wasn't found, throw exception
1050         throw UnknownElement("Polygon " + id);
1051     } else {
1052         return nullptr;
1053     }
1054 }
1055 
1056 
1057 GNEPOI*
retrievePOI(const std::string & id,bool failHard) const1058 GNENet::retrievePOI(const std::string& id, bool failHard) const {
1059     if (myPOIs.get(id) != 0) {
1060         return reinterpret_cast<GNEPOI*>(myPOIs.get(id));
1061     } else if (failHard) {
1062         // If POI wasn't found, throw exception
1063         throw UnknownElement("POI " + id);
1064     } else {
1065         return nullptr;
1066     }
1067 }
1068 
1069 
1070 GNEConnection*
retrieveConnection(const std::string & id,bool failHard) const1071 GNENet::retrieveConnection(const std::string& id, bool failHard) const {
1072     // iterate over junctions
1073     for (auto i : myAttributeCarriers.junctions) {
1074         // iterate over connections
1075         for (auto j : i.second->getGNEConnections()) {
1076             if (j->getID() == id) {
1077                 return j;
1078             }
1079         }
1080     }
1081     if (failHard) {
1082         // If POI wasn't found, throw exception
1083         throw UnknownElement("Connection " + id);
1084     } else {
1085         return nullptr;
1086     }
1087 }
1088 
1089 
1090 std::vector<GNEConnection*>
retrieveConnections(bool onlySelected) const1091 GNENet::retrieveConnections(bool onlySelected) const {
1092     std::vector<GNEConnection*> result;
1093     // iterate over junctions
1094     for (auto i : myAttributeCarriers.junctions) {
1095         // iterate over connections
1096         for (auto j : i.second->getGNEConnections()) {
1097             if (!onlySelected || j->isAttributeCarrierSelected()) {
1098                 result.push_back(j);
1099             }
1100         }
1101     }
1102     return result;
1103 }
1104 
1105 
1106 GNECrossing*
retrieveCrossing(const std::string & id,bool failHard) const1107 GNENet::retrieveCrossing(const std::string& id, bool failHard) const {
1108     // iterate over junctions
1109     for (auto i : myAttributeCarriers.junctions) {
1110         // iterate over crossings
1111         for (auto j : i.second->getGNECrossings()) {
1112             if (j->getID() == id) {
1113                 return j;
1114             }
1115         }
1116     }
1117     if (failHard) {
1118         // If POI wasn't found, throw exception
1119         throw UnknownElement("Crossing " + id);
1120     } else {
1121         return nullptr;
1122     }
1123 }
1124 
1125 
1126 std::vector<GNECrossing*>
retrieveCrossings(bool onlySelected) const1127 GNENet::retrieveCrossings(bool onlySelected) const {
1128     std::vector<GNECrossing*> result;
1129     // iterate over junctions
1130     for (auto i : myAttributeCarriers.junctions) {
1131         // iterate over crossings
1132         for (auto j : i.second->getGNECrossings()) {
1133             if (!onlySelected || j->isAttributeCarrierSelected()) {
1134                 result.push_back(j);
1135             }
1136         }
1137     }
1138     return result;
1139 }
1140 
1141 
1142 std::vector<GNEEdge*>
retrieveEdges(bool onlySelected)1143 GNENet::retrieveEdges(bool onlySelected) {
1144     std::vector<GNEEdge*> result;
1145     // returns edges depending of selection
1146     for (auto i : myAttributeCarriers.edges) {
1147         if (!onlySelected || i.second->isAttributeCarrierSelected()) {
1148             result.push_back(i.second);
1149         }
1150     }
1151     return result;
1152 }
1153 
1154 
1155 std::vector<GNELane*>
retrieveLanes(bool onlySelected)1156 GNENet::retrieveLanes(bool onlySelected) {
1157     std::vector<GNELane*> result;
1158     // returns lanes depending of selection
1159     for (auto i : myAttributeCarriers.edges) {
1160         for (auto j : i.second->getLanes()) {
1161             if (!onlySelected || j->isAttributeCarrierSelected()) {
1162                 result.push_back(j);
1163             }
1164         }
1165     }
1166     return result;
1167 }
1168 
1169 
1170 GNELane*
retrieveLane(const std::string & id,bool failHard,bool checkVolatileChange)1171 GNENet::retrieveLane(const std::string& id, bool failHard, bool checkVolatileChange) {
1172     const std::string edge_id = SUMOXMLDefinitions::getEdgeIDFromLane(id);
1173     GNEEdge* edge = retrieveEdge(edge_id, failHard);
1174     if (edge != nullptr) {
1175         GNELane* lane = nullptr;
1176         // search  lane in lane's edges
1177         for (auto it : edge->getLanes()) {
1178             if (it->getID() == id) {
1179                 lane = it;
1180             }
1181         }
1182         // throw exception or return nullptr if lane wasn't found
1183         if (lane == nullptr) {
1184             if (failHard) {
1185                 // Throw exception if failHard is enabled
1186                 throw UnknownElement(toString(SUMO_TAG_LANE) + " " + id);
1187             }
1188         } else {
1189             // check if the recomputing with volatile option has changed the number of lanes (needed for additionals and demand elements)
1190             if (checkVolatileChange && (myEdgesAndNumberOfLanes.count(edge_id) == 1) && myEdgesAndNumberOfLanes[edge_id] != (int)edge->getLanes().size()) {
1191                 return edge->getLanes().at(lane->getIndex() + 1);
1192             }
1193             return lane;
1194         }
1195     } else if (failHard) {
1196         // Throw exception if failHard is enabled
1197         throw UnknownElement(toString(SUMO_TAG_EDGE) + " " + edge_id);
1198     }
1199     return nullptr;
1200 }
1201 
1202 
1203 std::vector<GNEJunction*>
retrieveJunctions(bool onlySelected)1204 GNENet::retrieveJunctions(bool onlySelected) {
1205     std::vector<GNEJunction*> result;
1206     // returns junctions depending of selection
1207     for (auto i : myAttributeCarriers.junctions) {
1208         if (!onlySelected || i.second->isAttributeCarrierSelected()) {
1209             result.push_back(i.second);
1210         }
1211     }
1212     return result;
1213 }
1214 
1215 
1216 std::vector<GNEShape*>
retrieveShapes(SumoXMLTag shapeTag,bool onlySelected)1217 GNENet::retrieveShapes(SumoXMLTag shapeTag, bool onlySelected) {
1218     std::vector<GNEShape*> result;
1219     // return dependingn of shape type
1220     if (shapeTag == SUMO_TAG_POLY) {
1221         // return all polys depending of onlySelected
1222         for (auto it : getPolygons()) {
1223             GNEShape* shape = dynamic_cast<GNEShape*>(it.second);
1224             if (!onlySelected || shape->isAttributeCarrierSelected()) {
1225                 result.push_back(shape);
1226             }
1227         }
1228     } else {
1229         // check if we need to return a POI or POILane
1230         for (auto it : getPOIs()) {
1231             GNEPOI* poi = dynamic_cast<GNEPOI*>(it.second);
1232             if (poi && (poi->getTagProperty().getTag() == shapeTag)) {
1233                 // return all POIs or POILanes depending of onlySelected
1234                 if (!onlySelected || poi->isAttributeCarrierSelected()) {
1235                     result.push_back(poi);
1236                 }
1237             }
1238         }
1239     }
1240     return result;
1241 }
1242 
1243 
1244 std::vector<GNEShape*>
retrieveShapes(bool onlySelected)1245 GNENet::retrieveShapes(bool onlySelected) {
1246     std::vector<GNEShape*> result;
1247     // return all polygons and POIs
1248     for (const auto& it : getPolygons()) {
1249         GNEPoly* poly = dynamic_cast<GNEPoly*>(it.second);
1250         if (!onlySelected || poly->isAttributeCarrierSelected()) {
1251             result.push_back(poly);
1252         }
1253     }
1254     for (const auto& it : getPOIs()) {
1255         GNEPOI* poi = dynamic_cast<GNEPOI*>(it.second);
1256         if (!onlySelected || poi->isAttributeCarrierSelected()) {
1257             result.push_back(poi);
1258         }
1259     }
1260     return result;
1261 }
1262 
1263 
1264 void
addGLObjectIntoGrid(GUIGlObject * o)1265 GNENet::addGLObjectIntoGrid(GUIGlObject* o) {
1266     myGrid.addAdditionalGLObject(o);
1267 }
1268 
1269 
1270 void
removeGLObjectFromGrid(GUIGlObject * o)1271 GNENet::removeGLObjectFromGrid(GUIGlObject* o) {
1272     myGrid.removeAdditionalGLObject(o);
1273 }
1274 
1275 
1276 GNEAttributeCarrier*
retrieveAttributeCarrier(GUIGlID id,bool failHard)1277 GNENet::retrieveAttributeCarrier(GUIGlID id, bool failHard) {
1278     // obtain blocked GUIGlObject
1279     GUIGlObject* object = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
1280     // Make sure that object exists
1281     if (object != nullptr) {
1282         // unblock and try to parse to AtributeCarrier
1283         GUIGlObjectStorage::gIDStorage.unblockObject(id);
1284         GNEAttributeCarrier* ac = dynamic_cast<GNEAttributeCarrier*>(object);
1285         // If was sucesfully parsed, return it
1286         if (ac == nullptr) {
1287             throw ProcessError("GUIGlObject does not match the declared type");
1288         } else {
1289             return ac;
1290         }
1291     } else if (failHard) {
1292         throw ProcessError("Attempted to retrieve non-existant GUIGlObject");
1293     } else {
1294         return nullptr;
1295     }
1296 }
1297 
1298 
1299 std::vector<GNEAttributeCarrier*>
retrieveAttributeCarriers(SumoXMLTag type)1300 GNENet::retrieveAttributeCarriers(SumoXMLTag type) {
1301     std::vector<GNEAttributeCarrier*> result;
1302     if (type == SUMO_TAG_NOTHING) {
1303         // return all elements
1304         for (auto i : myAttributeCarriers.junctions) {
1305             result.push_back(i.second);
1306             for (auto j : i.second->getGNECrossings()) {
1307                 result.push_back(j);
1308             }
1309         }
1310         for (auto i : myAttributeCarriers.edges) {
1311             result.push_back(i.second);
1312             for (auto j : i.second->getLanes()) {
1313                 result.push_back(j);
1314             }
1315             for (auto j : i.second->getGNEConnections()) {
1316                 result.push_back(j);
1317             }
1318         }
1319         for (auto i : myAttributeCarriers.additionals) {
1320             for (auto j : i.second) {
1321                 result.push_back(j.second);
1322             }
1323         }
1324         for (auto i : myPolygons) {
1325             result.push_back(dynamic_cast<GNEPoly*>(i.second));
1326         }
1327         for (auto i : myPOIs) {
1328             result.push_back(dynamic_cast<GNEPOI*>(i.second));
1329         }
1330         for (auto i : myAttributeCarriers.demandElements) {
1331             for (auto j : i.second) {
1332                 result.push_back(j.second);
1333             }
1334         }
1335     } else if (GNEAttributeCarrier::getTagProperties(type).isAdditional() || GNEAttributeCarrier::getTagProperties(type).isTAZ()) {
1336         // only returns additionals of a certain type.
1337         for (auto i : myAttributeCarriers.additionals.at(type)) {
1338             result.push_back(i.second);
1339         }
1340     } else if (GNEAttributeCarrier::getTagProperties(type).isDemandElement() || GNEAttributeCarrier::getTagProperties(type).isStop()) {
1341         // only returns demand elements of a certain type.
1342         for (auto i : myAttributeCarriers.demandElements.at(type)) {
1343             result.push_back(i.second);
1344         }
1345     } else {
1346         // return only a part of elements, depending of type
1347         switch (type) {
1348             case SUMO_TAG_JUNCTION:
1349                 for (auto i : myAttributeCarriers.junctions) {
1350                     result.push_back(i.second);
1351                 }
1352                 break;
1353             case SUMO_TAG_EDGE:
1354                 for (auto i : myAttributeCarriers.edges) {
1355                     result.push_back(i.second);
1356                 }
1357                 break;
1358             case SUMO_TAG_LANE:
1359                 for (auto i : myAttributeCarriers.edges) {
1360                     for (auto j : i.second->getLanes()) {
1361                         result.push_back(j);
1362                     }
1363                 }
1364                 break;
1365             case SUMO_TAG_CONNECTION:
1366                 for (auto i : myAttributeCarriers.edges) {
1367                     for (auto j : i.second->getGNEConnections()) {
1368                         result.push_back(j);
1369                     }
1370                 }
1371                 break;
1372             case SUMO_TAG_CROSSING:
1373                 for (auto i : myAttributeCarriers.junctions) {
1374                     for (auto j : i.second->getGNECrossings()) {
1375                         result.push_back(j);
1376                     }
1377                 }
1378                 break;
1379             case SUMO_TAG_POLY:
1380                 for (auto i : myPolygons) {
1381                     result.push_back(dynamic_cast<GNEPoly*>(i.second));
1382                 }
1383                 break;
1384             case SUMO_TAG_POI:
1385             case SUMO_TAG_POILANE:
1386                 for (auto i : myPOIs) {
1387                     result.push_back(dynamic_cast<GNEPOI*>(i.second));
1388                 }
1389                 break;
1390             default:
1391                 // return nothing
1392                 break;
1393         }
1394     }
1395     return result;
1396 }
1397 
1398 
1399 void
computeEverything(GNEApplicationWindow * window,bool force,bool volatileOptions,std::string additionalPath,std::string demandPath)1400 GNENet::computeEverything(GNEApplicationWindow* window, bool force, bool volatileOptions, std::string additionalPath, std::string demandPath) {
1401     if (!myNeedRecompute) {
1402         if (force) {
1403             if (volatileOptions) {
1404                 window->setStatusBarText("Forced computing junctions with volatile options ...");
1405             } else {
1406                 window->setStatusBarText("Forced computing junctions ...");
1407             }
1408         } else {
1409             return;
1410         }
1411     } else {
1412         if (volatileOptions) {
1413             window->setStatusBarText("Computing junctions with volatile options ...");
1414         } else {
1415             window->setStatusBarText("Computing junctions  ...");
1416         }
1417     }
1418     // save current number of lanes for every edge if recomputing is with volatile options
1419     if (volatileOptions) {
1420         for (auto it : myAttributeCarriers.edges) {
1421             myEdgesAndNumberOfLanes[it.second->getID()] = (int)it.second->getLanes().size();
1422         }
1423     }
1424 
1425     // compute and update
1426     OptionsCont& oc = OptionsCont::getOptions();
1427     computeAndUpdate(oc, volatileOptions);
1428 
1429     // load additionals if was recomputed with volatile options
1430     if (additionalPath != "") {
1431         // fill additionals with tags
1432         auto listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL, false);
1433         for (auto i : listOfTags) {
1434             myAttributeCarriers.additionals.insert(std::make_pair(i, std::map<std::string, GNEAdditional*>()));
1435         }
1436         listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_TAZ, false);
1437         for (auto i : listOfTags) {
1438             myAttributeCarriers.additionals.insert(std::make_pair(i, std::map<std::string, GNEAdditional*>()));
1439         }
1440         // Create additional handler
1441         GNEAdditionalHandler additionalHandler(additionalPath, myViewNet, false);
1442         // Run parser
1443         if (!XMLSubSys::runParser(additionalHandler, additionalPath, false)) {
1444             WRITE_MESSAGE("Loading of " + additionalPath + " failed.");
1445         } else {
1446             // update view
1447             update();
1448         }
1449         // clear myEdgesAndNumberOfLanes after reload additionals
1450         myEdgesAndNumberOfLanes.clear();
1451     }
1452     // load demand elements if was recomputed with volatile options
1453     if (demandPath != "") {
1454         // fill demandElements with tags
1455         auto listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_DEMANDELEMENT, false);
1456         for (auto i : listOfTags) {
1457             myAttributeCarriers.demandElements.insert(std::make_pair(i, std::map<std::string, GNEDemandElement*>()));
1458         }
1459         listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_STOP, false);
1460         for (auto i : listOfTags) {
1461             myAttributeCarriers.demandElements.insert(std::make_pair(i, std::map<std::string, GNEDemandElement*>()));
1462         }
1463         // Create demandElement handler
1464         GNERouteHandler demandElementHandler(demandPath, myViewNet, false);
1465         // Run parser
1466         if (!XMLSubSys::runParser(demandElementHandler, demandPath, false)) {
1467             WRITE_MESSAGE("Loading of " + demandPath + " failed.");
1468         } else {
1469             // update view
1470             update();
1471         }
1472         // clear myEdgesAndNumberOfLanes after reload demandElements
1473         myEdgesAndNumberOfLanes.clear();
1474     }
1475     window->getApp()->endWaitCursor();
1476     window->setStatusBarText("Finished computing junctions.");
1477 }
1478 
1479 
1480 void
updateGeometryDemandElements()1481 GNENet::updateGeometryDemandElements() {
1482     for (const auto& i : myAttributeCarriers.demandElements) {
1483         for (const auto& j : i.second) {
1484             j.second->updateGeometry(true);
1485         }
1486     }
1487 }
1488 
1489 
1490 void
computeJunction(GNEJunction * junction)1491 GNENet::computeJunction(GNEJunction* junction) {
1492     // recompute tl-logics
1493     OptionsCont& oc = OptionsCont::getOptions();
1494     NBTrafficLightLogicCont& tllCont = getTLLogicCont();
1495     // iterate over traffic lights definitions. Make a copy because invalid
1496     // definitions will be removed (and would otherwise destroy the iterator)
1497     const std::set<NBTrafficLightDefinition*> tlsDefs = junction->getNBNode()->getControllingTLS();
1498     for (auto it : tlsDefs) {
1499         it->setParticipantsInformation();
1500         it->setTLControllingInformation();
1501         tllCont.computeSingleLogic(oc, it);
1502     }
1503 
1504     // @todo compute connections etc...
1505 }
1506 
1507 
1508 void
requireRecompute()1509 GNENet::requireRecompute() {
1510     myNeedRecompute = true;
1511 }
1512 
1513 
1514 bool
netHasGNECrossings() const1515 GNENet::netHasGNECrossings() const {
1516     for (auto n : myAttributeCarriers.junctions) {
1517         if (n.second->getGNECrossings().size() > 0) {
1518             return true;
1519         }
1520     }
1521     return false;
1522 }
1523 
1524 
1525 FXApp*
getApp()1526 GNENet::getApp() {
1527     return myViewNet->getApp();
1528 }
1529 
1530 
1531 NBNetBuilder*
getNetBuilder() const1532 GNENet::getNetBuilder() const {
1533     return myNetBuilder;
1534 }
1535 
1536 
1537 bool
joinSelectedJunctions(GNEUndoList * undoList)1538 GNENet::joinSelectedJunctions(GNEUndoList* undoList) {
1539     std::vector<GNEJunction*> selectedJunctions = retrieveJunctions(true);
1540     if (selectedJunctions.size() < 2) {
1541         return false;
1542     }
1543     EdgeVector allIncoming;
1544     EdgeVector allOutgoing;
1545     std::set<NBNode*, ComparatorIdLess> cluster;
1546     for (auto it : selectedJunctions) {
1547         cluster.insert(it->getNBNode());
1548         const EdgeVector& incoming = it->getNBNode()->getIncomingEdges();
1549         allIncoming.insert(allIncoming.end(), incoming.begin(), incoming.end());
1550         const EdgeVector& outgoing = it->getNBNode()->getOutgoingEdges();
1551         allOutgoing.insert(allOutgoing.end(), outgoing.begin(), outgoing.end());
1552     }
1553     // create new junction
1554     Position pos;
1555     Position oldPos;
1556     bool setTL;
1557     std::string id = "cluster";
1558     TrafficLightType type;
1559     SumoXMLNodeType nodeType = NODETYPE_UNKNOWN;
1560     myNetBuilder->getNodeCont().analyzeCluster(cluster, id, pos, setTL, type, nodeType);
1561     // save position
1562     oldPos = pos;
1563 
1564     // Check that there isn't another junction in the same position as Pos but doesn't belong to cluster
1565     for (auto i : myAttributeCarriers.junctions) {
1566         if ((i.second->getPositionInView() == pos) && (cluster.find(i.second->getNBNode()) == cluster.end())) {
1567             // show warning in gui testing debug mode
1568             WRITE_DEBUG("Opening FXMessageBox 'Join non-selected junction'");
1569             // Ask confirmation to user
1570             FXuint answer = FXMessageBox::question(getApp(), MBOX_YES_NO,
1571                                                    ("Position of joined " + toString(SUMO_TAG_JUNCTION)).c_str(), "%s",
1572                                                    ("There is another unselected " + toString(SUMO_TAG_JUNCTION) + " in the same position of joined " + toString(SUMO_TAG_JUNCTION) +
1573                                                     + ".\nIt will be joined with the other selected " + toString(SUMO_TAG_JUNCTION) + "s. Continue?").c_str());
1574             if (answer != 1) { // 1:yes, 2:no, 4:esc
1575                 // write warning if netedit is running in testing mode
1576                 if (answer == 2) {
1577                     WRITE_DEBUG("Closed FXMessageBox 'Join non-selected junction' with 'No'");
1578                 } else if (answer == 4) {
1579                     WRITE_DEBUG("Closed FXMessageBox 'Join non-selected junction' with 'ESC'");
1580                 }
1581                 return false;
1582             } else {
1583                 // write warning if netedit is running in testing mode
1584                 WRITE_DEBUG("Closed FXMessageBox 'Join non-selected junction' with 'Yes'");
1585                 // select conflicted junction an join all again
1586                 i.second->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
1587                 return joinSelectedJunctions(undoList);
1588             }
1589         }
1590     }
1591 
1592     // use checkJunctionPosition to avoid conflicts with junction in the same position as others
1593     while (checkJunctionPosition(pos) == false) {
1594         pos.setx(pos.x() + 0.1);
1595         pos.sety(pos.y() + 0.1);
1596     }
1597 
1598     // start with the join selected junctions
1599     undoList->p_begin("Join selected " + toString(SUMO_TAG_JUNCTION) + "s");
1600     GNEJunction* joined = createJunction(pos, undoList);
1601     joined->setAttribute(SUMO_ATTR_TYPE, toString(nodeType), undoList); // i.e. rail crossing
1602     if (setTL) {
1603         joined->setAttribute(SUMO_ATTR_TLTYPE, toString(type), undoList);
1604     }
1605 
1606     // #3128 this is not undone when calling 'undo'
1607     myNetBuilder->getNodeCont().registerJoinedCluster(cluster);
1608 
1609     // first remove all crossing of the involved junctions and edges
1610     // (otherwise edge removal will trigger discarding)
1611     std::vector<NBNode::Crossing> oldCrossings;
1612     for (auto i : selectedJunctions) {
1613         while (i->getGNECrossings().size() > 0) {
1614             GNECrossing* crossing = i->getGNECrossings().front();
1615             oldCrossings.push_back(*crossing->getNBCrossing());
1616             deleteCrossing(crossing, undoList);
1617         }
1618     }
1619 
1620     // preserve old connections
1621     for (auto it : selectedJunctions) {
1622         it->setLogicValid(false, undoList);
1623     }
1624     // remap edges
1625     for (auto it : allIncoming) {
1626         undoList->p_add(new GNEChange_Attribute(myAttributeCarriers.edges[it->getID()], this, SUMO_ATTR_TO, joined->getID()));
1627     }
1628 
1629     EdgeSet edgesWithin;
1630     for (auto it : allOutgoing) {
1631         // delete edges within the cluster
1632         GNEEdge* e = myAttributeCarriers.edges[it->getID()];
1633         assert(e != 0);
1634         if (e->getGNEJunctionDestiny() == joined) {
1635             edgesWithin.insert(it);
1636             deleteEdge(e, undoList, false);
1637         } else {
1638             undoList->p_add(new GNEChange_Attribute(myAttributeCarriers.edges[it->getID()], this, SUMO_ATTR_FROM, joined->getID()));
1639         }
1640     }
1641 
1642     // remap all crossing of the involved junctions and edges
1643     for (auto nbc : oldCrossings) {
1644         bool keep = true;
1645         for (NBEdge* e : nbc.edges) {
1646             if (edgesWithin.count(e) != 0) {
1647                 keep = false;
1648                 break;
1649             }
1650         };
1651         if (keep) {
1652             undoList->add(new GNEChange_Crossing(joined, nbc.edges, nbc.width,
1653                                                  nbc.priority || joined->getNBNode()->isTLControlled(),
1654                                                  nbc.customTLIndex, nbc.customTLIndex2, nbc.customShape,
1655                                                  false, true), true);
1656         }
1657     }
1658 
1659     // delete original junctions
1660     for (auto it : selectedJunctions) {
1661         deleteJunction(it, undoList);
1662     }
1663     joined->setAttribute(SUMO_ATTR_ID, id, undoList);
1664 
1665 
1666     // check if joined junction had to change their original position to avoid errors
1667     if (pos != oldPos) {
1668         joined->setAttribute(SUMO_ATTR_POSITION, toString(oldPos), undoList);
1669     }
1670     undoList->p_end();
1671     return true;
1672 }
1673 
1674 
1675 bool
cleanInvalidCrossings(GNEUndoList * undoList)1676 GNENet::cleanInvalidCrossings(GNEUndoList* undoList) {
1677     // obtain current net's crossings
1678     std::vector<GNECrossing*> myNetCrossings;
1679     for (auto it : myAttributeCarriers.junctions) {
1680         myNetCrossings.reserve(myNetCrossings.size() + it.second->getGNECrossings().size());
1681         myNetCrossings.insert(myNetCrossings.end(), it.second->getGNECrossings().begin(), it.second->getGNECrossings().end());
1682     }
1683     // obtain invalid crossigns
1684     std::vector<GNECrossing*> myInvalidCrossings;
1685     for (auto i = myNetCrossings.begin(); i != myNetCrossings.end(); i++) {
1686         if ((*i)->getNBCrossing()->valid == false) {
1687             myInvalidCrossings.push_back(*i);
1688         }
1689     }
1690 
1691     if (myInvalidCrossings.empty()) {
1692         // show warning in gui testing debug mode
1693         WRITE_DEBUG("Opening FXMessageBox 'No crossing to remove'");
1694         // open a dialog informing that there isn't crossing to remove
1695         FXMessageBox::warning(getApp(), MBOX_OK,
1696                               ("Clear " + toString(SUMO_TAG_CROSSING) + "s").c_str(), "%s",
1697                               ("There is no invalid " + toString(SUMO_TAG_CROSSING) + "s to remove").c_str());
1698         // show warning in gui testing debug mode
1699         WRITE_DEBUG("Closed FXMessageBox 'No crossing to remove' with 'OK'");
1700     } else {
1701         std::string plural = myInvalidCrossings.size() == 1 ? ("") : ("s");
1702         // show warning in gui testing debug mode
1703         WRITE_DEBUG("Opening FXMessageBox 'clear crossings'");
1704         // Ask confirmation to user
1705         FXuint answer = FXMessageBox::question(getApp(), MBOX_YES_NO,
1706                                                ("Clear " + toString(SUMO_TAG_CROSSING) + "s").c_str(), "%s",
1707                                                ("Clear " + toString(SUMO_TAG_CROSSING) + plural + " will be removed. Continue?").c_str());
1708         if (answer != 1) { // 1:yes, 2:no, 4:esc
1709             // write warning if netedit is running in testing mode
1710             if (answer == 2) {
1711                 WRITE_DEBUG("Closed FXMessageBox 'clear crossings' with 'No'");
1712             } else if (answer == 4) {
1713                 WRITE_DEBUG("Closed FXMessageBox 'clear crossings' with 'ESC'");
1714             }
1715         } else {
1716             undoList->p_begin("Clean " + toString(SUMO_TAG_CROSSING) + "s");
1717             for (auto i = myInvalidCrossings.begin(); i != myInvalidCrossings.end(); i++) {
1718                 deleteCrossing((*i), undoList);
1719             }
1720             undoList->p_end();
1721         }
1722     }
1723     return 1;
1724 }
1725 
1726 
1727 void
removeSolitaryJunctions(GNEUndoList * undoList)1728 GNENet::removeSolitaryJunctions(GNEUndoList* undoList) {
1729     undoList->p_begin("Clean " + toString(SUMO_TAG_JUNCTION) + "s");
1730     std::vector<GNEJunction*> toRemove;
1731     for (auto it : myAttributeCarriers.junctions) {
1732         GNEJunction* junction = it.second;
1733         if (junction->getNBNode()->getEdges().size() == 0) {
1734             toRemove.push_back(junction);
1735         }
1736     }
1737     for (auto it : toRemove) {
1738         deleteJunction(it, undoList);
1739     }
1740     undoList->p_end();
1741 }
1742 
1743 
1744 void
replaceJunctionByGeometry(GNEJunction * junction,GNEUndoList * undoList)1745 GNENet::replaceJunctionByGeometry(GNEJunction* junction, GNEUndoList* undoList) {
1746     assert(junction->getNBNode()->checkIsRemovable());
1747     // start operation
1748     undoList->p_begin("Replace junction by geometry");
1749     // obtain Edges to join
1750     std::vector<std::pair<NBEdge*, NBEdge*> > toJoin = junction->getNBNode()->getEdgesToJoin();
1751     // clear connections of junction to replace
1752     clearJunctionConnections(junction, undoList);
1753     // iterate over NBEdges to join
1754     for (auto j : toJoin) {
1755         // obtain GNEEdges
1756         GNEEdge* begin = myAttributeCarriers.edges[j.first->getID()];
1757         GNEEdge* continuation = myAttributeCarriers.edges[j.second->getID()];
1758         // remove connections between the edges
1759         std::vector<NBEdge::Connection> connections = begin->getNBEdge()->getConnections();
1760         for (auto con : connections) {
1761             undoList->add(new GNEChange_Connection(begin, con, false, false), true);
1762         }
1763         // fix shape of replaced edge
1764         PositionVector newShape = begin->getNBEdge()->getInnerGeometry();
1765         if (begin->getNBEdge()->hasDefaultGeometryEndpointAtNode(begin->getNBEdge()->getToNode())) {
1766             newShape.push_back(junction->getNBNode()->getPosition());
1767         } else {
1768             newShape.push_back(begin->getNBEdge()->getGeometry()[-1]);
1769         }
1770         if (continuation->getNBEdge()->hasDefaultGeometryEndpointAtNode(begin->getNBEdge()->getToNode())) {
1771             newShape.push_back_noDoublePos(junction->getNBNode()->getPosition());
1772         } else {
1773             newShape.push_back_noDoublePos(continuation->getNBEdge()->getGeometry()[0]);
1774         }
1775         // replace incoming edge
1776         replaceIncomingEdge(continuation, begin, undoList);
1777 
1778         newShape.append(continuation->getNBEdge()->getInnerGeometry());
1779         begin->setAttribute(GNE_ATTR_SHAPE_END, continuation->getAttribute(GNE_ATTR_SHAPE_END), undoList);
1780         begin->setAttribute(SUMO_ATTR_ENDOFFSET, continuation->getAttribute(SUMO_ATTR_ENDOFFSET), undoList);
1781         begin->setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList);
1782     }
1783     //delete replaced junction
1784     deleteJunction(junction, undoList);
1785     // finish operation
1786     undoList->p_end();
1787 }
1788 
1789 
1790 void
splitJunction(GNEJunction * junction,bool reconnect,GNEUndoList * undoList)1791 GNENet::splitJunction(GNEJunction* junction, bool reconnect, GNEUndoList* undoList) {
1792     std::vector<std::pair<Position, std::string> > endpoints = junction->getNBNode()->getEndPoints();
1793     if (endpoints.size() < 2) {
1794         return;
1795     }
1796     // start operation
1797     undoList->p_begin("Split junction");
1798     // record connections
1799     std::map<GNEEdge*, std::vector<NBEdge::Connection>> straightConnections;
1800     for (GNEEdge* e : junction->getGNEIncomingEdges()) {
1801         for (const auto& c : e->getNBEdge()->getConnections()) {
1802             if (c.fromLane >= 0 && junction->getNBNode()->getDirection(e->getNBEdge(), c.toEdge) == LINKDIR_STRAIGHT) {
1803                 straightConnections[e].push_back(c);
1804             }
1805         };
1806     }
1807     //std::cout << "split junction at endpoints:\n";
1808 
1809     junction->setLogicValid(false, undoList);
1810     for (const auto& pair : endpoints) {
1811         const Position& pos = pair.first;
1812         const std::string& origID = pair.second;
1813         GNEJunction* newJunction = createJunction(pos, undoList);
1814         std::string newID = origID != "" ? origID : newJunction->getID();
1815         // make a copy because the original vectors are modified during iteration
1816         const std::vector<GNEEdge*> incoming = junction->getGNEIncomingEdges();
1817         const std::vector<GNEEdge*> outgoing = junction->getGNEOutgoingEdges();
1818         //std::cout << "  checkEndpoint " << pair.first << " " << pair.second << " newID=" << newID << "\n";
1819         for (GNEEdge* e : incoming) {
1820             //std::cout << "   incoming " << e->getID() << " pos=" << pos << " origTo=" << e->getNBEdge()->getParameter("origTo") << " newID=" << newID << "\n";
1821             if (e->getNBEdge()->getGeometry().back().almostSame(pos) || e->getNBEdge()->getParameter("origTo") == newID) {
1822                 //std::cout << "     match\n";
1823                 undoList->p_add(new GNEChange_Attribute(e, this, SUMO_ATTR_TO, newJunction->getID()));
1824             }
1825         }
1826         for (GNEEdge* e : outgoing) {
1827             //std::cout << "   outgoing " << e->getID() << " pos=" << pos << " origFrom=" << e->getNBEdge()->getParameter("origFrom") << " newID=" << newID << "\n";
1828             if (e->getNBEdge()->getGeometry().front().almostSame(pos) || e->getNBEdge()->getParameter("origFrom") == newID) {
1829                 //std::cout << "     match\n";
1830                 undoList->p_add(new GNEChange_Attribute(e, this, SUMO_ATTR_FROM, newJunction->getID()));
1831             }
1832         }
1833         if (newID != newJunction->getID()) {
1834             if (newJunction->isValid(SUMO_ATTR_ID, newID)) {
1835                 undoList->p_add(new GNEChange_Attribute(newJunction, this, SUMO_ATTR_ID, newID));
1836             } else {
1837                 WRITE_WARNING("Could not rename split node to '" + newID + "'");
1838             }
1839         }
1840     }
1841     // recreate edges from straightConnections
1842     if (reconnect) {
1843         for (const auto& item : straightConnections) {
1844             GNEEdge* in = item.first;
1845             std::map<NBEdge*, GNEEdge*> newEdges;
1846             for (auto& c : item.second) {
1847                 GNEEdge* out = retrieveEdge(c.toEdge->getID());
1848                 GNEEdge* newEdge = nullptr;
1849                 if (in->getGNEJunctionDestiny() == out->getGNEJunctionSource()) {
1850                     continue;
1851                 }
1852                 if (newEdges.count(c.toEdge) == 0) {
1853                     newEdge = createEdge(in->getGNEJunctionDestiny(), out->getGNEJunctionSource(), in, undoList);
1854                     newEdges[c.toEdge] = newEdge;
1855                     newEdge->setAttribute(SUMO_ATTR_NUMLANES, "1", undoList);
1856                 } else {
1857                     newEdge = newEdges[c.toEdge];
1858                     duplicateLane(newEdge->getLanes().back(), undoList, true);
1859                 }
1860                 // copy permissions
1861                 newEdge->getLanes().back()->setAttribute(SUMO_ATTR_ALLOW,
1862                         in->getLanes()[c.fromLane]-> getAttribute(SUMO_ATTR_ALLOW), undoList);
1863             }
1864         }
1865     }
1866 
1867     deleteJunction(junction, undoList);
1868     // finish operation
1869     undoList->p_end();
1870 }
1871 
1872 
1873 
1874 void
clearJunctionConnections(GNEJunction * junction,GNEUndoList * undoList)1875 GNENet::clearJunctionConnections(GNEJunction* junction, GNEUndoList* undoList) {
1876     undoList->p_begin("clear junction connections");
1877     std::vector<GNEConnection*> connections = junction->getGNEConnections();
1878     // Iterate over all connections and clear it
1879     for (auto i : connections) {
1880         deleteConnection(i, undoList);
1881     }
1882     undoList->p_end();
1883 }
1884 
1885 
1886 void
resetJunctionConnections(GNEJunction * junction,GNEUndoList * undoList)1887 GNENet::resetJunctionConnections(GNEJunction* junction, GNEUndoList* undoList) {
1888     undoList->p_begin("reset junction connections");
1889     // first clear connections
1890     clearJunctionConnections(junction, undoList);
1891     // invalidate logic to create new connections in the next recomputing
1892     junction->setLogicValid(false, undoList);
1893     undoList->p_end();
1894 }
1895 
1896 
1897 void
renameEdge(GNEEdge * edge,const std::string & newID)1898 GNENet::renameEdge(GNEEdge* edge, const std::string& newID) {
1899     myAttributeCarriers.edges.erase(edge->getNBEdge()->getID());
1900     myNetBuilder->getEdgeCont().rename(edge->getNBEdge(), newID);
1901     edge->setMicrosimID(newID);
1902     myAttributeCarriers.edges[newID] = edge;
1903     // rename all connections related to this edge
1904     for (auto i : edge->getLanes()) {
1905         i->updateConnectionIDs();
1906     }
1907 }
1908 
1909 
1910 void
changeEdgeEndpoints(GNEEdge * edge,const std::string & newSource,const std::string & newDest)1911 GNENet::changeEdgeEndpoints(GNEEdge* edge, const std::string& newSource, const std::string& newDest) {
1912     NBNode* from = retrieveJunction(newSource)->getNBNode();
1913     NBNode* to = retrieveJunction(newDest)->getNBNode();
1914     edge->getNBEdge()->reinitNodes(from, to);
1915     requireRecompute();
1916     update();
1917 }
1918 
1919 
1920 GNEViewNet*
getViewNet() const1921 GNENet::getViewNet() const {
1922     return myViewNet;
1923 }
1924 
1925 
1926 std::vector<GNEAttributeCarrier*>
getSelectedAttributeCarriers(bool ignoreCurrentSupermode)1927 GNENet::getSelectedAttributeCarriers(bool ignoreCurrentSupermode) {
1928     // declare vector to save result
1929     std::vector<GNEAttributeCarrier*> result;
1930     result.reserve(gSelected.getSelected().size());
1931     // iterate over all elements of global selection
1932     for (auto i : gSelected.getSelected()) {
1933         // obtain AC
1934         GNEAttributeCarrier* AC = retrieveAttributeCarrier(i, false);
1935         // check if attribute carrier exist and is selected
1936         if (AC && AC->isAttributeCarrierSelected()) {
1937             // now check if selected supermode is correct
1938             if (ignoreCurrentSupermode ||
1939                     ((myViewNet->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) && !AC->getTagProperty().isDemandElement()) ||
1940                     ((myViewNet->getEditModes().currentSupermode == GNE_SUPERMODE_DEMAND) && AC->getTagProperty().isDemandElement())) {
1941                 // add it into result vector
1942                 result.push_back(AC);
1943             }
1944         }
1945     }
1946     return result;
1947 }
1948 
1949 
1950 NBTrafficLightLogicCont&
getTLLogicCont()1951 GNENet::getTLLogicCont() {
1952     return myNetBuilder->getTLLogicCont();
1953 }
1954 
1955 
1956 NBEdgeCont&
getEdgeCont()1957 GNENet::getEdgeCont() {
1958     return myNetBuilder->getEdgeCont();
1959 }
1960 
1961 
1962 void
renameJunction(GNEJunction * junction,const std::string & newID)1963 GNENet::renameJunction(GNEJunction* junction, const std::string& newID) {
1964     std::string oldID = junction->getID();
1965     myAttributeCarriers.junctions.erase(junction->getNBNode()->getID());
1966     myNetBuilder->getNodeCont().rename(junction->getNBNode(), newID);
1967     junction->setMicrosimID(newID);
1968     myAttributeCarriers.junctions[newID] = junction;
1969     // build crossings
1970     junction->getNBNode()->buildCrossings();
1971 }
1972 
1973 
1974 void
addExplicitTurnaround(std::string id)1975 GNENet::addExplicitTurnaround(std::string id) {
1976     myExplicitTurnarounds.insert(id);
1977 }
1978 
1979 
1980 void
removeExplicitTurnaround(std::string id)1981 GNENet::removeExplicitTurnaround(std::string id) {
1982     myExplicitTurnarounds.erase(id);
1983 }
1984 
1985 
1986 GNEAdditional*
retrieveAdditional(SumoXMLTag type,const std::string & id,bool hardFail) const1987 GNENet::retrieveAdditional(SumoXMLTag type, const std::string& id, bool hardFail) const {
1988     if ((myAttributeCarriers.additionals.count(type) > 0) && (myAttributeCarriers.additionals.at(type).count(id) != 0)) {
1989         return myAttributeCarriers.additionals.at(type).at(id);
1990     } else if (hardFail) {
1991         throw ProcessError("Attempted to retrieve non-existant additional");
1992     } else {
1993         return nullptr;
1994     }
1995 }
1996 
1997 
1998 std::vector<GNEAdditional*>
retrieveAdditionals(bool onlySelected) const1999 GNENet::retrieveAdditionals(bool onlySelected) const {
2000     std::vector<GNEAdditional*> result;
2001     // returns additionals depending of selection
2002     for (auto i : myAttributeCarriers.additionals) {
2003         for (auto j : i.second) {
2004             if (!onlySelected || j.second->isAttributeCarrierSelected()) {
2005                 result.push_back(j.second);
2006             }
2007         }
2008     }
2009     return result;
2010 }
2011 
2012 
2013 const std::map<std::string, GNEAdditional*>&
getAdditionalByType(SumoXMLTag type) const2014 GNENet::getAdditionalByType(SumoXMLTag type) const {
2015     return myAttributeCarriers.additionals.at(type);
2016 }
2017 
2018 
2019 int
getNumberOfAdditionals(SumoXMLTag type) const2020 GNENet::getNumberOfAdditionals(SumoXMLTag type) const {
2021     int counter = 0;
2022     for (auto i : myAttributeCarriers.additionals) {
2023         if ((type == SUMO_TAG_NOTHING) || (type == i.first)) {
2024             counter += (int)i.second.size();
2025         }
2026     }
2027     return counter;
2028 }
2029 
2030 
2031 void
updateAdditionalID(const std::string & oldID,GNEAdditional * additional)2032 GNENet::updateAdditionalID(const std::string& oldID, GNEAdditional* additional) {
2033     if (myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).count(oldID) == 0) {
2034         throw ProcessError(additional->getTagStr() + " with old ID='" + oldID + "' doesn't exist");
2035     } else {
2036         // remove an insert additional again into container
2037         myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).erase(oldID);
2038         myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).insert(std::make_pair(additional->getID(), additional));
2039         // additionals has to be saved
2040         requiereSaveAdditionals(true);
2041     }
2042 }
2043 
2044 
2045 void
requiereSaveAdditionals(bool value)2046 GNENet::requiereSaveAdditionals(bool value) {
2047     if (myAdditionalsSaved == true) {
2048         WRITE_DEBUG("Additionals has to be saved");
2049         std::string netSaved = (myNetSaved ? "saved" : "unsaved");
2050         std::string demandElementsSaved = (myDemandElementsSaved ? "saved" : "unsaved");
2051         WRITE_DEBUG("Current saving Status: net " + netSaved + ", additionals unsaved, demand elements " + demandElementsSaved);
2052     }
2053     myAdditionalsSaved = !value;
2054     if (myViewNet != nullptr) {
2055         if (myAdditionalsSaved) {
2056             myViewNet->getViewParent()->getGNEAppWindows()->disableSaveAdditionalsMenu();
2057         } else {
2058             myViewNet->getViewParent()->getGNEAppWindows()->enableSaveAdditionalsMenu();
2059         }
2060     }
2061 }
2062 
2063 
2064 void
saveAdditionals(const std::string & filename)2065 GNENet::saveAdditionals(const std::string& filename) {
2066     // obtain invalid additionals depending of number of their lane parents
2067     std::vector<GNEAdditional*> invalidSingleLaneAdditionals;
2068     std::vector<GNEAdditional*> invalidMultiLaneAdditionals;
2069     // iterate over additionals and obtain invalids
2070     for (auto i : myAttributeCarriers.additionals) {
2071         for (auto j : i.second) {
2072             // check if has to be fixed
2073             if (j.second->getTagProperty().hasAttribute(SUMO_ATTR_LANE) && !j.second->isAdditionalValid()) {
2074                 invalidSingleLaneAdditionals.push_back(j.second);
2075             } else if (j.second->getTagProperty().hasAttribute(SUMO_ATTR_LANES) && !j.second->isAdditionalValid()) {
2076                 invalidMultiLaneAdditionals.push_back(j.second);
2077             }
2078         }
2079     }
2080     // if there are invalid StoppingPlaces or detectors, open GNEDialog_FixAdditionalElements
2081     if (invalidSingleLaneAdditionals.size() > 0 || invalidMultiLaneAdditionals.size() > 0) {
2082         // 0 -> Canceled Saving, with or whithout selecting invalid stopping places and E2
2083         // 1 -> Invalid stoppingPlaces and E2 fixed, friendlyPos enabled, or saved with invalid positions
2084         GNEDialog_FixAdditionalElements fixAdditionalElementsDialog(myViewNet, invalidSingleLaneAdditionals, invalidMultiLaneAdditionals);
2085         if (fixAdditionalElementsDialog.execute() == 0) {
2086             // Here a console message
2087             ;
2088         } else {
2089             saveAdditionalsConfirmed(filename);
2090         }
2091         // set focus again in viewNet
2092         myViewNet->setFocus();
2093     } else {
2094         saveAdditionalsConfirmed(filename);
2095     }
2096     // change value of flag
2097     myAdditionalsSaved = true;
2098     // show debug information
2099     WRITE_DEBUG("Additionals saved");
2100 }
2101 
2102 
2103 bool
isAdditionalsSaved() const2104 GNENet::isAdditionalsSaved() const {
2105     return myAdditionalsSaved;
2106 }
2107 
2108 
2109 std::string
generateAdditionalID(SumoXMLTag type) const2110 GNENet::generateAdditionalID(SumoXMLTag type) const {
2111     int counter = 0;
2112     while (myAttributeCarriers.additionals.at(type).count(toString(type) + "_" + toString(counter)) != 0) {
2113         counter++;
2114     }
2115     return (toString(type) + "_" + toString(counter));
2116 }
2117 
2118 
2119 GNEDemandElement*
retrieveDemandElement(SumoXMLTag type,const std::string & id,bool hardFail) const2120 GNENet::retrieveDemandElement(SumoXMLTag type, const std::string& id, bool hardFail) const {
2121     if ((myAttributeCarriers.demandElements.count(type) > 0) && (myAttributeCarriers.demandElements.at(type).count(id) != 0)) {
2122         return myAttributeCarriers.demandElements.at(type).at(id);
2123     } else if (hardFail) {
2124         throw ProcessError("Attempted to retrieve non-existant demand element");
2125     } else {
2126         return nullptr;
2127     }
2128 }
2129 
2130 
2131 std::vector<GNEDemandElement*>
retrieveDemandElements(bool onlySelected) const2132 GNENet::retrieveDemandElements(bool onlySelected) const {
2133     std::vector<GNEDemandElement*> result;
2134     // returns demand elements depending of selection
2135     for (auto i : myAttributeCarriers.demandElements) {
2136         for (auto j : i.second) {
2137             if (!onlySelected || j.second->isAttributeCarrierSelected()) {
2138                 result.push_back(j.second);
2139             }
2140         }
2141     }
2142     return result;
2143 }
2144 
2145 
2146 const std::map<std::string, GNEDemandElement*>&
getDemandElementByType(SumoXMLTag type) const2147 GNENet::getDemandElementByType(SumoXMLTag type) const {
2148     return myAttributeCarriers.demandElements.at(type);
2149 }
2150 
2151 
2152 int
getNumberOfDemandElements(SumoXMLTag type) const2153 GNENet::getNumberOfDemandElements(SumoXMLTag type) const {
2154     int counter = 0;
2155     for (auto i : myAttributeCarriers.demandElements) {
2156         if ((type == SUMO_TAG_NOTHING) || (type == i.first)) {
2157             counter += (int)i.second.size();
2158         }
2159     }
2160     return counter;
2161 }
2162 
2163 
2164 void
updateDemandElementID(const std::string & oldID,GNEDemandElement * demandElement)2165 GNENet::updateDemandElementID(const std::string& oldID, GNEDemandElement* demandElement) {
2166     if (myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).count(oldID) == 0) {
2167         throw ProcessError(demandElement->getTagStr() + " with old ID='" + oldID + "' doesn't exist");
2168     } else {
2169         // remove an insert demand element again into container
2170         myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).erase(oldID);
2171         myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).insert(std::make_pair(demandElement->getID(), demandElement));
2172         // remove an insert demand element again into vehicleDepartures container
2173         if (demandElement->getTagProperty().isVehicle()) {
2174             if (myAttributeCarriers.vehicleDepartures.count(demandElement->getBegin() + "_" + oldID) == 0) {
2175                 throw ProcessError(demandElement->getTagStr() + " with old ID='" + oldID + "' doesn't exist");
2176             } else {
2177                 myAttributeCarriers.vehicleDepartures.erase(demandElement->getBegin() + "_" + oldID);
2178                 myAttributeCarriers.vehicleDepartures.insert(std::make_pair(demandElement->getBegin() + "_" + demandElement->getID(), demandElement));
2179             }
2180         }
2181         // demand elements has to be saved
2182         requiereSaveDemandElements(true);
2183     }
2184 }
2185 
2186 
2187 void
updateDemandElementBegin(const std::string & oldBegin,GNEDemandElement * demandElement)2188 GNENet::updateDemandElementBegin(const std::string& oldBegin, GNEDemandElement* demandElement) {
2189     if (myAttributeCarriers.vehicleDepartures.count(oldBegin + "_" + demandElement->getID()) == 0) {
2190         throw ProcessError(demandElement->getTagStr() + " with old begin='" + oldBegin + "' doesn't exist");
2191     } else {
2192         // remove an insert demand element again into vehicleDepartures container
2193         if (demandElement->getTagProperty().isVehicle()) {
2194             myAttributeCarriers.vehicleDepartures.erase(oldBegin + "_" + demandElement->getID());
2195             myAttributeCarriers.vehicleDepartures.insert(std::make_pair(demandElement->getBegin() + "_" + demandElement->getID(), demandElement));
2196         }
2197     }
2198 }
2199 
2200 
2201 void
requiereSaveDemandElements(bool value)2202 GNENet::requiereSaveDemandElements(bool value) {
2203     if (myDemandElementsSaved == true) {
2204         WRITE_DEBUG("DemandElements has to be saved");
2205         std::string netSaved = (myNetSaved ? "saved" : "unsaved");
2206         std::string additionalsSaved = (myAdditionalsSaved ? "saved" : "unsaved");
2207         WRITE_DEBUG("Current saving Status: net " + netSaved + ", additionals " + additionalsSaved + ", demand elements unsaved");
2208     }
2209     myDemandElementsSaved = !value;
2210     if (myViewNet != nullptr) {
2211         if (myDemandElementsSaved) {
2212             myViewNet->getViewParent()->getGNEAppWindows()->disableSaveDemandElementsMenu();
2213         } else {
2214             myViewNet->getViewParent()->getGNEAppWindows()->enableSaveDemandElementsMenu();
2215         }
2216     }
2217 }
2218 
2219 
2220 void
saveDemandElements(const std::string & filename)2221 GNENet::saveDemandElements(const std::string& filename) {
2222     // obtain invalid demandElements depending of number of their lane parents
2223     std::vector<GNEDemandElement*> invalidSingleLaneDemandElements;
2224     // iterate over demandElements and obtain invalids
2225     for (auto i : myAttributeCarriers.demandElements) {
2226         for (auto j : i.second) {
2227             // check if has to be fixed
2228             if (!j.second->isDemandElementValid()) {
2229                 invalidSingleLaneDemandElements.push_back(j.second);
2230             }
2231         }
2232     }
2233     // if there are invalid StoppingPlaces or detectors, open GNEDialog_FixDemandElementPositions
2234     if (invalidSingleLaneDemandElements.size() > 0) {
2235         // 0 -> Canceled Saving, with or whithout selecting invalid stopping places and E2
2236         // 1 -> Invalid stoppingPlaces and E2 fixed, friendlyPos enabled, or saved with invalid positions
2237         GNEDialog_FixDemandElements fixDemandElementsDialog(myViewNet, invalidSingleLaneDemandElements);
2238         if (fixDemandElementsDialog.execute() == 0) {
2239             // Here a console message
2240             ;
2241         } else {
2242             saveDemandElementsConfirmed(filename);
2243         }
2244         // set focus again in viewNet
2245         myViewNet->setFocus();
2246     } else {
2247         saveDemandElementsConfirmed(filename);
2248     }
2249     // change value of flag
2250     myDemandElementsSaved = true;
2251     // show debug information
2252     WRITE_DEBUG("DemandElements saved");
2253 }
2254 
2255 
2256 bool
isDemandElementsSaved() const2257 GNENet::isDemandElementsSaved() const {
2258     return myDemandElementsSaved;
2259 }
2260 
2261 
2262 std::string
generateDemandElementID(SumoXMLTag type) const2263 GNENet::generateDemandElementID(SumoXMLTag type) const {
2264     int counter = 0;
2265     while (myAttributeCarriers.demandElements.at(type).count(toString(type) + "_" + toString(counter)) != 0) {
2266         counter++;
2267     }
2268     return (toString(type) + "_" + toString(counter));
2269 }
2270 
2271 
2272 void
saveAdditionalsConfirmed(const std::string & filename)2273 GNENet::saveAdditionalsConfirmed(const std::string& filename) {
2274     OutputDevice& device = OutputDevice::getDevice(filename);
2275     device.writeXMLHeader("additional", "additional_file.xsd");
2276     // now write all route probes (see Ticket #4058)
2277     for (auto i : myAttributeCarriers.additionals) {
2278         if (i.first == SUMO_TAG_ROUTEPROBE) {
2279             for (auto j : i.second) {
2280                 j.second->writeAdditional(device);
2281             }
2282         }
2283     }
2284     // now write all stoppingPlaces
2285     for (auto i : myAttributeCarriers.additionals) {
2286         if (GNEAttributeCarrier::getTagProperties(i.first).isStoppingPlace()) {
2287             for (auto j : i.second) {
2288                 // only save stoppingPlaces that doesn't have Additional parents, because they are automatically writed by writeAdditional(...) parent's function
2289                 if (j.second->getAdditionalParents().empty()) {
2290                     j.second->writeAdditional(device);
2291                 }
2292             }
2293         }
2294     }
2295     // now write all detectors
2296     for (auto i : myAttributeCarriers.additionals) {
2297         if (GNEAttributeCarrier::getTagProperties(i.first).isDetector()) {
2298             for (auto j : i.second) {
2299                 // only save Detectors that doesn't have Additional parents, because they are automatically writed by writeAdditional(...) parent's function
2300                 if (j.second->getAdditionalParents().empty()) {
2301                     j.second->writeAdditional(device);
2302                 }
2303             }
2304         }
2305     }
2306     // now write rest of additionals
2307     for (auto i : myAttributeCarriers.additionals) {
2308         const auto& tagValue = GNEAttributeCarrier::getTagProperties(i.first);
2309         if (!tagValue.isStoppingPlace() && !tagValue.isDetector() && (i.first != SUMO_TAG_ROUTEPROBE) && (i.first != SUMO_TAG_VTYPE) && (i.first != SUMO_TAG_ROUTE)) {
2310             for (auto j : i.second) {
2311                 // only save additionals that doesn't have Additional parents, because they are automatically writed by writeAdditional(...) parent's function
2312                 if (j.second->getAdditionalParents().empty()) {
2313                     j.second->writeAdditional(device);
2314                 }
2315             }
2316         }
2317     }
2318     // now write shapes and POIs
2319     for (const auto& i : myPolygons) {
2320         dynamic_cast<GNEShape*>(i.second)->writeShape(device);
2321     }
2322     for (const auto& i : myPOIs) {
2323         dynamic_cast<GNEShape*>(i.second)->writeShape(device);
2324     }
2325     device.close();
2326 }
2327 
2328 
2329 void
saveDemandElementsConfirmed(const std::string & filename)2330 GNENet::saveDemandElementsConfirmed(const std::string& filename) {
2331     OutputDevice& device = OutputDevice::getDevice(filename);
2332     device.writeXMLHeader("routes", "routes_file.xsd");
2333     // first write all routes (and their associated stops)
2334     for (auto i : myAttributeCarriers.demandElements) {
2335         if (i.first == SUMO_TAG_ROUTE) {
2336             for (auto j : i.second) {
2337                 j.second->writeDemandElement(device);
2338             }
2339         }
2340     }
2341     // now  write all vehicle types
2342     for (auto i : myAttributeCarriers.demandElements) {
2343         if (i.first == SUMO_TAG_VTYPE) {
2344             for (auto j : i.second) {
2345                 j.second->writeDemandElement(device);
2346             }
2347         }
2348     }
2349     // finally write all vehicles sorted by depart time (and their associated stops)
2350     for (auto i : myAttributeCarriers.vehicleDepartures) {
2351         i.second->writeDemandElement(device);
2352     }
2353     device.close();
2354 }
2355 
2356 
2357 GNEPoly*
addPolygonForEditShapes(GNENetElement * netElement,const PositionVector & shape,bool fill,RGBColor col)2358 GNENet::addPolygonForEditShapes(GNENetElement* netElement, const PositionVector& shape, bool fill, RGBColor col) {
2359     if (shape.size() > 0) {
2360         // create poly for edit shapes
2361         GNEPoly* shapePoly = new GNEPoly(this, "edit_shape", "edit_shape", shape, false, fill, 0.3, col, GLO_POLYGON, 0, "", false, false, false);
2362         shapePoly->setShapeEditedElement(netElement);
2363         myGrid.addAdditionalGLObject(shapePoly);
2364         myViewNet->update();
2365         return shapePoly;
2366     } else {
2367         throw ProcessError("shape cannot be empty");
2368     }
2369 }
2370 
2371 
2372 void
removePolygonForEditShapes(GNEPoly * polygon)2373 GNENet::removePolygonForEditShapes(GNEPoly* polygon) {
2374     if (polygon) {
2375         // remove it from Inspector Frame
2376         myViewNet->getViewParent()->getInspectorFrame()->getAttributesEditor()->removeEditedAC(polygon);
2377         // Remove from grid
2378         myGrid.removeAdditionalGLObject(polygon);
2379         myViewNet->update();
2380     } else {
2381         throw ProcessError("Polygon for edit shapes has to be inicializated");
2382     }
2383 }
2384 
2385 
2386 std::string
generateShapeID(SumoXMLTag shapeTag) const2387 GNENet::generateShapeID(SumoXMLTag shapeTag) const {
2388     // generate tag depending of type of shape
2389     if (shapeTag == SUMO_TAG_POLY) {
2390         int counter = 0;
2391         std::string newID = "poly_" + toString(counter);
2392         // generate new IDs to find a non-assigned ID
2393         while (myPolygons.get(newID) != nullptr) {
2394             counter++;
2395             newID = "poly_" + toString(counter);
2396         }
2397         return newID;
2398     } else {
2399         int counter = 0;
2400         std::string newID = "POI_" + toString(counter);
2401         // generate new IDs to find a non-assigned ID
2402         while (myPOIs.get(newID) != nullptr) {
2403             counter++;
2404             newID = "POI_" + toString(counter);
2405         }
2406         return newID;
2407     }
2408 }
2409 
2410 
2411 void
changeShapeID(GNEShape * s,const std::string & OldID)2412 GNENet::changeShapeID(GNEShape* s, const std::string& OldID) {
2413     if (s->getTagProperty().getTag() == SUMO_TAG_POLY) {
2414         if (myPolygons.get(OldID) == 0) {
2415             throw UnknownElement("Polygon " + OldID);
2416         } else {
2417             myPolygons.changeID(OldID, s->getID());
2418         }
2419     } else {
2420         if (myPOIs.get(OldID) == 0) {
2421             throw UnknownElement("POI " + OldID);
2422         } else {
2423             myPOIs.changeID(OldID, s->getID());
2424         }
2425     }
2426 }
2427 
2428 
2429 int
getNumberOfShapes() const2430 GNENet::getNumberOfShapes() const {
2431     return (int)(myPolygons.size() + myPOIs.size());
2432 }
2433 
2434 
2435 void
requiereSaveTLSPrograms()2436 GNENet::requiereSaveTLSPrograms() {
2437     if (myTLSProgramsSaved == true) {
2438         WRITE_DEBUG("TLSPrograms has to be saved");
2439     }
2440     myTLSProgramsSaved = false;
2441     myViewNet->getViewParent()->getGNEAppWindows()->enableSaveTLSProgramsMenu();
2442 }
2443 
2444 
2445 void
saveTLSPrograms(const std::string & filename)2446 GNENet::saveTLSPrograms(const std::string& filename) {
2447     // open output device
2448     OutputDevice& device = OutputDevice::getDevice(filename);
2449     device.openTag("additionals");
2450     // write traffic lights using NWWriter
2451     NWWriter_SUMO::writeTrafficLights(device, getTLLogicCont());
2452     device.close();
2453     // change flag to true
2454     myTLSProgramsSaved = true;
2455     // show debug information
2456     WRITE_DEBUG("TLSPrograms saved");
2457 }
2458 
2459 
2460 int
getNumberOfTLSPrograms() const2461 GNENet::getNumberOfTLSPrograms() const {
2462     return -1;
2463 }
2464 
2465 void
enableUpdateGeometry()2466 GNENet::enableUpdateGeometry() {
2467     myUpdateGeometryEnabled = true;
2468 }
2469 
2470 
2471 void
disableUpdateGeometry()2472 GNENet::disableUpdateGeometry() {
2473     myUpdateGeometryEnabled = false;
2474 }
2475 
2476 
2477 bool
isUpdateGeometryEnabled() const2478 GNENet::isUpdateGeometryEnabled() const {
2479     return myUpdateGeometryEnabled;
2480 }
2481 
2482 // ---------------------------------------------------------------------------
2483 // GNENet - protected methods
2484 // ---------------------------------------------------------------------------
2485 
2486 bool
additionalExist(GNEAdditional * additional) const2487 GNENet::additionalExist(GNEAdditional* additional) const {
2488     // first check that additional pointer is valid
2489     if (additional) {
2490         return myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).find(additional->getID()) !=
2491                myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).end();
2492     } else {
2493         throw ProcessError("Invalid additional pointer");
2494     }
2495 }
2496 
2497 
2498 void
insertAdditional(GNEAdditional * additional)2499 GNENet::insertAdditional(GNEAdditional* additional) {
2500     // Check if additional element exists before insertion
2501     if (!additionalExist(additional)) {
2502         myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).insert(std::make_pair(additional->getID(), additional));
2503         // only add drawable elements in grid
2504         if (additional->getTagProperty().isDrawable()) {
2505             myGrid.addAdditionalGLObject(additional);
2506         }
2507         // check if additional is selected
2508         if (additional->isAttributeCarrierSelected()) {
2509             additional->selectAttributeCarrier(false);
2510         }
2511         // update geometry after insertion of additionals if myUpdateGeometryEnabled is enabled
2512         if (myUpdateGeometryEnabled) {
2513             additional->updateGeometry(true);
2514         }
2515         // additionals has to be saved
2516         requiereSaveAdditionals(true);
2517     } else {
2518         throw ProcessError(additional->getTagStr() + " with ID='" + additional->getID() + "' already exist");
2519     }
2520 }
2521 
2522 
2523 bool
deleteAdditional(GNEAdditional * additional,bool updateViewAfterDeleting)2524 GNENet::deleteAdditional(GNEAdditional* additional, bool updateViewAfterDeleting) {
2525     // first check that additional pointer is valid
2526     if (additionalExist(additional)) {
2527         // obtain demand element and erase it from container
2528         auto it = myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).find(additional->getID());
2529         myAttributeCarriers.additionals.at(additional->getTagProperty().getTag()).erase(it);
2530         // remove it from Inspector Frame
2531         myViewNet->getViewParent()->getInspectorFrame()->getAttributesEditor()->removeEditedAC(additional);
2532         // only remove drawable elements of grid
2533         if (additional->getTagProperty().isDrawable()) {
2534             myGrid.removeAdditionalGLObject(additional);
2535         }
2536         // check if additional is selected
2537         if (additional->isAttributeCarrierSelected()) {
2538             additional->unselectAttributeCarrier(false);
2539         }
2540         // check if view has to be updated
2541         if (updateViewAfterDeleting) {
2542             myViewNet->update();
2543         }
2544         // additionals has to be saved
2545         requiereSaveAdditionals(true);
2546         // additional removed, then return true
2547         return true;
2548     } else {
2549         throw ProcessError("Invalid additional pointer");
2550     }
2551 }
2552 
2553 
2554 bool
demandElementExist(GNEDemandElement * demandElement) const2555 GNENet::demandElementExist(GNEDemandElement* demandElement) const {
2556     // first check that demandElement pointer is valid
2557     if (demandElement) {
2558         return myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).find(demandElement->getID()) !=
2559                myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).end();
2560     } else {
2561         throw ProcessError("Invalid demandElement pointer");
2562     }
2563 }
2564 
2565 
2566 void
insertDemandElement(GNEDemandElement * demandElement)2567 GNENet::insertDemandElement(GNEDemandElement* demandElement) {
2568     // Check if demandElement element exists before insertion
2569     if (!demandElementExist(demandElement)) {
2570         // insert in demandElements container
2571         myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).insert(std::make_pair(demandElement->getID(), demandElement));
2572         // also insert in vehicleDepartures container
2573         if (demandElement->getTagProperty().isVehicle()) {
2574             if (myAttributeCarriers.vehicleDepartures.count(demandElement->getBegin() + "_" + demandElement->getID()) != 0) {
2575                 throw ProcessError(demandElement->getTagStr() + " with departure ='" + demandElement->getBegin() + "_" + demandElement->getID() + "' already inserted");
2576             } else {
2577                 myAttributeCarriers.vehicleDepartures.insert(std::make_pair(demandElement->getBegin() + "_" + demandElement->getID(), demandElement));
2578             }
2579         }
2580         // only add drawable elements in grid
2581         if (demandElement->getTagProperty().isDrawable()) {
2582             myGrid.addAdditionalGLObject(demandElement);
2583         }
2584         // check if demandElement is selected
2585         if (demandElement->isAttributeCarrierSelected()) {
2586             demandElement->selectAttributeCarrier(false);
2587         }
2588         // update geometry after insertion of demandElements if myUpdateGeometryEnabled is enabled
2589         if (myUpdateGeometryEnabled) {
2590             demandElement->updateGeometry(true);
2591         }
2592         // demandElements has to be saved
2593         requiereSaveDemandElements(true);
2594     } else {
2595         throw ProcessError(demandElement->getTagStr() + " with ID='" + demandElement->getID() + "' already exist");
2596     }
2597 }
2598 
2599 
2600 bool
deleteDemandElement(GNEDemandElement * demandElement,bool updateViewAfterDeleting)2601 GNENet::deleteDemandElement(GNEDemandElement* demandElement, bool updateViewAfterDeleting) {
2602     // first check that demandElement pointer is valid
2603     if (demandElementExist(demandElement)) {
2604         // obtain demand element and erase it from container
2605         auto it = myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).find(demandElement->getID());
2606         myAttributeCarriers.demandElements.at(demandElement->getTagProperty().getTag()).erase(it);
2607         // remove it from Inspector Frame
2608         myViewNet->getViewParent()->getInspectorFrame()->getAttributesEditor()->removeEditedAC(demandElement);
2609         // also remove fromvehicleDepartures container
2610         if (demandElement->getTagProperty().isVehicle()) {
2611             if (myAttributeCarriers.vehicleDepartures.count(demandElement->getBegin() + "_" + demandElement->getID()) == 0) {
2612                 throw ProcessError(demandElement->getTagStr() + " with departure ='" + demandElement->getBegin() + "_" + demandElement->getID() + "' doesn't exist");
2613             } else {
2614                 myAttributeCarriers.vehicleDepartures.erase(demandElement->getBegin() + "_" + demandElement->getID());
2615             }
2616         }
2617         // only remove drawable elements of grid
2618         if (demandElement->getTagProperty().isDrawable()) {
2619             myGrid.removeAdditionalGLObject(demandElement);
2620         }
2621         // check if demandElement is selected
2622         if (demandElement->isAttributeCarrierSelected()) {
2623             demandElement->unselectAttributeCarrier(false);
2624         }
2625         // check if view has to be updated
2626         if (updateViewAfterDeleting) {
2627             myViewNet->update();
2628         }
2629         // demandElements has to be saved
2630         requiereSaveDemandElements(true);
2631         // demandElement removed, then return true
2632         return true;
2633     } else {
2634         throw ProcessError("Invalid demandElement pointer");
2635     }
2636 }
2637 
2638 // ===========================================================================
2639 // private
2640 // ===========================================================================
2641 
2642 void
initJunctionsAndEdges()2643 GNENet::initJunctionsAndEdges() {
2644     // init junctions (by default Crossing and walking areas aren't created)
2645     NBNodeCont& nodeContainer = myNetBuilder->getNodeCont();
2646     for (auto name_it : nodeContainer.getAllNames()) {
2647         NBNode* nbn = nodeContainer.retrieve(name_it);
2648         registerJunction(new GNEJunction(*nbn, this, true));
2649     }
2650 
2651     // init edges
2652     NBEdgeCont& ec = myNetBuilder->getEdgeCont();
2653     for (auto name_it : ec.getAllNames()) {
2654         NBEdge* nbe = ec.retrieve(name_it);
2655         registerEdge(new GNEEdge(*nbe, this, false, true));
2656         if (myGrid.getWidth() > 10e16 || myGrid.getHeight() > 10e16) {
2657             throw ProcessError("Network size exceeds 1 Lightyear. Please reconsider your inputs.\n");
2658         }
2659     }
2660 
2661     // make sure myGrid is initialized even for an empty net
2662     if (myAttributeCarriers.edges.size() == 0) {
2663         myGrid.add(Boundary(0, 0, 100, 100));
2664     }
2665 
2666     // sort nodes edges so that arrows can be drawn correctly
2667     NBNodesEdgesSorter::sortNodesEdges(nodeContainer);
2668 }
2669 
2670 
2671 void
insertJunction(GNEJunction * junction)2672 GNENet::insertJunction(GNEJunction* junction) {
2673     myNetBuilder->getNodeCont().insert(junction->getNBNode());
2674     registerJunction(junction);
2675 }
2676 
2677 
2678 void
insertEdge(GNEEdge * edge)2679 GNENet::insertEdge(GNEEdge* edge) {
2680     NBEdge* nbe = edge->getNBEdge();
2681     myNetBuilder->getEdgeCont().insert(nbe); // should we ignore pruning double edges?
2682     // if this edge was previouls extracted from the edgeContainer we have to rewire the nodes
2683     nbe->getFromNode()->addOutgoingEdge(nbe);
2684     nbe->getToNode()->addIncomingEdge(nbe);
2685     registerEdge(edge);
2686 }
2687 
2688 
2689 GNEJunction*
registerJunction(GNEJunction * junction)2690 GNENet::registerJunction(GNEJunction* junction) {
2691     // increase reference
2692     junction->incRef("GNENet::registerJunction");
2693     junction->setResponsible(false);
2694     myAttributeCarriers.junctions[junction->getMicrosimID()] = junction;
2695     // add it into grid
2696     myGrid.add(junction->getBoundary());
2697     myGrid.addAdditionalGLObject(junction);
2698     // update geometry
2699     junction->updateGeometry(true);
2700     // check if junction is selected
2701     if (junction->isAttributeCarrierSelected()) {
2702         junction->selectAttributeCarrier(false);
2703     }
2704     // @todo let Boundary class track z-coordinate natively
2705     const double z = junction->getNBNode()->getPosition().z();
2706     if (z != 0) {
2707         myZBoundary.add(z, Z_INITIALIZED);
2708     }
2709     update();
2710     return junction;
2711 }
2712 
2713 
2714 GNEEdge*
registerEdge(GNEEdge * edge)2715 GNENet::registerEdge(GNEEdge* edge) {
2716     edge->incRef("GNENet::registerEdge");
2717     edge->setResponsible(false);
2718     // add edge to internal container of GNENet
2719     myAttributeCarriers.edges[edge->getMicrosimID()] = edge;
2720     // add edge to grid
2721     myGrid.add(edge->getBoundary());
2722     myGrid.addAdditionalGLObject(edge);
2723     // check if edge is selected
2724     if (edge->isAttributeCarrierSelected()) {
2725         edge->selectAttributeCarrier(false);
2726     }
2727     // Add references into GNEJunctions
2728     edge->getGNEJunctionSource()->addOutgoingGNEEdge(edge);
2729     edge->getGNEJunctionDestiny()->addIncomingGNEEdge(edge);
2730     // update view
2731     update();
2732     return edge;
2733 }
2734 
2735 
2736 void
deleteSingleJunction(GNEJunction * junction,bool updateViewAfterDeleting)2737 GNENet::deleteSingleJunction(GNEJunction* junction, bool updateViewAfterDeleting) {
2738     // remove it from Inspector Frame
2739     myViewNet->getViewParent()->getInspectorFrame()->getAttributesEditor()->removeEditedAC(junction);
2740     // Remove from grid and container
2741     myGrid.removeAdditionalGLObject(junction);
2742     // check if junction is selected
2743     if (junction->isAttributeCarrierSelected()) {
2744         junction->unselectAttributeCarrier(false);
2745     }
2746     myAttributeCarriers.junctions.erase(junction->getMicrosimID());
2747     myNetBuilder->getNodeCont().extract(junction->getNBNode());
2748     junction->decRef("GNENet::deleteSingleJunction");
2749     junction->setResponsible(true);
2750     // check if view has to be updated
2751     if (updateViewAfterDeleting) {
2752         myViewNet->update();
2753     }
2754 }
2755 
2756 
2757 void
deleteSingleEdge(GNEEdge * edge,bool updateViewAfterDeleting)2758 GNENet::deleteSingleEdge(GNEEdge* edge, bool updateViewAfterDeleting) {
2759     // remove it from Inspector Frame
2760     myViewNet->getViewParent()->getInspectorFrame()->getAttributesEditor()->removeEditedAC(edge);
2761     // remove edge from visual grid and container
2762     myGrid.removeAdditionalGLObject(edge);
2763     // check if junction is selected
2764     if (edge->isAttributeCarrierSelected()) {
2765         edge->unselectAttributeCarrier(false);
2766     }
2767     myAttributeCarriers.edges.erase(edge->getMicrosimID());
2768     // extract edge of district container
2769     myNetBuilder->getEdgeCont().extract(myNetBuilder->getDistrictCont(), edge->getNBEdge());
2770     edge->decRef("GNENet::deleteSingleEdge");
2771     edge->setResponsible(true);
2772     // Remove refrences from GNEJunctions
2773     edge->getGNEJunctionSource()->removeOutgoingGNEEdge(edge);
2774     edge->getGNEJunctionDestiny()->removeIncomingGNEEdge(edge);
2775     // check if view has to be updated
2776     if (updateViewAfterDeleting) {
2777         myViewNet->update();
2778     }
2779 }
2780 
2781 
2782 void
insertShape(GNEShape * shape,bool updateViewAfterDeleting)2783 GNENet::insertShape(GNEShape* shape, bool updateViewAfterDeleting) {
2784     // add shape depending of their type and if is selected
2785     if (shape->getTagProperty().getTag() == SUMO_TAG_POLY) {
2786         GUIPolygon* poly = dynamic_cast<GUIPolygon*>(shape);
2787         myGrid.addAdditionalGLObject(poly);
2788         myPolygons.add(shape->getID(), poly);
2789     } else {
2790         GUIPointOfInterest* poi = dynamic_cast<GUIPointOfInterest*>(shape);
2791         myGrid.addAdditionalGLObject(poi);
2792         myPOIs.add(shape->getID(), poi);
2793 
2794     }
2795     // check if shape has to be selected
2796     if (shape->isAttributeCarrierSelected()) {
2797         shape->selectAttributeCarrier(false);
2798     }
2799     // insert shape requieres always save additionals
2800     requiereSaveAdditionals(true);
2801     // after inserting, update geometry (needed for POILanes
2802     shape->updateGeometry(true);
2803     // check if view has to be updated
2804     if (updateViewAfterDeleting) {
2805         myViewNet->update();
2806     }
2807 }
2808 
2809 
2810 void
removeShape(GNEShape * shape,bool updateViewAfterDeleting)2811 GNENet::removeShape(GNEShape* shape, bool updateViewAfterDeleting) {
2812     // remove it from Inspector Frame
2813     myViewNet->getViewParent()->getInspectorFrame()->getAttributesEditor()->removeEditedAC(shape);
2814     if (shape->getTagProperty().getTag() == SUMO_TAG_POLY) {
2815         GUIPolygon* poly = dynamic_cast<GUIPolygon*>(shape);
2816         myGrid.removeAdditionalGLObject(poly);
2817         myPolygons.remove(shape->getID(), false);
2818     } else {
2819         GUIPointOfInterest* poi = dynamic_cast<GUIPointOfInterest*>(shape);
2820         myGrid.removeAdditionalGLObject(poi);
2821         myPOIs.remove(shape->getID(), false);
2822     }
2823     // check if shape has to be unselected
2824     if (shape->isAttributeCarrierSelected()) {
2825         shape->unselectAttributeCarrier(false);
2826     }
2827     // remove shape requires always save additionals
2828     requiereSaveAdditionals(true);
2829     // check if view has to be updated
2830     if (updateViewAfterDeleting) {
2831         myViewNet->update();
2832     }
2833 }
2834 
2835 
2836 void
update()2837 GNENet::update() {
2838     if (myViewNet) {
2839         myViewNet->update();
2840     }
2841 }
2842 
2843 
2844 void
reserveEdgeID(const std::string & id)2845 GNENet::reserveEdgeID(const std::string& id) {
2846     myEdgeIDSupplier.avoid(id);
2847 }
2848 
2849 
2850 void
reserveJunctionID(const std::string & id)2851 GNENet::reserveJunctionID(const std::string& id) {
2852     myJunctionIDSupplier.avoid(id);
2853 }
2854 
2855 
2856 void
initGNEConnections()2857 GNENet::initGNEConnections() {
2858     for (const auto& i : myAttributeCarriers.edges) {
2859         // remake connections
2860         i.second->remakeGNEConnections();
2861         // update geometry of connections
2862         for (const auto& j : i.second->getGNEConnections()) {
2863             j->updateGeometry(true);
2864         }
2865     }
2866 }
2867 
2868 
2869 void
computeAndUpdate(OptionsCont & oc,bool volatileOptions)2870 GNENet::computeAndUpdate(OptionsCont& oc, bool volatileOptions) {
2871     // make sure we only add turn arounds to edges which currently exist within the network
2872     std::set<std::string> liveExplicitTurnarounds;
2873     for (auto it : myExplicitTurnarounds) {
2874         if (myAttributeCarriers.edges.count(it) > 0) {
2875             liveExplicitTurnarounds.insert(it);
2876         }
2877     }
2878 
2879     // removes all junctions of grid
2880     for (const auto& it : myAttributeCarriers.junctions) {
2881         myGrid.removeAdditionalGLObject(it.second);
2882     }
2883 
2884     // remove all edges from grid
2885     for (const auto& it : myAttributeCarriers.edges) {
2886         myGrid.removeAdditionalGLObject(it.second);
2887     }
2888 
2889     myNetBuilder->compute(oc, liveExplicitTurnarounds, volatileOptions);
2890     // update ids if necessary
2891     if (oc.getBool("numerical-ids") || oc.isSet("reserved-ids")) {
2892         std::map<std::string, GNEEdge*> newEdgeMap;
2893         std::map<std::string, GNEJunction*> newJunctionMap;
2894         // fill newEdgeMap
2895         for (auto it : myAttributeCarriers.edges) {
2896             it.second->setMicrosimID(it.second->getNBEdge()->getID());
2897             newEdgeMap[it.second->getNBEdge()->getID()] = it.second;
2898         }
2899         for (auto it : myAttributeCarriers.junctions) {
2900             newJunctionMap[it.second->getNBNode()->getID()] = it.second;
2901             it.second->setMicrosimID(it.second->getNBNode()->getID());
2902         }
2903         myAttributeCarriers.edges = newEdgeMap;
2904         myAttributeCarriers.junctions = newJunctionMap;
2905     }
2906     // update rtree if necessary
2907     if (!oc.getBool("offset.disable-normalization")) {
2908         for (auto it : myAttributeCarriers.edges) {
2909             // refresh edge geometry
2910             it.second->updateGeometry(true);
2911         }
2912     }
2913     // Clear current inspected ACs in inspectorFrame if a previous net was loaded
2914     if (myViewNet != nullptr) {
2915         myViewNet->getViewParent()->getInspectorFrame()->clearInspectedAC();
2916     }
2917     // Remove from container
2918     myGrid.reset();
2919     myGrid.add(GeoConvHelper::getFinal().getConvBoundary());
2920 
2921     // if volatile options are true
2922     if (volatileOptions) {
2923         assert(myViewNet != 0);
2924 
2925         // clear undo list (This will be remove additionals and shapes)
2926         myViewNet->getUndoList()->clear();
2927 
2928         // remove all edges of net (It was already removed from grid)
2929         auto copyOfEdges = myAttributeCarriers.edges;
2930         for (auto it : copyOfEdges) {
2931             myAttributeCarriers.edges.erase(it.second->getMicrosimID());
2932         }
2933 
2934         // removes all junctions of net  (It was already removed from grid)
2935         auto copyOfJunctions = myAttributeCarriers.junctions;
2936         for (auto it : copyOfJunctions) {
2937             myAttributeCarriers.junctions.erase(it.second->getMicrosimID());
2938         }
2939 
2940         // clear rest of additional that weren't removed during cleaning of undo list
2941         for (const auto& it : myAttributeCarriers.additionals) {
2942             for (const auto& j : it.second) {
2943                 // only remove drawable additionals
2944                 if (j.second->getTagProperty().isDrawable()) {
2945                     myGrid.removeAdditionalGLObject(j.second);
2946                 }
2947             }
2948         }
2949         myAttributeCarriers.additionals.clear();
2950         // fill additionals with tags (note: this include the TAZS)
2951         auto listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL, false);
2952         for (auto i : listOfTags) {
2953             myAttributeCarriers.additionals.insert(std::make_pair(i, std::map<std::string, GNEAdditional*>()));
2954         }
2955         listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_TAZ, false);
2956         for (auto i : listOfTags) {
2957             myAttributeCarriers.additionals.insert(std::make_pair(i, std::map<std::string, GNEAdditional*>()));
2958         }
2959 
2960         // clear rest of polygons that weren't removed during cleaning of undo list
2961         for (const auto& it : myPolygons) {
2962             myGrid.removeAdditionalGLObject(dynamic_cast<GUIGlObject*>(it.second));
2963         }
2964         myPolygons.clear();
2965 
2966         // clear rest of POIs that weren't removed during cleaning of undo list
2967         for (const auto& it : myPOIs) {
2968             myGrid.removeAdditionalGLObject(dynamic_cast<GUIGlObject*>(it.second));
2969         }
2970         myPOIs.clear();
2971 
2972         // clear rest of demand elements that weren't removed during cleaning of undo list
2973         for (const auto& it : myAttributeCarriers.demandElements) {
2974             for (const auto& j : it.second) {
2975                 // only remove drawable additionals
2976                 if (j.second->getTagProperty().isDrawable()) {
2977                     myGrid.removeAdditionalGLObject(j.second);
2978                 }
2979             }
2980         }
2981         myAttributeCarriers.additionals.clear();
2982         // fill demand elements with tags
2983         listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_DEMANDELEMENT, false);
2984         for (auto i : listOfTags) {
2985             myAttributeCarriers.demandElements.insert(std::make_pair(i, std::map<std::string, GNEDemandElement*>()));
2986         }
2987         listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_STOP, false);
2988         for (auto i : listOfTags) {
2989             myAttributeCarriers.demandElements.insert(std::make_pair(i, std::map<std::string, GNEDemandElement*>()));
2990         }
2991 
2992         // init again junction an edges (Additionals and shapes will be loaded after the end of this function)
2993         initJunctionsAndEdges();
2994 
2995     } else {
2996         // remake connections
2997         for (auto it : myAttributeCarriers.edges) {
2998             it.second->remakeGNEConnections();
2999         }
3000 
3001         // iterate over junctions of net
3002         for (const auto& it : myAttributeCarriers.junctions) {
3003             // undolist may not yet exist but is also not needed when just marking junctions as valid
3004             it.second->setLogicValid(true, nullptr);
3005             // insert junction in grid again
3006             myGrid.addAdditionalGLObject(it.second);
3007             // updated geometry
3008             it.second->updateGeometry(true);
3009         }
3010 
3011         // iterate over all edges of net
3012         for (const auto& it : myAttributeCarriers.edges) {
3013             // insert edge in grid again
3014             myGrid.addAdditionalGLObject(it.second);
3015             // update geometry
3016             it.second->updateGeometry(true);
3017         }
3018     }
3019 
3020     // net recomputed, then return false;
3021     myNeedRecompute = false;
3022 }
3023 
3024 
3025 void
replaceInListAttribute(GNEAttributeCarrier * ac,SumoXMLAttr key,const std::string & which,const std::string & by,GNEUndoList * undoList)3026 GNENet::replaceInListAttribute(GNEAttributeCarrier* ac, SumoXMLAttr key, const std::string& which, const std::string& by, GNEUndoList* undoList) {
3027     assert(ac->getTagProperty().getAttributeProperties(key).isList());
3028     std::vector<std::string> values = GNEAttributeCarrier::parse<std::vector<std::string> >(ac->getAttribute(key));
3029     std::vector<std::string> newValues;
3030     for (auto v : values) {
3031         newValues.push_back(v == which ? by : v);
3032     }
3033     ac->setAttribute(key, toString(newValues), undoList);
3034 }
3035 
3036 /****************************************************************************/
3037