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