Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/demand/GNEDemandElementPlan.cpp
185790 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GNEDemandElementPlan.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Sep 2023
17
///
18
// An auxiliar, asbtract class for plan elements
19
/****************************************************************************/
20
21
#include <netedit/changes/GNEChange_Attribute.h>
22
#include <netedit/GNENet.h>
23
#include <netedit/GNESegment.h>
24
#include <utils/gui/div/GLHelper.h>
25
#include <utils/gui/div/GUIDesigns.h>
26
#include <utils/xml/NamespaceIDs.h>
27
28
#include "GNEDemandElementPlan.h"
29
#include "GNERoute.h"
30
31
// ===========================================================================
32
// static definitions
33
// ===========================================================================
34
35
const double GNEDemandElementPlan::myArrivalPositionDiameter = SUMO_const_halfLaneWidth;
36
37
// ===========================================================================
38
// GNEDemandElement method definitions
39
// ===========================================================================
40
41
GNEDemandElementPlan::GNEDemandElementPlan(GNEDemandElement* planElement, const double departPosition, const double arrivalPosition) :
42
myMoveElementPlan(new GNEMoveElementPlan(planElement, myDepartPosition)),
43
myDepartPosition(departPosition),
44
myArrivalPosition(arrivalPosition),
45
myPlanElement(planElement) {
46
}
47
48
49
void
50
GNEDemandElementPlan::writeLocationAttributes(OutputDevice& device) const {
51
const auto tagProperty = myPlanElement->getTagProperty();
52
// write attributes depending of parent elements
53
if (tagProperty->planConsecutiveEdges()) {
54
device.writeAttr(SUMO_ATTR_EDGES, myPlanElement->parseIDs(myPlanElement->getParentEdges()));
55
} else if (tagProperty->planRoute()) {
56
device.writeAttr(SUMO_ATTR_ROUTE, myPlanElement->getParentDemandElements().at(1)->getID());
57
} else if (tagProperty->planEdge()) {
58
device.writeAttr(SUMO_ATTR_EDGE, myPlanElement->getParentEdges().front()->getID());
59
} else if (tagProperty->planBusStop()) {
60
device.writeAttr(SUMO_ATTR_BUS_STOP, myPlanElement->getParentStoppingPlaces().front()->getID());
61
} else if (tagProperty->planTrainStop()) {
62
device.writeAttr(SUMO_ATTR_TRAIN_STOP, myPlanElement->getParentStoppingPlaces().front()->getID());
63
} else if (tagProperty->planContainerStop()) {
64
device.writeAttr(SUMO_ATTR_CONTAINER_STOP, myPlanElement->getParentStoppingPlaces().front()->getID());
65
} else if (tagProperty->planChargingStation()) {
66
device.writeAttr(SUMO_ATTR_CHARGING_STATION, myPlanElement->getParentStoppingPlaces().front()->getID());
67
} else if (tagProperty->planParkingArea()) {
68
device.writeAttr(SUMO_ATTR_PARKING_AREA, myPlanElement->getParentStoppingPlaces().front()->getID());
69
} else {
70
// write from attribute (if this is the first element)
71
if (myPlanElement->getParentDemandElements().at(0)->getPreviousChildDemandElement(myPlanElement) == nullptr) {
72
// check if write edge or junction
73
if (tagProperty->planFromEdge()) {
74
device.writeAttr(SUMO_ATTR_FROM, myPlanElement->getParentEdges().front()->getID());
75
} else if (tagProperty->planFromTAZ()) {
76
device.writeAttr(SUMO_ATTR_FROM_TAZ, myPlanElement->getParentTAZs().front()->getID());
77
} else if (tagProperty->planFromJunction()) {
78
device.writeAttr(SUMO_ATTR_FROM_JUNCTION, myPlanElement->getParentJunctions().front()->getID());
79
}
80
// origin stopping places are transformed into an intial stop stage (see writeOriginStop)
81
}
82
// continue writting to attribute
83
if (tagProperty->planToEdge()) {
84
device.writeAttr(SUMO_ATTR_TO, myPlanElement->getParentEdges().back()->getID());
85
} else if (tagProperty->planToJunction()) {
86
device.writeAttr(SUMO_ATTR_TO_JUNCTION, myPlanElement->getParentJunctions().back()->getID());
87
} else if (tagProperty->planToTAZ()) {
88
device.writeAttr(SUMO_ATTR_TO_TAZ, myPlanElement->getParentTAZs().back()->getID());
89
} else if (tagProperty->planToBusStop()) {
90
device.writeAttr(SUMO_ATTR_BUS_STOP, myPlanElement->getParentStoppingPlaces().back()->getID());
91
} else if (tagProperty->planToTrainStop()) {
92
device.writeAttr(SUMO_ATTR_TRAIN_STOP, myPlanElement->getParentStoppingPlaces().back()->getID());
93
} else if (tagProperty->planToContainerStop()) {
94
device.writeAttr(SUMO_ATTR_CONTAINER_STOP, myPlanElement->getParentStoppingPlaces().back()->getID());
95
} else if (tagProperty->planToChargingStation()) {
96
device.writeAttr(SUMO_ATTR_CHARGING_STATION, myPlanElement->getParentStoppingPlaces().back()->getID());
97
} else if (tagProperty->planToParkingArea()) {
98
device.writeAttr(SUMO_ATTR_PARKING_AREA, myPlanElement->getParentStoppingPlaces().back()->getID());
99
}
100
}
101
// check if write depart position
102
if (tagProperty->hasAttribute(SUMO_ATTR_DEPARTPOS) && (myDepartPosition > 0)) {
103
device.writeAttr(SUMO_ATTR_DEPARTPOS, myDepartPosition);
104
}
105
// check if write arrival position
106
if (tagProperty->hasAttribute(SUMO_ATTR_ARRIVALPOS) && (myArrivalPosition > 0)) {
107
device.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPosition);
108
}
109
// check if write end position
110
if (tagProperty->hasAttribute(SUMO_ATTR_ENDPOS)) {
111
device.writeAttr(SUMO_ATTR_ENDPOS, myArrivalPosition);
112
}
113
}
114
115
116
void
117
GNEDemandElementPlan::writeOriginStop(OutputDevice& device) const {
118
const auto tagProperty = myPlanElement->getTagProperty();
119
// write an extra stop element with duration 0 over a stopping place (if this is the first element)
120
if (tagProperty->planFromStoppingPlace()
121
&& myPlanElement->getParentDemandElements().at(0)->getPreviousChildDemandElement(myPlanElement) == nullptr) {
122
device.openTag(SUMO_TAG_STOP);
123
const std::string stopID = myPlanElement->getParentStoppingPlaces().front()->getID();
124
if (tagProperty->planFromBusStop()) {
125
device.writeAttr(SUMO_ATTR_BUS_STOP, stopID);
126
} else if (tagProperty->planFromTrainStop()) {
127
device.writeAttr(SUMO_ATTR_TRAIN_STOP, stopID);
128
} else if (tagProperty->planFromContainerStop()) {
129
device.writeAttr(SUMO_ATTR_CONTAINER_STOP, stopID);
130
} else if (tagProperty->planFromChargingStation()) {
131
device.writeAttr(SUMO_ATTR_CHARGING_STATION, stopID);
132
} else if (tagProperty->planFromParkingArea()) {
133
device.writeAttr(SUMO_ATTR_PARKING_AREA, stopID);
134
}
135
device.writeAttr(SUMO_ATTR_DURATION, 0);
136
device.closeTag();
137
}
138
}
139
140
141
GUIGLObjectPopupMenu*
142
GNEDemandElementPlan::getPlanPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
143
// create popup
144
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, myPlanElement);
145
// build common options
146
myPlanElement->buildPopUpMenuCommonOptions(ret, app, myPlanElement->myNet->getViewNet(), myPlanElement->getTagProperty()->getTag(), myPlanElement->isAttributeCarrierSelected());
147
GUIDesigns::buildFXMenuCommand(ret, ("Cursor position in view: " + toString(getPlanPositionInView().x()) + "," + toString(getPlanPositionInView().y())).c_str(), nullptr, nullptr, 0);
148
return ret;
149
}
150
151
152
GNELane*
153
GNEDemandElementPlan::getFirstPlanPathLane() const {
154
// get tag property
155
const auto tagProperty = myPlanElement->getTagProperty();
156
// get vclass
157
auto vClass = myPlanElement->getVClass();
158
// continue depending of parents
159
if (tagProperty->planRoute()) {
160
// route
161
return myPlanElement->getParentDemandElements().at(1)->getParentEdges().front()->getLaneByAllowedVClass(vClass);
162
} else if (tagProperty->planConsecutiveEdges() || tagProperty->planFromEdge() || tagProperty->planEdge()) {
163
// edges
164
return myPlanElement->getParentEdges().front()->getLaneByAllowedVClass(vClass);
165
} else if (tagProperty->planStoppingPlace() || tagProperty->planFromStoppingPlace() || tagProperty->planToStoppingPlace()) {
166
// additional
167
return myPlanElement->getParentStoppingPlaces().front()->getParentLanes().front();
168
} else {
169
// in other cases (TAZ, junctions, etc.) return null
170
return nullptr;
171
}
172
}
173
174
175
GNELane*
176
GNEDemandElementPlan::getLastPlanPathLane() const {
177
// get tag property
178
const auto tagProperty = myPlanElement->getTagProperty();
179
// get vclass
180
auto vClass = myPlanElement->getVClass();
181
// check parents
182
if (tagProperty->planRoute()) {
183
// route
184
return myPlanElement->getParentDemandElements().at(1)->getParentEdges().back()->getLaneByAllowedVClass(vClass);
185
} else if (tagProperty->planConsecutiveEdges() || tagProperty->planToEdge() || tagProperty->planEdge()) {
186
// edges
187
return myPlanElement->getParentEdges().back()->getLaneByAllowedVClass(vClass);
188
} else if (tagProperty->planStoppingPlace() || tagProperty->planFromStoppingPlace() || tagProperty->planToStoppingPlace()) {
189
// additional
190
return myPlanElement->getParentStoppingPlaces().back()->getParentLanes().front()->getParentEdge()->getLaneByAllowedVClass(vClass);
191
} else {
192
// in other cases (TAZ, junctions, etc.) return null
193
return nullptr;
194
}
195
}
196
197
198
void
199
GNEDemandElementPlan::computePlanPathElement() {
200
// get tag property
201
const auto tagProperty = myPlanElement->getTagProperty();
202
// get vClass
203
auto vClass = myPlanElement->getVClass();
204
// get path manager
205
auto pathManager = myPlanElement->getNet()->getDemandPathManager();
206
// continue depending of parents
207
if (tagProperty->planRoute()) {
208
// calculate consecutive path using route edges
209
pathManager->calculateConsecutivePathEdges(myPlanElement, vClass, myPlanElement->getParentDemandElements().at(1)->getParentEdges());
210
} else if (tagProperty->planConsecutiveEdges()) {
211
// calculate consecutive path using edges
212
pathManager->calculateConsecutivePathEdges(myPlanElement, vClass, myPlanElement->getParentEdges());
213
} else if (myPlanElement->myTagProperty->planFromJunction() && myPlanElement->myTagProperty->planToJunction()) {
214
// calculate path using junctions
215
pathManager->calculatePath(myPlanElement, vClass, myPlanElement->getParentJunctions().front(), myPlanElement->getParentJunctions().back());
216
} else if (myPlanElement->myTagProperty->planFromJunction()) {
217
// declare last lane
218
GNELane* lastLane = nullptr;
219
if (myPlanElement->myTagProperty->planStoppingPlace()) {
220
lastLane = myPlanElement->getParentStoppingPlaces().back()->getParentLanes().back();
221
} else if (myPlanElement->myTagProperty->planToStoppingPlace()) {
222
lastLane = myPlanElement->getParentStoppingPlaces().back()->getParentLanes().front();
223
} else if (myPlanElement->myTagProperty->planToEdge()) {
224
lastLane = myPlanElement->getParentEdges().back()->getLaneByAllowedVClass(vClass);
225
}
226
// calculate path
227
if (lastLane) {
228
pathManager->calculatePath(myPlanElement, vClass, myPlanElement->getParentJunctions().front(), lastLane);
229
}
230
} else if (myPlanElement->myTagProperty->planToJunction()) {
231
// declare first lane
232
GNELane* firstLane = nullptr;
233
if (myPlanElement->myTagProperty->planStoppingPlace()) {
234
firstLane = myPlanElement->getParentStoppingPlaces().front()->getParentLanes().back();
235
} else if (myPlanElement->myTagProperty->planFromStoppingPlace()) {
236
firstLane = myPlanElement->getParentStoppingPlaces().front()->getParentLanes().front();
237
} else if (myPlanElement->myTagProperty->planFromEdge()) {
238
firstLane = myPlanElement->getParentEdges().front()->getLaneByAllowedVClass(vClass);
239
}
240
// calculate path
241
if (firstLane) {
242
pathManager->calculatePath(myPlanElement, vClass, firstLane, myPlanElement->getParentJunctions().back());
243
}
244
} else {
245
// declare first edge
246
GNELane* firstLane = nullptr;
247
if (myPlanElement->myTagProperty->planFromEdge()) {
248
firstLane = myPlanElement->getParentEdges().front()->getLaneByAllowedVClass(vClass);
249
} else if (myPlanElement->myTagProperty->planStoppingPlace()) {
250
firstLane = myPlanElement->getParentStoppingPlaces().front()->getParentLanes().back();
251
} else if (myPlanElement->myTagProperty->planFromStoppingPlace()) {
252
firstLane = myPlanElement->getParentStoppingPlaces().front()->getParentLanes().front();
253
}
254
// declare last lane
255
GNELane* lastLane = nullptr;
256
if (myPlanElement->myTagProperty->planToEdge()) {
257
lastLane = myPlanElement->getParentEdges().back()->getLaneByAllowedVClass(vClass);
258
} else if (myPlanElement->myTagProperty->planStoppingPlace()) {
259
lastLane = myPlanElement->getParentStoppingPlaces().back()->getParentLanes().back();
260
} else if (myPlanElement->myTagProperty->planToStoppingPlace()) {
261
lastLane = myPlanElement->getParentStoppingPlaces().back()->getParentLanes().front();
262
}
263
if (firstLane && lastLane) {
264
pathManager->calculatePath(myPlanElement, vClass, firstLane, lastLane);
265
} else if (firstLane) {
266
pathManager->calculateConsecutivePathLanes(myPlanElement, {firstLane});
267
} else if (lastLane) {
268
pathManager->calculateConsecutivePathLanes(myPlanElement, {lastLane});
269
}
270
}
271
// update geometry
272
updatePlanGeometry();
273
}
274
275
276
void
277
GNEDemandElementPlan::updatePlanGeometry() {
278
// get tag property
279
const auto tagProperty = myPlanElement->getTagProperty();
280
// check if plan start or end in a TAZ (becase in this case has to be inserted in RTREE
281
if (tagProperty->planFromTAZ() || tagProperty->planToTAZ()) {
282
// declare first and last positions
283
Position firstPos = Position::INVALID;
284
Position lastPos = Position::INVALID;
285
// set first position
286
if (tagProperty->planFromEdge()) {
287
// from junction
288
firstPos = myPlanElement->getFirstPathLane()->getLaneShape().back();
289
} else if (tagProperty->planFromJunction()) {
290
// from junction
291
firstPos = myPlanElement->getParentJunctions().front()->getPositionInView();
292
} else if (tagProperty->planFromStoppingPlace()) {
293
// end of stoppingPlace lane shape
294
firstPos = myPlanElement->getParentStoppingPlaces().front()->getParentLanes().front()->getLaneShape().back();
295
} else if (tagProperty->planFromTAZ()) {
296
// from TAZ
297
if (myPlanElement->getParentTAZs().front()->getAttribute(SUMO_ATTR_CENTER).empty()) {
298
firstPos = myPlanElement->getParentTAZs().front()->getAttributePosition(GNE_ATTR_TAZ_CENTROID);
299
} else {
300
firstPos = myPlanElement->getParentTAZs().front()->getAttributePosition(SUMO_ATTR_CENTER);
301
}
302
}
303
// set last position
304
if (tagProperty->planToEdge()) {
305
// from junction
306
lastPos = myPlanElement->getLastPathLane()->getLaneShape().back();
307
} else if (tagProperty->planToJunction()) {
308
// from junction
309
lastPos = myPlanElement->getParentJunctions().back()->getPositionInView();
310
} else if (tagProperty->planToStoppingPlace()) {
311
// end of stoppingPlace lane shape
312
lastPos = myPlanElement->getParentStoppingPlaces().back()->getParentLanes().front()->getLaneShape().front();
313
} else if (tagProperty->planToTAZ()) {
314
// from TAZ
315
if (myPlanElement->getParentTAZs().back()->getAttribute(SUMO_ATTR_CENTER).empty()) {
316
lastPos = myPlanElement->getParentTAZs().back()->getAttributePosition(GNE_ATTR_TAZ_CENTROID);
317
} else {
318
lastPos = myPlanElement->getParentTAZs().back()->getAttributePosition(SUMO_ATTR_CENTER);
319
}
320
}
321
// use both position to calculate a line
322
if ((firstPos != Position::INVALID) && (lastPos != Position::INVALID)) {
323
myPlanElement->myDemandElementGeometry.updateGeometry({firstPos, lastPos});
324
} else {
325
myPlanElement->myDemandElementGeometry.clearGeometry();
326
}
327
}
328
// update centering boundary
329
updatePlanCenteringBoundary(true);
330
// update child demand elements
331
for (const auto& demandElement : myPlanElement->getChildDemandElements()) {
332
demandElement->updateGeometry();
333
}
334
}
335
336
337
Boundary
338
GNEDemandElementPlan::getPlanCenteringBoundary() const {
339
return myPlanBoundary;
340
}
341
342
343
void
344
GNEDemandElementPlan::updatePlanCenteringBoundary(const bool updateGrid) {
345
// remove additional from grid
346
if (myPlanBoundary.isInitialised() && updateGrid) {
347
myPlanElement->getNet()->removeGLObjectFromGrid(myPlanElement);
348
}
349
myPlanBoundary = myPlanElement->getDemandElementGeometry().getShape().getBoxBoundary();
350
// if this element is over route, add their boundary
351
if (myPlanElement->getParentDemandElements().size() > 1) {
352
myPlanBoundary.add(myPlanElement->getParentDemandElements().at(1)->getCenteringBoundary());
353
}
354
// add the combination of all parent edges's boundaries
355
for (const auto& edge : myPlanElement->getParentEdges()) {
356
myPlanBoundary.add(edge->getCenteringBoundary());
357
}
358
// add the combination of all parent edges's boundaries
359
for (const auto& junction : myPlanElement->getParentJunctions()) {
360
myPlanBoundary.add(junction->getCenteringBoundary());
361
}
362
// add the combination of all parent additional's boundaries (stoppingPlaces and TAZs)
363
for (const auto& additional : myPlanElement->getParentAdditionals()) {
364
if (additional->getTagProperty()->getTag() == SUMO_TAG_TAZ) {
365
if (additional->getAttribute(SUMO_ATTR_CENTER).empty()) {
366
myPlanBoundary.add(additional->getAttributePosition(GNE_ATTR_TAZ_CENTROID));
367
} else {
368
myPlanBoundary.add(additional->getAttributePosition(SUMO_ATTR_CENTER));
369
}
370
} else {
371
myPlanBoundary.add(additional->getCenteringBoundary());
372
}
373
}
374
// check if is valid
375
if (myPlanBoundary.isInitialised()) {
376
myPlanBoundary.grow(5);
377
}
378
// add additional into RTREE again
379
if (myPlanBoundary.isInitialised() && updateGrid) {
380
myPlanElement->getNet()->addGLObjectIntoGrid(myPlanElement);
381
}
382
}
383
384
385
Position
386
GNEDemandElementPlan::getPlanPositionInView() const {
387
// get tag property
388
const auto tagProperty = myPlanElement->getTagProperty();
389
// continue depending of parents
390
if (tagProperty->planRoute()) {
391
// route
392
return myPlanElement->getParentDemandElements().at(1)->getPositionInView();
393
} else if (tagProperty->isPlanStop()) {
394
return myPlanElement->getDemandElementGeometry().getShape().front();
395
} else if (tagProperty->planFromEdge() || tagProperty->planConsecutiveEdges() || tagProperty->planEdge()) {
396
// first edge
397
return myPlanElement->getParentEdges().front()->getPositionInView();
398
} else if (tagProperty->planFromJunction()) {
399
// first junction
400
return myPlanElement->getParentJunctions().front()->getPositionInView();
401
} else if (tagProperty->planStoppingPlace() || tagProperty->planFromStoppingPlace()) {
402
// first additional
403
return myPlanElement->getParentStoppingPlaces().front()->getPositionInView();
404
} else if (tagProperty->planFromTAZ()) {
405
if (myPlanElement->getParentTAZs().front()->getAttribute(SUMO_ATTR_CENTER).empty()) {
406
return myPlanElement->getParentTAZs().front()->getAttributePosition(GNE_ATTR_TAZ_CENTROID);
407
} else {
408
return myPlanElement->getParentTAZs().front()->getAttributePosition(SUMO_ATTR_CENTER);
409
}
410
} else {
411
// return parent position
412
return Position(0, 0);
413
}
414
}
415
416
417
std::string
418
GNEDemandElementPlan::getPlanAttribute(SumoXMLAttr key) const {
419
// continue depending of key
420
switch (key) {
421
// Common plan attributes
422
case SUMO_ATTR_ID:
423
case GNE_ATTR_PARENT:
424
return myPlanElement->getParentDemandElements().at(0)->getID();
425
case SUMO_ATTR_DEPARTPOS:
426
if (myDepartPosition < 0) {
427
return "";
428
} else {
429
return toString(myDepartPosition);
430
}
431
case SUMO_ATTR_ENDPOS:
432
case SUMO_ATTR_ARRIVALPOS:
433
if (myArrivalPosition < 0) {
434
return "";
435
} else {
436
return toString(myArrivalPosition);
437
}
438
// route
439
case SUMO_ATTR_ROUTE:
440
return myPlanElement->getParentDemandElements().at(1)->getID();
441
// edges
442
case SUMO_ATTR_EDGE:
443
case SUMO_ATTR_EDGES:
444
return myPlanElement->parseIDs(myPlanElement->getParentEdges());
445
// stoppingPlaces (single and back)
446
case SUMO_ATTR_BUS_STOP:
447
case SUMO_ATTR_TRAIN_STOP:
448
case SUMO_ATTR_CONTAINER_STOP:
449
case SUMO_ATTR_CHARGING_STATION:
450
case SUMO_ATTR_PARKING_AREA:
451
return myPlanElement->getParentStoppingPlaces().back()->getID();
452
// from elements
453
case SUMO_ATTR_FROM:
454
return myPlanElement->getParentEdges().front()->getID();
455
case SUMO_ATTR_FROM_JUNCTION:
456
return myPlanElement->getParentJunctions().front()->getID();
457
case SUMO_ATTR_FROM_TAZ:
458
return myPlanElement->getParentTAZs().front()->getID();
459
case GNE_ATTR_FROM_BUSSTOP:
460
case GNE_ATTR_FROM_TRAINSTOP:
461
case GNE_ATTR_FROM_CONTAINERSTOP:
462
case GNE_ATTR_FROM_CHARGINGSTATION:
463
case GNE_ATTR_FROM_PARKINGAREA:
464
return myPlanElement->getParentStoppingPlaces().front()->getID();
465
// to elements
466
case SUMO_ATTR_TO:
467
return myPlanElement->getParentEdges().back()->getID();
468
case SUMO_ATTR_TO_JUNCTION:
469
return myPlanElement->getParentJunctions().back()->getID();
470
case SUMO_ATTR_TO_TAZ:
471
return myPlanElement->getParentTAZs().back()->getID();
472
default:
473
return myPlanElement->getCommonAttribute(key);
474
}
475
}
476
477
478
double
479
GNEDemandElementPlan::getPlanAttributeDouble(SumoXMLAttr key) const {
480
// get tag property
481
const auto tagProperty = myPlanElement->getTagProperty();
482
// declare plan parent
483
const auto planParent = myPlanElement->getParentDemandElements().at(0);
484
// continue depending of key
485
switch (key) {
486
case GNE_ATTR_PLAN_GEOMETRY_STARTPOS: {
487
if (tagProperty->planStoppingPlace()) {
488
// use startpos of stoppingPlace parent (stops)
489
const auto factor = myPlanElement->getParentStoppingPlaces().front()->getParentLanes().front()->getLengthGeometryFactor();
490
return myPlanElement->getParentStoppingPlaces().front()->getAttributeDouble(SUMO_ATTR_STARTPOS) * factor;
491
} else if (tagProperty->planFromStoppingPlace()) {
492
// use end position of stoppingPlace parent (for plans that starts in stoppingPlaces)
493
const auto factor = myPlanElement->getParentStoppingPlaces().front()->getParentLanes().front()->getLengthGeometryFactor();
494
return myPlanElement->getParentStoppingPlaces().front()->getAttributeDouble(SUMO_ATTR_ENDPOS) * factor;
495
} else if (tagProperty->planFromTAZ()) {
496
return 0;
497
} else if (tagProperty->planFromJunction()) {
498
return -1;
499
} else {
500
// get previous plan element
501
const auto previousPlan = planParent->getPreviousChildDemandElement(myPlanElement);
502
// continue depending of previous plan
503
if (previousPlan) {
504
// use previous plan end position (normally the arrival position)
505
const auto posOverLane = previousPlan->getAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS);
506
// if posOverLane is -1, means that previousPlan ends in the end of lane.
507
if (posOverLane == -1) {
508
// INVALID_DOUBLE will put the startPositio at the end of line
509
return INVALID_DOUBLE;
510
} else {
511
return previousPlan->getAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS);
512
}
513
} else {
514
// use depart position defined in parent (person or container)
515
return planParent->getAttributeDouble(SUMO_ATTR_DEPARTPOS);
516
}
517
}
518
}
519
case GNE_ATTR_PLAN_GEOMETRY_ENDPOS:
520
// continue depending of parents
521
if (tagProperty->planStoppingPlace()) {
522
// use end position of the stoppingPlace (stops)
523
const auto factor = myPlanElement->getParentStoppingPlaces().back()->getParentLanes().front()->getLengthGeometryFactor();
524
return myPlanElement->getParentStoppingPlaces().back()->getAttributeDouble(SUMO_ATTR_ENDPOS) * factor;
525
} else if (tagProperty->planToStoppingPlace()) {
526
// use start position of the stoppingPlace (for elements that ends in stoppingPlaces)
527
const auto factor = myPlanElement->getParentStoppingPlaces().back()->getParentLanes().front()->getLengthGeometryFactor();
528
return myPlanElement->getParentStoppingPlaces().back()->getAttributeDouble(SUMO_ATTR_STARTPOS) * factor;
529
} else if (tagProperty->planToJunction() || tagProperty->planToTAZ()) {
530
// junctions and TAZs return always -1
531
return -1;
532
} else if ((tagProperty->isPlanStopPerson() || tagProperty->isPlanStopContainer()) && tagProperty->planEdge()) {
533
// elements that ends in stop always uses the end (arrival) position of the stops over edges
534
return myArrivalPosition;
535
} else {
536
// check if next plan is a stop over edge
537
const auto nextPlan = planParent->getNextChildDemandElement(myPlanElement);
538
if (nextPlan && (nextPlan->getTagProperty()->isPlanStopPerson() ||
539
nextPlan->getTagProperty()->isPlanStopContainer()) &&
540
nextPlan->getTagProperty()->planEdge()) {
541
// if next plan is an stop over stoppingPlaces, use ends of stoppingPlace
542
return nextPlan->getAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS);
543
} else {
544
// use arrival position
545
return myArrivalPosition;
546
}
547
}
548
case SUMO_ATTR_DEPARTPOS:
549
return myDepartPosition;
550
case SUMO_ATTR_ENDPOS:
551
case SUMO_ATTR_ARRIVALPOS:
552
return myArrivalPosition;
553
default:
554
throw InvalidArgument(myPlanElement->getTagStr() + " doesn't have a doubleattribute of type '" + toString(key) + "'");
555
}
556
}
557
558
559
Position
560
GNEDemandElementPlan::getPlanAttributePosition(SumoXMLAttr key) const {
561
// get tag property
562
const auto tagProperty = myPlanElement->getTagProperty();
563
// declare plan parent
564
const auto planParent = myPlanElement->getParentDemandElements().at(0);
565
// continue depending of key
566
switch (key) {
567
case GNE_ATTR_PLAN_GEOMETRY_STARTPOS: {
568
// get previous plan
569
const auto previousPlan = planParent->getPreviousChildDemandElement(myPlanElement);
570
if (previousPlan && previousPlan->getTagProperty()->isPlanStop() && previousPlan->getTagProperty()->planStoppingPlace()) {
571
return previousPlan->getParentStoppingPlaces().front()->getAdditionalGeometry().getShape().back();
572
}
573
// continue depending of from element
574
if (tagProperty->planStoppingPlace()) {
575
return myPlanElement->getParentStoppingPlaces().front()->getAdditionalGeometry().getShape().front();
576
} else if (tagProperty->planFromStoppingPlace()) {
577
return myPlanElement->getParentStoppingPlaces().front()->getAdditionalGeometry().getShape().back();
578
} else if (tagProperty->planFromJunction()) {
579
// junction view position
580
return myPlanElement->getParentJunctions().front()->getPositionInView();
581
} else if (tagProperty->planFromTAZ()) {
582
if (myPlanElement->getParentTAZs().front()->getAttribute(SUMO_ATTR_CENTER).empty()) {
583
return myPlanElement->getParentTAZs().front()->getAttributePosition(GNE_ATTR_TAZ_CENTROID);
584
} else {
585
return myPlanElement->getParentTAZs().front()->getAttributePosition(SUMO_ATTR_CENTER);
586
}
587
} else if (tagProperty->planConsecutiveEdges() || tagProperty->planRoute() || tagProperty->planFromEdge()) {
588
// get first path lane
589
const auto firstLane = myPlanElement->getFirstPathLane();
590
// check if first lane exists
591
if (firstLane == nullptr) {
592
return Position::INVALID;
593
}
594
// declare lane position
595
double lanePosition = 0;
596
// continue depending of conditions
597
if (previousPlan) {
598
// use previous geometry end position
599
lanePosition = previousPlan->getAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS);
600
} else {
601
// use departPos defined in planParent
602
lanePosition = planParent->getAttributeDouble(SUMO_ATTR_DEPARTPOS);
603
}
604
// get lane shape
605
const auto& laneShape = firstLane->getLaneShape();
606
// continue depending of lane position
607
if (lanePosition <= 0) {
608
return laneShape.front();
609
} else if (lanePosition >= laneShape.length2D()) {
610
return laneShape.back();
611
} else {
612
return laneShape.positionAtOffset2D(lanePosition);
613
}
614
} else {
615
return Position::INVALID;
616
}
617
}
618
case GNE_ATTR_PLAN_GEOMETRY_ENDPOS: {
619
// check parents
620
if (tagProperty->planToJunction()) {
621
// junctions
622
return myPlanElement->getParentJunctions().back()->getPositionInView();
623
} else if (tagProperty->planStoppingPlace()) {
624
// get additional back shape (stops)
625
return myPlanElement->getParentStoppingPlaces().back()->getAdditionalGeometry().getShape().back();
626
} else if (tagProperty->planToStoppingPlace()) {
627
// get additional front shape
628
return myPlanElement->getParentStoppingPlaces().back()->getAdditionalGeometry().getShape().front();
629
} else if (tagProperty->planToTAZ()) {
630
// taz
631
if (myPlanElement->getParentTAZs().back()->getAttribute(SUMO_ATTR_CENTER).empty()) {
632
return myPlanElement->getParentTAZs().back()->getAttributePosition(GNE_ATTR_TAZ_CENTROID);
633
} else {
634
return myPlanElement->getParentTAZs().back()->getAttributePosition(SUMO_ATTR_CENTER);
635
}
636
} else if (tagProperty->planConsecutiveEdges() || tagProperty->planRoute() || tagProperty->planFromEdge()) {
637
// get next plan
638
const auto nextPlan = planParent->getNextChildDemandElement(myPlanElement);
639
// if next plan exist, then use their first lane (needed to maintain connectivity with rides)
640
const auto lastLane = nextPlan ? nextPlan->getFirstPathLane() : myPlanElement->getLastPathLane();
641
// check if last lane exists
642
if (lastLane == nullptr) {
643
return Position::INVALID;
644
}
645
// get lane shape
646
const auto& laneShape = lastLane->getLaneShape();
647
// continue depending of arrival position
648
if (nextPlan && nextPlan->getTagProperty()->isPlanStop()) {
649
return nextPlan->getAttributePosition(GNE_ATTR_PLAN_GEOMETRY_ENDPOS);
650
} else if (myArrivalPosition == 0) {
651
return laneShape.front();
652
} else if ((myArrivalPosition == -1) || (myArrivalPosition >= laneShape.length2D())) {
653
return laneShape.back();
654
} else {
655
return laneShape.positionAtOffset2D(myArrivalPosition);
656
}
657
} else {
658
return Position::INVALID;
659
}
660
}
661
default:
662
throw InvalidArgument(myPlanElement->getTagStr() + " doesn't have a position attribute of type '" + toString(key) + "'");
663
}
664
}
665
666
667
void
668
GNEDemandElementPlan::setPlanAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
669
// continue depending of key
670
switch (key) {
671
// common attributes
672
case SUMO_ATTR_DEPARTPOS:
673
case SUMO_ATTR_ARRIVALPOS:
674
case SUMO_ATTR_ENDPOS:
675
case GNE_ATTR_PARENT:
676
GNEChange_Attribute::changeAttribute(myPlanElement, key, value, undoList);
677
break;
678
default:
679
myPlanElement->setCommonAttribute(key, value, undoList);
680
break;
681
}
682
}
683
684
685
bool
686
GNEDemandElementPlan::isPlanValid(SumoXMLAttr key, const std::string& value) {
687
// continue depending of key
688
switch (key) {
689
// common attributes
690
case GNE_ATTR_PARENT:
691
return false;
692
case SUMO_ATTR_DEPARTPOS:
693
case SUMO_ATTR_ARRIVALPOS:
694
if (value.empty()) {
695
return true;
696
} else if (GNEAttributeCarrier::canParse<double>(value)) {
697
return GNEAttributeCarrier::parse<double>(value) >= 0;
698
} else {
699
return false;
700
}
701
case SUMO_ATTR_ENDPOS:
702
return GNEAttributeCarrier::canParse<double>(value);
703
default:
704
return myPlanElement->isCommonAttributeValid(key, value);
705
}
706
}
707
708
709
bool
710
GNEDemandElementPlan::isPlanAttributeEnabled(SumoXMLAttr key) const {
711
switch (key) {
712
// edges
713
case SUMO_ATTR_EDGES:
714
// edge
715
case SUMO_ATTR_EDGE:
716
// route
717
case SUMO_ATTR_ROUTE:
718
// from
719
case SUMO_ATTR_FROM:
720
case SUMO_ATTR_FROM_JUNCTION:
721
case SUMO_ATTR_FROM_TAZ:
722
case GNE_ATTR_FROM_BUSSTOP:
723
case GNE_ATTR_FROM_TRAINSTOP:
724
case GNE_ATTR_FROM_CONTAINERSTOP:
725
case GNE_ATTR_FROM_CHARGINGSTATION:
726
case GNE_ATTR_FROM_PARKINGAREA:
727
// to
728
case SUMO_ATTR_TO:
729
case SUMO_ATTR_TO_JUNCTION:
730
case SUMO_ATTR_TO_TAZ:
731
case SUMO_ATTR_BUS_STOP:
732
case SUMO_ATTR_TRAIN_STOP:
733
case SUMO_ATTR_CONTAINER_STOP:
734
case SUMO_ATTR_CHARGING_STATION:
735
case SUMO_ATTR_PARKING_AREA:
736
// depart pos (temporal, probably will be removed)
737
case SUMO_ATTR_DEPARTPOS:
738
return false;
739
default:
740
return true;
741
}
742
}
743
744
745
void
746
GNEDemandElementPlan::setPlanAttribute(SumoXMLAttr key, const std::string& value) {
747
bool recompute = false;
748
switch (key) {
749
// from-to attributes (needed if we're replacing junction by geometry points and similar operations)
750
case SUMO_ATTR_FROM:
751
myPlanElement->replaceFirstParentEdge(value);
752
recompute = true;
753
break;
754
case SUMO_ATTR_TO:
755
myPlanElement->replaceLastParentEdge(value);
756
recompute = true;
757
break;
758
// Common plan attributes
759
case GNE_ATTR_PARENT:
760
replacePlanParent(value);
761
break;
762
case SUMO_ATTR_DEPARTPOS:
763
if (value.empty()) {
764
myDepartPosition = -1;
765
} else {
766
myDepartPosition = GNEAttributeCarrier::parse<double>(value);
767
}
768
recompute = true;
769
break;
770
case SUMO_ATTR_ENDPOS:
771
case SUMO_ATTR_ARRIVALPOS:
772
if (value.empty()) {
773
myArrivalPosition = -1;
774
} else {
775
myArrivalPosition = GNEAttributeCarrier::parse<double>(value);
776
}
777
recompute = true;
778
break;
779
default:
780
myPlanElement->setCommonAttribute(key, value);
781
break;
782
}
783
// check if compute geometry and path
784
if (recompute && !myPlanElement->isTemplate()) {
785
myPlanElement->updateGeometry();
786
myPlanElement->computePathElement();
787
}
788
}
789
790
791
std::string
792
GNEDemandElementPlan::getPlanHierarchyName() const {
793
// get tag property
794
const auto tagProperty = myPlanElement->getTagProperty();
795
// declare result
796
std::string result;
797
// clear result
798
int index = 0;
799
while (tagProperty->getTagStr().at(index) != ':') {
800
result.push_back(tagProperty->getTagStr().at(index));
801
index++;
802
}
803
result += ": ";
804
// continue depending of attributes
805
if (tagProperty->planConsecutiveEdges()) {
806
// edges
807
return result + myPlanElement->getParentEdges().front()->getID() + " ... " + myPlanElement->getParentEdges().back()->getID();
808
} else if (tagProperty->planRoute()) {
809
// route
810
return result + myPlanElement->getParentDemandElements().at(1)->getID();
811
} else if (tagProperty->planEdge()) {
812
// edge
813
return result + myPlanElement->getParentEdges().front()->getID();
814
} else if (tagProperty->planStoppingPlace()) {
815
// stoppingPlace
816
return myPlanElement->getParentStoppingPlaces().front()->getID();
817
} else {
818
// stoppingPlace
819
if (tagProperty->planFromStoppingPlace()) {
820
result += myPlanElement->getParentStoppingPlaces().front()->getID();
821
}
822
// TAZ
823
if (tagProperty->planFromTAZ()) {
824
result += myPlanElement->getParentTAZs().front()->getID();
825
}
826
// junction
827
if (tagProperty->planFromJunction()) {
828
result += myPlanElement->getParentJunctions().front()->getID();
829
}
830
// edge
831
if (tagProperty->planFromEdge()) {
832
result += myPlanElement->getParentEdges().front()->getID();
833
}
834
// arrow
835
result += " -> ";
836
// stoppingPlace
837
if (tagProperty->planToStoppingPlace()) {
838
result += myPlanElement->getParentStoppingPlaces().back()->getID();
839
}
840
// TAZ
841
if (tagProperty->planToTAZ()) {
842
result += myPlanElement->getParentTAZs().back()->getID();
843
}
844
// junction
845
if (tagProperty->planToJunction()) {
846
result += myPlanElement->getParentJunctions().back()->getID();
847
}
848
// edge
849
if (tagProperty->planToEdge()) {
850
result += myPlanElement->getParentEdges().back()->getID();
851
}
852
return result;
853
}
854
}
855
856
857
bool
858
GNEDemandElementPlan::checkDrawPersonPlan() const {
859
const auto viewNet = myPlanElement->getNet()->getViewNet();
860
const auto& inspectedElements = viewNet->getInspectedElements();
861
// check conditions
862
if (viewNet->getEditModes().isCurrentSupermodeNetwork() &&
863
viewNet->getNetworkViewOptions().showDemandElements() &&
864
viewNet->getDemandViewOptions().showAllPersonPlans()) {
865
// show all person plans in network mode
866
return true;
867
} else if (viewNet->getEditModes().isCurrentSupermodeDemand() &&
868
viewNet->getDemandViewOptions().showAllPersonPlans()) {
869
// show all person plans
870
return true;
871
} else if (viewNet->getEditModes().isCurrentSupermodeDemand() && myPlanElement->isAttributeCarrierSelected()) {
872
// show selected
873
return true;
874
} else if (inspectedElements.isACInspected(myPlanElement->getParentDemandElements().front())) {
875
// person parent is inspected
876
return true;
877
} else if (viewNet->getDemandViewOptions().getLockedPerson() == myPlanElement->getParentDemandElements().front()) {
878
// person parent is locked
879
return true;
880
} else {
881
// check if parent
882
if (inspectedElements.getFirstAC() && inspectedElements.getFirstAC()->getTagProperty()->isPlanPerson() &&
883
(inspectedElements.getFirstAC()->getAttribute(GNE_ATTR_PARENT) == myPlanElement->getAttribute(GNE_ATTR_PARENT))) {
884
// common person parent
885
return true;
886
} else {
887
// all conditions are false
888
return false;
889
}
890
}
891
}
892
893
894
bool
895
GNEDemandElementPlan::checkDrawContainerPlan() const {
896
const auto viewNet = myPlanElement->getNet()->getViewNet();
897
const auto& inspectedElements = viewNet->getInspectedElements();
898
// check conditions
899
if (viewNet->getEditModes().isCurrentSupermodeNetwork() &&
900
viewNet->getNetworkViewOptions().showDemandElements() &&
901
viewNet->getDemandViewOptions().showAllContainerPlans()) {
902
// show all container plans in network mode
903
return true;
904
} else if (viewNet->getEditModes().isCurrentSupermodeDemand() &&
905
viewNet->getDemandViewOptions().showAllContainerPlans()) {
906
// show all container plans
907
return true;
908
} else if (viewNet->getEditModes().isCurrentSupermodeDemand() && myPlanElement->isAttributeCarrierSelected()) {
909
// show selected
910
return true;
911
} else if (inspectedElements.isACInspected(myPlanElement->getParentDemandElements().front())) {
912
// container parent is inspected
913
return true;
914
} else if (viewNet->getDemandViewOptions().getLockedContainer() == myPlanElement->getParentDemandElements().front()) {
915
// container parent is locked
916
return true;
917
} else {
918
// check if parent is inspected
919
if (inspectedElements.getFirstAC() && inspectedElements.getFirstAC()->getTagProperty()->isPlanContainer() &&
920
(inspectedElements.getFirstAC()->getAttribute(GNE_ATTR_PARENT) == myPlanElement->getAttribute(GNE_ATTR_PARENT))) {
921
// common container parent
922
return true;
923
} else {
924
// all conditions are false
925
return false;
926
}
927
}
928
}
929
930
931
void
932
GNEDemandElementPlan::drawPlanGL(const bool drawPlan, const GUIVisualizationSettings& s, const RGBColor& planColor, const RGBColor& planSelectedColor) const {
933
const auto viewNet = myPlanElement->getNet()->getViewNet();
934
const auto& inspectedElements = viewNet->getInspectedElements();
935
// get plan parent
936
const GNEDemandElement* planParent = myPlanElement->getParentDemandElements().front();
937
// get tag property
938
const auto tagProperty = myPlanElement->getTagProperty();
939
// get plan geometry
940
auto& planGeometry = myPlanElement->myDemandElementGeometry;
941
// draw relations between TAZs
942
if (drawPlan && (planGeometry.getShape().size() > 0)) {
943
// draw boundary
944
if (s.drawBoundaries) {
945
GLHelper::drawBoundary(s, getPlanCenteringBoundary());
946
}
947
// get detail level
948
const auto d = s.getDetailLevel(1);
949
// check if draw with double width
950
const bool drawHalfWidth = ((inspectedElements.getFirstAC() != myPlanElement) && (inspectedElements.getFirstAC() != planParent) && !gViewObjectsHandler.isObjectSelected(myPlanElement));
951
// calculate path width
952
double pathWidth = s.widthSettings.walkWidth;
953
if (tagProperty->isPlanRide()) {
954
pathWidth = s.widthSettings.rideWidth;
955
} else if (tagProperty->isPlanPersonTrip()) {
956
pathWidth = s.widthSettings.personTripWidth;
957
}
958
// draw geometry only if we'rent in drawForObjectUnderCursor mode
959
if ((tagProperty->isPlanPerson() && s.checkDrawPerson(d, myPlanElement->isAttributeCarrierSelected())) ||
960
(tagProperty->isPlanContainer() && s.checkDrawContainer(d, myPlanElement->isAttributeCarrierSelected()))) {
961
// push matrix
962
GLHelper::pushMatrix();
963
// translate to front
964
myPlanElement->drawInLayer(GLO_TAZ + 1);
965
// set color
966
GLHelper::setColor(myPlanElement->drawUsingSelectColor() ? planSelectedColor : planColor);
967
// draw line
968
GUIGeometry::drawGeometry(d, planGeometry, pathWidth * (drawHalfWidth ? 1 : 2));
969
if (drawHalfWidth) {
970
GLHelper::drawTriangleAtEnd(planGeometry.getShape().front(), planGeometry.getShape().back(), 0.5, 0.5, 0.5);
971
} else {
972
GLHelper::drawTriangleAtEnd(planGeometry.getShape().front(), planGeometry.getShape().back(), 1, 1, 1);
973
}
974
// pop matrix
975
GLHelper::popMatrix();
976
// draw dotted contour
977
myPlanContour.drawDottedContours(s, d, myPlanElement, s.dottedContourSettings.segmentWidth, true);
978
}
979
// calculate contour and draw dotted geometry
980
myPlanContour.calculateContourExtrudedShape(s, d, myPlanElement, planGeometry.getShape(), myPlanElement->getType(), pathWidth * 2,
981
1, true, true, 0, nullptr, nullptr);
982
// calculate contour for end
983
myPlanContourEnd.calculateContourCircleShape(s, d, myPlanElement, planGeometry.getShape().back(), 1, myPlanElement->getType(), 1, nullptr);
984
}
985
// check if draw plan parent
986
if (planParent->getPreviousChildDemandElement(myPlanElement) == nullptr) {
987
planParent->drawGL(s);
988
}
989
}
990
991
992
void
993
GNEDemandElementPlan::drawPlanLanePartial(const bool drawPlan, const GUIVisualizationSettings& s, const GNESegment* segment,
994
const double offsetFront, const double planWidth, const RGBColor& planColor, const RGBColor& planSelectedColor) const {
995
const auto viewNet = myPlanElement->getNet()->getViewNet();
996
const auto& inspectedElements = viewNet->getInspectedElements();
997
// get tag property
998
const auto tagProperty = myPlanElement->getTagProperty();
999
// get plan parent
1000
const GNEDemandElement* planParent = myPlanElement->getParentDemandElements().front();
1001
// check if draw plan element can be drawn
1002
if (drawPlan && segment->getLane() && myPlanElement->getNet()->getDemandPathManager()->getPathDraw()->checkDrawPathGeometry(s, segment->getLane(), tagProperty->getTag(), true)) {
1003
// draw boundary
1004
if (tagProperty->isPlacedInRTree() && s.drawBoundaries) {
1005
GLHelper::drawBoundary(s, getPlanCenteringBoundary());
1006
}
1007
// get detail level
1008
const auto d = s.getDetailLevel(1);
1009
// declare path geometry
1010
GUIGeometry planGeometry;
1011
// update pathGeometry depending of first and last segment
1012
if (segment->isFirstSegment() && segment->isLastSegment()) {
1013
if (tagProperty->planFromTAZ()) {
1014
planGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
1015
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_STARTPOS),
1016
Position::INVALID,
1017
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS),
1018
getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_ENDPOS));
1019
} else if (tagProperty->planToTAZ()) {
1020
planGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
1021
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_STARTPOS),
1022
getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_STARTPOS),
1023
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS),
1024
Position::INVALID);
1025
} else {
1026
planGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
1027
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_STARTPOS),
1028
getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_STARTPOS),
1029
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS),
1030
getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_ENDPOS));
1031
}
1032
} else if (segment->isFirstSegment()) {
1033
planGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
1034
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_STARTPOS),
1035
getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_STARTPOS),
1036
-1,
1037
Position::INVALID);
1038
} else if (segment->isLastSegment()) {
1039
planGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
1040
-1,
1041
Position::INVALID,
1042
getPlanAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS),
1043
getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_ENDPOS));
1044
} else {
1045
planGeometry = segment->getLane()->getLaneGeometry();
1046
}
1047
// calculate path width double
1048
const double drawingWidth = s.addSize.getExaggeration(s, segment->getLane()) * planWidth * 2;
1049
// check if draw with double width
1050
const bool drawHalfWidth = ((inspectedElements.getFirstAC() != myPlanElement) && (inspectedElements.getFirstAC() != planParent) && !gViewObjectsHandler.isObjectSelected(myPlanElement));
1051
// get end pos radius
1052
const double endPosRadius = getEndPosRadius(s, segment, drawHalfWidth);
1053
// draw geometry only if we'rent in drawForObjectUnderCursor mode
1054
if ((tagProperty->isPlanPerson() && s.checkDrawPerson(d, myPlanElement->isAttributeCarrierSelected())) ||
1055
(tagProperty->isPlanContainer() && s.checkDrawContainer(d, myPlanElement->isAttributeCarrierSelected()))) {
1056
// Add a draw matrix
1057
GLHelper::pushMatrix();
1058
// Start with the drawing of the area traslating matrix to origin
1059
myPlanElement->drawInLayer(myPlanElement->getType(), offsetFront);
1060
// Set color
1061
GLHelper::setColor(myPlanElement->drawUsingSelectColor() ? planSelectedColor : planColor);
1062
// draw geometry depending of drawWithDoubleWidth
1063
GUIGeometry::drawGeometry(d, planGeometry, drawingWidth * (drawHalfWidth ? 0.5 : 1));
1064
// draw red arrows
1065
drawFromArrow(s, segment->getLane(), segment);
1066
drawToArrow(s, segment->getLane(), segment);
1067
// Pop last matrix
1068
GLHelper::popMatrix();
1069
// Draw name if isn't being drawn for selecting
1070
myPlanElement->drawName(myPlanElement->getCenteringBoundary().getCenter(), s.scale, s.addName);
1071
// draw dotted contour
1072
segment->getContour()->drawDottedContours(s, d, myPlanElement, s.dottedContourSettings.segmentWidth, true);
1073
// draw TAZ Center dotted contour
1074
myPlanContourEnd.drawDottedContours(s, d, myPlanElement, s.dottedContourSettings.segmentWidth, true);
1075
}
1076
// declare trim geometry to draw
1077
const auto& shape = (segment->isFirstSegment() || segment->isLastSegment()) ? planGeometry.getShape() : segment->getLane()->getLaneShape();
1078
// calculate contour and draw dotted geometry (always with double width)
1079
if (segment->isFirstSegment()) {
1080
segment->getContour()->calculateContourExtrudedShape(s, d, myPlanElement, shape, myPlanElement->getType(), drawingWidth, 1, true, false,
1081
0, segment, segment->getLane()->getParentEdge());
1082
} else if (segment->isLastSegment()) {
1083
segment->getContour()->calculateContourExtrudedShape(s, d, myPlanElement, shape, myPlanElement->getType(), drawingWidth, 1, false, false,
1084
0, segment, segment->getLane()->getParentEdge());
1085
// calculate contour for end
1086
myPlanContourEnd.calculateContourCircleShape(s, d, myPlanElement, getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_ENDPOS), 2 * endPosRadius,
1087
myPlanElement->getType(), 1, segment->getLane());
1088
} else {
1089
segment->getContour()->calculateContourExtrudedShape(s, d, myPlanElement, shape, myPlanElement->getType(), drawingWidth, 1, false, false, 0,
1090
segment, segment->getLane()->getParentEdge());
1091
}
1092
// check if add this path element to redraw buffer
1093
if (!gViewObjectsHandler.isPathElementMarkForRedraw(myPlanElement) && segment->getContour()->checkDrawPathContour(s, d, myPlanElement)) {
1094
gViewObjectsHandler.addToRedrawPathElements(myPlanElement);
1095
}
1096
}
1097
// check if draw plan parent
1098
if (planParent->getPreviousChildDemandElement(myPlanElement) == nullptr) {
1099
planParent->drawGL(s);
1100
}
1101
}
1102
1103
1104
void
1105
GNEDemandElementPlan::drawPlanJunctionPartial(const bool drawPlan, const GUIVisualizationSettings& s, const GNESegment* segment,
1106
const double offsetFront, const double planWidth, const RGBColor& planColor, const RGBColor& planSelectedColor) const {
1107
const auto viewNet = myPlanElement->getNet()->getViewNet();
1108
const auto& inspectedElements = viewNet->getInspectedElements();
1109
// get tag property
1110
const auto tagProperty = myPlanElement->getTagProperty();
1111
// get plan parent
1112
const GNEDemandElement* planParent = myPlanElement->getParentDemandElements().front();
1113
// check if draw plan elements can be drawn
1114
if (drawPlan && myPlanElement->getNet()->getDemandPathManager()->getPathDraw()->checkDrawPathGeometry(s, segment, tagProperty->getTag(), false)) {
1115
// draw boundary
1116
if (tagProperty->isPlacedInRTree() && s.drawBoundaries) {
1117
GLHelper::drawBoundary(s, getPlanCenteringBoundary());
1118
}
1119
// get detail level
1120
const auto d = s.getDetailLevel(1);
1121
// calculate path width double
1122
const double pathWidthDouble = s.addSize.getExaggeration(s, segment->getLane()) * planWidth * 2;
1123
// check if draw with double width
1124
const bool drawWithDoubleWidth = ((inspectedElements.getFirstAC() == myPlanElement) || (inspectedElements.getFirstAC() == planParent) || gViewObjectsHandler.isObjectSelected(myPlanElement));
1125
// draw geometry only if we'rent in drawForObjectUnderCursor mode
1126
if (!s.drawForViewObjectsHandler) {
1127
// push a draw matrix
1128
GLHelper::pushMatrix();
1129
// Start with the drawing of the area traslating matrix to origin
1130
myPlanElement->drawInLayer(myPlanElement->getType(), offsetFront);
1131
// Set plan color
1132
GLHelper::setColor(myPlanElement->drawUsingSelectColor() ? planSelectedColor : planColor);
1133
// check if draw lane2lane connection or a red line
1134
if (segment->getPreviousLane() && segment->getNextLane()) {
1135
if (segment->getPreviousLane()->getLane2laneConnections().exist(segment->getNextLane())) {
1136
// obtain lane2lane geometry
1137
const GUIGeometry& lane2laneGeometry = segment->getPreviousLane()->getLane2laneConnections().getLane2laneGeometry(segment->getNextLane());
1138
// draw lane2lane
1139
GUIGeometry::drawGeometry(d, lane2laneGeometry, pathWidthDouble * (drawWithDoubleWidth ? 1 : 0.5));
1140
} else {
1141
// Set invalid plan color
1142
GLHelper::setColor(RGBColor::RED);
1143
// draw line between end of first shape and first position of second shape
1144
GLHelper::drawBoxLines({segment->getPreviousLane()->getLaneShape().back(), segment->getNextLane()->getLaneShape().front()}, (0.5 * pathWidthDouble * (drawWithDoubleWidth ? 1 : 0.5)));
1145
}
1146
} else if (segment->getPreviousLane()) {
1147
// draw line between center of junction and last lane shape
1148
GLHelper::drawBoxLines({segment->getPreviousLane()->getLaneShape().back(), myPlanElement->getParentJunctions().back()->getPositionInView()}, pathWidthDouble * (drawWithDoubleWidth ? 1 : 0.5));
1149
} else if (segment->getNextLane()) {
1150
// draw line between center of junction and first lane shape
1151
GLHelper::drawBoxLines({myPlanElement->getParentJunctions().front()->getPositionInView(), segment->getNextLane()->getLaneShape().front()}, pathWidthDouble * (drawWithDoubleWidth ? 1 : 0.5));
1152
}
1153
// Pop last matrix
1154
GLHelper::popMatrix();
1155
// draw lock icon
1156
GNEViewNetHelper::LockIcon::drawLockIcon(d, myPlanElement, myPlanElement->getType(), myPlanElement->getPositionInView(), 0.5);
1157
// draw dotted contour
1158
segment->getContour()->drawDottedContours(s, d, myPlanElement, s.dottedContourSettings.segmentWidth, true);
1159
}
1160
// check if shape dotted contour has to be drawn
1161
if (segment->getPreviousLane() && segment->getNextLane()) {
1162
if (segment->getPreviousLane()->getLane2laneConnections().exist(segment->getNextLane())) {
1163
// get shape
1164
const auto& shape = segment->getPreviousLane()->getLane2laneConnections().getLane2laneGeometry(segment->getNextLane()).getShape();
1165
// calculate contour and draw dotted geometry (always with double width)
1166
segment->getContour()->calculateContourExtrudedShape(s, d, myPlanElement, shape, myPlanElement->getType(), pathWidthDouble, 1, false, false, 0, segment, segment->getJunction());
1167
}
1168
} else if (segment->getPreviousLane()) {
1169
segment->getContour()->calculateContourExtrudedShape(s, d, myPlanElement, {segment->getPreviousLane()->getLaneShape().back(), myPlanElement->getParentJunctions().back()->getPositionInView()},
1170
myPlanElement->getType(), pathWidthDouble, 1, false, true, 0, segment, segment->getJunction());
1171
} else if (segment->getNextLane()) {
1172
segment->getContour()->calculateContourExtrudedShape(s, d, myPlanElement, {myPlanElement->getParentJunctions().front()->getPositionInView(), segment->getNextLane()->getLaneShape().front()},
1173
myPlanElement->getType(), pathWidthDouble, 1, true, false, 0, segment, segment->getJunction());
1174
}
1175
// check if add this path element to redraw buffer
1176
if (!gViewObjectsHandler.isPathElementMarkForRedraw(myPlanElement) && segment->getContour()->checkDrawPathContour(s, d, myPlanElement)) {
1177
gViewObjectsHandler.addToRedrawPathElements(myPlanElement);
1178
}
1179
}
1180
// check if draw plan parent
1181
if (planParent->getPreviousChildDemandElement(myPlanElement) == nullptr) {
1182
planParent->drawGL(s);
1183
}
1184
}
1185
1186
1187
GNEDemandElement::Problem
1188
GNEDemandElementPlan::isPlanPersonValid() const {
1189
// get previous plan
1190
const auto previousPlan = myPlanElement->getParentDemandElements().at(0)->getPreviousChildDemandElement(myPlanElement);
1191
if (previousPlan) {
1192
// get previous lane
1193
const auto previousLastLane = previousPlan->getLastPathLane();
1194
// get first lane
1195
const auto firstLane = myPlanElement->getFirstPathLane();
1196
// compare edges
1197
if (previousLastLane && firstLane && (previousLastLane->getParentEdge() != firstLane->getParentEdge())) {
1198
return GNEDemandElement::Problem::DISCONNECTED_PLAN;
1199
}
1200
// in the future, check more elements
1201
}
1202
// get next child
1203
const auto nextPlan = myPlanElement->getParentDemandElements().at(0)->getNextChildDemandElement(myPlanElement);
1204
if (nextPlan) {
1205
// get previous lane
1206
const auto nextFirstLane = nextPlan->getFirstPathLane();
1207
// get first lane
1208
const auto lastLane = myPlanElement->getLastPathLane();
1209
// compare edges
1210
if (nextFirstLane && lastLane && (nextFirstLane->getParentEdge() != lastLane->getParentEdge())) {
1211
return GNEDemandElement::Problem::DISCONNECTED_PLAN;
1212
}
1213
// in the future, check more elements
1214
}
1215
// all ok, then return true
1216
return GNEDemandElement::Problem::OK;
1217
}
1218
1219
1220
std::string
1221
GNEDemandElementPlan::getPersonPlanProblem() const {
1222
// get previous plan
1223
const auto previousPlan = myPlanElement->getParentDemandElements().at(0)->getPreviousChildDemandElement(myPlanElement);
1224
if (previousPlan) {
1225
// get previous lane
1226
const auto previousLastLane = previousPlan->getLastPathLane();
1227
// get first lane
1228
const auto firstLane = myPlanElement->getLastPathLane();
1229
// compare edges
1230
if (previousLastLane && firstLane && (previousLastLane->getParentEdge() != firstLane->getParentEdge())) {
1231
return TLF("Edge '%' is not consecutive with edge '%'", previousLastLane->getParentEdge()->getID(), firstLane->getParentEdge()->getID());
1232
}
1233
// in the future, check more elements
1234
}
1235
// get next child
1236
const auto nextPlan = myPlanElement->getParentDemandElements().at(0)->getNextChildDemandElement(myPlanElement);
1237
if (nextPlan) {
1238
// get previous lane
1239
const auto nextFirstLane = nextPlan->getFirstPathLane();
1240
// get first lane
1241
const auto lastLane = myPlanElement->getLastPathLane();
1242
// compare edges
1243
if (nextFirstLane && lastLane && (nextFirstLane->getParentEdge() != lastLane->getParentEdge())) {
1244
return TLF("Edge '%' is not consecutive with edge '%'", nextFirstLane->getParentEdge()->getID(), lastLane->getParentEdge()->getID());
1245
}
1246
// in the future, check more elements
1247
}
1248
// undefined problem
1249
return "undefined problem";
1250
}
1251
1252
1253
double
1254
GNEDemandElementPlan::getEndPosRadius(const GUIVisualizationSettings& s, const GNESegment* segment, const bool drawHalfWidth) const {
1255
// check if myPlanElement is the last segment
1256
if (segment->isLastSegment()) {
1257
// calculate circle width
1258
const double circleRadius = (drawHalfWidth ? myArrivalPositionDiameter * 0.5 : myArrivalPositionDiameter);
1259
return circleRadius * MIN2((double)0.5, s.laneWidthExaggeration);
1260
} else {
1261
return -1;
1262
}
1263
}
1264
1265
1266
void
1267
GNEDemandElementPlan::drawFromArrow(const GUIVisualizationSettings& s, const GNELane* lane, const GNESegment* segment) const {
1268
// draw ifcurrent amd next segment is placed over lanes
1269
if (segment->getNextLane()) {
1270
// get firstPosition (last position of current lane shape)
1271
const Position from = lane->getLaneShape().back();
1272
// get lastPosition (first position of next lane shape)
1273
const Position to = segment->getNextLane()->getLaneShape().front();
1274
// push draw matrix
1275
GLHelper::pushMatrix();
1276
// move front
1277
glTranslated(0, 0, 4);
1278
// draw child line
1279
GUIGeometry::drawChildLine(s, from, to, RGBColor::RED, myPlanElement->isAttributeCarrierSelected(), .05);
1280
// pop draw matrix
1281
GLHelper::popMatrix();
1282
}
1283
}
1284
1285
1286
void
1287
GNEDemandElementPlan::drawToArrow(const GUIVisualizationSettings& s, const GNELane* lane, const GNESegment* segment) const {
1288
// draw the line if previos segment and current segment is placed over lanes
1289
if (segment->getPreviousLane()) {
1290
// get firstPosition (last position of current lane shape)
1291
const Position from = lane->getLaneShape().front();
1292
// get lastPosition (first position of next lane shape)
1293
const Position to = segment->getPreviousLane()->getLaneShape().back();
1294
// push draw matrix
1295
GLHelper::pushMatrix();
1296
// move front
1297
glTranslated(0, 0, 4);
1298
// draw child line
1299
GUIGeometry::drawChildLine(s, from, to, RGBColor::RED, myPlanElement->isAttributeCarrierSelected(), .05);
1300
// pop draw matrix
1301
GLHelper::popMatrix();
1302
}
1303
}
1304
1305
1306
void
1307
GNEDemandElementPlan::drawEndPosition(const GUIVisualizationSettings& /* s */, const GUIVisualizationSettings::Detail d, const double endPosRadius) const {
1308
// check if myPlanElement is the last segment
1309
if (endPosRadius > 0) {
1310
const Position geometryEndPos = getPlanAttributePosition(GNE_ATTR_PLAN_GEOMETRY_ENDPOS);
1311
// push draw matrix
1312
GLHelper::pushMatrix();
1313
// translate to pos and move to
1314
glTranslated(geometryEndPos.x(), geometryEndPos.y(), 4);
1315
// resolution of drawn circle depending of the zoom (To improve smothness)
1316
GLHelper::drawFilledCircleDetailled(d, endPosRadius);
1317
// pop draw matrix
1318
GLHelper::popMatrix();
1319
}
1320
}
1321
1322
1323
void
1324
GNEDemandElementPlan::replacePlanParent(const std::string& newParentID) {
1325
if (myPlanElement->myTagProperty->isPlanPerson()) {
1326
myPlanElement->replaceDemandElementParent(NamespaceIDs::persons, newParentID, 0);
1327
} else {
1328
myPlanElement->replaceDemandElementParent(NamespaceIDs::containers, newParentID, 0);
1329
}
1330
}
1331
1332
/****************************************************************************/
1333
1334