Skip to content

Commit 2601f28

Browse files
authored
WebMercatorViewport support external projectionMatrix (#5930)
1 parent 5a733f5 commit 2601f28

File tree

4 files changed

+48
-15
lines changed

4 files changed

+48
-15
lines changed

docs/api-reference/core/web-mercator-viewport.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,15 @@ Parameters:
5151
+ `nearZMultiplier` (Number, optional) - Scaler for the near plane, 1 unit equals to the height of the viewport. Default to `0.1`.
5252
+ `farZMultiplier` (Number, optional) - Scaler for the far plane, 1 unit equals to the distance from the camera to the top edge of the screen. Default to `1.01`.
5353
+ `orthographic` (Boolean, optional) - Default `false`.
54+
+ `projectionMatrix` (Array, optional) - Optional 16-element 4x4 projection matrix, that overrides the matrix created from the parameters above.
5455

5556
Remarks:
5657

5758
* `altitude` has a default value that matches assumptions in mapbox-gl
5859
* `width` and `height` are forced to 1 if supplied as 0, to avoid division by zero. This is intended to reduce the burden of apps to check values before instantiating a `Viewport`.
5960
* When using Mercator projection, per cartographic tradition, longitudes and latitudes are specified as degrees.
6061
* `latitude` of `90` or `-90` are projected to infinity in [Web Mercator projection](https://en.wikipedia.org/wiki/Web_Mercator_projection). Using pole locations with this viewport may result in `NaN`s. Many base map providers cut off at `85.051129` at which the full world becomes a square.
62+
* When constructing the viewport, a field of view is not specified, but rather is calculated from the `altitude` or (if present) the `projectionMatrix`. The value can be obtained from `this.fovy` (in degrees).
6163

6264
Inherits all [Viewport methods](/docs/api-reference/core/viewport.md#methods).
6365

examples/webpack.config.local.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ function makeLocalDevConfig(EXAMPLE_DIR = LIB_DIR, linkToLuma, linkToMath) {
6161
'geoid',
6262
'geospatial',
6363
'main',
64-
'mercator',
64+
'web-mercator',
6565
'polygon',
6666
'proj4',
6767
'sun',

modules/core/src/viewports/web-mercator-viewport.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
getViewMatrix,
2828
addMetersToLngLat,
2929
getProjectionParameters,
30+
altitudeToFovy,
3031
fitBounds,
3132
getBounds
3233
} from '@math.gl/web-mercator';
@@ -53,6 +54,7 @@ export default class WebMercatorViewport extends Viewport {
5354
nearZMultiplier = 0.1,
5455
farZMultiplier = 1.01,
5556
orthographic = false,
57+
projectionMatrix,
5658

5759
repeat = false,
5860
worldOffset = 0
@@ -69,14 +71,27 @@ export default class WebMercatorViewport extends Viewport {
6971
// TODO - just throw an Error instead?
7072
altitude = Math.max(0.75, altitude);
7173

72-
const {fov, aspect, focalDistance, near, far} = getProjectionParameters({
73-
width,
74-
height,
75-
pitch,
76-
altitude,
77-
nearZMultiplier,
78-
farZMultiplier
79-
});
74+
let fovy;
75+
let projectionParameters = null;
76+
if (projectionMatrix) {
77+
fovy = altitudeToFovy(projectionMatrix[5] / 2);
78+
} else {
79+
fovy = altitudeToFovy(altitude);
80+
const {aspect, fov: fovyRadians, near, far} = getProjectionParameters({
81+
width,
82+
height,
83+
pitch,
84+
fovy,
85+
nearZMultiplier,
86+
farZMultiplier
87+
});
88+
projectionParameters = {
89+
fovyRadians,
90+
aspect,
91+
near,
92+
far
93+
};
94+
}
8095

8196
// The uncentered matrix allows us two move the center addition to the
8297
// shader (cheap) which gives a coordinate system that has its center in
@@ -108,12 +123,9 @@ export default class WebMercatorViewport extends Viewport {
108123
zoom,
109124

110125
// projection matrix parameters
111-
orthographic,
112-
fovyRadians: fov,
113-
aspect,
114-
focalDistance,
115-
near,
116-
far
126+
...projectionParameters,
127+
fovy,
128+
focalDistance: altitude
117129
});
118130

119131
// Save parameters
@@ -123,6 +135,7 @@ export default class WebMercatorViewport extends Viewport {
123135
this.pitch = pitch;
124136
this.bearing = bearing;
125137
this.altitude = altitude;
138+
this.fovy = fovy;
126139

127140
this.orthographic = orthographic;
128141

test/modules/core/viewports/web-mercator-viewport.spec.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@
2121
import test from 'tape-catch';
2222
import {equals, config, Vector3} from 'math.gl';
2323
import {WebMercatorViewport} from 'deck.gl';
24+
import {Matrix4} from 'math.gl';
2425

2526
// Adjust sensitivity of math.gl's equals
2627
const LNGLAT_TOLERANCE = 1e-6;
2728
const ALT_TOLERANCE = 1e-5;
2829
const OFFSET_TOLERANCE = 1e-5;
2930

31+
const DEGREES_TO_RADIANS = Math.PI / 180;
32+
3033
/* eslint-disable */
3134
const TEST_VIEWPORTS = [
3235
{
@@ -276,6 +279,21 @@ test('WebMercatorViewport.subViewports', t => {
276279
t.end();
277280
});
278281

282+
test('WebMercatorViewport.projectionMatrix', t => {
283+
const opts = {...TEST_VIEWPORTS[0]};
284+
285+
const fovy = 25;
286+
const projectionMatrix = new Matrix4().perspective({
287+
fovy: fovy * DEGREES_TO_RADIANS,
288+
aspect: opts.width / opts.height,
289+
near: 0.1,
290+
far: 10
291+
});
292+
let viewport = new WebMercatorViewport({projectionMatrix, ...opts});
293+
t.deepEqual(viewport.fovy, fovy, 'fovy is passed through');
294+
t.end();
295+
});
296+
279297
function getCulling(p, planes) {
280298
let outDir = null;
281299
p = new Vector3(p);

0 commit comments

Comments
 (0)