Skip to content

Commit

Permalink
feat: Remove feature.properties data type limits
Browse files Browse the repository at this point in the history
  • Loading branch information
JiriHoffmann committed Jan 28, 2024
1 parent 5f14f6f commit abe3ae9
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 228 deletions.
10 changes: 10 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Language: Cpp
BasedOnStyle: Google
IndentWidth: 2
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ColumnLimit: 80
PenaltyBreakAssignment: 2
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
SpaceBeforeParens: Never
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ This library provides three different ways to use Supercluster based on your nee

If you are looking for a JS drag-and-drop replacement to speed up point clustering, you should be aware of some caveats:

- Currently supported Point properties are `null`, `boolean`, `number`, `string`. The rest will be discarded when the supercluster is created. If you need to store other properties you can always turn them into a JSON.
- Missing `Map/reduce` functionality.

# useClusterer
Expand Down
126 changes: 72 additions & 54 deletions cpp/SuperclusterHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,31 @@
namespace clusterer {
SuperclusterHostObject::SuperclusterHostObject(jsi::Runtime &rt,
const jsi::Value *args,
size_t count) {
if (count != 2)
size_t count)
: featuresInput(jsi::Array(rt, 0)) {
if(count != 2)
throw jsi::JSError(rt, "React-Native-Clusterer: expects 2 arguments");

// jsi features to cpp
mapbox::feature::feature_collection<double> features;
parseJSIFeatures(rt, features, args[0]);

if(args[0].isObject() && args[0].asObject(rt).isArray(rt)) {
featuresInput = args[0].asObject(rt).asArray(rt);
for(int i = 0; i < featuresInput.size(rt); i++) {
mapbox::feature::feature<double> feature;
parseJSIFeature(rt, i, feature, featuresInput.getValueAtIndex(rt, i));
features.push_back(feature);
}
} else {
throw jsi::JSError(rt, "Expected array of GeoJSON Feature objects");
}
// jsi options to cpp
mapbox::supercluster::Options options;
parseJSIOptions(rt, options, args[1]);

try {
instance = new mapbox::supercluster::Supercluster(features, options);
} catch (exception &e) {
} catch(exception &e) {
std::string message =
std::string("React-Native-Clusterer: Error creating Supercluser") +
e.what();
Expand All @@ -27,8 +37,8 @@ SuperclusterHostObject::SuperclusterHostObject(jsi::Runtime &rt,

SuperclusterHostObject::~SuperclusterHostObject() { delete instance; }

std::vector<jsi::PropNameID>
SuperclusterHostObject::getPropertyNames(jsi::Runtime &rt) {
std::vector<jsi::PropNameID> SuperclusterHostObject::getPropertyNames(
jsi::Runtime &rt) {
std::vector<jsi::PropNameID> result;
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getTile")));
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getClusters")));
Expand All @@ -44,16 +54,17 @@ jsi::Value SuperclusterHostObject::get(jsi::Runtime &runtime,
auto propName = propNameId.utf8(runtime);
auto funcName = "Supercluster." + propName;

if (propName == "getTile") {
if(propName == "getTile") {
return jsi::Function::createFromHostFunction(
runtime, jsi::PropNameID::forAscii(runtime, funcName),
3, // zoom, x, y
3, // zoom, x, y
[this](jsi::Runtime &rt, const jsi::Value &thisVal,
const jsi::Value *args, size_t count) -> jsi::Value {
if (count != 3 || !args[0].isNumber() || !args[1].isNumber() ||
!args[2].isNumber())
throw jsi::JSError(rt, "React-Native-Clusterer: getTile "
"expects 3 numbers as arguments");
if(count != 3 || !args[0].isNumber() || !args[1].isNumber() ||
!args[2].isNumber())
throw jsi::JSError(rt,
"React-Native-Clusterer: getTile "
"expects 3 numbers as arguments");

int zoom = (int)args[0].asNumber();
int x = (int)args[1].asNumber();
Expand All @@ -63,26 +74,27 @@ jsi::Value SuperclusterHostObject::get(jsi::Runtime &runtime,

jsi::Array result = jsi::Array(rt, tiles.size());
int i = 0;
for (auto &tile : tiles) {
for(auto &tile : tiles) {
jsi::Object jsiTile = jsi::Object(rt);
featureToJSI(rt, jsiTile, tile);
featureToJSI(rt, jsiTile, tile, featuresInput);
result.setValueAtIndex(rt, i, jsiTile);
i++;
}
return result;
});
}

if (propName == "getClusters") {
if(propName == "getClusters") {
return jsi::Function::createFromHostFunction(
runtime, jsi::PropNameID::forAscii(runtime, funcName),
2, // bbox, zoom
2, // bbox, zoom
[this](jsi::Runtime &rt, const jsi::Value &thisVal,
const jsi::Value *args, size_t count) -> jsi::Value {
if (count != 2 || !args[0].asObject(rt).isArray(rt) ||
!args[1].isNumber())
throw jsi::JSError(rt, "React-Native-Clusterer: getClusters "
"expects an array and a number");
if(count != 2 || !args[0].asObject(rt).isArray(rt) ||
!args[1].isNumber())
throw jsi::JSError(rt,
"React-Native-Clusterer: getClusters "
"expects an array and a number");

double bbox[4];

Expand All @@ -92,10 +104,11 @@ jsi::Value SuperclusterHostObject::get(jsi::Runtime &runtime,
bbox[1] = jsibbox.getValueAtIndex(rt, 1).asNumber();
bbox[2] = jsibbox.getValueAtIndex(rt, 2).asNumber();
bbox[3] = jsibbox.getValueAtIndex(rt, 3).asNumber();
} catch (exception &e) {
} catch(exception &e) {
throw jsi::JSError(
rt, "React-Native-Clusterer: GetClusters error, make sure "
"boundingBox is an array of 4 numbers");
rt,
"React-Native-Clusterer: GetClusters error, make sure "
"boundingBox is an array of 4 numbers");
}

int zoom = (int)args[1].asNumber();
Expand All @@ -104,63 +117,67 @@ jsi::Value SuperclusterHostObject::get(jsi::Runtime &runtime,
jsi::Array result = jsi::Array(rt, clusters.size());

int i = 0;
for (auto &cluster : clusters) {
for(auto &cluster : clusters) {
jsi::Object jsiCluster = jsi::Object(rt);
clusterToJSI(rt, jsiCluster, cluster);
clusterToJSI(rt, jsiCluster, cluster, featuresInput);
result.setValueAtIndex(rt, i, jsiCluster);
i++;
}
return result;
});
}

if (propName == "getChildren") {
if(propName == "getChildren") {
return jsi::Function::createFromHostFunction(
runtime, jsi::PropNameID::forAscii(runtime, funcName),
1, // cluster_id
1, // cluster_id
[this](jsi::Runtime &rt, const jsi::Value &thisVal,
const jsi::Value *args, size_t count) -> jsi::Value {
if (count != 1 || !args[0].isNumber())
throw jsi::JSError(rt, "React-Native-Clusterer: getChildren "
"expects a number for cluster_id");
if(count != 1 || !args[0].isNumber())
throw jsi::JSError(rt,
"React-Native-Clusterer: getChildren "
"expects a number for cluster_id");

auto cluster_id = (int)args[0].asNumber();
auto children = instance->getChildren(cluster_id);
jsi::Array result = jsi::Array(rt, children.size());

int i = 0;
for (auto &child : children) {
for(auto &child : children) {
jsi::Object jsiChild = jsi::Object(rt);
clusterToJSI(rt, jsiChild, child);
clusterToJSI(rt, jsiChild, child, featuresInput);
result.setValueAtIndex(rt, i, jsiChild);
i++;
}
return result;
});
}

if (propName == "getLeaves") {
if(propName == "getLeaves") {
return jsi::Function::createFromHostFunction(
runtime, jsi::PropNameID::forAscii(runtime, funcName),
3, // clusterId, limit = 10, offset = 0
3, // clusterId, limit = 10, offset = 0
[this](jsi::Runtime &rt, const jsi::Value &thisVal,
const jsi::Value *args, size_t count) -> jsi::Value {
if (count < 1 || count > 3)
if(count < 1 || count > 3)
throw jsi::JSError(rt,
"React-Native-Clusterer: getLeaves "
"expects at least 1 argument, at most 3");
"React-Native-Clusterer: getLeaves "
"expects at least 1 argument, at most 3");

if (!args[0].isNumber())
throw jsi::JSError(rt, "React-Native-Clusterer: getLeaves "
"first argument must be a number");
if(!args[0].isNumber())
throw jsi::JSError(rt,
"React-Native-Clusterer: getLeaves "
"first argument must be a number");

if (count >= 2 && !args[1].isNumber())
throw jsi::JSError(rt, "React-Native-Clusterer: getLeaves "
"second argument must be a number");
if(count >= 2 && !args[1].isNumber())
throw jsi::JSError(rt,
"React-Native-Clusterer: getLeaves "
"second argument must be a number");

if (count == 3 && !args[2].isNumber())
throw jsi::JSError(rt, "React-Native-Clusterer: getLeaves "
"third argument must be a number");
if(count == 3 && !args[2].isNumber())
throw jsi::JSError(rt,
"React-Native-Clusterer: getLeaves "
"third argument must be a number");

auto cluster_id = (int)args[0].asNumber();
auto limit = count >= 2 ? (int)args[1].asNumber() : 10;
Expand All @@ -170,9 +187,9 @@ jsi::Value SuperclusterHostObject::get(jsi::Runtime &runtime,
jsi::Array result = jsi::Array(rt, leaves.size());

int i = 0;
for (auto &leaf : leaves) {
for(auto &leaf : leaves) {
jsi::Object jsiLeaf = jsi::Object(rt);
clusterToJSI(rt, jsiLeaf, leaf);
clusterToJSI(rt, jsiLeaf, leaf, featuresInput);
result.setValueAtIndex(rt, i, jsiLeaf);
i++;
}
Expand All @@ -181,16 +198,17 @@ jsi::Value SuperclusterHostObject::get(jsi::Runtime &runtime,
});
}

if (propName == "getClusterExpansionZoom") {
if(propName == "getClusterExpansionZoom") {
return jsi::Function::createFromHostFunction(
runtime, jsi::PropNameID::forAscii(runtime, funcName),
1, // cluster_id
1, // cluster_id
[this](jsi::Runtime &rt, const jsi::Value &thisVal,
const jsi::Value *args, size_t count) -> jsi::Value {
if (count != 1 || !args[0].isNumber())
if(count != 1 || !args[0].isNumber())
throw jsi::JSError(
rt, "React-Native-Clusterer: getClusterExpansionZoom expects "
"number for cluster_id");
rt,
"React-Native-Clusterer: getClusterExpansionZoom expects "
"number for cluster_id");

auto cluster_id = (int)args[0].asNumber();

Expand All @@ -200,4 +218,4 @@ jsi::Value SuperclusterHostObject::get(jsi::Runtime &runtime,

return jsi::Value::undefined();
}
} // namespace clusterer
} // namespace clusterer
12 changes: 7 additions & 5 deletions cpp/SuperclusterHostObject.h
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
#pragma once

#include <jsi/jsi.h>

#include "helpers.h"
#include "supercluster.hpp"
#include <jsi/jsi.h>

using namespace std;
using namespace facebook;

namespace clusterer {
class JSI_EXPORT SuperclusterHostObject : public jsi::HostObject {
public:
public:
SuperclusterHostObject(jsi::Runtime &rt, const jsi::Value *args,
size_t count);
~SuperclusterHostObject();

public:
public:
jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;

private:
private:
mapbox::supercluster::Supercluster *instance;
jsi::Array featuresInput;
};
} // namespace clusterer
} // namespace clusterer
Loading

0 comments on commit abe3ae9

Please sign in to comment.