Skip to content

Commit 8d4f740

Browse files
committed
Feature: Rewrite regionToBBox and getMarkersRegion in cpp
1 parent da3b708 commit 8d4f740

6 files changed

Lines changed: 185 additions & 65 deletions

File tree

android/cpp-adapter.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include <jni.h>
22
#include "react-native-clusterer.h"
33

4-
extern "C"
5-
JNIEXPORT void JNICALL
6-
Java_com_reactnativeclusterer_ClustererModule_initialize(JNIEnv *env, jclass clazz, jlong jsi) {
7-
clusterer::install(*reinterpret_cast<facebook::jsi::Runtime *>(jsi));
4+
extern "C" JNIEXPORT void JNICALL
5+
Java_com_reactnativeclusterer_ClustererModule_initialize(JNIEnv *env,
6+
jclass clazz,
7+
jlong jsi) {
8+
clusterer::install(*reinterpret_cast<facebook::jsi::Runtime *>(jsi));
9+
clusterer::installHelpers(*reinterpret_cast<facebook::jsi::Runtime *>(jsi));
810
}

cpp/helpers.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,144 @@ void featurePropertyToJSI(
221221
return;
222222
}
223223
}
224+
225+
double calculateDelta(double x, double y) {
226+
if(x > y) {
227+
return x - y;
228+
}
229+
return y - x;
230+
}
231+
232+
double calculateAverage(initializer_list<double> args) {
233+
if(args.size() == 0) {
234+
return 0;
235+
}
236+
237+
double sum = 0;
238+
for(auto &num : args) sum += num;
239+
240+
return sum / args.size();
241+
}
242+
243+
void installHelpers(jsi::Runtime &jsiRuntime) {
244+
auto regionToBBox = jsi::Function::createFromHostFunction(
245+
jsiRuntime, jsi::PropNameID::forAscii(jsiRuntime, "regionToBBox"), 1,
246+
[](jsi::Runtime &runtime, const jsi::Value &thisValue,
247+
const jsi::Value *arguments, size_t count) -> jsi::Array {
248+
jsi::Object region = arguments[0].getObject(runtime);
249+
250+
double longitudeDelta =
251+
region.getProperty(runtime, "longitudeDelta").asNumber();
252+
253+
double latitudeDelta =
254+
region.getProperty(runtime, "latitudeDelta").asNumber();
255+
256+
double longitude = region.getProperty(runtime, "longitude").asNumber();
257+
258+
double latitude = region.getProperty(runtime, "latitude").asNumber();
259+
260+
double lngD = longitudeDelta;
261+
262+
if(longitudeDelta < 0) {
263+
lngD = longitudeDelta + 360;
264+
}
265+
266+
jsi::Array bbox = jsi::Array(runtime, 4);
267+
268+
bbox.setValueAtIndex(runtime, 0, longitude - lngD);
269+
bbox.setValueAtIndex(runtime, 1, latitude - latitudeDelta);
270+
bbox.setValueAtIndex(runtime, 2, longitude + lngD);
271+
bbox.setValueAtIndex(runtime, 3, latitude + latitudeDelta);
272+
273+
return bbox;
274+
});
275+
276+
auto getMarkersRegion = jsi::Function::createFromHostFunction(
277+
jsiRuntime, jsi::PropNameID::forAscii(jsiRuntime, "getMarkersRegion"), 1,
278+
[](jsi::Runtime &runtime, const jsi::Value &thisValue,
279+
const jsi::Value *arguments, size_t count) -> jsi::Object {
280+
auto points = arguments[0].getObject(runtime).asArray(runtime);
281+
282+
jsi::Object initialValue =
283+
points.getValueAtIndex(runtime, 0).asObject(runtime);
284+
285+
jsi::Object coordinates = jsi::Object(runtime);
286+
287+
coordinates.setProperty(
288+
runtime, "minX",
289+
initialValue.getProperty(runtime, "latitude").asNumber());
290+
291+
coordinates.setProperty(
292+
runtime, "maxX",
293+
initialValue.getProperty(runtime, "latitude").asNumber());
294+
295+
coordinates.setProperty(
296+
runtime, "minY",
297+
initialValue.getProperty(runtime, "longitude").asNumber());
298+
299+
coordinates.setProperty(
300+
runtime, "maxY",
301+
initialValue.getProperty(runtime, "longitude").asNumber());
302+
303+
for(int i = 0; i < points.size(runtime); i++) {
304+
jsi::Object point =
305+
points.getValueAtIndex(runtime, i).asObject(runtime);
306+
307+
double minX =
308+
std::min(coordinates.getProperty(runtime, "minX").asNumber(),
309+
point.getProperty(runtime, "latitude").asNumber());
310+
311+
double maxX =
312+
std::max(coordinates.getProperty(runtime, "maxX").asNumber(),
313+
point.getProperty(runtime, "latitude").asNumber());
314+
315+
double minY =
316+
std::min(coordinates.getProperty(runtime, "minY").asNumber(),
317+
point.getProperty(runtime, "longitude").asNumber());
318+
319+
double maxY =
320+
std::max(coordinates.getProperty(runtime, "maxY").asNumber(),
321+
point.getProperty(runtime, "longitude").asNumber());
322+
323+
coordinates.setProperty(runtime, "minX", minX);
324+
325+
coordinates.setProperty(runtime, "maxX", maxX);
326+
327+
coordinates.setProperty(runtime, "minY", minY);
328+
329+
coordinates.setProperty(runtime, "maxY", maxY);
330+
}
331+
332+
double deltaX =
333+
calculateDelta(coordinates.getProperty(runtime, "maxX").asNumber(),
334+
coordinates.getProperty(runtime, "minX").asNumber());
335+
double deltaY =
336+
calculateDelta(coordinates.getProperty(runtime, "maxY").asNumber(),
337+
coordinates.getProperty(runtime, "minY").asNumber());
338+
339+
jsi::Object region = jsi::Object(runtime);
340+
341+
region.setProperty(
342+
runtime, "latitude",
343+
calculateAverage(
344+
{coordinates.getProperty(runtime, "minX").asNumber(),
345+
coordinates.getProperty(runtime, "maxX").asNumber()}));
346+
347+
region.setProperty(
348+
runtime, "longitude",
349+
calculateAverage(
350+
{coordinates.getProperty(runtime, "minY").asNumber(),
351+
coordinates.getProperty(runtime, "maxY").asNumber()}));
352+
353+
region.setProperty(runtime, "latitudeDelta", deltaX * 1.5);
354+
region.setProperty(runtime, "longitudeDelta", deltaY * 1.5);
355+
356+
return region;
357+
});
358+
359+
jsiRuntime.global().setProperty(jsiRuntime, "regionToBBox",
360+
std::move(regionToBBox));
361+
jsiRuntime.global().setProperty(jsiRuntime, "getMarkersRegion",
362+
std::move(getMarkersRegion));
363+
}
224364
} // namespace clusterer

cpp/helpers.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ void tileToJSI(jsi::Runtime &rt, jsi::Object &jsiObject,
2626
mapbox::feature::feature<std::int16_t> &f,
2727
jsi::Array &featuresInput);
2828

29-
void featurePropertyToJSI(jsi::Runtime &rt,
30-
jsi::Object &jsiFeatureProperties,
31-
std::pair<const std::string, mapbox::feature::value> &itr,
32-
int &origFeatureIndex);
29+
void featurePropertyToJSI(
30+
jsi::Runtime &rt, jsi::Object &jsiFeatureProperties,
31+
std::pair<const std::string, mapbox::feature::value> &itr,
32+
int &origFeatureIndex);
33+
34+
void installHelpers(jsi::Runtime &jsiRuntime);
3335

3436
} // namespace clusterer

ios/Clusterer.mm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,22 @@ + (BOOL)requiresMainQueueSetup {
4141
return @true;
4242
}
4343

44+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(installHelpers)
45+
{
46+
RCTBridge* bridge = [RCTBridge currentBridge];
47+
RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
48+
if (cxxBridge == nil) {
49+
return @false;
50+
}
51+
52+
auto jsiRuntime = (jsi::Runtime*) cxxBridge.runtime;
53+
if (jsiRuntime == nil) {
54+
return @false;
55+
}
56+
57+
clusterer::installHelpers(*(facebook::jsi::Runtime *)jsiRuntime);
58+
59+
return @true;
60+
}
61+
4462
@end

src/Supercluster.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { NativeModules, Platform } from 'react-native';
22
import GeoViewport from '@mapbox/geo-viewport';
3-
import { getMarkersCoordinates, getMarkersRegion, regionToBBox } from './utils';
3+
import { getMarkersCoordinates } from './utils';
44

55
import type * as GeoJSON from 'geojson';
6-
import type { MapDimensions, Region } from './types';
6+
import type { MapDimensions, Region, BBox, LatLng } from './types';
77
import type Supercluster from './types';
88

99
const module = NativeModules.Clusterer;
@@ -16,6 +16,19 @@ if (
1616
module.install();
1717
}
1818

19+
if (
20+
module &&
21+
typeof module.installHelpers === 'function' &&
22+
!(global as any).regionToBBox &&
23+
!(global as any).getMarkersRegion
24+
) {
25+
module.installHelpers();
26+
}
27+
28+
const regionToBBox: (region: Region) => BBox = (global as any).regionToBBox;
29+
const getMarkersRegion: (points: LatLng[]) => Region = (global as any)
30+
.getMarkersRegion;
31+
1932
const createSupercluster = (global as any).createSupercluster;
2033
const defaultOptions = {
2134
minZoom: 0, // min zoom to generate clusters on

src/utils.ts

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,5 @@
11
import type { Feature, Point } from 'geojson';
22
import type Supercluster from './types';
3-
import type { BBox, LatLng, Region } from './types';
4-
5-
const calculateDelta = (x: number, y: number): number =>
6-
x > y ? x - y : y - x;
7-
8-
const calculateAverage = (...args: number[]): number => {
9-
const argList = [...args];
10-
if (!argList.length) {
11-
return 0;
12-
}
13-
return argList.reduce((sum, num: number) => sum + num, 0) / argList.length;
14-
};
15-
16-
export const regionToBBox = (region: Region): BBox => {
17-
const lngD =
18-
region.longitudeDelta < 0
19-
? region.longitudeDelta + 360
20-
: region.longitudeDelta;
21-
22-
return [
23-
region.longitude - lngD, // westLng - min lng
24-
region.latitude - region.latitudeDelta, // southLat - min lat
25-
region.longitude + lngD, // eastLng - max lng
26-
region.latitude + region.latitudeDelta, // northLat - max lat
27-
];
28-
};
29-
30-
export const getMarkersRegion = (points: LatLng[]): Region => {
31-
const coordinates = {
32-
minX: points[0]!.latitude,
33-
maxX: points[0]!.latitude,
34-
maxY: points[0]!.longitude,
35-
minY: points[0]!.longitude,
36-
};
37-
38-
const { maxX, minX, maxY, minY } = points.reduce(
39-
(acc, point) => ({
40-
minX: Math.min(acc.minX, point.latitude),
41-
maxX: Math.max(acc.maxX, point.latitude),
42-
minY: Math.min(acc.minY, point.longitude),
43-
maxY: Math.max(acc.maxY, point.longitude),
44-
}),
45-
{ ...coordinates }
46-
);
47-
48-
const deltaX = calculateDelta(maxX, minX);
49-
const deltaY = calculateDelta(maxY, minY);
50-
51-
return {
52-
latitude: calculateAverage(minX, maxX),
53-
longitude: calculateAverage(minY, maxY),
54-
latitudeDelta: deltaX * 1.5,
55-
longitudeDelta: deltaY * 1.5,
56-
};
57-
};
583

594
export const getMarkersCoordinates = (markers: Feature<Point>) => {
605
const [longitude, latitude] = markers.geometry.coordinates;

0 commit comments

Comments
 (0)