Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GNEMoveElementLaneDouble.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 elements that can be moved over a lane with two positions
19/****************************************************************************/
20
25#include <netedit/GNENet.h>
27#include <netedit/GNEUndoList.h>
30
33
34// ===========================================================================
35// static members
36// ===========================================================================
37
39
40// ===========================================================================
41// member method definitions
42// ===========================================================================
43
45 SumoXMLAttr startPosAttr, double& startPosValue, SumoXMLAttr endPosAttr,
46 double& endPosValue, bool& friendlyPosition) :
47 GNEMoveElement(element),
48 myStartPos(new GNEMoveElementLaneSingle(element, startPosAttr, startPosValue, friendlyPosition,
49 GNEMoveElementLaneSingle::PositionType::STARPOS)),
50 myEndPos(new GNEMoveElementLaneSingle(element, endPosAttr, endPosValue, friendlyPosition,
51 GNEMoveElementLaneSingle::PositionType::ENDPOS)) {
52}
53
54
59
60
63 const auto& parentLanes = myMovedElement->getHierarchicalElement()->getParentLanes();
64 // get allow change lane
66 // fist check if we're moving only extremes
68 // get geometry points under cursor
70 // continue depending of clicked geometry point
71 if (geometryPoints.empty()) {
72 return nullptr;
73 } else {
74 if (geometryPoints.front() == 0) {
75 // move start position
77 } else {
78 // move end position
79 return myEndPos->getMoveOperation();
80 }
81 }
83 // move both start and end positions depending of number of lanes
84 if (parentLanes.size() > 1) {
85 if (gViewObjectsHandler.isObjectSelected(parentLanes.front())) {
86 return new GNEMoveOperation(myMovedElement->getMoveElement(), parentLanes.front(), myStartPos->myPosOverLane, parentLanes.back(), myEndPos->myPosOverLane, true, false);
87 } else if (gViewObjectsHandler.isObjectSelected(parentLanes.back())) {
88 return new GNEMoveOperation(myMovedElement->getMoveElement(), parentLanes.front(), myStartPos->myPosOverLane, parentLanes.back(), myEndPos->myPosOverLane, false, false);
89 } else {
90 // temporal, in the future will be allow, clicking in the intermediate lanes
91 return nullptr;
92 }
93 } else {
94 return new GNEMoveOperation(myMovedElement->getMoveElement(), parentLanes.front(), myStartPos->myPosOverLane, myEndPos->myPosOverLane, allowChangeLane);
95 }
97 // move only start position
99 } else if (myEndPos->myPosOverLane != INVALID_DOUBLE) {
100 // move only end position
101 return myEndPos->getMoveOperation();
102 } else {
103 // start and end positions undefined, then nothing to move
104 return nullptr;
105 }
106}
107
108
109std::string
111 // position attributes
112 if (key == myStartPos->myPosAttr) {
113 return myStartPos->getMovingAttribute(key);
114 } else if (key == myEndPos->myPosAttr) {
115 return myEndPos->getMovingAttribute(key);
116 } else {
117 // other attributes
118 switch (key) {
119 case SUMO_ATTR_LANE:
120 case SUMO_ATTR_LANES:
123 return myStartPos->getMovingAttribute(key);
125 return "";
126 case SUMO_ATTR_LENGTH:
127 case GNE_ATTR_SIZE:
128 if (myMovedElement->isTemplate()) {
129 return toString(myTemplateSize);
130 } else {
132 }
137 default:
139 }
140 }
141}
142
143
144double
146 // position attributes
147 if (key == myStartPos->myPosAttr) {
149 } else if (key == myEndPos->myPosAttr) {
150 return myEndPos->myPosOverLane;
151 } else {
152 // other attributes
153 switch (key) {
154 case SUMO_ATTR_CENTER:
155 return (getStartFixedPositionOverLane(false) + getEndFixedPositionOverLane(false)) * 0.5;
156 case SUMO_ATTR_LENGTH:
157 case GNE_ATTR_SIZE:
158 if (myMovedElement->isTemplate()) {
159 return myTemplateSize;
160 } else {
162 }
163 default:
164 throw InvalidArgument(myMovedElement->getTagStr() + " doesn't have a moving attribute of type '" + toString(key) + "'");
165 }
166 }
167}
168
169
174
175
180
181
182void
184 // position attributes
185 if (key == myStartPos->myPosAttr) {
187 } else if (key == myEndPos->myPosAttr) {
189 } else {
190 // other attributes
191 switch (key) {
192 case SUMO_ATTR_LANE:
193 case SUMO_ATTR_LANES:
199 break;
200 case SUMO_ATTR_LENGTH:
201 if (myMovedElement->isTemplate()) {
202 // use size value
204 } else {
205 // change end position
206 GNEChange_Attribute::changeAttribute(myMovedElement, myEndPos->myPosAttr, toString(getStartFixedPositionOverLane(true) + GNEAttributeCarrier::parse<double>(value)), undoList);
207 }
208 break;
209 case GNE_ATTR_SIZE:
210 if (myMovedElement->isTemplate()) {
212 } else {
213 setSize(value, undoList);
214 }
215 break;
216 default:
217 myMovedElement->setCommonAttribute(key, value, undoList);
218 break;
219 }
220 }
221}
222
223
224bool
226 // position attributes
227 if (key == myStartPos->myPosAttr) {
228 return myStartPos->isMovingAttributeValid(key, value);
229 } else if (key == myEndPos->myPosAttr) {
230 return myEndPos->isMovingAttributeValid(key, value);
231 } else {
232 // other attributes
233 switch (key) {
234 case SUMO_ATTR_LANE:
235 case SUMO_ATTR_LANES:
236 if (value.empty()) {
237 return false;
238 } else {
239 return GNEAttributeCarrier::canParse<std::vector<GNELane*> >(myMovedElement->getNet(), value, true);
240 }
242 return myStartPos->isMovingAttributeValid(key, value);
244 return true;
245 case SUMO_ATTR_LENGTH:
246 case GNE_ATTR_SIZE:
247 if (value.empty()) {
248 return false;
249 } else {
250 return GNEAttributeCarrier::canParse<double>(value) && GNEAttributeCarrier::parse<double>(value) >= POSITION_EPS;
251 }
253 return GNEAttributeCarrier::canParse<bool>(value);
256 default:
257 return myMovedElement->isCommonAttributeValid(key, value);
258 }
259 }
260}
261
262
263void
265 // position attributes
266 if (key == myStartPos->myPosAttr) {
267 myStartPos->setMovingAttribute(key, value);
268 } else if (key == myEndPos->myPosAttr) {
269 myEndPos->setMovingAttribute(key, value);
270 } else {
271 // other attributes
272 switch (key) {
274 myStartPos->setMovingAttribute(key, value);
275 break;
276 case SUMO_ATTR_LENGTH:
277 case GNE_ATTR_SIZE:
278 if (value.empty()) {
280 } else {
281 myTemplateSize = GNEAttributeCarrier::parse<double>(value);
282 }
283 break;
285 myTemplateForceSize = GNEAttributeCarrier::parse<bool>(value);
286 break;
289 break;
290 default:
291 return myMovedElement->setCommonAttribute(key, value);
292 }
293 }
294}
295
296
297void
298GNEMoveElementLaneDouble::removeGeometryPoint(const Position /*clickedPosition*/, GNEUndoList* /*undoList*/) {
299 // nothing to do here
300}
301
302
303bool
305 // first check if lanes are connected
307 return false;
309 return false;
311 return false;
312 } else if ((myMovedElement->getHierarchicalElement()->getParentLanes().size() == 1) &&
313 (myStartPos->getFixedPositionOverLane(false) > (myEndPos->getFixedPositionOverLane(false) - POSITION_EPS))) {
314 return false;
315 } else {
316 return true;
317 }
318}
319
320
321std::string
323 // first check if lanes are connected
325 return TL("Lanes aren't consecutives");
327 return TL("Lanes aren't connected");
328 } else if (!myStartPos->isMoveElementValid()) {
330 } else if (!myEndPos->isMoveElementValid()) {
331 return myEndPos->getMovingProblem();
332 } else if ((myMovedElement->getHierarchicalElement()->getParentLanes().size() == 1) &&
333 (myStartPos->getFixedPositionOverLane(false) > (myEndPos->getFixedPositionOverLane(false) - POSITION_EPS))) {
334 return TL("starPos > (endPos - EPS)");
335 } else {
336 return "";
337 }
338}
339
340
341void
343 const auto undolist = myMovedElement->getNet()->getViewNet()->getUndoList();
344 // iterate over all lanes and build connections
345 for (int i = 1; i < (int)myMovedElement->getHierarchicalElement()->getParentLanes().size(); i++) {
346 // get lanes
347 const auto firstLane = myMovedElement->getHierarchicalElement()->getParentLanes().at(i - 1);
348 const auto secondLane = myMovedElement->getHierarchicalElement()->getParentLanes().at(i);
349 // search connection
350 bool foundConnection = false;
351 for (const auto& connection : firstLane->getParentEdge()->getGNEConnections()) {
352 if ((connection->getLaneFrom() == firstLane) && (connection->getLaneTo() == secondLane)) {
353 foundConnection = true;
354 break;
355 }
356 }
357 // check if connection exist
358 if (!foundConnection) {
359 // create new connection manually
360 NBEdge::Connection newCon(firstLane->getIndex(), secondLane->getParentEdge()->getNBEdge(), secondLane->getIndex());
361 // allow to undo creation of new lane
362 undolist->add(new GNEChange_Connection(firstLane->getParentEdge(), newCon, false, true), true);
363 }
364 }
365 // Fix both position
369 // extra if starPos > endPos (endPos is dominant)
370 const double finalLenght = myMovedElement->getHierarchicalElement()->getParentLanes().back()->getParentEdge()->getNBEdge()->getFinalLength();
371 const double maxStartPos = (myEndPos->myPosOverLane == INVALID_DOUBLE) ? finalLenght : (myEndPos->getFixedPositionOverLane(false) - POSITION_EPS);
372 if (maxStartPos < POSITION_EPS) {
374 myMovedElement->setAttribute(myEndPos->myPosAttr, toString(POSITION_EPS), undolist);
375 } else if (myStartPos->getFixedPositionOverLane(false) > maxStartPos) {
376 // use truncate to avoid problem precission under certain conditions
377 const double newStartPos = (std::trunc(maxStartPos * 1000) / 1000);
378 myMovedElement->setAttribute(myStartPos->myPosAttr, toString(newStartPos), undolist);
379 }
380 }
381}
382
383
384void
385GNEMoveElementLaneDouble::writeMoveAttributes(OutputDevice& device, const bool writeLength) const {
386 // lane/s
389 } else {
391 }
392 // write start position
395 }
396 // write end position depending of lenght
397 if (writeLength) {
401 }
402 // friendly position (only if true)
405 }
406}
407
408
409double
410GNEMoveElementLaneDouble::getStartFixedPositionOverLane(const bool adjustGeometryFactor) const {
411 if (myStartPos->getFixedPositionOverLane(adjustGeometryFactor) < 0) {
412 return 0;
413 } else if (myStartPos->getFixedPositionOverLane(adjustGeometryFactor) > (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) - POSITION_EPS)) {
414 return (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) - POSITION_EPS);
415 } else {
416 return myStartPos->getFixedPositionOverLane(adjustGeometryFactor);
417 }
418}
419
420
421double
422GNEMoveElementLaneDouble::getEndFixedPositionOverLane(const bool adjustGeometryFactor) const {
423 if (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) < POSITION_EPS) {
424 return POSITION_EPS;
425 } else if (myStartPos->getFixedPositionOverLane(adjustGeometryFactor) > (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) - POSITION_EPS)) {
426 return myEndPos->getFixedPositionOverLane(adjustGeometryFactor);
427 } else {
428 return myEndPos->getFixedPositionOverLane(adjustGeometryFactor);
429 }
430}
431
432
433void
435 // check if we're moving both points
436 if ((moveResult.newFirstPos != INVALID_DOUBLE) && (moveResult.newLastPos != INVALID_DOUBLE)) {
437 // change both position
438 myStartPos->setMoveShape(moveResult);
439 myEndPos->setMoveShape(moveResult);
440 // set lateral offset
442 } else if (moveResult.newFirstPos != INVALID_DOUBLE) {
443 // change only start position
444 myStartPos->setMoveShape(moveResult);
445 } else if (moveResult.newLastPos != INVALID_DOUBLE) {
446 myEndPos->setMoveShape(moveResult);
447 }
448 // update geometry
450}
451
452
453void
455 // begin change attribute
456 undoList->begin(myMovedElement, TLF("position of %", myMovedElement->getTagStr()));
457 // check if we're moving both points
458 if ((moveResult.newFirstPos != INVALID_DOUBLE) && (moveResult.newLastPos != INVALID_DOUBLE)) {
459 // set both positions
460 myStartPos->commitMoveShape(moveResult, undoList);
461 myEndPos->commitMoveShape(moveResult, undoList);
462 } else if (moveResult.newFirstPos != INVALID_DOUBLE) {
463 // set only start position
464 myStartPos->commitMoveShape(moveResult, undoList);
465 } else if (moveResult.newLastPos != INVALID_DOUBLE) {
466 // set only end position
467 myEndPos->commitMoveShape(moveResult, undoList);
468 }
469 // end change attribute
470 undoList->end();
471}
472
473
474void
475GNEMoveElementLaneDouble::setSize(const std::string& value, GNEUndoList* undoList) {
476 const auto laneLength = myMovedElement->getHierarchicalElement()->getParentLanes().front()->getLaneShapeLength();
477 const double newSize = GNEAttributeCarrier::parse<double>(value);
478 // continue depending of values of start und end position
480 // get middle lengths
481 const double center = (getStartFixedPositionOverLane(false) + getEndFixedPositionOverLane(false)) * 0.5;
482 // calculate new lenghts
483 double newStartPos = center - (newSize * 0.5);
484 double newEndPos = center + (newSize * 0.5);
485 // adjust positions
486 if (newStartPos < 0) {
487 newStartPos = 0;
488 }
489 if (newEndPos > laneLength) {
490 newEndPos = laneLength;
491 }
492 // set new start und end positions
493 undoList->begin(myMovedElement, TLF(" %'s size", myMovedElement->getTagStr()));
496 undoList->end();
497 } else if (myStartPos->myPosOverLane != INVALID_DOUBLE) {
498 double newStartPos = laneLength - newSize;
499 // adjust new StartPos
500 if (newStartPos < 0) {
501 newStartPos = 0;
502 }
503 undoList->begin(myMovedElement, TLF(" %'s size", myMovedElement->getTagStr()));
505 undoList->end();
506 } else if (myEndPos->myPosOverLane != INVALID_DOUBLE) {
507 double newEndPos = newSize;
508 // adjust endPos
509 if (newEndPos > laneLength) {
510 newEndPos = laneLength;
511 }
512 undoList->begin(myMovedElement, TLF(" %'s size", myMovedElement->getTagStr()));
514 undoList->end();
515 }
516}
517
518/****************************************************************************/
GUIViewObjectsHandler gViewObjectsHandler
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
@ SUMO_ATTR_LANE
@ GNE_ATTR_FORCESIZE
size (used in stopping places)
@ SUMO_ATTR_LANES
@ GNE_ATTR_SIZE
size (used in stopping places)
@ GNE_ATTR_REFERENCE
reference position (used creating stoppingPlaces)
@ SUMO_ATTR_CENTER
@ SUMO_ATTR_FRIENDLY_POS
@ SUMO_ATTR_LENGTH
@ GNE_ATTR_SHIFTLANEINDEX
shift lane index (only used by elements over lanes)
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:68
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
static bool areLaneConnected(const std::vector< GNELane * > &lanes)
check if the given lanes are connected
static bool areLaneConsecutives(const std::vector< GNELane * > &lanes)
check if the given lanes are consecutive
bool drawMovingGeometryPoints() const
check if draw moving geometry points
virtual GNEMoveElement * getMoveElement() const =0
get GNEMoveElement associated with this AttributeCarrier
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
bool isTemplate() const
check if this AC is template
Position getCommonAttributePosition(SumoXMLAttr key) const
const GNETagProperties * getTagProperty() const
get tagProperty associated with this Attribute Carrier
virtual GNEHierarchicalElement * getHierarchicalElement()=0
methods to retrieve the elements linked to this AttributeCarrier
GNENet * getNet() const
get pointer to net
static std::string parseIDs(const std::vector< T > &ACs)
parses a list of specific Attribute Carriers into a string of IDs
bool isCommonAttributeValid(SumoXMLAttr key, const std::string &value) const
virtual void updateGeometry()=0
update pre-computed geometry information
virtual void setAttribute(SumoXMLAttr key, const std::string &value, GNEUndoList *undoList)=0
virtual std::string getAttribute(SumoXMLAttr key) const =0
std::string getCommonAttribute(SumoXMLAttr key) const
virtual GUIGlObject * getGUIGlObject()=0
get GUIGlObject associated with this AttributeCarrier
static void changeAttribute(GNEAttributeCarrier *AC, SumoXMLAttr key, const std::string &value, GNEUndoList *undoList, const bool force=false)
change attribute
const GNEHierarchicalContainerParents< GNELane * > & getParentLanes() const
get parent lanes
double myMovingLateralOffset
move element lateral offset
GNEAttributeCarrier * myMovedElement
pointer to element
std::string getMovingAttribute(SumoXMLAttr key) const override
get moving attribute
void removeGeometryPoint(const Position clickedPosition, GNEUndoList *undoList) override
remove geometry point in the clicked position
void fixMovingProblem()
fix moving problem
Position getMovingAttributePosition(SumoXMLAttr key) const override
get moving attribute position
double getEndFixedPositionOverLane(const bool adjustGeometryFactor) const
get end offset position over lane
void setSize(const std::string &value, GNEUndoList *undoList)
set size
void setMoveShape(const GNEMoveResult &moveResult) override
set move shape
double getMovingAttributeDouble(SumoXMLAttr key) const override
get moving attribute double
GNEMoveOperation * getMoveOperation()
get lane movable move operation for elements with
GNEMoveElementLaneSingle * myEndPos
end position
void commitMoveShape(const GNEMoveResult &moveResult, GNEUndoList *undoList) override
commit move shape
std::string getMovingProblem() const
return a string with the current moving problem
bool isMovingAttributeValid(SumoXMLAttr key, const std::string &value) const override
check if the given moving attribute is valid
PositionVector getMovingAttributePositionVector(SumoXMLAttr key) const override
get moving attribute positionVector
ReferencePosition myReferencePosition
reference position
bool isMoveElementValid() const
check if current moving element is valid to be written into XML
double getStartFixedPositionOverLane(const bool adjustGeometryFactor) const
get start offset position over lane
double myTemplateSize
size (only use in AttributeCarrier templates)
void writeMoveAttributes(OutputDevice &device, const bool writeLength) const
write move attributes
bool myTemplateForceSize
force size (only used in AttributeCarrier templates
static const double defaultSize
default element size
GNEMoveElementLaneDouble(GNEAttributeCarrier *element, SumoXMLAttr startPosAttr, double &startPosValue, SumoXMLAttr endPosAttr, double &endPosValue, bool &friendlyPosition)
Constructor.
GNEMoveElementLaneSingle * myStartPos
start position
void setMovingAttribute(SumoXMLAttr key, const std::string &value, GNEUndoList *undoList) override
set moving attribute (using undo-list)
double & myPosOverLane
position over lane
bool & myFriendlyPos
friendly position
bool isMoveElementValid() const
check if current moving element is valid to be written into XML
std::string getMovingProblem() const
return a string with the current moving problem
SumoXMLAttr myPosAttr
pos attribute
std::string getMovingAttribute(SumoXMLAttr key) const override
get moving attribute
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
void commitMoveShape(const GNEMoveResult &moveResult, GNEUndoList *undoList) override
commit move shape
void setMoveShape(const GNEMoveResult &moveResult) override
set move shape
GNEMoveOperation * getMoveOperation()
get move operation
double getFixedPositionOverLane(const bool adjustGeometryFactor) const
get fixed offset position over lane
void fixMovingProblem()
fix moving problem
bool getAllowChangeLane() const
allow change lane
CommonMoveOptions * getCommonMoveOptions() const
get common mode options
double newFirstPos
new first position
double firstLaneOffset
lane offset
double newLastPos
new last position
GNEViewNet * getViewNet() const
get view net
Definition GNENet.cpp:2193
double getDefaultDoubleValue(SumoXMLAttr attr) const
get default double value
bool hasAttribute(SumoXMLAttr attr) const
check if current TagProperties owns the attribute "attr"
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...
GNEViewParent * getViewParent() const
get the net object
GNEUndoList * getUndoList() const
get the undoList object
GNEMoveFrame * getMoveFrame() const
get frame for move elements
bool isObjectSelected(const GUIGlObject *GLObject) const
check if element was already selected
const std::vector< int > & getSelectedGeometryPoints(const GUIGlObject *GLObject) const
get geometry points for the given glObject
Static storage of an output device and its base (abstract) implementation.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
A list of positions.
static StringBijection< ReferencePosition > ReferencePositions
reference positions (used creating certain elements in netedit)
const std::string & getString(const T key) const
get string
bool hasString(const std::string &str) const
check if the given string exist
T get(const std::string &str) const
get key
A structure which describes a connection between edges or lanes.
Definition NBEdge.h:201