From 2b40acb9ae303c02a2f368ffb6599e71ba6b98c5 Mon Sep 17 00:00:00 2001 From: blacklime Date: Sun, 8 Apr 2018 15:42:05 +1000 Subject: [PATCH 01/21] geojson --- R/RcppExports.R | 4 + R/scratch.R | 29 +++++++ inst/include/geojson_wkt.h | 9 ++- src/RcppExports.cpp | 12 +++ src/geojson_geo.cpp | 154 ++++++++++++++++++++++++++++++++++++- src/geojson_sfc.cpp | 1 - src/geojson_to_wkt.cpp | 6 +- src/geojson_wkt.cpp | 16 ++-- 8 files changed, 211 insertions(+), 20 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index 1e190fb..d4473a4 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,6 +1,10 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 +rcpp_sfc_to_geojson <- function(sfc) { + .Call(`_geojsonsf_rcpp_sfc_to_geojson`, sfc) +} + rcpp_sf_to_geojson <- function(sf) { .Call(`_geojsonsf_rcpp_sf_to_geojson`, sf) } diff --git a/R/scratch.R b/R/scratch.R index cd2f9d5..1bc7241 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -9,3 +9,32 @@ ## stream the data.frame, row by row. ## + +# js <- '{"type" : "Point", "coordinates" : [0, 0]}' +# sf <- geojson_sf(js) +# sf +# geojsonsf:::rcpp_sf_to_geojson(sf) +# +# js <- '{"type" : "MultiPoint", "coordinates" : [ [0, 0], [1, 1] ]}' +# sf <- geojson_sf(js) +# sf +# geojsonsf:::rcpp_sf_to_geojson(sf) +# +# js <- '{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}' +# sf <- geojson_sf(js) +# sf +# geojsonsf:::rcpp_sf_to_geojson(sf) + +# library(Rcpp) +# +# cppFunction('Rcpp::NumericMatrix mymat(Rcpp::NumericVector vec) { +# vec.attr("dim") = Dimension(2, 2); +# Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix>(vec); +# return m; +# }') +# +# mymat(c(1:4)) + + + + diff --git a/inst/include/geojson_wkt.h b/inst/include/geojson_wkt.h index e24c38d..5bac085 100644 --- a/inst/include/geojson_wkt.h +++ b/inst/include/geojson_wkt.h @@ -3,18 +3,19 @@ #define GEOJSON_WKT_H #include "rapidjson/document.h" +using namespace rapidjson; -void coordSeparateWKT(std::ostringstream& os, int i, int n); +void coord_separator(std::ostringstream& os, int i, int n); -void lineSeparateWKT(std::ostringstream& os, int i, int n); +void line_separator_wkt(std::ostringstream& os, int i, int n); void polygonSeparateWKT(std::ostringstream& os, int i, int n); void addLonLatToWKTStream(std::ostringstream& os, float lon, float lat ); -void beginWKT(std::ostringstream& os, std::string& geom_type); +void begin_wkt(std::ostringstream& os, std::string& geom_type); -void endWKT(std::ostringstream& os, std::string& geom_type); +void end_wkt(std::ostringstream& os, std::string& geom_type); void point_to_wkt(std::ostringstream& os, const Value& coord_array); diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index ab88265..37763c6 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -6,6 +6,17 @@ using namespace Rcpp; +// rcpp_sfc_to_geojson +Rcpp::StringVector rcpp_sfc_to_geojson(Rcpp::List sfc); +RcppExport SEXP _geojsonsf_rcpp_sfc_to_geojson(SEXP sfcSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::List >::type sfc(sfcSEXP); + rcpp_result_gen = Rcpp::wrap(rcpp_sfc_to_geojson(sfc)); + return rcpp_result_gen; +END_RCPP +} // rcpp_sf_to_geojson Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf); RcppExport SEXP _geojsonsf_rcpp_sf_to_geojson(SEXP sfSEXP) { @@ -62,6 +73,7 @@ END_RCPP } static const R_CallMethodDef CallEntries[] = { + {"_geojsonsf_rcpp_sfc_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sfc_to_geojson, 1}, {"_geojsonsf_rcpp_sf_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sf_to_geojson, 1}, {"_geojsonsf_rcpp_geojson_to_sfc", (DL_FUNC) &_geojsonsf_rcpp_geojson_to_sfc, 1}, {"_geojsonsf_rcpp_geojson_to_sf", (DL_FUNC) &_geojsonsf_rcpp_geojson_to_sf, 1}, diff --git a/src/geojson_geo.cpp b/src/geojson_geo.cpp index bc5db53..2d01fd9 100644 --- a/src/geojson_geo.cpp +++ b/src/geojson_geo.cpp @@ -1,12 +1,153 @@ +#include "geojson_wkt.h" + #include using namespace Rcpp; +template +Rcpp::CharacterVector sfClass(Vector v) { + return v.attr("class"); +} + +Rcpp::CharacterVector getSfClass(SEXP sf) { + + switch( TYPEOF(sf) ) { + case REALSXP: + return sfClass(sf); + case VECSXP: + return sfClass(sf); + case INTSXP: + return sfClass(sf); + default: Rcpp::stop("unknown sf type"); + } + return ""; +} + // Stream an SF object to GeoJSON +void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { + if (geom_type == "POINT") { + os << "\"Point\" :"; + } else if (geom_type == "MULTIPOIT") { + os << "\"MultiPoint\" : ["; + } else if (geom_type == "LINESTRING") { + os << "\"LineString\" : ["; + } else if (geom_type == "MULTILINESTRING") { + os << "\"MultiLineString\" : [["; + } else if (geom_type == "POLYGON") { + os << "\"Polygon\" : [["; + } else if (geom_type == "MULTIPOLYGON") { + os << "\"MultiPolygon\" : [[["; + } else if (geom_type == "GEOMETRYCOLLECTION") { + os << "\"GeometryCollection\" : ["; + } +} + +void end_geojson_geometry(std::ostringstream& os, std::string& geom_type) { + if (geom_type == "POINT") { + os << ""; + } else if (geom_type == "MULTIPOINT") { + os << "]"; + } else if (geom_type == "LINESTRING") { + os << "]"; + } else if (geom_type == "MULTILINESTRING") { + os << "]] "; + } else if (geom_type == "POLYGON") { + os << "]]"; + } else if (geom_type == "MULTIPOLYGON") { + os << "]]]"; + } else if (geom_type == "GEOMETRYCOLLECTION") { + os << "]"; + } +} + +void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points) { -void geometry_column_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { + //Rcpp::Rcout << "Debug point size: " << points.size() << std::endl; + // a matrix is a vector with a dimension attribute... + + Rcpp::Rcout << "debug: points size: " << points.size() << std::endl; + + Rcpp::Rcout << points << std::endl; + + points.attr("dim") = Dimension(points.size() / 2, 2); + Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); + + Rcpp::Rcout << "debug: m rows: " << m.nrow() << std::endl; + Rcpp::Rcout << "debug: m cols: " << m.ncol() << std::endl; + + for (int i = 0; i < m.nrow(); i++) { + os << "[" << m(i, 0) << "," << m(i, 1) << "]"; + coord_separator(os, i, m.nrow()); + } +} + +void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { + + //Rcpp::Rcout << "debug: sfc size: " << sfc.size() << std::endl; + //os << "["; + //bracket_counter++; + + for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { + switch( TYPEOF(*it) ) { + case VECSXP: { + //Rcpp::Rcout << "debug: list" << std::endl; + Rcpp::List tmp = as(*it); + fetch_coordinates(os, tmp); + break; + } + case REALSXP: { + Rcpp::NumericVector tmp = as(*it); + add_lonlat_to_stream(os, tmp); + break; + } + case INTSXP: { + Rcpp::IntegerVector tmp = as(*it); + break; + } + default: { + Rcpp::stop("Coordinates could not be found"); + } + } + } +} + + +void add_geometry_to_stream(std::ostringstream& os, Rcpp::List& sfc) { + + // recurse into list to find 'sfg' + // each recursion adds a bracket '(' + // need to keep track of closing braces + fetch_coordinates(os, sfc); +} + +void sfc_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { + Rcpp::CharacterVector cls; + std::string geom_type; + + for (int i = 0; i < sfc.size(); i++) { + + //Rcpp::List sfci = as< Rcpp::List>(sfc[i]); + cls = getSfClass(sfc[i]); + + Rcpp::Rcout << cls << std::endl; + geom_type = cls[1]; + + begin_geojson_geometry(os, geom_type); + //add_geometry_to_stream(os, sfc[i]); + end_geojson_geometry(os, geom_type); + } +} + +void sfg_to_geojson() { } +// [[Rcpp::export]] +Rcpp::StringVector rcpp_sfc_to_geojson(Rcpp::List sfc) { + std::ostringstream os; + sfc_to_geojson(os, sfc); + return os.str(); +} + // [[Rcpp::export]] Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { @@ -15,14 +156,19 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { // // if 'atomise', return one object per row std::ostringstream os; + std::string geom_column = sf.attr("sf_column"); + Rcpp::List sfc = sf[geom_column]; - geometry_column_to_geojson(os, sf); + sfc_to_geojson(os, sfc); + //for (int i = 0; i < sf.size(); i++) { + // Rcpp::List sfc = sf[i]; + // Rcpp::CharacterVector cls_attr = getSfClass(sfc); + // add_geometry_to_stream(os, sfc); + //} Rcpp::StringVector res = os.str(); - return res; - } diff --git a/src/geojson_sfc.cpp b/src/geojson_sfc.cpp index 352e519..05c083f 100644 --- a/src/geojson_sfc.cpp +++ b/src/geojson_sfc.cpp @@ -92,7 +92,6 @@ void fetch_geometries(Rcpp::List& sf, Rcpp::List& res, int& sfg_counter) { std::string geom_attr; - for (Rcpp::List::iterator it = sf.begin(); it != sf.end(); it++) { switch( TYPEOF(*it) ) { diff --git a/src/geojson_to_wkt.cpp b/src/geojson_to_wkt.cpp index faf5adb..61f58d2 100644 --- a/src/geojson_to_wkt.cpp +++ b/src/geojson_to_wkt.cpp @@ -28,7 +28,7 @@ void parse_geometry_object_wkt(Rcpp::List& sfc, std::ostringstream os; Rcpp::StringVector wkt; - beginWKT(os, geom_type); + begin_wkt(os, geom_type); if (geom_type == "Point") { point_to_wkt(os, coord_array); @@ -52,7 +52,7 @@ void parse_geometry_object_wkt(Rcpp::List& sfc, Rcpp::stop("unknown sfg type"); } - endWKT(os, geom_type); + end_wkt(os, geom_type); wkt = os.str(); transform(geom_type.begin(), geom_type.end(), geom_type.begin(), ::toupper); @@ -89,7 +89,7 @@ Rcpp::List parse_geometry_collection_object_wkt(const Value& val, for (int i = 0; i < n; i++) { std::string g = geom_collection[i]; os << g; - coordSeparateWKT(os, i, n); + coord_separator(os, i, n); } os << ")"; diff --git a/src/geojson_wkt.cpp b/src/geojson_wkt.cpp index fce921d..3d101fe 100644 --- a/src/geojson_wkt.cpp +++ b/src/geojson_wkt.cpp @@ -7,7 +7,7 @@ using namespace rapidjson; using namespace Rcpp; -void beginWKT(std::ostringstream& os, std::string& geom_type) { +void begin_wkt(std::ostringstream& os, std::string& geom_type) { if (geom_type == "Point") { os << "POINT ("; @@ -26,7 +26,7 @@ void beginWKT(std::ostringstream& os, std::string& geom_type) { } } -void endWKT(std::ostringstream& os, std::string& geom_type) { +void end_wkt(std::ostringstream& os, std::string& geom_type) { if (geom_type == "Point") { os << ")"; @@ -45,13 +45,13 @@ void endWKT(std::ostringstream& os, std::string& geom_type) { } } -void coordSeparateWKT(std::ostringstream& os, int i, int n) { +void coord_separator(std::ostringstream& os, int i, int n) { if (i < (n - 1) ) { os << ", "; } } -void lineSeparateWKT(std::ostringstream& os, int i, int n) { +void line_separator_wkt(std::ostringstream& os, int i, int n) { if (i < (n - 1) ) { os << "),("; } @@ -83,7 +83,7 @@ void multi_point_to_wkt(std::ostringstream& os, const Value& coord_array) { for (int i = 0; i < n; i++) { validate_array(coord_array[i]); point_to_wkt(os, coord_array[i]); - coordSeparateWKT(os, i, n); + coord_separator(os, i, n); } } @@ -93,7 +93,7 @@ void line_string_to_wkt(std::ostringstream& os, const Value& coord_array) { for (int i = 0; i < n; i++) { validate_array(coord_array[i]); point_to_wkt(os, coord_array[i]); - coordSeparateWKT(os, i, n); + coord_separator(os, i, n); } } @@ -103,7 +103,7 @@ void multi_line_string_to_wkt(std::ostringstream& os, const Value& coord_array) for (int i = 0; i < n; i++) { validate_array(coord_array[i]); line_string_to_wkt(os, coord_array[i]); - lineSeparateWKT(os, i, n); + line_separator_wkt(os, i, n); } } @@ -114,7 +114,7 @@ void polygon_to_wkt(std::ostringstream& os, const Value& coord_array) { for (int i = 0; i < n; i++) { validate_array(coord_array[i]); line_string_to_wkt(os, coord_array[i]); - lineSeparateWKT(os, i, n); + line_separator_wkt(os, i, n); } } From 876a67f5d6d95733ae3e59994724d614ce67c59e Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sun, 8 Apr 2018 16:42:47 +1000 Subject: [PATCH 02/21] geojson --- R/scratch.R | 11 +++++++++-- src/geojson_geo.cpp | 35 +++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/R/scratch.R b/R/scratch.R index 1bc7241..7444610 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -20,20 +20,27 @@ # sf # geojsonsf:::rcpp_sf_to_geojson(sf) # +# js <- '{"type" : "MultiLineString", "coordinates" : [ [ [0, 0], [1, 1] ] ]}' +# sf <- geojson_sf(js) +# sf +# geojsonsf:::rcpp_sf_to_geojson(sf) +# # js <- '{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}' # sf <- geojson_sf(js) # sf # geojsonsf:::rcpp_sf_to_geojson(sf) + + # library(Rcpp) # # cppFunction('Rcpp::NumericMatrix mymat(Rcpp::NumericVector vec) { -# vec.attr("dim") = Dimension(2, 2); +# vec.attr("dim") = Dimension(1, 2); # Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix>(vec); # return m; # }') # -# mymat(c(1:4)) +# mymat(c(1:2)) diff --git a/src/geojson_geo.cpp b/src/geojson_geo.cpp index 2d01fd9..4ebc113 100644 --- a/src/geojson_geo.cpp +++ b/src/geojson_geo.cpp @@ -24,20 +24,21 @@ Rcpp::CharacterVector getSfClass(SEXP sf) { // Stream an SF object to GeoJSON void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { + os << "\"type\" : "; if (geom_type == "POINT") { - os << "\"Point\" :"; - } else if (geom_type == "MULTIPOIT") { - os << "\"MultiPoint\" : ["; + os << "\"Point\" , \"coordinates\" : "; + } else if (geom_type == "MULTIPOINT") { + os << "\"MultiPoint\" , \"coordinates\" : ["; } else if (geom_type == "LINESTRING") { - os << "\"LineString\" : ["; + os << "\"LineString\" , \"coordinates\" : ["; } else if (geom_type == "MULTILINESTRING") { - os << "\"MultiLineString\" : [["; + os << "\"MultiLineString\" , \"coordinates\" : [["; } else if (geom_type == "POLYGON") { - os << "\"Polygon\" : [["; + os << "\"Polygon\" , \"coordinates\" : [["; } else if (geom_type == "MULTIPOLYGON") { - os << "\"MultiPolygon\" : [[["; + os << "\"MultiPolygon\" , \"coordinates\" : [[["; } else if (geom_type == "GEOMETRYCOLLECTION") { - os << "\"GeometryCollection\" : ["; + os << "\"GeometryCollection\" , \"coordinates\" : ["; } } @@ -68,7 +69,7 @@ void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points) { Rcpp::Rcout << points << std::endl; - points.attr("dim") = Dimension(points.size() / 2, 2); + //points.attr("dim") = Dimension(1, 2); Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); Rcpp::Rcout << "debug: m rows: " << m.nrow() << std::endl; @@ -91,7 +92,7 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { case VECSXP: { //Rcpp::Rcout << "debug: list" << std::endl; Rcpp::List tmp = as(*it); - fetch_coordinates(os, tmp); + fetch_coordinates(os, tmp); break; } case REALSXP: { @@ -100,7 +101,8 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { break; } case INTSXP: { - Rcpp::IntegerVector tmp = as(*it); + //Rcpp::IntegerVector tmp = as(*it); + //add_lonlat_to_stream(os, tmp); break; } default: { @@ -122,6 +124,9 @@ void add_geometry_to_stream(std::ostringstream& os, Rcpp::List& sfc) { void sfc_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { Rcpp::CharacterVector cls; std::string geom_type; + Rcpp::List sfci(1); + + Rcpp::Rcout << "sfc.size; " << sfc.size() << std::endl; for (int i = 0; i < sfc.size(); i++) { @@ -131,8 +136,14 @@ void sfc_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { Rcpp::Rcout << cls << std::endl; geom_type = cls[1]; + Rcpp::NumericVector nv = sfc[i]; + Rcpp::Rcout << "debug point: " << nv << std::endl; + + sfci = sfc[i]; + //Rcpp::Rcout << "debug sfci vector: " << sfci << std::endl; + begin_geojson_geometry(os, geom_type); - //add_geometry_to_stream(os, sfc[i]); + add_geometry_to_stream(os, sfci); end_geojson_geometry(os, geom_type); } } From c2c25cbfcc5d548afbc2bdcc70cec7cdb47470db Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sun, 8 Apr 2018 21:51:47 +1000 Subject: [PATCH 03/21] geojson --- src/geojson_geo.cpp | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/geojson_geo.cpp b/src/geojson_geo.cpp index 4ebc113..2f31ecb 100644 --- a/src/geojson_geo.cpp +++ b/src/geojson_geo.cpp @@ -24,7 +24,7 @@ Rcpp::CharacterVector getSfClass(SEXP sf) { // Stream an SF object to GeoJSON void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { - os << "\"type\" : "; + os << "{\"type\" : "; if (geom_type == "POINT") { os << "\"Point\" , \"coordinates\" : "; } else if (geom_type == "MULTIPOINT") { @@ -44,19 +44,19 @@ void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { void end_geojson_geometry(std::ostringstream& os, std::string& geom_type) { if (geom_type == "POINT") { - os << ""; + os << "}"; } else if (geom_type == "MULTIPOINT") { - os << "]"; + os << "]}"; } else if (geom_type == "LINESTRING") { - os << "]"; + os << "]}"; } else if (geom_type == "MULTILINESTRING") { - os << "]] "; + os << "]]}"; } else if (geom_type == "POLYGON") { - os << "]]"; + os << "]]}"; } else if (geom_type == "MULTIPOLYGON") { - os << "]]]"; + os << "]]]}"; } else if (geom_type == "GEOMETRYCOLLECTION") { - os << "]"; + os << "]}"; } } @@ -65,15 +65,15 @@ void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points) { //Rcpp::Rcout << "Debug point size: " << points.size() << std::endl; // a matrix is a vector with a dimension attribute... - Rcpp::Rcout << "debug: points size: " << points.size() << std::endl; + //Rcpp::Rcout << "debug: points size: " << points.size() << std::endl; - Rcpp::Rcout << points << std::endl; + //Rcpp::Rcout << points << std::endl; - //points.attr("dim") = Dimension(1, 2); + points.attr("dim") = Dimension(points.size() / 2, 2); Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); - Rcpp::Rcout << "debug: m rows: " << m.nrow() << std::endl; - Rcpp::Rcout << "debug: m cols: " << m.ncol() << std::endl; + //Rcpp::Rcout << "debug: m rows: " << m.nrow() << std::endl; + //Rcpp::Rcout << "debug: m cols: " << m.ncol() << std::endl; for (int i = 0; i < m.nrow(); i++) { os << "[" << m(i, 0) << "," << m(i, 1) << "]"; @@ -86,17 +86,20 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { //Rcpp::Rcout << "debug: sfc size: " << sfc.size() << std::endl; //os << "["; //bracket_counter++; + //Rcpp::Rcout << "type sfc: " << TYPEOF(sfc) << std::endl; + for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { switch( TYPEOF(*it) ) { case VECSXP: { - //Rcpp::Rcout << "debug: list" << std::endl; Rcpp::List tmp = as(*it); + //Rcpp::Rcout << "debug: list " << tmp.size() << std::endl; fetch_coordinates(os, tmp); break; } case REALSXP: { Rcpp::NumericVector tmp = as(*it); + //Rcpp::Rcout << "debug: numeric vector " << tmp << std::endl; add_lonlat_to_stream(os, tmp); break; } @@ -126,20 +129,20 @@ void sfc_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { std::string geom_type; Rcpp::List sfci(1); - Rcpp::Rcout << "sfc.size; " << sfc.size() << std::endl; + //Rcpp::Rcout << "sfc.size; " << sfc.size() << std::endl; for (int i = 0; i < sfc.size(); i++) { //Rcpp::List sfci = as< Rcpp::List>(sfc[i]); cls = getSfClass(sfc[i]); - Rcpp::Rcout << cls << std::endl; + //Rcpp::Rcout << cls << std::endl; geom_type = cls[1]; - Rcpp::NumericVector nv = sfc[i]; - Rcpp::Rcout << "debug point: " << nv << std::endl; + //Rcpp::NumericVector nv = sfc[i]; + //Rcpp::Rcout << "debug point: " << nv << std::endl; - sfci = sfc[i]; + sfci[0] = sfc[i]; //Rcpp::Rcout << "debug sfci vector: " << sfci << std::endl; begin_geojson_geometry(os, geom_type); From 9a171eecb28bb653f57b5c17c165d32701238553 Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sun, 8 Apr 2018 22:30:22 +1000 Subject: [PATCH 04/21] geojson --- R/scratch.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/R/scratch.R b/R/scratch.R index 7444610..b47b090 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -30,6 +30,11 @@ # sf # geojsonsf:::rcpp_sf_to_geojson(sf) +# js <- '[{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}, +# {"type" : "MultiLineString", "coordinates" : [ [ [0, 0], [1, 1] ] ]}]' +# sf <- geojson_sf(js) +# sf +# geojsonsf:::rcpp_sf_to_geojson(sf) # library(Rcpp) From 823f01320e96a8ef976e5c9a44a6cf38519f3b26 Mon Sep 17 00:00:00 2001 From: David Cooley Date: Mon, 9 Apr 2018 10:29:02 +1000 Subject: [PATCH 05/21] r functions --- NAMESPACE | 4 ++++ R/geojson_sf.R | 22 ++++++++++++++++++++++ R/scratch.R | 12 ++++++------ man/geojson_sf.Rd | 2 +- man/geojson_sfc.Rd | 2 +- man/geojson_wkt.Rd | 2 +- man/sf_geojson.Rd | 11 +++++++++++ src/geojson_geo.cpp | 36 +++++++++++++++++++++--------------- 8 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 man/sf_geojson.Rd diff --git a/NAMESPACE b/NAMESPACE index 152f0fb..dd1e39e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,7 +1,11 @@ # Generated by roxygen2: do not edit by hand +S3method(sf_geojson,sf) +S3method(sf_geojson,sfc) +S3method(sf_geojson,sfg) export(geojson_sf) export(geojson_sfc) export(geojson_wkt) +export(sf_geojson) importFrom(Rcpp,sourceCpp) useDynLib(geojsonsf, .registration = TRUE) diff --git a/R/geojson_sf.R b/R/geojson_sf.R index 6e1b0dc..5299c68 100644 --- a/R/geojson_sf.R +++ b/R/geojson_sf.R @@ -32,3 +32,25 @@ geojson_sfc <- function(geojson) { geojson_sf <- function(geojson){ rcpp_geojson_to_sf(geojson) } + +#' sf to GeoJSON +#' +#' @export +sf_geojson <- function(sf) UseMethod("sf_geojson") + +#' @export +sf_geojson.sf <- function(sf) { + rcpp_sf_to_geojson(sf) +} + +#' @export +sf_geojson.sfc <- function(sf) { + rcpp_sfc_to_geojson(sf) +} + +#' @export +sf_geojson.sfg <- function(sf) { + rcpp_sfg_to_geojson(sf) +} + +sf_geojson.default <- function(sf) stop("Expected an sf object") diff --git a/R/scratch.R b/R/scratch.R index b47b090..c0fa587 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -13,28 +13,28 @@ # js <- '{"type" : "Point", "coordinates" : [0, 0]}' # sf <- geojson_sf(js) # sf -# geojsonsf:::rcpp_sf_to_geojson(sf) +# sf_geojson(sf) # # js <- '{"type" : "MultiPoint", "coordinates" : [ [0, 0], [1, 1] ]}' # sf <- geojson_sf(js) # sf -# geojsonsf:::rcpp_sf_to_geojson(sf) +# sf_geojson(sf) # # js <- '{"type" : "MultiLineString", "coordinates" : [ [ [0, 0], [1, 1] ] ]}' # sf <- geojson_sf(js) # sf -# geojsonsf:::rcpp_sf_to_geojson(sf) +# sf_geojson(sf) # # js <- '{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}' # sf <- geojson_sf(js) # sf -# geojsonsf:::rcpp_sf_to_geojson(sf) - +# sf_geojson(sf) +# # js <- '[{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}, # {"type" : "MultiLineString", "coordinates" : [ [ [0, 0], [1, 1] ] ]}]' # sf <- geojson_sf(js) # sf -# geojsonsf:::rcpp_sf_to_geojson(sf) +# sf_geojson(sf) # library(Rcpp) diff --git a/man/geojson_sf.Rd b/man/geojson_sf.Rd index 1b1a3ce..c726939 100644 --- a/man/geojson_sf.Rd +++ b/man/geojson_sf.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gsf_sf.R +% Please edit documentation in R/geojson_sf.R \name{geojson_sf} \alias{geojson_sf} \title{Geojson to sf} diff --git a/man/geojson_sfc.Rd b/man/geojson_sfc.Rd index f55e0c0..edce55f 100644 --- a/man/geojson_sfc.Rd +++ b/man/geojson_sfc.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gsf_sf.R +% Please edit documentation in R/geojson_sf.R \name{geojson_sfc} \alias{geojson_sfc} \title{Geojson to sfc} diff --git a/man/geojson_wkt.Rd b/man/geojson_wkt.Rd index 5d39133..85a7aab 100644 --- a/man/geojson_wkt.Rd +++ b/man/geojson_wkt.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gsf_wkt.R +% Please edit documentation in R/geojson_wkt.R \name{geojson_wkt} \alias{geojson_wkt} \title{Geojson to WKT} diff --git a/man/sf_geojson.Rd b/man/sf_geojson.Rd new file mode 100644 index 0000000..984098a --- /dev/null +++ b/man/sf_geojson.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/geojson_sf.R +\name{sf_geojson} +\alias{sf_geojson} +\title{sf to GeoJSON} +\usage{ +sf_geojson(sf) +} +\description{ +sf to GeoJSON +} diff --git a/src/geojson_geo.cpp b/src/geojson_geo.cpp index 2f31ecb..84db660 100644 --- a/src/geojson_geo.cpp +++ b/src/geojson_geo.cpp @@ -124,35 +124,41 @@ void add_geometry_to_stream(std::ostringstream& os, Rcpp::List& sfc) { fetch_coordinates(os, sfc); } -void sfc_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { +void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { Rcpp::CharacterVector cls; std::string geom_type; Rcpp::List sfci(1); //Rcpp::Rcout << "sfc.size; " << sfc.size() << std::endl; - for (int i = 0; i < sfc.size(); i++) { + for (int i = 0; i < sfc.size(); i++) { - //Rcpp::List sfci = as< Rcpp::List>(sfc[i]); - cls = getSfClass(sfc[i]); + //Rcpp::List sfci = as< Rcpp::List>(sfc[i]); + cls = getSfClass(sfc[i]); - //Rcpp::Rcout << cls << std::endl; - geom_type = cls[1]; + //Rcpp::Rcout << cls << std::endl; + geom_type = cls[1]; - //Rcpp::NumericVector nv = sfc[i]; - //Rcpp::Rcout << "debug point: " << nv << std::endl; + //Rcpp::NumericVector nv = sfc[i]; + //Rcpp::Rcout << "debug point: " << nv << std::endl; - sfci[0] = sfc[i]; - //Rcpp::Rcout << "debug sfci vector: " << sfci << std::endl; + sfci[0] = sfc[i]; + //Rcpp::Rcout << "debug sfci vector: " << sfci << std::endl; - begin_geojson_geometry(os, geom_type); - add_geometry_to_stream(os, sfci); - end_geojson_geometry(os, geom_type); - } + begin_geojson_geometry(os, geom_type); + add_geometry_to_stream(os, sfci); + end_geojson_geometry(os, geom_type); + } } -void sfg_to_geojson() { +void sfc_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { + sfg_to_geojson(os, sfc); +} +Rcpp::StringVector rcpp_sfg_to_geojson(Rcpp::List sfg) { + std::ostringstream os; + sfg_to_geojson(os, sfg); + return os.str(); } // [[Rcpp::export]] From fefaf8922b6602edeffb6d1df2ae58470b797052 Mon Sep 17 00:00:00 2001 From: David Cooley Date: Mon, 9 Apr 2018 15:48:27 +1000 Subject: [PATCH 06/21] geojson --- R/geojson_sf.R | 6 ++++++ R/scratch.R | 11 +++++++++++ src/geojson_geo.cpp | 28 +++++++++++++++++++--------- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/R/geojson_sf.R b/R/geojson_sf.R index 5299c68..4cb99a2 100644 --- a/R/geojson_sf.R +++ b/R/geojson_sf.R @@ -33,6 +33,12 @@ geojson_sf <- function(geojson){ rcpp_geojson_to_sf(geojson) } + +## TODO: +## - atomise - logical? +## -- Return a JSON array of objects +## -- Return an R Vector of objects? + #' sf to GeoJSON #' #' @export diff --git a/R/scratch.R b/R/scratch.R index c0fa587..8d8835a 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -36,6 +36,17 @@ # sf # sf_geojson(sf) +# js <- '{ +# "type": "GeometryCollection", "geometries": [ +# {"type": "Point", "coordinates": [100.0, 0.0]}, +# {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]}, +# {"type" : "MultiPoint", "coordinates" : [[0,0], [1,1], [2,2]]} +# ]}' +# sf <- geojson_sf(js) +# sf +# sf_geojson(sf) + + # library(Rcpp) # diff --git a/src/geojson_geo.cpp b/src/geojson_geo.cpp index 84db660..dacb489 100644 --- a/src/geojson_geo.cpp +++ b/src/geojson_geo.cpp @@ -38,7 +38,7 @@ void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { } else if (geom_type == "MULTIPOLYGON") { os << "\"MultiPolygon\" , \"coordinates\" : [[["; } else if (geom_type == "GEOMETRYCOLLECTION") { - os << "\"GeometryCollection\" , \"coordinates\" : ["; + os << "\"GeometryCollection\" , \"geometries\" : [{"; } } @@ -56,7 +56,7 @@ void end_geojson_geometry(std::ostringstream& os, std::string& geom_type) { } else if (geom_type == "MULTIPOLYGON") { os << "]]]}"; } else if (geom_type == "GEOMETRYCOLLECTION") { - os << "]}"; + os << "}]}"; } } @@ -66,7 +66,6 @@ void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points) { // a matrix is a vector with a dimension attribute... //Rcpp::Rcout << "debug: points size: " << points.size() << std::endl; - //Rcpp::Rcout << points << std::endl; points.attr("dim") = Dimension(points.size() / 2, 2); @@ -138,16 +137,27 @@ void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { //Rcpp::Rcout << cls << std::endl; geom_type = cls[1]; + /* + if (geom_type == "GEOMETRYCOLLECTION") { + begin_geojson_geometry(os, geom_type); + Rcpp::List gc = sfc[i]; + for (int j = 0; j < gc.size(); j++) { + Rcpp::List gcj = gc[j]; + begin_geojson_geometry(os, geom_type); + add_geometry_to_stream(os, gcj); + end_geojson_geometry(os, geom_type); + } + } else { + */ + sfci[0] = sfc[i]; + begin_geojson_geometry(os, geom_type); + add_geometry_to_stream(os, sfci); + end_geojson_geometry(os, geom_type); + //Rcpp::NumericVector nv = sfc[i]; //Rcpp::Rcout << "debug point: " << nv << std::endl; - - sfci[0] = sfc[i]; //Rcpp::Rcout << "debug sfci vector: " << sfci << std::endl; - - begin_geojson_geometry(os, geom_type); - add_geometry_to_stream(os, sfci); - end_geojson_geometry(os, geom_type); } } From e82bad90bdf2d57b752274aa505a3bd74ab2c96c Mon Sep 17 00:00:00 2001 From: symbolixau Date: Mon, 9 Apr 2018 21:26:07 +1000 Subject: [PATCH 07/21] renamed file --- src/{geojson_geo.cpp => sf_geojson.cpp} | 1 - 1 file changed, 1 deletion(-) rename src/{geojson_geo.cpp => sf_geojson.cpp} (99%) diff --git a/src/geojson_geo.cpp b/src/sf_geojson.cpp similarity index 99% rename from src/geojson_geo.cpp rename to src/sf_geojson.cpp index dacb489..1582ad0 100644 --- a/src/geojson_geo.cpp +++ b/src/sf_geojson.cpp @@ -87,7 +87,6 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { //bracket_counter++; //Rcpp::Rcout << "type sfc: " << TYPEOF(sfc) << std::endl; - for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { switch( TYPEOF(*it) ) { case VECSXP: { From 19387d50a2086b711d897ed6b2686437714aff9d Mon Sep 17 00:00:00 2001 From: David Cooley Date: Tue, 10 Apr 2018 15:49:00 +1000 Subject: [PATCH 08/21] still not right --- R/RcppExports.R | 16 ++++++------- src/RcppExports.cpp | 48 ++++++++++++++++++------------------- src/geojson_wkt.cpp | 4 ++++ src/sf_geojson.cpp | 58 ++++++++++++++++++++++----------------------- 4 files changed, 64 insertions(+), 62 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index d4473a4..0d8becd 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,14 +1,6 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 -rcpp_sfc_to_geojson <- function(sfc) { - .Call(`_geojsonsf_rcpp_sfc_to_geojson`, sfc) -} - -rcpp_sf_to_geojson <- function(sf) { - .Call(`_geojsonsf_rcpp_sf_to_geojson`, sf) -} - rcpp_geojson_to_sfc <- function(geojson) { .Call(`_geojsonsf_rcpp_geojson_to_sfc`, geojson) } @@ -25,3 +17,11 @@ rcpp_stream_in <- function(url) { invisible(.Call(`_geojsonsf_rcpp_stream_in`, url)) } +rcpp_sfc_to_geojson <- function(sfc) { + .Call(`_geojsonsf_rcpp_sfc_to_geojson`, sfc) +} + +rcpp_sf_to_geojson <- function(sf) { + .Call(`_geojsonsf_rcpp_sf_to_geojson`, sf) +} + diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 37763c6..72a2b90 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -6,28 +6,6 @@ using namespace Rcpp; -// rcpp_sfc_to_geojson -Rcpp::StringVector rcpp_sfc_to_geojson(Rcpp::List sfc); -RcppExport SEXP _geojsonsf_rcpp_sfc_to_geojson(SEXP sfcSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< Rcpp::List >::type sfc(sfcSEXP); - rcpp_result_gen = Rcpp::wrap(rcpp_sfc_to_geojson(sfc)); - return rcpp_result_gen; -END_RCPP -} -// rcpp_sf_to_geojson -Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf); -RcppExport SEXP _geojsonsf_rcpp_sf_to_geojson(SEXP sfSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< Rcpp::List >::type sf(sfSEXP); - rcpp_result_gen = Rcpp::wrap(rcpp_sf_to_geojson(sf)); - return rcpp_result_gen; -END_RCPP -} // rcpp_geojson_to_sfc Rcpp::List rcpp_geojson_to_sfc(Rcpp::StringVector geojson); RcppExport SEXP _geojsonsf_rcpp_geojson_to_sfc(SEXP geojsonSEXP) { @@ -71,14 +49,36 @@ BEGIN_RCPP return R_NilValue; END_RCPP } +// rcpp_sfc_to_geojson +Rcpp::StringVector rcpp_sfc_to_geojson(Rcpp::List sfc); +RcppExport SEXP _geojsonsf_rcpp_sfc_to_geojson(SEXP sfcSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::List >::type sfc(sfcSEXP); + rcpp_result_gen = Rcpp::wrap(rcpp_sfc_to_geojson(sfc)); + return rcpp_result_gen; +END_RCPP +} +// rcpp_sf_to_geojson +Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf); +RcppExport SEXP _geojsonsf_rcpp_sf_to_geojson(SEXP sfSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::List >::type sf(sfSEXP); + rcpp_result_gen = Rcpp::wrap(rcpp_sf_to_geojson(sf)); + return rcpp_result_gen; +END_RCPP +} static const R_CallMethodDef CallEntries[] = { - {"_geojsonsf_rcpp_sfc_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sfc_to_geojson, 1}, - {"_geojsonsf_rcpp_sf_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sf_to_geojson, 1}, {"_geojsonsf_rcpp_geojson_to_sfc", (DL_FUNC) &_geojsonsf_rcpp_geojson_to_sfc, 1}, {"_geojsonsf_rcpp_geojson_to_sf", (DL_FUNC) &_geojsonsf_rcpp_geojson_to_sf, 1}, {"_geojsonsf_rcpp_geojson_to_wkt", (DL_FUNC) &_geojsonsf_rcpp_geojson_to_wkt, 1}, {"_geojsonsf_rcpp_stream_in", (DL_FUNC) &_geojsonsf_rcpp_stream_in, 1}, + {"_geojsonsf_rcpp_sfc_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sfc_to_geojson, 1}, + {"_geojsonsf_rcpp_sf_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sf_to_geojson, 1}, {NULL, NULL, 0} }; diff --git a/src/geojson_wkt.cpp b/src/geojson_wkt.cpp index 3d101fe..5b19563 100644 --- a/src/geojson_wkt.cpp +++ b/src/geojson_wkt.cpp @@ -45,6 +45,10 @@ void end_wkt(std::ostringstream& os, std::string& geom_type) { } } +void object_separator(std::ostringstream& os) { + os << ","; +} + void coord_separator(std::ostringstream& os, int i, int n) { if (i < (n - 1) ) { os << ", "; diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index 1582ad0..1b54502 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -38,7 +38,7 @@ void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { } else if (geom_type == "MULTIPOLYGON") { os << "\"MultiPolygon\" , \"coordinates\" : [[["; } else if (geom_type == "GEOMETRYCOLLECTION") { - os << "\"GeometryCollection\" , \"geometries\" : [{"; + os << "\"GeometryCollection\" , \"geometries\" : ["; } } @@ -56,7 +56,7 @@ void end_geojson_geometry(std::ostringstream& os, std::string& geom_type) { } else if (geom_type == "MULTIPOLYGON") { os << "]]]}"; } else if (geom_type == "GEOMETRYCOLLECTION") { - os << "}]}"; + os << "]}"; } } @@ -86,19 +86,31 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { //os << "["; //bracket_counter++; //Rcpp::Rcout << "type sfc: " << TYPEOF(sfc) << std::endl; + Rcpp::CharacterVector cls; + std::string geom_type; for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { switch( TYPEOF(*it) ) { case VECSXP: { Rcpp::List tmp = as(*it); - //Rcpp::Rcout << "debug: list " << tmp.size() << std::endl; - fetch_coordinates(os, tmp); + if(!Rf_isNull(tmp.attr("class"))) { + cls = getSfClass(tmp); + geom_type = cls[1]; + begin_geojson_geometry(os, geom_type); + fetch_coordinates(os, tmp); + end_geojson_geometry(os, geom_type); + } break; } case REALSXP: { Rcpp::NumericVector tmp = as(*it); - //Rcpp::Rcout << "debug: numeric vector " << tmp << std::endl; - add_lonlat_to_stream(os, tmp); + if(!Rf_isNull(tmp.attr("class"))) { + cls = getSfClass(tmp); + geom_type = cls[1]; + begin_geojson_geometry(os, geom_type); + add_lonlat_to_stream(os, tmp); + end_geojson_geometry(os, geom_type); + } break; } case INTSXP: { @@ -131,32 +143,18 @@ void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { for (int i = 0; i < sfc.size(); i++) { - //Rcpp::List sfci = as< Rcpp::List>(sfc[i]); - cls = getSfClass(sfc[i]); - - //Rcpp::Rcout << cls << std::endl; - geom_type = cls[1]; - /* - if (geom_type == "GEOMETRYCOLLECTION") { - begin_geojson_geometry(os, geom_type); - Rcpp::List gc = sfc[i]; - for (int j = 0; j < gc.size(); j++) { - Rcpp::List gcj = gc[j]; - begin_geojson_geometry(os, geom_type); - add_geometry_to_stream(os, gcj); - end_geojson_geometry(os, geom_type); - } - } else { - */ + // recurse into each geometry + // if it's a list, AND has a class/attribute, 'begin GEOJSON string', recurse again to get the vec/matrix/obj + // if if's not a list, get the obj & 'begin GEOJSON string' + // - get the obj & convert to GEOJSON + // + // move the 'getSfClass' into the recursing bit, 'begin' the stream if the sfg class exists + // recurse again to get the objects (if it's a list, it will recurse once more) + // - just need to make sure to close of geometrycollection objects...? + // keep track of inner-objects? like a counter + sfci[0] = sfc[i]; - begin_geojson_geometry(os, geom_type); add_geometry_to_stream(os, sfci); - end_geojson_geometry(os, geom_type); - - - //Rcpp::NumericVector nv = sfc[i]; - //Rcpp::Rcout << "debug point: " << nv << std::endl; - //Rcpp::Rcout << "debug sfci vector: " << sfci << std::endl; } } From bd1e09b3f4ceb955f211b42cfc65722a39fe12f1 Mon Sep 17 00:00:00 2001 From: symbolixau Date: Tue, 10 Apr 2018 21:16:40 +1000 Subject: [PATCH 09/21] separating objects --- inst/include/geojson_wkt.h | 2 + inst/include/sf_geojson.h | 20 ++++++++++ src/sf_geojson.cpp | 77 +++++++++++++++++++++++++++----------- 3 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 inst/include/sf_geojson.h diff --git a/inst/include/geojson_wkt.h b/inst/include/geojson_wkt.h index 5bac085..71548c6 100644 --- a/inst/include/geojson_wkt.h +++ b/inst/include/geojson_wkt.h @@ -9,6 +9,8 @@ void coord_separator(std::ostringstream& os, int i, int n); void line_separator_wkt(std::ostringstream& os, int i, int n); +void object_separator(std::ostringstream& os); + void polygonSeparateWKT(std::ostringstream& os, int i, int n); void addLonLatToWKTStream(std::ostringstream& os, float lon, float lat ); diff --git a/inst/include/sf_geojson.h b/inst/include/sf_geojson.h new file mode 100644 index 0000000..bfe5ba5 --- /dev/null +++ b/inst/include/sf_geojson.h @@ -0,0 +1,20 @@ +#ifndef SFGEOJSON_H +#define SFGEOJSON_H + +#include +using namespace Rcpp; + + +//void add_geometrycollection_to_stream(std::ostringstream& os, Rcpp::List& gc); + +void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type); + +void begin_geojson_geometry(std::ostringstream& os, Rcpp::List& sfc, std::string& geom_type); + +void end_geojson_geometry(std::ostringstream& os, std::string& geom_type); + +void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points); + +void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_counter); + +#endif diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index 1b54502..4428ad1 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -1,4 +1,5 @@ #include "geojson_wkt.h" +#include "sf_geojson.h" #include using namespace Rcpp; @@ -21,9 +22,26 @@ Rcpp::CharacterVector getSfClass(SEXP sf) { } return ""; } +/* +void add_geometrycollection_to_stream(std::ostringstream& os, Rcpp::List& gc) { + os << "\"GeometryCollection\" , \"geometries\" : ["; + // recurse into gc object + Rcpp::List gci(1); + for (int i = 0; i < gc.size(); i++) { + gci[0] = gc[i]; + fetch_coordinates(os, gci); + object_separator(os); + } + os << "]}"; +} +*/ +void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { + Rcpp::List sfc; + begin_geojson_geometry(os, sfc, geom_type); +} // Stream an SF object to GeoJSON -void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { +void begin_geojson_geometry(std::ostringstream& os, Rcpp::List& sfc, std::string& geom_type) { os << "{\"type\" : "; if (geom_type == "POINT") { os << "\"Point\" , \"coordinates\" : "; @@ -38,6 +56,7 @@ void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { } else if (geom_type == "MULTIPOLYGON") { os << "\"MultiPolygon\" , \"coordinates\" : [[["; } else if (geom_type == "GEOMETRYCOLLECTION") { + //add_geometrycollection_to_stream(os, sfc); os << "\"GeometryCollection\" , \"geometries\" : ["; } } @@ -62,25 +81,18 @@ void end_geojson_geometry(std::ostringstream& os, std::string& geom_type) { void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points) { - //Rcpp::Rcout << "Debug point size: " << points.size() << std::endl; - // a matrix is a vector with a dimension attribute... - - //Rcpp::Rcout << "debug: points size: " << points.size() << std::endl; - //Rcpp::Rcout << points << std::endl; - points.attr("dim") = Dimension(points.size() / 2, 2); Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); - //Rcpp::Rcout << "debug: m rows: " << m.nrow() << std::endl; - //Rcpp::Rcout << "debug: m cols: " << m.ncol() << std::endl; - for (int i = 0; i < m.nrow(); i++) { os << "[" << m(i, 0) << "," << m(i, 1) << "]"; coord_separator(os, i, m.nrow()); } } -void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { +void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_counter) { + + Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; //Rcpp::Rcout << "debug: sfc size: " << sfc.size() << std::endl; //os << "["; @@ -90,27 +102,53 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { std::string geom_type; for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { + + if (object_counter > 0) { + object_separator(os); + } + switch( TYPEOF(*it) ) { case VECSXP: { Rcpp::List tmp = as(*it); if(!Rf_isNull(tmp.attr("class"))) { + + // if there's a 'class' attribute, it's an sfg object + // but it's also a list + // so need to go through the list elemetns and fetch the geometries + // + // but, if the list is a 'GEOMETRYCOLLECTION', we need a ',' separator + // after each geometry + + //Rcpp::Rcout << "debug list " << std::endl; cls = getSfClass(tmp); - geom_type = cls[1]; - begin_geojson_geometry(os, geom_type); - fetch_coordinates(os, tmp); + geom_type = cls[1]; // TODO: error handle (there should aways be 3 elements as we're workgin wtih sfg objects) + begin_geojson_geometry(os, tmp, geom_type); + fetch_coordinates(os, tmp, object_counter); end_geojson_geometry(os, geom_type); + } else { + // if no class attribute, go further into the list to try and find one + fetch_coordinates(os, tmp, object_counter); } + Rcpp::Rcout << "debug: updating object_counter" << std::endl; + object_counter++; + Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; break; } case REALSXP: { Rcpp::NumericVector tmp = as(*it); if(!Rf_isNull(tmp.attr("class"))) { + //Rcpp::Rcout << "debug vector " << std::endl; cls = getSfClass(tmp); geom_type = cls[1]; begin_geojson_geometry(os, geom_type); add_lonlat_to_stream(os, tmp); end_geojson_geometry(os, geom_type); + } else { + add_lonlat_to_stream(os, tmp); } + Rcpp::Rcout << "debug: updating object_counter" << std::endl; + object_counter++; + Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; break; } case INTSXP: { @@ -127,11 +165,9 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc) { void add_geometry_to_stream(std::ostringstream& os, Rcpp::List& sfc) { - - // recurse into list to find 'sfg' - // each recursion adds a bracket '(' - // need to keep track of closing braces - fetch_coordinates(os, sfc); + Rcpp::Rcout << "debug: resetting object_counter" << std::endl; + int object_counter = 0; + fetch_coordinates(os, sfc, object_counter); } void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { @@ -139,8 +175,6 @@ void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { std::string geom_type; Rcpp::List sfci(1); - //Rcpp::Rcout << "sfc.size; " << sfc.size() << std::endl; - for (int i = 0; i < sfc.size(); i++) { // recurse into each geometry @@ -155,6 +189,7 @@ void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { sfci[0] = sfc[i]; add_geometry_to_stream(os, sfci); + coord_separator(os, i, sfc.size()); } } From 1e18de2fb430b638c793d149d8f967fa6fb99a41 Mon Sep 17 00:00:00 2001 From: David Cooley Date: Wed, 11 Apr 2018 15:54:31 +1000 Subject: [PATCH 10/21] some thoughts on geojson --- R/scratch.R | 25 ++++++++++++------------- README.md | 5 ++--- src/sf_geojson.cpp | 37 +++++++++++++++++-------------------- 3 files changed, 31 insertions(+), 36 deletions(-) diff --git a/R/scratch.R b/R/scratch.R index 8d8835a..9c73113 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -47,17 +47,16 @@ # sf_geojson(sf) - -# library(Rcpp) -# -# cppFunction('Rcpp::NumericMatrix mymat(Rcpp::NumericVector vec) { -# vec.attr("dim") = Dimension(1, 2); -# Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix>(vec); -# return m; -# }') -# -# mymat(c(1:2)) - - - +# js <- '[{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}, +# {"type" : "MultiLineString", "coordinates" : [ [ [0, 0], [1, 1] ] ]}, +# { +# "type": "GeometryCollection", "geometries": [ +# {"type": "Point", "coordinates": [100.0, 0.0]}, +# {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]}, +# {"type" : "MultiPoint", "coordinates" : [[0,0], [1,1], [2,2]]} +# ]} +# ]' +# sf <- geojson_sf(js) +# sf +# sf_geojson(sf) diff --git a/README.md b/README.md index 655ea14..5aa054c 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,10 @@ Converts ## Install -This is a development package, which itself is dependant on another development package [rapidjsonr](https://github.com/SymbolixAU/rapidjsonr) +This is a development package so can be installed directly from github ``` -devtools::install_github("SymbolixAU/rapidjsonr") -devtools::install_github("SymbolixAU/geo") +devtools::install_github("SymbolixAU/geojsonsf") ``` ## Motivation diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index 4428ad1..d45ed07 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -92,7 +92,7 @@ void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points) { void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_counter) { - Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; + //Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; //Rcpp::Rcout << "debug: sfc size: " << sfc.size() << std::endl; //os << "["; @@ -129,9 +129,9 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_coun // if no class attribute, go further into the list to try and find one fetch_coordinates(os, tmp, object_counter); } - Rcpp::Rcout << "debug: updating object_counter" << std::endl; + //Rcpp::Rcout << "debug: updating object_counter" << std::endl; object_counter++; - Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; + //Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; break; } case REALSXP: { @@ -146,9 +146,9 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_coun } else { add_lonlat_to_stream(os, tmp); } - Rcpp::Rcout << "debug: updating object_counter" << std::endl; + //Rcpp::Rcout << "debug: updating object_counter" << std::endl; object_counter++; - Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; + //Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; break; } case INTSXP: { @@ -165,31 +165,28 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_coun void add_geometry_to_stream(std::ostringstream& os, Rcpp::List& sfc) { - Rcpp::Rcout << "debug: resetting object_counter" << std::endl; + //Rcpp::Rcout << "debug: resetting object_counter" << std::endl; int object_counter = 0; fetch_coordinates(os, sfc, object_counter); } +// if only one object with properties, it's a 'feature' +// if only one object without properties, it's a 'geometry' +// if many objects it's a 'featurecollection' + + void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { Rcpp::CharacterVector cls; std::string geom_type; Rcpp::List sfci(1); - + Rcpp::List sfg_geojson(sfc.size()); for (int i = 0; i < sfc.size(); i++) { + // iff 'atomise'; return a StringVector of each geometry + // iff not, return an array of each vecor - // recurse into each geometry - // if it's a list, AND has a class/attribute, 'begin GEOJSON string', recurse again to get the vec/matrix/obj - // if if's not a list, get the obj & 'begin GEOJSON string' - // - get the obj & convert to GEOJSON - // - // move the 'getSfClass' into the recursing bit, 'begin' the stream if the sfg class exists - // recurse again to get the objects (if it's a list, it will recurse once more) - // - just need to make sure to close of geometrycollection objects...? - // keep track of inner-objects? like a counter - - sfci[0] = sfc[i]; - add_geometry_to_stream(os, sfci); - coord_separator(os, i, sfc.size()); + sfci[0] = sfc[i]; + add_geometry_to_stream(os, sfci); + coord_separator(os, i, sfc.size()); } } From 0cd00be02066fae5d4c625d618d36e0077d8d0af Mon Sep 17 00:00:00 2001 From: symbolixau Date: Wed, 11 Apr 2018 21:16:16 +1000 Subject: [PATCH 11/21] working through some ideas --- src/sf_geojson.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 6 deletions(-) diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index d45ed07..b042ba7 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -22,6 +22,41 @@ Rcpp::CharacterVector getSfClass(SEXP sf) { } return ""; } + + +void get_column_type(Rcpp::List& sf, Rcpp::StringVector& property_names, Rcpp::StringVector& column_types) { + + //int counter = 0; + //for (Rcpp::List::iterator it = sf.begin(); it != sf.end(); it++) { + for (int i = 0; i < property_names.size(); i++) { + + Rcpp::String col = property_names[i]; + SEXP vec = sf[col]; + + switch(TYPEOF(vec)) { + case REALSXP: + //Rcpp::Rcout << "REAL Number" << std::endl; + column_types[i] = "Number"; + break; + //case VECSXP: + // Rcpp::Rcout << "Number" << std::endl; + // break; + case INTSXP: + //Rcpp::Rcout << "INT Number" << std::endl; + column_types[i] = "Number"; + break; + case LGLSXP: + //Rcpp::Rcout << "LGL Logical" << std::endl; + column_types[i] = "Logical"; + break; + default: { + //Rcpp::Rcout << "default: String" << std::endl; + column_types[i] = "String"; + break; + } + } + } +} /* void add_geometrycollection_to_stream(std::ostringstream& os, Rcpp::List& gc) { os << "\"GeometryCollection\" , \"geometries\" : ["; @@ -207,23 +242,78 @@ Rcpp::StringVector rcpp_sfc_to_geojson(Rcpp::List sfc) { return os.str(); } + +void properties_to_json(std::ostringstream& os, Rcpp::List sf_row) { + // iterate over rows and add to JSON stream + +} + + +//void get_column_types(Rcpp::StringVector& column_types, Rcpp::List& sf) { +// for (int i = 0; i < sf.ncol(); i++) { +// column_types[i] = get_column_type(sf[i]); +// //Rcpp::Rcout << "debug: column type: " << column_types[i] << std::endl; +// } +//} + // [[Rcpp::export]] Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { + std::ostringstream os; // If it contains properties // it's a 'feature' (or featureCollection) // // if 'atomise', return one object per row - std::ostringstream os; + + Rcpp::StringVector column_types(sf.size() - 1); + //get_column_type(sf, column_types); + Rcpp::StringVector property_names(sf.size() - 1); + std::string geom_column = sf.attr("sf_column"); + Rcpp::StringVector col_names = sf.names(); + + // fill 'property_names' with all the columns which aren't 'sf_column' + int property_counter = 0; + for (int i = 0; i < sf.length(); i++) { + if (col_names[i] != geom_column) { + property_names[property_counter] = col_names[i]; + property_counter++; + } + } + + get_column_type(sf, property_names, column_types); + Rcpp::Rcout << "debug property names : " << property_names << std::endl; + Rcpp::Rcout << "debug column types : " << column_types << std::endl; + Rcpp::List sfc = sf[geom_column]; + Rcpp::List properties; + + // TODO: + // construct a StringMatrix with the dimensions of sf + // then I can fill a column at a time with a string of JSON... + // then can manipulate it as I want at the end; either atomising or combining + Rcpp::NumericMatrix json_mat(sfc.length(), sf.size()); // row x cols + for (int i = 0; i < sf.size(); i++) { + // iterate the list elements + for (int j = 0; j < sfc.length(); j++) { + // iterate each row + // construct a string of the property { name : value } + + + // TODO: what if there's a mssing element? + + } + } + sfc_to_geojson(os, sfc); - //for (int i = 0; i < sf.size(); i++) { - // Rcpp::List sfc = sf[i]; - // Rcpp::CharacterVector cls_attr = getSfClass(sfc); - // add_geometry_to_stream(os, sfc); - //} + + // iterate over each row of sf + // - properties to js + // - geometry to sf + // - combine + // IFF atomise, assign os.str() to result vector + // ELSE, don't. Rcpp::StringVector res = os.str(); From f258b6d5510a2c2f71637864fb62eeab5c2ffaf8 Mon Sep 17 00:00:00 2001 From: David Cooley Date: Thu, 12 Apr 2018 16:24:05 +1000 Subject: [PATCH 12/21] thoughts --- src/sf_geojson.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index b042ba7..ca27b2c 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -293,15 +293,17 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { // then I can fill a column at a time with a string of JSON... // then can manipulate it as I want at the end; either atomising or combining Rcpp::NumericMatrix json_mat(sfc.length(), sf.size()); // row x cols + for (int i = 0; i < sf.size(); i++) { // iterate the list elements + for (int j = 0; j < sfc.length(); j++) { // iterate each row // construct a string of the property { name : value } - // TODO: what if there's a mssing element? + // TODO: what if there's a mssing element? } } From 09d3a5e67cfcd73d23c2f15c93e2f94f2fb256cf Mon Sep 17 00:00:00 2001 From: symbolixau Date: Thu, 12 Apr 2018 21:09:53 +1000 Subject: [PATCH 13/21] ideas --- R/scratch.R | 30 +++++++++++ src/sf_geojson.cpp | 126 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 135 insertions(+), 21 deletions(-) diff --git a/R/scratch.R b/R/scratch.R index 9c73113..fdde451 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -60,3 +60,33 @@ # sf # sf_geojson(sf) +# js <- '[ +# { +# "type": "Feature", +# "properties" : {}, +# "geometry": { +# "type": "Polygon", +# "coordinates": [[ +# [-10.0, -10.0], +# [10.0, -10.0], +# [10.0, 10.0], +# [-10.0, -10.0]]] +# } +# }, +# { +# "type": "Feature", +# "properties" : { "id" : 1, "foo" : false, "bar" : "world" }, +# "geometry": { +# "type": "MultiPolygon", +# "coordinates": [ +# [[[180.0, 40.0], [180.0, 50.0], [170.0, 50.0], +# [170.0, 40.0], [180.0, 40.0]]], +# [[[-170.0, 40.0], [-170.0, 50.0], [-180.0, 50.0], +# [-180.0, 40.0], [-170.0, 40.0]]]] +# } +# } +# ]' +# sf <- geojson_sf(js) +# sf_geojson(sf) + + diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index ca27b2c..939f76f 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -1,5 +1,8 @@ +#include "geojsonsf.h" #include "geojson_wkt.h" #include "sf_geojson.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" #include using namespace Rcpp; @@ -248,29 +251,104 @@ void properties_to_json(std::ostringstream& os, Rcpp::List sf_row) { } +rapidjson::Value get_json_value(SEXP s, rapidjson::Document::AllocatorType& allocator) { + // TODO: + // switch on R type and return the rapidjson equivalent + rapidjson::Value v1; + switch (TYPEOF(s)) { + case VECSXP: { + rapidjson::Value v(rapidjson::kStringType); + std::string st = "bar"; + v.SetString(st.c_str(), allocator); + return v; + } + default: { + rapidjson::Value v(rapidjson::kStringType); + return v; + } + } + return v1; +} + +/* +// There's o such thing as a data.frame 'row'. +// have to operate on the lists/vector columns +void create_json(Rcpp::DataFrame df) { + + rapidjson::Document d; + d.SetObject(); + //rapidjson::Value o(rapidjson::kObjectType); + + rapidjson::Document::AllocatorType& allocator = d.GetAllocator(); + + for (int i = 0; i < df.nrow(); i++) { + rapidjson::Value o(rapidjson::kObjectType); + for (int j = 0; j < df.ncol(); j++) { + + // TOOD: + // iterate over the data.frame rows and create the properties object + + rapidjson::Value v(rapidjson::kStringType); + v.SetString("world", allocator); + o.AddMember("foo", v, allocator); + o.AddMember("bar", 2, allocator); + } + d.AddMember("properties", o, allocator); + } + + StringBuffer strbuf; + Writer writer(strbuf); + d.Accept(writer); + + std::cout << strbuf.GetString() << std::endl; +} +*/ + + +// TODO: +// For each column construct a JSON array of objects. +// and add the array to the document. +// Then reconstruct each array? +// the arrays will have nrow() members +void vector_to_json(Rcpp::StringVector& sv, std::string& this_type) { + std::string this_value; + if (this_type == "Number") { + for (int j = 0; j < sv.size(); j++) { + sv[j] = sv[j]; + } + // dont' do anything + } else if (this_type == "Logical") { + // convert to lower + for (int j = 0; j < sv.size(); j++) { + this_value = sv[j]; + transform(this_value.begin(), this_value.end(), this_value.begin(), tolower); + sv[j] = this_value; + } + } else { + for (int j = 0; j < sv.size(); j++) { + sv[j] = "\"" + sv[j] + "\""; + } + } +} + -//void get_column_types(Rcpp::StringVector& column_types, Rcpp::List& sf) { -// for (int i = 0; i < sf.ncol(); i++) { -// column_types[i] = get_column_type(sf[i]); -// //Rcpp::Rcout << "debug: column type: " << column_types[i] << std::endl; -// } -//} // [[Rcpp::export]] Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { std::ostringstream os; + Rcpp::List sf_copy = clone(sf); // If it contains properties // it's a 'feature' (or featureCollection) // // if 'atomise', return one object per row - Rcpp::StringVector column_types(sf.size() - 1); + Rcpp::StringVector column_types(sf_copy.size() - 1); //get_column_type(sf, column_types); - Rcpp::StringVector property_names(sf.size() - 1); + Rcpp::StringVector property_names(sf_copy.size() - 1); - std::string geom_column = sf.attr("sf_column"); - Rcpp::StringVector col_names = sf.names(); + std::string geom_column = sf_copy.attr("sf_column"); + Rcpp::StringVector col_names = sf_copy.names(); // fill 'property_names' with all the columns which aren't 'sf_column' int property_counter = 0; @@ -281,30 +359,36 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { } } - get_column_type(sf, property_names, column_types); - Rcpp::Rcout << "debug property names : " << property_names << std::endl; - Rcpp::Rcout << "debug column types : " << column_types << std::endl; + get_column_type(sf_copy, property_names, column_types); + //Rcpp::Rcout << "debug property names : " << property_names << std::endl; + //Rcpp::Rcout << "debug column types : " << column_types << std::endl; - Rcpp::List sfc = sf[geom_column]; + Rcpp::List sfc = sf_copy[geom_column]; Rcpp::List properties; // TODO: // construct a StringMatrix with the dimensions of sf // then I can fill a column at a time with a string of JSON... // then can manipulate it as I want at the end; either atomising or combining - Rcpp::NumericMatrix json_mat(sfc.length(), sf.size()); // row x cols + Rcpp::NumericMatrix json_mat(sfc.length(), sf_copy.size()); // row x cols + std::string this_name; + std::string this_type; + std::string this_value; + Rcpp::StringVector this_vector; - for (int i = 0; i < sf.size(); i++) { + for (int i = 0; i < property_names.length(); i++) { // iterate the list elements + this_name = property_names[i]; + this_type = column_types[i]; - for (int j = 0; j < sfc.length(); j++) { - // iterate each row - // construct a string of the property { name : value } + Rcpp::Rcout << "column: " << this_name << ", type: " << this_type << std::endl; + this_vector = as< Rcpp::StringVector >(sf_copy[this_name]); + vector_to_json(this_vector, this_type); + Rcpp::Rcout << this_vector << std::endl; - // TODO: what if there's a mssing element? - } + // TODO: what if there's a mssing element? } From 3014bba80e15ca646d1f112dd388773565cadf2d Mon Sep 17 00:00:00 2001 From: David Cooley Date: Fri, 20 Apr 2018 15:57:37 +1000 Subject: [PATCH 14/21] design --- R/geojson_sf.R | 12 +++--------- src/sf_geojson.cpp | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/R/geojson_sf.R b/R/geojson_sf.R index 1f83dde..12fbc80 100644 --- a/R/geojson_sf.R +++ b/R/geojson_sf.R @@ -100,19 +100,13 @@ geojson_sf.default <- function(geojson) rcpp_geojson_to_sf(geojson) sf_geojson <- function(sf) UseMethod("sf_geojson") #' @export -sf_geojson.sf <- function(sf) { - rcpp_sf_to_geojson(sf) -} +sf_geojson.sf <- function(sf) rcpp_sf_to_geojson(sf) #' @export -sf_geojson.sfc <- function(sf) { - rcpp_sfc_to_geojson(sf) -} +sf_geojson.sfc <- function(sf) rcpp_sfc_to_geojson(sf) #' @export -sf_geojson.sfg <- function(sf) { - rcpp_sfg_to_geojson(sf) -} +sf_geojson.sfg <- function(sf) rcpp_sfg_to_geojson(sf) sf_geojson.default <- function(sf) stop("Expected an sf object") diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index 939f76f..c1ca35d 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -407,3 +407,18 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { } +/// DESIGN: +/// should work for both properties & non-property sf +// result vector res(nrow(sf)); +// property_columns(); +// property_column_types(); +// for (i = 0; i < nrow(sf); i++) { +// for (j = 0; j < ncol(properties); j++){ +// stream each column into "properties": { } +// } +// if (ncol(properties) > 0) { +// needs to be a {"type":"Feature", ...} +// then create "geometry":{"type" :"geom","coordinates":[]} +// } +// result will be a vector of JSON. +// can combine or keep 'atomic'. From e9c79be196b567bc032f6239b91af874870403c5 Mon Sep 17 00:00:00 2001 From: symbolixau Date: Fri, 20 Apr 2018 17:27:48 +1000 Subject: [PATCH 15/21] tidying --- R/RcppExports.R | 14 +++---- tests/testthat/test-geojson_properties.R | 53 ++++++------------------ 2 files changed, 20 insertions(+), 47 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index 1a31c1e..19fd6ee 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -2,30 +2,30 @@ # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 rcpp_geojson_to_sfc <- function(geojson) { - .Call('_geojsonsf_rcpp_geojson_to_sfc', PACKAGE = 'geojsonsf', geojson) + .Call(`_geojsonsf_rcpp_geojson_to_sfc`, geojson) } rcpp_geojson_to_sf <- function(geojson) { - .Call('_geojsonsf_rcpp_geojson_to_sf', PACKAGE = 'geojsonsf', geojson) + .Call(`_geojsonsf_rcpp_geojson_to_sf`, geojson) } rcpp_geojson_to_wkt <- function(geojson) { - .Call('_geojsonsf_rcpp_geojson_to_wkt', PACKAGE = 'geojsonsf', geojson) + .Call(`_geojsonsf_rcpp_geojson_to_wkt`, geojson) } rcpp_read_sfc_file <- function(file) { - .Call('_geojsonsf_rcpp_read_sfc_file', PACKAGE = 'geojsonsf', file) + .Call(`_geojsonsf_rcpp_read_sfc_file`, file) } rcpp_read_sf_file <- function(file) { - .Call('_geojsonsf_rcpp_read_sf_file', PACKAGE = 'geojsonsf', file) + .Call(`_geojsonsf_rcpp_read_sf_file`, file) } rcpp_sfc_to_geojson <- function(sfc) { - .Call('_geojsonsf_rcpp_sfc_to_geojson', PACKAGE = 'geojsonsf', sfc) + .Call(`_geojsonsf_rcpp_sfc_to_geojson`, sfc) } rcpp_sf_to_geojson <- function(sf) { - .Call('_geojsonsf_rcpp_sf_to_geojson', PACKAGE = 'geojsonsf', sf) + .Call(`_geojsonsf_rcpp_sf_to_geojson`, sf) } diff --git a/tests/testthat/test-geojson_properties.R b/tests/testthat/test-geojson_properties.R index 0362b53..c705866 100644 --- a/tests/testthat/test-geojson_properties.R +++ b/tests/testthat/test-geojson_properties.R @@ -11,25 +11,12 @@ test_that("properties captured correctly", { sf <- geojson_sf(f) wkt <- geojson_wkt(f) - expect_true( - all(names(sf) == c("geometry", "id", "name")) - ) - expect_true( - all(names(wkt) == c("geometry", "id", "name")) - ) - - expect_true( - sf$id == 1 - ) - expect_true( - wkt$id == 1 - ) - expect_true( - sf$name == "foo" - ) - expect_true( - wkt$name == "foo" - ) + expect_true(all(names(sf) == c("geometry", "id", "name"))) + expect_true(all(names(wkt) == c("geometry", "id", "name"))) + expect_true(sf$id == 1) + expect_true(wkt$id == 1) + expect_true(sf$name == "foo") + expect_true(wkt$name == "foo") js <- '[ { @@ -131,24 +118,12 @@ test_that("properties captured correctly", { sf <- geojson_sf(js) wkt <- geojson_wkt(js) - expect_true( - ncol(sf) == 3 - ) - expect_true( - ncol(wkt) == 3 - ) - expect_true( - sum(sf$id, na.rm = T) == 3 - ) - expect_true( - sum(wkt$id, na.rm = T) == 3 - ) - expect_true( - sf$value[!is.na(sf$value)] == "foo" - ) - expect_true( - wkt$value[!is.na(wkt$value)] == "foo" - ) + expect_true(ncol(sf) == 3) + expect_true(ncol(wkt) == 3) + expect_true(sum(sf$id, na.rm = T) == 3) + expect_true(sum(wkt$id, na.rm = T) == 3) + expect_true(sf$value[!is.na(sf$value)] == "foo") + expect_true(wkt$value[!is.na(wkt$value)] == "foo") }) @@ -163,8 +138,6 @@ test_that("sf and sfc created equally", { sf <- geojson_sf(f) sfc <- geojson_sfc(f) - expect_true( - all(class(sf$geometry) == class(sfc)) - ) + expect_true(all(class(sf$geometry) == class(sfc))) }) From 088d32373c70d6c9ff14712f36f8ae42929e6a70 Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sat, 21 Apr 2018 12:57:17 +1000 Subject: [PATCH 16/21] changed to strings --- R/RcppExports.R | 4 - inst/include/sf_geojson.h | 16 ++- src/RcppExports.cpp | 14 +- src/geojson_wkt.cpp | 2 +- src/sf_geojson.cpp | 276 ++++++++++++++------------------------ 5 files changed, 116 insertions(+), 196 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index 19fd6ee..0dbccb0 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -21,10 +21,6 @@ rcpp_read_sf_file <- function(file) { .Call(`_geojsonsf_rcpp_read_sf_file`, file) } -rcpp_sfc_to_geojson <- function(sfc) { - .Call(`_geojsonsf_rcpp_sfc_to_geojson`, sfc) -} - rcpp_sf_to_geojson <- function(sf) { .Call(`_geojsonsf_rcpp_sf_to_geojson`, sf) } diff --git a/inst/include/sf_geojson.h b/inst/include/sf_geojson.h index bfe5ba5..cb3bc9b 100644 --- a/inst/include/sf_geojson.h +++ b/inst/include/sf_geojson.h @@ -7,14 +7,20 @@ using namespace Rcpp; //void add_geometrycollection_to_stream(std::ostringstream& os, Rcpp::List& gc); -void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type); +void begin_geojson_geometry(Rcpp::String& geojson, std::string& geom_type); -void begin_geojson_geometry(std::ostringstream& os, Rcpp::List& sfc, std::string& geom_type); +void begin_geojson_geometry(Rcpp::String& geojson, Rcpp::List& sfc, std::string& geom_type); -void end_geojson_geometry(std::ostringstream& os, std::string& geom_type); +void end_geojson_geometry(Rcpp::String& geojson, std::string& geom_type); -void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points); +void add_lonlat_to_stream(Rcpp::String& geojson, Rcpp::NumericVector& points); -void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_counter); +void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_counter); + +void coord_separator(Rcpp::String& geojson, int i, int n); + +void line_separator_geojson(Rcpp::String& geojson, int i, int n); + +void polygon_separator_geojson(Rcpp::String& geojson, int i, int n); #endif diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 07bde20..4d34be4 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -61,19 +61,8 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } -// rcpp_sfc_to_geojson -Rcpp::StringVector rcpp_sfc_to_geojson(Rcpp::List sfc); -RcppExport SEXP _geojsonsf_rcpp_sfc_to_geojson(SEXP sfcSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< Rcpp::List >::type sfc(sfcSEXP); - rcpp_result_gen = Rcpp::wrap(rcpp_sfc_to_geojson(sfc)); - return rcpp_result_gen; -END_RCPP -} // rcpp_sf_to_geojson -Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf); +Rcpp::StringMatrix rcpp_sf_to_geojson(Rcpp::List sf); RcppExport SEXP _geojsonsf_rcpp_sf_to_geojson(SEXP sfSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; @@ -90,7 +79,6 @@ static const R_CallMethodDef CallEntries[] = { {"_geojsonsf_rcpp_geojson_to_wkt", (DL_FUNC) &_geojsonsf_rcpp_geojson_to_wkt, 1}, {"_geojsonsf_rcpp_read_sfc_file", (DL_FUNC) &_geojsonsf_rcpp_read_sfc_file, 1}, {"_geojsonsf_rcpp_read_sf_file", (DL_FUNC) &_geojsonsf_rcpp_read_sf_file, 1}, - {"_geojsonsf_rcpp_sfc_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sfc_to_geojson, 1}, {"_geojsonsf_rcpp_sf_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sf_to_geojson, 1}, {NULL, NULL, 0} }; diff --git a/src/geojson_wkt.cpp b/src/geojson_wkt.cpp index d2d1884..f5063ba 100644 --- a/src/geojson_wkt.cpp +++ b/src/geojson_wkt.cpp @@ -51,7 +51,7 @@ void object_separator(std::ostringstream& os) { void coord_separator(std::ostringstream& os, int i, int n) { if (i < (n - 1) ) { - os << ", "; + os << ","; } } diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index c1ca35d..b298fbf 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -13,7 +13,6 @@ Rcpp::CharacterVector sfClass(Vector v) { } Rcpp::CharacterVector getSfClass(SEXP sf) { - switch( TYPEOF(sf) ) { case REALSXP: return sfClass(sf); @@ -27,7 +26,8 @@ Rcpp::CharacterVector getSfClass(SEXP sf) { } -void get_column_type(Rcpp::List& sf, Rcpp::StringVector& property_names, Rcpp::StringVector& column_types) { +void get_column_type(Rcpp::List& sf, Rcpp::StringVector& property_names, + Rcpp::StringVector& column_types) { //int counter = 0; //for (Rcpp::List::iterator it = sf.begin(); it != sf.end(); it++) { @@ -60,89 +60,107 @@ void get_column_type(Rcpp::List& sf, Rcpp::StringVector& property_names, Rcpp::S } } } -/* -void add_geometrycollection_to_stream(std::ostringstream& os, Rcpp::List& gc) { - os << "\"GeometryCollection\" , \"geometries\" : ["; - // recurse into gc object - Rcpp::List gci(1); - for (int i = 0; i < gc.size(); i++) { - gci[0] = gc[i]; - fetch_coordinates(os, gci); - object_separator(os); - } - os << "]}"; -} -*/ -void begin_geojson_geometry(std::ostringstream& os, std::string& geom_type) { + +void begin_geojson_geometry(Rcpp::String& geojson, std::string& geom_type) { Rcpp::List sfc; - begin_geojson_geometry(os, sfc, geom_type); + begin_geojson_geometry(geojson, sfc, geom_type); } -// Stream an SF object to GeoJSON -void begin_geojson_geometry(std::ostringstream& os, Rcpp::List& sfc, std::string& geom_type) { - os << "{\"type\" : "; +void begin_geojson_geometry(Rcpp::String& geojson, Rcpp::List& sfc, std::string& geom_type) { + //os << "{\"type\" : "; + geojson += "{\"type\":"; if (geom_type == "POINT") { - os << "\"Point\" , \"coordinates\" : "; + //os << "\"Point\" , \"coordinates\" : "; + geojson += "\"Point\",\"coordinates\":"; } else if (geom_type == "MULTIPOINT") { - os << "\"MultiPoint\" , \"coordinates\" : ["; + //os << "\"MultiPoint\" , \"coordinates\" : ["; + geojson += "\"MultiPoint\",\"coordinates\":["; } else if (geom_type == "LINESTRING") { - os << "\"LineString\" , \"coordinates\" : ["; + //os << "\"LineString\" , \"coordinates\" : ["; + geojson += "\"LineString\",\"coordinates\":["; } else if (geom_type == "MULTILINESTRING") { - os << "\"MultiLineString\" , \"coordinates\" : [["; + //os << "\"MultiLineString\" , \"coordinates\" : [["; + geojson += "\"MultiLineString\",\"coordinates\":[["; } else if (geom_type == "POLYGON") { - os << "\"Polygon\" , \"coordinates\" : [["; + //os << "\"Polygon\" , \"coordinates\" : [["; + geojson += "\"Polygon\",\"coordinates\":[["; } else if (geom_type == "MULTIPOLYGON") { - os << "\"MultiPolygon\" , \"coordinates\" : [[["; + //os << "\"MultiPolygon\" , \"coordinates\" : [[["; + geojson += "\"MultiPolygon\",\"coordinates\":[[["; } else if (geom_type == "GEOMETRYCOLLECTION") { //add_geometrycollection_to_stream(os, sfc); - os << "\"GeometryCollection\" , \"geometries\" : ["; + //os << "\"GeometryCollection\" , \"geometries\" : ["; + geojson += "\"GeometryCollection\",\"geometries\":["; } } -void end_geojson_geometry(std::ostringstream& os, std::string& geom_type) { +void end_geojson_geometry(Rcpp::String& geojson, std::string& geom_type) { if (geom_type == "POINT") { - os << "}"; + //os << "}"; + geojson += "}"; } else if (geom_type == "MULTIPOINT") { - os << "]}"; + //os << "]}"; + geojson += "]}"; } else if (geom_type == "LINESTRING") { - os << "]}"; + //os << "]}"; + geojson += "]}"; } else if (geom_type == "MULTILINESTRING") { - os << "]]}"; + //os << "]]}"; + geojson += "]]}"; } else if (geom_type == "POLYGON") { - os << "]]}"; + //os << "]]}"; + geojson += "]]}"; } else if (geom_type == "MULTIPOLYGON") { - os << "]]]}"; + //os << "]]]}"; + geojson += "]]]}"; } else if (geom_type == "GEOMETRYCOLLECTION") { - os << "]}"; + //os << "]}"; + geojson += "]}"; + } +} + +void coord_separator(Rcpp::String& geojson, int i, int n) { + if (i < (n - 1) ) { + geojson += ","; } } -void add_lonlat_to_stream(std::ostringstream& os, Rcpp::NumericVector& points) { +void line_separator_geojson(Rcpp::String& geojson, int i, int n) { + if (i < (n - 1) ) { + geojson += "],["; + } +} + +void polygon_separator_geojson(Rcpp::String& geojson, int i, int n) { + if (i < (n - 1) ) { + geojson += "]],[["; + } +} + +void add_lonlat_to_stream(Rcpp::String& geojson, Rcpp::NumericVector& points) { points.attr("dim") = Dimension(points.size() / 2, 2); Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); for (int i = 0; i < m.nrow(); i++) { - os << "[" << m(i, 0) << "," << m(i, 1) << "]"; - coord_separator(os, i, m.nrow()); + geojson += "["; + geojson += m(i,0); + geojson += ","; + geojson += m(i,1); + geojson += "]"; + coord_separator(geojson, i, m.nrow()); } } -void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_counter) { - - //Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; +void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_counter) { - //Rcpp::Rcout << "debug: sfc size: " << sfc.size() << std::endl; - //os << "["; - //bracket_counter++; - //Rcpp::Rcout << "type sfc: " << TYPEOF(sfc) << std::endl; Rcpp::CharacterVector cls; std::string geom_type; for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { if (object_counter > 0) { - object_separator(os); + geojson += ","; } switch( TYPEOF(*it) ) { @@ -150,26 +168,16 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_coun Rcpp::List tmp = as(*it); if(!Rf_isNull(tmp.attr("class"))) { - // if there's a 'class' attribute, it's an sfg object - // but it's also a list - // so need to go through the list elemetns and fetch the geometries - // - // but, if the list is a 'GEOMETRYCOLLECTION', we need a ',' separator - // after each geometry - - //Rcpp::Rcout << "debug list " << std::endl; cls = getSfClass(tmp); geom_type = cls[1]; // TODO: error handle (there should aways be 3 elements as we're workgin wtih sfg objects) - begin_geojson_geometry(os, tmp, geom_type); - fetch_coordinates(os, tmp, object_counter); - end_geojson_geometry(os, geom_type); + begin_geojson_geometry(geojson, tmp, geom_type); + fetch_coordinates(geojson, tmp, object_counter); + end_geojson_geometry(geojson, geom_type); } else { // if no class attribute, go further into the list to try and find one - fetch_coordinates(os, tmp, object_counter); + fetch_coordinates(geojson, tmp, object_counter); } - //Rcpp::Rcout << "debug: updating object_counter" << std::endl; object_counter++; - //Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; break; } case REALSXP: { @@ -178,34 +186,32 @@ void fetch_coordinates(std::ostringstream& os, Rcpp::List& sfc, int& object_coun //Rcpp::Rcout << "debug vector " << std::endl; cls = getSfClass(tmp); geom_type = cls[1]; - begin_geojson_geometry(os, geom_type); - add_lonlat_to_stream(os, tmp); - end_geojson_geometry(os, geom_type); + begin_geojson_geometry(geojson, geom_type); + add_lonlat_to_stream(geojson, tmp); + end_geojson_geometry(geojson, geom_type); } else { - add_lonlat_to_stream(os, tmp); + add_lonlat_to_stream(geojson, tmp); } - //Rcpp::Rcout << "debug: updating object_counter" << std::endl; object_counter++; - //Rcpp::Rcout << "debug object_couter: " << object_counter << std::endl; break; } case INTSXP: { - //Rcpp::IntegerVector tmp = as(*it); - //add_lonlat_to_stream(os, tmp); break; } default: { Rcpp::stop("Coordinates could not be found"); } - } + } } } +Rcpp::String add_geometry_to_stream(Rcpp::List& sfg) { -void add_geometry_to_stream(std::ostringstream& os, Rcpp::List& sfc) { - //Rcpp::Rcout << "debug: resetting object_counter" << std::endl; + Rcpp::String geojson; int object_counter = 0; - fetch_coordinates(os, sfc, object_counter); + fetch_coordinates(geojson, sfg, object_counter); + + return geojson; } // if only one object with properties, it's a 'feature' @@ -213,44 +219,6 @@ void add_geometry_to_stream(std::ostringstream& os, Rcpp::List& sfc) { // if many objects it's a 'featurecollection' -void sfg_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { - Rcpp::CharacterVector cls; - std::string geom_type; - Rcpp::List sfci(1); - Rcpp::List sfg_geojson(sfc.size()); - for (int i = 0; i < sfc.size(); i++) { - // iff 'atomise'; return a StringVector of each geometry - // iff not, return an array of each vecor - - sfci[0] = sfc[i]; - add_geometry_to_stream(os, sfci); - coord_separator(os, i, sfc.size()); - } -} - -void sfc_to_geojson(std::ostringstream& os, Rcpp::List& sfc) { - sfg_to_geojson(os, sfc); -} - -Rcpp::StringVector rcpp_sfg_to_geojson(Rcpp::List sfg) { - std::ostringstream os; - sfg_to_geojson(os, sfg); - return os.str(); -} - -// [[Rcpp::export]] -Rcpp::StringVector rcpp_sfc_to_geojson(Rcpp::List sfc) { - std::ostringstream os; - sfc_to_geojson(os, sfc); - return os.str(); -} - - -void properties_to_json(std::ostringstream& os, Rcpp::List sf_row) { - // iterate over rows and add to JSON stream - -} - rapidjson::Value get_json_value(SEXP s, rapidjson::Document::AllocatorType& allocator) { // TODO: // switch on R type and return the rapidjson equivalent @@ -258,51 +226,20 @@ rapidjson::Value get_json_value(SEXP s, rapidjson::Document::AllocatorType& allo switch (TYPEOF(s)) { case VECSXP: { rapidjson::Value v(rapidjson::kStringType); - std::string st = "bar"; + std::string st = as< std::string >(s); v.SetString(st.c_str(), allocator); return v; } default: { rapidjson::Value v(rapidjson::kStringType); + std::string st = as< std::string >(s); + v.SetString(st.c_str(), allocator); return v; } } return v1; } -/* -// There's o such thing as a data.frame 'row'. -// have to operate on the lists/vector columns -void create_json(Rcpp::DataFrame df) { - - rapidjson::Document d; - d.SetObject(); - //rapidjson::Value o(rapidjson::kObjectType); - - rapidjson::Document::AllocatorType& allocator = d.GetAllocator(); - - for (int i = 0; i < df.nrow(); i++) { - rapidjson::Value o(rapidjson::kObjectType); - for (int j = 0; j < df.ncol(); j++) { - - // TOOD: - // iterate over the data.frame rows and create the properties object - - rapidjson::Value v(rapidjson::kStringType); - v.SetString("world", allocator); - o.AddMember("foo", v, allocator); - o.AddMember("bar", 2, allocator); - } - d.AddMember("properties", o, allocator); - } - - StringBuffer strbuf; - Writer writer(strbuf); - d.Accept(writer); - - std::cout << strbuf.GetString() << std::endl; -} -*/ // TODO: @@ -310,33 +247,39 @@ void create_json(Rcpp::DataFrame df) { // and add the array to the document. // Then reconstruct each array? // the arrays will have nrow() members -void vector_to_json(Rcpp::StringVector& sv, std::string& this_type) { +void vector_to_json(Rcpp::StringVector& sv, std::string& this_type, std::string& this_name) { std::string this_value; + if (this_type == "Number") { for (int j = 0; j < sv.size(); j++) { - sv[j] = sv[j]; + sv[j] = "\"" + this_name + "\"" + ":" + sv[j]; } - // dont' do anything } else if (this_type == "Logical") { // convert to lower for (int j = 0; j < sv.size(); j++) { this_value = sv[j]; transform(this_value.begin(), this_value.end(), this_value.begin(), tolower); - sv[j] = this_value; + sv[j] = "\"" + this_name + "\"" + ":" + this_value; } } else { for (int j = 0; j < sv.size(); j++) { - sv[j] = "\"" + sv[j] + "\""; + sv[j] = "\"" + this_name + "\"" + ":" + "\"" + sv[j] + "\""; } } } - +void geometry_vector_to_geojson(Rcpp::StringVector& geometry_json, Rcpp::List& sfc) { + Rcpp::List sfg(1); + for (int i = 0; i < sfc.size(); i++) { + sfg[0] = sfc[i]; + geometry_json[i] = add_geometry_to_stream(sfg); + } +} // [[Rcpp::export]] -Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { +Rcpp::StringMatrix rcpp_sf_to_geojson(Rcpp::List sf) { - std::ostringstream os; + //std::ostringstream os; Rcpp::List sf_copy = clone(sf); // If it contains properties // it's a 'feature' (or featureCollection) @@ -360,9 +303,6 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { } get_column_type(sf_copy, property_names, column_types); - //Rcpp::Rcout << "debug property names : " << property_names << std::endl; - //Rcpp::Rcout << "debug column types : " << column_types << std::endl; - Rcpp::List sfc = sf_copy[geom_column]; Rcpp::List properties; @@ -370,7 +310,7 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { // construct a StringMatrix with the dimensions of sf // then I can fill a column at a time with a string of JSON... // then can manipulate it as I want at the end; either atomising or combining - Rcpp::NumericMatrix json_mat(sfc.length(), sf_copy.size()); // row x cols + Rcpp::StringMatrix json_mat(sfc.length(), col_names.size()); // row x cols std::string this_name; std::string this_type; std::string this_value; @@ -380,30 +320,20 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { // iterate the list elements this_name = property_names[i]; this_type = column_types[i]; - - Rcpp::Rcout << "column: " << this_name << ", type: " << this_type << std::endl; - this_vector = as< Rcpp::StringVector >(sf_copy[this_name]); - vector_to_json(this_vector, this_type); - Rcpp::Rcout << this_vector << std::endl; + vector_to_json(this_vector, this_type, this_name); + //this_vector = "{\"properties\":{" + this_vector + "}"; + json_mat(_, i) = this_vector; // TODO: what if there's a mssing element? } + Rcpp::StringVector geometry_json(sfc.length()); + geometry_vector_to_geojson(geometry_json, sfc); + json_mat(_, (json_mat.ncol() - 1) ) = geometry_json; - sfc_to_geojson(os, sfc); - - // iterate over each row of sf - // - properties to js - // - geometry to sf - // - combine - // IFF atomise, assign os.str() to result vector - // ELSE, don't. - - Rcpp::StringVector res = os.str(); - - return res; + return json_mat; } From 114dbb1bb7a1e2181fb69070f97ce3841c487c73 Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sat, 21 Apr 2018 14:59:05 +1000 Subject: [PATCH 17/21] string fixes --- R/scratch.R | 7 +++ inst/include/geojson_wkt.h | 4 +- src/RcppExports.cpp | 2 +- src/geojson_wkt.cpp | 8 ++-- src/sf_geojson.cpp | 88 +++++++++++++++++++++----------------- 5 files changed, 62 insertions(+), 47 deletions(-) diff --git a/R/scratch.R b/R/scratch.R index 388a0f3..b74f9e7 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -82,3 +82,10 @@ # sf <- geojson_sf(js) # sf_geojson(sf) + + + + + + + diff --git a/inst/include/geojson_wkt.h b/inst/include/geojson_wkt.h index 71548c6..df405f7 100644 --- a/inst/include/geojson_wkt.h +++ b/inst/include/geojson_wkt.h @@ -11,9 +11,9 @@ void line_separator_wkt(std::ostringstream& os, int i, int n); void object_separator(std::ostringstream& os); -void polygonSeparateWKT(std::ostringstream& os, int i, int n); +void polygon_separate_wkt(std::ostringstream& os, int i, int n); -void addLonLatToWKTStream(std::ostringstream& os, float lon, float lat ); +void add_lonlat_to_wkt_stream(std::ostringstream& os, float lon, float lat ); void begin_wkt(std::ostringstream& os, std::string& geom_type); diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 4d34be4..48a9cb3 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -62,7 +62,7 @@ BEGIN_RCPP END_RCPP } // rcpp_sf_to_geojson -Rcpp::StringMatrix rcpp_sf_to_geojson(Rcpp::List sf); +Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf); RcppExport SEXP _geojsonsf_rcpp_sf_to_geojson(SEXP sfSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; diff --git a/src/geojson_wkt.cpp b/src/geojson_wkt.cpp index f5063ba..d22dd37 100644 --- a/src/geojson_wkt.cpp +++ b/src/geojson_wkt.cpp @@ -61,14 +61,14 @@ void line_separator_wkt(std::ostringstream& os, int i, int n) { } } -void polygonSeparateWKT(std::ostringstream& os, int i, int n) { +void polygon_separate_wkt(std::ostringstream& os, int i, int n) { if (i < (n - 1) ) { os << ")),(("; } } -void addLonLatToWKTStream(std::ostringstream& os, float lon, float lat ) { +void add_lonlat_to_wkt_stream(std::ostringstream& os, float lon, float lat ) { os << lon << " " << lat; } @@ -76,7 +76,7 @@ void point_to_wkt(std::ostringstream& os, const Value& coord_array) { Rcpp::NumericVector point(2); point[0] = get_lon(coord_array); point[1] = get_lat(coord_array); - addLonLatToWKTStream(os, point[0], point[1]); + add_lonlat_to_wkt_stream(os, point[0], point[1]); } @@ -126,7 +126,7 @@ void multi_polygon_to_wkt(std::ostringstream& os, const Value& coord_array) { for (i = 0; i < n; i++) { validate_array(coord_array[i]); polygon_to_wkt(os, coord_array[i]); - polygonSeparateWKT(os, i, n); + polygon_separate_wkt(os, i, n); } } diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index b298fbf..f2c8ac5 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -26,11 +26,10 @@ Rcpp::CharacterVector getSfClass(SEXP sf) { } -void get_column_type(Rcpp::List& sf, Rcpp::StringVector& property_names, +void get_column_type(Rcpp::List& sf, + Rcpp::StringVector& property_names, Rcpp::StringVector& column_types) { - //int counter = 0; - //for (Rcpp::List::iterator it = sf.begin(); it != sf.end(); it++) { for (int i = 0; i < property_names.size(); i++) { Rcpp::String col = property_names[i]; @@ -38,22 +37,15 @@ void get_column_type(Rcpp::List& sf, Rcpp::StringVector& property_names, switch(TYPEOF(vec)) { case REALSXP: - //Rcpp::Rcout << "REAL Number" << std::endl; column_types[i] = "Number"; break; - //case VECSXP: - // Rcpp::Rcout << "Number" << std::endl; - // break; case INTSXP: - //Rcpp::Rcout << "INT Number" << std::endl; column_types[i] = "Number"; break; case LGLSXP: - //Rcpp::Rcout << "LGL Logical" << std::endl; column_types[i] = "Logical"; break; default: { - //Rcpp::Rcout << "default: String" << std::endl; column_types[i] = "String"; break; } @@ -67,54 +59,39 @@ void begin_geojson_geometry(Rcpp::String& geojson, std::string& geom_type) { } void begin_geojson_geometry(Rcpp::String& geojson, Rcpp::List& sfc, std::string& geom_type) { - //os << "{\"type\" : "; + geojson += "{\"type\":"; if (geom_type == "POINT") { - //os << "\"Point\" , \"coordinates\" : "; geojson += "\"Point\",\"coordinates\":"; } else if (geom_type == "MULTIPOINT") { - //os << "\"MultiPoint\" , \"coordinates\" : ["; geojson += "\"MultiPoint\",\"coordinates\":["; } else if (geom_type == "LINESTRING") { - //os << "\"LineString\" , \"coordinates\" : ["; geojson += "\"LineString\",\"coordinates\":["; } else if (geom_type == "MULTILINESTRING") { - //os << "\"MultiLineString\" , \"coordinates\" : [["; geojson += "\"MultiLineString\",\"coordinates\":[["; } else if (geom_type == "POLYGON") { - //os << "\"Polygon\" , \"coordinates\" : [["; geojson += "\"Polygon\",\"coordinates\":[["; } else if (geom_type == "MULTIPOLYGON") { - //os << "\"MultiPolygon\" , \"coordinates\" : [[["; geojson += "\"MultiPolygon\",\"coordinates\":[[["; } else if (geom_type == "GEOMETRYCOLLECTION") { - //add_geometrycollection_to_stream(os, sfc); - //os << "\"GeometryCollection\" , \"geometries\" : ["; geojson += "\"GeometryCollection\",\"geometries\":["; } } void end_geojson_geometry(Rcpp::String& geojson, std::string& geom_type) { if (geom_type == "POINT") { - //os << "}"; geojson += "}"; } else if (geom_type == "MULTIPOINT") { - //os << "]}"; geojson += "]}"; } else if (geom_type == "LINESTRING") { - //os << "]}"; geojson += "]}"; } else if (geom_type == "MULTILINESTRING") { - //os << "]]}"; geojson += "]]}"; } else if (geom_type == "POLYGON") { - //os << "]]}"; geojson += "]]}"; } else if (geom_type == "MULTIPOLYGON") { - //os << "]]]}"; geojson += "]]]}"; } else if (geom_type == "GEOMETRYCOLLECTION") { - //os << "]}"; geojson += "]}"; } } @@ -162,7 +139,6 @@ void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_count if (object_counter > 0) { geojson += ","; } - switch( TYPEOF(*it) ) { case VECSXP: { Rcpp::List tmp = as(*it); @@ -183,7 +159,7 @@ void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_count case REALSXP: { Rcpp::NumericVector tmp = as(*it); if(!Rf_isNull(tmp.attr("class"))) { - //Rcpp::Rcout << "debug vector " << std::endl; + cls = getSfClass(tmp); geom_type = cls[1]; begin_geojson_geometry(geojson, geom_type); @@ -218,7 +194,6 @@ Rcpp::String add_geometry_to_stream(Rcpp::List& sfg) { // if only one object without properties, it's a 'geometry' // if many objects it's a 'featurecollection' - rapidjson::Value get_json_value(SEXP s, rapidjson::Document::AllocatorType& allocator) { // TODO: // switch on R type and return the rapidjson equivalent @@ -241,29 +216,35 @@ rapidjson::Value get_json_value(SEXP s, rapidjson::Document::AllocatorType& allo } - -// TODO: -// For each column construct a JSON array of objects. -// and add the array to the document. -// Then reconstruct each array? -// the arrays will have nrow() members void vector_to_json(Rcpp::StringVector& sv, std::string& this_type, std::string& this_name) { std::string this_value; if (this_type == "Number") { for (int j = 0; j < sv.size(); j++) { - sv[j] = "\"" + this_name + "\"" + ":" + sv[j]; + this_value = sv[j]; + if(this_value == "NA") { + this_value = "null"; + } + sv[j] = "\"" + this_name + "\"" + ":" + this_value; } } else if (this_type == "Logical") { - // convert to lower for (int j = 0; j < sv.size(); j++) { this_value = sv[j]; + if(this_value == "NA") { + this_value = "null"; + } transform(this_value.begin(), this_value.end(), this_value.begin(), tolower); sv[j] = "\"" + this_name + "\"" + ":" + this_value; } } else { for (int j = 0; j < sv.size(); j++) { - sv[j] = "\"" + this_name + "\"" + ":" + "\"" + sv[j] + "\""; + this_value = sv[j]; + if (this_value == "NA") { + this_value = "null"; + } else { + this_value = "\"" + this_value + "\""; + } + sv[j] = "\"" + this_name + "\"" + ":" + this_value; } } } @@ -276,8 +257,28 @@ void geometry_vector_to_geojson(Rcpp::StringVector& geometry_json, Rcpp::List& s } } +Rcpp::String matrix_row_to_json(Rcpp::StringMatrix& json_mat, int i) { + std::ostringstream os; + int n = json_mat.ncol(); + os << "{\"type\":\"Feature\",\"properties\":{"; + for (int j = 0; j < (n-1); j++) { + os << json_mat(i, j); + coord_separator(os, j, (n-1)); + } + os << "},"; + + os << "\"geometry\":"; + //s = json_mat(i, (n-1)); + //st = s; + os << json_mat(i, (n-1)); + os << "}"; + + Rcpp::String res = os.str(); + return res; +} + // [[Rcpp::export]] -Rcpp::StringMatrix rcpp_sf_to_geojson(Rcpp::List sf) { +Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { //std::ostringstream os; Rcpp::List sf_copy = clone(sf); @@ -333,7 +334,14 @@ Rcpp::StringMatrix rcpp_sf_to_geojson(Rcpp::List sf) { geometry_vector_to_geojson(geometry_json, sfc); json_mat(_, (json_mat.ncol() - 1) ) = geometry_json; - return json_mat; + Rcpp::StringVector res(json_mat.nrow()); + + // If properties, do this bit. else return a vector (column of matrix) + for (int i = 0; i < res.length(); i++) { + res[i] = matrix_row_to_json(json_mat, i); + } + + return res; } From 995e6bb5cfc360d57913a62a7a22e8cd68eec1c9 Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sat, 21 Apr 2018 18:57:18 +1000 Subject: [PATCH 18/21] changing logic --- DESCRIPTION | 2 +- R/scratch.R | 48 ++++++++++++++-- src/sf_geojson.cpp | 134 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 168 insertions(+), 16 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 0de5631..87e73dd 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: geojsonsf Type: Package Title: GeoJSON to Simple Feature Converter -Version: 0.3.0003 +Version: 0.3.0004 Authors@R: c( person("David", "Cooley", ,"dcooley@symbolix.com.au", role = c("aut", "cre")) ) diff --git a/R/scratch.R b/R/scratch.R index b74f9e7..8785238 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -24,7 +24,7 @@ # sf_geojson(sf) # # js <- '[{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}, -# {"type" : "MultiLineString", "coordinates" : [ [ [0, 0], [1, 1] ] ]}]' +# {"type" : "MultiLineString", "coordinates" : [ [ [0, 0], [1, 1] ], [[3,3],[4,4]] ]}]' # sf <- geojson_sf(js) # sf # sf_geojson(sf) @@ -36,8 +36,10 @@ # {"type" : "MultiPoint", "coordinates" : [[0,0], [1,1], [2,2]]} # ]}' # sf <- geojson_sf(js) -# sf -# sf_geojson(sf) +# j <- sf_geojson(sf) +# +# j +# gsub(" |\\n|\\r","",js) # js <- '[{"type" : "Polygon", "coordinates" : [ [ [0, 0], [1, 1] ] ]}, @@ -79,13 +81,49 @@ # } # } # ]' -# sf <- geojson_sf(js) -# sf_geojson(sf) +# sf <- geojson_sf(js) +# sf_geojson(sf) +# geojson_sf( sf_geojson(sf) ) +# js <- '{"type":"MultiPolygon","coordinates":[[[[0,0],[0,1],[1,1],[1,0],[0,0]]]]}' +# sf_geojson(geojson_sf(js)) +# js <- '{ +# "type":"MultiLineString", +# "coordinates":[ +# [ +# [0,0],[0,1],[1,1],[1,0],[0,0] +# ], +# [ +# [2,2],[2,3],[3,3],[3,2],[2,2] +# ] +# ] +# }' +# +# sf_geojson(geojson_sf(js)) +# js <- '{ +# "type":"MultiPolygon", +# "coordinates":[ +# [ +# [ +# [0,0],[0,1],[1,1],[1,0],[0,0] +# ], +# [ +# [0.5,0.5],[0.5,0.75],[0.75,0.75],[0.75,0.5],[0.5,0.5] +# ] +# ], +# [ +# [ +# [2,2],[2,3],[3,3],[3,2],[2,2] +# ] +# ] +# ] +# }' +# +# sf_geojson(geojson_sf(js)) diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index f2c8ac5..04320af 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -102,6 +102,10 @@ void coord_separator(Rcpp::String& geojson, int i, int n) { } } +void object_separator(Rcpp::String& geojson, int i, int n) { + geojson += ","; +} + void line_separator_geojson(Rcpp::String& geojson, int i, int n) { if (i < (n - 1) ) { geojson += "],["; @@ -114,7 +118,10 @@ void polygon_separator_geojson(Rcpp::String& geojson, int i, int n) { } } -void add_lonlat_to_stream(Rcpp::String& geojson, Rcpp::NumericVector& points) { +void add_lonlat_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& points) { + + Rcpp::Rcout << "adding lonlat" << std::endl; + Rcpp::Rcout << points << std::endl; points.attr("dim") = Dimension(points.size() / 2, 2); Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); @@ -129,16 +136,77 @@ void add_lonlat_to_stream(Rcpp::String& geojson, Rcpp::NumericVector& points) { } } +void point_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& point) { + Rcpp::Rcout << "adding points" << std::endl; +// Rcpp::NumericVector points = as(sfg); +// Rcpp::Rcout << points << std::endl; + add_lonlat_to_geojson(geojson, point); +} + +void multi_point_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& points) { + + for (int i = 0; i < points.size(); i++) { + Rcpp::Rcout << "adding multipoint" << std::endl; + Rcpp::NumericVector point = points[i]; +// Rcpp::List sfgi = sfg[i]; + add_lonlat_to_geojson(geojson, point); + } +} + +void line_string_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& line) { + Rcpp::Rcout << "adding line string" << std::endl; + Rcpp::Rcout << line << std::endl; +// Rcpp::List line = as(sfg); +// add_lonlat_to_geojson(geojson, line); + add_lonlat_to_geojson(geojson, line); +} + +void multi_line_string_to_geojson(Rcpp::String& geojson, Rcpp::List& sfg) { + for (int i = 0; i < sfg.size(); i++) { + Rcpp::Rcout << "adding multi line" << std::endl; + Rcpp::NumericVector sfgi = sfg[i]; + add_lonlat_to_geojson(geojson, sfgi); + line_separator_geojson(geojson, i, sfg.size()); + } +} + +void polygon_to_geojson(Rcpp::String& geojson, Rcpp::List& sfg) { + for (int i = 0; i < sfg.size(); i++) { + Rcpp::Rcout << "adding polygon" << std::endl; + Rcpp::NumericVector sfgi = sfg[i]; + add_lonlat_to_geojson(geojson, sfgi); + line_separator_geojson(geojson, i, sfg.size()); + } +} + +void multi_polygon_to_geojson(Rcpp::String& geojson, Rcpp::List& sfg) { + for (int i = 0; i < sfg.size(); i++) { + Rcpp::Rcout << "adding multi polygon" << std::endl; + Rcpp::List sfgi = sfg[i]; + polygon_to_geojson(geojson, sfgi); + polygon_separator_geojson(geojson, i, sfg.size()); + } + +} + +// need to keep track of lines & polygons +// so we can correctly insert the inner braces ],[ void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_counter) { Rcpp::CharacterVector cls; std::string geom_type; + Rcpp::Rcout << "sfc size: " << sfc.size() << std::endl; + for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { - if (object_counter > 0) { - geojson += ","; - } + Rcpp::Rcout << "object counter " << object_counter << std::endl; + + //if (object_counter > 0) { + // geojson += ","; + //} + //line_separator_geojson(geojson, object_counter, sfc.size()); + switch( TYPEOF(*it) ) { case VECSXP: { Rcpp::List tmp = as(*it); @@ -153,6 +221,7 @@ void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_count // if no class attribute, go further into the list to try and find one fetch_coordinates(geojson, tmp, object_counter); } + //line_separator_geojson(geojson, object_counter, sfc.size()); object_counter++; break; } @@ -163,11 +232,12 @@ void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_count cls = getSfClass(tmp); geom_type = cls[1]; begin_geojson_geometry(geojson, geom_type); - add_lonlat_to_stream(geojson, tmp); + add_lonlat_to_geojson(geojson, tmp); end_geojson_geometry(geojson, geom_type); } else { - add_lonlat_to_stream(geojson, tmp); + add_lonlat_to_geojson(geojson, tmp); } + //line_separator_geojson(geojson, object_counter, sfc.size()); object_counter++; break; } @@ -185,7 +255,8 @@ Rcpp::String add_geometry_to_stream(Rcpp::List& sfg) { Rcpp::String geojson; int object_counter = 0; - fetch_coordinates(geojson, sfg, object_counter); + +// fetch_coordinates(geojson, sfg, object_counter); return geojson; } @@ -249,12 +320,55 @@ void vector_to_json(Rcpp::StringVector& sv, std::string& this_type, std::string& } } +void write_geojson(Rcpp::String& geojson, SEXP sfg, std::string& geom_type) { + + //geometry_json[i] = add_geometry_to_stream(sfg); + if (geom_type == "POINT") { + Rcpp::NumericVector point = as(sfg); + point_to_geojson(geojson, point); + } else if (geom_type == "MULTIPIONT") { + Rcpp::NumericVector multipoint = as(sfg); + multi_point_to_geojson(geojson, multipoint); + } else if (geom_type == "LINESTRING") { + Rcpp::NumericVector line = as(sfg); + line_string_to_geojson(geojson, line); + } else if (geom_type == "MULTILINESTRING") { + Rcpp::List multiline = as(sfg); + multi_line_string_to_geojson(geojson, multiline); + } else if (geom_type == "POLYGON") { + Rcpp::List polygon = as(sfg); + polygon_to_geojson(geojson, polygon); + } else if (geom_type == "MULTIPOLYGON") { + Rcpp::List multipolygon = as(sfg); + multi_polygon_to_geojson(geojson, multipolygon); + } else if (geom_type == "GEOMETRYCOLLEcTION") { + + } +} + +void write_geometry(Rcpp::String& geojson, std::string& geom_type) { + begin_geojson_geometry(geojson, geom_type); + +} + void geometry_vector_to_geojson(Rcpp::StringVector& geometry_json, Rcpp::List& sfc) { - Rcpp::List sfg(1); + + Rcpp::List sfg; + Rcpp::String geojson; for (int i = 0; i < sfc.size(); i++) { - sfg[0] = sfc[i]; - geometry_json[i] = add_geometry_to_stream(sfg); + sfg = sfc[i]; + Rcpp::CharacterVector cls = getSfClass(sfg); + Rcpp::Rcout << "cls : " << cls << std::endl; + Rcpp::String g = cls[1]; + std::string geom_type = g; + begin_geojson_geometry(geojson, geom_type); + + write_geojson(geojson, sfg, geom_type); + + end_geojson_geometry(geojson, geom_type); + geometry_json[i] = geojson; } + } Rcpp::String matrix_row_to_json(Rcpp::StringMatrix& json_mat, int i) { From 787e5450cbab65e5282de6d34057f919788512ae Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sat, 21 Apr 2018 20:10:36 +1000 Subject: [PATCH 19/21] geojson --- inst/include/sf_geojson.h | 4 ++ src/sf_geojson.cpp | 89 +++++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/inst/include/sf_geojson.h b/inst/include/sf_geojson.h index cb3bc9b..2f7829a 100644 --- a/inst/include/sf_geojson.h +++ b/inst/include/sf_geojson.h @@ -23,4 +23,8 @@ void line_separator_geojson(Rcpp::String& geojson, int i, int n); void polygon_separator_geojson(Rcpp::String& geojson, int i, int n); +void write_geometry(Rcpp::List& sfg, Rcpp::String& geojson); + +void make_gc_type(Rcpp::String& geojson, Rcpp::List& sfg, std::string& geom_type, Rcpp::CharacterVector& cls); + #endif diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index 04320af..d816760 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -186,7 +186,6 @@ void multi_polygon_to_geojson(Rcpp::String& geojson, Rcpp::List& sfg) { polygon_to_geojson(geojson, sfgi); polygon_separator_geojson(geojson, i, sfg.size()); } - } // need to keep track of lines & polygons @@ -320,35 +319,100 @@ void vector_to_json(Rcpp::StringVector& sv, std::string& this_type, std::string& } } -void write_geojson(Rcpp::String& geojson, SEXP sfg, std::string& geom_type) { +void write_geojson(Rcpp::String& geojson, SEXP sfg, std::string& geom_type, Rcpp::CharacterVector& cls) { //geometry_json[i] = add_geometry_to_stream(sfg); if (geom_type == "POINT") { + Rcpp::NumericVector point = as(sfg); point_to_geojson(geojson, point); } else if (geom_type == "MULTIPIONT") { + Rcpp::NumericVector multipoint = as(sfg); multi_point_to_geojson(geojson, multipoint); } else if (geom_type == "LINESTRING") { + Rcpp::NumericVector line = as(sfg); line_string_to_geojson(geojson, line); } else if (geom_type == "MULTILINESTRING") { + Rcpp::List multiline = as(sfg); multi_line_string_to_geojson(geojson, multiline); } else if (geom_type == "POLYGON") { + Rcpp::List polygon = as(sfg); polygon_to_geojson(geojson, polygon); } else if (geom_type == "MULTIPOLYGON") { + Rcpp::List multipolygon = as(sfg); multi_polygon_to_geojson(geojson, multipolygon); - } else if (geom_type == "GEOMETRYCOLLEcTION") { + } else if (geom_type == "GEOMETRYCOLLECTION") { + Rcpp::List gc = as(sfg); + for (int i = 0; i < gc.size(); i++) { + Rcpp::Rcout << "gc" << std::endl; + Rcpp::List sfgi = gc[i]; + + make_gc_type(geojson, gc, geom_type, cls); + //write_geometry(sfgi, geojson); + //write_geojson(geojson, sfgi, geom_type, cls); + } + } +} + +void make_gc_type(Rcpp::String& geojson, Rcpp::List& sfg, std::string& geom_type, Rcpp::CharacterVector& cls) { + + for (Rcpp::List::iterator it = sfg.begin(); it != sfg.end(); it++) { + Rcpp::Rcout << "finding type" << std::endl; + switch( TYPEOF(*it) ) { + case VECSXP: { + Rcpp::List tmp = as(*it); + if (!Rf_isNull(tmp.attr("class"))) { + Rcpp::Rcout << "found type (list) " << std::endl; + cls = tmp.attr("class"); + Rcpp::Rcout << cls << std::endl; + geom_type = cls[1]; // TODO: error handle (there should aways be 3 elements as we're workgin wtih sfg objects)\ + write_geojson(geojson, tmp, geom_type, cls); + } else { + make_gc_type(geojson, tmp, geom_type, cls); + } + break; + } + case REALSXP: { + Rcpp::NumericVector tmp = as(*it); + if (!Rf_isNull(tmp.attr("class"))) { + Rcpp::Rcout << "found type (num vec) " << std::endl; + cls = tmp.attr("class"); + Rcpp::Rcout << "type: " << cls << std::endl; + geom_type = cls[1]; + write_geojson(geojson, tmp, geom_type, cls); + } + break; + } + case INTSXP: { + break; + } + default: { + Rcpp::stop("Coordinates could not be found"); + } + } } } -void write_geometry(Rcpp::String& geojson, std::string& geom_type) { +void write_geometry(Rcpp::List& sfg, Rcpp::String& geojson) { + Rcpp::Rcout << "write_geometry" << std::endl; + Rcpp::CharacterVector cls = getSfClass(sfg); + //Rcpp::CharacterVector cls; + //std::string geom_type; + + Rcpp::Rcout << "cls : " << cls << std::endl; + Rcpp::String g = cls[1]; + std::string geom_type = g; begin_geojson_geometry(geojson, geom_type); + write_geojson(geojson, sfg, geom_type, cls); + + end_geojson_geometry(geojson, geom_type); } void geometry_vector_to_geojson(Rcpp::StringVector& geometry_json, Rcpp::List& sfc) { @@ -357,15 +421,14 @@ void geometry_vector_to_geojson(Rcpp::StringVector& geometry_json, Rcpp::List& s Rcpp::String geojson; for (int i = 0; i < sfc.size(); i++) { sfg = sfc[i]; - Rcpp::CharacterVector cls = getSfClass(sfg); - Rcpp::Rcout << "cls : " << cls << std::endl; - Rcpp::String g = cls[1]; - std::string geom_type = g; - begin_geojson_geometry(geojson, geom_type); - - write_geojson(geojson, sfg, geom_type); - - end_geojson_geometry(geojson, geom_type); + //Rcpp::CharacterVector cls = getSfClass(sfg); + //Rcpp::Rcout << "cls : " << cls << std::endl; + //Rcpp::String g = cls[1]; + //std::string geom_type = g; + //begin_geojson_geometry(geojson, geom_type); + //write_geojson(geojson, sfg, geom_type); + //end_geojson_geometry(geojson, geom_type); + write_geometry(sfg, geojson); geometry_json[i] = geojson; } From c4fe7eb21ebcb4394e680a18b0a7a5b675f5e979 Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sun, 22 Apr 2018 13:01:00 +1000 Subject: [PATCH 20/21] sf to vector of geojson --- src/sf_geojson.cpp | 450 +++++++++++++++++---------------------------- 1 file changed, 168 insertions(+), 282 deletions(-) diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index d816760..9218557 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -60,196 +60,116 @@ void begin_geojson_geometry(Rcpp::String& geojson, std::string& geom_type) { void begin_geojson_geometry(Rcpp::String& geojson, Rcpp::List& sfc, std::string& geom_type) { - geojson += "{\"type\":"; - if (geom_type == "POINT") { - geojson += "\"Point\",\"coordinates\":"; - } else if (geom_type == "MULTIPOINT") { - geojson += "\"MultiPoint\",\"coordinates\":["; - } else if (geom_type == "LINESTRING") { - geojson += "\"LineString\",\"coordinates\":["; - } else if (geom_type == "MULTILINESTRING") { - geojson += "\"MultiLineString\",\"coordinates\":[["; - } else if (geom_type == "POLYGON") { + geojson += "{\"type\":"; + if (geom_type == "POINT") { + geojson += "\"Point\",\"coordinates\":"; + } else if (geom_type == "MULTIPOINT") { + geojson += "\"MultiPoint\",\"coordinates\":["; + } else if (geom_type == "LINESTRING") { + geojson += "\"LineString\",\"coordinates\":["; + } else if (geom_type == "MULTILINESTRING") { + geojson += "\"MultiLineString\",\"coordinates\":[["; + } else if (geom_type == "POLYGON") { geojson += "\"Polygon\",\"coordinates\":[["; - } else if (geom_type == "MULTIPOLYGON") { - geojson += "\"MultiPolygon\",\"coordinates\":[[["; - } else if (geom_type == "GEOMETRYCOLLECTION") { - geojson += "\"GeometryCollection\",\"geometries\":["; - } + } else if (geom_type == "MULTIPOLYGON") { + geojson += "\"MultiPolygon\",\"coordinates\":[[["; + } else if (geom_type == "GEOMETRYCOLLECTION") { + geojson += "\"GeometryCollection\",\"geometries\":["; + } } void end_geojson_geometry(Rcpp::String& geojson, std::string& geom_type) { - if (geom_type == "POINT") { - geojson += "}"; - } else if (geom_type == "MULTIPOINT") { - geojson += "]}"; - } else if (geom_type == "LINESTRING") { - geojson += "]}"; - } else if (geom_type == "MULTILINESTRING") { - geojson += "]]}"; - } else if (geom_type == "POLYGON") { - geojson += "]]}"; - } else if (geom_type == "MULTIPOLYGON") { - geojson += "]]]}"; - } else if (geom_type == "GEOMETRYCOLLECTION") { - geojson += "]}"; - } + if (geom_type == "POINT") { + geojson += "}"; + } else if (geom_type == "MULTIPOINT") { + geojson += "]}"; + } else if (geom_type == "LINESTRING") { + geojson += "]}"; + } else if (geom_type == "MULTILINESTRING") { + geojson += "]]}"; + } else if (geom_type == "POLYGON") { + geojson += "]]}"; + } else if (geom_type == "MULTIPOLYGON") { + geojson += "]]]}"; + } else if (geom_type == "GEOMETRYCOLLECTION") { + geojson += "]}"; + } } void coord_separator(Rcpp::String& geojson, int i, int n) { - if (i < (n - 1) ) { - geojson += ","; - } + if (i < (n - 1) ) { + geojson += ","; + } } void object_separator(Rcpp::String& geojson, int i, int n) { - geojson += ","; + geojson += ","; } void line_separator_geojson(Rcpp::String& geojson, int i, int n) { - if (i < (n - 1) ) { - geojson += "],["; - } + if (i < (n - 1) ) { + geojson += "],["; + } } void polygon_separator_geojson(Rcpp::String& geojson, int i, int n) { - if (i < (n - 1) ) { - geojson += "]],[["; - } + if (i < (n - 1) ) { + geojson += "]],[["; + } } void add_lonlat_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& points) { - Rcpp::Rcout << "adding lonlat" << std::endl; - Rcpp::Rcout << points << std::endl; - - points.attr("dim") = Dimension(points.size() / 2, 2); - Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); + points.attr("dim") = Dimension(points.size() / 2, 2); + Rcpp::NumericMatrix m = as< Rcpp::NumericMatrix >(points); - for (int i = 0; i < m.nrow(); i++) { - geojson += "["; - geojson += m(i,0); - geojson += ","; - geojson += m(i,1); - geojson += "]"; - coord_separator(geojson, i, m.nrow()); - } + for (int i = 0; i < m.nrow(); i++) { + geojson += "["; + geojson += m(i,0); + geojson += ","; + geojson += m(i,1); + geojson += "]"; + coord_separator(geojson, i, m.nrow()); + } } void point_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& point) { - Rcpp::Rcout << "adding points" << std::endl; -// Rcpp::NumericVector points = as(sfg); -// Rcpp::Rcout << points << std::endl; - add_lonlat_to_geojson(geojson, point); + add_lonlat_to_geojson(geojson, point); } void multi_point_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& points) { - - for (int i = 0; i < points.size(); i++) { - Rcpp::Rcout << "adding multipoint" << std::endl; - Rcpp::NumericVector point = points[i]; -// Rcpp::List sfgi = sfg[i]; - add_lonlat_to_geojson(geojson, point); - } + add_lonlat_to_geojson(geojson, points); } void line_string_to_geojson(Rcpp::String& geojson, Rcpp::NumericVector& line) { - Rcpp::Rcout << "adding line string" << std::endl; - Rcpp::Rcout << line << std::endl; -// Rcpp::List line = as(sfg); -// add_lonlat_to_geojson(geojson, line); add_lonlat_to_geojson(geojson, line); } void multi_line_string_to_geojson(Rcpp::String& geojson, Rcpp::List& sfg) { - for (int i = 0; i < sfg.size(); i++) { - Rcpp::Rcout << "adding multi line" << std::endl; - Rcpp::NumericVector sfgi = sfg[i]; - add_lonlat_to_geojson(geojson, sfgi); - line_separator_geojson(geojson, i, sfg.size()); - } + for (int i = 0; i < sfg.size(); i++) { + Rcpp::NumericVector sfgi = sfg[i]; + add_lonlat_to_geojson(geojson, sfgi); + line_separator_geojson(geojson, i, sfg.size()); + } } void polygon_to_geojson(Rcpp::String& geojson, Rcpp::List& sfg) { - for (int i = 0; i < sfg.size(); i++) { - Rcpp::Rcout << "adding polygon" << std::endl; - Rcpp::NumericVector sfgi = sfg[i]; - add_lonlat_to_geojson(geojson, sfgi); - line_separator_geojson(geojson, i, sfg.size()); - } + for (int i = 0; i < sfg.size(); i++) { + Rcpp::NumericVector sfgi = sfg[i]; + add_lonlat_to_geojson(geojson, sfgi); + line_separator_geojson(geojson, i, sfg.size()); + } } void multi_polygon_to_geojson(Rcpp::String& geojson, Rcpp::List& sfg) { - for (int i = 0; i < sfg.size(); i++) { - Rcpp::Rcout << "adding multi polygon" << std::endl; - Rcpp::List sfgi = sfg[i]; - polygon_to_geojson(geojson, sfgi); - polygon_separator_geojson(geojson, i, sfg.size()); - } -} - -// need to keep track of lines & polygons -// so we can correctly insert the inner braces ],[ -void fetch_coordinates(Rcpp::String& geojson, Rcpp::List& sfc, int& object_counter) { - - Rcpp::CharacterVector cls; - std::string geom_type; - - Rcpp::Rcout << "sfc size: " << sfc.size() << std::endl; - - for (Rcpp::List::iterator it = sfc.begin(); it != sfc.end(); it++) { - - Rcpp::Rcout << "object counter " << object_counter << std::endl; - - //if (object_counter > 0) { - // geojson += ","; - //} - //line_separator_geojson(geojson, object_counter, sfc.size()); - - switch( TYPEOF(*it) ) { - case VECSXP: { - Rcpp::List tmp = as(*it); - if(!Rf_isNull(tmp.attr("class"))) { - - cls = getSfClass(tmp); - geom_type = cls[1]; // TODO: error handle (there should aways be 3 elements as we're workgin wtih sfg objects) - begin_geojson_geometry(geojson, tmp, geom_type); - fetch_coordinates(geojson, tmp, object_counter); - end_geojson_geometry(geojson, geom_type); - } else { - // if no class attribute, go further into the list to try and find one - fetch_coordinates(geojson, tmp, object_counter); - } - //line_separator_geojson(geojson, object_counter, sfc.size()); - object_counter++; - break; - } - case REALSXP: { - Rcpp::NumericVector tmp = as(*it); - if(!Rf_isNull(tmp.attr("class"))) { - - cls = getSfClass(tmp); - geom_type = cls[1]; - begin_geojson_geometry(geojson, geom_type); - add_lonlat_to_geojson(geojson, tmp); - end_geojson_geometry(geojson, geom_type); - } else { - add_lonlat_to_geojson(geojson, tmp); - } - //line_separator_geojson(geojson, object_counter, sfc.size()); - object_counter++; - break; - } - case INTSXP: { - break; - } - default: { - Rcpp::stop("Coordinates could not be found"); - } - } - } + for (int i = 0; i < sfg.size(); i++) { + Rcpp::List sfgi = sfg[i]; + polygon_to_geojson(geojson, sfgi); + polygon_separator_geojson(geojson, i, sfg.size()); + } } +/* Rcpp::String add_geometry_to_stream(Rcpp::List& sfg) { Rcpp::String geojson; @@ -259,11 +179,12 @@ Rcpp::String add_geometry_to_stream(Rcpp::List& sfg) { return geojson; } +*/ // if only one object with properties, it's a 'feature' // if only one object without properties, it's a 'geometry' // if many objects it's a 'featurecollection' - +/* rapidjson::Value get_json_value(SEXP s, rapidjson::Document::AllocatorType& allocator) { // TODO: // switch on R type and return the rapidjson equivalent @@ -284,7 +205,7 @@ rapidjson::Value get_json_value(SEXP s, rapidjson::Document::AllocatorType& allo } return v1; } - +*/ void vector_to_json(Rcpp::StringVector& sv, std::string& this_type, std::string& this_name) { std::string this_value; @@ -319,139 +240,121 @@ void vector_to_json(Rcpp::StringVector& sv, std::string& this_type, std::string& } } -void write_geojson(Rcpp::String& geojson, SEXP sfg, std::string& geom_type, Rcpp::CharacterVector& cls) { +void write_geojson(Rcpp::String& geojson, SEXP sfg, + std::string& geom_type, Rcpp::CharacterVector& cls) { //geometry_json[i] = add_geometry_to_stream(sfg); - if (geom_type == "POINT") { - - Rcpp::NumericVector point = as(sfg); - point_to_geojson(geojson, point); - } else if (geom_type == "MULTIPIONT") { - - Rcpp::NumericVector multipoint = as(sfg); - multi_point_to_geojson(geojson, multipoint); - } else if (geom_type == "LINESTRING") { - - Rcpp::NumericVector line = as(sfg); - line_string_to_geojson(geojson, line); - } else if (geom_type == "MULTILINESTRING") { - - Rcpp::List multiline = as(sfg); - multi_line_string_to_geojson(geojson, multiline); - } else if (geom_type == "POLYGON") { - - Rcpp::List polygon = as(sfg); - polygon_to_geojson(geojson, polygon); - } else if (geom_type == "MULTIPOLYGON") { - - Rcpp::List multipolygon = as(sfg); - multi_polygon_to_geojson(geojson, multipolygon); - } else if (geom_type == "GEOMETRYCOLLECTION") { - - Rcpp::List gc = as(sfg); - for (int i = 0; i < gc.size(); i++) { - Rcpp::Rcout << "gc" << std::endl; - Rcpp::List sfgi = gc[i]; - - make_gc_type(geojson, gc, geom_type, cls); - //write_geometry(sfgi, geojson); - //write_geojson(geojson, sfgi, geom_type, cls); - } - } + if (geom_type == "POINT") { + + Rcpp::NumericVector point = as(sfg); + point_to_geojson(geojson, point); + } else if (geom_type == "MULTIPOINT") { + + Rcpp::NumericVector multipoint = as(sfg); + multi_point_to_geojson(geojson, multipoint); + } else if (geom_type == "LINESTRING") { + + Rcpp::NumericVector line = as(sfg); + line_string_to_geojson(geojson, line); + } else if (geom_type == "MULTILINESTRING") { + + Rcpp::List multiline = as(sfg); + multi_line_string_to_geojson(geojson, multiline); + } else if (geom_type == "POLYGON") { + + Rcpp::List polygon = as(sfg); + polygon_to_geojson(geojson, polygon); + } else if (geom_type == "MULTIPOLYGON") { + + Rcpp::List multipolygon = as(sfg); + multi_polygon_to_geojson(geojson, multipolygon); + } else if (geom_type == "GEOMETRYCOLLECTION") { + + Rcpp::List gc = as(sfg); + Rcpp::List sfgi(1); + for (int i = 0; i < gc.size(); i++) { + sfgi[0] = gc[i]; + make_gc_type(geojson, sfgi, geom_type, cls); + coord_separator(geojson, i, gc.size()); + } + } } -void make_gc_type(Rcpp::String& geojson, Rcpp::List& sfg, std::string& geom_type, Rcpp::CharacterVector& cls) { - - for (Rcpp::List::iterator it = sfg.begin(); it != sfg.end(); it++) { - Rcpp::Rcout << "finding type" << std::endl; - switch( TYPEOF(*it) ) { - case VECSXP: { - Rcpp::List tmp = as(*it); - if (!Rf_isNull(tmp.attr("class"))) { - Rcpp::Rcout << "found type (list) " << std::endl; - cls = tmp.attr("class"); - Rcpp::Rcout << cls << std::endl; - geom_type = cls[1]; // TODO: error handle (there should aways be 3 elements as we're workgin wtih sfg objects)\ - write_geojson(geojson, tmp, geom_type, cls); - } else { - make_gc_type(geojson, tmp, geom_type, cls); - } - break; - } - case REALSXP: { - Rcpp::NumericVector tmp = as(*it); - if (!Rf_isNull(tmp.attr("class"))) { - Rcpp::Rcout << "found type (num vec) " << std::endl; - cls = tmp.attr("class"); - Rcpp::Rcout << "type: " << cls << std::endl; - geom_type = cls[1]; - write_geojson(geojson, tmp, geom_type, cls); - } - break; - } - case INTSXP: { - break; - } - default: { - Rcpp::stop("Coordinates could not be found"); - } - } - } +void make_gc_type(Rcpp::String& geojson, Rcpp::List& sfg, + std::string& geom_type, Rcpp::CharacterVector& cls) { + + for (Rcpp::List::iterator it = sfg.begin(); it != sfg.end(); it++) { + + switch( TYPEOF(*it) ) { + case VECSXP: { + Rcpp::List tmp = as(*it); + if (!Rf_isNull(tmp.attr("class"))) { + + cls = tmp.attr("class"); + geom_type = cls[1]; // TODO: error handle (there should aways be 3 elements as we're workgin wtih sfg objects)\ + begin_geojson_geometry(geojson, geom_type); + write_geojson(geojson, tmp, geom_type, cls); + end_geojson_geometry(geojson, geom_type); + } else { + make_gc_type(geojson, tmp, geom_type, cls); + } + break; + } + case REALSXP: { + Rcpp::NumericVector tmp = as(*it); + if (!Rf_isNull(tmp.attr("class"))) { + + cls = tmp.attr("class"); + geom_type = cls[1]; + begin_geojson_geometry(geojson, geom_type); + write_geojson(geojson, tmp, geom_type, cls); + end_geojson_geometry(geojson, geom_type); + } + break; + } + default: { + Rcpp::stop("Coordinates could not be found"); + } + } + } } void write_geometry(Rcpp::List& sfg, Rcpp::String& geojson) { - Rcpp::Rcout << "write_geometry" << std::endl; - Rcpp::CharacterVector cls = getSfClass(sfg); - //Rcpp::CharacterVector cls; - //std::string geom_type; - - Rcpp::Rcout << "cls : " << cls << std::endl; - Rcpp::String g = cls[1]; - std::string geom_type = g; - begin_geojson_geometry(geojson, geom_type); - - write_geojson(geojson, sfg, geom_type, cls); - end_geojson_geometry(geojson, geom_type); + Rcpp::CharacterVector cls = getSfClass(sfg); + Rcpp::String g = cls[1]; + std::string geom_type = g; + begin_geojson_geometry(geojson, geom_type); + write_geojson(geojson, sfg, geom_type, cls); + end_geojson_geometry(geojson, geom_type); } void geometry_vector_to_geojson(Rcpp::StringVector& geometry_json, Rcpp::List& sfc) { - Rcpp::List sfg; - Rcpp::String geojson; + Rcpp::List sfg; for (int i = 0; i < sfc.size(); i++) { - sfg = sfc[i]; - //Rcpp::CharacterVector cls = getSfClass(sfg); - //Rcpp::Rcout << "cls : " << cls << std::endl; - //Rcpp::String g = cls[1]; - //std::string geom_type = g; - //begin_geojson_geometry(geojson, geom_type); - //write_geojson(geojson, sfg, geom_type); - //end_geojson_geometry(geojson, geom_type); - write_geometry(sfg, geojson); - geometry_json[i] = geojson; + Rcpp::String geojson; + sfg = sfc[i]; + write_geometry(sfg, geojson); + geometry_json[i] = geojson; } - } Rcpp::String matrix_row_to_json(Rcpp::StringMatrix& json_mat, int i) { - std::ostringstream os; - int n = json_mat.ncol(); - os << "{\"type\":\"Feature\",\"properties\":{"; - for (int j = 0; j < (n-1); j++) { - os << json_mat(i, j); - coord_separator(os, j, (n-1)); - } - os << "},"; - - os << "\"geometry\":"; - //s = json_mat(i, (n-1)); - //st = s; - os << json_mat(i, (n-1)); - os << "}"; + std::ostringstream os; + int n = json_mat.ncol(); + os << "{\"type\":\"Feature\",\"properties\":{"; + for (int j = 0; j < (n-1); j++) { + os << json_mat(i, j); + coord_separator(os, j, (n-1)); + } + os << "},"; + os << "\"geometry\":"; + os << json_mat(i, (n-1)); + os << "}"; - Rcpp::String res = os.str(); - return res; + Rcpp::String res = os.str(); + return res; } // [[Rcpp::export]] @@ -520,20 +423,3 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { return res; } - - -/// DESIGN: -/// should work for both properties & non-property sf -// result vector res(nrow(sf)); -// property_columns(); -// property_column_types(); -// for (i = 0; i < nrow(sf); i++) { -// for (j = 0; j < ncol(properties); j++){ -// stream each column into "properties": { } -// } -// if (ncol(properties) > 0) { -// needs to be a {"type":"Feature", ...} -// then create "geometry":{"type" :"geom","coordinates":[]} -// } -// result will be a vector of JSON. -// can combine or keep 'atomic'. From 756536814e0d728acd6bbd0fd2822460ecc5634f Mon Sep 17 00:00:00 2001 From: symbolixau Date: Sun, 22 Apr 2018 13:17:03 +1000 Subject: [PATCH 21/21] atomise --- R/RcppExports.R | 4 ++-- R/geojson_sf.R | 15 ++++++++++----- R/scratch.R | 2 +- man/sf_geojson.Rd | 9 +++++++-- src/RcppExports.cpp | 9 +++++---- src/sf_geojson.cpp | 39 ++++++++++++++++++++++++--------------- 6 files changed, 49 insertions(+), 29 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index 0dbccb0..ddc4885 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -21,7 +21,7 @@ rcpp_read_sf_file <- function(file) { .Call(`_geojsonsf_rcpp_read_sf_file`, file) } -rcpp_sf_to_geojson <- function(sf) { - .Call(`_geojsonsf_rcpp_sf_to_geojson`, sf) +rcpp_sf_to_geojson <- function(sf, atomise) { + .Call(`_geojsonsf_rcpp_sf_to_geojson`, sf, atomise) } diff --git a/R/geojson_sf.R b/R/geojson_sf.R index 12fbc80..39aadee 100644 --- a/R/geojson_sf.R +++ b/R/geojson_sf.R @@ -96,19 +96,24 @@ geojson_sf.default <- function(geojson) rcpp_geojson_to_sf(geojson) #' sf to GeoJSON #' +#' Converts `sf`, `sfc` and `sfg` objects to GeoJSON +#' +#' @param sf simple feature object +#' @param atomise logical +#' #' @export -sf_geojson <- function(sf) UseMethod("sf_geojson") +sf_geojson <- function(sf, atomise = FALSE) UseMethod("sf_geojson") #' @export -sf_geojson.sf <- function(sf) rcpp_sf_to_geojson(sf) +sf_geojson.sf <- function(sf, atomise) rcpp_sf_to_geojson(sf, atomise) #' @export -sf_geojson.sfc <- function(sf) rcpp_sfc_to_geojson(sf) +sf_geojson.sfc <- function(sf, atomise) rcpp_sf_to_geojson(sf, atomise) #' @export -sf_geojson.sfg <- function(sf) rcpp_sfg_to_geojson(sf) +sf_geojson.sfg <- function(sf, atomise) rcpp_sf_to_geojson(sf, atomise) -sf_geojson.default <- function(sf) stop("Expected an sf object") +sf_geojson.default <- function(sf, atomise) stop("Expected an sf object") diff --git a/R/scratch.R b/R/scratch.R index 8785238..d1b79bb 100644 --- a/R/scratch.R +++ b/R/scratch.R @@ -124,6 +124,6 @@ # ] # }' # -# sf_geojson(geojson_sf(js)) +# sf_geojson(geojson_sf(js), TRUE) diff --git a/man/sf_geojson.Rd b/man/sf_geojson.Rd index 984098a..778e1c4 100644 --- a/man/sf_geojson.Rd +++ b/man/sf_geojson.Rd @@ -4,8 +4,13 @@ \alias{sf_geojson} \title{sf to GeoJSON} \usage{ -sf_geojson(sf) +sf_geojson(sf, atomise = FALSE) +} +\arguments{ +\item{sf}{simple feature object} + +\item{atomise}{logical} } \description{ -sf to GeoJSON +Converts `sf`, `sfc` and `sfg` objects to GeoJSON } diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 48a9cb3..463ef02 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -62,13 +62,14 @@ BEGIN_RCPP END_RCPP } // rcpp_sf_to_geojson -Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf); -RcppExport SEXP _geojsonsf_rcpp_sf_to_geojson(SEXP sfSEXP) { +Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf, bool atomise); +RcppExport SEXP _geojsonsf_rcpp_sf_to_geojson(SEXP sfSEXP, SEXP atomiseSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< Rcpp::List >::type sf(sfSEXP); - rcpp_result_gen = Rcpp::wrap(rcpp_sf_to_geojson(sf)); + Rcpp::traits::input_parameter< bool >::type atomise(atomiseSEXP); + rcpp_result_gen = Rcpp::wrap(rcpp_sf_to_geojson(sf, atomise)); return rcpp_result_gen; END_RCPP } @@ -79,7 +80,7 @@ static const R_CallMethodDef CallEntries[] = { {"_geojsonsf_rcpp_geojson_to_wkt", (DL_FUNC) &_geojsonsf_rcpp_geojson_to_wkt, 1}, {"_geojsonsf_rcpp_read_sfc_file", (DL_FUNC) &_geojsonsf_rcpp_read_sfc_file, 1}, {"_geojsonsf_rcpp_read_sf_file", (DL_FUNC) &_geojsonsf_rcpp_read_sf_file, 1}, - {"_geojsonsf_rcpp_sf_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sf_to_geojson, 1}, + {"_geojsonsf_rcpp_sf_to_geojson", (DL_FUNC) &_geojsonsf_rcpp_sf_to_geojson, 2}, {NULL, NULL, 0} }; diff --git a/src/sf_geojson.cpp b/src/sf_geojson.cpp index 9218557..648816e 100644 --- a/src/sf_geojson.cpp +++ b/src/sf_geojson.cpp @@ -342,13 +342,16 @@ void geometry_vector_to_geojson(Rcpp::StringVector& geometry_json, Rcpp::List& s Rcpp::String matrix_row_to_json(Rcpp::StringMatrix& json_mat, int i) { std::ostringstream os; + os << "{"; int n = json_mat.ncol(); - os << "{\"type\":\"Feature\",\"properties\":{"; - for (int j = 0; j < (n-1); j++) { - os << json_mat(i, j); - coord_separator(os, j, (n-1)); - } - os << "},"; + //if (n > 1) { + os << "\"type\":\"Feature\",\"properties\":{"; + for (int j = 0; j < (n-1); j++) { + os << json_mat(i, j); + coord_separator(os, j, (n-1)); + } + os << "},"; + //} os << "\"geometry\":"; os << json_mat(i, (n-1)); os << "}"; @@ -358,7 +361,7 @@ Rcpp::String matrix_row_to_json(Rcpp::StringMatrix& json_mat, int i) { } // [[Rcpp::export]] -Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { +Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf, bool atomise) { //std::ostringstream os; Rcpp::List sf_copy = clone(sf); @@ -368,7 +371,6 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { // if 'atomise', return one object per row Rcpp::StringVector column_types(sf_copy.size() - 1); - //get_column_type(sf, column_types); Rcpp::StringVector property_names(sf_copy.size() - 1); std::string geom_column = sf_copy.attr("sf_column"); @@ -402,11 +404,8 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { this_name = property_names[i]; this_type = column_types[i]; this_vector = as< Rcpp::StringVector >(sf_copy[this_name]); - vector_to_json(this_vector, this_type, this_name); - //this_vector = "{\"properties\":{" + this_vector + "}"; json_mat(_, i) = this_vector; - // TODO: what if there's a mssing element? } @@ -417,9 +416,19 @@ Rcpp::StringVector rcpp_sf_to_geojson(Rcpp::List sf) { Rcpp::StringVector res(json_mat.nrow()); // If properties, do this bit. else return a vector (column of matrix) - for (int i = 0; i < res.length(); i++) { - res[i] = matrix_row_to_json(json_mat, i); - } + if (json_mat.ncol() > 1) { + for (int i = 0; i < res.length(); i++) { + res[i] = matrix_row_to_json(json_mat, i); + } + } else { + res = json_mat(_, 0); + } + + if(atomise) { + return res; + } + + // TODO: convert to FeatureCollection + return res; - return res; }