Skip to content

Commit 243bc6f

Browse files
mournergithub-actions[bot]
authored andcommitted
Fix polygon rendering for dynamic GeoJSON sources
GitOrigin-RevId: e1b8e665c2ab3934b2b48dfdafa07064ef9ebc2d
1 parent 987ded3 commit 243bc6f

File tree

1 file changed

+68
-6
lines changed

1 file changed

+68
-6
lines changed

src/source/geojson_rt.ts

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,14 @@ function outputFeature(feature: InternalFeature, z2: number, tx: number, ty: num
184184
const tileGeom = [];
185185

186186
if (type === 1) {
187-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
188-
transformPoints(geometry as number[], z2, tx, ty, tileGeom);
189-
} else {
187+
transformPoints(geometry as number[], z2, tx, ty, tileGeom as [number, number][]);
188+
} else if (type === 2) {
190189
for (const ring of geometry) {
191-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
192-
transformAndClipLine(ring as number[], z2, tx, ty, tileGeom);
190+
transformAndClipLine(ring as number[], z2, tx, ty, tileGeom as [number, number][][]);
191+
}
192+
} else if (type === 3) {
193+
for (const ring of geometry) {
194+
transformAndClipPolygon(ring as number[], z2, tx, ty, tileGeom as [number, number][][]);
193195
}
194196
}
195197

@@ -209,7 +211,7 @@ function transformPoints(line: number[], z2: number, tx: number, ty: number, out
209211
}
210212
}
211213

212-
function transformAndClipLine(line: number[], z2: number, tx: number, ty: number, out: [number, number][]) {
214+
function transformAndClipLine(line: number[], z2: number, tx: number, ty: number, out: [number, number][][]) {
213215
const min = -PAD_PX;
214216
const max = EXTENT + PAD_PX;
215217
let part;
@@ -274,6 +276,66 @@ function transformAndClipLine(line: number[], z2: number, tx: number, ty: number
274276
}
275277
}
276278

279+
function transformAndClipPolygon(input: number[], z2: number, tx: number, ty: number, out: [number, number][][]) {
280+
const minX = (tx - PAD) / z2;
281+
const minY = (ty - PAD) / z2;
282+
const maxX = (tx + 1 + PAD) / z2;
283+
const maxY = (ty + 1 + PAD) / z2;
284+
285+
function bitCode(x, y) {
286+
let code = 0;
287+
288+
if (x < minX) code |= 1; // left
289+
else if (x > maxX) code |= 2; // right
290+
291+
if (y < minY) code |= 4; // top
292+
else if (y > maxY) code |= 8; // bottom
293+
294+
return code;
295+
}
296+
297+
let clipped: number[] = [];
298+
299+
// clip against each side of the clip rectangle
300+
for (let edge = 1; edge <= 8; edge *= 2) {
301+
let x0 = input[input.length - 2];
302+
let y0 = input[input.length - 1];
303+
let prevInside = !(bitCode(x0, y0) & edge);
304+
305+
for (let i = 0; i < input.length; i += 2) {
306+
const x1 = input[i];
307+
const y1 = input[i + 1];
308+
const inside = !(bitCode(x1, y1) & edge);
309+
310+
// if segment goes through the clip window, add an intersection
311+
if (inside !== prevInside) {
312+
if (edge & 8) clipped.push(x0 + (x1 - x0) * (maxY - y0) / (y1 - y0), maxY); // bottom
313+
else if (edge & 4) clipped.push(x0 + (x1 - x0) * (minY - y0) / (y1 - y0), minY); // top
314+
else if (edge & 2) clipped.push(maxX, y0 + (y1 - y0) * (maxX - x0) / (x1 - x0)); // right
315+
else if (edge & 1) clipped.push(minX, y0 + (y1 - y0) * (minX - x0) / (x1 - x0)); // left
316+
}
317+
318+
if (inside) clipped.push(x1, y1); // add a point if it's inside
319+
320+
x0 = x1;
321+
y0 = y1;
322+
prevInside = inside;
323+
}
324+
325+
input = clipped;
326+
327+
if (!input.length || edge === 8) break;
328+
clipped = [];
329+
}
330+
331+
const ring: [number, number][] = [];
332+
for (let i = 0; i < clipped.length; i += 2) ring.push([
333+
Math.round(EXTENT * (clipped[i] * z2 - tx)),
334+
Math.round(EXTENT * (clipped[i + 1] * z2 - ty))
335+
]);
336+
out.push(ring);
337+
}
338+
277339
// rewind a polygon ring to a given winding order (clockwise or anti-clockwise)
278340
function rewind(ring: number[], clockwise: boolean) {
279341
let area = 0;

0 commit comments

Comments
 (0)