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

Type tile_coord.js #4948

Merged
merged 1 commit into from
Jul 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/source/source.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ exports.setType = function (name: string, type: any) {
*/


import type {TileCoord} from './tile_coord';
import type TileCoord from './tile_coord';
import type {Actor} from '../util/actor';
import type {StyleLayerIndex} from '../style/style_layer_index';
import type {SerializedBucket} from '../data/bucket';
Expand Down
121 changes: 65 additions & 56 deletions src/source/tile_coord.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
// @flow

const assert = require('assert');
const WhooTS = require('@mapbox/whoots-js');
const Coordinate = require('../geo/coordinate');

class TileCoord {
constructor(z, x, y, w) {
z: number;
x: number;
y: number;
w: number;
id: number;
posMatrix: Float32Array;

constructor(z: number, x: number, y: number, w: number | void) {
assert(!isNaN(z) && z >= 0 && z % 1 === 0);
assert(!isNaN(x) && x >= 0 && x % 1 === 0);
assert(!isNaN(y) && y >= 0 && y % 1 === 0);

if (isNaN(w)) w = 0;
if (w === undefined || isNaN(w)) w = 0;

this.z = +z;
this.x = +x;
Expand All @@ -23,14 +31,14 @@ class TileCoord {
this.id = ((dim * dim * w + dim * this.y + this.x) * 32) + this.z;

// for caching pos matrix calculation when rendering
this.posMatrix = null;
(this : any).posMatrix = null;
}

toString() {
return `${this.z}/${this.x}/${this.y}`;
}

toCoordinate(sourceMaxZoom) {
toCoordinate(sourceMaxZoom: number | void) {
const zoom = Math.min(this.z, sourceMaxZoom === undefined ? this.z : sourceMaxZoom);
const tileScale = Math.pow(2, zoom);
const row = this.y;
Expand All @@ -39,21 +47,21 @@ class TileCoord {
}

// given a list of urls, choose a url template and return a tile URL
url(urls, sourceMaxZoom, scheme) {
url(urls: Array<string>, sourceMaxZoom: ?number, scheme: ?string) {
const bbox = WhooTS.getTileBBox(this.x, this.y, this.z);
const quadkey = getQuadkey(this.z, this.x, this.y);

return urls[(this.x + this.y) % urls.length]
.replace('{prefix}', (this.x % 16).toString(16) + (this.y % 16).toString(16))
.replace('{z}', Math.min(this.z, sourceMaxZoom || this.z))
.replace('{x}', this.x)
.replace('{y}', scheme === 'tms' ? (Math.pow(2, this.z) - this.y - 1) : this.y)
.replace('{z}', String(Math.min(this.z, sourceMaxZoom || this.z)))
.replace('{x}', String(this.x))
.replace('{y}', String(scheme === 'tms' ? (Math.pow(2, this.z) - this.y - 1) : this.y))
.replace('{quadkey}', quadkey)
.replace('{bbox-epsg-3857}', bbox);
}

// Return the coordinate of the parent tile
parent(sourceMaxZoom) {
parent(sourceMaxZoom: number) {
if (this.z === 0) return null;

// the id represents an overscaled tile, return the same coordinates with a lower z
Expand All @@ -69,7 +77,7 @@ class TileCoord {
}

// Return the coordinates of the tile's children
children(sourceMaxZoom) {
children(sourceMaxZoom: number) {

if (this.z >= sourceMaxZoom) {
// return a single tile coord representing a an overscaled tile
Expand All @@ -86,12 +94,57 @@ class TileCoord {
new TileCoord(z, x + 1, y + 1, this.w)
];
}

static cover(z: number, bounds: [Coordinate, Coordinate, Coordinate, Coordinate],
actualZ: number, renderWorldCopies: boolean | void) {
if (renderWorldCopies === undefined) {
renderWorldCopies = true;
}
const tiles = 1 << z;
const t = {};

function scanLine(x0, x1, y) {
let x, w, wx, coord;
if (y >= 0 && y <= tiles) {
for (x = x0; x < x1; x++) {
w = Math.floor(x / tiles);
wx = (x % tiles + tiles) % tiles;
if (w === 0 || renderWorldCopies === true) {
coord = new TileCoord(actualZ, wx, y, w);
t[coord.id] = coord;
}
}
}
}

// Divide the screen up in two triangles and scan each of them:
// +---/
// | / |
// /---+
scanTriangle(bounds[0], bounds[1], bounds[2], 0, tiles, scanLine);
scanTriangle(bounds[2], bounds[3], bounds[0], 0, tiles, scanLine);

return Object.keys(t).map((id) => {
return t[id];
});
}

// Parse a packed integer id into a TileCoord object
static fromID(id: number) {
const z = id % 32, dim = 1 << z;
const xy = ((id - z) / 32);
const x = xy % dim, y = ((xy - x) / dim) % dim;
let w = Math.floor(xy / (dim * dim));
if (w % 2 !== 0) w = w * -1 - 1;
w /= 2;
return new TileCoord(z, x, y, w);
}
}

// Taken from polymaps src/Layer.js
// https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383

function edge(a, b) {
function edge(a: Coordinate, b: Coordinate) {
if (a.row > b.row) { const t = a; a = b; b = t; }
return {
x0: a.column,
Expand Down Expand Up @@ -126,7 +179,7 @@ function scanSpans(e0, e1, ymin, ymax, scanLine) {
}
}

function scanTriangle(a, b, c, ymin, ymax, scanLine) {
function scanTriangle(a: Coordinate, b: Coordinate, c: Coordinate, ymin, ymax, scanLine) {
let ab = edge(a, b),
bc = edge(b, c),
ca = edge(c, a);
Expand All @@ -143,50 +196,6 @@ function scanTriangle(a, b, c, ymin, ymax, scanLine) {
if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine);
}

TileCoord.cover = function(z, bounds, actualZ, renderWorldCopies) {
if (renderWorldCopies === undefined) {
renderWorldCopies = true;
}
const tiles = 1 << z;
const t = {};

function scanLine(x0, x1, y) {
let x, w, wx, coord;
if (y >= 0 && y <= tiles) {
for (x = x0; x < x1; x++) {
w = Math.floor(x / tiles);
wx = (x % tiles + tiles) % tiles;
if (w === 0 || renderWorldCopies === true) {
coord = new TileCoord(actualZ, wx, y, w);
t[coord.id] = coord;
}
}
}
}

// Divide the screen up in two triangles and scan each of them:
// +---/
// | / |
// /---+
scanTriangle(bounds[0], bounds[1], bounds[2], 0, tiles, scanLine);
scanTriangle(bounds[2], bounds[3], bounds[0], 0, tiles, scanLine);

return Object.keys(t).map((id) => {
return t[id];
});
};

// Parse a packed integer id into a TileCoord object
TileCoord.fromID = function(id) {
const z = id % 32, dim = 1 << z;
const xy = ((id - z) / 32);
const x = xy % dim, y = ((xy - x) / dim) % dim;
let w = Math.floor(xy / (dim * dim));
if (w % 2 !== 0) w = w * -1 - 1;
w /= 2;
return new TileCoord(z, x, y, w);
};

function getQuadkey(z, x, y) {
let quadkey = '', mask;
for (let i = z; i > 0; i--) {
Expand Down
2 changes: 1 addition & 1 deletion src/source/worker_tile.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const DictionaryCoder = require('../util/dictionary_coder');
const util = require('../util/util');
const assert = require('assert');

import type {TileCoord} from './tile_coord';
import type TileCoord from './tile_coord';
import type SymbolBucket from '../data/bucket/symbol_bucket';
import type {Actor} from '../util/actor';
import type {StyleLayerIndex} from '../style/style_layer_index';
Expand Down