Skip to content

Commit

Permalink
Merge pull request #12 from SymbolixAU/null
Browse files Browse the repository at this point in the history
Null
  • Loading branch information
SymbolixAU authored Apr 23, 2018
2 parents c64fd9b + 765751e commit 0c120ed
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 35 deletions.
14 changes: 5 additions & 9 deletions R/scratch.R
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@


## TODO:
## work on sfc objects
# sf <- sf::st_sfc(list(sf::st_point(c(0,0)), sf::st_point(c(1,1))))
# attributes(sf)
# sfc_geojson(sf)

## an sfc object doesn't have properties.
## and it doesn't have an 'sf_column' attribute

#
# url <- "https://data.seattle.gov/resource/pdbw-sw7q.geojson"
# sf <- sf::st_read(url, quiet = T)
# sf2 <- geojson_sf(url)


# sf <- sf::st_sf(geometry = sf::st_sfc(list(sf::st_point(c(0,0)), sf::st_point(c(1,1)))))
# attributes(sf)
# sf_geojson(sf, TRUE)
5 changes: 5 additions & 0 deletions src/geojson_sfc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,12 @@ void fetch_geometries(Rcpp::List& sf, Rcpp::List& res, int& sfg_counter) {
break;
}
default: {
Rcpp::Rcout << "debug: default geometry" << std::endl;
//Rcpp::List tmp;
//tmp.attr("class") = Rcpp::CharacterVector::create("XY","POLYGON","sfg");
Rcpp::stop("Geometry could not be determined");
//res[sfg_counter] = tmp;
//sfg_counter++;
}
}
}
Expand Down
76 changes: 50 additions & 26 deletions src/geojson_to_sf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ Rcpp::List parse_geometry_collection_object(const Value& val,
return geom_collection;
}


Rcpp::List parse_feature_object(const Value& feature,
Rcpp::NumericVector& bbox,
std::set< std::string >& geometry_types,
Expand All @@ -98,38 +97,63 @@ Rcpp::List parse_feature_object(const Value& feature,
Document& doc_properties,
std::map< std::string, std::string>& property_types) {

validate_geometry(feature, sfg_objects);
validate_properties(feature, sfg_objects);

const Value& geometry = feature["geometry"];
validate_type(geometry, sfg_objects);
std::string type = geometry["type"].GetString();
Rcpp::List sfc(1);

if (type == "GeometryCollection") {
sfc[0] = parse_geometry_collection_object(geometry, bbox, geometry_types, sfg_objects);
} else {
parse_geometry_object(sfc, 0, geometry, bbox, geometry_types, sfg_objects);
}
validate_geometry(feature, sfg_objects);
validate_properties(feature, sfg_objects);

const Value& geometry = feature["geometry"];
//validate_type(geometry, sfg_objects);
//std::string type = geometry["type"].GetString();
Rcpp::List sfc(1);

if (geometry.Size() > 0) {

validate_type(geometry, sfg_objects);
std::string type = geometry["type"].GetString();

if (type == "GeometryCollection") {
sfc[0] = parse_geometry_collection_object(geometry, bbox, geometry_types, sfg_objects);
} else {
parse_geometry_object(sfc, 0, geometry, bbox, geometry_types, sfg_objects);
}
} else {
// TODO:
// insert the geometry as per teh rules followed by 'sf'
//
// needs to be a null geometry
Rcpp::List nullObj;
/*
std::string temp_geom;
if (geometry_types.empty()) {
temp_geom = "POINT";
} else {
temp_geom = *geometry_types.rbegin();
transform(temp_geom.begin(), temp_geom.end(), temp_geom.begin(), ::toupper);
}
*/
//Rcpp::Rcout << "debug: temp_geom: " << temp_geom << std::endl;

nullObj.attr("class") = sfg_attributes("POLYGON");
sfc[0] = nullObj;
geometry_types.insert("POLYGON");
}

sfg_objects++;
sfg_objects++;

const Value& p = feature["properties"];
get_property_keys(p, property_keys);
get_property_types(p, property_types);
const Value& p = feature["properties"];
get_property_keys(p, property_keys);
get_property_types(p, property_types);

//https://stackoverflow.com/a/33473321/5977215
std::string s = std::to_string(sfg_objects);
Value n(s.c_str(), doc_properties.GetAllocator());
//https://stackoverflow.com/a/33473321/5977215
std::string s = std::to_string(sfg_objects);
Value n(s.c_str(), doc_properties.GetAllocator());

// TODO: is this method deep-cloning?
Value properties(feature["properties"], doc_properties.GetAllocator());
doc_properties.AddMember(n, properties, doc_properties.GetAllocator());
// TODO: is this method deep-cloning?
Value properties(feature["properties"], doc_properties.GetAllocator());
doc_properties.AddMember(n, properties, doc_properties.GetAllocator());

return sfc;
return sfc;
}


Rcpp::List parse_feature_collection_object(const Value& fc,
Rcpp::NumericVector& bbox,
std::set< std::string >& geometry_types,
Expand Down
53 changes: 53 additions & 0 deletions tests/testthat/test-geojson_properties.R
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,56 @@ test_that("sf and sfc created equally", {
expect_true(all(class(sf$geometry) == class(sfc)))

})

test_that("null geometries are valid for features", {

js <- '{"type":"Point","coordinates":[null,null]}'
geojson_sf(js) ## TODO: needs to error!!

js <- '{"type":"Point","coordinates":[,]}'
expect_error(geojson_sf(js), "Invalid JSON")

js <- '{"type":"Point","coordinates":[]}'
expect_error(geojson_sf(js), "Invalid lon/lat object")

js <- '{"type":"Point","coordinates":{}}'
expect_error(geojson_sf(js), "No 'array' member at object index 0 - invalid GeoJSON")

js <- '{"type","Feature","geometry":null}'
expect_error(geojson_sf(js), "Invalid JSON")

js <- '{"type","Feature","geometry":null,"properties":{}}'
expect_error(geojson_sf(js), "Invalid JSON")

## NULL geometry should be fine / parse
js <- '{"type":"FeatureCollection","features":[
{"type":"Feature","properties":{"id":1},"geometry":{"type":"Point","coordinates":[0,0]}},
{"type":"Feature","properties":{"id":2},"geometry":null}
]}'
expect_true(nrow(geojson_sf(js)) == 2)
## TODO: Which geometry should the empty row be?

js <- '{"type":"Feature","properties":{"id":2},"geometry": null}'
expect_true(nrow(geojson_sf(js)) == 1)
## TODO: Which geometry should the empty row be?

js <- '{"type":"FeatureCollection","features":[
{"type":"Feature","properties":{"id":1},"geometry":{"type":"MultiPoint","coordinates":[[0,0],[1,1]]}},
{"type":"Feature","properties":{"id":2},"geometry":{"type":"Point","coordinates":[0,0]}},
{"type":"Feature","properties":{"id":3},"geometry":null}
]}'
expect_true(nrow(geojson_sf(js)) == 3)
## TODO: Which geometry should this be?

## null geometries that aren't part of features should still error
js <- '{"type":"Point","coordinates":null}'
expect_error(geojson_sf(js), "No 'array' member at object index 0 - invalid GeoJSON")


})






0 comments on commit 0c120ed

Please sign in to comment.