UNPKG

4.74 kBPlain TextView Raw
1import StyleLayer from '../style_layer';
2
3import CircleBucket from '../../data/bucket/circle_bucket';
4import {polygonIntersectsBufferedPoint} from '../../util/intersection_tests';
5import {getMaximumPaintValue, translateDistance, translate} from '../query_utils';
6import properties, {CircleLayoutPropsPossiblyEvaluated, CirclePaintPropsPossiblyEvaluated} from './circle_style_layer_properties.g';
7import {Transitionable, Transitioning, Layout, PossiblyEvaluated} from '../properties';
8import {mat4, vec4} from 'gl-matrix';
9import Point from '@mapbox/point-geometry';
10import type {FeatureState} from '../../style-spec/expression';
11import type Transform from '../../geo/transform';
12import type {Bucket, BucketParameters} from '../../data/bucket';
13import type {CircleLayoutProps, CirclePaintProps} from './circle_style_layer_properties.g';
14import type {LayerSpecification} from '../../style-spec/types.g';
15import type {VectorTileFeature} from '@mapbox/vector-tile';
16
17class CircleStyleLayer extends StyleLayer {
18 _unevaluatedLayout: Layout<CircleLayoutProps>;
19 layout: PossiblyEvaluated<CircleLayoutProps, CircleLayoutPropsPossiblyEvaluated>;
20
21 _transitionablePaint: Transitionable<CirclePaintProps>;
22 _transitioningPaint: Transitioning<CirclePaintProps>;
23 paint: PossiblyEvaluated<CirclePaintProps, CirclePaintPropsPossiblyEvaluated>;
24
25 constructor(layer: LayerSpecification) {
26 super(layer, properties);
27 }
28
29 createBucket(parameters: BucketParameters<any>) {
30 return new CircleBucket(parameters);
31 }
32
33 queryRadius(bucket: Bucket): number {
34 const circleBucket: CircleBucket<CircleStyleLayer> = (bucket as any);
35 return getMaximumPaintValue('circle-radius', this, circleBucket) +
36 getMaximumPaintValue('circle-stroke-width', this, circleBucket) +
37 translateDistance(this.paint.get('circle-translate'));
38 }
39
40 queryIntersectsFeature(
41 queryGeometry: Array<Point>,
42 feature: VectorTileFeature,
43 featureState: FeatureState,
44 geometry: Array<Array<Point>>,
45 zoom: number,
46 transform: Transform,
47 pixelsToTileUnits: number,
48 pixelPosMatrix: mat4
49 ): boolean {
50 const translatedPolygon = translate(queryGeometry,
51 this.paint.get('circle-translate'),
52 this.paint.get('circle-translate-anchor'),
53 transform.angle, pixelsToTileUnits);
54 const radius = this.paint.get('circle-radius').evaluate(feature, featureState);
55 const stroke = this.paint.get('circle-stroke-width').evaluate(feature, featureState);
56 const size = radius + stroke;
57
58 // For pitch-alignment: map, compare feature geometry to query geometry in the plane of the tile
59 // // Otherwise, compare geometry in the plane of the viewport
60 // // A circle with fixed scaling relative to the viewport gets larger in tile space as it moves into the distance
61 // // A circle with fixed scaling relative to the map gets smaller in viewport space as it moves into the distance
62 const alignWithMap = this.paint.get('circle-pitch-alignment') === 'map';
63 const transformedPolygon = alignWithMap ? translatedPolygon : projectQueryGeometry(translatedPolygon, pixelPosMatrix);
64 const transformedSize = alignWithMap ? size * pixelsToTileUnits : size;
65
66 for (const ring of geometry) {
67 for (const point of ring) {
68
69 const transformedPoint = alignWithMap ? point : projectPoint(point, pixelPosMatrix);
70
71 let adjustedSize = transformedSize;
72 const projectedCenter = vec4.transformMat4([] as any, [point.x, point.y, 0, 1], pixelPosMatrix);
73 if (this.paint.get('circle-pitch-scale') === 'viewport' && this.paint.get('circle-pitch-alignment') === 'map') {
74 adjustedSize *= projectedCenter[3] / transform.cameraToCenterDistance;
75 } else if (this.paint.get('circle-pitch-scale') === 'map' && this.paint.get('circle-pitch-alignment') === 'viewport') {
76 adjustedSize *= transform.cameraToCenterDistance / projectedCenter[3];
77 }
78
79 if (polygonIntersectsBufferedPoint(transformedPolygon, transformedPoint, adjustedSize)) return true;
80 }
81 }
82
83 return false;
84 }
85}
86
87function projectPoint(p: Point, pixelPosMatrix: mat4) {
88 const point = vec4.transformMat4([] as any, [p.x, p.y, 0, 1], pixelPosMatrix);
89 return new Point(point[0] / point[3], point[1] / point[3]);
90}
91
92function projectQueryGeometry(queryGeometry: Array<Point>, pixelPosMatrix: mat4) {
93 return queryGeometry.map((p) => {
94 return projectPoint(p, pixelPosMatrix);
95 });
96}
97
98export default CircleStyleLayer;