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#include <config.h>
21
26#include <netedit/GNENet.h>
28#include <netedit/GNEUndoList.h>
31
34
35// ===========================================================================
36// static members
37// ===========================================================================
38
40
41// ===========================================================================
42// member method definitions
43// ===========================================================================
44
46 SumoXMLAttr startPosAttr, double& startPosValue, SumoXMLAttr endPosAttr,
47 double& endPosValue, bool& friendlyPosition) :
48 GNEMoveElement(element),
49 myStartPos(new GNEMoveElementLaneSingle(element, startPosAttr, startPosValue, friendlyPosition,
50 GNEMoveElementLaneSingle::PositionType::STARPOS)),
51 myEndPos(new GNEMoveElementLaneSingle(element, endPosAttr, endPosValue, friendlyPosition,
52 GNEMoveElementLaneSingle::PositionType::ENDPOS)) {
53}
54
55
60
61
64 const auto& parentLanes = myMovedElement->getHierarchicalElement()->getParentLanes();
65 // get allow change lane
67 // fist check if we're moving only extremes
69 // get geometry points under cursor
71 // continue depending of clicked geometry point
72 if (geometryPoints.empty()) {
73 return nullptr;
74 } else {
75 if (geometryPoints.front() == 0) {
76 // move start position
78 } else {
79 // move end position
80 return myEndPos->getMoveOperation();
81 }
82 }
84 // move both start and end positions depending of number of lanes
85 if (parentLanes.size() > 1) {
86 if (gViewObjectsHandler.isObjectSelected(parentLanes.front())) {
87 return new GNEMoveOperation(myMovedElement->getMoveElement(), parentLanes.front(), myStartPos->myPosOverLane, parentLanes.back(), myEndPos->myPosOverLane, true, false);
88 } else if (gViewObjectsHandler.isObjectSelected(parentLanes.back())) {
89 return new GNEMoveOperation(myMovedElement->getMoveElement(), parentLanes.front(), myStartPos->myPosOverLane, parentLanes.back(), myEndPos->myPosOverLane, false, false);
90 } else {
91 // temporal, in the future will be allow, clicking in the intermediate lanes
92 return nullptr;
93 }
94 } else {
95 return new GNEMoveOperation(myMovedElement->getMoveElement(), parentLanes.front(), myStartPos->myPosOverLane, myEndPos->myPosOverLane, allowChangeLane);
96 }
98 // move only start position
100 } else if (myEndPos->myPosOverLane != INVALID_DOUBLE) {
101 // move only end position
102 return myEndPos->getMoveOperation();
103 } else {
104 // start and end positions undefined, then nothing to move
105 return nullptr;
106 }
107}
108
109
110std::string
112 // position attributes
113 if (key == myStartPos->myPosAttr) {
114 return myStartPos->getMovingAttribute(key);
115 } else if (key == myEndPos->myPosAttr) {
116 return myEndPos->getMovingAttribute(key);
117 } else {
118 // other attributes
119 switch (key) {
120 case SUMO_ATTR_LANE:
121 case SUMO_ATTR_LANES:
124 return myStartPos->getMovingAttribute(key);
126 return "";
127 case SUMO_ATTR_LENGTH:
128 case GNE_ATTR_SIZE:
129 if (myMovedElement->isTemplate()) {
130 return toString(myTemplateSize);
131 } else {
133 }
138 default:
140 }
141 }
142}
143
144
145double
147 // position attributes
148 if (key == myStartPos->myPosAttr) {
150 } else if (key == myEndPos->myPosAttr) {
151 return myEndPos->myPosOverLane;
152 } else {
153 // other attributes
154 switch (key) {
155 case SUMO_ATTR_CENTER:
156 return (getStartFixedPositionOverLane(false) + getEndFixedPositionOverLane(false)) * 0.5;
157 case SUMO_ATTR_LENGTH:
158 case GNE_ATTR_SIZE:
159 if (myMovedElement->isTemplate()) {
160 return myTemplateSize;
161 } else {
163 }
164 default:
165 throw InvalidArgument(myMovedElement->getTagStr() + " doesn't have a moving attribute of type '" + toString(key) + "'");
166 }
167 }
168}
169
170
175
176
181
182
183void
185 // position attributes
186 if (key == myStartPos->myPosAttr) {
188 } else if (key == myEndPos->myPosAttr) {
190 } else {
191 // other attributes
192 switch (key) {
193 case SUMO_ATTR_LANE:
194 case SUMO_ATTR_LANES:
200 break;
201 case SUMO_ATTR_LENGTH:
202 if (myMovedElement->isTemplate()) {
203 // use size value
205 } else {
206 // change end position
207 GNEChange_Attribute::changeAttribute(myMovedElement, myEndPos->myPosAttr, toString(getStartFixedPositionOverLane(true) + GNEAttributeCarrier::parse<double>(value)), undoList);
208 }
209 break;
210 case GNE_ATTR_SIZE:
211 if (myMovedElement->isTemplate()) {
213 } else {
214 setSize(value, undoList);
215 }
216 break;
217 default:
218 myMovedElement->setCommonAttribute(key, value, undoList);
219 break;
220 }
221 }
222}
223
224
225bool
227 // position attributes
228 if (key == myStartPos->myPosAttr) {
229 return myStartPos->isMovingAttributeValid(key, value);
230 } else if (key == myEndPos->myPosAttr) {
231 return myEndPos->isMovingAttributeValid(key, value);
232 } else {
233 // other attributes
234 switch (key) {
235 case SUMO_ATTR_LANE:
236 case SUMO_ATTR_LANES:
237 if (value.empty()) {
238 return false;
239 } else {
240 return GNEAttributeCarrier::canParse<std::vector<GNELane*> >(myMovedElement->getNet(), value, true);
241 }
243 return myStartPos->isMovingAttributeValid(key, value);
245 return true;
246 case SUMO_ATTR_LENGTH:
247 case GNE_ATTR_SIZE:
248 if (value.empty()) {
249 return false;
250 } else {
251 return GNEAttributeCarrier::canParse<double>(value) && GNEAttributeCarrier::parse<double>(value) >= POSITION_EPS;
252 }
254 return GNEAttributeCarrier::canParse<bool>(value);
257 default:
258 return myMovedElement->isCommonAttributeValid(key, value);
259 }
260 }
261}
262
263
264void
266 // position attributes
267 if (key == myStartPos->myPosAttr) {
268 myStartPos->setMovingAttribute(key, value);
269 } else if (key == myEndPos->myPosAttr) {
270 myEndPos->setMovingAttribute(key, value);
271 } else {
272 // other attributes
273 switch (key) {
275 myStartPos->setMovingAttribute(key, value);
276 break;
277 case SUMO_ATTR_LENGTH:
278 case GNE_ATTR_SIZE:
279 if (value.empty()) {
281 } else {
282 myTemplateSize = GNEAttributeCarrier::parse<double>(value);
283 }
284 break;
286 myTemplateForceSize = GNEAttributeCarrier::parse<bool>(value);
287 break;
290 break;
291 default:
292 return myMovedElement->setCommonAttribute(key, value);
293 }
294 }
295}
296
297
298void
299GNEMoveElementLaneDouble::removeGeometryPoint(const Position /*clickedPosition*/, GNEUndoList* /*undoList*/) {
300 // nothing to do here
301}
302
303
304bool
306 // first check if lanes are connected
308 return false;
310 return false;
312 return false;
313 } else if ((myMovedElement->getHierarchicalElement()->getParentLanes().size() == 1) &&
314 (myStartPos->getFixedPositionOverLane(false) > (myEndPos->getFixedPositionOverLane(false) - POSITION_EPS))) {
315 return false;
316 } else {
317 return true;
318 }
319}
320
321
322std::string
324 // first check if lanes are connected
326 return TL("Lanes aren't consecutives");
328 return TL("Lanes aren't connected");
329 } else if (!myStartPos->isMoveElementValid()) {
331 } else if (!myEndPos->isMoveElementValid()) {
332 return myEndPos->getMovingProblem();
333 } else if ((myMovedElement->getHierarchicalElement()->getParentLanes().size() == 1) &&
334 (myStartPos->getFixedPositionOverLane(false) > (myEndPos->getFixedPositionOverLane(false) - POSITION_EPS))) {
335 return TL("starPos > (endPos - EPS)");
336 } else {
337 return "";
338 }
339}
340
341
342void
344 const auto undolist = myMovedElement->getNet()->getViewNet()->getUndoList();
345 // iterate over all lanes and build connections
346 for (int i = 1; i < (int)myMovedElement->getHierarchicalElement()->getParentLanes().size(); i++) {
347 // get lanes
348 const auto firstLane = myMovedElement->getHierarchicalElement()->getParentLanes().at(i - 1);
349 const auto secondLane = myMovedElement->getHierarchicalElement()->getParentLanes().at(i);
350 // search connection
351 bool foundConnection = false;
352 for (const auto& connection : firstLane->getParentEdge()->getGNEConnections()) {
353 if ((connection->getLaneFrom() == firstLane) && (connection->getLaneTo() == secondLane)) {
354 foundConnection = true;
355 break;
356 }
357 }
358 // check if connection exist
359 if (!foundConnection) {
360 // create new connection manually
361 NBEdge::Connection newCon(firstLane->getIndex(), secondLane->getParentEdge()->getNBEdge(), secondLane->getIndex());
362 // allow to undo creation of new lane
363 undolist->add(new GNEChange_Connection(firstLane->getParentEdge(), newCon, false, true), true);
364 }
365 }
366 // Fix both position
370 // extra if starPos > endPos (endPos is dominant)
371 const double finalLenght = myMovedElement->getHierarchicalElement()->getParentLanes().back()->getParentEdge()->getNBEdge()->getFinalLength();
372 const double maxStartPos = (myEndPos->myPosOverLane == INVALID_DOUBLE) ? finalLenght : (myEndPos->getFixedPositionOverLane(false) - POSITION_EPS);
373 if (maxStartPos < POSITION_EPS) {
375 myMovedElement->setAttribute(myEndPos->myPosAttr, toString(POSITION_EPS), undolist);
376 } else if (myStartPos->getFixedPositionOverLane(false) > maxStartPos) {
377 // use truncate to avoid problem precission under certain conditions
378 const double newStartPos = (std::trunc(maxStartPos * 1000) / 1000);
379 myMovedElement->setAttribute(myStartPos->myPosAttr, toString(newStartPos), undolist);
380 }
381 }
382}
383
384
385void
386GNEMoveElementLaneDouble::writeMoveAttributes(OutputDevice& device, const bool writeLength) const {
387 // lane/s
390 } else {
392 }
393 // write start position
396 }
397 // write end position depending of lenght
398 if (writeLength) {
402 }
403 // friendly position (only if true)
406 }
407}
408
409
410double
411GNEMoveElementLaneDouble::getStartFixedPositionOverLane(const bool adjustGeometryFactor) const {
412 if (myStartPos->getFixedPositionOverLane(adjustGeometryFactor) < 0) {
413 return 0;
414 } else if (myStartPos->getFixedPositionOverLane(adjustGeometryFactor) > (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) - POSITION_EPS)) {
415 return (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) - POSITION_EPS);
416 } else {
417 return myStartPos->getFixedPositionOverLane(adjustGeometryFactor);
418 }
419}
420
421
422double
423GNEMoveElementLaneDouble::getEndFixedPositionOverLane(const bool adjustGeometryFactor) const {
424 if (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) < POSITION_EPS) {
425 return POSITION_EPS;
426 } else if (myStartPos->getFixedPositionOverLane(adjustGeometryFactor) > (myEndPos->getFixedPositionOverLane(adjustGeometryFactor) - POSITION_EPS)) {
427 return myEndPos->getFixedPositionOverLane(adjustGeometryFactor);
428 } else {
429 return myEndPos->getFixedPositionOverLane(adjustGeometryFactor);
430 }
431}
432
433
434void
436 // check if we're moving both points
437 if ((moveResult.newFirstPos != INVALID_DOUBLE) && (moveResult.newLastPos != INVALID_DOUBLE)) {
438 // change both position
439 myStartPos->setMoveShape(moveResult);
440 myEndPos->setMoveShape(moveResult);
441 // set lateral offset
443 } else if (moveResult.newFirstPos != INVALID_DOUBLE) {
444 // change only start position
445 myStartPos->setMoveShape(moveResult);
446 } else if (moveResult.newLastPos != INVALID_DOUBLE) {
447 myEndPos->setMoveShape(moveResult);
448 }
449 // update geometry
451}
452
453
454void
456 // begin change attribute
457 undoList->begin(myMovedElement, TLF("position of %", myMovedElement->getTagStr()));
458 // check if we're moving both points
459 if ((moveResult.newFirstPos != INVALID_DOUBLE) && (moveResult.newLastPos != INVALID_DOUBLE)) {
460 // set both positions
461 myStartPos->commitMoveShape(moveResult, undoList);
462 myEndPos->commitMoveShape(moveResult, undoList);
463 } else if (moveResult.newFirstPos != INVALID_DOUBLE) {
464 // set only start position
465 myStartPos->commitMoveShape(moveResult, undoList);
466 } else if (moveResult.newLastPos != INVALID_DOUBLE) {
467 // set only end position
468 myEndPos->commitMoveShape(moveResult, undoList);
469 }
470 // end change attribute
471 undoList->end();
472}
473
474
475void
476GNEMoveElementLaneDouble::setSize(const std::string& value, GNEUndoList* undoList) {
477 const auto laneLength = myMovedElement->getHierarchicalElement()->getParentLanes().front()->getLaneShapeLength();
478 const double newSize = GNEAttributeCarrier::parse<double>(value);
479 // continue depending of values of start und end position
481 // get middle lengths
482 const double center = (getStartFixedPositionOverLane(false) + getEndFixedPositionOverLane(false)) * 0.5;
483 // calculate new lenghts
484 double newStartPos = center - (newSize * 0.5);
485 double newEndPos = center + (newSize * 0.5);
486 // adjust positions
487 if (newStartPos < 0) {
488 newStartPos = 0;
489 }
490 if (newEndPos > laneLength) {
491 newEndPos = laneLength;
492 }
493 // set new start und end positions
494 undoList->begin(myMovedElement, TLF(" %'s size", myMovedElement->getTagStr()));
497 undoList->end();
498 } else if (myStartPos->myPosOverLane != INVALID_DOUBLE) {
499 double newStartPos = laneLength - newSize;
500 // adjust new StartPos
501 if (newStartPos < 0) {
502 newStartPos = 0;
503 }
504 undoList->begin(myMovedElement, TLF(" %'s size", myMovedElement->getTagStr()));
506 undoList->end();
507 } else if (myEndPos->myPosOverLane != INVALID_DOUBLE) {
508 double newEndPos = newSize;
509 // adjust endPos
510 if (newEndPos > laneLength) {
511 newEndPos = laneLength;
512 }
513 undoList->begin(myMovedElement, TLF(" %'s size", myMovedElement->getTagStr()));
515 undoList->end();
516 }
517}
518
519/****************************************************************************/
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
GNEMoveElementLaneSingle * myEndPos
end position
void commitMoveShape(const GNEMoveResult &moveResult, GNEUndoList *undoList) override
commit move shape
GNEMoveOperation * getMoveOperation() override
get lane movable move operation for elements with
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
GNEMoveOperation * getMoveOperation() override
get move operation
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
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