` to the `json11.cpp` file
7 | * I removed the `CXX_STD = CXX11` flag from the `Makevars` files
8 |
9 |
10 | ## geojsonR 1.1.1
11 |
12 | * I modified the *json11.cpp* file by excluding the *using std::move* from the top of the file and converting all *move* to *std::move* to remove the significant warning *"warning: unqualified call to 'std::move' [-Wunqualified-std-cast-call]"*
13 |
14 |
15 | ## geojsonR 1.1.0
16 |
17 | * I've added the *CITATION* file in the *inst* directory listing all papers and software used in the *geojsonR* package
18 | * I've removed *Lazydata* from the DESCRIPTION file
19 |
20 |
21 | ## geojsonR 1.0.9
22 |
23 | * I've adjusted the tolerance value in the test-case of the *save_R_list_Features_2_FeatureCollection* function (file 'test-geojson.R') because it threw an error in 2 operating systems. I also replaced the invalid url's in the vignette.
24 |
25 |
26 | ## geojsonR 1.0.8
27 |
28 | * I've added the *save_R_list_Features_2_FeatureCollection* function and I've modified the *typeof_item* method of the *GeoJson_Collections* C++ class to accept also input objects of type integer.
29 |
30 |
31 | ## geojsonR 1.0.7
32 |
33 | * I've added the *write_path* and *verbose* parameters to the *Features_2Collection* function
34 | * I've added error handling in the *parse_geojson_string* and *parse_geojson_objects* methods of the *From_GeoJson_geometries* C++ class to account for cases where the output of the *json11::Json::parse* function is a NULL object ( I've included also a test case for demonstration )
35 |
36 |
37 | ## geojsonR 1.0.6
38 |
39 | I fixed minor typos in the .cpp files
40 |
41 |
42 | ## geojsonR 1.0.5
43 |
44 | I modified the R functions which made a connection to Url's (previously the connection was not closed in an appropriate way producing that way a warning)
45 |
46 |
47 | ## geojsonR 1.0.4
48 |
49 | I modified the *Makevars* files to allow *OpenMP* usage. The *geojsonR* package is not parallelized, however the *Armadillo* library uses *OpenMP* internally to improve the execuction time of the functions.
50 |
51 |
52 | ## geojsonR 1.0.3
53 |
54 | I added the *merge_files* function.
55 |
56 |
57 | ## geojsonR 1.0.2
58 |
59 | I added the *FROM_GeoJson_Schema* function. This function is appropriate when the property-names do not match exactly the *RFC 7946* specification ( for instance if the *geometry-object-name* appears as *location*, as is the case sometimes in mongodb queries ). This way one can avoid unnecessary errors when reading *geojson* files/strings.
60 |
61 |
62 | ## geojsonR 1.0.1
63 |
64 | I added a Vignette and corrected mistakes of the examples in the documentation
65 |
66 |
67 | ## geojsonR 1.0.0
68 |
69 |
--------------------------------------------------------------------------------
/R/RcppExports.R:
--------------------------------------------------------------------------------
1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand
2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
3 |
4 | export_From_geojson <- function(input_file, flatten_coords = FALSE, average_coordinates = FALSE, to_list = FALSE) {
5 | .Call(`_geojsonR_export_From_geojson`, input_file, flatten_coords, average_coordinates, to_list)
6 | }
7 |
8 | export_From_JSON <- function(input_file) {
9 | .Call(`_geojsonR_export_From_JSON`, input_file)
10 | }
11 |
12 | dump_geojson <- function(input_data) {
13 | .Call(`_geojsonR_dump_geojson`, input_data)
14 | }
15 |
16 | Features_TO_Collection <- function(feat_files_lst, bbox_vec, verbose = FALSE) {
17 | .Call(`_geojsonR_Features_TO_Collection`, feat_files_lst, bbox_vec, verbose)
18 | }
19 |
20 | export_From_geojson_schema <- function(input_file, GEOMETRY_OBJECT_NAME = "", average_coordinates = FALSE, to_list = FALSE) {
21 | .Call(`_geojsonR_export_From_geojson_schema`, input_file, GEOMETRY_OBJECT_NAME, average_coordinates, to_list)
22 | }
23 |
24 | list_files <- function(path, full_path = TRUE) {
25 | .Call(`_geojsonR_list_files`, path, full_path)
26 | }
27 |
28 | merge_json <- function(input_folder, output_file, concat_delimiter = "\n", verbose = FALSE) {
29 | invisible(.Call(`_geojsonR_merge_json`, input_folder, output_file, concat_delimiter, verbose))
30 | }
31 |
32 | DATA_TYPE <- function(sublist) {
33 | .Call(`_geojsonR_DATA_TYPE`, sublist)
34 | }
35 |
36 | inner_coords <- function(geom_lst, z, polygon_interior = FALSE) {
37 | .Call(`_geojsonR_inner_coords`, geom_lst, z, polygon_interior)
38 | }
39 |
40 | Polygon_with_interior_rings <- function(geom_lst, i, verbose) {
41 | .Call(`_geojsonR_Polygon_with_interior_rings`, geom_lst, i, verbose)
42 | }
43 |
44 | SAVE_R_list_Features_2_FeatureCollection <- function(x, path_to_file = "", verbose = FALSE) {
45 | .Call(`_geojsonR_SAVE_R_list_Features_2_FeatureCollection`, x, path_to_file, verbose)
46 | }
47 |
48 | export_To_GeoJson <- function(geometry_object, data_POINTS, data_ARRAYS, data_ARRAY_ARRAYS, data_POLYGON_ARRAYS, stringify = FALSE) {
49 | .Call(`_geojsonR_export_To_GeoJson`, geometry_object, data_POINTS, data_ARRAYS, data_ARRAY_ARRAYS, data_POLYGON_ARRAYS, stringify)
50 | }
51 |
52 | Geom_Collection <- function(geometry_object_names, geometry_objects, stringify = FALSE) {
53 | .Call(`_geojsonR_Geom_Collection`, geometry_object_names, geometry_objects, stringify)
54 | }
55 |
56 | Feature_Obj <- function(geometry_object_names, geometry_objects, stringify = FALSE) {
57 | .Call(`_geojsonR_Feature_Obj`, geometry_object_names, geometry_objects, stringify)
58 | }
59 |
60 | Feature_collection_Obj <- function(geometry_object_names, geometry_objects, stringify = FALSE) {
61 | .Call(`_geojsonR_Feature_collection_Obj`, geometry_object_names, geometry_objects, stringify)
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/R/geojsonR.R:
--------------------------------------------------------------------------------
1 | #' @useDynLib geojsonR, .registration = TRUE
2 | #' @importFrom Rcpp evalCpp
3 | NULL
--------------------------------------------------------------------------------
/R/utils.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' reads GeoJson data
4 | #'
5 | #' @param url_file_string a string specifying the input path to a file OR a geojson object (in form of a character string) OR a valid url (beginning with 'http..') pointing to a geojson object
6 | #' @param Flatten_Coords either TRUE or FALSE. If TRUE then the properties member of the geojson file will be omitted during parsing.
7 | #' @param Average_Coordinates either TRUE or FALSE. If TRUE then additionally a geojson-dump and the average latitude and longitude of the geometry object will be returned.
8 | #' @param To_List either TRUE or FALSE. If TRUE then the \emph{coordinates} of the geometry object will be returned in form of a list, otherwise in form of a numeric matrix.
9 | #' @return a (nested) list
10 | #' @details
11 | #' The \emph{FROM_GeoJson} function is based on the 'RFC 7946' specification. Thus, geojson files/strings which include property-names other than the 'RFC 7946' specifies will return an error. To avoid errors of
12 | #' that kind a user should take advantage of the \emph{FROM_GeoJson_Schema} function, which is not as strict concerning the property names.
13 | #' @export
14 | #' @examples
15 | #'
16 | #' \dontrun{
17 | #'
18 | #' library(geojsonR)
19 | #'
20 | #'
21 | #' # INPUT IS A FILE
22 | #'
23 | #' res = FROM_GeoJson(url_file_string = "/myfolder/feature_collection.geojson")
24 | #'
25 | #'
26 | #' # INPUT IS A GEOJSON (character string)
27 | #'
28 | #' tmp_str = '{ "type": "MultiPolygon", "coordinates": [
29 | #' [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],
30 | #' [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],
31 | #' [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]
32 | #' ]
33 | #' }'
34 | #'
35 | #' res = FROM_GeoJson(url_file_string = tmp_str)
36 | #'
37 | #'
38 | #' # INPUT IS A URL
39 | #'
40 | #' res = FROM_GeoJson(url_file_string = "http://www.EXAMPLE_web_page.geojson")
41 | #' }
42 | #'
43 |
44 | FROM_GeoJson = function(url_file_string, Flatten_Coords = FALSE, Average_Coordinates = FALSE, To_List = FALSE) {
45 |
46 | if (!inherits(url_file_string, 'character') && length(url_file_string) != 1) { stop("the 'url_file_string' parameter should be of type character string", call. = F) }
47 | if (!inherits(Flatten_Coords, "logical")) { stop("the 'Flatten_Coords' parameter should be of type boolean", call. = F) }
48 | if (!inherits(Average_Coordinates, "logical")) { stop("the 'Average_Coordinates' parameter should be of type boolean", call. = F) }
49 | if (!inherits(To_List, "logical")) { stop("the 'To_List' parameter should be of type boolean", call. = F) }
50 |
51 | if (substring(url_file_string, 1, 4) == "http") { # only url-addresses which start with 'http' will be considered as valid
52 |
53 | con = url(url_file_string, method = "libcurl") # test url-output with : 'https://raw.githubusercontent.com/lyzidiamond/learn-geojson/master/geojson/cupcakes.geojson'
54 |
55 | url_json = readLines(con, warn = FALSE)
56 |
57 | url_file_string = paste(url_json, collapse = "\n")
58 |
59 | close(con); gc()
60 | }
61 |
62 | res = export_From_geojson(url_file_string, Flatten_Coords, Average_Coordinates, To_List)
63 |
64 | return(res)
65 | }
66 |
67 |
68 |
69 | #' reads GeoJson data using a one-word-schema
70 | #'
71 | #' @param url_file_string a string specifying the input path to a file OR a geojson object (in form of a character string) OR a valid url (beginning with 'http..') pointing to a geojson object
72 | #' @param geometry_name a string specifying the geometry name in the geojson string/file. The \emph{geometry_name} functions as a one-word schema and can significantly speed up the parsing of the data.
73 | #' @param Average_Coordinates either TRUE or FALSE. If TRUE then additionally a geojson-dump and the average latitude and longitude of the geometry object will be returned.
74 | #' @param To_List either TRUE or FALSE. If TRUE then the \emph{coordinates} of the geometry object will be returned in form of a list, otherwise in form of a numeric matrix.
75 | #' @return a (nested) list
76 | #' @details
77 | #' This function is appropriate when the property-names do not match exactly the 'RFC 7946' specification ( for instance if the \emph{geometry} object-name appears as \emph{location} as is the case sometimes in mongodb queries ).
78 | #' The user can then specify the \emph{geometry_name} as it exactly appears in the .geojson string/file (consult the example for more details). If no \emph{geometry_name} is given then recursion will be used, which increases the processing time.
79 | #' In case that the input .geojson object is of \emph{type} : \emph{Point}, \emph{LineString}, \emph{MultiPoint}, \emph{Polygon}, \emph{GeometryCollection}, \emph{MultiLineString}, \emph{MultiPolygon},
80 | #' \emph{Feature} or \emph{FeatureCollection} with a second attribute name : \emph{coordinates}, then the \emph{geometry_name} parameter is not necessary.
81 | #' @export
82 | #' @examples
83 | #'
84 | #' library(geojsonR)
85 | #'
86 | #'
87 | #' # INPUT IS A GEOJSON (character string)
88 | #'
89 | #' tmp_str = '{
90 | #' "name" : "example_name",
91 | #' "location" : {
92 | #' "type" : "Point",
93 | #' "coordinates" : [ -120.24, 39.21 ]
94 | #' }
95 | #' }'
96 | #'
97 | #' res = FROM_GeoJson_Schema(url_file_string = tmp_str, geometry_name = "location")
98 | #'
99 |
100 | FROM_GeoJson_Schema = function(url_file_string, geometry_name = "", Average_Coordinates = FALSE, To_List = FALSE) {
101 |
102 | if (!inherits(url_file_string, 'character') && length(url_file_string) != 1) { stop("the 'url_file_string' parameter should be of type character string", call. = F) }
103 | if (!inherits(geometry_name, "character")) { stop("the 'geometry_name' parameter should be of type character", call. = F) }
104 | if (!inherits(Average_Coordinates, "logical")) { stop("the 'Average_Coordinates' parameter should be of type boolean", call. = F) }
105 | if (!inherits(To_List, "logical")) { stop("the 'To_List' parameter should be of type boolean", call. = F) }
106 |
107 | if (substring(url_file_string, 1, 4) == "http") { # only url-addresses which start with 'http' will be considered as valid
108 |
109 | con = url(url_file_string, method = "libcurl") # test url-output with : 'https://raw.githubusercontent.com/lyzidiamond/learn-geojson/master/geojson/cupcakes.geojson'
110 |
111 | url_json = readLines(con, warn = FALSE)
112 |
113 | url_file_string = paste(url_json, collapse = "\n")
114 |
115 | close(con); gc()
116 | }
117 |
118 | res = export_From_geojson_schema(url_file_string, geometry_name, Average_Coordinates, To_List)
119 |
120 | return(res)
121 | }
122 |
123 |
124 |
125 | #' returns a json-dump from a geojson file
126 | #'
127 | #' @param url_file either a string specifying the input path to a file OR a valid url (beginning with 'http..') pointing to a geojson object
128 | #' @return a character string (json dump)
129 | #' @export
130 | #' @examples
131 | #'
132 | #' \dontrun{
133 | #'
134 | #' library(geojsonR)
135 | #'
136 | #' res = Dump_From_GeoJson("/myfolder/point.geojson")
137 | #' }
138 | #'
139 |
140 | Dump_From_GeoJson = function(url_file) {
141 |
142 | if (!inherits(url_file, 'character') && length(url_file) != 1) {
143 |
144 | stop("the 'url_file' parameter should be of type character string", call. = F)
145 | }
146 |
147 | if (substring(url_file, 1, 4) == "http") { # only url-addresses which start with 'http' will be considered as valid
148 |
149 | con = url(url_file, method = "libcurl") # test url-output with : 'https://raw.githubusercontent.com/lyzidiamond/learn-geojson/master/geojson/hackspots.geojson'
150 |
151 | url_json = readLines(con, warn = FALSE)
152 |
153 | res = paste(url_json, collapse = "\n")
154 |
155 | close(con); gc()}
156 |
157 | else if (file.exists(url_file)) {
158 |
159 | res = dump_geojson(url_file)}
160 |
161 | else {
162 |
163 | stop("the input shoud be either a valid url (beginning with 'http..') OR a valid path to a geojson file", call. = F)
164 | }
165 |
166 | return(res)
167 | }
168 |
169 |
170 |
171 | #' converts data to a GeoJson object
172 | #'
173 | #' @param data a list specifying the geojson geometry object
174 | #' @param stringify either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)
175 | #' @return a List
176 | #' @export
177 | #' @docType class
178 | #' @importFrom R6 R6Class
179 | #' @section Methods:
180 | #'
181 | #' \describe{
182 | #' \item{\code{TO_GeoJson$new()}}{}
183 | #'
184 | #' \item{\code{--------------}}{}
185 | #'
186 | #' \item{\code{Point(data, stringify = FALSE)}}{}
187 | #'
188 | #' \item{\code{--------------}}{}
189 | #'
190 | #' \item{\code{MultiPoint(data, stringify = FALSE)}}{}
191 | #'
192 | #' \item{\code{--------------}}{}
193 | #'
194 | #' \item{\code{LineString(data, stringify = FALSE)}}{}
195 | #'
196 | #' \item{\code{--------------}}{}
197 | #'
198 | #' \item{\code{MultiLineString(data, stringify = FALSE)}}{}
199 | #'
200 | #' \item{\code{--------------}}{}
201 | #'
202 | #' \item{\code{Polygon(data, stringify = FALSE)}}{}
203 | #'
204 | #' \item{\code{--------------}}{}
205 | #'
206 | #' \item{\code{MultiPolygon(data, stringify = FALSE)}}{}
207 | #'
208 | #' \item{\code{--------------}}{}
209 | #'
210 | #' \item{\code{GeometryCollection(data, stringify = FALSE)}}{}
211 | #'
212 | #' \item{\code{--------------}}{}
213 | #'
214 | #' \item{\code{Feature(data, stringify = FALSE)}}{}
215 | #'
216 | #' \item{\code{--------------}}{}
217 | #'
218 | #' \item{\code{FeatureCollection(data, stringify = FALSE)}}{}
219 | #'
220 | #' \item{\code{--------------}}{}
221 | #' }
222 | #'
223 | #' @usage # utl <- TO_GeoJson$new()
224 | #' @examples
225 | #'
226 | #' library(geojsonR)
227 | #'
228 | #'
229 | #'# initialize class
230 | #'
231 | #' init = TO_GeoJson$new()
232 | #'
233 | #'
234 | #' # Examples covering all geometry-objects
235 | #'
236 | #'
237 | #' # Point
238 | #'
239 | #' point_dat = c(100, 1.01)
240 | #'
241 | #' point = init$Point(point_dat, stringify = TRUE)
242 | #' point
243 | #'
244 | #'
245 | #' # MultiPoint
246 | #'
247 | #' multi_point_dat = list(c(100, 1.01), c(200, 2.01))
248 | #'
249 | #' multi_point = init$MultiPoint(multi_point_dat, stringify = TRUE)
250 | #' multi_point
251 | #'
252 | #'
253 | #' # LineString
254 | #'
255 | #' linestring_dat = list(c(100, 1.01), c(200, 2.01))
256 | #'
257 | #' line_string = init$LineString(linestring_dat, stringify = TRUE)
258 | #' line_string
259 | #'
260 | #'
261 | #' # MultiLineString
262 | #'
263 | #' multilinestring_dat = list(list(c(100, 0.0), c(101, 1.0)), list(c(102, 2.0), c(103, 3.0)))
264 | #'
265 | #' multiline_string = init$MultiLineString(multilinestring_dat, stringify = TRUE)
266 | #' multiline_string
267 | #'
268 | #'
269 | #' # Polygon (WITHOUT interior rings)
270 | #'
271 | #' polygon_WITHOUT_dat = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)))
272 | #'
273 | #' polygon_without = init$Polygon(polygon_WITHOUT_dat, stringify = TRUE)
274 | #' polygon_without
275 | #'
276 | #'
277 | #' # Polygon (WITH interior rings)
278 | #'
279 | #' polygon_WITH_dat = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)),
280 | #'
281 | #' list(c(50, 0.5), c(50, 0.8), c(50, 0.9), c(50, 0.5)))
282 | #'
283 | #' polygon_with = init$Polygon(polygon_WITH_dat, stringify = TRUE)
284 | #' polygon_with
285 | #'
286 | #'
287 | #' # MultiPolygon
288 | #'
289 | #' # the first polygon is without interior rings and the second one is with interior rings
290 | #'
291 | #' multi_polygon_dat = list(list(list(c(102, 2.0), c(103, 2.0), c(103, 3.0), c(102, 2.0))),
292 | #'
293 | #' list(list(c(100, 0.0), c(101, 1.0), c(101, 1.0), c(100, 0.0)),
294 | #'
295 | #' list(c(100.2, 0.2), c(100.2, 0.8), c(100.8, 0.8), c(100.2, 0.2))))
296 | #'
297 | #' multi_polygon = init$MultiPolygon(multi_polygon_dat, stringify = TRUE)
298 | #' multi_polygon
299 | #'
300 | #'
301 | #'
302 | #' # GeometryCollection (named list)
303 | #'
304 | #'
305 | #' Point = c(100, 1.01)
306 | #'
307 | #' MultiPoint = list(c(100, 1.01), c(200, 2.01))
308 | #'
309 | #' MultiLineString = list(list(c(100, 0.0), c(101, 1.0)),
310 | #'
311 | #' list(c(102, 2.0), c(103, 3.0)))
312 | #'
313 | #' LineString = list(c(100, 1.01), c(200, 2.01))
314 | #'
315 | #' MultiLineString = list(list(c(100, 0.0), c(101, 1.0)),
316 | #'
317 | #' list(c(102, 2.0), c(103, 3.0)))
318 | #'
319 | #' Polygon = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)))
320 | #'
321 | #' Polygon = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)),
322 | #'
323 | #' list(c(50, 0.5), c(50, 0.8), c(50, 0.9), c(50, 0.5)))
324 | #'
325 | #' MultiPolygon = list(list(list(c(102, 2.0), c(103, 2.0), c(103, 3.0), c(102, 2.0))),
326 | #'
327 | #' list(list(c(100, 0.0), c(101, 1.0), c(101, 1.0), c(100, 0.0)),
328 | #'
329 | #' list(c(100.2, 0.2), c(100.2, 0.8), c(100.8, 0.8), c(100.2, 0.2))))
330 | #'
331 | #'
332 | #' geometry_collection_dat = list(Point = Point, MultiPoint = MultiPoint,
333 | #'
334 | #' MultiLineString = MultiLineString, LineString = LineString,
335 | #'
336 | #' MultiLineString = MultiLineString, Polygon = Polygon,
337 | #'
338 | #' Polygon = Polygon, MultiPolygon = MultiPolygon)
339 | #'
340 | #'
341 | #' geometry_col = init$GeometryCollection(geometry_collection_dat, stringify = TRUE)
342 | #' geometry_col
343 | #'
344 | #'
345 | #' # Feature (named list)
346 | #'
347 | #'
348 | #' # Empty 'properties' list
349 | #'
350 | #' feature_dat1 = list(id = 1, bbox = c(1,2,3,4), geometry = list(Point = c(100, 1.01)),
351 | #'
352 | #' properties = list())
353 | #'
354 | #'
355 | #' # Nested 'properties' list
356 | #'
357 | #' feature_dat2 = list(id = "1", bbox = c(1,2,3,4), geometry = list(Point = c(100, 1.01)),
358 | #'
359 | #' properties = list(prop0 = 'value0',
360 | #'
361 | #' prop1 = 0.0, vec = c(1,2,3), lst = list(a = 1, d = 2)))
362 | #'
363 | #'
364 | #' feature_obj = init$Feature(feature_dat2, stringify = TRUE)
365 | #' feature_obj
366 | #' cat(feature_obj$json_dump)
367 | #'
368 | #'
369 | #'
370 | #' # FeatureCollection (named list)
371 | #'
372 | #'
373 | #' # takes as input the previously created 'feature_dat1', 'feature_dat2'
374 | #'
375 | #' feature_col_dat = list(bbox = c(-10.01, -10.01, 10.01, 10.01),
376 | #'
377 | #' features = list(Feature = feature_dat1, Feature = feature_dat2))
378 | #' feature_col_dat
379 | #'
380 | #'
381 | #' feature_collection_obj = init$FeatureCollection(feature_col_dat, stringify = TRUE)
382 | #' feature_collection_obj
383 | #' cat(feature_collection_obj$json_dump)
384 | #'
385 |
386 | TO_GeoJson <- R6::R6Class("TO_GeoJson",
387 |
388 | public = list(
389 |
390 | initialize = function() {
391 |
392 | private$empty_vec = numeric(0)
393 |
394 | },
395 |
396 | Point = function(data, stringify = FALSE) {
397 |
398 | if (!inherits(data, c('numeric', 'vector'))) { stop("the 'data' parameter should be a numeric vector", call. = F) }
399 |
400 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
401 |
402 | res = export_To_GeoJson("Point", data, private$empty_vec, private$empty_vec, private$empty_vec, stringify)
403 |
404 | return(res)
405 | },
406 |
407 | MultiPoint = function(data, stringify = FALSE) {
408 |
409 | if (!inherits(data, c('numeric', 'list'))) { stop("the 'data' parameter should be a numeric list", call. = F) }
410 |
411 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
412 |
413 | res = export_To_GeoJson("MultiPoint", private$empty_vec, data, private$empty_vec, private$empty_vec, stringify)
414 |
415 | return(res)
416 | },
417 |
418 | LineString = function(data, stringify = FALSE) {
419 |
420 | if (!inherits(data, c('numeric', 'list'))) { stop("the 'data' parameter should be a numeric list", call. = F) }
421 |
422 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
423 |
424 | res = export_To_GeoJson("LineString", private$empty_vec, data, private$empty_vec, private$empty_vec, stringify)
425 |
426 | return(res)
427 | },
428 |
429 | MultiLineString = function(data, stringify = FALSE) {
430 |
431 | if (!inherits(data, c('numeric', 'list'))) { stop("the 'data' parameter should be a numeric list", call. = F) }
432 |
433 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
434 |
435 | res = export_To_GeoJson("MultiLineString", private$empty_vec, private$empty_vec, data, private$empty_vec, stringify)
436 |
437 | return(res)
438 | },
439 |
440 | Polygon = function(data, stringify = FALSE) {
441 |
442 | if (!inherits(data, c('numeric', 'list'))) { stop("the 'data' parameter should be a numeric list", call. = F) }
443 |
444 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
445 |
446 | res = export_To_GeoJson("Polygon", private$empty_vec, private$empty_vec, data, private$empty_vec, stringify)
447 |
448 | return(res)
449 | },
450 |
451 | MultiPolygon = function(data, stringify = FALSE) {
452 |
453 | if (!inherits(data, c('numeric', 'list'))) { stop("the 'data' parameter should be a numeric list", call. = F) }
454 |
455 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
456 |
457 | res = export_To_GeoJson("MultiPolygon", private$empty_vec, private$empty_vec, private$empty_vec, data, stringify)
458 |
459 | return(res)
460 | },
461 |
462 | GeometryCollection = function(data, stringify = FALSE) {
463 |
464 | if (!inherits(data, c('numeric', 'list'))) { stop("the 'data' parameter should be a numeric list", call. = F) }
465 |
466 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
467 |
468 | geometry_names = names(data)
469 |
470 | res = Geom_Collection(geometry_names, data, stringify)
471 |
472 | return(res)
473 | },
474 |
475 | Feature = function(data, stringify = FALSE) {
476 |
477 | if (!inherits(data, 'list')) { stop("the 'data' parameter should be of type list", call. = F) }
478 |
479 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
480 |
481 | feature_names = names(data)
482 |
483 | res = Feature_Obj(feature_names, data, stringify)
484 |
485 | return(res)
486 | },
487 |
488 | FeatureCollection = function(data, stringify = FALSE) {
489 |
490 | if (!inherits(data, 'list')) { stop("the 'data' parameter should be of type list", call. = F) }
491 |
492 | if (!inherits(stringify, 'logical')) { stop("the 'stringify' parameter should be of type boolean", call. = F) }
493 |
494 | feature_col_names = names(data)
495 |
496 | res = Feature_collection_Obj(feature_col_names, data, stringify)
497 |
498 | return(res)
499 | }
500 | ),
501 |
502 | private = list(
503 |
504 | empty_vec = NULL
505 | )
506 | )
507 |
508 |
509 |
510 | #' creates a FeatureCollection dump from multiple Feature geojson objects
511 | #'
512 | #' @param Features_files_vec a character vector specifying paths to files (Feature geojson objects)
513 | #' @param bbox_vec either NULL or a numeric vector
514 | #' @param write_path either NULL or a character string specifying a valid path to a file ( preferably with a \emph{.geojson extension} ) where the output data will be saved
515 | #' @param verbose a boolean. If TRUE then information will be printed out in the console
516 | #' @return a FeatureCollection dump
517 | #' @details
518 | #' The \emph{Features_2Collection} function utilizes internally a for-loop. In case of an error set the \emph{verbose} parameter to TRUE to find out which file leads to this error.
519 | #' @export
520 | #' @examples
521 | #'
522 | #' \dontrun{
523 | #'
524 | #' library(geojsonR)
525 | #'
526 | #' vec_files = c("/myfolder/Feature1.geojson", "/myfolder/Feature2.geojson",
527 | #' "/myfolder/Feature3.geojson", "/myfolder/Feature4.geojson",
528 | #' "/myfolder/Feature5.geojson")
529 | #'
530 | #' res = Features_2Collection(vec_files, bbox_vec = NULL)
531 | #' }
532 | #'
533 |
534 | Features_2Collection = function(Features_files_vec, bbox_vec = NULL, write_path = NULL, verbose = FALSE) {
535 |
536 | if (!inherits(Features_files_vec, c('vector', 'character'))) {
537 |
538 | stop("the 'Features_files_vec' parameter should be a character vector", call. = F)
539 | }
540 |
541 | if (is.null(bbox_vec)) {
542 |
543 | bbox_vec = numeric(0)}
544 |
545 | else {
546 |
547 | if (!inherits(bbox_vec, c('vector', 'numeric'))) {
548 |
549 | stop("the 'bbox' parameter should be a numeric vector", call. = F)
550 | }
551 | }
552 |
553 | tmp_feat = Features_TO_Collection(Features_files_vec, bbox_vec, verbose)
554 |
555 | if (!is.null(write_path)) {
556 | fileConn = file(write_path)
557 | writeLines(tmp_feat, fileConn)
558 | close(fileConn)
559 | }
560 |
561 | return(tmp_feat)
562 | }
563 |
564 |
565 |
566 |
567 | #' creates a FeatureCollection from R list objects ( see the details section about the limitations of this function )
568 | #'
569 | #'
570 | #' @param input_list a list object that includes 1 or more geojson R list Features
571 | #' @param path_to_file either an empty string ("") or a valid path to a file where the output FeatureCollection will be saved
572 | #' @param verbose a boolean. If TRUE then information will be printed out in the console
573 | #' @return a FeatureCollection in form of a character string
574 | #' @return a FeatureCollection saved in a file
575 | #' @details
576 | #'
577 | #' \itemize{
578 | #' \item it allows the following attributes: \emph{'type'}, \emph{'id'}, \emph{'properties'} and \emph{'geometry'}
579 | #' \item it allows only coordinates of type \emph{'Polygon'} or \emph{'MultiPolygon'} to be processed. In case of a \emph{'Polygon'} there are 2 cases: (a.) Polygon WITHOUT interior rings (a numeric matrix is expected) and (b.) Polygon WITH interior rings (a list of numeric matrices is expected). See the test-cases if you receive an error for the correct format of the input data. In case of a \emph{'MultiPolygon'} both Polygons with OR without interior rings can be included. Multipolygons are of the form: list of lists where each SUBLIST can be either a numeric matrix (Polygon without interior rings) or a list (Polygon with interior rings)
580 | #' \item the \emph{properties} attribute must be a list that can take only \emph{character strings}, \emph{numeric} and \emph{integer} values of SIZE 1. In case that any of the input properties is of SIZE > 1 then it will throw an error.
581 | #' }
582 | #'
583 | #' The \emph{input_list} parameter can be EITHER created from scratch OR GeoJson Features (in form of a FeatureCollection) can be loaded in R and modified so that this list can be processed by this function
584 | #'
585 | #' @export
586 | #' @examples
587 | #'
588 | #' \dontrun{
589 | #'
590 | #' library(geojsonR)
591 | #'
592 | #' #------------------------------------------------
593 | #' # valid example that will save the data to a file
594 | #' #------------------------------------------------
595 | #'
596 | #' Feature1 = list(type ="Feature",
597 | #' id = 1L,
598 | #' properties = list(prop1 = 'id', prop2 = 1.0234),
599 | #' geometry = list(type = 'Polygon',
600 | #' coordinates = matrix(runif(20), nrow = 10, ncol = 2)))
601 | #'
602 | #' Feature2 = list(type ="Feature",
603 | #' id = 2L,
604 | #' properties = list(prop1 = 'non-id', prop2 = 6.0987),
605 | #' geometry = list(type = 'MultiPolygon',
606 | #' coordinates = list(matrix(runif(20), nrow = 10, ncol = 2),
607 | #' matrix(runif(20), nrow = 10, ncol = 2))))
608 | #'
609 | #' list_features = list(Feature1, Feature2)
610 | #'
611 | #' path_feat_col = tempfile(fileext = '.geojson')
612 | #'
613 | #' res = save_R_list_Features_2_FeatureCollection(input_list = list_features,
614 | #' path_to_file = path_feat_col,
615 | #' verbose = TRUE)
616 | #'
617 | #' #-------------------------------------
618 | #' # validate that the file can be loaded
619 | #' #-------------------------------------
620 | #'
621 | #' res_load = FROM_GeoJson_Schema(url_file_string = path_feat_col)
622 | #' str(res_load)
623 | #'
624 | #'
625 | #' #----------------------------------------------------
626 | #' # INVALID data types such as NA's will throw an ERROR
627 | #' #----------------------------------------------------
628 | #'
629 | #'
630 | #' Feature1 = list(type ="Feature",
631 | #' id = 1L,
632 | #' properties = list(prop1 = NA, prop2 = 1.0234),
633 | #' geometry = list(type = 'Polygon',
634 | #' coordinates = matrix(runif(20), nrow = 10, ncol = 2)))
635 | #'
636 | #' list_features = list(Feature1, Feature2)
637 | #'
638 | #' path_feat_col = tempfile(fileext = '.geojson')
639 | #'
640 | #' res = save_R_list_Features_2_FeatureCollection(input_list = list_features,
641 | #' path_to_file = path_feat_col,
642 | #' verbose = TRUE)
643 | #' }
644 | #'
645 |
646 | save_R_list_Features_2_FeatureCollection = function(input_list,
647 | path_to_file = "",
648 | verbose = FALSE) {
649 |
650 | if (length(input_list) < 1) {
651 | stop("The 'input_list' parameter must be at least of length 1!", call. = F)
652 | }
653 |
654 | res = SAVE_R_list_Features_2_FeatureCollection(x = input_list,
655 | path_to_file = path_to_file,
656 | verbose = verbose)
657 | return(res)
658 | }
659 |
660 |
661 |
662 |
663 | #' secondary function for shiny Applications
664 | #'
665 | #' @param input_file a character string specifying a path to a file
666 | #' @return a (nested) list
667 | #' @details
668 | #' This function is meant for \emph{shiny Applications}. To read a GeoJson file use either the \emph{FROM_GeoJson} or \emph{FROM_GeoJson_Schema} function.
669 | #' @export
670 |
671 | shiny_from_JSON = function(input_file) { # shiny apps should be in a separate package if Rcpp::class(es) are present
672 |
673 | if (!inherits(input_file, 'character') && length(input_file) != 1) {
674 |
675 | stop("the 'input_file' parameter should be a character string", call. = F)
676 | }
677 |
678 | return(export_From_JSON(input_file))
679 | }
680 |
681 |
682 |
683 |
684 | #' merge json files (or any kind of text files) from a directory
685 | #'
686 | #' @param INPUT_FOLDER a character string specifying a path to the input folder
687 | #' @param OUTPUT_FILE a character string specifying a path to the output file
688 | #' @param CONCAT_DELIMITER a character string specifying the delimiter to use when merging the files
689 | #' @param verbose either TRUE or FALSE. If TRUE then information will be printed in the console.
690 | #' @details
691 | #' This function is meant for json files but it can be applied to any kind of text files. It takes an input folder (\emph{INPUT_FOLDER}) and an output file
692 | #' (\emph{OUTPUT_FILE}) and merges all files from the \emph{INPUT_FOLDER} to a single \emph{OUTPUT_FILE} using the concatenation delimiter (\emph{CONCAT_DELIMITER}).
693 | #' @export
694 | #' @examples
695 | #'
696 | #' \dontrun{
697 | #' library(geojsonR)
698 | #'
699 | #' merge_files(INPUT_FOLDER = "/my_folder/", OUTPUT_FILE = "output_file.json")
700 | #' }
701 |
702 | merge_files = function(INPUT_FOLDER, OUTPUT_FILE, CONCAT_DELIMITER = "\n", verbose = FALSE) {
703 |
704 | if (!inherits(INPUT_FOLDER, 'character') && length(INPUT_FOLDER) != 1) stop("the 'INPUT_FOLDER' parameter should be a character string", call. = F)
705 | if (!inherits(OUTPUT_FILE, 'character') && length(OUTPUT_FILE) != 1) stop("the 'OUTPUT_FILE' parameter should be a character string", call. = F)
706 | if (!inherits(CONCAT_DELIMITER, 'character') && length(CONCAT_DELIMITER) != 1) stop("the 'CONCAT_DELIMITER' parameter should be a character string", call. = F)
707 | if (!inherits(verbose, 'logical')) stop("the 'verbose' parameter should be of type boolean", call. = F)
708 |
709 | str_SPL = strsplit(INPUT_FOLDER, "")[[1]]
710 | if (!str_SPL[nchar(INPUT_FOLDER)] %in% c("/", "\\")) stop('the "INPUT_FOLDER" parameter should end in slash', call. = F)
711 |
712 | if (file.exists(OUTPUT_FILE)) warning(paste("the '", OUTPUT_FILE, "' file already exists. New data will be added to the end of '", OUTPUT_FILE, "' !", sep = ""), call. = F)
713 | if (!dir.exists(INPUT_FOLDER)) stop("the path to the 'INPUT_FOLDER' parameter does not exist", call. = F)
714 |
715 | merge_json(INPUT_FOLDER, OUTPUT_FILE, CONCAT_DELIMITER, verbose)
716 |
717 | invisible()
718 | }
719 |
720 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](https://github.com/mlampros/geojsonR/actions)
3 | [](https://codecov.io/github/mlampros/geojsonR?branch=master)
4 | [](http://cran.r-project.org/package=geojsonR)
5 | [](http://www.r-pkg.org/pkg/geojsonR)
6 |
7 | [](https://cran.r-project.org/package=geojsonR)
8 |
9 |
10 | ## geojsonR
11 |
12 |
13 | The **geojsonR** package includes functions for processing [GeoJson objects](https://en.wikipedia.org/wiki/GeoJSON) relying on [RFC 7946](https://datatracker.ietf.org/doc/html/rfc7946). The geojson encoding is based on [json11](https://github.com/dropbox/json11), a tiny JSON library for C++11. Furthermore, the source code is exported in R through the *Rcpp* and *RcppArmadillo* packages. More details on the functionality of geojsonR can be found in the [blog-post](http://mlampros.github.io/2017/03/29/geojsonR_package/) and in the package Vignette.
14 |
15 |
16 | To install the package from CRAN use,
17 |
18 | ```R
19 |
20 | install.packages("geojsonR")
21 |
22 |
23 | ```
24 |
25 |
26 | and to download the latest version from Github use the *install_github* function of the *remotes* package,
27 |
28 |
29 | ```R
30 |
31 | remotes::install_github('mlampros/geojsonR')
32 |
33 |
34 | ```
35 |
36 |
37 | Use the following link to report bugs/issues,
38 |
39 |
40 | [https://github.com/mlampros/geojsonR/issues](https://github.com/mlampros/geojsonR/issues)
41 |
42 |
43 |
44 | ### **Citation:**
45 |
46 | If you use the code of this repository in your paper or research please cite both **geojsonR** and the **original articles / software** `https://CRAN.R-project.org/package=geojsonR`:
47 |
48 |
49 |
50 | ```R
51 | @Manual{,
52 | title = {{geojsonR}: A GeoJson Processing Toolkit},
53 | author = {Lampros Mouselimis},
54 | year = {2021},
55 | note = {R package version 1.1.2},
56 | url = {https://CRAN.R-project.org/package=geojsonR},
57 | }
58 | ```
59 |
60 |
61 |
--------------------------------------------------------------------------------
/inst/CITATION:
--------------------------------------------------------------------------------
1 | citHeader("Please cite both the package and the original articles / software in your publications:")
2 |
3 | year <- sub("-.*", "", meta$Date)
4 | note <- sprintf("R package version %s", meta$Version)
5 |
6 | bibentry(
7 | bibtype = "Manual",
8 | title = "{geojsonR}: A GeoJson Processing Toolkit",
9 | author = person("Lampros", "Mouselimis"),
10 | year = year,
11 | note = note,
12 | url = "https://CRAN.R-project.org/package=geojsonR"
13 | )
14 |
15 | bibentry(
16 | bibtype = "Manual",
17 | title = "{json11}: A tiny JSON library for C++11, providing JSON parsing and serialization",
18 | author = person("Dropbox", "Inc"),
19 | year = "2013",
20 | url = "https://github.com/dropbox/json11"
21 | )
22 |
--------------------------------------------------------------------------------
/inst/COPYRIGHTS:
--------------------------------------------------------------------------------
1 |
2 |
3 | ========================================
4 | 'json11' : A tiny JSON library for C++11
5 | ========================================
6 |
7 |
8 | Copyright (c) 2013 Dropbox, Inc.
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in
18 | all copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/man/Dump_From_GeoJson.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{Dump_From_GeoJson}
4 | \alias{Dump_From_GeoJson}
5 | \title{returns a json-dump from a geojson file}
6 | \usage{
7 | Dump_From_GeoJson(url_file)
8 | }
9 | \arguments{
10 | \item{url_file}{either a string specifying the input path to a file OR a valid url (beginning with 'http..') pointing to a geojson object}
11 | }
12 | \value{
13 | a character string (json dump)
14 | }
15 | \description{
16 | returns a json-dump from a geojson file
17 | }
18 | \examples{
19 |
20 | \dontrun{
21 |
22 | library(geojsonR)
23 |
24 | res = Dump_From_GeoJson("/myfolder/point.geojson")
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/man/FROM_GeoJson.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{FROM_GeoJson}
4 | \alias{FROM_GeoJson}
5 | \title{reads GeoJson data}
6 | \usage{
7 | FROM_GeoJson(
8 | url_file_string,
9 | Flatten_Coords = FALSE,
10 | Average_Coordinates = FALSE,
11 | To_List = FALSE
12 | )
13 | }
14 | \arguments{
15 | \item{url_file_string}{a string specifying the input path to a file OR a geojson object (in form of a character string) OR a valid url (beginning with 'http..') pointing to a geojson object}
16 |
17 | \item{Flatten_Coords}{either TRUE or FALSE. If TRUE then the properties member of the geojson file will be omitted during parsing.}
18 |
19 | \item{Average_Coordinates}{either TRUE or FALSE. If TRUE then additionally a geojson-dump and the average latitude and longitude of the geometry object will be returned.}
20 |
21 | \item{To_List}{either TRUE or FALSE. If TRUE then the \emph{coordinates} of the geometry object will be returned in form of a list, otherwise in form of a numeric matrix.}
22 | }
23 | \value{
24 | a (nested) list
25 | }
26 | \description{
27 | reads GeoJson data
28 | }
29 | \details{
30 | The \emph{FROM_GeoJson} function is based on the 'RFC 7946' specification. Thus, geojson files/strings which include property-names other than the 'RFC 7946' specifies will return an error. To avoid errors of
31 | that kind a user should take advantage of the \emph{FROM_GeoJson_Schema} function, which is not as strict concerning the property names.
32 | }
33 | \examples{
34 |
35 | \dontrun{
36 |
37 | library(geojsonR)
38 |
39 |
40 | # INPUT IS A FILE
41 |
42 | res = FROM_GeoJson(url_file_string = "/myfolder/feature_collection.geojson")
43 |
44 |
45 | # INPUT IS A GEOJSON (character string)
46 |
47 | tmp_str = '{ "type": "MultiPolygon", "coordinates": [
48 | [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],
49 | [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],
50 | [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]
51 | ]
52 | }'
53 |
54 | res = FROM_GeoJson(url_file_string = tmp_str)
55 |
56 |
57 | # INPUT IS A URL
58 |
59 | res = FROM_GeoJson(url_file_string = "http://www.EXAMPLE_web_page.geojson")
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/man/FROM_GeoJson_Schema.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{FROM_GeoJson_Schema}
4 | \alias{FROM_GeoJson_Schema}
5 | \title{reads GeoJson data using a one-word-schema}
6 | \usage{
7 | FROM_GeoJson_Schema(
8 | url_file_string,
9 | geometry_name = "",
10 | Average_Coordinates = FALSE,
11 | To_List = FALSE
12 | )
13 | }
14 | \arguments{
15 | \item{url_file_string}{a string specifying the input path to a file OR a geojson object (in form of a character string) OR a valid url (beginning with 'http..') pointing to a geojson object}
16 |
17 | \item{geometry_name}{a string specifying the geometry name in the geojson string/file. The \emph{geometry_name} functions as a one-word schema and can significantly speed up the parsing of the data.}
18 |
19 | \item{Average_Coordinates}{either TRUE or FALSE. If TRUE then additionally a geojson-dump and the average latitude and longitude of the geometry object will be returned.}
20 |
21 | \item{To_List}{either TRUE or FALSE. If TRUE then the \emph{coordinates} of the geometry object will be returned in form of a list, otherwise in form of a numeric matrix.}
22 | }
23 | \value{
24 | a (nested) list
25 | }
26 | \description{
27 | reads GeoJson data using a one-word-schema
28 | }
29 | \details{
30 | This function is appropriate when the property-names do not match exactly the 'RFC 7946' specification ( for instance if the \emph{geometry} object-name appears as \emph{location} as is the case sometimes in mongodb queries ).
31 | The user can then specify the \emph{geometry_name} as it exactly appears in the .geojson string/file (consult the example for more details). If no \emph{geometry_name} is given then recursion will be used, which increases the processing time.
32 | In case that the input .geojson object is of \emph{type} : \emph{Point}, \emph{LineString}, \emph{MultiPoint}, \emph{Polygon}, \emph{GeometryCollection}, \emph{MultiLineString}, \emph{MultiPolygon},
33 | \emph{Feature} or \emph{FeatureCollection} with a second attribute name : \emph{coordinates}, then the \emph{geometry_name} parameter is not necessary.
34 | }
35 | \examples{
36 |
37 | library(geojsonR)
38 |
39 |
40 | # INPUT IS A GEOJSON (character string)
41 |
42 | tmp_str = '{
43 | "name" : "example_name",
44 | "location" : {
45 | "type" : "Point",
46 | "coordinates" : [ -120.24, 39.21 ]
47 | }
48 | }'
49 |
50 | res = FROM_GeoJson_Schema(url_file_string = tmp_str, geometry_name = "location")
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/man/Features_2Collection.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{Features_2Collection}
4 | \alias{Features_2Collection}
5 | \title{creates a FeatureCollection dump from multiple Feature geojson objects}
6 | \usage{
7 | Features_2Collection(
8 | Features_files_vec,
9 | bbox_vec = NULL,
10 | write_path = NULL,
11 | verbose = FALSE
12 | )
13 | }
14 | \arguments{
15 | \item{Features_files_vec}{a character vector specifying paths to files (Feature geojson objects)}
16 |
17 | \item{bbox_vec}{either NULL or a numeric vector}
18 |
19 | \item{write_path}{either NULL or a character string specifying a valid path to a file ( preferably with a \emph{.geojson extension} ) where the output data will be saved}
20 |
21 | \item{verbose}{a boolean. If TRUE then information will be printed out in the console}
22 | }
23 | \value{
24 | a FeatureCollection dump
25 | }
26 | \description{
27 | creates a FeatureCollection dump from multiple Feature geojson objects
28 | }
29 | \details{
30 | The \emph{Features_2Collection} function utilizes internally a for-loop. In case of an error set the \emph{verbose} parameter to TRUE to find out which file leads to this error.
31 | }
32 | \examples{
33 |
34 | \dontrun{
35 |
36 | library(geojsonR)
37 |
38 | vec_files = c("/myfolder/Feature1.geojson", "/myfolder/Feature2.geojson",
39 | "/myfolder/Feature3.geojson", "/myfolder/Feature4.geojson",
40 | "/myfolder/Feature5.geojson")
41 |
42 | res = Features_2Collection(vec_files, bbox_vec = NULL)
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/man/TO_GeoJson.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \docType{class}
4 | \name{TO_GeoJson}
5 | \alias{TO_GeoJson}
6 | \title{converts data to a GeoJson object}
7 | \usage{
8 | # utl <- TO_GeoJson$new()
9 | }
10 | \value{
11 | a List
12 | }
13 | \description{
14 | converts data to a GeoJson object
15 |
16 | converts data to a GeoJson object
17 | }
18 | \section{Methods}{
19 |
20 |
21 | \describe{
22 | \item{\code{TO_GeoJson$new()}}{}
23 |
24 | \item{\code{--------------}}{}
25 |
26 | \item{\code{Point(data, stringify = FALSE)}}{}
27 |
28 | \item{\code{--------------}}{}
29 |
30 | \item{\code{MultiPoint(data, stringify = FALSE)}}{}
31 |
32 | \item{\code{--------------}}{}
33 |
34 | \item{\code{LineString(data, stringify = FALSE)}}{}
35 |
36 | \item{\code{--------------}}{}
37 |
38 | \item{\code{MultiLineString(data, stringify = FALSE)}}{}
39 |
40 | \item{\code{--------------}}{}
41 |
42 | \item{\code{Polygon(data, stringify = FALSE)}}{}
43 |
44 | \item{\code{--------------}}{}
45 |
46 | \item{\code{MultiPolygon(data, stringify = FALSE)}}{}
47 |
48 | \item{\code{--------------}}{}
49 |
50 | \item{\code{GeometryCollection(data, stringify = FALSE)}}{}
51 |
52 | \item{\code{--------------}}{}
53 |
54 | \item{\code{Feature(data, stringify = FALSE)}}{}
55 |
56 | \item{\code{--------------}}{}
57 |
58 | \item{\code{FeatureCollection(data, stringify = FALSE)}}{}
59 |
60 | \item{\code{--------------}}{}
61 | }
62 | }
63 |
64 | \examples{
65 |
66 | library(geojsonR)
67 |
68 |
69 | # initialize class
70 |
71 | init = TO_GeoJson$new()
72 |
73 |
74 | # Examples covering all geometry-objects
75 |
76 |
77 | # Point
78 |
79 | point_dat = c(100, 1.01)
80 |
81 | point = init$Point(point_dat, stringify = TRUE)
82 | point
83 |
84 |
85 | # MultiPoint
86 |
87 | multi_point_dat = list(c(100, 1.01), c(200, 2.01))
88 |
89 | multi_point = init$MultiPoint(multi_point_dat, stringify = TRUE)
90 | multi_point
91 |
92 |
93 | # LineString
94 |
95 | linestring_dat = list(c(100, 1.01), c(200, 2.01))
96 |
97 | line_string = init$LineString(linestring_dat, stringify = TRUE)
98 | line_string
99 |
100 |
101 | # MultiLineString
102 |
103 | multilinestring_dat = list(list(c(100, 0.0), c(101, 1.0)), list(c(102, 2.0), c(103, 3.0)))
104 |
105 | multiline_string = init$MultiLineString(multilinestring_dat, stringify = TRUE)
106 | multiline_string
107 |
108 |
109 | # Polygon (WITHOUT interior rings)
110 |
111 | polygon_WITHOUT_dat = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)))
112 |
113 | polygon_without = init$Polygon(polygon_WITHOUT_dat, stringify = TRUE)
114 | polygon_without
115 |
116 |
117 | # Polygon (WITH interior rings)
118 |
119 | polygon_WITH_dat = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)),
120 |
121 | list(c(50, 0.5), c(50, 0.8), c(50, 0.9), c(50, 0.5)))
122 |
123 | polygon_with = init$Polygon(polygon_WITH_dat, stringify = TRUE)
124 | polygon_with
125 |
126 |
127 | # MultiPolygon
128 |
129 | # the first polygon is without interior rings and the second one is with interior rings
130 |
131 | multi_polygon_dat = list(list(list(c(102, 2.0), c(103, 2.0), c(103, 3.0), c(102, 2.0))),
132 |
133 | list(list(c(100, 0.0), c(101, 1.0), c(101, 1.0), c(100, 0.0)),
134 |
135 | list(c(100.2, 0.2), c(100.2, 0.8), c(100.8, 0.8), c(100.2, 0.2))))
136 |
137 | multi_polygon = init$MultiPolygon(multi_polygon_dat, stringify = TRUE)
138 | multi_polygon
139 |
140 |
141 |
142 | # GeometryCollection (named list)
143 |
144 |
145 | Point = c(100, 1.01)
146 |
147 | MultiPoint = list(c(100, 1.01), c(200, 2.01))
148 |
149 | MultiLineString = list(list(c(100, 0.0), c(101, 1.0)),
150 |
151 | list(c(102, 2.0), c(103, 3.0)))
152 |
153 | LineString = list(c(100, 1.01), c(200, 2.01))
154 |
155 | MultiLineString = list(list(c(100, 0.0), c(101, 1.0)),
156 |
157 | list(c(102, 2.0), c(103, 3.0)))
158 |
159 | Polygon = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)))
160 |
161 | Polygon = list(list(c(100, 1.01), c(200, 2.01), c(100, 1.0), c(100, 1.01)),
162 |
163 | list(c(50, 0.5), c(50, 0.8), c(50, 0.9), c(50, 0.5)))
164 |
165 | MultiPolygon = list(list(list(c(102, 2.0), c(103, 2.0), c(103, 3.0), c(102, 2.0))),
166 |
167 | list(list(c(100, 0.0), c(101, 1.0), c(101, 1.0), c(100, 0.0)),
168 |
169 | list(c(100.2, 0.2), c(100.2, 0.8), c(100.8, 0.8), c(100.2, 0.2))))
170 |
171 |
172 | geometry_collection_dat = list(Point = Point, MultiPoint = MultiPoint,
173 |
174 | MultiLineString = MultiLineString, LineString = LineString,
175 |
176 | MultiLineString = MultiLineString, Polygon = Polygon,
177 |
178 | Polygon = Polygon, MultiPolygon = MultiPolygon)
179 |
180 |
181 | geometry_col = init$GeometryCollection(geometry_collection_dat, stringify = TRUE)
182 | geometry_col
183 |
184 |
185 | # Feature (named list)
186 |
187 |
188 | # Empty 'properties' list
189 |
190 | feature_dat1 = list(id = 1, bbox = c(1,2,3,4), geometry = list(Point = c(100, 1.01)),
191 |
192 | properties = list())
193 |
194 |
195 | # Nested 'properties' list
196 |
197 | feature_dat2 = list(id = "1", bbox = c(1,2,3,4), geometry = list(Point = c(100, 1.01)),
198 |
199 | properties = list(prop0 = 'value0',
200 |
201 | prop1 = 0.0, vec = c(1,2,3), lst = list(a = 1, d = 2)))
202 |
203 |
204 | feature_obj = init$Feature(feature_dat2, stringify = TRUE)
205 | feature_obj
206 | cat(feature_obj$json_dump)
207 |
208 |
209 |
210 | # FeatureCollection (named list)
211 |
212 |
213 | # takes as input the previously created 'feature_dat1', 'feature_dat2'
214 |
215 | feature_col_dat = list(bbox = c(-10.01, -10.01, 10.01, 10.01),
216 |
217 | features = list(Feature = feature_dat1, Feature = feature_dat2))
218 | feature_col_dat
219 |
220 |
221 | feature_collection_obj = init$FeatureCollection(feature_col_dat, stringify = TRUE)
222 | feature_collection_obj
223 | cat(feature_collection_obj$json_dump)
224 |
225 | }
226 | \section{Methods}{
227 | \subsection{Public methods}{
228 | \itemize{
229 | \item \href{#method-TO_GeoJson-new}{\code{TO_GeoJson$new()}}
230 | \item \href{#method-TO_GeoJson-Point}{\code{TO_GeoJson$Point()}}
231 | \item \href{#method-TO_GeoJson-MultiPoint}{\code{TO_GeoJson$MultiPoint()}}
232 | \item \href{#method-TO_GeoJson-LineString}{\code{TO_GeoJson$LineString()}}
233 | \item \href{#method-TO_GeoJson-MultiLineString}{\code{TO_GeoJson$MultiLineString()}}
234 | \item \href{#method-TO_GeoJson-Polygon}{\code{TO_GeoJson$Polygon()}}
235 | \item \href{#method-TO_GeoJson-MultiPolygon}{\code{TO_GeoJson$MultiPolygon()}}
236 | \item \href{#method-TO_GeoJson-GeometryCollection}{\code{TO_GeoJson$GeometryCollection()}}
237 | \item \href{#method-TO_GeoJson-Feature}{\code{TO_GeoJson$Feature()}}
238 | \item \href{#method-TO_GeoJson-FeatureCollection}{\code{TO_GeoJson$FeatureCollection()}}
239 | \item \href{#method-TO_GeoJson-clone}{\code{TO_GeoJson$clone()}}
240 | }
241 | }
242 | \if{html}{\out{
}}
243 | \if{html}{\out{}}
244 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-new}{}}}
245 | \subsection{Method \code{new()}}{
246 | \subsection{Usage}{
247 | \if{html}{\out{}}\preformatted{TO_GeoJson$new()}\if{html}{\out{
}}
248 | }
249 |
250 | }
251 | \if{html}{\out{
}}
252 | \if{html}{\out{}}
253 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-Point}{}}}
254 | \subsection{Method \code{Point()}}{
255 | \subsection{Usage}{
256 | \if{html}{\out{}}\preformatted{TO_GeoJson$Point(data, stringify = FALSE)}\if{html}{\out{
}}
257 | }
258 |
259 | \subsection{Arguments}{
260 | \if{html}{\out{}}
261 | \describe{
262 | \item{\code{data}}{a list specifying the geojson geometry object}
263 |
264 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
265 | }
266 | \if{html}{\out{
}}
267 | }
268 | }
269 | \if{html}{\out{
}}
270 | \if{html}{\out{}}
271 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-MultiPoint}{}}}
272 | \subsection{Method \code{MultiPoint()}}{
273 | \subsection{Usage}{
274 | \if{html}{\out{}}\preformatted{TO_GeoJson$MultiPoint(data, stringify = FALSE)}\if{html}{\out{
}}
275 | }
276 |
277 | \subsection{Arguments}{
278 | \if{html}{\out{}}
279 | \describe{
280 | \item{\code{data}}{a list specifying the geojson geometry object}
281 |
282 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
283 | }
284 | \if{html}{\out{
}}
285 | }
286 | }
287 | \if{html}{\out{
}}
288 | \if{html}{\out{}}
289 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-LineString}{}}}
290 | \subsection{Method \code{LineString()}}{
291 | \subsection{Usage}{
292 | \if{html}{\out{}}\preformatted{TO_GeoJson$LineString(data, stringify = FALSE)}\if{html}{\out{
}}
293 | }
294 |
295 | \subsection{Arguments}{
296 | \if{html}{\out{}}
297 | \describe{
298 | \item{\code{data}}{a list specifying the geojson geometry object}
299 |
300 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
301 | }
302 | \if{html}{\out{
}}
303 | }
304 | }
305 | \if{html}{\out{
}}
306 | \if{html}{\out{}}
307 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-MultiLineString}{}}}
308 | \subsection{Method \code{MultiLineString()}}{
309 | \subsection{Usage}{
310 | \if{html}{\out{}}\preformatted{TO_GeoJson$MultiLineString(data, stringify = FALSE)}\if{html}{\out{
}}
311 | }
312 |
313 | \subsection{Arguments}{
314 | \if{html}{\out{}}
315 | \describe{
316 | \item{\code{data}}{a list specifying the geojson geometry object}
317 |
318 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
319 | }
320 | \if{html}{\out{
}}
321 | }
322 | }
323 | \if{html}{\out{
}}
324 | \if{html}{\out{}}
325 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-Polygon}{}}}
326 | \subsection{Method \code{Polygon()}}{
327 | \subsection{Usage}{
328 | \if{html}{\out{}}\preformatted{TO_GeoJson$Polygon(data, stringify = FALSE)}\if{html}{\out{
}}
329 | }
330 |
331 | \subsection{Arguments}{
332 | \if{html}{\out{}}
333 | \describe{
334 | \item{\code{data}}{a list specifying the geojson geometry object}
335 |
336 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
337 | }
338 | \if{html}{\out{
}}
339 | }
340 | }
341 | \if{html}{\out{
}}
342 | \if{html}{\out{}}
343 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-MultiPolygon}{}}}
344 | \subsection{Method \code{MultiPolygon()}}{
345 | \subsection{Usage}{
346 | \if{html}{\out{}}\preformatted{TO_GeoJson$MultiPolygon(data, stringify = FALSE)}\if{html}{\out{
}}
347 | }
348 |
349 | \subsection{Arguments}{
350 | \if{html}{\out{}}
351 | \describe{
352 | \item{\code{data}}{a list specifying the geojson geometry object}
353 |
354 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
355 | }
356 | \if{html}{\out{
}}
357 | }
358 | }
359 | \if{html}{\out{
}}
360 | \if{html}{\out{}}
361 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-GeometryCollection}{}}}
362 | \subsection{Method \code{GeometryCollection()}}{
363 | \subsection{Usage}{
364 | \if{html}{\out{}}\preformatted{TO_GeoJson$GeometryCollection(data, stringify = FALSE)}\if{html}{\out{
}}
365 | }
366 |
367 | \subsection{Arguments}{
368 | \if{html}{\out{}}
369 | \describe{
370 | \item{\code{data}}{a list specifying the geojson geometry object}
371 |
372 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
373 | }
374 | \if{html}{\out{
}}
375 | }
376 | }
377 | \if{html}{\out{
}}
378 | \if{html}{\out{}}
379 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-Feature}{}}}
380 | \subsection{Method \code{Feature()}}{
381 | \subsection{Usage}{
382 | \if{html}{\out{}}\preformatted{TO_GeoJson$Feature(data, stringify = FALSE)}\if{html}{\out{
}}
383 | }
384 |
385 | \subsection{Arguments}{
386 | \if{html}{\out{}}
387 | \describe{
388 | \item{\code{data}}{a list specifying the geojson geometry object}
389 |
390 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
391 | }
392 | \if{html}{\out{
}}
393 | }
394 | }
395 | \if{html}{\out{
}}
396 | \if{html}{\out{}}
397 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-FeatureCollection}{}}}
398 | \subsection{Method \code{FeatureCollection()}}{
399 | \subsection{Usage}{
400 | \if{html}{\out{}}\preformatted{TO_GeoJson$FeatureCollection(data, stringify = FALSE)}\if{html}{\out{
}}
401 | }
402 |
403 | \subsection{Arguments}{
404 | \if{html}{\out{}}
405 | \describe{
406 | \item{\code{data}}{a list specifying the geojson geometry object}
407 |
408 | \item{\code{stringify}}{either TRUE or FALSE, specifying if the output should also include a geojson-dump (as a character string)}
409 | }
410 | \if{html}{\out{
}}
411 | }
412 | }
413 | \if{html}{\out{
}}
414 | \if{html}{\out{}}
415 | \if{latex}{\out{\hypertarget{method-TO_GeoJson-clone}{}}}
416 | \subsection{Method \code{clone()}}{
417 | The objects of this class are cloneable with this method.
418 | \subsection{Usage}{
419 | \if{html}{\out{}}\preformatted{TO_GeoJson$clone(deep = FALSE)}\if{html}{\out{
}}
420 | }
421 |
422 | \subsection{Arguments}{
423 | \if{html}{\out{}}
424 | \describe{
425 | \item{\code{deep}}{Whether to make a deep clone.}
426 | }
427 | \if{html}{\out{
}}
428 | }
429 | }
430 | }
431 |
--------------------------------------------------------------------------------
/man/merge_files.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{merge_files}
4 | \alias{merge_files}
5 | \title{merge json files (or any kind of text files) from a directory}
6 | \usage{
7 | merge_files(
8 | INPUT_FOLDER,
9 | OUTPUT_FILE,
10 | CONCAT_DELIMITER = "\\n",
11 | verbose = FALSE
12 | )
13 | }
14 | \arguments{
15 | \item{INPUT_FOLDER}{a character string specifying a path to the input folder}
16 |
17 | \item{OUTPUT_FILE}{a character string specifying a path to the output file}
18 |
19 | \item{CONCAT_DELIMITER}{a character string specifying the delimiter to use when merging the files}
20 |
21 | \item{verbose}{either TRUE or FALSE. If TRUE then information will be printed in the console.}
22 | }
23 | \description{
24 | merge json files (or any kind of text files) from a directory
25 | }
26 | \details{
27 | This function is meant for json files but it can be applied to any kind of text files. It takes an input folder (\emph{INPUT_FOLDER}) and an output file
28 | (\emph{OUTPUT_FILE}) and merges all files from the \emph{INPUT_FOLDER} to a single \emph{OUTPUT_FILE} using the concatenation delimiter (\emph{CONCAT_DELIMITER}).
29 | }
30 | \examples{
31 |
32 | \dontrun{
33 | library(geojsonR)
34 |
35 | merge_files(INPUT_FOLDER = "/my_folder/", OUTPUT_FILE = "output_file.json")
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/man/save_R_list_Features_2_FeatureCollection.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{save_R_list_Features_2_FeatureCollection}
4 | \alias{save_R_list_Features_2_FeatureCollection}
5 | \title{creates a FeatureCollection from R list objects ( see the details section about the limitations of this function )}
6 | \usage{
7 | save_R_list_Features_2_FeatureCollection(
8 | input_list,
9 | path_to_file = "",
10 | verbose = FALSE
11 | )
12 | }
13 | \arguments{
14 | \item{input_list}{a list object that includes 1 or more geojson R list Features}
15 |
16 | \item{path_to_file}{either an empty string ("") or a valid path to a file where the output FeatureCollection will be saved}
17 |
18 | \item{verbose}{a boolean. If TRUE then information will be printed out in the console}
19 | }
20 | \value{
21 | a FeatureCollection in form of a character string
22 |
23 | a FeatureCollection saved in a file
24 | }
25 | \description{
26 | creates a FeatureCollection from R list objects ( see the details section about the limitations of this function )
27 | }
28 | \details{
29 | \itemize{
30 | \item it allows the following attributes: \emph{'type'}, \emph{'id'}, \emph{'properties'} and \emph{'geometry'}
31 | \item it allows only coordinates of type \emph{'Polygon'} or \emph{'MultiPolygon'} to be processed. In case of a \emph{'Polygon'} there are 2 cases: (a.) Polygon WITHOUT interior rings (a numeric matrix is expected) and (b.) Polygon WITH interior rings (a list of numeric matrices is expected). See the test-cases if you receive an error for the correct format of the input data. In case of a \emph{'MultiPolygon'} both Polygons with OR without interior rings can be included. Multipolygons are of the form: list of lists where each SUBLIST can be either a numeric matrix (Polygon without interior rings) or a list (Polygon with interior rings)
32 | \item the \emph{properties} attribute must be a list that can take only \emph{character strings}, \emph{numeric} and \emph{integer} values of SIZE 1. In case that any of the input properties is of SIZE > 1 then it will throw an error.
33 | }
34 |
35 | The \emph{input_list} parameter can be EITHER created from scratch OR GeoJson Features (in form of a FeatureCollection) can be loaded in R and modified so that this list can be processed by this function
36 | }
37 | \examples{
38 |
39 | \dontrun{
40 |
41 | library(geojsonR)
42 |
43 | #------------------------------------------------
44 | # valid example that will save the data to a file
45 | #------------------------------------------------
46 |
47 | Feature1 = list(type ="Feature",
48 | id = 1L,
49 | properties = list(prop1 = 'id', prop2 = 1.0234),
50 | geometry = list(type = 'Polygon',
51 | coordinates = matrix(runif(20), nrow = 10, ncol = 2)))
52 |
53 | Feature2 = list(type ="Feature",
54 | id = 2L,
55 | properties = list(prop1 = 'non-id', prop2 = 6.0987),
56 | geometry = list(type = 'MultiPolygon',
57 | coordinates = list(matrix(runif(20), nrow = 10, ncol = 2),
58 | matrix(runif(20), nrow = 10, ncol = 2))))
59 |
60 | list_features = list(Feature1, Feature2)
61 |
62 | path_feat_col = tempfile(fileext = '.geojson')
63 |
64 | res = save_R_list_Features_2_FeatureCollection(input_list = list_features,
65 | path_to_file = path_feat_col,
66 | verbose = TRUE)
67 |
68 | #-------------------------------------
69 | # validate that the file can be loaded
70 | #-------------------------------------
71 |
72 | res_load = FROM_GeoJson_Schema(url_file_string = path_feat_col)
73 | str(res_load)
74 |
75 |
76 | #----------------------------------------------------
77 | # INVALID data types such as NA's will throw an ERROR
78 | #----------------------------------------------------
79 |
80 |
81 | Feature1 = list(type ="Feature",
82 | id = 1L,
83 | properties = list(prop1 = NA, prop2 = 1.0234),
84 | geometry = list(type = 'Polygon',
85 | coordinates = matrix(runif(20), nrow = 10, ncol = 2)))
86 |
87 | list_features = list(Feature1, Feature2)
88 |
89 | path_feat_col = tempfile(fileext = '.geojson')
90 |
91 | res = save_R_list_Features_2_FeatureCollection(input_list = list_features,
92 | path_to_file = path_feat_col,
93 | verbose = TRUE)
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/man/shiny_from_JSON.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{shiny_from_JSON}
4 | \alias{shiny_from_JSON}
5 | \title{secondary function for shiny Applications}
6 | \usage{
7 | shiny_from_JSON(input_file)
8 | }
9 | \arguments{
10 | \item{input_file}{a character string specifying a path to a file}
11 | }
12 | \value{
13 | a (nested) list
14 | }
15 | \description{
16 | secondary function for shiny Applications
17 | }
18 | \details{
19 | This function is meant for \emph{shiny Applications}. To read a GeoJson file use either the \emph{FROM_GeoJson} or \emph{FROM_GeoJson_Schema} function.
20 | }
21 |
--------------------------------------------------------------------------------
/src/Makevars:
--------------------------------------------------------------------------------
1 | PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) -DNDEBUG
2 | PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(SHLIB_OPENMP_CXXFLAGS)
3 | PKG_CPPFLAGS = -I../inst/include/
4 |
5 |
--------------------------------------------------------------------------------
/src/Makevars.win:
--------------------------------------------------------------------------------
1 | PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) -DNDEBUG
2 | PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(SHLIB_OPENMP_CXXFLAGS)
3 | PKG_CPPFLAGS = -I../inst/include/
4 |
--------------------------------------------------------------------------------
/src/RcppExports.cpp:
--------------------------------------------------------------------------------
1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand
2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
3 |
4 | #include
5 | #include
6 |
7 | using namespace Rcpp;
8 |
9 | #ifdef RCPP_USE_GLOBAL_ROSTREAM
10 | Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get();
11 | Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
12 | #endif
13 |
14 | // export_From_geojson
15 | Rcpp::List export_From_geojson(std::string input_file, bool flatten_coords, bool average_coordinates, bool to_list);
16 | RcppExport SEXP _geojsonR_export_From_geojson(SEXP input_fileSEXP, SEXP flatten_coordsSEXP, SEXP average_coordinatesSEXP, SEXP to_listSEXP) {
17 | BEGIN_RCPP
18 | Rcpp::RObject rcpp_result_gen;
19 | Rcpp::RNGScope rcpp_rngScope_gen;
20 | Rcpp::traits::input_parameter< std::string >::type input_file(input_fileSEXP);
21 | Rcpp::traits::input_parameter< bool >::type flatten_coords(flatten_coordsSEXP);
22 | Rcpp::traits::input_parameter< bool >::type average_coordinates(average_coordinatesSEXP);
23 | Rcpp::traits::input_parameter< bool >::type to_list(to_listSEXP);
24 | rcpp_result_gen = Rcpp::wrap(export_From_geojson(input_file, flatten_coords, average_coordinates, to_list));
25 | return rcpp_result_gen;
26 | END_RCPP
27 | }
28 | // export_From_JSON
29 | SEXP export_From_JSON(std::string input_file);
30 | RcppExport SEXP _geojsonR_export_From_JSON(SEXP input_fileSEXP) {
31 | BEGIN_RCPP
32 | Rcpp::RObject rcpp_result_gen;
33 | Rcpp::RNGScope rcpp_rngScope_gen;
34 | Rcpp::traits::input_parameter< std::string >::type input_file(input_fileSEXP);
35 | rcpp_result_gen = Rcpp::wrap(export_From_JSON(input_file));
36 | return rcpp_result_gen;
37 | END_RCPP
38 | }
39 | // dump_geojson
40 | std::string dump_geojson(std::string input_data);
41 | RcppExport SEXP _geojsonR_dump_geojson(SEXP input_dataSEXP) {
42 | BEGIN_RCPP
43 | Rcpp::RObject rcpp_result_gen;
44 | Rcpp::RNGScope rcpp_rngScope_gen;
45 | Rcpp::traits::input_parameter< std::string >::type input_data(input_dataSEXP);
46 | rcpp_result_gen = Rcpp::wrap(dump_geojson(input_data));
47 | return rcpp_result_gen;
48 | END_RCPP
49 | }
50 | // Features_TO_Collection
51 | std::string Features_TO_Collection(std::vector feat_files_lst, std::vector bbox_vec, bool verbose);
52 | RcppExport SEXP _geojsonR_Features_TO_Collection(SEXP feat_files_lstSEXP, SEXP bbox_vecSEXP, SEXP verboseSEXP) {
53 | BEGIN_RCPP
54 | Rcpp::RObject rcpp_result_gen;
55 | Rcpp::RNGScope rcpp_rngScope_gen;
56 | Rcpp::traits::input_parameter< std::vector >::type feat_files_lst(feat_files_lstSEXP);
57 | Rcpp::traits::input_parameter< std::vector >::type bbox_vec(bbox_vecSEXP);
58 | Rcpp::traits::input_parameter< bool >::type verbose(verboseSEXP);
59 | rcpp_result_gen = Rcpp::wrap(Features_TO_Collection(feat_files_lst, bbox_vec, verbose));
60 | return rcpp_result_gen;
61 | END_RCPP
62 | }
63 | // export_From_geojson_schema
64 | Rcpp::List export_From_geojson_schema(std::string input_file, std::string GEOMETRY_OBJECT_NAME, bool average_coordinates, bool to_list);
65 | RcppExport SEXP _geojsonR_export_From_geojson_schema(SEXP input_fileSEXP, SEXP GEOMETRY_OBJECT_NAMESEXP, SEXP average_coordinatesSEXP, SEXP to_listSEXP) {
66 | BEGIN_RCPP
67 | Rcpp::RObject rcpp_result_gen;
68 | Rcpp::RNGScope rcpp_rngScope_gen;
69 | Rcpp::traits::input_parameter< std::string >::type input_file(input_fileSEXP);
70 | Rcpp::traits::input_parameter< std::string >::type GEOMETRY_OBJECT_NAME(GEOMETRY_OBJECT_NAMESEXP);
71 | Rcpp::traits::input_parameter< bool >::type average_coordinates(average_coordinatesSEXP);
72 | Rcpp::traits::input_parameter< bool >::type to_list(to_listSEXP);
73 | rcpp_result_gen = Rcpp::wrap(export_From_geojson_schema(input_file, GEOMETRY_OBJECT_NAME, average_coordinates, to_list));
74 | return rcpp_result_gen;
75 | END_RCPP
76 | }
77 | // list_files
78 | std::vector list_files(const std::string& path, bool full_path);
79 | RcppExport SEXP _geojsonR_list_files(SEXP pathSEXP, SEXP full_pathSEXP) {
80 | BEGIN_RCPP
81 | Rcpp::RObject rcpp_result_gen;
82 | Rcpp::RNGScope rcpp_rngScope_gen;
83 | Rcpp::traits::input_parameter< const std::string& >::type path(pathSEXP);
84 | Rcpp::traits::input_parameter< bool >::type full_path(full_pathSEXP);
85 | rcpp_result_gen = Rcpp::wrap(list_files(path, full_path));
86 | return rcpp_result_gen;
87 | END_RCPP
88 | }
89 | // merge_json
90 | void merge_json(const std::string& input_folder, std::string output_file, std::string concat_delimiter, bool verbose);
91 | RcppExport SEXP _geojsonR_merge_json(SEXP input_folderSEXP, SEXP output_fileSEXP, SEXP concat_delimiterSEXP, SEXP verboseSEXP) {
92 | BEGIN_RCPP
93 | Rcpp::RNGScope rcpp_rngScope_gen;
94 | Rcpp::traits::input_parameter< const std::string& >::type input_folder(input_folderSEXP);
95 | Rcpp::traits::input_parameter< std::string >::type output_file(output_fileSEXP);
96 | Rcpp::traits::input_parameter< std::string >::type concat_delimiter(concat_delimiterSEXP);
97 | Rcpp::traits::input_parameter< bool >::type verbose(verboseSEXP);
98 | merge_json(input_folder, output_file, concat_delimiter, verbose);
99 | return R_NilValue;
100 | END_RCPP
101 | }
102 | // DATA_TYPE
103 | std::string DATA_TYPE(SEXP sublist);
104 | RcppExport SEXP _geojsonR_DATA_TYPE(SEXP sublistSEXP) {
105 | BEGIN_RCPP
106 | Rcpp::RObject rcpp_result_gen;
107 | Rcpp::RNGScope rcpp_rngScope_gen;
108 | Rcpp::traits::input_parameter< SEXP >::type sublist(sublistSEXP);
109 | rcpp_result_gen = Rcpp::wrap(DATA_TYPE(sublist));
110 | return rcpp_result_gen;
111 | END_RCPP
112 | }
113 | // inner_coords
114 | std::string inner_coords(Rcpp::List geom_lst, int z, bool polygon_interior);
115 | RcppExport SEXP _geojsonR_inner_coords(SEXP geom_lstSEXP, SEXP zSEXP, SEXP polygon_interiorSEXP) {
116 | BEGIN_RCPP
117 | Rcpp::RObject rcpp_result_gen;
118 | Rcpp::RNGScope rcpp_rngScope_gen;
119 | Rcpp::traits::input_parameter< Rcpp::List >::type geom_lst(geom_lstSEXP);
120 | Rcpp::traits::input_parameter< int >::type z(zSEXP);
121 | Rcpp::traits::input_parameter< bool >::type polygon_interior(polygon_interiorSEXP);
122 | rcpp_result_gen = Rcpp::wrap(inner_coords(geom_lst, z, polygon_interior));
123 | return rcpp_result_gen;
124 | END_RCPP
125 | }
126 | // Polygon_with_interior_rings
127 | std::string Polygon_with_interior_rings(Rcpp::List geom_lst, int i, bool verbose);
128 | RcppExport SEXP _geojsonR_Polygon_with_interior_rings(SEXP geom_lstSEXP, SEXP iSEXP, SEXP verboseSEXP) {
129 | BEGIN_RCPP
130 | Rcpp::RObject rcpp_result_gen;
131 | Rcpp::RNGScope rcpp_rngScope_gen;
132 | Rcpp::traits::input_parameter< Rcpp::List >::type geom_lst(geom_lstSEXP);
133 | Rcpp::traits::input_parameter< int >::type i(iSEXP);
134 | Rcpp::traits::input_parameter< bool >::type verbose(verboseSEXP);
135 | rcpp_result_gen = Rcpp::wrap(Polygon_with_interior_rings(geom_lst, i, verbose));
136 | return rcpp_result_gen;
137 | END_RCPP
138 | }
139 | // SAVE_R_list_Features_2_FeatureCollection
140 | std::string SAVE_R_list_Features_2_FeatureCollection(Rcpp::List x, std::string path_to_file, bool verbose);
141 | RcppExport SEXP _geojsonR_SAVE_R_list_Features_2_FeatureCollection(SEXP xSEXP, SEXP path_to_fileSEXP, SEXP verboseSEXP) {
142 | BEGIN_RCPP
143 | Rcpp::RObject rcpp_result_gen;
144 | Rcpp::RNGScope rcpp_rngScope_gen;
145 | Rcpp::traits::input_parameter< Rcpp::List >::type x(xSEXP);
146 | Rcpp::traits::input_parameter< std::string >::type path_to_file(path_to_fileSEXP);
147 | Rcpp::traits::input_parameter< bool >::type verbose(verboseSEXP);
148 | rcpp_result_gen = Rcpp::wrap(SAVE_R_list_Features_2_FeatureCollection(x, path_to_file, verbose));
149 | return rcpp_result_gen;
150 | END_RCPP
151 | }
152 | // export_To_GeoJson
153 | Rcpp::List export_To_GeoJson(std::string geometry_object, std::vector data_POINTS, std::vector> data_ARRAYS, std::vector>> data_ARRAY_ARRAYS, std::vector>>> data_POLYGON_ARRAYS, bool stringify);
154 | RcppExport SEXP _geojsonR_export_To_GeoJson(SEXP geometry_objectSEXP, SEXP data_POINTSSEXP, SEXP data_ARRAYSSEXP, SEXP data_ARRAY_ARRAYSSEXP, SEXP data_POLYGON_ARRAYSSEXP, SEXP stringifySEXP) {
155 | BEGIN_RCPP
156 | Rcpp::RObject rcpp_result_gen;
157 | Rcpp::RNGScope rcpp_rngScope_gen;
158 | Rcpp::traits::input_parameter< std::string >::type geometry_object(geometry_objectSEXP);
159 | Rcpp::traits::input_parameter< std::vector >::type data_POINTS(data_POINTSSEXP);
160 | Rcpp::traits::input_parameter< std::vector> >::type data_ARRAYS(data_ARRAYSSEXP);
161 | Rcpp::traits::input_parameter< std::vector>> >::type data_ARRAY_ARRAYS(data_ARRAY_ARRAYSSEXP);
162 | Rcpp::traits::input_parameter< std::vector>>> >::type data_POLYGON_ARRAYS(data_POLYGON_ARRAYSSEXP);
163 | Rcpp::traits::input_parameter< bool >::type stringify(stringifySEXP);
164 | rcpp_result_gen = Rcpp::wrap(export_To_GeoJson(geometry_object, data_POINTS, data_ARRAYS, data_ARRAY_ARRAYS, data_POLYGON_ARRAYS, stringify));
165 | return rcpp_result_gen;
166 | END_RCPP
167 | }
168 | // Geom_Collection
169 | Rcpp::List Geom_Collection(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify);
170 | RcppExport SEXP _geojsonR_Geom_Collection(SEXP geometry_object_namesSEXP, SEXP geometry_objectsSEXP, SEXP stringifySEXP) {
171 | BEGIN_RCPP
172 | Rcpp::RObject rcpp_result_gen;
173 | Rcpp::RNGScope rcpp_rngScope_gen;
174 | Rcpp::traits::input_parameter< std::vector >::type geometry_object_names(geometry_object_namesSEXP);
175 | Rcpp::traits::input_parameter< Rcpp::List >::type geometry_objects(geometry_objectsSEXP);
176 | Rcpp::traits::input_parameter< bool >::type stringify(stringifySEXP);
177 | rcpp_result_gen = Rcpp::wrap(Geom_Collection(geometry_object_names, geometry_objects, stringify));
178 | return rcpp_result_gen;
179 | END_RCPP
180 | }
181 | // Feature_Obj
182 | Rcpp::List Feature_Obj(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify);
183 | RcppExport SEXP _geojsonR_Feature_Obj(SEXP geometry_object_namesSEXP, SEXP geometry_objectsSEXP, SEXP stringifySEXP) {
184 | BEGIN_RCPP
185 | Rcpp::RObject rcpp_result_gen;
186 | Rcpp::RNGScope rcpp_rngScope_gen;
187 | Rcpp::traits::input_parameter< std::vector >::type geometry_object_names(geometry_object_namesSEXP);
188 | Rcpp::traits::input_parameter< Rcpp::List >::type geometry_objects(geometry_objectsSEXP);
189 | Rcpp::traits::input_parameter< bool >::type stringify(stringifySEXP);
190 | rcpp_result_gen = Rcpp::wrap(Feature_Obj(geometry_object_names, geometry_objects, stringify));
191 | return rcpp_result_gen;
192 | END_RCPP
193 | }
194 | // Feature_collection_Obj
195 | Rcpp::List Feature_collection_Obj(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify);
196 | RcppExport SEXP _geojsonR_Feature_collection_Obj(SEXP geometry_object_namesSEXP, SEXP geometry_objectsSEXP, SEXP stringifySEXP) {
197 | BEGIN_RCPP
198 | Rcpp::RObject rcpp_result_gen;
199 | Rcpp::RNGScope rcpp_rngScope_gen;
200 | Rcpp::traits::input_parameter< std::vector >::type geometry_object_names(geometry_object_namesSEXP);
201 | Rcpp::traits::input_parameter< Rcpp::List >::type geometry_objects(geometry_objectsSEXP);
202 | Rcpp::traits::input_parameter< bool >::type stringify(stringifySEXP);
203 | rcpp_result_gen = Rcpp::wrap(Feature_collection_Obj(geometry_object_names, geometry_objects, stringify));
204 | return rcpp_result_gen;
205 | END_RCPP
206 | }
207 |
--------------------------------------------------------------------------------
/src/TO_geojson.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Copyright (C) 2017 Lampros Mouselimis
4 | *
5 | * @file TO_geojson.cpp
6 | *
7 | * @author Lampros Mouselimis
8 | *
9 | * @date February - March 2017
10 | *
11 | * @Notes: converts data to a GeoJson object
12 | *
13 | * @last_modified: March 2017
14 | *
15 | **/
16 |
17 |
18 | # include
19 | // [[Rcpp::depends("RcppArmadillo")]]
20 | // [[Rcpp::plugins(cpp11)]]
21 |
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include
29 | #include
30 |
31 | #include "json11.h"
32 |
33 |
34 |
35 | // Classes to build GeoJson-Geometries
36 | //
37 |
38 | template
39 | class GeoJson_Geometries {
40 |
41 | public:
42 |
43 | GeoJson_Geometries() { }
44 |
45 |
46 | // inner geometry object (json11)
47 | //
48 |
49 | json11::Json Inner_GeoJson(std::string geometry_object, T data) {
50 |
51 | json11::Json::array OBJ;
52 |
53 | for (unsigned int i = 0; i < data.size(); i++) {
54 |
55 | OBJ.push_back(data[i]);
56 | }
57 |
58 | json11::Json geo_json = json11::Json::object {
59 |
60 | { "type", geometry_object },
61 |
62 | { "coordinates", OBJ },
63 | };
64 |
65 | return geo_json;
66 | }
67 |
68 |
69 | // geometry-object : "Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"
70 | //
71 |
72 | Rcpp::List To_Geom_Obj(std::string geometry_object, T data, bool stringify = false) {
73 |
74 | Rcpp::List RES;
75 |
76 | if (stringify) {
77 |
78 | json11::Json geo_json = Inner_GeoJson(geometry_object, data);
79 |
80 | std::string json_str = geo_json.dump();
81 |
82 | RES["json_dump"] = json_str;
83 | }
84 |
85 | RES["type"] = geometry_object;
86 |
87 | RES["coordinates"] = data;
88 |
89 | return RES;
90 | }
91 |
92 | ~GeoJson_Geometries() { }
93 | };
94 |
95 |
96 |
97 |
98 | // Class to build : 'Geometry-Collection', 'Feature', and 'Feature-Collection'
99 | //
100 |
101 |
102 | class GeoJson_Collections {
103 |
104 | public:
105 |
106 | // array of geometry-objects
107 | //
108 |
109 | json11::Json::array array_geometry_collection(std::vector geometry_object_names, Rcpp::List geometry_objects) {
110 |
111 | json11::Json::array array_geometries;
112 |
113 | for (unsigned int i = 0; i < geometry_object_names.size(); i++) {
114 |
115 | json11::Json geo_json;
116 |
117 | if (geometry_object_names[i] == "Point") {
118 |
119 | GeoJson_Geometries> gjg;
120 |
121 | std::vector tmp_dat = geometry_objects[i];
122 |
123 | geo_json = gjg.Inner_GeoJson(geometry_object_names[i], tmp_dat);
124 | }
125 |
126 | else if (geometry_object_names[i] == "MultiPoint" || geometry_object_names[i] == "LineString") {
127 |
128 | GeoJson_Geometries>> gjg;
129 |
130 | std::vector> tmp_dat = geometry_objects[i];
131 |
132 | geo_json = gjg.Inner_GeoJson(geometry_object_names[i], tmp_dat);
133 | }
134 |
135 | else if (geometry_object_names[i] == "MultiLineString" || geometry_object_names[i] == "Polygon") {
136 |
137 | GeoJson_Geometries>>> gjg;
138 |
139 | std::vector>> tmp_dat = geometry_objects[i];
140 |
141 | geo_json = gjg.Inner_GeoJson(geometry_object_names[i], tmp_dat);
142 | }
143 |
144 | else if (geometry_object_names[i] == "MultiPolygon") {
145 |
146 | GeoJson_Geometries>>>> gjg;
147 |
148 | std::vector>>> tmp_dat = geometry_objects[i];
149 |
150 | geo_json = gjg.Inner_GeoJson(geometry_object_names[i], tmp_dat);
151 | }
152 |
153 | else {
154 |
155 | Rcpp::stop("invalid GeoJson geometry object --> array_geometry_collection() function");
156 | }
157 |
158 | array_geometries.push_back(geo_json);
159 | }
160 |
161 | return array_geometries;
162 | }
163 |
164 |
165 | // 'GeometryCollection' object
166 | //
167 |
168 | Rcpp::List geometry_collection(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify = false) {
169 |
170 | Rcpp::List RES;
171 |
172 | std::string tmp_nam = "GeometryCollection";
173 |
174 | if (stringify) {
175 |
176 | json11::Json::array ARRAY = array_geometry_collection(geometry_object_names, geometry_objects);
177 |
178 | json11::Json geom_OBJECTS = json11::Json::object {
179 |
180 | { "type", tmp_nam },
181 |
182 | { "geometries", ARRAY },
183 |
184 | };
185 |
186 | std::string json_str = geom_OBJECTS.dump();
187 |
188 | RES["json_dump"] = json_str;
189 | }
190 |
191 | RES["type"] = tmp_nam;
192 |
193 | RES["geometries"] = geometry_objects;
194 |
195 | return RES;
196 | }
197 |
198 |
199 | // recursive function for the 'properties' member of the 'Feature' object [ if stringify = TRUE ]
200 | // For, the 'TYPEOF()', 'LENGTH', 'REALSXP', 'LGLSXP etc. SEE :
201 | // http://adv-r.had.co.nz/C-interface.html, https://github.com/hadley/pryr/blob/master/src/typename.cpp,
202 | // https://github.com/hadley/r-internals/blob/master/vectors.md, http://gallery.rcpp.org/articles/rcpp-wrap-and-recurse/
203 | //
204 |
205 | json11::Json typeof_item(Rcpp::List rec_prop) {
206 |
207 | json11::Json::object properties_OBJ;
208 |
209 | std::vector prop_nams = rec_prop.attr("names");
210 |
211 | unsigned int REC_SIZE = rec_prop.size();
212 |
213 | for (unsigned int f = 0; f < REC_SIZE; f++) {
214 |
215 | std::string tmp_nam = prop_nams[f];
216 |
217 | int length_item = LENGTH(rec_prop[f]); // distinction between 'float' and 'vector of floats' using LENGTH()
218 |
219 | if (length_item == 1) {
220 |
221 | if (TYPEOF(rec_prop[f]) == REALSXP) {
222 |
223 | double tmp_dbl = Rcpp::as(rec_prop[f]);
224 |
225 | properties_OBJ[tmp_nam] = json11::Json(tmp_dbl);}
226 |
227 | else if (TYPEOF(rec_prop[f]) == INTSXP) {
228 |
229 | int tmp_dbl_int = Rcpp::as(rec_prop[f]);
230 |
231 | properties_OBJ[tmp_nam] = json11::Json(tmp_dbl_int);}
232 |
233 | else if (TYPEOF(rec_prop[f]) == LGLSXP) {
234 |
235 | bool tmp_bool = rec_prop[f];
236 |
237 | properties_OBJ[tmp_nam] = json11::Json(tmp_bool);}
238 |
239 | else if (TYPEOF(rec_prop[f]) == STRSXP) {
240 |
241 | std::string tmp_str = Rcpp::as(rec_prop[f]);
242 |
243 | properties_OBJ[tmp_nam] = json11::Json(tmp_str);}
244 |
245 | else if (TYPEOF(rec_prop[f]) == NILSXP) {
246 |
247 | std::string tmp_str = "null";
248 |
249 | properties_OBJ[tmp_nam] = json11::Json(tmp_str);}
250 |
251 | else if (TYPEOF(rec_prop[f]) == VECSXP) {
252 |
253 | Rcpp::List tmp_lst = rec_prop[f];
254 |
255 | properties_OBJ[tmp_nam] = typeof_item(tmp_lst);}
256 |
257 | else {
258 |
259 | Rcpp::stop("invalid Json object of length == 1 --> typeof_item() function");
260 | }
261 | }
262 |
263 | else {
264 |
265 | if (TYPEOF(rec_prop[f]) == REALSXP) {
266 |
267 | std::vector arr_vec = Rcpp::as>(rec_prop[f]);
268 |
269 | properties_OBJ[tmp_nam] = json11::Json(arr_vec);}
270 |
271 | else if (TYPEOF(rec_prop[f]) == INTSXP) {
272 |
273 | std::vector arr_vec_int = Rcpp::as>(rec_prop[f]);
274 |
275 | properties_OBJ[tmp_nam] = json11::Json(arr_vec_int);}
276 |
277 | else if (TYPEOF(rec_prop[f]) == VECSXP) {
278 |
279 | Rcpp::List tmp_lst = rec_prop[f];
280 |
281 | properties_OBJ[tmp_nam] = typeof_item(tmp_lst);}
282 |
283 | else {
284 |
285 | Rcpp::stop("invalid Json object of length > 1 --> typeof_item() function");
286 | }
287 | }
288 | }
289 |
290 | return properties_OBJ;
291 | }
292 |
293 |
294 | // inner 'json11::Json::object' function for the 'properties' member of the 'Feature' object [ if stringify = TRUE ]
295 | //
296 |
297 | json11::Json::object inner_Feature(std::vector geometry_object_names, Rcpp::List geometry_objects, std::string Feature_name) {
298 |
299 | json11::Json::object feature_OBJ; // build the Json::object incrementally
300 |
301 | feature_OBJ["type"] = Feature_name;
302 |
303 | for (unsigned int i = 0; i < geometry_object_names.size(); i++) {
304 |
305 | if (geometry_object_names[i] == "id") {
306 |
307 | if (TYPEOF(geometry_objects[i]) == STRSXP) {
308 |
309 | std::string tmp_id = Rcpp::as(geometry_objects["id"]);
310 |
311 | feature_OBJ["id"] = json11::Json(tmp_id);}
312 |
313 | else if (TYPEOF(geometry_objects[i]) == REALSXP) {
314 |
315 | double tmp_id = Rcpp::as(geometry_objects["id"]);
316 |
317 | feature_OBJ["id"] = json11::Json(tmp_id);}
318 |
319 | else {
320 |
321 | Rcpp::stop("the 'id' member should be either a character string or a numeric value --> inner_Feature() function");
322 | }
323 | }
324 |
325 | else if (geometry_object_names[i] == "bbox") {
326 |
327 | std::vector bbox_vec = geometry_objects["bbox"];
328 |
329 | feature_OBJ["bbox"] = json11::Json(bbox_vec);}
330 |
331 | else if (geometry_object_names[i] == "geometry") {
332 |
333 | Rcpp::List tmp_lst = geometry_objects[i];
334 |
335 | std::vector tmp_lst_nams = tmp_lst.attr("names");
336 |
337 | json11::Json::array tmp_lst_array = array_geometry_collection(tmp_lst_nams, geometry_objects[i]); // std::vector, Rcpp::List as input
338 |
339 | feature_OBJ["geometry"] = json11::Json(tmp_lst_array[0]);} // extract the object from the array [ first array element ]
340 |
341 | else if (geometry_object_names[i] == "properties") {
342 |
343 | json11::Json::object properties_OBJ; // initialize second json-object for properties;
344 |
345 | Rcpp::List tmp_prop = geometry_objects[i];
346 |
347 | if (tmp_prop.size() == 0) {
348 |
349 | feature_OBJ["properties"] = json11::Json(properties_OBJ);} // empty object if Rcpp::List is empty
350 |
351 | else {
352 |
353 | feature_OBJ["properties"] = typeof_item(tmp_prop); // recursive function
354 | }
355 | }
356 |
357 | else {
358 |
359 | Rcpp::stop("invalid member of the Feature geometry object --> inner_Feature() function");
360 | }
361 | }
362 |
363 | return feature_OBJ;
364 | }
365 |
366 |
367 | // 'Feature' geometry object
368 | //
369 |
370 | Rcpp::List feature_OBJECT(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify = false) {
371 |
372 | Rcpp::List RES = geometry_objects;
373 |
374 | std::string tmp_nam = "Feature";
375 |
376 | if (stringify) {
377 |
378 | json11::Json::object feature_OBJ = inner_Feature(geometry_object_names, geometry_objects, tmp_nam);
379 |
380 | json11::Json res_json = feature_OBJ;
381 |
382 | std::string json_str = res_json.dump();
383 |
384 | RES["json_dump"] = json_str;
385 | }
386 |
387 | RES["type"] = tmp_nam;
388 |
389 | return RES;
390 | }
391 |
392 |
393 | // 'FeatureCollection' geometry object
394 | //
395 |
396 | Rcpp::List feature_collection(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify = false) {
397 |
398 | Rcpp::List RES = geometry_objects;
399 |
400 | std::string feat_col_nam = "FeatureCollection";
401 |
402 | RES["type"] = feat_col_nam;
403 |
404 | if (stringify) {
405 |
406 | json11::Json::object feature_col_OBJ;
407 |
408 | feature_col_OBJ["type"] = feat_col_nam;
409 |
410 | for (unsigned int i = 0; i < geometry_object_names.size(); i++) {
411 |
412 | if (geometry_object_names[i] == "bbox") {
413 |
414 | std::vector bbox_vec = geometry_objects["bbox"];
415 |
416 | feature_col_OBJ["bbox"] = json11::Json(bbox_vec);}
417 |
418 | else if (geometry_object_names[i] == "features") {
419 |
420 | json11::Json::array multiple_features_OBJ; // initialize second json-object for multiple-feature-objects;
421 |
422 | Rcpp::List tmp_feat = geometry_objects[i];
423 |
424 | if (tmp_feat.size() == 0) {
425 |
426 | feature_col_OBJ["features"] = json11::Json(multiple_features_OBJ);} // empty object if Rcpp::List is empty
427 |
428 | else {
429 |
430 | std::vector outer_lst_nams = tmp_feat.attr("names");
431 |
432 | for (unsigned int j = 0; j < outer_lst_nams.size(); j++) {
433 |
434 | Rcpp::List inner_feat_lst = tmp_feat[j];
435 |
436 | std::vector inner_lst_nams = inner_feat_lst.attr("names");
437 |
438 | std::string tmp_inner_nam = outer_lst_nams[j];
439 |
440 | json11::Json::object inner_loop_json11 = inner_Feature(inner_lst_nams, inner_feat_lst, tmp_inner_nam);
441 |
442 | multiple_features_OBJ.push_back(inner_loop_json11);
443 | }
444 | }
445 |
446 | feature_col_OBJ["features"] = multiple_features_OBJ;
447 | }
448 |
449 | else {
450 |
451 | Rcpp::stop("invalid object for the member 'features' of the 'FeatureCollection' object --> feature_collection() function");
452 | }
453 | }
454 |
455 | json11::Json inner_res_json = feature_col_OBJ;
456 |
457 | std::string json_str = inner_res_json.dump();
458 |
459 | RES["json_dump"] = json_str;
460 | }
461 |
462 | return RES;
463 | }
464 |
465 | };
466 |
467 |
468 |
469 |
470 | //----------------------------------
471 | // TO-GeoJson functions [ exported ]
472 | //----------------------------------
473 |
474 |
475 | // Returns one of the following geometry-objects : "Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"
476 | // either the 'vector' OR the 'nested-vector' of the objects must be an empty object [ empty = numeric(0) ]
477 | //
478 |
479 | // [[Rcpp::export]]
480 | Rcpp::List export_To_GeoJson(std::string geometry_object, std::vector data_POINTS, std::vector> data_ARRAYS, std::vector>> data_ARRAY_ARRAYS,
481 |
482 | std::vector>>> data_POLYGON_ARRAYS, bool stringify = false) {
483 |
484 |
485 | if (geometry_object == "Point") {
486 |
487 | GeoJson_Geometries> tgj;
488 |
489 | return tgj.To_Geom_Obj(geometry_object, data_POINTS, stringify);
490 | }
491 |
492 | else if (geometry_object == "MultiPoint" || geometry_object == "LineString") {
493 |
494 | GeoJson_Geometries>> tgj;
495 |
496 | return tgj.To_Geom_Obj(geometry_object, data_ARRAYS, stringify);}
497 |
498 | else if (geometry_object == "MultiLineString" || geometry_object == "Polygon") {
499 |
500 | GeoJson_Geometries>>> tgj;
501 |
502 | return tgj.To_Geom_Obj(geometry_object, data_ARRAY_ARRAYS, stringify);}
503 |
504 | else if (geometry_object == "MultiPolygon") {
505 |
506 | GeoJson_Geometries>>>> tgj;
507 |
508 | return tgj.To_Geom_Obj(geometry_object, data_POLYGON_ARRAYS, stringify);}
509 |
510 | else {
511 |
512 | Rcpp::stop("invalid geometry object --> export_To_GeoJson() function");
513 | }
514 | }
515 |
516 |
517 |
518 | // Geometry-collection object
519 | //
520 |
521 | // [[Rcpp::export]]
522 | Rcpp::List Geom_Collection(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify = false) {
523 |
524 | GeoJson_Collections gjc_geometry;
525 |
526 | return gjc_geometry.geometry_collection(geometry_object_names, geometry_objects, stringify);
527 | }
528 |
529 |
530 |
531 | // Feature object
532 | //
533 |
534 | // [[Rcpp::export]]
535 | Rcpp::List Feature_Obj(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify = false) {
536 |
537 | GeoJson_Collections gjc_feature;
538 |
539 | return gjc_feature.feature_OBJECT(geometry_object_names, geometry_objects, stringify);
540 | }
541 |
542 |
543 |
544 | // FeatureCollection object
545 | //
546 |
547 | // [[Rcpp::export]]
548 | Rcpp::List Feature_collection_Obj(std::vector geometry_object_names, Rcpp::List geometry_objects, bool stringify = false) {
549 |
550 | GeoJson_Collections gjc_feature_collection;
551 |
552 | return gjc_feature_collection.feature_collection(geometry_object_names, geometry_objects, stringify);
553 | }
554 |
555 |
556 |
--------------------------------------------------------------------------------
/src/init.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include // for NULL
4 | #include
5 |
6 | /* FIXME:
7 | Check these declarations against the C/Fortran source code.
8 | */
9 |
10 | /* .Call calls */
11 | extern SEXP _geojsonR_DATA_TYPE(SEXP);
12 | extern SEXP _geojsonR_dump_geojson(SEXP);
13 | extern SEXP _geojsonR_export_From_geojson(SEXP, SEXP, SEXP, SEXP);
14 | extern SEXP _geojsonR_export_From_geojson_schema(SEXP, SEXP, SEXP, SEXP);
15 | extern SEXP _geojsonR_export_From_JSON(SEXP);
16 | extern SEXP _geojsonR_export_To_GeoJson(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
17 | extern SEXP _geojsonR_Feature_collection_Obj(SEXP, SEXP, SEXP);
18 | extern SEXP _geojsonR_Feature_Obj(SEXP, SEXP, SEXP);
19 | extern SEXP _geojsonR_Features_TO_Collection(SEXP, SEXP, SEXP);
20 | extern SEXP _geojsonR_Geom_Collection(SEXP, SEXP, SEXP);
21 | extern SEXP _geojsonR_inner_coords(SEXP, SEXP, SEXP);
22 | extern SEXP _geojsonR_list_files(SEXP, SEXP);
23 | extern SEXP _geojsonR_merge_json(SEXP, SEXP, SEXP, SEXP);
24 | extern SEXP _geojsonR_Polygon_with_interior_rings(SEXP, SEXP, SEXP);
25 | extern SEXP _geojsonR_SAVE_R_list_Features_2_FeatureCollection(SEXP, SEXP, SEXP);
26 |
27 | static const R_CallMethodDef CallEntries[] = {
28 | {"_geojsonR_DATA_TYPE", (DL_FUNC) &_geojsonR_DATA_TYPE, 1},
29 | {"_geojsonR_dump_geojson", (DL_FUNC) &_geojsonR_dump_geojson, 1},
30 | {"_geojsonR_export_From_geojson", (DL_FUNC) &_geojsonR_export_From_geojson, 4},
31 | {"_geojsonR_export_From_geojson_schema", (DL_FUNC) &_geojsonR_export_From_geojson_schema, 4},
32 | {"_geojsonR_export_From_JSON", (DL_FUNC) &_geojsonR_export_From_JSON, 1},
33 | {"_geojsonR_export_To_GeoJson", (DL_FUNC) &_geojsonR_export_To_GeoJson, 6},
34 | {"_geojsonR_Feature_collection_Obj", (DL_FUNC) &_geojsonR_Feature_collection_Obj, 3},
35 | {"_geojsonR_Feature_Obj", (DL_FUNC) &_geojsonR_Feature_Obj, 3},
36 | {"_geojsonR_Features_TO_Collection", (DL_FUNC) &_geojsonR_Features_TO_Collection, 3},
37 | {"_geojsonR_Geom_Collection", (DL_FUNC) &_geojsonR_Geom_Collection, 3},
38 | {"_geojsonR_inner_coords", (DL_FUNC) &_geojsonR_inner_coords, 3},
39 | {"_geojsonR_list_files", (DL_FUNC) &_geojsonR_list_files, 2},
40 | {"_geojsonR_merge_json", (DL_FUNC) &_geojsonR_merge_json, 4},
41 | {"_geojsonR_Polygon_with_interior_rings", (DL_FUNC) &_geojsonR_Polygon_with_interior_rings, 3},
42 | {"_geojsonR_SAVE_R_list_Features_2_FeatureCollection", (DL_FUNC) &_geojsonR_SAVE_R_list_Features_2_FeatureCollection, 3},
43 | {NULL, NULL, 0}
44 | };
45 |
46 | void R_init_geojsonR(DllInfo *dll)
47 | {
48 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
49 | R_useDynamicSymbols(dll, FALSE);
50 | }
51 |
--------------------------------------------------------------------------------
/src/json11.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2013 Dropbox, Inc.
2 | *
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy
4 | * of this software and associated documentation files (the "Software"), to deal
5 | * in the Software without restriction, including without limitation the rights
6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | * copies of the Software, and to permit persons to whom the Software is
8 | * furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in
11 | * all copies or substantial portions of the Software.
12 | *
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | * THE SOFTWARE.
20 | */
21 |
22 | #include "json11.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | namespace json11 {
31 |
32 | static const int max_depth = 200;
33 |
34 | using std::string;
35 | using std::vector;
36 | using std::map;
37 | using std::make_shared;
38 | using std::initializer_list;
39 |
40 | /* Helper for representing null - just a do-nothing struct, plus comparison
41 | * operators so the helpers in JsonValue work. We can't use nullptr_t because
42 | * it may not be orderable.
43 | */
44 | struct NullStruct {
45 | bool operator==(NullStruct) const { return true; }
46 | bool operator<(NullStruct) const { return false; }
47 | };
48 |
49 | /* * * * * * * * * * * * * * * * * * * *
50 | * Serialization
51 | */
52 |
53 | static void dump(NullStruct, string &out) {
54 | out += "null";
55 | }
56 |
57 | static void dump(double value, string &out) {
58 | if (std::isfinite(value)) {
59 | char buf[32];
60 | snprintf(buf, sizeof buf, "%.17g", value);
61 | out += buf;
62 | } else {
63 | out += "null";
64 | }
65 | }
66 |
67 | static void dump(int value, string &out) {
68 | char buf[32];
69 | snprintf(buf, sizeof buf, "%d", value);
70 | out += buf;
71 | }
72 |
73 | static void dump(bool value, string &out) {
74 | out += value ? "true" : "false";
75 | }
76 |
77 | static void dump(const string &value, string &out) {
78 | out += '"';
79 | for (size_t i = 0; i < value.length(); i++) {
80 | const char ch = value[i];
81 | if (ch == '\\') {
82 | out += "\\\\";
83 | } else if (ch == '"') {
84 | out += "\\\"";
85 | } else if (ch == '\b') {
86 | out += "\\b";
87 | } else if (ch == '\f') {
88 | out += "\\f";
89 | } else if (ch == '\n') {
90 | out += "\\n";
91 | } else if (ch == '\r') {
92 | out += "\\r";
93 | } else if (ch == '\t') {
94 | out += "\\t";
95 | } else if (static_cast(ch) <= 0x1f) {
96 | char buf[8];
97 | snprintf(buf, sizeof buf, "\\u%04x", ch);
98 | out += buf;
99 | } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80
100 | && static_cast(value[i+2]) == 0xa8) {
101 | out += "\\u2028";
102 | i += 2;
103 | } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80
104 | && static_cast(value[i+2]) == 0xa9) {
105 | out += "\\u2029";
106 | i += 2;
107 | } else {
108 | out += ch;
109 | }
110 | }
111 | out += '"';
112 | }
113 |
114 | static void dump(const Json::array &values, string &out) {
115 | bool first = true;
116 | out += "[";
117 | for (const auto &value : values) {
118 | if (!first)
119 | out += ", ";
120 | value.dump(out);
121 | first = false;
122 | }
123 | out += "]";
124 | }
125 |
126 | static void dump(const Json::object &values, string &out) {
127 | bool first = true;
128 | out += "{";
129 | for (const auto &kv : values) {
130 | if (!first)
131 | out += ", ";
132 | dump(kv.first, out);
133 | out += ": ";
134 | kv.second.dump(out);
135 | first = false;
136 | }
137 | out += "}";
138 | }
139 |
140 | void Json::dump(string &out) const {
141 | m_ptr->dump(out);
142 | }
143 |
144 | /* * * * * * * * * * * * * * * * * * * *
145 | * Value wrappers
146 | */
147 |
148 | template
149 | class Value : public JsonValue {
150 | protected:
151 |
152 | // Constructors
153 | explicit Value(const T &value) : m_value(value) {}
154 | explicit Value(T &&value) : m_value(std::move(value)) {}
155 |
156 | // Get type tag
157 | Json::Type type() const override {
158 | return tag;
159 | }
160 |
161 | // Comparisons
162 | bool equals(const JsonValue * other) const override {
163 | return m_value == static_cast *>(other)->m_value;
164 | }
165 | bool less(const JsonValue * other) const override {
166 | return m_value < static_cast *>(other)->m_value;
167 | }
168 |
169 | const T m_value;
170 | void dump(string &out) const override { json11::dump(m_value, out); }
171 | };
172 |
173 | class JsonDouble final : public Value {
174 | double number_value() const override { return m_value; }
175 | int int_value() const override { return static_cast(m_value); }
176 | bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
177 | bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
178 | public:
179 | explicit JsonDouble(double value) : Value(value) {}
180 | };
181 |
182 | class JsonInt final : public Value {
183 | double number_value() const override { return m_value; }
184 | int int_value() const override { return m_value; }
185 | bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
186 | bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
187 | public:
188 | explicit JsonInt(int value) : Value(value) {}
189 | };
190 |
191 | class JsonBoolean final : public Value {
192 | bool bool_value() const override { return m_value; }
193 | public:
194 | explicit JsonBoolean(bool value) : Value(value) {}
195 | };
196 |
197 | class JsonString final : public Value {
198 | const string &string_value() const override { return m_value; }
199 | public:
200 | explicit JsonString(const string &value) : Value(value) {}
201 | explicit JsonString(string &&value) : Value(std::move(value)) {}
202 | };
203 |
204 | class JsonArray final : public Value {
205 | const Json::array &array_items() const override { return m_value; }
206 | const Json & operator[](size_t i) const override;
207 | public:
208 | explicit JsonArray(const Json::array &value) : Value(value) {}
209 | explicit JsonArray(Json::array &&value) : Value(std::move(value)) {}
210 | };
211 |
212 | class JsonObject final : public Value {
213 | const Json::object &object_items() const override { return m_value; }
214 | const Json & operator[](const string &key) const override;
215 | public:
216 | explicit JsonObject(const Json::object &value) : Value(value) {}
217 | explicit JsonObject(Json::object &&value) : Value(std::move(value)) {}
218 | };
219 |
220 | class JsonNull final : public Value {
221 | public:
222 | JsonNull() : Value({}) {}
223 | };
224 |
225 | /* * * * * * * * * * * * * * * * * * * *
226 | * Static globals - static-init-safe
227 | */
228 | struct Statics {
229 | const std::shared_ptr null = make_shared();
230 | const std::shared_ptr t = make_shared(true);
231 | const std::shared_ptr f = make_shared(false);
232 | const string empty_string;
233 | const vector empty_vector;
234 | const map empty_map;
235 | Statics() {}
236 | };
237 |
238 | static const Statics & statics() {
239 | static const Statics s {};
240 | return s;
241 | }
242 |
243 | static const Json & static_null() {
244 | // This has to be separate, not in Statics, because Json() accesses statics().null.
245 | static const Json json_null;
246 | return json_null;
247 | }
248 |
249 | /* * * * * * * * * * * * * * * * * * * *
250 | * Constructors
251 | */
252 |
253 | Json::Json() noexcept : m_ptr(statics().null) {}
254 | Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
255 | Json::Json(double value) : m_ptr(make_shared(value)) {}
256 | Json::Json(int value) : m_ptr(make_shared(value)) {}
257 | Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
258 | Json::Json(const string &value) : m_ptr(make_shared(value)) {}
259 | Json::Json(string &&value) : m_ptr(make_shared(std::move(value))) {}
260 | Json::Json(const char * value) : m_ptr(make_shared(value)) {}
261 | Json::Json(const Json::array &values) : m_ptr(make_shared(values)) {}
262 | Json::Json(Json::array &&values) : m_ptr(make_shared(std::move(values))) {}
263 | Json::Json(const Json::object &values) : m_ptr(make_shared(values)) {}
264 | Json::Json(Json::object &&values) : m_ptr(make_shared(std::move(values))) {}
265 |
266 | /* * * * * * * * * * * * * * * * * * * *
267 | * Accessors
268 | */
269 |
270 | Json::Type Json::type() const { return m_ptr->type(); }
271 | double Json::number_value() const { return m_ptr->number_value(); }
272 | int Json::int_value() const { return m_ptr->int_value(); }
273 | bool Json::bool_value() const { return m_ptr->bool_value(); }
274 | const string & Json::string_value() const { return m_ptr->string_value(); }
275 | const vector & Json::array_items() const { return m_ptr->array_items(); }
276 | const map & Json::object_items() const { return m_ptr->object_items(); }
277 | const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; }
278 | const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; }
279 |
280 | double JsonValue::number_value() const { return 0; }
281 | int JsonValue::int_value() const { return 0; }
282 | bool JsonValue::bool_value() const { return false; }
283 | const string & JsonValue::string_value() const { return statics().empty_string; }
284 | const vector & JsonValue::array_items() const { return statics().empty_vector; }
285 | const map & JsonValue::object_items() const { return statics().empty_map; }
286 | const Json & JsonValue::operator[] (size_t) const { return static_null(); }
287 | const Json & JsonValue::operator[] (const string &) const { return static_null(); }
288 |
289 | const Json & JsonObject::operator[] (const string &key) const {
290 | auto iter = m_value.find(key);
291 | return (iter == m_value.end()) ? static_null() : iter->second;
292 | }
293 | const Json & JsonArray::operator[] (size_t i) const {
294 | if (i >= m_value.size()) return static_null();
295 | else return m_value[i];
296 | }
297 |
298 | /* * * * * * * * * * * * * * * * * * * *
299 | * Comparison
300 | */
301 |
302 | bool Json::operator== (const Json &other) const {
303 | if (m_ptr->type() != other.m_ptr->type())
304 | return false;
305 |
306 | return m_ptr->equals(other.m_ptr.get());
307 | }
308 |
309 | bool Json::operator< (const Json &other) const {
310 | if (m_ptr->type() != other.m_ptr->type())
311 | return m_ptr->type() < other.m_ptr->type();
312 |
313 | return m_ptr->less(other.m_ptr.get());
314 | }
315 |
316 | /* * * * * * * * * * * * * * * * * * * *
317 | * Parsing
318 | */
319 |
320 | /* esc(c)
321 | *
322 | * Format char c suitable for printing in an error message.
323 | */
324 | static inline string esc(char c) {
325 | char buf[12];
326 | if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) {
327 | snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
328 | } else {
329 | snprintf(buf, sizeof buf, "(%d)", c);
330 | }
331 | return string(buf);
332 | }
333 |
334 | static inline bool in_range(long x, long lower, long upper) {
335 | return (x >= lower && x <= upper);
336 | }
337 |
338 | namespace {
339 | /* JsonParser
340 | *
341 | * Object that tracks all state of an in-progress parse.
342 | */
343 | struct JsonParser final {
344 |
345 | /* State
346 | */
347 | const string &str;
348 | size_t i;
349 | string &err;
350 | bool failed;
351 | const JsonParse strategy;
352 |
353 | /* fail(msg, err_ret = Json())
354 | *
355 | * Mark this parse as failed.
356 | */
357 | Json fail(string &&msg) {
358 | return fail(std::move(msg), Json());
359 | }
360 |
361 | template
362 | T fail(string &&msg, const T err_ret) {
363 | if (!failed)
364 | err = std::move(msg);
365 | failed = true;
366 | return err_ret;
367 | }
368 |
369 | /* consume_whitespace()
370 | *
371 | * Advance until the current character is non-whitespace.
372 | */
373 | void consume_whitespace() {
374 | while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
375 | i++;
376 | }
377 |
378 | /* consume_comment()
379 | *
380 | * Advance comments (c-style inline and multiline).
381 | */
382 | bool consume_comment() {
383 | bool comment_found = false;
384 | if (str[i] == '/') {
385 | i++;
386 | if (i == str.size())
387 | return fail("unexpected end of input inside comment", false);
388 | if (str[i] == '/') { // inline comment
389 | i++;
390 | if (i == str.size())
391 | return fail("unexpected end of input inside inline comment", false);
392 | // advance until next line
393 | while (str[i] != '\n') {
394 | i++;
395 | if (i == str.size())
396 | return fail("unexpected end of input inside inline comment", false);
397 | }
398 | comment_found = true;
399 | }
400 | else if (str[i] == '*') { // multiline comment
401 | i++;
402 | if (i > str.size()-2)
403 | return fail("unexpected end of input inside multi-line comment", false);
404 | // advance until closing tokens
405 | while (!(str[i] == '*' && str[i+1] == '/')) {
406 | i++;
407 | if (i > str.size()-2)
408 | return fail(
409 | "unexpected end of input inside multi-line comment", false);
410 | }
411 | i += 2;
412 | if (i == str.size())
413 | return fail(
414 | "unexpected end of input inside multi-line comment", false);
415 | comment_found = true;
416 | }
417 | else
418 | return fail("malformed comment", false);
419 | }
420 | return comment_found;
421 | }
422 |
423 | /* consume_garbage()
424 | *
425 | * Advance until the current character is non-whitespace and non-comment.
426 | */
427 | void consume_garbage() {
428 | consume_whitespace();
429 | if(strategy == JsonParse::COMMENTS) {
430 | bool comment_found = false;
431 | do {
432 | comment_found = consume_comment();
433 | consume_whitespace();
434 | }
435 | while(comment_found);
436 | }
437 | }
438 |
439 | /* get_next_token()
440 | *
441 | * Return the next non-whitespace character. If the end of the input is reached,
442 | * flag an error and return 0.
443 | */
444 | char get_next_token() {
445 | consume_garbage();
446 | if (i == str.size())
447 | return fail("unexpected end of input", (char)0);
448 |
449 | return str[i++];
450 | }
451 |
452 | /* encode_utf8(pt, out)
453 | *
454 | * Encode pt as UTF-8 and add it to out.
455 | */
456 | void encode_utf8(long pt, string & out) {
457 | if (pt < 0)
458 | return;
459 |
460 | if (pt < 0x80) {
461 | out += static_cast(pt);
462 | } else if (pt < 0x800) {
463 | out += static_cast((pt >> 6) | 0xC0);
464 | out += static_cast((pt & 0x3F) | 0x80);
465 | } else if (pt < 0x10000) {
466 | out += static_cast((pt >> 12) | 0xE0);
467 | out += static_cast(((pt >> 6) & 0x3F) | 0x80);
468 | out += static_cast((pt & 0x3F) | 0x80);
469 | } else {
470 | out += static_cast((pt >> 18) | 0xF0);
471 | out += static_cast(((pt >> 12) & 0x3F) | 0x80);
472 | out += static_cast(((pt >> 6) & 0x3F) | 0x80);
473 | out += static_cast((pt & 0x3F) | 0x80);
474 | }
475 | }
476 |
477 | /* parse_string()
478 | *
479 | * Parse a string, starting at the current position.
480 | */
481 | string parse_string() {
482 | string out;
483 | long last_escaped_codepoint = -1;
484 | while (true) {
485 | if (i == str.size())
486 | return fail("unexpected end of input in string", "");
487 |
488 | char ch = str[i++];
489 |
490 | if (ch == '"') {
491 | encode_utf8(last_escaped_codepoint, out);
492 | return out;
493 | }
494 |
495 | if (in_range(ch, 0, 0x1f))
496 | return fail("unescaped " + esc(ch) + " in string", "");
497 |
498 | // The usual case: non-escaped characters
499 | if (ch != '\\') {
500 | encode_utf8(last_escaped_codepoint, out);
501 | last_escaped_codepoint = -1;
502 | out += ch;
503 | continue;
504 | }
505 |
506 | // Handle escapes
507 | if (i == str.size())
508 | return fail("unexpected end of input in string", "");
509 |
510 | ch = str[i++];
511 |
512 | if (ch == 'u') {
513 | // Extract 4-byte escape sequence
514 | string esc = str.substr(i, 4);
515 | // Explicitly check length of the substring. The following loop
516 | // relies on std::string returning the terminating NUL when
517 | // accessing str[length]. Checking here reduces brittleness.
518 | if (esc.length() < 4) {
519 | return fail("bad \\u escape: " + esc, "");
520 | }
521 | for (size_t j = 0; j < 4; j++) {
522 | if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
523 | && !in_range(esc[j], '0', '9'))
524 | return fail("bad \\u escape: " + esc, "");
525 | }
526 |
527 | long codepoint = strtol(esc.data(), nullptr, 16);
528 |
529 | // JSON specifies that characters outside the BMP shall be encoded as a pair
530 | // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
531 | // whether we're in the middle of such a beast: the previous codepoint was an
532 | // escaped lead (high) surrogate, and this is a trail (low) surrogate.
533 | if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
534 | && in_range(codepoint, 0xDC00, 0xDFFF)) {
535 | // Reassemble the two surrogate pairs into one astral-plane character, per
536 | // the UTF-16 algorithm.
537 | encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
538 | | (codepoint - 0xDC00)) + 0x10000, out);
539 | last_escaped_codepoint = -1;
540 | } else {
541 | encode_utf8(last_escaped_codepoint, out);
542 | last_escaped_codepoint = codepoint;
543 | }
544 |
545 | i += 4;
546 | continue;
547 | }
548 |
549 | encode_utf8(last_escaped_codepoint, out);
550 | last_escaped_codepoint = -1;
551 |
552 | if (ch == 'b') {
553 | out += '\b';
554 | } else if (ch == 'f') {
555 | out += '\f';
556 | } else if (ch == 'n') {
557 | out += '\n';
558 | } else if (ch == 'r') {
559 | out += '\r';
560 | } else if (ch == 't') {
561 | out += '\t';
562 | } else if (ch == '"' || ch == '\\' || ch == '/') {
563 | out += ch;
564 | } else {
565 | return fail("invalid escape character " + esc(ch), "");
566 | }
567 | }
568 | }
569 |
570 | /* parse_number()
571 | *
572 | * Parse a double.
573 | */
574 | Json parse_number() {
575 | size_t start_pos = i;
576 |
577 | if (str[i] == '-')
578 | i++;
579 |
580 | // Integer part
581 | if (str[i] == '0') {
582 | i++;
583 | if (in_range(str[i], '0', '9'))
584 | return fail("leading 0s not permitted in numbers");
585 | } else if (in_range(str[i], '1', '9')) {
586 | i++;
587 | while (in_range(str[i], '0', '9'))
588 | i++;
589 | } else {
590 | return fail("invalid " + esc(str[i]) + " in number");
591 | }
592 |
593 | if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
594 | && (i - start_pos) <= static_cast(std::numeric_limits::digits10)) {
595 | return std::atoi(str.c_str() + start_pos);
596 | }
597 |
598 | // Decimal part
599 | if (str[i] == '.') {
600 | i++;
601 | if (!in_range(str[i], '0', '9'))
602 | return fail("at least one digit required in fractional part");
603 |
604 | while (in_range(str[i], '0', '9'))
605 | i++;
606 | }
607 |
608 | // Exponent part
609 | if (str[i] == 'e' || str[i] == 'E') {
610 | i++;
611 |
612 | if (str[i] == '+' || str[i] == '-')
613 | i++;
614 |
615 | if (!in_range(str[i], '0', '9'))
616 | return fail("at least one digit required in exponent");
617 |
618 | while (in_range(str[i], '0', '9'))
619 | i++;
620 | }
621 |
622 | return std::strtod(str.c_str() + start_pos, nullptr);
623 | }
624 |
625 | /* expect(str, res)
626 | *
627 | * Expect that 'str' starts at the character that was just read. If it does, advance
628 | * the input and return res. If not, flag an error.
629 | */
630 | Json expect(const string &expected, Json res) {
631 | assert(i != 0);
632 | i--;
633 | if (str.compare(i, expected.length(), expected) == 0) {
634 | i += expected.length();
635 | return res;
636 | } else {
637 | return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
638 | }
639 | }
640 |
641 | /* parse_json()
642 | *
643 | * Parse a JSON object.
644 | */
645 | Json parse_json(int depth) {
646 | if (depth > max_depth) {
647 | return fail("exceeded maximum nesting depth");
648 | }
649 |
650 | char ch = get_next_token();
651 | if (failed)
652 | return Json();
653 |
654 | if (ch == '-' || (ch >= '0' && ch <= '9')) {
655 | i--;
656 | return parse_number();
657 | }
658 |
659 | if (ch == 't')
660 | return expect("true", true);
661 |
662 | if (ch == 'f')
663 | return expect("false", false);
664 |
665 | if (ch == 'n')
666 | return expect("null", Json());
667 |
668 | if (ch == '"')
669 | return parse_string();
670 |
671 | if (ch == '{') {
672 | map data;
673 | ch = get_next_token();
674 | if (ch == '}')
675 | return data;
676 |
677 | while (1) {
678 | if (ch != '"')
679 | return fail("expected '\"' in object, got " + esc(ch));
680 |
681 | string key = parse_string();
682 | if (failed)
683 | return Json();
684 |
685 | ch = get_next_token();
686 | if (ch != ':')
687 | return fail("expected ':' in object, got " + esc(ch));
688 |
689 | data[std::move(key)] = parse_json(depth + 1);
690 | if (failed)
691 | return Json();
692 |
693 | ch = get_next_token();
694 | if (ch == '}')
695 | break;
696 | if (ch != ',')
697 | return fail("expected ',' in object, got " + esc(ch));
698 |
699 | ch = get_next_token();
700 | }
701 | return data;
702 | }
703 |
704 | if (ch == '[') {
705 | vector data;
706 | ch = get_next_token();
707 | if (ch == ']')
708 | return data;
709 |
710 | while (1) {
711 | i--;
712 | data.push_back(parse_json(depth + 1));
713 | if (failed)
714 | return Json();
715 |
716 | ch = get_next_token();
717 | if (ch == ']')
718 | break;
719 | if (ch != ',')
720 | return fail("expected ',' in list, got " + esc(ch));
721 |
722 | ch = get_next_token();
723 | (void)ch;
724 | }
725 | return data;
726 | }
727 |
728 | return fail("expected value, got " + esc(ch));
729 | }
730 | };
731 | }//namespace {
732 |
733 | Json Json::parse(const string &in, string &err, JsonParse strategy) {
734 | JsonParser parser { in, 0, err, false, strategy };
735 | Json result = parser.parse_json(0);
736 |
737 | // Check for any trailing garbage
738 | parser.consume_garbage();
739 | if (parser.i != in.size())
740 | return parser.fail("unexpected trailing " + esc(in[parser.i]));
741 |
742 | return result;
743 | }
744 |
745 | // Documented in json11.hpp
746 | vector Json::parse_multi(const string &in,
747 | std::string::size_type &parser_stop_pos,
748 | string &err,
749 | JsonParse strategy) {
750 | JsonParser parser { in, 0, err, false, strategy };
751 | parser_stop_pos = 0;
752 | vector json_vec;
753 | while (parser.i != in.size() && !parser.failed) {
754 | json_vec.push_back(parser.parse_json(0));
755 | // Check for another object
756 | parser.consume_garbage();
757 | if (!parser.failed)
758 | parser_stop_pos = parser.i;
759 | }
760 | return json_vec;
761 | }
762 |
763 | /* * * * * * * * * * * * * * * * * * * *
764 | * Shape-checking
765 | */
766 |
767 | bool Json::has_shape(const shape & types, string & err) const {
768 | if (!is_object()) {
769 | err = "expected JSON object, got " + dump();
770 | return false;
771 | }
772 |
773 | for (auto & item : types) {
774 | if ((*this)[item.first].type() != item.second) {
775 | err = "bad type for " + item.first + " in " + dump();
776 | return false;
777 | }
778 | }
779 |
780 | return true;
781 | }
782 |
783 | } // namespace json11
784 |
--------------------------------------------------------------------------------
/src/json11.h:
--------------------------------------------------------------------------------
1 | /* json11
2 | *
3 | * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
4 | *
5 | * The core object provided by the library is json11::Json. A Json object represents any JSON
6 | * value: null, bool, number (int or double), string (std::string), array (std::vector), or
7 | * object (std::map).
8 | *
9 | * Json objects act like values: they can be assigned, copied, moved, compared for equality or
10 | * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and
11 | * Json::parse (static) to parse a std::string as a Json object.
12 | *
13 | * Internally, the various types of Json object are represented by the JsonValue class
14 | * hierarchy.
15 | *
16 | * A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
17 | * so some JSON implementations distinguish between integers and floating-point numbers, while
18 | * some don't. In json11, we choose the latter. Because some JSON implementations (namely
19 | * Javascript itself) treat all numbers as the same type, distinguishing the two leads
20 | * to JSON that will be *silently* changed by a round-trip through those implementations.
21 | * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
22 | * provides integer helpers.
23 | *
24 | * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the
25 | * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64
26 | * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch
27 | * will be exact for +/- 275 years.)
28 | */
29 |
30 | /* Copyright (c) 2013 Dropbox, Inc.
31 | *
32 | * Permission is hereby granted, free of charge, to any person obtaining a copy
33 | * of this software and associated documentation files (the "Software"), to deal
34 | * in the Software without restriction, including without limitation the rights
35 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36 | * copies of the Software, and to permit persons to whom the Software is
37 | * furnished to do so, subject to the following conditions:
38 | *
39 | * The above copyright notice and this permission notice shall be included in
40 | * all copies or substantial portions of the Software.
41 | *
42 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48 | * THE SOFTWARE.
49 | */
50 |
51 | #pragma once
52 |
53 | #include
54 | #include
55 | #include