Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for non-mercator projections #11124

Merged
merged 42 commits into from Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ace7e13
rough projection support
ansis Dec 11, 2020
20896c5
projections stencil clipping and refactor (#410)
May 26, 2021
51b7609
Projections fix location issues (#414)
May 26, 2021
c56bac9
[projections] Adaptive geometry resampling for alternative projection…
mourner Jun 8, 2021
dc31595
Refactor projections code to get all tests passing (#10732)
Jun 15, 2021
159f0a5
[projections] Simplify and optimize tile transform code (#10780)
mourner Jun 16, 2021
4719fc7
[projections] Fix performance regression in draw_background (#10747)
mourner Jun 24, 2021
f40ca99
Pin chrome to version 91 (#10887) (#10896)
Jul 27, 2021
602cf58
Refactor raw projections, handle projection options (#10913)
mourner Aug 9, 2021
d83d1a3
Fix bearing for non-mercator projections (#10781)
Aug 9, 2021
2066b6a
Use adaptive resampling with MARTINI & Earcut for non-Mercator tiles …
mourner Sep 20, 2021
947ca58
Clamp unproject to valid geo range in alternate projections (#10992)
mourner Sep 20, 2021
480cc45
correct zoom, bearing and shear for projections (#10976)
ansis Sep 29, 2021
9ea3ad1
Fix circle and heatmap on alternate projections (#11074)
mourner Oct 1, 2021
f42389d
fix pitch, line-width and other properties for projections (#11080)
ansis Oct 5, 2021
a71116b
Add Equal Earth, Natural Earth and Lambert Conformal Conic projection…
Oct 6, 2021
2d22069
Fix constraining logic for alternate projections (#11092)
mourner Oct 13, 2021
0cc5e30
Projections public API (#11002)
Oct 14, 2021
2f8e11b
Merge remote-tracking branch 'origin/main' into projections
ansis Oct 14, 2021
a2edaef
fix conflicts
mourner Oct 14, 2021
be8b158
fix seams around alternate-projected tiles (#11119)
mourner Oct 14, 2021
6d00091
fix unit tests
mourner Oct 14, 2021
b80a469
remove alaska
ansis Oct 15, 2021
ec815c8
Basic support for custom maxBounds in alternate projections (#11121)
mourner Oct 15, 2021
b3e01e9
fix image and video sources in alternate projections (#11123)
ansis Oct 15, 2021
9e92589
clean up debug pages
ansis Oct 15, 2021
efc3cde
remove uncessary deg <--> rad conversions
ansis Oct 15, 2021
2044835
fix filename casing
ansis Oct 15, 2021
6b9b811
fix queryRenderedFeatures for alternate projections (#11125)
ansis Oct 15, 2021
503a4a7
Projections fixups (#11127)
Oct 15, 2021
534f6b9
disable terrain and fog for alternate projections (#11126)
ansis Oct 15, 2021
658ad81
Lazily instantiate projected tile debug buffers and release projected…
Oct 16, 2021
2c08a6e
enable lod tile loading for projections (#11129)
ansis Oct 18, 2021
2a4dc1d
allow map.setProjection(null)
ansis Oct 18, 2021
fe7230f
add limitations
ansis Oct 18, 2021
8047cd5
avoid recreating tile buffer
ansis Oct 18, 2021
d0afb1b
fix assertion error
ansis Oct 18, 2021
e673a44
Merge remote-tracking branch 'origin/main' into projections
ansis Oct 18, 2021
1b43ca6
fix requires
ansis Oct 18, 2021
4296809
center projections vertically
ansis Oct 19, 2021
c63fd55
Fix tile buffer destroyed but not reset (#11134)
karimnaaji Oct 19, 2021
5af4076
mention settin bounds in projection docs
ansis Oct 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion LICENSE.txt
Expand Up @@ -53,8 +53,10 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------

Contains a portion of d3-color https://github.com/d3/d3-color
Contains a portion of d3-geo https://github.com/d3/d3-geo
Contains a portion of d3-geo-projection https://github.com/d3/d3-geo-projection

Copyright 2010-2016 Mike Bostock
Copyright 2010-2021 Mike Bostock
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
Expand Down
4 changes: 4 additions & 0 deletions build/generate-flow-typed-style-spec.js
Expand Up @@ -38,6 +38,8 @@ function flowType(property) {
return 'TerrainSpecification';
case 'fog':
return 'FogSpecification';
case 'projection':
return 'ProjectionSpecification';
case 'sources':
return '{[_: string]: SourceSpecification}';
case '*':
Expand Down Expand Up @@ -185,6 +187,8 @@ ${flowObjectDeclaration('TerrainSpecification', spec.terrain)}

${flowObjectDeclaration('FogSpecification', spec.fog)}

${flowObjectDeclaration('ProjectionSpecification', spec.projection)}

${spec.source.map(key => flowObjectDeclaration(flowSourceTypeName(key), spec[key])).join('\n\n')}

export type SourceSpecification =
Expand Down
9 changes: 6 additions & 3 deletions build/generate-struct-arrays.js
Expand Up @@ -118,10 +118,10 @@ function camelize (str) {
global.camelize = camelize;

import posAttributes from '../src/data/pos_attributes.js';
import rasterBoundsAttributes from '../src/data/raster_bounds_attributes.js';
import boundsAttributes from '../src/data/bounds_attributes.js';

createStructArrayType('pos', posAttributes);
createStructArrayType('raster_bounds', rasterBoundsAttributes);
createStructArrayType('raster_bounds', boundsAttributes);

import circleAttributes from '../src/data/bucket/circle_attributes.js';
import fillAttributes from '../src/data/bucket/fill_attributes.js';
Expand All @@ -130,6 +130,7 @@ import lineAttributesExt from '../src/data/bucket/line_attributes_ext.js';
import patternAttributes from '../src/data/bucket/pattern_attributes.js';
import dashAttributes from '../src/data/bucket/dash_attributes.js';
import skyboxAttributes from '../src/render/skybox_attributes.js';
import tileBoundsAttributes from '../src/data/bounds_attributes.js';
import {fillExtrusionAttributes, centroidAttributes} from '../src/data/bucket/fill_extrusion_attributes.js';

// layout vertex arrays
Expand Down Expand Up @@ -208,6 +209,9 @@ createStructArrayType('line_strip_index', createLayout([
// skybox vertex array
createStructArrayType(`skybox_vertex`, skyboxAttributes);

// tile bounds vertex array
createStructArrayType(`tile_bounds`, tileBoundsAttributes);

// paint vertex arrays

// used by SourceBinder for float properties
Expand Down Expand Up @@ -244,7 +248,6 @@ fs.writeFileSync('src/data/array_types.js',
import assert from 'assert';
import {Struct, StructArray} from '../util/struct_array.js';
import {register} from '../util/web_worker_transfer.js';
import Point from '@mapbox/point-geometry';

${layouts.map(structArrayLayoutJs).join('\n')}
${arraysWithStructAccessors.map(structArrayJs).join('\n')}
Expand Down
189 changes: 189 additions & 0 deletions debug/projections.html
@@ -0,0 +1,189 @@
<!DOCTYPE html>
ansis marked this conversation as resolved.
Show resolved Hide resolved
<html>
<head>
<title>Mapbox GL JS debug page</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel='stylesheet' href='../dist/mapbox-gl.css' />
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
.map-overlay {
background-color: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
font: bold 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
left: 10px;
padding: 10px;
position: absolute;
top: 10px;
width: 150px;
z-index: 1;
}

fieldset {
border: none;
padding: 5px 0;
}

select, input {
background-color: transparent;
border-radius: 3px;
margin: 0;
}

select {
width: 100%;
}
</style>
</head>

<body>
<div class="map-overlay top">
<fieldset>
<label>Projection:</label>
<select id="projName">
<option value="albers" selected>Albers USA</option>
<option value="equalEarth">Equal Earth</option>
<option value="equirectangular">Equirectangular</option>
<option value="lambertConformalConic">Lambert Conformal Conic</option>
<option value="mercator">Mercator</option>
<option value="naturalEarth">Natural Earth</option>
<option value="winkelTripel">Winkel Tripel</option>
</select>
</fieldset>
<fieldset>
<label>Style:</label>
<select id="styleName">
<option value="streets" selected>Streets</option>
<option value="satellite">Satellite</option>
</select>
</fieldset>
<fieldset>
<label>Graticule:</label>
<input id="graticule" type="checkbox">
</fieldset>
<fieldset>
<label>Show Debug Tiles:</label>
<input id="debug" type="checkbox" checked=true>
</fieldset>
</div>
<div id='map'></div>

<script src='../dist/mapbox-gl-dev.js'></script>
<script src='../debug/access_token_generated.js'></script>
<script>

let map;

const zooms = {
albers: 3,
lambertConformalConic: 3,
winkelTripel: 1.2
};
const centers = {
albers: [-122.414, 37.776],
lambertConformalConic: [-122.414, 37.776]
};

makeMap();

function makeMap() {
if (map) map.remove();
const el = document.getElementById('projName');
const projection = el.options[el.selectedIndex].value;
const zoom = zooms[projection] || 1;
const center = centers[projection] || [0, 0];
const styles = {
streets: 'mapbox://styles/mapbox/streets-v10',
satellite: 'mapbox://styles/mapbox/satellite-streets-v11'
};
const styleEl = document.getElementById('styleName');
const styleName = styleEl.options[styleEl.selectedIndex].value;
const style = styles[styleName];

map = new mapboxgl.Map({
projection,
container: 'map',
zoom,
center,
style,
hash: true
});
map.showTileBoundaries = true;
addGraticule();
}

map.on('click', function () {
console.log('projection', map.getProjection());
});

document.getElementById('projName').addEventListener('change', (e) => {
const el = document.getElementById('projName');
const projection = el.options[el.selectedIndex].value;
const zoom = zooms[projection] || 1;
const center = centers[projection] || [0, 0];
map.jumpTo({center, zoom});
map.setProjection(el.options[el.selectedIndex].value);
});

document.getElementById('styleName').addEventListener('change', (e) => {
makeMap();
});

document.getElementById('graticule').addEventListener('change', (e) => {
map.setPaintProperty('graticule', 'line-opacity', e.target.checked ? 1 : 0);
});

document.getElementById('debug').addEventListener('change', (e) => {
map.showTileBoundaries = e.target.checked;
});

function addGraticule() {
map.on('style.load', () => {
const fc = {
type: 'FeatureCollection',
features: []
};

for (let i = -170; i < 180; i += 10) {
fc.features.push({
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[i, -80], [i, 80]]
}
});
}
for (let i = -80; i < 80; i += 10) {
fc.features.push({
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[-180, i], [180, i]]
}
});
}

map.addSource('graticule', {
buffer: 0,
type: 'geojson',
data: fc
});

map.addLayer({
id: 'graticule',
source: 'graticule',
type: 'line',
paint: {
'line-width': 1,
'line-color': '#aaa',
'line-opacity': document.getElementById('graticule').checked ? 1 : 0
}
});
});
}

</script>
</body>
</html>
40 changes: 2 additions & 38 deletions src/data/array_types.js
Expand Up @@ -815,41 +815,6 @@ class StructArrayLayout1ui2 extends StructArray {
StructArrayLayout1ui2.prototype.bytesPerElement = 2;
register('StructArrayLayout1ui2', StructArrayLayout1ui2);

/**
* Implementation of the StructArray layout:
* [0]: Float32[5]
*
* @private
*/
class StructArrayLayout5f20 extends StructArray {
uint8: Uint8Array;
float32: Float32Array;

_refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}

emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number) {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4);
}

emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number) {
const o4 = i * 5;
this.float32[o4 + 0] = v0;
this.float32[o4 + 1] = v1;
this.float32[o4 + 2] = v2;
this.float32[o4 + 3] = v3;
this.float32[o4 + 4] = v4;
return i;
}
}

StructArrayLayout5f20.prototype.bytesPerElement = 20;
register('StructArrayLayout5f20', StructArrayLayout5f20);

/**
* Implementation of the StructArray layout:
* [0]: Float32[2]
Expand Down Expand Up @@ -1227,7 +1192,6 @@ export {
StructArrayLayout1ul3ui12,
StructArrayLayout2ui4,
StructArrayLayout1ui2,
StructArrayLayout5f20,
StructArrayLayout2f8,
StructArrayLayout4f16,
StructArrayLayout2i4 as PosArray,
Expand All @@ -1251,6 +1215,6 @@ export {
StructArrayLayout3ui6 as TriangleIndexArray,
StructArrayLayout2ui4 as LineIndexArray,
StructArrayLayout1ui2 as LineStripIndexArray,
StructArrayLayout5f20 as GlobeVertexArray,
StructArrayLayout3f12 as SkyboxVertexArray
StructArrayLayout3f12 as SkyboxVertexArray,
StructArrayLayout4i8 as TileBoundsArray
};
File renamed without changes.
3 changes: 2 additions & 1 deletion src/data/bucket.js
Expand Up @@ -9,6 +9,7 @@ import type {FeatureStates} from '../source/source_state.js';
import type {ImagePosition} from '../render/image_atlas.js';
import type LineAtlas from '../render/line_atlas.js';
import type {CanonicalTileID} from '../source/tile_id.js';
import type {TileTransform} from '../geo/projection/tile_transform.js';

export type BucketParameters<Layer: TypedStyleLayer> = {
index: number,
Expand Down Expand Up @@ -78,7 +79,7 @@ export interface Bucket {
+layers: Array<any>;
+stateDependentLayers: Array<any>;
+stateDependentLayerIds: Array<string>;
populate(features: Array<IndexedFeature>, options: PopulateParameters, canonical: CanonicalTileID): void;
populate(features: Array<IndexedFeature>, options: PopulateParameters, canonical: CanonicalTileID, tileTransform: TileTransform): void;
update(states: FeatureStates, vtLayer: VectorTileLayer, availableImages: Array<string>, imagePositions: {[_: string]: ImagePosition}): void;
isEmpty(): boolean;

Expand Down
5 changes: 3 additions & 2 deletions src/data/bucket/circle_bucket.js
Expand Up @@ -28,6 +28,7 @@ import type VertexBuffer from '../../gl/vertex_buffer.js';
import type Point from '@mapbox/point-geometry';
import type {FeatureStates} from '../../source/source_state.js';
import type {ImagePosition} from '../../render/image_atlas.js';
import type {TileTransform} from '../../geo/projection/tile_transform.js';

function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) {
layoutVertexArray.emplaceBack(
Expand Down Expand Up @@ -77,7 +78,7 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);
}

populate(features: Array<IndexedFeature>, options: PopulateParameters, canonical: CanonicalTileID) {
populate(features: Array<IndexedFeature>, options: PopulateParameters, canonical: CanonicalTileID, tileTransform: TileTransform) {
const styleLayer = this.layers[0];
const bucketFeatures = [];
let circleSortKey = null;
Expand All @@ -103,7 +104,7 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
type: feature.type,
sourceLayerIndex,
index,
geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature),
geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature, canonical, tileTransform),
patterns: {},
sortKey
};
Expand Down
5 changes: 3 additions & 2 deletions src/data/bucket/fill_bucket.js
Expand Up @@ -31,6 +31,7 @@ import type VertexBuffer from '../../gl/vertex_buffer.js';
import type Point from '@mapbox/point-geometry';
import type {FeatureStates} from '../../source/source_state.js';
import type {ImagePosition} from '../../render/image_atlas.js';
import type {TileTransform} from '../../geo/projection/tile_transform.js';

class FillBucket implements Bucket {
index: number;
Expand Down Expand Up @@ -75,7 +76,7 @@ class FillBucket implements Bucket {
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);
}

populate(features: Array<IndexedFeature>, options: PopulateParameters, canonical: CanonicalTileID) {
populate(features: Array<IndexedFeature>, options: PopulateParameters, canonical: CanonicalTileID, tileTransform: TileTransform) {
this.hasPattern = hasPattern('fill', this.layers, options);
const fillSortKey = this.layers[0].layout.get('fill-sort-key');
const bucketFeatures = [];
Expand All @@ -96,7 +97,7 @@ class FillBucket implements Bucket {
type: feature.type,
sourceLayerIndex,
index,
geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature),
geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature, canonical, tileTransform),
patterns: {},
sortKey
};
Expand Down