Skip to content

Commit 920bba0

Browse files
ibesoragithub-actions[bot]
authored andcommitted
Support pitch and distance in filter expressions
GitOrigin-RevId: 2cf969518f29e817609e5ead69d22dd8dc18eadd
1 parent 8c6f20a commit 920bba0

5 files changed

Lines changed: 93 additions & 7 deletions

File tree

src/style-spec/expression/definitions/distance.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ class Distance implements Expression {
562562
}
563563
console.warn("Distance Expression: currently only evaluates valid Point/LineString/Polygon geometries.");
564564
} else {
565-
console.warn("Distance Expression: requirs valid feature and canonical information.");
565+
console.warn("Distance Expression: requires valid feature and canonical information.");
566566
}
567567
return null;
568568
}

src/style/style_layer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,10 @@ class StyleLayer extends Evented {
445445
return this._featureFilter.needFeature;
446446
}
447447

448+
dynamicFilterNeedsGeometry(): boolean {
449+
return this._featureFilter.needGeometry;
450+
}
451+
448452
getLayerRenderingStats(): LayerRenderingStats | null | undefined {
449453
return this._stats;
450454
}

src/symbol/placement.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import ONE_EM from './one_em';
1212
import * as projection from './projection';
1313
import {getAnchorAlignment, WritingMode} from './shaping';
1414
import {evaluateVariableOffset, getAnchorJustification} from './symbol_layout';
15+
import toEvaluationFeature from '../data/evaluation_feature';
1516
import {evaluateSizeForFeature, evaluateSizeForZoom} from './symbol_size';
1617
import {Elevation} from '../terrain/elevation';
1718

@@ -203,6 +204,7 @@ type ClippingData = {
203204
unwrappedTileID: UnwrappedTileID;
204205
dynamicFilter: FilterExpression;
205206
dynamicFilterNeedsFeature: boolean;
207+
needGeometry: boolean;
206208
};
207209

208210
type TileLayerParameters = {
@@ -307,6 +309,7 @@ export class Placement {
307309

308310
const dynamicFilter = styleLayer.dynamicFilter();
309311
const dynamicFilterNeedsFeature = styleLayer.dynamicFilterNeedsFeature();
312+
const dynamicFilterNeedsGeometry = styleLayer.dynamicFilterNeedsGeometry();
310313
const pixelsToTiles = this.transform.calculatePixelsToTileUnitsMatrix(tile);
311314

312315
const textLabelPlaneMatrix = projection.getLabelPlaneMatrixForPlacement(posMatrix,
@@ -340,7 +343,8 @@ export class Placement {
340343
clippingData = {
341344
unwrappedTileID,
342345
dynamicFilter,
343-
dynamicFilterNeedsFeature
346+
dynamicFilterNeedsFeature,
347+
needGeometry: dynamicFilterNeedsGeometry
344348
};
345349
}
346350

@@ -555,7 +559,7 @@ export class Placement {
555559

556560
const retainedQueryData = this.retainedQueryData[bucket.bucketInstanceId];
557561

558-
feature = latestFeatureIndex.loadFeature({
562+
const vtFeature = latestFeatureIndex.loadFeature({
559563
featureIndex: symbolInstance.featureIndex,
560564
bucketIndex: retainedQueryData.bucketIndex,
561565
sourceLayerIndex: retainedQueryData.sourceLayerIndex,
@@ -564,17 +568,23 @@ export class Placement {
564568

565569
// since we recreate the feature from raw tile data when there's a dynamic filter,
566570
// we have to patch it with localization info again
567-
const worldview = feature.properties ? feature.properties.worldview : null;
571+
const worldview = vtFeature.properties ? vtFeature.properties.worldview : null;
568572
if (bucket.localizable && bucket.worldview && typeof worldview === 'string') {
569573
if (worldview === 'all') {
570-
feature.properties['$localized'] = true;
574+
vtFeature.properties['$localized'] = true;
571575
} else if (worldview.split(',').includes(bucket.worldview)) {
572-
feature.properties['$localized'] = true;
573-
feature.properties['worldview'] = bucket.worldview;
576+
vtFeature.properties['$localized'] = true;
577+
vtFeature.properties['worldview'] = bucket.worldview;
574578
} else {
575579
return;
576580
}
577581
}
582+
583+
// If the dynamic filter contains geometry-dependent expressions (e.g. 'distance'),
584+
// the raw VectorTileFeature won't have a 'geometry' property — only a loadGeometry()
585+
// method — so EvaluationContext.geometry() would return null. Convert to an
586+
// EvaluationFeature so the geometry is available as a plain property.
587+
feature = (clippingData && clippingData.needGeometry) ? toEvaluationFeature(vtFeature, true) : vtFeature;
578588
}
579589

580590
if (clippingData) {
3.11 KB
Loading
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"version": 8,
3+
"metadata": {
4+
"test": {
5+
"height": 200,
6+
"width": 300,
7+
"allowed": 0.001,
8+
"operations": [["wait"]]
9+
}
10+
},
11+
"center": [0, 0],
12+
"zoom": 13,
13+
"pitch": 30,
14+
"glyphs": "local://glyphs/{fontstack}/{range}.pbf",
15+
"sources": {
16+
"points": {
17+
"type": "geojson",
18+
"data": {
19+
"type": "FeatureCollection",
20+
"features": [
21+
{
22+
"type": "Feature",
23+
"properties": {"label": "near"},
24+
"geometry": {"type": "Point", "coordinates": [0.001, 0]}
25+
},
26+
{
27+
"type": "Feature",
28+
"properties": {"label": "near"},
29+
"geometry": {"type": "Point", "coordinates": [-0.001, 0]}
30+
},
31+
{
32+
"type": "Feature",
33+
"properties": {"label": "far"},
34+
"geometry": {"type": "Point", "coordinates": [0.005, 0]}
35+
},
36+
{
37+
"type": "Feature",
38+
"properties": {"label": "far"},
39+
"geometry": {"type": "Point", "coordinates": [-0.005, 0]}
40+
}
41+
]
42+
}
43+
}
44+
},
45+
"layers": [
46+
{
47+
"id": "background",
48+
"type": "background",
49+
"paint": {"background-color": "white"}
50+
},
51+
{
52+
"id": "symbols",
53+
"type": "symbol",
54+
"source": "points",
55+
"filter": [
56+
"all",
57+
["case", ["<", ["pitch"], 60], true, false],
58+
[">", ["distance", {"type": "Point", "coordinates": [0, 0]}], 300]
59+
],
60+
"layout": {
61+
"text-field": ["get", "label"],
62+
"text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
63+
"text-size": 14,
64+
"text-allow-overlap": true,
65+
"text-pitch-alignment": "viewport"
66+
},
67+
"paint": {
68+
"text-color": "red"
69+
}
70+
}
71+
]
72+
}

0 commit comments

Comments
 (0)