spacemap 0.1.22 → 0.1.24
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 +323 -248
- package/dist/spacemap.js +327 -252
- package/index.d.ts +14 -6
- package/index.js +792 -420
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -3061,9 +3061,6 @@ function isExtrasolar(body) {
|
|
|
3061
3061
|
function isExoplanet(body) {
|
|
3062
3062
|
return body.data.objectType === ObjectType.EXOPLANET;
|
|
3063
3063
|
}
|
|
3064
|
-
function isSurfaceFeature(body) {
|
|
3065
|
-
return body.data.objectType === ObjectType.SURFACE_FEATURE;
|
|
3066
|
-
}
|
|
3067
3064
|
var ObjectType = /* @__PURE__ */ function(ObjectType) {
|
|
3068
3065
|
ObjectType[ObjectType["BARYCENTER"] = 0] = "BARYCENTER";
|
|
3069
3066
|
ObjectType[ObjectType["LAGRANGE_POINT"] = 1] = "LAGRANGE_POINT";
|
|
@@ -6837,7 +6834,6 @@ var BodyIndex = class {
|
|
|
6837
6834
|
majorBodies = [];
|
|
6838
6835
|
asteroidBodiesByZone = /* @__PURE__ */ new Map();
|
|
6839
6836
|
spacecraftByParent = /* @__PURE__ */ new Map();
|
|
6840
|
-
focusFeature = null;
|
|
6841
6837
|
extrasolar = /* @__PURE__ */ new Map();
|
|
6842
6838
|
pinnedExtrasolar = /* @__PURE__ */ new Set();
|
|
6843
6839
|
tripCentreId = null;
|
|
@@ -6884,7 +6880,6 @@ var BodyIndex = class {
|
|
|
6884
6880
|
getBody(id, zone) {
|
|
6885
6881
|
const major = this.bodiesById.get(id);
|
|
6886
6882
|
if (major) return major;
|
|
6887
|
-
if (this.focusFeature?.data.id === id) return this.focusFeature;
|
|
6888
6883
|
const star = this.extrasolar.get(id) ?? this.exoplanets.get(this.exoplanetAliases.get(id) ?? id);
|
|
6889
6884
|
if (star) return star;
|
|
6890
6885
|
if (zone !== void 0) return this.spacecraftByParent.get(zone)?.get(id) ?? this.asteroidBodiesByZone.get(zone)?.get(id);
|
|
@@ -7778,6 +7773,7 @@ var VisibilityController = class {
|
|
|
7778
7773
|
systemCentres = /* @__PURE__ */ new Map();
|
|
7779
7774
|
focusedBodyIdPlain = SUN_ID;
|
|
7780
7775
|
focusedSystemIdPlain = null;
|
|
7776
|
+
subjectIdPlain;
|
|
7781
7777
|
travelSystemActive = false;
|
|
7782
7778
|
cameraDistThreeJS = 0;
|
|
7783
7779
|
lastRecomputeDist = -1;
|
|
@@ -7881,11 +7877,15 @@ var VisibilityController = class {
|
|
|
7881
7877
|
this.focusedSystemIdPlain = sysId;
|
|
7882
7878
|
this.lastRecomputeDist = -1;
|
|
7883
7879
|
}
|
|
7880
|
+
inFocus(id) {
|
|
7881
|
+
return id === this.focusedBodyIdPlain || id === this.subjectIdPlain;
|
|
7882
|
+
}
|
|
7884
7883
|
clearTravelSystem() {
|
|
7885
7884
|
this.travelSystemActive = false;
|
|
7886
7885
|
}
|
|
7887
|
-
setFocused(body) {
|
|
7886
|
+
setFocused(body, subject) {
|
|
7888
7887
|
this.travelSystemActive = false;
|
|
7888
|
+
this.subjectIdPlain = subject?.data.id;
|
|
7889
7889
|
if (body.data.id === this.focusedBodyIdPlain) return;
|
|
7890
7890
|
this.focusedBodyId = body.data.id;
|
|
7891
7891
|
this.focusedBodyIdPlain = body.data.id;
|
|
@@ -7910,7 +7910,7 @@ var VisibilityController = class {
|
|
|
7910
7910
|
else if (isAsteroidMoon && !this.matchesSmallBodyClass(moon.data.parentId)) vis = VISIBILITY.HIDE;
|
|
7911
7911
|
else {
|
|
7912
7912
|
const ratio = this.cameraDistThreeJS / 10 / moon.data.a;
|
|
7913
|
-
const isFocused = moon.data.id
|
|
7913
|
+
const isFocused = this.inFocus(moon.data.id);
|
|
7914
7914
|
vis = computeVisibilityFromRatio(ratio, this.scaledPlanetary, 5, isFocused);
|
|
7915
7915
|
if (!isAsteroidMoon && vis === VISIBILITY.FULL && !this.fullMoonIds.has(moon.data.id) && !isFocused) vis = VISIBILITY.CAPPED;
|
|
7916
7916
|
}
|
|
@@ -7958,7 +7958,7 @@ var VisibilityController = class {
|
|
|
7958
7958
|
if (!this.isInFocusedSystem(body.data.parentId)) return VISIBILITY.HIDE;
|
|
7959
7959
|
const refA = body.data.a;
|
|
7960
7960
|
if (!refA || refA <= 0) return VISIBILITY.FULL;
|
|
7961
|
-
const isFocused = body.data.id
|
|
7961
|
+
const isFocused = this.inFocus(body.data.id);
|
|
7962
7962
|
return computeVisibilityFromRatio(camDistThreeJS / 10 / refA, this.scaledPlanetary, 5, isFocused);
|
|
7963
7963
|
}
|
|
7964
7964
|
let refA = body.extrasolar?.pairAxis ?? body.data.a;
|
|
@@ -7970,7 +7970,7 @@ var VisibilityController = class {
|
|
|
7970
7970
|
if (refA === 0 && body.data.e < .9) console.warn(`No semi-major axis available for body ${body.data.id} (${body.data.name}), falling back to FULL visibility`);
|
|
7971
7971
|
return VISIBILITY.FULL;
|
|
7972
7972
|
}
|
|
7973
|
-
const isFocused = body.data.id
|
|
7973
|
+
const isFocused = this.inFocus(body.data.id);
|
|
7974
7974
|
const noLine = isExtrasolar(body) && !body.orbitElements;
|
|
7975
7975
|
const tier = computeVisibilityFromRatio(camDistThreeJS / 10 / refA, this.scaledSystem, 50, isFocused || noLine);
|
|
7976
7976
|
return tier === VISIBILITY.CLOSE ? VISIBILITY.FULL : tier;
|
|
@@ -7978,7 +7978,7 @@ var VisibilityController = class {
|
|
|
7978
7978
|
getProbeVisibility(body, camDistThreeJS) {
|
|
7979
7979
|
const ps = this.getProbeStore();
|
|
7980
7980
|
if ((ps ? ps.containingSystemAt(body.data.id, this.currentJd) : null) === EARTH_SYSTEM_NAIF && this.getEarthSatGroupFilter()) return VISIBILITY.HIDE;
|
|
7981
|
-
const isFocused = body.data.id
|
|
7981
|
+
const isFocused = this.inFocus(body.data.id);
|
|
7982
7982
|
if (!(ps ? !ps.hasHeliocentricFit(body.data.id, this.currentJd) : false)) {
|
|
7983
7983
|
const sun = this.bodies.bodiesById.get(SUN_ID);
|
|
7984
7984
|
const helioDist = sun?.position && body.position ? f64dist(body.position, sun.position) / 10 : 0;
|
|
@@ -8043,7 +8043,7 @@ var VisibilityController = class {
|
|
|
8043
8043
|
bodyUnclearedShare(body) {
|
|
8044
8044
|
if (this.clearing.share === 0) return 1;
|
|
8045
8045
|
const { id, objectType, parentId, orbitalSource } = body.data;
|
|
8046
|
-
if (
|
|
8046
|
+
if (this.inFocus(id) || id === this.focusedSystemIdPlain || this.pinned.has(id) || this.tripEnds.has(id)) return 1;
|
|
8047
8047
|
const layer = bodyLayer(objectType, parentId);
|
|
8048
8048
|
if (layer === "spacecraft" || orbitalSource === OrbitalSource.SPICE_PROBE) {
|
|
8049
8049
|
const page = this.getProbePage();
|
|
@@ -16768,7 +16768,7 @@ function seedAccepted() {
|
|
|
16768
16768
|
for (let i = 0; i < _reservedActive; i++) copyRect(poolSlot(_accepted, i, makeRect), _reserved[i]);
|
|
16769
16769
|
return _reservedActive;
|
|
16770
16770
|
}
|
|
16771
|
-
function cullOverlappingLabels(bodyObjects, screenWidth, screenHeight, camera,
|
|
16771
|
+
function cullOverlappingLabels(bodyObjects, screenWidth, screenHeight, camera, ctx, hoveredBodyIds, screenOccluders, focusTruePos = [
|
|
16772
16772
|
0,
|
|
16773
16773
|
0,
|
|
16774
16774
|
0
|
|
@@ -16783,7 +16783,7 @@ function cullOverlappingLabels(bodyObjects, screenWidth, screenHeight, camera, f
|
|
|
16783
16783
|
if (span && span.offsetWidth > 0) bo.labelTextWidth = span.offsetWidth;
|
|
16784
16784
|
}
|
|
16785
16785
|
if (!labelScreenRect(bo, camera, focusTruePos, screenWidth, screenHeight, _projRect)) continue;
|
|
16786
|
-
const isFocused = body.data.id
|
|
16786
|
+
const isFocused = ctx.visibility.inFocus(body.data.id);
|
|
16787
16787
|
const isHovered = hoveredBodyIds.has(body.data.id);
|
|
16788
16788
|
const c = poolSlot(_candidates, _candidatesActive++, makeCandidate);
|
|
16789
16789
|
copyRect(c.rect, _projRect);
|
|
@@ -18063,12 +18063,6 @@ function onLinkTap(el, handler) {
|
|
|
18063
18063
|
}
|
|
18064
18064
|
|
|
18065
18065
|
// src/lib/scene/objects/surface/nomenclature.ts
|
|
18066
|
-
function nomenclatureBodyId(focused, bodyObjects) {
|
|
18067
|
-
if (!focused) return void 0;
|
|
18068
|
-
if (isSurfaceFeature(focused)) return focused.featureAnchor.hostId;
|
|
18069
|
-
if (bodyObjects.get(focused.data.id)?.isLanded) return focused.data.parentId;
|
|
18070
|
-
return focused.data.id;
|
|
18071
|
-
}
|
|
18072
18066
|
var DEG2RAD$4 = Math.PI / 180;
|
|
18073
18067
|
var MIN_BODY_SCREEN_RADIUS_PX = 128;
|
|
18074
18068
|
var LABEL_DISC_FRACTION = .9;
|
|
@@ -22390,6 +22384,87 @@ var SimClock = class {
|
|
|
22390
22384
|
}
|
|
22391
22385
|
};
|
|
22392
22386
|
|
|
22387
|
+
// src/lib/scene/camera/two-finger.ts
|
|
22388
|
+
var TWO_FINGER_SLOP = 10;
|
|
22389
|
+
var TWO_FINGER_ALONE = 30;
|
|
22390
|
+
var TILT_MAX_SPREAD_SLOPE = Math.tan(MathUtils.degToRad(40));
|
|
22391
|
+
var TILT_MAX_SIDEWAYS = .5;
|
|
22392
|
+
var TILT_MIN_TOGETHER = .3;
|
|
22393
|
+
var TWIST_ENGAGE = MathUtils.degToRad(12);
|
|
22394
|
+
var TwoFingerGesture = class {
|
|
22395
|
+
mode = "map";
|
|
22396
|
+
a0 = {
|
|
22397
|
+
x: 0,
|
|
22398
|
+
y: 0
|
|
22399
|
+
};
|
|
22400
|
+
b0 = {
|
|
22401
|
+
x: 0,
|
|
22402
|
+
y: 0
|
|
22403
|
+
};
|
|
22404
|
+
lastMidY = 0;
|
|
22405
|
+
lastAngle = 0;
|
|
22406
|
+
twisted = 0;
|
|
22407
|
+
twisting = false;
|
|
22408
|
+
begin(a, b, canTilt) {
|
|
22409
|
+
this.mode = canTilt ? "undecided" : "map";
|
|
22410
|
+
this.a0.x = a.x;
|
|
22411
|
+
this.a0.y = a.y;
|
|
22412
|
+
this.b0.x = b.x;
|
|
22413
|
+
this.b0.y = b.y;
|
|
22414
|
+
this.lastMidY = (a.y + b.y) / 2;
|
|
22415
|
+
this.lastAngle = Math.atan2(b.y - a.y, b.x - a.x);
|
|
22416
|
+
this.twisted = 0;
|
|
22417
|
+
this.twisting = false;
|
|
22418
|
+
}
|
|
22419
|
+
move(a, b) {
|
|
22420
|
+
const angle = Math.atan2(b.y - a.y, b.x - a.x);
|
|
22421
|
+
const turn = MathUtils.euclideanModulo(angle - this.lastAngle + Math.PI, 2 * Math.PI) - Math.PI;
|
|
22422
|
+
this.lastAngle = angle;
|
|
22423
|
+
const midY = (a.y + b.y) / 2;
|
|
22424
|
+
let down = midY - this.lastMidY;
|
|
22425
|
+
this.lastMidY = midY;
|
|
22426
|
+
this.twisted += turn;
|
|
22427
|
+
if (this.mode === "undecided") {
|
|
22428
|
+
this.mode = this.decide(a, b);
|
|
22429
|
+
if (this.mode === "tilt") down = midY - (this.a0.y + this.b0.y) / 2;
|
|
22430
|
+
}
|
|
22431
|
+
switch (this.mode) {
|
|
22432
|
+
case "undecided": return {
|
|
22433
|
+
mode: "undecided",
|
|
22434
|
+
down: 0,
|
|
22435
|
+
twist: 0
|
|
22436
|
+
};
|
|
22437
|
+
case "tilt": return {
|
|
22438
|
+
mode: "tilt",
|
|
22439
|
+
down,
|
|
22440
|
+
twist: 0
|
|
22441
|
+
};
|
|
22442
|
+
case "map": {
|
|
22443
|
+
const engaged = this.twisting;
|
|
22444
|
+
this.twisting ||= Math.abs(this.twisted) > TWIST_ENGAGE;
|
|
22445
|
+
return {
|
|
22446
|
+
mode: "map",
|
|
22447
|
+
down: 0,
|
|
22448
|
+
twist: engaged ? turn : 0
|
|
22449
|
+
};
|
|
22450
|
+
}
|
|
22451
|
+
}
|
|
22452
|
+
}
|
|
22453
|
+
decide(a, b) {
|
|
22454
|
+
const ax = a.x - this.a0.x;
|
|
22455
|
+
const ay = a.y - this.a0.y;
|
|
22456
|
+
const bx = b.x - this.b0.x;
|
|
22457
|
+
const by = b.y - this.b0.y;
|
|
22458
|
+
const aTravel = Math.hypot(ax, ay);
|
|
22459
|
+
const bTravel = Math.hypot(bx, by);
|
|
22460
|
+
if (Math.max(aTravel, bTravel) < (aTravel > 0 && bTravel > 0 ? 10 : TWO_FINGER_ALONE)) return "undecided";
|
|
22461
|
+
const sideBySide = Math.abs(this.b0.y - this.a0.y) <= Math.abs(this.b0.x - this.a0.x) * TILT_MAX_SPREAD_SLOPE;
|
|
22462
|
+
const vertical = Math.abs(ax) <= Math.abs(ay) * TILT_MAX_SIDEWAYS && Math.abs(bx) <= Math.abs(by) * TILT_MAX_SIDEWAYS;
|
|
22463
|
+
const together = Math.sign(ay) === Math.sign(by) && Math.min(aTravel, bTravel) >= Math.max(aTravel, bTravel) * TILT_MIN_TOGETHER;
|
|
22464
|
+
return sideBySide && vertical && together ? "tilt" : "map";
|
|
22465
|
+
}
|
|
22466
|
+
};
|
|
22467
|
+
|
|
22393
22468
|
// src/lib/scene/camera/look-controls.ts
|
|
22394
22469
|
var MAX_TILT = MathUtils.degToRad(80);
|
|
22395
22470
|
var LOOK_NONE_HEIGHT = 1;
|
|
@@ -22411,14 +22486,15 @@ var _turnBack = new Quaternion();
|
|
|
22411
22486
|
var _was = new Quaternion();
|
|
22412
22487
|
var _pivotGround = new Vector3();
|
|
22413
22488
|
var _look = new Matrix4();
|
|
22489
|
+
var GLIDE_DONE = 1e-5;
|
|
22414
22490
|
var ANCHOR_PASSES = 3;
|
|
22415
22491
|
var SIN_MIN_ANCHOR_ELEVATION = Math.sin(MathUtils.degToRad(20));
|
|
22416
22492
|
var GROUND_PASSES = 3;
|
|
22493
|
+
var PIVOT_REFINE = 1e-7;
|
|
22417
22494
|
var orbitHandlers = OrbitControls.prototype;
|
|
22418
22495
|
var LookOrbitControls = class extends OrbitControls {
|
|
22419
22496
|
canvas;
|
|
22420
22497
|
surfaceRadius;
|
|
22421
|
-
standingHeight;
|
|
22422
22498
|
onTurnSettled;
|
|
22423
22499
|
heading = 0;
|
|
22424
22500
|
tilt = 0;
|
|
@@ -22426,6 +22502,7 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22426
22502
|
orbitPos = new Vector3();
|
|
22427
22503
|
orbitQuat = new Quaternion();
|
|
22428
22504
|
pivotRadius = 0;
|
|
22505
|
+
placedByName = false;
|
|
22429
22506
|
lastUp = new Vector3();
|
|
22430
22507
|
holdsNorth = false;
|
|
22431
22508
|
northTurning = false;
|
|
@@ -22436,16 +22513,22 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22436
22513
|
dragPointer = null;
|
|
22437
22514
|
dragX = 0;
|
|
22438
22515
|
dragY = 0;
|
|
22439
|
-
|
|
22516
|
+
twoFinger = new TwoFingerGesture();
|
|
22517
|
+
glideHeading = 0;
|
|
22518
|
+
glideTilt = 0;
|
|
22519
|
+
constructor(camera, canvas, surfaceRadius, onTurnSettled = () => {}) {
|
|
22440
22520
|
super(camera, canvas);
|
|
22441
22521
|
this.canvas = canvas;
|
|
22442
22522
|
this.surfaceRadius = surfaceRadius;
|
|
22443
|
-
this.standingHeight = standingHeight;
|
|
22444
22523
|
this.onTurnSettled = onTurnSettled;
|
|
22445
22524
|
this.mouseButtons.MIDDLE = null;
|
|
22446
|
-
this.addEventListener("start", () =>
|
|
22525
|
+
this.addEventListener("start", () => {
|
|
22526
|
+
this.pendingLook = null;
|
|
22527
|
+
this.placedByName = false;
|
|
22528
|
+
});
|
|
22447
22529
|
canvas.addEventListener("pointerdown", this.onLookDown);
|
|
22448
22530
|
canvas.addEventListener("mousedown", this.blockMiddle);
|
|
22531
|
+
canvas.addEventListener("pointerdown", this.onCatch);
|
|
22449
22532
|
}
|
|
22450
22533
|
get orbitPosition() {
|
|
22451
22534
|
return this.looking ? this.orbitPos : this.object.position;
|
|
@@ -22464,6 +22547,8 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22464
22547
|
const cam = this.object;
|
|
22465
22548
|
this.looking = false;
|
|
22466
22549
|
this.pendingLook = null;
|
|
22550
|
+
this.placedByName = false;
|
|
22551
|
+
this.stopGlide();
|
|
22467
22552
|
if (tilt === 0 && heading === 0) return;
|
|
22468
22553
|
if (!this.groundKnown()) {
|
|
22469
22554
|
this.pendingLook = {
|
|
@@ -22484,6 +22569,7 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22484
22569
|
this.heading = heading;
|
|
22485
22570
|
this.holdAngles(share);
|
|
22486
22571
|
this.looking = true;
|
|
22572
|
+
this.placedByName = true;
|
|
22487
22573
|
this.place();
|
|
22488
22574
|
}
|
|
22489
22575
|
toOrbitAxes(x, y) {
|
|
@@ -22501,6 +22587,12 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22501
22587
|
endLook() {
|
|
22502
22588
|
this.looking = false;
|
|
22503
22589
|
this.pendingLook = null;
|
|
22590
|
+
this.placedByName = false;
|
|
22591
|
+
this.stopGlide();
|
|
22592
|
+
}
|
|
22593
|
+
stopGlide() {
|
|
22594
|
+
this.glideHeading = 0;
|
|
22595
|
+
this.glideTilt = 0;
|
|
22504
22596
|
}
|
|
22505
22597
|
groundKnown() {
|
|
22506
22598
|
_n.subVectors(this.orbitPosition, this.target).normalize();
|
|
@@ -22530,22 +22622,28 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22530
22622
|
this.placedQuat.copy(cam.quaternion);
|
|
22531
22623
|
return;
|
|
22532
22624
|
}
|
|
22533
|
-
if (this.pivotRadius === 0) {
|
|
22534
|
-
const was = _from$1.subVectors(this.placedPos, this.target);
|
|
22535
|
-
const now = _hit.subVectors(cam.position, this.target);
|
|
22536
|
-
const stretch = now.length() / was.length();
|
|
22537
|
-
_turnBack.setFromUnitVectors(was.normalize(), now.normalize());
|
|
22538
|
-
this.orbitPos.sub(this.target).applyQuaternion(_turnBack).multiplyScalar(stretch).add(this.target);
|
|
22539
|
-
this.orbitQuat.premultiply(_turnBack);
|
|
22540
|
-
this.place();
|
|
22541
|
-
return;
|
|
22542
|
-
}
|
|
22543
22625
|
const holds = this.holdsNorth;
|
|
22544
22626
|
_n.subVectors(this.orbitPos, this.target).normalize();
|
|
22545
22627
|
this.lookToward(_pivotGround.copy(_n).multiplyScalar(this.pivotRadius));
|
|
22546
22628
|
this.holdsNorth = holds;
|
|
22547
22629
|
}
|
|
22548
22630
|
update(deltaTime = null) {
|
|
22631
|
+
const changed = this.step(deltaTime);
|
|
22632
|
+
return this.glide() || changed;
|
|
22633
|
+
}
|
|
22634
|
+
glide() {
|
|
22635
|
+
if (!this.glideHeading && !this.glideTilt) return false;
|
|
22636
|
+
const f = this.dampingFactor;
|
|
22637
|
+
this.turnNow(this.glideHeading * f, this.glideTilt * f);
|
|
22638
|
+
this.glideHeading *= 1 - f;
|
|
22639
|
+
this.glideTilt *= 1 - f;
|
|
22640
|
+
if (Math.abs(this.glideHeading) < GLIDE_DONE && Math.abs(this.glideTilt) < GLIDE_DONE) {
|
|
22641
|
+
this.stopGlide();
|
|
22642
|
+
this.onTurnSettled();
|
|
22643
|
+
}
|
|
22644
|
+
return true;
|
|
22645
|
+
}
|
|
22646
|
+
step(deltaTime) {
|
|
22549
22647
|
if (!this.looking) {
|
|
22550
22648
|
const changed = super.update(deltaTime);
|
|
22551
22649
|
if (this.pendingLook && this.groundKnown()) this.setLook(this.pendingLook);
|
|
@@ -22554,14 +22652,19 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22554
22652
|
const cam = this.object;
|
|
22555
22653
|
if (!cam.position.equals(this.placedPos) || !cam.quaternion.equals(this.placedQuat)) {
|
|
22556
22654
|
this.looking = false;
|
|
22655
|
+
this.stopGlide();
|
|
22557
22656
|
return super.update(deltaTime);
|
|
22558
22657
|
}
|
|
22658
|
+
if (!this.followGround()) return super.update(deltaTime);
|
|
22559
22659
|
cam.position.copy(this.orbitPos);
|
|
22560
22660
|
cam.quaternion.copy(this.orbitQuat);
|
|
22561
22661
|
_was.copy(this.orbitQuat);
|
|
22562
22662
|
const changed = super.update(deltaTime);
|
|
22563
22663
|
const moved = cam.position.distanceToSquared(this.orbitPos) > this.orbitPos.lengthSq() * 1e-20;
|
|
22564
|
-
if (moved)
|
|
22664
|
+
if (moved) {
|
|
22665
|
+
this.orbitMoved = true;
|
|
22666
|
+
this.placedByName = false;
|
|
22667
|
+
}
|
|
22565
22668
|
this.orbitPos.copy(cam.position);
|
|
22566
22669
|
this.orbitQuat.copy(cam.quaternion);
|
|
22567
22670
|
if (moved) this.samplePivot();
|
|
@@ -22586,6 +22689,7 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22586
22689
|
super.dispose();
|
|
22587
22690
|
this.canvas.removeEventListener("pointerdown", this.onLookDown);
|
|
22588
22691
|
this.canvas.removeEventListener("mousedown", this.blockMiddle);
|
|
22692
|
+
this.canvas.removeEventListener("pointerdown", this.onCatch);
|
|
22589
22693
|
this.endLookDrag();
|
|
22590
22694
|
}
|
|
22591
22695
|
_handleMouseDownRotate(event) {
|
|
@@ -22600,6 +22704,28 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22600
22704
|
_handleTouchMoveRotate(event) {
|
|
22601
22705
|
orbitHandlers._handleTouchMoveRotate.call(this, this.rotatedTouch(event));
|
|
22602
22706
|
}
|
|
22707
|
+
_handleTouchStartDollyPan(event) {
|
|
22708
|
+
orbitHandlers._handleTouchStartDollyPan.call(this, event);
|
|
22709
|
+
const [a, b] = this.fingers();
|
|
22710
|
+
this.twoFinger.begin(a, b, this.enableRotate && this.lookShare() > 0);
|
|
22711
|
+
}
|
|
22712
|
+
_handleTouchMoveDollyPan(event) {
|
|
22713
|
+
const [a, b] = this.fingers();
|
|
22714
|
+
const step = this.twoFinger.move(a, b);
|
|
22715
|
+
if (step.mode === "undecided") return;
|
|
22716
|
+
const rate = TURN_PER_HEIGHT / (this.canvas.clientHeight || 1);
|
|
22717
|
+
if (step.mode === "tilt") {
|
|
22718
|
+
if (this.enableRotate) this.turn(0, -step.down * rate);
|
|
22719
|
+
return;
|
|
22720
|
+
}
|
|
22721
|
+
orbitHandlers._handleTouchMoveDollyPan.call(this, event);
|
|
22722
|
+
if (step.twist !== 0 && this.enableRotate) this.turn(step.twist, 0);
|
|
22723
|
+
}
|
|
22724
|
+
fingers() {
|
|
22725
|
+
const touch = this;
|
|
22726
|
+
const [a, b] = touch._pointers;
|
|
22727
|
+
return [touch._pointerPositions[a], touch._pointerPositions[b]];
|
|
22728
|
+
}
|
|
22603
22729
|
_handleMouseWheel(event) {
|
|
22604
22730
|
const anchored = this.enableRotate && this.groundAt(event.clientX, event.clientY, _anchor) && -_ray.dot(_hit.copy(_anchor).normalize()) > SIN_MIN_ANCHOR_ELEVATION;
|
|
22605
22731
|
orbitHandlers._handleMouseWheel.call(this, event);
|
|
@@ -22664,6 +22790,7 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22664
22790
|
const level = offset.addScaledVector(n, -offset.dot(n));
|
|
22665
22791
|
this.heading = Math.atan2(_ray.crossVectors(down, level).dot(n), down.dot(level));
|
|
22666
22792
|
this.holdsNorth = false;
|
|
22793
|
+
this.placedByName = false;
|
|
22667
22794
|
this.looking = true;
|
|
22668
22795
|
if (!this.holdAngles(this.lookShare())) {
|
|
22669
22796
|
this.looking = false;
|
|
@@ -22712,7 +22839,15 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22712
22839
|
pageY: 2 * y - other.y
|
|
22713
22840
|
};
|
|
22714
22841
|
}
|
|
22715
|
-
turn(
|
|
22842
|
+
turn(heading, tilt) {
|
|
22843
|
+
if (!this.enableDamping) {
|
|
22844
|
+
this.turnNow(heading, tilt);
|
|
22845
|
+
return;
|
|
22846
|
+
}
|
|
22847
|
+
this.glideHeading += heading;
|
|
22848
|
+
this.glideTilt += tilt;
|
|
22849
|
+
}
|
|
22850
|
+
turnNow(heading, tilt) {
|
|
22716
22851
|
const cam = this.object;
|
|
22717
22852
|
const share = this.lookShare();
|
|
22718
22853
|
if (share === 0) return;
|
|
@@ -22726,9 +22861,8 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22726
22861
|
this.lastUp.copy(cam.up);
|
|
22727
22862
|
}
|
|
22728
22863
|
this.holdsNorth = false;
|
|
22729
|
-
|
|
22730
|
-
this.
|
|
22731
|
-
this.tilt = Math.max(0, this.tilt - dy * rate);
|
|
22864
|
+
this.heading += heading;
|
|
22865
|
+
this.tilt = Math.max(0, this.tilt + tilt);
|
|
22732
22866
|
this.holdAngles(share);
|
|
22733
22867
|
this.place();
|
|
22734
22868
|
}
|
|
@@ -22736,10 +22870,7 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22736
22870
|
_n.subVectors(this.orbitPosition, this.target);
|
|
22737
22871
|
const range = _n.length();
|
|
22738
22872
|
const ground = range > 0 ? this.surfaceRadius(_n.divideScalar(range)) : null;
|
|
22739
|
-
|
|
22740
|
-
if (ground > 0) return this.shareAt((range - ground) / ground);
|
|
22741
|
-
const height = this.standingHeight();
|
|
22742
|
-
return height === null ? 0 : this.shareAt(height);
|
|
22873
|
+
return ground ? this.shareAt((range - ground) / ground) : 0;
|
|
22743
22874
|
}
|
|
22744
22875
|
shareAt(height) {
|
|
22745
22876
|
const t = MathUtils.clamp((1 - height) / .5, 0, 1);
|
|
@@ -22751,6 +22882,22 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22751
22882
|
this.heading = MathUtils.clamp(this.heading, -Math.PI * share, Math.PI * share);
|
|
22752
22883
|
return share > 0;
|
|
22753
22884
|
}
|
|
22885
|
+
followGround() {
|
|
22886
|
+
_n.subVectors(this.orbitPos, this.target);
|
|
22887
|
+
const range = _n.length();
|
|
22888
|
+
const ground = range > 0 ? this.surfaceRadius(_n.divideScalar(range)) : null;
|
|
22889
|
+
if (ground === null) return true;
|
|
22890
|
+
const pivot = Math.min(ground, range);
|
|
22891
|
+
if (Math.abs(pivot - this.pivotRadius) <= ground * PIVOT_REFINE) return true;
|
|
22892
|
+
if (this.placedByName) {
|
|
22893
|
+
this.pivotRadius = pivot;
|
|
22894
|
+
return true;
|
|
22895
|
+
}
|
|
22896
|
+
const holds = this.holdsNorth;
|
|
22897
|
+
this.lookToward(_pivotGround.copy(_n).multiplyScalar(ground));
|
|
22898
|
+
this.holdsNorth = holds;
|
|
22899
|
+
return this.looking;
|
|
22900
|
+
}
|
|
22754
22901
|
samplePivot() {
|
|
22755
22902
|
_n.subVectors(this.orbitPos, this.target);
|
|
22756
22903
|
const range = _n.length();
|
|
@@ -22772,6 +22919,11 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22772
22919
|
this.placedPos.copy(cam.position);
|
|
22773
22920
|
this.placedQuat.copy(cam.quaternion);
|
|
22774
22921
|
}
|
|
22922
|
+
onCatch = () => {
|
|
22923
|
+
if (!this.glideHeading && !this.glideTilt) return;
|
|
22924
|
+
this.stopGlide();
|
|
22925
|
+
this.onTurnSettled();
|
|
22926
|
+
};
|
|
22775
22927
|
blockMiddle = (event) => {
|
|
22776
22928
|
if (event.button === 1) event.preventDefault();
|
|
22777
22929
|
};
|
|
@@ -22796,7 +22948,8 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22796
22948
|
const dy = event.clientY - this.dragY;
|
|
22797
22949
|
this.dragX = event.clientX;
|
|
22798
22950
|
this.dragY = event.clientY;
|
|
22799
|
-
|
|
22951
|
+
const rate = TURN_PER_HEIGHT / (this.canvas.clientHeight || 1);
|
|
22952
|
+
if (dx !== 0 || dy !== 0) this.turn(-dx * rate, -dy * rate);
|
|
22800
22953
|
};
|
|
22801
22954
|
onLookUp = (event) => {
|
|
22802
22955
|
if (event.pointerId !== this.dragPointer) return;
|
|
@@ -22815,35 +22968,42 @@ var LookOrbitControls = class extends OrbitControls {
|
|
|
22815
22968
|
// src/lib/scene/framing.ts
|
|
22816
22969
|
var DEFAULT_FOCUS_ID = EARTH_ID;
|
|
22817
22970
|
|
|
22818
|
-
// src/lib/scene/
|
|
22819
|
-
|
|
22820
|
-
|
|
22821
|
-
|
|
22822
|
-
function
|
|
22823
|
-
|
|
22824
|
-
|
|
22825
|
-
|
|
22826
|
-
|
|
22827
|
-
|
|
22828
|
-
|
|
22829
|
-
|
|
22830
|
-
|
|
22831
|
-
|
|
22832
|
-
|
|
22833
|
-
|
|
22834
|
-
|
|
22835
|
-
|
|
22836
|
-
|
|
22837
|
-
|
|
22838
|
-
|
|
22839
|
-
|
|
22840
|
-
|
|
22841
|
-
|
|
22842
|
-
|
|
22843
|
-
|
|
22844
|
-
|
|
22845
|
-
|
|
22846
|
-
|
|
22971
|
+
// src/lib/scene/position/feature-seat.ts
|
|
22972
|
+
var DEG2RAD$3 = Math.PI / 180;
|
|
22973
|
+
var _fixed = new Vector3();
|
|
22974
|
+
var _addend = new Vector3();
|
|
22975
|
+
function featureSeat(anchor, host, hostPos, hostBo, jd) {
|
|
22976
|
+
_addend.set(0, 0, 0);
|
|
22977
|
+
const idx = hostBo?.nomenclatureActiveIndex ?? -1;
|
|
22978
|
+
const label = idx >= 0 ? hostBo?.nomenclatureLabels?.[idx] ?? null : null;
|
|
22979
|
+
if (label && label.element.dataset.featureId === String(anchor.featureId)) {
|
|
22980
|
+
const modelAnchor = hostBo?.nomenclatureAnchor;
|
|
22981
|
+
if (modelAnchor) {
|
|
22982
|
+
_fixed.copy(label.position);
|
|
22983
|
+
_addend.copy(modelAnchor.position);
|
|
22984
|
+
} else {
|
|
22985
|
+
_fixed.copy(label.position);
|
|
22986
|
+
if (hostBo?.mesh) _fixed.multiply(hostBo.mesh.scale);
|
|
22987
|
+
}
|
|
22988
|
+
} else {
|
|
22989
|
+
const radiusKm = host.data.radiusKm;
|
|
22990
|
+
const latR = anchor.lat * DEG2RAD$3;
|
|
22991
|
+
const lngR = anchor.lon * DEG2RAD$3;
|
|
22992
|
+
const seat = host.orientation && Number.isFinite(radiusKm) && radiusKm > 0 ? renderedSeatAt(hostBo, host.data.id, radiusKm, latR, lngR) : null;
|
|
22993
|
+
if (seat) _fixed.set(seat.pointKm[0], seat.pointKm[1], seat.pointKm[2]);
|
|
22994
|
+
else {
|
|
22995
|
+
const r = Number.isFinite(radiusKm) && radiusKm > 0 ? radiusKm : 0;
|
|
22996
|
+
const [nx, ny, nz] = bodyFixedUnit(latR, lngR);
|
|
22997
|
+
_fixed.set(r * nx, r * ny, r * nz);
|
|
22998
|
+
}
|
|
22999
|
+
_fixed.multiplyScalar(kmToScene(1));
|
|
23000
|
+
}
|
|
23001
|
+
if (host.orientation) _fixed.applyQuaternion(bodyQuaternion(host.orientation, jd, host.nutPrec));
|
|
23002
|
+
return [
|
|
23003
|
+
hostPos[0] + _fixed.x + _addend.x,
|
|
23004
|
+
hostPos[1] + _fixed.y + _addend.y,
|
|
23005
|
+
hostPos[2] + _fixed.z + _addend.z
|
|
23006
|
+
];
|
|
22847
23007
|
}
|
|
22848
23008
|
|
|
22849
23009
|
// src/lib/scene/label/throttled-renderer.ts
|
|
@@ -23045,6 +23205,7 @@ function makeTrailMaterial(color, brightness = TRAIL_DIM) {
|
|
|
23045
23205
|
}
|
|
23046
23206
|
var TRIM_DEPTH = CAMERA_NEAR / 2;
|
|
23047
23207
|
var TRIM_SHARE = 1e-6;
|
|
23208
|
+
var MITER_LIMIT = 4;
|
|
23048
23209
|
function makeFatTrailMaterial(color, lineWidth, brightness = TRAIL_DIM, dash) {
|
|
23049
23210
|
return new ShaderMaterial({
|
|
23050
23211
|
defines: dash ? { DASHED: "" } : {},
|
|
@@ -23070,9 +23231,11 @@ function makeFatTrailMaterial(color, lineWidth, brightness = TRAIL_DIM, dash) {
|
|
|
23070
23231
|
uniform float uLineWidth;
|
|
23071
23232
|
uniform vec2 uResolution;
|
|
23072
23233
|
uniform vec2 uTrim;
|
|
23073
|
-
attribute
|
|
23234
|
+
attribute vec3 corner;
|
|
23235
|
+
attribute vec3 segPrev;
|
|
23074
23236
|
attribute vec3 segStart;
|
|
23075
23237
|
attribute vec3 segEnd;
|
|
23238
|
+
attribute vec3 segNext;
|
|
23076
23239
|
attribute vec2 alphaStart;
|
|
23077
23240
|
attribute vec2 alphaEnd;
|
|
23078
23241
|
varying float vAlpha;
|
|
@@ -23082,9 +23245,78 @@ function makeFatTrailMaterial(color, lineWidth, brightness = TRAIL_DIM, dash) {
|
|
|
23082
23245
|
varying float vDistW;
|
|
23083
23246
|
varying float vW;
|
|
23084
23247
|
#endif
|
|
23248
|
+
vec3 toView(vec3 point) {
|
|
23249
|
+
return mat3(viewMatrix) * (point + uCenterOffset);
|
|
23250
|
+
}
|
|
23251
|
+
vec2 toPx(vec3 view) {
|
|
23252
|
+
vec4 clip = projectionMatrix * vec4(view, 1.0);
|
|
23253
|
+
return clip.xy / clip.w * uResolution * 0.5;
|
|
23254
|
+
}
|
|
23255
|
+
// The unit direction on screen from one point to another, with the
|
|
23256
|
+
// distance in pixels in z.
|
|
23257
|
+
vec3 heading(vec2 from, vec2 to) {
|
|
23258
|
+
vec2 d = to - from;
|
|
23259
|
+
// Scaled before normalising: an end cut just ahead of the camera can
|
|
23260
|
+
// sit 1e20 px off screen, and its square overflows a float.
|
|
23261
|
+
float span = max(abs(d.x), abs(d.y));
|
|
23262
|
+
// Seen end on: any direction will do.
|
|
23263
|
+
if (span < 1e-4) return vec3(1.0, 0.0, 0.0);
|
|
23264
|
+
vec2 u = d / span;
|
|
23265
|
+
return vec3(normalize(u), span * length(u));
|
|
23266
|
+
}
|
|
23267
|
+
// The screen headings into and out of the middle of three points. Both
|
|
23268
|
+
// segments at a turn call this with the same points, so they place
|
|
23269
|
+
// their shared corners alike.
|
|
23270
|
+
void turnAt(vec3 before, vec3 at, vec3 after, out vec3 din, out vec3 dout) {
|
|
23271
|
+
vec2 p = toPx(toView(at));
|
|
23272
|
+
din = heading(toPx(toView(before)), p);
|
|
23273
|
+
dout = heading(p, toPx(toView(after)));
|
|
23274
|
+
}
|
|
23275
|
+
// A mitred corner: its offset, and how far along the quad's own
|
|
23276
|
+
// segment it moves.
|
|
23277
|
+
vec3 mitredAt(vec2 offset, vec2 own) {
|
|
23278
|
+
return vec3(offset, dot(offset, own));
|
|
23279
|
+
}
|
|
23280
|
+
// This corner's offset in pixels from the point where the line turns
|
|
23281
|
+
// from din to dout, and in z how far it moves along the quad's own
|
|
23282
|
+
// segment, own. The quads either side compute it from the same three
|
|
23283
|
+
// points, so they meet exactly. A square end, the fallback, moves
|
|
23284
|
+
// nothing along: exactly nothing, since a dash can end right there.
|
|
23285
|
+
vec3 cornerAt(vec3 din, vec3 dout, vec2 own, bool joins) {
|
|
23286
|
+
float h = uLineWidth * 0.5;
|
|
23287
|
+
vec3 square = vec3(vec2(-own.y, own.x) * corner.x * h, 0.0);
|
|
23288
|
+
bool bevel = corner.z > 0.5;
|
|
23289
|
+
if (!joins || din.z == 0.0 || dout.z == 0.0) return bevel ? vec3(0.0) : square;
|
|
23290
|
+
float inner = din.x * dout.y - din.y * dout.x >= 0.0 ? 1.0 : -1.0;
|
|
23291
|
+
vec2 bisector = din.xy + dout.xy;
|
|
23292
|
+
// The cosine of half the turn.
|
|
23293
|
+
float cosHalf = length(bisector) * 0.5;
|
|
23294
|
+
float safeCos = max(cosHalf, 1e-6);
|
|
23295
|
+
vec2 mitre = vec2(-bisector.y, bisector.x) / (2.0 * safeCos) * (h / safeCos);
|
|
23296
|
+
// How far along each segment the inner corner moves. Past half the
|
|
23297
|
+
// shorter segment it would cross that segment's other corner, and
|
|
23298
|
+
// square ends overlap instead, as with no join.
|
|
23299
|
+
float reach = h * sqrt(max(1.0 - cosHalf * cosHalf, 0.0)) / safeCos;
|
|
23300
|
+
bool fits = cosHalf > 1e-3 && reach <= 0.5 * min(din.z, dout.z);
|
|
23301
|
+
bool mitred = fits && cosHalf * ${MITER_LIMIT.toFixed(1)} >= 1.0;
|
|
23302
|
+
if (bevel) {
|
|
23303
|
+
// Each segment's square outer corner and the inner corner they
|
|
23304
|
+
// share, at the turn's own distance along the line. Flat under a
|
|
23305
|
+
// mitre, which covers the turn by itself, and beside a segment
|
|
23306
|
+
// shorter than the line is wide, where it could reach into the
|
|
23307
|
+
// quad past that segment.
|
|
23308
|
+
if (mitred || (!fits && min(din.z, dout.z) < uLineWidth)) return vec3(0.0);
|
|
23309
|
+
if (corner.z < 1.5) return vec3(-inner * vec2(-din.y, din.x) * h, 0.0);
|
|
23310
|
+
if (corner.z < 2.5) return vec3(-inner * vec2(-dout.y, dout.x) * h, 0.0);
|
|
23311
|
+
return vec3(fits ? inner * mitre : vec2(0.0), 0.0);
|
|
23312
|
+
}
|
|
23313
|
+
if (!fits) return square;
|
|
23314
|
+
if (corner.x == inner) return mitredAt(inner * mitre, own);
|
|
23315
|
+
return mitred ? mitredAt(-inner * mitre, own) : square;
|
|
23316
|
+
}
|
|
23085
23317
|
void main() {
|
|
23086
|
-
vec3 a =
|
|
23087
|
-
vec3 b =
|
|
23318
|
+
vec3 a = toView(segStart);
|
|
23319
|
+
vec3 b = toView(segEnd);
|
|
23088
23320
|
float aheadA = -a.z;
|
|
23089
23321
|
float aheadB = -b.z;
|
|
23090
23322
|
float front = max(aheadA, aheadB);
|
|
@@ -23106,28 +23338,32 @@ function makeFatTrailMaterial(color, lineWidth, brightness = TRAIL_DIM, dash) {
|
|
|
23106
23338
|
float cutB = aheadB < uTrim.x ? (cut - aheadB) / (aheadA - aheadB) : 0.0;
|
|
23107
23339
|
if (cutA > 0.0) a = vec3(mix(a.xy, b.xy, cutA), -cut);
|
|
23108
23340
|
if (cutB > 0.0) b = vec3(mix(b.xy, a.xy, cutB), -cut);
|
|
23109
|
-
vec4 clipA = projectionMatrix * vec4(a, 1.0);
|
|
23110
|
-
vec4 clipB = projectionMatrix * vec4(b, 1.0);
|
|
23111
|
-
vec2 ndcA = clipA.xy / clipA.w;
|
|
23112
|
-
vec2 ndcB = clipB.xy / clipB.w;
|
|
23113
|
-
vec2 dirPx = (ndcB - ndcA) * uResolution * 0.5;
|
|
23114
|
-
// Scaled before normalising: an end cut just ahead of the camera can
|
|
23115
|
-
// sit 1e20 px off screen, and its square overflows a float.
|
|
23116
|
-
float span = max(abs(dirPx.x), abs(dirPx.y));
|
|
23117
|
-
// A segment seen end on: any perpendicular will do.
|
|
23118
|
-
vec2 dirN = span < 1e-4 ? vec2(1.0, 0.0) : normalize(dirPx / span);
|
|
23119
|
-
vec2 offsetNDC = vec2(-dirN.y, dirN.x) * corner.x * uLineWidth / uResolution;
|
|
23120
23341
|
bool atEnd = corner.y > 0.5;
|
|
23121
|
-
|
|
23122
|
-
|
|
23123
|
-
|
|
23342
|
+
vec3 own = heading(toPx(a), toPx(b));
|
|
23343
|
+
// The turn this corner sits on, read in the line's direction: only
|
|
23344
|
+
// with all three of its points ahead of the camera, so that both
|
|
23345
|
+
// segments at the turn agree on it.
|
|
23346
|
+
bool joins = cutA == 0.0 && cutB == 0.0 && -toView(atEnd ? segNext : segPrev).z >= uTrim.x;
|
|
23347
|
+
vec3 din = own;
|
|
23348
|
+
vec3 dout = own;
|
|
23349
|
+
if (joins) {
|
|
23350
|
+
if (atEnd) turnAt(segStart, segEnd, segNext, din, dout);
|
|
23351
|
+
else turnAt(segPrev, segStart, segEnd, din, dout);
|
|
23352
|
+
own = atEnd ? din : dout;
|
|
23353
|
+
}
|
|
23354
|
+
vec3 offset = cornerAt(din, dout, own.xy, joins);
|
|
23355
|
+
vec4 clip = projectionMatrix * vec4(atEnd ? b : a, 1.0);
|
|
23356
|
+
gl_Position = vec4((clip.xy / clip.w + offset.xy * 2.0 / uResolution) * clip.w, clip.zw);
|
|
23124
23357
|
vec2 alphas = atEnd ? mix(alphaEnd, alphaStart, cutB) : mix(alphaStart, alphaEnd, cutA);
|
|
23125
23358
|
vAlpha = mix(alphas.x, alphas.y, uShowFull);
|
|
23126
23359
|
#ifdef DASHED
|
|
23127
23360
|
// Carried times w and divided back out per fragment, which undoes
|
|
23128
23361
|
// the perspective a varying is interpolated with: the dashes are
|
|
23129
|
-
// even on screen however much nearer one end is.
|
|
23362
|
+
// even on screen however much nearer one end is. A corner a mitre
|
|
23363
|
+
// moves along the segment counts on by as much, so dash ends stay
|
|
23364
|
+
// square to the line.
|
|
23130
23365
|
float dist = atEnd ? mix(distEnd, distStart, cutB) : mix(distStart, distEnd, cutA);
|
|
23366
|
+
dist += offset.z;
|
|
23131
23367
|
vDistW = dist * clip.w;
|
|
23132
23368
|
vW = clip.w;
|
|
23133
23369
|
#endif
|
|
@@ -25015,7 +25251,7 @@ function clampCameraOutsideBody(camera, body, focusTruePos, surface, clearanceKm
|
|
|
25015
25251
|
const dist = Math.hypot(dx, dy, dz);
|
|
25016
25252
|
if (surface?.seated) {
|
|
25017
25253
|
if (dist < 1e-9) {
|
|
25018
|
-
camera.position.set(cx, cy +
|
|
25254
|
+
camera.position.set(cx, cy + kmToScene(radiusKm + LANDED_KEEP_AWAY_KM), cz);
|
|
25019
25255
|
return;
|
|
25020
25256
|
}
|
|
25021
25257
|
const hh = Math.tan(camera.fov * Math.PI / 360) * camera.near;
|
|
@@ -25060,7 +25296,7 @@ function clampCameraOutsideBody(camera, body, focusTruePos, surface, clearanceKm
|
|
|
25060
25296
|
_dirBF.y,
|
|
25061
25297
|
_dirBF.z
|
|
25062
25298
|
]);
|
|
25063
|
-
const wall =
|
|
25299
|
+
const wall = kmToScene((sKm ?? radiusKm) + LANDED_KEEP_AWAY_KM);
|
|
25064
25300
|
if (wall - r > lift) lift = wall - r;
|
|
25065
25301
|
}
|
|
25066
25302
|
if (lift <= 0) return;
|
|
@@ -25284,7 +25520,6 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
25284
25520
|
screenOccluders.length = occluderCount;
|
|
25285
25521
|
const focusedSystemId = ctx.visibility.focusedSystemId;
|
|
25286
25522
|
let newlyShownLabel = false;
|
|
25287
|
-
const nomFocusedBodyId = focusedBodyId ? nomenclatureBodyId(ctx.getBody(focusedBodyId), bodyObjects) : void 0;
|
|
25288
25523
|
for (const bo of bodyObjects.values()) {
|
|
25289
25524
|
const { body, group, trail } = bo;
|
|
25290
25525
|
const dist = bo.cachedDist;
|
|
@@ -25292,7 +25527,7 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
25292
25527
|
const drawn = isDrawn(bo);
|
|
25293
25528
|
bo.root.visible = drawn;
|
|
25294
25529
|
let showLabel;
|
|
25295
|
-
const isFocused = body.data.id
|
|
25530
|
+
const isFocused = ctx.visibility.inFocus(body.data.id);
|
|
25296
25531
|
const isSystemRoot = focusedSystemId !== null && body.data.id === focusedSystemId;
|
|
25297
25532
|
const centreShare = ctx.visibility.systemCentres.get(body.data.id);
|
|
25298
25533
|
const isHeldStar = isFocused || ctx.visibility.isPinned(body.data.id) || centreShare === 1;
|
|
@@ -25401,7 +25636,7 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
25401
25636
|
if (bo.label) fadeLabel(bo.label, labelShare);
|
|
25402
25637
|
if (bo.planetDot) bo.planetDot.material.opacity = labelShare;
|
|
25403
25638
|
const nomScreenR = bo.radiusScene > 0 ? bo.radiusScene / dist * projScale : 0;
|
|
25404
|
-
const isNomFocused = showNomenclature && body.data.id ===
|
|
25639
|
+
const isNomFocused = showNomenclature && body.data.id === focusedBodyId;
|
|
25405
25640
|
updateNomenclatureVisibility(bo, isNomFocused, nomScreenR, projScale, camera, screenW, screenH);
|
|
25406
25641
|
}
|
|
25407
25642
|
if (screenOccluders.length > 0) {
|
|
@@ -25413,7 +25648,7 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
25413
25648
|
if (isScreenOccluded(_occlusionRect.x, _occlusionRect.y, bo.cachedDist, id, screenOccluders, id === focusedBodyId ? focusedPrimaryId : null)) bo.label.visible = false;
|
|
25414
25649
|
}
|
|
25415
25650
|
}
|
|
25416
|
-
const groundBo =
|
|
25651
|
+
const groundBo = focusedBodyId ? bodyObjects.get(focusedBodyId) : void 0;
|
|
25417
25652
|
const ground = groundBo?.body.position;
|
|
25418
25653
|
if (groundBo && ground) {
|
|
25419
25654
|
const relief = reliefRadiiKm(groundBo);
|
|
@@ -25424,17 +25659,17 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
25424
25659
|
for (const bo of bodyObjects.values()) {
|
|
25425
25660
|
const at = bo.body.position;
|
|
25426
25661
|
const id = bo.body.data.id;
|
|
25427
|
-
if (!bo.label?.visible || !at || id
|
|
25662
|
+
if (!bo.label?.visible || !at || ctx.visibility.inFocus(id)) continue;
|
|
25428
25663
|
if (behindGround(at[0] - ground[0], at[1] - ground[1], at[2] - ground[2], cx, cy, cz, top)) bo.label.visible = false;
|
|
25429
25664
|
}
|
|
25430
25665
|
}
|
|
25431
25666
|
if (forceCull || newlyShownLabel || ++cullFrameCounter >= 3) {
|
|
25432
25667
|
cullFrameCounter = 0;
|
|
25433
|
-
cullOverlappingLabels(bodyObjects, screenW, screenH, camera,
|
|
25668
|
+
cullOverlappingLabels(bodyObjects, screenW, screenH, camera, ctx, hoveredBodyIds, screenOccluders, focusTruePos);
|
|
25434
25669
|
}
|
|
25435
25670
|
refreshVisibleBodyLabelRects(bodyObjects, screenW, screenH, camera, focusTruePos, sceneSettings().showConstellations);
|
|
25436
|
-
if (
|
|
25437
|
-
const focusedBo = bodyObjects.get(
|
|
25671
|
+
if (focusedBodyId) {
|
|
25672
|
+
const focusedBo = bodyObjects.get(focusedBodyId);
|
|
25438
25673
|
if (focusedBo) cullOverlappingNomenclatureLabels(focusedBo);
|
|
25439
25674
|
}
|
|
25440
25675
|
for (const bo of bodyObjects.values()) {
|
|
@@ -25442,7 +25677,7 @@ function updateBodyVisibility(bodyObjects, camera, ctx, focusTruePos, focusedBod
|
|
|
25442
25677
|
if (!line?.visible) continue;
|
|
25443
25678
|
const mat = line.material;
|
|
25444
25679
|
mat.uniforms.uCenterOffset.value.set(-camera.position.x, -camera.position.y, -camera.position.z);
|
|
25445
|
-
const isFocused = bo.body.data.id
|
|
25680
|
+
const isFocused = ctx.visibility.inFocus(bo.body.data.id);
|
|
25446
25681
|
const isHovered = hoveredBodyIds.has(bo.body.data.id);
|
|
25447
25682
|
const share = ctx.visibility.systemShareOf(bo.body) * (line.userData.zoneShare ?? 1) * (line.userData.thresholdShare ?? 1) * (line.userData.haloShare ?? 1);
|
|
25448
25683
|
mat.uniforms.uAlphaMultiplier.value = (isHovered ? 2 : isFocused ? 1.75 : 1) * share;
|
|
@@ -29525,13 +29760,9 @@ var GALACTIC_NORTH_SCENE = (() => {
|
|
|
29525
29760
|
function galacticNorthVector(out) {
|
|
29526
29761
|
return (out ?? new Vector3()).copy(GALACTIC_NORTH_SCENE);
|
|
29527
29762
|
}
|
|
29528
|
-
function bodyNorthVector(body, jd, out
|
|
29763
|
+
function bodyNorthVector(body, jd, out) {
|
|
29529
29764
|
const target = out ?? new Vector3();
|
|
29530
29765
|
if (!body.orientation) {
|
|
29531
|
-
if (landed && body.orbitCenter && body.position) {
|
|
29532
|
-
target.set(body.position[0] - body.orbitCenter[0], body.position[1] - body.orbitCenter[1], body.position[2] - body.orbitCenter[2]);
|
|
29533
|
-
if (target.lengthSq() > 1e-20) return target.normalize();
|
|
29534
|
-
}
|
|
29535
29766
|
target.copy(SCENE_UP);
|
|
29536
29767
|
if (body.modelBaseFrame) target.applyQuaternion(body.modelBaseFrame).normalize();
|
|
29537
29768
|
return target;
|
|
@@ -29545,7 +29776,6 @@ var CameraUpController = class {
|
|
|
29545
29776
|
camera;
|
|
29546
29777
|
controls;
|
|
29547
29778
|
ctx;
|
|
29548
|
-
isLanded;
|
|
29549
29779
|
refId = null;
|
|
29550
29780
|
startVec = new Vector3(0, 1, 0);
|
|
29551
29781
|
targetVec = new Vector3(0, 1, 0);
|
|
@@ -29556,11 +29786,10 @@ var CameraUpController = class {
|
|
|
29556
29786
|
plane = null;
|
|
29557
29787
|
_quatA = new Quaternion();
|
|
29558
29788
|
_quatB = new Quaternion();
|
|
29559
|
-
constructor(camera, controls, ctx
|
|
29789
|
+
constructor(camera, controls, ctx) {
|
|
29560
29790
|
this.camera = camera;
|
|
29561
29791
|
this.controls = controls;
|
|
29562
29792
|
this.ctx = ctx;
|
|
29563
|
-
this.isLanded = isLanded;
|
|
29564
29793
|
}
|
|
29565
29794
|
setNorthReference(id) {
|
|
29566
29795
|
if (id === this.refId) return;
|
|
@@ -29579,10 +29808,8 @@ var CameraUpController = class {
|
|
|
29579
29808
|
else this.targetVec.copy(SCENE_UP);
|
|
29580
29809
|
} else {
|
|
29581
29810
|
const refBody = this.refId ? this.ctx.getBody(this.refId) : void 0;
|
|
29582
|
-
if (refBody)
|
|
29583
|
-
|
|
29584
|
-
bodyNorthVector(refBody, jd, this.targetVec, landed);
|
|
29585
|
-
} else this.targetVec.copy(SCENE_UP);
|
|
29811
|
+
if (refBody) bodyNorthVector(refBody, jd, this.targetVec);
|
|
29812
|
+
else this.targetVec.copy(SCENE_UP);
|
|
29586
29813
|
}
|
|
29587
29814
|
if (this.needsDurationCalc) {
|
|
29588
29815
|
this.needsDurationCalc = false;
|
|
@@ -30323,46 +30550,71 @@ function orbitalElementsToCurve(el, numPoints = 512) {
|
|
|
30323
30550
|
|
|
30324
30551
|
// src/lib/scene/objects/trail/geometry.ts
|
|
30325
30552
|
var TRAIL_RENDER_ORDER = 3;
|
|
30326
|
-
var
|
|
30553
|
+
var CORNERS = [
|
|
30327
30554
|
-1,
|
|
30328
30555
|
0,
|
|
30556
|
+
0,
|
|
30329
30557
|
1,
|
|
30330
30558
|
0,
|
|
30559
|
+
0,
|
|
30331
30560
|
-1,
|
|
30332
30561
|
1,
|
|
30562
|
+
0,
|
|
30333
30563
|
1,
|
|
30334
|
-
1
|
|
30564
|
+
1,
|
|
30565
|
+
0,
|
|
30566
|
+
0,
|
|
30567
|
+
0,
|
|
30568
|
+
1,
|
|
30569
|
+
0,
|
|
30570
|
+
0,
|
|
30571
|
+
2,
|
|
30572
|
+
0,
|
|
30573
|
+
0,
|
|
30574
|
+
3
|
|
30335
30575
|
];
|
|
30336
|
-
var
|
|
30576
|
+
var CORNER_INDICES = [
|
|
30337
30577
|
0,
|
|
30338
30578
|
1,
|
|
30339
30579
|
2,
|
|
30340
30580
|
2,
|
|
30341
30581
|
1,
|
|
30342
|
-
3
|
|
30582
|
+
3,
|
|
30583
|
+
4,
|
|
30584
|
+
5,
|
|
30585
|
+
6
|
|
30343
30586
|
];
|
|
30344
30587
|
function instanced(geometry, name) {
|
|
30345
30588
|
return geometry.getAttribute(name).data;
|
|
30346
30589
|
}
|
|
30347
|
-
function
|
|
30348
|
-
const buffer = new InstancedInterleavedBuffer(new Float32Array(
|
|
30349
|
-
geometry.setAttribute(
|
|
30350
|
-
geometry.setAttribute(names[1], new InterleavedBufferAttribute(buffer, stride, stride));
|
|
30590
|
+
function setPointAttributes(geometry, names, count, stride) {
|
|
30591
|
+
const buffer = new InstancedInterleavedBuffer(new Float32Array(count * stride), stride);
|
|
30592
|
+
names.forEach((name, i) => geometry.setAttribute(name, new InterleavedBufferAttribute(buffer, stride, i * stride)));
|
|
30351
30593
|
}
|
|
30352
30594
|
function makeFatTrailGeometry(capacity) {
|
|
30353
30595
|
const geometry = new InstancedBufferGeometry();
|
|
30354
|
-
geometry.setAttribute("corner", new Float32BufferAttribute(
|
|
30355
|
-
geometry.setIndex(
|
|
30356
|
-
|
|
30357
|
-
|
|
30596
|
+
geometry.setAttribute("corner", new Float32BufferAttribute(CORNERS, 3));
|
|
30597
|
+
geometry.setIndex(CORNER_INDICES);
|
|
30598
|
+
setPointAttributes(geometry, [
|
|
30599
|
+
"segPrev",
|
|
30600
|
+
"segStart",
|
|
30601
|
+
"segEnd",
|
|
30602
|
+
"segNext"
|
|
30603
|
+
], capacity + 2, 3);
|
|
30604
|
+
setPointAttributes(geometry, ["alphaStart", "alphaEnd"], capacity, 2);
|
|
30358
30605
|
geometry.instanceCount = 0;
|
|
30359
30606
|
return geometry;
|
|
30360
30607
|
}
|
|
30361
30608
|
function writeFatTrailVertices(geometry, posSrc, trailSrc, fullSrc, n) {
|
|
30362
30609
|
const points = instanced(geometry, "segStart");
|
|
30363
30610
|
const alphas = instanced(geometry, "alphaStart");
|
|
30364
|
-
const m = Math.min(n,
|
|
30365
|
-
points.array
|
|
30611
|
+
const m = Math.min(n, alphas.count);
|
|
30612
|
+
const arr = points.array;
|
|
30613
|
+
arr.set(posSrc.subarray(0, m * 3), 3);
|
|
30614
|
+
const last = (m - 1) * 3;
|
|
30615
|
+
const closed = m > 2 && posSrc[0] === posSrc[last] && posSrc[1] === posSrc[last + 1] && posSrc[2] === posSrc[last + 2];
|
|
30616
|
+
arr.copyWithin(0, closed ? last : 3, closed ? last + 3 : 6);
|
|
30617
|
+
arr.copyWithin((m + 1) * 3, closed ? 6 : m * 3, closed ? 9 : (m + 1) * 3);
|
|
30366
30618
|
const alphaArr = alphas.array;
|
|
30367
30619
|
for (let i = 0; i < m; i++) {
|
|
30368
30620
|
alphaArr[2 * i] = trailSrc[i];
|
|
@@ -30371,7 +30623,7 @@ function writeFatTrailVertices(geometry, posSrc, trailSrc, fullSrc, n) {
|
|
|
30371
30623
|
points.needsUpdate = true;
|
|
30372
30624
|
alphas.needsUpdate = true;
|
|
30373
30625
|
geometry.instanceCount = Math.max(0, m - 1);
|
|
30374
|
-
geometry.setDrawRange(0,
|
|
30626
|
+
geometry.setDrawRange(0, CORNER_INDICES.length);
|
|
30375
30627
|
}
|
|
30376
30628
|
function makeEmptyTrail() {
|
|
30377
30629
|
const geometry = new BufferGeometry();
|
|
@@ -30401,7 +30653,7 @@ function writeLineDistances(geometry, src, n) {
|
|
|
30401
30653
|
}
|
|
30402
30654
|
function buildFatLineFromThin(capacity, posArr, trailAlphas, fullAlphas, total, color, lineWidth, brightness, dash) {
|
|
30403
30655
|
const geometry = makeFatTrailGeometry(capacity);
|
|
30404
|
-
if (dash)
|
|
30656
|
+
if (dash) setPointAttributes(geometry, ["distStart", "distEnd"], capacity, 1);
|
|
30405
30657
|
writeFatTrailVertices(geometry, posArr, trailAlphas, fullAlphas, total);
|
|
30406
30658
|
const mesh = new Mesh(geometry, makeFatTrailMaterial(color, lineWidth, brightness, dash));
|
|
30407
30659
|
mesh.matrixAutoUpdate = false;
|
|
@@ -30768,7 +31020,7 @@ var SystemDataLoader = class {
|
|
|
30768
31020
|
};
|
|
30769
31021
|
|
|
30770
31022
|
// src/lib/scene/debug/skybox-adjust.ts
|
|
30771
|
-
var DEG2RAD$
|
|
31023
|
+
var DEG2RAD$2 = Math.PI / 180;
|
|
30772
31024
|
var SkyboxAdjuster = class {
|
|
30773
31025
|
scene;
|
|
30774
31026
|
adjust = {
|
|
@@ -30792,15 +31044,15 @@ var SkyboxAdjuster = class {
|
|
|
30792
31044
|
this.adjust.rxDeg = rxDeg;
|
|
30793
31045
|
this.adjust.ryDeg = ryDeg;
|
|
30794
31046
|
this.adjust.rzDeg = rzDeg;
|
|
30795
|
-
this._adjustQ.setFromAxisAngle(this._axisX, rxDeg * DEG2RAD$
|
|
31047
|
+
this._adjustQ.setFromAxisAngle(this._axisX, rxDeg * DEG2RAD$2).premultiply(this._tmpQ.setFromAxisAngle(this._axisY, ryDeg * DEG2RAD$2)).premultiply(this._tmpQ.setFromAxisAngle(this._axisZ, rzDeg * DEG2RAD$2));
|
|
30796
31048
|
this._q.copy(SKYBOX_BASE_ROTATION).multiply(this._adjustQ);
|
|
30797
31049
|
this.scene.backgroundRotation.setFromQuaternion(this._q);
|
|
30798
31050
|
}
|
|
30799
31051
|
};
|
|
30800
31052
|
|
|
30801
31053
|
// src/lib/scene/objects/sky/debug-markers.ts
|
|
30802
|
-
var DEG2RAD$
|
|
30803
|
-
var OBL_RAD = EARTH_OBLIQUITY_DEG * DEG2RAD$
|
|
31054
|
+
var DEG2RAD$1 = Math.PI / 180;
|
|
31055
|
+
var OBL_RAD = EARTH_OBLIQUITY_DEG * DEG2RAD$1;
|
|
30804
31056
|
var COS_OBL = Math.cos(OBL_RAD);
|
|
30805
31057
|
var SIN_OBL = Math.sin(OBL_RAD);
|
|
30806
31058
|
var SKY_MARKER_RADIUS = 5e3;
|
|
@@ -30916,8 +31168,8 @@ var REFERENCE_CIRCLES = [
|
|
|
30916
31168
|
}
|
|
30917
31169
|
];
|
|
30918
31170
|
function eqToScene(raDeg, decDeg, out) {
|
|
30919
|
-
const ra = raDeg * DEG2RAD$
|
|
30920
|
-
const dec = decDeg * DEG2RAD$
|
|
31171
|
+
const ra = raDeg * DEG2RAD$1;
|
|
31172
|
+
const dec = decDeg * DEG2RAD$1;
|
|
30921
31173
|
const cd = Math.cos(dec);
|
|
30922
31174
|
const xEq = cd * Math.cos(ra);
|
|
30923
31175
|
const yEq = cd * Math.sin(ra);
|
|
@@ -32600,16 +32852,16 @@ function between(points, jds, jd, from = 0, to = points.length) {
|
|
|
32600
32852
|
}
|
|
32601
32853
|
|
|
32602
32854
|
// src/lib/math/travel/state.ts
|
|
32603
|
-
var DEG2RAD
|
|
32604
|
-
var COS_EPS = Math.cos(EARTH_OBLIQUITY_DEG * DEG2RAD
|
|
32605
|
-
var SIN_EPS = Math.sin(EARTH_OBLIQUITY_DEG * DEG2RAD
|
|
32855
|
+
var DEG2RAD = Math.PI / 180;
|
|
32856
|
+
var COS_EPS = Math.cos(EARTH_OBLIQUITY_DEG * DEG2RAD);
|
|
32857
|
+
var SIN_EPS = Math.sin(EARTH_OBLIQUITY_DEG * DEG2RAD);
|
|
32606
32858
|
function planeRotation(w, i, om, equatorial) {
|
|
32607
|
-
const cosW = Math.cos(w * DEG2RAD
|
|
32608
|
-
const sinW = Math.sin(w * DEG2RAD
|
|
32609
|
-
const cosI = Math.cos(i * DEG2RAD
|
|
32610
|
-
const sinI = Math.sin(i * DEG2RAD
|
|
32611
|
-
const cosOm = Math.cos(om * DEG2RAD
|
|
32612
|
-
const sinOm = Math.sin(om * DEG2RAD
|
|
32859
|
+
const cosW = Math.cos(w * DEG2RAD);
|
|
32860
|
+
const sinW = Math.sin(w * DEG2RAD);
|
|
32861
|
+
const cosI = Math.cos(i * DEG2RAD);
|
|
32862
|
+
const sinI = Math.sin(i * DEG2RAD);
|
|
32863
|
+
const cosOm = Math.cos(om * DEG2RAD);
|
|
32864
|
+
const sinOm = Math.sin(om * DEG2RAD);
|
|
32613
32865
|
return {
|
|
32614
32866
|
m11: cosOm * cosW - sinOm * sinW * cosI,
|
|
32615
32867
|
m12: -cosOm * sinW - sinOm * cosW * cosI,
|
|
@@ -32659,10 +32911,10 @@ function elementsToState(el, jd) {
|
|
|
32659
32911
|
}
|
|
32660
32912
|
if (!isFinite(e) || !isFinite(ma)) return null;
|
|
32661
32913
|
const aKm = a * AU_KM;
|
|
32662
|
-
const nRadPerSec = n * DEG2RAD
|
|
32914
|
+
const nRadPerSec = n * DEG2RAD / SEC_PER_DAY$1;
|
|
32663
32915
|
const mu = nRadPerSec * nRadPerSec * Math.abs(aKm) * Math.abs(aKm) * Math.abs(aKm);
|
|
32664
32916
|
if (!isFinite(mu) || mu <= 0) return null;
|
|
32665
|
-
const M = (ma + n * (t - epoch)) * DEG2RAD
|
|
32917
|
+
const M = (ma + n * (t - epoch)) * DEG2RAD;
|
|
32666
32918
|
let nu;
|
|
32667
32919
|
let rKm;
|
|
32668
32920
|
if (e < 1 || a > 0) {
|
|
@@ -33658,65 +33910,6 @@ function addVec(out, a, b) {
|
|
|
33658
33910
|
out[2] = a[2] + b[2];
|
|
33659
33911
|
}
|
|
33660
33912
|
|
|
33661
|
-
// src/lib/scene/position/feature-seat.ts
|
|
33662
|
-
var DEG2RAD = Math.PI / 180;
|
|
33663
|
-
var SEAT_GLIDE_TAU_MS = 120;
|
|
33664
|
-
var SEAT_GLIDE_SNAP_SQ = kmToScene(.001) ** 2;
|
|
33665
|
-
var glideState = /* @__PURE__ */ new WeakMap();
|
|
33666
|
-
var _fixed = new Vector3();
|
|
33667
|
-
var _addend = new Vector3();
|
|
33668
|
-
function glideVec(current, target, k) {
|
|
33669
|
-
if (current.distanceToSquared(target) <= SEAT_GLIDE_SNAP_SQ) current.copy(target);
|
|
33670
|
-
else current.lerp(target, k);
|
|
33671
|
-
}
|
|
33672
|
-
function seatFeatureBody(fb, host, hostPos, hostBo, jd) {
|
|
33673
|
-
const anchor = fb.featureAnchor;
|
|
33674
|
-
setOrbitCenter(fb, hostPos);
|
|
33675
|
-
_addend.set(0, 0, 0);
|
|
33676
|
-
const idx = hostBo?.nomenclatureActiveIndex ?? -1;
|
|
33677
|
-
const label = idx >= 0 ? hostBo?.nomenclatureLabels?.[idx] ?? null : null;
|
|
33678
|
-
if (label && label.element.dataset.featureId === String(anchor.featureId)) {
|
|
33679
|
-
const modelAnchor = hostBo?.nomenclatureAnchor;
|
|
33680
|
-
if (modelAnchor) {
|
|
33681
|
-
_fixed.copy(label.position);
|
|
33682
|
-
_addend.copy(modelAnchor.position);
|
|
33683
|
-
} else {
|
|
33684
|
-
_fixed.copy(label.position);
|
|
33685
|
-
if (hostBo?.mesh) _fixed.multiply(hostBo.mesh.scale);
|
|
33686
|
-
}
|
|
33687
|
-
} else {
|
|
33688
|
-
const radiusKm = host.data.radiusKm;
|
|
33689
|
-
const latR = anchor.lat * DEG2RAD;
|
|
33690
|
-
const lngR = anchor.lon * DEG2RAD;
|
|
33691
|
-
const seat = host.orientation && Number.isFinite(radiusKm) && radiusKm > 0 ? renderedSeatAt(hostBo, host.data.id, radiusKm, latR, lngR) : null;
|
|
33692
|
-
if (seat) _fixed.set(seat.pointKm[0], seat.pointKm[1], seat.pointKm[2]);
|
|
33693
|
-
else {
|
|
33694
|
-
const r = Number.isFinite(radiusKm) && radiusKm > 0 ? radiusKm : 0;
|
|
33695
|
-
const [nx, ny, nz] = bodyFixedUnit(latR, lngR);
|
|
33696
|
-
_fixed.set(r * nx, r * ny, r * nz);
|
|
33697
|
-
}
|
|
33698
|
-
_fixed.multiplyScalar(kmToScene(1));
|
|
33699
|
-
}
|
|
33700
|
-
const now = performance.now();
|
|
33701
|
-
let st = glideState.get(fb);
|
|
33702
|
-
if (!st) {
|
|
33703
|
-
st = {
|
|
33704
|
-
fixed: _fixed.clone(),
|
|
33705
|
-
addend: _addend.clone(),
|
|
33706
|
-
t: now
|
|
33707
|
-
};
|
|
33708
|
-
glideState.set(fb, st);
|
|
33709
|
-
} else {
|
|
33710
|
-
const k = 1 - Math.exp(-(now - st.t) / SEAT_GLIDE_TAU_MS);
|
|
33711
|
-
st.t = now;
|
|
33712
|
-
glideVec(st.fixed, _fixed, k);
|
|
33713
|
-
glideVec(st.addend, _addend, k);
|
|
33714
|
-
}
|
|
33715
|
-
_fixed.copy(st.fixed);
|
|
33716
|
-
if (host.orientation) _fixed.applyQuaternion(bodyQuaternion(host.orientation, jd, host.nutPrec));
|
|
33717
|
-
return setPlaced(fb, hostPos[0] + _fixed.x + st.addend.x, hostPos[1] + _fixed.y + st.addend.y, hostPos[2] + _fixed.z + st.addend.z);
|
|
33718
|
-
}
|
|
33719
|
-
|
|
33720
33913
|
// src/lib/math/orbit/lagrange.ts
|
|
33721
33914
|
var EARTH_SUN_MASS_RATIO = 30034e-10;
|
|
33722
33915
|
var ALONG_MIN = .45;
|
|
@@ -34051,7 +34244,7 @@ var Placer = class {
|
|
|
34051
34244
|
return null;
|
|
34052
34245
|
}
|
|
34053
34246
|
this.settling.add(id);
|
|
34054
|
-
const pos =
|
|
34247
|
+
const pos = isExtrasolar(body) && !body.data.parentId ? fixedPlace(body) : this.settle(body, jd);
|
|
34055
34248
|
this.settling.delete(id);
|
|
34056
34249
|
if (jd === this.passJd) this.settled.set(id, body);
|
|
34057
34250
|
return pos;
|
|
@@ -34060,13 +34253,6 @@ var Placer = class {
|
|
|
34060
34253
|
const why = (this.ctx.getBody(aboveId) ?? this.bodyObjects.get(aboveId)?.body)?.unplaced;
|
|
34061
34254
|
return why === "loading" || why === "never" ? why : "parent";
|
|
34062
34255
|
}
|
|
34063
|
-
seatFeature(body, jd) {
|
|
34064
|
-
const hostId = body.featureAnchor.hostId;
|
|
34065
|
-
const host = this.ctx.getBody(hostId);
|
|
34066
|
-
const hostPos = host && this.place(host, jd);
|
|
34067
|
-
if (!host || !hostPos) return setUnplaced(body, this.under(hostId));
|
|
34068
|
-
return seatFeatureBody(body, host, hostPos, this.bodyObjects.get(hostId), jd);
|
|
34069
|
-
}
|
|
34070
34256
|
rideAt(jd) {
|
|
34071
34257
|
if (jd !== this.rideJd || this.focusedId !== this.rideFocus) {
|
|
34072
34258
|
this.rideJd = jd;
|
|
@@ -35250,14 +35436,13 @@ function updateSphereLOD(bodyObjects, camera, renderer, ctx, focusedId, invalida
|
|
|
35250
35436
|
const fovRad = camera.fov * Math.PI / 180;
|
|
35251
35437
|
const projScale = renderer.domElement.clientHeight / (2 * Math.tan(fovRad / 2));
|
|
35252
35438
|
const activeSystem = ctx.visibility.activeSystemId;
|
|
35253
|
-
const terrainId = focusedId;
|
|
35254
35439
|
for (const bo of bodyObjects.values()) {
|
|
35255
35440
|
if (!bo.mesh || !bo.radiusScene || !bo.group.visible) continue;
|
|
35256
35441
|
if (bo.cachedDist <= 0) continue;
|
|
35257
35442
|
const isStar = bo.body.data.objectType === ObjectType.STAR;
|
|
35258
35443
|
const id = bo.body.data.id;
|
|
35259
|
-
if (id ===
|
|
35260
|
-
if (updateTerrainWindow(bo, camera, id ===
|
|
35444
|
+
if (id === focusedId || bo.terrainWindow) {
|
|
35445
|
+
if (updateTerrainWindow(bo, camera, id === focusedId, invalidate)) continue;
|
|
35261
35446
|
}
|
|
35262
35447
|
const desired = desiredSphereSegments(bo.radiusScene / bo.cachedDist * projScale, isStar, activeSystem ? id === activeSystem || ctx.visibility.isInActiveSystem(bo.body.data.parentId) : id === focusedId, bo.currentSegments ?? 64);
|
|
35263
35448
|
if (desired === bo.currentSegments) continue;
|
|
@@ -35642,8 +35827,11 @@ var PromotionRegistry = class {
|
|
|
35642
35827
|
this.finalizeBuilds();
|
|
35643
35828
|
}
|
|
35644
35829
|
syncSystemBodies(bodies) {
|
|
35645
|
-
const
|
|
35646
|
-
|
|
35830
|
+
for (const id of this.systemPromoted) {
|
|
35831
|
+
if (!this.deps.inFocus(id)) continue;
|
|
35832
|
+
this.systemPromoted.delete(id);
|
|
35833
|
+
this.userPromoted.add(id);
|
|
35834
|
+
}
|
|
35647
35835
|
const wanted = new Set(bodies.map((b) => b.data.id));
|
|
35648
35836
|
const dropped = [...this.systemPromoted].filter((id) => !wanted.has(id) && !this.pinned.has(id));
|
|
35649
35837
|
this.tearDownBodies(dropped, this.systemPromoted);
|
|
@@ -35755,11 +35943,10 @@ var PromotionRegistry = class {
|
|
|
35755
35943
|
}
|
|
35756
35944
|
teardownAutoPromoted(forceAll) {
|
|
35757
35945
|
if (this.autoPromoted.size === 0) return;
|
|
35758
|
-
const focusedId = this.deps.getFocusedId();
|
|
35759
35946
|
const jd = this.deps.clock.jd;
|
|
35760
35947
|
const toRemove = [];
|
|
35761
35948
|
for (const id of this.autoPromoted) {
|
|
35762
|
-
if (id
|
|
35949
|
+
if (this.deps.inFocus(id)) continue;
|
|
35763
35950
|
if (forceAll || this.groupTargets && !this.groupTargets.has(id)) {
|
|
35764
35951
|
toRemove.push(id);
|
|
35765
35952
|
continue;
|
|
@@ -35772,21 +35959,21 @@ var PromotionRegistry = class {
|
|
|
35772
35959
|
}
|
|
35773
35960
|
setPinned(ids) {
|
|
35774
35961
|
this.pinned = new Set(ids);
|
|
35775
|
-
const focusedId = this.deps.getFocusedId();
|
|
35776
35962
|
const dropped = [...this.pinPromoted].filter((id) => !this.pinned.has(id));
|
|
35777
|
-
|
|
35778
|
-
|
|
35779
|
-
this.
|
|
35780
|
-
this.
|
|
35963
|
+
const kept = dropped.filter(this.deps.inFocus);
|
|
35964
|
+
for (const id of kept) {
|
|
35965
|
+
this.pinPromoted.delete(id);
|
|
35966
|
+
this.userPromoted.add(id);
|
|
35781
35967
|
}
|
|
35782
|
-
|
|
35968
|
+
if (kept.length > 0) this.emitUserPromotedCount();
|
|
35969
|
+
this.tearDownBodies(dropped.filter((id) => !this.deps.inFocus(id)), this.pinPromoted);
|
|
35783
35970
|
this.buildPinned();
|
|
35784
35971
|
}
|
|
35785
35972
|
buildPinned() {
|
|
35786
35973
|
let built = false;
|
|
35787
35974
|
for (const id of this.pinned) {
|
|
35788
35975
|
const body = this.deps.ctx.getBody(id);
|
|
35789
|
-
if (!body ||
|
|
35976
|
+
if (!body || body.data.objectType === ObjectType.MOON) continue;
|
|
35790
35977
|
if (!this.buildBodyInstance(body)) continue;
|
|
35791
35978
|
built = true;
|
|
35792
35979
|
if (this.userPromoted.delete(id)) this.pinPromoted.add(id);
|
|
@@ -35796,8 +35983,7 @@ var PromotionRegistry = class {
|
|
|
35796
35983
|
this.finalizeBuilds();
|
|
35797
35984
|
}
|
|
35798
35985
|
clearUserPromoted() {
|
|
35799
|
-
const
|
|
35800
|
-
const toRemove = [...this.userPromoted].filter((id) => id !== focusedId);
|
|
35986
|
+
const toRemove = [...this.userPromoted].filter((id) => !this.deps.inFocus(id));
|
|
35801
35987
|
this.tearDownBodies(toRemove, this.userPromoted);
|
|
35802
35988
|
this.emitUserPromotedCount();
|
|
35803
35989
|
}
|
|
@@ -35858,15 +36044,61 @@ var PromotionRegistry = class {
|
|
|
35858
36044
|
}
|
|
35859
36045
|
emitUserPromotedCount() {
|
|
35860
36046
|
if (!this.deps.onUserPromotedChange) return;
|
|
35861
|
-
|
|
35862
|
-
|
|
35863
|
-
if (focusedId && this.userPromoted.has(focusedId)) count--;
|
|
36047
|
+
let count = 0;
|
|
36048
|
+
for (const id of this.userPromoted) if (!this.deps.inFocus(id)) count++;
|
|
35864
36049
|
this.deps.onUserPromotedChange(count);
|
|
35865
36050
|
}
|
|
35866
36051
|
};
|
|
35867
36052
|
|
|
35868
36053
|
// src/lib/scene/focus/controller.ts
|
|
36054
|
+
function surfaceSite(host, point, hostPos, jd) {
|
|
36055
|
+
const s = cartesianToSpherical([...point], [...hostPos], siteQuat(host, jd));
|
|
36056
|
+
return {
|
|
36057
|
+
latitude: s.latitude,
|
|
36058
|
+
longitude: s.longitude,
|
|
36059
|
+
radius: s.distance
|
|
36060
|
+
};
|
|
36061
|
+
}
|
|
36062
|
+
function siteQuat(host, jd) {
|
|
36063
|
+
const q = host.orientation && bodyQuaternion(host.orientation, jd, host.nutPrec);
|
|
36064
|
+
return q ? [
|
|
36065
|
+
q.x,
|
|
36066
|
+
q.y,
|
|
36067
|
+
q.z,
|
|
36068
|
+
q.w
|
|
36069
|
+
] : void 0;
|
|
36070
|
+
}
|
|
36071
|
+
function underHalfRadius(host, distance) {
|
|
36072
|
+
return distance < kmToScene(effectiveRadiusKm(host.data)) / 2;
|
|
36073
|
+
}
|
|
36074
|
+
function viewOverSite(site, offset, quat) {
|
|
36075
|
+
const { latitude, longitude } = site;
|
|
36076
|
+
const up = new Vector3(...sphericalToCartesian([
|
|
36077
|
+
0,
|
|
36078
|
+
0,
|
|
36079
|
+
0
|
|
36080
|
+
], latitude, longitude, 1, quat));
|
|
36081
|
+
const down = new Vector3(...sphericalToCartesian([
|
|
36082
|
+
0,
|
|
36083
|
+
0,
|
|
36084
|
+
0
|
|
36085
|
+
], latitude + 90, longitude, 1, quat)).negate();
|
|
36086
|
+
const range = offset.length();
|
|
36087
|
+
const level = offset.clone().addScaledVector(up, -offset.dot(up));
|
|
36088
|
+
const tilt = Math.acos(MathUtils.clamp(offset.dot(up) / range, -1, 1));
|
|
36089
|
+
const heading = Math.atan2(new Vector3().crossVectors(down, level).dot(up), down.dot(level));
|
|
36090
|
+
return {
|
|
36091
|
+
latitude,
|
|
36092
|
+
longitude,
|
|
36093
|
+
zoom: site.radius + range,
|
|
36094
|
+
look: {
|
|
36095
|
+
tilt,
|
|
36096
|
+
heading
|
|
36097
|
+
}
|
|
36098
|
+
};
|
|
36099
|
+
}
|
|
35869
36100
|
var _from = new Vector3();
|
|
36101
|
+
var _shift = new Vector3();
|
|
35870
36102
|
var _forward = new Vector3();
|
|
35871
36103
|
var _ground = new Vector3();
|
|
35872
36104
|
var FocusController = class {
|
|
@@ -35875,6 +36107,10 @@ var FocusController = class {
|
|
|
35875
36107
|
readerFocusFilter = null;
|
|
35876
36108
|
focusSets = 0;
|
|
35877
36109
|
focusedBody;
|
|
36110
|
+
subjectBody;
|
|
36111
|
+
onGround = false;
|
|
36112
|
+
subjectSite = null;
|
|
36113
|
+
placedOffSubject = false;
|
|
35878
36114
|
_tmpV3 = new Vector3();
|
|
35879
36115
|
pendingInitialView = null;
|
|
35880
36116
|
heldEpoch = -1;
|
|
@@ -35896,7 +36132,7 @@ var FocusController = class {
|
|
|
35896
36132
|
onBodyClick: (b) => this.handleFocus(b),
|
|
35897
36133
|
assignMapLayerToTrails: deps.assignMapLayerToTrails,
|
|
35898
36134
|
repositionAll: deps.repositionAll,
|
|
35899
|
-
|
|
36135
|
+
inFocus: (id) => id === this.focusedBody?.data.id || id === this.subjectBody?.data.id,
|
|
35900
36136
|
onUserPromotedChange: deps.callbacks.onUserPromotedChange,
|
|
35901
36137
|
onSystemBodies: (bodies) => deps.systemData.loadPlanets(bodies)
|
|
35902
36138
|
});
|
|
@@ -35904,6 +36140,151 @@ var FocusController = class {
|
|
|
35904
36140
|
get current() {
|
|
35905
36141
|
return this.focusedBody;
|
|
35906
36142
|
}
|
|
36143
|
+
get subject() {
|
|
36144
|
+
return this.subjectBody;
|
|
36145
|
+
}
|
|
36146
|
+
get groundView() {
|
|
36147
|
+
return this.onGround;
|
|
36148
|
+
}
|
|
36149
|
+
onGroundAt(body, jd = this.deps.clock.jd) {
|
|
36150
|
+
if (body.data.objectType !== ObjectType.SPACECRAFT) return false;
|
|
36151
|
+
const probe = this.probeRecord(body, jd);
|
|
36152
|
+
return probe && isLandedAt(probe, jd);
|
|
36153
|
+
}
|
|
36154
|
+
landedSite(body, jd = this.deps.clock.jd) {
|
|
36155
|
+
const probe = this.probeRecord(body, jd);
|
|
36156
|
+
if (!probe?.landed || !isLandedAt(probe, jd)) return void 0;
|
|
36157
|
+
const { ctx } = this.deps;
|
|
36158
|
+
const host = ctx.getBody(`naif-${probe.landed.bodyNaifId}`);
|
|
36159
|
+
const pos = ctx.place(body, jd);
|
|
36160
|
+
const hostPos = host && ctx.place(host, jd);
|
|
36161
|
+
if (!host || !pos || !hostPos) return void 0;
|
|
36162
|
+
return {
|
|
36163
|
+
host,
|
|
36164
|
+
site: surfaceSite(host, pos, hostPos, jd)
|
|
36165
|
+
};
|
|
36166
|
+
}
|
|
36167
|
+
probeRecord(body, jd) {
|
|
36168
|
+
if (body.data.objectType !== ObjectType.SPACECRAFT) return void 0;
|
|
36169
|
+
return this.deps.ctx.probeStore?.probeWithCenter(body.data.id, jd)?.probe;
|
|
36170
|
+
}
|
|
36171
|
+
followSubject(jd) {
|
|
36172
|
+
const subject = this.subjectBody;
|
|
36173
|
+
const host = this.focusedBody;
|
|
36174
|
+
const now = subject && this.landedSite(subject, jd);
|
|
36175
|
+
if (!subject || !host || !now || now.host !== host) return;
|
|
36176
|
+
const was = this.subjectSite;
|
|
36177
|
+
this.subjectSite = now.site;
|
|
36178
|
+
if (!was || !this.placedOffSubject && this.pendingInitialView) return;
|
|
36179
|
+
const q = this.focusedBodyQuat(host);
|
|
36180
|
+
const a = sphericalToCartesian([
|
|
36181
|
+
0,
|
|
36182
|
+
0,
|
|
36183
|
+
0
|
|
36184
|
+
], was.latitude, was.longitude, was.radius, q);
|
|
36185
|
+
const b = sphericalToCartesian([
|
|
36186
|
+
0,
|
|
36187
|
+
0,
|
|
36188
|
+
0
|
|
36189
|
+
], now.site.latitude, now.site.longitude, now.site.radius, q);
|
|
36190
|
+
const shift = _shift.set(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
36191
|
+
if (shift.length() < kmToScene(1e-6)) return;
|
|
36192
|
+
this.deps.controls.moveOrbit((orbit) => orbit.add(shift));
|
|
36193
|
+
const held = this.pendingInitialView;
|
|
36194
|
+
if (held) {
|
|
36195
|
+
const at = sphericalToCartesian([
|
|
36196
|
+
0,
|
|
36197
|
+
0,
|
|
36198
|
+
0
|
|
36199
|
+
], held.latitude, held.longitude, held.zoom, q);
|
|
36200
|
+
const moved = cartesianToSpherical([
|
|
36201
|
+
at[0] + shift.x,
|
|
36202
|
+
at[1] + shift.y,
|
|
36203
|
+
at[2] + shift.z
|
|
36204
|
+
], [
|
|
36205
|
+
0,
|
|
36206
|
+
0,
|
|
36207
|
+
0
|
|
36208
|
+
], q);
|
|
36209
|
+
this.pendingInitialView = {
|
|
36210
|
+
...held,
|
|
36211
|
+
latitude: moved.latitude,
|
|
36212
|
+
longitude: moved.longitude,
|
|
36213
|
+
zoom: moved.distance
|
|
36214
|
+
};
|
|
36215
|
+
}
|
|
36216
|
+
}
|
|
36217
|
+
leaveGround() {
|
|
36218
|
+
const subject = this.subjectBody;
|
|
36219
|
+
const host = this.focusedBody;
|
|
36220
|
+
const site = this.subjectSite;
|
|
36221
|
+
if (!subject || !host) return;
|
|
36222
|
+
const pos = this.place(subject);
|
|
36223
|
+
if (!pos || !site) {
|
|
36224
|
+
this.setFocusTarget(subject);
|
|
36225
|
+
return;
|
|
36226
|
+
}
|
|
36227
|
+
const seat = sphericalToCartesian([
|
|
36228
|
+
0,
|
|
36229
|
+
0,
|
|
36230
|
+
0
|
|
36231
|
+
], site.latitude, site.longitude, site.radius, siteQuat(host, this.deps.clock.jd));
|
|
36232
|
+
const cam = this.deps.camera.position;
|
|
36233
|
+
const offset = cartesianToSpherical([
|
|
36234
|
+
cam.x - seat[0],
|
|
36235
|
+
cam.y - seat[1],
|
|
36236
|
+
cam.z - seat[2]
|
|
36237
|
+
], [
|
|
36238
|
+
0,
|
|
36239
|
+
0,
|
|
36240
|
+
0
|
|
36241
|
+
]);
|
|
36242
|
+
this.settleOnBodyInstant(subject, pos);
|
|
36243
|
+
this.snapToBodyFrame(offset.latitude, offset.longitude, offset.distance);
|
|
36244
|
+
}
|
|
36245
|
+
panToSurfacePoint(host, site, height, subject) {
|
|
36246
|
+
const { focus, camera, controls, callbacks, pointClouds } = this.deps;
|
|
36247
|
+
const hostPos = this.place(host);
|
|
36248
|
+
if (!hostPos) return 0;
|
|
36249
|
+
const current = this.focusedBody;
|
|
36250
|
+
if (!(current !== void 0 && (current.data.id === host.data.id || this.landedSite(current)?.host.data.id === host.data.id)) && height !== void 0) return this.arriveAbove(host, site, height, subject);
|
|
36251
|
+
const camWorld = this.cameraTruePos();
|
|
36252
|
+
if (f64dist(focus.focusTruePos, hostPos) > 0) {
|
|
36253
|
+
focus.focusTruePos = [...hostPos];
|
|
36254
|
+
camera.position.set(camWorld[0] - hostPos[0], camWorld[1] - hostPos[1], camWorld[2] - hostPos[2]);
|
|
36255
|
+
this.deps.repositionAll();
|
|
36256
|
+
pointClouds.rebuildBasis();
|
|
36257
|
+
}
|
|
36258
|
+
this.setFocusTarget(host, void 0, subject);
|
|
36259
|
+
this.onGround = true;
|
|
36260
|
+
this.placedOffSubject = true;
|
|
36261
|
+
focus.aim = null;
|
|
36262
|
+
focus.aimLooks = false;
|
|
36263
|
+
focus.aimPose = null;
|
|
36264
|
+
const quat = siteQuat(host, this.deps.clock.jd);
|
|
36265
|
+
const ground = new Vector3(...sphericalToCartesian([
|
|
36266
|
+
0,
|
|
36267
|
+
0,
|
|
36268
|
+
0
|
|
36269
|
+
], site.latitude, site.longitude, site.radius, quat));
|
|
36270
|
+
const from = _from.set(camWorld[0] - hostPos[0], camWorld[1] - hostPos[1], camWorld[2] - hostPos[2]);
|
|
36271
|
+
if (controls.looksOver(from, ground)) {
|
|
36272
|
+
focus.aimPose = controls.lookPose(from, ground, new Quaternion());
|
|
36273
|
+
focus.aim = [
|
|
36274
|
+
ground.x,
|
|
36275
|
+
ground.y,
|
|
36276
|
+
ground.z
|
|
36277
|
+
];
|
|
36278
|
+
focus.aimLooks = true;
|
|
36279
|
+
focus.focusDurationMs = angularDuration(camera.quaternion.angleTo(focus.aimPose), FOCUS_ROT_PACING);
|
|
36280
|
+
return focus.focusDurationMs;
|
|
36281
|
+
}
|
|
36282
|
+
const distance = from.length();
|
|
36283
|
+
callbacks.onCameraPosition?.(site.latitude, site.longitude, distance);
|
|
36284
|
+
const camPos = sphericalToCartesian([...hostPos], site.latitude, site.longitude, distance, quat);
|
|
36285
|
+
prepareFlyToCamera(focus, camera, camWorld, camPos, sceneSettings().resolvedReducedMotion);
|
|
36286
|
+
return focus.focusDurationMs;
|
|
36287
|
+
}
|
|
35907
36288
|
get focusChanges() {
|
|
35908
36289
|
return this.focusSets;
|
|
35909
36290
|
}
|
|
@@ -35946,12 +36327,12 @@ var FocusController = class {
|
|
|
35946
36327
|
];
|
|
35947
36328
|
}
|
|
35948
36329
|
holdsModel(id) {
|
|
35949
|
-
|
|
35950
|
-
return id === (focused && (isSurfaceFeature(focused) ? focused.featureAnchor.hostId : focused.data.id)) || this.upgradeTargetIds.has(id);
|
|
36330
|
+
return id === this.focusedBody?.data.id || id === this.subjectBody?.data.id || this.upgradeTargetIds.has(id);
|
|
35951
36331
|
}
|
|
35952
36332
|
syncUpgradeTargets(body) {
|
|
35953
36333
|
const { ctx, scene, clickables, meshToBody, bodyObjects, pointClouds, clock, loadTexture, assignMapLayerToTrails } = this.deps;
|
|
35954
36334
|
const targets = upgradeTargets(body, ctx);
|
|
36335
|
+
if (this.subjectBody && !targets.includes(this.subjectBody)) targets.push(this.subjectBody);
|
|
35955
36336
|
const newIds = new Set(targets.map((t) => t.data.id));
|
|
35956
36337
|
for (const id of this.upgradeTargetIds) {
|
|
35957
36338
|
if (newIds.has(id)) continue;
|
|
@@ -36011,6 +36392,8 @@ var FocusController = class {
|
|
|
36011
36392
|
];
|
|
36012
36393
|
}
|
|
36013
36394
|
this.focusedBody = void 0;
|
|
36395
|
+
this.subjectBody = void 0;
|
|
36396
|
+
this.onGround = false;
|
|
36014
36397
|
this.promotion.emitUserPromotedCount();
|
|
36015
36398
|
prepareFocusTarget(focus, [...position], camera, camWorld, camPos, sceneSettings().resolvedReducedMotion);
|
|
36016
36399
|
const spherical = cartesianToSpherical(camPos ?? camWorld, position, void 0);
|
|
@@ -36051,8 +36434,13 @@ var FocusController = class {
|
|
|
36051
36434
|
}
|
|
36052
36435
|
handleFocus(body) {
|
|
36053
36436
|
if (this.readerFocusFilter && !this.readerFocusFilter(body)) return;
|
|
36054
|
-
if (this.focusedBody?.data.id === body.data.id && !this.deps.focus.aim) {
|
|
36055
|
-
this.deps.callbacks.onFocusChange(body);
|
|
36437
|
+
if ((this.subjectBody ?? this.focusedBody)?.data.id === body.data.id && !this.deps.focus.aim) {
|
|
36438
|
+
this.deps.callbacks.onFocusChange(body, this.focusedBody);
|
|
36439
|
+
return;
|
|
36440
|
+
}
|
|
36441
|
+
const landed = this.landedSite(body);
|
|
36442
|
+
if (landed) {
|
|
36443
|
+
this.panToSurfacePoint(landed.host, landed.site, void 0, body);
|
|
36056
36444
|
return;
|
|
36057
36445
|
}
|
|
36058
36446
|
this.setFocusTarget(body);
|
|
@@ -36062,36 +36450,28 @@ var FocusController = class {
|
|
|
36062
36450
|
const { latitude, longitude, distance } = cartesianToSpherical(camWorld, pos, this.focusedBodyQuat(body));
|
|
36063
36451
|
this.deps.callbacks.onCameraPosition?.(latitude, longitude, distance);
|
|
36064
36452
|
}
|
|
36065
|
-
setFocusTarget(body, camPos) {
|
|
36453
|
+
setFocusTarget(body, camPos, subject) {
|
|
36066
36454
|
const { ctx, bodyObjects, callbacks, focus, camera, systemData, loadTexture } = this.deps;
|
|
36067
36455
|
this.focusSets++;
|
|
36068
|
-
|
|
36069
|
-
|
|
36456
|
+
this.subjectBody = subject;
|
|
36457
|
+
this.subjectSite = (subject && this.landedSite(subject)?.site) ?? null;
|
|
36458
|
+
this.placedOffSubject = false;
|
|
36459
|
+
this.onGround = false;
|
|
36460
|
+
const drawsItself = !isExtrasolar(body) && !isExoplanet(body);
|
|
36461
|
+
this.promotion.ensureBodyObjects(body);
|
|
36070
36462
|
const prev = this.focusedBody;
|
|
36071
|
-
const
|
|
36072
|
-
const newNomBodyId = nomenclatureBodyId(body, bodyObjects);
|
|
36073
|
-
const prevModelId = prev && (isSurfaceFeature(prev) ? prev.featureAnchor.hostId : prev.data.id);
|
|
36074
|
-
const newModelId = isSurfaceFeature(body) ? body.featureAnchor.hostId : body.data.id;
|
|
36463
|
+
const prevId = prev?.data.id;
|
|
36075
36464
|
const newTargetIds = this.syncUpgradeTargets(body);
|
|
36076
|
-
if (
|
|
36077
|
-
const prevBo = bodyObjects.get(
|
|
36078
|
-
if (prevBo) unloadBodyModel(prevBo);
|
|
36079
|
-
|
|
36080
|
-
if (prevNomBodyId && prevNomBodyId !== newNomBodyId) {
|
|
36081
|
-
const prevNomBo = bodyObjects.get(prevNomBodyId);
|
|
36082
|
-
if (prevNomBo) disposeNomenclatureLabels(prevNomBo);
|
|
36465
|
+
if (prevId && prevId !== body.data.id) {
|
|
36466
|
+
const prevBo = bodyObjects.get(prevId);
|
|
36467
|
+
if (prevBo && !newTargetIds.has(prevId)) unloadBodyModel(prevBo);
|
|
36468
|
+
if (prevBo) disposeNomenclatureLabels(prevBo);
|
|
36083
36469
|
}
|
|
36084
36470
|
if (body.data.id !== prev?.data.id) this.pendingInitialView = null;
|
|
36085
36471
|
this.focusedBody = body;
|
|
36086
|
-
|
|
36087
|
-
|
|
36088
|
-
ctx.visibility.setFocused(featureHost ?? body);
|
|
36089
|
-
callbacks.onFocusChange(body);
|
|
36472
|
+
ctx.visibility.setFocused(body, subject);
|
|
36473
|
+
callbacks.onFocusChange(subject ?? body, body);
|
|
36090
36474
|
if (drawsItself) loadTexture(body);
|
|
36091
|
-
if (newNomBodyId && newNomBodyId !== body.data.id) {
|
|
36092
|
-
const landingBody = ctx.getBody(newNomBodyId);
|
|
36093
|
-
if (landingBody) loadTexture(landingBody);
|
|
36094
|
-
}
|
|
36095
36475
|
systemData.syncToFocus();
|
|
36096
36476
|
const pos = this.place(body);
|
|
36097
36477
|
if (pos) {
|
|
@@ -36109,6 +36489,19 @@ var FocusController = class {
|
|
|
36109
36489
|
this.setFocusTarget(body);
|
|
36110
36490
|
return 0;
|
|
36111
36491
|
}
|
|
36492
|
+
const landed = this.landedSite(body);
|
|
36493
|
+
if (landed) {
|
|
36494
|
+
const { host, site } = landed;
|
|
36495
|
+
if (zoom === void 0 || underHalfRadius(host, zoom)) return this.panToSurfacePoint(host, site, zoom, body);
|
|
36496
|
+
const view = {
|
|
36497
|
+
latitude: latitude ?? site.latitude,
|
|
36498
|
+
longitude: longitude ?? site.longitude
|
|
36499
|
+
};
|
|
36500
|
+
return this.flyOntoGround(host, {
|
|
36501
|
+
...view,
|
|
36502
|
+
zoom
|
|
36503
|
+
}, body);
|
|
36504
|
+
}
|
|
36112
36505
|
let camPos;
|
|
36113
36506
|
if (zoom !== void 0) {
|
|
36114
36507
|
if (latitude !== void 0 && longitude !== void 0) camPos = sphericalToCartesian(pos, latitude, longitude, zoom, this.focusedBodyQuat(body));
|
|
@@ -36127,7 +36520,7 @@ var FocusController = class {
|
|
|
36127
36520
|
callbacks.onCameraPosition?.(spherical.latitude, spherical.longitude, spherical.distance);
|
|
36128
36521
|
if (zoom !== void 0 && camPos) {
|
|
36129
36522
|
this.pendingInitialView = null;
|
|
36130
|
-
if (this.focusedBody?.data.id === id && f64dist(focus.focusTruePos, pos) < minCameraDistance(body)) {
|
|
36523
|
+
if (this.focusedBody?.data.id === id && !this.subjectBody && !this.onGround && f64dist(focus.focusTruePos, pos) < minCameraDistance(body)) {
|
|
36131
36524
|
focus.focusTruePos = [...pos];
|
|
36132
36525
|
this.deps.repositionAll();
|
|
36133
36526
|
pointClouds.rebuildBasis();
|
|
@@ -36143,9 +36536,55 @@ var FocusController = class {
|
|
|
36143
36536
|
const body = this.deps.ctx.getBody(id);
|
|
36144
36537
|
const pos = body && this.place(body);
|
|
36145
36538
|
if (!body || !pos) return;
|
|
36539
|
+
const landed = this.landedSite(body);
|
|
36540
|
+
if (landed) {
|
|
36541
|
+
const { host, site } = landed;
|
|
36542
|
+
if (underHalfRadius(host, zoom)) this.arriveAbove(host, site, zoom, body, true, look);
|
|
36543
|
+
else this.snapOntoGround(host, {
|
|
36544
|
+
latitude,
|
|
36545
|
+
longitude,
|
|
36546
|
+
zoom,
|
|
36547
|
+
look
|
|
36548
|
+
}, body);
|
|
36549
|
+
return;
|
|
36550
|
+
}
|
|
36146
36551
|
this.settleOnBodyInstant(body, pos);
|
|
36147
36552
|
this.snapToBodyFrame(latitude, longitude, zoom, look);
|
|
36148
36553
|
}
|
|
36554
|
+
arriveAbove(host, site, height, subject, instant = false, look = LEVEL_LOOK) {
|
|
36555
|
+
const view = {
|
|
36556
|
+
latitude: site.latitude,
|
|
36557
|
+
longitude: site.longitude,
|
|
36558
|
+
zoom: site.radius + height
|
|
36559
|
+
};
|
|
36560
|
+
if (!instant) return this.flyOntoGround(host, view, subject);
|
|
36561
|
+
this.snapOntoGround(host, {
|
|
36562
|
+
...view,
|
|
36563
|
+
look
|
|
36564
|
+
}, subject);
|
|
36565
|
+
this.placedOffSubject = true;
|
|
36566
|
+
return 0;
|
|
36567
|
+
}
|
|
36568
|
+
flyOntoGround(host, view, subject) {
|
|
36569
|
+
const { focus, callbacks } = this.deps;
|
|
36570
|
+
const hostPos = this.place(host);
|
|
36571
|
+
if (!hostPos) return 0;
|
|
36572
|
+
const camPos = sphericalToCartesian([...hostPos], view.latitude, view.longitude, view.zoom, siteQuat(host, this.deps.clock.jd));
|
|
36573
|
+
callbacks.onCameraPosition?.(view.latitude, view.longitude, view.zoom);
|
|
36574
|
+
this.pendingInitialView = null;
|
|
36575
|
+
this.setFocusTarget(host, camPos, subject);
|
|
36576
|
+
focus.orbitFly = true;
|
|
36577
|
+
this.onGround = true;
|
|
36578
|
+
this.placedOffSubject = true;
|
|
36579
|
+
return focus.focusDurationMs;
|
|
36580
|
+
}
|
|
36581
|
+
snapOntoGround(host, view, subject) {
|
|
36582
|
+
const pos = this.place(host);
|
|
36583
|
+
if (!pos) return;
|
|
36584
|
+
this.settleOnBodyInstant(host, pos, subject);
|
|
36585
|
+
this.snapToBodyFrame(view.latitude, view.longitude, view.zoom, view.look);
|
|
36586
|
+
this.onGround = true;
|
|
36587
|
+
}
|
|
36149
36588
|
snapToBodyFacing(id, towardId, elevationDeg, distance) {
|
|
36150
36589
|
const { ctx, camera, controls, callbacks } = this.deps;
|
|
36151
36590
|
const body = ctx.getBody(id);
|
|
@@ -36190,9 +36629,9 @@ var FocusController = class {
|
|
|
36190
36629
|
callbacks.onCameraPosition?.(settled.latitude, settled.longitude, settled.distance);
|
|
36191
36630
|
this.pendingInitialView = null;
|
|
36192
36631
|
}
|
|
36193
|
-
settleOnBodyInstant(body, pos) {
|
|
36632
|
+
settleOnBodyInstant(body, pos, subject) {
|
|
36194
36633
|
const { focus, pointClouds } = this.deps;
|
|
36195
|
-
this.setFocusTarget(body);
|
|
36634
|
+
this.setFocusTarget(body, void 0, subject);
|
|
36196
36635
|
focus.focusTruePos = [...pos];
|
|
36197
36636
|
focus.focusOriginWorld = [...pos];
|
|
36198
36637
|
focus.focusTargetWorld = [...pos];
|
|
@@ -36203,6 +36642,10 @@ var FocusController = class {
|
|
|
36203
36642
|
focus.orbitFly = false;
|
|
36204
36643
|
focus.arcOrbit = false;
|
|
36205
36644
|
focus.cameraStaysOnBody = false;
|
|
36645
|
+
focus.aim = null;
|
|
36646
|
+
focus.aimLooks = false;
|
|
36647
|
+
focus.aimPose = null;
|
|
36648
|
+
focus.leavesAim = false;
|
|
36206
36649
|
this.deps.repositionAll();
|
|
36207
36650
|
pointClouds.rebuildBasis();
|
|
36208
36651
|
}
|
|
@@ -36272,10 +36715,6 @@ function framesInBodyAxes(b) {
|
|
|
36272
36715
|
}
|
|
36273
36716
|
function upgradeTargets(focus, ctx) {
|
|
36274
36717
|
if (!focus) return [];
|
|
36275
|
-
if (isSurfaceFeature(focus)) {
|
|
36276
|
-
const host = ctx.getBody(focus.featureAnchor.hostId);
|
|
36277
|
-
return host && isMeshUpgradable(host) ? [host] : [];
|
|
36278
|
-
}
|
|
36279
36718
|
const out = [];
|
|
36280
36719
|
if (isMeshUpgradable(focus)) out.push(focus);
|
|
36281
36720
|
if (focus.data.objectType === ObjectType.MOON || focus.data.orbitalSource === OrbitalSource.SPICE_PROBE) {
|
|
@@ -36736,7 +37175,7 @@ var SPHERE_GROUND = {
|
|
|
36736
37175
|
radiusKm: () => null
|
|
36737
37176
|
};
|
|
36738
37177
|
var _toCamera = new Vector3();
|
|
36739
|
-
function cameraMotionScale(camera, focusTruePos, focused, parent,
|
|
37178
|
+
function cameraMotionScale(camera, focusTruePos, focused, parent, position = camera.position, ground = SPHERE_GROUND) {
|
|
36740
37179
|
const orbitRadius = position.length();
|
|
36741
37180
|
if (!(orbitRadius > 0)) return {
|
|
36742
37181
|
rotate: 1,
|
|
@@ -36747,7 +37186,7 @@ function cameraMotionScale(camera, focusTruePos, focused, parent, seated, positi
|
|
|
36747
37186
|
const floor = focusRadius > 0 ? kmToScene(ground.clearanceKm(sized)) : 0;
|
|
36748
37187
|
let clearance = orbitRadius;
|
|
36749
37188
|
let height = Math.max(orbitRadius - focusRadius, floor);
|
|
36750
|
-
for (const body of [sized,
|
|
37189
|
+
for (const body of [sized, parent]) {
|
|
36751
37190
|
const at = body?.position;
|
|
36752
37191
|
if (!body || !at) continue;
|
|
36753
37192
|
if (!(effectiveRadiusKm(body.data) > 0)) continue;
|
|
@@ -36822,7 +37261,6 @@ var TIGHT_FAR_RELEASE = 2.3;
|
|
|
36822
37261
|
var SUN_PROXY_FAR_FRACTION = .9;
|
|
36823
37262
|
var _sunLiftDir = new Vector3();
|
|
36824
37263
|
var _lookDir = new Vector3();
|
|
36825
|
-
var _lookUp = new Vector3();
|
|
36826
37264
|
var SPIN_FOLLOW_NONE = 2;
|
|
36827
37265
|
var _spinNow = new Quaternion();
|
|
36828
37266
|
var _spinStep = new Quaternion();
|
|
@@ -36985,7 +37423,6 @@ var SceneRenderer = class SceneRenderer {
|
|
|
36985
37423
|
};
|
|
36986
37424
|
viewportH = 1;
|
|
36987
37425
|
tier = currentRenderTier();
|
|
36988
|
-
landedNomBodyId = null;
|
|
36989
37426
|
rafId = 0;
|
|
36990
37427
|
paused = false;
|
|
36991
37428
|
covered = false;
|
|
@@ -37091,7 +37528,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37091
37528
|
const dust = new StarDust(this.renderer, dustPlan(), this.invalidate);
|
|
37092
37529
|
this.starfield = new StarfieldSystem(ctx, this.scene, starBudget(), this.invalidate, this.pointClouds.pickRegistry, dust, new GlowSky(this.renderer, this.scene, glowPlan(), dust, this.invalidate, () => this.skyboxSource(), new StarlessSky(loadStarlessSky, this.invalidate)));
|
|
37093
37530
|
this.constellations = new ConstellationSystem(ctx, this.scene, SceneRenderer.MAP_LAYER, this.invalidate, canvas, (slug, figure, name) => this.callbacks.onConstellationSelect?.(slug, figure, name), (direction, instant) => this.aimAt(direction, instant), () => this.focus.camOriginWorld !== null);
|
|
37094
|
-
this.controls = new LookOrbitControls(this.camera, canvas, this.lookSurfaceRadius,
|
|
37531
|
+
this.controls = new LookOrbitControls(this.camera, canvas, this.lookSurfaceRadius, () => this.pendingUrlWrite = true);
|
|
37095
37532
|
this.controls.enableDamping = true;
|
|
37096
37533
|
this.orbitDampingFactor = orbitDamping(sceneSettings().resolvedReducedMotion);
|
|
37097
37534
|
Object.defineProperty(this.controls, "minDistance", { get: () => this.minCameraDistance() });
|
|
@@ -37112,7 +37549,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37112
37549
|
}
|
|
37113
37550
|
this.invalidate();
|
|
37114
37551
|
});
|
|
37115
|
-
this.cameraUp = new CameraUpController(this.camera, this.controls, ctx
|
|
37552
|
+
this.cameraUp = new CameraUpController(this.camera, this.controls, ctx);
|
|
37116
37553
|
this.systemData = new SystemDataLoader(this.scene, ctx, this.renderer, this.textureLoader, this.bodyObjects, clock, () => {
|
|
37117
37554
|
this.focusController.reapplyInitialViewIfPending();
|
|
37118
37555
|
this.invalidate();
|
|
@@ -37165,7 +37602,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37165
37602
|
ctx.visibility.updateCamera(framing.zoom, this.clock.jd);
|
|
37166
37603
|
this.viewOpen = !ctx.loading;
|
|
37167
37604
|
this.updateSystemShare(0);
|
|
37168
|
-
callbacks.onFocusChange(focusBody);
|
|
37605
|
+
callbacks.onFocusChange(focusBody, focusBody);
|
|
37169
37606
|
this.buildScene();
|
|
37170
37607
|
if (focusBody) this.focusController.promotion.ensureBodyObjects(focusBody);
|
|
37171
37608
|
if (focusBody) this.focusController.syncUpgradeTargets(focusBody);
|
|
@@ -37176,6 +37613,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37176
37613
|
this.gpuPick = new GpuPickPass(this.renderer, this.camera);
|
|
37177
37614
|
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.ctx.visibility.planetarySystemShare() === 0 ? this.starfield.pickDraws() : [], (pickId) => this.pickStar(pickId));
|
|
37178
37615
|
this.pointerInteraction.attach();
|
|
37616
|
+
if (focusBody && this.focusController.landedSite(focusBody)) this.focusController.snapToBody(focusBody.data.id, framing.latitude, framing.longitude, framing.zoom, framing.look);
|
|
37179
37617
|
this.tick();
|
|
37180
37618
|
}
|
|
37181
37619
|
buildScene() {
|
|
@@ -37450,6 +37888,9 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37450
37888
|
at[1] + offset[1],
|
|
37451
37889
|
at[2] + offset[2]
|
|
37452
37890
|
];
|
|
37891
|
+
const host = this.focusController.landedSite(body, this.sceneJd)?.host;
|
|
37892
|
+
const hostAt = host && this.whereBody(host);
|
|
37893
|
+
if (host && hostAt) return cartesianToSpherical(camera, hostAt, siteQuat(host, this.sceneJd));
|
|
37453
37894
|
return cartesianToSpherical(camera, at, this.focusController.focusedBodyQuat(body));
|
|
37454
37895
|
}
|
|
37455
37896
|
where(id) {
|
|
@@ -37496,7 +37937,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37496
37937
|
this.controls.target.set(0, 0, 0);
|
|
37497
37938
|
this.controls.update();
|
|
37498
37939
|
}
|
|
37499
|
-
this.coverageWatch?.sync(this.focusController.current, this.clock.jd);
|
|
37940
|
+
this.coverageWatch?.sync(this.focusController.subject ?? this.focusController.current, this.clock.jd);
|
|
37500
37941
|
this.clock.tick(performance.now());
|
|
37501
37942
|
if (!this.shouldRender(nowMs)) {
|
|
37502
37943
|
this.controls.update();
|
|
@@ -37522,13 +37963,14 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37522
37963
|
if (!this.dateHeld() && !this.seekAwaitsData) this.clock.placed(this.seenJumps);
|
|
37523
37964
|
this.refreshTravelFocus();
|
|
37524
37965
|
this.callbacks.onFrame?.(this.sceneJd, renderedDtMs);
|
|
37966
|
+
this.followLanding(nowMs);
|
|
37525
37967
|
this.followSpin(nowMs);
|
|
37526
37968
|
const controlsSettled = this.holdingCamera ? this.applyHeldCamera() : stepFocusAnimation(this.focus, this.camera, this.controls, () => this.repositionAll(), () => this.pointClouds.rebuildBasis());
|
|
37527
37969
|
this.applyReaderLimits(nowMs);
|
|
37528
37970
|
const near = this.nearSurfaces();
|
|
37529
37971
|
if (near) {
|
|
37530
37972
|
this.clampToSurfaces(near);
|
|
37531
|
-
this.setMotionScale(cameraMotionScale(this.camera, this.focus.focusTruePos, near.focused, near.parent,
|
|
37973
|
+
this.setMotionScale(cameraMotionScale(this.camera, this.focus.focusTruePos, near.focused, near.parent, this.controls.orbitPosition, this.motionGround));
|
|
37532
37974
|
} else this.setMotionScale({
|
|
37533
37975
|
rotate: 1,
|
|
37534
37976
|
translate: 1
|
|
@@ -37587,7 +38029,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37587
38029
|
}
|
|
37588
38030
|
for (const light of this.ambientLights) light.intensity = ambient;
|
|
37589
38031
|
updateUserLocationOcclusion(this.userLocationMarker, this.bodyObjects, this.camera);
|
|
37590
|
-
const focusedIdLod =
|
|
38032
|
+
const focusedIdLod = this.focusController.current?.data.id;
|
|
37591
38033
|
updateTextureLOD(this.bodyObjects, this.camera, this.renderer, this.ctx, this.textureLoader, focusedIdLod, this.sceneJd, this.appearances, this.invalidate);
|
|
37592
38034
|
updateSphereLOD(this.bodyObjects, this.camera, this.renderer, this.ctx, focusedIdLod, this.invalidate);
|
|
37593
38035
|
updateSunShadowLight(this.bodyObjects, this.focus.focusTruePos, this.ctx, this.shadowLight, starPointLight, distance, this._tmpV3, sceneSettings().realisticLighting && this.starLight.starId === "naif-10", this.sunIntensityScale);
|
|
@@ -37644,6 +38086,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37644
38086
|
if (!body) return POINT_MIN_DISTANCE;
|
|
37645
38087
|
const bo = this.bodyObjects.get(body.data.id);
|
|
37646
38088
|
const lowest = bo && (modelMinRadiusKm(bo) ?? reliefRadiiKm(bo)?.min ?? smallestRadiusKm(bo));
|
|
38089
|
+
if (this.focusController.groundView) return kmToScene((lowest ?? effectiveRadiusKm(body.data)) + LANDED_KEEP_AWAY_KM);
|
|
37647
38090
|
return minCameraDistance(body, lowest, bo && finestTexelKm(bo));
|
|
37648
38091
|
}
|
|
37649
38092
|
clearanceKm(body) {
|
|
@@ -37651,7 +38094,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37651
38094
|
return surfaceClearanceKm(body, bo && finestTexelKm(bo));
|
|
37652
38095
|
}
|
|
37653
38096
|
followSpin(nowMs) {
|
|
37654
|
-
const body = this.
|
|
38097
|
+
const body = this.focusController.current;
|
|
37655
38098
|
const flying = nowMs - this.focus.focusStartTime < this.focus.focusDurationMs;
|
|
37656
38099
|
if (!body?.orientation || flying || this.holdingCamera || this.focus.aim) {
|
|
37657
38100
|
this.spinFrom = null;
|
|
@@ -37665,16 +38108,26 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37665
38108
|
};
|
|
37666
38109
|
if (!from || from.id !== body.data.id) return;
|
|
37667
38110
|
const radiusKm = effectiveRadiusKm(body.data);
|
|
37668
|
-
const height = sceneToKm(this.controls.orbitPosition.length()) / radiusKm -
|
|
38111
|
+
const height = sceneToKm(this.controls.orbitPosition.length()) / radiusKm - 1;
|
|
37669
38112
|
const t = MathUtils.clamp((SPIN_FOLLOW_NONE - height) / 1.5, 0, 1);
|
|
37670
38113
|
const share = t * t * (3 - 2 * t);
|
|
37671
38114
|
if (share === 0) return;
|
|
37672
38115
|
_spinStep.copy(_spinNow).multiply(from.quat.invert());
|
|
37673
38116
|
this.controls.carry(_noTurn.identity().slerp(_spinStep, share));
|
|
37674
38117
|
}
|
|
37675
|
-
|
|
37676
|
-
|
|
37677
|
-
|
|
38118
|
+
followLanding(nowMs) {
|
|
38119
|
+
if (nowMs - this.focus.focusStartTime < this.focus.focusDurationMs || this.holdingCamera || this.dateHeld()) return;
|
|
38120
|
+
const fc = this.focusController;
|
|
38121
|
+
const subject = fc.subject;
|
|
38122
|
+
if (subject) {
|
|
38123
|
+
const onGround = fc.onGroundAt(subject);
|
|
38124
|
+
if (onGround === false) fc.leaveGround();
|
|
38125
|
+
else if (onGround) fc.followSubject(this.sceneJd);
|
|
38126
|
+
return;
|
|
38127
|
+
}
|
|
38128
|
+
const current = fc.current;
|
|
38129
|
+
const landed = current && fc.landedSite(current);
|
|
38130
|
+
if (landed) fc.panToSurfacePoint(landed.host, landed.site, void 0, current);
|
|
37678
38131
|
}
|
|
37679
38132
|
settleCamera() {
|
|
37680
38133
|
this.settleLook();
|
|
@@ -37692,22 +38145,23 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37692
38145
|
return {
|
|
37693
38146
|
focused,
|
|
37694
38147
|
parent: parentId ? this.ctx.getBody(parentId) : void 0,
|
|
37695
|
-
|
|
38148
|
+
onGround: this.focusController.groundView
|
|
37696
38149
|
};
|
|
37697
38150
|
}
|
|
37698
|
-
clampToSurfaces({ focused, parent,
|
|
38151
|
+
clampToSurfaces({ focused, parent, onGround }) {
|
|
37699
38152
|
const { camera } = this;
|
|
37700
38153
|
const at = this.focus.focusTruePos;
|
|
38154
|
+
const own = parent?.data.id === focused.data.id;
|
|
37701
38155
|
if (parent) {
|
|
37702
|
-
const surface = this.surfaceClamp(parent,
|
|
38156
|
+
const surface = this.surfaceClamp(parent, own && onGround);
|
|
37703
38157
|
clampCameraOutsideBody(camera, parent, at, surface, this.clearanceKm(parent));
|
|
37704
38158
|
}
|
|
37705
|
-
if (
|
|
37706
|
-
const surface = this.surfaceClamp(focused,
|
|
38159
|
+
if (own) return;
|
|
38160
|
+
const surface = this.surfaceClamp(focused, onGround);
|
|
37707
38161
|
if (surface) clampCameraOutsideBody(camera, focused, at, surface, this.clearanceKm(focused));
|
|
37708
38162
|
}
|
|
37709
38163
|
motionGround = {
|
|
37710
|
-
clearanceKm: (body) => this.clearanceKm(body),
|
|
38164
|
+
clearanceKm: (body) => this.focusController.groundView && body === this.focusController.current ? LANDED_KEEP_AWAY_KM : this.clearanceKm(body),
|
|
37711
38165
|
radiusKm: (body, direction) => {
|
|
37712
38166
|
const surface = this.surfaceClamp(body, false);
|
|
37713
38167
|
if (!surface) return null;
|
|
@@ -37783,20 +38237,10 @@ var SceneRenderer = class SceneRenderer {
|
|
|
37783
38237
|
}
|
|
37784
38238
|
updateTightFar(distance) {
|
|
37785
38239
|
if (isReversedDepth()) return;
|
|
37786
|
-
const
|
|
37787
|
-
const
|
|
37788
|
-
const anchorBo = anchorId ? this.bodyObjects.get(anchorId) : void 0;
|
|
37789
|
-
const radius = anchorBo?.radiusScene ?? 0;
|
|
37790
|
-
let dist = distance;
|
|
37791
|
-
const anchorAt = anchorBo?.body.position;
|
|
37792
|
-
if (focused && anchorAt && anchorId !== focused.data.id) {
|
|
37793
|
-
const [fx, fy, fz] = this.focus.focusTruePos;
|
|
37794
|
-
const [bx, by, bz] = anchorAt;
|
|
37795
|
-
const cam = this.camera.position;
|
|
37796
|
-
dist = Math.hypot(fx + cam.x - bx, fy + cam.y - by, fz + cam.z - bz);
|
|
37797
|
-
}
|
|
38240
|
+
const id = this.focusController.current?.data.id;
|
|
38241
|
+
const radius = id && this.bodyObjects.get(id)?.radiusScene || 0;
|
|
37798
38242
|
const bound = this.tightFar ? TIGHT_FAR_RELEASE : TIGHT_FAR_ENGAGE;
|
|
37799
|
-
this.tightFar = radius > 0 && this.ctx.visibility.activeSystemId !== null &&
|
|
38243
|
+
this.tightFar = radius > 0 && this.ctx.visibility.activeSystemId !== null && distance < radius * bound;
|
|
37800
38244
|
}
|
|
37801
38245
|
updateDepthFar() {
|
|
37802
38246
|
if (isReversedDepth()) return;
|
|
@@ -38232,31 +38676,11 @@ var SceneRenderer = class SceneRenderer {
|
|
|
38232
38676
|
lookSurfaceRadius = (direction) => {
|
|
38233
38677
|
const focused = this.focusController.current;
|
|
38234
38678
|
if (this.holdingCamera || this.focus.aim || !focused) return null;
|
|
38235
|
-
if (this.standingOn(focused)) return 0;
|
|
38236
38679
|
const bo = this.bodyObjects.get(focused.data.id);
|
|
38237
38680
|
if (isModelBearing(focused) || !(bo?.mesh || hasModelSurface(bo))) return null;
|
|
38238
38681
|
const radiusKm = effectiveRadiusKm(focused.data);
|
|
38239
38682
|
return kmToScene(this.motionGround.radiusKm(focused, direction) ?? radiusKm);
|
|
38240
38683
|
};
|
|
38241
|
-
standingOn(focused) {
|
|
38242
|
-
if (isSurfaceFeature(focused)) return this.ctx.getBody(focused.featureAnchor.hostId);
|
|
38243
|
-
if (!this.bodyObjects.get(focused.data.id)?.isLanded) return void 0;
|
|
38244
|
-
const parentId = collisionParentId(focused.data.parentId);
|
|
38245
|
-
return parentId ? this.ctx.getBody(parentId) : void 0;
|
|
38246
|
-
}
|
|
38247
|
-
standingHeight = () => {
|
|
38248
|
-
const focused = this.focusController.current;
|
|
38249
|
-
const host = focused && this.standingOn(focused);
|
|
38250
|
-
const at = host?.position;
|
|
38251
|
-
if (!host || !at) return null;
|
|
38252
|
-
const fp = this.focus.focusTruePos;
|
|
38253
|
-
const cam = this.controls.orbitPosition;
|
|
38254
|
-
const up = _lookUp.set(cam.x + fp[0] - at[0], cam.y + fp[1] - at[1], cam.z + fp[2] - at[2]);
|
|
38255
|
-
const dist = up.length();
|
|
38256
|
-
const groundKm = this.motionGround.radiusKm(host, up.divideScalar(dist));
|
|
38257
|
-
const ground = kmToScene(groundKm ?? effectiveRadiusKm(host.data));
|
|
38258
|
-
return ground > 0 ? (dist - ground) / ground : null;
|
|
38259
|
-
};
|
|
38260
38684
|
onControlsEnd = () => {
|
|
38261
38685
|
this.pendingUrlWrite = true;
|
|
38262
38686
|
this.focusController.clearPendingInitialView();
|
|
@@ -38303,26 +38727,17 @@ var SceneRenderer = class SceneRenderer {
|
|
|
38303
38727
|
}
|
|
38304
38728
|
setSelectedFeature(featureId) {
|
|
38305
38729
|
this.selectedFeatureId = featureId;
|
|
38306
|
-
const nomId =
|
|
38730
|
+
const nomId = this.focusController.current?.data.id;
|
|
38307
38731
|
const bo = nomId ? this.bodyObjects.get(nomId) : void 0;
|
|
38308
38732
|
if (bo) setActiveFeatureLabel(bo, featureId);
|
|
38309
38733
|
}
|
|
38310
|
-
syncLandedNomenclature() {
|
|
38311
|
-
const focused = this.focusController.current;
|
|
38312
|
-
const landingId = (focused ? this.bodyObjects.get(focused.data.id) : void 0)?.isLanded ? focused.data.parentId : null;
|
|
38313
|
-
if (landingId === this.landedNomBodyId) return;
|
|
38314
|
-
this.landedNomBodyId = landingId;
|
|
38315
|
-
if (!landingId) return;
|
|
38316
|
-
const landingBody = this.ctx.getBody(landingId);
|
|
38317
|
-
if (landingBody) this.maybeLoadTexture(landingBody);
|
|
38318
|
-
}
|
|
38319
38734
|
clearUserPromoted() {
|
|
38320
38735
|
this.focusController.promotion.clearUserPromoted();
|
|
38321
38736
|
}
|
|
38322
38737
|
focusedSeatConfigKey() {
|
|
38323
|
-
const focused = this.focusController.current;
|
|
38738
|
+
const focused = this.focusController.subject ?? this.focusController.current;
|
|
38324
38739
|
if (!focused) return null;
|
|
38325
|
-
if (focused.data.objectType !== ObjectType.SPACECRAFT
|
|
38740
|
+
if (focused.data.objectType !== ObjectType.SPACECRAFT) return null;
|
|
38326
38741
|
const parentId = collisionParentId(focused.data.parentId);
|
|
38327
38742
|
const bo = parentId ? this.bodyObjects.get(parentId) : void 0;
|
|
38328
38743
|
if (!bo) return null;
|
|
@@ -38436,7 +38851,6 @@ var SceneRenderer = class SceneRenderer {
|
|
|
38436
38851
|
this.repositionBodies();
|
|
38437
38852
|
this.pointClouds.maybeRebase();
|
|
38438
38853
|
}
|
|
38439
|
-
this.syncLandedNomenclature();
|
|
38440
38854
|
this.seekAwaitsData = seeked && result.focusLoading;
|
|
38441
38855
|
const losingPlace = result.focusUnplaced && !this.focusWasOutOfRange;
|
|
38442
38856
|
this.focusWasOutOfRange = result.focusUnplaced;
|
|
@@ -38454,83 +38868,32 @@ var SceneRenderer = class SceneRenderer {
|
|
|
38454
38868
|
this.focusWasOutOfRange = false;
|
|
38455
38869
|
return this.focusController.focusOnBody(id, zoom, latitude, longitude);
|
|
38456
38870
|
}
|
|
38457
|
-
focusOnFeature(anchor,
|
|
38871
|
+
focusOnFeature(anchor, zoom, move = "turn", view = null, look = LEVEL_LOOK) {
|
|
38458
38872
|
this.disarmLimits();
|
|
38459
38873
|
this.applyJdUpdate();
|
|
38460
38874
|
this.focusWasOutOfRange = false;
|
|
38461
38875
|
const host = this.ctx.getBody(anchor.hostId);
|
|
38462
38876
|
const hostPos = host && this.whereBody(host);
|
|
38463
38877
|
if (!host || !hostPos) return 0;
|
|
38464
|
-
this.focusController
|
|
38465
|
-
|
|
38466
|
-
const fb = makeFeatureBody(anchor, name);
|
|
38467
|
-
this.ctx.bodies.focusFeature = fb;
|
|
38878
|
+
const fc = this.focusController;
|
|
38879
|
+
fc.clearPendingInitialView();
|
|
38468
38880
|
const hostBo = this.bodyObjects.get(host.data.id);
|
|
38469
38881
|
this.selectedFeatureId = anchor.featureId;
|
|
38470
38882
|
if (hostBo) setActiveFeatureLabel(hostBo, anchor.featureId);
|
|
38471
|
-
const seat = this.
|
|
38472
|
-
|
|
38473
|
-
|
|
38474
|
-
if (
|
|
38475
|
-
|
|
38476
|
-
|
|
38477
|
-
|
|
38478
|
-
|
|
38479
|
-
|
|
38480
|
-
|
|
38481
|
-
|
|
38482
|
-
let zz = seat[2] - hostPos[2];
|
|
38483
|
-
const len = Math.hypot(zx, zy, zz);
|
|
38484
|
-
if (len > 1e-9) {
|
|
38485
|
-
zx /= len;
|
|
38486
|
-
zy /= len;
|
|
38487
|
-
zz /= len;
|
|
38488
|
-
} else {
|
|
38489
|
-
zx = 0;
|
|
38490
|
-
zy = 1;
|
|
38491
|
-
zz = 0;
|
|
38492
|
-
}
|
|
38493
|
-
const camPos = mode === "snap" && view ? sphericalToCartesian(seat, view.latitude, view.longitude, view.zoom, quat) : [
|
|
38494
|
-
seat[0] + zx * zoom,
|
|
38495
|
-
seat[1] + zy * zoom,
|
|
38496
|
-
seat[2] + zz * zoom
|
|
38497
|
-
];
|
|
38498
|
-
const s = cartesianToSpherical(camPos, seat, quat);
|
|
38499
|
-
this.callbacks.onCameraPosition?.(s.latitude, s.longitude, s.distance);
|
|
38500
|
-
if (mode === "snap") {
|
|
38501
|
-
this.focusController.setFocusTarget(fb, camPos);
|
|
38502
|
-
const f = this.focus;
|
|
38503
|
-
f.focusTruePos = [...seat];
|
|
38504
|
-
f.focusOriginWorld = [...seat];
|
|
38505
|
-
f.focusTargetWorld = [...seat];
|
|
38506
|
-
f.focusStartTime = -FOCUS_DURATION_MS;
|
|
38507
|
-
f.camOriginWorld = null;
|
|
38508
|
-
f.camTargetWorld = null;
|
|
38509
|
-
f.camTargetOffset = null;
|
|
38510
|
-
f.camOriginOffset = null;
|
|
38511
|
-
f.flyQ0 = null;
|
|
38512
|
-
f.orbitFly = false;
|
|
38513
|
-
f.arcOrbit = false;
|
|
38514
|
-
f.cameraStaysOnBody = false;
|
|
38515
|
-
this.repositionAll();
|
|
38516
|
-
this.pointClouds.rebuildBasis();
|
|
38517
|
-
this.camera.position.set(camPos[0] - seat[0], camPos[1] - seat[1], camPos[2] - seat[2]);
|
|
38518
|
-
this.controls.update();
|
|
38519
|
-
return 0;
|
|
38520
|
-
}
|
|
38521
|
-
if (alreadyOnHost) {
|
|
38522
|
-
const camWorld = this.focusController.cameraTruePos();
|
|
38523
|
-
this.focusController.setFocusTarget(fb);
|
|
38524
|
-
this.focus.focusTruePos = [...seat];
|
|
38525
|
-
this.camera.position.set(camWorld[0] - seat[0], camWorld[1] - seat[1], camWorld[2] - seat[2]);
|
|
38526
|
-
this.repositionAll();
|
|
38527
|
-
this.pointClouds.rebuildBasis();
|
|
38528
|
-
prepareFlyToCamera(this.focus, this.camera, camWorld, camPos, sceneSettings().resolvedReducedMotion);
|
|
38529
|
-
} else {
|
|
38530
|
-
this.focusController.setFocusTarget(fb, camPos);
|
|
38531
|
-
this.focus.orbitFly = true;
|
|
38883
|
+
const seat = featureSeat(anchor, host, hostPos, hostBo, this.sceneJd);
|
|
38884
|
+
const site = surfaceSite(host, seat, hostPos, this.sceneJd);
|
|
38885
|
+
if (move === "turn") return fc.panToSurfacePoint(host, site, zoom);
|
|
38886
|
+
if (move === "frame" || !view) return fc.arriveAbove(host, site, zoom, void 0, move === "snap", look);
|
|
38887
|
+
if (underHalfRadius(host, view.zoom)) {
|
|
38888
|
+
const offset = sphericalToCartesian([
|
|
38889
|
+
0,
|
|
38890
|
+
0,
|
|
38891
|
+
0
|
|
38892
|
+
], view.latitude, view.longitude, view.zoom);
|
|
38893
|
+
view = viewOverSite(site, new Vector3(...offset), siteQuat(host, this.sceneJd));
|
|
38532
38894
|
}
|
|
38533
|
-
|
|
38895
|
+
fc.snapOntoGround(host, view);
|
|
38896
|
+
return 0;
|
|
38534
38897
|
}
|
|
38535
38898
|
pickFocusedModel(ndcX, ndcY) {
|
|
38536
38899
|
if (!this.overlayActive) return null;
|
|
@@ -38551,13 +38914,12 @@ var SceneRenderer = class SceneRenderer {
|
|
|
38551
38914
|
}
|
|
38552
38915
|
overlayModelBo() {
|
|
38553
38916
|
const withModel = (bo) => bo?.model && isDrawn(bo) ? bo : null;
|
|
38554
|
-
const focusBody = this.focusController.current;
|
|
38917
|
+
const focusBody = this.focusController.subject ?? this.focusController.current;
|
|
38555
38918
|
if (!focusBody) {
|
|
38556
38919
|
const centerId = this.travelFocus?.centerId;
|
|
38557
38920
|
return withModel(centerId ? this.bodyObjects.get(centerId) : void 0);
|
|
38558
38921
|
}
|
|
38559
|
-
const
|
|
38560
|
-
const bo = this.bodyObjects.get(modelId);
|
|
38922
|
+
const bo = this.bodyObjects.get(focusBody.data.id);
|
|
38561
38923
|
const own = withModel(bo);
|
|
38562
38924
|
if (own) return own;
|
|
38563
38925
|
if (focusBody.data.orbitalSource === OrbitalSource.SPICE_PROBE && !bo?.isLanded) {
|
|
@@ -41330,6 +41692,14 @@ var SpaceMap = class {
|
|
|
41330
41692
|
set focusedBody(value) {
|
|
41331
41693
|
set(this.#focusedBody, value);
|
|
41332
41694
|
}
|
|
41695
|
+
#cameraBody = state();
|
|
41696
|
+
get cameraBody() {
|
|
41697
|
+
return get(this.#cameraBody);
|
|
41698
|
+
}
|
|
41699
|
+
set cameraBody(value) {
|
|
41700
|
+
set(this.#cameraBody, value);
|
|
41701
|
+
}
|
|
41702
|
+
movingToFeature = false;
|
|
41333
41703
|
attribution = null;
|
|
41334
41704
|
objects = new MapObjectCollection(() => this.requireRenderer().extensions, () => this.requireCanvas());
|
|
41335
41705
|
dragRotate;
|
|
@@ -41426,9 +41796,7 @@ var SpaceMap = class {
|
|
|
41426
41796
|
}
|
|
41427
41797
|
getFocusedBody() {
|
|
41428
41798
|
const focused = this.focusedBody;
|
|
41429
|
-
|
|
41430
|
-
const body = isSurfaceFeature(focused) ? this.ctx.getBody(focused.featureAnchor.hostId) : focused;
|
|
41431
|
-
return body && bodyView(body);
|
|
41799
|
+
return focused && bodyView(focused);
|
|
41432
41800
|
}
|
|
41433
41801
|
getChildren(id) {
|
|
41434
41802
|
return [...this.ctx.bodies.getChildren(id) ?? []];
|
|
@@ -41652,11 +42020,12 @@ var SpaceMap = class {
|
|
|
41652
42020
|
notify: (notice) => this.emit("notice", notice),
|
|
41653
42021
|
dismiss: (topic) => this.emit("noticedismiss", topic)
|
|
41654
42022
|
},
|
|
41655
|
-
onFocusChange: (body) => {
|
|
42023
|
+
onFocusChange: (body, orbited) => {
|
|
41656
42024
|
const initial = this.initialFocusPending;
|
|
41657
42025
|
this.initialFocusPending = false;
|
|
41658
42026
|
this.focusedBody = body;
|
|
41659
|
-
|
|
42027
|
+
this.cameraBody = orbited;
|
|
42028
|
+
const feature = this.movingToFeature;
|
|
41660
42029
|
this.emit("focuschange", {
|
|
41661
42030
|
body: this.getFocusedBody(),
|
|
41662
42031
|
initial,
|
|
@@ -41671,7 +42040,7 @@ var SpaceMap = class {
|
|
|
41671
42040
|
},
|
|
41672
42041
|
onIdle: () => this.emit("idle"),
|
|
41673
42042
|
onCameraPosition: (latitude, longitude, zoom, look = LEVEL_LOOK) => {
|
|
41674
|
-
const body = this.
|
|
42043
|
+
const body = this.cameraBody?.data.id;
|
|
41675
42044
|
if (body === void 0) return;
|
|
41676
42045
|
this.emit("camera", {
|
|
41677
42046
|
body,
|
|
@@ -41904,7 +42273,7 @@ var SpaceMap = class {
|
|
|
41904
42273
|
});
|
|
41905
42274
|
}
|
|
41906
42275
|
panTo(target) {
|
|
41907
|
-
return this.toFeature(this.targetBody(target), target.feature, "
|
|
42276
|
+
return this.toFeature(this.targetBody(target), target.feature, "turn");
|
|
41908
42277
|
}
|
|
41909
42278
|
async jumpTo(target) {
|
|
41910
42279
|
const body = this.targetBody(target);
|
|
@@ -41937,8 +42306,7 @@ var SpaceMap = class {
|
|
|
41937
42306
|
}
|
|
41938
42307
|
if (target.feature) {
|
|
41939
42308
|
const { featureId, lat, lon, diameterM } = target.feature;
|
|
41940
|
-
this.focusOnFeature(body, featureId, lat, lon, diameterM, null,
|
|
41941
|
-
this.renderer?.setLook(lookOf(target));
|
|
42309
|
+
this.focusOnFeature(body, featureId, lat, lon, diameterM, "snap", null, lookOf(target));
|
|
41942
42310
|
return;
|
|
41943
42311
|
}
|
|
41944
42312
|
const camera = this.getCamera();
|
|
@@ -41946,7 +42314,7 @@ var SpaceMap = class {
|
|
|
41946
42314
|
}
|
|
41947
42315
|
getCamera() {
|
|
41948
42316
|
const renderer = this.renderer;
|
|
41949
|
-
const body = this.
|
|
42317
|
+
const body = this.cameraBody?.data.id;
|
|
41950
42318
|
if (!renderer || body === void 0) return null;
|
|
41951
42319
|
const { latitude, longitude, distance } = renderer.getCameraState();
|
|
41952
42320
|
return {
|
|
@@ -42019,9 +42387,9 @@ var SpaceMap = class {
|
|
|
42019
42387
|
onTouchMove = (e) => {
|
|
42020
42388
|
this.cooperative?.allowsTouchDrag(e.touches.length);
|
|
42021
42389
|
};
|
|
42022
|
-
toFeature(body, feature,
|
|
42390
|
+
toFeature(body, feature, move) {
|
|
42023
42391
|
const { featureId, lat, lon, diameterM } = feature;
|
|
42024
|
-
return this.settled(this.focusOnFeature(body, featureId, lat, lon, diameterM,
|
|
42392
|
+
return this.settled(this.focusOnFeature(body, featureId, lat, lon, diameterM, move));
|
|
42025
42393
|
}
|
|
42026
42394
|
settled(ms) {
|
|
42027
42395
|
return new Promise((resolve) => {
|
|
@@ -42071,7 +42439,7 @@ var SpaceMap = class {
|
|
|
42071
42439
|
if (!renderer || !vantage || vantage.kept) return null;
|
|
42072
42440
|
return (body) => renderer.viewFrom(body.data.id, vantage.offset) ?? {};
|
|
42073
42441
|
}
|
|
42074
|
-
focusOnFeature(bodyId, featureId, lat, lon, diameterM,
|
|
42442
|
+
focusOnFeature(bodyId, featureId, lat, lon, diameterM, move = "turn", view = null, look) {
|
|
42075
42443
|
const hostBody = this.ctx.getBody(bodyId);
|
|
42076
42444
|
if (!hostBody) return 0;
|
|
42077
42445
|
const idealScene = kmToScene(featureDiameterM(diameterM, effectiveRadiusKm(hostBody.data)) * 4 / 1e3);
|
|
@@ -42085,16 +42453,20 @@ var SpaceMap = class {
|
|
|
42085
42453
|
lon,
|
|
42086
42454
|
diameterM
|
|
42087
42455
|
};
|
|
42088
|
-
|
|
42456
|
+
this.movingToFeature = true;
|
|
42457
|
+
try {
|
|
42458
|
+
return this.renderer?.focusOnFeature(anchor, zoom, move, view, look) ?? 0;
|
|
42459
|
+
} finally {
|
|
42460
|
+
this.movingToFeature = false;
|
|
42461
|
+
}
|
|
42089
42462
|
}
|
|
42090
42463
|
setFocusTarget(body, camPos) {
|
|
42091
42464
|
this.renderer?.setFocusTarget(body, camPos);
|
|
42092
42465
|
}
|
|
42093
42466
|
getPose() {
|
|
42094
42467
|
const renderer = this.renderer;
|
|
42095
|
-
const
|
|
42096
|
-
if (!renderer ||
|
|
42097
|
-
const body = focused.data.id;
|
|
42468
|
+
const body = this.cameraBody?.data.id;
|
|
42469
|
+
if (!renderer || body === void 0) return null;
|
|
42098
42470
|
return {
|
|
42099
42471
|
position: {
|
|
42100
42472
|
body,
|