Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GNEMoveElementEdge.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-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/****************************************************************************/
18// Class used for moving edge shapes
19/****************************************************************************/
20
22#include <netedit/GNENet.h>
23#include <netedit/GNEUndoList.h>
24
25#include "GNEMoveElementEdge.h"
26
27// ===========================================================================
28// defines
29// ===========================================================================
30
31#define ENDPOINT_TOLERANCE 2
32
33// ===========================================================================
34// Method definitions
35// ===========================================================================
36
38 GNEMoveElement(edge),
39 myEdge(edge) {
40}
41
42
44
45
48 // get geometry point radius
49 const double geometryPointRadius = myEdge->getGeometryPointRadius();
50 // check if edge is selected
52 // check if both junctions are selected
61 // special case: when only a single edge is selected, move all shape points (including custom end points)
63 } else {
64 // synchronized movement of a single point
65 return processNoneJunctionSelected(geometryPointRadius);
66 }
67 } else {
68 // calculate move shape operation (because there are only an edge selected)
70 }
71 } else {
72 // calculate move shape operation
74 }
75}
76
77
78std::string
82
83
84double
88
89
94
95
100
101
102void
103GNEMoveElementEdge::setMovingAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
104 myMovedElement->setCommonAttribute(key, value, undoList);
105}
106
107
108bool
109GNEMoveElementEdge::isMovingAttributeValid(SumoXMLAttr key, const std::string& value) const {
110 return myMovedElement->isCommonAttributeValid(key, value);
111}
112
113
114void
117}
118
119
120void
122 // get geometry point radius
123 const double geometryPointRadius = myEdge->getGeometryPointRadius();
124 // declare shape to move
126 // obtain flags for start and end positions
127 const bool customStartPosition = (myEdge->getNBEdge()->getGeometry().front().distanceSquaredTo2D(myEdge->getFromJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE);
128 const bool customEndPosition = (myEdge->getNBEdge()->getGeometry().back().distanceSquaredTo2D(myEdge->getToJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE);
129 // get variable for last index
130 const int lastIndex = (int)myEdge->getNBEdge()->getGeometry().size() - 1;
131 // flag to enable/disable remove geometry point
132 bool removeGeometryPoint = true;
133 // obtain index
134 const int index = myEdge->getNBEdge()->getGeometry().indexOfClosest(clickedPosition, true);
135 // check index
136 if (index == -1) {
137 removeGeometryPoint = false;
138 }
139 // check distance
140 if (shape[index].distanceSquaredTo2D(clickedPosition) > (geometryPointRadius * geometryPointRadius)) {
141 removeGeometryPoint = false;
142 }
143 // check custom start position
144 if (!customStartPosition && (index == 0)) {
145 removeGeometryPoint = false;
146 }
147 // check custom end position
148 if (!customEndPosition && (index == lastIndex)) {
149 removeGeometryPoint = false;
150 }
151 // check if we can remove geometry point
153 // check if we're removing first geometry proint
154 if (index == 0) {
155 // commit new geometry start
156 undoList->begin(myEdge, TLF("remove first geometry point of %", myEdge->getTagStr()));
158 undoList->end();
159 } else if (index == lastIndex) {
160 // commit new geometry end
161 undoList->begin(myEdge, TLF("remove last geometry point of %", myEdge->getTagStr()));
163 undoList->end();
164 } else {
165 // remove geometry point
166 shape.erase(shape.begin() + index);
167 // get innen shape
168 shape.pop_front();
169 shape.pop_back();
170 // remove double points
171 shape.removeDoublePoints((geometryPointRadius * geometryPointRadius));
172 // commit new shape
173 undoList->begin(myEdge, TLF("remove geometry point of %", myEdge->getTagStr()));
175 undoList->end();
176 }
177 }
178}
179
180
181void
183 // get start and end points
184 const Position shapeStart = moveResult.shapeToUpdate.front();
185 const Position shapeEnd = moveResult.shapeToUpdate.back();
186 // get innen shape
187 PositionVector innenShape = moveResult.shapeToUpdate;
188 innenShape.pop_front();
189 innenShape.pop_back();
190 // set shape start
191 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), 0) != moveResult.geometryPointsToMove.end()) {
192 myEdge->setShapeStartPos(shapeStart);
193 }
194 // set innen geometry
195 myEdge->setGeometry(innenShape, true);
196 // set shape end
197 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), ((int)moveResult.shapeToUpdate.size() - 1)) != moveResult.geometryPointsToMove.end()) {
198 myEdge->setShapeEndPos(shapeEnd);
199 }
200}
201
202
203void
205 // make sure that newShape isn't empty
206 if (moveResult.shapeToUpdate.size() > 1) {
207 // get innen shape
208 PositionVector innenShapeToUpdate = moveResult.shapeToUpdate;
209 innenShapeToUpdate.pop_front();
210 innenShapeToUpdate.pop_back();
211 // commit new shape
212 undoList->begin(myEdge, TLF("moving shape of %", myEdge->getTagStr()));
213 // update start position
214 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), 0) != moveResult.geometryPointsToMove.end()) {
216 }
217 // check if update shape
218 if (innenShapeToUpdate.size() > 0) {
220 }
221 // update end position
222 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), ((int)moveResult.shapeToUpdate.size() - 1)) != moveResult.geometryPointsToMove.end()) {
224 }
225 undoList->end();
226 }
227}
228
229
231GNEMoveElementEdge::processMoveFromJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius) {
232 // calculate squared snapRadius
233 const double squaredSnapRadius = (snapRadius * snapRadius);
234 // declare shape to move
235 PositionVector shapeToMove = originalShape;
236 // obtain nearest index
237 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
238 // obtain nearest position
239 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
240 // generate indexes
241 std::vector<int> indexes;
242 // check conditions
243 if (nearestIndex == -1) {
244 return nullptr;
245 } else if (nearestPosition == Position::INVALID) {
246 // special case for extremes
247 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
248 for (int i = 1; i <= nearestIndex; i++) {
249 indexes.push_back(i);
250 }
251 // move extrem without creating new geometry point
252 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
253 } else {
254 return nullptr;
255 }
256 } else if (nearestPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
257 for (int i = 1; i <= nearestIndex; i++) {
258 indexes.push_back(i);
259 }
260 // move geometry point without creating new geometry point
261 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
262 } else {
263 // create new geometry point and keep new index (if we clicked near of shape)
264 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
265 for (int i = 1; i <= newIndex; i++) {
266 indexes.push_back(i);
267 }
268 // move after setting new geometry point in shapeToMove
269 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
270 }
271}
272
273
275GNEMoveElementEdge::processMoveToJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius) {
276 // calculate squared snapRadius
277 const double squaredSnapRadius = (snapRadius * snapRadius);
278 // declare shape to move
279 PositionVector shapeToMove = originalShape;
280 // obtain nearest index
281 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
282 // obtain nearest position
283 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
284 // generate indexes
285 std::vector<int> indexes;
286 // check conditions
287 if (nearestIndex == -1) {
288 return nullptr;
289 } else if (nearestPosition == Position::INVALID) {
290 // special case for extremes
291 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
292 for (int i = nearestIndex; i < ((int)originalShape.size() - 1); i++) {
293 indexes.push_back(i);
294 }
295 // move extrem without creating new geometry point
296 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
297 } else {
298 return nullptr;
299 }
300 } else if (nearestPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
301 for (int i = nearestIndex; i < ((int)originalShape.size() - 1); i++) {
302 indexes.push_back(i);
303 }
304 // move geometry point without creating new geometry point
305 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
306 } else {
307 // create new geometry point and keep new index (if we clicked near of shape)
308 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
309 for (int i = newIndex; i < ((int)originalShape.size() - 1); i++) {
310 indexes.push_back(i);
311 }
312 // move after setting new geometry point in shapeToMove
313 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
314 }
315}
316
317
320 std::vector<int> geometryPointsToMove;
321 for (int i = 0; i < (int)myEdge->getNBEdge()->getGeometry().size(); i++) {
322 geometryPointsToMove.push_back(i);
323 }
324 // move entire shape (including extremes)
325 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), geometryPointsToMove, myEdge->getNBEdge()->getGeometry(), geometryPointsToMove);
326}
327
328
331 // get move multiple element values
332 const auto& moveMultipleElementValues = myEdge->getNet()->getViewNet()->getMoveMultipleElementValues();
333 // declare shape to move
334 PositionVector shapeToMove = myEdge->getNBEdge()->getGeometry();
335 // first check if kept offset is larger than geometry
336 if (shapeToMove.length2D() < moveMultipleElementValues.getEdgeOffset()) {
337 return nullptr;
338 }
339 // declare offset
340 double offset = 0;
341 // set offset depending of convex angle
342 if (myEdge->isConvexAngle()) {
343 offset = moveMultipleElementValues.getEdgeOffset();
344 } else {
345 offset = shapeToMove.length2D() - moveMultipleElementValues.getEdgeOffset();
346 }
347 // obtain offset position
348 const Position offsetPosition = myEdge->getNBEdge()->getGeometry().positionAtOffset2D(offset);
349 // obtain nearest index to offset position
350 const int nearestIndex = myEdge->getNBEdge()->getGeometry().indexOfClosest(offsetPosition);
351 // check conditions
352 if ((nearestIndex == -1) || (offsetPosition == Position::INVALID)) {
353 return nullptr;
354 } else if (offsetPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= (snapRadius * snapRadius)) {
355 // move geometry point without creating new geometry point
356 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), {nearestIndex}, shapeToMove, {nearestIndex});
357 } else {
358 // create new geometry point and keep new index (if we clicked near of shape)
359 const int newIndex = shapeToMove.insertAtClosest(offsetPosition, true);
360 // move after setting new geometry point in shapeToMove
361 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), {nearestIndex}, shapeToMove, {newIndex});
362 }
363}
364
365
366/****************************************************************************/
#define ENDPOINT_TOLERANCE
#define TLF(string,...)
Definition MsgHandler.h:306
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
@ SUMO_ATTR_SHAPE
edge: the shape in xml-definition
@ GNE_ATTR_SHAPE_END
last coordinate of edge shape
@ GNE_ATTR_SHAPE_START
first coordinate of edge shape
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
bool isAttributeCarrierSelected() const
check if attribute carrier is selected
double getCommonAttributeDouble(SumoXMLAttr key) const
PositionVector getCommonAttributePositionVector(SumoXMLAttr key) const
void setCommonAttribute(SumoXMLAttr key, const std::string &value, GNEUndoList *undoList)
const std::string & getTagStr() const
get tag assigned to this object in string format
Position getCommonAttributePosition(SumoXMLAttr key) const
GNENet * getNet() const
get pointer to net
bool isCommonAttributeValid(SumoXMLAttr key, const std::string &value) const
std::string getCommonAttribute(SumoXMLAttr key) const
static void changeAttribute(GNEAttributeCarrier *AC, SumoXMLAttr key, const std::string &value, GNEUndoList *undoList, const bool force=false)
change attribute
bool isConvexAngle() const
check if edge makes a convex angle [0 - 180) degrees
Definition GNEEdge.cpp:1725
double getGeometryPointRadius() const
get geometry point radius
Definition GNEEdge.cpp:2945
NBEdge * getNBEdge() const
returns the internal NBEdge
Definition GNEEdge.cpp:753
void setGeometry(PositionVector geom, bool inner)
update edge geometry and inform the lanes
Definition GNEEdge.cpp:851
GNEJunction * getFromJunction() const
get from Junction (only used to increase readability)
Definition GNEEdge.h:87
void setShapeStartPos(const Position &pos)
change Shape StartPos
Definition GNEEdge.cpp:2383
GNEJunction * getToJunction() const
get from Junction (only used to increase readability)
Definition GNEEdge.h:92
void setShapeEndPos(const Position &pos)
change Shape EndPos
Definition GNEEdge.cpp:2394
NBNode * getNBNode() const
Return net build node.
PositionVector getMovingAttributePositionVector(SumoXMLAttr key) const override
get moving attribute positionVector
GNEMoveOperation * processMoveFromJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius)
process moving edge when only from junction is selected
Position getMovingAttributePosition(SumoXMLAttr key) const override
get moving attribute position
double getMovingAttributeDouble(SumoXMLAttr key) const override
get moving attribute double
GNEMoveOperation * processMoveToJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius)
process moving edge when only to junction is selected
GNEMoveElementEdge()=delete
invalidate default constructor
GNEMoveOperation * processNoneJunctionSelected(const double snapRadius)
process moving edge when none junction are selected
void setMovingAttribute(SumoXMLAttr key, const std::string &value, GNEUndoList *undoList) override
set moving attribute (using undo-list)
GNEMoveOperation * getMoveOperation()
get move operation
bool isMovingAttributeValid(SumoXMLAttr key, const std::string &value) const override
check if the given moving attribute is valid
GNEEdge * myEdge
pointer to edge
void setMoveShape(const GNEMoveResult &moveResult) override
set move shape
GNEMoveOperation * processMoveBothJunctionSelected()
process moving edge when both junctions are selected
void commitMoveShape(const GNEMoveResult &moveResult, GNEUndoList *undoList) override
commit move shape
void removeGeometryPoint(const Position clickedPosition, GNEUndoList *undoList) override
remove geometry point in the clicked position
std::string getMovingAttribute(SumoXMLAttr key) const override
get moving attribute
GNEAttributeCarrier * myMovedElement
pointer to element
GNEMoveOperation * getEditShapeOperation(const GUIGlObject *obj, const PositionVector originalShape, const bool maintainShapeClosed)
calculate move shape operation
std::vector< int > geometryPointsToMove
shape points to move (of shapeToMove)
PositionVector shapeToUpdate
shape to update (edited in moveElement)
int getNumberOfSelectedEdges() const
get number of selected edges
GNENetHelper::AttributeCarriers * getAttributeCarriers() const
get all attribute carriers used in this net
Definition GNENet.cpp:144
GNEViewNet * getViewNet() const
get view net
Definition GNENet.cpp:2193
void end()
End undo command sub-group. If the sub-group is still empty, it will be deleted; otherwise,...
void begin(GUIIcon icon, const std::string &description)
Begin undo command sub-group with current supermode. This begins a new group of commands that are tre...
const GNEViewNetHelper::MoveMultipleElementModul & getMoveMultipleElementValues() const
get move multiple element values
virtual Position getPositionInformation() const
Returns the cursor's x/y position within the network.
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition NBEdge.h:789
const Position & getPosition() const
Definition NBNode.h:260
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:278
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:323
A list of positions.
double length2D() const
Returns the length.
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
int insertAtClosest(const Position &p, bool interpolateZ)
inserts p between the two closest positions
Position positionAtOffset2D(double pos, double lateralOffset=0, bool extrapolateBeyond=false) const
Returns the position at the given length.
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false, int beginOffset=0, int endOffset=0, bool resample=false)
Removes positions if too near.
void pop_front()
pop first Position
bool isMovingSelectedEdge() const
flag for moving edge