Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEParkingSpace.cpp
193871 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 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
21
#include <netedit/changes/GNEChange_Attribute.h>
22
#include <netedit/elements/moving/GNEMoveElementViewResizable.h>
23
#include <netedit/GNENet.h>
24
#include <netedit/GNETagProperties.h>
25
#include <utils/gui/div/GLHelper.h>
26
27
#include "GNEParkingSpace.h"
28
29
// ===========================================================================
30
// method definitions
31
// ===========================================================================
32
33
GNEParkingSpace::GNEParkingSpace(GNENet* net) :
34
GNEAdditional(net, SUMO_TAG_PARKING_SPACE),
35
myMoveElementViewResizable(new GNEMoveElementViewResizable(this, GNEMoveElementView::AttributesFormat::CARTESIAN,
36
GNEMoveElementViewResizable::ResizingFormat::WIDTH_LENGTH, SUMO_ATTR_POSITION,
37
myPosOverView)) {
38
}
39
40
41
GNEParkingSpace::GNEParkingSpace(GNEAdditional* parkingAreaParent, const Position& pos,
42
const double width, const double length, const double angle,
43
const double slope, const std::string& name,
44
const Parameterised::Map& parameters) :
45
GNEAdditional(parkingAreaParent, SUMO_TAG_PARKING_SPACE, name),
46
Parameterised(parameters),
47
myPosOverView(pos),
48
myWidth(width),
49
myLength(length),
50
myMoveElementViewResizable(new GNEMoveElementViewResizable(this, GNEMoveElementView::AttributesFormat::CARTESIAN,
51
GNEMoveElementViewResizable::ResizingFormat::WIDTH_LENGTH, SUMO_ATTR_POSITION,
52
myPosOverView)),
53
myAngle(angle),
54
mySlope(slope) {
55
// set parents
56
setParent<GNEAdditional*>(parkingAreaParent);
57
// update centering boundary without updating grid
58
updateCenteringBoundary(false);
59
}
60
61
62
GNEParkingSpace::~GNEParkingSpace() {
63
delete myMoveElementViewResizable;
64
}
65
66
67
GNEMoveElement*
68
GNEParkingSpace::getMoveElement() const {
69
return myMoveElementViewResizable;
70
}
71
72
73
Parameterised*
74
GNEParkingSpace::getParameters() {
75
return this;
76
}
77
78
79
const Parameterised*
80
GNEParkingSpace::getParameters() const {
81
return this;
82
}
83
84
85
void
86
GNEParkingSpace::writeAdditional(OutputDevice& device) const {
87
device.openTag(getTagProperty()->getTag());
88
// write common additional attributes
89
writeAdditionalAttributes(device);
90
// write move atributes
91
myMoveElementViewResizable->writeMoveAttributes(device);
92
// write specific attributes
93
if (myWidth != INVALID_DOUBLE) {
94
device.writeAttr(SUMO_ATTR_WIDTH, myWidth);
95
}
96
if (myLength != INVALID_DOUBLE) {
97
device.writeAttr(SUMO_ATTR_LENGTH, myLength);
98
}
99
if (myAngle != INVALID_DOUBLE) {
100
device.writeAttr(SUMO_ATTR_ANGLE, myAngle);
101
}
102
if (mySlope != myTagProperty->getDefaultDoubleValue(SUMO_ATTR_SLOPE)) {
103
device.writeAttr(SUMO_ATTR_SLOPE, mySlope);
104
}
105
// write parameters (Always after children to avoid problems with additionals.xsd)
106
writeParams(device);
107
device.closeTag();
108
}
109
110
111
bool
112
GNEParkingSpace::isAdditionalValid() const {
113
return true;
114
}
115
116
117
std::string
118
GNEParkingSpace::getAdditionalProblem() const {
119
return "";
120
}
121
122
123
void
124
GNEParkingSpace::fixAdditionalProblem() {
125
// nothing to fix
126
}
127
128
129
bool
130
GNEParkingSpace::checkDrawMoveContour() const {
131
// get edit modes
132
const auto& editModes = myNet->getViewNet()->getEditModes();
133
// check if we're in move mode
134
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
135
!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&
136
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
137
// only move the first element
138
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
139
} else {
140
return false;
141
}
142
}
143
144
145
void
146
GNEParkingSpace::updateGeometry() {
147
// get width an length
148
const double width = getAttributeDouble(SUMO_ATTR_WIDTH) <= 0 ? POSITION_EPS : getAttributeDouble(SUMO_ATTR_WIDTH);
149
const double length = getAttributeDouble(SUMO_ATTR_LENGTH) <= 0 ? POSITION_EPS : getAttributeDouble(SUMO_ATTR_LENGTH);
150
// calculate shape length
151
myMoveElementViewResizable->myShapeHeight.clear();
152
myMoveElementViewResizable->myShapeHeight.push_back(Position(0, 0));
153
myMoveElementViewResizable->myShapeHeight.push_back(Position(0, length));
154
// rotate
155
myMoveElementViewResizable->myShapeHeight.rotate2D(DEG2RAD(getAttributeDouble(SUMO_ATTR_ANGLE)));
156
// move
157
myMoveElementViewResizable->myShapeHeight.add(myPosOverView);
158
// calculate shape width
159
PositionVector leftShape = myMoveElementViewResizable->myShapeHeight;
160
leftShape.move2side(width * -0.5);
161
PositionVector rightShape = myMoveElementViewResizable->myShapeHeight;
162
rightShape.move2side(width * 0.5);
163
myMoveElementViewResizable->myShapeWidth = {leftShape.getCentroid(), rightShape.getCentroid()};
164
// update centering boundary
165
updateCenteringBoundary(true);
166
}
167
168
169
Position
170
GNEParkingSpace::getPositionInView() const {
171
return myPosOverView;
172
}
173
174
175
void
176
GNEParkingSpace::updateCenteringBoundary(const bool updateGrid) {
177
// remove additional from grid
178
if (updateGrid) {
179
myNet->removeGLObjectFromGrid(this);
180
}
181
// first reset boundary
182
myAdditionalBoundary.reset();
183
// add position
184
myAdditionalBoundary.add(myPosOverView);
185
// add center
186
myAdditionalBoundary.add(myPosOverView);
187
// add width
188
for (const auto& pos : myMoveElementViewResizable->myShapeWidth) {
189
myAdditionalBoundary.add(pos);
190
}
191
// add length
192
for (const auto& pos : myMoveElementViewResizable->myShapeHeight) {
193
myAdditionalBoundary.add(pos);
194
}
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 = myMoveElementViewResizable->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();
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(), myMoveElementViewResizable->myShapeHeight.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 (myMoveElementViewResizable->myShapeHeight.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) {
251
myMoveElementViewResizable->myMovingContourUp.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
252
myMoveElementViewResizable->myMovingContourDown.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
253
} else if ((myMoveElementViewResizable->myShapeWidth.front().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) ||
254
(myMoveElementViewResizable->myShapeWidth.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared)) {
255
myMoveElementViewResizable->myMovingContourLeft.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
256
myMoveElementViewResizable->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_NAME:
275
return myAdditionalName;
276
case SUMO_ATTR_WIDTH:
277
return (myWidth != INVALID_DOUBLE) ? toString(myWidth) : "";
278
case SUMO_ATTR_LENGTH:
279
return (myLength != INVALID_DOUBLE) ? toString(myLength) : "";
280
case SUMO_ATTR_ANGLE:
281
return (myAngle != INVALID_DOUBLE) ? toString(myAngle) : "";;
282
case SUMO_ATTR_SLOPE:
283
return toString(mySlope);
284
case GNE_ATTR_PARENT:
285
if (isTemplate()) {
286
return "";
287
} else {
288
return getParentAdditionals().at(0)->getID();
289
}
290
default:
291
return myMoveElementViewResizable->getMovingAttribute(key);
292
}
293
}
294
295
296
double
297
GNEParkingSpace::getAttributeDouble(SumoXMLAttr key) const {
298
switch (key) {
299
case SUMO_ATTR_WIDTH:
300
return (myWidth != INVALID_DOUBLE) ? myWidth : getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_WIDTH);
301
case SUMO_ATTR_LENGTH:
302
return (myLength != INVALID_DOUBLE) ? myLength : getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_LENGTH);
303
case SUMO_ATTR_ANGLE:
304
return (myAngle != INVALID_DOUBLE) ? myAngle : getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_ANGLE);
305
default:
306
return myMoveElementViewResizable->getMovingAttributeDouble(key);
307
}
308
}
309
310
311
Position
312
GNEParkingSpace::getAttributePosition(SumoXMLAttr key) const {
313
return myMoveElementViewResizable->getMovingAttributePosition(key);
314
}
315
316
317
PositionVector
318
GNEParkingSpace::getAttributePositionVector(SumoXMLAttr key) const {
319
return myMoveElementViewResizable->getMovingAttributePositionVector(key);
320
}
321
322
323
void
324
GNEParkingSpace::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
325
if (value == getAttribute(key)) {
326
return; //avoid needless changes, later logic relies on the fact that attributes have changed
327
}
328
switch (key) {
329
case SUMO_ATTR_NAME:
330
case SUMO_ATTR_WIDTH:
331
case SUMO_ATTR_LENGTH:
332
case SUMO_ATTR_ANGLE:
333
case SUMO_ATTR_SLOPE:
334
case GNE_ATTR_PARENT:
335
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
336
break;
337
default:
338
myMoveElementViewResizable->setMovingAttribute(key, value, undoList);
339
break;
340
}
341
}
342
343
344
bool
345
GNEParkingSpace::isValid(SumoXMLAttr key, const std::string& value) {
346
switch (key) {
347
case SUMO_ATTR_NAME:
348
return SUMOXMLDefinitions::isValidAttribute(value);
349
case SUMO_ATTR_WIDTH:
350
return value.empty() || (canParse<double>(value) && (parse<double>(value) > 0));
351
case SUMO_ATTR_LENGTH:
352
return value.empty() || (canParse<double>(value) && (parse<double>(value) > 0));
353
case SUMO_ATTR_ANGLE:
354
return value.empty() || canParse<double>(value);
355
case SUMO_ATTR_SLOPE:
356
return canParse<double>(value);
357
case GNE_ATTR_PARENT:
358
return (myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_PARKING_AREA, value, false) != nullptr);
359
default:
360
return myMoveElementViewResizable->isMovingAttributeValid(key, value);
361
}
362
}
363
364
365
std::string
366
GNEParkingSpace::getPopUpID() const {
367
return getTagStr();
368
}
369
370
371
std::string
372
GNEParkingSpace::getHierarchyName() const {
373
return getTagStr() + ": " + getAttribute(SUMO_ATTR_POSITION);
374
}
375
376
// ===========================================================================
377
// private
378
// ===========================================================================
379
380
void
381
GNEParkingSpace::drawSpace(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
382
const double width, const bool movingGeometryPoints) const {
383
// get angle
384
const double angle = getAttributeDouble(SUMO_ATTR_ANGLE);
385
// get contour color
386
RGBColor contourColor = s.colorSettings.parkingSpaceColorContour;
387
if (drawUsingSelectColor()) {
388
contourColor = s.colorSettings.selectedAdditionalColor;
389
} else if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {
390
contourColor = s.colorSettings.parkingSpaceColorContour;
391
}
392
// push later matrix
393
GLHelper::pushMatrix();
394
// translate to front
395
drawInLayer(GLO_PARKING_SPACE);
396
// set contour color
397
GLHelper::setColor(contourColor);
398
// draw extern
399
GLHelper::drawBoxLines(myMoveElementViewResizable->myShapeHeight, width);
400
// make a copy of myShapeLength and scale
401
PositionVector shapeLengthInner = myMoveElementViewResizable->myShapeHeight;
402
shapeLengthInner.scaleAbsolute(-0.1);
403
// draw intern
404
if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {
405
// Traslate to front
406
glTranslated(0, 0, 0.1);
407
// set base color
408
GLHelper::setColor(drawUsingSelectColor() ? s.colorSettings.selectedAdditionalColor : s.colorSettings.parkingSpaceColor);
409
//draw intern
410
GLHelper::drawBoxLines(shapeLengthInner, width - 0.1);
411
}
412
// draw geometry points
413
if (movingGeometryPoints) {
414
if (myMoveElementViewResizable->myShapeHeight.size() > 0) {
415
drawUpGeometryPoint(s, d, myMoveElementViewResizable->myShapeHeight.back(), angle, RGBColor::ORANGE);
416
}
417
if (myMoveElementViewResizable->myShapeWidth.size() > 0) {
418
drawLeftGeometryPoint(s, d, myMoveElementViewResizable->myShapeWidth.back(), angle - 90, RGBColor::ORANGE);
419
drawRightGeometryPoint(s, d, myMoveElementViewResizable->myShapeWidth.front(), angle - 90, RGBColor::ORANGE);
420
}
421
}
422
// pop layer matrix
423
GLHelper::popMatrix();
424
}
425
426
427
void
428
GNEParkingSpace::calculateSpaceContour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
429
const double width, const double exaggeration, const bool movingGeometryPoints) const {
430
// check if we're calculating the contour or the moving geometry points
431
if (movingGeometryPoints) {
432
myMoveElementViewResizable->myMovingContourUp.calculateContourCircleShape(s, d, this, myMoveElementViewResizable->myShapeHeight.back(), s.neteditSizeSettings.additionalGeometryPointRadius,
433
getType(), exaggeration, nullptr);
434
myMoveElementViewResizable->myMovingContourLeft.calculateContourCircleShape(s, d, this, myMoveElementViewResizable->myShapeWidth.front(), s.neteditSizeSettings.additionalGeometryPointRadius, getType(),
435
exaggeration, nullptr);
436
myMoveElementViewResizable->myMovingContourRight.calculateContourCircleShape(s, d, this, myMoveElementViewResizable->myShapeWidth.back(), s.neteditSizeSettings.additionalGeometryPointRadius, getType(),
437
exaggeration, nullptr);
438
} else {
439
myAdditionalContour.calculateContourExtrudedShape(s, d, this, myMoveElementViewResizable->myShapeHeight, getType(), width, exaggeration, true, true, 0, nullptr, nullptr);
440
}
441
}
442
443
444
void
445
GNEParkingSpace::setAttribute(SumoXMLAttr key, const std::string& value) {
446
switch (key) {
447
case SUMO_ATTR_NAME:
448
myAdditionalName = value;
449
break;
450
case SUMO_ATTR_WIDTH:
451
if (value.empty()) {
452
myWidth = INVALID_DOUBLE;
453
} else {
454
myWidth = parse<double>(value);
455
}
456
break;
457
case SUMO_ATTR_LENGTH:
458
if (value.empty()) {
459
myLength = INVALID_DOUBLE;
460
} else {
461
myLength = parse<double>(value);
462
}
463
break;
464
case SUMO_ATTR_ANGLE:
465
if (value.empty()) {
466
myAngle = INVALID_DOUBLE;
467
} else {
468
myAngle = parse<double>(value);
469
}
470
break;
471
case SUMO_ATTR_SLOPE:
472
mySlope = parse<double>(value);
473
break;
474
case GNE_ATTR_PARENT:
475
replaceAdditionalParent(SUMO_TAG_PARKING_AREA, value, 0);
476
break;
477
default:
478
myMoveElementViewResizable->setMovingAttribute(key, value);
479
break;
480
}
481
// update geometry (except for template)
482
if (getParentAdditionals().size() > 0) {
483
updateGeometry();
484
}
485
}
486
487
/****************************************************************************/
488
489