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.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
18 // Class used for move shape elements
19 /****************************************************************************/
21 #include <netedit/GNEViewNet.h>
22 #include <netedit/GNEViewParent.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  allowChangeLane(false),
38  firstGeometryPoint(false),
39 operationType(OperationType::POSITION) {
40 }
41 
42 
44  const PositionVector _originalShape) :
45  moveElement(_moveElement),
46  originalShape(_originalShape),
47  shapeToMove(_originalShape),
48  allowChangeLane(false),
49  firstGeometryPoint(false),
50  operationType(OperationType::ENTIRE_SHAPE) {
51 }
52 
54  const PositionVector _originalShape,
55  const bool _firstGeometryPoint,
56  const OperationType _operationType) :
57  moveElement(_moveElement),
58  originalShape(_originalShape),
59  shapeToMove(_originalShape),
60  allowChangeLane(false),
61  firstGeometryPoint(_firstGeometryPoint),
62  operationType(_operationType) {
63 }
64 
66  const PositionVector _originalShape,
67  const std::vector<int> _originalgeometryPoints,
68  const PositionVector _shapeToMove,
69  const std::vector<int> _geometryPointsToMove) :
70  moveElement(_moveElement),
71  originalShape(_originalShape),
72  originalGeometryPoints(_originalgeometryPoints),
73  shapeToMove(_shapeToMove),
74  geometryPointsToMove(_geometryPointsToMove),
75  allowChangeLane(false),
76  firstGeometryPoint(false),
77  operationType(OperationType::GEOMETRY_POINTS) {
78 }
79 
80 
82  const GNELane* _lane,
83  const double _firstPosition,
84  const bool _allowChangeLane) :
85  moveElement(_moveElement),
86  firstLane(_lane),
87  firstPosition(_firstPosition * _lane->getLengthGeometryFactor()),
88  allowChangeLane(_allowChangeLane),
89  firstGeometryPoint(false),
90  operationType(OperationType::ONE_LANE) {
91 }
92 
93 
95  const GNELane* _lane,
96  const double _firstPosition,
97  const double _secondPosition,
98  const bool _allowChangeLane,
99  const OperationType _operationType) :
100  moveElement(_moveElement),
101  firstLane(_lane),
102  firstPosition(_firstPosition * _lane->getLengthGeometryFactor()),
103  secondPosition(_secondPosition * _lane->getLengthGeometryFactor()),
104  allowChangeLane(_allowChangeLane),
105  firstGeometryPoint(false),
106  operationType(_operationType) {
107 }
108 
109 
111  const GNELane* _firstLane,
112  const double _firstStartPos,
113  const GNELane* _secondLane,
114  const double _secondStartPos,
115  const bool _allowChangeLane,
116  const OperationType _operationType) :
117  moveElement(_moveElement),
118  firstLane(_firstLane),
119  firstPosition((_firstStartPos != INVALID_DOUBLE) ? _firstStartPos * _firstLane->getLengthGeometryFactor() : INVALID_DOUBLE),
120  secondLane(_secondLane),
121  secondPosition((_secondStartPos != INVALID_DOUBLE) ? _secondStartPos * _secondLane->getLengthGeometryFactor() : INVALID_DOUBLE),
122  allowChangeLane(_allowChangeLane),
123  firstGeometryPoint(false),
124  operationType(_operationType) {
125 }
126 
127 
129 
130 // ===========================================================================
131 // GNEMoveOffset method definitions
132 // ===========================================================================
133 
135  x(0),
136  y(0),
137  z(0) {
138 }
139 
140 
141 GNEMoveOffset::GNEMoveOffset(const double x_, const double y_) :
142  x(x_),
143  y(y_),
144  z(0) {
145 }
146 
147 
149  x(0),
150  y(0),
151  z(z_) {
152 }
153 
154 
156 
157 // ===========================================================================
158 // GNEMoveResult method definitions
159 // ===========================================================================
160 
162  operationType(moveOperation->operationType),
163  firstLaneOffset(0),
164  newFirstLane(nullptr),
165  newFirstPos(0),
166  secondLaneOffset(0),
167  newSecondLane(nullptr),
168  newSecondPos(0) {}
169 
170 
172 
173 
174 void
176  firstLaneOffset = 0;
177  newFirstLane = nullptr;
178  secondLaneOffset = 0;
179  newSecondLane = nullptr;
180 }
181 
182 // ===========================================================================
183 // GNEMoveElement method definitions
184 // ===========================================================================
185 
187  myMoveElementLateralOffset(0) {
188 }
189 
190 
193  const bool maintainShapeClosed) {
194  // get moved geometry points
195  const auto geometryPoints = gViewObjectsHandler.getGeometryPoints(obj);
196  // get pos over shape
197  const auto posOverShape = gViewObjectsHandler.getPositionOverShape(obj);
198  // declare shape to move
199  PositionVector shapeToMove = originalShape;
200  const int lastIndex = (int)shapeToMove.size() - 1;
201  // check if move existent geometry points or create new
202  if (geometryPoints.size() > 0) {
203  // move geometry point without creating new geometry point
204  if (maintainShapeClosed && ((geometryPoints.front() == 0) || (geometryPoints.front() == lastIndex))) {
205  // move first and last point
206  return new GNEMoveOperation(this, originalShape, {0, lastIndex}, shapeToMove, {0, lastIndex});
207  } else {
208  return new GNEMoveOperation(this, originalShape, {geometryPoints.front()}, shapeToMove, {geometryPoints.front()});
209  }
210  } else if (posOverShape != Position::INVALID) {
211  // create new geometry point and keep new index (if we clicked near of shape)
212  const int newIndex = shapeToMove.insertAtClosest(posOverShape, true);
213  return new GNEMoveOperation(this, originalShape, {shapeToMove.indexOfClosest(posOverShape)}, shapeToMove, {newIndex});
214  } else {
215  return nullptr;
216  }
217 }
218 
219 
220 void
221 GNEMoveElement::moveElement(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset) {
222  // declare move result
223  GNEMoveResult moveResult(moveOperation);
224  // set geometry points to move
225  moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
226  // check if we're moving over a lane shape, an entire shape or only certain geometry point
227  if (moveOperation->firstLane) {
228  // calculate movement over lane
229  if (moveOperation->secondLane) {
230  // continue depending of operationType
232  // move only first position
233  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
234  0, moveOperation->firstLane->getLaneShapeLength());
236  // move only second position
237  calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset,
238  0, moveOperation->secondLane->getLaneShapeLength());
239  } else {
240  // adjust positions
241  adjustBothPositions(viewNet, moveOperation, moveResult, offset);
242  }
243  } else {
245  // move first position around the entire lane
246  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
247  0, moveOperation->firstLane->getLaneShapeLength());
249  // move first position around [0, secondPosition]
250  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
251  0, moveOperation->secondPosition);
253  // move first position around [firstPosition, laneLength]
254  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->secondPosition, offset,
255  moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
256  } else {
257  // move both first and second positions
258  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
259  moveOperation->secondPosition, offset);
260  }
261  // calculate new lane
262  if (moveOperation->allowChangeLane) {
263  calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
264  } else {
265  moveResult.clearLanes();
266  }
267  }
268  } else if (moveOperation->geometryPointsToMove.size() > 0) {
269  // set values in moveResult
270  moveResult.shapeToUpdate = moveOperation->shapeToMove;
271  // move geometry points
272  for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
273  if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
274  // add offset
275  moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
276  // apply snap to active grid
277  moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
278  } else {
279  throw ProcessError("trying to move an invalid position");
280  }
281  }
282  } else {
283  // set values in moveResult
284  moveResult.shapeToUpdate = moveOperation->shapeToMove;
285  // move entire shape
286  for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
287  if (geometryPointIndex != Position::INVALID) {
288  // add offset
289  geometryPointIndex.add(offset.x, offset.y, offset.z);
290  // apply snap to active grid
291  geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
292  } else {
293  throw ProcessError("trying to move an invalid position");
294  }
295  }
296  // check if we're adjusting width or height
297  if ((moveOperation->operationType == GNEMoveOperation::OperationType::WIDTH) ||
300  // calculate extrapolate vector
301  moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
302  }
303  }
304  // move shape element
305  moveOperation->moveElement->setMoveShape(moveResult);
306 }
307 
308 
309 void
310 GNEMoveElement::commitMove(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset, GNEUndoList* undoList) {
311  // declare move result
312  GNEMoveResult moveResult(moveOperation);
313  // check if we're moving over a lane shape, an entire shape or only certain geometry point
314  if (moveOperation->firstLane) {
315  // calculate original move result
316  moveResult.newFirstLane = moveOperation->firstLane;
317  moveResult.newFirstPos = moveOperation->firstPosition;
318  moveResult.newSecondLane = moveOperation->secondLane;
319  moveResult.newSecondPos = moveOperation->secondPosition;
320  // set original positions in element
321  moveOperation->moveElement->setMoveShape(moveResult);
322  // calculate movement over lane
323  if (moveOperation->secondLane) {
325  // move only first position
326  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
327  0, moveOperation->firstLane->getLaneShapeLength());
329  // move only two position
330  calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset,
331  0, moveOperation->secondLane->getLaneShapeLength());
332  } else {
333  // adjust positions
334  adjustBothPositions(viewNet, moveOperation, moveResult, offset);
335  }
336  // calculate new lane
337  if (moveOperation->allowChangeLane) {
338  calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
339  calculateNewLane(viewNet, moveOperation->secondLane, moveResult.newSecondLane, moveResult.secondLaneOffset);
340  } else {
341  moveResult.clearLanes();
342  }
343  // calculate new lane
344  if (moveOperation->allowChangeLane) {
345  calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
346  calculateNewLane(viewNet, moveOperation->secondLane, moveResult.newSecondLane, moveResult.secondLaneOffset);
347  } else {
348  moveResult.clearLanes();
349  }
350  } else {
352  // move first position around the entire lane
353  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
354  0, moveOperation->firstLane->getLaneShapeLength());
356  // move first position around [0, secondPosition]
357  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
358  0, moveOperation->secondPosition);
360  // move first position around [firstPosition, laneLength]
361  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->secondPosition, offset,
362  moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
363  } else {
364  // move both first and second positions
365  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
366  moveOperation->secondPosition, offset);
367  }
368  // calculate new lane
369  if (moveOperation->allowChangeLane) {
370  calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
371  } else {
372  moveResult.clearLanes();
373  }
374  // calculate new lane
375  if (moveOperation->allowChangeLane) {
376  calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
377  } else {
378  moveResult.clearLanes();
379  }
380  }
381  } else {
382  // set original geometry points to move
383  moveResult.geometryPointsToMove = moveOperation->originalGeometryPoints;
384  // set shapeToUpdate with originalPosOverLanes
385  moveResult.shapeToUpdate = moveOperation->originalShape;
386  // first restore original geometry geometry
387  moveOperation->moveElement->setMoveShape(moveResult);
388  // set new geometry points to move
389  moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
390  // set values in moveResult
391  moveResult.shapeToUpdate = moveOperation->shapeToMove;
392  // check if we're moving an entire shape or only certain geometry point
393  if (moveOperation->geometryPointsToMove.size() > 0) {
394  // only move certain geometry points
395  for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
396  if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
397  // add offset
398  moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
399  // apply snap to active grid
400  moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
401  } else {
402  throw ProcessError("trying to move an invalid position");
403  }
404  }
405  // remove double points if merge points is enabled (only in commitMove)
406  if (viewNet->getViewParent()->getMoveFrame()->getCommonModeOptions()->getMergeGeometryPoints() && (moveResult.shapeToUpdate.size() > 2)) {
407  moveResult.shapeToUpdate.removeDoublePoints(2);
408  }
409  } else {
410  // move entire shape
411  for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
412  if (geometryPointIndex != Position::INVALID) {
413  // add offset
414  geometryPointIndex.add(offset.x, offset.y, offset.z);
415  // apply snap to active grid
416  geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
417  } else {
418  throw ProcessError("trying to move an invalid position");
419  }
420  }
421  // check if we're adjusting width or height
422  if ((moveOperation->operationType == GNEMoveOperation::OperationType::WIDTH) ||
425  // calculate extrapolate vector
426  moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
427  }
428  }
429  }
430  // commit move shape
431  moveOperation->moveElement->commitMoveShape(moveResult, undoList);
432 }
433 
434 
435 double
436 GNEMoveElement::calculateLaneOffset(const GNEViewNet* viewNet, const GNELane* lane, const double firstPosition, const double secondPosition,
437  const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
438  // declare laneOffset
439  double laneOffset = 0;
440  // calculate central position between two given positions
441  const double offsetCentralPosition = (firstPosition + secondPosition) * 0.5;
442  // calculate middle length between two given positions
443  const double middleLength = std::abs(secondPosition - firstPosition) * 0.5;
444  // calculate lane position at offset given by offsetCentralPosition
445  Position laneCentralPosition = lane->getLaneShape().positionAtOffset2D(offsetCentralPosition);
446  // apply offset to positionAtCentralPosition
447  laneCentralPosition.add(offset.x, offset.y, offset.z);
448  // snap to grid
449  laneCentralPosition = viewNet->snapToActiveGrid(laneCentralPosition);
450  // calculate offset over lane using laneCentralPosition
451  const double offsetLaneCentralPositionPerpendicular = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition);
452  // check if offset is within lane shape
453  if (offsetLaneCentralPositionPerpendicular == -1) {
454  // calculate non-perpendicular offset over lane using laneCentralPosition
455  const double offsetLaneCentralPosition = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition, false);
456  // due laneCentralPosition is out of lane shape, then place positions in extremes
457  if (offsetLaneCentralPosition == 0) {
458  laneOffset = firstPosition;
459  } else {
460  laneOffset = secondPosition - lane->getLaneShape().length2D();
461  }
462  } else {
463  // laneCentralPosition is within of lane shapen, then calculate offset using middlelength
464  if ((offsetLaneCentralPositionPerpendicular - middleLength) < extremFrom) {
465  laneOffset = firstPosition + extremFrom;
466  } else if ((offsetLaneCentralPositionPerpendicular + middleLength) > extremTo) {
467  laneOffset = secondPosition - extremTo;
468  } else {
469  laneOffset = (offsetCentralPosition - offsetLaneCentralPositionPerpendicular);
470  }
471  }
472  return laneOffset;
473 }
474 
475 
476 void
477 GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* lane,
478  const double pos, const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
479  // get lane offset
480  const double laneOffset = calculateLaneOffset(viewNet, lane, pos, pos, offset, extremFrom, extremTo);
481  // update moveResult
482  moveResult.newFirstPos = (pos - laneOffset) / lane->getLengthGeometryFactor();
483  moveResult.newSecondPos = 0;
484 }
485 
486 
487 void
488 GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* lane,
489  const double firstPos, const double secondPos, const GNEMoveOffset& offset) {
490  // get lane offset
491  const double laneOffset = calculateLaneOffset(viewNet, lane, firstPos, secondPos, offset, 0, lane->getLaneShape().length2D());
492  // update moveResult
493  moveResult.newFirstPos = (firstPos - laneOffset) / lane->getLengthGeometryFactor();
494  moveResult.newSecondPos = (secondPos - laneOffset) / lane->getLengthGeometryFactor();
495 }
496 
497 
498 void
499 GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* firstLane,
500  const double firstPos, const GNELane* secondLane, const double secondPos, const GNEMoveOffset& offset) {
501  // get lane offset of the first lane
502  const double laneOffset = calculateLaneOffset(viewNet, firstLane, firstPos, firstPos, offset, secondLane->getLaneShape().length2D() - firstPos, firstLane->getLaneShape().length2D());
503  // update moveResult
504  moveResult.newFirstPos = (firstPos - laneOffset) / firstLane->getLengthGeometryFactor();
505  moveResult.newSecondPos = (secondPos - laneOffset) / firstLane->getLengthGeometryFactor();
506 }
507 
508 
509 void
510 GNEMoveElement::calculateNewLane(const GNEViewNet* viewNet, const GNELane* originalLane, const GNELane*& newLane, double& laneOffset) {
511  // get cursor position
512  const Position cursorPosition = viewNet->getPositionInformation();
513  // iterate over edge lanes
514  for (const auto& lane : originalLane->getParentEdge()->getLanes()) {
515  // avoid moveOperation lane
516  if (lane != originalLane) {
517  // calculate offset over lane shape
518  const double offSet = lane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
519  // calculate position over lane shape
520  const Position posOverLane = lane->getLaneShape().positionAtOffset2D(offSet);
521  // check distance
522  if (posOverLane.distanceSquaredTo2D(cursorPosition) < 1) {
523  // update newlane
524  newLane = lane;
525  // calculate offset over moveOperation lane
526  const double offsetMoveOperationLane = originalLane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
527  // calculate position over moveOperation lane
528  const Position posOverMoveOperationLane = originalLane->getLaneShape().positionAtOffset2D(offsetMoveOperationLane);
529  // update moveResult of laneOffset
530  laneOffset = posOverLane.distanceTo2D(posOverMoveOperationLane);
531  // change sign of moveResult laneOffset depending of lane index
532  if (originalLane->getIndex() < newLane->getIndex()) {
533  laneOffset *= -1;
534  }
535  }
536  }
537  }
538 }
539 
540 
541 void
542 GNEMoveElement::adjustBothPositions(const GNEViewNet* viewNet, const GNEMoveOperation* moveOperation, GNEMoveResult& moveResult, const GNEMoveOffset& offset) {
543  // get lane shape lengths
544  const double firstLaneLength = moveOperation->firstLane->getLaneShapeLength();
545  const double secondLaneLength = moveOperation->secondLane->getLaneShapeLength();
547  // move only first position
548  calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset, 0, firstLaneLength);
549  // calculate second position
550  moveResult.newSecondPos = (moveOperation->secondPosition - (moveOperation->firstPosition - moveResult.newFirstPos));
551  // adjust positions
552  if (moveResult.newSecondPos < 0) {
553  moveResult.newFirstPos = (moveOperation->firstPosition - moveOperation->secondPosition);
554  moveResult.newSecondPos = 0;
555  } else if (moveResult.newSecondPos > secondLaneLength) {
556  moveResult.newFirstPos = (moveOperation->firstPosition + (secondLaneLength - moveOperation->secondPosition));
557  moveResult.newSecondPos = secondLaneLength;
558  }
560  // move only second position
561  calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset, 0, secondLaneLength);
562  // swap (because move results is always stored in newFirstPos)
563  moveResult.newSecondPos = moveResult.newFirstPos;
564  moveResult.newFirstPos = 0;
565  // calculate first position
566  moveResult.newFirstPos = (moveOperation->firstPosition - (moveOperation->secondPosition - moveResult.newSecondPos));
567  // adjust positions
568  if (moveResult.newFirstPos < 0) {
569  moveResult.newSecondPos = (moveOperation->secondPosition - moveOperation->firstPosition);
570  moveResult.newFirstPos = 0;
571  } else if (moveResult.newFirstPos > firstLaneLength) {
572  moveResult.newSecondPos = (moveOperation->secondPosition + (firstLaneLength - moveOperation->firstPosition));
573  moveResult.newFirstPos = firstLaneLength;
574  }
575  } else {
576  throw ProcessError("Invalid move operationType");
577  }
578 }
579 
580 
583  // get original shape half length
584  const double halfLength = moveOperation->originalShape.length2D() * -0.5;
585  // get original shape and extrapolate
586  PositionVector extendedShape = moveOperation->originalShape;
587  extendedShape.extrapolate2D(10e5);
588  // get geometry point
589  const Position geometryPoint = moveOperation->firstGeometryPoint ? moveResult.shapeToUpdate.front() : moveResult.shapeToUpdate.back();
590  // calculate offsets to first and last positions
591  const double offset = extendedShape.nearest_offset_to_point2D(geometryPoint, false);
592  // calculate extrapolate value
593  double extrapolateValue = (10e5 - offset);
594  // adjust extrapolation
595  if (moveOperation->firstGeometryPoint) {
596  if (extrapolateValue < halfLength) {
597  extrapolateValue = (halfLength - POSITION_EPS);
598  }
599  } else {
600  if (extrapolateValue > halfLength) {
601  extrapolateValue = (halfLength - POSITION_EPS);
602  }
603  }
604  // restore shape in in moveResult
605  PositionVector extrapolatedShape = moveOperation->shapeToMove;
606  // extrapolate
607  extrapolatedShape.extrapolate2D(extrapolateValue);
608  // check if return reverse
609  if (moveOperation->firstGeometryPoint) {
610  return extrapolatedShape;
611  } else {
612  return extrapolatedShape.reverse();
613  }
614 }
615 
616 /****************************************************************************/
GUIViewObjectsHandler gViewObjectsHandler
const double INVALID_DOUBLE
invalid double
Definition: StdDefs.h:64
const std::vector< GNELane * > & getLanes() const
returns a reference to the lane vector
Definition: GNEEdge.cpp:1047
This lane is powered by an underlying GNEEdge and basically knows how to draw itself.
Definition: GNELane.h:46
const PositionVector & getLaneShape() const
get elements shape
Definition: GNELane.cpp:214
double getLengthGeometryFactor() const
get length geometry factor
Definition: GNELane.cpp:1964
int getIndex() const
returns the index of the lane
Definition: GNELane.cpp:642
double getLaneShapeLength() const
returns the length of the lane's shape
Definition: GNELane.cpp:672
GNEEdge * getParentEdge() const
get parent edge
Definition: GNELane.cpp:196
move element
static PositionVector calculateExtrapolatedVector(const GNEMoveOperation *moveOperation, const GNEMoveResult &moveResult)
calculate width/height shape
static void adjustBothPositions(const GNEViewNet *viewNet, const GNEMoveOperation *moveOperation, GNEMoveResult &moveResult, const GNEMoveOffset &offset)
virtual void setMoveShape(const GNEMoveResult &moveResult)=0
set move shape
GNEMoveElement()
constructor
static void calculateMoveResult(GNEMoveResult &moveResult, const GNEViewNet *viewNet, const GNELane *lane, const double pos, const GNEMoveOffset &offset, const double extremFrom, const double extremTo)
calculate single movement over one lane
static void commitMove(const GNEViewNet *viewNet, GNEMoveOperation *moveOperation, const GNEMoveOffset &offset, GNEUndoList *undoList)
commit move element for the given offset
static double calculateLaneOffset(const GNEViewNet *viewNet, const GNELane *lane, const double firstPosition, const double secondPosition, const GNEMoveOffset &offset, const double extremFrom, const double extremTo)
calculate lane offset
virtual void commitMoveShape(const GNEMoveResult &moveResult, GNEUndoList *undoList)=0
commit move shape
GNEMoveOperation * calculateMoveShapeOperation(const GUIGlObject *obj, const PositionVector originalShape, const bool maintainShapeClosed)
calculate move shape operation
static void calculateNewLane(const GNEViewNet *viewNet, const GNELane *originalLane, const GNELane *&newLane, double &laneOffset)
calculate new lane
static void moveElement(const GNEViewNet *viewNet, GNEMoveOperation *moveOperation, const GNEMoveOffset &offset)
move element the for given offset (note: offset can be X-Y-0, 0-0-Z or X-Y-Z)
bool getMergeGeometryPoints() const
check if merge geometry points
CommonModeOptions * getCommonModeOptions() const
get common mode options
move offset
const double z
Z.
const double x
X.
const double y
Y.
GNEMoveOffset()
constructor
~GNEMoveOffset()
destructor
move operation
const OperationType operationType
operation type
const PositionVector originalShape
original shape
const std::vector< int > originalGeometryPoints
original shape points to move (of original shape)
const PositionVector shapeToMove
shape to move
GNEMoveOperation(GNEMoveElement *moveElement, const Position originalPosition)
constructor for values with a single position (junctions, E3, ParkingSpaces...)
~GNEMoveOperation()
destructor
const double secondPosition
original second Position
const GNELane * firstLane
original first lane
const GNELane * secondLane
original second lane
const std::vector< int > geometryPointsToMove
shape points to move (of shapeToMove)
const double firstPosition
original first Position
const bool allowChangeLane
allow change lane
GNEMoveElement * moveElement
move element
const bool firstGeometryPoint
first position (used for edit with/height
move result
const GNELane * newFirstLane
new first Lane
double newFirstPos
new first position
GNEMoveResult(const GNEMoveOperation *moveOperation)
constructor
~GNEMoveResult()
destructor
const GNELane * newSecondLane
new second Lane
void clearLanes()
clear lanes
double firstLaneOffset
lane offset
std::vector< int > geometryPointsToMove
shape points to move (of shapeToMove)
double newSecondPos
new second position
PositionVector shapeToUpdate
shape to update (edited in moveElement)
double secondLaneOffset
lane offset
GNEViewParent * getViewParent() const
get the net object
GNEMoveFrame * getMoveFrame() const
get frame for move elements
Position snapToActiveGrid(const Position &pos, bool snapXY=true) const
Returns a position that is mapped to the closest grid point if the grid is active.
virtual Position getPositionInformation() const
Returns the cursor's x/y position within the network.
const std::vector< int > & getGeometryPoints(const GUIGlObject *GLObject) const
get geometry points for the given glObject
const Position & getPositionOverShape(const GUIGlObject *GLObject) const
get position over shape
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
double distanceSquaredTo2D(const Position &p2) const
returns the square of the distance to another position (Only using x and y positions)
Definition: Position.h:276
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:317
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:271
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:132
A list of positions.
double length2D() const
Returns the length.
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
int indexOfClosest(const Position &p, bool twoD=false) const
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
int insertAtClosest(const Position &p, bool interpolateZ)
inserts p between the two closest positions
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false, int beginOffset=0, int endOffset=0, bool resample=false)
Removes positions if too near.
PositionVector reverse() const
reverse position vector
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.