Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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-2023 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>
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),
39operationType(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
141GNEMoveOffset::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
174void
176 firstLaneOffset = 0;
177 newFirstLane = nullptr;
179 newSecondLane = nullptr;
180}
181
182// ===========================================================================
183// GNEMoveElement method definitions
184// ===========================================================================
185
187 myMoveElementLateralOffset(0) {
188}
189
190
192GNEMoveElement::calculateMoveShapeOperation(const PositionVector originalShape, const Position mousePosition, const double snapRadius, const bool onlyContour) {
193 // calculate squared snapRadius
194 const double squaredSnapRadius = (snapRadius * snapRadius);
195 // declare shape to move
196 PositionVector shapeToMove = originalShape;
197 // obtain nearest index
198 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
199 // obtain nearest position
200 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
201 // check conditions
202 if (nearestIndex == -1) {
203 return nullptr;
204 } else if (nearestPosition == Position::INVALID) {
205 // special case for extremes
206 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
207 // move extrem without creating new geometry point
208 return new GNEMoveOperation(this, originalShape, {nearestIndex}, shapeToMove, {nearestIndex});
209 } else {
210 return nullptr;
211 }
212 } else if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
213 // move geometry point without creating new geometry point
214 return new GNEMoveOperation(this, originalShape, {nearestIndex}, shapeToMove, {nearestIndex});
215 } else if (!onlyContour || nearestPosition.distanceSquaredTo2D(mousePosition) <= squaredSnapRadius) {
216 // create new geometry point and keep new index (if we clicked near of shape)
217 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
218 // move after setting new geometry point in shapeToMove
219 return new GNEMoveOperation(this, originalShape, {nearestIndex}, shapeToMove, {newIndex});
220 } else {
221 return nullptr;
222 }
223}
224
225
226void
227GNEMoveElement::moveElement(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset) {
228 // declare move result
229 GNEMoveResult moveResult(moveOperation);
230 // set geometry points to move
231 moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
232 // check if we're moving over a lane shape, an entire shape or only certain geometry point
233 if (moveOperation->firstLane) {
234 // calculate movement over lane
235 if (moveOperation->secondLane) {
236 // continue depending of operationType
238 // move only first position
239 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
240 0, moveOperation->firstLane->getLaneShapeLength());
242 // move only second position
243 calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset,
244 0, moveOperation->secondLane->getLaneShapeLength());
245 } else {
246 // adjust positions
247 adjustBothPositions(viewNet, moveOperation, moveResult, offset);
248 }
249 } else {
251 // move first position around the entire lane
252 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
253 0, moveOperation->firstLane->getLaneShapeLength());
255 // move first position around [0, secondPosition]
256 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
257 0, moveOperation->secondPosition);
259 // move first position around [firstPosition, laneLength]
260 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->secondPosition, offset,
261 moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
262 } else {
263 // move both first and second positions
264 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
265 moveOperation->secondPosition, offset);
266 }
267 // calculate new lane
268 if (moveOperation->allowChangeLane) {
269 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
270 } else {
271 moveResult.clearLanes();
272 }
273 }
274 } else if (moveOperation->geometryPointsToMove.size() > 0) {
275 // set values in moveResult
276 moveResult.shapeToUpdate = moveOperation->shapeToMove;
277 // move geometry points
278 for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
279 if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
280 // add offset
281 moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
282 // apply snap to active grid
283 moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
284 } else {
285 throw ProcessError("trying to move an invalid position");
286 }
287 }
288 } else {
289 // set values in moveResult
290 moveResult.shapeToUpdate = moveOperation->shapeToMove;
291 // move entire shape
292 for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
293 if (geometryPointIndex != Position::INVALID) {
294 // add offset
295 geometryPointIndex.add(offset.x, offset.y, offset.z);
296 // apply snap to active grid
297 geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
298 } else {
299 throw ProcessError("trying to move an invalid position");
300 }
301 }
302 // check if we're adjusting width or height
306 // calculate extrapolate vector
307 moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
308 }
309 }
310 // move shape element
311 moveOperation->moveElement->setMoveShape(moveResult);
312}
313
314
315void
316GNEMoveElement::commitMove(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset, GNEUndoList* undoList) {
317 // declare move result
318 GNEMoveResult moveResult(moveOperation);
319 // check if we're moving over a lane shape, an entire shape or only certain geometry point
320 if (moveOperation->firstLane) {
321 // calculate original move result
322 moveResult.newFirstLane = moveOperation->firstLane;
323 moveResult.newFirstPos = moveOperation->firstPosition;
324 moveResult.newSecondLane = moveOperation->secondLane;
325 moveResult.newSecondPos = moveOperation->secondPosition;
326 // set original positions in element
327 moveOperation->moveElement->setMoveShape(moveResult);
328 // calculate movement over lane
329 if (moveOperation->secondLane) {
331 // move only first position
332 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
333 0, moveOperation->firstLane->getLaneShapeLength());
335 // move only two position
336 calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset,
337 0, moveOperation->secondLane->getLaneShapeLength());
338 } else {
339 // adjust positions
340 adjustBothPositions(viewNet, moveOperation, moveResult, offset);
341 }
342 // calculate new lane
343 if (moveOperation->allowChangeLane) {
344 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
345 calculateNewLane(viewNet, moveOperation->secondLane, moveResult.newSecondLane, moveResult.secondLaneOffset);
346 } else {
347 moveResult.clearLanes();
348 }
349 // calculate new lane
350 if (moveOperation->allowChangeLane) {
351 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
352 calculateNewLane(viewNet, moveOperation->secondLane, moveResult.newSecondLane, moveResult.secondLaneOffset);
353 } else {
354 moveResult.clearLanes();
355 }
356 } else {
358 // move first position around the entire lane
359 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
360 0, moveOperation->firstLane->getLaneShapeLength());
362 // move first position around [0, secondPosition]
363 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
364 0, moveOperation->secondPosition);
366 // move first position around [firstPosition, laneLength]
367 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->secondPosition, offset,
368 moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
369 } else {
370 // move both first and second positions
371 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
372 moveOperation->secondPosition, offset);
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 // calculate new lane
381 if (moveOperation->allowChangeLane) {
382 calculateNewLane(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
383 } else {
384 moveResult.clearLanes();
385 }
386 }
387 } else {
388 // set original geometry points to move
389 moveResult.geometryPointsToMove = moveOperation->originalGeometryPoints;
390 // set shapeToUpdate with originalPosOverLanes
391 moveResult.shapeToUpdate = moveOperation->originalShape;
392 // first restore original geometry geometry
393 moveOperation->moveElement->setMoveShape(moveResult);
394 // set new geometry points to move
395 moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
396 // set values in moveResult
397 moveResult.shapeToUpdate = moveOperation->shapeToMove;
398 // check if we're moving an entire shape or only certain geometry point
399 if (moveOperation->geometryPointsToMove.size() > 0) {
400 // only move certain geometry points
401 for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
402 if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
403 // add offset
404 moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
405 // apply snap to active grid
406 moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
407 } else {
408 throw ProcessError("trying to move an invalid position");
409 }
410 }
411 // remove double points if merge points is enabled (only in commitMove)
412 if (viewNet->getViewParent()->getMoveFrame()->getCommonModeOptions()->getMergeGeometryPoints() && (moveResult.shapeToUpdate.size() > 2)) {
413 moveResult.shapeToUpdate.removeDoublePoints(2);
414 }
415 } else {
416 // move entire shape
417 for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
418 if (geometryPointIndex != Position::INVALID) {
419 // add offset
420 geometryPointIndex.add(offset.x, offset.y, offset.z);
421 // apply snap to active grid
422 geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
423 } else {
424 throw ProcessError("trying to move an invalid position");
425 }
426 }
427 // check if we're adjusting width or height
431 // calculate extrapolate vector
432 moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
433 }
434 }
435 }
436 // commit move shape
437 moveOperation->moveElement->commitMoveShape(moveResult, undoList);
438}
439
440
441double
442GNEMoveElement::calculateLaneOffset(const GNEViewNet* viewNet, const GNELane* lane, const double firstPosition, const double secondPosition,
443 const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
444 // declare laneOffset
445 double laneOffset = 0;
446 // calculate central position between two given positions
447 const double offsetCentralPosition = (firstPosition + secondPosition) * 0.5;
448 // calculate middle length between two given positions
449 const double middleLength = std::abs(secondPosition - firstPosition) * 0.5;
450 // calculate lane position at offset given by offsetCentralPosition
451 Position laneCentralPosition = lane->getLaneShape().positionAtOffset2D(offsetCentralPosition);
452 // apply offset to positionAtCentralPosition
453 laneCentralPosition.add(offset.x, offset.y, offset.z);
454 // snap to grid
455 laneCentralPosition = viewNet->snapToActiveGrid(laneCentralPosition);
456 // calculate offset over lane using laneCentralPosition
457 const double offsetLaneCentralPositionPerpendicular = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition);
458 // check if offset is within lane shape
459 if (offsetLaneCentralPositionPerpendicular == -1) {
460 // calculate non-perpendicular offset over lane using laneCentralPosition
461 const double offsetLaneCentralPosition = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition, false);
462 // due laneCentralPosition is out of lane shape, then place positions in extremes
463 if (offsetLaneCentralPosition == 0) {
464 laneOffset = firstPosition;
465 } else {
466 laneOffset = secondPosition - lane->getLaneShape().length2D();
467 }
468 } else {
469 // laneCentralPosition is within of lane shapen, then calculate offset using middlelength
470 if ((offsetLaneCentralPositionPerpendicular - middleLength) < extremFrom) {
471 laneOffset = firstPosition + extremFrom;
472 } else if ((offsetLaneCentralPositionPerpendicular + middleLength) > extremTo) {
473 laneOffset = secondPosition - extremTo;
474 } else {
475 laneOffset = (offsetCentralPosition - offsetLaneCentralPositionPerpendicular);
476 }
477 }
478 return laneOffset;
479}
480
481
482void
484 const double pos, const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
485 // get lane offset
486 const double laneOffset = calculateLaneOffset(viewNet, lane, pos, pos, offset, extremFrom, extremTo);
487 // update moveResult
488 moveResult.newFirstPos = (pos - laneOffset) / lane->getLengthGeometryFactor();
489 moveResult.newSecondPos = 0;
490}
491
492
493void
495 const double firstPos, const double secondPos, const GNEMoveOffset& offset) {
496 // get lane offset
497 const double laneOffset = calculateLaneOffset(viewNet, lane, firstPos, secondPos, offset, 0, lane->getLaneShape().length2D());
498 // update moveResult
499 moveResult.newFirstPos = (firstPos - laneOffset) / lane->getLengthGeometryFactor();
500 moveResult.newSecondPos = (secondPos - laneOffset) / lane->getLengthGeometryFactor();
501}
502
503
504void
505GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* firstLane,
506 const double firstPos, const GNELane* secondLane, const double secondPos, const GNEMoveOffset& offset) {
507 // get lane offset of the first lane
508 const double laneOffset = calculateLaneOffset(viewNet, firstLane, firstPos, firstPos, offset, secondLane->getLaneShape().length2D() - firstPos, firstLane->getLaneShape().length2D());
509 // update moveResult
510 moveResult.newFirstPos = (firstPos - laneOffset) / firstLane->getLengthGeometryFactor();
511 moveResult.newSecondPos = (secondPos - laneOffset) / firstLane->getLengthGeometryFactor();
512}
513
514
515void
516GNEMoveElement::calculateNewLane(const GNEViewNet* viewNet, const GNELane* originalLane, const GNELane*& newLane, double& laneOffset) {
517 // get cursor position
518 const Position cursorPosition = viewNet->getPositionInformation();
519 // iterate over edge lanes
520 for (const auto& lane : originalLane->getParentEdge()->getLanes()) {
521 // avoid moveOperation lane
522 if (lane != originalLane) {
523 // calculate offset over lane shape
524 const double offSet = lane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
525 // calculate position over lane shape
526 const Position posOverLane = lane->getLaneShape().positionAtOffset2D(offSet);
527 // check distance
528 if (posOverLane.distanceSquaredTo2D(cursorPosition) < 1) {
529 // update newlane
530 newLane = lane;
531 // calculate offset over moveOperation lane
532 const double offsetMoveOperationLane = originalLane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
533 // calculate position over moveOperation lane
534 const Position posOverMoveOperationLane = originalLane->getLaneShape().positionAtOffset2D(offsetMoveOperationLane);
535 // update moveResult of laneOffset
536 laneOffset = posOverLane.distanceTo2D(posOverMoveOperationLane);
537 // change sign of moveResult laneOffset depending of lane index
538 if (originalLane->getIndex() < newLane->getIndex()) {
539 laneOffset *= -1;
540 }
541 }
542 }
543 }
544}
545
546
547void
548GNEMoveElement::adjustBothPositions(const GNEViewNet* viewNet, const GNEMoveOperation* moveOperation, GNEMoveResult& moveResult, const GNEMoveOffset& offset) {
549 // get lane shape lengths
550 const double firstLaneLength = moveOperation->firstLane->getLaneShapeLength();
551 const double secondLaneLength = moveOperation->secondLane->getLaneShapeLength();
553 // move only first position
554 calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset, 0, firstLaneLength);
555 // calculate second position
556 moveResult.newSecondPos = (moveOperation->secondPosition - (moveOperation->firstPosition - moveResult.newFirstPos));
557 // adjust positions
558 if (moveResult.newSecondPos < 0) {
559 moveResult.newFirstPos = (moveOperation->firstPosition - moveOperation->secondPosition);
560 moveResult.newSecondPos = 0;
561 } else if (moveResult.newSecondPos > secondLaneLength) {
562 moveResult.newFirstPos = (moveOperation->firstPosition + (secondLaneLength - moveOperation->secondPosition));
563 moveResult.newSecondPos = secondLaneLength;
564 }
566 // move only second position
567 calculateMoveResult(moveResult, viewNet, moveOperation->secondLane, moveOperation->secondPosition, offset, 0, secondLaneLength);
568 // swap (because move results is always stored in newFirstPos)
569 moveResult.newSecondPos = moveResult.newFirstPos;
570 moveResult.newFirstPos = 0;
571 // calculate first position
572 moveResult.newFirstPos = (moveOperation->firstPosition - (moveOperation->secondPosition - moveResult.newSecondPos));
573 // adjust positions
574 if (moveResult.newFirstPos < 0) {
575 moveResult.newSecondPos = (moveOperation->secondPosition - moveOperation->firstPosition);
576 moveResult.newFirstPos = 0;
577 } else if (moveResult.newFirstPos > firstLaneLength) {
578 moveResult.newSecondPos = (moveOperation->secondPosition + (firstLaneLength - moveOperation->firstPosition));
579 moveResult.newFirstPos = firstLaneLength;
580 }
581 } else {
582 throw ProcessError("Invalid move operationType");
583 }
584}
585
586
589 // get original shape half length
590 const double halfLength = moveOperation->originalShape.length2D() * -0.5;
591 // get original shape and extrapolate
592 PositionVector extendedShape = moveOperation->originalShape;
593 extendedShape.extrapolate2D(10e5);
594 // get geometry point
595 const Position geometryPoint = moveOperation->firstGeometryPoint ? moveResult.shapeToUpdate.front() : moveResult.shapeToUpdate.back();
596 // calculate offsets to first and last positions
597 const double offset = extendedShape.nearest_offset_to_point2D(geometryPoint, false);
598 // calculate extrapolate value
599 double extrapolateValue = (10e5 - offset);
600 // adjust extrapolation
601 if (moveOperation->firstGeometryPoint) {
602 if (extrapolateValue < halfLength) {
603 extrapolateValue = (halfLength - POSITION_EPS);
604 }
605 } else {
606 if (extrapolateValue > halfLength) {
607 extrapolateValue = (halfLength - POSITION_EPS);
608 }
609 }
610 // restore shape in in moveResult
611 PositionVector extrapolatedShape = moveOperation->shapeToMove;
612 // extrapolate
613 extrapolatedShape.extrapolate2D(extrapolateValue);
614 // check if return reverse
615 if (moveOperation->firstGeometryPoint) {
616 return extrapolatedShape;
617 } else {
618 return extrapolatedShape.reverse();
619 }
620}
621
622/****************************************************************************/
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:840
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:136
double getLengthGeometryFactor() const
get length geometry factor
Definition GNELane.cpp:1824
int getIndex() const
returns the index of the lane
Definition GNELane.cpp:788
double getLaneShapeLength() const
returns the length of the lane's shape
Definition GNELane.cpp:817
GNEEdge * getParentEdge() const
get parent edge
Definition GNELane.cpp:118
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)
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.
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:259
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:300
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:254
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.