Path: blob/main/src/netedit/elements/additional/GNEPoly.cpp
169684 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 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 GNEPoly.cpp14/// @author Pablo Alvarez Lopez15/// @date Jun 201716///17// A class for visualizing and editing POIS in netedit (adapted from18// GUIPolygon and NLHandler)19/****************************************************************************/20#include <config.h>2122#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/div/GUIDesigns.h>31#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>32#include <utils/gui/div/GUIParameterTableWindow.h>33#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>34#include <utils/xml/NamespaceIDs.h>3536#include "GNEPoly.h"3738// ===========================================================================39// method definitions40// ===========================================================================4142GNEPoly::GNEPoly(SumoXMLTag tag, GNENet* net) :43TesselatedPolygon("", "", RGBColor::BLACK, {}, false, false, 0, 0, 0, "", "", Parameterised::Map()),44GNEAdditional("", net, "", tag, "") {45}464748GNEPoly::GNEPoly(const std::string& id, GNENet* net, const std::string& filename, const std::string& type, const PositionVector& shape,49bool geo, bool fill, double lineWidth, const RGBColor& color, double layer, double angle, const std::string& imgFile,50const std::string& name, const Parameterised::Map& parameters) :51TesselatedPolygon(id, type, color, shape, geo, fill, lineWidth, layer, angle, imgFile, name, parameters),52GNEAdditional(id, net, filename, SUMO_TAG_POLY, ""),53myClosedShape(shape.isClosed()) {54// check if imgFile is valid55if (!imgFile.empty() && GUITexturesHelper::getTextureID(imgFile) == -1) {56setShapeImgFile("");57}58// set GEO shape59myGeoShape = myShape;60if (geo) {61for (int i = 0; i < (int) myGeoShape.size(); i++) {62GeoConvHelper::getFinal().x2cartesian_const(myShape[i]);63}64} else {65for (int i = 0; i < (int) myGeoShape.size(); i++) {66GeoConvHelper::getFinal().cartesian2geo(myGeoShape[i]);67}68}69// update centering boundary without updating grid70updateCenteringBoundary(false);71// update geometry72updateGeometry();73}747576GNEPoly::GNEPoly(SumoXMLTag tag, const std::string& id, GNENet* net, const std::string& filename, const PositionVector& shape,77bool geo, const std::string& name, const Parameterised::Map& parameters) :78TesselatedPolygon(id, getJuPedSimType(tag), getJuPedSimColor(tag), shape, geo, getJuPedSimFill(tag), 1,79getJuPedSimLayer(tag), 0, "", name, parameters),80GNEAdditional(id, net, filename, tag, ""),81myClosedShape(shape.isClosed()),82mySimplifiedShape(false) {83// set GEO shape84myGeoShape = myShape;85if (geo) {86for (int i = 0; i < (int) myGeoShape.size(); i++) {87GeoConvHelper::getFinal().x2cartesian_const(myShape[i]);88}89} else {90for (int i = 0; i < (int) myGeoShape.size(); i++) {91GeoConvHelper::getFinal().cartesian2geo(myGeoShape[i]);92}93}94// update centering boundary without updating grid95updateCenteringBoundary(false);96// update geometry97updateGeometry();98}99100101GNEPoly::~GNEPoly() {}102103104GNEMoveOperation*105GNEPoly::getMoveOperation() {106// edit depending if shape is blocked107if (myNet->getViewNet()->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveWholePolygons()) {108// move entire shape109return new GNEMoveOperation(this, myShape);110} else {111// continue depending of tag112switch (getTagProperty()->getTag()) {113case GNE_TAG_JPS_WALKABLEAREA:114case GNE_TAG_JPS_OBSTACLE:115// calculate move shape operation maintain shape closed116return calculateMoveShapeOperation(this, myShape, true);117default:118// calculate move shape operation119return calculateMoveShapeOperation(this, myShape, false);120}121}122}123124125void126GNEPoly::removeGeometryPoint(const Position clickedPosition, GNEUndoList* undoList) {127// get original shape128PositionVector shape = myShape;129// check shape size130if (shape.size() > 2) {131// obtain index132int index = shape.indexOfClosest(clickedPosition);133// get snap radius134const double snap_radius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.polygonGeometryPointRadius;135// check if we have to create a new index136if ((index != -1) && shape[index].distanceSquaredTo2D(clickedPosition) < (snap_radius * snap_radius)) {137// remove geometry point138shape.erase(shape.begin() + index);139// commit new shape140undoList->begin(this, "remove geometry point of " + getTagStr());141GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_SHAPE, toString(shape), undoList);142undoList->end();143}144}145}146147148std::string149GNEPoly::generateChildID(SumoXMLTag /*childTag*/) {150return "";151}152153154void155GNEPoly::updateGeometry() {156// just update polygon geometry157myAdditionalGeometry.updateGeometry(myShape);158myTesselation.clear();159}160161162Position163GNEPoly::getPositionInView() const {164return myAdditionalBoundary.getCenter();165}166167168double169GNEPoly::getExaggeration(const GUIVisualizationSettings& s) const {170return s.polySize.getExaggeration(s, this);171}172173174void175GNEPoly::updateCenteringBoundary(const bool updateGrid) {176// Remove object from net177if (updateGrid) {178myNet->removeGLObjectFromGrid(this);179}180// use shape as boundary181myAdditionalBoundary = myShape.getBoxBoundary();182// grow boundary183myAdditionalBoundary.grow(5);184// add object into net185if (updateGrid) {186myNet->addGLObjectIntoGrid(this);187}188}189190191void192GNEPoly::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {193// nothing to split194}195196197void198GNEPoly::writeAdditional(OutputDevice& device) const {199writeXML(device, myGEO);200}201202203bool204GNEPoly::isAdditionalValid() const {205return true;206}207208209std::string210GNEPoly::getAdditionalProblem() const {211return "";212}213214215void216GNEPoly::fixAdditionalProblem() {217// nothing to fix218}219220221GUIGlID222GNEPoly::getGlID() const {223return GUIGlObject::getGlID();224}225226227bool228GNEPoly::checkDrawMoveContour() const {229// get edit modes230const auto& editModes = myNet->getViewNet()->getEditModes();231// check if we're in move mode232if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&233!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&234(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {235// only move the first element236return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;237} else {238return false;239}240}241242243std::string244GNEPoly::getParentName() const {245return myNet->getMicrosimID();246}247248249GUIGLObjectPopupMenu*250GNEPoly::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {251// create popup252GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);253// build common options254buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected);255FXMenuCommand* simplifyShape = GUIDesigns::buildFXMenuCommand(ret, TL("Simplify Shape"), TL("Replace current shape with a rectangle"), nullptr, &parent, MID_GNE_POLYGON_SIMPLIFY_SHAPE);256// disable simplify shape if polygon was already simplified257if (mySimplifiedShape || myShape.size() <= 2) {258simplifyShape->disable();259}260// only allow open/close for non juPedSim polygons261if (!myTagProperty->isJuPedSimElement()) {262if (myShape.isClosed()) {263GUIDesigns::buildFXMenuCommand(ret, TL("Open shape"), TL("Open polygon's shape"), nullptr, &parent, MID_GNE_POLYGON_OPEN);264} else {265GUIDesigns::buildFXMenuCommand(ret, TL("Close shape"), TL("Close polygon's shape"), nullptr, &parent, MID_GNE_POLYGON_CLOSE);266}267}268GUIDesigns::buildFXMenuCommand(ret, TL("Select elements within polygon"), TL("Select elements within polygon boundary"), nullptr, &parent, MID_GNE_POLYGON_SELECT);269if (myShape.size() > 3) {270GUIDesigns::buildFXMenuCommand(ret, TL("Triangulate polygon"), TL("Convert the current polygon in triangles"), nullptr, &parent, MID_GNE_POLYGON_TRIANGULATE);271}272// create a extra FXMenuCommand if mouse is over a vertex273const int index = getVertexIndex(myNet->getViewNet()->getPositionInformation(), false);274if (index != -1) {275// add separator276new FXMenuSeparator(ret);277// check if we're in network mode278if (myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_MOVE) {279GUIDesigns::buildFXMenuCommand(ret, "Set custom Geometry Point", nullptr, &parent, MID_GNE_CUSTOM_GEOMETRYPOINT);280}281FXMenuCommand* removeGeometryPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Remove geometry point"), TL("Remove geometry point under mouse"), nullptr, &parent, MID_GNE_POLYGON_DELETE_GEOMETRY_POINT);282FXMenuCommand* setFirstPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Set first geometry point"), TL("Set first geometry point"), nullptr, &parent, MID_GNE_POLYGON_SET_FIRST_POINT);283// disable setFirstPoint if shape only have three points284if ((myShape.isClosed() && (myShape.size() <= 4)) || (!myShape.isClosed() && (myShape.size() <= 2))) {285removeGeometryPoint->disable();286}287// disable setFirstPoint if mouse is over first point288if (index == 0) {289setFirstPoint->disable();290}291}292return ret;293}294295296void297GNEPoly::drawGL(const GUIVisualizationSettings& s) const {298// first check if poly can be drawn299if (myNet->getViewNet()->getDemandViewOptions().showShapes() &&300myNet->getViewNet()->getDataViewOptions().showShapes() &&301GUIPolygon::checkDraw(s, this, this)) {302// draw boundary303const auto boundary = getCenteringBoundary();304GLHelper::drawBoundary(s, getCenteringBoundary());305// get exaggeration306const double polyExaggeration = getExaggeration(s);307// get detail level308const auto d = s.getDetailLevel(polyExaggeration);309// draw geometry only if we'rent in drawForObjectUnderCursor mode310if (s.checkDrawPoly(boundary, isAttributeCarrierSelected())) {311// get colors312const RGBColor color = isAttributeCarrierSelected() ? s.colorSettings.selectionColor : getShapeColor();313// push layer matrix314GLHelper::pushMatrix();315// translate to front316drawInLayer(s.polyUseCustomLayer ? s.polyCustomLayer : getShapeLayer());317// draw polygon318drawPolygon(s, d, color, polyExaggeration);319// draw contour if don't move whole polygon320if (!myNet->getViewNet()->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveWholePolygons()) {321// get darker color322const RGBColor darkerColor = color.changedBrightness(-32);323// draw contour324drawPolygonContour(s, d, darkerColor, polyExaggeration);325// draw geometry points326drawGeometryPoints(s, d, darkerColor, polyExaggeration);327}328// pop layer matrix329GLHelper::popMatrix();330// draw name and type331drawPolygonNameAndType(s);332// draw lock icon333GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), getPositionInView(), polyExaggeration);334// draw dotted contour335myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);336}337// calculate contour338calculateContourPolygons(s, d, getShapeLayer(), polyExaggeration, getFill());339}340}341342343int344GNEPoly::getVertexIndex(Position pos, bool snapToGrid) {345// check if position has to be snapped to grid346if (snapToGrid) {347pos = myNet->getViewNet()->snapToActiveGrid(pos);348}349// first check if vertex already exists350for (const auto& shapePosition : myShape) {351if (shapePosition.distanceTo2D(pos) < myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.polygonGeometryPointRadius) {352return myShape.indexOfClosest(shapePosition);353}354}355return -1;356}357358359void360GNEPoly::deleteGeometryPoint(const Position& pos, bool allowUndo) {361if (myShape.size() > 1) {362// obtain index363PositionVector modifiedShape = myShape;364int index = modifiedShape.indexOfClosest(pos);365// remove point dependending of366if (myShape.isClosed() && (index == 0 || index == (int)modifiedShape.size() - 1) && (myShape.size() > 2)) {367modifiedShape.erase(modifiedShape.begin());368modifiedShape.erase(modifiedShape.end() - 1);369modifiedShape.push_back(modifiedShape.front());370} else {371modifiedShape.erase(modifiedShape.begin() + index);372}373// set new shape depending of allowUndo374if (allowUndo) {375myNet->getViewNet()->getUndoList()->begin(this, "delete geometry point");376setAttribute(SUMO_ATTR_SHAPE, toString(modifiedShape), myNet->getViewNet()->getUndoList());377myNet->getViewNet()->getUndoList()->end();378} else {379// first remove object from grid due shape is used for boundary380myNet->removeGLObjectFromGrid(this);381// set new shape382myShape = modifiedShape;383// disable simplified shape flag384mySimplifiedShape = false;385// add object into grid again386myNet->addGLObjectIntoGrid(this);387}388myTesselation.clear();389} else {390WRITE_WARNING(TL("Number of remaining points insufficient"))391}392}393394395bool396GNEPoly::isPolygonClosed() const {397return myShape.isClosed();398}399400401void402GNEPoly::openPolygon(bool allowUndo) {403// only open if shape is closed404if (myShape.isClosed()) {405if (allowUndo) {406myNet->getViewNet()->getUndoList()->begin(this, "open polygon");407setAttribute(GNE_ATTR_CLOSE_SHAPE, "false", myNet->getViewNet()->getUndoList());408myNet->getViewNet()->getUndoList()->end();409} else {410myShape.pop_back();411// disable simplified shape flag412mySimplifiedShape = false;413// update geometry to avoid grabbing Problems414updateGeometry();415}416} else {417WRITE_WARNING(TL("Polygon already opened"))418}419}420421422void423GNEPoly::closePolygon(bool allowUndo) {424// only close if shape is opened425if (!myShape.isClosed()) {426if (allowUndo) {427myNet->getViewNet()->getUndoList()->begin(this, "close shape");428setAttribute(GNE_ATTR_CLOSE_SHAPE, "true", myNet->getViewNet()->getUndoList());429myNet->getViewNet()->getUndoList()->end();430} else {431myShape.closePolygon();432// disable simplified shape flag433mySimplifiedShape = false;434// update geometry to avoid grabbing Problems435updateGeometry();436}437} else {438WRITE_WARNING(TL("Polygon already closed"))439}440}441442443void444GNEPoly::changeFirstGeometryPoint(int oldIndex, bool allowUndo) {445// check that old index is correct446if (oldIndex >= (int)myShape.size()) {447throw InvalidArgument("Invalid old Index");448} else if (oldIndex == 0) {449WRITE_WARNING(TL("Selected point must be different of the first point"))450} else {451// Configure new shape452PositionVector newShape;453for (int i = oldIndex; i < (int)myShape.size(); i++) {454newShape.push_back(myShape[i]);455}456if (myShape.isClosed()) {457for (int i = 1; i < oldIndex; i++) {458newShape.push_back(myShape[i]);459}460newShape.push_back(newShape.front());461} else {462for (int i = 0; i < oldIndex; i++) {463newShape.push_back(myShape[i]);464}465}466// set new rotated shape467if (allowUndo) {468myNet->getViewNet()->getUndoList()->begin(this, "change first geometry point");469setAttribute(SUMO_ATTR_SHAPE, toString(newShape), myNet->getViewNet()->getUndoList());470myNet->getViewNet()->getUndoList()->end();471} else {472// set new shape473myShape = newShape;474// disable simplified shape flag475mySimplifiedShape = false;476// update geometry to avoid grabbing Problems477updateGeometry();478}479}480}481482483void484GNEPoly::simplifyShape(bool allowUndo) {485if (!mySimplifiedShape && myShape.size() > 2) {486const Boundary b = myShape.getBoxBoundary();487// create a square as simplified shape488PositionVector simplifiedShape;489simplifiedShape.push_back(Position(b.xmin(), b.ymin()));490simplifiedShape.push_back(Position(b.xmin(), b.ymax()));491simplifiedShape.push_back(Position(b.xmax(), b.ymax()));492simplifiedShape.push_back(Position(b.xmax(), b.ymin()));493if (myShape.isClosed()) {494simplifiedShape.push_back(simplifiedShape[0]);495}496// set new shape depending of allowUndo497if (allowUndo) {498myNet->getViewNet()->getUndoList()->begin(this, "simplify shape");499setAttribute(SUMO_ATTR_SHAPE, toString(simplifiedShape), myNet->getViewNet()->getUndoList());500myNet->getViewNet()->getUndoList()->end();501} else {502// set new shape503myShape = simplifiedShape;504// update geometry to avoid grabbing Problems505updateGeometry();506}507// change flag after setting simplified shape508mySimplifiedShape = true;509} else {510WRITE_WARNING(TL("Polygon already simplified"))511}512}513514515CommonXMLStructure::SumoBaseObject*516GNEPoly::getSumoBaseObject() const {517CommonXMLStructure::SumoBaseObject* polygonBaseObject = new CommonXMLStructure::SumoBaseObject(nullptr);518polygonBaseObject->setTag(myTagProperty->getTag());519// fill attributes520polygonBaseObject->addStringAttribute(SUMO_ATTR_ID, myID);521polygonBaseObject->addPositionVectorAttribute(SUMO_ATTR_SHAPE, myShape);522polygonBaseObject->addBoolAttribute(SUMO_ATTR_GEO, myGEO);523polygonBaseObject->addBoolAttribute(SUMO_ATTR_FILL, myFill);524polygonBaseObject->addDoubleAttribute(SUMO_ATTR_LINEWIDTH, myLineWidth);525polygonBaseObject->addColorAttribute(SUMO_ATTR_COLOR, getShapeColor());526polygonBaseObject->addStringAttribute(SUMO_ATTR_TYPE, getShapeType());527polygonBaseObject->addDoubleAttribute(SUMO_ATTR_LAYER, getShapeLayer());528polygonBaseObject->addStringAttribute(SUMO_ATTR_IMGFILE, getShapeImgFile());529polygonBaseObject->addDoubleAttribute(SUMO_ATTR_ANGLE, getShapeNaviDegree());530polygonBaseObject->addStringAttribute(SUMO_ATTR_NAME, getShapeName());531return polygonBaseObject;532}533534535std::string536GNEPoly::getAttribute(SumoXMLAttr key) const {537switch (key) {538case SUMO_ATTR_ID:539return myID;540case SUMO_ATTR_SHAPE:541if ((GeoConvHelper::getFinal().getProjString() != "!") && myGEO) {542return TL("Using GEO Shape");543} else {544return toString(myShape);545}546case SUMO_ATTR_GEOSHAPE:547if (GeoConvHelper::getFinal().getProjString() != "!") {548return toString(myGeoShape, gPrecisionGeo);549} else {550return TL("No geo-conversion defined");551}552case SUMO_ATTR_COLOR:553return toString(getShapeColor());554case SUMO_ATTR_FILL:555return toString(myFill);556case SUMO_ATTR_LINEWIDTH:557return toString(myLineWidth);558case SUMO_ATTR_LAYER:559return toString(getShapeLayer());560case SUMO_ATTR_TYPE:561return getShapeType();562case SUMO_ATTR_IMGFILE:563return getShapeImgFile();564case SUMO_ATTR_ANGLE:565return toString(getShapeNaviDegree());566case SUMO_ATTR_GEO:567return toString(myGEO);568case SUMO_ATTR_NAME:569return getShapeName();570case GNE_ATTR_CLOSE_SHAPE:571return toString(myClosedShape);572default:573return getCommonAttribute(this, key);574}575}576577578double579GNEPoly::getAttributeDouble(SumoXMLAttr key) const {580throw InvalidArgument(getTagStr() + " attribute '" + toString(key) + "' not allowed");581}582583584const Parameterised::Map&585GNEPoly::getACParametersMap() const {586return SUMOPolygon::getParametersMap();587}588589590void591GNEPoly::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {592if (value == getAttribute(key)) {593return; //avoid needless changes, later logic relies on the fact that attributes have changed594}595switch (key) {596case SUMO_ATTR_ID:597case SUMO_ATTR_SHAPE:598case SUMO_ATTR_GEOSHAPE:599case SUMO_ATTR_COLOR:600case SUMO_ATTR_FILL:601case SUMO_ATTR_LINEWIDTH:602case SUMO_ATTR_LAYER:603case SUMO_ATTR_TYPE:604case SUMO_ATTR_IMGFILE:605case SUMO_ATTR_ANGLE:606case SUMO_ATTR_GEO:607case SUMO_ATTR_NAME:608case GNE_ATTR_CLOSE_SHAPE:609GNEChange_Attribute::changeAttribute(this, key, value, undoList);610break;611default:612setCommonAttribute(key, value, undoList);613break;614}615}616617618bool619GNEPoly::isValid(SumoXMLAttr key, const std::string& value) {620switch (key) {621case SUMO_ATTR_ID:622return isValidAdditionalID(NamespaceIDs::polygons, value);623case SUMO_ATTR_SHAPE:624case SUMO_ATTR_GEOSHAPE:625// empty shapes AREN'T allowed626if (value.empty()) {627return false;628} else {629return canParse<PositionVector>(value);630}631case SUMO_ATTR_COLOR:632return canParse<RGBColor>(value);633case SUMO_ATTR_FILL:634return canParse<bool>(value);635case SUMO_ATTR_LINEWIDTH:636return canParse<double>(value) && (parse<double>(value) >= 0);637case SUMO_ATTR_LAYER:638if (value.empty()) {639return true;640} else {641return canParse<double>(value);642}643case SUMO_ATTR_TYPE:644return true;645case SUMO_ATTR_IMGFILE:646if (value == "") {647return true;648} else {649// check that image can be loaded650return GUITexturesHelper::getTextureID(value) != -1;651}652case SUMO_ATTR_ANGLE:653return canParse<double>(value);654case SUMO_ATTR_GEO:655return canParse<bool>(value);656case SUMO_ATTR_NAME:657return SUMOXMLDefinitions::isValidAttribute(value);658case GNE_ATTR_CLOSE_SHAPE:659return canParse<bool>(value);660default:661return isCommonValid(key, value);662}663}664665666bool667GNEPoly::isAttributeEnabled(SumoXMLAttr key) const {668switch (key) {669case SUMO_ATTR_SHAPE:670if (GeoConvHelper::getFinal().getProjString() != "!") {671return myGEO == false;672} else {673return true;674}675case SUMO_ATTR_GEO:676return GeoConvHelper::getFinal().getProjString() != "!";677case SUMO_ATTR_GEOSHAPE:678if (GeoConvHelper::getFinal().getProjString() != "!") {679return myGEO == true;680} else {681return false;682}683case GNE_ATTR_CLOSE_SHAPE:684if (isTemplate()) {685return true;686} else {687return myShape.size() > 1;688}689default:690return true;691}692}693694695std::string696GNEPoly::getPopUpID() const {697return getTagStr() + ": " + getID();698}699700701std::string702GNEPoly::getHierarchyName() const {703return getTagStr();704}705706// ===========================================================================707// private708// ===========================================================================709710void711GNEPoly::setAttribute(SumoXMLAttr key, const std::string& value) {712switch (key) {713case SUMO_ATTR_ID: {714// update microsimID715setAdditionalID(value);716// set named ID717myID = value;718break;719}720case SUMO_ATTR_SHAPE: {721// set new shape722myShape = parse<PositionVector>(value);723// set GEO shape724myGeoShape = myShape;725for (int i = 0; i < (int) myGeoShape.size(); i++) {726GeoConvHelper::getFinal().cartesian2geo(myGeoShape[i]);727}728// disable simplified shape flag729mySimplifiedShape = false;730// update geometry731updateGeometry();732// update centering boundary733updateCenteringBoundary(true);734break;735}736case SUMO_ATTR_GEOSHAPE: {737// set new GEO shape738myGeoShape = parse<PositionVector>(value);739// set shape740myShape = myGeoShape ;741for (int i = 0; i < (int) myShape.size(); i++) {742GeoConvHelper::getFinal().x2cartesian_const(myShape[i]);743}744// disable simplified shape flag745mySimplifiedShape = false;746// update geometry747updateGeometry();748// update centering boundary749updateCenteringBoundary(true);750break;751}752case SUMO_ATTR_COLOR:753setShapeColor(parse<RGBColor>(value));754break;755case SUMO_ATTR_FILL:756myFill = parse<bool>(value);757myAdditionalContour.clearContour();758break;759case SUMO_ATTR_LINEWIDTH:760myLineWidth = parse<double>(value);761break;762case SUMO_ATTR_LAYER:763if (value.empty()) {764setShapeLayer(myTagProperty->getDefaultDoubleValue(key));765} else {766setShapeLayer(parse<double>(value));767}768break;769case SUMO_ATTR_TYPE:770setShapeType(value);771break;772case SUMO_ATTR_IMGFILE:773setShapeImgFile(value);774// all textures must be refresh775GUITexturesHelper::clearTextures();776break;777case SUMO_ATTR_ANGLE:778setShapeNaviDegree(parse<double>(value));779break;780case SUMO_ATTR_GEO:781myGEO = parse<bool>(value);782// update centering boundary783updateCenteringBoundary(true);784break;785case SUMO_ATTR_NAME:786setShapeName(value);787break;788case GNE_ATTR_CLOSE_SHAPE:789myClosedShape = parse<bool>(value);790if (!isTemplate()) {791if (myClosedShape) {792myShape.closePolygon();793myGeoShape.closePolygon();794795} else {796myShape.openPolygon();797myGeoShape.openPolygon();798}799// disable simplified shape flag800mySimplifiedShape = false;801// update geometry802updateGeometry();803// update centering boundary804updateCenteringBoundary(true);805}806break;807default:808setCommonAttribute(this, key, value);809break;810}811}812813814void815GNEPoly::setMoveShape(const GNEMoveResult& moveResult) {816// update new shape817myShape = moveResult.shapeToUpdate;818// update geometry819myAdditionalGeometry.updateGeometry(myShape);820}821822823void824GNEPoly::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {825// commit new shape826undoList->begin(this, "moving " + toString(SUMO_ATTR_SHAPE) + " of " + getTagStr());827GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_SHAPE, toString(moveResult.shapeToUpdate), undoList);828undoList->end();829}830831832void833GNEPoly::drawPolygon(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,834const RGBColor& color, const double exaggeration) const {835// check if we're drawing a polygon or a polyline836if (getFill()) {837// draw inner polygon838GUIPolygon::drawInnerPolygon(s, this, this, myAdditionalGeometry.getShape(), 0, getFill(), myTagProperty->isJuPedSimElement() ? false : drawUsingSelectColor());839} else {840// push matrix841GLHelper::pushMatrix();842// set color843GLHelper::setColor(color);844// draw geometry (polyline)845GUIGeometry::drawGeometry(d, myAdditionalGeometry, s.neteditSizeSettings.polylineWidth * exaggeration);846// pop matrix847GLHelper::popMatrix();848}849}850851852void853GNEPoly::drawPolygonContour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,854const RGBColor& color, const double exaggeration) const {855// push contour matrix856GLHelper::pushMatrix();857// translate to front858glTranslated(0, 0, 0.1);859// set color860GLHelper::setColor(color);861// draw polygon contour862GUIGeometry::drawGeometry(d, myAdditionalGeometry, s.neteditSizeSettings.polygonContourWidth * exaggeration);863// pop contour matrix864GLHelper::popMatrix();865}866867868void869GNEPoly::drawGeometryPoints(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,870const RGBColor& color, const double exaggeration) const {871// draw shape points only in supermode network872if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {873// check if we're in move mode874const bool moveMode = (myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_MOVE);875// get geometry point sizes876const double geometryPointSize = s.neteditSizeSettings.polygonGeometryPointRadius * (moveMode ? 1 : 0.5);877// draw geometry points878GUIGeometry::drawGeometryPoints(d, myAdditionalGeometry.getShape(), color, geometryPointSize, exaggeration,879myNet->getViewNet()->getNetworkViewOptions().editingElevation());880// draw dotted contours for geometry points if we're in move mode881if (moveMode) {882myAdditionalContour.drawDottedContourGeometryPoints(s, d, this, myAdditionalGeometry.getShape(), geometryPointSize,883exaggeration, s.dottedContourSettings.segmentWidthSmall);884}885}886}887888889void890GNEPoly::drawPolygonNameAndType(const GUIVisualizationSettings& s) const {891// get name position892const Position& namePos = myAdditionalGeometry.getShape().getPolygonCenter();893// draw name894drawName(namePos, s.scale, s.polyName, s.angle);895// check if draw poly type896if (s.polyType.show(this)) {897const Position p = namePos + Position(0, -0.6 * s.polyType.size / s.scale);898GLHelper::drawTextSettings(s.polyType, getShapeType(), p, s.scale, s.angle);899}900}901902/****************************************************************************/903904905