Path: blob/main/src/netedit/elements/additional/GNEParkingSpace.cpp
193871 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GNEParkingSpace.cpp14/// @author Pablo Alvarez Lopez15/// @date Feb 201816///17// A lane area vehicles can halt at (GNE version)18/****************************************************************************/1920#include <netedit/changes/GNEChange_Attribute.h>21#include <netedit/elements/moving/GNEMoveElementViewResizable.h>22#include <netedit/GNENet.h>23#include <netedit/GNETagProperties.h>24#include <utils/gui/div/GLHelper.h>2526#include "GNEParkingSpace.h"2728// ===========================================================================29// method definitions30// ===========================================================================3132GNEParkingSpace::GNEParkingSpace(GNENet* net) :33GNEAdditional(net, SUMO_TAG_PARKING_SPACE),34myMoveElementViewResizable(new GNEMoveElementViewResizable(this, GNEMoveElementView::AttributesFormat::CARTESIAN,35GNEMoveElementViewResizable::ResizingFormat::WIDTH_LENGTH, SUMO_ATTR_POSITION,36myPosOverView)) {37}383940GNEParkingSpace::GNEParkingSpace(GNEAdditional* parkingAreaParent, const Position& pos,41const double width, const double length, const double angle,42const double slope, const std::string& name,43const Parameterised::Map& parameters) :44GNEAdditional(parkingAreaParent, SUMO_TAG_PARKING_SPACE, name),45Parameterised(parameters),46myPosOverView(pos),47myWidth(width),48myLength(length),49myMoveElementViewResizable(new GNEMoveElementViewResizable(this, GNEMoveElementView::AttributesFormat::CARTESIAN,50GNEMoveElementViewResizable::ResizingFormat::WIDTH_LENGTH, SUMO_ATTR_POSITION,51myPosOverView)),52myAngle(angle),53mySlope(slope) {54// set parents55setParent<GNEAdditional*>(parkingAreaParent);56// update centering boundary without updating grid57updateCenteringBoundary(false);58}596061GNEParkingSpace::~GNEParkingSpace() {62delete myMoveElementViewResizable;63}646566GNEMoveElement*67GNEParkingSpace::getMoveElement() const {68return myMoveElementViewResizable;69}707172Parameterised*73GNEParkingSpace::getParameters() {74return this;75}767778const Parameterised*79GNEParkingSpace::getParameters() const {80return this;81}828384void85GNEParkingSpace::writeAdditional(OutputDevice& device) const {86device.openTag(getTagProperty()->getTag());87// write common additional attributes88writeAdditionalAttributes(device);89// write move atributes90myMoveElementViewResizable->writeMoveAttributes(device);91// write specific attributes92if (myWidth != INVALID_DOUBLE) {93device.writeAttr(SUMO_ATTR_WIDTH, myWidth);94}95if (myLength != INVALID_DOUBLE) {96device.writeAttr(SUMO_ATTR_LENGTH, myLength);97}98if (myAngle != INVALID_DOUBLE) {99device.writeAttr(SUMO_ATTR_ANGLE, myAngle);100}101if (mySlope != myTagProperty->getDefaultDoubleValue(SUMO_ATTR_SLOPE)) {102device.writeAttr(SUMO_ATTR_SLOPE, mySlope);103}104// write parameters (Always after children to avoid problems with additionals.xsd)105writeParams(device);106device.closeTag();107}108109110bool111GNEParkingSpace::isAdditionalValid() const {112return true;113}114115116std::string117GNEParkingSpace::getAdditionalProblem() const {118return "";119}120121122void123GNEParkingSpace::fixAdditionalProblem() {124// nothing to fix125}126127128bool129GNEParkingSpace::checkDrawMoveContour() const {130// get edit modes131const auto& editModes = myNet->getViewNet()->getEditModes();132// check if we're in move mode133if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&134!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&135(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {136// only move the first element137return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;138} else {139return false;140}141}142143144void145GNEParkingSpace::updateGeometry() {146// get width an length147const double width = getAttributeDouble(SUMO_ATTR_WIDTH) <= 0 ? POSITION_EPS : getAttributeDouble(SUMO_ATTR_WIDTH);148const double length = getAttributeDouble(SUMO_ATTR_LENGTH) <= 0 ? POSITION_EPS : getAttributeDouble(SUMO_ATTR_LENGTH);149// calculate shape length150myMoveElementViewResizable->myShapeHeight.clear();151myMoveElementViewResizable->myShapeHeight.push_back(Position(0, 0));152myMoveElementViewResizable->myShapeHeight.push_back(Position(0, length));153// rotate154myMoveElementViewResizable->myShapeHeight.rotate2D(DEG2RAD(getAttributeDouble(SUMO_ATTR_ANGLE)));155// move156myMoveElementViewResizable->myShapeHeight.add(myPosOverView);157// calculate shape width158PositionVector leftShape = myMoveElementViewResizable->myShapeHeight;159leftShape.move2side(width * -0.5);160PositionVector rightShape = myMoveElementViewResizable->myShapeHeight;161rightShape.move2side(width * 0.5);162myMoveElementViewResizable->myShapeWidth = {leftShape.getCentroid(), rightShape.getCentroid()};163// update centering boundary164updateCenteringBoundary(true);165}166167168Position169GNEParkingSpace::getPositionInView() const {170return myPosOverView;171}172173174void175GNEParkingSpace::updateCenteringBoundary(const bool updateGrid) {176// remove additional from grid177if (updateGrid) {178myNet->removeGLObjectFromGrid(this);179}180// first reset boundary181myAdditionalBoundary.reset();182// add position183myAdditionalBoundary.add(myPosOverView);184// add center185myAdditionalBoundary.add(myPosOverView);186// add width187for (const auto& pos : myMoveElementViewResizable->myShapeWidth) {188myAdditionalBoundary.add(pos);189}190// add length191for (const auto& pos : myMoveElementViewResizable->myShapeHeight) {192myAdditionalBoundary.add(pos);193}194// grow195myAdditionalBoundary.grow(5);196// add additional into RTREE again197if (updateGrid) {198myNet->addGLObjectIntoGrid(this);199}200}201202203void204GNEParkingSpace::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {205// geometry of this element cannot be splitted206}207208209std::string210GNEParkingSpace::getParentName() const {211return getParentAdditionals().at(0)->getID();212}213214215void216GNEParkingSpace::drawGL(const GUIVisualizationSettings& s) const {217// first check if additional has to be drawn218if (myNet->getViewNet()->getDataViewOptions().showAdditionals()) {219// draw boundaries220GLHelper::drawBoundary(s, getCenteringBoundary());221// get exaggeration222const double spaceExaggeration = getExaggeration(s);223// get witdh224const double parkingSpaceWidth = myMoveElementViewResizable->myShapeWidth.length2D() * 0.5 + (spaceExaggeration * 0.1);225// get detail level226const auto d = s.getDetailLevel(spaceExaggeration);227// check if draw moving geometry points228const bool movingGeometryPoints = drawMovingGeometryPoints();229// draw geometry only if we'rent in drawForObjectUnderCursor mode230if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {231// draw space232drawSpace(s, d, parkingSpaceWidth, movingGeometryPoints);233// draw parent and child lines234drawParentChildLines(s, s.additionalSettings.connectionColor);235// draw lock icon236GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), myMoveElementViewResizable->myShapeHeight.getPolygonCenter(), spaceExaggeration);237// Draw additional ID238drawAdditionalID(s);239// draw additional name240drawAdditionalName(s);241// draw dotted contours242if (movingGeometryPoints) {243// get snap radius244const double snapRadius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;245const double snapRadiusSquared = snapRadius * snapRadius;246// get mouse position247const Position mousePosition = myNet->getViewNet()->getPositionInformation();248// check if we're editing width or height249if (myMoveElementViewResizable->myShapeHeight.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) {250myMoveElementViewResizable->myMovingContourUp.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);251myMoveElementViewResizable->myMovingContourDown.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);252} else if ((myMoveElementViewResizable->myShapeWidth.front().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) ||253(myMoveElementViewResizable->myShapeWidth.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared)) {254myMoveElementViewResizable->myMovingContourLeft.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);255myMoveElementViewResizable->myMovingContourRight.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);256}257} else {258myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);259}260261}262// calculate contour263calculateSpaceContour(s, d, parkingSpaceWidth, spaceExaggeration, movingGeometryPoints);264}265}266267268std::string269GNEParkingSpace::getAttribute(SumoXMLAttr key) const {270switch (key) {271case SUMO_ATTR_ID:272return getMicrosimID();273case SUMO_ATTR_NAME:274return myAdditionalName;275case SUMO_ATTR_WIDTH:276return (myWidth != INVALID_DOUBLE) ? toString(myWidth) : "";277case SUMO_ATTR_LENGTH:278return (myLength != INVALID_DOUBLE) ? toString(myLength) : "";279case SUMO_ATTR_ANGLE:280return (myAngle != INVALID_DOUBLE) ? toString(myAngle) : "";;281case SUMO_ATTR_SLOPE:282return toString(mySlope);283case GNE_ATTR_PARENT:284if (isTemplate()) {285return "";286} else {287return getParentAdditionals().at(0)->getID();288}289default:290return myMoveElementViewResizable->getMovingAttribute(key);291}292}293294295double296GNEParkingSpace::getAttributeDouble(SumoXMLAttr key) const {297switch (key) {298case SUMO_ATTR_WIDTH:299return (myWidth != INVALID_DOUBLE) ? myWidth : getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_WIDTH);300case SUMO_ATTR_LENGTH:301return (myLength != INVALID_DOUBLE) ? myLength : getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_LENGTH);302case SUMO_ATTR_ANGLE:303return (myAngle != INVALID_DOUBLE) ? myAngle : getParentAdditionals().front()->getAttributeDouble(SUMO_ATTR_ANGLE);304default:305return myMoveElementViewResizable->getMovingAttributeDouble(key);306}307}308309310Position311GNEParkingSpace::getAttributePosition(SumoXMLAttr key) const {312return myMoveElementViewResizable->getMovingAttributePosition(key);313}314315316PositionVector317GNEParkingSpace::getAttributePositionVector(SumoXMLAttr key) const {318return myMoveElementViewResizable->getMovingAttributePositionVector(key);319}320321322void323GNEParkingSpace::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {324if (value == getAttribute(key)) {325return; //avoid needless changes, later logic relies on the fact that attributes have changed326}327switch (key) {328case SUMO_ATTR_NAME:329case SUMO_ATTR_WIDTH:330case SUMO_ATTR_LENGTH:331case SUMO_ATTR_ANGLE:332case SUMO_ATTR_SLOPE:333case GNE_ATTR_PARENT:334GNEChange_Attribute::changeAttribute(this, key, value, undoList);335break;336default:337myMoveElementViewResizable->setMovingAttribute(key, value, undoList);338break;339}340}341342343bool344GNEParkingSpace::isValid(SumoXMLAttr key, const std::string& value) {345switch (key) {346case SUMO_ATTR_NAME:347return SUMOXMLDefinitions::isValidAttribute(value);348case SUMO_ATTR_WIDTH:349return value.empty() || (canParse<double>(value) && (parse<double>(value) > 0));350case SUMO_ATTR_LENGTH:351return value.empty() || (canParse<double>(value) && (parse<double>(value) > 0));352case SUMO_ATTR_ANGLE:353return value.empty() || canParse<double>(value);354case SUMO_ATTR_SLOPE:355return canParse<double>(value);356case GNE_ATTR_PARENT:357return (myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_PARKING_AREA, value, false) != nullptr);358default:359return myMoveElementViewResizable->isMovingAttributeValid(key, value);360}361}362363364std::string365GNEParkingSpace::getPopUpID() const {366return getTagStr();367}368369370std::string371GNEParkingSpace::getHierarchyName() const {372return getTagStr() + ": " + getAttribute(SUMO_ATTR_POSITION);373}374375// ===========================================================================376// private377// ===========================================================================378379void380GNEParkingSpace::drawSpace(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,381const double width, const bool movingGeometryPoints) const {382// get angle383const double angle = getAttributeDouble(SUMO_ATTR_ANGLE);384// get contour color385RGBColor contourColor = s.colorSettings.parkingSpaceColorContour;386if (drawUsingSelectColor()) {387contourColor = s.colorSettings.selectedAdditionalColor;388} else if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {389contourColor = s.colorSettings.parkingSpaceColorContour;390}391// push later matrix392GLHelper::pushMatrix();393// translate to front394drawInLayer(GLO_PARKING_SPACE);395// set contour color396GLHelper::setColor(contourColor);397// draw extern398GLHelper::drawBoxLines(myMoveElementViewResizable->myShapeHeight, width);399// make a copy of myShapeLength and scale400PositionVector shapeLengthInner = myMoveElementViewResizable->myShapeHeight;401shapeLengthInner.scaleAbsolute(-0.1);402// draw intern403if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {404// Traslate to front405glTranslated(0, 0, 0.1);406// set base color407GLHelper::setColor(drawUsingSelectColor() ? s.colorSettings.selectedAdditionalColor : s.colorSettings.parkingSpaceColor);408//draw intern409GLHelper::drawBoxLines(shapeLengthInner, width - 0.1);410}411// draw geometry points412if (movingGeometryPoints) {413if (myMoveElementViewResizable->myShapeHeight.size() > 0) {414drawUpGeometryPoint(s, d, myMoveElementViewResizable->myShapeHeight.back(), angle, RGBColor::ORANGE);415}416if (myMoveElementViewResizable->myShapeWidth.size() > 0) {417drawLeftGeometryPoint(s, d, myMoveElementViewResizable->myShapeWidth.back(), angle - 90, RGBColor::ORANGE);418drawRightGeometryPoint(s, d, myMoveElementViewResizable->myShapeWidth.front(), angle - 90, RGBColor::ORANGE);419}420}421// pop layer matrix422GLHelper::popMatrix();423}424425426void427GNEParkingSpace::calculateSpaceContour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,428const double width, const double exaggeration, const bool movingGeometryPoints) const {429// check if we're calculating the contour or the moving geometry points430if (movingGeometryPoints) {431myMoveElementViewResizable->myMovingContourUp.calculateContourCircleShape(s, d, this, myMoveElementViewResizable->myShapeHeight.back(), s.neteditSizeSettings.additionalGeometryPointRadius,432getType(), exaggeration, nullptr);433myMoveElementViewResizable->myMovingContourLeft.calculateContourCircleShape(s, d, this, myMoveElementViewResizable->myShapeWidth.front(), s.neteditSizeSettings.additionalGeometryPointRadius, getType(),434exaggeration, nullptr);435myMoveElementViewResizable->myMovingContourRight.calculateContourCircleShape(s, d, this, myMoveElementViewResizable->myShapeWidth.back(), s.neteditSizeSettings.additionalGeometryPointRadius, getType(),436exaggeration, nullptr);437} else {438myAdditionalContour.calculateContourExtrudedShape(s, d, this, myMoveElementViewResizable->myShapeHeight, getType(), width, exaggeration, true, true, 0, nullptr, nullptr);439}440}441442443void444GNEParkingSpace::setAttribute(SumoXMLAttr key, const std::string& value) {445switch (key) {446case SUMO_ATTR_NAME:447myAdditionalName = value;448break;449case SUMO_ATTR_WIDTH:450if (value.empty()) {451myWidth = INVALID_DOUBLE;452} else {453myWidth = parse<double>(value);454}455break;456case SUMO_ATTR_LENGTH:457if (value.empty()) {458myLength = INVALID_DOUBLE;459} else {460myLength = parse<double>(value);461}462break;463case SUMO_ATTR_ANGLE:464if (value.empty()) {465myAngle = INVALID_DOUBLE;466} else {467myAngle = parse<double>(value);468}469break;470case SUMO_ATTR_SLOPE:471mySlope = parse<double>(value);472break;473case GNE_ATTR_PARENT:474replaceAdditionalParent(SUMO_TAG_PARKING_AREA, value, 0);475break;476default:477myMoveElementViewResizable->setMovingAttribute(key, value);478break;479}480// update geometry (except for template)481if (getParentAdditionals().size() > 0) {482updateGeometry();483}484}485486/****************************************************************************/487488489