Skip to content

Commit

Permalink
projections stencil clipping and refactor (#410)
Browse files Browse the repository at this point in the history
* Enable stencil clipping for line and fill layers

* Use buffers from tile

* Refactor tile bounds buffers

* Rename things to not exclusively be RasterBounds

* Create projections directory

* More refactoring

* Combine matrix calculations

* Cleanup

* Refactor projections to new folder

* Begin debug work

* Tile boundaries are working

* Refactor indexbuffer and segmentvector to per painter

* merge projectx and projecty functions

* nits

Co-authored-by: Ansis Brammanis <ansis@mapbox.com>
  • Loading branch information
Ryan Hamley and ansis committed May 26, 2021
1 parent ace7e13 commit 20896c5
Show file tree
Hide file tree
Showing 24 changed files with 271 additions and 219 deletions.
2 changes: 1 addition & 1 deletion build/generate-struct-arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ function camelize (str) {
global.camelize = camelize;

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

createStructArrayType('pos', posAttributes);
createStructArrayType('raster_bounds', rasterBoundsAttributes);
Expand Down
1 change: 1 addition & 0 deletions src/data/array_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,7 @@ export {
StructArrayLayout4f16,
StructArrayLayout2i4 as PosArray,
StructArrayLayout4i8 as RasterBoundsArray,
StructArrayLayout4i8 as StencilBoundsArray,
StructArrayLayout2i4 as CircleLayoutArray,
StructArrayLayout2i4 as FillLayoutArray,
StructArrayLayout4i8 as FillExtrusionLayoutArray,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// @flow
import {createLayout} from '../util/struct_array.js';

export default createLayout([
export const rasterBoundsAttributes = createLayout([
{name: 'a_pos', type: 'Int16', components: 2},
{name: 'a_texture_pos', type: 'Int16', components: 2}
]);

export const stencilBoundsAttributes = createLayout([
{name: 'a_pos', type: 'Int16', components: 2}
]);
13 changes: 6 additions & 7 deletions src/data/load_geometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,12 @@ export default function loadGeometry(feature: VectorTileFeature, canonical): Arr
const cs = projection.tileTransform(canonical);
const reproject = (p, featureExtent) => {
const s = Math.pow(2, canonical.z)
const x = (canonical.x + p.x / featureExtent) / s;
const y = (canonical.y + p.y / featureExtent) / s;
const l = new MercatorCoordinate(x, y).toLngLat();
const x_ = projection.projectX(l.lng, l.lat);
const y_ = projection.projectY(l.lng, l.lat);
p.x = (x_ * cs.scale - cs.x) * EXTENT;
p.y = (y_ * cs.scale - cs.y) * EXTENT;
const x_ = (canonical.x + p.x / featureExtent) / s;
const y_ = (canonical.y + p.y / featureExtent) / s;
const l = new MercatorCoordinate(x_, y_).toLngLat();
const {x, y} = projection.project(l.lng, l.lat);
p.x = (x * cs.scale - cs.x) * EXTENT;
p.y = (y * cs.scale - cs.y) * EXTENT;
};
const scale = EXTENT / EXTENT;
const geometry = feature.loadGeometry();
Expand Down
22 changes: 3 additions & 19 deletions src/geo/mercator_coordinate.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,16 @@
import LngLat, {earthRadius} from '../geo/lng_lat.js';
import type {LngLatLike} from '../geo/lng_lat.js';

export const mercatorProjection = {
projectX: (lng) => mercatorXfromLng(lng),
projectY: (lng, lat) => mercatorYfromLat(lat),
unproject: (x, y) => new MercatorCoordinate(x, y).toLngLat(),
tileTransform: (id) => {
const scale = Math.pow(2, id.z);
return {
x: id.x,
y: id.y,
x2: id.x + 1,
y2: id.y + 1,
scale
};
}
}

/*
* The average circumference of the world in meters.
*/
const earthCircumfrence = 2 * Math.PI * earthRadius; // meters
const earthCircumference = 2 * Math.PI * earthRadius; // meters

/*
* The circumference at a line of latitude in meters.
*/
function circumferenceAtLatitude(latitude: number) {
return earthCircumfrence * Math.cos(latitude * Math.PI / 180);
return earthCircumference * Math.cos(latitude * Math.PI / 180);
}

export function mercatorXfromLng(lng: number) {
Expand Down Expand Up @@ -158,7 +142,7 @@ class MercatorCoordinate {
*/
meterInMercatorCoordinateUnits() {
// 1 meter / circumference at equator in meters * Mercator projection scale factor at this latitude
return 1 / earthCircumfrence * mercatorScale(latFromMercatorY(this.y));
return 1 / earthCircumference * mercatorScale(latFromMercatorY(this.y));
}

}
Expand Down
28 changes: 28 additions & 0 deletions src/geo/projections/albers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
function albers (lng, lat) {
const p1r = 29.5;
const p2r = 45.5;
const p1 = p1r / 180 * Math.PI;
const p2 = p2r / 180 * Math.PI;
const n = 0.5 * (Math.sin(p1) + Math.sin(p2));
const theta = n * ((lng + 77) / 180 * Math.PI);
const c = Math.pow(Math.cos(p1), 2) + 2 * n * Math.sin(p1);
const r = 0.5;
const a = r / n * Math.sqrt(c - 2 * n * Math.sin(lat / 180 * Math.PI));
const b = r / n * Math.sqrt(c - 2 * n * Math.sin(0 / 180 * Math.PI));
const x = a * Math.sin(theta);
const y = b - a * Math.cos(theta);

return {x: 0.5 + 0.5 * x, y: 0.5 + 0.5 * -y};
}

export default {
project: (lng, lat) => {
const {x, y} = albers(lng, lat);

return {
x: x + 0.5,
y: y + 0.5
};
},
unproject: (x, y) => mercatorProjection.unproject(x, y)
};
62 changes: 62 additions & 0 deletions src/geo/projections/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import albers from './albers';
import mercator from './mercator';
import sinusoidal from './sinusoidal';
import wgs84 from './wgs84';
import winkelTripel from './winkelTripel';
import MercatorCoordinate from '../mercator_coordinate.js';

export default {
albers,
mercator,
sinusoidal,
wgs84,
winkelTripel
};

function idBounds(id) {
const s = Math.pow(2, -id.z);
const x1 = (id.x) * s;
const x2 = (id.x + 1) * s;
const y1 = (id.y) * s;
const y2 = (id.y + 1) * s;

const interp = (a, b, t) => a * (1 - t) + b * t;

const n = 2;
const locs = [];
for (let i = 0; i <= n; i++) {
const f = i / n;
locs.push(new MercatorCoordinate(interp(x1, x2, f), y1).toLngLat());
locs.push(new MercatorCoordinate(interp(x1, x2, f), y2).toLngLat());
locs.push(new MercatorCoordinate(x1, interp(y1, y2, f)).toLngLat());
locs.push(new MercatorCoordinate(x2, interp(y1, y2, f)).toLngLat());
}
return locs;
}

export function makeTileTransform (projection) {
return (id) => {
const locs = idBounds(id);
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
for (const l of locs) {
const {x, y} = projection.project(l.lng, l.lat);
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
}

const max = Math.max(maxX - minX, maxY - minY);
const scale = 1 / max;
return {
scale,
x: minX * scale,
y: minY * scale,
x2: maxX * scale,
y2: maxY * scale
};
}
}
11 changes: 11 additions & 0 deletions src/geo/projections/mercator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import MercatorCoordinate, {mercatorXfromLng, mercatorYfromLat} from '../mercator_coordinate.js';

export default {
project: (lng, lat) => {
const x = mercatorXfromLng(lng);
const y = mercatorYfromLat(lat);

return {x, y};
},
unproject: (x, y) => new MercatorCoordinate(x, y).toLngLat()
}
12 changes: 12 additions & 0 deletions src/geo/projections/sinusoidal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default {
project: (lng, lat) => {
const x = 0.5 + lng * Math.cos(lat / 180 * Math.PI) / 360 * 2;
const y = 0.5 - lat / 360 * 2;
return {x, y};
},
unproject: (x, y) => {
const lat = (0.5 - y) / 2 * 360;
const lng = (x - 0.5) / Math.cos(lat / 180 * Math.PI) / 2 * 360;
return new LngLat(lng, lat);
}
};
9 changes: 9 additions & 0 deletions src/geo/projections/wgs84.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default {
project: (lng, lat) => {
const x = 0.5 + lng / 360;
const y = 0.5 - lat / 360;

return {x, y};
},
unproject: () => {},
};
21 changes: 21 additions & 0 deletions src/geo/projections/winkelTripel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function sinc(x) {
return Math.sin(x) / x;
}

function winkelTripel(lng, lat) {
lat = lat / 180 * Math.PI;
lng = lng / 180 * Math.PI;
const phi1 = Math.acos(2 / Math.PI);
const alpha = Math.acos(Math.cos(lat) * Math.cos(lng / 2));
const x = 0.5 * (lng * Math.cos(phi1) + (2 * Math.cos(lat) * Math.sin(lng/2)) / sinc(alpha)) || 0;
const y = 0.5 * (lat + Math.sin(lat) / sinc(alpha)) || 0;
function s(n) {
return (n / (Math.PI) + 0.5) * 0.5;
}
return { x: s(x), y: 1 - s(y) };
}

export default {
project: (lng, lat) => winkelTripel(lng, lat),
unproject: () => {}
};
Loading

0 comments on commit 20896c5

Please sign in to comment.