worldorbit 3.2.2 → 4.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.
- package/README.md +546 -545
- package/dist/browser/core/dist/atlas-edit.js +146 -1
- package/dist/browser/core/dist/atlas-validate.js +105 -10
- package/dist/browser/core/dist/draft-parse.js +341 -16
- package/dist/browser/core/dist/draft.d.ts +2 -1
- package/dist/browser/core/dist/draft.js +25 -3
- package/dist/browser/core/dist/format.js +86 -4
- package/dist/browser/core/dist/index.d.ts +1 -0
- package/dist/browser/core/dist/index.js +1 -0
- package/dist/browser/core/dist/load.js +7 -2
- package/dist/browser/core/dist/normalize.js +1 -0
- package/dist/browser/core/dist/scene.js +11 -2
- package/dist/browser/core/dist/schema.js +11 -1
- package/dist/browser/core/dist/solver.d.ts +26 -0
- package/dist/browser/core/dist/solver.js +27 -0
- package/dist/browser/core/dist/types.d.ts +57 -3
- package/dist/browser/editor/dist/editor.js +844 -719
- package/dist/browser/editor/dist/types.d.ts +2 -1
- package/dist/browser/viewer/dist/minimap.js +9 -7
- package/dist/browser/viewer/dist/render.js +23 -19
- package/dist/browser/viewer/dist/runtime-3d.js +2 -0
- package/dist/browser/viewer/dist/viewer.js +7 -3
- package/dist/obsidian-plugin/README.md +141 -124
- package/dist/obsidian-plugin/main.js +31 -31
- package/dist/unpkg/core/dist/atlas-edit.js +146 -1
- package/dist/unpkg/core/dist/atlas-validate.js +105 -10
- package/dist/unpkg/core/dist/draft-parse.js +341 -16
- package/dist/unpkg/core/dist/draft.d.ts +2 -1
- package/dist/unpkg/core/dist/draft.js +25 -3
- package/dist/unpkg/core/dist/format.js +86 -4
- package/dist/unpkg/core/dist/index.d.ts +1 -0
- package/dist/unpkg/core/dist/index.js +1 -0
- package/dist/unpkg/core/dist/load.js +7 -2
- package/dist/unpkg/core/dist/normalize.js +1 -0
- package/dist/unpkg/core/dist/scene.js +11 -2
- package/dist/unpkg/core/dist/schema.js +11 -1
- package/dist/unpkg/core/dist/solver.d.ts +26 -0
- package/dist/unpkg/core/dist/solver.js +27 -0
- package/dist/unpkg/core/dist/types.d.ts +57 -3
- package/dist/unpkg/editor/dist/editor.js +844 -719
- package/dist/unpkg/editor/dist/types.d.ts +2 -1
- package/dist/unpkg/viewer/dist/minimap.js +9 -7
- package/dist/unpkg/viewer/dist/render.js +23 -19
- package/dist/unpkg/viewer/dist/runtime-3d.js +2 -0
- package/dist/unpkg/viewer/dist/viewer.js +7 -3
- package/dist/unpkg/worldorbit-core.min.js +10 -10
- package/dist/unpkg/worldorbit-editor.min.js +359 -332
- package/dist/unpkg/worldorbit-markdown.min.js +28 -28
- package/dist/unpkg/worldorbit-viewer.min.js +214 -214
- package/dist/unpkg/worldorbit.js +758 -40
- package/dist/unpkg/worldorbit.min.js +223 -223
- package/package.json +5 -1
- package/packages/core/dist/atlas-edit.js +146 -1
- package/packages/core/dist/atlas-validate.js +105 -10
- package/packages/core/dist/draft-parse.js +341 -16
- package/packages/core/dist/draft.d.ts +2 -1
- package/packages/core/dist/draft.js +25 -3
- package/packages/core/dist/format.js +86 -4
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/load.js +7 -2
- package/packages/core/dist/normalize.js +1 -0
- package/packages/core/dist/scene.js +11 -2
- package/packages/core/dist/schema.js +11 -1
- package/packages/core/dist/solver.d.ts +26 -0
- package/packages/core/dist/solver.js +27 -0
- package/packages/core/dist/types.d.ts +57 -3
- package/packages/editor/dist/editor.js +844 -719
- package/packages/editor/dist/types.d.ts +2 -1
- package/packages/viewer/dist/minimap.js +9 -7
- package/packages/viewer/dist/render.js +23 -19
- package/packages/viewer/dist/runtime-3d.js +2 -0
- package/packages/viewer/dist/viewer.js +7 -3
|
@@ -8,6 +8,14 @@ const STRUCTURED_TYPED_BLOCKS = new Set([
|
|
|
8
8
|
"habitability",
|
|
9
9
|
"settlement",
|
|
10
10
|
]);
|
|
11
|
+
const TRAJECTORY_SEGMENT_KINDS = new Set([
|
|
12
|
+
"departure",
|
|
13
|
+
"transfer",
|
|
14
|
+
"flyby",
|
|
15
|
+
"capture",
|
|
16
|
+
"stationkeeping",
|
|
17
|
+
"escape",
|
|
18
|
+
]);
|
|
11
19
|
const DRAFT_OBJECT_FIELD_SPECS = new Map();
|
|
12
20
|
for (const key of [
|
|
13
21
|
"orbit",
|
|
@@ -40,6 +48,7 @@ for (const key of [
|
|
|
40
48
|
"on",
|
|
41
49
|
"source",
|
|
42
50
|
"cycle",
|
|
51
|
+
"trajectory",
|
|
43
52
|
]) {
|
|
44
53
|
const schema = getFieldSchema(key);
|
|
45
54
|
if (schema) {
|
|
@@ -65,10 +74,11 @@ for (const spec of [
|
|
|
65
74
|
{ key: "validate", inlineMode: "single", allowRepeat: true },
|
|
66
75
|
{ key: "locked", inlineMode: "multiple", allowRepeat: false },
|
|
67
76
|
{ key: "tolerance", inlineMode: "pair", allowRepeat: true },
|
|
77
|
+
{ key: "trajectory", inlineMode: "single", allowRepeat: false },
|
|
68
78
|
]) {
|
|
69
79
|
DRAFT_OBJECT_FIELD_SPECS.set(spec.key, {
|
|
70
80
|
key: spec.key,
|
|
71
|
-
version: "2.1",
|
|
81
|
+
version: spec.key === "trajectory" ? "3.0" : "2.1",
|
|
72
82
|
inlineMode: spec.inlineMode,
|
|
73
83
|
allowRepeat: spec.allowRepeat,
|
|
74
84
|
});
|
|
@@ -90,6 +100,8 @@ const EVENT_POSE_FIELD_KEYS = new Set([
|
|
|
90
100
|
"outer",
|
|
91
101
|
"epoch",
|
|
92
102
|
"referencePlane",
|
|
103
|
+
"segment",
|
|
104
|
+
"maneuver",
|
|
93
105
|
]);
|
|
94
106
|
export function parseWorldOrbitAtlas(source) {
|
|
95
107
|
return parseAtlasSource(source);
|
|
@@ -109,6 +121,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
109
121
|
const groups = [];
|
|
110
122
|
const relations = [];
|
|
111
123
|
const events = [];
|
|
124
|
+
const trajectories = [];
|
|
112
125
|
const eventPoseNodes = new Map();
|
|
113
126
|
let sawDefaults = false;
|
|
114
127
|
let sawAtlas = false;
|
|
@@ -117,6 +130,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
117
130
|
const groupIds = new Set();
|
|
118
131
|
const relationIds = new Set();
|
|
119
132
|
const eventIds = new Set();
|
|
133
|
+
const trajectoryIds = new Set();
|
|
120
134
|
for (let index = 0; index < lines.length; index++) {
|
|
121
135
|
const rawLine = lines[index];
|
|
122
136
|
const lineNumber = index + 1;
|
|
@@ -147,7 +161,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
147
161
|
continue;
|
|
148
162
|
}
|
|
149
163
|
if (indent === 0) {
|
|
150
|
-
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
164
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, trajectories, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, trajectoryIds, { sawDefaults, sawAtlas });
|
|
151
165
|
if (section.kind === "system") {
|
|
152
166
|
system = section.system;
|
|
153
167
|
}
|
|
@@ -165,7 +179,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
165
179
|
handleSectionLine(section, indent, tokens, lineNumber);
|
|
166
180
|
}
|
|
167
181
|
if (!sawSchemaHeader) {
|
|
168
|
-
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
182
|
+
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0" or "schema 3.0"');
|
|
169
183
|
}
|
|
170
184
|
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
171
185
|
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
@@ -179,6 +193,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
179
193
|
groups,
|
|
180
194
|
relations,
|
|
181
195
|
events: normalizedEvents,
|
|
196
|
+
trajectories,
|
|
182
197
|
objects,
|
|
183
198
|
diagnostics,
|
|
184
199
|
};
|
|
@@ -210,21 +225,23 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
210
225
|
function assertDraftSchemaHeader(tokens, line) {
|
|
211
226
|
if (tokens.length !== 2 ||
|
|
212
227
|
tokens[0].value.toLowerCase() !== "schema" ||
|
|
213
|
-
!["2.0-draft", "2.0", "2.1", "2.5", "2.6"].includes(tokens[1].value.toLowerCase())) {
|
|
214
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", "schema 2.6", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
228
|
+
!["2.0-draft", "2.0", "2.1", "2.5", "2.6", "3.0"].includes(tokens[1].value.toLowerCase())) {
|
|
229
|
+
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);
|
|
215
230
|
}
|
|
216
231
|
const version = tokens[1].value.toLowerCase();
|
|
217
232
|
return version === "2.6"
|
|
218
233
|
? "2.6"
|
|
219
|
-
: version === "
|
|
220
|
-
? "
|
|
221
|
-
: version === "2.
|
|
222
|
-
? "2.
|
|
223
|
-
: version === "2.
|
|
224
|
-
? "2.
|
|
225
|
-
: "2.0"
|
|
226
|
-
|
|
227
|
-
|
|
234
|
+
: version === "3.0"
|
|
235
|
+
? "3.0"
|
|
236
|
+
: version === "2.5"
|
|
237
|
+
? "2.5"
|
|
238
|
+
: version === "2.1"
|
|
239
|
+
? "2.1"
|
|
240
|
+
: version === "2.0-draft"
|
|
241
|
+
? "2.0-draft"
|
|
242
|
+
: "2.0";
|
|
243
|
+
}
|
|
244
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, trajectories, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, trajectoryIds, flags) {
|
|
228
245
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
229
246
|
switch (keyword) {
|
|
230
247
|
case "system":
|
|
@@ -278,6 +295,9 @@ function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, sy
|
|
|
278
295
|
case "event":
|
|
279
296
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
280
297
|
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
298
|
+
case "trajectory":
|
|
299
|
+
warnIfSchema30Feature(sourceSchemaVersion, diagnostics, "trajectory", { line, column: tokens[0].column });
|
|
300
|
+
return startTrajectorySection(tokens, line, trajectories, trajectoryIds, sourceSchemaVersion, diagnostics);
|
|
281
301
|
case "object":
|
|
282
302
|
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
283
303
|
default:
|
|
@@ -485,6 +505,45 @@ function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourc
|
|
|
485
505
|
activePoseSeenFields: new Set(),
|
|
486
506
|
};
|
|
487
507
|
}
|
|
508
|
+
function startTrajectorySection(tokens, line, trajectories, trajectoryIds, sourceSchemaVersion, diagnostics) {
|
|
509
|
+
if (tokens.length !== 2) {
|
|
510
|
+
throw new WorldOrbitError("Invalid trajectory declaration", line, tokens[0]?.column ?? 1);
|
|
511
|
+
}
|
|
512
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
513
|
+
if (!id) {
|
|
514
|
+
throw new WorldOrbitError("Trajectory id must not be empty", line, tokens[1].column);
|
|
515
|
+
}
|
|
516
|
+
if (trajectoryIds.has(id)) {
|
|
517
|
+
throw new WorldOrbitError(`Duplicate trajectory id "${id}"`, line, tokens[1].column);
|
|
518
|
+
}
|
|
519
|
+
const trajectory = {
|
|
520
|
+
id,
|
|
521
|
+
label: humanizeIdentifier(id),
|
|
522
|
+
summary: null,
|
|
523
|
+
craftObjectId: null,
|
|
524
|
+
tags: [],
|
|
525
|
+
color: null,
|
|
526
|
+
hidden: false,
|
|
527
|
+
segments: [],
|
|
528
|
+
};
|
|
529
|
+
trajectories.push(trajectory);
|
|
530
|
+
trajectoryIds.add(id);
|
|
531
|
+
return {
|
|
532
|
+
kind: "trajectory",
|
|
533
|
+
trajectory,
|
|
534
|
+
sourceSchemaVersion,
|
|
535
|
+
diagnostics,
|
|
536
|
+
seenFields: new Set(),
|
|
537
|
+
inSegment: false,
|
|
538
|
+
segmentIndent: null,
|
|
539
|
+
activeSegment: null,
|
|
540
|
+
activeSegmentSeenFields: new Set(),
|
|
541
|
+
inManeuver: false,
|
|
542
|
+
maneuverIndent: null,
|
|
543
|
+
activeManeuver: null,
|
|
544
|
+
activeManeuverSeenFields: new Set(),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
488
547
|
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
489
548
|
if (tokens.length < 3) {
|
|
490
549
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
@@ -544,6 +603,9 @@ function handleSectionLine(section, indent, tokens, line) {
|
|
|
544
603
|
case "event":
|
|
545
604
|
applyEventField(section, indent, tokens, line);
|
|
546
605
|
return;
|
|
606
|
+
case "trajectory":
|
|
607
|
+
applyTrajectoryField(section, indent, tokens, line);
|
|
608
|
+
return;
|
|
547
609
|
case "object":
|
|
548
610
|
applyObjectField(section, indent, tokens, line);
|
|
549
611
|
return;
|
|
@@ -863,6 +925,13 @@ function applyEventField(section, indent, tokens, line) {
|
|
|
863
925
|
column: tokens[0]?.column ?? 1,
|
|
864
926
|
});
|
|
865
927
|
}
|
|
928
|
+
if (tokens[0]?.value === "segment" ||
|
|
929
|
+
tokens[0]?.value === "maneuver") {
|
|
930
|
+
warnIfSchema30Feature(section.sourceSchemaVersion, section.diagnostics, `pose.${tokens[0].value}`, {
|
|
931
|
+
line,
|
|
932
|
+
column: tokens[0]?.column ?? 1,
|
|
933
|
+
});
|
|
934
|
+
}
|
|
866
935
|
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
867
936
|
return;
|
|
868
937
|
}
|
|
@@ -905,6 +974,13 @@ function applyEventField(section, indent, tokens, line) {
|
|
|
905
974
|
case "summary":
|
|
906
975
|
section.event.summary = joinFieldValue(tokens, line);
|
|
907
976
|
return;
|
|
977
|
+
case "trajectory":
|
|
978
|
+
warnIfSchema30Feature(section.sourceSchemaVersion, section.diagnostics, "event.trajectory", {
|
|
979
|
+
line,
|
|
980
|
+
column: tokens[0].column,
|
|
981
|
+
});
|
|
982
|
+
section.event.trajectoryId = joinFieldValue(tokens, line);
|
|
983
|
+
return;
|
|
908
984
|
case "target":
|
|
909
985
|
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
910
986
|
return;
|
|
@@ -947,6 +1023,219 @@ function applyEventField(section, indent, tokens, line) {
|
|
|
947
1023
|
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
948
1024
|
}
|
|
949
1025
|
}
|
|
1026
|
+
function applyTrajectoryField(section, indent, tokens, line) {
|
|
1027
|
+
if (section.activeManeuver && indent <= (section.maneuverIndent ?? 0)) {
|
|
1028
|
+
section.activeManeuver = null;
|
|
1029
|
+
section.maneuverIndent = null;
|
|
1030
|
+
section.activeManeuverSeenFields.clear();
|
|
1031
|
+
section.inManeuver = false;
|
|
1032
|
+
}
|
|
1033
|
+
if (section.activeSegment && indent <= (section.segmentIndent ?? 0)) {
|
|
1034
|
+
section.activeSegment = null;
|
|
1035
|
+
section.segmentIndent = null;
|
|
1036
|
+
section.activeSegmentSeenFields.clear();
|
|
1037
|
+
section.inSegment = false;
|
|
1038
|
+
}
|
|
1039
|
+
if (section.activeManeuver) {
|
|
1040
|
+
applyTrajectoryManeuverField(section, tokens, line);
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
if (section.activeSegment) {
|
|
1044
|
+
if (tokens[0]?.value.toLowerCase() === "maneuver") {
|
|
1045
|
+
if (tokens.length !== 2) {
|
|
1046
|
+
throw new WorldOrbitError("Invalid trajectory maneuver declaration", line, tokens[0]?.column ?? 1);
|
|
1047
|
+
}
|
|
1048
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
1049
|
+
if (!id) {
|
|
1050
|
+
throw new WorldOrbitError("Trajectory maneuver id must not be empty", line, tokens[1].column);
|
|
1051
|
+
}
|
|
1052
|
+
if (section.activeSegment.maneuvers.some((maneuver) => maneuver.id === id)) {
|
|
1053
|
+
throw new WorldOrbitError(`Duplicate trajectory maneuver id "${id}"`, line, tokens[1].column);
|
|
1054
|
+
}
|
|
1055
|
+
const maneuver = {
|
|
1056
|
+
id,
|
|
1057
|
+
kind: "burn",
|
|
1058
|
+
label: null,
|
|
1059
|
+
epoch: null,
|
|
1060
|
+
notes: [],
|
|
1061
|
+
};
|
|
1062
|
+
section.activeSegment.maneuvers.push(maneuver);
|
|
1063
|
+
section.activeManeuver = maneuver;
|
|
1064
|
+
section.inManeuver = true;
|
|
1065
|
+
section.maneuverIndent = indent;
|
|
1066
|
+
section.activeManeuverSeenFields = new Set();
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
applyTrajectorySegmentField(section, tokens, line);
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
if (tokens[0]?.value.toLowerCase() === "segment") {
|
|
1073
|
+
if (tokens.length !== 2) {
|
|
1074
|
+
throw new WorldOrbitError("Invalid trajectory segment declaration", line, tokens[0]?.column ?? 1);
|
|
1075
|
+
}
|
|
1076
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
1077
|
+
if (!id) {
|
|
1078
|
+
throw new WorldOrbitError("Trajectory segment id must not be empty", line, tokens[1].column);
|
|
1079
|
+
}
|
|
1080
|
+
if (section.trajectory.segments.some((segment) => segment.id === id)) {
|
|
1081
|
+
throw new WorldOrbitError(`Duplicate trajectory segment id "${id}"`, line, tokens[1].column);
|
|
1082
|
+
}
|
|
1083
|
+
const segment = {
|
|
1084
|
+
id,
|
|
1085
|
+
kind: "transfer",
|
|
1086
|
+
label: null,
|
|
1087
|
+
summary: null,
|
|
1088
|
+
fromObjectId: null,
|
|
1089
|
+
toObjectId: null,
|
|
1090
|
+
aroundObjectId: null,
|
|
1091
|
+
assist: null,
|
|
1092
|
+
epoch: null,
|
|
1093
|
+
notes: [],
|
|
1094
|
+
maneuvers: [],
|
|
1095
|
+
};
|
|
1096
|
+
section.trajectory.segments.push(segment);
|
|
1097
|
+
section.activeSegment = {
|
|
1098
|
+
id,
|
|
1099
|
+
fields: [],
|
|
1100
|
+
maneuvers: segment.maneuvers,
|
|
1101
|
+
assist: null,
|
|
1102
|
+
location: { line, column: tokens[0].column },
|
|
1103
|
+
};
|
|
1104
|
+
section.inSegment = true;
|
|
1105
|
+
section.segmentIndent = indent;
|
|
1106
|
+
section.activeSegmentSeenFields = new Set();
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
1110
|
+
const value = joinFieldValue(tokens, line);
|
|
1111
|
+
switch (key) {
|
|
1112
|
+
case "label":
|
|
1113
|
+
section.trajectory.label = value;
|
|
1114
|
+
return;
|
|
1115
|
+
case "summary":
|
|
1116
|
+
section.trajectory.summary = value;
|
|
1117
|
+
return;
|
|
1118
|
+
case "craft":
|
|
1119
|
+
section.trajectory.craftObjectId = value;
|
|
1120
|
+
return;
|
|
1121
|
+
case "tags":
|
|
1122
|
+
section.trajectory.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
1123
|
+
return;
|
|
1124
|
+
case "color":
|
|
1125
|
+
section.trajectory.color = value;
|
|
1126
|
+
return;
|
|
1127
|
+
case "hidden":
|
|
1128
|
+
section.trajectory.hidden = parseAtlasBoolean(value, "hidden", {
|
|
1129
|
+
line,
|
|
1130
|
+
column: tokens[0].column,
|
|
1131
|
+
});
|
|
1132
|
+
return;
|
|
1133
|
+
default:
|
|
1134
|
+
throw new WorldOrbitError(`Unknown trajectory field "${tokens[0].value}"`, line, tokens[0].column);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
function applyTrajectorySegmentField(section, tokens, line) {
|
|
1138
|
+
const segment = section.activeSegment;
|
|
1139
|
+
if (!segment) {
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
const key = requireUniqueField(tokens, section.activeSegmentSeenFields, line);
|
|
1143
|
+
const value = joinFieldValue(tokens, line);
|
|
1144
|
+
const target = section.trajectory.segments.find((entry) => entry.id === segment.id);
|
|
1145
|
+
switch (key) {
|
|
1146
|
+
case "kind": {
|
|
1147
|
+
const normalized = value.toLowerCase();
|
|
1148
|
+
if (!TRAJECTORY_SEGMENT_KINDS.has(normalized)) {
|
|
1149
|
+
throw new WorldOrbitError(`Unknown trajectory segment kind "${value}"`, line, tokens[0].column);
|
|
1150
|
+
}
|
|
1151
|
+
target.kind = normalized;
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
case "label":
|
|
1155
|
+
target.label = value;
|
|
1156
|
+
return;
|
|
1157
|
+
case "summary":
|
|
1158
|
+
target.summary = value;
|
|
1159
|
+
return;
|
|
1160
|
+
case "from":
|
|
1161
|
+
target.fromObjectId = value;
|
|
1162
|
+
return;
|
|
1163
|
+
case "to":
|
|
1164
|
+
target.toObjectId = value;
|
|
1165
|
+
return;
|
|
1166
|
+
case "around":
|
|
1167
|
+
target.aroundObjectId = value;
|
|
1168
|
+
return;
|
|
1169
|
+
case "assist":
|
|
1170
|
+
target.assist = {
|
|
1171
|
+
objectId: value,
|
|
1172
|
+
notes: [],
|
|
1173
|
+
};
|
|
1174
|
+
return;
|
|
1175
|
+
case "epoch":
|
|
1176
|
+
target.epoch = value;
|
|
1177
|
+
return;
|
|
1178
|
+
case "periapsis":
|
|
1179
|
+
target.periapsis = parseAtlasUnitValue(value, { line, column: tokens[0].column }, "periapsis");
|
|
1180
|
+
return;
|
|
1181
|
+
case "apoapsis":
|
|
1182
|
+
target.apoapsis = parseAtlasUnitValue(value, { line, column: tokens[0].column }, "apoapsis");
|
|
1183
|
+
return;
|
|
1184
|
+
case "inclination":
|
|
1185
|
+
target.inclination = parseAtlasUnitValue(value, { line, column: tokens[0].column }, "inclination");
|
|
1186
|
+
return;
|
|
1187
|
+
case "duration":
|
|
1188
|
+
target.duration = parseAtlasUnitValue(value, { line, column: tokens[0].column }, "duration");
|
|
1189
|
+
return;
|
|
1190
|
+
case "deltav":
|
|
1191
|
+
target.deltaV = parseAtlasUnitValue(value, { line, column: tokens[0].column });
|
|
1192
|
+
return;
|
|
1193
|
+
case "phaseangle":
|
|
1194
|
+
target.phaseAngle = parseAtlasUnitValue(value, { line, column: tokens[0].column }, "phaseAngle");
|
|
1195
|
+
return;
|
|
1196
|
+
case "turnangle":
|
|
1197
|
+
target.turnAngle = parseAtlasUnitValue(value, { line, column: tokens[0].column }, "turnAngle");
|
|
1198
|
+
return;
|
|
1199
|
+
case "energy":
|
|
1200
|
+
target.energy = parseAtlasUnitValue(value, { line, column: tokens[0].column });
|
|
1201
|
+
return;
|
|
1202
|
+
case "notes":
|
|
1203
|
+
target.notes = parseTokenList(tokens.slice(1), line, "notes");
|
|
1204
|
+
return;
|
|
1205
|
+
default:
|
|
1206
|
+
throw new WorldOrbitError(`Unknown trajectory segment field "${tokens[0].value}"`, line, tokens[0].column);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
function applyTrajectoryManeuverField(section, tokens, line) {
|
|
1210
|
+
const maneuver = section.activeManeuver;
|
|
1211
|
+
if (!maneuver) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
const key = requireUniqueField(tokens, section.activeManeuverSeenFields, line);
|
|
1215
|
+
const value = joinFieldValue(tokens, line);
|
|
1216
|
+
switch (key) {
|
|
1217
|
+
case "kind":
|
|
1218
|
+
maneuver.kind = value;
|
|
1219
|
+
return;
|
|
1220
|
+
case "label":
|
|
1221
|
+
maneuver.label = value;
|
|
1222
|
+
return;
|
|
1223
|
+
case "epoch":
|
|
1224
|
+
maneuver.epoch = value;
|
|
1225
|
+
return;
|
|
1226
|
+
case "deltav":
|
|
1227
|
+
maneuver.deltaV = parseAtlasUnitValue(value, { line, column: tokens[0].column });
|
|
1228
|
+
return;
|
|
1229
|
+
case "duration":
|
|
1230
|
+
maneuver.duration = parseAtlasUnitValue(value, { line, column: tokens[0].column }, "duration");
|
|
1231
|
+
return;
|
|
1232
|
+
case "notes":
|
|
1233
|
+
maneuver.notes = parseTokenList(tokens.slice(1), line, "notes");
|
|
1234
|
+
return;
|
|
1235
|
+
default:
|
|
1236
|
+
throw new WorldOrbitError(`Unknown trajectory maneuver field "${tokens[0].value}"`, line, tokens[0].column);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
950
1239
|
function parseEventPoseField(tokens, line, seenFields) {
|
|
951
1240
|
if (tokens.length < 2) {
|
|
952
1241
|
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
@@ -1181,6 +1470,12 @@ function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion,
|
|
|
1181
1470
|
column: keyToken.column,
|
|
1182
1471
|
});
|
|
1183
1472
|
}
|
|
1473
|
+
else if (spec.version === "3.0") {
|
|
1474
|
+
warnIfSchema30Feature(sourceSchemaVersion, diagnostics, keyToken.value, {
|
|
1475
|
+
line,
|
|
1476
|
+
column: keyToken.column,
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1184
1479
|
index++;
|
|
1185
1480
|
const valueTokens = [];
|
|
1186
1481
|
if (spec.inlineMode === "single") {
|
|
@@ -1233,6 +1528,12 @@ function parseObjectField(tokens, line, objectType, sourceSchemaVersion, diagnos
|
|
|
1233
1528
|
column: tokens[0].column,
|
|
1234
1529
|
});
|
|
1235
1530
|
}
|
|
1531
|
+
else if (spec.version === "3.0") {
|
|
1532
|
+
warnIfSchema30Feature(sourceSchemaVersion, diagnostics, tokens[0].value, {
|
|
1533
|
+
line,
|
|
1534
|
+
column: tokens[0].column,
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1236
1537
|
const field = {
|
|
1237
1538
|
type: "field",
|
|
1238
1539
|
key: tokens[0].value,
|
|
@@ -1277,6 +1578,7 @@ function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
|
1277
1578
|
const tolerances = fieldMap.get("tolerance")?.map((field) => parseToleranceField(field));
|
|
1278
1579
|
const typedBlocks = normalizeTypedBlocks(node.typedBlockEntries);
|
|
1279
1580
|
const info = normalizeInfoEntries(node.infoEntries, "info");
|
|
1581
|
+
const trajectoryId = parseOptionalJoinedValue(fieldMap.get("trajectory")?.[0]);
|
|
1280
1582
|
const object = {
|
|
1281
1583
|
type: node.objectType,
|
|
1282
1584
|
id: node.id,
|
|
@@ -1306,6 +1608,8 @@ function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
|
1306
1608
|
object.tolerances = tolerances;
|
|
1307
1609
|
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
1308
1610
|
object.typedBlocks = typedBlocks;
|
|
1611
|
+
if (trajectoryId)
|
|
1612
|
+
object.trajectoryId = trajectoryId;
|
|
1309
1613
|
if (isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
1310
1614
|
if (object.groups ||
|
|
1311
1615
|
object.epoch ||
|
|
@@ -1317,10 +1621,14 @@ function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
|
1317
1621
|
object.validationRules?.length ||
|
|
1318
1622
|
object.lockedFields?.length ||
|
|
1319
1623
|
object.tolerances?.length ||
|
|
1320
|
-
object.typedBlocks
|
|
1624
|
+
object.typedBlocks ||
|
|
1625
|
+
object.trajectoryId) {
|
|
1321
1626
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
1322
1627
|
}
|
|
1323
1628
|
}
|
|
1629
|
+
if (object.trajectoryId) {
|
|
1630
|
+
warnIfSchema30Feature(sourceSchemaVersion, diagnostics, `${node.id}.trajectory`, node.location);
|
|
1631
|
+
}
|
|
1324
1632
|
return object;
|
|
1325
1633
|
}
|
|
1326
1634
|
function normalizeDraftEvent(event, rawPoses) {
|
|
@@ -1337,6 +1645,8 @@ function normalizeDraftEventPose(rawPose) {
|
|
|
1337
1645
|
return {
|
|
1338
1646
|
objectId: rawPose.objectId,
|
|
1339
1647
|
placement,
|
|
1648
|
+
trajectorySegmentId: parseOptionalJoinedValue(fieldMap.get("segment")?.[0]),
|
|
1649
|
+
trajectoryManeuverId: parseOptionalJoinedValue(fieldMap.get("maneuver")?.[0]),
|
|
1340
1650
|
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
1341
1651
|
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer"),
|
|
1342
1652
|
epoch: parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]),
|
|
@@ -1553,6 +1863,19 @@ function warnIfSchema25Feature(sourceSchemaVersion, diagnostics, featureName, lo
|
|
|
1553
1863
|
column: location.column,
|
|
1554
1864
|
});
|
|
1555
1865
|
}
|
|
1866
|
+
function warnIfSchema30Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
1867
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "3.0")) {
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
diagnostics.push({
|
|
1871
|
+
code: "parse.schema30.featureCompatibility",
|
|
1872
|
+
severity: "warning",
|
|
1873
|
+
source: "parse",
|
|
1874
|
+
message: `Feature "${featureName}" requires schema 3.0; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
1875
|
+
line: location.line,
|
|
1876
|
+
column: location.column,
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1556
1879
|
function isSchemaOlderThan(sourceSchemaVersion, requiredVersion) {
|
|
1557
1880
|
return schemaVersionRank(sourceSchemaVersion) < schemaVersionRank(requiredVersion);
|
|
1558
1881
|
}
|
|
@@ -1568,8 +1891,10 @@ function schemaVersionRank(version) {
|
|
|
1568
1891
|
return 3;
|
|
1569
1892
|
case "2.6":
|
|
1570
1893
|
return 4;
|
|
1571
|
-
|
|
1894
|
+
case "3.0":
|
|
1572
1895
|
return 5;
|
|
1896
|
+
default:
|
|
1897
|
+
return 6;
|
|
1573
1898
|
}
|
|
1574
1899
|
}
|
|
1575
1900
|
function preprocessAtlasSource(source) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SceneRenderOptions, WorldOrbitAtlasDocument, WorldOrbitEvent, WorldOrbitAtlasSystem, WorldOrbitDiagnostic, WorldOrbitDocument, WorldOrbitObject } from "./types.js";
|
|
1
|
+
import type { SceneRenderOptions, WorldOrbitAtlasDocument, WorldOrbitEvent, WorldOrbitAtlasSystem, WorldOrbitDiagnostic, WorldOrbitDocument, WorldOrbitObject, WorldOrbitTrajectory } from "./types.js";
|
|
2
2
|
interface UpgradeOptions extends Pick<SceneRenderOptions, "preset" | "projection"> {
|
|
3
3
|
}
|
|
4
4
|
export declare function upgradeDocumentToV2(document: WorldOrbitDocument, options?: UpgradeOptions): WorldOrbitAtlasDocument;
|
|
@@ -12,6 +12,7 @@ export declare function upgradeDocumentToDraftV2(document: WorldOrbitDocument, o
|
|
|
12
12
|
groups: import("./types.js").WorldOrbitGroup[];
|
|
13
13
|
relations: import("./types.js").WorldOrbitRelation[];
|
|
14
14
|
events: WorldOrbitEvent[];
|
|
15
|
+
trajectories: WorldOrbitTrajectory[];
|
|
15
16
|
objects: WorldOrbitObject[];
|
|
16
17
|
diagnostics: WorldOrbitDiagnostic[];
|
|
17
18
|
};
|
|
@@ -18,15 +18,16 @@ export function upgradeDocumentToV2(document, options = {}) {
|
|
|
18
18
|
}
|
|
19
19
|
return {
|
|
20
20
|
format: "worldorbit",
|
|
21
|
-
version: "
|
|
22
|
-
schemaVersion: "
|
|
21
|
+
version: "3.0",
|
|
22
|
+
schemaVersion: "3.0",
|
|
23
23
|
sourceVersion: document.version,
|
|
24
24
|
theme: document.theme ?? null,
|
|
25
25
|
system,
|
|
26
26
|
groups: structuredClone(document.groups ?? []),
|
|
27
27
|
relations: structuredClone(document.relations ?? []),
|
|
28
28
|
events: structuredClone(document.events ?? []),
|
|
29
|
-
|
|
29
|
+
trajectories: [],
|
|
30
|
+
objects: document.objects.map(cloneWorldOrbitObject).map(normalizeLegacyCraftObject),
|
|
30
31
|
diagnostics,
|
|
31
32
|
};
|
|
32
33
|
}
|
|
@@ -57,6 +58,7 @@ export function materializeAtlasDocument(document, options = {}) {
|
|
|
57
58
|
groups: structuredClone(document.groups ?? []),
|
|
58
59
|
relations: structuredClone(document.relations ?? []),
|
|
59
60
|
events: document.events.map(cloneWorldOrbitEvent),
|
|
61
|
+
trajectories: document.trajectories.map(cloneWorldOrbitTrajectory),
|
|
60
62
|
objects,
|
|
61
63
|
};
|
|
62
64
|
}
|
|
@@ -226,6 +228,7 @@ function mapSceneViewpointToDraftViewpoint(viewpoint) {
|
|
|
226
228
|
function cloneWorldOrbitObject(object) {
|
|
227
229
|
return {
|
|
228
230
|
...object,
|
|
231
|
+
trajectoryId: object.trajectoryId ?? null,
|
|
229
232
|
groups: object.groups ? [...object.groups] : undefined,
|
|
230
233
|
resonance: object.resonance ? { ...object.resonance } : object.resonance,
|
|
231
234
|
renderHints: object.renderHints ? { ...object.renderHints } : object.renderHints,
|
|
@@ -255,6 +258,7 @@ function cloneWorldOrbitObject(object) {
|
|
|
255
258
|
function cloneWorldOrbitEvent(event) {
|
|
256
259
|
return {
|
|
257
260
|
...event,
|
|
261
|
+
trajectoryId: event.trajectoryId ?? null,
|
|
258
262
|
participantObjectIds: [...event.participantObjectIds],
|
|
259
263
|
tags: [...event.tags],
|
|
260
264
|
positions: event.positions.map(cloneWorldOrbitEventPose),
|
|
@@ -264,12 +268,30 @@ function cloneWorldOrbitEventPose(pose) {
|
|
|
264
268
|
return {
|
|
265
269
|
objectId: pose.objectId,
|
|
266
270
|
placement: clonePlacement(pose.placement),
|
|
271
|
+
trajectorySegmentId: pose.trajectorySegmentId ?? null,
|
|
272
|
+
trajectoryManeuverId: pose.trajectoryManeuverId ?? null,
|
|
267
273
|
inner: pose.inner ? { ...pose.inner } : undefined,
|
|
268
274
|
outer: pose.outer ? { ...pose.outer } : undefined,
|
|
269
275
|
epoch: pose.epoch ?? null,
|
|
270
276
|
referencePlane: pose.referencePlane ?? null,
|
|
271
277
|
};
|
|
272
278
|
}
|
|
279
|
+
function cloneWorldOrbitTrajectory(trajectory) {
|
|
280
|
+
return structuredClone(trajectory);
|
|
281
|
+
}
|
|
282
|
+
function normalizeLegacyCraftObject(object) {
|
|
283
|
+
if (object.type !== "structure") {
|
|
284
|
+
return object;
|
|
285
|
+
}
|
|
286
|
+
const kind = typeof object.properties.kind === "string" ? object.properties.kind.toLowerCase() : "";
|
|
287
|
+
if (!["ship", "probe", "station"].includes(kind)) {
|
|
288
|
+
return object;
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
...object,
|
|
292
|
+
type: "craft",
|
|
293
|
+
};
|
|
294
|
+
}
|
|
273
295
|
function clonePlacement(placement) {
|
|
274
296
|
return placement ? structuredClone(placement) : null;
|
|
275
297
|
}
|