Eclipse SUMO - Simulation of Urban MObility
ShapeHandler.cpp
Go to the documentation of this file.
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 /****************************************************************************/
18 // The XML-Handler for network loading
19 /****************************************************************************/
20 #include <config.h>
21 
22 #include <string>
25 #include <utils/xml/XMLSubSys.h>
29 #include <utils/common/RGBColor.h>
35 
36 #include "Shape.h"
37 #include "ShapeContainer.h"
38 #include "ShapeHandler.h"
39 
40 
41 // ===========================================================================
42 // method definitions
43 // ===========================================================================
44 
45 ShapeHandler::ShapeHandler(const std::string& file, ShapeContainer& sc, const GeoConvHelper* geoConvHelper) :
46  SUMOSAXHandler(file),
47  myShapeContainer(sc),
48  myPrefix(""),
49  myDefaultColor(RGBColor::RED),
50  myDefaultIcon(SUMOXMLDefinitions::POIIcons.getString(POIIcon::NONE)),
51  myDefaultLayer(0),
52  myDefaultFill(false),
53  myLastParameterised(nullptr),
54  myGeoConvHelper(geoConvHelper) {
55 }
56 
57 
59 
60 
61 void
62 ShapeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
63  try {
64  switch (element) {
65  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
68  addPoly(attrs, false, false);
69  break;
70  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
73  addPOI(attrs, false, false);
74  break;
75  case SUMO_TAG_PARAM:
76  if (myLastParameterised != nullptr) {
77  bool ok = true;
78  const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
79  // continue if key was successfully loaded
80  if (ok) {
81  // circumventing empty string value
82  const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
83  // show warnings if values are invalid
84  if (key.empty()) {
85  WRITE_WARNING(TL("Error parsing key from shape generic parameter. Key cannot be empty"));
86  } else if (!SUMOXMLDefinitions::isValidParameterKey(key)) {
87  WRITE_WARNING(TL("Error parsing key from shape generic parameter. Key contains invalid characters"));
88  } else {
89  WRITE_DEBUG("Inserting generic parameter '" + key + "|" + val + "' into shape.");
91  }
92  }
93  }
94  break;
95  default:
96  break;
97  }
98  } catch (InvalidArgument& e) {
99  WRITE_ERROR(e.what());
100  }
101 }
102 
103 
104 void
106  if (element != SUMO_TAG_PARAM) {
107  myLastParameterised = nullptr;
108  }
109 }
110 
111 
112 void
113 ShapeHandler::addPOI(const SUMOSAXAttributes& attrs, const bool ignorePruning, const bool useProcessing) {
114  bool ok = true;
115  const double INVALID_POSITION(-1000000);
116  const std::string id = myPrefix + attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
117  double x = attrs.getOpt<double>(SUMO_ATTR_X, id.c_str(), ok, INVALID_POSITION);
118  const double y = attrs.getOpt<double>(SUMO_ATTR_Y, id.c_str(), ok, INVALID_POSITION);
119  const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, INVALID_POSITION);
120  double lon = attrs.getOpt<double>(SUMO_ATTR_LON, id.c_str(), ok, INVALID_POSITION);
121  double lat = attrs.getOpt<double>(SUMO_ATTR_LAT, id.c_str(), ok, INVALID_POSITION);
122  const double lanePos = attrs.getOpt<double>(SUMO_ATTR_POSITION, id.c_str(), ok, 0);
123  const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
124  const double lanePosLat = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, id.c_str(), ok, 0);
125  std::string icon = attrs.getOpt<std::string>(SUMO_ATTR_ICON, id.c_str(), ok, myDefaultIcon);
126  // check icon
127  if (!SUMOXMLDefinitions::POIIcons.hasString(icon)) {
128  WRITE_WARNING(TLF("Invalid icon % for POI '%', using default", icon, id));
129  icon = "none";
130  }
131  const double layer = attrs.getOpt<double>(SUMO_ATTR_LAYER, id.c_str(), ok, myDefaultLayer);
132  const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
133  const std::string laneID = attrs.getOpt<std::string>(SUMO_ATTR_LANE, id.c_str(), ok, "");
134  const double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, Shape::DEFAULT_ANGLE);
135  std::string imgFile = attrs.getOpt<std::string>(SUMO_ATTR_IMGFILE, id.c_str(), ok, Shape::DEFAULT_IMG_FILE);
136  const RGBColor color = attrs.hasAttribute(SUMO_ATTR_COLOR) ? attrs.get<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok) : (imgFile != "" ? RGBColor::WHITE : myDefaultColor);
137  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  if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
141  }
142  const double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, Shape::DEFAULT_IMG_WIDTH);
143  const double height = attrs.getOpt<double>(SUMO_ATTR_HEIGHT, id.c_str(), ok, Shape::DEFAULT_IMG_HEIGHT);
144  // check if ID is valid
146  WRITE_WARNING(TL("Invalid characters for PoI ID"));
147  ok = false;
148  }
149  // continue
150  if (ok) {
151  const GeoConvHelper* gch;
152  // set GEOConverter
153  if (myGeoConvHelper != nullptr) {
154  gch = myGeoConvHelper;
155  } else if (useProcessing) {
157  } else {
158  gch = &GeoConvHelper::getFinal();
159  }
160  // check if GEOProjection has to be used
161  if (useProcessing && gch->usingGeoProjection()) {
162  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  if ((x == INVALID_POSITION) || (y == INVALID_POSITION)) {
171  // try computing x,y from lane,pos
172  if (laneID != "") {
173  pos = getLanePos(id, laneID, lanePos, friendlyPos, lanePosLat);
174  } else {
175  // try computing x,y from lon,lat
176  if ((lat == INVALID_POSITION) || (lon == INVALID_POSITION)) {
177  WRITE_ERRORF(TL("Either (x, y), (lon, lat) or (lane, pos) must be specified for PoI '%'."), id);
178  return;
179  } else if (!gch->usingGeoProjection()) {
180  WRITE_ERRORF(TL("(lon, lat) is specified for PoI '%' but no geo-conversion is specified for the network."), id);
181  return;
182  }
183  pos.set(lon, lat);
184  useGeo = true;
185  bool success = true;
186  if (useProcessing) {
187  success = GeoConvHelper::getProcessing().x2cartesian(pos);
188  } else {
189  success = gch->x2cartesian_const(pos);
190  }
191  if (!success) {
192  WRITE_ERRORF(TL("Unable to project coordinates for PoI '%'."), id);
193  return;
194  }
195  }
196  }
197  if (z != INVALID_POSITION) {
198  pos.setz(z);
199  }
200  if (!myShapeContainer.addPOI(id, type, color, pos, useGeo, laneID, lanePos, friendlyPos, lanePosLat, icon,
201  layer, angle, imgFile, relativePath, width, height, ignorePruning)) {
202  WRITE_ERRORF(TL("PoI '%' already exists."), id);
203  }
205  if ((laneID != "") && addLanePosParams()) {
209  }
210  }
211 }
212 
213 
214 void
215 ShapeHandler::addPoly(const SUMOSAXAttributes& attrs, const bool ignorePruning, const bool useProcessing) {
216  bool ok = true;
217  const std::string id = myPrefix + attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
218  // check if ID is valid
220  WRITE_WARNING(TL("Invalid characters for Poly ID"));
221  ok = false;
222  }
223  // get the id, report an error if not given or empty...
224  if (ok) {
225  // continue loading parameters
226  const double layer = attrs.getOpt<double>(SUMO_ATTR_LAYER, id.c_str(), ok, myDefaultLayer);
227  const bool fill = attrs.getOpt<bool>(SUMO_ATTR_FILL, id.c_str(), ok, myDefaultFill);
228  const double lineWidth = attrs.getOpt<double>(SUMO_ATTR_LINEWIDTH, id.c_str(), ok, Shape::DEFAULT_LINEWIDTH);
229  const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, Shape::DEFAULT_TYPE);
230  const RGBColor color = attrs.hasAttribute(SUMO_ATTR_COLOR) ? attrs.get<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok) : myDefaultColor;
231  PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
232  const bool geo = attrs.getOpt<bool>(SUMO_ATTR_GEO, id.c_str(), ok, false);
233  // set geo converter
234  const GeoConvHelper* gch;
235  if (myGeoConvHelper != nullptr) {
236  gch = myGeoConvHelper;
237  } else {
238  gch = &GeoConvHelper::getFinal();
239  }
240  // check if poly use geo coordinates
241  if (geo || useProcessing) {
242  bool success = true;
243  for (int i = 0; i < (int)shape.size(); i++) {
244  if (useProcessing) {
245  success &= GeoConvHelper::getProcessing().x2cartesian(shape[i]);
246  } else {
247  success &= gch->x2cartesian_const(shape[i]);
248  }
249  }
250  if (!success) {
251  WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), id);
252  return;
253  }
254  }
255  const double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, Shape::DEFAULT_ANGLE);
256  std::string imgFile = attrs.getOpt<std::string>(SUMO_ATTR_IMGFILE, id.c_str(), ok, Shape::DEFAULT_IMG_FILE);
257  bool relativePath = attrs.getOpt<bool>(SUMO_ATTR_RELATIVEPATH, id.c_str(), ok, Shape::DEFAULT_RELATIVEPATH);
258  if (imgFile != "" && !FileHelpers::isAbsolute(imgFile)) {
260  }
261  // check that shape's size is valid
262  if (shape.size() == 0) {
263  WRITE_ERROR(TL("Polygon's shape cannot be empty."));
264  return;
265  }
266  // check that lineWidth is positive
267  if (lineWidth <= 0) {
268  WRITE_ERROR(TL("Polygon's lineWidth must be greater than 0."));
269  return;
270  }
271  // create polygon, or show an error if polygon already exists
272  if (!myShapeContainer.addPolygon(id, type, color, layer, angle, imgFile, relativePath, shape, geo, fill, lineWidth, ignorePruning)) {
273  WRITE_ERRORF(TL("Polygon '%' already exists."), id);
274  }
276  }
277 }
278 
279 
282  return myLastParameterised;
283 }
284 
285 
286 bool
287 ShapeHandler::loadFiles(const std::vector<std::string>& files, ShapeHandler& sh) {
288  for (const auto& fileIt : files) {
289  if (!XMLSubSys::runParser(sh, fileIt, false)) {
290  WRITE_MESSAGEF(TL("Loading of shapes from % failed."), fileIt);
291  return false;
292  }
293  }
294  return true;
295 }
296 
297 
298 void
299 ShapeHandler::setDefaults(const std::string& prefix, const RGBColor& color, const std::string& icon, const double layer, const bool fill) {
300  myPrefix = prefix;
301  myDefaultColor = color;
302  myDefaultIcon = icon;
303  myDefaultLayer = layer;
304  myDefaultFill = fill;
305 }
306 
307 
308 bool
310  return false;
311 }
312 
313 
314 /****************************************************************************/
#define INVALID_POSITION
#define WRITE_DEBUG(msg)
Definition: MsgHandler.h:306
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_MESSAGEF(...)
Definition: MsgHandler.h:298
#define WRITE_ERRORF(...)
Definition: MsgHandler.h:305
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
POIIcon
POI icons.
@ SUMO_TAG_POI
begin/end of the description of a Point of interest
@ SUMO_TAG_POLY
begin/end of the description of a polygon
@ SUMO_TAG_PARAM
parameter associated to a certain key
@ SUMO_ATTR_ICON
icon
@ SUMO_ATTR_LANE
@ SUMO_ATTR_LON
@ SUMO_ATTR_VALUE
@ SUMO_ATTR_Y
@ SUMO_ATTR_Z
@ SUMO_ATTR_X
@ SUMO_ATTR_LINEWIDTH
@ SUMO_ATTR_POSITION_LAT
@ SUMO_ATTR_GEO
@ SUMO_ATTR_SHAPE
edge: the shape in xml-definition
@ SUMO_ATTR_FILL
Fill the polygon.
@ SUMO_ATTR_LAYER
A layer number.
@ SUMO_ATTR_ANGLE
@ SUMO_ATTR_HEIGHT
@ SUMO_ATTR_FRIENDLY_POS
@ SUMO_ATTR_LAT
@ SUMO_ATTR_TYPE
@ SUMO_ATTR_COLOR
A color information.
@ SUMO_ATTR_ID
@ SUMO_ATTR_IMGFILE
@ SUMO_ATTR_WIDTH
@ SUMO_ATTR_KEY
@ SUMO_ATTR_POSITION
@ SUMO_ATTR_RELATIVEPATH
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static bool isAbsolute(const std::string &path)
Returns the information whether the given path is absolute.
static std::string getConfigurationRelative(const std::string &configPath, const std::string &path)
Returns the second path as a relative path to the first file.
const std::string & getFileName() const
returns the current file name
static methods for processing the coordinates conversion for the current net
Definition: GeoConvHelper.h:53
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
Definition: GeoConvHelper.h:84
bool x2cartesian(Position &from, bool includeInBoundary=true)
Converts the given coordinate into a cartesian and optionally update myConvBoundary.
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
bool usingGeoProjection() const
Returns whether a transformation from geo to metric coordinates will be performed.
bool x2cartesian_const(Position &from) const
Converts the given coordinate into a cartesian using the previous initialisation.
T get(const std::string &id) const
Retrieves an item.
An upper class for objects with additional parameters.
Definition: Parameterised.h:41
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
void set(double x, double y)
set positions x and y
Definition: Position.h:85
void setz(double z)
set position z
Definition: Position.h:80
A list of positions.
static const RGBColor WHITE
Definition: RGBColor.h:192
Encapsulated SAX-Attributes.
virtual std::string getString(int id, bool *isPresent=nullptr) const =0
Returns the string-value of the named (by its enum-value) attribute.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
SAX-handler base for SUMO-files.
class for maintaining associations between enums and xml-strings
static bool isValidTypeID(const std::string &value)
whether the given string is a valid id for an edge or vehicle type
static StringBijection< POIIcon > POIIcons
POI icon values.
static bool isValidParameterKey(const std::string &value)
whether the given string is a valid key for a parameter
Storage for geometrical objects.
const Polygons & getPolygons() const
Returns all polygons.
virtual bool addPolygon(const std::string &id, const std::string &type, const RGBColor &color, double layer, double angle, const std::string &imgFile, bool relativePath, const PositionVector &shape, bool geo, bool fill, double lineWidth, bool ignorePruning=false, const std::string &name=Shape::DEFAULT_NAME)
Builds a polygon using the given values and adds it to the container.
virtual bool addPOI(const std::string &id, const std::string &type, const RGBColor &color, const Position &pos, bool geo, const std::string &lane, double posOverLane, bool friendlyPos, double posLat, const std::string &icon, double layer, double angle, const std::string &imgFile, bool relativePath, double width, double height, bool ignorePruning=false)
Builds a POI using the given values and adds it to the container.
const POIs & getPOIs() const
Returns all pois.
The XML-Handler for network loading.
Definition: ShapeHandler.h:47
virtual bool addLanePosParams()
Whether some input attributes shall be automatically added as params (Can be implemented in all child...
std::string myPrefix
The prefix to use.
Definition: ShapeHandler.h:112
virtual void myEndElement(int element)
Called when a closing tag occurs.
void addPOI(const SUMOSAXAttributes &attrs, const bool ignorePruning, const bool useProcessing)
adds a POI
void addPoly(const SUMOSAXAttributes &attrs, const bool ignorePruning, const bool useProcessing)
adds a polygon
RGBColor myDefaultColor
The default color to use.
Definition: ShapeHandler.h:115
virtual void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
ShapeContainer & myShapeContainer
reference to shape container in which all Shares are being added
Definition: ShapeHandler.h:109
Parameterised * myLastParameterised
element to receive parameters
Definition: ShapeHandler.h:127
static bool loadFiles(const std::vector< std::string > &files, ShapeHandler &sh)
loads all of the given files
virtual Position getLanePos(const std::string &poiID, const std::string &laneID, double lanePos, bool friendlyPos, double lanePosLat)=0
get position for a given laneID (Has to be implemented in all child)
void setDefaults(const std::string &prefix, const RGBColor &color, const std::string &icon, const double layer, const bool fill=false)
set default values
bool myDefaultFill
Information whether polygons should be filled.
Definition: ShapeHandler.h:124
virtual ~ShapeHandler()
Destructor.
ShapeHandler(const std::string &file, ShapeContainer &sc, const GeoConvHelper *=nullptr)
Constructor.
Parameterised * getLastParameterised() const
get last parameterised object
std::string myDefaultIcon
The default icon to use.
Definition: ShapeHandler.h:118
const GeoConvHelper * myGeoConvHelper
geo-conversion to use during loading
Definition: ShapeHandler.h:130
double myDefaultLayer
The default layer to use.
Definition: ShapeHandler.h:121
static const bool DEFAULT_RELATIVEPATH
Definition: Shape.h:48
static const double DEFAULT_LAYER
Definition: Shape.h:43
static const double DEFAULT_LAYER_POI
Definition: Shape.h:45
static const double DEFAULT_IMG_WIDTH
Definition: Shape.h:49
static const std::string DEFAULT_IMG_FILE
Definition: Shape.h:47
static const double DEFAULT_LINEWIDTH
Definition: Shape.h:44
static const double DEFAULT_ANGLE
Definition: Shape.h:46
static const double DEFAULT_IMG_HEIGHT
Definition: Shape.h:50
static const std::string DEFAULT_TYPE
Definition: Shape.h:42
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false, const bool isRoute=false, const bool isExternal=false, const bool catchExceptions=true)
Runs the given handler on the given file; returns if everything's ok.
Definition: XMLSubSys.cpp:157