Skip to content

Commit

Permalink
GeoJSON writer for debugging (#609)
Browse files Browse the repository at this point in the history
  • Loading branch information
systemed authored Dec 9, 2023
1 parent 3e90739 commit b278569
Showing 1 changed file with 137 additions and 0 deletions.
137 changes: 137 additions & 0 deletions include/geojson.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*! \file */
#ifndef _GEOJSON_H
#define _GEOJSON_H

/*
GeoJSON writer for boost::geometry objects, using RapidJSON.
This isn't core tilemaker functionality but helps with debugging.
As yet it only outputs (Multi)Polygons but can be extended for more types.
Example:
auto gj = GeoJSON()
gj.addGeometry(myMultiPolygon);
gj.finalise();
std::cout << gj.toString() << std::endl;
Or use gj.toFile("output.geojson") to write to file.
Calling finalise(true) will 'unproject' Y values (i.e. latp2lat).
Todo: support more geometries, set/write properties.
*/

#include <iostream>
#include <math.h>
#include "geom.h"

#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filewritestream.h"

typedef boost::variant<Point,Linestring,MultiLinestring,Polygon,MultiPolygon,Ring> AnyGeometry;

using namespace rapidjson;

struct GeoJSON {
Document document;
std::vector<AnyGeometry> geometries;

GeoJSON() {
document.SetObject();
document.AddMember("type", Value().SetString("FeatureCollection"), document.GetAllocator());
}
void addGeometry(AnyGeometry geom) {
geometries.emplace_back(geom);
}
struct SerialiseGeometry {
Value *obj;
Document::AllocatorType *alloc;
bool unproject;

SerialiseGeometry(Value *obj, Document::AllocatorType *alloc, bool unproject) :
obj(obj), alloc(alloc), unproject(unproject) {}

double deg2rad(double deg) { return (M_PI/180.0) * deg; }
double rad2deg(double rad) { return (180.0/M_PI) * rad; }
double latp2lat(double latp) { return rad2deg(atan(exp(deg2rad(latp)))*2.0)-90.0; }
Value ringToArray(Ring &r) {
Value arr(kArrayType);
for (auto &point : r) {
Value pt(kArrayType);
pt.PushBack(point.x(), *alloc);
pt.PushBack(unproject ? latp2lat(point.y()) : point.y(), *alloc);
arr.PushBack(pt, *alloc);
}
return arr;
}
void operator()(Point &p) {} // todo
void operator()(Linestring &ls) {} // todo
void operator()(MultiLinestring &mls) {} // todo
void operator()(Ring &r) {
Value coordinates(kArrayType);
coordinates.PushBack(ringToArray(r), *alloc);
obj->AddMember("coordinates", coordinates, *alloc);
obj->AddMember("type", Value().SetString("Polygon"), *alloc);
}
void operator()(Polygon &p) {
Value coordinates(kArrayType);
coordinates.PushBack(ringToArray(p.outer()), *alloc);
for (auto &inner : p.inners()) {
coordinates.PushBack(ringToArray(inner), *alloc);
}
obj->AddMember("coordinates", coordinates, *alloc);
obj->AddMember("type", Value().SetString("Polygon"), *alloc);
}
void operator()(MultiPolygon &mp) {
Value coordinates(kArrayType);
for (auto &polygon : mp) {
Value polyCoords(kArrayType);
polyCoords.PushBack(ringToArray(polygon.outer()), *alloc);
for (auto &inner : polygon.inners()) {
polyCoords.PushBack(ringToArray(inner), *alloc);
}
coordinates.PushBack(polyCoords, *alloc);
}
obj->AddMember("coordinates", coordinates, *alloc);
obj->AddMember("type", Value().SetString("MultiPolygon"), *alloc);
}
};
void finalise(bool unproject = false) {
Value features(kArrayType);
for (AnyGeometry &g : geometries) {
// type
Value obj(kObjectType);
obj.AddMember("type", Value().SetString("Feature"), document.GetAllocator());
// properties (todo)
Value properties(kObjectType);
obj.AddMember("properties", properties, document.GetAllocator());
// geometry
Value geometry(kObjectType);
boost::apply_visitor(SerialiseGeometry(&geometry, &(document.GetAllocator()), unproject), g);
obj.AddMember("geometry", geometry, document.GetAllocator());
// add to list
features.PushBack(obj, document.GetAllocator());
}
document.AddMember("features", features, document.GetAllocator());
geometries.clear();
}
std::string toString() {
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(5);
document.Accept(writer);
std::string json(buffer.GetString(), buffer.GetSize());
return json;
}
void toFile(std::string filename) {
auto fp = std::fopen(filename.c_str(), "w");
char writeBuffer[65536];
FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
Writer<FileWriteStream> writer(os);
writer.SetMaxDecimalPlaces(5);
document.Accept(writer);
fclose(fp);
}
};

#endif //_GEOJSON_H

0 comments on commit b278569

Please sign in to comment.