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