@mapwhit/tilerenderer 0.47.1 → 0.48.0
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 +1 -2
- package/src/data/array_types.js +1 -1
- package/src/data/bucket/circle_bucket.js +1 -1
- package/src/data/bucket/fill_bucket.js +1 -1
- package/src/data/bucket/fill_extrusion_bucket.js +1 -1
- package/src/data/bucket/heatmap_bucket.js +1 -1
- package/src/data/bucket/line_bucket.js +1 -1
- package/src/data/bucket/symbol_bucket.js +26 -12
- package/src/data/dem_data.js +1 -1
- package/src/data/feature_index.js +43 -82
- package/src/data/program_configuration.js +19 -11
- package/src/data/segment.js +2 -2
- package/src/geo/transform.js +4 -2
- package/src/gl/color_mode.js +6 -6
- package/src/index.js +3 -1
- package/src/render/glyph_atlas.js +1 -1
- package/src/render/glyph_manager.js +43 -48
- package/src/render/image_atlas.js +1 -1
- package/src/render/image_manager.js +9 -37
- package/src/source/geojson_source.js +49 -93
- package/src/source/geojson_worker_source.js +33 -134
- package/src/source/image_source.js +9 -14
- package/src/source/load_tilejson.js +27 -34
- package/src/source/raster_dem_tile_source.js +27 -40
- package/src/source/raster_tile_source.js +53 -62
- package/src/source/rtl_text_plugin.js +3 -1
- package/src/source/source_cache.js +23 -21
- package/src/source/source_state.js +17 -26
- package/src/source/tile.js +6 -5
- package/src/source/tile_id.js +1 -1
- package/src/source/vector_tile_source.js +56 -73
- package/src/source/vector_tile_worker_source.js +20 -85
- package/src/source/worker.js +37 -103
- package/src/source/worker_tile.js +39 -84
- package/src/style/load_sprite.js +14 -17
- package/src/style/properties.js +1 -1
- package/src/style/style.js +22 -37
- package/src/style/style_layer/symbol_style_layer_properties.js +1 -1
- package/src/style/style_layer_index.js +17 -23
- package/src/style-spec/expression/compound_expression.js +30 -16
- package/src/style-spec/expression/definitions/coercion.js +13 -0
- package/src/style-spec/expression/definitions/comparison.js +193 -0
- package/src/style-spec/expression/definitions/formatted.js +123 -0
- package/src/style-spec/expression/definitions/index.js +10 -60
- package/src/style-spec/expression/definitions/interpolate.js +17 -7
- package/src/style-spec/expression/definitions/literal.js +5 -0
- package/src/style-spec/expression/parsing_context.js +4 -0
- package/src/style-spec/expression/types.js +12 -1
- package/src/style-spec/feature_filter/index.js +1 -1
- package/src/style-spec/reference/v8.json +120 -49
- package/src/symbol/anchor.js +1 -1
- package/src/symbol/collision_index.js +23 -16
- package/src/symbol/get_anchors.js +11 -22
- package/src/symbol/grid_index.js +176 -182
- package/src/symbol/mergelines.js +51 -48
- package/src/symbol/opacity_state.js +1 -1
- package/src/symbol/placement.js +8 -2
- package/src/symbol/quads.js +7 -6
- package/src/symbol/shaping.js +185 -40
- package/src/symbol/symbol_layout.js +9 -6
- package/src/symbol/transform_text.js +12 -1
- package/src/ui/camera.js +82 -85
- package/src/ui/map.js +13 -57
- package/src/util/actor.js +46 -42
- package/src/util/browser.js +6 -0
- package/src/util/dictionary_coder.js +13 -21
- package/src/util/dispatcher.js +14 -17
- package/src/util/image.js +1 -1
- package/src/util/loader/image.js +11 -11
- package/src/util/polyfill.js +16 -0
- package/src/util/task_queue.js +39 -43
- package/src/util/transfer_registry.js +167 -0
- package/src/util/web_worker_transfer.js +5 -190
- package/src/source/raster_dem_tile_worker_source.js +0 -26
- package/src/style-spec/expression/definitions/equals.js +0 -93
|
@@ -17,7 +17,7 @@ function getAngleWindowSize(shapedText, glyphSize, boxScale) {
|
|
|
17
17
|
return shapedText ? (3 / 5) * glyphSize * boxScale : 0;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
function
|
|
20
|
+
function getShapedLabelLength(shapedText, shapedIcon) {
|
|
21
21
|
return Math.max(
|
|
22
22
|
shapedText ? shapedText.right - shapedText.left : 0,
|
|
23
23
|
shapedIcon ? shapedIcon.right - shapedIcon.left : 0
|
|
@@ -26,7 +26,7 @@ function getLabelLength(shapedText, shapedIcon) {
|
|
|
26
26
|
|
|
27
27
|
function getCenterAnchor(line, maxAngle, shapedText, shapedIcon, glyphSize, boxScale) {
|
|
28
28
|
const angleWindowSize = getAngleWindowSize(shapedText, glyphSize, boxScale);
|
|
29
|
-
const labelLength =
|
|
29
|
+
const labelLength = getShapedLabelLength(shapedText, shapedIcon) * boxScale;
|
|
30
30
|
|
|
31
31
|
let prevDistance = 0;
|
|
32
32
|
const centerDistance = getLineLength(line) / 2;
|
|
@@ -45,11 +45,10 @@ function getCenterAnchor(line, maxAngle, shapedText, shapedIcon, glyphSize, boxS
|
|
|
45
45
|
|
|
46
46
|
const anchor = new Anchor(x, y, b.angleTo(a), i);
|
|
47
47
|
anchor._round();
|
|
48
|
-
if (angleWindowSize
|
|
49
|
-
return;
|
|
48
|
+
if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) {
|
|
49
|
+
return anchor;
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
return anchor;
|
|
51
|
+
return;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
prevDistance += segmentDistance;
|
|
@@ -62,16 +61,16 @@ function getAnchors(line, spacing, maxAngle, shapedText, shapedIcon, glyphSize,
|
|
|
62
61
|
// on the line.
|
|
63
62
|
|
|
64
63
|
const angleWindowSize = getAngleWindowSize(shapedText, glyphSize, boxScale);
|
|
65
|
-
|
|
66
|
-
const labelLength =
|
|
64
|
+
const shapedLabelLength = getShapedLabelLength(shapedText, shapedIcon);
|
|
65
|
+
const labelLength = shapedLabelLength * boxScale;
|
|
67
66
|
|
|
68
67
|
// Is the line continued from outside the tile boundary?
|
|
69
68
|
const isLineContinued = line[0].x === 0 || line[0].x === tileExtent || line[0].y === 0 || line[0].y === tileExtent;
|
|
70
69
|
|
|
71
70
|
// Is the label long, relative to the spacing?
|
|
72
71
|
// If so, adjust the spacing so there is always a minimum space of `spacing / 4` between label edges.
|
|
73
|
-
if (spacing - labelLength
|
|
74
|
-
spacing = labelLength
|
|
72
|
+
if (spacing - labelLength < spacing / 4) {
|
|
73
|
+
spacing = labelLength + spacing / 4;
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
// Offset the first anchor by:
|
|
@@ -82,20 +81,10 @@ function getAnchors(line, spacing, maxAngle, shapedText, shapedIcon, glyphSize,
|
|
|
82
81
|
const fixedExtraOffset = glyphSize * 2;
|
|
83
82
|
|
|
84
83
|
const offset = !isLineContinued
|
|
85
|
-
? ((
|
|
84
|
+
? ((shapedLabelLength / 2 + fixedExtraOffset) * boxScale * overscaling) % spacing
|
|
86
85
|
: ((spacing / 2) * overscaling) % spacing;
|
|
87
86
|
|
|
88
|
-
return resample(
|
|
89
|
-
line,
|
|
90
|
-
offset,
|
|
91
|
-
spacing,
|
|
92
|
-
angleWindowSize,
|
|
93
|
-
maxAngle,
|
|
94
|
-
labelLength * boxScale,
|
|
95
|
-
isLineContinued,
|
|
96
|
-
false,
|
|
97
|
-
tileExtent
|
|
98
|
-
);
|
|
87
|
+
return resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength, isLineContinued, false, tileExtent);
|
|
99
88
|
}
|
|
100
89
|
|
|
101
90
|
function resample(
|
package/src/symbol/grid_index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { clamp } = require('../util/util');
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* GridIndex is a data structure for testing the intersection of
|
|
3
5
|
* circles and rectangles in a 2d plane.
|
|
@@ -8,24 +10,21 @@
|
|
|
8
10
|
* at least one cell. As long as the geometries are relatively
|
|
9
11
|
* uniformly distributed across the plane, this greatly reduces
|
|
10
12
|
* the number of comparisons necessary.
|
|
11
|
-
*
|
|
12
|
-
* @private
|
|
13
13
|
*/
|
|
14
14
|
class GridIndex {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const circleCells = (this.circleCells = []);
|
|
15
|
+
#boxUid = 0;
|
|
16
|
+
#circleUid = 0;
|
|
18
17
|
|
|
18
|
+
constructor(width, height, cellSize) {
|
|
19
19
|
// More cells -> fewer geometries to check per cell, but items tend
|
|
20
20
|
// to be split across more cells.
|
|
21
21
|
// Sweet spot allows most small items to fit in one cell
|
|
22
22
|
this.xCellCount = Math.ceil(width / cellSize);
|
|
23
23
|
this.yCellCount = Math.ceil(height / cellSize);
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
25
|
+
const size = this.xCellCount * this.yCellCount;
|
|
26
|
+
this.boxCells = new Array(size);
|
|
27
|
+
this.circleCells = new Array(size);
|
|
29
28
|
this.circleKeys = [];
|
|
30
29
|
this.boxKeys = [];
|
|
31
30
|
this.bboxes = [];
|
|
@@ -35,8 +34,6 @@ class GridIndex {
|
|
|
35
34
|
this.height = height;
|
|
36
35
|
this.xScale = this.xCellCount / width;
|
|
37
36
|
this.yScale = this.yCellCount / height;
|
|
38
|
-
this.boxUid = 0;
|
|
39
|
-
this.circleUid = 0;
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
keysLength() {
|
|
@@ -44,33 +41,30 @@ class GridIndex {
|
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
insert(key, x1, y1, x2, y2) {
|
|
47
|
-
|
|
44
|
+
const { boxCells } = this;
|
|
45
|
+
this.#forEachCell(x1, y1, x2, y2, insertBoxCell, this.#boxUid++);
|
|
48
46
|
this.boxKeys.push(key);
|
|
49
|
-
this.bboxes.push(x1);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
this.bboxes.push(x1, y1, x2, y2);
|
|
48
|
+
|
|
49
|
+
function insertBoxCell(x1, y1, x2, y2, cellIndex, uid) {
|
|
50
|
+
(boxCells[cellIndex] ??= []).push(uid);
|
|
51
|
+
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
insertCircle(key, x, y, radius) {
|
|
55
|
+
const { circleCells } = this;
|
|
56
56
|
// Insert circle into grid for all cells in the circumscribing square
|
|
57
57
|
// It's more than necessary (by a factor of 4/PI), but fast to insert
|
|
58
|
-
this
|
|
58
|
+
this.#forEachCell(x - radius, y - radius, x + radius, y + radius, insertCircleCell, this.#circleUid++);
|
|
59
59
|
this.circleKeys.push(key);
|
|
60
|
-
this.circles.push(x);
|
|
61
|
-
this.circles.push(y);
|
|
62
|
-
this.circles.push(radius);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
_insertBoxCell(x1, y1, x2, y2, cellIndex, uid) {
|
|
66
|
-
this.boxCells[cellIndex].push(uid);
|
|
67
|
-
}
|
|
60
|
+
this.circles.push(x, y, radius);
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
function insertCircleCell(x1, y1, x2, y2, cellIndex, uid) {
|
|
63
|
+
(circleCells[cellIndex] ??= []).push(uid);
|
|
64
|
+
}
|
|
71
65
|
}
|
|
72
66
|
|
|
73
|
-
|
|
67
|
+
#query(x1, y1, x2, y2, hitTest, predicate) {
|
|
74
68
|
if (x2 < 0 || x1 > this.width || y2 < 0 || y1 > this.height) {
|
|
75
69
|
return hitTest ? false : [];
|
|
76
70
|
}
|
|
@@ -106,11 +100,73 @@ class GridIndex {
|
|
|
106
100
|
hitTest,
|
|
107
101
|
seenUids: { box: {}, circle: {} }
|
|
108
102
|
};
|
|
109
|
-
this
|
|
103
|
+
this.#forEachCell(x1, y1, x2, y2, queryCell, result, queryArgs, predicate);
|
|
110
104
|
return hitTest ? result.length > 0 : result;
|
|
105
|
+
|
|
106
|
+
function queryCell(x1, y1, x2, y2, cellIndex, result, queryArgs, predicate) {
|
|
107
|
+
const { seenUids } = queryArgs;
|
|
108
|
+
const boxCell = this.boxCells[cellIndex];
|
|
109
|
+
if (boxCell != null) {
|
|
110
|
+
const { bboxes } = this;
|
|
111
|
+
for (const boxUid of boxCell) {
|
|
112
|
+
if (!seenUids.box[boxUid]) {
|
|
113
|
+
seenUids.box[boxUid] = true;
|
|
114
|
+
const offset = boxUid * 4;
|
|
115
|
+
if (
|
|
116
|
+
x1 <= bboxes[offset + 2] &&
|
|
117
|
+
y1 <= bboxes[offset + 3] &&
|
|
118
|
+
x2 >= bboxes[offset + 0] &&
|
|
119
|
+
y2 >= bboxes[offset + 1] &&
|
|
120
|
+
(!predicate || predicate(this.boxKeys[boxUid]))
|
|
121
|
+
) {
|
|
122
|
+
if (queryArgs.hitTest) {
|
|
123
|
+
result.push(true);
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
result.push({
|
|
127
|
+
key: this.boxKeys[boxUid],
|
|
128
|
+
x1: bboxes[offset],
|
|
129
|
+
y1: bboxes[offset + 1],
|
|
130
|
+
x2: bboxes[offset + 2],
|
|
131
|
+
y2: bboxes[offset + 3]
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const circleCell = this.circleCells[cellIndex];
|
|
138
|
+
if (circleCell != null) {
|
|
139
|
+
const { circles } = this;
|
|
140
|
+
for (const circleUid of circleCell) {
|
|
141
|
+
if (!seenUids.circle[circleUid]) {
|
|
142
|
+
seenUids.circle[circleUid] = true;
|
|
143
|
+
const offset = circleUid * 3;
|
|
144
|
+
if (
|
|
145
|
+
circleAndRectCollide(circles[offset], circles[offset + 1], circles[offset + 2], x1, y1, x2, y2) &&
|
|
146
|
+
(!predicate || predicate(this.circleKeys[circleUid]))
|
|
147
|
+
) {
|
|
148
|
+
if (queryArgs.hitTest) {
|
|
149
|
+
result.push(true);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
const x = circles[offset];
|
|
153
|
+
const y = circles[offset + 1];
|
|
154
|
+
const radius = circles[offset + 2];
|
|
155
|
+
result.push({
|
|
156
|
+
key: this.circleKeys[circleUid],
|
|
157
|
+
x1: x - radius,
|
|
158
|
+
y1: y - radius,
|
|
159
|
+
x2: x + radius,
|
|
160
|
+
y2: y + radius
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
111
167
|
}
|
|
112
168
|
|
|
113
|
-
|
|
169
|
+
#queryCircle(x, y, radius, hitTest, predicate) {
|
|
114
170
|
// Insert circle into grid for all cells in the circumscribing square
|
|
115
171
|
// It's more than necessary (by a factor of 4/PI), but fast to insert
|
|
116
172
|
const x1 = x - radius;
|
|
@@ -127,192 +183,130 @@ class GridIndex {
|
|
|
127
183
|
const result = [];
|
|
128
184
|
const queryArgs = {
|
|
129
185
|
hitTest,
|
|
130
|
-
circle: { x
|
|
186
|
+
circle: { x, y, radius },
|
|
131
187
|
seenUids: { box: {}, circle: {} }
|
|
132
188
|
};
|
|
133
|
-
this
|
|
189
|
+
this.#forEachCell(x1, y1, x2, y2, queryCellCircle, result, queryArgs, predicate);
|
|
134
190
|
return hitTest ? result.length > 0 : result;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
query(x1, y1, x2, y2, predicate) {
|
|
138
|
-
return this._query(x1, y1, x2, y2, false, predicate);
|
|
139
|
-
}
|
|
140
191
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
y2 >= bboxes[offset + 1] &&
|
|
163
|
-
(!predicate || predicate(this.boxKeys[boxUid]))
|
|
164
|
-
) {
|
|
165
|
-
if (queryArgs.hitTest) {
|
|
192
|
+
function queryCellCircle(x1, y1, x2, y2, cellIndex, result, queryArgs, predicate) {
|
|
193
|
+
const { circle, seenUids } = queryArgs;
|
|
194
|
+
const boxCell = this.boxCells[cellIndex];
|
|
195
|
+
if (boxCell != null) {
|
|
196
|
+
const { bboxes } = this;
|
|
197
|
+
for (const boxUid of boxCell) {
|
|
198
|
+
if (!seenUids.box[boxUid]) {
|
|
199
|
+
seenUids.box[boxUid] = true;
|
|
200
|
+
const offset = boxUid * 4;
|
|
201
|
+
if (
|
|
202
|
+
circleAndRectCollide(
|
|
203
|
+
circle.x,
|
|
204
|
+
circle.y,
|
|
205
|
+
circle.radius,
|
|
206
|
+
bboxes[offset + 0],
|
|
207
|
+
bboxes[offset + 1],
|
|
208
|
+
bboxes[offset + 2],
|
|
209
|
+
bboxes[offset + 3]
|
|
210
|
+
) &&
|
|
211
|
+
(!predicate || predicate(this.boxKeys[boxUid]))
|
|
212
|
+
) {
|
|
166
213
|
result.push(true);
|
|
167
214
|
return true;
|
|
168
215
|
}
|
|
169
|
-
result.push({
|
|
170
|
-
key: this.boxKeys[boxUid],
|
|
171
|
-
x1: bboxes[offset],
|
|
172
|
-
y1: bboxes[offset + 1],
|
|
173
|
-
x2: bboxes[offset + 2],
|
|
174
|
-
y2: bboxes[offset + 3]
|
|
175
|
-
});
|
|
176
216
|
}
|
|
177
217
|
}
|
|
178
218
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
219
|
+
|
|
220
|
+
const circleCell = this.circleCells[cellIndex];
|
|
221
|
+
if (circleCell != null) {
|
|
222
|
+
const { circles } = this;
|
|
223
|
+
for (const circleUid of circleCell) {
|
|
224
|
+
if (!seenUids.circle[circleUid]) {
|
|
225
|
+
seenUids.circle[circleUid] = true;
|
|
226
|
+
const offset = circleUid * 3;
|
|
227
|
+
if (
|
|
228
|
+
circlesCollide(
|
|
229
|
+
circles[offset],
|
|
230
|
+
circles[offset + 1],
|
|
231
|
+
circles[offset + 2],
|
|
232
|
+
circle.x,
|
|
233
|
+
circle.y,
|
|
234
|
+
circle.radius
|
|
235
|
+
) &&
|
|
236
|
+
(!predicate || predicate(this.circleKeys[circleUid]))
|
|
237
|
+
) {
|
|
192
238
|
result.push(true);
|
|
193
239
|
return true;
|
|
194
240
|
}
|
|
195
|
-
const x = circles[offset];
|
|
196
|
-
const y = circles[offset + 1];
|
|
197
|
-
const radius = circles[offset + 2];
|
|
198
|
-
result.push({
|
|
199
|
-
key: this.circleKeys[circleUid],
|
|
200
|
-
x1: x - radius,
|
|
201
|
-
y1: y - radius,
|
|
202
|
-
x2: x + radius,
|
|
203
|
-
y2: y + radius
|
|
204
|
-
});
|
|
205
241
|
}
|
|
206
242
|
}
|
|
207
243
|
}
|
|
208
244
|
}
|
|
209
245
|
}
|
|
210
246
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const boxCell = this.boxCells[cellIndex];
|
|
215
|
-
if (boxCell !== null) {
|
|
216
|
-
const bboxes = this.bboxes;
|
|
217
|
-
for (const boxUid of boxCell) {
|
|
218
|
-
if (!seenUids.box[boxUid]) {
|
|
219
|
-
seenUids.box[boxUid] = true;
|
|
220
|
-
const offset = boxUid * 4;
|
|
221
|
-
if (
|
|
222
|
-
this._circleAndRectCollide(
|
|
223
|
-
circle.x,
|
|
224
|
-
circle.y,
|
|
225
|
-
circle.radius,
|
|
226
|
-
bboxes[offset + 0],
|
|
227
|
-
bboxes[offset + 1],
|
|
228
|
-
bboxes[offset + 2],
|
|
229
|
-
bboxes[offset + 3]
|
|
230
|
-
) &&
|
|
231
|
-
(!predicate || predicate(this.boxKeys[boxUid]))
|
|
232
|
-
) {
|
|
233
|
-
result.push(true);
|
|
234
|
-
return true;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
247
|
+
query(x1, y1, x2, y2, predicate) {
|
|
248
|
+
return this.#query(x1, y1, x2, y2, false, predicate);
|
|
249
|
+
}
|
|
239
250
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const circles = this.circles;
|
|
243
|
-
for (const circleUid of circleCell) {
|
|
244
|
-
if (!seenUids.circle[circleUid]) {
|
|
245
|
-
seenUids.circle[circleUid] = true;
|
|
246
|
-
const offset = circleUid * 3;
|
|
247
|
-
if (
|
|
248
|
-
this._circlesCollide(
|
|
249
|
-
circles[offset],
|
|
250
|
-
circles[offset + 1],
|
|
251
|
-
circles[offset + 2],
|
|
252
|
-
circle.x,
|
|
253
|
-
circle.y,
|
|
254
|
-
circle.radius
|
|
255
|
-
) &&
|
|
256
|
-
(!predicate || predicate(this.circleKeys[circleUid]))
|
|
257
|
-
) {
|
|
258
|
-
result.push(true);
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
251
|
+
hitTest(x1, y1, x2, y2, predicate) {
|
|
252
|
+
return this.#query(x1, y1, x2, y2, true, predicate);
|
|
264
253
|
}
|
|
265
254
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
255
|
+
hitTestCircle(x, y, radius, predicate) {
|
|
256
|
+
return this.#queryCircle(x, y, radius, true, predicate);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
#forEachCell(x1, y1, x2, y2, fn, ...args) {
|
|
260
|
+
const { xCellCount, yCellCount, xScale, yScale } = this;
|
|
261
|
+
const cx1 = cellX(x1);
|
|
262
|
+
const cy1 = cellY(y1);
|
|
263
|
+
const cx2 = cellX(x2);
|
|
264
|
+
const cy2 = cellY(y2);
|
|
271
265
|
|
|
272
266
|
for (let x = cx1; x <= cx2; x++) {
|
|
273
267
|
for (let y = cy1; y <= cy2; y++) {
|
|
274
|
-
const cellIndex =
|
|
275
|
-
if (fn.call(this, x1, y1, x2, y2, cellIndex,
|
|
268
|
+
const cellIndex = xCellCount * y + x;
|
|
269
|
+
if (fn.call(this, x1, y1, x2, y2, cellIndex, ...args)) return;
|
|
276
270
|
}
|
|
277
271
|
}
|
|
278
|
-
}
|
|
279
272
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
273
|
+
function cellX(x) {
|
|
274
|
+
return clamp(Math.floor(x * xScale), 0, xCellCount - 1);
|
|
275
|
+
}
|
|
283
276
|
|
|
284
|
-
|
|
285
|
-
|
|
277
|
+
function cellY(y) {
|
|
278
|
+
return clamp(Math.floor(y * yScale), 0, yCellCount - 1);
|
|
279
|
+
}
|
|
286
280
|
}
|
|
281
|
+
}
|
|
287
282
|
|
|
288
|
-
|
|
289
|
-
const dx = x2 - x1;
|
|
290
|
-
const dy = y2 - y1;
|
|
291
|
-
const bothRadii = r1 + r2;
|
|
292
|
-
return bothRadii * bothRadii > dx * dx + dy * dy;
|
|
293
|
-
}
|
|
283
|
+
module.exports = GridIndex;
|
|
294
284
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
285
|
+
function circlesCollide(x1, y1, r1, x2, y2, r2) {
|
|
286
|
+
const dx = x2 - x1;
|
|
287
|
+
const dy = y2 - y1;
|
|
288
|
+
const bothRadii = r1 + r2;
|
|
289
|
+
return bothRadii * bothRadii > dx * dx + dy * dy;
|
|
290
|
+
}
|
|
301
291
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
292
|
+
function circleAndRectCollide(circleX, circleY, radius, x1, y1, x2, y2) {
|
|
293
|
+
const halfRectWidth = (x2 - x1) / 2;
|
|
294
|
+
const distX = Math.abs(circleX - (x1 + halfRectWidth));
|
|
295
|
+
if (distX > halfRectWidth + radius) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
307
298
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
299
|
+
const halfRectHeight = (y2 - y1) / 2;
|
|
300
|
+
const distY = Math.abs(circleY - (y1 + halfRectHeight));
|
|
301
|
+
if (distY > halfRectHeight + radius) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
311
304
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return dx * dx + dy * dy <= radius * radius;
|
|
305
|
+
if (distX <= halfRectWidth || distY <= halfRectHeight) {
|
|
306
|
+
return true;
|
|
315
307
|
}
|
|
316
|
-
}
|
|
317
308
|
|
|
318
|
-
|
|
309
|
+
const dx = distX - halfRectWidth;
|
|
310
|
+
const dy = distY - halfRectHeight;
|
|
311
|
+
return dx * dx + dy * dy <= radius * radius;
|
|
312
|
+
}
|
package/src/symbol/mergelines.js
CHANGED
|
@@ -1,75 +1,78 @@
|
|
|
1
|
+
const { Formatted } = require('../style-spec/expression/definitions/formatted');
|
|
2
|
+
|
|
1
3
|
module.exports = function (features) {
|
|
2
|
-
const leftIndex =
|
|
3
|
-
const rightIndex =
|
|
4
|
+
const leftIndex = new Map();
|
|
5
|
+
const rightIndex = new Map();
|
|
4
6
|
const mergedFeatures = [];
|
|
5
7
|
let mergedIndex = 0;
|
|
6
8
|
|
|
7
|
-
function add(k) {
|
|
8
|
-
mergedFeatures.push(features[k]);
|
|
9
|
-
mergedIndex++;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function mergeFromRight(leftKey, rightKey, geom) {
|
|
13
|
-
const i = rightIndex[leftKey];
|
|
14
|
-
delete rightIndex[leftKey];
|
|
15
|
-
rightIndex[rightKey] = i;
|
|
16
|
-
|
|
17
|
-
mergedFeatures[i].geometry[0].pop();
|
|
18
|
-
mergedFeatures[i].geometry[0] = mergedFeatures[i].geometry[0].concat(geom[0]);
|
|
19
|
-
return i;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function mergeFromLeft(leftKey, rightKey, geom) {
|
|
23
|
-
const i = leftIndex[rightKey];
|
|
24
|
-
delete leftIndex[rightKey];
|
|
25
|
-
leftIndex[leftKey] = i;
|
|
26
|
-
|
|
27
|
-
mergedFeatures[i].geometry[0].shift();
|
|
28
|
-
mergedFeatures[i].geometry[0] = geom[0].concat(mergedFeatures[i].geometry[0]);
|
|
29
|
-
return i;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function getKey(text, geom, onRight) {
|
|
33
|
-
const point = onRight ? geom[0][geom[0].length - 1] : geom[0][0];
|
|
34
|
-
return `${text}:${point.x}:${point.y}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
9
|
for (let k = 0; k < features.length; k++) {
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const text = feature.text;
|
|
10
|
+
const { geometry, text: featureText } = features[k];
|
|
11
|
+
const text = featureText instanceof Formatted ? featureText.toString() : featureText;
|
|
41
12
|
|
|
42
13
|
if (!text) {
|
|
43
14
|
add(k);
|
|
44
15
|
continue;
|
|
45
16
|
}
|
|
46
17
|
|
|
47
|
-
const leftKey = getKey(text,
|
|
48
|
-
const rightKey = getKey(text,
|
|
18
|
+
const leftKey = getKey(text, geometry);
|
|
19
|
+
const rightKey = getKey(text, geometry, true);
|
|
49
20
|
|
|
50
|
-
if (leftKey
|
|
21
|
+
if (rightIndex.has(leftKey) && leftIndex.has(rightKey) && rightIndex.get(leftKey) !== leftIndex.get(rightKey)) {
|
|
51
22
|
// found lines with the same text adjacent to both ends of the current line, merge all three
|
|
52
|
-
const j = mergeFromLeft(leftKey, rightKey,
|
|
23
|
+
const j = mergeFromLeft(leftKey, rightKey, geometry);
|
|
53
24
|
const i = mergeFromRight(leftKey, rightKey, mergedFeatures[j].geometry);
|
|
54
25
|
|
|
55
|
-
delete
|
|
56
|
-
delete
|
|
26
|
+
leftIndex.delete(leftKey);
|
|
27
|
+
rightIndex.delete(rightKey);
|
|
57
28
|
|
|
58
|
-
rightIndex
|
|
29
|
+
rightIndex.set(getKey(text, mergedFeatures[i].geometry, true), i);
|
|
59
30
|
mergedFeatures[j].geometry = null;
|
|
60
|
-
} else if (leftKey
|
|
31
|
+
} else if (rightIndex.has(leftKey)) {
|
|
61
32
|
// found mergeable line adjacent to the start of the current line, merge
|
|
62
|
-
mergeFromRight(leftKey, rightKey,
|
|
63
|
-
} else if (rightKey
|
|
33
|
+
mergeFromRight(leftKey, rightKey, geometry);
|
|
34
|
+
} else if (leftIndex.has(rightKey)) {
|
|
64
35
|
// found mergeable line adjacent to the end of the current line, merge
|
|
65
|
-
mergeFromLeft(leftKey, rightKey,
|
|
36
|
+
mergeFromLeft(leftKey, rightKey, geometry);
|
|
66
37
|
} else {
|
|
67
38
|
// no adjacent lines, add as a new item
|
|
68
39
|
add(k);
|
|
69
|
-
leftIndex
|
|
70
|
-
rightIndex
|
|
40
|
+
leftIndex.set(leftKey, mergedIndex - 1);
|
|
41
|
+
rightIndex.set(rightKey, mergedIndex - 1);
|
|
71
42
|
}
|
|
72
43
|
}
|
|
73
44
|
|
|
74
45
|
return mergedFeatures.filter(f => f.geometry);
|
|
46
|
+
|
|
47
|
+
function add(k) {
|
|
48
|
+
mergedFeatures.push(features[k]);
|
|
49
|
+
mergedIndex++;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function mergeFromRight(leftKey, rightKey, [geom]) {
|
|
53
|
+
const i = rightIndex.get(leftKey);
|
|
54
|
+
rightIndex.delete(leftKey);
|
|
55
|
+
rightIndex.set(rightKey, i);
|
|
56
|
+
|
|
57
|
+
const feature = mergedFeatures[i];
|
|
58
|
+
feature.geometry[0].pop();
|
|
59
|
+
feature.geometry[0].push(...geom);
|
|
60
|
+
return i;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function mergeFromLeft(leftKey, rightKey, [geom]) {
|
|
64
|
+
const i = leftIndex.get(rightKey);
|
|
65
|
+
leftIndex.delete(rightKey);
|
|
66
|
+
leftIndex.set(leftKey, i);
|
|
67
|
+
|
|
68
|
+
const feature = mergedFeatures[i];
|
|
69
|
+
feature.geometry[0].shift();
|
|
70
|
+
feature.geometry[0].unshift(...geom);
|
|
71
|
+
return i;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getKey(text, [geom], onRight) {
|
|
75
|
+
const { x, y } = geom.at(onRight ? -1 : 0);
|
|
76
|
+
return `${text}:${x}:${y}`;
|
|
77
|
+
}
|
|
75
78
|
};
|