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