forked from mapbox/mapbox-gl-js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LOD support for tile coverage (mapbox#8975)
* LOD support for tile coverage
- Loading branch information
1 parent
3396e00
commit f2f4faa
Showing
6 changed files
with
486 additions
and
209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// @flow | ||
|
||
import {vec3, vec4} from 'gl-matrix'; | ||
import assert from 'assert'; | ||
|
||
class Frustum { | ||
points: Array<Array<number>>; | ||
planes: Array<Array<number>>; | ||
|
||
constructor(points_: Array<Array<number>>, planes_: Array<Array<number>>) { | ||
this.points = points_; | ||
this.planes = planes_; | ||
} | ||
|
||
static fromInvProjectionMatrix(invProj: Float64Array, worldSize: number, zoom: number): Frustum { | ||
const clipSpaceCorners = [ | ||
[-1, 1, -1, 1], | ||
[ 1, 1, -1, 1], | ||
[ 1, -1, -1, 1], | ||
[-1, -1, -1, 1], | ||
[-1, 1, 1, 1], | ||
[ 1, 1, 1, 1], | ||
[ 1, -1, 1, 1], | ||
[-1, -1, 1, 1] | ||
]; | ||
|
||
const scale = Math.pow(2, zoom); | ||
|
||
// Transform frustum corner points from clip space to tile space | ||
const frustumCoords = clipSpaceCorners | ||
.map(v => vec4.transformMat4([], v, invProj)) | ||
.map(v => vec4.scale([], v, 1.0 / v[3] / worldSize * scale)); | ||
|
||
const frustumPlanePointIndices = [ | ||
[0, 1, 2], // near | ||
[6, 5, 4], // far | ||
[0, 3, 7], // left | ||
[2, 1, 5], // right | ||
[3, 2, 6], // bottom | ||
[0, 4, 5] // top | ||
]; | ||
|
||
const frustumPlanes = frustumPlanePointIndices.map((p: Array<number>) => { | ||
const a = vec3.sub([], frustumCoords[p[0]], frustumCoords[p[1]]); | ||
const b = vec3.sub([], frustumCoords[p[2]], frustumCoords[p[1]]); | ||
const n = vec3.normalize([], vec3.cross([], a, b)); | ||
const d = -vec3.dot(n, frustumCoords[p[1]]); | ||
return n.concat(d); | ||
}); | ||
|
||
return new Frustum(frustumCoords, frustumPlanes); | ||
} | ||
} | ||
|
||
class Aabb { | ||
min: vec3; | ||
max: vec3; | ||
center: vec3; | ||
|
||
constructor(min_: vec3, max_: vec3) { | ||
this.min = min_; | ||
this.max = max_; | ||
this.center = vec3.scale([], vec3.add([], this.min, this.max), 0.5); | ||
} | ||
|
||
quadrant(index: number): Aabb { | ||
const split = [(index % 2) === 0, index < 2]; | ||
const qMin = vec3.clone(this.min); | ||
const qMax = vec3.clone(this.max); | ||
for (let axis = 0; axis < split.length; axis++) { | ||
qMin[axis] = split[axis] ? this.min[axis] : this.center[axis]; | ||
qMax[axis] = split[axis] ? this.center[axis] : this.max[axis]; | ||
} | ||
// Elevation is always constant, hence quadrant.max.z = this.max.z | ||
qMax[2] = this.max[2]; | ||
return new Aabb(qMin, qMax); | ||
} | ||
|
||
distanceX(point: Array<number>): number { | ||
const pointOnAabb = Math.max(Math.min(this.max[0], point[0]), this.min[0]); | ||
return pointOnAabb - point[0]; | ||
} | ||
|
||
distanceY(point: Array<number>): number { | ||
const pointOnAabb = Math.max(Math.min(this.max[1], point[1]), this.min[1]); | ||
return pointOnAabb - point[1]; | ||
} | ||
|
||
// Performs a frustum-aabb intersection test. Returns 0 if there's no intersection, | ||
// 1 if shapes are intersecting and 2 if the aabb if fully inside the frustum. | ||
intersects(frustum: Frustum): number { | ||
// Execute separating axis test between two convex objects to find intersections | ||
// Each frustum plane together with 3 major axes define the separating axes | ||
// Note: test only 4 points as both min and max points have equal elevation | ||
assert(this.min[2] === 0 && this.max[2] === 0); | ||
|
||
const aabbPoints = [ | ||
[this.min[0], this.min[1], 0.0, 1], | ||
[this.max[0], this.min[1], 0.0, 1], | ||
[this.max[0], this.max[1], 0.0, 1], | ||
[this.min[0], this.max[1], 0.0, 1] | ||
]; | ||
|
||
let fullyInside = true; | ||
|
||
for (let p = 0; p < frustum.planes.length; p++) { | ||
const plane = frustum.planes[p]; | ||
let pointsInside = 0; | ||
|
||
for (let i = 0; i < aabbPoints.length; i++) { | ||
pointsInside += vec4.dot(plane, aabbPoints[i]) >= 0; | ||
} | ||
|
||
if (pointsInside === 0) | ||
return 0; | ||
|
||
if (pointsInside !== aabbPoints.length) | ||
fullyInside = false; | ||
} | ||
|
||
if (fullyInside) | ||
return 2; | ||
|
||
for (let axis = 0; axis < 3; axis++) { | ||
let projMin = Number.MAX_VALUE; | ||
let projMax = -Number.MAX_VALUE; | ||
|
||
for (let p = 0; p < frustum.points.length; p++) { | ||
const projectedPoint = frustum.points[p][axis] - this.min[axis]; | ||
|
||
projMin = Math.min(projMin, projectedPoint); | ||
projMax = Math.max(projMax, projectedPoint); | ||
} | ||
|
||
if (projMax < 0 || projMin > this.max[axis] - this.min[axis]) | ||
return 0; | ||
} | ||
|
||
return 1; | ||
} | ||
} | ||
export { | ||
Aabb, | ||
Frustum | ||
}; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.