LCOV - code coverage report
Current view: top level - src/libsumo - Polygon.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.3 % 164 158
Test Date: 2026-07-26 16:30:20 Functions: 92.1 % 38 35

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2017-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    Polygon.cpp
      15              : /// @author  Gregor Laemmel
      16              : /// @date    15.03.2017
      17              : ///
      18              : // C++ TraCI client API implementation
      19              : /****************************************************************************/
      20              : #include <microsim/MSNet.h>
      21              : #include <microsim/MSEventControl.h>
      22              : #include <microsim/MSVehicleControl.h>
      23              : #include <microsim/transportables/MSTransportableControl.h>
      24              : #include <microsim/MSDynamicShapeUpdater.h>
      25              : #include <libsumo/TraCIConstants.h>
      26              : #include <utils/shapes/SUMOPolygon.h>
      27              : #include <utils/shapes/PolygonDynamics.h>
      28              : #include <utils/shapes/ShapeContainer.h>
      29              : #include <utils/common/ParametrisedWrappingCommand.h>
      30              : 
      31              : #include "Polygon.h"
      32              : #include "Helper.h"
      33              : 
      34              : 
      35              : namespace libsumo {
      36              : // ===========================================================================
      37              : // static member initializations
      38              : // ===========================================================================
      39              : SubscriptionResults Polygon::mySubscriptionResults;
      40              : ContextSubscriptionResults Polygon::myContextSubscriptionResults;
      41              : NamedRTree* Polygon::myTree(nullptr);
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // static member definitions
      46              : // ===========================================================================
      47              : std::vector<std::string>
      48          523 : Polygon::getIDList() {
      49            0 :     std::vector<std::string> ids;
      50          523 :     MSNet::getInstance()->getShapeContainer().getPolygons().insertIDs(ids);
      51          521 :     return ids;
      52            2 : }
      53              : 
      54              : 
      55              : int
      56          134 : Polygon::getIDCount() {
      57          134 :     return (int)getIDList().size();
      58              : }
      59              : 
      60              : 
      61              : std::string
      62           98 : Polygon::getType(const std::string& polygonID) {
      63           98 :     return getPolygon(polygonID)->getShapeType();
      64              : }
      65              : 
      66              : 
      67              : TraCIPositionVector
      68        10115 : Polygon::getShape(const std::string& polygonID) {
      69        10115 :     SUMOPolygon* p = getPolygon(polygonID);
      70        10115 :     return Helper::makeTraCIPositionVector(p->getShape());
      71              : }
      72              : 
      73              : 
      74              : bool
      75           98 : Polygon::getFilled(const std::string& polygonID) {
      76           98 :     return getPolygon(polygonID)->getFill();
      77              : }
      78              : 
      79              : 
      80              : double
      81           19 : Polygon::getLineWidth(const std::string& polygonID) {
      82           19 :     return getPolygon(polygonID)->getLineWidth();
      83              : }
      84              : 
      85              : 
      86              : double
      87            1 : Polygon::getHeight(const std::string& polygonID) {
      88            1 :     return getPolygon(polygonID)->getHeight();
      89              : }
      90              : 
      91              : 
      92              : TraCIColor
      93          106 : Polygon::getColor(const std::string& polygonID) {
      94          106 :     SUMOPolygon* p = getPolygon(polygonID);
      95          104 :     return Helper::makeTraCIColor(p->getShapeColor());
      96              : }
      97              : 
      98              : 
      99              : std::string
     100           28 : Polygon::getParameter(const std::string& polygonID, const std::string& key) {
     101           56 :     return getPolygon(polygonID)->getParameter(key, "");
     102              : }
     103              : 
     104              : 
     105           16 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Polygon)
     106              : 
     107              : 
     108              : void
     109            7 : Polygon::setType(const std::string& polygonID, const std::string& polygonType) {
     110            7 :     getPolygon(polygonID)->setShapeType(polygonType);
     111            6 : }
     112              : 
     113              : 
     114              : void
     115            8 : Polygon::setShape(const std::string& polygonID, const TraCIPositionVector& shape) {
     116            8 :     PositionVector positionVector = Helper::makePositionVector(shape);
     117            8 :     getPolygon(polygonID); // just to check whether it exists
     118            7 :     ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
     119            7 :     shapeCont.reshapePolygon(polygonID, positionVector);
     120            8 : }
     121              : 
     122              : 
     123              : void
     124           12 : Polygon::setColor(const std::string& polygonID, const TraCIColor& c) {
     125           12 :     getPolygon(polygonID)->setShapeColor(Helper::makeRGBColor(c));
     126           11 : }
     127              : 
     128              : 
     129              : void
     130          218 : Polygon::add(const std::string& polygonID, const TraCIPositionVector& shape, const TraCIColor& color, bool fill, const std::string& polygonType, int layer, double lineWidth) {
     131          218 :     ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
     132          218 :     PositionVector pShape = Helper::makePositionVector(shape);
     133          213 :     RGBColor col = Helper::makeRGBColor(color);
     134          213 :     if (!shapeCont.addPolygon(polygonID, polygonType, col, (double)layer, Shape::DEFAULT_ANGLE, Shape::DEFAULT_IMG_FILE, pShape, false, fill, lineWidth)) {
     135            0 :         throw TraCIException("Could not add polygon '" + polygonID + "'");
     136              :     }
     137          213 :     if (myTree != nullptr) {
     138              :         SUMOPolygon* p = shapeCont.getPolygons().get(polygonID);
     139            5 :         Boundary b = p->getShape().getBoxBoundary();
     140            5 :         const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
     141            5 :         const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
     142            5 :         myTree->Insert(cmin, cmax, p);
     143              :     }
     144          213 : }
     145              : 
     146              : 
     147              : void
     148           59 : Polygon::addHighlightPolygon(const std::string& objectID, const int type, const std::string& polygonID, const TraCIPositionVector& shape, const TraCIColor& color, bool fill, const std::string& polygonType, int layer, double lineWidth) {
     149           59 :     add(polygonID, shape, color, fill, polygonType, layer, lineWidth);
     150           59 :     MSNet::getInstance()->getShapeContainer().registerHighlight(objectID, type, polygonID);
     151           59 : }
     152              : 
     153              : 
     154              : void
     155          189 : Polygon::addDynamics(const std::string& polygonID, const std::string& trackedObjectID, const std::vector<double>& timeSpan, const std::vector<double>& alphaSpan, bool looped, bool rotate) {
     156          189 :     if (timeSpan.empty()) {
     157           58 :         if (trackedObjectID == "") {
     158           16 :             throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': dynamics underspecified (either a tracked object ID or a time span have to be provided).");
     159              :         }
     160           50 :         if (looped) {
     161           16 :             throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': looped==true requires time line of positive length.");
     162              :         }
     163              :     }
     164          173 :     if (timeSpan.size() == 1) {
     165           16 :         throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': time span cannot have length one.");
     166          165 :     } else if (timeSpan.size() > 0 && timeSpan[0] != 0.0) {
     167           16 :         throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': first element of time span must be zero.");
     168              :     }
     169          157 :     if (timeSpan.size() != alphaSpan.size() && alphaSpan.size() != 0) {
     170           16 :         throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': alpha span must have length zero or equal to time span length.");
     171              :     }
     172          149 :     if (timeSpan.size() >= 2) {
     173          572 :         for (unsigned int i = 1; i < timeSpan.size(); ++i) {
     174          473 :             if (timeSpan[i - 1] > timeSpan[i]) {
     175           16 :                 throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': entries of time span must be ordered ascendingly.");
     176              :             }
     177              :         }
     178              :     }
     179              : 
     180          141 :     SUMOTrafficObject* obj = getTrafficObject(trackedObjectID);
     181          139 :     ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
     182          278 :     PolygonDynamics* pd = shapeCont.addPolygonDynamics(SIMTIME, polygonID, obj, timeSpan, alphaSpan, looped, rotate);
     183          139 :     if (pd == nullptr) {
     184            0 :         throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': polygon doesn't exist.");
     185              :     }
     186              :     // Ensure existence of a DynamicShapeUpdater
     187          139 :     if (MSNet::getInstance()->getDynamicShapeUpdater() == nullptr) {
     188           22 :         MSNet::VehicleStateListener* listener = dynamic_cast<MSNet::VehicleStateListener*>(MSNet::getInstance()->makeDynamicShapeUpdater());
     189           22 :         MSNet::getInstance()->addVehicleStateListener(listener);
     190              :     }
     191              : 
     192              :     // Schedule the regular polygon update
     193          139 :     auto cmd = new ParametrisedWrappingCommand<ShapeContainer, PolygonDynamics*>(&shapeCont, pd, &ShapeContainer::polygonDynamicsUpdate);
     194          278 :     shapeCont.addPolygonUpdateCommand(pd->getPolygonID(), cmd);
     195          139 :     MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(cmd, SIMSTEP);
     196          139 : }
     197              : 
     198              : 
     199              : void
     200           22 : Polygon::remove(const std::string& polygonID, int /* layer */) {
     201              :     // !!! layer not used yet (shouldn't the id be enough?)
     202           22 :     ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
     203           22 :     if (myTree != nullptr) {
     204              :         SUMOPolygon* p = shapeCont.getPolygons().get(polygonID);
     205            5 :         if (p != nullptr) {
     206            5 :             Boundary b = p->getShape().getBoxBoundary();
     207            5 :             const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
     208            5 :             const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
     209            5 :             myTree->Remove(cmin, cmax, p);
     210              :         }
     211              :     }
     212           22 :     if (!shapeCont.removePolygon(polygonID)) {
     213            2 :         throw TraCIException("Could not remove polygon '" + polygonID + "'");
     214              :     }
     215           21 : }
     216              : 
     217              : 
     218              : void
     219            7 : Polygon::setFilled(std::string polygonID, bool filled) {
     220            7 :     getPolygon(polygonID)->setFill(filled);
     221            6 : }
     222              : 
     223              : 
     224              : void
     225            6 : Polygon::setLineWidth(std::string polygonID, double lineWidth) {
     226            6 :     getPolygon(polygonID)->setLineWidth(lineWidth);
     227            6 : }
     228              : 
     229              : 
     230              : void
     231            0 : Polygon::setHeight(std::string polygonID, double height) {
     232            0 :     getPolygon(polygonID)->setHeight(height);
     233            0 : }
     234              : 
     235              : 
     236              : SUMOPolygon*
     237        30872 : Polygon::getPolygon(const std::string& id) {
     238        30872 :     SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(id);
     239        30866 :     if (p == nullptr) {
     240           12 :         throw TraCIException("Polygon '" + id + "' is not known");
     241              :     }
     242        30866 :     return p;
     243              : }
     244              : 
     245              : 
     246              : SUMOTrafficObject*
     247          141 : Polygon::getTrafficObject(const std::string& id) {
     248          141 :     if (id == "") {
     249              :         return nullptr;
     250              :     }
     251          102 :     MSNet* net = MSNet::getInstance();
     252              :     // First try to find a vehicle with the given id
     253          102 :     SUMOVehicle* sumoVehicle = net->getVehicleControl().getVehicle(id);
     254          102 :     if (sumoVehicle != nullptr) {
     255              :         return static_cast<SUMOTrafficObject*>(sumoVehicle);
     256              :     }
     257            2 :     MSTransportable* transportable = net->getPersonControl().get(id);
     258            2 :     if (transportable != nullptr) {
     259              :         return static_cast<SUMOTrafficObject*>(transportable);
     260              :     } else {
     261            4 :         throw TraCIException("Traffic object '" + id + "' is not known");
     262              :     }
     263              : }
     264              : 
     265              : 
     266              : void
     267            6 : Polygon::setParameter(const std::string& polygonID, const std::string& key, const std::string& value) {
     268            6 :     SUMOPolygon* p = getPolygon(polygonID);
     269            6 :     p->setParameter(key, value);
     270            6 : }
     271              : 
     272              : 
     273         8309 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Polygon, POLYGON)
     274              : 
     275              : 
     276              : NamedRTree*
     277          352 : Polygon::getTree() {
     278          352 :     if (myTree == nullptr) {
     279           17 :         myTree = new NamedRTree();
     280           17 :         ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
     281           58 :         for (const auto& i : shapeCont.getPolygons()) {
     282           41 :             Boundary b = i.second->getShape().getBoxBoundary();
     283           41 :             const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
     284           41 :             const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
     285           41 :             myTree->Insert(cmin, cmax, i.second);
     286              :         }
     287              :     }
     288          352 :     return myTree;
     289              : }
     290              : 
     291              : void
     292        42458 : Polygon::cleanup() {
     293        42458 :     delete myTree;
     294        42458 :     myTree = nullptr;
     295        42458 : }
     296              : 
     297              : void
     298        20361 : Polygon::storeShape(const std::string& id, PositionVector& shape) {
     299        20361 :     shape = getPolygon(id)->getShape();
     300        20361 : }
     301              : 
     302              : 
     303              : std::shared_ptr<VariableWrapper>
     304          267 : Polygon::makeWrapper() {
     305          267 :     return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
     306              : }
     307              : 
     308              : 
     309              : bool
     310         6696 : Polygon::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
     311         6696 :     switch (variable) {
     312          245 :         case TRACI_ID_LIST:
     313          245 :             return wrapper->wrapStringList(objID, variable, getIDList());
     314          100 :         case ID_COUNT:
     315          100 :             return wrapper->wrapInt(objID, variable, getIDCount());
     316           72 :         case VAR_TYPE:
     317          144 :             return wrapper->wrapString(objID, variable, getType(objID));
     318           78 :         case VAR_COLOR:
     319           78 :             return wrapper->wrapColor(objID, variable, getColor(objID));
     320           72 :         case VAR_FILL:
     321           72 :             return wrapper->wrapInt(objID, variable, getFilled(objID));
     322           15 :         case VAR_WIDTH:
     323           15 :             return wrapper->wrapDouble(objID, variable, getLineWidth(objID));
     324            1 :         case VAR_HEIGHT:
     325            1 :             return wrapper->wrapDouble(objID, variable, getHeight(objID));
     326         6083 :         case VAR_SHAPE:
     327        12166 :             return wrapper->wrapPositionVector(objID, variable, getShape(objID));
     328           16 :         case libsumo::VAR_PARAMETER:
     329           16 :             paramData->readUnsignedByte();
     330           32 :             return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
     331            8 :         case libsumo::VAR_PARAMETER_WITH_KEY:
     332            8 :             paramData->readUnsignedByte();
     333           16 :             return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
     334              :         default:
     335              :             return false;
     336              :     }
     337              : }
     338              : 
     339              : 
     340              : bool
     341           73 : Polygon::exists(std::string polyID) {
     342           73 :     SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(polyID);
     343           73 :     return p != nullptr;
     344              : }
     345              : }
     346              : 
     347              : 
     348              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1