Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEAccess.cpp
169684 views
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
/****************************************************************************/
14
/// @file GNEAccess.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jun 2018
17
///
18
//
19
/****************************************************************************/
20
#include <config.h>
21
22
#include <netedit/GNENet.h>
23
#include <netedit/GNETagProperties.h>
24
#include <netedit/GNEUndoList.h>
25
#include <netedit/GNEViewNet.h>
26
#include <netedit/GNEViewParent.h>
27
#include <netedit/changes/GNEChange_Attribute.h>
28
#include <netedit/frames/common/GNEMoveFrame.h>
29
#include <utils/gui/div/GLHelper.h>
30
#include <utils/gui/globjects/GLIncludes.h>
31
#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>
32
#include <utils/xml/NamespaceIDs.h>
33
34
#include "GNEAccess.h"
35
#include "GNEAdditionalHandler.h"
36
37
// ===========================================================================
38
// member method definitions
39
// ===========================================================================
40
41
GNEAccess::GNEAccess(GNENet* net) :
42
GNEAdditional("", net, "", SUMO_TAG_ACCESS, ""),
43
myPositionOverLane(0),
44
myLength(0),
45
myFriendlyPosition(false) {
46
}
47
48
49
GNEAccess::GNEAccess(GNEAdditional* busStop, GNELane* lane, const double pos, const std::string& specialPos,
50
const bool friendlyPos, const double length, const Parameterised::Map& parameters) :
51
GNEAdditional(busStop, SUMO_TAG_ACCESS, ""),
52
Parameterised(parameters),
53
myPositionOverLane(pos),
54
mySpecialPosition(specialPos),
55
myLength(length),
56
myFriendlyPosition(friendlyPos) {
57
// set parents
58
setParent<GNELane*>(lane);
59
setParent<GNEAdditional*>(busStop);
60
// update centering boundary without updating grid
61
updateCenteringBoundary(false);
62
}
63
64
65
GNEAccess::~GNEAccess() {
66
}
67
68
69
GNEMoveOperation*
70
GNEAccess::getMoveOperation() {
71
// return move operation for additional placed over shape
72
return new GNEMoveOperation(this, getParentLanes().front(), myPositionOverLane,
73
myNet->getViewNet()->getViewParent()->getMoveFrame()->getCommonMoveOptions()->getAllowChangeLane());
74
}
75
76
77
void
78
GNEAccess::updateGeometry() {
79
// set start position
80
double fixedPositionOverLane;
81
if (myPositionOverLane < 0) {
82
fixedPositionOverLane = 0;
83
} else if (myPositionOverLane > getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength()) {
84
fixedPositionOverLane = getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength();
85
} else {
86
fixedPositionOverLane = myPositionOverLane;
87
}
88
// update geometry
89
myAdditionalGeometry.updateGeometry(getParentLanes().front()->getLaneShape(), fixedPositionOverLane * getParentLanes().front()->getLengthGeometryFactor(), myMoveElementLateralOffset);
90
}
91
92
93
Position
94
GNEAccess::getPositionInView() const {
95
return myAdditionalGeometry.getShape().getPolygonCenter();
96
}
97
98
99
void
100
GNEAccess::updateCenteringBoundary(const bool /*updateGrid*/) {
101
// nothing to update
102
}
103
104
105
void
106
GNEAccess::splitEdgeGeometry(const double splitPosition, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* newElement, GNEUndoList* undoList) {
107
if (splitPosition < myPositionOverLane) {
108
// change lane
109
setAttribute(SUMO_ATTR_LANE, newElement->getID(), undoList);
110
// now adjust start position
111
setAttribute(SUMO_ATTR_POSITION, toString(myPositionOverLane - splitPosition), undoList);
112
}
113
}
114
115
116
bool
117
GNEAccess::isAccessPositionFixed() const {
118
// with friendly position enabled position are "always fixed"
119
if (myFriendlyPosition) {
120
return true;
121
} else {
122
if (myPositionOverLane != INVALID_DOUBLE) {
123
return (myPositionOverLane >= 0) && (myPositionOverLane <= getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength());
124
} else {
125
return false;
126
}
127
}
128
}
129
130
131
void
132
GNEAccess::writeAdditional(OutputDevice& device) const {
133
device.openTag(SUMO_TAG_ACCESS);
134
device.writeAttr(SUMO_ATTR_LANE, getParentLanes().front()->getID());
135
device.writeAttr(SUMO_ATTR_POSITION, getAttribute(SUMO_ATTR_POSITION));
136
if (myLength != -1) {
137
device.writeAttr(SUMO_ATTR_LENGTH, myLength);
138
}
139
if (myFriendlyPosition) {
140
device.writeAttr(SUMO_ATTR_FRIENDLY_POS, myFriendlyPosition);
141
}
142
device.closeTag();
143
}
144
145
146
bool
147
GNEAccess::isAdditionalValid() const {
148
// with friendly position enabled position is "always fixed"
149
if (myFriendlyPosition) {
150
return true;
151
} else if (myPositionOverLane == INVALID_DOUBLE) {
152
return true;
153
} else {
154
return fabs(myPositionOverLane) <= getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength();
155
}
156
}
157
158
159
std::string GNEAccess::getAdditionalProblem() const {
160
// obtain final length
161
const double len = getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength();
162
// check if detector has a problem
163
if (GNEAdditionalHandler::checkLanePosition(myPositionOverLane, 0, len, myFriendlyPosition)) {
164
return "";
165
} else {
166
// declare variable for error position
167
std::string errorPosition;
168
// check positions over lane
169
if (myPositionOverLane < 0) {
170
errorPosition = (toString(SUMO_ATTR_POSITION) + " < 0");
171
}
172
if (myPositionOverLane > len) {
173
errorPosition = (toString(SUMO_ATTR_POSITION) + TL(" > lanes's length"));
174
}
175
return errorPosition;
176
}
177
}
178
179
180
void GNEAccess::fixAdditionalProblem() {
181
// declare new position
182
double newPositionOverLane = myPositionOverLane;
183
// declare new length (but unsed in this context)
184
double length = 0;
185
// fix pos and length with fixLanePosition
186
GNEAdditionalHandler::fixLanePosition(newPositionOverLane, length, getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength());
187
// set new position
188
setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myNet->getViewNet()->getUndoList());
189
}
190
191
192
bool
193
GNEAccess::checkDrawMoveContour() const {
194
// get edit modes
195
const auto& editModes = myNet->getViewNet()->getEditModes();
196
// check if we're in move mode
197
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
198
!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&
199
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
200
// only move the first element
201
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
202
} else {
203
return false;
204
}
205
}
206
207
208
GNEEdge*
209
GNEAccess::getEdge() const {
210
return getParentLanes().front()->getParentEdge();
211
}
212
213
214
std::string
215
GNEAccess::getParentName() const {
216
return getParentAdditionals().at(0)->getID();
217
}
218
219
220
void
221
GNEAccess::drawGL(const GUIVisualizationSettings& s) const {
222
// first check if additional has to be drawn
223
if (myNet->getViewNet()->getDataViewOptions().showAdditionals()) {
224
// Obtain exaggeration
225
const double accessExaggeration = getExaggeration(s);
226
// adjust radius depending of mode and distance to mouse position
227
double radius = 0.5;
228
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() &&
229
myNet->getViewNet()->getPositionInformation().distanceSquaredTo2D(myAdditionalGeometry.getShape().front()) < 1) {
230
radius = 1;
231
}
232
// get detail level
233
const auto d = s.getDetailLevel(1);
234
// draw geometry only if we'rent in drawForObjectUnderCursor mode
235
if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {
236
// get color
237
RGBColor accessColor;
238
if (drawUsingSelectColor()) {
239
accessColor = s.colorSettings.selectedAdditionalColor;
240
} else if (!getParentAdditionals().front()->getAttribute(SUMO_ATTR_COLOR).empty()) {
241
accessColor = parse<RGBColor>(getParentAdditionals().front()->getAttribute(SUMO_ATTR_COLOR));
242
} else if (getParentAdditionals().front()->getTagProperty()->getTag() == SUMO_TAG_CONTAINER_STOP) {
243
accessColor = s.colorSettings.containerStopColor;
244
} else {
245
accessColor = s.colorSettings.busStopColor;
246
}
247
// draw parent and child lines
248
drawParentChildLines(s, accessColor);
249
// push layer matrix
250
GLHelper::pushMatrix();
251
// translate to front
252
drawInLayer(GLO_ACCESS);
253
// set color
254
GLHelper::setColor(accessColor);
255
// translate to geometry position
256
glTranslated(myAdditionalGeometry.getShape().front().x(), myAdditionalGeometry.getShape().front().y(), 0);
257
// draw circle
258
GLHelper::drawFilledCircleDetailled(d, radius * accessExaggeration);
259
// pop layer matrix
260
GLHelper::popMatrix();
261
// draw lock icon
262
GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), myAdditionalGeometry.getShape().front(), accessExaggeration, 0.3);
263
// draw dotted contour
264
myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
265
}
266
// calculate contour
267
myAdditionalContour.calculateContourCircleShape(s, d, this, myAdditionalGeometry.getShape().front(), radius, getType(),
268
accessExaggeration, getParentLanes().front()->getParentEdge());
269
}
270
}
271
272
273
std::string
274
GNEAccess::getAttribute(SumoXMLAttr key) const {
275
switch (key) {
276
case SUMO_ATTR_ID:
277
return getParentAdditionals().front()->getID();
278
case SUMO_ATTR_LANE:
279
return getParentLanes().front()->getID();
280
case SUMO_ATTR_POSITION:
281
if (myPositionOverLane == INVALID_DOUBLE) {
282
return mySpecialPosition;
283
} else {
284
return toString(myPositionOverLane);
285
}
286
case SUMO_ATTR_LENGTH:
287
if (myLength == -1) {
288
return "";
289
} else {
290
return toString(myLength);
291
}
292
case SUMO_ATTR_FRIENDLY_POS:
293
return toString(myFriendlyPosition);
294
case GNE_ATTR_PARENT:
295
if (isTemplate()) {
296
return "";
297
} else {
298
return getParentAdditionals().at(0)->getID();
299
}
300
case GNE_ATTR_SHIFTLANEINDEX:
301
return "";
302
default:
303
return getCommonAttribute(this, key);
304
}
305
}
306
307
308
double
309
GNEAccess::getAttributeDouble(SumoXMLAttr key) const {
310
throw InvalidArgument(getTagStr() + " doesn't have a double attribute of type '" + toString(key) + "'");
311
}
312
313
314
const Parameterised::Map&
315
GNEAccess::getACParametersMap() const {
316
return getParametersMap();
317
}
318
319
320
void
321
GNEAccess::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
322
switch (key) {
323
case SUMO_ATTR_LANE:
324
case SUMO_ATTR_POSITION:
325
case SUMO_ATTR_LENGTH:
326
case SUMO_ATTR_FRIENDLY_POS:
327
case GNE_ATTR_PARENT:
328
case GNE_ATTR_SHIFTLANEINDEX:
329
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
330
break;
331
default:
332
setCommonAttribute(key, value, undoList);
333
break;
334
}
335
}
336
337
338
bool
339
GNEAccess::isValid(SumoXMLAttr key, const std::string& value) {
340
switch (key) {
341
case SUMO_ATTR_LANE: {
342
GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(value, false);
343
if (lane != nullptr) {
344
if (getParentLanes().front()->getParentEdge()->getID() != lane->getParentEdge()->getID()) {
345
return GNEAdditionalHandler::accessCanBeCreated(getParentAdditionals().at(0), lane->getParentEdge());
346
} else {
347
return true;
348
}
349
} else {
350
return false;
351
}
352
}
353
case SUMO_ATTR_POSITION:
354
if (value.empty() || value == "random" || value == "doors" || value == "carriage") {
355
return true;
356
} else {
357
return canParse<double>(value);
358
}
359
case SUMO_ATTR_LENGTH:
360
if (canParse<double>(value)) {
361
const double valueDouble = parse<double>(value);
362
return (valueDouble == -1) || (valueDouble >= 0);
363
} else {
364
return false;
365
}
366
case SUMO_ATTR_FRIENDLY_POS:
367
return canParse<bool>(value);
368
case GNE_ATTR_PARENT:
369
return (myNet->getAttributeCarriers()->retrieveAdditionals(NamespaceIDs::busStops, value, false) != nullptr);
370
default:
371
return isCommonValid(key, value);
372
}
373
}
374
375
376
std::string
377
GNEAccess::getPopUpID() const {
378
return getTagStr();
379
}
380
381
382
std::string
383
GNEAccess::getHierarchyName() const {
384
return getTagStr() + ": " + getParentLanes().front()->getParentEdge()->getID();
385
}
386
387
// ===========================================================================
388
// private
389
// ===========================================================================
390
391
void
392
GNEAccess::setAttribute(SumoXMLAttr key, const std::string& value) {
393
switch (key) {
394
case SUMO_ATTR_LANE:
395
replaceAdditionalParentLanes(value);
396
break;
397
case SUMO_ATTR_POSITION:
398
if (value.empty()) {
399
myPositionOverLane = 0;
400
} else if (value == "random" || value == "doors" || value == "carriage") {
401
myPositionOverLane = INVALID_DOUBLE;
402
mySpecialPosition = value;
403
} else {
404
myPositionOverLane = parse<double>(value);
405
}
406
break;
407
case SUMO_ATTR_LENGTH:
408
if (value.empty()) {
409
myLength = myTagProperty->getDefaultDoubleValue(key);
410
} else {
411
myLength = parse<double>(value);
412
}
413
break;
414
case SUMO_ATTR_FRIENDLY_POS:
415
myFriendlyPosition = parse<bool>(value);
416
break;
417
case GNE_ATTR_PARENT:
418
if (myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_BUS_STOP, value, false) != nullptr) {
419
replaceAdditionalParent(SUMO_TAG_BUS_STOP, value, 0);
420
} else if (myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_TRAIN_STOP, value, false) != nullptr) {
421
replaceAdditionalParent(SUMO_TAG_TRAIN_STOP, value, 0);
422
} else {
423
replaceAdditionalParent(SUMO_TAG_CONTAINER_STOP, value, 0);
424
}
425
break;
426
case GNE_ATTR_SHIFTLANEINDEX:
427
shiftLaneIndex();
428
break;
429
default:
430
setCommonAttribute(this, key, value);
431
break;
432
}
433
}
434
435
436
void
437
GNEAccess::setMoveShape(const GNEMoveResult& moveResult) {
438
// change both position
439
myPositionOverLane = moveResult.newFirstPos;
440
// set lateral offset
441
myMoveElementLateralOffset = moveResult.firstLaneOffset;
442
// update geometry
443
updateGeometry();
444
}
445
446
447
void
448
GNEAccess::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {
449
// reset lateral offset
450
myMoveElementLateralOffset = 0;
451
undoList->begin(this, "position of " + getTagStr());
452
// now adjust start position
453
setAttribute(SUMO_ATTR_POSITION, toString(moveResult.newFirstPos), undoList);
454
// check if lane has to be changed
455
if (moveResult.newFirstLane) {
456
// set new lane
457
setAttribute(SUMO_ATTR_LANE, moveResult.newFirstLane->getID(), undoList);
458
}
459
// end change attribute
460
undoList->end();
461
}
462
463
464
/****************************************************************************/
465
466