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 49 : std::set<std::string> PCLoaderOSM::initMyKeysToInclude() {
58 : std::set<std::string> result;
59 49 : result.insert("highway");
60 49 : result.insert("railway");
61 49 : result.insert("railway:position");
62 49 : result.insert("railway:position:exact");
63 49 : result.insert("waterway");
64 49 : result.insert("aeroway");
65 49 : result.insert("aerialway");
66 49 : result.insert("power");
67 49 : result.insert("man_made");
68 49 : result.insert("building");
69 49 : result.insert("leisure");
70 49 : result.insert("amenity");
71 49 : result.insert("shop");
72 49 : result.insert("tourism");
73 49 : result.insert("historic");
74 49 : result.insert("landuse");
75 49 : result.insert("natural");
76 49 : result.insert("military");
77 49 : result.insert("boundary");
78 49 : result.insert("admin_level");
79 49 : result.insert("sport");
80 49 : result.insert("polygon");
81 49 : result.insert("place");
82 49 : result.insert("population");
83 49 : result.insert("barrier");
84 49 : result.insert("openGeoDB:population");
85 49 : result.insert("openGeoDB:name");
86 49 : return result;
87 : }
88 :
89 : void
90 42 : PCLoaderOSM::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
91 84 : if (!oc.isSet("osm-files")) {
92 19 : 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 : 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 : 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 30990 : for (std::map<std::string, std::string>::iterator it = e->myAttributes.begin(); it != e->myAttributes.end(); ++it) {
250 26013 : const std::string& key = it->first;
251 : const std::string& value = it->second;
252 26013 : const std::string fullType = key + "." + value;
253 78039 : 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 26013 : } 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 : int
326 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) {
327 5287 : if (def.discard) {
328 2801 : return index;
329 : } else {
330 : const bool closedShape = vec.front() == vec.back();
331 2486 : const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
332 2486 : const std::string id = def.prefix + (useName && edge->name != "" ? edge->name : toString(edge->id)) + idSuffix;
333 2486 : bool fill = def.allowFill == PCTypeMap::Filltype::FORCE || (def.allowFill == PCTypeMap::Filltype::FILL && closedShape);
334 : SUMOPolygon* poly = new SUMOPolygon(
335 4972 : StringUtils::escapeXML(id),
336 2486 : StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
337 4972 : def.color, vec, false, fill, 1, def.layer);
338 2486 : if (withAttributes) {
339 71 : poly->updateParameters(edge->myAttributes);
340 : }
341 2486 : if (!toFill.add(poly, ignorePruning)) {
342 : return index;
343 : } else {
344 2486 : return index + 1;
345 : }
346 : }
347 : }
348 :
349 :
350 : int
351 3824 : 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 3824 : if (def.discard) {
354 1038 : return index;
355 : } else {
356 2786 : const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
357 2786 : const std::string id = def.prefix + (useName && node->name != "" ? node->name : toString(node->id)) + idSuffix;
358 : PointOfInterest* poi = new PointOfInterest(
359 5572 : StringUtils::escapeXML(id),
360 5572 : StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
361 5572 : def.color, pos, false, "", 0, false, 0, def.icon, def.layer);
362 2786 : if (withAttributes) {
363 44 : poi->updateParameters(node->myAttributes);
364 : }
365 2786 : if (!toFill.add(poi, ignorePruning)) {
366 : return index;
367 : } else {
368 2782 : return index + 1;
369 : }
370 : }
371 : }
372 :
373 :
374 : // ---------------------------------------------------------------------------
375 : // definitions of PCLoaderOSM::NodesHandler-methods
376 : // ---------------------------------------------------------------------------
377 23 : PCLoaderOSM::NodesHandler::NodesHandler(std::map<long long int, PCOSMNode*>& toFill,
378 23 : bool withAttributes, MsgHandler& errorHandler) :
379 23 : SUMOSAXHandler("osm - file"), myWithAttributes(withAttributes), myErrorHandler(errorHandler),
380 46 : myToFill(toFill), myLastNodeID(-1) {}
381 :
382 :
383 23 : PCLoaderOSM::NodesHandler::~NodesHandler() {}
384 :
385 :
386 : void
387 213659 : PCLoaderOSM::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
388 213659 : myParentElements.push_back(element);
389 213659 : if (element == SUMO_TAG_NODE) {
390 41718 : bool ok = true;
391 41718 : long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
392 41718 : if (!ok) {
393 0 : return;
394 : }
395 41718 : myLastNodeID = -1;
396 83436 : if (myToFill.find(id) == myToFill.end()) {
397 41718 : myLastNodeID = id;
398 : // assume we are loading multiple files...
399 : // ... so we won't report duplicate nodes
400 41718 : PCOSMNode* toAdd = new PCOSMNode();
401 41718 : toAdd->id = id;
402 41718 : toAdd->lon = attrs.get<double>(SUMO_ATTR_LON, toString(id).c_str(), ok);
403 41718 : toAdd->lat = attrs.get<double>(SUMO_ATTR_LAT, toString(id).c_str(), ok);
404 41718 : if (!ok) {
405 0 : delete toAdd;
406 0 : return;
407 : }
408 41718 : myToFill[toAdd->id] = toAdd;
409 : }
410 : }
411 63180 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_NODE
412 247624 : && myLastNodeID != -1) {
413 33965 : bool ok = true;
414 67930 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, "", false);
415 67930 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "", false);
416 33965 : if (key == "name") {
417 1770 : myToFill[myLastNodeID]->name = value;
418 32195 : } 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 33965 : if (!ok) {
423 : return;
424 : }
425 33963 : myToFill[myLastNodeID]->myAttributes[key] = value;
426 : }
427 : }
428 :
429 :
430 : void
431 213659 : PCLoaderOSM::NodesHandler::myEndElement(int element) {
432 213659 : if (element == SUMO_TAG_NODE) {
433 41718 : myLastNodeID = -1;
434 : }
435 : myParentElements.pop_back();
436 213659 : }
437 :
438 :
439 : // ---------------------------------------------------------------------------
440 : // definitions of PCLoaderOSM::RelationsHandler-methods
441 : // ---------------------------------------------------------------------------
442 22 : PCLoaderOSM::RelationsHandler::RelationsHandler(RelationsMap& additionalWays,
443 : Relations& relations,
444 : std::set<long long int>& innerEdges,
445 : bool withAttributes,
446 22 : MsgHandler& errorHandler) :
447 : SUMOSAXHandler("osm - file"),
448 22 : myAdditionalWays(additionalWays),
449 22 : myRelations(relations),
450 22 : myInnerEdges(innerEdges),
451 22 : myWithAttributes(withAttributes),
452 22 : myErrorHandler(errorHandler),
453 44 : myCurrentRelation(nullptr) {
454 22 : }
455 :
456 :
457 22 : PCLoaderOSM::RelationsHandler::~RelationsHandler() {
458 22 : }
459 :
460 :
461 : void
462 213640 : PCLoaderOSM::RelationsHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
463 213640 : myParentElements.push_back(element);
464 : // parse "relation" elements
465 213640 : if (element == SUMO_TAG_RELATION) {
466 : myCurrentWays.clear();
467 489 : bool ok = true;
468 489 : const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
469 489 : if (action == "delete" || !ok) {
470 0 : myCurrentRelation = nullptr;
471 : } else {
472 489 : myCurrentRelation = new PCOSMRelation();
473 : myCurrentRelation->keep = false;
474 489 : myCurrentRelation->id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
475 489 : myRelations.push_back(myCurrentRelation);
476 : }
477 : return;
478 213151 : } else if (myCurrentRelation == nullptr) {
479 : return;
480 : }
481 : // parse member elements
482 52919 : if (element == SUMO_TAG_MEMBER) {
483 48978 : bool ok = true;
484 146934 : std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
485 48978 : long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
486 48978 : if (role == "outer" || role == "inner") {
487 2423 : std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
488 2423 : if (memberType == "way") {
489 2423 : myCurrentWays.push_back(ref);
490 2423 : if (role == "inner") {
491 325 : myInnerEdges.insert(ref);
492 : }
493 : }
494 : }
495 : return;
496 : }
497 : // parse values
498 3941 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_RELATION
499 3941 : && myCurrentRelation != nullptr) {
500 3941 : bool ok = true;
501 7882 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, "", false);
502 7882 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, "", false);
503 3941 : if (key == "") {
504 0 : myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentRelation) + "' occurred.");
505 0 : ok = false;
506 : }
507 3941 : if (!ok) {
508 : return;
509 : }
510 3941 : if (key == "name") {
511 262 : myCurrentRelation->name = value;
512 : } else if (MyKeysToInclude.count(key) > 0) {
513 191 : myCurrentRelation->keep = true;
514 4414 : for (std::vector<long long int>::iterator it = myCurrentWays.begin(); it != myCurrentWays.end(); ++it) {
515 4223 : myAdditionalWays[*it] = myCurrentRelation;
516 : }
517 : }
518 3941 : myCurrentRelation->myAttributes[key] = value;
519 : }
520 : }
521 :
522 :
523 : void
524 213640 : PCLoaderOSM::RelationsHandler::myEndElement(int element) {
525 : myParentElements.pop_back();
526 213640 : if (element == SUMO_TAG_RELATION) {
527 489 : myCurrentRelation->myWays = myCurrentWays;
528 489 : myCurrentRelation = nullptr;
529 : myCurrentWays.clear();
530 : }
531 213640 : }
532 :
533 :
534 : // ---------------------------------------------------------------------------
535 : // definitions of PCLoaderOSM::EdgesHandler-methods
536 : // ---------------------------------------------------------------------------
537 22 : PCLoaderOSM::EdgesHandler::EdgesHandler(const std::map<long long int, PCOSMNode*>& osmNodes,
538 : EdgeMap& toFill,
539 : const RelationsMap& additionalWays,
540 22 : bool withAttributes, MsgHandler& errorHandler) :
541 : SUMOSAXHandler("osm - file"),
542 22 : myWithAttributes(withAttributes),
543 22 : myErrorHandler(errorHandler),
544 22 : myOSMNodes(osmNodes),
545 22 : myEdgeMap(toFill),
546 44 : myAdditionalWays(additionalWays) {
547 22 : }
548 :
549 :
550 22 : PCLoaderOSM::EdgesHandler::~EdgesHandler() {
551 22 : }
552 :
553 :
554 : void
555 213640 : PCLoaderOSM::EdgesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
556 213640 : myParentElements.push_back(element);
557 : // parse "way" elements
558 213640 : if (element == SUMO_TAG_WAY) {
559 5761 : bool ok = true;
560 5761 : const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
561 5761 : const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
562 5761 : if (action == "delete" || !ok) {
563 1 : myCurrentEdge = nullptr;
564 : return;
565 : }
566 5760 : myCurrentEdge = new PCOSMEdge();
567 5760 : myCurrentEdge->id = id;
568 : myCurrentEdge->myIsClosed = false;
569 : myCurrentEdge->standalone = false;
570 11520 : myKeep = (myAdditionalWays.find(id) != myAdditionalWays.end());
571 : }
572 : // parse "nd" (node) elements
573 213639 : if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
574 53490 : bool ok = true;
575 53490 : const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
576 53490 : if (ok) {
577 106980 : 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 53186 : myCurrentEdge->myCurrentNodes.push_back(ref);
582 : }
583 : }
584 : // parse values
585 63173 : if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY
586 238606 : && myCurrentEdge != nullptr) {
587 25270 : bool ok = true;
588 50540 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, "", false);
589 50540 : std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, "", false);
590 25270 : 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 25270 : if (!ok) {
595 : return;
596 : }
597 25268 : if (key == "name") {
598 1253 : myCurrentEdge->name = value;
599 : } else if (MyKeysToInclude.count(key) > 0) {
600 4790 : myKeep = true;
601 4790 : myCurrentEdge->standalone = true;
602 : }
603 25268 : myCurrentEdge->myAttributes[key] = value;
604 : }
605 : }
606 :
607 :
608 : void
609 213640 : PCLoaderOSM::EdgesHandler::myEndElement(int element) {
610 : myParentElements.pop_back();
611 213640 : if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
612 5760 : if (myKeep) {
613 5007 : RelationsMap::const_iterator it = myAdditionalWays.find(myCurrentEdge->id);
614 5007 : if (it != myAdditionalWays.end()) {
615 498 : myCurrentEdge->myAttributes.insert((*it).second->myAttributes.begin(), (*it).second->myAttributes.end());
616 : }
617 5007 : myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
618 : } else {
619 753 : delete myCurrentEdge;
620 : }
621 5760 : myCurrentEdge = nullptr;
622 : }
623 213640 : }
624 :
625 :
626 : double
627 75 : 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 841 : for (int i = 0; i < (int)snippets.size(); i++) {
635 8126 : for (int j = i + 1; j < (int)snippets.size(); j++) {
636 14720 : Position front1(convertNodePosition(nodes.find(snippets[i].front())->second));
637 7360 : Position back1(convertNodePosition(nodes.find(snippets[i].back())->second));
638 14720 : Position front2(convertNodePosition(nodes.find(snippets[j].front())->second));
639 7360 : 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 7360 : if (dist1 < best) {
645 : best = dist1;
646 : best_i = i;
647 : best_j = j;
648 : iFW = false;
649 : jFW = true;
650 : }
651 7360 : if (dist2 < best) {
652 : best = dist2;
653 : best_i = i;
654 : best_j = j;
655 : iFW = false;
656 : jFW = false;
657 : }
658 7360 : if (dist3 < best) {
659 : best = dist3;
660 : best_i = i;
661 : best_j = j;
662 : iFW = true;
663 : jFW = true;
664 : }
665 7360 : 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 75 : if (iFW) {
676 55 : merged.insert(merged.end(), snippets[best_i].begin(), snippets[best_i].end());
677 : } else {
678 20 : merged.insert(merged.end(), snippets[best_i].rbegin(), snippets[best_i].rend());
679 : }
680 75 : if (jFW) {
681 54 : merged.insert(merged.end(), snippets[best_j].begin(), snippets[best_j].end());
682 : } else {
683 21 : 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 75 : snippets.push_back(merged);
688 75 : return best;
689 75 : }
690 :
691 : /****************************************************************************/
|