spacemap 0.1.15 → 0.1.16
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/README.md +17 -1
- package/dist/spacemap.iife.js +387 -303
- package/dist/spacemap.js +387 -303
- package/index.d.ts +22 -8
- package/index.js +2120 -815
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*! spacemap SDK — https://spacemap.co — Mozilla Public License 2.0. Bundles MIT and ISC libraries: THIRD_PARTY_NOTICES.txt in the spacemap npm package. */
|
|
2
|
-
import { ACESFilmicToneMapping, AdditiveBlending, AmbientLight, ArrowHelper, BackSide, Box3, BufferAttribute, BufferGeometry, CanvasTexture, Color, CubeTexture, CustomBlending, DataArrayTexture, DataTexture, DepthTexture, DirectionalLight, DoubleSide, Euler, Float32BufferAttribute, FloatType, FrontSide, Group, HalfFloatType, InstancedBufferAttribute, InstancedMesh, Line, LineBasicMaterial, LineLoop, LinearFilter, LinearMipmapLinearFilter, LinearSRGBColorSpace, MathUtils, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshStandardMaterial, NoBlending, NoColorSpace, NormalBlending, OneFactor, OneMinusSrcAlphaFactor, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, RGBAFormat, RGFormat, RawShaderMaterial, Raycaster, RedFormat, RepeatWrapping, RingGeometry, SRGBColorSpace, Scene, ShaderChunk, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapeUtils, SphereGeometry, Sprite, SpriteMaterial, TOUCH, Texture, TextureLoader, Uint16BufferAttribute, UnsignedByteType, Vector2, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
2
|
+
import { ACESFilmicToneMapping, AdditiveBlending, AmbientLight, ArrowHelper, BackSide, Box3, BufferAttribute, BufferGeometry, CanvasTexture, ClampToEdgeWrapping, Color, CubeTexture, CustomBlending, DataArrayTexture, DataTexture, DataUtils, DepthTexture, DirectionalLight, DoubleSide, Euler, Float32BufferAttribute, FloatType, FrontSide, Group, HalfFloatType, InstancedBufferAttribute, InstancedMesh, Line, LineBasicMaterial, LineLoop, LinearFilter, LinearMipmapLinearFilter, LinearSRGBColorSpace, MathUtils, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshStandardMaterial, NoBlending, NoColorSpace, NormalBlending, OneFactor, OneMinusSrcAlphaFactor, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, RGBAFormat, RGFormat, RawShaderMaterial, Raycaster, RedFormat, RepeatWrapping, RingGeometry, SRGBColorSpace, Scene, ShaderChunk, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapeUtils, SphereGeometry, Sprite, SpriteMaterial, TOUCH, Texture, TextureLoader, Uint16BufferAttribute, UnsignedByteType, Vector2, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
3
|
+
import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";
|
|
3
4
|
import { CSS2DObject } from "three/addons/renderers/CSS2DRenderer.js";
|
|
4
5
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
5
6
|
import { MeshoptDecoder } from "three/addons/libs/meshopt_decoder.module.js";
|
|
@@ -8,7 +9,6 @@ import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
|
|
|
8
9
|
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
|
|
9
10
|
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
|
|
10
11
|
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
|
|
11
|
-
import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";
|
|
12
12
|
import { FullScreenQuad } from "three/addons/postprocessing/Pass.js";
|
|
13
13
|
|
|
14
14
|
//#region src/lib/host.ts
|
|
@@ -2986,6 +2986,9 @@ var versions = {};
|
|
|
2986
2986
|
function setDataVersions(v) {
|
|
2987
2987
|
versions = v ?? {};
|
|
2988
2988
|
}
|
|
2989
|
+
function getDataVersions() {
|
|
2990
|
+
return versions;
|
|
2991
|
+
}
|
|
2989
2992
|
function versionedUrl(path, cls) {
|
|
2990
2993
|
return buildVersionedUrl(dataBase(), path, cls);
|
|
2991
2994
|
}
|
|
@@ -5314,13 +5317,392 @@ function equatorialToScene(xEq, yEq, zEq, out) {
|
|
|
5314
5317
|
}
|
|
5315
5318
|
|
|
5316
5319
|
//#endregion
|
|
5317
|
-
//#region src/lib/
|
|
5318
|
-
var
|
|
5319
|
-
var
|
|
5320
|
-
var SIN_EPS$4 = Math.sin(EARTH_OBLIQUITY_DEG * DEG2RAD$9);
|
|
5320
|
+
//#region src/lib/time/jd.ts
|
|
5321
|
+
var J2000_JD$1 = 2451545;
|
|
5322
|
+
var SECONDS_PER_DAY$2 = 86400;
|
|
5321
5323
|
var JD_UNIX_EPOCH$1 = 2440587.5;
|
|
5324
|
+
var MS_PER_DAY = 864e5;
|
|
5325
|
+
function unixMsToJD(ms) {
|
|
5326
|
+
return ms / MS_PER_DAY + JD_UNIX_EPOCH$1;
|
|
5327
|
+
}
|
|
5328
|
+
function dateToJD(date) {
|
|
5329
|
+
return unixMsToJD(date.getTime());
|
|
5330
|
+
}
|
|
5331
|
+
function jdToDate(jd) {
|
|
5332
|
+
return new Date((jd - JD_UNIX_EPOCH$1) * MS_PER_DAY);
|
|
5333
|
+
}
|
|
5334
|
+
var TT_MINUS_TAI = 32.184;
|
|
5335
|
+
var LEAP_SECONDS = [
|
|
5336
|
+
[2441317.5, 10],
|
|
5337
|
+
[2441499.5, 11],
|
|
5338
|
+
[2441683.5, 12],
|
|
5339
|
+
[2442048.5, 13],
|
|
5340
|
+
[2442413.5, 14],
|
|
5341
|
+
[2442778.5, 15],
|
|
5342
|
+
[2443144.5, 16],
|
|
5343
|
+
[2443509.5, 17],
|
|
5344
|
+
[2443874.5, 18],
|
|
5345
|
+
[2444239.5, 19],
|
|
5346
|
+
[2444786.5, 20],
|
|
5347
|
+
[2445151.5, 21],
|
|
5348
|
+
[2445516.5, 22],
|
|
5349
|
+
[2446247.5, 23],
|
|
5350
|
+
[2447161.5, 24],
|
|
5351
|
+
[2447892.5, 25],
|
|
5352
|
+
[2448257.5, 26],
|
|
5353
|
+
[2448804.5, 27],
|
|
5354
|
+
[2449169.5, 28],
|
|
5355
|
+
[2449534.5, 29],
|
|
5356
|
+
[2450083.5, 30],
|
|
5357
|
+
[2450630.5, 31],
|
|
5358
|
+
[2451179.5, 32],
|
|
5359
|
+
[2453736.5, 33],
|
|
5360
|
+
[2454832.5, 34],
|
|
5361
|
+
[2456109.5, 35],
|
|
5362
|
+
[2457204.5, 36],
|
|
5363
|
+
[2457754.5, 37]
|
|
5364
|
+
];
|
|
5365
|
+
function taiMinusUtc(jdUtc) {
|
|
5366
|
+
for (let k = LEAP_SECONDS.length - 1; k >= 0; k--) if (jdUtc >= LEAP_SECONDS[k][0]) return LEAP_SECONDS[k][1];
|
|
5367
|
+
return LEAP_SECONDS[0][1] - 1;
|
|
5368
|
+
}
|
|
5369
|
+
function tdbMinusTt(jd) {
|
|
5370
|
+
const m = 6.239996 + 1.99096871e-7 * (jd - J2000_JD$1) * SECONDS_PER_DAY$2;
|
|
5371
|
+
return .001657 * Math.sin(m + .01671 * Math.sin(m));
|
|
5372
|
+
}
|
|
5373
|
+
function utcToTdb(jd) {
|
|
5374
|
+
if (!Number.isFinite(jd)) return jd;
|
|
5375
|
+
const tt = jd + (taiMinusUtc(jd) + TT_MINUS_TAI) / SECONDS_PER_DAY$2;
|
|
5376
|
+
return tt + tdbMinusTt(tt) / SECONDS_PER_DAY$2;
|
|
5377
|
+
}
|
|
5378
|
+
function tdbToUtc(jd) {
|
|
5379
|
+
if (!Number.isFinite(jd)) return jd;
|
|
5380
|
+
const tt = jd - tdbMinusTt(jd) / SECONDS_PER_DAY$2;
|
|
5381
|
+
return tt - (taiMinusUtc(tt - (taiMinusUtc(tt) + TT_MINUS_TAI) / SECONDS_PER_DAY$2) + TT_MINUS_TAI) / SECONDS_PER_DAY$2;
|
|
5382
|
+
}
|
|
5383
|
+
function jdToEt(jd) {
|
|
5384
|
+
return (utcToTdb(jd) - J2000_JD$1) * SECONDS_PER_DAY$2;
|
|
5385
|
+
}
|
|
5386
|
+
function etToTdbJd(et) {
|
|
5387
|
+
return J2000_JD$1 + et / SECONDS_PER_DAY$2;
|
|
5388
|
+
}
|
|
5389
|
+
function tdbJdToEt(jd) {
|
|
5390
|
+
return (jd - J2000_JD$1) * SECONDS_PER_DAY$2;
|
|
5391
|
+
}
|
|
5392
|
+
|
|
5393
|
+
//#endregion
|
|
5394
|
+
//#region src/lib/math/orbit/teme.ts
|
|
5395
|
+
var DEG$10 = Math.PI / 180;
|
|
5396
|
+
var ARCSEC = DEG$10 / 3600;
|
|
5397
|
+
var NUT_UNIT = 1e-4 * ARCSEC;
|
|
5398
|
+
var REUSE_DAYS = .01;
|
|
5399
|
+
var NUTATION = [
|
|
5400
|
+
[
|
|
5401
|
+
0,
|
|
5402
|
+
0,
|
|
5403
|
+
0,
|
|
5404
|
+
0,
|
|
5405
|
+
1,
|
|
5406
|
+
-171996,
|
|
5407
|
+
-174.2,
|
|
5408
|
+
92025,
|
|
5409
|
+
8.9
|
|
5410
|
+
],
|
|
5411
|
+
[
|
|
5412
|
+
0,
|
|
5413
|
+
0,
|
|
5414
|
+
2,
|
|
5415
|
+
-2,
|
|
5416
|
+
2,
|
|
5417
|
+
-13187,
|
|
5418
|
+
-1.6,
|
|
5419
|
+
5736,
|
|
5420
|
+
-3.1
|
|
5421
|
+
],
|
|
5422
|
+
[
|
|
5423
|
+
0,
|
|
5424
|
+
0,
|
|
5425
|
+
2,
|
|
5426
|
+
0,
|
|
5427
|
+
2,
|
|
5428
|
+
-2274,
|
|
5429
|
+
-.2,
|
|
5430
|
+
977,
|
|
5431
|
+
-.5
|
|
5432
|
+
],
|
|
5433
|
+
[
|
|
5434
|
+
0,
|
|
5435
|
+
0,
|
|
5436
|
+
0,
|
|
5437
|
+
0,
|
|
5438
|
+
2,
|
|
5439
|
+
2062,
|
|
5440
|
+
.2,
|
|
5441
|
+
-895,
|
|
5442
|
+
.5
|
|
5443
|
+
],
|
|
5444
|
+
[
|
|
5445
|
+
0,
|
|
5446
|
+
1,
|
|
5447
|
+
0,
|
|
5448
|
+
0,
|
|
5449
|
+
0,
|
|
5450
|
+
1426,
|
|
5451
|
+
-3.4,
|
|
5452
|
+
54,
|
|
5453
|
+
-.1
|
|
5454
|
+
],
|
|
5455
|
+
[
|
|
5456
|
+
1,
|
|
5457
|
+
0,
|
|
5458
|
+
0,
|
|
5459
|
+
0,
|
|
5460
|
+
0,
|
|
5461
|
+
712,
|
|
5462
|
+
.1,
|
|
5463
|
+
-7,
|
|
5464
|
+
0
|
|
5465
|
+
],
|
|
5466
|
+
[
|
|
5467
|
+
0,
|
|
5468
|
+
1,
|
|
5469
|
+
2,
|
|
5470
|
+
-2,
|
|
5471
|
+
2,
|
|
5472
|
+
-517,
|
|
5473
|
+
1.2,
|
|
5474
|
+
224,
|
|
5475
|
+
-.6
|
|
5476
|
+
],
|
|
5477
|
+
[
|
|
5478
|
+
0,
|
|
5479
|
+
0,
|
|
5480
|
+
2,
|
|
5481
|
+
0,
|
|
5482
|
+
1,
|
|
5483
|
+
-386,
|
|
5484
|
+
-.4,
|
|
5485
|
+
200,
|
|
5486
|
+
0
|
|
5487
|
+
],
|
|
5488
|
+
[
|
|
5489
|
+
1,
|
|
5490
|
+
0,
|
|
5491
|
+
2,
|
|
5492
|
+
0,
|
|
5493
|
+
2,
|
|
5494
|
+
-301,
|
|
5495
|
+
0,
|
|
5496
|
+
129,
|
|
5497
|
+
-.1
|
|
5498
|
+
],
|
|
5499
|
+
[
|
|
5500
|
+
0,
|
|
5501
|
+
-1,
|
|
5502
|
+
2,
|
|
5503
|
+
-2,
|
|
5504
|
+
2,
|
|
5505
|
+
217,
|
|
5506
|
+
-.5,
|
|
5507
|
+
-95,
|
|
5508
|
+
.3
|
|
5509
|
+
],
|
|
5510
|
+
[
|
|
5511
|
+
1,
|
|
5512
|
+
0,
|
|
5513
|
+
0,
|
|
5514
|
+
-2,
|
|
5515
|
+
0,
|
|
5516
|
+
-158,
|
|
5517
|
+
0,
|
|
5518
|
+
-1,
|
|
5519
|
+
0
|
|
5520
|
+
],
|
|
5521
|
+
[
|
|
5522
|
+
0,
|
|
5523
|
+
0,
|
|
5524
|
+
2,
|
|
5525
|
+
-2,
|
|
5526
|
+
1,
|
|
5527
|
+
129,
|
|
5528
|
+
.1,
|
|
5529
|
+
-70,
|
|
5530
|
+
0
|
|
5531
|
+
],
|
|
5532
|
+
[
|
|
5533
|
+
-1,
|
|
5534
|
+
0,
|
|
5535
|
+
2,
|
|
5536
|
+
0,
|
|
5537
|
+
2,
|
|
5538
|
+
123,
|
|
5539
|
+
0,
|
|
5540
|
+
-53,
|
|
5541
|
+
0
|
|
5542
|
+
],
|
|
5543
|
+
[
|
|
5544
|
+
1,
|
|
5545
|
+
0,
|
|
5546
|
+
0,
|
|
5547
|
+
0,
|
|
5548
|
+
1,
|
|
5549
|
+
63,
|
|
5550
|
+
.1,
|
|
5551
|
+
-33,
|
|
5552
|
+
0
|
|
5553
|
+
],
|
|
5554
|
+
[
|
|
5555
|
+
0,
|
|
5556
|
+
0,
|
|
5557
|
+
0,
|
|
5558
|
+
2,
|
|
5559
|
+
0,
|
|
5560
|
+
63,
|
|
5561
|
+
0,
|
|
5562
|
+
-2,
|
|
5563
|
+
0
|
|
5564
|
+
],
|
|
5565
|
+
[
|
|
5566
|
+
-1,
|
|
5567
|
+
0,
|
|
5568
|
+
2,
|
|
5569
|
+
2,
|
|
5570
|
+
2,
|
|
5571
|
+
-59,
|
|
5572
|
+
0,
|
|
5573
|
+
26,
|
|
5574
|
+
0
|
|
5575
|
+
],
|
|
5576
|
+
[
|
|
5577
|
+
-1,
|
|
5578
|
+
0,
|
|
5579
|
+
0,
|
|
5580
|
+
0,
|
|
5581
|
+
1,
|
|
5582
|
+
-58,
|
|
5583
|
+
-.1,
|
|
5584
|
+
32,
|
|
5585
|
+
0
|
|
5586
|
+
],
|
|
5587
|
+
[
|
|
5588
|
+
1,
|
|
5589
|
+
0,
|
|
5590
|
+
2,
|
|
5591
|
+
0,
|
|
5592
|
+
1,
|
|
5593
|
+
-51,
|
|
5594
|
+
0,
|
|
5595
|
+
27,
|
|
5596
|
+
0
|
|
5597
|
+
]
|
|
5598
|
+
];
|
|
5599
|
+
function mul(a, b) {
|
|
5600
|
+
const out = new Array(9);
|
|
5601
|
+
for (let r = 0; r < 3; r++) for (let c = 0; c < 3; c++) out[3 * r + c] = a[3 * r] * b[c] + a[3 * r + 1] * b[3 + c] + a[3 * r + 2] * b[6 + c];
|
|
5602
|
+
return out;
|
|
5603
|
+
}
|
|
5604
|
+
function rx(a) {
|
|
5605
|
+
const c = Math.cos(a);
|
|
5606
|
+
const s = Math.sin(a);
|
|
5607
|
+
return [
|
|
5608
|
+
1,
|
|
5609
|
+
0,
|
|
5610
|
+
0,
|
|
5611
|
+
0,
|
|
5612
|
+
c,
|
|
5613
|
+
s,
|
|
5614
|
+
0,
|
|
5615
|
+
-s,
|
|
5616
|
+
c
|
|
5617
|
+
];
|
|
5618
|
+
}
|
|
5619
|
+
function ry(a) {
|
|
5620
|
+
const c = Math.cos(a);
|
|
5621
|
+
const s = Math.sin(a);
|
|
5622
|
+
return [
|
|
5623
|
+
c,
|
|
5624
|
+
0,
|
|
5625
|
+
-s,
|
|
5626
|
+
0,
|
|
5627
|
+
1,
|
|
5628
|
+
0,
|
|
5629
|
+
s,
|
|
5630
|
+
0,
|
|
5631
|
+
c
|
|
5632
|
+
];
|
|
5633
|
+
}
|
|
5634
|
+
function rz(a) {
|
|
5635
|
+
const c = Math.cos(a);
|
|
5636
|
+
const s = Math.sin(a);
|
|
5637
|
+
return [
|
|
5638
|
+
c,
|
|
5639
|
+
s,
|
|
5640
|
+
0,
|
|
5641
|
+
-s,
|
|
5642
|
+
c,
|
|
5643
|
+
0,
|
|
5644
|
+
0,
|
|
5645
|
+
0,
|
|
5646
|
+
1
|
|
5647
|
+
];
|
|
5648
|
+
}
|
|
5649
|
+
function temeToEclipticAt(jd) {
|
|
5650
|
+
const T = (jd - J2000_JD$1) / 36525;
|
|
5651
|
+
const zeta = (2306.2181 * T + .30188 * T * T + .017998 * T ** 3) * ARCSEC;
|
|
5652
|
+
const theta = (2004.3109 * T - .42665 * T * T - .041833 * T ** 3) * ARCSEC;
|
|
5653
|
+
const z = (2306.2181 * T + 1.09468 * T * T + .018203 * T ** 3) * ARCSEC;
|
|
5654
|
+
const l = 134.96298139 + 477198.8673981 * T + .0086972 * T * T;
|
|
5655
|
+
const lp = 357.52772333 + 35999.05034 * T - 1603e-7 * T * T;
|
|
5656
|
+
const F = 93.27191028 + 483202.0175381 * T - .0036825 * T * T;
|
|
5657
|
+
const D = 297.85036306 + 445267.11148 * T - .0019142 * T * T;
|
|
5658
|
+
const om = 125.04452222 - 1934.1362608 * T + .0020708 * T * T;
|
|
5659
|
+
let dpsi = 0;
|
|
5660
|
+
let deps = 0;
|
|
5661
|
+
for (const [kl, klp, kF, kD, kOm, a, b, c, d] of NUTATION) {
|
|
5662
|
+
const arg = (kl * l + klp * lp + kF * F + kD * D + kOm * om) * DEG$10;
|
|
5663
|
+
dpsi += (a + b * T) * Math.sin(arg);
|
|
5664
|
+
deps += (c + d * T) * Math.cos(arg);
|
|
5665
|
+
}
|
|
5666
|
+
dpsi *= NUT_UNIT;
|
|
5667
|
+
deps *= NUT_UNIT;
|
|
5668
|
+
const epsMean = (84381.448 - 46.815 * T - 59e-5 * T * T + .001813 * T ** 3) * ARCSEC;
|
|
5669
|
+
const eqEquinoxes = dpsi * Math.cos(epsMean);
|
|
5670
|
+
const toJ2000 = mul(mul(mul(mul(rz(zeta), ry(-theta)), rz(z)), mul(mul(rx(-epsMean), rz(dpsi)), rx(epsMean + deps))), rz(-eqEquinoxes));
|
|
5671
|
+
return mul(rx(EARTH_OBLIQUITY_DEG * DEG$10), toJ2000);
|
|
5672
|
+
}
|
|
5673
|
+
var cachedJd = NaN;
|
|
5674
|
+
var cached = [
|
|
5675
|
+
1,
|
|
5676
|
+
0,
|
|
5677
|
+
0,
|
|
5678
|
+
0,
|
|
5679
|
+
1,
|
|
5680
|
+
0,
|
|
5681
|
+
0,
|
|
5682
|
+
0,
|
|
5683
|
+
1
|
|
5684
|
+
];
|
|
5685
|
+
function temeToEclipticMatrix(jd) {
|
|
5686
|
+
if (!(Math.abs(jd - cachedJd) <= REUSE_DAYS)) {
|
|
5687
|
+
cached = temeToEclipticAt(jd);
|
|
5688
|
+
cachedJd = jd;
|
|
5689
|
+
}
|
|
5690
|
+
return cached;
|
|
5691
|
+
}
|
|
5692
|
+
function temeToEcliptic(x, y, z, jd) {
|
|
5693
|
+
const m = temeToEclipticMatrix(jd);
|
|
5694
|
+
return [
|
|
5695
|
+
m[0] * x + m[1] * y + m[2] * z,
|
|
5696
|
+
m[3] * x + m[4] * y + m[5] * z,
|
|
5697
|
+
m[6] * x + m[7] * y + m[8] * z
|
|
5698
|
+
];
|
|
5699
|
+
}
|
|
5700
|
+
|
|
5701
|
+
//#endregion
|
|
5702
|
+
//#region src/lib/math/orbit/sgp4.ts
|
|
5703
|
+
var JD_UNIX_EPOCH = 2440587.5;
|
|
5322
5704
|
function jdToIso(jd) {
|
|
5323
|
-
return (/* @__PURE__ */ new Date((jd - JD_UNIX_EPOCH
|
|
5705
|
+
return (/* @__PURE__ */ new Date((jd - JD_UNIX_EPOCH) * 864e5)).toISOString();
|
|
5324
5706
|
}
|
|
5325
5707
|
function buildSatrec(inputs, name) {
|
|
5326
5708
|
const satrec = json2satrec({
|
|
@@ -5358,25 +5740,19 @@ function sgp4PositionTEME(satrec, jd) {
|
|
|
5358
5740
|
z
|
|
5359
5741
|
];
|
|
5360
5742
|
}
|
|
5361
|
-
function temeKmToThreeJS(x, y, z) {
|
|
5743
|
+
function temeKmToThreeJS(x, y, z, jd) {
|
|
5362
5744
|
const scale = 10 / AU_KM;
|
|
5363
|
-
const
|
|
5364
|
-
let ys = y * scale;
|
|
5365
|
-
let zs = z * scale;
|
|
5366
|
-
const yEcl = ys * COS_EPS$4 + zs * SIN_EPS$4;
|
|
5367
|
-
const zEcl = -ys * SIN_EPS$4 + zs * COS_EPS$4;
|
|
5368
|
-
ys = yEcl;
|
|
5369
|
-
zs = zEcl;
|
|
5745
|
+
const [xe, ye, ze] = temeToEcliptic(x, y, z, jd);
|
|
5370
5746
|
return [
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
-
|
|
5747
|
+
xe * scale,
|
|
5748
|
+
ze * scale,
|
|
5749
|
+
-ye * scale
|
|
5374
5750
|
];
|
|
5375
5751
|
}
|
|
5376
5752
|
function sgp4PositionScene(satrec, jd) {
|
|
5377
5753
|
const teme = sgp4PositionTEME(satrec, jd);
|
|
5378
5754
|
if (!teme) return null;
|
|
5379
|
-
return temeKmToThreeJS(teme[0], teme[1], teme[2]);
|
|
5755
|
+
return temeKmToThreeJS(teme[0], teme[1], teme[2], jd);
|
|
5380
5756
|
}
|
|
5381
5757
|
|
|
5382
5758
|
//#endregion
|
|
@@ -5445,32 +5821,109 @@ function yieldToMain() {
|
|
|
5445
5821
|
}
|
|
5446
5822
|
|
|
5447
5823
|
//#endregion
|
|
5448
|
-
//#region src/lib/
|
|
5449
|
-
var
|
|
5450
|
-
var
|
|
5451
|
-
var
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5824
|
+
//#region src/lib/math/orbit/position.ts
|
|
5825
|
+
var DEG2RAD$8 = Math.PI / 180;
|
|
5826
|
+
var COS_EPS$2 = Math.cos(EARTH_OBLIQUITY_DEG * DEG2RAD$8);
|
|
5827
|
+
var SIN_EPS$2 = Math.sin(EARTH_OBLIQUITY_DEG * DEG2RAD$8);
|
|
5828
|
+
function orbitalToThreeJS(xOrb, yOrb, w, i, om, equatorial = false) {
|
|
5829
|
+
const cosW = Math.cos(w * DEG2RAD$8);
|
|
5830
|
+
const sinW = Math.sin(w * DEG2RAD$8);
|
|
5831
|
+
const cosI = Math.cos(i * DEG2RAD$8);
|
|
5832
|
+
const sinI = Math.sin(i * DEG2RAD$8);
|
|
5833
|
+
const cosOm = Math.cos(om * DEG2RAD$8);
|
|
5834
|
+
const sinOm = Math.sin(om * DEG2RAD$8);
|
|
5835
|
+
const x = (cosOm * cosW - sinOm * sinW * cosI) * xOrb + (-cosOm * sinW - sinOm * cosW * cosI) * yOrb;
|
|
5836
|
+
let y = (sinOm * cosW + cosOm * sinW * cosI) * xOrb + (-sinOm * sinW + cosOm * cosW * cosI) * yOrb;
|
|
5837
|
+
let z = sinW * sinI * xOrb + cosW * sinI * yOrb;
|
|
5838
|
+
if (equatorial) {
|
|
5839
|
+
const yEcl = y * COS_EPS$2 + z * SIN_EPS$2;
|
|
5840
|
+
const zEcl = -y * SIN_EPS$2 + z * COS_EPS$2;
|
|
5841
|
+
y = yEcl;
|
|
5842
|
+
z = zEcl;
|
|
5843
|
+
}
|
|
5844
|
+
return [
|
|
5845
|
+
x * 10,
|
|
5846
|
+
z * 10,
|
|
5847
|
+
-y * 10
|
|
5848
|
+
];
|
|
5455
5849
|
}
|
|
5456
|
-
function
|
|
5457
|
-
return
|
|
5850
|
+
function elementsJd(el, jd) {
|
|
5851
|
+
return el.equatorial ? jd : utcToTdb(jd);
|
|
5458
5852
|
}
|
|
5459
|
-
function
|
|
5460
|
-
return
|
|
5853
|
+
function clockJd(el, t) {
|
|
5854
|
+
return el.equatorial ? t : tdbToUtc(t);
|
|
5461
5855
|
}
|
|
5462
|
-
function
|
|
5463
|
-
return (
|
|
5856
|
+
function propagateOrbitAngles(el, jd) {
|
|
5857
|
+
return anglesAt(el, elementsJd(el, jd));
|
|
5464
5858
|
}
|
|
5465
|
-
function
|
|
5466
|
-
|
|
5859
|
+
function anglesAt(el, t) {
|
|
5860
|
+
const { omDot, wDot, om, w, epoch } = el;
|
|
5861
|
+
if (!omDot && !wDot) return el;
|
|
5862
|
+
const dt = t - epoch;
|
|
5863
|
+
return {
|
|
5864
|
+
...el,
|
|
5865
|
+
om: omDot ? om + omDot * dt : om,
|
|
5866
|
+
w: wDot ? w + wDot * dt : w
|
|
5867
|
+
};
|
|
5868
|
+
}
|
|
5869
|
+
function orbitalElementsToPositionJD(el, jd) {
|
|
5870
|
+
const { a, e, i, ma, n, epoch } = el;
|
|
5871
|
+
if (!isFinite(a) || !isFinite(e) || !isFinite(ma) || !isFinite(n)) {
|
|
5872
|
+
console.warn(`NaN in orbital elements: a=${a} e=${e} ma=${ma} n=${n}`);
|
|
5873
|
+
return null;
|
|
5874
|
+
}
|
|
5875
|
+
const t = elementsJd(el, jd);
|
|
5876
|
+
const M = (ma + n * (t - epoch)) * DEG2RAD$8;
|
|
5877
|
+
const { om: omPropagated, w: wPropagated } = anglesAt(el, t);
|
|
5878
|
+
let nu;
|
|
5879
|
+
let r;
|
|
5880
|
+
if (e < 1 || a > 0) {
|
|
5881
|
+
const eClamped = Math.min(e, .9999999);
|
|
5882
|
+
const E = solveKepler(M, eClamped);
|
|
5883
|
+
const sinNu = Math.sqrt(1 - eClamped * eClamped) * Math.sin(E) / (1 - eClamped * Math.cos(E));
|
|
5884
|
+
const cosNu = (Math.cos(E) - eClamped) / (1 - eClamped * Math.cos(E));
|
|
5885
|
+
nu = Math.atan2(sinNu, cosNu);
|
|
5886
|
+
r = a * (1 - eClamped * Math.cos(E));
|
|
5887
|
+
} else {
|
|
5888
|
+
const H = solveKeplerHyperbolic(M, e);
|
|
5889
|
+
if (!isFinite(H)) {
|
|
5890
|
+
console.warn(`solveKeplerHyperbolic overflow: M=${M} e=${e}`);
|
|
5891
|
+
return null;
|
|
5892
|
+
}
|
|
5893
|
+
const denom = e * Math.cosh(H) - 1;
|
|
5894
|
+
if (Math.abs(denom) < 1e-15) {
|
|
5895
|
+
console.warn(`Hyperbolic denom near zero: H=${H} e=${e} denom=${denom}`);
|
|
5896
|
+
return null;
|
|
5897
|
+
}
|
|
5898
|
+
const sinNu = Math.sqrt(e * e - 1) * Math.sinh(H) / denom;
|
|
5899
|
+
const cosNu = (e - Math.cosh(H)) / denom;
|
|
5900
|
+
nu = Math.atan2(sinNu, cosNu);
|
|
5901
|
+
r = a * (1 - e * Math.cosh(H));
|
|
5902
|
+
}
|
|
5903
|
+
const xOrb = r * Math.cos(nu);
|
|
5904
|
+
const yOrb = r * Math.sin(nu);
|
|
5905
|
+
if (!isFinite(xOrb) || !isFinite(yOrb)) {
|
|
5906
|
+
console.warn(`Non-finite orbital position: r=${r} nu=${nu} xOrb=${xOrb} yOrb=${yOrb} a=${a} e=${e}`);
|
|
5907
|
+
return null;
|
|
5908
|
+
}
|
|
5909
|
+
return orbitalToThreeJS(xOrb, yOrb, wPropagated, i, omPropagated, el.equatorial);
|
|
5910
|
+
}
|
|
5911
|
+
function parabolicToPositionJD(el, jd) {
|
|
5912
|
+
const { q, tp, i, om, w } = el;
|
|
5913
|
+
if (q == null || tp == null || !isFinite(q) || !isFinite(tp)) return null;
|
|
5914
|
+
const result = solveBarker(q, tp, elementsJd(el, jd));
|
|
5915
|
+
if (!result) return null;
|
|
5916
|
+
const xOrb = result.r * Math.cos(result.nu);
|
|
5917
|
+
const yOrb = result.r * Math.sin(result.nu);
|
|
5918
|
+
if (!isFinite(xOrb) || !isFinite(yOrb)) return null;
|
|
5919
|
+
return orbitalToThreeJS(xOrb, yOrb, w, i, om, el.equatorial);
|
|
5467
5920
|
}
|
|
5468
5921
|
|
|
5469
5922
|
//#endregion
|
|
5470
5923
|
//#region src/lib/math/orbit/soa.ts
|
|
5471
|
-
var DEG2RAD$
|
|
5472
|
-
var COS_EPS$
|
|
5473
|
-
var SIN_EPS$
|
|
5924
|
+
var DEG2RAD$7 = Math.PI / 180;
|
|
5925
|
+
var COS_EPS$1 = Math.cos(EARTH_OBLIQUITY_DEG * DEG2RAD$7);
|
|
5926
|
+
var SIN_EPS$1 = Math.sin(EARTH_OBLIQUITY_DEG * DEG2RAD$7);
|
|
5474
5927
|
var KM_TO_SCENE = 10 / AU_KM;
|
|
5475
5928
|
var KIND_SKIP = 0;
|
|
5476
5929
|
var KIND_KEPLER = 1;
|
|
@@ -5529,8 +5982,10 @@ async function packBodiesSliced(bodies, skip, applyFlagFilter = false) {
|
|
|
5529
5982
|
}
|
|
5530
5983
|
if (!packRowInto(cols, idx, bodies[idx], skip)) continue;
|
|
5531
5984
|
const d = bodies[idx].data;
|
|
5532
|
-
|
|
5533
|
-
|
|
5985
|
+
const s = clockJd(d, d.validityStart);
|
|
5986
|
+
const e = clockJd(d, d.validityEnd);
|
|
5987
|
+
if (s < start) start = s;
|
|
5988
|
+
if (e > end) end = e;
|
|
5534
5989
|
}
|
|
5535
5990
|
cols.validityStart = start === Infinity ? -Infinity : start;
|
|
5536
5991
|
cols.validityEnd = end === -Infinity ? Infinity : end;
|
|
@@ -5870,6 +6325,11 @@ var TYPE_COLOR_PROBE = "#d5cfe7";
|
|
|
5870
6325
|
var SUN_ID = "naif-10";
|
|
5871
6326
|
var EARTH_ID = "naif-399";
|
|
5872
6327
|
var SSB_ID = "naif-0";
|
|
6328
|
+
function naifId(objectId) {
|
|
6329
|
+
if (!objectId.startsWith("naif-")) return null;
|
|
6330
|
+
const value = Number.parseInt(objectId.slice(5), 10);
|
|
6331
|
+
return Number.isFinite(value) ? value : null;
|
|
6332
|
+
}
|
|
5873
6333
|
function dominantPlanetId(id) {
|
|
5874
6334
|
const m = /^naif-([1-9])$/.exec(id);
|
|
5875
6335
|
return m ? `naif-${m[1]}99` : null;
|
|
@@ -5937,10 +6397,6 @@ function resolveBodyColor(data) {
|
|
|
5937
6397
|
}
|
|
5938
6398
|
return DEFAULT_BODY_COLOR;
|
|
5939
6399
|
}
|
|
5940
|
-
var UNKNOWN_SURFACE_COLOR = "#6b6b6b";
|
|
5941
|
-
function bodyMeshColor(data) {
|
|
5942
|
-
return data.color ?? UNKNOWN_SURFACE_COLOR;
|
|
5943
|
-
}
|
|
5944
6400
|
|
|
5945
6401
|
//#endregion
|
|
5946
6402
|
//#region src/lib/math/orbit/partition.ts
|
|
@@ -6202,6 +6658,8 @@ var MinorBucket = class {
|
|
|
6202
6658
|
keys: new Float64Array(counts[b]).fill(NO_KEY)
|
|
6203
6659
|
});
|
|
6204
6660
|
}
|
|
6661
|
+
const clockStarts = this.chunks.map((chunk) => tdbToUtc(chunk.validityStart));
|
|
6662
|
+
const clockEnds = this.chunks.map((chunk) => tdbToUtc(chunk.validityEnd));
|
|
6205
6663
|
const starts = new Array(k).fill(Infinity);
|
|
6206
6664
|
const ends = new Array(k).fill(-Infinity);
|
|
6207
6665
|
const writeIdx = new Array(k).fill(0);
|
|
@@ -6222,8 +6680,11 @@ var MinorBucket = class {
|
|
|
6222
6680
|
const key = rowKey(cols, i);
|
|
6223
6681
|
g.keys[outIdx] = key;
|
|
6224
6682
|
if (fillOrbitColumnRow(cols, i, g.cols, outIdx, key, skip)) {
|
|
6225
|
-
|
|
6226
|
-
|
|
6683
|
+
const tle = g.cols.equatorial[outIdx] === 1;
|
|
6684
|
+
const start = tle ? cols.validityStart : clockStarts[c];
|
|
6685
|
+
const end = tle ? cols.validityEnd : clockEnds[c];
|
|
6686
|
+
if (start < starts[b]) starts[b] = start;
|
|
6687
|
+
if (end > ends[b]) ends[b] = end;
|
|
6227
6688
|
}
|
|
6228
6689
|
if (g.colors && tmp) {
|
|
6229
6690
|
const data = materializeBodyData(cols, i, this.labels, this.parentIdType);
|
|
@@ -6618,17 +7079,23 @@ async function fetchWithTimeout(input, init = {}, timeoutMs = BOOT_FETCH_TIMEOUT
|
|
|
6618
7079
|
|
|
6619
7080
|
//#endregion
|
|
6620
7081
|
//#region src/lib/fetch/systems-global.ts
|
|
6621
|
-
var
|
|
7082
|
+
var phases = /* @__PURE__ */ new Map();
|
|
6622
7083
|
var gmKm3s2 = /* @__PURE__ */ new Map();
|
|
6623
7084
|
var loadPromise$1 = null;
|
|
6624
7085
|
function loadSystemsGlobal() {
|
|
6625
7086
|
if (loadPromise$1) return loadPromise$1;
|
|
6626
7087
|
const p = (async () => {
|
|
6627
7088
|
const r = await fetchWithTimeout(`${dataBase()}/v1/systems/global.json`);
|
|
6628
|
-
if (!r.ok)
|
|
7089
|
+
if (!r.ok) throw new Error(`systems/global.json: ${r.status}`);
|
|
6629
7090
|
const raw = await r.json();
|
|
6630
7091
|
if (raw.gm) for (const [k, v] of Object.entries(raw.gm)) gmKm3s2.set(parseInt(k, 10), v);
|
|
6631
|
-
if (raw.nut_prec_angles) for (const [k, v] of Object.entries(raw.nut_prec_angles))
|
|
7092
|
+
if (raw.nut_prec_angles) for (const [k, v] of Object.entries(raw.nut_prec_angles)) {
|
|
7093
|
+
const phaseDegree = raw.nut_prec_phase_degree?.[k] ?? 1;
|
|
7094
|
+
phases.set(parseInt(k, 10), {
|
|
7095
|
+
angles: v,
|
|
7096
|
+
phaseDegree
|
|
7097
|
+
});
|
|
7098
|
+
}
|
|
6632
7099
|
})();
|
|
6633
7100
|
p.catch(() => {
|
|
6634
7101
|
if (loadPromise$1 === p) loadPromise$1 = null;
|
|
@@ -6636,11 +7103,14 @@ function loadSystemsGlobal() {
|
|
|
6636
7103
|
loadPromise$1 = p;
|
|
6637
7104
|
return p;
|
|
6638
7105
|
}
|
|
6639
|
-
function
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
return
|
|
7106
|
+
function nutPrecFor(id, sums) {
|
|
7107
|
+
const naif = naifId(id);
|
|
7108
|
+
if (naif === null || !sums) return void 0;
|
|
7109
|
+
const owned = phases.get(naif >= 100 ? Math.trunc(naif / 100) : naif);
|
|
7110
|
+
return owned && {
|
|
7111
|
+
...sums,
|
|
7112
|
+
...owned
|
|
7113
|
+
};
|
|
6644
7114
|
}
|
|
6645
7115
|
function getGmKm3s2(naifId) {
|
|
6646
7116
|
return gmKm3s2.get(naifId);
|
|
@@ -7433,7 +7903,7 @@ function parseProbesPayload(buffer, startJd, endJd, float64Coeffs) {
|
|
|
7433
7903
|
const probeCount = view.getUint32(24, true);
|
|
7434
7904
|
const subchunkDays = view.getFloat32(28, true);
|
|
7435
7905
|
const subchunkS = subchunkDays * SECONDS_PER_DAY$2;
|
|
7436
|
-
const chunkStartEt =
|
|
7906
|
+
const chunkStartEt = tdbJdToEt(startJd);
|
|
7437
7907
|
const probes = [];
|
|
7438
7908
|
let offset = HEADER_SIZE$2;
|
|
7439
7909
|
for (let p = 0; p < probeCount; p++) {
|
|
@@ -7558,11 +8028,12 @@ function findSegmentIndex(starts, ends, jd) {
|
|
|
7558
8028
|
return jd < ends[lo] ? lo : -1;
|
|
7559
8029
|
}
|
|
7560
8030
|
function chebyshevPositionKm(body, jd) {
|
|
7561
|
-
const
|
|
8031
|
+
const tdb = utcToTdb(jd);
|
|
8032
|
+
const idx = findSegmentIndex(body.startJds, body.endJds, tdb);
|
|
7562
8033
|
if (idx < 0) return null;
|
|
7563
8034
|
const start = body.startJds[idx];
|
|
7564
8035
|
const end = body.endJds[idx];
|
|
7565
|
-
const tau = 2 * (
|
|
8036
|
+
const tau = 2 * (tdb - start) / (end - start) - 1;
|
|
7566
8037
|
const N = body.coeffsPerAxis;
|
|
7567
8038
|
const coeffs = body.coeffs;
|
|
7568
8039
|
const base = idx * 3 * N;
|
|
@@ -7599,11 +8070,12 @@ function chebyshevPositionScene(body, jd) {
|
|
|
7599
8070
|
];
|
|
7600
8071
|
}
|
|
7601
8072
|
function chebyshevStateKm(body, jd) {
|
|
7602
|
-
const
|
|
8073
|
+
const tdb = utcToTdb(jd);
|
|
8074
|
+
const idx = findSegmentIndex(body.startJds, body.endJds, tdb);
|
|
7603
8075
|
if (idx < 0) return null;
|
|
7604
8076
|
const start = body.startJds[idx];
|
|
7605
8077
|
const end = body.endJds[idx];
|
|
7606
|
-
const tau = 2 * (
|
|
8078
|
+
const tau = 2 * (tdb - start) / (end - start) - 1;
|
|
7607
8079
|
const dTauDt = 2 / (end - start);
|
|
7608
8080
|
const N = body.coeffsPerAxis;
|
|
7609
8081
|
const coeffs = body.coeffs;
|
|
@@ -7651,7 +8123,7 @@ function chebyshevStateKm(body, jd) {
|
|
|
7651
8123
|
|
|
7652
8124
|
//#endregion
|
|
7653
8125
|
//#region src/lib/math/orbit/state.ts
|
|
7654
|
-
var DEG2RAD$
|
|
8126
|
+
var DEG2RAD$6 = Math.PI / 180;
|
|
7655
8127
|
var RAD2DEG$1 = 180 / Math.PI;
|
|
7656
8128
|
var SEC_PER_DAY = 86400;
|
|
7657
8129
|
var AU_PER_DAY_TO_KM_PER_SEC = AU_KM / SEC_PER_DAY;
|
|
@@ -7920,7 +8392,7 @@ var RAD2DEG = 180 / Math.PI;
|
|
|
7920
8392
|
function keplerPureElements(sub, subStartEt, muKm3S2) {
|
|
7921
8393
|
if (muKm3S2 <= 0) return null;
|
|
7922
8394
|
const nRadS = Math.sqrt(muKm3S2 / (sub.aKm * sub.aKm * sub.aKm));
|
|
7923
|
-
const epoch =
|
|
8395
|
+
const epoch = etToTdbJd(subStartEt + sub.tAnchorOffsetS);
|
|
7924
8396
|
return {
|
|
7925
8397
|
a: sub.aKm / AU_KM,
|
|
7926
8398
|
e: sub.e,
|
|
@@ -7934,7 +8406,7 @@ function keplerPureElements(sub, subStartEt, muKm3S2) {
|
|
|
7934
8406
|
};
|
|
7935
8407
|
}
|
|
7936
8408
|
function keplerDriftElements(sub, subStartEt) {
|
|
7937
|
-
const epoch =
|
|
8409
|
+
const epoch = etToTdbJd(subStartEt + sub.tAnchorOffsetS);
|
|
7938
8410
|
return {
|
|
7939
8411
|
a: sub.aKm / AU_KM,
|
|
7940
8412
|
e: sub.e,
|
|
@@ -7962,7 +8434,7 @@ function chebyshevElements(probe, jd, muKm3S2) {
|
|
|
7962
8434
|
state.velocity[0] * KM_DAY_TO_AU_DAY,
|
|
7963
8435
|
state.velocity[1] * KM_DAY_TO_AU_DAY,
|
|
7964
8436
|
state.velocity[2] * KM_DAY_TO_AU_DAY
|
|
7965
|
-
], muAuDay2, jd);
|
|
8437
|
+
], muAuDay2, utcToTdb(jd));
|
|
7966
8438
|
}
|
|
7967
8439
|
function probeOsculatingElements(probe, jd, muKm3S2) {
|
|
7968
8440
|
const idx = findSubChunkIndex(probe, jdToEt(jd));
|
|
@@ -8351,7 +8823,7 @@ function chebyshevOsculatingElements(body, parentId, jd, origin) {
|
|
|
8351
8823
|
(state.velocity[0] - (from?.velocity[0] ?? 0)) * KM_DAY_TO_AU_DAY,
|
|
8352
8824
|
(state.velocity[1] - (from?.velocity[1] ?? 0)) * KM_DAY_TO_AU_DAY,
|
|
8353
8825
|
(state.velocity[2] - (from?.velocity[2] ?? 0)) * KM_DAY_TO_AU_DAY
|
|
8354
|
-
], muAuDay2, jd);
|
|
8826
|
+
], muAuDay2, utcToTdb(jd));
|
|
8355
8827
|
}
|
|
8356
8828
|
function chebyshevHelioElements(body, jd, sun) {
|
|
8357
8829
|
if (!sun || body.parentId !== SSB_NAIF_ID || body.naifId === SUN_NAIF_ID) return null;
|
|
@@ -8845,7 +9317,7 @@ function isChebyshev(zoom) {
|
|
|
8845
9317
|
return zoom.shape === "chunked";
|
|
8846
9318
|
}
|
|
8847
9319
|
function chunkIndexForJd(zone, jd) {
|
|
8848
|
-
const idx = Math.floor((jd - zone.start_jd) / zone.chunk_days);
|
|
9320
|
+
const idx = Math.floor((utcToTdb(jd) - zone.start_jd) / zone.chunk_days);
|
|
8849
9321
|
return Math.max(0, Math.min(zone.chunks - 1, idx));
|
|
8850
9322
|
}
|
|
8851
9323
|
function isProbeZone(entry) {
|
|
@@ -9184,8 +9656,8 @@ var ChebyshevStore = class extends ChunkWindow {
|
|
|
9184
9656
|
const params = this.zoneParams.get(zone);
|
|
9185
9657
|
if (!params) return null;
|
|
9186
9658
|
return {
|
|
9187
|
-
start: params.start_jd,
|
|
9188
|
-
end: params.end_jd
|
|
9659
|
+
start: tdbToUtc(params.start_jd),
|
|
9660
|
+
end: tdbToUtc(params.end_jd)
|
|
9189
9661
|
};
|
|
9190
9662
|
}
|
|
9191
9663
|
isAwaited(objectId, jd) {
|
|
@@ -9504,6 +9976,28 @@ function rowsFor(chunk, id) {
|
|
|
9504
9976
|
return index.get(id) ?? NO_ROWS;
|
|
9505
9977
|
}
|
|
9506
9978
|
|
|
9979
|
+
//#endregion
|
|
9980
|
+
//#region src/lib/fetch/version-check.ts
|
|
9981
|
+
var CHECK_TIMEOUT_MS = 15e3;
|
|
9982
|
+
async function dataVersionChanged() {
|
|
9983
|
+
try {
|
|
9984
|
+
const res = await fetch(`${dataBase()}/v1/metadata.json`, {
|
|
9985
|
+
cache: "no-store",
|
|
9986
|
+
signal: AbortSignal.timeout(CHECK_TIMEOUT_MS)
|
|
9987
|
+
});
|
|
9988
|
+
if (!res.ok) return false;
|
|
9989
|
+
const meta = await res.json();
|
|
9990
|
+
const live = getDataVersions();
|
|
9991
|
+
if (Object.keys(live).length === 0) return false;
|
|
9992
|
+
const next = meta.versions ?? {};
|
|
9993
|
+
const keys = new Set([...Object.keys(live), ...Object.keys(next)]);
|
|
9994
|
+
for (const k of keys) if (live[k] !== next[k]) return true;
|
|
9995
|
+
return false;
|
|
9996
|
+
} catch {
|
|
9997
|
+
return false;
|
|
9998
|
+
}
|
|
9999
|
+
}
|
|
10000
|
+
|
|
9507
10001
|
//#endregion
|
|
9508
10002
|
//#region src/lib/fetch/gz.ts
|
|
9509
10003
|
function gunzip(res) {
|
|
@@ -9537,12 +10031,12 @@ function memoizedGzJson(url, opts = {}) {
|
|
|
9537
10031
|
//#endregion
|
|
9538
10032
|
//#region src/lib/fetch/bundle-cache.ts
|
|
9539
10033
|
var MAX_BUNDLES = 24;
|
|
9540
|
-
var cache$
|
|
10034
|
+
var cache$3 = /* @__PURE__ */ new Map();
|
|
9541
10035
|
function fetchGzipBundle(url, init) {
|
|
9542
|
-
let p = cache$
|
|
10036
|
+
let p = cache$3.get(url);
|
|
9543
10037
|
if (p) {
|
|
9544
|
-
cache$
|
|
9545
|
-
cache$
|
|
10038
|
+
cache$3.delete(url);
|
|
10039
|
+
cache$3.set(url, p);
|
|
9546
10040
|
}
|
|
9547
10041
|
if (!p) {
|
|
9548
10042
|
p = (async () => {
|
|
@@ -9553,13 +10047,13 @@ function fetchGzipBundle(url, init) {
|
|
|
9553
10047
|
}
|
|
9554
10048
|
return gunzipJson(res);
|
|
9555
10049
|
})();
|
|
9556
|
-
cache$
|
|
10050
|
+
cache$3.set(url, p);
|
|
9557
10051
|
p.catch(() => {
|
|
9558
|
-
if (cache$
|
|
10052
|
+
if (cache$3.get(url) === p) cache$3.delete(url);
|
|
9559
10053
|
});
|
|
9560
|
-
for (const key of cache$
|
|
9561
|
-
if (cache$
|
|
9562
|
-
cache$
|
|
10054
|
+
for (const key of cache$3.keys()) {
|
|
10055
|
+
if (cache$3.size <= MAX_BUNDLES) break;
|
|
10056
|
+
cache$3.delete(key);
|
|
9563
10057
|
}
|
|
9564
10058
|
}
|
|
9565
10059
|
return p;
|
|
@@ -9653,9 +10147,11 @@ async function earthZoneEndJd() {
|
|
|
9653
10147
|
return zoom && isDateSegmented(zoom) ? unixMsToJD(lastCoveredMs(zoom)) : Infinity;
|
|
9654
10148
|
}
|
|
9655
10149
|
async function coverageOf(id) {
|
|
9656
|
-
const
|
|
9657
|
-
const
|
|
9658
|
-
|
|
10150
|
+
const detail = await fetchObjectDetail(id, false);
|
|
10151
|
+
const windows = detail.global?.coverage?.windows ?? [];
|
|
10152
|
+
const tle = detail.global?.orbit?.scale === "planet";
|
|
10153
|
+
const openEnd = tle ? await earthZoneEndJd() : Infinity;
|
|
10154
|
+
return windows.map(([start, end]) => [start ?? -Infinity, end == null ? openEnd : tle ? end : tdbToUtc(end)]).filter(([start, end]) => end > start);
|
|
9659
10155
|
}
|
|
9660
10156
|
function nearestCoveredJd(windows, jd) {
|
|
9661
10157
|
let best = null;
|
|
@@ -9731,7 +10227,7 @@ function bodyDataFromGlobal(id, detail) {
|
|
|
9731
10227
|
validityStart: omm ? orbit.epoch_jd - SGP4_VALIDITY_SLACK_DAYS : -Infinity,
|
|
9732
10228
|
validityEnd: omm ? orbit.epoch_jd + SGP4_VALIDITY_SLACK_DAYS : Infinity,
|
|
9733
10229
|
orbitalSource: parseOrbitalSource(orbit.source),
|
|
9734
|
-
...coverageStart != null ? { visibleFromDays: coverageStart - J2000_JD$
|
|
10230
|
+
...coverageStart != null ? { visibleFromDays: coverageStart - J2000_JD$1 } : {},
|
|
9735
10231
|
...isParabolic ? {
|
|
9736
10232
|
q: orbit.q,
|
|
9737
10233
|
tp: orbit.tp
|
|
@@ -9829,34 +10325,44 @@ async function ensureTargetStreamed(ctx, targetId) {
|
|
|
9829
10325
|
|
|
9830
10326
|
//#endregion
|
|
9831
10327
|
//#region src/lib/math/orientation.ts
|
|
9832
|
-
var DEG2RAD$
|
|
9833
|
-
var J2000_JD$1 = 2451545;
|
|
10328
|
+
var DEG2RAD$5 = Math.PI / 180;
|
|
9834
10329
|
var DAYS_PER_CENTURY = 36525;
|
|
9835
|
-
function
|
|
9836
|
-
const dt = currentJd - J2000_JD$1;
|
|
10330
|
+
function iauAngles(orientation, currentJd, nutPrec) {
|
|
10331
|
+
const dt = utcToTdb(currentJd) - J2000_JD$1;
|
|
9837
10332
|
const T = dt / DAYS_PER_CENTURY;
|
|
9838
10333
|
let raDeg = orientation.pole_ra_0 + orientation.pole_ra_1 * T;
|
|
9839
10334
|
let decDeg = orientation.pole_dec_0 + orientation.pole_dec_1 * T;
|
|
9840
10335
|
let wDeg = orientation.w0 + orientation.w1 * dt + orientation.w2 * dt * dt;
|
|
9841
10336
|
if (nutPrec) {
|
|
9842
10337
|
const { ra, dec, pm, angles } = nutPrec;
|
|
9843
|
-
const
|
|
10338
|
+
const k = nutPrec.phaseDegree + 1;
|
|
10339
|
+
const n = Math.min(Math.floor(angles.length / k), Math.max(ra.length, dec.length, pm.length));
|
|
9844
10340
|
for (let i = 0; i < n; i++) {
|
|
9845
|
-
|
|
10341
|
+
let thetaDeg = 0;
|
|
10342
|
+
for (let j = k - 1; j >= 0; j--) thetaDeg = thetaDeg * T + angles[k * i + j];
|
|
10343
|
+
const theta = thetaDeg * DEG2RAD$5;
|
|
9846
10344
|
const s = Math.sin(theta);
|
|
9847
10345
|
if (i < ra.length) raDeg += ra[i] * s;
|
|
9848
10346
|
if (i < dec.length) decDeg += dec[i] * Math.cos(theta);
|
|
9849
10347
|
if (i < pm.length) wDeg += pm[i] * s;
|
|
9850
10348
|
}
|
|
9851
10349
|
}
|
|
9852
|
-
|
|
9853
|
-
|
|
10350
|
+
return {
|
|
10351
|
+
ra: raDeg,
|
|
10352
|
+
dec: decDeg,
|
|
10353
|
+
w: wDeg
|
|
10354
|
+
};
|
|
10355
|
+
}
|
|
10356
|
+
function bodyQuaternion(orientation, currentJd, nutPrec) {
|
|
10357
|
+
const { ra: raDeg, dec: decDeg, w: wDeg } = iauAngles(orientation, currentJd, nutPrec);
|
|
10358
|
+
const ra = raDeg * DEG2RAD$5;
|
|
10359
|
+
const dec = decDeg * DEG2RAD$5;
|
|
9854
10360
|
const cosDec = Math.cos(dec);
|
|
9855
10361
|
const pole = equatorialToScene(cosDec * Math.cos(ra), cosDec * Math.sin(ra), Math.sin(dec), new Vector3()).normalize();
|
|
9856
10362
|
const node = equatorialToScene(-Math.sin(ra), Math.cos(ra), 0, new Vector3()).normalize();
|
|
9857
10363
|
const third = new Vector3().crossVectors(node, pole).normalize();
|
|
9858
10364
|
const tiltQuat = new Quaternion().setFromRotationMatrix(new Matrix4().makeBasis(node, pole, third));
|
|
9859
|
-
return new Quaternion().setFromAxisAngle(pole, wDeg * DEG2RAD$
|
|
10365
|
+
return new Quaternion().setFromAxisAngle(pole, wDeg * DEG2RAD$5).multiply(tiltQuat);
|
|
9860
10366
|
}
|
|
9861
10367
|
function applyOrientation(obj, orientation, currentJd, nutPrec) {
|
|
9862
10368
|
obj.quaternion.copy(bodyQuaternion(orientation, currentJd, nutPrec));
|
|
@@ -9975,6 +10481,434 @@ function chainShaderHook(material, mod, patch) {
|
|
|
9975
10481
|
material.needsUpdate = true;
|
|
9976
10482
|
}
|
|
9977
10483
|
|
|
10484
|
+
//#endregion
|
|
10485
|
+
//#region src/lib/scene/lighting.ts
|
|
10486
|
+
var AMBIENT_INTENSITY = .01;
|
|
10487
|
+
var SUN_LIGHT_INTENSITY = 3.5;
|
|
10488
|
+
var ENV_BASE_INTENSITY = .04;
|
|
10489
|
+
function sunIrradianceFactor(sunDistScene) {
|
|
10490
|
+
const au = Math.max(sunDistScene / 10, .01);
|
|
10491
|
+
return 1 / (au * au);
|
|
10492
|
+
}
|
|
10493
|
+
function applySunPointLightMode(light, realistic, scale = 1) {
|
|
10494
|
+
light.decay = realistic ? 2 : 0;
|
|
10495
|
+
light.intensity = (realistic ? SUN_LIGHT_INTENSITY * 10 * 10 : SUN_LIGHT_INTENSITY) * scale;
|
|
10496
|
+
}
|
|
10497
|
+
function makeEnvMap(renderer) {
|
|
10498
|
+
const pmrem = new PMREMGenerator(renderer);
|
|
10499
|
+
const tex = pmrem.fromScene(new RoomEnvironment()).texture;
|
|
10500
|
+
pmrem.dispose();
|
|
10501
|
+
return tex;
|
|
10502
|
+
}
|
|
10503
|
+
|
|
10504
|
+
//#endregion
|
|
10505
|
+
//#region src/lib/scene/objects/surface/ring-light.ts
|
|
10506
|
+
var UNLIT_TINT = [
|
|
10507
|
+
1,
|
|
10508
|
+
.97075,
|
|
10509
|
+
.952
|
|
10510
|
+
];
|
|
10511
|
+
var FORWARD_TINT_BIAS = [
|
|
10512
|
+
1.02,
|
|
10513
|
+
.99,
|
|
10514
|
+
.97
|
|
10515
|
+
];
|
|
10516
|
+
var PROFILE_MU = Math.sin(8 * Math.PI / 180);
|
|
10517
|
+
function oneMinusExp(x) {
|
|
10518
|
+
return x < .001 ? x * (1 - .5 * x) : 1 - Math.exp(-x);
|
|
10519
|
+
}
|
|
10520
|
+
function reflectionGain(mu0, mu, tau) {
|
|
10521
|
+
const a = Math.max(mu0, 1e-4);
|
|
10522
|
+
const b = Math.max(mu, 1e-4);
|
|
10523
|
+
const t = Math.max(tau, 1e-6);
|
|
10524
|
+
return mu0 / (a + b) * oneMinusExp(t * (1 / a + 1 / b)) / (.5 * oneMinusExp(2 * t / PROFILE_MU));
|
|
10525
|
+
}
|
|
10526
|
+
var RINGSHINE_BANDS = 3;
|
|
10527
|
+
var SECTORS = 12;
|
|
10528
|
+
var RINGSHINE_PATCHES = RINGSHINE_BANDS * (SECTORS / 2 + 1);
|
|
10529
|
+
var RINGSHINE_MIN_MU0 = 1e-4;
|
|
10530
|
+
var PROFILE_BINS = 256;
|
|
10531
|
+
var _litGain = new Float64Array(PROFILE_BINS);
|
|
10532
|
+
var SECTOR_STEPS = 6;
|
|
10533
|
+
var PLANET_LIGHT_AZIMUTHS = 19;
|
|
10534
|
+
var PLANET_LIGHT_RADII = 8;
|
|
10535
|
+
var PLANET_ROWS = 24;
|
|
10536
|
+
var PLANET_COLUMNS = 48;
|
|
10537
|
+
function luminance$2(r, g, b) {
|
|
10538
|
+
return .2126 * r + .7152 * g + .0722 * b;
|
|
10539
|
+
}
|
|
10540
|
+
var SRGB_TO_LINEAR = Float64Array.from({ length: 256 }, (_, i) => {
|
|
10541
|
+
const c = i / 255;
|
|
10542
|
+
return c <= .04045 ? c / 12.92 : ((c + .055) / 1.055) ** 2.4;
|
|
10543
|
+
});
|
|
10544
|
+
function ringProfile(pixels, width, rows, inner, outer, intensity) {
|
|
10545
|
+
const back = new Float64Array(PROFILE_BINS);
|
|
10546
|
+
const forward = new Float64Array(PROFILE_BINS);
|
|
10547
|
+
const unlit = new Float64Array(PROFILE_BINS);
|
|
10548
|
+
const transmission = new Float64Array(PROFILE_BINS);
|
|
10549
|
+
const unlitLuminance = luminance$2(...UNLIT_TINT);
|
|
10550
|
+
const [br, bg, bb] = FORWARD_TINT_BIAS;
|
|
10551
|
+
const tint = [
|
|
10552
|
+
0,
|
|
10553
|
+
0,
|
|
10554
|
+
0
|
|
10555
|
+
];
|
|
10556
|
+
const at = (row, i) => (row * width + i) * 4;
|
|
10557
|
+
for (let k = 0; k < PROFILE_BINS; k++) {
|
|
10558
|
+
const from = Math.floor(k * width / PROFILE_BINS);
|
|
10559
|
+
const to = Math.max(from + 1, Math.floor((k + 1) * width / PROFILE_BINS));
|
|
10560
|
+
const r = inner + (k + .5) / PROFILE_BINS * (outer - inner);
|
|
10561
|
+
for (let i = from; i < to; i++) {
|
|
10562
|
+
const c = at(rows.color, i);
|
|
10563
|
+
const red = SRGB_TO_LINEAR[pixels[c]];
|
|
10564
|
+
const green = SRGB_TO_LINEAR[pixels[c + 1]];
|
|
10565
|
+
const blue = SRGB_TO_LINEAR[pixels[c + 2]];
|
|
10566
|
+
const opacity = Math.min(1, (1 - pixels[at(rows.transparency, i)] / 255) * intensity);
|
|
10567
|
+
const backscatter = pixels[at(rows.backscattered, i)] / 255 * intensity;
|
|
10568
|
+
back[k] += backscatter * luminance$2(red, green, blue);
|
|
10569
|
+
forward[k] += pixels[at(rows.forwardscattered, i)] / 255 * opacity * intensity * luminance$2(red * br, green * bg, blue * bb);
|
|
10570
|
+
unlit[k] += pixels[at(rows.unlitside, i)] / 255 * opacity * intensity * unlitLuminance;
|
|
10571
|
+
transmission[k] += 1 - opacity;
|
|
10572
|
+
tint[0] += backscatter * red * r;
|
|
10573
|
+
tint[1] += backscatter * green * r;
|
|
10574
|
+
tint[2] += backscatter * blue * r;
|
|
10575
|
+
}
|
|
10576
|
+
const n = to - from;
|
|
10577
|
+
back[k] /= n;
|
|
10578
|
+
forward[k] /= n;
|
|
10579
|
+
unlit[k] /= n;
|
|
10580
|
+
transmission[k] /= n;
|
|
10581
|
+
}
|
|
10582
|
+
const tintLuminance = luminance$2(tint[0], tint[1], tint[2]);
|
|
10583
|
+
return {
|
|
10584
|
+
inner,
|
|
10585
|
+
outer,
|
|
10586
|
+
back,
|
|
10587
|
+
forward,
|
|
10588
|
+
unlit,
|
|
10589
|
+
transmission,
|
|
10590
|
+
litTint: tintLuminance > 0 ? new Color(tint[0], tint[1], tint[2]).multiplyScalar(1 / tintLuminance) : new Color(1, 1, 1),
|
|
10591
|
+
bands: equalLightBands(back, unlit, inner, outer)
|
|
10592
|
+
};
|
|
10593
|
+
}
|
|
10594
|
+
function equalLightBands(back, unlit, inner, outer) {
|
|
10595
|
+
const cumulative = new Float64Array(PROFILE_BINS + 1);
|
|
10596
|
+
for (let k = 0; k < PROFILE_BINS; k++) {
|
|
10597
|
+
const r = inner + (k + .5) / PROFILE_BINS * (outer - inner);
|
|
10598
|
+
cumulative[k + 1] = cumulative[k] + (back[k] + unlit[k]) / r;
|
|
10599
|
+
}
|
|
10600
|
+
const total = cumulative[PROFILE_BINS];
|
|
10601
|
+
const edges = new Int32Array(RINGSHINE_BANDS + 1);
|
|
10602
|
+
edges[RINGSHINE_BANDS] = PROFILE_BINS;
|
|
10603
|
+
for (let b = 1; b < RINGSHINE_BANDS; b++) {
|
|
10604
|
+
let k = edges[b - 1] + 1;
|
|
10605
|
+
while (k < PROFILE_BINS - (RINGSHINE_BANDS - b) && cumulative[k] < total * b / RINGSHINE_BANDS) k++;
|
|
10606
|
+
edges[b] = k;
|
|
10607
|
+
}
|
|
10608
|
+
return edges;
|
|
10609
|
+
}
|
|
10610
|
+
function forwardWeight(cosPhase) {
|
|
10611
|
+
const t = Math.min(Math.max((cosPhase + 1) / 2, 0), 1);
|
|
10612
|
+
return 1 - t * t * (3 - 2 * t);
|
|
10613
|
+
}
|
|
10614
|
+
var PARTICLE_PHASE_EXPONENT = 3.09;
|
|
10615
|
+
function particlePhase(cosPhase) {
|
|
10616
|
+
return (1 - Math.acos(Math.min(Math.max(cosPhase, -1), 1)) / Math.PI) ** PARTICLE_PHASE_EXPONENT;
|
|
10617
|
+
}
|
|
10618
|
+
function inPlanetShadow(x, y, cosB, sinB, planet) {
|
|
10619
|
+
const ox = x / planet.equatorial;
|
|
10620
|
+
const oy = y / planet.equatorial;
|
|
10621
|
+
const dx = cosB / planet.equatorial;
|
|
10622
|
+
const dz = sinB / planet.polar;
|
|
10623
|
+
const b = ox * dx;
|
|
10624
|
+
if (b >= 0) return false;
|
|
10625
|
+
return ox * ox + oy * oy - b * b / (dx * dx + dz * dz) < 1;
|
|
10626
|
+
}
|
|
10627
|
+
function ringshinePatches(out, profile, sinB, planet) {
|
|
10628
|
+
const cosB = Math.sqrt(Math.max(0, 1 - sinB * sinB));
|
|
10629
|
+
const mu0 = Math.abs(sinB);
|
|
10630
|
+
const sunAbove = sinB >= 0;
|
|
10631
|
+
const { inner, outer, back, forward, unlit, transmission, bands } = profile;
|
|
10632
|
+
for (let i = 0; i < PROFILE_BINS; i++) _litGain[i] = reflectionGain(mu0, mu0, -Math.log(Math.max(transmission[i], 1e-6)));
|
|
10633
|
+
const dr = (outer - inner) / PROFILE_BINS;
|
|
10634
|
+
const sector = 2 * Math.PI / SECTORS;
|
|
10635
|
+
const dPhi = sector / SECTOR_STEPS;
|
|
10636
|
+
let p = 0;
|
|
10637
|
+
for (let band = 0; band < RINGSHINE_BANDS; band++) for (let k = 0; k <= SECTORS / 2; k++, p++) {
|
|
10638
|
+
let above = 0;
|
|
10639
|
+
let below = 0;
|
|
10640
|
+
let weight = 0;
|
|
10641
|
+
let wx = 0;
|
|
10642
|
+
let wy = 0;
|
|
10643
|
+
for (let s = 0; s < SECTOR_STEPS; s++) {
|
|
10644
|
+
const phi = (k - .5) * sector + (s + .5) * dPhi;
|
|
10645
|
+
const c = Math.cos(phi);
|
|
10646
|
+
const sn = Math.sin(phi);
|
|
10647
|
+
const w = forwardWeight(-cosB * c);
|
|
10648
|
+
const phase = particlePhase(-cosB * c);
|
|
10649
|
+
for (let i = bands[band]; i < bands[band + 1]; i++) {
|
|
10650
|
+
const r = inner + (i + .5) * dr;
|
|
10651
|
+
if (inPlanetShadow(r * c, r * sn, cosB, sinB, planet)) continue;
|
|
10652
|
+
const area = r * dr * dPhi;
|
|
10653
|
+
const lit = (back[i] * phase + (forward[i] - back[i] * phase) * w) * _litGain[i] * area;
|
|
10654
|
+
const through = unlit[i] * area;
|
|
10655
|
+
above += sunAbove ? lit : through;
|
|
10656
|
+
below += sunAbove ? through : lit;
|
|
10657
|
+
const light = lit + through;
|
|
10658
|
+
weight += light;
|
|
10659
|
+
wx += light * r * c;
|
|
10660
|
+
wy += light * r * Math.abs(sn);
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
10663
|
+
const share = k === 0 || k === SECTORS / 2 ? .5 : 1;
|
|
10664
|
+
if (weight > 0) {
|
|
10665
|
+
out[4 * p] = wx / weight;
|
|
10666
|
+
out[4 * p + 1] = wy / weight;
|
|
10667
|
+
} else {
|
|
10668
|
+
const r = inner + (bands[band] + bands[band + 1]) / 2 * dr;
|
|
10669
|
+
out[4 * p] = r * Math.cos(k * sector);
|
|
10670
|
+
out[4 * p + 1] = r * Math.abs(Math.sin(k * sector));
|
|
10671
|
+
}
|
|
10672
|
+
out[4 * p + 2] = above * share;
|
|
10673
|
+
out[4 * p + 3] = below * share;
|
|
10674
|
+
}
|
|
10675
|
+
}
|
|
10676
|
+
function ringshineAt(patches, mu0, qx, qy, qz, nx, ny, nz) {
|
|
10677
|
+
const above = qz >= 0;
|
|
10678
|
+
const height = Math.abs(qz);
|
|
10679
|
+
const qq = qx * qx + qy * qy + qz * qz;
|
|
10680
|
+
const nq = nx * qx + ny * qy + nz * qz;
|
|
10681
|
+
let sum = 0;
|
|
10682
|
+
for (let i = 0; i < 21; i++) {
|
|
10683
|
+
const px = patches[4 * i];
|
|
10684
|
+
const py = patches[4 * i + 1];
|
|
10685
|
+
const light = above ? patches[4 * i + 2] : patches[4 * i + 3];
|
|
10686
|
+
const base = qq + px * px + py * py - 2 * px * qx;
|
|
10687
|
+
const across = 2 * py * qy;
|
|
10688
|
+
const facingBase = px * nx - nq;
|
|
10689
|
+
const facingAcross = py * ny;
|
|
10690
|
+
for (const sign of [1, -1]) {
|
|
10691
|
+
const d2 = base - sign * across;
|
|
10692
|
+
const d = Math.sqrt(d2);
|
|
10693
|
+
const facing = Math.max(facingBase + sign * facingAcross, 0);
|
|
10694
|
+
sum += light * facing / (d2 * d * (mu0 * d + height));
|
|
10695
|
+
}
|
|
10696
|
+
}
|
|
10697
|
+
return 2 * mu0 * height * sum;
|
|
10698
|
+
}
|
|
10699
|
+
function ringTransmission(profile, x, y, z, cosB, sinB) {
|
|
10700
|
+
if (Math.abs(sinB) < 1e-6) return 1;
|
|
10701
|
+
const t = -z / sinB;
|
|
10702
|
+
if (t < 0) return 1;
|
|
10703
|
+
const u = (Math.hypot(x + t * cosB, y) - profile.inner) / (profile.outer - profile.inner);
|
|
10704
|
+
if (u < 0 || u > 1) return 1;
|
|
10705
|
+
const bin = Math.min(Math.floor(u * PROFILE_BINS), PROFILE_BINS - 1);
|
|
10706
|
+
return Math.max(profile.transmission[bin], 1e-4) ** (1 / Math.max(Math.abs(sinB), .02));
|
|
10707
|
+
}
|
|
10708
|
+
var _cells = {
|
|
10709
|
+
x: new Float64Array(PLANET_ROWS * PLANET_COLUMNS),
|
|
10710
|
+
y: new Float64Array(PLANET_ROWS * PLANET_COLUMNS),
|
|
10711
|
+
z: new Float64Array(PLANET_ROWS * PLANET_COLUMNS),
|
|
10712
|
+
nx: new Float64Array(PLANET_ROWS * PLANET_COLUMNS),
|
|
10713
|
+
ny: new Float64Array(PLANET_ROWS * PLANET_COLUMNS),
|
|
10714
|
+
nz: new Float64Array(PLANET_ROWS * PLANET_COLUMNS),
|
|
10715
|
+
light: new Float64Array(PLANET_ROWS * PLANET_COLUMNS)
|
|
10716
|
+
};
|
|
10717
|
+
function planetLightOnRing(out, inner, outer, sinB, planet, caster, patches) {
|
|
10718
|
+
const cosB = Math.sqrt(Math.max(0, 1 - sinB * sinB));
|
|
10719
|
+
const mu0 = Math.abs(sinB);
|
|
10720
|
+
const { equatorial: a, polar: c } = planet;
|
|
10721
|
+
const cells = _cells;
|
|
10722
|
+
const dBeta = Math.PI / PLANET_ROWS;
|
|
10723
|
+
const dLambda = 2 * Math.PI / PLANET_COLUMNS;
|
|
10724
|
+
for (let row = 0; row < PLANET_ROWS; row++) {
|
|
10725
|
+
const beta = -Math.PI / 2 + (row + .5) * dBeta;
|
|
10726
|
+
const cb = Math.cos(beta);
|
|
10727
|
+
const sb = Math.sin(beta);
|
|
10728
|
+
const area = a * cb * Math.sqrt(c * c * cb * cb + a * a * sb * sb) * dBeta * dLambda;
|
|
10729
|
+
for (let col = 0; col < PLANET_COLUMNS; col++) {
|
|
10730
|
+
const lambda = (col + .5) * dLambda;
|
|
10731
|
+
const cl = Math.cos(lambda);
|
|
10732
|
+
const sl = Math.sin(lambda);
|
|
10733
|
+
const i = row * PLANET_COLUMNS + col;
|
|
10734
|
+
const x = a * cb * cl;
|
|
10735
|
+
const y = a * cb * sl;
|
|
10736
|
+
const z = c * sb;
|
|
10737
|
+
let nx = cb * cl / a;
|
|
10738
|
+
let ny = cb * sl / a;
|
|
10739
|
+
let nz = sb / c;
|
|
10740
|
+
const len = Math.hypot(nx, ny, nz);
|
|
10741
|
+
nx /= len;
|
|
10742
|
+
ny /= len;
|
|
10743
|
+
nz /= len;
|
|
10744
|
+
const cosSun = nx * cosB + nz * sinB;
|
|
10745
|
+
const day = cosSun > 0 ? cosSun * ringTransmission(caster, x, y, z, cosB, sinB) : 0;
|
|
10746
|
+
const night = mu0 < RINGSHINE_MIN_MU0 ? 0 : ringshineAt(patches, mu0, x, y, z, nx, ny, nz) / SUN_LIGHT_INTENSITY;
|
|
10747
|
+
cells.x[i] = x;
|
|
10748
|
+
cells.y[i] = y;
|
|
10749
|
+
cells.z[i] = z;
|
|
10750
|
+
cells.nx[i] = nx;
|
|
10751
|
+
cells.ny[i] = ny;
|
|
10752
|
+
cells.nz[i] = nz;
|
|
10753
|
+
cells.light[i] = (day + night) / Math.PI * area;
|
|
10754
|
+
}
|
|
10755
|
+
}
|
|
10756
|
+
for (let j = 0; j < 8; j++) {
|
|
10757
|
+
const r = inner + j / (8 - 1) * (outer - inner);
|
|
10758
|
+
for (let k = 0; k < 19; k++) {
|
|
10759
|
+
const cosPhi = 1 - 2 * k / (19 - 1);
|
|
10760
|
+
const px = r * cosPhi;
|
|
10761
|
+
const py = r * Math.sqrt(1 - cosPhi * cosPhi);
|
|
10762
|
+
let above = 0;
|
|
10763
|
+
let below = 0;
|
|
10764
|
+
let aboveMu = 0;
|
|
10765
|
+
let belowMu = 0;
|
|
10766
|
+
for (let i = 0; i < PLANET_ROWS * PLANET_COLUMNS; i++) {
|
|
10767
|
+
const vx = px - cells.x[i];
|
|
10768
|
+
const vy = py - cells.y[i];
|
|
10769
|
+
const vz = -cells.z[i];
|
|
10770
|
+
const d2 = vx * vx + vy * vy + vz * vz;
|
|
10771
|
+
const facing = cells.nx[i] * vx + cells.ny[i] * vy + cells.nz[i] * vz;
|
|
10772
|
+
if (facing <= 0) continue;
|
|
10773
|
+
const d = Math.sqrt(d2);
|
|
10774
|
+
const e = cells.light[i] * facing / (d2 * d);
|
|
10775
|
+
const mu = Math.abs(vz) / d;
|
|
10776
|
+
if (cells.z[i] > 0) {
|
|
10777
|
+
above += e;
|
|
10778
|
+
aboveMu += e * mu;
|
|
10779
|
+
} else {
|
|
10780
|
+
below += e;
|
|
10781
|
+
belowMu += e * mu;
|
|
10782
|
+
}
|
|
10783
|
+
}
|
|
10784
|
+
const node = 4 * (j * 19 + k);
|
|
10785
|
+
out[node] = above;
|
|
10786
|
+
out[node + 1] = below;
|
|
10787
|
+
out[node + 2] = above > 0 ? aboveMu / above : 0;
|
|
10788
|
+
out[node + 3] = below > 0 ? belowMu / below : 0;
|
|
10789
|
+
}
|
|
10790
|
+
}
|
|
10791
|
+
}
|
|
10792
|
+
var _grid = new Float32Array(4 * 19 * 8);
|
|
10793
|
+
function makeRingLight(profile) {
|
|
10794
|
+
const texture = new DataTexture(new Uint16Array(4 * 19 * 8), 19, 8, RGBAFormat, HalfFloatType);
|
|
10795
|
+
texture.minFilter = LinearFilter;
|
|
10796
|
+
texture.magFilter = LinearFilter;
|
|
10797
|
+
texture.wrapS = ClampToEdgeWrapping;
|
|
10798
|
+
texture.wrapT = ClampToEdgeWrapping;
|
|
10799
|
+
texture.needsUpdate = true;
|
|
10800
|
+
return {
|
|
10801
|
+
profile,
|
|
10802
|
+
planet: {
|
|
10803
|
+
equatorial: 0,
|
|
10804
|
+
polar: 0
|
|
10805
|
+
},
|
|
10806
|
+
planetLight: texture,
|
|
10807
|
+
planetLightSinB: NaN,
|
|
10808
|
+
patches: new Float64Array(4 * 21),
|
|
10809
|
+
patchesSinB: NaN
|
|
10810
|
+
};
|
|
10811
|
+
}
|
|
10812
|
+
function fillPlanetLight(light, sinB, caster) {
|
|
10813
|
+
planetLightOnRing(_grid, light.profile.inner, light.profile.outer, sinB, light.planet, caster.profile, caster.patches);
|
|
10814
|
+
const data = light.planetLight.image.data;
|
|
10815
|
+
for (let i = 0; i < _grid.length; i++) data[i] = DataUtils.toHalfFloat(_grid[i]);
|
|
10816
|
+
light.planetLight.needsUpdate = true;
|
|
10817
|
+
light.planetLightSinB = sinB;
|
|
10818
|
+
}
|
|
10819
|
+
function peakRingshine(profile, planet) {
|
|
10820
|
+
const patches = new Float64Array(4 * 21);
|
|
10821
|
+
ringshinePatches(patches, profile, 1, planet);
|
|
10822
|
+
let peak = 0;
|
|
10823
|
+
for (let deg = 2; deg < 90; deg += 2) {
|
|
10824
|
+
const beta = deg * Math.PI / 180;
|
|
10825
|
+
const cb = Math.cos(beta);
|
|
10826
|
+
const sb = Math.sin(beta);
|
|
10827
|
+
const nx = cb / planet.equatorial;
|
|
10828
|
+
const nz = sb / planet.polar;
|
|
10829
|
+
const len = Math.hypot(nx, nz);
|
|
10830
|
+
const e = ringshineAt(patches, 1, planet.equatorial * cb, 0, planet.polar * sb, nx / len, 0, nz / len);
|
|
10831
|
+
peak = Math.max(peak, e / SUN_LIGHT_INTENSITY);
|
|
10832
|
+
}
|
|
10833
|
+
return peak;
|
|
10834
|
+
}
|
|
10835
|
+
var RINGSHINE_PARS = `
|
|
10836
|
+
#define RINGSHINE_PATCHES ${21}
|
|
10837
|
+
uniform vec4 uRingshinePatch[RINGSHINE_PATCHES];
|
|
10838
|
+
uniform vec3 uRingshineAxis;
|
|
10839
|
+
uniform vec3 uRingshineTint[2];
|
|
10840
|
+
`;
|
|
10841
|
+
var RINGSHINE_LIGHT = `
|
|
10842
|
+
if (uRingshineTint[0].g + uRingshineTint[1].g > 0.0) {
|
|
10843
|
+
vec3 q = vRingShadowWorldPos - uRingShadowCenter;
|
|
10844
|
+
vec3 axisY = cross(uRingShadowPoleDir, uRingshineAxis);
|
|
10845
|
+
float height = dot(q, uRingShadowPoleDir);
|
|
10846
|
+
float mu0 = abs(dot(uRingShadowSunDir, uRingShadowPoleDir));
|
|
10847
|
+
vec3 n = inverseTransformDirection(geometryNormal, viewMatrix);
|
|
10848
|
+
float qx = dot(q, uRingshineAxis);
|
|
10849
|
+
float qy = dot(q, axisY);
|
|
10850
|
+
float qq = dot(q, q);
|
|
10851
|
+
float nx = dot(n, uRingshineAxis);
|
|
10852
|
+
float ny = dot(n, axisY);
|
|
10853
|
+
float nq = dot(n, q);
|
|
10854
|
+
float above = step(0.0, height);
|
|
10855
|
+
float absHeight = abs(height);
|
|
10856
|
+
float sum = 0.0;
|
|
10857
|
+
for (int i = 0; i < RINGSHINE_PATCHES; i++) {
|
|
10858
|
+
vec4 p = uRingshinePatch[i];
|
|
10859
|
+
float light = mix(p.w, p.z, above);
|
|
10860
|
+
float base = qq + dot(p.xy, p.xy) - 2.0 * p.x * qx;
|
|
10861
|
+
float across = 2.0 * p.y * qy;
|
|
10862
|
+
float facingBase = p.x * nx - nq;
|
|
10863
|
+
float facingAcross = p.y * ny;
|
|
10864
|
+
// The patch and its mirror at -y.
|
|
10865
|
+
vec2 d2 = vec2(base - across, base + across);
|
|
10866
|
+
vec2 d = sqrt(d2);
|
|
10867
|
+
vec2 facing = max(vec2(facingBase + facingAcross, facingBase - facingAcross), 0.0);
|
|
10868
|
+
sum += light * dot(facing, 1.0 / (d2 * d * (mu0 * d + absHeight)));
|
|
10869
|
+
}
|
|
10870
|
+
vec3 tint = mix(uRingshineTint[1], uRingshineTint[0], above);
|
|
10871
|
+
reflectedLight.indirectDiffuse +=
|
|
10872
|
+
tint * (2.0 * mu0 * absHeight * sum) * BRDF_Lambert(material.diffuseContribution);
|
|
10873
|
+
}
|
|
10874
|
+
`;
|
|
10875
|
+
function attachRingshine(material) {
|
|
10876
|
+
const carrier = material.userData;
|
|
10877
|
+
if (carrier.ringshine) return carrier.ringshine;
|
|
10878
|
+
const uniforms = {
|
|
10879
|
+
uRingshinePatch: { value: Array.from({ length: 21 }, () => new Vector4()) },
|
|
10880
|
+
uRingshineAxis: { value: new Vector3(1, 0, 0) },
|
|
10881
|
+
uRingshineTint: { value: [new Vector3(), new Vector3()] },
|
|
10882
|
+
disable: () => {
|
|
10883
|
+
for (const tint of uniforms.uRingshineTint.value) tint.set(0, 0, 0);
|
|
10884
|
+
}
|
|
10885
|
+
};
|
|
10886
|
+
chainShaderHook(material, "ringshine", (shader) => {
|
|
10887
|
+
shader.uniforms.uRingshinePatch = uniforms.uRingshinePatch;
|
|
10888
|
+
shader.uniforms.uRingshineAxis = uniforms.uRingshineAxis;
|
|
10889
|
+
shader.uniforms.uRingshineTint = uniforms.uRingshineTint;
|
|
10890
|
+
shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `#include <common>\n${RINGSHINE_PARS}`).replace("#include <lights_fragment_end>", `#include <lights_fragment_end>\n${RINGSHINE_LIGHT}`);
|
|
10891
|
+
});
|
|
10892
|
+
carrier.ringshine = uniforms;
|
|
10893
|
+
return uniforms;
|
|
10894
|
+
}
|
|
10895
|
+
function writeRingshine(uniforms, light, axis, sinB, lightScale) {
|
|
10896
|
+
const patches = uniforms.uRingshinePatch.value;
|
|
10897
|
+
for (let i = 0; i < 21; i++) patches[i].fromArray(light.patches, 4 * i);
|
|
10898
|
+
uniforms.uRingshineAxis.value.copy(axis);
|
|
10899
|
+
const [above, below] = uniforms.uRingshineTint.value;
|
|
10900
|
+
if (Math.abs(sinB) < RINGSHINE_MIN_MU0) {
|
|
10901
|
+
above.set(0, 0, 0);
|
|
10902
|
+
below.set(0, 0, 0);
|
|
10903
|
+
return;
|
|
10904
|
+
}
|
|
10905
|
+
const lit = light.profile.litTint;
|
|
10906
|
+
const unlitLuminance = luminance$2(...UNLIT_TINT);
|
|
10907
|
+
const [litFace, unlitFace] = sinB >= 0 ? [above, below] : [below, above];
|
|
10908
|
+
litFace.set(lit.r, lit.g, lit.b).multiplyScalar(lightScale);
|
|
10909
|
+
unlitFace.set(...UNLIT_TINT).multiplyScalar(lightScale / unlitLuminance);
|
|
10910
|
+
}
|
|
10911
|
+
|
|
9978
10912
|
//#endregion
|
|
9979
10913
|
//#region src/lib/scene/objects/surface/rings.ts
|
|
9980
10914
|
var RING_ANGULAR_SEGMENTS = 256;
|
|
@@ -9986,30 +10920,47 @@ async function loadStripTextures(url, rows, maxTextureSize) {
|
|
|
9986
10920
|
if (!response.ok) throw new Error(`Failed to load ${url}: ${response.status} ${response.statusText}`);
|
|
9987
10921
|
const blob = await response.blob();
|
|
9988
10922
|
const bitmap = await createImageBitmap(blob);
|
|
9989
|
-
const
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
const
|
|
9993
|
-
|
|
10923
|
+
const width = bitmap.width;
|
|
10924
|
+
const targetWidth = Math.min(width, maxTextureSize);
|
|
10925
|
+
if (targetWidth < width) console.info(`Ring strip ${url}: downscaling ${width}px → ${targetWidth}px to fit GL MAX_TEXTURE_SIZE.`);
|
|
10926
|
+
const pixels = readStripPixels(bitmap, url, maxTextureSize);
|
|
10927
|
+
bitmap.close();
|
|
10928
|
+
const line = (row) => boxFilterRow(pixels, width, row, targetWidth);
|
|
10929
|
+
const texture = (data, srgb = false) => {
|
|
9994
10930
|
const canvas = document.createElement("canvas");
|
|
9995
10931
|
canvas.width = targetWidth;
|
|
9996
10932
|
canvas.height = 2;
|
|
9997
10933
|
const ctx = canvas.getContext("2d");
|
|
9998
10934
|
if (!ctx) throw new Error(`Failed to acquire 2D context for ring strip ${url}`);
|
|
9999
|
-
|
|
10000
|
-
ctx.putImageData(
|
|
10001
|
-
ctx.putImageData(line, 0, 1);
|
|
10935
|
+
ctx.putImageData(data, 0, 0);
|
|
10936
|
+
ctx.putImageData(data, 0, 1);
|
|
10002
10937
|
const tex = new CanvasTexture(canvas);
|
|
10003
|
-
if (
|
|
10938
|
+
if (srgb) tex.colorSpace = SRGBColorSpace;
|
|
10004
10939
|
tex.minFilter = LinearMipmapLinearFilter;
|
|
10005
10940
|
tex.magFilter = LinearFilter;
|
|
10006
10941
|
tex.generateMipmaps = true;
|
|
10007
10942
|
tex.anisotropy = 16;
|
|
10008
10943
|
tex.needsUpdate = true;
|
|
10009
|
-
|
|
10944
|
+
return tex;
|
|
10945
|
+
};
|
|
10946
|
+
const scatter = line(rows.backscattered);
|
|
10947
|
+
const forward = line(rows.forwardscattered);
|
|
10948
|
+
const unlit = line(rows.unlitside);
|
|
10949
|
+
for (let d = 0; d < scatter.data.length; d += 4) {
|
|
10950
|
+
scatter.data[d + 1] = forward.data[d];
|
|
10951
|
+
scatter.data[d + 2] = unlit.data[d];
|
|
10010
10952
|
}
|
|
10011
|
-
|
|
10012
|
-
|
|
10953
|
+
const textures = {
|
|
10954
|
+
color: texture(line(rows.color), true),
|
|
10955
|
+
scatter: texture(scatter),
|
|
10956
|
+
transparency: texture(line(rows.transparency))
|
|
10957
|
+
};
|
|
10958
|
+
if (rows.thickness !== void 0) textures.thickness = texture(line(rows.thickness));
|
|
10959
|
+
return {
|
|
10960
|
+
textures,
|
|
10961
|
+
pixels,
|
|
10962
|
+
width
|
|
10963
|
+
};
|
|
10013
10964
|
}
|
|
10014
10965
|
function readStripPixels(bitmap, url, maxTextureSize) {
|
|
10015
10966
|
const out = new Uint8ClampedArray(bitmap.width * bitmap.height * 4);
|
|
@@ -10090,9 +11041,7 @@ var FRAGMENT_SHADER$2 = `
|
|
|
10090
11041
|
#include <common>
|
|
10091
11042
|
#include <logdepthbuf_pars_fragment>
|
|
10092
11043
|
|
|
10093
|
-
uniform sampler2D
|
|
10094
|
-
uniform sampler2D uForwardscattered;
|
|
10095
|
-
uniform sampler2D uUnlitside;
|
|
11044
|
+
uniform sampler2D uScatter;
|
|
10096
11045
|
uniform sampler2D uTransparency;
|
|
10097
11046
|
uniform sampler2D uColor;
|
|
10098
11047
|
uniform float uInnerScene;
|
|
@@ -10114,18 +11063,56 @@ var FRAGMENT_SHADER$2 = `
|
|
|
10114
11063
|
// 1/layerCount: opacity is split across the vertical layer instances so
|
|
10115
11064
|
// the composited stack reproduces the strip's alpha.
|
|
10116
11065
|
uniform float uLayerAlphaExp;
|
|
11066
|
+
// Light of the planet on the +Y and the -Y face over the Sun's, per unit of the
|
|
11067
|
+
// planet's albedo, and the mean sine of its incidence on each, by the cosine
|
|
11068
|
+
// of the azimuth from the Sun (x) and radius (y).
|
|
11069
|
+
uniform sampler2D uPlanetLight;
|
|
11070
|
+
// Lambert albedo of the planet, linear RGB.
|
|
11071
|
+
uniform vec3 uPlanetAlbedo;
|
|
11072
|
+
// Unit direction of the Sun in the local XZ plane.
|
|
11073
|
+
uniform vec2 uSunAzimuth;
|
|
10117
11074
|
|
|
10118
11075
|
varying vec3 vLocalPos;
|
|
10119
11076
|
varying vec3 vWorldPos;
|
|
10120
11077
|
varying vec3 vWorldNormal;
|
|
10121
11078
|
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
const
|
|
11079
|
+
const vec3 UNLIT_TINT = vec3(${UNLIT_TINT.join(", ")});
|
|
11080
|
+
const vec3 FORWARD_TINT_BIAS = vec3(${FORWARD_TINT_BIAS.join(", ")});
|
|
11081
|
+
const float PROFILE_MU = ${PROFILE_MU};
|
|
11082
|
+
|
|
11083
|
+
float oneMinusExp(float x) {
|
|
11084
|
+
return x < 1e-3 ? x * (1.0 - 0.5 * x) : 1.0 - exp(-x);
|
|
11085
|
+
}
|
|
11086
|
+
|
|
11087
|
+
float reflectionGain(float mu0, float mu, float tau) {
|
|
11088
|
+
float a = max(mu0, 1e-4);
|
|
11089
|
+
float b = max(mu, 1e-4);
|
|
11090
|
+
return mu0 / (a + b) * oneMinusExp(tau * (1.0 / a + 1.0 / b))
|
|
11091
|
+
/ (0.5 * oneMinusExp(2.0 * tau / PROFILE_MU));
|
|
11092
|
+
}
|
|
11093
|
+
|
|
11094
|
+
float unlitGain(float mu0, float mu) {
|
|
11095
|
+
return 2.0 * mu0 / max(mu0 + mu, 1e-4);
|
|
11096
|
+
}
|
|
10125
11097
|
|
|
10126
|
-
//
|
|
10127
|
-
|
|
10128
|
-
|
|
11098
|
+
// Weight of forward scatter: 0 at phase 0, 1 at phase 180 deg, 0.5 edge-on.
|
|
11099
|
+
float forwardWeight(float cosPhase) {
|
|
11100
|
+
return 1.0 - smoothstep(-1.0, 1.0, cosPhase);
|
|
11101
|
+
}
|
|
11102
|
+
|
|
11103
|
+
float particlePhase(float cosPhase) {
|
|
11104
|
+
return pow(1.0 - acos(clamp(cosPhase, -1.0, 1.0)) / PI, ${PARTICLE_PHASE_EXPONENT});
|
|
11105
|
+
}
|
|
11106
|
+
|
|
11107
|
+
// The lit face at a phase and a gain: the backscatter profile under the
|
|
11108
|
+
// phase function of the particles, blended into the forward-scatter profile.
|
|
11109
|
+
vec3 litLight(vec3 back, vec3 forward, float cosPhase, float gain) {
|
|
11110
|
+
return mix(
|
|
11111
|
+
back * particlePhase(cosPhase) * gain,
|
|
11112
|
+
forward * min(gain, 1.0),
|
|
11113
|
+
forwardWeight(cosPhase)
|
|
11114
|
+
);
|
|
11115
|
+
}
|
|
10129
11116
|
|
|
10130
11117
|
// Ray-march from the fragment toward the sun against the planet's oblate
|
|
10131
11118
|
// spheroid: warp into the pole-aligned frame so the spheroid becomes a
|
|
@@ -10166,40 +11153,49 @@ var FRAGMENT_SHADER$2 = `
|
|
|
10166
11153
|
// the outward direction of the face actually being viewed.
|
|
10167
11154
|
vec3 N = gl_FrontFacing ? vWorldNormal : -vWorldNormal;
|
|
10168
11155
|
|
|
10169
|
-
|
|
11156
|
+
float sunMu = dot(uSunDir, N);
|
|
11157
|
+
bool lit = sunMu > 0.0;
|
|
11158
|
+
float mu0 = abs(sunMu);
|
|
10170
11159
|
|
|
10171
|
-
// cosAlpha = cos(phase angle): +1 low phase, -1 high phase.
|
|
10172
11160
|
vec3 viewDir = normalize(cameraPosition - vWorldPos);
|
|
10173
|
-
float
|
|
10174
|
-
|
|
10175
|
-
vec3 finalAlbedo;
|
|
10176
|
-
if (lit) {
|
|
10177
|
-
// Blend backscatter → forward scatter with phase angle; smoothstep
|
|
10178
|
-
// over [-1, 1] centers the transition on edge-on viewing (α = 90°).
|
|
10179
|
-
// Both branches share the Cassini color profile (calibrated for
|
|
10180
|
-
// backscatter only) plus a small red bias on the forward branch,
|
|
10181
|
-
// since dropping color entirely visibly loses the ring's tan/gold
|
|
10182
|
-
// hue seen in forward-scattered Cassini imagery.
|
|
10183
|
-
vec3 colorTint = texture2D(uColor, uv).rgb;
|
|
10184
|
-
vec3 forwardTint = colorTint * FORWARD_TINT_BIAS;
|
|
10185
|
-
vec3 back = texture2D(uBackscattered, uv).rgb * colorTint;
|
|
10186
|
-
vec3 forward = texture2D(uForwardscattered, uv).rgb * forwardTint;
|
|
10187
|
-
float wForward = 1.0 - smoothstep(-1.0, 1.0, cosAlpha);
|
|
10188
|
-
finalAlbedo = mix(back, forward, wForward);
|
|
10189
|
-
} else {
|
|
10190
|
-
// unlitside already is the transmitted-light appearance; no
|
|
10191
|
-
// phase-angle blend needed.
|
|
10192
|
-
finalAlbedo = texture2D(uUnlitside, uv).rgb * UNLIT_TINT;
|
|
10193
|
-
}
|
|
11161
|
+
float mu = abs(dot(viewDir, N));
|
|
10194
11162
|
// Transparency convention: 1.0 = empty space, 0.0 = opaque.
|
|
10195
|
-
float
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
11163
|
+
float opacity = clamp((1.0 - texture2D(uTransparency, uv).r) * uIntensityScale, 0.0, 1.0);
|
|
11164
|
+
float tau = max(-log(max(1.0 - opacity, 1e-6)), 1e-6);
|
|
11165
|
+
|
|
11166
|
+
vec3 colorTint = texture2D(uColor, uv).rgb;
|
|
11167
|
+
vec3 scatter = texture2D(uScatter, uv).rgb;
|
|
11168
|
+
vec3 back = scatter.r * colorTint;
|
|
11169
|
+
vec3 forward = scatter.g * opacity * colorTint * FORWARD_TINT_BIAS;
|
|
11170
|
+
vec3 unlit = scatter.b * opacity * UNLIT_TINT;
|
|
11171
|
+
vec3 sunLit = lit
|
|
11172
|
+
? litLight(back, forward, dot(uSunDir, viewDir), reflectionGain(mu0, mu, tau))
|
|
11173
|
+
: unlit * min(unlitGain(mu0, mu), 1.0);
|
|
11174
|
+
|
|
11175
|
+
// The light is the same at plus and minus an azimuth, so the texture holds its cosine.
|
|
11176
|
+
float azimuth = 0.5 - 0.5 * dot(vLocalPos.xz, uSunAzimuth) / radius;
|
|
11177
|
+
const vec2 NODES = vec2(${19}.0, ${8}.0);
|
|
11178
|
+
vec4 planet = texture2D(uPlanetLight, (vec2(azimuth, t) * (NODES - 1.0) + 0.5) / NODES);
|
|
11179
|
+
vec2 near = gl_FrontFacing ? planet.xz : planet.yw;
|
|
11180
|
+
vec2 far = gl_FrontFacing ? planet.yw : planet.xz;
|
|
11181
|
+
float planetPhase = dot(normalize(uPlanetCenter - vWorldPos), viewDir);
|
|
11182
|
+
vec3 planetLit = uPlanetAlbedo * (
|
|
11183
|
+
near.x * litLight(back, forward, planetPhase, reflectionGain(near.y, mu, tau))
|
|
11184
|
+
+ far.x * min(unlitGain(far.y, mu), 1.0) * unlit);
|
|
11185
|
+
|
|
11186
|
+
// The slant path hides more of the background.
|
|
11187
|
+
float alpha = oneMinusExp(tau / max(mu, 0.02));
|
|
11188
|
+
// Split the opacity across the sheets of the stack so that it composites
|
|
11189
|
+
// to the layer's. Each sheet adds its share of the light.
|
|
11190
|
+
float layerAlpha = 1.0 - pow(1.0 - alpha, uLayerAlphaExp);
|
|
11191
|
+
float share = alpha > 1e-4 ? layerAlpha / alpha : uLayerAlphaExp;
|
|
10199
11192
|
|
|
10200
11193
|
float shadow = planetShadow();
|
|
10201
11194
|
|
|
10202
|
-
gl_FragColor = vec4(
|
|
11195
|
+
gl_FragColor = vec4(
|
|
11196
|
+
(sunLit * shadow + planetLit) * uIntensityScale * uLightScale * share,
|
|
11197
|
+
layerAlpha
|
|
11198
|
+
);
|
|
10203
11199
|
#include <logdepthbuf_fragment>
|
|
10204
11200
|
}
|
|
10205
11201
|
`;
|
|
@@ -10306,8 +11302,11 @@ async function loadRingNode(bodyId, meta, maxTextureSize) {
|
|
|
10306
11302
|
const outerScene = kmToScene(meta.outer_radius_km);
|
|
10307
11303
|
const intensityScale = meta.intensity_scale ?? 1;
|
|
10308
11304
|
let textures;
|
|
11305
|
+
let light;
|
|
10309
11306
|
try {
|
|
10310
|
-
|
|
11307
|
+
const strip = await loadStripTextures(versionedUrl(`/v1/rings/${bodyId}/${meta.strip}`, "rings"), meta.strip_rows, maxTextureSize);
|
|
11308
|
+
textures = strip.textures;
|
|
11309
|
+
light = makeRingLight(ringProfile(strip.pixels, strip.width, meta.strip_rows, innerScene, outerScene, intensityScale));
|
|
10311
11310
|
} catch (err) {
|
|
10312
11311
|
console.warn(`Failed to load ring strip for ${bodyId}:`, err);
|
|
10313
11312
|
return null;
|
|
@@ -10316,9 +11315,7 @@ async function loadRingNode(bodyId, meta, maxTextureSize) {
|
|
|
10316
11315
|
const layers = thicknessScene > 0 ? 48 : 1;
|
|
10317
11316
|
const material = new ShaderMaterial({
|
|
10318
11317
|
uniforms: {
|
|
10319
|
-
|
|
10320
|
-
uForwardscattered: { value: textures.forwardscattered },
|
|
10321
|
-
uUnlitside: { value: textures.unlitside },
|
|
11318
|
+
uScatter: { value: textures.scatter },
|
|
10322
11319
|
uTransparency: { value: textures.transparency },
|
|
10323
11320
|
uColor: { value: textures.color },
|
|
10324
11321
|
uThickness: { value: textures.thickness ?? textures.transparency },
|
|
@@ -10334,13 +11331,17 @@ async function loadRingNode(bodyId, meta, maxTextureSize) {
|
|
|
10334
11331
|
uPlanetEquatorialScene: { value: 0 },
|
|
10335
11332
|
uPlanetPolarScene: { value: 0 },
|
|
10336
11333
|
uLightScale: { value: 1 },
|
|
10337
|
-
uIntensityScale: { value: intensityScale }
|
|
11334
|
+
uIntensityScale: { value: intensityScale },
|
|
11335
|
+
uPlanetLight: { value: light.planetLight },
|
|
11336
|
+
uPlanetAlbedo: { value: new Color(0, 0, 0) },
|
|
11337
|
+
uSunAzimuth: { value: new Vector2(1, 0) }
|
|
10338
11338
|
},
|
|
10339
11339
|
vertexShader: VERTEX_SHADER$2,
|
|
10340
11340
|
fragmentShader: FRAGMENT_SHADER$2,
|
|
10341
11341
|
transparent: true,
|
|
10342
11342
|
depthWrite: false,
|
|
10343
11343
|
blending: NormalBlending,
|
|
11344
|
+
premultipliedAlpha: true,
|
|
10344
11345
|
side: DoubleSide
|
|
10345
11346
|
});
|
|
10346
11347
|
const geometry = new RingGeometry(innerScene, outerScene * (1 / Math.cos(Math.PI / RING_ANGULAR_SEGMENTS)), RING_ANGULAR_SEGMENTS, layers > 1 ? RING_RADIAL_SEGMENTS : 1);
|
|
@@ -10371,19 +11372,20 @@ async function loadRingNode(bodyId, meta, maxTextureSize) {
|
|
|
10371
11372
|
innerScene,
|
|
10372
11373
|
outerScene,
|
|
10373
11374
|
planetShadow: null,
|
|
10374
|
-
planetShadowOnRing
|
|
11375
|
+
planetShadowOnRing,
|
|
11376
|
+
light,
|
|
11377
|
+
ringshine: null
|
|
10375
11378
|
};
|
|
10376
11379
|
}
|
|
10377
11380
|
function disposeRingNode(ring) {
|
|
10378
11381
|
ring.mesh.geometry.dispose();
|
|
10379
11382
|
const uniforms = ring.material.uniforms;
|
|
10380
11383
|
for (const key of [
|
|
10381
|
-
"
|
|
10382
|
-
"uForwardscattered",
|
|
10383
|
-
"uUnlitside",
|
|
11384
|
+
"uScatter",
|
|
10384
11385
|
"uTransparency",
|
|
10385
11386
|
"uColor",
|
|
10386
|
-
"uThickness"
|
|
11387
|
+
"uThickness",
|
|
11388
|
+
"uPlanetLight"
|
|
10387
11389
|
]) (uniforms[key]?.value)?.dispose();
|
|
10388
11390
|
ring.mesh.material.dispose();
|
|
10389
11391
|
}
|
|
@@ -10627,6 +11629,14 @@ var SHARED = {
|
|
|
10627
11629
|
uOccluders: { value: Array.from({ length: 32 }, () => new Vector4()) },
|
|
10628
11630
|
uOccluderLeak: { value: Array.from({ length: 32 }, () => new Vector4()) }
|
|
10629
11631
|
};
|
|
11632
|
+
var POOL = {
|
|
11633
|
+
occluders: [],
|
|
11634
|
+
leaks: [],
|
|
11635
|
+
count: 0
|
|
11636
|
+
};
|
|
11637
|
+
function getOccluderPool() {
|
|
11638
|
+
return POOL;
|
|
11639
|
+
}
|
|
10630
11640
|
var ECLIPSE_FACTOR_GLSL = `
|
|
10631
11641
|
#define ECLIPSE_MAX_OCCLUDERS ${32}
|
|
10632
11642
|
uniform float uSunAngularRadius;
|
|
@@ -10712,13 +11722,18 @@ function makeEclipseSelfUniforms() {
|
|
|
10712
11722
|
uOccluderCount: { value: 0 }
|
|
10713
11723
|
};
|
|
10714
11724
|
}
|
|
11725
|
+
var _kept = new Int32Array(0);
|
|
11726
|
+
var _size = new Float64Array(0);
|
|
11727
|
+
var largestFirst = (a, b) => _size[b] - _size[a];
|
|
10715
11728
|
function cullOccludersFor(dst, center, radius, sunDir, leakDst) {
|
|
10716
11729
|
const aSun = SHARED.uSunAngularRadius.value;
|
|
10717
|
-
const src =
|
|
10718
|
-
|
|
10719
|
-
|
|
11730
|
+
const src = POOL.occluders;
|
|
11731
|
+
if (_kept.length < POOL.count) {
|
|
11732
|
+
_kept = new Int32Array(POOL.count);
|
|
11733
|
+
_size = new Float64Array(POOL.count);
|
|
11734
|
+
}
|
|
10720
11735
|
let n = 0;
|
|
10721
|
-
for (let i = 0; i <
|
|
11736
|
+
for (let i = 0; i < POOL.count; i++) {
|
|
10722
11737
|
const oc = src[i];
|
|
10723
11738
|
const ox = oc.x - center.x;
|
|
10724
11739
|
const oy = oc.y - center.y;
|
|
@@ -10729,8 +11744,17 @@ function cullOccludersFor(dst, center, radius, sunDir, leakDst) {
|
|
|
10729
11744
|
if (t < -(radius + oc.w)) continue;
|
|
10730
11745
|
const reach = radius + oc.w + aSun * (t + radius) * 1.5;
|
|
10731
11746
|
if (d2 - t * t > reach * reach) continue;
|
|
10732
|
-
|
|
10733
|
-
|
|
11747
|
+
_size[i] = oc.w * oc.w / d2;
|
|
11748
|
+
_kept[n++] = i;
|
|
11749
|
+
}
|
|
11750
|
+
if (n > 32) {
|
|
11751
|
+
_kept.subarray(0, n).sort(largestFirst);
|
|
11752
|
+
n = 32;
|
|
11753
|
+
}
|
|
11754
|
+
for (let k = 0; k < n; k++) {
|
|
11755
|
+
const i = _kept[k];
|
|
11756
|
+
leakDst?.[k].copy(POOL.leaks[i]);
|
|
11757
|
+
dst[k].copy(src[i]);
|
|
10734
11758
|
}
|
|
10735
11759
|
return n;
|
|
10736
11760
|
}
|
|
@@ -11616,6 +12640,96 @@ function disposeAtmosphereNode(node) {
|
|
|
11616
12640
|
node.mesh.material.dispose();
|
|
11617
12641
|
}
|
|
11618
12642
|
|
|
12643
|
+
//#endregion
|
|
12644
|
+
//#region src/lib/scene/objects/surface/planetshine.ts
|
|
12645
|
+
var MAX_SHINERS = 2;
|
|
12646
|
+
var SHINE_FLOOR = 1e-4;
|
|
12647
|
+
function lambertSpherePhase(a) {
|
|
12648
|
+
return (Math.sin(a) + (Math.PI - a) * Math.cos(a)) / Math.PI;
|
|
12649
|
+
}
|
|
12650
|
+
function planetshineFraction(radius, distance, a) {
|
|
12651
|
+
const k = radius / distance;
|
|
12652
|
+
return 2 / 3 * lambertSpherePhase(a) * k * k;
|
|
12653
|
+
}
|
|
12654
|
+
var PLANETSHINE_GLSL = `
|
|
12655
|
+
#define PLANETSHINE_SHINERS ${2}
|
|
12656
|
+
uniform vec4 uShineDir[PLANETSHINE_SHINERS];
|
|
12657
|
+
uniform vec3 uShineLight[PLANETSHINE_SHINERS];
|
|
12658
|
+
|
|
12659
|
+
float sphereLightCosine(float cosTheta, float sinAlpha) {
|
|
12660
|
+
float t = max(cosTheta + sinAlpha, 0.0);
|
|
12661
|
+
return cosTheta >= sinAlpha ? cosTheta : t * t / (4.0 * sinAlpha);
|
|
12662
|
+
}
|
|
12663
|
+
`;
|
|
12664
|
+
var PLANETSHINE_LIGHT = `
|
|
12665
|
+
for (int i = 0; i < PLANETSHINE_SHINERS; i++) {
|
|
12666
|
+
vec4 shiner = uShineDir[i];
|
|
12667
|
+
// The slots fill in order, so the first empty slot ends the list.
|
|
12668
|
+
if (shiner.w <= 0.0) break;
|
|
12669
|
+
float cosine = sphereLightCosine(dot(geometryNormal, mat3(viewMatrix) * shiner.xyz), shiner.w);
|
|
12670
|
+
reflectedLight.indirectDiffuse += uShineLight[i] * cosine * BRDF_Lambert(material.diffuseContribution);
|
|
12671
|
+
}
|
|
12672
|
+
`;
|
|
12673
|
+
function makePlanetshineUniforms() {
|
|
12674
|
+
return {
|
|
12675
|
+
uShineDir: { value: Array.from({ length: 2 }, () => new Vector4(0, 0, 0, 0)) },
|
|
12676
|
+
uShineLight: { value: Array.from({ length: 2 }, () => new Vector3()) }
|
|
12677
|
+
};
|
|
12678
|
+
}
|
|
12679
|
+
function attachPlanetshine(material, uniforms) {
|
|
12680
|
+
const self = uniforms ?? makePlanetshineUniforms();
|
|
12681
|
+
chainShaderHook(material, "planetshine", (shader) => {
|
|
12682
|
+
Object.assign(shader.uniforms, self);
|
|
12683
|
+
shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `#include <common>\n${PLANETSHINE_GLSL}`).replace("#include <lights_fragment_end>", `#include <lights_fragment_end>\n${PLANETSHINE_LIGHT}`);
|
|
12684
|
+
});
|
|
12685
|
+
return self;
|
|
12686
|
+
}
|
|
12687
|
+
var _strength = new Float64Array(2);
|
|
12688
|
+
var _swapDir = new Vector4();
|
|
12689
|
+
var _swapLight = new Vector3();
|
|
12690
|
+
function selectShiners(out, x, y, z, shiners, count) {
|
|
12691
|
+
const dirs = out.uShineDir.value;
|
|
12692
|
+
const lights = out.uShineLight.value;
|
|
12693
|
+
let kept = 0;
|
|
12694
|
+
for (let i = 0; i < count; i++) {
|
|
12695
|
+
const s = shiners[i];
|
|
12696
|
+
const dx = s.x - x;
|
|
12697
|
+
const dy = s.y - y;
|
|
12698
|
+
const dz = s.z - z;
|
|
12699
|
+
const d2 = dx * dx + dy * dy + dz * dz;
|
|
12700
|
+
if (2 / 3 * s.radius * s.radius < 1e-4 * d2) continue;
|
|
12701
|
+
const d = Math.sqrt(d2);
|
|
12702
|
+
if (d <= s.radius) continue;
|
|
12703
|
+
const k = s.radius / d;
|
|
12704
|
+
const cosPhase = -(dx * s.sunX + dy * s.sunY + dz * s.sunZ) / d;
|
|
12705
|
+
const fraction = planetshineFraction(s.radius, d, Math.acos(Math.max(-1, Math.min(1, cosPhase))));
|
|
12706
|
+
const strength = fraction * (.2126 * s.albedo.r + .7152 * s.albedo.g + .0722 * s.albedo.b);
|
|
12707
|
+
if (strength < 1e-4) continue;
|
|
12708
|
+
let slot = kept;
|
|
12709
|
+
if (kept < 2) kept++;
|
|
12710
|
+
else if (strength > _strength[2 - 1]) slot = 2 - 1;
|
|
12711
|
+
else continue;
|
|
12712
|
+
_strength[slot] = strength;
|
|
12713
|
+
dirs[slot].set(dx / d, dy / d, dz / d, k);
|
|
12714
|
+
lights[slot].set(s.albedo.r, s.albedo.g, s.albedo.b).multiplyScalar(s.sunlight * fraction);
|
|
12715
|
+
for (; slot > 0 && _strength[slot - 1] < strength; slot--) {
|
|
12716
|
+
_strength[slot] = _strength[slot - 1];
|
|
12717
|
+
_strength[slot - 1] = strength;
|
|
12718
|
+
_swapDir.copy(dirs[slot - 1]);
|
|
12719
|
+
dirs[slot - 1].copy(dirs[slot]);
|
|
12720
|
+
dirs[slot].copy(_swapDir);
|
|
12721
|
+
_swapLight.copy(lights[slot - 1]);
|
|
12722
|
+
lights[slot - 1].copy(lights[slot]);
|
|
12723
|
+
lights[slot].copy(_swapLight);
|
|
12724
|
+
}
|
|
12725
|
+
}
|
|
12726
|
+
for (let i = kept; i < 2; i++) {
|
|
12727
|
+
dirs[i].set(0, 0, 0, 0);
|
|
12728
|
+
lights[i].set(0, 0, 0);
|
|
12729
|
+
}
|
|
12730
|
+
return kept;
|
|
12731
|
+
}
|
|
12732
|
+
|
|
11619
12733
|
//#endregion
|
|
11620
12734
|
//#region src/lib/scene/objects/surface/ring-attach.ts
|
|
11621
12735
|
function attachRingBundles(bodyId, systemId, rings, radii, bo, scene, maxTextureSize, ctx) {
|
|
@@ -11635,12 +12749,15 @@ function attachRingBundles(bodyId, systemId, rings, radii, bo, scene, maxTexture
|
|
|
11635
12749
|
return;
|
|
11636
12750
|
}
|
|
11637
12751
|
node.mesh.userData.ringBundle = ringMeta.bundle;
|
|
12752
|
+
node.light.planet = ringPlanet(radii, bo.radiusScene);
|
|
11638
12753
|
const host = bo.mesh ?? bo.model;
|
|
11639
12754
|
if (host) node.mesh.quaternion.copy(host.quaternion);
|
|
11640
12755
|
bo.rings.push(node);
|
|
11641
12756
|
bo.root.add(node.mesh);
|
|
11642
12757
|
if (bo.mesh && ringMeta === shadowCaster) {
|
|
11643
|
-
|
|
12758
|
+
const material = bo.mesh.material;
|
|
12759
|
+
node.planetShadow = attachRingShadowToPlanet(material, node.innerScene, node.outerScene, node.transparency, node.intensityScale);
|
|
12760
|
+
if (peakRingshine(node.light.profile, node.light.planet) >= 1e-4) node.ringshine = attachRingshine(material);
|
|
11644
12761
|
if (bo.atmosphere) attachRingShadowToAtmosphere(bo.atmosphere, node.planetShadow, node.transparency, node.innerScene, node.outerScene);
|
|
11645
12762
|
}
|
|
11646
12763
|
if (radii) {
|
|
@@ -11651,6 +12768,15 @@ function attachRingBundles(bodyId, systemId, rings, radii, bo, scene, maxTexture
|
|
|
11651
12768
|
}
|
|
11652
12769
|
return promises;
|
|
11653
12770
|
}
|
|
12771
|
+
function ringPlanet(radii, radiusScene) {
|
|
12772
|
+
return radii ? {
|
|
12773
|
+
equatorial: kmToScene((radii.a + radii.b) / 2),
|
|
12774
|
+
polar: kmToScene(radii.c)
|
|
12775
|
+
} : {
|
|
12776
|
+
equatorial: radiusScene,
|
|
12777
|
+
polar: radiusScene
|
|
12778
|
+
};
|
|
12779
|
+
}
|
|
11654
12780
|
|
|
11655
12781
|
//#endregion
|
|
11656
12782
|
//#region src/lib/fetch/nomenclature/parse.ts
|
|
@@ -11685,7 +12811,7 @@ function parseNomenclature(buffer) {
|
|
|
11685
12811
|
|
|
11686
12812
|
//#endregion
|
|
11687
12813
|
//#region src/lib/fetch/nomenclature/fetch.ts
|
|
11688
|
-
var cache$
|
|
12814
|
+
var cache$2 = /* @__PURE__ */ new Map();
|
|
11689
12815
|
async function fetchPositions(bodyId) {
|
|
11690
12816
|
const url = versionedUrl(`/v1/nomenclature/positions/${bodyId}.bin.gz`, "nomenclature");
|
|
11691
12817
|
const res = await fetch(url);
|
|
@@ -11713,16 +12839,16 @@ function nameFeatures(records, labelText) {
|
|
|
11713
12839
|
}
|
|
11714
12840
|
function fetchBodyNomenclature(bodyId, lang = getLocale()) {
|
|
11715
12841
|
const key = `${bodyId}:${lang}`;
|
|
11716
|
-
let p = cache$
|
|
12842
|
+
let p = cache$2.get(key);
|
|
11717
12843
|
if (!p) {
|
|
11718
12844
|
p = (async () => {
|
|
11719
12845
|
await fetchMetadata();
|
|
11720
12846
|
const [records, labels] = await Promise.all([fetchPositions(bodyId), fetchLabelText(bodyId, lang)]);
|
|
11721
12847
|
return nameFeatures(records, labels);
|
|
11722
12848
|
})();
|
|
11723
|
-
cache$
|
|
12849
|
+
cache$2.set(key, p);
|
|
11724
12850
|
p.catch(() => {
|
|
11725
|
-
if (cache$
|
|
12851
|
+
if (cache$2.get(key) === p) cache$2.delete(key);
|
|
11726
12852
|
});
|
|
11727
12853
|
}
|
|
11728
12854
|
return p;
|
|
@@ -11765,6 +12891,100 @@ function attachCanvasForwarders(el, canvas) {
|
|
|
11765
12891
|
});
|
|
11766
12892
|
}
|
|
11767
12893
|
|
|
12894
|
+
//#endregion
|
|
12895
|
+
//#region src/lib/scene/relief/worker.ts?worker&inline
|
|
12896
|
+
var jsContent$1 = "function e(e,t,n,r){return`${e&&`${e}/`}${t}/${n}/${r}.webp`}function t(e,t,n,r,i=1){let a=t.length,o=n.length,s=new Float32Array(a*o*3),c=new Float32Array(a*o*3),l=new Float32Array(a*o*2),u=Float64Array.from(n,Math.sin),d=Float64Array.from(n,Math.cos);for(let f=0;f<a;f++){let a=t[f],p=Math.sin(a),m=Math.cos(a);for(let t=0;t<o;t++){let h=f*o+t,g=-d[t]*p,_=m,v=u[t]*p,y=e+(r?r[h]*i:0),b=h*3;s[b]=y*g,s[b+1]=y*_,s[b+2]=y*v,c[b]=g,c[b+1]=_,c[b+2]=v;let x=h*2;l[x]=n[t]/(2*Math.PI),l[x+1]=1-a/Math.PI}}let f=new Uint32Array((a-1)*(o-1)*6),p=0;for(let e=0;e<a-1;e++){let n=t[e]<=0,r=t[e+1]>=Math.PI;for(let t=0;t<o-1;t++){let i=e*o+t+1,a=e*o+t,s=(e+1)*o+t,c=(e+1)*o+t+1;n||(f[p++]=i,f[p++]=a,f[p++]=c),r||(f[p++]=a,f[p++]=s,f[p++]=c)}}return{positions:s,normals:c,uvs:l,indices:f.subarray(0,p)}}const n=[``,`north`,`south`],r=Math.SQRT2-1;function i(e,t){return e===0?2<<t:1<<t-1}function a(e,t){return e===0?1<<t:1<<t-1}function o(e,t,n,i){if(e===0){let e=Math.atan2(i,-t)/(2*Math.PI);return{x:e<0?e+1:e,y:Math.acos(Math.min(Math.max(n,-1),1))/Math.PI}}let a=e===1?1:-1,o=.5/(r*(1+a*n));return{x:.5+t*o,y:.5+a*i*o}}function s(e,t,n,r){let i=e.max_level-t;return i>=0&&n>=e.x[0]>>i&&n<=e.x[1]>>i&&r>=e.y[0]>>i&&r<=e.y[1]>>i}function c(e,t,n,r){return e?.find(e=>s(e,t,n,r))}const l=Math.sin(60*Math.PI/180),u=2**18,d=2**17;function f(e,t,n,r){return((e*32+t)*u+n)*d+r}function p(e){let t=e%d,n=Math.floor(e/d)%u,r=Math.floor(e/(d*u));return{chart:Math.floor(r/32),level:r%32,x:n,y:t}}const m={chart:0,level:0,x0:0,x1:0,y0:0,y1:0,fx:0,fy:0};function h(e,t,n,r,s){let c=e<1||Math.abs(n)<=l?0:n>0?1:2,u=i(c,e)*s,d=a(c,e)*s,f=o(c,t,n,r),p=f.x*u-.5,h=f.y*d-.5,g=Math.floor(p),_=Math.floor(h),v=e=>Math.min(Math.max(e,0),u-1),y=e=>Math.min(Math.max(e,0),d-1);return m.chart=c,m.level=e,m.fx=p-g,m.fy=h-_,m.x0=c===0?(g+u)%u:v(g),m.x1=c===0?(g+1)%u:v(g+1),m.y0=y(_),m.y1=y(_+1),m}function g(e,t,n){let r=Float64Array.from(t.at,Math.sin),i=Float64Array.from(t.at,Math.cos),a=t.at.length;for(let o=0;o<e.at.length;o++){let s=Math.sin(e.at[o]),c=Math.cos(e.at[o]);for(let l=0;l<a;l++){let u=Math.min(e.level[o],t.level[l]);n(o*a+l,u,-i[l]*s,c,r[l]*s)}}}function _(e,t,n,r=1/0,i=()=>!0){let a=new Set([f(0,0,0,0),f(0,0,1,0)]);return g(e,t,(e,t,o,s,c)=>{for(let e=t;;e--){let t=h(e,o,s,c,n),l=Math.floor(t.x0/n),u=Math.floor(t.x1/n),d=Math.floor(t.y0/n),p=Math.floor(t.y1/n);if(!(e>r&&!(i(t.chart,e,l,d)&&i(t.chart,e,u,d)&&i(t.chart,e,l,p)&&i(t.chart,e,u,p)))){a.add(f(t.chart,e,l,d)),u!==l&&a.add(f(t.chart,e,u,d)),p!==d&&(a.add(f(t.chart,e,l,p)),u!==l&&a.add(f(t.chart,e,u,p)));return}}}),a}function v(e,t,n,r,i,a){for(let o=t;o>=0;o--){let t=h(o,n,r,i,a),s=(n,r)=>{let i=e(f(t.chart,o,Math.floor(n/a),Math.floor(r/a)));return i&&i[r%a*a+n%a]},c=s(t.x0,t.y0),l=s(t.x1,t.y0),u=s(t.x0,t.y1),d=s(t.x1,t.y1);if(c===void 0||l===void 0||u===void 0||d===void 0)continue;let p=c+(l-c)*t.fx;return p+(u+(d-u)*t.fx-p)*t.fy}}function y(e,t,n,r,i,a){let o=new Float32Array(e.at.length*t.at.length),s=!1;return g(e,t,(e,t,c,l,u)=>{let d=v(n,t,c,l,u,r);d===void 0?s=!0:o[e]=a+i*d/65535}),s?null:o}function b(e,t){let n=new Uint8Array(t*t*2);for(let r=0;r<t;r++){let i=(t-1-r)*t*4,a=r*t*2;for(let r=0;r<t;r++,i+=4,a+=2)n[a]=e[i],n[a+1]=e[i+1]}return n}function x(e,t){let n=new Float32Array(t*t);for(let r=0;r<t;r++){let i=(t-1-r)*t*4,a=(r+1)*t;for(let o=r*t;o<a;o++,i+=4)n[o]=(e[i]<<8|e[i+1])+e[i+2]/256}return n}function S(e,t,n){let r=n?new Float32Array(t*t):new Uint16Array(t*t);for(let t=0,i=0;t<r.length;t++,i+=4){let a=e[i]<<8|e[i+1];r[t]=n?a+e[i+2]/256:a}return r}const C=self,w=new Map;let T;async function E(e,t){let n=await fetch(e,{signal:t});if(!n.ok)throw Error(`tile ${n.status}`);let r=await createImageBitmap(await n.blob(),{premultiplyAlpha:`none`,colorSpaceConversion:`none`}),i=r.width;T?.width!==i&&(T=new OffscreenCanvas(i,i));let a=T.getContext(`2d`,{willReadFrequently:!0});if(!a)throw Error(`no 2d canvas in this worker`);return a.globalCompositeOperation=`copy`,a.drawImage(r,0,0),r.close(),{rgba:a.getImageData(0,0,i,i).data,size:i}}async function D(e,t){let{rgba:n,size:r}=await E(e.url,t),i=e.fine?x(n,r):b(n,r);C.postMessage({type:`tile`,id:e.id,size:r,heights:i},[i.buffer])}const O=new Map;let k=``;async function A(r,i){let{rows:a,columns:o,tileSize:s,maxLevel:l,patches:u}=r,d=[r.version,...u.map(e=>e.version)],f=`${r.root}?${d.join()}`;f!==k&&O.clear(),k=f;let m=(e,t,n,r)=>e===0?c(u,t,n,r):void 0,h=_(a,o,s,l,(e,t,n,r)=>m(e,t,n,r)!==void 0),g=[...h].filter(e=>!O.has(e));await Promise.all(Array.from({length:6},async()=>{for(let t=g.pop();t!==void 0;t=g.pop()){let{chart:a,level:o,x:s,y:c}=p(t),u=o>l,d=u?m(a,o,s,c)?.version:r.version,f=`${r.root}${e(n[a],o,s,c)}?v=${d}`;try{let{rgba:e,size:n}=await E(f,i);O.set(t,S(e,n,u))}catch{if(i.aborted)return}}})),i.throwIfAborted();let v=y(a,o,e=>O.get(e),s,r.scaleKm,r.biasKm);for(let e of[...O.keys()])h.has(e)||O.delete(e);if(!v)throw Error(`no height tiles for the grid`);let b=t(r.radius,a.at,o.at,v,r.unitsPerKm),x=b.indices.slice();C.postMessage({type:`grid`,id:r.id,...b,indices:x,riseKm:v},[b.positions.buffer,b.normals.buffer,b.uvs.buffer,x.buffer,v.buffer])}async function j(e){let t=new AbortController;w.set(e.id,t);try{e.type===`tile`?await D(e,t.signal):await A(e,t.signal)}catch{C.postMessage({type:`failed`,id:e.id})}finally{w.delete(e.id)}}self.onmessage=e=>{let t=e.data;t.type===`abort`?w.get(t.id)?.abort():j(t)};";
|
|
12897
|
+
var blob$1 = typeof self !== "undefined" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", jsContent$1], { type: "text/javascript;charset=utf-8" });
|
|
12898
|
+
function WorkerWrapper$1(options) {
|
|
12899
|
+
let objURL;
|
|
12900
|
+
try {
|
|
12901
|
+
objURL = blob$1 && (self.URL || self.webkitURL).createObjectURL(blob$1);
|
|
12902
|
+
if (!objURL) throw "";
|
|
12903
|
+
const worker = new Worker(objURL, {
|
|
12904
|
+
type: "module",
|
|
12905
|
+
name: options?.name
|
|
12906
|
+
});
|
|
12907
|
+
worker.addEventListener("error", () => {
|
|
12908
|
+
(self.URL || self.webkitURL).revokeObjectURL(objURL);
|
|
12909
|
+
});
|
|
12910
|
+
return worker;
|
|
12911
|
+
} catch (e) {
|
|
12912
|
+
return new Worker("data:text/javascript;charset=utf-8," + encodeURIComponent(jsContent$1), {
|
|
12913
|
+
type: "module",
|
|
12914
|
+
name: options?.name
|
|
12915
|
+
});
|
|
12916
|
+
}
|
|
12917
|
+
}
|
|
12918
|
+
|
|
12919
|
+
//#endregion
|
|
12920
|
+
//#region src/lib/scene/relief/client.ts
|
|
12921
|
+
var worker = null;
|
|
12922
|
+
var nextId = 1;
|
|
12923
|
+
var pending$1 = /* @__PURE__ */ new Map();
|
|
12924
|
+
function drop(reason) {
|
|
12925
|
+
worker?.terminate();
|
|
12926
|
+
worker = null;
|
|
12927
|
+
const lost = [...pending$1.values()];
|
|
12928
|
+
pending$1.clear();
|
|
12929
|
+
for (const { reject } of lost) reject(new Error(reason));
|
|
12930
|
+
}
|
|
12931
|
+
function ensureWorker() {
|
|
12932
|
+
if (worker) return worker;
|
|
12933
|
+
worker = new WorkerWrapper$1();
|
|
12934
|
+
worker.onmessage = (ev) => {
|
|
12935
|
+
const msg = ev.data;
|
|
12936
|
+
const request = pending$1.get(msg.id);
|
|
12937
|
+
pending$1.delete(msg.id);
|
|
12938
|
+
if (!request) return;
|
|
12939
|
+
if (msg.type === "failed") request.reject(/* @__PURE__ */ new Error("relief worker could not answer"));
|
|
12940
|
+
else request.resolve(msg);
|
|
12941
|
+
};
|
|
12942
|
+
worker.onerror = (ev) => drop(`relief worker error: ${ev.message || "unknown"}`);
|
|
12943
|
+
worker.onmessageerror = () => drop("relief worker sent a message that could not be read");
|
|
12944
|
+
return worker;
|
|
12945
|
+
}
|
|
12946
|
+
function ask(build, signal) {
|
|
12947
|
+
return new Promise((resolve, reject) => {
|
|
12948
|
+
if (typeof Worker === "undefined") {
|
|
12949
|
+
reject(/* @__PURE__ */ new Error("no workers here"));
|
|
12950
|
+
return;
|
|
12951
|
+
}
|
|
12952
|
+
const id = nextId++;
|
|
12953
|
+
pending$1.set(id, {
|
|
12954
|
+
resolve,
|
|
12955
|
+
reject
|
|
12956
|
+
});
|
|
12957
|
+
signal.addEventListener("abort", () => {
|
|
12958
|
+
if (!pending$1.delete(id)) return;
|
|
12959
|
+
ensureWorker().postMessage({
|
|
12960
|
+
type: "abort",
|
|
12961
|
+
id
|
|
12962
|
+
});
|
|
12963
|
+
reject(new DOMException("aborted", "AbortError"));
|
|
12964
|
+
}, { once: true });
|
|
12965
|
+
ensureWorker().postMessage(build(id));
|
|
12966
|
+
});
|
|
12967
|
+
}
|
|
12968
|
+
function absolute(url) {
|
|
12969
|
+
return new URL(url, location.href).href;
|
|
12970
|
+
}
|
|
12971
|
+
function loadHeightTile(url, fine, signal) {
|
|
12972
|
+
return ask((id) => ({
|
|
12973
|
+
type: "tile",
|
|
12974
|
+
id,
|
|
12975
|
+
url: absolute(url),
|
|
12976
|
+
fine
|
|
12977
|
+
}), signal);
|
|
12978
|
+
}
|
|
12979
|
+
function buildTerrainGrid(spec, signal) {
|
|
12980
|
+
return ask((id) => ({
|
|
12981
|
+
...spec,
|
|
12982
|
+
type: "grid",
|
|
12983
|
+
id,
|
|
12984
|
+
root: absolute(spec.root)
|
|
12985
|
+
}), signal);
|
|
12986
|
+
}
|
|
12987
|
+
|
|
11768
12988
|
//#endregion
|
|
11769
12989
|
//#region src/lib/scene/lod/tile-window.ts
|
|
11770
12990
|
var WINDOW_TILES = 4;
|
|
@@ -11919,100 +13139,6 @@ function slotTile(placement, sx, sy) {
|
|
|
11919
13139
|
};
|
|
11920
13140
|
}
|
|
11921
13141
|
|
|
11922
|
-
//#endregion
|
|
11923
|
-
//#region src/lib/scene/relief/worker.ts?worker&inline
|
|
11924
|
-
var jsContent$1 = "function e(e,t,n,r){return`${e&&`${e}/`}${t}/${n}/${r}.webp`}function t(e,t,n,r,i=1){let a=t.length,o=n.length,s=new Float32Array(a*o*3),c=new Float32Array(a*o*3),l=new Float32Array(a*o*2),u=Float64Array.from(n,Math.sin),d=Float64Array.from(n,Math.cos);for(let f=0;f<a;f++){let a=t[f],p=Math.sin(a),m=Math.cos(a);for(let t=0;t<o;t++){let h=f*o+t,g=-d[t]*p,_=m,v=u[t]*p,y=e+(r?r[h]*i:0),b=h*3;s[b]=y*g,s[b+1]=y*_,s[b+2]=y*v,c[b]=g,c[b+1]=_,c[b+2]=v;let x=h*2;l[x]=n[t]/(2*Math.PI),l[x+1]=1-a/Math.PI}}let f=new Uint32Array((a-1)*(o-1)*6),p=0;for(let e=0;e<a-1;e++){let n=t[e]<=0,r=t[e+1]>=Math.PI;for(let t=0;t<o-1;t++){let i=e*o+t+1,a=e*o+t,s=(e+1)*o+t,c=(e+1)*o+t+1;n||(f[p++]=i,f[p++]=a,f[p++]=c),r||(f[p++]=a,f[p++]=s,f[p++]=c)}}return{positions:s,normals:c,uvs:l,indices:f.subarray(0,p)}}const n=[``,`north`,`south`],r=Math.SQRT2-1;function i(e,t){return e===0?2<<t:1<<t-1}function a(e,t){return e===0?1<<t:1<<t-1}function o(e,t,n,i){if(e===0){let e=Math.atan2(i,-t)/(2*Math.PI);return{x:e<0?e+1:e,y:Math.acos(Math.min(Math.max(n,-1),1))/Math.PI}}let a=e===1?1:-1,o=.5/(r*(1+a*n));return{x:.5+t*o,y:.5+a*i*o}}function s(e,t,n,r){let i=e.max_level-t;return i>=0&&n>=e.x[0]>>i&&n<=e.x[1]>>i&&r>=e.y[0]>>i&&r<=e.y[1]>>i}function c(e,t,n,r){return e?.find(e=>s(e,t,n,r))}const l=Math.sin(60*Math.PI/180),u=2**18,d=2**17;function f(e,t,n,r){return((e*32+t)*u+n)*d+r}function p(e){let t=e%d,n=Math.floor(e/d)%u,r=Math.floor(e/(d*u));return{chart:Math.floor(r/32),level:r%32,x:n,y:t}}const m={chart:0,level:0,x0:0,x1:0,y0:0,y1:0,fx:0,fy:0};function h(e,t,n,r,s){let c=e<1||Math.abs(n)<=l?0:n>0?1:2,u=i(c,e)*s,d=a(c,e)*s,f=o(c,t,n,r),p=f.x*u-.5,h=f.y*d-.5,g=Math.floor(p),_=Math.floor(h),v=e=>Math.min(Math.max(e,0),u-1),y=e=>Math.min(Math.max(e,0),d-1);return m.chart=c,m.level=e,m.fx=p-g,m.fy=h-_,m.x0=c===0?(g+u)%u:v(g),m.x1=c===0?(g+1)%u:v(g+1),m.y0=y(_),m.y1=y(_+1),m}function g(e,t,n){let r=Float64Array.from(t.at,Math.sin),i=Float64Array.from(t.at,Math.cos),a=t.at.length;for(let o=0;o<e.at.length;o++){let s=Math.sin(e.at[o]),c=Math.cos(e.at[o]);for(let l=0;l<a;l++){let u=Math.min(e.level[o],t.level[l]);n(o*a+l,u,-i[l]*s,c,r[l]*s)}}}function _(e,t,n,r=1/0,i=()=>!0){let a=new Set([f(0,0,0,0),f(0,0,1,0)]);return g(e,t,(e,t,o,s,c)=>{for(let e=t;;e--){let t=h(e,o,s,c,n),l=Math.floor(t.x0/n),u=Math.floor(t.x1/n),d=Math.floor(t.y0/n),p=Math.floor(t.y1/n);if(!(e>r&&!(i(t.chart,e,l,d)&&i(t.chart,e,u,d)&&i(t.chart,e,l,p)&&i(t.chart,e,u,p)))){a.add(f(t.chart,e,l,d)),u!==l&&a.add(f(t.chart,e,u,d)),p!==d&&(a.add(f(t.chart,e,l,p)),u!==l&&a.add(f(t.chart,e,u,p)));return}}}),a}function v(e,t,n,r,i,a){for(let o=t;o>=0;o--){let t=h(o,n,r,i,a),s=(n,r)=>{let i=e(f(t.chart,o,Math.floor(n/a),Math.floor(r/a)));return i&&i[r%a*a+n%a]},c=s(t.x0,t.y0),l=s(t.x1,t.y0),u=s(t.x0,t.y1),d=s(t.x1,t.y1);if(c===void 0||l===void 0||u===void 0||d===void 0)continue;let p=c+(l-c)*t.fx;return p+(u+(d-u)*t.fx-p)*t.fy}}function y(e,t,n,r,i,a){let o=new Float32Array(e.at.length*t.at.length),s=!1;return g(e,t,(e,t,c,l,u)=>{let d=v(n,t,c,l,u,r);d===void 0?s=!0:o[e]=a+i*d/65535}),s?null:o}function b(e,t){let n=new Uint8Array(t*t*2);for(let r=0;r<t;r++){let i=(t-1-r)*t*4,a=r*t*2;for(let r=0;r<t;r++,i+=4,a+=2)n[a]=e[i],n[a+1]=e[i+1]}return n}function x(e,t){let n=new Float32Array(t*t);for(let r=0;r<t;r++){let i=(t-1-r)*t*4,a=(r+1)*t;for(let o=r*t;o<a;o++,i+=4)n[o]=(e[i]<<8|e[i+1])+e[i+2]/256}return n}function S(e,t,n){let r=n?new Float32Array(t*t):new Uint16Array(t*t);for(let t=0,i=0;t<r.length;t++,i+=4){let a=e[i]<<8|e[i+1];r[t]=n?a+e[i+2]/256:a}return r}const C=self,w=new Map;let T;async function E(e,t){let n=await fetch(e,{signal:t});if(!n.ok)throw Error(`tile ${n.status}`);let r=await createImageBitmap(await n.blob(),{premultiplyAlpha:`none`,colorSpaceConversion:`none`}),i=r.width;T?.width!==i&&(T=new OffscreenCanvas(i,i));let a=T.getContext(`2d`,{willReadFrequently:!0});if(!a)throw Error(`no 2d canvas in this worker`);return a.globalCompositeOperation=`copy`,a.drawImage(r,0,0),r.close(),{rgba:a.getImageData(0,0,i,i).data,size:i}}async function D(e,t){let{rgba:n,size:r}=await E(e.url,t),i=e.fine?x(n,r):b(n,r);C.postMessage({type:`tile`,id:e.id,size:r,heights:i},[i.buffer])}const O=new Map;let k=``;async function A(r,i){let{rows:a,columns:o,tileSize:s,maxLevel:l,patches:u}=r,d=[r.version,...u.map(e=>e.version)],f=`${r.root}?${d.join()}`;f!==k&&O.clear(),k=f;let m=(e,t,n,r)=>e===0?c(u,t,n,r):void 0,h=_(a,o,s,l,(e,t,n,r)=>m(e,t,n,r)!==void 0),g=[...h].filter(e=>!O.has(e));await Promise.all(Array.from({length:6},async()=>{for(let t=g.pop();t!==void 0;t=g.pop()){let{chart:a,level:o,x:s,y:c}=p(t),u=o>l,d=u?m(a,o,s,c)?.version:r.version,f=`${r.root}${e(n[a],o,s,c)}?v=${d}`;try{let{rgba:e,size:n}=await E(f,i);O.set(t,S(e,n,u))}catch{if(i.aborted)return}}})),i.throwIfAborted();let v=y(a,o,e=>O.get(e),s,r.scaleKm,r.biasKm);for(let e of[...O.keys()])h.has(e)||O.delete(e);if(!v)throw Error(`no height tiles for the grid`);let b=t(r.radius,a.at,o.at,v,r.unitsPerKm),x=b.indices.slice();C.postMessage({type:`grid`,id:r.id,...b,indices:x,riseKm:v},[b.positions.buffer,b.normals.buffer,b.uvs.buffer,x.buffer,v.buffer])}async function j(e){let t=new AbortController;w.set(e.id,t);try{e.type===`tile`?await D(e,t.signal):await A(e,t.signal)}catch{C.postMessage({type:`failed`,id:e.id})}finally{w.delete(e.id)}}self.onmessage=e=>{let t=e.data;t.type===`abort`?w.get(t.id)?.abort():j(t)};";
|
|
11925
|
-
var blob$1 = typeof self !== "undefined" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", jsContent$1], { type: "text/javascript;charset=utf-8" });
|
|
11926
|
-
function WorkerWrapper$1(options) {
|
|
11927
|
-
let objURL;
|
|
11928
|
-
try {
|
|
11929
|
-
objURL = blob$1 && (self.URL || self.webkitURL).createObjectURL(blob$1);
|
|
11930
|
-
if (!objURL) throw "";
|
|
11931
|
-
const worker = new Worker(objURL, {
|
|
11932
|
-
type: "module",
|
|
11933
|
-
name: options?.name
|
|
11934
|
-
});
|
|
11935
|
-
worker.addEventListener("error", () => {
|
|
11936
|
-
(self.URL || self.webkitURL).revokeObjectURL(objURL);
|
|
11937
|
-
});
|
|
11938
|
-
return worker;
|
|
11939
|
-
} catch (e) {
|
|
11940
|
-
return new Worker("data:text/javascript;charset=utf-8," + encodeURIComponent(jsContent$1), {
|
|
11941
|
-
type: "module",
|
|
11942
|
-
name: options?.name
|
|
11943
|
-
});
|
|
11944
|
-
}
|
|
11945
|
-
}
|
|
11946
|
-
|
|
11947
|
-
//#endregion
|
|
11948
|
-
//#region src/lib/scene/relief/client.ts
|
|
11949
|
-
var worker = null;
|
|
11950
|
-
var nextId = 1;
|
|
11951
|
-
var pending$1 = /* @__PURE__ */ new Map();
|
|
11952
|
-
function drop(reason) {
|
|
11953
|
-
worker?.terminate();
|
|
11954
|
-
worker = null;
|
|
11955
|
-
const lost = [...pending$1.values()];
|
|
11956
|
-
pending$1.clear();
|
|
11957
|
-
for (const { reject } of lost) reject(new Error(reason));
|
|
11958
|
-
}
|
|
11959
|
-
function ensureWorker() {
|
|
11960
|
-
if (worker) return worker;
|
|
11961
|
-
worker = new WorkerWrapper$1();
|
|
11962
|
-
worker.onmessage = (ev) => {
|
|
11963
|
-
const msg = ev.data;
|
|
11964
|
-
const request = pending$1.get(msg.id);
|
|
11965
|
-
pending$1.delete(msg.id);
|
|
11966
|
-
if (!request) return;
|
|
11967
|
-
if (msg.type === "failed") request.reject(/* @__PURE__ */ new Error("relief worker could not answer"));
|
|
11968
|
-
else request.resolve(msg);
|
|
11969
|
-
};
|
|
11970
|
-
worker.onerror = (ev) => drop(`relief worker error: ${ev.message || "unknown"}`);
|
|
11971
|
-
worker.onmessageerror = () => drop("relief worker sent a message that could not be read");
|
|
11972
|
-
return worker;
|
|
11973
|
-
}
|
|
11974
|
-
function ask(build, signal) {
|
|
11975
|
-
return new Promise((resolve, reject) => {
|
|
11976
|
-
if (typeof Worker === "undefined") {
|
|
11977
|
-
reject(/* @__PURE__ */ new Error("no workers here"));
|
|
11978
|
-
return;
|
|
11979
|
-
}
|
|
11980
|
-
const id = nextId++;
|
|
11981
|
-
pending$1.set(id, {
|
|
11982
|
-
resolve,
|
|
11983
|
-
reject
|
|
11984
|
-
});
|
|
11985
|
-
signal.addEventListener("abort", () => {
|
|
11986
|
-
if (!pending$1.delete(id)) return;
|
|
11987
|
-
ensureWorker().postMessage({
|
|
11988
|
-
type: "abort",
|
|
11989
|
-
id
|
|
11990
|
-
});
|
|
11991
|
-
reject(new DOMException("aborted", "AbortError"));
|
|
11992
|
-
}, { once: true });
|
|
11993
|
-
ensureWorker().postMessage(build(id));
|
|
11994
|
-
});
|
|
11995
|
-
}
|
|
11996
|
-
function absolute(url) {
|
|
11997
|
-
return new URL(url, location.href).href;
|
|
11998
|
-
}
|
|
11999
|
-
function loadHeightTile(url, fine, signal) {
|
|
12000
|
-
return ask((id) => ({
|
|
12001
|
-
type: "tile",
|
|
12002
|
-
id,
|
|
12003
|
-
url: absolute(url),
|
|
12004
|
-
fine
|
|
12005
|
-
}), signal);
|
|
12006
|
-
}
|
|
12007
|
-
function buildTerrainGrid(spec, signal) {
|
|
12008
|
-
return ask((id) => ({
|
|
12009
|
-
...spec,
|
|
12010
|
-
type: "grid",
|
|
12011
|
-
id,
|
|
12012
|
-
root: absolute(spec.root)
|
|
12013
|
-
}), signal);
|
|
12014
|
-
}
|
|
12015
|
-
|
|
12016
13142
|
//#endregion
|
|
12017
13143
|
//#region src/lib/scene/render-tier.ts
|
|
12018
13144
|
var RENDER_TIER_PRESETS = {
|
|
@@ -12103,37 +13229,28 @@ var TILE_CHAIN_GLSL = `
|
|
|
12103
13229
|
#ifndef TILE_CHAIN
|
|
12104
13230
|
#define TILE_CHAIN
|
|
12105
13231
|
|
|
12106
|
-
//
|
|
12107
|
-
//
|
|
12108
|
-
// the cap is from the chart's north-west corner. The place on the map is from
|
|
12109
|
-
// the point that the maker of the charts counts from.
|
|
12110
|
-
struct TileCharts {
|
|
12111
|
-
vec2 mapAt;
|
|
12112
|
-
vec2 mapDx;
|
|
12113
|
-
vec2 mapDy;
|
|
12114
|
-
vec2 capAt;
|
|
12115
|
-
vec2 capDx;
|
|
12116
|
-
vec2 capDy;
|
|
12117
|
-
float side;
|
|
12118
|
-
};
|
|
13232
|
+
// A fragment on one chart is a mat3x2: its place, as a fraction of the
|
|
13233
|
+
// chart, then what a screen pixel adds to that along x and along y.
|
|
12119
13234
|
|
|
12120
|
-
// The cap of the hemisphere of dir, seen from above its pole
|
|
12121
|
-
// what a screen pixel
|
|
12122
|
-
|
|
13235
|
+
// The cap of the hemisphere of dir, seen from above its pole: the place is
|
|
13236
|
+
// from the chart's north-west corner. ddx and ddy are what a screen pixel
|
|
13237
|
+
// adds to dir.
|
|
13238
|
+
void tileCap( vec3 dir, vec3 ddx, vec3 ddy, out float side, out mat3x2 cap ) {
|
|
12123
13239
|
side = dir.y < 0.0 ? - 1.0 : 1.0;
|
|
12124
13240
|
float fold = 1.0 + side * dir.y;
|
|
12125
13241
|
vec2 plane = vec2( dir.x, side * dir.z );
|
|
12126
13242
|
float capScale = 0.5 / ( ${CAP_EDGE.toFixed(8)} * fold );
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
13243
|
+
cap = mat3x2(
|
|
13244
|
+
0.5 + plane * capScale,
|
|
13245
|
+
( vec2( ddx.x, side * ddx.z ) - plane * ( side * ddx.y / fold ) ) * capScale,
|
|
13246
|
+
( vec2( ddy.x, side * ddy.z ) - plane * ( side * ddy.y / fold ) ) * capScale
|
|
13247
|
+
);
|
|
12130
13248
|
}
|
|
12131
13249
|
|
|
12132
|
-
// The
|
|
12133
|
-
//
|
|
12134
|
-
// the offset keeps its own.
|
|
12135
|
-
|
|
12136
|
-
TileCharts charts;
|
|
13250
|
+
// The point at + off on the map, counted from at, and on the cap of its own
|
|
13251
|
+
// hemisphere, which side gives. A position on the sphere has seven digits,
|
|
13252
|
+
// and a tile index of a patch takes them all; the offset keeps its own.
|
|
13253
|
+
void tileChartsFrom( vec3 at, vec3 off, out mat3x2 map, out mat3x2 cap, out float side ) {
|
|
12137
13254
|
vec3 pos = at + off;
|
|
12138
13255
|
vec3 ox = dFdx( off );
|
|
12139
13256
|
vec3 oy = dFdy( off );
|
|
@@ -12146,19 +13263,20 @@ TileCharts tileChartsFrom( vec3 at, vec3 off ) {
|
|
|
12146
13263
|
float turn = atan( at.z * off.x - at.x * off.z, at.x * pos.x + at.z * pos.z );
|
|
12147
13264
|
float out1 = ( 2.0 * ( at.x * off.x + at.z * off.z ) + off.x * off.x + off.z * off.z ) / ( flat1 + flat0 );
|
|
12148
13265
|
float drop = atan( out1 * at.y - off.y * flat0, pos.y * at.y + flat1 * flat0 );
|
|
12149
|
-
charts.mapAt = vec2( turn / ( 2.0 * PI ), drop / PI );
|
|
12150
13266
|
float east = 1.0 / ( 2.0 * PI * flat2 );
|
|
12151
13267
|
float south = 1.0 / ( PI * dot( pos, pos ) );
|
|
12152
|
-
|
|
12153
|
-
|
|
13268
|
+
map = mat3x2(
|
|
13269
|
+
turn / ( 2.0 * PI ), drop / PI,
|
|
13270
|
+
( pos.z * ox.x - pos.x * ox.z ) * east, ( pos.y * ( pos.x * ox.x + pos.z * ox.z ) / flat1 - flat1 * ox.y ) * south,
|
|
13271
|
+
( pos.z * oy.x - pos.x * oy.z ) * east, ( pos.y * ( pos.x * oy.x + pos.z * oy.z ) / flat1 - flat1 * oy.y ) * south
|
|
13272
|
+
);
|
|
12154
13273
|
|
|
12155
13274
|
// A cap goes no deeper than the pyramid, so the direction itself will do.
|
|
12156
13275
|
float range = length( pos );
|
|
12157
13276
|
vec3 dir = pos / range;
|
|
12158
13277
|
vec3 ddx = ( ox - dir * dot( dir, ox ) ) / range;
|
|
12159
13278
|
vec3 ddy = ( oy - dir * dot( dir, oy ) ) / range;
|
|
12160
|
-
tileCap( dir, ddx, ddy,
|
|
12161
|
-
return charts;
|
|
13279
|
+
tileCap( dir, ddx, ddy, side, cap );
|
|
12162
13280
|
}
|
|
12163
13281
|
|
|
12164
13282
|
// Long and short half-axes of the footprint whose sides are fx and fy. The
|
|
@@ -12182,12 +13300,13 @@ void tileAxes( vec2 fx, vec2 fy, out vec2 major, out vec2 minor ) {
|
|
|
12182
13300
|
// home is the point that the charts count the map from, in tiles from the
|
|
12183
13301
|
// window's north-west corner. Gives the fragment's place in the window's
|
|
12184
13302
|
// texture, in tiles, and the axes of its footprint, in the window's pixels.
|
|
12185
|
-
float tileWindowWeight(
|
|
13303
|
+
float tileWindowWeight( mat3x2 map, mat3x2 cap, float side, vec4 window, vec4 grid, vec2 home, vec2 tileFilter, out vec2 spot, out vec2 major, out vec2 minor ) {
|
|
12186
13304
|
bool onMap = window.x < 0.5;
|
|
12187
13305
|
// The other pole's cap.
|
|
12188
|
-
if ( ! onMap && ( window.x < 1.5 ) != (
|
|
12189
|
-
|
|
12190
|
-
vec2
|
|
13306
|
+
if ( ! onMap && ( window.x < 1.5 ) != ( side > 0.0 ) ) return 0.0;
|
|
13307
|
+
mat3x2 chart = onMap ? map : cap;
|
|
13308
|
+
vec2 dx = chart[ 1 ] * grid.xy * tileFilter.y;
|
|
13309
|
+
vec2 dy = chart[ 2 ] * grid.xy * tileFilter.y;
|
|
12191
13310
|
|
|
12192
13311
|
// Level this fragment asks of the window, from the short axis of its
|
|
12193
13312
|
// footprint in the window's pixels: the long axis is the anisotropic
|
|
@@ -12200,7 +13319,7 @@ float tileWindowWeight( TileCharts charts, vec4 window, vec4 grid, vec2 home, ve
|
|
|
12200
13319
|
|
|
12201
13320
|
float rows = ${4 .toFixed(1)};
|
|
12202
13321
|
// Offset from the window's north-west corner, in tiles.
|
|
12203
|
-
vec2 rel = onMap ? home +
|
|
13322
|
+
vec2 rel = onMap ? home + chart[ 0 ] * grid.xy : chart[ 0 ] * grid.xy - grid.zw;
|
|
12204
13323
|
if ( onMap ) {
|
|
12205
13324
|
// Half a pixel in from a pole of the map: past it the filter would
|
|
12206
13325
|
// read the far row. The map's longitude wraps.
|
|
@@ -12511,40 +13630,35 @@ float reliefValue( vec4 texel ) {
|
|
|
12511
13630
|
return dot( texel, uReliefRead );
|
|
12512
13631
|
}
|
|
12513
13632
|
|
|
12514
|
-
// How the coordinates of each chart change along the sphere at a direction
|
|
12515
|
-
//
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
vec3 mapY;
|
|
12519
|
-
vec3 capX;
|
|
12520
|
-
vec3 capY;
|
|
12521
|
-
};
|
|
12522
|
-
|
|
12523
|
-
ReliefRates reliefRates( vec3 dir, float side ) {
|
|
12524
|
-
ReliefRates rates;
|
|
13633
|
+
// How the coordinates of each chart change along the sphere at a direction,
|
|
13634
|
+
// as a mat2x3 per chart: a step along the sphere times it is that step on the
|
|
13635
|
+
// chart, and it times a step on the chart is that step along the sphere.
|
|
13636
|
+
void reliefRates( vec3 dir, float side, out mat2x3 map, out mat2x3 cap ) {
|
|
12525
13637
|
float flat2 = max( dir.x * dir.x + dir.z * dir.z, 1e-12 );
|
|
12526
|
-
|
|
12527
|
-
|
|
13638
|
+
map = mat2x3(
|
|
13639
|
+
vec3( dir.z, 0.0, - dir.x ) / ( 2.0 * PI * flat2 ),
|
|
13640
|
+
( dir * dir.y - vec3( 0.0, 1.0, 0.0 ) ) / ( PI * sqrt( flat2 ) )
|
|
13641
|
+
);
|
|
12528
13642
|
float fold = 1.0 + side * dir.y;
|
|
12529
13643
|
float capScale = 0.5 / ( ${CAP_EDGE.toFixed(8)} * fold );
|
|
12530
13644
|
vec2 plane = vec2( dir.x, side * dir.z ) * side / fold;
|
|
12531
|
-
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
rates.capY -= dir * dot( rates.capY, dir );
|
|
12535
|
-
return rates;
|
|
13645
|
+
vec3 capX = vec3( 1.0, - plane.x, 0.0 ) * capScale;
|
|
13646
|
+
vec3 capY = vec3( 0.0, - plane.y, side ) * capScale;
|
|
13647
|
+
cap = mat2x3( capX - dir * dot( capX, dir ), capY - dir * dot( capY, dir ) );
|
|
12536
13648
|
}
|
|
12537
13649
|
|
|
12538
13650
|
// Slope of the ground at a direction of the body's frame: a vector along the
|
|
12539
13651
|
// unit sphere that points uphill, as long as the rise over the run. Also
|
|
12540
13652
|
// gives the part of the fragment that the tiles answer for, and the finest
|
|
12541
13653
|
// window that does, or -1.
|
|
12542
|
-
vec3 reliefTileSlope( vec3 dir,
|
|
13654
|
+
vec3 reliefTileSlope( vec3 dir, mat3x2 map, mat3x2 cap, float side, out float covered, out int first ) {
|
|
12543
13655
|
covered = 0.0;
|
|
12544
13656
|
first = - 1;
|
|
12545
13657
|
vec3 slope = vec3( 0.0 );
|
|
12546
13658
|
if ( uReliefWindow[ 0 ].w < 0.5 ) return slope;
|
|
12547
|
-
|
|
13659
|
+
mat2x3 mapRates;
|
|
13660
|
+
mat2x3 capRates;
|
|
13661
|
+
reliefRates( dir, side, mapRates, capRates );
|
|
12548
13662
|
|
|
12549
13663
|
float rows = ${4 .toFixed(1)};
|
|
12550
13664
|
for ( int i = 0; i < ${7}; i ++ ) {
|
|
@@ -12554,7 +13668,7 @@ vec3 reliefTileSlope( vec3 dir, TileCharts charts, out float covered, out int fi
|
|
|
12554
13668
|
vec2 spot;
|
|
12555
13669
|
vec2 major;
|
|
12556
13670
|
vec2 minor;
|
|
12557
|
-
float alpha = tileWindowWeight(
|
|
13671
|
+
float alpha = tileWindowWeight( map, cap, side, window, grid, uReliefHome[ i ], uReliefFilter, spot, major, minor );
|
|
12558
13672
|
if ( alpha <= 0.0 ) continue;
|
|
12559
13673
|
// Filtered, the mask falls towards a missing tile. The pixels beside
|
|
12560
13674
|
// one are left out: their slope would read its blank slot.
|
|
@@ -12573,8 +13687,7 @@ vec3 reliefTileSlope( vec3 dir, TileCharts charts, out float covered, out int fi
|
|
|
12573
13687
|
reliefValue( textureGrad( uReliefMap, st + east, gx, gy ) ) - reliefValue( textureGrad( uReliefMap, st - east, gx, gy ) ),
|
|
12574
13688
|
reliefValue( textureGrad( uReliefMap, st + south, gx, gy ) ) - reliefValue( textureGrad( uReliefMap, st - south, gx, gy ) )
|
|
12575
13689
|
) * 0.5 * grid.xy * uReliefFilter.y;
|
|
12576
|
-
|
|
12577
|
-
vec3 uphill = rise.x * ( onMap ? rates.mapX : rates.capX ) + rise.y * ( onMap ? rates.mapY : rates.capY );
|
|
13690
|
+
vec3 uphill = ( window.x < 0.5 ? mapRates : capRates ) * rise;
|
|
12578
13691
|
slope += ( 1.0 - covered ) * alpha * uphill;
|
|
12579
13692
|
covered += ( 1.0 - covered ) * alpha;
|
|
12580
13693
|
if ( covered > 0.995 ) break;
|
|
@@ -12586,25 +13699,14 @@ function shadowGlsl(steps) {
|
|
|
12586
13699
|
return `
|
|
12587
13700
|
// One window as a shadow ray reads it. The ray is a line on the window's
|
|
12588
13701
|
// chart, so where it is inside the window is worked out once, not at each
|
|
12589
|
-
// sample.
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
|
|
12596
|
-
|
|
12597
|
-
float leaves;
|
|
12598
|
-
// The longest step that the window's pixels still hold, and the step from
|
|
12599
|
-
// which the ray reads the next window.
|
|
12600
|
-
float widest;
|
|
12601
|
-
float hands;
|
|
12602
|
-
// How far from the fragment the next window can be read at all.
|
|
12603
|
-
float beyond;
|
|
12604
|
-
int loaded;
|
|
12605
|
-
};
|
|
12606
|
-
|
|
12607
|
-
ReliefSight reliefSight( int i, TileCharts charts, vec2 mapStep, vec2 capStep ) {
|
|
13702
|
+
// sample. 'sight' holds what a sample reads, as a mat2x4 and not a struct
|
|
13703
|
+
// (see the chain code): the fragment's place in the window's texture and how
|
|
13704
|
+
// far the ray goes there in a radian; then the part of the ray inside the
|
|
13705
|
+
// window, in radians along it, the window's layer and its tiles that are in,
|
|
13706
|
+
// a bit each. 'widest' is the longest step that the window's pixels still
|
|
13707
|
+
// hold, 'hands' the step from which the ray reads the next window, and
|
|
13708
|
+
// 'beyond' how far from the fragment the next window can be read at all.
|
|
13709
|
+
void reliefSight( int i, mat3x2 map, mat3x2 cap, float side, vec2 mapStep, vec2 capStep, out mat2x4 sight, out float widest, out float hands, out float beyond ) {
|
|
12608
13710
|
vec4 window = uReliefWindow[ i ];
|
|
12609
13711
|
vec4 grid = uReliefGrid[ i ];
|
|
12610
13712
|
bool onMap = window.x < 0.5;
|
|
@@ -12612,7 +13714,7 @@ ReliefSight reliefSight( int i, TileCharts charts, vec2 mapStep, vec2 capStep )
|
|
|
12612
13714
|
// In tiles from the window's north-west corner. The map is counted from
|
|
12613
13715
|
// the point under the camera, so the fragment is on the side of the globe
|
|
12614
13716
|
// nearest the window.
|
|
12615
|
-
vec2 rel = onMap ? uReliefHome[ i ] +
|
|
13717
|
+
vec2 rel = onMap ? uReliefHome[ i ] + map[ 0 ] * grid.xy : cap[ 0 ] * grid.xy - grid.zw;
|
|
12616
13718
|
vec2 rate = ( onMap ? mapStep : capStep ) * grid.xy;
|
|
12617
13719
|
|
|
12618
13720
|
// Half a pixel in from the window's sides: past it the filter reads the
|
|
@@ -12624,51 +13726,50 @@ ReliefSight reliefSight( int i, TileCharts charts, vec2 mapStep, vec2 capStep )
|
|
|
12624
13726
|
vec2 near = min( a, b );
|
|
12625
13727
|
vec2 far = max( a, b );
|
|
12626
13728
|
|
|
12627
|
-
ReliefSight sight;
|
|
12628
13729
|
// The texture repeats every window. The tile index of a patch alone takes
|
|
12629
13730
|
// all the digits of a float: only its place in the window is added.
|
|
12630
13731
|
vec2 slot = rel + mod( grid.zw, rows );
|
|
12631
|
-
|
|
12632
|
-
sight.rate = vec2( rate.x, - rate.y ) / rows;
|
|
12633
|
-
sight.enters = max( near.x, near.y );
|
|
12634
|
-
sight.leaves = min( far.x, far.y );
|
|
13732
|
+
float leaves = min( far.x, far.y );
|
|
12635
13733
|
// The other pole's cap holds none of the ray.
|
|
12636
|
-
if ( ! onMap && ( window.x < 1.5 ) != (
|
|
12637
|
-
sight
|
|
13734
|
+
if ( ! onMap && ( window.x < 1.5 ) != ( side > 0.0 ) ) leaves = - 1.0;
|
|
13735
|
+
sight = mat2x4(
|
|
13736
|
+
slot.x / rows, - slot.y / rows, rate.x / rows, - rate.y / rows,
|
|
13737
|
+
max( near.x, near.y ), leaves, window.y, float( uReliefLoaded[ i ] )
|
|
13738
|
+
);
|
|
13739
|
+
widest = ${STEP_PIXELS.toFixed(2)} * PI / ( uReliefFilter.y * exp2( window.z ) );
|
|
12638
13740
|
// Near a patch the next window can be some levels coarser. The ray then
|
|
12639
13741
|
// stays here until its step is half of what that window holds: too wide
|
|
12640
13742
|
// for these pixels, but they are the same ground as the fragment's. The
|
|
12641
13743
|
// pyramid around a patch is not: it has none of the hills that only the
|
|
12642
13744
|
// patch resolves, and close to the fragment it would stand in the ray.
|
|
12643
|
-
|
|
12644
|
-
|
|
13745
|
+
hands = widest;
|
|
13746
|
+
beyond = 0.0;
|
|
12645
13747
|
if ( i + 1 < ${7} ) {
|
|
12646
13748
|
float next = PI / ( uReliefFilter.y * exp2( uReliefWindow[ i + 1 ].z ) );
|
|
12647
|
-
|
|
13749
|
+
hands = max( hands, 0.5 * ${STEP_PIXELS.toFixed(2)} * next );
|
|
12648
13750
|
// Within half a pixel of a window, its height is that of the fragment's
|
|
12649
13751
|
// own pixel, and the fragment stands above or below that by all the
|
|
12650
13752
|
// relief that the pixel averages away.
|
|
12651
|
-
|
|
13753
|
+
beyond = 0.5 * next;
|
|
12652
13754
|
}
|
|
12653
|
-
sight.loaded = uReliefLoaded[ i ];
|
|
12654
|
-
return sight;
|
|
12655
13755
|
}
|
|
12656
13756
|
|
|
12657
13757
|
// Height of the ground 't' radians along the ray, as a part of the pyramid's
|
|
12658
13758
|
// range. Negative where the window does not hold that ground.
|
|
12659
|
-
float reliefSightValue(
|
|
12660
|
-
if ( t < sight.
|
|
12661
|
-
vec2 st = sight.
|
|
13759
|
+
float reliefSightValue( mat2x4 sight, float t ) {
|
|
13760
|
+
if ( t < sight[ 1 ].x || t > sight[ 1 ].y ) return - 1.0;
|
|
13761
|
+
vec2 st = sight[ 0 ].xy + t * sight[ 0 ].zw;
|
|
12662
13762
|
// Both tiles that the filter can read must be in.
|
|
12663
|
-
if ( sight.
|
|
13763
|
+
if ( sight[ 1 ].w != ${((1 << 4 * 4) - 1).toFixed(1)} ) {
|
|
13764
|
+
int loaded = int( sight[ 1 ].w );
|
|
12664
13765
|
vec2 tile = vec2( st.x, - st.y ) * ${4 .toFixed(1)};
|
|
12665
13766
|
float inset = 0.5 / uReliefFilter.y;
|
|
12666
13767
|
ivec2 a = ivec2( floor( tile - inset ) ) & ${4 - 1};
|
|
12667
13768
|
ivec2 b = ivec2( floor( tile + inset ) ) & ${4 - 1};
|
|
12668
|
-
int both = (
|
|
13769
|
+
int both = ( loaded >> ( a.x + ${4} * a.y ) ) & ( loaded >> ( b.x + ${4} * b.y ) );
|
|
12669
13770
|
if ( ( both & 1 ) == 0 ) return - 1.0;
|
|
12670
13771
|
}
|
|
12671
|
-
return reliefValue( textureLod( uReliefMap, vec3( st, sight.
|
|
13772
|
+
return reliefValue( textureLod( uReliefMap, vec3( st, sight[ 1 ].z ), 0.0 ) );
|
|
12672
13773
|
}
|
|
12673
13774
|
|
|
12674
13775
|
// Part of the Sun's disc that the ground leaves in sight of the fragment at
|
|
@@ -12681,23 +13782,28 @@ float reliefSightValue( ReliefSight sight, float t ) {
|
|
|
12681
13782
|
// read from the window whose pixels are about as wide as the step. A shadow
|
|
12682
13783
|
// is then sharp beside what casts it, at a cost that does not grow with its
|
|
12683
13784
|
// length.
|
|
12684
|
-
float reliefTileShadow( vec3 dir,
|
|
12685
|
-
|
|
12686
|
-
|
|
12687
|
-
|
|
13785
|
+
float reliefTileShadow( vec3 dir, mat3x2 map, mat3x2 cap, float side, vec3 toSun, float tanElev, float sunSize, int first ) {
|
|
13786
|
+
mat2x3 mapRates;
|
|
13787
|
+
mat2x3 capRates;
|
|
13788
|
+
reliefRates( dir, side, mapRates, capRates );
|
|
13789
|
+
vec2 mapStep = toSun * mapRates;
|
|
13790
|
+
vec2 capStep = toSun * capRates;
|
|
12688
13791
|
|
|
12689
13792
|
int drawn = 0;
|
|
12690
13793
|
for ( int i = 0; i < ${7}; i ++ ) {
|
|
12691
13794
|
if ( uReliefWindow[ i ].w > 0.5 ) drawn = i + 1;
|
|
12692
13795
|
}
|
|
12693
13796
|
int w = first;
|
|
12694
|
-
|
|
13797
|
+
mat2x4 sight;
|
|
13798
|
+
float widest;
|
|
13799
|
+
float hands;
|
|
13800
|
+
float beyond;
|
|
12695
13801
|
float own = - 1.0;
|
|
12696
13802
|
for ( int i = 0; i < ${7}; i ++ ) {
|
|
12697
13803
|
if ( i < first ) continue;
|
|
12698
13804
|
if ( i >= drawn ) break;
|
|
12699
13805
|
w = i;
|
|
12700
|
-
|
|
13806
|
+
reliefSight( i, map, cap, side, mapStep, capStep, sight, widest, hands, beyond );
|
|
12701
13807
|
own = reliefSightValue( sight, 0.0 );
|
|
12702
13808
|
if ( own >= 0.0 ) break;
|
|
12703
13809
|
}
|
|
@@ -12714,7 +13820,7 @@ float reliefTileShadow( vec3 dir, TileCharts charts, vec3 toSun, float tanElev,
|
|
|
12714
13820
|
// The ratio that takes steps from one pixel to the reach: 'rate' is its
|
|
12715
13821
|
// logarithm times the count, and solves rate / ( exp( rate ) - 1 ) = part.
|
|
12716
13822
|
float count = ${steps.toFixed(1)};
|
|
12717
|
-
float pixel =
|
|
13823
|
+
float pixel = widest / ${STEP_PIXELS.toFixed(2)};
|
|
12718
13824
|
float part = count * pixel / reach;
|
|
12719
13825
|
float rate = 0.0;
|
|
12720
13826
|
if ( part < 1.0 ) {
|
|
@@ -12738,16 +13844,16 @@ float reliefTileShadow( vec3 dir, TileCharts charts, vec3 toSun, float tanElev,
|
|
|
12738
13844
|
for ( int i = 1; i <= ${steps}; i ++ ) {
|
|
12739
13845
|
float before = t;
|
|
12740
13846
|
t = t * ratio + head;
|
|
12741
|
-
if ( w + 1 < drawn && t - before >
|
|
13847
|
+
if ( w + 1 < drawn && t - before > hands ) {
|
|
12742
13848
|
w ++;
|
|
12743
|
-
|
|
13849
|
+
reliefSight( w, map, cap, side, mapStep, capStep, sight, widest, hands, beyond );
|
|
12744
13850
|
}
|
|
12745
13851
|
float value = reliefSightValue( sight, t );
|
|
12746
13852
|
// The ray left this window, or a tile of it is missing.
|
|
12747
13853
|
if ( value < 0.0 && w + 1 < drawn ) {
|
|
12748
|
-
if ( t <
|
|
13854
|
+
if ( t < beyond ) continue;
|
|
12749
13855
|
w ++;
|
|
12750
|
-
|
|
13856
|
+
reliefSight( w, map, cap, side, mapStep, capStep, sight, widest, hands, beyond );
|
|
12751
13857
|
value = reliefSightValue( sight, t );
|
|
12752
13858
|
}
|
|
12753
13859
|
if ( value < 0.0 ) continue;
|
|
@@ -12769,19 +13875,19 @@ float reliefTileShadow( vec3 dir, TileCharts charts, vec3 toSun, float tanElev,
|
|
|
12769
13875
|
float crest = ${(STEEPEST * .5).toFixed(2)} * around / max( worst, 1e-9 ) * perDisc;
|
|
12770
13876
|
if ( hidden < 1.0 && hidden + crest > - 1.0 ) {
|
|
12771
13877
|
w = worstWindow;
|
|
12772
|
-
|
|
13878
|
+
reliefSight( w, map, cap, side, mapStep, capStep, sight, widest, hands, beyond );
|
|
12773
13879
|
for ( int k = 0; k < ${REFINE_STEPS}; k ++ ) {
|
|
12774
13880
|
around *= 0.5;
|
|
12775
|
-
if ( w > start && around <
|
|
13881
|
+
if ( w > start && around < widest ) {
|
|
12776
13882
|
w --;
|
|
12777
|
-
|
|
13883
|
+
reliefSight( w, map, cap, side, mapStep, capStep, sight, widest, hands, beyond );
|
|
12778
13884
|
}
|
|
12779
13885
|
float centre = worst;
|
|
12780
13886
|
for ( int e = 0; e < 2; e ++ ) {
|
|
12781
13887
|
float at = centre + ( e == 0 ? - around : around );
|
|
12782
13888
|
// Nearer than a pixel, the window holds no crest: only the slope
|
|
12783
13889
|
// of the fragment's own ground, which is the normal's to light.
|
|
12784
|
-
if ( at <
|
|
13890
|
+
if ( at < widest * ${(1 / STEP_PIXELS).toFixed(4)} ) continue;
|
|
12785
13891
|
float value = reliefSightValue( sight, at );
|
|
12786
13892
|
if ( value < 0.0 ) continue;
|
|
12787
13893
|
float stands = ( ( value - own ) * uReliefScale / at - tanElev - 0.5 * at ) * perDisc;
|
|
@@ -12895,7 +14001,7 @@ var TILE_LIGHT = `
|
|
|
12895
14001
|
float up = dot(sunward, selfDir);
|
|
12896
14002
|
vec3 along = sunward - selfDir * up;
|
|
12897
14003
|
float run = length(along);
|
|
12898
|
-
if (run > 1e-4) tileLight = reliefTileShadow(selfDir,
|
|
14004
|
+
if (run > 1e-4) tileLight = reliefTileShadow(selfDir, selfMap, selfCap, selfSide, along / run, up / run, uSelfSunSize, selfFirst);
|
|
12899
14005
|
if (tileLight < 0.0) byTiles = 0.0;
|
|
12900
14006
|
}`;
|
|
12901
14007
|
function attachSelfShadowToBody(material, heightMap, scaleScene, sunDir, tiles) {
|
|
@@ -13029,10 +14135,10 @@ function attachSelfShadowToBody(material, heightMap, scaleScene, sunDir, tiles)
|
|
|
13029
14135
|
vec3 selfDir = normalize(vSelfDir);
|
|
13030
14136
|
// The part of the fragment that the tiles answer for.
|
|
13031
14137
|
float selfCovered = 0.0;
|
|
13032
|
-
${tiles ? "
|
|
14138
|
+
${tiles ? "mat3x2 selfMap;\n mat3x2 selfCap;\n float selfSide;\n tileChartsFrom(uReliefAnchor, vReliefOff, selfMap, selfCap, selfSide);\n int selfFirst = -1;" : ""}
|
|
13033
14139
|
{
|
|
13034
14140
|
vec3 slope = vec3(0.0);
|
|
13035
|
-
${tiles ? "slope = reliefTileSlope(selfDir,
|
|
14141
|
+
${tiles ? "slope = reliefTileSlope(selfDir, selfMap, selfCap, selfSide, selfCovered, selfFirst);" : ""}
|
|
13036
14142
|
if (selfCovered < 0.995 && uSelfScale > 0.0) slope += (1.0 - selfCovered) * selfMapSlope(selfDir);
|
|
13037
14143
|
float steep = length(slope);
|
|
13038
14144
|
if (steep > ${SLOPE_CLAMP.toFixed(3)}) slope *= ${SLOPE_CLAMP.toFixed(3)} / steep;
|
|
@@ -13125,34 +14231,23 @@ async function readHeightRows(bitmap, y0, y1) {
|
|
|
13125
14231
|
}
|
|
13126
14232
|
return out;
|
|
13127
14233
|
}
|
|
14234
|
+
var PYRAMID_TIER = "pyramid";
|
|
14235
|
+
var pyramidFailed = /* @__PURE__ */ new WeakSet();
|
|
14236
|
+
function pyramidHeightsServe(bo, renderer) {
|
|
14237
|
+
const tiles = bo.displacementMeta?.tiles;
|
|
14238
|
+
return !!tiles && tiles.scale_km !== void 0 && tilesBase() !== "" && textureAllowed(tiles.distribution) && renderer.extensions.has("OES_texture_float_linear") && !pyramidFailed.has(bo);
|
|
14239
|
+
}
|
|
13128
14240
|
async function swapDisplacementTier(bo, tier) {
|
|
13129
14241
|
const meta = bo.displacementMeta;
|
|
13130
14242
|
if (!meta || !bo.mesh || bo.displacementLoading || bo.displacementTier === tier) return;
|
|
13131
14243
|
bo.displacementLoading = true;
|
|
13132
14244
|
try {
|
|
13133
|
-
const
|
|
13134
|
-
if (!
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
if (!rows) return;
|
|
13140
|
-
if (!bo.mesh || !bo.displacementMap) return;
|
|
13141
|
-
const tmp = new Uint8Array(w);
|
|
13142
|
-
for (let y = 0; y < h >> 1; y++) {
|
|
13143
|
-
const top = rows.subarray(y * w, (y + 1) * w);
|
|
13144
|
-
const bottom = rows.subarray((h - 1 - y) * w, (h - y) * w);
|
|
13145
|
-
tmp.set(top);
|
|
13146
|
-
top.set(bottom);
|
|
13147
|
-
bottom.set(tmp);
|
|
13148
|
-
}
|
|
13149
|
-
const tex = new DataTexture(rows, w, h, RedFormat, UnsignedByteType);
|
|
13150
|
-
tex.colorSpace = NoColorSpace;
|
|
13151
|
-
tex.magFilter = LinearFilter;
|
|
13152
|
-
tex.minFilter = LinearFilter;
|
|
13153
|
-
tex.generateMipmaps = false;
|
|
13154
|
-
tex.unpackAlignment = 1;
|
|
13155
|
-
tex.needsUpdate = true;
|
|
14245
|
+
const tex = tier === "pyramid" ? await pyramidMap(bo, meta) : await tierMap(meta, tier);
|
|
14246
|
+
if (!tex) return;
|
|
14247
|
+
if (!bo.mesh || !bo.displacementMap) {
|
|
14248
|
+
tex.dispose();
|
|
14249
|
+
return;
|
|
14250
|
+
}
|
|
13156
14251
|
const material = bo.mesh.material;
|
|
13157
14252
|
const old = material.displacementMap;
|
|
13158
14253
|
material.displacementMap = tex;
|
|
@@ -13164,6 +14259,96 @@ async function swapDisplacementTier(bo, tier) {
|
|
|
13164
14259
|
bo.displacementLoading = false;
|
|
13165
14260
|
}
|
|
13166
14261
|
}
|
|
14262
|
+
async function tierMap(meta, tier) {
|
|
14263
|
+
const bitmap = await fetchHeightBitmap(displacementTierUrl(meta, tier));
|
|
14264
|
+
if (!bitmap) return null;
|
|
14265
|
+
const w = bitmap.width;
|
|
14266
|
+
const h = bitmap.height;
|
|
14267
|
+
const rows = await readHeightRows(bitmap, 0, h - 1);
|
|
14268
|
+
bitmap.close();
|
|
14269
|
+
if (!rows) return null;
|
|
14270
|
+
const tmp = new Uint8Array(w);
|
|
14271
|
+
for (let y = 0; y < h >> 1; y++) {
|
|
14272
|
+
const top = rows.subarray(y * w, (y + 1) * w);
|
|
14273
|
+
const bottom = rows.subarray((h - 1 - y) * w, (h - y) * w);
|
|
14274
|
+
tmp.set(top);
|
|
14275
|
+
top.set(bottom);
|
|
14276
|
+
bottom.set(tmp);
|
|
14277
|
+
}
|
|
14278
|
+
const tex = new DataTexture(rows, w, h, RedFormat, UnsignedByteType);
|
|
14279
|
+
tex.colorSpace = NoColorSpace;
|
|
14280
|
+
tex.magFilter = LinearFilter;
|
|
14281
|
+
tex.minFilter = LinearFilter;
|
|
14282
|
+
tex.generateMipmaps = false;
|
|
14283
|
+
tex.unpackAlignment = 1;
|
|
14284
|
+
tex.needsUpdate = true;
|
|
14285
|
+
return tex;
|
|
14286
|
+
}
|
|
14287
|
+
async function pyramidMap(bo, meta) {
|
|
14288
|
+
if (!meta.tiles) return null;
|
|
14289
|
+
try {
|
|
14290
|
+
return await pyramidHeights(meta, meta.tiles);
|
|
14291
|
+
} catch (err) {
|
|
14292
|
+
console.warn(`Failed to load the height pyramid of ${meta.id}:`, err);
|
|
14293
|
+
pyramidFailed.add(bo);
|
|
14294
|
+
return null;
|
|
14295
|
+
}
|
|
14296
|
+
}
|
|
14297
|
+
async function pyramidHeights(meta, tiles) {
|
|
14298
|
+
const signal = new AbortController().signal;
|
|
14299
|
+
const halves = await Promise.all([0, 1].map((x) => loadHeightTile(tileUrl(tiles, "", 0, x, 0), true, signal)));
|
|
14300
|
+
const size = halves[0].size;
|
|
14301
|
+
const width = 2 * size;
|
|
14302
|
+
const data = new Float32Array(width * size);
|
|
14303
|
+
const gain = (tiles.scale_km ?? 0) / 65535 / meta.scale_km;
|
|
14304
|
+
const offset = ((tiles.bias_km ?? 0) - meta.bias_km) / meta.scale_km;
|
|
14305
|
+
halves.forEach(({ heights }, x) => {
|
|
14306
|
+
for (let row = 0; row < size; row++) {
|
|
14307
|
+
const src = row * size;
|
|
14308
|
+
const dst = row * width + x * size;
|
|
14309
|
+
for (let i = 0; i < size; i++) data[dst + i] = heights[src + i] * gain + offset;
|
|
14310
|
+
}
|
|
14311
|
+
});
|
|
14312
|
+
const tex = new DataTexture(data, width, size, RedFormat, FloatType);
|
|
14313
|
+
tex.colorSpace = NoColorSpace;
|
|
14314
|
+
tex.magFilter = LinearFilter;
|
|
14315
|
+
tex.minFilter = LinearMipmapLinearFilter;
|
|
14316
|
+
tex.generateMipmaps = false;
|
|
14317
|
+
tex.mipmaps = mipChain(data, width, size);
|
|
14318
|
+
tex.needsUpdate = true;
|
|
14319
|
+
return tex;
|
|
14320
|
+
}
|
|
14321
|
+
function mipChain(data, width, height) {
|
|
14322
|
+
const chain = [{
|
|
14323
|
+
data,
|
|
14324
|
+
width,
|
|
14325
|
+
height
|
|
14326
|
+
}];
|
|
14327
|
+
while (width > 1 || height > 1) {
|
|
14328
|
+
const w = Math.max(1, width >> 1);
|
|
14329
|
+
const h = Math.max(1, height >> 1);
|
|
14330
|
+
const sx = width / w;
|
|
14331
|
+
const sy = height / h;
|
|
14332
|
+
const out = new Float32Array(w * h);
|
|
14333
|
+
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
|
|
14334
|
+
let sum = 0;
|
|
14335
|
+
for (let dy = 0; dy < sy; dy++) {
|
|
14336
|
+
const row = (y * sy + dy) * width + x * sx;
|
|
14337
|
+
for (let dx = 0; dx < sx; dx++) sum += data[row + dx];
|
|
14338
|
+
}
|
|
14339
|
+
out[y * w + x] = sum / (sx * sy);
|
|
14340
|
+
}
|
|
14341
|
+
chain.push({
|
|
14342
|
+
data: out,
|
|
14343
|
+
width: w,
|
|
14344
|
+
height: h
|
|
14345
|
+
});
|
|
14346
|
+
data = out;
|
|
14347
|
+
width = w;
|
|
14348
|
+
height = h;
|
|
14349
|
+
}
|
|
14350
|
+
return chain;
|
|
14351
|
+
}
|
|
13167
14352
|
function bilinearHeightTexel(data, w, h, fx, fy) {
|
|
13168
14353
|
const x0 = Math.floor(fx);
|
|
13169
14354
|
const y0 = Math.floor(fy);
|
|
@@ -13177,7 +14362,8 @@ function bilinearHeightTexel(data, w, h, fx, fy) {
|
|
|
13177
14362
|
const r1 = clampRow(y0 + 1) * w;
|
|
13178
14363
|
const top = data[r0 + c0] * (1 - tx) + data[r0 + c1] * tx;
|
|
13179
14364
|
const bot = data[r1 + c0] * (1 - tx) + data[r1 + c1] * tx;
|
|
13180
|
-
|
|
14365
|
+
const texel = top * (1 - ty) + bot * ty;
|
|
14366
|
+
return data instanceof Float32Array ? texel : texel / 255;
|
|
13181
14367
|
}
|
|
13182
14368
|
function disposeDisplacementFromMaterial(material) {
|
|
13183
14369
|
if (!material.displacementMap) return;
|
|
@@ -13367,8 +14553,9 @@ function loadLowField(bodyId, meta) {
|
|
|
13367
14553
|
function heightFieldFor(bo, bodyId) {
|
|
13368
14554
|
const image = bo.displacementMap?.image;
|
|
13369
14555
|
if (!image) return null;
|
|
13370
|
-
|
|
13371
|
-
|
|
14556
|
+
const data = image.data;
|
|
14557
|
+
if ((data instanceof Uint8Array || data instanceof Float32Array) && image.width && image.height) return {
|
|
14558
|
+
data,
|
|
13372
14559
|
width: image.width,
|
|
13373
14560
|
height: image.height,
|
|
13374
14561
|
bottomUp: true
|
|
@@ -13864,20 +15051,24 @@ var AttitudeTrack = class {
|
|
|
13864
15051
|
this.files = manifest.files;
|
|
13865
15052
|
}
|
|
13866
15053
|
covers(jd) {
|
|
13867
|
-
return
|
|
15054
|
+
return this.coversTdb(utcToTdb(jd));
|
|
15055
|
+
}
|
|
15056
|
+
coversTdb(tdb) {
|
|
15057
|
+
return tdb >= this.startJd && tdb <= this.endJd && this.files.length > 0;
|
|
13868
15058
|
}
|
|
13869
15059
|
orientationAt(jd, out) {
|
|
13870
|
-
|
|
13871
|
-
|
|
15060
|
+
const tdb = utcToTdb(jd);
|
|
15061
|
+
if (!this.coversTdb(tdb)) return false;
|
|
15062
|
+
const ci = this.fileIndexFor(tdb);
|
|
13872
15063
|
const chunk = this.ensure(ci);
|
|
13873
15064
|
if (!chunk) return false;
|
|
13874
15065
|
this.ensure(ci - 1);
|
|
13875
15066
|
this.ensure(ci + 1);
|
|
13876
|
-
this.sampleChunk(
|
|
15067
|
+
this.sampleChunk(tdb, ci, chunk);
|
|
13877
15068
|
const baseline = this.baselines?.[this.files[ci].baseline_index ?? 0];
|
|
13878
15069
|
if (baseline) {
|
|
13879
15070
|
const { axis, rate_rad_s, anchor, anchor_jd } = baseline;
|
|
13880
|
-
const tSeconds = (
|
|
15071
|
+
const tSeconds = (tdb - anchor_jd) * SECONDS_PER_DAY;
|
|
13881
15072
|
_baselineAxis.set(axis[0], axis[1], axis[2]);
|
|
13882
15073
|
_qBaseline.setFromAxisAngle(_baselineAxis, rate_rad_s * tSeconds);
|
|
13883
15074
|
_qb.set(anchor[1], anchor[2], anchor[3], anchor[0]);
|
|
@@ -14152,29 +15343,6 @@ function setSurfaceMap(material, map, tintHex) {
|
|
|
14152
15343
|
material.needsUpdate = true;
|
|
14153
15344
|
}
|
|
14154
15345
|
|
|
14155
|
-
//#endregion
|
|
14156
|
-
//#region src/lib/scene/objects/body/shape-model-policy.ts
|
|
14157
|
-
var PREFER_MODEL_OVER_DEM = /* @__PURE__ */ new Set([]);
|
|
14158
|
-
function shapeModelSkipReason(global) {
|
|
14159
|
-
if (!global?.model_name) return "no-bundle";
|
|
14160
|
-
if (isLowEndDevice() && global.render_quality !== "high") return "low-end-device";
|
|
14161
|
-
if (global.displacement && !PREFER_MODEL_OVER_DEM.has(global.id)) return "dem-preferred";
|
|
14162
|
-
return null;
|
|
14163
|
-
}
|
|
14164
|
-
|
|
14165
|
-
//#endregion
|
|
14166
|
-
//#region src/lib/scene/objects/body/orientation-apply.ts
|
|
14167
|
-
function applyBodyOrientation(body, orientation, ctx, systemId) {
|
|
14168
|
-
body.orientation = orientation;
|
|
14169
|
-
if (ctx) ctx.bodies.dataVersion++;
|
|
14170
|
-
ctx?.credits.registerOrientation({
|
|
14171
|
-
bodyId: body.data.id,
|
|
14172
|
-
systemId: systemId ?? body.data.id,
|
|
14173
|
-
source: orientation.source,
|
|
14174
|
-
reference: orientation.reference
|
|
14175
|
-
});
|
|
14176
|
-
}
|
|
14177
|
-
|
|
14178
15346
|
//#endregion
|
|
14179
15347
|
//#region src/lib/scene/objects/surface/photometry.ts
|
|
14180
15348
|
var WEIGHT_POLY = [
|
|
@@ -14184,16 +15352,24 @@ var WEIGHT_POLY = [
|
|
|
14184
15352
|
];
|
|
14185
15353
|
var GRAZE_FLOOR = .05;
|
|
14186
15354
|
var LUNAR_LAMBERT_GLSL = `
|
|
14187
|
-
float lunarLambertWeight(float phaseDeg) {
|
|
14188
|
-
return clamp(1.0 + phaseDeg * (${WEIGHT_POLY[0].toFixed(8)} + phaseDeg * (${WEIGHT_POLY[1].toFixed(8)} + phaseDeg * ${WEIGHT_POLY[2].toFixed(8)})), 0.0, 1.0);
|
|
15355
|
+
float lunarLambertWeight(float phaseDeg, float scale) {
|
|
15356
|
+
return min(scale * clamp(1.0 + phaseDeg * (${WEIGHT_POLY[0].toFixed(8)} + phaseDeg * (${WEIGHT_POLY[1].toFixed(8)} + phaseDeg * ${WEIGHT_POLY[2].toFixed(8)})), 0.0, 1.0), 1.0);
|
|
14189
15357
|
}
|
|
14190
15358
|
|
|
14191
|
-
float lunarLambertGain(float phaseDeg, float mu0, float mu) {
|
|
14192
|
-
float weight = lunarLambertWeight(phaseDeg);
|
|
15359
|
+
float lunarLambertGain(float phaseDeg, float mu0, float mu, float scale) {
|
|
15360
|
+
float weight = lunarLambertWeight(phaseDeg, scale);
|
|
14193
15361
|
float sun = max(mu0, 0.0);
|
|
14194
15362
|
return 2.0 * weight / max(sun + max(mu, sun), ${GRAZE_FLOOR.toFixed(3)}) + 1.0 - weight;
|
|
14195
15363
|
}
|
|
14196
15364
|
`;
|
|
15365
|
+
function makePhotometryUniforms(scale) {
|
|
15366
|
+
return { uLunarWeightScale: { value: scale ?? 1 } };
|
|
15367
|
+
}
|
|
15368
|
+
function lunarLambertWeight(phaseDeg, scale) {
|
|
15369
|
+
const [a, b, c] = WEIGHT_POLY;
|
|
15370
|
+
const moon = Math.min(1, Math.max(0, 1 + phaseDeg * (a + phaseDeg * (b + phaseDeg * c))));
|
|
15371
|
+
return Math.min(1, scale * moon);
|
|
15372
|
+
}
|
|
14197
15373
|
var DRY_GROUND = `
|
|
14198
15374
|
#ifdef USE_ROUGHNESSMAP
|
|
14199
15375
|
reflectedLight.directSpecular *= texelRoughness.g;
|
|
@@ -14212,18 +15388,20 @@ var LUNAR_LAMBERT = `
|
|
|
14212
15388
|
reflectedLight.directDiffuse *= lunarLambertGain(
|
|
14213
15389
|
phaseDeg,
|
|
14214
15390
|
dot(geometryNormal, sunView),
|
|
14215
|
-
dot(geometryNormal, geometryViewDir)
|
|
15391
|
+
dot(geometryNormal, geometryViewDir),
|
|
15392
|
+
uLunarWeightScale
|
|
14216
15393
|
);
|
|
14217
15394
|
}
|
|
14218
15395
|
`;
|
|
14219
|
-
function attachSurfacePhotometry(material, bodyId, sunDir) {
|
|
15396
|
+
function attachSurfacePhotometry(material, bodyId, uniforms, sunDir) {
|
|
14220
15397
|
const airless = !getAtmosphereParams(bodyId);
|
|
14221
15398
|
chainShaderHook(material, airless ? "photometryAirless" : "photometry", (shader) => {
|
|
14222
15399
|
let pars = "";
|
|
14223
15400
|
let light = DRY_GROUND;
|
|
14224
15401
|
if (airless) {
|
|
14225
15402
|
shader.uniforms.uPhotometrySunDir = sunDir ?? getEclipseSceneUniforms().uSunDir;
|
|
14226
|
-
|
|
15403
|
+
Object.assign(shader.uniforms, uniforms);
|
|
15404
|
+
pars = `uniform vec3 uPhotometrySunDir;\nuniform float uLunarWeightScale;\n${LUNAR_LAMBERT_GLSL}`;
|
|
14227
15405
|
light += LUNAR_LAMBERT;
|
|
14228
15406
|
}
|
|
14229
15407
|
shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `#include <common>\n${pars}`).replace("#include <lights_fragment_end>", `#include <lights_fragment_end>\n${light}`);
|
|
@@ -14231,92 +15409,60 @@ function attachSurfacePhotometry(material, bodyId, sunDir) {
|
|
|
14231
15409
|
}
|
|
14232
15410
|
|
|
14233
15411
|
//#endregion
|
|
14234
|
-
//#region src/lib/scene/objects/surface
|
|
14235
|
-
var
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
15412
|
+
//#region src/lib/scene/objects/body/surface-albedo.ts
|
|
15413
|
+
var UNKNOWN_SURFACE_COLOR = "#6b6b6b";
|
|
15414
|
+
function luminance$1(c) {
|
|
15415
|
+
return .2126 * c.r + .7152 * c.g + .0722 * c.b;
|
|
15416
|
+
}
|
|
15417
|
+
function discAlbedoPerColour(airless, lunarWeightScale) {
|
|
15418
|
+
if (!airless) return 2 / 3;
|
|
15419
|
+
return (2 + lunarLambertWeight(0, lunarWeightScale ?? 1)) / 3;
|
|
15420
|
+
}
|
|
15421
|
+
var _hex = new Color();
|
|
15422
|
+
function surfaceAlbedoTarget(body) {
|
|
15423
|
+
if (!body.color) return null;
|
|
15424
|
+
return (body.geometricAlbedo ?? luminance$1(_hex.set(body.color))) / discAlbedoPerColour(!getAtmosphereParams(body.id), body.lunarWeightScale);
|
|
15425
|
+
}
|
|
15426
|
+
function untexturedSurfaceColour(body, out = new Color()) {
|
|
15427
|
+
const target = surfaceAlbedoTarget(body);
|
|
15428
|
+
if (target === null) return out.set(UNKNOWN_SURFACE_COLOR);
|
|
15429
|
+
out.set(body.color);
|
|
15430
|
+
return out.multiplyScalar(target / luminance$1(out));
|
|
15431
|
+
}
|
|
15432
|
+
function shinerAlbedo(body, map, out) {
|
|
15433
|
+
if (body.color) out.set(body.color);
|
|
15434
|
+
else if (body.geometricAlbedo === void 0) return null;
|
|
15435
|
+
else {
|
|
15436
|
+
const mean = map && meanMapColor(map);
|
|
15437
|
+
if (mean) out.copy(mean);
|
|
15438
|
+
else out.setRGB(1, 1, 1);
|
|
15439
|
+
}
|
|
15440
|
+
const albedo = body.geometricAlbedo ?? luminance$1(out);
|
|
15441
|
+
return out.multiplyScalar(1.5 * albedo / luminance$1(out));
|
|
14243
15442
|
}
|
|
14244
|
-
var PLANETSHINE_GLSL = `
|
|
14245
|
-
#define PLANETSHINE_SHINERS ${2}
|
|
14246
|
-
uniform vec4 uShineDir[PLANETSHINE_SHINERS];
|
|
14247
|
-
uniform vec3 uShineLight[PLANETSHINE_SHINERS];
|
|
14248
15443
|
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
// The slots fill in order, so the first empty slot ends the list.
|
|
14258
|
-
if (shiner.w <= 0.0) break;
|
|
14259
|
-
float cosine = sphereLightCosine(dot(geometryNormal, mat3(viewMatrix) * shiner.xyz), shiner.w);
|
|
14260
|
-
reflectedLight.indirectDiffuse += uShineLight[i] * cosine * BRDF_Lambert(material.diffuseContribution);
|
|
14261
|
-
}
|
|
14262
|
-
`;
|
|
14263
|
-
function makePlanetshineUniforms() {
|
|
14264
|
-
return {
|
|
14265
|
-
uShineDir: { value: Array.from({ length: 2 }, () => new Vector4(0, 0, 0, 0)) },
|
|
14266
|
-
uShineLight: { value: Array.from({ length: 2 }, () => new Vector3()) }
|
|
14267
|
-
};
|
|
15444
|
+
//#endregion
|
|
15445
|
+
//#region src/lib/scene/objects/body/shape-model-policy.ts
|
|
15446
|
+
var PREFER_MODEL_OVER_DEM = /* @__PURE__ */ new Set([]);
|
|
15447
|
+
function shapeModelSkipReason(global) {
|
|
15448
|
+
if (!global?.model_name) return "no-bundle";
|
|
15449
|
+
if (isLowEndDevice() && global.render_quality !== "high") return "low-end-device";
|
|
15450
|
+
if (global.displacement && !PREFER_MODEL_OVER_DEM.has(global.id)) return "dem-preferred";
|
|
15451
|
+
return null;
|
|
14268
15452
|
}
|
|
14269
|
-
|
|
14270
|
-
|
|
14271
|
-
|
|
14272
|
-
|
|
14273
|
-
|
|
15453
|
+
|
|
15454
|
+
//#endregion
|
|
15455
|
+
//#region src/lib/scene/objects/body/orientation-apply.ts
|
|
15456
|
+
function applyBodyOrientation(body, orientation, nutPrec, ctx, systemId) {
|
|
15457
|
+
body.orientation = orientation;
|
|
15458
|
+
body.nutPrec = nutPrecFor(body.data.id, nutPrec);
|
|
15459
|
+
if (ctx) ctx.bodies.dataVersion++;
|
|
15460
|
+
ctx?.credits.registerOrientation({
|
|
15461
|
+
bodyId: body.data.id,
|
|
15462
|
+
systemId: systemId ?? body.data.id,
|
|
15463
|
+
source: orientation.source,
|
|
15464
|
+
reference: orientation.reference
|
|
14274
15465
|
});
|
|
14275
|
-
return self;
|
|
14276
|
-
}
|
|
14277
|
-
var _strength = new Float64Array(2);
|
|
14278
|
-
var _swapDir = new Vector4();
|
|
14279
|
-
var _swapLight = new Vector3();
|
|
14280
|
-
function selectShiners(out, x, y, z, shiners, count) {
|
|
14281
|
-
const dirs = out.uShineDir.value;
|
|
14282
|
-
const lights = out.uShineLight.value;
|
|
14283
|
-
let kept = 0;
|
|
14284
|
-
for (let i = 0; i < count; i++) {
|
|
14285
|
-
const s = shiners[i];
|
|
14286
|
-
const dx = s.x - x;
|
|
14287
|
-
const dy = s.y - y;
|
|
14288
|
-
const dz = s.z - z;
|
|
14289
|
-
const d = Math.hypot(dx, dy, dz);
|
|
14290
|
-
if (d <= s.radius) continue;
|
|
14291
|
-
const k = s.radius / d;
|
|
14292
|
-
if (2 / 3 * k * k < 1e-4) continue;
|
|
14293
|
-
const cosPhase = -(dx * s.sunX + dy * s.sunY + dz * s.sunZ) / d;
|
|
14294
|
-
const fraction = planetshineFraction(s.radius, d, Math.acos(Math.max(-1, Math.min(1, cosPhase))));
|
|
14295
|
-
const strength = fraction * (.2126 * s.albedo.r + .7152 * s.albedo.g + .0722 * s.albedo.b);
|
|
14296
|
-
if (strength < 1e-4) continue;
|
|
14297
|
-
let slot = kept;
|
|
14298
|
-
if (kept < 2) kept++;
|
|
14299
|
-
else if (strength > _strength[2 - 1]) slot = 2 - 1;
|
|
14300
|
-
else continue;
|
|
14301
|
-
_strength[slot] = strength;
|
|
14302
|
-
dirs[slot].set(dx / d, dy / d, dz / d, k);
|
|
14303
|
-
lights[slot].set(s.albedo.r, s.albedo.g, s.albedo.b).multiplyScalar(s.sunlight * fraction);
|
|
14304
|
-
for (; slot > 0 && _strength[slot - 1] < strength; slot--) {
|
|
14305
|
-
_strength[slot] = _strength[slot - 1];
|
|
14306
|
-
_strength[slot - 1] = strength;
|
|
14307
|
-
_swapDir.copy(dirs[slot - 1]);
|
|
14308
|
-
dirs[slot - 1].copy(dirs[slot]);
|
|
14309
|
-
dirs[slot].copy(_swapDir);
|
|
14310
|
-
_swapLight.copy(lights[slot - 1]);
|
|
14311
|
-
lights[slot - 1].copy(lights[slot]);
|
|
14312
|
-
lights[slot].copy(_swapLight);
|
|
14313
|
-
}
|
|
14314
|
-
}
|
|
14315
|
-
for (let i = kept; i < 2; i++) {
|
|
14316
|
-
dirs[i].set(0, 0, 0, 0);
|
|
14317
|
-
lights[i].set(0, 0, 0);
|
|
14318
|
-
}
|
|
14319
|
-
return kept;
|
|
14320
15466
|
}
|
|
14321
15467
|
|
|
14322
15468
|
//#endregion
|
|
@@ -14647,7 +15793,11 @@ async function loadSpacecraftModel(bo, modelScene, ctx) {
|
|
|
14647
15793
|
bo.body.modelBaseFrame = baseFrame ?? void 0;
|
|
14648
15794
|
const root = withBaseFrame(gltf.scene, baseFrame);
|
|
14649
15795
|
const anchor = meta.model_anchor ? new Vector3(...meta.model_anchor) : null;
|
|
14650
|
-
fitToUnitRadius(root, anchor && baseFrame ? anchor.applyQuaternion(baseFrame) : anchor)
|
|
15796
|
+
if (!fitToUnitRadius(root, anchor && baseFrame ? anchor.applyQuaternion(baseFrame) : anchor)) {
|
|
15797
|
+
disposeGltf(gltf.scene);
|
|
15798
|
+
bo.noPhysical = "model";
|
|
15799
|
+
return;
|
|
15800
|
+
}
|
|
14651
15801
|
enableShadows(root);
|
|
14652
15802
|
modelScene.add(root);
|
|
14653
15803
|
root.visible = !bo.isCrashed;
|
|
@@ -14683,7 +15833,7 @@ async function loadNaturalBodyModel(bo, ctx) {
|
|
|
14683
15833
|
console.info(`Skipping ${detail.global?.render_quality ?? "unrated"} shape mesh for ${bo.body.data.id}: ${skip}`);
|
|
14684
15834
|
return;
|
|
14685
15835
|
}
|
|
14686
|
-
if (detail.global?.orientation && !bo.body.orientation) applyBodyOrientation(bo.body, detail.global.orientation, ctx);
|
|
15836
|
+
if (detail.global?.orientation && !bo.body.orientation) applyBodyOrientation(bo.body, detail.global.orientation, detail.global.nut_prec, ctx);
|
|
14687
15837
|
const metaPromise = fetchBundleMeta(slug);
|
|
14688
15838
|
const gltf = await _loader.loadAsync(versionedUrl(`/v1/models/${slug}/high.glb`, "models"));
|
|
14689
15839
|
if ((bo.modelLoadEpoch ?? 0) !== epoch) {
|
|
@@ -14703,14 +15853,18 @@ async function loadNaturalBodyModel(bo, ctx) {
|
|
|
14703
15853
|
return;
|
|
14704
15854
|
}
|
|
14705
15855
|
const root = gltf.scene;
|
|
14706
|
-
fitToUnitRadius(root)
|
|
15856
|
+
if (!fitToUnitRadius(root)) {
|
|
15857
|
+
disposeGltf(gltf.scene);
|
|
15858
|
+
return;
|
|
15859
|
+
}
|
|
14707
15860
|
root.userData.radialIndex = buildRadialIndex(root);
|
|
14708
|
-
const material = makeShapeModelMaterial(
|
|
14709
|
-
|
|
15861
|
+
const material = makeShapeModelMaterial(untexturedSurfaceColour(bo.body.data));
|
|
15862
|
+
bo.photometry ??= makePhotometryUniforms(bo.body.data.lunarWeightScale);
|
|
15863
|
+
attachSurfacePhotometry(material, bo.body.data.id, bo.photometry);
|
|
14710
15864
|
bo.planetshine = attachPlanetshine(material, bo.planetshine ?? void 0);
|
|
14711
15865
|
applyShapeModelMaterial(root, material);
|
|
14712
15866
|
const sphereMap = bo.mesh ? bo.mesh.material.map : null;
|
|
14713
|
-
if (sphereMap) setShapeModelMap(root, sphereMap,
|
|
15867
|
+
if (sphereMap) setShapeModelMap(root, sphereMap, untexturedSurfaceColour(bo.body.data), bo.body.data.color);
|
|
14714
15868
|
enableShadows(root);
|
|
14715
15869
|
attachModelEclipse(bo, root);
|
|
14716
15870
|
if (meta.true_scale) {
|
|
@@ -14796,7 +15950,7 @@ function fitToUnitRadius(root, anchor = null) {
|
|
|
14796
15950
|
const size = bbox.getSize(new Vector3());
|
|
14797
15951
|
const center = bbox.getCenter(new Vector3());
|
|
14798
15952
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
14799
|
-
if (maxDim <= 0) return;
|
|
15953
|
+
if (maxDim <= 0) return false;
|
|
14800
15954
|
const k = 2 / maxDim;
|
|
14801
15955
|
root.userData.boxCenter = center.clone().multiplyScalar(k);
|
|
14802
15956
|
if (anchor) center.addScaledVector(anchor, maxDim / 2);
|
|
@@ -14811,6 +15965,7 @@ function fitToUnitRadius(root, anchor = null) {
|
|
|
14811
15965
|
const offset = root.userData.centerOffset.length();
|
|
14812
15966
|
root.userData.minRadius = Math.max(0, fit.minRadius - offset);
|
|
14813
15967
|
root.userData.maxRadius = root.userData.halfExtents.length() + offset;
|
|
15968
|
+
return true;
|
|
14814
15969
|
}
|
|
14815
15970
|
var OCCLUDER_SLICES = 8;
|
|
14816
15971
|
var OCCLUDER_SAMPLE_TARGET = 4096;
|
|
@@ -14963,7 +16118,7 @@ function nomenclatureBodyId(focused, bodyObjects) {
|
|
|
14963
16118
|
if (bodyObjects.get(focused.data.id)?.isLanded) return focused.data.parentId;
|
|
14964
16119
|
return focused.data.id;
|
|
14965
16120
|
}
|
|
14966
|
-
var DEG2RAD$
|
|
16121
|
+
var DEG2RAD$4 = Math.PI / 180;
|
|
14967
16122
|
var MIN_BODY_SCREEN_RADIUS_PX = 128;
|
|
14968
16123
|
var LABEL_DISC_FRACTION = .9;
|
|
14969
16124
|
var MIN_FEATURE_PX = 24;
|
|
@@ -15016,8 +16171,8 @@ async function attachNomenclatureLabels(bo, canvas, onFeatureSelect) {
|
|
|
15016
16171
|
let dispKm = null;
|
|
15017
16172
|
if (detail.global.displacement) {
|
|
15018
16173
|
dispKm = await displacementsKmAt(bo, bo.body.data.id, detail.global.displacement, effectiveRadiusKm(bo.body.data), renderable.map((f) => ({
|
|
15019
|
-
latRad: f.lat * DEG2RAD$
|
|
15020
|
-
lonRad: f.lon * DEG2RAD$
|
|
16174
|
+
latRad: f.lat * DEG2RAD$4,
|
|
16175
|
+
lonRad: f.lon * DEG2RAD$4
|
|
15021
16176
|
})));
|
|
15022
16177
|
if (bo.nomenclatureLabels || !bo.mesh) return;
|
|
15023
16178
|
}
|
|
@@ -15041,7 +16196,7 @@ async function attachNomenclatureLabels(bo, canvas, onFeatureSelect) {
|
|
|
15041
16196
|
el.dataset.featureId = String(feature.featureId);
|
|
15042
16197
|
attachCanvasForwarders(el, canvas);
|
|
15043
16198
|
if (onFeatureSelect) onTapNotDrag(el, () => onFeatureSelect(feature.featureId, feature.lat, feature.lon, effDiam));
|
|
15044
|
-
const [ux, uy, uz] = bodyFixedUnit(feature.lat * DEG2RAD$
|
|
16199
|
+
const [ux, uy, uz] = bodyFixedUnit(feature.lat * DEG2RAD$4, feature.lon * DEG2RAD$4);
|
|
15045
16200
|
const rf = radial[i];
|
|
15046
16201
|
const obj = new CSS2DObject(el);
|
|
15047
16202
|
obj.position.set(rf * ux, rf * uy, rf * uz);
|
|
@@ -15066,8 +16221,8 @@ async function sampleModelSurface(model, features) {
|
|
|
15066
16221
|
const he = model.userData.halfExtents;
|
|
15067
16222
|
for (let i = 0; i < n; i++) {
|
|
15068
16223
|
if (i > 0 && i % MODEL_CAST_CHUNK === 0) await new Promise((r) => setTimeout(r));
|
|
15069
|
-
const latRad = features[i].lat * DEG2RAD$
|
|
15070
|
-
const lonRad = features[i].lon * DEG2RAD$
|
|
16224
|
+
const latRad = features[i].lat * DEG2RAD$4;
|
|
16225
|
+
const lonRad = features[i].lon * DEG2RAD$4;
|
|
15071
16226
|
const r = castModelRadius(model, latRad, lonRad, _castNormal);
|
|
15072
16227
|
if (r !== null) radii[i] = r;
|
|
15073
16228
|
else {
|
|
@@ -16240,7 +17395,10 @@ uniform vec2 uTileFilter;
|
|
|
16240
17395
|
${TILE_CHAIN_GLSL}
|
|
16241
17396
|
vec3 tileColour( vec3 below ) {
|
|
16242
17397
|
if ( uTileWindow[ 0 ].w < 0.5 ) return below;
|
|
16243
|
-
|
|
17398
|
+
mat3x2 map;
|
|
17399
|
+
mat3x2 cap;
|
|
17400
|
+
float side;
|
|
17401
|
+
tileChartsFrom( uTileAnchor, vTileOff, map, cap, side );
|
|
16244
17402
|
|
|
16245
17403
|
float rows = ${4 .toFixed(1)};
|
|
16246
17404
|
vec3 colour = vec3( 0.0 );
|
|
@@ -16251,7 +17409,7 @@ vec3 tileColour( vec3 below ) {
|
|
|
16251
17409
|
vec2 spot;
|
|
16252
17410
|
vec2 major;
|
|
16253
17411
|
vec2 minor;
|
|
16254
|
-
float alpha = tileWindowWeight(
|
|
17412
|
+
float alpha = tileWindowWeight( map, cap, side, window, uTileGrid[ i ], uTileHome[ i ], uTileFilter, spot, major, minor );
|
|
16255
17413
|
if ( alpha <= 0.0 ) continue;
|
|
16256
17414
|
ivec3 slot = ivec3( int( mod( spot.x, rows ) ), int( mod( spot.y, rows ) ), int( window.y ) );
|
|
16257
17415
|
alpha *= texelFetch( uTileMask, slot, 0 ).r;
|
|
@@ -16394,8 +17552,9 @@ async function swapBodyTexture(bo, tier, frame, textureLoader) {
|
|
|
16394
17552
|
return;
|
|
16395
17553
|
}
|
|
16396
17554
|
const material = bo.mesh.material;
|
|
16397
|
-
|
|
16398
|
-
|
|
17555
|
+
const data = bo.body.data;
|
|
17556
|
+
setSurfaceMap(material, texture, data.color);
|
|
17557
|
+
if (bo.model) setShapeModelMap(bo.model, texture, untexturedSurfaceColour(data), data.color);
|
|
16399
17558
|
bo.textureTier = tier;
|
|
16400
17559
|
bo.textureFrame = frame;
|
|
16401
17560
|
} catch (err) {
|
|
@@ -16404,6 +17563,13 @@ async function swapBodyTexture(bo, tier, frame, textureLoader) {
|
|
|
16404
17563
|
bo.textureLoading = false;
|
|
16405
17564
|
}
|
|
16406
17565
|
}
|
|
17566
|
+
function applySurfaceColour(bo) {
|
|
17567
|
+
if (!bo.mesh || !bo.photometry || isModelBearing(bo.body) || bo.appearance?.surfaceOwned) return;
|
|
17568
|
+
const material = bo.mesh.material;
|
|
17569
|
+
if (material.map) return;
|
|
17570
|
+
untexturedSurfaceColour(bo.body.data, material.color);
|
|
17571
|
+
if (bo.model) setShapeModelMap(bo.model, null, material.color);
|
|
17572
|
+
}
|
|
16407
17573
|
function applyRadiiToMesh(bo, radii) {
|
|
16408
17574
|
if (!bo.mesh) return;
|
|
16409
17575
|
const { a, b, c } = radii;
|
|
@@ -16415,6 +17581,11 @@ function applyRadiiToMesh(bo, radii) {
|
|
|
16415
17581
|
kmToScene(c),
|
|
16416
17582
|
kmToScene(b)
|
|
16417
17583
|
];
|
|
17584
|
+
bo.body.drawnRadii = {
|
|
17585
|
+
a,
|
|
17586
|
+
b,
|
|
17587
|
+
c
|
|
17588
|
+
};
|
|
16418
17589
|
if (bo.atmosphere) {
|
|
16419
17590
|
const eqKm = Math.max(a, b);
|
|
16420
17591
|
syncAtmosphereEllipsoid(bo.atmosphere, eqKm, c, kmToScene(eqKm));
|
|
@@ -16427,14 +17598,15 @@ async function loadBodyTexture(bo, textureLoader, currentJd, scene, maxTextureSi
|
|
|
16427
17598
|
const detail = await fetchObjectDetail(bo.body.data.id, false);
|
|
16428
17599
|
ctx?.bodies.orientationRead.add(bo.body.data.id);
|
|
16429
17600
|
if (!detail.global) return;
|
|
16430
|
-
if (detail.global.orientation && !bo.body.orientation) applyBodyOrientation(bo.body, detail.global.orientation, ctx);
|
|
17601
|
+
if (detail.global.orientation && !bo.body.orientation) applyBodyOrientation(bo.body, detail.global.orientation, detail.global.nut_prec, ctx);
|
|
16431
17602
|
if (detail.global.radii && bo.radiusScene > 0 && !bo.radiiApplied && !detail.global.displacement?.absolute_radius) applyRadiiToMesh(bo, detail.global.radii);
|
|
16432
17603
|
if (detail.global.rings?.length) await Promise.allSettled(attachRingBundles(bo.body.data.id, bo.body.data.id, detail.global.rings, detail.global.radii, bo, scene, maxTextureSize, ctx));
|
|
16433
|
-
const
|
|
16434
|
-
|
|
16435
|
-
|
|
16436
|
-
|
|
16437
|
-
|
|
17604
|
+
const data = bo.body.data;
|
|
17605
|
+
data.color = detail.global.sbdb?.color ?? detail.global.color;
|
|
17606
|
+
data.geometricAlbedo = detail.global.sbdb?.geometric_albedo ?? detail.global.geometric_albedo;
|
|
17607
|
+
data.lunarWeightScale = detail.global.lunar_weight_scale;
|
|
17608
|
+
if (bo.photometry) bo.photometry.uLunarWeightScale.value = data.lunarWeightScale ?? 1;
|
|
17609
|
+
applySurfaceColour(bo);
|
|
16438
17610
|
if (!detail.global.map_texture_available) return;
|
|
16439
17611
|
const bodyId = bo.body.data.id;
|
|
16440
17612
|
const surface = pickTexture([detail.global.texture && {
|
|
@@ -16476,9 +17648,9 @@ function unloadBodyTexture(bo) {
|
|
|
16476
17648
|
if (!material.map) return;
|
|
16477
17649
|
material.map.dispose();
|
|
16478
17650
|
material.map = null;
|
|
16479
|
-
|
|
17651
|
+
untexturedSurfaceColour(bo.body.data, material.color);
|
|
16480
17652
|
material.needsUpdate = true;
|
|
16481
|
-
if (bo.model) setShapeModelMap(bo.model, null,
|
|
17653
|
+
if (bo.model) setShapeModelMap(bo.model, null, material.color);
|
|
16482
17654
|
bo.textureTier = void 0;
|
|
16483
17655
|
}
|
|
16484
17656
|
async function loadBodyTextureTier(bo, tier, frame, textureLoader) {
|
|
@@ -16505,17 +17677,6 @@ async function downloadSystemMeta(barycenterId) {
|
|
|
16505
17677
|
if (!resp.ok) throw new Error(`systems/${barycenterId}.json: ${resp.status}`);
|
|
16506
17678
|
return resp.json();
|
|
16507
17679
|
}
|
|
16508
|
-
function adoptSystemSpin(body, orientation, nutPrec, ctx, barycenterId) {
|
|
16509
|
-
applyBodyOrientation(body, orientation, ctx, barycenterId);
|
|
16510
|
-
if (!nutPrec) return;
|
|
16511
|
-
const naifMatch = body.data.id.match(/^naif-(-?\d+)$/);
|
|
16512
|
-
const naifId = naifMatch ? parseInt(naifMatch[1], 10) : null;
|
|
16513
|
-
const angles = naifId !== null ? getNutPrecAngles(ownerIdFor(naifId)) : void 0;
|
|
16514
|
-
if (angles) body.nutPrec = {
|
|
16515
|
-
...nutPrec,
|
|
16516
|
-
angles
|
|
16517
|
-
};
|
|
16518
|
-
}
|
|
16519
17680
|
async function readSpin(body, ctx) {
|
|
16520
17681
|
const id = body.data.id;
|
|
16521
17682
|
const known = () => !!body.orientation || ctx.bodies.orientationRead.has(id);
|
|
@@ -16526,8 +17687,8 @@ async function readSpin(body, ctx) {
|
|
|
16526
17687
|
const record = barycenterId ? (await fetchSystemMeta(barycenterId))?.[id] : void 0;
|
|
16527
17688
|
const detail = record?.orientation ? null : await fetchObjectDetail(id, false);
|
|
16528
17689
|
if (known()) return;
|
|
16529
|
-
if (record?.orientation)
|
|
16530
|
-
else if (detail?.global?.orientation) applyBodyOrientation(body, detail.global.orientation, ctx);
|
|
17690
|
+
if (record?.orientation) applyBodyOrientation(body, record.orientation, record.nut_prec, ctx, barycenterId);
|
|
17691
|
+
else if (detail?.global?.orientation) applyBodyOrientation(body, detail.global.orientation, detail.global.nut_prec, ctx);
|
|
16531
17692
|
ctx.bodies.orientationRead.add(id);
|
|
16532
17693
|
if (body.orientation) ctx.bodies.orientationVersion++;
|
|
16533
17694
|
}
|
|
@@ -16550,8 +17711,14 @@ async function loadSystemData(barycenterId, bodyObjects, scene, textureLoader, c
|
|
|
16550
17711
|
const bo = bodyObjects.get(bodyId);
|
|
16551
17712
|
if (!bo?.mesh) continue;
|
|
16552
17713
|
ctx?.bodies.orientationRead.add(bodyId);
|
|
17714
|
+
const data = bo.body.data;
|
|
17715
|
+
data.color ??= bodyMeta.color;
|
|
17716
|
+
data.geometricAlbedo ??= bodyMeta.geometric_albedo;
|
|
17717
|
+
data.lunarWeightScale ??= bodyMeta.lunar_weight_scale;
|
|
17718
|
+
if (bo.photometry) bo.photometry.uLunarWeightScale.value = data.lunarWeightScale ?? 1;
|
|
17719
|
+
applySurfaceColour(bo);
|
|
16553
17720
|
if (bodyMeta.orientation) {
|
|
16554
|
-
|
|
17721
|
+
applyBodyOrientation(bo.body, bodyMeta.orientation, bodyMeta.nut_prec, ctx, barycenterId);
|
|
16555
17722
|
applyOrientation(bo.mesh, bodyMeta.orientation, currentJd, bo.body.nutPrec);
|
|
16556
17723
|
}
|
|
16557
17724
|
if (bodyMeta.radii && bo.radiusScene > 0 && !bo.radiiApplied && !bodyMeta.displacement?.absolute_radius) applyRadiiToMesh(bo, bodyMeta.radii);
|
|
@@ -16589,6 +17756,7 @@ function unloadSystemTextures(barycenterId, bodyObjects, scene, ctx) {
|
|
|
16589
17756
|
}
|
|
16590
17757
|
for (const ring of bo.rings) {
|
|
16591
17758
|
ring.planetShadow?.disable();
|
|
17759
|
+
ring.ringshine?.disable();
|
|
16592
17760
|
ring.mesh.removeFromParent();
|
|
16593
17761
|
disposeRingNode(ring);
|
|
16594
17762
|
}
|
|
@@ -16609,6 +17777,7 @@ var ZoneRefresher = class {
|
|
|
16609
17777
|
latestDate;
|
|
16610
17778
|
failureStreak = 0;
|
|
16611
17779
|
staleNotified = false;
|
|
17780
|
+
staleCheckRunning = false;
|
|
16612
17781
|
retries = new RetryBackoff(() => this.wakes++);
|
|
16613
17782
|
wakes = 0;
|
|
16614
17783
|
wakeTimer;
|
|
@@ -16664,10 +17833,17 @@ var ZoneRefresher = class {
|
|
|
16664
17833
|
recordFailure(key) {
|
|
16665
17834
|
this.retries.fail(key);
|
|
16666
17835
|
this.failureStreak++;
|
|
16667
|
-
if (this.failureStreak
|
|
17836
|
+
if (this.failureStreak < STALE_FAILURE_STREAK || this.staleNotified || this.staleCheckRunning) return;
|
|
17837
|
+
this.staleCheckRunning = true;
|
|
17838
|
+
dataVersionChanged().then((changed) => {
|
|
17839
|
+
this.staleCheckRunning = false;
|
|
17840
|
+
if (!changed) {
|
|
17841
|
+
this.failureStreak = 0;
|
|
17842
|
+
return;
|
|
17843
|
+
}
|
|
16668
17844
|
this.staleNotified = true;
|
|
16669
17845
|
this.ctx.onDataStale?.();
|
|
16670
|
-
}
|
|
17846
|
+
});
|
|
16671
17847
|
}
|
|
16672
17848
|
wakeIn(ms) {
|
|
16673
17849
|
this.wakeTimer ??= setTimeout(() => {
|
|
@@ -17636,7 +18812,7 @@ var SimClock = class {
|
|
|
17636
18812
|
//#region src/lib/math/spherical.ts
|
|
17637
18813
|
var { PI, sin, cos, asin, atan2, sqrt } = Math;
|
|
17638
18814
|
var DEG$9 = 180 / PI;
|
|
17639
|
-
var RAD$
|
|
18815
|
+
var RAD$4 = PI / 180;
|
|
17640
18816
|
function applyQuat(v, q, inverse) {
|
|
17641
18817
|
const [x, y, z] = v;
|
|
17642
18818
|
const [qx, qy, qz, qw] = inverse ? [
|
|
@@ -17672,8 +18848,8 @@ function cartesianToSpherical(cam, target, bodyQuat) {
|
|
|
17672
18848
|
};
|
|
17673
18849
|
}
|
|
17674
18850
|
function sphericalToCartesian(target, lat, lon, distance, bodyQuat) {
|
|
17675
|
-
const latR = lat * RAD$
|
|
17676
|
-
const lonR = lon * RAD$
|
|
18851
|
+
const latR = lat * RAD$4;
|
|
18852
|
+
const lonR = lon * RAD$4;
|
|
17677
18853
|
let ox;
|
|
17678
18854
|
let oy;
|
|
17679
18855
|
let oz;
|
|
@@ -17706,7 +18882,7 @@ function offsetFacing(focus, toward, elevationDeg, distance) {
|
|
|
17706
18882
|
hx = 0;
|
|
17707
18883
|
hz = 1;
|
|
17708
18884
|
}
|
|
17709
|
-
const e = elevationDeg * RAD$
|
|
18885
|
+
const e = elevationDeg * RAD$4;
|
|
17710
18886
|
const c = cos(e);
|
|
17711
18887
|
return [
|
|
17712
18888
|
distance * c * hx,
|
|
@@ -18041,26 +19217,6 @@ function makeFatTrailMaterial(color, lineWidth, brightness = TRAIL_DIM, dash) {
|
|
|
18041
19217
|
});
|
|
18042
19218
|
}
|
|
18043
19219
|
|
|
18044
|
-
//#endregion
|
|
18045
|
-
//#region src/lib/scene/lighting.ts
|
|
18046
|
-
var AMBIENT_INTENSITY = .01;
|
|
18047
|
-
var SUN_LIGHT_INTENSITY = 3.5;
|
|
18048
|
-
var ENV_BASE_INTENSITY = .04;
|
|
18049
|
-
function sunIrradianceFactor(sunDistScene) {
|
|
18050
|
-
const au = Math.max(sunDistScene / 10, .01);
|
|
18051
|
-
return 1 / (au * au);
|
|
18052
|
-
}
|
|
18053
|
-
function applySunPointLightMode(light, realistic, scale = 1) {
|
|
18054
|
-
light.decay = realistic ? 2 : 0;
|
|
18055
|
-
light.intensity = (realistic ? SUN_LIGHT_INTENSITY * 10 * 10 : SUN_LIGHT_INTENSITY) * scale;
|
|
18056
|
-
}
|
|
18057
|
-
function makeEnvMap(renderer) {
|
|
18058
|
-
const pmrem = new PMREMGenerator(renderer);
|
|
18059
|
-
const tex = pmrem.fromScene(new RoomEnvironment()).texture;
|
|
18060
|
-
pmrem.dispose();
|
|
18061
|
-
return tex;
|
|
18062
|
-
}
|
|
18063
|
-
|
|
18064
19220
|
//#endregion
|
|
18065
19221
|
//#region src/lib/scene/setup/bloom-high-pass.ts
|
|
18066
19222
|
var MAX_SPAN = 16;
|
|
@@ -18106,6 +19262,26 @@ function installBloomHighPass(pass) {
|
|
|
18106
19262
|
});
|
|
18107
19263
|
}
|
|
18108
19264
|
|
|
19265
|
+
//#endregion
|
|
19266
|
+
//#region src/lib/scene/setup/output-dither.ts
|
|
19267
|
+
var DITHER_GLSL = `
|
|
19268
|
+
vec3 outputDither(vec3 color) {
|
|
19269
|
+
// ES 1.00 gives gl_FragCoord at medium precision. Copy it before the arithmetic.
|
|
19270
|
+
vec3 p3 = gl_FragCoord.xyx;
|
|
19271
|
+
p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
|
|
19272
|
+
p3 += dot(p3, p3.yxz + 33.33);
|
|
19273
|
+
vec3 u = fract((p3.xxy + p3.yzz) * p3.zyx);
|
|
19274
|
+
// The difference of two uniform samples has a triangular distribution on (-1, 1).
|
|
19275
|
+
vec3 noise = u - u.yzx;
|
|
19276
|
+
// The noise goes to 0 in the last step at each end. Thus black stays black and no value clips.
|
|
19277
|
+
vec3 amplitude = clamp(min(color, 1.0 - color) * 255.0, 0.0, 1.0);
|
|
19278
|
+
return color + noise * amplitude / 255.0;
|
|
19279
|
+
}
|
|
19280
|
+
`;
|
|
19281
|
+
function installOutputDither(pass) {
|
|
19282
|
+
pass.material.fragmentShader = pass.material.fragmentShader.replace("#include <colorspace_pars_fragment>", `#include <colorspace_pars_fragment>\n${DITHER_GLSL}`).replace(/}\s*$/, "gl_FragColor.rgb = outputDither(gl_FragColor.rgb);\n}");
|
|
19283
|
+
}
|
|
19284
|
+
|
|
18109
19285
|
//#endregion
|
|
18110
19286
|
//#region src/lib/scene/setup/three-boot.ts
|
|
18111
19287
|
var CAMERA_FAR_DEFAULT = 1e5;
|
|
@@ -18178,6 +19354,7 @@ function bootThree(canvas, labelContainer, ctx) {
|
|
|
18178
19354
|
installBloomHighPass(bloomPass);
|
|
18179
19355
|
composer.addPass(bloomPass);
|
|
18180
19356
|
const outputPass = new OutputPass();
|
|
19357
|
+
installOutputDither(outputPass);
|
|
18181
19358
|
outputPass.needsSwap = false;
|
|
18182
19359
|
composer.addPass(outputPass);
|
|
18183
19360
|
return {
|
|
@@ -18186,7 +19363,7 @@ function bootThree(canvas, labelContainer, ctx) {
|
|
|
18186
19363
|
scene,
|
|
18187
19364
|
camera,
|
|
18188
19365
|
composer,
|
|
18189
|
-
maxSceneSamples: sampleCounts[0] ?? 0,
|
|
19366
|
+
maxSceneSamples: sampleCounts?.[0] ?? 0,
|
|
18190
19367
|
bloomPass,
|
|
18191
19368
|
ambientLight,
|
|
18192
19369
|
shadowLight
|
|
@@ -18855,7 +20032,7 @@ gl_Position = projectionMatrix * mvPosition;
|
|
|
18855
20032
|
`;
|
|
18856
20033
|
var anchors = /* @__PURE__ */ new WeakMap();
|
|
18857
20034
|
var _modelView = new Matrix4();
|
|
18858
|
-
var _inverse = new Matrix4();
|
|
20035
|
+
var _inverse$1 = new Matrix4();
|
|
18859
20036
|
var _eye = new Vector3();
|
|
18860
20037
|
function patch(material, anchor) {
|
|
18861
20038
|
chainShaderHook(material, "cameraRelative", (shader) => {
|
|
@@ -18873,7 +20050,7 @@ function attachCameraRelative(mesh, material) {
|
|
|
18873
20050
|
patch(material, anchor);
|
|
18874
20051
|
mesh.onBeforeRender = (_renderer, _scene, camera) => {
|
|
18875
20052
|
_modelView.multiplyMatrices(camera.matrixWorldInverse, mesh.matrixWorld);
|
|
18876
|
-
_eye.setFromMatrixPosition(_inverse.copy(_modelView).invert());
|
|
20053
|
+
_eye.setFromMatrixPosition(_inverse$1.copy(_modelView).invert());
|
|
18877
20054
|
anchor.local.value.set(Math.fround(_eye.x), Math.fround(_eye.y), Math.fround(_eye.z));
|
|
18878
20055
|
anchor.view.value.copy(anchor.local.value).applyMatrix4(_modelView);
|
|
18879
20056
|
};
|
|
@@ -18911,19 +20088,21 @@ function buildMajorBodies(bodies, scene, clickables, meshToBody, bodyObjects, re
|
|
|
18911
20088
|
let starExtras = null;
|
|
18912
20089
|
let eclipseShadow = null;
|
|
18913
20090
|
let planetshine = null;
|
|
20091
|
+
let photometry = null;
|
|
18914
20092
|
let atmosphere = null;
|
|
18915
20093
|
let sunTint;
|
|
18916
20094
|
if (!isVirtual && !noPhysical) {
|
|
18917
20095
|
if (isStar) starExtras = buildStarExtras(root, radius, color);
|
|
18918
20096
|
const segments = isStar ? STAR_SPHERE_SEGMENTS : BODY_SPHERE_SEGMENTS;
|
|
18919
20097
|
const geometry = new SphereGeometry(radius, segments, segments);
|
|
18920
|
-
const material = isStar ? makeStarSurfaceMaterial() : new MeshStandardMaterial({ color:
|
|
20098
|
+
const material = isStar ? makeStarSurfaceMaterial() : new MeshStandardMaterial({ color: untexturedSurfaceColour(body.data) });
|
|
18921
20099
|
mesh = new Mesh(geometry, material);
|
|
18922
20100
|
if (modelBearing) mesh.visible = false;
|
|
18923
20101
|
if (!isStar) {
|
|
18924
20102
|
eclipseShadow = attachEclipseShadowToBody(material);
|
|
18925
20103
|
attachCameraRelative(mesh, material);
|
|
18926
|
-
|
|
20104
|
+
photometry = makePhotometryUniforms(body.data.lunarWeightScale);
|
|
20105
|
+
attachSurfacePhotometry(material, id, photometry);
|
|
18927
20106
|
if (!modelBearing) planetshine = attachPlanetshine(material);
|
|
18928
20107
|
}
|
|
18929
20108
|
root.add(mesh);
|
|
@@ -18974,6 +20153,7 @@ function buildMajorBodies(bodies, scene, clickables, meshToBody, bodyObjects, re
|
|
|
18974
20153
|
selfShadow: null,
|
|
18975
20154
|
eclipseShadow,
|
|
18976
20155
|
planetshine,
|
|
20156
|
+
photometry,
|
|
18977
20157
|
nomenclatureLabels: null,
|
|
18978
20158
|
model: null
|
|
18979
20159
|
});
|
|
@@ -18992,10 +20172,9 @@ function upgradeBodyMesh(bo, scene, clickables, meshToBody) {
|
|
|
18992
20172
|
bo.noPhysical = "radius";
|
|
18993
20173
|
return;
|
|
18994
20174
|
}
|
|
18995
|
-
const color = bodyMeshColor(body.data);
|
|
18996
20175
|
const segments = BODY_SPHERE_SEGMENTS;
|
|
18997
20176
|
const geometry = new SphereGeometry(radiusScene, segments, segments);
|
|
18998
|
-
const material = new MeshStandardMaterial({ color });
|
|
20177
|
+
const material = new MeshStandardMaterial({ color: untexturedSurfaceColour(body.data) });
|
|
18999
20178
|
const mesh = new Mesh(geometry, material);
|
|
19000
20179
|
if (modelBearing) mesh.visible = false;
|
|
19001
20180
|
bo.root.add(mesh);
|
|
@@ -19004,7 +20183,8 @@ function upgradeBodyMesh(bo, scene, clickables, meshToBody) {
|
|
|
19004
20183
|
meshToBody.set(mesh, body);
|
|
19005
20184
|
bo.eclipseShadow = attachEclipseShadowToBody(material);
|
|
19006
20185
|
attachCameraRelative(mesh, material);
|
|
19007
|
-
|
|
20186
|
+
bo.photometry = makePhotometryUniforms(body.data.lunarWeightScale);
|
|
20187
|
+
attachSurfacePhotometry(material, body.data.id, bo.photometry);
|
|
19008
20188
|
if (!modelBearing) bo.planetshine = attachPlanetshine(material);
|
|
19009
20189
|
bo.currentSegments = segments;
|
|
19010
20190
|
const atmoParams = getAtmosphereParams(body.data.id);
|
|
@@ -19041,6 +20221,7 @@ function downgradeBodyMesh(bo, scene, clickables, meshToBody) {
|
|
|
19041
20221
|
bo.currentSegments = void 0;
|
|
19042
20222
|
bo.eclipseShadow = null;
|
|
19043
20223
|
bo.planetshine = null;
|
|
20224
|
+
bo.photometry = null;
|
|
19044
20225
|
bo.sunTint = void 0;
|
|
19045
20226
|
bo.radiiApplied = false;
|
|
19046
20227
|
bo.semiAxesScene = void 0;
|
|
@@ -19191,9 +20372,9 @@ function revert(bo, appearance) {
|
|
|
19191
20372
|
if (applied.surfaceOwned && appearance?.surface === void 0) {
|
|
19192
20373
|
applied.surfaceMap?.dispose();
|
|
19193
20374
|
material.map = null;
|
|
19194
|
-
|
|
20375
|
+
untexturedSurfaceColour(bo.body.data, material.color);
|
|
19195
20376
|
material.needsUpdate = true;
|
|
19196
|
-
if (bo.model) setShapeModelMap(bo.model, null,
|
|
20377
|
+
if (bo.model) setShapeModelMap(bo.model, null, material.color);
|
|
19197
20378
|
applied.surfaceOwned = void 0;
|
|
19198
20379
|
applied.surfaceUrl = void 0;
|
|
19199
20380
|
applied.surfaceMap = void 0;
|
|
@@ -19245,7 +20426,7 @@ async function applyToBody(bo, appearance, textureLoader, current) {
|
|
|
19245
20426
|
const live = liveMaterial(bo);
|
|
19246
20427
|
if (texture && live) {
|
|
19247
20428
|
setSurfaceMap(live, texture);
|
|
19248
|
-
if (bo.model) setShapeModelMap(bo.model, texture,
|
|
20429
|
+
if (bo.model) setShapeModelMap(bo.model, texture, untexturedSurfaceColour(bo.body.data));
|
|
19249
20430
|
applied.surfaceUrl = appearance.surface;
|
|
19250
20431
|
applied.surfaceMap = texture;
|
|
19251
20432
|
}
|
|
@@ -19465,95 +20646,6 @@ function makePointCloudFromBuffer(positions, drawCount, texture, color, size = 4
|
|
|
19465
20646
|
return points;
|
|
19466
20647
|
}
|
|
19467
20648
|
|
|
19468
|
-
//#endregion
|
|
19469
|
-
//#region src/lib/math/orbit/position.ts
|
|
19470
|
-
var DEG2RAD$4 = Math.PI / 180;
|
|
19471
|
-
var COS_EPS$2 = Math.cos(EARTH_OBLIQUITY_DEG * DEG2RAD$4);
|
|
19472
|
-
var SIN_EPS$2 = Math.sin(EARTH_OBLIQUITY_DEG * DEG2RAD$4);
|
|
19473
|
-
function orbitalToThreeJS(xOrb, yOrb, w, i, om, equatorial = false) {
|
|
19474
|
-
const cosW = Math.cos(w * DEG2RAD$4);
|
|
19475
|
-
const sinW = Math.sin(w * DEG2RAD$4);
|
|
19476
|
-
const cosI = Math.cos(i * DEG2RAD$4);
|
|
19477
|
-
const sinI = Math.sin(i * DEG2RAD$4);
|
|
19478
|
-
const cosOm = Math.cos(om * DEG2RAD$4);
|
|
19479
|
-
const sinOm = Math.sin(om * DEG2RAD$4);
|
|
19480
|
-
const x = (cosOm * cosW - sinOm * sinW * cosI) * xOrb + (-cosOm * sinW - sinOm * cosW * cosI) * yOrb;
|
|
19481
|
-
let y = (sinOm * cosW + cosOm * sinW * cosI) * xOrb + (-sinOm * sinW + cosOm * cosW * cosI) * yOrb;
|
|
19482
|
-
let z = sinW * sinI * xOrb + cosW * sinI * yOrb;
|
|
19483
|
-
if (equatorial) {
|
|
19484
|
-
const yEcl = y * COS_EPS$2 + z * SIN_EPS$2;
|
|
19485
|
-
const zEcl = -y * SIN_EPS$2 + z * COS_EPS$2;
|
|
19486
|
-
y = yEcl;
|
|
19487
|
-
z = zEcl;
|
|
19488
|
-
}
|
|
19489
|
-
return [
|
|
19490
|
-
x * 10,
|
|
19491
|
-
z * 10,
|
|
19492
|
-
-y * 10
|
|
19493
|
-
];
|
|
19494
|
-
}
|
|
19495
|
-
function propagateOrbitAngles(el, jd) {
|
|
19496
|
-
const { omDot, wDot, om, w, epoch } = el;
|
|
19497
|
-
if (!omDot && !wDot) return el;
|
|
19498
|
-
const dt = jd - epoch;
|
|
19499
|
-
return {
|
|
19500
|
-
...el,
|
|
19501
|
-
om: omDot ? om + omDot * dt : om,
|
|
19502
|
-
w: wDot ? w + wDot * dt : w
|
|
19503
|
-
};
|
|
19504
|
-
}
|
|
19505
|
-
function orbitalElementsToPositionJD(el, jd) {
|
|
19506
|
-
const { a, e, i, ma, n, epoch } = el;
|
|
19507
|
-
if (!isFinite(a) || !isFinite(e) || !isFinite(ma) || !isFinite(n)) {
|
|
19508
|
-
console.warn(`NaN in orbital elements: a=${a} e=${e} ma=${ma} n=${n}`);
|
|
19509
|
-
return null;
|
|
19510
|
-
}
|
|
19511
|
-
const M = (ma + n * (jd - epoch)) * DEG2RAD$4;
|
|
19512
|
-
const { om: omPropagated, w: wPropagated } = propagateOrbitAngles(el, jd);
|
|
19513
|
-
let nu;
|
|
19514
|
-
let r;
|
|
19515
|
-
if (e < 1 || a > 0) {
|
|
19516
|
-
const eClamped = Math.min(e, .9999999);
|
|
19517
|
-
const E = solveKepler(M, eClamped);
|
|
19518
|
-
const sinNu = Math.sqrt(1 - eClamped * eClamped) * Math.sin(E) / (1 - eClamped * Math.cos(E));
|
|
19519
|
-
const cosNu = (Math.cos(E) - eClamped) / (1 - eClamped * Math.cos(E));
|
|
19520
|
-
nu = Math.atan2(sinNu, cosNu);
|
|
19521
|
-
r = a * (1 - eClamped * Math.cos(E));
|
|
19522
|
-
} else {
|
|
19523
|
-
const H = solveKeplerHyperbolic(M, e);
|
|
19524
|
-
if (!isFinite(H)) {
|
|
19525
|
-
console.warn(`solveKeplerHyperbolic overflow: M=${M} e=${e}`);
|
|
19526
|
-
return null;
|
|
19527
|
-
}
|
|
19528
|
-
const denom = e * Math.cosh(H) - 1;
|
|
19529
|
-
if (Math.abs(denom) < 1e-15) {
|
|
19530
|
-
console.warn(`Hyperbolic denom near zero: H=${H} e=${e} denom=${denom}`);
|
|
19531
|
-
return null;
|
|
19532
|
-
}
|
|
19533
|
-
const sinNu = Math.sqrt(e * e - 1) * Math.sinh(H) / denom;
|
|
19534
|
-
const cosNu = (e - Math.cosh(H)) / denom;
|
|
19535
|
-
nu = Math.atan2(sinNu, cosNu);
|
|
19536
|
-
r = a * (1 - e * Math.cosh(H));
|
|
19537
|
-
}
|
|
19538
|
-
const xOrb = r * Math.cos(nu);
|
|
19539
|
-
const yOrb = r * Math.sin(nu);
|
|
19540
|
-
if (!isFinite(xOrb) || !isFinite(yOrb)) {
|
|
19541
|
-
console.warn(`Non-finite orbital position: r=${r} nu=${nu} xOrb=${xOrb} yOrb=${yOrb} a=${a} e=${e}`);
|
|
19542
|
-
return null;
|
|
19543
|
-
}
|
|
19544
|
-
return orbitalToThreeJS(xOrb, yOrb, wPropagated, i, omPropagated, el.equatorial);
|
|
19545
|
-
}
|
|
19546
|
-
function parabolicToPositionJD(el, jd) {
|
|
19547
|
-
const { q, tp, i, om, w } = el;
|
|
19548
|
-
if (q == null || tp == null || !isFinite(q) || !isFinite(tp)) return null;
|
|
19549
|
-
const result = solveBarker(q, tp, jd);
|
|
19550
|
-
if (!result) return null;
|
|
19551
|
-
const xOrb = result.r * Math.cos(result.nu);
|
|
19552
|
-
const yOrb = result.r * Math.sin(result.nu);
|
|
19553
|
-
if (!isFinite(xOrb) || !isFinite(yOrb)) return null;
|
|
19554
|
-
return orbitalToThreeJS(xOrb, yOrb, w, i, om, el.equatorial);
|
|
19555
|
-
}
|
|
19556
|
-
|
|
19557
20649
|
//#endregion
|
|
19558
20650
|
//#region src/lib/math/orbit/curves.ts
|
|
19559
20651
|
function orbitalElementsToParabola(el, numPoints = 512, rMaxAU = 50) {
|
|
@@ -19797,6 +20889,10 @@ function commitTrail(line, posArr, trailArr, fullArr, n, isOpenCurve, useTrail)
|
|
|
19797
20889
|
|
|
19798
20890
|
//#endregion
|
|
19799
20891
|
//#region src/lib/scene/objects/trail/builder.ts
|
|
20892
|
+
var FAT_TRAIL_MIN_PIXEL_RATIO = 1.5;
|
|
20893
|
+
function drawsFat(lineWidth) {
|
|
20894
|
+
return lineWidth > 1 || renderPixelRatio() >= FAT_TRAIL_MIN_PIXEL_RATIO;
|
|
20895
|
+
}
|
|
19800
20896
|
function writeBufferVerticesWithLiveHead(body, buffer, posArr, cx, cy, cz, basisPos, transform) {
|
|
19801
20897
|
const head = body.trailAnchor ?? body.position;
|
|
19802
20898
|
if (!head) return 0;
|
|
@@ -19820,7 +20916,7 @@ function makeBufferTrail(body, trailBuffer, color, basisPos, lineWidth) {
|
|
|
19820
20916
|
const fullAlphas = new Float32Array(geomCap);
|
|
19821
20917
|
const trailAlphas = new Float32Array(geomCap);
|
|
19822
20918
|
if (total > 0) writeTrailAlphas(fullAlphas.subarray(0, total), trailAlphas.subarray(0, total), true, useTrail);
|
|
19823
|
-
const isFat = lineWidth
|
|
20919
|
+
const isFat = drawsFat(lineWidth);
|
|
19824
20920
|
const obj = isFat ? buildFatLineFromThin(geomCap, posArr, trailAlphas, fullAlphas, total, color, lineWidth) : buildThinLineFromArrays(posArr, trailAlphas, fullAlphas, total, color);
|
|
19825
20921
|
obj.frustumCulled = false;
|
|
19826
20922
|
obj.visible = false;
|
|
@@ -19871,7 +20967,7 @@ function makeTrail(body, color, basisPos = [
|
|
|
19871
20967
|
posArr[k * 3 + 1] = validPoints[k][1] + by;
|
|
19872
20968
|
posArr[k * 3 + 2] = validPoints[k][2] + bz;
|
|
19873
20969
|
}
|
|
19874
|
-
const isFat = lineWidth
|
|
20970
|
+
const isFat = drawsFat(lineWidth);
|
|
19875
20971
|
const obj = isFat ? buildFatLineFromThin(bufferCapacity, posArr, trailAlphas, fullAlphas, validPoints.length, color, lineWidth) : buildThinLineFromArrays(posArr, trailAlphas, fullAlphas, validPoints.length, color);
|
|
19876
20972
|
obj.frustumCulled = false;
|
|
19877
20973
|
obj.visible = false;
|
|
@@ -20765,7 +21861,7 @@ function collectDebugStats(params) {
|
|
|
20765
21861
|
|
|
20766
21862
|
//#endregion
|
|
20767
21863
|
//#region src/lib/math/orbit/worker.ts?worker&inline
|
|
20768
|
-
var jsContent = "function e(e,t,n=1e-10,r=50){let i=e;for(let a=0;a<r;a++){let r=(i-t*Math.sin(i)-e)/(1-t*Math.cos(i));if(i-=Math.max(-1,Math.min(1,r)),Math.abs(r)<n)break}return i}function t(e,t,n=1e-10,r=50){if(e===0)return 0;let i=e<0?-1:1,a=Math.abs(e),o=0,s=1;for(;t*Math.sinh(s)-s<a;)if(s*=2,s>700)return NaN;let c=.5*(o+s);for(let e=0;e<r;e++){let e=t*Math.sinh(c)-c-a;e>0?s=c:o=c;let r=c-e/(t*Math.cosh(c)-1);r>o&&r<s||(r=.5*(o+s));let i=Math.abs(r-c);if(c=r,i<n)break}return i*c}function n(e,t,n){let r=.01720209895*(n-t)/(Math.sqrt(2)*e**1.5),i=Math.cbrt(3*r+Math.sqrt(1+9*r*r)),a=i-1/i,o=2*Math.atan(a),s=e*(1+a*a);return!isFinite(o)||!isFinite(s)||s<=0?null:{nu:o,r:s}}const r=149597870.7,i=23.4392911;86400**2/r**3,1/r,Math.cos(Math.PI/180*i),Math.sin(Math.PI/180*i);const a=Math.PI,o=a*2,s=a/180;180/a;const c=6378.135,l=60/Math.sqrt(c*c*c/398600.8),u=c*l/60,d=1/l,f=.001082616,p=-253881e-11/f,m=2/3,ee=1440/(2*a);function te(e,t){let n=[31,e%4==0?29:28,31,30,31,30,31,31,30,31,30,31],r=Math.floor(t),i=1,a=0;for(;r>a+n[i-1]&&i<12;)a+=n[i-1],i+=1;let o=i,s=r-a,c=(t-r)*24,l=Math.floor(c);c=(c-l)*60;let u=Math.floor(c);return{mon:o,day:s,hr:l,minute:u,sec:(c-u)*60}}function h(e,t,n,r,i,a,o=0){return 367*e-Math.floor(7*(e+Math.floor((t+9)/12))*.25)+Math.floor(275*t/9)+n+1721013.5+((o/6e4+a/60+i)/60+r)/24}function g(e,t,n,r,i,a,o=0){if(e instanceof Date){let t=e;return h(t.getUTCFullYear(),t.getUTCMonth()+1,t.getUTCDate(),t.getUTCHours(),t.getUTCMinutes(),t.getUTCSeconds(),t.getUTCMilliseconds())}return h(e,t,n,r,i,a,o)}function ne(e,t){let{e3:n,ee2:r,peo:i,pgho:s,pho:c,pinco:l,plo:u,se2:d,se3:f,sgh2:p,sgh3:m,sgh4:ee,sh2:te,sh3:h,si2:g,si3:ne,sl2:_,sl3:v,sl4:y,t:b,xgh2:re,xgh3:ie,xgh4:x,xh2:ae,xh3:S,xi2:C,xi3:w,xl2:T,xl3:E,xl4:D,zmol:O,zmos:k}=e,{init:A,opsmode:j}=t,{ep:oe,inclp:M,nodep:N,argpp:se,mp:P}=t,F,I,L,R,ce,z,B,V,H,U,W,G,K,q,J,le,Y,ue,de,X,fe;fe=k+119459e-10*b,A===`y`&&(fe=k),X=fe+2*.01675*Math.sin(fe),Y=Math.sin(X),U=.5*Y*Y-.25,W=-.5*Y*Math.cos(X);let pe=d*U+f*W,me=g*U+ne*W,he=_*U+v*W+y*Y,ge=p*U+m*W+ee*Y,Z=te*U+h*W;fe=O+.00015835218*b,A===`y`&&(fe=O),X=fe+2*.0549*Math.sin(fe),Y=Math.sin(X),U=.5*Y*Y-.25,W=-.5*Y*Math.cos(X);let _e=r*U+n*W,ve=C*U+w*W,ye=T*U+E*W+D*Y,be=re*U+ie*W+x*Y,xe=ae*U+S*W;return G=pe+_e,J=me+ve,le=he+ye,K=ge+be,q=Z+xe,A===`n`&&(G-=i,J-=l,le-=u,K-=s,q-=c,M+=J,oe+=G,R=Math.sin(M),L=Math.cos(M),M>=.2?(q/=R,K-=L*q,se+=K,N+=q,P+=le):(z=Math.sin(N),ce=Math.cos(N),F=R*z,I=R*ce,B=q*ce+J*L*z,V=-q*z+J*L*ce,F+=B,I+=V,N%=o,N<0&&j===`a`&&(N+=o),ue=P+se+L*N,H=le+K-J*N*R,ue+=H,de=N,N=Math.atan2(F,I),N<0&&j===`a`&&(N+=o),Math.abs(de-N)>a&&(N<de?N+=o:N-=o),P+=le,se=ue-P-L*N)),{ep:oe,inclp:M,nodep:N,argpp:se,mp:P}}function _(e){let{epoch:t,ep:n,argpp:r,tc:i,inclp:a,nodep:s,np:c}=e,l,u,d,f,p,m,ee,te,h,g,ne,_,v,y,b,re,ie,x,ae,S,C,w,T,E,D,O,k,A,j,oe,M,N,se,P,F,I,L,R,ce,z,B,V,H,U,W,G,K,q,J,le,Y,ue,de,X,fe,pe,me,he,ge,Z,_e,ve,ye,be=.01675,xe=.0549,Se=c,Ce=n,we=Math.sin(s),Te=Math.cos(s),Ee=Math.sin(r),Q=Math.cos(r),De=Math.sin(a),Oe=Math.cos(a),$=Ce*Ce,ke=1-$,Ae=Math.sqrt(ke),je=t+18261.5+i/1440,Me=(4.523602-.00092422029*je)%o,Ne=Math.sin(Me),Pe=Math.cos(Me),Fe=.91375164-.03568096*Pe,Ie=Math.sqrt(1-Fe*Fe),Le=.089683511*Ne/Ie,Re=Math.sqrt(1-Le*Le),ze=5.8351514+.001944368*je,Be=.39785416*Ne/Ie,Ve=Re*Pe+.91744867*Le*Ne;Be=Math.atan2(Be,Ve),Be+=ze-Me;let He=Math.cos(Be),Ue=Math.sin(Be);S=.1945905,C=-.98088458,E=.91744867,D=.39785416,w=Te,T=we,ne=29864797e-13;let We=1/Se,Ge=0;for(;Ge<2;)Ge+=1,l=S*w+C*E*T,d=-C*w+S*E*T,ee=-S*T+C*E*w,te=C*D,h=C*T+S*E*w,g=S*D,u=Oe*ee+De*te,f=Oe*h+De*g,p=-De*ee+Oe*te,m=-De*h+Oe*g,_=l*Q+u*Ee,v=d*Q+f*Ee,y=-l*Ee+u*Q,b=-d*Ee+f*Q,re=p*Ee,ie=m*Ee,x=p*Q,ae=m*Q,_e=12*_*_-3*y*y,ve=24*_*v-6*y*b,ye=12*v*v-3*b*b,ue=3*(l*l+u*u)+_e*$,de=6*(l*d+u*f)+ve*$,X=3*(d*d+f*f)+ye*$,fe=-6*l*p+$*(-24*_*x-6*y*re),pe=-6*(l*m+d*p)+$*(-24*(v*x+_*ae)+-6*(y*ie+b*re)),me=-6*d*m+$*(-24*v*ae-6*b*ie),he=6*u*p+$*(24*_*re-6*y*x),ge=6*(f*p+u*m)+$*(24*(v*re+_*ie)-6*(b*x+y*ae)),Z=6*f*m+$*(24*v*ie-6*b*ae),ue=ue+ue+ke*_e,de=de+de+ke*ve,X=X+X+ke*ye,K=ne*We,G=-.5*K/Ae,q=K*Ae,W=-15*Ce*q,J=_*y+v*b,le=v*y+_*b,Y=v*b-_*y,Ge===1&&(O=W,k=G,A=K,j=q,oe=J,M=le,N=Y,se=ue,P=de,F=X,I=fe,L=pe,R=me,ce=he,z=ge,B=Z,V=_e,H=ve,U=ye,S=He,C=Ue,E=Fe,D=Ie,w=Re*Te+Le*we,T=we*Re-Te*Le,ne=4.7968065e-7);let Ke=(4.7199672+(.2299715*je-ze))%o,qe=(6.2565837+.017201977*je)%o,Je=2*O*M,Ye=2*O*N,Xe=2*k*L,Ze=2*k*(R-I),Qe=-2*A*P,$e=-2*A*(F-se),et=-2*A*(-21-9*$)*be,tt=2*j*H,nt=2*j*(U-V),rt=-18*j*be,it=-2*k*z,at=-2*k*(B-ce),ot=2*W*le,st=2*W*Y,ct=2*G*pe,lt=2*G*(me-fe),ut=-2*K*de,dt=-2*K*(X-ue),ft=-2*K*(-21-9*$)*xe,pt=2*q*ve,mt=2*q*(ye-_e),ht=-18*q*xe,gt=-2*G*ge,_t=-2*G*(Z-he);return{snodm:we,cnodm:Te,sinim:De,cosim:Oe,sinomm:Ee,cosomm:Q,day:je,e3:st,ee2:ot,em:Ce,emsq:$,gam:ze,peo:0,pgho:0,pho:0,pinco:0,plo:0,rtemsq:Ae,se2:Je,se3:Ye,sgh2:tt,sgh3:nt,sgh4:rt,sh2:it,sh3:at,si2:Xe,si3:Ze,sl2:Qe,sl3:$e,sl4:et,s1:W,s2:G,s3:K,s4:q,s5:J,s6:le,s7:Y,ss1:O,ss2:k,ss3:A,ss4:j,ss5:oe,ss6:M,ss7:N,sz1:se,sz2:P,sz3:F,sz11:I,sz12:L,sz13:R,sz21:ce,sz22:z,sz23:B,sz31:V,sz32:H,sz33:U,xgh2:pt,xgh3:mt,xgh4:ht,xh2:gt,xh3:_t,xi2:ct,xi3:lt,xl2:ut,xl3:dt,xl4:ft,nm:Se,z1:ue,z2:de,z3:X,z11:fe,z12:pe,z13:me,z21:he,z22:ge,z23:Z,z31:_e,z32:ve,z33:ye,zmol:Ke,zmos:qe}}function v(e){let{cosim:t,argpo:n,s1:r,s2:i,s3:s,s4:c,s5:u,sinim:d,ss1:f,ss2:p,ss3:ee,ss4:te,ss5:h,sz1:g,sz3:ne,sz11:_,sz13:v,sz21:y,sz23:b,sz31:re,sz33:ie,t:x,tc:ae,gsto:S,mo:C,mdot:w,no:T,nodeo:E,nodedot:D,xpidot:O,z1:k,z3:A,z11:j,z13:oe,z21:M,z23:N,z31:se,z33:P,ecco:F,eccsq:I}=e,{emsq:L,em:R,argpm:ce,inclm:z,mm:B,nm:V,nodem:H,irez:U,atime:W,d2201:G,d2211:K,d3210:q,d3222:J,d4410:le,d4422:Y,d5220:ue,d5232:de,d5421:X,d5433:fe,dedt:pe,didt:me,dmdt:he,dnodt:ge,domdt:Z,del1:_e,del2:ve,del3:ye,xfact:be,xlamo:xe,xli:Se,xni:Ce}=e,we,Te,Ee,Q,De,Oe,$,ke,Ae,je,Me,Ne,Pe,Fe,Ie,Le,Re,ze,Be,Ve,He,Ue,We,Ge,Ke,qe,Je,Ye,Xe,Ze,Qe,$e,et=.0043752690880113,tt=.00015835218,nt=119459e-10;U=0,V<.0052359877&&V>.0034906585&&(U=1),V>=.00826&&V<=.00924&&R>=.5&&(U=2);let rt=f*nt*h,it=p*nt*(_+v),at=-nt*ee*(g+ne-14-6*L),ot=te*nt*(re+ie-6),st=-nt*p*(y+b);(z<.052359877||z>a-.052359877)&&(st=0),d!==0&&(st/=d);let ct=ot-t*st;pe=rt+r*tt*u,me=it+i*tt*(j+oe),he=at-tt*s*(k+A-14-6*L);let lt=c*tt*(se+P-6),ut=-tt*i*(M+N);(z<.052359877||z>a-.052359877)&&(ut=0),Z=ct+lt,ge=st,d!==0&&(Z-=t/d*ut,ge+=ut/d);let dt=(S+ae*et)%o;if(R+=pe*x,z+=me*x,ce+=Z*x,H+=ge*x,B+=he*x,U!==0){if(Ze=(V/l)**m,U===2){Qe=t*t;let e=R;R=F;let n=L;L=I,$e=R*L,Fe=-.306-(R-.64)*.44,R<=.65?(Ie=3.616-13.247*R+16.29*L,Re=-19.302+117.39*R-228.419*L+156.591*$e,ze=-18.9068+109.7927*R-214.6334*L+146.5816*$e,Be=-41.122+242.694*R-471.094*L+313.953*$e,Ve=-146.407+841.88*R-1629.014*L+1083.435*$e,He=-532.114+3017.977*R-5740.032*L+3708.276*$e):(Ie=-72.099+331.819*R-508.738*L+266.724*$e,Re=-346.844+1582.851*R-2415.925*L+1246.113*$e,ze=-342.585+1554.908*R-2366.899*L+1215.972*$e,Be=-1052.797+4758.686*R-7193.992*L+3651.957*$e,Ve=-3581.69+16178.11*R-24462.77*L+12422.52*$e,He=R>.715?-5149.66+29936.92*R-54087.36*L+31324.56*$e:1464.74-4664.75*R+3763.64*L),R<.7?(Ge=-919.2277+4988.61*R-9064.77*L+5542.21*$e,Ue=-822.71072+4568.6173*R-8491.4146*L+5337.524*$e,We=-853.666+4690.25*R-8624.77*L+5341.4*$e):(Ge=-37995.78+161616.52*R-229838.2*L+109377.94*$e,Ue=-51752.104+218913.95*R-309468.16*L+146349.42*$e,We=-40023.88+170470.89*R-242699.48*L+115605.82*$e),Ke=d*d,we=.75*(1+2*t+Qe),Te=1.5*Ke,Q=1.875*d*(1-2*t-3*Qe),De=-1.875*d*(1+2*t-3*Qe),$=35*Ke*we,ke=39.375*Ke*Ke,Ae=9.84375*d*(Ke*(1-2*t-5*Qe)+.33333333*(-2+4*t+6*Qe)),je=d*(4.92187512*Ke*(-2-4*t+10*Qe)+6.56250012*(1+2*t-3*Qe)),Me=29.53125*d*(2-8*t+Qe*(-12+8*t+10*Qe)),Ne=29.53125*d*(-2-8*t+Qe*(12+8*t-10*Qe)),Ye=V*V,Xe=Ze*Ze,Je=3*Ye*Xe,qe=Je*17891679e-13,G=qe*we*Fe,K=qe*Te*Ie,Je*=Ze,qe=Je*3.7393792e-7,q=qe*Q*Re,J=qe*De*ze,Je*=Ze,qe=2*Je*7.3636953e-9,le=qe*$*Be,Y=qe*ke*Ve,Je*=Ze,qe=Je*1.1428639e-7,ue=qe*Ae*He,de=qe*je*We,qe=2*Je*2.1765803e-9,X=qe*Me*Ue,fe=qe*Ne*Ge,xe=(C+E+E-(dt+dt))%o,be=w+he+2*(D+ge-et)-T,R=e,L=n}U===1&&(Pe=1+L*(-2.5+.8125*L),Re=1+2*L,Le=1+L*(-6+6.60937*L),we=.75*(1+t)*(1+t),Ee=.9375*d*d*(1+3*t)-.75*(1+t),Oe=1+t,Oe*=1.875*Oe*Oe,_e=3*V*V*Ze*Ze,ve=2*_e*we*Pe*17891679e-13,ye=3*_e*Oe*Le*2.2123015e-7*Ze,_e=_e*Ee*Re*21460748e-13*Ze,xe=(C+E+n-dt)%o,be=w+O+he+Z+ge-(T+et)),Se=xe,Ce=T,W=0,V=T+0}return{em:R,argpm:ce,inclm:z,mm:B,nm:V,nodem:H,irez:U,atime:W,d2201:G,d2211:K,d3210:q,d3222:J,d4410:le,d4422:Y,d5220:ue,d5232:de,d5421:X,d5433:fe,dedt:pe,didt:me,dmdt:he,dndt:0,dnodt:ge,domdt:Z,del1:_e,del2:ve,del3:ye,xfact:be,xlamo:xe,xli:Se,xni:Ce}}function y(e){let t=(e-2451545)/36525,n=-62e-7*t*t*t+.093104*t*t+3164400184.812866*t+67310.54841;return n=n*s/240%o,n<0&&(n+=o),n}function b(e,t,n,r,i,a,o){return e instanceof Date?y(g(e)):y(t===void 0?e:g(e,t,n,r,i,a,o))}function re(e){let{ecco:t,epoch:n,inclo:r,opsmode:i}=e,{no:a}=e,s=t*t,c=1-s,u=Math.sqrt(c),d=Math.cos(r),p=d*d,ee=(l/a)**m,te=.75*f*(3*p-1)/(u*c),h=te/(ee*ee),g=ee*(1-h*h-h*(1/3+134*h*h/81));h=te/(g*g),a/=1+h;let ne=(l/a)**m,_=Math.sin(r),v=ne*c,y=1-5*p,re=-y-p-p,ie=1/ne,x=v*v,ae=ne*(1-t),S;if(i===`a`){let e=n-7305,t=Math.floor(e+1e-8),r=e-t,i=.017202791694070362,a=i+o;S=(1.7321343856509375+i*t+a*r+e*e*5075514194322695e-30)%o,S<0&&(S+=o)}else S=b(n+2433281.5);return{no:a,method:`n`,ainv:ie,ao:ne,con41:re,con42:y,cosio:d,cosio2:p,eccsq:s,omeosq:c,posq:x,rp:ae,rteosq:u,sinio:_,gsto:S}}function ie(e){let{irez:t,d2201:n,d2211:r,d3210:i,d3222:a,d4410:s,d4422:c,d5220:l,d5232:u,d5421:d,d5433:f,dedt:p,del1:m,del2:ee,del3:te,didt:h,dmdt:g,dnodt:ne,domdt:_,argpo:v,argpdot:y,t:b,tc:re,gsto:ie,xfact:x,xlamo:ae,no:S}=e,{atime:C,em:w,argpm:T,inclm:E,xli:D,mm:O,xni:k,nodem:A,nm:j}=e,oe=.13130908,M=2.8843198,N=.37448087,se=5.7686396,P=.95240898,F=1.8014998,I=1.050833,L=4.4108898,R=259200,ce,z,B,V,H,U,W,G,K=0,q=0,J=(ie+re*.0043752690880113)%o;if(w+=p*b,E+=h*b,T+=_*b,A+=ne*b,O+=g*b,t!==0){(C===0||b*C<=0||Math.abs(b)<Math.abs(C))&&(C=0,k=S,D=ae),ce=b>0?720:-720;let e=381;for(;e===381;)t===2?(G=v+y*C,B=G+G,z=D+D,W=n*Math.sin(B+D-se)+r*Math.sin(D-se)+i*Math.sin(G+D-P)+a*Math.sin(-G+D-P)+s*Math.sin(B+z-F)+c*Math.sin(z-F)+l*Math.sin(G+D-I)+u*Math.sin(-G+D-I)+d*Math.sin(G+z-L)+f*Math.sin(-G+z-L),H=k+x,U=n*Math.cos(B+D-se)+r*Math.cos(D-se)+i*Math.cos(G+D-P)+a*Math.cos(-G+D-P)+l*Math.cos(G+D-I)+u*Math.cos(-G+D-I)+2*(s*Math.cos(B+z-F)+c*Math.cos(z-F)+d*Math.cos(G+z-L)+f*Math.cos(-G+z-L)),U*=H):(W=m*Math.sin(D-oe)+ee*Math.sin(2*(D-M))+te*Math.sin(3*(D-N)),H=k+x,U=m*Math.cos(D-oe)+2*ee*Math.cos(2*(D-M))+3*te*Math.cos(3*(D-N)),U*=H),Math.abs(b-C)>=720?e=381:(q=b-C,e=0),e===381&&(D+=H*ce+W*R,k+=W*ce+U*R,C+=ce);j=k+W*q+U*q*q*.5,V=D+H*q+W*q*q*.5,t===1?(O=V-A-T+J,K=j-S):(O=V-2*A+2*J,K=j-S),j=S+K}return{atime:C,em:w,argpm:T,inclm:E,xli:D,mm:O,xni:k,nodem:A,dndt:K,nm:j}}var x;(function(e){e[e.None=0]=`None`,e[e.MeanEccentricityOutOfRange=1]=`MeanEccentricityOutOfRange`,e[e.MeanMotionBelowZero=2]=`MeanMotionBelowZero`,e[e.PerturbedEccentricityOutOfRange=3]=`PerturbedEccentricityOutOfRange`,e[e.SemiLatusRectumBelowZero=4]=`SemiLatusRectumBelowZero`,e[e.Decayed=6]=`Decayed`})(x||={});function ae(e,t){let n,r,i,s,d,ee,te,h,g,_,v,y,b,re,ae,S,C,w,T,E,D,O,k,A,j,oe,M;e.t=t,e.error=x.None;let N=e.mo+e.mdot*e.t,se=e.argpo+e.argpdot*e.t,P=e.nodeo+e.nodedot*e.t;g=se,D=N;let F=e.t*e.t;if(k=P+e.nodecf*F,C=1-e.cc1*e.t,w=e.bstar*e.cc4*e.t,T=e.t2cof*F,e.isimp!==1){te=e.omgcof*e.t;let t=1+e.eta*Math.cos(N);ee=e.xmcof*(t*t*t-e.delmo),S=te+ee,D=N+S,g=se-S,y=F*e.t,b=y*e.t,C=C-e.d2*F-e.d3*y-e.d4*b,w+=e.bstar*e.cc5*(Math.sin(D)-e.sinmao),T=T+e.t3cof*y+b*(e.t4cof+e.t*e.t5cof)}O=e.no;let I=e.ecco;if(E=e.inclo,e.method===`d`){re=e.t;let t=ie({irez:e.irez,d2201:e.d2201,d2211:e.d2211,d3210:e.d3210,d3222:e.d3222,d4410:e.d4410,d4422:e.d4422,d5220:e.d5220,d5232:e.d5232,d5421:e.d5421,d5433:e.d5433,dedt:e.dedt,del1:e.del1,del2:e.del2,del3:e.del3,didt:e.didt,dmdt:e.dmdt,dnodt:e.dnodt,domdt:e.domdt,argpo:e.argpo,argpdot:e.argpdot,t:e.t,tc:re,gsto:e.gsto,xfact:e.xfact,xlamo:e.xlamo,no:e.no,atime:e.atime,em:I,argpm:g,inclm:E,xli:e.xli,mm:D,xni:e.xni,nodem:k,nm:O});({em:I,argpm:g,inclm:E,mm:D,nodem:k,nm:O}=t)}if(O<=0)return e.error=x.MeanMotionBelowZero,null;let L=(l/O)**m*C*C;if(O=l/L**1.5,I-=w,I>=1||I<-.001)return e.error=x.MeanEccentricityOutOfRange,null;I<1e-6&&(I=1e-6),D+=e.no*T,j=D+g+k,k%=o,g%=o,j%=o,D=(j-g-k)%o;let R={am:L,em:I,im:E,Om:k,om:g,mm:D,nm:O},ce=Math.sin(E),z=Math.cos(E),B=I;if(A=E,_=g,M=k,oe=D,s=ce,i=z,e.method===`d`){let t=ne(e,{inclo:e.inclo,init:`n`,ep:B,inclp:A,nodep:M,argpp:_,mp:oe,opsmode:e.operationmode});if({ep:B,nodep:M,argpp:_,mp:oe}=t,A=t.inclp,A<0&&(A=-A,M+=a,_-=a),B<0||B>1)return e.error=x.PerturbedEccentricityOutOfRange,null}e.method===`d`&&(s=Math.sin(A),i=Math.cos(A),e.aycof=-.5*p*s,Math.abs(i+1)>15e-13?e.xlcof=-.25*p*s*(3+5*i)/(1+i):e.xlcof=-.25*p*s*(3+5*i)/15e-13);let V=B*Math.cos(_);S=1/(L*(1-B*B));let H=B*Math.sin(_)+S*e.aycof,U=(oe+_+M+S*e.xlcof*V-M)%o;h=U,ae=9999.9;let W=1;for(;Math.abs(ae)>=1e-12&&W<=10;)r=Math.sin(h),n=Math.cos(h),ae=1-n*V-r*H,ae=(U-H*n+V*r-h)/ae,Math.abs(ae)>=.95&&(ae=ae>0?.95:-.95),h+=ae,W+=1;let G=V*n+H*r,K=V*r-H*n,q=V*V+H*H,J=L*(1-q);if(J<0)return e.error=x.SemiLatusRectumBelowZero,null;let le=L*(1-G),Y=Math.sqrt(L)*K/le,ue=Math.sqrt(J)/le,de=Math.sqrt(1-q);S=K/(1+de);let X=L/le*(r-H-V*S),fe=L/le*(n-V+H*S);v=Math.atan2(X,fe);let pe=(fe+fe)*X,me=1-2*X*X;S=1/J;let he=.5*f*S,ge=he*S;e.method===`d`&&(d=i*i,e.con41=3*d-1,e.x1mth2=1-d,e.x7thm1=7*d-1);let Z=le*(1-1.5*ge*de*e.con41)+.5*he*e.x1mth2*me;if(Z<1)return e.error=x.Decayed,null;v-=.25*ge*e.x7thm1*pe;let _e=M+1.5*ge*i*pe,ve=A+1.5*ge*i*s*me,ye=Y-O*he*e.x1mth2*pe/l,be=ue+O*he*(e.x1mth2*me+1.5*e.con41)/l,xe=Math.sin(v),Se=Math.cos(v),Ce=Math.sin(_e),we=Math.cos(_e),Te=Math.sin(ve),Ee=Math.cos(ve),Q=-Ce*Ee,De=we*Ee,Oe=Q*xe+we*Se,$=De*xe+Ce*Se,ke=Te*xe,Ae=Q*Se-we*xe,je=De*Se-Ce*xe,Me=Te*Se;return{position:{x:Z*Oe*c,y:Z*$*c,z:Z*ke*c},velocity:{x:(ye*Oe+be*Ae)*u,y:(ye*$+be*je)*u,z:(ye*ke+be*Me)*u},meanElements:R}}function S(e,t){let{opsmode:n,satn:r,epoch:i,xbstar:o,xecco:s,xargpo:l,xinclo:u,xmo:ee,xno:te,xnodeo:h}=t,g,y,b,ie,x,S,C,w,T,E,D,O,k,A,j,oe,M,N,se,P,F,I,L,R,ce,z,B,V,H,U,W,G,K,q,J,le,Y,ue,de,X,fe,pe,me,he,ge,Z,_e,ve,ye,be,xe,Se,Ce,we,Te,Ee,Q=e;Q.isimp=0,Q.method=`n`,Q.aycof=0,Q.con41=0,Q.cc1=0,Q.cc4=0,Q.cc5=0,Q.d2=0,Q.d3=0,Q.d4=0,Q.delmo=0,Q.eta=0,Q.argpdot=0,Q.omgcof=0,Q.sinmao=0,Q.t=0,Q.t2cof=0,Q.t3cof=0,Q.t4cof=0,Q.t5cof=0,Q.x1mth2=0,Q.x7thm1=0,Q.mdot=0,Q.nodedot=0,Q.xlcof=0,Q.xmcof=0,Q.nodecf=0,Q.irez=0,Q.d2201=0,Q.d2211=0,Q.d3210=0,Q.d3222=0,Q.d4410=0,Q.d4422=0,Q.d5220=0,Q.d5232=0,Q.d5421=0,Q.d5433=0,Q.dedt=0,Q.del1=0,Q.del2=0,Q.del3=0,Q.didt=0,Q.dmdt=0,Q.dnodt=0,Q.domdt=0,Q.e3=0,Q.ee2=0,Q.peo=0,Q.pgho=0,Q.pho=0,Q.pinco=0,Q.plo=0,Q.se2=0,Q.se3=0,Q.sgh2=0,Q.sgh3=0,Q.sgh4=0,Q.sh2=0,Q.sh3=0,Q.si2=0,Q.si3=0,Q.sl2=0,Q.sl3=0,Q.sl4=0,Q.gsto=0,Q.xfact=0,Q.xgh2=0,Q.xgh3=0,Q.xgh4=0,Q.xh2=0,Q.xh3=0,Q.xi2=0,Q.xi3=0,Q.xl2=0,Q.xl3=0,Q.xl4=0,Q.xlamo=0,Q.zmol=0,Q.zmos=0,Q.atime=0,Q.xli=0,Q.xni=0,Q.bstar=o,Q.ecco=s,Q.argpo=l,Q.inclo=u,Q.mo=ee,Q.no=te,Q.nodeo=h,Q.operationmode=n,78/c+1;let De=42/c;De*De*De*De,Q.init=`y`,Q.t=0;let Oe=re({satn:r,ecco:Q.ecco,epoch:i,inclo:Q.inclo,no:Q.no,method:Q.method,opsmode:Q.operationmode}),{ao:$,con42:ke,cosio:Ae,cosio2:je,eccsq:Me,omeosq:Ne,posq:Pe,rp:Fe,rteosq:Ie,sinio:Le}=Oe;if(Q.no=Oe.no,Q.con41=Oe.con41,Q.gsto=Oe.gsto,Q.a=(Q.no*d)**(-2/3),Q.alta=Q.a*(1+Q.ecco)-1,Q.altp=Q.a*(1-Q.ecco)-1,Q.error=0,Ne>=0||Q.no>=0){if(Q.isimp=0,Fe<1.034492841559484&&(Q.isimp=1),B=1.0122292801892716,F=1.880279159015271e-9,N=(Fe-1)*c,N<156){B=N-78,N<98&&(B=20);let e=(120-B)/c;F=e*e*e*e,B=B/c+1}se=1/Pe,Z=1/($-B),Q.eta=$*Q.ecco*Z,O=Q.eta*Q.eta,D=Q.ecco*Q.eta,P=Math.abs(1-O),S=F*Z**4,C=S/P**3.5,ie=C*Q.no*($*(1+1.5*O+D*(4+O))+.375*f*Z/P*Q.con41*(8+3*O*(8+O))),Q.cc1=Q.bstar*ie,x=0,Q.ecco>1e-4&&(x=-2*S*Z*p*Q.no*Le/Q.ecco),Q.x1mth2=1-je,Q.cc4=2*Q.no*C*$*Ne*(Q.eta*(2+.5*O)+Q.ecco*(.5+2*O)-f*Z/($*P)*(-3*Q.con41*(1-2*D+O*(1.5-.5*D))+.75*Q.x1mth2*(2*O-D*(1+O))*Math.cos(2*Q.argpo))),Q.cc5=2*C*$*Ne*(1+2.75*(O+D)+D*O),w=je*je,me=1.5*f*se*Q.no,he=.5*me*f*se,ge=-.46875*-165597e-11*se*se*Q.no,Q.mdot=Q.no+.5*me*Ie*Q.con41+.0625*he*Ie*(13-78*je+137*w),Q.argpdot=-.5*me*ke+.0625*he*(7-114*je+395*w)+ge*(3-36*je+49*w),ve=-me*Ae,Q.nodedot=ve+(.5*he*(4-19*je)+2*ge*(3-7*je))*Ae,_e=Q.argpdot+Q.nodedot,Q.omgcof=Q.bstar*x*Math.cos(Q.argpo),Q.xmcof=0,Q.ecco>1e-4&&(Q.xmcof=-m*S*Q.bstar/D),Q.nodecf=3.5*Ne*ve*Q.cc1,Q.t2cof=1.5*Q.cc1,Math.abs(Ae+1)>15e-13?Q.xlcof=-.25*p*Le*(3+5*Ae)/(1+Ae):Q.xlcof=-.25*p*Le*(3+5*Ae)/15e-13,Q.aycof=-.5*p*Le;let e=1+Q.eta*Math.cos(Q.mo);if(Q.delmo=e*e*e,Q.sinmao=Math.sin(Q.mo),Q.x7thm1=7*je-1,2*a/Q.no>=225){Q.method=`d`,Q.isimp=1,fe=0,j=Q.inclo;let e=_({epoch:i,ep:Q.ecco,argpp:Q.argpo,tc:fe,inclp:Q.inclo,nodep:Q.nodeo,np:Q.no,e3:Q.e3,ee2:Q.ee2,peo:Q.peo,pgho:Q.pgho,pho:Q.pho,pinco:Q.pinco,plo:Q.plo,se2:Q.se2,se3:Q.se3,sgh2:Q.sgh2,sgh3:Q.sgh3,sgh4:Q.sgh4,sh2:Q.sh2,sh3:Q.sh3,si2:Q.si2,si3:Q.si3,sl2:Q.sl2,sl3:Q.sl3,sl4:Q.sl4,xgh2:Q.xgh2,xgh3:Q.xgh3,xgh4:Q.xgh4,xh2:Q.xh2,xh3:Q.xh3,xi2:Q.xi2,xi3:Q.xi3,xl2:Q.xl2,xl3:Q.xl3,xl4:Q.xl4,zmol:Q.zmol,zmos:Q.zmos});Q.e3=e.e3,Q.ee2=e.ee2,Q.peo=e.peo,Q.pgho=e.pgho,Q.pho=e.pho,Q.pinco=e.pinco,Q.plo=e.plo,Q.se2=e.se2,Q.se3=e.se3,Q.sgh2=e.sgh2,Q.sgh3=e.sgh3,Q.sgh4=e.sgh4,Q.sh2=e.sh2,Q.sh3=e.sh3,Q.si2=e.si2,Q.si3=e.si3,Q.sl2=e.sl2,Q.sl3=e.sl3,Q.sl4=e.sl4,{sinim:y,cosim:g,em:T,emsq:E,s1:I,s2:L,s3:R,s4:ce,s5:z,ss1:V,ss2:H,ss3:U,ss4:W,ss5:G,sz1:K,sz3:q,sz11:J,sz13:le,sz21:Y,sz23:ue,sz31:de,sz33:X}=e,Q.xgh2=e.xgh2,Q.xgh3=e.xgh3,Q.xgh4=e.xgh4,Q.xh2=e.xh2,Q.xh3=e.xh3,Q.xi2=e.xi2,Q.xi3=e.xi3,Q.xl2=e.xl2,Q.xl3=e.xl3,Q.xl4=e.xl4,Q.zmol=e.zmol,Q.zmos=e.zmos,{nm:M,z1:ye,z3:be,z11:xe,z13:Se,z21:Ce,z23:we,z31:Te,z33:Ee}=e;let t=ne(Q,{inclo:j,init:Q.init,ep:Q.ecco,inclp:Q.inclo,nodep:Q.nodeo,argpp:Q.argpo,mp:Q.mo,opsmode:Q.operationmode});Q.ecco=t.ep,Q.inclo=t.inclp,Q.nodeo=t.nodep,Q.argpo=t.argpp,Q.mo=t.mp,k=0,A=0,oe=0;let n=v({cosim:g,emsq:E,argpo:Q.argpo,s1:I,s2:L,s3:R,s4:ce,s5:z,sinim:y,ss1:V,ss2:H,ss3:U,ss4:W,ss5:G,sz1:K,sz3:q,sz11:J,sz13:le,sz21:Y,sz23:ue,sz31:de,sz33:X,t:Q.t,tc:fe,gsto:Q.gsto,mo:Q.mo,mdot:Q.mdot,no:Q.no,nodeo:Q.nodeo,nodedot:Q.nodedot,xpidot:_e,z1:ye,z3:be,z11:xe,z13:Se,z21:Ce,z23:we,z31:Te,z33:Ee,ecco:Q.ecco,eccsq:Me,em:T,argpm:k,inclm:j,mm:oe,nm:M,nodem:A,irez:Q.irez,atime:Q.atime,d2201:Q.d2201,d2211:Q.d2211,d3210:Q.d3210,d3222:Q.d3222,d4410:Q.d4410,d4422:Q.d4422,d5220:Q.d5220,d5232:Q.d5232,d5421:Q.d5421,d5433:Q.d5433,dedt:Q.dedt,didt:Q.didt,dmdt:Q.dmdt,dnodt:Q.dnodt,domdt:Q.domdt,del1:Q.del1,del2:Q.del2,del3:Q.del3,xfact:Q.xfact,xlamo:Q.xlamo,xli:Q.xli,xni:Q.xni});Q.irez=n.irez,Q.atime=n.atime,Q.d2201=n.d2201,Q.d2211=n.d2211,Q.d3210=n.d3210,Q.d3222=n.d3222,Q.d4410=n.d4410,Q.d4422=n.d4422,Q.d5220=n.d5220,Q.d5232=n.d5232,Q.d5421=n.d5421,Q.d5433=n.d5433,Q.dedt=n.dedt,Q.didt=n.didt,Q.dmdt=n.dmdt,Q.dnodt=n.dnodt,Q.domdt=n.domdt,Q.del1=n.del1,Q.del2=n.del2,Q.del3=n.del3,Q.xfact=n.xfact,Q.xlamo=n.xlamo,Q.xli=n.xli,Q.xni=n.xni}Q.isimp!==1&&(b=Q.cc1*Q.cc1,Q.d2=4*$*Z*b,pe=Q.d2*Z*Q.cc1/3,Q.d3=(17*$+B)*pe,Q.d4=.5*pe*$*Z*(221*$+31*B)*Q.cc1,Q.t3cof=Q.d2+2*b,Q.t4cof=.25*(3*Q.d3+Q.cc1*(12*Q.d2+10*b)),Q.t5cof=.2*(3*Q.d4+12*Q.cc1*Q.d3+6*Q.d2*Q.d2+15*b*(2*Q.d2+b)))}ae(Q,0),Q.init=`n`}function C(e,t=`i`){let n=e.NORAD_CAT_ID.toString(),r=new Date(e.EPOCH.endsWith(`Z`)?e.EPOCH:`${e.EPOCH}Z`),i=r.getUTCFullYear(),a=Number(i.toString().slice(-2)),o=(r.valueOf()-new Date(Date.UTC(i,0,1,0,0,0)).valueOf())/(86400*1e3)+1,c=Number(e.MEAN_MOTION_DOT),l=Number(e.MEAN_MOTION_DDOT);c/=ee*1440,l/=ee*1440*1440;let u=Number(e.BSTAR),d=Number(e.INCLINATION)*s,f=Number(e.RA_OF_ASC_NODE)*s,p=Number(e.ECCENTRICITY),m=Number(e.ARG_OF_PERICENTER)*s,h=Number(e.MEAN_ANOMALY)*s,ne=Number(e.MEAN_MOTION)/ee,{mon:_,day:v,hr:y,minute:b,sec:re}=te(i,o),ie=g(i,_,v,y,b,re),x={error:0,satnum:n,epochyr:a,epochdays:o,ndot:c,nddot:l,bstar:u,inclo:d,nodeo:f,ecco:p,argpo:m,mo:h,no:ne,jdsatepoch:ie};return S(x,{opsmode:t,satn:x.satnum,epoch:x.jdsatepoch-2433281.5,xbstar:x.bstar,xecco:x.ecco,xargpo:x.argpo,xinclo:x.inclo,xmo:x.mo,xno:x.no,xnodeo:x.nodeo}),x}3*Float64Array.BYTES_PER_ELEMENT;const w=Math.PI/180;Math.cos(i*w),Math.sin(i*w);function T(e){return new Date((e-2440587.5)*864e5).toISOString()}function E(e,t){let n=C({OBJECT_NAME:t??String(e.noradCatId),OBJECT_ID:String(e.noradCatId),EPOCH:T(e.epochJd),MEAN_MOTION:e.meanMotion,ECCENTRICITY:e.eccentricity,INCLINATION:e.inclination,RA_OF_ASC_NODE:e.raOfAscNode,ARG_OF_PERICENTER:e.argOfPericenter,MEAN_ANOMALY:e.meanAnomaly,EPHEMERIS_TYPE:0,CLASSIFICATION_TYPE:`U`,NORAD_CAT_ID:e.noradCatId,ELEMENT_SET_NO:e.elementSetNo,REV_AT_EPOCH:e.revAtEpoch,BSTAR:e.bstar,MEAN_MOTION_DOT:e.meanMotionDot,MEAN_MOTION_DDOT:e.meanMotionDdot});return n.error===x.None?n:(console.warn(`buildSatrec: SGP4 init failed for NORAD ${e.noradCatId} (error=${n.error})`),null)}const D=Math.PI/180,O=Math.cos(i*D),k=Math.sin(i*D),A=10/r;function j(e,t,n,r,i){return!isFinite(Math.fround(n))||!isFinite(Math.fround(r))||!isFinite(Math.fround(i))?!1:(e[t*3]=n,e[t*3+1]=r,e[t*3+2]=i,!0)}function oe(r,i,a,o,s,c,l,u,d,f=null,p=0){if(i<r.validityStart||i>r.validityEnd)return 0;let{count:m,kind:ee,equatorial:te,a:h,e:g,i:ne,om:_,w:v,ma:y,n:b,epoch:re,q:ie,tp:S,satrec:C,flags:w,visibleFromDays:T}=r,oe=p!==0&&r.applyFlagFilter,M=r.pickBase,N=d.length/3|0,se=i-2451545,P=0;for(let F=0;F<m&&!(P>=N);F++){let m=ee[F];if(m===0||T[F]>se||oe&&(w[F]&p)!==p)continue;if(m===3){let e=C[F];if(!e){if(e=E({noradCatId:r.satnum[F],epochJd:re[F],meanMotion:b[F]/360,eccentricity:g[F],inclination:ne[F],raOfAscNode:_[F],argOfPericenter:v[F],meanAnomaly:y[F],bstar:r.bstar[F],meanMotionDot:r.ndot[F],meanMotionDdot:r.nddot[F],elementSetNo:0,revAtEpoch:0}),!e){ee[F]=0;continue}C[F]=e}let t=(i-e.jdsatepoch)*1440,n=ae(e,t);if(!n||e.error!==x.None)continue;let p=n.position.x,m=n.position.y,te=n.position.z,h=p*A,ie=m*A,S=te*A,w=ie*O+S*k,T=-ie*k+S*O,D=h,oe=T,N=-w;if(!j(d,P,a+D-c,o+oe-l,s+N-u))continue;if(f){let e=M+F,t=P*4;f[t]=e&255,f[t+1]=e>>>8&255,f[t+2]=e>>>16&255,f[t+3]=e>>>24&255}P++;continue}let N,I,L=g[F],R=ne[F],ce=_[F],z=v[F];if(m===2){let e=n(ie[F],S[F],i);if(!e)continue;N=e.r*Math.cos(e.nu),I=e.r*Math.sin(e.nu)}else{let n=h[F];if(!isFinite(n)||!isFinite(L)||!isFinite(y[F])||!isFinite(b[F]))continue;let r=i-re[F],a=(y[F]+b[F]*r)*D,o,s;if(L<1||n>0){let t=Math.min(L,.9999999),r=e(a,t),i=Math.sqrt(1-t*t)*Math.sin(r)/(1-t*Math.cos(r)),c=(Math.cos(r)-t)/(1-t*Math.cos(r));o=Math.atan2(i,c),s=n*(1-t*Math.cos(r))}else{let e=t(a,L);if(!isFinite(e))continue;let r=L*Math.cosh(e)-1;if(Math.abs(r)<1e-15)continue;let i=Math.sqrt(L*L-1)*Math.sinh(e)/r,c=(L-Math.cosh(e))/r;o=Math.atan2(i,c),s=n*(1-L*Math.cosh(e))}N=s*Math.cos(o),I=s*Math.sin(o)}if(!isFinite(N)||!isFinite(I))continue;let B=Math.cos(z*D),V=Math.sin(z*D),H=Math.cos(R*D),U=Math.sin(R*D),W=Math.cos(ce*D),G=Math.sin(ce*D),K=(W*B-G*V*H)*N+(-W*V-G*B*H)*I,q=(G*B+W*V*H)*N+(-G*V+W*B*H)*I,J=V*U*N+B*U*I;if(te[F]){let e=q*O+J*k,t=-q*k+J*O;q=e,J=t}let le=K*10,Y=J*10,ue=-q*10;if(j(d,P,a+le-c,o+Y-l,s+ue-u)){if(f){let e=M+F,t=P*4;f[t]=e&255,f[t+1]=e>>>8&255,f[t+2]=e>>>16&255,f[t+3]=e>>>24&255}P++}}return P}const M=new Map;self.onmessage=e=>{let t=e.data;if(t.type===`ping`){self.postMessage({type:`pong`});return}if(t.type===`rewireDelta`){if(t.remove)for(let e of t.remove)M.delete(e);for(let e of t.set)M.set(e.id,e.cols);return}if(t.type===`tick`){let e=[],n=[],[r,i,a]=t.basis;for(let o of t.groups){let s=M.get(o.id);if(!s){e.push({id:o.id,count:0,buf:o.out.buffer,idbuf:o.outIds.buffer}),n.push(o.out.buffer,o.outIds.buffer);continue}let c=oe(s,t.jd,o.parent[0],o.parent[1],o.parent[2],r,i,a,o.out,o.outIds,t.requiredFlags??0);e.push({id:o.id,count:c,buf:o.out.buffer,idbuf:o.outIds.buffer}),n.push(o.out.buffer,o.outIds.buffer)}self.postMessage({type:`tickResult`,groups:e},n);return}};";
|
|
21864
|
+
var jsContent = "function e(e,t,n=1e-10,r=50){let i=e;for(let a=0;a<r;a++){let r=(i-t*Math.sin(i)-e)/(1-t*Math.cos(i));if(i-=Math.max(-1,Math.min(1,r)),Math.abs(r)<n)break}return i}function t(e,t,n=1e-10,r=50){if(e===0)return 0;let i=e<0?-1:1,a=Math.abs(e),o=0,s=1;for(;t*Math.sinh(s)-s<a;)if(s*=2,s>700)return NaN;let c=.5*(o+s);for(let e=0;e<r;e++){let e=t*Math.sinh(c)-c-a;e>0?s=c:o=c;let r=c-e/(t*Math.cosh(c)-1);r>o&&r<s||(r=.5*(o+s));let i=Math.abs(r-c);if(c=r,i<n)break}return i*c}function n(e,t,n){let r=.01720209895*(n-t)/(Math.sqrt(2)*e**1.5),i=Math.cbrt(3*r+Math.sqrt(1+9*r*r)),a=i-1/i,o=2*Math.atan(a),s=e*(1+a*a);return!isFinite(o)||!isFinite(s)||s<=0?null:{nu:o,r:s}}const r=149597870.7,i=23.4392911;86400**2/r**3,1/r,Math.cos(Math.PI/180*i),Math.sin(Math.PI/180*i);const a=Math.PI,o=a*2,s=a/180;180/a;const c=6378.135,l=60/Math.sqrt(c*c*c/398600.8),u=c*l/60,d=1/l,f=.001082616,p=-253881e-11/f,m=2/3,ee=1440/(2*a);function te(e,t){let n=[31,e%4==0?29:28,31,30,31,30,31,31,30,31,30,31],r=Math.floor(t),i=1,a=0;for(;r>a+n[i-1]&&i<12;)a+=n[i-1],i+=1;let o=i,s=r-a,c=(t-r)*24,l=Math.floor(c);c=(c-l)*60;let u=Math.floor(c);return{mon:o,day:s,hr:l,minute:u,sec:(c-u)*60}}function h(e,t,n,r,i,a,o=0){return 367*e-Math.floor(7*(e+Math.floor((t+9)/12))*.25)+Math.floor(275*t/9)+n+1721013.5+((o/6e4+a/60+i)/60+r)/24}function g(e,t,n,r,i,a,o=0){if(e instanceof Date){let t=e;return h(t.getUTCFullYear(),t.getUTCMonth()+1,t.getUTCDate(),t.getUTCHours(),t.getUTCMinutes(),t.getUTCSeconds(),t.getUTCMilliseconds())}return h(e,t,n,r,i,a,o)}function ne(e,t){let{e3:n,ee2:r,peo:i,pgho:s,pho:c,pinco:l,plo:u,se2:d,se3:f,sgh2:p,sgh3:m,sgh4:ee,sh2:te,sh3:h,si2:g,si3:ne,sl2:_,sl3:v,sl4:y,t:b,xgh2:re,xgh3:ie,xgh4:x,xh2:ae,xh3:S,xi2:C,xi3:w,xl2:T,xl3:E,xl4:D,zmol:O,zmos:k}=e,{init:A,opsmode:j}=t,{ep:oe,inclp:M,nodep:N,argpp:P,mp:se}=t,F,I,L,R,ce,z,B,V,H,U,W,G,K,q,J,Y,X,le,ue,de,fe;fe=k+119459e-10*b,A===`y`&&(fe=k),de=fe+2*.01675*Math.sin(fe),X=Math.sin(de),U=.5*X*X-.25,W=-.5*X*Math.cos(de);let pe=d*U+f*W,me=g*U+ne*W,he=_*U+v*W+y*X,ge=p*U+m*W+ee*X,Z=te*U+h*W;fe=O+.00015835218*b,A===`y`&&(fe=O),de=fe+2*.0549*Math.sin(fe),X=Math.sin(de),U=.5*X*X-.25,W=-.5*X*Math.cos(de);let _e=r*U+n*W,ve=C*U+w*W,ye=T*U+E*W+D*X,be=re*U+ie*W+x*X,xe=ae*U+S*W;return G=pe+_e,J=me+ve,Y=he+ye,K=ge+be,q=Z+xe,A===`n`&&(G-=i,J-=l,Y-=u,K-=s,q-=c,M+=J,oe+=G,R=Math.sin(M),L=Math.cos(M),M>=.2?(q/=R,K-=L*q,P+=K,N+=q,se+=Y):(z=Math.sin(N),ce=Math.cos(N),F=R*z,I=R*ce,B=q*ce+J*L*z,V=-q*z+J*L*ce,F+=B,I+=V,N%=o,N<0&&j===`a`&&(N+=o),le=se+P+L*N,H=Y+K-J*N*R,le+=H,ue=N,N=Math.atan2(F,I),N<0&&j===`a`&&(N+=o),Math.abs(ue-N)>a&&(N<ue?N+=o:N-=o),se+=Y,P=le-se-L*N)),{ep:oe,inclp:M,nodep:N,argpp:P,mp:se}}function _(e){let{epoch:t,ep:n,argpp:r,tc:i,inclp:a,nodep:s,np:c}=e,l,u,d,f,p,m,ee,te,h,g,ne,_,v,y,b,re,ie,x,ae,S,C,w,T,E,D,O,k,A,j,oe,M,N,P,se,F,I,L,R,ce,z,B,V,H,U,W,G,K,q,J,Y,X,le,ue,de,fe,pe,me,he,ge,Z,_e,ve,ye,be=.01675,xe=.0549,Se=c,Ce=n,we=Math.sin(s),Te=Math.cos(s),Ee=Math.sin(r),Q=Math.cos(r),De=Math.sin(a),Oe=Math.cos(a),$=Ce*Ce,ke=1-$,Ae=Math.sqrt(ke),je=t+18261.5+i/1440,Me=(4.523602-.00092422029*je)%o,Ne=Math.sin(Me),Pe=Math.cos(Me),Fe=.91375164-.03568096*Pe,Ie=Math.sqrt(1-Fe*Fe),Le=.089683511*Ne/Ie,Re=Math.sqrt(1-Le*Le),ze=5.8351514+.001944368*je,Be=.39785416*Ne/Ie,Ve=Re*Pe+.91744867*Le*Ne;Be=Math.atan2(Be,Ve),Be+=ze-Me;let He=Math.cos(Be),Ue=Math.sin(Be);S=.1945905,C=-.98088458,E=.91744867,D=.39785416,w=Te,T=we,ne=29864797e-13;let We=1/Se,Ge=0;for(;Ge<2;)Ge+=1,l=S*w+C*E*T,d=-C*w+S*E*T,ee=-S*T+C*E*w,te=C*D,h=C*T+S*E*w,g=S*D,u=Oe*ee+De*te,f=Oe*h+De*g,p=-De*ee+Oe*te,m=-De*h+Oe*g,_=l*Q+u*Ee,v=d*Q+f*Ee,y=-l*Ee+u*Q,b=-d*Ee+f*Q,re=p*Ee,ie=m*Ee,x=p*Q,ae=m*Q,_e=12*_*_-3*y*y,ve=24*_*v-6*y*b,ye=12*v*v-3*b*b,le=3*(l*l+u*u)+_e*$,ue=6*(l*d+u*f)+ve*$,de=3*(d*d+f*f)+ye*$,fe=-6*l*p+$*(-24*_*x-6*y*re),pe=-6*(l*m+d*p)+$*(-24*(v*x+_*ae)+-6*(y*ie+b*re)),me=-6*d*m+$*(-24*v*ae-6*b*ie),he=6*u*p+$*(24*_*re-6*y*x),ge=6*(f*p+u*m)+$*(24*(v*re+_*ie)-6*(b*x+y*ae)),Z=6*f*m+$*(24*v*ie-6*b*ae),le=le+le+ke*_e,ue=ue+ue+ke*ve,de=de+de+ke*ye,K=ne*We,G=-.5*K/Ae,q=K*Ae,W=-15*Ce*q,J=_*y+v*b,Y=v*y+_*b,X=v*b-_*y,Ge===1&&(O=W,k=G,A=K,j=q,oe=J,M=Y,N=X,P=le,se=ue,F=de,I=fe,L=pe,R=me,ce=he,z=ge,B=Z,V=_e,H=ve,U=ye,S=He,C=Ue,E=Fe,D=Ie,w=Re*Te+Le*we,T=we*Re-Te*Le,ne=4.7968065e-7);let Ke=(4.7199672+(.2299715*je-ze))%o,qe=(6.2565837+.017201977*je)%o,Je=2*O*M,Ye=2*O*N,Xe=2*k*L,Ze=2*k*(R-I),Qe=-2*A*se,$e=-2*A*(F-P),et=-2*A*(-21-9*$)*be,tt=2*j*H,nt=2*j*(U-V),rt=-18*j*be,it=-2*k*z,at=-2*k*(B-ce),ot=2*W*Y,st=2*W*X,ct=2*G*pe,lt=2*G*(me-fe),ut=-2*K*ue,dt=-2*K*(de-le),ft=-2*K*(-21-9*$)*xe,pt=2*q*ve,mt=2*q*(ye-_e),ht=-18*q*xe,gt=-2*G*ge,_t=-2*G*(Z-he);return{snodm:we,cnodm:Te,sinim:De,cosim:Oe,sinomm:Ee,cosomm:Q,day:je,e3:st,ee2:ot,em:Ce,emsq:$,gam:ze,peo:0,pgho:0,pho:0,pinco:0,plo:0,rtemsq:Ae,se2:Je,se3:Ye,sgh2:tt,sgh3:nt,sgh4:rt,sh2:it,sh3:at,si2:Xe,si3:Ze,sl2:Qe,sl3:$e,sl4:et,s1:W,s2:G,s3:K,s4:q,s5:J,s6:Y,s7:X,ss1:O,ss2:k,ss3:A,ss4:j,ss5:oe,ss6:M,ss7:N,sz1:P,sz2:se,sz3:F,sz11:I,sz12:L,sz13:R,sz21:ce,sz22:z,sz23:B,sz31:V,sz32:H,sz33:U,xgh2:pt,xgh3:mt,xgh4:ht,xh2:gt,xh3:_t,xi2:ct,xi3:lt,xl2:ut,xl3:dt,xl4:ft,nm:Se,z1:le,z2:ue,z3:de,z11:fe,z12:pe,z13:me,z21:he,z22:ge,z23:Z,z31:_e,z32:ve,z33:ye,zmol:Ke,zmos:qe}}function v(e){let{cosim:t,argpo:n,s1:r,s2:i,s3:s,s4:c,s5:u,sinim:d,ss1:f,ss2:p,ss3:ee,ss4:te,ss5:h,sz1:g,sz3:ne,sz11:_,sz13:v,sz21:y,sz23:b,sz31:re,sz33:ie,t:x,tc:ae,gsto:S,mo:C,mdot:w,no:T,nodeo:E,nodedot:D,xpidot:O,z1:k,z3:A,z11:j,z13:oe,z21:M,z23:N,z31:P,z33:se,ecco:F,eccsq:I}=e,{emsq:L,em:R,argpm:ce,inclm:z,mm:B,nm:V,nodem:H,irez:U,atime:W,d2201:G,d2211:K,d3210:q,d3222:J,d4410:Y,d4422:X,d5220:le,d5232:ue,d5421:de,d5433:fe,dedt:pe,didt:me,dmdt:he,dnodt:ge,domdt:Z,del1:_e,del2:ve,del3:ye,xfact:be,xlamo:xe,xli:Se,xni:Ce}=e,we,Te,Ee,Q,De,Oe,$,ke,Ae,je,Me,Ne,Pe,Fe,Ie,Le,Re,ze,Be,Ve,He,Ue,We,Ge,Ke,qe,Je,Ye,Xe,Ze,Qe,$e,et=.0043752690880113,tt=.00015835218,nt=119459e-10;U=0,V<.0052359877&&V>.0034906585&&(U=1),V>=.00826&&V<=.00924&&R>=.5&&(U=2);let rt=f*nt*h,it=p*nt*(_+v),at=-nt*ee*(g+ne-14-6*L),ot=te*nt*(re+ie-6),st=-nt*p*(y+b);(z<.052359877||z>a-.052359877)&&(st=0),d!==0&&(st/=d);let ct=ot-t*st;pe=rt+r*tt*u,me=it+i*tt*(j+oe),he=at-tt*s*(k+A-14-6*L);let lt=c*tt*(P+se-6),ut=-tt*i*(M+N);(z<.052359877||z>a-.052359877)&&(ut=0),Z=ct+lt,ge=st,d!==0&&(Z-=t/d*ut,ge+=ut/d);let dt=(S+ae*et)%o;if(R+=pe*x,z+=me*x,ce+=Z*x,H+=ge*x,B+=he*x,U!==0){if(Ze=(V/l)**m,U===2){Qe=t*t;let e=R;R=F;let n=L;L=I,$e=R*L,Fe=-.306-(R-.64)*.44,R<=.65?(Ie=3.616-13.247*R+16.29*L,Re=-19.302+117.39*R-228.419*L+156.591*$e,ze=-18.9068+109.7927*R-214.6334*L+146.5816*$e,Be=-41.122+242.694*R-471.094*L+313.953*$e,Ve=-146.407+841.88*R-1629.014*L+1083.435*$e,He=-532.114+3017.977*R-5740.032*L+3708.276*$e):(Ie=-72.099+331.819*R-508.738*L+266.724*$e,Re=-346.844+1582.851*R-2415.925*L+1246.113*$e,ze=-342.585+1554.908*R-2366.899*L+1215.972*$e,Be=-1052.797+4758.686*R-7193.992*L+3651.957*$e,Ve=-3581.69+16178.11*R-24462.77*L+12422.52*$e,He=R>.715?-5149.66+29936.92*R-54087.36*L+31324.56*$e:1464.74-4664.75*R+3763.64*L),R<.7?(Ge=-919.2277+4988.61*R-9064.77*L+5542.21*$e,Ue=-822.71072+4568.6173*R-8491.4146*L+5337.524*$e,We=-853.666+4690.25*R-8624.77*L+5341.4*$e):(Ge=-37995.78+161616.52*R-229838.2*L+109377.94*$e,Ue=-51752.104+218913.95*R-309468.16*L+146349.42*$e,We=-40023.88+170470.89*R-242699.48*L+115605.82*$e),Ke=d*d,we=.75*(1+2*t+Qe),Te=1.5*Ke,Q=1.875*d*(1-2*t-3*Qe),De=-1.875*d*(1+2*t-3*Qe),$=35*Ke*we,ke=39.375*Ke*Ke,Ae=9.84375*d*(Ke*(1-2*t-5*Qe)+.33333333*(-2+4*t+6*Qe)),je=d*(4.92187512*Ke*(-2-4*t+10*Qe)+6.56250012*(1+2*t-3*Qe)),Me=29.53125*d*(2-8*t+Qe*(-12+8*t+10*Qe)),Ne=29.53125*d*(-2-8*t+Qe*(12+8*t-10*Qe)),Ye=V*V,Xe=Ze*Ze,Je=3*Ye*Xe,qe=Je*17891679e-13,G=qe*we*Fe,K=qe*Te*Ie,Je*=Ze,qe=Je*3.7393792e-7,q=qe*Q*Re,J=qe*De*ze,Je*=Ze,qe=2*Je*7.3636953e-9,Y=qe*$*Be,X=qe*ke*Ve,Je*=Ze,qe=Je*1.1428639e-7,le=qe*Ae*He,ue=qe*je*We,qe=2*Je*2.1765803e-9,de=qe*Me*Ue,fe=qe*Ne*Ge,xe=(C+E+E-(dt+dt))%o,be=w+he+2*(D+ge-et)-T,R=e,L=n}U===1&&(Pe=1+L*(-2.5+.8125*L),Re=1+2*L,Le=1+L*(-6+6.60937*L),we=.75*(1+t)*(1+t),Ee=.9375*d*d*(1+3*t)-.75*(1+t),Oe=1+t,Oe*=1.875*Oe*Oe,_e=3*V*V*Ze*Ze,ve=2*_e*we*Pe*17891679e-13,ye=3*_e*Oe*Le*2.2123015e-7*Ze,_e=_e*Ee*Re*21460748e-13*Ze,xe=(C+E+n-dt)%o,be=w+O+he+Z+ge-(T+et)),Se=xe,Ce=T,W=0,V=T+0}return{em:R,argpm:ce,inclm:z,mm:B,nm:V,nodem:H,irez:U,atime:W,d2201:G,d2211:K,d3210:q,d3222:J,d4410:Y,d4422:X,d5220:le,d5232:ue,d5421:de,d5433:fe,dedt:pe,didt:me,dmdt:he,dndt:0,dnodt:ge,domdt:Z,del1:_e,del2:ve,del3:ye,xfact:be,xlamo:xe,xli:Se,xni:Ce}}function y(e){let t=(e-2451545)/36525,n=-62e-7*t*t*t+.093104*t*t+3164400184.812866*t+67310.54841;return n=n*s/240%o,n<0&&(n+=o),n}function b(e,t,n,r,i,a,o){return e instanceof Date?y(g(e)):y(t===void 0?e:g(e,t,n,r,i,a,o))}function re(e){let{ecco:t,epoch:n,inclo:r,opsmode:i}=e,{no:a}=e,s=t*t,c=1-s,u=Math.sqrt(c),d=Math.cos(r),p=d*d,ee=(l/a)**m,te=.75*f*(3*p-1)/(u*c),h=te/(ee*ee),g=ee*(1-h*h-h*(1/3+134*h*h/81));h=te/(g*g),a/=1+h;let ne=(l/a)**m,_=Math.sin(r),v=ne*c,y=1-5*p,re=-y-p-p,ie=1/ne,x=v*v,ae=ne*(1-t),S;if(i===`a`){let e=n-7305,t=Math.floor(e+1e-8),r=e-t,i=.017202791694070362,a=i+o;S=(1.7321343856509375+i*t+a*r+e*e*5075514194322695e-30)%o,S<0&&(S+=o)}else S=b(n+2433281.5);return{no:a,method:`n`,ainv:ie,ao:ne,con41:re,con42:y,cosio:d,cosio2:p,eccsq:s,omeosq:c,posq:x,rp:ae,rteosq:u,sinio:_,gsto:S}}function ie(e){let{irez:t,d2201:n,d2211:r,d3210:i,d3222:a,d4410:s,d4422:c,d5220:l,d5232:u,d5421:d,d5433:f,dedt:p,del1:m,del2:ee,del3:te,didt:h,dmdt:g,dnodt:ne,domdt:_,argpo:v,argpdot:y,t:b,tc:re,gsto:ie,xfact:x,xlamo:ae,no:S}=e,{atime:C,em:w,argpm:T,inclm:E,xli:D,mm:O,xni:k,nodem:A,nm:j}=e,oe=.13130908,M=2.8843198,N=.37448087,P=5.7686396,se=.95240898,F=1.8014998,I=1.050833,L=4.4108898,R=259200,ce,z,B,V,H,U,W,G,K=0,q=0,J=(ie+re*.0043752690880113)%o;if(w+=p*b,E+=h*b,T+=_*b,A+=ne*b,O+=g*b,t!==0){(C===0||b*C<=0||Math.abs(b)<Math.abs(C))&&(C=0,k=S,D=ae),ce=b>0?720:-720;let e=381;for(;e===381;)t===2?(G=v+y*C,B=G+G,z=D+D,W=n*Math.sin(B+D-P)+r*Math.sin(D-P)+i*Math.sin(G+D-se)+a*Math.sin(-G+D-se)+s*Math.sin(B+z-F)+c*Math.sin(z-F)+l*Math.sin(G+D-I)+u*Math.sin(-G+D-I)+d*Math.sin(G+z-L)+f*Math.sin(-G+z-L),H=k+x,U=n*Math.cos(B+D-P)+r*Math.cos(D-P)+i*Math.cos(G+D-se)+a*Math.cos(-G+D-se)+l*Math.cos(G+D-I)+u*Math.cos(-G+D-I)+2*(s*Math.cos(B+z-F)+c*Math.cos(z-F)+d*Math.cos(G+z-L)+f*Math.cos(-G+z-L)),U*=H):(W=m*Math.sin(D-oe)+ee*Math.sin(2*(D-M))+te*Math.sin(3*(D-N)),H=k+x,U=m*Math.cos(D-oe)+2*ee*Math.cos(2*(D-M))+3*te*Math.cos(3*(D-N)),U*=H),Math.abs(b-C)>=720?e=381:(q=b-C,e=0),e===381&&(D+=H*ce+W*R,k+=W*ce+U*R,C+=ce);j=k+W*q+U*q*q*.5,V=D+H*q+W*q*q*.5,t===1?(O=V-A-T+J,K=j-S):(O=V-2*A+2*J,K=j-S),j=S+K}return{atime:C,em:w,argpm:T,inclm:E,xli:D,mm:O,xni:k,nodem:A,dndt:K,nm:j}}var x;(function(e){e[e.None=0]=`None`,e[e.MeanEccentricityOutOfRange=1]=`MeanEccentricityOutOfRange`,e[e.MeanMotionBelowZero=2]=`MeanMotionBelowZero`,e[e.PerturbedEccentricityOutOfRange=3]=`PerturbedEccentricityOutOfRange`,e[e.SemiLatusRectumBelowZero=4]=`SemiLatusRectumBelowZero`,e[e.Decayed=6]=`Decayed`})(x||={});function ae(e,t){let n,r,i,s,d,ee,te,h,g,_,v,y,b,re,ae,S,C,w,T,E,D,O,k,A,j,oe,M;e.t=t,e.error=x.None;let N=e.mo+e.mdot*e.t,P=e.argpo+e.argpdot*e.t,se=e.nodeo+e.nodedot*e.t;g=P,D=N;let F=e.t*e.t;if(k=se+e.nodecf*F,C=1-e.cc1*e.t,w=e.bstar*e.cc4*e.t,T=e.t2cof*F,e.isimp!==1){te=e.omgcof*e.t;let t=1+e.eta*Math.cos(N);ee=e.xmcof*(t*t*t-e.delmo),S=te+ee,D=N+S,g=P-S,y=F*e.t,b=y*e.t,C=C-e.d2*F-e.d3*y-e.d4*b,w+=e.bstar*e.cc5*(Math.sin(D)-e.sinmao),T=T+e.t3cof*y+b*(e.t4cof+e.t*e.t5cof)}O=e.no;let I=e.ecco;if(E=e.inclo,e.method===`d`){re=e.t;let t=ie({irez:e.irez,d2201:e.d2201,d2211:e.d2211,d3210:e.d3210,d3222:e.d3222,d4410:e.d4410,d4422:e.d4422,d5220:e.d5220,d5232:e.d5232,d5421:e.d5421,d5433:e.d5433,dedt:e.dedt,del1:e.del1,del2:e.del2,del3:e.del3,didt:e.didt,dmdt:e.dmdt,dnodt:e.dnodt,domdt:e.domdt,argpo:e.argpo,argpdot:e.argpdot,t:e.t,tc:re,gsto:e.gsto,xfact:e.xfact,xlamo:e.xlamo,no:e.no,atime:e.atime,em:I,argpm:g,inclm:E,xli:e.xli,mm:D,xni:e.xni,nodem:k,nm:O});({em:I,argpm:g,inclm:E,mm:D,nodem:k,nm:O}=t)}if(O<=0)return e.error=x.MeanMotionBelowZero,null;let L=(l/O)**m*C*C;if(O=l/L**1.5,I-=w,I>=1||I<-.001)return e.error=x.MeanEccentricityOutOfRange,null;I<1e-6&&(I=1e-6),D+=e.no*T,j=D+g+k,k%=o,g%=o,j%=o,D=(j-g-k)%o;let R={am:L,em:I,im:E,Om:k,om:g,mm:D,nm:O},ce=Math.sin(E),z=Math.cos(E),B=I;if(A=E,_=g,M=k,oe=D,s=ce,i=z,e.method===`d`){let t=ne(e,{inclo:e.inclo,init:`n`,ep:B,inclp:A,nodep:M,argpp:_,mp:oe,opsmode:e.operationmode});if({ep:B,nodep:M,argpp:_,mp:oe}=t,A=t.inclp,A<0&&(A=-A,M+=a,_-=a),B<0||B>1)return e.error=x.PerturbedEccentricityOutOfRange,null}e.method===`d`&&(s=Math.sin(A),i=Math.cos(A),e.aycof=-.5*p*s,Math.abs(i+1)>15e-13?e.xlcof=-.25*p*s*(3+5*i)/(1+i):e.xlcof=-.25*p*s*(3+5*i)/15e-13);let V=B*Math.cos(_);S=1/(L*(1-B*B));let H=B*Math.sin(_)+S*e.aycof,U=(oe+_+M+S*e.xlcof*V-M)%o;h=U,ae=9999.9;let W=1;for(;Math.abs(ae)>=1e-12&&W<=10;)r=Math.sin(h),n=Math.cos(h),ae=1-n*V-r*H,ae=(U-H*n+V*r-h)/ae,Math.abs(ae)>=.95&&(ae=ae>0?.95:-.95),h+=ae,W+=1;let G=V*n+H*r,K=V*r-H*n,q=V*V+H*H,J=L*(1-q);if(J<0)return e.error=x.SemiLatusRectumBelowZero,null;let Y=L*(1-G),X=Math.sqrt(L)*K/Y,le=Math.sqrt(J)/Y,ue=Math.sqrt(1-q);S=K/(1+ue);let de=L/Y*(r-H-V*S),fe=L/Y*(n-V+H*S);v=Math.atan2(de,fe);let pe=(fe+fe)*de,me=1-2*de*de;S=1/J;let he=.5*f*S,ge=he*S;e.method===`d`&&(d=i*i,e.con41=3*d-1,e.x1mth2=1-d,e.x7thm1=7*d-1);let Z=Y*(1-1.5*ge*ue*e.con41)+.5*he*e.x1mth2*me;if(Z<1)return e.error=x.Decayed,null;v-=.25*ge*e.x7thm1*pe;let _e=M+1.5*ge*i*pe,ve=A+1.5*ge*i*s*me,ye=X-O*he*e.x1mth2*pe/l,be=le+O*he*(e.x1mth2*me+1.5*e.con41)/l,xe=Math.sin(v),Se=Math.cos(v),Ce=Math.sin(_e),we=Math.cos(_e),Te=Math.sin(ve),Ee=Math.cos(ve),Q=-Ce*Ee,De=we*Ee,Oe=Q*xe+we*Se,$=De*xe+Ce*Se,ke=Te*xe,Ae=Q*Se-we*xe,je=De*Se-Ce*xe,Me=Te*Se;return{position:{x:Z*Oe*c,y:Z*$*c,z:Z*ke*c},velocity:{x:(ye*Oe+be*Ae)*u,y:(ye*$+be*je)*u,z:(ye*ke+be*Me)*u},meanElements:R}}function S(e,t){let{opsmode:n,satn:r,epoch:i,xbstar:o,xecco:s,xargpo:l,xinclo:u,xmo:ee,xno:te,xnodeo:h}=t,g,y,b,ie,x,S,C,w,T,E,D,O,k,A,j,oe,M,N,P,se,F,I,L,R,ce,z,B,V,H,U,W,G,K,q,J,Y,X,le,ue,de,fe,pe,me,he,ge,Z,_e,ve,ye,be,xe,Se,Ce,we,Te,Ee,Q=e;Q.isimp=0,Q.method=`n`,Q.aycof=0,Q.con41=0,Q.cc1=0,Q.cc4=0,Q.cc5=0,Q.d2=0,Q.d3=0,Q.d4=0,Q.delmo=0,Q.eta=0,Q.argpdot=0,Q.omgcof=0,Q.sinmao=0,Q.t=0,Q.t2cof=0,Q.t3cof=0,Q.t4cof=0,Q.t5cof=0,Q.x1mth2=0,Q.x7thm1=0,Q.mdot=0,Q.nodedot=0,Q.xlcof=0,Q.xmcof=0,Q.nodecf=0,Q.irez=0,Q.d2201=0,Q.d2211=0,Q.d3210=0,Q.d3222=0,Q.d4410=0,Q.d4422=0,Q.d5220=0,Q.d5232=0,Q.d5421=0,Q.d5433=0,Q.dedt=0,Q.del1=0,Q.del2=0,Q.del3=0,Q.didt=0,Q.dmdt=0,Q.dnodt=0,Q.domdt=0,Q.e3=0,Q.ee2=0,Q.peo=0,Q.pgho=0,Q.pho=0,Q.pinco=0,Q.plo=0,Q.se2=0,Q.se3=0,Q.sgh2=0,Q.sgh3=0,Q.sgh4=0,Q.sh2=0,Q.sh3=0,Q.si2=0,Q.si3=0,Q.sl2=0,Q.sl3=0,Q.sl4=0,Q.gsto=0,Q.xfact=0,Q.xgh2=0,Q.xgh3=0,Q.xgh4=0,Q.xh2=0,Q.xh3=0,Q.xi2=0,Q.xi3=0,Q.xl2=0,Q.xl3=0,Q.xl4=0,Q.xlamo=0,Q.zmol=0,Q.zmos=0,Q.atime=0,Q.xli=0,Q.xni=0,Q.bstar=o,Q.ecco=s,Q.argpo=l,Q.inclo=u,Q.mo=ee,Q.no=te,Q.nodeo=h,Q.operationmode=n,78/c+1;let De=42/c;De*De*De*De,Q.init=`y`,Q.t=0;let Oe=re({satn:r,ecco:Q.ecco,epoch:i,inclo:Q.inclo,no:Q.no,method:Q.method,opsmode:Q.operationmode}),{ao:$,con42:ke,cosio:Ae,cosio2:je,eccsq:Me,omeosq:Ne,posq:Pe,rp:Fe,rteosq:Ie,sinio:Le}=Oe;if(Q.no=Oe.no,Q.con41=Oe.con41,Q.gsto=Oe.gsto,Q.a=(Q.no*d)**(-2/3),Q.alta=Q.a*(1+Q.ecco)-1,Q.altp=Q.a*(1-Q.ecco)-1,Q.error=0,Ne>=0||Q.no>=0){if(Q.isimp=0,Fe<1.034492841559484&&(Q.isimp=1),B=1.0122292801892716,F=1.880279159015271e-9,N=(Fe-1)*c,N<156){B=N-78,N<98&&(B=20);let e=(120-B)/c;F=e*e*e*e,B=B/c+1}P=1/Pe,Z=1/($-B),Q.eta=$*Q.ecco*Z,O=Q.eta*Q.eta,D=Q.ecco*Q.eta,se=Math.abs(1-O),S=F*Z**4,C=S/se**3.5,ie=C*Q.no*($*(1+1.5*O+D*(4+O))+.375*f*Z/se*Q.con41*(8+3*O*(8+O))),Q.cc1=Q.bstar*ie,x=0,Q.ecco>1e-4&&(x=-2*S*Z*p*Q.no*Le/Q.ecco),Q.x1mth2=1-je,Q.cc4=2*Q.no*C*$*Ne*(Q.eta*(2+.5*O)+Q.ecco*(.5+2*O)-f*Z/($*se)*(-3*Q.con41*(1-2*D+O*(1.5-.5*D))+.75*Q.x1mth2*(2*O-D*(1+O))*Math.cos(2*Q.argpo))),Q.cc5=2*C*$*Ne*(1+2.75*(O+D)+D*O),w=je*je,me=1.5*f*P*Q.no,he=.5*me*f*P,ge=-.46875*-165597e-11*P*P*Q.no,Q.mdot=Q.no+.5*me*Ie*Q.con41+.0625*he*Ie*(13-78*je+137*w),Q.argpdot=-.5*me*ke+.0625*he*(7-114*je+395*w)+ge*(3-36*je+49*w),ve=-me*Ae,Q.nodedot=ve+(.5*he*(4-19*je)+2*ge*(3-7*je))*Ae,_e=Q.argpdot+Q.nodedot,Q.omgcof=Q.bstar*x*Math.cos(Q.argpo),Q.xmcof=0,Q.ecco>1e-4&&(Q.xmcof=-m*S*Q.bstar/D),Q.nodecf=3.5*Ne*ve*Q.cc1,Q.t2cof=1.5*Q.cc1,Math.abs(Ae+1)>15e-13?Q.xlcof=-.25*p*Le*(3+5*Ae)/(1+Ae):Q.xlcof=-.25*p*Le*(3+5*Ae)/15e-13,Q.aycof=-.5*p*Le;let e=1+Q.eta*Math.cos(Q.mo);if(Q.delmo=e*e*e,Q.sinmao=Math.sin(Q.mo),Q.x7thm1=7*je-1,2*a/Q.no>=225){Q.method=`d`,Q.isimp=1,fe=0,j=Q.inclo;let e=_({epoch:i,ep:Q.ecco,argpp:Q.argpo,tc:fe,inclp:Q.inclo,nodep:Q.nodeo,np:Q.no,e3:Q.e3,ee2:Q.ee2,peo:Q.peo,pgho:Q.pgho,pho:Q.pho,pinco:Q.pinco,plo:Q.plo,se2:Q.se2,se3:Q.se3,sgh2:Q.sgh2,sgh3:Q.sgh3,sgh4:Q.sgh4,sh2:Q.sh2,sh3:Q.sh3,si2:Q.si2,si3:Q.si3,sl2:Q.sl2,sl3:Q.sl3,sl4:Q.sl4,xgh2:Q.xgh2,xgh3:Q.xgh3,xgh4:Q.xgh4,xh2:Q.xh2,xh3:Q.xh3,xi2:Q.xi2,xi3:Q.xi3,xl2:Q.xl2,xl3:Q.xl3,xl4:Q.xl4,zmol:Q.zmol,zmos:Q.zmos});Q.e3=e.e3,Q.ee2=e.ee2,Q.peo=e.peo,Q.pgho=e.pgho,Q.pho=e.pho,Q.pinco=e.pinco,Q.plo=e.plo,Q.se2=e.se2,Q.se3=e.se3,Q.sgh2=e.sgh2,Q.sgh3=e.sgh3,Q.sgh4=e.sgh4,Q.sh2=e.sh2,Q.sh3=e.sh3,Q.si2=e.si2,Q.si3=e.si3,Q.sl2=e.sl2,Q.sl3=e.sl3,Q.sl4=e.sl4,{sinim:y,cosim:g,em:T,emsq:E,s1:I,s2:L,s3:R,s4:ce,s5:z,ss1:V,ss2:H,ss3:U,ss4:W,ss5:G,sz1:K,sz3:q,sz11:J,sz13:Y,sz21:X,sz23:le,sz31:ue,sz33:de}=e,Q.xgh2=e.xgh2,Q.xgh3=e.xgh3,Q.xgh4=e.xgh4,Q.xh2=e.xh2,Q.xh3=e.xh3,Q.xi2=e.xi2,Q.xi3=e.xi3,Q.xl2=e.xl2,Q.xl3=e.xl3,Q.xl4=e.xl4,Q.zmol=e.zmol,Q.zmos=e.zmos,{nm:M,z1:ye,z3:be,z11:xe,z13:Se,z21:Ce,z23:we,z31:Te,z33:Ee}=e;let t=ne(Q,{inclo:j,init:Q.init,ep:Q.ecco,inclp:Q.inclo,nodep:Q.nodeo,argpp:Q.argpo,mp:Q.mo,opsmode:Q.operationmode});Q.ecco=t.ep,Q.inclo=t.inclp,Q.nodeo=t.nodep,Q.argpo=t.argpp,Q.mo=t.mp,k=0,A=0,oe=0;let n=v({cosim:g,emsq:E,argpo:Q.argpo,s1:I,s2:L,s3:R,s4:ce,s5:z,sinim:y,ss1:V,ss2:H,ss3:U,ss4:W,ss5:G,sz1:K,sz3:q,sz11:J,sz13:Y,sz21:X,sz23:le,sz31:ue,sz33:de,t:Q.t,tc:fe,gsto:Q.gsto,mo:Q.mo,mdot:Q.mdot,no:Q.no,nodeo:Q.nodeo,nodedot:Q.nodedot,xpidot:_e,z1:ye,z3:be,z11:xe,z13:Se,z21:Ce,z23:we,z31:Te,z33:Ee,ecco:Q.ecco,eccsq:Me,em:T,argpm:k,inclm:j,mm:oe,nm:M,nodem:A,irez:Q.irez,atime:Q.atime,d2201:Q.d2201,d2211:Q.d2211,d3210:Q.d3210,d3222:Q.d3222,d4410:Q.d4410,d4422:Q.d4422,d5220:Q.d5220,d5232:Q.d5232,d5421:Q.d5421,d5433:Q.d5433,dedt:Q.dedt,didt:Q.didt,dmdt:Q.dmdt,dnodt:Q.dnodt,domdt:Q.domdt,del1:Q.del1,del2:Q.del2,del3:Q.del3,xfact:Q.xfact,xlamo:Q.xlamo,xli:Q.xli,xni:Q.xni});Q.irez=n.irez,Q.atime=n.atime,Q.d2201=n.d2201,Q.d2211=n.d2211,Q.d3210=n.d3210,Q.d3222=n.d3222,Q.d4410=n.d4410,Q.d4422=n.d4422,Q.d5220=n.d5220,Q.d5232=n.d5232,Q.d5421=n.d5421,Q.d5433=n.d5433,Q.dedt=n.dedt,Q.didt=n.didt,Q.dmdt=n.dmdt,Q.dnodt=n.dnodt,Q.domdt=n.domdt,Q.del1=n.del1,Q.del2=n.del2,Q.del3=n.del3,Q.xfact=n.xfact,Q.xlamo=n.xlamo,Q.xli=n.xli,Q.xni=n.xni}Q.isimp!==1&&(b=Q.cc1*Q.cc1,Q.d2=4*$*Z*b,pe=Q.d2*Z*Q.cc1/3,Q.d3=(17*$+B)*pe,Q.d4=.5*pe*$*Z*(221*$+31*B)*Q.cc1,Q.t3cof=Q.d2+2*b,Q.t4cof=.25*(3*Q.d3+Q.cc1*(12*Q.d2+10*b)),Q.t5cof=.2*(3*Q.d4+12*Q.cc1*Q.d3+6*Q.d2*Q.d2+15*b*(2*Q.d2+b)))}ae(Q,0),Q.init=`n`}function C(e,t=`i`){let n=e.NORAD_CAT_ID.toString(),r=new Date(e.EPOCH.endsWith(`Z`)?e.EPOCH:`${e.EPOCH}Z`),i=r.getUTCFullYear(),a=Number(i.toString().slice(-2)),o=(r.valueOf()-new Date(Date.UTC(i,0,1,0,0,0)).valueOf())/(86400*1e3)+1,c=Number(e.MEAN_MOTION_DOT),l=Number(e.MEAN_MOTION_DDOT);c/=ee*1440,l/=ee*1440*1440;let u=Number(e.BSTAR),d=Number(e.INCLINATION)*s,f=Number(e.RA_OF_ASC_NODE)*s,p=Number(e.ECCENTRICITY),m=Number(e.ARG_OF_PERICENTER)*s,h=Number(e.MEAN_ANOMALY)*s,ne=Number(e.MEAN_MOTION)/ee,{mon:_,day:v,hr:y,minute:b,sec:re}=te(i,o),ie=g(i,_,v,y,b,re),x={error:0,satnum:n,epochyr:a,epochdays:o,ndot:c,nddot:l,bstar:u,inclo:d,nodeo:f,ecco:p,argpo:m,mo:h,no:ne,jdsatepoch:ie};return S(x,{opsmode:t,satn:x.satnum,epoch:x.jdsatepoch-2433281.5,xbstar:x.bstar,xecco:x.ecco,xargpo:x.argpo,xinclo:x.inclo,xmo:x.mo,xno:x.no,xnodeo:x.nodeo}),x}3*Float64Array.BYTES_PER_ELEMENT;const w=2451545,T=86400,E=[[2441317.5,10],[2441499.5,11],[2441683.5,12],[2442048.5,13],[2442413.5,14],[2442778.5,15],[2443144.5,16],[2443509.5,17],[2443874.5,18],[2444239.5,19],[2444786.5,20],[2445151.5,21],[2445516.5,22],[2446247.5,23],[2447161.5,24],[2447892.5,25],[2448257.5,26],[2448804.5,27],[2449169.5,28],[2449534.5,29],[2450083.5,30],[2450630.5,31],[2451179.5,32],[2453736.5,33],[2454832.5,34],[2456109.5,35],[2457204.5,36],[2457754.5,37]];function D(e){for(let t=E.length-1;t>=0;t--)if(e>=E[t][0])return E[t][1];return E[0][1]-1}function O(e){let t=6.239996+1.99096871e-7*(e-w)*T;return .001657*Math.sin(t+.01671*Math.sin(t))}function k(e){if(!Number.isFinite(e))return e;let t=e+(D(e)+32.184)/T;return t+O(t)/T}const A=Math.PI/180,j=A/3600,oe=1e-4*j,M=[[0,0,0,0,1,-171996,-174.2,92025,8.9],[0,0,2,-2,2,-13187,-1.6,5736,-3.1],[0,0,2,0,2,-2274,-.2,977,-.5],[0,0,0,0,2,2062,.2,-895,.5],[0,1,0,0,0,1426,-3.4,54,-.1],[1,0,0,0,0,712,.1,-7,0],[0,1,2,-2,2,-517,1.2,224,-.6],[0,0,2,0,1,-386,-.4,200,0],[1,0,2,0,2,-301,0,129,-.1],[0,-1,2,-2,2,217,-.5,-95,.3],[1,0,0,-2,0,-158,0,-1,0],[0,0,2,-2,1,129,.1,-70,0],[-1,0,2,0,2,123,0,-53,0],[1,0,0,0,1,63,.1,-33,0],[0,0,0,2,0,63,0,-2,0],[-1,0,2,2,2,-59,0,26,0],[-1,0,0,0,1,-58,-.1,32,0],[1,0,2,0,1,-51,0,27,0]];function N(e,t){let n=Array(9);for(let r=0;r<3;r++)for(let i=0;i<3;i++)n[3*r+i]=e[3*r]*t[i]+e[3*r+1]*t[3+i]+e[3*r+2]*t[6+i];return n}function P(e){let t=Math.cos(e),n=Math.sin(e);return[1,0,0,0,t,n,0,-n,t]}function se(e){let t=Math.cos(e),n=Math.sin(e);return[t,0,-n,0,1,0,n,0,t]}function F(e){let t=Math.cos(e),n=Math.sin(e);return[t,n,0,-n,t,0,0,0,1]}function I(e){let t=(e-w)/36525,n=(2306.2181*t+.30188*t*t+.017998*t**3)*j,r=(2004.3109*t-.42665*t*t-.041833*t**3)*j,a=(2306.2181*t+1.09468*t*t+.018203*t**3)*j,o=134.96298139+477198.8673981*t+.0086972*t*t,s=357.52772333+35999.05034*t-1603e-7*t*t,c=93.27191028+483202.0175381*t-.0036825*t*t,l=297.85036306+445267.11148*t-.0019142*t*t,u=125.04452222-1934.1362608*t+.0020708*t*t,d=0,f=0;for(let[e,n,r,i,a,p,m,ee,te]of M){let h=(e*o+n*s+r*c+i*l+a*u)*A;d+=(p+m*t)*Math.sin(h),f+=(ee+te*t)*Math.cos(h)}d*=oe,f*=oe;let p=(84381.448-46.815*t-59e-5*t*t+.001813*t**3)*j,m=d*Math.cos(p),ee=N(N(N(N(F(n),se(-r)),F(a)),N(N(P(-p),F(d)),P(p+f))),F(-m));return N(P(i*A),ee)}let L=NaN,R=[1,0,0,0,1,0,0,0,1];function ce(e){return Math.abs(e-L)<=.01||(R=I(e),L=e),R}function z(e){return new Date((e-2440587.5)*864e5).toISOString()}function B(e,t){let n=C({OBJECT_NAME:t??String(e.noradCatId),OBJECT_ID:String(e.noradCatId),EPOCH:z(e.epochJd),MEAN_MOTION:e.meanMotion,ECCENTRICITY:e.eccentricity,INCLINATION:e.inclination,RA_OF_ASC_NODE:e.raOfAscNode,ARG_OF_PERICENTER:e.argOfPericenter,MEAN_ANOMALY:e.meanAnomaly,EPHEMERIS_TYPE:0,CLASSIFICATION_TYPE:`U`,NORAD_CAT_ID:e.noradCatId,ELEMENT_SET_NO:e.elementSetNo,REV_AT_EPOCH:e.revAtEpoch,BSTAR:e.bstar,MEAN_MOTION_DOT:e.meanMotionDot,MEAN_MOTION_DDOT:e.meanMotionDdot});return n.error===x.None?n:(console.warn(`buildSatrec: SGP4 init failed for NORAD ${e.noradCatId} (error=${n.error})`),null)}const V=Math.PI/180;Math.cos(i*V),Math.sin(i*V);const H=Math.PI/180,U=Math.cos(i*H),W=Math.sin(i*H),G=10/r;function K(e,t,n,r,i){return!isFinite(Math.fround(n))||!isFinite(Math.fround(r))||!isFinite(Math.fround(i))?!1:(e[t*3]=n,e[t*3+1]=r,e[t*3+2]=i,!0)}function q(r,i,a,o,s,c,l,u,d,f=null,p=0){if(i<r.validityStart||i>r.validityEnd)return 0;let{count:m,kind:ee,equatorial:te,a:h,e:g,i:ne,om:_,w:v,ma:y,n:b,epoch:re,q:ie,tp:S,satrec:C,flags:T,visibleFromDays:E}=r,D=p!==0&&r.applyFlagFilter,O=r.pickBase,A=d.length/3|0,j=i-w,oe=k(i),M=ce(i),N=0;for(let w=0;w<m&&!(N>=A);w++){let m=ee[w];if(m===0||E[w]>j||D&&(T[w]&p)!==p)continue;if(m===3){let e=C[w];if(!e){if(e=B({noradCatId:r.satnum[w],epochJd:re[w],meanMotion:b[w]/360,eccentricity:g[w],inclination:ne[w],raOfAscNode:_[w],argOfPericenter:v[w],meanAnomaly:y[w],bstar:r.bstar[w],meanMotionDot:r.ndot[w],meanMotionDdot:r.nddot[w],elementSetNo:0,revAtEpoch:0}),!e){ee[w]=0;continue}C[w]=e}let t=(i-e.jdsatepoch)*1440,n=ae(e,t);if(!n||e.error!==x.None)continue;let p=n.position.x*G,m=n.position.y*G,te=n.position.z*G,h=M[0]*p+M[1]*m+M[2]*te,ie=M[3]*p+M[4]*m+M[5]*te,S=M[6]*p+M[7]*m+M[8]*te,T=-ie;if(!K(d,N,a+h-c,o+S-l,s+T-u))continue;if(f){let e=O+w,t=N*4;f[t]=e&255,f[t+1]=e>>>8&255,f[t+2]=e>>>16&255,f[t+3]=e>>>24&255}N++;continue}let k,A,P=g[w],se=ne[w],F=_[w],I=v[w];if(m===2){let e=n(ie[w],S[w],te[w]?i:oe);if(!e)continue;k=e.r*Math.cos(e.nu),A=e.r*Math.sin(e.nu)}else{let n=h[w];if(!isFinite(n)||!isFinite(P)||!isFinite(y[w])||!isFinite(b[w]))continue;let r=(te[w]?i:oe)-re[w],a=(y[w]+b[w]*r)*H,o,s;if(P<1||n>0){let t=Math.min(P,.9999999),r=e(a,t),i=Math.sqrt(1-t*t)*Math.sin(r)/(1-t*Math.cos(r)),c=(Math.cos(r)-t)/(1-t*Math.cos(r));o=Math.atan2(i,c),s=n*(1-t*Math.cos(r))}else{let e=t(a,P);if(!isFinite(e))continue;let r=P*Math.cosh(e)-1;if(Math.abs(r)<1e-15)continue;let i=Math.sqrt(P*P-1)*Math.sinh(e)/r,c=(P-Math.cosh(e))/r;o=Math.atan2(i,c),s=n*(1-P*Math.cosh(e))}k=s*Math.cos(o),A=s*Math.sin(o)}if(!isFinite(k)||!isFinite(A))continue;let L=Math.cos(I*H),R=Math.sin(I*H),ce=Math.cos(se*H),z=Math.sin(se*H),V=Math.cos(F*H),q=Math.sin(F*H),J=(V*L-q*R*ce)*k+(-V*R-q*L*ce)*A,Y=(q*L+V*R*ce)*k+(-q*R+V*L*ce)*A,X=R*z*k+L*z*A;if(te[w]){let e=Y*U+X*W,t=-Y*W+X*U;Y=e,X=t}let le=J*10,ue=X*10,de=-Y*10;if(K(d,N,a+le-c,o+ue-l,s+de-u)){if(f){let e=O+w,t=N*4;f[t]=e&255,f[t+1]=e>>>8&255,f[t+2]=e>>>16&255,f[t+3]=e>>>24&255}N++}}return N}const J=new Map;self.onmessage=e=>{let t=e.data;if(t.type===`ping`){self.postMessage({type:`pong`});return}if(t.type===`rewireDelta`){if(t.remove)for(let e of t.remove)J.delete(e);for(let e of t.set)J.set(e.id,e.cols);return}if(t.type===`tick`){let e=[],n=[],[r,i,a]=t.basis;for(let o of t.groups){let s=J.get(o.id);if(!s){e.push({id:o.id,count:0,buf:o.out.buffer,idbuf:o.outIds.buffer}),n.push(o.out.buffer,o.outIds.buffer);continue}let c=q(s,t.jd,o.parent[0],o.parent[1],o.parent[2],r,i,a,o.out,o.outIds,t.requiredFlags??0);e.push({id:o.id,count:c,buf:o.out.buffer,idbuf:o.outIds.buffer}),n.push(o.out.buffer,o.outIds.buffer)}self.postMessage({type:`tickResult`,groups:e},n);return}};";
|
|
20769
21865
|
var blob = typeof self !== "undefined" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", jsContent], { type: "text/javascript;charset=utf-8" });
|
|
20770
21866
|
function WorkerWrapper(options) {
|
|
20771
21867
|
let objURL;
|
|
@@ -22247,8 +23343,8 @@ function between(points, jds, jd, from = 0, to = points.length) {
|
|
|
22247
23343
|
//#endregion
|
|
22248
23344
|
//#region src/lib/math/travel/state.ts
|
|
22249
23345
|
var DEG2RAD$1 = Math.PI / 180;
|
|
22250
|
-
var COS_EPS
|
|
22251
|
-
var SIN_EPS
|
|
23346
|
+
var COS_EPS = Math.cos(EARTH_OBLIQUITY_DEG * DEG2RAD$1);
|
|
23347
|
+
var SIN_EPS = Math.sin(EARTH_OBLIQUITY_DEG * DEG2RAD$1);
|
|
22252
23348
|
function planeRotation(w, i, om, equatorial) {
|
|
22253
23349
|
const cosW = Math.cos(w * DEG2RAD$1);
|
|
22254
23350
|
const sinW = Math.sin(w * DEG2RAD$1);
|
|
@@ -22271,8 +23367,8 @@ function perifocalToEcliptic(px, py, rot) {
|
|
|
22271
23367
|
let y = rot.m21 * px + rot.m22 * py;
|
|
22272
23368
|
let z = rot.m31 * px + rot.m32 * py;
|
|
22273
23369
|
if (rot.equatorial) {
|
|
22274
|
-
const yEcl = y * COS_EPS
|
|
22275
|
-
const zEcl = -y * SIN_EPS
|
|
23370
|
+
const yEcl = y * COS_EPS + z * SIN_EPS;
|
|
23371
|
+
const zEcl = -y * SIN_EPS + z * COS_EPS;
|
|
22276
23372
|
y = yEcl;
|
|
22277
23373
|
z = zEcl;
|
|
22278
23374
|
}
|
|
@@ -22292,11 +23388,12 @@ function eclipticToScene(r) {
|
|
|
22292
23388
|
}
|
|
22293
23389
|
function elementsToState(el, jd, muKm3S2) {
|
|
22294
23390
|
const { a, e, ma, n, epoch, q, tp } = el;
|
|
23391
|
+
const t = elementsJd(el, jd);
|
|
22295
23392
|
const { om, w } = propagateOrbitAngles(el, jd);
|
|
22296
23393
|
const equatorial = el.equatorial ?? false;
|
|
22297
23394
|
if (!isFinite(a) || a === 0 || !isFinite(n) || n <= 0) {
|
|
22298
23395
|
if (q == null || tp == null || !isFinite(q) || !isFinite(tp) || q <= 0) return null;
|
|
22299
|
-
const solved = solveBarker(q, tp,
|
|
23396
|
+
const solved = solveBarker(q, tp, t);
|
|
22300
23397
|
if (!solved) return null;
|
|
22301
23398
|
const mu = muKm3S2 && muKm3S2 > 0 ? muKm3S2 : GM_SUN_KM3_S2;
|
|
22302
23399
|
const rKm = solved.r * AU_KM;
|
|
@@ -22308,7 +23405,7 @@ function elementsToState(el, jd, muKm3S2) {
|
|
|
22308
23405
|
const nRadPerSec = n * DEG2RAD$1 / SEC_PER_DAY$1;
|
|
22309
23406
|
const mu = muKm3S2 && muKm3S2 > 0 ? muKm3S2 : nRadPerSec * nRadPerSec * Math.abs(aKm) * Math.abs(aKm) * Math.abs(aKm);
|
|
22310
23407
|
if (!isFinite(mu) || mu <= 0) return null;
|
|
22311
|
-
const M = (ma + n * (
|
|
23408
|
+
const M = (ma + n * (t - epoch)) * DEG2RAD$1;
|
|
22312
23409
|
let nu;
|
|
22313
23410
|
let rKm;
|
|
22314
23411
|
if (e < 1 || a > 0) {
|
|
@@ -23328,13 +24425,17 @@ function classifyLagrange(geocentric, earthToSun, massRatio = EARTH_SUN_MASS_RAT
|
|
|
23328
24425
|
function existsAt(d, jd) {
|
|
23329
24426
|
return !(d.visibleFromDays !== void 0 && jd - 2451545 < d.visibleFromDays);
|
|
23330
24427
|
}
|
|
24428
|
+
function withinValidity(d, jd) {
|
|
24429
|
+
const t = elementsJd(d, jd);
|
|
24430
|
+
return t >= d.validityStart && t <= d.validityEnd;
|
|
24431
|
+
}
|
|
23331
24432
|
function sitsOnParent(d) {
|
|
23332
24433
|
return d.a === 0 && (d.objectType === ObjectType.BARYCENTER || d.objectType === ObjectType.LAGRANGE_POINT || isMajorBody(d.objectType));
|
|
23333
24434
|
}
|
|
23334
24435
|
function elementsOffset$1(d, jd) {
|
|
23335
24436
|
if (d.pageOnly) return "never";
|
|
23336
24437
|
if (!existsAt(d, jd)) return "not-yet";
|
|
23337
|
-
if (
|
|
24438
|
+
if (!withinValidity(d, jd)) return "no-data";
|
|
23338
24439
|
let offset;
|
|
23339
24440
|
const satrec = d.satrec;
|
|
23340
24441
|
if (satrec) offset = sgp4PositionScene(satrec, jd);
|
|
@@ -23817,11 +24918,82 @@ var PositionDiagnostics = class {
|
|
|
23817
24918
|
}
|
|
23818
24919
|
};
|
|
23819
24920
|
|
|
24921
|
+
//#endregion
|
|
24922
|
+
//#region src/lib/scene/shaders/planetshine-uniforms.ts
|
|
24923
|
+
var _shiners = [];
|
|
24924
|
+
var _albedos = /* @__PURE__ */ new WeakMap();
|
|
24925
|
+
function measuredShinerAlbedo(bo, map) {
|
|
24926
|
+
const { color, geometricAlbedo } = bo.body.data;
|
|
24927
|
+
let entry = _albedos.get(bo);
|
|
24928
|
+
if (!entry || entry.color !== color || entry.geometricAlbedo !== geometricAlbedo || entry.map !== map) {
|
|
24929
|
+
entry = {
|
|
24930
|
+
color,
|
|
24931
|
+
geometricAlbedo,
|
|
24932
|
+
map,
|
|
24933
|
+
albedo: shinerAlbedo(bo.body.data, map, new Color())
|
|
24934
|
+
};
|
|
24935
|
+
_albedos.set(bo, entry);
|
|
24936
|
+
}
|
|
24937
|
+
return entry.albedo;
|
|
24938
|
+
}
|
|
24939
|
+
function shineAlbedo(bo, material, out) {
|
|
24940
|
+
const measured = measuredShinerAlbedo(bo, material.map);
|
|
24941
|
+
if (measured) return out.copy(measured);
|
|
24942
|
+
out.copy(material.color);
|
|
24943
|
+
const mean = material.map && meanMapColor(material.map);
|
|
24944
|
+
return mean ? out.multiply(mean) : out;
|
|
24945
|
+
}
|
|
24946
|
+
function updatePlanetshineUniforms(bodyObjects, occluders, realistic, sunScale) {
|
|
24947
|
+
const sunPos = bodyObjects.get(SUN_ID)?.body.position;
|
|
24948
|
+
let n = 0;
|
|
24949
|
+
if (sunPos) for (const bo of occluders) {
|
|
24950
|
+
if (!bo.mesh) continue;
|
|
24951
|
+
const material = bo.mesh.material;
|
|
24952
|
+
const [x, y, z] = bo.body.position;
|
|
24953
|
+
const sx = sunPos[0] - x;
|
|
24954
|
+
const sy = sunPos[1] - y;
|
|
24955
|
+
const sz = sunPos[2] - z;
|
|
24956
|
+
const sunDist = Math.hypot(sx, sy, sz);
|
|
24957
|
+
const s = _shiners[n++] ??= {
|
|
24958
|
+
x: 0,
|
|
24959
|
+
y: 0,
|
|
24960
|
+
z: 0,
|
|
24961
|
+
radius: 0,
|
|
24962
|
+
sunX: 0,
|
|
24963
|
+
sunY: 0,
|
|
24964
|
+
sunZ: 0,
|
|
24965
|
+
sunlight: 0,
|
|
24966
|
+
albedo: new Color()
|
|
24967
|
+
};
|
|
24968
|
+
s.x = x;
|
|
24969
|
+
s.y = y;
|
|
24970
|
+
s.z = z;
|
|
24971
|
+
s.radius = bo.radiusScene;
|
|
24972
|
+
s.sunX = sx / sunDist;
|
|
24973
|
+
s.sunY = sy / sunDist;
|
|
24974
|
+
s.sunZ = sz / sunDist;
|
|
24975
|
+
s.sunlight = SUN_LIGHT_INTENSITY * sunScale * (realistic ? sunIrradianceFactor(sunDist) : 1);
|
|
24976
|
+
shineAlbedo(bo, material, s.albedo);
|
|
24977
|
+
}
|
|
24978
|
+
for (const bo of bodyObjects.values()) {
|
|
24979
|
+
const shine = bo.planetshine;
|
|
24980
|
+
const at = bo.body.position;
|
|
24981
|
+
if (!shine || !at) continue;
|
|
24982
|
+
if (bo.cachedDist > 0 && bo.radiusScene < bo.cachedDist * 1e-4) continue;
|
|
24983
|
+
selectShiners(shine, at[0], at[1], at[2], _shiners, n);
|
|
24984
|
+
}
|
|
24985
|
+
}
|
|
24986
|
+
|
|
23820
24987
|
//#endregion
|
|
23821
24988
|
//#region src/lib/scene/shaders/ring-uniforms.ts
|
|
23822
24989
|
var SUN_RADIUS_SCENE = kmToScene(695700);
|
|
23823
24990
|
var SHEETS_PER_PX = 2;
|
|
24991
|
+
var SIN_B_STEP = 1e-4;
|
|
24992
|
+
var RING_LIGHT_MIN_PX = 2;
|
|
23824
24993
|
var tmp = new Vector3();
|
|
24994
|
+
var _axis = new Vector3();
|
|
24995
|
+
var _sunLocal = new Vector3();
|
|
24996
|
+
var _inverse = new Quaternion();
|
|
23825
24997
|
function annulusView(camPos, center, poleDir, innerScene, outerScene) {
|
|
23826
24998
|
tmp.subVectors(camPos, center);
|
|
23827
24999
|
const axial = tmp.dot(poleDir);
|
|
@@ -23874,6 +25046,35 @@ function updateRingShaders(bodyObjects, focusTruePos, realistic, overexpose, cam
|
|
|
23874
25046
|
ps.uRingShadowPoleDir.value.copy(psOnRing.uPlanetPoleDir.value);
|
|
23875
25047
|
ps.uRingShadowCenter.value.copy(psOnRing.uPlanetCenter.value);
|
|
23876
25048
|
}
|
|
25049
|
+
updateRingLight(bo, camPos, pxPerRad);
|
|
25050
|
+
}
|
|
25051
|
+
}
|
|
25052
|
+
function updateRingLight(bo, camPos, pxPerRad) {
|
|
25053
|
+
const caster = bo.rings.reduce((best, ring) => ring.intensityScale > best.intensityScale ? ring : best);
|
|
25054
|
+
const uniforms = caster.material.uniforms;
|
|
25055
|
+
const sunDir = uniforms.uSunDir.value;
|
|
25056
|
+
const pole = caster.planetShadowOnRing.uPlanetPoleDir.value;
|
|
25057
|
+
const center = caster.planetShadowOnRing.uPlanetCenter.value;
|
|
25058
|
+
const sinB = Math.min(Math.max(sunDir.dot(pole), -1), 1);
|
|
25059
|
+
const light = caster.light;
|
|
25060
|
+
const seen = caster.outerScene / Math.max(camPos.distanceTo(center), 1e-12) * pxPerRad >= RING_LIGHT_MIN_PX;
|
|
25061
|
+
if (seen && !(Math.abs(sinB - light.patchesSinB) < SIN_B_STEP)) {
|
|
25062
|
+
ringshinePatches(light.patches, light.profile, sinB, light.planet);
|
|
25063
|
+
light.patchesSinB = sinB;
|
|
25064
|
+
}
|
|
25065
|
+
_axis.copy(sunDir).addScaledVector(pole, -sinB);
|
|
25066
|
+
if (_axis.lengthSq() < 1e-12) _axis.set(Math.abs(pole.x) < .9 ? 1 : 0, Math.abs(pole.x) < .9 ? 0 : 1, 0).cross(pole);
|
|
25067
|
+
_axis.normalize();
|
|
25068
|
+
if (caster.ringshine) writeRingshine(caster.ringshine, light, _axis, sinB, uniforms.uLightScale.value);
|
|
25069
|
+
_sunLocal.copy(_axis).applyQuaternion(_inverse.copy(caster.mesh.quaternion).invert());
|
|
25070
|
+
for (const ring of bo.rings) {
|
|
25071
|
+
if (!ring.mesh.visible) continue;
|
|
25072
|
+
if (seen && ring.light.planetLightSinB !== light.patchesSinB) fillPlanetLight(ring.light, light.patchesSinB, light);
|
|
25073
|
+
const ringUniforms = ring.material.uniforms;
|
|
25074
|
+
ringUniforms.uSunAzimuth.value.set(_sunLocal.x, _sunLocal.z).normalize();
|
|
25075
|
+
const albedo = ringUniforms.uPlanetAlbedo.value;
|
|
25076
|
+
if (bo.mesh) shineAlbedo(bo, bo.mesh.material, albedo);
|
|
25077
|
+
else albedo.setRGB(0, 0, 0);
|
|
23877
25078
|
}
|
|
23878
25079
|
}
|
|
23879
25080
|
|
|
@@ -23919,15 +25120,15 @@ function seasonalAtmosphereParams(base, lsDeg) {
|
|
|
23919
25120
|
seasonal: void 0
|
|
23920
25121
|
};
|
|
23921
25122
|
}
|
|
23922
|
-
var cache = /* @__PURE__ */ new WeakMap();
|
|
25123
|
+
var cache$1 = /* @__PURE__ */ new WeakMap();
|
|
23923
25124
|
var LS_QUANTUM_DEG = .25;
|
|
23924
25125
|
function seasonalParamsForJd(base, jd) {
|
|
23925
25126
|
if (!base.seasonal) return base;
|
|
23926
25127
|
const lsQ = Math.round(marsSolarLongitudeDeg(jd) / LS_QUANTUM_DEG);
|
|
23927
|
-
const hit = cache.get(base);
|
|
25128
|
+
const hit = cache$1.get(base);
|
|
23928
25129
|
if (hit && hit.lsQ === lsQ) return hit.params;
|
|
23929
25130
|
const params = seasonalAtmosphereParams(base, lsQ * LS_QUANTUM_DEG);
|
|
23930
|
-
cache.set(base, {
|
|
25131
|
+
cache$1.set(base, {
|
|
23931
25132
|
lsQ,
|
|
23932
25133
|
params
|
|
23933
25134
|
});
|
|
@@ -24073,6 +25274,7 @@ function updateAtmosphereShaders(bodyObjects, cameraPosition, visible, realistic
|
|
|
24073
25274
|
|
|
24074
25275
|
//#endregion
|
|
24075
25276
|
//#region src/lib/scene/shaders/eclipse-uniforms.ts
|
|
25277
|
+
var FOCUS = new Vector3();
|
|
24076
25278
|
function collectOccluders(bodyObjects, out) {
|
|
24077
25279
|
let n = 0;
|
|
24078
25280
|
for (const bo of bodyObjects.values()) {
|
|
@@ -24083,19 +25285,17 @@ function collectOccluders(bodyObjects, out) {
|
|
|
24083
25285
|
out[n++] = bo;
|
|
24084
25286
|
}
|
|
24085
25287
|
out.length = n;
|
|
24086
|
-
if (n > 32) {
|
|
24087
|
-
out.sort((a, b) => b.radiusScene - a.radiusScene);
|
|
24088
|
-
out.length = 32;
|
|
24089
|
-
}
|
|
24090
25288
|
return out;
|
|
24091
25289
|
}
|
|
24092
|
-
function updateEclipseUniforms(bodyObjects, occluders, focusTruePos, air) {
|
|
25290
|
+
function updateEclipseUniforms(bodyObjects, occluders, focusTruePos, cameraDistance, air) {
|
|
24093
25291
|
const eclipse = getEclipseSceneUniforms();
|
|
25292
|
+
const pool = getOccluderPool();
|
|
24094
25293
|
const sunBo = bodyObjects.get(SUN_ID);
|
|
24095
25294
|
const sunPos = sunBo?.body.position;
|
|
24096
25295
|
if (!sunBo || !sunPos) {
|
|
24097
25296
|
eclipse.uSunAngularRadius.value = 0;
|
|
24098
25297
|
eclipse.uOccluderCount.value = 0;
|
|
25298
|
+
pool.count = 0;
|
|
24099
25299
|
return;
|
|
24100
25300
|
}
|
|
24101
25301
|
const [fx, fy, fz] = focusTruePos;
|
|
@@ -24108,17 +25308,20 @@ function updateEclipseUniforms(bodyObjects, occluders, focusTruePos, air) {
|
|
|
24108
25308
|
eclipse.uSunAngularRadius.value = Math.asin(Math.min(sunBo.radiusScene / sunDist, 1));
|
|
24109
25309
|
} else eclipse.uSunAngularRadius.value = 0;
|
|
24110
25310
|
const n = occluders.length;
|
|
24111
|
-
|
|
24112
|
-
|
|
25311
|
+
while (pool.occluders.length < n) {
|
|
25312
|
+
pool.occluders.push(new Vector4());
|
|
25313
|
+
pool.leaks.push(new Vector4());
|
|
25314
|
+
}
|
|
24113
25315
|
for (let i = 0; i < n; i++) {
|
|
24114
25316
|
const bo = occluders[i];
|
|
24115
25317
|
const [bx, by, bz] = bo.body.position;
|
|
24116
|
-
|
|
24117
|
-
if (air && bo.atmosphere) atmosphereLeak(bo.atmosphere.params, bo.atmosphere.planetRadiusKm, leaks[i]);
|
|
24118
|
-
else leaks[i].set(0, 0, 0, 0);
|
|
25318
|
+
pool.occluders[i].set(bx - fx, by - fy, bz - fz, bo.radiusScene);
|
|
25319
|
+
if (air && bo.atmosphere) atmosphereLeak(bo.atmosphere.params, bo.atmosphere.planetRadiusKm, pool.leaks[i]);
|
|
25320
|
+
else pool.leaks[i].set(0, 0, 0, 0);
|
|
24119
25321
|
}
|
|
24120
|
-
|
|
25322
|
+
pool.count = n;
|
|
24121
25323
|
const sunDir = eclipse.uSunDir.value;
|
|
25324
|
+
eclipse.uOccluderCount.value = cullOccludersFor(eclipse.uOccluders.value, FOCUS, cameraDistance, sunDir, eclipse.uOccluderLeak.value);
|
|
24122
25325
|
for (const bo of bodyObjects.values()) {
|
|
24123
25326
|
const self = bo.eclipseShadow;
|
|
24124
25327
|
const at = bo.body.position;
|
|
@@ -24130,52 +25333,6 @@ function updateEclipseUniforms(bodyObjects, occluders, focusTruePos, air) {
|
|
|
24130
25333
|
}
|
|
24131
25334
|
}
|
|
24132
25335
|
|
|
24133
|
-
//#endregion
|
|
24134
|
-
//#region src/lib/scene/shaders/planetshine-uniforms.ts
|
|
24135
|
-
var _shiners = Array.from({ length: 32 }, () => ({
|
|
24136
|
-
x: 0,
|
|
24137
|
-
y: 0,
|
|
24138
|
-
z: 0,
|
|
24139
|
-
radius: 0,
|
|
24140
|
-
sunX: 0,
|
|
24141
|
-
sunY: 0,
|
|
24142
|
-
sunZ: 0,
|
|
24143
|
-
sunlight: 0,
|
|
24144
|
-
albedo: new Color()
|
|
24145
|
-
}));
|
|
24146
|
-
function updatePlanetshineUniforms(bodyObjects, occluders, realistic, sunScale) {
|
|
24147
|
-
const sunPos = bodyObjects.get(SUN_ID)?.body.position;
|
|
24148
|
-
let n = 0;
|
|
24149
|
-
if (sunPos) for (const bo of occluders) {
|
|
24150
|
-
if (!bo.mesh) continue;
|
|
24151
|
-
const material = bo.mesh.material;
|
|
24152
|
-
const [x, y, z] = bo.body.position;
|
|
24153
|
-
const sx = sunPos[0] - x;
|
|
24154
|
-
const sy = sunPos[1] - y;
|
|
24155
|
-
const sz = sunPos[2] - z;
|
|
24156
|
-
const sunDist = Math.hypot(sx, sy, sz);
|
|
24157
|
-
const s = _shiners[n++];
|
|
24158
|
-
s.x = x;
|
|
24159
|
-
s.y = y;
|
|
24160
|
-
s.z = z;
|
|
24161
|
-
s.radius = bo.radiusScene;
|
|
24162
|
-
s.sunX = sx / sunDist;
|
|
24163
|
-
s.sunY = sy / sunDist;
|
|
24164
|
-
s.sunZ = sz / sunDist;
|
|
24165
|
-
s.sunlight = SUN_LIGHT_INTENSITY * sunScale * (realistic ? sunIrradianceFactor(sunDist) : 1);
|
|
24166
|
-
s.albedo.copy(material.color);
|
|
24167
|
-
const mean = material.map && meanMapColor(material.map);
|
|
24168
|
-
if (mean) s.albedo.multiply(mean);
|
|
24169
|
-
}
|
|
24170
|
-
for (const bo of bodyObjects.values()) {
|
|
24171
|
-
const shine = bo.planetshine;
|
|
24172
|
-
const at = bo.body.position;
|
|
24173
|
-
if (!shine || !at) continue;
|
|
24174
|
-
if (bo.cachedDist > 0 && bo.radiusScene < bo.cachedDist * 1e-4) continue;
|
|
24175
|
-
selectShiners(shine, at[0], at[1], at[2], _shiners, n);
|
|
24176
|
-
}
|
|
24177
|
-
}
|
|
24178
|
-
|
|
24179
25336
|
//#endregion
|
|
24180
25337
|
//#region src/lib/scene/shaders/sun-shadow-light.ts
|
|
24181
25338
|
var LIGHT_DIST = 10;
|
|
@@ -24702,7 +25859,9 @@ function updateTextureLOD(bodyObjects, camera, renderer, ctx, textureLoader, foc
|
|
|
24702
25859
|
updateTileOverlay(bo, camera, renderer, devicePx, settings.showSurfaceTexture && !bo.appearance?.surfaceOwned, invalidate);
|
|
24703
25860
|
updateReliefTiles(bo, camera, renderer, devicePx, invalidate);
|
|
24704
25861
|
const dispTiers = bo.displacementMeta?.tiers;
|
|
24705
|
-
if (bo.displacementMap &&
|
|
25862
|
+
if (bo.displacementMap && !bo.displacementLoading && pyramidHeightsServe(bo, renderer)) {
|
|
25863
|
+
if (bo.displacementTier !== "pyramid") swapDisplacementTier(bo, PYRAMID_TIER);
|
|
25864
|
+
} else if (bo.displacementMap && dispTiers?.length && !bo.displacementLoading) {
|
|
24706
25865
|
const maxTex = renderer.capabilities.maxTextureSize;
|
|
24707
25866
|
const capRank = maxTex >= 16383 && !reliefTilesServe(bo) ? 2 : maxTex >= 8192 ? 1 : 0;
|
|
24708
25867
|
const current = bo.displacementTier ?? "low";
|
|
@@ -25025,7 +26184,7 @@ function computeGroupMode(count) {
|
|
|
25025
26184
|
return "none";
|
|
25026
26185
|
}
|
|
25027
26186
|
function isCurrentlyValid(body, jd) {
|
|
25028
|
-
return body.data
|
|
26187
|
+
return withinValidity(body.data, jd);
|
|
25029
26188
|
}
|
|
25030
26189
|
var PromotionRegistry = class {
|
|
25031
26190
|
pendingDefaults = /* @__PURE__ */ new Set();
|
|
@@ -25204,7 +26363,8 @@ var PromotionRegistry = class {
|
|
|
25204
26363
|
let n = 0;
|
|
25205
26364
|
for (const body of bucket.values()) {
|
|
25206
26365
|
if (this.groupTargets && !this.groupTargets.has(body.data.id)) continue;
|
|
25207
|
-
const
|
|
26366
|
+
const validityStart = clockJd(body.data, body.data.validityStart);
|
|
26367
|
+
const validityEnd = clockJd(body.data, body.data.validityEnd);
|
|
25208
26368
|
if (validityStart <= jd) {
|
|
25209
26369
|
if (validityStart > this.countStableLo) this.countStableLo = validityStart;
|
|
25210
26370
|
} else if (validityStart < this.countStableHi) this.countStableHi = validityStart;
|
|
@@ -25744,19 +26904,45 @@ var ExtensionRegistry = class {
|
|
|
25744
26904
|
|
|
25745
26905
|
//#endregion
|
|
25746
26906
|
//#region src/lib/scene/extensions/anchor.ts
|
|
25747
|
-
var RAD$
|
|
26907
|
+
var RAD$3 = Math.PI / 180;
|
|
25748
26908
|
function isSurface(anchor) {
|
|
25749
26909
|
return "latitude" in anchor;
|
|
25750
26910
|
}
|
|
25751
|
-
function surfaceDirection(latitude, longitude) {
|
|
25752
|
-
const lat = latitude * RAD$
|
|
25753
|
-
const lon = longitude * RAD$
|
|
25754
|
-
|
|
26911
|
+
function surfaceDirection(latitude, longitude, radii) {
|
|
26912
|
+
const lat = latitude * RAD$3;
|
|
26913
|
+
const lon = longitude * RAD$3;
|
|
26914
|
+
const out = [
|
|
25755
26915
|
Math.cos(lat) * Math.cos(lon),
|
|
25756
26916
|
Math.sin(lat),
|
|
25757
26917
|
-Math.cos(lat) * Math.sin(lon)
|
|
25758
26918
|
];
|
|
26919
|
+
if (radii) onEllipsoid(radii, out, 0, out, 0);
|
|
26920
|
+
return out;
|
|
25759
26921
|
}
|
|
26922
|
+
function onEllipsoid(radii, from, at, out, to) {
|
|
26923
|
+
const x = from[at] * radii.a;
|
|
26924
|
+
const y = from[at + 1] * radii.c;
|
|
26925
|
+
const z = from[at + 2] * radii.b;
|
|
26926
|
+
const n = Math.hypot(x, y, z);
|
|
26927
|
+
out[to] = x / n;
|
|
26928
|
+
out[to + 1] = y / n;
|
|
26929
|
+
out[to + 2] = z / n;
|
|
26930
|
+
}
|
|
26931
|
+
var GroundDirections = class {
|
|
26932
|
+
source = null;
|
|
26933
|
+
radii;
|
|
26934
|
+
out = new Float64Array(0);
|
|
26935
|
+
of(dirs, radii) {
|
|
26936
|
+
if (!radii) return dirs;
|
|
26937
|
+
if (dirs !== this.source || radii !== this.radii) {
|
|
26938
|
+
if (this.out.length !== dirs.length) this.out = new Float64Array(dirs.length);
|
|
26939
|
+
for (let i = 0; i < dirs.length; i += 3) onEllipsoid(radii, dirs, i, this.out, i);
|
|
26940
|
+
this.source = dirs;
|
|
26941
|
+
this.radii = radii;
|
|
26942
|
+
}
|
|
26943
|
+
return this.out;
|
|
26944
|
+
}
|
|
26945
|
+
};
|
|
25760
26946
|
function rotateByQuaternion(q, x, y, z, out, at) {
|
|
25761
26947
|
const tx = 2 * (q.y * z - q.z * y);
|
|
25762
26948
|
const ty = 2 * (q.z * x - q.x * z);
|
|
@@ -25772,7 +26958,7 @@ function placeAnchor(anchor, body, centre, jd) {
|
|
|
25772
26958
|
const [cx, cy, cz] = centre;
|
|
25773
26959
|
if (isSurface(anchor)) {
|
|
25774
26960
|
const distance = kmToScene(effectiveRadiusKm(body.data) + (anchor.altitudeKm ?? 0));
|
|
25775
|
-
const [dx, dy, dz] = surfaceDirection(anchor.latitude, anchor.longitude);
|
|
26961
|
+
const [dx, dy, dz] = surfaceDirection(anchor.latitude, anchor.longitude, body.drawnRadii);
|
|
25776
26962
|
const q = body.orientation ? bodyQuaternion(body.orientation, jd, body.nutPrec) : null;
|
|
25777
26963
|
if (!q) return [
|
|
25778
26964
|
cx + dx * distance,
|
|
@@ -25860,9 +27046,13 @@ function resolvePose(pose, ctx, jd) {
|
|
|
25860
27046
|
//#region src/lib/scene/camera/motion-scale.ts
|
|
25861
27047
|
var MIN_TRANSLATE_SCALE = .02;
|
|
25862
27048
|
var MIN_ROTATE_SCALE = 1e-4;
|
|
27049
|
+
var DAMPING_FRAME_MS = 1e3 / 60;
|
|
25863
27050
|
function orbitDamping(reducedMotion) {
|
|
25864
27051
|
return reducedMotion ? .4 : .05;
|
|
25865
27052
|
}
|
|
27053
|
+
function frameDamping(factor, frameDtMs) {
|
|
27054
|
+
return 1 - (1 - factor) ** (frameDtMs / DAMPING_FRAME_MS);
|
|
27055
|
+
}
|
|
25866
27056
|
function cameraMotionScale(camera, focusTruePos, focused, parent, seated) {
|
|
25867
27057
|
const orbitRadius = camera.position.length();
|
|
25868
27058
|
if (!(orbitRadius > 0)) return {
|
|
@@ -25892,10 +27082,10 @@ function clamp$1(value, min) {
|
|
|
25892
27082
|
|
|
25893
27083
|
//#endregion
|
|
25894
27084
|
//#region src/lib/scene/user-location/marker.ts
|
|
25895
|
-
var RAD$
|
|
27085
|
+
var RAD$2 = Math.PI / 180;
|
|
25896
27086
|
function bodyLocalUnitVector(latitude, longitude) {
|
|
25897
|
-
const latR = latitude * RAD$
|
|
25898
|
-
const lonR = longitude * RAD$
|
|
27087
|
+
const latR = latitude * RAD$2;
|
|
27088
|
+
const lonR = longitude * RAD$2;
|
|
25899
27089
|
return [
|
|
25900
27090
|
Math.cos(latR) * Math.cos(lonR),
|
|
25901
27091
|
Math.sin(latR),
|
|
@@ -26088,6 +27278,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
26088
27278
|
firstFrame = true;
|
|
26089
27279
|
pendingUrlWrite = false;
|
|
26090
27280
|
lastTickMs = 0;
|
|
27281
|
+
orbitDampingFactor;
|
|
26091
27282
|
static FPS_SAMPLE_FRAMES = 30;
|
|
26092
27283
|
fpsSamples = [];
|
|
26093
27284
|
fpsSampleHead = 0;
|
|
@@ -26182,7 +27373,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
26182
27373
|
this.pointClouds.setPointBudget(this.tier.pointBudget);
|
|
26183
27374
|
this.controls = new OrbitControls(this.camera, canvas);
|
|
26184
27375
|
this.controls.enableDamping = true;
|
|
26185
|
-
this.
|
|
27376
|
+
this.orbitDampingFactor = orbitDamping(sceneSettings().resolvedReducedMotion);
|
|
26186
27377
|
this.controls.minDistance = focusBody ? minCameraDistance(focusBody) : kmToScene(.01);
|
|
26187
27378
|
this.controls.maxDistance = 31620.5 * 10;
|
|
26188
27379
|
this.controls.target.set(0, 0, 0);
|
|
@@ -26473,6 +27664,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
26473
27664
|
const nowMs = performance.now();
|
|
26474
27665
|
const frameDtMs = this.lastTickMs ? nowMs - this.lastTickMs : 0;
|
|
26475
27666
|
this.lastTickMs = nowMs;
|
|
27667
|
+
this.controls.dampingFactor = frameDamping(this.orbitDampingFactor, frameDtMs || 16.666666666666668);
|
|
26476
27668
|
if (!this.holdingCamera) this.cameraUp.update(this.sceneJd);
|
|
26477
27669
|
if (this.firstFrame) {
|
|
26478
27670
|
this.firstFrame = false;
|
|
@@ -26540,7 +27732,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
26540
27732
|
refreshDeferredTrails(this.bodyObjects, this.focus, this.lastUpdatedJd, this.trailView());
|
|
26541
27733
|
updateRingShaders(this.bodyObjects, this.focus.focusTruePos, sceneSettings().realisticLighting, sceneSettings().overexposeRings, this.camera.position, this.pxPerRad());
|
|
26542
27734
|
const occluders = collectOccluders(this.bodyObjects, this._occluders);
|
|
26543
|
-
updateEclipseUniforms(this.bodyObjects, occluders, this.focus.focusTruePos, sceneSettings().showAtmospheres);
|
|
27735
|
+
updateEclipseUniforms(this.bodyObjects, occluders, this.focus.focusTruePos, this.camera.position.length(), sceneSettings().showAtmospheres);
|
|
26544
27736
|
updatePlanetshineUniforms(this.bodyObjects, occluders, sceneSettings().realisticLighting, this.sunIntensityScale);
|
|
26545
27737
|
occluders.length = 0;
|
|
26546
27738
|
const atmoState = updateAtmosphereShaders(this.bodyObjects, this.camera.position, sceneSettings().showAtmospheres, sceneSettings().realisticLighting, this.sunIntensityScale, currentAtmosphereConfig(), this.sceneJd);
|
|
@@ -26685,7 +27877,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
26685
27877
|
surfaceRadialKm(bodyId, latitude, longitude) {
|
|
26686
27878
|
const body = this.ctx.getBody(bodyId);
|
|
26687
27879
|
if (!body) return null;
|
|
26688
|
-
const dir =
|
|
27880
|
+
const dir = surfaceDirection(latitude, longitude, body.drawnRadii);
|
|
26689
27881
|
return renderedSurfaceRadialKm(this.bodyObjects.get(bodyId), bodyId, effectiveRadiusKm(body.data), dir);
|
|
26690
27882
|
}
|
|
26691
27883
|
surfaceClamp(body, seated) {
|
|
@@ -27164,7 +28356,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27164
28356
|
}
|
|
27165
28357
|
}
|
|
27166
28358
|
setReducedMotion(on) {
|
|
27167
|
-
this.
|
|
28359
|
+
this.orbitDampingFactor = orbitDamping(on);
|
|
27168
28360
|
}
|
|
27169
28361
|
focusOnBody(id, zoom, latitude, longitude) {
|
|
27170
28362
|
this.disarmLimits();
|
|
@@ -28589,7 +29781,7 @@ var IconExtension = class extends MarkerExtension {
|
|
|
28589
29781
|
//#endregion
|
|
28590
29782
|
//#region src/lib/flatmap/projection.ts
|
|
28591
29783
|
var DEG$6 = Math.PI / 180;
|
|
28592
|
-
var RAD$
|
|
29784
|
+
var RAD$1 = 180 / Math.PI;
|
|
28593
29785
|
function wrapLon(lon) {
|
|
28594
29786
|
if (lon >= -180 && lon < 180) return lon;
|
|
28595
29787
|
return ((lon + 180) % 360 + 360) % 360 - 180;
|
|
@@ -28636,8 +29828,8 @@ function equirectangular(options) {
|
|
|
28636
29828
|
const rowInverse = (y) => {
|
|
28637
29829
|
if (Math.abs(y) > Math.PI / 2) return null;
|
|
28638
29830
|
return {
|
|
28639
|
-
lat: y * RAD$
|
|
28640
|
-
lonPerX: RAD$
|
|
29831
|
+
lat: y * RAD$1,
|
|
29832
|
+
lonPerX: RAD$1,
|
|
28641
29833
|
maxAbsX: Math.PI
|
|
28642
29834
|
};
|
|
28643
29835
|
};
|
|
@@ -28685,9 +29877,9 @@ function equalEarth(options) {
|
|
|
28685
29877
|
const theta = thetaFor(y);
|
|
28686
29878
|
const sinLat = 2 / EE_SQRT3 * Math.sin(theta);
|
|
28687
29879
|
if (Math.abs(sinLat) > 1) return null;
|
|
28688
|
-
const lonPerX = 3 * eeDy(theta) / (2 * EE_SQRT3 * Math.cos(theta)) * RAD$
|
|
29880
|
+
const lonPerX = 3 * eeDy(theta) / (2 * EE_SQRT3 * Math.cos(theta)) * RAD$1;
|
|
28689
29881
|
return {
|
|
28690
|
-
lat: Math.asin(sinLat) * RAD$
|
|
29882
|
+
lat: Math.asin(sinLat) * RAD$1,
|
|
28691
29883
|
lonPerX,
|
|
28692
29884
|
maxAbsX: 180 / lonPerX
|
|
28693
29885
|
};
|
|
@@ -28719,9 +29911,9 @@ function mollweide(options) {
|
|
|
28719
29911
|
lonPerX: 0,
|
|
28720
29912
|
maxAbsX: 0
|
|
28721
29913
|
};
|
|
28722
|
-
const lonPerX = Math.PI / (2 * MW_SQRT2 * cosTheta) * RAD$
|
|
29914
|
+
const lonPerX = Math.PI / (2 * MW_SQRT2 * cosTheta) * RAD$1;
|
|
28723
29915
|
return {
|
|
28724
|
-
lat: Math.asin(sinLat) * RAD$
|
|
29916
|
+
lat: Math.asin(sinLat) * RAD$1,
|
|
28725
29917
|
lonPerX,
|
|
28726
29918
|
maxAbsX: 180 / lonPerX
|
|
28727
29919
|
};
|
|
@@ -28768,8 +29960,8 @@ function sinusoidal(options) {
|
|
|
28768
29960
|
maxAbsX: 0
|
|
28769
29961
|
};
|
|
28770
29962
|
return {
|
|
28771
|
-
lat: y * RAD$
|
|
28772
|
-
lonPerX: RAD$
|
|
29963
|
+
lat: y * RAD$1,
|
|
29964
|
+
lonPerX: RAD$1 / cosLat,
|
|
28773
29965
|
maxAbsX: Math.PI * cosLat
|
|
28774
29966
|
};
|
|
28775
29967
|
};
|
|
@@ -28920,7 +30112,7 @@ function clamp1(v) {
|
|
|
28920
30112
|
}
|
|
28921
30113
|
function azimuthalInverse(x, y, cosC, k, lon0, sinPhi0, cosPhi0) {
|
|
28922
30114
|
const lat = Math.asin(clamp1(cosC * sinPhi0 + y * k * cosPhi0));
|
|
28923
|
-
return [wrapLon(lon0 + Math.atan2(x * k, cosC * cosPhi0 - y * k * sinPhi0) * RAD$
|
|
30115
|
+
return [wrapLon(lon0 + Math.atan2(x * k, cosC * cosPhi0 - y * k * sinPhi0) * RAD$1), lat * RAD$1];
|
|
28924
30116
|
}
|
|
28925
30117
|
function discExtent(r) {
|
|
28926
30118
|
return {
|
|
@@ -29017,7 +30209,7 @@ function createProjection(id, options = {}) {
|
|
|
29017
30209
|
var DEG$5 = Math.PI / 180;
|
|
29018
30210
|
var TAU = 2 * Math.PI;
|
|
29019
30211
|
var RIM_STEP = 2 * DEG$5;
|
|
29020
|
-
var RAD
|
|
30212
|
+
var RAD = 180 / Math.PI;
|
|
29021
30213
|
var MAX_STEPS = 512;
|
|
29022
30214
|
var DEFAULT_STEP_DEG = 2;
|
|
29023
30215
|
function angularDistance(a, b) {
|
|
@@ -29026,7 +30218,7 @@ function angularDistance(a, b) {
|
|
|
29026
30218
|
const dφ = φ2 - φ1;
|
|
29027
30219
|
const dλ = wrapLon(b.lon - a.lon) * DEG$5;
|
|
29028
30220
|
const h = Math.sin(dφ / 2) ** 2 + Math.cos(φ1) * Math.cos(φ2) * Math.sin(dλ / 2) ** 2;
|
|
29029
|
-
return 2 * Math.asin(Math.min(1, Math.sqrt(h))) * RAD
|
|
30221
|
+
return 2 * Math.asin(Math.min(1, Math.sqrt(h))) * RAD;
|
|
29030
30222
|
}
|
|
29031
30223
|
function slerp(a, b, t) {
|
|
29032
30224
|
const d = angularDistance(a, b) * DEG$5;
|
|
@@ -29042,8 +30234,8 @@ function slerp(a, b, t) {
|
|
|
29042
30234
|
const y = ka * Math.cos(φ1) * Math.sin(λ1) + kb * Math.cos(φ2) * Math.sin(λ2);
|
|
29043
30235
|
const z = ka * Math.sin(φ1) + kb * Math.sin(φ2);
|
|
29044
30236
|
return {
|
|
29045
|
-
lon: Math.atan2(y, x) * RAD
|
|
29046
|
-
lat: Math.atan2(z, Math.hypot(x, y)) * RAD
|
|
30237
|
+
lon: Math.atan2(y, x) * RAD,
|
|
30238
|
+
lat: Math.atan2(z, Math.hypot(x, y)) * RAD
|
|
29047
30239
|
};
|
|
29048
30240
|
}
|
|
29049
30241
|
function lerp(a, b, t) {
|
|
@@ -29346,8 +30538,8 @@ function smallCircle(center, radiusDeg, steps = 128) {
|
|
|
29346
30538
|
const y = c[1] * cosR + e[1] * a + n[1] * b;
|
|
29347
30539
|
const z = c[2] * cosR + e[2] * a + n[2] * b;
|
|
29348
30540
|
ring.push({
|
|
29349
|
-
lon: wrapLon(Math.atan2(y, x) * RAD
|
|
29350
|
-
lat: Math.atan2(z, Math.hypot(x, y)) * RAD
|
|
30541
|
+
lon: wrapLon(Math.atan2(y, x) * RAD),
|
|
30542
|
+
lat: Math.atan2(z, Math.hypot(x, y)) * RAD
|
|
29351
30543
|
});
|
|
29352
30544
|
}
|
|
29353
30545
|
return ring;
|
|
@@ -29400,6 +30592,8 @@ var SurfaceShapeExtension = class {
|
|
|
29400
30592
|
alphas = new Float32Array(0);
|
|
29401
30593
|
lengths = new Float32Array(0);
|
|
29402
30594
|
fanDirs = new Float64Array(0);
|
|
30595
|
+
groundDirs = new GroundDirections();
|
|
30596
|
+
groundFanDirs = new GroundDirections();
|
|
29403
30597
|
fill = null;
|
|
29404
30598
|
fillScratch = new Float32Array(0);
|
|
29405
30599
|
turned = [
|
|
@@ -29466,7 +30660,8 @@ var SurfaceShapeExtension = class {
|
|
|
29466
30660
|
centre[2] - basis[2]
|
|
29467
30661
|
];
|
|
29468
30662
|
if (this.line) {
|
|
29469
|
-
this.
|
|
30663
|
+
const dirs = this.groundDirs.of(this.dirs, body.drawnRadii);
|
|
30664
|
+
this.place(dirs, this.count, q, scale, origin, this.scratch);
|
|
29470
30665
|
writeFatTrailVertices(this.line.geometry, this.scratch, this.alphas, this.alphas, this.count);
|
|
29471
30666
|
if (this.dash) {
|
|
29472
30667
|
screenLengths(this.scratch, this.count, camera, viewportPx, this.lengths);
|
|
@@ -29476,7 +30671,8 @@ var SurfaceShapeExtension = class {
|
|
|
29476
30671
|
}
|
|
29477
30672
|
if (this.fill) {
|
|
29478
30673
|
const position = this.fill.geometry.getAttribute("position");
|
|
29479
|
-
this.
|
|
30674
|
+
const fanDirs = this.groundFanDirs.of(this.fanDirs, body.drawnRadii);
|
|
30675
|
+
this.place(fanDirs, this.fillScratch.length / 3, q, scale, origin, this.fillScratch);
|
|
29480
30676
|
position.needsUpdate = true;
|
|
29481
30677
|
this.fill.material.uniforms.uCenterOffset.value.copy(camera.position).negate();
|
|
29482
30678
|
}
|
|
@@ -31777,7 +32973,7 @@ async function acquireBitmap(url, decodeWidth) {
|
|
|
31777
32973
|
};
|
|
31778
32974
|
let work = pending.get(key);
|
|
31779
32975
|
if (!work) {
|
|
31780
|
-
work = decode(url, decodeWidth);
|
|
32976
|
+
work = decode$1(url, decodeWidth);
|
|
31781
32977
|
pending.set(key, work);
|
|
31782
32978
|
const done = () => pending.delete(key);
|
|
31783
32979
|
work.then(done, done);
|
|
@@ -31789,7 +32985,7 @@ async function acquireBitmap(url, decodeWidth) {
|
|
|
31789
32985
|
bitmap: bitmaps.put(key, bitmap, bitmapBytes(bitmap.width, bitmap.height))
|
|
31790
32986
|
};
|
|
31791
32987
|
}
|
|
31792
|
-
async function decode(url, decodeWidth) {
|
|
32988
|
+
async function decode$1(url, decodeWidth) {
|
|
31793
32989
|
const response = await fetch(url);
|
|
31794
32990
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
31795
32991
|
const blob = await response.blob();
|
|
@@ -33083,17 +34279,25 @@ function findPanorama(entries, at) {
|
|
|
33083
34279
|
if (!at) return null;
|
|
33084
34280
|
return entries.find((e) => panoramaAt(e) === at || legacyAt(e) === at) ?? null;
|
|
33085
34281
|
}
|
|
34282
|
+
var MIN_STEP_M = 1;
|
|
33086
34283
|
function neighboursOf(entries, current, radiusKm) {
|
|
33087
34284
|
const i = entries.findIndex((e) => e.id === current.id);
|
|
33088
|
-
const
|
|
33089
|
-
|
|
33090
|
-
|
|
33091
|
-
|
|
33092
|
-
|
|
33093
|
-
|
|
34285
|
+
const nearest = (step) => {
|
|
34286
|
+
for (let j = i + step; j >= 0 && j < entries.length; j += step) {
|
|
34287
|
+
const e = entries[j];
|
|
34288
|
+
if (e.mission !== current.mission) return null;
|
|
34289
|
+
const distanceM = groundDistanceM(current, e, radiusKm);
|
|
34290
|
+
if (distanceM >= MIN_STEP_M) return {
|
|
34291
|
+
entry: e,
|
|
34292
|
+
distanceM,
|
|
34293
|
+
bearingDeg: bearingDeg(current, e)
|
|
34294
|
+
};
|
|
34295
|
+
}
|
|
34296
|
+
return null;
|
|
34297
|
+
};
|
|
33094
34298
|
return {
|
|
33095
|
-
previous:
|
|
33096
|
-
next:
|
|
34299
|
+
previous: nearest(-1),
|
|
34300
|
+
next: nearest(1)
|
|
33097
34301
|
};
|
|
33098
34302
|
}
|
|
33099
34303
|
var DEG$1 = Math.PI / 180;
|
|
@@ -33121,7 +34325,6 @@ var ARROW_DISTANCE = 9;
|
|
|
33121
34325
|
var CLICK_SLOP_PX = 6;
|
|
33122
34326
|
var ANGLE_STEP_DEG = 10;
|
|
33123
34327
|
var ANGLE_SAMPLE_STEP_DEG = 1;
|
|
33124
|
-
var MIN_ARROW_DISTANCE_M = 1;
|
|
33125
34328
|
var GYRO_TILT = new Quaternion(-Math.SQRT1_2, 0, 0, Math.SQRT1_2);
|
|
33126
34329
|
var SCREEN_AXIS = new Vector3(0, 0, 1);
|
|
33127
34330
|
function wrapHeading(deg) {
|
|
@@ -33340,7 +34543,7 @@ var PanoramaView = class {
|
|
|
33340
34543
|
this.setArrowTargets(this.neighbours && hasHeading(entry) ? ["previous", "next"].map((key) => ({
|
|
33341
34544
|
key,
|
|
33342
34545
|
n: this.neighbours?.[key] ?? null
|
|
33343
|
-
})).filter((a) => a.n
|
|
34546
|
+
})).filter((a) => a.n).map((a) => ({
|
|
33344
34547
|
key: a.key,
|
|
33345
34548
|
bearingDeg: a.n.bearingDeg
|
|
33346
34549
|
})) : []);
|
|
@@ -33738,6 +34941,106 @@ var fetchPlanetarySystemsMap = memoizedGzJson(() => `${dataBase()}/v1/groups/__p
|
|
|
33738
34941
|
//#region src/lib/fetch/groups/solar-system-map.ts
|
|
33739
34942
|
var fetchSolarSystemMap = memoizedGzJson(() => `${dataBase()}/v1/groups/__solar_system_map__.json.gz`, { error: (res) => `Failed to fetch solar system map: ${res.status}` });
|
|
33740
34943
|
|
|
34944
|
+
//#endregion
|
|
34945
|
+
//#region src/lib/rings/strip.ts
|
|
34946
|
+
var cache = /* @__PURE__ */ new Map();
|
|
34947
|
+
function luminance(r, g, b) {
|
|
34948
|
+
return .2126 * r + .7152 * g + .0722 * b;
|
|
34949
|
+
}
|
|
34950
|
+
async function decode(bodyId, meta) {
|
|
34951
|
+
const rows = meta.strip_rows;
|
|
34952
|
+
if (rows.transparency === void 0 || rows.color === void 0) {
|
|
34953
|
+
console.warn(`Ring strip ${bodyId}/${meta.strip} has no transparency or color row, no profile drawn:`, rows);
|
|
34954
|
+
return null;
|
|
34955
|
+
}
|
|
34956
|
+
const response = await fetch(versionedUrl(`/v1/rings/${bodyId}/${meta.strip}`, "rings"));
|
|
34957
|
+
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
|
|
34958
|
+
const bitmap = await createImageBitmap(await response.blob());
|
|
34959
|
+
const canvas = document.createElement("canvas");
|
|
34960
|
+
canvas.width = bitmap.width;
|
|
34961
|
+
canvas.height = bitmap.height;
|
|
34962
|
+
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
34963
|
+
if (!ctx) {
|
|
34964
|
+
console.warn(`Ring strip ${bodyId}/${meta.strip}: no 2D context, no profile drawn`);
|
|
34965
|
+
return null;
|
|
34966
|
+
}
|
|
34967
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
34968
|
+
const n = bitmap.width;
|
|
34969
|
+
const pixels = ctx.getImageData(0, 0, n, bitmap.height).data;
|
|
34970
|
+
bitmap.close();
|
|
34971
|
+
const scale = meta.intensity_scale || 1;
|
|
34972
|
+
const tau = new Float32Array(n);
|
|
34973
|
+
const rgb = new Uint8ClampedArray(n * 3);
|
|
34974
|
+
const back = rows.backscattered ?? rows.color;
|
|
34975
|
+
const brightness = new Float32Array(n);
|
|
34976
|
+
let peak = 0;
|
|
34977
|
+
for (let i = 0; i < n; i++) {
|
|
34978
|
+
const t = (rows.transparency * n + i) * 4;
|
|
34979
|
+
const b = (back * n + i) * 4;
|
|
34980
|
+
const opacity = Math.min(1, (1 - pixels[t] / 255) * scale);
|
|
34981
|
+
tau[i] = opacity >= 1 ? Infinity : -Math.log(1 - opacity);
|
|
34982
|
+
brightness[i] = luminance(pixels[b], pixels[b + 1], pixels[b + 2]) / 255;
|
|
34983
|
+
if (brightness[i] > peak) peak = brightness[i];
|
|
34984
|
+
}
|
|
34985
|
+
const FLOOR = .35;
|
|
34986
|
+
for (let i = 0; i < n; i++) {
|
|
34987
|
+
const c = (rows.color * n + i) * 4;
|
|
34988
|
+
const lit = peak > 0 ? FLOOR + (1 - FLOOR) * (brightness[i] / peak) : 1;
|
|
34989
|
+
rgb[i * 3] = pixels[c] * lit;
|
|
34990
|
+
rgb[i * 3 + 1] = pixels[c + 1] * lit;
|
|
34991
|
+
rgb[i * 3 + 2] = pixels[c + 2] * lit;
|
|
34992
|
+
}
|
|
34993
|
+
return {
|
|
34994
|
+
inner: meta.inner_radius_km,
|
|
34995
|
+
outer: meta.outer_radius_km,
|
|
34996
|
+
tau,
|
|
34997
|
+
rgb
|
|
34998
|
+
};
|
|
34999
|
+
}
|
|
35000
|
+
async function load(bodyId) {
|
|
35001
|
+
const bundles = (await fetchObjectDetail(bodyId, false)).global?.rings ?? [];
|
|
35002
|
+
if (!bundles.length) console.warn(`Ring strips for ${bodyId}: no ring bundles on the object`);
|
|
35003
|
+
const profiles = [];
|
|
35004
|
+
for (const bundle of bundles) try {
|
|
35005
|
+
const profile = await decode(bodyId, bundle);
|
|
35006
|
+
if (profile) profiles.push(profile);
|
|
35007
|
+
} catch (err) {
|
|
35008
|
+
console.warn(`Ring strip ${bodyId}/${bundle.strip} unavailable:`, err);
|
|
35009
|
+
}
|
|
35010
|
+
return profiles;
|
|
35011
|
+
}
|
|
35012
|
+
var SEEN_TAU = -Math.log1p(-.02);
|
|
35013
|
+
function visibleSpan(profiles) {
|
|
35014
|
+
let inner = Infinity;
|
|
35015
|
+
let outer = -Infinity;
|
|
35016
|
+
for (const profile of profiles) {
|
|
35017
|
+
const n = profile.tau.length;
|
|
35018
|
+
const kmPerSample = (profile.outer - profile.inner) / (n - 1);
|
|
35019
|
+
for (let i = 0; i < n; i++) {
|
|
35020
|
+
if (profile.tau[i] < SEEN_TAU) continue;
|
|
35021
|
+
const km = profile.inner + i * kmPerSample;
|
|
35022
|
+
if (km < inner) inner = km;
|
|
35023
|
+
if (km > outer) outer = km;
|
|
35024
|
+
}
|
|
35025
|
+
}
|
|
35026
|
+
return outer >= inner ? {
|
|
35027
|
+
inner,
|
|
35028
|
+
outer
|
|
35029
|
+
} : null;
|
|
35030
|
+
}
|
|
35031
|
+
function loadRingStrips(bodyId) {
|
|
35032
|
+
let pending = cache.get(bodyId);
|
|
35033
|
+
if (!pending) {
|
|
35034
|
+
pending = load(bodyId).catch((err) => {
|
|
35035
|
+
console.warn(`Ring strips for ${bodyId} unavailable:`, err);
|
|
35036
|
+
cache.delete(bodyId);
|
|
35037
|
+
return [];
|
|
35038
|
+
});
|
|
35039
|
+
cache.set(bodyId, pending);
|
|
35040
|
+
}
|
|
35041
|
+
return pending;
|
|
35042
|
+
}
|
|
35043
|
+
|
|
33741
35044
|
//#endregion
|
|
33742
35045
|
//#region src/lib/charts/scrub.ts
|
|
33743
35046
|
var DRAG_SLOP = 8;
|
|
@@ -34527,6 +35830,15 @@ function systemFromMapEntry(entry, name) {
|
|
|
34527
35830
|
moonCount: entry.moon_count
|
|
34528
35831
|
};
|
|
34529
35832
|
}
|
|
35833
|
+
function visibleRings(system, profiles) {
|
|
35834
|
+
if (!system.rings || !profiles.length) return system.rings;
|
|
35835
|
+
const span = visibleSpan(profiles);
|
|
35836
|
+
const rKm = system.planetRadiusKm;
|
|
35837
|
+
return span && {
|
|
35838
|
+
innerRp: span.inner / rKm,
|
|
35839
|
+
outerRp: span.outer / rKm
|
|
35840
|
+
};
|
|
35841
|
+
}
|
|
34530
35842
|
var TOP_MOON_R = 14;
|
|
34531
35843
|
var AT_SURFACE = 1.001;
|
|
34532
35844
|
var PX_PER_DEG = .62;
|
|
@@ -34876,11 +36188,12 @@ function buildSystemView(data, primaryId, exported, options, text, pick) {
|
|
|
34876
36188
|
name: scope.name(moon.id, exported[moon.id])
|
|
34877
36189
|
}));
|
|
34878
36190
|
const rKm = system.planetRadiusKm;
|
|
34879
|
-
const
|
|
36191
|
+
const rings = data.ringProfiles ? visibleRings(system, data.ringProfiles) : system.rings;
|
|
36192
|
+
const bands = rings ? [{
|
|
34880
36193
|
key: "rings",
|
|
34881
36194
|
label: text.rings,
|
|
34882
|
-
innerKm:
|
|
34883
|
-
outerKm:
|
|
36195
|
+
innerKm: rings.innerRp * rKm,
|
|
36196
|
+
outerKm: rings.outerRp * rKm,
|
|
34884
36197
|
tone: "amber"
|
|
34885
36198
|
}] : [];
|
|
34886
36199
|
const model = planetarySystemModel(system, {
|
|
@@ -35027,6 +36340,7 @@ var SystemMap = class {
|
|
|
35027
36340
|
names;
|
|
35028
36341
|
grouping;
|
|
35029
36342
|
zones;
|
|
36343
|
+
rings;
|
|
35030
36344
|
places;
|
|
35031
36345
|
targets = [];
|
|
35032
36346
|
extras = /* @__PURE__ */ new Map();
|
|
@@ -35038,6 +36352,7 @@ var SystemMap = class {
|
|
|
35038
36352
|
this.names = options.names ?? {};
|
|
35039
36353
|
this.grouping = options.grouping ?? "bodies";
|
|
35040
36354
|
this.zones = options.zones ?? "belts";
|
|
36355
|
+
this.rings = options.rings ?? "all";
|
|
35041
36356
|
this.places = (options.places ?? []).map(extraFromPlace);
|
|
35042
36357
|
}
|
|
35043
36358
|
mount(container) {
|
|
@@ -35104,7 +36419,14 @@ var SystemMap = class {
|
|
|
35104
36419
|
};
|
|
35105
36420
|
switch (view.kind) {
|
|
35106
36421
|
case "solar-system": return buildSolarView(data, options, text, pick);
|
|
35107
|
-
case "system":
|
|
36422
|
+
case "system": {
|
|
36423
|
+
const ringed = this.rings === "visible" && !!systemEntry(systems, view.id)?.rings;
|
|
36424
|
+
const [names, ringProfiles] = await Promise.all([this.exportedNames(view.id, systems), ringed ? loadRingStrips(view.id) : void 0]);
|
|
36425
|
+
return buildSystemView({
|
|
36426
|
+
...data,
|
|
36427
|
+
ringProfiles
|
|
36428
|
+
}, view.id, names, options, text, pick);
|
|
36429
|
+
}
|
|
35108
36430
|
case "zone": {
|
|
35109
36431
|
const ids = unplacedIds(solar, systems, this.bodies, this.places.map((place) => place.id));
|
|
35110
36432
|
const read = (await Promise.all(ids.map((id) => this.extra(id)))).filter((extra) => extra !== null);
|
|
@@ -35357,9 +36679,6 @@ var PanoramaAttributionControl = class {
|
|
|
35357
36679
|
|
|
35358
36680
|
//#endregion
|
|
35359
36681
|
//#region src/lib/scene/extensions/trajectory.ts
|
|
35360
|
-
var RAD = Math.PI / 180;
|
|
35361
|
-
var COS_EPS = Math.cos(EARTH_OBLIQUITY_DEG * RAD);
|
|
35362
|
-
var SIN_EPS = Math.sin(EARTH_OBLIQUITY_DEG * RAD);
|
|
35363
36682
|
function fixed(place) {
|
|
35364
36683
|
return place;
|
|
35365
36684
|
}
|
|
@@ -35384,17 +36703,10 @@ function tle(line1, line2) {
|
|
|
35384
36703
|
offsetKm: (jd) => {
|
|
35385
36704
|
if (satrec.error !== SatRecError.None) return null;
|
|
35386
36705
|
const teme = sgp4PositionTEME(satrec, jd);
|
|
35387
|
-
return teme && temeToEcliptic(teme[0], teme[1], teme[2]);
|
|
36706
|
+
return teme && temeToEcliptic(teme[0], teme[1], teme[2], jd);
|
|
35388
36707
|
}
|
|
35389
36708
|
};
|
|
35390
36709
|
}
|
|
35391
|
-
function temeToEcliptic(x, y, z) {
|
|
35392
|
-
return [
|
|
35393
|
-
x,
|
|
35394
|
-
y * COS_EPS + z * SIN_EPS,
|
|
35395
|
-
-y * SIN_EPS + z * COS_EPS
|
|
35396
|
-
];
|
|
35397
|
-
}
|
|
35398
36710
|
function interpolateSamples(states, jd) {
|
|
35399
36711
|
const n = states.length;
|
|
35400
36712
|
if (n < 2 || jd < states[0].jd || jd > states[n - 1].jd) return null;
|
|
@@ -35478,7 +36790,7 @@ async function moonRow(id, { jd, metadata }) {
|
|
|
35478
36790
|
}
|
|
35479
36791
|
function elementsOffset(data, jd) {
|
|
35480
36792
|
if (!discovered(data.visibleFromDays, jd)) return null;
|
|
35481
|
-
if (
|
|
36793
|
+
if (!withinValidity(data, jd)) return null;
|
|
35482
36794
|
if (data.satrec) return sgp4PositionScene(data.satrec, jd);
|
|
35483
36795
|
if (data.q != null) return parabolicToPositionJD(data, jd);
|
|
35484
36796
|
if (data.a === 0) return [
|
|
@@ -35546,16 +36858,9 @@ function neighbours(id, { parents }, at) {
|
|
|
35546
36858
|
}
|
|
35547
36859
|
async function spinOf(id) {
|
|
35548
36860
|
const [detail] = await Promise.all([fetchObjectDetail(id, false), loadSystemsGlobal()]);
|
|
35549
|
-
const orientation = detail.global?.orientation;
|
|
35550
|
-
const sums = detail.global?.nut_prec;
|
|
35551
|
-
const naif = /^naif-(-?\d+)$/.exec(id);
|
|
35552
|
-
const angles = naif ? getNutPrecAngles(ownerIdFor(parseInt(naif[1], 10))) : void 0;
|
|
35553
36861
|
return {
|
|
35554
|
-
orientation,
|
|
35555
|
-
nutPrec:
|
|
35556
|
-
...sums,
|
|
35557
|
-
angles
|
|
35558
|
-
} : void 0
|
|
36862
|
+
orientation: detail.global?.orientation,
|
|
36863
|
+
nutPrec: nutPrecFor(id, detail.global?.nut_prec)
|
|
35559
36864
|
};
|
|
35560
36865
|
}
|
|
35561
36866
|
async function resolve(anchor, at) {
|