spacemap 0.1.17 → 0.1.18

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/index.d.ts CHANGED
@@ -1373,7 +1373,7 @@ export declare interface PanoramaEntry {
1373
1373
  * `unknown` means the sphere sits at an arbitrary azimuth, so nothing
1374
1374
  * may be drawn or written as a heading. The full set `export/panoramas.py`
1375
1375
  * writes — a wider union would erase the literals and stop checking. */
1376
- orientation?: 'unknown' | 'caption-aligned' | 'matched to an archival sphere' | 'matched to a controlled mosaic';
1376
+ orientation?: 'unknown' | 'caption-aligned' | 'matched to an archival sphere' | 'matched to a controlled mosaic' | 'matched to a terrain model' | 'fitted to the Sun';
1377
1377
  /** `estimated` where the sphere's angular bounds were fitted to a
1378
1378
  * published flat image rather than read from an archive label. */
1379
1379
  geometry?: 'estimated';
@@ -1853,6 +1853,8 @@ export declare class SimClock {
1853
1853
  private prevScale;
1854
1854
  private stops;
1855
1855
  private settleTimer;
1856
+ /** The promises of {@link jumpTo} that wait for a frame at their date. */
1857
+ private arrivals;
1856
1858
  constructor(initialJd: number, live?: boolean);
1857
1859
  /* Excluded from this release type: tick */
1858
1860
  /* Excluded from this release type: setBoundaryStops */
@@ -1860,9 +1862,12 @@ export declare class SimClock {
1860
1862
  setTimeScale(magnitude: number): void;
1861
1863
  toggleDirection(): void;
1862
1864
  /* Excluded from this release type: setJD */
1863
- /** Seek, and mark it as a discrete jump so listeners can react to the one
1864
- * move rather than to a stream of them. */
1865
- jumpTo(jd: number): void;
1865
+ /** Move the clock to `jd` in one jump, so that listeners react to it once.
1866
+ * The promise resolves when a frame shows the bodies at that date. Until
1867
+ * the data of the date loads, the map shows the date before the jump, and
1868
+ * the measures answer for that date. */
1869
+ jumpTo(jd: number): Promise<void>;
1870
+ /* Excluded from this release type: placed */
1866
1871
  /** Rest the settled date on where the clock stands now. */
1867
1872
  private settle;
1868
1873
  /** The same, once a drag holds still. A clock still playing is left alone: it
@@ -1877,8 +1882,9 @@ export declare class SimClock {
1877
1882
  get playing(): boolean;
1878
1883
  /** The moment the map is showing. */
1879
1884
  get date(): Date;
1880
- /** Show another moment, as one deliberate move. */
1881
- setDate(date: Date): void;
1885
+ /** Move the clock to `date` in one jump. The promise resolves as the promise
1886
+ * of {@link jumpTo} does. */
1887
+ setDate(date: Date): Promise<void>;
1882
1888
  }
1883
1889
 
1884
1890
  /**
@@ -2018,9 +2024,17 @@ export declare class SpaceMap {
2018
2024
  * the move a click on its label makes. Resolves when the camera comes
2019
2025
  * round. */
2020
2026
  panTo(target: FeatureTarget): Promise<void>;
2021
- /** Put the camera somewhere at once, with no flight: what a page restoring a
2022
- * stored view wants, where a flight from nowhere would read as a lurch. */
2023
- jumpTo(target: JumpTarget): this;
2027
+ /**
2028
+ * Put the camera at a place at once, with no flight. Use it to restore a
2029
+ * stored view. A body that the map has not loaded loads first. The promise
2030
+ * resolves one frame after the camera is in its place. It rejects when the
2031
+ * data of the body does not load. A later move stops this move.
2032
+ */
2033
+ jumpTo(target: JumpTarget): Promise<void>;
2034
+ /** Whether `id` is in the scene, with a place at the date it shows. */
2035
+ private placedNow;
2036
+ /** The placement of {@link jumpTo}, on a body in the scene. */
2037
+ private snap;
2024
2038
  /** Where the camera is now. Null before the first frame, and while nothing
2025
2039
  * is focused. */
2026
2040
  getCamera(): CameraState | null;
package/index.js CHANGED
@@ -10378,6 +10378,30 @@ function applySouthTowardParent(obj, bodyPos, parentPos) {
10378
10378
  function applyUpVector(obj, dir) {
10379
10379
  obj.quaternion.setFromUnitVectors(LOCAL_NORTH, dir);
10380
10380
  }
10381
+ function landedHeadingAt(headings, jd) {
10382
+ let deg;
10383
+ for (const h of headings ?? []) if (h.jd <= jd) deg = h.deg;
10384
+ return deg;
10385
+ }
10386
+ var LOCAL_FRONT = new Vector3(0, 0, 1);
10387
+ var _up = new Vector3();
10388
+ var _front = new Vector3();
10389
+ var _north = new Vector3();
10390
+ var _east = new Vector3();
10391
+ var _target = new Vector3();
10392
+ var _cross = new Vector3();
10393
+ var _turn = new Quaternion();
10394
+ function turnToHeading(obj, north, headingDeg) {
10395
+ _up.copy(LOCAL_NORTH).applyQuaternion(obj.quaternion);
10396
+ _north.copy(north).addScaledVector(_up, -north.dot(_up)).normalize();
10397
+ _east.crossVectors(_north, _up);
10398
+ const h = headingDeg * DEG2RAD$5;
10399
+ _target.copy(_north).multiplyScalar(Math.cos(h)).addScaledVector(_east, Math.sin(h));
10400
+ _front.copy(LOCAL_FRONT).applyQuaternion(obj.quaternion);
10401
+ _front.addScaledVector(_up, -_front.dot(_up)).normalize();
10402
+ const angle = Math.atan2(_cross.crossVectors(_front, _target).dot(_up), _front.dot(_target));
10403
+ obj.quaternion.premultiply(_turn.setFromAxisAngle(_up, angle));
10404
+ }
10381
10405
  var AXIS_VECTORS = {
10382
10406
  "+x": new Vector3(1, 0, 0),
10383
10407
  "-x": new Vector3(-1, 0, 0),
@@ -15770,6 +15794,7 @@ async function loadSpacecraftModel(bo, modelScene, ctx) {
15770
15794
  try {
15771
15795
  const detail = await fetchObjectDetail(bo.body.data.id, false);
15772
15796
  bo.body.pointing = detail.global?.pointing;
15797
+ bo.body.landedHeadings = landedHeadings(detail.global?.events?.items);
15773
15798
  const attitudeManifest = detail.global?.attitude;
15774
15799
  if (attitudeManifest && (bo.modelLoadEpoch ?? 0) === epoch) {
15775
15800
  const probeId = bo.body.data.id.replace(/^probe-/, "");
@@ -15809,8 +15834,9 @@ async function loadSpacecraftModel(bo, modelScene, ctx) {
15809
15834
  bo.model = root;
15810
15835
  bo.modelName = slug;
15811
15836
  setHaloLoading(bo, false);
15812
- if (meta.scale_meters) {
15813
- const spanKm = meta.scale_meters / 2e3;
15837
+ const spanM = meta.exports[tier]?.scale_meters;
15838
+ if (spanM) {
15839
+ const spanKm = spanM / 2e3;
15814
15840
  bo.body.data.radiusKm = spanKm * (meta.body_span_ratio ?? 1);
15815
15841
  bo.radiusScene = kmToScene(effectiveRadiusKm(bo.body.data));
15816
15842
  bo.modelUnitOverride = meta.body_span_ratio ? kmToScene(spanKm) : void 0;
@@ -15923,6 +15949,7 @@ function unloadBodyModel(bo) {
15923
15949
  bo.model = null;
15924
15950
  bo.modelName = void 0;
15925
15951
  bo.body.pointing = void 0;
15952
+ bo.body.landedHeadings = void 0;
15926
15953
  bo.body.attitudeTrack = void 0;
15927
15954
  bo.body.modelBaseFrame = void 0;
15928
15955
  if (bo.mesh && restoreSphere) bo.mesh.visible = true;
@@ -15942,6 +15969,17 @@ function setHaloLoading(bo, loading) {
15942
15969
  bo.loadingShown = void 0;
15943
15970
  }
15944
15971
  }
15972
+ function landedHeadings(events) {
15973
+ const out = [];
15974
+ for (const e of events ?? []) {
15975
+ const deg = e.type === "landing" ? e.site?.heading_deg : void 0;
15976
+ if (deg !== void 0) out.push({
15977
+ jd: e.jd,
15978
+ deg
15979
+ });
15980
+ }
15981
+ return out.length ? out : void 0;
15982
+ }
15945
15983
  function withBaseFrame(scene, q) {
15946
15984
  if (!q) return scene;
15947
15985
  const wrapper = new Group();
@@ -18713,6 +18751,7 @@ var SimClock = class {
18713
18751
  prevScale = 1;
18714
18752
  stops = null;
18715
18753
  settleTimer = null;
18754
+ arrivals = [];
18716
18755
  constructor(initialJd, live = false) {
18717
18756
  this.jd = initialJd;
18718
18757
  this.settledJd = initialJd;
@@ -18769,6 +18808,19 @@ var SimClock = class {
18769
18808
  this.setJD(jd);
18770
18809
  this.jumps++;
18771
18810
  this.settle();
18811
+ const jumps = this.jumps;
18812
+ return new Promise((resolve) => this.arrivals.push({
18813
+ jumps,
18814
+ resolve
18815
+ }));
18816
+ }
18817
+ placed(jumps) {
18818
+ if (this.arrivals.length === 0) return;
18819
+ this.arrivals = this.arrivals.filter((arrival) => {
18820
+ if (arrival.jumps > jumps) return true;
18821
+ arrival.resolve();
18822
+ return false;
18823
+ });
18772
18824
  }
18773
18825
  settle() {
18774
18826
  if (this.settleTimer !== null) clearTimeout(this.settleTimer);
@@ -18809,7 +18861,7 @@ var SimClock = class {
18809
18861
  return jdToDate(this.jd);
18810
18862
  }
18811
18863
  setDate(date) {
18812
- this.jumpTo(dateToJD(date));
18864
+ return this.jumpTo(dateToJD(date));
18813
18865
  }
18814
18866
  };
18815
18867
 
@@ -24524,6 +24576,7 @@ var OutOfRangeNotifier = class {
24524
24576
  //#region src/lib/scene/position/landed-probe.ts
24525
24577
  var lastSeat = /* @__PURE__ */ new Map();
24526
24578
  var _upScene = new Vector3();
24579
+ var _northScene = new Vector3();
24527
24580
  function renderLandedProbe(d, probe, landed, jd, where, ctx, bodyObjects) {
24528
24581
  const sample = landedPositionAt(landed, jd, landedOpenEnded(probe));
24529
24582
  if (!sample) return null;
@@ -24553,13 +24606,15 @@ function renderLandedProbe(d, probe, landed, jd, where, ctx, bodyObjects) {
24553
24606
  const quat = bodyQuaternion(landingBody.orientation, jd, landingBody.nutPrec);
24554
24607
  const tmp = new Vector3(bx, by, bz).applyQuaternion(quat);
24555
24608
  const up = eff ? _upScene.set(eff.normal[0], eff.normal[1], eff.normal[2]).applyQuaternion(quat) : null;
24609
+ const north = _northScene.set(-Math.sin(latR) * Math.cos(lngR), Math.cos(latR), Math.sin(latR) * Math.sin(lngR)).applyQuaternion(quat);
24556
24610
  d.parentId = bodyKey;
24557
24611
  return {
24558
24612
  x: bodyWorldPos[0] + kmToScene(tmp.x),
24559
24613
  y: bodyWorldPos[1] + kmToScene(tmp.y),
24560
24614
  z: bodyWorldPos[2] + kmToScene(tmp.z),
24561
24615
  parentPos: bodyWorldPos,
24562
- up
24616
+ up,
24617
+ north
24563
24618
  };
24564
24619
  }
24565
24620
 
@@ -24810,8 +24865,12 @@ var Placer = class {
24810
24865
  const up = landedRender.up;
24811
24866
  if (bo?.mesh) if (up) applyUpVector(bo.mesh, up);
24812
24867
  else applySouthTowardParent(bo.mesh, pos, landedRender.parentPos);
24813
- if (bo?.model) if (up) applyUpVector(bo.model, up);
24814
- else applySouthTowardParent(bo.model, pos, landedRender.parentPos);
24868
+ if (bo?.model) {
24869
+ if (up) applyUpVector(bo.model, up);
24870
+ else applySouthTowardParent(bo.model, pos, landedRender.parentPos);
24871
+ const heading = landedHeadingAt(body.landedHeadings, jd);
24872
+ if (heading !== void 0) turnToHeading(bo.model, landedRender.north, heading);
24873
+ }
24815
24874
  return pos;
24816
24875
  }
24817
24876
  const primary = resolveProbePrimary(located.probe, jd, located.fitCenterNaifId, ctx.chebStore ?? null, (id) => this.at(id, jd) !== null);
@@ -27733,6 +27792,7 @@ var SceneRenderer = class SceneRenderer {
27733
27792
  this.lastRenderedCamPos.copy(this.camera.position);
27734
27793
  this.lastRenderedCamQuat.copy(this.camera.quaternion);
27735
27794
  this.applyJdUpdate(true);
27795
+ if (!this.dateHeld() && !this.seekAwaitsData) this.clock.placed(this.seenJumps);
27736
27796
  this.refreshTravelFocus();
27737
27797
  this.callbacks.onFrame?.(this.sceneJd, renderedDtMs);
27738
27798
  const controlsSettled = this.holdingCamera ? this.applyHeldCamera() : stepFocusAnimation(this.focus, this.camera, this.controls, () => this.repositionAll(), () => this.pointClouds.rebuildBasis());
@@ -31791,20 +31851,38 @@ var SpaceMap = class {
31791
31851
  panTo(target) {
31792
31852
  return this.toFeature(this.targetBody(target), target.feature, "pan");
31793
31853
  }
31794
- jumpTo(target) {
31854
+ async jumpTo(target) {
31795
31855
  const body = this.targetBody(target);
31856
+ if (this.placedNow(body) && target.facing === void 0 || this.placedNow(target.facing)) this.navigation++;
31857
+ else {
31858
+ const loading = this.goTo(body, {
31859
+ clock: "keep",
31860
+ camera: "none"
31861
+ });
31862
+ const token = this.navigation;
31863
+ const arrival = await loading;
31864
+ if (arrival.outcome === "failed") throw arrival.error;
31865
+ if (arrival.outcome !== "placed" || token !== this.navigation) return;
31866
+ }
31867
+ this.snap(target, body);
31868
+ return this.settled(0);
31869
+ }
31870
+ placedNow(id) {
31871
+ const body = this.ctx.getBody(id);
31872
+ return !!body && !!this.renderer?.placeOf(body);
31873
+ }
31874
+ snap(target, body) {
31796
31875
  if (target.facing !== void 0) {
31797
31876
  this.snapToBodyFacing(body, target.facing, target.elevationDeg ?? 0, this.framing(target, body));
31798
- return this;
31877
+ return;
31799
31878
  }
31800
31879
  if (target.feature) {
31801
31880
  const { featureId, lat, lon, diameterM } = target.feature;
31802
31881
  this.focusOnFeature(body, featureId, lat, lon, diameterM, null, "snap");
31803
- return this;
31882
+ return;
31804
31883
  }
31805
31884
  const camera = this.getCamera();
31806
31885
  this.snapToBody(body, target.lat ?? camera?.lat ?? 45, target.lon ?? camera?.lon ?? 0, this.framing(target, body));
31807
- return this;
31808
31886
  }
31809
31887
  getCamera() {
31810
31888
  const renderer = this.renderer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spacemap",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "The map of the Solar System from spacemap.co, on your website!",
5
5
  "keywords": ["solar system", "spacecraft", "orbits", "map", "three.js"],
6
6
  "homepage": "https://spacemap.co",