Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-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 PCLoaderArcView.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // A reader of pois and polygons from shape files
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <string>
25 : #include <utils/common/MsgHandler.h>
26 : #include <utils/common/ToString.h>
27 : #include <utils/common/StringUtils.h>
28 : #include <utils/options/OptionsCont.h>
29 : #include <utils/geom/GeomHelper.h>
30 : #include <utils/geom/GeoConvHelper.h>
31 : #include <utils/common/RGBColor.h>
32 : #include <polyconvert/PCPolyContainer.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 <gdal_version.h>
46 : #include <ogrsf_frmts.h>
47 : #if __GNUC__ > 3
48 : #pragma GCC diagnostic pop
49 : #endif
50 : #ifdef _MSC_VER
51 : #pragma warning(pop)
52 : #endif
53 : #endif
54 :
55 :
56 : // ===========================================================================
57 : // static member variables
58 : // ===========================================================================
59 : bool PCLoaderArcView::myWarnMissingProjection = true;
60 :
61 :
62 : // ===========================================================================
63 : // method definitions
64 : // ===========================================================================
65 : void
66 44 : PCLoaderArcView::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
67 88 : if (!oc.isSet("shapefile-prefixes") && !oc.isSet("geojson-files")) {
68 : return;
69 : }
70 : // parse file(s)
71 15 : for (std::string file : oc.getStringVector("shapefile-prefixes")) {
72 : file += ".shp";
73 9 : PROGRESS_BEGIN_MESSAGE("Parsing from shape-file '" + file + "'");
74 3 : load(file, oc, toFill, tm);
75 3 : PROGRESS_DONE_MESSAGE();
76 : }
77 15 : for (const std::string& file : oc.getStringVector("geojson-files")) {
78 9 : PROGRESS_BEGIN_MESSAGE("Parsing from geojson-file '" + file + "'");
79 3 : load(file, oc, toFill, tm);
80 3 : PROGRESS_DONE_MESSAGE();
81 : }
82 : }
83 :
84 :
85 : #ifdef HAVE_GDAL
86 : const PositionVector
87 1262 : PCLoaderArcView::toShape(OGRLineString* geom, const std::string& tid) {
88 1262 : if (myWarnMissingProjection) {
89 : int outOfRange = 0;
90 63 : for (int j = 0; j < geom->getNumPoints(); j++) {
91 60 : if (fabs(geom->getX(j)) > 180 || fabs(geom->getY(j)) > 90) {
92 60 : outOfRange++;
93 : }
94 : }
95 3 : if (2 * outOfRange > geom->getNumPoints()) {
96 3 : WRITE_WARNING(TL("No coordinate system found and coordinates look already projected."));
97 6 : GeoConvHelper::init("!", GeoConvHelper::getProcessing().getOffset(), GeoConvHelper::getProcessing().getOrigBoundary(), GeoConvHelper::getProcessing().getConvBoundary());
98 : } else {
99 0 : WRITE_WARNING(TL("Could not find geo coordinate system, assuming WGS84."));
100 : }
101 3 : myWarnMissingProjection = false;
102 : }
103 : GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
104 1262 : PositionVector shape;
105 : #if GDAL_VERSION_MAJOR < 3
106 : for (int j = 0; j < geom->getNumPoints(); j++) {
107 : Position pos(geom->getX(j), geom->getY(j));
108 : #else
109 152870 : for (const OGRPoint& p : *geom) {
110 75173 : Position pos(p.getX(), p.getY(), p.Is3D() ? p.getZ() : 0.0);
111 : #endif
112 75173 : if (!geoConvHelper.x2cartesian(pos)) {
113 0 : WRITE_ERRORF(TL("Unable to project coordinates for polygon '%'."), tid);
114 : }
115 75173 : shape.push_back_noDoublePos(pos);
116 1262 : }
117 1262 : return shape;
118 0 : }
119 : #endif
120 :
121 :
122 : void
123 6 : PCLoaderArcView::load(const std::string& file, OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
124 : #ifdef HAVE_GDAL
125 : GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
126 : // get defaults
127 6 : const std::string idField = oc.getString("shapefile.id-column");
128 6 : const bool useRunningID = oc.getBool("shapefile.use-running-id") || idField == "";
129 : int fillType = -1;
130 12 : if (oc.getString("shapefile.fill") == "true") {
131 : fillType = 1;
132 12 : } else if (oc.getString("shapefile.fill") == "false") {
133 : fillType = 0;
134 : }
135 : #if GDAL_VERSION_MAJOR < 2
136 : OGRRegisterAll();
137 : OGRDataSource* poDS = OGRSFDriverRegistrar::Open(file.c_str(), FALSE);
138 : #else
139 6 : GDALAllRegister();
140 6 : GDALDataset* poDS = (GDALDataset*) GDALOpenEx(file.c_str(), GDAL_OF_VECTOR | GA_ReadOnly, NULL, NULL, NULL);
141 : #endif
142 6 : if (poDS == NULL) {
143 0 : throw ProcessError(TLF("Could not open shape description '%'.", file));
144 : }
145 :
146 : // begin file parsing
147 6 : OGRLayer* poLayer = poDS->GetLayer(0);
148 6 : poLayer->ResetReading();
149 :
150 : // build coordinate transformation
151 : #if GDAL_VERSION_MAJOR < 3
152 : OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
153 : #else
154 6 : const OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
155 : #endif
156 6 : OGRSpatialReference destTransf;
157 : // use wgs84 as destination
158 6 : destTransf.SetWellKnownGeogCS("WGS84");
159 : #if GDAL_VERSION_MAJOR > 2
160 12 : if (oc.getBool("shapefile.traditional-axis-mapping") || origTransf != nullptr) {
161 3 : destTransf.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
162 : }
163 : #endif
164 6 : OGRCoordinateTransformation* poCT = origTransf == nullptr ? nullptr : OGRCreateCoordinateTransformation(origTransf, &destTransf);
165 3 : if (poCT == nullptr) {
166 6 : if (oc.getBool("shapefile.guess-projection")) {
167 0 : OGRSpatialReference origTransf2;
168 0 : origTransf2.SetWellKnownGeogCS("WGS84");
169 0 : poCT = OGRCreateCoordinateTransformation(&origTransf2, &destTransf);
170 0 : }
171 : } else {
172 3 : myWarnMissingProjection = false;
173 : }
174 :
175 : OGRFeature* poFeature;
176 6 : poLayer->ResetReading();
177 6 : int runningID = 0;
178 1267 : while ((poFeature = poLayer->GetNextFeature()) != nullptr) {
179 1261 : if (runningID == 0) {
180 6 : std::vector<std::string> fields;
181 32 : for (int i = 0; i < poFeature->GetFieldCount(); i++) {
182 40 : fields.push_back(poFeature->GetFieldDefnRef(i)->GetNameRef());
183 : }
184 12 : WRITE_MESSAGE("Available fields: " + toString(fields));
185 6 : }
186 1261 : std::vector<Parameterised*> parCont;
187 : // read in edge attributes
188 1261 : std::string id = useRunningID ? toString(runningID) : poFeature->GetFieldAsString(idField.c_str());
189 1261 : ++runningID;
190 1261 : id = StringUtils::latin1_to_utf8(StringUtils::prune(id));
191 1261 : if (id == "") {
192 0 : throw ProcessError(TLF("Missing id under '%'", idField));
193 : }
194 3783 : id = oc.getString("prefix") + id;
195 : std::string type;
196 2522 : for (const std::string& typeField : oc.getStringVector("shapefile.type-columns")) {
197 0 : if (type != "") {
198 : type += ".";
199 : }
200 0 : type += poFeature->GetFieldAsString(typeField.c_str());
201 : }
202 1261 : RGBColor color = RGBColor::parseColor(oc.getString("color"));
203 1261 : std::string icon = oc.getString("icon");
204 1261 : double layer = oc.getFloat("layer");
205 1261 : double angle = Shape::DEFAULT_ANGLE;
206 : std::string imgFile = Shape::DEFAULT_IMG_FILE;
207 1261 : if (type != "") {
208 0 : if (tm.has(type)) {
209 0 : const PCTypeMap::TypeDef& def = tm.get(type);
210 0 : if (def.discard) {
211 0 : continue;
212 : }
213 0 : color = def.color;
214 0 : icon = def.icon;
215 0 : layer = def.layer;
216 0 : angle = def.angle;
217 0 : imgFile = def.imgFile;
218 0 : type = def.id;
219 : }
220 : } else {
221 2522 : type = oc.getString("type");
222 : }
223 1261 : if (poFeature->GetFieldIndex("angle") >= 0) {
224 0 : angle = poFeature->GetFieldAsDouble("angle");
225 : }
226 : // read in the geometry
227 1261 : OGRGeometry* poGeometry = poFeature->GetGeometryRef();
228 1261 : if (poGeometry == 0) {
229 0 : OGRFeature::DestroyFeature(poFeature);
230 0 : continue;
231 : }
232 : // try transform to wgs84
233 1261 : if (poCT != nullptr) {
234 66 : poGeometry->transform(poCT);
235 : }
236 1261 : OGRwkbGeometryType gtype = poGeometry->getGeometryType();
237 1261 : switch (gtype) {
238 0 : case wkbPoint:
239 : case wkbPoint25D: {
240 : OGRPoint* cgeom = (OGRPoint*) poGeometry;
241 : Position pos(cgeom->getX(), cgeom->getY());
242 0 : if (!geoConvHelper.x2cartesian(pos)) {
243 0 : WRITE_ERRORF(TL("Unable to project coordinates for POI '%'."), id);
244 : }
245 0 : PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer, angle, imgFile);
246 0 : if (toFill.add(poi)) {
247 0 : parCont.push_back(poi);
248 : }
249 : }
250 0 : break;
251 64 : case wkbLineString:
252 : case wkbLineString25D: {
253 64 : const PositionVector shape = toShape((OGRLineString*) poGeometry, id);
254 64 : SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, fillType == 1, 1, layer, angle, imgFile);
255 64 : if (toFill.add(poly)) {
256 64 : parCont.push_back(poly);
257 : }
258 64 : }
259 64 : break;
260 1194 : case wkbPolygon:
261 : case wkbPolygon25D: {
262 1194 : const bool fill = fillType < 0 || fillType == 1;
263 1194 : const PositionVector shape = toShape(((OGRPolygon*) poGeometry)->getExteriorRing(), id);
264 1194 : SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, fill, 1, layer, angle, imgFile);
265 1194 : if (toFill.add(poly)) {
266 1194 : parCont.push_back(poly);
267 : }
268 1194 : }
269 1194 : break;
270 0 : case wkbMultiPoint:
271 : case wkbMultiPoint25D: {
272 : OGRMultiPoint* cgeom = (OGRMultiPoint*) poGeometry;
273 0 : for (int i = 0; i < cgeom->getNumGeometries(); ++i) {
274 : OGRPoint* cgeom2 = (OGRPoint*) cgeom->getGeometryRef(i);
275 : Position pos(cgeom2->getX(), cgeom2->getY());
276 0 : const std::string tid = id + "#" + toString(i);
277 0 : if (!geoConvHelper.x2cartesian(pos)) {
278 0 : WRITE_ERRORF(TL("Unable to project coordinates for POI '%'."), tid);
279 : }
280 0 : PointOfInterest* poi = new PointOfInterest(tid, type, color, pos, false, "", 0, false, 0, icon, layer, angle, imgFile);
281 0 : if (toFill.add(poi)) {
282 0 : parCont.push_back(poi);
283 : }
284 : }
285 : }
286 0 : break;
287 2 : case wkbMultiLineString:
288 : case wkbMultiLineString25D: {
289 : OGRMultiLineString* cgeom = (OGRMultiLineString*) poGeometry;
290 4 : for (int i = 0; i < cgeom->getNumGeometries(); ++i) {
291 4 : const std::string tid = id + "#" + toString(i);
292 2 : const PositionVector shape = toShape((OGRLineString*) cgeom->getGeometryRef(i), tid);
293 2 : SUMOPolygon* poly = new SUMOPolygon(tid, type, color, shape, false, fillType == 1, 1, layer, angle, imgFile);
294 2 : if (toFill.add(poly)) {
295 2 : parCont.push_back(poly);
296 : }
297 2 : }
298 : }
299 2 : break;
300 1 : case wkbMultiPolygon:
301 : case wkbMultiPolygon25D: {
302 1 : const bool fill = fillType < 0 || fillType == 1;
303 : OGRMultiPolygon* cgeom = (OGRMultiPolygon*) poGeometry;
304 3 : for (int i = 0; i < cgeom->getNumGeometries(); ++i) {
305 4 : const std::string tid = id + "#" + toString(i);
306 2 : const PositionVector shape = toShape(((OGRPolygon*) cgeom->getGeometryRef(i))->getExteriorRing(), tid);
307 2 : SUMOPolygon* poly = new SUMOPolygon(tid, type, color, shape, false, fill, 1, layer, angle, imgFile);
308 2 : if (toFill.add(poly)) {
309 2 : parCont.push_back(poly);
310 : }
311 2 : }
312 : }
313 1 : break;
314 0 : default:
315 0 : WRITE_WARNINGF(TL("Unsupported shape type occurred (id='%')."), id);
316 0 : break;
317 : }
318 2522 : if (oc.getBool("shapefile.add-param") || oc.getBool("all-attributes")) {
319 68 : for (std::vector<Parameterised*>::const_iterator it = parCont.begin(); it != parCont.end(); ++it) {
320 34 : OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
321 146 : for (int iField = 0; iField < poFDefn->GetFieldCount(); iField++) {
322 112 : OGRFieldDefn* poFieldDefn = poFDefn->GetFieldDefn(iField);
323 112 : if (poFieldDefn->GetNameRef() != idField) {
324 336 : (*it)->setParameter(poFieldDefn->GetNameRef(), StringUtils::latin1_to_utf8(poFeature->GetFieldAsString(iField)));
325 : }
326 : }
327 : }
328 : }
329 1261 : OGRFeature::DestroyFeature(poFeature);
330 1261 : }
331 : #if GDAL_VERSION_MAJOR < 2
332 : OGRDataSource::DestroyDataSource(poDS);
333 : #else
334 6 : GDALClose(poDS);
335 : #endif
336 6 : PROGRESS_DONE_MESSAGE();
337 : #else
338 : UNUSED_PARAMETER(file);
339 : UNUSED_PARAMETER(oc);
340 : UNUSED_PARAMETER(toFill);
341 : UNUSED_PARAMETER(tm);
342 : WRITE_ERROR(TL("SUMO was compiled without GDAL support."));
343 : #endif
344 12 : }
345 :
346 :
347 : /****************************************************************************/
|