Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

GeoJSON point clustering #5724

Merged
merged 13 commits into from
Jul 27, 2016
4 changes: 3 additions & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ print_flags nunicode static_libs cflags ldflags
print_flags libzip static_libs cflags ldflags
print_flags geometry cflags
print_flags geojson static_libs cflags ldflags
print_flags geojsonvt static_libs cflags ldflags
print_flags geojsonvt cflags
print_flags supercluster cflags
print_flags kdbush cflags
print_flags variant cflags
print_flags rapidjson static_libs cflags ldflags
print_flags gtest static_libs cflags ldflags
Expand Down
89 changes: 74 additions & 15 deletions include/mbgl/style/conversion/source.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#pragma once

#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/style/conversion/tileset.hpp>
#include <mbgl/style/source.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/tileset.hpp>
#include <mbgl/style/conversion/geojson.hpp>

namespace mbgl {
namespace style {
Expand All @@ -18,17 +18,17 @@ struct Converter<std::unique_ptr<Source>> {
template <class V>
Result<std::unique_ptr<Source>> operator()(const V& value, const std::string& id) const {
if (!isObject(value)) {
return Error { "source must be an object" };
return Error{ "source must be an object" };
}

auto typeValue = objectMember(value, "type");
if (!typeValue) {
return Error { "source must have a type" };
return Error{ "source must have a type" };
}

optional<std::string> type = toString(*typeValue);
if (!type) {
return Error { "source type must be a string" };
return Error{ "source type must be a string" };
}

if (*type == "raster") {
Expand All @@ -38,7 +38,7 @@ struct Converter<std::unique_ptr<Source>> {
} else if (*type == "geojson") {
return convertGeoJSONSource(id, value);
} else {
return Error { "invalid source type" };
return Error{ "invalid source type" };
}
}

Expand All @@ -57,14 +57,15 @@ struct Converter<std::unique_ptr<Source>> {

optional<std::string> url = toString(*urlVal);
if (!url) {
return Error { "source url must be a string" };
return Error{ "source url must be a string" };
}

return *url;
}

template <class V>
Result<std::unique_ptr<Source>> convertRasterSource(const std::string& id, const V& value) const {
Result<std::unique_ptr<Source>> convertRasterSource(const std::string& id,
const V& value) const {
Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
if (!urlOrTileset) {
return urlOrTileset.error();
Expand All @@ -75,7 +76,7 @@ struct Converter<std::unique_ptr<Source>> {
if (tileSizeValue) {
optional<float> size = toNumber(*tileSizeValue);
if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) {
return Error { "invalid tileSize" };
return Error{ "invalid tileSize" };
}
tileSize = *size;
}
Expand All @@ -84,7 +85,8 @@ struct Converter<std::unique_ptr<Source>> {
}

template <class V>
Result<std::unique_ptr<Source>> convertVectorSource(const std::string& id, const V& value) const {
Result<std::unique_ptr<Source>> convertVectorSource(const std::string& id,
const V& value) const {
Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
if (!urlOrTileset) {
return urlOrTileset.error();
Expand All @@ -94,13 +96,70 @@ struct Converter<std::unique_ptr<Source>> {
}

template <class V>
Result<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id, const V& value) const {
Result<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id,
const V& value) const {
auto dataValue = objectMember(value, "data");
if (!dataValue) {
return Error { "GeoJSON source must have a data value" };
return Error{ "GeoJSON source must have a data value" };
}

GeoJSONOptions options;

const auto maxzoomValue = objectMember(value, "maxzoom");
if (maxzoomValue) {
if (toNumber(*maxzoomValue)) {
options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue));
} else {
return Error{ "GeoJSON source maxzoom value must be a number" };
}
}

const auto bufferValue = objectMember(value, "buffer");
if (bufferValue) {
if (toNumber(*bufferValue)) {
options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue));
} else {
return Error{ "GeoJSON source buffer value must be a number" };
}
}

const auto toleranceValue = objectMember(value, "tolerance");
if (toleranceValue) {
if (toNumber(*toleranceValue)) {
options.tolerance = static_cast<double>(*toNumber(*toleranceValue));
} else {
return Error{ "GeoJSON source tolerance value must be a number" };
}
}

const auto clusterValue = objectMember(value, "cluster");
if (clusterValue) {
if (toBool(*clusterValue)) {
options.cluster = *toBool(*clusterValue);
} else {
return Error{ "GeoJSON source cluster value must be a boolean" };
}
}

const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom");
if (clusterMaxZoomValue) {
if (toNumber(*clusterMaxZoomValue)) {
options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue));
} else {
return Error{ "GeoJSON source clusterMaxZoom value must be a number" };
}
}

const auto clusterRadiusValue = objectMember(value, "clusterRadius");
if (clusterRadiusValue) {
if (toNumber(*clusterRadiusValue)) {
options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue));
} else {
return Error{ "GeoJSON source clusterRadius value must be a number" };
}
}

auto result = std::make_unique<GeoJSONSource>(id);
auto result = std::make_unique<GeoJSONSource>(id, options);

if (isObject(*dataValue)) {
Result<GeoJSON> geoJSON = convertGeoJSON(*dataValue);
Expand All @@ -111,7 +170,7 @@ struct Converter<std::unique_ptr<Source>> {
} else if (toString(*dataValue)) {
result->setURL(*toString(*dataValue));
} else {
return Error { "GeoJSON data must be a URL or an object" };
return Error{ "GeoJSON data must be a URL or an object" };
}

return std::move(result);
Expand Down
35 changes: 33 additions & 2 deletions include/mbgl/style/sources/geojson_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,46 @@
#include <mbgl/style/source.hpp>
#include <mbgl/util/geojson.hpp>

#include <mapbox/geojson.hpp>

namespace mapbox {

namespace geojsonvt {
class GeoJSONVT;
} // namespace geojsonvt

namespace supercluster {
class Supercluster;
} // namespace supercluster

} // namespace mapbox

namespace mbgl {
namespace style {

using GeoJSONVTPointer = std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>;
using SuperclusterPointer = std::unique_ptr<mapbox::supercluster::Supercluster>;

struct GeoJSONOptions {
// GeoJSON-VT options
uint8_t maxzoom = 18;
uint16_t buffer = 128;
double tolerance = 0.375;

// Supercluster options
bool cluster = false;
uint16_t clusterRadius = 50;
uint8_t clusterMaxZoom = 17;
};

class GeoJSONSource : public Source {
public:
GeoJSONSource(const std::string& id);
GeoJSONSource(const std::string& id, const GeoJSONOptions options_ = GeoJSONOptions());

void setURL(const std::string& url);
void setGeoJSON(GeoJSON&&);
void setGeoJSON(const GeoJSON&);

std::string getURL();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since a GeoJSON source might not have a URL, let's make this optional<std::string> getURL() so that downstream code has to explicitly handle the non-present case. Conveys the intent better than a possibly-empty string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it's only called when loaded is false, in which case there's always a URL, so the empty string code path is never taken actually. Although it's probably right to make it bulletproof.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, the getter should assert that the URL isn’t empty.


// Private implementation

Expand Down
18 changes: 3 additions & 15 deletions include/mbgl/util/geojson.hpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
#pragma once

#include <memory>

namespace mapbox {
namespace geojsonvt {
class GeoJSONVT;
} // namespace geojsonvt
} // namespace mapbox
#include <mapbox/geojson.hpp>

namespace mbgl {

class GeoJSON {
public:
GeoJSON(std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>);
GeoJSON(GeoJSON&&);
~GeoJSON();

std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> impl;
};
using GeoJSON = mapbox::geojson::geojson;
using FeatureCollection = mapbox::geojson::feature_collection;

} // namespace mbgl
4 changes: 4 additions & 0 deletions mbgl.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@
'<@(geometry_cflags)',
'<@(geojson_cflags)',
'<@(geojsonvt_cflags)',
'<@(supercluster_cflags)',
'<@(kdbush_cflags)',
'<@(rapidjson_cflags)',
'<@(variant_cflags)',
'<@(earcut_cflags)',
Expand Down Expand Up @@ -313,12 +315,14 @@
'cflags_cc': [
'<@(variant_cflags)',
'<@(geometry_cflags)',
'<@(geojson_cflags)',
'<@(unique_resource_cflags)',
],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [
'<@(variant_cflags)',
'<@(geometry_cflags)',
'<@(geojson_cflags)',
'<@(unique_resource_cflags)',
],
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"express": "^4.11.1",
"mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#4d1f89514bf03536c8e682439df165c33a37122a",
"mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#83b1a3e5837d785af582efd5ed1a212f2df6a4ae",
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#fbd511a54a8c27d86c5b2d7cdab94d0e507ba8e8",
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#346aebbb3cf7af572e066e37c703634ceda95be2",
"node-gyp": "^3.3.1",
"request": "^2.72.0",
"tape": "^4.5.1"
Expand Down
2 changes: 2 additions & 0 deletions platform/android/scripts/configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ LIBZIP_VERSION=0.11.2
GEOMETRY_VERSION=0.8.0
GEOJSON_VERSION=0.1.4
GEOJSONVT_VERSION=6.1.2
SUPERCLUSTER_VERSION=0.2.0
KDBUSH_VERSION=0.1.1
VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
JNI_HPP_VERSION=2.0.0
Expand Down
Loading