R package for downloading OpenStreetMap data
at main 653 lines 26 kB view raw
1/*************************************************************************** 2 * Project: osmdata 3 * File: osmdata-sf.cpp 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 <https://www.gnu.org/licenses/>. 18 * 19 * Author: Mark Padgham 20 * E-Mail: mark.padgham@email.com 21 * 22 * Description: Extract OSM data from an object of class XmlData and return 23 * it in Rcpp::List format. 24 * 25 * Limitations: 26 * 27 * Dependencies: none (rapidXML header included in osmdata) 28 * 29 * Compiler Options: -std=c++11 30 ***************************************************************************/ 31 32#include "osmdata.h" 33 34#include <Rcpp.h> 35 36// Note: This code uses explicit index counters within most loops which use Rcpp 37// objects, because these otherwise require a 38// static_cast <size_t> (std::distance (...)). This operation copies each 39// instance and can slow the loops down by several orders of magnitude! 40 41/************************************************************************ 42 ************************************************************************ 43 ** ** 44 ** 1. PRIMARY FUNCTIONS TO TRACE WAYS AND RELATIONS ** 45 ** ** 46 ************************************************************************ 47 ************************************************************************/ 48 49 50//' get_osm_relations 51//' 52//' Return a dual Rcpp::List containing all OSM relations, the first element of 53//' which holds `multipolygon` relations, while the second holds all others, 54//' which are stored as `multilinestring` objects. 55//' 56//' @param rels Pointer to the vector of Relation objects 57//' @param nodes Pointer to the vector of node objects 58//' @param ways Pointer to the vector of way objects 59//' @param unique_vals Pointer to a UniqueVals object containing std::sets of 60//' all unique IDs and keys for each kind of OSM object (nodes, ways, rels). 61//' 62//' @return A Rcpp::List which contains the geometry, tags and metadata of the 63//' multipolygon and multilinestring relations. 64//' 65//' @noRd 66Rcpp::List osm_sf::get_osm_relations (const Relations &rels, 67 const std::map <osmid_t, Node> &nodes, 68 const std::map <osmid_t, OneWay> &ways, const UniqueVals &unique_vals, 69 const Rcpp::NumericVector &bbox, const Rcpp::List &crs) 70{ 71 /* Trace all multipolygon relations. These are the only OSM types where 72 * sizes are not known before, so lat-lons and node names are stored in 73 * dynamic vectors. These are 3D monsters: #1 for relation, #2 for polygon 74 * in relation, and #3 for data. There are also associated 2D vector<vector> 75 * objects for IDs and multilinestring roles. */ 76 std::set <std::string> keyset; // must be ordered! 77 std::vector <std::string> colnames = {"lat", "lon"}, rownames; 78 Rcpp::List dimnames (0); 79 Rcpp::NumericMatrix nmat (Rcpp::Dimension (0, 0)); 80 81 double_arr2 lat_vec, lon_vec; 82 double_arr3 lat_arr_mp, lon_arr_mp, lon_arr_ls, lat_arr_ls; 83 string_arr2 rowname_vec, id_vec_mp, roles_ls; 84 string_arr3 rowname_arr_mp, rowname_arr_ls; 85 std::vector <osmid_t> ids_ls; 86 std::vector <std::string> ids_mp, rel_id_mp, rel_id_ls; 87 osmt_arr2 id_vec_ls; 88 std::vector <std::string> roles; 89 90 unsigned int nmp = 0, nls = 0; // number of multipolygon and multilinestringrelations 91 for (auto itr = rels.begin (); itr != rels.end (); ++itr) 92 { 93 if (itr->ispoly) 94 nmp++; 95 else 96 { 97 // TODO: Store these as std::vector <std::set <>> to avoid 98 // repetition below 99 std::set <std::string> roles_set; 100 for (auto itw = itr->ways.begin (); itw != itr->ways.end (); ++itw) 101 roles_set.insert (itw->second); 102 nls += roles_set.size (); 103 } 104 } 105 std::vector <bool> mp_okay (nmp); 106 std::fill (mp_okay.begin (), mp_okay.end (), true); 107 108 size_t ncol = unique_vals.k_rel.size (); 109 rel_id_mp.reserve (nmp); 110 rel_id_ls.reserve (nls); 111 112 Rcpp::CharacterMatrix kv_mat_mp (Rcpp::Dimension (nmp, ncol)), 113 kv_mat_ls (Rcpp::Dimension (nls, ncol)); 114 std::fill (kv_mat_mp.begin (), kv_mat_mp.end (), NA_STRING); 115 std::fill (kv_mat_ls.begin (), kv_mat_ls.end (), NA_STRING); 116 Rcpp::CharacterMatrix meta_mat_mp (Rcpp::Dimension (nmp, 5L)), 117 meta_mat_ls (Rcpp::Dimension (nls, 5L)); 118 std::fill (meta_mat_mp.begin (), meta_mat_mp.end (), NA_STRING); 119 std::fill (meta_mat_ls.begin (), meta_mat_ls.end (), NA_STRING); 120 121 unsigned int count_mp = 0, count_ls = 0; 122 123 for (auto itr = rels.begin (); itr != rels.end (); ++itr) 124 { 125 Rcpp::checkUserInterrupt (); 126 if (itr->ispoly) // itr->second can only be "outer" or "inner" 127 { 128 trace_multipolygon (itr, ways, nodes, lon_vec, lat_vec, 129 rowname_vec, ids_mp); 130 rel_id_mp.push_back (std::to_string (itr->id)); 131 lon_arr_mp.push_back (lon_vec); 132 lat_arr_mp.push_back (lat_vec); 133 rowname_arr_mp.push_back (rowname_vec); 134 id_vec_mp.push_back (ids_mp); 135 136 if (rowname_vec.size () == 0) 137 mp_okay [count_mp] = false; 138 139 lon_vec.clear (); 140 lon_vec.shrink_to_fit (); 141 lat_vec.clear (); 142 lat_vec.shrink_to_fit (); 143 rowname_vec.clear (); 144 rowname_vec.shrink_to_fit (); 145 ids_mp.clear (); 146 ids_mp.shrink_to_fit (); 147 148 meta_mat_mp (count_mp, 0L) = itr->_version; 149 meta_mat_mp (count_mp, 1L) = itr->_timestamp; 150 meta_mat_mp (count_mp, 2L) = itr->_changeset; 151 meta_mat_mp (count_mp, 3L) = itr->_uid; 152 meta_mat_mp (count_mp, 4L) = itr->_user; 153 154 osm_convert::get_value_mat_rel (itr, unique_vals, kv_mat_mp, count_mp++); 155 } else // store as multilinestring 156 { 157 // multistrings are grouped here by roles, unlike GDAL which just 158 // dumps all of them. 159 std::set <std::string> roles_set; 160 for (auto itw = itr->ways.begin (); itw != itr->ways.end (); ++itw) 161 roles_set.insert (itw->second); 162 roles.reserve (roles_set.size ()); 163 for (auto it = roles_set.begin (); it != roles_set.end (); ++it) 164 roles.push_back (*it); 165 roles_set.clear (); 166 for (std::string role: roles) 167 { 168 trace_multilinestring (itr, role, ways, nodes, 169 lon_vec, lat_vec, rowname_vec, ids_ls); 170 std::stringstream ss; 171 ss.str (""); 172 if (role == "") 173 ss << std::to_string (itr->id) << "-(no role)"; 174 else 175 ss << std::to_string (itr->id) << "-" << role; 176 rel_id_ls.push_back (ss.str ()); 177 lon_arr_ls.push_back (lon_vec); 178 lat_arr_ls.push_back (lat_vec); 179 rowname_arr_ls.push_back (rowname_vec); 180 id_vec_ls.push_back (ids_ls); 181 182 lon_vec.clear (); 183 lon_vec.shrink_to_fit (); 184 lat_vec.clear (); 185 lat_vec.shrink_to_fit (); 186 rowname_vec.clear (); 187 rowname_vec.shrink_to_fit (); 188 ids_ls.clear (); 189 ids_ls.shrink_to_fit (); 190 191 meta_mat_ls (count_ls, 0L) = itr->_version; 192 meta_mat_ls (count_ls, 1L) = itr->_timestamp; 193 meta_mat_ls (count_ls, 2L) = itr->_changeset; 194 meta_mat_ls (count_ls, 3L) = itr->_uid; 195 meta_mat_ls (count_ls, 4L) = itr->_user; 196 197 osm_convert::get_value_mat_rel (itr, unique_vals, kv_mat_ls, count_ls++); 198 } 199 roles_ls.push_back (roles); 200 roles.clear (); 201 } 202 } 203 204 // Erase any multipolygon ways that are not okay. An example of these is 205 // opq("salzburg") |> add_osm_feature (key = "highway"), for which 206 // $osm_multipolygons [[42]] with way#4108738 is not okay. 207 std::vector <std::string> not_okay_id; 208 for (size_t i = 0; i < mp_okay.size (); i++) 209 if (!mp_okay [i]) 210 not_okay_id.push_back (rel_id_mp [i]); 211 212 for (std::string i: not_okay_id) 213 { 214 std::vector <std::string>::iterator it = 215 std::find (rel_id_mp.begin (), rel_id_mp.end (), i); 216 //size_t j = static_cast <size_t> (std::distance (rel_id_mp.begin (), it)); 217 long int j = std::distance (rel_id_mp.begin (), it); 218 lon_arr_mp.erase (lon_arr_mp.begin () + j); 219 lat_arr_mp.erase (lat_arr_mp.begin () + j); 220 rowname_arr_mp.erase (rowname_arr_mp.begin () + j); 221 id_vec_mp.erase (id_vec_mp.begin () + j); 222 rel_id_mp.erase (rel_id_mp.begin () + j); 223 224 // Retain static_cast here because there will generally be very few 225 // instances of this loop 226 size_t st_nrow = static_cast <size_t> (kv_mat_mp.nrow ()); 227 Rcpp::CharacterMatrix kv_mat_mp2 (Rcpp::Dimension (st_nrow - 1, ncol)); 228 Rcpp::CharacterMatrix meta_mp2 (Rcpp::Dimension (st_nrow - 1, 5L)); 229 // k is int for type-compatible Rcpp indexing 230 for (int k = 0; k < kv_mat_mp.nrow (); k++) 231 { 232 if (k < j) 233 { 234 kv_mat_mp2 (k, Rcpp::_) = kv_mat_mp (k, Rcpp::_); 235 meta_mp2 (k, Rcpp::_) = meta_mat_mp (k, Rcpp::_); 236 } else if (k > j) 237 { 238 kv_mat_mp2 (k - 1, Rcpp::_) = kv_mat_mp (k, Rcpp::_); 239 meta_mp2 (k - 1, Rcpp::_) = meta_mat_mp (k, Rcpp::_); 240 } 241 } 242 kv_mat_mp = kv_mat_mp2; 243 meta_mat_mp = meta_mp2; 244 } 245 246 Rcpp::List polygonList = osm_convert::convert_poly_linestring_to_sf <std::string> 247 (lon_arr_mp, lat_arr_mp, rowname_arr_mp, id_vec_mp, rel_id_mp, 248 "MULTIPOLYGON"); 249 polygonList.attr ("n_empty") = 0; 250 polygonList.attr ("class") = 251 Rcpp::CharacterVector::create ("sfc_MULTIPOLYGON", "sfc"); 252 polygonList.attr ("precision") = 0.0; 253 polygonList.attr ("bbox") = bbox; 254 polygonList.attr ("crs") = crs; 255 256 Rcpp::List linestringList = osm_convert::convert_poly_linestring_to_sf <osmid_t> 257 (lon_arr_ls, lat_arr_ls, rowname_arr_ls, id_vec_ls, rel_id_ls, 258 "MULTILINESTRING"); 259 // TODO: linenames just as in ways? 260 // linestringList.attr ("names") = ? 261 linestringList.attr ("n_empty") = 0; 262 linestringList.attr ("class") = 263 Rcpp::CharacterVector::create ("sfc_MULTILINESTRING", "sfc"); 264 linestringList.attr ("precision") = 0.0; 265 linestringList.attr ("bbox") = bbox; 266 linestringList.attr ("crs") = crs; 267 268 Rcpp::DataFrame kv_df_ls; 269 Rcpp::DataFrame meta_df_ls; 270 if (rel_id_ls.size () > 0) // only if there are linestrings 271 { 272 kv_mat_ls.attr ("dimnames") = Rcpp::List::create (rel_id_ls, unique_vals.k_rel); 273 kv_df_ls = osm_convert::restructure_kv_mat (kv_mat_ls, true); 274 meta_mat_ls.attr ("dimnames") = Rcpp::List::create (rel_id_ls, metanames); 275 meta_df_ls = meta_mat_ls; 276 } else 277 { 278 kv_df_ls = R_NilValue; 279 meta_df_ls = R_NilValue; 280 } 281 282 Rcpp::DataFrame kv_df_mp; 283 Rcpp::DataFrame meta_df_mp; 284 if (rel_id_mp.size () > 0) 285 { 286 kv_mat_mp.attr ("dimnames") = Rcpp::List::create (rel_id_mp, unique_vals.k_rel); 287 kv_df_mp = osm_convert::restructure_kv_mat (kv_mat_mp, false); 288 meta_mat_mp.attr ("dimnames") = Rcpp::List::create (rel_id_mp, metanames); 289 meta_df_mp = meta_mat_mp; 290 } else 291 { 292 kv_df_mp = R_NilValue; 293 meta_df_mp = R_NilValue; 294 } 295 296 // ****** clean up ***** 297 lon_arr_mp.clear (); 298 lon_arr_mp.shrink_to_fit (); 299 lon_arr_ls.clear (); 300 lon_arr_ls.shrink_to_fit (); 301 lat_arr_mp.clear (); 302 lat_arr_mp.shrink_to_fit (); 303 lat_arr_ls.clear (); 304 lat_arr_ls.shrink_to_fit (); 305 rowname_arr_mp.clear (); 306 rowname_arr_mp.shrink_to_fit (); 307 rowname_arr_ls.clear (); 308 rowname_arr_ls.shrink_to_fit (); 309 310 rel_id_mp.clear (); 311 rel_id_mp.shrink_to_fit (); 312 rel_id_ls.clear (); 313 rel_id_ls.shrink_to_fit (); 314 roles_ls.clear (); 315 roles_ls.shrink_to_fit (); 316 317 Rcpp::List ret (6); 318 ret [0] = polygonList; 319 ret [1] = kv_df_mp; 320 ret [2] = meta_df_mp; 321 ret [3] = linestringList; 322 ret [4] = kv_df_ls; 323 ret [5] = meta_df_ls; 324 return ret; 325} 326 327//' get_osm_ways 328//' 329//' Store OSM ways as `sf::LINESTRING` or `sf::POLYGON` objects. 330//' 331//' @param wayList Pointer to Rcpp::List to hold the resultant geometries 332//' @param kv_df Pointer to Rcpp::DataFrame to hold key-value pairs 333//' @param way_ids Vector of <osmid_t> IDs of ways to trace 334//' @param ways Pointer to all ways in data set 335//' @param nodes Pointer to all nodes in data set 336//' @param unique_vals pointer to all unique values (OSM IDs and keys) in data set 337//' @param geom_type Character string specifying "POLYGON" or "LINESTRING" 338//' @param bbox Pointer to the bbox needed for `sf` construction 339//' @param crs Pointer to the crs needed for `sf` construction 340//' 341//' @noRd 342void osm_sf::get_osm_ways (Rcpp::List &wayList, Rcpp::DataFrame &kv_df, Rcpp::DataFrame &meta_df, 343 const std::set <osmid_t> &way_ids, const Ways &ways, const Nodes &nodes, 344 const UniqueVals &unique_vals, const std::string &geom_type, 345 const Rcpp::NumericVector &bbox, const Rcpp::List &crs) 346{ 347 if (!(geom_type == "POLYGON" || geom_type == "LINESTRING")) 348 throw std::runtime_error ("geom_type must be POLYGON or LINESTRING"); 349 // NOTE that Rcpp `.size()` returns a **signed** int 350 if (static_cast <unsigned int> (wayList.size ()) != way_ids.size ()) 351 throw std::runtime_error ("ways and IDs must have same lengths"); 352 353 size_t nrow = way_ids.size (), ncol = unique_vals.k_way.size (); 354 std::vector <std::string> waynames; 355 waynames.reserve (way_ids.size ()); 356 357 Rcpp::CharacterMatrix kv_mat (Rcpp::Dimension (nrow, ncol)); 358 std::fill (kv_mat.begin (), kv_mat.end (), NA_STRING); 359 Rcpp::CharacterMatrix meta (Rcpp::Dimension (nrow, 5L)); 360 std::fill (meta.begin (), meta.end (), NA_STRING); 361 362 unsigned int count = 0; 363 for (auto wi = way_ids.begin (); wi != way_ids.end (); ++wi) 364 { 365 //unsigned int count = static_cast <unsigned int> ( 366 // std::distance (way_ids.begin (), wi)); 367 Rcpp::checkUserInterrupt (); 368 waynames.push_back (std::to_string (*wi)); 369 Rcpp::NumericMatrix nmat; 370 osm_convert::trace_way_nmat (ways, nodes, (*wi), nmat); 371 if (geom_type == "LINESTRING") 372 { 373 nmat.attr ("class") = 374 Rcpp::CharacterVector::create ("XY", geom_type, "sfg"); 375 wayList [count] = nmat; 376 } else // polygons are lists 377 { 378 Rcpp::List polyList_temp = Rcpp::List (1); 379 polyList_temp (0) = nmat; 380 polyList_temp.attr ("class") = 381 Rcpp::CharacterVector::create ("XY", geom_type, "sfg"); 382 wayList [count] = polyList_temp; 383 } 384 auto wj = ways.find (*wi); 385 osm_convert::get_value_mat_way (wj, unique_vals, kv_mat, count); 386 387 meta (count, 0L) = wj->second._version; 388 meta (count, 1L) = wj->second._timestamp; 389 meta (count, 2L) = wj->second._changeset; 390 meta (count, 3L) = wj->second._uid; 391 meta (count, 4L) = wj->second._user; 392 393 count++; 394 } 395 396 wayList.attr ("names") = waynames; 397 wayList.attr ("n_empty") = 0; 398 std::stringstream ss; 399 ss.str (""); 400 ss << "sfc_" << geom_type; 401 std::string sfc_type = ss.str (); 402 wayList.attr ("class") = Rcpp::CharacterVector::create (sfc_type, "sfc"); 403 wayList.attr ("precision") = 0.0; 404 wayList.attr ("bbox") = bbox; 405 wayList.attr ("crs") = crs; 406 407 kv_df = R_NilValue; 408 if (way_ids.size () > 0) 409 { 410 kv_mat.attr ("dimnames") = Rcpp::List::create (waynames, unique_vals.k_way); 411 if (kv_mat.nrow () > 0 && kv_mat.ncol () > 0) 412 kv_df = osm_convert::restructure_kv_mat (kv_mat, false); 413 414 meta.attr ("dimnames") = Rcpp::List::create (waynames, metanames); 415 meta_df = meta; 416 } 417 418} 419 420//' get_osm_nodes 421//' 422//' Store OSM nodes as `sf::POINT` objects 423//' 424//' @param ptxy Pointer to Rcpp::List to hold the resultant geometries 425//' @param kv_df Pointer to Rcpp::DataFrame to hold key-value pairs 426//' @param nodes Pointer to all nodes in data set 427//' @param unique_vals pointer to all unique values (OSM IDs and keys) in data set 428//' @param bbox Pointer to the bbox needed for `sf` construction 429//' @param crs Pointer to the crs needed for `sf` construction 430//' 431//' @noRd 432void osm_sf::get_osm_nodes (Rcpp::List &ptList, Rcpp::DataFrame &kv_df, Rcpp::DataFrame &meta_df, 433 const Nodes &nodes, const UniqueVals &unique_vals, 434 const Rcpp::NumericVector &bbox, const Rcpp::List &crs) 435{ 436 size_t nrow = nodes.size (), ncol = unique_vals.k_point.size (); 437 438 if (static_cast <size_t> (ptList.size ()) != nrow) 439 throw std::runtime_error ("points must have same size as nodes"); 440 441 Rcpp::CharacterMatrix kv_mat (Rcpp::Dimension (nrow, ncol)); 442 std::fill (kv_mat.begin (), kv_mat.end (), NA_STRING); 443 Rcpp::CharacterMatrix meta (Rcpp::Dimension (nrow, 5L)); 444 std::fill (meta.begin (), meta.end (), NA_STRING); 445 446 std::vector <std::string> ptnames; 447 ptnames.reserve (nodes.size ()); 448 449 unsigned int count = 0; 450 for (auto ni = nodes.begin (); ni != nodes.end (); ++ni) 451 { 452 // std::distance requires a static_cast which copies each instance and 453 // slows this down by lots of orders of magnitude 454 //unsigned int count = static_cast <unsigned int> ( 455 // std::distance (nodes.begin (), ni)); 456 if (count % 1000 == 0) 457 Rcpp::checkUserInterrupt (); 458 459 // These are pointers and so need to be explicitly recreated each time, 460 // otherwise they all just point to the initial value. 461 Rcpp::NumericVector ptxy = Rcpp::NumericVector::create (NA_REAL, NA_REAL); 462 ptxy.attr ("class") = Rcpp::CharacterVector::create ("XY", "POINT", "sfg"); 463 ptxy (0) = ni->second.lon; 464 ptxy (1) = ni->second.lat; 465 ptList (count) = ptxy; 466 ptnames.push_back (std::to_string (ni->first)); 467 468 meta (count, 0L) = ni->second._version; 469 meta (count, 1L) = ni->second._timestamp; 470 meta (count, 2L) = ni->second._changeset; 471 meta (count, 3L) = ni->second._uid; 472 meta (count, 4L) = ni->second._user; 473 474 for (auto kv_iter = ni->second.key_val.begin (); 475 kv_iter != ni->second.key_val.end (); ++kv_iter) 476 { 477 const std::string &key = kv_iter->first; 478 unsigned int ndi = unique_vals.k_point_index.at (key); 479 kv_mat (count, ndi) = kv_iter->second; 480 } 481 count++; 482 } 483 if (unique_vals.k_point.size () > 0) 484 { 485 kv_mat.attr ("dimnames") = Rcpp::List::create (ptnames, unique_vals.k_point); 486 kv_df = osm_convert::restructure_kv_mat (kv_mat, false); 487 488 meta.attr ("dimnames") = Rcpp::List::create (ptnames, metanames); 489 meta_df = meta; 490 } else 491 kv_df = R_NilValue; 492 493 ptList.attr ("names") = ptnames; 494 ptnames.clear (); 495 ptList.attr ("n_empty") = 0; 496 ptList.attr ("class") = Rcpp::CharacterVector::create ("sfc_POINT", "sfc"); 497 ptList.attr ("precision") = 0.0; 498 ptList.attr ("bbox") = bbox; 499 ptList.attr ("crs") = crs; 500} 501 502 503/************************************************************************ 504 ************************************************************************ 505 ** ** 506 ** THE FINAL RCPP FUNCTION CALLED BY osmdata_sf ** 507 ** ** 508 ************************************************************************ 509 ************************************************************************/ 510 511//' rcpp_osmdata_sf 512//' 513//' Return OSM data in Simple Features format 514//' 515//' @param st Text contents of an overpass API query 516//' @return Rcpp::List objects of OSM data 517//' 518//' @noRd 519// [[Rcpp::export]] 520Rcpp::List rcpp_osmdata_sf (const std::string& st) 521{ 522#ifdef DUMP_INPUT 523 { 524 std::ofstream dump ("./osmdata-sf.xml"); 525 if (dump.is_open()) 526 { 527 dump.write (st.c_str(), st.size()); 528 } 529 } 530#endif 531 532 XmlData xml (st); 533 534 const std::map <osmid_t, Node>& nodes = xml.nodes (); 535 const std::map <osmid_t, OneWay>& ways = xml.ways (); 536 const std::vector <Relation>& rels = xml.relations (); 537 const UniqueVals& unique_vals = xml.unique_vals (); 538 539 std::vector <double> lons, lats; 540 std::set <std::string> keyset; // must be ordered! 541 Rcpp::List dimnames (0); 542 Rcpp::NumericMatrix nmat (Rcpp::Dimension (0, 0)); 543 544 /* -------------------------------------------------------------- 545 * 1. Set up bbox and crs 546 * --------------------------------------------------------------*/ 547 548 std::vector <std::string> colnames, rownames; 549 colnames.push_back ("lon"); 550 colnames.push_back ("lat"); 551 552 Rcpp::NumericVector bbox = rcpp_get_bbox_sf (xml.x_min (), xml.y_min (), 553 xml.x_max (), xml.y_max ()); 554 Rcpp::List crs = Rcpp::List::create (NA_STRING, 555 Rcpp::CharacterVector::create (NA_STRING)); 556 crs (0) = "EPSG:4326"; 557 crs (1) = wkt; 558 //Rcpp::List crs = Rcpp::List::create ((int) 4326, p4s); 559 crs.attr ("names") = Rcpp::CharacterVector::create ("input", "wkt"); 560 crs.attr ("class") = "crs"; 561 562 /* -------------------------------------------------------------- 563 * 2. Extract OSM Relations 564 * --------------------------------------------------------------*/ 565 566 Rcpp::List tempList = osm_sf::get_osm_relations (rels, nodes, ways, unique_vals, 567 bbox, crs); 568 Rcpp::List multipolygons = tempList [0]; 569 // the followin line errors because of ambiguous conversion 570 //Rcpp::DataFrame kv_df_mp = tempList [1]; 571 Rcpp::List kv_df_mp = tempList [1]; 572 kv_df_mp.attr ("class") = "data.frame"; 573 Rcpp::List meta_df_mp = tempList [2]; 574 meta_df_mp.attr ("class") = "data.frame"; 575 Rcpp::List multilinestrings = tempList [3]; 576 Rcpp::List kv_df_ls = tempList [4]; 577 kv_df_ls.attr ("class") = "data.frame"; 578 Rcpp::List meta_df_ls = tempList [5]; 579 meta_df_ls.attr ("class") = "data.frame"; 580 581 /* -------------------------------------------------------------- 582 * 3. Extract OSM ways 583 * --------------------------------------------------------------*/ 584 585 // first divide into polygonal and non-polygonal 586 std::set <osmid_t> poly_ways, non_poly_ways; 587 for (auto itw = ways.begin (); itw != ways.end (); ++itw) 588 { 589 if ((*itw).second.nodes.front () == (*itw).second.nodes.back ()) 590 { 591 if (poly_ways.find ((*itw).first) == poly_ways.end ()) 592 poly_ways.insert ((*itw).first); 593 } else if (non_poly_ways.find ((*itw).first) == non_poly_ways.end ()) 594 non_poly_ways.insert ((*itw).first); 595 } 596 597 Rcpp::List polyList (poly_ways.size ()); 598 Rcpp::DataFrame kv_df_polys; 599 Rcpp::DataFrame meta_df_polys; 600 osm_sf::get_osm_ways (polyList, kv_df_polys, meta_df_polys, 601 poly_ways, ways, nodes, unique_vals, "POLYGON", bbox, crs); 602 603 Rcpp::List lineList (non_poly_ways.size ()); 604 Rcpp::DataFrame kv_df_lines; 605 Rcpp::DataFrame meta_df_lines; 606 osm_sf::get_osm_ways (lineList, kv_df_lines, meta_df_lines, 607 non_poly_ways, ways, nodes, unique_vals, "LINESTRING", bbox, crs); 608 609 /* -------------------------------------------------------------- 610 * 3. Extract OSM nodes 611 * --------------------------------------------------------------*/ 612 613 Rcpp::List pointList (nodes.size ()); 614 // NOTE: kv_df_points is actually an Rcpp::CharacterMatrix, and the 615 // following line *should* construct the wrapped data.frame version with 616 // strings not factors, yet this does not work. 617 //Rcpp::DataFrame kv_df_points = Rcpp::DataFrame::create (Rcpp::_["stringsAsFactors"] = false); 618 Rcpp::DataFrame kv_df_points; 619 Rcpp::DataFrame meta_df_points; 620 osm_sf::get_osm_nodes (pointList, kv_df_points, meta_df_points, 621 nodes, unique_vals, bbox, crs); 622 623 624 /* -------------------------------------------------------------- 625 * 5. Collate all data 626 * --------------------------------------------------------------*/ 627 628 Rcpp::List ret (16); 629 ret [0] = bbox; 630 ret [1] = pointList; 631 ret [2] = kv_df_points; 632 ret [3] = meta_df_points; 633 ret [4] = lineList; 634 ret [5] = kv_df_lines; 635 ret [6] = meta_df_lines; 636 ret [7] = polyList; 637 ret [8] = kv_df_polys; 638 ret [9] = meta_df_polys; 639 ret [10] = multipolygons; 640 ret [11] = kv_df_mp; 641 ret [12] = meta_df_mp; 642 ret [13] = multilinestrings; 643 ret [14] = kv_df_ls; 644 ret [15] = meta_df_ls; 645 646 std::vector <std::string> retnames {"bbox", "points", "points_kv", "points_meta", 647 "lines", "lines_kv", "lines_meta", "polygons", "polygons_kv", "polygons_meta", 648 "multipolygons", "multipolygons_kv", "multipolygons_meta", 649 "multilines", "multilines_kv", "multilines_meta"}; 650 ret.attr ("names") = retnames; 651 652 return ret; 653}