Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
PCLoaderOSM.cpp
Go to the documentation of this file.
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/****************************************************************************/
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>
37#include <utils/geom/Position.h>
39#include <utils/xml/XMLSubSys.h>
45#include "PCLoaderOSM.h"
46
47// static members
48// ---------------------------------------------------------------------------
50
51// ===========================================================================
52// method definitions
53// ===========================================================================
54// ---------------------------------------------------------------------------
55// static interface
56// ---------------------------------------------------------------------------
57std::set<std::string> PCLoaderOSM::initMyKeysToInclude() {
58 std::set<std::string> result;
59 result.insert("highway");
60 result.insert("railway");
61 result.insert("railway:position");
62 result.insert("railway:position:exact");
63 result.insert("waterway");
64 result.insert("aeroway");
65 result.insert("aerialway");
66 result.insert("power");
67 result.insert("man_made");
68 result.insert("building");
69 result.insert("leisure");
70 result.insert("amenity");
71 result.insert("shop");
72 result.insert("tourism");
73 result.insert("historic");
74 result.insert("landuse");
75 result.insert("natural");
76 result.insert("military");
77 result.insert("boundary");
78 result.insert("admin_level");
79 result.insert("sport");
80 result.insert("polygon");
81 result.insert("place");
82 result.insert("population");
83 result.insert("barrier");
84 result.insert("openGeoDB:population");
85 result.insert("openGeoDB:name");
86 return result;
87}
88
89void
91 if (!oc.isSet("osm-files")) {
92 return;
93 }
94 // parse file(s)
95 std::vector<std::string> files = oc.getStringVector("osm-files");
96 // load nodes, first
97 std::map<long long int, PCOSMNode*> nodes;
98 bool withAttributes = oc.getBool("all-attributes");
100 NodesHandler nodesHandler(nodes, withAttributes, *m);
101 for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
102 // nodes
103 if (!FileHelpers::isReadable(*file)) {
104 WRITE_ERRORF(TL("Could not open osm-file '%'."), *file);
105 return;
106 }
107 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
108 if (!XMLSubSys::runParser(nodesHandler, *file)) {
109 for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
110 delete (*i).second;
111 }
112 throw ProcessError();
113 }
114 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 RelationsHandler relationsHandler(additionalWays, relations, innerEdges, withAttributes, *m);
121 for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
122 // edges
123 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing relations from osm-file '" + *file + "'");
124 XMLSubSys::runParser(relationsHandler, *file);
125 PROGRESS_TIME_MESSAGE(before);
126 }
127
128 // load ways
129 EdgeMap edges;
130 EdgesHandler edgesHandler(nodes, edges, additionalWays, withAttributes, *m);
131 for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
132 // edges
133 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing edges from osm-file '" + *file + "'");
134 XMLSubSys::runParser(edgesHandler, *file);
135 PROGRESS_TIME_MESSAGE(before);
136 }
137
138 // build all
139 const bool useName = oc.getBool("osm.use-name");
140 const double mergeRelationsThreshold = OptionsCont::getOptions().getFloat("osm.merge-relations");
141 // create polygons from relations
142 if (mergeRelationsThreshold >= 0) {
143 for (PCOSMRelation* rel : relations) {
144 if (!rel->keep || rel->myWays.empty()) {
145 continue;
146 }
147 // filter unknown and empty ways
148 int numNodes = 0;
149 for (auto it = rel->myWays.begin(); it != rel->myWays.end();) {
150 if (edges.count(*it) == 0 || edges[*it]->myCurrentNodes.empty()) {
151 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 edges[*it]->standalone = true;
157 it = rel->myWays.erase(it);
158 } else {
159 numNodes += (int)edges[*it]->myCurrentNodes.size();
160 it++;
161 }
162 }
163 if (numNodes == 0) {
164 WRITE_WARNINGF(TL("Could not import polygon from relation '%' (missing ways)"), rel->id);
165 continue;
166 }
167 PCOSMEdge* e = new PCOSMEdge();
168 e->id = rel->id;
169 e->name = rel->name;
170 e->myAttributes = rel->myAttributes;
171 e->myIsClosed = false;
172 e->standalone = true;
173
174 std::vector<std::vector<long long int> > snippets;
175 for (const long long int wayID : rel->myWays) {
176 PCOSMEdge* edge = edges[wayID];
177 snippets.push_back(edge->myCurrentNodes);
178 }
179 double maxDist = 0.;
180 bool ok = true;
181 while (snippets.size() > 1) {
182 maxDist = MAX2(maxDist, mergeClosest(nodes, snippets));
183 if (maxDist > mergeRelationsThreshold) {
184 ok = false;
185 break;
186 }
187 }
188 if (ok) {
189 e->myCurrentNodes = snippets.front();
190 edges[e->id] = e;
191 double frontBackDist = 0;
192 if (e->myCurrentNodes.front() != e->myCurrentNodes.back()) {
193 // should be filled
194 const Position posFront = convertNodePosition(nodes[e->myCurrentNodes.front()]);
195 const Position posBack = convertNodePosition(nodes[e->myCurrentNodes.back()]);
196 frontBackDist = posFront.distanceTo2D(posBack);
197 if (frontBackDist < mergeRelationsThreshold) {
198 e->myCurrentNodes.push_back(e->myCurrentNodes.front());
199 frontBackDist = 0;
200 }
201 }
202 std::string frontBackMsg = "";
203 if (frontBackDist > 0) {
204 frontBackMsg = TLF(", (front-to-back dist: %)", frontBackDist);
205 }
206 WRITE_MESSAGEF(TL("Assembled polygon from relation '%' (name:%)%"), toString(rel->id), e->name, frontBackMsg);
207 } else {
208 WRITE_WARNINGF(TL("Could not import polygon from relation '%' (name:% reason: found gap of %m)."), rel->id, rel->name, maxDist)
209 delete e;
210 // export ways by themselves
211 for (long long int wayID : rel->myWays) {
212 PCOSMEdge* part = edges[wayID];
213 part->standalone = true;
214 }
215 }
216 }
217 }
218
219 // instantiate polygons
220 for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
221 PCOSMEdge* e = (*i).second;
222 if (e->myAttributes.size() == 0) {
223 // cannot be relevant as a polygon
224 continue;
225 }
226 if (!e->standalone && mergeRelationsThreshold >= 0) {
227 // part of a relation
228 continue;
229 }
230 if (e->myCurrentNodes.size() == 0) {
231 WRITE_WARNINGF(TL("Polygon '%' has no shape."), toString(e->id));
232 continue;
233 }
234 // compute shape
235 PositionVector vec;
236 for (std::vector<long long int>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
237 PCOSMNode* n = nodes.find(*j)->second;
238 Position pos(n->lon, n->lat);
239 if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
240 WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), e->id);
241 }
242 vec.push_back_noDoublePos(pos);
243 }
244 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 std::string unknownPolyType = "";
248 bool isInner = mergeRelationsThreshold >= 0 && innerEdges.count(e->id) != 0 && tm.has("inner");
249 for (std::map<std::string, std::string>::iterator it = e->myAttributes.begin(); it != e->myAttributes.end(); ++it) {
250 const std::string& key = it->first;
251 const std::string& value = it->second;
252 const std::string fullType = key + "." + value;
253 if (tm.has(key + "." + value)) {
254 auto def = tm.get(isInner ? "inner" : fullType);
255 index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
256 } else if (tm.has(key)) {
257 auto def = tm.get(isInner ? "inner" : key);
258 index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
259 } else if (MyKeysToInclude.count(key) > 0) {
260 unknownPolyType = fullType;
261 }
262 }
263 const PCTypeMap::TypeDef& def = tm.getDefault();
264 if (index == 0 && !def.discard && unknownPolyType != "") {
265 addPolygon(e, vec, def, unknownPolyType, index, useName, toFill, ignorePruning, withAttributes);
266 }
267 }
268
269
270 // instantiate pois
271 for (std::map<long long int, PCOSMNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) {
272 PCOSMNode* n = (*i).second;
273 if (n->myAttributes.size() == 0) {
274 // cannot be relevant as a poi
275 continue;
276 }
277 Position pos(n->lon, n->lat);
278 if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
279 WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), n->id);
280 }
281 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 std::string unKnownPOIType = "";
285 for (std::map<std::string, std::string>::iterator it = n->myAttributes.begin(); it != n->myAttributes.end(); ++it) {
286 const std::string& key = it->first;
287 const std::string& value = it->second;
288 const std::string fullType = key + "." + value;
289 if (tm.has(key + "." + value)) {
290 index = addPOI(n, pos, tm.get(fullType), fullType, index, useName, toFill, ignorePruning, withAttributes);
291 } else if (tm.has(key)) {
292 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 if (index == 0 && !def.discard && unKnownPOIType != "") {
299 addPOI(n, pos, def, unKnownPOIType, index, useName, toFill, ignorePruning, withAttributes);
300 }
301 }
302 // delete nodes
303 for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
304 delete (*i).second;
305 }
306 // delete edges
307 for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
308 delete (*i).second;
309 }
310 // delete relations
311 for (Relations::iterator i = relations.begin(); i != relations.end(); ++i) {
312 delete (*i);
313 }
314}
315
316
323
324
325double
326PCLoaderOSM::parseHeight(const std::map<std::string, std::string>& attrs, long long int id) {
327 auto itH = attrs.find("height");
328 if (itH != attrs.end()) {
329 try {
330 return StringUtils::parseDist(itH->second);
331 } catch (...) {
332 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in way '%'."), "height", itH->second, id);
333 }
334 }
336}
337
338
339int
340PCLoaderOSM::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 if (def.discard) {
342 return index;
343 } else {
344 const bool closedShape = vec.front() == vec.back();
345 const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
346 const std::string id = def.prefix + (useName && edge->name != "" ? edge->name : toString(edge->id)) + idSuffix;
347 bool fill = def.allowFill == PCTypeMap::Filltype::FORCE || (def.allowFill == PCTypeMap::Filltype::FILL && closedShape);
348 SUMOPolygon* poly = new SUMOPolygon(
350 StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
351 def.color, vec, false, fill, 1, def.layer,
355 parseHeight(edge->myAttributes, edge->id));
356 if (withAttributes) {
357 poly->updateParameters(edge->myAttributes);
358 }
359 if (!toFill.add(poly, ignorePruning)) {
360 return index;
361 } else {
362 return index + 1;
363 }
364 }
365}
366
367
368int
369PCLoaderOSM::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 if (def.discard) {
372 return index;
373 } else {
374 const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
375 const std::string id = def.prefix + (useName && node->name != "" ? node->name : toString(node->id)) + idSuffix;
378 StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
379 def.color, pos, false, "", 0, false, 0, def.icon, def.layer);
380 if (withAttributes) {
381 poi->updateParameters(node->myAttributes);
382 }
383 if (!toFill.add(poi, ignorePruning)) {
384 return index;
385 } else {
386 return index + 1;
387 }
388 }
389}
390
391
392// ---------------------------------------------------------------------------
393// definitions of PCLoaderOSM::NodesHandler-methods
394// ---------------------------------------------------------------------------
395PCLoaderOSM::NodesHandler::NodesHandler(std::map<long long int, PCOSMNode*>& toFill,
396 bool withAttributes, MsgHandler& errorHandler) :
397 SUMOSAXHandler("osm - file"), myWithAttributes(withAttributes), myErrorHandler(errorHandler),
398 myToFill(toFill), myLastNodeID(-1) {}
399
400
402
403
404void
406 myParentElements.push_back(element);
407 if (element == SUMO_TAG_NODE) {
408 bool ok = true;
409 long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
410 if (!ok) {
411 return;
412 }
413 myLastNodeID = -1;
414 if (myToFill.find(id) == myToFill.end()) {
415 myLastNodeID = id;
416 // assume we are loading multiple files...
417 // ... so we won't report duplicate nodes
418 PCOSMNode* toAdd = new PCOSMNode();
419 toAdd->id = id;
420 toAdd->lon = attrs.get<double>(SUMO_ATTR_LON, toString(id).c_str(), ok);
421 toAdd->lat = attrs.get<double>(SUMO_ATTR_LAT, toString(id).c_str(), ok);
422 if (!ok) {
423 delete toAdd;
424 return;
425 }
426 myToFill[toAdd->id] = toAdd;
427 }
428 }
429 if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_NODE
430 && myLastNodeID != -1) {
431 bool ok = true;
432 std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, "", false);
433 std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "", false);
434 if (key == "name") {
435 myToFill[myLastNodeID]->name = value;
436 } else if (key == "") {
437 myErrorHandler.inform("Empty key in a a tag while parsing node '" + toString(myLastNodeID) + "' occurred.");
438 ok = false;
439 }
440 if (!ok) {
441 return;
442 }
443 myToFill[myLastNodeID]->myAttributes[key] = value;
444 }
445}
446
447
448void
450 if (element == SUMO_TAG_NODE) {
451 myLastNodeID = -1;
452 }
453 myParentElements.pop_back();
454}
455
456
457// ---------------------------------------------------------------------------
458// definitions of PCLoaderOSM::RelationsHandler-methods
459// ---------------------------------------------------------------------------
461 Relations& relations,
462 std::set<long long int>& innerEdges,
463 bool withAttributes,
464 MsgHandler& errorHandler) :
465 SUMOSAXHandler("osm - file"),
466 myAdditionalWays(additionalWays),
467 myRelations(relations),
468 myInnerEdges(innerEdges),
469 myWithAttributes(withAttributes),
470 myErrorHandler(errorHandler),
471 myCurrentRelation(nullptr) {
472}
473
474
477
478
479void
481 myParentElements.push_back(element);
482 // parse "relation" elements
483 if (element == SUMO_TAG_RELATION) {
484 myCurrentWays.clear();
485 bool ok = true;
486 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
487 if (action == "delete" || !ok) {
488 myCurrentRelation = nullptr;
489 } else {
490 myCurrentRelation = new PCOSMRelation();
491 myCurrentRelation->keep = false;
492 myCurrentRelation->id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
493 myRelations.push_back(myCurrentRelation);
494 }
495 return;
496 } else if (myCurrentRelation == nullptr) {
497 return;
498 }
499 // parse member elements
500 if (element == SUMO_TAG_MEMBER) {
501 bool ok = true;
502 std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
503 long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
504 if (role == "outer" || role == "inner") {
505 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
506 if (memberType == "way") {
507 myCurrentWays.push_back(ref);
508 if (role == "inner") {
509 myInnerEdges.insert(ref);
510 }
511 }
512 }
513 return;
514 }
515 // parse values
516 if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_RELATION
517 && myCurrentRelation != nullptr) {
518 bool ok = true;
519 std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, "", false);
520 std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, "", false);
521 if (key == "") {
522 myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentRelation) + "' occurred.");
523 ok = false;
524 }
525 if (!ok) {
526 return;
527 }
528 if (key == "name") {
529 myCurrentRelation->name = value;
530 } else if (MyKeysToInclude.count(key) > 0) {
531 myCurrentRelation->keep = true;
532 for (std::vector<long long int>::iterator it = myCurrentWays.begin(); it != myCurrentWays.end(); ++it) {
533 myAdditionalWays[*it] = myCurrentRelation;
534 }
535 }
536 myCurrentRelation->myAttributes[key] = value;
537 }
538}
539
540
541void
543 myParentElements.pop_back();
544 if (element == SUMO_TAG_RELATION) {
545 myCurrentRelation->myWays = myCurrentWays;
546 myCurrentRelation = nullptr;
547 myCurrentWays.clear();
548 }
549}
550
551
552// ---------------------------------------------------------------------------
553// definitions of PCLoaderOSM::EdgesHandler-methods
554// ---------------------------------------------------------------------------
555PCLoaderOSM::EdgesHandler::EdgesHandler(const std::map<long long int, PCOSMNode*>& osmNodes,
556 EdgeMap& toFill,
557 const RelationsMap& additionalWays,
558 bool withAttributes, MsgHandler& errorHandler) :
559 SUMOSAXHandler("osm - file"),
560 myWithAttributes(withAttributes),
561 myErrorHandler(errorHandler),
562 myOSMNodes(osmNodes),
563 myEdgeMap(toFill),
564 myAdditionalWays(additionalWays) {
565}
566
567
570
571
572void
574 myParentElements.push_back(element);
575 // parse "way" elements
576 if (element == SUMO_TAG_WAY) {
577 bool ok = true;
578 const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
579 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
580 if (action == "delete" || !ok) {
581 myCurrentEdge = nullptr;
582 return;
583 }
584 myCurrentEdge = new PCOSMEdge();
585 myCurrentEdge->id = id;
586 myCurrentEdge->myIsClosed = false;
587 myCurrentEdge->standalone = false;
588 myKeep = (myAdditionalWays.find(id) != myAdditionalWays.end());
589 }
590 // parse "nd" (node) elements
591 if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
592 bool ok = true;
593 const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
594 if (ok) {
595 if (myOSMNodes.find(ref) == myOSMNodes.end()) {
596 WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), ref);
597 return;
598 }
599 myCurrentEdge->myCurrentNodes.push_back(ref);
600 }
601 }
602 // parse values
603 if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY
604 && myCurrentEdge != nullptr) {
605 bool ok = true;
606 std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, "", false);
607 std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, "", false);
608 if (key == "") {
609 myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentEdge->id) + "' occurred.");
610 ok = false;
611 }
612 if (!ok) {
613 return;
614 }
615 if (key == "name") {
616 myCurrentEdge->name = value;
617 } else if (MyKeysToInclude.count(key) > 0) {
618 myKeep = true;
619 myCurrentEdge->standalone = true;
620 }
621 myCurrentEdge->myAttributes[key] = value;
622 }
623}
624
625
626void
628 myParentElements.pop_back();
629 if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
630 if (myKeep) {
631 RelationsMap::const_iterator it = myAdditionalWays.find(myCurrentEdge->id);
632 if (it != myAdditionalWays.end()) {
633 myCurrentEdge->myAttributes.insert((*it).second->myAttributes.begin(), (*it).second->myAttributes.end());
634 }
635 myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
636 } else {
637 delete myCurrentEdge;
638 }
639 myCurrentEdge = nullptr;
640 }
641}
642
643
644double
645PCLoaderOSM::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 for (int i = 0; i < (int)snippets.size(); i++) {
653 for (int j = i + 1; j < (int)snippets.size(); j++) {
654 Position front1(convertNodePosition(nodes.find(snippets[i].front())->second));
655 Position back1(convertNodePosition(nodes.find(snippets[i].back())->second));
656 Position front2(convertNodePosition(nodes.find(snippets[j].front())->second));
657 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 if (dist1 < best) {
663 best = dist1;
664 best_i = i;
665 best_j = j;
666 iFW = false;
667 jFW = true;
668 }
669 if (dist2 < best) {
670 best = dist2;
671 best_i = i;
672 best_j = j;
673 iFW = false;
674 jFW = false;
675 }
676 if (dist3 < best) {
677 best = dist3;
678 best_i = i;
679 best_j = j;
680 iFW = true;
681 jFW = true;
682 }
683 if (dist4 < best) {
684 best = dist4;
685 best_i = i;
686 best_j = j;
687 iFW = true;
688 jFW = false;
689 }
690 }
691 }
692 std::vector<long long int> merged;
693 if (iFW) {
694 merged.insert(merged.end(), snippets[best_i].begin(), snippets[best_i].end());
695 } else {
696 merged.insert(merged.end(), snippets[best_i].rbegin(), snippets[best_i].rend());
697 }
698 if (jFW) {
699 merged.insert(merged.end(), snippets[best_j].begin(), snippets[best_j].end());
700 } else {
701 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 snippets.push_back(merged);
706 return best;
707}
708
709/****************************************************************************/
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_MESSAGEF(...)
Definition MsgHandler.h:289
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define PROGRESS_BEGIN_TIME_MESSAGE(msg)
Definition MsgHandler.h:292
#define TL(string)
Definition MsgHandler.h:304
#define PROGRESS_TIME_MESSAGE(before)
Definition MsgHandler.h:293
#define TLF(string,...)
Definition MsgHandler.h:306
@ SUMO_TAG_MEMBER
@ SUMO_TAG_ND
@ SUMO_TAG_WAY
@ SUMO_TAG_NODE
alternative definition for junction
@ SUMO_TAG_RELATION
@ SUMO_TAG_TAG
@ SUMO_ATTR_LON
@ SUMO_ATTR_V
@ SUMO_ATTR_REF
@ SUMO_ATTR_LAT
@ SUMO_ATTR_TYPE
@ SUMO_ATTR_ID
@ SUMO_ATTR_ACTION
@ SUMO_ATTR_K
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
static bool isReadable(std::string path)
Checks whether the given file is readable.
bool x2cartesian(Position &from, bool includeInBoundary=true)
Converts the given coordinate into a cartesian and optionally update myConvBoundary.
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
A storage for options typed value containers)
Definition OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
bool isInStringVector(const std::string &optionName, const std::string &itemName) const
Returns the named option is a list of string values containing the specified item.
A class which extracts OSM-edges from a parsed OSM-file.
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
void myEndElement(int element)
Called when a closing tag occurs.
EdgesHandler(const std::map< long long int, PCOSMNode * > &osmNodes, EdgeMap &toFill, const RelationsMap &additionalWays, bool withAttributes, MsgHandler &errorHandler)
Constructor.
A class which extracts OSM-nodes from a parsed OSM-file.
NodesHandler(std::map< long long int, PCOSMNode * > &toFill, bool withAttributes, MsgHandler &errorHandler)
Contructor.
void myEndElement(int element)
Called when a closing tag occurs.
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
A class which extracts relevant way-ids from relations in a parsed OSM-file.
void myEndElement(int element)
Called when a closing tag occurs.
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
RelationsHandler(RelationsMap &additionalWays, Relations &relations, std::set< long long int > &innerEdges, bool withAttributes, MsgHandler &errorHandler)
Constructor.
static int 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)
try add the polygon and return the next index on success
std::map< long long int, PCOSMEdge * > EdgeMap
static Position convertNodePosition(PCOSMNode *n)
retrieve cartesian coordinate for given node
static int addPOI(const PCOSMNode *node, const Position &pos, const PCTypeMap::TypeDef &def, const std::string &fullType, int index, bool useName, PCPolyContainer &toFill, bool ignorePruning, bool withAttributes)
try add the POI and return the next index on success
static double mergeClosest(const std::map< long long int, PCOSMNode * > &nodes, std::vector< std::vector< long long int > > &snippets)
static void loadIfSet(OptionsCont &oc, PCPolyContainer &toFill, PCTypeMap &tm)
Loads pois/polygons assumed to be stored as OSM-XML.
std::vector< PCOSMRelation * > Relations
static const std::set< std::string > MyKeysToInclude
std::map< long long int, PCOSMRelation * > RelationsMap
static double parseHeight(const std::map< std::string, std::string > &attrs, long long int id)
static std::set< std::string > initMyKeysToInclude()
A storage for loaded polygons and pois.
bool add(SUMOPolygon *poly, bool ignorePruning=false)
Adds a polygon to the storage.
A storage for type mappings.
Definition PCTypeMap.h:42
const TypeDef & getDefault()
get the default type according to the given options
Definition PCTypeMap.h:116
const TypeDef & get(const std::string &id)
Returns a type definition.
Definition PCTypeMap.cpp:70
bool has(const std::string &id)
Returns the information whether the named type is known.
Definition PCTypeMap.cpp:76
void updateParameters(const Parameterised::Map &mapArg)
Adds or updates all given parameters from the map.
A point-of-interest.
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:273
A list of positions.
void push_back_noDoublePos(const Position &p)
insert in back a non double position
Encapsulated SAX-Attributes.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
virtual std::string getStringSecure(int id, const std::string &def) const =0
Returns the string-value of the named (by its enum-value) attribute.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
SAX-handler base for SUMO-files.
static const double DEFAULT_HEIGHT
Definition Shape.h:50
static const std::string DEFAULT_IMG_FILE
Definition Shape.h:47
static const double DEFAULT_ANGLE
Definition Shape.h:46
static const std::string DEFAULT_NAME
Definition Shape.h:51
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
static double parseDist(const std::string &sData)
parse a distance, length or width value with a unit
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false, const bool isRoute=false, const bool isExternal=false, const bool catchExceptions=true)
Runs the given handler on the given file; returns if everything's ok.
An internal definition of a loaded edge.
bool myIsClosed
Information whether this area is closed.
long long int id
The edge's id.
std::map< std::string, std::string > myAttributes
Additional attributes.
std::vector< long long int > myCurrentNodes
The list of nodes this edge is made of.
std::string name
The edge's name (if any)
An internal representation of an OSM-node.
Definition PCLoaderOSM.h:68
double lat
The latitude the node is located at.
Definition PCLoaderOSM.h:74
double lon
The longitude the node is located at.
Definition PCLoaderOSM.h:72
std::string name
The nodes name (if any)
Definition PCLoaderOSM.h:76
long long int id
The node's id.
Definition PCLoaderOSM.h:70
std::map< std::string, std::string > myAttributes
Additional attributes.
Definition PCLoaderOSM.h:78
An internal definition of a loaded relation.
Definition PCLoaderOSM.h:84
A single definition of values that shall be used for a given type.
Definition PCTypeMap.h:61
std::string icon
the icon to use
Definition PCTypeMap.h:69
bool discard
Information whether polygons of this type shall be discarded.
Definition PCTypeMap.h:77
std::string prefix
The prefix to use.
Definition PCTypeMap.h:67
double layer
The layer to use.
Definition PCTypeMap.h:71
std::string id
The new type id to use.
Definition PCTypeMap.h:63
RGBColor color
The color to use.
Definition PCTypeMap.h:65
Filltype allowFill
Information whether polygons of this type can be filled.
Definition PCTypeMap.h:79