SUMO - Simulation of Urban MObility
GNEEdge.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 road/street connecting two junctions (netedit-version, adapted from GUIEdge)
16 // Basically a container for an NBEdge with drawing and editing capabilities
17 /****************************************************************************/
18 
19 
20 // ===========================================================================
21 // included modules
22 // ===========================================================================
23 #include <config.h>
24 
27 #include <utils/geom/bezier.h>
28 #include <utils/gui/div/GLHelper.h>
32 #include <netedit/GNENet.h>
33 #include <netedit/GNEViewNet.h>
34 #include <netedit/GNEUndoList.h>
39 
40 #include "GNEConnection.h"
41 #include "GNECrossing.h"
42 #include "GNEJunction.h"
43 #include "GNELane.h"
44 #include "GNEEdge.h"
45 
46 //#define DEBUG_SMOOTH_GEOM
47 //#define DEBUGCOND(obj) (true)
48 
49 // ===========================================================================
50 // static
51 // ===========================================================================
53 
55 
56 // ===========================================================================
57 // members methods
58 // ===========================================================================
59 
60 GNEEdge::GNEEdge(NBEdge& nbe, GNENet* net, bool wasSplit, bool loaded):
61  GNENetElement(net, nbe.getID(), GLO_EDGE, SUMO_TAG_EDGE),
62  myNBEdge(nbe) ,
63  myGNEJunctionSource(myNet->retrieveJunction(myNBEdge.getFromNode()->getID())),
64  myGNEJunctionDestiny(myNet->retrieveJunction(myNBEdge.getToNode()->getID())),
65  myLanes(0),
66  myAmResponsible(false),
67  myWasSplit(wasSplit),
68  myConnectionStatus(loaded ? FEATURE_LOADED : FEATURE_GUESSED) {
69  // Create lanes
70  int numLanes = myNBEdge.getNumLanes();
71  myLanes.reserve(numLanes);
72  for (int i = 0; i < numLanes; i++) {
73  myLanes.push_back(new GNELane(*this, i));
74  myLanes.back()->incRef("GNEEdge::GNEEdge");
75  }
76  // update Lane geometries
77  for (auto i : myLanes) {
78  i->updateGeometry(true);
79  }
80 }
81 
83  GNENetElement(nullptr, "DUMMY", GLO_EDGE, SUMO_TAG_NOTHING),
85 {
86 }
87 
89  // Delete references to this eddge in lanes
90  for (auto i : myLanes) {
91  i->decRef("GNEEdge::~GNEEdge");
92  if (i->unreferenced()) {
93  // show extra information for tests
94  WRITE_DEBUG("Deleting unreferenced " + i->getTagStr() + " '" + i->getID() + "' in GNEEdge destructor");
95  delete i;
96  }
97  }
98  // delete references to this eddge in connections
99  for (auto i : myGNEConnections) {
100  i->decRef("GNEEdge::~GNEEdge");
101  if (i->unreferenced()) {
102  // show extra information for tests
103  WRITE_DEBUG("Deleting unreferenced " + i->getTagStr() + " '" + i->getID() + "' in GNEEdge destructor");
104  delete i;
105  }
106  }
107  if (myAmResponsible) {
108  delete &myNBEdge;
109  }
110 }
111 
112 
113 void
114 GNEEdge::updateGeometry(bool updateGrid) {
115  // first check if object has to be removed from grid (SUMOTree)
116  if (updateGrid) {
118  }
119  // Update geometry of lanes
120  for (auto i : myLanes) {
121  i->updateGeometry(updateGrid);
122  }
123  // Update geometry of connections (Only if updateGrid is enabled, because in move mode connections are hidden
124  // (note: only the previous marked as deprecated will be updated)
125  if (updateGrid) {
126  for (auto i : myGNEConnections) {
127  i->updateGeometry(updateGrid);
128  }
129  }
130  // Update geometry of additionals childs vinculated to this edge
131  for (auto i : myAdditionalChilds) {
132  i->updateGeometry(updateGrid);
133  }
134  // Update geometry of additional parents that have this edge as parent
135  for (auto i : myFirstAdditionalParents) {
136  i->updateGeometry(updateGrid);
137  }
138  // last step is to check if object has to be added into grid (SUMOTree) again
139  if (updateGrid) {
140  myNet->addGLObjectIntoGrid(this);
141  }
142 }
143 
144 
145 bool
148  return (myNBEdge.getGeometry().front().distanceTo2D(pos) < SNAP_RADIUS);
149  } else {
150  return false;
151  }
152 }
153 
154 
155 bool
158  return (myNBEdge.getGeometry().back().distanceTo2D(pos) < SNAP_RADIUS);
159  } else {
160  return false;
161  }
162 }
163 
164 
165 void
166 GNEEdge::moveShapeStart(const Position& oldPos, const Position& offset) {
167  // change shape startPosition using oldPosition and offset
168  Position shapeStartEdited = oldPos;
169  shapeStartEdited.add(offset);
170  // snap to active grid
171  shapeStartEdited = myNet->getViewNet()->snapToActiveGrid(shapeStartEdited);
172  // make sure that start and end position are different
173  if (shapeStartEdited != myNBEdge.getGeometry().back()) {
174  // set shape start position without updating grid
175  setShapeStartPos(shapeStartEdited, false);
176  updateGeometry(false);
177  }
178 }
179 
180 
181 void
182 GNEEdge::moveShapeEnd(const Position& oldPos, const Position& offset) {
183  // change shape endPosition using oldPosition and offset
184  Position shapeEndEdited = oldPos;
185  shapeEndEdited.add(offset);
186  // snap to active grid
187  shapeEndEdited = myNet->getViewNet()->snapToActiveGrid(shapeEndEdited);
188  // make sure that start and end position are different
189  if (shapeEndEdited != myNBEdge.getGeometry().front()) {
190  // set shape end position without updating grid
191  setShapeEndPos(shapeEndEdited, false);
192  updateGeometry(false);
193  }
194 }
195 
196 
197 void
199  // first save current shape start position
200  Position modifiedShapeStartPos = myNBEdge.getGeometry().front();
201  // restore old shape start position
202  setShapeStartPos(oldPos, true);
203  // set attribute using undolist
204  undoList->p_begin("shape start of " + getTagStr());
205  undoList->p_add(new GNEChange_Attribute(this, GNE_ATTR_SHAPE_START, toString(modifiedShapeStartPos), true, toString(oldPos)));
206  undoList->p_end();
207 }
208 
209 
210 void
212  // first save current shape end position
213  Position modifiedShapeEndPos = myNBEdge.getGeometry().back();
214  // restore old shape end position
215  setShapeEndPos(oldPos, true);
216  // set attribute using undolist
217  undoList->p_begin("shape end of " + getTagStr());
218  undoList->p_add(new GNEChange_Attribute(this, GNE_ATTR_SHAPE_END, toString(modifiedShapeEndPos), true, toString(oldPos)));
219  undoList->p_end();
220 }
221 
222 
223 void
225  // save current centering boundary
227  // Save current centering boundary of lanes (and their childs)
228  for (auto i : myLanes) {
229  i->startGeometryMoving();
230  }
231  // Save current centering boundary of additionals childs vinculated to this edge
232  for (auto i : myAdditionalChilds) {
233  i->startGeometryMoving();
234  }
235  // Save current centering boundary of additional parents that have this edge as parent
236  for (auto i : myFirstAdditionalParents) {
237  i->startGeometryMoving();
238  }
239 }
240 
241 
242 void
244  // check that endGeometryMoving was called only once
246  // Remove object from net
248  // reset myMovingGeometryBoundary
250  // update geometry without updating grid
251  updateGeometry(false);
252  // Restore centering boundary of lanes (and their childs)
253  for (auto i : myLanes) {
254  i->endGeometryMoving();
255  }
256  // Restore centering boundary of additionals childs vinculated to this edge
257  for (auto i : myAdditionalChilds) {
258  i->endGeometryMoving();
259  }
260  // Restore centering boundary of additional parents that have this edge as parent
261  for (auto i : myFirstAdditionalParents) {
262  i->endGeometryMoving();
263  }
264  // add object into grid again (using the new centering boundary)
265  myNet->addGLObjectIntoGrid(this);
266  }
267 }
268 
269 
270 int
271 GNEEdge::getVertexIndex(Position pos, bool createIfNoExist, bool snapToGrid) {
272  PositionVector entireGeometry = myNBEdge.getGeometry();
273  // check if position has to be snapped to grid
274  if (snapToGrid) {
275  pos = myNet->getViewNet()->snapToActiveGrid(pos);
276  }
277  double offset = entireGeometry.nearest_offset_to_point2D(pos, true);
278  if (offset == GeomHelper::INVALID_OFFSET) {
279  return -1;
280  }
281  Position newPos = entireGeometry.positionAtOffset2D(offset);
282  // first check if vertex already exists in the inner geometry
283  for (int i = 0; i < (int)entireGeometry.size(); i++) {
284  if (entireGeometry[i].distanceTo2D(newPos) < SNAP_RADIUS) {
285  if (i == 0 || i == (int)(entireGeometry.size() - 1)) {
286  return -1;
287  }
288  // index refers to inner geometry
289  return i - 1;
290  }
291  }
292  // if vertex doesn't exist, insert it
293  if (createIfNoExist) {
294  // check if position has to be snapped to grid
295  if (snapToGrid) {
296  newPos = myNet->getViewNet()->snapToActiveGrid(newPos);
297  }
298  int index = entireGeometry.insertAtClosest(myNet->getViewNet()->snapToActiveGrid(newPos));
299  setGeometry(entireGeometry, false, true);
300  // index refers to inner geometry
301  return (index - 1);
302  } else {
303  return -1;
304  }
305 }
306 
307 
308 int
309 GNEEdge::getVertexIndex(const double offset, bool createIfNoExist, bool snapToGrid) {
310  return getVertexIndex(myNBEdge.getGeometry().positionAtOffset2D(offset), createIfNoExist, snapToGrid);
311 }
312 
313 
314 int
315 GNEEdge::moveVertexShape(const int index, const Position& oldPos, const Position& offset) {
316  // obtain inner geometry of edge
317  PositionVector edgeGeometry = myNBEdge.getInnerGeometry();
318  // Make sure that index is valid AND ins't the first and last index
319  if (index != -1) {
320  // check that index is correct before change position
321  if (index < (int)edgeGeometry.size()) {
322  // change position of vertex
323  edgeGeometry[index] = oldPos;
324  edgeGeometry[index].add(offset);
325  // filtern position using snap to active grid
326  edgeGeometry[index] = myNet->getViewNet()->snapToActiveGrid(edgeGeometry[index]);
327  // update edge's geometry without updating RTree (To avoid unnecesary changes in RTree)
328  setGeometry(edgeGeometry, true, false);
329  return index;
330  } else {
331  throw InvalidArgument("Index greater than shape size");
332  }
333  } else {
334  return index;
335  }
336 }
337 
338 
339 void
340 GNEEdge::moveEntireShape(const PositionVector& oldShape, const Position& offset) {
341  // make a copy of the old shape to change it
342  PositionVector modifiedShape = oldShape;
343  // change all points of the inner geometry using offset
344  for (auto& i : modifiedShape) {
345  i.add(offset);
346  }
347  // restore modified shape
348  setGeometry(modifiedShape, true, false);
349 }
350 
351 
352 void
354  // restore original shape into shapeToCommit
355  PositionVector innerShapeToCommit = myNBEdge.getInnerGeometry();
356  // first check if second and penultimate isn't in Junction's buubles
358  if (myNBEdge.getGeometry().size() > 2 && myNBEdge.getGeometry()[0].distanceTo(myNBEdge.getGeometry()[1]) < buubleRadius) {
359  innerShapeToCommit.removeClosest(innerShapeToCommit[0]);
360  }
361  if (myNBEdge.getGeometry().size() > 2 && myNBEdge.getGeometry()[(int)myNBEdge.getGeometry().size() - 2].distanceTo(myNBEdge.getGeometry()[(int)myNBEdge.getGeometry().size() - 1]) < buubleRadius) {
362  innerShapeToCommit.removeClosest(innerShapeToCommit[(int)innerShapeToCommit.size() - 1]);
363  }
364  // second check if double points has to be removed
365  innerShapeToCommit.removeDoublePoints(SNAP_RADIUS);
366  // show warning if some of edge's shape was merged
367  if (innerShapeToCommit.size() != myNBEdge.getInnerGeometry().size()) {
368  WRITE_WARNING("Merged shape's point")
369  }
370  // finish geometry moving
372  updateGeometry(false);
373  // restore old geometry to allow change attribute (And restore shape if during movement a new point was created
374  setGeometry(oldShape, true, true);
375  // commit new shape
376  undoList->p_begin("moving " + toString(SUMO_ATTR_SHAPE) + " of " + getTagStr());
377  undoList->p_add(new GNEChange_Attribute(this, SUMO_ATTR_SHAPE, toString(innerShapeToCommit)));
378  undoList->p_end();
379 }
380 
381 
382 void
383 GNEEdge::deleteGeometryPoint(const Position& pos, bool allowUndo) {
384  // obtain index and remove point
385  PositionVector modifiedShape = myNBEdge.getInnerGeometry();
386  int index = modifiedShape.indexOfClosest(pos);
387  modifiedShape.erase(modifiedShape.begin() + index);
388  // set new shape depending of allowUndo
389  if (allowUndo) {
390  myNet->getViewNet()->getUndoList()->p_begin("delete geometry point");
393  } else {
394  // set new shape
395  setGeometry(modifiedShape, true, true);
396  }
397 }
398 
399 
400 void
401 GNEEdge::updateJunctionPosition(GNEJunction* junction, const Position& origPos, bool updateGrid) {
402  Position delta = junction->getNBNode()->getPosition() - origPos;
404  // geometry endpoint need not equal junction position hence we modify it with delta
405  if (junction == myGNEJunctionSource) {
406  geom[0].add(delta);
407  } else {
408  geom[-1].add(delta);
409  }
410  setGeometry(geom, false, updateGrid);
411 }
412 
413 
414 Boundary
416  Boundary ret;
417  for (auto i : myLanes) {
418  ret.add(i->getBoundary());
419  }
420  // ensure that geometry points are selectable even if the lane geometry is strange
421  for (const Position& pos : myNBEdge.getGeometry()) {
422  ret.add(pos);
423  }
424  ret.grow(10); // !!! magic value
425  return ret;
426 }
427 
428 
429 Boundary
431  // Return Boundary depending if myMovingGeometryBoundary is initialised (important for move geometry)
434  } else {
435  Boundary b = getBoundary();
436  b.grow(20);
437  return b;
438  }
439 }
440 
441 
444  GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, *this);
445  buildPopupHeader(ret, app);
448  // build selection and show parameters menu
451  // build position copy entry
452  buildPositionCopyEntry(ret, false);
453  return ret;
454 }
455 
456 
459  return myGNEJunctionSource;
460 }
461 
462 
465  return myGNEJunctionDestiny;
466 }
467 
468 
469 GNEEdge*
472 }
473 
474 
475 void
477  /* do something different for connectors?
478  if (myNBEdge.isMacroscopicConnector()) {
479  }
480  */
481  // obtain circle width
482  double circleWidth = SNAP_RADIUS * MIN2((double)1, s.laneWidthExaggeration);
483  double circleWidthSquared = circleWidth * circleWidth;
484  int circleResolution = GNEAttributeCarrier::getCircleResolution(s);
485  // draw the lanes
486  for (auto i : myLanes) {
487  i->drawGL(s);
488  }
489  // draw geometry points if isnt's too small
490  if (s.scale > 8.0) {
491  GLHelper::setColor(s.junctionColorer.getSchemes()[0].getColor(2));
493  // override with special colors (unless the color scheme is based on selection)
495  }
496  // recognize full transparency and simply don't draw
497  GLfloat color[4];
498  glGetFloatv(GL_CURRENT_COLOR, color);
499  if (color[3] > 0) {
500  // push name
501  glPushName(getGlID());
502  // draw geometry points expect initial and final
503  for (int i = 1; i < (int)myNBEdge.getGeometry().size() - 1; i++) {
504  Position pos = myNBEdge.getGeometry()[i];
505  if (!s.drawForSelecting || (myNet->getViewNet()->getPositionInformation().distanceSquaredTo2D(pos) <= (circleWidthSquared + 2))) {
506  glPushMatrix();
507  glTranslated(pos.x(), pos.y(), GLO_JUNCTION - 0.01);
508  // resolution of drawn circle depending of the zoom (To improve smothness)
509  GLHelper::drawFilledCircle(circleWidth, circleResolution);
510  glPopMatrix();
511  // draw elevation or special symbols (Start, End and Block)
513  glPushMatrix();
514  // Translate to geometry point
515  glTranslated(pos.x(), pos.y(), GLO_JUNCTION);
516  // draw Z value
518  glPopMatrix();
519  }
520  }
521  }
522  // draw line geometry, start and end points if shapeStart or shape end is edited, and depending of drawForSelecting
525  (!s.drawForSelecting || (myNet->getViewNet()->getPositionInformation().distanceSquaredTo2D(myNBEdge.getGeometry().front()) <= (circleWidthSquared + 2)))) {
526  glPushMatrix();
527  glTranslated(myNBEdge.getGeometry().front().x(), myNBEdge.getGeometry().front().y(), GLO_JUNCTION + 0.01);
528  // resolution of drawn circle depending of the zoom (To improve smothness)
529  GLHelper::drawFilledCircle(circleWidth, circleResolution);
530  glPopMatrix();
531  // draw a "s" over last point depending of drawForSelecting
532  if (!s.drawForSelecting) {
533  glPushMatrix();
534  glTranslated(myNBEdge.getGeometry().front().x(), myNBEdge.getGeometry().front().y(), GLO_JUNCTION + 0.02);
535  GLHelper::drawText("S", Position(), 0, circleWidth, RGBColor::WHITE);
536  glPopMatrix();
537  // draw line between Junction and point
538  glPushMatrix();
539  glTranslated(0, 0, GLO_JUNCTION - 0.01);
540  glLineWidth(4);
542  // draw line between begin point of last lane shape and the first edge shape point
543  GLHelper::drawLine(myNBEdge.getGeometry().front(), myNBEdge.getLanes().back().shape.front());
544  glPopMatrix();
545  }
546  }
548  (!s.drawForSelecting || (myNet->getViewNet()->getPositionInformation().distanceSquaredTo2D(myNBEdge.getGeometry().back()) <= (circleWidthSquared + 2)))) {
549  glPushMatrix();
550  glTranslated(myNBEdge.getGeometry().back().x(), myNBEdge.getGeometry().back().y(), GLO_JUNCTION + 0.01);
551  // resolution of drawn circle depending of the zoom (To improve smothness)
552  GLHelper::drawFilledCircle(circleWidth, circleResolution);
553  glPopMatrix();
554  // draw a "e" over last point depending of drawForSelecting
555  if (!s.drawForSelecting) {
556  glPushMatrix();
557  glTranslated(myNBEdge.getGeometry().back().x(), myNBEdge.getGeometry().back().y(), GLO_JUNCTION + 0.02);
558  GLHelper::drawText("E", Position(), 0, circleWidth, RGBColor::WHITE);
559  glPopMatrix();
560  // draw line between Junction and point
561  glPushMatrix();
562  glTranslated(0, 0, GLO_JUNCTION - 0.01);
563  glLineWidth(4);
565  // draw line between last point of first lane shape and the last edge shape point
566  GLHelper::drawLine(myNBEdge.getGeometry().back(), myNBEdge.getLanes().back().shape.back());
567  glPopMatrix();
568  }
569  }
570  }
571  // pop name
572  glPopName();
573  }
574  }
575 
576  // (optionally) draw the name and/or the street name if isn't being drawn for selecting
577  const bool drawStreetName = s.streetName.show && (myNBEdge.getStreetName() != "");
578  if (!s.drawForSelecting && (s.edgeName.show || drawStreetName || s.edgeValue.show)) {
579  glPushName(getGlID());
580  GNELane* lane1 = myLanes[0];
581  GNELane* lane2 = myLanes[myLanes.size() - 1];
582  Position p = lane1->getShape().positionAtOffset(lane1->getShape().length() / (double) 2.);
583  p.add(lane2->getShape().positionAtOffset(lane2->getShape().length() / (double) 2.));
584  p.mul(.5);
585  double angle = lane1->getShape().rotationDegreeAtOffset(lane1->getShape().length() / (double) 2.);
586  angle += 90;
587  if (angle > 90 && angle < 270) {
588  angle -= 180;
589  }
590  if (s.edgeName.show) {
591  drawName(p, s.scale, s.edgeName, angle);
592  }
593  if (drawStreetName) {
595  }
596  if (s.edgeValue.show) {
597  double value = lane2->getColorValue(s, s.laneColorer.getActive());
598  GLHelper::drawTextSettings(s.edgeValue, toString(value), p, s.scale, angle);
599  }
600  glPopName();
601  }
602  if (!s.drawForSelecting && (myNet->getViewNet()->getDottedAC() == this)) {
603  // draw dotted contor around the first and last lane
604  const double myHalfLaneWidthFront = myNBEdge.getLaneWidth(myLanes.front()->getIndex()) / 2;
605  const double myHalfLaneWidthBack = myNBEdge.getLaneWidth(myLanes.back()->getIndex()) / 2;
606  GLHelper::drawShapeDottedContour(GLO_JUNCTION, myLanes.front()->getShape(), myHalfLaneWidthFront, myLanes.back()->getShape(), -1 * myHalfLaneWidthBack);
607  }
608  glPopMatrix();
609 }
610 
611 
612 NBEdge*
614  return &myNBEdge;
615 }
616 
617 
618 Position
619 GNEEdge::getSplitPos(const Position& clickPos) {
620  const PositionVector& geom = myNBEdge.getGeometry();
621  int index = geom.indexOfClosest(clickPos);
622  if (geom[index].distanceTo(clickPos) < SNAP_RADIUS) {
623  // split at existing geometry point
624  return geom[index];
625  } else {
626  // split straight between the next two points
627  return geom.positionAtOffset(geom.nearest_offset_to_point2D(clickPos));
628  }
629 }
630 
631 
632 void
634  if ((myNBEdge.getGeometry().front() != myGNEJunctionSource->getPositionInView()) && (myNBEdge.getGeometry().front().distanceTo(pos) < SNAP_RADIUS)) {
635  undoList->p_begin("remove endpoint");
636  setAttribute(GNE_ATTR_SHAPE_START, "", undoList);
637  undoList->p_end();
638  } else if ((myNBEdge.getGeometry().back() != myGNEJunctionDestiny->getPositionInView()) && (myNBEdge.getGeometry().back().distanceTo(pos) < SNAP_RADIUS)) {
639  undoList->p_begin("remove endpoint");
640  setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
641  undoList->p_end();
642  } else {
643  // we need to create new Start/End position over Edge shape, not over clicked position
645  if (offset != GeomHelper::INVALID_OFFSET) {
647  // calculate position over edge shape relative to clicked positino
648  Position newPos = geom.positionAtOffset2D(offset);
649  // snap new position to grid
650  newPos = myNet->getViewNet()->snapToActiveGrid(newPos);
651  undoList->p_begin("set endpoint");
652  int index = geom.indexOfClosest(pos);
653  // check if snap to existing geometry
654  if (geom[index].distanceTo(pos) < SNAP_RADIUS) {
655  pos = geom[index];
656  }
659  if (pos.distanceTo2D(destPos) < pos.distanceTo2D(sourcePos)) {
660  setAttribute(GNE_ATTR_SHAPE_END, toString(newPos), undoList);
662  } else {
663  setAttribute(GNE_ATTR_SHAPE_START, toString(newPos), undoList);
665  }
666  // possibly existing inner point is no longer needed
667  if (myNBEdge.getInnerGeometry().size() > 0 && getVertexIndex(pos, false, false) != -1) {
668  deleteGeometryPoint(pos, false);
669  }
670  undoList->p_end();
671  }
672  }
673 }
674 
675 
676 void
680  if (pos.distanceTo2D(destPos) < pos.distanceTo2D(sourcePos)) {
681  setAttribute(GNE_ATTR_SHAPE_END, toString(destPos), undoList);
683  } else {
684  setAttribute(GNE_ATTR_SHAPE_START, toString(sourcePos), undoList);
686  }
687 }
688 
689 
690 void
691 GNEEdge::setGeometry(PositionVector geom, bool inner, bool updateGrid) {
692  if (updateGrid) {
693  // first remove object from net grid
695  }
696  // set new geometry
697  myNBEdge.setGeometry(geom, inner);
698  if (updateGrid) {
699  // add object into net again
700  myNet->addGLObjectIntoGrid(this);
701  }
702  updateGeometry(updateGrid);
705 }
706 
707 
708 void
710  // create new and removed unused GNEConnectinos
711  const std::vector<NBEdge::Connection>& connections = myNBEdge.getConnections();
712  // create a vector to keep retrieved and created connections
713  std::vector<GNEConnection*> retrievedConnections;
714  // iterate over NBEdge::Connections of GNEEdge
715  for (auto it : connections) {
716  // retrieve existent GNEConnection, or create it
717  GNEConnection* retrievedGNEConnection = retrieveGNEConnection(it.fromLane, it.toEdge, it.toLane);
718  retrievedGNEConnection->updateLinkState();
719  retrievedConnections.push_back(retrievedGNEConnection);
720  // check if previously this GNEConnections exists, and if true, remove it from myGNEConnections
721  std::vector<GNEConnection*>::iterator retrievedExists = std::find(myGNEConnections.begin(), myGNEConnections.end(), retrievedGNEConnection);
722  if (retrievedExists != myGNEConnections.end()) {
723  myGNEConnections.erase(retrievedExists);
724  } else {
725  // include reference to created GNEConnection
726  retrievedGNEConnection->incRef("GNEEdge::remakeGNEConnections");
727  }
728  // mark it as deprecated
729  retrievedGNEConnection->markConnectionGeometryDeprecated();
730  }
731  // delete non retrieved GNEConnections
732  for (auto it : myGNEConnections) {
733  // remove it from Tree
735  it->decRef();
736  if (it->unreferenced()) {
737  // show extra information for tests
738  WRITE_DEBUG("Deleting unreferenced " + it->getTagStr() + " '" + it->getID() + "' in rebuildGNEConnections()");
739  delete it;
740  }
741  }
742  // copy retrieved (existent and created) GNECrossigns to myGNEConnections
743  myGNEConnections = retrievedConnections;
744 }
745 
746 
747 void
749  // Drop all existents connections that aren't referenced anymore
750  for (auto i : myGNEConnections) {
751  // check if connection is selected
752  if (i->isAttributeCarrierSelected()) {
753  i->unselectAttributeCarrier();
754  }
755  // remove it from Tree
757  // Dec reference of connection
758  i->decRef("GNEEdge::clearGNEConnections");
759  // Delete GNEConnectionToErase if is unreferenced
760  if (i->unreferenced()) {
761  // show extra information for tests
762  WRITE_DEBUG("Deleting unreferenced " + i->getTagStr() + " '" + i->getID() + "' in clearGNEConnections()");
763  delete i;
764  }
765  }
766  myGNEConnections.clear();
767 }
768 
769 
770 int
772  std::vector<GNEAdditional*> routeProbes;
773  for (auto i : myAdditionalChilds) {
774  if (i->getTagProperty().getTag() == routeProbe->getTagProperty().getTag()) {
775  routeProbes.push_back(i);
776  }
777  }
778  // return index of routeProbe in routeProbes vector
779  auto it = std::find(routeProbes.begin(), routeProbes.end(), routeProbe);
780  if (it == routeProbes.end()) {
781  return -1;
782  } else {
783  return (int)(it - routeProbes.begin());
784  }
785 }
786 
787 
788 std::vector<GNECrossing*>
790  std::vector<GNECrossing*> crossings;
791  for (auto i : myGNEJunctionSource->getGNECrossings()) {
792  if (i->checkEdgeBelong(this)) {
793  crossings.push_back(i);
794  }
795  }
796  for (auto i : myGNEJunctionDestiny->getGNECrossings()) {
797  if (i->checkEdgeBelong(this)) {
798  crossings.push_back(i);
799  }
800  }
801  return crossings;
802 }
803 
804 
805 void
807  // iterate over all additional parents of edge
808  while (myFirstAdditionalParents.size() > 0) {
809  // Obtain attribute Edge or Edges of additional
810  std::vector<std::string> edgeIDs;
811  if(myFirstAdditionalParents.front()->getTagProperty().hasAttribute(SUMO_ATTR_EDGES)) {
812  edgeIDs = parse<std::vector<std::string> >(myFirstAdditionalParents.front()->getAttribute(SUMO_ATTR_EDGES));
813  } else {
814  edgeIDs.push_back(myFirstAdditionalParents.front()->getAttribute(SUMO_ATTR_EDGE));
815  }
816  // check that at least there is an Edge
817  if (edgeIDs.empty()) {
818  throw ProcessError("Additional edge childs is empty");
819  } else if (edgeIDs.size() == 1) {
820  // remove entire Additional if SUMO_ATTR_EDGES cannot be empty
821  if (edgeIDs.front() == getID()) {
822  undoList->add(new GNEChange_Additional(myFirstAdditionalParents.front(), false), true);
823  } else {
824  throw ProcessError("Edge ID wasnt' found in Additional");
825  }
826  } else {
827  auto it = std::find(edgeIDs.begin(), edgeIDs.end(), getID());
828  if (it != edgeIDs.end()) {
829  // set new attribute in Additional
830  edgeIDs.erase(it);
831  myFirstAdditionalParents.front()->setAttribute(SUMO_ATTR_EDGES, toString(edgeIDs), undoList);
832  } else {
833  throw ProcessError("Edge ID wasnt' found in Additional");
834  }
835  }
836  }
837 }
838 
839 
840 void
842  undoList->p_begin("copy template");
850  // copy lane attributes as well
851  for (int i = 0; i < (int)myLanes.size(); i++) {
852  myLanes[i]->setAttribute(SUMO_ATTR_ALLOW, tpl->myLanes[i]->getAttribute(SUMO_ATTR_ALLOW), undoList);
853  myLanes[i]->setAttribute(SUMO_ATTR_DISALLOW, tpl->myLanes[i]->getAttribute(SUMO_ATTR_DISALLOW), undoList);
854  myLanes[i]->setAttribute(SUMO_ATTR_SPEED, tpl->myLanes[i]->getAttribute(SUMO_ATTR_SPEED), undoList);
855  myLanes[i]->setAttribute(SUMO_ATTR_WIDTH, tpl->myLanes[i]->getAttribute(SUMO_ATTR_WIDTH), undoList);
856  myLanes[i]->setAttribute(SUMO_ATTR_ENDOFFSET, tpl->myLanes[i]->getAttribute(SUMO_ATTR_ENDOFFSET), undoList);
857  }
858  undoList->p_end();
859 }
860 
861 
862 std::set<GUIGlID>
864  std::set<GUIGlID> result;
865  for (auto i : myLanes) {
866  result.insert(i->getGlID());
867  }
868  return result;
869 }
870 
871 
872 const std::vector<GNELane*>&
874  return myLanes;
875 }
876 
877 
878 const std::vector<GNEConnection*>&
880  return myGNEConnections;
881 }
882 
883 
884 bool
886  return myWasSplit;
887 }
888 
889 
890 std::string
892  switch (key) {
893  case SUMO_ATTR_ID:
894  return getMicrosimID();
895  case SUMO_ATTR_FROM:
897  case SUMO_ATTR_TO:
899  case SUMO_ATTR_NUMLANES:
900  return toString(myNBEdge.getNumLanes());
901  case SUMO_ATTR_PRIORITY:
902  return toString(myNBEdge.getPriority());
903  case SUMO_ATTR_LENGTH:
904  return toString(myNBEdge.getFinalLength());
905  case SUMO_ATTR_TYPE:
906  return myNBEdge.getTypeID();
907  case SUMO_ATTR_SHAPE:
911  case SUMO_ATTR_NAME:
912  return myNBEdge.getStreetName();
913  case SUMO_ATTR_ALLOW:
914  return (getVehicleClassNames(myNBEdge.getPermissions()) + (myNBEdge.hasLaneSpecificPermissions() ? " (combined!)" : ""));
915  case SUMO_ATTR_DISALLOW: {
917  }
918  case SUMO_ATTR_SPEED:
920  return "lane specific";
921  } else {
922  return toString(myNBEdge.getSpeed());
923  }
924  case SUMO_ATTR_WIDTH:
926  return "lane specific";
927  } else {
928  return toString(myNBEdge.getLaneWidth());
929  }
930  case SUMO_ATTR_ENDOFFSET:
932  return "lane specific";
933  } else {
934  return toString(myNBEdge.getEndOffset());
935  }
937  return myConnectionStatus;
940  return "";
941  } else {
942  return toString(myNBEdge.getGeometry().front());
943  }
944  case GNE_ATTR_SHAPE_END:
946  return "";
947  } else {
948  return toString(myNBEdge.getGeometry().back());
949  }
950  case GNE_ATTR_BIDIR:
951  return toString(myNBEdge.isBidiRail());
952  case GNE_ATTR_SELECTED:
954  case GNE_ATTR_GENERIC:
955  return getGenericParametersStr();
956  default:
957  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
958  }
959 }
960 
961 std::string
963  std::string result = getAttribute(key);
964  if ((key == SUMO_ATTR_ALLOW || key == SUMO_ATTR_DISALLOW) && result.find("all") != std::string::npos) {
965  result += " " + getVehicleClassNames(SVCAll, true);
966  }
967  return result;
968 }
969 
970 void
971 GNEEdge::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
972  switch (key) {
973  case SUMO_ATTR_WIDTH:
974  case SUMO_ATTR_ENDOFFSET:
975  case SUMO_ATTR_SPEED:
976  case SUMO_ATTR_ALLOW:
977  case SUMO_ATTR_DISALLOW: {
978  undoList->p_begin("change " + getTagStr() + " attribute");
979  const std::string origValue = myLanes.at(0)->getAttribute(key); // will have intermediate value of "lane specific"
980  // lane specific attributes need to be changed via lanes to allow undo
981  for (auto it : myLanes) {
982  it->setAttribute(key, value, undoList);
983  }
984  // ensure that the edge value is also changed. Actually this sets the lane attributes again but it does not matter
985  undoList->p_add(new GNEChange_Attribute(this, key, value, true, origValue));
986  undoList->p_end();
987  break;
988  }
989  case SUMO_ATTR_FROM: {
990  undoList->p_begin("change " + getTagStr() + " attribute");
991  // Remove edge from crossings of junction source
993  // continue changing from junction
994  GNEJunction* oldGNEJunctionSource = myGNEJunctionSource;
995  myGNEJunctionSource->setLogicValid(false, undoList);
996  undoList->p_add(new GNEChange_Attribute(this, key, value));
997  myGNEJunctionSource->setLogicValid(false, undoList);
998  myNet->retrieveJunction(value)->setLogicValid(false, undoList);
1001  undoList->p_end();
1002  // update geometries of all implicated junctions
1003  oldGNEJunctionSource->updateGeometry(true);
1006  break;
1007  }
1008  case SUMO_ATTR_TO: {
1009  undoList->p_begin("change " + getTagStr() + " attribute");
1010  // Remove edge from crossings of junction destiny
1012  // continue changing destiny junction
1013  GNEJunction* oldGNEJunctionDestiny = myGNEJunctionDestiny;
1014  myGNEJunctionDestiny->setLogicValid(false, undoList);
1015  undoList->p_add(new GNEChange_Attribute(this, key, value));
1016  myGNEJunctionDestiny->setLogicValid(false, undoList);
1017  myNet->retrieveJunction(value)->setLogicValid(false, undoList);
1020  undoList->p_end();
1021  // update geometries of all implicated junctions
1022  oldGNEJunctionDestiny->updateGeometry(true);
1025  break;
1026  }
1027  case SUMO_ATTR_ID:
1028  case SUMO_ATTR_PRIORITY:
1029  case SUMO_ATTR_LENGTH:
1030  case SUMO_ATTR_TYPE:
1031  case SUMO_ATTR_SPREADTYPE:
1033  case GNE_ATTR_SHAPE_START:
1034  case GNE_ATTR_SHAPE_END:
1035  case GNE_ATTR_SELECTED:
1036  case GNE_ATTR_GENERIC:
1037  undoList->p_add(new GNEChange_Attribute(this, key, value));
1038  break;
1039  case SUMO_ATTR_NAME:
1040  // user cares about street names. Make sure they appear in the output
1042  OptionsCont::getOptions().set("output.street-names", "true");
1043  undoList->p_add(new GNEChange_Attribute(this, key, value));
1044  break;
1045  case SUMO_ATTR_NUMLANES:
1046  if (value != getAttribute(key)) {
1047  // Remove edge from crossings of junction source
1049  // Remove edge from crossings of junction destiny
1051  // set num lanes
1052  setNumLanes(parse<int>(value), undoList);
1053  }
1054  break;
1055  case SUMO_ATTR_SHAPE:
1056  // @note: assumes value of inner geometry!
1057  // actually the geometry is already updated (incrementally
1058  // during mouse movement). We set the restore point to the end
1059  // of the last change-set
1060  undoList->p_add(new GNEChange_Attribute(this, key, value));
1061  break;
1062  case GNE_ATTR_BIDIR:
1063  throw InvalidArgument("Attribute of '" + toString(key) + "' cannot be modified");
1064  default:
1065  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
1066  }
1067 }
1068 
1069 
1070 bool
1071 GNEEdge::isValid(SumoXMLAttr key, const std::string& value) {
1072  switch (key) {
1073  case SUMO_ATTR_ID:
1074  return SUMOXMLDefinitions::isValidNetID(value) && (myNet->retrieveEdge(value, false) == nullptr);
1075  case SUMO_ATTR_FROM: {
1076  // check that is a valid ID and is different of ID of junction destiny
1078  GNEJunction* junctionFrom = myNet->retrieveJunction(value, false);
1079  // check that there isn't already another edge with the same From and To Edge
1080  if ((junctionFrom != nullptr) && (myNet->retrieveEdge(junctionFrom, myGNEJunctionDestiny, false) == nullptr)) {
1081  return true;
1082  } else {
1083  return false;
1084  }
1085  } else {
1086  return false;
1087  }
1088  }
1089  case SUMO_ATTR_TO: {
1090  // check that is a valid ID and is different of ID of junction Source
1092  GNEJunction* junctionTo = myNet->retrieveJunction(value, false);
1093  // check that there isn't already another edge with the same From and To Edge
1094  if ((junctionTo != nullptr) && (myNet->retrieveEdge(myGNEJunctionSource, junctionTo, false) == nullptr)) {
1095  return true;
1096  } else {
1097  return false;
1098  }
1099  } else {
1100  return false;
1101  }
1102  }
1103  case SUMO_ATTR_SPEED:
1104  return canParse<double>(value) && (parse<double>(value) > 0);
1105  case SUMO_ATTR_NUMLANES:
1106  return canParse<int>(value) && (parse<double>(value) > 0);
1107  case SUMO_ATTR_PRIORITY:
1108  return canParse<int>(value);
1109  case SUMO_ATTR_LENGTH:
1110  return canParse<double>(value) && ((parse<double>(value) > 0) || (parse<double>(value) == NBEdge::UNSPECIFIED_LOADED_LENGTH));
1111  case SUMO_ATTR_ALLOW:
1112  case SUMO_ATTR_DISALLOW:
1113  return canParseVehicleClasses(value);
1114  case SUMO_ATTR_TYPE:
1115  return true;
1116  case SUMO_ATTR_SHAPE:
1117  // empty shapes are allowed
1118  return canParse<PositionVector>(value);
1119  case SUMO_ATTR_SPREADTYPE:
1121  case SUMO_ATTR_NAME:
1122  return true;
1123  case SUMO_ATTR_WIDTH:
1124  return canParse<double>(value) && ((parse<double>(value) > 0) || (parse<double>(value) == NBEdge::UNSPECIFIED_WIDTH));
1125  case SUMO_ATTR_ENDOFFSET:
1126  return canParse<double>(value) && (parse<double>(value) >= 0);
1127  case GNE_ATTR_SHAPE_START: {
1128  if (value.empty()) {
1129  return true;
1130  } else if(canParse<Position>(value)) {
1131  Position shapeStart = parse<Position>(value);
1132  return (shapeStart != myNBEdge.getGeometry()[-1]);
1133  } else {
1134  return false;
1135  }
1136  }
1137  case GNE_ATTR_SHAPE_END: {
1138  if (value.empty()) {
1139  return true;
1140  } else if(canParse<Position>(value)) {
1141  Position shapeEnd = parse<Position>(value);
1142  return (shapeEnd != myNBEdge.getGeometry()[0]);
1143  } else {
1144  return false;
1145  }
1146  }
1147  case GNE_ATTR_BIDIR:
1148  return false;
1149  case GNE_ATTR_SELECTED:
1150  return canParse<bool>(value);
1151  case GNE_ATTR_GENERIC:
1152  return isGenericParametersValid(value);
1153  default:
1154  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
1155  }
1156 }
1157 
1158 
1159 std::string
1161  std::string result;
1162  // Generate an string using the following structure: "key1=value1|key2=value2|...
1163  for (auto i : myNBEdge.getParametersMap()) {
1164  result += i.first + "=" + i.second + "|";
1165  }
1166  // remove the last "|"
1167  if (!result.empty()) {
1168  result.pop_back();
1169  }
1170  return result;
1171 }
1172 
1173 
1174 std::vector<std::pair<std::string, std::string> >
1176  std::vector<std::pair<std::string, std::string> > result;
1177  // iterate over parameters map and fill result
1178  for (auto i : myNBEdge.getParametersMap()) {
1179  result.push_back(std::make_pair(i.first, i.second));
1180  }
1181  return result;
1182 }
1183 
1184 
1185 void
1186 GNEEdge::setGenericParametersStr(const std::string& value) {
1187  // clear parameters
1189  // separate value in a vector of string using | as separator
1190  std::vector<std::string> parsedValues;
1191  StringTokenizer stValues(value, "|", true);
1192  while (stValues.hasNext()) {
1193  parsedValues.push_back(stValues.next());
1194  }
1195  // check that parsed values (A=B)can be parsed in generic parameters
1196  for (auto i : parsedValues) {
1197  std::vector<std::string> parsedParameters;
1198  StringTokenizer stParam(i, "=", true);
1199  while (stParam.hasNext()) {
1200  parsedParameters.push_back(stParam.next());
1201  }
1202  // Check that parsed parameters are exactly two and contains valid chracters
1203  if (parsedParameters.size() == 2 && SUMOXMLDefinitions::isValidGenericParameterKey(parsedParameters.front()) && SUMOXMLDefinitions::isValidGenericParameterValue(parsedParameters.back())) {
1204  myNBEdge.setParameter(parsedParameters.front(), parsedParameters.back());
1205  }
1206  }
1207 }
1208 
1209 
1210 void
1212  myAmResponsible = newVal;
1213 }
1214 
1215 // ===========================================================================
1216 // private
1217 // ===========================================================================
1218 
1219 void
1220 GNEEdge::setAttribute(SumoXMLAttr key, const std::string& value) {
1221  switch (key) {
1222  case SUMO_ATTR_ID:
1223  myNet->renameEdge(this, value);
1224  break;
1225  case SUMO_ATTR_FROM:
1227  // update this edge of list of outgoings edges of the old GNEJunctionSource
1229  // update GNEJunctionSource
1231  // update this edge of list of outgoings edges of the new GNEJunctionSource
1233  break;
1234  case SUMO_ATTR_TO:
1236  // update this edge of list of incomings edges of the old GNEJunctionDestiny
1238  // update GNEJunctionDestiny
1240  // update this edge of list of incomings edges of the new GNEJunctionDestiny
1242  break;
1243  case SUMO_ATTR_NUMLANES:
1244  throw InvalidArgument("GNEEdge::setAttribute (private) called for attr SUMO_ATTR_NUMLANES. This should never happen");
1245  break;
1246  case SUMO_ATTR_PRIORITY:
1247  myNBEdge.myPriority = parse<int>(value);
1248  break;
1249  case SUMO_ATTR_LENGTH:
1250  myNBEdge.setLoadedLength(parse<double>(value));
1251  break;
1252  case SUMO_ATTR_TYPE:
1253  myNBEdge.myType = value;
1254  break;
1255  case SUMO_ATTR_SHAPE:
1256  setGeometry(parse<PositionVector>(value), true, true);
1257  break;
1258  case SUMO_ATTR_SPREADTYPE:
1260  break;
1261  case SUMO_ATTR_NAME:
1262  myNBEdge.setStreetName(value);
1263  break;
1264  case SUMO_ATTR_SPEED:
1265  myNBEdge.setSpeed(-1, parse<double>(value));
1266  break;
1267  case SUMO_ATTR_WIDTH:
1268  myNBEdge.setLaneWidth(-1, parse<double>(value));
1269  break;
1270  case SUMO_ATTR_ENDOFFSET:
1271  myNBEdge.setEndOffset(-1, parse<double>(value));
1272  break;
1273  case SUMO_ATTR_ALLOW:
1274  break; // no edge value
1275  case SUMO_ATTR_DISALLOW:
1276  break; // no edge value
1278  myConnectionStatus = value;
1279  if (value == FEATURE_GUESSED) {
1280  WRITE_DEBUG("invalidating (removing) connections of edge '" + getID() + "' due it were guessed");
1283  } else if (value != FEATURE_GUESSED) {
1284  WRITE_DEBUG("declaring connections of edge '" + getID() + "' as loaded (It will not be removed)");
1286  }
1287  break;
1288  case GNE_ATTR_SHAPE_START: {
1289  // get geometry of NBEdge, remove FIRST element with the new value (or with the Junction Source position) and set it back to edge
1290  Position newShapeStart;
1291  if (value == "") {
1292  newShapeStart = myGNEJunctionSource->getPositionInView();
1293  } else {
1294  newShapeStart = parse<Position>(value);
1295  }
1296  // set shape start position
1297  setShapeStartPos(newShapeStart, true);
1298  break;
1299  }
1300  case GNE_ATTR_SHAPE_END: {
1301  // get geometry of NBEdge, remove LAST element with the new value (or with the Junction Destiny position) and set it back to edge
1302  Position newShapeEnd;
1303  if (value == "") {
1304  newShapeEnd = myGNEJunctionDestiny->getPositionInView();
1305  } else {
1306  newShapeEnd = parse<Position>(value);
1307  }
1308  // set shape end position
1309  setShapeEndPos(newShapeEnd, true);
1310  break;
1311  }
1312  case GNE_ATTR_BIDIR:
1313  throw InvalidArgument("Attribute of '" + toString(key) + "' cannot be modified");
1314  case GNE_ATTR_SELECTED:
1315  if (parse<bool>(value)) {
1317  } else {
1319  }
1320  break;
1321  case GNE_ATTR_GENERIC:
1322  setGenericParametersStr(value);
1323  break;
1324  default:
1325  throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
1326  }
1327  // Update Geometry after setting a new attribute (but avoided for certain attributes)
1328  if((key != SUMO_ATTR_ID) && (key != GNE_ATTR_GENERIC) && (key != GNE_ATTR_SELECTED)) {
1329  updateGeometry(true);
1330  }
1331 }
1332 
1333 
1334 void
1336 }
1337 
1338 
1339 void
1340 GNEEdge::setNumLanes(int numLanes, GNEUndoList* undoList) {
1341  undoList->p_begin("change number of " + toString(SUMO_TAG_LANE) + "s");
1342  myGNEJunctionSource->setLogicValid(false, undoList);
1343  myGNEJunctionDestiny->setLogicValid(false, undoList);
1344 
1345  const int oldNumLanes = (int)myLanes.size();
1346  for (int i = oldNumLanes; i < numLanes; i++) {
1347  // since the GNELane does not exist yet, it cannot have yet been referenced so we only pass a zero-pointer
1348  undoList->add(new GNEChange_Lane(this, nullptr,
1349  myNBEdge.getLaneStruct(oldNumLanes - 1), true), true);
1350  }
1351  for (int i = oldNumLanes - 1; i > numLanes - 1; i--) {
1352  // delete leftmost lane
1353  undoList->add(new GNEChange_Lane(this, myLanes[i], myNBEdge.getLaneStruct(i), false), true);
1354  }
1355  undoList->p_end();
1356 }
1357 
1358 
1359 void
1360 GNEEdge::addLane(GNELane* lane, const NBEdge::Lane& laneAttrs, bool recomputeConnections) {
1361  // boundary of edge depends of number of lanes. We need to extract if before add or remove lane
1363  const int index = lane ? lane->getIndex() : myNBEdge.getNumLanes();
1364  // the laneStruct must be created first to ensure we have some geometry
1365  // unless the connections are fully recomputed, existing indices must be shifted
1366  myNBEdge.addLane(index, true, recomputeConnections, !recomputeConnections);
1367  if (lane) {
1368  // restore a previously deleted lane
1369  myLanes.insert(myLanes.begin() + index, lane);
1370 
1371  } else {
1372  // create a new lane by copying leftmost lane
1373  lane = new GNELane(*this, index);
1374  myLanes.push_back(lane);
1375  }
1376  lane->incRef("GNEEdge::addLane");
1377  // check if lane is selected
1378  if (lane->isAttributeCarrierSelected()) {
1379  lane->selectAttributeCarrier();
1380  }
1381  // we copy all attributes except shape since this is recomputed from edge shape
1382  myNBEdge.setSpeed(lane->getIndex(), laneAttrs.speed);
1383  myNBEdge.setPermissions(laneAttrs.permissions, lane->getIndex());
1385  myNBEdge.setEndOffset(lane->getIndex(), laneAttrs.endOffset);
1386  myNBEdge.setLaneWidth(lane->getIndex(), laneAttrs.width);
1387  // udate indices
1388  for (int i = 0; i < (int)myLanes.size(); ++i) {
1389  myLanes[i]->setIndex(i);
1390  }
1391  /* while technically correct, this looks ugly
1392  myGNEJunctionSource->invalidateShape();
1393  myGNEJunctionDestiny->invalidateShape();
1394  */
1395  // Remake connections for this edge and all edges that target this lane
1397  // remake connections of all edges of junction source and destiny
1398  for (auto i : myGNEJunctionSource->getGNEEdges()) {
1399  i->remakeGNEConnections();
1400  }
1401  // remake connections of all edges of junction source and destiny
1402  for (auto i : myGNEJunctionDestiny->getGNEEdges()) {
1403  i->remakeGNEConnections();
1404  }
1405  // add object again
1406  myNet->addGLObjectIntoGrid(this);
1407  // Update geometry with the new lane
1408  updateGeometry(true);
1409 }
1410 
1411 
1412 void
1413 GNEEdge::removeLane(GNELane* lane, bool recomputeConnections) {
1414  // boundary of edge depends of number of lanes. We need to extract if before add or remove lane
1416  if (myLanes.size() == 0) {
1417  throw ProcessError("Should not remove the last " + toString(SUMO_TAG_LANE) + " from an " + getTagStr());
1418  }
1419  if (lane == nullptr) {
1420  lane = myLanes.back();
1421  }
1422  // check if lane is selected
1423  if (lane->isAttributeCarrierSelected()) {
1424  lane->unselectAttributeCarrier();
1425  }
1426  // Delete lane of edge's container
1427  // unless the connections are fully recomputed, existing indices must be shifted
1428  myNBEdge.deleteLane(lane->getIndex(), recomputeConnections, !recomputeConnections);
1429  lane->decRef("GNEEdge::removeLane");
1430  myLanes.erase(myLanes.begin() + lane->getIndex());
1431  // Delete lane if is unreferenced
1432  if (lane->unreferenced()) {
1433  // show extra information for tests
1434  WRITE_DEBUG("Deleting unreferenced " + lane->getTagStr() + " '" + lane->getID() + "' in removeLane()");
1435  delete lane;
1436  }
1437  // udate indices
1438  for (int i = 0; i < (int)myLanes.size(); ++i) {
1439  myLanes[i]->setIndex(i);
1440  }
1441  /* while technically correct, this looks ugly
1442  myGNEJunctionSource->invalidateShape();
1443  myGNEJunctionDestiny->invalidateShape();
1444  */
1445  // Remake connections of this edge
1447  // remake connections of all edges of junction source and destiny
1448  for (auto i : myGNEJunctionSource->getGNEEdges()) {
1449  i->remakeGNEConnections();
1450  }
1451  // remake connections of all edges of junction source and destiny
1452  for (auto i : myGNEJunctionDestiny->getGNEEdges()) {
1453  i->remakeGNEConnections();
1454  }
1455  // add object again
1456  myNet->addGLObjectIntoGrid(this);
1457  // Update element
1458  updateGeometry(true);
1459 }
1460 
1461 
1462 void
1463 GNEEdge::addConnection(NBEdge::Connection nbCon, bool selectAfterCreation) {
1464  // If a new connection was sucesfully created
1465  if (myNBEdge.setConnection(nbCon.fromLane, nbCon.toEdge, nbCon.toLane, NBEdge::L2L_USER, true, nbCon.mayDefinitelyPass,
1466  nbCon.keepClear, nbCon.contPos, nbCon.visibility,
1467  nbCon.speed, nbCon.customShape, nbCon.uncontrolled)) {
1468  // Create or retrieve existent GNEConection
1469  GNEConnection* con = retrieveGNEConnection(nbCon.fromLane, nbCon.toEdge, nbCon.toLane);
1470  // add it to GNEConnection container
1471  myGNEConnections.push_back(con);
1472  // Add reference
1473  myGNEConnections.back()->incRef("GNEEdge::addConnection");
1474  // select GNEConnection if needed
1475  if (selectAfterCreation) {
1476  con->selectAttributeCarrier();
1477  }
1478  // update geometry
1479  con->updateGeometry(true);
1480  // iterate over all additionals from "from" lane and check E2 multilane integrity
1481  for (auto i : con->getLaneFrom()->getAdditionalChilds()) {
1482  if (i->getTagProperty().getTag() == SUMO_TAG_E2DETECTOR_MULTILANE) {
1483  dynamic_cast<GNEDetectorE2*>(i)->checkE2MultilaneIntegrity();
1484  }
1485  }
1486  // iterate over all additionals from "to" lane and check E2 multilane integrity
1487  for (auto i : con->getLaneTo()->getAdditionalChilds()) {
1488  if (i->getTagProperty().getTag() == SUMO_TAG_E2DETECTOR_MULTILANE) {
1489  dynamic_cast<GNEDetectorE2*>(i)->checkE2MultilaneIntegrity();
1490  }
1491  }
1492  }
1493  // actually we only do this to force a redraw
1494  updateGeometry(true);
1495 }
1496 
1497 
1498 void
1500  // check if is a explicit turnaround
1501  if (nbCon.toEdge == myNBEdge.getTurnDestination()) {
1503  }
1504  // remove NBEdge::connection from NBEdge
1506  // remove their associated GNEConnection
1507  GNEConnection* con = retrieveGNEConnection(nbCon.fromLane, nbCon.toEdge, nbCon.toLane, false);
1508  if (con != nullptr) {
1509  con->decRef("GNEEdge::removeConnection");
1510  myGNEConnections.erase(std::find(myGNEConnections.begin(), myGNEConnections.end(), con));
1511  // iterate over all additionals from "from" lane and check E2 multilane integrity
1512  for (auto i : con->getLaneFrom()->getAdditionalChilds()) {
1513  if (i->getTagProperty().getTag() == SUMO_TAG_E2DETECTOR_MULTILANE) {
1514  dynamic_cast<GNEDetectorE2*>(i)->checkE2MultilaneIntegrity();
1515  }
1516  }
1517  // iterate over all additionals from "to" lane and check E2 multilane integrity
1518  for (auto i : con->getLaneTo()->getAdditionalChilds()) {
1519  if (i->getTagProperty().getTag() == SUMO_TAG_E2DETECTOR_MULTILANE) {
1520  dynamic_cast<GNEDetectorE2*>(i)->checkE2MultilaneIntegrity();
1521  }
1522  }
1523  // remove it from Tree
1525  // check if connection is selected
1526  if (con->isAttributeCarrierSelected()) {
1527  con->unselectAttributeCarrier();
1528  }
1529  if (con->unreferenced()) {
1530  // show extra information for tests
1531  WRITE_DEBUG("Deleting unreferenced " + con->getTagStr() + " '" + con->getID() + "' in removeConnection()");
1532  delete con;
1533  // actually we only do this to force a redraw
1534  updateGeometry(true);
1535  }
1536  }
1537 }
1538 
1539 
1541 GNEEdge::retrieveGNEConnection(int fromLane, NBEdge* to, int toLane, bool createIfNoExist) {
1542  for (auto i : myGNEConnections) {
1543  if ((i->getFromLaneIndex() == fromLane) && (i->getEdgeTo()->getNBEdge() == to) && (i->getToLaneIndex() == toLane)) {
1544  return i;
1545  }
1546  }
1547  if (createIfNoExist) {
1548  // create new connection. Will be added to the rTree on first geometry computation
1549  GNEConnection* createdConnection = new GNEConnection(myLanes[fromLane], myNet->retrieveEdge(to->getID())->getLanes()[toLane]);
1550  // show extra information for tests
1551  WRITE_DEBUG("Created " + createdConnection->getTagStr() + " '" + createdConnection->getID() + "' in retrieveGNEConnection()");
1552  // insert it in Tree
1553  myNet->addGLObjectIntoGrid(createdConnection);
1554  // iterate over all additionals from "from" lane and check E2 multilane integrity
1555  for (auto i : createdConnection->getLaneFrom()->getAdditionalChilds()) {
1556  if (i->getTagProperty().getTag() == SUMO_TAG_E2DETECTOR_MULTILANE) {
1557  dynamic_cast<GNEDetectorE2*>(i)->checkE2MultilaneIntegrity();
1558  }
1559  }
1560  // iterate over all additionals from "to" lane and check E2 multilane integrity
1561  for (auto i : createdConnection->getLaneTo()->getAdditionalChilds()) {
1562  if (i->getTagProperty().getTag() == SUMO_TAG_E2DETECTOR_MULTILANE) {
1563  dynamic_cast<GNEDetectorE2*>(i)->checkE2MultilaneIntegrity();
1564  }
1565  }
1566  return createdConnection;
1567  } else {
1568  return nullptr;
1569  }
1570 }
1571 
1572 
1573 
1574 void
1575 GNEEdge::setMicrosimID(const std::string& newID) {
1577  for (auto i : myLanes) {
1578  i->setMicrosimID(getNBEdge()->getLaneID(i->getIndex()));
1579  }
1580 }
1581 
1582 
1583 bool
1585  for (auto i : myLanes) {
1586  if (i->isRestricted(vclass)) {
1587  return true;
1588  }
1589  }
1590  return false;
1591 }
1592 
1593 
1594 void
1596  // Remove all crossings that contain this edge in parameter "edges"
1597  for (GNECrossing* const i : junction->getGNECrossings()) {
1598  if (i->checkEdgeBelong(this)) {
1599  myNet->deleteCrossing(i, undoList);
1600  }
1601  }
1602 }
1603 
1604 
1605 void
1607  PositionVector modifiedShape = myNBEdge.getGeometry().interpolateZ(
1609  myNBEdge.getToNode()->getPosition().z());
1610  PositionVector innerShape(modifiedShape.begin() + 1, modifiedShape.end() - 1);
1611  setAttribute(SUMO_ATTR_SHAPE, toString(innerShape), undoList);
1612 }
1613 
1614 
1616 GNEEdge::smoothShape(const PositionVector& old, bool forElevation) {
1617  const OptionsCont& oc = OptionsCont::getOptions();
1618  // distinguish 3 cases:
1619  // a) if the edge has exactly 3 or 4 points, use these as control points
1620  // b) if the edge has more than 4 points, use the first 2 and the last 2 as control points
1621  // c) if the edge is straight and both nodes are geometry-like nodes, use geometry of the continuation edges as control points
1622  PositionVector init;
1623 #ifdef DEBUG_SMOOTH_GEOM
1624  if (DEBUGCOND(this)) std::cout << getID()
1625  << " forElevation=" << forElevation
1626  << " fromGeometryLike=" << myNBEdge.getFromNode()->geometryLike()
1627  << " toGeometryLike=" << myNBEdge.getToNode()->geometryLike()
1628  << " smoothShape old=" << old << "\n";
1629 #endif
1630  if (old.size() == 3 || old.size() == 4) {
1631  init = old;
1632  } else if (old.size() > 4 && !forElevation) {
1633  // for elevation, the initial segments are not useful
1634  init.push_back(old[0]);
1635  init.push_back(old[1]);
1636  init.push_back(old[-2]);
1637  init.push_back(old[-1]);
1638  } else if (myNBEdge.getFromNode()->geometryLike() && myNBEdge.getToNode()->geometryLike()) {
1639  PositionVector begShape;
1640  PositionVector endShape;
1641  const EdgeVector& incoming = myNBEdge.getFromNode()->getIncomingEdges();
1642  const EdgeVector& outgoing = myNBEdge.getToNode()->getOutgoingEdges();
1643  if (incoming.size() == 1) {
1644  begShape = incoming[0]->getGeometry();
1645  } else {
1646  assert(incoming.size() == 2);
1647  begShape = myNBEdge.isTurningDirectionAt(incoming[0]) ? incoming[1]->getGeometry() : incoming[0]->getGeometry();
1648  }
1649  if (outgoing.size() == 1) {
1650  endShape = outgoing[0]->getGeometry();
1651  } else {
1652  assert(outgoing.size() == 2);
1653  endShape = myNBEdge.isTurningDirectionAt(outgoing[0]) ? outgoing[1]->getGeometry() : outgoing[0]->getGeometry();
1654  }
1655  const double dist = MIN2(old.length2D(), MAX2(old.length2D() / 8, fabs(old[0].z() - old[-1].z()) * OptionsCont::getOptions().getFloat("geometry.max-grade") / 3));
1656  if (forElevation) {
1657  // initialize control point elevation for smooth continuation
1658  init.push_back(old[0]);
1659  init.push_back(old.positionAtOffset2D(dist));
1660  init.push_back(old.positionAtOffset2D(old.length2D() - dist));
1661  init.push_back(old[-1]);
1662  double begZ = begShape.positionAtOffset2D(MAX2(0.0, begShape.length2D() - dist)).z();
1663  double endZ = endShape.positionAtOffset2D(MIN2(begShape.length2D(), dist)).z();
1664  // continue incline
1665  init[1].setz(2 * init[0].z() - begZ);
1666  init[2].setz(2 * init[-1].z() - endZ);
1667  } else {
1668  bool ok = true;
1669  const double straightThresh = DEG2RAD(oc.getFloat("opendrive-output.straight-threshold"));
1670  init = NBNode::bezierControlPoints(begShape, endShape, false, dist, dist, ok, nullptr, straightThresh);
1671  }
1672 #ifdef DEBUG_SMOOTH_GEOM
1673  if (DEBUGCOND(this)) {
1674  std::cout << " begShape=" << begShape << " endShape=" << endShape << " forElevation=" << forElevation << " dist=" << dist << " ok=" << ok << " init=" << init << "\n";
1675  }
1676 #endif
1677  }
1678  if (init.size() == 0) {
1679  return PositionVector::EMPTY;
1680  } else {
1681  const int numPoints = MAX2(oc.getInt("junctions.internal-link-detail"),
1682  int(old.length2D() / oc.getFloat("opendrive.curve-resolution")));
1683  return bezier(init, numPoints);
1684  }
1685 }
1686 
1687 
1688 void
1690  PositionVector modifiedShape = smoothShape(myNBEdge.getGeometry(), false);
1691  if (modifiedShape.size() < 2) {
1692  WRITE_WARNING("Could not compute smooth shape for edge '" + getID() + "'");
1693  } else {
1694  PositionVector innerShape(modifiedShape.begin() + 1, modifiedShape.end() - 1);
1695  setAttribute(SUMO_ATTR_SHAPE, toString(innerShape), undoList);
1696  }
1697 }
1698 
1699 
1700 void
1702  PositionVector elevationBase;
1703  for (const Position& pos : myNBEdge.getGeometry()) {
1704  if (elevationBase.size() == 0 || elevationBase[-1].z() != pos.z()) {
1705  elevationBase.push_back(pos);
1706  }
1707  }
1708  PositionVector elevation = smoothShape(elevationBase, true);
1709  if (elevation.size() <= 2) {
1710  WRITE_WARNING("Could not compute smooth elevation for edge '" + getID() + "'");
1711  } else {
1712  PositionVector modifiedShape = myNBEdge.getGeometry();
1713  if (modifiedShape.size() < 5) {
1714  modifiedShape = modifiedShape.resample(OptionsCont::getOptions().getFloat("opendrive.curve-resolution"));
1715  }
1716  const double scale = elevation.length2D() / modifiedShape.length2D();
1717  //std::cout << " elevation=" << elevation << "\n mod1=" << modifiedShape << " scale=" << scale << "\n";
1718  double seen = 0;
1719  for (int i = 1; i < (int)modifiedShape.size(); ++i) {
1720  seen += modifiedShape[i - 1].distanceTo2D(modifiedShape[i]);
1721  modifiedShape[i].setz(elevation.positionAtOffset2D(seen * scale).z());
1722  }
1723  //std::cout << " mod2=" << modifiedShape << "\n";
1724  PositionVector innerShape(modifiedShape.begin() + 1, modifiedShape.end() - 1);
1725  setAttribute(SUMO_ATTR_SHAPE, toString(innerShape), undoList);
1726  }
1727 }
1728 
1729 
1730 void
1731 GNEEdge::setShapeStartPos(const Position& pos, bool updateGrid) {
1732  // remove start position and add it the new position
1734  geom.erase(geom.begin());
1735  geom.push_front_noDoublePos(pos);
1736  // restore modified shape
1737  setGeometry(geom, false, updateGrid);
1738 }
1739 
1740 
1741 void
1742 GNEEdge::setShapeEndPos(const Position& pos, bool updateGrid) {
1743  // remove end position and add it the new position
1745  geom.pop_back();
1746  geom.push_back_noDoublePos(pos);
1747  // restore modified shape
1748  setGeometry(geom, false, updateGrid);
1749 }
1750 
1751 /****************************************************************************/
GUIVisualizationSizeSettings junctionSize
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge&#39;s lanes&#39; lateral offset is computed.
Definition: NBEdge.h:704
static const PositionVector EMPTY
empty Vector
void copyTemplate(GNEEdge *tpl, GNEUndoList *undolist)
copy edge attributes from tpl
Definition: GNEEdge.cpp:841
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
Definition: NBEdge.cpp:1348
GNEJunction * myGNEJunctionSource
pointer to GNEJunction source
Definition: GNEEdge.h:311
The information about how to spread the lanes from the given position.
std::string getVehicleClassNames(SVCPermissions permissions, bool expand)
Returns the ids of the given classes, divided using a &#39; &#39;.
void remakeGNEConnections()
remake connections
Definition: GNEEdge.cpp:709
double rotationDegreeAtOffset(double pos) const
Returns the rotation at the given length.
Position getPositionInView() const
Return current position.
double length2D() const
Returns the length.
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:160
void addIncomingGNEEdge(GNEEdge *edge)
add incoming GNEEdge
void setNumLanes(int numLanes, GNEUndoList *undoList)
changes the number of lanes. When reducing the number of lanes, higher-numbered lanes are removed fir...
Definition: GNEEdge.cpp:1340
int toLane
The lane the connections yields in.
Definition: NBEdge.h:188
const std::vector< T > & getSchemes() const
GNEEdge * retrieveEdge(const std::string &id, bool failHard=true)
get edge by id
Definition: GNENet.cpp:900
double scale
information about a lane&#39;s width (temporary, used for a single view)
GUIVisualizationTextSettings streetName
double laneWidthExaggeration
The lane exaggeration (upscale thickness)
RGBColor changedBrightness(int change, int toChange=3) const
Returns a new color with altered brightness.
Definition: RGBColor.cpp:154
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
static const double UNSPECIFIED_LOADED_LENGTH
no length override given
Definition: NBEdge.h:273
void resetWritable()
Resets all options to be writeable.
GNENet * myNet
the net to inform about updates
bool myAmResponsible
whether we are responsible for deleting myNBNode
Definition: GNEEdge.h:323
mode for moving things
Definition: GNEViewNet.h:48
std::string next()
void smoothElevation(GNEUndoList *undoList)
smooth elevation with regard to adjoining edges
Definition: GNEEdge.cpp:1701
void invalidateShape()
void drawGL(const GUIVisualizationSettings &s) const
Draws the object.
Definition: GNEEdge.cpp:476
void removeIncomingGNEEdge(GNEEdge *edge)
remove incoming GNEEdge
double z() const
Returns the z-position.
Definition: Position.h:67
void addLane(GNELane *lane, const NBEdge::Lane &laneAttrs, bool recomputeConnections)
increase number of lanes by one use the given attributes and restore the GNELane
Definition: GNEEdge.cpp:1360
void buildNameCopyPopupEntry(GUIGLObjectPopupMenu *ret, bool addSeparator=true)
Builds entries which allow to copy the name / typed name into the clipboard.
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:185
Boundary getCenteringBoundary() const
Returns the boundary to which the view shall be centered in order to show the object.
Definition: GNEEdge.cpp:430
begin/end of the description of a single lane
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
std::string myConnectionStatus
modification status of the connections
Definition: GNEEdge.h:329
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:127
void setEndOffset(int lane, double offset)
set lane specific end-offset (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3222
GNEJunction * myGNEJunctionDestiny
pointer to GNEJunction destiny
Definition: GNEEdge.h:314
bool setConnection(int lane, NBEdge *destEdge, int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1042
int indexOfClosest(const Position &p) const
index of the closest position to p
an e2 detector over multiple lanes (used by Netedit)
void setMicrosimID(const std::string &newID)
override to also set lane ids
Definition: GNEEdge.cpp:1575
static const RGBColor WHITE
Definition: RGBColor.h:191
void endGeometryMoving()
begin movement (used when user click over edge to start a movement, to avoid problems with problems w...
Definition: GNEEdge.cpp:243
static StringBijection< LaneSpreadFunction > LaneSpreadFunctions
lane spread functions
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:244
GNEEdge()
constructor for dummy edge
Definition: GNEEdge.cpp:82
void straightenElevation(GNEUndoList *undoList)
interpolate z values linear between junctions
Definition: GNEEdge.cpp:1606
std::set< GUIGlID > getLaneGlIDs()
returns GLIDs of all lanes
Definition: GNEEdge.cpp:863
void addLane(int index, bool recomputeShape, bool recomputeConnections, bool shiftIndices)
add lane
Definition: NBEdge.cpp:3042
void setSpeed(int lane, double speed)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3272
double exaggeration
The size exaggeration (upscale)
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
GUIColorer laneColorer
The lane colorer.
Stores the information about how to visualize structures.
PositionVector resample(double maxLength) const
resample shape with the given number of points (equal spacing)
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:427
const std::string & getTypeID() const
get ID of type
Definition: NBEdge.h:1004
static const double SNAP_RADIUS
Definition: GNEEdge.h:274
double y() const
Returns the y-position.
Definition: Position.h:62
GUIVisualizationSettings * getVisualisationSettings() const
get visualitation settings
GUIVisualizationTextSettings edgeValue
Position snapToActiveGrid(const Position &pos) const
Returns a position that is mapped to the closest grid point if the grid is active.
The representation of a single edge during network building.
Definition: NBEdge.h:65
void moveShapeStart(const Position &oldPos, const Position &offset)
move position of shape start without commiting change
Definition: GNEEdge.cpp:166
static void drawTextSettings(const GUIVisualizationTextSettings &settings, const std::string &text, const Position &pos, const double scale, const double angle=0, const double layer=2048)
Definition: GLHelper.cpp:635
bool hasLaneSpecificSpeed() const
whether lanes differ in speed
Definition: NBEdge.cpp:1992
bool hasRestrictedLane(SUMOVehicleClass vclass) const
check if edge has a restricted lane
Definition: GNEEdge.cpp:1584
double x() const
Returns the x-position.
Definition: Position.h:57
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:668
Representation of a RouteProbe in netedit.
Definition: GNERouteProbe.h:35
void setStreetName(const std::string &name)
sets the street name of this edge
Definition: NBEdge.h:548
void buildCenterPopupEntry(GUIGLObjectPopupMenu *ret, bool addSeparator=true)
Builds an entry which allows to center to the object.
void smooth(GNEUndoList *undoList)
make geometry smooth
Definition: GNEEdge.cpp:1689
static void drawText(const std::string &text, const Position &pos, const double layer, const double size, const RGBColor &col=RGBColor::BLACK, const double angle=0, int align=0, double width=-1)
Definition: GLHelper.cpp:611
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false, const bool adaptToLaneRemoval=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:1281
T MAX2(T a, T b)
Definition: StdDefs.h:76
A NBNetBuilder extended by visualisation and editing capabilities.
Definition: GNENet.h:77
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3013
void setPermissions(SVCPermissions permissions, int lane=-1)
set allowed/disallowed classes for the given lane or for all lanes if -1 is given ...
Definition: NBEdge.cpp:3303
This lane is powered by an underlying GNEEdge and basically knows how to draw itself.
Definition: GNELane.h:47
void setLoadedLength(double val)
set loaded lenght
Definition: NBEdge.cpp:3346
void p_begin(const std::string &description)
Begin undo command sub-group. This begins a new group of commands that are treated as a single comman...
Definition: GNEUndoList.cpp:73
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:589
void setShapeStartPos(const Position &pos, bool updateGrid)
change Shape StartPos
Definition: GNEEdge.cpp:1731
bool mayDefinitelyPass
Information about being definitely free to drive (on-ramps)
Definition: NBEdge.h:197
double endOffset
This lane&#39;s offset to the intersection begin.
Definition: NBEdge.h:133
void clearGNEConnections()
clear current connections
Definition: GNEEdge.cpp:748
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
void moveShapeEnd(const Position &oldPos, const Position &offset)
move position of shape end without commiting change
Definition: GNEEdge.cpp:182
PositionVector interpolateZ(double zStart, double zEnd) const
returned vector that varies z smoothly over its length
double visibility
custom foe visiblity for connection
Definition: NBEdge.h:206
void removeEdgeFromCrossings(GNEJunction *junction, GNEUndoList *undoList)
remove crossing of junction
Definition: GNEEdge.cpp:1595
int getVertexIndex(Position pos, bool createIfNoExist, bool snapToGrid)
return index of a vertex of shape, or of a new vertex if position is over an shape&#39;s edge ...
Definition: GNEEdge.cpp:271
const std::vector< GNEConnection * > & getGNEConnections()
returns a reference to the GNEConnection vector
Definition: GNEEdge.cpp:879
const std::string & getID() const
Returns the id.
Definition: Named.h:78
void buildShowParamsPopupEntry(GUIGLObjectPopupMenu *ret, bool addSeparator=true)
Builds an entry which allows to open the parameter window.
const SVCPermissions SVCAll
all VClasses are allowed
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1206
void commitShapeStartChange(const Position &oldPos, GNEUndoList *undoList)
commit position changing in shape start
Definition: GNEEdge.cpp:198
PositionVector smoothShape(const PositionVector &shape, bool forElevation)
return smoothed shape
Definition: GNEEdge.cpp:1616
void removeLane(GNELane *lane, bool recomputeConnections)
the number of lanes by one. argument is only used to increase robustness (assertions) ...
Definition: GNEEdge.cpp:1413
bool myWasSplit
whether this edge was created from a split
Definition: GNEEdge.h:326
~GNEEdge()
Destructor.
Definition: GNEEdge.cpp:88
static void drawFilledCircle(double width, int steps=8)
Draws a filled circle around (0,0)
Definition: GLHelper.cpp:344
const std::vector< GNEEdge * > & getGNEEdges() const
Returns all GNEEdges vinculated with this Junction.
first coordinate of edge shape
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.
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge&#39;s geometry
Definition: NBEdge.cpp:559
generic attribute
void editEndpoint(Position pos, GNEUndoList *undoList)
makes pos the new geometry endpoint at the appropriate end, or remove current existent endpoint ...
Definition: GNEEdge.cpp:633
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:258
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:42
PositionVector customShape
custom shape for connection
Definition: NBEdge.h:212
void deleteGeometryPoint(const Position &pos, bool allowUndo=true)
delete the geometry point closest to the given pos
Definition: GNEEdge.cpp:383
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:241
Boundary myMovingGeometryBoundary
boundary used during moving of elements
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
whether a feature has been loaded,guessed,modified or approved
SVCPermissions invertPermissions(SVCPermissions permissions)
negate the given permissions and ensure that only relevant bits are set
GNELane * getLaneFrom() const
get lane of the incoming lane
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:255
void setGeometry(PositionVector geom, bool inner, bool updateGrid)
update edge geometry and inform the lanes
Definition: GNEEdge.cpp:691
void removeOutgoingGNEEdge(GNEEdge *edge)
remove outgoing GNEEdge
bool keepClear
whether the junction must be kept clear when using this connection
Definition: NBEdge.h:200
void p_add(GNEChange_Attribute *cmd)
special method, avoid empty changes, always execute
GUIVisualizationTextSettings edgeName
const std::vector< GNECrossing * > & getGNECrossings() const
Returns GNECrossings.
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:116
static GNEEdge DummyEdge
Dummy edge to use when a reference must be supplied in the no-arguments constructor (FOX technicality...
Definition: GNEEdge.h:277
void updateJunctionPosition(GNEJunction *junction, const Position &origPos, bool updateGrid)
update edge geometry after junction move
Definition: GNEEdge.cpp:401
SVCPermissions permissions
List of vehicle types that are allowed on this lane.
Definition: NBEdge.h:127
std::string getAttribute(SumoXMLAttr key) const
Definition: GNEEdge.cpp:891
GNEUndoList * getUndoList() const
get the undoList object
int getIndex() const
returns the index of the lane
Definition: GNELane.cpp:757
void push_front_noDoublePos(const Position &p)
insert in front a non double position
void updateGeometry(bool updateGrid)
update pre-computed geometry information
Definition: GNEEdge.cpp:114
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
whether an edge is part of a bidirectional railway
bool hasLaneSpecificWidth() const
whether lanes differ in width
Definition: NBEdge.cpp:2003
static bool isValidGenericParameterValue(const std::string &value)
whether the given string is a valid value for a generic parameter
double speed
custom speed for connection
Definition: NBEdge.h:209
bool hasLaneSpecificEndOffset() const
whether lanes differ in offset
Definition: NBEdge.cpp:2014
the edges of a route
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
SumoXMLTag getTag() const
get Tag vinculated with this attribute Property
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition: GLHelper.cpp:573
This object is responsible for drawing a shape and for supplying a a popup menu. Messages are routete...
Definition: GNECrossing.h:45
const double SUMO_const_halfLaneWidth
Definition: StdDefs.h:53
bool clickedOverShapeStart(const Position &pos)
Definition: GNEEdge.cpp:146
void commitShapeEndChange(const Position &oldPos, GNEUndoList *undoList)
commit position changing in shape end
Definition: GNEEdge.cpp:211
SVCPermissions preferred
List of vehicle types that are preferred on this lane.
Definition: NBEdge.h:130
std::string getGenericParametersStr() const
return generic parameters in string format
Definition: GNEEdge.cpp:1160
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:420
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:182
void p_end()
End undo command sub-group. If the sub-group is still empty, it will be deleted; otherwise, the sub-group will be added as a new command into parent group. A matching begin() must have been called previously.
Definition: GNEUndoList.cpp:80
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
GNEJunction * retrieveJunction(const std::string &id, bool failHard=true)
get junction by id
Definition: GNENet.cpp:887
GNELane * getLaneTo() const
get lane of the outgoing lane
A list of positions.
double scaledSize(double scale, double constFactor=0.1) const
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
const PositionVector getInnerGeometry() const
Returns the geometry of the edge without the endpoints.
Definition: NBEdge.cpp:529
friend class GNEChange_Attribute
declare friend class
GNEEdge * getOppositeEdge() const
get opposite edge
Definition: GNEEdge.cpp:470
std::vector< std::pair< std::string, std::string > > getGenericParameters() const
return generic parameters as vector of pairs format
Definition: GNEEdge.cpp:1175
void deleteLane(int index, bool recompute, bool shiftIndices)
delete lane
Definition: NBEdge.cpp:3096
void updateGeometry(bool updateGrid)
Update the boundary of the junction.
Definition: GNEJunction.cpp:91
GNEJunction * getGNEJunctionDestiny() const
returns the destination-junction
Definition: GNEEdge.cpp:464
static const std::string FEATURE_GUESSED
feature has been reguessed (may still be unchanged be we can&#39;t tell (yet)
GNEConnection * retrieveGNEConnection(int fromLane, NBEdge *to, int toLane, bool createIfNoExist=true)
get GNEConnection if exist, and if not create it if create is enabled
Definition: GNEEdge.cpp:1541
int myPriority
The priority of the edge.
Definition: NBEdge.h:1467
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:2882
T MIN2(T a, T b)
Definition: StdDefs.h:70
void drawName(const Position &pos, const double scale, const GUIVisualizationTextSettings &settings, const double angle=0) const
draw name of item
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:543
void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
void startGeometryMoving()
Definition: GNEEdge.cpp:224
edge: the shape in xml-definition
Boundary & grow(double by)
extends the boundary by the given amount
Definition: Boundary.cpp:301
GUIColorer junctionColorer
The junction colorer.
virtual const std::string & getMicrosimID() const
Returns the id of the object as known to microsim.
void deleteCrossing(GNECrossing *crossing, GNEUndoList *undoList)
remove crossing
Definition: GNENet.cpp:555
void addOutgoingGNEEdge(GNEEdge *edge)
add outgoing GNEEdge
const std::string getID() const
function to support debugging
int insertAtClosest(const Position &p)
inserts p between the two closest positions and returns the insertion index
static PositionVector bezierControlPoints(const PositionVector &begShape, const PositionVector &endShape, bool isTurnaround, double extrapolateBeg, double extrapolateEnd, bool &ok, NBNode *recordError=0, double straightThresh=DEG2RAD(5), int shapeFlag=0)
get bezier control points
Definition: NBNode.cpp:503
static void drawLine(const Position &beg, double rot, double visLength)
Draws a thin line.
Definition: GLHelper.cpp:270
double getEndOffset() const
Returns the offset to the destination node.
Definition: NBEdge.h:555
#define WRITE_DEBUG(msg)
Definition: MsgHandler.h:248
#define DEG2RAD(x)
Definition: GeomHelper.h:38
bool clickedOverShapeEnd(const Position &pos)
return true if user clicked over ShapeEnd
Definition: GNEEdge.cpp:156
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:52
GNEJunction * getGNEJunctionSource() const
returns the source-junction
Definition: GNEEdge.cpp:458
void incRef(const std::string &debugMsg="")
Increarse reference.
The connection was given by the user.
Definition: NBEdge.h:107
double speed
The speed allowed on this lane.
Definition: NBEdge.h:124
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
double width
This lane&#39;s width.
Definition: NBEdge.h:140
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3331
double getFinalLength() const
get length that will be assigned to the lanes in the final network
Definition: NBEdge.cpp:3575
void selectAttributeCarrier(bool changeFlag=true)
select attribute carrier using GUIGlobalSelection
bool hasLaneSpecificPermissions() const
whether lanes differ in allowed vehicle classes
Definition: NBEdge.cpp:1978
GUIGLObjectPopupMenu * getPopUpMenu(GUIMainWindow &app, GUISUMOAbstractView &parent)
Returns an own popup-menu.
Definition: GNEEdge.cpp:443
void decRef(const std::string &debugMsg="")
Decrease reference.
std::vector< GNECrossing * > getGNECrossings()
get GNECrossings vinculated with this Edge
Definition: GNEEdge.cpp:789
begin/end of the description of an edge
void unselectAttributeCarrier(bool changeFlag=true)
unselect attribute carrier using GUIGlobalSelection
EditMode getCurrentEditMode() const
get the current edit mode
static bool isValidNetID(const std::string &value)
whether the given string is a valid id for a network element
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:514
bool canParseVehicleClasses(const std::string &classes)
Checks whether the given string contains only known vehicle classes.
#define DEBUGCOND(PEDID)
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:622
A road/street connecting two junctions (netedit-version)
Definition: GNEEdge.h:50
int getRouteProbeRelativePosition(GNERouteProbe *routeProbe) const
obtain relative positions of RouteProbes
Definition: GNEEdge.cpp:771
ConnectionVector myGNEConnections
vector with the connections of this edge
Definition: GNEEdge.h:320
void updateGeometry(bool updateGrid)
update pre-computed geometry information
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:530
int moveVertexShape(const int index, const Position &oldPos, const Position &offset)
change position of a vertex of shape without commiting change
Definition: GNEEdge.cpp:315
static const double BUBBLE_RADIUS
constant values for drawing buubles
Definition: GNEJunction.h:56
void reset()
Resets the boundary.
Definition: Boundary.cpp:67
void setResponsible(bool newVal)
set responsibility for deleting internal strctures
Definition: GNEEdge.cpp:1211
void addConnection(NBEdge::Connection nbCon, bool selectAfterCreation=false)
adds a connection
Definition: GNEEdge.cpp:1463
const PositionVector & getShape() const
returns the shape of the lane
Definition: GNELane.cpp:669
const std::vector< GNELane * > & getLanes()
returns a reference to the lane vector
Definition: GNEEdge.cpp:873
void buildSelectionACPopupEntry(GUIGLObjectPopupMenu *ret, GNEAttributeCarrier *AC)
Builds an entry which allows to (de)select the object.
Definition: GNEViewNet.cpp:617
double length() const
Returns the length.
bool set(const std::string &name, const std::string &value)
Sets the given value for the named option.
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:250
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:867
virtual void setMicrosimID(const std::string &newID)
Changes the microsimID of the object.
void setGenericParametersStr(const std::string &value)
set generic parameters in string format
Definition: GNEEdge.cpp:1186
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
bool editingElevation() const
return true if elevation is being edited
Definition: GNEViewNet.cpp:739
void moveEntireShape(const PositionVector &oldShape, const Position &offset)
move entire shape without commiting change
Definition: GNEEdge.cpp:340
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
void setPreferredVehicleClass(SVCPermissions permissions, int lane=-1)
set preferred Vehicle Class
Definition: NBEdge.cpp:3317
double contPos
custom position for internal junction on this connection
Definition: NBEdge.h:203
element is selected
bool isInitialised() const
check if Boundary is Initialised
Definition: Boundary.cpp:217
A storage for options typed value containers)
Definition: OptionsCont.h:92
bool uncontrolled
check if Connection is uncontrolled
Definition: NBEdge.h:242
void markConnectionGeometryDeprecated()
check that connection&#39;s Geometry has to be updated
void mouseOverObject(const GUIVisualizationSettings &s) const
method for check if mouse is over objects
Definition: GNEEdge.cpp:1335
The popup menu of a globject.
an edge
static int getCircleResolution(const GUIVisualizationSettings &settings)
function to calculate circle resolution for all circles drawn in drawGL(...) functions ...
double distanceSquaredTo2D(const Position &p2) const
returns the square of the distance to another position (Only using x and y positions) ...
Definition: Position.h:249
std::string myType
The type of the edge.
Definition: NBEdge.h:1451
void renameEdge(GNEEdge *edge, const std::string &newID)
updates the map and reserves new id
Definition: GNENet.cpp:1707
bool isValid(SumoXMLAttr key, const std::string &value)
Definition: GNEEdge.cpp:1071
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2684
void declareConnectionsAsLoaded(EdgeBuildingStep step=LANES2LANES_USER)
declares connections as fully loaded. This is needed to avoid recomputing connections if an edge has ...
Definition: NBEdge.h:1220
const Position & getPosition() const
Definition: NBNode.h:242
void removeExplicitTurnaround(std::string id)
remove edge id from the list of explicit turnarounds
Definition: GNENet.cpp:1779
void commitShapeChange(const PositionVector &oldShape, GNEUndoList *undoList)
commit geometry changes in the attributes of an element after use of changeShapeGeometry(...)
Definition: GNEEdge.cpp:353
const std::map< std::string, std::string > & getParametersMap() const
Returns the inner key/value map.
GUIGlID getGlID() const
Returns the numerical id of the object.
LaneVector myLanes
vectgor with the lanes of this edge
Definition: GNEEdge.h:317
std::vector< GNEAdditional * > myAdditionalChilds
list of Additional Childs of this NetElement
void removeConnection(NBEdge::Connection nbCon)
removes a connection
Definition: GNEEdge.cpp:1499
void updateLinkState()
recompute cached myLinkState
const TagProperties & getTagProperty() const
get Tag Property assigned to this object
const std::vector< GNEAdditional * > & getAdditionalChilds() const
return vector of additionals that have as Parent this edge (For example, Calibrators) ...
Position getPositionInformation() const
Returns the cursor&#39;s x/y position within the network.
last coordinate of edge shape
std::vector< GNEAdditional * > myFirstAdditionalParents
list of Additional parents of this NetElement
void push_back_noDoublePos(const Position &p)
insert in back a non double position
empty max
NBEdge & myNBEdge
the underlying NBEdge
Definition: GNEEdge.h:305
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:434
void mul(double val)
Multiplies both positions with the given value.
Definition: Position.h:107
bool hasString(const std::string &str) const
void setShapeEndPos(const Position &pos, bool updateGrid)
change Shape EndPos
Definition: GNEEdge.cpp:1742
NBEdge * getNBEdge()
returns the internal NBEdge
Definition: GNEEdge.cpp:613
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Definition: Boundary.cpp:79
void add(double xoff, double yoff, double zoff)
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:861
bool drawForSelecting
whether drawing is performed for the purpose of selecting objects
Boundary getBoundary() const
Returns the street&#39;s geometry.
Definition: GNEEdge.cpp:415
double getColorValue(const GUIVisualizationSettings &s, int activeScheme) const
return value for lane coloring according to the given scheme
Definition: GNELane.cpp:1105
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
NBNode * getNBNode() const
Return net build node.
void setAttribute(SumoXMLAttr key, const std::string &value, GNEUndoList *undoList)
Definition: GNEEdge.cpp:971
void addGLObjectIntoGrid(GUIGlObject *o)
add GL Object into net
Definition: GNENet.cpp:1153
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void resetEndpoint(const Position &pos, GNEUndoList *undoList)
restores the endpoint to the junction position at the appropriate end
Definition: GNEEdge.cpp:677
void setLogicValid(bool valid, GNEUndoList *undoList, const std::string &status=FEATURE_GUESSED)
void changeEdgeEndpoints(GNEEdge *edge, const std::string &newSourceID, const std::string &newDestID)
modifies endpoins of the given edge
Definition: GNENet.cpp:1720
int removeClosest(const Position &p)
removes the point closest to p and return the removal index
std::string getAttributeForSelection(SumoXMLAttr key) const
method for getting the attribute in the context of object selection
Definition: GNEEdge.cpp:962
bool wasSplit()
whether this edge was created from a split
Definition: GNEEdge.cpp:885
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:441
Position getSplitPos(const Position &clickPos)
Definition: GNEEdge.cpp:619
bool unreferenced()
check if object ins&#39;t referenced
friend class GNEChange_Lane
Friend class.
Definition: GNEEdge.h:53
bool isAttributeCarrierSelected() const
check if attribute carrier is selected
void removeEdgeOfAdditionalParents(GNEUndoList *undoList)
remove Edge of Additional Parent
Definition: GNEEdge.cpp:806
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3174
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
void bezier(int npts, double b[], int cpts, double p[])
Definition: bezier.cpp:90