@@ -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)
278340function rewind ( ring : number [ ] , clockwise : boolean ) {
279341 let area = 0 ;
0 commit comments