@carto/api-client 0.5.7-alpha-optional-spatial-filter.0 → 0.5.7-alpha-optional-spatial-filter.1

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/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "homepage": "https://github.com/CartoDB/carto-api-client#readme",
9
9
  "author": "Don McCurdy <donmccurdy@carto.com>",
10
10
  "packageManager": "yarn@4.3.1",
11
- "version": "0.5.7-alpha-optional-spatial-filter.0",
11
+ "version": "0.5.7-alpha-optional-spatial-filter.1",
12
12
  "license": "MIT",
13
13
  "publishConfig": {
14
14
  "access": "public"
@@ -31,24 +31,26 @@ export function tileFeaturesSpatialIndex({
31
31
  return [];
32
32
  }
33
33
 
34
+ let intersection: undefined | boolean | Set<bigint | string>;
35
+
36
+ // Compute H3 intersection globally, Quadbin intersection per-tile. See tileIntersection.ts.
37
+ if (spatialIndex === SpatialIndex.H3) {
38
+ intersection = intersectTileH3(cellResolution as number, spatialFilter);
39
+ }
40
+
34
41
  for (const tile of tiles) {
35
42
  if (tile.isVisible === false || !tile.data) {
36
43
  continue;
37
44
  }
38
45
 
39
- const parent = getTileIndex(tile, spatialIndex);
40
- const intersection =
41
- spatialIndex === SpatialIndex.QUADBIN
42
- ? intersectTileQuadbin(
43
- parent as bigint,
44
- cellResolution as bigint,
45
- spatialFilter
46
- )
47
- : intersectTileH3(
48
- parent as string,
49
- cellResolution as number,
50
- spatialFilter
51
- );
46
+ if (spatialIndex === SpatialIndex.QUADBIN) {
47
+ const parent = getTileIndex(tile, spatialIndex);
48
+ intersection = intersectTileQuadbin(
49
+ parent as bigint,
50
+ cellResolution as bigint,
51
+ spatialFilter
52
+ );
53
+ }
52
54
 
53
55
  if (!intersection) continue;
54
56
 
@@ -1,4 +1,4 @@
1
- import type {BBox, Polygon} from 'geojson';
1
+ import type {BBox} from 'geojson';
2
2
  import type {SpatialFilter} from '../types.js';
3
3
  import bboxPolygon from '@turf/bbox-polygon';
4
4
  import booleanWithin from '@turf/boolean-within';
@@ -10,10 +10,7 @@ import {
10
10
  cellToBoundary as quadbinCellToBoundary,
11
11
  geometryToCells as quadbinGeometryToCells,
12
12
  } from 'quadbin';
13
- import {
14
- cellToBoundary as h3CellToBoundary,
15
- polygonToCells as h3PolygonToCells,
16
- } from 'h3-js';
13
+ import {polygonToCells as h3PolygonToCells} from 'h3-js';
17
14
  import bboxClip from '@turf/bbox-clip';
18
15
 
19
16
  // Computes intersections between spatial filters and tiles in various formats,
@@ -29,8 +26,13 @@ import bboxClip from '@turf/bbox-clip';
29
26
  // Computing a covering set for spatial indexes may be very expensive for large
30
27
  // spatial filters and small cell resolutions. For example, a viewport at z=3
31
28
  // would contain ~18,000,000 raster cells at resolution=14. To avoid ever
32
- // creating a covering set of this size, do filtering per-tile, not globally,
33
- // and skip the covering for tiles fully inside or outside the spatial filter.
29
+ // creating a covering set of this size, compute per-tile (not global) coverings
30
+ // when possible. For tiles fully inside or outside the spatial filter, creating
31
+ // a covering set can be skipped.
32
+ //
33
+ // H3 is currently a special case where coverage must be computed for the entire
34
+ // spatial filter; per-tile coverage would return a different result, because
35
+ // H3 child cells are not fully contained within their parents.
34
36
 
35
37
  ///////////////////////////////////////////////////////////////////////////////
36
38
  // GEOMETRY
@@ -113,33 +115,28 @@ const BBOX_EAST: BBox = [0, -90, 180, 90];
113
115
 
114
116
  /** @internal */
115
117
  export function intersectTileH3(
116
- parent: string,
117
118
  cellResolution: number,
118
119
  spatialFilter?: SpatialFilter
119
- ): boolean | Set<string> {
120
- const tilePolygon: Polygon = {
121
- type: 'Polygon',
122
- coordinates: [h3CellToBoundary(parent, true)],
123
- };
124
-
125
- if (!spatialFilter || booleanWithin(tilePolygon, spatialFilter)) {
120
+ ): true | Set<string> {
121
+ if (!spatialFilter) {
126
122
  return true;
127
123
  }
128
124
 
129
- const clippedSpatialFilter = intersect(
130
- featureCollection([feature(tilePolygon), feature(spatialFilter)])
131
- );
125
+ // Unlike quadbin and raster tiles, H3 children do not align to the parent's
126
+ // boundaries. Per-tile coverage with `h3PolygonToCells` would return only
127
+ // cells with _centers_ inside the clipped polygon — fewer cells. So for H3
128
+ // we compute the coverage set for the entire spatial filter (more expensive).
129
+ // In the future this could be replaced with `polygonToCellsExperimental`,
130
+ // which can compute child cells in different modes.
132
131
 
133
- if (!clippedSpatialFilter) {
134
- return false;
135
- }
132
+ const spatialFilterFeature = feature(spatialFilter);
136
133
 
137
134
  // The current H3 polyfill algorithm can't deal with polygon segments of greater than 180 degrees longitude
138
135
  // so we clip the geometry to be sure that none of them is greater than 180 degrees
139
136
  // https://github.com/uber/h3-js/issues/24#issuecomment-431893796
140
137
 
141
138
  const cellsWest = h3PolygonToCells(
142
- bboxClip(clippedSpatialFilter, BBOX_WEST).geometry.coordinates as
139
+ bboxClip(spatialFilterFeature, BBOX_WEST).geometry.coordinates as
143
140
  | number[][]
144
141
  | number[][][],
145
142
  cellResolution,
@@ -147,7 +144,7 @@ export function intersectTileH3(
147
144
  );
148
145
 
149
146
  const cellsEast = h3PolygonToCells(
150
- bboxClip(clippedSpatialFilter, BBOX_EAST).geometry.coordinates as
147
+ bboxClip(spatialFilterFeature, BBOX_EAST).geometry.coordinates as
151
148
  | number[][]
152
149
  | number[][][],
153
150
  cellResolution,