@takram/three-geospatial 0.0.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +15 -0
  2. package/build/index.cjs +43 -0
  3. package/build/index.js +932 -0
  4. package/build/r3f.cjs +1 -0
  5. package/build/r3f.js +38 -0
  6. package/build/shared.cjs +1 -0
  7. package/build/shared.js +198 -0
  8. package/package.json +42 -0
  9. package/src/ArrayBufferLoader.ts +35 -0
  10. package/src/DataLoader.ts +114 -0
  11. package/src/Ellipsoid.ts +128 -0
  12. package/src/EllipsoidGeometry.ts +107 -0
  13. package/src/Geodetic.ts +160 -0
  14. package/src/PointOfView.ts +169 -0
  15. package/src/Rectangle.ts +97 -0
  16. package/src/TileCoordinate.test.ts +38 -0
  17. package/src/TileCoordinate.ts +112 -0
  18. package/src/TilingScheme.test.ts +63 -0
  19. package/src/TilingScheme.ts +76 -0
  20. package/src/TypedArrayLoader.ts +53 -0
  21. package/src/assertions.ts +13 -0
  22. package/src/bufferGeometry.ts +62 -0
  23. package/src/helpers/projectOnEllipsoidSurface.ts +72 -0
  24. package/src/index.ts +25 -0
  25. package/src/math.ts +41 -0
  26. package/src/r3f/EastNorthUpFrame.tsx +52 -0
  27. package/src/r3f/EllipsoidMesh.tsx +36 -0
  28. package/src/r3f/index.ts +2 -0
  29. package/src/shaders/depth.glsl +15 -0
  30. package/src/shaders/packing.glsl +20 -0
  31. package/src/shaders/transform.glsl +12 -0
  32. package/src/typedArray.ts +76 -0
  33. package/src/types.ts +54 -0
  34. package/types/ArrayBufferLoader.d.ts +5 -0
  35. package/types/DataLoader.d.ts +67 -0
  36. package/types/Ellipsoid.d.ts +18 -0
  37. package/types/EllipsoidGeometry.d.ts +13 -0
  38. package/types/Geodetic.d.ts +37 -0
  39. package/types/PointOfView.d.ts +20 -0
  40. package/types/Rectangle.d.ts +27 -0
  41. package/types/TileCoordinate.d.ts +21 -0
  42. package/types/TilingScheme.d.ts +21 -0
  43. package/types/TypedArrayLoader.d.ts +16 -0
  44. package/types/assertions.d.ts +4 -0
  45. package/types/bufferGeometry.d.ts +5 -0
  46. package/types/helpers/projectOnEllipsoidSurface.d.ts +6 -0
  47. package/types/index.d.ts +18 -0
  48. package/types/math.d.ts +13 -0
  49. package/types/r3f/EastNorthUpFrame.d.ts +15 -0
  50. package/types/r3f/EllipsoidMesh.d.ts +13 -0
  51. package/types/r3f/index.d.ts +2 -0
  52. package/types/typedArray.d.ts +10 -0
  53. package/types/types.d.ts +22 -0
@@ -0,0 +1,76 @@
1
+ import { Vector2 } from 'three'
2
+
3
+ import { type GeodeticLike } from './Geodetic'
4
+ import { Rectangle, type RectangleLike } from './Rectangle'
5
+ import { TileCoordinate, type TileCoordinateLike } from './TileCoordinate'
6
+
7
+ const vectorScratch = /*#__PURE__*/ new Vector2()
8
+
9
+ export interface TilingSchemeLike {
10
+ readonly width: number
11
+ readonly height: number
12
+ readonly rectangle: RectangleLike
13
+ }
14
+
15
+ // TODO: Support slippyMap and EPSG:3857
16
+ export class TilingScheme {
17
+ constructor(
18
+ public width = 2,
19
+ public height = 1,
20
+ public rectangle = Rectangle.MAX
21
+ ) {}
22
+
23
+ clone(): TilingScheme {
24
+ return new TilingScheme(this.width, this.height, this.rectangle.clone())
25
+ }
26
+
27
+ copy(other: TilingSchemeLike): this {
28
+ this.width = other.width
29
+ this.height = other.height
30
+ this.rectangle.copy(other.rectangle)
31
+ return this
32
+ }
33
+
34
+ getSize(z: number, result = new Vector2()): Vector2 {
35
+ return result.set(this.width << z, this.height << z)
36
+ }
37
+
38
+ // Reference: https://github.com/CesiumGS/cesium/blob/1.122/packages/engine/Source/Core/GeographicTilingScheme.js#L210
39
+ getTile(
40
+ geodetic: GeodeticLike,
41
+ z: number,
42
+ result = new TileCoordinate()
43
+ ): TileCoordinate {
44
+ const size = this.getSize(z, vectorScratch)
45
+ const width = this.rectangle.width / size.x
46
+ const height = this.rectangle.height / size.y
47
+ let longitude = geodetic.longitude
48
+ if (this.rectangle.east < this.rectangle.west) {
49
+ longitude += Math.PI * 2
50
+ }
51
+ let x = Math.floor((longitude - this.rectangle.west) / width)
52
+ if (x >= size.x) {
53
+ x = size.x - 1
54
+ }
55
+ let y = Math.floor((geodetic.latitude - this.rectangle.south) / height)
56
+ if (y >= size.y) {
57
+ y = size.y - 1
58
+ }
59
+ result.x = x
60
+ result.y = y
61
+ result.z = z
62
+ return result
63
+ }
64
+
65
+ // Reference: https://github.com/CesiumGS/cesium/blob/1.122/packages/engine/Source/Core/GeographicTilingScheme.js#L169
66
+ getRectangle(tile: TileCoordinateLike, result = new Rectangle()): Rectangle {
67
+ const size = this.getSize(tile.z, vectorScratch)
68
+ const width = this.rectangle.width / size.x
69
+ const height = this.rectangle.height / size.y
70
+ result.west = tile.x * width + this.rectangle.west
71
+ result.east = (tile.x + 1) * width + this.rectangle.west
72
+ result.north = this.rectangle.north - (size.y - tile.y - 1) * height
73
+ result.south = this.rectangle.north - (size.y - tile.y) * height
74
+ return result
75
+ }
76
+ }
@@ -0,0 +1,53 @@
1
+ import { Loader, type TypedArray } from 'three'
2
+
3
+ import { ArrayBufferLoader } from './ArrayBufferLoader'
4
+ import {
5
+ parseFloat32Array,
6
+ parseInt16Array,
7
+ parseUint16Array
8
+ } from './typedArray'
9
+
10
+ export abstract class TypedArrayLoader<T extends TypedArray> extends Loader<T> {
11
+ abstract parseTypedArray(buffer: ArrayBuffer): T
12
+
13
+ override load(
14
+ url: string,
15
+ onLoad: (data: T) => void,
16
+ onProgress?: (event: ProgressEvent) => void,
17
+ onError?: (error: unknown) => void
18
+ ): void {
19
+ const loader = new ArrayBufferLoader(this.manager)
20
+ loader.setRequestHeader(this.requestHeader)
21
+ loader.setPath(this.path)
22
+ loader.setWithCredentials(this.withCredentials)
23
+ loader.load(
24
+ url,
25
+ arrayBuffer => {
26
+ try {
27
+ onLoad(this.parseTypedArray(arrayBuffer))
28
+ } catch (error) {
29
+ if (onError != null) {
30
+ onError(error)
31
+ } else {
32
+ console.error(error)
33
+ }
34
+ this.manager.itemError(url)
35
+ }
36
+ },
37
+ onProgress,
38
+ onError
39
+ )
40
+ }
41
+ }
42
+
43
+ export class Int16ArrayLoader extends TypedArrayLoader<Int16Array> {
44
+ readonly parseTypedArray = parseInt16Array
45
+ }
46
+
47
+ export class Uint16ArrayLoader extends TypedArrayLoader<Uint16Array> {
48
+ readonly parseTypedArray = parseUint16Array
49
+ }
50
+
51
+ export class Float32ArrayLoader extends TypedArrayLoader<Float32Array> {
52
+ readonly parseTypedArray = parseFloat32Array
53
+ }
@@ -0,0 +1,13 @@
1
+ export function assertType<T>(value: unknown): asserts value is T {}
2
+
3
+ export function isNotNullish<T>(value: T | null | undefined): value is T {
4
+ return value != null
5
+ }
6
+
7
+ export function isNotUndefined<T>(value: T | undefined): value is T {
8
+ return value !== undefined
9
+ }
10
+
11
+ export function isNotFalse<T>(value: T | false): value is T {
12
+ return value !== false
13
+ }
@@ -0,0 +1,62 @@
1
+ import { pick } from 'lodash-es'
2
+ import { Box3, BufferAttribute, BufferGeometry, Sphere, Vector3 } from 'three'
3
+
4
+ import { isNotNullish } from './assertions'
5
+
6
+ export type BufferGeometryLike = Pick<
7
+ BufferGeometry,
8
+ 'attributes' | 'index' | 'boundingBox' | 'boundingSphere'
9
+ >
10
+
11
+ export function toBufferGeometryLike(
12
+ geometry: BufferGeometry
13
+ ): [BufferGeometryLike, ArrayBuffer[]] {
14
+ return [
15
+ pick(geometry, ['attributes', 'index', 'boundingBox', 'boundingSphere']),
16
+ [
17
+ ...Object.values(geometry.attributes).map(
18
+ attribute => attribute.array.buffer
19
+ ),
20
+ geometry.index?.array.buffer
21
+ ].filter(isNotNullish)
22
+ ]
23
+ }
24
+
25
+ export function fromBufferGeometryLike(
26
+ input: BufferGeometryLike,
27
+ result = new BufferGeometry()
28
+ ): BufferGeometry {
29
+ for (const [name, attribute] of Object.entries(input.attributes)) {
30
+ result.setAttribute(
31
+ name,
32
+ new BufferAttribute(
33
+ attribute.array,
34
+ attribute.itemSize,
35
+ attribute.normalized
36
+ )
37
+ )
38
+ }
39
+ result.index =
40
+ input.index != null
41
+ ? new BufferAttribute(
42
+ input.index.array,
43
+ input.index.itemSize,
44
+ input.index.normalized
45
+ )
46
+ : null
47
+ if (input.boundingBox != null) {
48
+ const { min, max } = input.boundingBox
49
+ result.boundingBox = new Box3(
50
+ new Vector3(min.x, min.y, min.z),
51
+ new Vector3(max.x, max.y, max.z)
52
+ )
53
+ }
54
+ if (input.boundingSphere != null) {
55
+ const { center, radius } = input.boundingSphere
56
+ result.boundingSphere = new Sphere(
57
+ new Vector3(center.x, center.y, center.z),
58
+ radius
59
+ )
60
+ }
61
+ return result
62
+ }
@@ -0,0 +1,72 @@
1
+ import { Vector3 } from 'three'
2
+
3
+ const vectorScratch = /*#__PURE__*/ new Vector3()
4
+
5
+ // See: https://en.wikipedia.org/wiki/Geographic_coordinate_conversion
6
+ // Reference: https://github.com/CesiumGS/cesium/blob/1.122/packages/engine/Source/Core/scaleToGeodeticSurface.js
7
+
8
+ export interface ProjectOnEllipsoidSurfaceOptions {
9
+ centerTolerance?: number
10
+ }
11
+
12
+ export function projectOnEllipsoidSurface(
13
+ position: Vector3,
14
+ reciprocalRadiiSquared: Vector3,
15
+ result = new Vector3(),
16
+ options?: ProjectOnEllipsoidSurfaceOptions
17
+ ): Vector3 | undefined {
18
+ const { x, y, z } = position
19
+ const rx = reciprocalRadiiSquared.x
20
+ const ry = reciprocalRadiiSquared.y
21
+ const rz = reciprocalRadiiSquared.z
22
+ const x2 = x * x * rx
23
+ const y2 = y * y * ry
24
+ const z2 = z * z * rz
25
+
26
+ // Compute the squared ellipsoid norm.
27
+ const normSquared = x2 + y2 + z2
28
+ const ratio = Math.sqrt(1 / normSquared)
29
+
30
+ // When very close to center or at center.
31
+ if (!Number.isFinite(ratio)) {
32
+ return undefined
33
+ }
34
+
35
+ // As an initial approximation, assume that the radial intersection is the
36
+ // projection point.
37
+ const intersection = vectorScratch.copy(position).multiplyScalar(ratio)
38
+ if (normSquared < (options?.centerTolerance ?? 0.1)) {
39
+ return result.copy(intersection)
40
+ }
41
+
42
+ // Use the gradient at the intersection point in place of the true unit
43
+ // normal. The difference in magnitude will be absorbed in the multiplier.
44
+ const gradient = intersection
45
+ .multiply(reciprocalRadiiSquared)
46
+ .multiplyScalar(2)
47
+
48
+ // Compute the initial guess at the normal vector multiplier.
49
+ let lambda = ((1 - ratio) * position.length()) / (gradient.length() / 2)
50
+
51
+ let correction = 0
52
+ let sx: number
53
+ let sy: number
54
+ let sz: number
55
+ let error: number
56
+ do {
57
+ lambda -= correction
58
+ sx = 1 / (1 + lambda * rx)
59
+ sy = 1 / (1 + lambda * ry)
60
+ sz = 1 / (1 + lambda * rz)
61
+ const sx2 = sx * sx
62
+ const sy2 = sy * sy
63
+ const sz2 = sz * sz
64
+ const sx3 = sx2 * sx
65
+ const sy3 = sy2 * sy
66
+ const sz3 = sz2 * sz
67
+ error = x2 * sx2 + y2 * sy2 + z2 * sz2 - 1
68
+ correction = error / ((x2 * sx3 * rx + y2 * sy3 * ry + z2 * sz3 * rz) * -2)
69
+ } while (Math.abs(error) > 1e-12)
70
+
71
+ return result.set(x * sx, y * sy, z * sz)
72
+ }
package/src/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ /// <reference types="vite-plugin-glsl/ext" />
2
+
3
+ import depth from './shaders/depth.glsl'
4
+ import packing from './shaders/packing.glsl'
5
+ import transform from './shaders/transform.glsl'
6
+
7
+ export const depthShader: string = depth
8
+ export const packingShader: string = packing
9
+ export const transformShader: string = transform
10
+
11
+ export * from './ArrayBufferLoader'
12
+ export * from './assertions'
13
+ export * from './bufferGeometry'
14
+ export * from './DataLoader'
15
+ export * from './Ellipsoid'
16
+ export * from './EllipsoidGeometry'
17
+ export * from './Geodetic'
18
+ export * from './math'
19
+ export * from './PointOfView'
20
+ export * from './Rectangle'
21
+ export * from './TileCoordinate'
22
+ export * from './TilingScheme'
23
+ export * from './typedArray'
24
+ export * from './TypedArrayLoader'
25
+ export * from './types'
package/src/math.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { MathUtils } from 'three'
2
+
3
+ export const clamp = MathUtils.clamp
4
+ export const euclideanModulo = MathUtils.euclideanModulo
5
+ export const inverseLerp = MathUtils.inverseLerp
6
+ export const lerp = MathUtils.lerp
7
+ export const radians = MathUtils.degToRad
8
+ export const degrees = MathUtils.radToDeg
9
+ export const isPowerOfTwo = MathUtils.isPowerOfTwo
10
+ export const ceilPowerOfTwo = MathUtils.ceilPowerOfTwo
11
+ export const floorPowerOfTwo = MathUtils.floorPowerOfTwo
12
+ export const normalize = MathUtils.normalize
13
+
14
+ // Prefer glsl's argument order which differs from that of MathUtils.
15
+ export function smoothstep(min: number, max: number, x: number): number {
16
+ if (x <= min) {
17
+ return 0
18
+ }
19
+ if (x >= max) {
20
+ return 1
21
+ }
22
+ x = (x - min) / (max - min)
23
+ return x * x * (3 - 2 * x)
24
+ }
25
+
26
+ export function saturate(x: number): number {
27
+ return Math.min(Math.max(x, 0), 1)
28
+ }
29
+
30
+ export function closeTo(
31
+ a: number,
32
+ b: number,
33
+ relativeEpsilon: number,
34
+ absoluteEpsilon = relativeEpsilon
35
+ ): boolean {
36
+ const diff = Math.abs(a - b)
37
+ return (
38
+ diff <= absoluteEpsilon ||
39
+ diff <= relativeEpsilon * Math.max(Math.abs(a), Math.abs(b))
40
+ )
41
+ }
@@ -0,0 +1,52 @@
1
+ import { forwardRef, useEffect, useMemo, type ReactNode } from 'react'
2
+ import { Group, Matrix4, Vector3 } from 'three'
3
+ import { type SetOptional } from 'type-fest'
4
+
5
+ import { Ellipsoid } from '../Ellipsoid'
6
+ import { Geodetic, type GeodeticLike } from '../Geodetic'
7
+
8
+ const matrixScratch = /*#__PURE__*/ new Matrix4()
9
+ const geodeticScratch = /*#__PURE__*/ new Geodetic()
10
+ const vectorScratch = /*#__PURE__*/ new Vector3()
11
+
12
+ class EastNorthUpFrameGroup extends Group {
13
+ set(
14
+ longitude: number,
15
+ latitude: number,
16
+ height: number,
17
+ ellipsoid = Ellipsoid.WGS84
18
+ ): void {
19
+ // TODO: Support nesting
20
+ const position = geodeticScratch
21
+ .set(longitude, latitude, height)
22
+ .toECEF(vectorScratch)
23
+ const matrix = ellipsoid.getEastNorthUpFrame(position, matrixScratch)
24
+ matrix.decompose(this.position, this.quaternion, this.scale)
25
+ }
26
+ }
27
+
28
+ export interface EastNorthUpFrameProps
29
+ extends SetOptional<GeodeticLike, 'height'> {
30
+ ellipsoid?: Ellipsoid
31
+ children?: ReactNode
32
+ }
33
+
34
+ export const EastNorthUpFrame = /*#__PURE__*/ forwardRef<
35
+ EastNorthUpFrameGroup,
36
+ EastNorthUpFrameProps
37
+ >(function EastNorthUpFrame(
38
+ { longitude, latitude, height = 0, ellipsoid = Ellipsoid.WGS84, children },
39
+ forwardedRef
40
+ ) {
41
+ const group = useMemo(() => new EastNorthUpFrameGroup(), [])
42
+
43
+ useEffect(() => {
44
+ group.set(longitude, latitude, height, ellipsoid)
45
+ }, [longitude, latitude, height, ellipsoid, group])
46
+
47
+ return (
48
+ <primitive ref={forwardedRef} object={group}>
49
+ {children}
50
+ </primitive>
51
+ )
52
+ })
@@ -0,0 +1,36 @@
1
+ import {
2
+ extend,
3
+ type BufferGeometryNode,
4
+ type MeshProps
5
+ } from '@react-three/fiber'
6
+ import { forwardRef, useRef } from 'react'
7
+ import { mergeRefs } from 'react-merge-refs'
8
+ import { type Mesh } from 'three'
9
+
10
+ import { EllipsoidGeometry } from '../EllipsoidGeometry'
11
+
12
+ declare module '@react-three/fiber' {
13
+ interface ThreeElements {
14
+ ellipsoidGeometry: BufferGeometryNode<
15
+ EllipsoidGeometry,
16
+ typeof EllipsoidGeometry
17
+ >
18
+ }
19
+ }
20
+
21
+ export interface EllipsoidMeshProps extends Omit<MeshProps, 'args'> {
22
+ args?: ConstructorParameters<typeof EllipsoidGeometry>
23
+ }
24
+
25
+ export const EllipsoidMesh = /*#__PURE__*/ forwardRef<Mesh, EllipsoidMeshProps>(
26
+ function Ellipsoid({ args, children, ...props }, forwardedRef) {
27
+ const ref = useRef<Mesh | null>(null)
28
+ extend({ EllipsoidGeometry })
29
+ return (
30
+ <mesh ref={mergeRefs([ref, forwardedRef])} {...props}>
31
+ <ellipsoidGeometry args={args} />
32
+ {children}
33
+ </mesh>
34
+ )
35
+ }
36
+ )
@@ -0,0 +1,2 @@
1
+ export * from './EastNorthUpFrame'
2
+ export * from './EllipsoidMesh'
@@ -0,0 +1,15 @@
1
+ float reverseLogDepth(const float depth, const float near, const float far) {
2
+ #ifdef USE_LOGDEPTHBUF
3
+ float d = pow(2.0, depth * log2(far + 1.0)) - 1.0;
4
+ float a = far / (far - near);
5
+ float b = far * near / (near - far);
6
+ return a + b / d;
7
+ #else
8
+ return depth;
9
+ #endif // USE_LOGDEPTHBUF
10
+ }
11
+
12
+ float linearizeDepth(const float depth, const float near, const float far) {
13
+ float ndc = depth * 2.0 - 1.0;
14
+ return 2.0 * near * far / (far + near - ndc * (far - near));
15
+ }
@@ -0,0 +1,20 @@
1
+ // Reference: https://jcgt.org/published/0003/02/01/paper.pdf
2
+
3
+ vec2 signNotZero(vec2 v) {
4
+ return vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);
5
+ }
6
+
7
+ vec2 packNormalToVec2(vec3 v) {
8
+ vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z)));
9
+ return v.z <= 0.0
10
+ ? (1.0 - abs(p.yx)) * signNotZero(p)
11
+ : p;
12
+ }
13
+
14
+ vec3 unpackVec2ToNormal(vec2 e) {
15
+ vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
16
+ if (v.z < 0.0) {
17
+ v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
18
+ }
19
+ return normalize(v);
20
+ }
@@ -0,0 +1,12 @@
1
+ vec3 screenToView(
2
+ const vec2 uv,
3
+ const float depth,
4
+ const float viewZ,
5
+ const mat4 projectionMatrix,
6
+ const mat4 inverseProjectionMatrix
7
+ ) {
8
+ vec4 clip = vec4(vec3(uv, depth) * 2.0 - 1.0, 1.0);
9
+ float clipW = projectionMatrix[2][3] * viewZ + projectionMatrix[3][3];
10
+ clip *= clipW;
11
+ return (inverseProjectionMatrix * clip).xyz;
12
+ }
@@ -0,0 +1,76 @@
1
+ export type TypedArray =
2
+ | Int8Array
3
+ | Uint8Array
4
+ | Uint8ClampedArray
5
+ | Int16Array
6
+ | Uint16Array
7
+ | Int32Array
8
+ | Uint32Array
9
+ | Float32Array
10
+ | Float64Array
11
+
12
+ export type TypedArrayConstructor =
13
+ | Int8ArrayConstructor
14
+ | Uint8ArrayConstructor
15
+ | Uint8ClampedArrayConstructor
16
+ | Int16ArrayConstructor
17
+ | Uint16ArrayConstructor
18
+ | Int32ArrayConstructor
19
+ | Uint32ArrayConstructor
20
+ | Float32ArrayConstructor
21
+ | Float64ArrayConstructor
22
+
23
+ type GetValue = keyof {
24
+ [K in keyof DataView as DataView[K] extends (byteOffset: number) => number
25
+ ? K
26
+ : never]: DataView[K]
27
+ }
28
+
29
+ export function parseTypedArray<
30
+ T extends TypedArrayConstructor,
31
+ K extends GetValue
32
+ >(
33
+ buffer: ArrayBuffer,
34
+ TypedArray: T,
35
+ getValue: K,
36
+ littleEndian?: boolean
37
+ ): InstanceType<T>
38
+
39
+ export function parseTypedArray<K extends GetValue>(
40
+ buffer: ArrayBuffer,
41
+ TypedArray: TypedArrayConstructor,
42
+ getValue: K,
43
+ littleEndian = true
44
+ ): TypedArray {
45
+ const data = new DataView(buffer)
46
+ const array = new TypedArray(data.byteLength / TypedArray.BYTES_PER_ELEMENT)
47
+ for (
48
+ let index = 0, byteIndex = 0;
49
+ index < array.length;
50
+ ++index, byteIndex += TypedArray.BYTES_PER_ELEMENT
51
+ ) {
52
+ array[index] = data[getValue](byteIndex, littleEndian)
53
+ }
54
+ return array
55
+ }
56
+
57
+ export function parseInt16Array(
58
+ buffer: ArrayBuffer,
59
+ littleEndian?: boolean
60
+ ): Int16Array {
61
+ return parseTypedArray(buffer, Int16Array, 'getInt16', littleEndian)
62
+ }
63
+
64
+ export function parseUint16Array(
65
+ buffer: ArrayBuffer,
66
+ littleEndian?: boolean
67
+ ): Uint16Array {
68
+ return parseTypedArray(buffer, Uint16Array, 'getUint16', littleEndian)
69
+ }
70
+
71
+ export function parseFloat32Array(
72
+ buffer: ArrayBuffer,
73
+ littleEndian?: boolean
74
+ ): Float32Array {
75
+ return parseTypedArray(buffer, Float32Array, 'getFloat32', littleEndian)
76
+ }
package/src/types.ts ADDED
@@ -0,0 +1,54 @@
1
+ import {
2
+ type Matrix2,
3
+ type Matrix3,
4
+ type Matrix4,
5
+ type Vector2,
6
+ type Vector3,
7
+ type Vector4
8
+ } from 'three'
9
+ import { type ReadonlyTuple } from 'type-fest'
10
+
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ export type Callable = (...args: any) => any
13
+
14
+ export type ReadonlyTuple2<T = number> = ReadonlyTuple<T, 2>
15
+ export type ReadonlyTuple3<T = number> = ReadonlyTuple<T, 3>
16
+ export type ReadonlyTuple4<T = number> = ReadonlyTuple<T, 4>
17
+
18
+ // Non-readonly version of ReadonlyTuple. This is not type-safe because mutable
19
+ // methods still exist in the type.
20
+ // See https://github.com/sindresorhus/type-fest/blob/main/source/readonly-tuple.d.ts
21
+ type BuildTupleHelper<
22
+ Element,
23
+ Length extends number,
24
+ Rest extends Element[]
25
+ > = Rest['length'] extends Length
26
+ ? [...Rest]
27
+ : BuildTupleHelper<Element, Length, [Element, ...Rest]>
28
+
29
+ export type Tuple<T, Length extends number> = number extends Length
30
+ ? readonly T[]
31
+ : BuildTupleHelper<T, Length, []>
32
+
33
+ export type Tuple2<T = number> = BuildTupleHelper<T, 2, []>
34
+ export type Tuple3<T = number> = BuildTupleHelper<T, 3, []>
35
+ export type Tuple4<T = number> = BuildTupleHelper<T, 4, []>
36
+
37
+ // Suppose return type of the mutable methods of classes like Vector3 is `this`.
38
+ // TODO: How can we specify `this` as a constraint?
39
+ type ReadonlyThreeInstance<T> = Readonly<{
40
+ [K in keyof T as T[K] extends Callable
41
+ ? ReturnType<T[K]> extends T
42
+ ? K extends 'clone'
43
+ ? K
44
+ : never
45
+ : K
46
+ : K]: T[K]
47
+ }>
48
+
49
+ export type ReadonlyVector2 = ReadonlyThreeInstance<Vector2>
50
+ export type ReadonlyVector3 = ReadonlyThreeInstance<Vector3>
51
+ export type ReadonlyVector4 = ReadonlyThreeInstance<Vector4>
52
+ export type ReadonlyMatrix2 = ReadonlyThreeInstance<Matrix2>
53
+ export type ReadonlyMatrix3 = ReadonlyThreeInstance<Matrix3>
54
+ export type ReadonlyMatrix4 = ReadonlyThreeInstance<Matrix4>
@@ -0,0 +1,5 @@
1
+ import { Loader } from 'three';
2
+
3
+ export declare class ArrayBufferLoader extends Loader<ArrayBuffer> {
4
+ load(url: string, onLoad: (data: ArrayBuffer) => void, onProgress?: (event: ProgressEvent) => void, onError?: (error: unknown) => void): void;
5
+ }