3d-tiles-renderer
Version:
https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification
1,342 lines (1,303 loc) • 310 kB
JavaScript
import { C as Xn, G as jn, Q as $n, b as Qn } from "./QuantizedMeshLoaderBase-DIIZywLI.js";
import { Vector3 as C, MathUtils as w, PlaneGeometry as Zs, Mesh as _e, MeshBasicMaterial as xe, Sphere as Te, Texture as Kn, SRGBColorSpace as ct, TextureUtils as Zn, Matrix4 as Y, BufferGeometry as Fe, BufferAttribute as G, Triangle as Os, Vector4 as be, CanvasTexture as ht, Color as Vs, Box3 as Ft, DefaultLoadingManager as Jn, MeshStandardMaterial as ln, DataTexture as zt, RGFormat as cn, UnsignedByteType as hn, LinearMipMapLinearFilter as er, LinearFilter as un, Vector2 as k, Matrix3 as tr, Matrix2 as sr, WebGLRenderer as ir, WebGLRenderTarget as Js, ShaderMaterial as nr, OneFactor as rr, ZeroFactor as or, CustomBlending as ar, Box2 as lr, FileLoader as cr, Quaternion as dn, BatchedMesh as hr, Source as ur, REVISION as dr, WebGLArrayRenderTarget as ei, Raycaster as fn, DoubleSide as Pt, Ray as fr, LineSegments as ks, LineBasicMaterial as pr, EdgesGeometry as mr, BoxGeometry as pn, Group as Le, Box3Helper as gr, SphereGeometry as yr, PointsMaterial as mn, EventDispatcher as Ns, Frustum as xr, Points as As, GreaterDepth as _r } from "three";
import { W as Tr, g as br, a as gn, c as vr, O as wr, b as Fs } from "./MemoryUtils-ZzXvtRjr.js";
import { GLTFLoader as Sr } from "three/addons/loaders/GLTFLoader.js";
import { FullScreenQuad as yn } from "three/addons/postprocessing/Pass.js";
import { c as zs, D as Mr, u as Cr, b as Ar, e as xn } from "./TilesRendererBase-BGxy2Uih.js";
import { c as Lr, L as _n } from "./LoaderBase-CU5shB7w.js";
const jt = /* @__PURE__ */ new C(), ft = /* @__PURE__ */ new C();
function Er(h, e, t) {
const i = t + 1e-5;
let n = e + 1e-5;
Math.abs(n) > Math.PI / 2 && (n = n - 1e-5), h.getCartographicToPosition(e, t, 0, jt), h.getCartographicToPosition(n, t, 0, ft);
const r = jt.distanceTo(ft) / 1e-5;
return h.getCartographicToPosition(e, i, 0, ft), [jt.distanceTo(ft) / 1e-5, r];
}
class ee {
get isMercator() {
return this.scheme === "EPSG:3857";
}
get isCartographic() {
return this.scheme !== "none";
}
constructor(e = "EPSG:4326") {
this.scheme = e, this.tileCountX = 1, this.tileCountY = 1, this.setScheme(e);
}
setScheme(e) {
switch (this.scheme = e, e) {
// equirect
case "CRS:84":
case "EPSG:4326":
this.tileCountX = 2, this.tileCountY = 1;
break;
// mercator
case "EPSG:3857":
this.tileCountX = 1, this.tileCountY = 1;
break;
case "none":
this.tileCountX = 1, this.tileCountY = 1;
break;
default:
throw new Error(`ProjectionScheme: Unknown projection scheme "${e}"`);
}
}
convertNormalizedToLatitude(e) {
if (this.scheme === "none")
return e;
if (this.isMercator) {
const t = w.mapLinear(e, 0, 1, -1, 1);
return 2 * Math.atan(Math.exp(t * Math.PI)) - Math.PI / 2;
} else
return w.mapLinear(e, 0, 1, -Math.PI / 2, Math.PI / 2);
}
convertNormalizedToLongitude(e) {
return this.scheme === "none" ? e : w.mapLinear(e, 0, 1, -Math.PI, Math.PI);
}
convertLatitudeToNormalized(e) {
if (this.scheme === "none")
return e;
if (this.isMercator) {
const t = Math.log(Math.tan(Math.PI / 4 + e / 2));
return 1 / 2 + 1 * t / (2 * Math.PI);
} else
return w.mapLinear(e, -Math.PI / 2, Math.PI / 2, 0, 1);
}
convertLongitudeToNormalized(e) {
return this.scheme === "none" ? e : (e + Math.PI) / (2 * Math.PI);
}
getLongitudeDerivativeAtNormalized(e) {
return this.scheme === "none" ? 1 : 2 * Math.PI;
}
getLatitudeDerivativeAtNormalized(e) {
if (this.scheme === "none")
return 1;
{
let s = e - 1e-5;
return s < 0 && (s = e + 1e-5), this.isMercator ? Math.abs(this.convertNormalizedToLatitude(e) - this.convertNormalizedToLatitude(s)) / 1e-5 : Math.PI;
}
}
getBounds() {
return this.scheme === "none" ? [0, 0, 1, 1] : [
this.convertNormalizedToLongitude(0),
this.convertNormalizedToLatitude(0),
this.convertNormalizedToLongitude(1),
this.convertNormalizedToLatitude(1)
];
}
toNormalizedPoint(e, t) {
const s = [e, t];
return s[0] = this.convertLongitudeToNormalized(s[0]), s[1] = this.convertLatitudeToNormalized(s[1]), s;
}
toNormalizedRange(e) {
return [
...this.toNormalizedPoint(e[0], e[1]),
...this.toNormalizedPoint(e[2], e[3])
];
}
toCartographicPoint(e, t) {
const s = [e, t];
return s[0] = this.convertNormalizedToLongitude(s[0]), s[1] = this.convertNormalizedToLatitude(s[1]), s;
}
toCartographicRange(e) {
return [
...this.toCartographicPoint(e[0], e[1]),
...this.toCartographicPoint(e[2], e[3])
];
}
clampToBounds(e, t = !1) {
const s = [...e];
let i;
t ? i = [0, 0, 1, 1] : i = this.getBounds();
const [n, r, o, a] = i;
return s[0] = w.clamp(s[0], n, o), s[2] = w.clamp(s[2], n, o), s[1] = w.clamp(s[1], r, a), s[3] = w.clamp(s[3], r, a), s;
}
}
function ti(h, e) {
const [t, s, i, n] = h, [r, o, a, l] = e;
return !(t >= a || i <= r || s >= l || n <= o);
}
class Gt {
get levelCount() {
return this._levels.length;
}
get maxLevel() {
return this.levelCount - 1;
}
get minLevel() {
const e = this._levels;
for (let t = 0; t < e.length; t++)
if (e[t] !== null)
return t;
return -1;
}
// prioritize user-set bounds over projection bounds if present
get contentBounds() {
return this._contentBounds ?? this.projection.getBounds();
}
get aspectRatio() {
const { pixelWidth: e, pixelHeight: t } = this.getLevel(this.maxLevel);
return e / t;
}
constructor() {
this.flipY = !1, this.pixelOverlap = 0, this._contentBounds = null, this.projection = new ee("none"), this._levels = [];
}
// build the zoom levels
setLevel(e, t = {}) {
const s = this._levels;
for (; s.length < e; )
s.push(null);
const {
tileSplitX: i = 2,
tileSplitY: n = 2
} = t, {
tilePixelWidth: r = 256,
tilePixelHeight: o = 256,
tileCountX: a = i ** e,
tileCountY: l = n ** e,
tileBounds: c = null
} = t, {
pixelWidth: u = r * a,
pixelHeight: d = o * l
} = t;
s[e] = {
// The pixel resolution of each tile.
tilePixelWidth: r,
tilePixelHeight: o,
// The total pixel resolution of the final image at this level. These numbers
// may not be a round multiple of the tile width.
pixelWidth: u,
pixelHeight: d,
// Or the total number of tiles that can be loaded at this level.
tileCountX: a,
tileCountY: l,
// The number of tiles that the tiles at this layer split in to
tileSplitX: i,
tileSplitY: n,
// The bounds covered by the extent of the tiles at this loaded. The actual content covered by the overall tileset
// may be a subset of this range (eg there may be unused space).
tileBounds: c
};
}
generateLevels(e, t, s, i = {}) {
const {
minLevel: n = 0,
tilePixelWidth: r = 256,
tilePixelHeight: o = 256
} = i, a = e - 1, {
pixelWidth: l = r * t * 2 ** a,
pixelHeight: c = o * s * 2 ** a
} = i;
for (let u = n; u < e; u++) {
const d = e - u - 1, p = Math.ceil(l * 2 ** -d), m = Math.ceil(c * 2 ** -d), f = Math.ceil(p / r), g = Math.ceil(m / o);
this.setLevel(u, {
tilePixelWidth: r,
tilePixelHeight: o,
pixelWidth: p,
pixelHeight: m,
tileCountX: f,
tileCountY: g
});
}
}
getLevel(e) {
return this._levels[e];
}
// bounds representing the contentful region of the image
setContentBounds(e, t, s, i) {
this._contentBounds = [e, t, s, i];
}
setProjection(e) {
this.projection = e;
}
// query functions
getTileAtPoint(e, t, s, i = !1) {
const { flipY: n } = this, { tileCountY: r, tileBounds: o, pixelHeight: a, pixelWidth: l, tilePixelHeight: c, tilePixelWidth: u } = this.getLevel(s), d = u / l, p = c / a;
if (i || ([e, t] = this.toNormalizedPoint(e, t)), o) {
const g = this.toNormalizedRange(o);
e = w.mapLinear(e, g[0], g[2], 0, 1), t = w.mapLinear(t, g[1], g[3], 0, 1);
}
const m = Math.floor(e / d);
let f = Math.floor(t / p);
return n && (f = r - 1 - f), [m, f];
}
getTilesInRange(e, t, s, i, n, r = !1) {
const o = [e, t, s, i], a = this.getContentBounds(r);
let l = this.getLevel(n).tileBounds;
if (!ti(o, a))
return [0, 0, -1, -1];
if (l && (r && (l = this.toNormalizedRange(l)), !ti(o, a)))
return [0, 0, -1, -1];
const [c, u, d, p] = this.clampToContentBounds(o, r), m = this.getTileAtPoint(c, u, n, r), f = this.getTileAtPoint(d, p, n, r);
this.flipY && ([m[1], f[1]] = [f[1], m[1]]);
const { tileCountX: g, tileCountY: y } = this.getLevel(n), [x, _] = m, [b, T] = f;
return b < 0 || T < 0 || x >= g || _ >= y ? [0, 0, -1, -1] : [
w.clamp(x, 0, g - 1),
w.clamp(_, 0, y - 1),
w.clamp(b, 0, g - 1),
w.clamp(T, 0, y - 1)
];
}
getTileExists(e, t, s) {
const [i, n, r, o] = this.contentBounds, [a, l, c, u] = this.getTileBounds(e, t, s);
return !(a >= c || l >= u) && a <= r && l <= o && c >= i && u >= n;
}
getContentBounds(e = !1) {
const { projection: t } = this, s = [...this.contentBounds];
return e && (s[0] = t.convertLongitudeToNormalized(s[0]), s[1] = t.convertLatitudeToNormalized(s[1]), s[2] = t.convertLongitudeToNormalized(s[2]), s[3] = t.convertLatitudeToNormalized(s[3])), s;
}
// returns the UV range associated with the content in the given tile
getTileContentUVBounds(e, t, s) {
const [i, n, r, o] = this.getTileBounds(e, t, s, !0, !0), [a, l, c, u] = this.getTileBounds(e, t, s, !0, !1);
return [
w.mapLinear(i, a, c, 0, 1),
w.mapLinear(n, l, u, 0, 1),
w.mapLinear(r, a, c, 0, 1),
w.mapLinear(o, l, u, 0, 1)
];
}
getTileBounds(e, t, s, i = !1, n = !0) {
const { flipY: r, pixelOverlap: o, projection: a } = this, { tilePixelWidth: l, tilePixelHeight: c, pixelWidth: u, pixelHeight: d, tileBounds: p } = this.getLevel(s);
let m = l * e - o, f = c * t - o, g = m + l + o * 2, y = f + c + o * 2;
if (m = Math.max(m, 0), f = Math.max(f, 0), g = Math.min(g, u), y = Math.min(y, d), m = m / u, g = g / u, f = f / d, y = y / d, r) {
const _ = (y - f) / 2, T = 1 - (f + y) / 2;
f = T - _, y = T + _;
}
let x = [m, f, g, y];
if (p) {
const _ = this.toNormalizedRange(p);
x[0] = w.mapLinear(x[0], 0, 1, _[0], _[2]), x[2] = w.mapLinear(x[2], 0, 1, _[0], _[2]), x[1] = w.mapLinear(x[1], 0, 1, _[1], _[3]), x[3] = w.mapLinear(x[3], 0, 1, _[1], _[3]);
}
return n && (x = this.clampToBounds(x, !0)), i || (x[0] = a.convertNormalizedToLongitude(x[0]), x[1] = a.convertNormalizedToLatitude(x[1]), x[2] = a.convertNormalizedToLongitude(x[2]), x[3] = a.convertNormalizedToLatitude(x[3])), x;
}
toNormalizedPoint(e, t) {
return this.projection.toNormalizedPoint(e, t);
}
toNormalizedRange(e) {
return this.projection.toNormalizedRange(e);
}
toCartographicPoint(e, t) {
return this.projection.toCartographicPoint(e, t);
}
toCartographicRange(e) {
return this.projection.toCartographicRange(e);
}
clampToContentBounds(e, t = !1) {
const s = [...e], [i, n, r, o] = this.getContentBounds(t);
return s[0] = w.clamp(s[0], i, r), s[1] = w.clamp(s[1], n, o), s[2] = w.clamp(s[2], i, r), s[3] = w.clamp(s[3], n, o), s;
}
clampToBounds(e, t = !1) {
return this.projection.clampToBounds(e, t);
}
}
const Pe = Symbol("TILE_X"), Re = Symbol("TILE_Y"), ve = Symbol("TILE_LEVEL"), Ir = 30, Pr = 15, si = 20, pt = Symbol("OVERLAY_RANGE"), mt = Symbol("OVERLAY_LEVEL"), We = /* @__PURE__ */ new C(), He = /* @__PURE__ */ new C(), $t = /* @__PURE__ */ new Te();
class Rr {
constructor(e = {}) {
const {
overlay: t = null,
shape: s = "ellipsoid",
endCaps: i = !0,
center: n = !0,
useRecommendedSettings: r = !0,
applyOverlayTexture: o = !1
} = e;
this.priority = -10, this.tiles = null, this.overlay = t, this.shape = s, this.endCaps = i, this.center = n, this.useRecommendedSettings = r, this.applyOverlayTexture = o, this._tiling = null;
}
// Plugin functions
init(e) {
this.useRecommendedSettings && (e.errorTarget = 1), this.tiles = e;
}
async loadRootTileset() {
const { overlay: e } = this;
return e ? (await e.init(), this._tiling = e.tiling || this._createDefaultTiling()) : this._tiling = this._createDefaultTiling(), this.getTileset();
}
async parseToMesh(e, t, s, i, n) {
if (s !== "generated_surface")
return null;
let r;
this._useEllipsoid() ? r = this._createEllipsoidMesh(t) : r = this._createPlanarMesh(t);
const { overlay: o, applyOverlayTexture: a } = this;
if (o && a) {
const l = t[Pe], c = t[Re], u = t[ve], d = this._tiling.getTileBounds(l, c, u, !0, !1);
if (o.hasContent(d, u)) {
try {
await o.lockTexture(d, u);
} catch (m) {
if (m.name !== "AbortError")
throw m;
return null;
}
const p = o.getTexture(d, u);
if (t[pt] = d, t[mt] = u, n.aborted)
return o.releaseTexture(d, u), delete t[pt], delete t[mt], null;
r.material.map = p, r.material.needsUpdate = !0;
}
}
return r;
}
preprocessNode(e) {
const s = this._tiling.maxLevel;
e[ve] < s && e.parent !== null && this.expandChildren(e);
}
disposeTile(e) {
const t = e[pt];
this.overlay && t && (this.overlay.releaseTexture(t, e[mt]), delete e[pt], delete e[mt]);
}
dispose() {
this.tiles.forEachLoadedModel((e, t) => {
this.disposeTile(t);
});
}
/**
* Returns the cartographic coordinates for a given world-space position. "lat" and "lon" are assigned
* to the target object.
* @param {Vector3} position - World-space position. For ellipsoid surfaces this is a
* 3D point on the surface; for planar surfaces it is a 2D point in the plane.
* @param {{ lat: number, lon: number }} [target={}] - Optional target object to write results into.
* @returns {{ lat: number, lon: number }} The cartographic coordinates in radians.
* @throws {Error} If the tiling projection is not cartographic.
*/
getCartographicFromPosition(e, t = {}) {
const { _tiling: s } = this, { projection: i } = s;
if (!i.isCartographic)
throw new Error("GeneratedSurfacePlugin: getCartographicFromPosition requires a cartographic projection.");
if (this._useEllipsoid())
return this.tiles.ellipsoid.getPositionToCartographic(e, t);
const { center: n } = this, r = e.x / s.aspectRatio + (n ? 0.5 : 0), o = e.y + (n ? 0.5 : 0);
return t.lat = i.convertNormalizedToLatitude(o), t.lon = i.convertNormalizedToLongitude(r), t;
}
/**
* Returns the world-space position for a given cartographic coordinate.
* @param {number} lat - Latitude in radians.
* @param {number} lon - Longitude in radians.
* @param {Vector3} [target=new Vector3()] - Optional target Vector3 to write results into.
* @returns {Vector3} The world-space position. For planar surfaces z is set to 0.
* @throws {Error} If the tiling projection is not cartographic.
*/
getPositionFromCartographic(e, t, s = new C()) {
const { _tiling: i } = this, { projection: n } = i;
if (!n.isCartographic)
throw new Error("GeneratedSurfacePlugin: getPositionFromCartographic requires a cartographic projection.");
if (this._useEllipsoid())
return this.tiles.ellipsoid.getCartographicToPosition(e, t, 0, s);
const { center: r } = this, o = n.convertLongitudeToNormalized(t), a = n.convertLatitudeToNormalized(e);
return s.x = (o - (r ? 0.5 : 0)) * i.aspectRatio, s.y = a - (r ? 0.5 : 0), s.z = 0, s;
}
// whether the plugin is loading as an ellipsoid or not
_useEllipsoid() {
return this._tiling.projection.isCartographic && this.shape === "ellipsoid";
}
_createPlanarMesh(e) {
const t = e[Pe], s = e[Re], i = e[ve], n = e.boundingVolume.box;
let r = 1, o = 1, a = 0, l = 0, c = 0;
n && ([a, l, c] = n, r = n[3], o = n[7]);
const u = new Zs(2 * r, 2 * o), d = new _e(u, new xe());
d.position.set(a, l, c);
const p = this._tiling.getTileContentUVBounds(t, s, i), { uv: m } = u.attributes;
for (let f = 0; f < m.count; f++)
m.setXY(
f,
w.mapLinear(m.getX(f), 0, 1, p[0], p[2]),
w.mapLinear(m.getY(f), 0, 1, p[1], p[3])
);
return d;
}
_createEllipsoidMesh(e) {
const { tiles: t, endCaps: s, _tiling: i } = this, { projection: n } = i, r = e[ve], o = e[Pe], a = e[Re], [l, c, u, d] = e.boundingVolume.region, p = Math.max(Pr, Math.ceil((d - c) * w.RAD2DEG * 0.25)), m = Math.max(Ir, Math.ceil((u - l) * w.RAD2DEG * 0.25)), f = m + 3, g = p + 3, y = new Zs(1, 1, m + 2, p + 2), [x, _, b, T] = i.getTileBounds(o, a, r, !0, !0), v = i.getTileContentUVBounds(o, a, r), { position: S, normal: M, uv: P } = y.attributes, E = S.count;
e.engineData.boundingVolume.getSphere($t);
for (let B = 0; B < E; B++) {
const W = B % f, q = Math.floor(B / f), K = W === 0 || W === f - 1 || q === 0 || q === g - 1, A = Math.max(1, Math.min(f - 2, W)), L = Math.max(1, Math.min(g - 2, q)), D = (A - 1) / m, R = 1 - (L - 1) / p, I = n.convertNormalizedToLongitude(w.mapLinear(D, 0, 1, x, b));
let O = n.convertNormalizedToLatitude(w.mapLinear(R, 0, 1, _, T));
if (n.isMercator && s && (T === 1 && R === 1 && (O = Math.PI / 2), _ === 0 && R === 0 && (O = -Math.PI / 2)), n.isMercator && R !== 0 && R !== 1) {
const N = n.convertNormalizedToLatitude(1), V = 1 / p, $ = w.mapLinear(R - V, 0, 1, c, d), ae = w.mapLinear(R + V, 0, 1, c, d);
O > N && $ < N && (O = N), O < -N && ae > -N && (O = -N);
}
t.ellipsoid.getCartographicToPosition(O, I, 0, We).sub($t.center), t.ellipsoid.getCartographicToNormal(O, I, He), K && We.addScaledVector(He, -e.geometricError);
const J = w.mapLinear(n.convertLongitudeToNormalized(I), x, b, v[0], v[2]), H = w.mapLinear(n.convertLatitudeToNormalized(O), _, T, v[1], v[3]);
S.setXYZ(B, We.x, We.y, We.z), M.setXYZ(B, He.x, He.y, He.z), P.setXY(B, J, H);
}
const F = new _e(y, new xe());
return F.position.copy($t.center), F;
}
getTileset() {
const { tiles: e, _tiling: t } = this, s = t.minLevel, { tileCountX: i, tileCountY: n } = t.getLevel(s), r = [];
for (let a = 0; a < i; a++)
for (let l = 0; l < n; l++) {
const c = this.createChild(a, l, s);
c !== null && r.push(c);
}
const o = {
asset: { version: "1.1" },
geometricError: 1 / 0,
root: {
refine: "REPLACE",
geometricError: 1 / 0,
boundingVolume: this.createBoundingVolume(0, 0, -1),
children: r,
[ve]: -1,
[Pe]: 0,
[Re]: 0
}
};
return e.preprocessTileset(o, ""), o;
}
getUrl() {
return "tile.generated_surface";
}
fetchData(e) {
if (/generated_surface/.test(e))
return new ArrayBuffer();
}
createBoundingVolume(e, t, s, i = 0) {
const { _tiling: n } = this, r = s === -1;
if (this._useEllipsoid()) {
const { endCaps: o } = this;
let a, l;
return r ? (a = n.getContentBounds(!0), l = n.getContentBounds()) : (a = n.getTileBounds(e, t, s, !0, !0), l = n.getTileBounds(e, t, s, !1, !0)), o && (a[3] === 1 && (l[3] = Math.PI / 2), a[1] === 0 && (l[1] = -Math.PI / 2)), { region: [...l, -i, 1] };
} else {
const { center: o } = this;
let a;
r ? a = n.getContentBounds(!0) : a = n.getTileBounds(e, t, s, !0);
const [l, c, u, d] = a;
let p = (u - l) / 2, m = (d - c) / 2, f = l + p, g = c + m;
return o && (f -= 0.5, g -= 0.5), f *= n.aspectRatio, p *= n.aspectRatio, {
box: [
// center
f,
g,
0,
// x, y, z half extents
p,
0,
0,
0,
m,
0,
0,
0,
0
]
};
}
}
createChild(e, t, s) {
const { _tiling: i } = this, { projection: n } = i;
if (!i.getTileExists(e, t, s))
return null;
let r;
const o = this._useEllipsoid();
if (o) {
const [a, l, c, u] = i.getTileBounds(e, t, s, !0), { tilePixelWidth: d, tilePixelHeight: p } = i.getLevel(s), m = (c - a) / d, f = (u - l) / p, [
/* west */
,
g,
y,
x
] = i.getTileBounds(e, t, s), _ = g > 0 != x > 0 ? 0 : Math.min(Math.abs(g), Math.abs(x)), b = n.convertLatitudeToNormalized(_), T = n.getLongitudeDerivativeAtNormalized(a), v = n.getLatitudeDerivativeAtNormalized(b), [S, M] = Er(this.tiles.ellipsoid, _, y);
r = Math.max(m * T * S, f * v * M);
} else {
const { pixelWidth: a, pixelHeight: l } = i.getLevel(s);
r = Math.max(i.aspectRatio / a, 1 / l);
}
return {
refine: "REPLACE",
geometricError: r,
boundingVolume: this.createBoundingVolume(e, t, s, o ? r : 0),
content: {
uri: this.getUrl(e, t, s)
},
children: [],
// save the tile params so we can expand later
[Pe]: e,
[Re]: t,
[ve]: s
};
}
expandChildren(e) {
const t = e[ve], s = e[Pe], i = e[Re], { tileSplitX: n, tileSplitY: r } = this._tiling.getLevel(t);
for (let o = 0; o < n; o++)
for (let a = 0; a < r; a++) {
const l = this.createChild(n * s + o, r * i + a, t + 1);
l && e.children.push(l);
}
}
_createDefaultTiling() {
const e = new Gt();
if (this.shape === "ellipsoid") {
const t = new ee("EPSG:3857");
e.setProjection(t), e.generateLevels(si, t.tileCountX, t.tileCountY);
} else {
const t = new ee("none");
e.setProjection(t), e.generateLevels(si, 1, 1);
}
return e;
}
}
class ii extends DOMException {
constructor() {
super("DataCache: Item removed", "AbortError");
}
}
function Ye(...h) {
return h.join("_");
}
class Gs {
constructor() {
this.cache = {}, this.count = 0, this.cachedBytes = 0, this.active = 0;
}
// overridable
fetchItem(e, t) {
}
// called with null if the fetch failed
disposeItem(e, t) {
}
getMemoryUsage(e) {
return 0;
}
// sets the data in the cache explicitly without need to load
setData(...e) {
const { cache: t } = this, s = e.pop(), i = Ye(...e);
if (i in t)
throw new Error(`DataCache: "${i}" is already present.`);
return this.cache[i] = {
abortController: new AbortController(),
result: s,
count: 1,
bytes: this.getMemoryUsage(s)
}, this.count++, this.cachedBytes += this.cache[i].bytes, s;
}
// fetches the associated data if it doesn't exist and increments the lock counter
lock(...e) {
const { cache: t } = this, s = Ye(...e);
if (s in t)
t[s].count++;
else {
const i = new AbortController(), n = {
abortController: i,
result: null,
count: 1,
bytes: 0,
args: e
};
this.active++, n.result = this.fetchItem(e, i.signal), n.result instanceof Promise ? n.result = n.result.then((r) => (i.signal.throwIfAborted(), n.result = r, n.bytes = this.getMemoryUsage(r), this.cachedBytes += n.bytes, r)).finally(() => {
this.active--;
}) : (this.active--, n.bytes = this.getMemoryUsage(n.result), this.cachedBytes += n.bytes), this.cache[s] = n, this.count++;
}
return t[s].result;
}
// decrements the lock counter for the item and deletes the item if it has reached zero
release(...e) {
const t = Ye(...e);
this.releaseViaFullKey(t);
}
// get the loaded item
get(...e) {
const { cache: t } = this, s = Ye(...e);
return s in t && t[s].count > 0 ? t[s].result : null;
}
has(...e) {
const { cache: t } = this;
return Ye(...e) in t;
}
forEachItem(e) {
const { cache: t } = this;
for (const s in t) {
const i = t[s];
i.result instanceof Promise || e(i.result, i.args);
}
}
// dispose all items
dispose() {
const { cache: e } = this;
for (const t in e) {
const { abortController: s } = e[t];
s.abort(new ii()), this.releaseViaFullKey(t, !0);
}
this.cache = {};
}
// releases an item with an optional force flag
releaseViaFullKey(e, t = !1) {
const { cache: s } = this;
if (e in s && s[e].count > 0) {
const i = s[e];
if (i.count--, i.count === 0 || t) {
const n = () => {
if (s[e] !== i)
return;
const { result: r, abortController: o } = i;
o.abort(new ii()), r instanceof Promise ? r.then((a) => {
this.disposeItem(a, i.args);
}).catch(() => {
this.disposeItem(null, i.args);
}).finally(() => {
this.count--, this.cachedBytes -= i.bytes;
}) : (this.disposeItem(r, i.args), this.count--, this.cachedBytes -= i.bytes), delete s[e];
};
t ? n() : queueMicrotask(() => {
i.count === 0 && n();
});
}
return !0;
}
throw new Error("DataCache: Attempting to release key that does not exist");
}
}
class Ge extends Gs {
constructor(e = {}) {
super();
const {
fetchOptions: t = {}
} = e;
this.tiling = new Gt(), this.fetchOptions = t, this.fetchData = (...s) => fetch(...s);
}
// async function for initializing the tiled image set
init() {
}
// helper for processing the buffer into a texture
async processBufferToTexture(e) {
const t = new Blob([e]), s = await createImageBitmap(t, {
premultiplyAlpha: "none",
colorSpaceConversion: "none",
imageOrientation: "flipY"
}), i = new Kn(s);
return i.generateMipmaps = !1, i.colorSpace = ct, i.needsUpdate = !0, i;
}
getMemoryUsage(e) {
const { format: t, type: s, image: i, generateMipmaps: n } = e, { width: r, height: o } = i, a = Zn.getByteLength(r, o, t, s);
return n ? a * 4 / 3 : a;
}
// fetch the item with the given key fields
fetchItem(e, t) {
const s = {
...this.fetchOptions,
signal: t
}, i = this.getUrl(...e);
return this.fetchData(i, s).then((n) => n.arrayBuffer()).then((n) => this.processBufferToTexture(n));
}
// dispose of the item that was fetched
disposeItem(e) {
e && (e.dispose(), e.image instanceof ImageBitmap && e.image.close());
}
getUrl(...e) {
}
}
class Wt extends Ge {
constructor(e = {}) {
const {
levels: t = 20,
tileDimension: s = 256,
projection: i = "EPSG:3857",
url: n = null,
...r
} = e;
super(r), this.tileDimension = s, this.levels = t, this.projection = i, this.url = n;
}
getUrl(e, t, s) {
return this.url.replace(/{\s*z\s*}/gi, s).replace(/{\s*x\s*}/gi, e).replace(/{\s*(y|reverseY|-\s*y)\s*}/gi, t);
}
init() {
const { tiling: e, tileDimension: t, levels: s, url: i, projection: n } = this;
return e.flipY = !/{\s*reverseY|-\s*y\s*}/g.test(i), e.setProjection(new ee(n)), e.setContentBounds(...e.projection.getBounds()), Array.isArray(s) ? s.forEach((r, o) => {
r !== null && e.setLevel(o, {
tilePixelWidth: t,
tilePixelHeight: t,
...r
});
}) : e.generateLevels(s, e.projection.tileCountX, e.projection.tileCountY, {
tilePixelWidth: t,
tilePixelHeight: t
}), this.url = i, Promise.resolve();
}
}
class Dr extends Wt {
constructor(e = {}) {
const {
subdomains: t = ["t0"],
...s
} = e;
super(s), this.subdomains = t, this.subDomainIndex = 0;
}
getUrl(e, t, s) {
return this.url.replace(/{\s*subdomain\s*}/gi, this._getSubdomain()).replace(/{\s*quadkey\s*}/gi, this._tileToQuadKey(e, t, s));
}
_tileToQuadKey(e, t, s) {
let i = "";
for (let n = s; n > 0; n--) {
let r = 0;
const o = 1 << n - 1;
(e & o) !== 0 && (r += 1), (t & o) !== 0 && (r += 2), i += r.toString();
}
return i;
}
_getSubdomain() {
return this.subDomainIndex = (this.subDomainIndex + 1) % this.subdomains.length, this.subdomains[this.subDomainIndex];
}
}
class Tn extends Ge {
constructor(e = {}) {
const {
url: t = null,
...s
} = e;
super(s), this.tileSets = null, this.extension = null, this.url = t;
}
getUrl(e, t, s) {
const { url: i, extension: n, tileSets: r, tiling: o } = this;
return new URL(`${parseInt(r[s - o.minLevel].href)}/${e}/${t}.${n}`, i).toString();
}
init() {
const { url: e } = this;
return this.fetchData(new URL("tilemapresource.xml", e), this.fetchOptions).then((t) => t.text()).then((t) => {
const { tiling: s } = this, i = new DOMParser().parseFromString(t, "text/xml"), n = i.querySelector("BoundingBox"), r = i.querySelector("TileFormat"), a = [...i.querySelector("TileSets").querySelectorAll("TileSet")].map((y) => ({
href: parseInt(y.getAttribute("href")),
unitsPerPixel: parseFloat(y.getAttribute("units-per-pixel")),
order: parseInt(y.getAttribute("order"))
})).sort((y, x) => y.order - x.order), l = parseFloat(n.getAttribute("minx")) * w.DEG2RAD, c = parseFloat(n.getAttribute("maxx")) * w.DEG2RAD, u = parseFloat(n.getAttribute("miny")) * w.DEG2RAD, d = parseFloat(n.getAttribute("maxy")) * w.DEG2RAD, p = parseInt(r.getAttribute("width")), m = parseInt(r.getAttribute("height")), f = r.getAttribute("extension"), g = i.querySelector("SRS").textContent;
this.extension = f, this.url = e, this.tileSets = a, s.setProjection(new ee(g)), s.setContentBounds(l, u, c, d), a.forEach(({ order: y }) => {
s.setLevel(y, {
tileCountX: s.projection.tileCountX * 2 ** y,
tilePixelWidth: p,
tilePixelHeight: m
});
});
});
}
}
function le(h, e, t, s) {
let [i, n, r, o] = h;
n += 1e-8, i += 1e-8, o -= 1e-8, r -= 1e-8;
const a = Math.max(Math.min(e, t.maxLevel), t.minLevel), [l, c, u, d] = t.getTilesInRange(i, n, r, o, a, !0);
for (let p = l; p <= u; p++)
for (let m = c; m <= d; m++)
s(p, m, a);
}
function Br(h, e, t) {
const s = new C(), i = {}, n = [], r = h.getAttribute("position");
h.computeBoundingBox(), h.boundingBox.getCenter(s).applyMatrix4(e), t.getPositionToCartographic(s, i);
const o = i.lat || 0, a = i.lon || 0;
let l = 1 / 0, c = 1 / 0, u = 1 / 0, d = -1 / 0, p = -1 / 0, m = -1 / 0;
for (let y = 0; y < r.count; y++)
s.fromBufferAttribute(r, y).applyMatrix4(e), t.getPositionToCartographic(s, i), Math.abs(Math.abs(i.lat) - Math.PI / 2) < 1e-5 && (i.lon = a), Math.abs(a - i.lon) > Math.PI && (i.lon += Math.sign(a - i.lon) * Math.PI * 2), Math.abs(o - i.lat) > Math.PI && (i.lat += Math.sign(o - i.lat) * Math.PI * 2), n.push(i.lon, i.lat, i.height), l = Math.min(l, i.lat), d = Math.max(d, i.lat), c = Math.min(c, i.lon), p = Math.max(p, i.lon), u = Math.min(u, i.height), m = Math.max(m, i.height);
const f = [c, l, p, d], g = [...f, u, m];
return {
uv: n,
range: f,
region: g
};
}
function Ls(h, e, t = null, s = null, i = null) {
let n = 1 / 0, r = 1 / 0, o = 1 / 0, a = -1 / 0, l = -1 / 0, c = -1 / 0;
const u = [], d = new Y();
if (h.forEach((p) => {
d.copy(p.matrixWorld), t && d.premultiply(t);
const { uv: m, region: f } = Br(p.geometry, d, e);
u.push(m), n = Math.min(n, f[1]), a = Math.max(a, f[3]), r = Math.min(r, f[0]), l = Math.max(l, f[2]), o = Math.min(o, f[4]), c = Math.max(c, f[5]);
}), s !== null) {
i === null && (i = s.clampToBounds([r, n, l, a]), i = s.toNormalizedRange(i));
const [p, m, f, g] = i;
u.forEach((y) => {
for (let x = 0, _ = y.length; x < _; x += 3) {
const b = y[x + 0], T = y[x + 1], v = y[x + 2];
let [S, M] = s.toNormalizedPoint(b, T);
S = w.clamp(S, 0, 1), M = w.clamp(M, 0, 1), y[x + 0] = w.mapLinear(S, p, f, 0, 1), y[x + 1] = w.mapLinear(M, m, g, 0, 1), y[x + 2] = w.mapLinear(v, o, c, 0, 1);
}
});
}
return {
uvs: u,
range: i,
region: [r, n, l, a, o, c]
};
}
function Ur(h, e) {
const t = new C(), s = [], i = h.getAttribute("position");
let n = 1 / 0, r = 1 / 0, o = 1 / 0, a = -1 / 0, l = -1 / 0, c = -1 / 0;
for (let d = 0; d < i.count; d++)
t.fromBufferAttribute(i, d).applyMatrix4(e), s.push(t.x, t.y, t.z), n = Math.min(n, t.x), a = Math.max(a, t.x), r = Math.min(r, t.y), l = Math.max(l, t.y), o = Math.min(o, t.z), c = Math.max(c, t.z);
return {
uv: s,
range: [n, r, a, l],
heightRange: [o, c]
};
}
function Or(h, e) {
let t = 1 / 0, s = 1 / 0, i = 1 / 0, n = -1 / 0, r = -1 / 0, o = -1 / 0;
const a = [], l = new Y();
return h.forEach((c) => {
l.copy(c.matrixWorld), e && l.premultiply(e);
const { uv: u, range: d, heightRange: p } = Ur(c.geometry, l);
a.push(u), t = Math.min(t, d[0]), n = Math.max(n, d[2]), s = Math.min(s, d[1]), r = Math.max(r, d[3]), i = Math.min(i, p[0]), o = Math.max(o, p[1]);
}), a.forEach((c) => {
for (let u = 0, d = c.length; u < d; u += 3) {
const p = c[u + 0], m = c[u + 1];
c[u + 0] = w.mapLinear(p, t, n, 0, 1), c[u + 1] = w.mapLinear(m, s, r, 0, 1);
}
}), {
uvs: a,
range: [t, s, n, r],
heightRange: [i, o]
};
}
const Qt = Symbol("OVERLAY_PARAMS");
function Vr(h, e) {
if (h[Qt])
return h[Qt];
const t = {
layerMaps: { value: [] },
layerInfo: { value: [] }
};
return h[Qt] = t, h.defines = {
...h.defines || {},
LAYER_COUNT: 0
}, h.onBeforeCompile = (s) => {
e && e(s), s.uniforms = {
...s.uniforms,
...t
}, s.vertexShader = s.vertexShader.replace(/void main\(\s*\)\s*{/, (i) => (
/* glsl */
`
#pragma unroll_loop_start
for ( int i = 0; i < 10; i ++ ) {
#if UNROLLED_LOOP_INDEX < LAYER_COUNT
attribute vec3 layer_uv_UNROLLED_LOOP_INDEX;
varying vec3 v_layer_uv_UNROLLED_LOOP_INDEX;
#endif
}
#pragma unroll_loop_end
${i}
#pragma unroll_loop_start
for ( int i = 0; i < 10; i ++ ) {
#if UNROLLED_LOOP_INDEX < LAYER_COUNT
v_layer_uv_UNROLLED_LOOP_INDEX = layer_uv_UNROLLED_LOOP_INDEX;
#endif
}
#pragma unroll_loop_end
`
)), s.fragmentShader = s.fragmentShader.replace(/void main\(/, (i) => (
/* glsl */
`
#if LAYER_COUNT != 0
struct LayerInfo {
vec3 color;
float opacity;
int alphaMask;
int alphaInvert;
};
uniform sampler2D layerMaps[ LAYER_COUNT ];
uniform LayerInfo layerInfo[ LAYER_COUNT ];
#endif
#pragma unroll_loop_start
for ( int i = 0; i < 10; i ++ ) {
#if UNROLLED_LOOP_INDEX < LAYER_COUNT
varying vec3 v_layer_uv_UNROLLED_LOOP_INDEX;
#endif
}
#pragma unroll_loop_end
${i}
`
)).replace(/#include <color_fragment>/, (i) => (
/* glsl */
`
${i}
#if LAYER_COUNT != 0
{
vec4 tint;
vec3 layerUV;
float layerOpacity;
float wOpacity;
float wDelta;
#pragma unroll_loop_start
for ( int i = 0; i < 10; i ++ ) {
#if UNROLLED_LOOP_INDEX < LAYER_COUNT
layerUV = v_layer_uv_UNROLLED_LOOP_INDEX;
tint = texture( layerMaps[ i ], layerUV.xy );
// discard texture outside 0, 1 on w - offset the stepped value by an epsilon to avoid cases
// where wDelta is near 0 (eg a flat surface) at the w boundary, resulting in artifacts on some
// hardware.
wDelta = max( fwidth( layerUV.z ), 1e-7 );
wOpacity =
smoothstep( - wDelta, 0.0, layerUV.z ) *
smoothstep( 1.0 + wDelta, 1.0, layerUV.z );
// apply tint & opacity
tint.rgb *= layerInfo[ i ].color;
tint.rgba *= layerInfo[ i ].opacity * wOpacity;
// invert the alpha
if ( layerInfo[ i ].alphaInvert > 0 ) {
tint.a = 1.0 - tint.a;
}
// apply the alpha across all existing layers if alpha mask is true
if ( layerInfo[ i ].alphaMask > 0 ) {
diffuseColor.a *= tint.a;
} else {
tint.rgb *= tint.a;
diffuseColor = tint + diffuseColor * ( 1.0 - tint.a );
}
#endif
}
#pragma unroll_loop_end
}
#endif
`
));
}, t;
}
const X = 0, pe = ["a", "b", "c"], U = /* @__PURE__ */ new be(), ni = /* @__PURE__ */ new be(), ri = /* @__PURE__ */ new be(), oi = /* @__PURE__ */ new be();
class bn {
constructor() {
this.attributeList = null, this.splitOperations = [], this.trianglePool = new kr();
}
forEachSplitPermutation(e) {
const { splitOperations: t } = this, s = (i = 0) => {
if (i >= t.length) {
e();
return;
}
t[i].keepPositive = !0, s(i + 1), t[i].keepPositive = !1, s(i + 1);
};
s();
}
// Takes an operation that returns a value for the given vertex passed to the callback. Triangles
// are clipped along edges where the interpolated value is equal to 0. The polygons on the positive
// side of the operation are kept if "keepPositive" is true.
// callback( geometry, i0, i1, i2, barycoord );
addSplitOperation(e, t = !0) {
this.splitOperations.push({
callback: e,
keepPositive: t
});
}
// Removes all split operations
clearSplitOperations() {
this.splitOperations.length = 0;
}
// clips an object hierarchy
clipObject(e) {
const t = e.clone(), s = [];
return t.traverse((i) => {
i.isMesh && (i.geometry = this.clip(i).geometry, (i.geometry.index ? i.geometry.index.count / 3 : i.attributes.position.count / 3) === 0 && s.push(i));
}), s.forEach((i) => {
i.removeFromParent();
}), t;
}
// Returns a new mesh that has been clipped by the split operations. Range indicates the range of
// elements to include when clipping.
clip(e, t = null) {
const s = this.getClippedData(e, t);
return this.constructMesh(s.attributes, s.index, e);
}
// Appends the clip operation data to the given "target" object so multiple ranges can be appended.
// The "target" object is returned with an "index" field, "vertexIsClipped" field, and series of arrays
// in "attributes".
// attributes - set of attribute arrays
// index - triangle indices referencing vertices in attributes
// vertexIsClipped - array indicating whether a vertex is on a clipped edge
getClippedData(e, t = null, s = {}) {
const { trianglePool: i, splitOperations: n, attributeList: r } = this, o = e.geometry, a = o.attributes.position, l = o.index;
let c = 0;
const u = {};
s.index = s.index || [], s.vertexIsClipped = s.vertexIsClipped || [], s.attributes = s.attributes || {};
for (const f in o.attributes) {
if (r !== null) {
if (r instanceof Function && !r(f))
continue;
if (Array.isArray(r) && !r.includes(f))
continue;
}
s.attributes[f] = [];
}
let d = 0, p = l ? l.count : a.count;
t !== null && (d = t.start, p = t.count);
for (let f = d, g = d + p; f < g; f += 3) {
let y = f + 0, x = f + 1, _ = f + 2;
l && (y = l.getX(y), x = l.getX(x), _ = l.getX(_));
const b = i.get();
b.initFromIndices(y, x, _);
let T = [b];
for (let v = 0; v < n.length; v++) {
const { keepPositive: S, callback: M } = n[v], P = [];
for (let E = 0; E < T.length; E++) {
const F = T[E], { indices: B, barycoord: W } = F;
F.clipValues.a = M(o, B.a, B.b, B.c, W.a, e.matrixWorld), F.clipValues.b = M(o, B.a, B.b, B.c, W.b, e.matrixWorld), F.clipValues.c = M(o, B.a, B.b, B.c, W.c, e.matrixWorld), this.splitTriangle(F, !S, P);
}
T = P;
}
for (let v = 0, S = T.length; v < S; v++) {
const M = T[v];
m(M, o);
}
i.reset();
}
return s;
function m(f, g) {
for (let y = 0; y < 3; y++) {
const x = f.getVertexHash(y, g);
x in u || (u[x] = c, c++, f.getVertexData(y, g, s.attributes), s.vertexIsClipped.push(f.clipValues[pe[y]] === X));
const _ = u[x];
s.index.push(_);
}
}
}
// Takes the set of resultant data and constructs a mesh
constructMesh(e, t, s) {
const i = s.geometry, n = new Fe(), r = e.position.length / 3 > 65535 ? new Uint32Array(t) : new Uint16Array(t);
n.setIndex(new G(r, 1, !1));
for (const a in e) {
const l = i.getAttribute(a), c = new l.array.constructor(e[a]), u = new G(c, l.itemSize, l.normalized);
u.gpuType = l.gpuType, n.setAttribute(a, u);
}
const o = new _e(n, s.material.clone());
return o.position.copy(s.position), o.quaternion.copy(s.quaternion), o.scale.copy(s.scale), o;
}
// Splits the given triangle
splitTriangle(e, t, s) {
const { trianglePool: i } = this, n = [], r = [], o = [];
for (let a = 0; a < 3; a++) {
const l = pe[a], c = pe[(a + 1) % 3], u = e.clipValues[l], d = e.clipValues[c];
(u < X != d < X || u === X) && (n.push(a), r.push([l, c]), u === d ? o.push(0) : o.push(w.mapLinear(X, u, d, 0, 1)));
}
if (n.length !== 2)
Math.min(
e.clipValues.a,
e.clipValues.b,
e.clipValues.c
) < X === t && s.push(e);
else if (n.length === 2) {
const a = i.get().initFromTriangle(e), l = i.get().initFromTriangle(e), c = i.get().initFromTriangle(e);
(n[0] + 1) % 3 === n[1] ? (a.lerpVertexFromEdge(e, r[0][0], r[0][1], o[0], "a"), a.copyVertex(e, r[0][1], "b"), a.lerpVertexFromEdge(e, r[1][0], r[1][1], o[1], "c"), a.clipValues.a = X, a.clipValues.c = X, l.lerpVertexFromEdge(e, r[0][0], r[0][1], o[0], "a"), l.copyVertex(e, r[1][1], "b"), l.copyVertex(e, r[0][0], "c"), l.clipValues.a = X, c.lerpVertexFromEdge(e, r[0][0], r[0][1], o[0], "a"), c.lerpVertexFromEdge(e, r[1][0], r[1][1], o[1], "b"), c.copyVertex(e, r[1][1], "c"), c.clipValues.a = X, c.clipValues.b = X) : (a.lerpVertexFromEdge(e, r[0][0], r[0][1], o[0], "a"), a.lerpVertexFromEdge(e, r[1][0], r[1][1], o[1], "b"), a.copyVertex(e, r[0][0], "c"), a.clipValues.a = X, a.clipValues.b = X, l.lerpVertexFromEdge(e, r[0][0], r[0][1], o[0], "a"), l.copyVertex(e, r[0][1], "b"), l.lerpVertexFromEdge(e, r[1][0], r[1][1], o[1], "c"), l.clipValues.a = X, l.clipValues.c = X, c.copyVertex(e, r[0][1], "a"), c.copyVertex(e, r[1][0], "b"), c.lerpVertexFromEdge(e, r[1][0], r[1][1], o[1], "c"), c.clipValues.c = X);
let d, p;
d = Math.min(a.clipValues.a, a.clipValues.b, a.clipValues.c), p = d < X, p === t && s.push(a), d = Math.min(l.clipValues.a, l.clipValues.b, l.clipValues.c), p = d < X, p === t && s.push(l), d = Math.min(c.clipValues.a, c.clipValues.b, c.clipValues.c), p = d < X, p === t && s.push(c);
}
}
}
class kr {
constructor() {
this.pool = [], this.index = 0;
}
get() {
if (this.index >= this.pool.length) {
const t = new Nr();
this.pool.push(t);
}
const e = this.pool[this.index];
return this.index++, e;
}
reset() {
this.index = 0;
}
}
class Nr {
constructor() {
this.indices = {
a: -1,
b: -1,
c: -1
}, this.clipValues = {
a: -1,
b: -1,
c: -1
}, this.barycoord = new Os();
}
// returns a hash for the given [0, 2] index based on attributes of the referenced geometry
getVertexHash(e, t) {
const { barycoord: s, indices: i } = this, n = pe[e], r = s[n];
if (r.x === 1)
return i[pe[0]];
if (r.y === 1)
return i[pe[1]];
if (r.z === 1)
return i[pe[2]];
{
const { attributes: o } = t;
let a = "";
for (const l in o) {
const c = o[l];
switch (ai(c, i.a, i.b, i.c, r, U), (l === "normal" || l === "tangent" || l === "bitangent") && U.normalize(), c.itemSize) {
case 4:
a += it(U.x, U.y, U.z, U.w);
break;
case 3:
a += it(U.x, U.y, U.z);
break;
case 2:
a += it(U.x, U.y);
break;
case 1:
a += it(U.x);
break;
}
a += "|";
}
return a;
}
}
// Accumulate the vertex data in the given attribute arrays
getVertexData(e, t, s) {
const { barycoord: i, indices: n } = this, r = pe[e], o = i[r], { attributes: a } = t;
for (const l in a) {
if (!s[l])
continue;
const c = a[l], u = s[l];
switch (ai(c, n.a, n.b, n.c, o, U), (l === "normal" || l === "tangent" || l === "bitangent") && U.normalize(), c.itemSize) {
case 4:
u.push(U.x, U.y, U.z, U.w);
break;
case 3:
u.push(U.x, U.y, U.z);
break;
case 2:
u.push(U.x, U.y);
break;
case 1:
u.push(U.x);
break;
}
}
}
// Copy the indices from a target triangle
initFromTriangle(e) {
return this.initFromIndices(
e.indices.a,
e.indices.b,
e.indices.c
);
}
// Set the indices for the given
initFromIndices(e, t, s) {
return this.indices.a = e, this.indices.b = t, this.indices.c = s, this.clipValues.a = -1, this.clipValues.b = -1, this.clipValues.c = -1, this.barycoord.a.set(1, 0, 0), this.barycoord.b.set(0, 1, 0), this.barycoord.c.set(0, 0, 1), this;
}
// Lerp the given vertex along to the provided edge of the provided triangle
lerpVertexFromEdge(e, t, s, i, n) {
this.clipValues[n] = w.lerp(e.clipValues[t], e.clipValues[s], i), this.barycoord[n].lerpVectors(e.barycoord[t], e.barycoord[s], i);
}
// Copy a vertex from the provided triangle
copyVertex(e, t, s) {
this.clipValues[s] = e.clipValues[t], this.barycoord[s].copy(e.barycoord[t]);
}
}
function ai(h, e, t, s, i, n) {
switch (ni.fromBufferAttribute(h, e), ri.fromBufferAttribute(h, t), oi.fromBufferAttribute(h, s), n.set(0, 0, 0, 0).addScaledVector(ni, i.x).addScaledVector(ri, i.y).addScaledVector(oi, i.z), h.itemSize) {
case 3:
U.w = 0;
break;
case 2:
U.w = 0, U.z = 0;
break;
case 1:
U.w = 0, U.z = 0, U.y = 0;
break;
}
return n;
}
function it(...h) {
let s = "";
for (let i = 0, n = h.length; i < n; i++)
s += ~~(h[i] * 1e5 + 0.5), i !== n - 1 && (s += "_");
return s;
}
class Fr extends Ge {
/**
* @param {WMTSImageSourceOptions} options - Configuration options.
*/
constructor(e = {}) {
const {
layer: t = null,
tileMatrixSet: s = "default",
style: i = "default",
url: n = null,
format: r = "image/jpeg",
dimensions: o = null,
tileMatrixLabels: a = null,
tileMatrices: l = null,
projection: c = null,
levels: u = 20,
tileDimension: d = 256,
contentBoundingBox: p = null,
...m
} = e;
super(m), this.layer = t, this.tileMatrixSet = s, this.style = i, this.url = n, this.format = r, this.dimensions = o, this.tileMatrixLabels = a, this.tileMatrices = l, this.projection = c, this.levels = u, this.tileDimension = d, this.contentBoundingBox = p, this._useKvp = !1;
}
/**
* Detects whether the URL uses KVP or RESTful mode.
* If the URL contains no template variables, it is considered a KVP endpoint.
*/
_detectRequestMode(e) {
return !/\{/.test(e);
}
init() {
const {
tiling: e,
tileDimension: t,
levels: s,
dimensions: i,
contentBoundingBox: n,
tileMatrices: r,
style: o,
tileMatrixSet: a
} = this;
let { url: l } = this;
const c = this.projection || "EPSG:3857";
if (e.flipY = !0, e.setProjection(new ee(c)), n !== null ? e.setContentBounds(
n[0],
n[1],
n[2],
n[3]
) : e.setContentBounds(...e.projection.getBounds()), Array.isArray(r) ? r.forEach((u, d) => {
const p = u.tileWidth || t, m = u.tileHeight || t;
e.setLevel(d, {
tilePixelWidth: p,
tilePixelHeight: m,
tileCountX: u.matrixWidth,
tileCountY: u.matrixHeight,
tileBounds: u.tileBounds || u.bounds
});
}) : e.generateLevels(
s,
e.projection.tileCountX,
e.projection.tileCountY,
{
tilePixelWidth: t,
tilePixelHeight: t
}
), this._useKvp = this._detectRequestMode(l), !this._useKvp && (l = l.replace(/{\s*TileMatrixSet\s*}/gi, a).replace(/{\s*Style\s*}/gi, o), i))
for (const u in i)
l = l.replace(new RegExp(`{\\s*${u}\\s*}`, "gi"), i[u]);
return this.url = l, Promise.resolve();
}
getUrl(e, t, s) {
const { tileMatrices: i, tileMatrixLabels: n } = this;
let r;
return i !== null && i.length > 0 ? r = i[s].identifier : n ? r = n[s] : r = s.toString(), this._useKvp ? this._buildKvpUrl(e, t, r) : this._buildRestfulUrl(e, t, r);
}
_buildRestfulUrl(e, t, s) {
return this.url.replace(/{\s*TileMatrix\s*}/gi, s).replace(/{\s*TileCol\s*}/gi, e).replace(/{\s*TileRow\s*}/gi, t);
}
_buildKvpUrl(e, t, s) {
const { dimensions: i, format: n } = this, r = this.url, o = new URLSearchParams({
SERVICE: "WMTS",
VERSION: "1.0.0",
REQUEST: "GetTile",
LAYER: this.layer,
STYLE: this.style,
TILEMATRIXSET: this.tileMatrixSet,
TILEMATRIX: s,
TILEROW: t,
TILECOL: e,
FORMAT: n
});
if (i)
for (const l in i)
o.set(l, i[l]);
const a = r.includes("?") ? "&" : "?";
return r + a + o.toString();
}
}
class vn {
constructor() {
this.canvas = null, this.context = null, this.range = [0, 0, 1, 1];
}
// set the target render texture and the range that represents the full span
setTarget(e, t) {
this.canvas = e.image, this.context = e.image.getContext("2d"), this.range = [...t];
}
// draw the given texture at the given span with the provided projection
draw(e, t) {
const { canvas: s, range: i, context: n } = this, { width: r, height: o } = s, { image: a } = e, l = Math.round(w.mapLinear(t[0], i[0], i[2], 0, r)), c = Math.round(w.mapLinear(t[1], i[1], i[3], 0, o)), u = Math.round(w.mapLinear(t[2], i[0], i[2], 0