Skip to content

Commit

Permalink
Merge a67b2e6 into b2a5ec9
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress committed Jan 15, 2020
2 parents b2a5ec9 + a67b2e6 commit eb64031
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 12 deletions.
4 changes: 3 additions & 1 deletion docs/api-reference/map-view.md
Expand Up @@ -11,7 +11,9 @@ import {MapView} from '@deck.gl/core';
const view = new MapView({id, ...});
```

`MapView` takes the same parameters as the [View](/docs/api-reference/view.md) superclass constructor.
`MapView` takes the same parameters as the [View](/docs/api-reference/view.md) superclass constructor, plus the following:

- `repeat` (`Boolean`) - Whether to render multiple copies of the map at low zoom levels. Default `false`.

## View State

Expand Down
26 changes: 17 additions & 9 deletions modules/core/src/passes/layers-pass.js
Expand Up @@ -23,27 +23,32 @@ export default class LayersPass extends Pass {

const renderStats = [];

viewports.forEach((viewportOrDescriptor, i) => {
for (const viewportOrDescriptor of viewports) {
// Get a viewport from a viewport descriptor (which can be a plain viewport)
const viewport = viewportOrDescriptor.viewport || viewportOrDescriptor;
const view = views && views[viewport.id];

// Update context to point to this viewport
onViewportActive(viewport);

props.viewport = viewport;
props.view = view;

// render this viewport
const stats = this._drawLayersInViewport(gl, props);
renderStats.push(stats);
});
const subViewports = viewport.subViewports || [viewport];
for (const subViewport of subViewports) {
props.viewport = subViewport;

const stats = this._drawLayersInViewport(gl, props);
renderStats.push(stats);
}
}
return renderStats;
}

// Draws a list of layers in one viewport
// TODO - when picking we could completely skip rendering viewports that dont
// intersect with the picking rect
/* eslint-disable max-depth */
_drawLayersInViewport(
gl,
{layers, layerFilter, onError, viewport, view, pass = 'unknown', effects, moduleParameters}
Expand Down Expand Up @@ -73,7 +78,8 @@ export default class LayersPass extends Pass {
setParameters(gl, {viewport: glViewport});

// render layers in normal colors
layers.forEach((layer, layerIndex) => {
for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) {
const layer = layers[layerIndex];
// Check if we should draw layer
const shouldDrawLayer = this._shouldDrawLayer(layer, viewport, pass, layerFilter);

Expand All @@ -90,13 +96,14 @@ export default class LayersPass extends Pass {
renderStatus.visibleCount++;

const _moduleParameters = this._getModuleParameters(layer, effects, pass, moduleParameters);
const uniforms = Object.assign({}, layer.context.uniforms, {layerIndex});
const layerParameters = this.getLayerParameters(layer, layerIndex);
// overwrite layer.context.viewport with the sub viewport
_moduleParameters.viewport = viewport;

try {
layer.drawLayer({
moduleParameters: _moduleParameters,
uniforms,
uniforms: {layerIndex},
parameters: layerParameters
});
} catch (err) {
Expand All @@ -107,10 +114,11 @@ export default class LayersPass extends Pass {
}
}
}
});
}

return renderStatus;
}
/* eslint-enable max-depth */

/* Methods for subclass overrides */
shouldDrawLayer(layer) {
Expand Down
42 changes: 40 additions & 2 deletions modules/core/src/viewports/web-mercator-viewport.js
Expand Up @@ -32,6 +32,7 @@ import {

// TODO - import from math.gl
import * as vec2 from 'gl-matrix/vec2';
import {Matrix4} from 'math.gl';

export default class WebMercatorViewport extends Viewport {
/**
Expand All @@ -50,7 +51,10 @@ export default class WebMercatorViewport extends Viewport {
bearing = 0,
nearZMultiplier = 0.1,
farZMultiplier = 1.01,
orthographic = false
orthographic = false,

repeat = false,
worldOffset = 0
} = opts;

let {width, height, altitude = 1.5} = opts;
Expand All @@ -77,14 +81,19 @@ export default class WebMercatorViewport extends Viewport {
// shader (cheap) which gives a coordinate system that has its center in
// the layer's center position. This makes rotations and other modelMatrx
// transforms much more useful.
const viewMatrixUncentered = getViewMatrix({
let viewMatrixUncentered = getViewMatrix({
height,
pitch,
bearing,
scale,
altitude
});

if (worldOffset) {
const viewOffset = new Matrix4().translate([512 * worldOffset, 0, 0]);
viewMatrixUncentered = viewOffset.multiplyLeft(viewMatrixUncentered);
}

const viewportOpts = Object.assign({}, opts, {
// x, y,
width,
Expand Down Expand Up @@ -118,10 +127,39 @@ export default class WebMercatorViewport extends Viewport {

this.orthographic = orthographic;

this._subViewports = repeat ? [] : null;

Object.freeze(this);
}
/* eslint-enable complexity, max-statements */

get subViewports() {
if (this._subViewports && !this._subViewports.length) {
// Cache sub viewports so that we only calculate them once
const topLeft = this.unproject([0, 0]);
const topRight = this.unproject([this.width, 0]);
const bottomLeft = this.unproject([0, this.height]);
const bottomRight = this.unproject([this.width, this.height]);

const minLon = Math.min(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]);
const maxLon = Math.max(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]);

const minOffset = Math.floor((minLon + 180) / 360);
const maxOffset = Math.ceil((maxLon - 180) / 360);

for (let x = minOffset; x <= maxOffset; x++) {
const offsetViewport = x
? new WebMercatorViewport({
...this,
worldOffset: x
})
: this;
this._subViewports.push(offsetViewport);
}
}
return this._subViewports;
}

/**
* Add a meter delta to a base lnglat coordinate, returning a new lnglat array
*
Expand Down
34 changes: 34 additions & 0 deletions test/modules/core/viewports/web-mercator-viewport.spec.js
Expand Up @@ -242,6 +242,40 @@ test('WebMercatorViewport.getFrustumPlanes', t => {
t.end();
});

test('WebMercatorViewport.subViewports', t => {
let viewport = new WebMercatorViewport(TEST_VIEWPORTS[0]);
t.deepEqual(viewport.subViewports, null, 'gets correct subViewports');

viewport = new WebMercatorViewport({...TEST_VIEWPORTS[0], repeat: true});
t.deepEqual(viewport.subViewports, [viewport], 'gets correct subViewports');

viewport = new WebMercatorViewport({
width: 800,
height: 400,
longitude: 0,
latitude: 0,
zoom: 0,
repeat: true
});
const {subViewports} = viewport;
t.is(subViewports.length, 3, 'gets correct subViewports');
t.deepEqual(
subViewports[0].project([0, 0]),
[400 - 512, 200],
'center offset in subViewports[0]'
);
t.deepEqual(subViewports[1].project([0, 0]), [400, 200], 'center offset in subViewports[1]');
t.deepEqual(
subViewports[2].project([0, 0]),
[400 + 512, 200],
'center offset in subViewports[2]'
);

t.is(viewport.subViewports, subViewports, 'subViewports are cached');

t.end();
});

function getCulling(p, planes) {
let outDir = null;
p = new Vector3(p);
Expand Down
Binary file added test/render/golden-images/map-repeat.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions test/render/test-cases.js
Expand Up @@ -9,6 +9,7 @@ import {
} from '@deck.gl/aggregation-layers';
import {
COORDINATE_SYSTEM,
MapView,
OrbitView,
OrthographicView,
FirstPersonView,
Expand Down Expand Up @@ -1984,5 +1985,25 @@ export const TEST_CASES = [
})
],
goldenImage: './test/render/golden-images/binary.png'
},
{
name: 'map-repeat',
views: new MapView({repeat: true}),
viewState: {
latitude: 0,
longitude: 0,
zoom: 0,
pitch: 0,
bearing: 0
},
layers: [
new ScatterplotLayer({
data: h3.getRes0Indexes(),
getPosition: d => h3.h3ToGeo(d).reverse(),
radiusMinPixels: 4,
getFillColor: [255, 0, 0]
})
],
goldenImage: './test/render/golden-images/map-repeat.png'
}
];

0 comments on commit eb64031

Please sign in to comment.