Eclipse SUMO - Simulation of Urban MObility
PCLoaderArcView.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 /****************************************************************************/
20 // A reader of pois and polygons from shape files
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <string>
26 #include <utils/common/ToString.h>
29 #include <utils/geom/GeomHelper.h>
31 #include <utils/common/RGBColor.h>
33 #include <polyconvert/PCTypeMap.h>
34 #include "PCLoaderArcView.h"
35 
36 #ifdef HAVE_GDAL
37 #ifdef _MSC_VER
38 #pragma warning(push)
39 #pragma warning(disable: 4435 5219 5220)
40 #endif
41 #if __GNUC__ > 3
42 #pragma GCC diagnostic push
43 #pragma GCC diagnostic ignored "-Wpedantic"
44 #endif
45 #include <ogrsf_frmts.h>
46 #if __GNUC__ > 3
47 #pragma GCC diagnostic pop
48 #endif
49 #ifdef _MSC_VER
50 #pragma warning(pop)
51 #endif
52 #endif
53 
54 
55 // ===========================================================================
56 // static member variables
57 // ===========================================================================
59 
60 
61 // ===========================================================================
62 // method definitions
63 // ===========================================================================
64 void
66  if (!oc.isSet("shapefile-prefixes")) {
67  return;
68  }
69  // parse file(s)
70  std::vector<std::string> files = oc.getStringVector("shapefile-prefixes");
71  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
72  PROGRESS_BEGIN_MESSAGE("Parsing from shape-file '" + *file + "'");
73  load(*file, oc, toFill, tm);
75  }
76 }
77 
78 
79 #ifdef HAVE_GDAL
80 const PositionVector
81 PCLoaderArcView::toShape(OGRLineString* geom, const std::string& tid) {
83  int outOfRange = 0;
84  for (int j = 0; j < geom->getNumPoints(); j++) {
85  if (fabs(geom->getX(j)) > 180 || fabs(geom->getY(j)) > 90) {
86  outOfRange++;
87  }
88  }
89  if (2 * outOfRange > geom->getNumPoints()) {
90  WRITE_WARNING(TL("No coordinate system found and coordinates look already projected."));
91  GeoConvHelper::init("!", GeoConvHelper::getProcessing().getOffset(), GeoConvHelper::getProcessing().getOrigBoundary(), GeoConvHelper::getProcessing().getConvBoundary());
92  } else {
93  WRITE_WARNING(TL("Could not find geo coordinate system, assuming WGS84."));
94  }
96  }
98  PositionVector shape;
99 #if GDAL_VERSION_MAJOR < 3
100  for (int j = 0; j < geom->getNumPoints(); j++) {
101  Position pos(geom->getX(j), geom->getY(j));
102 #else
103  for (const OGRPoint& p : *geom) {
104  Position pos(p.getX(), p.getY());
105 #endif
106  if (!geoConvHelper.x2cartesian(pos)) {
107  WRITE_ERRORF(TL("Unable to project coordinates for polygon '%'."), tid);
108  }
109  shape.push_back_noDoublePos(pos);
110  }
111  return shape;
112 }
113 #endif
114 
115 
116 void
117 PCLoaderArcView::load(const std::string& file, OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
118 #ifdef HAVE_GDAL
119  GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
120  // get defaults
121  const std::string idField = oc.getString("shapefile.id-column");
122  const bool useRunningID = oc.getBool("shapefile.use-running-id") || idField == "";
123  // start parsing
124  std::string shpName = file + ".shp";
125  int fillType = -1;
126  if (oc.getString("shapefile.fill") == "true") {
127  fillType = 1;
128  } else if (oc.getString("shapefile.fill") == "false") {
129  fillType = 0;
130  }
131 #if GDAL_VERSION_MAJOR < 2
132  OGRRegisterAll();
133  OGRDataSource* poDS = OGRSFDriverRegistrar::Open(shpName.c_str(), FALSE);
134 #else
135  GDALAllRegister();
136  GDALDataset* poDS = (GDALDataset*) GDALOpenEx(shpName.c_str(), GDAL_OF_VECTOR | GA_ReadOnly, NULL, NULL, NULL);
137 #endif
138  if (poDS == NULL) {
139  throw ProcessError(TLF("Could not open shape description '%'.", shpName));
140  }
141 
142  // begin file parsing
143  OGRLayer* poLayer = poDS->GetLayer(0);
144  poLayer->ResetReading();
145 
146  // build coordinate transformation
147  OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
148  OGRSpatialReference destTransf;
149  // use wgs84 as destination
150  destTransf.SetWellKnownGeogCS("WGS84");
151 #if GDAL_VERSION_MAJOR > 2
152  if (oc.getBool("shapefile.traditional-axis-mapping") || origTransf != nullptr) {
153  destTransf.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
154  }
155 #endif
156  OGRCoordinateTransformation* poCT = origTransf == nullptr ? nullptr : OGRCreateCoordinateTransformation(origTransf, &destTransf);
157  if (poCT == nullptr) {
158  if (oc.getBool("shapefile.guess-projection")) {
159  OGRSpatialReference origTransf2;
160  origTransf2.SetWellKnownGeogCS("WGS84");
161  poCT = OGRCreateCoordinateTransformation(&origTransf2, &destTransf);
162  }
163  } else {
164  myWarnMissingProjection = false;
165  }
166 
167  OGRFeature* poFeature;
168  poLayer->ResetReading();
169  int runningID = 0;
170  while ((poFeature = poLayer->GetNextFeature()) != nullptr) {
171  if (runningID == 0) {
172  std::vector<std::string> fields;
173  for (int i = 0; i < poFeature->GetFieldCount(); i++) {
174  fields.push_back(poFeature->GetFieldDefnRef(i)->GetNameRef());
175  }
176  WRITE_MESSAGE("Available fields: " + toString(fields));
177  }
178  std::vector<Parameterised*> parCont;
179  // read in edge attributes
180  std::string id = useRunningID ? toString(runningID) : poFeature->GetFieldAsString(idField.c_str());
181  ++runningID;
183  if (id == "") {
184  throw ProcessError(TLF("Missing id under '%'", idField));
185  }
186  id = oc.getString("prefix") + id;
187  std::string type;
188  for (const std::string& typeField : oc.getStringVector("shapefile.type-columns")) {
189  if (type != "") {
190  type += ".";
191  }
192  type += poFeature->GetFieldAsString(typeField.c_str());
193  }
194  RGBColor color = RGBColor::parseColor(oc.getString("color"));
195  std::string icon = oc.getString("icon");
196  double layer = oc.getFloat("layer");
197  double angle = Shape::DEFAULT_ANGLE;
198  std::string imgFile = Shape::DEFAULT_IMG_FILE;
199  if (type != "") {
200  if (tm.has(type)) {
201  const PCTypeMap::TypeDef& def = tm.get(type);
202  if (def.discard) {
203  continue;
204  }
205  color = def.color;
206  icon = def.icon;
207  layer = def.layer;
208  angle = def.angle;
209  imgFile = def.imgFile;
210  type = def.id;
211  }
212  } else {
213  type = oc.getString("type");
214  }
215  if (poFeature->GetFieldIndex("angle") >= 0) {
216  angle = poFeature->GetFieldAsDouble("angle");
217  }
218  // read in the geometry
219  OGRGeometry* poGeometry = poFeature->GetGeometryRef();
220  if (poGeometry == 0) {
221  OGRFeature::DestroyFeature(poFeature);
222  continue;
223  }
224  // try transform to wgs84
225  if (poCT != nullptr) {
226  poGeometry->transform(poCT);
227  }
228  OGRwkbGeometryType gtype = poGeometry->getGeometryType();
229  switch (gtype) {
230  case wkbPoint: {
231  OGRPoint* cgeom = (OGRPoint*) poGeometry;
232  Position pos(cgeom->getX(), cgeom->getY());
233  if (!geoConvHelper.x2cartesian(pos)) {
234  WRITE_ERRORF(TL("Unable to project coordinates for POI '%'."), id);
235  }
236  PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer, angle, imgFile);
237  if (toFill.add(poi)) {
238  parCont.push_back(poi);
239  }
240  }
241  break;
242  case wkbLineString:
243  case wkbLineString25D: {
244  const PositionVector shape = toShape((OGRLineString*) poGeometry, id);
245  SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, fillType == 1, 1, layer, angle, imgFile);
246  if (toFill.add(poly)) {
247  parCont.push_back(poly);
248  }
249  }
250  break;
251  case wkbPolygon: {
252  const bool fill = fillType < 0 || fillType == 1;
253  const PositionVector shape = toShape(((OGRPolygon*) poGeometry)->getExteriorRing(), id);
254  SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, fill, 1, layer, angle, imgFile);
255  if (toFill.add(poly)) {
256  parCont.push_back(poly);
257  }
258  }
259  break;
260  case wkbMultiPoint: {
261  OGRMultiPoint* cgeom = (OGRMultiPoint*) poGeometry;
262  for (int i = 0; i < cgeom->getNumGeometries(); ++i) {
263  OGRPoint* cgeom2 = (OGRPoint*) cgeom->getGeometryRef(i);
264  Position pos(cgeom2->getX(), cgeom2->getY());
265  const std::string tid = id + "#" + toString(i);
266  if (!geoConvHelper.x2cartesian(pos)) {
267  WRITE_ERRORF(TL("Unable to project coordinates for POI '%'."), tid);
268  }
269  PointOfInterest* poi = new PointOfInterest(tid, type, color, pos, false, "", 0, false, 0, icon, layer, angle, imgFile);
270  if (toFill.add(poi)) {
271  parCont.push_back(poi);
272  }
273  }
274  }
275  break;
276  case wkbMultiLineString: {
277  OGRMultiLineString* cgeom = (OGRMultiLineString*) poGeometry;
278  for (int i = 0; i < cgeom->getNumGeometries(); ++i) {
279  const std::string tid = id + "#" + toString(i);
280  const PositionVector shape = toShape((OGRLineString*) cgeom->getGeometryRef(i), tid);
281  SUMOPolygon* poly = new SUMOPolygon(tid, type, color, shape, false, fillType == 1, 1, layer, angle, imgFile);
282  if (toFill.add(poly)) {
283  parCont.push_back(poly);
284  }
285  }
286  }
287  break;
288  case wkbMultiPolygon: {
289  const bool fill = fillType < 0 || fillType == 1;
290  OGRMultiPolygon* cgeom = (OGRMultiPolygon*) poGeometry;
291  for (int i = 0; i < cgeom->getNumGeometries(); ++i) {
292  const std::string tid = id + "#" + toString(i);
293  const PositionVector shape = toShape(((OGRPolygon*) cgeom->getGeometryRef(i))->getExteriorRing(), tid);
294  SUMOPolygon* poly = new SUMOPolygon(tid, type, color, shape, false, fill, 1, layer, angle, imgFile);
295  if (toFill.add(poly)) {
296  parCont.push_back(poly);
297  }
298  }
299  }
300  break;
301  default:
302  WRITE_WARNINGF(TL("Unsupported shape type occurred (id='%')."), id);
303  break;
304  }
305  if (oc.getBool("shapefile.add-param")) {
306  for (std::vector<Parameterised*>::const_iterator it = parCont.begin(); it != parCont.end(); ++it) {
307  OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
308  for (int iField = 0; iField < poFDefn->GetFieldCount(); iField++) {
309  OGRFieldDefn* poFieldDefn = poFDefn->GetFieldDefn(iField);
310  if (poFieldDefn->GetNameRef() != idField) {
311  if (poFieldDefn->GetType() == OFTReal) {
312  (*it)->setParameter(poFieldDefn->GetNameRef(), toString(poFeature->GetFieldAsDouble(iField)));
313  } else {
314  (*it)->setParameter(poFieldDefn->GetNameRef(), StringUtils::latin1_to_utf8(poFeature->GetFieldAsString(iField)));
315  }
316  }
317  }
318  }
319  }
320  OGRFeature::DestroyFeature(poFeature);
321  }
322 #if GDAL_VERSION_MAJOR < 2
323  OGRDataSource::DestroyDataSource(poDS);
324 #else
325  GDALClose(poDS);
326 #endif
328 #else
329  UNUSED_PARAMETER(file);
330  UNUSED_PARAMETER(oc);
331  UNUSED_PARAMETER(toFill);
332  UNUSED_PARAMETER(tm);
333  WRITE_ERROR(TL("SUMO was compiled without GDAL support."));
334 #endif
335 }
336 
337 
338 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_ERRORF(...)
Definition: MsgHandler.h:305
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:297
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:300
#define TLF(string,...)
Definition: MsgHandler.h:317
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:299
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
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 bool init(OptionsCont &oc)
Initialises the processing and the final instance using the given options.
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static bool myWarnMissingProjection
static void load(const std::string &file, OptionsCont &oc, PCPolyContainer &toFill, PCTypeMap &tm)
Parses pois/polys stored within the given file.
static void loadIfSet(OptionsCont &oc, PCPolyContainer &toFill, PCTypeMap &tm)
Loads pois/polygons assumed to be stored as shape files-files.
A storage for loaded polygons and pois.
bool add(SUMOPolygon *poly, bool ignorePruning=false)
Adds a polygon to the storage.
A storage for type mappings.
Definition: PCTypeMap.h:42
const TypeDef & get(const std::string &id)
Returns a type definition.
Definition: PCTypeMap.cpp:70
bool has(const std::string &id)
Returns the information whether the named type is known.
Definition: PCTypeMap.cpp:76
A point-of-interest.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
A list of positions.
void push_back_noDoublePos(const Position &p)
insert in back a non double position
static RGBColor parseColor(std::string coldef)
Parses a color information.
Definition: RGBColor.cpp:239
static const std::string DEFAULT_IMG_FILE
Definition: Shape.h:47
static const double DEFAULT_ANGLE
Definition: Shape.h:46
static std::string latin1_to_utf8(std::string str)
Transfers from Latin 1 (ISO-8859-1) to UTF-8.
Definition: StringUtils.cpp:87
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:56
A single definition of values that shall be used for a given type.
Definition: PCTypeMap.h:61
std::string icon
the icon to use
Definition: PCTypeMap.h:69
bool discard
Information whether polygons of this type shall be discarded.
Definition: PCTypeMap.h:77
double layer
The layer to use.
Definition: PCTypeMap.h:71
double angle
The angle to use.
Definition: PCTypeMap.h:73
std::string imgFile
The image file to use.
Definition: PCTypeMap.h:75
std::string id
The new type id to use.
Definition: PCTypeMap.h:63
RGBColor color
The color to use.
Definition: PCTypeMap.h:65