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-2022 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
23#include "GNEMoveElement.h"
24
25
26// ===========================================================================
27// GNEMoveOperation method definitions
28// ===========================================================================
29
31 const Position _originalPosition) :
32 moveElement(_moveElement),
33 originalShape({_originalPosition}),
34 shapeToMove({_originalPosition}),
35 allowChangeLane(false),
36 firstGeometryPoint(false),
37operationType(OperationType::POSITION) {
38}
39
40
42 const PositionVector _originalShape) :
43 moveElement(_moveElement),
44 originalShape(_originalShape),
45 shapeToMove(_originalShape),
46 allowChangeLane(false),
47 firstGeometryPoint(false),
48 operationType(OperationType::ENTIRE_SHAPE) {
49}
50
52 const PositionVector _originalShape,
53 const bool _firstGeometryPoint,
54 const OperationType _operationType) :
55 moveElement(_moveElement),
56 originalShape(_originalShape),
57 shapeToMove(_originalShape),
58 allowChangeLane(false),
59 firstGeometryPoint(_firstGeometryPoint),
60 operationType(_operationType) {
61}
62
64 const PositionVector _originalShape,
65 const std::vector<int> _originalgeometryPoints,
66 const PositionVector _shapeToMove,
67 const std::vector<int> _geometryPointsToMove) :
68 moveElement(_moveElement),
69 originalShape(_originalShape),
70 originalGeometryPoints(_originalgeometryPoints),
71 shapeToMove(_shapeToMove),
72 geometryPointsToMove(_geometryPointsToMove),
73 allowChangeLane(false),
74 firstGeometryPoint(false),
75 operationType(OperationType::GEOMETRY_POINTS) {
76}
77
78
80 const GNELane* _lane,
81 const double _firstPosition,
82 const bool _allowChangeLane) :
83 moveElement(_moveElement),
84 firstLane(_lane),
85 firstPosition(_firstPosition * _lane->getLengthGeometryFactor()),
86 allowChangeLane(_allowChangeLane),
87 firstGeometryPoint(false),
88 operationType(OperationType::ONE_LANE) {
89}
90
91
93 const GNELane* _lane,
94 const double _firstPosition,
95 const double _secondPosition,
96 const bool _allowChangeLane,
97 const OperationType _operationType) :
98 moveElement(_moveElement),
99 firstLane(_lane),
100 firstPosition(_firstPosition * _lane->getLengthGeometryFactor()),
101 secondPosition(_secondPosition * _lane->getLengthGeometryFactor()),
102 allowChangeLane(_allowChangeLane),
103 firstGeometryPoint(false),
104 operationType(_operationType) {
105}
106
107
109 const GNELane* _firstLane,
110 const double _firstStartPos,
111 const GNELane* _secondLane,
112 const double _secondStartPos,
113 const bool _allowChangeLane,
114 const OperationType _operationType) :
115 moveElement(_moveElement),
116 firstLane(_firstLane),
117 firstPosition((_firstStartPos != INVALID_DOUBLE) ? _firstStartPos * _firstLane->getLengthGeometryFactor() : INVALID_DOUBLE),
118 secondLane(_secondLane),
119 secondPosition((_secondStartPos != INVALID_DOUBLE) ? _secondStartPos * _secondLane->getLengthGeometryFactor() : INVALID_DOUBLE),
120 allowChangeLane(_allowChangeLane),
121 firstGeometryPoint(false),
122 operationType(_operationType) {
123}
124
125
127
128// ===========================================================================
129// GNEMoveOffset method definitions
130// ===========================================================================
131
133 x(0),
134 y(0),
135 z(0) {
136}
137
138
139GNEMoveOffset::GNEMoveOffset(const double x_, const double y_) :
140 x(x_),
141 y(y_),
142 z(0) {
143}
144
145
147 x(0),
148 y(0),
149 z(z_) {
150}
151
152
154
155// ===========================================================================
156// GNEMoveResult method definitions
157// ===========================================================================
158
160 operationType(moveOperation->operationType),
161 firstLaneOffset(0),
162 newFirstLane(nullptr),
163 newFirstPos(0),
164 secondLaneOffset(0),
165 newSecondLane(nullptr),
166 newSecondPos(0) {}
167
168
170
171
172void
174 firstLaneOffset = 0;
175 newFirstLane = nullptr;
177 newSecondLane = nullptr;
178}
179
180// ===========================================================================
181// GNEMoveElement method definitions
182// ===========================================================================
183
185 myMoveElementLateralOffset(0) {
186}
187
188
190GNEMoveElement::calculateMoveShapeOperation(const PositionVector originalShape, const Position mousePosition, const double snapRadius, const bool onlyContour) {
191 // calculate squared snapRadius
192 const double squaredSnapRadius = (snapRadius * snapRadius);
193 // declare shape to move
194 PositionVector shapeToMove = originalShape;
195 // obtain nearest index
196 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
197 // obtain nearest position
198 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
199 // check conditions
200 if (nearestIndex == -1) {
201 return nullptr;
202 } else if (nearestPosition == Position::INVALID) {
203 // special case for extremes
204 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
205 // move extrem without creating new geometry point
206 return new GNEMoveOperation(this, originalShape, {nearestIndex}, shapeToMove, {nearestIndex});
207 } else {
208 return nullptr;
209 }
210 } else if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
211 // move geometry point without creating new geometry point
212 return new GNEMoveOperation(this, originalShape, {nearestIndex}, shapeToMove, {nearestIndex});
213 } else if (!onlyContour || nearestPosition.distanceSquaredTo2D(mousePosition) <= squaredSnapRadius) {
214 // create new geometry point and keep new index (if we clicked near of shape)
215 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
216 // move after setting new geometry point in shapeToMove
217 return new GNEMoveOperation(this, originalShape, {nearestIndex}, shapeToMove, {newIndex});
218 } else {
219 return nullptr;
220 }
221}
222
223
224void
225GNEMoveElement::moveElement(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset) {
226 // declare move result
227 GNEMoveResult moveResult(moveOperation);
228 // set geometry points to move
229 moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
230 // check if we're moving over a lane shape, an entire shape or only certain geometry point
231 if (moveOperation->firstLane) {
232 // calculate movement over lane
233 if (moveOperation->secondLane) {
234 // continue depending of operationType
236 // move only first position
237 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
238 0, moveOperation->firstLane->getLaneShapeLength());
240 // move only second position
241 calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset,
242 0, moveOperation->secondLane->getLaneShapeLength());
243 } else {
244 // adjust positions
245 adjustBothPositions(viewNet, moveOperation, moveResult, offset);
246 }
247 } else {
249 // move first position around the entire lane
250 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
251 0, moveOperation->firstLane->getLaneShapeLength());
253 // move first position around [0, secondPosition]
254 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
255 0, moveOperation->secondPosition);
257 // move first position around [firstPosition, laneLength]
258 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->secondPosition, offset,
259 moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
260 } else {
261 // move both first and second positions
262 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
263 moveOperation->secondPosition, offset);
264 }
265 // calculate new lane
266 if (moveOperation->allowChangeLane) {
267 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
268 } else {
269 moveResult.clearLanes();
270 }
271 }
272 } else if (moveOperation->geometryPointsToMove.size() > 0) {
273 // set values in moveResult
274 moveResult.shapeToUpdate = moveOperation->shapeToMove;
275 // move geometry points
276 for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
277 if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
278 // add offset
279 moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
280 // apply snap to active grid
281 moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
282 } else {
283 throw ProcessError("trying to move an invalid position");
284 }
285 }
286 } else {
287 // set values in moveResult
288 moveResult.shapeToUpdate = moveOperation->shapeToMove;
289 // move entire shape
290 for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
291 if (geometryPointIndex != Position::INVALID) {
292 // add offset
293 geometryPointIndex.add(offset.x, offset.y, offset.z);
294 // apply snap to active grid
295 geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
296 } else {
297 throw ProcessError("trying to move an invalid position");
298 }
299 }
300 // check if we're adjusting width or height
304 // calculate extrapolate vector
305 moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
306 }
307 }
308 // move shape element
309 moveOperation->moveElement->setMoveShape(moveResult);
310}
311
312
313void
314GNEMoveElement::commitMove(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset, GNEUndoList* undoList) {
315 // declare move result
316 GNEMoveResult moveResult(moveOperation);
317 // check if we're moving over a lane shape, an entire shape or only certain geometry point
318 if (moveOperation->firstLane) {
319 // calculate original move result
320 moveResult.newFirstLane = moveOperation->firstLane;
321 moveResult.newFirstPos = moveOperation->firstPosition;
322 moveResult.newSecondLane = moveOperation->secondLane;
323 moveResult.newSecondPos = moveOperation->secondPosition;
324 // set original positions in element
325 moveOperation->moveElement->setMoveShape(moveResult);
326 // calculate movement over lane
327 if (moveOperation->secondLane) {
329 // move only first position
330 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
331 0, moveOperation->firstLane->getLaneShapeLength());
333 // move only two position
334 calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset,
335 0, moveOperation->secondLane->getLaneShapeLength());
336 } else {
337 // adjust positions
338 adjustBothPositions(viewNet, moveOperation, moveResult, offset);
339 }
340 // calculate new lane
341 if (moveOperation->allowChangeLane) {
342 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
343 calculateNewLane(viewNet, moveOperation->secondLane, moveResult.newSecondLane, moveResult.secondLaneOffset);
344 } else {
345 moveResult.clearLanes();
346 }
347 // calculate new lane
348 if (moveOperation->allowChangeLane) {
349 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
350 calculateNewLane(viewNet, moveOperation->secondLane, moveResult.newSecondLane, moveResult.secondLaneOffset);
351 } else {
352 moveResult.clearLanes();
353 }
354 } else {
356 // move first position around the entire lane
357 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
358 0, moveOperation->firstLane->getLaneShapeLength());
360 // move first position around [0, secondPosition]
361 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
362 0, moveOperation->secondPosition);
364 // move first position around [firstPosition, laneLength]
365 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->secondPosition, offset,
366 moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
367 } else {
368 // move both first and second positions
369 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
370 moveOperation->secondPosition, offset);
371 }
372 // calculate new lane
373 if (moveOperation->allowChangeLane) {
374 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
375 } else {
376 moveResult.clearLanes();
377 }
378 // calculate new lane
379 if (moveOperation->allowChangeLane) {
380 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
381 } else {
382 moveResult.clearLanes();
383 }
384 }
385 } else {
386 // set original geometry points to move
387 moveResult.geometryPointsToMove = moveOperation->originalGeometryPoints;
388 // set shapeToUpdate with originalPosOverLanes
389 moveResult.shapeToUpdate = moveOperation->originalShape;
390 // first restore original geometry geometry
391 moveOperation->moveElement->setMoveShape(moveResult);
392 // set new geometry points to move
393 moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
394 // set values in moveResult
395 moveResult.shapeToUpdate = moveOperation->shapeToMove;
396 // check if we're moving an entire shape or only certain geometry point
397 if (moveOperation->geometryPointsToMove.size() > 0) {
398 // only move certain geometry points
399 for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
400 if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
401 // add offset
402 moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
403 // apply snap to active grid
404 moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
405 } else {
406 throw ProcessError("trying to move an invalid position");
407 }
408 }
409 // remove double points (only in commitMove)
410 if (moveResult.shapeToUpdate.size() > 2) {
411 moveResult.shapeToUpdate.removeDoublePoints(2);
412 }
413 } else {
414 // move entire shape
415 for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
416 if (geometryPointIndex != Position::INVALID) {
417 // add offset
418 geometryPointIndex.add(offset.x, offset.y, offset.z);
419 // apply snap to active grid
420 geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
421 } else {
422 throw ProcessError("trying to move an invalid position");
423 }
424 }
425 // check if we're adjusting width or height
429 // calculate extrapolate vector
430 moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
431 }
432 }
433 }
434 // commit move shape
435 moveOperation->moveElement->commitMoveShape(moveResult, undoList);
436}
437
438
439double
440GNEMoveElement::calculateLaneOffset(const GNEViewNet* viewNet, const GNELane* lane, const double firstPosition, const double secondPosition,
441 const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
442 // declare laneOffset
443 double laneOffset = 0;
444 // calculate central position between two given positions
445 const double offsetCentralPosition = (firstPosition + secondPosition) * 0.5;
446 // calculate middle length between two given positions
447 const double middleLength = std::abs(secondPosition - firstPosition) * 0.5;
448 // calculate lane position at offset given by offsetCentralPosition
449 Position laneCentralPosition = lane->getLaneShape().positionAtOffset2D(offsetCentralPosition);
450 // apply offset to positionAtCentralPosition
451 laneCentralPosition.add(offset.x, offset.y, offset.z);
452 // snap to grid
453 laneCentralPosition = viewNet->snapToActiveGrid(laneCentralPosition);
454 // calculate offset over lane using laneCentralPosition
455 const double offsetLaneCentralPositionPerpendicular = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition);
456 // check if offset is within lane shape
457 if (offsetLaneCentralPositionPerpendicular == -1) {
458 // calculate non-perpendicular offset over lane using laneCentralPosition
459 const double offsetLaneCentralPosition = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition, false);
460 // due laneCentralPosition is out of lane shape, then place positions in extremes
461 if (offsetLaneCentralPosition == 0) {
462 laneOffset = firstPosition;
463 } else {
464 laneOffset = secondPosition - lane->getLaneShape().length2D();
465 }
466 } else {
467 // laneCentralPosition is within of lane shapen, then calculate offset using middlelength
468 if ((offsetLaneCentralPositionPerpendicular - middleLength) < extremFrom) {
469 laneOffset = firstPosition + extremFrom;
470 } else if ((offsetLaneCentralPositionPerpendicular + middleLength) > extremTo) {
471 laneOffset = secondPosition - extremTo;
472 } else {
473 laneOffset = (offsetCentralPosition - offsetLaneCentralPositionPerpendicular);
474 }
475 }
476 return laneOffset;
477}
478
479
480void
482 const double pos, const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
483 // get lane offset
484 const double laneOffset = calculateLaneOffset(viewNet, lane, pos, pos, offset, extremFrom, extremTo);
485 // update moveResult
486 moveResult.newFirstPos = (pos - laneOffset) / lane->getLengthGeometryFactor();
487 moveResult.newSecondPos = 0;
488}
489
490
491void
493 const double firstPos, const double secondPos, const GNEMoveOffset& offset) {
494 // get lane offset
495 const double laneOffset = calculateLaneOffset(viewNet, lane, firstPos, secondPos, offset, 0, lane->getLaneShape().length2D());
496 // update moveResult
497 moveResult.newFirstPos = (firstPos - laneOffset) / lane->getLengthGeometryFactor();
498 moveResult.newSecondPos = (secondPos - laneOffset) / lane->getLengthGeometryFactor();
499}
500
501
502void
503GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* firstLane,
504 const double firstPos, const GNELane* secondLane, const double secondPos, const GNEMoveOffset& offset) {
505 // get lane offset of the first lane
506 const double laneOffset = calculateLaneOffset(viewNet, firstLane, firstPos, firstPos, offset, secondLane->getLaneShape().length2D() - firstPos, firstLane->getLaneShape().length2D());
507 // update moveResult
508 moveResult.newFirstPos = (firstPos - laneOffset) / firstLane->getLengthGeometryFactor();
509 moveResult.newSecondPos = (secondPos - laneOffset) / firstLane->getLengthGeometryFactor();
510}
511
512
513void
514GNEMoveElement::calculateNewLane(const GNEViewNet* viewNet, const GNELane* originalLane, const GNELane*& newLane, double& laneOffset) {
515 // get cursor position
516 const Position cursorPosition = viewNet->getPositionInformation();
517 // iterate over edge lanes
518 for (const auto& lane : originalLane->getParentEdge()->getLanes()) {
519 // avoid moveOperation lane
520 if (lane != originalLane) {
521 // calculate offset over lane shape
522 const double offSet = lane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
523 // calculate position over lane shape
524 const Position posOverLane = lane->getLaneShape().positionAtOffset2D(offSet);
525 // check distance
526 if (posOverLane.distanceSquaredTo2D(cursorPosition) < 1) {
527 // update newlane
528 newLane = lane;
529 // calculate offset over moveOperation lane
530 const double offsetMoveOperationLane = originalLane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
531 // calculate position over moveOperation lane
532 const Position posOverMoveOperationLane = originalLane->getLaneShape().positionAtOffset2D(offsetMoveOperationLane);
533 // update moveResult of laneOffset
534 laneOffset = posOverLane.distanceTo2D(posOverMoveOperationLane);
535 // change sign of moveResult laneOffset depending of lane index
536 if (originalLane->getIndex() < newLane->getIndex()) {
537 laneOffset *= -1;
538 }
539 }
540 }
541 }
542}
543
544
545void
546GNEMoveElement::adjustBothPositions(const GNEViewNet* viewNet, const GNEMoveOperation* moveOperation, GNEMoveResult& moveResult, const GNEMoveOffset& offset) {
547 // get lane shape lengths
548 const double firstLaneLength = moveOperation->firstLane->getLaneShapeLength();
549 const double secondLaneLength = moveOperation->secondLane->getLaneShapeLength();
551 // move only first position
552 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset, 0, firstLaneLength);
553 // calculate second position
554 moveResult.newSecondPos = (moveOperation->secondPosition - (moveOperation->firstPosition - moveResult.newFirstPos));
555 // adjust positions
556 if (moveResult.newSecondPos < 0) {
557 moveResult.newFirstPos = (moveOperation->firstPosition - moveOperation->secondPosition);
558 moveResult.newSecondPos = 0;
559 } else if (moveResult.newSecondPos > secondLaneLength) {
560 moveResult.newFirstPos = (moveOperation->firstPosition + (secondLaneLength - moveOperation->secondPosition));
561 moveResult.newSecondPos = secondLaneLength;
562 }
564 // move only second position
565 calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset, 0, secondLaneLength);
566 // swap (because move results is always stored in newFirstPos)
567 moveResult.newSecondPos = moveResult.newFirstPos;
568 moveResult.newFirstPos = 0;
569 // calculate first position
570 moveResult.newFirstPos = (moveOperation->firstPosition - (moveOperation->secondPosition - moveResult.newSecondPos));
571 // adjust positions
572 if (moveResult.newFirstPos < 0) {
573 moveResult.newSecondPos = (moveOperation->secondPosition - moveOperation->firstPosition);
574 moveResult.newFirstPos = 0;
575 } else if (moveResult.newFirstPos > firstLaneLength) {
576 moveResult.newSecondPos = (moveOperation->secondPosition + (firstLaneLength - moveOperation->firstPosition));
577 moveResult.newFirstPos = firstLaneLength;
578 }
579 } else {
580 throw ProcessError("Invalid move operationType");
581 }
582}
583
584
587 // get original shape half length
588 const double halfLength = moveOperation->originalShape.length2D() * -0.5;
589 // get original shape and extrapolate
590 PositionVector extendedShape = moveOperation->originalShape;
591 extendedShape.extrapolate2D(10e5);
592 // get geometry point
593 const Position geometryPoint = moveOperation->firstGeometryPoint ? moveResult.shapeToUpdate.front() : moveResult.shapeToUpdate.back();
594 // calculate offsets to first and last positions
595 const double offset = extendedShape.nearest_offset_to_point2D(geometryPoint, false);
596 // calculate extrapolate value
597 double extrapolateValue = (10e5 - offset);
598 // adjust extrapolation
599 if (moveOperation->firstGeometryPoint) {
600 if (extrapolateValue < halfLength) {
601 extrapolateValue = (halfLength - POSITION_EPS);
602 }
603 } else {
604 if (extrapolateValue > halfLength) {
605 extrapolateValue = (halfLength - POSITION_EPS);
606 }
607 }
608 // restore shape in in moveResult
609 PositionVector extrapolatedShape = moveOperation->shapeToMove;
610 // extrapolate
611 extrapolatedShape.extrapolate2D(extrapolateValue);
612 // check if return reverse
613 if (moveOperation->firstGeometryPoint) {
614 return extrapolatedShape;
615 } else {
616 return extrapolatedShape.reverse();
617 }
618}
619
620/****************************************************************************/
const double INVALID_DOUBLE
Definition: StdDefs.h:60
const std::vector< GNELane * > & getLanes() const
returns a reference to the lane vector
Definition: GNEEdge.cpp:839
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:142
double getLengthGeometryFactor() const
get length geometry factor
Definition: GNELane.cpp:1807
int getIndex() const
returns the index of the lane
Definition: GNELane.cpp:876
double getLaneShapeLength() const
returns the length of the lane's shape
Definition: GNELane.cpp:905
GNEEdge * getParentEdge() const
get parent edge
Definition: GNELane.cpp:124
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
GNEMoveOperation * calculateMoveShapeOperation(const PositionVector originalShape, const Position mousePosition, const double snapRadius, const bool onlyContour)
calculate move shape operation
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
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)
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
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.
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:257
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:298
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:252
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:125
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.