worldorbit 4.0.0 → 5.0.0

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.
Files changed (48) hide show
  1. package/README.md +17 -18
  2. package/dist/browser/core/dist/draft-parse.js +131 -12
  3. package/dist/browser/core/dist/draft.js +4 -4
  4. package/dist/browser/core/dist/format.js +42 -3
  5. package/dist/browser/core/dist/load.js +7 -2
  6. package/dist/browser/core/dist/scene.js +215 -3
  7. package/dist/browser/core/dist/solver.d.ts +8 -1
  8. package/dist/browser/core/dist/solver.js +72 -0
  9. package/dist/browser/core/dist/spatial-scene.js +56 -0
  10. package/dist/browser/core/dist/types.d.ts +74 -2
  11. package/dist/browser/viewer/dist/render.js +71 -15
  12. package/dist/browser/viewer/dist/theme.js +1 -0
  13. package/dist/browser/viewer/dist/types.d.ts +7 -0
  14. package/dist/browser/viewer/dist/viewer.js +27 -0
  15. package/dist/obsidian-plugin/main.js +81 -67
  16. package/dist/unpkg/core/dist/draft-parse.js +131 -12
  17. package/dist/unpkg/core/dist/draft.js +4 -4
  18. package/dist/unpkg/core/dist/format.js +42 -3
  19. package/dist/unpkg/core/dist/load.js +7 -2
  20. package/dist/unpkg/core/dist/scene.js +215 -3
  21. package/dist/unpkg/core/dist/solver.d.ts +8 -1
  22. package/dist/unpkg/core/dist/solver.js +72 -0
  23. package/dist/unpkg/core/dist/spatial-scene.js +56 -0
  24. package/dist/unpkg/core/dist/types.d.ts +74 -2
  25. package/dist/unpkg/viewer/dist/render.js +71 -15
  26. package/dist/unpkg/viewer/dist/theme.js +1 -0
  27. package/dist/unpkg/viewer/dist/types.d.ts +7 -0
  28. package/dist/unpkg/viewer/dist/viewer.js +27 -0
  29. package/dist/unpkg/worldorbit-core.min.js +12 -12
  30. package/dist/unpkg/worldorbit-editor.min.js +336 -322
  31. package/dist/unpkg/worldorbit-markdown.min.js +50 -36
  32. package/dist/unpkg/worldorbit-viewer.min.js +225 -211
  33. package/dist/unpkg/worldorbit.js +473 -19
  34. package/dist/unpkg/worldorbit.min.js +229 -215
  35. package/package.json +1 -1
  36. package/packages/core/dist/draft-parse.js +131 -12
  37. package/packages/core/dist/draft.js +4 -4
  38. package/packages/core/dist/format.js +42 -3
  39. package/packages/core/dist/load.js +7 -2
  40. package/packages/core/dist/scene.js +215 -3
  41. package/packages/core/dist/solver.d.ts +8 -1
  42. package/packages/core/dist/solver.js +72 -0
  43. package/packages/core/dist/spatial-scene.js +56 -0
  44. package/packages/core/dist/types.d.ts +74 -2
  45. package/packages/viewer/dist/render.js +71 -15
  46. package/packages/viewer/dist/theme.js +1 -0
  47. package/packages/viewer/dist/types.d.ts +7 -0
  48. package/packages/viewer/dist/viewer.js +27 -0
@@ -32001,7 +32001,8 @@ void main() {
32001
32001
  const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
32002
32002
  const relations = createSceneRelations(document2, objects);
32003
32003
  const events = createSceneEvents(document2.events ?? [], objects, activeEventId);
32004
- const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
32004
+ const trajectories = createSceneTrajectories(document2, objects, events, options);
32005
+ const layers = createSceneLayers(orbitVisuals, trajectories, relations, events, leaders, objects, labels);
32005
32006
  const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
32006
32007
  const semanticGroups = createSceneSemanticGroups(document2, objects);
32007
32008
  const viewpoints = createSceneViewpoints(document2, schemaProjection, frame.preset, relationships, objectMap);
@@ -32041,6 +32042,7 @@ void main() {
32041
32042
  viewpoints,
32042
32043
  events,
32043
32044
  activeEventId,
32045
+ trajectories,
32044
32046
  objects,
32045
32047
  orbitVisuals,
32046
32048
  relations,
@@ -32497,7 +32499,7 @@ void main() {
32497
32499
  }
32498
32500
  }
32499
32501
  }
32500
- function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
32502
+ function createSceneLayers(orbitVisuals, trajectories, relations, events, leaders, objects, labels) {
32501
32503
  const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
32502
32504
  const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
32503
32505
  return [
@@ -32508,6 +32510,13 @@ void main() {
32508
32510
  },
32509
32511
  { id: "orbits-back", renderIds: backOrbitIds },
32510
32512
  { id: "orbits-front", renderIds: frontOrbitIds },
32513
+ {
32514
+ id: "trajectories",
32515
+ renderIds: trajectories.filter((trajectory) => !trajectory.hidden).flatMap((trajectory) => [
32516
+ trajectory.renderId,
32517
+ ...trajectory.waypoints.filter((waypoint) => !waypoint.hidden).map((waypoint) => waypoint.renderId)
32518
+ ])
32519
+ },
32511
32520
  {
32512
32521
  id: "relations",
32513
32522
  renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
@@ -32633,6 +32642,192 @@ void main() {
32633
32642
  };
32634
32643
  }).sort((left, right) => left.event.id.localeCompare(right.event.id));
32635
32644
  }
32645
+ function createSceneTrajectories(document2, objects, events, options) {
32646
+ const objectMap = new Map(objects.map((object) => [object.objectId, object]));
32647
+ return document2.trajectories.map((trajectory) => createSceneTrajectory(trajectory, objectMap, events, options)).sort((left, right) => left.trajectoryId.localeCompare(right.trajectoryId));
32648
+ }
32649
+ function createSceneTrajectory(trajectory, objectMap, events, options) {
32650
+ const craftObject = trajectory.craftObjectId ? objectMap.get(trajectory.craftObjectId) ?? null : null;
32651
+ const mode = resolveTrajectoryMode(trajectory, options);
32652
+ const stroke = trajectory.stroke ?? trajectory.color ?? craftObject?.fillColor ?? null;
32653
+ const strokeWidth = trajectory.strokeWidth ?? 2.4;
32654
+ const showWaypoints = options.showTrajectoryWaypoints ?? trajectory.showWaypoints ?? true;
32655
+ const labelMode = trajectory.labelMode ?? (options.showTrajectoryLabels === false ? "hidden" : "waypoint");
32656
+ const pathParts = [];
32657
+ const waypoints = [];
32658
+ const objectIds = /* @__PURE__ */ new Set();
32659
+ let lastAnchor = craftObject;
32660
+ if (craftObject) {
32661
+ objectIds.add(craftObject.objectId);
32662
+ }
32663
+ trajectory.segments.forEach((segment, index) => {
32664
+ const geometry = buildTrajectorySegmentGeometry(trajectory, segment, index, mode, objectMap, lastAnchor, showWaypoints);
32665
+ if (geometry.path) {
32666
+ pathParts.push(geometry.path);
32667
+ }
32668
+ geometry.objectIds.forEach((objectId) => objectIds.add(objectId));
32669
+ waypoints.push(...geometry.waypoints);
32670
+ lastAnchor = geometry.lastAnchor ?? lastAnchor;
32671
+ });
32672
+ for (const event of events.filter((entry) => entry.event.trajectoryId === trajectory.id)) {
32673
+ const eventObject = event.targetObjectId ? objectMap.get(event.targetObjectId) ?? null : event.objectIds.map((objectId) => objectMap.get(objectId) ?? null).find(Boolean) ?? null;
32674
+ if (!eventObject) {
32675
+ continue;
32676
+ }
32677
+ waypoints.push({
32678
+ renderId: `${createRenderId(`${trajectory.id}-${event.eventId}`)}-waypoint`,
32679
+ trajectoryId: trajectory.id,
32680
+ segmentId: null,
32681
+ maneuverId: null,
32682
+ objectId: eventObject.objectId,
32683
+ x: eventObject.x,
32684
+ y: eventObject.y,
32685
+ label: event.event.label ?? event.event.id,
32686
+ dateLabel: event.event.epoch ?? null,
32687
+ hidden: trajectory.hidden || event.hidden || !showWaypoints
32688
+ });
32689
+ objectIds.add(eventObject.objectId);
32690
+ }
32691
+ return {
32692
+ renderId: `${createRenderId(trajectory.id)}-trajectory`,
32693
+ trajectoryId: trajectory.id,
32694
+ trajectory,
32695
+ craftObjectId: trajectory.craftObjectId,
32696
+ mode,
32697
+ path: pathParts.join(" "),
32698
+ stroke,
32699
+ strokeWidth,
32700
+ marker: trajectory.marker ?? "arrow",
32701
+ labelMode,
32702
+ showWaypoints,
32703
+ objectIds: [...objectIds],
32704
+ waypoints,
32705
+ hidden: trajectory.hidden || pathParts.length === 0
32706
+ };
32707
+ }
32708
+ function buildTrajectorySegmentGeometry(trajectory, segment, segmentIndex, mode, objectMap, fallbackStart, showWaypoints) {
32709
+ const start = resolveTrajectoryObject(segment.fromObjectId, objectMap) ?? fallbackStart;
32710
+ const assist = resolveTrajectoryObject(segment.assist?.objectId ?? segment.aroundObjectId ?? null, objectMap);
32711
+ const end = resolveTrajectoryObject(segment.toObjectId, objectMap) ?? resolveTrajectoryObject(segment.aroundObjectId, objectMap) ?? assist ?? start;
32712
+ if (!start || !end) {
32713
+ return {
32714
+ path: "",
32715
+ objectIds: [],
32716
+ waypoints: [],
32717
+ lastAnchor: fallbackStart
32718
+ };
32719
+ }
32720
+ const objectIds = [start.objectId, end.objectId];
32721
+ if (assist) {
32722
+ objectIds.push(assist.objectId);
32723
+ }
32724
+ const hidden = trajectory.hidden || segment.renderHidden === true || start.hidden || end.hidden;
32725
+ const waypoints = [];
32726
+ const label = segment.waypointLabel ?? segment.label ?? humanizeIdentifier(segment.id);
32727
+ const dateLabel = segment.waypointDate ?? segment.epoch ?? null;
32728
+ if (showWaypoints) {
32729
+ if (segmentIndex === 0) {
32730
+ waypoints.push(createTrajectoryWaypoint(trajectory.id, segment.id, null, start, start.label, null, hidden));
32731
+ }
32732
+ if (assist && assist.objectId !== start.objectId && assist.objectId !== end.objectId) {
32733
+ waypoints.push(createTrajectoryWaypoint(trajectory.id, segment.id, null, assist, label, dateLabel, hidden));
32734
+ }
32735
+ waypoints.push(createTrajectoryWaypoint(trajectory.id, segment.id, null, end, label, dateLabel, hidden));
32736
+ }
32737
+ const samples = mode === "solver" ? sampleQuadraticPoints(start, resolveTrajectoryControlPoint(start, end, assist, segmentIndex), end, Math.max(10, Math.round((segment.sampleDensity ?? 1) * 14))) : null;
32738
+ const control = resolveTrajectoryControlPoint(start, end, assist, segmentIndex);
32739
+ const path = mode === "solver" ? pointsToPath(samples ?? [start, end]) : `M ${formatPathNumber(start.x)} ${formatPathNumber(start.y)} Q ${formatPathNumber(control.x)} ${formatPathNumber(control.y)} ${formatPathNumber(end.x)} ${formatPathNumber(end.y)}`;
32740
+ segment.maneuvers.forEach((maneuver, maneuverIndex) => {
32741
+ if (!showWaypoints) {
32742
+ return;
32743
+ }
32744
+ const point = samplePointOnQuadratic(start, control, end, (maneuverIndex + 1) / (segment.maneuvers.length + 1));
32745
+ waypoints.push({
32746
+ renderId: `${createRenderId(`${trajectory.id}-${segment.id}-${maneuver.id}`)}-waypoint`,
32747
+ trajectoryId: trajectory.id,
32748
+ segmentId: segment.id,
32749
+ maneuverId: maneuver.id,
32750
+ objectId: null,
32751
+ x: point.x,
32752
+ y: point.y,
32753
+ label: maneuver.label ?? maneuver.kind,
32754
+ dateLabel: maneuver.epoch ?? null,
32755
+ hidden
32756
+ });
32757
+ });
32758
+ return {
32759
+ path,
32760
+ objectIds: [...new Set(objectIds)],
32761
+ waypoints,
32762
+ lastAnchor: end
32763
+ };
32764
+ }
32765
+ function createTrajectoryWaypoint(trajectoryId, segmentId, maneuverId, object, label, dateLabel, hidden) {
32766
+ return {
32767
+ renderId: `${createRenderId(`${trajectoryId}-${segmentId ?? object.objectId}-${maneuverId ?? object.objectId}`)}-waypoint`,
32768
+ trajectoryId,
32769
+ segmentId,
32770
+ maneuverId,
32771
+ objectId: object.objectId,
32772
+ x: object.x,
32773
+ y: object.y,
32774
+ label,
32775
+ dateLabel,
32776
+ hidden
32777
+ };
32778
+ }
32779
+ function resolveTrajectoryMode(trajectory, options) {
32780
+ const requested = options.trajectoryMode ?? trajectory.renderMode ?? "auto";
32781
+ if (requested !== "auto") {
32782
+ return requested;
32783
+ }
32784
+ const segmentCount = trajectory.segments.filter((segment) => segment.fromObjectId || segment.toObjectId || segment.assist?.objectId || segment.aroundObjectId).length;
32785
+ return segmentCount > 0 ? "solver" : "illustrative";
32786
+ }
32787
+ function resolveTrajectoryObject(objectId, objectMap) {
32788
+ return objectId ? objectMap.get(objectId) ?? null : null;
32789
+ }
32790
+ function resolveTrajectoryControlPoint(start, end, assist, segmentIndex) {
32791
+ if (assist) {
32792
+ return {
32793
+ x: assist.x,
32794
+ y: assist.y
32795
+ };
32796
+ }
32797
+ const dx = end.x - start.x;
32798
+ const dy = end.y - start.y;
32799
+ const length = Math.max(Math.hypot(dx, dy), 1);
32800
+ const offset = Math.min(Math.max(length * 0.18, 26), 120) * (segmentIndex % 2 === 0 ? 1 : -1);
32801
+ const normalX = -dy / length;
32802
+ const normalY = dx / length;
32803
+ return {
32804
+ x: (start.x + end.x) / 2 + normalX * offset,
32805
+ y: (start.y + end.y) / 2 + normalY * offset
32806
+ };
32807
+ }
32808
+ function sampleQuadraticPoints(start, control, end, count) {
32809
+ const samples = [];
32810
+ for (let index = 0; index <= count; index += 1) {
32811
+ samples.push(samplePointOnQuadratic(start, control, end, index / count));
32812
+ }
32813
+ return samples;
32814
+ }
32815
+ function samplePointOnQuadratic(start, control, end, t) {
32816
+ const inverse = 1 - t;
32817
+ return {
32818
+ x: inverse * inverse * start.x + 2 * inverse * t * control.x + t * t * end.x,
32819
+ y: inverse * inverse * start.y + 2 * inverse * t * control.y + t * t * end.y
32820
+ };
32821
+ }
32822
+ function pointsToPath(points) {
32823
+ if (points.length === 0) {
32824
+ return "";
32825
+ }
32826
+ return points.map((point, index) => `${index === 0 ? "M" : "L"} ${formatPathNumber(point.x)} ${formatPathNumber(point.y)}`).join(" ");
32827
+ }
32828
+ function formatPathNumber(value) {
32829
+ return Number.isFinite(value) ? value.toFixed(2) : "0";
32830
+ }
32636
32831
  function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
32637
32832
  const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
32638
32833
  const drafts = /* @__PURE__ */ new Map();
@@ -32892,7 +33087,7 @@ void main() {
32892
33087
  next["orbits-front"] = enabled;
32893
33088
  continue;
32894
33089
  }
32895
- if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
33090
+ if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata" || rawLayer === "trajectories") {
32896
33091
  next[rawLayer] = enabled;
32897
33092
  }
32898
33093
  }
@@ -33742,6 +33937,7 @@ void main() {
33742
33937
  const spatialObjects = scene.objects.map((entry) => createSpatialObject(entry, scene, sceneCenter, objectMap, orbitMap, scaleModel, positionCache, minimumMotionMetric));
33743
33938
  const spatialObjectMap = new Map(spatialObjects.map((object) => [object.objectId, object]));
33744
33939
  const spatialOrbits = scene.orbitVisuals.map((orbit) => createSpatialOrbit(orbit, spatialObjectMap, minimumMotionMetric, scene.activeEventId !== null));
33940
+ const spatialTrajectories = scene.trajectories.map((trajectory) => createSpatialTrajectory(trajectory, spatialObjectMap));
33745
33941
  const focusTargets = spatialObjects.map((object) => ({
33746
33942
  objectId: object.objectId,
33747
33943
  center: { ...object.position },
@@ -33771,6 +33967,7 @@ void main() {
33771
33967
  timeFrozen: scene.activeEventId !== null,
33772
33968
  objects: spatialObjects,
33773
33969
  orbits: spatialOrbits,
33970
+ trajectories: spatialTrajectories,
33774
33971
  focusTargets
33775
33972
  };
33776
33973
  }
@@ -33818,6 +34015,39 @@ void main() {
33818
34015
  motion: owner?.motion ?? createMotionModel(orbit.object, orbit, minimumMotionMetric, frozen)
33819
34016
  };
33820
34017
  }
34018
+ function createSpatialTrajectory(trajectory, objectMap) {
34019
+ const samples = samplePathPoints(trajectory.path).map((point) => ({
34020
+ x: point.x,
34021
+ y: 0,
34022
+ z: point.y
34023
+ }));
34024
+ return {
34025
+ trajectoryId: trajectory.trajectoryId,
34026
+ trajectory: trajectory.trajectory,
34027
+ craftObjectId: trajectory.craftObjectId,
34028
+ mode: trajectory.mode,
34029
+ stroke: trajectory.stroke,
34030
+ strokeWidth: trajectory.strokeWidth,
34031
+ marker: trajectory.marker,
34032
+ labelMode: trajectory.labelMode,
34033
+ showWaypoints: trajectory.showWaypoints,
34034
+ samples,
34035
+ waypoints: trajectory.waypoints.map((waypoint) => {
34036
+ const object = waypoint.objectId ? objectMap.get(waypoint.objectId) ?? null : null;
34037
+ return {
34038
+ trajectoryId: waypoint.trajectoryId,
34039
+ segmentId: waypoint.segmentId,
34040
+ maneuverId: waypoint.maneuverId,
34041
+ objectId: waypoint.objectId,
34042
+ position: object ? { ...object.position } : { x: waypoint.x, y: 0, z: waypoint.y },
34043
+ label: waypoint.label,
34044
+ dateLabel: waypoint.dateLabel,
34045
+ hidden: waypoint.hidden
34046
+ };
34047
+ }),
34048
+ hidden: trajectory.hidden
34049
+ };
34050
+ }
33821
34051
  function resolveSpatialObjectPosition(entry, scene, sceneCenter, objectMap, orbitMap, cache) {
33822
34052
  const cached = cache.get(entry.objectId);
33823
34053
  if (cached) {
@@ -34101,6 +34331,25 @@ void main() {
34101
34331
  function degreesToRadians2(value) {
34102
34332
  return value * Math.PI / 180;
34103
34333
  }
34334
+ function samplePathPoints(path) {
34335
+ const matches = [...path.matchAll(/[MLQ]\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)(?:\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?))?(?:\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?))?/g)];
34336
+ if (matches.length === 0) {
34337
+ return [];
34338
+ }
34339
+ const points = [];
34340
+ for (const match of matches) {
34341
+ const command = match[0][0];
34342
+ if (command === "M" || command === "L") {
34343
+ points.push({ x: Number(match[1]), y: Number(match[2]) });
34344
+ continue;
34345
+ }
34346
+ if (command === "Q") {
34347
+ points.push({ x: Number(match[1]), y: Number(match[2]) });
34348
+ points.push({ x: Number(match[5]), y: Number(match[6]) });
34349
+ }
34350
+ }
34351
+ return points;
34352
+ }
34104
34353
 
34105
34354
  // packages/core/dist/solver.js
34106
34355
  function createTrajectorySolverSnapshot(trajectory) {
@@ -34149,15 +34398,15 @@ void main() {
34149
34398
  }
34150
34399
  return {
34151
34400
  format: "worldorbit",
34152
- version: "3.0",
34153
- schemaVersion: "3.0",
34401
+ version: "3.1",
34402
+ schemaVersion: "3.1",
34154
34403
  sourceVersion: document2.version,
34155
34404
  theme: document2.theme ?? null,
34156
34405
  system,
34157
34406
  groups: structuredClone(document2.groups ?? []),
34158
34407
  relations: structuredClone(document2.relations ?? []),
34159
34408
  events: structuredClone(document2.events ?? []),
34160
- trajectories: [],
34409
+ trajectories: structuredClone(document2.trajectories ?? []),
34161
34410
  objects: document2.objects.map(cloneWorldOrbitObject).map(normalizeLegacyCraftObject),
34162
34411
  diagnostics
34163
34412
  };
@@ -34576,7 +34825,7 @@ void main() {
34576
34825
  if (orbitFront !== void 0 || orbitBack !== void 0) {
34577
34826
  tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
34578
34827
  }
34579
- for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
34828
+ for (const key of ["background", "guides", "relations", "events", "objects", "trajectories", "labels", "metadata"]) {
34580
34829
  if (layers[key] !== void 0) {
34581
34830
  tokens.push(layers[key] ? key : `-${key}`);
34582
34831
  }
@@ -34629,7 +34878,7 @@ void main() {
34629
34878
  ];
34630
34879
  function formatDocument(document2, options = {}) {
34631
34880
  const schema = options.schema ?? "auto";
34632
- const useDraft = schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6" || schema === "3.0" || schema === "2.0-draft" || document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "3.0" || document2.version === "2.6" || document2.version === "2.0-draft";
34881
+ const useDraft = schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6" || schema === "3.0" || schema === "3.1" || schema === "2.0-draft" || document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "3.0" || document2.version === "3.1" || document2.version === "2.6" || document2.version === "2.0-draft";
34633
34882
  if (useDraft) {
34634
34883
  if (schema === "2.0-draft") {
34635
34884
  const legacyDraftDocument = document2.version === "2.0-draft" ? document2 : document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "2.6" ? {
@@ -34639,12 +34888,12 @@ void main() {
34639
34888
  } : upgradeDocumentToDraftV2(document2);
34640
34889
  return formatDraftDocument(legacyDraftDocument);
34641
34890
  }
34642
- const atlasDocument = document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "2.6" || document2.version === "3.0" ? document2 : document2.version === "2.0-draft" ? {
34891
+ const atlasDocument = document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "2.6" || document2.version === "3.0" || document2.version === "3.1" ? document2 : document2.version === "2.0-draft" ? {
34643
34892
  ...document2,
34644
34893
  version: "2.0",
34645
34894
  schemaVersion: "2.0"
34646
34895
  } : upgradeDocumentToV2(document2);
34647
- if ((schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6" || schema === "3.0") && atlasDocument.version !== schema) {
34896
+ if ((schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6" || schema === "3.0" || schema === "3.1") && atlasDocument.version !== schema) {
34648
34897
  return formatAtlasDocument({
34649
34898
  ...atlasDocument,
34650
34899
  version: schema,
@@ -35104,6 +35353,24 @@ void main() {
35104
35353
  if (trajectory.color) {
35105
35354
  lines.push(` color ${quoteIfNeeded(trajectory.color)}`);
35106
35355
  }
35356
+ if (trajectory.renderMode) {
35357
+ lines.push(` renderMode ${trajectory.renderMode}`);
35358
+ }
35359
+ if (trajectory.stroke) {
35360
+ lines.push(` stroke ${quoteIfNeeded(trajectory.stroke)}`);
35361
+ }
35362
+ if (trajectory.strokeWidth !== null && trajectory.strokeWidth !== void 0) {
35363
+ lines.push(` strokeWidth ${trajectory.strokeWidth}`);
35364
+ }
35365
+ if (trajectory.marker) {
35366
+ lines.push(` marker ${quoteIfNeeded(trajectory.marker)}`);
35367
+ }
35368
+ if (trajectory.labelMode) {
35369
+ lines.push(` labelMode ${quoteIfNeeded(trajectory.labelMode)}`);
35370
+ }
35371
+ if (trajectory.showWaypoints !== null && trajectory.showWaypoints !== void 0) {
35372
+ lines.push(` showWaypoints ${trajectory.showWaypoints ? "true" : "false"}`);
35373
+ }
35107
35374
  if (trajectory.hidden) {
35108
35375
  lines.push(" hidden true");
35109
35376
  }
@@ -35140,6 +35407,10 @@ void main() {
35140
35407
  ...formatOptionalUnit("phaseAngle", segment.phaseAngle),
35141
35408
  ...formatOptionalUnit("turnAngle", segment.turnAngle),
35142
35409
  ...formatOptionalUnit("energy", segment.energy),
35410
+ ...segment.waypointLabel ? [`waypointLabel ${quoteIfNeeded(segment.waypointLabel)}`] : [],
35411
+ ...segment.waypointDate ? [`waypointDate ${quoteIfNeeded(segment.waypointDate)}`] : [],
35412
+ ...segment.renderHidden !== null && segment.renderHidden !== void 0 ? [`renderHidden ${segment.renderHidden ? "true" : "false"}`] : [],
35413
+ ...segment.sampleDensity !== null && segment.sampleDensity !== void 0 ? [`sampleDensity ${segment.sampleDensity}`] : [],
35143
35414
  ...segment.notes.length > 0 ? [`notes ${segment.notes.map(quoteIfNeeded).join(" ")}`] : []
35144
35415
  ];
35145
35416
  }
@@ -35197,7 +35468,7 @@ void main() {
35197
35468
  if (orbitFront !== void 0 || orbitBack !== void 0) {
35198
35469
  tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
35199
35470
  }
35200
- for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
35471
+ for (const key of ["background", "guides", "relations", "events", "objects", "trajectories", "labels", "metadata"]) {
35201
35472
  if (layers[key] !== void 0) {
35202
35473
  tokens.push(layers[key] ? key : `-${key}`);
35203
35474
  }
@@ -36141,7 +36412,7 @@ void main() {
36141
36412
  handleSectionLine(section, indent, tokens, lineNumber);
36142
36413
  }
36143
36414
  if (!sawSchemaHeader) {
36144
- throw new WorldOrbitError('Missing required atlas schema header "schema 2.0" or "schema 3.0"');
36415
+ throw new WorldOrbitError('Missing required atlas schema header "schema 2.0", "schema 3.0", or "schema 3.1"');
36145
36416
  }
36146
36417
  const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
36147
36418
  const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
@@ -36184,11 +36455,11 @@ void main() {
36184
36455
  return document2;
36185
36456
  }
36186
36457
  function assertDraftSchemaHeader(tokens, line) {
36187
- if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1", "2.5", "2.6", "3.0"].includes(tokens[1].value.toLowerCase())) {
36188
- throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", "schema 2.6", "schema 3.0", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
36458
+ if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1", "2.5", "2.6", "3.0", "3.1"].includes(tokens[1].value.toLowerCase())) {
36459
+ throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", "schema 2.6", "schema 3.0", "schema 3.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
36189
36460
  }
36190
36461
  const version = tokens[1].value.toLowerCase();
36191
- return version === "2.6" ? "2.6" : version === "3.0" ? "3.0" : version === "2.5" ? "2.5" : version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
36462
+ return version === "2.6" ? "2.6" : version === "3.0" ? "3.0" : version === "3.1" ? "3.1" : version === "2.5" ? "2.5" : version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
36192
36463
  }
36193
36464
  function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, trajectories, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, trajectoryIds, flags) {
36194
36465
  const keyword = tokens[0]?.value.toLowerCase();
@@ -36472,6 +36743,12 @@ void main() {
36472
36743
  craftObjectId: null,
36473
36744
  tags: [],
36474
36745
  color: null,
36746
+ renderMode: null,
36747
+ stroke: null,
36748
+ strokeWidth: null,
36749
+ marker: null,
36750
+ labelMode: null,
36751
+ showWaypoints: null,
36475
36752
  hidden: false,
36476
36753
  segments: []
36477
36754
  };
@@ -37037,6 +37314,10 @@ void main() {
37037
37314
  aroundObjectId: null,
37038
37315
  assist: null,
37039
37316
  epoch: null,
37317
+ waypointLabel: null,
37318
+ waypointDate: null,
37319
+ renderHidden: null,
37320
+ sampleDensity: null,
37040
37321
  notes: [],
37041
37322
  maneuvers: []
37042
37323
  };
@@ -37071,6 +37352,54 @@ void main() {
37071
37352
  case "color":
37072
37353
  section.trajectory.color = value;
37073
37354
  return;
37355
+ case "rendermode":
37356
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "trajectory.renderMode", {
37357
+ line,
37358
+ column: tokens[0].column
37359
+ });
37360
+ if (value !== "illustrative" && value !== "solver" && value !== "auto") {
37361
+ throw new WorldOrbitError(`Unknown trajectory render mode "${value}"`, line, tokens[0].column);
37362
+ }
37363
+ section.trajectory.renderMode = value;
37364
+ return;
37365
+ case "stroke":
37366
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "trajectory.stroke", {
37367
+ line,
37368
+ column: tokens[0].column
37369
+ });
37370
+ section.trajectory.stroke = value;
37371
+ return;
37372
+ case "strokewidth":
37373
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "trajectory.strokeWidth", {
37374
+ line,
37375
+ column: tokens[0].column
37376
+ });
37377
+ section.trajectory.strokeWidth = parsePositiveNumber2(value, line, tokens[0].column, "strokeWidth");
37378
+ return;
37379
+ case "marker":
37380
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "trajectory.marker", {
37381
+ line,
37382
+ column: tokens[0].column
37383
+ });
37384
+ section.trajectory.marker = value;
37385
+ return;
37386
+ case "labelmode":
37387
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "trajectory.labelMode", {
37388
+ line,
37389
+ column: tokens[0].column
37390
+ });
37391
+ section.trajectory.labelMode = value;
37392
+ return;
37393
+ case "showwaypoints":
37394
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "trajectory.showWaypoints", {
37395
+ line,
37396
+ column: tokens[0].column
37397
+ });
37398
+ section.trajectory.showWaypoints = parseAtlasBoolean(value, "showWaypoints", {
37399
+ line,
37400
+ column: tokens[0].column
37401
+ });
37402
+ return;
37074
37403
  case "hidden":
37075
37404
  section.trajectory.hidden = parseAtlasBoolean(value, "hidden", {
37076
37405
  line,
@@ -37146,6 +37475,37 @@ void main() {
37146
37475
  case "energy":
37147
37476
  target.energy = parseAtlasUnitValue(value, { line, column: tokens[0].column });
37148
37477
  return;
37478
+ case "waypointlabel":
37479
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "segment.waypointLabel", {
37480
+ line,
37481
+ column: tokens[0].column
37482
+ });
37483
+ target.waypointLabel = value;
37484
+ return;
37485
+ case "waypointdate":
37486
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "segment.waypointDate", {
37487
+ line,
37488
+ column: tokens[0].column
37489
+ });
37490
+ target.waypointDate = value;
37491
+ return;
37492
+ case "renderhidden":
37493
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "segment.renderHidden", {
37494
+ line,
37495
+ column: tokens[0].column
37496
+ });
37497
+ target.renderHidden = parseAtlasBoolean(value, "renderHidden", {
37498
+ line,
37499
+ column: tokens[0].column
37500
+ });
37501
+ return;
37502
+ case "sampledensity":
37503
+ warnIfSchema31Feature(section.sourceSchemaVersion, section.diagnostics, "segment.sampleDensity", {
37504
+ line,
37505
+ column: tokens[0].column
37506
+ });
37507
+ target.sampleDensity = parsePositiveNumber2(value, line, tokens[0].column, "sampleDensity");
37508
+ return;
37149
37509
  case "notes":
37150
37510
  target.notes = parseTokenList(tokens.slice(1), line, "notes");
37151
37511
  return;
@@ -37270,7 +37630,7 @@ void main() {
37270
37630
  layers["orbits-front"] = enabled;
37271
37631
  continue;
37272
37632
  }
37273
- if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
37633
+ if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata" || raw === "trajectories") {
37274
37634
  if (raw === "events" && sourceSchemaVersion && diagnostics) {
37275
37635
  warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
37276
37636
  line,
@@ -37393,6 +37753,11 @@ void main() {
37393
37753
  line,
37394
37754
  column: keyToken.column
37395
37755
  });
37756
+ } else if (spec.version === "3.1") {
37757
+ warnIfSchema31Feature(sourceSchemaVersion, diagnostics, keyToken.value, {
37758
+ line,
37759
+ column: keyToken.column
37760
+ });
37396
37761
  }
37397
37762
  index++;
37398
37763
  const valueTokens = [];
@@ -37448,6 +37813,11 @@ void main() {
37448
37813
  line,
37449
37814
  column: tokens[0].column
37450
37815
  });
37816
+ } else if (spec.version === "3.1") {
37817
+ warnIfSchema31Feature(sourceSchemaVersion, diagnostics, tokens[0].value, {
37818
+ line,
37819
+ column: tokens[0].column
37820
+ });
37451
37821
  }
37452
37822
  const field = {
37453
37823
  type: "field",
@@ -37773,6 +38143,19 @@ void main() {
37773
38143
  column: location.column
37774
38144
  });
37775
38145
  }
38146
+ function warnIfSchema31Feature(sourceSchemaVersion, diagnostics, featureName, location) {
38147
+ if (!isSchemaOlderThan(sourceSchemaVersion, "3.1")) {
38148
+ return;
38149
+ }
38150
+ diagnostics.push({
38151
+ code: "parse.schema31.featureCompatibility",
38152
+ severity: "warning",
38153
+ source: "parse",
38154
+ message: `Feature "${featureName}" requires schema 3.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
38155
+ line: location.line,
38156
+ column: location.column
38157
+ });
38158
+ }
37776
38159
  function isSchemaOlderThan(sourceSchemaVersion, requiredVersion) {
37777
38160
  return schemaVersionRank(sourceSchemaVersion) < schemaVersionRank(requiredVersion);
37778
38161
  }
@@ -37790,8 +38173,10 @@ void main() {
37790
38173
  return 4;
37791
38174
  case "3.0":
37792
38175
  return 5;
37793
- default:
38176
+ case "3.1":
37794
38177
  return 6;
38178
+ default:
38179
+ return 7;
37795
38180
  }
37796
38181
  }
37797
38182
  function preprocessAtlasSource(source) {
@@ -38374,11 +38759,12 @@ void main() {
38374
38759
  }
38375
38760
 
38376
38761
  // packages/core/dist/load.js
38377
- var ATLAS_SCHEMA_PATTERN = /^schema\s+(?:2(?:\.0|\.1|\.5|\.6)?|3(?:\.0)?)$/i;
38762
+ var ATLAS_SCHEMA_PATTERN = /^schema\s+(?:2(?:\.0|\.1|\.5|\.6)?|3(?:\.0|\.1)?)$/i;
38378
38763
  var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
38379
38764
  var ATLAS_SCHEMA_25_PATTERN = /^schema\s+2\.5$/i;
38380
38765
  var ATLAS_SCHEMA_26_PATTERN = /^schema\s+2\.6$/i;
38381
38766
  var ATLAS_SCHEMA_30_PATTERN = /^schema\s+3(?:\.0)?$/i;
38767
+ var ATLAS_SCHEMA_31_PATTERN = /^schema\s+3\.1$/i;
38382
38768
  var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
38383
38769
  function detectWorldOrbitSchemaVersion(source) {
38384
38770
  for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
@@ -38401,6 +38787,9 @@ void main() {
38401
38787
  if (ATLAS_SCHEMA_30_PATTERN.test(trimmed)) {
38402
38788
  return "3.0";
38403
38789
  }
38790
+ if (ATLAS_SCHEMA_31_PATTERN.test(trimmed)) {
38791
+ return "3.1";
38792
+ }
38404
38793
  if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
38405
38794
  return "2.0";
38406
38795
  }
@@ -38461,7 +38850,7 @@ void main() {
38461
38850
  }
38462
38851
  function loadWorldOrbitSourceWithDiagnostics(source) {
38463
38852
  const schemaVersion = detectWorldOrbitSchemaVersion(source);
38464
- if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1" || schemaVersion === "2.5" || schemaVersion === "2.6" || schemaVersion === "3.0") {
38853
+ if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1" || schemaVersion === "2.5" || schemaVersion === "2.6" || schemaVersion === "3.0" || schemaVersion === "3.1") {
38465
38854
  return loadAtlasSourceWithDiagnostics(source, schemaVersion);
38466
38855
  }
38467
38856
  let ast;
@@ -38634,6 +39023,7 @@ void main() {
38634
39023
  relations: true,
38635
39024
  events: true,
38636
39025
  orbits: true,
39026
+ trajectories: true,
38637
39027
  objects: true,
38638
39028
  labels: true,
38639
39029
  structures: true,
@@ -39175,6 +39565,11 @@ void main() {
39175
39565
  const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
39176
39566
  const leaderMarkup = layers.guides ? scene.leaders.filter((leader) => !leader.hidden).filter((leader) => visibleObjectIds.has(leader.objectId)).filter((leader) => layers.structures || !isStructureLike(leader.object)).map((leader) => `<line class="wo-leader wo-leader-${leader.mode}" x1="${leader.x1}" y1="${leader.y1}" x2="${leader.x2}" y2="${leader.y2}" data-render-id="${escapeXml(leader.renderId)}" data-group-id="${escapeAttribute(leader.groupId ?? "")}" />`).join("") : "";
39177
39567
  const relationMarkup = layers.relations ? scene.relations.filter((relation) => !relation.hidden).filter((relation) => visibleObjectIds.has(relation.fromObjectId) && visibleObjectIds.has(relation.toObjectId)).map((relation) => `<line class="wo-relation" x1="${relation.x1}" y1="${relation.y1}" x2="${relation.x2}" y2="${relation.y2}" data-render-id="${escapeXml(relation.renderId)}" data-relation-id="${escapeAttribute(relation.relationId)}" />`).join("") : "";
39568
+ const trajectoryMarkup = layers.trajectories ? renderTrajectoryLayer(scene, visibleObjectIds, {
39569
+ showLabels: options.showTrajectoryLabels ?? true,
39570
+ showWaypoints: options.showTrajectoryWaypoints ?? true,
39571
+ includeStructures: layers.structures
39572
+ }) : "";
39178
39573
  const eventMarkup = layers.events ? scene.events.filter((event) => !event.hidden).map((event) => renderSceneEventOverlay(scene, event, visibleObjectIds, theme)).join("") : "";
39179
39574
  const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
39180
39575
  const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
@@ -39200,6 +39595,9 @@ void main() {
39200
39595
  <stop offset="0%" stop-color="${theme.backgroundGlow}" />
39201
39596
  <stop offset="100%" stop-color="transparent" />
39202
39597
  </radialGradient>
39598
+ <marker id="wo-trajectory-arrow" markerWidth="12" markerHeight="12" refX="10" refY="6" orient="auto" markerUnits="strokeWidth">
39599
+ <path d="M 0 0 L 12 6 L 0 12 z" fill="${theme.accent}" />
39600
+ </marker>
39203
39601
  ${imageDefinitions}
39204
39602
  </defs>
39205
39603
  <style>
@@ -39211,6 +39609,10 @@ void main() {
39211
39609
  .wo-orbit-front { opacity: 0.9; }
39212
39610
  .wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
39213
39611
  .wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
39612
+ .wo-trajectory { fill: none; stroke: ${theme.accent}; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; opacity: 0.92; }
39613
+ .wo-trajectory-waypoint { fill: ${theme.spaceFog}; stroke: ${theme.selected}; stroke-width: 1.4; }
39614
+ .wo-trajectory-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
39615
+ .wo-trajectory-date { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
39214
39616
  .wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
39215
39617
  .wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
39216
39618
  .wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
@@ -39251,6 +39653,7 @@ void main() {
39251
39653
  ${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
39252
39654
  ${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
39253
39655
  ${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
39656
+ ${layers.trajectories ? `<g data-layer-id="trajectories">${trajectoryMarkup}</g>` : ""}
39254
39657
  ${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
39255
39658
  </g>
39256
39659
  </g>
@@ -39271,6 +39674,30 @@ void main() {
39271
39674
  <text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
39272
39675
  </g>`;
39273
39676
  }
39677
+ function renderTrajectoryLayer(scene, visibleObjectIds, options) {
39678
+ return scene.trajectories.filter((trajectory) => !trajectory.hidden).filter((trajectory) => trajectory.objectIds.length === 0 || trajectory.objectIds.some((objectId) => visibleObjectIds.has(objectId))).filter((trajectory) => options.includeStructures || !trajectory.objectIds.some((objectId) => {
39679
+ const object = scene.objects.find((entry) => entry.objectId === objectId)?.object;
39680
+ return object ? isStructureLike(object) : false;
39681
+ })).map((trajectory) => {
39682
+ const stroke = trajectory.stroke ?? "#f0b464";
39683
+ const markerEnd = trajectory.marker === "none" ? "" : ` marker-end="url(#wo-trajectory-arrow)"`;
39684
+ const waypointMarkup = trajectory.showWaypoints && options.showWaypoints ? trajectory.waypoints.filter((waypoint) => !waypoint.hidden).map((waypoint) => renderTrajectoryWaypoint(trajectory, waypoint, options.showLabels)).join("") : "";
39685
+ return `<g class="wo-trajectory-group" data-render-id="${escapeXml(trajectory.renderId)}" data-trajectory-id="${escapeAttribute(trajectory.trajectoryId)}">
39686
+ <path class="wo-trajectory wo-trajectory-${trajectory.mode}" d="${trajectory.path}" stroke="${escapeAttribute(stroke)}" stroke-width="${trajectory.strokeWidth}"${markerEnd} />
39687
+ ${waypointMarkup}
39688
+ </g>`;
39689
+ }).join("");
39690
+ }
39691
+ function renderTrajectoryWaypoint(trajectory, waypoint, showLabels) {
39692
+ const labelMarkup = showLabels && trajectory.labelMode !== "hidden" ? [
39693
+ waypoint.label ? `<text class="wo-trajectory-label" x="${waypoint.x + 10}" y="${waypoint.y - 10}" font-size="10">${escapeXml(waypoint.label)}</text>` : "",
39694
+ waypoint.dateLabel ? `<text class="wo-trajectory-date" x="${waypoint.x + 10}" y="${waypoint.y + 4}" font-size="9">${escapeXml(waypoint.dateLabel)}</text>` : ""
39695
+ ].join("") : "";
39696
+ return `<g class="wo-trajectory-waypoint-group" data-render-id="${escapeXml(waypoint.renderId)}" data-trajectory-id="${escapeAttribute(waypoint.trajectoryId)}">
39697
+ <circle class="wo-trajectory-waypoint" cx="${waypoint.x}" cy="${waypoint.y}" r="4.5" />
39698
+ ${labelMarkup}
39699
+ </g>`;
39700
+ }
39274
39701
  function renderDocumentToSvg(document2, options = {}) {
39275
39702
  return renderSceneToSvg(renderDocumentToScene(document2, options), options);
39276
39703
  }
@@ -42231,6 +42658,33 @@ void main() {
42231
42658
  hidden: orbit.hidden,
42232
42659
  motion: null
42233
42660
  })),
42661
+ trajectories: scene.trajectories.map((trajectory) => ({
42662
+ trajectoryId: trajectory.trajectoryId,
42663
+ trajectory: trajectory.trajectory,
42664
+ craftObjectId: trajectory.craftObjectId,
42665
+ mode: trajectory.mode,
42666
+ stroke: trajectory.stroke,
42667
+ strokeWidth: trajectory.strokeWidth,
42668
+ marker: trajectory.marker,
42669
+ labelMode: trajectory.labelMode,
42670
+ showWaypoints: trajectory.showWaypoints,
42671
+ samples: [],
42672
+ waypoints: trajectory.waypoints.map((waypoint) => ({
42673
+ trajectoryId: waypoint.trajectoryId,
42674
+ segmentId: waypoint.segmentId,
42675
+ maneuverId: waypoint.maneuverId,
42676
+ objectId: waypoint.objectId,
42677
+ position: {
42678
+ x: waypoint.x - scene.contentBounds.centerX,
42679
+ y: 0,
42680
+ z: waypoint.y - scene.contentBounds.centerY
42681
+ },
42682
+ label: waypoint.label,
42683
+ dateLabel: waypoint.dateLabel,
42684
+ hidden: waypoint.hidden
42685
+ })),
42686
+ hidden: trajectory.hidden
42687
+ })),
42234
42688
  focusTargets: scene.objects.map((object) => ({
42235
42689
  objectId: object.objectId,
42236
42690
  center: {