@mapwhit/tilerenderer 1.2.0 → 1.2.2
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/build/min/package.json +1 -1
- package/package.json +5 -5
- package/src/data/bucket/fill_extrusion_bucket.js +34 -39
- package/src/data/bucket/line_bucket.js +40 -48
- package/src/data/bucket/symbol_bucket.js +4 -5
- package/src/data/feature_index.js +10 -3
- package/src/geo/transform.js +13 -13
- package/src/index.js +1 -1
- package/src/source/geojson_wrapper.js +1 -9
- package/src/source/query_features.js +4 -1
- package/src/source/rtl_text_plugin.js +3 -1
- package/src/source/source_cache.js +3 -3
- package/src/source/tile.js +1 -1
- package/src/style/evaluation_parameters.js +5 -4
- package/src/style/query_utils.js +82 -7
- package/src/style/style.js +8 -2
- package/src/style/style_layer/circle_style_layer.js +26 -45
- package/src/style/style_layer/fill_extrusion_style_layer.js +26 -33
- package/src/style/style_layer/heatmap_style_layer.js +21 -7
- package/src/style/style_layer/line_style_layer.js +7 -7
- package/src/style/style_layer.js +3 -3
- package/src/style-spec/feature_filter/index.js +24 -19
- package/src/symbol/anchor.js +1 -1
- package/src/symbol/check_max_angle.js +6 -6
- package/src/symbol/collision_feature.js +9 -15
- package/src/symbol/collision_index.js +33 -27
- package/src/symbol/get_anchors.js +6 -5
- package/src/symbol/projection.js +3 -3
- package/src/symbol/quads.js +1 -1
- package/src/symbol/symbol_layout.js +1 -2
- package/src/ui/camera.js +1 -1
- package/src/ui/map.js +24 -24
- package/src/util/classify_rings.js +2 -4
- package/src/util/vectortile_to_geojson.js +65 -26
- package/build/min/src/shaders/.dir +0 -0
- package/src/symbol/clip_line.js +0 -72
package/src/style/query_utils.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import glMatrix from '@mapbox/gl-matrix';
|
|
2
|
+
import { polygonIntersectsBufferedPoint } from '@mapwhit/geometry';
|
|
3
|
+
import { Point } from '@mapwhit/point-geometry';
|
|
4
|
+
|
|
5
|
+
const { vec4 } = glMatrix;
|
|
2
6
|
|
|
3
7
|
export function getMaximumPaintValue(property, layer, bucket) {
|
|
4
8
|
const value = layer._paint.get(property).value;
|
|
@@ -18,16 +22,87 @@ export function translate(queryGeometry, translate, translateAnchor, bearing, pi
|
|
|
18
22
|
return queryGeometry;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
const pt = Point
|
|
25
|
+
const pt = new Point(translate[0], translate[1])._mult(pixelsToTileUnits);
|
|
22
26
|
|
|
23
27
|
if (translateAnchor === 'viewport') {
|
|
24
28
|
pt._rotate(-bearing);
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
pt;
|
|
32
|
+
|
|
33
|
+
return queryGeometry.map(point => point.sub(pt));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const circleIntersectionTests = new Map([
|
|
37
|
+
[
|
|
38
|
+
'map',
|
|
39
|
+
new Map([
|
|
40
|
+
[
|
|
41
|
+
'map',
|
|
42
|
+
({ queryGeometry, point, size }) => {
|
|
43
|
+
return polygonIntersectsBufferedPoint(queryGeometry, point, size);
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
[
|
|
47
|
+
'viewport',
|
|
48
|
+
({ queryGeometry, point, pixelPosMatrix, size, transform }) => {
|
|
49
|
+
const projectedCenter = vec4.transformMat4([], [point.x, point.y, 0, 1], pixelPosMatrix);
|
|
50
|
+
const adjustedSize = (size * projectedCenter[3]) / transform.cameraToCenterDistance;
|
|
51
|
+
return polygonIntersectsBufferedPoint(queryGeometry, point, adjustedSize);
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
])
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
'viewport',
|
|
58
|
+
new Map([
|
|
59
|
+
[
|
|
60
|
+
'map',
|
|
61
|
+
({ queryGeometry, point, pixelPosMatrix, size, transform }) => {
|
|
62
|
+
const projectedCenter = vec4.transformMat4([], [point.x, point.y, 0, 1], pixelPosMatrix);
|
|
63
|
+
const adjustedSize = (size * transform.cameraToCenterDistance) / projectedCenter[3];
|
|
64
|
+
return polygonIntersectsBufferedPoint(queryGeometry, projectPoint(point, pixelPosMatrix), adjustedSize);
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
[
|
|
68
|
+
'viewport',
|
|
69
|
+
({ queryGeometry, point, pixelPosMatrix, size }) => {
|
|
70
|
+
return polygonIntersectsBufferedPoint(queryGeometry, projectPoint(point, pixelPosMatrix), size);
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
])
|
|
74
|
+
]
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
export function circleIntersection({
|
|
78
|
+
queryGeometry,
|
|
79
|
+
geometry,
|
|
80
|
+
pixelPosMatrix,
|
|
81
|
+
size,
|
|
82
|
+
transform,
|
|
83
|
+
pitchAlignment = 'map',
|
|
84
|
+
pitchScale = 'map'
|
|
85
|
+
}) {
|
|
86
|
+
const intersectionTest = circleIntersectionTests.get(pitchAlignment).get(pitchScale);
|
|
87
|
+
const param = { queryGeometry, pixelPosMatrix, size, transform };
|
|
88
|
+
for (const ring of geometry) {
|
|
89
|
+
for (const point of ring) {
|
|
90
|
+
param.point = point;
|
|
91
|
+
if (intersectionTest(param)) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
31
95
|
}
|
|
32
|
-
return
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function projectPoint(p, pixelPosMatrix) {
|
|
100
|
+
const point = vec4.transformMat4([], [p.x, p.y, 0, 1], pixelPosMatrix);
|
|
101
|
+
return new Point(point[0] / point[3], point[1] / point[3]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function projectQueryGeometry(queryGeometry, pixelPosMatrix) {
|
|
105
|
+
return queryGeometry.map(p => {
|
|
106
|
+
return projectPoint(p, pixelPosMatrix);
|
|
107
|
+
});
|
|
33
108
|
}
|
package/src/style/style.js
CHANGED
|
@@ -920,8 +920,9 @@ class Style extends Evented {
|
|
|
920
920
|
}
|
|
921
921
|
|
|
922
922
|
const sourceResults = [];
|
|
923
|
+
params = params ? { ...params, globalState: this._globalState } : { globalState: this._globalState };
|
|
923
924
|
for (const id in this._sources) {
|
|
924
|
-
if (params
|
|
925
|
+
if (params?.layers && !includedSources[id]) {
|
|
925
926
|
continue;
|
|
926
927
|
}
|
|
927
928
|
sourceResults.push(
|
|
@@ -948,7 +949,12 @@ class Style extends Evented {
|
|
|
948
949
|
|
|
949
950
|
querySourceFeatures(sourceID, params) {
|
|
950
951
|
const sourceCache = this._sources[sourceID];
|
|
951
|
-
return sourceCache
|
|
952
|
+
return sourceCache
|
|
953
|
+
? querySourceFeatures(
|
|
954
|
+
sourceCache,
|
|
955
|
+
params ? { ...params, globalState: this._globalState } : { globalState: this._globalState }
|
|
956
|
+
)
|
|
957
|
+
: [];
|
|
952
958
|
}
|
|
953
959
|
|
|
954
960
|
getLight() {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import glMatrix from '@mapbox/gl-matrix';
|
|
2
|
-
import Point from '@mapbox/point-geometry';
|
|
3
|
-
import { polygonIntersectsBufferedPoint } from '@mapwhit/geometry';
|
|
4
1
|
import CircleBucket from '../../data/bucket/circle_bucket.js';
|
|
5
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
circleIntersection,
|
|
4
|
+
getMaximumPaintValue,
|
|
5
|
+
projectQueryGeometry,
|
|
6
|
+
translate,
|
|
7
|
+
translateDistance
|
|
8
|
+
} from '../query_utils.js';
|
|
6
9
|
import StyleLayer from '../style_layer.js';
|
|
7
10
|
import properties from './circle_style_layer_properties.js';
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class CircleStyleLayer extends StyleLayer {
|
|
12
|
+
export default class CircleStyleLayer extends StyleLayer {
|
|
12
13
|
constructor(layer, globalState) {
|
|
13
14
|
super(layer, properties, globalState);
|
|
14
15
|
}
|
|
@@ -51,48 +52,28 @@ class CircleStyleLayer extends StyleLayer {
|
|
|
51
52
|
// // Otherwise, compare geometry in the plane of the viewport
|
|
52
53
|
// // A circle with fixed scaling relative to the viewport gets larger in tile space as it moves into the distance
|
|
53
54
|
// // A circle with fixed scaling relative to the map gets smaller in viewport space as it moves into the distance
|
|
55
|
+
|
|
54
56
|
const pitchScale = this._paint.get('circle-pitch-scale');
|
|
55
57
|
const pitchAlignment = this._paint.get('circle-pitch-alignment');
|
|
56
|
-
const alignWithMap = pitchAlignment === 'map';
|
|
57
|
-
const alignWithViewport = pitchAlignment === 'viewport';
|
|
58
|
-
const transformedPolygon = alignWithMap
|
|
59
|
-
? translatedPolygon
|
|
60
|
-
: projectQueryGeometry(translatedPolygon, pixelPosMatrix);
|
|
61
|
-
const transformedSize = alignWithMap ? size * pixelsToTileUnits : size;
|
|
62
|
-
const adjustViewportToMap = pitchScale === 'viewport' && alignWithMap;
|
|
63
|
-
const adjustMapToViewport = pitchScale === 'map' && alignWithViewport;
|
|
64
|
-
|
|
65
|
-
for (const ring of geometry) {
|
|
66
|
-
for (const point of ring) {
|
|
67
|
-
const transformedPoint = alignWithMap ? point : projectPoint(point, pixelPosMatrix);
|
|
68
58
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (polygonIntersectsBufferedPoint(transformedPolygon, transformedPoint, adjustedSize)) {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
59
|
+
let transformedPolygon;
|
|
60
|
+
let transformedSize;
|
|
61
|
+
if (pitchAlignment === 'map') {
|
|
62
|
+
transformedPolygon = translatedPolygon;
|
|
63
|
+
transformedSize = size * pixelsToTileUnits;
|
|
64
|
+
} else {
|
|
65
|
+
transformedPolygon = projectQueryGeometry(translatedPolygon, pixelPosMatrix);
|
|
66
|
+
transformedSize = size;
|
|
81
67
|
}
|
|
82
68
|
|
|
83
|
-
return
|
|
69
|
+
return circleIntersection({
|
|
70
|
+
queryGeometry: transformedPolygon,
|
|
71
|
+
geometry,
|
|
72
|
+
pixelPosMatrix,
|
|
73
|
+
size: transformedSize,
|
|
74
|
+
transform,
|
|
75
|
+
pitchAlignment,
|
|
76
|
+
pitchScale
|
|
77
|
+
});
|
|
84
78
|
}
|
|
85
79
|
}
|
|
86
|
-
|
|
87
|
-
function projectPoint(p, pixelPosMatrix) {
|
|
88
|
-
const point = vec4.transformMat4([], [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, pixelPosMatrix) {
|
|
93
|
-
return queryGeometry.map(p => {
|
|
94
|
-
return projectPoint(p, pixelPosMatrix);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export default CircleStyleLayer;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import glMatrix from '@mapbox/gl-matrix';
|
|
2
|
-
import Point from '@mapbox/point-geometry';
|
|
3
2
|
import { polygonIntersectsMultiPolygon, polygonIntersectsPolygon } from '@mapwhit/geometry';
|
|
3
|
+
import { clone, equals, sub } from '@mapwhit/point-geometry';
|
|
4
4
|
import FillExtrusionBucket from '../../data/bucket/fill_extrusion_bucket.js';
|
|
5
5
|
import { translate, translateDistance } from '../query_utils.js';
|
|
6
6
|
import StyleLayer from '../style_layer.js';
|
|
@@ -45,11 +45,9 @@ export class FillExtrusionStyleLayer extends StyleLayer {
|
|
|
45
45
|
const height = this._paint.get('fill-extrusion-height').evaluate(feature, featureState);
|
|
46
46
|
const base = this._paint.get('fill-extrusion-base').evaluate(feature, featureState);
|
|
47
47
|
|
|
48
|
-
const projectedQueryGeometry = projectQueryGeometry(translatedPolygon, pixelPosMatrix,
|
|
48
|
+
const projectedQueryGeometry = projectQueryGeometry(translatedPolygon, pixelPosMatrix, 0);
|
|
49
49
|
|
|
50
|
-
const
|
|
51
|
-
const projectedBase = projected[0];
|
|
52
|
-
const projectedTop = projected[1];
|
|
50
|
+
const { projectedBase, projectedTop } = projectExtrusion(geometry, base, height, pixelPosMatrix);
|
|
53
51
|
return checkIntersection(projectedBase, projectedTop, projectedQueryGeometry);
|
|
54
52
|
}
|
|
55
53
|
}
|
|
@@ -72,7 +70,7 @@ export function getIntersectionDistance(projectedQueryGeometry, projectedFace) {
|
|
|
72
70
|
let i = 0;
|
|
73
71
|
const a = projectedFace[i++];
|
|
74
72
|
let b;
|
|
75
|
-
while (!b ||
|
|
73
|
+
while (!b || equals(a, b)) {
|
|
76
74
|
b = projectedFace[i++];
|
|
77
75
|
if (!b) {
|
|
78
76
|
return Number.POSITIVE_INFINITY;
|
|
@@ -84,9 +82,9 @@ export function getIntersectionDistance(projectedQueryGeometry, projectedFace) {
|
|
|
84
82
|
const c = projectedFace[i];
|
|
85
83
|
const p = projectedQueryGeometry[0];
|
|
86
84
|
|
|
87
|
-
const ab =
|
|
88
|
-
const ac =
|
|
89
|
-
const ap =
|
|
85
|
+
const ab = sub(clone(b), a);
|
|
86
|
+
const ac = sub(clone(c), a);
|
|
87
|
+
const ap = sub(clone(p), a);
|
|
90
88
|
|
|
91
89
|
const dotABAB = dot(ab, ab);
|
|
92
90
|
const dotABAC = dot(ab, ac);
|
|
@@ -153,8 +151,8 @@ function checkIntersection(projectedBase, projectedTop, projectedQueryGeometry)
|
|
|
153
151
|
* performance improvement.
|
|
154
152
|
*/
|
|
155
153
|
function projectExtrusion(geometry, zBase, zTop, m) {
|
|
156
|
-
const projectedBase =
|
|
157
|
-
const projectedTop =
|
|
154
|
+
const projectedBase = new Array(geometry.length);
|
|
155
|
+
const projectedTop = new Array(geometry.length);
|
|
158
156
|
|
|
159
157
|
const baseXZ = m[8] * zBase;
|
|
160
158
|
const baseYZ = m[9] * zBase;
|
|
@@ -165,12 +163,12 @@ function projectExtrusion(geometry, zBase, zTop, m) {
|
|
|
165
163
|
const topZZ = m[10] * zTop;
|
|
166
164
|
const topWZ = m[11] * zTop;
|
|
167
165
|
|
|
168
|
-
for (
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const y =
|
|
166
|
+
for (let i = 0; i < geometry.length; i++) {
|
|
167
|
+
const ring = geometry[i];
|
|
168
|
+
const ringBase = new Array(ring.length);
|
|
169
|
+
const ringTop = new Array(ring.length);
|
|
170
|
+
for (let j = 0; j < ring.length; j++) {
|
|
171
|
+
const { x, y } = ring[j];
|
|
174
172
|
|
|
175
173
|
const sX = m[0] * x + m[4] * y + m[12];
|
|
176
174
|
const sY = m[1] * x + m[5] * y + m[13];
|
|
@@ -181,32 +179,27 @@ function projectExtrusion(geometry, zBase, zTop, m) {
|
|
|
181
179
|
const baseY = sY + baseYZ;
|
|
182
180
|
const baseZ = sZ + baseZZ;
|
|
183
181
|
const baseW = sW + baseWZ;
|
|
182
|
+
ringBase[j] = { x: baseX / baseW, y: baseY / baseW, z: baseZ / baseW };
|
|
184
183
|
|
|
185
184
|
const topX = sX + topXZ;
|
|
186
185
|
const topY = sY + topYZ;
|
|
187
186
|
const topZ = sZ + topZZ;
|
|
188
187
|
const topW = sW + topWZ;
|
|
189
|
-
|
|
190
|
-
const b = new Point(baseX / baseW, baseY / baseW);
|
|
191
|
-
b.z = baseZ / baseW;
|
|
192
|
-
ringBase.push(b);
|
|
193
|
-
|
|
194
|
-
const t = new Point(topX / topW, topY / topW);
|
|
195
|
-
t.z = topZ / topW;
|
|
196
|
-
ringTop.push(t);
|
|
188
|
+
ringTop[j] = { x: topX / topW, y: topY / topW, z: topZ / topW };
|
|
197
189
|
}
|
|
198
|
-
projectedBase
|
|
199
|
-
projectedTop
|
|
190
|
+
projectedBase[i] = ringBase;
|
|
191
|
+
projectedTop[i] = ringTop;
|
|
200
192
|
}
|
|
201
|
-
return
|
|
193
|
+
return { projectedBase, projectedTop };
|
|
202
194
|
}
|
|
203
195
|
|
|
204
|
-
function projectQueryGeometry(queryGeometry, pixelPosMatrix,
|
|
205
|
-
const projectedQueryGeometry =
|
|
206
|
-
for (
|
|
207
|
-
const
|
|
196
|
+
function projectQueryGeometry(queryGeometry, pixelPosMatrix, z) {
|
|
197
|
+
const projectedQueryGeometry = new Array(queryGeometry.length);
|
|
198
|
+
for (let i = 0; i < queryGeometry.length; i++) {
|
|
199
|
+
const { x, y } = queryGeometry[i];
|
|
200
|
+
const v = [x, y, z, 1];
|
|
208
201
|
vec4.transformMat4(v, v, pixelPosMatrix);
|
|
209
|
-
projectedQueryGeometry
|
|
202
|
+
projectedQueryGeometry[i] = { x: v[0] / v[3], y: v[1] / v[3] };
|
|
210
203
|
}
|
|
211
204
|
return projectedQueryGeometry;
|
|
212
205
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import HeatmapBucket from '../../data/bucket/heatmap_bucket.js';
|
|
2
2
|
import renderColorRamp from '../../util/color_ramp.js';
|
|
3
|
+
import { circleIntersection, getMaximumPaintValue } from '../query_utils.js';
|
|
3
4
|
import StyleLayer from '../style_layer.js';
|
|
4
5
|
import properties from './heatmap_style_layer_properties.js';
|
|
5
6
|
|
|
6
|
-
class HeatmapStyleLayer extends StyleLayer {
|
|
7
|
+
export default class HeatmapStyleLayer extends StyleLayer {
|
|
7
8
|
createBucket(options) {
|
|
8
9
|
return new HeatmapBucket(options);
|
|
9
10
|
}
|
|
@@ -34,17 +35,30 @@ class HeatmapStyleLayer extends StyleLayer {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
queryRadius() {
|
|
38
|
-
return
|
|
38
|
+
queryRadius(bucket) {
|
|
39
|
+
return getMaximumPaintValue('heatmap-radius', this, bucket);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
queryIntersectsFeature(
|
|
42
|
-
|
|
42
|
+
queryIntersectsFeature(
|
|
43
|
+
queryGeometry,
|
|
44
|
+
feature,
|
|
45
|
+
featureState,
|
|
46
|
+
geometry,
|
|
47
|
+
zoom,
|
|
48
|
+
transform,
|
|
49
|
+
pixelsToTileUnits,
|
|
50
|
+
pixelPosMatrix
|
|
51
|
+
) {
|
|
52
|
+
return circleIntersection({
|
|
53
|
+
queryGeometry,
|
|
54
|
+
geometry,
|
|
55
|
+
pixelPosMatrix,
|
|
56
|
+
size: this._paint.get('heatmap-radius').evaluate(feature, featureState) * pixelsToTileUnits,
|
|
57
|
+
transform
|
|
58
|
+
});
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
hasOffscreenPass() {
|
|
46
62
|
return this._paint.get('heatmap-opacity') !== 0 && !this.isHidden();
|
|
47
63
|
}
|
|
48
64
|
}
|
|
49
|
-
|
|
50
|
-
export default HeatmapStyleLayer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Point from '@mapbox/point-geometry';
|
|
2
1
|
import { polygonIntersectsBufferedMultiLine } from '@mapwhit/geometry';
|
|
2
|
+
import { add, clone, div, mult, perp, sub, unit } from '@mapwhit/point-geometry';
|
|
3
3
|
import LineBucket from '../../data/bucket/line_bucket.js';
|
|
4
4
|
import renderColorRamp from '../../util/color_ramp.js';
|
|
5
5
|
import EvaluationParameters from '../evaluation_parameters.js';
|
|
@@ -111,22 +111,22 @@ function offsetLine(rings, offset) {
|
|
|
111
111
|
newRings[k] = newRing;
|
|
112
112
|
|
|
113
113
|
let b = ring[0];
|
|
114
|
-
let aToB =
|
|
114
|
+
let aToB = { x: 0, y: 0 };
|
|
115
115
|
for (let i = 0; i < ring.length - 1; i++) {
|
|
116
116
|
const c = ring[i + 1];
|
|
117
|
-
const bToC =
|
|
118
|
-
const extrude = aToB
|
|
117
|
+
const bToC = perp(unit(sub(clone(c), b)));
|
|
118
|
+
const extrude = unit(add(aToB, bToC));
|
|
119
119
|
const cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y;
|
|
120
120
|
if (cosHalfAngle !== 0) {
|
|
121
|
-
extrude
|
|
121
|
+
div(extrude, cosHalfAngle);
|
|
122
122
|
}
|
|
123
|
-
newRing[i] = extrude
|
|
123
|
+
newRing[i] = add(mult(extrude, offset), b);
|
|
124
124
|
|
|
125
125
|
b = c;
|
|
126
126
|
aToB = bToC;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
newRing[ring.length - 1] = aToB
|
|
129
|
+
newRing[ring.length - 1] = add(mult(unit(aToB), offset), b);
|
|
130
130
|
}
|
|
131
131
|
return newRings;
|
|
132
132
|
}
|
package/src/style/style_layer.js
CHANGED
|
@@ -35,10 +35,10 @@ class StyleLayer extends Evented {
|
|
|
35
35
|
this.source = layer.source;
|
|
36
36
|
this['source-layer'] = this.sourceLayer = layer['source-layer'];
|
|
37
37
|
this.filter = layer.filter;
|
|
38
|
-
this._featureFilter = featureFilter(layer.filter);
|
|
38
|
+
this._featureFilter = featureFilter(layer.filter, globalState);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
this._featureFilter ??= featureFilter
|
|
41
|
+
this._featureFilter ??= featureFilter(undefined, globalState);
|
|
42
42
|
|
|
43
43
|
if (properties.layout) {
|
|
44
44
|
this._unevaluatedLayout = new Layout(properties.layout, globalState);
|
|
@@ -59,7 +59,7 @@ class StyleLayer extends Evented {
|
|
|
59
59
|
setFilter(filter) {
|
|
60
60
|
this.#key = undefined;
|
|
61
61
|
this.filter = filter;
|
|
62
|
-
this._featureFilter
|
|
62
|
+
this._featureFilter.setValue(filter);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
_setZoomRange(minzoom, maxzoom) {
|
|
@@ -64,29 +64,34 @@ const filterSpec = {
|
|
|
64
64
|
* @returns {Function} filter-evaluating function
|
|
65
65
|
*/
|
|
66
66
|
export default function createFilter(filter, globalState) {
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
let evaluate;
|
|
68
|
+
const expression = (globalProperties, feature) => evaluate(globalProperties, feature);
|
|
69
|
+
expression.setValue = setValue;
|
|
70
|
+
setValue(filter);
|
|
71
|
+
return expression;
|
|
72
|
+
|
|
73
|
+
function setValue(filter) {
|
|
74
|
+
if (filter === null || filter === undefined) {
|
|
75
|
+
evaluate = () => true;
|
|
76
|
+
addGlobalStateRefs(expression);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!isExpressionFilter(filter)) {
|
|
81
|
+
filter = convertFilter(filter);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const compiled = createExpression(filter, filterSpec, globalState);
|
|
85
|
+
if (compiled.result === 'error') {
|
|
86
|
+
throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', '));
|
|
87
|
+
}
|
|
88
|
+
evaluate = (globalProperties, feature) => compiled.value.evaluate(globalProperties, feature);
|
|
89
|
+
addGlobalStateRefs(expression, () => findGlobalStateRefs(compiled.value.expression));
|
|
69
90
|
}
|
|
70
|
-
|
|
71
|
-
if (!isExpressionFilter(filter)) {
|
|
72
|
-
filter = convertFilter(filter);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const compiled = createExpression(filter, filterSpec, globalState);
|
|
76
|
-
if (compiled.result === 'error') {
|
|
77
|
-
throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', '));
|
|
78
|
-
}
|
|
79
|
-
return Object.assign(
|
|
80
|
-
addGlobalStateRefs(
|
|
81
|
-
(globalProperties, feature) => compiled.value.evaluate(globalProperties, feature),
|
|
82
|
-
() => findGlobalStateRefs(compiled.value.expression)
|
|
83
|
-
)
|
|
84
|
-
);
|
|
85
91
|
}
|
|
86
92
|
|
|
87
|
-
|
|
93
|
+
function addGlobalStateRefs(filter, getGlobalStateRefs = () => new Set()) {
|
|
88
94
|
filter.getGlobalStateRefs = getGlobalStateRefs;
|
|
89
|
-
return filter;
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
// Comparison function to sort numbers and strings
|
package/src/symbol/anchor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { angleTo, dist } from '@mapwhit/point-geometry';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Labels placed around really sharp angles aren't readable. Check if any
|
|
@@ -13,7 +13,7 @@ export default checkMaxAngle;
|
|
|
13
13
|
* @returns {boolean} whether the label should be placed
|
|
14
14
|
* @private
|
|
15
15
|
*/
|
|
16
|
-
function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) {
|
|
16
|
+
export default function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) {
|
|
17
17
|
// horizontal labels always pass
|
|
18
18
|
if (anchor.segment === undefined) {
|
|
19
19
|
return true;
|
|
@@ -32,11 +32,11 @@ function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) {
|
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
anchorDistance -= line[index]
|
|
35
|
+
anchorDistance -= dist(line[index], p);
|
|
36
36
|
p = line[index];
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
anchorDistance += line[index]
|
|
39
|
+
anchorDistance += dist(line[index], line[index + 1]);
|
|
40
40
|
index++;
|
|
41
41
|
|
|
42
42
|
// store recent corners and their total angle difference
|
|
@@ -54,7 +54,7 @@ function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) {
|
|
|
54
54
|
return false;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
let angleDelta =
|
|
57
|
+
let angleDelta = angleTo(prev, current) - angleTo(current, next);
|
|
58
58
|
// restrict angle to -pi..pi range
|
|
59
59
|
angleDelta = Math.abs(((angleDelta + 3 * Math.PI) % (Math.PI * 2)) - Math.PI);
|
|
60
60
|
|
|
@@ -75,7 +75,7 @@ function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
index++;
|
|
78
|
-
anchorDistance +=
|
|
78
|
+
anchorDistance += dist(current, next);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// no part of the line had an angle greater than the maximum allowed. check passes.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Point from '@
|
|
1
|
+
import { dist, Point, rotate as rotatePoint } from '@mapwhit/point-geometry';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A CollisionFeature represents the area of the tile covered by a single label.
|
|
@@ -67,17 +67,11 @@ class CollisionFeature {
|
|
|
67
67
|
// See https://github.com/mapbox/mapbox-gl-js/issues/6075
|
|
68
68
|
// Doesn't account for icon-text-fit
|
|
69
69
|
|
|
70
|
-
const tl = new Point(x1, y1);
|
|
71
|
-
const tr = new Point(x2, y1);
|
|
72
|
-
const bl = new Point(x1, y2);
|
|
73
|
-
const br = new Point(x2, y2);
|
|
74
|
-
|
|
75
70
|
const rotateRadians = (rotate * Math.PI) / 180;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
br._rotate(rotateRadians);
|
|
71
|
+
const tl = rotatePoint({ x: x1, y: y1 }, rotateRadians);
|
|
72
|
+
const tr = rotatePoint({ x: x2, y: y1 }, rotateRadians);
|
|
73
|
+
const bl = rotatePoint({ x: x1, y: y2 }, rotateRadians);
|
|
74
|
+
const br = rotatePoint({ x: x2, y: y2 }, rotateRadians);
|
|
81
75
|
|
|
82
76
|
// Collision features require an "on-axis" geometry,
|
|
83
77
|
// so take the envelope of the rotated geometry
|
|
@@ -162,11 +156,11 @@ class CollisionFeature {
|
|
|
162
156
|
index = 0;
|
|
163
157
|
break;
|
|
164
158
|
}
|
|
165
|
-
anchorDistance -= line[index]
|
|
159
|
+
anchorDistance -= dist(line[index], p);
|
|
166
160
|
p = line[index];
|
|
167
161
|
} while (anchorDistance > paddingStartDistance);
|
|
168
162
|
|
|
169
|
-
let segmentLength = line[index]
|
|
163
|
+
let segmentLength = dist(line[index], line[index + 1]);
|
|
170
164
|
|
|
171
165
|
for (let i = -nPitchPaddingBoxes; i < nBoxes + nPitchPaddingBoxes; i++) {
|
|
172
166
|
// the distance the box will be from the anchor
|
|
@@ -197,7 +191,7 @@ class CollisionFeature {
|
|
|
197
191
|
return;
|
|
198
192
|
}
|
|
199
193
|
|
|
200
|
-
segmentLength = line[index]
|
|
194
|
+
segmentLength = dist(line[index], line[index + 1]);
|
|
201
195
|
}
|
|
202
196
|
|
|
203
197
|
// the distance the box will be from the beginning of the segment
|
|
@@ -205,7 +199,7 @@ class CollisionFeature {
|
|
|
205
199
|
|
|
206
200
|
const p0 = line[index];
|
|
207
201
|
const p1 = line[index + 1];
|
|
208
|
-
const boxAnchorPoint = p1.
|
|
202
|
+
const boxAnchorPoint = Point.clone(p1)._sub(p0)._unit()._mult(segmentBoxDistance)._add(p0)._round();
|
|
209
203
|
|
|
210
204
|
// If the box is within boxSize of the anchor, force the box to be used
|
|
211
205
|
// (so even 0-width labels use at least one box)
|