#include <netedit/changes/GNEChange_Attribute.h>
#include <netedit/GNEViewNet.h>
#include <netedit/GNEViewParent.h>
#include <netedit/frames/common/GNEMoveFrame.h>
#include "GNEMoveElement.h"
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
const Position _originalPosition) :
moveElement(_moveElement),
originalShape({_originalPosition}),
shapeToMove({_originalPosition}),
allowChangeLane(false),
firstGeometryPoint(false),
operationType(OperationType::POSITION) {
}
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
const PositionVector _originalShape) :
moveElement(_moveElement),
originalShape(_originalShape),
shapeToMove(_originalShape),
allowChangeLane(false),
firstGeometryPoint(false),
operationType(OperationType::ENTIRE_SHAPE) {
}
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
const PositionVector _originalShape,
const bool _firstGeometryPoint,
const OperationType _operationType) :
moveElement(_moveElement),
originalShape(_originalShape),
shapeToMove(_originalShape),
allowChangeLane(false),
firstGeometryPoint(_firstGeometryPoint),
operationType(_operationType) {
}
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
const PositionVector _originalShape,
const std::vector<int> _originalgeometryPoints,
const PositionVector _shapeToMove,
const std::vector<int> _geometryPointsToMove) :
moveElement(_moveElement),
originalShape(_originalShape),
originalGeometryPoints(_originalgeometryPoints),
shapeToMove(_shapeToMove),
geometryPointsToMove(_geometryPointsToMove),
allowChangeLane(false),
firstGeometryPoint(false),
operationType(OperationType::GEOMETRY_POINTS) {
}
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
const GNELane* _lane,
const double _firstPosition,
const bool _allowChangeLane) :
moveElement(_moveElement),
firstLane(_lane),
firstPosition(_firstPosition * _lane->getLengthGeometryFactor()),
allowChangeLane(_allowChangeLane),
firstGeometryPoint(false),
operationType(OperationType::SINGLE_LANE) {
}
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
const GNELane* _lane,
const double _firstPosition,
const double _lastPosition,
const bool _allowChangeLane,
const OperationType _operationType) :
moveElement(_moveElement),
firstLane(_lane),
firstPosition(_firstPosition * _lane->getLengthGeometryFactor()),
lastPosition(_lastPosition * _lane->getLengthGeometryFactor()),
allowChangeLane(_allowChangeLane),
firstGeometryPoint(false),
operationType(_operationType) {
}
GNEMoveOperation::GNEMoveOperation(GNEMoveElement* _moveElement,
const GNELane* _firstLane,
const double _firstStartPos,
const GNELane* _lastLane,
const double _lastStartPos,
const bool _allowChangeLane,
const OperationType _operationType) :
moveElement(_moveElement),
firstLane(_firstLane),
firstPosition((_firstStartPos != INVALID_DOUBLE) ? _firstStartPos * _firstLane->getLengthGeometryFactor() : INVALID_DOUBLE),
lastLane(_lastLane),
lastPosition((_lastStartPos != INVALID_DOUBLE) ? _lastStartPos * _lastLane->getLengthGeometryFactor() : INVALID_DOUBLE),
allowChangeLane(_allowChangeLane),
firstGeometryPoint(false),
operationType(_operationType) {
}
GNEMoveOperation::~GNEMoveOperation() {}
GNEMoveOffset::GNEMoveOffset() :
x(0),
y(0),
z(0) {
}
GNEMoveOffset::GNEMoveOffset(const double x_, const double y_) :
x(x_),
y(y_),
z(0) {
}
GNEMoveOffset::GNEMoveOffset(const double z_) :
x(0),
y(0),
z(z_) {
}
GNEMoveOffset::~GNEMoveOffset() {}
GNEMoveResult::GNEMoveResult(const GNEMoveOperation* moveOperation) :
operationType(moveOperation->operationType),
firstLaneOffset(0),
newFirstLane(nullptr),
newFirstPos(0),
lastLaneOffset(0),
newLastLane(nullptr),
newLastPos(0) {}
GNEMoveResult::~GNEMoveResult() {}
void
GNEMoveResult::clearLanes() {
firstLaneOffset = 0;
newFirstLane = nullptr;
lastLaneOffset = 0;
newLastLane = nullptr;
}
GNEMoveElement::GNEMoveElement() :
myMoveElementLateralOffset(0) {
}
GNEMoveOperation*
GNEMoveElement::calculateMoveShapeOperation(const GUIGlObject* obj, const PositionVector originalShape,
const bool maintainShapeClosed) {
const auto geometryPoints = gViewObjectsHandler.getSelectedGeometryPoints(obj);
const auto posOverShape = gViewObjectsHandler.getSelectedPositionOverShape(obj);
PositionVector shapeToMove = originalShape;
const int lastIndex = (int)shapeToMove.size() - 1;
if (geometryPoints.size() > 0) {
if (maintainShapeClosed && ((geometryPoints.front() == 0) || (geometryPoints.front() == lastIndex))) {
return new GNEMoveOperation(this, originalShape, {0, lastIndex}, shapeToMove, {0, lastIndex});
} else {
return new GNEMoveOperation(this, originalShape, {geometryPoints.front()}, shapeToMove, {geometryPoints.front()});
}
} else if (posOverShape != Position::INVALID) {
const int newIndex = shapeToMove.insertAtClosest(posOverShape, true);
return new GNEMoveOperation(this, originalShape, {shapeToMove.indexOfClosest(posOverShape)}, shapeToMove, {newIndex});
} else {
return nullptr;
}
}
void
GNEMoveElement::moveElement(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset) {
GNEMoveResult moveResult(moveOperation);
moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
if (moveOperation->firstLane) {
if (moveOperation->lastLane) {
if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_FIRST) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_FIRST)) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
0, moveOperation->firstLane->getLaneShapeLength());
} else if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_LAST) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_LAST)) {
calculateMoveResult(moveResult, viewNet, moveOperation->lastLane, moveOperation->lastPosition, offset,
0, moveOperation->lastLane->getLaneShapeLength());
}
} else {
if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
0, moveOperation->firstLane->getLaneShapeLength());
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_FIRST) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
0, moveOperation->lastPosition);
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_LAST) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->lastPosition, offset,
moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
} else {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
moveOperation->lastPosition, offset);
}
if (moveOperation->allowChangeLane) {
calculateNewLaneChange(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
} else {
moveResult.clearLanes();
}
}
} else if (moveOperation->geometryPointsToMove.size() > 0) {
moveResult.shapeToUpdate = moveOperation->shapeToMove;
for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
} else {
throw ProcessError("trying to move an invalid position");
}
}
} else {
moveResult.shapeToUpdate = moveOperation->shapeToMove;
for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
if (geometryPointIndex != Position::INVALID) {
geometryPointIndex.add(offset.x, offset.y, offset.z);
geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
} else {
throw ProcessError("trying to move an invalid position");
}
}
if ((moveOperation->operationType == GNEMoveOperation::OperationType::WIDTH) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::HEIGHT) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::LENGTH)) {
moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
}
}
moveOperation->moveElement->setMoveShape(moveResult);
}
void
GNEMoveElement::commitMove(const GNEViewNet* viewNet, GNEMoveOperation* moveOperation, const GNEMoveOffset& offset, GNEUndoList* undoList) {
GNEMoveResult moveResult(moveOperation);
if (moveOperation->firstLane) {
moveResult.newFirstLane = moveOperation->firstLane;
moveResult.newFirstPos = moveOperation->firstPosition;
moveResult.newLastLane = moveOperation->lastLane;
moveResult.newLastPos = moveOperation->lastPosition;
moveOperation->moveElement->setMoveShape(moveResult);
if (moveOperation->lastLane) {
if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_FIRST) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_FIRST)) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
0, moveOperation->firstLane->getLaneShapeLength());
} else if ((moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_LAST) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_LAST)) {
calculateMoveResult(moveResult, viewNet, moveOperation->lastLane, moveOperation->lastPosition, offset,
0, moveOperation->lastLane->getLaneShapeLength());
}
if (moveOperation->allowChangeLane) {
calculateNewLaneChange(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
calculateNewLaneChange(viewNet, moveOperation->lastLane, moveResult.newLastLane, moveResult.lastLaneOffset);
} else {
moveResult.clearLanes();
}
} else {
if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
0, moveOperation->firstLane->getLaneShapeLength());
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_FIRST) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition, offset,
0, moveOperation->lastPosition);
} else if (moveOperation->operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_LAST) {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->lastPosition, offset,
moveOperation->firstPosition, moveOperation->firstLane->getLaneShapeLength());
} else {
calculateMoveResult(moveResult, viewNet, moveOperation->firstLane, moveOperation->firstPosition,
moveOperation->lastPosition, offset);
}
if (moveOperation->allowChangeLane) {
calculateNewLaneChange(viewNet, moveOperation->firstLane, moveResult.newFirstLane, moveResult.firstLaneOffset);
} else {
moveResult.clearLanes();
}
}
} else {
moveResult.geometryPointsToMove = moveOperation->originalGeometryPoints;
moveResult.shapeToUpdate = moveOperation->originalShape;
moveOperation->moveElement->setMoveShape(moveResult);
moveResult.geometryPointsToMove = moveOperation->geometryPointsToMove;
moveResult.shapeToUpdate = moveOperation->shapeToMove;
if (moveOperation->geometryPointsToMove.size() > 0) {
for (const auto& geometryPointIndex : moveOperation->geometryPointsToMove) {
if (moveResult.shapeToUpdate[geometryPointIndex] != Position::INVALID) {
moveResult.shapeToUpdate[geometryPointIndex].add(offset.x, offset.y, offset.z);
moveResult.shapeToUpdate[geometryPointIndex] = viewNet->snapToActiveGrid(moveResult.shapeToUpdate[geometryPointIndex]);
} else {
throw ProcessError("trying to move an invalid position");
}
}
if (viewNet->getViewParent()->getMoveFrame()->getCommonMoveOptions()->getMergeGeometryPoints() && (moveResult.shapeToUpdate.size() > 2)) {
moveResult.shapeToUpdate.removeDoublePoints(2);
}
} else {
for (auto& geometryPointIndex : moveResult.shapeToUpdate) {
if (geometryPointIndex != Position::INVALID) {
geometryPointIndex.add(offset.x, offset.y, offset.z);
geometryPointIndex = viewNet->snapToActiveGrid(geometryPointIndex);
} else {
throw ProcessError("trying to move an invalid position");
}
}
if ((moveOperation->operationType == GNEMoveOperation::OperationType::WIDTH) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::HEIGHT) ||
(moveOperation->operationType == GNEMoveOperation::OperationType::LENGTH)) {
moveResult.shapeToUpdate = calculateExtrapolatedVector(moveOperation, moveResult);
}
}
}
moveOperation->moveElement->commitMoveShape(moveResult, undoList);
}
double
GNEMoveElement::calculateLaneOffset(const GNEViewNet* viewNet, const GNELane* lane, const double firstPosition, const double lastPosition,
const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
double laneOffset = 0;
const double offsetCentralPosition = (firstPosition + lastPosition) * 0.5;
const double middleLength = std::abs(lastPosition - firstPosition) * 0.5;
Position laneCentralPosition = lane->getLaneShape().positionAtOffset2D(offsetCentralPosition);
laneCentralPosition.add(offset.x, offset.y, offset.z);
laneCentralPosition = viewNet->snapToActiveGrid(laneCentralPosition);
const double offsetLaneCentralPositionPerpendicular = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition);
if (offsetLaneCentralPositionPerpendicular == -1) {
const double offsetLaneCentralPosition = lane->getLaneShape().nearest_offset_to_point2D(laneCentralPosition, false);
if (offsetLaneCentralPosition == 0) {
laneOffset = firstPosition;
} else {
laneOffset = lastPosition - lane->getLaneShape().length2D();
}
} else {
if ((offsetLaneCentralPositionPerpendicular - middleLength) < extremFrom) {
laneOffset = firstPosition + extremFrom;
} else if ((offsetLaneCentralPositionPerpendicular + middleLength) > extremTo) {
laneOffset = lastPosition - extremTo;
} else {
laneOffset = (offsetCentralPosition - offsetLaneCentralPositionPerpendicular);
}
}
return laneOffset;
}
void
GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* lane,
const double pos, const GNEMoveOffset& offset, const double extremFrom, const double extremTo) {
const double laneOffset = calculateLaneOffset(viewNet, lane, pos, pos, offset, extremFrom, extremTo);
moveResult.newFirstPos = (pos - laneOffset) / lane->getLengthGeometryFactor();
moveResult.newLastPos = 0;
}
void
GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* lane,
const double firstPos, const double lastPos, const GNEMoveOffset& offset) {
const double laneOffset = calculateLaneOffset(viewNet, lane, firstPos, lastPos, offset, 0, lane->getLaneShape().length2D());
moveResult.newFirstPos = (firstPos - laneOffset) / lane->getLengthGeometryFactor();
moveResult.newLastPos = (lastPos - laneOffset) / lane->getLengthGeometryFactor();
}
void
GNEMoveElement::calculateMoveResult(GNEMoveResult& moveResult, const GNEViewNet* viewNet, const GNELane* firstLane,
const double firstPos, const GNELane* lastLane, const double lastPos, const GNEMoveOffset& offset) {
const double laneOffset = calculateLaneOffset(viewNet, firstLane, firstPos, firstPos, offset, lastLane->getLaneShape().length2D() - firstPos, firstLane->getLaneShape().length2D());
moveResult.newFirstPos = (firstPos - laneOffset) / firstLane->getLengthGeometryFactor();
moveResult.newLastPos = (lastPos - laneOffset) / firstLane->getLengthGeometryFactor();
}
void
GNEMoveElement::calculateNewLaneChange(const GNEViewNet* viewNet, const GNELane* originalLane, const GNELane*& newLane, double& laneOffset) {
const Position cursorPosition = viewNet->getPositionInformation();
for (const auto& lane : originalLane->getParentEdge()->getChildLanes()) {
if (lane != originalLane) {
const double offSet = lane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
const Position posOverLane = lane->getLaneShape().positionAtOffset2D(offSet);
if (posOverLane.distanceSquaredTo2D(cursorPosition) < 1) {
newLane = lane;
const double offsetMoveOperationLane = originalLane->getLaneShape().nearest_offset_to_point2D(cursorPosition, true);
const Position posOverMoveOperationLane = originalLane->getLaneShape().positionAtOffset2D(offsetMoveOperationLane);
laneOffset = posOverLane.distanceTo2D(posOverMoveOperationLane);
if (originalLane->getIndex() < newLane->getIndex()) {
laneOffset *= -1;
}
}
}
}
}
PositionVector
GNEMoveElement::calculateExtrapolatedVector(const GNEMoveOperation* moveOperation, const GNEMoveResult& moveResult) {
const double halfLength = moveOperation->originalShape.length2D() * -0.5;
PositionVector extendedShape = moveOperation->originalShape;
extendedShape.extrapolate2D(10e5);
const Position geometryPoint = moveOperation->firstGeometryPoint ? moveResult.shapeToUpdate.front() : moveResult.shapeToUpdate.back();
const double offset = extendedShape.nearest_offset_to_point2D(geometryPoint, false);
double extrapolateValue = (10e5 - offset);
if (moveOperation->firstGeometryPoint) {
if (extrapolateValue < halfLength) {
extrapolateValue = (halfLength - POSITION_EPS);
}
} else {
if (extrapolateValue > halfLength) {
extrapolateValue = (halfLength - POSITION_EPS);
}
}
PositionVector extrapolatedShape = moveOperation->shapeToMove;
extrapolatedShape.extrapolate2D(extrapolateValue);
if (moveOperation->firstGeometryPoint) {
return extrapolatedShape;
} else {
return extrapolatedShape.reverse();
}
}