UNPKG

mapbox-3d-tiles

Version:

Integrate threejs with mapbox-gl to enable 3dtiles / 3dgs / gltf rendering.

1,157 lines 694 kB
import * as Z from "three"; import { Matrix4 as z, Vector3 as x, Object3D as Tt, Vector2 as H, WebGLRenderer as co, DataTextureLoader as nA, HalfFloatType as ke, FloatType as Ve, DataUtils as ps, LinearSRGBColorSpace as he, LinearFilter as ne, Quaternion as qe, Euler as vn, Scene as iA, DirectionalLight as $i, AmbientLight as rA, Group as le, PerspectiveCamera as Sn, EquirectangularReflectionMapping as aA, TrianglesDrawMode as Ao, TriangleFanDrawMode as Zt, TriangleStripDrawMode as Tn, Loader as ns, LoaderUtils as it, FileLoader as He, MeshPhysicalMaterial as ue, Color as X, SRGBColorSpace as Qe, SpotLight as lo, PointLight as ho, InstancedMesh as er, InstancedBufferAttribute as Qn, TextureLoader as uo, ImageBitmapLoader as fo, BufferAttribute as oe, InterleavedBuffer as go, InterleavedBufferAttribute as xt, LinearMipmapLinearFilter as is, NearestMipmapLinearFilter as po, LinearMipmapNearestFilter as mo, NearestMipmapNearestFilter as bo, NearestFilter as $t, RepeatWrapping as es, MirroredRepeatWrapping as Eo, ClampToEdgeWrapping as fe, PointsMaterial as Rn, Material as dt, LineBasicMaterial as tr, MeshStandardMaterial as rs, DoubleSide as gt, MeshBasicMaterial as ye, PropertyBinding as Co, BufferGeometry as xe, SkinnedMesh as Io, Mesh as De, LineSegments as Mn, Line as yo, LineLoop as xo, Points as sr, MathUtils as ee, OrthographicCamera as nr, Skeleton as Bo, AnimationClip as _o, Bone as wo, InterpolateDiscrete as vo, InterpolateLinear as Dn, Texture as ln, VectorKeyframeTrack as hn, NumberKeyframeTrack as un, QuaternionKeyframeTrack as dn, ColorManagement as ys, FrontSide as ir, Interpolant as So, Box3 as Le, Sphere as Fe, DefaultLoadingManager as Ln, Spherical as To, Ray as rr, Plane as Qo, Frustum as oA, Matrix3 as Ro, LoadingManager as cA, EventDispatcher as Ls, Float32BufferAttribute as Re, EdgesGeometry as Mo, BoxGeometry as AA, Box3Helper as lA, Matrix2 as hA, Vector4 as ft, WebGLRenderTarget as Qi, ShaderMaterial as Me, OneFactor as uA, ZeroFactor as dA, CustomBlending as fA, Box2 as gA, CompressedCubeTexture as pA, CompressedArrayTexture as mA, CompressedTexture as Do, NoColorSpace as Sr, RGBA_BPTC_Format as Ri, RGBA_S3TC_DXT5_Format as Mi, RGBA_S3TC_DXT3_Format as Tr, RGB_S3TC_DXT1_Format as Qr, RGBA_S3TC_DXT1_Format as Di, RGBA_ASTC_6x6_Format as Rr, RGBA_ASTC_4x4_Format as rn, RGBA_ETC2_EAC_Format as Lo, RGB_ETC2_Format as Fo, RedFormat as qt, RGFormat as Bt, RGBAFormat as Ie, UnsignedByteType as ve, DataTexture as ut, Data3DTexture as bA, RGB_PVRTC_4BPPV1_Format as EA, RGB_ETC1_Format as CA, RGBA_PVRTC_4BPPV1_Format as IA, RGB_BPTC_UNSIGNED_Format as yA, InstancedBufferGeometry as ar, DynamicDrawUsage as ko, NormalBlending as Po, UnsignedShort4444Type as xA, UnsignedShort5551Type as BA, UnsignedInt5999Type as _A, ByteType as wA, ShortType as vA, UnsignedShortType as SA, IntType as TA, UnsignedIntType as Go, AlphaFormat as QA, RGBFormat as RA, DepthFormat as MA, DepthStencilFormat as DA, RedIntegerFormat as LA, RGIntegerFormat as FA, RGBAIntegerFormat as Uo, UnsignedInt248Type as kA, UVMapping as _t, ShaderLib as an, UniformsUtils as fn, UniformsLib as Wt, InstancedInterleavedBuffer as Li, WireframeGeometry as PA, Line3 as GA, CurvePath as UA, LineCurve3 as NA, MeshMatcapMaterial as OA, MeshNormalMaterial as HA, MeshToonMaterial as zA, MeshDistanceMaterial as jA, MeshDepthMaterial as VA, MeshPhongMaterial as qA, MeshLambertMaterial as KA, AdditiveBlending as Fn, CircleGeometry as WA, CatmullRomCurve3 as or, TubeGeometry as JA, CanvasTexture as YA, Raycaster as XA } from "three"; import { MercatorCoordinate as Nn } from "mapbox-gl"; class No extends Tt { /** * Constructs a new CSS2D object. * * @param {DOMElement} [element] - The DOM element. */ constructor(e = document.createElement("div")) { super(), this.isCSS2DObject = !0, this.element = e, this.element.style.position = "absolute", this.element.style.userSelect = "none", this.element.setAttribute("draggable", !1), this.center = new H(0.5, 0.5), this.addEventListener("removed", function() { this.traverse(function(t) { t.element instanceof t.element.ownerDocument.defaultView.Element && t.element.parentNode !== null && t.element.remove(); }); }); } copy(e, t) { return super.copy(e, t), this.element = e.element.cloneNode(!0), this.center = e.center, this; } } const Ht = new x(), Mr = new z(), Dr = new z(), Lr = new x(), Fr = new x(); class ZA { /** * Constructs a new CSS2D renderer. * * @param {CSS2DRenderer~Parameters} [parameters] - The parameters. */ constructor(e = {}) { const t = this; let s, n, i, r; const o = { objects: /* @__PURE__ */ new WeakMap() }, c = e.element !== void 0 ? e.element : document.createElement("div"); c.style.overflow = "hidden", this.domElement = c, this.getSize = function() { return { width: s, height: n }; }, this.render = function(f, g) { f.matrixWorldAutoUpdate === !0 && f.updateMatrixWorld(), g.parent === null && g.matrixWorldAutoUpdate === !0 && g.updateMatrixWorld(), Mr.copy(g.matrixWorldInverse), Dr.multiplyMatrices(g.projectionMatrix, Mr), l(f, f, g), d(f); }, this.setSize = function(f, g) { s = f, n = g, i = s / 2, r = n / 2, c.style.width = f + "px", c.style.height = g + "px"; }; function A(f) { f.isCSS2DObject && (f.element.style.display = "none"); for (let g = 0, p = f.children.length; g < p; g++) A(f.children[g]); } function l(f, g, p) { if (f.visible === !1) { A(f); return; } if (f.isCSS2DObject) { Ht.setFromMatrixPosition(f.matrixWorld), Ht.applyMatrix4(Dr); const E = Ht.z >= -1 && Ht.z <= 1 && f.layers.test(p.layers) === !0, m = f.element; m.style.display = E === !0 ? "" : "none", E === !0 && (f.onBeforeRender(t, g, p), m.style.transform = "translate(" + -100 * f.center.x + "%," + -100 * f.center.y + "%)translate(" + (Ht.x * i + i) + "px," + (-Ht.y * r + r) + "px)", m.parentNode !== c && c.appendChild(m), f.onAfterRender(t, g, p)); const b = { distanceToCameraSquared: h(p, f) }; o.objects.set(f, b); } for (let E = 0, m = f.children.length; E < m; E++) l(f.children[E], g, p); } function h(f, g) { return Lr.setFromMatrixPosition(f.matrixWorld), Fr.setFromMatrixPosition(g.matrixWorld), Lr.distanceToSquared(Fr); } function u(f) { const g = []; return f.traverseVisible(function(p) { p.isCSS2DObject && g.push(p); }), g; } function d(f) { const g = u(f).sort(function(E, m) { if (E.renderOrder !== m.renderOrder) return m.renderOrder - E.renderOrder; const b = o.objects.get(E).distanceToCameraSquared, C = o.objects.get(m).distanceToCameraSquared; return b - C; }), p = g.length; for (let E = 0, m = g.length; E < m; E++) g[E].element.style.zIndex = p - E; } } } class $A { constructor(e, t) { if (this._map = e, this._renderer && this._labelRenderer) return; let s = new co({ alpha: !0, antialias: !0, canvas: e.getCanvas(), context: t }); s.shadowMap.enabled = !0, s.autoClear = !1; let n = new ZA(); n.setSize(e._containerWidth, e._containerHeight), n.domElement.style.position = "absolute", n.domElement.style.top = "0px", n.domElement.style.pointerEvents = "none", e._container.appendChild(n.domElement), e.on("resize", () => { n.setSize(e._containerWidth, e._containerHeight); }), this._renderer = s, this._labelRenderer = n; } getRenderer() { return this._renderer; } render(e, t) { this._renderer.resetState(), this._renderer.render(e, t), this._labelRenderer.render(e, t); } } class el extends nA { /** * Constructs a new RGBE loader. * * @param {LoadingManager} [manager] - The loading manager. */ constructor(e) { super(e), this.type = ke; } /** * Parses the given RGBE texture data. * * @param {ArrayBuffer} buffer - The raw texture data. * @return {DataTextureLoader~TexData} An object representing the parsed texture data. */ parse(e) { const r = function(y, _) { switch (y) { case 1: throw new Error("THREE.RGBELoader: Read Error: " + (_ || "")); case 2: throw new Error("THREE.RGBELoader: Write Error: " + (_ || "")); case 3: throw new Error("THREE.RGBELoader: Bad File Format: " + (_ || "")); default: case 4: throw new Error("THREE.RGBELoader: Memory Error: " + (_ || "")); } }, l = ` `, h = function(y, _, v) { _ = _ || 1024; let M = y.pos, U = -1, F = 0, N = "", P = String.fromCharCode.apply(null, new Uint16Array(y.subarray(M, M + 128))); for (; 0 > (U = P.indexOf(l)) && F < _ && M < y.byteLength; ) N += P, F += P.length, M += 128, P += String.fromCharCode.apply(null, new Uint16Array(y.subarray(M, M + 128))); return -1 < U ? (y.pos += F + U + 1, N + P.slice(0, U)) : !1; }, u = function(y) { const _ = /^#\?(\S+)/, v = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/, S = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/, M = /^\s*FORMAT=(\S+)\s*$/, U = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/, F = { valid: 0, /* indicate which fields are valid */ string: "", /* the actual header string */ comments: "", /* comments found in header */ programtype: "RGBE", /* listed at beginning of file to identify it after "#?". defaults to "RGBE" */ format: "", /* RGBE format, default 32-bit_rle_rgbe */ gamma: 1, /* image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) */ exposure: 1, /* a value of 1.0 in an image corresponds to <exposure> watts/steradian/m^2. defaults to 1.0 */ width: 0, height: 0 /* image dimensions, width/height */ }; let N, P; for ((y.pos >= y.byteLength || !(N = h(y))) && r(1, "no header found"), (P = N.match(_)) || r(3, "bad initial token"), F.valid |= 1, F.programtype = P[1], F.string += N + ` `; N = h(y), N !== !1; ) { if (F.string += N + ` `, N.charAt(0) === "#") { F.comments += N + ` `; continue; } if ((P = N.match(v)) && (F.gamma = parseFloat(P[1])), (P = N.match(S)) && (F.exposure = parseFloat(P[1])), (P = N.match(M)) && (F.valid |= 2, F.format = P[1]), (P = N.match(U)) && (F.valid |= 4, F.height = parseInt(P[1], 10), F.width = parseInt(P[2], 10)), F.valid & 2 && F.valid & 4) break; } return F.valid & 2 || r(3, "missing format specifier"), F.valid & 4 || r(3, "missing image size specifier"), F; }, d = function(y, _, v) { const S = _; if ( // run length encoding is not allowed so read flat S < 8 || S > 32767 || // this file is not run length encoded y[0] !== 2 || y[1] !== 2 || y[2] & 128 ) return new Uint8Array(y); S !== (y[2] << 8 | y[3]) && r(3, "wrong scanline width"); const M = new Uint8Array(4 * _ * v); M.length || r(4, "unable to allocate buffer space"); let U = 0, F = 0; const N = 4 * S, P = new Uint8Array(4), T = new Uint8Array(N); let q = v; for (; q > 0 && F < y.byteLength; ) { F + 4 > y.byteLength && r(1), P[0] = y[F++], P[1] = y[F++], P[2] = y[F++], P[3] = y[F++], (P[0] != 2 || P[1] != 2 || (P[2] << 8 | P[3]) != S) && r(3, "bad rgbe scanline format"); let K = 0, V; for (; K < N && F < y.byteLength; ) { V = y[F++]; const $ = V > 128; if ($ && (V -= 128), (V === 0 || K + V > N) && r(3, "bad scanline data"), $) { const se = y[F++]; for (let Be = 0; Be < V; Be++) T[K++] = se; } else T.set(y.subarray(F, F + V), K), K += V, F += V; } const te = S; for (let $ = 0; $ < te; $++) { let se = 0; M[U] = T[$ + se], se += S, M[U + 1] = T[$ + se], se += S, M[U + 2] = T[$ + se], se += S, M[U + 3] = T[$ + se], U += 4; } q--; } return M; }, f = function(y, _, v, S) { const M = y[_ + 3], U = Math.pow(2, M - 128) / 255; v[S + 0] = y[_ + 0] * U, v[S + 1] = y[_ + 1] * U, v[S + 2] = y[_ + 2] * U, v[S + 3] = 1; }, g = function(y, _, v, S) { const M = y[_ + 3], U = Math.pow(2, M - 128) / 255; v[S + 0] = ps.toHalfFloat(Math.min(y[_ + 0] * U, 65504)), v[S + 1] = ps.toHalfFloat(Math.min(y[_ + 1] * U, 65504)), v[S + 2] = ps.toHalfFloat(Math.min(y[_ + 2] * U, 65504)), v[S + 3] = ps.toHalfFloat(1); }, p = new Uint8Array(e); p.pos = 0; const E = u(p), m = E.width, b = E.height, C = d(p.subarray(p.pos), m, b); let I, w, B; switch (this.type) { case Ve: B = C.length / 4; const y = new Float32Array(B * 4); for (let v = 0; v < B; v++) f(C, v * 4, y, v * 4); I = y, w = Ve; break; case ke: B = C.length / 4; const _ = new Uint16Array(B * 4); for (let v = 0; v < B; v++) g(C, v * 4, _, v * 4); I = _, w = ke; break; default: throw new Error("THREE.RGBELoader: Unsupported type: " + this.type); } return { width: m, height: b, data: I, header: E.string, gamma: E.gamma, exposure: E.exposure, type: w }; } /** * Sets the texture type. * * @param {(HalfFloatType|FloatType)} value - The texture type to set. * @return {RGBELoader} A reference to this loader. */ setDataType(e) { return this.type = e, this; } load(e, t, s, n) { function i(r, o) { switch (r.type) { case Ve: case ke: r.colorSpace = he, r.minFilter = ne, r.magFilter = ne, r.generateMipmaps = !1, r.flipY = !0; break; } t && t(r, o); } return super.load(e, i, s, n); } } class st { // 更新世界矩阵, 需要根据 map 的中心点计算世界矩阵,将相对中心的坐标转换到墨卡托坐标系中 static updateWorldMatrix(e, t = null) { const s = t || e.getCenter(), n = Nn.fromLngLat(s), i = n.meterInMercatorCoordinateUnits(), r = [0, 0, 0], o = new z(); return o.compose(new x(n.x, n.y, n.z), new qe().setFromEuler(new vn(r[0], r[1], r[2])), new x(i, -i, i)), o; } static toScenePositionMercator(e, t) { return new x(t.x, t.y, t.z).applyMatrix4(e); } static toMapPositionMercator(e, t) { const s = t.clone().applyMatrix4(e); return new Nn(s.x, s.y, s.z); } static toScenePosition(e, t, s) { const n = Nn.fromLngLat(t, s); return this.toScenePositionMercator(e, n); } static toMapPosition(e, t) { const s = this.toMapPositionMercator(e, t), n = s.toLngLat(), i = s.toAltitude(); return [n.lng, n.lat, i]; } // 角度转弧度 static degToRad(e) { return e / 180 * Math.PI; } // 角度转弧度 static radToDeg(e) { return e / Math.PI * 180; } // static loadGeojson(url: string): Promise<any> { // return new Promise((resolve, reject) => { // const xhr = new XMLHttpRequest(); // xhr.open("GET", url); // xhr.onload = () => { // if (xhr.status === 200) { // resolve(JSON.parse(xhr.responseText)); // } else { // reject(xhr.statusText); // } // }; // xhr.onerror = () => { // reject(xhr.statusText); // }; // xhr.send(); // }); // } static toSceneGeometry(e) { } } class tl { // 创建场景 createScene(e = !0) { const t = new iA(); if (e) { const s = new $i(16777215, 4); s.position.set(1, 2, 3), t.add(s); const n = new rA(16777215, 0.2); t.add(n); } return t; } // 创建渲染组 createGroup(e, t) { const s = new le(); return s.name = t, e.add(s), s; } // 创建相机, 默认使用 PerspectiveCamera createCamera(e, t) { const s = new Sn(); s.name = t; const n = new le(); return n.name = t + "-parent", n.add(s), e.add(n), s; } _calcProjectionMatrices(e) { const t = e.centerOffset; let s; const n = e._camera.getCameraToClipPerspective(e._fov, e.width / e.height, e._nearZ, e._farZ); if (n[8] = -t.x * 2 / e.width, n[9] = t.y * 2 / e.height, e.isOrthographic) { const r = (g, p, E) => (1 - E) * g + E * p, o = (g) => g * g * g * g * g, c = (g, p, E, m) => { for (let b = 0; b < 16; b++) g[b] = r(p[b], E[b], m); return g; }; let l = 0.5 * e.height / Math.tan(e._fov / 2) * 1 * Math.tan(e._fov * 0.5), h = l * e.aspect, u = -h, d = -l; h -= t.x, u -= t.x, l += t.y, d += t.y, s = e._camera.getCameraToClipOrthographic(u, h, d, l, e._nearZ, e._farZ); const f = e.pitch >= 15 ? 1 : e.pitch / 15; c(s, s, n, o(f)); } else s = n; return new z().fromArray(s); } // 更新相机矩阵,需要将 mapbox 的矩阵转换为 threejs 的矩阵 // 转换过程中,需要将 viewMatrix 和 projectionMatrix 拆分, 以便设置正确的 view 和 projection 矩阵 updateCameraForRender(e, t, s, n, i) { const r = new z().fromArray(s), o = new z().multiplyMatrices(r, n); e.fov = st.radToDeg(t.transform.fovX), e.aspect = t.transform.aspect, e.near = t.transform._nearZ, e.far = t.transform._farZ; const c = t.transform; this._calcProjectionMatrices(c); const A = this._calcProjectionMatrices(c); e.projectionMatrix.copy(A), e.projectionMatrixInverse.copy(e.projectionMatrix).invert(); const l = e.projectionMatrixInverse, h = new z().multiplyMatrices(l, o), u = h.clone().invert(); e.matrixWorld.copy(u), e.matrixWorldInverse.copy(h), e.matrixAutoUpdate = !1, e.matrixWorldAutoUpdate = !1; const d = new x(), f = new qe(), g = new x(); e.matrixWorld.decompose(d, f, g), e.position.set(d.x, d.y, d.z); const p = new vn().setFromQuaternion(f, "YXZ"); e.rotation.set(p.x, p.y, p.z); } // 创建环境贴图, 支持通用的 hdr 贴图和官方的压缩 env 贴图 createEnvTexture(e, t) { e && e.length > 3 && e.indexOf(".hdr") === e.length - 4 && new el().load(e, (n) => { n.mapping = aA, t.environment = n, t.environmentRotation.x = Math.PI / 2; }); } } const xs = "scene-update", Fi = "scene-recenter"; function kr(a) { if (!a) return null; const e = a.replace(/[a-z]+:\/\/[^/]+/i, "").replace(/\?.*$/i, "").replace(/.*\//g, ""), t = e.lastIndexOf("."); return t === -1 ? null : e.substring(t + 1) || null; } const Pr = 2 ** 30; class Oo { get unloadPriorityCallback() { return this._unloadPriorityCallback; } set unloadPriorityCallback(e) { e.length === 1 ? (console.warn('LRUCache: "unloadPriorityCallback" function has been changed to take two arguments.'), this._unloadPriorityCallback = (t, s) => { const n = e(t), i = e(s); return n < i ? -1 : n > i ? 1 : 0; }) : this._unloadPriorityCallback = e; } constructor() { this.minSize = 6e3, this.maxSize = 8e3, this.minBytesSize = 0.3 * Pr, this.maxBytesSize = 0.4 * Pr, this.unloadPercent = 0.05, this.autoMarkUnused = !0, this.itemSet = /* @__PURE__ */ new Map(), this.itemList = [], this.usedSet = /* @__PURE__ */ new Set(), this.callbacks = /* @__PURE__ */ new Map(), this.unloadingHandle = -1, this.cachedBytes = 0, this.bytesMap = /* @__PURE__ */ new Map(), this.loadedSet = /* @__PURE__ */ new Set(), this._unloadPriorityCallback = null; const e = this.itemSet; this.defaultPriorityCallback = (t) => e.get(t); } // Returns whether or not the cache has reached the maximum size isFull() { return this.itemSet.size >= this.maxSize || this.cachedBytes >= this.maxBytesSize; } getMemoryUsage(e) { return this.bytesMap.get(e) || 0; } setMemoryUsage(e, t) { const { bytesMap: s, itemSet: n } = this; n.has(e) && (this.cachedBytes -= s.get(e) || 0, s.set(e, t), this.cachedBytes += t); } add(e, t) { const s = this.itemSet; if (s.has(e) || this.isFull()) return !1; const n = this.usedSet, i = this.itemList, r = this.callbacks; return i.push(e), n.add(e), s.set(e, Date.now()), r.set(e, t), !0; } has(e) { return this.itemSet.has(e); } remove(e) { const t = this.usedSet, s = this.itemSet, n = this.itemList, i = this.bytesMap, r = this.callbacks, o = this.loadedSet; if (s.has(e)) { this.cachedBytes -= i.get(e) || 0, i.delete(e), r.get(e)(e); const c = n.indexOf(e); return n.splice(c, 1), t.delete(e), s.delete(e), r.delete(e), o.delete(e), !0; } return !1; } // Marks whether tiles in the cache have been completely loaded or not. Tiles that have not been completely // loaded are subject to being disposed early if the cache is full above its max size limits, even if they // are marked as used. setLoaded(e, t) { const { itemSet: s, loadedSet: n } = this; s.has(e) && (t === !0 ? n.add(e) : n.delete(e)); } markUsed(e) { const t = this.itemSet, s = this.usedSet; t.has(e) && !s.has(e) && (t.set(e, Date.now()), s.add(e)); } markUnused(e) { this.usedSet.delete(e); } markAllUnused() { this.usedSet.clear(); } // TODO: this should be renamed because it's not necessarily unloading all unused content // Maybe call it "cleanup" or "unloadToMinSize" unloadUnusedContent() { const { unloadPercent: e, minSize: t, maxSize: s, itemList: n, itemSet: i, usedSet: r, loadedSet: o, callbacks: c, bytesMap: A, minBytesSize: l, maxBytesSize: h } = this, u = n.length - r.size, d = n.length - o.size, f = Math.max(Math.min(n.length - t, u), 0), g = this.cachedBytes - l, p = this.unloadPriorityCallback || this.defaultPriorityCallback; let E = !1; const m = f > 0 && u > 0 || d && n.length > s; if (u && this.cachedBytes > l || d && this.cachedBytes > h || m) { n.sort((v, S) => { const M = r.has(v), U = r.has(S); if (M === U) { const F = o.has(v), N = o.has(S); return F === N ? -p(v, S) : F ? 1 : -1; } else return M ? 1 : -1; }); const C = Math.max(t * e, f * e), I = Math.ceil(Math.min(C, u, f)), w = Math.max(e * g, e * l), B = Math.min(w, g); let y = 0, _ = 0; for (; this.cachedBytes - _ > h || n.length - y > s; ) { const v = n[y], S = A.get(v) || 0; if (r.has(v) && o.has(v) || this.cachedBytes - _ - S < h && n.length - y <= s) break; _ += S, y++; } for (; _ < B || y < I; ) { const v = n[y], S = A.get(v) || 0; if (r.has(v) || this.cachedBytes - _ - S < l && y >= I) break; _ += S, y++; } n.splice(0, y).forEach((v) => { this.cachedBytes -= A.get(v) || 0, c.get(v)(v), A.delete(v), i.delete(v), c.delete(v), o.delete(v), r.delete(v); }), E = y < f || _ < g && y < u, E = E && y > 0; } E && (this.unloadingHandle = requestAnimationFrame(() => this.scheduleUnload())); } scheduleUnload() { cancelAnimationFrame(this.unloadingHandle), this.scheduled || (this.scheduled = !0, queueMicrotask(() => { this.scheduled = !1, this.unloadUnusedContent(); })); } } class On { // returns whether tasks are queued or actively running get running() { return this.items.length !== 0 || this.currJobs !== 0; } constructor() { this.maxJobs = 6, this.items = [], this.callbacks = /* @__PURE__ */ new Map(), this.currJobs = 0, this.scheduled = !1, this.autoUpdate = !0, this.priorityCallback = () => { throw new Error("PriorityQueue: PriorityCallback function not defined."); }, this.schedulingCallback = (e) => { requestAnimationFrame(e); }, this._runjobs = () => { this.scheduled = !1, this.tryRunJobs(); }; } sort() { const e = this.priorityCallback; this.items.sort(e); } has(e) { return this.callbacks.has(e); } add(e, t) { const s = { callback: t, reject: null, resolve: null, promise: null }; return s.promise = new Promise((n, i) => { const r = this.items, o = this.callbacks; s.resolve = n, s.reject = i, r.push(e), o.set(e, s), this.autoUpdate && this.scheduleJobRun(); }), s.promise; } remove(e) { const t = this.items, s = this.callbacks, n = t.indexOf(e); if (n !== -1) { const i = s.get(e); i.promise.catch(() => { }), i.reject(new Error("PriorityQueue: Item removed.")), t.splice(n, 1), s.delete(e); } } removeByFilter(e) { const { items: t } = this; for (let s = 0; s < t.length; s++) { const n = t[s]; e(n) && this.remove(n); } } tryRunJobs() { this.sort(); const e = this.items, t = this.callbacks, s = this.maxJobs; let n = 0; const i = () => { this.currJobs--, this.autoUpdate && this.scheduleJobRun(); }; for (; s > this.currJobs && e.length > 0 && n < s; ) { this.currJobs++, n++; const r = e.pop(), { callback: o, resolve: c, reject: A } = t.get(r); t.delete(r); let l; try { l = o(r); } catch (h) { A(h), i(); } l instanceof Promise ? l.then(c).catch(A).finally(i) : (c(l), i()); } } scheduleJobRun() { this.scheduled || (this.schedulingCallback(this._runjobs), this.scheduled = !0); } } const Kt = -1, ct = 0, Fs = 1, Hn = 2, Bs = 3, Gr = 6378137, sl = 6356752314245179e-9, ks = { inView: !1, error: 1 / 0, distanceFromCamera: 1 / 0 }; function Ho(a) { return a === Bs || a === Kt; } function vt(a, e) { return a.__lastFrameVisited === e && a.__used; } function cr(a) { return a.__childrenProcessed === a.children.length; } function Ar(a, e) { a.__lastFrameVisited !== e.frameCount && (a.__lastFrameVisited = e.frameCount, a.__used = !1, a.__inFrustum = !1, a.__isLeaf = !1, a.__visible = !1, a.__active = !1, a.__error = 1 / 0, a.__distanceFromCamera = 1 / 0, a.__childrenWereVisible = !1, a.__allChildrenLoaded = !1, e.calculateTileViewError(a, ks), a.__inFrustum = ks.inView, a.__error = ks.error, a.__distanceFromCamera = ks.distanceFromCamera); } function zo(a, e) { if (e.ensureChildrenArePreprocessed(a), Ar(a, e), ki(a, e), !a.__hasRenderableContent && cr(a)) { const t = a.children; for (let s = 0, n = t.length; s < n; s++) zo(t[s], e); } } function jo(a, e) { if (e.ensureChildrenArePreprocessed(a), vt(a, e.frameCount) && (a.__hasContent && a.__loadingState === ct && !e.lruCache.isFull() && e.queueTileForDownload(a), cr(a))) { const t = a.children; for (let s = 0, n = t.length; s < n; s++) jo(t[s], e); } } function ki(a, e) { a.__used || (a.__used = !0, e.markTileUsed(a), e.stats.used++, a.__inFrustum === !0 && e.stats.inFrustum++); } function nl(a, e) { return !(a.__error <= e.errorTarget || e.maxDepth > 0 && a.__depth + 1 >= e.maxDepth || !cr(a)); } function Pi(a, e = null, t = null) { const s = []; for (s.push(a), s.push(null), s.push(0); s.length > 0; ) { const n = s.pop(), i = s.pop(), r = s.pop(); if (e && e(r, i, n)) { t && t(r, i, n); return; } const o = r.children; if (o) for (let c = o.length - 1; c >= 0; c--) s.push(o[c]), s.push(r), s.push(n + 1); t && t(r, i, n); } } function Vo(a, e) { if (e.ensureChildrenArePreprocessed(a), Ar(a, e), !a.__inFrustum) return; if (!nl(a, e)) { ki(a, e); return; } let t = !1, s = !1; const n = a.children; for (let i = 0, r = n.length; i < r; i++) { const o = n[i]; Vo(o, e), t = t || vt(o, e.frameCount), s = s || o.__inFrustum; } if (ki(a, e), t && a.refine === "REPLACE") for (let i = 0, r = n.length; i < r; i++) { const o = n[i]; zo(o, e); } } function qo(a, e) { const t = e.frameCount; if (!vt(a, t)) return; const s = a.children; let n = !1; for (let i = 0, r = s.length; i < r; i++) { const o = s[i]; n = n || vt(o, t); } if (!n) a.__isLeaf = !0; else { let i = !1, r = !0; for (let o = 0, c = s.length; o < c; o++) { const A = s[o]; if (qo(A, e), i = i || A.__wasSetVisible || A.__childrenWereVisible, vt(A, t)) { const l = A.__allChildrenLoaded || A.__hasRenderableContent && Ho(A.__loadingState) || !A.__hasContent && A.children.length === 0 || A.__hasUnrenderableContent && A.__loadingState === Kt; r = r && l; } } a.__childrenWereVisible = i, a.__allChildrenLoaded = r; } } function Ko(a, e) { const t = e.stats; if (!vt(a, e.frameCount)) return; const s = e.lruCache; if (a.__isLeaf) { a.__loadingState === Bs ? (a.__inFrustum && (a.__visible = !0, t.visible++), a.__active = !0, t.active++) : !s.isFull() && a.__hasContent && e.queueTileForDownload(a); return; } const n = a.children, i = a.__hasContent, r = Ho(a.__loadingState) && i, o = (e.errorTarget + 1) * e.errorThreshold, c = a.__error <= o, A = a.__childrenWereVisible, l = a.__allChildrenLoaded; if ((c || a.refine === "ADD") && !r && !s.isFull() && i && e.queueTileForDownload(a), (c && !l && !A && r || a.refine === "ADD" && r) && (a.__inFrustum && (a.__visible = !0, t.visible++), a.__active = !0, t.active++), a.refine === "REPLACE" && c && !l) for (let u = 0, d = n.length; u < d; u++) { const f = n[u]; vt(f, e.frameCount) && jo(f, e); } else for (let u = 0, d = n.length; u < d; u++) Ko(n[u], e); } function Wo(a, e) { const t = vt(a, e.frameCount); if (t || a.__usedLastFrame) { let s = !1, n = !1; t ? (s = a.__active, e.displayActiveTiles ? n = a.__active || a.__visible : n = a.__visible) : Ar(a, e), a.__hasRenderableContent && a.__loadingState === Bs && (a.__wasSetActive !== s && e.invokeOnePlugin((r) => r.setTileActive && r.setTileActive(a, s)), a.__wasSetVisible !== n && e.invokeOnePlugin((r) => r.setTileVisible && r.setTileVisible(a, n))), a.__wasSetActive = s, a.__wasSetVisible = n, a.__usedLastFrame = t; const i = a.children; for (let r = 0, o = i.length; r < o; r++) { const c = i[r]; Wo(c, e); } } } function il(a, e = null) { let t = a; for (; t; ) { const s = t.__depth, n = t.parent; e && e(t, n, s), t = n; } } function rl(a) { let e = null; return () => { e === null && (e = requestAnimationFrame(() => { e = null, a(); })); }; } const Ur = Symbol("PLUGIN_REGISTERED"), zn = (a, e) => { const t = a.priority || 0, s = e.priority || 0; return t !== s ? t > s ? 1 : -1 : a.__depthFromRenderedParent !== e.__depthFromRenderedParent ? a.__depthFromRenderedParent > e.__depthFromRenderedParent ? -1 : 1 : a.__inFrustum !== e.__inFrustum ? a.__inFrustum ? 1 : -1 : a.__used !== e.__used ? a.__used ? 1 : -1 : a.__error !== e.__error ? a.__error > e.__error ? 1 : -1 : a.__distanceFromCamera !== e.__distanceFromCamera ? a.__distanceFromCamera > e.__distanceFromCamera ? -1 : 1 : 0; }, al = (a, e) => { const t = a.priority || 0, s = e.priority || 0; return t !== s ? t > s ? 1 : -1 : a.__depthFromRenderedParent !== e.__depthFromRenderedParent ? a.__depthFromRenderedParent > e.__depthFromRenderedParent ? 1 : -1 : a.__loadingState !== e.__loadingState ? a.__loadingState > e.__loadingState ? -1 : 1 : a.__lastFrameVisited !== e.__lastFrameVisited ? a.__lastFrameVisited > e.__lastFrameVisited ? -1 : 1 : a.__hasUnrenderableContent !== e.__hasUnrenderableContent ? a.__hasUnrenderableContent ? -1 : 1 : a.__error !== e.__error ? a.__error > e.__error ? -1 : 1 : 0; }; class ol { get root() { const e = this.rootTileSet; return e ? e.root : null; } get loadProgress() { const { stats: e, isLoading: t } = this, s = e.downloading + e.parsing, n = e.inCacheSinceLoad + (t ? 1 : 0); return n === 0 ? 1 : 1 - s / n; } get errorThreshold() { return this._errorThreshold; } set errorThreshold(e) { console.warn('TilesRenderer: The "errorThreshold" option has been deprecated.'), this._errorThreshold = e; } constructor(e = null) { this.rootLoadingState = ct, this.rootTileSet = null, this.rootURL = e, this.fetchOptions = {}, this.plugins = [], this.queuedTiles = [], this.cachedSinceLoadComplete = /* @__PURE__ */ new Set(), this.isLoading = !1; const t = new Oo(); t.unloadPriorityCallback = al; const s = new On(); s.maxJobs = 25, s.priorityCallback = zn; const n = new On(); n.maxJobs = 5, n.priorityCallback = zn; const i = new On(); i.maxJobs = 25, i.priorityCallback = zn, i.log = !0, this.processedTiles = /* @__PURE__ */ new WeakSet(), this.visibleTiles = /* @__PURE__ */ new Set(), this.activeTiles = /* @__PURE__ */ new Set(), this.usedSet = /* @__PURE__ */ new Set(), this.lruCache = t, this.downloadQueue = s, this.parseQueue = n, this.processNodeQueue = i, this.stats = { inCacheSinceLoad: 0, inCache: 0, parsing: 0, downloading: 0, failed: 0, inFrustum: 0, used: 0, active: 0, visible: 0 }, this.frameCount = 0, this._dispatchNeedsUpdateEvent = rl(() => { this.dispatchEvent({ type: "needs-update" }); }), this.errorTarget = 16, this._errorThreshold = 1 / 0, this.displayActiveTiles = !1, this.maxDepth = 1 / 0; } // Plugins registerPlugin(e) { if (e[Ur] === !0) throw new Error("TilesRendererBase: A plugin can only be registered to a single tile set"); const t = this.plugins, s = e.priority || 0; let n = t.length; for (let i = 0; i < t.length; i++) if ((t[i].priority || 0) > s) { n = i; break; } t.splice(n, 0, e), e[Ur] = !0, e.init && e.init(this); } unregisterPlugin(e) { const t = this.plugins; if (typeof e == "string" && (e = this.getPluginByName(name)), t.includes(e)) { const s = t.indexOf(e); return t.splice(s, 1), e.dispose && e.dispose(), !0; } return !1; } getPluginByName(e) { return this.plugins.find((t) => t.name === e) || null; } traverse(e, t, s = !0) { this.root && Pi(this.root, (n, ...i) => (s && this.ensureChildrenArePreprocessed(n, !0), e ? e(n, ...i) : !1), t); } queueTileForDownload(e) { e.__loadingState === ct && this.queuedTiles.push(e); } markTileUsed(e) { this.usedSet.add(e), this.lruCache.markUsed(e); } // Public API update() { const { lruCache: e, usedSet: t, stats: s, root: n, downloadQueue: i, parseQueue: r, processNodeQueue: o } = this; if (this.rootLoadingState === ct && (this.rootLoadingState = Fs, this.invokeOnePlugin((l) => l.loadRootTileSet && l.loadRootTileSet()).then((l) => { let h = this.rootURL; h !== null && this.invokeAllPlugins((u) => h = u.preprocessURL ? u.preprocessURL(h, null) : h), this.rootLoadingState = Bs, this.rootTileSet = l, this.dispatchEvent({ type: "needs-update" }), this.dispatchEvent({ type: "load-content" }), this.dispatchEvent({ type: "load-tile-set", tileSet: l, url: h }); }).catch((l) => { this.rootLoadingState = Kt, console.error(l), this.rootTileSet = null, this.dispatchEvent({ type: "load-error", tile: null, error: l, url: this.rootURL }); })), !n) return; s.inFrustum = 0, s.used = 0, s.active = 0, s.visible = 0, this.frameCount++, t.forEach((l) => e.markUnused(l)), t.clear(), Vo(n, this), qo(n, this), Ko(n, this), Wo(n, this); const c = this.queuedTiles; c.sort(e.unloadPriorityCallback); for (let l = 0, h = c.length; l < h && !e.isFull(); l++) this.requestTileContents(c[l]); c.length = 0, e.scheduleUnload(), (i.running || r.running || o.running) === !1 && this.isLoading === !0 && (this.cachedSinceLoadComplete.clear(), s.inCacheSinceLoad = 0, this.dispatchEvent({ type: "tiles-load-end" }), this.isLoading = !1); } resetFailedTiles() { this.rootLoadingState === Kt && (this.rootLoadingState = ct); const e = this.stats; e.failed !== 0 && (this.traverse((t) => { t.__loadingState === Kt && (t.__loadingState = ct); }, null, !1), e.failed = 0); } dispose() { [...this.plugins].forEach((n) => { this.unregisterPlugin(n); }); const t = this.lruCache, s = []; this.traverse((n) => (s.push(n), !1), null, !1); for (let n = 0, i = s.length; n < i; n++) t.remove(s[n]); this.stats = { parsing: 0, downloading: 0, failed: 0, inFrustum: 0, used: 0, active: 0, visible: 0 }, this.frameCount = 0; } // Overrideable calculateBytesUsed(e, t) { return 0; } dispatchEvent(e) { } fetchData(e, t) { return fetch(e, t); } parseTile(e, t, s) { return null; } disposeTile(e) { e.__visible && (this.invokeOnePlugin((t) => t.setTileVisible && t.setTileVisible(e, !1)), e.__visible = !1), e.__active && (this.invokeOnePlugin((t) => t.setTileActive && t.setTileActive(e, !1)), e.__active = !1); } preprocessNode(e, t, s = null) { var n; if (this.processedTiles.add(e), e.content && (!("uri" in e.content) && "url" in e.content && (e.content.uri = e.content.url, delete e.content.url), e.content.boundingVolume && !("box" in e.content.boundingVolume || "sphere" in e.content.boundingVolume || "region" in e.content.boundingVolume) && delete e.content.boundingVolume), e.parent = s, e.children = e.children || [], (n = e.content) != null && n.uri) { const i = kr(e.content.uri); e.__hasContent = !0, e.__hasUnrenderableContent = !!(i && /json$/.test(i)), e.__hasRenderableContent = !e.__hasUnrenderableContent; } else e.__hasContent = !1, e.__hasUnrenderableContent = !1, e.__hasRenderableContent = !1; e.__childrenProcessed = 0, s && s.__childrenProcessed++, e.__distanceFromCamera = 1 / 0, e.__error = 1 / 0, e.__inFrustum = !1, e.__isLeaf = !1, e.__usedLastFrame = !1, e.__used = !1, e.__wasSetVisible = !1, e.__visible = !1, e.__childrenWereVisible = !1, e.__allChildrenLoaded = !1, e.__wasSetActive = !1, e.__active = !1, e.__loadingState = ct, s === null ? (e.__depth = 0, e.__depthFromRenderedParent = e.__hasRenderableContent ? 1 : 0, e.refine = e.refine || "REPLACE") : (e.__depth = s.__depth + 1, e.__depthFromRenderedParent = s.__depthFromRenderedParent + (e.__hasRenderableContent ? 1 : 0), e.refine = e.refine || s.refine), e.__basePath = t, e.__lastFrameVisited = -1, this.invokeAllPlugins((i) => { i !== this && i.preprocessNode && i.preprocessNode(e, t, s); }); } setTileActive(e, t) { t ? this.activeTiles.add(e) : this.activeTiles.delete(e); } setTileVisible(e, t) { t ? this.visibleTiles.add(e) : this.visibleTiles.delete(e); } calculateTileViewError(e, t) { } ensureChildrenArePreprocessed(e, t = !1) { const s = e.children; for (let n = 0, i = s.length; n < i; n++) { const r = s[n]; if ("__depth" in r) break; t ? (this.processNodeQueue.remove(r), this.preprocessNode(r, e.__basePath, e)) : this.processNodeQueue.has(r) || this.processNodeQueue.add(r, (o) => { this.preprocessNode(o, e.__basePath, e), this._dispatchNeedsUpdateEvent(); }); } } // Private Functions // returns the total bytes used for by the given tile as reported by all plugins getBytesUsed(e) { let t = 0; return this.invokeAllPlugins((s) => { s.calculateBytesUsed && (t += s.calculateBytesUsed(e, e.cached.scene) || 0); }), t; } // force a recalculation of the tile or all tiles if no tile is provided recalculateBytesUsed(e = null) { const { lruCache: t, processedTiles: s } = this; e === null ? t.itemSet.forEach((n) => { s.has(n) && t.setMemoryUsage(n, this.getBytesUsed(n)); }) : t.setMemoryUsage(e, this.getBytesUsed(e)); } preprocessTileSet(e, t, s = null) { const n = e.asset.version, [i, r] = n.split(".").map((c) => parseInt(c)); console.assert( i <= 1, "TilesRenderer: asset.version is expected to be a 1.x or a compatible version." ), i === 1 && r > 0 && console.warn("TilesRenderer: tiles versions at 1.1 or higher have limited support. Some new extensions and features may not be supported."); let o = t.replace(/\/[^/]*$/, ""); o = new URL(o, window.location.href).toString(), this.preprocessNode(e.root, o, s); } loadRootTileSet() { let e = this.rootURL; return this.invokeAllPlugins((s) => e = s.preprocessURL ? s.preprocessURL(e, null) : e), this.invokeOnePlugin((s) => s.fetchData && s.fetchData(e, this.fetchOptions)).then((s) => { if (s instanceof Response) { if (s.ok) return s.json(); throw new Error(`TilesRenderer: Failed to load tileset "${e}" with status ${s.status} : ${s.statusText}`); } else return s; }).then((s) => (this.preprocessTileSet(s, e), s)); } requestTileContents(e) { if (e.__loadingState !== ct) return; let t = !1, s = null, n = new URL(e.content.uri, e.__basePath + "/").toString(); this.invokeAllPlugins((d) => n = d.preprocessURL ? d.preprocessURL(n, e) : n); const i = this.stats, r = this.lruCache, o = this.downloadQueue, c = this.parseQueue, A = kr(n), l = new AbortController(), h = l.signal; if (r.add(e, (d) => { l.abort(), t ? (d.children.length = 0, d.__childrenProcessed = 0) : this.invokeAllPlugins((f) => { f.disposeTile && f.disposeTile(d); }), i.inCache--, this.cachedSinceLoadComplete.has(e) && (this.cachedSinceLoadComplete.delete(e), i.inCacheSinceLoad--), d.__loadingState === Fs ? i.downloading-- : d.__loadingState === Hn && i.parsing--, d.__loadingState = ct, c.remove(d), o.remove(d); })) return this.isLoading || (this.isLoading = !0, this.dispatchEvent({ type: "tiles-load-start" })), r.setMemoryUsage(e, this.getBytesUsed(e)), this.cachedSinceLoadComplete.add(e), i.inCacheSinceLoad++, i.inCache++, i.downloading++, e.__loadingState = Fs, o.add(e, (d) => { if (h.aborted) return Promise.resolve(); const f = this.invokeOnePlugin((g) => g.fetchData && g.fetchData(n, { ...this.fetchOptions, signal: h })); return this.dispatchEvent({ type: "tile-download-start", tile: e }), f; }).then((d) => { if (!h.aborted) if (d instanceof Response) { if (d.ok) return A === "json" ? d.json() : d.arrayBuffer(); throw new Error(`Failed to load model with error code ${d.status}`); } else return d; }).then((d) => { if (!h.aborted) return i.downloading--, i.parsing++, e.__loadingState = Hn, c.add(e, (f) => h.aborted ? Promise.resolve() : A === "json" && d.root ? (this.preprocessTileSet(d, n, e), e.children.push(d.root), s = d, t = !0, Promise.resolve()) : this.invokeOnePlugin((g) => g.parseTile && g.parseTile(d, f, A, n, h))); }).then(() => { if (!h.aborted) { if (i.parsing--, e.__loadingState = Bs, r.setLoaded(e, !0), r.getMemoryUsage(e) === 0) { const d = this.getBytesUsed(e); if (r.isFull() && d > 0) { r.remove(e); return; } else r.setMemoryUsage(e, d); } this.dispatchEvent({ type: "needs-update" }), this.dispatchEvent({ type: "load-content" }), t && this.dispatchEvent({ type: "load-tile-set", tileSet: s, url: n }), e.cached.scene && this.dispatchEvent({ type: "load-model", scene: e.cached.scene, tile: e }); } }).catch((d) => { h.aborted || (d.name !== "AbortError" ? (c.remove(e), o.remove(e), e.__loadingState === Hn ? i.parsing-- : e.__loadingState === Fs && i.downloading--, i.failed++, console.error(`TilesRenderer : Failed to load tile at url "${e.content.uri}".`), console.error(d), e.__loadingState = Kt, r.setLoaded(e, !0), this.dispatchEvent({ type: "load-error", tile: e, error: d, url: n })) : r.remove(e)); }); } getAttributions(e = []) { return this.invokeAllPlugins((t) => t !== this && t.getAttributions && t.getAttributions(e)), e; } invokeOnePlugin(e) { const t = [...this.plugins, this]; for (let s = 0; s < t.length; s++) { const n = e(t[s]); if (n) return n; } return null; } invokeAllPlugins(e) { const t = [...this.plugins, this], s = []; for (let n = 0; n < t.length; n++) { const i = e(t[n]); i && s.push(i); } return s.length === 0 ? null : Promise.all(s); } } class Qs { constructor() { this.fetchOptions = {}, this.workingPath = ""; } load(...e) { return console.warn('Loader: "load" function has been deprecated in favor of "loadAsync".'), this.loadAsync(...e); } loadAsync(e) { return fetch(e, this.fetchOptions).then((t) => { if (!t.ok) throw new Error(`Failed to load file "${e}" with status ${t.status} : ${t.statusText}`); return t.arrayBuffer(); }).then((t) => (this.workingPath === "" && (this.workingPath = this.workingPathForURL(e)), this.parse(t))); } resolveExternalURL(e) { return /^[^\\/]/.test(e) && !/^http/.test(e) ? this.workingPath + "/" + e : e; } workingPathForURL(e) { const t = e.split(/[\\/]/g); return t.pop(), t.join("/") + "/"; } parse(e) { throw new Error("LoaderBase: Parse not implemented."); } } const cl = new TextDecoder(); function lr(a) { return cl.decode(a); } function Jo(a, e, t, s, n, i) { let r; switch (s) { case "SCALAR": r = 1; break; case "VEC2": r = 2; break; case "VEC3": r = 3; break; case "VEC4": r = 4; break; default: throw new Error(`FeatureTable : Feature type not provided for "${i}".`); } let o; const c = t * r; switch (n) { case "BYTE": o = new Int8Array(a, e, c); break; case "UNSIGNED_BYTE": o = new Uint8Array(a, e, c); break; case "SHORT": o = new Int16Array(a, e, c); break; case "UNSIGNED_SHORT": o = new Uint16Array(a, e, c); break; case "INT": o = new Int32Array(a, e, c); break; case "UNSIGNED_INT": o = new Uint32Array(a, e, c); break; case "FLOAT": o = new Float32Array(a, e, c); break; case "DOUBLE": o = new Float64Array(a, e, c); break; default: throw new Error(`FeatureTable : Feature component type not provided for "${i}".`); } return o; } class kn { constructor(e, t, s, n) { this.buffer = e, this.binOffset = t + s, this.binLength = n; let i = null; if (s !== 0) { const r = new Uint8Array(e, t, s); i = JSON.parse(lr(r)); } else i = {}; this.header = i; } getKeys() { return Object.keys(this.header); } getData(e, t, s = null, n = null) { const i = this.header; if (!(e in i)) return null; const r = i[e]; if (r instanceof Object) { if (Array.isArray(r)) return r; { const { buffer: o, binOffset: c, binLength: A } = this, l = r.byteOffset || 0, h = r.type || n, u = r.componentType || s; if ("type" in r && n && r.type !== n) throw new Error("FeatureTable: Specified type does not match expected type."); const d = c + l, f = Jo(o, d, t, h, u, e); if (d + f.byteLength > c + A) throw new Error("FeatureTable: Feature data read outside binary body length."); return f; } } else return r; } getBuffer(e, t) { const { buffer: s, binOffset: n } = this; return s.slice(n + e, n + e + t); } } class Al { constructor(e) { this.batchTable = e; const t = e.header.extensions["3DTILES_batch_table_hierarchy"]; this.classes = t.classes; for (const n of this.classes) { const i = n.instances; for (const r in i) n.instances[r] = this._parseProperty(i[r], n.length, r); } if (this.instancesLength = t.instancesLength, this.classIds = this._parseProperty(t.classIds, this.instancesLength, "classIds"), t.parentCounts ? this.parentCounts = this._parseProperty(t.parentCounts, this.instancesLength, "parentCounts") : this.parentCounts = new Array(this.instancesLength).fill(1), t.parentIds) { const n = this.parentCounts.reduce((i, r) => i + r, 0); this.parentIds = this._parseProperty(t.parentIds, n, "parentIds"); } else this.parentIds = null; this.instancesIds = []; const s = {}; for (const n of this.classIds) s[n] = s[n] ?? 0, this.instancesIds.push(s[n]), s[n]++; } _parseProperty(e, t, s) { if (Array.isArray(e)) return e; { const { buffer: n, binOffset: i } = this.batchTable, r = e.byteOffset, o = e.componentType || "UNSIGNED_SHORT", c = i + r; return Jo(n, c, t, "SCALAR", o, s); } } getDataFromId(e, t = {}) { const s = this.parentCounts[e]; if (this.parentIds && s > 0) { let c = 0; for (let A = 0; A < e; A++) c += this.parentCounts[A]; for (let A = 0; A < s; A++