Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/GNEMoveElement.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
/****************************************************************************/
14
/// @file GNEMoveElement.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Mar 2020
17
///
18
// Class used for move shape elements
19
/****************************************************************************/
20
21
#include <netedit/changes/GNEChange_Attribute.h>
22
#include <netedit/GNEViewNet.h>
23
#include <netedit/GNEViewParent.h>
24
#include <netedit/frames/common/GNEMoveFrame.h>
25
26
#include "GNEMoveElement.h"
27
28
// ===========================================================================
29
// GNEMoveOperation method definitions
30
// ===========================================================================
31
32
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
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
43
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
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
53
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
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
65
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
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
81
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
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::SINGLE_LANE) {
91
}
92
93
94
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
95
const GNELane* _lane,
96
const double _firstPosition,
97
const double _lastPosition,
98
const bool _allowChangeLane,
99
const OperationType _operationType) :
100
moveElement(_moveElement),
101
firstLane(_lane),
102
firstPosition(_firstPosition * _lane->getLengthGeometryFactor()),
103
lastPosition(_lastPosition * _lane->getLengthGeometryFactor()),
104
allowChangeLane(_allowChangeLane),
105
firstGeometryPoint(false),
106
operationType(_operationType) {
107
}
108
109
110
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
111
const GNELane* _firstLane,
112
const double _firstStartPos,
113
const GNELane* _lastLane,
114
const double _lastStartPos,
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
lastLane(_lastLane),
121
lastPosition((_lastStartPos != INVALID_DOUBLE) ? _lastStartPos * _lastLane->getLengthGeometryFactor() : INVALID_DOUBLE),
122
allowChangeLane(_allowChangeLane),
123
firstGeometryPoint(false),
124
operationType(_operationType) {
125
}
126
127
128
GNEMoveOperation::~GNEMoveOperation() {}
129
130
// ===========================================================================
131
// GNEMoveOffset method definitions
132
// ===========================================================================
133
134
GNEMoveOffset::GNEMoveOffset() :
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
148
GNEMoveOffset::GNEMoveOffset(const double z_) :
149
x(0),
150
y(0),
151
z(z_) {
152
}
153
154
155
GNEMoveOffset::~GNEMoveOffset() {}
156
157
// ===========================================================================
158
// GNEMoveResult method definitions
159
// ===========================================================================
160
161
GNEMoveResult::GNEMoveResult(const GNEMoveOperation* moveOperation) :
162
operationType(moveOperation->operationType),
163
firstLaneOffset(0),
164
newFirstLane(nullptr),
165
newFirstPos(0),
166
lastLaneOffset(0),
167
newLastLane(nullptr),
168
newLastPos(0) {}
169
170
171
GNEMoveResult::~GNEMoveResult() {}
172
173
174
void
175
GNEMoveResult::clearLanes() {
176
firstLaneOffset = 0;
177
newFirstLane = nullptr;
178
lastLaneOffset = 0;
179
newLastLane = nullptr;
180
}
181
182
// ===========================================================================
183
// GNEMoveElement method definitions
184
// ===========================================================================
185
186
GNEMoveElement::GNEMoveElement() :
187
myMoveElementLateralOffset(0) {
188
}
189
190
191
GNEMoveOperation*
192
GNEMoveElement::calculateMoveShapeOperation(const GUIGlObject* obj, const PositionVector originalShape,
193
const bool maintainShapeClosed) {
194
// get moved geometry points
195
const auto geometryPoints = gViewObjectsHandler.getSelectedGeometryPoints(obj);
196
// get pos over shape
197
const auto posOverShape = gViewObjectsHandler.getSelectedPositionOverShape(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->lastLane) {
230
// continue depending of operationType
231
if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_FIRST) ||
232
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_FIRST)) {
233
// move only first position
234
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
235
0, moveOperation->firstLane->getLaneShapeLength());
236
} else if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_LAST) ||
237
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_LAST)) {
238
// move only last position
239
calculateMoveResult(moveResult, viewNet, moveOperation->lastLane, moveOperation->lastPosition, offset,
240
0, moveOperation->lastLane->getLaneShapeLength());
241
}
242
} else {
243
if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE) {
244
// move first position around the entire lane
245
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
246
0, moveOperation->firstLane->getLaneShapeLength());
247
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_FIRST) {
248
// move first position around [0, lastPosition]
249
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
250
0, moveOperation->lastPosition);
251
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_LAST) {
252
// move first position around [firstPosition, laneLength]
253
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->lastPosition, offset,
254
moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
255
} else {
256
// move both first and last positions
257
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
258
moveOperation->lastPosition, offset);
259
}
260
// calculate new lane
261
if (moveOperation->allowChangeLane) {
262
calculateNewLaneChange(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
263
} else {
264
moveResult.clearLanes();
265
}
266
}
267
} else if (moveOperation->geometryPointsToMove.size() > 0) {
268
// set values in moveResult
269
moveResult.shapeToUpdate = moveOperation->shapeToMove;
270
// move geometry points
271
for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
272
if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
273
// add offset
274
moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
275
// apply snap to active grid
276
moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
277
} else {
278
throw ProcessError("trying to move an invalid position");
279
}
280
}
281
} else {
282
// set values in moveResult
283
moveResult.shapeToUpdate = moveOperation->shapeToMove;
284
// move entire shape
285
for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
286
if (geometryPointIndex != Position::INVALID) {
287
// add offset
288
geometryPointIndex.add(offset.x, offset.y, offset.z);
289
// apply snap to active grid
290
geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
291
} else {
292
throw ProcessError("trying to move an invalid position");
293
}
294
}
295
// check if we're adjusting width or height
296
if ((moveOperation->operationType == GNEMoveOperation::OperationType::WIDTH) ||
297
(moveOperation->operationType == GNEMoveOperation::OperationType::HEIGHT) ||
298
(moveOperation->operationType == GNEMoveOperation::OperationType::LENGTH)) {
299
// calculate extrapolate vector
300
moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
301
}
302
}
303
// move shape element
304
moveOperation->moveElement->setMoveShape(moveResult);
305
}
306
307
308
void
309
GNEMoveElement::commitMove(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset, GNEUndoList* undoList) {
310
// declare move result
311
GNEMoveResult moveResult(moveOperation);
312
// check if we're moving over a lane shape, an entire shape or only certain geometry point
313
if (moveOperation->firstLane) {
314
// calculate original move result
315
moveResult.newFirstLane = moveOperation->firstLane;
316
moveResult.newFirstPos = moveOperation->firstPosition;
317
moveResult.newLastLane = moveOperation->lastLane;
318
moveResult.newLastPos = moveOperation->lastPosition;
319
// set original positions in element
320
moveOperation->moveElement->setMoveShape(moveResult);
321
// calculate movement over lane
322
if (moveOperation->lastLane) {
323
if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_FIRST) ||
324
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_FIRST)) {
325
// move only first position
326
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
327
0, moveOperation->firstLane->getLaneShapeLength());
328
} else if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_LAST) ||
329
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_LAST)) {
330
// move only two position
331
calculateMoveResult(moveResult, viewNet, moveOperation->lastLane, moveOperation->lastPosition, offset,
332
0, moveOperation->lastLane->getLaneShapeLength());
333
}
334
// calculate new lane
335
if (moveOperation->allowChangeLane) {
336
calculateNewLaneChange(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
337
calculateNewLaneChange(viewNet, moveOperation->lastLane, moveResult.newLastLane, moveResult.lastLaneOffset);
338
} else {
339
moveResult.clearLanes();
340
}
341
} else {
342
if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE) {
343
// move first position around the entire lane
344
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
345
0, moveOperation->firstLane->getLaneShapeLength());
346
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_FIRST) {
347
// move first position around [0, lastPosition]
348
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
349
0, moveOperation->lastPosition);
350
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_LAST) {
351
// move first position around [firstPosition, laneLength]
352
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->lastPosition, offset,
353
moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
354
} else {
355
// move both first and last positions
356
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
357
moveOperation->lastPosition, offset);
358
}
359
// calculate new lane
360
if (moveOperation->allowChangeLane) {
361
calculateNewLaneChange(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
362
} else {
363
moveResult.clearLanes();
364
}
365
}
366
} else {
367
// set original geometry points to move
368
moveResult.geometryPointsToMove = moveOperation->originalGeometryPoints;
369
// set shapeToUpdate with originalPosOverLanes
370
moveResult.shapeToUpdate = moveOperation->originalShape;
371
// first restore original geometry geometry
372
moveOperation->moveElement->setMoveShape(moveResult);
373
// set new geometry points to move
374
moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
375
// set values in moveResult
376
moveResult.shapeToUpdate = moveOperation->shapeToMove;
377
// check if we're moving an entire shape or only certain geometry point
378
if (moveOperation->geometryPointsToMove.size() > 0) {
379
// only move certain geometry points
380
for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
381
if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
382
// add offset
383
moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
384
// apply snap to active grid
385
moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
386
} else {
387
throw ProcessError("trying to move an invalid position");
388
}
389
}
390
// remove double points if merge points is enabled (only in commitMove)
391
if (viewNet->getViewParent()->getMoveFrame()->getCommonMoveOptions()->getMergeGeometryPoints() && (moveResult.shapeToUpdate.size() > 2)) {
392
moveResult.shapeToUpdate.removeDoublePoints(2);
393
}
394
} else {
395
// move entire shape
396
for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
397
if (geometryPointIndex != Position::INVALID) {
398
// add offset
399
geometryPointIndex.add(offset.x, offset.y, offset.z);
400
// apply snap to active grid
401
geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
402
} else {
403
throw ProcessError("trying to move an invalid position");
404
}
405
}
406
// check if we're adjusting width or height
407
if ((moveOperation->operationType == GNEMoveOperation::OperationType::WIDTH) ||
408
(moveOperation->operationType == GNEMoveOperation::OperationType::HEIGHT) ||
409
(moveOperation->operationType == GNEMoveOperation::OperationType::LENGTH)) {
410
// calculate extrapolate vector
411
moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
412
}
413
}
414
}
415
// commit move shape
416
moveOperation->moveElement->commitMoveShape(moveResult, undoList);
417
}
418
419
420
double
421
GNEMoveElement::calculateLaneOffset(const GNEViewNet* viewNet, const GNELane* lane, const double firstPosition, const double lastPosition,
422
const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
423
// declare laneOffset
424
double laneOffset = 0;
425
// calculate central position between two given positions
426
const double offsetCentralPosition = (firstPosition + lastPosition) * 0.5;
427
// calculate middle length between two given positions
428
const double middleLength = std::abs(lastPosition - firstPosition) * 0.5;
429
// calculate lane position at offset given by offsetCentralPosition
430
Position laneCentralPosition = lane->getLaneShape().positionAtOffset2D(offsetCentralPosition);
431
// apply offset to positionAtCentralPosition
432
laneCentralPosition.add(offset.x, offset.y, offset.z);
433
// snap to grid
434
laneCentralPosition = viewNet->snapToActiveGrid(laneCentralPosition);
435
// calculate offset over lane using laneCentralPosition
436
const double offsetLaneCentralPositionPerpendicular = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition);
437
// check if offset is within lane shape
438
if (offsetLaneCentralPositionPerpendicular == -1) {
439
// calculate non-perpendicular offset over lane using laneCentralPosition
440
const double offsetLaneCentralPosition = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition, false);
441
// due laneCentralPosition is out of lane shape, then place positions in extremes
442
if (offsetLaneCentralPosition == 0) {
443
laneOffset = firstPosition;
444
} else {
445
laneOffset = lastPosition - lane->getLaneShape().length2D();
446
}
447
} else {
448
// laneCentralPosition is within of lane shapen, then calculate offset using middlelength
449
if ((offsetLaneCentralPositionPerpendicular - middleLength) < extremFrom) {
450
laneOffset = firstPosition + extremFrom;
451
} else if ((offsetLaneCentralPositionPerpendicular + middleLength) > extremTo) {
452
laneOffset = lastPosition - extremTo;
453
} else {
454
laneOffset = (offsetCentralPosition - offsetLaneCentralPositionPerpendicular);
455
}
456
}
457
return laneOffset;
458
}
459
460
461
void
462
GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* lane,
463
const double pos, const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
464
// get lane offset
465
const double laneOffset = calculateLaneOffset(viewNet, lane, pos, pos, offset, extremFrom, extremTo);
466
// update moveResult
467
moveResult.newFirstPos = (pos - laneOffset) / lane->getLengthGeometryFactor();
468
moveResult.newLastPos = 0;
469
}
470
471
472
void
473
GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* lane,
474
const double firstPos, const double lastPos, const GNEMoveOffset& offset) {
475
// get lane offset
476
const double laneOffset = calculateLaneOffset(viewNet, lane, firstPos, lastPos, offset, 0, lane->getLaneShape().length2D());
477
// update moveResult
478
moveResult.newFirstPos = (firstPos - laneOffset) / lane->getLengthGeometryFactor();
479
moveResult.newLastPos = (lastPos - laneOffset) / lane->getLengthGeometryFactor();
480
}
481
482
483
void
484
GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* firstLane,
485
const double firstPos, const GNELane* lastLane, const double lastPos, const GNEMoveOffset& offset) {
486
// get lane offset of the first lane
487
const double laneOffset = calculateLaneOffset(viewNet, firstLane, firstPos, firstPos, offset, lastLane->getLaneShape().length2D() - firstPos, firstLane->getLaneShape().length2D());
488
// update moveResult
489
moveResult.newFirstPos = (firstPos - laneOffset) / firstLane->getLengthGeometryFactor();
490
moveResult.newLastPos = (lastPos - laneOffset) / firstLane->getLengthGeometryFactor();
491
}
492
493
494
void
495
GNEMoveElement::calculateNewLaneChange(const GNEViewNet* viewNet, const GNELane* originalLane, const GNELane*& newLane, double& laneOffset) {
496
// get cursor position
497
const Position cursorPosition = viewNet->getPositionInformation();
498
// iterate over edge lanes
499
for (const auto& lane : originalLane->getParentEdge()->getChildLanes()) {
500
// avoid moveOperation lane
501
if (lane != originalLane) {
502
// calculate offset over lane shape
503
const double offSet = lane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
504
// calculate position over lane shape
505
const Position posOverLane = lane->getLaneShape().positionAtOffset2D(offSet);
506
// check distance
507
if (posOverLane.distanceSquaredTo2D(cursorPosition) < 1) {
508
// update newlane
509
newLane = lane;
510
// calculate offset over moveOperation lane
511
const double offsetMoveOperationLane = originalLane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
512
// calculate position over moveOperation lane
513
const Position posOverMoveOperationLane = originalLane->getLaneShape().positionAtOffset2D(offsetMoveOperationLane);
514
// update moveResult of laneOffset
515
laneOffset = posOverLane.distanceTo2D(posOverMoveOperationLane);
516
// change sign of moveResult laneOffset depending of lane index
517
if (originalLane->getIndex() < newLane->getIndex()) {
518
laneOffset *= -1;
519
}
520
}
521
}
522
}
523
}
524
525
526
PositionVector
527
GNEMoveElement::calculateExtrapolatedVector(const GNEMoveOperation* moveOperation, const GNEMoveResult& moveResult) {
528
// get original shape half length
529
const double halfLength = moveOperation->originalShape.length2D() * -0.5;
530
// get original shape and extrapolate
531
PositionVector extendedShape = moveOperation->originalShape;
532
extendedShape.extrapolate2D(10e5);
533
// get geometry point
534
const Position geometryPoint = moveOperation->firstGeometryPoint ? moveResult.shapeToUpdate.front() : moveResult.shapeToUpdate.back();
535
// calculate offsets to first and last positions
536
const double offset = extendedShape.nearest_offset_to_point2D(geometryPoint, false);
537
// calculate extrapolate value
538
double extrapolateValue = (10e5 - offset);
539
// adjust extrapolation
540
if (moveOperation->firstGeometryPoint) {
541
if (extrapolateValue < halfLength) {
542
extrapolateValue = (halfLength - POSITION_EPS);
543
}
544
} else {
545
if (extrapolateValue > halfLength) {
546
extrapolateValue = (halfLength - POSITION_EPS);
547
}
548
}
549
// restore shape in in moveResult
550
PositionVector extrapolatedShape = moveOperation->shapeToMove;
551
// extrapolate
552
extrapolatedShape.extrapolate2D(extrapolateValue);
553
// check if return reverse
554
if (moveOperation->firstGeometryPoint) {
555
return extrapolatedShape;
556
} else {
557
return extrapolatedShape.reverse();
558
}
559
}
560
561
/****************************************************************************/
562
563