LCOV - code coverage report
Current view: top level - src/polyconvert - PCLoaderOSM.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.6 % 349 337
Test Date: 2024-12-21 15:45:41 Functions: 81.0 % 21 17

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2008-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    PCLoaderOSM.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Christoph Sommer
      18              : /// @author  Michael Behrisch
      19              : /// @author  Melanie Knocke
      20              : /// @date    Wed, 19.11.2008
      21              : ///
      22              : // A reader of pois and polygons stored in OSM-format
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <string>
      27              : #include <map>
      28              : #include <fstream>
      29              : #include <utils/common/UtilExceptions.h>
      30              : #include <utils/common/MsgHandler.h>
      31              : #include <utils/common/ToString.h>
      32              : #include <utils/common/StringUtils.h>
      33              : #include <utils/common/StdDefs.h>
      34              : #include <utils/common/SysUtils.h>
      35              : #include <utils/common/RGBColor.h>
      36              : #include <utils/geom/GeomHelper.h>
      37              : #include <utils/geom/Position.h>
      38              : #include <utils/geom/GeoConvHelper.h>
      39              : #include <utils/xml/XMLSubSys.h>
      40              : #include <utils/geom/GeomConvHelper.h>
      41              : #include <utils/common/FileHelpers.h>
      42              : #include <utils/options/OptionsCont.h>
      43              : #include <utils/options/Option.h>
      44              : #include <polyconvert/PCPolyContainer.h>
      45              : #include "PCLoaderOSM.h"
      46              : 
      47              : // static members
      48              : // ---------------------------------------------------------------------------
      49              : const std::set<std::string> PCLoaderOSM::MyKeysToInclude(PCLoaderOSM::initMyKeysToInclude());
      50              : 
      51              : // ===========================================================================
      52              : // method definitions
      53              : // ===========================================================================
      54              : // ---------------------------------------------------------------------------
      55              : // static interface
      56              : // ---------------------------------------------------------------------------
      57           49 : std::set<std::string> PCLoaderOSM::initMyKeysToInclude() {
      58              :     std::set<std::string> result;
      59           49 :     result.insert("highway");
      60           49 :     result.insert("railway");
      61           49 :     result.insert("railway:position");
      62           49 :     result.insert("railway:position:exact");
      63           49 :     result.insert("waterway");
      64           49 :     result.insert("aeroway");
      65           49 :     result.insert("aerialway");
      66           49 :     result.insert("power");
      67           49 :     result.insert("man_made");
      68           49 :     result.insert("building");
      69           49 :     result.insert("leisure");
      70           49 :     result.insert("amenity");
      71           49 :     result.insert("shop");
      72           49 :     result.insert("tourism");
      73           49 :     result.insert("historic");
      74           49 :     result.insert("landuse");
      75           49 :     result.insert("natural");
      76           49 :     result.insert("military");
      77           49 :     result.insert("boundary");
      78           49 :     result.insert("admin_level");
      79           49 :     result.insert("sport");
      80           49 :     result.insert("polygon");
      81           49 :     result.insert("place");
      82           49 :     result.insert("population");
      83           49 :     result.insert("barrier");
      84           49 :     result.insert("openGeoDB:population");
      85           49 :     result.insert("openGeoDB:name");
      86           49 :     return result;
      87              : }
      88              : 
      89              : void
      90           42 : PCLoaderOSM::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill, PCTypeMap& tm) {
      91           84 :     if (!oc.isSet("osm-files")) {
      92           19 :         return;
      93              :     }
      94              :     // parse file(s)
      95           46 :     std::vector<std::string> files = oc.getStringVector("osm-files");
      96              :     // load nodes, first
      97              :     std::map<long long int, PCOSMNode*> nodes;
      98           23 :     bool withAttributes = oc.getBool("all-attributes");
      99           24 :     MsgHandler* m = OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance();
     100           23 :     NodesHandler nodesHandler(nodes, withAttributes, *m);
     101           45 :     for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
     102              :         // nodes
     103           46 :         if (!FileHelpers::isReadable(*file)) {
     104            0 :             WRITE_ERRORF(TL("Could not open osm-file '%'."), *file);
     105              :             return;
     106              :         }
     107           69 :         const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
     108           23 :         if (!XMLSubSys::runParser(nodesHandler, *file)) {
     109            6 :             for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
     110           10 :                 delete (*i).second;
     111              :             }
     112            1 :             throw ProcessError();
     113              :         }
     114           22 :         PROGRESS_TIME_MESSAGE(before);
     115              :     }
     116              :     // load relations to see which additional ways may be relevant
     117              :     Relations relations;
     118              :     RelationsMap additionalWays;
     119              :     std::set<long long int> innerEdges;
     120           22 :     RelationsHandler relationsHandler(additionalWays, relations, innerEdges, withAttributes, *m);
     121           44 :     for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
     122              :         // edges
     123           66 :         const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing relations from osm-file '" + *file + "'");
     124           22 :         XMLSubSys::runParser(relationsHandler, *file);
     125           22 :         PROGRESS_TIME_MESSAGE(before);
     126              :     }
     127              : 
     128              :     // load ways
     129              :     EdgeMap edges;
     130           22 :     EdgesHandler edgesHandler(nodes, edges, additionalWays, withAttributes, *m);
     131           44 :     for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
     132              :         // edges
     133           66 :         const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing edges from osm-file '" + *file + "'");
     134           22 :         XMLSubSys::runParser(edgesHandler, *file);
     135           22 :         PROGRESS_TIME_MESSAGE(before);
     136              :     }
     137              : 
     138              :     // build all
     139           22 :     const bool useName = oc.getBool("osm.use-name");
     140           22 :     const double mergeRelationsThreshold = OptionsCont::getOptions().getFloat("osm.merge-relations");
     141              :     // create polygons from relations
     142           22 :     if (mergeRelationsThreshold >= 0) {
     143          458 :         for (PCOSMRelation* rel : relations) {
     144          454 :             if (!rel->keep || rel->myWays.empty()) {
     145          313 :                 continue;
     146              :             }
     147              :             // filter unknown and empty ways
     148              :             int numNodes = 0;
     149         2304 :             for (auto it = rel->myWays.begin(); it != rel->myWays.end();) {
     150          487 :                 if (edges.count(*it) == 0 || edges[*it]->myCurrentNodes.empty()) {
     151         1669 :                     it = rel->myWays.erase(it);
     152              :                 } else if (innerEdges.count(*it) > 0) {
     153              :                     // @note: it would be a good idea to merge inner shapes but
     154              :                     // it's difficult since there may be more than one
     155              :                     // independent inner shape
     156          271 :                     edges[*it]->standalone = true;
     157          271 :                     it = rel->myWays.erase(it);
     158              :                 } else {
     159          216 :                     numNodes += (int)edges[*it]->myCurrentNodes.size();
     160              :                     it++;
     161              :                 }
     162              :             }
     163          148 :             if (numNodes == 0) {
     164            7 :                 WRITE_WARNINGF(TL("Could not import polygon from relation '%' (missing ways)"), rel->id);
     165            7 :                 continue;
     166              :             }
     167          141 :             PCOSMEdge* e = new PCOSMEdge();
     168          141 :             e->id = rel->id;
     169          141 :             e->name = rel->name;
     170              :             e->myAttributes = rel->myAttributes;
     171          141 :             e->myIsClosed = false;
     172          141 :             e->standalone = true;
     173              : 
     174              :             std::vector<std::vector<long long int> > snippets;
     175          357 :             for (const long long int wayID : rel->myWays) {
     176          216 :                 PCOSMEdge* edge = edges[wayID];
     177          216 :                 snippets.push_back(edge->myCurrentNodes);
     178              :             }
     179              :             double maxDist = 0.;
     180              :             bool ok = true;
     181          214 :             while (snippets.size() > 1) {
     182           75 :                 maxDist = MAX2(maxDist, mergeClosest(nodes, snippets));
     183           75 :                 if (maxDist > mergeRelationsThreshold) {
     184              :                     ok = false;
     185              :                     break;
     186              :                 }
     187              :             }
     188          141 :             if (ok) {
     189          139 :                 e->myCurrentNodes = snippets.front();
     190          139 :                 edges[e->id] = e;
     191              :                 double frontBackDist = 0;
     192          139 :                 if (e->myCurrentNodes.front() != e->myCurrentNodes.back()) {
     193              :                     // should be filled
     194            9 :                     const Position posFront = convertNodePosition(nodes[e->myCurrentNodes.front()]);
     195            9 :                     const Position posBack = convertNodePosition(nodes[e->myCurrentNodes.back()]);
     196              :                     frontBackDist = posFront.distanceTo2D(posBack);
     197            9 :                     if (frontBackDist < mergeRelationsThreshold) {
     198            0 :                         e->myCurrentNodes.push_back(e->myCurrentNodes.front());
     199              :                         frontBackDist = 0;
     200              :                     }
     201              :                 }
     202          139 :                 std::string frontBackMsg = "";
     203          139 :                 if (frontBackDist > 0) {
     204           18 :                     frontBackMsg = TLF(", (front-to-back dist: %)", frontBackDist);
     205              :                 }
     206          417 :                 WRITE_MESSAGEF(TL("Assembled polygon from relation '%' (name:%)%"), toString(rel->id), e->name, frontBackMsg);
     207              :             } else {
     208            6 :                 WRITE_WARNINGF(TL("Could not import polygon from relation '%' (name:% reason: found gap of %m)."), rel->id, rel->name, maxDist)
     209            2 :                 delete e;
     210              :                 // export ways by themselves
     211           10 :                 for (long long int wayID : rel->myWays) {
     212            8 :                     PCOSMEdge* part = edges[wayID];
     213            8 :                     part->standalone = true;
     214              :                 }
     215              :             }
     216          141 :         }
     217              :     }
     218              : 
     219              :     // instantiate polygons
     220         5168 :     for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
     221         5146 :         PCOSMEdge* e = (*i).second;
     222         5146 :         if (e->myAttributes.size() == 0) {
     223              :             // cannot be relevant as a polygon
     224          169 :             continue;
     225              :         }
     226         5146 :         if (!e->standalone && mergeRelationsThreshold >= 0) {
     227              :             // part of a relation
     228          167 :             continue;
     229              :         }
     230         4979 :         if (e->myCurrentNodes.size() == 0) {
     231            4 :             WRITE_WARNINGF(TL("Polygon '%' has no shape."), toString(e->id));
     232            2 :             continue;
     233              :         }
     234              :         // compute shape
     235         4977 :         PositionVector vec;
     236        52576 :         for (std::vector<long long int>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
     237        47599 :             PCOSMNode* n = nodes.find(*j)->second;
     238        47599 :             Position pos(n->lon, n->lat);
     239        47599 :             if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
     240            0 :                 WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), e->id);
     241              :             }
     242        47599 :             vec.push_back_noDoublePos(pos);
     243              :         }
     244         9954 :         const bool ignorePruning = OptionsCont::getOptions().isInStringVector("prune.keep-list", toString(e->id));
     245              :         // add as many polygons as keys match defined types
     246              :         int index = 0;
     247         4977 :         std::string unknownPolyType = "";
     248        10051 :         bool isInner = mergeRelationsThreshold >= 0 && innerEdges.count(e->id) != 0 && tm.has("inner");
     249        30990 :         for (std::map<std::string, std::string>::iterator it = e->myAttributes.begin(); it != e->myAttributes.end(); ++it) {
     250        26013 :             const std::string& key = it->first;
     251              :             const std::string& value = it->second;
     252        26013 :             const std::string fullType = key + "." + value;
     253        78039 :             if (tm.has(key + "." + value)) {
     254          494 :                 auto def = tm.get(isInner ? "inner" : fullType);
     255          252 :                 index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
     256        26013 :             } else if (tm.has(key)) {
     257         9656 :                 auto def = tm.get(isInner ? "inner" : key);
     258         5024 :                 index = addPolygon(e, vec, def, fullType, index, useName, toFill, ignorePruning, withAttributes);
     259         5024 :             } else if (MyKeysToInclude.count(key) > 0) {
     260              :                 unknownPolyType = fullType;
     261              :             }
     262              :         }
     263              :         const PCTypeMap::TypeDef& def = tm.getDefault();
     264         4977 :         if (index == 0 && !def.discard && unknownPolyType != "") {
     265           11 :             addPolygon(e, vec, def, unknownPolyType, index, useName, toFill, ignorePruning, withAttributes);
     266              :         }
     267         4977 :     }
     268              : 
     269              : 
     270              :     // instantiate pois
     271        41735 :     for (std::map<long long int, PCOSMNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) {
     272        41713 :         PCOSMNode* n = (*i).second;
     273        41713 :         if (n->myAttributes.size() == 0) {
     274              :             // cannot be relevant as a poi
     275        34695 :             continue;
     276              :         }
     277         7018 :         Position pos(n->lon, n->lat);
     278         7018 :         if (!GeoConvHelper::getProcessing().x2cartesian(pos)) {
     279            0 :             WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), n->id);
     280              :         }
     281        14036 :         const bool ignorePruning = OptionsCont::getOptions().isInStringVector("prune.keep-list", toString(n->id));
     282              :         // add as many POIs as keys match defined types
     283              :         int index = 0;
     284         7018 :         std::string unKnownPOIType = "";
     285        40978 :         for (std::map<std::string, std::string>::iterator it = n->myAttributes.begin(); it != n->myAttributes.end(); ++it) {
     286        33960 :             const std::string& key = it->first;
     287              :             const std::string& value = it->second;
     288        33960 :             const std::string fullType = key + "." + value;
     289       101880 :             if (tm.has(key + "." + value)) {
     290           44 :                 index = addPOI(n, pos, tm.get(fullType), fullType, index, useName, toFill, ignorePruning, withAttributes);
     291        33916 :             } else if (tm.has(key)) {
     292         3780 :                 index = addPOI(n, pos, tm.get(key), fullType, index, useName, toFill, ignorePruning, withAttributes);
     293              :             } else if (MyKeysToInclude.count(key) > 0) {
     294              :                 unKnownPOIType = fullType;
     295              :             }
     296              :         }
     297              :         const PCTypeMap::TypeDef& def = tm.getDefault();
     298         7018 :         if (index == 0 && !def.discard && unKnownPOIType != "") {
     299            0 :             addPOI(n, pos, def, unKnownPOIType, index, useName, toFill, ignorePruning, withAttributes);
     300              :         }
     301              :     }
     302              :     // delete nodes
     303        41735 :     for (std::map<long long int, PCOSMNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
     304        83426 :         delete (*i).second;
     305              :     }
     306              :     // delete edges
     307         5168 :     for (EdgeMap::iterator i = edges.begin(); i != edges.end(); ++i) {
     308         5146 :         delete (*i).second;
     309              :     }
     310              :     // delete relations
     311          511 :     for (Relations::iterator i = relations.begin(); i != relations.end(); ++i) {
     312          489 :         delete (*i);
     313              :     }
     314           46 : }
     315              : 
     316              : 
     317              : Position
     318            0 : PCLoaderOSM::convertNodePosition(PCOSMNode* n) {
     319           18 :     Position pos(n->lon, n->lat);
     320        29458 :     GeoConvHelper::getProcessing().x2cartesian(pos);
     321           18 :     return pos;
     322              : }
     323              : 
     324              : 
     325              : int
     326         5287 : PCLoaderOSM::addPolygon(const PCOSMEdge* edge, const PositionVector& vec, const PCTypeMap::TypeDef& def, const std::string& fullType, int index, bool useName, PCPolyContainer& toFill, bool ignorePruning, bool withAttributes) {
     327         5287 :     if (def.discard) {
     328         2801 :         return index;
     329              :     } else {
     330              :         const bool closedShape = vec.front() == vec.back();
     331         2486 :         const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
     332         2486 :         const std::string id = def.prefix + (useName && edge->name != "" ? edge->name : toString(edge->id)) + idSuffix;
     333         2486 :         bool fill = def.allowFill == PCTypeMap::Filltype::FORCE || (def.allowFill == PCTypeMap::Filltype::FILL && closedShape);
     334              :         SUMOPolygon* poly = new SUMOPolygon(
     335         4972 :             StringUtils::escapeXML(id),
     336         2486 :             StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
     337         4972 :             def.color, vec, false, fill, 1, def.layer);
     338         2486 :         if (withAttributes) {
     339           71 :             poly->updateParameters(edge->myAttributes);
     340              :         }
     341         2486 :         if (!toFill.add(poly, ignorePruning)) {
     342              :             return index;
     343              :         } else {
     344         2486 :             return index + 1;
     345              :         }
     346              :     }
     347              : }
     348              : 
     349              : 
     350              : int
     351         3824 : PCLoaderOSM::addPOI(const PCOSMNode* node, const Position& pos, const PCTypeMap::TypeDef& def, const std::string& fullType,
     352              :                     int index, bool useName, PCPolyContainer& toFill, bool ignorePruning, bool withAttributes) {
     353         3824 :     if (def.discard) {
     354         1038 :         return index;
     355              :     } else {
     356         2786 :         const std::string idSuffix = (index == 0 ? "" : "#" + toString(index));
     357         2786 :         const std::string id = def.prefix + (useName && node->name != "" ? node->name : toString(node->id)) + idSuffix;
     358              :         PointOfInterest* poi = new PointOfInterest(
     359         5572 :             StringUtils::escapeXML(id),
     360         5572 :             StringUtils::escapeXML(OptionsCont::getOptions().getBool("osm.keep-full-type") ? fullType : def.id),
     361         5572 :             def.color, pos, false, "", 0, false, 0, def.icon, def.layer);
     362         2786 :         if (withAttributes) {
     363           44 :             poi->updateParameters(node->myAttributes);
     364              :         }
     365         2786 :         if (!toFill.add(poi, ignorePruning)) {
     366              :             return index;
     367              :         } else {
     368         2782 :             return index + 1;
     369              :         }
     370              :     }
     371              : }
     372              : 
     373              : 
     374              : // ---------------------------------------------------------------------------
     375              : // definitions of PCLoaderOSM::NodesHandler-methods
     376              : // ---------------------------------------------------------------------------
     377           23 : PCLoaderOSM::NodesHandler::NodesHandler(std::map<long long int, PCOSMNode*>& toFill,
     378           23 :                                         bool withAttributes, MsgHandler& errorHandler) :
     379           23 :     SUMOSAXHandler("osm - file"), myWithAttributes(withAttributes), myErrorHandler(errorHandler),
     380           46 :     myToFill(toFill), myLastNodeID(-1) {}
     381              : 
     382              : 
     383           23 : PCLoaderOSM::NodesHandler::~NodesHandler() {}
     384              : 
     385              : 
     386              : void
     387       213659 : PCLoaderOSM::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     388       213659 :     myParentElements.push_back(element);
     389       213659 :     if (element == SUMO_TAG_NODE) {
     390        41718 :         bool ok = true;
     391        41718 :         long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
     392        41718 :         if (!ok) {
     393            0 :             return;
     394              :         }
     395        41718 :         myLastNodeID = -1;
     396        83436 :         if (myToFill.find(id) == myToFill.end()) {
     397        41718 :             myLastNodeID = id;
     398              :             // assume we are loading multiple files...
     399              :             //  ... so we won't report duplicate nodes
     400        41718 :             PCOSMNode* toAdd = new PCOSMNode();
     401        41718 :             toAdd->id = id;
     402        41718 :             toAdd->lon = attrs.get<double>(SUMO_ATTR_LON, toString(id).c_str(), ok);
     403        41718 :             toAdd->lat = attrs.get<double>(SUMO_ATTR_LAT, toString(id).c_str(), ok);
     404        41718 :             if (!ok) {
     405            0 :                 delete toAdd;
     406            0 :                 return;
     407              :             }
     408        41718 :             myToFill[toAdd->id] = toAdd;
     409              :         }
     410              :     }
     411        63180 :     if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_NODE
     412       247624 :             && myLastNodeID != -1) {
     413        33965 :         bool ok = true;
     414        67930 :         std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, "", false);
     415        67930 :         std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "", false);
     416        33965 :         if (key == "name") {
     417         1770 :             myToFill[myLastNodeID]->name = value;
     418        32195 :         } else if (key == "") {
     419            4 :             myErrorHandler.inform("Empty key in a a tag while parsing node '" + toString(myLastNodeID) + "' occurred.");
     420            2 :             ok = false;
     421              :         }
     422        33965 :         if (!ok) {
     423              :             return;
     424              :         }
     425        33963 :         myToFill[myLastNodeID]->myAttributes[key] = value;
     426              :     }
     427              : }
     428              : 
     429              : 
     430              : void
     431       213659 : PCLoaderOSM::NodesHandler::myEndElement(int element) {
     432       213659 :     if (element == SUMO_TAG_NODE) {
     433        41718 :         myLastNodeID = -1;
     434              :     }
     435              :     myParentElements.pop_back();
     436       213659 : }
     437              : 
     438              : 
     439              : // ---------------------------------------------------------------------------
     440              : // definitions of PCLoaderOSM::RelationsHandler-methods
     441              : // ---------------------------------------------------------------------------
     442           22 : PCLoaderOSM::RelationsHandler::RelationsHandler(RelationsMap& additionalWays,
     443              :         Relations& relations,
     444              :         std::set<long long int>& innerEdges,
     445              :         bool withAttributes,
     446           22 :         MsgHandler& errorHandler) :
     447              :     SUMOSAXHandler("osm - file"),
     448           22 :     myAdditionalWays(additionalWays),
     449           22 :     myRelations(relations),
     450           22 :     myInnerEdges(innerEdges),
     451           22 :     myWithAttributes(withAttributes),
     452           22 :     myErrorHandler(errorHandler),
     453           44 :     myCurrentRelation(nullptr) {
     454           22 : }
     455              : 
     456              : 
     457           22 : PCLoaderOSM::RelationsHandler::~RelationsHandler() {
     458           22 : }
     459              : 
     460              : 
     461              : void
     462       213640 : PCLoaderOSM::RelationsHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     463       213640 :     myParentElements.push_back(element);
     464              :     // parse "relation" elements
     465       213640 :     if (element == SUMO_TAG_RELATION) {
     466              :         myCurrentWays.clear();
     467          489 :         bool ok = true;
     468          489 :         const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
     469          489 :         if (action == "delete" || !ok) {
     470            0 :             myCurrentRelation = nullptr;
     471              :         } else {
     472          489 :             myCurrentRelation = new PCOSMRelation();
     473              :             myCurrentRelation->keep = false;
     474          489 :             myCurrentRelation->id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
     475          489 :             myRelations.push_back(myCurrentRelation);
     476              :         }
     477              :         return;
     478       213151 :     } else if (myCurrentRelation == nullptr) {
     479              :         return;
     480              :     }
     481              :     // parse member elements
     482        52919 :     if (element == SUMO_TAG_MEMBER) {
     483        48978 :         bool ok = true;
     484       146934 :         std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
     485        48978 :         long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
     486        48978 :         if (role == "outer" || role == "inner") {
     487         2423 :             std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
     488         2423 :             if (memberType == "way") {
     489         2423 :                 myCurrentWays.push_back(ref);
     490         2423 :                 if (role == "inner") {
     491          325 :                     myInnerEdges.insert(ref);
     492              :                 }
     493              :             }
     494              :         }
     495              :         return;
     496              :     }
     497              :     // parse values
     498         3941 :     if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_RELATION
     499         3941 :             && myCurrentRelation != nullptr) {
     500         3941 :         bool ok = true;
     501         7882 :         std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, "", false);
     502         7882 :         std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, "", false);
     503         3941 :         if (key == "") {
     504            0 :             myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentRelation) + "' occurred.");
     505            0 :             ok = false;
     506              :         }
     507         3941 :         if (!ok) {
     508              :             return;
     509              :         }
     510         3941 :         if (key == "name") {
     511          262 :             myCurrentRelation->name = value;
     512              :         } else if (MyKeysToInclude.count(key) > 0) {
     513          191 :             myCurrentRelation->keep = true;
     514         4414 :             for (std::vector<long long int>::iterator it = myCurrentWays.begin(); it != myCurrentWays.end(); ++it) {
     515         4223 :                 myAdditionalWays[*it] = myCurrentRelation;
     516              :             }
     517              :         }
     518         3941 :         myCurrentRelation->myAttributes[key] = value;
     519              :     }
     520              : }
     521              : 
     522              : 
     523              : void
     524       213640 : PCLoaderOSM::RelationsHandler::myEndElement(int element) {
     525              :     myParentElements.pop_back();
     526       213640 :     if (element == SUMO_TAG_RELATION) {
     527          489 :         myCurrentRelation->myWays = myCurrentWays;
     528          489 :         myCurrentRelation = nullptr;
     529              :         myCurrentWays.clear();
     530              :     }
     531       213640 : }
     532              : 
     533              : 
     534              : // ---------------------------------------------------------------------------
     535              : // definitions of PCLoaderOSM::EdgesHandler-methods
     536              : // ---------------------------------------------------------------------------
     537           22 : PCLoaderOSM::EdgesHandler::EdgesHandler(const std::map<long long int, PCOSMNode*>& osmNodes,
     538              :                                         EdgeMap& toFill,
     539              :                                         const RelationsMap& additionalWays,
     540           22 :                                         bool withAttributes, MsgHandler& errorHandler) :
     541              :     SUMOSAXHandler("osm - file"),
     542           22 :     myWithAttributes(withAttributes),
     543           22 :     myErrorHandler(errorHandler),
     544           22 :     myOSMNodes(osmNodes),
     545           22 :     myEdgeMap(toFill),
     546           44 :     myAdditionalWays(additionalWays) {
     547           22 : }
     548              : 
     549              : 
     550           22 : PCLoaderOSM::EdgesHandler::~EdgesHandler() {
     551           22 : }
     552              : 
     553              : 
     554              : void
     555       213640 : PCLoaderOSM::EdgesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     556       213640 :     myParentElements.push_back(element);
     557              :     // parse "way" elements
     558       213640 :     if (element == SUMO_TAG_WAY) {
     559         5761 :         bool ok = true;
     560         5761 :         const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
     561         5761 :         const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
     562         5761 :         if (action == "delete" || !ok) {
     563            1 :             myCurrentEdge = nullptr;
     564              :             return;
     565              :         }
     566         5760 :         myCurrentEdge = new PCOSMEdge();
     567         5760 :         myCurrentEdge->id = id;
     568              :         myCurrentEdge->myIsClosed = false;
     569              :         myCurrentEdge->standalone = false;
     570        11520 :         myKeep = (myAdditionalWays.find(id) != myAdditionalWays.end());
     571              :     }
     572              :     // parse "nd" (node) elements
     573       213639 :     if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
     574        53490 :         bool ok = true;
     575        53490 :         const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
     576        53490 :         if (ok) {
     577       106980 :             if (myOSMNodes.find(ref) == myOSMNodes.end()) {
     578          304 :                 WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), ref);
     579          304 :                 return;
     580              :             }
     581        53186 :             myCurrentEdge->myCurrentNodes.push_back(ref);
     582              :         }
     583              :     }
     584              :     // parse values
     585        63173 :     if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY
     586       238606 :             && myCurrentEdge != nullptr) {
     587        25270 :         bool ok = true;
     588        50540 :         std::string key = attrs.getOpt<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, "", false);
     589        50540 :         std::string value = attrs.getOpt<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, "", false);
     590        25270 :         if (key == "") {
     591            4 :             myErrorHandler.inform("Empty key in a a tag while parsing way '" + toString(myCurrentEdge->id) + "' occurred.");
     592            2 :             ok = false;
     593              :         }
     594        25270 :         if (!ok) {
     595              :             return;
     596              :         }
     597        25268 :         if (key == "name") {
     598         1253 :             myCurrentEdge->name = value;
     599              :         } else if (MyKeysToInclude.count(key) > 0) {
     600         4790 :             myKeep = true;
     601         4790 :             myCurrentEdge->standalone = true;
     602              :         }
     603        25268 :         myCurrentEdge->myAttributes[key] = value;
     604              :     }
     605              : }
     606              : 
     607              : 
     608              : void
     609       213640 : PCLoaderOSM::EdgesHandler::myEndElement(int element) {
     610              :     myParentElements.pop_back();
     611       213640 :     if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
     612         5760 :         if (myKeep) {
     613         5007 :             RelationsMap::const_iterator it = myAdditionalWays.find(myCurrentEdge->id);
     614         5007 :             if (it != myAdditionalWays.end()) {
     615          498 :                 myCurrentEdge->myAttributes.insert((*it).second->myAttributes.begin(), (*it).second->myAttributes.end());
     616              :             }
     617         5007 :             myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
     618              :         } else {
     619          753 :             delete myCurrentEdge;
     620              :         }
     621         5760 :         myCurrentEdge = nullptr;
     622              :     }
     623       213640 : }
     624              : 
     625              : 
     626              : double
     627           75 : PCLoaderOSM::mergeClosest(const std::map<long long int, PCOSMNode*>& nodes, std::vector<std::vector<long long int> >& snippets) {
     628              :     double best = std::numeric_limits<double>::max();
     629              :     int best_i = 0;
     630              :     int best_j = 1;
     631              :     bool iFW = true;
     632              :     bool jFW = true;
     633              : 
     634          841 :     for (int i = 0; i < (int)snippets.size(); i++) {
     635         8126 :         for (int j = i + 1; j < (int)snippets.size(); j++) {
     636        14720 :             Position front1(convertNodePosition(nodes.find(snippets[i].front())->second));
     637         7360 :             Position back1(convertNodePosition(nodes.find(snippets[i].back())->second));
     638        14720 :             Position front2(convertNodePosition(nodes.find(snippets[j].front())->second));
     639         7360 :             Position back2(convertNodePosition(nodes.find(snippets[j].back())->second));
     640              :             double dist1 = front1.distanceTo2D(front2);
     641              :             double dist2 = front1.distanceTo2D(back2);
     642              :             double dist3 = back1.distanceTo2D(front2);
     643              :             double dist4 = back1.distanceTo2D(back2);
     644         7360 :             if (dist1 < best) {
     645              :                 best = dist1;
     646              :                 best_i = i;
     647              :                 best_j = j;
     648              :                 iFW = false;
     649              :                 jFW = true;
     650              :             }
     651         7360 :             if (dist2 < best) {
     652              :                 best = dist2;
     653              :                 best_i = i;
     654              :                 best_j = j;
     655              :                 iFW = false;
     656              :                 jFW = false;
     657              :             }
     658         7360 :             if (dist3 < best) {
     659              :                 best = dist3;
     660              :                 best_i = i;
     661              :                 best_j = j;
     662              :                 iFW = true;
     663              :                 jFW = true;
     664              :             }
     665         7360 :             if (dist4 < best) {
     666              :                 best = dist4;
     667              :                 best_i = i;
     668              :                 best_j = j;
     669              :                 iFW = true;
     670              :                 jFW = false;
     671              :             }
     672              :         }
     673              :     }
     674              :     std::vector<long long int> merged;
     675           75 :     if (iFW) {
     676           55 :         merged.insert(merged.end(), snippets[best_i].begin(), snippets[best_i].end());
     677              :     } else {
     678           20 :         merged.insert(merged.end(), snippets[best_i].rbegin(), snippets[best_i].rend());
     679              :     }
     680           75 :     if (jFW) {
     681           54 :         merged.insert(merged.end(), snippets[best_j].begin(), snippets[best_j].end());
     682              :     } else {
     683           21 :         merged.insert(merged.end(), snippets[best_j].rbegin(), snippets[best_j].rend());
     684              :     }
     685              :     snippets.erase(snippets.begin() + best_j);
     686              :     snippets.erase(snippets.begin() + best_i);
     687           75 :     snippets.push_back(merged);
     688           75 :     return best;
     689           75 : }
     690              : 
     691              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1