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