Skip to content

Commit

Permalink
add support for loading lines and points from geojson
Browse files Browse the repository at this point in the history
  • Loading branch information
asmuth committed Feb 3, 2020
1 parent 6097070 commit 191159a
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/data.cc
Expand Up @@ -185,6 +185,51 @@ ReturnCode data_load_strings(
return expr_to_strings(expr, values);
}

ReturnCode data_load_polylines2_geojson(
const Expr* expr,
std::vector<PolyLine2>* data) {
if (!expr || !expr_is_value(expr)) {
return errorf(
ERROR,
"argument error; expected a filename, got: {}",
expr_inspect(expr));
}

const auto& path = expr_get_value(expr);

GeoJSONReader reader;
reader.on_lines = [data] (const PolyLine3* polys, size_t poly_count) {
for (size_t i = 0; i < poly_count; ++i) {
data->emplace_back(polyline3_to_polyline2(polys[i]));
}

return OK;
};

return geojson_read_file(path, reader);
}

ReturnCode data_load_polylines2(
const Expr* expr,
std::vector<PolyLine2>* data) {
if (!expr || !expr_is_list(expr) || !expr_get_list(expr)) {
return errorf(
ERROR,
"argument error; expected a list, got: {}",
expr_inspect(expr));
}

auto args = expr_get_list(expr);

if (args && expr_is_value_literal(args, "geojson")) {
return data_load_polylines2_geojson(expr_next(args), data);
}

return err_invalid_value(expr_inspect(expr), {
"geojson"
});
}

ReturnCode data_load_polys2_geojson(
const Expr* expr,
std::vector<Poly2>* data) {
Expand Down Expand Up @@ -230,6 +275,51 @@ ReturnCode data_load_polys2(
});
}

ReturnCode data_load_points2_geojson(
const Expr* expr,
std::vector<vec2>* data) {
if (!expr || !expr_is_value(expr)) {
return errorf(
ERROR,
"argument error; expected a filename, got: {}",
expr_inspect(expr));
}

const auto& path = expr_get_value(expr);

GeoJSONReader reader;
reader.on_points = [data] (const vec3* points, size_t point_count) {
for (size_t i = 0; i < point_count; ++i) {
data->emplace_back(points[i]);
}

return OK;
};

return geojson_read_file(path, reader);
}

ReturnCode data_load_points2(
const Expr* expr,
std::vector<vec2>* data) {
if (!expr || !expr_is_list(expr) || !expr_get_list(expr)) {
return errorf(
ERROR,
"argument error; expected a list, got: {}",
expr_inspect(expr));
}

auto args = expr_get_list(expr);

if (args && expr_is_value_literal(args, "geojson")) {
return data_load_points2_geojson(expr_next(args), data);
}

return err_invalid_value(expr_inspect(expr), {
"geojson"
});
}

ReturnCode data_load(
const Expr* expr,
std::vector<Measure>* values) {
Expand Down
8 changes: 8 additions & 0 deletions src/data.h
Expand Up @@ -52,10 +52,18 @@ ReturnCode data_load_strings(
const Expr* expr,
std::vector<std::string>* values);

ReturnCode data_load_polylines2(
const Expr* expr,
std::vector<PolyLine2>* data);

ReturnCode data_load_polys2(
const Expr* expr,
std::vector<Poly2>* data);

ReturnCode data_load_points2(
const Expr* expr,
std::vector<vec2>* data);

ReturnCode data_load(
const Expr* expr,
std::vector<Measure>* values);
Expand Down
12 changes: 12 additions & 0 deletions src/graphics/path.cc
Expand Up @@ -296,6 +296,18 @@ void path_add_circle(Path* path, vec2 origin, double radius) {
path->closePath();
}

void path_add_poly_line(Path* path, const PolyLine2& line) {
if (line.vertices.empty()) {
return;
}

path->moveTo(line.vertices[0].x, line.vertices[0].y);

for (size_t i = 1; i < line.vertices.size(); ++i) {
path->lineTo(line.vertices[i].x, line.vertices[i].y);
}
}

void path_add_poly_ring(Path* path, const PolyLine2& ring) {
if (ring.vertices.empty()) {
return;
Expand Down
5 changes: 5 additions & 0 deletions src/graphics/path.h
Expand Up @@ -108,6 +108,11 @@ void path_add_rectangle(Path* path, const Rectangle& rect);
*/
void path_add_circle(Path* path, vec2 origin, double radius);

/**
* Add a polyline to a path
*/
void path_add_poly_line(Path* path, const PolyLine2& line);

/**
* Add a polygonal ring to a path
*/
Expand Down
162 changes: 162 additions & 0 deletions src/utils/geojson.cc
Expand Up @@ -174,6 +174,152 @@ ReturnCode geojson_read_multi_polygon(
return OK;
}

ReturnCode geojson_read_point(
const GeoJSONReader& reader,
const std::vector<GeoJSONCoord>& coords) {
std::optional<vec3> point;

if (coords.size() == 2 &&
coords[0].rlevel == 0 &&
coords[1].rlevel == 0) {
point = vec3(
coords[0].value,
coords[1].value,
coords[2].value);
}

if (coords.size() == 3 &&
coords[0].rlevel == 0 &&
coords[1].rlevel == 0 &&
coords[2].rlevel == 0) {
point = vec3(
coords[0].value,
coords[1].value,
0);
}

if (!point) {
return {ERROR, "invalid coordinate format for 'Point' objects"};
}

if (reader.on_points) {
if (auto rc = reader.on_points(&*point, 1); !rc) {
return rc;
}
}

return OK;
}

ReturnCode geojson_read_multi_point(
const GeoJSONReader& reader,
const std::vector<GeoJSONCoord>& coords) {
std::vector<vec3> points;
for (size_t i = 0; i < coords.size(); i += 2) {
if (i + 2 > coords.size() || coords[i].rlevel != 0 || coords[i + 1].rlevel != 1) {
return {ERROR, "invalid coordinate format for 'MultiPoint' objects"};
}

if (i + 2 < coords.size() && coords[i + 2].rlevel == 1) {
points.emplace_back(
coords[i + 0].value,
coords[i + 1].value,
coords[i + 2].value);
} else {
points.emplace_back(
coords[i + 0].value,
coords[i + 1].value,
0);
}
}

if (points.empty()) {
return {ERROR, "invalid coordinate format for 'MultiPoint' objects"};
}

if (reader.on_points) {
if (auto rc = reader.on_points(points.data(), points.size()); !rc) {
return rc;
}
}

return OK;
}

ReturnCode geojson_read_line_string(
const GeoJSONReader& reader,
const std::vector<GeoJSONCoord>& coords) {
PolyLine3 line;
for (size_t i = 0; i < coords.size(); i += 2) {
if (i + 2 > coords.size() || coords[i].rlevel != 0 || coords[i + 1].rlevel != 1) {
return {ERROR, "invalid coordinate format for 'LineString' objects"};
}

if (i + 2 < coords.size() && coords[i + 2].rlevel == 1) {
line.vertices.emplace_back(
coords[i + 0].value,
coords[i + 1].value,
coords[i + 2].value);
} else {
line.vertices.emplace_back(
coords[i + 0].value,
coords[i + 1].value,
0);
}
}

if (line.vertices.empty()) {
return {ERROR, "invalid coordinate format for 'LineString' objects"};
}

if (reader.on_lines) {
if (auto rc = reader.on_lines(&line, 1); !rc) {
return rc;
}
}

return OK;
}

ReturnCode geojson_read_multi_line_string(
const GeoJSONReader& reader,
const std::vector<GeoJSONCoord>& coords) {
std::vector<PolyLine3> lines;
for (size_t i = 0; i < coords.size(); i += 2) {
if (coords[i].rlevel == 0) {
lines.emplace_back();
}

if (i + 2 > coords.size() || coords[i + 1].rlevel != 2 || lines.empty()) {
return {ERROR, "invalid coordinate format for 'MultiLineString' objects"};
}

if (i + 2 < coords.size() && coords[i + 2].rlevel == 2) {
lines.back().vertices.emplace_back(
coords[i + 0].value,
coords[i + 1].value,
coords[i + 2].value);
} else {
lines.back().vertices.emplace_back(
coords[i + 0].value,
coords[i + 1].value,
0);
}
}

if (lines.empty()) {
return {ERROR, "invalid coordinate format for 'MultiLineString' objects"};
}

if (reader.on_lines) {
if (auto rc = reader.on_lines(lines.data(), lines.size()); !rc) {
return rc;
}
}

return OK;
}

ReturnCode geojson_read_object_data(
const GeoJSONReader& reader,
std::istream* input) {
Expand Down Expand Up @@ -236,6 +382,14 @@ ReturnCode geojson_read_object_data(
return OK;
}

if (type == "Point") {
return geojson_read_point(reader, coords);
}

if (type == "MultiPoint") {
return geojson_read_multi_point(reader, coords);
}

if (type == "Polygon") {
return geojson_read_polygon(reader, coords);
}
Expand All @@ -244,6 +398,14 @@ ReturnCode geojson_read_object_data(
return geojson_read_multi_polygon(reader, coords);
}

if (type == "LineString") {
return geojson_read_multi_line_string(reader, coords);
}

if (type == "MultiLineString") {
return geojson_read_multi_line_string(reader, coords);
}

return errorf(ERROR, "invalid object type: {}", type);
}

Expand Down
2 changes: 2 additions & 0 deletions src/utils/geojson.h
Expand Up @@ -21,6 +21,8 @@
namespace clip {

struct GeoJSONReader {
std::function<ReturnCode (const vec3*, size_t)> on_points;
std::function<ReturnCode (const PolyLine3*, size_t)> on_lines;
std::function<ReturnCode (const Poly3*, size_t)> on_polygons;
};

Expand Down

0 comments on commit 191159a

Please sign in to comment.