Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEAdditional.cpp
193871 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GNEAdditional.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Dec 2015
17
///
18
// A abstract class for representation of additional elements
19
/****************************************************************************/
20
#include <config.h>
21
22
#include <foreign/fontstash/fontstash.h>
23
#include <netedit/frames/common/GNEInspectorFrame.h>
24
#include <netedit/frames/common/GNEMoveFrame.h>
25
#include <netedit/frames/common/GNESelectorFrame.h>
26
#include <netedit/frames/data/GNETAZRelDataFrame.h>
27
#include <netedit/frames/demand/GNEContainerFrame.h>
28
#include <netedit/frames/demand/GNEContainerPlanFrame.h>
29
#include <netedit/frames/demand/GNEPersonFrame.h>
30
#include <netedit/frames/demand/GNEPersonPlanFrame.h>
31
#include <netedit/frames/demand/GNEVehicleFrame.h>
32
#include <netedit/frames/GNEAttributesEditor.h>
33
#include <netedit/frames/GNEPathCreator.h>
34
#include <netedit/frames/GNEPlanCreator.h>
35
#include <netedit/GNEApplicationWindow.h>
36
#include <netedit/GNENet.h>
37
#include <netedit/GNETagPropertiesDatabase.h>
38
#include <netedit/GNEViewParent.h>
39
#include <utils/gui/div/GLHelper.h>
40
#include <utils/gui/div/GUIDesigns.h>
41
#include <utils/gui/div/GUIParameterTableWindow.h>
42
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
43
44
#include "GNEAdditional.h"
45
#include "GNETAZ.h"
46
47
// ===========================================================================
48
// member method definitions
49
// ===========================================================================
50
51
GNEAdditional::GNEAdditional(GNENet* net, SumoXMLTag tag) :
52
GNEAttributeCarrier(tag, net),
53
GUIGlObject(myTagProperty->getGLType(), "", GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
54
GNEPathElement(GNEPathElement::Options::ADDITIONAL_ELEMENT) {
55
}
56
57
58
GNEAdditional::GNEAdditional(const std::string& id, GNENet* net, SumoXMLTag tag, FileBucket* fileBucket, const std::string& name) :
59
GNEAttributeCarrier(tag, net, fileBucket),
60
GUIGlObject(myTagProperty->getGLType(), id, GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
61
GNEPathElement(GNEPathElement::Options::ADDITIONAL_ELEMENT),
62
myAdditionalName(name) {
63
}
64
65
66
GNEAdditional::GNEAdditional(GNEAdditional* additionalParent, SumoXMLTag tag, const std::string& name) :
67
GNEAttributeCarrier(tag, additionalParent->getNet(), additionalParent->getFileBucket()),
68
GUIGlObject(myTagProperty->getGLType(), "", GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
69
GNEPathElement(GNEPathElement::Options::ADDITIONAL_ELEMENT),
70
myAdditionalName(name) {
71
}
72
73
74
GNEAdditional::~GNEAdditional() {}
75
76
77
GNEHierarchicalElement*
78
GNEAdditional::getHierarchicalElement() {
79
return this;
80
}
81
82
83
GUIGlObject*
84
GNEAdditional::getGUIGlObject() {
85
return this;
86
}
87
88
89
const GUIGlObject*
90
GNEAdditional::getGUIGlObject() const {
91
return this;
92
}
93
94
95
FileBucket*
96
GNEAdditional::getFileBucket() const {
97
if (myTagProperty->saveInParentFile()) {
98
if (isTemplate()) {
99
return nullptr;
100
} else {
101
return getParentAdditionals().front()->getFileBucket();
102
}
103
} else {
104
return myFileBucket;
105
}
106
}
107
108
109
const std::string
110
GNEAdditional::getOptionalName() const {
111
try {
112
return getAttribute(SUMO_ATTR_NAME);
113
} catch (InvalidArgument&) {
114
return "";
115
}
116
}
117
118
119
const GUIGeometry&
120
GNEAdditional::getAdditionalGeometry() const {
121
return myAdditionalGeometry;
122
}
123
124
125
void
126
GNEAdditional::setSpecialColor(const RGBColor* color) {
127
mySpecialColor = color;
128
}
129
130
131
void
132
GNEAdditional::resetAdditionalContour() {
133
myAdditionalContour.clearContour();
134
}
135
136
137
bool
138
GNEAdditional::isAdditionalValid() const {
139
return true;
140
}
141
142
143
std::string
144
GNEAdditional::getAdditionalProblem() const {
145
return "";
146
}
147
148
149
void
150
GNEAdditional::fixAdditionalProblem() {
151
throw InvalidArgument(getTagStr() + " cannot fix any problem");
152
}
153
154
155
void
156
GNEAdditional::openAdditionalDialog(FXWindow* /* restoringFocusWindow */) {
157
throw InvalidArgument(getTagStr() + " doesn't have an additional dialog");
158
}
159
160
161
double
162
GNEAdditional::getExaggeration(const GUIVisualizationSettings& s) const {
163
return s.addSize.getExaggeration(s, this);
164
}
165
166
167
Boundary
168
GNEAdditional::getCenteringBoundary() const {
169
if (myAdditionalBoundary.isInitialised()) {
170
return myAdditionalBoundary;
171
} else {
172
Boundary contourBoundary = myAdditionalContour.getContourBoundary();
173
if (contourBoundary.isInitialised()) {
174
contourBoundary.grow(5);
175
return contourBoundary;
176
} else if (myAdditionalGeometry.getShape().size() > 0) {
177
Boundary geometryBoundary = myAdditionalGeometry.getShape().getBoxBoundary();
178
geometryBoundary.grow(5);
179
return geometryBoundary;
180
} else if (getParentAdditionals().size() > 0) {
181
return getParentAdditionals().front()->getCenteringBoundary();
182
} else {
183
Boundary centerBoundary(0, 0, 0, 0);
184
centerBoundary.grow(5);
185
return centerBoundary;
186
}
187
}
188
}
189
190
191
bool
192
GNEAdditional::checkDrawFromContour() const {
193
// get modes and viewParent (for code legibility)
194
const auto& modes = myNet->getViewNet()->getEditModes();
195
const auto& viewParent = myNet->getViewParent();
196
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
197
// continue depending of current status
198
if (inspectedElements.isInspectingSingleElement()) {
199
const auto inspectedAC = inspectedElements.getFirstAC();
200
// check conditions
201
if (inspectedAC->hasAttribute(SUMO_ATTR_FROM_TAZ)) {
202
return (inspectedAC->getAttribute(SUMO_ATTR_FROM_TAZ) == getID());
203
} else if ((inspectedAC->getTagProperty()->getTag() == SUMO_TAG_TAZREL)) {
204
return (inspectedAC->getAttribute(SUMO_ATTR_FROM) == getID());
205
}
206
} else if (modes.isCurrentSupermodeDemand()) {
207
// get current GNEPlanCreator
208
GNEPlanCreator* planCreator = nullptr;
209
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
210
planCreator = viewParent->getPersonFrame()->getPlanCreator();
211
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
212
planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();
213
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
214
planCreator = viewParent->getContainerFrame()->getPlanCreator();
215
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
216
planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();
217
}
218
// continue depending of planCreator
219
if (planCreator) {
220
// check if this is the from additional
221
const auto additionalID = getID();
222
if ((planCreator->getPlanParameteres().fromBusStop == additionalID) ||
223
(planCreator->getPlanParameteres().fromTrainStop == additionalID) ||
224
(planCreator->getPlanParameteres().fromContainerStop == additionalID) ||
225
(planCreator->getPlanParameteres().fromChargingStation == additionalID) ||
226
(planCreator->getPlanParameteres().fromParkingArea == additionalID) ||
227
(planCreator->getPlanParameteres().fromTAZ == additionalID)) {
228
return true;
229
}
230
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
231
// get selected TAZs
232
const auto& selectedTAZs = viewParent->getVehicleFrame()->getPathCreator()->getSelectedTAZs();
233
// check if this is the first selected TAZ
234
if ((selectedTAZs.size() > 0) && (selectedTAZs.front() == this)) {
235
return true;
236
}
237
}
238
} else if (modes.isCurrentSupermodeData()) {
239
// get TAZRelDataFrame
240
const auto& TAZRelDataFrame = viewParent->getTAZRelDataFrame();
241
if (TAZRelDataFrame->shown() && (TAZRelDataFrame->getFirstTAZ() == this)) {
242
return true;
243
}
244
}
245
// nothing to draw
246
return false;
247
}
248
249
250
bool
251
GNEAdditional::checkDrawToContour() const {
252
// get modes and viewParent (for code legibility)
253
const auto& modes = myNet->getViewNet()->getEditModes();
254
const auto& viewParent = myNet->getViewParent();
255
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
256
// check conditions
257
if (myNet->getViewParent()->getInspectorFrame()->getAttributesEditor()->isReparenting()) {
258
return false;
259
} else if (inspectedElements.isInspectingSingleElement()) {
260
const auto inspectedAC = inspectedElements.getFirstAC();
261
// check conditions
262
if (inspectedAC->hasAttribute(SUMO_ATTR_TO_TAZ)) {
263
return (inspectedAC->getAttribute(SUMO_ATTR_TO_TAZ) == getID());
264
} else if (inspectedAC->getTagProperty()->getTag() == SUMO_TAG_TAZREL) {
265
return (inspectedAC->getAttribute(SUMO_ATTR_TO) == getID());
266
} else if (inspectedAC->hasAttribute(GNE_ATTR_PARENT)) {
267
// check all parent tags
268
const auto& parentTags = inspectedAC->getTagProperty()->getXMLParentTags();
269
if (std::find(parentTags.begin(), parentTags.end(), myTagProperty->getTag()) != parentTags.end()) {
270
return (inspectedAC->getAttribute(GNE_ATTR_PARENT) == getID());
271
}
272
}
273
} else if (modes.isCurrentSupermodeDemand()) {
274
// get current GNEPlanCreator
275
GNEPlanCreator* planCreator = nullptr;
276
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
277
planCreator = viewParent->getPersonFrame()->getPlanCreator();
278
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
279
planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();
280
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
281
planCreator = viewParent->getContainerFrame()->getPlanCreator();
282
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
283
planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();
284
}
285
// continue depending of planCreator
286
if (planCreator) {
287
// check if this is the from additional
288
const auto additionalID = getID();
289
if ((planCreator->getPlanParameteres().toBusStop == additionalID) ||
290
(planCreator->getPlanParameteres().toTrainStop == additionalID) ||
291
(planCreator->getPlanParameteres().toContainerStop == additionalID) ||
292
(planCreator->getPlanParameteres().toChargingStation == additionalID) ||
293
(planCreator->getPlanParameteres().toParkingArea == additionalID) ||
294
(planCreator->getPlanParameteres().toTAZ == additionalID)) {
295
return true;
296
}
297
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
298
// get selected TAZs
299
const auto& selectedTAZs = viewParent->getVehicleFrame()->getPathCreator()->getSelectedTAZs();
300
// check if this is the first selected TAZ
301
if ((selectedTAZs.size() > 1) && (selectedTAZs.back() == this)) {
302
return true;
303
}
304
}
305
} else if (modes.isCurrentSupermodeData()) {
306
// get TAZRelDataFrame
307
const auto& TAZRelDataFrame = viewParent->getTAZRelDataFrame();
308
if (TAZRelDataFrame->shown() && (TAZRelDataFrame->getSecondTAZ() == this)) {
309
return true;
310
}
311
}
312
// nothing to draw
313
return false;
314
}
315
316
317
bool
318
GNEAdditional::checkDrawRelatedContour() const {
319
const auto& neteditAttributesEditor = myNet->getViewParent()->getInspectorFrame()->getAttributesEditor();
320
if (neteditAttributesEditor->isReparenting()) {
321
return neteditAttributesEditor->checkNewParent(this);
322
}
323
// check opened popup
324
if (myNet->getViewNet()->getPopup()) {
325
return myNet->getViewNet()->getPopup()->getGLObject() == this;
326
}
327
return false;
328
}
329
330
331
bool
332
GNEAdditional::checkDrawOverContour() const {
333
const auto& modes = myNet->getViewNet()->getEditModes();
334
if (myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() != this) {
335
return false;
336
} else {
337
const auto& viewParent = myNet->getViewParent();
338
if (modes.isCurrentSupermodeDemand()) {
339
// get current plan selector
340
GNEPlanSelector* planSelector = nullptr;
341
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
342
planSelector = viewParent->getPersonFrame()->getPlanSelector();
343
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
344
planSelector = viewParent->getPersonPlanFrame()->getPlanSelector();
345
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
346
planSelector = viewParent->getContainerFrame()->getPlanSelector();
347
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
348
planSelector = viewParent->getContainerPlanFrame()->getPlanSelector();
349
}
350
// continue depending of plan selector
351
if (planSelector) {
352
if ((myTagProperty->isStoppingPlace() && planSelector->markStoppingPlaces()) ||
353
(myTagProperty->isTAZElement() && planSelector->markTAZs())) {
354
return true;
355
}
356
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
357
// get current vehicle template
358
const auto& vehicleTemplate = viewParent->getVehicleFrame()->getVehicleTagSelector()->getCurrentTemplateAC();
359
// check if vehicle can be placed over from-to TAZs
360
if (vehicleTemplate && vehicleTemplate->getTagProperty()->vehicleTAZs()) {
361
return true;
362
}
363
}
364
} else if (modes.isCurrentSupermodeData()) {
365
// get TAZRelDataFrame
366
const auto& TAZRelDataFrame = viewParent->getTAZRelDataFrame();
367
if (TAZRelDataFrame->shown()) {
368
if (TAZRelDataFrame->getFirstTAZ() && TAZRelDataFrame->getSecondTAZ()) {
369
return false;
370
} else if (TAZRelDataFrame->getFirstTAZ() == this) {
371
return false;
372
} else if (TAZRelDataFrame->getSecondTAZ() == this) {
373
return false;
374
} else {
375
return true;
376
}
377
}
378
}
379
return false;
380
}
381
}
382
383
384
bool
385
GNEAdditional::checkDrawDeleteContour() const {
386
// get edit modes
387
const auto& editModes = myNet->getViewNet()->getEditModes();
388
// check if we're in delete mode
389
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE)) {
390
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
391
} else {
392
return false;
393
}
394
}
395
396
397
bool
398
GNEAdditional::checkDrawDeleteContourSmall() const {
399
// get edit modes
400
const auto& editModes = myNet->getViewNet()->getEditModes();
401
// check if we're in delete mode and this additional has a parent
402
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE) && (getParentAdditionals().size() > 0)) {
403
const auto additional = myNet->getViewNet()->getViewObjectsSelector().getAdditionalFront();
404
if (additional && (additional == myNet->getViewNet()->getViewObjectsSelector().getAttributeCarrierFront())) {
405
return (getParentAdditionals().front() == additional);
406
}
407
}
408
return false;
409
}
410
411
412
bool
413
GNEAdditional::checkDrawSelectContour() const {
414
// get edit modes
415
const auto& editModes = myNet->getViewNet()->getEditModes();
416
// check if we're in select mode
417
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_SELECT)) {
418
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
419
} else {
420
return false;
421
}
422
}
423
424
425
GUIGLObjectPopupMenu*
426
GNEAdditional::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
427
// create popup
428
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
429
// build common options
430
buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected);
431
// show option to open additional dialog
432
if (myTagProperty->hasDialog()) {
433
GUIDesigns::buildFXMenuCommand(ret, TL("Open ") + getTagStr() + TL(" Dialog"), getACIcon(), &parent, MID_OPEN_ADDITIONAL_DIALOG);
434
new FXMenuSeparator(ret);
435
}
436
// Show position parameters
437
if (myTagProperty->hasAttribute(SUMO_ATTR_LANE) && (myAdditionalGeometry.getShape().size() > 1)) {
438
const GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(getAttribute(SUMO_ATTR_LANE));
439
// Show menu command inner position
440
const double innerPos = myAdditionalGeometry.getShape().nearest_offset_to_point2D(parent.getPositionInformation());
441
GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position over additional shape: ") + toString(innerPos), nullptr, nullptr, 0);
442
// If shape isn't empty, show menu command lane position
443
if (myAdditionalGeometry.getShape().size() > 0) {
444
const double lanePos = lane->getLaneShape().nearest_offset_to_point2D(myAdditionalGeometry.getShape().front());
445
GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position over lane: ") + toString(innerPos + lanePos), nullptr, nullptr, 0);
446
}
447
} else if (myTagProperty->hasAttribute(SUMO_ATTR_EDGE) && (myAdditionalGeometry.getShape().size() > 1)) {
448
const GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(getAttribute(SUMO_ATTR_EDGE));
449
// Show menu command inner position
450
const double innerPos = myAdditionalGeometry.getShape().nearest_offset_to_point2D(parent.getPositionInformation());
451
GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position over additional shape: ") + toString(innerPos), nullptr, nullptr, 0);
452
// If shape isn't empty, show menu command edge position
453
if (myAdditionalGeometry.getShape().size() > 0) {
454
const double edgePos = edge->getChildLanes().at(0)->getLaneShape().nearest_offset_to_point2D(myAdditionalGeometry.getShape().front());
455
GUIDesigns::buildFXMenuCommand(ret, TL("Mouse position over edge: ") + toString(innerPos + edgePos), nullptr, nullptr, 0);
456
}
457
} else {
458
const auto mousePos = myNet->getViewNet()->getPositionInformation();
459
GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position in view: ") + toString(mousePos.x()) + "," + toString(mousePos.y()), nullptr, nullptr, 0);
460
}
461
return ret;
462
}
463
464
465
GUIParameterTableWindow*
466
GNEAdditional::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
467
// Create table
468
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
469
// Iterate over attributes
470
for (const auto& attributeProperty : myTagProperty->getAttributeProperties()) {
471
// Add attribute and set it dynamic if aren't unique
472
if (attributeProperty->isUnique()) {
473
ret->mkItem(attributeProperty->getAttrStr().c_str(), false, getAttribute(attributeProperty->getAttr()));
474
} else {
475
ret->mkItem(attributeProperty->getAttrStr().c_str(), true, getAttribute(attributeProperty->getAttr()));
476
}
477
}
478
// close building
479
ret->closeBuilding();
480
return ret;
481
}
482
483
484
const std::string&
485
GNEAdditional::getOptionalAdditionalName() const {
486
return myAdditionalName;
487
}
488
489
490
bool
491
GNEAdditional::isGLObjectLocked() const {
492
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {
493
return myNet->getViewNet()->getLockManager().isObjectLocked(getType(), isAttributeCarrierSelected());
494
} else {
495
return true;
496
}
497
}
498
499
500
void
501
GNEAdditional::markAsFrontElement() {
502
markForDrawingFront();
503
}
504
505
506
void
507
GNEAdditional::deleteGLObject() {
508
myNet->deleteAdditional(this, myNet->getUndoList());
509
}
510
511
512
void
513
GNEAdditional::selectGLObject() {
514
if (isAttributeCarrierSelected()) {
515
unselectAttributeCarrier();
516
} else {
517
selectAttributeCarrier();
518
}
519
// update information label
520
myNet->getViewParent()->getSelectorFrame()->getSelectionInformation()->updateInformationLabel();
521
}
522
523
524
void GNEAdditional::updateGLObject() {
525
updateGeometry();
526
}
527
528
529
void
530
GNEAdditional::computePathElement() {
531
// Nothing to compute
532
}
533
534
535
bool
536
GNEAdditional::isPathElementSelected() const {
537
return mySelected;
538
}
539
540
541
void
542
GNEAdditional::drawLanePartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {
543
// Nothing to draw
544
}
545
546
547
void
548
GNEAdditional::drawJunctionPartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {
549
// Nothing to draw
550
}
551
552
// ---------------------------------------------------------------------------
553
// GNEAdditional - protected methods
554
// ---------------------------------------------------------------------------
555
556
void
557
GNEAdditional::writeAdditionalAttributes(OutputDevice& device) const {
558
// ID (if defined)
559
if (myTagProperty->hasAttribute(SUMO_ATTR_ID)) {
560
device.writeAttr(SUMO_ATTR_ID, StringUtils::escapeXML(getID()));
561
}
562
// name
563
if (myAdditionalName.size() > 0) {
564
device.writeAttr(SUMO_ATTR_NAME, myAdditionalName);
565
}
566
}
567
568
569
bool
570
GNEAdditional::isValidAdditionalID(const std::string& value) const {
571
if (!isTemplate() && (value == getID())) {
572
return true;
573
} else if (SUMOXMLDefinitions::isValidAdditionalID(value)) {
574
return (myNet->getAttributeCarriers()->retrieveAdditional(myTagProperty->getTag(), value, false) == nullptr);
575
} else {
576
return false;
577
}
578
}
579
580
581
bool
582
GNEAdditional::isValidAdditionalID(const std::vector<SumoXMLTag>& tags, const std::string& value) const {
583
if (isTemplate() && value.empty()) {
584
return true;
585
} else if (!isTemplate() && (value == getID())) {
586
return true;
587
} else if (SUMOXMLDefinitions::isValidAdditionalID(value)) {
588
return (myNet->getAttributeCarriers()->retrieveAdditionals(tags, value, false) == nullptr);
589
} else {
590
return false;
591
}
592
}
593
594
595
bool
596
GNEAdditional::isValidDetectorID(const std::string& value) const {
597
if (isTemplate() && value.empty()) {
598
return true;
599
} else if (!isTemplate() && (value == getID())) {
600
return true;
601
} else if (SUMOXMLDefinitions::isValidDetectorID(value)) {
602
return (myNet->getAttributeCarriers()->retrieveAdditional(myTagProperty->getTag(), value, false) == nullptr);
603
} else {
604
return false;
605
}
606
}
607
608
609
bool
610
GNEAdditional::isValidDetectorID(const std::vector<SumoXMLTag>& tags, const std::string& value) const {
611
if (!isTemplate() && (value == getID())) {
612
return true;
613
} else if (SUMOXMLDefinitions::isValidDetectorID(value)) {
614
return (myNet->getAttributeCarriers()->retrieveAdditionals(tags, value, false) == nullptr);
615
} else {
616
return false;
617
}
618
}
619
620
621
void
622
GNEAdditional::setAdditionalID(const std::string& newID) {
623
// update ID
624
if (isTemplate()) {
625
setMicrosimID(newID);
626
} else if ((myTagProperty->getTag() == SUMO_TAG_VAPORIZER) || !myTagProperty->hasAttribute(SUMO_ATTR_ID)) {
627
setMicrosimID(newID);
628
} else {
629
myNet->getAttributeCarriers()->updateAdditionalID(this, newID);
630
}
631
// change IDs of certain children
632
for (const auto& additionalChild : getChildAdditionals()) {
633
// get tag
634
const auto tag = additionalChild->getTagProperty()->getTag();
635
if ((tag == SUMO_TAG_ACCESS) || (tag == SUMO_TAG_PARKING_SPACE) ||
636
(tag == SUMO_TAG_DET_ENTRY) || (tag == SUMO_TAG_DET_EXIT)) {
637
additionalChild->setAdditionalID(getID());
638
}
639
}
640
// enable save demand elements if this additional has children
641
if (getChildDemandElements().size() > 0) {
642
myNet->getSavingStatus()->requireSaveDemandElements();
643
}
644
// enable save data elements if this additional has children
645
if (getChildGenericDatas().size() > 0) {
646
myNet->getSavingStatus()->requireSaveDataElements();
647
}
648
}
649
650
651
void
652
GNEAdditional::drawAdditionalID(const GUIVisualizationSettings& s) const {
653
if (s.addName.show(this) && (myAdditionalGeometry.getShape().size() > 0)) {
654
// calculate middle point
655
const double middlePoint = (myAdditionalGeometry.getShape().length2D() * 0.5);
656
// calculate position
657
const Position pos = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShape().front() : myAdditionalGeometry.getShape().positionAtOffset2D(middlePoint);
658
// calculate rotation
659
const double rot = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShapeRotations().front() : myAdditionalGeometry.getShape().rotationDegreeAtOffset(middlePoint);
660
// draw additional ID
661
if (myTagProperty->hasAttribute(SUMO_ATTR_LANE)) {
662
GLHelper::drawText(getMicrosimID(), pos, GLO_MAX - getType(), s.addName.scaledSize(s.scale), s.addName.color, s.getTextAngle(rot - 90));
663
} else {
664
GLHelper::drawText(getMicrosimID(), pos, GLO_MAX - getType(), s.addName.scaledSize(s.scale), s.addName.color, 0);
665
}
666
}
667
}
668
669
670
void
671
GNEAdditional::drawAdditionalName(const GUIVisualizationSettings& s) const {
672
if (s.addFullName.show(this) && (myAdditionalGeometry.getShape().size() > 0) && (myAdditionalName != "")) {
673
// calculate middle point
674
const double middlePoint = (myAdditionalGeometry.getShape().length2D() * 0.5);
675
// calculate position
676
const Position pos = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShape().front() : myAdditionalGeometry.getShape().positionAtOffset2D(middlePoint);
677
// calculate rotation
678
const double rot = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShapeRotations().front() : myAdditionalGeometry.getShape().rotationDegreeAtOffset(middlePoint);
679
// draw additional name
680
if (myTagProperty->hasAttribute(SUMO_ATTR_LANE)) {
681
GLHelper::drawText(myAdditionalName, pos, GLO_MAX - getType(), s.addFullName.scaledSize(s.scale), s.addFullName.color, s.getTextAngle(rot - 90));
682
} else {
683
GLHelper::drawText(myAdditionalName, pos, GLO_MAX - getType(), s.addFullName.scaledSize(s.scale), s.addFullName.color, 0);
684
}
685
}
686
}
687
688
689
void
690
GNEAdditional::replaceAdditionalParentEdges(const std::string& value) {
691
GNEHierarchicalElement::updateParents(this, parse<GNEHierarchicalContainerParents<GNEEdge*> >(getNet(), value));
692
}
693
694
695
void
696
GNEAdditional::replaceAdditionalParentLanes(const std::string& value) {
697
GNEHierarchicalElement::updateParents(this, parse<GNEHierarchicalContainerParents<GNELane*> >(getNet(), value));
698
699
}
700
701
702
void
703
GNEAdditional::replaceAdditionalChildEdges(const std::string& value) {
704
GNEHierarchicalElement::updateChildren(this, parse<GNEHierarchicalContainerParents<GNEEdge*> >(getNet(), value));
705
}
706
707
708
void
709
GNEAdditional::replaceAdditionalChildLanes(const std::string& value) {
710
GNEHierarchicalElement::updateChildren(this, parse<GNEHierarchicalContainerParents<GNELane*> >(getNet(), value));
711
712
}
713
714
715
void
716
GNEAdditional::replaceAdditionalParent(SumoXMLTag tag, const std::string& value, const int parentIndex) {
717
std::vector<GNEAdditional*> newParentAdditionals;
718
// special case for calibrators and routeprobes
719
if (value.size() > 0) {
720
newParentAdditionals = getParentAdditionals();
721
if ((newParentAdditionals.size() == 0) && (parentIndex == 0)) {
722
newParentAdditionals.push_back(myNet->getAttributeCarriers()->retrieveAdditional(tag, value));
723
} else {
724
newParentAdditionals[parentIndex] = myNet->getAttributeCarriers()->retrieveAdditional(tag, value);
725
}
726
}
727
GNEHierarchicalElement::updateParents(this, newParentAdditionals);
728
}
729
730
731
void
732
GNEAdditional::replaceDemandElementParent(SumoXMLTag tag, const std::string& value, const int parentIndex) {
733
auto newDemandElement = myNet->getAttributeCarriers()->retrieveDemandElement(tag, value);
734
GNEHierarchicalElement::updateParent(this, parentIndex, newDemandElement);
735
}
736
737
738
void
739
GNEAdditional::shiftLaneIndex() {
740
const std::vector<GNELane*> newLanes = {getParentLanes().front()->getParentEdge()->getChildLanes().at(getParentLanes().front()->getIndex() + 1)};
741
GNEHierarchicalElement::updateParents(this, newLanes);
742
}
743
744
745
void
746
GNEAdditional::calculatePerpendicularLine(const double endLaneposition) {
747
if (getParentEdges().empty()) {
748
throw ProcessError(TL("Invalid number of edges"));
749
} else {
750
// get lanes
751
const GNELane* firstLane = getParentEdges().front()->getChildLanes().front();
752
const GNELane* lastLane = getParentEdges().front()->getChildLanes().back();
753
// get first and back lane shapes
754
PositionVector firstLaneShape = firstLane->getLaneShape();
755
PositionVector lastLaneShape = lastLane->getLaneShape();
756
// move shapes
757
firstLaneShape.move2side((firstLane->getParentEdge()->getNBEdge()->getLaneWidth(firstLane->getIndex()) * 0.5) + 1);
758
lastLaneShape.move2side(lastLane->getParentEdge()->getNBEdge()->getLaneWidth(lastLane->getIndex()) * -0.5);
759
// calculate lane postion
760
const double lanePosition = firstLaneShape.length2D() >= endLaneposition ? endLaneposition : firstLaneShape.length2D();
761
// update geometry
762
myAdditionalGeometry.updateGeometry({firstLaneShape.positionAtOffset2D(lanePosition), lastLaneShape.positionAtOffset2D(lanePosition)});
763
}
764
}
765
766
767
void
768
GNEAdditional::drawDemandElementChildren(const GUIVisualizationSettings& s) const {
769
// draw child demand elements
770
for (const auto& demandElement : getChildDemandElements()) {
771
if (!demandElement->getTagProperty()->isPlacedInRTree()) {
772
demandElement->drawGL(s);
773
}
774
}
775
}
776
777
778
std::string
779
GNEAdditional::getJuPedSimType(SumoXMLTag tag) {
780
// continue depending of tag
781
switch (tag) {
782
case GNE_TAG_JPS_WALKABLEAREA:
783
return "jupedsim.walkable_area";
784
case GNE_TAG_JPS_OBSTACLE:
785
return "jupedsim.obstacle";
786
default:
787
throw InvalidArgument("Invalid JuPedSim tag");
788
}
789
}
790
791
792
RGBColor
793
GNEAdditional::getJuPedSimColor(SumoXMLTag tag) {
794
// continue depending of tag
795
switch (tag) {
796
case GNE_TAG_JPS_WALKABLEAREA:
797
return RGBColor(179, 217, 255);
798
case GNE_TAG_JPS_OBSTACLE:
799
return RGBColor(255, 204, 204);
800
default:
801
throw InvalidArgument("Invalid JuPedSim tag");
802
}
803
}
804
805
806
bool
807
GNEAdditional::getJuPedSimFill(SumoXMLTag tag) {
808
// continue depending of tag
809
switch (tag) {
810
case GNE_TAG_JPS_WALKABLEAREA:
811
case GNE_TAG_JPS_OBSTACLE:
812
return true;
813
default:
814
throw InvalidArgument("Invalid JuPedSim tag");
815
}
816
}
817
818
819
double
820
GNEAdditional::getJuPedSimLayer(SumoXMLTag tag) {
821
// continue depending of tag
822
switch (tag) {
823
case GNE_TAG_JPS_WALKABLEAREA:
824
return 1;
825
case GNE_TAG_JPS_OBSTACLE:
826
return 2;
827
default:
828
throw InvalidArgument("Invalid JuPedSim tag");
829
}
830
}
831
832
833
void
834
GNEAdditional::calculateContourPolygons(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
835
const double layer, const double exaggeration, const bool filledShape) const {
836
// calculate contour depending of contoured shape
837
if (filledShape) {
838
myAdditionalContour.calculateContourClosedShape(s, d, this, myAdditionalGeometry.getShape(), layer, 1, nullptr);
839
} else {
840
myAdditionalContour.calculateContourExtrudedShape(s, d, this, myAdditionalGeometry.getShape(), layer,
841
s.neteditSizeSettings.polylineWidth, exaggeration, true, true, 0, nullptr, nullptr);
842
}
843
// get edit modes
844
const auto& editModes = myNet->getViewNet()->getEditModes();
845
// check if draw geometry points
846
if (editModes.isCurrentSupermodeNetwork() && !myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveWholePolygons()) {
847
// check if we're in move mode
848
const bool moveMode = (editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE);
849
// get geometry point radius (size depends if we're in move mode)
850
const double geometryPointRaidus = s.neteditSizeSettings.polygonGeometryPointRadius * (moveMode ? 1 : 0.5);
851
// calculate contour geometry points
852
myAdditionalContour.calculateContourAllGeometryPoints(s, d, this, myAdditionalGeometry.getShape(), layer, geometryPointRaidus, exaggeration, moveMode);
853
}
854
}
855
856
857
GNELane*
858
GNEAdditional::getFirstPathLane() const {
859
return getParentLanes().front();
860
}
861
862
863
GNELane*
864
GNEAdditional::getLastPathLane() const {
865
return getParentLanes().back();
866
}
867
868
869
void
870
GNEAdditional::drawParentChildLines(const GUIVisualizationSettings& s, const RGBColor& color, const bool onlySymbols) const {
871
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
872
// check if current additional is inspected, front or selected
873
const bool currentDrawEntire = inspectedElements.isACInspected(this) || myDrawInFront || isAttributeCarrierSelected();
874
// push layer matrix
875
GLHelper::pushMatrix();
876
// translate to parentChildLine layer
877
glTranslated(0, 0, GLO_PARENTCHILDLINE);
878
// iterate over parent additionals
879
for (const auto& parent : getParentAdditionals()) {
880
// get inspected flag
881
const bool parentInspected = inspectedElements.isACInspected(parent);
882
// draw parent lines
883
GUIGeometry::drawParentLine(s, getPositionInView(), parent->getPositionInView(),
884
(isAttributeCarrierSelected() || parent->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,
885
currentDrawEntire || parentInspected || parent->isAttributeCarrierSelected(), .05);
886
}
887
// special case for Parking area reroutes
888
if (getTagProperty()->getTag() == SUMO_TAG_REROUTER) {
889
// iterate over rerouter elements
890
for (const auto& rerouterInterval : getChildAdditionals()) {
891
for (const auto& rerouterElement : rerouterInterval->getChildAdditionals()) {
892
if (rerouterElement->getTagProperty()->getTag() == SUMO_TAG_PARKING_AREA_REROUTE) {
893
// get parking area
894
const auto parkingArea = rerouterElement->getParentAdditionals().at(1);
895
// get inspected flag
896
const bool parkingAreaInspected = inspectedElements.isACInspected(parkingArea);
897
// draw parent lines
898
GUIGeometry::drawParentLine(s, getPositionInView(), parkingArea->getPositionInView(),
899
(isAttributeCarrierSelected() || parkingArea->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,
900
currentDrawEntire || parkingAreaInspected || parkingArea->isAttributeCarrierSelected(), .05);
901
}
902
}
903
}
904
}
905
// iterate over child additionals
906
for (const auto& child : getChildAdditionals()) {
907
// get inspected flag
908
const bool childInspected = inspectedElements.isACInspected(child);
909
// special case for parking zone reroute
910
if (child->getTagProperty()->getTag() == SUMO_TAG_PARKING_AREA_REROUTE) {
911
// draw child line between parking area and rerouter
912
GUIGeometry::drawChildLine(s, getPositionInView(), child->getParentAdditionals().front()->getParentAdditionals().front()->getPositionInView(),
913
(isAttributeCarrierSelected() || child->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,
914
currentDrawEntire || childInspected || child->isAttributeCarrierSelected(), .05);
915
} else if (!onlySymbols || child->getTagProperty()->isSymbol()) {
916
// draw child line
917
GUIGeometry::drawChildLine(s, getPositionInView(), child->getPositionInView(),
918
(isAttributeCarrierSelected() || child->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,
919
currentDrawEntire || childInspected || child->isAttributeCarrierSelected(), .05);
920
}
921
}
922
// pop layer matrix
923
GLHelper::popMatrix();
924
}
925
926
927
void
928
GNEAdditional::drawUpGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,
929
const double rot, const RGBColor& baseColor, const bool ignoreShift) const {
930
drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, -90, 90, ignoreShift);
931
}
932
933
void
934
GNEAdditional::drawDownGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,
935
const double rot, const RGBColor& baseColor, const bool ignoreShift) const {
936
drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, 90, 270, ignoreShift);
937
}
938
939
void
940
GNEAdditional::drawLeftGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,
941
const double rot, const RGBColor& baseColor, const bool ignoreShift) const {
942
drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, -90, 90, ignoreShift);
943
}
944
945
946
void
947
GNEAdditional::drawRightGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,
948
const double rot, const RGBColor& baseColor, const bool ignoreShift) const {
949
drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, 270, 90, ignoreShift);
950
}
951
952
953
bool
954
GNEAdditional::areLaneConsecutives(const std::vector<GNELane*>& lanes) {
955
// declare lane iterator
956
int laneIt = 0;
957
// iterate over all lanes
958
while (laneIt < ((int)lanes.size() - 1)) {
959
// we assume that lanes aren't consecutive
960
bool consecutiveFound = false;
961
// get lanes
962
const auto lane = lanes.at(laneIt);
963
const auto nextLane = lanes.at(laneIt + 1);
964
// if there is a connection between "from" lane and "to" lane of connection, change connectionFound to true
965
for (const auto& outgoingEdge : lane->getParentEdge()->getToJunction()->getGNEOutgoingEdges()) {
966
for (const auto& outgoingLane : outgoingEdge->getChildLanes()) {
967
if (outgoingLane == nextLane) {
968
consecutiveFound = true;
969
}
970
}
971
}
972
// abort if consecutiveFound is false
973
if (!consecutiveFound) {
974
return false;
975
}
976
// update iterator
977
laneIt++;
978
}
979
// lanes are consecutive, then return true
980
return true;
981
}
982
983
984
bool
985
GNEAdditional::areLaneConnected(const std::vector<GNELane*>& lanes) {
986
// declare lane iterator
987
int laneIt = 0;
988
// iterate over all lanes, and stop if myE2valid is false
989
while (laneIt < ((int)lanes.size() - 1)) {
990
// we assume that E2 is invalid
991
bool connectionFound = false;
992
// get lanes
993
const auto lane = lanes.at(laneIt);
994
const auto nextLane = lanes.at(laneIt + 1);
995
// check if both lanes are sidewalks
996
if ((lane->getAttribute(SUMO_ATTR_ALLOW) == "pedestrian") && (nextLane->getAttribute(SUMO_ATTR_ALLOW) == "pedestrian")) {
997
connectionFound = true;
998
}
999
// if there is a connection between "from" lane and "to" lane of connection, change connectionFound to true
1000
for (const auto& connection : lane->getParentEdge()->getNBEdge()->getConnections()) {
1001
if ((connection.toEdge == nextLane->getParentEdge()->getNBEdge()) &&
1002
(connection.fromLane == lane->getIndex()) &&
1003
(connection.toLane == nextLane->getIndex())) {
1004
connectionFound = true;
1005
}
1006
}
1007
// abort if connectionFound is false
1008
if (!connectionFound) {
1009
return false;
1010
}
1011
// update iterator
1012
laneIt++;
1013
}
1014
// there are connections between all lanes, then return true
1015
return true;
1016
}
1017
1018
1019
bool
1020
GNEAdditional::checkChildAdditionalRestriction() const {
1021
// throw exception because this function mus be implemented in child (see GNEE3Detector)
1022
throw ProcessError(StringUtils::format("Calling non-implemented function checkChildAdditionalRestriction during saving of %. It muss be reimplemented in child class", getTagStr()));
1023
}
1024
1025
1026
void
1027
GNEAdditional::drawSemiCircleGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
1028
const Position& pos, const double rot, const RGBColor& baseColor, const double fromAngle, const double toAngle,
1029
const bool /* ignoreShift */) const {
1030
// check if draw geometry point
1031
if (!s.drawForViewObjectsHandler && (d <= GUIVisualizationSettings::Detail::GeometryPoint)) {
1032
// push matrix
1033
GLHelper::pushMatrix();
1034
// translated to front
1035
glTranslated(0, 0, 0.1);
1036
// set color depending if check if mouse is over element
1037
GLHelper::setColor(baseColor.changedBrightness(-50));
1038
// translate and rotate
1039
glTranslated(pos.x(), pos.y(), 0.1);
1040
glRotated(rot, 0, 0, 1);
1041
// draw geometry point
1042
GLHelper::drawFilledCircleDetailled(d, s.neteditSizeSettings.additionalGeometryPointRadius, fromAngle, toAngle);
1043
// pop geometry point matrix
1044
GLHelper::popMatrix();
1045
}
1046
}
1047
1048
/****************************************************************************/
1049
1050