R package for downloading OpenStreetMap data
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}