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