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