@maydon_tech/react-native-nitro-maps 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/NitroMap.podspec +42 -0
- package/README.md +172 -0
- package/android/CMakeLists.txt +27 -0
- package/android/build.gradle +141 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/ClusterIconGenerator.kt +108 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/ColorUtils.kt +63 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMap.kt +408 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMapConfig.kt +68 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconCache.kt +176 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconFactory.kt +252 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/NitroMapPackage.kt +33 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +252 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/clustering/QuadTree.kt +195 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/providers/GoogleMapProvider.kt +912 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +70 -0
- package/cpp/ClusterEngine.hpp +411 -0
- package/cpp/KDBush.hpp +238 -0
- package/cpp/QuadTree.hpp +246 -0
- package/ios/Clustering/ClusterEngineWrapper.h +58 -0
- package/ios/Clustering/ClusterEngineWrapper.mm +142 -0
- package/ios/Clustering/ClusterIconRenderer.swift +80 -0
- package/ios/Clustering/NitroClusterEngine.swift +117 -0
- package/ios/Clustering/NitroClusterIconGenerator.swift +35 -0
- package/ios/MarkerRenderer/MarkerIconFactory.swift +322 -0
- package/ios/MarkerRenderer/PriceMarkerRenderer.swift +140 -0
- package/ios/NitroMap.swift +332 -0
- package/ios/NitroMapConfig/HybridNitroMapConfig.swift +33 -0
- package/ios/Providers/GoogleMapDelegate.swift +310 -0
- package/ios/Providers/GoogleMapProvider+Camera.swift +164 -0
- package/ios/Providers/GoogleMapProvider.swift +924 -0
- package/ios/Providers/MapProviderProtocol.swift +78 -0
- package/ios/Shared/ClusterConfig+Factory.swift +58 -0
- package/ios/Shared/ClusteringManager.swift +211 -0
- package/ios/Shared/MapStyleProvider.swift +135 -0
- package/ios/Shared/MarkerSelectionHandler.swift +116 -0
- package/ios/Utils/ColorValueExtension.swift +54 -0
- package/lib/module/components/ImageMarker.js +146 -0
- package/lib/module/components/ImageMarker.js.map +1 -0
- package/lib/module/components/NitroMap.js +320 -0
- package/lib/module/components/NitroMap.js.map +1 -0
- package/lib/module/components/PriceMarker.js +165 -0
- package/lib/module/components/PriceMarker.js.map +1 -0
- package/lib/module/context/NitroMapContext.js +15 -0
- package/lib/module/context/NitroMapContext.js.map +1 -0
- package/lib/module/hooks/useNitroMarker.js +104 -0
- package/lib/module/hooks/useNitroMarker.js.map +1 -0
- package/lib/module/index.js +21 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/modules/index.js +4 -0
- package/lib/module/modules/index.js.map +1 -0
- package/lib/module/modules/module.js +30 -0
- package/lib/module/modules/module.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/specs/NitroMap.nitro.js +4 -0
- package/lib/module/specs/NitroMap.nitro.js.map +1 -0
- package/lib/module/specs/NitroMapConfig.nitro.js +4 -0
- package/lib/module/specs/NitroMapConfig.nitro.js.map +1 -0
- package/lib/module/types/map.js +2 -0
- package/lib/module/types/map.js.map +1 -0
- package/lib/module/types/marker.js +4 -0
- package/lib/module/types/marker.js.map +1 -0
- package/lib/module/utils/colors.js +147 -0
- package/lib/module/utils/colors.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/components/ImageMarker.d.ts +70 -0
- package/lib/typescript/src/components/ImageMarker.d.ts.map +1 -0
- package/lib/typescript/src/components/NitroMap.d.ts +14 -0
- package/lib/typescript/src/components/NitroMap.d.ts.map +1 -0
- package/lib/typescript/src/components/PriceMarker.d.ts +88 -0
- package/lib/typescript/src/components/PriceMarker.d.ts.map +1 -0
- package/lib/typescript/src/context/NitroMapContext.d.ts +16 -0
- package/lib/typescript/src/context/NitroMapContext.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useNitroMarker.d.ts +78 -0
- package/lib/typescript/src/hooks/useNitroMarker.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +12 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/modules/index.d.ts +2 -0
- package/lib/typescript/src/modules/index.d.ts.map +1 -0
- package/lib/typescript/src/modules/module.d.ts +22 -0
- package/lib/typescript/src/modules/module.d.ts.map +1 -0
- package/lib/typescript/src/specs/NitroMap.nitro.d.ts +227 -0
- package/lib/typescript/src/specs/NitroMap.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/NitroMapConfig.nitro.d.ts +10 -0
- package/lib/typescript/src/specs/NitroMapConfig.nitro.d.ts.map +1 -0
- package/lib/typescript/src/types/map.d.ts +154 -0
- package/lib/typescript/src/types/map.d.ts.map +1 -0
- package/lib/typescript/src/types/marker.d.ts +248 -0
- package/lib/typescript/src/types/marker.d.ts.map +1 -0
- package/lib/typescript/src/utils/colors.d.ts +82 -0
- package/lib/typescript/src/utils/colors.d.ts.map +1 -0
- package/nitro.json +21 -0
- package/nitrogen/generated/android/c++/JCamera.hpp +74 -0
- package/nitrogen/generated/android/c++/JClusterAnimationStyle.hpp +68 -0
- package/nitrogen/generated/android/c++/JClusterConfig.hpp +121 -0
- package/nitrogen/generated/android/c++/JClusterPressEvent.hpp +86 -0
- package/nitrogen/generated/android/c++/JClusterStrategy.hpp +59 -0
- package/nitrogen/generated/android/c++/JColorValue.cpp +26 -0
- package/nitrogen/generated/android/c++/JColorValue.hpp +70 -0
- package/nitrogen/generated/android/c++/JCoordinate.hpp +61 -0
- package/nitrogen/generated/android/c++/JEdgePadding.hpp +69 -0
- package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_ClusterPressEvent.hpp +81 -0
- package/nitrogen/generated/android/c++/JFunc_void_MapError.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_MapPressEvent.hpp +81 -0
- package/nitrogen/generated/android/c++/JFunc_void_MarkerDragEvent.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_MarkerPressEvent.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_RegionChangeEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JHybridNitroMapConfigSpec.cpp +59 -0
- package/nitrogen/generated/android/c++/JHybridNitroMapConfigSpec.hpp +66 -0
- package/nitrogen/generated/android/c++/JHybridNitroMapSpec.cpp +593 -0
- package/nitrogen/generated/android/c++/JHybridNitroMapSpec.hpp +125 -0
- package/nitrogen/generated/android/c++/JImageMarkerConfig.hpp +86 -0
- package/nitrogen/generated/android/c++/JMapBoundaries.hpp +62 -0
- package/nitrogen/generated/android/c++/JMapError.hpp +61 -0
- package/nitrogen/generated/android/c++/JMapPressEvent.hpp +64 -0
- package/nitrogen/generated/android/c++/JMapProvider.hpp +62 -0
- package/nitrogen/generated/android/c++/JMapStyleElement.hpp +87 -0
- package/nitrogen/generated/android/c++/JMapStyler.hpp +78 -0
- package/nitrogen/generated/android/c++/JMapType.hpp +62 -0
- package/nitrogen/generated/android/c++/JMarkerAnimation.hpp +62 -0
- package/nitrogen/generated/android/c++/JMarkerColor.hpp +69 -0
- package/nitrogen/generated/android/c++/JMarkerConfig.hpp +77 -0
- package/nitrogen/generated/android/c++/JMarkerData.hpp +121 -0
- package/nitrogen/generated/android/c++/JMarkerDragEvent.hpp +63 -0
- package/nitrogen/generated/android/c++/JMarkerPressEvent.hpp +63 -0
- package/nitrogen/generated/android/c++/JMarkerStyle.hpp +62 -0
- package/nitrogen/generated/android/c++/JPoint.hpp +61 -0
- package/nitrogen/generated/android/c++/JPriceMarkerStyle.hpp +102 -0
- package/nitrogen/generated/android/c++/JRegion.hpp +69 -0
- package/nitrogen/generated/android/c++/JRegionChangeEvent.hpp +62 -0
- package/nitrogen/generated/android/c++/JVariant_String_MarkerColor.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_String_MarkerColor.hpp +70 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroMapStateUpdater.cpp +144 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroMapStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Camera.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterAnimationStyle.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterConfig.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterPressEvent.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterStrategy.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ColorValue.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Coordinate.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/EdgePadding.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_ClusterPressEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MapError.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MapPressEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MarkerDragEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MarkerPressEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_RegionChangeEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/HybridNitroMapConfigSpec.kt +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/HybridNitroMapSpec.kt +342 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ImageMarkerConfig.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapBoundaries.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapError.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapPressEvent.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapProvider.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapStyleElement.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapStyler.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapType.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerAnimation.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerColor.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerConfig.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerData.kt +71 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerDragEvent.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerPressEvent.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerStyle.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Point.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PriceMarkerStyle.kt +68 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Region.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/RegionChangeEvent.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Variant_String_MarkerColor.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/nitromapOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/views/HybridNitroMapManager.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/views/HybridNitroMapStateUpdater.kt +23 -0
- package/nitrogen/generated/android/nitromap+autolinking.cmake +87 -0
- package/nitrogen/generated/android/nitromap+autolinking.gradle +27 -0
- package/nitrogen/generated/android/nitromapOnLoad.cpp +70 -0
- package/nitrogen/generated/android/nitromapOnLoad.hpp +25 -0
- package/nitrogen/generated/ios/NitroMap+autolinking.rb +60 -0
- package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.cpp +130 -0
- package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.hpp +793 -0
- package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Umbrella.hpp +132 -0
- package/nitrogen/generated/ios/NitroMapAutolinking.mm +41 -0
- package/nitrogen/generated/ios/NitroMapAutolinking.swift +40 -0
- package/nitrogen/generated/ios/c++/HybridNitroMapConfigSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNitroMapConfigSpecSwift.hpp +84 -0
- package/nitrogen/generated/ios/c++/HybridNitroMapSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNitroMapSpecSwift.hpp +410 -0
- package/nitrogen/generated/ios/c++/views/HybridNitroMapComponent.mm +206 -0
- package/nitrogen/generated/ios/swift/Camera.swift +80 -0
- package/nitrogen/generated/ios/swift/ClusterAnimationStyle.swift +52 -0
- package/nitrogen/generated/ios/swift/ClusterConfig.swift +268 -0
- package/nitrogen/generated/ios/swift/ClusterPressEvent.swift +70 -0
- package/nitrogen/generated/ios/swift/ClusterStrategy.swift +40 -0
- package/nitrogen/generated/ios/swift/ColorValue.swift +18 -0
- package/nitrogen/generated/ios/swift/Coordinate.swift +47 -0
- package/nitrogen/generated/ios/swift/EdgePadding.swift +69 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_Camera.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_ClusterPressEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_MapBoundaries.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_MapError.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_MapPressEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_MarkerDragEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_MarkerPressEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RegionChangeEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridNitroMapConfigSpec.swift +57 -0
- package/nitrogen/generated/ios/swift/HybridNitroMapConfigSpec_cxx.swift +142 -0
- package/nitrogen/generated/ios/swift/HybridNitroMapSpec.swift +93 -0
- package/nitrogen/generated/ios/swift/HybridNitroMapSpec_cxx.swift +953 -0
- package/nitrogen/generated/ios/swift/ImageMarkerConfig.swift +166 -0
- package/nitrogen/generated/ios/swift/MapBoundaries.swift +47 -0
- package/nitrogen/generated/ios/swift/MapError.swift +47 -0
- package/nitrogen/generated/ios/swift/MapPressEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/MapProvider.swift +44 -0
- package/nitrogen/generated/ios/swift/MapStyleElement.swift +108 -0
- package/nitrogen/generated/ios/swift/MapStyler.swift +177 -0
- package/nitrogen/generated/ios/swift/MapType.swift +44 -0
- package/nitrogen/generated/ios/swift/MarkerAnimation.swift +44 -0
- package/nitrogen/generated/ios/swift/MarkerColor.swift +69 -0
- package/nitrogen/generated/ios/swift/MarkerConfig.swift +82 -0
- package/nitrogen/generated/ios/swift/MarkerData.swift +195 -0
- package/nitrogen/generated/ios/swift/MarkerDragEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/MarkerPressEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/MarkerStyle.swift +44 -0
- package/nitrogen/generated/ios/swift/Point.swift +47 -0
- package/nitrogen/generated/ios/swift/PriceMarkerStyle.swift +374 -0
- package/nitrogen/generated/ios/swift/Region.swift +69 -0
- package/nitrogen/generated/ios/swift/RegionChangeEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Variant_String_MarkerColor.swift +18 -0
- package/nitrogen/generated/shared/c++/Camera.hpp +92 -0
- package/nitrogen/generated/shared/c++/ClusterAnimationStyle.hpp +88 -0
- package/nitrogen/generated/shared/c++/ClusterConfig.hpp +140 -0
- package/nitrogen/generated/shared/c++/ClusterPressEvent.hpp +86 -0
- package/nitrogen/generated/shared/c++/ClusterStrategy.hpp +76 -0
- package/nitrogen/generated/shared/c++/Coordinate.hpp +79 -0
- package/nitrogen/generated/shared/c++/EdgePadding.hpp +87 -0
- package/nitrogen/generated/shared/c++/HybridNitroMapConfigSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridNitroMapConfigSpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridNitroMapSpec.cpp +82 -0
- package/nitrogen/generated/shared/c++/HybridNitroMapSpec.hpp +173 -0
- package/nitrogen/generated/shared/c++/ImageMarkerConfig.hpp +103 -0
- package/nitrogen/generated/shared/c++/MapBoundaries.hpp +80 -0
- package/nitrogen/generated/shared/c++/MapError.hpp +79 -0
- package/nitrogen/generated/shared/c++/MapPressEvent.hpp +83 -0
- package/nitrogen/generated/shared/c++/MapProvider.hpp +80 -0
- package/nitrogen/generated/shared/c++/MapStyleElement.hpp +87 -0
- package/nitrogen/generated/shared/c++/MapStyler.hpp +96 -0
- package/nitrogen/generated/shared/c++/MapType.hpp +80 -0
- package/nitrogen/generated/shared/c++/MarkerAnimation.hpp +80 -0
- package/nitrogen/generated/shared/c++/MarkerColor.hpp +87 -0
- package/nitrogen/generated/shared/c++/MarkerConfig.hpp +91 -0
- package/nitrogen/generated/shared/c++/MarkerData.hpp +131 -0
- package/nitrogen/generated/shared/c++/MarkerDragEvent.hpp +81 -0
- package/nitrogen/generated/shared/c++/MarkerPressEvent.hpp +81 -0
- package/nitrogen/generated/shared/c++/MarkerStyle.hpp +80 -0
- package/nitrogen/generated/shared/c++/Point.hpp +79 -0
- package/nitrogen/generated/shared/c++/PriceMarkerStyle.hpp +119 -0
- package/nitrogen/generated/shared/c++/Region.hpp +87 -0
- package/nitrogen/generated/shared/c++/RegionChangeEvent.hpp +80 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.cpp +351 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.hpp +141 -0
- package/nitrogen/generated/shared/json/NitroMapConfig.json +32 -0
- package/package.json +176 -0
- package/react-native.config.js +16 -0
- package/src/components/ImageMarker.tsx +254 -0
- package/src/components/NitroMap.tsx +433 -0
- package/src/components/PriceMarker.tsx +311 -0
- package/src/context/NitroMapContext.tsx +33 -0
- package/src/hooks/useNitroMarker.ts +198 -0
- package/src/index.tsx +62 -0
- package/src/modules/index.ts +6 -0
- package/src/modules/module.ts +45 -0
- package/src/specs/NitroMap.nitro.ts +292 -0
- package/src/specs/NitroMapConfig.nitro.ts +8 -0
- package/src/types/map.ts +166 -0
- package/src/types/marker.ts +267 -0
- package/src/utils/colors.ts +159 -0
package/cpp/KDBush.hpp
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <vector>
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <cmath>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
|
|
8
|
+
namespace nitromap {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* KDBush — a fast static 2D spatial index for flat coordinate arrays.
|
|
12
|
+
* Port of the JavaScript kdbush library used by Mapbox Supercluster.
|
|
13
|
+
*
|
|
14
|
+
* Build: O(n log n)
|
|
15
|
+
* Range: O(√n + k)
|
|
16
|
+
* Within: O(√n + k)
|
|
17
|
+
* Returns: flat array indices (not objects)
|
|
18
|
+
*/
|
|
19
|
+
class KDBush {
|
|
20
|
+
public:
|
|
21
|
+
KDBush() : nodeSize_(64) {}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Build the index from a flat coordinate array.
|
|
25
|
+
* @param coords Flat array [x0, y0, x1, y1, ...] of length numPoints*2
|
|
26
|
+
* @param numPoints Number of points
|
|
27
|
+
* @param nodeSize KD-tree leaf node size (default 64)
|
|
28
|
+
*/
|
|
29
|
+
void build(const std::vector<double>& coords, size_t numPoints, int nodeSize = 64) {
|
|
30
|
+
nodeSize_ = nodeSize;
|
|
31
|
+
numPoints_ = numPoints;
|
|
32
|
+
|
|
33
|
+
// Copy coordinates
|
|
34
|
+
coords_.resize(numPoints * 2);
|
|
35
|
+
for (size_t i = 0; i < numPoints * 2; i++) {
|
|
36
|
+
coords_[i] = coords[i];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Initialize indices [0, 1, 2, ...]
|
|
40
|
+
ids_.resize(numPoints);
|
|
41
|
+
for (size_t i = 0; i < numPoints; i++) {
|
|
42
|
+
ids_[i] = static_cast<int>(i);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Sort in KD-tree order
|
|
46
|
+
if (numPoints > 0) {
|
|
47
|
+
sortKD(0, static_cast<int>(numPoints) - 1, 0);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Find all point indices within a bounding box.
|
|
53
|
+
* @return Vector of original point indices
|
|
54
|
+
*/
|
|
55
|
+
std::vector<int> range(double minX, double minY, double maxX, double maxY) const {
|
|
56
|
+
std::vector<int> result;
|
|
57
|
+
if (numPoints_ == 0) return result;
|
|
58
|
+
|
|
59
|
+
std::vector<int> stack;
|
|
60
|
+
stack.push_back(0);
|
|
61
|
+
stack.push_back(static_cast<int>(numPoints_) - 1);
|
|
62
|
+
stack.push_back(0);
|
|
63
|
+
|
|
64
|
+
while (!stack.empty()) {
|
|
65
|
+
int axis = stack.back(); stack.pop_back();
|
|
66
|
+
int right = stack.back(); stack.pop_back();
|
|
67
|
+
int left = stack.back(); stack.pop_back();
|
|
68
|
+
|
|
69
|
+
if (right - left <= nodeSize_) {
|
|
70
|
+
// Linear scan of leaf
|
|
71
|
+
for (int i = left; i <= right; i++) {
|
|
72
|
+
double x = coords_[2 * i];
|
|
73
|
+
double y = coords_[2 * i + 1];
|
|
74
|
+
if (x >= minX && x <= maxX && y >= minY && y <= maxY) {
|
|
75
|
+
result.push_back(ids_[i]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
int mid = (left + right) >> 1;
|
|
82
|
+
double x = coords_[2 * mid];
|
|
83
|
+
double y = coords_[2 * mid + 1];
|
|
84
|
+
|
|
85
|
+
if (x >= minX && x <= maxX && y >= minY && y <= maxY) {
|
|
86
|
+
result.push_back(ids_[mid]);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
int nextAxis = (axis + 1) % 2;
|
|
90
|
+
|
|
91
|
+
if (axis == 0 ? minX <= x : minY <= y) {
|
|
92
|
+
stack.push_back(left);
|
|
93
|
+
stack.push_back(mid - 1);
|
|
94
|
+
stack.push_back(nextAxis);
|
|
95
|
+
}
|
|
96
|
+
if (axis == 0 ? maxX >= x : maxY >= y) {
|
|
97
|
+
stack.push_back(mid + 1);
|
|
98
|
+
stack.push_back(right);
|
|
99
|
+
stack.push_back(nextAxis);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Find all point indices within a circle.
|
|
108
|
+
* @return Vector of original point indices
|
|
109
|
+
*/
|
|
110
|
+
std::vector<int> within(double qx, double qy, double r) const {
|
|
111
|
+
std::vector<int> result;
|
|
112
|
+
if (numPoints_ == 0) return result;
|
|
113
|
+
|
|
114
|
+
double r2 = r * r;
|
|
115
|
+
|
|
116
|
+
std::vector<int> stack;
|
|
117
|
+
stack.push_back(0);
|
|
118
|
+
stack.push_back(static_cast<int>(numPoints_) - 1);
|
|
119
|
+
stack.push_back(0);
|
|
120
|
+
|
|
121
|
+
while (!stack.empty()) {
|
|
122
|
+
int axis = stack.back(); stack.pop_back();
|
|
123
|
+
int right = stack.back(); stack.pop_back();
|
|
124
|
+
int left = stack.back(); stack.pop_back();
|
|
125
|
+
|
|
126
|
+
if (right - left <= nodeSize_) {
|
|
127
|
+
for (int i = left; i <= right; i++) {
|
|
128
|
+
double dx = coords_[2 * i] - qx;
|
|
129
|
+
double dy = coords_[2 * i + 1] - qy;
|
|
130
|
+
if (dx * dx + dy * dy <= r2) {
|
|
131
|
+
result.push_back(ids_[i]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
int mid = (left + right) >> 1;
|
|
138
|
+
double x = coords_[2 * mid];
|
|
139
|
+
double y = coords_[2 * mid + 1];
|
|
140
|
+
|
|
141
|
+
double dx = x - qx;
|
|
142
|
+
double dy = y - qy;
|
|
143
|
+
if (dx * dx + dy * dy <= r2) {
|
|
144
|
+
result.push_back(ids_[mid]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
int nextAxis = (axis + 1) % 2;
|
|
148
|
+
|
|
149
|
+
if (axis == 0 ? qx - r <= x : qy - r <= y) {
|
|
150
|
+
stack.push_back(left);
|
|
151
|
+
stack.push_back(mid - 1);
|
|
152
|
+
stack.push_back(nextAxis);
|
|
153
|
+
}
|
|
154
|
+
if (axis == 0 ? qx + r >= x : qy + r >= y) {
|
|
155
|
+
stack.push_back(mid + 1);
|
|
156
|
+
stack.push_back(right);
|
|
157
|
+
stack.push_back(nextAxis);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
size_t size() const { return numPoints_; }
|
|
165
|
+
|
|
166
|
+
private:
|
|
167
|
+
void sortKD(int left, int right, int depth) {
|
|
168
|
+
if (right <= left) return;
|
|
169
|
+
|
|
170
|
+
int mid = (left + right) >> 1;
|
|
171
|
+
int axis = depth % 2;
|
|
172
|
+
|
|
173
|
+
// Select median using nth_element-style partitioning
|
|
174
|
+
select(left, right, mid, axis);
|
|
175
|
+
|
|
176
|
+
// Recurse
|
|
177
|
+
sortKD(left, mid - 1, depth + 1);
|
|
178
|
+
sortKD(mid + 1, right, depth + 1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
void select(int left, int right, int k, int axis) {
|
|
182
|
+
// Floyd-Rivest selection algorithm (simplified)
|
|
183
|
+
while (right > left) {
|
|
184
|
+
if (right - left > 600) {
|
|
185
|
+
int n = right - left + 1;
|
|
186
|
+
int m = k - left + 1;
|
|
187
|
+
double z = std::log(static_cast<double>(n));
|
|
188
|
+
double s = 0.5 * std::exp(2.0 * z / 3.0);
|
|
189
|
+
double sd = 0.5 * std::sqrt(z * s * (n - s) / n) * (2.0 * m - n < 0 ? -1.0 : 1.0);
|
|
190
|
+
int newLeft = std::max(left, static_cast<int>(k - m * s / n + sd));
|
|
191
|
+
int newRight = std::min(right, static_cast<int>(k + (n - m) * s / n + sd));
|
|
192
|
+
select(newLeft, newRight, k, axis);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
double t = (axis == 0) ? coords_[2 * k] : coords_[2 * k + 1];
|
|
196
|
+
int i = left;
|
|
197
|
+
int j = right;
|
|
198
|
+
|
|
199
|
+
swapItem(left, k);
|
|
200
|
+
if (getVal(right, axis) > t) swapItem(left, right);
|
|
201
|
+
|
|
202
|
+
while (i < j) {
|
|
203
|
+
swapItem(i, j);
|
|
204
|
+
i++;
|
|
205
|
+
j--;
|
|
206
|
+
while (getVal(i, axis) < t) i++;
|
|
207
|
+
while (getVal(j, axis) > t) j--;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (getVal(left, axis) == t) {
|
|
211
|
+
swapItem(left, j);
|
|
212
|
+
} else {
|
|
213
|
+
j++;
|
|
214
|
+
swapItem(j, right);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (j <= k) left = j + 1;
|
|
218
|
+
if (k <= j) right = j - 1;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
double getVal(int idx, int axis) const {
|
|
223
|
+
return coords_[2 * idx + axis];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
void swapItem(int i, int j) {
|
|
227
|
+
std::swap(ids_[i], ids_[j]);
|
|
228
|
+
std::swap(coords_[2 * i], coords_[2 * j]);
|
|
229
|
+
std::swap(coords_[2 * i + 1], coords_[2 * j + 1]);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
std::vector<double> coords_;
|
|
233
|
+
std::vector<int> ids_;
|
|
234
|
+
int nodeSize_;
|
|
235
|
+
size_t numPoints_;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
} // namespace nitromap
|
package/cpp/QuadTree.hpp
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <vector>
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <cmath>
|
|
6
|
+
#include <algorithm>
|
|
7
|
+
|
|
8
|
+
namespace nitromap {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Point structure for QuadTree
|
|
12
|
+
*/
|
|
13
|
+
struct Point {
|
|
14
|
+
double x; // longitude
|
|
15
|
+
double y; // latitude
|
|
16
|
+
std::string id;
|
|
17
|
+
|
|
18
|
+
Point() : x(0), y(0), id("") {}
|
|
19
|
+
Point(double x, double y, const std::string& id) : x(x), y(y), id(id) {}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Bounding box for spatial queries
|
|
24
|
+
*/
|
|
25
|
+
struct BoundingBox {
|
|
26
|
+
double minX, minY, maxX, maxY;
|
|
27
|
+
|
|
28
|
+
BoundingBox() : minX(0), minY(0), maxX(0), maxY(0) {}
|
|
29
|
+
BoundingBox(double minX, double minY, double maxX, double maxY)
|
|
30
|
+
: minX(minX), minY(minY), maxX(maxX), maxY(maxY) {}
|
|
31
|
+
|
|
32
|
+
inline bool contains(const Point& p) const {
|
|
33
|
+
return p.x >= minX && p.x <= maxX && p.y >= minY && p.y <= maxY;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
inline bool intersects(const BoundingBox& other) const {
|
|
37
|
+
return !(other.minX > maxX || other.maxX < minX ||
|
|
38
|
+
other.minY > maxY || other.maxY < minY);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
inline double centerX() const { return (minX + maxX) / 2.0; }
|
|
42
|
+
inline double centerY() const { return (minY + maxY) / 2.0; }
|
|
43
|
+
inline double width() const { return maxX - minX; }
|
|
44
|
+
inline double height() const { return maxY - minY; }
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* QuadTree for efficient spatial indexing
|
|
49
|
+
* Provides O(log n) insert and query operations
|
|
50
|
+
*/
|
|
51
|
+
class QuadTree {
|
|
52
|
+
public:
|
|
53
|
+
static constexpr int MAX_POINTS = 4;
|
|
54
|
+
static constexpr int MAX_DEPTH = 12;
|
|
55
|
+
|
|
56
|
+
QuadTree(const BoundingBox& bounds, int depth = 0)
|
|
57
|
+
: bounds_(bounds), depth_(depth), divided_(false) {}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Insert a point into the QuadTree
|
|
61
|
+
* @return true if inserted successfully
|
|
62
|
+
*/
|
|
63
|
+
bool insert(const Point& point) {
|
|
64
|
+
// Point outside bounds
|
|
65
|
+
if (!bounds_.contains(point)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If we have capacity and haven't subdivided, add here
|
|
70
|
+
if (points_.size() < MAX_POINTS && !divided_) {
|
|
71
|
+
points_.push_back(point);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Subdivide if we haven't already and we're not at max depth
|
|
76
|
+
if (!divided_ && depth_ < MAX_DEPTH) {
|
|
77
|
+
subdivide();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// If we've subdivided, try to insert into children
|
|
81
|
+
if (divided_) {
|
|
82
|
+
if (nw_->insert(point)) return true;
|
|
83
|
+
if (ne_->insert(point)) return true;
|
|
84
|
+
if (sw_->insert(point)) return true;
|
|
85
|
+
if (se_->insert(point)) return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// If we're at max depth, just add to this node
|
|
89
|
+
points_.push_back(point);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Query all points within a bounding box
|
|
95
|
+
* @param range The bounding box to query
|
|
96
|
+
* @param found Vector to store found points
|
|
97
|
+
*/
|
|
98
|
+
void query(const BoundingBox& range, std::vector<Point>& found) const {
|
|
99
|
+
// Range doesn't intersect this quad
|
|
100
|
+
if (!bounds_.intersects(range)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check points in this node
|
|
105
|
+
for (const auto& point : points_) {
|
|
106
|
+
if (range.contains(point)) {
|
|
107
|
+
found.push_back(point);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Recurse into children
|
|
112
|
+
if (divided_) {
|
|
113
|
+
nw_->query(range, found);
|
|
114
|
+
ne_->query(range, found);
|
|
115
|
+
sw_->query(range, found);
|
|
116
|
+
se_->query(range, found);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Query all points within a radius of a center point
|
|
122
|
+
* Uses squared distance for efficiency (no sqrt)
|
|
123
|
+
*/
|
|
124
|
+
void queryRadius(double centerX, double centerY, double radius,
|
|
125
|
+
std::vector<Point>& found) const {
|
|
126
|
+
// Create bounding box around circle for initial filter
|
|
127
|
+
BoundingBox range(
|
|
128
|
+
centerX - radius, centerY - radius,
|
|
129
|
+
centerX + radius, centerY + radius
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (!bounds_.intersects(range)) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
double radiusSquared = radius * radius;
|
|
137
|
+
|
|
138
|
+
// Check points in this node
|
|
139
|
+
for (const auto& point : points_) {
|
|
140
|
+
double dx = point.x - centerX;
|
|
141
|
+
double dy = point.y - centerY;
|
|
142
|
+
if (dx * dx + dy * dy <= radiusSquared) {
|
|
143
|
+
found.push_back(point);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Recurse into children
|
|
148
|
+
if (divided_) {
|
|
149
|
+
nw_->queryRadius(centerX, centerY, radius, found);
|
|
150
|
+
ne_->queryRadius(centerX, centerY, radius, found);
|
|
151
|
+
sw_->queryRadius(centerX, centerY, radius, found);
|
|
152
|
+
se_->queryRadius(centerX, centerY, radius, found);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get all points in the tree
|
|
158
|
+
*/
|
|
159
|
+
void getAllPoints(std::vector<Point>& allPoints) const {
|
|
160
|
+
for (const auto& point : points_) {
|
|
161
|
+
allPoints.push_back(point);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (divided_) {
|
|
165
|
+
nw_->getAllPoints(allPoints);
|
|
166
|
+
ne_->getAllPoints(allPoints);
|
|
167
|
+
sw_->getAllPoints(allPoints);
|
|
168
|
+
se_->getAllPoints(allPoints);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Clear all points from the tree
|
|
174
|
+
*/
|
|
175
|
+
void clear() {
|
|
176
|
+
points_.clear();
|
|
177
|
+
divided_ = false;
|
|
178
|
+
nw_.reset();
|
|
179
|
+
ne_.reset();
|
|
180
|
+
sw_.reset();
|
|
181
|
+
se_.reset();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get total number of points
|
|
186
|
+
*/
|
|
187
|
+
size_t size() const {
|
|
188
|
+
size_t count = points_.size();
|
|
189
|
+
if (divided_) {
|
|
190
|
+
count += nw_->size() + ne_->size() + sw_->size() + se_->size();
|
|
191
|
+
}
|
|
192
|
+
return count;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private:
|
|
196
|
+
void subdivide() {
|
|
197
|
+
double cx = bounds_.centerX();
|
|
198
|
+
double cy = bounds_.centerY();
|
|
199
|
+
|
|
200
|
+
// Northwest (top-left)
|
|
201
|
+
nw_ = std::make_unique<QuadTree>(
|
|
202
|
+
BoundingBox(bounds_.minX, cy, cx, bounds_.maxY),
|
|
203
|
+
depth_ + 1
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// Northeast (top-right)
|
|
207
|
+
ne_ = std::make_unique<QuadTree>(
|
|
208
|
+
BoundingBox(cx, cy, bounds_.maxX, bounds_.maxY),
|
|
209
|
+
depth_ + 1
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Southwest (bottom-left)
|
|
213
|
+
sw_ = std::make_unique<QuadTree>(
|
|
214
|
+
BoundingBox(bounds_.minX, bounds_.minY, cx, cy),
|
|
215
|
+
depth_ + 1
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// Southeast (bottom-right)
|
|
219
|
+
se_ = std::make_unique<QuadTree>(
|
|
220
|
+
BoundingBox(cx, bounds_.minY, bounds_.maxX, cy),
|
|
221
|
+
depth_ + 1
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
divided_ = true;
|
|
225
|
+
|
|
226
|
+
// Move existing points to children
|
|
227
|
+
std::vector<Point> oldPoints = std::move(points_);
|
|
228
|
+
points_.clear();
|
|
229
|
+
|
|
230
|
+
for (const auto& point : oldPoints) {
|
|
231
|
+
if (!nw_->insert(point) && !ne_->insert(point) &&
|
|
232
|
+
!sw_->insert(point) && !se_->insert(point)) {
|
|
233
|
+
// Shouldn't happen, but keep point here if it fails
|
|
234
|
+
points_.push_back(point);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
BoundingBox bounds_;
|
|
240
|
+
int depth_;
|
|
241
|
+
bool divided_;
|
|
242
|
+
std::vector<Point> points_;
|
|
243
|
+
std::unique_ptr<QuadTree> nw_, ne_, sw_, se_;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
} // namespace nitromap
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <CoreLocation/CoreLocation.h>
|
|
3
|
+
|
|
4
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
5
|
+
|
|
6
|
+
/// Single marker point returned from clustering
|
|
7
|
+
@interface ClusterMarkerPoint : NSObject
|
|
8
|
+
@property (nonatomic, copy) NSString *markerId;
|
|
9
|
+
@property (nonatomic, assign) double latitude;
|
|
10
|
+
@property (nonatomic, assign) double longitude;
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
/// Cluster result containing multiple markers
|
|
14
|
+
@interface ClusterData : NSObject
|
|
15
|
+
@property (nonatomic, assign) double latitude;
|
|
16
|
+
@property (nonatomic, assign) double longitude;
|
|
17
|
+
@property (nonatomic, strong) NSArray<NSString *> *markerIds;
|
|
18
|
+
@property (nonatomic, assign) NSInteger count;
|
|
19
|
+
@property (nonatomic, assign) double iconSize;
|
|
20
|
+
@end
|
|
21
|
+
|
|
22
|
+
/// Full clustering result
|
|
23
|
+
@interface ClusteringResult : NSObject
|
|
24
|
+
@property (nonatomic, strong) NSArray<ClusterData *> *clusters;
|
|
25
|
+
@property (nonatomic, strong) NSArray<ClusterMarkerPoint *> *singleMarkers;
|
|
26
|
+
@end
|
|
27
|
+
|
|
28
|
+
/// Objective-C++ wrapper for C++ ClusterEngine.
|
|
29
|
+
/// Pure spatial grouping — no icon dimensions.
|
|
30
|
+
@interface ClusterEngineWrapper : NSObject
|
|
31
|
+
|
|
32
|
+
- (instancetype)init;
|
|
33
|
+
|
|
34
|
+
/// Configuration
|
|
35
|
+
- (void)setClusterRadius:(double)radiusPixels;
|
|
36
|
+
- (void)setMinClusterSize:(NSInteger)size;
|
|
37
|
+
- (void)setMaxZoom:(double)zoom;
|
|
38
|
+
|
|
39
|
+
/// Marker management — only geographic data
|
|
40
|
+
- (void)addMarkerWithId:(NSString *)markerId
|
|
41
|
+
latitude:(double)latitude
|
|
42
|
+
longitude:(double)longitude;
|
|
43
|
+
- (void)removeMarkerWithId:(NSString *)markerId;
|
|
44
|
+
- (void)clearMarkers;
|
|
45
|
+
- (NSUInteger)markerCount;
|
|
46
|
+
|
|
47
|
+
/// Perform clustering
|
|
48
|
+
- (ClusteringResult *)clusterWithMinLat:(double)minLat
|
|
49
|
+
maxLat:(double)maxLat
|
|
50
|
+
minLon:(double)minLon
|
|
51
|
+
maxLon:(double)maxLon
|
|
52
|
+
zoom:(double)zoom
|
|
53
|
+
mapWidth:(double)mapWidth
|
|
54
|
+
mapHeight:(double)mapHeight;
|
|
55
|
+
|
|
56
|
+
@end
|
|
57
|
+
|
|
58
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#import "ClusterEngineWrapper.h"
|
|
2
|
+
#include "ClusterEngine.hpp"
|
|
3
|
+
|
|
4
|
+
using namespace nitromap;
|
|
5
|
+
|
|
6
|
+
// MARK: - ClusterMarkerPoint
|
|
7
|
+
|
|
8
|
+
@implementation ClusterMarkerPoint
|
|
9
|
+
@end
|
|
10
|
+
|
|
11
|
+
// MARK: - ClusterData
|
|
12
|
+
|
|
13
|
+
@implementation ClusterData
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
// MARK: - ClusteringResult
|
|
17
|
+
|
|
18
|
+
@implementation ClusteringResult
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
// MARK: - ClusterEngineWrapper
|
|
22
|
+
|
|
23
|
+
@interface ClusterEngineWrapper () {
|
|
24
|
+
std::unique_ptr<ClusterEngine> _engine;
|
|
25
|
+
}
|
|
26
|
+
@end
|
|
27
|
+
|
|
28
|
+
@implementation ClusterEngineWrapper
|
|
29
|
+
|
|
30
|
+
- (instancetype)init {
|
|
31
|
+
self = [super init];
|
|
32
|
+
if (self) {
|
|
33
|
+
_engine = std::make_unique<ClusterEngine>();
|
|
34
|
+
}
|
|
35
|
+
return self;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
- (void)setClusterRadius:(double)radiusPixels {
|
|
39
|
+
if (_engine) {
|
|
40
|
+
_engine->setClusterRadius(radiusPixels);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
- (void)setMinClusterSize:(NSInteger)size {
|
|
45
|
+
if (_engine) {
|
|
46
|
+
_engine->setMinClusterSize(static_cast<int>(size));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
- (void)setMaxZoom:(double)zoom {
|
|
51
|
+
if (_engine) {
|
|
52
|
+
_engine->setMaxZoom(zoom);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
- (void)addMarkerWithId:(NSString *)markerId
|
|
57
|
+
latitude:(double)latitude
|
|
58
|
+
longitude:(double)longitude {
|
|
59
|
+
if (_engine && markerId) {
|
|
60
|
+
MarkerPoint marker(
|
|
61
|
+
[markerId UTF8String],
|
|
62
|
+
latitude,
|
|
63
|
+
longitude
|
|
64
|
+
);
|
|
65
|
+
_engine->addMarker(marker);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
- (void)removeMarkerWithId:(NSString *)markerId {
|
|
70
|
+
if (_engine && markerId) {
|
|
71
|
+
_engine->removeMarker([markerId UTF8String]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (void)clearMarkers {
|
|
76
|
+
if (_engine) {
|
|
77
|
+
_engine->clearMarkers();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (NSUInteger)markerCount {
|
|
82
|
+
if (_engine) {
|
|
83
|
+
return _engine->markerCount();
|
|
84
|
+
}
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Helper to convert C++ Cluster vector to NSArray<ClusterData*>
|
|
89
|
+
static NSArray<ClusterData *> *convertClusters(const std::vector<Cluster>& cppClusters) {
|
|
90
|
+
NSMutableArray<ClusterData *> *clusters = [NSMutableArray arrayWithCapacity:cppClusters.size()];
|
|
91
|
+
for (const auto& cluster : cppClusters) {
|
|
92
|
+
ClusterData *clusterData = [[ClusterData alloc] init];
|
|
93
|
+
clusterData.latitude = cluster.latitude;
|
|
94
|
+
clusterData.longitude = cluster.longitude;
|
|
95
|
+
clusterData.count = cluster.count;
|
|
96
|
+
clusterData.iconSize = Cluster::iconSize(cluster.count);
|
|
97
|
+
|
|
98
|
+
NSMutableArray<NSString *> *markerIds = [NSMutableArray arrayWithCapacity:cluster.markerIds.size()];
|
|
99
|
+
for (const auto& markerId : cluster.markerIds) {
|
|
100
|
+
[markerIds addObject:[NSString stringWithUTF8String:markerId.c_str()]];
|
|
101
|
+
}
|
|
102
|
+
clusterData.markerIds = markerIds;
|
|
103
|
+
[clusters addObject:clusterData];
|
|
104
|
+
}
|
|
105
|
+
return clusters;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
- (ClusteringResult *)clusterWithMinLat:(double)minLat
|
|
109
|
+
maxLat:(double)maxLat
|
|
110
|
+
minLon:(double)minLon
|
|
111
|
+
maxLon:(double)maxLon
|
|
112
|
+
zoom:(double)zoom
|
|
113
|
+
mapWidth:(double)mapWidth
|
|
114
|
+
mapHeight:(double)mapHeight {
|
|
115
|
+
ClusteringResult *result = [[ClusteringResult alloc] init];
|
|
116
|
+
result.clusters = @[];
|
|
117
|
+
result.singleMarkers = @[];
|
|
118
|
+
|
|
119
|
+
if (!_engine) {
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
ClusterResult cppResult = _engine->cluster(
|
|
124
|
+
minLat, maxLat, minLon, maxLon,
|
|
125
|
+
zoom, mapWidth, mapHeight
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
result.clusters = convertClusters(cppResult.clusters);
|
|
129
|
+
|
|
130
|
+
NSMutableArray<ClusterMarkerPoint *> *singleMarkers = [NSMutableArray arrayWithCapacity:cppResult.singleMarkers.size()];
|
|
131
|
+
for (const auto& marker : cppResult.singleMarkers) {
|
|
132
|
+
ClusterMarkerPoint *point = [[ClusterMarkerPoint alloc] init];
|
|
133
|
+
point.markerId = [NSString stringWithUTF8String:marker.id.c_str()];
|
|
134
|
+
point.latitude = marker.latitude;
|
|
135
|
+
point.longitude = marker.longitude;
|
|
136
|
+
[singleMarkers addObject:point];
|
|
137
|
+
}
|
|
138
|
+
result.singleMarkers = singleMarkers;
|
|
139
|
+
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
@end
|