UNPKG

@deck.gl/core

Version:

deck.gl core library

169 lines (148 loc) 5.62 kB
// deck.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors // Extensions to math.gl library. Intended to be folded back. import typedArrayManager from './typed-array-manager'; import {Vector3, NumericArray} from '@math.gl/core'; import type {Matrix4} from '@math.gl/core'; // Helper, avoids low-precision 32 bit matrices from gl-matrix mat4.create() export function createMat4(): number[] { return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; } export function mod(value: number, divisor: number): number { const modulus = value % divisor; return modulus < 0 ? divisor + modulus : modulus; } // Extract camera vectors (move to math library?) export function getCameraPosition( viewMatrixInverse: Matrix4 | NumericArray ): [number, number, number] { // Read the translation from the inverse view matrix return [viewMatrixInverse[12], viewMatrixInverse[13], viewMatrixInverse[14]]; } export type FrustumPlane = { distance: number; normal: Vector3; }; // https://www.gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf export function getFrustumPlanes(viewProjectionMatrix: Matrix4 | NumericArray): { left: FrustumPlane; right: FrustumPlane; top: FrustumPlane; bottom: FrustumPlane; near: FrustumPlane; far: FrustumPlane; } { return { left: getFrustumPlane( viewProjectionMatrix[3] + viewProjectionMatrix[0], viewProjectionMatrix[7] + viewProjectionMatrix[4], viewProjectionMatrix[11] + viewProjectionMatrix[8], viewProjectionMatrix[15] + viewProjectionMatrix[12] ), right: getFrustumPlane( viewProjectionMatrix[3] - viewProjectionMatrix[0], viewProjectionMatrix[7] - viewProjectionMatrix[4], viewProjectionMatrix[11] - viewProjectionMatrix[8], viewProjectionMatrix[15] - viewProjectionMatrix[12] ), bottom: getFrustumPlane( viewProjectionMatrix[3] + viewProjectionMatrix[1], viewProjectionMatrix[7] + viewProjectionMatrix[5], viewProjectionMatrix[11] + viewProjectionMatrix[9], viewProjectionMatrix[15] + viewProjectionMatrix[13] ), top: getFrustumPlane( viewProjectionMatrix[3] - viewProjectionMatrix[1], viewProjectionMatrix[7] - viewProjectionMatrix[5], viewProjectionMatrix[11] - viewProjectionMatrix[9], viewProjectionMatrix[15] - viewProjectionMatrix[13] ), near: getFrustumPlane( viewProjectionMatrix[3] + viewProjectionMatrix[2], viewProjectionMatrix[7] + viewProjectionMatrix[6], viewProjectionMatrix[11] + viewProjectionMatrix[10], viewProjectionMatrix[15] + viewProjectionMatrix[14] ), far: getFrustumPlane( viewProjectionMatrix[3] - viewProjectionMatrix[2], viewProjectionMatrix[7] - viewProjectionMatrix[6], viewProjectionMatrix[11] - viewProjectionMatrix[10], viewProjectionMatrix[15] - viewProjectionMatrix[14] ) }; } const scratchVector = new Vector3(); function getFrustumPlane(a: number, b: number, c: number, d: number): FrustumPlane { scratchVector.set(a, b, c); const L = scratchVector.len(); return {distance: d / L, normal: new Vector3(-a / L, -b / L, -c / L)}; } /** * Calculate the low part of a WebGL 64 bit float * @param x {number} - the input float number * @returns {number} - the lower 32 bit of the number */ export function fp64LowPart(x: number): number { return x - Math.fround(x); } let scratchArray; /** * Split a Float64Array into a double-length Float32Array * @param typedArray * @param options * @param options.size - per attribute size * @param options.startIndex - start index in the source array * @param options.endIndex - end index in the source array * @returns {} - high part, low part for each attribute: [1xHi, 1yHi, 1zHi, 1xLow, 1yLow, 1zLow, 2xHi, ...] */ export function toDoublePrecisionArray( typedArray: Float64Array, options: {size?: number; startIndex?: number; endIndex?: number} ): Float32Array { const {size = 1, startIndex = 0} = options; const endIndex = options.endIndex !== undefined ? options.endIndex : typedArray.length; const count = (endIndex - startIndex) / size; scratchArray = typedArrayManager.allocate(scratchArray, count, { type: Float32Array, size: size * 2 }); let sourceIndex = startIndex; let targetIndex = 0; while (sourceIndex < endIndex) { for (let j = 0; j < size; j++) { const value = typedArray[sourceIndex++]; scratchArray[targetIndex + j] = value; scratchArray[targetIndex + j + size] = fp64LowPart(value); } targetIndex += size * 2; } return scratchArray.subarray(0, count * size * 2); } type LayerBounds = [number[], number[]]; export function mergeBounds(boundsList: (LayerBounds | null)[]): LayerBounds | null { let mergedBounds: LayerBounds | null = null; let isMerged = false; for (const bounds of boundsList) { /* eslint-disable-next-line no-continue */ if (!bounds) continue; if (!mergedBounds) { mergedBounds = bounds; } else { if (!isMerged) { // Copy to avoid mutating input bounds mergedBounds = [ [mergedBounds[0][0], mergedBounds[0][1]], [mergedBounds[1][0], mergedBounds[1][1]] ]; isMerged = true; } mergedBounds[0][0] = Math.min(mergedBounds[0][0], bounds[0][0]); mergedBounds[0][1] = Math.min(mergedBounds[0][1], bounds[0][1]); mergedBounds[1][0] = Math.max(mergedBounds[1][0], bounds[1][0]); mergedBounds[1][1] = Math.max(mergedBounds[1][1], bounds[1][1]); } } return mergedBounds; }