R package for downloading OpenStreetMap data
at main 571 lines 23 kB view raw
1/*************************************************************************** 2 * Project: osmdata 3 * File: osmdatap.h 4 * Language: C++ 5 * 6 * osmdata is free software: you can redistribute it and/or modify it under 7 * the terms of the GNU General Public License as published by the Free 8 * Software Foundation, either version 3 of the License, or (at your option) 9 * any later version. 10 * 11 * osmdata is distributed in the hope that it will be useful, but WITHOUT ANY 12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 * details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * osm-router. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * Author: Mark Padgham / Andrew Smith 20 * E-Mail: mark.padgham@email.com / andrew@casacazaz.net 21 * 22 * Description: Class definition of XmlData 23 * 24 * Limitations: 25 * 26 * Dependencies: none (rapidXML header included in osmdata) 27 * 28 * Compiler Options: -std=c++11 29 ***************************************************************************/ 30 31#pragma once 32 33#include <Rcpp.h> 34 35#include "common.h" 36#include "get-bbox.h" 37#include "trace-osm.h" 38#include "convert-osm-rcpp.h" 39 40// sf::st_crs(4326)$wkt 41const std::string wkt = 42"GEOGCRS[\"WGS 84\",\n\ 43 ENSEMBLE[\"World Geodetic System 1984 ensemble\",\n\ 44 MEMBER[\"World Geodetic System 1984 (Transit)\"],\n\ 45 MEMBER[\"World Geodetic System 1984 (G730)\"],\n\ 46 MEMBER[\"World Geodetic System 1984 (G873)\"],\n\ 47 MEMBER[\"World Geodetic System 1984 (G1150)\"],\n\ 48 MEMBER[\"World Geodetic System 1984 (G1674)\"],\n\ 49 MEMBER[\"World Geodetic System 1984 (G1762)\"],\n\ 50 ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n\ 51 LENGTHUNIT[\"metre\",1]],\n\ 52 ENSEMBLEACCURACY[2.0]],\n\ 53 PRIMEM[\"Greenwich\",0,\n\ 54 ANGLEUNIT[\"degree\",0.0174532925199433]],\n\ 55 CS[ellipsoidal,2],\n\ 56 AXIS[\"geodetic latitude (Lat)\",north,\n\ 57 ORDER[1],\n\ 58 ANGLEUNIT[\"degree\",0.0174532925199433]],\n\ 59 AXIS[\"geodetic longitude (Lon)\",east,\n\ 60 ORDER[2],\n\ 61 ANGLEUNIT[\"degree\",0.0174532925199433]],\n\ 62 USAGE[\n\ 63 SCOPE[\"Horizontal component of 3D system.\"],\n\ 64 AREA[\"World.\"],\n\ 65 BBOX[-90,-180,90,180]],\n\ 66 ID[\"EPSG\",4326]]"; 67 68const Rcpp::CharacterVector metanames = {"_version", "_timestamp", "_changeset", "_uid", "_user"}; 69const Rcpp::CharacterVector centernames = {"_lat", "_lon"}; 70 71/************************************************************************ 72 ************************************************************************ 73 ** ** 74 ** STRUCTURE OF THESE FILES ** 75 ** ** 76 ************************************************************************ 77 ************************************************************************ 78 * 79 * 1. osmdata.h = Class definition of XmlData that reads initial XML structure 80 * 2. trace_osm.h = Primary functions to trace ways and relations (pure C++) 81 * 2a. trace_multipolygon () 82 * 2b. trace_multilinestring () 83 * 2c. trace_way () 84 * 3. convert_osm_rcpp.h = Functions to convert C++ objects to Rcpp::List objects 85 * 3a. trace_way_nmat () (here coz it uses Rcpp) 86 * 3b. get_value_mat_way () 87 * 3c. get_value_mat_rel () 88 * 3d. convert_poly_linestring_to_Rcpp () 89 * 3e. restructure_kv_mat () 90 * 4. osmdata.cpp 91 * 5c. get_osm_relations () 92 * 5d. get_osm_ways () 93 * 5e. get_osm_nodes () 94 * 5a. rcpp_osmdata () - The final Rcpp function called by osmdata_sf 95 * 96 * ---------------------------------------------------------------------- 97 * 98 * The calling hierarchy extends generally from bottom to top as follows: 99 * rcpp_osmdata () { 100 * -> get_osm_relations () 101 * { 102 * -> trace_multipolygon () 103 * -> trace_way () 104 * -> restructure_kv_mat 105 * -> trace_multilinestring () 106 * -> trace_way () 107 * -> restructure_kv_mat 108 * -> get_value_vec () 109 * -> convert_poly_linestring_to_Rcpp () 110 * -> [... most check and clean functions ...] 111 * } 112 * -> get_osm_ways () 113 * { 114 * -> trace_way_nmat () 115 * -> get_value_mat_way () 116 * -> restructure_kv_mat 117 * } 118 * -> get_osm_nodes () 119 * -> restructure_kv_mat 120 * } 121 */ 122 123/************************************************************************ 124 ************************************************************************ 125 ** ** 126 ** CLASS::XMLDATA ** 127 ** ** 128 ************************************************************************ 129 ************************************************************************/ 130 131 132class XmlData 133{ 134 private: 135 136 Nodes m_nodes; 137 Ways m_ways; 138 Relations m_relations; 139 UniqueVals m_unique; 140 141 public: 142 143 double xmin = DOUBLE_MAX, xmax = -DOUBLE_MAX, 144 ymin = DOUBLE_MAX, ymax = -DOUBLE_MAX; 145 146 XmlData (const std::string& str) 147 { 148 // APS empty m_nodes/m_ways/m_relations constructed here, no need to explicitly clear 149 XmlDocPtr p = parseXML (str); 150 traverseWays (p->first_node ()); 151 make_key_val_indices (); 152 } 153 154 // APS make the dtor virtual since compiler support for "final" is limited 155 virtual ~XmlData () 156 { 157 // APS m_nodes/m_ways/m_relations destructed here, no need to explicitly clear 158 } 159 160 // Const accessors for members 161 const Nodes& nodes() const { return m_nodes; } 162 const Ways& ways() const { return m_ways; } 163 const Relations& relations() const { return m_relations; } 164 const UniqueVals& unique_vals() const { return m_unique; } 165 double x_min() { return xmin; } 166 double x_max() { return xmax; } 167 double y_min() { return ymin; } 168 double y_max() { return ymax; } 169 170 private: 171 172 void traverseWays (XmlNodePtr pt); 173 void traverseRelation (XmlNodePtr pt, RawRelation& rrel); 174 void traverseWay (XmlNodePtr pt, RawWay& rway); 175 void traverseNode (XmlNodePtr pt, RawNode& rnode); 176 void make_key_val_indices (); 177 178}; // end Class::XmlData 179 180 181/************************************************************************ 182 ************************************************************************ 183 ** ** 184 ** FUNCTION::TRAVERSEWAYS ** 185 ** ** 186 ************************************************************************ 187 ************************************************************************/ 188 189inline void XmlData::traverseWays (XmlNodePtr pt) 190{ 191 RawRelation rrel; 192 RawWay rway; 193 Relation relation; 194 OneWay way; 195 RawNode rnode; 196 Node node; 197 198 for (XmlNodePtr it = pt->first_node (); it != nullptr; 199 it = it->next_sibling()) 200 { 201 if (!strcmp (it->name(), "node")) 202 { 203 rnode.key.clear (); 204 rnode.value.clear (); 205 206 traverseNode (it, rnode); 207 if (rnode.key.size () != rnode.value.size ()) 208 throw std::runtime_error ("sizes of keys and values differ"); 209 210 // Only insert unique nodes 211 if (m_unique.id_node.find (rnode.id) == m_unique.id_node.end ()) 212 { 213 if (rnode.lon < xmin) xmin = rnode.lon; 214 if (rnode.lon > xmax) xmax = rnode.lon; 215 if (rnode.lat < ymin) ymin = rnode.lat; 216 if (rnode.lat > ymax) ymax = rnode.lat; 217 m_unique.id_node.insert (rnode.id); 218 node.id = rnode.id; 219 node.lat = rnode.lat; 220 node.lon = rnode.lon; 221 node.key_val.clear (); 222 for (size_t i=0; i<rnode.key.size (); i++) 223 { 224 node.key_val.insert (std::make_pair 225 (rnode.key [i], rnode.value [i])); 226 m_unique.k_point.insert (rnode.key [i]); // only inserts unique keys 227 } 228 // metadata: 229 node._version = rnode._version; 230 node._changeset = rnode._changeset; 231 node._timestamp = rnode._timestamp; 232 node._uid = rnode._uid; 233 node._user = rnode._user; 234 235 m_nodes.insert (std::make_pair (node.id, node)); 236 } 237 } 238 else if (!strcmp (it->name(), "way")) 239 { 240 rway.key.clear (); 241 rway.value.clear (); 242 rway.nodes.clear (); 243 244 traverseWay (it, rway); 245 if (rway.key.size () != rway.value.size ()) 246 throw std::runtime_error ("sizes of keys and values differ"); 247 248 if (m_unique.id_way.find (rway.id) == m_unique.id_way.end ()) 249 { 250 m_unique.id_way.insert (rway.id); 251 way.id = rway.id; 252 way.key_val.clear(); 253 way.nodes.clear(); 254 for (size_t i=0; i<rway.key.size (); i++) 255 { 256 way.key_val.insert (std::make_pair 257 (rway.key [i], rway.value [i])); 258 m_unique.k_way.insert (rway.key [i]); 259 } 260 // metadata: 261 way._version = rway._version; 262 way._changeset = rway._changeset; 263 way._timestamp = rway._timestamp; 264 way._uid = rway._uid; 265 way._user = rway._user; 266 // center: 267 way._lat = rway._lat; 268 way._lon = rway._lon; 269 270 // Then copy nodes from rway to way. 271 way.nodes.swap (rway.nodes); 272 m_ways.insert (std::make_pair (way.id, way)); 273 } 274 } 275 else if (!strcmp (it->name(), "relation")) 276 { 277 rrel.key.clear(); 278 rrel.value.clear(); 279 rrel.role_way.clear(); 280 rrel.role_node.clear(); 281 rrel.ways.clear(); 282 rrel.nodes.clear(); 283 rrel.member_type = ""; 284 rrel.ispoly = false; 285 286 traverseRelation (it, rrel); 287 if (rrel.key.size () != rrel.value.size ()) 288 throw std::runtime_error ("sizes of keys and values differ"); 289 if (rrel.ways.size () != rrel.role_way.size ()) 290 throw std::runtime_error ("size of ways and roles differ"); 291 if (rrel.nodes.size () != rrel.role_node.size ()) 292 throw std::runtime_error ("size of nodes and roles differ"); 293 294 if (m_unique.id_rel.find (rrel.id) == m_unique.id_rel.end ()) 295 { 296 m_unique.id_rel.insert (rrel.id); 297 relation.id = rrel.id; 298 relation.key_val.clear(); 299 relation.ways.clear(); 300 relation.ispoly = rrel.ispoly; 301 for (size_t i=0; i<rrel.key.size (); i++) 302 { 303 relation.key_val.insert (std::make_pair (rrel.key [i], 304 rrel.value [i])); 305 m_unique.k_rel.insert (rrel.key [i]); 306 if (rrel.key [i] == "type") 307 relation.rel_type = rrel.value [i]; 308 } 309 for (size_t i=0; i<rrel.ways.size (); i++) 310 relation.ways.push_back (std::make_pair (rrel.ways [i], 311 rrel.role_way [i])); 312 for (size_t i=0; i<rrel.nodes.size (); i++) 313 relation.nodes.push_back (std::make_pair (rrel.nodes [i], 314 rrel.role_node [i])); 315 // metadata: 316 relation._version = rrel._version; 317 relation._changeset = rrel._changeset; 318 relation._timestamp = rrel._timestamp; 319 relation._uid = rrel._uid; 320 relation._user = rrel._user; 321 // center: 322 relation._lat = rrel._lat; 323 relation._lon = rrel._lon; 324 325 m_relations.push_back (relation); 326 } 327 } 328 else 329 { 330 traverseWays (it); 331 } 332 } 333 334} // end function XmlData::traverseWays 335 336 337/************************************************************************ 338 ************************************************************************ 339 ** ** 340 ** FUNCTION::TRAVERSERELATION ** 341 ** ** 342 ************************************************************************ 343 ************************************************************************/ 344 345inline void XmlData::traverseRelation (XmlNodePtr pt, RawRelation& rrel) 346{ 347 for (XmlAttrPtr it = pt->first_attribute (); it != nullptr; 348 it = it->next_attribute()) 349 { 350 if (!strcmp (it->name(), "k")) 351 rrel.key.push_back (it->value()); 352 else if (!strcmp (it->name(), "v")) 353 rrel.value.push_back (it->value()); 354 else if (!strcmp (it->name(), "id")) 355 rrel.id = std::stoll(it->value()); 356 else if (!strcmp (it->name(), "type")) 357 rrel.member_type = it->value (); 358 else if (!strcmp (it->name(), "ref")) 359 { 360 if (rrel.member_type == "node") 361 rrel.nodes.push_back (std::stoll (it->value ())); 362 else if (rrel.member_type == "way") 363 rrel.ways.push_back (std::stoll (it->value ())); 364 else if (rrel.member_type == "relation") 365 rrel.relations.push_back (std::stoll (it->value ())); 366 else 367 throw std::runtime_error ("unknown member_type"); 368 } else if (!strcmp (it->name(), "role")) 369 { 370 if (rrel.member_type == "node") 371 rrel.role_node.push_back (it->value ()); 372 else if (rrel.member_type == "way") 373 rrel.role_way.push_back (it->value ()); 374 else if (rrel.member_type == "relation") 375 rrel.role_relation.push_back (it->value ()); 376 else 377 throw std::runtime_error ("unknown member_type"); 378 // Not all OSM Multipolygons have (key="type", 379 // value="multipolygon"): For example, (key="type", 380 // value="boundary") are often multipolygons. The things they all 381 // have are "inner" and "outer" roles. 382 if (!strcmp (it->value(), "inner") || !strcmp (it->value(), "outer")) 383 rrel.ispoly = true; 384 } else if (!strcmp (it->name(), "version")) 385 rrel._version = it->value(); 386 else if (!strcmp (it->name(), "timestamp")) 387 rrel._timestamp = it->value(); 388 else if (!strcmp (it->name(), "changeset")) 389 rrel._changeset = it->value(); 390 else if (!strcmp (it->name(), "uid")) 391 rrel._uid = it->value(); 392 else if (!strcmp (it->name(), "user")) 393 rrel._user = it->value(); 394 else if (!strcmp (it->name(), "lat")) 395 rrel._lat = std::stod(it->value()); 396 else if (!strcmp (it->name(), "lon")) 397 rrel._lon = std::stod(it->value()); 398 } 399 // allows for >1 child nodes 400 for (XmlNodePtr it = pt->first_node(); it != nullptr; it = it->next_sibling()) 401 { 402 traverseRelation (it, rrel); 403 } 404} // end function XmlData::traverseRelation 405 406 407/************************************************************************ 408 ************************************************************************ 409 ** ** 410 ** FUNCTION::TRAVERSEWAY ** 411 ** ** 412 ************************************************************************ 413 ************************************************************************/ 414 415inline void XmlData::traverseWay (XmlNodePtr pt, RawWay& rway) 416{ 417 for (XmlAttrPtr it = pt->first_attribute (); it != nullptr; 418 it = it->next_attribute()) 419 { 420 if (!strcmp (it->name(), "k")) 421 rway.key.push_back (it->value()); 422 else if (!strcmp (it->name(), "v")) 423 rway.value.push_back (it->value()); 424 else if (!strcmp (it->name(), "id")) 425 rway.id = std::stoll(it->value()); 426 else if (!strcmp (it->name(), "ref")) 427 rway.nodes.push_back (std::stoll(it->value())); 428 else if (!strcmp (it->name(), "version")) 429 rway._version = it->value(); 430 else if (!strcmp (it->name(), "timestamp")) 431 rway._timestamp = it->value(); 432 else if (!strcmp (it->name(), "changeset")) 433 rway._changeset = it->value(); 434 else if (!strcmp (it->name(), "uid")) 435 rway._uid = it->value(); 436 else if (!strcmp (it->name(), "user")) 437 rway._user = it->value(); 438 else if (!strcmp (it->name(), "lat")) 439 rway._lat = std::stod(it->value()); 440 else if (!strcmp (it->name(), "lon")) 441 rway._lon = std::stod(it->value()); 442 } 443 // allows for >1 child nodes 444 for (XmlNodePtr it = pt->first_node(); it != nullptr; it = it->next_sibling()) 445 { 446 traverseWay (it, rway); 447 } 448} // end function XmlData::traverseWay 449 450 451/************************************************************************ 452 ************************************************************************ 453 ** ** 454 ** FUNCTION::TRAVERSENODE ** 455 ** ** 456 ************************************************************************ 457 ************************************************************************/ 458 459inline void XmlData::traverseNode (XmlNodePtr pt, RawNode& rnode) 460{ 461 for (XmlAttrPtr it = pt->first_attribute (); it != nullptr; 462 it = it->next_attribute()) 463 { 464 if (!strcmp (it->name(), "id")) 465 rnode.id = std::stoll(it->value()); 466 else if (!strcmp (it->name(), "lat")) 467 rnode.lat = std::stod(it->value()); 468 else if (!strcmp (it->name(), "lon")) 469 rnode.lon = std::stod(it->value()); 470 else if (!strcmp (it->name(), "k")) 471 rnode.key.push_back (it->value ()); 472 else if (!strcmp (it->name(), "v")) 473 rnode.value.push_back (it->value ()); 474 else if (!strcmp (it->name(), "version")) // metadata 475 rnode._version = it->value (); 476 else if (!strcmp (it->name(), "timestamp")) // metadata 477 rnode._timestamp = it->value (); 478 else if (!strcmp (it->name(), "changeset")) // metadata 479 rnode._changeset = it->value (); 480 else if (!strcmp (it->name(), "uid")) // metadata 481 rnode._uid = it->value (); 482 else if (!strcmp (it->name(), "user")) // metadata 483 rnode._user = it->value (); 484 } 485 // allows for >1 child nodes 486 for (XmlNodePtr it = pt->first_node(); it != nullptr; it = it->next_sibling()) 487 { 488 traverseNode (it, rnode); 489 } 490} // end function XmlData::traverseNode 491 492inline void XmlData::make_key_val_indices () 493{ 494 // These are std::maps which enable keys to be mapped directly onto their 495 // column number in the key-val matrices 496 unsigned int i = 0; 497 for (auto m: m_unique.k_point) 498 m_unique.k_point_index.insert (std::make_pair (m, i++)); 499 500 i = 0; 501 for (auto m: m_unique.k_way) 502 m_unique.k_way_index.insert (std::make_pair (m, i++)); 503 504 i = 0; 505 for (auto m: m_unique.k_rel) 506 m_unique.k_rel_index.insert (std::make_pair (m, i++)); 507} 508 509/*---------------------------- fn headers -----------------------------*/ 510 511namespace osm_sf { 512 513Rcpp::List get_osm_relations (const Relations &rels, 514 const std::map <osmid_t, Node> &nodes, 515 const std::map <osmid_t, OneWay> &ways, const UniqueVals &unique_vals, 516 const Rcpp::NumericVector &bbox, const Rcpp::List &crs); 517void get_osm_ways (Rcpp::List &wayList, Rcpp::DataFrame &kv_df, 518 Rcpp::DataFrame &meta_df, 519 const std::set <osmid_t> &way_ids, const Ways &ways, const Nodes &nodes, 520 const UniqueVals &unique_vals, const std::string &geom_type, 521 const Rcpp::NumericVector &bbox, const Rcpp::List &crs); 522void get_osm_nodes (Rcpp::List &ptList, Rcpp::DataFrame &kv_df, 523 Rcpp::DataFrame &meta_df, 524 const Nodes &nodes, const UniqueVals &unique_vals, 525 const Rcpp::NumericVector &bbox, const Rcpp::List &crs); 526 527} // end namespace osm_sf 528 529Rcpp::List rcpp_osmdata_sf (const std::string& st); 530 531namespace osm_sp { 532 533void get_osm_nodes (Rcpp::S4 &sp_points, const Nodes &nodes, 534 const UniqueVals &unique_vals); 535void get_osm_ways (Rcpp::S4 &sp_ways, 536 const std::set <osmid_t> &way_ids, const Ways &ways, const Nodes &nodes, 537 const UniqueVals &unique_vals, const std::string &geom_type); 538void get_osm_relations (Rcpp::S4 &multilines, Rcpp::S4 &multipolygons, 539 const Relations &rels, const std::map <osmid_t, Node> &nodes, 540 const std::map <osmid_t, OneWay> &ways, const UniqueVals &unique_vals); 541 542} // end namespace osm_sp 543 544Rcpp::List rcpp_osmdata_sp (const std::string& st); 545 546namespace osm_sc { 547 548void get_osm_relations (Rcpp::DataFrame &rel_df, Rcpp::DataFrame &kv_df, 549 const Relations &rels); 550void get_osm_ways (Rcpp::DataFrame &edge, 551 Rcpp::DataFrame &object_link_edge, Rcpp::DataFrame &kv_df, 552 const Ways &ways); 553void get_osm_nodes (Rcpp::DataFrame &node_df, Rcpp::DataFrame &kv_df, 554 const Nodes &nodes); 555 556} // end namespace osm_sc 557 558Rcpp::List rcpp_osmdata_sc (const std::string& st); 559 560namespace osm_df { 561 562Rcpp::List get_osm_relations (const Relations &rels, 563 const UniqueVals &unique_vals); 564Rcpp::List get_osm_ways (const std::set <osmid_t> &way_ids, 565 const Ways &ways, const UniqueVals &unique_vals); 566Rcpp::List get_osm_nodes (const Nodes &nodes, 567 const UniqueVals &unique_vals); 568 569} // end namespace osm_df 570 571Rcpp::List rcpp_osmdata_df (const std::string& st);