LCOV - code coverage report
Current view: top level - src/utils/shapes - ShapeHandler.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 124 148 83.8 %
Date: 2024-05-05 15:31:14 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 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    ShapeHandler.cpp
      15             : /// @author  Jakob Erdmann
      16             : /// @date    Feb 2015
      17             : ///
      18             : // The XML-Handler for network loading
      19             : /****************************************************************************/
      20             : #include <config.h>
      21             : 
      22             : #include <string>
      23             : #include <utils/xml/SUMOXMLDefinitions.h>
      24             : #include <utils/xml/SUMOSAXHandler.h>
      25             : #include <utils/xml/XMLSubSys.h>
      26             : #include <utils/common/MsgHandler.h>
      27             : #include <utils/common/StringUtils.h>
      28             : #include <utils/common/StringTokenizer.h>
      29             : #include <utils/common/RGBColor.h>
      30             : #include <utils/geom/GeomConvHelper.h>
      31             : #include <utils/iodevices/OutputDevice.h>
      32             : #include <utils/common/UtilExceptions.h>
      33             : #include <utils/geom/GeoConvHelper.h>
      34             : #include <utils/gui/globjects/GUIGlObjectTypes.h>
      35             : 
      36             : #include "Shape.h"
      37             : #include "ShapeContainer.h"
      38             : #include "ShapeHandler.h"
      39             : 
      40             : 
      41             : // ===========================================================================
      42             : // method definitions
      43             : // ===========================================================================
      44             : 
      45       22559 : ShapeHandler::ShapeHandler(const std::string& file, ShapeContainer& sc, const GeoConvHelper* geoConvHelper) :
      46             :     SUMOSAXHandler(file),
      47       22559 :     myShapeContainer(sc),
      48       45118 :     myPrefix(""),
      49       22559 :     myDefaultColor(RGBColor::RED),
      50       22559 :     myDefaultIcon(SUMOXMLDefinitions::POIIcons.getString(POIIcon::NONE)),
      51       22559 :     myDefaultLayer(0),
      52       22559 :     myDefaultFill(false),
      53       22559 :     myLastParameterised(nullptr),
      54       45118 :     myGeoConvHelper(geoConvHelper) {
      55       22559 : }
      56             : 
      57             : 
      58       45118 : ShapeHandler::~ShapeHandler() {}
      59             : 
      60             : 
      61             : void
      62      345840 : ShapeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
      63             :     try {
      64      345840 :         switch (element) {
      65        5214 :             case SUMO_TAG_POLY:
      66             :                 // default layer is different depending if we're parsing a Poly or a POI, therefore it has to be here defined
      67        5214 :                 myDefaultLayer = Shape::DEFAULT_LAYER;
      68        5214 :                 addPoly(attrs, false, false);
      69             :                 break;
      70       13154 :             case SUMO_TAG_POI:
      71             :                 // default layer is different depending if we're parsing a Poly or a POI, therefore it has to be here defined
      72       13154 :                 myDefaultLayer = Shape::DEFAULT_LAYER_POI;
      73       13154 :                 addPOI(attrs, false, false);
      74             :                 break;
      75       17319 :             case SUMO_TAG_PARAM:
      76       17319 :                 if (myLastParameterised != nullptr) {
      77        1428 :                     bool ok = true;
      78        1428 :                     const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
      79             :                     // continue if key was successfully loaded
      80        1428 :                     if (ok) {
      81             :                         // circumventing empty string value
      82        1428 :                         const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
      83             :                         // show warnings if values are invalid
      84        1428 :                         if (key.empty()) {
      85           0 :                             WRITE_WARNING(TL("Error parsing key from shape generic parameter. Key cannot be empty"));
      86        1428 :                         } else if (!SUMOXMLDefinitions::isValidParameterKey(key)) {
      87           0 :                             WRITE_WARNING(TL("Error parsing key from shape generic parameter. Key contains invalid characters"));
      88             :                         } else {
      89        1428 :                             WRITE_DEBUG("Inserting generic parameter '" + key + "|" + val + "' into shape.");
      90        1428 :                             myLastParameterised->setParameter(key, val);
      91             :                         }
      92             :                     }
      93             :                 }
      94             :                 break;
      95             :             default:
      96             :                 break;
      97             :         }
      98           0 :     } catch (InvalidArgument& e) {
      99           0 :         WRITE_ERROR(e.what());
     100           0 :     }
     101      345840 : }
     102             : 
     103             : 
     104             : void
     105      345869 : ShapeHandler::myEndElement(int element) {
     106      345869 :     if (element != SUMO_TAG_PARAM) {
     107      328550 :         myLastParameterised = nullptr;
     108             :     }
     109      345869 : }
     110             : 
     111             : 
     112             : void
     113       13163 : ShapeHandler::addPOI(const SUMOSAXAttributes& attrs, const bool ignorePruning, const bool useProcessing) {
     114       13163 :     bool ok = true;
     115             :     const double INVALID_POSITION(-1000000);
     116       26326 :     const std::string id = myPrefix + attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     117       13163 :     double x = attrs.getOpt<double>(SUMO_ATTR_X, id.c_str(), ok, INVALID_POSITION);
     118       13163 :     const double y = attrs.getOpt<double>(SUMO_ATTR_Y, id.c_str(), ok, INVALID_POSITION);
     119       13163 :     const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, INVALID_POSITION);
     120       13163 :     double lon = attrs.getOpt<double>(SUMO_ATTR_LON, id.c_str(), ok, INVALID_POSITION);
     121       13163 :     double lat = attrs.getOpt<double>(SUMO_ATTR_LAT, id.c_str(), ok, INVALID_POSITION);
     122       13163 :     const double lanePos = attrs.getOpt<double>(SUMO_ATTR_POSITION, id.c_str(), ok, 0);
     123       13163 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     124       13163 :     const double lanePosLat = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, id.c_str(), ok, 0);
     125       26326 :     std::string icon = attrs.getOpt<std::string>(SUMO_ATTR_ICON, id.c_str(), ok, myDefaultIcon);
     126             :     // check icon
     127       13163 :     if (!SUMOXMLDefinitions::POIIcons.hasString(icon)) {
     128           0 :         WRITE_WARNING(TLF("Invalid icon % for POI '%', using default", icon, id));
     129             :         icon = "none";
     130             :     }
     131       13163 :     const double layer = attrs.getOpt<double>(SUMO_ATTR_LAYER, id.c_str(), ok, myDefaultLayer);
     132       13163 :     const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
     133       13163 :     const std::string laneID = attrs.getOpt<std::string>(SUMO_ATTR_LANE, id.c_str(), ok, "");
     134       13163 :     const double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, Shape::DEFAULT_ANGLE);
     135       13163 :     std::string imgFile = attrs.getOpt<std::string>(SUMO_ATTR_IMGFILE, id.c_str(), ok, Shape::DEFAULT_IMG_FILE);
     136       14197 :     const RGBColor color = attrs.hasAttribute(SUMO_ATTR_COLOR) ? attrs.get<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok) : (imgFile != "" ? RGBColor::WHITE : myDefaultColor);
     137       13163 :     bool relativePath = attrs.getOpt<bool>(SUMO_ATTR_RELATIVEPATH, id.c_str(), ok, Shape::DEFAULT_RELATIVEPATH);
     138             :     // If the image file is set, change the default POI color to white.
     139       13163 :     if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
     140       12130 :         imgFile = FileHelpers::getConfigurationRelative(getFileName(), imgFile);
     141             :     }
     142       13163 :     const double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, Shape::DEFAULT_IMG_WIDTH);
     143       13163 :     const double height = attrs.getOpt<double>(SUMO_ATTR_HEIGHT, id.c_str(), ok, Shape::DEFAULT_IMG_HEIGHT);
     144             :     // check if ID is valid
     145       13163 :     if (!SUMOXMLDefinitions::isValidTypeID(id)) {
     146           0 :         WRITE_WARNING(TL("Invalid characters for PoI ID"));
     147           0 :         ok = false;
     148             :     }
     149             :     // continue
     150       13163 :     if (ok) {
     151             :         const GeoConvHelper* gch;
     152             :         // set GEOConverter
     153       13163 :         if (myGeoConvHelper != nullptr) {
     154             :             gch = myGeoConvHelper;
     155       13105 :         } else if (useProcessing) {
     156             :             gch = &GeoConvHelper::getProcessing();
     157             :         } else {
     158             :             gch = &GeoConvHelper::getFinal();
     159             :         }
     160             :         // check if GEOProjection has to be used
     161       13163 :         if (useProcessing && gch->usingGeoProjection()) {
     162           6 :             if ((lat == INVALID_POSITION) || (lon == INVALID_POSITION)) {
     163             :                 lon = x;
     164             :                 lat = y;
     165             :                 x = INVALID_POSITION;
     166             :             }
     167             :         }
     168             :         Position pos(x, y);
     169             :         bool useGeo = false;
     170       13163 :         if ((x == INVALID_POSITION) || (y == INVALID_POSITION)) {
     171             :             // try computing x,y from lane,pos
     172         744 :             if (laneID != "") {
     173         642 :                 pos = getLanePos(id, laneID, lanePos, friendlyPos, lanePosLat);
     174             :             } else {
     175             :                 // try computing x,y from lon,lat
     176         102 :                 if ((lat == INVALID_POSITION) || (lon == INVALID_POSITION)) {
     177           0 :                     WRITE_ERRORF(TL("Either (x, y), (lon, lat) or (lane, pos) must be specified for PoI '%'."), id);
     178           0 :                     return;
     179         102 :                 } else if (!gch->usingGeoProjection()) {
     180           0 :                     WRITE_ERRORF(TL("(lon, lat) is specified for PoI '%' but no geo-conversion is specified for the network."), id);
     181           0 :                     return;
     182             :                 }
     183             :                 pos.set(lon, lat);
     184             :                 useGeo = true;
     185             :                 bool success = true;
     186         102 :                 if (useProcessing) {
     187           6 :                     success = GeoConvHelper::getProcessing().x2cartesian(pos);
     188             :                 } else {
     189          96 :                     success = gch->x2cartesian_const(pos);
     190             :                 }
     191         102 :                 if (!success) {
     192           0 :                     WRITE_ERRORF(TL("Unable to project coordinates for PoI '%'."), id);
     193           0 :                     return;
     194             :                 }
     195             :             }
     196             :         }
     197       13163 :         if (z != INVALID_POSITION) {
     198             :             pos.setz(z);
     199             :         }
     200       13163 :         if (!myShapeContainer.addPOI(id, type, color, pos, useGeo, laneID, lanePos, friendlyPos, lanePosLat, icon,
     201             :                                      layer, angle, imgFile, relativePath, width, height, ignorePruning)) {
     202           3 :             WRITE_ERRORF(TL("PoI '%' already exists."), id);
     203             :         }
     204       13163 :         myLastParameterised = myShapeContainer.getPOIs().get(id);
     205       13163 :         if ((laneID != "") && addLanePosParams()) {
     206         641 :             myLastParameterised->setParameter(toString(SUMO_ATTR_LANE), laneID);
     207        1282 :             myLastParameterised->setParameter(toString(SUMO_ATTR_POSITION), toString(lanePos));
     208        1282 :             myLastParameterised->setParameter(toString(SUMO_ATTR_POSITION_LAT), toString(lanePosLat));
     209             :         }
     210             :     }
     211             : }
     212             : 
     213             : 
     214             : void
     215        5223 : ShapeHandler::addPoly(const SUMOSAXAttributes& attrs, const bool ignorePruning, const bool useProcessing) {
     216        5223 :     bool ok = true;
     217        5223 :     const std::string id = myPrefix + attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     218             :     // check if ID is valid
     219        5223 :     if (!SUMOXMLDefinitions::isValidTypeID(id)) {
     220           0 :         WRITE_WARNING(TL("Invalid characters for Poly ID"));
     221           0 :         ok = false;
     222             :     }
     223             :     // get the id, report an error if not given or empty...
     224        5223 :     if (ok) {
     225             :         // continue loading parameters
     226        5223 :         const double layer = attrs.getOpt<double>(SUMO_ATTR_LAYER, id.c_str(), ok, myDefaultLayer);
     227        5223 :         const bool fill = attrs.getOpt<bool>(SUMO_ATTR_FILL, id.c_str(), ok, myDefaultFill);
     228        5223 :         const double lineWidth = attrs.getOpt<double>(SUMO_ATTR_LINEWIDTH, id.c_str(), ok, Shape::DEFAULT_LINEWIDTH);
     229        5223 :         const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, Shape::DEFAULT_TYPE);
     230        5223 :         const RGBColor color = attrs.hasAttribute(SUMO_ATTR_COLOR) ? attrs.get<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok) : myDefaultColor;
     231        5223 :         PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
     232        5223 :         const bool geo = attrs.getOpt<bool>(SUMO_ATTR_GEO, id.c_str(), ok, false);
     233             :         // set geo converter
     234             :         const GeoConvHelper* gch;
     235        5223 :         if (myGeoConvHelper != nullptr) {
     236             :             gch = myGeoConvHelper;
     237             :         } else {
     238             :             gch = &GeoConvHelper::getFinal();
     239             :         }
     240             :         // check if poly use geo coordinates
     241        5223 :         if (geo || useProcessing) {
     242             :             bool success = true;
     243          76 :             for (int i = 0; i < (int)shape.size(); i++) {
     244          63 :                 if (useProcessing) {
     245          39 :                     success &= GeoConvHelper::getProcessing().x2cartesian(shape[i]);
     246             :                 } else {
     247          24 :                     success &= gch->x2cartesian_const(shape[i]);
     248             :                 }
     249             :             }
     250          13 :             if (!success) {
     251           3 :                 WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), id);
     252           1 :                 return;
     253             :             }
     254             :         }
     255        5222 :         const double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, Shape::DEFAULT_ANGLE);
     256        5222 :         std::string imgFile = attrs.getOpt<std::string>(SUMO_ATTR_IMGFILE, id.c_str(), ok, Shape::DEFAULT_IMG_FILE);
     257        5222 :         bool relativePath = attrs.getOpt<bool>(SUMO_ATTR_RELATIVEPATH, id.c_str(), ok, Shape::DEFAULT_RELATIVEPATH);
     258        5222 :         if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
     259          26 :             imgFile = FileHelpers::getConfigurationRelative(getFileName(), imgFile);
     260             :         }
     261             :         // check that shape's size is valid
     262        5222 :         if (shape.size() == 0) {
     263           0 :             WRITE_ERROR(TL("Polygon's shape cannot be empty."));
     264           0 :             return;
     265             :         }
     266             :         // check that lineWidth is positive
     267        5222 :         if (lineWidth <= 0) {
     268           0 :             WRITE_ERROR(TL("Polygon's lineWidth must be greater than 0."));
     269           0 :             return;
     270             :         }
     271             :         // create polygon, or show an error if polygon already exists
     272        5222 :         if (!myShapeContainer.addPolygon(id, type, color, layer, angle, imgFile, relativePath, shape, geo, fill, lineWidth, ignorePruning)) {
     273           0 :             WRITE_ERRORF(TL("Polygon '%' already exists."), id);
     274             :         }
     275        5222 :         myLastParameterised = myShapeContainer.getPolygons().get(id);
     276        5223 :     }
     277             : }
     278             : 
     279             : 
     280             : Parameterised*
     281           0 : ShapeHandler::getLastParameterised() const {
     282           0 :     return myLastParameterised;
     283             : }
     284             : 
     285             : 
     286             : bool
     287       20385 : ShapeHandler::loadFiles(const std::vector<std::string>& files, ShapeHandler& sh) {
     288       48526 :     for (const auto& fileIt : files) {
     289       28141 :         if (!XMLSubSys::runParser(sh, fileIt, false)) {
     290           0 :             WRITE_MESSAGEF(TL("Loading of shapes from % failed."), fileIt);
     291             :             return false;
     292             :         }
     293             :     }
     294             :     return true;
     295             : }
     296             : 
     297             : 
     298             : void
     299          18 : ShapeHandler::setDefaults(const std::string& prefix, const RGBColor& color, const std::string& icon, const double layer, const bool fill) {
     300          18 :     myPrefix = prefix;
     301          18 :     myDefaultColor = color;
     302          18 :     myDefaultIcon = icon;
     303          18 :     myDefaultLayer = layer;
     304          18 :     myDefaultFill = fill;
     305          18 : }
     306             : 
     307             : 
     308             : bool
     309           1 : ShapeHandler::addLanePosParams() {
     310           1 :     return false;
     311             : }
     312             : 
     313             : 
     314             : /****************************************************************************/

Generated by: LCOV version 1.14