Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/polyconvert/PCLoaderOSM.cpp
169666 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2008-2025 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
std::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
89
void
90
PCLoaderOSM::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
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");
99
MsgHandler* m = OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance();
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
317
Position
318
PCLoaderOSM::convertNodePosition(PCOSMNode* n) {
319
Position pos(n->lon, n->lat);
320
GeoConvHelper::getProcessing().x2cartesian(pos);
321
return pos;
322
}
323
324
325
int
326
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
if (def.discard) {
328
return index;
329
} else {
330
const bool closedShape = vec.front() == vec.back();
331
const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
332
const std::string id = def.prefix + (useName && edge->name != "" ? edge->name : toString(edge->id)) + idSuffix;
333
bool fill = def.allowFill == PCTypeMap::Filltype::FORCE || (def.allowFill == PCTypeMap::Filltype::FILL && closedShape);
334
SUMOPolygon* poly = new SUMOPolygon(
335
StringUtils::escapeXML(id),
336
StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
337
def.color, vec, false, fill, 1, def.layer);
338
if (withAttributes) {
339
poly->updateParameters(edge->myAttributes);
340
}
341
if (!toFill.add(poly, ignorePruning)) {
342
return index;
343
} else {
344
return index + 1;
345
}
346
}
347
}
348
349
350
int
351
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
if (def.discard) {
354
return index;
355
} else {
356
const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
357
const std::string id = def.prefix + (useName && node->name != "" ? node->name : toString(node->id)) + idSuffix;
358
PointOfInterest* poi = new PointOfInterest(
359
StringUtils::escapeXML(id),
360
StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
361
def.color, pos, false, "", 0, false, 0, def.icon, def.layer);
362
if (withAttributes) {
363
poi->updateParameters(node->myAttributes);
364
}
365
if (!toFill.add(poi, ignorePruning)) {
366
return index;
367
} else {
368
return index + 1;
369
}
370
}
371
}
372
373
374
// ---------------------------------------------------------------------------
375
// definitions of PCLoaderOSM::NodesHandler-methods
376
// ---------------------------------------------------------------------------
377
PCLoaderOSM::NodesHandler::NodesHandler(std::map<long long int, PCOSMNode*>& toFill,
378
bool withAttributes, MsgHandler& errorHandler) :
379
SUMOSAXHandler("osm - file"), myWithAttributes(withAttributes), myErrorHandler(errorHandler),
380
myToFill(toFill), myLastNodeID(-1) {}
381
382
383
PCLoaderOSM::NodesHandler::~NodesHandler() {}
384
385
386
void
387
PCLoaderOSM::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
388
myParentElements.push_back(element);
389
if (element == SUMO_TAG_NODE) {
390
bool ok = true;
391
long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
392
if (!ok) {
393
return;
394
}
395
myLastNodeID = -1;
396
if (myToFill.find(id) == myToFill.end()) {
397
myLastNodeID = id;
398
// assume we are loading multiple files...
399
// ... so we won't report duplicate nodes
400
PCOSMNode* toAdd = new PCOSMNode();
401
toAdd->id = id;
402
toAdd->lon = attrs.get<double>(SUMO_ATTR_LON, toString(id).c_str(), ok);
403
toAdd->lat = attrs.get<double>(SUMO_ATTR_LAT, toString(id).c_str(), ok);
404
if (!ok) {
405
delete toAdd;
406
return;
407
}
408
myToFill[toAdd->id] = toAdd;
409
}
410
}
411
if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_NODE
412
&& myLastNodeID != -1) {
413
bool ok = true;
414
std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, "", false);
415
std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "", false);
416
if (key == "name") {
417
myToFill[myLastNodeID]->name = value;
418
} else if (key == "") {
419
myErrorHandler.inform("Empty key in a a tag while parsing node '" + toString(myLastNodeID) + "' occurred.");
420
ok = false;
421
}
422
if (!ok) {
423
return;
424
}
425
myToFill[myLastNodeID]->myAttributes[key] = value;
426
}
427
}
428
429
430
void
431
PCLoaderOSM::NodesHandler::myEndElement(int element) {
432
if (element == SUMO_TAG_NODE) {
433
myLastNodeID = -1;
434
}
435
myParentElements.pop_back();
436
}
437
438
439
// ---------------------------------------------------------------------------
440
// definitions of PCLoaderOSM::RelationsHandler-methods
441
// ---------------------------------------------------------------------------
442
PCLoaderOSM::RelationsHandler::RelationsHandler(RelationsMap& additionalWays,
443
Relations& relations,
444
std::set<long long int>& innerEdges,
445
bool withAttributes,
446
MsgHandler& errorHandler) :
447
SUMOSAXHandler("osm - file"),
448
myAdditionalWays(additionalWays),
449
myRelations(relations),
450
myInnerEdges(innerEdges),
451
myWithAttributes(withAttributes),
452
myErrorHandler(errorHandler),
453
myCurrentRelation(nullptr) {
454
}
455
456
457
PCLoaderOSM::RelationsHandler::~RelationsHandler() {
458
}
459
460
461
void
462
PCLoaderOSM::RelationsHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
463
myParentElements.push_back(element);
464
// parse "relation" elements
465
if (element == SUMO_TAG_RELATION) {
466
myCurrentWays.clear();
467
bool ok = true;
468
const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
469
if (action == "delete" || !ok) {
470
myCurrentRelation = nullptr;
471
} else {
472
myCurrentRelation = new PCOSMRelation();
473
myCurrentRelation->keep = false;
474
myCurrentRelation->id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
475
myRelations.push_back(myCurrentRelation);
476
}
477
return;
478
} else if (myCurrentRelation == nullptr) {
479
return;
480
}
481
// parse member elements
482
if (element == SUMO_TAG_MEMBER) {
483
bool ok = true;
484
std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
485
long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
486
if (role == "outer" || role == "inner") {
487
std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
488
if (memberType == "way") {
489
myCurrentWays.push_back(ref);
490
if (role == "inner") {
491
myInnerEdges.insert(ref);
492
}
493
}
494
}
495
return;
496
}
497
// parse values
498
if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_RELATION
499
&& myCurrentRelation != nullptr) {
500
bool ok = true;
501
std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, "", false);
502
std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, "", false);
503
if (key == "") {
504
myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentRelation) + "' occurred.");
505
ok = false;
506
}
507
if (!ok) {
508
return;
509
}
510
if (key == "name") {
511
myCurrentRelation->name = value;
512
} else if (MyKeysToInclude.count(key) > 0) {
513
myCurrentRelation->keep = true;
514
for (std::vector<long long int>::iterator it = myCurrentWays.begin(); it != myCurrentWays.end(); ++it) {
515
myAdditionalWays[*it] = myCurrentRelation;
516
}
517
}
518
myCurrentRelation->myAttributes[key] = value;
519
}
520
}
521
522
523
void
524
PCLoaderOSM::RelationsHandler::myEndElement(int element) {
525
myParentElements.pop_back();
526
if (element == SUMO_TAG_RELATION) {
527
myCurrentRelation->myWays = myCurrentWays;
528
myCurrentRelation = nullptr;
529
myCurrentWays.clear();
530
}
531
}
532
533
534
// ---------------------------------------------------------------------------
535
// definitions of PCLoaderOSM::EdgesHandler-methods
536
// ---------------------------------------------------------------------------
537
PCLoaderOSM::EdgesHandler::EdgesHandler(const std::map<long long int, PCOSMNode*>& osmNodes,
538
EdgeMap& toFill,
539
const RelationsMap& additionalWays,
540
bool withAttributes, MsgHandler& errorHandler) :
541
SUMOSAXHandler("osm - file"),
542
myWithAttributes(withAttributes),
543
myErrorHandler(errorHandler),
544
myOSMNodes(osmNodes),
545
myEdgeMap(toFill),
546
myAdditionalWays(additionalWays) {
547
}
548
549
550
PCLoaderOSM::EdgesHandler::~EdgesHandler() {
551
}
552
553
554
void
555
PCLoaderOSM::EdgesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
556
myParentElements.push_back(element);
557
// parse "way" elements
558
if (element == SUMO_TAG_WAY) {
559
bool ok = true;
560
const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
561
const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
562
if (action == "delete" || !ok) {
563
myCurrentEdge = nullptr;
564
return;
565
}
566
myCurrentEdge = new PCOSMEdge();
567
myCurrentEdge->id = id;
568
myCurrentEdge->myIsClosed = false;
569
myCurrentEdge->standalone = false;
570
myKeep = (myAdditionalWays.find(id) != myAdditionalWays.end());
571
}
572
// parse "nd" (node) elements
573
if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
574
bool ok = true;
575
const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
576
if (ok) {
577
if (myOSMNodes.find(ref) == myOSMNodes.end()) {
578
WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), ref);
579
return;
580
}
581
myCurrentEdge->myCurrentNodes.push_back(ref);
582
}
583
}
584
// parse values
585
if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY
586
&& myCurrentEdge != nullptr) {
587
bool ok = true;
588
std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, "", false);
589
std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, "", false);
590
if (key == "") {
591
myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentEdge->id) + "' occurred.");
592
ok = false;
593
}
594
if (!ok) {
595
return;
596
}
597
if (key == "name") {
598
myCurrentEdge->name = value;
599
} else if (MyKeysToInclude.count(key) > 0) {
600
myKeep = true;
601
myCurrentEdge->standalone = true;
602
}
603
myCurrentEdge->myAttributes[key] = value;
604
}
605
}
606
607
608
void
609
PCLoaderOSM::EdgesHandler::myEndElement(int element) {
610
myParentElements.pop_back();
611
if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
612
if (myKeep) {
613
RelationsMap::const_iterator it = myAdditionalWays.find(myCurrentEdge->id);
614
if (it != myAdditionalWays.end()) {
615
myCurrentEdge->myAttributes.insert((*it).second->myAttributes.begin(), (*it).second->myAttributes.end());
616
}
617
myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
618
} else {
619
delete myCurrentEdge;
620
}
621
myCurrentEdge = nullptr;
622
}
623
}
624
625
626
double
627
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
for (int i = 0; i < (int)snippets.size(); i++) {
635
for (int j = i + 1; j < (int)snippets.size(); j++) {
636
Position front1(convertNodePosition(nodes.find(snippets[i].front())->second));
637
Position back1(convertNodePosition(nodes.find(snippets[i].back())->second));
638
Position front2(convertNodePosition(nodes.find(snippets[j].front())->second));
639
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
if (dist1 < best) {
645
best = dist1;
646
best_i = i;
647
best_j = j;
648
iFW = false;
649
jFW = true;
650
}
651
if (dist2 < best) {
652
best = dist2;
653
best_i = i;
654
best_j = j;
655
iFW = false;
656
jFW = false;
657
}
658
if (dist3 < best) {
659
best = dist3;
660
best_i = i;
661
best_j = j;
662
iFW = true;
663
jFW = true;
664
}
665
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
if (iFW) {
676
merged.insert(merged.end(), snippets[best_i].begin(), snippets[best_i].end());
677
} else {
678
merged.insert(merged.end(), snippets[best_i].rbegin(), snippets[best_i].rend());
679
}
680
if (jFW) {
681
merged.insert(merged.end(), snippets[best_j].begin(), snippets[best_j].end());
682
} else {
683
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
snippets.push_back(merged);
688
return best;
689
}
690
691
/****************************************************************************/
692
693