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 // get geometry point radius
50 const double geometryPointRadius = myEdge->getGeometryPointRadius();
51 // check if edge is selected
53 // check if both junctions are selected
62 // special case: when only a single edge is selected, move all shape points (including custom end points)
64 } else {
65 // synchronized movement of a single point
66 return processNoneJunctionSelected(geometryPointRadius);
67 }
68 } else {
69 // calculate move shape operation (because there are only an edge selected)
71 }
72 } else {
73 // calculate move shape operation
75 }
76}
77
78
79std::string
83
84
85double
89
90
95
96
101
102
103void
104GNEMoveElementEdge::setMovingAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
105 myMovedElement->setCommonAttribute(key, value, undoList);
106}
107
108
109bool
110GNEMoveElementEdge::isMovingAttributeValid(SumoXMLAttr key, const std::string& value) const {
111 return myMovedElement->isCommonAttributeValid(key, value);
112}
113
114
115void
118}
119
120
121void
123 // get geometry point radius
124 const double geometryPointRadius = myEdge->getGeometryPointRadius();
125 // declare shape to move
127 // obtain flags for start and end positions
128 const bool customStartPosition = (myEdge->getNBEdge()->getGeometry().front().distanceSquaredTo2D(myEdge->getFromJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE);
129 const bool customEndPosition = (myEdge->getNBEdge()->getGeometry().back().distanceSquaredTo2D(myEdge->getToJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE);
130 // get variable for last index
131 const int lastIndex = (int)myEdge->getNBEdge()->getGeometry().size() - 1;
132 // flag to enable/disable remove geometry point
133 bool removeGeometryPoint = true;
134 // obtain index
135 const int index = myEdge->getNBEdge()->getGeometry().indexOfClosest(clickedPosition, true);
136 // check index
137 if (index == -1) {
138 removeGeometryPoint = false;
139 }
140 // check distance
141 if (shape[index].distanceSquaredTo2D(clickedPosition) > (geometryPointRadius * geometryPointRadius)) {
142 removeGeometryPoint = false;
143 }
144 // check custom start position
145 if (!customStartPosition && (index == 0)) {
146 removeGeometryPoint = false;
147 }
148 // check custom end position
149 if (!customEndPosition && (index == lastIndex)) {
150 removeGeometryPoint = false;
151 }
152 // check if we can remove geometry point
154 // check if we're removing first geometry proint
155 if (index == 0) {
156 // commit new geometry start
157 undoList->begin(myEdge, TLF("remove first geometry point of %", myEdge->getTagStr()));
159 undoList->end();
160 } else if (index == lastIndex) {
161 // commit new geometry end
162 undoList->begin(myEdge, TLF("remove last geometry point of %", myEdge->getTagStr()));
164 undoList->end();
165 } else {
166 // remove geometry point
167 shape.erase(shape.begin() + index);
168 // get innen shape
169 shape.pop_front();
170 shape.pop_back();
171 // remove double points
172 shape.removeDoublePoints((geometryPointRadius * geometryPointRadius));
173 // commit new shape
174 undoList->begin(myEdge, TLF("remove geometry point of %", myEdge->getTagStr()));
176 undoList->end();
177 }
178 }
179}
180
181
182void
184 // get start and end points
185 const Position shapeStart = moveResult.shapeToUpdate.front();
186 const Position shapeEnd = moveResult.shapeToUpdate.back();
187 // get innen shape
188 PositionVector innenShape = moveResult.shapeToUpdate;
189 innenShape.pop_front();
190 innenShape.pop_back();
191 // set shape start
192 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), 0) != moveResult.geometryPointsToMove.end()) {
193 myEdge->setShapeStartPos(shapeStart);
194 }
195 // set innen geometry
196 myEdge->setGeometry(innenShape, true);
197 // set shape end
198 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), ((int)moveResult.shapeToUpdate.size() - 1)) != moveResult.geometryPointsToMove.end()) {
199 myEdge->setShapeEndPos(shapeEnd);
200 }
201}
202
203
204void
206 // make sure that newShape isn't empty
207 if (moveResult.shapeToUpdate.size() > 1) {
208 // get innen shape
209 PositionVector innenShapeToUpdate = moveResult.shapeToUpdate;
210 innenShapeToUpdate.pop_front();
211 innenShapeToUpdate.pop_back();
212 // commit new shape
213 undoList->begin(myEdge, TLF("moving shape of %", myEdge->getTagStr()));
214 // update start position
215 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), 0) != moveResult.geometryPointsToMove.end()) {
217 }
218 // check if update shape
219 if (innenShapeToUpdate.size() > 0) {
221 }
222 // update end position
223 if (std::find(moveResult.geometryPointsToMove.begin(), moveResult.geometryPointsToMove.end(), ((int)moveResult.shapeToUpdate.size() - 1)) != moveResult.geometryPointsToMove.end()) {
225 }
226 undoList->end();
227 }
228}
229
230
232GNEMoveElementEdge::processMoveFromJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius) {
233 // calculate squared snapRadius
234 const double squaredSnapRadius = (snapRadius * snapRadius);
235 // declare shape to move
236 PositionVector shapeToMove = originalShape;
237 // obtain nearest index
238 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
239 // obtain nearest position
240 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
241 // generate indexes
242 std::vector<int> indexes;
243 // check conditions
244 if (nearestIndex == -1) {
245 return nullptr;
246 } else if (nearestPosition == Position::INVALID) {
247 // special case for extremes
248 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
249 for (int i = 1; i <= nearestIndex; i++) {
250 indexes.push_back(i);
251 }
252 // move extrem without creating new geometry point
253 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
254 } else {
255 return nullptr;
256 }
257 } else if (nearestPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
258 for (int i = 1; i <= nearestIndex; i++) {
259 indexes.push_back(i);
260 }
261 // move geometry point without creating new geometry point
262 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
263 } else {
264 // create new geometry point and keep new index (if we clicked near of shape)
265 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
266 for (int i = 1; i <= newIndex; i++) {
267 indexes.push_back(i);
268 }
269 // move after setting new geometry point in shapeToMove
270 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
271 }
272}
273
274
276GNEMoveElementEdge::processMoveToJunctionSelected(const PositionVector originalShape, const Position mousePosition, const double snapRadius) {
277 // calculate squared snapRadius
278 const double squaredSnapRadius = (snapRadius * snapRadius);
279 // declare shape to move
280 PositionVector shapeToMove = originalShape;
281 // obtain nearest index
282 const int nearestIndex = originalShape.indexOfClosest(mousePosition);
283 // obtain nearest position
284 const Position nearestPosition = originalShape.positionAtOffset2D(originalShape.nearest_offset_to_point2D(mousePosition));
285 // generate indexes
286 std::vector<int> indexes;
287 // check conditions
288 if (nearestIndex == -1) {
289 return nullptr;
290 } else if (nearestPosition == Position::INVALID) {
291 // special case for extremes
292 if (mousePosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
293 for (int i = nearestIndex; i < ((int)originalShape.size() - 1); i++) {
294 indexes.push_back(i);
295 }
296 // move extrem without creating new geometry point
297 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
298 } else {
299 return nullptr;
300 }
301 } else if (nearestPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= squaredSnapRadius) {
302 for (int i = nearestIndex; i < ((int)originalShape.size() - 1); i++) {
303 indexes.push_back(i);
304 }
305 // move geometry point without creating new geometry point
306 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
307 } else {
308 // create new geometry point and keep new index (if we clicked near of shape)
309 const int newIndex = shapeToMove.insertAtClosest(nearestPosition, true);
310 for (int i = newIndex; i < ((int)originalShape.size() - 1); i++) {
311 indexes.push_back(i);
312 }
313 // move after setting new geometry point in shapeToMove
314 return new GNEMoveOperation(this, originalShape, indexes, shapeToMove, indexes);
315 }
316}
317
318
321 std::vector<int> geometryPointsToMove;
322 for (int i = 0; i < (int)myEdge->getNBEdge()->getGeometry().size(); i++) {
323 geometryPointsToMove.push_back(i);
324 }
325 // move entire shape (including extremes)
326 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), geometryPointsToMove, myEdge->getNBEdge()->getGeometry(), geometryPointsToMove);
327}
328
329
332 // get move multiple element values
333 const auto& moveMultipleElementValues = myEdge->getNet()->getViewNet()->getMoveMultipleElementValues();
334 // declare shape to move
335 PositionVector shapeToMove = myEdge->getNBEdge()->getGeometry();
336 // first check if kept offset is larger than geometry
337 if (shapeToMove.length2D() < moveMultipleElementValues.getEdgeOffset()) {
338 return nullptr;
339 }
340 // declare offset
341 double offset = 0;
342 // set offset depending of convex angle
343 if (myEdge->isConvexAngle()) {
344 offset = moveMultipleElementValues.getEdgeOffset();
345 } else {
346 offset = shapeToMove.length2D() - moveMultipleElementValues.getEdgeOffset();
347 }
348 // obtain offset position
349 const Position offsetPosition = myEdge->getNBEdge()->getGeometry().positionAtOffset2D(offset);
350 // obtain nearest index to offset position
351 const int nearestIndex = myEdge->getNBEdge()->getGeometry().indexOfClosest(offsetPosition);
352 // check conditions
353 if ((nearestIndex == -1) || (offsetPosition == Position::INVALID)) {
354 return nullptr;
355 } else if (offsetPosition.distanceSquaredTo2D(shapeToMove[nearestIndex]) <= (snapRadius * snapRadius)) {
356 // move geometry point without creating new geometry point
357 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), {nearestIndex}, shapeToMove, {nearestIndex});
358 } else {
359 // create new geometry point and keep new index (if we clicked near of shape)
360 const int newIndex = shapeToMove.insertAtClosest(offsetPosition, true);
361 // move after setting new geometry point in shapeToMove
362 return new GNEMoveOperation(this, myEdge->getNBEdge()->getGeometry(), {nearestIndex}, shapeToMove, {newIndex});
363 }
364}
365
366
367/****************************************************************************/
#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 * 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
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