-
-
Notifications
You must be signed in to change notification settings - Fork 734
/
line_style_layer.ts
133 lines (113 loc) · 5.38 KB
/
line_style_layer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import type Point from '@mapbox/point-geometry';
import {StyleLayer} from '../style_layer';
import {LineBucket} from '../../data/bucket/line_bucket';
import {polygonIntersectsBufferedMultiLine} from '../../util/intersection_tests';
import {getMaximumPaintValue, translateDistance, translate, offsetLine} from '../query_utils';
import properties, {type LineLayoutPropsPossiblyEvaluated, type LinePaintPropsPossiblyEvaluated} from './line_style_layer_properties.g';
import {extend} from '../../util/util';
import {EvaluationParameters} from '../evaluation_parameters';
import {type Transitionable, type Transitioning, type Layout, type PossiblyEvaluated, DataDrivenProperty} from '../properties';
import {isZoomExpression, Step} from '@maplibre/maplibre-gl-style-spec';
import type {FeatureState, LayerSpecification} from '@maplibre/maplibre-gl-style-spec';
import type {Bucket, BucketParameters} from '../../data/bucket';
import type {LineLayoutProps, LinePaintProps} from './line_style_layer_properties.g';
import type {IReadonlyTransform} from '../../geo/transform_interface';
import type {VectorTileFeature} from '@mapbox/vector-tile';
export class LineFloorwidthProperty extends DataDrivenProperty<number> {
useIntegerZoom: true;
possiblyEvaluate(value, parameters) {
parameters = new EvaluationParameters(Math.floor(parameters.zoom), {
now: parameters.now,
fadeDuration: parameters.fadeDuration,
zoomHistory: parameters.zoomHistory,
transition: parameters.transition
});
return super.possiblyEvaluate(value, parameters);
}
evaluate(value, globals, feature, featureState) {
globals = extend({}, globals, {zoom: Math.floor(globals.zoom)});
return super.evaluate(value, globals, feature, featureState);
}
}
let lineFloorwidthProperty: LineFloorwidthProperty;
export const isLineStyleLayer = (layer: StyleLayer): layer is LineStyleLayer => layer.type === 'line';
export class LineStyleLayer extends StyleLayer {
_unevaluatedLayout: Layout<LineLayoutProps>;
layout: PossiblyEvaluated<LineLayoutProps, LineLayoutPropsPossiblyEvaluated>;
gradientVersion: number;
stepInterpolant: boolean;
_transitionablePaint: Transitionable<LinePaintProps>;
_transitioningPaint: Transitioning<LinePaintProps>;
paint: PossiblyEvaluated<LinePaintProps, LinePaintPropsPossiblyEvaluated>;
constructor(layer: LayerSpecification) {
super(layer, properties);
this.gradientVersion = 0;
if (!lineFloorwidthProperty) {
lineFloorwidthProperty =
new LineFloorwidthProperty(properties.paint.properties['line-width'].specification);
lineFloorwidthProperty.useIntegerZoom = true;
}
}
_handleSpecialPaintPropertyUpdate(name: string) {
if (name === 'line-gradient') {
const expression = this.gradientExpression();
if (isZoomExpression(expression)) {
this.stepInterpolant = expression._styleExpression.expression instanceof Step;
} else {
this.stepInterpolant = false;
}
this.gradientVersion = (this.gradientVersion + 1) % Number.MAX_SAFE_INTEGER;
}
}
gradientExpression() {
return this._transitionablePaint._values['line-gradient'].value.expression;
}
recalculate(parameters: EvaluationParameters, availableImages: Array<string>) {
super.recalculate(parameters, availableImages);
(this.paint._values as any)['line-floorwidth'] =
lineFloorwidthProperty.possiblyEvaluate(this._transitioningPaint._values['line-width'].value, parameters);
}
createBucket(parameters: BucketParameters<any>) {
return new LineBucket(parameters);
}
queryRadius(bucket: Bucket): number {
const lineBucket: LineBucket = (bucket as any);
const width = getLineWidth(
getMaximumPaintValue('line-width', this, lineBucket),
getMaximumPaintValue('line-gap-width', this, lineBucket));
const offset = getMaximumPaintValue('line-offset', this, lineBucket);
return width / 2 + Math.abs(offset) + translateDistance(this.paint.get('line-translate'));
}
queryIntersectsFeature(
queryGeometry: Array<Point>,
feature: VectorTileFeature,
featureState: FeatureState,
geometry: Array<Array<Point>>,
zoom: number,
transform: IReadonlyTransform,
pixelsToTileUnits: number
): boolean {
const translatedPolygon = translate(queryGeometry,
this.paint.get('line-translate'),
this.paint.get('line-translate-anchor'),
-transform.bearingInRadians, pixelsToTileUnits);
const halfWidth = pixelsToTileUnits / 2 * getLineWidth(
this.paint.get('line-width').evaluate(feature, featureState),
this.paint.get('line-gap-width').evaluate(feature, featureState));
const lineOffset = this.paint.get('line-offset').evaluate(feature, featureState);
if (lineOffset) {
geometry = offsetLine(geometry, lineOffset * pixelsToTileUnits);
}
return polygonIntersectsBufferedMultiLine(translatedPolygon, geometry, halfWidth);
}
isTileClipped() {
return true;
}
}
function getLineWidth(lineWidth, lineGapWidth) {
if (lineGapWidth > 0) {
return lineGapWidth + 2 * lineWidth;
} else {
return lineWidth;
}
}