Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2008-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 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 53 : std::set<std::string> PCLoaderOSM::initMyKeysToInclude() {
58 : std::set<std::string> result;
59 53 : result.insert("highway");
60 53 : result.insert("railway");
61 53 : result.insert("railway:position");
62 53 : result.insert("railway:position:exact");
63 53 : result.insert("waterway");
64 53 : result.insert("aeroway");
65 53 : result.insert("aerialway");
66 53 : result.insert("power");
67 53 : result.insert("man_made");
68 53 : result.insert("building");
69 53 : result.insert("leisure");
70 53 : result.insert("amenity");
71 53 : result.insert("shop");
72 53 : result.insert("tourism");
73 53 : result.insert("historic");
74 53 : result.insert("landuse");
75 53 : result.insert("natural");
76 53 : result.insert("military");
77 53 : result.insert("boundary");
78 53 : result.insert("admin_level");
79 53 : result.insert("sport");
80 53 : result.insert("polygon");
81 53 : result.insert("place");
82 53 : result.insert("population");
83 53 : result.insert("barrier");
84 53 : result.insert("openGeoDB:population");
85 53 : result.insert("openGeoDB:name");
86 53 : return result;
87 : }
88 :
89 : void
90 44 : PCLoaderOSM::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
91 88 : if (!oc.isSet("osm-files")) {
92 19 : return;
93 : }
94 : // parse file(s)
95 50 : std::vector<std::string> files = oc.getStringVector("osm-files");
96 : // load nodes, first
97 : std::map<long long int, PCOSMNode*> nodes;
98 25 : bool withAttributes = oc.getBool("all-attributes");
99 26 : MsgHandler* m = OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance();
100 25 : NodesHandler nodesHandler(nodes, withAttributes, *m);
101 49 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
102 : // nodes
103 50 : if (!FileHelpers::isReadable(*file)) {
104 0 : WRITE_ERRORF(TL("Could not open osm-file '%'."), *file);
105 : return;
106 : }
107 50 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
108 25 : if (!XMLSubSys::runParser(nodesHandler, *file)) {
109 6 : for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
110 5 : delete (*i).second;
111 : }
112 1 : throw ProcessError();
113 : }
114 24 : PROGRESS_TIME_MESSAGE(before);
115 : }
116 : // load relations to see which additional ways may be relevant
117 : Relations relations;
118 : RelationsMap additionalWays;
119 : std::set<long long int> innerEdges;
120 24 : RelationsHandler relationsHandler(additionalWays, relations, innerEdges, withAttributes, *m);
121 48 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
122 : // edges
123 48 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing relations from osm-file '" + *file + "'");
124 24 : XMLSubSys::runParser(relationsHandler, *file);
125 24 : PROGRESS_TIME_MESSAGE(before);
126 : }
127 :
128 : // load ways
129 : EdgeMap edges;
130 24 : EdgesHandler edgesHandler(nodes, edges, additionalWays, withAttributes, *m);
131 48 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
132 : // edges
133 48 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing edges from osm-file '" + *file + "'");
134 24 : XMLSubSys::runParser(edgesHandler, *file);
135 24 : PROGRESS_TIME_MESSAGE(before);
136 : }
137 :
138 : // build all
139 24 : const bool useName = oc.getBool("osm.use-name");
140 24 : const double mergeRelationsThreshold = OptionsCont::getOptions().getFloat("osm.merge-relations");
141 : // create polygons from relations
142 24 : if (mergeRelationsThreshold >= 0) {
143 891 : for (PCOSMRelation* rel : relations) {
144 885 : if (!rel->keep || rel->myWays.empty()) {
145 606 : continue;
146 : }
147 : // filter unknown and empty ways
148 : int numNodes = 0;
149 4558 : for (auto it = rel->myWays.begin(); it != rel->myWays.end();) {
150 929 : if (edges.count(*it) == 0 || edges[*it]->myCurrentNodes.empty()) {
151 3336 : 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 538 : edges[*it]->standalone = true;
157 538 : it = rel->myWays.erase(it);
158 : } else {
159 391 : numNodes += (int)edges[*it]->myCurrentNodes.size();
160 : it++;
161 : }
162 : }
163 293 : if (numNodes == 0) {
164 14 : WRITE_WARNINGF(TL("Could not import polygon from relation '%' (missing ways)"), rel->id);
165 14 : continue;
166 : }
167 279 : PCOSMEdge* e = new PCOSMEdge();
168 279 : e->id = rel->id;
169 279 : e->name = rel->name;
170 : e->myAttributes = rel->myAttributes;
171 279 : e->myIsClosed = false;
172 279 : e->standalone = true;
173 :
174 : std::vector<std::vector<long long int> > snippets;
175 670 : for (const long long int wayID : rel->myWays) {
176 391 : PCOSMEdge* edge = edges[wayID];
177 391 : snippets.push_back(edge->myCurrentNodes);
178 : }
179 : double maxDist = 0.;
180 : bool ok = true;
181 387 : while (snippets.size() > 1) {
182 112 : maxDist = MAX2(maxDist, mergeClosest(nodes, snippets));
183 112 : if (maxDist > mergeRelationsThreshold) {
184 : ok = false;
185 : break;
186 : }
187 : }
188 279 : if (ok) {
189 275 : e->myCurrentNodes = snippets.front();
190 275 : edges[e->id] = e;
191 : double frontBackDist = 0;
192 275 : if (e->myCurrentNodes.front() != e->myCurrentNodes.back()) {
193 : // should be filled
194 17 : const Position posFront = convertNodePosition(nodes[e->myCurrentNodes.front()]);
195 17 : const Position posBack = convertNodePosition(nodes[e->myCurrentNodes.back()]);
196 : frontBackDist = posFront.distanceTo2D(posBack);
197 17 : if (frontBackDist < mergeRelationsThreshold) {
198 0 : e->myCurrentNodes.push_back(e->myCurrentNodes.front());
199 : frontBackDist = 0;
200 : }
201 : }
202 275 : std::string frontBackMsg = "";
203 275 : if (frontBackDist > 0) {
204 51 : frontBackMsg = TLF(", (front-to-back dist: %)", frontBackDist);
205 : }
206 897 : WRITE_MESSAGEF(TL("Assembled polygon from relation '%' (name:%)%"), toString(rel->id), e->name, frontBackMsg);
207 : } else {
208 12 : WRITE_WARNINGF(TL("Could not import polygon from relation '%' (name:% reason: found gap of %m)\n."), rel->id, rel->name, maxDist)
209 4 : delete e;
210 : // export ways by themselves
211 20 : for (long long int wayID : rel->myWays) {
212 16 : PCOSMEdge* part = edges[wayID];
213 16 : part->standalone = true;
214 : }
215 : }
216 279 : }
217 : }
218 :
219 : // instatiate polygons
220 10033 : for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
221 10009 : PCOSMEdge* e = (*i).second;
222 10009 : if (e->myAttributes.size() == 0) {
223 : // cannot be relevant as a polygon
224 296 : continue;
225 : }
226 10009 : if (!e->standalone && mergeRelationsThreshold >= 0) {
227 : // part of a relation
228 294 : continue;
229 : }
230 9715 : 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 9713 : PositionVector vec;
236 102819 : for (std::vector<long long int>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
237 93106 : PCOSMNode* n = nodes.find(*j)->second;
238 93106 : Position pos(n->lon, n->lat);
239 93106 : if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
240 0 : WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), e->id);
241 : }
242 93106 : vec.push_back_noDoublePos(pos);
243 : }
244 19426 : 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 9713 : std::string unknownPolyType = "";
248 19784 : bool isInner = mergeRelationsThreshold >= 0 && innerEdges.count(e->id) != 0 && tm.has("inner");
249 60678 : for (std::map<std::string, std::string>::iterator it = e->myAttributes.begin(); it != e->myAttributes.end(); ++it) {
250 50965 : const std::string& key = it->first;
251 50965 : const std::string& value = it->second;
252 50965 : const std::string fullType = key + "." + value;
253 101930 : if (tm.has(key + "." + value)) {
254 940 : auto def = tm.get(isInner ? "inner" : fullType);
255 480 : index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
256 50965 : } else if (tm.has(key)) {
257 18875 : auto def = tm.get(isInner ? "inner" : key);
258 9827 : index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
259 9827 : } else if (MyKeysToInclude.count(key) > 0) {
260 : unknownPolyType = fullType;
261 : }
262 : }
263 : const PCTypeMap::TypeDef& def = tm.getDefault();
264 15089 : if (index == 0 && !def.discard && unknownPolyType != "") {
265 11 : addPolygon(e, vec, def, unknownPolyType, index, useName, toFill, ignorePruning, withAttributes);
266 : }
267 9713 : }
268 :
269 :
270 : // instantiate pois
271 79384 : for (std::map<long long int, PCOSMNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) {
272 79360 : PCOSMNode* n = (*i).second;
273 79360 : if (n->myAttributes.size() == 0) {
274 : // cannot be relevant as a poi
275 66023 : continue;
276 : }
277 13337 : Position pos(n->lon, n->lat);
278 13337 : if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
279 0 : WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), n->id);
280 : }
281 26674 : 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 13337 : std::string unKnownPOIType = "";
285 80027 : for (std::map<std::string, std::string>::iterator it = n->myAttributes.begin(); it != n->myAttributes.end(); ++it) {
286 66690 : const std::string& key = it->first;
287 66690 : const std::string& value = it->second;
288 66690 : const std::string fullType = key + "." + value;
289 133380 : if (tm.has(key + "." + value)) {
290 73 : index = addPOI(n, pos, tm.get(fullType), fullType, index, useName, toFill, ignorePruning, withAttributes);
291 66617 : } else if (tm.has(key)) {
292 7385 : 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 21234 : if (index == 0 && !def.discard && unKnownPOIType != "") {
299 0 : addPOI(n, pos, def, unKnownPOIType, index, useName, toFill, ignorePruning, withAttributes);
300 : }
301 : }
302 : // delete nodes
303 79384 : for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
304 79360 : delete (*i).second;
305 : }
306 : // delete edges
307 10033 : for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
308 10009 : delete (*i).second;
309 : }
310 : // delete relations
311 944 : for (Relations::iterator i = relations.begin(); i != relations.end(); ++i) {
312 920 : delete (*i);
313 : }
314 98 : }
315 :
316 :
317 : Position
318 0 : PCLoaderOSM::convertNodePosition(PCOSMNode* n) {
319 34 : Position pos(n->lon, n->lat);
320 30310 : GeoConvHelper::getProcessing().x2cartesian(pos);
321 34 : return pos;
322 : }
323 :
324 :
325 : int
326 10318 : 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) {
327 10318 : if (def.discard) {
328 5463 : return index;
329 : } else {
330 : const bool closedShape = vec.front() == vec.back();
331 4855 : const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
332 9711 : const std::string id = def.prefix + (useName && edge->name != "" ? edge->name : toString(edge->id)) + idSuffix;
333 4855 : bool fill = def.allowFill == PCTypeMap::FORCE || (def.allowFill == PCTypeMap::FILL && closedShape);
334 : SUMOPolygon* poly = new SUMOPolygon(
335 4855 : StringUtils::escapeXML(id),
336 14565 : StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
337 4855 : def.color, vec, false, fill, 1, def.layer);
338 4855 : if (withAttributes) {
339 71 : poly->updateParameters(edge->myAttributes);
340 : }
341 4855 : if (!toFill.add(poly, ignorePruning)) {
342 0 : return index;
343 : } else {
344 4855 : return index + 1;
345 : }
346 : }
347 : }
348 :
349 :
350 : int
351 7458 : PCLoaderOSM::addPOI(const PCOSMNode* node, const Position& pos, const PCTypeMap::TypeDef& def, const std::string& fullType,
352 : int index, bool useName, PCPolyContainer& toFill, bool ignorePruning, bool withAttributes) {
353 7458 : if (def.discard) {
354 1956 : return index;
355 : } else {
356 5502 : const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
357 11005 : const std::string id = def.prefix + (useName && node->name != "" ? node->name : toString(node->id)) + idSuffix;
358 : PointOfInterest* poi = new PointOfInterest(
359 5502 : StringUtils::escapeXML(id),
360 16506 : StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
361 11004 : def.color, pos, false, "", 0, false, 0, def.icon, def.layer);
362 5502 : if (withAttributes) {
363 44 : poi->updateParameters(node->myAttributes);
364 : }
365 5502 : if (!toFill.add(poi, ignorePruning)) {
366 4 : return index;
367 : } else {
368 5498 : return index + 1;
369 : }
370 : }
371 : }
372 :
373 :
374 : // ---------------------------------------------------------------------------
375 : // definitions of PCLoaderOSM::NodesHandler-methods
376 : // ---------------------------------------------------------------------------
377 25 : PCLoaderOSM::NodesHandler::NodesHandler(std::map<long long int, PCOSMNode*>& toFill,
378 25 : bool withAttributes, MsgHandler& errorHandler) :
379 25 : SUMOSAXHandler("osm - file"), myWithAttributes(withAttributes), myErrorHandler(errorHandler),
380 50 : myToFill(toFill), myLastNodeID(-1) {}
381 :
382 :
383 50 : PCLoaderOSM::NodesHandler::~NodesHandler() {}
384 :
385 :
386 : void
387 417112 : PCLoaderOSM::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
388 417112 : myParentElements.push_back(element);
389 417112 : if (element == SUMO_TAG_NODE) {
390 79365 : bool ok = true;
391 79365 : long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
392 79365 : if (!ok) {
393 0 : return;
394 : }
395 79365 : myLastNodeID = -1;
396 158730 : if (myToFill.find(id) == myToFill.end()) {
397 79365 : myLastNodeID = id;
398 : // assume we are loading multiple files...
399 : // ... so we won't report duplicate nodes
400 79365 : PCOSMNode* toAdd = new PCOSMNode();
401 79365 : toAdd->id = id;
402 79365 : toAdd->lon = attrs.get<double>(SUMO_ATTR_LON, toString(id).c_str(), ok);
403 79365 : toAdd->lat = attrs.get<double>(SUMO_ATTR_LAT, toString(id).c_str(), ok);
404 79365 : if (!ok) {
405 0 : delete toAdd;
406 0 : return;
407 : }
408 79365 : myToFill[toAdd->id] = toAdd;
409 : }
410 : }
411 124073 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_NODE
412 483807 : && myLastNodeID != -1) {
413 66695 : bool ok = true;
414 133390 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, "", false);
415 133390 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "", false);
416 66695 : if (key == "name") {
417 3476 : myToFill[myLastNodeID]->name = value;
418 63219 : } else if (key == "") {
419 4 : myErrorHandler.inform("Empty key in a a tag while parsing node '" + toString(myLastNodeID) + "' occurred.");
420 2 : ok = false;
421 : }
422 66695 : if (!ok) {
423 : return;
424 : }
425 66693 : myToFill[myLastNodeID]->myAttributes[key] = value;
426 : }
427 : }
428 :
429 :
430 : void
431 417112 : PCLoaderOSM::NodesHandler::myEndElement(int element) {
432 417112 : if (element == SUMO_TAG_NODE) {
433 79365 : myLastNodeID = -1;
434 : }
435 : myParentElements.pop_back();
436 417112 : }
437 :
438 :
439 : // ---------------------------------------------------------------------------
440 : // definitions of PCLoaderOSM::RelationsHandler-methods
441 : // ---------------------------------------------------------------------------
442 24 : PCLoaderOSM::RelationsHandler::RelationsHandler(RelationsMap& additionalWays,
443 : Relations& relations,
444 : std::set<long long int>& innerEdges,
445 : bool withAttributes,
446 24 : MsgHandler& errorHandler) :
447 : SUMOSAXHandler("osm - file"),
448 24 : myAdditionalWays(additionalWays),
449 24 : myRelations(relations),
450 24 : myInnerEdges(innerEdges),
451 24 : myWithAttributes(withAttributes),
452 24 : myErrorHandler(errorHandler),
453 48 : myCurrentRelation(nullptr) {
454 24 : }
455 :
456 :
457 24 : PCLoaderOSM::RelationsHandler::~RelationsHandler() {
458 24 : }
459 :
460 :
461 : void
462 417093 : PCLoaderOSM::RelationsHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
463 417093 : myParentElements.push_back(element);
464 : // parse "relation" elements
465 417093 : if (element == SUMO_TAG_RELATION) {
466 : myCurrentWays.clear();
467 920 : bool ok = true;
468 1840 : const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
469 920 : if (action == "delete" || !ok) {
470 0 : myCurrentRelation = nullptr;
471 : } else {
472 920 : myCurrentRelation = new PCOSMRelation();
473 : myCurrentRelation->keep = false;
474 920 : myCurrentRelation->id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
475 920 : myRelations.push_back(myCurrentRelation);
476 : }
477 : return;
478 416173 : } else if (myCurrentRelation == nullptr) {
479 : return;
480 : }
481 : // parse member elements
482 104944 : if (element == SUMO_TAG_MEMBER) {
483 97304 : bool ok = true;
484 291912 : std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
485 97304 : long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
486 190676 : if (role == "outer" || role == "inner") {
487 4553 : std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
488 4553 : if (memberType == "way") {
489 4553 : myCurrentWays.push_back(ref);
490 4553 : if (role == "inner") {
491 621 : myInnerEdges.insert(ref);
492 : }
493 : }
494 : }
495 : return;
496 : }
497 : // parse values
498 7640 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_RELATION
499 7640 : && myCurrentRelation != nullptr) {
500 7640 : bool ok = true;
501 15280 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, "", false);
502 15280 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, "", false);
503 7640 : if (key == "") {
504 0 : myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentRelation) + "' occurred.");
505 0 : ok = false;
506 : }
507 7640 : if (!ok) {
508 : return;
509 : }
510 7640 : if (key == "name") {
511 511 : myCurrentRelation->name = value;
512 : } else if (MyKeysToInclude.count(key) > 0) {
513 370 : myCurrentRelation->keep = true;
514 8704 : for (std::vector<long long int>::iterator it = myCurrentWays.begin(); it != myCurrentWays.end(); ++it) {
515 8334 : myAdditionalWays[*it] = myCurrentRelation;
516 : }
517 : }
518 7640 : myCurrentRelation->myAttributes[key] = value;
519 : }
520 : }
521 :
522 :
523 : void
524 417093 : PCLoaderOSM::RelationsHandler::myEndElement(int element) {
525 : myParentElements.pop_back();
526 417093 : if (element == SUMO_TAG_RELATION) {
527 920 : myCurrentRelation->myWays = myCurrentWays;
528 920 : myCurrentRelation = nullptr;
529 : myCurrentWays.clear();
530 : }
531 417093 : }
532 :
533 :
534 : // ---------------------------------------------------------------------------
535 : // definitions of PCLoaderOSM::EdgesHandler-methods
536 : // ---------------------------------------------------------------------------
537 24 : PCLoaderOSM::EdgesHandler::EdgesHandler(const std::map<long long int, PCOSMNode*>& osmNodes,
538 : EdgeMap& toFill,
539 : const RelationsMap& additionalWays,
540 24 : bool withAttributes, MsgHandler& errorHandler) :
541 : SUMOSAXHandler("osm - file"),
542 24 : myWithAttributes(withAttributes),
543 24 : myErrorHandler(errorHandler),
544 24 : myOSMNodes(osmNodes),
545 24 : myEdgeMap(toFill),
546 48 : myAdditionalWays(additionalWays) {
547 24 : }
548 :
549 :
550 24 : PCLoaderOSM::EdgesHandler::~EdgesHandler() {
551 24 : }
552 :
553 :
554 : void
555 417093 : PCLoaderOSM::EdgesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
556 417093 : myParentElements.push_back(element);
557 : // parse "way" elements
558 417093 : if (element == SUMO_TAG_WAY) {
559 11188 : bool ok = true;
560 11188 : const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
561 22376 : const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
562 11188 : if (action == "delete" || !ok) {
563 1 : myCurrentEdge = nullptr;
564 : return;
565 : }
566 11187 : myCurrentEdge = new PCOSMEdge();
567 11187 : myCurrentEdge->id = id;
568 : myCurrentEdge->myIsClosed = false;
569 : myCurrentEdge->standalone = false;
570 22374 : myKeep = (myAdditionalWays.find(id) != myAdditionalWays.end());
571 : }
572 : // parse "nd" (node) elements
573 417092 : if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
574 104213 : bool ok = true;
575 104213 : const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
576 104213 : if (ok) {
577 208426 : if (myOSMNodes.find(ref) == myOSMNodes.end()) {
578 304 : WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), ref);
579 304 : return;
580 : }
581 103909 : myCurrentEdge->myCurrentNodes.push_back(ref);
582 : }
583 : }
584 : // parse values
585 124066 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY
586 466523 : && myCurrentEdge != nullptr) {
587 49734 : bool ok = true;
588 99468 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, "", false);
589 99468 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, "", false);
590 49734 : if (key == "") {
591 4 : myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentEdge->id) + "' occurred.");
592 2 : ok = false;
593 : }
594 49734 : if (!ok) {
595 : return;
596 : }
597 49732 : if (key == "name") {
598 2441 : myCurrentEdge->name = value;
599 : } else if (MyKeysToInclude.count(key) > 0) {
600 9359 : myKeep = true;
601 9359 : myCurrentEdge->standalone = true;
602 : }
603 49732 : myCurrentEdge->myAttributes[key] = value;
604 : }
605 : }
606 :
607 :
608 : void
609 417093 : PCLoaderOSM::EdgesHandler::myEndElement(int element) {
610 : myParentElements.pop_back();
611 417093 : if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
612 11187 : if (myKeep) {
613 9734 : RelationsMap::const_iterator it = myAdditionalWays.find(myCurrentEdge->id);
614 9734 : if (it != myAdditionalWays.end()) {
615 921 : myCurrentEdge->myAttributes.insert((*it).second->myAttributes.begin(), (*it).second->myAttributes.end());
616 : }
617 9734 : myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
618 : } else {
619 1453 : delete myCurrentEdge;
620 : }
621 11187 : myCurrentEdge = nullptr;
622 : }
623 417093 : }
624 :
625 :
626 : double
627 112 : PCLoaderOSM::mergeClosest(const std::map<long long int, PCOSMNode*>& nodes, std::vector<std::vector<long long int> >& snippets) {
628 : double best = std::numeric_limits<double>::max();
629 : int best_i = 0;
630 : int best_j = 1;
631 : bool iFW = true;
632 : bool jFW = true;
633 :
634 1004 : for (int i = 0; i < (int)snippets.size(); i++) {
635 8461 : for (int j = i + 1; j < (int)snippets.size(); j++) {
636 15138 : Position front1(convertNodePosition(nodes.find(snippets[i].front())->second));
637 7569 : Position back1(convertNodePosition(nodes.find(snippets[i].back())->second));
638 15138 : Position front2(convertNodePosition(nodes.find(snippets[j].front())->second));
639 7569 : Position back2(convertNodePosition(nodes.find(snippets[j].back())->second));
640 : double dist1 = front1.distanceTo2D(front2);
641 : double dist2 = front1.distanceTo2D(back2);
642 : double dist3 = back1.distanceTo2D(front2);
643 : double dist4 = back1.distanceTo2D(back2);
644 7569 : if (dist1 < best) {
645 : best = dist1;
646 : best_i = i;
647 : best_j = j;
648 : iFW = false;
649 : jFW = true;
650 : }
651 7569 : if (dist2 < best) {
652 : best = dist2;
653 : best_i = i;
654 : best_j = j;
655 : iFW = false;
656 : jFW = false;
657 : }
658 7569 : if (dist3 < best) {
659 : best = dist3;
660 : best_i = i;
661 : best_j = j;
662 : iFW = true;
663 : jFW = true;
664 : }
665 7569 : if (dist4 < best) {
666 : best = dist4;
667 : best_i = i;
668 : best_j = j;
669 : iFW = true;
670 : jFW = false;
671 : }
672 : }
673 : }
674 : std::vector<long long int> merged;
675 112 : if (iFW) {
676 76 : merged.insert(merged.end(), snippets[best_i].begin(), snippets[best_i].end());
677 : } else {
678 36 : merged.insert(merged.end(), snippets[best_i].rbegin(), snippets[best_i].rend());
679 : }
680 112 : if (jFW) {
681 75 : merged.insert(merged.end(), snippets[best_j].begin(), snippets[best_j].end());
682 : } else {
683 37 : merged.insert(merged.end(), snippets[best_j].rbegin(), snippets[best_j].rend());
684 : }
685 : snippets.erase(snippets.begin() + best_j);
686 : snippets.erase(snippets.begin() + best_i);
687 112 : snippets.push_back(merged);
688 112 : return best;
689 : }
690 :
691 : /****************************************************************************/
|