Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/frames/network/GNEAdditionalFrame.cpp
193863 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 GNEAdditionalFrame.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Dec 2015
17
///
18
// The Widget for add additional elements
19
/****************************************************************************/
20
21
#include <netedit/GNEApplicationWindow.h>
22
#include <netedit/GNENet.h>
23
#include <netedit/GNEViewParent.h>
24
#include <netedit/elements/additional/GNEAdditionalHandler.h>
25
#include <netedit/frames/GNEAttributesEditor.h>
26
#include <netedit/frames/GNEConsecutiveSelector.h>
27
#include <netedit/frames/GNEViewObjectSelector.h>
28
#include <netedit/frames/GNESelectorParent.h>
29
#include <netedit/frames/GNETagSelector.h>
30
#include <utils/gui/div/GUIDesigns.h>
31
32
#include "GNEAdditionalFrame.h"
33
34
// ===========================================================================
35
// method definitions
36
// ===========================================================================
37
38
// ---------------------------------------------------------------------------
39
// GNEAdditionalFrame::E2MultilaneLegendModule - methods
40
// ---------------------------------------------------------------------------
41
42
GNEAdditionalFrame::E2MultilaneLegendModule::E2MultilaneLegendModule(GNEFrame* frameParent) :
43
GNEGroupBoxModule(frameParent, TL("Legend")) {
44
// declare label
45
FXLabel* legendLabel = nullptr;
46
// edge candidate
47
legendLabel = new FXLabel(getCollapsableFrame(), TL(" edge candidate"), 0, GUIDesignLabel(JUSTIFY_LEFT));
48
legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.possible));
49
legendLabel->setTextColor(MFXUtils::getFXColor(RGBColor::WHITE));
50
// last edge selected
51
legendLabel = new FXLabel(getCollapsableFrame(), TL(" last edge selected"), 0, GUIDesignLabel(JUSTIFY_LEFT));
52
legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.target));
53
// edge selected
54
legendLabel = new FXLabel(getCollapsableFrame(), TL(" edge selected"), 0, GUIDesignLabel(JUSTIFY_LEFT));
55
legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.source));
56
// edge disconnected
57
legendLabel = new FXLabel(getCollapsableFrame(), TL(" edge disconnected"), 0, GUIDesignLabel(JUSTIFY_LEFT));
58
legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.conflict));
59
}
60
61
62
GNEAdditionalFrame::E2MultilaneLegendModule::~E2MultilaneLegendModule() {}
63
64
65
void
66
GNEAdditionalFrame::E2MultilaneLegendModule::showE2MultilaneLegend() {
67
show();
68
}
69
70
71
void
72
GNEAdditionalFrame::E2MultilaneLegendModule::hideE2MultilaneLegend() {
73
hide();
74
}
75
76
// ---------------------------------------------------------------------------
77
// GNEAdditionalFrame::HelpCreationModule - methods
78
// ---------------------------------------------------------------------------
79
80
GNEAdditionalFrame::HelpCreationModule::HelpCreationModule(GNEFrame* frameParent) :
81
GNEGroupBoxModule(frameParent, TL("Help")) {
82
// edge candidate
83
myHelpLabel = new FXLabel(getCollapsableFrame(), "", 0, GUIDesignLabelFrameInformation);
84
// fill map
85
//addTLString(TL("-Requires EntryExitDetector\n")) +
86
// E1
87
myHelpMap[SUMO_TAG_INDUCTION_LOOP] = addTLString(TL("-Click over lane to create it"));
88
// E1 Instant
89
myHelpMap[SUMO_TAG_INSTANT_INDUCTION_LOOP] = addTLString(TL("-Click over lane to create it"));
90
// E2
91
myHelpMap[SUMO_TAG_LANE_AREA_DETECTOR] = addTLString(TL("-Click over lane to create it"));
92
// E3
93
myHelpMap[SUMO_TAG_ENTRY_EXIT_DETECTOR] = addTLString(TL("-Click over view to create it")) +
94
addTLString(TL("-Requires at least one Entry\n and one Exit"));
95
// E3 Entry
96
myHelpMap[SUMO_TAG_DET_ENTRY] = addTLString(TL("-Requires EntryExitDetector\n parent\n")) +
97
addTLString(TL("-Select EntryExitDetector\n before creating either\n clicking over one in view\n or by selecting from list"));
98
// E3 Exit
99
myHelpMap[SUMO_TAG_DET_EXIT] = addTLString(TL("-Requires EntryExitDetector\n parent\n")) +
100
addTLString(TL("-Select EntryExitDetector\n before creating either\n clicking over one in view\n or by selecting from list"));
101
}
102
103
104
GNEAdditionalFrame::HelpCreationModule::~HelpCreationModule() {}
105
106
107
void
108
GNEAdditionalFrame::HelpCreationModule::showHelpCreationModule(SumoXMLTag XMLTag) {
109
if (myHelpMap.count(XMLTag) > 0) {
110
myHelpLabel->setText(myHelpMap.at(XMLTag).c_str());
111
show();
112
} else {
113
hide();
114
}
115
}
116
117
118
void
119
GNEAdditionalFrame::HelpCreationModule::hideHelpCreationModule() {
120
hide();
121
}
122
123
124
std::string
125
GNEAdditionalFrame::HelpCreationModule::addTLString(const std::string& str) {
126
return std::string(str.c_str());
127
}
128
129
// ---------------------------------------------------------------------------
130
// GNEAdditionalFrame: - methods
131
// ---------------------------------------------------------------------------
132
133
GNEAdditionalFrame::GNEAdditionalFrame(GNEViewParent* viewParent, GNEViewNet* viewNet) :
134
GNEFrame(viewParent, viewNet, TL("Additionals")) {
135
136
// create item Selector module for additionals
137
myAdditionalTagSelector = new GNETagSelector(this, GNETagProperties::Type::ADDITIONALELEMENT, SUMO_TAG_BUS_STOP);
138
139
// Create additional parameters
140
myAdditionalAttributesEditor = new GNEAttributesEditor(this, GNEAttributesEditorType::EditorType::CREATOR);
141
142
// Create selector parent
143
mySelectorAdditionalParent = new GNESelectorParent(this);
144
145
// Create selector child edges
146
myViewObjetsSelector = new GNEViewObjectSelector(this);
147
148
// Create list for E2Multilane lane selector
149
myConsecutiveLaneSelector = new GNEConsecutiveSelector(this, false);
150
151
// create help creation module
152
myHelpCreationModule = new HelpCreationModule(this);
153
154
// Create legend for E2 detector
155
myE2MultilaneLegendModule = new E2MultilaneLegendModule(this);
156
}
157
158
159
GNEAdditionalFrame::~GNEAdditionalFrame() {
160
// check if we have to delete base additional object
161
if (myBaseAdditional) {
162
delete myBaseAdditional;
163
}
164
}
165
166
167
void
168
GNEAdditionalFrame::show() {
169
// refresh tag selector
170
myAdditionalTagSelector->refreshTagSelector();
171
// reset last position
172
myLastClickedPosition = Position::INVALID;
173
// show frame
174
GNEFrame::show();
175
}
176
177
178
bool
179
GNEAdditionalFrame::addAdditional(const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {
180
// first check that current selected additional is valid
181
if (myAdditionalTagSelector->getCurrentTemplateAC() == nullptr) {
182
myViewNet->setStatusBarText(TL("Current selected additional isn't valid."));
183
return false;
184
}
185
// obtain tagproperty (only for improve code legibility)
186
const auto& tagProperties = myAdditionalTagSelector->getCurrentTemplateAC()->getTagProperty();
187
// check if toogle selection
188
if ((viewObjects.getAttributeCarrierFront() == viewObjects.getLaneFront()) &&
189
(myViewObjetsSelector->toggleSelectedLane(viewObjects.getLaneFront()))) {
190
return true;
191
}
192
if (myViewObjetsSelector->toggleSelectedElement(viewObjects.getAttributeCarrierFront())) {
193
return true;
194
}
195
// check if add a lane in consecutive lane selector
196
if (tagProperties->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
197
return myConsecutiveLaneSelector->addLane(viewObjects.getLaneFront());
198
}
199
// disable rerouter elements (temporal)
200
if ((tagProperties->getTag() == SUMO_TAG_INTERVAL) ||
201
(tagProperties->getTag() == SUMO_TAG_DEST_PROB_REROUTE) ||
202
(tagProperties->getTag() == SUMO_TAG_CLOSING_REROUTE) ||
203
(tagProperties->getTag() == SUMO_TAG_CLOSING_LANE_REROUTE) ||
204
(tagProperties->getTag() == SUMO_TAG_ROUTE_PROB_REROUTE) ||
205
(tagProperties->getTag() == SUMO_TAG_PARKING_AREA_REROUTE)) {
206
WRITE_WARNING(TL("Currently unsupported. Create rerouter elements using rerouter dialog"));
207
return false;
208
}
209
// disable steps (temporal)
210
if (tagProperties->getTag() == SUMO_TAG_STEP) {
211
WRITE_WARNING(TL("Currently unsupported. Create VSS steps using VSS dialog"));
212
return false;
213
}
214
// disable flows (temporal)
215
if (tagProperties->getTag() == GNE_TAG_CALIBRATOR_FLOW) {
216
WRITE_WARNING(TL("Currently unsupported. Create calibratorFlows using calibrator dialog"));
217
return false;
218
}
219
// check last position
220
if ((myViewNet->getPositionInformation() == myLastClickedPosition) && !myViewNet->getMouseButtonKeyPressed().shiftKeyPressed()) {
221
WRITE_WARNING(TL("Shift + click to create two additionals in the same position"));
222
return false;
223
}
224
// check if additional attributes are valid
225
if (!myAdditionalAttributesEditor->checkAttributes(true)) {
226
return false;
227
}
228
// reset base additional
229
resetBaseAdditionalObject();
230
// init base additional object
231
if (!initBaseAdditionalObject(tagProperties, viewObjects)) {
232
return false;
233
}
234
// parse common attributes
235
if (!myViewObjetsSelector->fillSumoBaseObject(myBaseAdditional)) {
236
return false;
237
}
238
// add basic attributes and values
239
myAdditionalAttributesEditor->fillSumoBaseObject(myBaseAdditional);
240
// declare additional handler
241
GNEAdditionalHandler additionalHandler(myViewNet->getNet(), myViewNet->getNet()->getACTemplates()->getTemplateAC(tagProperties->getTag())->getFileBucket(),
242
myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());
243
// build additional
244
additionalHandler.parseSumoBaseObject(myBaseAdditional);
245
// Refresh additional Parent Selector (For additionals that have a limited number of children)
246
mySelectorAdditionalParent->refreshSelectorParentModule();
247
// clear selected view objects
248
myViewObjetsSelector->clearSelection();
249
myAdditionalAttributesEditor->refreshAttributesEditor();
250
return true;
251
}
252
253
254
GNETagSelector*
255
GNEAdditionalFrame::getAdditionalTagSelector() const {
256
return myAdditionalTagSelector;
257
}
258
259
260
GNEConsecutiveSelector*
261
GNEAdditionalFrame::getConsecutiveLaneSelector() const {
262
return myConsecutiveLaneSelector;
263
}
264
265
266
GNEAttributesEditor*
267
GNEAdditionalFrame::getAttributesEditor() const {
268
return myAdditionalAttributesEditor;
269
}
270
271
272
GNEViewObjectSelector*
273
GNEAdditionalFrame::getViewObjetsSelector() const {
274
return myViewObjetsSelector;
275
}
276
277
278
bool
279
GNEAdditionalFrame::createPath(const bool /* useLastRoute */) {
280
// obtain tagproperty (only for improve code legibility)
281
const auto tagProperty = myAdditionalTagSelector->getCurrentTemplateAC()->getTagProperty();
282
// first check that current tag is valid (currently only for E2 multilane detectors)
283
if (tagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
284
// now check number of lanes
285
if (myConsecutiveLaneSelector->getLanePath().size() < 2) {
286
WRITE_WARNING(TL("E2 multilane detectors need at least two consecutive lanes"));
287
} else {
288
// reset base object
289
resetBaseAdditionalObject();
290
// set tag
291
myBaseAdditional->setTag(SUMO_TAG_LANE_AREA_DETECTOR);
292
// get attributes and values
293
myAdditionalAttributesEditor->fillSumoBaseObject(myBaseAdditional);
294
// add lane IDs
295
myBaseAdditional->addStringListAttribute(SUMO_ATTR_LANES, myConsecutiveLaneSelector->getLaneIDPath());
296
// set positions
297
myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, myConsecutiveLaneSelector->getLanePath().front().second);
298
myBaseAdditional->addDoubleAttribute(SUMO_ATTR_ENDPOS, myConsecutiveLaneSelector->getLanePath().back().second);
299
// parse common attributes
300
if (myViewObjetsSelector->fillSumoBaseObject(myBaseAdditional)) {
301
// show warning dialogbox and stop check if input parameters are valid
302
if (myAdditionalAttributesEditor->checkAttributes(true)) {
303
// declare additional handler
304
GNEAdditionalHandler additionalHandler(myViewNet->getNet(), myViewNet->getNet()->getACTemplates()->getTemplateAC(SUMO_TAG_LANE_AREA_DETECTOR)->getFileBucket(),
305
myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());
306
// build additional
307
additionalHandler.parseSumoBaseObject(myBaseAdditional);
308
// Refresh additional Parent Selector (For additionals that have a limited number of children)
309
mySelectorAdditionalParent->refreshSelectorParentModule();
310
// abort E2 creation
311
myConsecutiveLaneSelector->abortPathCreation();
312
return true;
313
}
314
}
315
}
316
}
317
return false;
318
}
319
320
321
void
322
GNEAdditionalFrame::tagSelected() {
323
// get template AC
324
const auto templateAC = myAdditionalTagSelector->getCurrentTemplateAC();
325
if (templateAC) {
326
// show parameters
327
myAdditionalAttributesEditor->showAttributesEditor(templateAC, true);
328
// Show myAdditionalFrameParent if we're adding an slave element
329
if (templateAC->getTagProperty()->isChild()) {
330
mySelectorAdditionalParent->showSelectorParentModule(templateAC->getTagProperty()->getXMLParentTags());
331
} else {
332
mySelectorAdditionalParent->hideSelectorParentModule();
333
}
334
// Show EdgesSelector if we're adding an additional that own the attribute SUMO_ATTR_EDGES
335
if (templateAC->getTagProperty()->hasAttribute(SUMO_ATTR_EDGES)) {
336
myViewObjetsSelector->showNetworkElementsSelector(SUMO_TAG_EDGE, SUMO_ATTR_EDGES);
337
} else {
338
myViewObjetsSelector->hideNetworkElementsSelector();
339
}
340
// show help creation modul
341
myHelpCreationModule->showHelpCreationModule(templateAC->getTagProperty()->getTag());
342
// check if we must show consecutive lane selector
343
if (templateAC->getTagProperty()->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
344
myConsecutiveLaneSelector->showConsecutiveLaneSelectorModule();
345
myE2MultilaneLegendModule->showE2MultilaneLegend();
346
myViewObjetsSelector->hideNetworkElementsSelector();
347
// recompute network
348
myViewNet->getNet()->computeNetwork(myViewNet->getViewParent()->getGNEAppWindows());
349
} else if (templateAC->getTagProperty()->hasAttribute(SUMO_ATTR_LANES)) {
350
myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();
351
myE2MultilaneLegendModule->hideE2MultilaneLegend();
352
myViewObjetsSelector->showNetworkElementsSelector(SUMO_TAG_LANE, SUMO_ATTR_LANES);
353
} else {
354
myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();
355
myE2MultilaneLegendModule->hideE2MultilaneLegend();
356
}
357
// reset last position
358
myLastClickedPosition = Position::INVALID;
359
} else {
360
// hide all modules if additional isn't valid
361
myAdditionalAttributesEditor->hideAttributesEditor();
362
mySelectorAdditionalParent->hideSelectorParentModule();
363
myViewObjetsSelector->hideNetworkElementsSelector();
364
myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();
365
myHelpCreationModule->hideHelpCreationModule();
366
myE2MultilaneLegendModule->hideE2MultilaneLegend();
367
}
368
}
369
370
371
void
372
GNEAdditionalFrame::resetBaseAdditionalObject() {
373
// check if baseAdditional exist, and if yes, delete it
374
if (myBaseAdditional) {
375
// go to base additional root
376
while (myBaseAdditional->getParentSumoBaseObject()) {
377
myBaseAdditional = myBaseAdditional->getParentSumoBaseObject();
378
}
379
// delete baseAdditional (and all children)
380
delete myBaseAdditional;
381
// reset baseAdditional
382
myBaseAdditional = nullptr;
383
}
384
// create an new base additional
385
myBaseAdditional = new CommonXMLStructure::SumoBaseObject(nullptr);
386
}
387
388
389
bool
390
GNEAdditionalFrame::initBaseAdditionalObject(const GNETagProperties* tagProperty, const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {
391
// declare tag for base additional
392
auto baseAdditionalTag = tagProperty->getTag();
393
// check if tag has to be updated
394
if (baseAdditionalTag == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
395
baseAdditionalTag = SUMO_TAG_LANE_AREA_DETECTOR;
396
} else if (baseAdditionalTag == GNE_TAG_CALIBRATOR_FLOW) {
397
baseAdditionalTag = SUMO_TAG_FLOW;
398
}
399
// update view objects parents
400
viewObjects.fillSumoBaseObject(myBaseAdditional);
401
// check if additional is child of other element
402
if (tagProperty->isChild()) {
403
// check if we clicked over a parent
404
SumoXMLTag parentTag = SUMO_TAG_NOTHING;
405
for (const auto& pTag : tagProperty->getXMLParentTags()) {
406
if (myBaseAdditional->hasParentID(pTag)) {
407
parentTag = pTag;
408
}
409
}
410
// update selector additional parent
411
if (parentTag != SUMO_TAG_NOTHING) {
412
// update parent additional selected
413
mySelectorAdditionalParent->setIDSelected(myBaseAdditional->getParentID(parentTag));
414
}
415
// continue depending of parents
416
if (mySelectorAdditionalParent->getIdSelected().empty()) {
417
std::string messageError = toString(tagProperty->getXMLParentTags().front());
418
if (tagProperty->getXMLParentTags().size() > 1) {
419
const int numParents = (int)tagProperty->getXMLParentTags().size();
420
messageError.clear();
421
for (int i = 0; i < numParents; i++) {
422
messageError.append(toString(tagProperty->getXMLParentTags().at(i)));
423
if (i == numParents - 2) {
424
messageError.append(" or ");
425
} else if (i < (numParents - 2)) {
426
messageError.append(", ");
427
}
428
}
429
}
430
WRITE_WARNING(TLF("A % must be selected before insertion of %.", messageError, tagProperty->getTagStr()));
431
return false;
432
} else {
433
// set parent tag // POSSIBLE ERROR WITH ACCESS AND BUSSTOPS!
434
myBaseAdditional->setTag(tagProperty->getXMLParentTags().front());
435
// add ID
436
myBaseAdditional->addStringAttribute(SUMO_ATTR_ID, mySelectorAdditionalParent->getIdSelected());
437
// create base additional again as child of current base additional
438
myBaseAdditional = new CommonXMLStructure::SumoBaseObject(myBaseAdditional);
439
}
440
}
441
// set baseAdditional tag
442
myBaseAdditional->setTag(baseAdditionalTag);
443
// Obtain position as the clicked position over view
444
const Position viewPosSnapped = myViewNet->snapToActiveGrid(myViewNet->getPositionInformation());
445
// add position and X-Y-Z attributes
446
myBaseAdditional->addPositionAttribute(SUMO_ATTR_POSITION, viewPosSnapped);
447
myBaseAdditional->addDoubleAttribute(SUMO_ATTR_X, viewPosSnapped.x());
448
myBaseAdditional->addDoubleAttribute(SUMO_ATTR_Y, viewPosSnapped.y());
449
myBaseAdditional->addDoubleAttribute(SUMO_ATTR_Z, viewPosSnapped.z());
450
// check if add edge attributes
451
if (tagProperty->hasAttribute(SUMO_ATTR_EDGE)) {
452
if (viewObjects.getEdgeFront() == nullptr) {
453
return false;
454
} else {
455
myBaseAdditional->addStringAttribute(SUMO_ATTR_EDGE, viewObjects.getEdgeFront()->getID());
456
// Obtain position of the mouse over lane (limited over grid)
457
const auto firstLane = viewObjects.getEdgeFront()->getChildLanes().front();
458
const double mousePositionOverLane = firstLane->getLaneShape().nearest_offset_to_point2D(viewPosSnapped) / firstLane->getLengthGeometryFactor();
459
myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, mousePositionOverLane);
460
}
461
} else if (tagProperty->getTag() == SUMO_TAG_VAPORIZER) {
462
// special case for vaporizers
463
if (viewObjects.getEdgeFront() == nullptr) {
464
return false;
465
} else {
466
myBaseAdditional->addStringAttribute(SUMO_ATTR_ID, viewObjects.getEdgeFront()->getID());
467
}
468
}
469
// check if add lane attributes
470
if (tagProperty->hasAttribute(SUMO_ATTR_LANE)) {
471
if (viewObjects.getLaneFront() == nullptr) {
472
return false;
473
} else {
474
myBaseAdditional->addStringAttribute(SUMO_ATTR_LANE, viewObjects.getLaneFront()->getID());
475
myBaseAdditional->addDoubleAttribute(GNE_ATTR_LANELENGTH, viewObjects.getLaneFront()->getLaneShapeLength() / viewObjects.getLaneFront()->getLengthGeometryFactor());
476
// Obtain position of the mouse over lane (limited over grid)
477
const double mousePositionOverLane = viewObjects.getLaneFront()->getLaneShape().nearest_offset_to_point2D(viewPosSnapped) / viewObjects.getLaneFront()->getLengthGeometryFactor();
478
// special case for access
479
if (tagProperty->getTag() == SUMO_TAG_ACCESS) {
480
myBaseAdditional->addStringAttribute(SUMO_ATTR_POSITION, toString(mousePositionOverLane));
481
} else {
482
myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, mousePositionOverLane);
483
}
484
}
485
}
486
// BaseAdditional created, then return true
487
return true;
488
}
489
490
/****************************************************************************/
491
492