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#include <config.h>
21
23#include <netedit/GNENet.h>
24#include <netedit/GNEUndoList.h>
25
26#include "GNEMoveElementEdge.h"
27
28// ===========================================================================
29// defines
30// ===========================================================================
31
32#define ENDPOINT_TOLERANCE 2
33
34// ===========================================================================
35// Method definitions
36// ===========================================================================
37
39 GNEMoveElement(edge),
40 myEdge(edge) {
41}
42
43
45
46
49 return myEdge;
50}
51
52
55 // get geometry point radius
56 const double geometryPointRadius = myEdge->getGeometryPointRadius();
57 // check if edge is selected
59 // check if both junctions are selected
68 // special case: when only a single edge is selected, move all shape points (including custom end points)
70 } else {
71 // synchronized movement of a single point
72 return processNoneJunctionSelected(geometryPointRadius);
73 }
74 } else {
75 // calculate move shape operation (because there are only an edge selected)
77 }
78 } else {
79 // calculate move shape operation
81 }
82}
83
84
85std::string
89
90
91double
95
96
101
102
107
108
109void
110GNEMoveElementEdge::setMovingAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
111 myMovedElement->setCommonAttribute(key, value, undoList);
112}
113
114
115bool
116GNEMoveElementEdge::isMovingAttributeValid(SumoXMLAttr key, const std::string& value) const {
117 return myMovedElement->isCommonAttributeValid(key, value);
118}
119
120
121void
124}
125
126
127void
129 // get geometry point radius
130 const double geometryPointRadius = myEdge->getGeometryPointRadius();
131 // declare shape to move
133 // obtain flags for start and end positions
134 const bool customStartPosition = (myEdge->getNBEdge()->getGeometry().front().distanceSquaredTo2D(myEdge->getFromJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE);
135 const bool customEndPosition = (myEdge->getNBEdge()->getGeometry().back().distanceSquaredTo2D(myEdge->getToJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE);
136 // get variable for last index
137 const int lastIndex = (int)myEdge->getNBEdge()->getGeometry().size() - 1;
138 // flag to enable/disable remove geometry point
139 bool removeGeometryPoint = true;
140 // obtain index
141 const int index = myEdge->getNBEdge()->getGeometry().indexOfClosest(clickedPosition, true);
142 // check index
143 if (index == -1) {
144 removeGeometryPoint = false;
145 }
146 // check distance
147 if (shape[index].distanceSquaredTo2D(clickedPosition) > (geometryPointRadius * geometryPointRadius)) {
148 removeGeometryPoint = false;
149 }
150 // check custom start position
151 if (!customStartPosition && (index == 0)) {
152 removeGeometryPoint = false;
153 }
154 // check custom end position
155 if (!customEndPosition && (index == lastIndex)) {
156 removeGeometryPoint = false;
157 }
158 // check if we can remove geometry point
160 // check if we're removing first geometry proint
161 if (index == 0) {
162 // commit new geometry start
163 undoList->begin(myEdge, TLF("remove first geometry point of %", myEdge->getTagStr()));
165 undoList->end();
166 } else if (index == lastIndex) {
167 // commit new geometry end
168 undoList->begin(myEdge, TLF("remove last geometry point of %", myEdge->getTagStr()));
170 undoList->end();
171 } else {
172 // remove geometry point
173 shape.erase(shape.begin() + index);
174 // get innen shape
175 shape.pop_front();
176 shape.pop_back();
177 // remove double points
178 shape.removeDoublePoints((geometryPointRadius * geometryPointRadius));
179 // commit new shape
180 undoList->begin(myEdge, TLF("remove geometry point of %", myEdge->getTagStr()));
182 undoList->end();
183 }
184 }
185}
186
187
188void
190 // get start and end points
191 const Position shapeStart = moveResult.shapeToUpdate.front();
192 const Position shapeEnd = moveResult.shapeToUpdate.back();
193 // get innen shape
194 PositionVector innenShape = moveResult.shapeToUpdate;
195 innenShape.pop_front();
196 innenShape.pop_back();
197 // set shape start
198 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), 0) != moveResult.geometryPointsToMove.end()) {
199 myEdge->setShapeStartPos(shapeStart);
200 }
201 // set innen geometry
202 myEdge->setGeometry(innenShape, true);
203 // set shape end
204 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), ((int)moveResult.shapeToUpdate.size() - 1)) != moveResult.geometryPointsToMove.end()) {
205 myEdge->setShapeEndPos(shapeEnd);
206 }
207}
208
209
210void
212 // make sure that newShape isn't empty
213 if (moveResult.shapeToUpdate.size() > 1) {
214 // get innen shape
215 PositionVector innenShapeToUpdate = moveResult.shapeToUpdate;
216 innenShapeToUpdate.pop_front();
217 innenShapeToUpdate.pop_back();
218 // commit new shape
219 undoList->begin(myEdge, TLF("moving shape of %", myEdge->getTagStr()));
220 // update start position
221 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), 0) != moveResult.geometryPointsToMove.end()) {
223 }
224 // check if update shape
225 if (innenShapeToUpdate.size() > 0) {
227 }
228 // update end position
229 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), ((int)moveResult.shapeToUpdate.size() - 1)) != moveResult.geometryPointsToMove.end()) {
231 }
232 undoList->end();
233 }
234}
235
236
238GNEMoveElementEdge::processMoveFromJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius) {
239 // calculate squared snapRadius
240 const double squaredSnapRadius = (snapRadius * snapRadius);
241 // declare shape to move
242 PositionVector shapeToMove = originalShape;
243 // obtain nearest index
244 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
245 // obtain nearest position
246 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
247 // generate indexes
248 std::vector<int> indexes;
249 // check conditions
250 if (nearestIndex == -1) {
251 return nullptr;
252 } else if (nearestPosition == Position::INVALID) {
253 // special case for extremes
254 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
255 for (int i = 1; i <= nearestIndex; i++) {
256 indexes.push_back(i);
257 }
258 // move extrem without creating new geometry point
259 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
260 } else {
261 return nullptr;
262 }
263 } else if (nearestPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
264 for (int i = 1; i <= nearestIndex; i++) {
265 indexes.push_back(i);
266 }
267 // move geometry point without creating new geometry point
268 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
269 } else {
270 // create new geometry point and keep new index (if we clicked near of shape)
271 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
272 for (int i = 1; i <= newIndex; i++) {
273 indexes.push_back(i);
274 }
275 // move after setting new geometry point in shapeToMove
276 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
277 }
278}
279
280
282GNEMoveElementEdge::processMoveToJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius) {
283 // calculate squared snapRadius
284 const double squaredSnapRadius = (snapRadius * snapRadius);
285 // declare shape to move
286 PositionVector shapeToMove = originalShape;
287 // obtain nearest index
288 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
289 // obtain nearest position
290 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
291 // generate indexes
292 std::vector<int> indexes;
293 // check conditions
294 if (nearestIndex == -1) {
295 return nullptr;
296 } else if (nearestPosition == Position::INVALID) {
297 // special case for extremes
298 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
299 for (int i = nearestIndex; i < ((int)originalShape.size() - 1); i++) {
300 indexes.push_back(i);
301 }
302 // move extrem without creating new geometry point
303 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
304 } else {
305 return nullptr;
306 }
307 } else if (nearestPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
308 for (int i = nearestIndex; i < ((int)originalShape.size() - 1); i++) {
309 indexes.push_back(i);
310 }
311 // move geometry point without creating new geometry point
312 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
313 } else {
314 // create new geometry point and keep new index (if we clicked near of shape)
315 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
316 for (int i = newIndex; i < ((int)originalShape.size() - 1); i++) {
317 indexes.push_back(i);
318 }
319 // move after setting new geometry point in shapeToMove
320 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
321 }
322}
323
324
327 std::vector<int> geometryPointsToMove;
328 for (int i = 0; i < (int)myEdge->getNBEdge()->getGeometry().size(); i++) {
329 geometryPointsToMove.push_back(i);
330 }
331 // move entire shape (including extremes)
332 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), geometryPointsToMove, myEdge->getNBEdge()->getGeometry(), geometryPointsToMove);
333}
334
335
338 // get move multiple element values
339 const auto& moveMultipleElementValues = myEdge->getNet()->getViewNet()->getMoveMultipleElementValues();
340 // declare shape to move
341 PositionVector shapeToMove = myEdge->getNBEdge()->getGeometry();
342 // first check if kept offset is larger than geometry
343 if (shapeToMove.length2D() < moveMultipleElementValues.getEdgeOffset()) {
344 return nullptr;
345 }
346 // declare offset
347 double offset = 0;
348 // set offset depending of convex angle
349 if (myEdge->isConvexAngle()) {
350 offset = moveMultipleElementValues.getEdgeOffset();
351 } else {
352 offset = shapeToMove.length2D() - moveMultipleElementValues.getEdgeOffset();
353 }
354 // obtain offset position
355 const Position offsetPosition = myEdge->getNBEdge()->getGeometry().positionAtOffset2D(offset);
356 // obtain nearest index to offset position
357 const int nearestIndex = myEdge->getNBEdge()->getGeometry().indexOfClosest(offsetPosition);
358 // check conditions
359 if ((nearestIndex == -1) || (offsetPosition == Position::INVALID)) {
360 return nullptr;
361 } else if (offsetPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= (snapRadius * snapRadius)) {
362 // move geometry point without creating new geometry point
363 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), {nearestIndex}, shapeToMove, {nearestIndex});
364 } else {
365 // create new geometry point and keep new index (if we clicked near of shape)
366 const int newIndex = shapeToMove.insertAtClosest(offsetPosition, true);
367 // move after setting new geometry point in shapeToMove
368 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), {nearestIndex}, shapeToMove, {newIndex});
369 }
370}
371
372
373/****************************************************************************/
#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:1727
double getGeometryPointRadius() const
get geometry point radius
Definition GNEEdge.cpp:2947
NBEdge * getNBEdge() const
returns the internal NBEdge
Definition GNEEdge.cpp:755
void setGeometry(PositionVector geom, bool inner)
update edge geometry and inform the lanes
Definition GNEEdge.cpp:853
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:2385
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:2396
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 * getMoveOperation() override
get move operation
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)
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
GNEEdge * getEdge() const
get pointer to edge
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:174
GNEViewNet * getViewNet() const
get view net (used for simplify code)
Definition GNENet.cpp:144
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