Eclipse SUMO - Simulation of Urban MObility
GNEMoveElement.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-2020 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
18 // Class used for move shape elements
19 /****************************************************************************/
22 #include <netedit/GNEUndoList.h>
23 #include <netedit/GNEViewNet.h>
24 
25 #include "GNEMoveElement.h"
26 
27 
28 // ===========================================================================
29 // GNEMoveOperation method definitions
30 // ===========================================================================
31 
33  const Position _originalPosition) :
34  moveElement(_moveElement),
35  originalShape({_originalPosition}),
36  shapeToMove({_originalPosition}),
37 lane(nullptr) {
38 }
39 
40 
42  const PositionVector _originalShape) :
43  moveElement(_moveElement),
44  originalShape(_originalShape),
45  shapeToMove(_originalShape),
46  lane(nullptr) {
47 }
48 
49 
51  const PositionVector _originalShape,
52  const std::vector<int> _originalgeometryPoints,
53  const PositionVector _shapeToMove,
54  const std::vector<int> _geometryPointsToMove) :
55  moveElement(_moveElement),
56  originalShape(_originalShape),
57  originalGeometryPoints(_originalgeometryPoints),
58  shapeToMove(_shapeToMove),
59  geometryPointsToMove(_geometryPointsToMove),
60  lane(nullptr) {
61 }
62 
63 
65  const GNELane* _lane,
66  const std::vector<double> _originalPosOverLanes) :
67  moveElement(_moveElement),
68  lane(_lane),
69  originalPosOverLanes(_originalPosOverLanes) {
70 }
71 
72 
74  const GNELane* _lane,
75  const std::vector<double> _originalPosOverLanes,
76  const std::vector<int> _geometryPointsToMove) :
77  moveElement(_moveElement),
78  geometryPointsToMove(_geometryPointsToMove),
79  lane(_lane),
80  originalPosOverLanes(_originalPosOverLanes) {
81 }
82 
83 
85 
86 // ===========================================================================
87 // GNEMoveResult method definitions
88 // ===========================================================================
89 
91 
92 
94 
95 // ===========================================================================
96 // GNEMoveElement method definitions
97 // ===========================================================================
98 
100 }
101 
102 
103 void
104 GNEMoveElement::moveElement(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const Position& offset) {
105  // declare move result
106  GNEMoveResult moveResult;
107  // set geometry points to move
108  moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
109  // check if we're moving over a lane shape, an entire shape or only certain geometry point
110  if (moveOperation->lane) {
111  // calculate movement over lane
112  moveResult.shapeToUpdate = calculateMovementOverLane(viewNet, moveOperation, offset);
113  } else if (moveOperation->geometryPointsToMove.empty()) {
114  // set values in moveResult
115  moveResult.shapeToUpdate = moveOperation->shapeToMove;
116  // move entire shape
117  for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
118  if (geometryPointIndex != Position::INVALID) {
119  // add offset
120  geometryPointIndex.add(offset);
121  // apply snap to active grid
122  geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
123  } else {
124  throw ProcessError("trying to move an invalid position");
125  }
126  }
127  } else {
128  // set values in moveResult
129  moveResult.shapeToUpdate = moveOperation->shapeToMove;
130  // move geometry points
131  for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
132  if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
133  // add offset
134  moveResult.shapeToUpdate[geometryPointIndex].add(offset);
135  // apply snap to active grid
136  moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
137  } else {
138  throw ProcessError("trying to move an invalid position");
139  }
140  }
141  }
142  // move shape element
143  moveOperation->moveElement->setMoveShape(moveResult);
144 }
145 
146 
147 void
148 GNEMoveElement::commitMove(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const Position& offset, GNEUndoList* undoList) {
149  // declare move result
150  GNEMoveResult moveResult;
151  // check if we're moving over a lane shape, an entire shape or only certain geometry point
152  if (moveOperation->lane) {
153  // set geometry points to move
154  moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
155  // restore original position over lanes
156  PositionVector originalPosOverLanes;
157  for (const auto& posOverlane : moveOperation->originalPosOverLanes) {
158  originalPosOverLanes.push_back(Position(posOverlane, 0));
159  }
160  // set shapeToUpdate with originalPosOverLanes
161  moveResult.shapeToUpdate = originalPosOverLanes;
162  // set originalPosOverLanes in element
163  moveOperation->moveElement->setMoveShape(moveResult);
164  // calculate movement over lane
165  moveResult.shapeToUpdate = calculateMovementOverLane(viewNet, moveOperation, offset);
166  } else {
167  // set original geometry points to move
168  moveResult.geometryPointsToMove = moveOperation->originalGeometryPoints;
169  // set shapeToUpdate with originalPosOverLanes
170  moveResult.shapeToUpdate = moveOperation->originalShape;
171  // first restore original geometry geometry
172  moveOperation->moveElement->setMoveShape(moveResult);
173  // set new geometry points to move
174  moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
175  // set values in moveResult
176  moveResult.shapeToUpdate = moveOperation->shapeToMove;
177  // check if we're moving an entire shape or only certain geometry point
178  if (moveOperation->geometryPointsToMove.empty()) {
179  // move entire shape
180  for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
181  if (geometryPointIndex != Position::INVALID) {
182  // add offset
183  geometryPointIndex.add(offset);
184  // apply snap to active grid
185  geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
186  } else {
187  throw ProcessError("trying to move an invalid position");
188  }
189  }
190  } else {
191  // only move certain geometry points
192  for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
193  if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
194  // add offset
195  moveResult.shapeToUpdate[geometryPointIndex].add(offset);
196  // apply snap to active grid
197  moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
198  } else {
199  throw ProcessError("trying to move an invalid position");
200  }
201  }
202  // remove double points (only in commitMove)
203  if (moveResult.shapeToUpdate.size() > 2) {
204  moveResult.shapeToUpdate.removeDoublePoints(2);
205  }
206  }
207  }
208  // commit move shape
209  moveOperation->moveElement->commitMoveShape(moveResult, undoList);
210 }
211 
212 
213 const PositionVector
214 GNEMoveElement::calculateMovementOverLane(const GNEViewNet* viewNet, const GNEMoveOperation* moveOperation, const Position& offset) {
215  // declare new shape
216  PositionVector newShape;
217  // calculate lenght between pos over lanes
218  const double centralPosition = (moveOperation->originalPosOverLanes.front() + moveOperation->originalPosOverLanes.back()) * 0.5;
219  // calculate middle lenght between first and last pos over lanes
220  const double middleLenght = std::abs(moveOperation->originalPosOverLanes.back() - moveOperation->originalPosOverLanes.front()) * 0.5;
221  // get lane length
222  const double laneLengt = moveOperation->lane->getParentEdge()->getNBEdge()->getFinalLength() * moveOperation->lane->getLengthGeometryFactor();
223  // declare position over lane offset
224  double posOverLaneOffset = 0;
225  // calculate position at offset given by centralPosition
226  Position lanePositionAtCentralPosition = moveOperation->lane->getLaneShape().positionAtOffset2D(centralPosition);
227  // apply offset to positionAtCentralPosition
228  lanePositionAtCentralPosition.add(offset);
229  // snap to grid
230  lanePositionAtCentralPosition = viewNet->snapToActiveGrid(lanePositionAtCentralPosition);
231  // calculate new posOverLane perpendicular
232  const double newPosOverLanePerpendicular = moveOperation->lane->getLaneShape().nearest_offset_to_point2D(lanePositionAtCentralPosition);
233  // calculate posOverLaneOffset
234  if (newPosOverLanePerpendicular == -1) {
235  // calculate new posOverLane non-perpendicular
236  const double newPosOverLane = moveOperation->lane->getLaneShape().nearest_offset_to_point2D(lanePositionAtCentralPosition, false);
237  // out of lane shape, then place element in lane extremes
238  if (newPosOverLane == 0) {
239  posOverLaneOffset = moveOperation->originalPosOverLanes.front();
240  } else {
241  posOverLaneOffset = moveOperation->originalPosOverLanes.back() - laneLengt;
242  }
243  } else {
244  // within of lane shape
245  if ((newPosOverLanePerpendicular - middleLenght) < 0) {
246  posOverLaneOffset = moveOperation->originalPosOverLanes.front();
247  } else if ((newPosOverLanePerpendicular + middleLenght) > laneLengt) {
248  posOverLaneOffset = moveOperation->originalPosOverLanes.back() - laneLengt;
249  } else {
250  posOverLaneOffset = centralPosition - newPosOverLanePerpendicular;
251  }
252  }
253  // apply posOverLaneOffset to all posOverLanes and generate new shape
254  for (const auto& posOverlane : moveOperation->originalPosOverLanes) {
255  newShape.push_back(Position(posOverlane - posOverLaneOffset, 0));
256  }
257  // return newShape
258  return newShape;
259 }
260 
261 /****************************************************************************/
NBEdge * getNBEdge() const
returns the internal NBEdge
Definition: GNEEdge.cpp:399
This lane is powered by an underlying GNEEdge and basically knows how to draw itself.
Definition: GNELane.h:45
const PositionVector & getLaneShape() const
Definition: GNELane.cpp:117
double getLengthGeometryFactor() const
get length geometry factor
Definition: GNELane.cpp:1615
GNEEdge * getParentEdge() const
get arent edge
Definition: GNELane.cpp:111
move element
virtual void setMoveShape(const GNEMoveResult &moveResult)=0
set move shape
static const PositionVector calculateMovementOverLane(const GNEViewNet *viewNet, const GNEMoveOperation *moveOperation, const Position &offset)
calculate movement over lane
GNEMoveElement()
constructor
static void commitMove(const GNEViewNet *viewNet, GNEMoveOperation *moveOperation, const Position &offset, GNEUndoList *undoList)
commit move element for the given offset
virtual void commitMoveShape(const GNEMoveResult &moveResult, GNEUndoList *undoList)=0
commit move shape
static void moveElement(const GNEViewNet *viewNet, GNEMoveOperation *moveOperation, const Position &offset)
move element the for given offset (note: offset can be X-Y-0, 0-0-Z or X-Y-Z)
move operation
const PositionVector originalShape
original shape
const std::vector< int > originalGeometryPoints
original shape points to move (of original shape)
const PositionVector shapeToMove
shape to move
const std::vector< double > originalPosOverLanes
original position over lanes
GNEMoveOperation(GNEMoveElement *moveElement, const Position originalPosition)
constructor for values with a single position (junctions, E3, ParkingSpaces...)
~GNEMoveOperation()
destructor
const GNELane * lane
original lane
const std::vector< int > geometryPointsToMove
shape points to move (of shapeToMove)
GNEMoveElement * moveElement
move element
move result
~GNEMoveResult()
destructor
GNEMoveResult()
constructor
std::vector< int > geometryPointsToMove
shape points to move (of shapeToMove)
PositionVector shapeToUpdate
shape to update (edited in moveElement)
Position snapToActiveGrid(const Position &pos, bool snapXY=true) const
Returns a position that is mapped to the closest grid point if the grid is active.
double getFinalLength() const
get length that will be assigned to the lanes in the final network
Definition: NBEdge.cpp:3954
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:36
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:282
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:124
A list of positions.
void add(double xoff, double yoff, double zoff)
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.