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

            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        30381 : ShapeHandler::ShapeHandler(const std::string& file, ShapeContainer& sc, const GeoConvHelper* geoConvHelper) :
      46              :     SUMOSAXHandler(file),
      47        30381 :     myShapeContainer(sc),
      48        60762 :     myPrefix(""),
      49        30381 :     myDefaultColor(RGBColor::RED),
      50        30381 :     myDefaultIcon(SUMOXMLDefinitions::POIIcons.getString(POIIcon::NONE)),
      51        30381 :     myDefaultLayer(0),
      52        30381 :     myDefaultFill(false),
      53        30381 :     myLastParameterised(nullptr),
      54        60762 :     myGeoConvHelper(geoConvHelper) {
      55        30381 : }
      56              : 
      57              : 
      58        30381 : ShapeHandler::~ShapeHandler() {}
      59              : 
      60              : 
      61              : void
      62       404803 : ShapeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
      63              :     try {
      64       404803 :         switch (element) {
      65         3477 :             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         3477 :                 myDefaultLayer = Shape::DEFAULT_LAYER;
      68         3477 :                 addPoly(attrs, false, false);
      69              :                 break;
      70         8453 :             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         8453 :                 myDefaultLayer = Shape::DEFAULT_LAYER_POI;
      73         8453 :                 addPOI(attrs, false, false);
      74              :                 break;
      75        11231 :             case SUMO_TAG_PARAM:
      76        11231 :                 if (myLastParameterised != nullptr) {
      77         1467 :                     bool ok = true;
      78         1467 :                     const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
      79              :                     // continue if key was successfully loaded
      80         1467 :                     if (ok) {
      81              :                         // circumventing empty string value
      82         1467 :                         const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
      83              :                         // show warnings if values are invalid
      84         1467 :                         if (key.empty()) {
      85            0 :                             WRITE_WARNING(TL("Error parsing key from shape generic parameter. Key cannot be empty"));
      86         1467 :                         } else if (!SUMOXMLDefinitions::isValidParameterKey(key)) {
      87            0 :                             WRITE_WARNING(TL("Error parsing key from shape generic parameter. Key contains invalid characters"));
      88              :                         } else {
      89         1467 :                             WRITE_DEBUG("Inserting generic parameter '" + key + "|" + val + "' into shape.");
      90         1467 :                             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       404803 : }
     102              : 
     103              : 
     104              : void
     105       404832 : ShapeHandler::myEndElement(int element) {
     106       404832 :     if (element != SUMO_TAG_PARAM) {
     107       393601 :         myLastParameterised = nullptr;
     108              :     }
     109       404832 : }
     110              : 
     111              : 
     112              : void
     113         8462 : ShapeHandler::addPOI(const SUMOSAXAttributes& attrs, const bool ignorePruning, const bool useProcessing) {
     114         8462 :     bool ok = true;
     115              :     const double INVALID_POSITION(-1000000);
     116        16924 :     const std::string id = myPrefix + attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     117         8462 :     double x = attrs.getOpt<double>(SUMO_ATTR_X, id.c_str(), ok, INVALID_POSITION);
     118         8462 :     const double y = attrs.getOpt<double>(SUMO_ATTR_Y, id.c_str(), ok, INVALID_POSITION);
     119         8462 :     const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, INVALID_POSITION);
     120         8462 :     double lon = attrs.getOpt<double>(SUMO_ATTR_LON, id.c_str(), ok, INVALID_POSITION);
     121         8462 :     double lat = attrs.getOpt<double>(SUMO_ATTR_LAT, id.c_str(), ok, INVALID_POSITION);
     122         8462 :     const double lanePos = attrs.getOpt<double>(SUMO_ATTR_POSITION, id.c_str(), ok, 0);
     123         8462 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     124         8462 :     const double lanePosLat = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, id.c_str(), ok, 0);
     125        16924 :     std::string icon = attrs.getOpt<std::string>(SUMO_ATTR_ICON, id.c_str(), ok, myDefaultIcon);
     126              :     // check icon
     127         8462 :     if (!SUMOXMLDefinitions::POIIcons.hasString(icon)) {
     128            0 :         WRITE_WARNING(TLF("Invalid icon % for POI '%', using default", icon, id));
     129              :         icon = "none";
     130              :     }
     131         8462 :     const double layer = attrs.getOpt<double>(SUMO_ATTR_LAYER, id.c_str(), ok, myDefaultLayer);
     132         8462 :     const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
     133         8462 :     const std::string laneID = attrs.getOpt<std::string>(SUMO_ATTR_LANE, id.c_str(), ok, "");
     134         8462 :     const double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, Shape::DEFAULT_ANGLE);
     135         8462 :     std::string imgFile = attrs.getOpt<std::string>(SUMO_ATTR_IMGFILE, id.c_str(), ok, Shape::DEFAULT_IMG_FILE);
     136         8462 :     const RGBColor color = attrs.hasAttribute(SUMO_ATTR_COLOR) ? attrs.get<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok) : (imgFile != "" ? RGBColor::WHITE : myDefaultColor);
     137         8462 :     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         8462 :     if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
     140         7824 :         imgFile = FileHelpers::getConfigurationRelative(getFileName(), imgFile);
     141              :     }
     142         8462 :     const double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, Shape::DEFAULT_IMG_WIDTH);
     143         8462 :     const double height = attrs.getOpt<double>(SUMO_ATTR_HEIGHT, id.c_str(), ok, Shape::DEFAULT_IMG_HEIGHT);
     144              :     // check if ID is valid
     145         8462 :     if (!SUMOXMLDefinitions::isValidTypeID(id)) {
     146            0 :         WRITE_WARNING(TL("Invalid characters for PoI ID"));
     147            0 :         ok = false;
     148              :     }
     149              :     // continue
     150         8462 :     if (ok) {
     151              :         const GeoConvHelper* gch;
     152              :         // set GEOConverter
     153         8462 :         if (myGeoConvHelper != nullptr) {
     154              :             gch = myGeoConvHelper;
     155         8404 :         } else if (useProcessing) {
     156              :             gch = &GeoConvHelper::getProcessing();
     157              :         } else {
     158              :             gch = &GeoConvHelper::getFinal();
     159              :         }
     160              :         // check if GEOProjection has to be used
     161           67 :         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         8462 :         if ((x == INVALID_POSITION) || (y == INVALID_POSITION)) {
     171              :             // try computing x,y from lane,pos
     172         1032 :             if (laneID != "") {
     173          674 :                 pos = getLanePos(id, laneID, lanePos, friendlyPos, lanePosLat);
     174              :             } else {
     175              :                 // try computing x,y from lon,lat
     176          358 :                 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          358 :                 } 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          358 :                 if (useProcessing) {
     187            6 :                     success = GeoConvHelper::getProcessing().x2cartesian(pos);
     188              :                 } else {
     189          352 :                     success = gch->x2cartesian_const(pos);
     190              :                 }
     191          358 :                 if (!success) {
     192            0 :                     WRITE_ERRORF(TL("Unable to project coordinates for POI '%'."), id);
     193            0 :                     return;
     194              :                 }
     195              :             }
     196              :         }
     197         8462 :         if (z != INVALID_POSITION) {
     198              :             pos.setz(z);
     199              :         }
     200         8462 :         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         8462 :         myLastParameterised = myShapeContainer.getPOIs().get(id);
     205         8462 :         if ((laneID != "") && addLanePosParams()) {
     206          673 :             myLastParameterised->setParameter(toString(SUMO_ATTR_LANE), laneID);
     207         1346 :             myLastParameterised->setParameter(toString(SUMO_ATTR_POSITION), toString(lanePos));
     208         1346 :             myLastParameterised->setParameter(toString(SUMO_ATTR_POSITION_LAT), toString(lanePosLat));
     209              :         }
     210              :     }
     211              : }
     212              : 
     213              : 
     214              : void
     215         3486 : ShapeHandler::addPoly(const SUMOSAXAttributes& attrs, const bool ignorePruning, const bool useProcessing) {
     216         3486 :     bool ok = true;
     217         3486 :     const std::string id = myPrefix + attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     218              :     // check if ID is valid
     219         3486 :     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         3486 :     if (ok) {
     225              :         // continue loading parameters
     226         3486 :         const double layer = attrs.getOpt<double>(SUMO_ATTR_LAYER, id.c_str(), ok, myDefaultLayer);
     227         3486 :         const bool fill = attrs.getOpt<bool>(SUMO_ATTR_FILL, id.c_str(), ok, myDefaultFill);
     228         3486 :         const double lineWidth = attrs.getOpt<double>(SUMO_ATTR_LINEWIDTH, id.c_str(), ok, Shape::DEFAULT_LINEWIDTH);
     229         3486 :         const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, Shape::DEFAULT_TYPE);
     230         3486 :         const RGBColor color = attrs.hasAttribute(SUMO_ATTR_COLOR) ? attrs.get<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok) : myDefaultColor;
     231         3486 :         PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
     232         3486 :         const bool geo = attrs.getOpt<bool>(SUMO_ATTR_GEO, id.c_str(), ok, false);
     233              :         // set geo converter
     234              :         const GeoConvHelper* gch;
     235         3486 :         if (myGeoConvHelper != nullptr) {
     236              :             gch = myGeoConvHelper;
     237              :         } else {
     238              :             gch = &GeoConvHelper::getFinal();
     239              :         }
     240              :         // check if poly use geo coordinates
     241         3486 :         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         3485 :         const double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, Shape::DEFAULT_ANGLE);
     256         3485 :         std::string imgFile = attrs.getOpt<std::string>(SUMO_ATTR_IMGFILE, id.c_str(), ok, Shape::DEFAULT_IMG_FILE);
     257         3485 :         bool relativePath = attrs.getOpt<bool>(SUMO_ATTR_RELATIVEPATH, id.c_str(), ok, Shape::DEFAULT_RELATIVEPATH);
     258         3485 :         if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
     259           26 :             imgFile = FileHelpers::getConfigurationRelative(getFileName(), imgFile);
     260              :         }
     261              :         // check that shape's size is valid
     262         3485 :         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         3485 :         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         3485 :         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         3485 :         myLastParameterised = myShapeContainer.getPolygons().get(id);
     276         3486 :     }
     277              : }
     278              : 
     279              : 
     280              : Parameterised*
     281            0 : ShapeHandler::getLastParameterised() const {
     282            0 :     return myLastParameterised;
     283              : }
     284              : 
     285              : 
     286              : bool
     287        28546 : ShapeHandler::loadFiles(const std::vector<std::string>& files, ShapeHandler& sh) {
     288        64254 :     for (const auto& fileIt : files) {
     289        35708 :         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 2.0-1