Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/GNENet.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GNENet.cpp
15
/// @author Jakob Erdmann
16
/// @date Feb 2011
17
///
18
// A visual container for GNE-network-components such as GNEEdge and GNEJunction.
19
// GNE components wrap netbuild-components and supply visualisation and editing
20
// capabilities (adapted from GUINet)
21
//
22
// WorkrouteFlow (rough draft)
23
// use NILoader to fill
24
// do netedit stuff
25
// call compute to save results
26
//
27
/****************************************************************************/
28
29
#include <netbuild/NBAlgorithms.h>
30
#include <netbuild/NBNetBuilder.h>
31
#include <netedit/GNETagProperties.h>
32
#include <netedit/dialogs/basic/GNEWarningBasicDialog.h>
33
#include <netedit/dialogs/basic/GNEQuestionBasicDialog.h>
34
#include <netedit/changes/GNEChange_Additional.h>
35
#include <netedit/changes/GNEChange_Attribute.h>
36
#include <netedit/changes/GNEChange_Connection.h>
37
#include <netedit/changes/GNEChange_Crossing.h>
38
#include <netedit/changes/GNEChange_DataInterval.h>
39
#include <netedit/changes/GNEChange_DataSet.h>
40
#include <netedit/changes/GNEChange_DemandElement.h>
41
#include <netedit/changes/GNEChange_Edge.h>
42
#include <netedit/changes/GNEChange_GenericData.h>
43
#include <netedit/changes/GNEChange_Junction.h>
44
#include <netedit/changes/GNEChange_Lane.h>
45
#include <netedit/changes/GNEChange_MeanData.h>
46
#include <netedit/changes/GNEChange_RegisterJoin.h>
47
#include <netedit/changes/GNEChange_TAZSourceSink.h>
48
#include <netedit/dialogs/fix/GNEFixAdditionalElementsDialog.h>
49
#include <netedit/dialogs/fix/GNEFixDemandElementsDialog.h>
50
#include <netedit/elements/GNEGeneralHandler.h>
51
#include <netedit/elements/data/GNEDataHandler.h>
52
#include <netedit/elements/data/GNEDataInterval.h>
53
#include <netedit/elements/data/GNEMeanData.h>
54
#include <netedit/elements/network/GNEConnection.h>
55
#include <netedit/elements/network/GNECrossing.h>
56
#include <netedit/elements/network/GNEEdgeTemplate.h>
57
#include <netedit/elements/network/GNEEdgeType.h>
58
#include <netedit/elements/network/GNELaneType.h>
59
#include <netedit/frames/common/GNEInspectorFrame.h>
60
#include <netwrite/NWFrame.h>
61
#include <netwrite/NWWriter_SUMO.h>
62
#include <netwrite/NWWriter_XML.h>
63
#include <utils/common/StringTokenizer.h>
64
#include <utils/gui/div/GLHelper.h>
65
#include <utils/gui/div/GUIDesigns.h>
66
#include <utils/gui/div/GUIParameterTableWindow.h>
67
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
68
#include <utils/gui/globjects/GUIGlObjectStorage.h>
69
70
#include "GNEApplicationWindow.h"
71
#include "GNENet.h"
72
#include "GNEUndoList.h"
73
#include "GNEViewParent.h"
74
75
// ===========================================================================
76
// FOX callback mapping
77
// ===========================================================================
78
79
FXIMPLEMENT_ABSTRACT(GNENetHelper::GNEChange_ReplaceEdgeInTLS, GNEChange, nullptr, 0)
80
81
// ===========================================================================
82
// static members
83
// ===========================================================================
84
const double GNENet::Z_INITIALIZED = 1;
85
const std::map<SumoXMLAttr, std::string> GNENet::EMPTY_HEADER;
86
87
88
// ===========================================================================
89
// member method definitions
90
// ===========================================================================
91
#ifdef _MSC_VER
92
#pragma warning(push)
93
#pragma warning(disable: 4355) // mask warning about "this" in initializers
94
#endif
95
GNENet::GNENet(NBNetBuilder* netBuilder, const GNETagPropertiesDatabase* tagPropertiesDatabase) :
96
GUIGlObject(GLO_NETWORK, "", nullptr),
97
myNetBuilder(netBuilder),
98
myTagPropertiesDatabase(tagPropertiesDatabase),
99
myAttributeCarriers(new GNENetHelper::AttributeCarriers(this)),
100
myACTemplates(new GNENetHelper::ACTemplate(this)),
101
mySavingFilesHandler(new GNENetHelper::SavingFilesHandler(this)),
102
mySavingStatus(new GNENetHelper::SavingStatus(this)),
103
myNetworkPathManager(new GNEPathManager(this)),
104
myDemandPathManager(new GNEPathManager(this)),
105
myDataPathManager(new GNEPathManager(this)) {
106
// set net in gIDStorage
107
GUIGlObjectStorage::gIDStorage.setNetObject(this);
108
// build templates
109
myACTemplates->buildTemplates();
110
// init junction and edges
111
initJunctionsAndEdges();
112
// check Z boundary
113
if (myZBoundary.ymin() != Z_INITIALIZED) {
114
myZBoundary.add(0, 0);
115
}
116
117
}
118
#ifdef _MSC_VER
119
#pragma warning(pop)
120
#endif
121
122
123
GNENet::~GNENet() {
124
// delete path managers
125
delete myNetworkPathManager;
126
delete myDemandPathManager;
127
delete myDataPathManager;
128
// delete attribute carriers
129
delete myAttributeCarriers;
130
delete myACTemplates;
131
// delete saving status
132
delete mySavingStatus;
133
delete myNetBuilder;
134
}
135
136
137
const GNETagPropertiesDatabase*
138
GNENet::getTagPropertiesDatabase() const {
139
return myTagPropertiesDatabase;
140
}
141
142
143
GNENetHelper::AttributeCarriers*
144
GNENet::getAttributeCarriers() const {
145
return myAttributeCarriers;
146
}
147
148
149
GNENetHelper::ACTemplate*
150
GNENet::getACTemplates() const {
151
return myACTemplates;
152
}
153
154
155
GNENetHelper::SavingFilesHandler*
156
GNENet::getSavingFilesHandler() const {
157
return mySavingFilesHandler;
158
}
159
160
161
GNENetHelper::SavingStatus*
162
GNENet::getSavingStatus() const {
163
return mySavingStatus;
164
}
165
166
167
GNEPathManager*
168
GNENet::getNetworkPathManager() {
169
return myNetworkPathManager;
170
}
171
172
173
GNEPathManager*
174
GNENet::getDemandPathManager() {
175
return myDemandPathManager;
176
}
177
178
179
GNEPathManager*
180
GNENet::getDataPathManager() {
181
return myDataPathManager;
182
}
183
184
185
const Boundary&
186
GNENet::getBoundary() const {
187
// SUMORTree is also a Boundary
188
return myGrid;
189
}
190
191
192
SUMORTree&
193
GNENet::getGrid() {
194
return myGrid;
195
}
196
197
const std::map<std::string, int>&
198
GNENet::getEdgesAndNumberOfLanes() const {
199
return myEdgesAndNumberOfLanes;
200
}
201
202
203
GUIGLObjectPopupMenu*
204
GNENet::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
205
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
206
buildPopupHeader(ret, app);
207
buildCenterPopupEntry(ret);
208
buildPositionCopyEntry(ret, app);
209
if (GeoConvHelper::getFinal().usingGeoProjection()) {
210
GUIDesigns::buildFXMenuCommand(ret, TL("Copy view geo-boundary to clipboard"), nullptr, ret, MID_COPY_VIEW_GEOBOUNDARY);
211
}
212
return ret;
213
}
214
215
216
GUIParameterTableWindow*
217
GNENet::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
218
// Nets lanes don't have attributes
219
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
220
// close building
221
ret->closeBuilding();
222
return ret;
223
}
224
225
226
void
227
GNENet::drawGL(const GUIVisualizationSettings& s) const {
228
// draw boundaries
229
GLHelper::drawBoundary(s, getCenteringBoundary());
230
}
231
232
233
Boundary
234
GNENet::getCenteringBoundary() const {
235
return getBoundary();
236
}
237
238
239
void
240
GNENet::expandBoundary(const Boundary& newBoundary) {
241
myGrid.add(newBoundary);
242
}
243
244
245
const Boundary&
246
GNENet::getZBoundary() const {
247
return myZBoundary;
248
}
249
250
251
void
252
GNENet::addZValueInBoundary(const double z) {
253
// @todo let Boundary class track z-coordinate natively
254
if (z != 0) {
255
myZBoundary.add(z, Z_INITIALIZED);
256
}
257
}
258
259
260
GNEJunction*
261
GNENet::createJunction(const Position& pos, GNEUndoList* undoList) {
262
// get junction prefix
263
const std::string junctionPrefix = OptionsCont::getOptions().getString("prefix") + OptionsCont::getOptions().getString("node-prefix");
264
// generate new ID
265
while (myAttributeCarriers->getJunctions().count(junctionPrefix + toString(myJunctionIDCounter)) != 0) {
266
myJunctionIDCounter++;
267
}
268
// create new NBNode
269
NBNode* nbn = new NBNode(junctionPrefix + toString(myJunctionIDCounter), pos);
270
GNEJunction* junction = new GNEJunction(this, nbn);
271
undoList->add(new GNEChange_Junction(junction, true), true);
272
return junction;
273
}
274
275
276
GNEEdge*
277
GNENet::createEdge(GNEJunction* src, GNEJunction* dest, GNEEdge* edgeTemplate, GNEUndoList* undoList,
278
const std::string& suggestedName, bool wasSplit, bool allowDuplicateGeom, bool recomputeConnections) {
279
// prevent duplicate edge (same geometry)
280
for (const auto& outgoingEdge : src->getNBNode()->getOutgoingEdges()) {
281
if (outgoingEdge->getToNode() == dest->getNBNode() && outgoingEdge->getGeometry().size() == 2) {
282
if (!allowDuplicateGeom) {
283
return nullptr;
284
}
285
}
286
}
287
// check if exist opposite edge
288
const auto oppositeEdges = myAttributeCarriers->retrieveEdges(dest, src);
289
// get edge prefix
290
const std::string edgePrefix = OptionsCont::getOptions().getString("prefix") + OptionsCont::getOptions().getString("edge-prefix");
291
// get edge infix
292
std::string edgeInfix = OptionsCont::getOptions().getString("edge-infix");
293
// declare edge id
294
std::string edgeID;
295
// update id
296
if (oppositeEdges.size() > 0) {
297
// avoid ids with "--..."
298
if ((oppositeEdges.front()->getID().size() > 1) && (oppositeEdges.front()->getID().front() == '-')) {
299
edgeID = oppositeEdges.front()->getID().substr(1);
300
} else {
301
edgeID = "-" + oppositeEdges.front()->getID();
302
}
303
// check if already exist an edge with edgeID
304
if (myAttributeCarriers->getEdges().count(edgeID) > 0) {
305
int counter = 0;
306
// generate new ID using edgeID and counter
307
while (myAttributeCarriers->getEdges().count(edgeID + toString(counter)) > 0) {
308
counter++;
309
}
310
edgeID = edgeID + toString(counter);
311
}
312
} else if ((suggestedName.size() > 0) && (myAttributeCarriers->retrieveEdge(suggestedName, false) == nullptr)) {
313
edgeID = suggestedName;
314
} else if (edgeInfix.size() > 0) {
315
// permit empty infix by setting it to <SPACE>
316
edgeInfix = StringUtils::trim(edgeInfix);
317
// check if exist edge with id <fromNodeID><infix><toNodeID>
318
if (myAttributeCarriers->getEdges().count(src->getID() + edgeInfix + dest->getID()) == 0) {
319
edgeID = src->getID() + edgeInfix + dest->getID();
320
} else {
321
int counter = 0;
322
// generate new ID using edgeInfix and counter
323
while (myAttributeCarriers->getEdges().count(src->getID() + edgeInfix + toString(counter) + dest->getID()) != 0) {
324
myEdgeIDCounter++;
325
}
326
edgeID = src->getID() + edgeInfix + toString(counter) + dest->getID();
327
}
328
} else {
329
edgeID = myAttributeCarriers->generateEdgeID();
330
}
331
GNEEdge* edge;
332
// check if there is a template edge
333
if (edgeTemplate) {
334
// create NBEdgeTemplate
335
NBEdge* nbe = new NBEdge(edgeID, src->getNBNode(), dest->getNBNode(), edgeTemplate->getNBEdge());
336
edge = new GNEEdge(this, nbe, wasSplit);
337
} else {
338
// default if no template is given
339
const auto& neteditOptions = OptionsCont::getOptions();
340
double defaultSpeed = neteditOptions.getFloat("default.speed");
341
const std::string defaultType = neteditOptions.getString("default.type");
342
const int defaultNrLanes = neteditOptions.getInt("default.lanenumber");
343
const int defaultPriority = neteditOptions.getInt("default.priority");
344
const double defaultWidth = NBEdge::UNSPECIFIED_WIDTH;
345
const double defaultOffset = NBEdge::UNSPECIFIED_OFFSET;
346
const LaneSpreadFunction spread = LaneSpreadFunction::RIGHT;
347
// build NBEdge
348
NBEdge* nbe = new NBEdge(edgeID, src->getNBNode(), dest->getNBNode(),
349
defaultType, defaultSpeed, NBEdge::UNSPECIFIED_FRICTION,
350
defaultNrLanes, defaultPriority,
351
defaultWidth, defaultOffset, spread);
352
// create edge
353
edge = new GNEEdge(this, nbe, wasSplit);
354
}
355
// add edge using undo list
356
undoList->begin(edge, TL("create edge"));
357
undoList->add(new GNEChange_Edge(edge, true), true);
358
// recompute connection
359
if (recomputeConnections) {
360
src->setLogicValid(false, undoList);
361
dest->setLogicValid(false, undoList);
362
}
363
requireRecompute();
364
undoList->end();
365
return edge;
366
}
367
368
369
void
370
GNENet::deleteNetworkElement(GNENetworkElement* networkElement, GNEUndoList* undoList) {
371
if (networkElement->getTagProperty()->getTag() == SUMO_TAG_JUNCTION) {
372
// get junction (note: could be already removed if is a child, then hardfail=false)
373
GNEJunction* junction = myAttributeCarriers->retrieveJunction(networkElement->getID(), false);
374
// if exist, remove it
375
if (junction) {
376
deleteJunction(junction, undoList);
377
}
378
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_CROSSING) {
379
// get crossing (note: could be already removed if is a child, then hardfail=false)
380
GNECrossing* crossing = myAttributeCarriers->retrieveCrossing(networkElement->getGUIGlObject(), false);
381
// if exist, remove it
382
if (crossing) {
383
deleteCrossing(crossing, undoList);
384
}
385
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_EDGE) {
386
// get edge (note: could be already removed if is a child, then hardfail=false)
387
GNEEdge* edge = myAttributeCarriers->retrieveEdge(networkElement->getID(), false);
388
// if exist, remove it
389
if (edge) {
390
deleteEdge(edge, undoList, false);
391
}
392
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_LANE) {
393
// get lane (note: could be already removed if is a child, then hardfail=false)
394
GNELane* lane = myAttributeCarriers->retrieveLane(networkElement->getGUIGlObject(), false);
395
// if exist, remove it
396
if (lane) {
397
deleteLane(lane, undoList, false);
398
}
399
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_CONNECTION) {
400
// get connection (note: could be already removed if is a child, then hardfail=false)
401
GNEConnection* connection = myAttributeCarriers->retrieveConnection(networkElement->getGUIGlObject(), false);
402
// if exist, remove it
403
if (connection) {
404
deleteConnection(connection, undoList);
405
}
406
}
407
}
408
409
410
void
411
GNENet::deleteJunction(GNEJunction* junction, GNEUndoList* undoList) {
412
// we have to delete all incident edges because they cannot exist without that junction
413
// all deletions must be undone/redone together so we start a new command group
414
// @todo if any of those edges are dead-ends should we remove their orphan junctions as well?
415
undoList->begin(GUIIcon::MODEDELETE, TL("delete junction"));
416
// invalidate junction path elements
417
myNetworkPathManager->invalidateJunctionPath(junction);
418
myDemandPathManager->invalidateJunctionPath(junction);
419
myDataPathManager->invalidateJunctionPath(junction);
420
// delete junction child demand elements
421
while (junction->getChildDemandElements().size() > 0) {
422
deleteDemandElement(junction->getChildDemandElements().front(), undoList);
423
}
424
// delete all crossings vinculated with junction
425
while (junction->getGNECrossings().size() > 0) {
426
deleteCrossing(junction->getGNECrossings().front(), undoList);
427
}
428
// find all crossings of neighbour junctions that shares an edge of this junction
429
std::vector<GNECrossing*> crossingsToRemove;
430
std::vector<GNEJunction*> junctionNeighbours = junction->getJunctionNeighbours();
431
for (const auto& junctionNeighbour : junctionNeighbours) {
432
// iterate over crossing of neighbour junction
433
for (const auto& crossing : junctionNeighbour->getGNECrossings()) {
434
// if at least one of the edges of junction to remove belongs to a crossing of the neighbour junction, delete it
435
if (crossing->checkEdgeBelong(junction->getChildEdges())) {
436
crossingsToRemove.push_back(crossing);
437
}
438
}
439
}
440
// delete collected crossings
441
for (const auto& crossing : crossingsToRemove) {
442
deleteCrossing(crossing, undoList);
443
}
444
// deleting edges changes in the underlying EdgeVector so we have to make a copy
445
const EdgeVector incidentEdges = junction->getNBNode()->getEdges();
446
for (const auto& edge : incidentEdges) {
447
deleteEdge(myAttributeCarriers->getEdges().at(edge->getID()), undoList, true);
448
}
449
// remove any traffic lights from the traffic light container (avoids lots of warnings)
450
junction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), undoList);
451
// delete edge
452
undoList->add(new GNEChange_Junction(junction, false), true);
453
undoList->end();
454
}
455
456
457
void
458
GNENet::deleteEdge(GNEEdge* edge, GNEUndoList* undoList, bool recomputeConnections) {
459
undoList->begin(GUIIcon::MODEDELETE, TL("delete edge"));
460
// iterate over lanes
461
for (const auto& lane : edge->getChildLanes()) {
462
// invalidate lane path elements
463
myNetworkPathManager->invalidateLanePath(lane);
464
myDemandPathManager->invalidateLanePath(lane);
465
myDataPathManager->invalidateLanePath(lane);
466
// delete lane additionals
467
while (lane->getChildAdditionals().size() > 0) {
468
deleteAdditional(lane->getChildAdditionals().front(), undoList);
469
}
470
// delete lane demand elements
471
while (lane->getChildDemandElements().size() > 0) {
472
deleteDemandElement(lane->getChildDemandElements().front(), undoList);
473
}
474
// delete lane generic data elements
475
while (lane->getChildGenericDatas().size() > 0) {
476
deleteGenericData(lane->getChildGenericDatas().front(), undoList);
477
}
478
}
479
// delete edge child additionals
480
while (edge->getChildAdditionals().size() > 0) {
481
deleteAdditional(edge->getChildAdditionals().front(), undoList);
482
}
483
// delete TAZSourceSink children
484
while (edge->getChildTAZSourceSinks().size() > 0) {
485
deleteTAZSourceSink(*edge->getChildTAZSourceSinks().begin(), undoList);
486
}
487
// delete edge child demand elements
488
while (edge->getChildDemandElements().size() > 0) {
489
// special case for embedded routes
490
if (edge->getChildDemandElements().front()->getTagProperty()->getTag() == GNE_TAG_ROUTE_EMBEDDED) {
491
deleteDemandElement(edge->getChildDemandElements().front()->getParentDemandElements().front(), undoList);
492
} else if (edge->getChildDemandElements().front()->getTagProperty()->isPlan()) {
493
const auto planParent = edge->getChildDemandElements().front()->getParentDemandElements().front();
494
// if this is the last person child, remove plan parent (person/container) instead plan element
495
if (planParent->getChildDemandElements().size() == 1) {
496
deleteDemandElement(planParent, undoList);
497
} else {
498
deleteDemandElement(edge->getChildDemandElements().front(), undoList);
499
}
500
} else {
501
deleteDemandElement(edge->getChildDemandElements().front(), undoList);
502
}
503
}
504
// delete edge child generic datas
505
while (edge->getChildGenericDatas().size() > 0) {
506
deleteGenericData(edge->getChildGenericDatas().front(), undoList);
507
}
508
// remove edge from crossings related with this edge
509
edge->getFromJunction()->removeEdgeFromCrossings(edge, undoList);
510
edge->getToJunction()->removeEdgeFromCrossings(edge, undoList);
511
// update affected connections
512
if (recomputeConnections) {
513
edge->getFromJunction()->setLogicValid(false, undoList);
514
edge->getToJunction()->setLogicValid(false, undoList);
515
} else {
516
edge->getFromJunction()->removeConnectionsTo(edge, undoList, true);
517
edge->getToJunction()->removeConnectionsFrom(edge, undoList, true);
518
}
519
// if junction source is a TLS and after deletion will have only an edge, remove TLS
520
if (edge->getFromJunction()->getNBNode()->isTLControlled() && (edge->getFromJunction()->getGNEOutgoingEdges().size() <= 1)) {
521
edge->getFromJunction()->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), undoList);
522
}
523
// if junction destination is a TLS and after deletion will have only an edge, remove TLS
524
if (edge->getToJunction()->getNBNode()->isTLControlled() && (edge->getToJunction()->getGNEIncomingEdges().size() <= 1)) {
525
edge->getToJunction()->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), undoList);
526
}
527
const std::string oppLaneID = edge->getChildLanes().back()->getAttribute(GNE_ATTR_OPPOSITE);
528
if (oppLaneID != "") {
529
GNELane* lane = myAttributeCarriers->retrieveLane(oppLaneID, false);
530
if (lane != nullptr) {
531
lane->setAttribute(GNE_ATTR_OPPOSITE, "", undoList);
532
}
533
}
534
// Delete edge
535
undoList->add(new GNEChange_Edge(edge, false), true);
536
// remove edge requires always a recompute (due geometry and connections)
537
requireRecompute();
538
// finish delete edge
539
undoList->end();
540
}
541
542
543
void
544
GNENet::replaceIncomingEdge(GNEEdge* which, GNEEdge* by, GNEUndoList* undoList) {
545
undoList->begin(which, TL("replace edge"));
546
GNEChange_Attribute::changeAttribute(by, SUMO_ATTR_TO, which->getAttribute(SUMO_ATTR_TO), undoList);
547
// iterate over lane
548
for (const auto& lane : which->getChildLanes()) {
549
// replace in additionals
550
std::vector<GNEAdditional*> copyOfLaneAdditionals = lane->getChildAdditionals();
551
for (const auto& additional : copyOfLaneAdditionals) {
552
GNEChange_Attribute::changeAttribute(additional, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(lane->getIndex()), undoList);
553
if (additional->hasAttribute(SUMO_ATTR_STARTPOS)) {
554
GNEChange_Attribute::changeAttribute(additional, SUMO_ATTR_STARTPOS,
555
toString(StringUtils::toDouble(additional->getAttribute(SUMO_ATTR_STARTPOS)) + which->getNBEdge()->getFinalLength()),
556
undoList);
557
}
558
if (additional->hasAttribute(SUMO_ATTR_ENDPOS)) {
559
GNEChange_Attribute::changeAttribute(additional, SUMO_ATTR_ENDPOS,
560
toString(StringUtils::toDouble(additional->getAttribute(SUMO_ATTR_ENDPOS)) + which->getNBEdge()->getFinalLength()),
561
undoList);
562
}
563
}
564
// replace in demand elements
565
std::vector<GNEDemandElement*> copyOfLaneDemandElements = lane->getChildDemandElements();
566
for (const auto& demandElement : copyOfLaneDemandElements) {
567
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(lane->getIndex()), undoList);
568
}
569
// replace in generic datas
570
std::vector<GNEGenericData*> copyOfLaneGenericDatas = lane->getChildGenericDatas();
571
for (const auto& demandElement : copyOfLaneGenericDatas) {
572
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(lane->getIndex()), undoList);
573
}
574
}
575
// replace in edge additionals children
576
std::vector<GNEAdditional*> addElements = which->getChildAdditionals();
577
for (GNEAdditional* add : addElements) {
578
if (add->hasAttribute(SUMO_ATTR_EDGE)) {
579
GNEChange_Attribute::changeAttribute(add, SUMO_ATTR_EDGE, by->getID(), undoList);
580
}
581
}
582
// replace in edge demand elements children
583
const std::vector<GNEDemandElement*> demandElements = which->getChildDemandElements();
584
for (GNEDemandElement* demandElement : demandElements) {
585
if (demandElement->hasAttribute(SUMO_ATTR_EDGE)) {
586
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_EDGE, by->getID(), undoList);
587
}
588
if (demandElement->hasAttribute(SUMO_ATTR_EDGES)) {
589
replaceInListAttribute(demandElement, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
590
}
591
if (demandElement->hasAttribute(SUMO_ATTR_VIA)) {
592
replaceInListAttribute(demandElement, SUMO_ATTR_VIA, which->getID(), by->getID(), undoList);
593
}
594
if (demandElement->hasAttribute(SUMO_ATTR_FROM) && demandElement->getAttribute(SUMO_ATTR_FROM) == which->getID()) {
595
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_FROM, by->getID(), undoList);
596
}
597
if (demandElement->hasAttribute(SUMO_ATTR_TO) && demandElement->getAttribute(SUMO_ATTR_TO) == which->getID()) {
598
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_TO, by->getID(), undoList);
599
}
600
}
601
// replace in data
602
const std::vector<GNEGenericData*> dataElements = which->getChildGenericDatas();
603
for (GNEGenericData* dataElement : dataElements) {
604
if (dataElement->hasAttribute(SUMO_ATTR_EDGE)) {
605
GNEChange_Attribute::changeAttribute(dataElement, SUMO_ATTR_EDGE, by->getID(), undoList);
606
}
607
}
608
// replace in rerouters
609
addElements = which->getParentAdditionals();
610
for (GNEAdditional* add : addElements) {
611
if (add->hasAttribute(SUMO_ATTR_EDGES)) {
612
replaceInListAttribute(add, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
613
}
614
}
615
// replace in crossings
616
for (const auto& crossing : which->getToJunction()->getGNECrossings()) {
617
// if at least one of the edges of junction to remove belongs to a crossing of the source junction, delete it
618
replaceInListAttribute(crossing, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
619
}
620
// fix connections (make a copy because they will be modified
621
std::vector<NBEdge::Connection> NBConnections = which->getNBEdge()->getConnections();
622
for (const auto& NBConnection : NBConnections) {
623
if (NBConnection.toEdge != nullptr) {
624
undoList->add(new GNEChange_Connection(which, NBConnection, false, false), true);
625
undoList->add(new GNEChange_Connection(by, NBConnection, false, true), true);
626
}
627
}
628
undoList->add(new GNENetHelper::GNEChange_ReplaceEdgeInTLS(getTLLogicCont(), which->getNBEdge(), by->getNBEdge()), true);
629
// Delete edge
630
undoList->add(new GNEChange_Edge(which, false), true);
631
// finish replace edge
632
undoList->end();
633
}
634
635
636
void
637
GNENet::deleteLane(GNELane* lane, GNEUndoList* undoList, bool recomputeConnections) {
638
GNEEdge* edge = lane->getParentEdge();
639
if (edge->getNBEdge()->getNumLanes() == 1) {
640
// remove the whole edge instead
641
deleteEdge(edge, undoList, recomputeConnections);
642
} else {
643
undoList->begin(GUIIcon::MODEDELETE, TL("delete lane"));
644
// invalidate lane path elements
645
myNetworkPathManager->invalidateLanePath(lane);
646
myDemandPathManager->invalidateLanePath(lane);
647
myDataPathManager->invalidateLanePath(lane);
648
// delete lane additional children
649
while (lane->getChildAdditionals().size() > 0) {
650
deleteAdditional(lane->getChildAdditionals().front(), undoList);
651
}
652
// delete lane demand element children
653
while (lane->getChildDemandElements().size() > 0) {
654
deleteDemandElement(lane->getChildDemandElements().front(), undoList);
655
}
656
// delete lane generic data children
657
while (lane->getChildGenericDatas().size() > 0) {
658
deleteGenericData(lane->getChildGenericDatas().front(), undoList);
659
}
660
// update affected connections
661
if (recomputeConnections) {
662
edge->getFromJunction()->setLogicValid(false, undoList);
663
edge->getToJunction()->setLogicValid(false, undoList);
664
} else {
665
edge->getFromJunction()->removeConnectionsTo(edge, undoList, true, lane->getIndex());
666
edge->getToJunction()->removeConnectionsFrom(edge, undoList, true, lane->getIndex());
667
}
668
// delete lane
669
const NBEdge::Lane& laneAttrs = edge->getNBEdge()->getLaneStruct(lane->getIndex());
670
undoList->add(new GNEChange_Lane(edge, lane, laneAttrs, false, recomputeConnections), true);
671
// remove lane requires always a recompute (due geometry and connections)
672
requireRecompute();
673
undoList->end();
674
}
675
}
676
677
678
void
679
GNENet::deleteConnection(GNEConnection* connection, GNEUndoList* undoList) {
680
undoList->begin(GUIIcon::MODEDELETE, TL("delete connection"));
681
// obtain NBConnection to remove
682
NBConnection deleted = connection->getNBConnection();
683
GNEJunction* junctionDestination = connection->getEdgeFrom()->getToJunction();
684
junctionDestination->markAsModified(undoList);
685
undoList->add(new GNEChange_Connection(connection->getEdgeFrom(), connection->getNBEdgeConnection(), connection->isAttributeCarrierSelected(), false), true);
686
junctionDestination->invalidateTLS(undoList, deleted);
687
// remove connection requires always a recompute (due geometry and connections)
688
requireRecompute();
689
undoList->end();
690
}
691
692
693
void
694
GNENet::deleteCrossing(GNECrossing* crossing, GNEUndoList* undoList) {
695
undoList->begin(GUIIcon::MODEDELETE, TL("delete crossing"));
696
// remove it using GNEChange_Crossing
697
undoList->add(new GNEChange_Crossing(
698
crossing->getParentJunctions().front(), crossing->getNBCrossing()->edges,
699
crossing->getNBCrossing()->width, crossing->getNBCrossing()->priority,
700
crossing->getNBCrossing()->customTLIndex,
701
crossing->getNBCrossing()->customTLIndex2,
702
crossing->getNBCrossing()->customShape,
703
crossing->isAttributeCarrierSelected(),
704
false), true);
705
// remove crossing requires always a recompute (due geometry and connections)
706
requireRecompute();
707
undoList->end();
708
}
709
710
711
void
712
GNENet::deleteAdditional(GNEAdditional* additional, GNEUndoList* undoList) {
713
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + additional->getTagStr());
714
// remove all demand element children
715
while (additional->getChildDemandElements().size() > 0) {
716
deleteDemandElement(additional->getChildDemandElements().front(), undoList);
717
}
718
// remove all generic data children
719
while (additional->getChildGenericDatas().size() > 0) {
720
deleteGenericData(additional->getChildGenericDatas().front(), undoList);
721
}
722
// remove all additional children
723
while (additional->getChildAdditionals().size() > 0) {
724
deleteAdditional(additional->getChildAdditionals().front(), undoList);
725
}
726
// remove all TAZSourceSinks children
727
while (additional->getChildTAZSourceSinks().size() > 0) {
728
deleteTAZSourceSink(*additional->getChildTAZSourceSinks().begin(), undoList);
729
}
730
// remove additional
731
undoList->add(new GNEChange_Additional(additional, false), true);
732
undoList->end();
733
}
734
735
736
void
737
GNENet::deleteTAZSourceSink(GNETAZSourceSink* TAZSourceSink, GNEUndoList* undoList) {
738
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + TAZSourceSink->getTagStr());
739
// remove additional
740
undoList->add(new GNEChange_TAZSourceSink(TAZSourceSink, false), true);
741
undoList->end();
742
}
743
744
745
void
746
GNENet::deleteDemandElement(GNEDemandElement* demandElement, GNEUndoList* undoList) {
747
// check that default VTypes aren't removed
748
if ((demandElement->getTagProperty()->getTag() == SUMO_TAG_VTYPE) && (GNEAttributeCarrier::parse<bool>(demandElement->getAttribute(GNE_ATTR_DEFAULT_VTYPE)))) {
749
throw ProcessError(TL("Trying to delete a default Vehicle Type"));
750
} else {
751
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + demandElement->getTagStr());
752
// remove all child additional elements of this demandElement calling this function recursively
753
while (demandElement->getChildAdditionals().size() > 0) {
754
deleteAdditional(demandElement->getChildAdditionals().front(), undoList);
755
}
756
// remove all child demand elements of this demandElement calling this function recursively
757
while (demandElement->getChildDemandElements().size() > 0) {
758
deleteDemandElement(demandElement->getChildDemandElements().front(), undoList);
759
}
760
// remove all generic data children of this additional deleteGenericData this function recursively
761
while (demandElement->getChildGenericDatas().size() > 0) {
762
deleteGenericData(demandElement->getChildGenericDatas().front(), undoList);
763
}
764
// remove demandElement
765
undoList->add(new GNEChange_DemandElement(demandElement, false), true);
766
undoList->end();
767
}
768
}
769
770
771
void
772
GNENet::deleteDataSet(GNEDataSet* dataSet, GNEUndoList* undoList) {
773
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + dataSet->getTagStr());
774
// make a copy of all generic data children
775
auto copyOfDataIntervalChildren = dataSet->getDataIntervalChildren();
776
// clear all data intervals (this will be delete also the dataSet)
777
for (const auto& dataInterval : copyOfDataIntervalChildren) {
778
deleteDataInterval(dataInterval.second, undoList);
779
}
780
undoList->end();
781
}
782
783
784
void
785
GNENet::deleteDataInterval(GNEDataInterval* dataInterval, GNEUndoList* undoList) {
786
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + dataInterval->getTagStr());
787
// make a copy of all generic data children
788
auto copyOfGenericDataChildren = dataInterval->getGenericDataChildren();
789
// clear all generic datas (this will be delete also the data intervals)
790
for (const auto& genericData : copyOfGenericDataChildren) {
791
deleteGenericData(genericData, undoList);
792
}
793
undoList->end();
794
}
795
796
797
void
798
GNENet::deleteGenericData(GNEGenericData* genericData, GNEUndoList* undoList) {
799
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + genericData->getTagStr());
800
// remove all child demand elements of this demandElement calling this function recursively
801
while (genericData->getChildDemandElements().size() > 0) {
802
deleteDemandElement(genericData->getChildDemandElements().front(), undoList);
803
}
804
// remove all generic data children of this additional deleteGenericData this function recursively
805
while (genericData->getChildGenericDatas().size() > 0) {
806
deleteGenericData(genericData->getChildGenericDatas().front(), undoList);
807
}
808
// get pointer to dataInterval and dataSet
809
GNEDataInterval* dataInterval = genericData->getDataIntervalParent();
810
GNEDataSet* dataSet = dataInterval->getDataSetParent();
811
// remove generic data
812
undoList->add(new GNEChange_GenericData(genericData, false), true);
813
// check if data interval is empty
814
if (dataInterval->getGenericDataChildren().empty()) {
815
// remove data interval
816
undoList->add(new GNEChange_DataInterval(genericData->getDataIntervalParent(), false), true);
817
// now check if data set is empty
818
if (dataSet->getDataIntervalChildren().empty()) {
819
// remove data set
820
undoList->add(new GNEChange_DataSet(genericData->getDataIntervalParent()->getDataSetParent(), false), true);
821
}
822
}
823
undoList->end();
824
}
825
826
827
void
828
GNENet::deleteMeanData(GNEMeanData* meanData, GNEUndoList* undoList) {
829
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + meanData->getTagStr());
830
// remove mean data
831
undoList->add(new GNEChange_MeanData(meanData, false), true);
832
undoList->end();
833
}
834
835
836
void
837
GNENet::duplicateLane(GNELane* lane, GNEUndoList* undoList, bool recomputeConnections) {
838
undoList->begin(lane, TL("duplicate lane"));
839
GNEEdge* edge = lane->getParentEdge();
840
const NBEdge::Lane& laneAttrs = edge->getNBEdge()->getLaneStruct(lane->getIndex());
841
if (recomputeConnections) {
842
edge->getFromJunction()->setLogicValid(false, undoList);
843
edge->getToJunction()->setLogicValid(false, undoList);
844
}
845
GNELane* newLane = new GNELane(edge, lane->getIndex());
846
undoList->add(new GNEChange_Lane(edge, newLane, laneAttrs, true, recomputeConnections), true);
847
requireRecompute();
848
undoList->end();
849
}
850
851
852
bool
853
GNENet::restrictLane(SUMOVehicleClass vclass, GNELane* lane, GNEUndoList* undoList) {
854
bool addRestriction = true;
855
if (vclass == SVC_PEDESTRIAN) {
856
GNEEdge* edge = lane->getParentEdge();
857
for (const auto& edgeLane : edge->getChildLanes()) {
858
if (edgeLane->isRestricted(SVC_PEDESTRIAN)) {
859
// prevent adding a 2nd sidewalk
860
addRestriction = false;
861
} else {
862
// ensure that the sidewalk is used exclusively
863
const SVCPermissions allOldWithoutPeds = edge->getNBEdge()->getPermissions(edgeLane->getIndex()) & ~SVC_PEDESTRIAN;
864
edgeLane->setAttribute(SUMO_ATTR_ALLOW, getVehicleClassNames(allOldWithoutPeds), undoList);
865
}
866
}
867
}
868
// restrict the lane
869
if (addRestriction) {
870
double width;
871
if (vclass == SVC_PEDESTRIAN) {
872
width = OptionsCont::getOptions().getFloat("default.sidewalk-width");
873
} else if (vclass == SVC_BICYCLE) {
874
width = OptionsCont::getOptions().getFloat("default.bikelane-width");
875
} else {
876
width = OptionsCont::getOptions().getFloat("default.lanewidth");
877
}
878
lane->setAttribute(SUMO_ATTR_ALLOW, toString(vclass), undoList);
879
lane->setAttribute(SUMO_ATTR_WIDTH, toString(width), undoList);
880
if ((vclass & ~SVC_PEDESTRIAN) == 0) {
881
std::vector<GNEConnection*> cons;
882
const bool reguess = lane->getParentEdge()->getNBEdge()->getStep() <= NBEdge::EdgeBuildingStep::LANES2LANES_RECHECK;
883
if (reguess) {
884
// remove all connections and rebuild from scratch
885
cons = lane->getParentEdge()->getGNEConnections();
886
} else {
887
// remove connections that have become invalid (pedestrians are
888
// connected via walkingareas somewhere else)
889
cons = lane->getGNEOutcomingConnections();
890
}
891
for (auto c : cons) {
892
undoList->add(new GNEChange_Connection(lane->getParentEdge(), c->getNBEdgeConnection(), false, false), true);
893
}
894
if (reguess) {
895
GNEChange_Attribute::changeAttribute(lane->getParentEdge(), GNE_ATTR_MODIFICATION_STATUS, GNEAttributeCarrier::FEATURE_GUESSED, undoList, true);
896
}
897
}
898
return true;
899
} else {
900
return false;
901
}
902
}
903
904
905
bool
906
GNENet::addRestrictedLane(SUMOVehicleClass vclass, GNEEdge* edge, int index, GNEUndoList* undoList) {
907
// First check that edge don't have a restricted lane of the given vclass
908
for (const auto& lane : edge->getChildLanes()) {
909
if (lane->isRestricted(vclass)) {
910
return false;
911
}
912
}
913
// check that index is correct (index == size adds to the left of the leftmost lane)
914
const int numLanes = (int)edge->getChildLanes().size();
915
if (index > numLanes) {
916
return false;
917
}
918
if (index < 0) {
919
// for pedestrians and greenVerge, always index 0
920
index = 0;
921
// guess index from vclass
922
if (vclass == SVC_BICYCLE) {
923
// add bikelanes to the left of an existing sidewalk
924
index = edge->getChildLanes()[0]->isRestricted(SVC_PEDESTRIAN) ? 1 : 0;
925
} else if (vclass == SVC_BUS) {
926
// add greenVerge to the left of an existing sidewalk or bikeLane
927
// add busLane to the left of an existing sidewalk, bikeLane or greenVerge
928
index = 0;
929
while (index < numLanes && (edge->getNBEdge()->getPermissions(index) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) {
930
index++;
931
}
932
}
933
}
934
// duplicate selected lane
935
duplicateLane(edge->getChildLanes().at(MIN2(index, numLanes - 1)), undoList, true);
936
// transform the created lane
937
return restrictLane(vclass, edge->getChildLanes().at(index), undoList);
938
}
939
940
941
bool
942
GNENet::addGreenVergeLane(GNEEdge* edge, int index, GNEUndoList* undoList) {
943
// check that index is correct (index == size adds to the left of the leftmost lane)
944
const int numLanes = (int)edge->getChildLanes().size();
945
if (index > numLanes) {
946
index = numLanes;
947
}
948
if (index < 0) {
949
index = 0;
950
}
951
// duplicate selected lane
952
duplicateLane(edge->getChildLanes().at(MIN2(index, numLanes - 1)), undoList, true);
953
// transform the created lane
954
return restrictLane(SVC_IGNORING, edge->getChildLanes().at(index), undoList);
955
}
956
957
958
bool
959
GNENet::removeRestrictedLane(SUMOVehicleClass vclass, GNEEdge* edge, GNEUndoList* undoList) {
960
// iterate over lanes of edge
961
for (const auto& lane : edge->getChildLanes()) {
962
if (lane->isRestricted(vclass)) {
963
// Delete lane
964
deleteLane(lane, undoList, true);
965
return true;
966
}
967
}
968
return false;
969
}
970
971
972
std::pair<GNEJunction*, GNEEdge*>
973
GNENet::splitEdge(GNEEdge* edge, const Position& pos, GNEUndoList* undoList, GNEJunction* newJunction) {
974
// begin undo list
975
undoList->begin(edge, TL("split edge"));
976
// check if we have to create a new edge
977
if (newJunction == nullptr) {
978
newJunction = createJunction(pos, undoList);
979
}
980
// obtain edge geometry and split position
981
const PositionVector& oldEdgeGeometry = edge->getNBEdge()->getGeometry();
982
const double edgeSplitPosition = oldEdgeGeometry.nearest_offset_to_point2D(pos, false);
983
// obtain lane geometry and split position (needed for adjust additional and demand childs)
984
const PositionVector& oldLaneGeometry = edge->getChildLanes().front()->getLaneShape();
985
const double laneSplitPosition = oldLaneGeometry.nearest_offset_to_point2D(pos, false);
986
// split edge geometry in two new geometries using edgeSplitPosition
987
std::pair<PositionVector, PositionVector> newGeoms = oldEdgeGeometry.splitAt(edgeSplitPosition);
988
const double oldLength = oldEdgeGeometry.length();
989
const double relativeLength1 = oldLength != 0 ? newGeoms.first.length() / oldLength : 1;
990
const double relativeLength2 = oldLength != 0 ? newGeoms.second.length() / oldLength : 1;
991
// get shape end
992
const std::string shapeEnd = edge->getAttribute(GNE_ATTR_SHAPE_END);
993
// figure out the new name
994
int posBase = 0;
995
// set baseName
996
std::string baseName = edge->getMicrosimID();
997
if (edge->wasSplit()) {
998
const std::string::size_type sep_index = baseName.rfind('.');
999
// edge may have been renamed in between
1000
if (sep_index != std::string::npos) {
1001
std::string posString = baseName.substr(sep_index + 1);
1002
if (GNEAttributeCarrier::canParse<int>(posString.c_str())) {
1003
;
1004
posBase = GNEAttributeCarrier::parse<int>(posString.c_str());
1005
baseName = baseName.substr(0, sep_index); // includes the .
1006
}
1007
}
1008
}
1009
baseName += '.';
1010
// create a new edge from the new junction to the previous destination
1011
GNEEdge* secondPart = createEdge(newJunction, edge->getToJunction(), edge,
1012
undoList, baseName + toString(posBase + (int)edgeSplitPosition), true, false, false);
1013
// fix connections from the split edge (must happen before changing SUMO_ATTR_TO)
1014
edge->getToJunction()->replaceIncomingConnections(edge, secondPart, undoList);
1015
// remove affected crossings from junction (must happen before changing SUMO_ATTR_TO)
1016
std::vector<NBNode::Crossing> affectedCrossings;
1017
for (GNECrossing* crossing : edge->getToJunction()->getGNECrossings()) {
1018
if (crossing->checkEdgeBelong(edge)) {
1019
NBNode::Crossing nbC = *crossing->getNBCrossing();
1020
undoList->add(new GNEChange_Crossing(edge->getToJunction(), nbC, false), true);
1021
EdgeVector newEdges;
1022
for (NBEdge* nbEdge : nbC.edges) {
1023
if (nbEdge == edge->getNBEdge()) {
1024
newEdges.push_back(secondPart->getNBEdge());
1025
} else {
1026
newEdges.push_back(nbEdge);
1027
}
1028
}
1029
nbC.edges = newEdges;
1030
affectedCrossings.push_back(nbC);
1031
}
1032
}
1033
// modify the edge so that it ends at the new junction (and all incoming connections are preserved
1034
GNEChange_Attribute::changeAttribute(edge, SUMO_ATTR_TO, newJunction->getID(), undoList);
1035
// set first part of geometry
1036
newGeoms.first.pop_back();
1037
newGeoms.first.erase(newGeoms.first.begin());
1038
edge->setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
1039
edge->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.first), undoList);
1040
// set second part of geometry
1041
secondPart->setAttribute(GNE_ATTR_SHAPE_END, shapeEnd, undoList);
1042
newGeoms.second.pop_back();
1043
newGeoms.second.erase(newGeoms.second.begin());
1044
secondPart->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.second), undoList);
1045
// fix custom length
1046
if (edge->getNBEdge()->hasLoadedLength()) {
1047
// split in proportion to geometry lengths
1048
const double loadedLength = edge->getNBEdge()->getLoadedLength();
1049
edge->setAttribute(SUMO_ATTR_LENGTH, toString(relativeLength1 * loadedLength), undoList);
1050
secondPart->setAttribute(SUMO_ATTR_LENGTH, toString(relativeLength2 * loadedLength), undoList);
1051
}
1052
// reconnect across the split
1053
for (int i = 0; i < (int)edge->getChildLanes().size(); ++i) {
1054
undoList->add(new GNEChange_Connection(edge, NBEdge::Connection(i, secondPart->getNBEdge(), i), false, true), true);
1055
}
1056
// re-add modified crossings
1057
for (const auto& nbC : affectedCrossings) {
1058
undoList->add(new GNEChange_Crossing(secondPart->getToJunction(), nbC, true), true);
1059
}
1060
// Split geometry of all child additional
1061
auto childAdditionals = edge->getChildAdditionals();
1062
for (const auto& additional : childAdditionals) {
1063
additional->splitEdgeGeometry(edgeSplitPosition, edge, secondPart, undoList);
1064
}
1065
// Split geometry of all child lane additional
1066
for (int i = 0; i < (int)edge->getChildLanes().size(); i++) {
1067
for (const auto& additional : edge->getChildLanes().at(i)->getChildAdditionals()) {
1068
additional->splitEdgeGeometry(laneSplitPosition, edge->getChildLanes().at(i), secondPart->getChildLanes().at(i), undoList);
1069
}
1070
}
1071
// Split geometry of all child demand elements
1072
auto childDemandElements = edge->getChildDemandElements();
1073
for (const auto& demandElement : childDemandElements) {
1074
demandElement->splitEdgeGeometry(edgeSplitPosition, edge, secondPart, undoList);
1075
}
1076
// Split geometry of all child lane demand elements
1077
for (int i = 0; i < (int)edge->getChildLanes().size(); i++) {
1078
for (const auto& demandElement : edge->getChildLanes().at(i)->getChildDemandElements()) {
1079
demandElement->splitEdgeGeometry(laneSplitPosition, edge->getChildLanes().at(i), secondPart->getChildLanes().at(i), undoList);
1080
}
1081
}
1082
// finish undo list
1083
undoList->end();
1084
// return new junction
1085
return std::make_pair(newJunction, secondPart);
1086
}
1087
1088
1089
void
1090
GNENet::splitEdgesBidi(GNEEdge* edge, GNEEdge* oppositeEdge, const Position& pos, GNEUndoList* undoList) {
1091
GNEJunction* newJunction = nullptr;
1092
undoList->begin(edge, TL("split edges"));
1093
// split edge and save created junction
1094
auto newStuff = splitEdge(edge, pos, undoList, newJunction);
1095
newJunction = newStuff.first;
1096
// split second edge
1097
splitEdge(oppositeEdge, pos, undoList, newJunction);
1098
if (edge->getChildLanes().back()->getAttribute(GNE_ATTR_OPPOSITE) != "") {
1099
// restore opposite lane information
1100
for (const auto& nbEdge : newJunction->getNBNode()->getEdges()) {
1101
GNEEdge* e = myAttributeCarriers->retrieveEdge(nbEdge->getID());
1102
// store old attribute before it's changed by guess opposite
1103
e->getChildLanes().back()->setAttribute(GNE_ATTR_OPPOSITE, "", undoList);
1104
if (nbEdge->guessOpposite(true)) {
1105
e->getChildLanes().back()->setAttribute(GNE_ATTR_OPPOSITE, nbEdge->getLanes().back().oppositeID, undoList);
1106
}
1107
}
1108
}
1109
undoList->end();
1110
}
1111
1112
1113
void
1114
GNENet::reverseEdge(GNEEdge* edge, GNEUndoList* undoList) {
1115
undoList->begin(edge, TL("reverse edge"));
1116
auto fromJunction = edge->getFromJunction();
1117
auto ToJunction = edge->getToJunction();
1118
deleteEdge(edge, undoList, false); // still exists. we delete it so we can reuse the name in case of resplit
1119
GNEEdge* reversed = createEdge(ToJunction, fromJunction, edge, undoList, edge->getID(), false, true);
1120
if (reversed) {
1121
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(edge->getNBEdge()->getInnerGeometry().reverse()), undoList);
1122
reversed->setAttribute(GNE_ATTR_SHAPE_START, edge->getAttribute(GNE_ATTR_SHAPE_END), undoList);
1123
reversed->setAttribute(GNE_ATTR_SHAPE_END, edge->getAttribute(GNE_ATTR_SHAPE_START), undoList);
1124
}
1125
undoList->end();
1126
}
1127
1128
1129
GNEEdge*
1130
GNENet::addReversedEdge(GNEEdge* edge, const bool disconnected, GNEUndoList* undoList) {
1131
GNEEdge* reversed = edge->getReverseEdge();
1132
if (reversed != nullptr) {
1133
return reversed;
1134
}
1135
undoList->begin(edge, TL("add reversed edge"));
1136
if (!disconnected) {
1137
// for rail edges, we assume bi-directional tracks are wanted
1138
reversed = createEdge(edge->getToJunction(), edge->getFromJunction(), edge, undoList, "-" + edge->getID(), false, true);
1139
assert(reversed != 0);
1140
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(edge->getNBEdge()->getInnerGeometry().reverse()), undoList);
1141
reversed->setAttribute(GNE_ATTR_SHAPE_START, edge->getAttribute(GNE_ATTR_SHAPE_END), undoList);
1142
reversed->setAttribute(GNE_ATTR_SHAPE_END, edge->getAttribute(GNE_ATTR_SHAPE_START), undoList);
1143
} else {
1144
// if the edge is centered it should probably connect somewhere else
1145
// make it easy to move and reconnect it
1146
PositionVector orig = edge->getNBEdge()->getGeometry();
1147
PositionVector origInner = edge->getNBEdge()->getInnerGeometry();
1148
const double tentativeShift = edge->getNBEdge()->getTotalWidth() + 2;
1149
orig.move2side(-tentativeShift);
1150
origInner.move2side(-tentativeShift);
1151
GNEJunction* src = createJunction(orig.back(), undoList);
1152
GNEJunction* dest = createJunction(orig.front(), undoList);
1153
reversed = createEdge(src, dest, edge, undoList, "-" + edge->getID(), false, true);
1154
assert(reversed != 0);
1155
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(origInner.reverse()), undoList);
1156
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(origInner.reverse()), undoList);
1157
// select the new edge and its nodes
1158
reversed->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
1159
src->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
1160
dest->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
1161
}
1162
undoList->end();
1163
return reversed;
1164
}
1165
1166
1167
void
1168
GNENet::mergeJunctions(GNEJunction* moved, const GNEJunction* target, GNEUndoList* undoList) {
1169
undoList->begin(moved, TL("merge junctions"));
1170
// deleting edges changes in the underlying EdgeVector so we have to make a copy
1171
const EdgeVector incomingNBEdges = moved->getNBNode()->getIncomingEdges();
1172
for (const auto& incomingNBEdge : incomingNBEdges) {
1173
// delete edges between the merged junctions
1174
GNEEdge* edge = myAttributeCarriers->getEdges().at(incomingNBEdge->getID());
1175
if (edge->getFromJunction() == target) {
1176
deleteEdge(edge, undoList, false);
1177
} else {
1178
edge->setAttribute(SUMO_ATTR_TO, target->getID(), undoList);
1179
}
1180
}
1181
// deleting edges changes in the underlying EdgeVector so we have to make a copy
1182
const EdgeVector outgoingNBEdges = moved->getNBNode()->getOutgoingEdges();
1183
for (const auto& outgoingNBEdge : outgoingNBEdges) {
1184
// delete edges between the merged junctions
1185
GNEEdge* edge = myAttributeCarriers->getEdges().at(outgoingNBEdge->getID());
1186
if (edge->getToJunction() == target) {
1187
deleteEdge(edge, undoList, false);
1188
} else {
1189
edge->setAttribute(SUMO_ATTR_FROM, target->getID(), undoList);
1190
}
1191
}
1192
// deleted moved junction
1193
deleteJunction(moved, undoList);
1194
undoList->end();
1195
}
1196
1197
1198
void
1199
GNENet::selectRoundabout(GNEJunction* junction, GNEUndoList* undoList) {
1200
for (const EdgeSet& roundabout : myNetBuilder->getEdgeCont().getRoundabouts()) {
1201
for (NBEdge* edge : roundabout) {
1202
if (edge->getFromNode() == junction->getNBNode()) {
1203
undoList->begin(junction, TL("select roundabout"));
1204
for (const auto& roundaboutEdge : roundabout) {
1205
GNEEdge* e = myAttributeCarriers->retrieveEdge(roundaboutEdge->getID());
1206
e->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
1207
e->getToJunction()->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
1208
}
1209
undoList->end();
1210
return;
1211
}
1212
}
1213
}
1214
}
1215
1216
1217
void
1218
GNENet::createRoundabout(GNEJunction* junction, GNEUndoList* undoList) {
1219
undoList->begin(junction, TL("create roundabout"));
1220
// reset shape end from incoming edges
1221
for (const auto& incomingEdge : junction->getGNEIncomingEdges()) {
1222
incomingEdge->setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
1223
}
1224
// reset shape start from outgoing edges
1225
for (const auto& outgoingEdge : junction->getGNEOutgoingEdges()) {
1226
outgoingEdge->setAttribute(GNE_ATTR_SHAPE_START, "", undoList);
1227
}
1228
junction->getNBNode()->updateSurroundingGeometry();
1229
double radius = junction->getNBNode()->getRadius();
1230
if (radius == NBNode::UNSPECIFIED_RADIUS) {
1231
radius = OptionsCont::getOptions().getFloat("default.junctions.radius");
1232
}
1233
std::vector<GNEEdge*> edges;
1234
// use clockwise sorting
1235
for (const auto& nbEdge : junction->getNBNode()->getEdges()) {
1236
edges.push_back(myAttributeCarriers->retrieveEdge(nbEdge->getID()));
1237
}
1238
const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
1239
if (lefthand) {
1240
std::reverse(edges.begin(), edges.end());
1241
}
1242
const double lefthandSign = lefthand ? -1 : 1;
1243
std::vector<GNEJunction*> newJunctions;
1244
GNEEdge* templateEdge = nullptr;
1245
GNEEdge* prevOpposite = nullptr;
1246
// store old crossings edges as ids because edges are renamed and pointers will be invalid
1247
std::vector<std::pair<NBNode::Crossing, std::vector<std::string>>> oldCrossings;
1248
for (const auto& crossing : junction->getGNECrossings()) {
1249
std::vector<std::string> edgeIDs;
1250
for (auto e : crossing->getCrossingEdges()) {
1251
edgeIDs.push_back(e->getID());
1252
}
1253
oldCrossings.push_back(std::make_pair(*crossing->getNBCrossing(), edgeIDs));
1254
}
1255
std::map<std::string, std::string> edgeRename;
1256
// split incoming/outgoing edges
1257
for (GNEEdge* edge : edges) {
1258
GNEJunction* newJunction = nullptr;
1259
if (edge == prevOpposite) {
1260
newJunction = newJunctions.back();
1261
}
1262
// update template (most "important" incoming edge)
1263
if (edge->getToJunction() == junction) {
1264
if (templateEdge == nullptr) {
1265
templateEdge = edge;
1266
} else {
1267
NBEdge* tpl = templateEdge->getNBEdge();
1268
NBEdge* e = edge->getNBEdge();
1269
if (tpl->getNumLanes() < e->getNumLanes()
1270
|| (tpl->getNumLanes() == e->getNumLanes()
1271
&& tpl->getPriority() < e->getPriority())) {
1272
templateEdge = edge;
1273
}
1274
}
1275
}
1276
//std::cout << " edge=" << edge->getID() << " prevOpposite=" << Named::getIDSecure(prevOpposite) << " newJunction=" << Named::getIDSecure(newJunction) << "\n";
1277
prevOpposite = edge->getOppositeEdges().size() > 0 ? edge->getOppositeEdges().front() : nullptr;
1278
const double geomLength = edge->getNBEdge()->getGeometry().length2D();
1279
const double splitOffset = (edge->getToJunction() == junction
1280
? MAX2(POSITION_EPS, geomLength - radius)
1281
: MIN2(geomLength - POSITION_EPS, radius));
1282
Position pos = edge->getNBEdge()->getGeometry().positionAtOffset2D(splitOffset);
1283
auto newStuff = splitEdge(edge, pos, undoList, newJunction);
1284
newJunction = newStuff.first;
1285
if (edge->getFromJunction() == junction) {
1286
// edge will be deleted and the new part after the split kept. Preserve edge id
1287
edgeRename[newStuff.second->getID()] = edge->getID();
1288
}
1289
if (newJunctions.empty() || newJunction != newJunctions.back()) {
1290
newJunctions.push_back(newJunction);
1291
}
1292
}
1293
1294
Position center = junction->getPositionInView();
1295
deleteJunction(junction, undoList);
1296
// rename edges after the originals have been deleted
1297
for (auto item : edgeRename) {
1298
GNEEdge* outgoing = myAttributeCarriers->retrieveEdge(item.first);
1299
outgoing->setAttribute(SUMO_ATTR_ID, item.second, undoList);
1300
}
1301
// restore crossings (after rename)
1302
for (auto nbCItem : oldCrossings) {
1303
for (GNEJunction* nj : newJunctions) {
1304
nbCItem.first.edges.clear();
1305
// check whether this junction has all the edges of the crossing
1306
for (const std::string& ce : nbCItem.second) {
1307
bool foundCE = false;
1308
for (NBEdge* je : nj->getNBNode()->getEdges()) {
1309
if (je->getID() == ce) {
1310
foundCE = true;
1311
nbCItem.first.edges.push_back(je);
1312
break;
1313
}
1314
}
1315
if (!foundCE) {
1316
break;
1317
}
1318
}
1319
if (nbCItem.first.edges.size() == nbCItem.second.size()) {
1320
undoList->add(new GNEChange_Crossing(nj, nbCItem.first, true), true);
1321
break;
1322
}
1323
}
1324
}
1325
// create new edges to connect roundabout junctions (counter-clockwise)
1326
const double resolution = OptionsCont::getOptions().getFloat("opendrive.curve-resolution") * 3;
1327
for (int i = 0; i < (int)newJunctions.size(); i++) {
1328
GNEJunction* from = newJunctions[(i + 1) % newJunctions.size()];
1329
GNEJunction* to = newJunctions[i];
1330
GNEEdge* newEdge = createEdge(from, to, nullptr, undoList);
1331
const double angle1 = center.angleTo2D(from->getPositionInView());
1332
const double angle2 = center.angleTo2D(to->getPositionInView());
1333
// insert geometry points every resolution meters
1334
const double angleDiff = fabs(GeomHelper::angleDiff(angle2, angle1));
1335
// circumference = 2 * M_PI * radius, angularFraction = angleDiff / 2 * M_PI
1336
int numSegments = MAX2(2, (int)ceil(angleDiff * radius / resolution));
1337
PositionVector innerGeom;
1338
for (int j = 1; j < numSegments; j++) {
1339
const double angle = angle1 + lefthandSign * j * angleDiff / numSegments;
1340
innerGeom.push_back(center + Position(cos(angle) * radius, sin(angle) * radius));
1341
}
1342
//std::cout << " newEdge=" << newEdge->getID() << " angle1=" << angle1 << " angle2=" << angle2 << " angleDiff=" << angleDiff
1343
// << " numSegments=" << numSegments << " innerGeom=" << innerGeom << "\n";
1344
newEdge->setAttribute(SUMO_ATTR_SHAPE, toString(innerGeom), undoList);
1345
if (templateEdge) {
1346
GNEEdgeTemplate t(templateEdge);
1347
newEdge->copyTemplate(&t, undoList);
1348
}
1349
}
1350
undoList->end();
1351
}
1352
1353
1354
bool
1355
GNENet::checkJunctionPosition(const Position& pos) {
1356
// Check that there isn't another junction in the same position as Pos
1357
for (auto& junction : myAttributeCarriers->getJunctions()) {
1358
if (junction.second->getPositionInView() == pos) {
1359
return false;
1360
}
1361
}
1362
return true;
1363
}
1364
1365
1366
void
1367
GNENet::saveNetwork() {
1368
auto& neteditOptions = OptionsCont::getOptions();
1369
auto& sumoOptions = myViewNet->getViewParent()->getGNEAppWindows()->getSumoOptions();
1370
// begin save network
1371
getApp()->beginWaitCursor();
1372
// set output file in SUMO and netedit options
1373
neteditOptions.resetWritable();
1374
neteditOptions.set("output-file", neteditOptions.getString("net-file"));
1375
sumoOptions.resetWritable();
1376
sumoOptions.set("net-file", neteditOptions.getString("net-file"));
1377
// compute without volatile options and update network
1378
computeAndUpdate(neteditOptions, false);
1379
// clear typeContainer
1380
myNetBuilder->getTypeCont().clearTypes();
1381
// now update typeContainer with edgeTypes
1382
for (const auto& edgeType : myAttributeCarriers->getEdgeTypes()) {
1383
myNetBuilder->getTypeCont().insertEdgeType(edgeType.first, edgeType.second);
1384
for (int i = 0; i < (int)edgeType.second->getLaneTypes().size(); i++) {
1385
myNetBuilder->getTypeCont().insertLaneType(edgeType.first, i,
1386
edgeType.second->getLaneTypes().at(i)->speed,
1387
edgeType.second->getLaneTypes().at(i)->permissions,
1388
edgeType.second->getLaneTypes().at(i)->width,
1389
edgeType.second->getLaneTypes().at(i)->attrs);
1390
}
1391
}
1392
// write network
1393
NWFrame::writeNetwork(neteditOptions, *myNetBuilder);
1394
// reset output file
1395
sumoOptions.resetWritable();
1396
neteditOptions.resetDefault("output-file");
1397
// mark network as saved
1398
mySavingStatus->networkSaved();
1399
// end save network
1400
getApp()->endWaitCursor();
1401
}
1402
1403
1404
void
1405
GNENet::savePlain(const std::string& prefix) {
1406
auto& neteditOptions = OptionsCont::getOptions();
1407
// compute without volatile options
1408
computeAndUpdate(neteditOptions, false);
1409
NWWriter_XML::writeNetwork(neteditOptions, prefix, *myNetBuilder);
1410
}
1411
1412
1413
void
1414
GNENet::saveJoined(const std::string& filename) {
1415
// compute without volatile options
1416
computeAndUpdate(OptionsCont::getOptions(), false);
1417
NWWriter_XML::writeJoinedJunctions(filename, myNetBuilder->getNodeCont());
1418
}
1419
1420
1421
void
1422
GNENet::setViewNet(GNEViewNet* viewNet) {
1423
// set view net
1424
myViewNet = viewNet;
1425
// add default vTypes
1426
myAttributeCarriers->addDefaultVTypes();
1427
// update all edge geometries
1428
for (const auto& edge : myAttributeCarriers->getEdges()) {
1429
edge.second->updateGeometry();
1430
}
1431
// update view Net and recalculate edge boundaries)
1432
myViewNet->update();
1433
for (const auto& edge : myAttributeCarriers->getEdges()) {
1434
edge.second->updateCenteringBoundary(true);
1435
}
1436
}
1437
1438
1439
void
1440
GNENet::addGLObjectIntoGrid(GNEAttributeCarrier* AC) {
1441
// check if object must be inserted in RTREE
1442
if (AC->getTagProperty()->isPlacedInRTree() && !AC->inGrid()) {
1443
myGrid.addAdditionalGLObject(AC->getGUIGlObject());
1444
AC->setInGrid(true);
1445
}
1446
}
1447
1448
1449
void
1450
GNENet::removeGLObjectFromGrid(GNEAttributeCarrier* AC) {
1451
// check if object must be inserted in RTREE
1452
if (AC->getTagProperty()->isPlacedInRTree() && AC->inGrid()) {
1453
myGrid.removeAdditionalGLObject(AC->getGUIGlObject());
1454
AC->setInGrid(false);
1455
}
1456
}
1457
1458
1459
void
1460
GNENet::computeNetwork(GNEApplicationWindow* window, bool force, bool volatileOptions) {
1461
if (!myNeedRecompute) {
1462
if (force) {
1463
if (volatileOptions) {
1464
window->setStatusBarText(TL("Forced computing junctions with volatile options ..."));
1465
} else {
1466
window->setStatusBarText(TL("Forced computing junctions ..."));
1467
}
1468
} else {
1469
return;
1470
}
1471
} else {
1472
if (volatileOptions) {
1473
window->setStatusBarText(TL("Computing junctions with volatile options ..."));
1474
} else {
1475
window->setStatusBarText(TL("Computing junctions ..."));
1476
}
1477
}
1478
// start recomputing
1479
getApp()->beginWaitCursor();
1480
// save current number of lanes for every edge if recomputing is with volatile options
1481
if (volatileOptions) {
1482
for (const auto& edge : myAttributeCarriers->getEdges()) {
1483
myEdgesAndNumberOfLanes[edge.second->getID()] = (int)edge.second->getChildLanes().size();
1484
}
1485
}
1486
// compute and update
1487
auto& neteditOptions = OptionsCont::getOptions();
1488
computeAndUpdate(neteditOptions, volatileOptions);
1489
// load additionals if was recomputed with volatile options
1490
if (volatileOptions && OptionsCont::getOptions().getString("additional-files").size() > 0) {
1491
// split and load every file individually
1492
const auto additionalFiles = StringTokenizer(OptionsCont::getOptions().getString("additional-files"), ";").getVector();
1493
for (const auto& file : additionalFiles) {
1494
// Create additional handler
1495
GNEGeneralHandler generalHandler(this, file, myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());
1496
// Run parser
1497
if (!generalHandler.parse()) {
1498
WRITE_ERROR(TL("Loading of additional file failed: ") + file);
1499
} else {
1500
WRITE_MESSAGE(TL("Loading of additional file successfully: ") + file);
1501
}
1502
}
1503
}
1504
// load demand elements if was recomputed with volatile options
1505
if (volatileOptions && OptionsCont::getOptions().getString("route-files").size() > 0) {
1506
// Create general handler
1507
GNEGeneralHandler generalHandler(this, OptionsCont::getOptions().getString("route-files"), false);
1508
// Run parser
1509
if (!generalHandler.parse()) {
1510
WRITE_ERROR(TL("Loading of route file failed: ") + OptionsCont::getOptions().getString("route-files"));
1511
} else {
1512
WRITE_MESSAGE(TL("Loading of route file successfully: ") + OptionsCont::getOptions().getString("route-files"));
1513
}
1514
}
1515
// load datas if was recomputed with volatile options
1516
if (volatileOptions && OptionsCont::getOptions().getString("data-files").size() > 0) {
1517
// Create data handler
1518
GNEDataHandler dataHandler(this, OptionsCont::getOptions().getString("data-files"), false);
1519
// Run parser
1520
if (!dataHandler.parse()) {
1521
WRITE_ERROR(TL("Loading of data file failed: ") + OptionsCont::getOptions().getString("data-files"));
1522
} else {
1523
WRITE_MESSAGE(TL("Loading of data file successfully: ") + OptionsCont::getOptions().getString("data-files"));
1524
}
1525
}
1526
// load meanDatas if was recomputed with volatile options
1527
if (volatileOptions && OptionsCont::getOptions().getString("meandata-files").size() > 0) {
1528
// Create meanData handler
1529
GNEGeneralHandler generalHandler(this, OptionsCont::getOptions().getString("meandata-files"), false);
1530
// Run parser
1531
if (!generalHandler.parse()) {
1532
WRITE_ERROR(TL("Loading of meandata file failed: ") + OptionsCont::getOptions().getString("meandata-files"));
1533
} else {
1534
WRITE_MESSAGE(TL("Loading of meandata file successfully: ") + OptionsCont::getOptions().getString("meandata-files"));
1535
}
1536
}
1537
// clear myEdgesAndNumberOfLanes after reload additionals
1538
myEdgesAndNumberOfLanes.clear();
1539
// end recomputing
1540
getApp()->endWaitCursor();
1541
// update status bar
1542
window->setStatusBarText(TL("Finished computing junctions."));
1543
}
1544
1545
1546
void
1547
GNENet::computeDemandElements(GNEApplicationWindow* window) {
1548
window->setStatusBarText(TL("Computing demand elements ..."));
1549
// if we aren't in Demand mode, update path calculator
1550
if (!myViewNet->getEditModes().isCurrentSupermodeDemand() &&
1551
!myDemandPathManager->getPathCalculator()->isPathCalculatorUpdated()) {
1552
myDemandPathManager->getPathCalculator()->updatePathCalculator();
1553
}
1554
// clear demand paths
1555
myDemandPathManager->clearSegments();
1556
// iterate over all demand elements and compute
1557
for (const auto& demandElements : myAttributeCarriers->getDemandElements()) {
1558
for (const auto& demandElement : demandElements.second) {
1559
demandElement.second->computePathElement();
1560
}
1561
}
1562
window->setStatusBarText(TL("Finished computing demand elements."));
1563
}
1564
1565
1566
void
1567
GNENet::computeDataElements(GNEApplicationWindow* window) {
1568
window->setStatusBarText(TL("Computing data elements ..."));
1569
// iterate over all demand elements and compute
1570
for (const auto& genericDataTag : myAttributeCarriers->getGenericDatas()) {
1571
for (const auto& genericData : genericDataTag.second) {
1572
genericData.second->computePathElement();
1573
}
1574
}
1575
window->setStatusBarText(TL("Finished computing data elements."));
1576
}
1577
1578
1579
void
1580
GNENet::computeJunction(GNEJunction* junction) {
1581
// recompute tl-logics
1582
auto& neteditOptions = OptionsCont::getOptions();
1583
NBTrafficLightLogicCont& tllCont = getTLLogicCont();
1584
// iterate over traffic lights definitions. Make a copy because invalid
1585
// definitions will be removed (and would otherwise destroy the iterator)
1586
const std::set<NBTrafficLightDefinition*> tlsDefs = junction->getNBNode()->getControllingTLS();
1587
for (auto it : tlsDefs) {
1588
it->setParticipantsInformation();
1589
it->setTLControllingInformation();
1590
tllCont.computeSingleLogic(neteditOptions, it);
1591
}
1592
1593
// @todo compute connections etc...
1594
}
1595
1596
1597
void
1598
GNENet::requireRecompute() {
1599
myNeedRecompute = true;
1600
}
1601
1602
1603
bool
1604
GNENet::isNetRecomputed() const {
1605
return !myNeedRecompute;
1606
}
1607
1608
1609
FXApp*
1610
GNENet::getApp() {
1611
return myViewNet->getApp();
1612
}
1613
1614
1615
NBNetBuilder*
1616
GNENet::getNetBuilder() const {
1617
return myNetBuilder;
1618
}
1619
1620
1621
bool
1622
GNENet::joinSelectedJunctions(GNEUndoList* undoList) {
1623
const auto selectedJunctions = myAttributeCarriers->getSelectedJunctions();
1624
if (selectedJunctions.size() < 2) {
1625
return false;
1626
}
1627
EdgeVector allIncoming;
1628
EdgeVector allOutgoing;
1629
std::set<NBNode*, ComparatorIdLess> cluster;
1630
for (const auto& selectedJunction : selectedJunctions) {
1631
cluster.insert(selectedJunction->getNBNode());
1632
const EdgeVector& incoming = selectedJunction->getNBNode()->getIncomingEdges();
1633
allIncoming.insert(allIncoming.end(), incoming.begin(), incoming.end());
1634
const EdgeVector& outgoing = selectedJunction->getNBNode()->getOutgoingEdges();
1635
allOutgoing.insert(allOutgoing.end(), outgoing.begin(), outgoing.end());
1636
}
1637
// create new junction
1638
Position pos;
1639
Position oldPos;
1640
bool setTL = false;
1641
std::string id = "cluster";
1642
TrafficLightType type;
1643
SumoXMLNodeType nodeType = SumoXMLNodeType::UNKNOWN;
1644
myNetBuilder->getNodeCont().analyzeCluster(cluster, id, pos, setTL, type, nodeType);
1645
// save position
1646
oldPos = pos;
1647
// Check that there isn't another junction in the same position as Pos but doesn't belong to cluster
1648
for (const auto& junction : myAttributeCarriers->getJunctions()) {
1649
if ((junction.second->getPositionInView() == pos) && (cluster.find(junction.second->getNBNode()) == cluster.end())) {
1650
// open dialog
1651
const auto questionDialog = GNEQuestionBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(), GNEDialog::Buttons::YES_NO,
1652
TL("Position of joined junction"),
1653
TL("There is another unselected junction in the same position of joined junction."),
1654
TL("It will be joined with the other selected junctions. Continue?"));
1655
// check dialog result
1656
if (questionDialog.getResult() == GNEDialog::Result::ACCEPT) {
1657
// select conflicted junction an join all again
1658
junction.second->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
1659
return joinSelectedJunctions(undoList);
1660
} else {
1661
return false;
1662
}
1663
}
1664
}
1665
// use checkJunctionPosition to avoid conflicts with junction in the same position as others
1666
while (!checkJunctionPosition(pos)) {
1667
pos.setx(pos.x() + 0.1);
1668
pos.sety(pos.y() + 0.1);
1669
}
1670
// start with the join selected junctions
1671
undoList->begin(GUIIcon::JUNCTION, "Join selected " + toString(SUMO_TAG_JUNCTION) + "s");
1672
GNEJunction* joined = createJunction(pos, undoList);
1673
joined->setAttribute(SUMO_ATTR_ID, id, undoList);
1674
// id must be set before type because it is used when creating a new tls
1675
joined->setAttribute(SUMO_ATTR_TYPE, toString(nodeType), undoList); // i.e. rail crossing
1676
if (setTL) {
1677
joined->setAttribute(SUMO_ATTR_TLTYPE, toString(type), undoList);
1678
}
1679
GNEChange_RegisterJoin::registerJoin(cluster, myNetBuilder->getNodeCont(), undoList);
1680
// first remove all crossing of the involved junctions and edges
1681
// (otherwise edge removal will trigger discarding)
1682
std::vector<NBNode::Crossing> oldCrossings;
1683
for (const auto& selectedJunction : selectedJunctions) {
1684
const auto crossings = selectedJunction->getGNECrossings();
1685
for (auto crossing : crossings) {
1686
deleteCrossing(crossing, undoList);
1687
}
1688
}
1689
// preserve old connections
1690
for (const auto& selectedJunction : selectedJunctions) {
1691
selectedJunction->setLogicValid(false, undoList);
1692
}
1693
// remap edges
1694
for (const auto& incomingEdge : allIncoming) {
1695
if (std::find(allOutgoing.begin(), allOutgoing.end(), incomingEdge) == allOutgoing.end()) {
1696
GNEChange_Attribute::changeAttribute(myAttributeCarriers->getEdges().at(incomingEdge->getID()), SUMO_ATTR_TO, joined->getID(), undoList);
1697
}
1698
}
1699
EdgeSet edgesWithin;
1700
for (const auto& outgoingEdge : allOutgoing) {
1701
// delete edges within the cluster
1702
GNEEdge* edge = myAttributeCarriers->getEdges().at(outgoingEdge->getID());
1703
if (edge->getToJunction() == joined) {
1704
edgesWithin.insert(outgoingEdge);
1705
deleteEdge(edge, undoList, false);
1706
} else {
1707
GNEChange_Attribute::changeAttribute(myAttributeCarriers->getEdges().at(outgoingEdge->getID()), SUMO_ATTR_FROM, joined->getID(), undoList);
1708
}
1709
}
1710
// remap all crossing of the involved junctions and edges
1711
for (const auto& nbc : oldCrossings) {
1712
bool keep = true;
1713
for (NBEdge* e : nbc.edges) {
1714
if (edgesWithin.count(e) != 0) {
1715
keep = false;
1716
break;
1717
}
1718
};
1719
if (keep) {
1720
undoList->add(new GNEChange_Crossing(joined, nbc.edges, nbc.width,
1721
nbc.priority || joined->getNBNode()->isTLControlled(),
1722
nbc.customTLIndex, nbc.customTLIndex2, nbc.customShape,
1723
false, true), true);
1724
}
1725
}
1726
// delete original junctions
1727
for (const auto& selectedJunction : selectedJunctions) {
1728
deleteJunction(selectedJunction, undoList);
1729
}
1730
// check if joined junction had to change their original position to avoid errors
1731
if (pos != oldPos) {
1732
joined->setAttribute(SUMO_ATTR_POSITION, toString(oldPos), undoList);
1733
}
1734
undoList->end();
1735
return true;
1736
}
1737
1738
1739
bool
1740
GNENet::cleanInvalidCrossings(GNEUndoList* undoList) {
1741
// obtain current net's crossings
1742
std::vector<GNECrossing*> myNetCrossings;
1743
for (const auto& junction : myAttributeCarriers->getJunctions()) {
1744
myNetCrossings.reserve(myNetCrossings.size() + junction.second->getGNECrossings().size());
1745
myNetCrossings.insert(myNetCrossings.end(), junction.second->getGNECrossings().begin(), junction.second->getGNECrossings().end());
1746
}
1747
// obtain invalid crossings
1748
std::vector<GNECrossing*> myInvalidCrossings;
1749
for (auto i = myNetCrossings.begin(); i != myNetCrossings.end(); i++) {
1750
if (!(*i)->getNBCrossing()->valid) {
1751
myInvalidCrossings.push_back(*i);
1752
}
1753
}
1754
// continue depending of invalid crossings
1755
if (myInvalidCrossings.empty()) {
1756
// open a warning dialog informing that there isn't crossing to remove
1757
GNEWarningBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(),
1758
TL("Clear crossings"),
1759
TL("There are no invalid crossings to remove."));
1760
} else {
1761
std::string plural = myInvalidCrossings.size() == 1 ? ("") : ("s");
1762
// Ask confirmation to user
1763
const auto questionDialog = GNEQuestionBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(),
1764
GNEDialog::Buttons::YES_NO, TL("Clear crossings"),
1765
TL("Crossings will be cleared. Continue?"));
1766
// 1:yes, 2:no, 4:esc
1767
if (questionDialog.getResult() == GNEDialog::Result::ACCEPT) {
1768
undoList->begin(GUIIcon::MODEDELETE, TL("clear crossings"));
1769
for (const auto& crossing : myInvalidCrossings) {
1770
deleteCrossing(crossing, undoList);
1771
}
1772
undoList->end();
1773
} else {
1774
return false;
1775
}
1776
}
1777
return true;
1778
}
1779
1780
1781
void
1782
GNENet::removeSolitaryJunctions(GNEUndoList* undoList) {
1783
undoList->begin(GUIIcon::MODEDELETE, TL("clear junctions"));
1784
std::vector<GNEJunction*> toRemove;
1785
for (auto& junction : myAttributeCarriers->getJunctions()) {
1786
if (junction.second->getNBNode()->getEdges().size() == 0) {
1787
toRemove.push_back(junction.second);
1788
}
1789
}
1790
for (auto junction : toRemove) {
1791
deleteJunction(junction, undoList);
1792
}
1793
undoList->end();
1794
}
1795
1796
1797
void
1798
GNENet::cleanUnusedRoutes(GNEUndoList* undoList) {
1799
// first declare a vector to save all routes without children
1800
std::vector<GNEDemandElement*> routesWithoutChildren;
1801
routesWithoutChildren.reserve(myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE).size());
1802
// iterate over routes
1803
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
1804
if (route.second->getChildDemandElements().empty()) {
1805
routesWithoutChildren.push_back(route.second);
1806
}
1807
}
1808
// finally remove all routesWithoutChildren
1809
if (routesWithoutChildren.size() > 0) {
1810
// begin undo list
1811
undoList->begin(GUIIcon::MODEDELETE, TL("clear unused routes"));
1812
// iterate over routesWithoutChildren
1813
for (const auto& i : routesWithoutChildren) {
1814
// due route doesn't have children, simply call GNEChange_DemandElement
1815
undoList->add(new GNEChange_DemandElement(i, false), true);
1816
}
1817
// end undo list
1818
undoList->end();
1819
}
1820
}
1821
1822
1823
void
1824
GNENet::joinRoutes(GNEUndoList* undoList) {
1825
// first declare a sorted set of sorted route's edges in string format
1826
std::set<std::pair<std::string, GNEDemandElement*> > mySortedRoutes;
1827
// iterate over routes and save it in mySortedRoutes (only if it doesn't have Stop Children)
1828
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
1829
// first check route has stops
1830
bool hasStops = false;
1831
for (const auto& stop : route.second->getChildDemandElements()) {
1832
if (stop->getTagProperty()->isVehicleStop()) {
1833
hasStops = true;
1834
}
1835
}
1836
if (!hasStops) {
1837
mySortedRoutes.insert(std::make_pair(GNEAttributeCarrier::parseIDs(route.second->getParentEdges()), route.second));
1838
}
1839
}
1840
// now declare a matrix in which organize routes to be merged
1841
std::vector<std::vector<GNEDemandElement*> > routesToMerge;
1842
auto index = mySortedRoutes.begin();
1843
// iterate over mySortedRoutes
1844
for (auto i = mySortedRoutes.begin(); i != mySortedRoutes.end(); i++) {
1845
if (routesToMerge.empty()) {
1846
routesToMerge.push_back({i->second});
1847
} else {
1848
if (index->first == i->first) {
1849
routesToMerge.back().push_back(i->second);
1850
} else {
1851
routesToMerge.push_back({i->second});
1852
index = i;
1853
}
1854
}
1855
}
1856
// now check if there is routes to merge
1857
bool thereIsRoutesToMerge = false;
1858
for (const auto& i : routesToMerge) {
1859
if (i.size() > 1) {
1860
thereIsRoutesToMerge = true;
1861
}
1862
}
1863
// if exist
1864
if (thereIsRoutesToMerge) {
1865
// begin undo list
1866
undoList->begin(GUIIcon::ROUTE, TL("merge routes"));
1867
// iterate over route to edges
1868
for (const auto& routes : routesToMerge) {
1869
if (routes.size() > 1) {
1870
// iterate over duplicated routes
1871
for (int i = 1; i < (int)routes.size(); i++) {
1872
// move all vehicles of every duplicated route
1873
while (routes.at(i)->getChildDemandElements().size() > 0) {
1874
routes.at(i)->getChildDemandElements().front()->setAttribute(SUMO_ATTR_ROUTE, routes.at(0)->getID(), undoList);
1875
}
1876
// finally remove route
1877
undoList->add(new GNEChange_DemandElement(routes.at(i), false), true);
1878
}
1879
}
1880
}
1881
// end undo list
1882
undoList->end();
1883
}
1884
}
1885
1886
1887
void
1888
GNENet::adjustPersonPlans(GNEUndoList* undoList) {
1889
// declare personPlan-pos map
1890
std::map<GNEDemandElement*, std::string> personPlanMap;
1891
// iterate over persons
1892
for (const auto& persontag : {
1893
SUMO_TAG_PERSON, SUMO_TAG_PERSONFLOW
1894
}) {
1895
for (const auto& person : myAttributeCarriers->getDemandElements().at(persontag)) {
1896
if (person.second->getChildDemandElements().size() > 0) {
1897
// get person plan
1898
GNEDemandElement* personPlan = person.second->getChildDemandElements().front();
1899
// iterate over all personPlans
1900
while (personPlan) {
1901
// check if personPlan is a stopPerson over edge
1902
if (personPlan->getTagProperty()->getTag() == GNE_TAG_STOPPERSON_EDGE) {
1903
// get previous person plan
1904
GNEDemandElement* previousPersonPlan = person.second->getPreviousChildDemandElement(personPlan);
1905
// check if arrivalPos of previous personPlan is different of endPos of stopPerson
1906
if (previousPersonPlan && previousPersonPlan->getTagProperty()->hasAttribute(SUMO_ATTR_ARRIVALPOS) &&
1907
(previousPersonPlan->getAttribute(SUMO_ATTR_ARRIVALPOS) != personPlan->getAttribute(SUMO_ATTR_ENDPOS))) {
1908
personPlanMap[previousPersonPlan] = personPlan->getAttribute(SUMO_ATTR_ENDPOS);
1909
}
1910
}
1911
// go to next person plan
1912
personPlan = person.second->getNextChildDemandElement(personPlan);
1913
}
1914
}
1915
}
1916
}
1917
// continue if there is personPlanMap to adjust
1918
if (personPlanMap.size() > 0) {
1919
// begin undo list
1920
undoList->begin(GUIIcon::MODEPERSONPLAN, TL("adjust person plans"));
1921
// iterate over invalidDemandElements
1922
for (const auto& personPlan : personPlanMap) {
1923
// set arrivalPos attribute
1924
personPlan.first->setAttribute(SUMO_ATTR_ARRIVALPOS, personPlan.second, undoList);
1925
}
1926
// end undo list
1927
undoList->end();
1928
}
1929
}
1930
1931
1932
void
1933
GNENet::cleanInvalidDemandElements(GNEUndoList* undoList) {
1934
// first declare a vector to save all invalid demand elements
1935
std::vector<GNEDemandElement*> invalidDemandElements;
1936
invalidDemandElements.reserve(myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE).size() +
1937
myAttributeCarriers->getDemandElements().at(SUMO_TAG_FLOW).size() +
1938
myAttributeCarriers->getDemandElements().at(SUMO_TAG_TRIP).size());
1939
// iterate over routes
1940
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
1941
if (route.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
1942
invalidDemandElements.push_back(route.second);
1943
}
1944
}
1945
// iterate over flows
1946
for (const auto& flow : myAttributeCarriers->getDemandElements().at(SUMO_TAG_FLOW)) {
1947
if (flow.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
1948
invalidDemandElements.push_back(flow.second);
1949
}
1950
}
1951
// iterate over trip
1952
for (const auto& trip : myAttributeCarriers->getDemandElements().at(SUMO_TAG_TRIP)) {
1953
if (trip.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
1954
invalidDemandElements.push_back(trip.second);
1955
}
1956
}
1957
// continue if there is invalidDemandElements to remove
1958
if (invalidDemandElements.size() > 0) {
1959
// begin undo list
1960
undoList->begin(GUIIcon::MODEDELETE, TL("remove invalid demand elements"));
1961
// iterate over invalidDemandElements
1962
for (const auto& invalidDemandElement : invalidDemandElements) {
1963
// simply call GNEChange_DemandElement
1964
undoList->add(new GNEChange_DemandElement(invalidDemandElement, false), true);
1965
}
1966
// end undo list
1967
undoList->end();
1968
}
1969
}
1970
1971
void
1972
GNENet::replaceJunctionByGeometry(GNEJunction* junction, GNEUndoList* undoList) {
1973
if (junction->getNBNode()->checkIsRemovable()) {
1974
// start operation
1975
undoList->begin(junction, TL("replace junction by geometry"));
1976
// obtain Edges to join
1977
std::vector<std::pair<NBEdge*, NBEdge*> > edgesToJoin = junction->getNBNode()->getEdgesToJoin();
1978
// clear connections of junction to replace
1979
clearJunctionConnections(junction, undoList);
1980
// iterate over NBEdges to join
1981
for (auto edgePair : edgesToJoin) {
1982
// obtain GNEEdges
1983
GNEEdge* begin = myAttributeCarriers->getEdges().at(edgePair.first->getID());
1984
GNEEdge* continuation = myAttributeCarriers->getEdges().at(edgePair.second->getID());
1985
// remove connections between the edges
1986
std::vector<NBEdge::Connection> connections = begin->getNBEdge()->getConnections();
1987
for (auto con : connections) {
1988
undoList->add(new GNEChange_Connection(begin, con, false, false), true);
1989
}
1990
// fix shape of replaced edge
1991
PositionVector newShape = begin->getNBEdge()->getInnerGeometry();
1992
newShape.push_back(junction->getNBNode()->getPosition());
1993
// replace incoming edge
1994
replaceIncomingEdge(continuation, begin, undoList);
1995
1996
newShape.append(continuation->getNBEdge()->getInnerGeometry());
1997
begin->setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
1998
begin->setAttribute(SUMO_ATTR_ENDOFFSET, continuation->getAttribute(SUMO_ATTR_ENDOFFSET), undoList);
1999
begin->setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList);
2000
begin->getNBEdge()->resetNodeBorder(begin->getNBEdge()->getToNode());
2001
// fix loaded lengths
2002
if (begin->getNBEdge()->hasLoadedLength() || continuation->getNBEdge()->hasLoadedLength()) {
2003
begin->setAttribute(SUMO_ATTR_LENGTH, toString(begin->getNBEdge()->getLoadedLength() + continuation->getNBEdge()->getLoadedLength()), undoList);
2004
}
2005
}
2006
//delete replaced junction
2007
deleteJunction(junction, undoList);
2008
// finish operation
2009
undoList->end();
2010
} else {
2011
throw ProcessError(TL("Junction isn't removable"));
2012
}
2013
}
2014
2015
2016
void
2017
GNENet::splitJunction(GNEJunction* junction, bool reconnect, GNEUndoList* undoList) {
2018
std::vector<std::pair<Position, std::string> > endpoints = junction->getNBNode()->getEndPoints();
2019
if (endpoints.size() < 2) {
2020
return;
2021
}
2022
// start operation
2023
undoList->begin(junction, TL("split junction"));
2024
// record connections
2025
std::map<std::pair<std::string, GNEEdge*>, std::vector<NBEdge::Connection>> straightConnections;
2026
for (GNEEdge* e : junction->getGNEIncomingEdges()) {
2027
for (const auto& c : e->getNBEdge()->getConnections()) {
2028
if (c.fromLane >= 0 && junction->getNBNode()->getDirection(e->getNBEdge(), c.toEdge) == LinkDirection::STRAIGHT) {
2029
straightConnections[std::make_pair(e->getID(), e)].push_back(c);
2030
}
2031
};
2032
}
2033
junction->setLogicValid(false, undoList);
2034
for (const auto& pair : endpoints) {
2035
const Position& pos = pair.first;
2036
const std::string& origID = pair.second;
2037
GNEJunction* newJunction = createJunction(pos, undoList);
2038
std::string newID = origID != "" ? origID : newJunction->getID();
2039
// make a copy because the original vectors are modified during iteration
2040
const std::vector<GNEEdge*> incoming = junction->getGNEIncomingEdges();
2041
const std::vector<GNEEdge*> outgoing = junction->getGNEOutgoingEdges();
2042
//std::cout << " checkEndpoint " << pair.first << " " << pair.second << " newID=" << newID << "\n";
2043
for (GNEEdge* e : incoming) {
2044
//std::cout << " incoming " << e->getID() << " pos=" << pos << " origTo=" << e->getNBEdge()->getParameter("origTo") << " newID=" << newID << "\n";
2045
if (e->getNBEdge()->getGeometry().back().almostSame(pos) || e->getNBEdge()->getParameter("origTo") == newID) {
2046
//std::cout << " match\n";
2047
GNEChange_Attribute::changeAttribute(e, SUMO_ATTR_TO, newJunction->getID(), undoList);
2048
}
2049
}
2050
for (GNEEdge* e : outgoing) {
2051
//std::cout << " outgoing " << e->getID() << " pos=" << pos << " origFrom=" << e->getNBEdge()->getParameter("origFrom") << " newID=" << newID << "\n";
2052
if (e->getNBEdge()->getGeometry().front().almostSame(pos) || e->getNBEdge()->getParameter("origFrom") == newID) {
2053
//std::cout << " match\n";
2054
GNEChange_Attribute::changeAttribute(e, SUMO_ATTR_FROM, newJunction->getID(), undoList);
2055
}
2056
}
2057
if (newID != newJunction->getID()) {
2058
if (newJunction->isValid(SUMO_ATTR_ID, newID)) {
2059
GNEChange_Attribute::changeAttribute(newJunction, SUMO_ATTR_ID, newID, undoList);
2060
} else {
2061
WRITE_WARNINGF(TL("Could not rename split node to '%'"), newID);
2062
}
2063
}
2064
}
2065
// recreate edges from straightConnections
2066
if (reconnect) {
2067
for (const auto& item : straightConnections) {
2068
GNEEdge* in = item.first.second;
2069
std::map<std::pair<std::string, NBEdge*>, GNEEdge*> newEdges;
2070
for (auto& c : item.second) {
2071
GNEEdge* out = myAttributeCarriers->retrieveEdge(c.toEdge->getID());
2072
GNEEdge* newEdge = nullptr;
2073
if (in->getToJunction() == out->getFromJunction()) {
2074
continue;
2075
}
2076
if (newEdges.count(std::make_pair(c.toEdge->getID(), c.toEdge)) == 0) {
2077
newEdge = createEdge(in->getToJunction(), out->getFromJunction(), in, undoList);
2078
if (newEdge) {
2079
newEdges[std::make_pair(c.toEdge->getID(), c.toEdge)] = newEdge;
2080
newEdge->setAttribute(SUMO_ATTR_NUMLANES, "1", undoList);
2081
}
2082
} else {
2083
newEdge = newEdges[std::make_pair(c.toEdge->getID(), c.toEdge)];
2084
duplicateLane(newEdge->getChildLanes().back(), undoList, true);
2085
}
2086
if (newEdge) {
2087
// copy permissions
2088
newEdge->getChildLanes().back()->setAttribute(SUMO_ATTR_ALLOW,
2089
in->getChildLanes()[c.fromLane]-> getAttribute(SUMO_ATTR_ALLOW), undoList);
2090
}
2091
}
2092
}
2093
}
2094
deleteJunction(junction, undoList);
2095
// finish operation
2096
undoList->end();
2097
}
2098
2099
2100
2101
void
2102
GNENet::clearJunctionConnections(GNEJunction* junction, GNEUndoList* undoList) {
2103
undoList->begin(GUIIcon::MODEDELETE, TL("clear junction connections"));
2104
std::vector<GNEConnection*> connections = junction->getGNEConnections();
2105
// Iterate over all connections and clear it
2106
for (auto i : connections) {
2107
deleteConnection(i, undoList);
2108
}
2109
undoList->end();
2110
}
2111
2112
2113
void
2114
GNENet::resetJunctionConnections(GNEJunction* junction, GNEUndoList* undoList) {
2115
undoList->begin(junction, TL("reset junction connections"));
2116
// first clear connections
2117
clearJunctionConnections(junction, undoList);
2118
// invalidate logic to create new connections in the next recomputing
2119
junction->setLogicValid(false, undoList);
2120
undoList->end();
2121
}
2122
2123
2124
void
2125
GNENet::clearAdditionalElements(GNEUndoList* undoList) {
2126
undoList->begin(GUIIcon::MODEDELETE, TL("clear additional elements"));
2127
// clear additionals
2128
for (const auto& additionalMap : myAttributeCarriers->getAdditionals()) {
2129
while (additionalMap.second.size() > 0) {
2130
deleteAdditional(additionalMap.second.begin()->second, undoList);
2131
}
2132
}
2133
undoList->end();
2134
}
2135
2136
2137
void
2138
GNENet::clearDemandElements(GNEUndoList* undoList) {
2139
undoList->begin(GUIIcon::MODEDELETE, TL("clear demand elements"));
2140
// clear demand elements
2141
for (const auto& demandElementsMap : myAttributeCarriers->getDemandElements()) {
2142
if (demandElementsMap.first != SUMO_TAG_VTYPE) {
2143
while (demandElementsMap.second.size() > 0) {
2144
deleteDemandElement(demandElementsMap.second.begin()->second, undoList);
2145
}
2146
}
2147
}
2148
// special case for vTypes
2149
const std::unordered_map<const GUIGlObject*, GNEDemandElement*> types = myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE);
2150
for (const auto& type : types) {
2151
if (type.second->getAttribute(GNE_ATTR_DEFAULT_VTYPE) == GNEAttributeCarrier::FALSE_STR) {
2152
deleteDemandElement(type.second, undoList);
2153
}
2154
}
2155
undoList->end();
2156
}
2157
2158
2159
void
2160
GNENet::clearDataElements(GNEUndoList* undoList) {
2161
undoList->begin(GUIIcon::MODEDELETE, TL("clear data elements"));
2162
// clear data sets
2163
while (myAttributeCarriers->getDataSets().size() > 0) {
2164
deleteDataSet(myAttributeCarriers->getDataSets().begin()->second, undoList);
2165
}
2166
undoList->end();
2167
}
2168
2169
2170
void
2171
GNENet::clearMeanDataElements(GNEUndoList* undoList) {
2172
undoList->begin(GUIIcon::MODEDELETE, TL("clear meanData elements"));
2173
// clear meanDatas
2174
for (const auto& meanDataMap : myAttributeCarriers->getMeanDatas()) {
2175
while (meanDataMap.second.size() > 0) {
2176
deleteMeanData(meanDataMap.second.begin()->second, undoList);
2177
}
2178
}
2179
undoList->end();
2180
}
2181
2182
2183
void
2184
GNENet::changeEdgeEndpoints(GNEEdge* edge, const std::string& newSource, const std::string& newDest) {
2185
NBNode* from = myAttributeCarriers->retrieveJunction(newSource)->getNBNode();
2186
NBNode* to = myAttributeCarriers->retrieveJunction(newDest)->getNBNode();
2187
edge->getNBEdge()->reinitNodes(from, to);
2188
requireRecompute();
2189
}
2190
2191
2192
GNEViewNet*
2193
GNENet::getViewNet() const {
2194
return myViewNet;
2195
}
2196
2197
2198
NBTrafficLightLogicCont&
2199
GNENet::getTLLogicCont() {
2200
return myNetBuilder->getTLLogicCont();
2201
}
2202
2203
2204
NBEdgeCont&
2205
GNENet::getEdgeCont() {
2206
return myNetBuilder->getEdgeCont();
2207
}
2208
2209
2210
void
2211
GNENet::addExplicitTurnaround(std::string id) {
2212
myExplicitTurnarounds.insert(id);
2213
}
2214
2215
2216
void
2217
GNENet::removeExplicitTurnaround(std::string id) {
2218
myExplicitTurnarounds.erase(id);
2219
}
2220
2221
2222
bool
2223
GNENet::saveAdditionals() {
2224
// obtain invalid additionals depending of number of their parent lanes
2225
std::vector<GNEAdditional*> invalidAdditionals;
2226
// iterate over additionals and obtain invalids
2227
for (const auto& additionalPair : myAttributeCarriers->getAdditionals()) {
2228
for (const auto& addditional : additionalPair.second) {
2229
// check if has to be fixed
2230
if (!addditional.second->isAdditionalValid()) {
2231
invalidAdditionals.push_back(addditional.second);
2232
}
2233
}
2234
}
2235
// if there are invalid additionls, open GNEFixAdditionalElementsDialog
2236
if (invalidAdditionals.size() > 0) {
2237
// open fix additional elements dialog
2238
const auto fixAdditionalElements = GNEFixAdditionalElementsDialog(myViewNet->getViewParent()->getGNEAppWindows(),
2239
invalidAdditionals);
2240
if (fixAdditionalElements.getResult() != GNEDialog::Result::ACCEPT) {
2241
return false;
2242
}
2243
}
2244
saveAdditionalsConfirmed();
2245
return true;
2246
}
2247
2248
2249
bool
2250
GNENet::saveJuPedSimElements(const std::unordered_set<const GNEAttributeCarrier*>& ACs, const std::string& file) {
2251
OutputDevice& device = OutputDevice::getDevice(file);
2252
// open header
2253
device.writeXMLHeader("additional", "additional_file.xsd", EMPTY_HEADER, false);
2254
// juPedSim elements
2255
writeJuPedSimComment(device, ACs);
2256
writeAdditionalByType(device, ACs, {GNE_TAG_JPS_WALKABLEAREA});
2257
writeAdditionalByType(device, ACs, {GNE_TAG_JPS_OBSTACLE});
2258
// close device
2259
device.close();
2260
// set focus again in net
2261
myViewNet->setFocus();
2262
return true;
2263
}
2264
2265
2266
bool
2267
GNENet::saveDemandElements() {
2268
// first recompute demand elements
2269
computeDemandElements(myViewNet->getViewParent()->getGNEAppWindows());
2270
// obtain invalid demandElements depending of number of their parent lanes
2271
std::vector<GNEDemandElement*> invalidSingleLaneDemandElements;
2272
// iterate over demandElements and obtain invalids
2273
for (const auto& demandElementSet : myAttributeCarriers->getDemandElements()) {
2274
for (const auto& demandElement : demandElementSet.second) {
2275
// compute before check if demand element is valid
2276
demandElement.second->computePathElement();
2277
// check if has to be fixed
2278
if (demandElement.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
2279
invalidSingleLaneDemandElements.push_back(demandElement.second);
2280
}
2281
}
2282
}
2283
// if there are invalid demand elements, open GNEFixDemandElementsDialog
2284
if (invalidSingleLaneDemandElements.size() > 0) {
2285
// open fix demand elements dialog
2286
const auto fixDemandElement = GNEFixDemandElementsDialog(myViewNet->getViewParent()->getGNEAppWindows(),
2287
invalidSingleLaneDemandElements);
2288
if (fixDemandElement.getResult() != GNEDialog::Result::ACCEPT) {
2289
return false;
2290
}
2291
}
2292
saveDemandElementsConfirmed();
2293
return true;
2294
}
2295
2296
2297
bool
2298
GNENet::saveDataElements() {
2299
// first recompute data sets
2300
computeDataElements(myViewNet->getViewParent()->getGNEAppWindows());
2301
// save data elements
2302
saveDataElementsConfirmed();
2303
// set focus again in net
2304
myViewNet->setFocus();
2305
return true;
2306
}
2307
2308
2309
double
2310
GNENet::getDataSetIntervalMinimumBegin() const {
2311
double minimumBegin = 0;
2312
// update with first minimum (if exist)
2313
if (myAttributeCarriers->getDataIntervals().size() > 0) {
2314
minimumBegin = myAttributeCarriers->getDataIntervals().begin()->second->getAttributeDouble(SUMO_ATTR_BEGIN);
2315
}
2316
// iterate over interval
2317
for (const auto& interval : myAttributeCarriers->getDataIntervals()) {
2318
if (interval.second->getAttributeDouble(SUMO_ATTR_BEGIN) < minimumBegin) {
2319
minimumBegin = interval.second->getAttributeDouble(SUMO_ATTR_BEGIN);
2320
}
2321
}
2322
return minimumBegin;
2323
}
2324
2325
2326
double
2327
GNENet::getDataSetIntervalMaximumEnd() const {
2328
double maximumEnd = 0;
2329
// update with first maximum (if exist)
2330
if (myAttributeCarriers->getDataIntervals().size() > 0) {
2331
maximumEnd = myAttributeCarriers->getDataIntervals().begin()->second->getAttributeDouble(SUMO_ATTR_END);
2332
}
2333
// iterate over intervals
2334
for (const auto& interval : myAttributeCarriers->getDataIntervals()) {
2335
if (interval.second->getAttributeDouble(SUMO_ATTR_END) > maximumEnd) {
2336
maximumEnd = interval.second->getAttributeDouble(SUMO_ATTR_END);
2337
}
2338
}
2339
return maximumEnd;
2340
}
2341
2342
2343
bool
2344
GNENet::saveMeanDatas() {
2345
saveMeanDatasConfirmed();
2346
// set focus again in net
2347
myViewNet->setFocus();
2348
return true;
2349
}
2350
2351
2352
void
2353
GNENet::saveAdditionalsConfirmed() {
2354
// Start saving additionals
2355
getApp()->beginWaitCursor();
2356
// get all additionales separated by filenames
2357
const auto additionalByFilenames = mySavingFilesHandler->getAdditionalsByFilename();
2358
// update netedit connfig
2359
mySavingFilesHandler->updateNeteditConfig();
2360
// iterate over all elements and save files
2361
for (const auto& additionalsByFilename : additionalByFilenames) {
2362
// open file
2363
OutputDevice& device = OutputDevice::getDevice(additionalsByFilename.first);
2364
// open header
2365
device.writeXMLHeader("additional", "additional_file.xsd", EMPTY_HEADER, false);
2366
// write vTypes with additional childrens (due calibrators)
2367
writeVTypeComment(device, additionalsByFilename.second, true);
2368
writeVTypes(device, additionalsByFilename.second, true);
2369
// write routes with additional children (due route prob reroutes)
2370
writeRouteComment(device, additionalsByFilename.second, true);
2371
writeRoutes(device, additionalsByFilename.second, true);
2372
// routeProbes
2373
writeRouteProbeComment(device, additionalsByFilename.second);
2374
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_ROUTEPROBE});
2375
// calibrator
2376
writeCalibratorComment(device, additionalsByFilename.second);
2377
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_CALIBRATOR, GNE_TAG_CALIBRATOR_LANE});
2378
// stoppingPlaces
2379
writeStoppingPlaceComment(device, additionalsByFilename.second);
2380
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_BUS_STOP});
2381
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_TRAIN_STOP});
2382
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_CONTAINER_STOP});
2383
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_PARKING_AREA});
2384
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_CHARGING_STATION});
2385
// detectors
2386
writeDetectorComment(device, additionalsByFilename.second);
2387
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_INDUCTION_LOOP});
2388
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_INSTANT_INDUCTION_LOOP});
2389
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_LANE_AREA_DETECTOR, GNE_TAG_MULTI_LANE_AREA_DETECTOR});
2390
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_ENTRY_EXIT_DETECTOR});
2391
// Other additionals
2392
writeOtherAdditionalsComment(device, additionalsByFilename.second);
2393
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_REROUTER});
2394
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_VSS});
2395
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_VAPORIZER});
2396
// shapes
2397
writeShapesComment(device, additionalsByFilename.second);
2398
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_POLY});
2399
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_POI, GNE_TAG_POILANE, GNE_TAG_POIGEO});
2400
// TAZs
2401
writeTAZComment(device, additionalsByFilename.second);
2402
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_TAZ});
2403
// Wire element
2404
writeWireComment(device, additionalsByFilename.second);
2405
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_TRACTION_SUBSTATION});
2406
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_OVERHEAD_WIRE_SECTION});
2407
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_OVERHEAD_WIRE_CLAMP});
2408
// juPedSim elements
2409
writeJuPedSimComment(device, additionalsByFilename.second);
2410
writeAdditionalByType(device, additionalsByFilename.second, {GNE_TAG_JPS_WALKABLEAREA});
2411
writeAdditionalByType(device, additionalsByFilename.second, {GNE_TAG_JPS_OBSTACLE});
2412
// close device
2413
device.close();
2414
}
2415
// mark additionals as saved
2416
mySavingStatus->additionalsSaved();
2417
// end saving additionals
2418
getApp()->endWaitCursor();
2419
}
2420
2421
2422
void
2423
GNENet::saveDemandElementsConfirmed() {
2424
// Start saving additionals
2425
getApp()->beginWaitCursor();
2426
// get all demand elements separated by filenames
2427
const auto demandByFilenames = mySavingFilesHandler->getDemandsByFilename();
2428
// update netedit connfig
2429
mySavingFilesHandler->updateNeteditConfig();
2430
// iterate over all elements and save files
2431
for (const auto& demandByFilename : demandByFilenames) {
2432
// open file
2433
OutputDevice& device = OutputDevice::getDevice(demandByFilename.first);
2434
// open header
2435
device.writeXMLHeader("routes", "routes_file.xsd", EMPTY_HEADER, false);
2436
// first write all vTypeDistributions (and their vTypes)
2437
writeVTypeComment(device, demandByFilename.second, false);
2438
writeVTypes(device, demandByFilename.second, false);
2439
writeVTypeDistributions(device, demandByFilename.second);
2440
// now write all routes (and their associated stops), except routes with additional children (due routeProbReroutes)
2441
writeRouteComment(device, demandByFilename.second, false);
2442
writeRoutes(device, demandByFilename.second, false);
2443
writeRouteDistributions(device, demandByFilename.second);
2444
// sort vehicles/persons by depart
2445
std::map<double, std::map<std::pair<SumoXMLTag, std::string>, GNEDemandElement*> > vehiclesSortedByDepart;
2446
for (const auto& demandElementTag : myAttributeCarriers->getDemandElements()) {
2447
for (const auto& demandElement : demandElementTag.second) {
2448
if (demandElement.second->getTagProperty()->isVehicle() || demandElement.second->getTagProperty()->isPerson() || demandElement.second->getTagProperty()->isContainer()) {
2449
vehiclesSortedByDepart[demandElement.second->getAttributeDouble(SUMO_ATTR_DEPART)][std::make_pair(demandElement.second->getTagProperty()->getTag(), demandElement.second->getID())] = demandElement.second;
2450
}
2451
}
2452
}
2453
// finally write all vehicles, persons and containers sorted by depart time (and their associated stops, personPlans, etc.)
2454
if (vehiclesSortedByDepart.size() > 0) {
2455
device << (" <!-- Vehicles, persons and containers (sorted by depart) -->\n");
2456
for (const auto& vehicleTag : vehiclesSortedByDepart) {
2457
for (const auto& vehicle : vehicleTag.second) {
2458
if (demandByFilename.second.count(vehicle.second) > 0) {
2459
vehicle.second->writeDemandElement(device);
2460
}
2461
}
2462
}
2463
}
2464
// close device
2465
device.close();
2466
}
2467
// mark demand elements as saved
2468
mySavingStatus->demandElementsSaved();
2469
// end saving additionals
2470
getApp()->endWaitCursor();
2471
}
2472
2473
2474
void
2475
GNENet::saveDataElementsConfirmed() {
2476
// Start saving additionals
2477
getApp()->beginWaitCursor();
2478
// get all data elements separated by filenames
2479
const auto dataByFilenames = mySavingFilesHandler->getDatasByFilename();
2480
// update netedit connfig
2481
mySavingFilesHandler->updateNeteditConfig();
2482
// iterate over all elements and save files
2483
for (const auto& dataByFilename : dataByFilenames) {
2484
OutputDevice& device = OutputDevice::getDevice(dataByFilename.first);
2485
device.writeXMLHeader("data", "datamode_file.xsd", EMPTY_HEADER, false);
2486
// write all data sets
2487
for (const auto& dataSet : myAttributeCarriers->getDataSets()) {
2488
if (dataByFilename.second.count(dataSet.second) > 0) {
2489
dataSet.second->writeDataSet(device);
2490
}
2491
}
2492
// close device
2493
device.close();
2494
}
2495
// mark data element as saved
2496
mySavingStatus->dataElementsSaved();
2497
// end saving additionals
2498
getApp()->endWaitCursor();
2499
}
2500
2501
2502
void
2503
GNENet::saveMeanDatasConfirmed() {
2504
// Start saving additionals
2505
getApp()->beginWaitCursor();
2506
// get all meanData separated by filenames
2507
const auto meanDataByFilenames = mySavingFilesHandler->getMeanDatasByFilename();
2508
// update netedit connfig
2509
mySavingFilesHandler->updateNeteditConfig();
2510
// iterate over all elements and save files
2511
for (const auto& meanDataByFilename : meanDataByFilenames) {
2512
// open file
2513
OutputDevice& device = OutputDevice::getDevice(meanDataByFilename.first);
2514
// open header
2515
device.writeXMLHeader("additional", "additional_file.xsd", EMPTY_HEADER, false);
2516
// MeanDataEdges
2517
writeMeanDataEdgeComment(device);
2518
writeMeanDatas(device, meanDataByFilename.second, SUMO_TAG_MEANDATA_EDGE);
2519
// MeanDataLanes
2520
writeMeanDataLaneComment(device);
2521
writeMeanDatas(device, meanDataByFilename.second, SUMO_TAG_MEANDATA_LANE);
2522
// close device
2523
device.close();
2524
}
2525
// mark mean datas as saved
2526
mySavingStatus->meanDatasSaved();
2527
// end saving additionals
2528
getApp()->endWaitCursor();
2529
}
2530
2531
2532
void
2533
GNENet::writeAdditionalByType(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs,
2534
const std::vector<SumoXMLTag> tags) const {
2535
std::map<std::string, std::vector<GNEAdditional*> > sortedAdditionals;
2536
for (const auto& tag : tags) {
2537
for (const auto& additional : myAttributeCarriers->getAdditionals().at(tag)) {
2538
if ((tag == SUMO_TAG_VAPORIZER) || (sortedAdditionals.count(additional.second->getID()) == 0)) {
2539
sortedAdditionals[additional.second->getID()].push_back(additional.second);
2540
} else {
2541
throw ProcessError(TL("Duplicated ID"));
2542
}
2543
}
2544
}
2545
for (const auto& additionalVector : sortedAdditionals) {
2546
for (const auto& additional : additionalVector.second) {
2547
if (ACs.count(additional) > 0) {
2548
additional->writeAdditional(device);
2549
}
2550
}
2551
}
2552
}
2553
2554
2555
void
2556
GNENet::writeDemandByType(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, SumoXMLTag tag) const {
2557
std::map<std::string, GNEDemandElement*> sortedDemandElements;
2558
for (const auto& demandElement : myAttributeCarriers->getDemandElements().at(tag)) {
2559
if (ACs.count(demandElement.second) > 0) {
2560
sortedDemandElements[demandElement.second->getID()] = demandElement.second;
2561
}
2562
}
2563
for (const auto& demandElement : sortedDemandElements) {
2564
demandElement.second->writeDemandElement(device);
2565
}
2566
}
2567
2568
2569
void
2570
GNENet::writeRouteDistributions(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2571
std::map<std::string, GNEDemandElement*> sortedElements;
2572
// first write route Distributions
2573
for (const auto& routeDistribution : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE_DISTRIBUTION)) {
2574
if (ACs.count(routeDistribution.second) > 0) {
2575
sortedElements[routeDistribution.second->getID()] = routeDistribution.second;
2576
}
2577
}
2578
for (const auto& element : sortedElements) {
2579
element.second->writeDemandElement(device);
2580
}
2581
sortedElements.clear();
2582
}
2583
2584
2585
void
2586
GNENet::writeRoutes(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
2587
std::map<std::string, GNEDemandElement*> sortedRoutes;
2588
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
2589
if (ACs.count(route.second) > 0) {
2590
// first check if element is part of a distribution
2591
int numRefs = 0;
2592
for (const auto vTypeChild : route.second->getChildDemandElements()) {
2593
if (vTypeChild->getTagProperty()->getTag() == GNE_TAG_ROUTEREF) {
2594
numRefs++;
2595
}
2596
}
2597
// routes with reference 1 will be saved in route distribution
2598
if (numRefs != 1) {
2599
if ((additionalFile && (route.second->getChildAdditionals().size() > 0)) ||
2600
(!additionalFile && (route.second->getChildAdditionals().size() == 0))) {
2601
sortedRoutes[route.second->getID()] = route.second;
2602
}
2603
}
2604
}
2605
}
2606
for (const auto& route : sortedRoutes) {
2607
route.second->writeDemandElement(device);
2608
}
2609
}
2610
2611
2612
void
2613
GNENet::writeVTypeDistributions(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2614
std::map<std::string, GNEDemandElement*> sortedElements;
2615
// first write vType Distributions
2616
for (const auto& vTypeDistribution : myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE_DISTRIBUTION)) {
2617
if (ACs.count(vTypeDistribution.second) > 0) {
2618
sortedElements[vTypeDistribution.second->getID()] = vTypeDistribution.second;
2619
}
2620
}
2621
for (const auto& element : sortedElements) {
2622
element.second->writeDemandElement(device);
2623
}
2624
sortedElements.clear();
2625
}
2626
2627
2628
void
2629
GNENet::writeVTypes(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
2630
std::map<std::string, GNEDemandElement*> sortedVTypes;
2631
for (const auto& vType : myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE)) {
2632
if (ACs.count(vType.second) > 0) {
2633
// first check if element is part of a distribution
2634
int numRefs = 0;
2635
for (const auto vTypeChild : vType.second->getChildDemandElements()) {
2636
if (vTypeChild->getTagProperty()->getTag() == GNE_TAG_VTYPEREF) {
2637
numRefs++;
2638
}
2639
}
2640
// vTypes with reference 1 will be saved in vType distribution
2641
if (numRefs != 1) {
2642
if ((additionalFile && (vType.second->getChildAdditionals().size() > 0)) ||
2643
(!additionalFile && (vType.second->getChildAdditionals().size() == 0))) {
2644
sortedVTypes[vType.second->getID()] = vType.second;
2645
}
2646
}
2647
}
2648
}
2649
for (const auto& vType : sortedVTypes) {
2650
vType.second->writeDemandElement(device);
2651
}
2652
}
2653
2654
2655
void
2656
GNENet::writeMeanDatas(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, SumoXMLTag tag) const {
2657
std::map<std::string, GNEMeanData*> sortedMeanDatas;
2658
for (const auto& meanData : myAttributeCarriers->getMeanDatas().at(tag)) {
2659
if (ACs.count(meanData.second) > 0) {
2660
if (sortedMeanDatas.count(meanData.second->getID()) == 0) {
2661
sortedMeanDatas[meanData.second->getID()] = meanData.second;
2662
} else {
2663
throw ProcessError(TL("Duplicated ID"));
2664
}
2665
}
2666
}
2667
for (const auto& additional : sortedMeanDatas) {
2668
additional.second->writeMeanData(device);
2669
}
2670
}
2671
2672
bool
2673
GNENet::writeVTypeComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
2674
// vTypes
2675
for (const auto& vType : myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE)) {
2676
// special case for default vTypes
2677
const bool defaultVType = GNEAttributeCarrier::parse<bool>(vType.second->getAttribute(GNE_ATTR_DEFAULT_VTYPE));
2678
const bool defaultVTypeModified = GNEAttributeCarrier::parse<bool>(vType.second->getAttribute(GNE_ATTR_DEFAULT_VTYPE_MODIFIED));
2679
// only write default vType modified
2680
if ((vType.second->getParentDemandElements().size() == 0) && (!defaultVType || (defaultVType && defaultVTypeModified))) {
2681
if (ACs.count(vType.second) > 0) {
2682
if (additionalFile && (vType.second->getChildAdditionals().size() != 0)) {
2683
device << (" <!-- VTypes (used in calibratorFlows) -->\n");
2684
return true;
2685
} else if (!additionalFile && (vType.second->getChildAdditionals().size() == 0)) {
2686
device << (" <!-- VTypes -->\n");
2687
return true;
2688
}
2689
}
2690
}
2691
}
2692
return false;
2693
}
2694
2695
2696
bool
2697
GNENet::writeRouteComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
2698
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
2699
if (ACs.count(route.second) > 0) {
2700
if (additionalFile && (route.second->getChildAdditionals().size() != 0)) {
2701
device << (" <!-- Routes (used in RouteProbReroutes and calibratorFlows) -->\n");
2702
return true;
2703
} else if (!additionalFile && (route.second->getChildAdditionals().size() == 0)) {
2704
device << (" <!-- Routes -->\n");
2705
return true;
2706
}
2707
}
2708
}
2709
return false;
2710
}
2711
2712
2713
bool
2714
GNENet::writeRouteProbeComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2715
for (const auto& AC : ACs) {
2716
if (AC->getTagProperty()->getTag() == SUMO_TAG_ROUTEPROBE) {
2717
device << (" <!-- RouteProbes -->\n");
2718
return true;
2719
}
2720
}
2721
return false;
2722
}
2723
2724
2725
bool
2726
GNENet::writeCalibratorComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2727
for (const auto& AC : ACs) {
2728
if (AC->getTagProperty()->isCalibrator()) {
2729
device << (" <!-- Calibrators -->\n");
2730
return true;
2731
}
2732
}
2733
return false;
2734
}
2735
2736
2737
bool
2738
GNENet::writeStoppingPlaceComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2739
for (const auto& AC : ACs) {
2740
if (AC->getTagProperty()->isStoppingPlace()) {
2741
device << (" <!-- StoppingPlaces -->\n");
2742
return true;
2743
}
2744
}
2745
return false;
2746
}
2747
2748
2749
bool
2750
GNENet::writeDetectorComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2751
for (const auto& AC : ACs) {
2752
if (AC->getTagProperty()->isDetector()) {
2753
device << (" <!-- Detectors -->\n");
2754
return true;
2755
}
2756
}
2757
return false;
2758
}
2759
2760
2761
bool
2762
GNENet::writeOtherAdditionalsComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2763
for (const auto& AC : ACs) {
2764
if (AC->getTagProperty()->isAdditionalPureElement() &&
2765
!AC->getTagProperty()->isStoppingPlace() &&
2766
!AC->getTagProperty()->isDetector() &&
2767
!AC->getTagProperty()->isCalibrator() &&
2768
(AC->getTagProperty()->getTag() != SUMO_TAG_ROUTEPROBE) &&
2769
(AC->getTagProperty()->getTag() != SUMO_TAG_ACCESS) &&
2770
(AC->getTagProperty()->getTag() != SUMO_TAG_PARKING_SPACE)) {
2771
device << (" <!-- Other additionals -->\n");
2772
return true;
2773
}
2774
}
2775
return false;
2776
}
2777
2778
2779
bool
2780
GNENet::writeShapesComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2781
for (const auto& AC : ACs) {
2782
if (AC->getTagProperty()->isShapeElement() && !AC->getTagProperty()->isJuPedSimElement()) {
2783
device << (" <!-- Shapes -->\n");
2784
return true;
2785
}
2786
}
2787
return false;
2788
}
2789
2790
2791
bool
2792
GNENet::writeJuPedSimComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2793
for (const auto& AC : ACs) {
2794
if (AC->getTagProperty()->isJuPedSimElement()) {
2795
device << (" <!-- JuPedSim elements -->\n");
2796
return true;
2797
}
2798
}
2799
return false;
2800
}
2801
2802
2803
bool
2804
GNENet::writeTAZComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2805
for (const auto& AC : ACs) {
2806
if (AC->getTagProperty()->getTag() == SUMO_TAG_TAZ) {
2807
device << (" <!-- TAZs -->\n");
2808
return true;
2809
}
2810
}
2811
return false;
2812
}
2813
2814
2815
bool
2816
GNENet::writeWireComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
2817
for (const auto& AC : ACs) {
2818
if (AC->getTagProperty()->isWireElement()) {
2819
device << (" <!-- Wires -->\n");
2820
return true;
2821
}
2822
}
2823
return false;
2824
}
2825
2826
2827
bool
2828
GNENet::writeMeanDataEdgeComment(OutputDevice& device) const {
2829
if (myAttributeCarriers->getMeanDatas().at(SUMO_TAG_MEANDATA_EDGE).size() > 0) {
2830
device << (" <!-- MeanDataEdges -->\n");
2831
return true;
2832
}
2833
return false;
2834
}
2835
2836
2837
bool
2838
GNENet::writeMeanDataLaneComment(OutputDevice& device) const {
2839
if (myAttributeCarriers->getMeanDatas().at(SUMO_TAG_MEANDATA_LANE).size() > 0) {
2840
device << (" <!-- MeanDataLanes -->\n");
2841
return true;
2842
}
2843
return false;
2844
}
2845
2846
2847
void
2848
GNENet::saveTLSPrograms(const std::string& filename) {
2849
// open output device
2850
OutputDevice& device = OutputDevice::getDevice(filename);
2851
device.openTag("additionals");
2852
// write traffic lights using NWWriter
2853
NWWriter_SUMO::writeTrafficLights(device, getTLLogicCont());
2854
device.close();
2855
// change save status
2856
mySavingStatus->TLSSaved();
2857
}
2858
2859
2860
int
2861
GNENet::getNumberOfTLSPrograms() const {
2862
return -1;
2863
}
2864
2865
2866
void
2867
GNENet::saveEdgeTypes(const std::string& filename) {
2868
// first clear typeContainer
2869
myNetBuilder->getTypeCont().clearTypes();
2870
// now update typeContainer with edgeTypes
2871
for (const auto& edgeType : myAttributeCarriers->getEdgeTypes()) {
2872
myNetBuilder->getTypeCont().insertEdgeType(edgeType.first, edgeType.second);
2873
for (int i = 0; i < (int)edgeType.second->getLaneTypes().size(); i++) {
2874
myNetBuilder->getTypeCont().insertLaneType(edgeType.first, i,
2875
edgeType.second->getLaneTypes().at(i)->speed,
2876
edgeType.second->getLaneTypes().at(i)->permissions,
2877
edgeType.second->getLaneTypes().at(i)->width,
2878
edgeType.second->getLaneTypes().at(i)->attrs);
2879
}
2880
}
2881
// open device
2882
OutputDevice& device = OutputDevice::getDevice(filename);
2883
// open tag
2884
device.openTag(SUMO_TAG_TYPES);
2885
// write edge types
2886
myNetBuilder->getTypeCont().writeEdgeTypes(device);
2887
// close tag
2888
device.closeTag();
2889
// close device
2890
device.close();
2891
}
2892
2893
2894
void
2895
GNENet::enableUpdateGeometry() {
2896
myUpdateGeometryEnabled = true;
2897
}
2898
2899
2900
void
2901
GNENet::disableUpdateGeometry() {
2902
myUpdateGeometryEnabled = false;
2903
}
2904
2905
2906
bool
2907
GNENet::isUpdateGeometryEnabled() const {
2908
return myUpdateGeometryEnabled;
2909
}
2910
2911
2912
void
2913
GNENet::enableUpdateData() {
2914
myUpdateDataEnabled = true;
2915
// update data elements
2916
for (const auto& dataInterval : myAttributeCarriers->getDataIntervals()) {
2917
dataInterval.second->updateGenericDataIDs();
2918
dataInterval.second->updateAttributeColors();
2919
}
2920
}
2921
2922
2923
void
2924
GNENet::disableUpdateData() {
2925
myUpdateDataEnabled = false;
2926
}
2927
2928
2929
bool
2930
GNENet::isUpdateDataEnabled() const {
2931
return myUpdateDataEnabled;
2932
}
2933
2934
2935
unsigned int&
2936
GNENet::getJunctionIDCounter() {
2937
return myJunctionIDCounter;
2938
}
2939
2940
2941
unsigned int&
2942
GNENet::getEdgeIDCounter() {
2943
return myEdgeIDCounter;
2944
}
2945
2946
// ===========================================================================
2947
// private
2948
// ===========================================================================
2949
2950
void
2951
GNENet::initJunctionsAndEdges() {
2952
// init edge types
2953
for (const auto& edgeType : myNetBuilder->getTypeCont()) {
2954
// register edge type
2955
myAttributeCarriers->registerEdgeType(new GNEEdgeType(this, edgeType.first, edgeType.second));
2956
}
2957
// init junctions (by default Crossing and walking areas aren't created)
2958
for (const auto& nodeName : myNetBuilder->getNodeCont().getAllNames()) {
2959
// create and register junction
2960
myAttributeCarriers->registerJunction(new GNEJunction(this, myNetBuilder->getNodeCont().retrieve(nodeName), true));
2961
}
2962
// init edges
2963
for (const auto& edgeName : myNetBuilder->getEdgeCont().getAllNames()) {
2964
// create edge using NBEdge
2965
GNEEdge* edge = new GNEEdge(this, myNetBuilder->getEdgeCont().retrieve(edgeName), false, true);
2966
// register edge
2967
myAttributeCarriers->registerEdge(edge);
2968
// add manually child references due initJunctionsAndEdges doesn't use undo-redo
2969
edge->getFromJunction()->addChildElement(edge);
2970
edge->getToJunction()->addChildElement(edge);
2971
// check grid
2972
if (myGrid.getWidth() > 10e16 || myGrid.getHeight() > 10e16) {
2973
throw ProcessError(TL("Network size exceeds 1 Lightyear. Please reconsider your inputs.") + std::string("\n"));
2974
}
2975
}
2976
// make sure myGrid is initialized even for an empty net. This ensure that the network starts with a zoom of 100
2977
if (myAttributeCarriers->getEdges().size() == 0) {
2978
myGrid.add(Boundary(-50, -50, 50, 50));
2979
}
2980
// recalculate all lane2lane connections
2981
for (const auto& edge : myAttributeCarriers->getEdges()) {
2982
for (const auto& lane : edge.second->getChildLanes()) {
2983
lane->updateGeometry();
2984
}
2985
}
2986
// sort nodes edges so that arrows can be drawn correctly
2987
NBNodesEdgesSorter::sortNodesEdges(myNetBuilder->getNodeCont());
2988
}
2989
2990
2991
void
2992
GNENet::initGNEConnections() {
2993
for (const auto& edge : myAttributeCarriers->getEdges()) {
2994
// remake connections
2995
edge.second->remakeGNEConnections();
2996
// update geometry of connections
2997
for (const auto& connection : edge.second->getGNEConnections()) {
2998
connection->updateGeometry();
2999
}
3000
}
3001
}
3002
3003
3004
void
3005
GNENet::computeAndUpdate(OptionsCont& neteditOptions, bool volatileOptions) {
3006
// make sure we only add turn arounds to edges which currently exist within the network
3007
std::set<std::string> liveExplicitTurnarounds;
3008
for (const auto& explicitTurnarounds : myExplicitTurnarounds) {
3009
if (myAttributeCarriers->getEdges().count(explicitTurnarounds) > 0) {
3010
liveExplicitTurnarounds.insert(explicitTurnarounds);
3011
}
3012
}
3013
// removes all junctions of grid
3014
for (const auto& junction : myAttributeCarriers->getJunctions()) {
3015
removeGLObjectFromGrid(junction.second);
3016
}
3017
// remove all edges from grid
3018
for (const auto& edge : myAttributeCarriers->getEdges()) {
3019
removeGLObjectFromGrid(edge.second);
3020
}
3021
// compute using NetBuilder
3022
myNetBuilder->compute(neteditOptions, liveExplicitTurnarounds, volatileOptions);
3023
// remap ids if necessary
3024
if (neteditOptions.getBool("numerical-ids") || neteditOptions.isSet("reserved-ids")) {
3025
myAttributeCarriers->remapJunctionAndEdgeIds();
3026
}
3027
// update rtree if necessary
3028
if (!neteditOptions.getBool("offset.disable-normalization")) {
3029
for (const auto& edge : myAttributeCarriers->getEdges()) {
3030
// refresh edge geometry
3031
edge.second->updateGeometry();
3032
}
3033
}
3034
// Clear current inspected ACs in inspectorFrame if a previous net was loaded
3035
if (myViewNet != nullptr) {
3036
myViewNet->getViewParent()->getInspectorFrame()->clearInspection();
3037
}
3038
// Reset Grid
3039
myGrid.reset();
3040
myGrid.add(GeoConvHelper::getFinal().getConvBoundary());
3041
// if volatile options are true
3042
if (volatileOptions) {
3043
// check that net exist
3044
if (myViewNet == nullptr) {
3045
throw ProcessError("ViewNet doesn't exist");
3046
}
3047
// disable update geometry before clear undo list
3048
myUpdateGeometryEnabled = false;
3049
// destroy Popup
3050
myViewNet->destroyPopup();
3051
// clear undo list (This will be remove additionals and shapes)
3052
myViewNet->getUndoList()->clear();
3053
// clear all elements (it will also removed from grid)
3054
myAttributeCarriers->clearJunctions();
3055
myAttributeCarriers->clearEdges();
3056
myAttributeCarriers->clearAdditionals();
3057
myAttributeCarriers->clearDemandElements();
3058
// enable update geometry again
3059
myUpdateGeometryEnabled = true;
3060
// init again junction an edges (Additionals and shapes will be loaded after the end of this function)
3061
initJunctionsAndEdges();
3062
// init default vTypes again
3063
myAttributeCarriers->addDefaultVTypes();
3064
} else {
3065
// insert all junctions of grid again
3066
for (const auto& junction : myAttributeCarriers->getJunctions()) {
3067
// update centering boundary
3068
junction.second->updateCenteringBoundary(false);
3069
// add junction in grid again
3070
addGLObjectIntoGrid(junction.second);
3071
}
3072
// insert all edges from grid again
3073
for (const auto& edge : myAttributeCarriers->getEdges()) {
3074
// update centeting boundary
3075
edge.second->updateCenteringBoundary(false);
3076
// add edge in grid again
3077
addGLObjectIntoGrid(edge.second);
3078
}
3079
// remake connections
3080
for (const auto& edge : myAttributeCarriers->getEdges()) {
3081
edge.second->remakeGNEConnections(true);
3082
}
3083
// iterate over junctions of net
3084
for (const auto& junction : myAttributeCarriers->getJunctions()) {
3085
// undolist may not yet exist but is also not needed when just marking junctions as valid
3086
junction.second->setLogicValid(true, nullptr);
3087
// updated geometry
3088
junction.second->updateGeometryAfterNetbuild();
3089
// rebuild walking areas
3090
junction.second->rebuildGNEWalkingAreas();
3091
}
3092
// iterate over all edges of net
3093
for (const auto& edge : myAttributeCarriers->getEdges()) {
3094
// update geometry
3095
edge.second->updateGeometry();
3096
}
3097
}
3098
// net recomputed, then return false;
3099
myNeedRecompute = false;
3100
}
3101
3102
3103
void
3104
GNENet::replaceInListAttribute(GNEAttributeCarrier* ac, SumoXMLAttr key, const std::string& which, const std::string& by, GNEUndoList* undoList) {
3105
assert(ac->getTagProperty()->getAttributeProperties(key)->isList());
3106
std::vector<std::string> values = GNEAttributeCarrier::parse<std::vector<std::string> >(ac->getAttribute(key));
3107
std::vector<std::string> newValues;
3108
bool lastBy = false;
3109
for (auto v : values) {
3110
if (v == which && !lastBy) {
3111
// avoid duplicate occurence of the 'by' edge (i.e. in routes)
3112
newValues.push_back(by);
3113
} else {
3114
newValues.push_back(v);
3115
}
3116
lastBy = v == by;
3117
}
3118
ac->setAttribute(key, toString(newValues), undoList);
3119
}
3120
3121
3122
/****************************************************************************/
3123
3124