Skip to content

Commit

Permalink
Merge branch 'master' into x/picking-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress committed Jun 18, 2020
2 parents da817b6 + 8af69dc commit b4c79b7
Show file tree
Hide file tree
Showing 24 changed files with 296 additions and 104 deletions.
6 changes: 4 additions & 2 deletions docs/api-reference/layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,11 @@ Specifies a longitude and a latitude from which meter offsets are calculated. Se

##### `wrapLongitude` (Boolean, optional)

Automatically wraps longitudes over the 180th antimeridian for the best visibility in the current viewport.
Automatically wraps longitudes over the 180th antimeridian.

This option is applied per vertex by dynamically moving the antimeridian the furthest away from the current center of the viewport. It is useful when viewing local data that cross the 180th meridian. However, path/polygon features that get split by the dynamic antimeridian may still be rendered incorrectly. When viewing at a global zoom level, it is recommended that you disable this option and preprocess the data for their best placement.
When enabled on `PathLayer`, `PolygonLayer` and `GeoJsonLayer`, the paths/polygons are interpretted such that the connection between any two neighboring vertices is drawn on the shorter side of the world, and split into two if it crosses the 180th meridian. Note that this introduces CPU overhead at runtime. When working with static data, it is recommend that you preprocess the features offline instead of using this option.

When enabled on other layers, the effect is applied per vertex by dynamically moving the antimeridian the furthest away from the current center of the viewport. It is most useful when viewing local data that cross the 180th meridian.

Default `false`.

Expand Down
4 changes: 4 additions & 0 deletions modules/core/src/lib/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ export default class Layer extends Component {
return this.internalState && !this.internalState.isAsyncPropLoading();
}

get wrapLongitude() {
return this.props.wrapLongitude;
}

// Returns true if the layer is pickable and visible.
isPickable() {
return this.props.pickable && this.props.visible;
Expand Down
1 change: 1 addition & 0 deletions modules/core/src/passes/layers-pass.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export default class LayersPass extends Pass {

_getModuleParameters(layer, effects, pass, overrides) {
const moduleParameters = Object.assign(Object.create(layer.props), {
autoWrapLongitude: layer.wrapLongitude,
viewport: layer.context.viewport,
mousePosition: layer.context.mousePosition,
pickingActive: 0,
Expand Down
4 changes: 2 additions & 2 deletions modules/core/src/shaderlib/project/viewport-uniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export function getUniformsFromViewport({
// Match Layer.defaultProps
coordinateSystem = COORDINATE_SYSTEM.DEFAULT,
coordinateOrigin,
wrapLongitude = false,
autoWrapLongitude = false,
// Deprecated
projectionMode,
positionOrigin
Expand All @@ -191,7 +191,7 @@ export function getUniformsFromViewport({
coordinateOrigin
});

uniforms.project_uWrapLongitude = wrapLongitude;
uniforms.project_uWrapLongitude = autoWrapLongitude;
uniforms.project_uModelMatrix = modelMatrix || IDENTITY_MATRIX;

return uniforms;
Expand Down
1 change: 1 addition & 0 deletions modules/geo-layers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"dependencies": {
"@loaders.gl/3d-tiles": "^2.1.5",
"@loaders.gl/core": "^2.1.5",
"@loaders.gl/loader-utils": "^2.2.0-alpha.3",
"@loaders.gl/mvt": "^2.1.5",
"@loaders.gl/terrain": "^2.1.5",
"@loaders.gl/tiles": "^2.1.5",
Expand Down
48 changes: 29 additions & 19 deletions modules/geo-layers/src/tile-layer/tile-2d-header.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import {log} from '@deck.gl/core';
import {isPromise} from '@loaders.gl/core';

export default class Tile2DHeader {
constructor({x, y, z, onTileLoad, onTileError}) {
this.x = x;
this.y = y;
this.z = z;
this.isVisible = false;
this.isSelected = false;
this.parent = null;
this.children = [];

this.content = null;
this._isLoaded = false;
this._isCancelled = false;

this.onTileLoad = onTileLoad;
this.onTileError = onTileError;
Expand All @@ -25,6 +26,10 @@ export default class Tile2DHeader {
return this._isLoaded;
}

get isCancelled() {
return this._isCancelled;
}

get byteLength() {
const result = this.content ? this.content.byteLength : 0;
if (!Number.isFinite(result)) {
Expand All @@ -33,38 +38,43 @@ export default class Tile2DHeader {
return result;
}

loadData(getTileData) {
async _loadData(getTileData, requestScheduler) {
const {x, y, z, bbox} = this;
if (!getTileData) {

const requestToken = await requestScheduler.scheduleRequest(this, tile => {
return tile.isSelected;
});

if (!requestToken) {
this._isCancelled = true;
return;
}

this._isCancelled = false;
let tileData;
let error;
try {
tileData = getTileData({x, y, z, bbox});
tileData = await getTileData({x, y, z, bbox});
} catch (err) {
error = err || true;
} finally {
requestToken.done();
this._isLoaded = true;
this.onTileError(err, this);
return;
}

if (!isPromise(tileData)) {
if (error) {
this.onTileError(error, this);
} else {
this.content = tileData;
this._isLoaded = true;
this.onTileLoad(this);
}
}

loadData(getTileData, requestScheduler) {
if (!getTileData) {
return;
}

this._loader = tileData
.then(buffers => {
this.content = buffers;
this._isLoaded = true;
this.onTileLoad(this);
return buffers;
})
.catch(err => {
this._isLoaded = true;
this.onTileError(err, this);
});
this._loader = this._loadData(getTileData, requestScheduler);
}
}
12 changes: 9 additions & 3 deletions modules/geo-layers/src/tile-layer/tile-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ const defaultProps = {
maxCacheSize: null,
maxCacheByteSize: null,
refinementStrategy: STRATEGY_DEFAULT,
zRange: null
zRange: null,
throttleRequests: true,
maxRequests: 8
};

export default class TileLayer extends CompositeLayer {
Expand Down Expand Up @@ -59,7 +61,9 @@ export default class TileLayer extends CompositeLayer {
maxCacheSize,
maxCacheByteSize,
refinementStrategy,
extent
extent,
throttleRequests,
maxRequests
} = props;
tileset = new Tileset2D({
getTileData: this.getTileData.bind(this),
Expand All @@ -71,7 +75,9 @@ export default class TileLayer extends CompositeLayer {
refinementStrategy,
extent,
onTileLoad: this._onTileLoad.bind(this),
onTileError: this._onTileError.bind(this)
onTileError: this._onTileError.bind(this),
throttleRequests,
maxRequests
});
this.setState({tileset});
} else if (changeFlags.propsChanged || changeFlags.updateTriggersChanged) {
Expand Down
14 changes: 13 additions & 1 deletion modules/geo-layers/src/tile-layer/tileset-2d.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Tile2DHeader from './tile-2d-header';
import {getTileIndices, tileToBoundingBox} from './utils';
import {RequestScheduler} from '@loaders.gl/loader-utils';

const TILE_STATE_UNKNOWN = 0;
const TILE_STATE_VISIBLE = 1;
Expand Down Expand Up @@ -55,6 +56,11 @@ export default class Tileset2D {
}
};

this._requestScheduler = new RequestScheduler({
maxRequests: opts.maxRequests,
throttleRequests: opts.throttleRequests && opts.maxRequests > 0
});

// Maps tile id in string {z}-{x}-{y} to a Tile object
this._cache = new Map();
this._tiles = [];
Expand Down Expand Up @@ -161,6 +167,9 @@ export default class Tileset2D {
changed = true;
tile.isVisible = isVisible;
}

// isSelected used in request scheduler
tile.isSelected = tile.state === TILE_STATE_SELECTED;
}

return changed;
Expand Down Expand Up @@ -273,10 +282,13 @@ export default class Tileset2D {
onTileError: this.onTileError
});
Object.assign(tile, this.getTileMetadata(tile));
tile.loadData(this._getTileData);
tile.loadData(this._getTileData, this._requestScheduler);
this._cache.set(tileId, tile);
this._dirty = true;
} else if (tile && tile.isCancelled) {
tile.loadData(this._getTileData, this._requestScheduler);
}

return tile;
}

Expand Down
5 changes: 5 additions & 0 deletions modules/layers/src/path-layer/path-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ export default class PathLayer extends Layer {
return super.getShaders({vs, fs, modules: [project32, picking]}); // 'project' module added by default.
}

get wrapLongitude() {
return false;
}

initializeState() {
const noAlloc = true;
const attributeManager = this.getAttributeManager();
Expand Down Expand Up @@ -148,6 +152,7 @@ export default class PathLayer extends Layer {
loop: props._pathType === 'loop',
getGeometry: props.getPath,
positionFormat: props.positionFormat,
wrapLongitude: props.wrapLongitude,
// TODO - move the flag out of the viewport
resolution: this.context.viewport.resolution,
dataChanged: changeFlags.dataChanged
Expand Down
22 changes: 19 additions & 3 deletions modules/layers/src/path-layer/path-tesselator.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default class PathTesselator extends Tesselator {

normalizeGeometry(path) {
if (this.normalize) {
return normalizePath(path, this.positionSize, this.opts.resolution);
return normalizePath(path, this.positionSize, this.opts.resolution, this.opts.wrapLongitude);
}
return path;
}
Expand All @@ -66,6 +66,13 @@ export default class PathTesselator extends Tesselator {

/* Implement base Tesselator interface */
getGeometrySize(path) {
if (Array.isArray(path[0])) {
let size = 0;
for (const subPath of path) {
size += this.getGeometrySize(subPath);
}
return size;
}
const numPoints = this.getPathLength(path);
if (numPoints < 2) {
// invalid path
Expand All @@ -82,8 +89,17 @@ export default class PathTesselator extends Tesselator {
if (context.geometrySize === 0) {
return;
}
this._updateSegmentTypes(path, context);
this._updatePositions(path, context);
if (path && Array.isArray(path[0])) {
for (const subPath of path) {
const geometrySize = this.getGeometrySize(subPath);
context.geometrySize = geometrySize;
this.updateGeometryAttributes(subPath, context);
context.vertexStart += geometrySize;
}
} else {
this._updateSegmentTypes(path, context);
this._updatePositions(path, context);
}
}

_updateSegmentTypes(path, context) {
Expand Down
7 changes: 5 additions & 2 deletions modules/layers/src/path-layer/path.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {cutPolylineByGrid} from '@math.gl/polygon';
import {cutPolylineByGrid, cutPolylineByMercatorBounds} from '@math.gl/polygon';

/** Returns a flat array of path positions
* Flattens a nested path object
* Cut the feature if needed (globe projection, wrap longitude, etc.)
*/
export function normalizePath(path, size, gridResolution) {
export function normalizePath(path, size, gridResolution, wrapLongitude) {
let flatPath = path;
if (Array.isArray(path[0])) {
const length = path.length * size;
Expand All @@ -18,5 +18,8 @@ export function normalizePath(path, size, gridResolution) {
if (gridResolution) {
return cutPolylineByGrid(flatPath, {size, gridResolution});
}
if (wrapLongitude) {
return cutPolylineByMercatorBounds(flatPath, {size});
}
return flatPath;
}
9 changes: 8 additions & 1 deletion modules/layers/src/solid-polygon-layer/polygon-tesselator.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
// - 3D wireframes (not yet)
import * as Polygon from './polygon';
import {Tesselator} from '@deck.gl/core';
import {cutPolygonByGrid} from '@math.gl/polygon';
import {cutPolygonByGrid, cutPolygonByMercatorBounds} from '@math.gl/polygon';

// This class is set up to allow querying one attribute at a time
// the way the AttributeManager expects it
Expand Down Expand Up @@ -72,6 +72,13 @@ export default class PolygonTesselator extends Tesselator {
edgeTypes: true
});
}
if (this.opts.wrapLongitude) {
return cutPolygonByMercatorBounds(polygon.positions || polygon, polygon.holeIndices, {
size: this.positionSize,
maxLatitude: 86,
edgeTypes: true
});
}
}
return polygon;
}
Expand Down
5 changes: 5 additions & 0 deletions modules/layers/src/solid-polygon-layer/solid-polygon-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export default class SolidPolygonLayer extends Layer {
});
}

get wrapLongitude() {
return false;
}

initializeState() {
const {gl, viewport} = this.context;
let {coordinateSystem} = this.props;
Expand Down Expand Up @@ -273,6 +277,7 @@ export default class SolidPolygonLayer extends Layer {
buffers,
getGeometry: props.getPolygon,
positionFormat: props.positionFormat,
wrapLongitude: props.wrapLongitude,
// TODO - move the flag out of the viewport
resolution: this.context.viewport.resolution,
fp64: this.use64bitPositions(),
Expand Down
3 changes: 3 additions & 0 deletions modules/react/src/utils/extract-jsx-layers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ function wrapInView(node) {
if (Array.isArray(node)) {
return node.map(wrapInView);
}
if (node.type === React.Fragment) {
return wrapInView(node.props.children);
}
if (inheritsFrom(node.type, View)) {
return node;
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"jsdom": false
},
"resolutions": {
"@loaders.gl/loader-utils": "^2.2.0-alpha.3",
"@math.gl/core": "3.2.0-alpha.5"
},
"devDependencies": {
Expand Down
Loading

0 comments on commit b4c79b7

Please sign in to comment.