spacemap 0.1.18 → 0.1.19
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 +1 -1
- package/dist/spacemap.iife.js +223 -152
- package/dist/spacemap.js +223 -152
- package/index.d.ts +22 -6
- package/index.js +2585 -182
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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, 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";
|
|
2
|
+
import { ACESFilmicToneMapping, AddEquation, 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, OneMinusDstColorFactor, 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
3
|
import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";
|
|
4
4
|
import { CSS2DObject } from "three/addons/renderers/CSS2DRenderer.js";
|
|
5
5
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -22,6 +22,7 @@ var DEFAULT_HOST = {
|
|
|
22
22
|
imagesUrl: "https://images.spacemap.co",
|
|
23
23
|
liveUrl: "https://live.spacemap.co",
|
|
24
24
|
tilesUrl: "",
|
|
25
|
+
extrasolarUrl: "",
|
|
25
26
|
locale: () => "en",
|
|
26
27
|
messages: {
|
|
27
28
|
body_note_no_model: () => "no model available",
|
|
@@ -31,6 +32,7 @@ var DEFAULT_HOST = {
|
|
|
31
32
|
scene_canvas_label: () => "Interactive 3D map of the Solar System",
|
|
32
33
|
attribution_orbits: () => "Orbits",
|
|
33
34
|
attribution_imagery: () => "Imagery",
|
|
35
|
+
attribution_stars: () => "Stars",
|
|
34
36
|
credits_see_all: () => "See full credits",
|
|
35
37
|
layer_surface: () => "Surface",
|
|
36
38
|
layer_clouds: () => "Clouds",
|
|
@@ -69,6 +71,7 @@ function configureHost(overrides) {
|
|
|
69
71
|
current$1.imagesUrl = current$1.imagesUrl.replace(/\/$/, "");
|
|
70
72
|
current$1.liveUrl = current$1.liveUrl.replace(/\/$/, "");
|
|
71
73
|
current$1.tilesUrl = current$1.tilesUrl.replace(/\/$/, "");
|
|
74
|
+
current$1.extrasolarUrl = current$1.extrasolarUrl.replace(/\/$/, "");
|
|
72
75
|
}
|
|
73
76
|
function host() {
|
|
74
77
|
return current$1;
|
|
@@ -3003,10 +3006,10 @@ function buildVersionedUrl(base, path, cls) {
|
|
|
3003
3006
|
|
|
3004
3007
|
//#endregion
|
|
3005
3008
|
//#region src/lib/fetch/position/format.ts
|
|
3006
|
-
var MAGIC$
|
|
3009
|
+
var MAGIC$3 = 1346456915;
|
|
3007
3010
|
var COMMON_HEADER_SIZE = 24;
|
|
3008
3011
|
var EXTENSION_SIZE = 8;
|
|
3009
|
-
var HEADER_SIZE$
|
|
3012
|
+
var HEADER_SIZE$3 = 24 + 8;
|
|
3010
3013
|
var labelsUrl = (lang) => `${dataBase()}/v1/labels/${lang}.gz`;
|
|
3011
3014
|
function zoomSegment(zoom) {
|
|
3012
3015
|
return zoom === null ? "" : `${zoom}/`;
|
|
@@ -3073,6 +3076,9 @@ function buildObjectId(idType, value) {
|
|
|
3073
3076
|
|
|
3074
3077
|
//#endregion
|
|
3075
3078
|
//#region src/lib/types/objects.ts
|
|
3079
|
+
function isExtrasolar(body) {
|
|
3080
|
+
return body.data.objectType === ObjectType.EXTRASOLAR;
|
|
3081
|
+
}
|
|
3076
3082
|
function isSurfaceFeature(body) {
|
|
3077
3083
|
return body.data.objectType === ObjectType.SURFACE_FEATURE;
|
|
3078
3084
|
}
|
|
@@ -3094,6 +3100,7 @@ var ObjectType = /* @__PURE__ */ function(ObjectType) {
|
|
|
3094
3100
|
ObjectType[ObjectType["DEBRIS"] = 14] = "DEBRIS";
|
|
3095
3101
|
ObjectType[ObjectType["UNDOCUMENTED"] = 15] = "UNDOCUMENTED";
|
|
3096
3102
|
ObjectType[ObjectType["SURFACE_FEATURE"] = 16] = "SURFACE_FEATURE";
|
|
3103
|
+
ObjectType[ObjectType["EXTRASOLAR"] = 17] = "EXTRASOLAR";
|
|
3097
3104
|
return ObjectType;
|
|
3098
3105
|
}({});
|
|
3099
3106
|
var ZONE_A_RANGE = {
|
|
@@ -3177,7 +3184,8 @@ var NOMINAL_RADIUS_KM_BY_SOURCE = {
|
|
|
3177
3184
|
var NOMINAL_RADIUS_KM_BY_TYPE = {
|
|
3178
3185
|
[ObjectType.SPACECRAFT]: .005,
|
|
3179
3186
|
[ObjectType.DEBRIS]: .005,
|
|
3180
|
-
[ObjectType.SURFACE_FEATURE]: .001
|
|
3187
|
+
[ObjectType.SURFACE_FEATURE]: .001,
|
|
3188
|
+
[ObjectType.EXTRASOLAR]: 695700
|
|
3181
3189
|
};
|
|
3182
3190
|
var NOMINAL_RADIUS_KM_DEFAULT = .1;
|
|
3183
3191
|
function effectiveRadiusKm(data) {
|
|
@@ -3292,6 +3300,13 @@ var CreditsStore = class {
|
|
|
3292
3300
|
set skybox(value) {
|
|
3293
3301
|
set(this.#skybox, value, true);
|
|
3294
3302
|
}
|
|
3303
|
+
#stars = state([]);
|
|
3304
|
+
get stars() {
|
|
3305
|
+
return get(this.#stars);
|
|
3306
|
+
}
|
|
3307
|
+
set stars(value) {
|
|
3308
|
+
set(this.#stars, value);
|
|
3309
|
+
}
|
|
3295
3310
|
#orbitSources = state(proxy(/* @__PURE__ */ new Set()));
|
|
3296
3311
|
get orbitSources() {
|
|
3297
3312
|
return get(this.#orbitSources);
|
|
@@ -3342,6 +3357,9 @@ var CreditsStore = class {
|
|
|
3342
3357
|
imageryOf(layer) {
|
|
3343
3358
|
return [...this.imagery.values()].filter((c) => c.layer === layer);
|
|
3344
3359
|
}
|
|
3360
|
+
setStars(credits) {
|
|
3361
|
+
if (this.stars.length === 0) this.stars = credits;
|
|
3362
|
+
}
|
|
3345
3363
|
registerOrientation(credit) {
|
|
3346
3364
|
if (this.orientation.has(credit.bodyId)) return;
|
|
3347
3365
|
this.orientation.set(credit.bodyId, credit);
|
|
@@ -3446,7 +3464,7 @@ function rowKey(cols, i) {
|
|
|
3446
3464
|
return objectKey(cols.idType, cols.id[i]);
|
|
3447
3465
|
}
|
|
3448
3466
|
function parseSharedColumns(buffer, rowCount) {
|
|
3449
|
-
let offset = HEADER_SIZE$
|
|
3467
|
+
let offset = HEADER_SIZE$3;
|
|
3450
3468
|
const id = new Int32Array(buffer, offset, rowCount);
|
|
3451
3469
|
offset += align8(rowCount * 4);
|
|
3452
3470
|
const objectType = new Uint8Array(buffer, offset, rowCount);
|
|
@@ -5315,6 +5333,12 @@ function equatorialToScene(xEq, yEq, zEq, out) {
|
|
|
5315
5333
|
target.z = -(yEq * COS_OBL$1 + zEq * SIN_OBL$1);
|
|
5316
5334
|
return target;
|
|
5317
5335
|
}
|
|
5336
|
+
function sceneToEquatorial(x, y, z, out) {
|
|
5337
|
+
out.x = x;
|
|
5338
|
+
out.y = -y * SIN_OBL$1 - z * COS_OBL$1;
|
|
5339
|
+
out.z = y * COS_OBL$1 - z * SIN_OBL$1;
|
|
5340
|
+
return out;
|
|
5341
|
+
}
|
|
5318
5342
|
|
|
5319
5343
|
//#endregion
|
|
5320
5344
|
//#region src/lib/time/jd.ts
|
|
@@ -6385,7 +6409,7 @@ function resolveBodyColor(data) {
|
|
|
6385
6409
|
const planetId = `naif-${data.id.replace("naif-", "")}99`;
|
|
6386
6410
|
if (BODY_COLORS[planetId]) return BODY_COLORS[planetId];
|
|
6387
6411
|
}
|
|
6388
|
-
if (objectType === ObjectType.STAR) return TYPE_COLOR_STAR;
|
|
6412
|
+
if (objectType === ObjectType.STAR || objectType === ObjectType.EXTRASOLAR) return TYPE_COLOR_STAR;
|
|
6389
6413
|
if (objectType === ObjectType.PLANET || objectType === ObjectType.DWARF_PLANET) return TYPE_COLOR_PLANET;
|
|
6390
6414
|
if (objectType === ObjectType.MOON) return TYPE_COLOR_MOON;
|
|
6391
6415
|
if (isAsteroid(objectType)) return TYPE_COLOR_ASTEROID;
|
|
@@ -6724,12 +6748,14 @@ function adoptRow(held, fresh) {
|
|
|
6724
6748
|
held.orbitCenterId = fresh.orbitCenterId ?? held.orbitCenterId;
|
|
6725
6749
|
held.trailAnchorId = fresh.trailAnchorId;
|
|
6726
6750
|
}
|
|
6751
|
+
var EXTRASOLAR_KEPT = 64;
|
|
6727
6752
|
var BodyIndex = class {
|
|
6728
6753
|
bodiesById = /* @__PURE__ */ new Map();
|
|
6729
6754
|
majorBodies = [];
|
|
6730
6755
|
asteroidBodiesByZone = /* @__PURE__ */ new Map();
|
|
6731
6756
|
spacecraftByParent = /* @__PURE__ */ new Map();
|
|
6732
6757
|
focusFeature = null;
|
|
6758
|
+
extrasolar = /* @__PURE__ */ new Map();
|
|
6733
6759
|
dirtyAsteroidZones = /* @__PURE__ */ new Set();
|
|
6734
6760
|
dirtySpacecraftGroups = /* @__PURE__ */ new Set();
|
|
6735
6761
|
minorStreaming = false;
|
|
@@ -6764,6 +6790,8 @@ var BodyIndex = class {
|
|
|
6764
6790
|
const major = this.bodiesById.get(id);
|
|
6765
6791
|
if (major) return major;
|
|
6766
6792
|
if (this.focusFeature?.data.id === id) return this.focusFeature;
|
|
6793
|
+
const star = this.extrasolar.get(id);
|
|
6794
|
+
if (star) return star;
|
|
6767
6795
|
if (zone !== void 0) return this.spacecraftByParent.get(zone)?.get(id) ?? this.asteroidBodiesByZone.get(zone)?.get(id);
|
|
6768
6796
|
for (const byId of this.spacecraftByParent.values()) {
|
|
6769
6797
|
const hit = byId.get(id);
|
|
@@ -6774,6 +6802,13 @@ var BodyIndex = class {
|
|
|
6774
6802
|
if (hit) return hit;
|
|
6775
6803
|
}
|
|
6776
6804
|
}
|
|
6805
|
+
addExtrasolar(body, ids = []) {
|
|
6806
|
+
for (const id of [body.data.id, ...ids]) {
|
|
6807
|
+
this.extrasolar.delete(id);
|
|
6808
|
+
this.extrasolar.set(id, body);
|
|
6809
|
+
}
|
|
6810
|
+
while (this.extrasolar.size > EXTRASOLAR_KEPT) this.extrasolar.delete(this.extrasolar.keys().next().value);
|
|
6811
|
+
}
|
|
6777
6812
|
addBodies(bodies) {
|
|
6778
6813
|
let added = false;
|
|
6779
6814
|
for (const b of bodies) {
|
|
@@ -7210,6 +7245,7 @@ var MAP_LAYERS = [
|
|
|
7210
7245
|
"spacecraft",
|
|
7211
7246
|
"satellites",
|
|
7212
7247
|
"debris",
|
|
7248
|
+
"starfield",
|
|
7213
7249
|
"orbits",
|
|
7214
7250
|
"labels",
|
|
7215
7251
|
"halos",
|
|
@@ -7358,6 +7394,117 @@ function computeVisibilityFromRatio(ratio, thresholds, focusedMultiplier, isFocu
|
|
|
7358
7394
|
return VISIBILITY.HIDE;
|
|
7359
7395
|
}
|
|
7360
7396
|
|
|
7397
|
+
//#endregion
|
|
7398
|
+
//#region src/lib/scene/visibility/switch-fade.ts
|
|
7399
|
+
var SYSTEM_SWITCH_FADE_MS = 300;
|
|
7400
|
+
var SwitchFade = class {
|
|
7401
|
+
progress;
|
|
7402
|
+
target;
|
|
7403
|
+
started;
|
|
7404
|
+
constructor(on, durationMs = 300) {
|
|
7405
|
+
this.durationMs = durationMs;
|
|
7406
|
+
this.started = on !== void 0;
|
|
7407
|
+
this.progress = this.target = on ? 1 : 0;
|
|
7408
|
+
}
|
|
7409
|
+
step(on, dtMs) {
|
|
7410
|
+
this.target = on ? 1 : 0;
|
|
7411
|
+
if (!this.started) {
|
|
7412
|
+
this.started = true;
|
|
7413
|
+
this.progress = this.target;
|
|
7414
|
+
return;
|
|
7415
|
+
}
|
|
7416
|
+
const delta = dtMs / this.durationMs;
|
|
7417
|
+
this.progress = this.target === 1 ? Math.min(this.progress + delta, 1) : Math.max(this.progress - delta, 0);
|
|
7418
|
+
}
|
|
7419
|
+
get share() {
|
|
7420
|
+
const p = this.progress;
|
|
7421
|
+
return p * p * (3 - 2 * p);
|
|
7422
|
+
}
|
|
7423
|
+
get fading() {
|
|
7424
|
+
return this.progress !== this.target;
|
|
7425
|
+
}
|
|
7426
|
+
};
|
|
7427
|
+
|
|
7428
|
+
//#endregion
|
|
7429
|
+
//#region src/lib/scene/visibility/zone-fade.ts
|
|
7430
|
+
var ZoneFades = class {
|
|
7431
|
+
main = new SwitchFade(true);
|
|
7432
|
+
systems = [];
|
|
7433
|
+
stepped = false;
|
|
7434
|
+
step(activeSystemId, dtMs) {
|
|
7435
|
+
if (!this.stepped) {
|
|
7436
|
+
this.stepped = true;
|
|
7437
|
+
this.main = new SwitchFade(activeSystemId === null);
|
|
7438
|
+
if (activeSystemId !== null) this.systems.push({
|
|
7439
|
+
id: activeSystemId,
|
|
7440
|
+
fade: new SwitchFade(true)
|
|
7441
|
+
});
|
|
7442
|
+
return;
|
|
7443
|
+
}
|
|
7444
|
+
this.main.step(activeSystemId === null, dtMs);
|
|
7445
|
+
if (activeSystemId !== null && !this.systems.some((s) => s.id === activeSystemId)) this.systems.push({
|
|
7446
|
+
id: activeSystemId,
|
|
7447
|
+
fade: new SwitchFade(false)
|
|
7448
|
+
});
|
|
7449
|
+
for (let i = this.systems.length - 1; i >= 0; i--) {
|
|
7450
|
+
const { id, fade } = this.systems[i];
|
|
7451
|
+
fade.step(id === activeSystemId, dtMs);
|
|
7452
|
+
if (fade.share === 0 && !fade.fading) this.systems.splice(i, 1);
|
|
7453
|
+
}
|
|
7454
|
+
}
|
|
7455
|
+
get mainShare() {
|
|
7456
|
+
return this.main.share;
|
|
7457
|
+
}
|
|
7458
|
+
get fading() {
|
|
7459
|
+
return this.main.fading || this.systems.some((s) => s.fade.fading);
|
|
7460
|
+
}
|
|
7461
|
+
};
|
|
7462
|
+
|
|
7463
|
+
//#endregion
|
|
7464
|
+
//#region src/lib/scene/visibility/threshold-fade.ts
|
|
7465
|
+
var VisibilityThresholdFades = class {
|
|
7466
|
+
labels = /* @__PURE__ */ new Map();
|
|
7467
|
+
orbits = /* @__PURE__ */ new Map();
|
|
7468
|
+
frame = 0;
|
|
7469
|
+
dtMs = 0;
|
|
7470
|
+
beginFrame(dtMs) {
|
|
7471
|
+
this.frame++;
|
|
7472
|
+
this.dtMs = dtMs;
|
|
7473
|
+
this.prune(this.labels);
|
|
7474
|
+
this.prune(this.orbits);
|
|
7475
|
+
}
|
|
7476
|
+
labelShare(id, shown) {
|
|
7477
|
+
return this.share(this.labels, id, shown);
|
|
7478
|
+
}
|
|
7479
|
+
orbitShare(id, shown) {
|
|
7480
|
+
return this.share(this.orbits, id, shown);
|
|
7481
|
+
}
|
|
7482
|
+
get fading() {
|
|
7483
|
+
return this.anyFading(this.labels) || this.anyFading(this.orbits);
|
|
7484
|
+
}
|
|
7485
|
+
share(entries, id, shown) {
|
|
7486
|
+
let entry = entries.get(id);
|
|
7487
|
+
if (!entry) {
|
|
7488
|
+
entry = {
|
|
7489
|
+
fade: new SwitchFade(shown, 100),
|
|
7490
|
+
frame: this.frame
|
|
7491
|
+
};
|
|
7492
|
+
entries.set(id, entry);
|
|
7493
|
+
} else if (entry.frame !== this.frame) {
|
|
7494
|
+
entry.frame = this.frame;
|
|
7495
|
+
entry.fade.step(shown, this.dtMs);
|
|
7496
|
+
}
|
|
7497
|
+
return entry.fade.share;
|
|
7498
|
+
}
|
|
7499
|
+
anyFading(entries) {
|
|
7500
|
+
for (const entry of entries.values()) if (entry.frame === this.frame && entry.fade.fading) return true;
|
|
7501
|
+
return false;
|
|
7502
|
+
}
|
|
7503
|
+
prune(entries) {
|
|
7504
|
+
for (const [id, entry] of entries) if (entry.frame < this.frame - 1) entries.delete(id);
|
|
7505
|
+
}
|
|
7506
|
+
};
|
|
7507
|
+
|
|
7361
7508
|
//#endregion
|
|
7362
7509
|
//#region src/lib/scene/visibility/controller.svelte.ts
|
|
7363
7510
|
var ALL_LAYERS = new LayerSet();
|
|
@@ -7383,6 +7530,10 @@ var VisibilityController = class {
|
|
|
7383
7530
|
}
|
|
7384
7531
|
activeSystemId = null;
|
|
7385
7532
|
isZoomedIn = false;
|
|
7533
|
+
zones = new ZoneFades();
|
|
7534
|
+
thresholds = new VisibilityThresholdFades();
|
|
7535
|
+
systemShare = 1;
|
|
7536
|
+
starShare = 0;
|
|
7386
7537
|
focusedBodyIdPlain = SUN_ID;
|
|
7387
7538
|
focusedSystemIdPlain = null;
|
|
7388
7539
|
travelSystemActive = false;
|
|
@@ -7429,6 +7580,19 @@ var VisibilityController = class {
|
|
|
7429
7580
|
this.recomputeFullMoons();
|
|
7430
7581
|
}
|
|
7431
7582
|
}
|
|
7583
|
+
stepZones(dtMs) {
|
|
7584
|
+
this.zones.step(this.activeSystemId, dtMs);
|
|
7585
|
+
this.thresholds.beginFrame(dtMs);
|
|
7586
|
+
}
|
|
7587
|
+
labelThresholdShare(id, shown) {
|
|
7588
|
+
return this.thresholds.labelShare(id, shown);
|
|
7589
|
+
}
|
|
7590
|
+
orbitThresholdShare(id, shown) {
|
|
7591
|
+
return this.thresholds.orbitShare(id, shown);
|
|
7592
|
+
}
|
|
7593
|
+
get fading() {
|
|
7594
|
+
return this.zones.fading || this.thresholds.fading;
|
|
7595
|
+
}
|
|
7432
7596
|
refreshProbeFocusedSystem() {
|
|
7433
7597
|
const ps = this.getProbeStore();
|
|
7434
7598
|
if (!ps) return;
|
|
@@ -7442,6 +7606,7 @@ var VisibilityController = class {
|
|
|
7442
7606
|
this.lastRecomputeDist = -1;
|
|
7443
7607
|
}
|
|
7444
7608
|
resolveSystemId(body) {
|
|
7609
|
+
if (isExtrasolar(body)) return null;
|
|
7445
7610
|
const isSystemBarycenter = body.data.objectType === ObjectType.BARYCENTER && isTopLevelParent(body.data.parentId) && !isTopLevelParent(body.data.id);
|
|
7446
7611
|
const isTopLevel = body.data.objectType === ObjectType.STAR || !isSystemBarycenter && isTopLevelParent(body.data.parentId);
|
|
7447
7612
|
if (isSystemBarycenter) return body.data.id;
|
|
@@ -7474,6 +7639,7 @@ var VisibilityController = class {
|
|
|
7474
7639
|
this.recomputeFullMoons();
|
|
7475
7640
|
}
|
|
7476
7641
|
getMoonVisibility(moon) {
|
|
7642
|
+
if (this.systemShare === 0) return VISIBILITY.HIDE;
|
|
7477
7643
|
if (this.getLayers().hidesBody(moon.data.objectType, moon.data.parentId)) return VISIBILITY.HIDE;
|
|
7478
7644
|
const cached = this.moonVisibilityCache.get(moon.data.id);
|
|
7479
7645
|
if (cached !== void 0) return cached;
|
|
@@ -7498,6 +7664,7 @@ var VisibilityController = class {
|
|
|
7498
7664
|
return this.pinned.has(id);
|
|
7499
7665
|
}
|
|
7500
7666
|
getPlanetVisibility(body, camDistThreeJS) {
|
|
7667
|
+
if (this.systemShare === 0 && body.data.objectType !== ObjectType.STAR) return VISIBILITY.HIDE;
|
|
7501
7668
|
const pinned = this.pinned.has(body.data.id);
|
|
7502
7669
|
const vis = this.ratioVisibility(body, camDistThreeJS, pinned);
|
|
7503
7670
|
return pinned && vis !== VISIBILITY.CLOSE ? VISIBILITY.FULL : vis;
|
|
@@ -7556,15 +7723,24 @@ var VisibilityController = class {
|
|
|
7556
7723
|
return sysNaif !== null && this.isInFocusedSystem(`naif-${sysNaif}`);
|
|
7557
7724
|
}
|
|
7558
7725
|
hasFullRendering(body) {
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
const
|
|
7563
|
-
if (
|
|
7564
|
-
const
|
|
7565
|
-
|
|
7726
|
+
return this.fullRenderingShare(body) > 0;
|
|
7727
|
+
}
|
|
7728
|
+
fullRenderingShare(body) {
|
|
7729
|
+
const main = this.zones.mainShare;
|
|
7730
|
+
if (main === 1 || this.pinned.has(body.data.id)) return 1;
|
|
7731
|
+
const home = isTopLevelParent(body.data.parentId) ? body.data.id : body.data.parentId;
|
|
7732
|
+
const probeSystem = this.probeSystemId(body);
|
|
7733
|
+
let share = main;
|
|
7734
|
+
for (const { id, fade } of this.zones.systems) if (this.bodies.isInSystem(home, id) || probeSystem !== null && this.bodies.isInSystem(probeSystem, id)) share += fade.share;
|
|
7735
|
+
return Math.min(share, 1);
|
|
7736
|
+
}
|
|
7737
|
+
probeSystemId(body) {
|
|
7738
|
+
if (body.data.orbitalSource !== OrbitalSource.SPICE_PROBE) return null;
|
|
7739
|
+
const sysNaif = this.getProbeStore()?.containingSystemAt(body.data.id, this.currentJd);
|
|
7740
|
+
return sysNaif === null || sysNaif === void 0 ? null : `naif-${sysNaif}`;
|
|
7566
7741
|
}
|
|
7567
7742
|
isMoonGroupVisible(parentId) {
|
|
7743
|
+
if (this.systemShare === 0) return false;
|
|
7568
7744
|
if (!this.getLayers().isVisible("moons")) return false;
|
|
7569
7745
|
if (!this.isInFocusedSystem(parentId)) return false;
|
|
7570
7746
|
const maxA = this.bodies.maxMoonA(parentId);
|
|
@@ -7572,19 +7748,25 @@ var VisibilityController = class {
|
|
|
7572
7748
|
return this.cameraDistThreeJS / 10 / maxA <= this.scaledPlanetary[VISIBILITY.FAR];
|
|
7573
7749
|
}
|
|
7574
7750
|
isSpacecraftGroupVisible(groupParentId) {
|
|
7575
|
-
|
|
7751
|
+
return this.spacecraftGroupShare(groupParentId) > 0;
|
|
7752
|
+
}
|
|
7753
|
+
spacecraftGroupShare(groupParentId) {
|
|
7754
|
+
if (this.systemShare === 0) return 0;
|
|
7755
|
+
if (this.getLayers().hidesSpacecraftGroup(groupParentId)) return 0;
|
|
7576
7756
|
const parent = this.bodies.bodiesById.get(groupParentId);
|
|
7577
|
-
if (groupParentId !== "naif-0" && !parent?.position) return
|
|
7578
|
-
|
|
7579
|
-
if (
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7757
|
+
if (groupParentId !== "naif-0" && !parent?.position) return 0;
|
|
7758
|
+
if (isTopLevelParent(groupParentId)) return this.zones.mainShare;
|
|
7759
|
+
if (parent?.data.objectType === ObjectType.STAR) return this.zones.mainShare;
|
|
7760
|
+
for (const { id, fade } of this.zones.systems) if (this.bodies.isInSystem(groupParentId, id)) return fade.share;
|
|
7761
|
+
return 0;
|
|
7762
|
+
}
|
|
7763
|
+
asteroidGroupShare(zone) {
|
|
7764
|
+
return this.isAsteroidGroupVisible(zone) ? this.zones.mainShare : 0;
|
|
7584
7765
|
}
|
|
7585
7766
|
isAsteroidGroupVisible(zone) {
|
|
7767
|
+
if (this.systemShare === 0) return false;
|
|
7586
7768
|
if (this.getLayers().hidesZone(zone)) return false;
|
|
7587
|
-
if (this.
|
|
7769
|
+
if (this.zones.mainShare === 0) return false;
|
|
7588
7770
|
if (!this.bodies.bodiesById.get("naif-10")?.position) return false;
|
|
7589
7771
|
const filter = this.getSmallBodyFilter();
|
|
7590
7772
|
if (filter && zone.startsWith("small_bodies/")) {
|
|
@@ -7745,7 +7927,7 @@ function parseChebyshevPayload$1(buffer, startJd, endJd) {
|
|
|
7745
7927
|
const float64Coeffs = (view.getUint8(28) & 1) !== 0;
|
|
7746
7928
|
const coeffBytes = float64Coeffs ? 8 : 4;
|
|
7747
7929
|
const bodies = [];
|
|
7748
|
-
let offset = HEADER_SIZE$
|
|
7930
|
+
let offset = HEADER_SIZE$3;
|
|
7749
7931
|
for (let b = 0; b < bodyCount; b++) {
|
|
7750
7932
|
const naifId = view.getInt32(offset, true);
|
|
7751
7933
|
const parentId = view.getInt32(offset + 4, true);
|
|
@@ -7905,7 +8087,7 @@ function parseProbesPayload(buffer, startJd, endJd, float64Coeffs) {
|
|
|
7905
8087
|
const subchunkS = subchunkDays * SECONDS_PER_DAY$2;
|
|
7906
8088
|
const chunkStartEt = tdbJdToEt(startJd);
|
|
7907
8089
|
const probes = [];
|
|
7908
|
-
let offset = HEADER_SIZE$
|
|
8090
|
+
let offset = HEADER_SIZE$3;
|
|
7909
8091
|
for (let p = 0; p < probeCount; p++) {
|
|
7910
8092
|
const objIdValue = view.getInt32(offset, true);
|
|
7911
8093
|
const idTypeOrdinal = view.getUint8(offset + 4);
|
|
@@ -8129,7 +8311,7 @@ var SEC_PER_DAY = 86400;
|
|
|
8129
8311
|
var AU_PER_DAY_TO_KM_PER_SEC = AU_KM / SEC_PER_DAY;
|
|
8130
8312
|
var SMALL_E = 1e-9;
|
|
8131
8313
|
var SMALL_SIN_I = 1e-9;
|
|
8132
|
-
function clamp$
|
|
8314
|
+
function clamp$4(x, lo, hi) {
|
|
8133
8315
|
return x < lo ? lo : x > hi ? hi : x;
|
|
8134
8316
|
}
|
|
8135
8317
|
function stateVectorToElements(r, v, muAuDay2, jd) {
|
|
@@ -8143,7 +8325,7 @@ function stateVectorToElements(r, v, muAuDay2, jd) {
|
|
|
8143
8325
|
const hz = rx * vy - ry * vx;
|
|
8144
8326
|
const hNorm = Math.hypot(hx, hy, hz);
|
|
8145
8327
|
if (hNorm === 0) return null;
|
|
8146
|
-
const iRad = Math.acos(clamp$
|
|
8328
|
+
const iRad = Math.acos(clamp$4(hz / hNorm, -1, 1));
|
|
8147
8329
|
const sinI = Math.sin(iRad);
|
|
8148
8330
|
const evX = (vy * hz - vz * hy) / muAuDay2 - rx / rNorm;
|
|
8149
8331
|
const evY = (vz * hx - vx * hz) / muAuDay2 - ry / rNorm;
|
|
@@ -8158,7 +8340,7 @@ function stateVectorToElements(r, v, muAuDay2, jd) {
|
|
|
8158
8340
|
let omRad;
|
|
8159
8341
|
if (sinI < SMALL_SIN_I || nNorm === 0) omRad = 0;
|
|
8160
8342
|
else {
|
|
8161
|
-
omRad = Math.acos(clamp$
|
|
8343
|
+
omRad = Math.acos(clamp$4(nx / nNorm, -1, 1));
|
|
8162
8344
|
if (ny < 0) omRad = 2 * Math.PI - omRad;
|
|
8163
8345
|
}
|
|
8164
8346
|
let wRad;
|
|
@@ -8169,7 +8351,7 @@ function stateVectorToElements(r, v, muAuDay2, jd) {
|
|
|
8169
8351
|
if (wRad < 0) wRad += 2 * Math.PI;
|
|
8170
8352
|
} else {
|
|
8171
8353
|
const cosW = (nx * evX + ny * evY) / (nNorm * e);
|
|
8172
|
-
wRad = Math.acos(clamp$
|
|
8354
|
+
wRad = Math.acos(clamp$4(cosW, -1, 1));
|
|
8173
8355
|
if (evZ < 0) wRad = 2 * Math.PI - wRad;
|
|
8174
8356
|
}
|
|
8175
8357
|
let nuRad;
|
|
@@ -8180,11 +8362,11 @@ function stateVectorToElements(r, v, muAuDay2, jd) {
|
|
|
8180
8362
|
if (nuRad < 0) nuRad += 2 * Math.PI;
|
|
8181
8363
|
} else if (e < SMALL_E) {
|
|
8182
8364
|
const cosU = (nx * rx + ny * ry) / (nNorm * rNorm);
|
|
8183
|
-
nuRad = Math.acos(clamp$
|
|
8365
|
+
nuRad = Math.acos(clamp$4(cosU, -1, 1));
|
|
8184
8366
|
if (rz < 0) nuRad = 2 * Math.PI - nuRad;
|
|
8185
8367
|
} else {
|
|
8186
8368
|
const cosNu = (evX * rx + evY * ry + evZ * rz) / (e * rNorm);
|
|
8187
|
-
nuRad = Math.acos(clamp$
|
|
8369
|
+
nuRad = Math.acos(clamp$4(cosNu, -1, 1));
|
|
8188
8370
|
if (rDotV < 0) nuRad = 2 * Math.PI - nuRad;
|
|
8189
8371
|
}
|
|
8190
8372
|
let maRad;
|
|
@@ -9998,6 +10180,46 @@ async function dataVersionChanged() {
|
|
|
9998
10180
|
}
|
|
9999
10181
|
}
|
|
10000
10182
|
|
|
10183
|
+
//#endregion
|
|
10184
|
+
//#region src/lib/fetch/extrasolar/ids.ts
|
|
10185
|
+
var CELL_LEVEL = 10;
|
|
10186
|
+
var CELL_COUNT = 12 * 4 ** 10;
|
|
10187
|
+
var FIRST_TABLE = 1;
|
|
10188
|
+
var LAST_TABLE = 30;
|
|
10189
|
+
var CELL_SPAN = 2 ** 24;
|
|
10190
|
+
var TABLE_SPAN = 32;
|
|
10191
|
+
var SERIAL_SPAN = 2 ** 29;
|
|
10192
|
+
var ID_TEXT = /^[1-9][0-9]{0,15}$/;
|
|
10193
|
+
var EXTRASOLAR_PREFIX = "x-";
|
|
10194
|
+
function decodeId(id) {
|
|
10195
|
+
return {
|
|
10196
|
+
serial: Math.floor(id / SERIAL_SPAN),
|
|
10197
|
+
table: Math.floor(id / CELL_SPAN) % TABLE_SPAN,
|
|
10198
|
+
cell: id % CELL_SPAN
|
|
10199
|
+
};
|
|
10200
|
+
}
|
|
10201
|
+
function cellOf(id) {
|
|
10202
|
+
return id % CELL_SPAN;
|
|
10203
|
+
}
|
|
10204
|
+
function tableOf(id) {
|
|
10205
|
+
return Math.floor(id / CELL_SPAN) % TABLE_SPAN;
|
|
10206
|
+
}
|
|
10207
|
+
function parseExtrasolarId(text, tables) {
|
|
10208
|
+
if (!ID_TEXT.test(text)) return null;
|
|
10209
|
+
const id = Number(text);
|
|
10210
|
+
if (id > Number.MAX_SAFE_INTEGER) return null;
|
|
10211
|
+
const { table, cell } = decodeId(id);
|
|
10212
|
+
if (cell >= CELL_COUNT) return null;
|
|
10213
|
+
if (tables ? !tables.has(table) : table < 1 || table > 30) return null;
|
|
10214
|
+
return id;
|
|
10215
|
+
}
|
|
10216
|
+
function isExtrasolarObjectId(objectId) {
|
|
10217
|
+
return objectId.startsWith("x-");
|
|
10218
|
+
}
|
|
10219
|
+
function extrasolarObjectId(id) {
|
|
10220
|
+
return `${"x-"}${id}`;
|
|
10221
|
+
}
|
|
10222
|
+
|
|
10001
10223
|
//#endregion
|
|
10002
10224
|
//#region src/lib/fetch/gz.ts
|
|
10003
10225
|
function gunzip(res) {
|
|
@@ -10100,6 +10322,10 @@ function isViewable(entry) {
|
|
|
10100
10322
|
return textureAllowed(entry.distribution);
|
|
10101
10323
|
}
|
|
10102
10324
|
function fetchObjectDetail(fileId, fetchLocalized = true, lang = getLocale(), background = false) {
|
|
10325
|
+
if (isExtrasolarObjectId(fileId)) return Promise.resolve({
|
|
10326
|
+
global: null,
|
|
10327
|
+
localized: null
|
|
10328
|
+
});
|
|
10103
10329
|
return fetchBundlePair(OBJECT_BUNDLES, fileId, lang, fetchLocalized, background);
|
|
10104
10330
|
}
|
|
10105
10331
|
|
|
@@ -10135,6 +10361,585 @@ function planRideMarkers(rides, focusedId, sceneName) {
|
|
|
10135
10361
|
};
|
|
10136
10362
|
}
|
|
10137
10363
|
|
|
10364
|
+
//#endregion
|
|
10365
|
+
//#region src/lib/fetch/extrasolar/container.ts
|
|
10366
|
+
var MAGIC$2 = "SMXS";
|
|
10367
|
+
var FORMAT_VERSION = 1;
|
|
10368
|
+
var KIND_NODE = 3;
|
|
10369
|
+
var HEADER_SIZE$2 = 32;
|
|
10370
|
+
var TOKEN_AT = 8;
|
|
10371
|
+
var TOKEN_SIZE = 16;
|
|
10372
|
+
var HAS_VALIDITY = 1;
|
|
10373
|
+
var NODE_INFO_SIZE = 80;
|
|
10374
|
+
var TYPE_CODES = {
|
|
10375
|
+
1: "bool",
|
|
10376
|
+
2: "int8",
|
|
10377
|
+
3: "int16",
|
|
10378
|
+
4: "int32",
|
|
10379
|
+
5: "uint8",
|
|
10380
|
+
6: "uint16",
|
|
10381
|
+
7: "uint32",
|
|
10382
|
+
8: "float32",
|
|
10383
|
+
9: "float64",
|
|
10384
|
+
10: "id",
|
|
10385
|
+
11: "string",
|
|
10386
|
+
12: "dict",
|
|
10387
|
+
13: "cross_ids",
|
|
10388
|
+
14: "bits"
|
|
10389
|
+
};
|
|
10390
|
+
var ContainerFormatError = class extends Error {
|
|
10391
|
+
constructor(message) {
|
|
10392
|
+
super(message);
|
|
10393
|
+
this.name = "ContainerFormatError";
|
|
10394
|
+
}
|
|
10395
|
+
};
|
|
10396
|
+
var decoder = new TextDecoder();
|
|
10397
|
+
function bitAt(bytes, i) {
|
|
10398
|
+
return (bytes[i >> 3] >> (i & 7) & 1) === 1;
|
|
10399
|
+
}
|
|
10400
|
+
var StringColumn = class {
|
|
10401
|
+
constructor(offsets, bytes, validity) {
|
|
10402
|
+
this.offsets = offsets;
|
|
10403
|
+
this.bytes = bytes;
|
|
10404
|
+
this.validity = validity;
|
|
10405
|
+
}
|
|
10406
|
+
get length() {
|
|
10407
|
+
return this.offsets.length - 1;
|
|
10408
|
+
}
|
|
10409
|
+
get(i) {
|
|
10410
|
+
if (this.validity && !bitAt(this.validity, i)) return null;
|
|
10411
|
+
return decoder.decode(this.bytes.subarray(this.offsets[i], this.offsets[i + 1]));
|
|
10412
|
+
}
|
|
10413
|
+
};
|
|
10414
|
+
var DictColumn = class {
|
|
10415
|
+
constructor(codes, values, validity) {
|
|
10416
|
+
this.codes = codes;
|
|
10417
|
+
this.values = values;
|
|
10418
|
+
this.validity = validity;
|
|
10419
|
+
}
|
|
10420
|
+
get length() {
|
|
10421
|
+
return this.codes.length;
|
|
10422
|
+
}
|
|
10423
|
+
get(i) {
|
|
10424
|
+
if (this.validity && !bitAt(this.validity, i)) return null;
|
|
10425
|
+
return this.values[this.codes[i]];
|
|
10426
|
+
}
|
|
10427
|
+
};
|
|
10428
|
+
var CrossIdsColumn = class {
|
|
10429
|
+
constructor(list, codes, ids, pairs, validity) {
|
|
10430
|
+
this.list = list;
|
|
10431
|
+
this.codes = codes;
|
|
10432
|
+
this.ids = ids;
|
|
10433
|
+
this.pairs = pairs;
|
|
10434
|
+
this.validity = validity;
|
|
10435
|
+
}
|
|
10436
|
+
get length() {
|
|
10437
|
+
return this.list.length - 1;
|
|
10438
|
+
}
|
|
10439
|
+
get(i) {
|
|
10440
|
+
if (this.validity && !bitAt(this.validity, i)) return null;
|
|
10441
|
+
const out = [];
|
|
10442
|
+
for (let j = this.list[i]; j < this.list[i + 1]; j++) {
|
|
10443
|
+
const code = this.codes[j];
|
|
10444
|
+
out.push({
|
|
10445
|
+
catalogue: this.pairs.get(2 * code) ?? "",
|
|
10446
|
+
release: this.pairs.get(2 * code + 1) ?? "",
|
|
10447
|
+
catalogueId: this.ids.get(j) ?? ""
|
|
10448
|
+
});
|
|
10449
|
+
}
|
|
10450
|
+
return out;
|
|
10451
|
+
}
|
|
10452
|
+
};
|
|
10453
|
+
var BitColumn = class {
|
|
10454
|
+
constructor(bytes, length) {
|
|
10455
|
+
this.bytes = bytes;
|
|
10456
|
+
this.length = length;
|
|
10457
|
+
}
|
|
10458
|
+
get(i) {
|
|
10459
|
+
return bitAt(this.bytes, i);
|
|
10460
|
+
}
|
|
10461
|
+
};
|
|
10462
|
+
var Container = class {
|
|
10463
|
+
kind;
|
|
10464
|
+
token;
|
|
10465
|
+
rows;
|
|
10466
|
+
info;
|
|
10467
|
+
columns = /* @__PURE__ */ new Map();
|
|
10468
|
+
constructor(buffer) {
|
|
10469
|
+
this.buffer = buffer;
|
|
10470
|
+
if (buffer.byteLength < HEADER_SIZE$2) throw new ContainerFormatError("payload too short");
|
|
10471
|
+
const view = new DataView(buffer);
|
|
10472
|
+
if (decoder.decode(new Uint8Array(buffer, 0, 4)) !== "SMXS") throw new ContainerFormatError("not an extrasolar file");
|
|
10473
|
+
const version = view.getUint16(4, true);
|
|
10474
|
+
if (version !== 1) throw new ContainerFormatError(`format version ${version}, this code reads ${1}`);
|
|
10475
|
+
this.kind = view.getUint8(6);
|
|
10476
|
+
this.token = decoder.decode(new Uint8Array(buffer, TOKEN_AT, TOKEN_SIZE));
|
|
10477
|
+
this.rows = view.getUint32(24, true);
|
|
10478
|
+
const count = view.getUint16(28, true);
|
|
10479
|
+
const infoSize = view.getUint16(30, true);
|
|
10480
|
+
this.info = new DataView(buffer, HEADER_SIZE$2, infoSize);
|
|
10481
|
+
let at = HEADER_SIZE$2 + infoSize;
|
|
10482
|
+
for (let c = 0; c < count; c++) {
|
|
10483
|
+
const code = view.getUint8(at);
|
|
10484
|
+
const flags = view.getUint8(at + 1);
|
|
10485
|
+
const buffers = view.getUint8(at + 2);
|
|
10486
|
+
const nameSize = view.getUint8(at + 3);
|
|
10487
|
+
at += 4;
|
|
10488
|
+
const name = decoder.decode(new Uint8Array(buffer, at, nameSize));
|
|
10489
|
+
at += nameSize;
|
|
10490
|
+
const places = [];
|
|
10491
|
+
for (let b = 0; b < buffers; b++) {
|
|
10492
|
+
const offset = view.getUint32(at, true);
|
|
10493
|
+
const length = view.getUint32(at + 4, true);
|
|
10494
|
+
if (offset % 8 !== 0 || offset + length > buffer.byteLength) throw new ContainerFormatError(`${name}: buffer ${b} out of place`);
|
|
10495
|
+
places.push({
|
|
10496
|
+
offset,
|
|
10497
|
+
length
|
|
10498
|
+
});
|
|
10499
|
+
at += 8;
|
|
10500
|
+
}
|
|
10501
|
+
const type = TYPE_CODES[code];
|
|
10502
|
+
if (!type) throw new ContainerFormatError(`${name}: unknown type ${code}`);
|
|
10503
|
+
const first = (flags & HAS_VALIDITY) !== 0 ? places.shift() : void 0;
|
|
10504
|
+
this.columns.set(name, {
|
|
10505
|
+
type,
|
|
10506
|
+
validity: first ? new Uint8Array(buffer, first.offset, first.length) : null,
|
|
10507
|
+
places
|
|
10508
|
+
});
|
|
10509
|
+
}
|
|
10510
|
+
}
|
|
10511
|
+
names() {
|
|
10512
|
+
return [...this.columns.keys()];
|
|
10513
|
+
}
|
|
10514
|
+
has(name) {
|
|
10515
|
+
return this.columns.has(name);
|
|
10516
|
+
}
|
|
10517
|
+
type(name) {
|
|
10518
|
+
return this.entry(name).type;
|
|
10519
|
+
}
|
|
10520
|
+
isValid(name, row) {
|
|
10521
|
+
const { validity } = this.entry(name);
|
|
10522
|
+
return validity === null || bitAt(validity, row);
|
|
10523
|
+
}
|
|
10524
|
+
bool(name) {
|
|
10525
|
+
return this.numbers(name, "bool", Uint8Array);
|
|
10526
|
+
}
|
|
10527
|
+
int8(name) {
|
|
10528
|
+
return this.numbers(name, "int8", Int8Array);
|
|
10529
|
+
}
|
|
10530
|
+
int16(name) {
|
|
10531
|
+
return this.numbers(name, "int16", Int16Array);
|
|
10532
|
+
}
|
|
10533
|
+
int32(name) {
|
|
10534
|
+
return this.numbers(name, "int32", Int32Array);
|
|
10535
|
+
}
|
|
10536
|
+
uint8(name) {
|
|
10537
|
+
return this.numbers(name, "uint8", Uint8Array);
|
|
10538
|
+
}
|
|
10539
|
+
uint16(name) {
|
|
10540
|
+
return this.numbers(name, "uint16", Uint16Array);
|
|
10541
|
+
}
|
|
10542
|
+
uint32(name) {
|
|
10543
|
+
return this.numbers(name, "uint32", Uint32Array);
|
|
10544
|
+
}
|
|
10545
|
+
float32(name) {
|
|
10546
|
+
return this.numbers(name, "float32", Float32Array);
|
|
10547
|
+
}
|
|
10548
|
+
float64(name) {
|
|
10549
|
+
return this.numbers(name, "float64", Float64Array);
|
|
10550
|
+
}
|
|
10551
|
+
ids(name) {
|
|
10552
|
+
return this.numbers(name, "id", Float64Array);
|
|
10553
|
+
}
|
|
10554
|
+
strings(name) {
|
|
10555
|
+
const { validity, places } = this.typed(name, "string");
|
|
10556
|
+
return this.stringList(places[0], places[1], validity);
|
|
10557
|
+
}
|
|
10558
|
+
dict(name) {
|
|
10559
|
+
const { validity, places } = this.typed(name, "dict");
|
|
10560
|
+
const values = this.stringList(places[1], places[2], null);
|
|
10561
|
+
const strings = [];
|
|
10562
|
+
for (let k = 0; k < values.length; k++) strings.push(values.get(k) ?? "");
|
|
10563
|
+
return new DictColumn(this.view(places[0], Uint16Array), strings, validity);
|
|
10564
|
+
}
|
|
10565
|
+
crossIds(name) {
|
|
10566
|
+
const { validity, places } = this.typed(name, "cross_ids");
|
|
10567
|
+
return new CrossIdsColumn(this.view(places[0], Uint32Array), this.view(places[1], Uint16Array), this.stringList(places[2], places[3], null), this.stringList(places[4], places[5], null), validity);
|
|
10568
|
+
}
|
|
10569
|
+
bits(name) {
|
|
10570
|
+
const { places } = this.typed(name, "bits");
|
|
10571
|
+
return new BitColumn(this.view(places[0], Uint8Array), this.rows);
|
|
10572
|
+
}
|
|
10573
|
+
entry(name) {
|
|
10574
|
+
const entry = this.columns.get(name);
|
|
10575
|
+
if (!entry) throw new ContainerFormatError(`no column ${name}`);
|
|
10576
|
+
return entry;
|
|
10577
|
+
}
|
|
10578
|
+
typed(name, type) {
|
|
10579
|
+
const entry = this.entry(name);
|
|
10580
|
+
if (entry.type !== type) throw new ContainerFormatError(`${name} is ${entry.type}, not ${type}`);
|
|
10581
|
+
return entry;
|
|
10582
|
+
}
|
|
10583
|
+
numbers(name, type, Kind) {
|
|
10584
|
+
return this.view(this.typed(name, type).places[0], Kind);
|
|
10585
|
+
}
|
|
10586
|
+
view(place, Kind) {
|
|
10587
|
+
return new Kind(this.buffer, place.offset, place.length / Kind.BYTES_PER_ELEMENT);
|
|
10588
|
+
}
|
|
10589
|
+
stringList(offsets, bytes, validity) {
|
|
10590
|
+
return new StringColumn(this.view(offsets, Uint32Array), new Uint8Array(this.buffer, bytes.offset, bytes.length), validity);
|
|
10591
|
+
}
|
|
10592
|
+
};
|
|
10593
|
+
function nodeInfo(container) {
|
|
10594
|
+
const info = container.info;
|
|
10595
|
+
if (container.kind !== 3 || info.byteLength !== NODE_INFO_SIZE) throw new ContainerFormatError("not a render node");
|
|
10596
|
+
const childRange = new Float32Array(8);
|
|
10597
|
+
for (let k = 0; k < 8; k++) childRange[k] = info.getFloat32(40 + 4 * k, true);
|
|
10598
|
+
return {
|
|
10599
|
+
centre: [
|
|
10600
|
+
info.getFloat64(0, true),
|
|
10601
|
+
info.getFloat64(8, true),
|
|
10602
|
+
info.getFloat64(16, true)
|
|
10603
|
+
],
|
|
10604
|
+
half: info.getFloat64(24, true),
|
|
10605
|
+
minRange: info.getFloat32(32, true),
|
|
10606
|
+
maxRange: info.getFloat32(36, true),
|
|
10607
|
+
childRange,
|
|
10608
|
+
depth: info.getUint8(72),
|
|
10609
|
+
childMask: info.getUint8(73)
|
|
10610
|
+
};
|
|
10611
|
+
}
|
|
10612
|
+
|
|
10613
|
+
//#endregion
|
|
10614
|
+
//#region src/lib/fetch/extrasolar/files.ts
|
|
10615
|
+
var EXTRASOLAR_FORMAT = 1;
|
|
10616
|
+
var ExtrasolarStaleError = class extends Error {
|
|
10617
|
+
constructor(path, found, expected) {
|
|
10618
|
+
super(`${path}: token ${found}, expected ${expected}`);
|
|
10619
|
+
this.name = "ExtrasolarStaleError";
|
|
10620
|
+
}
|
|
10621
|
+
};
|
|
10622
|
+
function extrasolarBase() {
|
|
10623
|
+
return host().extrasolarUrl;
|
|
10624
|
+
}
|
|
10625
|
+
function extrasolarAllowed(entry) {
|
|
10626
|
+
return textureAllowed(entry.distribution);
|
|
10627
|
+
}
|
|
10628
|
+
function extrasolarPath(pattern, fields) {
|
|
10629
|
+
return pattern.replace(/\{(\w+)\}/g, (whole, key) => {
|
|
10630
|
+
const value = fields[key];
|
|
10631
|
+
if (value === void 0) throw new Error(`extrasolarPath: no ${key} for ${pattern}`);
|
|
10632
|
+
return String(value);
|
|
10633
|
+
});
|
|
10634
|
+
}
|
|
10635
|
+
function extrasolarUrl(path, token) {
|
|
10636
|
+
return `${extrasolarBase()}/v1/x/${path}?v=${token}`;
|
|
10637
|
+
}
|
|
10638
|
+
var metadataBase = null;
|
|
10639
|
+
var metadataPending = null;
|
|
10640
|
+
function fetchExtrasolarMetadata() {
|
|
10641
|
+
const base = extrasolarBase();
|
|
10642
|
+
if (metadataPending && metadataBase === base) return metadataPending;
|
|
10643
|
+
metadataBase = base;
|
|
10644
|
+
if (base === "") {
|
|
10645
|
+
metadataPending = Promise.resolve(null);
|
|
10646
|
+
return metadataPending;
|
|
10647
|
+
}
|
|
10648
|
+
const p = (async () => {
|
|
10649
|
+
const res = await fetchWithTimeout(`${base}/v1/x/metadata.json`, { cache: "no-cache" });
|
|
10650
|
+
if (!res.ok) throw new Error(`extrasolar metadata.json returned ${res.status}`);
|
|
10651
|
+
const meta = await res.json();
|
|
10652
|
+
if (meta.format !== 1) throw new Error(`extrasolar format ${meta.format}, this code reads ${1}`);
|
|
10653
|
+
return meta;
|
|
10654
|
+
})();
|
|
10655
|
+
metadataPending = p;
|
|
10656
|
+
p.catch(() => {
|
|
10657
|
+
if (metadataPending === p) metadataPending = null;
|
|
10658
|
+
});
|
|
10659
|
+
return p;
|
|
10660
|
+
}
|
|
10661
|
+
var staleListeners = /* @__PURE__ */ new Set();
|
|
10662
|
+
var staleReported = false;
|
|
10663
|
+
function onExtrasolarStale(listener) {
|
|
10664
|
+
staleListeners.add(listener);
|
|
10665
|
+
return () => staleListeners.delete(listener);
|
|
10666
|
+
}
|
|
10667
|
+
function reportStale() {
|
|
10668
|
+
if (staleReported) return;
|
|
10669
|
+
staleReported = true;
|
|
10670
|
+
for (const listener of staleListeners) listener();
|
|
10671
|
+
}
|
|
10672
|
+
async function fetchExtrasolarFile(path, token, options = {}) {
|
|
10673
|
+
const url = extrasolarUrl(path, token);
|
|
10674
|
+
const res = await fetchWithTimeout(url, {
|
|
10675
|
+
signal: options.signal,
|
|
10676
|
+
priority: options.priority
|
|
10677
|
+
});
|
|
10678
|
+
if (!res.ok) throw new Error(`${url} returned ${res.status}`);
|
|
10679
|
+
const container = new Container(await gunzip(res).arrayBuffer());
|
|
10680
|
+
if (container.token !== token) {
|
|
10681
|
+
reportStale();
|
|
10682
|
+
throw new ExtrasolarStaleError(path, container.token, token);
|
|
10683
|
+
}
|
|
10684
|
+
return container;
|
|
10685
|
+
}
|
|
10686
|
+
|
|
10687
|
+
//#endregion
|
|
10688
|
+
//#region src/lib/fetch/extrasolar/split.ts
|
|
10689
|
+
var ROOTS = 12;
|
|
10690
|
+
var SplitTree = class SplitTree {
|
|
10691
|
+
constructor(first, level) {
|
|
10692
|
+
this.first = first;
|
|
10693
|
+
this.level = level;
|
|
10694
|
+
}
|
|
10695
|
+
static fromBits(bits) {
|
|
10696
|
+
const first = [];
|
|
10697
|
+
const level = [];
|
|
10698
|
+
let at = 0;
|
|
10699
|
+
const visit = (depth, pixel) => {
|
|
10700
|
+
if (at >= bits.length) throw new ContainerFormatError("split table too short");
|
|
10701
|
+
if (!bits.get(at++)) {
|
|
10702
|
+
first.push(pixel * 4 ** (10 - depth));
|
|
10703
|
+
level.push(depth);
|
|
10704
|
+
return;
|
|
10705
|
+
}
|
|
10706
|
+
if (depth === 10) throw new ContainerFormatError("a cell cannot split");
|
|
10707
|
+
for (let k = 0; k < 4; k++) visit(depth + 1, 4 * pixel + k);
|
|
10708
|
+
};
|
|
10709
|
+
for (let root = 0; root < ROOTS; root++) visit(0, root);
|
|
10710
|
+
if (at !== bits.length) throw new ContainerFormatError(`split table has ${bits.length} bits, the tree ${at}`);
|
|
10711
|
+
return new SplitTree(Uint32Array.from(first), Uint8Array.from(level));
|
|
10712
|
+
}
|
|
10713
|
+
get leaves() {
|
|
10714
|
+
return this.first.length;
|
|
10715
|
+
}
|
|
10716
|
+
tileOf(cell) {
|
|
10717
|
+
const first = this.first;
|
|
10718
|
+
let lo = 0;
|
|
10719
|
+
let hi = first.length - 1;
|
|
10720
|
+
while (lo < hi) {
|
|
10721
|
+
const mid = lo + hi + 1 >> 1;
|
|
10722
|
+
if (first[mid] <= cell) lo = mid;
|
|
10723
|
+
else hi = mid - 1;
|
|
10724
|
+
}
|
|
10725
|
+
const level = this.level[lo];
|
|
10726
|
+
return {
|
|
10727
|
+
level,
|
|
10728
|
+
pixel: first[lo] / 4 ** (10 - level)
|
|
10729
|
+
};
|
|
10730
|
+
}
|
|
10731
|
+
};
|
|
10732
|
+
function findId(ids, id) {
|
|
10733
|
+
let lo = 0;
|
|
10734
|
+
let hi = ids.length - 1;
|
|
10735
|
+
while (lo <= hi) {
|
|
10736
|
+
const mid = lo + hi >>> 1;
|
|
10737
|
+
const at = ids[mid];
|
|
10738
|
+
if (at === id) return mid;
|
|
10739
|
+
if (at < id) lo = mid + 1;
|
|
10740
|
+
else hi = mid - 1;
|
|
10741
|
+
}
|
|
10742
|
+
return -1;
|
|
10743
|
+
}
|
|
10744
|
+
|
|
10745
|
+
//#endregion
|
|
10746
|
+
//#region src/lib/fetch/extrasolar/lookup.ts
|
|
10747
|
+
var METADATA_SLUG = "metadata";
|
|
10748
|
+
var TableRow = class {
|
|
10749
|
+
constructor(slug, table, container, row) {
|
|
10750
|
+
this.slug = slug;
|
|
10751
|
+
this.table = table;
|
|
10752
|
+
this.container = container;
|
|
10753
|
+
this.row = row;
|
|
10754
|
+
}
|
|
10755
|
+
has(name) {
|
|
10756
|
+
return this.container.has(name);
|
|
10757
|
+
}
|
|
10758
|
+
number(name) {
|
|
10759
|
+
const c = this.container;
|
|
10760
|
+
if (!c.has(name) || !c.isValid(name, this.row)) return null;
|
|
10761
|
+
let value;
|
|
10762
|
+
switch (c.type(name)) {
|
|
10763
|
+
case "float32":
|
|
10764
|
+
value = c.float32(name)[this.row];
|
|
10765
|
+
break;
|
|
10766
|
+
case "float64":
|
|
10767
|
+
value = c.float64(name)[this.row];
|
|
10768
|
+
break;
|
|
10769
|
+
case "int8":
|
|
10770
|
+
value = c.int8(name)[this.row];
|
|
10771
|
+
break;
|
|
10772
|
+
case "int16":
|
|
10773
|
+
value = c.int16(name)[this.row];
|
|
10774
|
+
break;
|
|
10775
|
+
case "int32":
|
|
10776
|
+
value = c.int32(name)[this.row];
|
|
10777
|
+
break;
|
|
10778
|
+
case "uint8":
|
|
10779
|
+
value = c.uint8(name)[this.row];
|
|
10780
|
+
break;
|
|
10781
|
+
case "uint16":
|
|
10782
|
+
value = c.uint16(name)[this.row];
|
|
10783
|
+
break;
|
|
10784
|
+
case "uint32":
|
|
10785
|
+
value = c.uint32(name)[this.row];
|
|
10786
|
+
break;
|
|
10787
|
+
case "id":
|
|
10788
|
+
value = c.ids(name)[this.row];
|
|
10789
|
+
break;
|
|
10790
|
+
default: throw new Error(`${this.slug}.${name} is not a number column`);
|
|
10791
|
+
}
|
|
10792
|
+
return Number.isNaN(value) ? null : value;
|
|
10793
|
+
}
|
|
10794
|
+
text(name) {
|
|
10795
|
+
const c = this.container;
|
|
10796
|
+
if (!c.has(name)) return null;
|
|
10797
|
+
const type = c.type(name);
|
|
10798
|
+
if (type === "dict") return c.dict(name).get(this.row);
|
|
10799
|
+
if (type === "string") return c.strings(name).get(this.row);
|
|
10800
|
+
throw new Error(`${this.slug}.${name} is not a text column`);
|
|
10801
|
+
}
|
|
10802
|
+
flag(name) {
|
|
10803
|
+
const c = this.container;
|
|
10804
|
+
if (!c.has(name) || !c.isValid(name, this.row)) return null;
|
|
10805
|
+
return c.bool(name)[this.row] === 1;
|
|
10806
|
+
}
|
|
10807
|
+
};
|
|
10808
|
+
var DEFAULT_LIMITS = {
|
|
10809
|
+
tiles: 32,
|
|
10810
|
+
results: 64
|
|
10811
|
+
};
|
|
10812
|
+
var MIN_PARALLAX_SNR = 5;
|
|
10813
|
+
function parallaxDistancePc(row) {
|
|
10814
|
+
const parallax = row.number("parallax");
|
|
10815
|
+
const error = row.number("parallax_error");
|
|
10816
|
+
if (parallax === null || error === null || !(parallax / error > MIN_PARALLAX_SNR)) return null;
|
|
10817
|
+
return 1e3 / parallax;
|
|
10818
|
+
}
|
|
10819
|
+
function homeRow(record) {
|
|
10820
|
+
return record.home && record.rows.get(record.home) || null;
|
|
10821
|
+
}
|
|
10822
|
+
function hasDistance(record) {
|
|
10823
|
+
const home = homeRow(record);
|
|
10824
|
+
return home !== null && parallaxDistancePc(home) !== null;
|
|
10825
|
+
}
|
|
10826
|
+
function readMetadataRow(c, row) {
|
|
10827
|
+
const alias = c.isValid("alias_target", row) ? c.ids("alias_target")[row] : 0;
|
|
10828
|
+
return {
|
|
10829
|
+
id: c.ids("id")[row],
|
|
10830
|
+
name: c.strings("name").get(row),
|
|
10831
|
+
nameSource: c.dict("name_source").get(row),
|
|
10832
|
+
class: c.dict("class").get(row),
|
|
10833
|
+
classSource: c.dict("class_source").get(row),
|
|
10834
|
+
crossIds: c.crossIds("cross_ids").get(row) ?? [],
|
|
10835
|
+
mask: c.uint32("mask")[row],
|
|
10836
|
+
objectFile: c.strings("object_file").get(row),
|
|
10837
|
+
aliasTarget: alias > 0 ? alias : null
|
|
10838
|
+
};
|
|
10839
|
+
}
|
|
10840
|
+
var ExtrasolarLookup = class {
|
|
10841
|
+
splits = /* @__PURE__ */ new Map();
|
|
10842
|
+
tiles;
|
|
10843
|
+
results;
|
|
10844
|
+
constructor(source, limits = DEFAULT_LIMITS) {
|
|
10845
|
+
this.source = source;
|
|
10846
|
+
this.tiles = new LruPromiseCache(limits.tiles);
|
|
10847
|
+
this.results = new LruPromiseCache(limits.results);
|
|
10848
|
+
}
|
|
10849
|
+
async live(id, options = {}) {
|
|
10850
|
+
const first = await this.lookup(id, options);
|
|
10851
|
+
return first.kind === "alias" ? this.lookup(first.target, options) : first;
|
|
10852
|
+
}
|
|
10853
|
+
lookup(id, options = {}) {
|
|
10854
|
+
const data = options.data ?? true;
|
|
10855
|
+
return this.results.getOrCompute(`${id}:${data}`, () => this.resolve(String(id), data));
|
|
10856
|
+
}
|
|
10857
|
+
async resolve(text, data) {
|
|
10858
|
+
const meta = await this.source.metadata();
|
|
10859
|
+
if (!meta) return {
|
|
10860
|
+
kind: "missing",
|
|
10861
|
+
reason: "unconfigured"
|
|
10862
|
+
};
|
|
10863
|
+
const numbered = /* @__PURE__ */ new Map();
|
|
10864
|
+
for (const [slug, table] of Object.entries(meta.tables)) if (table.number !== null) numbered.set(table.number, {
|
|
10865
|
+
slug,
|
|
10866
|
+
table
|
|
10867
|
+
});
|
|
10868
|
+
const id = parseExtrasolarId(text, new Set(numbered.keys()));
|
|
10869
|
+
if (id === null) return {
|
|
10870
|
+
kind: "missing",
|
|
10871
|
+
reason: "id"
|
|
10872
|
+
};
|
|
10873
|
+
const metaTable = meta.tables[METADATA_SLUG];
|
|
10874
|
+
if (!metaTable || !this.source.allowed(metaTable)) return {
|
|
10875
|
+
kind: "missing",
|
|
10876
|
+
reason: "barred"
|
|
10877
|
+
};
|
|
10878
|
+
const cell = cellOf(id);
|
|
10879
|
+
const home = numbered.get(tableOf(id));
|
|
10880
|
+
const homeShown = data && this.source.allowed(home.table);
|
|
10881
|
+
const [metaTile, homeTile] = await Promise.all([this.tile(METADATA_SLUG, metaTable, cell), homeShown ? this.tile(home.slug, home.table, cell) : null]);
|
|
10882
|
+
const metaRow = findId(metaTile.ids("id"), id);
|
|
10883
|
+
if (metaRow < 0) return {
|
|
10884
|
+
kind: "missing",
|
|
10885
|
+
reason: "no-row"
|
|
10886
|
+
};
|
|
10887
|
+
const metadata = readMetadataRow(metaTile, metaRow);
|
|
10888
|
+
if (metadata.aliasTarget !== null) return {
|
|
10889
|
+
kind: "alias",
|
|
10890
|
+
id,
|
|
10891
|
+
target: metadata.aliasTarget
|
|
10892
|
+
};
|
|
10893
|
+
const rows = /* @__PURE__ */ new Map();
|
|
10894
|
+
const adopt = (entry, tile) => {
|
|
10895
|
+
const row = findId(tile.ids("id"), id);
|
|
10896
|
+
if (row >= 0) rows.set(entry.slug, new TableRow(entry.slug, entry.table, tile, row));
|
|
10897
|
+
};
|
|
10898
|
+
if (homeTile) adopt(home, homeTile);
|
|
10899
|
+
if (data) {
|
|
10900
|
+
const others = [];
|
|
10901
|
+
for (let n = 1; n <= 30; n++) {
|
|
10902
|
+
const entry = numbered.get(n);
|
|
10903
|
+
if (!(metadata.mask >>> n & 1) || !entry || entry === home) continue;
|
|
10904
|
+
if (this.source.allowed(entry.table)) others.push(entry);
|
|
10905
|
+
}
|
|
10906
|
+
const tiles = await Promise.all(others.map((entry) => this.tile(entry.slug, entry.table, cell)));
|
|
10907
|
+
others.forEach((entry, i) => adopt(entry, tiles[i]));
|
|
10908
|
+
}
|
|
10909
|
+
return {
|
|
10910
|
+
kind: "live",
|
|
10911
|
+
record: {
|
|
10912
|
+
id,
|
|
10913
|
+
metadata,
|
|
10914
|
+
rows,
|
|
10915
|
+
home: home.slug,
|
|
10916
|
+
credits: meta.credits
|
|
10917
|
+
}
|
|
10918
|
+
};
|
|
10919
|
+
}
|
|
10920
|
+
split(slug, table) {
|
|
10921
|
+
const key = `${slug}?v=${table.token}`;
|
|
10922
|
+
const held = this.splits.get(key);
|
|
10923
|
+
if (held) return held;
|
|
10924
|
+
const p = this.source.file(table.split, table.token).then((c) => SplitTree.fromBits(c.bits("split")));
|
|
10925
|
+
this.splits.set(key, p);
|
|
10926
|
+
p.catch(() => {
|
|
10927
|
+
if (this.splits.get(key) === p) this.splits.delete(key);
|
|
10928
|
+
});
|
|
10929
|
+
return p;
|
|
10930
|
+
}
|
|
10931
|
+
async tile(slug, table, cell) {
|
|
10932
|
+
const split = await this.split(slug, table);
|
|
10933
|
+
const path = extrasolarPath(table.tile, split.tileOf(cell));
|
|
10934
|
+
return this.tiles.getOrCompute(`${path}?v=${table.token}`, () => this.source.file(path, table.token));
|
|
10935
|
+
}
|
|
10936
|
+
};
|
|
10937
|
+
var extrasolarLookup = new ExtrasolarLookup({
|
|
10938
|
+
metadata: fetchExtrasolarMetadata,
|
|
10939
|
+
file: (path, token) => fetchExtrasolarFile(path, token),
|
|
10940
|
+
allowed: extrasolarAllowed
|
|
10941
|
+
});
|
|
10942
|
+
|
|
10138
10943
|
//#endregion
|
|
10139
10944
|
//#region src/lib/fetch/coverage.ts
|
|
10140
10945
|
var EDGE_INSET_JD = 1 / 1440;
|
|
@@ -10147,6 +10952,10 @@ async function earthZoneEndJd() {
|
|
|
10147
10952
|
return zoom && isDateSegmented(zoom) ? unixMsToJD(lastCoveredMs(zoom)) : Infinity;
|
|
10148
10953
|
}
|
|
10149
10954
|
async function coverageOf(id) {
|
|
10955
|
+
if (isExtrasolarObjectId(id)) {
|
|
10956
|
+
const result = await extrasolarLookup.live(id.slice("x-".length));
|
|
10957
|
+
return result.kind === "live" && hasDistance(result.record) ? [[-Infinity, Infinity]] : [];
|
|
10958
|
+
}
|
|
10150
10959
|
const detail = await fetchObjectDetail(id, false);
|
|
10151
10960
|
const windows = detail.global?.coverage?.windows ?? [];
|
|
10152
10961
|
const tle = detail.global?.orbit?.scale === "planet";
|
|
@@ -11429,7 +12238,7 @@ function isLowEndDevice() {
|
|
|
11429
12238
|
return typeof mem === "number" && mem > 0 && mem <= LOW_MEMORY_GIB;
|
|
11430
12239
|
}
|
|
11431
12240
|
var coarsePointer;
|
|
11432
|
-
function isCoarsePointer() {
|
|
12241
|
+
function isCoarsePointer$1() {
|
|
11433
12242
|
if (coarsePointer === void 0) coarsePointer = typeof window !== "undefined" && !!window.matchMedia?.("(pointer: coarse)").matches;
|
|
11434
12243
|
return coarsePointer;
|
|
11435
12244
|
}
|
|
@@ -11550,7 +12359,7 @@ var ATMOSPHERE_QUALITY_PRESETS = {
|
|
|
11550
12359
|
}
|
|
11551
12360
|
};
|
|
11552
12361
|
function heuristicAtmosphereTier() {
|
|
11553
|
-
if (isCoarsePointer()) return isLowEndDevice() ? "low" : "medium";
|
|
12362
|
+
if (isCoarsePointer$1()) return isLowEndDevice() ? "low" : "medium";
|
|
11554
12363
|
return isLowEndDevice() ? "high" : "ultra";
|
|
11555
12364
|
}
|
|
11556
12365
|
function resolveAtmosphereTier(tier) {
|
|
@@ -12917,7 +13726,7 @@ function attachCanvasForwarders(el, canvas) {
|
|
|
12917
13726
|
|
|
12918
13727
|
//#endregion
|
|
12919
13728
|
//#region src/lib/scene/relief/worker.ts?worker&inline
|
|
12920
|
-
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
|
|
13729
|
+
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){return e.cap===`north`?1:e.cap===`south`?2:0}function c(e,t,n,r,i){let a=e.max_level-n;return a>=0&&s(e)===t&&r>=e.x[0]>>a&&r<=e.x[1]>>a&&i>=e.y[0]>>a&&i<=e.y[1]>>a}function l(e,t,n,r,i){return e?.find(e=>c(e,t,n,r,i))}const u=Math.sin(60*Math.PI/180),d=2**18,f=2**17;function p(e,t,n,r){return((e*32+t)*d+n)*f+r}function m(e){let t=e%f,n=Math.floor(e/f)%d,r=Math.floor(e/(f*d));return{chart:Math.floor(r/32),level:r%32,x:n,y:t}}const h={chart:0,level:0,x0:0,x1:0,y0:0,y1:0,fx:0,fy:0};function g(e,t){return e<1||Math.abs(t)<=u?0:t>0?1:2}function _(e,t,n,r,s){let c=g(e,n),l=i(c,e)*s,u=a(c,e)*s,d=o(c,t,n,r),f=d.x*l-.5,p=d.y*u-.5,m=Math.floor(f),_=Math.floor(p),v=e=>Math.min(Math.max(e,0),l-1),y=e=>Math.min(Math.max(e,0),u-1);return h.chart=c,h.level=e,h.fx=f-m,h.fy=p-_,h.x0=c===0?(m+l)%l:v(m),h.x1=c===0?(m+1)%l:v(m+1),h.y0=y(_),h.y1=y(_+1),h}function v(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 y(e,t,n,r=1/0,i=()=>!0){let a=new Set([p(0,0,0,0),p(0,0,1,0)]);return v(e,t,(e,t,o,s,c)=>{for(let e=t;;e--){let t=_(e,o,s,c,n),l=Math.floor(t.x0/n),u=Math.floor(t.x1/n),d=Math.floor(t.y0/n),f=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,f)&&i(t.chart,e,u,f)))){a.add(p(t.chart,e,l,d)),u!==l&&a.add(p(t.chart,e,u,d)),f!==d&&(a.add(p(t.chart,e,l,f)),u!==l&&a.add(p(t.chart,e,u,f)));return}}}),a}function b(e,t,n,r,i,a){for(let o=t;o>=0;o--){let t=_(o,n,r,i,a),s=(n,r)=>{let i=e(p(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 f=c+(l-c)*t.fx;return f+(u+(d-u)*t.fx-f)*t.fy}}function x(e,t,n,r,i,a){let o=new Float32Array(e.at.length*t.at.length),s=!1;return v(e,t,(e,t,c,l,u)=>{let d=b(n,t,c,l,u,r);d===void 0?s=!0:o[e]=a+i*d/65535}),s?null:o}function S(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 C(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 w(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 T=self,E=new Map;let D;async function O(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;D?.width!==i&&(D=new OffscreenCanvas(i,i));let a=D.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 k(e,t){let{rgba:n,size:r}=await O(e.url,t),i=e.fine?C(n,r):S(n,r);T.postMessage({type:`tile`,id:e.id,size:r,heights:i},[i.buffer])}const A=new Map;let j=``;async function M(r,i){let{rows:a,columns:o,tileSize:s,maxLevel:c,patches:u}=r,d=[r.version,...u.map(e=>e.version)],f=`${r.root}?${d.join()}`;f!==j&&A.clear(),j=f;let p=(e,t,n,r)=>l(u,e,t,n,r),h=y(a,o,s,c,(e,t,n,r)=>p(e,t,n,r)!==void 0),g=[...h].filter(e=>!A.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:l}=m(t),u=o>c,d=u?p(a,o,s,l)?.version:r.version,f=`${r.root}${e(n[a],o,s,l)}?v=${d}`;try{let{rgba:e,size:n}=await O(f,i);A.set(t,w(e,n,u))}catch{if(i.aborted)return}}})),i.throwIfAborted();let _=x(a,o,e=>A.get(e),s,r.scaleKm,r.biasKm);for(let e of[...A.keys()])h.has(e)||A.delete(e);if(!_)throw Error(`no height tiles for the grid`);let v=t(r.radius,a.at,o.at,_,r.unitsPerKm),b=v.indices.slice();T.postMessage({type:`grid`,id:r.id,...v,indices:b,riseKm:_},[v.positions.buffer,v.normals.buffer,v.uvs.buffer,b.buffer,_.buffer])}async function N(e){let t=new AbortController;E.set(e.id,t);try{e.type===`tile`?await k(e,t.signal):await M(e,t.signal)}catch{T.postMessage({type:`failed`,id:e.id})}finally{E.delete(e.id)}}self.onmessage=e=>{let t=e.data;t.type===`abort`?E.get(t.id)?.abort():N(t)};";
|
|
12921
13730
|
var blob$1 = typeof self !== "undefined" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", jsContent$1], { type: "text/javascript;charset=utf-8" });
|
|
12922
13731
|
function WorkerWrapper$1(options) {
|
|
12923
13732
|
let objURL;
|
|
@@ -13112,34 +13921,40 @@ function placeWindow(chart, level, x, y, previous) {
|
|
|
13112
13921
|
ty0
|
|
13113
13922
|
};
|
|
13114
13923
|
}
|
|
13115
|
-
function
|
|
13924
|
+
function patchChart(patch) {
|
|
13925
|
+
return patch.cap === "north" ? 1 : patch.cap === "south" ? 2 : 0;
|
|
13926
|
+
}
|
|
13927
|
+
function inRange(patch, chart, level, x, y) {
|
|
13116
13928
|
const up = patch.max_level - level;
|
|
13117
|
-
return up >= 0 && x >= patch.x[0] >> up && x <= patch.x[1] >> up && y >= patch.y[0] >> up && y <= patch.y[1] >> up;
|
|
13929
|
+
return up >= 0 && patchChart(patch) === chart && x >= patch.x[0] >> up && x <= patch.x[1] >> up && y >= patch.y[0] >> up && y <= patch.y[1] >> up;
|
|
13118
13930
|
}
|
|
13119
|
-
function patchOfTile(patches, level, x, y) {
|
|
13120
|
-
return patches?.find((patch) => inRange(patch, level, x, y));
|
|
13931
|
+
function patchOfTile(patches, chart, level, x, y) {
|
|
13932
|
+
return patches?.find((patch) => inRange(patch, chart, level, x, y));
|
|
13121
13933
|
}
|
|
13122
|
-
function
|
|
13123
|
-
const over = pyramid.patches?.filter((patch) => level > pyramid.max_level - (patch.map_levels ?? 0) && inRange(patch, level, x, y));
|
|
13934
|
+
function tileVersion(pyramid, chart, level, x, y) {
|
|
13935
|
+
const over = pyramid.patches?.filter((patch) => level > pyramid.max_level - (patch.map_levels ?? 0) && inRange(patch, chart, level, x, y));
|
|
13124
13936
|
return over?.length ? over.map((patch) => patch.version).join(".") : pyramid.version;
|
|
13125
13937
|
}
|
|
13126
13938
|
var REACH_TILES = 4 / 2 - .5;
|
|
13127
|
-
function deepestLevel(maxLevel, patches, x, y) {
|
|
13939
|
+
function deepestLevel(maxLevel, patches, chart, x, y) {
|
|
13128
13940
|
let deepest = maxLevel;
|
|
13129
13941
|
if (!patches) return deepest;
|
|
13130
|
-
for (const patch of patches)
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
|
|
13142
|
-
|
|
13942
|
+
for (const patch of patches) {
|
|
13943
|
+
if (patchChart(patch) !== chart) continue;
|
|
13944
|
+
for (let level = patch.max_level; level > deepest; level--) {
|
|
13945
|
+
const up = patch.max_level - level;
|
|
13946
|
+
const columns = chartColumns(chart, level);
|
|
13947
|
+
const x0 = patch.x[0] >> up;
|
|
13948
|
+
const y0 = patch.y[0] >> up;
|
|
13949
|
+
const halfWidth = ((patch.x[1] >> up) + 1 - x0) / 2;
|
|
13950
|
+
const halfHeight = ((patch.y[1] >> up) + 1 - y0) / 2;
|
|
13951
|
+
let east = x * columns - (x0 + halfWidth);
|
|
13952
|
+
if (chart === 0) east -= columns * Math.round(east / columns);
|
|
13953
|
+
const south = y * chartRows(chart, level) - (y0 + halfHeight);
|
|
13954
|
+
if (Math.abs(east) - halfWidth <= REACH_TILES && Math.abs(south) - halfHeight <= REACH_TILES) {
|
|
13955
|
+
deepest = level;
|
|
13956
|
+
break;
|
|
13957
|
+
}
|
|
13143
13958
|
}
|
|
13144
13959
|
}
|
|
13145
13960
|
return deepest;
|
|
@@ -13147,7 +13962,7 @@ function deepestLevel(maxLevel, patches, x, y) {
|
|
|
13147
13962
|
function windowHome(placement, x, y) {
|
|
13148
13963
|
const columns = chartColumns(placement.chart, placement.level);
|
|
13149
13964
|
let east = x * columns - placement.tx0;
|
|
13150
|
-
east -= columns * Math.round(east / columns);
|
|
13965
|
+
if (placement.chart === 0) east -= columns * Math.round(east / columns);
|
|
13151
13966
|
return {
|
|
13152
13967
|
x: east,
|
|
13153
13968
|
y: y * chartRows(placement.chart, placement.level) - placement.ty0
|
|
@@ -13165,6 +13980,7 @@ function slotTile(placement, sx, sy) {
|
|
|
13165
13980
|
|
|
13166
13981
|
//#endregion
|
|
13167
13982
|
//#region src/lib/scene/render-tier.ts
|
|
13983
|
+
var MB = 1024 * 1024;
|
|
13168
13984
|
var RENDER_TIER_PRESETS = {
|
|
13169
13985
|
low: {
|
|
13170
13986
|
maxPixelRatio: 1.25,
|
|
@@ -13178,7 +13994,10 @@ var RENDER_TIER_PRESETS = {
|
|
|
13178
13994
|
reliefWindows: 2,
|
|
13179
13995
|
reliefShadowSteps: 12,
|
|
13180
13996
|
terrainBandCells: 16,
|
|
13181
|
-
maxSkyboxFace: 2048
|
|
13997
|
+
maxSkyboxFace: 2048,
|
|
13998
|
+
starPoints: 12e5,
|
|
13999
|
+
starBytes: 80 * MB,
|
|
14000
|
+
starFetches: 3
|
|
13182
14001
|
},
|
|
13183
14002
|
medium: {
|
|
13184
14003
|
maxPixelRatio: 1.5,
|
|
@@ -13192,7 +14011,10 @@ var RENDER_TIER_PRESETS = {
|
|
|
13192
14011
|
reliefWindows: 3,
|
|
13193
14012
|
reliefShadowSteps: 16,
|
|
13194
14013
|
terrainBandCells: 24,
|
|
13195
|
-
maxSkyboxFace: 2048
|
|
14014
|
+
maxSkyboxFace: 2048,
|
|
14015
|
+
starPoints: 16e5,
|
|
14016
|
+
starBytes: 160 * MB,
|
|
14017
|
+
starFetches: 4
|
|
13196
14018
|
},
|
|
13197
14019
|
high: {
|
|
13198
14020
|
maxPixelRatio: 2,
|
|
@@ -13206,7 +14028,10 @@ var RENDER_TIER_PRESETS = {
|
|
|
13206
14028
|
reliefWindows: 4,
|
|
13207
14029
|
reliefShadowSteps: 32,
|
|
13208
14030
|
terrainBandCells: 32,
|
|
13209
|
-
maxSkyboxFace: Infinity
|
|
14031
|
+
maxSkyboxFace: Infinity,
|
|
14032
|
+
starPoints: 25e5,
|
|
14033
|
+
starBytes: 400 * MB,
|
|
14034
|
+
starFetches: 6
|
|
13210
14035
|
}
|
|
13211
14036
|
};
|
|
13212
14037
|
function maxTextureTier() {
|
|
@@ -13228,7 +14053,7 @@ function resolveRenderTier() {
|
|
|
13228
14053
|
const measured = sceneSettings().atmosphereCalibration?.tier;
|
|
13229
14054
|
if (measured === "low" || measured === "medium") return measured;
|
|
13230
14055
|
if (measured === "high" || measured === "ultra") return "high";
|
|
13231
|
-
if (isCoarsePointer()) return isLowEndDevice() ? "low" : "medium";
|
|
14056
|
+
if (isCoarsePointer$1()) return isLowEndDevice() ? "low" : "medium";
|
|
13232
14057
|
return isLowEndDevice() ? "medium" : "high";
|
|
13233
14058
|
}
|
|
13234
14059
|
function currentRenderTier() {
|
|
@@ -13238,6 +14063,15 @@ function renderPixelRatio() {
|
|
|
13238
14063
|
if (typeof window === "undefined") return 1;
|
|
13239
14064
|
return Math.min(window.devicePixelRatio, currentRenderTier().maxPixelRatio);
|
|
13240
14065
|
}
|
|
14066
|
+
function starBudget() {
|
|
14067
|
+
const tier = currentRenderTier();
|
|
14068
|
+
const bytes = isLowEndDevice() ? Math.min(tier.starBytes, 64 * MB) : tier.starBytes;
|
|
14069
|
+
return {
|
|
14070
|
+
points: tier.starPoints,
|
|
14071
|
+
bytes,
|
|
14072
|
+
fetches: tier.starFetches
|
|
14073
|
+
};
|
|
14074
|
+
}
|
|
13241
14075
|
|
|
13242
14076
|
//#endregion
|
|
13243
14077
|
//#region src/lib/scene/objects/surface/tile-chain.ts
|
|
@@ -13271,9 +14105,9 @@ void tileCap( vec3 dir, vec3 ddx, vec3 ddy, out float side, out mat3x2 cap ) {
|
|
|
13271
14105
|
);
|
|
13272
14106
|
}
|
|
13273
14107
|
|
|
13274
|
-
// The point at + off on the map
|
|
13275
|
-
//
|
|
13276
|
-
// and a tile index of a patch takes them all
|
|
14108
|
+
// The point at + off on the map and on the cap of its own hemisphere, which
|
|
14109
|
+
// side gives, each counted from at. A position on the sphere has seven
|
|
14110
|
+
// digits, and a tile index of a patch takes them all. The offset keeps its own.
|
|
13277
14111
|
void tileChartsFrom( vec3 at, vec3 off, out mat3x2 map, out mat3x2 cap, out float side ) {
|
|
13278
14112
|
vec3 pos = at + off;
|
|
13279
14113
|
vec3 ox = dFdx( off );
|
|
@@ -13295,12 +14129,19 @@ void tileChartsFrom( vec3 at, vec3 off, out mat3x2 map, out mat3x2 cap, out floa
|
|
|
13295
14129
|
( pos.z * oy.x - pos.x * oy.z ) * east, ( pos.y * ( pos.x * oy.x + pos.z * oy.z ) / flat1 - flat1 * oy.y ) * south
|
|
13296
14130
|
);
|
|
13297
14131
|
|
|
13298
|
-
// A cap goes no deeper than the pyramid, so the direction itself will do.
|
|
13299
14132
|
float range = length( pos );
|
|
13300
14133
|
vec3 dir = pos / range;
|
|
13301
14134
|
vec3 ddx = ( ox - dir * dot( dir, ox ) ) / range;
|
|
13302
14135
|
vec3 ddy = ( oy - dir * dot( dir, oy ) ) / range;
|
|
13303
14136
|
tileCap( dir, ddx, ddy, side, cap );
|
|
14137
|
+
|
|
14138
|
+
// The point on the cap, counted from at.
|
|
14139
|
+
float reach = length( at );
|
|
14140
|
+
float foldAt = max( reach + side * at.y, 1e-6 * reach );
|
|
14141
|
+
float grow = ( 2.0 * dot( at, off ) + dot( off, off ) ) / ( range + reach );
|
|
14142
|
+
vec2 planeAt = vec2( at.x, side * at.z );
|
|
14143
|
+
vec2 shift = vec2( off.x, side * off.z ) * foldAt - planeAt * ( grow + side * off.y );
|
|
14144
|
+
cap[ 0 ] = shift / ( ( range + side * pos.y ) * foldAt ) * ( 0.5 / ${CAP_EDGE.toFixed(8)} );
|
|
13304
14145
|
}
|
|
13305
14146
|
|
|
13306
14147
|
// Long and short half-axes of the footprint whose sides are fx and fy. The
|
|
@@ -13343,7 +14184,7 @@ float tileWindowWeight( mat3x2 map, mat3x2 cap, float side, vec4 window, vec4 gr
|
|
|
13343
14184
|
|
|
13344
14185
|
float rows = ${4 .toFixed(1)};
|
|
13345
14186
|
// Offset from the window's north-west corner, in tiles.
|
|
13346
|
-
vec2 rel =
|
|
14187
|
+
vec2 rel = home + chart[ 0 ] * grid.xy;
|
|
13347
14188
|
if ( onMap ) {
|
|
13348
14189
|
// Half a pixel in from a pole of the map: past it the filter would
|
|
13349
14190
|
// read the far row. The map's longitude wraps.
|
|
@@ -13445,8 +14286,8 @@ function release(store, win) {
|
|
|
13445
14286
|
store.free.push(win.layer);
|
|
13446
14287
|
}
|
|
13447
14288
|
function patchOf(tiles, win, tile) {
|
|
13448
|
-
if (win.
|
|
13449
|
-
return patchOfTile(tiles.patches, win.level, tile.x, tile.y);
|
|
14289
|
+
if (win.level <= tiles.max_level) return void 0;
|
|
14290
|
+
return patchOfTile(tiles.patches, win.chart, win.level, tile.x, tile.y);
|
|
13450
14291
|
}
|
|
13451
14292
|
function exists(tiles, win, slot) {
|
|
13452
14293
|
if (win.level <= tiles.max_level) return true;
|
|
@@ -13502,7 +14343,7 @@ function pump(chain, store, tiles, win, x, y, renderer, invalidate) {
|
|
|
13502
14343
|
});
|
|
13503
14344
|
chain.inflight++;
|
|
13504
14345
|
const folder = CHART_FOLDER[win.chart];
|
|
13505
|
-
const version = patchOf(tiles, win, tile)?.version ?? (win.chart
|
|
14346
|
+
const version = patchOf(tiles, win, tile)?.version ?? tileVersion(tiles, win.chart, win.level, tile.x, tile.y);
|
|
13506
14347
|
const pyramid = {
|
|
13507
14348
|
id: tiles.id,
|
|
13508
14349
|
version
|
|
@@ -13557,9 +14398,9 @@ function pointUnderCamera(mesh, camera) {
|
|
|
13557
14398
|
return over.copy(camera.position).applyMatrix4(inverse.copy(mesh.matrixWorld).invert()).normalize();
|
|
13558
14399
|
}
|
|
13559
14400
|
function finestLevelAt$1(chain, tiles, over) {
|
|
13560
|
-
|
|
13561
|
-
const point = chartPoint(
|
|
13562
|
-
return deepestLevel(tiles.max_level, tiles.patches, point.x, point.y);
|
|
14401
|
+
const chart = cameraChart(over.y, chain?.chart);
|
|
14402
|
+
const point = chartPoint(chart, over.x, over.y, over.z);
|
|
14403
|
+
return deepestLevel(tiles.max_level, tiles.patches, chart, point.x, point.y);
|
|
13563
14404
|
}
|
|
13564
14405
|
function chainLength(tiles, limit) {
|
|
13565
14406
|
let finest = tiles.max_level;
|
|
@@ -13581,7 +14422,11 @@ function updateChain(chain, tiles, count, level, over, radius, frame, renderer,
|
|
|
13581
14422
|
anchor.set(Math.fround(over.x * radius), Math.fround(over.y * radius), Math.fround(over.z * radius));
|
|
13582
14423
|
chain.uniforms.anchor.value.copy(anchor);
|
|
13583
14424
|
const range = anchor.length();
|
|
13584
|
-
const
|
|
14425
|
+
const homes = [
|
|
14426
|
+
0,
|
|
14427
|
+
1,
|
|
14428
|
+
2
|
|
14429
|
+
].map((chart) => chartPoint(chart, anchor.x / range, anchor.y / range, anchor.z / range));
|
|
13585
14430
|
const windowOf = (link) => store.windows.find((win) => win.chart === link.chart && win.level === link.level);
|
|
13586
14431
|
store.windows = store.windows.filter((win) => {
|
|
13587
14432
|
win.rank = links.findIndex((link) => link.chart === win.chart && link.level === win.level);
|
|
@@ -13622,10 +14467,9 @@ function updateChain(chain, tiles, count, level, over, radius, frame, renderer,
|
|
|
13622
14467
|
continue;
|
|
13623
14468
|
}
|
|
13624
14469
|
chain.uniforms.grid.value[i].set(chartColumns(win.chart, win.level), chartRows(win.chart, win.level), win.placement.tx0, win.placement.ty0);
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
}
|
|
14470
|
+
const home = homes[win.chart];
|
|
14471
|
+
const from = windowHome(win.placement, home.x, home.y);
|
|
14472
|
+
chain.uniforms.home.value[i].set(from.x, from.y);
|
|
13629
14473
|
link.set(win.chart, win.layer, win.level, 1);
|
|
13630
14474
|
let loaded = 0;
|
|
13631
14475
|
for (let slot = 0; slot < SLOTS; slot++) if (isLoaded(store, win.layer, slot)) loaded |= 1 << slot;
|
|
@@ -13740,10 +14584,10 @@ void reliefSight( int i, mat3x2 map, mat3x2 cap, float side, vec2 mapStep, vec2
|
|
|
13740
14584
|
vec4 grid = uReliefGrid[ i ];
|
|
13741
14585
|
bool onMap = window.x < 0.5;
|
|
13742
14586
|
float rows = ${4 .toFixed(1)};
|
|
13743
|
-
// In tiles from the window's north-west corner
|
|
13744
|
-
//
|
|
13745
|
-
// nearest the window.
|
|
13746
|
-
vec2 rel =
|
|
14587
|
+
// In tiles from the window's north-west corner, counted from the point
|
|
14588
|
+
// under the camera. On the map the fragment is then on the side of the
|
|
14589
|
+
// globe nearest the window.
|
|
14590
|
+
vec2 rel = uReliefHome[ i ] + ( onMap ? map[ 0 ] : cap[ 0 ] ) * grid.xy;
|
|
13747
14591
|
vec2 rate = ( onMap ? mapStep : capStep ) * grid.xy;
|
|
13748
14592
|
|
|
13749
14593
|
// Half a pixel in from the window's sides: past it the filter reads the
|
|
@@ -17356,7 +18200,7 @@ function setLabelName(bo, name, variant, isLarge) {
|
|
|
17356
18200
|
}
|
|
17357
18201
|
function getLabelVariant(body) {
|
|
17358
18202
|
const t = body.data.objectType;
|
|
17359
|
-
if (isMajorBody(t) || t === ObjectType.STAR || isAsteroid(t) || t === ObjectType.COMET || t === ObjectType.BARYCENTER || t === ObjectType.LAGRANGE_POINT) return "major";
|
|
18203
|
+
if (isMajorBody(t) || t === ObjectType.STAR || t === ObjectType.EXTRASOLAR || isAsteroid(t) || t === ObjectType.COMET || t === ObjectType.BARYCENTER || t === ObjectType.LAGRANGE_POINT) return "major";
|
|
17360
18204
|
if (t === ObjectType.SPACECRAFT) return "spacecraft";
|
|
17361
18205
|
if (t === ObjectType.DEBRIS) return "debris";
|
|
17362
18206
|
return "none";
|
|
@@ -18315,6 +19159,231 @@ async function loadSkybox(scene, renderer, ctx, disposed = () => false) {
|
|
|
18315
19159
|
}
|
|
18316
19160
|
}
|
|
18317
19161
|
|
|
19162
|
+
//#endregion
|
|
19163
|
+
//#region src/lib/scene/starfield/tree.ts
|
|
19164
|
+
var PC_AU = 648e3 / Math.PI;
|
|
19165
|
+
var PC_SCENE = PC_AU * 10;
|
|
19166
|
+
function childCentre(centre, half, k) {
|
|
19167
|
+
const q = half / 2;
|
|
19168
|
+
return [
|
|
19169
|
+
centre[0] + (k & 1 ? q : -q),
|
|
19170
|
+
centre[1] + (k & 2 ? q : -q),
|
|
19171
|
+
centre[2] + (k & 4 ? q : -q)
|
|
19172
|
+
];
|
|
19173
|
+
}
|
|
19174
|
+
function boxDistance(p, centre, half) {
|
|
19175
|
+
const dx = Math.max(Math.abs(p[0] - centre[0]) - half, 0);
|
|
19176
|
+
const dy = Math.max(Math.abs(p[1] - centre[1]) - half, 0);
|
|
19177
|
+
const dz = Math.max(Math.abs(p[2] - centre[2]) - half, 0);
|
|
19178
|
+
return Math.hypot(dx, dy, dz);
|
|
19179
|
+
}
|
|
19180
|
+
function boxMagnitude(distance, range, rangeLimitMag) {
|
|
19181
|
+
if (distance <= 0) return -Infinity;
|
|
19182
|
+
if (range <= 0) return Infinity;
|
|
19183
|
+
return rangeLimitMag + 5 * Math.log10(distance / range);
|
|
19184
|
+
}
|
|
19185
|
+
function sceneToTree(x, y, z) {
|
|
19186
|
+
const eq = sceneToEquatorial(x, y, z, {
|
|
19187
|
+
x: 0,
|
|
19188
|
+
y: 0,
|
|
19189
|
+
z: 0
|
|
19190
|
+
});
|
|
19191
|
+
return [
|
|
19192
|
+
eq.x / PC_SCENE,
|
|
19193
|
+
eq.y / PC_SCENE,
|
|
19194
|
+
eq.z / PC_SCENE
|
|
19195
|
+
];
|
|
19196
|
+
}
|
|
19197
|
+
function treeToScene(x, y, z, out) {
|
|
19198
|
+
return equatorialToScene(x * PC_SCENE, y * PC_SCENE, z * PC_SCENE, out);
|
|
19199
|
+
}
|
|
19200
|
+
function icrsToTree(raDeg, decDeg, distancePc) {
|
|
19201
|
+
const ra = raDeg * Math.PI / 180;
|
|
19202
|
+
const dec = decDeg * Math.PI / 180;
|
|
19203
|
+
const c = Math.cos(dec) * distancePc;
|
|
19204
|
+
return [
|
|
19205
|
+
c * Math.cos(ra),
|
|
19206
|
+
c * Math.sin(ra),
|
|
19207
|
+
Math.sin(dec) * distancePc
|
|
19208
|
+
];
|
|
19209
|
+
}
|
|
19210
|
+
function treeMatrixElements(focus, out) {
|
|
19211
|
+
const x = treeToScene(1, 0, 0, {
|
|
19212
|
+
x: 0,
|
|
19213
|
+
y: 0,
|
|
19214
|
+
z: 0
|
|
19215
|
+
});
|
|
19216
|
+
const y = treeToScene(0, 1, 0, {
|
|
19217
|
+
x: 0,
|
|
19218
|
+
y: 0,
|
|
19219
|
+
z: 0
|
|
19220
|
+
});
|
|
19221
|
+
const z = treeToScene(0, 0, 1, {
|
|
19222
|
+
x: 0,
|
|
19223
|
+
y: 0,
|
|
19224
|
+
z: 0
|
|
19225
|
+
});
|
|
19226
|
+
out.length = 16;
|
|
19227
|
+
out[0] = x.x;
|
|
19228
|
+
out[1] = x.y;
|
|
19229
|
+
out[2] = x.z;
|
|
19230
|
+
out[3] = 0;
|
|
19231
|
+
out[4] = y.x;
|
|
19232
|
+
out[5] = y.y;
|
|
19233
|
+
out[6] = y.z;
|
|
19234
|
+
out[7] = 0;
|
|
19235
|
+
out[8] = z.x;
|
|
19236
|
+
out[9] = z.y;
|
|
19237
|
+
out[10] = z.z;
|
|
19238
|
+
out[11] = 0;
|
|
19239
|
+
out[12] = -focus[0];
|
|
19240
|
+
out[13] = -focus[1];
|
|
19241
|
+
out[14] = -focus[2];
|
|
19242
|
+
out[15] = 1;
|
|
19243
|
+
return out;
|
|
19244
|
+
}
|
|
19245
|
+
|
|
19246
|
+
//#endregion
|
|
19247
|
+
//#region src/lib/scene/starfield/record.ts
|
|
19248
|
+
var RENDER_EPOCH = 2016;
|
|
19249
|
+
var MAG_STEP = 1 / 1024;
|
|
19250
|
+
var G_MINUS_V = [
|
|
19251
|
+
-.02907,
|
|
19252
|
+
-.02385,
|
|
19253
|
+
-.2297,
|
|
19254
|
+
-.001768
|
|
19255
|
+
];
|
|
19256
|
+
var B_V_RANGE = [-.3, 2.4];
|
|
19257
|
+
var G_MINUS_HP = -.28;
|
|
19258
|
+
var BP_RP_FROM_V_I = [
|
|
19259
|
+
-.01612,
|
|
19260
|
+
1.274,
|
|
19261
|
+
-.08143
|
|
19262
|
+
];
|
|
19263
|
+
var V_I_RANGE = [-.5, 3.5];
|
|
19264
|
+
var MAS_PER_RAD = 180 / Math.PI * 36e5;
|
|
19265
|
+
function clamp$3(x, [lo, hi]) {
|
|
19266
|
+
return Math.min(Math.max(x, lo), hi);
|
|
19267
|
+
}
|
|
19268
|
+
function poly(x, coefficients) {
|
|
19269
|
+
let out = 0;
|
|
19270
|
+
for (let i = coefficients.length - 1; i >= 0; i--) out = out * x + coefficients[i];
|
|
19271
|
+
return out;
|
|
19272
|
+
}
|
|
19273
|
+
function propagate(raDeg, decDeg, pmra, pmdec, years) {
|
|
19274
|
+
const ra = raDeg * Math.PI / 180;
|
|
19275
|
+
const dec = decDeg * Math.PI / 180;
|
|
19276
|
+
const rate = years / MAS_PER_RAD;
|
|
19277
|
+
const [cr, sr, cd, sd] = [
|
|
19278
|
+
Math.cos(ra),
|
|
19279
|
+
Math.sin(ra),
|
|
19280
|
+
Math.cos(dec),
|
|
19281
|
+
Math.sin(dec)
|
|
19282
|
+
];
|
|
19283
|
+
const x = cd * cr + rate * (pmra * -sr + pmdec * -sd * cr);
|
|
19284
|
+
const y = cd * sr + rate * (pmra * cr + pmdec * -sd * sr);
|
|
19285
|
+
const z = sd + rate * (pmdec * cd);
|
|
19286
|
+
const n = Math.hypot(x, y, z);
|
|
19287
|
+
return [(Math.atan2(y / n, x / n) * 180 / Math.PI % 360 + 360) % 360, Math.asin(Math.min(Math.max(z / n, -1), 1)) * 180 / Math.PI];
|
|
19288
|
+
}
|
|
19289
|
+
function starPlace(row) {
|
|
19290
|
+
const distancePc = parallaxDistancePc(row);
|
|
19291
|
+
let ra = row.number("ra");
|
|
19292
|
+
let dec = row.number("dec");
|
|
19293
|
+
if (distancePc === null || ra === null || dec === null) return null;
|
|
19294
|
+
const years = RENDER_EPOCH - (row.number("epoch") ?? 2016);
|
|
19295
|
+
const pmra = row.number("pmra");
|
|
19296
|
+
if (years !== 0 && pmra !== null) [ra, dec] = propagate(ra, dec, pmra, row.number("pmdec") ?? 0, years);
|
|
19297
|
+
const tree = icrsToTree(ra, dec, distancePc);
|
|
19298
|
+
const s = treeToScene(tree[0], tree[1], tree[2], {
|
|
19299
|
+
x: 0,
|
|
19300
|
+
y: 0,
|
|
19301
|
+
z: 0
|
|
19302
|
+
});
|
|
19303
|
+
return {
|
|
19304
|
+
ra,
|
|
19305
|
+
dec,
|
|
19306
|
+
distancePc,
|
|
19307
|
+
tree,
|
|
19308
|
+
scene: [
|
|
19309
|
+
s.x,
|
|
19310
|
+
s.y,
|
|
19311
|
+
s.z
|
|
19312
|
+
]
|
|
19313
|
+
};
|
|
19314
|
+
}
|
|
19315
|
+
function gEstimate(v, bv, hp) {
|
|
19316
|
+
if (v !== null && bv !== null) return v + poly(clamp$3(bv, B_V_RANGE), G_MINUS_V);
|
|
19317
|
+
return hp === null ? null : hp + G_MINUS_HP;
|
|
19318
|
+
}
|
|
19319
|
+
function apparentG(row) {
|
|
19320
|
+
return row.number("phot_g_mean_mag") ?? gEstimate(row.number("v_mag"), row.number("b_v"), row.number("hp_mag"));
|
|
19321
|
+
}
|
|
19322
|
+
function absoluteG(row) {
|
|
19323
|
+
const g = apparentG(row);
|
|
19324
|
+
const parallax = row.number("parallax");
|
|
19325
|
+
if (g === null || parallaxDistancePc(row) === null || parallax === null) return null;
|
|
19326
|
+
return Math.round((g + 5 * Math.log10(parallax) - 10) / MAG_STEP) * MAG_STEP;
|
|
19327
|
+
}
|
|
19328
|
+
function colourBpRp(row) {
|
|
19329
|
+
const bp = row.number("phot_bp_mean_mag");
|
|
19330
|
+
const rp = row.number("phot_rp_mean_mag");
|
|
19331
|
+
if (bp !== null && rp !== null) return bp - rp;
|
|
19332
|
+
const vi = row.number("v_i");
|
|
19333
|
+
return vi === null ? null : poly(clamp$3(vi, V_I_RANGE), BP_RP_FROM_V_I);
|
|
19334
|
+
}
|
|
19335
|
+
|
|
19336
|
+
//#endregion
|
|
19337
|
+
//#region src/lib/scene/focus/star-focus.ts
|
|
19338
|
+
function makeStarBody(record) {
|
|
19339
|
+
const home = homeRow(record);
|
|
19340
|
+
const place = home ? starPlace(home) : null;
|
|
19341
|
+
return {
|
|
19342
|
+
data: {
|
|
19343
|
+
id: extrasolarObjectId(record.id),
|
|
19344
|
+
name: record.metadata.name,
|
|
19345
|
+
objectType: ObjectType.EXTRASOLAR,
|
|
19346
|
+
parentId: "",
|
|
19347
|
+
radiusKm: NaN,
|
|
19348
|
+
hasLocalized: false,
|
|
19349
|
+
a: 0,
|
|
19350
|
+
e: 0,
|
|
19351
|
+
i: 0,
|
|
19352
|
+
om: 0,
|
|
19353
|
+
w: 0,
|
|
19354
|
+
ma: 0,
|
|
19355
|
+
n: 0,
|
|
19356
|
+
epoch: 0,
|
|
19357
|
+
validityStart: -Infinity,
|
|
19358
|
+
validityEnd: Infinity,
|
|
19359
|
+
orbitalSource: OrbitalSource.UNKNOWN
|
|
19360
|
+
},
|
|
19361
|
+
position: null,
|
|
19362
|
+
extrasolar: {
|
|
19363
|
+
id: record.id,
|
|
19364
|
+
record,
|
|
19365
|
+
scene: place?.scene ?? null,
|
|
19366
|
+
tree: place?.tree ?? null,
|
|
19367
|
+
absMag: home ? absoluteG(home) : null,
|
|
19368
|
+
colour: home ? colourBpRp(home) : null
|
|
19369
|
+
}
|
|
19370
|
+
};
|
|
19371
|
+
}
|
|
19372
|
+
|
|
19373
|
+
//#endregion
|
|
19374
|
+
//#region src/lib/scene/setup/extrasolar.ts
|
|
19375
|
+
async function ensureExtrasolarBody(ctx, objectId) {
|
|
19376
|
+
const text = objectId.slice("x-".length);
|
|
19377
|
+
const first = await extrasolarLookup.lookup(text);
|
|
19378
|
+
const result = first.kind === "alias" ? await extrasolarLookup.live(text) : first;
|
|
19379
|
+
if (result.kind === "live") {
|
|
19380
|
+
const held = ctx.getBody(extrasolarObjectId(result.record.id));
|
|
19381
|
+
const body = held?.extrasolar ? held : makeStarBody(result.record);
|
|
19382
|
+
ctx.bodies.addExtrasolar(body, first.kind === "alias" ? [objectId] : []);
|
|
19383
|
+
}
|
|
19384
|
+
return result;
|
|
19385
|
+
}
|
|
19386
|
+
|
|
18318
19387
|
//#endregion
|
|
18319
19388
|
//#region src/lib/scene/setup/scene-load.ts
|
|
18320
19389
|
var EAGER_ZOOM1_PARTS = 13;
|
|
@@ -18423,6 +19492,7 @@ async function loadScene(ctx, date, targetId) {
|
|
|
18423
19492
|
});
|
|
18424
19493
|
const probePromise = metadataPromise.then((metadata) => buildProbeStore(metadata, jd, ctx.layers));
|
|
18425
19494
|
const passengerPromise = passengerFor(targetId);
|
|
19495
|
+
const extrasolarTarget = targetId && isExtrasolarObjectId(targetId) ? ensureExtrasolarBody(ctx, targetId).catch((e) => console.warn(`scene-load: ${targetId} did not load:`, e)) : null;
|
|
18426
19496
|
const metadata = await metadataPromise;
|
|
18427
19497
|
loadProgress.reach("metadata");
|
|
18428
19498
|
ctx.chebStore = await chebPromise;
|
|
@@ -18448,7 +19518,8 @@ async function loadScene(ctx, date, targetId) {
|
|
|
18448
19518
|
addedSinceFlush = false;
|
|
18449
19519
|
ctx.bodies.flushMinor(added);
|
|
18450
19520
|
};
|
|
18451
|
-
if (
|
|
19521
|
+
if (extrasolarTarget) await extrasolarTarget;
|
|
19522
|
+
else if (targetId && !ctx.getBody(targetId)) {
|
|
18452
19523
|
const placeholders = await createPlaceholderBody(targetId, ctx);
|
|
18453
19524
|
if (routePlaceholders(ctx, placeholders, labels) > 0) noteAdded();
|
|
18454
19525
|
if (placeholders.length > 0) flush();
|
|
@@ -18456,7 +19527,7 @@ async function loadScene(ctx, date, targetId) {
|
|
|
18456
19527
|
ctx.bodies.majorBodies = major.filter((b) => b.data.objectType !== ObjectType.BARYCENTER && b.data.objectType !== ObjectType.LAGRANGE_POINT && b.data.orbitalSource !== OrbitalSource.SPICE_PROBE);
|
|
18457
19528
|
try {
|
|
18458
19529
|
ctx.refresher = new ZoneRefresher(ctx, metadata, loader, date);
|
|
18459
|
-
if (targetId) ctx.refresher.want(targetId);
|
|
19530
|
+
if (targetId && !extrasolarTarget) ctx.refresher.want(targetId);
|
|
18460
19531
|
} catch (e) {
|
|
18461
19532
|
console.error("scene-load: ZoneRefresher init failed; time-segmented zones stay empty:", e);
|
|
18462
19533
|
}
|
|
@@ -18625,12 +19696,17 @@ var ContextManager = class {
|
|
|
18625
19696
|
console.error("[scene-load]", e);
|
|
18626
19697
|
}
|
|
18627
19698
|
refreshTick(date) {
|
|
19699
|
+
if (this.visibility.systemShare === 0) return;
|
|
18628
19700
|
this.refresher?.tick(date);
|
|
18629
19701
|
}
|
|
18630
19702
|
async ready(date) {
|
|
18631
19703
|
await this.refresher?.ready(date);
|
|
18632
19704
|
}
|
|
18633
19705
|
async ensureBody(targetId, date) {
|
|
19706
|
+
if (isExtrasolarObjectId(targetId)) {
|
|
19707
|
+
await ensureExtrasolarBody(this, targetId);
|
|
19708
|
+
return;
|
|
19709
|
+
}
|
|
18634
19710
|
await this.refresher?.ensureBody(targetId, date);
|
|
18635
19711
|
}
|
|
18636
19712
|
applyGroupFilter(slug) {
|
|
@@ -19342,6 +20418,9 @@ function installOutputDither(pass) {
|
|
|
19342
20418
|
//#endregion
|
|
19343
20419
|
//#region src/lib/scene/setup/three-boot.ts
|
|
19344
20420
|
var CAMERA_FAR_DEFAULT = 1e5;
|
|
20421
|
+
var CAMERA_MAX_DISTANCE = 1e5 * PC_SCENE;
|
|
20422
|
+
var SOLAR_MAX_DISTANCE = 31620.5 * 10;
|
|
20423
|
+
var CAMERA_FAR_REVERSED = 1e6 * PC_SCENE;
|
|
19345
20424
|
function probeClipControl() {
|
|
19346
20425
|
try {
|
|
19347
20426
|
const gl = document.createElement("canvas").getContext("webgl2");
|
|
@@ -19395,7 +20474,9 @@ function bootThree(canvas, labelContainer, ctx) {
|
|
|
19395
20474
|
shadowLight.shadow.bias = -1e-4;
|
|
19396
20475
|
scene.add(shadowLight);
|
|
19397
20476
|
scene.add(shadowLight.target);
|
|
19398
|
-
const
|
|
20477
|
+
const aspect = canvas.clientWidth / canvas.clientHeight;
|
|
20478
|
+
const far = renderer.capabilities.reversedDepthBuffer ? CAMERA_FAR_REVERSED : CAMERA_FAR_DEFAULT;
|
|
20479
|
+
const camera = new PerspectiveCamera(60, aspect, kmToScene(.001), far);
|
|
19399
20480
|
const composerTarget = new WebGLRenderTarget(canvas.clientWidth, canvas.clientHeight, {
|
|
19400
20481
|
type: HalfFloatType,
|
|
19401
20482
|
resolveDepthBuffer: false,
|
|
@@ -19427,38 +20508,1006 @@ function bootThree(canvas, labelContainer, ctx) {
|
|
|
19427
20508
|
};
|
|
19428
20509
|
}
|
|
19429
20510
|
|
|
20511
|
+
//#endregion
|
|
20512
|
+
//#region src/lib/scene/starfield/band.ts
|
|
20513
|
+
var STARS_IN_AU = 2e3;
|
|
20514
|
+
var STARS_OUT_AU = 1800;
|
|
20515
|
+
function starsTakeSky(distanceAu, taken) {
|
|
20516
|
+
if (distanceAu > 2e3) return true;
|
|
20517
|
+
if (distanceAu < 1800) return false;
|
|
20518
|
+
return taken;
|
|
20519
|
+
}
|
|
20520
|
+
|
|
20521
|
+
//#endregion
|
|
20522
|
+
//#region src/lib/scene/starfield/colour.ts
|
|
20523
|
+
var BP_RP_TEFF = [
|
|
20524
|
+
[-.12, 10700],
|
|
20525
|
+
[-.087, 10400],
|
|
20526
|
+
[-.037, 9700],
|
|
20527
|
+
[.005, 9300],
|
|
20528
|
+
[.068, 8800],
|
|
20529
|
+
[.11, 8600],
|
|
20530
|
+
[.166, 8250],
|
|
20531
|
+
[.194, 8100],
|
|
20532
|
+
[.222, 7910],
|
|
20533
|
+
[.263, 7760],
|
|
20534
|
+
[.32, 7590],
|
|
20535
|
+
[.327, 7400],
|
|
20536
|
+
[.377, 7220],
|
|
20537
|
+
[.434, 7020],
|
|
20538
|
+
[.49, 6820],
|
|
20539
|
+
[.518, 6750],
|
|
20540
|
+
[.546, 6670],
|
|
20541
|
+
[.587, 6550],
|
|
20542
|
+
[.64, 6350],
|
|
20543
|
+
[.67, 6280],
|
|
20544
|
+
[.694, 6180],
|
|
20545
|
+
[.719, 6050],
|
|
20546
|
+
[.767, 5990],
|
|
20547
|
+
[.784, 5930],
|
|
20548
|
+
[.803, 5860],
|
|
20549
|
+
[.823, 5770],
|
|
20550
|
+
[.832, 5720],
|
|
20551
|
+
[.841, 5680],
|
|
20552
|
+
[.85, 5660],
|
|
20553
|
+
[.869, 5600],
|
|
20554
|
+
[.88, 5550],
|
|
20555
|
+
[.9, 5480],
|
|
20556
|
+
[.95, 5380],
|
|
20557
|
+
[.983, 5270],
|
|
20558
|
+
[1.01, 5170],
|
|
20559
|
+
[1.1, 5100],
|
|
20560
|
+
[1.21, 4830],
|
|
20561
|
+
[1.34, 4600],
|
|
20562
|
+
[1.43, 4440],
|
|
20563
|
+
[1.53, 4300],
|
|
20564
|
+
[1.7, 4100],
|
|
20565
|
+
[1.73, 3990],
|
|
20566
|
+
[1.79, 3930],
|
|
20567
|
+
[1.84, 3850],
|
|
20568
|
+
[1.97, 3770],
|
|
20569
|
+
[2.09, 3660],
|
|
20570
|
+
[2.13, 3620],
|
|
20571
|
+
[2.23, 3560],
|
|
20572
|
+
[2.39, 3470],
|
|
20573
|
+
[2.5, 3430],
|
|
20574
|
+
[2.78, 3270],
|
|
20575
|
+
[2.94, 3210],
|
|
20576
|
+
[3.16, 3110],
|
|
20577
|
+
[3.35, 3060],
|
|
20578
|
+
[3.71, 2930],
|
|
20579
|
+
[4.16, 2810],
|
|
20580
|
+
[4.5, 2740],
|
|
20581
|
+
[4.65, 2680],
|
|
20582
|
+
[4.72, 2630],
|
|
20583
|
+
[4.86, 2570],
|
|
20584
|
+
[5.1, 2420]
|
|
20585
|
+
];
|
|
20586
|
+
function teffFromBpRp(bpRp) {
|
|
20587
|
+
const table = BP_RP_TEFF;
|
|
20588
|
+
if (bpRp <= table[0][0]) return table[0][1];
|
|
20589
|
+
const last = table[table.length - 1];
|
|
20590
|
+
if (bpRp >= last[0]) return last[1];
|
|
20591
|
+
let lo = 0;
|
|
20592
|
+
let hi = table.length - 1;
|
|
20593
|
+
while (hi - lo > 1) {
|
|
20594
|
+
const mid = lo + hi >> 1;
|
|
20595
|
+
if (table[mid][0] <= bpRp) lo = mid;
|
|
20596
|
+
else hi = mid;
|
|
20597
|
+
}
|
|
20598
|
+
const [c0, t0] = table[lo];
|
|
20599
|
+
const [c1, t1] = table[hi];
|
|
20600
|
+
return t0 + (bpRp - c0) / (c1 - c0) * (t1 - t0);
|
|
20601
|
+
}
|
|
20602
|
+
function planckianRgb(teff, out) {
|
|
20603
|
+
const t = Math.min(Math.max(teff, 1667), 25e3);
|
|
20604
|
+
const t1 = 1e3 / t;
|
|
20605
|
+
const t2 = t1 * t1;
|
|
20606
|
+
const t3 = t2 * t1;
|
|
20607
|
+
const x = t <= 4e3 ? -.2661239 * t3 - .2343589 * t2 + .8776956 * t1 + .17991 : -3.0258469 * t3 + 2.1070379 * t2 + .2226347 * t1 + .24039;
|
|
20608
|
+
const x2 = x * x;
|
|
20609
|
+
const x3 = x2 * x;
|
|
20610
|
+
let y;
|
|
20611
|
+
if (t <= 2222) y = -1.1063814 * x3 - 1.3481102 * x2 + 2.18555832 * x - .20219683;
|
|
20612
|
+
else if (t <= 4e3) y = -.9549476 * x3 - 1.37418593 * x2 + 2.09137015 * x - .16748867;
|
|
20613
|
+
else y = 3.081758 * x3 - 5.8733867 * x2 + 3.75112997 * x - .37001483;
|
|
20614
|
+
const X = x / y;
|
|
20615
|
+
const Z = (1 - x - y) / y;
|
|
20616
|
+
const r = Math.max(3.2404542 * X - 1.5371385 - .4985314 * Z, 0);
|
|
20617
|
+
const g = Math.max(-.969266 * X + 1.8760108 + .041556 * Z, 0);
|
|
20618
|
+
const b = Math.max(.0556434 * X - .2040259 + 1.0572252 * Z, 0);
|
|
20619
|
+
const peak = Math.max(r, g, b);
|
|
20620
|
+
out[0] = r / peak;
|
|
20621
|
+
out[1] = g / peak;
|
|
20622
|
+
out[2] = b / peak;
|
|
20623
|
+
return out;
|
|
20624
|
+
}
|
|
20625
|
+
var LUT_LO = BP_RP_TEFF[0][0];
|
|
20626
|
+
var LUT_HI = BP_RP_TEFF[BP_RP_TEFF.length - 1][0];
|
|
20627
|
+
var LUT_SIZE = 512;
|
|
20628
|
+
var lut = null;
|
|
20629
|
+
function buildLut() {
|
|
20630
|
+
const bytes = new Uint8Array(LUT_SIZE * 3);
|
|
20631
|
+
const rgb = [
|
|
20632
|
+
0,
|
|
20633
|
+
0,
|
|
20634
|
+
0
|
|
20635
|
+
];
|
|
20636
|
+
for (let i = 0; i < LUT_SIZE; i++) {
|
|
20637
|
+
planckianRgb(teffFromBpRp(LUT_LO + (LUT_HI - LUT_LO) * i / (LUT_SIZE - 1)), rgb);
|
|
20638
|
+
bytes[3 * i] = Math.round(rgb[0] * 255);
|
|
20639
|
+
bytes[3 * i + 1] = Math.round(rgb[1] * 255);
|
|
20640
|
+
bytes[3 * i + 2] = Math.round(rgb[2] * 255);
|
|
20641
|
+
}
|
|
20642
|
+
return bytes;
|
|
20643
|
+
}
|
|
20644
|
+
function starColours(bpRp, out) {
|
|
20645
|
+
const table = lut ??= buildLut();
|
|
20646
|
+
const scale = (LUT_SIZE - 1) / (LUT_HI - LUT_LO);
|
|
20647
|
+
for (let i = 0; i < bpRp.length; i++) {
|
|
20648
|
+
const c = bpRp[i];
|
|
20649
|
+
if (Number.isNaN(c)) {
|
|
20650
|
+
out[3 * i] = 255;
|
|
20651
|
+
out[3 * i + 1] = 255;
|
|
20652
|
+
out[3 * i + 2] = 255;
|
|
20653
|
+
continue;
|
|
20654
|
+
}
|
|
20655
|
+
const at = 3 * Math.round(Math.min(Math.max((c - LUT_LO) * scale, 0), LUT_SIZE - 1));
|
|
20656
|
+
out[3 * i] = table[at];
|
|
20657
|
+
out[3 * i + 1] = table[at + 1];
|
|
20658
|
+
out[3 * i + 2] = table[at + 2];
|
|
20659
|
+
}
|
|
20660
|
+
return out;
|
|
20661
|
+
}
|
|
20662
|
+
|
|
20663
|
+
//#endregion
|
|
20664
|
+
//#region src/lib/scene/starfield/material.ts
|
|
20665
|
+
function starUniforms() {
|
|
20666
|
+
return {
|
|
20667
|
+
uLimit: { value: 7 },
|
|
20668
|
+
uPixelRatio: { value: 1 },
|
|
20669
|
+
uGain: { value: 1 }
|
|
20670
|
+
};
|
|
20671
|
+
}
|
|
20672
|
+
var FADE_MAG = 1;
|
|
20673
|
+
var CONTRAST = .75;
|
|
20674
|
+
var CORE_AT_LIMIT = .06;
|
|
20675
|
+
var DOT_PX = 2.5;
|
|
20676
|
+
var MAX_DOT_PX = 14;
|
|
20677
|
+
var starVertexShader = (pick = false) => `
|
|
20678
|
+
uniform float uLimit;
|
|
20679
|
+
uniform float uPixelRatio;
|
|
20680
|
+
uniform float uGain;
|
|
20681
|
+
uniform float uFade;
|
|
20682
|
+
uniform float uFloor;
|
|
20683
|
+
uniform int uHidden;
|
|
20684
|
+
attribute float mag;
|
|
20685
|
+
attribute vec3 starColour;
|
|
20686
|
+
varying vec3 vColour;
|
|
20687
|
+
${pick ? "uniform highp uint uPickBase;\nflat varying highp uint vPick;" : ""}
|
|
20688
|
+
|
|
20689
|
+
void main() {
|
|
20690
|
+
${pick ? "vPick = uPickBase + uint(gl_VertexID);" : ""}
|
|
20691
|
+
vec4 mv = modelViewMatrix * vec4(position, 1.0);
|
|
20692
|
+
float pc = length(mv.xyz) / ${PC_SCENE.toFixed(4)};
|
|
20693
|
+
float m = mag + 5.0 * log2(max(pc, 1e-9)) * 0.30103 - 5.0;
|
|
20694
|
+
float above = max(uLimit - m, uFloor);
|
|
20695
|
+
if (above <= 0.0 || mv.z >= 0.0 || gl_VertexID == uHidden) {
|
|
20696
|
+
// Too faint, behind the camera, or drawn on its own: put it off screen.
|
|
20697
|
+
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
20698
|
+
gl_PointSize = 0.0;
|
|
20699
|
+
vColour = vec3(0.0);
|
|
20700
|
+
return;
|
|
20701
|
+
}
|
|
20702
|
+
float fade = smoothstep(0.0, ${FADE_MAG.toFixed(1)}, above) * uFade;
|
|
20703
|
+
// Energy relative to a star at the limit. Past a full core, the dot grows.
|
|
20704
|
+
float energy = ${CORE_AT_LIMIT.toFixed(3)} * exp2(above * ${(.4 * CONTRAST * Math.log2(10)).toFixed(5)});
|
|
20705
|
+
float core = min(energy, 1.0);
|
|
20706
|
+
float size = ${DOT_PX.toFixed(2)} * sqrt(max(energy, 1.0));
|
|
20707
|
+
vColour = starColour * core * fade * uGain;
|
|
20708
|
+
gl_Position = projectionMatrix * mv;
|
|
20709
|
+
// Past the far plane a star stays on it, behind everything else.
|
|
20710
|
+
${isReversedDepth() ? "gl_Position.z = max(gl_Position.z, 0.0);" : "gl_Position.z = min(gl_Position.z, gl_Position.w);"}
|
|
20711
|
+
gl_PointSize = min(size, ${MAX_DOT_PX.toFixed(1)}) * uPixelRatio;
|
|
20712
|
+
}
|
|
20713
|
+
`;
|
|
20714
|
+
var FRAGMENT = `
|
|
20715
|
+
varying vec3 vColour;
|
|
20716
|
+
|
|
20717
|
+
void main() {
|
|
20718
|
+
vec2 c = gl_PointCoord * 2.0 - 1.0;
|
|
20719
|
+
float r2 = dot(c, c);
|
|
20720
|
+
if (r2 > 1.0) discard;
|
|
20721
|
+
gl_FragColor = vec4(vColour * exp(-5.0 * r2), 1.0);
|
|
20722
|
+
}
|
|
20723
|
+
`;
|
|
20724
|
+
var PICK_MIN_LIGHT = 1 / 255;
|
|
20725
|
+
var pickFragment = () => `
|
|
20726
|
+
varying vec3 vColour;
|
|
20727
|
+
flat varying highp uint vPick;
|
|
20728
|
+
|
|
20729
|
+
void main() {
|
|
20730
|
+
vec2 c = gl_PointCoord * 2.0 - 1.0;
|
|
20731
|
+
float r2 = dot(c, c);
|
|
20732
|
+
if (r2 > 1.0) discard;
|
|
20733
|
+
float light = max(vColour.r, max(vColour.g, vColour.b)) * exp(-5.0 * r2);
|
|
20734
|
+
if (light < ${PICK_MIN_LIGHT.toFixed(6)}) discard;
|
|
20735
|
+
gl_FragDepth = ${isReversedDepth() ? "light / (1.0 + light)" : "1.0 / (1.0 + light)"};
|
|
20736
|
+
gl_FragColor = vec4(
|
|
20737
|
+
float(vPick & 255u),
|
|
20738
|
+
float((vPick >> 8) & 255u),
|
|
20739
|
+
float((vPick >> 16) & 255u),
|
|
20740
|
+
float(vPick >> 24)
|
|
20741
|
+
) / 255.0;
|
|
20742
|
+
}
|
|
20743
|
+
`;
|
|
20744
|
+
var NO_FLOOR = -1e9;
|
|
20745
|
+
function makeStarMaterial(shared, floor = NO_FLOOR) {
|
|
20746
|
+
return new ShaderMaterial({
|
|
20747
|
+
uniforms: {
|
|
20748
|
+
...shared,
|
|
20749
|
+
uFade: { value: 0 },
|
|
20750
|
+
uFloor: { value: floor },
|
|
20751
|
+
uHidden: { value: -1 }
|
|
20752
|
+
},
|
|
20753
|
+
vertexShader: starVertexShader(),
|
|
20754
|
+
fragmentShader: FRAGMENT,
|
|
20755
|
+
blending: CustomBlending,
|
|
20756
|
+
blendEquation: AddEquation,
|
|
20757
|
+
blendSrc: OneMinusDstColorFactor,
|
|
20758
|
+
blendDst: OneFactor,
|
|
20759
|
+
transparent: true,
|
|
20760
|
+
depthTest: true,
|
|
20761
|
+
depthWrite: false
|
|
20762
|
+
});
|
|
20763
|
+
}
|
|
20764
|
+
function makeStarPickMaterial(draw, base) {
|
|
20765
|
+
return new ShaderMaterial({
|
|
20766
|
+
uniforms: {
|
|
20767
|
+
...draw.uniforms,
|
|
20768
|
+
uPixelRatio: { value: 1 },
|
|
20769
|
+
uPickBase: { value: base }
|
|
20770
|
+
},
|
|
20771
|
+
vertexShader: starVertexShader(true),
|
|
20772
|
+
fragmentShader: pickFragment(),
|
|
20773
|
+
blending: NoBlending,
|
|
20774
|
+
depthTest: true,
|
|
20775
|
+
depthWrite: true
|
|
20776
|
+
});
|
|
20777
|
+
}
|
|
20778
|
+
|
|
20779
|
+
//#endregion
|
|
20780
|
+
//#region src/lib/scene/starfield/starfield.ts
|
|
20781
|
+
var TREE = "mw";
|
|
20782
|
+
var ROOT = "r";
|
|
20783
|
+
var METADATA = "metadata.json";
|
|
20784
|
+
var BASE_LIMIT_MAG = 7.5;
|
|
20785
|
+
var EXPOSURE_PC = 1;
|
|
20786
|
+
var MUST_LOAD_MAG = 1;
|
|
20787
|
+
var ABORT_MARGIN_MAG = 1;
|
|
20788
|
+
var LIMIT_EASE_MS = 300;
|
|
20789
|
+
var NODE_FADE_MS = 400;
|
|
20790
|
+
var SELECT_EVERY_MS = 100;
|
|
20791
|
+
var ADDS_PER_FRAME = 4;
|
|
20792
|
+
var BOOT_GATE_MS = 1e4;
|
|
20793
|
+
var FOCUS_FLOOR_MAG = 3;
|
|
20794
|
+
var NO_MAGNITUDE = 99;
|
|
20795
|
+
var STAR_RENDER_ORDER = -1;
|
|
20796
|
+
var NODE_PICK_PREFIX = "star:";
|
|
20797
|
+
var FOCUS_PICK_GROUP = "star-focus";
|
|
20798
|
+
var _view = new Vector3();
|
|
20799
|
+
var StarfieldSystem = class {
|
|
20800
|
+
group = new Group();
|
|
20801
|
+
uniforms = starUniforms();
|
|
20802
|
+
tree = null;
|
|
20803
|
+
credits = [];
|
|
20804
|
+
root = null;
|
|
20805
|
+
nodes = /* @__PURE__ */ new Map();
|
|
20806
|
+
drawn = /* @__PURE__ */ new Set();
|
|
20807
|
+
retries = new RetryBackoff(() => this.markDirty());
|
|
20808
|
+
idLoads = /* @__PURE__ */ new Map();
|
|
20809
|
+
loading = 0;
|
|
20810
|
+
cachedBytes = 0;
|
|
20811
|
+
drawable;
|
|
20812
|
+
metadataLoading = false;
|
|
20813
|
+
bootGate = null;
|
|
20814
|
+
stale = false;
|
|
20815
|
+
disposed = false;
|
|
20816
|
+
dirty = true;
|
|
20817
|
+
lastSelectMs = -Infinity;
|
|
20818
|
+
lastFrameMs = 0;
|
|
20819
|
+
targetLimit = BASE_LIMIT_MAG;
|
|
20820
|
+
allowedLimit = BASE_LIMIT_MAG;
|
|
20821
|
+
creditsShown = false;
|
|
20822
|
+
active = false;
|
|
20823
|
+
ready = false;
|
|
20824
|
+
skyTaken = false;
|
|
20825
|
+
sky = new SwitchFade();
|
|
20826
|
+
matrix = [];
|
|
20827
|
+
focusStar = null;
|
|
20828
|
+
focusPoints = null;
|
|
20829
|
+
focusPick = null;
|
|
20830
|
+
constructor(ctx, scene, budget, onChange, pickRegistry) {
|
|
20831
|
+
this.ctx = ctx;
|
|
20832
|
+
this.budget = budget;
|
|
20833
|
+
this.onChange = onChange;
|
|
20834
|
+
this.pickRegistry = pickRegistry;
|
|
20835
|
+
this.group.name = "starfield";
|
|
20836
|
+
this.group.matrixAutoUpdate = false;
|
|
20837
|
+
this.group.visible = false;
|
|
20838
|
+
scene.add(this.group);
|
|
20839
|
+
const open = extrasolarBase() !== "" && !ctx.layers.skipped.has("starfield");
|
|
20840
|
+
this.drawable = open ? "unknown" : "no";
|
|
20841
|
+
}
|
|
20842
|
+
setBudget(budget) {
|
|
20843
|
+
this.budget = budget;
|
|
20844
|
+
this.markDirty();
|
|
20845
|
+
}
|
|
20846
|
+
setFocusStar(star) {
|
|
20847
|
+
const next = star?.tree ? star : null;
|
|
20848
|
+
if (next?.id === this.focusStar?.id) return;
|
|
20849
|
+
this.focusStar = next;
|
|
20850
|
+
if (this.focusPoints) {
|
|
20851
|
+
this.focusPoints.removeFromParent();
|
|
20852
|
+
this.focusPoints.geometry.dispose();
|
|
20853
|
+
this.focusPoints.material.dispose();
|
|
20854
|
+
this.focusPoints = null;
|
|
20855
|
+
}
|
|
20856
|
+
this.dropPick(this.focusPick, FOCUS_PICK_GROUP);
|
|
20857
|
+
this.focusPick = null;
|
|
20858
|
+
if (next) this.focusPoints = this.focusPoint(next);
|
|
20859
|
+
for (const node of this.drawn) if (node.points) this.applyHidden(node);
|
|
20860
|
+
this.onChange();
|
|
20861
|
+
}
|
|
20862
|
+
treeEntry() {
|
|
20863
|
+
return this.tree;
|
|
20864
|
+
}
|
|
20865
|
+
drawnNodes() {
|
|
20866
|
+
const out = [];
|
|
20867
|
+
for (const node of this.drawn) {
|
|
20868
|
+
const view = this.view(node);
|
|
20869
|
+
if (view) out.push(view);
|
|
20870
|
+
}
|
|
20871
|
+
return out;
|
|
20872
|
+
}
|
|
20873
|
+
node(name) {
|
|
20874
|
+
const node = this.nodes.get(name);
|
|
20875
|
+
return node ? this.view(node) : void 0;
|
|
20876
|
+
}
|
|
20877
|
+
pickDraws() {
|
|
20878
|
+
if (!this.group.visible) return [];
|
|
20879
|
+
const out = [];
|
|
20880
|
+
for (const node of this.drawn) {
|
|
20881
|
+
const points = node.points;
|
|
20882
|
+
if (!points?.visible || !node.data) continue;
|
|
20883
|
+
node.pick ??= {
|
|
20884
|
+
base: this.pickRegistry.allocateRows(NODE_PICK_PREFIX + node.name, node.data.container.rows),
|
|
20885
|
+
material: null
|
|
20886
|
+
};
|
|
20887
|
+
out.push({
|
|
20888
|
+
points,
|
|
20889
|
+
material: this.pickMaterial(node.pick, points)
|
|
20890
|
+
});
|
|
20891
|
+
}
|
|
20892
|
+
const focus = this.focusPoints;
|
|
20893
|
+
if (focus) {
|
|
20894
|
+
this.focusPick ??= {
|
|
20895
|
+
base: this.pickRegistry.allocateRows(FOCUS_PICK_GROUP, 1),
|
|
20896
|
+
material: null
|
|
20897
|
+
};
|
|
20898
|
+
out.push({
|
|
20899
|
+
points: focus,
|
|
20900
|
+
material: this.pickMaterial(this.focusPick, focus)
|
|
20901
|
+
});
|
|
20902
|
+
}
|
|
20903
|
+
return out;
|
|
20904
|
+
}
|
|
20905
|
+
pickedStar(pickId) {
|
|
20906
|
+
const at = this.pickRegistry.locate(pickId);
|
|
20907
|
+
if (!at) return null;
|
|
20908
|
+
if (at.groupId === FOCUS_PICK_GROUP) return this.focusStar ? { id: this.focusStar.id } : null;
|
|
20909
|
+
if (!at.groupId.startsWith(NODE_PICK_PREFIX)) return null;
|
|
20910
|
+
return {
|
|
20911
|
+
node: at.groupId.slice(5),
|
|
20912
|
+
row: at.row
|
|
20913
|
+
};
|
|
20914
|
+
}
|
|
20915
|
+
async starId(star) {
|
|
20916
|
+
if ("id" in star) return star.id;
|
|
20917
|
+
const id = (this.nodes.get(star.node)?.ids?.column ?? await this.idsOf(star.node))[star.row];
|
|
20918
|
+
if (!id) throw new Error(`[starfield] row ${star.row} of node ${star.node} has no ID`);
|
|
20919
|
+
return id;
|
|
20920
|
+
}
|
|
20921
|
+
idsOf(name) {
|
|
20922
|
+
let load = this.idLoads.get(name);
|
|
20923
|
+
if (!load) {
|
|
20924
|
+
load = this.loadIds(name).finally(() => this.idLoads.delete(name));
|
|
20925
|
+
this.idLoads.set(name, load);
|
|
20926
|
+
}
|
|
20927
|
+
return load;
|
|
20928
|
+
}
|
|
20929
|
+
async loadIds(name) {
|
|
20930
|
+
const tree = this.tree;
|
|
20931
|
+
if (!tree) throw new Error("[starfield] no tree to read IDs from");
|
|
20932
|
+
const container = await fetchExtrasolarFile(extrasolarPath(tree.ids, { name }), tree.token, { priority: "high" });
|
|
20933
|
+
const node = this.nodes.get(name);
|
|
20934
|
+
const rows = node?.data?.container.rows;
|
|
20935
|
+
if (rows !== void 0 && container.rows !== rows) throw new Error(`[starfield] ID file of node ${name} has ${container.rows} rows, not ${rows}`);
|
|
20936
|
+
const column = container.ids("id");
|
|
20937
|
+
if (node?.data && !node.ids) {
|
|
20938
|
+
node.ids = {
|
|
20939
|
+
column,
|
|
20940
|
+
bytes: container.buffer.byteLength
|
|
20941
|
+
};
|
|
20942
|
+
this.cachedBytes += container.buffer.byteLength;
|
|
20943
|
+
}
|
|
20944
|
+
return column;
|
|
20945
|
+
}
|
|
20946
|
+
pickMaterial(range, points) {
|
|
20947
|
+
range.material ??= makeStarPickMaterial(points.material, range.base);
|
|
20948
|
+
return range.material;
|
|
20949
|
+
}
|
|
20950
|
+
dropPick(range, groupId) {
|
|
20951
|
+
if (!range) return;
|
|
20952
|
+
range.material?.dispose();
|
|
20953
|
+
this.pickRegistry.release(groupId);
|
|
20954
|
+
}
|
|
20955
|
+
rowPosition(name, row) {
|
|
20956
|
+
const data = this.nodes.get(name)?.data;
|
|
20957
|
+
if (!data || row < 0 || row >= data.container.rows) return null;
|
|
20958
|
+
const at = data.geometry.getAttribute("position").array;
|
|
20959
|
+
const [cx, cy, cz] = data.info.centre;
|
|
20960
|
+
const p = treeToScene(cx + at[3 * row], cy + at[3 * row + 1], cz + at[3 * row + 2], {
|
|
20961
|
+
x: 0,
|
|
20962
|
+
y: 0,
|
|
20963
|
+
z: 0
|
|
20964
|
+
});
|
|
20965
|
+
return [
|
|
20966
|
+
p.x,
|
|
20967
|
+
p.y,
|
|
20968
|
+
p.z
|
|
20969
|
+
];
|
|
20970
|
+
}
|
|
20971
|
+
stats() {
|
|
20972
|
+
let drawnPoints = 0;
|
|
20973
|
+
for (const node of this.drawn) drawnPoints += node.data?.container.rows ?? 0;
|
|
20974
|
+
let cachedNodes = 0;
|
|
20975
|
+
for (const node of this.nodes.values()) if (node.data) cachedNodes++;
|
|
20976
|
+
return {
|
|
20977
|
+
drawnNodes: this.drawn.size,
|
|
20978
|
+
drawnPoints,
|
|
20979
|
+
cachedNodes,
|
|
20980
|
+
cachedBytes: this.cachedBytes,
|
|
20981
|
+
loading: this.loading,
|
|
20982
|
+
limit: this.uniforms.uLimit.value,
|
|
20983
|
+
targetLimit: this.targetLimit,
|
|
20984
|
+
active: this.active,
|
|
20985
|
+
share: this.sky.share
|
|
20986
|
+
};
|
|
20987
|
+
}
|
|
20988
|
+
share() {
|
|
20989
|
+
return this.sky.share;
|
|
20990
|
+
}
|
|
20991
|
+
availability() {
|
|
20992
|
+
return this.drawable;
|
|
20993
|
+
}
|
|
20994
|
+
busy() {
|
|
20995
|
+
if (this.loading > 0) return true;
|
|
20996
|
+
if (this.sky.fading) return true;
|
|
20997
|
+
if (this.drawn.size === 0) return false;
|
|
20998
|
+
if (Math.abs(this.uniforms.uLimit.value - this.allowedLimit) > .01) return true;
|
|
20999
|
+
for (const node of this.drawn) {
|
|
21000
|
+
if (node.fade !== (node.wanted ? 1 : 0)) return true;
|
|
21001
|
+
if (node.wanted && node.data && !node.points) return true;
|
|
21002
|
+
}
|
|
21003
|
+
return false;
|
|
21004
|
+
}
|
|
21005
|
+
update(camera, focus, pixelRatio, gain, nowMs) {
|
|
21006
|
+
const dtMs = this.lastFrameMs ? Math.min(nowMs - this.lastFrameMs, 250) : 0;
|
|
21007
|
+
this.lastFrameMs = nowMs;
|
|
21008
|
+
const wx = camera.position.x + focus[0];
|
|
21009
|
+
const wy = camera.position.y + focus[1];
|
|
21010
|
+
const wz = camera.position.z + focus[2];
|
|
21011
|
+
const au = Math.hypot(wx, wy, wz) / 10;
|
|
21012
|
+
if (!this.active && au > 500) this.active = true;
|
|
21013
|
+
else if (this.active && au < 400) this.stopLoading();
|
|
21014
|
+
if (this.active) this.start();
|
|
21015
|
+
const shown = this.ctx.layers.isVisible("starfield");
|
|
21016
|
+
this.skyTaken = starsTakeSky(au, this.skyTaken);
|
|
21017
|
+
this.sky.step(shown && this.ready && this.root !== null && this.skyTaken, dtMs);
|
|
21018
|
+
const skyShare = this.sky.share;
|
|
21019
|
+
this.group.visible = shown && this.root !== null && skyShare > 0;
|
|
21020
|
+
if (!this.root) return;
|
|
21021
|
+
this.group.matrix.fromArray(treeMatrixElements(focus, this.matrix));
|
|
21022
|
+
this.group.matrixWorldNeedsUpdate = true;
|
|
21023
|
+
const cam = sceneToTree(wx, wy, wz);
|
|
21024
|
+
const fromSunPc = Math.hypot(wx, wy, wz) / PC_SCENE;
|
|
21025
|
+
const target = BASE_LIMIT_MAG + 5 * Math.log10(Math.max(1, fromSunPc / EXPOSURE_PC));
|
|
21026
|
+
if (target !== this.targetLimit) this.dirty = true;
|
|
21027
|
+
this.targetLimit = target;
|
|
21028
|
+
const due = this.dirty || nowMs - this.lastSelectMs >= SELECT_EVERY_MS;
|
|
21029
|
+
if (this.active && !this.stale && due) this.select(cam, nowMs);
|
|
21030
|
+
const limit = this.uniforms.uLimit;
|
|
21031
|
+
const ease = dtMs > 0 ? 1 - Math.exp(-dtMs / LIMIT_EASE_MS) : 1;
|
|
21032
|
+
limit.value += (this.allowedLimit - limit.value) * ease;
|
|
21033
|
+
this.uniforms.uPixelRatio.value = pixelRatio;
|
|
21034
|
+
this.uniforms.uGain.value = gain * skyShare;
|
|
21035
|
+
this.applyFades(dtMs, camera, focus);
|
|
21036
|
+
if (this.group.visible && !this.creditsShown && this.drawn.size > 0) {
|
|
21037
|
+
this.creditsShown = true;
|
|
21038
|
+
this.ctx.credits.setStars(this.credits);
|
|
21039
|
+
}
|
|
21040
|
+
}
|
|
21041
|
+
dispose() {
|
|
21042
|
+
this.disposed = true;
|
|
21043
|
+
for (const node of this.nodes.values()) {
|
|
21044
|
+
node.abort?.abort();
|
|
21045
|
+
this.undraw(node);
|
|
21046
|
+
this.dropPick(node.pick, NODE_PICK_PREFIX + node.name);
|
|
21047
|
+
node.data?.geometry.dispose();
|
|
21048
|
+
}
|
|
21049
|
+
this.nodes.clear();
|
|
21050
|
+
this.setFocusStar(null);
|
|
21051
|
+
this.group.removeFromParent();
|
|
21052
|
+
}
|
|
21053
|
+
stopLoading() {
|
|
21054
|
+
this.active = false;
|
|
21055
|
+
this.ready = false;
|
|
21056
|
+
for (const node of this.nodes.values()) {
|
|
21057
|
+
node.wanted = false;
|
|
21058
|
+
node.abort?.abort();
|
|
21059
|
+
}
|
|
21060
|
+
this.markDirty();
|
|
21061
|
+
}
|
|
21062
|
+
start() {
|
|
21063
|
+
if (this.drawable !== "unknown" || this.metadataLoading) return;
|
|
21064
|
+
if (this.retries.waiting(METADATA)) return;
|
|
21065
|
+
this.metadataLoading = true;
|
|
21066
|
+
this.bootGate ??= Promise.race([eagerMinorsDone, new Promise((resolve) => setTimeout(resolve, BOOT_GATE_MS))]);
|
|
21067
|
+
(async () => {
|
|
21068
|
+
await this.bootGate;
|
|
21069
|
+
const meta = await fetchExtrasolarMetadata();
|
|
21070
|
+
const tree = meta?.trees[TREE];
|
|
21071
|
+
if (this.disposed) return;
|
|
21072
|
+
this.retries.clear(METADATA);
|
|
21073
|
+
if (!meta || !tree || !extrasolarAllowed(tree)) {
|
|
21074
|
+
this.noStars();
|
|
21075
|
+
return;
|
|
21076
|
+
}
|
|
21077
|
+
this.tree = tree;
|
|
21078
|
+
this.credits = meta.credits;
|
|
21079
|
+
this.root = this.record(ROOT, 0, tree.centre, tree.half_size, Infinity, null);
|
|
21080
|
+
this.drawable = "yes";
|
|
21081
|
+
this.markDirty();
|
|
21082
|
+
})().catch((err) => {
|
|
21083
|
+
if (this.disposed) return;
|
|
21084
|
+
console.warn("[starfield] metadata.json did not load:", err);
|
|
21085
|
+
this.retries.fail(METADATA);
|
|
21086
|
+
}).finally(() => {
|
|
21087
|
+
this.metadataLoading = false;
|
|
21088
|
+
});
|
|
21089
|
+
}
|
|
21090
|
+
noStars() {
|
|
21091
|
+
this.drawable = "no";
|
|
21092
|
+
this.onChange();
|
|
21093
|
+
}
|
|
21094
|
+
record(name, depth, centre, half, range, parent) {
|
|
21095
|
+
const node = {
|
|
21096
|
+
name,
|
|
21097
|
+
depth,
|
|
21098
|
+
centre,
|
|
21099
|
+
half,
|
|
21100
|
+
range,
|
|
21101
|
+
parent,
|
|
21102
|
+
children: [],
|
|
21103
|
+
state: "idle",
|
|
21104
|
+
abort: null,
|
|
21105
|
+
data: null,
|
|
21106
|
+
points: null,
|
|
21107
|
+
magnitude: Infinity,
|
|
21108
|
+
wanted: false,
|
|
21109
|
+
lastWantedMs: -Infinity,
|
|
21110
|
+
fade: 0,
|
|
21111
|
+
hidden: null,
|
|
21112
|
+
pick: null,
|
|
21113
|
+
ids: null
|
|
21114
|
+
};
|
|
21115
|
+
this.nodes.set(name, node);
|
|
21116
|
+
return node;
|
|
21117
|
+
}
|
|
21118
|
+
markDirty() {
|
|
21119
|
+
this.dirty = true;
|
|
21120
|
+
this.onChange();
|
|
21121
|
+
}
|
|
21122
|
+
select(cam, nowMs) {
|
|
21123
|
+
const tree = this.tree;
|
|
21124
|
+
const root = this.root;
|
|
21125
|
+
if (!tree || !root) return;
|
|
21126
|
+
this.dirty = false;
|
|
21127
|
+
this.lastSelectMs = nowMs;
|
|
21128
|
+
for (const node of this.nodes.values()) node.wanted = false;
|
|
21129
|
+
const magnitude = (node) => node === root ? -Infinity : boxMagnitude(boxDistance(cam, node.centre, node.half), node.range, tree.range_limit_mag);
|
|
21130
|
+
const heap = new NodeHeap();
|
|
21131
|
+
root.magnitude = magnitude(root);
|
|
21132
|
+
heap.push(root);
|
|
21133
|
+
let points = 0;
|
|
21134
|
+
let allowed = this.targetLimit;
|
|
21135
|
+
const wanted = [];
|
|
21136
|
+
for (let node = heap.pop(); node; node = heap.pop()) {
|
|
21137
|
+
if (node.magnitude > this.targetLimit) break;
|
|
21138
|
+
const rows = node.data?.container.rows ?? tree.node_rows;
|
|
21139
|
+
if (points + rows > this.budget.points && node.magnitude > MUST_LOAD_MAG) {
|
|
21140
|
+
allowed = node.magnitude;
|
|
21141
|
+
break;
|
|
21142
|
+
}
|
|
21143
|
+
points += rows;
|
|
21144
|
+
node.wanted = true;
|
|
21145
|
+
node.lastWantedMs = nowMs;
|
|
21146
|
+
wanted.push(node);
|
|
21147
|
+
for (const child of node.children) {
|
|
21148
|
+
child.magnitude = magnitude(child);
|
|
21149
|
+
heap.push(child);
|
|
21150
|
+
}
|
|
21151
|
+
}
|
|
21152
|
+
this.allowedLimit = allowed;
|
|
21153
|
+
if (wanted.every((node) => node.data || this.retries.waiting(node.name))) this.ready = true;
|
|
21154
|
+
for (const node of wanted) {
|
|
21155
|
+
if (this.loading >= this.budget.fetches) break;
|
|
21156
|
+
if (node.state === "idle" && !this.retries.waiting(node.name)) this.load(node);
|
|
21157
|
+
}
|
|
21158
|
+
for (const node of this.nodes.values()) {
|
|
21159
|
+
if (node.state !== "loading" || node.wanted) continue;
|
|
21160
|
+
if (node.magnitude > allowed + ABORT_MARGIN_MAG || !node.parent?.wanted) node.abort?.abort();
|
|
21161
|
+
}
|
|
21162
|
+
for (const node of wanted) if (node.data) this.drawn.add(node);
|
|
21163
|
+
this.evict();
|
|
21164
|
+
}
|
|
21165
|
+
load(node) {
|
|
21166
|
+
const tree = this.tree;
|
|
21167
|
+
if (!tree) return;
|
|
21168
|
+
node.state = "loading";
|
|
21169
|
+
this.loading++;
|
|
21170
|
+
const abort = new AbortController();
|
|
21171
|
+
node.abort = abort;
|
|
21172
|
+
fetchExtrasolarFile(extrasolarPath(tree.node, { name: node.name }), tree.token, {
|
|
21173
|
+
signal: abort.signal,
|
|
21174
|
+
priority: "low"
|
|
21175
|
+
}).then((container) => {
|
|
21176
|
+
if (this.disposed) return;
|
|
21177
|
+
this.retries.clear(node.name);
|
|
21178
|
+
this.adopt(node, container);
|
|
21179
|
+
}).catch((err) => {
|
|
21180
|
+
node.state = "idle";
|
|
21181
|
+
if (this.disposed || abort.signal.aborted) return;
|
|
21182
|
+
if (err instanceof ExtrasolarStaleError) {
|
|
21183
|
+
this.stale = true;
|
|
21184
|
+
return;
|
|
21185
|
+
}
|
|
21186
|
+
this.retries.fail(node.name);
|
|
21187
|
+
console.warn(`[starfield] node ${node.name} did not load:`, err);
|
|
21188
|
+
}).finally(() => {
|
|
21189
|
+
this.loading--;
|
|
21190
|
+
node.abort = null;
|
|
21191
|
+
this.markDirty();
|
|
21192
|
+
});
|
|
21193
|
+
}
|
|
21194
|
+
adopt(node, container) {
|
|
21195
|
+
const info = nodeInfo(container);
|
|
21196
|
+
const rows = container.rows;
|
|
21197
|
+
const x = container.float32("x");
|
|
21198
|
+
const y = container.float32("y");
|
|
21199
|
+
const z = container.float32("z");
|
|
21200
|
+
const position = new Float32Array(3 * rows);
|
|
21201
|
+
for (let i = 0; i < rows; i++) {
|
|
21202
|
+
position[3 * i] = x[i];
|
|
21203
|
+
position[3 * i + 1] = y[i];
|
|
21204
|
+
position[3 * i + 2] = z[i];
|
|
21205
|
+
}
|
|
21206
|
+
const colour = starColours(container.float32("colour"), new Uint8Array(3 * rows));
|
|
21207
|
+
const geometry = new BufferGeometry();
|
|
21208
|
+
geometry.setAttribute("position", new BufferAttribute(position, 3));
|
|
21209
|
+
geometry.setAttribute("mag", new BufferAttribute(container.float32("mag"), 1));
|
|
21210
|
+
geometry.setAttribute("starColour", new BufferAttribute(colour, 3, true));
|
|
21211
|
+
const bytes = container.buffer.byteLength + position.byteLength + colour.byteLength;
|
|
21212
|
+
node.data = {
|
|
21213
|
+
container,
|
|
21214
|
+
info,
|
|
21215
|
+
geometry,
|
|
21216
|
+
bytes
|
|
21217
|
+
};
|
|
21218
|
+
node.state = "loaded";
|
|
21219
|
+
node.centre = info.centre;
|
|
21220
|
+
node.half = info.half;
|
|
21221
|
+
node.range = info.maxRange;
|
|
21222
|
+
this.cachedBytes += bytes;
|
|
21223
|
+
node.children = [];
|
|
21224
|
+
for (let k = 0; k < 8; k++) {
|
|
21225
|
+
if (!(info.childMask >> k & 1)) continue;
|
|
21226
|
+
node.children.push(this.record(node.name + k, node.depth + 1, childCentre(info.centre, info.half, k), info.half / 2, info.childRange[k], node));
|
|
21227
|
+
}
|
|
21228
|
+
}
|
|
21229
|
+
evict() {
|
|
21230
|
+
if (this.cachedBytes <= this.budget.bytes) return;
|
|
21231
|
+
const candidates = [...this.nodes.values()].filter((node) => node.data && !node.wanted && !node.points && node.children.every((child) => child.state === "idle" && !child.data));
|
|
21232
|
+
candidates.sort((a, b) => a.lastWantedMs - b.lastWantedMs || b.depth - a.depth);
|
|
21233
|
+
for (const node of candidates) {
|
|
21234
|
+
if (this.cachedBytes <= this.budget.bytes) break;
|
|
21235
|
+
if (node.children.some((child) => child.data)) continue;
|
|
21236
|
+
this.release(node);
|
|
21237
|
+
}
|
|
21238
|
+
}
|
|
21239
|
+
release(node) {
|
|
21240
|
+
const data = node.data;
|
|
21241
|
+
if (!data) return;
|
|
21242
|
+
data.geometry.dispose();
|
|
21243
|
+
this.cachedBytes -= data.bytes;
|
|
21244
|
+
node.data = null;
|
|
21245
|
+
node.state = "idle";
|
|
21246
|
+
node.hidden = null;
|
|
21247
|
+
this.dropPick(node.pick, NODE_PICK_PREFIX + node.name);
|
|
21248
|
+
node.pick = null;
|
|
21249
|
+
if (node.ids) this.cachedBytes -= node.ids.bytes;
|
|
21250
|
+
node.ids = null;
|
|
21251
|
+
for (const child of node.children) this.forget(child);
|
|
21252
|
+
node.children = [];
|
|
21253
|
+
}
|
|
21254
|
+
forget(node) {
|
|
21255
|
+
for (const child of node.children) this.forget(child);
|
|
21256
|
+
this.nodes.delete(node.name);
|
|
21257
|
+
}
|
|
21258
|
+
applyFades(dtMs, camera, focus) {
|
|
21259
|
+
const step = dtMs / NODE_FADE_MS;
|
|
21260
|
+
let adds = 0;
|
|
21261
|
+
const view = new ViewCone(camera);
|
|
21262
|
+
for (const node of [...this.drawn]) {
|
|
21263
|
+
const target = node.wanted ? 1 : 0;
|
|
21264
|
+
if (!node.points) {
|
|
21265
|
+
if (!node.wanted || !node.data || adds >= ADDS_PER_FRAME) {
|
|
21266
|
+
if (!node.wanted) this.drawn.delete(node);
|
|
21267
|
+
continue;
|
|
21268
|
+
}
|
|
21269
|
+
adds++;
|
|
21270
|
+
this.draw(node);
|
|
21271
|
+
}
|
|
21272
|
+
if (target > node.fade) node.fade = Math.min(node.fade + step, 1);
|
|
21273
|
+
else if (target < node.fade) node.fade = Math.max(node.fade - step, 0);
|
|
21274
|
+
if (node.fade === 0 && !node.wanted) {
|
|
21275
|
+
this.undraw(node);
|
|
21276
|
+
this.drawn.delete(node);
|
|
21277
|
+
continue;
|
|
21278
|
+
}
|
|
21279
|
+
const points = node.points;
|
|
21280
|
+
points.material.uniforms.uFade.value = node.fade;
|
|
21281
|
+
points.visible = view.sees(node, focus);
|
|
21282
|
+
}
|
|
21283
|
+
}
|
|
21284
|
+
draw(node) {
|
|
21285
|
+
const data = node.data;
|
|
21286
|
+
const points = new Points(data.geometry, makeStarMaterial(this.uniforms));
|
|
21287
|
+
points.position.set(...data.info.centre);
|
|
21288
|
+
points.updateMatrix();
|
|
21289
|
+
points.matrixAutoUpdate = false;
|
|
21290
|
+
points.frustumCulled = false;
|
|
21291
|
+
points.renderOrder = STAR_RENDER_ORDER;
|
|
21292
|
+
points.userData.starNode = node.name;
|
|
21293
|
+
node.points = points;
|
|
21294
|
+
node.fade = 0;
|
|
21295
|
+
this.applyHidden(node);
|
|
21296
|
+
this.group.add(points);
|
|
21297
|
+
}
|
|
21298
|
+
focusPoint(star) {
|
|
21299
|
+
const geometry = new BufferGeometry();
|
|
21300
|
+
geometry.setAttribute("position", new BufferAttribute(new Float32Array(3), 3));
|
|
21301
|
+
const mag = star.absMag ?? NO_MAGNITUDE;
|
|
21302
|
+
geometry.setAttribute("mag", new BufferAttribute(new Float32Array([mag]), 1));
|
|
21303
|
+
const colour = starColours(new Float32Array([star.colour ?? NaN]), new Uint8Array(3));
|
|
21304
|
+
geometry.setAttribute("starColour", new BufferAttribute(colour, 3, true));
|
|
21305
|
+
const material = makeStarMaterial(this.uniforms, FOCUS_FLOOR_MAG);
|
|
21306
|
+
material.uniforms.uFade.value = 1;
|
|
21307
|
+
const points = new Points(geometry, material);
|
|
21308
|
+
points.position.set(...star.tree);
|
|
21309
|
+
points.updateMatrix();
|
|
21310
|
+
points.matrixAutoUpdate = false;
|
|
21311
|
+
points.frustumCulled = false;
|
|
21312
|
+
points.renderOrder = STAR_RENDER_ORDER;
|
|
21313
|
+
points.userData.focusStar = star.id;
|
|
21314
|
+
this.group.add(points);
|
|
21315
|
+
return points;
|
|
21316
|
+
}
|
|
21317
|
+
applyHidden(node) {
|
|
21318
|
+
const star = this.focusStar;
|
|
21319
|
+
let row = -1;
|
|
21320
|
+
if (star && node.data) {
|
|
21321
|
+
if (node.hidden?.id !== star.id) node.hidden = {
|
|
21322
|
+
id: star.id,
|
|
21323
|
+
row: findStarRow(node.data, star)
|
|
21324
|
+
};
|
|
21325
|
+
row = node.hidden.row;
|
|
21326
|
+
}
|
|
21327
|
+
node.points.material.uniforms.uHidden.value = row;
|
|
21328
|
+
}
|
|
21329
|
+
undraw(node) {
|
|
21330
|
+
const points = node.points;
|
|
21331
|
+
if (!points) return;
|
|
21332
|
+
points.removeFromParent();
|
|
21333
|
+
points.material.dispose();
|
|
21334
|
+
if (node.pick) {
|
|
21335
|
+
node.pick.material?.dispose();
|
|
21336
|
+
node.pick.material = null;
|
|
21337
|
+
}
|
|
21338
|
+
node.data?.geometry.dispose();
|
|
21339
|
+
node.points = null;
|
|
21340
|
+
node.fade = 0;
|
|
21341
|
+
}
|
|
21342
|
+
view(node) {
|
|
21343
|
+
const data = node.data;
|
|
21344
|
+
if (!data || !node.points) return void 0;
|
|
21345
|
+
return {
|
|
21346
|
+
name: node.name,
|
|
21347
|
+
rows: data.container.rows,
|
|
21348
|
+
points: node.points,
|
|
21349
|
+
container: data.container,
|
|
21350
|
+
info: data.info
|
|
21351
|
+
};
|
|
21352
|
+
}
|
|
21353
|
+
};
|
|
21354
|
+
var ROW_STEPS = 2 ** -22;
|
|
21355
|
+
var ROW_FLOOR_PC = 1e-9;
|
|
21356
|
+
var ROW_MAG = .01;
|
|
21357
|
+
function findStarRow(data, star) {
|
|
21358
|
+
const tree = star.tree;
|
|
21359
|
+
if (!tree) return -1;
|
|
21360
|
+
const { centre, half } = data.info;
|
|
21361
|
+
const ox = tree[0] - centre[0];
|
|
21362
|
+
const oy = tree[1] - centre[1];
|
|
21363
|
+
const oz = tree[2] - centre[2];
|
|
21364
|
+
if (Math.max(Math.abs(ox), Math.abs(oy), Math.abs(oz)) > half * 1.000001) return -1;
|
|
21365
|
+
const tx = Math.abs(ox) * ROW_STEPS + ROW_FLOOR_PC;
|
|
21366
|
+
const ty = Math.abs(oy) * ROW_STEPS + ROW_FLOOR_PC;
|
|
21367
|
+
const tz = Math.abs(oz) * ROW_STEPS + ROW_FLOOR_PC;
|
|
21368
|
+
const c = data.container;
|
|
21369
|
+
const x = c.float32("x");
|
|
21370
|
+
const y = c.float32("y");
|
|
21371
|
+
const z = c.float32("z");
|
|
21372
|
+
const mag = c.float32("mag");
|
|
21373
|
+
let best = -1;
|
|
21374
|
+
let bestDistance = Infinity;
|
|
21375
|
+
for (let i = 0; i < c.rows; i++) {
|
|
21376
|
+
const dx = Math.abs(x[i] - ox);
|
|
21377
|
+
const dy = Math.abs(y[i] - oy);
|
|
21378
|
+
const dz = Math.abs(z[i] - oz);
|
|
21379
|
+
if (dx > tx || dy > ty || dz > tz) continue;
|
|
21380
|
+
if (star.absMag !== null && Math.abs(mag[i] - star.absMag) > ROW_MAG) continue;
|
|
21381
|
+
const distance = dx + dy + dz;
|
|
21382
|
+
if (distance < bestDistance) {
|
|
21383
|
+
best = i;
|
|
21384
|
+
bestDistance = distance;
|
|
21385
|
+
}
|
|
21386
|
+
}
|
|
21387
|
+
return best;
|
|
21388
|
+
}
|
|
21389
|
+
var ViewCone = class {
|
|
21390
|
+
tanY;
|
|
21391
|
+
tanX;
|
|
21392
|
+
inverse;
|
|
21393
|
+
constructor(camera) {
|
|
21394
|
+
this.tanY = Math.tan(camera.fov / 2 * Math.PI / 180) / camera.zoom;
|
|
21395
|
+
this.tanX = this.tanY * camera.aspect;
|
|
21396
|
+
this.inverse = camera.matrixWorldInverse;
|
|
21397
|
+
}
|
|
21398
|
+
sees(node, focus) {
|
|
21399
|
+
const [cx, cy, cz] = node.centre;
|
|
21400
|
+
const at = treeToScene(cx, cy, cz, _view);
|
|
21401
|
+
_view.set(at.x - focus[0], at.y - focus[1], at.z - focus[2]).applyMatrix4(this.inverse);
|
|
21402
|
+
const r = node.half * Math.sqrt(3) * PC_SCENE;
|
|
21403
|
+
const depth = -_view.z;
|
|
21404
|
+
if (depth < -r) return false;
|
|
21405
|
+
const sideX = (Math.abs(_view.x) - depth * this.tanX) / Math.hypot(1, this.tanX);
|
|
21406
|
+
const sideY = (Math.abs(_view.y) - depth * this.tanY) / Math.hypot(1, this.tanY);
|
|
21407
|
+
return sideX <= r && sideY <= r;
|
|
21408
|
+
}
|
|
21409
|
+
};
|
|
21410
|
+
var NodeHeap = class {
|
|
21411
|
+
items = [];
|
|
21412
|
+
push(node) {
|
|
21413
|
+
const items = this.items;
|
|
21414
|
+
items.push(node);
|
|
21415
|
+
let i = items.length - 1;
|
|
21416
|
+
while (i > 0) {
|
|
21417
|
+
const up = i - 1 >> 1;
|
|
21418
|
+
if (items[up].magnitude <= items[i].magnitude) break;
|
|
21419
|
+
[items[up], items[i]] = [items[i], items[up]];
|
|
21420
|
+
i = up;
|
|
21421
|
+
}
|
|
21422
|
+
}
|
|
21423
|
+
pop() {
|
|
21424
|
+
const items = this.items;
|
|
21425
|
+
const top = items[0];
|
|
21426
|
+
const last = items.pop();
|
|
21427
|
+
if (items.length > 0 && last) {
|
|
21428
|
+
items[0] = last;
|
|
21429
|
+
let i = 0;
|
|
21430
|
+
for (;;) {
|
|
21431
|
+
const l = 2 * i + 1;
|
|
21432
|
+
const r = l + 1;
|
|
21433
|
+
let min = i;
|
|
21434
|
+
if (l < items.length && items[l].magnitude < items[min].magnitude) min = l;
|
|
21435
|
+
if (r < items.length && items[r].magnitude < items[min].magnitude) min = r;
|
|
21436
|
+
if (min === i) break;
|
|
21437
|
+
[items[min], items[i]] = [items[i], items[min]];
|
|
21438
|
+
i = min;
|
|
21439
|
+
}
|
|
21440
|
+
}
|
|
21441
|
+
return top;
|
|
21442
|
+
}
|
|
21443
|
+
};
|
|
21444
|
+
|
|
21445
|
+
//#endregion
|
|
21446
|
+
//#region src/lib/scene/visibility/system-fade.ts
|
|
21447
|
+
var SYSTEM_RADIUS_AU = 30.07;
|
|
21448
|
+
var SYSTEM_OUT_PX = 4.3;
|
|
21449
|
+
var SYSTEM_IN_PX = 4.75;
|
|
21450
|
+
function systemDiameterPx(distanceScene, viewportPx, fovDeg) {
|
|
21451
|
+
const pxPerRad = viewportPx / 2 / Math.tan(fovDeg * Math.PI / 360);
|
|
21452
|
+
return 2 * SYSTEM_RADIUS_AU * 10 / distanceScene * pxPerRad;
|
|
21453
|
+
}
|
|
21454
|
+
function systemShown(distanceScene, viewportPx, fovDeg, shown) {
|
|
21455
|
+
const px = systemDiameterPx(distanceScene, viewportPx, fovDeg);
|
|
21456
|
+
if (px < 4.3) return false;
|
|
21457
|
+
if (px > 4.75) return true;
|
|
21458
|
+
return shown;
|
|
21459
|
+
}
|
|
21460
|
+
|
|
19430
21461
|
//#endregion
|
|
19431
21462
|
//#region src/lib/scene/interaction/picking.ts
|
|
19432
|
-
function
|
|
19433
|
-
|
|
21463
|
+
function isCoarsePointer(pointerType) {
|
|
21464
|
+
return pointerType === "touch" || pointerType === "pen";
|
|
21465
|
+
}
|
|
21466
|
+
function pickRadiusPx(pointerType) {
|
|
21467
|
+
return isCoarsePointer(pointerType) ? 48 : 24;
|
|
21468
|
+
}
|
|
21469
|
+
function pickMoonDot(pick) {
|
|
21470
|
+
const { ctx } = pick;
|
|
21471
|
+
return pickDot(ctx.bodies.majorBodies.filter((body) => body.data.objectType === ObjectType.MOON && ctx.visibility.isMoonGroupVisible(body.data.parentId)), pick);
|
|
21472
|
+
}
|
|
21473
|
+
function pickPlanetDot(pick) {
|
|
21474
|
+
const { ctx, camera, focusTruePos } = pick;
|
|
21475
|
+
const [fx, fy, fz] = focusTruePos;
|
|
21476
|
+
const cam = camera.position;
|
|
21477
|
+
return pickDot(ctx.bodies.majorBodies.filter((body) => {
|
|
21478
|
+
const t = body.data.objectType;
|
|
21479
|
+
if (t !== ObjectType.STAR && t !== ObjectType.PLANET && t !== ObjectType.DWARF_PLANET) return false;
|
|
21480
|
+
const at = body.position;
|
|
21481
|
+
if (!at) return false;
|
|
21482
|
+
const dist = Math.hypot(at[0] - fx - cam.x, at[1] - fy - cam.y, at[2] - fz - cam.z);
|
|
21483
|
+
return ctx.visibility.getPlanetVisibility(body, dist) !== VISIBILITY.HIDE;
|
|
21484
|
+
}), pick);
|
|
21485
|
+
}
|
|
21486
|
+
function pickDot(bodies, pick) {
|
|
21487
|
+
const { pointer, camera, ctx, canvasWidth, canvasHeight, jd, isVisible } = pick;
|
|
19434
21488
|
const px = (pointer.x + 1) * .5 * canvasWidth;
|
|
19435
21489
|
const py = (1 - pointer.y) * .5 * canvasHeight;
|
|
19436
|
-
const v = tmpV3;
|
|
19437
|
-
const [fx, fy, fz] = focusTruePos;
|
|
21490
|
+
const v = pick.tmpV3;
|
|
21491
|
+
const [fx, fy, fz] = pick.focusTruePos;
|
|
19438
21492
|
const cam = camera.position;
|
|
19439
21493
|
let bestBody;
|
|
19440
|
-
let bestScreenDist =
|
|
21494
|
+
let bestScreenDist = pickRadiusPx(pick.pointerType);
|
|
19441
21495
|
let bestWorldDist = Infinity;
|
|
19442
|
-
const
|
|
21496
|
+
for (const body of bodies) {
|
|
19443
21497
|
const at = ctx.place(body, jd);
|
|
19444
|
-
if (!at)
|
|
21498
|
+
if (!at) continue;
|
|
19445
21499
|
v.set(at[0] - fx, at[1] - fy, at[2] - fz);
|
|
19446
21500
|
const worldDist = Math.hypot(v.x - cam.x, v.y - cam.y, v.z - cam.z);
|
|
19447
21501
|
v.project(camera);
|
|
19448
|
-
if (!ndcZVisible(v.z))
|
|
21502
|
+
if (!ndcZVisible(v.z)) continue;
|
|
19449
21503
|
const sx = (v.x + 1) * .5 * canvasWidth;
|
|
19450
21504
|
const sy = (1 - v.y) * .5 * canvasHeight;
|
|
19451
21505
|
const screenDist = Math.hypot(sx - px, sy - py);
|
|
19452
|
-
if (!(screenDist < bestScreenDist || screenDist === bestScreenDist && worldDist < bestWorldDist))
|
|
19453
|
-
if (isVisible && !isVisible(v.x, v.y, worldDist))
|
|
21506
|
+
if (!(screenDist < bestScreenDist || screenDist === bestScreenDist && worldDist < bestWorldDist)) continue;
|
|
21507
|
+
if (isVisible && !isVisible(v.x, v.y, worldDist)) continue;
|
|
19454
21508
|
bestScreenDist = screenDist;
|
|
19455
21509
|
bestWorldDist = worldDist;
|
|
19456
21510
|
bestBody = body;
|
|
19457
|
-
};
|
|
19458
|
-
for (const body of ctx.bodies.majorBodies) {
|
|
19459
|
-
if (body.data.objectType !== ObjectType.MOON) continue;
|
|
19460
|
-
if (!ctx.visibility.isMoonGroupVisible(body.data.parentId)) continue;
|
|
19461
|
-
testBody(body);
|
|
19462
21511
|
}
|
|
19463
21512
|
if (!bestBody) return null;
|
|
19464
21513
|
return {
|
|
@@ -19470,7 +21519,12 @@ function pickMoonDot(pointer, camera, ctx, focusTruePos, canvasWidth, canvasHeig
|
|
|
19470
21519
|
|
|
19471
21520
|
//#endregion
|
|
19472
21521
|
//#region src/lib/scene/interaction/pointer.ts
|
|
19473
|
-
var
|
|
21522
|
+
var CLICK_DRAG_PX = 3;
|
|
21523
|
+
var TOUCH_SLOP_PX = 10;
|
|
21524
|
+
function movedTooFar(e, from) {
|
|
21525
|
+
const limit = isCoarsePointer(e.pointerType) ? TOUCH_SLOP_PX : CLICK_DRAG_PX;
|
|
21526
|
+
return Math.hypot(e.clientX - from.x, e.clientY - from.y) > limit;
|
|
21527
|
+
}
|
|
19474
21528
|
function inHiddenRoot(obj) {
|
|
19475
21529
|
let top = obj;
|
|
19476
21530
|
while (top.parent?.parent) top = top.parent;
|
|
@@ -19478,11 +21532,13 @@ function inHiddenRoot(obj) {
|
|
|
19478
21532
|
}
|
|
19479
21533
|
var PointerInteraction = class {
|
|
19480
21534
|
downPos = new Vector2();
|
|
21535
|
+
down = /* @__PURE__ */ new Set();
|
|
21536
|
+
gesture = false;
|
|
19481
21537
|
pointer = new Vector2();
|
|
19482
21538
|
_tmpPointer = new Vector2();
|
|
19483
21539
|
raycaster = new Raycaster();
|
|
19484
21540
|
_tmpV3 = new Vector3();
|
|
19485
|
-
constructor(canvas, camera, ctx, clock, focus, clickables, meshToBody, onPick, modelPick, gpuPick, getClouds, pickRegistry) {
|
|
21541
|
+
constructor(canvas, camera, ctx, clock, focus, clickables, meshToBody, onPick, modelPick, gpuPick, getClouds, pickRegistry, getStars, onStarPick) {
|
|
19486
21542
|
this.canvas = canvas;
|
|
19487
21543
|
this.camera = camera;
|
|
19488
21544
|
this.ctx = ctx;
|
|
@@ -19495,22 +21551,39 @@ var PointerInteraction = class {
|
|
|
19495
21551
|
this.gpuPick = gpuPick;
|
|
19496
21552
|
this.getClouds = getClouds;
|
|
19497
21553
|
this.pickRegistry = pickRegistry;
|
|
21554
|
+
this.getStars = getStars;
|
|
21555
|
+
this.onStarPick = onStarPick;
|
|
19498
21556
|
}
|
|
19499
21557
|
attach() {
|
|
19500
21558
|
this.canvas.addEventListener("pointerdown", this.onDown);
|
|
21559
|
+
this.canvas.addEventListener("pointermove", this.onMove);
|
|
19501
21560
|
this.canvas.addEventListener("pointerup", this.onUp);
|
|
21561
|
+
this.canvas.addEventListener("pointercancel", this.onCancel);
|
|
19502
21562
|
}
|
|
19503
21563
|
detach() {
|
|
19504
21564
|
this.canvas.removeEventListener("pointerdown", this.onDown);
|
|
21565
|
+
this.canvas.removeEventListener("pointermove", this.onMove);
|
|
19505
21566
|
this.canvas.removeEventListener("pointerup", this.onUp);
|
|
21567
|
+
this.canvas.removeEventListener("pointercancel", this.onCancel);
|
|
19506
21568
|
}
|
|
19507
21569
|
onDown = (e) => {
|
|
19508
|
-
|
|
21570
|
+
if (e.isPrimary) {
|
|
21571
|
+
this.down.clear();
|
|
21572
|
+
this.gesture = false;
|
|
21573
|
+
this.downPos.set(e.clientX, e.clientY);
|
|
21574
|
+
} else this.gesture = true;
|
|
21575
|
+
this.down.add(e.pointerId);
|
|
21576
|
+
};
|
|
21577
|
+
onMove = (e) => {
|
|
21578
|
+
if (this.gesture || !this.down.has(e.pointerId)) return;
|
|
21579
|
+
if (movedTooFar(e, this.downPos)) this.gesture = true;
|
|
21580
|
+
};
|
|
21581
|
+
onCancel = (e) => {
|
|
21582
|
+
this.down.delete(e.pointerId);
|
|
21583
|
+
this.gesture = true;
|
|
19509
21584
|
};
|
|
19510
21585
|
onUp = (e) => {
|
|
19511
|
-
|
|
19512
|
-
const dy = e.clientY - this.downPos.y;
|
|
19513
|
-
if (dx * dx + dy * dy > CLICK_DRAG_PX2) return;
|
|
21586
|
+
if (!this.down.delete(e.pointerId) || this.gesture || movedTooFar(e, this.downPos)) return;
|
|
19514
21587
|
const rect = this.canvas.getBoundingClientRect();
|
|
19515
21588
|
this.pointer.set((e.clientX - rect.left) / rect.width * 2 - 1, -((e.clientY - rect.top) / rect.height) * 2 + 1);
|
|
19516
21589
|
const modelBody = this.modelPick(this.pointer.x, this.pointer.y);
|
|
@@ -19520,11 +21593,41 @@ var PointerInteraction = class {
|
|
|
19520
21593
|
}
|
|
19521
21594
|
this.raycaster.setFromCamera(this.pointer, this.camera);
|
|
19522
21595
|
const meshBody = this.resolveMeshHit(this.raycaster.intersectObjects([...this.clickables, ...attachedModelRoots]))?.body;
|
|
19523
|
-
const
|
|
21596
|
+
const dots = {
|
|
21597
|
+
pointer: this.pointer,
|
|
21598
|
+
camera: this.camera,
|
|
21599
|
+
ctx: this.ctx,
|
|
21600
|
+
focusTruePos: this.focus.focusTruePos,
|
|
21601
|
+
canvasWidth: this.canvas.clientWidth,
|
|
21602
|
+
canvasHeight: this.canvas.clientHeight,
|
|
21603
|
+
tmpV3: this._tmpV3,
|
|
21604
|
+
jd: this.clock.jd,
|
|
21605
|
+
pointerType: e.pointerType,
|
|
21606
|
+
isVisible: this.isDotVisible
|
|
21607
|
+
};
|
|
21608
|
+
const moonHit = pickMoonDot(dots);
|
|
19524
21609
|
const gpuHit = this.gpuPickCloud(e, rect);
|
|
19525
21610
|
const bestBody = this.nearer(moonHit, gpuHit)?.body ?? meshBody;
|
|
19526
|
-
if (bestBody)
|
|
21611
|
+
if (bestBody) {
|
|
21612
|
+
this.onPick(bestBody);
|
|
21613
|
+
return;
|
|
21614
|
+
}
|
|
21615
|
+
this.pickStar(e, rect, dots);
|
|
19527
21616
|
};
|
|
21617
|
+
pickStar(e, rect, dots) {
|
|
21618
|
+
const stars = this.getStars();
|
|
21619
|
+
if (stars.length === 0) return;
|
|
21620
|
+
const planet = pickPlanetDot(dots);
|
|
21621
|
+
if (planet) {
|
|
21622
|
+
this.onPick(planet.body);
|
|
21623
|
+
return;
|
|
21624
|
+
}
|
|
21625
|
+
const candidates = this.gpuPick.pickDraws(stars, this.camera, e.clientX, e.clientY, rect, pickRadiusPx(e.pointerType));
|
|
21626
|
+
for (const c of candidates) {
|
|
21627
|
+
if (!this.isDotVisible(c.ndcX, c.ndcY, Infinity)) continue;
|
|
21628
|
+
if (this.onStarPick(c.pickId)) return;
|
|
21629
|
+
}
|
|
21630
|
+
}
|
|
19528
21631
|
nearer(a, b) {
|
|
19529
21632
|
if (!a) return b;
|
|
19530
21633
|
if (!b) return a;
|
|
@@ -19533,9 +21636,8 @@ var PointerInteraction = class {
|
|
|
19533
21636
|
return a;
|
|
19534
21637
|
}
|
|
19535
21638
|
gpuPickCloud(e, rect) {
|
|
19536
|
-
const radius = e.pointerType === "touch" || e.pointerType === "pen" ? 48 : 24;
|
|
19537
21639
|
const jd = this.clock.jd;
|
|
19538
|
-
const candidates = this.gpuPick.pick(this.getClouds(), this.camera, e.clientX, e.clientY, rect,
|
|
21640
|
+
const candidates = this.gpuPick.pick(this.getClouds(), this.camera, e.clientX, e.clientY, rect, pickRadiusPx(e.pointerType));
|
|
19539
21641
|
for (const c of candidates) {
|
|
19540
21642
|
const bodyId = this.pickRegistry.resolve(c.pickId);
|
|
19541
21643
|
if (!bodyId) continue;
|
|
@@ -19618,6 +21720,7 @@ var GpuPickPass = class {
|
|
|
19618
21720
|
buffer = new Uint8Array(0);
|
|
19619
21721
|
prevClear = new Color();
|
|
19620
21722
|
proxies = [];
|
|
21723
|
+
idleGeometry = new BufferGeometry();
|
|
19621
21724
|
constructor(renderer, camera) {
|
|
19622
21725
|
this.renderer = renderer;
|
|
19623
21726
|
this.target = new WebGLRenderTarget(1, 1, { depthBuffer: true });
|
|
@@ -19640,19 +21743,33 @@ var GpuPickPass = class {
|
|
|
19640
21743
|
this.target.setSize(px, px);
|
|
19641
21744
|
this.buffer = new Uint8Array(px * px * 4);
|
|
19642
21745
|
}
|
|
19643
|
-
proxyAt(index, src) {
|
|
21746
|
+
proxyAt(index, src, material) {
|
|
19644
21747
|
let p = this.proxies[index];
|
|
19645
21748
|
if (!p) {
|
|
19646
|
-
p = new Points(src.geometry,
|
|
21749
|
+
p = new Points(src.geometry, material);
|
|
19647
21750
|
p.frustumCulled = false;
|
|
19648
21751
|
p.matrixAutoUpdate = false;
|
|
19649
21752
|
p.matrixWorldAutoUpdate = false;
|
|
19650
21753
|
this.proxies[index] = p;
|
|
19651
|
-
} else
|
|
21754
|
+
} else {
|
|
21755
|
+
p.geometry = src.geometry;
|
|
21756
|
+
p.material = material;
|
|
21757
|
+
}
|
|
19652
21758
|
p.matrixWorld.copy(src.matrixWorld);
|
|
19653
21759
|
return p;
|
|
19654
21760
|
}
|
|
19655
21761
|
pick(clouds, camera, clientX, clientY, rect, radiusCss) {
|
|
21762
|
+
const draws = [];
|
|
21763
|
+
for (const points of clouds) {
|
|
21764
|
+
if (!points.geometry.getAttribute("pickColor")) continue;
|
|
21765
|
+
draws.push({
|
|
21766
|
+
points,
|
|
21767
|
+
material: this.material
|
|
21768
|
+
});
|
|
21769
|
+
}
|
|
21770
|
+
return this.pickDraws(draws, camera, clientX, clientY, rect, radiusCss);
|
|
21771
|
+
}
|
|
21772
|
+
pickDraws(draws, camera, clientX, clientY, rect, radiusCss) {
|
|
19656
21773
|
const r = Math.max(1, Math.round(radiusCss));
|
|
19657
21774
|
const boxPx = r * 2 + 1;
|
|
19658
21775
|
this.ensureSize(boxPx);
|
|
@@ -19660,13 +21777,11 @@ var GpuPickPass = class {
|
|
|
19660
21777
|
const cy = clientY - rect.top;
|
|
19661
21778
|
const offsetX = cx - r;
|
|
19662
21779
|
const offsetY = cy - r;
|
|
19663
|
-
this.scene.clear();
|
|
19664
21780
|
let n = 0;
|
|
19665
|
-
for (const
|
|
19666
|
-
if (!
|
|
19667
|
-
if (
|
|
19668
|
-
|
|
19669
|
-
this.scene.add(this.proxyAt(n++, pts));
|
|
21781
|
+
for (const { points, material } of draws) {
|
|
21782
|
+
if (!points.visible) continue;
|
|
21783
|
+
if (points.geometry.drawRange.count === 0) continue;
|
|
21784
|
+
this.scene.add(this.proxyAt(n++, points, material));
|
|
19670
21785
|
}
|
|
19671
21786
|
if (n === 0) return [];
|
|
19672
21787
|
this.pickCamera.copy(camera);
|
|
@@ -19682,12 +21797,21 @@ var GpuPickPass = class {
|
|
|
19682
21797
|
this.renderer.clear(true, true, false);
|
|
19683
21798
|
this.renderer.render(this.scene, this.pickCamera);
|
|
19684
21799
|
this.renderer.readRenderTargetPixels(this.target, 0, 0, boxPx, boxPx, this.buffer);
|
|
21800
|
+
this.letGo(n);
|
|
19685
21801
|
this.renderer.setRenderTarget(prevTarget);
|
|
19686
21802
|
this.renderer.autoClear = prevAutoClear;
|
|
19687
21803
|
this.renderer.setClearColor(this.prevClear, prevClearAlpha);
|
|
19688
21804
|
this.pickCamera.clearViewOffset();
|
|
19689
21805
|
return this.decode(boxPx, r, rect, offsetX, offsetY);
|
|
19690
21806
|
}
|
|
21807
|
+
letGo(n) {
|
|
21808
|
+
this.scene.clear();
|
|
21809
|
+
for (let i = 0; i < n; i++) {
|
|
21810
|
+
this.proxies[i].geometry = this.idleGeometry;
|
|
21811
|
+
this.proxies[i].material = this.material;
|
|
21812
|
+
}
|
|
21813
|
+
this.renderer.render(this.scene, this.pickCamera);
|
|
21814
|
+
}
|
|
19691
21815
|
decode(boxPx, r, rect, offsetX, offsetY) {
|
|
19692
21816
|
const buf = this.buffer;
|
|
19693
21817
|
const nearest = /* @__PURE__ */ new Map();
|
|
@@ -19717,6 +21841,7 @@ var GpuPickPass = class {
|
|
|
19717
21841
|
dispose() {
|
|
19718
21842
|
this.target.dispose();
|
|
19719
21843
|
this.material.dispose();
|
|
21844
|
+
this.idleGeometry.dispose();
|
|
19720
21845
|
this.proxies.length = 0;
|
|
19721
21846
|
}
|
|
19722
21847
|
};
|
|
@@ -20130,7 +22255,7 @@ function buildMajorBodies(bodies, scene, clickables, meshToBody, bodyObjects, re
|
|
|
20130
22255
|
const id = body.data.id;
|
|
20131
22256
|
const isHalfPromoted = halfPromoteIds?.has(id) ?? false;
|
|
20132
22257
|
const t = body.data.objectType;
|
|
20133
|
-
const isVirtual = isHalfPromoted || t === ObjectType.BARYCENTER || t === ObjectType.LAGRANGE_POINT || t === ObjectType.COMET || isAsteroid(t) || body.data.orbitalSource === OrbitalSource.SPICE_PROBE;
|
|
22258
|
+
const isVirtual = isHalfPromoted || t === ObjectType.EXTRASOLAR || t === ObjectType.BARYCENTER || t === ObjectType.LAGRANGE_POINT || t === ObjectType.COMET || isAsteroid(t) || body.data.orbitalSource === OrbitalSource.SPICE_PROBE;
|
|
20134
22259
|
const color = resolveBodyColor(body.data);
|
|
20135
22260
|
const radius = kmToScene(effectiveRadiusKm(body.data));
|
|
20136
22261
|
const isStar = t === ObjectType.STAR;
|
|
@@ -20173,7 +22298,7 @@ function buildMajorBodies(bodies, scene, clickables, meshToBody, bodyObjects, re
|
|
|
20173
22298
|
}
|
|
20174
22299
|
}
|
|
20175
22300
|
const variant = getLabelVariant(body);
|
|
20176
|
-
const isLarge = isStar || t === ObjectType.PLANET;
|
|
22301
|
+
const isLarge = isStar || t === ObjectType.EXTRASOLAR || t === ObjectType.PLANET;
|
|
20177
22302
|
const isMinor = isHalfPromoted || MINOR_PROMOTED_IDS.has(id) || body.data.isMinor === true;
|
|
20178
22303
|
const label = createLabel(color, body.data.name ?? "", variant, host().bodyHref(id, body.data.name ?? ""), () => handleFocus(body), isLarge, onHoverChange ? (hovered) => onHoverChange(id, hovered) : void 0, isMinor);
|
|
20179
22304
|
if (label) {
|
|
@@ -21066,7 +23191,7 @@ function buildTrails(bodyObjects, scene, basisPos = [
|
|
|
21066
23191
|
for (const [, bo] of bodyObjects) {
|
|
21067
23192
|
if (bo.trail !== null) continue;
|
|
21068
23193
|
const { body } = bo;
|
|
21069
|
-
if (body.data.objectType === ObjectType.STAR) continue;
|
|
23194
|
+
if (body.data.objectType === ObjectType.STAR || isExtrasolar(body)) continue;
|
|
21070
23195
|
if (body.data.orbitalSource === OrbitalSource.SPICE_PROBE) {
|
|
21071
23196
|
if (bo.isMinor && !bo.mesh) continue;
|
|
21072
23197
|
} else if (!bo.mesh && !bo.focusUpgraded && isMeshUpgradable(body)) continue;
|
|
@@ -22182,10 +24307,18 @@ var PickRegistry = class {
|
|
|
22182
24307
|
#next = 1;
|
|
22183
24308
|
#groups = /* @__PURE__ */ new Map();
|
|
22184
24309
|
allocate(groupId, keys) {
|
|
24310
|
+
return this.add(groupId, keys.length, keys);
|
|
24311
|
+
}
|
|
24312
|
+
allocateRows(groupId, length) {
|
|
24313
|
+
return this.add(groupId, length, null);
|
|
24314
|
+
}
|
|
24315
|
+
add(groupId, length, keys) {
|
|
22185
24316
|
const base = this.#next;
|
|
22186
|
-
this.#next +=
|
|
24317
|
+
this.#next += length;
|
|
22187
24318
|
this.#groups.set(groupId, {
|
|
24319
|
+
groupId,
|
|
22188
24320
|
base,
|
|
24321
|
+
length,
|
|
22189
24322
|
keys
|
|
22190
24323
|
});
|
|
22191
24324
|
return base;
|
|
@@ -22194,8 +24327,20 @@ var PickRegistry = class {
|
|
|
22194
24327
|
this.#groups.delete(groupId);
|
|
22195
24328
|
}
|
|
22196
24329
|
resolve(pickId) {
|
|
22197
|
-
|
|
22198
|
-
|
|
24330
|
+
const group = this.find(pickId);
|
|
24331
|
+
if (!group?.keys) return null;
|
|
24332
|
+
return keyToId(group.keys[pickId - group.base]);
|
|
24333
|
+
}
|
|
24334
|
+
locate(pickId) {
|
|
24335
|
+
const group = this.find(pickId);
|
|
24336
|
+
if (!group || group.keys) return null;
|
|
24337
|
+
return {
|
|
24338
|
+
groupId: group.groupId,
|
|
24339
|
+
row: pickId - group.base
|
|
24340
|
+
};
|
|
24341
|
+
}
|
|
24342
|
+
find(pickId) {
|
|
24343
|
+
for (const group of this.#groups.values()) if (pickId >= group.base && pickId < group.base + group.length) return group;
|
|
22199
24344
|
return null;
|
|
22200
24345
|
}
|
|
22201
24346
|
clear() {
|
|
@@ -22295,6 +24440,8 @@ var PointCloudSystem = class {
|
|
|
22295
24440
|
brightMult: 1,
|
|
22296
24441
|
opacity: EMPHASIS_BASE_OPACITY
|
|
22297
24442
|
};
|
|
24443
|
+
fade = 1;
|
|
24444
|
+
moonFades = /* @__PURE__ */ new Map();
|
|
22298
24445
|
constructor(ctx, scene, bodyObjects, circleTexture, focus, mapLayer, onBasisRebuilt) {
|
|
22299
24446
|
this.ctx = ctx;
|
|
22300
24447
|
this.scene = scene;
|
|
@@ -22314,13 +24461,13 @@ var PointCloudSystem = class {
|
|
|
22314
24461
|
}
|
|
22315
24462
|
applyPointBudget() {
|
|
22316
24463
|
let total = 0;
|
|
22317
|
-
for (const kind of WORKER_CLOUD_KINDS) for (const pts of this.workerPoints[kind].values()) if (pts.visible) total += pts.userData.solvedCount ?? 0;
|
|
22318
|
-
|
|
22319
|
-
if (fraction === this.drawFraction) return;
|
|
22320
|
-
this.drawFraction = fraction;
|
|
24464
|
+
for (const kind of WORKER_CLOUD_KINDS) for (const pts of this.workerPoints[kind].values()) if (pts.visible && !pts.userData.leaving) total += pts.userData.solvedCount ?? 0;
|
|
24465
|
+
this.drawFraction = total > this.pointBudget ? this.pointBudget / total : 1;
|
|
22321
24466
|
for (const kind of WORKER_CLOUD_KINDS) for (const pts of this.workerPoints[kind].values()) {
|
|
24467
|
+
if (pts.userData.leaving || pts.userData.drawFraction === this.drawFraction) continue;
|
|
24468
|
+
pts.userData.drawFraction = this.drawFraction;
|
|
22322
24469
|
const n = pts.userData.solvedCount;
|
|
22323
|
-
if (n !== void 0) pts.geometry.setDrawRange(0, Math.ceil(n *
|
|
24470
|
+
if (n !== void 0) pts.geometry.setDrawRange(0, Math.ceil(n * this.drawFraction));
|
|
22324
24471
|
}
|
|
22325
24472
|
}
|
|
22326
24473
|
setEarthSatEmphasis(count) {
|
|
@@ -22343,7 +24490,49 @@ var PointCloudSystem = class {
|
|
|
22343
24490
|
const { size, dim, opacity } = this.earthSatEmphasis;
|
|
22344
24491
|
mat.size = size;
|
|
22345
24492
|
mat.color.setRGB(dim, dim, dim);
|
|
22346
|
-
|
|
24493
|
+
this.setOpacity(pts, opacity);
|
|
24494
|
+
}
|
|
24495
|
+
setFade(fade) {
|
|
24496
|
+
if (fade === this.fade) return;
|
|
24497
|
+
this.fade = fade;
|
|
24498
|
+
for (const kind of WORKER_CLOUD_KINDS) for (const pts of this.workerPoints[kind].values()) this.applyOpacity(pts);
|
|
24499
|
+
for (const pts of this.moonPoints.values()) this.applyOpacity(pts);
|
|
24500
|
+
}
|
|
24501
|
+
setOpacity(pts, opacity) {
|
|
24502
|
+
pts.userData.opacity = opacity;
|
|
24503
|
+
this.applyOpacity(pts);
|
|
24504
|
+
}
|
|
24505
|
+
applyOpacity(pts) {
|
|
24506
|
+
pts.material.opacity = pts.userData.opacity * this.fade * (pts.userData.share ?? 1);
|
|
24507
|
+
}
|
|
24508
|
+
updateVisibility(dtMs) {
|
|
24509
|
+
const vis = this.ctx.visibility;
|
|
24510
|
+
for (const [key, pts] of this.workerPoints.asteroid) this.setShare(pts, vis.asteroidGroupShare(parentIdFromSubkey(key)));
|
|
24511
|
+
for (const [key, pts] of this.workerPoints.spacecraft) this.setShare(pts, vis.spacecraftGroupShare(parentIdFromSubkey(key)));
|
|
24512
|
+
for (const [parentId, pts] of this.moonPoints) {
|
|
24513
|
+
let fade = this.moonFades.get(parentId);
|
|
24514
|
+
if (!fade) {
|
|
24515
|
+
fade = new SwitchFade(void 0, 100);
|
|
24516
|
+
this.moonFades.set(parentId, fade);
|
|
24517
|
+
}
|
|
24518
|
+
fade.step(vis.isMoonGroupVisible(parentId), dtMs);
|
|
24519
|
+
this.setShare(pts, fade.share);
|
|
24520
|
+
}
|
|
24521
|
+
}
|
|
24522
|
+
get fading() {
|
|
24523
|
+
for (const fade of this.moonFades.values()) if (fade.fading) return true;
|
|
24524
|
+
return false;
|
|
24525
|
+
}
|
|
24526
|
+
setShare(pts, share) {
|
|
24527
|
+
pts.visible = share > 0;
|
|
24528
|
+
const was = pts.userData.share;
|
|
24529
|
+
if (was === share) return;
|
|
24530
|
+
pts.userData.leaving = was !== void 0 && share < was;
|
|
24531
|
+
pts.userData.share = share;
|
|
24532
|
+
this.applyOpacity(pts);
|
|
24533
|
+
}
|
|
24534
|
+
fadeNewCloud(pts) {
|
|
24535
|
+
this.setOpacity(pts, pts.material.opacity);
|
|
22347
24536
|
}
|
|
22348
24537
|
setEmphasizedSmallBodyZone(zone, count) {
|
|
22349
24538
|
const prev = this.emphasizedSmallBodyZone;
|
|
@@ -22375,14 +24564,14 @@ var PointCloudSystem = class {
|
|
|
22375
24564
|
const { sizeMult, brightMult, opacity } = this.smallBodyEmphasis;
|
|
22376
24565
|
mat.size = baseSize * sizeMult;
|
|
22377
24566
|
mat.color.copy(baseColor).multiplyScalar(brightMult);
|
|
22378
|
-
|
|
24567
|
+
this.setOpacity(pts, opacity);
|
|
22379
24568
|
}
|
|
22380
24569
|
resetSmallBodyEmphasis(pts) {
|
|
22381
24570
|
if (pts.userData.smallBodyBaseSize === void 0) return;
|
|
22382
24571
|
const mat = pts.material;
|
|
22383
24572
|
mat.size = pts.userData.smallBodyBaseSize;
|
|
22384
24573
|
mat.color.copy(pts.userData.smallBodyBaseColor);
|
|
22385
|
-
|
|
24574
|
+
this.setOpacity(pts, EMPHASIS_BASE_OPACITY);
|
|
22386
24575
|
pts.userData.smallBodyBaseSize = void 0;
|
|
22387
24576
|
pts.userData.smallBodyBaseColor = void 0;
|
|
22388
24577
|
}
|
|
@@ -22397,8 +24586,10 @@ var PointCloudSystem = class {
|
|
|
22397
24586
|
for (const kind of WORKER_CLOUD_KINDS) for (const [key, p] of this.workerPoints[kind]) {
|
|
22398
24587
|
const bucketKey = parentIdFromSubkey(key);
|
|
22399
24588
|
p.userData.parentBodyId = this.cloudParentId(kind, bucketKey);
|
|
24589
|
+
this.fadeNewCloud(p);
|
|
22400
24590
|
this.emphasiseNewCloud(kind, bucketKey, p);
|
|
22401
24591
|
}
|
|
24592
|
+
for (const p of this.moonPoints.values()) this.fadeNewCloud(p);
|
|
22402
24593
|
this.assignMapLayer();
|
|
22403
24594
|
}
|
|
22404
24595
|
assignMapLayer() {
|
|
@@ -22556,6 +24747,7 @@ var PointCloudSystem = class {
|
|
|
22556
24747
|
0,
|
|
22557
24748
|
0
|
|
22558
24749
|
];
|
|
24750
|
+
this.fadeNewCloud(pts);
|
|
22559
24751
|
this.emphasiseNewCloud(kind, bucketKey, pts);
|
|
22560
24752
|
this.workerPoints[kind].set(key, pts);
|
|
22561
24753
|
this.pendingSceneAdds.push(pts);
|
|
@@ -22613,7 +24805,8 @@ var PointCloudSystem = class {
|
|
|
22613
24805
|
posAttr.needsUpdate = true;
|
|
22614
24806
|
this.bindPickIds(pts, pickIds);
|
|
22615
24807
|
pts.userData.solvedCount = count;
|
|
22616
|
-
pts.
|
|
24808
|
+
const fraction = pts.userData.drawFraction ?? this.drawFraction;
|
|
24809
|
+
pts.geometry.setDrawRange(0, Math.ceil(count * fraction));
|
|
22617
24810
|
this.lastSolvedJd.set(groupId, jd);
|
|
22618
24811
|
pts.userData.frontBasis = [
|
|
22619
24812
|
basisUsed[0],
|
|
@@ -22749,7 +24942,7 @@ var PointCloudSystem = class {
|
|
|
22749
24942
|
for (const [parentId, moons] of this.moonsByParent()) {
|
|
22750
24943
|
const pts = this.moonPoints.get(parentId);
|
|
22751
24944
|
if (!pts) continue;
|
|
22752
|
-
if (!this.ctx.visibility.isMoonGroupVisible(parentId)) continue;
|
|
24945
|
+
if (!pts.visible && !this.ctx.visibility.isMoonGroupVisible(parentId)) continue;
|
|
22753
24946
|
const posAttr = pts.geometry.getAttribute("position");
|
|
22754
24947
|
const arr = posAttr.array;
|
|
22755
24948
|
const n = Math.min(moons.length, arr.length / 3);
|
|
@@ -23054,9 +25247,16 @@ var _anchorOut = {
|
|
|
23054
25247
|
};
|
|
23055
25248
|
var _modelSphereCenter = new Vector3();
|
|
23056
25249
|
var _anchorProj = new Vector3();
|
|
23057
|
-
function
|
|
25250
|
+
function fadeLabel(label, share) {
|
|
25251
|
+
if (label.userData.systemShare === share) return;
|
|
25252
|
+
label.userData.systemShare = share;
|
|
25253
|
+
label.element.style.opacity = share < 1 ? String(share) : "";
|
|
25254
|
+
}
|
|
25255
|
+
function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBodyId, hideCappedMoonLabels, hoveredBodyIds, cullFrameCounter, renderer, tmpV3, forceCull, suppressHeliocentricTrails) {
|
|
23058
25256
|
const layers = ctx.layers;
|
|
23059
25257
|
const hideOrbits = !layers.isVisible("orbits");
|
|
25258
|
+
const systemShare = ctx.visibility.systemShare;
|
|
25259
|
+
const starShare = ctx.visibility.starShare;
|
|
23060
25260
|
const showNomenclature = layers.isVisible("nomenclature");
|
|
23061
25261
|
const fovRad = camera.fov * Math.PI / 180;
|
|
23062
25262
|
const screenW = renderer.domElement.clientWidth;
|
|
@@ -23188,10 +25388,18 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
23188
25388
|
let isClose;
|
|
23189
25389
|
const isFocused = body.data.id === focusedBodyId;
|
|
23190
25390
|
const isSystemRoot = focusedSystemId !== null && body.data.id === focusedSystemId;
|
|
23191
|
-
|
|
25391
|
+
let zoneShare = 1;
|
|
25392
|
+
let labelThresholdShare = 1;
|
|
25393
|
+
let orbitThresholdShare = 1;
|
|
25394
|
+
if (isExtrasolar(body)) {
|
|
25395
|
+
const visible = starShare > 0;
|
|
25396
|
+
group.visible = visible;
|
|
25397
|
+
showLabel = visible;
|
|
25398
|
+
isClose = false;
|
|
25399
|
+
} else if (bo.mesh === null && !isMajorBody(body.data.objectType)) {
|
|
23192
25400
|
const ot = body.data.objectType;
|
|
23193
25401
|
if (ot === ObjectType.BARYCENTER || ot === ObjectType.LAGRANGE_POINT) {
|
|
23194
|
-
let visible =
|
|
25402
|
+
let visible = systemShare > 0;
|
|
23195
25403
|
const primaryId = !isFocused ? barycenterPrimaryId(body.data.id) : void 0;
|
|
23196
25404
|
if (primaryId) {
|
|
23197
25405
|
const primary = bodyObjects.get(primaryId)?.body ?? ctx.getBody(primaryId);
|
|
@@ -23204,7 +25412,9 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
23204
25412
|
showLabel = visible;
|
|
23205
25413
|
isClose = false;
|
|
23206
25414
|
} else {
|
|
23207
|
-
const
|
|
25415
|
+
const vis = ctx.visibility.getPlanetVisibility(body, dist);
|
|
25416
|
+
zoneShare = ctx.visibility.fullRenderingShare(body);
|
|
25417
|
+
const visible = vis !== VISIBILITY.HIDE && zoneShare > 0;
|
|
23208
25418
|
group.visible = visible;
|
|
23209
25419
|
if (trail) trail.visible = visible;
|
|
23210
25420
|
showLabel = visible;
|
|
@@ -23213,18 +25423,32 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
23213
25423
|
} else {
|
|
23214
25424
|
const isMoon = body.data.objectType === ObjectType.MOON;
|
|
23215
25425
|
const vis = isMoon ? ctx.visibility.getMoonVisibility(body) : ctx.visibility.getPlanetVisibility(body, dist);
|
|
23216
|
-
|
|
25426
|
+
if (!isMoon) zoneShare = ctx.visibility.fullRenderingShare(body);
|
|
25427
|
+
const vf = isMoon ? moonVisFlags(vis, hideCappedMoonLabels, isFocused) : bodyVisFlags(vis, zoneShare > 0, isFocused || isSystemRoot);
|
|
23217
25428
|
group.visible = vf.groupVisible;
|
|
23218
25429
|
if (trail) trail.visible = vf.orbitVisible;
|
|
23219
25430
|
showLabel = vf.showLabel;
|
|
23220
25431
|
isClose = vf.isClose;
|
|
23221
25432
|
}
|
|
25433
|
+
if (focusedSystemId !== null && ctx.visibility.isBodyInSystem(body, focusedSystemId)) {
|
|
25434
|
+
labelThresholdShare = ctx.visibility.labelThresholdShare(body.data.id, showLabel);
|
|
25435
|
+
orbitThresholdShare = ctx.visibility.orbitThresholdShare(body.data.id, !!trail?.visible);
|
|
25436
|
+
if (labelThresholdShare > 0) {
|
|
25437
|
+
group.visible = true;
|
|
25438
|
+
showLabel = true;
|
|
25439
|
+
}
|
|
25440
|
+
if (trail && orbitThresholdShare > 0) trail.visible = true;
|
|
25441
|
+
}
|
|
23222
25442
|
if (!drawn) {
|
|
23223
25443
|
group.visible = false;
|
|
23224
25444
|
showLabel = false;
|
|
23225
25445
|
isClose = false;
|
|
23226
25446
|
}
|
|
23227
25447
|
if (trail && (!drawn || body.orbitCenter === null)) trail.visible = false;
|
|
25448
|
+
if (trail) {
|
|
25449
|
+
trail.userData.zoneShare = zoneShare;
|
|
25450
|
+
trail.userData.thresholdShare = orbitThresholdShare;
|
|
25451
|
+
}
|
|
23228
25452
|
let starIsPoint = false;
|
|
23229
25453
|
if (bo.starPoint && drawn) {
|
|
23230
25454
|
const t = bo.radiusScene / dist * projScale / STAR_POINT_HANDOFF_R;
|
|
@@ -23257,12 +25481,10 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
23257
25481
|
}
|
|
23258
25482
|
}
|
|
23259
25483
|
if (applyLabelDisplay(bo, showLabel, isClose, dist, projScale, focusedBodyId)) newlyShownLabel = true;
|
|
25484
|
+
if (bo.label) fadeLabel(bo.label, bo.starPoint ? 1 : isExtrasolar(body) ? starShare : systemShare * zoneShare * labelThresholdShare);
|
|
23260
25485
|
const nomScreenR = bo.radiusScene > 0 ? bo.radiusScene / dist * projScale : 0;
|
|
23261
25486
|
updateNomenclatureVisibility(bo, showNomenclature && body.data.id === nomFocusedBodyId, nomScreenR, camera, screenW, screenH);
|
|
23262
25487
|
}
|
|
23263
|
-
for (const [key, pts] of asteroidPoints) pts.visible = ctx.visibility.isAsteroidGroupVisible(parentIdFromSubkey(key));
|
|
23264
|
-
for (const [key, pts] of spacecraftPoints) pts.visible = ctx.visibility.isSpacecraftGroupVisible(parentIdFromSubkey(key));
|
|
23265
|
-
for (const [parentId, pts] of moonPoints) pts.visible = ctx.visibility.isMoonGroupVisible(parentId);
|
|
23266
25488
|
if (screenOccluders.length > 0) {
|
|
23267
25489
|
const focusedPrimaryId = focusedBodyId ? barycenterPrimaryId(focusedBodyId) : null;
|
|
23268
25490
|
for (const bo of bodyObjects.values()) {
|
|
@@ -23288,7 +25510,8 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
23288
25510
|
mat.uniforms.uCenterOffset.value.set(-camera.position.x, -camera.position.y, -camera.position.z);
|
|
23289
25511
|
const isFocused = bo.body.data.id === focusedBodyId;
|
|
23290
25512
|
const isHovered = hoveredBodyIds.has(bo.body.data.id);
|
|
23291
|
-
|
|
25513
|
+
const share = systemShare * (line.userData.zoneShare ?? 1) * (line.userData.thresholdShare ?? 1);
|
|
25514
|
+
mat.uniforms.uAlphaMultiplier.value = (isHovered ? 2 : isFocused ? 1.75 : 1) * share;
|
|
23292
25515
|
const isClosed = line.userData.isOpenCurve === false;
|
|
23293
25516
|
mat.uniforms.uAlphaMin.value = isFocused && isClosed ? .15 : 0;
|
|
23294
25517
|
mat.uniforms.uShowFull.value = isFocused ? 1 : 0;
|
|
@@ -24620,6 +26843,10 @@ function renderLandedProbe(d, probe, landed, jd, where, ctx, bodyObjects) {
|
|
|
24620
26843
|
|
|
24621
26844
|
//#endregion
|
|
24622
26845
|
//#region src/lib/scene/position/placer.ts
|
|
26846
|
+
function fixedPlace(body) {
|
|
26847
|
+
const at = body.extrasolar?.scene;
|
|
26848
|
+
return at ? setPlaced(body, at[0], at[1], at[2]) : setUnplaced(body, "never");
|
|
26849
|
+
}
|
|
24623
26850
|
var newestPosScratch = [
|
|
24624
26851
|
0,
|
|
24625
26852
|
0,
|
|
@@ -24704,7 +26931,7 @@ var Placer = class {
|
|
|
24704
26931
|
return null;
|
|
24705
26932
|
}
|
|
24706
26933
|
this.settling.add(id);
|
|
24707
|
-
const pos = isSurfaceFeature(body) ? this.seatFeature(body, jd) : this.settle(body, jd);
|
|
26934
|
+
const pos = isSurfaceFeature(body) ? this.seatFeature(body, jd) : isExtrasolar(body) ? fixedPlace(body) : this.settle(body, jd);
|
|
24708
26935
|
this.settling.delete(id);
|
|
24709
26936
|
if (jd === this.passJd) this.settled.add(id);
|
|
24710
26937
|
return pos;
|
|
@@ -25433,6 +27660,13 @@ function updateSunShadowLight(bodyObjects, focusTruePos, ctx, shadowLight, sunPo
|
|
|
25433
27660
|
shadowCam.updateProjectionMatrix();
|
|
25434
27661
|
}
|
|
25435
27662
|
|
|
27663
|
+
//#endregion
|
|
27664
|
+
//#region src/lib/scene/relief/grid-heights.ts
|
|
27665
|
+
var CAP_SIN = Math.sin(60 * Math.PI / 180);
|
|
27666
|
+
function gridChart(level, y) {
|
|
27667
|
+
return level < 1 || Math.abs(y) <= CAP_SIN ? 0 : y > 0 ? 1 : 2;
|
|
27668
|
+
}
|
|
27669
|
+
|
|
25436
27670
|
//#endregion
|
|
25437
27671
|
//#region src/lib/scene/lod/terrain-grid.ts
|
|
25438
27672
|
var COARSE_SEGS = 128;
|
|
@@ -25650,7 +27884,14 @@ function heightTilesOf(bo) {
|
|
|
25650
27884
|
return reliefTilesAvailable(tiles) && !tiledStates.get(bo)?.dead ? tiles : void 0;
|
|
25651
27885
|
}
|
|
25652
27886
|
function gridLevel(tiles, theta, phi, radius) {
|
|
25653
|
-
const
|
|
27887
|
+
const y = Math.cos(theta);
|
|
27888
|
+
const chart = gridChart(tiles.max_level, y);
|
|
27889
|
+
const point = chartPoint(chart, ...[
|
|
27890
|
+
-Math.cos(phi) * Math.sin(theta),
|
|
27891
|
+
y,
|
|
27892
|
+
Math.sin(phi) * Math.sin(theta)
|
|
27893
|
+
]);
|
|
27894
|
+
const deepest = deepestLevel(tiles.max_level, tiles.patches, chart, point.x, point.y);
|
|
25654
27895
|
if (deepest === tiles.max_level) return deepest;
|
|
25655
27896
|
const floatStep = 2 ** (Math.floor(Math.log2(radius)) - 23);
|
|
25656
27897
|
const cells = 2 * Math.PI * radius / (CELL_FLOAT_STEPS * floatStep);
|
|
@@ -25718,7 +27959,8 @@ function updateTiledWindow(bo, mesh, tiles, altitude, centerTheta, centerPhi, in
|
|
|
25718
27959
|
root: tileRoot(tiles),
|
|
25719
27960
|
version: tiles.version,
|
|
25720
27961
|
maxLevel: tiles.max_level,
|
|
25721
|
-
patches: (tiles.patches ?? []).map(({ max_level, x, y, version }) => ({
|
|
27962
|
+
patches: (tiles.patches ?? []).map(({ cap, max_level, x, y, version }) => ({
|
|
27963
|
+
cap,
|
|
25722
27964
|
max_level,
|
|
25723
27965
|
x,
|
|
25724
27966
|
y,
|
|
@@ -26289,6 +28531,7 @@ var PromotionRegistry = class {
|
|
|
26289
28531
|
autoPromoted = /* @__PURE__ */ new Set();
|
|
26290
28532
|
pinned = /* @__PURE__ */ new Set();
|
|
26291
28533
|
pinPromoted = /* @__PURE__ */ new Set();
|
|
28534
|
+
focusPromoted = /* @__PURE__ */ new Set();
|
|
26292
28535
|
groupTargets = null;
|
|
26293
28536
|
groupMode = "none";
|
|
26294
28537
|
smallBodyZone = null;
|
|
@@ -26373,10 +28616,15 @@ var PromotionRegistry = class {
|
|
|
26373
28616
|
if (!this.buildBodyInstance(body)) return;
|
|
26374
28617
|
this.finalizeBuilds();
|
|
26375
28618
|
}
|
|
28619
|
+
releaseFocusPromoted(focusedId) {
|
|
28620
|
+
if (this.focusPromoted.size === 0) return;
|
|
28621
|
+
const ids = [...this.focusPromoted].filter((id) => id !== focusedId);
|
|
28622
|
+
this.tearDownBodies(ids, this.focusPromoted);
|
|
28623
|
+
}
|
|
26376
28624
|
buildBodyInstance(body, halfPromoteIds, auto = false) {
|
|
26377
28625
|
const { bodyObjects, ctx, clock, scene, clickables, meshToBody, renderer } = this.deps;
|
|
26378
28626
|
if (bodyObjects.has(body.data.id)) return false;
|
|
26379
|
-
if (!body.orbitElements && !body.data.pageOnly && body.data.orbitalSource !== OrbitalSource.SPICE_PROBE) {
|
|
28627
|
+
if (!body.orbitElements && !body.data.pageOnly && !isExtrasolar(body) && body.data.orbitalSource !== OrbitalSource.SPICE_PROBE) {
|
|
26380
28628
|
body.orbitElements = body.data;
|
|
26381
28629
|
body.orbitCenterId = body.data.parentId;
|
|
26382
28630
|
}
|
|
@@ -26390,7 +28638,8 @@ var PromotionRegistry = class {
|
|
|
26390
28638
|
if (zone) ctx.bodies.dirtyAsteroidZones.add(zone);
|
|
26391
28639
|
}
|
|
26392
28640
|
const id = body.data.id;
|
|
26393
|
-
if (this.defaults.has(id)) {} else if (
|
|
28641
|
+
if (this.defaults.has(id)) {} else if (isExtrasolar(body)) this.focusPromoted.add(id);
|
|
28642
|
+
else if (auto) this.autoPromoted.add(id);
|
|
26394
28643
|
else {
|
|
26395
28644
|
this.userPromoted.add(id);
|
|
26396
28645
|
this.emitUserPromotedCount();
|
|
@@ -26583,6 +28832,7 @@ var PromotionRegistry = class {
|
|
|
26583
28832
|
var FocusController = class {
|
|
26584
28833
|
promotion;
|
|
26585
28834
|
readerFocusFilter = null;
|
|
28835
|
+
focusSets = 0;
|
|
26586
28836
|
focusedBody;
|
|
26587
28837
|
_tmpV3 = new Vector3();
|
|
26588
28838
|
pendingInitialView = null;
|
|
@@ -26610,6 +28860,9 @@ var FocusController = class {
|
|
|
26610
28860
|
get current() {
|
|
26611
28861
|
return this.focusedBody;
|
|
26612
28862
|
}
|
|
28863
|
+
get focusChanges() {
|
|
28864
|
+
return this.focusSets;
|
|
28865
|
+
}
|
|
26613
28866
|
place(body) {
|
|
26614
28867
|
return this.deps.ctx.place(body, this.deps.clock.jd);
|
|
26615
28868
|
}
|
|
@@ -26702,6 +28955,7 @@ var FocusController = class {
|
|
|
26702
28955
|
];
|
|
26703
28956
|
}
|
|
26704
28957
|
this.focusedBody = void 0;
|
|
28958
|
+
this.promotion.releaseFocusPromoted(void 0);
|
|
26705
28959
|
prepareFocusTarget(focus, [...position], camera, camWorld, camPos, sceneSettings().resolvedReducedMotion);
|
|
26706
28960
|
const spherical = cartesianToSpherical(camPos ?? camWorld, position, void 0);
|
|
26707
28961
|
callbacks.onCameraPosition?.(spherical.latitude, spherical.longitude, spherical.distance);
|
|
@@ -26720,6 +28974,8 @@ var FocusController = class {
|
|
|
26720
28974
|
}
|
|
26721
28975
|
setFocusTarget(body, camPos) {
|
|
26722
28976
|
const { ctx, bodyObjects, controls, callbacks, focus, camera, systemData, loadTexture } = this.deps;
|
|
28977
|
+
this.focusSets++;
|
|
28978
|
+
const drawsItself = !isSurfaceFeature(body) && !isExtrasolar(body);
|
|
26723
28979
|
if (!isSurfaceFeature(body)) this.promotion.ensureBodyObjects(body);
|
|
26724
28980
|
const prev = this.focusedBody;
|
|
26725
28981
|
const prevNomBodyId = nomenclatureBodyId(prev, bodyObjects);
|
|
@@ -26737,12 +28993,13 @@ var FocusController = class {
|
|
|
26737
28993
|
}
|
|
26738
28994
|
if (body.data.id !== prev?.data.id) this.pendingInitialView = null;
|
|
26739
28995
|
this.focusedBody = body;
|
|
28996
|
+
this.promotion.releaseFocusPromoted(body.data.id);
|
|
26740
28997
|
if (!isSurfaceFeature(body)) ctx.bodies.focusFeature = null;
|
|
26741
28998
|
controls.minDistance = minCameraDistance(body, modelMinRadiusKm(bodyObjects.get(body.data.id)));
|
|
26742
28999
|
const featureHost = isSurfaceFeature(body) ? ctx.getBody(body.featureAnchor.hostId) : void 0;
|
|
26743
29000
|
ctx.visibility.setFocused(featureHost ?? body);
|
|
26744
29001
|
callbacks.onFocusChange(body);
|
|
26745
|
-
if (
|
|
29002
|
+
if (drawsItself) loadTexture(body);
|
|
26746
29003
|
if (newNomBodyId && newNomBodyId !== body.data.id) {
|
|
26747
29004
|
const landingBody = ctx.getBody(newNomBodyId);
|
|
26748
29005
|
if (landingBody) loadTexture(landingBody);
|
|
@@ -26814,6 +29071,30 @@ var FocusController = class {
|
|
|
26814
29071
|
callbacks.onCameraPosition?.(settled.latitude, settled.longitude, settled.distance);
|
|
26815
29072
|
this.pendingInitialView = null;
|
|
26816
29073
|
}
|
|
29074
|
+
snapToBodyFrom(id, fromId, distance) {
|
|
29075
|
+
const { ctx, camera, controls, callbacks } = this.deps;
|
|
29076
|
+
const body = ctx.getBody(id);
|
|
29077
|
+
const from = ctx.getBody(fromId);
|
|
29078
|
+
const pos = body && this.place(body);
|
|
29079
|
+
const at = from && this.place(from);
|
|
29080
|
+
if (!body || !pos || !at) return;
|
|
29081
|
+
this.settleOnBodyInstant(body, pos);
|
|
29082
|
+
const d = f64dist(at, pos);
|
|
29083
|
+
const offset = [
|
|
29084
|
+
(at[0] - pos[0]) / d * distance,
|
|
29085
|
+
(at[1] - pos[1]) / d * distance,
|
|
29086
|
+
(at[2] - pos[2]) / d * distance
|
|
29087
|
+
];
|
|
29088
|
+
camera.position.set(offset[0], offset[1], offset[2]);
|
|
29089
|
+
controls.update();
|
|
29090
|
+
const settled = cartesianToSpherical(offset, [
|
|
29091
|
+
0,
|
|
29092
|
+
0,
|
|
29093
|
+
0
|
|
29094
|
+
]);
|
|
29095
|
+
callbacks.onCameraPosition?.(settled.latitude, settled.longitude, settled.distance);
|
|
29096
|
+
this.pendingInitialView = null;
|
|
29097
|
+
}
|
|
26817
29098
|
settleOnBodyInstant(body, pos) {
|
|
26818
29099
|
const { focus, pointClouds } = this.deps;
|
|
26819
29100
|
this.setFocusTarget(body);
|
|
@@ -26834,7 +29115,7 @@ var FocusController = class {
|
|
|
26834
29115
|
const body = this.focusedBody;
|
|
26835
29116
|
if (!body) return;
|
|
26836
29117
|
const { camera, controls, callbacks } = this.deps;
|
|
26837
|
-
const bodyFixed = !isModelBearing(body);
|
|
29118
|
+
const bodyFixed = !isModelBearing(body) && !isExtrasolar(body);
|
|
26838
29119
|
const quat = bodyFixed ? this.focusedBodyQuat(body) ?? [
|
|
26839
29120
|
0,
|
|
26840
29121
|
0,
|
|
@@ -27233,6 +29514,7 @@ var TIGHT_FAR_RELEASE = 2.3;
|
|
|
27233
29514
|
var SUN_PROXY_FAR_FRACTION = .9;
|
|
27234
29515
|
var _sunLiftDir = new Vector3();
|
|
27235
29516
|
var TRAIL_DRIFT_PX = .25;
|
|
29517
|
+
var SKY_GONE_SHARE = .9999;
|
|
27236
29518
|
var MODEL_SHADOW_DIST = 10;
|
|
27237
29519
|
var MODEL_SHADOW_EXTENT = 4;
|
|
27238
29520
|
var MODEL_SHADOW_NEAR = 4;
|
|
@@ -27263,6 +29545,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27263
29545
|
bodyObjects = /* @__PURE__ */ new Map();
|
|
27264
29546
|
circleTexture = makeCircleTexture();
|
|
27265
29547
|
pointClouds;
|
|
29548
|
+
starfield;
|
|
27266
29549
|
systemData;
|
|
27267
29550
|
positionDiagnostics = new PositionDiagnostics();
|
|
27268
29551
|
placer;
|
|
@@ -27283,6 +29566,8 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27283
29566
|
limitsArmed = false;
|
|
27284
29567
|
bodySelectEnabled = true;
|
|
27285
29568
|
featureSelectEnabled = true;
|
|
29569
|
+
starSelectEnabled = false;
|
|
29570
|
+
pickSerial = 0;
|
|
27286
29571
|
modelScene;
|
|
27287
29572
|
modelCamera;
|
|
27288
29573
|
modelLight;
|
|
@@ -27384,6 +29669,8 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27384
29669
|
fpsSamples = [];
|
|
27385
29670
|
fpsSampleHead = 0;
|
|
27386
29671
|
stashedSky = null;
|
|
29672
|
+
systemOn = true;
|
|
29673
|
+
systemFade = new SwitchFade();
|
|
27387
29674
|
namesShown = true;
|
|
27388
29675
|
halosShown = true;
|
|
27389
29676
|
textureLoader = new TextureLoader();
|
|
@@ -27472,11 +29759,12 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27472
29759
|
this.pointClouds = new PointCloudSystem(ctx, this.scene, this.bodyObjects, this.circleTexture, this.focus, SceneRenderer.MAP_LAYER, () => this.rebuildTrailBasis());
|
|
27473
29760
|
this.pointClouds.seedBasis(focusPos);
|
|
27474
29761
|
this.pointClouds.setPointBudget(this.tier.pointBudget);
|
|
29762
|
+
this.starfield = new StarfieldSystem(ctx, this.scene, starBudget(), this.invalidate, this.pointClouds.pickRegistry);
|
|
27475
29763
|
this.controls = new OrbitControls(this.camera, canvas);
|
|
27476
29764
|
this.controls.enableDamping = true;
|
|
27477
29765
|
this.orbitDampingFactor = orbitDamping(sceneSettings().resolvedReducedMotion);
|
|
27478
29766
|
this.controls.minDistance = focusBody ? minCameraDistance(focusBody) : kmToScene(.01);
|
|
27479
|
-
this.controls
|
|
29767
|
+
Object.defineProperty(this.controls, "maxDistance", { get: () => this.maxCameraDistance() });
|
|
27480
29768
|
this.controls.target.set(0, 0, 0);
|
|
27481
29769
|
this.controls.update();
|
|
27482
29770
|
this.controls.addEventListener("end", this.onControlsEnd);
|
|
@@ -27533,7 +29821,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27533
29821
|
this.systemData.syncToFocus();
|
|
27534
29822
|
this.focusController.readerFocusFilter = this.readerMayFocus;
|
|
27535
29823
|
this.gpuPick = new GpuPickPass(this.renderer, this.camera);
|
|
27536
|
-
this.pointerInteraction = new PointerInteraction(canvas, this.camera, ctx, clock, this.focus, this.clickables, this.meshToBody,
|
|
29824
|
+
this.pointerInteraction = new PointerInteraction(canvas, this.camera, ctx, clock, this.focus, this.clickables, this.meshToBody, this.pickBody, (ndcX, ndcY) => this.pickFocusedModel(ndcX, ndcY), this.gpuPick, () => [...this.pointClouds.asteroids().values(), ...this.pointClouds.spacecraft().values()], this.pointClouds.pickRegistry, () => this.starSelectEnabled && this.bodySelectEnabled ? this.starfield.pickDraws() : [], (pickId) => this.pickStar(pickId));
|
|
27537
29825
|
this.pointerInteraction.attach();
|
|
27538
29826
|
this.tick();
|
|
27539
29827
|
}
|
|
@@ -27817,7 +30105,9 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27817
30105
|
if (this.systemData.hasPendingUnloads() && performance.now() - this.focus.focusStartTime >= this.focus.focusDurationMs) this.systemData.drainPendingUnloads();
|
|
27818
30106
|
const { distance } = this.getCameraState();
|
|
27819
30107
|
this.updateTravelCraftSystem();
|
|
30108
|
+
this.updateSystemShare(renderedDtMs);
|
|
27820
30109
|
this.ctx.visibility.updateCamera(distance, this.sceneJd);
|
|
30110
|
+
this.ctx.visibility.stepZones(renderedDtMs);
|
|
27821
30111
|
this.updateTightFar(distance);
|
|
27822
30112
|
this.systemData.syncToFocus();
|
|
27823
30113
|
this.refreshTravelPath();
|
|
@@ -27829,7 +30119,9 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27829
30119
|
viewportPx: this.viewportH,
|
|
27830
30120
|
ctx: this.ctx
|
|
27831
30121
|
});
|
|
27832
|
-
this.
|
|
30122
|
+
this.ctx.visibility.starShare = this.starfield.share();
|
|
30123
|
+
this.cullFrameCounter = updateBodyVisibility(this.bodyObjects, this.camera, this.ctx, this.focus.focusTruePos, this.focusController.current?.data.id, this.hideCappedMoonLabels, this.hoveredBodyIds, this.cullFrameCounter, this.renderer, this._tmpV3, !controlsSettled, this.tightFar);
|
|
30124
|
+
this.pointClouds.updateVisibility(renderedDtMs);
|
|
27833
30125
|
this.pointClouds.applyPointBudget();
|
|
27834
30126
|
refreshDeferredTrails(this.bodyObjects, this.focus, this.lastUpdatedJd, this.trailView());
|
|
27835
30127
|
updateRingShaders(this.bodyObjects, this.focus.focusTruePos, sceneSettings().realisticLighting, sceneSettings().overexposeRings, this.camera.position, this.pxPerRad());
|
|
@@ -27839,7 +30131,6 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27839
30131
|
occluders.length = 0;
|
|
27840
30132
|
const atmoState = updateAtmosphereShaders(this.bodyObjects, this.camera.position, sceneSettings().showAtmospheres, sceneSettings().realisticLighting, this.sunIntensityScale, currentAtmosphereConfig(), this.sceneJd);
|
|
27841
30133
|
recordAtmospherePerf(renderedDtMs, atmoState.shellProminent);
|
|
27842
|
-
this.scene.backgroundIntensity = atmoState.skyboxIntensity;
|
|
27843
30134
|
this.applyLayerChrome();
|
|
27844
30135
|
const sunBo = this.bodyObjects.get(SUN_ID);
|
|
27845
30136
|
if (sunBo) applyStarTint(sunBo.corona, sunBo.starPoint, atmoState.sunTint);
|
|
@@ -27861,6 +30152,11 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27861
30152
|
this.pointClouds.drainOnePendingSceneAdd();
|
|
27862
30153
|
this.updateDepthFar();
|
|
27863
30154
|
this.updateSunProxy(atmoState.sunRefraction);
|
|
30155
|
+
this.camera.updateMatrixWorld();
|
|
30156
|
+
const focusedStar = this.focusController.current;
|
|
30157
|
+
this.starfield.setFocusStar(focusedStar && isExtrasolar(focusedStar) ? focusedStar.extrasolar ?? null : null);
|
|
30158
|
+
this.starfield.update(this.camera, this.focus.focusTruePos, this.renderer.getPixelRatio(), atmoState.skyboxIntensity, nowMs);
|
|
30159
|
+
this.updateSky(atmoState.skyboxIntensity);
|
|
27864
30160
|
if (atmoState.insideShell) this.atmoDepthPass.run(this.renderer, this.scene, this.camera, this.bodyObjects, SceneRenderer.ATMO_DEPTH_LAYER);
|
|
27865
30161
|
this.syncSceneSamples(atmoState.insideShell);
|
|
27866
30162
|
this.composer.readBuffer.resolveDepthBuffer = this.overlayActive;
|
|
@@ -27886,6 +30182,8 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27886
30182
|
if (nowMs - this.focus.focusStartTime < this.focus.focusDurationMs) return true;
|
|
27887
30183
|
if (this.jumpJd !== null || this.seekAwaitsData) return true;
|
|
27888
30184
|
if (this.focusLoads > 0 || this.systemData.isLoading()) return true;
|
|
30185
|
+
if (this.systemFade.fading || this.ctx.visibility.fading) return true;
|
|
30186
|
+
if (this.pointClouds.fading) return true;
|
|
27889
30187
|
for (const bo of this.bodyObjects.values()) if (bo.group.visible && bodyLoading(bo)) return true;
|
|
27890
30188
|
return false;
|
|
27891
30189
|
}
|
|
@@ -27896,6 +30194,26 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27896
30194
|
target.samples = samples;
|
|
27897
30195
|
target.dispose();
|
|
27898
30196
|
}
|
|
30197
|
+
maxCameraDistance() {
|
|
30198
|
+
switch (this.starfield.availability()) {
|
|
30199
|
+
case "yes": return CAMERA_MAX_DISTANCE;
|
|
30200
|
+
case "no": return SOLAR_MAX_DISTANCE;
|
|
30201
|
+
case "unknown": return Math.max(SOLAR_MAX_DISTANCE, this.camera.position.distanceTo(this.controls.target));
|
|
30202
|
+
}
|
|
30203
|
+
}
|
|
30204
|
+
updateSystemShare(dtMs) {
|
|
30205
|
+
const [fx, fy, fz] = this.focus.focusTruePos;
|
|
30206
|
+
const cam = this.camera.position;
|
|
30207
|
+
const fromBarycentre = Math.hypot(fx + cam.x, fy + cam.y, fz + cam.z);
|
|
30208
|
+
this.systemOn = systemShown(fromBarycentre, this.viewportH, this.camera.fov, this.systemOn);
|
|
30209
|
+
this.systemFade.step(this.systemOn, dtMs);
|
|
30210
|
+
const share = this.systemFade.share;
|
|
30211
|
+
const visibility = this.ctx.visibility;
|
|
30212
|
+
const wasHidden = visibility.systemShare === 0;
|
|
30213
|
+
visibility.systemShare = share;
|
|
30214
|
+
this.pointClouds.setFade(share);
|
|
30215
|
+
if (wasHidden && share > 0) this.ctx.refreshTick(jdToDate(this.clock.jd));
|
|
30216
|
+
}
|
|
27899
30217
|
updateTightFar(distance) {
|
|
27900
30218
|
if (isReversedDepth()) return;
|
|
27901
30219
|
const focused = this.focusController.current;
|
|
@@ -27915,10 +30233,12 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27915
30233
|
}
|
|
27916
30234
|
updateDepthFar() {
|
|
27917
30235
|
if (isReversedDepth()) return;
|
|
27918
|
-
|
|
30236
|
+
const [fx, fy, fz] = this.focus.focusTruePos;
|
|
30237
|
+
const cam = this.camera.position;
|
|
30238
|
+
const span = Math.max(cam.length(), Math.hypot(fx + cam.x, fy + cam.y, fz + cam.z));
|
|
30239
|
+
let far = Math.max(CAMERA_FAR_DEFAULT, span * FAR_MARGIN);
|
|
27919
30240
|
const sysId = this.ctx.visibility.activeSystemId;
|
|
27920
30241
|
if (sysId) {
|
|
27921
|
-
const [fx, fy, fz] = this.focus.focusTruePos;
|
|
27922
30242
|
let maxDistSq = this.camera.position.lengthSq();
|
|
27923
30243
|
const consider = (pos) => {
|
|
27924
30244
|
const dx = pos[0] - fx;
|
|
@@ -27939,7 +30259,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
27939
30259
|
const p = bo.body.position;
|
|
27940
30260
|
if (p && this.ctx.visibility.hasFullRendering(bo.body)) consider(p);
|
|
27941
30261
|
}
|
|
27942
|
-
far = Math.min(
|
|
30262
|
+
far = Math.min(far, Math.max(FAR_MIN, Math.sqrt(maxDistSq) * FAR_MARGIN));
|
|
27943
30263
|
}
|
|
27944
30264
|
if (Math.abs(far - this.camera.far) > this.camera.far * FAR_UPDATE_EPS) {
|
|
27945
30265
|
this.camera.far = far;
|
|
@@ -28197,7 +30517,30 @@ var SceneRenderer = class SceneRenderer {
|
|
|
28197
30517
|
setFeatureSelectEnabled(enabled) {
|
|
28198
30518
|
this.featureSelectEnabled = enabled;
|
|
28199
30519
|
}
|
|
30520
|
+
setStarSelectEnabled(enabled) {
|
|
30521
|
+
this.starSelectEnabled = enabled;
|
|
30522
|
+
}
|
|
28200
30523
|
readerMayFocus = (body) => this.bodySelectEnabled && (this.focusableBodies?.has(body.data.id) ?? true);
|
|
30524
|
+
pickBody = (body) => {
|
|
30525
|
+
this.pickSerial++;
|
|
30526
|
+
this.focusController.handleFocus(body);
|
|
30527
|
+
};
|
|
30528
|
+
pickStar(pickId) {
|
|
30529
|
+
const star = this.starfield.pickedStar(pickId);
|
|
30530
|
+
if (!star) return false;
|
|
30531
|
+
const serial = ++this.pickSerial;
|
|
30532
|
+
const focusChanges = this.focusController.focusChanges;
|
|
30533
|
+
const current = () => serial === this.pickSerial && focusChanges === this.focusController.focusChanges;
|
|
30534
|
+
(async () => {
|
|
30535
|
+
const objectId = extrasolarObjectId(await this.starfield.starId(star));
|
|
30536
|
+
if (!current()) return;
|
|
30537
|
+
await this.ctx.ensureBody(objectId, jdToDate(this.clock.jd));
|
|
30538
|
+
const body = this.ctx.getBody(objectId);
|
|
30539
|
+
if (!body) throw new Error(`no record for ${objectId}`);
|
|
30540
|
+
if (current()) this.pickBody(body);
|
|
30541
|
+
})().catch((err) => console.warn("[starfield] the picked star did not load:", err));
|
|
30542
|
+
return true;
|
|
30543
|
+
}
|
|
28201
30544
|
setCooperativeTouch(cooperative) {
|
|
28202
30545
|
this.controls.touches.ONE = cooperative ? NO_TOUCH_GESTURE : TOUCH.ROTATE;
|
|
28203
30546
|
this.canvas.style.touchAction = cooperative ? "pan-x pan-y" : "none";
|
|
@@ -28286,7 +30629,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
28286
30629
|
}
|
|
28287
30630
|
shouldRender(nowMs) {
|
|
28288
30631
|
if (this.holdingCamera) return true;
|
|
28289
|
-
if (nowMs - this.focus.focusStartTime < this.focus.focusDurationMs || this.focusKey() !== this.lastRenderedFocusKey || this.ctx.bodies.minorStreaming || this.pointClouds.hasPendingSceneAdds() || this.systemData.hasPendingUnloads()) return true;
|
|
30632
|
+
if (nowMs - this.focus.focusStartTime < this.focus.focusDurationMs || this.focusKey() !== this.lastRenderedFocusKey || this.ctx.bodies.minorStreaming || this.pointClouds.hasPendingSceneAdds() || this.systemData.hasPendingUnloads() || this.systemFade.fading || this.ctx.visibility.fading || this.pointClouds.fading || this.starfield.busy()) return true;
|
|
28290
30633
|
if (this.covered) return false;
|
|
28291
30634
|
if (this.frameIndex - this.lastRenderedFrame >= SceneRenderer.IDLE_HEARTBEAT_FRAMES) return true;
|
|
28292
30635
|
if (this.cameraMovedFrom(this.lastRenderedCamPos, this.lastRenderedCamQuat) || this.frameIndex < this.wakeUntilFrame || this.haloDebug.active) return true;
|
|
@@ -28608,6 +30951,10 @@ var SceneRenderer = class SceneRenderer {
|
|
|
28608
30951
|
this.disarmLimits();
|
|
28609
30952
|
this.focusController.snapToBody(id, latitude, longitude, zoom);
|
|
28610
30953
|
}
|
|
30954
|
+
snapToBodyFrom(id, fromId, distance) {
|
|
30955
|
+
this.disarmLimits();
|
|
30956
|
+
this.focusController.snapToBodyFrom(id, fromId, distance);
|
|
30957
|
+
}
|
|
28611
30958
|
setFocusTarget(body, camPos) {
|
|
28612
30959
|
this.disarmLimits();
|
|
28613
30960
|
this.applyJdUpdate();
|
|
@@ -28737,16 +31084,21 @@ var SceneRenderer = class SceneRenderer {
|
|
|
28737
31084
|
setSkyDebugMarkersVisible(visible) {
|
|
28738
31085
|
this.skyDebugMarkers.setVisible(visible);
|
|
28739
31086
|
}
|
|
28740
|
-
|
|
28741
|
-
|
|
31087
|
+
updateSky(skyboxIntensity) {
|
|
31088
|
+
const share = this.starfield.share();
|
|
31089
|
+
if (this.ctx.layers.isVisible("stars") && share < SKY_GONE_SHARE) {
|
|
28742
31090
|
if (this.stashedSky) {
|
|
28743
31091
|
this.scene.background = this.stashedSky;
|
|
28744
31092
|
this.stashedSky = null;
|
|
28745
31093
|
}
|
|
28746
31094
|
} else if (this.scene.background) {
|
|
31095
|
+
if (this.stashedSky !== this.scene.background) disposeTexture(this.stashedSky);
|
|
28747
31096
|
this.stashedSky = this.scene.background;
|
|
28748
31097
|
this.scene.background = null;
|
|
28749
31098
|
}
|
|
31099
|
+
this.scene.backgroundIntensity = skyboxIntensity * (1 - share);
|
|
31100
|
+
}
|
|
31101
|
+
applyLayerChrome() {
|
|
28750
31102
|
const names = this.ctx.layers.isVisible("labels");
|
|
28751
31103
|
if (names !== this.namesShown) {
|
|
28752
31104
|
this.namesShown = names;
|
|
@@ -28813,6 +31165,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
28813
31165
|
this.resize(this.canvas.clientWidth, this.canvas.clientHeight);
|
|
28814
31166
|
}
|
|
28815
31167
|
this.pointClouds.setPointBudget(this.tier.pointBudget);
|
|
31168
|
+
this.starfield.setBudget(starBudget());
|
|
28816
31169
|
}
|
|
28817
31170
|
resize(width, height) {
|
|
28818
31171
|
this.invalidate();
|
|
@@ -28850,9 +31203,11 @@ var SceneRenderer = class SceneRenderer {
|
|
|
28850
31203
|
disposeReliefTiles(bo);
|
|
28851
31204
|
}
|
|
28852
31205
|
this.pointClouds.dispose();
|
|
31206
|
+
this.starfield.dispose();
|
|
28853
31207
|
this.disposeScene(this.scene);
|
|
28854
31208
|
this.disposeScene(this.modelScene);
|
|
28855
31209
|
disposeTexture(this.scene.background);
|
|
31210
|
+
disposeTexture(this.stashedSky);
|
|
28856
31211
|
disposeTexture(this.scene.environment);
|
|
28857
31212
|
disposeTexture(this.modelScene.environment);
|
|
28858
31213
|
this.circleTexture.dispose();
|
|
@@ -31196,7 +33551,8 @@ var TYPES = {
|
|
|
31196
33551
|
[ObjectType.SPACECRAFT]: "spacecraft",
|
|
31197
33552
|
[ObjectType.DEBRIS]: "debris",
|
|
31198
33553
|
[ObjectType.UNDOCUMENTED]: "unknown",
|
|
31199
|
-
[ObjectType.SURFACE_FEATURE]: "surface-feature"
|
|
33554
|
+
[ObjectType.SURFACE_FEATURE]: "surface-feature",
|
|
33555
|
+
[ObjectType.EXTRASOLAR]: "star"
|
|
31200
33556
|
};
|
|
31201
33557
|
var ORBIT_CLASSES = {
|
|
31202
33558
|
[ObjectType.ASTEROID_INNER]: "inner",
|
|
@@ -31325,9 +33681,11 @@ var SpaceMap = class {
|
|
|
31325
33681
|
canvas = null;
|
|
31326
33682
|
labelLayer = null;
|
|
31327
33683
|
stopWatching = null;
|
|
33684
|
+
stopExtrasolarStale = null;
|
|
31328
33685
|
controls = null;
|
|
31329
33686
|
lostPanelTimer;
|
|
31330
33687
|
cooperative = null;
|
|
33688
|
+
starSelectEnabled = false;
|
|
31331
33689
|
limits = {};
|
|
31332
33690
|
initialFocusPending = true;
|
|
31333
33691
|
pendingFocusId = null;
|
|
@@ -31469,6 +33827,7 @@ var SpaceMap = class {
|
|
|
31469
33827
|
container.classList.add("sm-map");
|
|
31470
33828
|
mapsIn.set(container, (mapsIn.get(container) ?? 0) + 1);
|
|
31471
33829
|
this.controls = new ControlHost(this, container);
|
|
33830
|
+
this.stopExtrasolarStale = onExtrasolarStale(() => this.ctx.onDataStale?.());
|
|
31472
33831
|
const canvas = document.createElement("canvas");
|
|
31473
33832
|
canvas.className = "sm-map__canvas";
|
|
31474
33833
|
canvas.tabIndex = 0;
|
|
@@ -31532,6 +33891,8 @@ var SpaceMap = class {
|
|
|
31532
33891
|
this.controls = null;
|
|
31533
33892
|
this.stopWatching?.();
|
|
31534
33893
|
this.stopWatching = null;
|
|
33894
|
+
this.stopExtrasolarStale?.();
|
|
33895
|
+
this.stopExtrasolarStale = null;
|
|
31535
33896
|
clearTimeout(this.lostPanelTimer);
|
|
31536
33897
|
canvas.removeEventListener("keydown", this.onKeyDown);
|
|
31537
33898
|
canvas.removeEventListener("touchmove", this.onTouchMove);
|
|
@@ -31940,8 +34301,13 @@ var SpaceMap = class {
|
|
|
31940
34301
|
renderer.setZoomEnabled(this.scrollZoom.isEnabled());
|
|
31941
34302
|
renderer.setBodySelectEnabled(this.bodySelect.isEnabled());
|
|
31942
34303
|
renderer.setFeatureSelectEnabled(this.featureSelect.isEnabled());
|
|
34304
|
+
renderer.setStarSelectEnabled(this.starSelectEnabled);
|
|
31943
34305
|
renderer.setCooperativeTouch(cooperative);
|
|
31944
34306
|
}
|
|
34307
|
+
setStarSelectEnabled(enabled) {
|
|
34308
|
+
this.starSelectEnabled = enabled;
|
|
34309
|
+
this.renderer?.setStarSelectEnabled(enabled);
|
|
34310
|
+
}
|
|
31945
34311
|
onWheelCapture = (e) => {
|
|
31946
34312
|
if (!this.scrollZoom.isEnabled()) return;
|
|
31947
34313
|
if (this.cooperative && !this.cooperative.allowsWheel(e)) e.stopPropagation();
|
|
@@ -31982,6 +34348,9 @@ var SpaceMap = class {
|
|
|
31982
34348
|
snapToBody(id, latitude, longitude, zoom) {
|
|
31983
34349
|
this.renderer?.snapToBody(id, latitude, longitude, zoom);
|
|
31984
34350
|
}
|
|
34351
|
+
snapToBodyFrom(id, fromId, distance) {
|
|
34352
|
+
this.renderer?.snapToBodyFrom(id, fromId, distance);
|
|
34353
|
+
}
|
|
31985
34354
|
snapToBodyFacing(id, towardId, elevationDeg, distance) {
|
|
31986
34355
|
this.renderer?.snapToBodyFacing(id, towardId, elevationDeg, distance);
|
|
31987
34356
|
}
|
|
@@ -32329,7 +34698,7 @@ var MarkerDrawing = class {
|
|
|
32329
34698
|
const screen = this.visible ? viewport.project(this.at.lon, this.at.lat) : null;
|
|
32330
34699
|
this.element.style.display = screen ? "" : "none";
|
|
32331
34700
|
if (!screen) return;
|
|
32332
|
-
const shift = viewport.
|
|
34701
|
+
const shift = viewport.shiftInFrame(screen[0]);
|
|
32333
34702
|
this.element.style.transform = `translate(${screen[0] + shift}px, ${screen[1]}px) translate(${-this.align[0] * 100}%, ${-this.align[1] * 100}%)`;
|
|
32334
34703
|
}
|
|
32335
34704
|
setPosition(at) {
|
|
@@ -32433,14 +34802,15 @@ function stepOfLevel(level, tileSize) {
|
|
|
32433
34802
|
return 2 * Math.PI / (2 * tileSize * 2 ** level);
|
|
32434
34803
|
}
|
|
32435
34804
|
function finestLevelAt(pyramid, lon, lat) {
|
|
32436
|
-
const [across, fy] = chartFraction(0, lon, lat);
|
|
32437
|
-
const fx = across - Math.floor(across);
|
|
32438
34805
|
let finest = pyramid.max_level;
|
|
32439
34806
|
for (const patch of pyramid.patches ?? []) {
|
|
32440
34807
|
if (patch.max_level <= finest) continue;
|
|
32441
|
-
const
|
|
32442
|
-
const
|
|
32443
|
-
|
|
34808
|
+
const chart = patchChart(patch);
|
|
34809
|
+
const [across, fy] = chartFraction(chart, lon, lat);
|
|
34810
|
+
const fx = chart === 0 ? across - Math.floor(across) : across;
|
|
34811
|
+
const x = Math.floor(fx * chartColumns(chart, patch.max_level));
|
|
34812
|
+
const y = Math.floor(fy * chartRows(chart, patch.max_level));
|
|
34813
|
+
if (patchOfTile([patch], chart, patch.max_level, x, y)) finest = patch.max_level;
|
|
32444
34814
|
}
|
|
32445
34815
|
return finest;
|
|
32446
34816
|
}
|
|
@@ -32523,12 +34893,13 @@ function fitted(chart, level, tileSize, extent, margin) {
|
|
|
32523
34893
|
}
|
|
32524
34894
|
}
|
|
32525
34895
|
function reaches(patch, extent) {
|
|
32526
|
-
const
|
|
32527
|
-
const
|
|
34896
|
+
const chart = patchChart(patch);
|
|
34897
|
+
const columns = chartColumns(chart, patch.max_level);
|
|
34898
|
+
const rows = chartRows(chart, patch.max_level);
|
|
32528
34899
|
const south = (patch.y[1] + 1) / rows;
|
|
32529
34900
|
if (patch.y[0] / rows > extent.maxY || south < extent.minY) return false;
|
|
32530
34901
|
let west = patch.x[0] / columns;
|
|
32531
|
-
west -= Math.round(west - (extent.minX + extent.maxX) / 2);
|
|
34902
|
+
if (chart === 0) west -= Math.round(west - (extent.minX + extent.maxX) / 2);
|
|
32532
34903
|
const east = west + (patch.x[1] + 1 - patch.x[0]) / columns;
|
|
32533
34904
|
return west <= extent.maxX && east >= extent.minX;
|
|
32534
34905
|
}
|
|
@@ -32542,18 +34913,32 @@ function planWindows(pyramid, frame, firstLevel, moves = true) {
|
|
|
32542
34913
|
if (place) places.push(place);
|
|
32543
34914
|
}
|
|
32544
34915
|
const onMap = extentOn(0, frame, places, centre);
|
|
34916
|
+
const cap = centre[1] >= 0 ? 1 : 2;
|
|
34917
|
+
const onCap = extentOn(cap, frame, places, centre);
|
|
32545
34918
|
const wanted = levelForStep(frame.step, pyramid.tile_size);
|
|
32546
34919
|
const specs = [];
|
|
32547
34920
|
let finest = pyramid.max_level;
|
|
32548
|
-
|
|
34921
|
+
let finestOn = {
|
|
34922
|
+
chart: 0,
|
|
34923
|
+
extent: onMap
|
|
34924
|
+
};
|
|
34925
|
+
for (const patch of pyramid.patches ?? []) {
|
|
34926
|
+
const chart = patchChart(patch);
|
|
34927
|
+
const extent = chart === 0 ? onMap : chart === cap ? onCap : null;
|
|
34928
|
+
if (extent && patch.max_level > finest && reaches(patch, extent)) {
|
|
34929
|
+
finest = patch.max_level;
|
|
34930
|
+
finestOn = {
|
|
34931
|
+
chart,
|
|
34932
|
+
extent
|
|
34933
|
+
};
|
|
34934
|
+
}
|
|
34935
|
+
}
|
|
32549
34936
|
for (let level = Math.min(wanted, finest); level > pyramid.max_level; level--) {
|
|
32550
|
-
const spec = fitted(
|
|
34937
|
+
const spec = fitted(finestOn.chart, level, pyramid.tile_size, finestOn.extent, margin);
|
|
32551
34938
|
if (!spec) continue;
|
|
32552
34939
|
specs.push(spec);
|
|
32553
34940
|
break;
|
|
32554
34941
|
}
|
|
32555
|
-
const cap = centre[1] >= 0 ? 1 : 2;
|
|
32556
|
-
const onCap = extentOn(cap, frame, places, centre);
|
|
32557
34942
|
for (let level = Math.min(wanted, pyramid.max_level); level >= firstLevel; level--) {
|
|
32558
34943
|
const map = fitted(0, level, pyramid.tile_size, onMap, margin);
|
|
32559
34944
|
const polar = onCap && level >= 1 ? fitted(cap, level, pyramid.tile_size, onCap, margin) : void 0;
|
|
@@ -32575,7 +34960,7 @@ function windowTiles(spec, pyramid) {
|
|
|
32575
34960
|
for (let ty = Math.max(Math.floor(spec.y0 / size), 0); ty <= lastY; ty++) for (let tx = Math.floor(spec.x0 / size); tx <= lastX; tx++) {
|
|
32576
34961
|
if (spec.chart !== 0 && (tx < 0 || tx >= columns)) continue;
|
|
32577
34962
|
const x = (tx % columns + columns) % columns;
|
|
32578
|
-
const patch = spec.level > pyramid.max_level ? patchOfTile(pyramid.patches, spec.level, x, ty) : void 0;
|
|
34963
|
+
const patch = spec.level > pyramid.max_level ? patchOfTile(pyramid.patches, spec.chart, spec.level, x, ty) : void 0;
|
|
32579
34964
|
if (spec.level > pyramid.max_level && !patch) continue;
|
|
32580
34965
|
tiles.push({
|
|
32581
34966
|
cap: CHART_FOLDER[spec.chart],
|
|
@@ -33245,7 +35630,8 @@ var LayerTiles = class {
|
|
|
33245
35630
|
win.ctx = canvas.getContext("2d") ?? void 0;
|
|
33246
35631
|
} else win.data = new Uint8ClampedArray(spec.width * spec.height * 4);
|
|
33247
35632
|
for (const tile of windowTiles(spec, this.block)) {
|
|
33248
|
-
const
|
|
35633
|
+
const chart = CHART_FOLDER.indexOf(tile.cap);
|
|
35634
|
+
const version = tile.patch?.version ?? tileVersion(this.block, chart, tile.level, tile.x, tile.y);
|
|
33249
35635
|
const url = tileUrl({
|
|
33250
35636
|
id: this.block.id,
|
|
33251
35637
|
version
|
|
@@ -33317,7 +35703,10 @@ var Viewport = class {
|
|
|
33317
35703
|
}
|
|
33318
35704
|
unproject(px, py) {
|
|
33319
35705
|
const [x, y] = this.fromScreen(px, py);
|
|
33320
|
-
return this.projection.inverse(x, y);
|
|
35706
|
+
if (!this.repeatsHorizontally) return this.projection.inverse(x, y);
|
|
35707
|
+
const { minX, maxX } = this.projection.extent;
|
|
35708
|
+
const worldW = maxX - minX;
|
|
35709
|
+
return this.projection.inverse(((x - minX) % worldW + worldW) % worldW + minX, y);
|
|
33321
35710
|
}
|
|
33322
35711
|
get worldWidthPx() {
|
|
33323
35712
|
const { minX, maxX } = this.projection.extent;
|
|
@@ -33336,6 +35725,9 @@ var Viewport = class {
|
|
|
33336
35725
|
w
|
|
33337
35726
|
].filter((shift) => left + shift < this.width && left + shift + w > 0);
|
|
33338
35727
|
}
|
|
35728
|
+
shiftInFrame(x) {
|
|
35729
|
+
return this.repeatShifts.find((shift) => x + shift >= 0 && x + shift <= this.width) ?? 0;
|
|
35730
|
+
}
|
|
33339
35731
|
};
|
|
33340
35732
|
function repeats(projection, worldWidthPx, width) {
|
|
33341
35733
|
return projection.cyclic && projection.rectangular && worldWidthPx >= width - .5;
|
|
@@ -33772,7 +36164,9 @@ var FlatMap = class {
|
|
|
33772
36164
|
await this.adopt(bodyId);
|
|
33773
36165
|
}
|
|
33774
36166
|
project(lon, lat) {
|
|
33775
|
-
|
|
36167
|
+
const viewport = this.viewport();
|
|
36168
|
+
const screen = viewport.project(lon, lat);
|
|
36169
|
+
return screen ? [screen[0] + viewport.shiftInFrame(screen[0]), screen[1]] : null;
|
|
33776
36170
|
}
|
|
33777
36171
|
unproject(px, py) {
|
|
33778
36172
|
const found = this.viewport().unproject(px, py);
|
|
@@ -36678,9 +39072,11 @@ function attributionChips(ctx, labels = ORBIT_ARCHIVE_ORGANISATIONS) {
|
|
|
36678
39072
|
const bodyId = ctx.visibility.focusedBodyId;
|
|
36679
39073
|
const model = bodyId ? credits.model.get(bodyId) : void 0;
|
|
36680
39074
|
if (model) organisations.add(model.organisation);
|
|
39075
|
+
const stars = [...new Set(credits.stars.filter((c) => c.license).map((c) => c.organisation))];
|
|
36681
39076
|
return {
|
|
36682
39077
|
orbits,
|
|
36683
|
-
imagery: [...organisations].sort()
|
|
39078
|
+
imagery: [...organisations].sort(),
|
|
39079
|
+
stars
|
|
36684
39080
|
};
|
|
36685
39081
|
}
|
|
36686
39082
|
|
|
@@ -36716,12 +39112,14 @@ var AttributionControl = class {
|
|
|
36716
39112
|
const root = bar();
|
|
36717
39113
|
const orbits = group();
|
|
36718
39114
|
const imagery = group();
|
|
36719
|
-
|
|
39115
|
+
const stars = group();
|
|
39116
|
+
root.append(link(HOME_URL, "spacemap", "sm-attribution__home"), orbits, imagery, stars, link(CREDITS_URL, host().messages.credits_see_all()));
|
|
36720
39117
|
this.stop = effect_root(() => {
|
|
36721
39118
|
user_effect(() => {
|
|
36722
39119
|
const chips = attributionChips(map.ctx);
|
|
36723
39120
|
fill(orbits, host().messages.attribution_orbits(), chips.orbits);
|
|
36724
39121
|
fill(imagery, host().messages.attribution_imagery(), chips.imagery);
|
|
39122
|
+
fill(stars, host().messages.attribution_stars(), chips.stars);
|
|
36725
39123
|
});
|
|
36726
39124
|
});
|
|
36727
39125
|
return root;
|
|
@@ -37086,13 +39484,14 @@ async function fetchPanoramas(bodyId) {
|
|
|
37086
39484
|
//#endregion
|
|
37087
39485
|
//#region src/sdk/index.ts
|
|
37088
39486
|
async function createMap(options) {
|
|
37089
|
-
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, locale, messages, includeNonCommercial, controls, events, ...rest } = options;
|
|
39487
|
+
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, extrasolarUrl, locale, messages, includeNonCommercial, controls, events, ...rest } = options;
|
|
37090
39488
|
const element = resolveContainer(container);
|
|
37091
39489
|
applyHost({
|
|
37092
39490
|
dataUrl,
|
|
37093
39491
|
imagesUrl,
|
|
37094
39492
|
liveUrl,
|
|
37095
39493
|
tilesUrl,
|
|
39494
|
+
extrasolarUrl,
|
|
37096
39495
|
locale,
|
|
37097
39496
|
messages,
|
|
37098
39497
|
includeNonCommercial
|
|
@@ -37113,13 +39512,14 @@ async function createMap(options) {
|
|
|
37113
39512
|
return map;
|
|
37114
39513
|
}
|
|
37115
39514
|
async function createFlatMap(options) {
|
|
37116
|
-
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, locale, messages, includeNonCommercial, controls, events, ...rest } = options;
|
|
39515
|
+
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, extrasolarUrl, locale, messages, includeNonCommercial, controls, events, ...rest } = options;
|
|
37117
39516
|
const element = resolveContainer(container);
|
|
37118
39517
|
applyHost({
|
|
37119
39518
|
dataUrl,
|
|
37120
39519
|
imagesUrl,
|
|
37121
39520
|
liveUrl,
|
|
37122
39521
|
tilesUrl,
|
|
39522
|
+
extrasolarUrl,
|
|
37123
39523
|
locale,
|
|
37124
39524
|
messages,
|
|
37125
39525
|
includeNonCommercial
|
|
@@ -37134,13 +39534,14 @@ async function createFlatMap(options) {
|
|
|
37134
39534
|
return map;
|
|
37135
39535
|
}
|
|
37136
39536
|
async function createPanorama(options) {
|
|
37137
|
-
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, locale, messages, includeNonCommercial, controls, events, ...rest } = options;
|
|
39537
|
+
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, extrasolarUrl, locale, messages, includeNonCommercial, controls, events, ...rest } = options;
|
|
37138
39538
|
const element = resolveContainer(container);
|
|
37139
39539
|
applyHost({
|
|
37140
39540
|
dataUrl,
|
|
37141
39541
|
imagesUrl,
|
|
37142
39542
|
liveUrl,
|
|
37143
39543
|
tilesUrl,
|
|
39544
|
+
extrasolarUrl,
|
|
37144
39545
|
locale,
|
|
37145
39546
|
messages,
|
|
37146
39547
|
includeNonCommercial
|
|
@@ -37155,13 +39556,14 @@ async function createPanorama(options) {
|
|
|
37155
39556
|
return view;
|
|
37156
39557
|
}
|
|
37157
39558
|
async function createSystemMap(options) {
|
|
37158
|
-
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, locale, messages, includeNonCommercial, events, ...rest } = options;
|
|
39559
|
+
const { container, dataUrl, imagesUrl, liveUrl, tilesUrl, extrasolarUrl, locale, messages, includeNonCommercial, events, ...rest } = options;
|
|
37159
39560
|
const element = resolveContainer(container);
|
|
37160
39561
|
applyHost({
|
|
37161
39562
|
dataUrl,
|
|
37162
39563
|
imagesUrl,
|
|
37163
39564
|
liveUrl,
|
|
37164
39565
|
tilesUrl,
|
|
39566
|
+
extrasolarUrl,
|
|
37165
39567
|
locale,
|
|
37166
39568
|
messages,
|
|
37167
39569
|
includeNonCommercial
|
|
@@ -37189,6 +39591,7 @@ function applyHost(options) {
|
|
|
37189
39591
|
if (options.imagesUrl !== void 0) overrides.imagesUrl = options.imagesUrl;
|
|
37190
39592
|
if (options.liveUrl !== void 0) overrides.liveUrl = options.liveUrl;
|
|
37191
39593
|
if (options.tilesUrl !== void 0) overrides.tilesUrl = options.tilesUrl;
|
|
39594
|
+
if (options.extrasolarUrl !== void 0) overrides.extrasolarUrl = options.extrasolarUrl;
|
|
37192
39595
|
if (options.locale !== void 0) overrides.locale = () => options.locale;
|
|
37193
39596
|
if (options.messages !== void 0) overrides.messages = options.messages;
|
|
37194
39597
|
if (options.includeNonCommercial) overrides.textures = "non-commercial";
|