@@ -9,8 +9,10 @@ import {number as interpolate} from '../style-spec/util/interpolate';
99import EXTENT from '../data/extent' ;
1010import { vec4 , mat4 , mat2 , vec2 } from 'gl-matrix' ;
1111import { Aabb , Frustum } from '../util/primitives.js' ;
12+ import EdgeInsets from './edge_insets' ;
1213
1314import { UnwrappedTileID , OverscaledTileID , CanonicalTileID } from '../source/tile_id' ;
15+ import type { PaddingOptions } from './edge_insets' ;
1416
1517/**
1618 * A single transform, generally used for a single tile to be
@@ -49,6 +51,7 @@ class Transform {
4951 _minPitch : number ;
5052 _maxPitch : number ;
5153 _center : LngLat ;
54+ _edgeInsets : EdgeInsets ;
5255 _constraining : boolean ;
5356 _posMatrixCache : { [ string ] : Float32Array } ;
5457 _alignedPosMatrixCache: { [ string ] : Float32Array } ;
@@ -74,6 +77,7 @@ class Transform {
7477 this . _fov = 0.6435011087932844 ;
7578 this . _pitch = 0 ;
7679 this . _unmodified = true ;
80+ this . _edgeInsets = new EdgeInsets ( ) ;
7781 this . _posMatrixCache = { } ;
7882 this . _alignedPosMatrixCache = { } ;
7983 }
@@ -90,6 +94,7 @@ class Transform {
9094 clone . _fov = this . _fov ;
9195 clone . _pitch = this . _pitch ;
9296 clone . _unmodified = this . _unmodified ;
97+ clone . _edgeInsets = this . _edgeInsets . clone ( ) ;
9398 clone . _calcMatrices ( ) ;
9499 return clone ;
95100 }
@@ -137,8 +142,8 @@ class Transform {
137142 return this . tileSize * this . scale ;
138143 }
139144
140- get centerPoint ( ) : Point {
141- return this . size . _div ( 2 ) ;
145+ get centerOffset ( ) : Point {
146+ return this . centerPoint . _sub ( this . size . _div ( 2 ) ) ;
142147 }
143148
144149 get size ( ) : Point {
@@ -204,6 +209,52 @@ class Transform {
204209 this . _calcMatrices ( ) ;
205210 }
206211
212+ get padding ( ) : PaddingOptions { return this . _edgeInsets . toJSON ( ) ; }
213+ set padding ( padding : PaddingOptions ) {
214+ if ( this . _edgeInsets . equals ( padding ) ) return ;
215+ this . _unmodified = false ;
216+ //Update edge-insets inplace
217+ this . _edgeInsets . interpolate ( this . _edgeInsets , padding , 1 ) ;
218+ this . _calcMatrices ( ) ;
219+ }
220+
221+ /**
222+ * The center of the screen in pixels with the top-left corner being (0,0)
223+ * and +y axis pointing downwards. This accounts for padding.
224+ *
225+ * @readonly
226+ * @type {Point }
227+ * @memberof Transform
228+ */
229+ get centerPoint ( ) : Point {
230+ return this . _edgeInsets . getCenter ( this . width , this . height ) ;
231+ }
232+
233+ /**
234+ * Returns if the padding params match
235+ *
236+ * @param {PaddingOptions } padding
237+ * @returns {boolean }
238+ * @memberof Transform
239+ */
240+ isPaddingEqual ( padding : PaddingOptions ) : boolean {
241+ return this . _edgeInsets . equals ( padding ) ;
242+ }
243+
244+ /**
245+ * Helper method to upadte edge-insets inplace
246+ *
247+ * @param {PaddingOptions } target
248+ * @param {number } t
249+ * @memberof Transform
250+ */
251+ interpolatePadding ( start : PaddingOptions , target : PaddingOptions , t : number ) {
252+ this . _unmodified = false ;
253+ this . _edgeInsets . interpolate ( start , target , t ) ;
254+ this . _constrain ( ) ;
255+ this . _calcMatrices ( ) ;
256+ }
257+
207258 /**
208259 * Return a zoom level that will cover all tiles the transform
209260 * @param {Object } options
@@ -281,9 +332,10 @@ class Transform {
281332 const centerPoint = [ numTiles * centerCoord . x , numTiles * centerCoord . y , 0 ] ;
282333 const cameraFrustum = Frustum . fromInvProjectionMatrix ( this . invProjMatrix , this . worldSize , z ) ;
283334
284- // No change of LOD behavior for pitch lower than 60: return only tile ids from the requested zoom level
335+ // No change of LOD behavior for pitch lower than 60 and when there is no top padding : return only tile ids from the requested zoom level
285336 let minZoom = options . minzoom || 0 ;
286- if ( this . pitch <= 60.0 )
337+ // Use 0.1 as an epsilon to avoid for explicit == 0.0 floating point checks
338+ if ( this . pitch <= 60.0 && this . _edgeInsets . top < 0.1 )
287339 minZoom = z ;
288340
289341 // There should always be a certain number of maximum zoom level tiles surrounding the center location
@@ -616,15 +668,17 @@ class Transform {
616668 _calcMatrices ( ) {
617669 if ( ! this . height ) return ;
618670
619- this . cameraToCenterDistance = 0.5 / Math . tan ( this . _fov / 2 ) * this . height ;
671+ const halfFov = this . _fov / 2 ;
672+ const offset = this . centerOffset ;
673+ this . cameraToCenterDistance = 0.5 / Math . tan ( halfFov ) * this . height ;
620674
621- // Find the distance from the center point [width/2, height/2] to the
622- // center top point [width/2, 0] in Z units, using the law of sines.
675+ // Find the distance from the center point [width/2 + offset.x , height/2 + offset.y ] to the
676+ // center top point [width/2 + offset.x , 0] in Z units, using the law of sines.
623677 // 1 Z unit is equivalent to 1 horizontal px at the center of the map
624678 // (the distance between[width/2, height/2] and [width/2 + 1, height/2])
625- const halfFov = this . _fov / 2 ;
626679 const groundAngle = Math . PI / 2 + this . _pitch ;
627- const topHalfSurfaceDistance = Math . sin ( halfFov ) * this . cameraToCenterDistance / Math . sin ( clamp ( Math . PI - groundAngle - halfFov , 0.01 , Math . PI - 0.01 ) ) ;
680+ const fovAboveCenter = this . _fov * ( 0.5 + offset . y / this . height ) ;
681+ const topHalfSurfaceDistance = Math . sin ( fovAboveCenter ) * this . cameraToCenterDistance / Math . sin ( clamp ( Math . PI - groundAngle - fovAboveCenter , 0.01 , Math . PI - 0.01 ) ) ;
628682 const point = this . point ;
629683 const x = point . x , y = point . y ;
630684
@@ -646,6 +700,10 @@ class Transform {
646700 let m = new Float64Array ( 16 ) ;
647701 mat4 . perspective ( m , this . _fov , this . width / this . height , nearZ , farZ ) ;
648702
703+ //Apply center of perspective offset
704+ m [ 8 ] = - offset . x * 2 / this . width ;
705+ m [ 9 ] = offset . y * 2 / this . height ;
706+
649707 mat4 . scale ( m , m , [ 1 , - 1 , 1 ] ) ;
650708 mat4 . translate ( m , m , [ 0 , 0 , - this . cameraToCenterDistance ] ) ;
651709 mat4 . rotateX ( m , m , this . _pitch ) ;
0 commit comments