@math.gl/geospatial 5.0.0-alpha.11 → 5.0.0-alpha.13
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.
- package/LICENSE +7 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +4 -2
- package/dist/constants.js.map +1 -1
- package/dist/ellipsoid-helpers/ellipsoid-transform.d.ts.map +1 -1
- package/dist/ellipsoid-helpers/ellipsoid-transform.js +46 -15
- package/dist/ellipsoid-helpers/ellipsoid-transform.js.map +1 -1
- package/dist/ellipsoid-helpers/scale-to-geodetic-surface.d.ts +2 -0
- package/dist/ellipsoid-helpers/scale-to-geodetic-surface.d.ts.map +1 -1
- package/dist/ellipsoid-helpers/scale-to-geodetic-surface.js +46 -13
- package/dist/ellipsoid-helpers/scale-to-geodetic-surface.js.map +1 -1
- package/dist/ellipsoid-occluder.d.ts +28 -0
- package/dist/ellipsoid-occluder.d.ts.map +1 -0
- package/dist/ellipsoid-occluder.js +112 -0
- package/dist/ellipsoid-occluder.js.map +1 -0
- package/dist/ellipsoid-tangent-plane.d.ts.map +1 -1
- package/dist/ellipsoid-tangent-plane.js +4 -2
- package/dist/ellipsoid-tangent-plane.js.map +1 -1
- package/dist/ellipsoid.d.ts +11 -0
- package/dist/ellipsoid.d.ts.map +1 -1
- package/dist/ellipsoid.js +77 -7
- package/dist/ellipsoid.js.map +1 -1
- package/dist/geographic-tiles.d.ts +24 -0
- package/dist/geographic-tiles.d.ts.map +1 -0
- package/dist/geographic-tiles.js +72 -0
- package/dist/geographic-tiles.js.map +1 -0
- package/dist/globe-horizon-bounds.d.ts +13 -0
- package/dist/globe-horizon-bounds.d.ts.map +1 -0
- package/dist/globe-horizon-bounds.js +59 -0
- package/dist/globe-horizon-bounds.js.map +1 -0
- package/dist/index.cjs +557 -40
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lng-lat-rectangle.d.ts.map +1 -1
- package/dist/lng-lat-rectangle.js +4 -2
- package/dist/lng-lat-rectangle.js.map +1 -1
- package/dist/make-obb-from-region.d.ts.map +1 -1
- package/dist/make-obb-from-region.js +4 -2
- package/dist/make-obb-from-region.js.map +1 -1
- package/dist/type-utils.d.ts +2 -0
- package/dist/type-utils.d.ts.map +1 -1
- package/dist/type-utils.js +25 -2
- package/dist/type-utils.js.map +1 -1
- package/package.json +5 -5
- package/src/constants.ts +4 -2
- package/src/ellipsoid-helpers/ellipsoid-transform.ts +62 -15
- package/src/ellipsoid-helpers/scale-to-geodetic-surface.ts +48 -14
- package/src/ellipsoid-occluder.ts +135 -0
- package/src/ellipsoid-tangent-plane.ts +4 -2
- package/src/ellipsoid.ts +91 -7
- package/src/geographic-tiles.ts +87 -0
- package/src/globe-horizon-bounds.ts +68 -0
- package/src/index.ts +15 -1
- package/src/lng-lat-rectangle.ts +4 -2
- package/src/make-obb-from-region.ts +4 -2
- package/src/type-utils.ts +30 -2
package/dist/index.cjs
CHANGED
|
@@ -20,16 +20,161 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var index_exports = {};
|
|
21
21
|
__export(index_exports, {
|
|
22
22
|
Ellipsoid: () => Ellipsoid,
|
|
23
|
+
EllipsoidOccluder: () => EllipsoidOccluder,
|
|
23
24
|
EllipsoidTangentPlane: () => EllipsoidTangentPlane,
|
|
24
25
|
LngLatRectangle: () => LngLatRectangle,
|
|
26
|
+
getGeographicTile: () => getGeographicTile,
|
|
27
|
+
getGeographicTileBounds: () => getGeographicTileBounds,
|
|
28
|
+
getGeographicTileRanges: () => getGeographicTileRanges,
|
|
29
|
+
getGlobeHorizonBounds: () => getGlobeHorizonBounds,
|
|
25
30
|
isWGS84: () => isWGS84,
|
|
26
|
-
makeOBBFromRegion: () => makeOBBFromRegion
|
|
31
|
+
makeOBBFromRegion: () => makeOBBFromRegion,
|
|
32
|
+
splitGlobeBounds: () => splitGlobeBounds
|
|
27
33
|
});
|
|
28
34
|
module.exports = __toCommonJS(index_exports);
|
|
29
35
|
|
|
30
36
|
// dist/ellipsoid.js
|
|
31
37
|
var import_core4 = require("@math.gl/core");
|
|
32
38
|
|
|
39
|
+
// ../core/src/spheroid.ts
|
|
40
|
+
function spheroidToCartesian(point, geometry, result = point) {
|
|
41
|
+
const longitude = point.x, latitude = point.y, height = point.z;
|
|
42
|
+
const { semiMajorAxis: a, semiMinorAxis: b, eccentricitySquared: es } = geometry;
|
|
43
|
+
const sin = Math.sin(latitude), cos = Math.cos(latitude);
|
|
44
|
+
const ratio = b / a;
|
|
45
|
+
const radius = es < 0.9 ? a / Math.sqrt(1 - es * sin * sin) : a / Math.hypot(cos, ratio * sin);
|
|
46
|
+
const x = (radius + height) * cos * Math.cos(longitude);
|
|
47
|
+
const y = (radius + height) * cos * Math.sin(longitude);
|
|
48
|
+
const z = (radius * (es < 0.9 ? 1 - es : ratio * ratio) + height) * sin;
|
|
49
|
+
return commit(result, x, y, z);
|
|
50
|
+
}
|
|
51
|
+
function cartesianToSpheroid(point, geometry, result = point) {
|
|
52
|
+
const x = point.x, y = point.y, z = point.z;
|
|
53
|
+
const { semiMajorAxis: a, semiMinorAxis: b, eccentricitySquared: es } = geometry;
|
|
54
|
+
const p = Math.hypot(x, y), rr = Math.hypot(x, y, z);
|
|
55
|
+
if (!(rr > 0) || !Number.isFinite(rr)) return false;
|
|
56
|
+
if (es === 0) return commit(result, p === 0 ? 0 : Math.atan2(y, x), Math.atan2(z, p), rr - a);
|
|
57
|
+
if (p === 0) return commit(result, 0, Math.sign(z) * Math.PI / 2, Math.abs(z) - b);
|
|
58
|
+
const horizontal = p / a, vertical = z / b;
|
|
59
|
+
if (horizontal * horizontal + vertical * vertical < 1 - 16 * Number.EPSILON)
|
|
60
|
+
return interiorInverse(x, y, z, p, a, b, result);
|
|
61
|
+
if (es >= 0.9) return exteriorInverse(x, y, z, p, a, b, result);
|
|
62
|
+
const ct = z / rr, st = p / rr;
|
|
63
|
+
let rx = 1 / Math.sqrt(1 - es * (2 - es) * st * st);
|
|
64
|
+
let cos = st * (1 - es) * rx, sin = ct * rx;
|
|
65
|
+
for (let i = 0; i < 30; i++) {
|
|
66
|
+
const rn = a / Math.sqrt(1 - es * sin * sin);
|
|
67
|
+
const height = p * cos + z * sin - rn * (1 - es * sin * sin);
|
|
68
|
+
const rk = es * rn / (rn + height);
|
|
69
|
+
rx = 1 / Math.sqrt(1 - rk * (2 - rk) * st * st);
|
|
70
|
+
const nextCos = st * (1 - rk) * rx, nextSin = ct * rx;
|
|
71
|
+
if (Math.abs(nextSin * cos - nextCos * sin) <= 1e-12) {
|
|
72
|
+
if (!Number.isFinite(height) || !Number.isFinite(nextSin) || !Number.isFinite(nextCos)) break;
|
|
73
|
+
return commit(result, Math.atan2(y, x), Math.atan2(nextSin, Math.abs(nextCos)), height);
|
|
74
|
+
}
|
|
75
|
+
cos = nextCos;
|
|
76
|
+
sin = nextSin;
|
|
77
|
+
}
|
|
78
|
+
return exteriorInverse(x, y, z, p, a, b, result);
|
|
79
|
+
}
|
|
80
|
+
function interiorInverse(x, y, z, p, a, b, result) {
|
|
81
|
+
const ratio = b / a, ratio2 = ratio * ratio;
|
|
82
|
+
const horizontal = p / a, vertical = z / a, delta = 1 - ratio2;
|
|
83
|
+
if (!(ratio2 > 0) || ratio > 1) return false;
|
|
84
|
+
if (z === 0) {
|
|
85
|
+
if (horizontal < delta) return false;
|
|
86
|
+
return commit(result, Math.atan2(y, x), 0, p - a);
|
|
87
|
+
}
|
|
88
|
+
const aa = a * a, bb = b * b;
|
|
89
|
+
const ratioError = Number.isFinite(aa) && aa > 0 ? (bb - ratio2 * aa + productError(b, b, bb) - ratio2 * productError(a, a, aa) - productError(ratio2, aa, ratio2 * aa)) / aa : 0;
|
|
90
|
+
const pp = p * p, xx = x * x, yy = y * y, sum = xx + yy;
|
|
91
|
+
const radiusError = Number.isFinite(pp) && pp > 0 ? (sum - pp + sumError(xx, yy, sum) + productError(x, x, xx) + productError(y, y, yy) - productError(p, p, pp)) / (2 * p) : 0;
|
|
92
|
+
const shift = a * ratio2, base = p - a + shift;
|
|
93
|
+
const correction = radiusError + sumError(p - a, shift, base) + productError(a, ratio2, shift) + a * ratioError;
|
|
94
|
+
const weighted = Math.abs(vertical) * ratio;
|
|
95
|
+
if (!(weighted > 0)) return false;
|
|
96
|
+
let lower = 0, upper = ratio2;
|
|
97
|
+
let t = Math.max(weighted, horizontal - delta);
|
|
98
|
+
if (!(t > lower && t < upper)) t = upper / 2;
|
|
99
|
+
for (let i = 0; i < 128; i++) {
|
|
100
|
+
const equatorial = delta + t;
|
|
101
|
+
const u = horizontal / equatorial, v = weighted / t;
|
|
102
|
+
const at = a * t, difference = base - at;
|
|
103
|
+
const offset = (difference + (sumError(base, -at, difference) + correction - productError(a, t, at))) / (a * equatorial);
|
|
104
|
+
const term = offset * (u + 1);
|
|
105
|
+
const residual = term + v * v;
|
|
106
|
+
if (Math.abs(residual) <= 4 * Number.EPSILON * (Math.abs(term) + v * v) || upper - lower <= 4 * Number.EPSILON * t) {
|
|
107
|
+
const latitude = Math.atan2(vertical / t, horizontal / equatorial);
|
|
108
|
+
const sin = Math.sin(latitude), cos = Math.cos(latitude);
|
|
109
|
+
return commit(
|
|
110
|
+
result,
|
|
111
|
+
Math.atan2(y, x),
|
|
112
|
+
latitude,
|
|
113
|
+
p * cos + z * sin - a * Math.hypot(cos, ratio * sin)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (residual > 0) lower = t;
|
|
117
|
+
else upper = t;
|
|
118
|
+
const derivative = -2 * (u * u / equatorial + v * v / t);
|
|
119
|
+
const next = t - residual / derivative;
|
|
120
|
+
const candidate = Number.isFinite(next) && next > lower && next < upper ? next : lower + (upper - lower) / 2;
|
|
121
|
+
if (candidate === t) {
|
|
122
|
+
const latitude = Math.atan2(vertical / t, horizontal / equatorial);
|
|
123
|
+
return commit(
|
|
124
|
+
result,
|
|
125
|
+
Math.atan2(y, x),
|
|
126
|
+
latitude,
|
|
127
|
+
p * Math.cos(latitude) + z * Math.sin(latitude) - a * Math.hypot(Math.cos(latitude), ratio * Math.sin(latitude))
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
t = candidate;
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
function sumError(x, y, sum) {
|
|
135
|
+
const part = sum - x;
|
|
136
|
+
return x - (sum - part) + (y - part);
|
|
137
|
+
}
|
|
138
|
+
function productError(x, y, product) {
|
|
139
|
+
const sx = 134217729 * x, sy = 134217729 * y;
|
|
140
|
+
if (!Number.isFinite(sx) || !Number.isFinite(sy)) return 0;
|
|
141
|
+
const hx = sx - (sx - x), hy = sy - (sy - y), lx = x - hx, ly = y - hy;
|
|
142
|
+
return hx * hy - product + hx * ly + lx * hy + lx * ly;
|
|
143
|
+
}
|
|
144
|
+
function exteriorInverse(x, y, z, p, a, b, result) {
|
|
145
|
+
const ratio = b / a, ratio2 = ratio * ratio, horizontal = p / a, vertical = z / a;
|
|
146
|
+
const norm = Math.hypot(horizontal, z / b);
|
|
147
|
+
if (!Number.isFinite(norm) || norm < 1 - 8 * Number.EPSILON || !(ratio2 > 0)) return false;
|
|
148
|
+
let lower = 0, upper = Math.hypot(horizontal, vertical * ratio);
|
|
149
|
+
if (!Number.isFinite(upper)) return false;
|
|
150
|
+
let multiplier = norm <= 1 + 8 * Number.EPSILON ? 0 : upper / 2;
|
|
151
|
+
for (let i = 0; i < 96; i++) {
|
|
152
|
+
const equatorial = 1 + multiplier, polar = ratio2 + multiplier;
|
|
153
|
+
const u = horizontal / equatorial, v = vertical * ratio / polar;
|
|
154
|
+
const length2 = Math.hypot(u, v);
|
|
155
|
+
const residual = length2 - 1;
|
|
156
|
+
if (Math.abs(residual) <= 4 * Number.EPSILON) {
|
|
157
|
+
const latitude = Math.atan2(vertical / polar, horizontal / equatorial);
|
|
158
|
+
const sin = Math.sin(latitude), cos = Math.cos(latitude);
|
|
159
|
+
const height = p * cos + z * sin - a * Math.hypot(cos, ratio * sin);
|
|
160
|
+
return commit(result, Math.atan2(y, x), latitude, height);
|
|
161
|
+
}
|
|
162
|
+
if (residual > 0) lower = multiplier;
|
|
163
|
+
else upper = multiplier;
|
|
164
|
+
const derivative = -(u * u / equatorial + v * v / polar) / length2;
|
|
165
|
+
const next = multiplier - residual / derivative;
|
|
166
|
+
multiplier = Number.isFinite(next) && next > lower && next < upper ? next : (lower + upper) / 2;
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
function commit(result, x, y, z) {
|
|
171
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) return false;
|
|
172
|
+
result.x = x;
|
|
173
|
+
result.y = y;
|
|
174
|
+
result.z = z;
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
|
|
33
178
|
// ../core/src/gl-matrix/vec3.ts
|
|
34
179
|
function length(a) {
|
|
35
180
|
const x = a[0];
|
|
@@ -88,25 +233,24 @@ function fromCartographic(cartographic, result = [], map = identity) {
|
|
|
88
233
|
function fromCartographicToRadians(cartographic, vector = []) {
|
|
89
234
|
return fromCartographic(cartographic, vector, import_core.config._cartographicRadians ? identity : import_core.toRadians);
|
|
90
235
|
}
|
|
91
|
-
function
|
|
236
|
+
function toCartographicFromRadiansComponents(longitude, latitude, height, cartographic) {
|
|
237
|
+
const map = import_core.config._cartographicRadians ? identity : import_core.toDegrees;
|
|
238
|
+
const mappedLongitude = map(longitude), mappedLatitude = map(latitude);
|
|
92
239
|
if ("longitude" in cartographic) {
|
|
93
|
-
cartographic.longitude =
|
|
94
|
-
cartographic.latitude =
|
|
95
|
-
cartographic.height =
|
|
240
|
+
cartographic.longitude = mappedLongitude;
|
|
241
|
+
cartographic.latitude = mappedLatitude;
|
|
242
|
+
cartographic.height = height;
|
|
96
243
|
} else if ("x" in cartographic) {
|
|
97
|
-
cartographic.x =
|
|
98
|
-
cartographic.y =
|
|
99
|
-
cartographic.z =
|
|
244
|
+
cartographic.x = mappedLongitude;
|
|
245
|
+
cartographic.y = mappedLatitude;
|
|
246
|
+
cartographic.z = height;
|
|
100
247
|
} else {
|
|
101
|
-
cartographic[0] =
|
|
102
|
-
cartographic[1] =
|
|
103
|
-
cartographic[2] =
|
|
248
|
+
cartographic[0] = mappedLongitude;
|
|
249
|
+
cartographic[1] = mappedLatitude;
|
|
250
|
+
cartographic[2] = height;
|
|
104
251
|
}
|
|
105
252
|
return cartographic;
|
|
106
253
|
}
|
|
107
|
-
function toCartographicFromRadians(vector, cartographic) {
|
|
108
|
-
return toCartographic(vector, cartographic, import_core.config._cartographicRadians ? identity : import_core.toDegrees);
|
|
109
|
-
}
|
|
110
254
|
function isWGS84(vector) {
|
|
111
255
|
if (!vector) {
|
|
112
256
|
return false;
|
|
@@ -121,8 +265,93 @@ function isWGS84(vector) {
|
|
|
121
265
|
|
|
122
266
|
// dist/ellipsoid-helpers/ellipsoid-transform.js
|
|
123
267
|
var import_core2 = require("@math.gl/core");
|
|
268
|
+
|
|
269
|
+
// ../core/src/local-frame.ts
|
|
270
|
+
function createLocalFrameBasis() {
|
|
271
|
+
return { eastX: 0, eastY: 1, northZ: 1, upX: 1, upY: 0, upZ: 0 };
|
|
272
|
+
}
|
|
273
|
+
function eastNorthUpBasisFromDirections(east, up, result) {
|
|
274
|
+
const ex = east.x, ey = east.y, ez = east.z;
|
|
275
|
+
const ux = up.x, uy = up.y, uz = up.z;
|
|
276
|
+
if (ez !== 0) return false;
|
|
277
|
+
return commitBasis(result, ex, ey, ux * ey - uy * ex, ux, uy, uz);
|
|
278
|
+
}
|
|
279
|
+
function localFrameToMatrix(basis, origin, firstAxis, secondAxis, thirdAxis, result) {
|
|
280
|
+
const first = axisCode(firstAxis), second = axisCode(secondAxis), third = axisCode(thirdAxis);
|
|
281
|
+
const a = Math.abs(first), b = Math.abs(second), c = Math.abs(third);
|
|
282
|
+
if (!a || !b || !c || a === b || a === c || b === c) return false;
|
|
283
|
+
const parity = a % 3 + 1 === b ? 1 : -1;
|
|
284
|
+
if (parity * Math.sign(first * second * third) !== 1 || !Array.isArray(result) && result.length < 16)
|
|
285
|
+
return false;
|
|
286
|
+
const ex = basis.eastX, ey = basis.eastY, nz = basis.northZ;
|
|
287
|
+
const ux = basis.upX, uy = basis.upY, uz = basis.upZ;
|
|
288
|
+
const nx = -uz * ey, ny = uz * ex;
|
|
289
|
+
const x = origin.x, y = origin.y, z = origin.z;
|
|
290
|
+
const ax = (a === 1 ? ex : a === 2 ? nx : ux) * Math.sign(first);
|
|
291
|
+
const ay = (a === 1 ? ey : a === 2 ? ny : uy) * Math.sign(first);
|
|
292
|
+
const az = (a === 1 ? 0 : a === 2 ? nz : uz) * Math.sign(first);
|
|
293
|
+
const bx = (b === 1 ? ex : b === 2 ? nx : ux) * Math.sign(second);
|
|
294
|
+
const by = (b === 1 ? ey : b === 2 ? ny : uy) * Math.sign(second);
|
|
295
|
+
const bz = (b === 1 ? 0 : b === 2 ? nz : uz) * Math.sign(second);
|
|
296
|
+
const cx = (c === 1 ? ex : c === 2 ? nx : ux) * Math.sign(third);
|
|
297
|
+
const cy = (c === 1 ? ey : c === 2 ? ny : uy) * Math.sign(third);
|
|
298
|
+
const cz = (c === 1 ? 0 : c === 2 ? nz : uz) * Math.sign(third);
|
|
299
|
+
if (!Number.isFinite(ax) || !Number.isFinite(ay) || !Number.isFinite(az) || !Number.isFinite(bx) || !Number.isFinite(by) || !Number.isFinite(bz) || !Number.isFinite(cx) || !Number.isFinite(cy) || !Number.isFinite(cz) || !Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z))
|
|
300
|
+
return false;
|
|
301
|
+
if (result instanceof Float32Array && (!Number.isFinite(Math.fround(ax)) || !Number.isFinite(Math.fround(ay)) || !Number.isFinite(Math.fround(az)) || !Number.isFinite(Math.fround(bx)) || !Number.isFinite(Math.fround(by)) || !Number.isFinite(Math.fround(bz)) || !Number.isFinite(Math.fround(cx)) || !Number.isFinite(Math.fround(cy)) || !Number.isFinite(Math.fround(cz)) || !Number.isFinite(Math.fround(x)) || !Number.isFinite(Math.fround(y)) || !Number.isFinite(Math.fround(z))))
|
|
302
|
+
return false;
|
|
303
|
+
result[0] = ax;
|
|
304
|
+
result[1] = ay;
|
|
305
|
+
result[2] = az;
|
|
306
|
+
result[3] = 0;
|
|
307
|
+
result[4] = bx;
|
|
308
|
+
result[5] = by;
|
|
309
|
+
result[6] = bz;
|
|
310
|
+
result[7] = 0;
|
|
311
|
+
result[8] = cx;
|
|
312
|
+
result[9] = cy;
|
|
313
|
+
result[10] = cz;
|
|
314
|
+
result[11] = 0;
|
|
315
|
+
result[12] = x;
|
|
316
|
+
result[13] = y;
|
|
317
|
+
result[14] = z;
|
|
318
|
+
result[15] = 1;
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
function axisCode(axis) {
|
|
322
|
+
switch (axis) {
|
|
323
|
+
case "east":
|
|
324
|
+
return 1;
|
|
325
|
+
case "west":
|
|
326
|
+
return -1;
|
|
327
|
+
case "north":
|
|
328
|
+
return 2;
|
|
329
|
+
case "south":
|
|
330
|
+
return -2;
|
|
331
|
+
case "up":
|
|
332
|
+
return 3;
|
|
333
|
+
case "down":
|
|
334
|
+
return -3;
|
|
335
|
+
default:
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function commitBasis(result, ex, ey, nz, ux, uy, uz) {
|
|
340
|
+
if (!Number.isFinite(ex) || !Number.isFinite(ey) || !Number.isFinite(nz) || !Number.isFinite(ux) || !Number.isFinite(uy) || !Number.isFinite(uz))
|
|
341
|
+
return false;
|
|
342
|
+
result.eastX = ex;
|
|
343
|
+
result.eastY = ey;
|
|
344
|
+
result.northZ = nz;
|
|
345
|
+
result.upX = ux;
|
|
346
|
+
result.upY = uy;
|
|
347
|
+
result.upZ = uz;
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// dist/ellipsoid-helpers/ellipsoid-transform.js
|
|
124
352
|
var EPSILON14 = 1e-14;
|
|
125
353
|
var scratchOrigin = new import_core2.Vector3();
|
|
354
|
+
var scratchBasis = createLocalFrameBasis();
|
|
126
355
|
var VECTOR_PRODUCT_LOCAL_FRAME = {
|
|
127
356
|
up: {
|
|
128
357
|
south: "east",
|
|
@@ -188,6 +417,20 @@ function localFrameToFixedFrame(ellipsoid, firstAxis, secondAxis, thirdAxis, car
|
|
|
188
417
|
let thirdAxisVector;
|
|
189
418
|
const origin = scratchOrigin.copy(cartesianOrigin);
|
|
190
419
|
const atPole = (0, import_core2.equals)(origin.x, 0, EPSILON14) && (0, import_core2.equals)(origin.y, 0, EPSILON14);
|
|
420
|
+
const radii = ellipsoid.radii;
|
|
421
|
+
if (radii.x === radii.y && radii.x > 0 && radii.z > 0 && radii.z <= radii.x && (!atPole || origin.z !== 0)) {
|
|
422
|
+
const { east, up } = scratchAxisVectors;
|
|
423
|
+
if (atPole) {
|
|
424
|
+
east.set(0, 1, 0);
|
|
425
|
+
up.set(0, 0, Math.sign(origin.z));
|
|
426
|
+
} else {
|
|
427
|
+
east.set(-origin.y, origin.x, 0).normalize();
|
|
428
|
+
ellipsoid.geodeticSurfaceNormal(origin, up);
|
|
429
|
+
}
|
|
430
|
+
if (!eastNorthUpBasisFromDirections(east, up, scratchBasis) || !localFrameToMatrix(scratchBasis, origin, firstAxis, secondAxis, thirdAxis, result))
|
|
431
|
+
throw new Error("Unsupported local frame");
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
191
434
|
if (atPole) {
|
|
192
435
|
const sign = Math.sign(origin.z);
|
|
193
436
|
firstAxisVector = scratchVector1.fromArray(degeneratePositionLocalFrame[firstAxis]);
|
|
@@ -215,21 +458,25 @@ function localFrameToFixedFrame(ellipsoid, firstAxis, secondAxis, thirdAxis, car
|
|
|
215
458
|
secondAxisVector = scratchAxisVectors[secondAxis];
|
|
216
459
|
thirdAxisVector = scratchAxisVectors[thirdAxis];
|
|
217
460
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
461
|
+
const ax = firstAxisVector.x, ay = firstAxisVector.y, az = firstAxisVector.z;
|
|
462
|
+
const bx = secondAxisVector.x, by = secondAxisVector.y, bz = secondAxisVector.z;
|
|
463
|
+
const cx = thirdAxisVector.x, cy = thirdAxisVector.y, cz = thirdAxisVector.z;
|
|
464
|
+
const x = origin.x, y = origin.y, z = origin.z;
|
|
465
|
+
result[0] = ax;
|
|
466
|
+
result[1] = ay;
|
|
467
|
+
result[2] = az;
|
|
221
468
|
result[3] = 0;
|
|
222
|
-
result[4] =
|
|
223
|
-
result[5] =
|
|
224
|
-
result[6] =
|
|
469
|
+
result[4] = bx;
|
|
470
|
+
result[5] = by;
|
|
471
|
+
result[6] = bz;
|
|
225
472
|
result[7] = 0;
|
|
226
|
-
result[8] =
|
|
227
|
-
result[9] =
|
|
228
|
-
result[10] =
|
|
473
|
+
result[8] = cx;
|
|
474
|
+
result[9] = cy;
|
|
475
|
+
result[10] = cz;
|
|
229
476
|
result[11] = 0;
|
|
230
|
-
result[12] =
|
|
231
|
-
result[13] =
|
|
232
|
-
result[14] =
|
|
477
|
+
result[12] = x;
|
|
478
|
+
result[13] = y;
|
|
479
|
+
result[14] = z;
|
|
233
480
|
result[15] = 1;
|
|
234
481
|
return result;
|
|
235
482
|
}
|
|
@@ -241,10 +488,14 @@ var scaleToGeodeticSurfaceIntersection = new import_core3.Vector3();
|
|
|
241
488
|
var scaleToGeodeticSurfaceGradient = new import_core3.Vector3();
|
|
242
489
|
function scaleToGeodeticSurface(cartesian, ellipsoid, result = []) {
|
|
243
490
|
const { oneOverRadii, oneOverRadiiSquared, centerToleranceSquared } = ellipsoid;
|
|
244
|
-
|
|
245
|
-
const positionX =
|
|
246
|
-
const positionY =
|
|
247
|
-
const positionZ =
|
|
491
|
+
const object = cartesian;
|
|
492
|
+
const positionX = "x" in cartesian ? object.x : cartesian[0];
|
|
493
|
+
const positionY = "x" in cartesian ? object.y : cartesian[1];
|
|
494
|
+
const positionZ = "x" in cartesian ? object.z : cartesian[2];
|
|
495
|
+
if (!Number.isFinite(positionX) || !Number.isFinite(positionY) || !Number.isFinite(positionZ)) {
|
|
496
|
+
return void 0;
|
|
497
|
+
}
|
|
498
|
+
scratchVector4.set(positionX, positionY, positionZ);
|
|
248
499
|
const oneOverRadiiX = oneOverRadii.x;
|
|
249
500
|
const oneOverRadiiY = oneOverRadii.y;
|
|
250
501
|
const oneOverRadiiZ = oneOverRadii.z;
|
|
@@ -253,13 +504,13 @@ function scaleToGeodeticSurface(cartesian, ellipsoid, result = []) {
|
|
|
253
504
|
const z2 = positionZ * positionZ * oneOverRadiiZ * oneOverRadiiZ;
|
|
254
505
|
const squaredNorm = x2 + y2 + z2;
|
|
255
506
|
const ratio = Math.sqrt(1 / squaredNorm);
|
|
256
|
-
if (!Number.isFinite(ratio)) {
|
|
507
|
+
if (!Number.isFinite(ratio) || !Number.isFinite(squaredNorm)) {
|
|
257
508
|
return void 0;
|
|
258
509
|
}
|
|
259
510
|
const intersection = scaleToGeodeticSurfaceIntersection;
|
|
260
|
-
intersection.
|
|
511
|
+
intersection.set(positionX, positionY, positionZ).scale(ratio);
|
|
261
512
|
if (squaredNorm < centerToleranceSquared) {
|
|
262
|
-
return intersection.
|
|
513
|
+
return writeResult(result, intersection.x, intersection.y, intersection.z);
|
|
263
514
|
}
|
|
264
515
|
const oneOverRadiiSquaredX = oneOverRadiiSquared.x;
|
|
265
516
|
const oneOverRadiiSquaredY = oneOverRadiiSquared.y;
|
|
@@ -272,7 +523,7 @@ function scaleToGeodeticSurface(cartesian, ellipsoid, result = []) {
|
|
|
272
523
|
let yMultiplier;
|
|
273
524
|
let zMultiplier;
|
|
274
525
|
let func;
|
|
275
|
-
|
|
526
|
+
for (let iteration = 0; iteration < 64; iteration++) {
|
|
276
527
|
lambda -= correction;
|
|
277
528
|
xMultiplier = 1 / (1 + lambda * oneOverRadiiSquaredX);
|
|
278
529
|
yMultiplier = 1 / (1 + lambda * oneOverRadiiSquaredY);
|
|
@@ -284,21 +535,52 @@ function scaleToGeodeticSurface(cartesian, ellipsoid, result = []) {
|
|
|
284
535
|
const yMultiplier3 = yMultiplier2 * yMultiplier;
|
|
285
536
|
const zMultiplier3 = zMultiplier2 * zMultiplier;
|
|
286
537
|
func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1;
|
|
538
|
+
if (!Number.isFinite(func))
|
|
539
|
+
return void 0;
|
|
540
|
+
if (Math.abs(func) <= import_core3._MathUtils.EPSILON12) {
|
|
541
|
+
return writeResult(result, positionX * xMultiplier, positionY * yMultiplier, positionZ * zMultiplier);
|
|
542
|
+
}
|
|
287
543
|
const denominator = x2 * xMultiplier3 * oneOverRadiiSquaredX + y2 * yMultiplier3 * oneOverRadiiSquaredY + z2 * zMultiplier3 * oneOverRadiiSquaredZ;
|
|
288
544
|
const derivative = -2 * denominator;
|
|
545
|
+
if (!Number.isFinite(derivative) || derivative === 0)
|
|
546
|
+
return void 0;
|
|
289
547
|
correction = func / derivative;
|
|
290
|
-
|
|
291
|
-
|
|
548
|
+
if (!Number.isFinite(correction))
|
|
549
|
+
return void 0;
|
|
550
|
+
}
|
|
551
|
+
return void 0;
|
|
552
|
+
}
|
|
553
|
+
function writeResult(result, x, y, z) {
|
|
554
|
+
if ((0, import_core3.isArray)(result)) {
|
|
555
|
+
result[0] = x;
|
|
556
|
+
result[1] = y;
|
|
557
|
+
result[2] = z;
|
|
558
|
+
} else {
|
|
559
|
+
const point = result;
|
|
560
|
+
point.x = x;
|
|
561
|
+
point.y = y;
|
|
562
|
+
point.z = z;
|
|
563
|
+
}
|
|
564
|
+
return result;
|
|
292
565
|
}
|
|
293
566
|
|
|
294
567
|
// dist/ellipsoid.js
|
|
568
|
+
var spheroidScratch = { x: 0, y: 0, z: 0 };
|
|
295
569
|
var scratchVector5 = new import_core4.Vector3();
|
|
296
570
|
var scratchNormal = new import_core4.Vector3();
|
|
297
571
|
var scratchK = new import_core4.Vector3();
|
|
298
572
|
var scratchPosition = new import_core4.Vector3();
|
|
299
573
|
var scratchHeight = new import_core4.Vector3();
|
|
300
574
|
var scratchCartesian = new import_core4.Vector3();
|
|
301
|
-
var Ellipsoid = class {
|
|
575
|
+
var Ellipsoid = class _Ellipsoid {
|
|
576
|
+
/** Construct from two-axis geometry, including normalized projection ellipsoids.
|
|
577
|
+
* The equatorial X/Y radii are equal; no CRS or datum information is inferred.
|
|
578
|
+
*/
|
|
579
|
+
static fromSpheroid(parameters) {
|
|
580
|
+
const { semiMajorAxis, semiMinorAxis } = parameters;
|
|
581
|
+
validateSpheroid(semiMajorAxis, semiMinorAxis);
|
|
582
|
+
return new _Ellipsoid(semiMajorAxis, semiMajorAxis, semiMinorAxis);
|
|
583
|
+
}
|
|
302
584
|
constructor(x = 0, y = 0, z = 0) {
|
|
303
585
|
this.centerToleranceSquared = import_core4._MathUtils.EPSILON1;
|
|
304
586
|
(0, import_core4.assert)(x >= 0);
|
|
@@ -314,8 +596,25 @@ var Ellipsoid = class {
|
|
|
314
596
|
if (this.radiiSquared.z !== 0) {
|
|
315
597
|
this.squaredXOverSquaredZ = this.radiiSquared.x / this.radiiSquared.z;
|
|
316
598
|
}
|
|
599
|
+
if (x === y && z > 0 && z <= x && Number.isFinite(this.radiiSquared.x) && this.radiiSquared.z > 0)
|
|
600
|
+
this.spheroidGeometry = Object.freeze({
|
|
601
|
+
semiMajorAxis: x,
|
|
602
|
+
semiMinorAxis: z,
|
|
603
|
+
eccentricitySquared: 1 - this.radiiSquared.z / this.radiiSquared.x
|
|
604
|
+
});
|
|
317
605
|
Object.freeze(this);
|
|
318
606
|
}
|
|
607
|
+
/** Return an owned geometry snapshot for a sphere or oblate spheroid.
|
|
608
|
+
* Triaxial, prolate and degenerate ellipsoids cannot be represented by this contract.
|
|
609
|
+
* Call during setup, outside coordinate loops.
|
|
610
|
+
*/
|
|
611
|
+
toSpheroid() {
|
|
612
|
+
const { x, y, z } = this.radii;
|
|
613
|
+
if (x !== y)
|
|
614
|
+
throw new Error("Spheroid requires equal X/Y radii");
|
|
615
|
+
validateSpheroid(x, z);
|
|
616
|
+
return Object.freeze({ semiMajorAxis: x, semiMinorAxis: z });
|
|
617
|
+
}
|
|
319
618
|
/** Compares this Ellipsoid against the provided Ellipsoid componentwise */
|
|
320
619
|
equals(right) {
|
|
321
620
|
return this === right || Boolean(right && this.radii.equals(right.radii));
|
|
@@ -325,6 +624,15 @@ var Ellipsoid = class {
|
|
|
325
624
|
return this.radii.toString();
|
|
326
625
|
}
|
|
327
626
|
cartographicToCartesian(cartographic, result = [0, 0, 0]) {
|
|
627
|
+
if (this.spheroidGeometry) {
|
|
628
|
+
const llh = fromCartographicToRadians(cartographic, scratchCartesian);
|
|
629
|
+
spheroidScratch.x = llh[0];
|
|
630
|
+
spheroidScratch.y = llh[1];
|
|
631
|
+
spheroidScratch.z = llh[2];
|
|
632
|
+
if (!spheroidToCartesian(spheroidScratch, this.spheroidGeometry))
|
|
633
|
+
return void 0;
|
|
634
|
+
return writeResult(result, spheroidScratch.x, spheroidScratch.y, spheroidScratch.z);
|
|
635
|
+
}
|
|
328
636
|
const normal = scratchNormal;
|
|
329
637
|
const k = scratchK;
|
|
330
638
|
const [, , height] = cartographic;
|
|
@@ -337,7 +645,22 @@ var Ellipsoid = class {
|
|
|
337
645
|
return k.to(result);
|
|
338
646
|
}
|
|
339
647
|
cartesianToCartographic(cartesian, result = [0, 0, 0]) {
|
|
340
|
-
|
|
648
|
+
const object = cartesian;
|
|
649
|
+
const x = "x" in cartesian ? object.x : cartesian[0];
|
|
650
|
+
const y = "x" in cartesian ? object.y : cartesian[1];
|
|
651
|
+
const z = "x" in cartesian ? object.z : cartesian[2];
|
|
652
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z))
|
|
653
|
+
return void 0;
|
|
654
|
+
if (this.spheroidGeometry && Number.isFinite(x * x + y * y + z * z) && Number.isFinite(this.oneOverRadiiSquared.x) && Number.isFinite(this.oneOverRadiiSquared.z)) {
|
|
655
|
+
spheroidScratch.x = x;
|
|
656
|
+
spheroidScratch.y = y;
|
|
657
|
+
spheroidScratch.z = z;
|
|
658
|
+
if (!cartesianToSpheroid(spheroidScratch, this.spheroidGeometry))
|
|
659
|
+
return void 0;
|
|
660
|
+
const longitude2 = x === 0 && y === 0 ? Math.atan2(y, x) : spheroidScratch.x;
|
|
661
|
+
return toCartographicFromRadiansComponents(longitude2, spheroidScratch.y, spheroidScratch.z, result);
|
|
662
|
+
}
|
|
663
|
+
scratchCartesian.set(x, y, z);
|
|
341
664
|
const point = this.scaleToGeodeticSurface(scratchCartesian, scratchPosition);
|
|
342
665
|
if (!point) {
|
|
343
666
|
return void 0;
|
|
@@ -346,9 +669,9 @@ var Ellipsoid = class {
|
|
|
346
669
|
const h = scratchHeight;
|
|
347
670
|
h.copy(scratchCartesian).subtract(point);
|
|
348
671
|
const longitude = Math.atan2(normal.y, normal.x);
|
|
349
|
-
const latitude = Math.
|
|
672
|
+
const latitude = Math.atan2(normal.z, Math.hypot(normal.x, normal.y));
|
|
350
673
|
const height = Math.sign(dot(h, scratchCartesian)) * length(h);
|
|
351
|
-
return
|
|
674
|
+
return toCartographicFromRadiansComponents(longitude, latitude, height, result);
|
|
352
675
|
}
|
|
353
676
|
eastNorthUpToFixedFrame(origin, result = new import_core4.Matrix4()) {
|
|
354
677
|
return localFrameToFixedFrame(this, "east", "north", "up", origin, result);
|
|
@@ -412,6 +735,10 @@ var Ellipsoid = class {
|
|
|
412
735
|
}
|
|
413
736
|
};
|
|
414
737
|
Ellipsoid.WGS84 = new Ellipsoid(WGS84_RADIUS_X, WGS84_RADIUS_Y, WGS84_RADIUS_Z);
|
|
738
|
+
function validateSpheroid(a, b) {
|
|
739
|
+
if (!Number.isFinite(a) || !Number.isFinite(b) || a <= 0 || b <= 0 || b > a)
|
|
740
|
+
throw new Error("Spheroid requires finite positive axes with semiMinorAxis <= semiMajorAxis");
|
|
741
|
+
}
|
|
415
742
|
|
|
416
743
|
// dist/ellipsoid-tangent-plane.js
|
|
417
744
|
var import_core5 = require("@math.gl/core");
|
|
@@ -730,4 +1057,194 @@ function fromPlaneExtents(planeOrigin, planeXAxis, planeYAxis, planeZAxis, minim
|
|
|
730
1057
|
center.copy(planeOrigin).add(centerOffset);
|
|
731
1058
|
return result;
|
|
732
1059
|
}
|
|
1060
|
+
|
|
1061
|
+
// dist/ellipsoid-occluder.js
|
|
1062
|
+
var EllipsoidOccluder = class {
|
|
1063
|
+
constructor(radii, center = [0, 0, 0]) {
|
|
1064
|
+
validateVector(radii);
|
|
1065
|
+
validateVector(center);
|
|
1066
|
+
if (Array.from(radii).some((value) => value <= 0))
|
|
1067
|
+
throw new RangeError("Radii must be positive");
|
|
1068
|
+
this.radii = Object.freeze(Array.from(radii));
|
|
1069
|
+
this.center = Object.freeze(Array.from(center));
|
|
1070
|
+
}
|
|
1071
|
+
/** Nonnegative ray parameter interval, including tangency and inside-origin rays.
|
|
1072
|
+
* Direction need not be normalized. Undefined is a true miss; never clamps a miss
|
|
1073
|
+
* to the limb. Result is untouched on miss. Distances equal parameters only for
|
|
1074
|
+
* unit directions. Zero direction is a miss.
|
|
1075
|
+
*/
|
|
1076
|
+
intersectRay(origin, direction, result = [0, 0]) {
|
|
1077
|
+
validateVector(origin);
|
|
1078
|
+
validateVector(direction);
|
|
1079
|
+
const [x, y, z] = this.scalePoint(origin);
|
|
1080
|
+
const dx = direction[0] / this.radii[0];
|
|
1081
|
+
const dy = direction[1] / this.radii[1];
|
|
1082
|
+
const dz = direction[2] / this.radii[2];
|
|
1083
|
+
const length2 = Math.hypot(dx, dy, dz);
|
|
1084
|
+
if (length2 === 0 || !Number.isFinite(length2))
|
|
1085
|
+
return void 0;
|
|
1086
|
+
const ux = dx / length2, uy = dy / length2, uz = dz / length2;
|
|
1087
|
+
const along = -(x * ux + y * uy + z * uz);
|
|
1088
|
+
const perpendicular = Math.hypot(y * uz - z * uy, z * ux - x * uz, x * uy - y * ux);
|
|
1089
|
+
if (perpendicular > 1)
|
|
1090
|
+
return void 0;
|
|
1091
|
+
const half = Math.sqrt((1 - perpendicular) * (1 + perpendicular));
|
|
1092
|
+
let near = along - half;
|
|
1093
|
+
let far = along + half;
|
|
1094
|
+
const radius = Math.hypot(x, y, z);
|
|
1095
|
+
if (!Number.isFinite(radius))
|
|
1096
|
+
throw new RangeError("Scaled origin magnitude must be finite");
|
|
1097
|
+
if (half > 0 && along > 0 && far !== 0)
|
|
1098
|
+
near = (radius - 1) / far * (radius + 1);
|
|
1099
|
+
if (half > 0 && along < 0 && near !== 0)
|
|
1100
|
+
far = (radius - 1) / near * (radius + 1);
|
|
1101
|
+
if (far < 0)
|
|
1102
|
+
return void 0;
|
|
1103
|
+
result[0] = Math.max(0, Math.min(near, far)) / length2;
|
|
1104
|
+
result[1] = Math.max(0, far) / length2;
|
|
1105
|
+
return result;
|
|
1106
|
+
}
|
|
1107
|
+
/** True if the finite camera-to-point segment enters the solid interior.
|
|
1108
|
+
* Surface contact/tangency alone is not occlusion. Works for elevated points;
|
|
1109
|
+
* unlike a facing-normal test it does not discard visible points beyond the
|
|
1110
|
+
* surface horizon. tolerance is a nonnegative scaled-space squared-radius margin.
|
|
1111
|
+
*/
|
|
1112
|
+
isPointOccluded(camera, point, tolerance = 1e-12) {
|
|
1113
|
+
validateVector(camera);
|
|
1114
|
+
validateVector(point);
|
|
1115
|
+
if (!Number.isFinite(tolerance) || tolerance < 0 || tolerance >= 1)
|
|
1116
|
+
throw new RangeError("Tolerance must be in [0, 1)");
|
|
1117
|
+
const a = this.scalePoint(camera);
|
|
1118
|
+
const b = this.scalePoint(point);
|
|
1119
|
+
const dx = b[0] - a[0], dy = b[1] - a[1], dz = b[2] - a[2];
|
|
1120
|
+
const length2 = Math.hypot(dx, dy, dz);
|
|
1121
|
+
if (!Number.isFinite(length2))
|
|
1122
|
+
throw new RangeError("Segment magnitude must be finite");
|
|
1123
|
+
if (length2 === 0)
|
|
1124
|
+
return Math.hypot(...a) ** 2 < 1 - tolerance;
|
|
1125
|
+
const ux = dx / length2, uy = dy / length2, uz = dz / length2;
|
|
1126
|
+
const distance = Math.max(0, Math.min(length2, -(a[0] * ux + a[1] * uy + a[2] * uz)));
|
|
1127
|
+
return Math.hypot(a[0] + distance * ux, a[1] + distance * uy, a[2] + distance * uz) ** 2 < 1 - tolerance;
|
|
1128
|
+
}
|
|
1129
|
+
/** Exact apparent limb ellipse for an exterior camera; undefined on/inside surface. */
|
|
1130
|
+
getHorizon(camera) {
|
|
1131
|
+
validateVector(camera);
|
|
1132
|
+
const scaled = this.scalePoint(camera);
|
|
1133
|
+
const distance = Math.hypot(...scaled);
|
|
1134
|
+
if (!Number.isFinite(distance))
|
|
1135
|
+
throw new RangeError("Camera magnitude must be finite");
|
|
1136
|
+
if (distance <= 1)
|
|
1137
|
+
return void 0;
|
|
1138
|
+
const normal = scaled.map((value) => value / distance);
|
|
1139
|
+
const reference = Math.abs(normal[2]) < 0.9 ? [0, 0, 1] : [0, 1, 0];
|
|
1140
|
+
const u = cross(normal, reference);
|
|
1141
|
+
const uLength = Math.hypot(...u);
|
|
1142
|
+
const v = cross(normal, u.map((value) => value / uLength));
|
|
1143
|
+
const radius = Math.sqrt((1 - 1 / distance) * (1 + 1 / distance));
|
|
1144
|
+
return {
|
|
1145
|
+
center: normal.map((value, i) => this.center[i] + this.radii[i] * value / distance),
|
|
1146
|
+
axis1: u.map((value, i) => this.radii[i] * radius * value / uLength),
|
|
1147
|
+
axis2: v.map((value, i) => this.radii[i] * radius * value)
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
scalePoint(point) {
|
|
1151
|
+
const result = this.radii.map((radius, i) => (point[i] - this.center[i]) / radius);
|
|
1152
|
+
if (!result.every(Number.isFinite))
|
|
1153
|
+
throw new RangeError("Scaled coordinates must be finite");
|
|
1154
|
+
return result;
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
function validateVector(vector) {
|
|
1158
|
+
if (vector.length !== 3 || !Array.from(vector).every(Number.isFinite))
|
|
1159
|
+
throw new RangeError("Expected three finite Cartesian components");
|
|
1160
|
+
}
|
|
1161
|
+
function cross(a, b) {
|
|
1162
|
+
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// dist/globe-horizon-bounds.js
|
|
1166
|
+
function getGlobeHorizonBounds(camera, radius) {
|
|
1167
|
+
if (camera.length !== 3 || !Array.from(camera).every(Number.isFinite) || !Number.isFinite(radius) || radius <= 0)
|
|
1168
|
+
throw new RangeError("Expected a finite camera and positive sphere radius");
|
|
1169
|
+
const distance = Math.hypot(camera[0], camera[1], camera[2]);
|
|
1170
|
+
if (!Number.isFinite(distance))
|
|
1171
|
+
throw new RangeError("Camera magnitude must be finite");
|
|
1172
|
+
if (distance <= radius)
|
|
1173
|
+
return void 0;
|
|
1174
|
+
const latitude = Math.atan2(camera[2], Math.hypot(camera[0], camera[1]));
|
|
1175
|
+
const longitude = Math.atan2(camera[1], camera[0]);
|
|
1176
|
+
const angle = Math.acos(radius / distance);
|
|
1177
|
+
const degrees2 = 180 / Math.PI;
|
|
1178
|
+
const padding = 1e-10;
|
|
1179
|
+
const south = Math.max(-90, (latitude - angle) * degrees2 - padding);
|
|
1180
|
+
const north = Math.min(90, (latitude + angle) * degrees2 + padding);
|
|
1181
|
+
if (Math.abs(latitude) + angle >= Math.PI / 2 - 1e-12)
|
|
1182
|
+
return [-180, south, 180, north];
|
|
1183
|
+
const extent = Math.asin(Math.min(1, Math.sin(angle) / Math.cos(latitude))) * degrees2 + padding;
|
|
1184
|
+
return [wrap(longitude * degrees2 - extent), south, wrap(longitude * degrees2 + extent), north];
|
|
1185
|
+
}
|
|
1186
|
+
function splitGlobeBounds(bounds) {
|
|
1187
|
+
const [west, south, east, north] = bounds;
|
|
1188
|
+
if (bounds.length !== 4 || !bounds.every(Number.isFinite) || west < -180 || west > 180 || east < -180 || east > 180 || south < -90 || north > 90 || south > north)
|
|
1189
|
+
throw new RangeError("Invalid degree bounds");
|
|
1190
|
+
return west <= east ? [[west, south, east, north]] : [
|
|
1191
|
+
[west, south, 180, north],
|
|
1192
|
+
[-180, south, east, north]
|
|
1193
|
+
];
|
|
1194
|
+
}
|
|
1195
|
+
function wrap(longitude) {
|
|
1196
|
+
return ((longitude + 180) % 360 + 360) % 360 - 180;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// dist/geographic-tiles.js
|
|
1200
|
+
function getGeographicTileBounds(tile) {
|
|
1201
|
+
const size = gridSize(tile.level);
|
|
1202
|
+
if (![tile.x, tile.y].every((v) => Number.isInteger(v) && v >= 0 && v < size))
|
|
1203
|
+
throw new RangeError("Tile coordinates must be integers inside the level grid");
|
|
1204
|
+
return [
|
|
1205
|
+
-180 + 360 * tile.x / size,
|
|
1206
|
+
90 - 180 * (tile.y + 1) / size,
|
|
1207
|
+
-180 + 360 * (tile.x + 1) / size,
|
|
1208
|
+
90 - 180 * tile.y / size
|
|
1209
|
+
];
|
|
1210
|
+
}
|
|
1211
|
+
function getGeographicTile(longitude, latitude, level) {
|
|
1212
|
+
const size = gridSize(level);
|
|
1213
|
+
if (!Number.isFinite(longitude) || longitude < -180 || longitude > 180 || !Number.isFinite(latitude) || latitude < -90 || latitude > 90)
|
|
1214
|
+
throw new RangeError("Expected longitude in [-180, 180] and latitude in [-90, 90]");
|
|
1215
|
+
return {
|
|
1216
|
+
x: Math.min(size - 1, Math.floor((longitude + 180) / 360 * size)),
|
|
1217
|
+
y: Math.min(size - 1, Math.floor((90 - latitude) / 180 * size)),
|
|
1218
|
+
level
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
function getGeographicTileRanges(bounds, level) {
|
|
1222
|
+
const size = gridSize(level);
|
|
1223
|
+
const split = splitGlobeBounds(bounds);
|
|
1224
|
+
const positiveWidth = split.filter(([west, , east]) => east > west);
|
|
1225
|
+
const rectangles = positiveWidth.length ? positiveWidth : split;
|
|
1226
|
+
const intervals = rectangles.map(([west, south, east, north]) => {
|
|
1227
|
+
const start = getGeographicTile(west, north, level);
|
|
1228
|
+
return {
|
|
1229
|
+
minX: start.x,
|
|
1230
|
+
maxX: west === east ? start.x : Math.max(start.x, Math.min(size - 1, Math.ceil((east + 180) / 360 * size) - 1)),
|
|
1231
|
+
minY: start.y,
|
|
1232
|
+
maxY: south === north ? start.y : Math.max(start.y, Math.min(size - 1, Math.ceil((90 - south) / 180 * size) - 1))
|
|
1233
|
+
};
|
|
1234
|
+
}).sort((a, b) => a.minX - b.minX);
|
|
1235
|
+
const result = [];
|
|
1236
|
+
for (const range of intervals) {
|
|
1237
|
+
const previous = result[result.length - 1];
|
|
1238
|
+
if (previous && range.minX <= previous.maxX + 1)
|
|
1239
|
+
previous.maxX = Math.max(previous.maxX, range.maxX);
|
|
1240
|
+
else
|
|
1241
|
+
result.push(range);
|
|
1242
|
+
}
|
|
1243
|
+
return result;
|
|
1244
|
+
}
|
|
1245
|
+
function gridSize(level) {
|
|
1246
|
+
if (!Number.isInteger(level) || level < 0 || level > 30)
|
|
1247
|
+
throw new RangeError("Level must be an integer from 0 through 30");
|
|
1248
|
+
return 2 ** level;
|
|
1249
|
+
}
|
|
733
1250
|
//# sourceMappingURL=index.cjs.map
|