From c5aea580a847b372c02ac0588ae9b6c7784d96f8 Mon Sep 17 00:00:00 2001 From: Ewelina Betlejewska-Szulc Date: Fri, 5 Jan 2024 12:34:23 +0100 Subject: [PATCH 1/3] Add array type for storing coordinate values to allow improving accuracy for small radius --- README.md | 21 +++++++++++---------- index.js | 8 +++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1965e0e..d350bf1 100644 --- a/README.md +++ b/README.md @@ -63,16 +63,17 @@ Returns the zoom on which the cluster expands into several children (useful for ## Options -| Option | Default | Description | -|------------|---------|-------------------------------------------------------------------| -| minZoom | 0 | Minimum zoom level at which clusters are generated. | -| maxZoom | 16 | Maximum zoom level at which clusters are generated. | -| minPoints | 2 | Minimum number of points to form a cluster. | -| radius | 40 | Cluster radius, in pixels. | -| extent | 512 | (Tiles) Tile extent. Radius is calculated relative to this value. | -| nodeSize | 64 | Size of the KD-tree leaf node. Affects performance. | -| log | false | Whether timing info should be logged. | -| generateId | false | Whether to generate ids for input features in vector tiles. | +| Option | Default | Description | +|------------|--------------|------------------------------------------------------------------------------------| +| minZoom | 0 | Minimum zoom level at which clusters are generated. | +| maxZoom | 16 | Maximum zoom level at which clusters are generated. | +| minPoints | 2 | Minimum number of points to form a cluster. | +| radius | 40 | Cluster radius, in pixels. | +| extent | 512 | (Tiles) Tile extent. Radius is calculated relative to this value. | +| nodeSize | 64 | Size of the KD-tree leaf node. Affects performance. | +| arrayType | Float32Array | Array type to use for storing coordinate values. Affects accuracy for small radius | +| log | false | Whether timing info should be logged. | +| generateId | false | Whether to generate ids for input features in vector tiles. | ### Property map/reduce options diff --git a/index.js b/index.js index 4dce8d3..fb2021c 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ const defaultOptions = { radius: 40, // cluster radius in pixels extent: 512, // tile extent (radius is calculated relative to it) nodeSize: 64, // size of the KD-tree leaf node, affects performance + arrayType: Float32Array, // Array type to use for storing coordinate values. Affects accuracy for small radius log: false, // whether to log timing info // whether to generate numeric ids for input features (in vector tiles) @@ -34,6 +35,7 @@ export default class Supercluster { this.trees = new Array(this.options.maxZoom + 1); this.stride = this.options.reduce ? 7 : 6; this.clusterProps = []; + this.coordinateRoundFn = this.options.arrayType === Float32Array ? fround : (x => x); } load(points) { @@ -54,8 +56,8 @@ export default class Supercluster { if (!p.geometry) continue; const [lng, lat] = p.geometry.coordinates; - const x = fround(lngX(lng)); - const y = fround(latY(lat)); + const x = this.coordinateRoundFn(lngX(lng)); + const y = this.coordinateRoundFn(latY(lat)); // store internal point/cluster data in flat numeric arrays for performance data.push( x, y, // projected point coordinates @@ -220,7 +222,7 @@ export default class Supercluster { } _createTree(data) { - const tree = new KDBush(data.length / this.stride | 0, this.options.nodeSize, Float32Array); + const tree = new KDBush(data.length / this.stride | 0, this.options.nodeSize, this.options.arrayType); for (let i = 0; i < data.length; i += this.stride) tree.add(data[i], data[i + 1]); tree.finish(); tree.data = data; From a96bbae392e3f236a57ce16342bc9130c8d2db46 Mon Sep 17 00:00:00 2001 From: Andrew Harvey Date: Thu, 15 Aug 2024 15:06:17 +1000 Subject: [PATCH 2/3] consisent documentation formatting --- README.md | 22 +++++++++++----------- index.js | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d350bf1..5d644be 100644 --- a/README.md +++ b/README.md @@ -63,17 +63,17 @@ Returns the zoom on which the cluster expands into several children (useful for ## Options -| Option | Default | Description | -|------------|--------------|------------------------------------------------------------------------------------| -| minZoom | 0 | Minimum zoom level at which clusters are generated. | -| maxZoom | 16 | Maximum zoom level at which clusters are generated. | -| minPoints | 2 | Minimum number of points to form a cluster. | -| radius | 40 | Cluster radius, in pixels. | -| extent | 512 | (Tiles) Tile extent. Radius is calculated relative to this value. | -| nodeSize | 64 | Size of the KD-tree leaf node. Affects performance. | -| arrayType | Float32Array | Array type to use for storing coordinate values. Affects accuracy for small radius | -| log | false | Whether timing info should be logged. | -| generateId | false | Whether to generate ids for input features in vector tiles. | +| Option | Default | Description | +|------------|--------------|-------------------------------------------------------------------------------------| +| minZoom | 0 | Minimum zoom level at which clusters are generated. | +| maxZoom | 16 | Maximum zoom level at which clusters are generated. | +| minPoints | 2 | Minimum number of points to form a cluster. | +| radius | 40 | Cluster radius, in pixels. | +| extent | 512 | (Tiles) Tile extent. Radius is calculated relative to this value. | +| nodeSize | 64 | Size of the KD-tree leaf node. Affects performance. | +| arrayType | Float32Array | TypedArray to use for storing coordinate values. Affects accuracy for small radius. | +| log | false | Whether timing info should be logged. | +| generateId | false | Whether to generate ids for input features in vector tiles. | ### Property map/reduce options diff --git a/index.js b/index.js index fb2021c..671cbeb 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,7 @@ const defaultOptions = { radius: 40, // cluster radius in pixels extent: 512, // tile extent (radius is calculated relative to it) nodeSize: 64, // size of the KD-tree leaf node, affects performance - arrayType: Float32Array, // Array type to use for storing coordinate values. Affects accuracy for small radius + arrayType: Float32Array, // TypedArray to use for storing coordinate values, affects accuracy for small radius log: false, // whether to log timing info // whether to generate numeric ids for input features (in vector tiles) From 9126244a2c1d46d7bba98c3c0dcad604a5a750df Mon Sep 17 00:00:00 2001 From: Andrew Harvey Date: Thu, 15 Aug 2024 15:06:23 +1000 Subject: [PATCH 3/3] add test --- test/test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/test.js b/test/test.js index 5fb0510..a2c4fe8 100644 --- a/test/test.js +++ b/test/test.js @@ -179,3 +179,31 @@ test('does not throw on zero items', () => { assert.deepEqual(index.getClusters([-180, -85, 180, 85], 0), []); }); }); + +test('very close points which shouldn\'t cluster, are clustered when using Float32Array', () => { + const index = new Supercluster({ + maxZoom: 22, + extent: 8192, + radius: 4, + arrayType: Float32Array + }).load([ + {type: 'Feature', geometry: {type: 'Point', coordinates: [-1.426798, 53.943034]}}, + {type: 'Feature', geometry: {type: 'Point', coordinates: [-1.426799, 53.943034]}} + ]); + + assert.equal(index.trees[22].ids.length, 1); +}); + +test('very close points which shouldn\'t cluster, are not clustered when using Float64Array', () => { + const index = new Supercluster({ + maxZoom: 22, + extent: 8192, + radius: 4, + arrayType: Float64Array + }).load([ + {type: 'Feature', geometry: {type: 'Point', coordinates: [-1.426798, 53.943034]}}, + {type: 'Feature', geometry: {type: 'Point', coordinates: [-1.426799, 53.943034]}} + ]); + + assert.equal(index.trees[22].ids.length, 2); +});