Eclipse SUMO - Simulation of Urban MObility
GNEConsecutiveSelector.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 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 /****************************************************************************/
18 // Consecutive lane selector module
19 /****************************************************************************/
20 #include <config.h>
21 
23 #include <netedit/GNENet.h>
24 #include <netedit/GNEViewNet.h>
25 #include <netedit/GNEViewParent.h>
27 #include <utils/gui/div/GLHelper.h>
31 
32 #include "GNEConsecutiveSelector.h"
33 #include "GNEFrame.h"
34 
35 
36 // ===========================================================================
37 // FOX callback mapping
38 // ===========================================================================
39 
40 FXDEFMAP(GNEConsecutiveSelector) ConsecutiveLaneSelectorMap[] = {
45 };
46 
47 // Object implementation
48 FXIMPLEMENT(GNEConsecutiveSelector, MFXGroupBoxModule, ConsecutiveLaneSelectorMap, ARRAYNUMBER(ConsecutiveLaneSelectorMap))
49 
50 // ---------------------------------------------------------------------------
51 // GNEConsecutiveSelector - methods
52 // ---------------------------------------------------------------------------
53 
54 GNEConsecutiveSelector::GNEConsecutiveSelector(GNEFrame* frameParent, const bool allowOneLane) :
55  MFXGroupBoxModule(frameParent, TL("Consecutive lane selector")),
56  myFrameParent(frameParent),
57  myAllowOneLane(allowOneLane) {
58  // create label for route info
59  myInfoPathLabel = new FXLabel(getCollapsableFrame(), TL("No lanes selected"), 0, GUIDesignLabelThick(JUSTIFY_LEFT));
60  // create button for finish route creation
61  myFinishCreationButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Finish path creation"), "", "", nullptr, this, MID_GNE_FINISH, GUIDesignButton);
62  myFinishCreationButton->disable();
63  // create button for abort route creation
64  myAbortCreationButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Abort path creation"), "", "", nullptr, this, MID_GNE_ABORT, GUIDesignButton);
65  myAbortCreationButton->disable();
66  // create button for remove last inserted lane
67  myRemoveLastInsertedElement = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Remove last lane"), "", "", nullptr, this, MID_GNE_REMOVELAST, GUIDesignButton);
68  myRemoveLastInsertedElement->disable();
69  // create check button
70  myShowCandidateLanes = new FXCheckButton(getCollapsableFrame(), TL("Show candidate lanes"), this, MID_GNE_SHOWCANDIDATES, GUIDesignCheckButton);
71  myShowCandidateLanes->setCheck(TRUE);
72  // create information label
73  new FXLabel(this, (TL("-BACKSPACE: undo click") + std::string("\n") + TL("-ESC: Abort path creation")).c_str(), 0, GUIDesignLabelFrameInformation);
74 }
75 
76 
78 
79 
80 void
82  // first abort creation
84  // disable buttons
85  myFinishCreationButton->disable();
86  myAbortCreationButton->disable();
87  myRemoveLastInsertedElement->disable();
88  // update lane colors
90  // recalc before show (to avoid graphic problems)
91  recalc();
92  // show modul
93  show();
94 }
95 
96 
97 void
99  // clear path
100  clearPath();
101  // hide modul
102  hide();
103 }
104 
105 
106 const std::vector<std::pair<GNELane*, double> >&
108  return myLanePath;
109 }
110 
111 
112 const std::vector<std::string>
114  std::vector<std::string> laneIDs;
115  for (const auto& lane : myLanePath) {
116  if (laneIDs.empty() || (laneIDs.back() != lane.first->getID())) {
117  laneIDs.push_back(lane.first->getID());
118  }
119  }
120  return laneIDs;
121 }
122 
123 
124 bool
126  // first check if lane is valid
127  if (lane == nullptr) {
128  return false;
129  }
130  // check candidate lane
131  if ((myShowCandidateLanes->getCheck() == TRUE) && !lane->isPossibleCandidate()) {
132  if (lane->isSpecialCandidate() || lane->isConflictedCandidate()) {
133  // Write warning
134  WRITE_WARNING(TL("Invalid lane"));
135  // abort add lane
136  return false;
137  }
138  }
139  // get mouse position
141  // calculate lane offset
142  const double posOverLane = lane->getLaneShape().nearest_offset_to_point2D(mousePos);
143  // All checks ok, then add it in selected elements
144  if (myLanePath.empty()) {
145  myLanePath.push_back(std::make_pair(lane, posOverLane));
146  } else if ((myLanePath.size() == 1) && (myLanePath.front().first == lane)) {
147  if (myAllowOneLane) {
148  myLanePath.push_back(std::make_pair(lane, posOverLane));
149  } else {
150  // Write warning
151  WRITE_WARNING(TL("Lane path needs at least two lanes"));
152  // abort add lane
153  return false;
154  }
155  } else if (myLanePath.back().first == lane) {
156  // only change last position
157  myLanePath.back().second = posOverLane;
158  } else {
159  myLanePath.push_back(std::make_pair(lane, posOverLane));
160  // special case if we clicked over a new lane after a previous double lane
161  if ((myLanePath.size() == 3) && (myLanePath.at(0).first == myLanePath.at(1).first)) {
162  // remove second lane
163  myLanePath.erase(myLanePath.begin() + 1);
164  }
165  }
166  // enable abort route button
167  myAbortCreationButton->enable();
168  // enable finish button
169  myFinishCreationButton->enable();
170  // disable undo/redo
172  // enable or disable remove last lane button
173  if (myLanePath.size() > 1) {
174  myRemoveLastInsertedElement->enable();
175  } else {
176  myRemoveLastInsertedElement->disable();
177  }
178  // update info route label
180  // update lane colors
182  return true;
183 }
184 
185 
186 bool
188  return (myShowCandidateLanes->getCheck() == TRUE);
189 }
190 
191 
192 void
194  // reset all flags
195  for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
196  for (const auto& lane : edge.second.second->getLanes()) {
197  lane->resetCandidateFlags();
198  }
199  }
200  // set reachability
201  if (myLanePath.size() > 0 && (myShowCandidateLanes->getCheck() == TRUE)) {
202  // first mark all lanes as invalid
203  for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
204  for (const auto& lane : edge.second.second->getLanes()) {
205  lane->setConflictedCandidate(true);
206  }
207  }
208  // now mark lane paths as valid
209  for (const auto& lane : myLanePath) {
210  // disable conflicted candidate
211  lane.first->setConflictedCandidate(false);
212  if (lane == myLanePath.back()) {
213  lane.first->setSourceCandidate(true);
214  } else {
215  lane.first->setTargetCandidate(true);
216  }
217  }
218  // get parent edge
219  const GNEEdge* edge = myLanePath.back().first->getParentEdge();
220  // iterate over connections
221  for (const auto& connection : edge->getGNEConnections()) {
222  // mark possible candidates
223  if (connection->getLaneFrom() == myLanePath.back().first) {
224  connection->getLaneTo()->setConflictedCandidate(false);
225  connection->getLaneTo()->setPossibleCandidate(true);
226  }
227  }
228  }
229  // update view net
231 }
232 
233 
234 void
236  // Only draw if there is at least one lane
237  if (myLanePath.size() > 0) {
238  // get widths
239  const double lineWidth = 0.35;
240  const double lineWidthin = 0.25;
241  // declare vector with shapes
242  std::vector<PositionVector> shapes;
243  // iterate over lanes (only if there is more than one)
244  if ((myLanePath.size() == 2) && (myLanePath.front().first == myLanePath.back().first)) {
245  // only add first lane shape
246  shapes.push_back(myLanePath.front().first->getLaneShape());
247  // adjust shape
248  shapes.front() = shapes.front().getSubpart(myLanePath.front().second, myLanePath.back().second);
249  } else if (myLanePath.size() > 1) {
250  // get shapes
251  for (int i = 0; i < (int)myLanePath.size(); i++) {
252  // get lane
253  const GNELane* lane = myLanePath.at(i).first;
254  // add lane shape
255  shapes.push_back(lane->getLaneShape());
256  // draw connection between lanes
257  if ((i + 1) < (int)myLanePath.size()) {
258  // get next lane
259  const GNELane* nextLane = myLanePath.at(i + 1).first;
260  if (lane->getLane2laneConnections().exist(nextLane)) {
261  shapes.push_back(lane->getLane2laneConnections().getLane2laneGeometry(nextLane).getShape());
262  } else {
263  shapes.push_back({lane->getLaneShape().back(), nextLane->getLaneShape().front()});
264  }
265  }
266  }
267  // adjust first and last shape
268  shapes.front() = shapes.front().splitAt(myLanePath.front().second).second;
269  shapes.back() = shapes.back().splitAt(myLanePath.back().second).first;
270  }
271  // Add a draw matrix
273  // move to temporal shape
274  glTranslated(0, 0, GLO_TEMPORALSHAPE);
275  // iterate over shapes
276  for (const auto& shape : shapes) {
277  // set extern
279  // draw extern shape
280  GLHelper::drawBoxLines(shape, lineWidth);
281  // push matrix
283  // move to front
284  glTranslated(0, 0, 0.1);
285  // set orange color
287  // draw intern shape
288  GLHelper::drawBoxLines(shape, lineWidthin);
289  // Pop matrix
291  }
292  /*
293  // draw points
294  const RGBColor pointColor = RGBColor::RED;
295  // positions
296  const Position firstPosition = myLanePath.front().first->getLaneShape().positionAtOffset2D(myLanePath.front().second);
297  const Position secondPosition = myLanePath.back().first->getLaneShape().positionAtOffset2D(myLanePath.back().second);
298  // draw geometry points
299  GUIGeometry::drawGeometryPoints(s, nullptr, myFrameParent->getViewNet()->getPositionInformation(), {firstPosition, secondPosition},
300  pointColor, RGBColor::WHITE, s.neteditSizeSettings.polylineWidth, 1, false, true);
301  */
302  // Pop last matrix
304  }
305 }
306 
307 
308 void
310  // first check that there is elements
311  if (myLanePath.size() > 0) {
312  // unblock undo/redo
314  // clear lanes
315  clearPath();
316  // disable buttons
317  myFinishCreationButton->disable();
318  myAbortCreationButton->disable();
319  myRemoveLastInsertedElement->disable();
320  // update info route label
322  // update reachability
324  // update view (to see the new route)
326  }
327 }
328 
329 
330 void
332  if (myLanePath.size() > 1) {
333  // remove special color of last selected lane
334  myLanePath.back().first->resetCandidateFlags();
335  // remove last lane
336  myLanePath.pop_back();
337  // change last lane flag
338  if ((myLanePath.size() > 0) && myLanePath.back().first->isSourceCandidate()) {
339  myLanePath.back().first->setSourceCandidate(false);
340  myLanePath.back().first->setTargetCandidate(true);
341  }
342  // enable or disable remove last lane button
343  if (myLanePath.size() > 1) {
344  myRemoveLastInsertedElement->enable();
345  } else {
346  myRemoveLastInsertedElement->disable();
347  }
348  // update info route label
350  // update reachability
352  // update view
354  }
355 }
356 
357 
358 long
359 GNEConsecutiveSelector::onCmdCreatePath(FXObject*, FXSelector, void*) {
360  myFrameParent->createPath(false);
361  return 1;
362 }
363 
364 
365 long
366 GNEConsecutiveSelector::onCmdAbortPathCreation(FXObject*, FXSelector, void*) {
367  // just call abort path creation
369  return 1;
370 }
371 
372 
373 long
374 GNEConsecutiveSelector::onCmdRemoveLastElement(FXObject*, FXSelector, void*) {
375  // just call remove last element
377  return 1;
378 }
379 
380 
381 long
382 GNEConsecutiveSelector::onCmdShowCandidateLanes(FXObject*, FXSelector, void*) {
383  // recalc frame
384  recalc();
385  // update lane colors (view will be updated within function)
387  return 1;
388 }
389 
390 
392  myFrameParent(nullptr),
393  myAllowOneLane(false) {
394 }
395 
396 
397 void
399  if (myLanePath.size() > 0) {
400  // declare variables for route info
401  double length = 0;
402  for (const auto& lane : myLanePath) {
403  length += lane.first->getParentEdge()->getNBEdge()->getLength();
404  }
405  // declare ostringstream for label and fill it
406  std::ostringstream information;
407  information
408  << TL("- Selected lanes: ") << toString(myLanePath.size()) << "\n"
409  << TL("- Length: ") << toString(length);
410  // set new label
411  myInfoPathLabel->setText(information.str().c_str());
412  } else {
413  myInfoPathLabel->setText(TL("No lanes selected"));
414  }
415 }
416 
417 
418 void
420  // reset all flags
421  for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
422  for (const auto& lane : edge.second.second->getLanes()) {
423  lane->resetCandidateFlags();
424  }
425  }
426  // clear path
427  myLanePath.clear();
428  // update info route label
430 }
431 
432 /****************************************************************************/
FXDEFMAP(GNEConsecutiveSelector) ConsecutiveLaneSelectorMap[]
@ MID_GNE_SHOWCANDIDATES
enable or disable show path candidates
Definition: GUIAppEnum.h:994
@ MID_GNE_REMOVELAST
remove last inserted element in path
Definition: GUIAppEnum.h:992
@ MID_GNE_FINISH
finish lane path creation
Definition: GUIAppEnum.h:990
@ MID_GNE_ABORT
abort lane path creation
Definition: GUIAppEnum.h:988
#define GUIDesignButton
Definition: GUIDesigns.h:88
#define GUIDesignLabelThick(justify)
label extended over frame with thick and with text justify to left
Definition: GUIDesigns.h:255
#define GUIDesignCheckButton
checkButton placed in left position
Definition: GUIDesigns.h:198
#define GUIDesignLabelFrameInformation
label extended over frame without thick and with text justify to left, used to show information in fr...
Definition: GUIDesigns.h:285
@ GLO_TEMPORALSHAPE
temporal shape (used in netedit)
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition: GLHelper.cpp:655
static void popMatrix()
pop matrix
Definition: GLHelper.cpp:130
static void drawBoxLines(const PositionVector &geom, const std::vector< double > &rots, const std::vector< double > &lengths, double width, int cornerDetail=0, double offset=0)
Draws thick lines.
Definition: GLHelper.cpp:347
static void pushMatrix()
push matrix
Definition: GLHelper.cpp:117
void disableUndoRedo(const std::string &reason)
disable undo-redo giving a string with the reason
void enableUndoRedo()
disable undo-redo
bool isSpecialCandidate() const
check if this element is a special candidate
bool isPossibleCandidate() const
check if this element is a possible candidate
bool isConflictedCandidate() const
check if this element is a conflicted candidate
std::vector< std::pair< GNELane *, double > > myLanePath
vector with lanes and clicked positions
void drawTemporalConsecutiveLanePath() const
draw temporal consecutive lane path
bool addLane(GNELane *lane)
add lane
void abortPathCreation()
abort path creation
FXLabel * myInfoPathLabel
label with path info
GNEFrame * myFrameParent
pointer to frame parent
const bool myAllowOneLane
allow one lane
void updateLaneColors()
update lane colors
void showConsecutiveLaneSelectorModule()
show GNEConsecutiveSelector
long onCmdCreatePath(FXObject *, FXSelector, void *)
void clearPath()
clear lanes (and restore colors)
FXButton * myRemoveLastInsertedElement
button for removing last inserted element
FXCheckButton * myShowCandidateLanes
CheckBox for show candidate lanes.
long onCmdRemoveLastElement(FXObject *, FXSelector, void *)
Called when the user click over button "Remove las inserted lane".
void updateInfoRouteLabel()
update InfoRouteLabel
const std::vector< std::pair< GNELane *, double > > & getLanePath() const
get vector with lanes and clicked positions
void removeLastElement()
remove path element
bool drawCandidateLanesWithSpecialColor() const
draw candidate lanes with special color (Only for candidates, special and conflicted)
void hideConsecutiveLaneSelectorModule()
show GNEConsecutiveSelector
long onCmdShowCandidateLanes(FXObject *, FXSelector, void *)
Called when the user click over check button "show candidate lanes".
const std::vector< std::string > getLaneIDPath() const
get lane IDs
FXButton * myFinishCreationButton
button for finish route creation
long onCmdAbortPathCreation(FXObject *, FXSelector, void *)
Called when the user click over button "Abort route creation".
FXButton * myAbortCreationButton
button for abort route creation
A road/street connecting two junctions (netedit-version)
Definition: GNEEdge.h:53
const std::vector< GNEConnection * > & getGNEConnections() const
returns a reference to the GNEConnection vector
Definition: GNEEdge.cpp:1053
GNEViewNet * getViewNet() const
get view net
Definition: GNEFrame.cpp:150
virtual bool createPath(const bool useLastRoute)
create path between two elements
Definition: GNEFrame.cpp:304
bool exist(const GNELane *toLane) const
check if exist a lane2lane geometry for the given toLane
const GUIGeometry & getLane2laneGeometry(const GNELane *toLane) const
get lane2lane geometry
This lane is powered by an underlying GNEEdge and basically knows how to draw itself.
Definition: GNELane.h:46
const PositionVector & getLaneShape() const
get elements shape
Definition: GNELane.cpp:214
const GNELane2laneConnection & getLane2laneConnections() const
get Lane2laneConnection struct
Definition: GNELane.cpp:684
const std::map< std::string, std::pair< const GUIGlObject *, GNEEdge * > > & getEdges() const
map with the ID and pointer to edges of net
GNENetHelper::AttributeCarriers * getAttributeCarriers() const
get all attribute carriers used in this net
Definition: GNENet.cpp:121
GNENet * getNet() const
get the net object
GNEViewParent * getViewParent() const
get the net object
void updateViewNet() const
Mark the entire GNEViewNet to be repainted later.
Definition: GNEViewNet.cpp:410
GNEApplicationWindow * getGNEAppWindows() const
get GNE Application Windows
static FXButton * buildFXButton(FXComposite *p, const std::string &text, const std::string &tip, const std::string &help, FXIcon *ic, FXObject *tgt, FXSelector sel, FXuint opts=BUTTON_NORMAL, FXint x=0, FXint y=0, FXint w=0, FXint h=0, FXint pl=DEFAULT_PAD, FXint pr=DEFAULT_PAD, FXint pt=DEFAULT_PAD, FXint pb=DEFAULT_PAD)
build button
Definition: GUIDesigns.cpp:128
const PositionVector & getShape() const
The shape of the additional element.
Position snapToActiveGrid(const Position &pos, bool snapXY=true) const
Returns a position that is mapped to the closest grid point if the grid is active.
virtual Position getPositionInformation() const
Returns the cursor's x/y position within the network.
MFXGroupBoxModule (based on FXGroupBox)
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
static const RGBColor GREY
Definition: RGBColor.h:194
static const RGBColor ORANGE
Definition: RGBColor.h:191