SUMO - Simulation of Urban MObility
GNECrossing.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
15 // A class for visualizing Inner Lanes (used when editing traffic lights)
16 /****************************************************************************/
17 
18 
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <config.h>
23 
27 #include <utils/gui/div/GLHelper.h>
29 #include <netedit/GNEViewNet.h>
30 #include <netedit/GNEUndoList.h>
31 #include <netedit/GNENet.h>
33 
34 #include "GNECrossing.h"
35 #include "GNEJunction.h"
36 #include "GNEEdge.h"
37 
38 
39 // ===========================================================================
40 // method definitions
41 // ===========================================================================
42 GNECrossing::GNECrossing(GNEJunction* parentJunction, std::vector<NBEdge*> crossingEdges) :
43  GNENetElement(parentJunction->getNet(), parentJunction->getNBNode()->getCrossing(crossingEdges)->id, GLO_CROSSING, SUMO_TAG_CROSSING),
44  myParentJunction(parentJunction),
45  myCrossingEdges(crossingEdges) {
46 }
47 
48 
50 
51 
52 void
53 GNECrossing::updateGeometry(bool /*updateGrid*/) {
54  // rebuild crossing and walking areas form node parent
56  // obtain shape
57  myShape = crossing->customShape.size() > 0 ? crossing->customShape : crossing->shape;
58  // Clear Shape rotations and segments
59  myShapeRotations.clear();
60  myShapeLengths.clear();
61  // only rebuild shape if junction's shape isn't in Buuble mode
62  if (myParentJunction->getNBNode()->getShape().size() > 0) {
63  int segments = (int)myShape.size() - 1;
64  if (segments >= 0) {
65  myShapeRotations.reserve(segments);
66  myShapeLengths.reserve(segments);
67  for (int i = 0; i < segments; ++i) {
68  const Position& f = myShape[i];
69  const Position& s = myShape[i + 1];
70  myShapeLengths.push_back(f.distanceTo2D(s));
71  myShapeRotations.push_back((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double)M_PI);
72  }
73  }
74  }
75 }
76 
77 
80  return myParentJunction;
81 }
82 
83 
84 const std::vector<NBEdge*>&
86  return myCrossingEdges;
87 }
88 
89 
93 }
94 
95 
96 void
98  // only draw if option drawCrossingsAndWalkingareas is enabled and size of shape is greather than 0 and zoom is close enough
100  (myShapeRotations.size() > 0) &&
101  (myShapeLengths.size() > 0) &&
102  (s.scale > 3.0)) {
104  if (s.editMode != GNE_MODE_TLS) {
105  // push first draw matrix
106  glPushMatrix();
107  // push name
108  glPushName(getGlID());
109  // must draw on top of junction
110  glTranslated(0, 0, GLO_JUNCTION + 0.1);
111  // set color depending of selection and priority
113  glColor3d(0.118, 0.565, 1.000);
114  } else if (!crossing->valid) {
115  glColor3d(1.0, 0.1, 0.1);
116  } else if (crossing->priority) {
117  glColor3d(0.9, 0.9, 0.9);
118  } else {
119  glColor3d(0.1, 0.1, 0.1);
120  }
121  // traslate to front
122  glTranslated(0, 0, .2);
123  // set default values
124  double length = 0.5;
125  double spacing = 1.0;
126  double halfWidth = crossing->width * 0.5;
127  // push second draw matrix
128  glPushMatrix();
129  // draw on top of of the white area between the rails
130  glTranslated(0, 0, 0.1);
131  for (int i = 0; i < (int)myShape.size() - 1; ++i) {
132  // push three draw matrix
133  glPushMatrix();
134  // translate and rotate
135  glTranslated(myShape[i].x(), myShape[i].y(), 0.0);
136  glRotated(myShapeRotations[i], 0, 0, 1);
137  // draw crossing depending if isn't being drawn for selecting
138  if (!s.drawForSelecting) {
139  for (double t = 0; t < myShapeLengths[i]; t += spacing) {
140  glBegin(GL_QUADS);
141  glVertex2d(-halfWidth, -t);
142  glVertex2d(-halfWidth, -t - length);
143  glVertex2d(halfWidth, -t - length);
144  glVertex2d(halfWidth, -t);
145  glEnd();
146  }
147  } else {
148  // only draw a single rectangle if it's being drawn only for selecting
149  glBegin(GL_QUADS);
150  glVertex2d(-halfWidth, 0);
151  glVertex2d(-halfWidth, -myShapeLengths.back());
152  glVertex2d(halfWidth, -myShapeLengths.back());
153  glVertex2d(halfWidth, 0);
154  glEnd();
155  }
156  // pop three draw matrix
157  glPopMatrix();
158  }
159  // XXX draw junction index / tls index
160  // pop second draw matrix
161  glPopMatrix();
162  // traslate to back
163  glTranslated(0, 0, -.2);
164  // pop name
165  glPopName();
166  // pop draw matrix
167  glPopMatrix();
168  }
169  // link indices must be drawn in all edit modes if isn't being drawn for selecting
170  if (s.drawLinkTLIndex.show && !s.drawForSelecting) {
171  drawTLSLinkNo(s);
172  }
173  // check if dotted contour has to be drawn
174  if (!s.drawForSelecting && (myNet->getViewNet()->getDottedAC() == this)) {
175  GLHelper::drawShapeDottedContour(getType(), myShape, crossing->width * 0.5);
176  }
177  }
178 }
179 
180 
181 void
184  glPushMatrix();
185  glTranslated(0, 0, GLO_JUNCTION + 0.5);
186  PositionVector shape = crossing->shape;
187  shape.extrapolate(0.5); // draw on top of the walking area
188  int linkNo = crossing->tlLinkIndex;
189  int linkNo2 = crossing->tlLinkIndex2 > 0 ? crossing->tlLinkIndex2 : linkNo;
192  glPopMatrix();
193 }
194 
195 
198  GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, *this);
199  buildPopupHeader(ret, app);
202  // build selection and show parameters menu
205  // build position copy entry
206  buildPositionCopyEntry(ret, false);
207  // create menu commands
208  FXMenuCommand* mcCustomShape = new FXMenuCommand(ret, "Set custom crossing shape", nullptr, &parent, MID_GNE_CROSSING_EDIT_SHAPE);
209  // check if menu commands has to be disabled
210  EditMode editMode = myNet->getViewNet()->getCurrentEditMode();
211  const bool wrongMode = (editMode == GNE_MODE_CONNECT || editMode == GNE_MODE_TLS || editMode == GNE_MODE_CREATE_EDGE);
212  if (wrongMode) {
213  mcCustomShape->disable();
214  }
215  return ret;
216 }
217 
218 
219 Boundary
221  // make sure that shape isn't empty
222  if (myShape.size() == 0) {
223  // we need to use the center of junction parent as boundary if shape is empty
226  } else {
227  // use crossing boundary
229  b.grow(10);
230  return b;
231  }
232 }
233 
234 
235 std::string
237  auto crossing = myParentJunction->getNBNode()->getCrossing(myCrossingEdges, (key != SUMO_ATTR_ID));
238  switch (key) {
239  case SUMO_ATTR_ID:
240  // get attribute requieres a special case
241  if (crossing) {
242  return crossing->id;
243  } else {
244  return "Temporal Unreferenced";
245  }
246  case SUMO_ATTR_WIDTH:
247  return toString(crossing->customWidth);
248  case SUMO_ATTR_PRIORITY:
249  return crossing->priority ? "true" : "false";
250  case SUMO_ATTR_EDGES:
251  return toString(crossing->edges);
253  return toString(crossing->customTLIndex);
255  return toString(crossing->customTLIndex2);
257  return toString(crossing->customShape);
258  case GNE_ATTR_SELECTED:
260  case GNE_ATTR_GENERIC:
261  return getGenericParametersStr();
262  default:
263  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
264  }
265 }
266 
267 
268 void
269 GNECrossing::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
270  if (value == getAttribute(key)) {
271  return; //avoid needless changes, later logic relies on the fact that attributes have changed
272  }
273  switch (key) {
274  case SUMO_ATTR_ID:
275  throw InvalidArgument("Modifying attribute '" + toString(key) + "' of " + getTagStr() + " isn't allowed");
276  case SUMO_ATTR_EDGES:
277  case SUMO_ATTR_WIDTH:
278  case SUMO_ATTR_PRIORITY:
282  case GNE_ATTR_SELECTED:
283  case GNE_ATTR_GENERIC:
284  undoList->add(new GNEChange_Attribute(this, key, value), true);
285  break;
286  default:
287  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
288  }
289 }
290 
291 
292 bool
293 GNECrossing::isValid(SumoXMLAttr key, const std::string& value) {
295  switch (key) {
296  case SUMO_ATTR_ID:
297  return false;
298  case SUMO_ATTR_EDGES:
299  if (canParse<std::vector<GNEEdge*> >(myNet, value, false)) {
300  // parse edges and save their IDs in a set
301  std::vector<GNEEdge*> parsedEdges = parse<std::vector<GNEEdge*> >(myNet, value);
302  EdgeVector nbEdges;
303  for (auto i : parsedEdges) {
304  nbEdges.push_back(i->getNBEdge());
305  }
306  std::sort(nbEdges.begin(), nbEdges.end());
307  //
308  EdgeVector originalEdges = crossing->edges;
309  std::sort(originalEdges.begin(), originalEdges.end());
310  // return true if we're setting the same edges
311  if (toString(nbEdges) == toString(originalEdges)) {
312  return true;
313  } else {
315  }
316  } else {
317  return false;
318  }
319  case SUMO_ATTR_WIDTH:
320  return canParse<double>(value) && ((parse<double>(value) > 0) || (parse<double>(value) == -1)); // kann NICHT 0 sein, oder -1 (bedeutet default)
321  case SUMO_ATTR_PRIORITY:
322  return canParse<bool>(value);
325  return (crossing->tlID != "" && canParse<int>(value)
326  // -1 means that tlLinkIndex2 takes on the same value as tlLinkIndex when setting idnices
327  && ((parse<double>(value) >= 0) || ((parse<double>(value) == -1) && (key == SUMO_ATTR_TLLINKINDEX2)))
328  && myParentJunction->getNBNode()->getControllingTLS().size() > 0
329  && (*myParentJunction->getNBNode()->getControllingTLS().begin())->getMaxValidIndex() >= parse<int>(value));
330  case SUMO_ATTR_CUSTOMSHAPE: {
331  // empty shapes are allowed
332  return canParse<PositionVector>(value);
333  }
334  case GNE_ATTR_SELECTED:
335  return canParse<bool>(value);
336  case GNE_ATTR_GENERIC:
337  return isGenericParametersValid(value);
338  default:
339  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
340  }
341 }
342 
343 
344 std::string
347  std::string result;
348  // Generate an string using the following structure: "key1=value1|key2=value2|...
349  for (auto i : crossing->getParametersMap()) {
350  result += i.first + "=" + i.second + "|";
351  }
352  // remove the last "|"
353  if (!result.empty()) {
354  result.pop_back();
355  }
356  return result;
357 }
358 
359 
360 std::vector<std::pair<std::string, std::string> >
363  std::vector<std::pair<std::string, std::string> > result;
364  // iterate over parameters map and fill result
365  for (auto i : crossing->getParametersMap()) {
366  result.push_back(std::make_pair(i.first, i.second));
367  }
368  return result;
369 }
370 
371 
372 void
373 GNECrossing::setGenericParametersStr(const std::string& value) {
375  // clear parameters
376  crossing->clearParameter();
377  // separate value in a vector of string using | as separator
378  std::vector<std::string> parsedValues;
379  StringTokenizer stValues(value, "|", true);
380  while (stValues.hasNext()) {
381  parsedValues.push_back(stValues.next());
382  }
383  // check that parsed values (A=B)can be parsed in generic parameters
384  for (auto i : parsedValues) {
385  std::vector<std::string> parsedParameters;
386  StringTokenizer stParam(i, "=", true);
387  while (stParam.hasNext()) {
388  parsedParameters.push_back(stParam.next());
389  }
390  // Check that parsed parameters are exactly two and contains valid chracters
391  if (parsedParameters.size() == 2 && SUMOXMLDefinitions::isValidGenericParameterKey(parsedParameters.front()) && SUMOXMLDefinitions::isValidGenericParameterValue(parsedParameters.back())) {
392  crossing->setParameter(parsedParameters.front(), parsedParameters.back());
393  }
394  }
395 }
396 
397 
398 bool
401  if (std::find(crossing->edges.begin(), crossing->edges.end(), edge->getNBEdge()) != crossing->edges.end()) {
402  return true;
403  } else {
404  return false;
405  }
406 }
407 
408 
409 bool
410 GNECrossing::checkEdgeBelong(const std::vector<GNEEdge*>& edges) const {
411  for (auto i : edges) {
412  if (checkEdgeBelong(i)) {
413  return true;
414  }
415  }
416  return false;
417 }
418 
419 // ===========================================================================
420 // private
421 // ===========================================================================
422 
423 void
424 GNECrossing::setAttribute(SumoXMLAttr key, const std::string& value) {
426  switch (key) {
427  case SUMO_ATTR_ID:
428  throw InvalidArgument("Modifying attribute '" + toString(key) + "' of " + getTagStr() + " isn't allowed");
429  case SUMO_ATTR_EDGES: {
430  // obtain GNEEdges
431  std::vector<GNEEdge*> edges = parse<std::vector<GNEEdge*> >(myNet, value);
432  // remove NBEdges of crossing
433  crossing->edges.clear();
434  // set NBEdge of every GNEEdge into Crossing Edges
435  for (auto i : edges) {
436  crossing->edges.push_back(i->getNBEdge());
437  }
438  // sort new edges
439  std::sort(crossing->edges.begin(), crossing->edges.end());
440  // change myCrossingEdges by the new edges
441  myCrossingEdges = crossing->edges;
442  // update geometry of parent junction
444  break;
445  }
446  case SUMO_ATTR_WIDTH:
447  // Change width an refresh element
448  crossing->customWidth = parse<double>(value);
449  break;
450  case SUMO_ATTR_PRIORITY:
451  crossing->priority = parse<bool>(value);
452  break;
454  crossing->customTLIndex = parse<int>(value);
455  // make new value visible immediately
456  crossing->tlLinkIndex = crossing->customTLIndex;
457  break;
459  crossing->customTLIndex2 = parse<int>(value);
460  // make new value visible immediately
461  crossing->tlLinkIndex2 = crossing->customTLIndex2;
462  break;
463  case SUMO_ATTR_CUSTOMSHAPE: {
464  // first remove object from grid
466  // set custom shape
467  crossing->customShape = parse<PositionVector>(value);
468  // insert object in grid again
470  break;
471  }
472  case GNE_ATTR_SELECTED:
473  if (parse<bool>(value)) {
475  } else {
477  }
478  break;
479  case GNE_ATTR_GENERIC:
481  break;
482  default:
483  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
484  }
485  // Crossing are a special case and we need ot update geometry of junction instead of crossing
486  if((key != SUMO_ATTR_ID) && (key != GNE_ATTR_GENERIC) && (key != GNE_ATTR_SELECTED)) {
488  }
489 }
490 
491 
492 void
494 }
495 
496 
497 /****************************************************************************/
GNECrossing(GNEJunction *parentJunction, std::vector< NBEdge *> edges)
Constructor.
Definition: GNECrossing.cpp:42
a tl-logic
void setAttribute(SumoXMLAttr key, const std::string &value, GNEUndoList *undoList)
Position getPositionInView() const
Return current position.
bool checkEdgeBelong(GNEEdge *edges) const
return true if a edge belongs to crossing&#39;s edges
double scale
information about a lane&#39;s width (temporary, used for a single view)
const std::vector< NBEdge * > & getCrossingEdges() const
get crossingEdges
Definition: GNECrossing.cpp:85
whether a given shape is user-defined
GNENet * myNet
the net to inform about updates
std::string next()
void buildNameCopyPopupEntry(GUIGLObjectPopupMenu *ret, bool addSeparator=true)
Builds entries which allow to copy the name / typed name into the clipboard.
void drawGL(const GUIVisualizationSettings &s) const
Draws the object.
Definition: GNECrossing.cpp:97
void mouseOverObject(const GUIVisualizationSettings &s) const
method for check if mouse is over objects
static void drawTextAtEnd(const std::string &text, const PositionVector &shape, double x, double size, RGBColor color)
draw text and the end of shape
Definition: GLHelper.cpp:683
edit junction shape
Definition: GUIAppEnum.h:752
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:244
Stores the information about how to visualize structures.
double y() const
Returns the y-position.
Definition: Position.h:62
double x() const
Returns the x-position.
Definition: Position.h:57
mode for editing tls
Definition: GNEViewNet.h:58
void buildCenterPopupEntry(GUIGLObjectPopupMenu *ret, bool addSeparator=true)
Builds an entry which allows to center to the object.
void setGenericParametersStr(const std::string &value)
set generic parameters in string format
Crossing * getCrossing(const std::string &id) const
return the crossing with the given id
Definition: NBNode.cpp:2948
int editMode
the current NETEDIT mode (temporary)
PositionVector reverse() const
reverse position vector
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
void buildShowParamsPopupEntry(GUIGLObjectPopupMenu *ret, bool addSeparator=true)
Builds an entry which allows to open the parameter window.
std::string getGenericParametersStr() const
return generic parameters in string format
static bool isValidGenericParameterKey(const std::string &value)
whether the given string is a valid key for a generic parameter
void buildPositionCopyEntry(GUIGLObjectPopupMenu *ret, bool addSeparator=true)
Builds an entry which allows to copy the cursor position if geo projection is used, also builds an entry for copying the geo-position.
generic attribute
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:42
link: the index of the opposite direction link of a pedestrian crossing
Boundary getCenteringBoundary() const
Returns the boundary to which the view shall be centered in order to show the object.
void updateGeometry(bool updateGrid)
update pre-computed geometry information
Definition: GNECrossing.cpp:53
static bool isValidGenericParameterValue(const std::string &value)
whether the given string is a valid value for a generic parameter
GUIGlObjectType getType() const
Returns the type of the object as coded in GUIGlObjectType.
the edges of a route
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
std::vector< double > myShapeRotations
Definition: GNECrossing.h:150
std::vector< NBEdge * > myCrossingEdges
Crossing Edges (It works as ID because a junction can only ONE Crossing with the same edges) ...
Definition: GNECrossing.h:142
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
A list of positions.
static bool isGenericParametersValid(const std::string &value)
check if given string can be parsed to a map/list of generic parameters
void removeGLObjectFromGrid(GUIGlObject *o)
add GL Object into net
Definition: GNENet.cpp:1160
friend class GNEChange_Attribute
declare friend class
void updateGeometry(bool updateGrid)
Update the boundary of the junction.
Definition: GNEJunction.cpp:91
GUIVisualizationTextSettings drawLinkTLIndex
GNEJunction * myParentJunction
the parent junction of this crossing
Definition: GNECrossing.h:139
Boundary & grow(double by)
extends the boundary by the given amount
Definition: Boundary.cpp:301
void drawTLSLinkNo(const GUIVisualizationSettings &s) const
draw TLS Link Number
EditMode
Definition: GNEViewNet.h:42
void selectAttributeCarrier(bool changeFlag=true)
select attribute carrier using GUIGlobalSelection
void unselectAttributeCarrier(bool changeFlag=true)
unselect attribute carrier using GUIGlobalSelection
EditMode getCurrentEditMode() const
get the current edit mode
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:1979
GUIGLObjectPopupMenu * getPopUpMenu(GUIMainWindow &app, GUISUMOAbstractView &parent)
Returns an own popup-menu.
A road/street connecting two junctions (netedit-version)
Definition: GNEEdge.h:50
static bool canParse(const std::string &string)
true if a value of type T can be parsed from string
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
void buildSelectionACPopupEntry(GUIGLObjectPopupMenu *ret, GNEAttributeCarrier *AC)
Builds an entry which allows to (de)select the object.
Definition: GNEViewNet.cpp:617
bool checkCrossingDuplicated(EdgeVector edges)
return true if there already exist a crossing with the same edges as the input
Definition: NBNode.cpp:2240
#define M_PI
Definition: odrSpiral.cpp:40
static void drawShapeDottedContour(const int type, const PositionVector &shape, const double width)
draw a dotted contour around the given Non closed shape with certain width
Definition: GLHelper.cpp:471
const GNEAttributeCarrier * getDottedAC() const
get AttributeCarrier under cursor
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node) ...
Definition: NBNode.h:308
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
const std::string & getTagStr() const
get tag assigned to this object in string format
element is selected
The popup menu of a globject.
std::vector< std::pair< std::string, std::string > > getGenericParameters() const
return generic parameters as vector of pairs format
crossing between edges for pedestrians
~GNECrossing()
Destructor.
Definition: GNECrossing.cpp:49
bool drawCrossingsAndWalkingareas
whether crosings and walkingareas shall be drawn
GUIGlID getGlID() const
Returns the numerical id of the object.
A definition of a pedestrian crossing.
Definition: NBNode.h:125
PositionVector myShape
crossingShape
Definition: GNECrossing.h:145
link: the index of the link within the traffic light
bool isValid(SumoXMLAttr key, const std::string &value)
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
NBNode::Crossing * getNBCrossing() const
get referente to NBode::Crossing
Definition: GNECrossing.cpp:91
std::vector< double > myShapeLengths
The lengths of the shape parts.
Definition: GNECrossing.h:153
mode for connecting lanes
Definition: GNEViewNet.h:56
mode for creating new edges
Definition: GNEViewNet.h:46
NBEdge * getNBEdge()
returns the internal NBEdge
Definition: GNEEdge.cpp:613
bool drawForSelecting
whether drawing is performed for the purpose of selecting objects
NBNode * getNBNode() const
Return net build node.
bool isAttributeCarrierSelected() const
check if attribute carrier is selected
std::string getAttribute(SumoXMLAttr key) const
void buildPopupHeader(GUIGLObjectPopupMenu *ret, GUIMainWindow &app, bool addSeparator=true)
Builds the header.
GNEViewNet * getViewNet() const
get view net
Definition: GNENet.cpp:1730
void clearParameter()
Clears the parameter map.
a junction
GNEJunction * getParentJunction() const
get parent Junction
Definition: GNECrossing.cpp:79