Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEParkingSpace.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 GNEParkingSpace.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Feb 2018
17
///
18
// A lane area vehicles can halt at (GNE version)
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/changes/GNEChange_Attribute.h>
27
#include <utils/gui/div/GLHelper.h>
28
#include <utils/gui/globjects/GLIncludes.h>
29
#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>
30
31
#include "GNEParkingSpace.h"
32
33
// ===========================================================================
34
// method definitions
35
// ===========================================================================
36
37
GNEParkingSpace::GNEParkingSpace(GNENet* net) :
38
GNEAdditional("", net, "", SUMO_TAG_PARKING_SPACE, ""),
39
mySlope(0) {
40
}
41
42
43
GNEParkingSpace::GNEParkingSpace(GNEAdditional* parkingAreaParent, const Position& pos,
44
const std::string& width, const std::string& length, const std::string& angle, double slope,
45
const std::string& name, const Parameterised::Map& parameters) :
46
GNEAdditional(parkingAreaParent, SUMO_TAG_PARKING_SPACE, name),
47
Parameterised(parameters),
48
myPosition(pos),
49
myWidth(width),
50
myLength(length),
51
myAngle(angle),
52
mySlope(slope) {
53
// set parents
54
setParent<GNEAdditional*>(parkingAreaParent);
55
// update centering boundary without updating grid
56
updateCenteringBoundary(false);
57
}
58
59
60
GNEParkingSpace::~GNEParkingSpace() {}
61
62
63
GNEMoveOperation*
64
GNEParkingSpace::getMoveOperation() {
65
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() &&
66
(myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_MOVE) &&
67
myNet->getViewNet()->getMouseButtonKeyPressed().shiftKeyPressed()) {
68
// get snap radius
69
const double snap_radius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;
70
// get mouse position
71
const Position mousePosition = myNet->getViewNet()->getPositionInformation();
72
// check if we're editing width or height
73
if (myShapeLength.back().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {
74
// edit length
75
return new GNEMoveOperation(this, myShapeLength, false, GNEMoveOperation::OperationType::LENGTH);
76
} else if (myShapeWidth.front().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {
77
// edit width
78
return new GNEMoveOperation(this, myShapeWidth, true, GNEMoveOperation::OperationType::WIDTH);
79
} else if (myShapeWidth.back().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {
80
// edit width
81
return new GNEMoveOperation(this, myShapeWidth, false, GNEMoveOperation::OperationType::WIDTH);
82
} else {
83
return nullptr;
84
}
85
} else {
86
// move entire space
87
return new GNEMoveOperation(this, myPosition);
88
}
89
}
90
91
92
void
93
GNEParkingSpace::writeAdditional(OutputDevice& device) const {
94
device.openTag(getTagProperty()->getTag());
95
if (!myAdditionalName.empty()) {
96
device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myAdditionalName));
97
}
98
device.writeAttr(SUMO_ATTR_X, myPosition.x());
99
device.writeAttr(SUMO_ATTR_Y, myPosition.y());
100
if (myPosition.z() != 0) {
101
device.writeAttr(SUMO_ATTR_Z, myPosition.z());
102
}
103
if (myWidth.size() > 0) {
104
device.writeAttr(SUMO_ATTR_WIDTH, myWidth);
105
}
106
if (myLength.size() > 0) {
107
device.writeAttr(SUMO_ATTR_LENGTH, myLength);
108
}
109
if (myAngle.size() > 0) {
110
device.writeAttr(SUMO_ATTR_ANGLE, myAngle);
111
}
112
if (mySlope != myTagProperty->getDefaultDoubleValue(SUMO_ATTR_SLOPE)) {
113
device.writeAttr(SUMO_ATTR_SLOPE, mySlope);
114
}
115
// write parameters (Always after children to avoid problems with additionals.xsd)
116
writeParams(device);
117
device.closeTag();
118
}
119
120
121
bool GNEParkingSpace::isAdditionalValid() const {
122
return true;
123
}
124
125
126
std::string GNEParkingSpace::getAdditionalProblem() const {
127
return "";
128
}
129
130
131
void GNEParkingSpace::fixAdditionalProblem() {
132
// nothing to fix
133
}
134
135
136
bool
137
GNEParkingSpace::checkDrawMoveContour() const {
138
// get edit modes
139
const auto& editModes = myNet->getViewNet()->getEditModes();
140
// check if we're in move mode
141
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
142
!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&
143
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
144
// only move the first element
145
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
146
} else {
147
return false;
148
}
149
}
150
151
152
void
153
GNEParkingSpace::updateGeometry() {
154
// get width an length
155
const double width = getAttributeDouble(SUMO_ATTR_WIDTH) <= 0 ? POSITION_EPS : getAttributeDouble(SUMO_ATTR_WIDTH);
156
const double length = getAttributeDouble(SUMO_ATTR_LENGTH) <= 0 ? POSITION_EPS : getAttributeDouble(SUMO_ATTR_LENGTH);
157
// calculate shape length
158
myShapeLength.clear();
159
myShapeLength.push_back(Position(0, 0));
160
myShapeLength.push_back(Position(0, length));
161
// rotate
162
myShapeLength.rotate2D(DEG2RAD(getAttributeDouble(SUMO_ATTR_ANGLE)));
163
// move
164
myShapeLength.add(myPosition);
165
// calculate shape width
166
PositionVector leftShape = myShapeLength;
167
leftShape.move2side(width * -0.5);
168
PositionVector rightShape = myShapeLength;
169
rightShape.move2side(width * 0.5);
170
myShapeWidth = {leftShape.getCentroid(), rightShape.getCentroid()};
171
// update centering boundary
172
updateCenteringBoundary(true);
173
}
174
175
176
Position
177
GNEParkingSpace::getPositionInView() const {
178
return myPosition;
179
}
180
181
182
void
183
GNEParkingSpace::updateCenteringBoundary(const bool updateGrid) {
184
// remove additional from grid
185
if (updateGrid) {
186
myNet->removeGLObjectFromGrid(this);
187
}
188
// first reset boundary
189
myAdditionalBoundary.reset();
190
// add position
191
myAdditionalBoundary.add(myPosition);
192
// grow width and length
193
myAdditionalBoundary.grow(myShapeLength.length2D());
194
myAdditionalBoundary.grow(myShapeWidth.length2D());
195
// grow
196
myAdditionalBoundary.grow(5);
197
// add additional into RTREE again
198
if (updateGrid) {
199
myNet->addGLObjectIntoGrid(this);
200
}
201
}
202
203
204
void
205
GNEParkingSpace::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {
206
// geometry of this element cannot be splitted
207
}
208
209
210
std::string
211
GNEParkingSpace::getParentName() const {
212
return getParentAdditionals().at(0)->getID();
213
}
214
215
216
void
217
GNEParkingSpace::drawGL(const GUIVisualizationSettings& s) const {
218
// first check if additional has to be drawn
219
if (myNet->getViewNet()->getDataViewOptions().showAdditionals()) {
220
// draw boundaries
221
GLHelper::drawBoundary(s, getCenteringBoundary());
222
// get exaggeration
223
const double spaceExaggeration = getExaggeration(s);
224
// get witdh
225
const double parkingSpaceWidth = myShapeWidth.length2D() * 0.5 + (spaceExaggeration * 0.1);
226
// get detail level
227
const auto d = s.getDetailLevel(spaceExaggeration);
228
// check if draw moving geometry points
229
const bool movingGeometryPoints = drawMovingGeometryPoints(false);
230
// draw geometry only if we'rent in drawForObjectUnderCursor mode
231
if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {
232
// draw space
233
drawSpace(s, d, parkingSpaceWidth, movingGeometryPoints);
234
// draw parent and child lines
235
drawParentChildLines(s, s.additionalSettings.connectionColor);
236
// draw lock icon
237
GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), myShapeLength.getPolygonCenter(), spaceExaggeration);
238
// Draw additional ID
239
drawAdditionalID(s);
240
// draw additional name
241
drawAdditionalName(s);
242
// draw dotted contours
243
if (movingGeometryPoints) {
244
// get snap radius
245
const double snapRadius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;
246
const double snapRadiusSquared = snapRadius * snapRadius;
247
// get mouse position
248
const Position mousePosition = myNet->getViewNet()->getPositionInformation();
249
// check if we're editing width or height
250
if (myShapeLength.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) {
251
myMovingContourUp.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
252
myMovingContourDown.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
253
} else if ((myShapeWidth.front().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) ||
254
(myShapeWidth.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared)) {
255
myMovingContourLeft.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
256
myMovingContourRight.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
257
}
258
} else {
259
myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
260
}
261
262
}
263
// calculate contour
264
calculateSpaceContour(s, d, parkingSpaceWidth, spaceExaggeration, movingGeometryPoints);
265
}
266
}
267
268
269
std::string
270
GNEParkingSpace::getAttribute(SumoXMLAttr key) const {
271
switch (key) {
272
case SUMO_ATTR_ID:
273
return getMicrosimID();
274
case SUMO_ATTR_POSITION:
275
return toString(myPosition);
276
case SUMO_ATTR_NAME:
277
return myAdditionalName;
278
case SUMO_ATTR_WIDTH:
279
return myWidth;
280
case SUMO_ATTR_LENGTH:
281
return myLength;
282
case SUMO_ATTR_ANGLE:
283
return myAngle;
284
case SUMO_ATTR_SLOPE:
285
return toString(mySlope);
286
case GNE_ATTR_PARENT:
287
if (isTemplate()) {
288
return "";
289
} else {
290
return getParentAdditionals().at(0)->getID();
291
}
292
default:
293
return getCommonAttribute(this, key);
294
}
295
}
296
297
298
double
299
GNEParkingSpace::getAttributeDouble(SumoXMLAttr key) const {
300
switch (key) {
301
case SUMO_ATTR_WIDTH:
302
return myWidth.empty() ? getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_WIDTH) : parse<double>(myWidth);
303
case SUMO_ATTR_LENGTH:
304
return myLength.empty() ? getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_LENGTH) : parse<double>(myLength);
305
case SUMO_ATTR_ANGLE:
306
return myAngle.empty() ? getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_ANGLE) : parse<double>(myAngle);
307
default:
308
throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
309
}
310
}
311
312
313
const Parameterised::Map&
314
GNEParkingSpace::getACParametersMap() const {
315
return getParametersMap();
316
}
317
318
319
void
320
GNEParkingSpace::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
321
if (value == getAttribute(key)) {
322
return; //avoid needless changes, later logic relies on the fact that attributes have changed
323
}
324
switch (key) {
325
case SUMO_ATTR_POSITION:
326
case SUMO_ATTR_NAME:
327
case SUMO_ATTR_WIDTH:
328
case SUMO_ATTR_LENGTH:
329
case SUMO_ATTR_ANGLE:
330
case SUMO_ATTR_SLOPE:
331
case GNE_ATTR_PARENT:
332
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
333
break;
334
default:
335
setCommonAttribute(key, value, undoList);
336
break;
337
}
338
}
339
340
341
bool
342
GNEParkingSpace::isValid(SumoXMLAttr key, const std::string& value) {
343
switch (key) {
344
case SUMO_ATTR_POSITION:
345
return canParse<Position>(value);
346
case SUMO_ATTR_NAME:
347
return SUMOXMLDefinitions::isValidAttribute(value);
348
case SUMO_ATTR_WIDTH:
349
return value.empty() || (canParse<double>(value) && (parse<double>(value) > 0));
350
case SUMO_ATTR_LENGTH:
351
return value.empty() || (canParse<double>(value) && (parse<double>(value) > 0));
352
case SUMO_ATTR_ANGLE:
353
return value.empty() || canParse<double>(value);
354
case SUMO_ATTR_SLOPE:
355
return canParse<double>(value);
356
case GNE_ATTR_PARENT:
357
return (myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_PARKING_AREA, value, false) != nullptr);
358
default:
359
return isCommonValid(key, value);
360
}
361
}
362
363
364
std::string
365
GNEParkingSpace::getPopUpID() const {
366
return getTagStr();
367
}
368
369
370
std::string
371
GNEParkingSpace::getHierarchyName() const {
372
return getTagStr() + ": " + getAttribute(SUMO_ATTR_POSITION);
373
}
374
375
// ===========================================================================
376
// private
377
// ===========================================================================
378
379
void
380
GNEParkingSpace::drawSpace(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
381
const double width, const bool movingGeometryPoints) const {
382
// get angle
383
const double angle = getAttributeDouble(SUMO_ATTR_ANGLE);
384
// get contour color
385
RGBColor contourColor = s.colorSettings.parkingSpaceColorContour;
386
if (drawUsingSelectColor()) {
387
contourColor = s.colorSettings.selectedAdditionalColor;
388
} else if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {
389
contourColor = s.colorSettings.parkingSpaceColorContour;
390
}
391
// push later matrix
392
GLHelper::pushMatrix();
393
// translate to front
394
drawInLayer(GLO_PARKING_SPACE);
395
// set contour color
396
GLHelper::setColor(contourColor);
397
// draw extern
398
GLHelper::drawBoxLines(myShapeLength, width);
399
// make a copy of myShapeLength and scale
400
PositionVector shapeLengthInner = myShapeLength;
401
shapeLengthInner.scaleAbsolute(-0.1);
402
// draw intern
403
if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {
404
// Traslate to front
405
glTranslated(0, 0, 0.1);
406
// set base color
407
GLHelper::setColor(drawUsingSelectColor() ? s.colorSettings.selectedAdditionalColor : s.colorSettings.parkingSpaceColor);
408
//draw intern
409
GLHelper::drawBoxLines(shapeLengthInner, width - 0.1);
410
}
411
// draw geometry points
412
if (movingGeometryPoints) {
413
if (myShapeLength.size() > 0) {
414
drawUpGeometryPoint(s, d, myShapeLength.back(), angle, RGBColor::ORANGE);
415
}
416
if (myShapeWidth.size() > 0) {
417
drawLeftGeometryPoint(s, d, myShapeWidth.back(), angle - 90, RGBColor::ORANGE);
418
drawRightGeometryPoint(s, d, myShapeWidth.front(), angle - 90, RGBColor::ORANGE);
419
}
420
}
421
// pop layer matrix
422
GLHelper::popMatrix();
423
}
424
425
426
void
427
GNEParkingSpace::calculateSpaceContour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
428
const double width, const double exaggeration, const bool movingGeometryPoints) const {
429
// check if we're calculating the contour or the moving geometry points
430
if (movingGeometryPoints) {
431
myMovingContourUp.calculateContourCircleShape(s, d, this, myShapeLength.back(), s.neteditSizeSettings.additionalGeometryPointRadius,
432
getType(), exaggeration, nullptr);
433
myMovingContourLeft.calculateContourCircleShape(s, d, this, myShapeWidth.front(), s.neteditSizeSettings.additionalGeometryPointRadius, getType(),
434
exaggeration, nullptr);
435
myMovingContourRight.calculateContourCircleShape(s, d, this, myShapeWidth.back(), s.neteditSizeSettings.additionalGeometryPointRadius, getType(),
436
exaggeration, nullptr);
437
} else {
438
myAdditionalContour.calculateContourExtrudedShape(s, d, this, myShapeLength, getType(), width, exaggeration, true, true, 0, nullptr, nullptr);
439
}
440
}
441
442
443
void
444
GNEParkingSpace::setAttribute(SumoXMLAttr key, const std::string& value) {
445
switch (key) {
446
case SUMO_ATTR_POSITION:
447
myPosition = parse<Position>(value);
448
// update geometry
449
updateGeometry();
450
break;
451
case SUMO_ATTR_NAME:
452
myAdditionalName = value;
453
break;
454
case SUMO_ATTR_WIDTH:
455
myWidth = value;
456
// update geometry (except for template)
457
if (getParentAdditionals().size() > 0) {
458
updateGeometry();
459
}
460
break;
461
case SUMO_ATTR_LENGTH:
462
myLength = value;
463
// update geometry (except for template)
464
if (getParentAdditionals().size() > 0) {
465
updateGeometry();
466
}
467
break;
468
case SUMO_ATTR_ANGLE:
469
myAngle = value;
470
// update geometry (except for template)
471
if (getParentAdditionals().size() > 0) {
472
updateGeometry();
473
}
474
break;
475
case SUMO_ATTR_SLOPE:
476
mySlope = parse<double>(value);
477
break;
478
case GNE_ATTR_PARENT:
479
replaceAdditionalParent(SUMO_TAG_PARKING_AREA, value, 0);
480
break;
481
default:
482
setCommonAttribute(this, key, value);
483
break;
484
}
485
}
486
487
488
void
489
GNEParkingSpace::setMoveShape(const GNEMoveResult& moveResult) {
490
// check what are being updated
491
if (moveResult.operationType == GNEMoveOperation::OperationType::LENGTH) {
492
myShapeLength[1] = moveResult.shapeToUpdate[1];
493
} else if (moveResult.operationType == GNEMoveOperation::OperationType::WIDTH) {
494
myShapeWidth = moveResult.shapeToUpdate;
495
} else {
496
myPosition = moveResult.shapeToUpdate.front();
497
// update geometry
498
updateGeometry();
499
}
500
}
501
502
503
void
504
GNEParkingSpace::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {
505
// check what are being updated
506
if (moveResult.operationType == GNEMoveOperation::OperationType::LENGTH) {
507
undoList->begin(this, "length of " + getTagStr());
508
setAttribute(SUMO_ATTR_LENGTH, toString(myShapeLength[0].distanceTo2D(moveResult.shapeToUpdate[1])), undoList);
509
undoList->end();
510
} else if (moveResult.operationType == GNEMoveOperation::OperationType::WIDTH) {
511
undoList->begin(this, "width of " + getTagStr());
512
setAttribute(SUMO_ATTR_WIDTH, toString(moveResult.shapeToUpdate.length2D()), undoList);
513
undoList->end();
514
} else {
515
undoList->begin(this, "position of " + getTagStr());
516
setAttribute(SUMO_ATTR_POSITION, toString(moveResult.shapeToUpdate.front()), undoList);
517
undoList->end();
518
}
519
}
520
521
/****************************************************************************/
522
523