Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2008-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 PCLoaderOSM.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Christoph Sommer
18 : /// @author Michael Behrisch
19 : /// @author Melanie Knocke
20 : /// @date Wed, 19.11.2008
21 : ///
22 : // A reader of pois and polygons stored in OSM-format
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <string>
27 : #include <map>
28 : #include <fstream>
29 : #include <utils/common/UtilExceptions.h>
30 : #include <utils/common/MsgHandler.h>
31 : #include <utils/common/ToString.h>
32 : #include <utils/common/StringUtils.h>
33 : #include <utils/common/StdDefs.h>
34 : #include <utils/common/SysUtils.h>
35 : #include <utils/common/RGBColor.h>
36 : #include <utils/geom/GeomHelper.h>
37 : #include <utils/geom/Position.h>
38 : #include <utils/geom/GeoConvHelper.h>
39 : #include <utils/xml/XMLSubSys.h>
40 : #include <utils/geom/GeomConvHelper.h>
41 : #include <utils/common/FileHelpers.h>
42 : #include <utils/options/OptionsCont.h>
43 : #include <utils/options/Option.h>
44 : #include <polyconvert/PCPolyContainer.h>
45 : #include "PCLoaderOSM.h"
46 :
47 : // static members
48 : // ---------------------------------------------------------------------------
49 : const std::set<std::string> PCLoaderOSM::MyKeysToInclude(PCLoaderOSM::initMyKeysToInclude());
50 :
51 : // ===========================================================================
52 : // method definitions
53 : // ===========================================================================
54 : // ---------------------------------------------------------------------------
55 : // static interface
56 : // ---------------------------------------------------------------------------
57 52 : std::set<std::string> PCLoaderOSM::initMyKeysToInclude() {
58 : std::set<std::string> result;
59 52 : result.insert("highway");
60 52 : result.insert("railway");
61 52 : result.insert("railway:position");
62 52 : result.insert("railway:position:exact");
63 52 : result.insert("waterway");
64 52 : result.insert("aeroway");
65 52 : result.insert("aerialway");
66 52 : result.insert("power");
67 52 : result.insert("man_made");
68 52 : result.insert("building");
69 52 : result.insert("leisure");
70 52 : result.insert("amenity");
71 52 : result.insert("shop");
72 52 : result.insert("tourism");
73 52 : result.insert("historic");
74 52 : result.insert("landuse");
75 52 : result.insert("natural");
76 52 : result.insert("military");
77 52 : result.insert("boundary");
78 52 : result.insert("admin_level");
79 52 : result.insert("sport");
80 52 : result.insert("polygon");
81 52 : result.insert("place");
82 52 : result.insert("population");
83 52 : result.insert("barrier");
84 52 : result.insert("openGeoDB:population");
85 52 : result.insert("openGeoDB:name");
86 52 : return result;
87 : }
88 :
89 : void
90 45 : PCLoaderOSM::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
91 90 : if (!oc.isSet("osm-files")) {
92 22 : return;
93 : }
94 : // parse file(s)
95 46 : std::vector<std::string> files = oc.getStringVector("osm-files");
96 : // load nodes, first
97 : std::map<long long int, PCOSMNode*> nodes;
98 23 : bool withAttributes = oc.getBool("all-attributes");
99 24 : MsgHandler* m = OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance();
100 23 : NodesHandler nodesHandler(nodes, withAttributes, *m);
101 45 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
102 : // nodes
103 46 : if (!FileHelpers::isReadable(*file)) {
104 0 : WRITE_ERRORF(TL("Could not open osm-file '%'."), *file);
105 : return;
106 : }
107 69 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
108 23 : if (!XMLSubSys::runParser(nodesHandler, *file)) {
109 6 : for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
110 10 : delete (*i).second;
111 : }
112 1 : throw ProcessError();
113 : }
114 22 : PROGRESS_TIME_MESSAGE(before);
115 : }
116 : // load relations to see which additional ways may be relevant
117 22 : Relations relations;
118 : RelationsMap additionalWays;
119 : std::set<long long int> innerEdges;
120 22 : RelationsHandler relationsHandler(additionalWays, relations, innerEdges, withAttributes, *m);
121 44 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
122 : // edges
123 66 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing relations from osm-file '" + *file + "'");
124 22 : XMLSubSys::runParser(relationsHandler, *file);
125 22 : PROGRESS_TIME_MESSAGE(before);
126 : }
127 :
128 : // load ways
129 : EdgeMap edges;
130 22 : EdgesHandler edgesHandler(nodes, edges, additionalWays, withAttributes, *m);
131 44 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
132 : // edges
133 66 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing edges from osm-file '" + *file + "'");
134 22 : XMLSubSys::runParser(edgesHandler, *file);
135 22 : PROGRESS_TIME_MESSAGE(before);
136 : }
137 :
138 : // build all
139 22 : const bool useName = oc.getBool("osm.use-name");
140 22 : const double mergeRelationsThreshold = OptionsCont::getOptions().getFloat("osm.merge-relations");
141 : // create polygons from relations
142 22 : if (mergeRelationsThreshold >= 0) {
143 458 : for (PCOSMRelation* rel : relations) {
144 454 : if (!rel->keep || rel->myWays.empty()) {
145 313 : continue;
146 : }
147 : // filter unknown and empty ways
148 : int numNodes = 0;
149 2304 : for (auto it = rel->myWays.begin(); it != rel->myWays.end();) {
150 487 : if (edges.count(*it) == 0 || edges[*it]->myCurrentNodes.empty()) {
151 1669 : it = rel->myWays.erase(it);
152 : } else if (innerEdges.count(*it) > 0) {
153 : // @note: it would be a good idea to merge inner shapes but
154 : // it's difficult since there may be more than one
155 : // independent inner shape
156 271 : edges[*it]->standalone = true;
157 271 : it = rel->myWays.erase(it);
158 : } else {
159 216 : numNodes += (int)edges[*it]->myCurrentNodes.size();
160 : it++;
161 : }
162 : }
163 148 : if (numNodes == 0) {
164 7 : WRITE_WARNINGF(TL("Could not import polygon from relation '%' (missing ways)"), rel->id);
165 7 : continue;
166 : }
167 141 : PCOSMEdge* e = new PCOSMEdge();
168 141 : e->id = rel->id;
169 141 : e->name = rel->name;
170 : e->myAttributes = rel->myAttributes;
171 141 : e->myIsClosed = false;
172 141 : e->standalone = true;
173 :
174 141 : std::vector<std::vector<long long int> > snippets;
175 357 : for (const long long int wayID : rel->myWays) {
176 216 : PCOSMEdge* edge = edges[wayID];
177 216 : snippets.push_back(edge->myCurrentNodes);
178 : }
179 : double maxDist = 0.;
180 : bool ok = true;
181 214 : while (snippets.size() > 1) {
182 75 : maxDist = MAX2(maxDist, mergeClosest(nodes, snippets));
183 75 : if (maxDist > mergeRelationsThreshold) {
184 : ok = false;
185 : break;
186 : }
187 : }
188 141 : if (ok) {
189 139 : e->myCurrentNodes = snippets.front();
190 139 : edges[e->id] = e;
191 : double frontBackDist = 0;
192 139 : if (e->myCurrentNodes.front() != e->myCurrentNodes.back()) {
193 : // should be filled
194 9 : const Position posFront = convertNodePosition(nodes[e->myCurrentNodes.front()]);
195 9 : const Position posBack = convertNodePosition(nodes[e->myCurrentNodes.back()]);
196 : frontBackDist = posFront.distanceTo2D(posBack);
197 9 : if (frontBackDist < mergeRelationsThreshold) {
198 0 : e->myCurrentNodes.push_back(e->myCurrentNodes.front());
199 : frontBackDist = 0;
200 : }
201 : }
202 139 : std::string frontBackMsg = "";
203 139 : if (frontBackDist > 0) {
204 18 : frontBackMsg = TLF(", (front-to-back dist: %)", frontBackDist);
205 : }
206 417 : WRITE_MESSAGEF(TL("Assembled polygon from relation '%' (name:%)%"), toString(rel->id), e->name, frontBackMsg);
207 : } else {
208 6 : WRITE_WARNINGF(TL("Could not import polygon from relation '%' (name:% reason: found gap of %m)."), rel->id, rel->name, maxDist)
209 2 : delete e;
210 : // export ways by themselves
211 10 : for (long long int wayID : rel->myWays) {
212 8 : PCOSMEdge* part = edges[wayID];
213 8 : part->standalone = true;
214 : }
215 : }
216 141 : }
217 : }
218 :
219 : // instantiate polygons
220 5168 : for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
221 5146 : PCOSMEdge* e = (*i).second;
222 5146 : if (e->myAttributes.size() == 0) {
223 : // cannot be relevant as a polygon
224 169 : continue;
225 : }
226 5146 : if (!e->standalone && mergeRelationsThreshold >= 0) {
227 : // part of a relation
228 167 : continue;
229 : }
230 4979 : if (e->myCurrentNodes.size() == 0) {
231 4 : WRITE_WARNINGF(TL("Polygon '%' has no shape."), toString(e->id));
232 2 : continue;
233 : }
234 : // compute shape
235 4977 : PositionVector vec;
236 52576 : for (std::vector<long long int>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
237 47599 : PCOSMNode* n = nodes.find(*j)->second;
238 47599 : Position pos(n->lon, n->lat);
239 47599 : if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
240 0 : WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), e->id);
241 : }
242 47599 : vec.push_back_noDoublePos(pos);
243 : }
244 9954 : const bool ignorePruning = OptionsCont::getOptions().isInStringVector("prune.keep-list", toString(e->id));
245 : // add as many polygons as keys match defined types
246 : int index = 0;
247 4977 : std::string unknownPolyType = "";
248 10051 : bool isInner = mergeRelationsThreshold >= 0 && innerEdges.count(e->id) != 0 && tm.has("inner");
249 30991 : for (std::map<std::string, std::string>::iterator it = e->myAttributes.begin(); it != e->myAttributes.end(); ++it) {
250 26014 : const std::string& key = it->first;
251 : const std::string& value = it->second;
252 26014 : const std::string fullType = key + "." + value;
253 78042 : if (tm.has(key + "." + value)) {
254 494 : auto def = tm.get(isInner ? "inner" : fullType);
255 252 : index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
256 26014 : } else if (tm.has(key)) {
257 9656 : auto def = tm.get(isInner ? "inner" : key);
258 5024 : index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
259 5024 : } else if (MyKeysToInclude.count(key) > 0) {
260 : unknownPolyType = fullType;
261 : }
262 : }
263 : const PCTypeMap::TypeDef& def = tm.getDefault();
264 4977 : if (index == 0 && !def.discard && unknownPolyType != "") {
265 11 : addPolygon(e, vec, def, unknownPolyType, index, useName, toFill, ignorePruning, withAttributes);
266 : }
267 4977 : }
268 :
269 :
270 : // instantiate pois
271 41735 : for (std::map<long long int, PCOSMNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) {
272 41713 : PCOSMNode* n = (*i).second;
273 41713 : if (n->myAttributes.size() == 0) {
274 : // cannot be relevant as a poi
275 34695 : continue;
276 : }
277 7018 : Position pos(n->lon, n->lat);
278 7018 : if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
279 0 : WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), n->id);
280 : }
281 14036 : const bool ignorePruning = OptionsCont::getOptions().isInStringVector("prune.keep-list", toString(n->id));
282 : // add as many POIs as keys match defined types
283 : int index = 0;
284 7018 : std::string unKnownPOIType = "";
285 40978 : for (std::map<std::string, std::string>::iterator it = n->myAttributes.begin(); it != n->myAttributes.end(); ++it) {
286 33960 : const std::string& key = it->first;
287 : const std::string& value = it->second;
288 33960 : const std::string fullType = key + "." + value;
289 101880 : if (tm.has(key + "." + value)) {
290 44 : index = addPOI(n, pos, tm.get(fullType), fullType, index, useName, toFill, ignorePruning, withAttributes);
291 33916 : } else if (tm.has(key)) {
292 3780 : index = addPOI(n, pos, tm.get(key), fullType, index, useName, toFill, ignorePruning, withAttributes);
293 : } else if (MyKeysToInclude.count(key) > 0) {
294 : unKnownPOIType = fullType;
295 : }
296 : }
297 : const PCTypeMap::TypeDef& def = tm.getDefault();
298 7018 : if (index == 0 && !def.discard && unKnownPOIType != "") {
299 0 : addPOI(n, pos, def, unKnownPOIType, index, useName, toFill, ignorePruning, withAttributes);
300 : }
301 : }
302 : // delete nodes
303 41735 : for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
304 83426 : delete (*i).second;
305 : }
306 : // delete edges
307 5168 : for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
308 5146 : delete (*i).second;
309 : }
310 : // delete relations
311 511 : for (Relations::iterator i = relations.begin(); i != relations.end(); ++i) {
312 489 : delete (*i);
313 : }
314 46 : }
315 :
316 :
317 : Position
318 0 : PCLoaderOSM::convertNodePosition(PCOSMNode* n) {
319 18 : Position pos(n->lon, n->lat);
320 29458 : GeoConvHelper::getProcessing().x2cartesian(pos);
321 18 : return pos;
322 : }
323 :
324 :
325 : double
326 2486 : PCLoaderOSM::parseHeight(const std::map<std::string, std::string>& attrs, long long int id) {
327 4972 : auto itH = attrs.find("height");
328 2486 : if (itH != attrs.end()) {
329 : try {
330 82 : return StringUtils::parseDist(itH->second);
331 0 : } catch (...) {
332 0 : WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in way '%'."), "height", itH->second, id);
333 0 : }
334 : }
335 2404 : return SUMOPolygon::DEFAULT_HEIGHT;
336 : }
337 :
338 :
339 : int
340 5287 : PCLoaderOSM::addPolygon(const PCOSMEdge* edge, const PositionVector& vec, const PCTypeMap::TypeDef& def, const std::string& fullType, int index, bool useName, PCPolyContainer& toFill, bool ignorePruning, bool withAttributes) {
341 5287 : if (def.discard) {
342 2801 : return index;
343 : } else {
344 : const bool closedShape = vec.front() == vec.back();
345 2486 : const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
346 2486 : const std::string id = def.prefix + (useName && edge->name != "" ? edge->name : toString(edge->id)) + idSuffix;
347 2486 : bool fill = def.allowFill == PCTypeMap::Filltype::FORCE || (def.allowFill == PCTypeMap::Filltype::FILL && closedShape);
348 : SUMOPolygon* poly = new SUMOPolygon(
349 4972 : StringUtils::escapeXML(id),
350 2486 : StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
351 2486 : def.color, vec, false, fill, 1, def.layer,
352 : SUMOPolygon::DEFAULT_ANGLE,
353 : SUMOPolygon::DEFAULT_IMG_FILE,
354 : SUMOPolygon::DEFAULT_NAME,
355 4972 : parseHeight(edge->myAttributes, edge->id));
356 2486 : if (withAttributes) {
357 71 : poly->updateParameters(edge->myAttributes);
358 : }
359 2486 : if (!toFill.add(poly, ignorePruning)) {
360 : return index;
361 : } else {
362 2486 : return index + 1;
363 : }
364 : }
365 : }
366 :
367 :
368 : int
369 3824 : PCLoaderOSM::addPOI(const PCOSMNode* node, const Position& pos, const PCTypeMap::TypeDef& def, const std::string& fullType,
370 : int index, bool useName, PCPolyContainer& toFill, bool ignorePruning, bool withAttributes) {
371 3824 : if (def.discard) {
372 1038 : return index;
373 : } else {
374 2786 : const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
375 2786 : const std::string id = def.prefix + (useName && node->name != "" ? node->name : toString(node->id)) + idSuffix;
376 : PointOfInterest* poi = new PointOfInterest(
377 5572 : StringUtils::escapeXML(id),
378 5572 : StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
379 5572 : def.color, pos, false, "", 0, false, 0, def.icon, def.layer);
380 2786 : if (withAttributes) {
381 44 : poi->updateParameters(node->myAttributes);
382 : }
383 2786 : if (!toFill.add(poi, ignorePruning)) {
384 : return index;
385 : } else {
386 2782 : return index + 1;
387 : }
388 : }
389 : }
390 :
391 :
392 : // ---------------------------------------------------------------------------
393 : // definitions of PCLoaderOSM::NodesHandler-methods
394 : // ---------------------------------------------------------------------------
395 23 : PCLoaderOSM::NodesHandler::NodesHandler(std::map<long long int, PCOSMNode*>& toFill,
396 23 : bool withAttributes, MsgHandler& errorHandler) :
397 23 : SUMOSAXHandler("osm - file"), myWithAttributes(withAttributes), myErrorHandler(errorHandler),
398 46 : myToFill(toFill), myLastNodeID(-1) {}
399 :
400 :
401 23 : PCLoaderOSM::NodesHandler::~NodesHandler() {}
402 :
403 :
404 : void
405 213660 : PCLoaderOSM::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
406 213660 : myParentElements.push_back(element);
407 213660 : if (element == SUMO_TAG_NODE) {
408 41718 : bool ok = true;
409 41718 : long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
410 41718 : if (!ok) {
411 0 : return;
412 : }
413 41718 : myLastNodeID = -1;
414 83436 : if (myToFill.find(id) == myToFill.end()) {
415 41718 : myLastNodeID = id;
416 : // assume we are loading multiple files...
417 : // ... so we won't report duplicate nodes
418 41718 : PCOSMNode* toAdd = new PCOSMNode();
419 41718 : toAdd->id = id;
420 41718 : toAdd->lon = attrs.get<double>(SUMO_ATTR_LON, toString(id).c_str(), ok);
421 41718 : toAdd->lat = attrs.get<double>(SUMO_ATTR_LAT, toString(id).c_str(), ok);
422 41718 : if (!ok) {
423 0 : delete toAdd;
424 0 : return;
425 : }
426 41718 : myToFill[toAdd->id] = toAdd;
427 : }
428 : }
429 63181 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_NODE
430 247625 : && myLastNodeID != -1) {
431 33965 : bool ok = true;
432 67930 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, "", false);
433 67930 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "", false);
434 33965 : if (key == "name") {
435 1770 : myToFill[myLastNodeID]->name = value;
436 32195 : } else if (key == "") {
437 4 : myErrorHandler.inform("Empty key in a a tag while parsing node '" + toString(myLastNodeID) + "' occurred.");
438 2 : ok = false;
439 : }
440 33965 : if (!ok) {
441 : return;
442 : }
443 33963 : myToFill[myLastNodeID]->myAttributes[key] = value;
444 : }
445 : }
446 :
447 :
448 : void
449 213660 : PCLoaderOSM::NodesHandler::myEndElement(int element) {
450 213660 : if (element == SUMO_TAG_NODE) {
451 41718 : myLastNodeID = -1;
452 : }
453 : myParentElements.pop_back();
454 213660 : }
455 :
456 :
457 : // ---------------------------------------------------------------------------
458 : // definitions of PCLoaderOSM::RelationsHandler-methods
459 : // ---------------------------------------------------------------------------
460 22 : PCLoaderOSM::RelationsHandler::RelationsHandler(RelationsMap& additionalWays,
461 : Relations& relations,
462 : std::set<long long int>& innerEdges,
463 : bool withAttributes,
464 22 : MsgHandler& errorHandler) :
465 : SUMOSAXHandler("osm - file"),
466 22 : myAdditionalWays(additionalWays),
467 22 : myRelations(relations),
468 22 : myInnerEdges(innerEdges),
469 22 : myWithAttributes(withAttributes),
470 22 : myErrorHandler(errorHandler),
471 44 : myCurrentRelation(nullptr) {
472 22 : }
473 :
474 :
475 22 : PCLoaderOSM::RelationsHandler::~RelationsHandler() {
476 22 : }
477 :
478 :
479 : void
480 213641 : PCLoaderOSM::RelationsHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
481 213641 : myParentElements.push_back(element);
482 : // parse "relation" elements
483 213641 : if (element == SUMO_TAG_RELATION) {
484 : myCurrentWays.clear();
485 489 : bool ok = true;
486 489 : const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
487 489 : if (action == "delete" || !ok) {
488 0 : myCurrentRelation = nullptr;
489 : } else {
490 489 : myCurrentRelation = new PCOSMRelation();
491 : myCurrentRelation->keep = false;
492 489 : myCurrentRelation->id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
493 489 : myRelations.push_back(myCurrentRelation);
494 : }
495 : return;
496 213152 : } else if (myCurrentRelation == nullptr) {
497 : return;
498 : }
499 : // parse member elements
500 52919 : if (element == SUMO_TAG_MEMBER) {
501 48978 : bool ok = true;
502 146934 : std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
503 48978 : long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
504 48978 : if (role == "outer" || role == "inner") {
505 2423 : std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
506 2423 : if (memberType == "way") {
507 2423 : myCurrentWays.push_back(ref);
508 2423 : if (role == "inner") {
509 325 : myInnerEdges.insert(ref);
510 : }
511 : }
512 : }
513 : return;
514 : }
515 : // parse values
516 3941 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_RELATION
517 3941 : && myCurrentRelation != nullptr) {
518 3941 : bool ok = true;
519 7882 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, "", false);
520 7882 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, "", false);
521 3941 : if (key == "") {
522 0 : myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentRelation) + "' occurred.");
523 0 : ok = false;
524 : }
525 3941 : if (!ok) {
526 : return;
527 : }
528 3941 : if (key == "name") {
529 262 : myCurrentRelation->name = value;
530 : } else if (MyKeysToInclude.count(key) > 0) {
531 191 : myCurrentRelation->keep = true;
532 4414 : for (std::vector<long long int>::iterator it = myCurrentWays.begin(); it != myCurrentWays.end(); ++it) {
533 4223 : myAdditionalWays[*it] = myCurrentRelation;
534 : }
535 : }
536 3941 : myCurrentRelation->myAttributes[key] = value;
537 : }
538 : }
539 :
540 :
541 : void
542 213641 : PCLoaderOSM::RelationsHandler::myEndElement(int element) {
543 : myParentElements.pop_back();
544 213641 : if (element == SUMO_TAG_RELATION) {
545 489 : myCurrentRelation->myWays = myCurrentWays;
546 489 : myCurrentRelation = nullptr;
547 : myCurrentWays.clear();
548 : }
549 213641 : }
550 :
551 :
552 : // ---------------------------------------------------------------------------
553 : // definitions of PCLoaderOSM::EdgesHandler-methods
554 : // ---------------------------------------------------------------------------
555 22 : PCLoaderOSM::EdgesHandler::EdgesHandler(const std::map<long long int, PCOSMNode*>& osmNodes,
556 : EdgeMap& toFill,
557 : const RelationsMap& additionalWays,
558 22 : bool withAttributes, MsgHandler& errorHandler) :
559 : SUMOSAXHandler("osm - file"),
560 22 : myWithAttributes(withAttributes),
561 22 : myErrorHandler(errorHandler),
562 22 : myOSMNodes(osmNodes),
563 22 : myEdgeMap(toFill),
564 44 : myAdditionalWays(additionalWays) {
565 22 : }
566 :
567 :
568 22 : PCLoaderOSM::EdgesHandler::~EdgesHandler() {
569 22 : }
570 :
571 :
572 : void
573 213641 : PCLoaderOSM::EdgesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
574 213641 : myParentElements.push_back(element);
575 : // parse "way" elements
576 213641 : if (element == SUMO_TAG_WAY) {
577 5761 : bool ok = true;
578 5761 : const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
579 5761 : const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
580 5761 : if (action == "delete" || !ok) {
581 1 : myCurrentEdge = nullptr;
582 : return;
583 : }
584 5760 : myCurrentEdge = new PCOSMEdge();
585 5760 : myCurrentEdge->id = id;
586 : myCurrentEdge->myIsClosed = false;
587 : myCurrentEdge->standalone = false;
588 11520 : myKeep = (myAdditionalWays.find(id) != myAdditionalWays.end());
589 : }
590 : // parse "nd" (node) elements
591 213640 : if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
592 53490 : bool ok = true;
593 53490 : const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
594 53490 : if (ok) {
595 106980 : if (myOSMNodes.find(ref) == myOSMNodes.end()) {
596 304 : WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), ref);
597 304 : return;
598 : }
599 53186 : myCurrentEdge->myCurrentNodes.push_back(ref);
600 : }
601 : }
602 : // parse values
603 63174 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY
604 238608 : && myCurrentEdge != nullptr) {
605 25271 : bool ok = true;
606 50542 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, "", false);
607 50542 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, "", false);
608 25271 : if (key == "") {
609 4 : myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentEdge->id) + "' occurred.");
610 2 : ok = false;
611 : }
612 25271 : if (!ok) {
613 : return;
614 : }
615 25269 : if (key == "name") {
616 1253 : myCurrentEdge->name = value;
617 : } else if (MyKeysToInclude.count(key) > 0) {
618 4790 : myKeep = true;
619 4790 : myCurrentEdge->standalone = true;
620 : }
621 25269 : myCurrentEdge->myAttributes[key] = value;
622 : }
623 : }
624 :
625 :
626 : void
627 213641 : PCLoaderOSM::EdgesHandler::myEndElement(int element) {
628 : myParentElements.pop_back();
629 213641 : if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
630 5760 : if (myKeep) {
631 5007 : RelationsMap::const_iterator it = myAdditionalWays.find(myCurrentEdge->id);
632 5007 : if (it != myAdditionalWays.end()) {
633 498 : myCurrentEdge->myAttributes.insert((*it).second->myAttributes.begin(), (*it).second->myAttributes.end());
634 : }
635 5007 : myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
636 : } else {
637 753 : delete myCurrentEdge;
638 : }
639 5760 : myCurrentEdge = nullptr;
640 : }
641 213641 : }
642 :
643 :
644 : double
645 75 : PCLoaderOSM::mergeClosest(const std::map<long long int, PCOSMNode*>& nodes, std::vector<std::vector<long long int> >& snippets) {
646 : double best = std::numeric_limits<double>::max();
647 : int best_i = 0;
648 : int best_j = 1;
649 : bool iFW = true;
650 : bool jFW = true;
651 :
652 841 : for (int i = 0; i < (int)snippets.size(); i++) {
653 8126 : for (int j = i + 1; j < (int)snippets.size(); j++) {
654 14720 : Position front1(convertNodePosition(nodes.find(snippets[i].front())->second));
655 7360 : Position back1(convertNodePosition(nodes.find(snippets[i].back())->second));
656 14720 : Position front2(convertNodePosition(nodes.find(snippets[j].front())->second));
657 7360 : Position back2(convertNodePosition(nodes.find(snippets[j].back())->second));
658 : double dist1 = front1.distanceTo2D(front2);
659 : double dist2 = front1.distanceTo2D(back2);
660 : double dist3 = back1.distanceTo2D(front2);
661 : double dist4 = back1.distanceTo2D(back2);
662 7360 : if (dist1 < best) {
663 : best = dist1;
664 : best_i = i;
665 : best_j = j;
666 : iFW = false;
667 : jFW = true;
668 : }
669 7360 : if (dist2 < best) {
670 : best = dist2;
671 : best_i = i;
672 : best_j = j;
673 : iFW = false;
674 : jFW = false;
675 : }
676 7360 : if (dist3 < best) {
677 : best = dist3;
678 : best_i = i;
679 : best_j = j;
680 : iFW = true;
681 : jFW = true;
682 : }
683 7360 : if (dist4 < best) {
684 : best = dist4;
685 : best_i = i;
686 : best_j = j;
687 : iFW = true;
688 : jFW = false;
689 : }
690 : }
691 : }
692 75 : std::vector<long long int> merged;
693 75 : if (iFW) {
694 55 : merged.insert(merged.end(), snippets[best_i].begin(), snippets[best_i].end());
695 : } else {
696 20 : merged.insert(merged.end(), snippets[best_i].rbegin(), snippets[best_i].rend());
697 : }
698 75 : if (jFW) {
699 54 : merged.insert(merged.end(), snippets[best_j].begin(), snippets[best_j].end());
700 : } else {
701 21 : merged.insert(merged.end(), snippets[best_j].rbegin(), snippets[best_j].rend());
702 : }
703 : snippets.erase(snippets.begin() + best_j);
704 : snippets.erase(snippets.begin() + best_i);
705 75 : snippets.push_back(merged);
706 75 : return best;
707 75 : }
708 :
709 : /****************************************************************************/
|