Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/demand/GNEDemandElement.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 GNEDemandElement.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Dec 2018
17
///
18
// A abstract class for demand elements
19
/****************************************************************************/
20
21
#include <netedit/frames/common/GNESelectorFrame.h>
22
#include <netedit/frames/demand/GNEContainerFrame.h>
23
#include <netedit/frames/demand/GNEContainerPlanFrame.h>
24
#include <netedit/frames/demand/GNEPersonFrame.h>
25
#include <netedit/frames/demand/GNEPersonPlanFrame.h>
26
#include <netedit/frames/demand/GNEVehicleFrame.h>
27
#include <netedit/frames/GNEPlanSelector.h>
28
#include <netedit/GNEApplicationWindow.h>
29
#include <netedit/GNENet.h>
30
#include <netedit/GNESegment.h>
31
#include <netedit/GNETagPropertiesDatabase.h>
32
#include <netedit/GNEViewParent.h>
33
#include <utils/gui/div/GLHelper.h>
34
#include <utils/gui/div/GUIDesigns.h>
35
#include <utils/gui/div/GUIParameterTableWindow.h>
36
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
37
38
#include "GNEDemandElement.h"
39
#include "GNERouteHandler.h"
40
41
// ===========================================================================
42
// member method definitions
43
// ===========================================================================
44
#ifdef _MSC_VER
45
#pragma warning(push)
46
#pragma warning(disable: 4355) // mask warning about "this" in initializers
47
#endif
48
49
GNEDemandElement::GNEDemandElement(GNENet* net, SumoXMLTag tag) :
50
GNEAttributeCarrier(tag, net),
51
GUIGlObject(myTagProperty->getGLType(), "", GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
52
GNEPathElement(myTagProperty->isRoute() ? GNEPathElement::Options::DEMAND_ELEMENT | GNEPathElement::Options::ROUTE :
53
GNEPathElement::Options::DEMAND_ELEMENT) {
54
}
55
56
57
GNEDemandElement::GNEDemandElement(const std::string& id, GNENet* net, SumoXMLTag tag, FileBucket* fileBucket) :
58
GNEAttributeCarrier(tag, net, fileBucket),
59
GUIGlObject(myTagProperty->getGLType(), id, GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
60
GNEPathElement(myTagProperty->isRoute() ? GNEPathElement::Options::DEMAND_ELEMENT | GNEPathElement::Options::ROUTE :
61
GNEPathElement::Options::DEMAND_ELEMENT) {
62
}
63
64
65
GNEDemandElement::GNEDemandElement(GNEDemandElement* demandElementParent, SumoXMLTag tag) :
66
GNEAttributeCarrier(tag, demandElementParent->getNet(), demandElementParent->getFileBucket()),
67
GUIGlObject(myTagProperty->getGLType(), demandElementParent->getID(), GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
68
GNEPathElement(myTagProperty->isRoute() ? GNEPathElement::Options::DEMAND_ELEMENT | GNEPathElement::Options::ROUTE :
69
GNEPathElement::Options::DEMAND_ELEMENT) {
70
}
71
#ifdef _MSC_VER
72
#pragma warning(pop)
73
#endif
74
75
GNEDemandElement::~GNEDemandElement() {}
76
77
78
GNEHierarchicalElement*
79
GNEDemandElement::getHierarchicalElement() {
80
return this;
81
}
82
83
84
GUIGlObject*
85
GNEDemandElement::getGUIGlObject() {
86
return this;
87
}
88
89
90
const GUIGlObject*
91
GNEDemandElement::getGUIGlObject() const {
92
return this;
93
}
94
95
96
FileBucket*
97
GNEDemandElement::getFileBucket() const {
98
if (myTagProperty->saveInParentFile()) {
99
if (isTemplate()) {
100
return nullptr;
101
} else {
102
return getParentDemandElements().front()->getFileBucket();
103
}
104
} else {
105
return myFileBucket;
106
}
107
}
108
109
110
void
111
GNEDemandElement::changeFileBucket(FileBucket* fileBucket) {
112
myFileBucket->removeElement(false);
113
myFileBucket = fileBucket;
114
myFileBucket->addElement(false);
115
// update options
116
myNet->getGNEApplicationWindow()->getFileBucketHandler()->updateOptions();
117
// mark demand elements to save
118
myNet->getSavingStatus()->requireSaveAdditionals();
119
myNet->getSavingStatus()->requireSaveDemandElements();
120
}
121
122
123
const GUIGeometry&
124
GNEDemandElement::getDemandElementGeometry() {
125
return myDemandElementGeometry;
126
}
127
128
129
GNEDemandElement*
130
GNEDemandElement::getPreviousChildDemandElement(const GNEDemandElement* demandElement) const {
131
// first check if there are demand elements
132
if (getChildDemandElements().empty()) {
133
return nullptr;
134
} else {
135
// find child demand element
136
auto it = std::find(getChildDemandElements().begin(), getChildDemandElements().end(), demandElement);
137
// return element or null depending of iterator
138
if (it == getChildDemandElements().end()) {
139
// in this case, we assume that the last child is the previos child
140
return getChildDemandElements().back();
141
} else if (it == getChildDemandElements().begin()) {
142
return nullptr;
143
} else {
144
return *(it - 1);
145
}
146
}
147
}
148
149
150
GNEDemandElement*
151
GNEDemandElement::getNextChildDemandElement(const GNEDemandElement* demandElement) const {
152
// find child demand element
153
auto it = std::find(getChildDemandElements().begin(), getChildDemandElements().end(), demandElement);
154
// return element or null depending of iterator
155
if (it == getChildDemandElements().end()) {
156
return nullptr;
157
} else if (it == (getChildDemandElements().end() - 1)) {
158
return nullptr;
159
} else {
160
return *(it + 1);
161
}
162
}
163
164
165
void
166
GNEDemandElement::updateDemandElementGeometry(const GNELane* lane, const double posOverLane) {
167
myDemandElementGeometry.updateGeometry(lane->getLaneShape(), posOverLane, /*myMovingLateralOffset*/ 0);
168
}
169
170
171
void
172
GNEDemandElement::updateDemandElementStackLabel(const int stack) {
173
myStackedLabelNumber = stack;
174
}
175
176
177
void
178
GNEDemandElement::updateDemandElementSpreadGeometry(const GNELane* lane, const double posOverLane) {
179
mySpreadGeometry.updateGeometry(lane->getLaneShape(), posOverLane, /*myMovingLateralOffset*/ 0);
180
}
181
182
183
const GUIGeometry&
184
GNEDemandElement::getDemandElementGeometry() const {
185
return myDemandElementGeometry;
186
}
187
188
189
bool
190
GNEDemandElement::checkDrawFromContour() const {
191
return false;
192
}
193
194
195
bool
196
GNEDemandElement::checkDrawToContour() const {
197
return false;
198
}
199
200
201
bool
202
GNEDemandElement::checkDrawRelatedContour() const {
203
if (myTagProperty->getTag() == GNE_TAG_ROUTE_EMBEDDED) {
204
// check if inspected parent is inspected
205
for (const auto& inspectedAC : myNet->getViewNet()->getInspectedElements().getACs()) {
206
if (inspectedAC->getTagProperty()->vehicleRouteEmbedded()) {
207
const auto demandElement = dynamic_cast<GNEDemandElement*>(inspectedAC);
208
if (demandElement && (demandElement->getChildDemandElements().size() > 0) &&
209
(demandElement->getChildDemandElements().at(0) == this)) {
210
return true;
211
}
212
}
213
}
214
}
215
// check opened popup
216
if (myNet->getViewNet()->getPopup()) {
217
return myNet->getViewNet()->getPopup()->getGLObject() == this;
218
}
219
return false;
220
}
221
222
223
bool
224
GNEDemandElement::checkDrawOverContour() const {
225
// get modes
226
const auto& modes = myNet->getViewNet()->getEditModes();
227
// get frames
228
const auto& personFramePlanSelector = myNet->getViewParent()->getPersonFrame()->getPlanSelector();
229
const auto& personPlanFramePlanSelector = myNet->getViewParent()->getPersonPlanFrame()->getPlanSelector();
230
const auto& containerFramePlanSelector = myNet->getViewParent()->getContainerFrame()->getPlanSelector();
231
const auto& containerPlanFramePlanSelector = myNet->getViewParent()->getContainerPlanFrame()->getPlanSelector();
232
// special case for Route
233
if (myTagProperty->getTag() == SUMO_TAG_ROUTE) {
234
// get vehicle frame
235
const auto& vehicleFrame = myNet->getViewParent()->getVehicleFrame();
236
// check if we're in vehicle mode
237
if (vehicleFrame->shown()) {
238
// get current vehicle template
239
const auto& vehicleTemplate = vehicleFrame->getVehicleTagSelector()->getCurrentTemplateAC();
240
// check if vehicle can be placed over route
241
if (vehicleTemplate && vehicleTemplate->getTagProperty()->vehicleRoute()) {
242
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
243
}
244
} else if (modes.isCurrentSupermodeDemand()) {
245
// check if we're in person or personPlan modes
246
if (((modes.demandEditMode == DemandEditMode::DEMAND_PERSON) && personFramePlanSelector->markRoutes()) ||
247
((modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) && personPlanFramePlanSelector->markRoutes()) ||
248
((modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) && containerFramePlanSelector->markRoutes()) ||
249
((modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) && containerPlanFramePlanSelector->markRoutes())) {
250
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
251
}
252
}
253
}
254
return false;
255
}
256
257
258
bool
259
GNEDemandElement::checkDrawDeleteContour() const {
260
// get edit modes
261
const auto& editModes = myNet->getViewNet()->getEditModes();
262
// check if we're in delete mode
263
if (editModes.isCurrentSupermodeDemand() && (editModes.demandEditMode == DemandEditMode::DEMAND_DELETE)) {
264
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
265
} else {
266
return false;
267
}
268
}
269
270
271
bool
272
GNEDemandElement::checkDrawDeleteContourSmall() const {
273
if (myTagProperty->vehicleRoute()) {
274
const auto route = myNet->getViewNet()->getViewObjectsSelector().getDemandElementFront();
275
if (route && (route == myNet->getViewNet()->getViewObjectsSelector().getAttributeCarrierFront())) {
276
return (getParentDemandElements().at(1) == route);
277
}
278
} else if (myTagProperty->getTag() == GNE_TAG_ROUTE_EMBEDDED) {
279
const auto vehicle = myNet->getViewNet()->getViewObjectsSelector().getDemandElementFront();
280
if (vehicle && (vehicle == myNet->getViewNet()->getViewObjectsSelector().getAttributeCarrierFront())) {
281
return (getParentDemandElements().front() == vehicle);
282
}
283
}
284
return false;
285
}
286
287
288
bool
289
GNEDemandElement::checkDrawSelectContour() const {
290
// get edit modes
291
const auto& editModes = myNet->getViewNet()->getEditModes();
292
// check if we're in select mode
293
if (editModes.isCurrentSupermodeDemand() && (editModes.demandEditMode == DemandEditMode::DEMAND_SELECT)) {
294
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
295
} else {
296
return false;
297
}
298
}
299
300
301
bool
302
GNEDemandElement::checkDrawMoveContour() const {
303
// get edit modes
304
const auto& editModes = myNet->getViewNet()->getEditModes();
305
// check first set of conditions
306
if (!myNet->getViewNet()->isCurrentlyMovingElements() && // another elements are not currently moved
307
editModes.isCurrentSupermodeDemand() && // supermode demand
308
(editModes.demandEditMode == DemandEditMode::DEMAND_MOVE) && // move mode
309
myNet->getViewNet()->checkOverLockedElement(this, mySelected) && // no locked
310
myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this) { // first element
311
// continue depending of subtype
312
if (myTagProperty->isVehicle()) {
313
// only vehicles over edges can be moved
314
if (myTagProperty->vehicleEdges() || myTagProperty->vehicleRoute() || myTagProperty->vehicleRouteEmbedded()) {
315
return true;
316
} else {
317
return false;
318
}
319
} else if ((myTagProperty->isPerson() || myTagProperty->isContainer()) && (getChildDemandElements().size() > 0)) {
320
// only persons/containers with their first plan over edge can be moved
321
return getChildDemandElements().front()->getTagProperty()->planFromEdge();
322
} else {
323
return false;
324
}
325
} else {
326
return false;
327
}
328
}
329
330
331
void
332
GNEDemandElement::openDemandElementDialog() {
333
throw InvalidArgument(getTagStr() + " doesn't have a demand element dialog");
334
}
335
336
337
GUIGLObjectPopupMenu*
338
GNEDemandElement::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
339
// create popup
340
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
341
// build common options
342
buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected);
343
// show option to open demand element dialog
344
if (myTagProperty->hasDialog()) {
345
GUIDesigns::buildFXMenuCommand(ret, ("Open " + getTagStr() + " Dialog").c_str(), getACIcon(), &parent, MID_OPEN_ADDITIONAL_DIALOG);
346
new FXMenuSeparator(ret);
347
}
348
GUIDesigns::buildFXMenuCommand(ret, "Cursor position in view: " + toString(getPositionInView().x()) + "," + toString(getPositionInView().y()), nullptr, nullptr, 0);
349
return ret;
350
}
351
352
353
GUIParameterTableWindow*
354
GNEDemandElement::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
355
// Create table
356
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
357
// Iterate over attributes
358
for (const auto& attrProperty : myTagProperty->getAttributeProperties()) {
359
// Add attribute and set it dynamic if aren't unique
360
if (attrProperty->isUnique()) {
361
ret->mkItem(attrProperty->getAttrStr().c_str(), false, getAttribute(attrProperty->getAttr()));
362
} else {
363
ret->mkItem(attrProperty->getAttrStr().c_str(), true, getAttribute(attrProperty->getAttr()));
364
}
365
}
366
// close building
367
ret->closeBuilding();
368
return ret;
369
}
370
371
372
bool
373
GNEDemandElement::isGLObjectLocked() const {
374
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand()) {
375
return myNet->getViewNet()->getLockManager().isObjectLocked(getType(), isAttributeCarrierSelected());
376
} else {
377
return true;
378
}
379
}
380
381
382
void
383
GNEDemandElement::markAsFrontElement() {
384
markForDrawingFront();
385
}
386
387
388
void
389
GNEDemandElement::deleteGLObject() {
390
// we need an special checks due hierarchies
391
if (myTagProperty->isPlan()) {
392
// get person/container plarent
393
GNEDemandElement* planParent = getParentDemandElements().front();
394
// if this is the last person/container plan element, remove parent instead plan
395
if (planParent->getChildDemandElements().size() == 1) {
396
planParent->deleteGLObject();
397
} else {
398
myNet->deleteDemandElement(this, myNet->getUndoList());
399
}
400
} else if (myTagProperty->getTag() == GNE_TAG_ROUTE_EMBEDDED) {
401
// remove parent demand element
402
getParentDemandElements().front()->deleteGLObject();
403
} else {
404
myNet->deleteDemandElement(this, myNet->getUndoList());
405
}
406
}
407
408
409
void
410
GNEDemandElement::selectGLObject() {
411
if (isAttributeCarrierSelected()) {
412
unselectAttributeCarrier();
413
} else {
414
selectAttributeCarrier();
415
}
416
// update information label
417
myNet->getViewParent()->getSelectorFrame()->getSelectionInformation()->updateInformationLabel();
418
}
419
420
421
void
422
GNEDemandElement::updateGLObject() {
423
updateGeometry();
424
}
425
426
427
Position
428
GNEDemandElement::getAttributePosition(SumoXMLAttr key) const {
429
return getCommonAttributePosition(key);
430
}
431
432
433
PositionVector
434
GNEDemandElement::getAttributePositionVector(SumoXMLAttr key) const {
435
return getCommonAttributePositionVector(key);
436
}
437
438
439
bool
440
GNEDemandElement::isPathElementSelected() const {
441
return mySelected;
442
}
443
444
// ---------------------------------------------------------------------------
445
// GNEDemandElement - protected methods
446
// ---------------------------------------------------------------------------
447
448
bool
449
GNEDemandElement::isValidDemandElementID(const std::string& value) const {
450
if (!isTemplate() && (value == getID())) {
451
return true;
452
} else if (SUMOXMLDefinitions::isValidVehicleID(value)) {
453
return (myNet->getAttributeCarriers()->retrieveDemandElement(myTagProperty->getTag(), value, false) == nullptr);
454
} else {
455
return false;
456
}
457
}
458
459
460
bool
461
GNEDemandElement::isValidDemandElementID(const std::vector<SumoXMLTag>& tags, const std::string& value) const {
462
if (isTemplate() && value.empty()) {
463
return true;
464
} else if (!isTemplate() && (value == getID())) {
465
return true;
466
} else if (SUMOXMLDefinitions::isValidVehicleID(value)) {
467
return (myNet->getAttributeCarriers()->retrieveDemandElements(tags, value, false) == nullptr);
468
} else {
469
return false;
470
}
471
}
472
473
474
void
475
GNEDemandElement::setDemandElementID(const std::string& newID) {
476
// update ID
477
if (isTemplate() || !myTagProperty->hasAttribute(SUMO_ATTR_ID)) {
478
setMicrosimID(newID);
479
} else {
480
myNet->getAttributeCarriers()->updateDemandElementID(this, newID);
481
}
482
// check if update ids of child elements
483
if (myTagProperty->isPerson() || myTagProperty->isContainer()) {
484
// Change IDs of all person plans children (stops, embedded routes...)
485
for (const auto& childDemandElement : getChildDemandElements()) {
486
childDemandElement->setDemandElementID(getID());
487
}
488
}
489
}
490
491
492
GNEDemandElement*
493
GNEDemandElement::getTypeParent() const {
494
if (getParentDemandElements().size() < 1) {
495
throw InvalidArgument("This demand element doesn't have a type parent");
496
} else if ((getParentDemandElements().at(0)->getTagProperty()->isType()) ||
497
(getParentDemandElements().at(0)->getTagProperty()->isTypeDistribution())) {
498
return getParentDemandElements().at(0);
499
} else {
500
throw InvalidArgument("The first parent isn't a type");
501
}
502
}
503
504
505
GNEDemandElement*
506
GNEDemandElement::getRouteParent() const {
507
if (getParentDemandElements().size() < 2) {
508
throw InvalidArgument("This demand element doesn't have a route parent");
509
} else if ((getParentDemandElements().at(1)->getTagProperty()->isRoute()) ||
510
(getParentDemandElements().at(1)->getTagProperty()->isRouteDistribution())) {
511
return getParentDemandElements().at(1);
512
} else {
513
throw InvalidArgument("The second parent isn't a route");
514
}
515
}
516
517
518
std::vector<GNEDemandElement*>
519
GNEDemandElement::getInvalidStops() const {
520
if (myTagProperty->isVehicleStop()) {
521
// get stops
522
std::vector<GNEDemandElement*> invalidStops;
523
// get edge stop index
524
const auto edgeStopIndex = getEdgeStopIndex();
525
// take all stops/waypoints with index = -1
526
for (const auto& edgeStop : edgeStopIndex) {
527
if (edgeStop.stopIndex == -1) {
528
for (const auto& stop : edgeStop.stops) {
529
invalidStops.push_back(stop);
530
}
531
}
532
}
533
return invalidStops;
534
} else {
535
return {};
536
}
537
}
538
539
540
void
541
GNEDemandElement::drawJunctionLine(const GNEDemandElement* element) const {
542
// get two points
543
const Position posA = element->getParentJunctions().front()->getPositionInView();
544
const Position posB = element->getParentJunctions().back()->getPositionInView();
545
const double rot = ((double)atan2((posB.x() - posA.x()), (posA.y() - posB.y())) * (double) 180.0 / (double)M_PI);
546
const double len = posA.distanceTo2D(posB);
547
// push draw matrix
548
GLHelper::pushMatrix();
549
// Start with the drawing of the area traslating matrix to origin
550
drawInLayer(element->getType() + 0.1);
551
// set trip color
552
GLHelper::setColor(RGBColor::RED);
553
// draw line
554
GLHelper::drawBoxLine(posA, rot, len, 0.25);
555
// pop draw matrix
556
GLHelper::popMatrix();
557
}
558
559
560
void
561
GNEDemandElement::drawStackLabel(const int number, const std::string& element, const Position& position, const double rotation,
562
const double width, const double length, const double exaggeration) const {
563
// declare contour width
564
const double contourWidth = (0.05 * exaggeration);
565
// Push matrix
566
GLHelper::pushMatrix();
567
// Traslate to top
568
glTranslated(position.x(), position.y(), GLO_VEHICLELABELS);
569
glRotated(rotation, 0, 0, -1);
570
glTranslated((width * exaggeration * 0.5) + (0.35 * exaggeration) + 0.05, 0, 0);
571
// draw external box
572
GLHelper::setColor(RGBColor::GREY);
573
GLHelper::drawBoxLine(Position(), 0, (length * exaggeration), 0.3 * exaggeration);
574
// draw internal box
575
glTranslated(0, 0, 0.1);
576
GLHelper::setColor(RGBColor(0, 128, 0));
577
GLHelper::drawBoxLine(Position(0, -contourWidth), Position(0, -contourWidth), 0, (length * exaggeration) - (contourWidth * 2), (0.3 * exaggeration) - contourWidth);
578
// draw stack label
579
GLHelper::drawText(element + "s stacked: " + toString(number), Position(0, length * exaggeration * -0.5), (.1 * exaggeration), (0.6 * exaggeration), RGBColor::WHITE, 90, 0, -1);
580
// pop draw matrix
581
GLHelper::popMatrix();
582
}
583
584
585
void
586
GNEDemandElement::replaceParentEdges(const std::string& value) {
587
auto newEdges = parse<GNEHierarchicalContainerParents<GNEEdge*> >(getNet(), value);
588
GNEHierarchicalElement::updateParents(this, newEdges);;
589
}
590
591
592
void
593
GNEDemandElement::replaceFirstParentLane(const std::string& value) {
594
auto newLane = myNet->getAttributeCarriers()->retrieveLane(value);
595
GNEHierarchicalElement::updateParent(this, 0, newLane);
596
}
597
598
599
void
600
GNEDemandElement::replaceFirstParentJunction(const std::string& value) {
601
auto newJunction = myNet->getAttributeCarriers()->retrieveJunction(value);
602
GNEHierarchicalElement::updateParent(this, 0, newJunction);
603
}
604
605
606
void
607
GNEDemandElement::replaceLastParentJunction(const std::string& value) {
608
auto newJunction = myNet->getAttributeCarriers()->retrieveJunction(value);
609
GNEHierarchicalElement::updateParent(this, (int)getParentJunctions().size() - 1, newJunction);
610
}
611
612
613
void
614
GNEDemandElement::replaceFirstParentEdge(const std::string& value) {
615
auto newEdge = myNet->getAttributeCarriers()->retrieveEdge(value);
616
GNEHierarchicalElement::updateParent(this, 0, newEdge);
617
}
618
619
620
void
621
GNEDemandElement::replaceLastParentEdge(const std::string& value) {
622
auto newEdge = myNet->getAttributeCarriers()->retrieveEdge(value);
623
GNEHierarchicalElement::updateParent(this, (int)getParentEdges().size() - 1, newEdge);
624
}
625
626
627
void
628
GNEDemandElement::replaceFirstParentAdditional(SumoXMLTag tag, const std::string& value) {
629
auto newAdditional = myNet->getAttributeCarriers()->retrieveAdditional(tag, value);
630
GNEHierarchicalElement::updateParent(this, 0, newAdditional);
631
}
632
633
634
void
635
GNEDemandElement::replaceLastParentAdditional(SumoXMLTag tag, const std::string& value) {
636
auto newAdditional = myNet->getAttributeCarriers()->retrieveAdditional(tag, value);
637
GNEHierarchicalElement::updateParent(this, (int)getParentAdditionals().size() - 1, newAdditional);
638
}
639
640
641
void
642
GNEDemandElement::replaceDemandElementParent(const std::vector<SumoXMLTag> tags, const std::string& value, const int parentIndex) {
643
GNEDemandElement* newDemandElement = nullptr;
644
// search demand element
645
for (auto it = tags.begin(); (it != tags.end()) && (newDemandElement == nullptr); it++) {
646
newDemandElement = myNet->getAttributeCarriers()->retrieveDemandElement(*it, value, false);
647
}
648
if (newDemandElement) {
649
GNEHierarchicalElement::updateParent(this, parentIndex, newDemandElement);
650
} else {
651
throw ProcessError("Attempted to replace with non-existant demand element " + value);
652
}
653
}
654
655
656
bool
657
GNEDemandElement::checkChildDemandElementRestriction() const {
658
// throw exception because this function mus be implemented in child (see GNEE3Detector)
659
throw ProcessError(StringUtils::format("Calling non-implemented function checkChildDemandElementRestriction during saving of %. It muss be reimplemented in child class", getTagStr()));
660
}
661
662
663
std::vector<GNEDemandElement::EdgeStopIndex>
664
GNEDemandElement::getEdgeStopIndex() const {
665
std::vector<GNEDemandElement::EdgeStopIndex> edgeStopIndex;
666
// first check that this stop has parent
667
if (getParentDemandElements().size() > 0) {
668
// get path edges depending of parent
669
std::vector<GNEEdge*> pathEdges;
670
// get parent demand element
671
const auto parent = getParentDemandElements().front();
672
// continue depending of parent
673
if (parent->getTagProperty()->hasAttribute(SUMO_ATTR_EDGES)) {
674
pathEdges = parent->getParentEdges();
675
} else if (parent->getTagProperty()->vehicleRoute()) {
676
// get route edges
677
if (parent->getParentDemandElements().size() > 1) {
678
pathEdges = parent->getParentDemandElements().at(1)->getParentEdges();
679
}
680
} else if (parent->getTagProperty()->vehicleRouteEmbedded()) {
681
// get embedded route edges
682
pathEdges = parent->getChildDemandElements().front()->getParentEdges();
683
} else {
684
// get last parent edge
685
const auto lastEdge = parent->getParentEdges().back();
686
bool stop = false;
687
const auto& pathElementSegments = myNet->getDemandPathManager()->getPathElementSegments(parent);
688
// extract all edges from pathElement parent
689
for (auto it = pathElementSegments.begin(); (it != pathElementSegments.end()) && !stop; it++) {
690
if ((*it)->getLane()) {
691
pathEdges.push_back((*it)->getLane()->getParentEdge());
692
// stop if path correspond to last edge
693
if (pathEdges.back() == lastEdge) {
694
stop = true;
695
}
696
}
697
}
698
}
699
// get all parent's stops and waypoints sorted by position
700
for (const auto& demandElement : parent->getChildDemandElements()) {
701
if (demandElement->getTagProperty()->isVehicleStop()) {
702
// get stop/waypoint edge
703
GNEEdge* edge = nullptr;
704
if (demandElement->getParentAdditionals().size() > 0) {
705
edge = demandElement->getParentAdditionals().front()->getParentLanes().front()->getParentEdge();
706
} else {
707
edge = demandElement->getParentLanes().front()->getParentEdge();
708
}
709
// check if add a new edgeStopIndex or update last
710
if ((edgeStopIndex.size() > 0) && (edgeStopIndex.back().edge == edge)) {
711
edgeStopIndex.back().stops.push_back(demandElement);
712
} else {
713
edgeStopIndex.push_back(EdgeStopIndex(edge, demandElement));
714
}
715
}
716
}
717
// declare index for current stop
718
int currentEdgeStopIndex = 0;
719
for (int i = 0; (i < (int)pathEdges.size()) && (currentEdgeStopIndex < (int)edgeStopIndex.size()); i++) {
720
// check if current edge stop index is in the path
721
if (edgeStopIndex[currentEdgeStopIndex].edge == pathEdges.at(i)) {
722
edgeStopIndex[currentEdgeStopIndex].stopIndex = i;
723
currentEdgeStopIndex++;
724
} else {
725
// check if edge exist in the rest of the path
726
bool next = false;
727
for (int j = (i + 1); j < (int)pathEdges.size(); j++) {
728
if (edgeStopIndex[currentEdgeStopIndex].edge == pathEdges.at(j)) {
729
next = true;
730
}
731
}
732
if (!next) {
733
// ignore current stops (because is out of path)
734
currentEdgeStopIndex++;
735
}
736
}
737
}
738
}
739
// sort stops by position
740
for (auto& edgeStop : edgeStopIndex) {
741
if (edgeStop.stops.size() > 1) {
742
// copy all stops to a map to sort it by endPos
743
std::map<double, std::vector<GNEDemandElement*> > sortedStops;
744
for (const auto& stop : edgeStop.stops) {
745
if (sortedStops.count(stop->getAttributeDouble(SUMO_ATTR_ENDPOS)) == 0) {
746
sortedStops[stop->getAttributeDouble(SUMO_ATTR_ENDPOS)] = {stop};
747
} else {
748
sortedStops[stop->getAttributeDouble(SUMO_ATTR_ENDPOS)].push_back(stop);
749
}
750
}
751
// update stops with sorted stops
752
edgeStop.stops.clear();
753
for (const auto& sortedStop : sortedStops) {
754
edgeStop.stops.insert(edgeStop.stops.end(), sortedStop.second.begin(), sortedStop.second.end());
755
}
756
}
757
}
758
return edgeStopIndex;
759
}
760
761
762
RGBColor
763
GNEDemandElement::getColorByScheme(const GUIColorer& c, const SUMOVehicleParameter* parameters) const {
764
// set color depending of color active
765
switch (c.getActive()) {
766
case 0: {
767
// test for emergency vehicle
768
if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "emergency") {
769
return RGBColor::WHITE;
770
}
771
// test for firebrigade
772
if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "firebrigade") {
773
return RGBColor::RED;
774
}
775
// test for police car
776
if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "police") {
777
return RGBColor::BLUE;
778
}
779
if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "scooter") {
780
return RGBColor::WHITE;
781
}
782
// check if color was set
783
if (parameters->wasSet(VEHPARS_COLOR_SET)) {
784
return parameters->color;
785
} else {
786
// take their parent's color)
787
return getTypeParent()->getColor();
788
}
789
}
790
case 2: {
791
if (parameters->wasSet(VEHPARS_COLOR_SET)) {
792
return parameters->color;
793
} else {
794
return c.getScheme().getColor(0);
795
}
796
}
797
case 3: {
798
if (getTypeParent()->isAttributeEnabled(SUMO_ATTR_COLOR)) {
799
return getTypeParent()->getColor();
800
} else {
801
return c.getScheme().getColor(0);
802
}
803
}
804
case 4: {
805
if (getRouteParent()->getColor() != RGBColor::DEFAULT_COLOR) {
806
return getRouteParent()->getColor();
807
} else {
808
return c.getScheme().getColor(0);
809
}
810
}
811
case 5: {
812
Position p = getRouteParent()->getParentEdges().at(0)->getChildLanes().at(0)->getLaneShape()[0];
813
const Boundary& b = myNet->getBoundary();
814
Position center = b.getCenter();
815
double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
816
double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
817
return RGBColor::fromHSV(hue, sat, 1.);
818
}
819
case 6: {
820
Position p = getRouteParent()->getParentEdges().back()->getChildLanes().at(0)->getLaneShape()[-1];
821
const Boundary& b = myNet->getBoundary();
822
Position center = b.getCenter();
823
double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
824
double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
825
return RGBColor::fromHSV(hue, sat, 1.);
826
}
827
case 7: {
828
Position pb = getRouteParent()->getParentEdges().at(0)->getChildLanes().at(0)->getLaneShape()[0];
829
Position pe = getRouteParent()->getParentEdges().back()->getChildLanes().at(0)->getLaneShape()[-1];
830
const Boundary& b = myNet->getBoundary();
831
double hue = 180. + atan2(pb.x() - pe.x(), pb.y() - pe.y()) * 180. / M_PI;
832
Position minp(b.xmin(), b.ymin());
833
Position maxp(b.xmax(), b.ymax());
834
double sat = pb.distanceTo(pe) / minp.distanceTo(maxp);
835
return RGBColor::fromHSV(hue, sat, 1.);
836
}
837
case 35: { // color randomly (by pointer hash)
838
std::hash<const GNEDemandElement*> ptr_hash;
839
const double hue = (double)(ptr_hash(this) % 360); // [0-360]
840
const double sat = (double)((ptr_hash(this) / 360) % 67) / 100. + 0.33; // [0.33-1]
841
return RGBColor::fromHSV(hue, sat, 1.);
842
}
843
default: {
844
return c.getScheme().getColor(0);
845
}
846
}
847
}
848
849
850
void
851
GNEDemandElement::buildMenuCommandRouteLength(GUIGLObjectPopupMenu* ret) const {
852
std::vector<GNEEdge*> edges;
853
if (myTagProperty->isRoute()) {
854
edges = getParentEdges();
855
} else if (myTagProperty->vehicleRoute()) {
856
edges = getParentDemandElements().at(1)->getParentEdges();
857
} else if (myTagProperty->vehicleRouteEmbedded()) {
858
edges = getChildDemandElements().front()->getParentEdges();
859
} else if (myTagProperty->vehicleEdges()) {
860
edges = getParentEdges();
861
}
862
// calculate path
863
const auto path = myNet->getDemandPathManager()->getPathCalculator()->calculateDijkstraPath(getVClass(), edges);
864
// check path size
865
if (path.size() > 0) {
866
double length = 0;
867
for (const auto& edge : path) {
868
length += edge->getNBEdge()->getFinalLength();
869
}
870
for (int i = 0; i < ((int)path.size() - 1); i++) {
871
length += path.at(i)->getChildLanes().front()->getLane2laneConnections().getLane2laneGeometry(path.at(i + 1)->getChildLanes().front()).getShape().length();
872
}
873
GUIDesigns::buildFXMenuCommand(ret, TL("Route length: ") + toString(length), nullptr, ret, MID_COPY_NAME);
874
}
875
}
876
877
878
void
879
GNEDemandElement::buildMenuAddReverse(GUIGLObjectPopupMenu* ret) const {
880
// create menu pane for transform operations
881
FXMenuPane* transformOperation = new FXMenuPane(ret);
882
ret->insertMenuPaneChild(transformOperation);
883
auto reverseMenuCascade = new FXMenuCascade(ret, TL("reverse"), nullptr, transformOperation);
884
// build menu commands
885
GUIDesigns::buildFXMenuCommand(transformOperation, TLF("reverse current %", myTagProperty->getTagStr()), nullptr, myNet->getViewNet(), MID_GNE_REVERSE);
886
GUIDesigns::buildFXMenuCommand(transformOperation, TLF("Add reverse %", myTagProperty->getTagStr()), nullptr, myNet->getViewNet(), MID_GNE_ADDREVERSE);
887
// check if reverse can be added
888
if (GNERouteHandler::canReverse(this)) {
889
reverseMenuCascade->enable();
890
} else {
891
reverseMenuCascade->disable();
892
}
893
}
894
895
/****************************************************************************/
896
897