Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/frames/GNEConsecutiveSelector.cpp
169678 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 GNEConsecutiveSelector.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Mar 2022
17
///
18
// Consecutive lane selector module
19
/****************************************************************************/
20
21
#include <netedit/GNEApplicationWindow.h>
22
#include <netedit/GNENet.h>
23
#include <netedit/GNEViewNet.h>
24
#include <netedit/GNEViewParent.h>
25
#include <netedit/elements/network/GNEConnection.h>
26
#include <utils/gui/div/GLHelper.h>
27
#include <utils/gui/div/GUIDesigns.h>
28
#include <utils/gui/globjects/GLIncludes.h>
29
#include <utils/gui/windows/GUIAppEnum.h>
30
31
#include "GNEConsecutiveSelector.h"
32
#include "GNEFrame.h"
33
34
// ===========================================================================
35
// FOX callback mapping
36
// ===========================================================================
37
38
FXDEFMAP(GNEConsecutiveSelector) ConsecutiveLaneSelectorMap[] = {
39
FXMAPFUNC(SEL_COMMAND, MID_GNE_ABORT, GNEConsecutiveSelector::onCmdAbortPathCreation),
40
FXMAPFUNC(SEL_COMMAND, MID_GNE_FINISH, GNEConsecutiveSelector::onCmdCreatePath),
41
FXMAPFUNC(SEL_COMMAND, MID_GNE_REMOVELAST, GNEConsecutiveSelector::onCmdRemoveLastElement),
42
FXMAPFUNC(SEL_COMMAND, MID_GNE_SHOWCANDIDATES, GNEConsecutiveSelector::onCmdShowCandidateLanes)
43
};
44
45
// Object implementation
46
FXIMPLEMENT(GNEConsecutiveSelector, MFXGroupBoxModule, ConsecutiveLaneSelectorMap, ARRAYNUMBER(ConsecutiveLaneSelectorMap))
47
48
// ---------------------------------------------------------------------------
49
// GNEConsecutiveSelector - methods
50
// ---------------------------------------------------------------------------
51
52
GNEConsecutiveSelector::GNEConsecutiveSelector(GNEFrame* frameParent, const bool allowOneLane) :
53
MFXGroupBoxModule(frameParent, TL("Consecutive lane selector")),
54
myFrameParent(frameParent),
55
myAllowOneLane(allowOneLane) {
56
// create label for route info
57
myInfoPathLabel = new FXLabel(getCollapsableFrame(), TL("No lanes selected"), 0, GUIDesignLabelThick(JUSTIFY_LEFT));
58
// create button for finish route creation
59
myFinishCreationButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Finish path creation"), "", "", nullptr, this, MID_GNE_FINISH, GUIDesignButton);
60
myFinishCreationButton->disable();
61
// create button for abort route creation
62
myAbortCreationButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Abort path creation"), "", "", nullptr, this, MID_GNE_ABORT, GUIDesignButton);
63
myAbortCreationButton->disable();
64
// create button for remove last inserted lane
65
myRemoveLastInsertedElement = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Remove last lane"), "", "", nullptr, this, MID_GNE_REMOVELAST, GUIDesignButton);
66
myRemoveLastInsertedElement->disable();
67
// create check button
68
myShowCandidateLanes = new FXCheckButton(getCollapsableFrame(), TL("Show candidate lanes"), this, MID_GNE_SHOWCANDIDATES, GUIDesignCheckButton);
69
myShowCandidateLanes->setCheck(TRUE);
70
// create information label
71
new FXLabel(this, (TL("-BACKSPACE: undo click") + std::string("\n") + TL("-ESC: Abort path creation")).c_str(), 0, GUIDesignLabelFrameInformation);
72
}
73
74
75
GNEConsecutiveSelector::~GNEConsecutiveSelector() {}
76
77
78
void
79
GNEConsecutiveSelector::showConsecutiveLaneSelectorModule() {
80
// first abort creation
81
abortPathCreation();
82
// disable buttons
83
myFinishCreationButton->disable();
84
myAbortCreationButton->disable();
85
myRemoveLastInsertedElement->disable();
86
// update lane colors
87
updateLaneColors();
88
// recalc before show (to avoid graphic problems)
89
recalc();
90
// show modul
91
show();
92
}
93
94
95
void
96
GNEConsecutiveSelector::hideConsecutiveLaneSelectorModule() {
97
// clear path
98
clearPath();
99
// hide modul
100
hide();
101
}
102
103
104
const std::vector<std::pair<GNELane*, double> >&
105
GNEConsecutiveSelector::getLanePath() const {
106
return myLanePath;
107
}
108
109
110
const std::vector<std::string>
111
GNEConsecutiveSelector::getLaneIDPath() const {
112
std::vector<std::string> laneIDs;
113
for (const auto& lane : myLanePath) {
114
if (laneIDs.empty() || (laneIDs.back() != lane.first->getID())) {
115
laneIDs.push_back(lane.first->getID());
116
}
117
}
118
return laneIDs;
119
}
120
121
122
bool
123
GNEConsecutiveSelector::addLane(GNELane* lane) {
124
// first check if lane is valid
125
if (lane == nullptr) {
126
return false;
127
}
128
// check candidate lane
129
if ((myShowCandidateLanes->getCheck() == TRUE) && !lane->isPossibleCandidate()) {
130
if (lane->isSpecialCandidate() || lane->isConflictedCandidate()) {
131
// Write warning
132
WRITE_WARNING(TL("Invalid lane"));
133
// abort add lane
134
return false;
135
}
136
}
137
// get mouse position
138
const Position mousePos = myFrameParent->getViewNet()->snapToActiveGrid(myFrameParent->getViewNet()->getPositionInformation());
139
// calculate lane offset
140
const double posOverLane = lane->getLaneShape().nearest_offset_to_point2D(mousePos);
141
// All checks ok, then add it in selected elements
142
if (myLanePath.empty()) {
143
myLanePath.push_back(std::make_pair(lane, posOverLane));
144
} else if ((myLanePath.size() == 1) && (myLanePath.front().first == lane)) {
145
if (myAllowOneLane) {
146
myLanePath.push_back(std::make_pair(lane, posOverLane));
147
} else {
148
// Write warning
149
WRITE_WARNING(TL("Lane path needs at least two lanes"));
150
// abort add lane
151
return false;
152
}
153
} else if (myLanePath.back().first == lane) {
154
// only change last position
155
myLanePath.back().second = posOverLane;
156
} else {
157
myLanePath.push_back(std::make_pair(lane, posOverLane));
158
// special case if we clicked over a new lane after a previous double lane
159
if ((myLanePath.size() == 3) && (myLanePath.at(0).first == myLanePath.at(1).first)) {
160
// remove second lane
161
myLanePath.erase(myLanePath.begin() + 1);
162
}
163
}
164
// enable abort route button
165
myAbortCreationButton->enable();
166
// enable finish button
167
myFinishCreationButton->enable();
168
// disable undo/redo temporally
169
myFrameParent->getViewNet()->getViewParent()->getGNEAppWindows()->disableUndoRedoTemporally(TL("route creation"));
170
// enable or disable remove last lane button
171
if (myLanePath.size() > 1) {
172
myRemoveLastInsertedElement->enable();
173
} else {
174
myRemoveLastInsertedElement->disable();
175
}
176
// update info route label
177
updateInfoRouteLabel();
178
// update lane colors
179
updateLaneColors();
180
return true;
181
}
182
183
184
bool
185
GNEConsecutiveSelector::drawCandidateLanesWithSpecialColor() const {
186
return (myShowCandidateLanes->getCheck() == TRUE);
187
}
188
189
190
void
191
GNEConsecutiveSelector::updateLaneColors() {
192
// reset all flags
193
for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
194
for (const auto& lane : edge.second->getChildLanes()) {
195
lane->resetCandidateFlags();
196
}
197
}
198
// set reachability
199
if (myLanePath.size() > 0 && (myShowCandidateLanes->getCheck() == TRUE)) {
200
// first mark all lanes as invalid
201
for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
202
for (const auto& lane : edge.second->getChildLanes()) {
203
lane->setConflictedCandidate(true);
204
}
205
}
206
// now mark lane paths as valid
207
for (const auto& lane : myLanePath) {
208
// disable conflicted candidate
209
lane.first->setConflictedCandidate(false);
210
if (lane == myLanePath.back()) {
211
lane.first->setSourceCandidate(true);
212
} else {
213
lane.first->setTargetCandidate(true);
214
}
215
}
216
// get parent edge
217
const GNEEdge* edge = myLanePath.back().first->getParentEdge();
218
// iterate over connections
219
for (const auto& connection : edge->getGNEConnections()) {
220
// mark possible candidates
221
if (connection->getLaneFrom() == myLanePath.back().first) {
222
connection->getLaneTo()->setConflictedCandidate(false);
223
connection->getLaneTo()->setPossibleCandidate(true);
224
}
225
}
226
}
227
// update view net
228
myFrameParent->getViewNet()->updateViewNet();
229
}
230
231
232
void
233
GNEConsecutiveSelector::drawTemporalConsecutiveLanePath() const {
234
// Only draw if there is at least one lane
235
if (myLanePath.size() > 0) {
236
// get widths
237
const double lineWidth = 0.35;
238
const double lineWidthin = 0.25;
239
// declare vector with shapes
240
std::vector<PositionVector> shapes;
241
// iterate over lanes (only if there is more than one)
242
if ((myLanePath.size() == 2) && (myLanePath.front().first == myLanePath.back().first)) {
243
// only add first lane shape
244
shapes.push_back(myLanePath.front().first->getLaneShape());
245
// adjust shape
246
shapes.front() = shapes.front().getSubpart(myLanePath.front().second, myLanePath.back().second);
247
} else if (myLanePath.size() > 1) {
248
// get shapes
249
for (int i = 0; i < (int)myLanePath.size(); i++) {
250
// get lane
251
const GNELane* lane = myLanePath.at(i).first;
252
// add lane shape
253
shapes.push_back(lane->getLaneShape());
254
// draw connection between lanes
255
if ((i + 1) < (int)myLanePath.size()) {
256
// get next lane
257
const GNELane* nextLane = myLanePath.at(i + 1).first;
258
if (lane->getLane2laneConnections().exist(nextLane)) {
259
shapes.push_back(lane->getLane2laneConnections().getLane2laneGeometry(nextLane).getShape());
260
} else {
261
shapes.push_back({lane->getLaneShape().back(), nextLane->getLaneShape().front()});
262
}
263
}
264
}
265
// adjust first and last shape
266
shapes.front() = shapes.front().splitAt(myLanePath.front().second).second;
267
shapes.back() = shapes.back().splitAt(myLanePath.back().second).first;
268
}
269
// Add a draw matrix
270
GLHelper::pushMatrix();
271
// move to temporal shape
272
glTranslated(0, 0, GLO_TEMPORALSHAPE);
273
// iterate over shapes
274
for (const auto& shape : shapes) {
275
// set extern
276
GLHelper::setColor(RGBColor::GREY);
277
// draw extern shape
278
GLHelper::drawBoxLines(shape, lineWidth);
279
// push matrix
280
GLHelper::pushMatrix();
281
// move to front
282
glTranslated(0, 0, 0.1);
283
// set orange color
284
GLHelper::setColor(RGBColor::ORANGE);
285
// draw intern shape
286
GLHelper::drawBoxLines(shape, lineWidthin);
287
// Pop matrix
288
GLHelper::popMatrix();
289
}
290
// draw points
291
if (shapes.size() > 0) {
292
// draw geometry points
293
GUIGeometry::drawGeometryPoints(GUIVisualizationSettings::Detail::AdditionalDetails,
294
{shapes.front().front(), shapes.back().back()}, RGBColor::RED,
295
myFrameParent->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius, 1, false);
296
}
297
// Pop last matrix
298
GLHelper::popMatrix();
299
}
300
}
301
302
303
void
304
GNEConsecutiveSelector::abortPathCreation() {
305
// first check that there is elements
306
if (myLanePath.size() > 0) {
307
// unblock undo/redo
308
myFrameParent->getViewNet()->getViewParent()->getGNEAppWindows()->enableUndoRedoTemporally();
309
// clear lanes
310
clearPath();
311
// disable buttons
312
myFinishCreationButton->disable();
313
myAbortCreationButton->disable();
314
myRemoveLastInsertedElement->disable();
315
// update info route label
316
updateInfoRouteLabel();
317
// update reachability
318
updateLaneColors();
319
// update view (to see the new route)
320
myFrameParent->getViewNet()->updateViewNet();
321
}
322
}
323
324
325
void
326
GNEConsecutiveSelector::removeLastElement() {
327
if (myLanePath.size() > 1) {
328
// remove special color of last selected lane
329
myLanePath.back().first->resetCandidateFlags();
330
// remove last lane
331
myLanePath.pop_back();
332
// change last lane flag
333
if ((myLanePath.size() > 0) && myLanePath.back().first->isSourceCandidate()) {
334
myLanePath.back().first->setSourceCandidate(false);
335
myLanePath.back().first->setTargetCandidate(true);
336
}
337
// enable or disable remove last lane button
338
if (myLanePath.size() > 1) {
339
myRemoveLastInsertedElement->enable();
340
} else {
341
myRemoveLastInsertedElement->disable();
342
}
343
// update info route label
344
updateInfoRouteLabel();
345
// update reachability
346
updateLaneColors();
347
// update view
348
myFrameParent->getViewNet()->updateViewNet();
349
}
350
}
351
352
353
long
354
GNEConsecutiveSelector::onCmdCreatePath(FXObject*, FXSelector, void*) {
355
myFrameParent->createPath(false);
356
return 1;
357
}
358
359
360
long
361
GNEConsecutiveSelector::onCmdAbortPathCreation(FXObject*, FXSelector, void*) {
362
// just call abort path creation
363
abortPathCreation();
364
return 1;
365
}
366
367
368
long
369
GNEConsecutiveSelector::onCmdRemoveLastElement(FXObject*, FXSelector, void*) {
370
// just call remove last element
371
removeLastElement();
372
return 1;
373
}
374
375
376
long
377
GNEConsecutiveSelector::onCmdShowCandidateLanes(FXObject*, FXSelector, void*) {
378
// recalc frame
379
recalc();
380
// update lane colors (view will be updated within function)
381
updateLaneColors();
382
return 1;
383
}
384
385
386
GNEConsecutiveSelector::GNEConsecutiveSelector() :
387
myFrameParent(nullptr),
388
myAllowOneLane(false) {
389
}
390
391
392
void
393
GNEConsecutiveSelector::updateInfoRouteLabel() {
394
if (myLanePath.size() > 0) {
395
// declare variables for route info
396
double length = 0;
397
for (const auto& lane : myLanePath) {
398
length += lane.first->getParentEdge()->getNBEdge()->getLength();
399
}
400
// declare ostringstream for label and fill it
401
std::ostringstream information;
402
information
403
<< TL("- Selected lanes: ") << toString(myLanePath.size()) << "\n"
404
<< TL("- Length: ") << toString(length);
405
// set new label
406
myInfoPathLabel->setText(information.str().c_str());
407
} else {
408
myInfoPathLabel->setText(TL("No lanes selected"));
409
}
410
}
411
412
413
void
414
GNEConsecutiveSelector::clearPath() {
415
// reset all flags
416
for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
417
for (const auto& lane : edge.second->getChildLanes()) {
418
lane->resetCandidateFlags();
419
}
420
}
421
// clear path
422
myLanePath.clear();
423
// update info route label
424
updateInfoRouteLabel();
425
}
426
427
/****************************************************************************/
428
429