LCOV - code coverage report
Current view: top level - src/polyconvert - PCLoaderOSM.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 339 352 96.3 %
Date: 2024-04-27 15:34:54 Functions: 17 21 81.0 %

          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             : /****************************************************************************/

Generated by: LCOV version 1.14