1 | import StyleLayer from '../style_layer';
|
2 |
|
3 | import CircleBucket from '../../data/bucket/circle_bucket';
|
4 | import {polygonIntersectsBufferedPoint} from '../../util/intersection_tests';
|
5 | import {getMaximumPaintValue, translateDistance, translate} from '../query_utils';
|
6 | import properties, {CircleLayoutPropsPossiblyEvaluated, CirclePaintPropsPossiblyEvaluated} from './circle_style_layer_properties.g';
|
7 | import {Transitionable, Transitioning, Layout, PossiblyEvaluated} from '../properties';
|
8 | import {mat4, vec4} from 'gl-matrix';
|
9 | import Point from '@mapbox/point-geometry';
|
10 | import type {FeatureState} from '../../style-spec/expression';
|
11 | import type Transform from '../../geo/transform';
|
12 | import type {Bucket, BucketParameters} from '../../data/bucket';
|
13 | import type {CircleLayoutProps, CirclePaintProps} from './circle_style_layer_properties.g';
|
14 | import type {LayerSpecification} from '../../style-spec/types.g';
|
15 | import type {VectorTileFeature} from '@mapbox/vector-tile';
|
16 |
|
17 | class 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 |
|
59 |
|
60 |
|
61 |
|
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 |
|
87 | function 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 |
|
92 | function projectQueryGeometry(queryGeometry: Array<Point>, pixelPosMatrix: mat4) {
|
93 | return queryGeometry.map((p) => {
|
94 | return projectPoint(p, pixelPosMatrix);
|
95 | });
|
96 | }
|
97 |
|
98 | export default CircleStyleLayer;
|