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 NIImporter_ArcView.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Eric Nicolay
17 : /// @author Jakob Erdmann
18 : /// @author Thimor Bohn
19 : /// @author Michael Behrisch
20 : /// @date Sept 2002
21 : ///
22 : // Importer for networks stored in ArcView-shape format
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <string>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/ToString.h>
29 : #include <utils/common/StringUtils.h>
30 : #include <utils/common/StringUtils.h>
31 : #include <utils/options/OptionsCont.h>
32 : #include <utils/geom/GeomHelper.h>
33 : #include <netbuild/NBNetBuilder.h>
34 : #include <netbuild/NBHelpers.h>
35 : #include <netbuild/NBEdge.h>
36 : #include <netbuild/NBEdgeCont.h>
37 : #include <netbuild/NBTypeCont.h>
38 : #include <netbuild/NBNode.h>
39 : #include <netbuild/NBNodeCont.h>
40 : #include <netimport/NINavTeqHelper.h>
41 : #include <utils/geom/GeoConvHelper.h>
42 : #include <utils/common/FileHelpers.h>
43 : #include "NILoader.h"
44 : #include "NIImporter_ArcView.h"
45 :
46 : #ifdef HAVE_GDAL
47 : #ifdef _MSC_VER
48 : #pragma warning(push)
49 : #pragma warning(disable: 4435 5219 5220)
50 : #endif
51 : #if __GNUC__ > 3
52 : #pragma GCC diagnostic push
53 : #pragma GCC diagnostic ignored "-Wpedantic"
54 : #endif
55 : #include <gdal_version.h>
56 : #include <ogrsf_frmts.h>
57 : #if __GNUC__ > 3
58 : #pragma GCC diagnostic pop
59 : #endif
60 : #ifdef _MSC_VER
61 : #pragma warning(pop)
62 : #endif
63 : #endif
64 :
65 :
66 : // ===========================================================================
67 : // method definitions
68 : // ===========================================================================
69 : // ---------------------------------------------------------------------------
70 : // static methods (interface in this case)
71 : // ---------------------------------------------------------------------------
72 : void
73 2437 : NIImporter_ArcView::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
74 4874 : if (!oc.isSet("shapefile-prefix")) {
75 2435 : return;
76 : }
77 : // check whether the correct set of entries is given
78 : // and compute all file names
79 2 : const std::string dbf_file = oc.getString("shapefile-prefix") + ".dbf";
80 2 : const std::string shp_file = oc.getString("shapefile-prefix") + ".shp";
81 2 : const std::string shx_file = oc.getString("shapefile-prefix") + ".shx";
82 4 : if (!StringUtils::startsWith(shp_file, "/vsi")) {
83 : // if we are not using a virtual file system, check whether the files do exist
84 4 : if (!FileHelpers::isReadable(dbf_file)) {
85 0 : WRITE_ERROR("File not accessible: " + dbf_file);
86 : }
87 4 : if (!FileHelpers::isReadable(shp_file)) {
88 0 : WRITE_ERROR("File not accessible: " + shp_file);
89 : }
90 4 : if (!FileHelpers::isReadable(shx_file)) {
91 0 : WRITE_ERROR("File not accessible: " + shx_file);
92 : }
93 : }
94 2 : if (MsgHandler::getErrorInstance()->wasInformed()) {
95 : return;
96 : }
97 : // load the arcview files
98 : NIImporter_ArcView loader(oc, nb.getNodeCont(), nb.getEdgeCont(), nb.getTypeCont(),
99 2 : shp_file, oc.getBool("speed-in-kmh"));
100 2 : loader.load();
101 2 : }
102 :
103 :
104 :
105 : // ---------------------------------------------------------------------------
106 : // loader methods
107 : // ---------------------------------------------------------------------------
108 2 : NIImporter_ArcView::NIImporter_ArcView(const OptionsCont& oc,
109 : NBNodeCont& nc,
110 : NBEdgeCont& ec,
111 : NBTypeCont& tc,
112 : const std::string& shp_name,
113 2 : bool speedInKMH)
114 2 : : myOptions(oc), mySHPName(shp_name),
115 2 : myNameAddition(0),
116 2 : myNodeCont(nc), myEdgeCont(ec), myTypeCont(tc),
117 2 : mySpeedInKMH(speedInKMH),
118 2 : myRunningEdgeID(0),
119 2 : myRunningNodeID(0) {
120 2 : }
121 :
122 :
123 2 : NIImporter_ArcView::~NIImporter_ArcView() {}
124 :
125 :
126 : void
127 2 : NIImporter_ArcView::load() {
128 : #ifdef HAVE_GDAL
129 6 : PROGRESS_BEGIN_MESSAGE("Loading data from '" + mySHPName + "'");
130 : #if GDAL_VERSION_MAJOR < 2
131 : OGRRegisterAll();
132 : OGRDataSource* poDS = OGRSFDriverRegistrar::Open(mySHPName.c_str(), FALSE);
133 : #else
134 2 : GDALAllRegister();
135 2 : GDALDataset* poDS = (GDALDataset*)GDALOpenEx(mySHPName.c_str(), GDAL_OF_VECTOR | GA_ReadOnly, NULL, NULL, NULL);
136 : #endif
137 2 : if (poDS == NULL) {
138 0 : WRITE_ERRORF(TL("Could not open shape description '%'."), mySHPName);
139 0 : return;
140 : }
141 :
142 : // begin file parsing
143 2 : OGRLayer* poLayer = poDS->GetLayer(0);
144 2 : poLayer->ResetReading();
145 :
146 : // build coordinate transformation
147 : #if GDAL_VERSION_MAJOR < 3
148 : OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
149 : #else
150 2 : const OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
151 : #endif
152 2 : OGRSpatialReference destTransf;
153 : // use wgs84 as destination
154 2 : destTransf.SetWellKnownGeogCS("WGS84");
155 : #if GDAL_VERSION_MAJOR > 2
156 4 : if (myOptions.getBool("shapefile.traditional-axis-mapping") || origTransf != nullptr) {
157 0 : destTransf.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
158 : }
159 : #endif
160 2 : OGRCoordinateTransformation* poCT = origTransf == nullptr ? nullptr : OGRCreateCoordinateTransformation(origTransf, &destTransf);
161 0 : if (poCT == nullptr) {
162 4 : if (myOptions.getBool("shapefile.guess-projection")) {
163 0 : OGRSpatialReference origTransf2;
164 0 : origTransf2.SetWellKnownGeogCS("WGS84");
165 0 : poCT = OGRCreateCoordinateTransformation(&origTransf2, &destTransf);
166 0 : }
167 : }
168 :
169 2 : const bool saveOrigIDs = OptionsCont::getOptions().getBool("output.original-names");
170 : OGRFeature* poFeature;
171 2 : poLayer->ResetReading();
172 :
173 2 : const double nodeJoinDist = myOptions.getFloat("shapefile.node-join-dist");
174 2 : const std::vector<std::string> params = myOptions.getStringVector("shapefile.add-params");
175 :
176 : int featureIndex = 0;
177 : bool warnNotUnique = true;
178 : bool warnMissingProjection = true;
179 2 : std::string idPrefix = ""; // prefix for non-unique street-id values
180 : std::map<std::string, int> idIndex; // running index to make street-id unique
181 120 : while ((poFeature = poLayer->GetNextFeature()) != NULL) {
182 : // read in edge attributes
183 118 : if (featureIndex == 0) {
184 6 : WRITE_MESSAGE("Available fields: " + toString(getFieldNames(poFeature)));
185 : }
186 : std::string id;
187 : std::string name;
188 : std::string from_node;
189 : std::string to_node;
190 236 : if (!getStringEntry(poFeature, "shapefile.street-id", "LINK_ID", true, id)) {
191 0 : WRITE_ERRORF(TL("Needed field '%' (street-id) is missing."), id);
192 : id = "";
193 : }
194 118 : if (id == "") {
195 0 : id = toString(myRunningEdgeID++);
196 : }
197 :
198 118 : getStringEntry(poFeature, "shapefile.name", "ST_NAME", true, name);
199 354 : name = StringUtils::replace(name, "&", "&");
200 :
201 236 : if (!getStringEntry(poFeature, "shapefile.from-id", "REF_IN_ID", true, from_node)) {
202 0 : WRITE_ERRORF(TL("Needed field '%' (from node id) is missing."), from_node);
203 : from_node = "";
204 : }
205 236 : if (!getStringEntry(poFeature, "shapefile.to-id", "NREF_IN_ID", true, to_node)) {
206 0 : WRITE_ERRORF(TL("Needed field '%' (to node id) is missing."), to_node);
207 : to_node = "";
208 : }
209 :
210 118 : if (from_node == "" || to_node == "") {
211 118 : from_node = toString(myRunningNodeID++);
212 236 : to_node = toString(myRunningNodeID++);
213 : }
214 :
215 : std::string type;
216 118 : if (myOptions.isSet("shapefile.type-id") && poFeature->GetFieldIndex(myOptions.getString("shapefile.type-id").c_str()) >= 0) {
217 0 : type = poFeature->GetFieldAsString(myOptions.getString("shapefile.type-id").c_str());
218 118 : } else if (poFeature->GetFieldIndex("ST_TYP_AFT") >= 0) {
219 0 : type = poFeature->GetFieldAsString("ST_TYP_AFT");
220 : }
221 236 : if ((type != "" || myOptions.isSet("shapefile.type-id")) && !myTypeCont.knows(type)) {
222 0 : WRITE_WARNINGF(TL("Unknown type '%' for edge '%'"), type, id);
223 : }
224 118 : bool oneway = myTypeCont.knows(type) ? myTypeCont.getEdgeTypeIsOneWay(type) : false;
225 118 : double speed = getSpeed(*poFeature, id);
226 118 : int nolanes = getLaneNo(*poFeature, id, speed);
227 118 : int priority = getPriority(*poFeature, id);
228 118 : double width = getLaneWidth(*poFeature, id, nolanes);
229 118 : double length = getLength(*poFeature, id);
230 118 : if (nolanes <= 0 || speed <= 0) {
231 236 : if (myOptions.getBool("shapefile.use-defaults-on-failure")) {
232 118 : nolanes = nolanes <= 0 ? myTypeCont.getEdgeTypeNumLanes(type) : nolanes;
233 118 : speed = speed <= 0 ? myTypeCont.getEdgeTypeSpeed(type) : speed;
234 : } else {
235 0 : const std::string lanesField = myOptions.isSet("shapefile.laneNumber") ? myOptions.getString("shapefile.laneNumber") : "nolanes";
236 0 : const std::string speedField = myOptions.isSet("shapefile.speed") ? myOptions.getString("shapefile.speed") : "speed";
237 0 : WRITE_ERRORF(TL("Required field '%' or '%' is missing (add fields or set option --shapefile.use-defaults-on-failure)."), lanesField, speedField);
238 0 : WRITE_ERROR("Available fields: " + toString(getFieldNames(poFeature)));
239 0 : OGRFeature::DestroyFeature(poFeature);
240 : return;
241 : }
242 : }
243 118 : if (mySpeedInKMH) {
244 0 : speed /= 3.6;
245 : }
246 :
247 :
248 : // read in the geometry
249 118 : OGRGeometry* poGeometry = poFeature->GetGeometryRef();
250 118 : OGRwkbGeometryType gtype = poGeometry->getGeometryType();
251 118 : if (gtype != wkbLineString && gtype != wkbLineString25D) {
252 0 : OGRFeature::DestroyFeature(poFeature);
253 0 : WRITE_ERRORF(TL("Road geometry must be of type 'linestring' or 'linestring25D' (found '%')"), toString(gtype));
254 0 : return;
255 : }
256 : OGRLineString* cgeom = (OGRLineString*) poGeometry;
257 118 : if (poCT == nullptr && warnMissingProjection) {
258 : int outOfRange = 0;
259 13 : for (int j = 0; j < cgeom->getNumPoints(); j++) {
260 11 : if (fabs(cgeom->getX(j)) > 180 || fabs(cgeom->getY(j)) > 90) {
261 5 : outOfRange++;
262 : }
263 : }
264 2 : if (2 * outOfRange > cgeom->getNumPoints()) {
265 1 : WRITE_WARNING(TL("No coordinate system found and coordinates look already projected."));
266 2 : GeoConvHelper::init("!", GeoConvHelper::getProcessing().getOffset(), GeoConvHelper::getProcessing().getOrigBoundary(), GeoConvHelper::getProcessing().getConvBoundary());
267 : } else {
268 2 : WRITE_WARNING(TL("Could not find geo coordinate system, assuming WGS84."));
269 : }
270 : warnMissingProjection = false;
271 : }
272 118 : if (poCT != nullptr) {
273 : // try transform to wgs84
274 0 : cgeom->transform(poCT);
275 : }
276 :
277 118 : PositionVector shape;
278 496 : for (int j = 0; j < cgeom->getNumPoints(); j++) {
279 378 : Position pos(cgeom->getX(j), cgeom->getY(j), cgeom->getZ(j));
280 378 : if (!NBNetBuilder::transformCoordinate(pos)) {
281 0 : WRITE_WARNINGF(TL("Unable to project coordinates for edge '%'."), id);
282 : }
283 378 : shape.push_back_noDoublePos(pos);
284 : }
285 :
286 : // build from-node
287 118 : NBNode* from = myNodeCont.retrieve(from_node);
288 118 : if (from == nullptr) {
289 118 : Position from_pos = shape[0];
290 118 : std::vector<NBNode*> cands = myNodeCont.retrieveByPos(from_pos, nodeJoinDist);
291 118 : if (!cands.empty()) {
292 39 : from = cands.front();
293 : }
294 118 : if (from == nullptr) {
295 79 : from = new NBNode(from_node, from_pos);
296 79 : if (!myNodeCont.insert(from)) {
297 0 : WRITE_ERRORF(TL("Node '%' could not be added"), from_node);
298 0 : delete from;
299 : continue;
300 : }
301 : }
302 118 : }
303 : // build to-node
304 118 : NBNode* to = myNodeCont.retrieve(to_node);
305 118 : if (to == nullptr) {
306 118 : Position to_pos = shape[-1];
307 118 : std::vector<NBNode*> cands = myNodeCont.retrieveByPos(to_pos, nodeJoinDist);
308 118 : if (!cands.empty()) {
309 39 : to = cands.front();
310 : }
311 118 : if (to == nullptr) {
312 79 : to = new NBNode(to_node, to_pos);
313 79 : if (!myNodeCont.insert(to)) {
314 0 : WRITE_ERRORF(TL("Node '%' could not be added"), to_node);
315 0 : delete to;
316 : continue;
317 : }
318 : }
319 118 : }
320 :
321 118 : if (from == to) {
322 3 : WRITE_WARNINGF(TL("Edge '%' connects identical nodes, skipping."), id);
323 1 : continue;
324 : }
325 :
326 : // retrieve the information whether the street is bi-directional
327 : std::string dir;
328 117 : int index = poFeature->GetDefnRef()->GetFieldIndex("DIR_TRAVEL");
329 117 : if (index >= 0 && poFeature->IsFieldSet(index)) {
330 0 : dir = poFeature->GetFieldAsString(index);
331 : }
332 117 : const std::string origID = saveOrigIDs ? id : "";
333 : // check for duplicate ids
334 117 : NBEdge* const existing = myEdgeCont.retrieve(id);
335 117 : NBEdge* const existingReverse = myEdgeCont.retrieve("-" + id);
336 117 : if (existing != nullptr || existingReverse != nullptr) {
337 0 : if ((existing != nullptr && existing->getGeometry() == shape)
338 0 : || (existingReverse != nullptr && existingReverse->getGeometry() == shape.reverse())) {
339 0 : WRITE_ERRORF(TL("Edge '%' is not unique."), (existing != nullptr ? id : existingReverse->getID()));
340 : } else {
341 : if (idIndex.count(id) == 0) {
342 0 : idIndex[id] = 0;
343 : }
344 0 : idIndex[id]++;
345 : idPrefix = id;
346 0 : id += "#" + toString(idIndex[id]);
347 0 : if (warnNotUnique) {
348 0 : WRITE_WARNINGF(TL("Edge '%' is not unique. Renaming subsequent edge to '%'."), idPrefix, id);
349 : warnNotUnique = false;
350 : }
351 : }
352 : }
353 : // add positive direction if wanted
354 117 : if (dir == "B" || dir == "F" || dir == "" || myOptions.getBool("shapefile.all-bidirectional")) {
355 117 : if (myEdgeCont.retrieve(id) == 0) {
356 117 : LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LaneSpreadFunction::RIGHT : LaneSpreadFunction::CENTER;
357 117 : if (spread == LaneSpreadFunction::RIGHT && OptionsCont::getOptions().getString("default.spreadtype") == toString(LaneSpreadFunction::ROADCENTER)) {
358 : spread = LaneSpreadFunction::ROADCENTER;
359 : }
360 468 : NBEdge* edge = new NBEdge(id, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape, spread, name, origID);
361 117 : edge->setPermissions(myTypeCont.getEdgeTypePermissions(type));
362 117 : edge->setLoadedLength(length);
363 117 : myEdgeCont.insert(edge);
364 117 : checkSpread(edge);
365 117 : addParams(edge, poFeature, params);
366 : } else {
367 0 : WRITE_ERRORF(TL("Could not create edge '%'. An edge with the same id already exists."), id);
368 : }
369 : }
370 : // add negative direction if wanted
371 234 : if ((dir == "B" || dir == "T" || myOptions.getBool("shapefile.all-bidirectional")) && !oneway) {
372 0 : if (myEdgeCont.retrieve("-" + id) == 0) {
373 0 : LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LaneSpreadFunction::RIGHT : LaneSpreadFunction::CENTER;
374 0 : if (spread == LaneSpreadFunction::RIGHT && OptionsCont::getOptions().getString("default.spreadtype") == toString(LaneSpreadFunction::ROADCENTER)) {
375 : spread = LaneSpreadFunction::ROADCENTER;
376 : }
377 0 : NBEdge* edge = new NBEdge("-" + id, to, from, type, speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), spread, name, origID);
378 0 : edge->setPermissions(myTypeCont.getEdgeTypePermissions(type));
379 0 : edge->setLoadedLength(length);
380 0 : myEdgeCont.insert(edge);
381 0 : checkSpread(edge);
382 0 : addParams(edge, poFeature, params);
383 : } else {
384 0 : WRITE_ERRORF(TL("Could not create edge '-%'. An edge with the same id already exists."), id);
385 : }
386 : }
387 : //
388 117 : OGRFeature::DestroyFeature(poFeature);
389 117 : featureIndex++;
390 118 : }
391 : #if GDAL_VERSION_MAJOR < 2
392 : OGRDataSource::DestroyDataSource(poDS);
393 : #else
394 2 : GDALClose(poDS);
395 : #endif
396 2 : PROGRESS_DONE_MESSAGE();
397 : #else
398 : WRITE_ERROR(TL("SUMO was compiled without GDAL support."));
399 : #endif
400 2 : }
401 :
402 : #ifdef HAVE_GDAL
403 : double
404 118 : NIImporter_ArcView::getSpeed(OGRFeature& poFeature, const std::string& edgeid) {
405 236 : if (myOptions.isSet("shapefile.speed")) {
406 0 : int index = poFeature.GetDefnRef()->GetFieldIndex(myOptions.getString("shapefile.speed").c_str());
407 0 : if (index >= 0 && poFeature.IsFieldSet(index)) {
408 0 : const double speed = poFeature.GetFieldAsDouble(index);
409 0 : if (speed <= 0) {
410 0 : WRITE_WARNING("invalid value for field: '"
411 : + myOptions.getString("shapefile.speed")
412 : + "': '" + std::string(poFeature.GetFieldAsString(index)) + "'");
413 : } else {
414 : return speed;
415 : }
416 : }
417 : }
418 236 : if (myOptions.isSet("shapefile.type-id")) {
419 0 : return myTypeCont.getEdgeTypeSpeed(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
420 : }
421 : // try to get definitions as to be found in SUMO-XML-definitions
422 : // idea by John Michael Calandrino
423 118 : int index = poFeature.GetDefnRef()->GetFieldIndex("speed");
424 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
425 0 : return (double) poFeature.GetFieldAsDouble(index);
426 : }
427 118 : index = poFeature.GetDefnRef()->GetFieldIndex("SPEED");
428 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
429 0 : return (double) poFeature.GetFieldAsDouble(index);
430 : }
431 : // try to get the NavTech-information
432 118 : index = poFeature.GetDefnRef()->GetFieldIndex("SPEED_CAT");
433 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
434 0 : std::string def = poFeature.GetFieldAsString(index);
435 0 : return NINavTeqHelper::getSpeed(edgeid, def);
436 : }
437 : return -1;
438 : }
439 :
440 :
441 : double
442 118 : NIImporter_ArcView::getLaneWidth(OGRFeature& poFeature, const std::string& edgeid, int laneNumber) {
443 236 : if (myOptions.isSet("shapefile.width")) {
444 0 : int index = poFeature.GetDefnRef()->GetFieldIndex(myOptions.getString("shapefile.width").c_str());
445 0 : if (index >= 0 && poFeature.IsFieldSet(index)) {
446 0 : const double width = poFeature.GetFieldAsDouble(index);
447 0 : if (width <= 0) {
448 0 : WRITE_WARNING("invalid value for field: '"
449 : + myOptions.getString("shapefile.width")
450 : + "' of edge '" + edgeid
451 : + "': '" + std::string(poFeature.GetFieldAsString(index)) + "'");
452 : } else {
453 0 : return width / laneNumber;
454 : }
455 : }
456 : }
457 236 : if (myOptions.isSet("shapefile.type-id")) {
458 0 : return myTypeCont.getEdgeTypeWidth(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
459 : }
460 118 : return NBEdge::UNSPECIFIED_WIDTH;
461 : }
462 :
463 :
464 :
465 : double
466 118 : NIImporter_ArcView::getLength(OGRFeature& poFeature, const std::string& edgeid) {
467 236 : if (myOptions.isSet("shapefile.length")) {
468 0 : int index = poFeature.GetDefnRef()->GetFieldIndex(myOptions.getString("shapefile.length").c_str());
469 0 : if (index >= 0 && poFeature.IsFieldSet(index)) {
470 0 : const double length = poFeature.GetFieldAsDouble(index);
471 0 : if (length <= 0) {
472 0 : WRITE_WARNING("invalid value for field: '"
473 : + myOptions.getString("shapefile.length")
474 : + "' of edge '" + edgeid
475 : + "': '" + std::string(poFeature.GetFieldAsString(index)) + "'");
476 : } else {
477 : return length;
478 : }
479 : }
480 : }
481 118 : return NBEdge::UNSPECIFIED_LOADED_LENGTH;
482 : }
483 :
484 :
485 : int
486 118 : NIImporter_ArcView::getLaneNo(OGRFeature& poFeature, const std::string& edgeid,
487 : double speed) {
488 236 : if (myOptions.isSet("shapefile.laneNumber")) {
489 0 : int index = poFeature.GetDefnRef()->GetFieldIndex(myOptions.getString("shapefile.laneNumber").c_str());
490 0 : if (index >= 0 && poFeature.IsFieldSet(index)) {
491 0 : const int laneNumber = poFeature.GetFieldAsInteger(index);
492 0 : if (laneNumber <= 0) {
493 0 : WRITE_WARNING("invalid value for field '"
494 : + myOptions.getString("shapefile.laneNumber")
495 : + "': '" + std::string(poFeature.GetFieldAsString(index)) + "'");
496 : } else {
497 : return laneNumber;
498 : }
499 : }
500 : }
501 236 : if (myOptions.isSet("shapefile.type-id")) {
502 0 : return (int) myTypeCont.getEdgeTypeNumLanes(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
503 : }
504 : // try to get definitions as to be found in SUMO-XML-definitions
505 : // idea by John Michael Calandrino
506 118 : int index = poFeature.GetDefnRef()->GetFieldIndex("nolanes");
507 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
508 0 : return (int) poFeature.GetFieldAsInteger(index);
509 : }
510 118 : index = poFeature.GetDefnRef()->GetFieldIndex("NOLANES");
511 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
512 0 : return (int) poFeature.GetFieldAsInteger(index);
513 : }
514 118 : index = poFeature.GetDefnRef()->GetFieldIndex("rnol");
515 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
516 0 : return (int) poFeature.GetFieldAsInteger(index);
517 : }
518 118 : index = poFeature.GetDefnRef()->GetFieldIndex("LANE_CAT");
519 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
520 0 : std::string def = poFeature.GetFieldAsString(index);
521 0 : return NINavTeqHelper::getLaneNumber(edgeid, def, speed);
522 : }
523 : return 0;
524 : }
525 :
526 :
527 : int
528 118 : NIImporter_ArcView::getPriority(OGRFeature& poFeature, const std::string& /*edgeid*/) {
529 236 : if (myOptions.isSet("shapefile.type-id")) {
530 0 : return myTypeCont.getEdgeTypePriority(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
531 : }
532 : // try to get definitions as to be found in SUMO-XML-definitions
533 : // idea by John Michael Calandrino
534 118 : int index = poFeature.GetDefnRef()->GetFieldIndex("priority");
535 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
536 0 : return poFeature.GetFieldAsInteger(index);
537 : }
538 118 : index = poFeature.GetDefnRef()->GetFieldIndex("PRIORITY");
539 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
540 0 : return poFeature.GetFieldAsInteger(index);
541 : }
542 : // try to determine priority from NavTechs FUNC_CLASS attribute
543 118 : index = poFeature.GetDefnRef()->GetFieldIndex("FUNC_CLASS");
544 118 : if (index >= 0 && poFeature.IsFieldSet(index)) {
545 0 : return poFeature.GetFieldAsInteger(index);
546 : }
547 : return 0;
548 : }
549 :
550 : void
551 117 : NIImporter_ArcView::checkSpread(NBEdge* e) {
552 117 : NBEdge* ret = e->getToNode()->getConnectionTo(e->getFromNode());
553 117 : if (ret != 0) {
554 0 : e->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
555 0 : ret->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
556 : }
557 117 : }
558 :
559 : bool
560 472 : NIImporter_ArcView::getStringEntry(OGRFeature* poFeature, const std::string& optionName, const char* defaultName, bool prune, std::string& into) {
561 472 : std::string v(defaultName);
562 472 : if (myOptions.isSet(optionName)) {
563 236 : v = myOptions.getString(optionName);
564 : }
565 472 : if (poFeature->GetFieldIndex(v.c_str()) < 0) {
566 354 : if (myOptions.isSet(optionName)) {
567 : into = v;
568 : return false;
569 : }
570 : into = "";
571 : return true;
572 : }
573 118 : into = poFeature->GetFieldAsString((char*)v.c_str());
574 118 : if (prune) {
575 236 : into = StringUtils::prune(into);
576 : }
577 : return true;
578 : }
579 :
580 : std::vector<std::string>
581 2 : NIImporter_ArcView::getFieldNames(OGRFeature* poFeature) const {
582 : std::vector<std::string> fields;
583 12 : for (int i = 0; i < poFeature->GetFieldCount(); i++) {
584 16 : fields.push_back(poFeature->GetFieldDefnRef(i)->GetNameRef());
585 : }
586 2 : return fields;
587 0 : }
588 :
589 : void
590 117 : NIImporter_ArcView::addParams(NBEdge* edge, OGRFeature* poFeature, const std::vector<std::string>& params) const {
591 117 : for (const std::string& p : params) {
592 0 : int index = poFeature->GetDefnRef()->GetFieldIndex(p.c_str());
593 0 : if (index >= 0 && poFeature->IsFieldSet(index)) {
594 0 : edge->setParameter(p, poFeature->GetFieldAsString(index));
595 : }
596 : }
597 117 : }
598 :
599 : #endif
600 :
601 :
602 : /****************************************************************************/
|