worldorbit 2.5.15 → 2.5.17
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/browser/core/dist/index.js +2444 -342
- package/dist/browser/editor/dist/index.js +11702 -0
- package/dist/browser/markdown/dist/index.js +2207 -392
- package/dist/browser/viewer/dist/index.js +2302 -382
- package/dist/unpkg/core/dist/index.js +2447 -345
- package/dist/unpkg/editor/dist/index.js +11727 -0
- package/dist/unpkg/markdown/dist/index.js +2210 -395
- package/dist/unpkg/viewer/dist/index.js +2305 -385
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +894 -0
- package/dist/unpkg/worldorbit-markdown.min.js +66 -58
- package/dist/unpkg/worldorbit-viewer.min.js +76 -68
- package/dist/unpkg/worldorbit.js +797 -78
- package/dist/unpkg/worldorbit.min.js +80 -72
- package/package.json +3 -2
- package/packages/core/dist/atlas-edit.js +74 -0
- package/packages/core/dist/atlas-validate.js +122 -8
- package/packages/core/dist/draft-parse.js +212 -8
- package/packages/core/dist/draft.d.ts +5 -2
- package/packages/core/dist/draft.js +59 -3
- package/packages/core/dist/format.js +63 -1
- package/packages/core/dist/normalize.js +1 -0
- package/packages/core/dist/scene.js +248 -46
- package/packages/core/dist/types.d.ts +41 -2
- package/packages/editor/dist/editor.d.ts +2 -0
- package/packages/editor/dist/editor.js +3578 -0
- package/packages/editor/dist/index.d.ts +2 -0
- package/packages/editor/dist/index.js +1 -0
- package/packages/editor/dist/types.d.ts +55 -0
- package/packages/editor/dist/types.js +1 -0
- package/packages/markdown/dist/html.d.ts +3 -0
- package/packages/markdown/dist/html.js +57 -0
- package/packages/markdown/dist/index.d.ts +4 -0
- package/packages/markdown/dist/index.js +3 -0
- package/packages/markdown/dist/rehype.d.ts +10 -0
- package/packages/markdown/dist/rehype.js +49 -0
- package/packages/markdown/dist/remark.d.ts +9 -0
- package/packages/markdown/dist/remark.js +28 -0
- package/packages/markdown/dist/types.d.ts +11 -0
- package/packages/markdown/dist/types.js +1 -0
- package/packages/viewer/dist/atlas-state.js +6 -0
- package/packages/viewer/dist/atlas-viewer.js +1 -0
- package/packages/viewer/dist/render.js +31 -2
- package/packages/viewer/dist/theme.js +1 -0
- package/packages/viewer/dist/tooltip.js +9 -0
- package/packages/viewer/dist/types.d.ts +8 -1
- package/packages/viewer/dist/viewer.js +12 -1
|
@@ -19,8 +19,8 @@ var WorldOrbit = (() => {
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
|
|
21
21
|
// packages/core/dist/index.js
|
|
22
|
-
var
|
|
23
|
-
__export(
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
24
|
WORLDORBIT_FIELD_KEYS: () => WORLDORBIT_FIELD_KEYS,
|
|
25
25
|
WORLDORBIT_FIELD_SCHEMAS: () => WORLDORBIT_FIELD_SCHEMAS,
|
|
26
26
|
WORLDORBIT_OBJECT_TYPES: () => WORLDORBIT_OBJECT_TYPES,
|
|
@@ -373,13 +373,13 @@ var WorldOrbit = (() => {
|
|
|
373
373
|
function unitFamilyAllowsUnit(family, unit) {
|
|
374
374
|
switch (family) {
|
|
375
375
|
case "distance":
|
|
376
|
-
return unit === null || ["au", "km", "re", "sol"].includes(unit);
|
|
376
|
+
return unit === null || ["au", "km", "m", "ly", "pc", "kpc", "re", "sol"].includes(unit);
|
|
377
377
|
case "radius":
|
|
378
|
-
return unit === null || ["km", "re", "sol"].includes(unit);
|
|
378
|
+
return unit === null || ["km", "m", "re", "rj", "sol"].includes(unit);
|
|
379
379
|
case "mass":
|
|
380
|
-
return unit === null || ["me", "sol"].includes(unit);
|
|
380
|
+
return unit === null || ["me", "mj", "sol"].includes(unit);
|
|
381
381
|
case "duration":
|
|
382
|
-
return unit === null || ["h", "d", "y"].includes(unit);
|
|
382
|
+
return unit === null || ["s", "min", "h", "d", "y", "ky", "my", "gy"].includes(unit);
|
|
383
383
|
case "angle":
|
|
384
384
|
return unit === null || unit === "deg";
|
|
385
385
|
case "generic":
|
|
@@ -586,7 +586,7 @@ var WorldOrbit = (() => {
|
|
|
586
586
|
}
|
|
587
587
|
|
|
588
588
|
// packages/core/dist/normalize.js
|
|
589
|
-
var UNIT_PATTERN = /^(-?\d+(?:\.\d+)?)(au|km|re|sol|
|
|
589
|
+
var UNIT_PATTERN = /^(-?\d+(?:\.\d+)?)(kpc|min|mj|rj|ky|my|gy|au|km|me|re|pc|ly|deg|sol|K|m|s|h|d|y)?$/;
|
|
590
590
|
var BOOLEAN_VALUES = /* @__PURE__ */ new Map([
|
|
591
591
|
["true", true],
|
|
592
592
|
["false", false],
|
|
@@ -611,7 +611,11 @@ var WorldOrbit = (() => {
|
|
|
611
611
|
return {
|
|
612
612
|
format: "worldorbit",
|
|
613
613
|
version: "1.0",
|
|
614
|
+
schemaVersion: "1.0",
|
|
614
615
|
system,
|
|
616
|
+
groups: [],
|
|
617
|
+
relations: [],
|
|
618
|
+
events: [],
|
|
615
619
|
objects
|
|
616
620
|
};
|
|
617
621
|
}
|
|
@@ -621,13 +625,17 @@ var WorldOrbit = (() => {
|
|
|
621
625
|
const fieldMap = collectFields(mergedFields);
|
|
622
626
|
const placement = extractPlacement(node.objectType, fieldMap);
|
|
623
627
|
const properties = normalizeProperties(fieldMap);
|
|
624
|
-
const
|
|
628
|
+
const info2 = normalizeInfo(node.infoEntries);
|
|
625
629
|
if (node.objectType === "system") {
|
|
626
630
|
return {
|
|
627
631
|
type: "system",
|
|
628
632
|
id: node.name,
|
|
633
|
+
title: typeof properties.title === "string" ? properties.title : null,
|
|
634
|
+
description: null,
|
|
635
|
+
epoch: null,
|
|
636
|
+
referencePlane: null,
|
|
629
637
|
properties,
|
|
630
|
-
info
|
|
638
|
+
info: info2
|
|
631
639
|
};
|
|
632
640
|
}
|
|
633
641
|
return {
|
|
@@ -635,7 +643,7 @@ var WorldOrbit = (() => {
|
|
|
635
643
|
id: node.name,
|
|
636
644
|
properties,
|
|
637
645
|
placement,
|
|
638
|
-
info
|
|
646
|
+
info: info2
|
|
639
647
|
};
|
|
640
648
|
}
|
|
641
649
|
function validateFieldCompatibility(objectType, fields) {
|
|
@@ -765,14 +773,14 @@ var WorldOrbit = (() => {
|
|
|
765
773
|
}
|
|
766
774
|
}
|
|
767
775
|
function normalizeInfo(entries) {
|
|
768
|
-
const
|
|
776
|
+
const info2 = {};
|
|
769
777
|
for (const entry of entries) {
|
|
770
|
-
if (entry.key in
|
|
778
|
+
if (entry.key in info2) {
|
|
771
779
|
throw WorldOrbitError.fromLocation(`Duplicate info key "${entry.key}"`, entry.location);
|
|
772
780
|
}
|
|
773
|
-
|
|
781
|
+
info2[entry.key] = entry.value;
|
|
774
782
|
}
|
|
775
|
-
return
|
|
783
|
+
return info2;
|
|
776
784
|
}
|
|
777
785
|
function parseAtReference(target, location) {
|
|
778
786
|
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
@@ -946,38 +954,38 @@ var WorldOrbit = (() => {
|
|
|
946
954
|
function createDiagnostic(diagnostic) {
|
|
947
955
|
return { ...diagnostic };
|
|
948
956
|
}
|
|
949
|
-
function diagnosticFromError(
|
|
950
|
-
if (
|
|
957
|
+
function diagnosticFromError(error2, source, code = `${source}.failed`) {
|
|
958
|
+
if (error2 instanceof WorldOrbitError) {
|
|
951
959
|
return {
|
|
952
960
|
code,
|
|
953
961
|
severity: "error",
|
|
954
962
|
source,
|
|
955
|
-
message:
|
|
956
|
-
line:
|
|
957
|
-
column:
|
|
963
|
+
message: error2.message,
|
|
964
|
+
line: error2.line,
|
|
965
|
+
column: error2.column
|
|
958
966
|
};
|
|
959
967
|
}
|
|
960
|
-
if (
|
|
968
|
+
if (error2 instanceof Error) {
|
|
961
969
|
return {
|
|
962
970
|
code,
|
|
963
971
|
severity: "error",
|
|
964
972
|
source,
|
|
965
|
-
message:
|
|
973
|
+
message: error2.message
|
|
966
974
|
};
|
|
967
975
|
}
|
|
968
976
|
return {
|
|
969
977
|
code,
|
|
970
978
|
severity: "error",
|
|
971
979
|
source,
|
|
972
|
-
message: String(
|
|
980
|
+
message: String(error2)
|
|
973
981
|
};
|
|
974
982
|
}
|
|
975
983
|
function parseWithDiagnostics(source) {
|
|
976
984
|
let ast;
|
|
977
985
|
try {
|
|
978
986
|
ast = parseWorldOrbit(source);
|
|
979
|
-
} catch (
|
|
980
|
-
const diagnostic = diagnosticFromError(
|
|
987
|
+
} catch (error2) {
|
|
988
|
+
const diagnostic = diagnosticFromError(error2, "parse");
|
|
981
989
|
return {
|
|
982
990
|
ok: false,
|
|
983
991
|
value: null,
|
|
@@ -987,20 +995,20 @@ var WorldOrbit = (() => {
|
|
|
987
995
|
let document;
|
|
988
996
|
try {
|
|
989
997
|
document = normalizeDocument(ast);
|
|
990
|
-
} catch (
|
|
998
|
+
} catch (error2) {
|
|
991
999
|
return {
|
|
992
1000
|
ok: false,
|
|
993
1001
|
value: null,
|
|
994
|
-
diagnostics: [diagnosticFromError(
|
|
1002
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
995
1003
|
};
|
|
996
1004
|
}
|
|
997
1005
|
try {
|
|
998
1006
|
validateDocument(document);
|
|
999
|
-
} catch (
|
|
1007
|
+
} catch (error2) {
|
|
1000
1008
|
return {
|
|
1001
1009
|
ok: false,
|
|
1002
1010
|
value: null,
|
|
1003
|
-
diagnostics: [diagnosticFromError(
|
|
1011
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
1004
1012
|
};
|
|
1005
1013
|
}
|
|
1006
1014
|
return {
|
|
@@ -1019,11 +1027,11 @@ var WorldOrbit = (() => {
|
|
|
1019
1027
|
value: normalizeDocument(ast),
|
|
1020
1028
|
diagnostics: []
|
|
1021
1029
|
};
|
|
1022
|
-
} catch (
|
|
1030
|
+
} catch (error2) {
|
|
1023
1031
|
return {
|
|
1024
1032
|
ok: false,
|
|
1025
1033
|
value: null,
|
|
1026
|
-
diagnostics: [diagnosticFromError(
|
|
1034
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
1027
1035
|
};
|
|
1028
1036
|
}
|
|
1029
1037
|
}
|
|
@@ -1035,11 +1043,11 @@ var WorldOrbit = (() => {
|
|
|
1035
1043
|
value: document,
|
|
1036
1044
|
diagnostics: []
|
|
1037
1045
|
};
|
|
1038
|
-
} catch (
|
|
1046
|
+
} catch (error2) {
|
|
1039
1047
|
return {
|
|
1040
1048
|
ok: false,
|
|
1041
1049
|
value: null,
|
|
1042
|
-
diagnostics: [diagnosticFromError(
|
|
1050
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
1043
1051
|
};
|
|
1044
1052
|
}
|
|
1045
1053
|
}
|
|
@@ -1047,7 +1055,11 @@ var WorldOrbit = (() => {
|
|
|
1047
1055
|
// packages/core/dist/scene.js
|
|
1048
1056
|
var AU_IN_KM = 1495978707e-1;
|
|
1049
1057
|
var EARTH_RADIUS_IN_KM = 6371;
|
|
1058
|
+
var JUPITER_RADIUS_IN_KM = 71492;
|
|
1050
1059
|
var SOLAR_RADIUS_IN_KM = 695700;
|
|
1060
|
+
var LY_IN_AU = 63241.077;
|
|
1061
|
+
var PC_IN_AU = 206264.806;
|
|
1062
|
+
var KPC_IN_AU = 206264806;
|
|
1051
1063
|
var ISO_FLATTENING = 0.68;
|
|
1052
1064
|
var MIN_ISO_MINOR_SCALE = 0.2;
|
|
1053
1065
|
var ARC_SAMPLE_COUNT = 28;
|
|
@@ -1061,8 +1073,10 @@ var WorldOrbit = (() => {
|
|
|
1061
1073
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
1062
1074
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
1063
1075
|
const systemId = document.system?.id ?? null;
|
|
1064
|
-
const
|
|
1065
|
-
const
|
|
1076
|
+
const activeEventId = options.activeEventId ?? null;
|
|
1077
|
+
const effectiveObjects = createEffectiveObjects(document.objects, document.events ?? [], activeEventId);
|
|
1078
|
+
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
1079
|
+
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
1066
1080
|
const positions = /* @__PURE__ */ new Map();
|
|
1067
1081
|
const orbitDrafts = [];
|
|
1068
1082
|
const leaderDrafts = [];
|
|
@@ -1071,7 +1085,7 @@ var WorldOrbit = (() => {
|
|
|
1071
1085
|
const atObjects = [];
|
|
1072
1086
|
const surfaceChildren = /* @__PURE__ */ new Map();
|
|
1073
1087
|
const orbitChildren = /* @__PURE__ */ new Map();
|
|
1074
|
-
for (const object of
|
|
1088
|
+
for (const object of effectiveObjects) {
|
|
1075
1089
|
const placement = object.placement;
|
|
1076
1090
|
if (!placement) {
|
|
1077
1091
|
rootObjects.push(object);
|
|
@@ -1166,11 +1180,14 @@ var WorldOrbit = (() => {
|
|
|
1166
1180
|
const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
|
|
1167
1181
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1168
1182
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1169
|
-
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1170
|
-
const
|
|
1171
|
-
const
|
|
1183
|
+
const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
|
|
1184
|
+
const relations = createSceneRelations(document, objects);
|
|
1185
|
+
const events = createSceneEvents(document.events ?? [], objects, activeEventId);
|
|
1186
|
+
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1187
|
+
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1188
|
+
const semanticGroups = createSceneSemanticGroups(document, objects);
|
|
1172
1189
|
const viewpoints = createSceneViewpoints(document, projection, frame.preset, relationships, objectMap);
|
|
1173
|
-
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1190
|
+
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1174
1191
|
return {
|
|
1175
1192
|
width,
|
|
1176
1193
|
height,
|
|
@@ -1178,7 +1195,7 @@ var WorldOrbit = (() => {
|
|
|
1178
1195
|
renderPreset: frame.preset,
|
|
1179
1196
|
projection,
|
|
1180
1197
|
scaleModel,
|
|
1181
|
-
title: String(document.system?.properties.title ?? document.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1198
|
+
title: String(document.system?.title ?? document.system?.properties.title ?? document.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1182
1199
|
subtitle: `${capitalizeLabel(projection)} view - ${capitalizeLabel(layoutPreset)} layout`,
|
|
1183
1200
|
systemId,
|
|
1184
1201
|
viewMode: projection,
|
|
@@ -1194,9 +1211,13 @@ var WorldOrbit = (() => {
|
|
|
1194
1211
|
contentBounds,
|
|
1195
1212
|
layers,
|
|
1196
1213
|
groups,
|
|
1214
|
+
semanticGroups,
|
|
1197
1215
|
viewpoints,
|
|
1216
|
+
events,
|
|
1217
|
+
activeEventId,
|
|
1198
1218
|
objects,
|
|
1199
1219
|
orbitVisuals,
|
|
1220
|
+
relations,
|
|
1200
1221
|
leaders,
|
|
1201
1222
|
labels
|
|
1202
1223
|
};
|
|
@@ -1212,6 +1233,35 @@ var WorldOrbit = (() => {
|
|
|
1212
1233
|
y: center.y + dx * sin + dy * cos
|
|
1213
1234
|
};
|
|
1214
1235
|
}
|
|
1236
|
+
function createEffectiveObjects(objects, events, activeEventId) {
|
|
1237
|
+
const cloned = objects.map((object) => structuredClone(object));
|
|
1238
|
+
if (!activeEventId) {
|
|
1239
|
+
return cloned;
|
|
1240
|
+
}
|
|
1241
|
+
const activeEvent = events.find((event) => event.id === activeEventId);
|
|
1242
|
+
if (!activeEvent) {
|
|
1243
|
+
return cloned;
|
|
1244
|
+
}
|
|
1245
|
+
const objectMap = new Map(cloned.map((object) => [object.id, object]));
|
|
1246
|
+
for (const pose of activeEvent.positions) {
|
|
1247
|
+
const object = objectMap.get(pose.objectId);
|
|
1248
|
+
if (!object) {
|
|
1249
|
+
continue;
|
|
1250
|
+
}
|
|
1251
|
+
object.placement = pose.placement ? structuredClone(pose.placement) : null;
|
|
1252
|
+
if (pose.inner) {
|
|
1253
|
+
object.properties.inner = { ...pose.inner };
|
|
1254
|
+
} else {
|
|
1255
|
+
delete object.properties.inner;
|
|
1256
|
+
}
|
|
1257
|
+
if (pose.outer) {
|
|
1258
|
+
object.properties.outer = { ...pose.outer };
|
|
1259
|
+
} else {
|
|
1260
|
+
delete object.properties.outer;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
return cloned;
|
|
1264
|
+
}
|
|
1215
1265
|
function resolveLayoutPreset(document) {
|
|
1216
1266
|
const rawScale = String(document.system?.properties.scale ?? "balanced").toLowerCase();
|
|
1217
1267
|
switch (rawScale) {
|
|
@@ -1306,6 +1356,7 @@ var WorldOrbit = (() => {
|
|
|
1306
1356
|
}
|
|
1307
1357
|
function createSceneObject(position, scaleModel, relationships) {
|
|
1308
1358
|
const { object, x, y, radius, sortKey, anchorX, anchorY } = position;
|
|
1359
|
+
const renderPriority = object.renderHints?.renderPriority ?? 0;
|
|
1309
1360
|
return {
|
|
1310
1361
|
renderId: createRenderId(object.id),
|
|
1311
1362
|
objectId: object.id,
|
|
@@ -1314,11 +1365,12 @@ var WorldOrbit = (() => {
|
|
|
1314
1365
|
ancestorIds: relationships.ancestorIds.get(object.id) ?? [],
|
|
1315
1366
|
childIds: relationships.childIds.get(object.id) ?? [],
|
|
1316
1367
|
groupId: relationships.groupIds.get(object.id) ?? null,
|
|
1368
|
+
semanticGroupIds: [...object.groups ?? []],
|
|
1317
1369
|
x,
|
|
1318
1370
|
y,
|
|
1319
1371
|
radius,
|
|
1320
1372
|
visualRadius: visualExtentForObject(object, radius, scaleModel),
|
|
1321
|
-
sortKey,
|
|
1373
|
+
sortKey: sortKey + renderPriority * 1e-3,
|
|
1322
1374
|
anchorX,
|
|
1323
1375
|
anchorY,
|
|
1324
1376
|
label: object.id,
|
|
@@ -1335,6 +1387,7 @@ var WorldOrbit = (() => {
|
|
|
1335
1387
|
object: draft.object,
|
|
1336
1388
|
parentId: draft.parentId,
|
|
1337
1389
|
groupId,
|
|
1390
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1338
1391
|
kind: draft.kind,
|
|
1339
1392
|
cx: draft.cx,
|
|
1340
1393
|
cy: draft.cy,
|
|
@@ -1346,7 +1399,7 @@ var WorldOrbit = (() => {
|
|
|
1346
1399
|
bandThickness: draft.bandThickness,
|
|
1347
1400
|
frontArcPath: draft.frontArcPath,
|
|
1348
1401
|
backArcPath: draft.backArcPath,
|
|
1349
|
-
hidden: draft.object.properties.hidden === true
|
|
1402
|
+
hidden: draft.object.properties.hidden === true || draft.object.renderHints?.renderOrbit === false
|
|
1350
1403
|
};
|
|
1351
1404
|
}
|
|
1352
1405
|
function createLeaderLine(draft) {
|
|
@@ -1355,6 +1408,7 @@ var WorldOrbit = (() => {
|
|
|
1355
1408
|
objectId: draft.object.id,
|
|
1356
1409
|
object: draft.object,
|
|
1357
1410
|
groupId: draft.groupId,
|
|
1411
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1358
1412
|
x1: draft.x1,
|
|
1359
1413
|
y1: draft.y1,
|
|
1360
1414
|
x2: draft.x2,
|
|
@@ -1363,42 +1417,144 @@ var WorldOrbit = (() => {
|
|
|
1363
1417
|
hidden: draft.object.properties.hidden === true
|
|
1364
1418
|
};
|
|
1365
1419
|
}
|
|
1366
|
-
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1420
|
+
function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1367
1421
|
const labels = [];
|
|
1368
1422
|
const occupied = [];
|
|
1369
|
-
const
|
|
1423
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1424
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
|
|
1370
1425
|
for (const object of visibleObjects) {
|
|
1371
|
-
const
|
|
1372
|
-
|
|
1373
|
-
let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
|
|
1374
|
-
let secondaryY = labelY + direction * (16 * labelMultiplier);
|
|
1375
|
-
let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1376
|
-
let attempts = 0;
|
|
1377
|
-
while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
|
|
1378
|
-
labelY += direction * 14 * labelMultiplier;
|
|
1379
|
-
secondaryY += direction * 14 * labelMultiplier;
|
|
1380
|
-
bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1381
|
-
attempts += 1;
|
|
1382
|
-
}
|
|
1383
|
-
occupied.push(bounds);
|
|
1426
|
+
const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
|
|
1427
|
+
occupied.push(createLabelRect(object, placement, labelMultiplier));
|
|
1384
1428
|
labels.push({
|
|
1385
1429
|
renderId: `${object.renderId}-label`,
|
|
1386
1430
|
objectId: object.objectId,
|
|
1387
1431
|
object: object.object,
|
|
1388
1432
|
groupId: object.groupId,
|
|
1433
|
+
semanticGroupIds: [...object.semanticGroupIds],
|
|
1389
1434
|
label: object.label,
|
|
1390
1435
|
secondaryLabel: object.secondaryLabel,
|
|
1391
|
-
x:
|
|
1392
|
-
y: labelY,
|
|
1393
|
-
secondaryY,
|
|
1394
|
-
textAnchor:
|
|
1395
|
-
direction: direction
|
|
1436
|
+
x: placement.x,
|
|
1437
|
+
y: placement.labelY,
|
|
1438
|
+
secondaryY: placement.secondaryY,
|
|
1439
|
+
textAnchor: placement.textAnchor,
|
|
1440
|
+
direction: placement.direction,
|
|
1396
1441
|
hidden: object.hidden
|
|
1397
1442
|
});
|
|
1398
1443
|
}
|
|
1399
1444
|
return labels;
|
|
1400
1445
|
}
|
|
1401
|
-
function
|
|
1446
|
+
function compareLabelPlacementOrder(left, right) {
|
|
1447
|
+
const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
|
|
1448
|
+
if (priorityDiff !== 0) {
|
|
1449
|
+
return priorityDiff;
|
|
1450
|
+
}
|
|
1451
|
+
const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
|
|
1452
|
+
if (renderPriorityDiff !== 0) {
|
|
1453
|
+
return renderPriorityDiff;
|
|
1454
|
+
}
|
|
1455
|
+
return left.sortKey - right.sortKey;
|
|
1456
|
+
}
|
|
1457
|
+
function labelPlacementPriority(object) {
|
|
1458
|
+
switch (object.object.type) {
|
|
1459
|
+
case "star":
|
|
1460
|
+
return 0;
|
|
1461
|
+
case "planet":
|
|
1462
|
+
return 1;
|
|
1463
|
+
case "moon":
|
|
1464
|
+
return 2;
|
|
1465
|
+
case "belt":
|
|
1466
|
+
case "ring":
|
|
1467
|
+
return 3;
|
|
1468
|
+
case "asteroid":
|
|
1469
|
+
case "comet":
|
|
1470
|
+
return 4;
|
|
1471
|
+
case "structure":
|
|
1472
|
+
case "phenomenon":
|
|
1473
|
+
return 5;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1477
|
+
for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
|
|
1478
|
+
const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
|
|
1479
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
|
|
1480
|
+
const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
|
|
1481
|
+
const rect = createLabelRect(object, placement, labelMultiplier);
|
|
1482
|
+
if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
|
|
1483
|
+
return placement;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
return null;
|
|
1488
|
+
}
|
|
1489
|
+
function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
|
|
1490
|
+
const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
|
|
1491
|
+
const vertical = defaultVerticalDirection(object, parent, sceneHeight);
|
|
1492
|
+
const oppositeVertical = vertical === "below" ? "above" : "below";
|
|
1493
|
+
const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
|
|
1494
|
+
const oppositeHorizontal = horizontal === "right" ? "left" : "right";
|
|
1495
|
+
const preferHorizontal = object.object.type === "structure" || object.object.type === "phenomenon" || object.object.placement?.mode === "at" || object.object.placement?.mode === "surface" || object.object.placement?.mode === "free";
|
|
1496
|
+
return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
|
|
1497
|
+
}
|
|
1498
|
+
function defaultVerticalDirection(object, parent, sceneHeight) {
|
|
1499
|
+
if (parent && Math.abs(object.y - parent.y) > 6) {
|
|
1500
|
+
return object.y >= parent.y ? "below" : "above";
|
|
1501
|
+
}
|
|
1502
|
+
return object.y > sceneHeight * 0.62 ? "above" : "below";
|
|
1503
|
+
}
|
|
1504
|
+
function defaultHorizontalDirection(object, parent, sceneWidth) {
|
|
1505
|
+
if (parent && Math.abs(object.x - parent.x) > 6) {
|
|
1506
|
+
return object.x >= parent.x ? "right" : "left";
|
|
1507
|
+
}
|
|
1508
|
+
return object.x >= sceneWidth / 2 ? "right" : "left";
|
|
1509
|
+
}
|
|
1510
|
+
function createLabelPlacement(object, direction, attempt, labelMultiplier) {
|
|
1511
|
+
const step = 14 * labelMultiplier;
|
|
1512
|
+
switch (direction) {
|
|
1513
|
+
case "above": {
|
|
1514
|
+
const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
|
|
1515
|
+
return {
|
|
1516
|
+
x: object.x,
|
|
1517
|
+
labelY,
|
|
1518
|
+
secondaryY: labelY - 16 * labelMultiplier,
|
|
1519
|
+
textAnchor: "middle",
|
|
1520
|
+
direction
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
case "below": {
|
|
1524
|
+
const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
|
|
1525
|
+
return {
|
|
1526
|
+
x: object.x,
|
|
1527
|
+
labelY,
|
|
1528
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1529
|
+
textAnchor: "middle",
|
|
1530
|
+
direction
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
case "left": {
|
|
1534
|
+
const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
|
|
1535
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1536
|
+
return {
|
|
1537
|
+
x,
|
|
1538
|
+
labelY,
|
|
1539
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1540
|
+
textAnchor: "end",
|
|
1541
|
+
direction
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
case "right": {
|
|
1545
|
+
const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
|
|
1546
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1547
|
+
return {
|
|
1548
|
+
x,
|
|
1549
|
+
labelY,
|
|
1550
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1551
|
+
textAnchor: "start",
|
|
1552
|
+
direction
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
|
|
1402
1558
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1403
1559
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1404
1560
|
return [
|
|
@@ -1409,6 +1565,14 @@ var WorldOrbit = (() => {
|
|
|
1409
1565
|
},
|
|
1410
1566
|
{ id: "orbits-back", renderIds: backOrbitIds },
|
|
1411
1567
|
{ id: "orbits-front", renderIds: frontOrbitIds },
|
|
1568
|
+
{
|
|
1569
|
+
id: "relations",
|
|
1570
|
+
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
id: "events",
|
|
1574
|
+
renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
|
|
1575
|
+
},
|
|
1412
1576
|
{
|
|
1413
1577
|
id: "objects",
|
|
1414
1578
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1420,7 +1584,7 @@ var WorldOrbit = (() => {
|
|
|
1420
1584
|
{ id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
|
|
1421
1585
|
];
|
|
1422
1586
|
}
|
|
1423
|
-
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
|
|
1587
|
+
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
|
|
1424
1588
|
const groups = /* @__PURE__ */ new Map();
|
|
1425
1589
|
const ensureGroup = (groupId) => {
|
|
1426
1590
|
if (!groupId) {
|
|
@@ -1469,10 +1633,63 @@ var WorldOrbit = (() => {
|
|
|
1469
1633
|
}
|
|
1470
1634
|
}
|
|
1471
1635
|
for (const group of groups.values()) {
|
|
1472
|
-
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
|
|
1636
|
+
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
|
|
1473
1637
|
}
|
|
1474
1638
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1475
1639
|
}
|
|
1640
|
+
function createSceneSemanticGroups(document, objects) {
|
|
1641
|
+
return [...document.groups].map((group) => ({
|
|
1642
|
+
id: group.id,
|
|
1643
|
+
label: group.label,
|
|
1644
|
+
summary: group.summary,
|
|
1645
|
+
color: group.color,
|
|
1646
|
+
tags: [...group.tags],
|
|
1647
|
+
hidden: group.hidden,
|
|
1648
|
+
objectIds: objects.filter((object) => !object.hidden && object.semanticGroupIds.includes(group.id)).map((object) => object.objectId)
|
|
1649
|
+
})).sort((left, right) => left.label.localeCompare(right.label));
|
|
1650
|
+
}
|
|
1651
|
+
function createSceneRelations(document, objects) {
|
|
1652
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1653
|
+
return document.relations.map((relation) => {
|
|
1654
|
+
const from = objectMap.get(relation.from);
|
|
1655
|
+
const to = objectMap.get(relation.to);
|
|
1656
|
+
return {
|
|
1657
|
+
renderId: `${createRenderId(relation.id)}-relation`,
|
|
1658
|
+
relationId: relation.id,
|
|
1659
|
+
relation,
|
|
1660
|
+
fromObjectId: relation.from,
|
|
1661
|
+
toObjectId: relation.to,
|
|
1662
|
+
x1: from?.x ?? 0,
|
|
1663
|
+
y1: from?.y ?? 0,
|
|
1664
|
+
x2: to?.x ?? 0,
|
|
1665
|
+
y2: to?.y ?? 0,
|
|
1666
|
+
hidden: relation.hidden || !from || !to || from.hidden || to.hidden
|
|
1667
|
+
};
|
|
1668
|
+
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1669
|
+
}
|
|
1670
|
+
function createSceneEvents(events, objects, activeEventId) {
|
|
1671
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1672
|
+
return events.map((event) => {
|
|
1673
|
+
const objectIds = [.../* @__PURE__ */ new Set([
|
|
1674
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
1675
|
+
...event.participantObjectIds
|
|
1676
|
+
])];
|
|
1677
|
+
const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
|
|
1678
|
+
const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
|
|
1679
|
+
const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
|
|
1680
|
+
return {
|
|
1681
|
+
renderId: `${createRenderId(event.id)}-event`,
|
|
1682
|
+
eventId: event.id,
|
|
1683
|
+
event,
|
|
1684
|
+
objectIds,
|
|
1685
|
+
participantIds: [...event.participantObjectIds],
|
|
1686
|
+
targetObjectId: event.targetObjectId,
|
|
1687
|
+
x: centroidX,
|
|
1688
|
+
y: centroidY,
|
|
1689
|
+
hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
|
|
1690
|
+
};
|
|
1691
|
+
}).sort((left, right) => left.event.id.localeCompare(right.event.id));
|
|
1692
|
+
}
|
|
1476
1693
|
function createSceneViewpoints(document, projection, preset, relationships, objectMap) {
|
|
1477
1694
|
const generatedOverview = createGeneratedOverviewViewpoint(document, projection, preset);
|
|
1478
1695
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1490,7 +1707,7 @@ var WorldOrbit = (() => {
|
|
|
1490
1707
|
}
|
|
1491
1708
|
const field = fieldParts.join(".").toLowerCase();
|
|
1492
1709
|
const draft = drafts.get(id) ?? { id };
|
|
1493
|
-
applyViewpointField(draft, field, value, projection, preset, relationships, objectMap);
|
|
1710
|
+
applyViewpointField(draft, field, value, document, projection, preset, relationships, objectMap);
|
|
1494
1711
|
drafts.set(id, draft);
|
|
1495
1712
|
}
|
|
1496
1713
|
const viewpoints = [...drafts.values()].map((draft) => finalizeViewpointDraft(draft, projection, preset, objectMap)).filter(Boolean);
|
|
@@ -1518,13 +1735,15 @@ var WorldOrbit = (() => {
|
|
|
1518
1735
|
});
|
|
1519
1736
|
}
|
|
1520
1737
|
function createGeneratedOverviewViewpoint(document, projection, preset) {
|
|
1521
|
-
const
|
|
1738
|
+
const title = document.system?.title ?? document.system?.properties.title;
|
|
1739
|
+
const label = title ? `${String(title)} Overview` : "Overview";
|
|
1522
1740
|
return {
|
|
1523
1741
|
id: "overview",
|
|
1524
1742
|
label,
|
|
1525
1743
|
summary: "Fit the whole system with the current atlas defaults.",
|
|
1526
1744
|
objectId: null,
|
|
1527
1745
|
selectedObjectId: null,
|
|
1746
|
+
eventIds: [],
|
|
1528
1747
|
projection,
|
|
1529
1748
|
preset,
|
|
1530
1749
|
rotationDeg: 0,
|
|
@@ -1534,7 +1753,7 @@ var WorldOrbit = (() => {
|
|
|
1534
1753
|
generated: true
|
|
1535
1754
|
};
|
|
1536
1755
|
}
|
|
1537
|
-
function applyViewpointField(draft, field, value, projection, preset, relationships, objectMap) {
|
|
1756
|
+
function applyViewpointField(draft, field, value, document, projection, preset, relationships, objectMap) {
|
|
1538
1757
|
const normalizedValue = value.trim();
|
|
1539
1758
|
switch (field) {
|
|
1540
1759
|
case "label":
|
|
@@ -1561,6 +1780,9 @@ var WorldOrbit = (() => {
|
|
|
1561
1780
|
draft.select = normalizedValue;
|
|
1562
1781
|
}
|
|
1563
1782
|
return;
|
|
1783
|
+
case "events":
|
|
1784
|
+
draft.eventIds = splitListValue(normalizedValue);
|
|
1785
|
+
return;
|
|
1564
1786
|
case "projection":
|
|
1565
1787
|
case "view":
|
|
1566
1788
|
draft.projection = parseViewProjection(normalizedValue) ?? projection;
|
|
@@ -1601,7 +1823,7 @@ var WorldOrbit = (() => {
|
|
|
1601
1823
|
case "groups":
|
|
1602
1824
|
draft.filter = {
|
|
1603
1825
|
...draft.filter ?? createEmptyViewpointFilter(),
|
|
1604
|
-
groupIds: parseViewpointGroups(normalizedValue, relationships, objectMap)
|
|
1826
|
+
groupIds: parseViewpointGroups(normalizedValue, document, relationships, objectMap)
|
|
1605
1827
|
};
|
|
1606
1828
|
return;
|
|
1607
1829
|
}
|
|
@@ -1617,6 +1839,7 @@ var WorldOrbit = (() => {
|
|
|
1617
1839
|
summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
|
|
1618
1840
|
objectId,
|
|
1619
1841
|
selectedObjectId,
|
|
1842
|
+
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
1620
1843
|
projection: draft.projection ?? projection,
|
|
1621
1844
|
preset: draft.preset ?? preset,
|
|
1622
1845
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
@@ -1674,7 +1897,7 @@ var WorldOrbit = (() => {
|
|
|
1674
1897
|
next["orbits-front"] = enabled;
|
|
1675
1898
|
continue;
|
|
1676
1899
|
}
|
|
1677
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1900
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1678
1901
|
next[rawLayer] = enabled;
|
|
1679
1902
|
}
|
|
1680
1903
|
}
|
|
@@ -1683,8 +1906,11 @@ var WorldOrbit = (() => {
|
|
|
1683
1906
|
function parseViewpointObjectTypes(value) {
|
|
1684
1907
|
return splitListValue(value).filter((entry) => entry === "star" || entry === "planet" || entry === "moon" || entry === "belt" || entry === "asteroid" || entry === "comet" || entry === "ring" || entry === "structure" || entry === "phenomenon");
|
|
1685
1908
|
}
|
|
1686
|
-
function parseViewpointGroups(value, relationships, objectMap) {
|
|
1909
|
+
function parseViewpointGroups(value, document, relationships, objectMap) {
|
|
1687
1910
|
return splitListValue(value).map((entry) => {
|
|
1911
|
+
if (document.schemaVersion === "2.1" || document.groups.some((group) => group.id === entry)) {
|
|
1912
|
+
return entry;
|
|
1913
|
+
}
|
|
1688
1914
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
1689
1915
|
return entry;
|
|
1690
1916
|
}
|
|
@@ -1719,7 +1945,7 @@ var WorldOrbit = (() => {
|
|
|
1719
1945
|
}
|
|
1720
1946
|
return parts.join(" - ");
|
|
1721
1947
|
}
|
|
1722
|
-
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
|
|
1948
|
+
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
1723
1949
|
let minX = Number.POSITIVE_INFINITY;
|
|
1724
1950
|
let minY = Number.POSITIVE_INFINITY;
|
|
1725
1951
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -1749,7 +1975,7 @@ var WorldOrbit = (() => {
|
|
|
1749
1975
|
for (const label of labels) {
|
|
1750
1976
|
if (label.hidden)
|
|
1751
1977
|
continue;
|
|
1752
|
-
includeLabelBounds(label, include);
|
|
1978
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
1753
1979
|
}
|
|
1754
1980
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
1755
1981
|
return createBounds(0, 0, width, height);
|
|
@@ -1787,13 +2013,10 @@ var WorldOrbit = (() => {
|
|
|
1787
2013
|
include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
|
|
1788
2014
|
include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
|
|
1789
2015
|
}
|
|
1790
|
-
function includeLabelBounds(label, include) {
|
|
1791
|
-
const
|
|
1792
|
-
|
|
1793
|
-
include(
|
|
1794
|
-
include(label.x + labelHalfWidth, label.y + 8);
|
|
1795
|
-
include(label.x - labelHalfWidth, label.secondaryY - 14);
|
|
1796
|
-
include(label.x + labelHalfWidth, label.secondaryY + 8);
|
|
2016
|
+
function includeLabelBounds(label, include, labelMultiplier) {
|
|
2017
|
+
const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
|
|
2018
|
+
include(bounds.left, bounds.top);
|
|
2019
|
+
include(bounds.right, bounds.bottom);
|
|
1797
2020
|
}
|
|
1798
2021
|
function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
|
|
1799
2022
|
if (positions.has(object.id)) {
|
|
@@ -1815,8 +2038,9 @@ var WorldOrbit = (() => {
|
|
|
1815
2038
|
}
|
|
1816
2039
|
const orbiting = [...context.orbitChildren.get(object.id) ?? []].sort(compareOrbiting);
|
|
1817
2040
|
const orbitMetricContext = computeOrbitMetricContext(orbiting, parent.radius, context.spacingFactor, context.scaleModel);
|
|
2041
|
+
const orbitRadiiPx = resolveOrbitRadiiPx(orbiting, orbitMetricContext);
|
|
1818
2042
|
orbiting.forEach((child, index) => {
|
|
1819
|
-
const orbitGeometry = resolveOrbitGeometry(child, index, orbiting.length, parent, orbitMetricContext, context);
|
|
2043
|
+
const orbitGeometry = resolveOrbitGeometry(child, index, orbiting.length, parent, orbitMetricContext, orbitRadiiPx[index] ?? orbitMetricContext.innerPx, context);
|
|
1820
2044
|
orbitDrafts.push({
|
|
1821
2045
|
object: child,
|
|
1822
2046
|
parentId: object.id,
|
|
@@ -1890,7 +2114,8 @@ var WorldOrbit = (() => {
|
|
|
1890
2114
|
metricSpread: 0,
|
|
1891
2115
|
innerPx,
|
|
1892
2116
|
stepPx,
|
|
1893
|
-
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx)
|
|
2117
|
+
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
2118
|
+
minimumGapPx: stepPx * 0.42
|
|
1894
2119
|
};
|
|
1895
2120
|
}
|
|
1896
2121
|
const minMetric = Math.min(...presentMetrics);
|
|
@@ -1903,10 +2128,11 @@ var WorldOrbit = (() => {
|
|
|
1903
2128
|
metricSpread,
|
|
1904
2129
|
innerPx,
|
|
1905
2130
|
stepPx,
|
|
1906
|
-
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx)
|
|
2131
|
+
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
2132
|
+
minimumGapPx: stepPx * 0.42
|
|
1907
2133
|
};
|
|
1908
2134
|
}
|
|
1909
|
-
function resolveOrbitGeometry(object, index, count, parent, metricContext, context) {
|
|
2135
|
+
function resolveOrbitGeometry(object, index, count, parent, metricContext, orbitRadiusPx, context) {
|
|
1910
2136
|
const placement = object.placement;
|
|
1911
2137
|
const band = object.type === "belt" || object.type === "ring";
|
|
1912
2138
|
if (!placement || placement.mode !== "orbit") {
|
|
@@ -1924,7 +2150,7 @@ var WorldOrbit = (() => {
|
|
|
1924
2150
|
};
|
|
1925
2151
|
}
|
|
1926
2152
|
const eccentricity = clampNumber(typeof placement.eccentricity === "number" ? placement.eccentricity : 0, 0, 0.92);
|
|
1927
|
-
const semiMajor =
|
|
2153
|
+
const semiMajor = orbitRadiusPx;
|
|
1928
2154
|
const baseMinor = Math.max(semiMajor * Math.sqrt(1 - eccentricity * eccentricity), semiMajor * 0.18);
|
|
1929
2155
|
const inclinationDeg = unitValueToDegrees(placement.inclination) ?? 0;
|
|
1930
2156
|
const inclinationScale = context.projection === "isometric" ? Math.max(MIN_ISO_MINOR_SCALE, Math.cos(degreesToRadians(inclinationDeg))) * ISO_FLATTENING : 1;
|
|
@@ -1954,15 +2180,19 @@ var WorldOrbit = (() => {
|
|
|
1954
2180
|
objectY: objectPoint.y
|
|
1955
2181
|
};
|
|
1956
2182
|
}
|
|
1957
|
-
function resolveOrbitRadiusPx(
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
2183
|
+
function resolveOrbitRadiusPx(metric, metricContext) {
|
|
2184
|
+
return metricContext.innerPx + metricContext.stepPx * log2(Math.max(metric, 0) + 1);
|
|
2185
|
+
}
|
|
2186
|
+
function resolveOrbitRadiiPx(objects, metricContext) {
|
|
2187
|
+
const radii = [];
|
|
2188
|
+
objects.forEach((object, index) => {
|
|
2189
|
+
const metric = orbitMetric(object);
|
|
2190
|
+
const fallbackRadius = metricContext.innerPx + index * metricContext.stepPx;
|
|
2191
|
+
const baseRadius = metric === null ? fallbackRadius : resolveOrbitRadiusPx(metric, metricContext);
|
|
2192
|
+
const minimumRadius = index === 0 ? metricContext.innerPx : (radii[index - 1] ?? metricContext.innerPx) + metricContext.minimumGapPx;
|
|
2193
|
+
radii.push(Math.max(baseRadius, minimumRadius));
|
|
2194
|
+
});
|
|
2195
|
+
return radii;
|
|
1966
2196
|
}
|
|
1967
2197
|
function orbitMetric(object) {
|
|
1968
2198
|
if (!object.placement || object.placement.mode !== "orbit") {
|
|
@@ -1970,6 +2200,9 @@ var WorldOrbit = (() => {
|
|
|
1970
2200
|
}
|
|
1971
2201
|
return toDistanceMetric(object.placement.semiMajor ?? object.placement.distance ?? null);
|
|
1972
2202
|
}
|
|
2203
|
+
function log2(value) {
|
|
2204
|
+
return Math.log(value) / Math.log(2);
|
|
2205
|
+
}
|
|
1973
2206
|
function resolveOrbitPhase(phase, index, count) {
|
|
1974
2207
|
const degreeValue = phase ? unitValueToDegrees(phase) : null;
|
|
1975
2208
|
if (degreeValue !== null) {
|
|
@@ -2173,7 +2406,7 @@ var WorldOrbit = (() => {
|
|
|
2173
2406
|
return null;
|
|
2174
2407
|
}
|
|
2175
2408
|
}
|
|
2176
|
-
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
|
|
2409
|
+
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2177
2410
|
let minX = Number.POSITIVE_INFINITY;
|
|
2178
2411
|
let minY = Number.POSITIVE_INFINITY;
|
|
2179
2412
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2202,7 +2435,7 @@ var WorldOrbit = (() => {
|
|
|
2202
2435
|
}
|
|
2203
2436
|
for (const label of labels) {
|
|
2204
2437
|
if (!label.hidden && group.labelIds.includes(label.objectId)) {
|
|
2205
|
-
includeLabelBounds(label, include);
|
|
2438
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2206
2439
|
}
|
|
2207
2440
|
}
|
|
2208
2441
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
@@ -2227,12 +2460,28 @@ var WorldOrbit = (() => {
|
|
|
2227
2460
|
}
|
|
2228
2461
|
return current.id;
|
|
2229
2462
|
}
|
|
2230
|
-
function createLabelRect(
|
|
2463
|
+
function createLabelRect(object, placement, labelMultiplier) {
|
|
2464
|
+
return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
|
|
2465
|
+
}
|
|
2466
|
+
function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
|
|
2467
|
+
const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
|
|
2468
|
+
const labelWidth = labelHalfWidth * 2;
|
|
2469
|
+
const topPadding = direction === "above" ? 18 : 12;
|
|
2470
|
+
const bottomPadding = direction === "above" ? 8 : 12;
|
|
2471
|
+
let left = x - labelHalfWidth;
|
|
2472
|
+
let right = x + labelHalfWidth;
|
|
2473
|
+
if (textAnchor === "start") {
|
|
2474
|
+
left = x;
|
|
2475
|
+
right = x + labelWidth;
|
|
2476
|
+
} else if (textAnchor === "end") {
|
|
2477
|
+
left = x - labelWidth;
|
|
2478
|
+
right = x;
|
|
2479
|
+
}
|
|
2231
2480
|
return {
|
|
2232
|
-
left
|
|
2233
|
-
right
|
|
2234
|
-
top: Math.min(labelY, secondaryY) -
|
|
2235
|
-
bottom: Math.max(labelY, secondaryY) +
|
|
2481
|
+
left,
|
|
2482
|
+
right,
|
|
2483
|
+
top: Math.min(labelY, secondaryY) - topPadding,
|
|
2484
|
+
bottom: Math.max(labelY, secondaryY) + bottomPadding
|
|
2236
2485
|
};
|
|
2237
2486
|
}
|
|
2238
2487
|
function rectsOverlap(left, right) {
|
|
@@ -2293,8 +2542,18 @@ var WorldOrbit = (() => {
|
|
|
2293
2542
|
return value.value;
|
|
2294
2543
|
case "km":
|
|
2295
2544
|
return value.value / AU_IN_KM;
|
|
2545
|
+
case "m":
|
|
2546
|
+
return value.value / 1e3 / AU_IN_KM;
|
|
2547
|
+
case "ly":
|
|
2548
|
+
return value.value * LY_IN_AU;
|
|
2549
|
+
case "pc":
|
|
2550
|
+
return value.value * PC_IN_AU;
|
|
2551
|
+
case "kpc":
|
|
2552
|
+
return value.value * KPC_IN_AU;
|
|
2296
2553
|
case "re":
|
|
2297
2554
|
return value.value * EARTH_RADIUS_IN_KM / AU_IN_KM;
|
|
2555
|
+
case "rj":
|
|
2556
|
+
return value.value * JUPITER_RADIUS_IN_KM / AU_IN_KM;
|
|
2298
2557
|
case "sol":
|
|
2299
2558
|
return value.value * SOLAR_RADIUS_IN_KM / AU_IN_KM;
|
|
2300
2559
|
default:
|
|
@@ -2409,11 +2668,6 @@ var WorldOrbit = (() => {
|
|
|
2409
2668
|
function customColorFor(value) {
|
|
2410
2669
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2411
2670
|
}
|
|
2412
|
-
function estimateLabelHalfWidth(object, labelMultiplier) {
|
|
2413
|
-
const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
|
|
2414
|
-
const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
2415
|
-
return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
|
|
2416
|
-
}
|
|
2417
2671
|
function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
|
|
2418
2672
|
const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
|
|
2419
2673
|
const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
@@ -2448,8 +2702,12 @@ var WorldOrbit = (() => {
|
|
|
2448
2702
|
return {
|
|
2449
2703
|
format: "worldorbit",
|
|
2450
2704
|
version: "2.0",
|
|
2705
|
+
schemaVersion: "2.0",
|
|
2451
2706
|
sourceVersion: document.version,
|
|
2452
2707
|
system,
|
|
2708
|
+
groups: structuredClone(document.groups ?? []),
|
|
2709
|
+
relations: structuredClone(document.relations ?? []),
|
|
2710
|
+
events: structuredClone(document.events ?? []),
|
|
2453
2711
|
objects: document.objects.map(cloneWorldOrbitObject),
|
|
2454
2712
|
diagnostics
|
|
2455
2713
|
};
|
|
@@ -2457,18 +2715,28 @@ var WorldOrbit = (() => {
|
|
|
2457
2715
|
function upgradeDocumentToDraftV2(document, options = {}) {
|
|
2458
2716
|
return convertAtlasDocumentToLegacyDraft(upgradeDocumentToV2(document, options));
|
|
2459
2717
|
}
|
|
2460
|
-
function materializeAtlasDocument(document) {
|
|
2718
|
+
function materializeAtlasDocument(document, options = {}) {
|
|
2461
2719
|
const system = document.system ? {
|
|
2462
2720
|
type: "system",
|
|
2463
2721
|
id: document.system.id,
|
|
2722
|
+
title: document.system.title,
|
|
2723
|
+
description: document.system.description,
|
|
2724
|
+
epoch: document.system.epoch,
|
|
2725
|
+
referencePlane: document.system.referencePlane,
|
|
2464
2726
|
properties: materializeDraftSystemProperties(document.system),
|
|
2465
2727
|
info: materializeDraftSystemInfo(document.system)
|
|
2466
2728
|
} : null;
|
|
2729
|
+
const objects = document.objects.map(cloneWorldOrbitObject);
|
|
2730
|
+
applyEventPoseOverrides(objects, document.events ?? [], options.activeEventId ?? null);
|
|
2467
2731
|
return {
|
|
2468
2732
|
format: "worldorbit",
|
|
2469
2733
|
version: "1.0",
|
|
2734
|
+
schemaVersion: document.version,
|
|
2470
2735
|
system,
|
|
2471
|
-
|
|
2736
|
+
groups: structuredClone(document.groups ?? []),
|
|
2737
|
+
relations: structuredClone(document.relations ?? []),
|
|
2738
|
+
events: document.events.map(cloneWorldOrbitEvent),
|
|
2739
|
+
objects
|
|
2472
2740
|
};
|
|
2473
2741
|
}
|
|
2474
2742
|
function materializeDraftDocument(document) {
|
|
@@ -2482,7 +2750,10 @@ var WorldOrbit = (() => {
|
|
|
2482
2750
|
return {
|
|
2483
2751
|
type: "system",
|
|
2484
2752
|
id: document.system?.id ?? "WorldOrbit",
|
|
2485
|
-
title: typeof document.system?.properties.title === "string" ? document.system.properties.title : null,
|
|
2753
|
+
title: document.system?.title ?? (typeof document.system?.properties.title === "string" ? document.system.properties.title : null),
|
|
2754
|
+
description: document.system?.description ?? null,
|
|
2755
|
+
epoch: document.system?.epoch ?? null,
|
|
2756
|
+
referencePlane: document.system?.referencePlane ?? null,
|
|
2486
2757
|
defaults,
|
|
2487
2758
|
atlasMetadata,
|
|
2488
2759
|
viewpoints: scene.viewpoints.map(mapSceneViewpointToDraftViewpoint),
|
|
@@ -2593,6 +2864,7 @@ var WorldOrbit = (() => {
|
|
|
2593
2864
|
summary: viewpoint.summary,
|
|
2594
2865
|
focusObjectId: viewpoint.objectId,
|
|
2595
2866
|
selectedObjectId: viewpoint.selectedObjectId,
|
|
2867
|
+
events: [...viewpoint.eventIds],
|
|
2596
2868
|
projection: viewpoint.projection,
|
|
2597
2869
|
preset: viewpoint.preset,
|
|
2598
2870
|
zoom: viewpoint.scale,
|
|
@@ -2609,11 +2881,68 @@ var WorldOrbit = (() => {
|
|
|
2609
2881
|
function cloneWorldOrbitObject(object) {
|
|
2610
2882
|
return {
|
|
2611
2883
|
...object,
|
|
2884
|
+
groups: object.groups ? [...object.groups] : void 0,
|
|
2885
|
+
resonance: object.resonance ? { ...object.resonance } : object.resonance,
|
|
2886
|
+
renderHints: object.renderHints ? { ...object.renderHints } : object.renderHints,
|
|
2887
|
+
deriveRules: object.deriveRules ? object.deriveRules.map((rule) => ({ ...rule })) : void 0,
|
|
2888
|
+
validationRules: object.validationRules ? object.validationRules.map((rule) => ({ ...rule })) : void 0,
|
|
2889
|
+
lockedFields: object.lockedFields ? [...object.lockedFields] : void 0,
|
|
2890
|
+
tolerances: object.tolerances ? object.tolerances.map((entry) => ({
|
|
2891
|
+
field: entry.field,
|
|
2892
|
+
value: entry.value && typeof entry.value === "object" && "value" in entry.value ? { value: entry.value.value, unit: entry.value.unit } : Array.isArray(entry.value) ? [...entry.value] : entry.value
|
|
2893
|
+
})) : void 0,
|
|
2894
|
+
typedBlocks: object.typedBlocks ? Object.fromEntries(Object.entries(object.typedBlocks).map(([key, block]) => [key, { ...block ?? {} }])) : void 0,
|
|
2612
2895
|
properties: cloneProperties(object.properties),
|
|
2613
2896
|
placement: object.placement ? structuredClone(object.placement) : null,
|
|
2614
2897
|
info: { ...object.info }
|
|
2615
2898
|
};
|
|
2616
2899
|
}
|
|
2900
|
+
function cloneWorldOrbitEvent(event) {
|
|
2901
|
+
return {
|
|
2902
|
+
...event,
|
|
2903
|
+
participantObjectIds: [...event.participantObjectIds],
|
|
2904
|
+
tags: [...event.tags],
|
|
2905
|
+
positions: event.positions.map(cloneWorldOrbitEventPose)
|
|
2906
|
+
};
|
|
2907
|
+
}
|
|
2908
|
+
function cloneWorldOrbitEventPose(pose) {
|
|
2909
|
+
return {
|
|
2910
|
+
objectId: pose.objectId,
|
|
2911
|
+
placement: clonePlacement(pose.placement),
|
|
2912
|
+
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
2913
|
+
outer: pose.outer ? { ...pose.outer } : void 0
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
function clonePlacement(placement) {
|
|
2917
|
+
return placement ? structuredClone(placement) : null;
|
|
2918
|
+
}
|
|
2919
|
+
function applyEventPoseOverrides(objects, events, activeEventId) {
|
|
2920
|
+
if (!activeEventId) {
|
|
2921
|
+
return;
|
|
2922
|
+
}
|
|
2923
|
+
const event = events.find((entry) => entry.id === activeEventId);
|
|
2924
|
+
if (!event) {
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2927
|
+
const objectMap = new Map(objects.map((object) => [object.id, object]));
|
|
2928
|
+
for (const pose of event.positions) {
|
|
2929
|
+
const object = objectMap.get(pose.objectId);
|
|
2930
|
+
if (!object) {
|
|
2931
|
+
continue;
|
|
2932
|
+
}
|
|
2933
|
+
object.placement = clonePlacement(pose.placement);
|
|
2934
|
+
if (pose.inner) {
|
|
2935
|
+
object.properties.inner = { ...pose.inner };
|
|
2936
|
+
} else {
|
|
2937
|
+
delete object.properties.inner;
|
|
2938
|
+
}
|
|
2939
|
+
if (pose.outer) {
|
|
2940
|
+
object.properties.outer = { ...pose.outer };
|
|
2941
|
+
} else {
|
|
2942
|
+
delete object.properties.outer;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2617
2946
|
function cloneProperties(properties) {
|
|
2618
2947
|
const next = {};
|
|
2619
2948
|
for (const [key, value] of Object.entries(properties)) {
|
|
@@ -2653,71 +2982,83 @@ var WorldOrbit = (() => {
|
|
|
2653
2982
|
if (system.defaults.units) {
|
|
2654
2983
|
properties.units = system.defaults.units;
|
|
2655
2984
|
}
|
|
2985
|
+
if (system.description) {
|
|
2986
|
+
properties.description = system.description;
|
|
2987
|
+
}
|
|
2988
|
+
if (system.epoch) {
|
|
2989
|
+
properties.epoch = system.epoch;
|
|
2990
|
+
}
|
|
2991
|
+
if (system.referencePlane) {
|
|
2992
|
+
properties.referencePlane = system.referencePlane;
|
|
2993
|
+
}
|
|
2656
2994
|
return properties;
|
|
2657
2995
|
}
|
|
2658
2996
|
function materializeDraftSystemInfo(system) {
|
|
2659
|
-
const
|
|
2997
|
+
const info2 = {
|
|
2660
2998
|
...system.atlasMetadata
|
|
2661
2999
|
};
|
|
2662
3000
|
if (system.defaults.theme) {
|
|
2663
|
-
|
|
3001
|
+
info2["atlas.theme"] = system.defaults.theme;
|
|
2664
3002
|
}
|
|
2665
3003
|
for (const viewpoint of system.viewpoints) {
|
|
2666
3004
|
const prefix = `viewpoint.${viewpoint.id}`;
|
|
2667
|
-
|
|
3005
|
+
info2[`${prefix}.label`] = viewpoint.label;
|
|
2668
3006
|
if (viewpoint.summary) {
|
|
2669
|
-
|
|
3007
|
+
info2[`${prefix}.summary`] = viewpoint.summary;
|
|
2670
3008
|
}
|
|
2671
3009
|
if (viewpoint.focusObjectId) {
|
|
2672
|
-
|
|
3010
|
+
info2[`${prefix}.focus`] = viewpoint.focusObjectId;
|
|
2673
3011
|
}
|
|
2674
3012
|
if (viewpoint.selectedObjectId) {
|
|
2675
|
-
|
|
3013
|
+
info2[`${prefix}.select`] = viewpoint.selectedObjectId;
|
|
2676
3014
|
}
|
|
2677
3015
|
if (viewpoint.projection) {
|
|
2678
|
-
|
|
3016
|
+
info2[`${prefix}.projection`] = viewpoint.projection;
|
|
2679
3017
|
}
|
|
2680
3018
|
if (viewpoint.preset) {
|
|
2681
|
-
|
|
3019
|
+
info2[`${prefix}.preset`] = viewpoint.preset;
|
|
2682
3020
|
}
|
|
2683
3021
|
if (viewpoint.zoom !== null) {
|
|
2684
|
-
|
|
3022
|
+
info2[`${prefix}.zoom`] = String(viewpoint.zoom);
|
|
2685
3023
|
}
|
|
2686
3024
|
if (viewpoint.rotationDeg !== 0) {
|
|
2687
|
-
|
|
3025
|
+
info2[`${prefix}.rotation`] = String(viewpoint.rotationDeg);
|
|
2688
3026
|
}
|
|
2689
3027
|
const serializedLayers = serializeViewpointLayers(viewpoint.layers);
|
|
2690
3028
|
if (serializedLayers) {
|
|
2691
|
-
|
|
3029
|
+
info2[`${prefix}.layers`] = serializedLayers;
|
|
2692
3030
|
}
|
|
2693
3031
|
if (viewpoint.filter?.query) {
|
|
2694
|
-
|
|
3032
|
+
info2[`${prefix}.query`] = viewpoint.filter.query;
|
|
2695
3033
|
}
|
|
2696
3034
|
if ((viewpoint.filter?.objectTypes.length ?? 0) > 0) {
|
|
2697
|
-
|
|
3035
|
+
info2[`${prefix}.types`] = viewpoint.filter?.objectTypes.join(" ") ?? "";
|
|
2698
3036
|
}
|
|
2699
3037
|
if ((viewpoint.filter?.tags.length ?? 0) > 0) {
|
|
2700
|
-
|
|
3038
|
+
info2[`${prefix}.tags`] = viewpoint.filter?.tags.join(" ") ?? "";
|
|
2701
3039
|
}
|
|
2702
3040
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2703
|
-
|
|
3041
|
+
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
3042
|
+
}
|
|
3043
|
+
if (viewpoint.events.length > 0) {
|
|
3044
|
+
info2[`${prefix}.events`] = viewpoint.events.join(" ");
|
|
2704
3045
|
}
|
|
2705
3046
|
}
|
|
2706
3047
|
for (const annotation of system.annotations) {
|
|
2707
3048
|
const prefix = `annotation.${annotation.id}`;
|
|
2708
|
-
|
|
3049
|
+
info2[`${prefix}.label`] = annotation.label;
|
|
2709
3050
|
if (annotation.targetObjectId) {
|
|
2710
|
-
|
|
3051
|
+
info2[`${prefix}.target`] = annotation.targetObjectId;
|
|
2711
3052
|
}
|
|
2712
|
-
|
|
3053
|
+
info2[`${prefix}.body`] = annotation.body;
|
|
2713
3054
|
if (annotation.tags.length > 0) {
|
|
2714
|
-
|
|
3055
|
+
info2[`${prefix}.tags`] = annotation.tags.join(" ");
|
|
2715
3056
|
}
|
|
2716
3057
|
if (annotation.sourceObjectId) {
|
|
2717
|
-
|
|
3058
|
+
info2[`${prefix}.source`] = annotation.sourceObjectId;
|
|
2718
3059
|
}
|
|
2719
3060
|
}
|
|
2720
|
-
return
|
|
3061
|
+
return info2;
|
|
2721
3062
|
}
|
|
2722
3063
|
function serializeViewpointLayers(layers) {
|
|
2723
3064
|
const tokens = [];
|
|
@@ -2726,7 +3067,7 @@ var WorldOrbit = (() => {
|
|
|
2726
3067
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2727
3068
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2728
3069
|
}
|
|
2729
|
-
for (const key of ["background", "guides", "objects", "labels", "metadata"]) {
|
|
3070
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
2730
3071
|
if (layers[key] !== void 0) {
|
|
2731
3072
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2732
3073
|
}
|
|
@@ -2736,7 +3077,8 @@ var WorldOrbit = (() => {
|
|
|
2736
3077
|
function convertAtlasDocumentToLegacyDraft(document) {
|
|
2737
3078
|
return {
|
|
2738
3079
|
...document,
|
|
2739
|
-
version: "2.0-draft"
|
|
3080
|
+
version: "2.0-draft",
|
|
3081
|
+
schemaVersion: "2.0-draft"
|
|
2740
3082
|
};
|
|
2741
3083
|
}
|
|
2742
3084
|
|
|
@@ -2778,19 +3120,28 @@ var WorldOrbit = (() => {
|
|
|
2778
3120
|
];
|
|
2779
3121
|
function formatDocument(document, options = {}) {
|
|
2780
3122
|
const schema = options.schema ?? "auto";
|
|
2781
|
-
const useDraft = schema === "2.0" || schema === "2.0-draft" || document.version === "2.0" || document.version === "2.0-draft";
|
|
3123
|
+
const useDraft = schema === "2.0" || schema === "2.1" || schema === "2.0-draft" || document.version === "2.0" || document.version === "2.1" || document.version === "2.0-draft";
|
|
2782
3124
|
if (useDraft) {
|
|
2783
3125
|
if (schema === "2.0-draft") {
|
|
2784
|
-
const legacyDraftDocument = document.version === "2.0-draft" ? document : document.version === "2.0" ? {
|
|
3126
|
+
const legacyDraftDocument = document.version === "2.0-draft" ? document : document.version === "2.0" || document.version === "2.1" ? {
|
|
2785
3127
|
...document,
|
|
2786
|
-
version: "2.0-draft"
|
|
3128
|
+
version: "2.0-draft",
|
|
3129
|
+
schemaVersion: "2.0-draft"
|
|
2787
3130
|
} : upgradeDocumentToDraftV2(document);
|
|
2788
3131
|
return formatDraftDocument(legacyDraftDocument);
|
|
2789
3132
|
}
|
|
2790
|
-
const atlasDocument = document.version === "2.0" ? document : document.version === "2.0-draft" ? {
|
|
3133
|
+
const atlasDocument = document.version === "2.0" || document.version === "2.1" ? document : document.version === "2.0-draft" ? {
|
|
2791
3134
|
...document,
|
|
2792
|
-
version: "2.0"
|
|
3135
|
+
version: "2.0",
|
|
3136
|
+
schemaVersion: "2.0"
|
|
2793
3137
|
} : upgradeDocumentToV2(document);
|
|
3138
|
+
if (schema === "2.1" && atlasDocument.version !== "2.1") {
|
|
3139
|
+
return formatAtlasDocument({
|
|
3140
|
+
...atlasDocument,
|
|
3141
|
+
version: "2.1",
|
|
3142
|
+
schemaVersion: "2.1"
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
2794
3145
|
return formatAtlasDocument(atlasDocument);
|
|
2795
3146
|
}
|
|
2796
3147
|
const lines = [];
|
|
@@ -2808,10 +3159,22 @@ var WorldOrbit = (() => {
|
|
|
2808
3159
|
return lines.join("\n");
|
|
2809
3160
|
}
|
|
2810
3161
|
function formatAtlasDocument(document) {
|
|
2811
|
-
const lines = [
|
|
3162
|
+
const lines = [`schema ${document.version}`, ""];
|
|
2812
3163
|
if (document.system) {
|
|
2813
3164
|
lines.push(...formatAtlasSystem(document.system));
|
|
2814
3165
|
}
|
|
3166
|
+
for (const group of [...document.groups].sort(compareIdLike)) {
|
|
3167
|
+
lines.push("");
|
|
3168
|
+
lines.push(...formatAtlasGroup(group));
|
|
3169
|
+
}
|
|
3170
|
+
for (const relation of [...document.relations].sort(compareIdLike)) {
|
|
3171
|
+
lines.push("");
|
|
3172
|
+
lines.push(...formatAtlasRelation(relation));
|
|
3173
|
+
}
|
|
3174
|
+
for (const event of [...document.events].sort(compareIdLike)) {
|
|
3175
|
+
lines.push("");
|
|
3176
|
+
lines.push(...formatAtlasEvent(event));
|
|
3177
|
+
}
|
|
2815
3178
|
const sortedObjects = [...document.objects].sort(compareObjects);
|
|
2816
3179
|
if (sortedObjects.length > 0 && lines.at(-1) !== "") {
|
|
2817
3180
|
lines.push("");
|
|
@@ -2827,12 +3190,25 @@ var WorldOrbit = (() => {
|
|
|
2827
3190
|
function formatDraftDocument(document) {
|
|
2828
3191
|
const legacy = document.version === "2.0-draft" ? document : {
|
|
2829
3192
|
...document,
|
|
2830
|
-
version: "2.0-draft"
|
|
3193
|
+
version: "2.0-draft",
|
|
3194
|
+
schemaVersion: "2.0-draft"
|
|
2831
3195
|
};
|
|
2832
3196
|
const lines = ["schema 2.0-draft", ""];
|
|
2833
3197
|
if (legacy.system) {
|
|
2834
3198
|
lines.push(...formatAtlasSystem(legacy.system));
|
|
2835
3199
|
}
|
|
3200
|
+
for (const group of [...legacy.groups].sort(compareIdLike)) {
|
|
3201
|
+
lines.push("");
|
|
3202
|
+
lines.push(...formatAtlasGroup(group));
|
|
3203
|
+
}
|
|
3204
|
+
for (const relation of [...legacy.relations].sort(compareIdLike)) {
|
|
3205
|
+
lines.push("");
|
|
3206
|
+
lines.push(...formatAtlasRelation(relation));
|
|
3207
|
+
}
|
|
3208
|
+
for (const event of [...legacy.events].sort(compareIdLike)) {
|
|
3209
|
+
lines.push("");
|
|
3210
|
+
lines.push(...formatAtlasEvent(event));
|
|
3211
|
+
}
|
|
2836
3212
|
const sortedObjects = [...legacy.objects].sort(compareObjects);
|
|
2837
3213
|
if (sortedObjects.length > 0 && lines.at(-1) !== "") {
|
|
2838
3214
|
lines.push("");
|
|
@@ -2848,11 +3224,38 @@ var WorldOrbit = (() => {
|
|
|
2848
3224
|
function formatSystem(system) {
|
|
2849
3225
|
return formatLines("system", system.id, system.properties, null, system.info);
|
|
2850
3226
|
}
|
|
3227
|
+
function formatLines(objectType, id, properties, placement, info2) {
|
|
3228
|
+
const lines = [`${objectType} ${id}`];
|
|
3229
|
+
const fieldLines = [...formatPlacement(placement), ...formatProperties(properties)];
|
|
3230
|
+
for (const fieldLine of fieldLines) {
|
|
3231
|
+
lines.push(` ${fieldLine}`);
|
|
3232
|
+
}
|
|
3233
|
+
const infoEntries = Object.entries(info2).sort(([left], [right]) => left.localeCompare(right));
|
|
3234
|
+
if (infoEntries.length > 0) {
|
|
3235
|
+
if (fieldLines.length > 0) {
|
|
3236
|
+
lines.push("");
|
|
3237
|
+
}
|
|
3238
|
+
lines.push(" info");
|
|
3239
|
+
for (const [key, value] of infoEntries) {
|
|
3240
|
+
lines.push(` ${key} ${quoteIfNeeded(value)}`);
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
return lines;
|
|
3244
|
+
}
|
|
2851
3245
|
function formatAtlasSystem(system) {
|
|
2852
3246
|
const lines = [`system ${system.id}`];
|
|
2853
3247
|
if (system.title) {
|
|
2854
3248
|
lines.push(` title ${quoteIfNeeded(system.title)}`);
|
|
2855
3249
|
}
|
|
3250
|
+
if (system.description) {
|
|
3251
|
+
lines.push(` description ${quoteIfNeeded(system.description)}`);
|
|
3252
|
+
}
|
|
3253
|
+
if (system.epoch) {
|
|
3254
|
+
lines.push(` epoch ${quoteIfNeeded(system.epoch)}`);
|
|
3255
|
+
}
|
|
3256
|
+
if (system.referencePlane) {
|
|
3257
|
+
lines.push(` referencePlane ${quoteIfNeeded(system.referencePlane)}`);
|
|
3258
|
+
}
|
|
2856
3259
|
lines.push("");
|
|
2857
3260
|
lines.push("defaults");
|
|
2858
3261
|
lines.push(` view ${system.defaults.view}`);
|
|
@@ -2887,18 +3290,22 @@ var WorldOrbit = (() => {
|
|
|
2887
3290
|
return lines;
|
|
2888
3291
|
}
|
|
2889
3292
|
function formatObject(object) {
|
|
2890
|
-
return
|
|
3293
|
+
return formatWorldOrbitObject(object.type, object.id, object);
|
|
2891
3294
|
}
|
|
2892
3295
|
function formatAtlasObject(object) {
|
|
2893
|
-
return
|
|
3296
|
+
return formatWorldOrbitObject(`object ${object.type}`, object.id, object);
|
|
2894
3297
|
}
|
|
2895
|
-
function
|
|
3298
|
+
function formatWorldOrbitObject(objectType, id, object) {
|
|
2896
3299
|
const lines = [`${objectType} ${id}`];
|
|
2897
|
-
const fieldLines = [
|
|
3300
|
+
const fieldLines = [
|
|
3301
|
+
...formatPlacement(object.placement),
|
|
3302
|
+
...formatProperties(object.properties),
|
|
3303
|
+
...formatObjectMetadata(object)
|
|
3304
|
+
];
|
|
2898
3305
|
for (const fieldLine of fieldLines) {
|
|
2899
3306
|
lines.push(` ${fieldLine}`);
|
|
2900
3307
|
}
|
|
2901
|
-
const infoEntries = Object.entries(info).sort(([left], [right]) => left.localeCompare(right));
|
|
3308
|
+
const infoEntries = Object.entries(object.info).sort(([left], [right]) => left.localeCompare(right));
|
|
2902
3309
|
if (infoEntries.length > 0) {
|
|
2903
3310
|
if (fieldLines.length > 0) {
|
|
2904
3311
|
lines.push("");
|
|
@@ -2908,6 +3315,16 @@ var WorldOrbit = (() => {
|
|
|
2908
3315
|
lines.push(` ${key} ${quoteIfNeeded(value)}`);
|
|
2909
3316
|
}
|
|
2910
3317
|
}
|
|
3318
|
+
for (const blockName of ["climate", "habitability", "settlement"]) {
|
|
3319
|
+
const blockEntries = Object.entries(object.typedBlocks?.[blockName] ?? {}).sort(([left], [right]) => left.localeCompare(right));
|
|
3320
|
+
if (blockEntries.length > 0) {
|
|
3321
|
+
lines.push("");
|
|
3322
|
+
lines.push(` ${blockName}`);
|
|
3323
|
+
for (const [key, value] of blockEntries) {
|
|
3324
|
+
lines.push(` ${key} ${quoteIfNeeded(value)}`);
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
2911
3328
|
return lines;
|
|
2912
3329
|
}
|
|
2913
3330
|
function formatPlacement(placement) {
|
|
@@ -2936,6 +3353,46 @@ var WorldOrbit = (() => {
|
|
|
2936
3353
|
function formatProperties(properties) {
|
|
2937
3354
|
return Object.keys(properties).sort(compareFieldKeys).map((key) => `${key} ${formatValue(properties[key])}`);
|
|
2938
3355
|
}
|
|
3356
|
+
function formatObjectMetadata(object) {
|
|
3357
|
+
const lines = [];
|
|
3358
|
+
if (object.groups?.length) {
|
|
3359
|
+
lines.push(`groups ${object.groups.join(" ")}`);
|
|
3360
|
+
}
|
|
3361
|
+
if (object.epoch) {
|
|
3362
|
+
lines.push(`epoch ${quoteIfNeeded(object.epoch)}`);
|
|
3363
|
+
}
|
|
3364
|
+
if (object.referencePlane) {
|
|
3365
|
+
lines.push(`referencePlane ${quoteIfNeeded(object.referencePlane)}`);
|
|
3366
|
+
}
|
|
3367
|
+
if (object.tidalLock !== void 0) {
|
|
3368
|
+
lines.push(`tidalLock ${object.tidalLock ? "true" : "false"}`);
|
|
3369
|
+
}
|
|
3370
|
+
if (object.renderHints?.renderLabel !== void 0) {
|
|
3371
|
+
lines.push(`renderLabel ${object.renderHints.renderLabel ? "true" : "false"}`);
|
|
3372
|
+
}
|
|
3373
|
+
if (object.renderHints?.renderOrbit !== void 0) {
|
|
3374
|
+
lines.push(`renderOrbit ${object.renderHints.renderOrbit ? "true" : "false"}`);
|
|
3375
|
+
}
|
|
3376
|
+
if (object.renderHints?.renderPriority !== void 0) {
|
|
3377
|
+
lines.push(`renderPriority ${object.renderHints.renderPriority}`);
|
|
3378
|
+
}
|
|
3379
|
+
if (object.resonance) {
|
|
3380
|
+
lines.push(`resonance ${object.resonance.targetObjectId} ${object.resonance.ratio}`);
|
|
3381
|
+
}
|
|
3382
|
+
for (const rule of object.deriveRules ?? []) {
|
|
3383
|
+
lines.push(`derive ${rule.field} ${rule.strategy}`);
|
|
3384
|
+
}
|
|
3385
|
+
for (const rule of object.validationRules ?? []) {
|
|
3386
|
+
lines.push(`validate ${rule.rule}`);
|
|
3387
|
+
}
|
|
3388
|
+
if (object.lockedFields?.length) {
|
|
3389
|
+
lines.push(`locked ${object.lockedFields.join(" ")}`);
|
|
3390
|
+
}
|
|
3391
|
+
for (const tolerance of object.tolerances ?? []) {
|
|
3392
|
+
lines.push(`tolerance ${tolerance.field} ${formatValue(tolerance.value)}`);
|
|
3393
|
+
}
|
|
3394
|
+
return lines;
|
|
3395
|
+
}
|
|
2939
3396
|
function formatAtlasViewpoint(viewpoint) {
|
|
2940
3397
|
const lines = [`viewpoint ${viewpoint.id}`, ` label ${quoteIfNeeded(viewpoint.label)}`];
|
|
2941
3398
|
if (viewpoint.focusObjectId) {
|
|
@@ -2963,6 +3420,9 @@ var WorldOrbit = (() => {
|
|
|
2963
3420
|
if (layerTokens.length > 0) {
|
|
2964
3421
|
lines.push(` layers ${layerTokens.join(" ")}`);
|
|
2965
3422
|
}
|
|
3423
|
+
if (viewpoint.events.length > 0) {
|
|
3424
|
+
lines.push(` events ${viewpoint.events.join(" ")}`);
|
|
3425
|
+
}
|
|
2966
3426
|
if (viewpoint.filter) {
|
|
2967
3427
|
lines.push(" filter");
|
|
2968
3428
|
if (viewpoint.filter.query) {
|
|
@@ -2991,6 +3451,98 @@ var WorldOrbit = (() => {
|
|
|
2991
3451
|
}
|
|
2992
3452
|
return lines;
|
|
2993
3453
|
}
|
|
3454
|
+
function formatAtlasGroup(group) {
|
|
3455
|
+
const lines = [`group ${group.id}`, ` label ${quoteIfNeeded(group.label)}`];
|
|
3456
|
+
if (group.summary) {
|
|
3457
|
+
lines.push(` summary ${quoteIfNeeded(group.summary)}`);
|
|
3458
|
+
}
|
|
3459
|
+
if (group.color) {
|
|
3460
|
+
lines.push(` color ${quoteIfNeeded(group.color)}`);
|
|
3461
|
+
}
|
|
3462
|
+
if (group.tags.length > 0) {
|
|
3463
|
+
lines.push(` tags ${group.tags.map(quoteIfNeeded).join(" ")}`);
|
|
3464
|
+
}
|
|
3465
|
+
if (group.hidden) {
|
|
3466
|
+
lines.push(" hidden true");
|
|
3467
|
+
}
|
|
3468
|
+
return lines;
|
|
3469
|
+
}
|
|
3470
|
+
function formatAtlasRelation(relation) {
|
|
3471
|
+
const lines = [`relation ${relation.id}`];
|
|
3472
|
+
if (relation.from) {
|
|
3473
|
+
lines.push(` from ${quoteIfNeeded(relation.from)}`);
|
|
3474
|
+
}
|
|
3475
|
+
if (relation.to) {
|
|
3476
|
+
lines.push(` to ${quoteIfNeeded(relation.to)}`);
|
|
3477
|
+
}
|
|
3478
|
+
if (relation.kind) {
|
|
3479
|
+
lines.push(` kind ${quoteIfNeeded(relation.kind)}`);
|
|
3480
|
+
}
|
|
3481
|
+
if (relation.label) {
|
|
3482
|
+
lines.push(` label ${quoteIfNeeded(relation.label)}`);
|
|
3483
|
+
}
|
|
3484
|
+
if (relation.summary) {
|
|
3485
|
+
lines.push(` summary ${quoteIfNeeded(relation.summary)}`);
|
|
3486
|
+
}
|
|
3487
|
+
if (relation.tags.length > 0) {
|
|
3488
|
+
lines.push(` tags ${relation.tags.map(quoteIfNeeded).join(" ")}`);
|
|
3489
|
+
}
|
|
3490
|
+
if (relation.color) {
|
|
3491
|
+
lines.push(` color ${quoteIfNeeded(relation.color)}`);
|
|
3492
|
+
}
|
|
3493
|
+
if (relation.hidden) {
|
|
3494
|
+
lines.push(" hidden true");
|
|
3495
|
+
}
|
|
3496
|
+
return lines;
|
|
3497
|
+
}
|
|
3498
|
+
function formatAtlasEvent(event) {
|
|
3499
|
+
const lines = [`event ${event.id}`, ` kind ${quoteIfNeeded(event.kind)}`];
|
|
3500
|
+
if (event.label) {
|
|
3501
|
+
lines.push(` label ${quoteIfNeeded(event.label)}`);
|
|
3502
|
+
}
|
|
3503
|
+
if (event.summary) {
|
|
3504
|
+
lines.push(` summary ${quoteIfNeeded(event.summary)}`);
|
|
3505
|
+
}
|
|
3506
|
+
if (event.targetObjectId) {
|
|
3507
|
+
lines.push(` target ${event.targetObjectId}`);
|
|
3508
|
+
}
|
|
3509
|
+
if (event.participantObjectIds.length > 0) {
|
|
3510
|
+
lines.push(` participants ${event.participantObjectIds.join(" ")}`);
|
|
3511
|
+
}
|
|
3512
|
+
if (event.timing) {
|
|
3513
|
+
lines.push(` timing ${quoteIfNeeded(event.timing)}`);
|
|
3514
|
+
}
|
|
3515
|
+
if (event.visibility) {
|
|
3516
|
+
lines.push(` visibility ${quoteIfNeeded(event.visibility)}`);
|
|
3517
|
+
}
|
|
3518
|
+
if (event.tags.length > 0) {
|
|
3519
|
+
lines.push(` tags ${event.tags.map(quoteIfNeeded).join(" ")}`);
|
|
3520
|
+
}
|
|
3521
|
+
if (event.color) {
|
|
3522
|
+
lines.push(` color ${quoteIfNeeded(event.color)}`);
|
|
3523
|
+
}
|
|
3524
|
+
if (event.hidden) {
|
|
3525
|
+
lines.push(" hidden true");
|
|
3526
|
+
}
|
|
3527
|
+
if (event.positions.length > 0) {
|
|
3528
|
+
lines.push("");
|
|
3529
|
+
lines.push(" positions");
|
|
3530
|
+
for (const pose of [...event.positions].sort(comparePoseObjectId)) {
|
|
3531
|
+
lines.push(` pose ${pose.objectId}`);
|
|
3532
|
+
for (const fieldLine of formatEventPoseFields(pose)) {
|
|
3533
|
+
lines.push(` ${fieldLine}`);
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
return lines;
|
|
3538
|
+
}
|
|
3539
|
+
function formatEventPoseFields(pose) {
|
|
3540
|
+
return [
|
|
3541
|
+
...formatPlacement(pose.placement),
|
|
3542
|
+
...formatOptionalUnit("inner", pose.inner),
|
|
3543
|
+
...formatOptionalUnit("outer", pose.outer)
|
|
3544
|
+
];
|
|
3545
|
+
}
|
|
2994
3546
|
function formatValue(value) {
|
|
2995
3547
|
if (Array.isArray(value)) {
|
|
2996
3548
|
return value.map((item) => quoteIfNeeded(item)).join(" ");
|
|
@@ -3032,7 +3584,7 @@ var WorldOrbit = (() => {
|
|
|
3032
3584
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
3033
3585
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
3034
3586
|
}
|
|
3035
|
-
for (const key of ["background", "guides", "objects", "labels", "metadata"]) {
|
|
3587
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
3036
3588
|
if (layers[key] !== void 0) {
|
|
3037
3589
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
3038
3590
|
}
|
|
@@ -3057,6 +3609,12 @@ var WorldOrbit = (() => {
|
|
|
3057
3609
|
return leftIndex - rightIndex;
|
|
3058
3610
|
return left.id.localeCompare(right.id);
|
|
3059
3611
|
}
|
|
3612
|
+
function compareIdLike(left, right) {
|
|
3613
|
+
return left.id.localeCompare(right.id);
|
|
3614
|
+
}
|
|
3615
|
+
function comparePoseObjectId(left, right) {
|
|
3616
|
+
return left.objectId.localeCompare(right.objectId);
|
|
3617
|
+
}
|
|
3060
3618
|
function objectTypeIndex(objectType) {
|
|
3061
3619
|
switch (objectType) {
|
|
3062
3620
|
case "star":
|
|
@@ -3086,107 +3644,760 @@ var WorldOrbit = (() => {
|
|
|
3086
3644
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
3087
3645
|
}
|
|
3088
3646
|
|
|
3089
|
-
// packages/core/dist/
|
|
3090
|
-
|
|
3091
|
-
|
|
3647
|
+
// packages/core/dist/atlas-utils.js
|
|
3648
|
+
var UNIT_PATTERN2 = /^(-?\d+(?:\.\d+)?)(kpc|min|mj|rj|ky|my|gy|au|km|me|re|pc|ly|deg|sol|K|m|s|h|d|y)?$/;
|
|
3649
|
+
var BOOLEAN_VALUES2 = /* @__PURE__ */ new Map([
|
|
3650
|
+
["true", true],
|
|
3651
|
+
["false", false],
|
|
3652
|
+
["yes", true],
|
|
3653
|
+
["no", false]
|
|
3654
|
+
]);
|
|
3655
|
+
var URL_SCHEME_PATTERN2 = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
3656
|
+
function normalizeIdentifier2(value) {
|
|
3657
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3092
3658
|
}
|
|
3093
|
-
function
|
|
3094
|
-
return
|
|
3659
|
+
function humanizeIdentifier3(value) {
|
|
3660
|
+
return value.split(/[-_]+/).filter(Boolean).map((segment) => segment[0].toUpperCase() + segment.slice(1)).join(" ");
|
|
3095
3661
|
}
|
|
3096
|
-
function
|
|
3097
|
-
const
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
let system = null;
|
|
3101
|
-
let section = null;
|
|
3102
|
-
const objectNodes = [];
|
|
3103
|
-
let sawDefaults = false;
|
|
3104
|
-
let sawAtlas = false;
|
|
3105
|
-
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3106
|
-
const annotationIds = /* @__PURE__ */ new Set();
|
|
3107
|
-
for (let index = 0; index < lines.length; index++) {
|
|
3108
|
-
const rawLine = lines[index];
|
|
3109
|
-
const lineNumber = index + 1;
|
|
3110
|
-
if (!rawLine.trim()) {
|
|
3111
|
-
continue;
|
|
3112
|
-
}
|
|
3113
|
-
const indent = getIndent(rawLine);
|
|
3114
|
-
const tokens = tokenizeLineDetailed(rawLine.slice(indent), {
|
|
3115
|
-
line: lineNumber,
|
|
3116
|
-
columnOffset: indent
|
|
3117
|
-
});
|
|
3118
|
-
if (tokens.length === 0) {
|
|
3119
|
-
continue;
|
|
3120
|
-
}
|
|
3121
|
-
if (!sawSchemaHeader) {
|
|
3122
|
-
schemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
3123
|
-
sawSchemaHeader = true;
|
|
3124
|
-
continue;
|
|
3125
|
-
}
|
|
3126
|
-
if (indent === 0) {
|
|
3127
|
-
section = startTopLevelSection(tokens, lineNumber, system, objectNodes, viewpointIds, annotationIds, {
|
|
3128
|
-
sawDefaults,
|
|
3129
|
-
sawAtlas
|
|
3130
|
-
});
|
|
3131
|
-
if (section.kind === "system") {
|
|
3132
|
-
system = section.system;
|
|
3133
|
-
} else if (section.kind === "defaults") {
|
|
3134
|
-
sawDefaults = true;
|
|
3135
|
-
} else if (section.kind === "atlas") {
|
|
3136
|
-
sawAtlas = true;
|
|
3137
|
-
}
|
|
3138
|
-
continue;
|
|
3139
|
-
}
|
|
3140
|
-
if (!section) {
|
|
3141
|
-
throw new WorldOrbitError("Indented line without parent atlas section", lineNumber, indent + 1);
|
|
3142
|
-
}
|
|
3143
|
-
handleSectionLine(section, indent, tokens, lineNumber);
|
|
3144
|
-
}
|
|
3145
|
-
if (!sawSchemaHeader) {
|
|
3146
|
-
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3662
|
+
function parseAtlasUnitValue(input, location, fieldKey) {
|
|
3663
|
+
const match = input.match(UNIT_PATTERN2);
|
|
3664
|
+
if (!match) {
|
|
3665
|
+
throw WorldOrbitError.fromLocation(`Invalid unit value "${input}"`, location);
|
|
3147
3666
|
}
|
|
3148
|
-
const
|
|
3149
|
-
|
|
3150
|
-
|
|
3667
|
+
const unitValue = {
|
|
3668
|
+
value: Number(match[1]),
|
|
3669
|
+
unit: match[2] ?? null
|
|
3151
3670
|
};
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
system: null,
|
|
3157
|
-
objects: normalizedObjects
|
|
3158
|
-
});
|
|
3159
|
-
const diagnostics = schemaVersion === "2.0-draft" && outputVersion === "2.0" ? [
|
|
3160
|
-
{
|
|
3161
|
-
code: "load.schema.deprecatedDraft",
|
|
3162
|
-
severity: "warning",
|
|
3163
|
-
source: "upgrade",
|
|
3164
|
-
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
3671
|
+
if (fieldKey) {
|
|
3672
|
+
const schema = getFieldSchema(fieldKey);
|
|
3673
|
+
if (schema?.unitFamily && !unitFamilyAllowsUnit(schema.unitFamily, unitValue.unit)) {
|
|
3674
|
+
throw WorldOrbitError.fromLocation(`Unit "${unitValue.unit ?? "none"}" is not valid for "${fieldKey}"`, location);
|
|
3165
3675
|
}
|
|
3166
|
-
|
|
3676
|
+
}
|
|
3677
|
+
return unitValue;
|
|
3678
|
+
}
|
|
3679
|
+
function tryParseAtlasUnitValue(input) {
|
|
3680
|
+
const match = input.match(UNIT_PATTERN2);
|
|
3681
|
+
if (!match) {
|
|
3682
|
+
return null;
|
|
3683
|
+
}
|
|
3167
3684
|
return {
|
|
3685
|
+
value: Number(match[1]),
|
|
3686
|
+
unit: match[2] ?? null
|
|
3687
|
+
};
|
|
3688
|
+
}
|
|
3689
|
+
function parseAtlasNumber(input, key, location) {
|
|
3690
|
+
const value = Number(input);
|
|
3691
|
+
if (!Number.isFinite(value)) {
|
|
3692
|
+
throw WorldOrbitError.fromLocation(`Invalid numeric value "${input}" for "${key}"`, location);
|
|
3693
|
+
}
|
|
3694
|
+
return value;
|
|
3695
|
+
}
|
|
3696
|
+
function parseAtlasBoolean(input, key, location) {
|
|
3697
|
+
const parsed = BOOLEAN_VALUES2.get(input.toLowerCase());
|
|
3698
|
+
if (parsed === void 0) {
|
|
3699
|
+
throw WorldOrbitError.fromLocation(`Invalid boolean value "${input}" for "${key}"`, location);
|
|
3700
|
+
}
|
|
3701
|
+
return parsed;
|
|
3702
|
+
}
|
|
3703
|
+
function parseAtlasAtReference(target, location) {
|
|
3704
|
+
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
3705
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
3706
|
+
}
|
|
3707
|
+
const pairedMatch = target.match(/^([A-Za-z0-9._-]+)-([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
3708
|
+
if (pairedMatch) {
|
|
3709
|
+
return {
|
|
3710
|
+
kind: "lagrange",
|
|
3711
|
+
primary: pairedMatch[1],
|
|
3712
|
+
secondary: pairedMatch[2],
|
|
3713
|
+
point: pairedMatch[3]
|
|
3714
|
+
};
|
|
3715
|
+
}
|
|
3716
|
+
const simpleMatch = target.match(/^([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
3717
|
+
if (simpleMatch) {
|
|
3718
|
+
return {
|
|
3719
|
+
kind: "lagrange",
|
|
3720
|
+
primary: simpleMatch[1],
|
|
3721
|
+
secondary: null,
|
|
3722
|
+
point: simpleMatch[2]
|
|
3723
|
+
};
|
|
3724
|
+
}
|
|
3725
|
+
if (/^[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
3726
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
3727
|
+
}
|
|
3728
|
+
const anchorMatch = target.match(/^([A-Za-z0-9._-]+):([A-Za-z0-9._-]+)$/);
|
|
3729
|
+
if (anchorMatch) {
|
|
3730
|
+
return {
|
|
3731
|
+
kind: "anchor",
|
|
3732
|
+
objectId: anchorMatch[1],
|
|
3733
|
+
anchor: anchorMatch[2]
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3736
|
+
return {
|
|
3737
|
+
kind: "named",
|
|
3738
|
+
name: target
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3741
|
+
function validateAtlasImageSource(value, location) {
|
|
3742
|
+
if (!value) {
|
|
3743
|
+
throw WorldOrbitError.fromLocation('Field "image" must not be empty', location);
|
|
3744
|
+
}
|
|
3745
|
+
if (value.startsWith("//")) {
|
|
3746
|
+
throw WorldOrbitError.fromLocation('Field "image" must use a relative path, root-relative path, or an http/https URL', location);
|
|
3747
|
+
}
|
|
3748
|
+
const schemeMatch = value.match(URL_SCHEME_PATTERN2);
|
|
3749
|
+
if (!schemeMatch) {
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
const scheme = schemeMatch[0].slice(0, -1).toLowerCase();
|
|
3753
|
+
if (scheme !== "http" && scheme !== "https") {
|
|
3754
|
+
throw WorldOrbitError.fromLocation(`Field "image" does not support the "${scheme}" scheme`, location);
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
function normalizeLegacyScalarValue(key, values, location) {
|
|
3758
|
+
const schema = getFieldSchema(key);
|
|
3759
|
+
if (!schema) {
|
|
3760
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
3761
|
+
}
|
|
3762
|
+
if (schema.arity === "single" && values.length !== 1) {
|
|
3763
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
3764
|
+
}
|
|
3765
|
+
switch (schema.kind) {
|
|
3766
|
+
case "list":
|
|
3767
|
+
return values;
|
|
3768
|
+
case "boolean":
|
|
3769
|
+
return parseAtlasBoolean(singleAtlasValue(values, key, location), key, location);
|
|
3770
|
+
case "number":
|
|
3771
|
+
return parseAtlasNumber(singleAtlasValue(values, key, location), key, location);
|
|
3772
|
+
case "unit":
|
|
3773
|
+
return parseAtlasUnitValue(singleAtlasValue(values, key, location), location, key);
|
|
3774
|
+
case "string": {
|
|
3775
|
+
const value = values.join(" ").trim();
|
|
3776
|
+
if (key === "image") {
|
|
3777
|
+
validateAtlasImageSource(value, location);
|
|
3778
|
+
}
|
|
3779
|
+
return value;
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
function ensureAtlasFieldSupported(key, objectType, location) {
|
|
3784
|
+
const schema = getFieldSchema(key);
|
|
3785
|
+
if (!schema) {
|
|
3786
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
3787
|
+
}
|
|
3788
|
+
if (!schema.objectTypes.includes(objectType)) {
|
|
3789
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" is not valid on "${objectType}"`, location);
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
function singleAtlasValue(values, key, location) {
|
|
3793
|
+
if (values.length !== 1) {
|
|
3794
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
3795
|
+
}
|
|
3796
|
+
return values[0];
|
|
3797
|
+
}
|
|
3798
|
+
|
|
3799
|
+
// packages/core/dist/atlas-validate.js
|
|
3800
|
+
var SURFACE_TARGET_TYPES2 = /* @__PURE__ */ new Set(["star", "planet", "moon", "asteroid", "comet"]);
|
|
3801
|
+
var EARTH_MASSES_PER_SOLAR = 332946.0487;
|
|
3802
|
+
var JUPITER_MASSES_PER_SOLAR = 1047.3486;
|
|
3803
|
+
var AU_IN_KM2 = 1495978707e-1;
|
|
3804
|
+
var EARTH_RADIUS_IN_KM2 = 6371;
|
|
3805
|
+
var SOLAR_RADIUS_IN_KM2 = 695700;
|
|
3806
|
+
var LY_IN_AU2 = 63241.077;
|
|
3807
|
+
var PC_IN_AU2 = 206264.806;
|
|
3808
|
+
var KPC_IN_AU2 = 206264806;
|
|
3809
|
+
function collectAtlasDiagnostics(document, sourceSchemaVersion) {
|
|
3810
|
+
const diagnostics = [];
|
|
3811
|
+
const objectMap = new Map(document.objects.map((object) => [object.id, object]));
|
|
3812
|
+
const groupIds = new Set(document.groups.map((group) => group.id));
|
|
3813
|
+
const eventIds = new Set(document.events.map((event) => event.id));
|
|
3814
|
+
if (!document.system) {
|
|
3815
|
+
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
3816
|
+
}
|
|
3817
|
+
const knownIds = /* @__PURE__ */ new Map();
|
|
3818
|
+
for (const [kind, ids] of [
|
|
3819
|
+
["group", document.groups.map((group) => group.id)],
|
|
3820
|
+
["viewpoint", document.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
3821
|
+
["annotation", document.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
3822
|
+
["relation", document.relations.map((relation) => relation.id)],
|
|
3823
|
+
["event", document.events.map((event) => event.id)],
|
|
3824
|
+
["object", document.objects.map((object) => object.id)]
|
|
3825
|
+
]) {
|
|
3826
|
+
for (const id of ids) {
|
|
3827
|
+
const previous = knownIds.get(id);
|
|
3828
|
+
if (previous) {
|
|
3829
|
+
diagnostics.push(error("validate.id.duplicate", `Duplicate ${kind} id "${id}" already used by ${previous}.`));
|
|
3830
|
+
} else {
|
|
3831
|
+
knownIds.set(id, kind);
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
for (const relation of document.relations) {
|
|
3836
|
+
validateRelation(relation, objectMap, diagnostics);
|
|
3837
|
+
}
|
|
3838
|
+
for (const viewpoint of document.system?.viewpoints ?? []) {
|
|
3839
|
+
validateViewpoint(viewpoint.filter, viewpoint.events ?? [], groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpoint.id);
|
|
3840
|
+
}
|
|
3841
|
+
for (const object of document.objects) {
|
|
3842
|
+
validateObject(object, document.system, objectMap, groupIds, diagnostics);
|
|
3843
|
+
}
|
|
3844
|
+
for (const event of document.events) {
|
|
3845
|
+
validateEvent(event, objectMap, diagnostics);
|
|
3846
|
+
}
|
|
3847
|
+
return diagnostics;
|
|
3848
|
+
}
|
|
3849
|
+
function validateRelation(relation, objectMap, diagnostics) {
|
|
3850
|
+
if (!relation.from) {
|
|
3851
|
+
diagnostics.push(error("validate.relation.from.required", `Relation "${relation.id}" is missing a "from" target.`));
|
|
3852
|
+
} else if (!objectMap.has(relation.from)) {
|
|
3853
|
+
diagnostics.push(error("validate.relation.from.unknown", `Unknown relation source "${relation.from}" on "${relation.id}".`));
|
|
3854
|
+
}
|
|
3855
|
+
if (!relation.to) {
|
|
3856
|
+
diagnostics.push(error("validate.relation.to.required", `Relation "${relation.id}" is missing a "to" target.`));
|
|
3857
|
+
} else if (!objectMap.has(relation.to)) {
|
|
3858
|
+
diagnostics.push(error("validate.relation.to.unknown", `Unknown relation target "${relation.to}" on "${relation.id}".`));
|
|
3859
|
+
}
|
|
3860
|
+
if (!relation.kind) {
|
|
3861
|
+
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
function validateViewpoint(filter, eventRefs, groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpointId) {
|
|
3865
|
+
if (sourceSchemaVersion === "2.1") {
|
|
3866
|
+
if (filter) {
|
|
3867
|
+
for (const groupId of filter.groupIds) {
|
|
3868
|
+
if (!groupIds.has(groupId)) {
|
|
3869
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.groups`));
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
for (const eventId of eventRefs) {
|
|
3874
|
+
if (!eventIds.has(eventId)) {
|
|
3875
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.events`));
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
function validateObject(object, system, objectMap, groupIds, diagnostics) {
|
|
3881
|
+
const placement = object.placement;
|
|
3882
|
+
const orbitPlacement = placement?.mode === "orbit" ? placement : null;
|
|
3883
|
+
const parentObject = placement?.mode === "orbit" ? objectMap.get(placement.target) ?? null : null;
|
|
3884
|
+
if (object.groups) {
|
|
3885
|
+
for (const groupId of object.groups) {
|
|
3886
|
+
if (!groupIds.has(groupId)) {
|
|
3887
|
+
diagnostics.push(warn("validate.group.unknown", `Unknown group "${groupId}" on "${object.id}".`, object.id, "groups"));
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
if (orbitPlacement) {
|
|
3892
|
+
if (!objectMap.has(orbitPlacement.target)) {
|
|
3893
|
+
diagnostics.push(error("validate.orbit.target.unknown", `Unknown placement target "${orbitPlacement.target}" on "${object.id}".`, object.id, "orbit"));
|
|
3894
|
+
}
|
|
3895
|
+
if (orbitPlacement.distance && orbitPlacement.semiMajor) {
|
|
3896
|
+
diagnostics.push(error("validate.orbit.distanceConflict", `Object "${object.id}" cannot declare both "distance" and "semiMajor".`, object.id, "distance"));
|
|
3897
|
+
}
|
|
3898
|
+
if (orbitPlacement.phase && !object.epoch && !system?.epoch) {
|
|
3899
|
+
diagnostics.push(warn("validate.phase.epochMissing", `Object "${object.id}" sets "phase" without an object or system epoch.`, object.id, "phase"));
|
|
3900
|
+
}
|
|
3901
|
+
if (orbitPlacement.inclination && !object.referencePlane && !system?.referencePlane) {
|
|
3902
|
+
diagnostics.push(warn("validate.inclination.referencePlaneMissing", `Object "${object.id}" sets "inclination" without an object or system reference plane.`, object.id, "inclination"));
|
|
3903
|
+
}
|
|
3904
|
+
if (orbitPlacement.period && !massInSolar(parentObject?.properties.mass)) {
|
|
3905
|
+
diagnostics.push(warn("validate.period.massMissing", `Object "${object.id}" sets "period" but its central mass cannot be derived.`, object.id, "period"));
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
if (placement?.mode === "surface") {
|
|
3909
|
+
const target = objectMap.get(placement.target);
|
|
3910
|
+
if (!target) {
|
|
3911
|
+
diagnostics.push(error("validate.surface.target.unknown", `Unknown placement target "${placement.target}" on "${object.id}".`, object.id, "surface"));
|
|
3912
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3913
|
+
diagnostics.push(error("validate.surface.target.invalid", `Surface target "${placement.target}" on "${object.id}" is not surface-capable.`, object.id, "surface"));
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
if (placement?.mode === "at") {
|
|
3917
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3918
|
+
diagnostics.push(error("validate.at.objectType", `Only structures and phenomena may use "at" placement; found "${object.type}" on "${object.id}".`, object.id, "at"));
|
|
3919
|
+
}
|
|
3920
|
+
if (!validateAtTarget(object, objectMap, diagnostics)) {
|
|
3921
|
+
diagnostics.push(error("validate.at.target.unknown", `Unknown at-reference target "${placement.target}" on "${object.id}".`, object.id, "at"));
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
if (object.resonance) {
|
|
3925
|
+
const target = objectMap.get(object.resonance.targetObjectId);
|
|
3926
|
+
if (!target) {
|
|
3927
|
+
diagnostics.push(error("validate.resonance.target.unknown", `Unknown resonance target "${object.resonance.targetObjectId}" on "${object.id}".`, object.id, "resonance"));
|
|
3928
|
+
} else if (object.placement?.mode !== "orbit" || target.placement?.mode !== "orbit" || object.placement.target !== target.placement.target) {
|
|
3929
|
+
diagnostics.push(warn("validate.resonance.orbitMismatch", `Resonance target "${object.resonance.targetObjectId}" on "${object.id}" does not share a compatible orbital parent.`, object.id, "resonance"));
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
for (const rule of object.deriveRules ?? []) {
|
|
3933
|
+
if (rule.field !== "period" || rule.strategy !== "kepler") {
|
|
3934
|
+
diagnostics.push(warn("validate.derive.unsupported", `Unsupported derive rule "${rule.field} ${rule.strategy}" on "${object.id}".`, object.id, "derive"));
|
|
3935
|
+
continue;
|
|
3936
|
+
}
|
|
3937
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3938
|
+
if (derivedPeriodDays === null) {
|
|
3939
|
+
diagnostics.push(warn("validate.derive.inputsMissing", `Object "${object.id}" requests "derive period kepler" but lacks enough input data.`, object.id, "derive"));
|
|
3940
|
+
continue;
|
|
3941
|
+
}
|
|
3942
|
+
if (!orbitPlacement?.period) {
|
|
3943
|
+
diagnostics.push(info("validate.derive.period.available", `Object "${object.id}" can derive a Kepler period of ${formatDays(derivedPeriodDays)}.`, object.id, "derive"));
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
for (const rule of object.validationRules ?? []) {
|
|
3947
|
+
if (rule.rule !== "kepler") {
|
|
3948
|
+
diagnostics.push(warn("validate.rule.unsupported", `Unsupported validation rule "${rule.rule}" on "${object.id}".`, object.id, "validate"));
|
|
3949
|
+
continue;
|
|
3950
|
+
}
|
|
3951
|
+
const actualPeriodDays = durationInDays(orbitPlacement?.period);
|
|
3952
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3953
|
+
if (actualPeriodDays === null || derivedPeriodDays === null) {
|
|
3954
|
+
continue;
|
|
3955
|
+
}
|
|
3956
|
+
const toleranceDays = toleranceForField(object, "period");
|
|
3957
|
+
if (Math.abs(actualPeriodDays - derivedPeriodDays) > toleranceDays) {
|
|
3958
|
+
diagnostics.push(error("validate.kepler.mismatch", `Object "${object.id}" fails Kepler validation for "period".`, object.id, "validate"));
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
function validateEvent(event, objectMap, diagnostics) {
|
|
3963
|
+
const fieldPrefix = `event.${event.id}`;
|
|
3964
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
3965
|
+
if (!event.kind.trim()) {
|
|
3966
|
+
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
3967
|
+
}
|
|
3968
|
+
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3969
|
+
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3970
|
+
}
|
|
3971
|
+
if (event.targetObjectId) {
|
|
3972
|
+
referencedIds.add(event.targetObjectId);
|
|
3973
|
+
if (!objectMap.has(event.targetObjectId)) {
|
|
3974
|
+
diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
const seenParticipants = /* @__PURE__ */ new Set();
|
|
3978
|
+
for (const participantId of event.participantObjectIds) {
|
|
3979
|
+
referencedIds.add(participantId);
|
|
3980
|
+
if (seenParticipants.has(participantId)) {
|
|
3981
|
+
diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
|
|
3982
|
+
continue;
|
|
3983
|
+
}
|
|
3984
|
+
seenParticipants.add(participantId);
|
|
3985
|
+
if (!objectMap.has(participantId)) {
|
|
3986
|
+
diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
|
|
3990
|
+
diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
|
|
3991
|
+
}
|
|
3992
|
+
if (event.positions.length === 0) {
|
|
3993
|
+
diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
|
|
3994
|
+
}
|
|
3995
|
+
if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
|
|
3996
|
+
diagnostics.push(warn("validate.event.kind.participants", `Event "${event.id}" looks like an eclipse or transit but references fewer than three bodies.`, void 0, `${fieldPrefix}.participants`));
|
|
3997
|
+
}
|
|
3998
|
+
const poseIds = /* @__PURE__ */ new Set();
|
|
3999
|
+
for (const pose of event.positions) {
|
|
4000
|
+
const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
|
|
4001
|
+
if (poseIds.has(pose.objectId)) {
|
|
4002
|
+
diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
|
|
4003
|
+
continue;
|
|
4004
|
+
}
|
|
4005
|
+
poseIds.add(pose.objectId);
|
|
4006
|
+
const object = objectMap.get(pose.objectId);
|
|
4007
|
+
if (!object) {
|
|
4008
|
+
diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
|
|
4009
|
+
continue;
|
|
4010
|
+
}
|
|
4011
|
+
if (!referencedIds.has(pose.objectId)) {
|
|
4012
|
+
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
4013
|
+
}
|
|
4014
|
+
validateEventPose(pose, object, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
function validateEventPose(pose, object, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
4018
|
+
const placement = pose.placement;
|
|
4019
|
+
if (!placement) {
|
|
4020
|
+
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
4021
|
+
return;
|
|
4022
|
+
}
|
|
4023
|
+
if (placement.mode === "orbit") {
|
|
4024
|
+
if (!objectMap.has(placement.target)) {
|
|
4025
|
+
diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
|
|
4026
|
+
}
|
|
4027
|
+
if (placement.distance && placement.semiMajor) {
|
|
4028
|
+
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
4029
|
+
}
|
|
4030
|
+
return;
|
|
4031
|
+
}
|
|
4032
|
+
if (placement.mode === "surface") {
|
|
4033
|
+
const target = objectMap.get(placement.target);
|
|
4034
|
+
if (!target) {
|
|
4035
|
+
diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
|
|
4036
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
4037
|
+
diagnostics.push(error("validate.event.pose.surface.target.invalid", `Event surface target "${placement.target}" on "${eventId}:${pose.objectId}" is not surface-capable.`, void 0, `${fieldPrefix}.surface`));
|
|
4038
|
+
}
|
|
4039
|
+
return;
|
|
4040
|
+
}
|
|
4041
|
+
if (placement.mode === "at") {
|
|
4042
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
4043
|
+
diagnostics.push(error("validate.event.pose.at.objectType", `Only structures and phenomena may use "at" placement in events; found "${object.type}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
4044
|
+
}
|
|
4045
|
+
const reference = placement.reference;
|
|
4046
|
+
if (reference.kind === "named" && !objectMap.has(reference.name)) {
|
|
4047
|
+
diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
4048
|
+
} else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
|
|
4049
|
+
diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
4050
|
+
} else if (reference.kind === "lagrange") {
|
|
4051
|
+
if (!objectMap.has(reference.primary)) {
|
|
4052
|
+
diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
4053
|
+
} else if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
4054
|
+
diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
function validateAtTarget(object, objectMap, diagnostics) {
|
|
4060
|
+
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
4061
|
+
if (!reference) {
|
|
4062
|
+
return true;
|
|
4063
|
+
}
|
|
4064
|
+
if (reference.kind === "named") {
|
|
4065
|
+
return objectMap.has(reference.name);
|
|
4066
|
+
}
|
|
4067
|
+
if (reference.kind === "anchor") {
|
|
4068
|
+
if (!objectMap.has(reference.objectId)) {
|
|
4069
|
+
diagnostics.push(error("validate.anchor.target.unknown", `Unknown anchor target "${reference.objectId}" on "${object.id}".`, object.id, "at"));
|
|
4070
|
+
return false;
|
|
4071
|
+
}
|
|
4072
|
+
return true;
|
|
4073
|
+
}
|
|
4074
|
+
if (!objectMap.has(reference.primary)) {
|
|
4075
|
+
diagnostics.push(error("validate.lagrange.primary.unknown", `Unknown Lagrange reference "${reference.primary}" on "${object.id}".`, object.id, "at"));
|
|
4076
|
+
return false;
|
|
4077
|
+
}
|
|
4078
|
+
if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
4079
|
+
diagnostics.push(error("validate.lagrange.secondary.unknown", `Unknown Lagrange reference "${reference.secondary}" on "${object.id}".`, object.id, "at"));
|
|
4080
|
+
return false;
|
|
4081
|
+
}
|
|
4082
|
+
return true;
|
|
4083
|
+
}
|
|
4084
|
+
function keplerPeriodDays(object, parentObject) {
|
|
4085
|
+
const placement = object.placement;
|
|
4086
|
+
if (!placement || placement.mode !== "orbit") {
|
|
4087
|
+
return null;
|
|
4088
|
+
}
|
|
4089
|
+
const semiMajorAu = distanceInAu(placement.semiMajor ?? placement.distance);
|
|
4090
|
+
const centralMassSolar = massInSolar(parentObject?.properties.mass);
|
|
4091
|
+
if (semiMajorAu === null || centralMassSolar === null || centralMassSolar <= 0) {
|
|
4092
|
+
return null;
|
|
4093
|
+
}
|
|
4094
|
+
const periodYears = Math.sqrt(semiMajorAu ** 3 / centralMassSolar);
|
|
4095
|
+
return periodYears * 365.25;
|
|
4096
|
+
}
|
|
4097
|
+
function distanceInAu(value) {
|
|
4098
|
+
if (!value)
|
|
4099
|
+
return null;
|
|
4100
|
+
switch (value.unit) {
|
|
4101
|
+
case null:
|
|
4102
|
+
case "au":
|
|
4103
|
+
return value.value;
|
|
4104
|
+
case "km":
|
|
4105
|
+
return value.value / AU_IN_KM2;
|
|
4106
|
+
case "m":
|
|
4107
|
+
return value.value / (AU_IN_KM2 * 1e3);
|
|
4108
|
+
case "ly":
|
|
4109
|
+
return value.value * LY_IN_AU2;
|
|
4110
|
+
case "pc":
|
|
4111
|
+
return value.value * PC_IN_AU2;
|
|
4112
|
+
case "kpc":
|
|
4113
|
+
return value.value * KPC_IN_AU2;
|
|
4114
|
+
case "re":
|
|
4115
|
+
return value.value * EARTH_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
4116
|
+
case "sol":
|
|
4117
|
+
return value.value * SOLAR_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
4118
|
+
default:
|
|
4119
|
+
return null;
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
function massInSolar(value) {
|
|
4123
|
+
if (!value || typeof value !== "object" || !("value" in value)) {
|
|
4124
|
+
return null;
|
|
4125
|
+
}
|
|
4126
|
+
const unitValue = value;
|
|
4127
|
+
switch (unitValue.unit) {
|
|
4128
|
+
case null:
|
|
4129
|
+
case "sol":
|
|
4130
|
+
return unitValue.value;
|
|
4131
|
+
case "me":
|
|
4132
|
+
return unitValue.value / EARTH_MASSES_PER_SOLAR;
|
|
4133
|
+
case "mj":
|
|
4134
|
+
return unitValue.value / JUPITER_MASSES_PER_SOLAR;
|
|
4135
|
+
default:
|
|
4136
|
+
return null;
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
function durationInDays(value) {
|
|
4140
|
+
if (!value)
|
|
4141
|
+
return null;
|
|
4142
|
+
switch (value.unit) {
|
|
4143
|
+
case null:
|
|
4144
|
+
case "d":
|
|
4145
|
+
return value.value;
|
|
4146
|
+
case "s":
|
|
4147
|
+
return value.value / 86400;
|
|
4148
|
+
case "min":
|
|
4149
|
+
return value.value / 1440;
|
|
4150
|
+
case "h":
|
|
4151
|
+
return value.value / 24;
|
|
4152
|
+
case "y":
|
|
4153
|
+
return value.value * 365.25;
|
|
4154
|
+
case "ky":
|
|
4155
|
+
return value.value * 365250;
|
|
4156
|
+
case "my":
|
|
4157
|
+
return value.value * 36525e4;
|
|
4158
|
+
case "gy":
|
|
4159
|
+
return value.value * 36525e7;
|
|
4160
|
+
default:
|
|
4161
|
+
return null;
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
function toleranceForField(object, field) {
|
|
4165
|
+
const tolerance = object.tolerances?.find((entry) => entry.field === field)?.value;
|
|
4166
|
+
if (typeof tolerance === "number") {
|
|
4167
|
+
return tolerance;
|
|
4168
|
+
}
|
|
4169
|
+
if (tolerance && typeof tolerance === "object" && "value" in tolerance) {
|
|
4170
|
+
return durationInDays(tolerance) ?? 0;
|
|
4171
|
+
}
|
|
4172
|
+
return 0;
|
|
4173
|
+
}
|
|
4174
|
+
function formatDays(days) {
|
|
4175
|
+
return `${Math.round(days * 100) / 100}d`;
|
|
4176
|
+
}
|
|
4177
|
+
function error(code, message, objectId, field) {
|
|
4178
|
+
return { code, severity: "error", source: "validate", message, objectId, field };
|
|
4179
|
+
}
|
|
4180
|
+
function warn(code, message, objectId, field) {
|
|
4181
|
+
return { code, severity: "warning", source: "validate", message, objectId, field };
|
|
4182
|
+
}
|
|
4183
|
+
function info(code, message, objectId, field) {
|
|
4184
|
+
return { code, severity: "info", source: "validate", message, objectId, field };
|
|
4185
|
+
}
|
|
4186
|
+
|
|
4187
|
+
// packages/core/dist/draft-parse.js
|
|
4188
|
+
var STRUCTURED_TYPED_BLOCKS = /* @__PURE__ */ new Set([
|
|
4189
|
+
"climate",
|
|
4190
|
+
"habitability",
|
|
4191
|
+
"settlement"
|
|
4192
|
+
]);
|
|
4193
|
+
var DRAFT_OBJECT_FIELD_SPECS = /* @__PURE__ */ new Map();
|
|
4194
|
+
for (const key of [
|
|
4195
|
+
"orbit",
|
|
4196
|
+
"distance",
|
|
4197
|
+
"semiMajor",
|
|
4198
|
+
"eccentricity",
|
|
4199
|
+
"period",
|
|
4200
|
+
"angle",
|
|
4201
|
+
"inclination",
|
|
4202
|
+
"phase",
|
|
4203
|
+
"at",
|
|
4204
|
+
"surface",
|
|
4205
|
+
"free",
|
|
4206
|
+
"kind",
|
|
4207
|
+
"class",
|
|
4208
|
+
"culture",
|
|
4209
|
+
"tags",
|
|
4210
|
+
"color",
|
|
4211
|
+
"image",
|
|
4212
|
+
"hidden",
|
|
4213
|
+
"radius",
|
|
4214
|
+
"mass",
|
|
4215
|
+
"density",
|
|
4216
|
+
"gravity",
|
|
4217
|
+
"temperature",
|
|
4218
|
+
"albedo",
|
|
4219
|
+
"atmosphere",
|
|
4220
|
+
"inner",
|
|
4221
|
+
"outer",
|
|
4222
|
+
"on",
|
|
4223
|
+
"source",
|
|
4224
|
+
"cycle"
|
|
4225
|
+
]) {
|
|
4226
|
+
const schema = getFieldSchema(key);
|
|
4227
|
+
if (schema) {
|
|
4228
|
+
DRAFT_OBJECT_FIELD_SPECS.set(key, {
|
|
4229
|
+
key,
|
|
4230
|
+
version: "2.0",
|
|
4231
|
+
inlineMode: schema.arity === "multiple" ? "multiple" : "single",
|
|
4232
|
+
allowRepeat: false,
|
|
4233
|
+
legacySchema: schema
|
|
4234
|
+
});
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
for (const spec of [
|
|
4238
|
+
{ key: "groups", inlineMode: "multiple", allowRepeat: false },
|
|
4239
|
+
{ key: "epoch", inlineMode: "single", allowRepeat: false },
|
|
4240
|
+
{ key: "referencePlane", inlineMode: "single", allowRepeat: false },
|
|
4241
|
+
{ key: "tidalLock", inlineMode: "single", allowRepeat: false },
|
|
4242
|
+
{ key: "renderLabel", inlineMode: "single", allowRepeat: false },
|
|
4243
|
+
{ key: "renderOrbit", inlineMode: "single", allowRepeat: false },
|
|
4244
|
+
{ key: "renderPriority", inlineMode: "single", allowRepeat: false },
|
|
4245
|
+
{ key: "resonance", inlineMode: "pair", allowRepeat: false },
|
|
4246
|
+
{ key: "derive", inlineMode: "pair", allowRepeat: true },
|
|
4247
|
+
{ key: "validate", inlineMode: "single", allowRepeat: true },
|
|
4248
|
+
{ key: "locked", inlineMode: "multiple", allowRepeat: false },
|
|
4249
|
+
{ key: "tolerance", inlineMode: "pair", allowRepeat: true }
|
|
4250
|
+
]) {
|
|
4251
|
+
DRAFT_OBJECT_FIELD_SPECS.set(spec.key, {
|
|
4252
|
+
key: spec.key,
|
|
4253
|
+
version: "2.1",
|
|
4254
|
+
inlineMode: spec.inlineMode,
|
|
4255
|
+
allowRepeat: spec.allowRepeat
|
|
4256
|
+
});
|
|
4257
|
+
}
|
|
4258
|
+
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
4259
|
+
var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
4260
|
+
"orbit",
|
|
4261
|
+
"distance",
|
|
4262
|
+
"semiMajor",
|
|
4263
|
+
"eccentricity",
|
|
4264
|
+
"period",
|
|
4265
|
+
"angle",
|
|
4266
|
+
"inclination",
|
|
4267
|
+
"phase",
|
|
4268
|
+
"at",
|
|
4269
|
+
"surface",
|
|
4270
|
+
"free",
|
|
4271
|
+
"inner",
|
|
4272
|
+
"outer"
|
|
4273
|
+
]);
|
|
4274
|
+
function parseWorldOrbitAtlas(source) {
|
|
4275
|
+
return parseAtlasSource(source);
|
|
4276
|
+
}
|
|
4277
|
+
function parseWorldOrbitDraft(source) {
|
|
4278
|
+
return parseAtlasSource(source, "2.0-draft");
|
|
4279
|
+
}
|
|
4280
|
+
function parseAtlasSource(source, forcedOutputVersion) {
|
|
4281
|
+
const prepared = preprocessAtlasSource(source);
|
|
4282
|
+
const lines = prepared.source.split(/\r?\n/);
|
|
4283
|
+
const diagnostics = [];
|
|
4284
|
+
let sawSchemaHeader = false;
|
|
4285
|
+
let sourceSchemaVersion = "2.0";
|
|
4286
|
+
let system = null;
|
|
4287
|
+
let section = null;
|
|
4288
|
+
const objectNodes = [];
|
|
4289
|
+
const groups = [];
|
|
4290
|
+
const relations = [];
|
|
4291
|
+
const events = [];
|
|
4292
|
+
const eventPoseNodes = /* @__PURE__ */ new Map();
|
|
4293
|
+
let sawDefaults = false;
|
|
4294
|
+
let sawAtlas = false;
|
|
4295
|
+
const viewpointIds = /* @__PURE__ */ new Set();
|
|
4296
|
+
const annotationIds = /* @__PURE__ */ new Set();
|
|
4297
|
+
const groupIds = /* @__PURE__ */ new Set();
|
|
4298
|
+
const relationIds = /* @__PURE__ */ new Set();
|
|
4299
|
+
const eventIds = /* @__PURE__ */ new Set();
|
|
4300
|
+
for (let index = 0; index < lines.length; index++) {
|
|
4301
|
+
const rawLine = lines[index];
|
|
4302
|
+
const lineNumber = index + 1;
|
|
4303
|
+
if (!rawLine.trim()) {
|
|
4304
|
+
continue;
|
|
4305
|
+
}
|
|
4306
|
+
const indent = getIndent(rawLine);
|
|
4307
|
+
const tokens = tokenizeLineDetailed(rawLine.slice(indent), {
|
|
4308
|
+
line: lineNumber,
|
|
4309
|
+
columnOffset: indent
|
|
4310
|
+
});
|
|
4311
|
+
if (tokens.length === 0) {
|
|
4312
|
+
continue;
|
|
4313
|
+
}
|
|
4314
|
+
if (!sawSchemaHeader) {
|
|
4315
|
+
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
4316
|
+
sawSchemaHeader = true;
|
|
4317
|
+
if (prepared.comments.length > 0 && sourceSchemaVersion !== "2.1") {
|
|
4318
|
+
diagnostics.push({
|
|
4319
|
+
code: "parse.schema21.commentCompatibility",
|
|
4320
|
+
severity: "warning",
|
|
4321
|
+
source: "parse",
|
|
4322
|
+
message: `Comments require schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
4323
|
+
line: prepared.comments[0].line,
|
|
4324
|
+
column: prepared.comments[0].column
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4327
|
+
continue;
|
|
4328
|
+
}
|
|
4329
|
+
if (indent === 0) {
|
|
4330
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
4331
|
+
if (section.kind === "system") {
|
|
4332
|
+
system = section.system;
|
|
4333
|
+
} else if (section.kind === "defaults") {
|
|
4334
|
+
sawDefaults = true;
|
|
4335
|
+
} else if (section.kind === "atlas") {
|
|
4336
|
+
sawAtlas = true;
|
|
4337
|
+
}
|
|
4338
|
+
continue;
|
|
4339
|
+
}
|
|
4340
|
+
if (!section) {
|
|
4341
|
+
throw new WorldOrbitError("Indented line without parent atlas section", lineNumber, indent + 1);
|
|
4342
|
+
}
|
|
4343
|
+
handleSectionLine(section, indent, tokens, lineNumber);
|
|
4344
|
+
}
|
|
4345
|
+
if (!sawSchemaHeader) {
|
|
4346
|
+
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
4347
|
+
}
|
|
4348
|
+
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
4349
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
4350
|
+
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
4351
|
+
const baseDocument = {
|
|
3168
4352
|
format: "worldorbit",
|
|
3169
|
-
version: outputVersion,
|
|
3170
4353
|
sourceVersion: "1.0",
|
|
3171
4354
|
system,
|
|
3172
|
-
|
|
4355
|
+
groups,
|
|
4356
|
+
relations,
|
|
4357
|
+
events: normalizedEvents,
|
|
4358
|
+
objects,
|
|
3173
4359
|
diagnostics
|
|
3174
4360
|
};
|
|
4361
|
+
if (outputVersion === "2.0-draft") {
|
|
4362
|
+
const document2 = {
|
|
4363
|
+
...baseDocument,
|
|
4364
|
+
version: "2.0-draft",
|
|
4365
|
+
schemaVersion: "2.0-draft"
|
|
4366
|
+
};
|
|
4367
|
+
document2.diagnostics.push(...collectAtlasDiagnostics(document2, sourceSchemaVersion));
|
|
4368
|
+
return document2;
|
|
4369
|
+
}
|
|
4370
|
+
const document = {
|
|
4371
|
+
...baseDocument,
|
|
4372
|
+
version: outputVersion,
|
|
4373
|
+
schemaVersion: outputVersion
|
|
4374
|
+
};
|
|
4375
|
+
if (sourceSchemaVersion === "2.0-draft") {
|
|
4376
|
+
document.diagnostics.push({
|
|
4377
|
+
code: "load.schema.deprecatedDraft",
|
|
4378
|
+
severity: "warning",
|
|
4379
|
+
source: "upgrade",
|
|
4380
|
+
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
4381
|
+
});
|
|
4382
|
+
}
|
|
4383
|
+
document.diagnostics.push(...collectAtlasDiagnostics(document, sourceSchemaVersion));
|
|
4384
|
+
return document;
|
|
3175
4385
|
}
|
|
3176
4386
|
function assertDraftSchemaHeader(tokens, line) {
|
|
3177
|
-
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" ||
|
|
3178
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0" or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
4387
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1"].includes(tokens[1].value.toLowerCase())) {
|
|
4388
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
3179
4389
|
}
|
|
3180
|
-
|
|
4390
|
+
const version = tokens[1].value.toLowerCase();
|
|
4391
|
+
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3181
4392
|
}
|
|
3182
|
-
function startTopLevelSection(tokens, line, system, objectNodes, viewpointIds, annotationIds, flags) {
|
|
4393
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3183
4394
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
3184
4395
|
switch (keyword) {
|
|
3185
4396
|
case "system":
|
|
3186
4397
|
if (system) {
|
|
3187
4398
|
throw new WorldOrbitError('Atlas section "system" may only appear once', line, tokens[0].column);
|
|
3188
4399
|
}
|
|
3189
|
-
return startSystemSection(tokens, line);
|
|
4400
|
+
return startSystemSection(tokens, line, sourceSchemaVersion, diagnostics);
|
|
3190
4401
|
case "defaults":
|
|
3191
4402
|
if (!system) {
|
|
3192
4403
|
throw new WorldOrbitError('Atlas section "defaults" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -3216,19 +4427,28 @@ var WorldOrbit = (() => {
|
|
|
3216
4427
|
if (!system) {
|
|
3217
4428
|
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
3218
4429
|
}
|
|
3219
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
4430
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
3220
4431
|
case "annotation":
|
|
3221
4432
|
if (!system) {
|
|
3222
4433
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
3223
4434
|
}
|
|
3224
4435
|
return startAnnotationSection(tokens, line, system, annotationIds);
|
|
4436
|
+
case "group":
|
|
4437
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "group", { line, column: tokens[0].column });
|
|
4438
|
+
return startGroupSection(tokens, line, groups, groupIds);
|
|
4439
|
+
case "relation":
|
|
4440
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
4441
|
+
return startRelationSection(tokens, line, relations, relationIds);
|
|
4442
|
+
case "event":
|
|
4443
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
4444
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
3225
4445
|
case "object":
|
|
3226
|
-
return startObjectSection(tokens, line, objectNodes);
|
|
4446
|
+
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3227
4447
|
default:
|
|
3228
4448
|
throw new WorldOrbitError(`Unknown atlas section "${tokens[0]?.value ?? ""}"`, line, tokens[0]?.column ?? 1);
|
|
3229
4449
|
}
|
|
3230
4450
|
}
|
|
3231
|
-
function startSystemSection(tokens, line) {
|
|
4451
|
+
function startSystemSection(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
3232
4452
|
if (tokens.length !== 2) {
|
|
3233
4453
|
throw new WorldOrbitError("Invalid atlas system declaration", line, tokens[0]?.column ?? 1);
|
|
3234
4454
|
}
|
|
@@ -3236,6 +4456,9 @@ var WorldOrbit = (() => {
|
|
|
3236
4456
|
type: "system",
|
|
3237
4457
|
id: tokens[1].value,
|
|
3238
4458
|
title: null,
|
|
4459
|
+
description: null,
|
|
4460
|
+
epoch: null,
|
|
4461
|
+
referencePlane: null,
|
|
3239
4462
|
defaults: {
|
|
3240
4463
|
view: "topdown",
|
|
3241
4464
|
scale: null,
|
|
@@ -3250,10 +4473,12 @@ var WorldOrbit = (() => {
|
|
|
3250
4473
|
return {
|
|
3251
4474
|
kind: "system",
|
|
3252
4475
|
system,
|
|
4476
|
+
sourceSchemaVersion,
|
|
4477
|
+
diagnostics,
|
|
3253
4478
|
seenFields: /* @__PURE__ */ new Set()
|
|
3254
4479
|
};
|
|
3255
4480
|
}
|
|
3256
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
4481
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
3257
4482
|
if (tokens.length !== 2) {
|
|
3258
4483
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
3259
4484
|
}
|
|
@@ -3270,6 +4495,7 @@ var WorldOrbit = (() => {
|
|
|
3270
4495
|
summary: "",
|
|
3271
4496
|
focusObjectId: null,
|
|
3272
4497
|
selectedObjectId: null,
|
|
4498
|
+
events: [],
|
|
3273
4499
|
projection: system.defaults.view,
|
|
3274
4500
|
preset: system.defaults.preset,
|
|
3275
4501
|
zoom: null,
|
|
@@ -3282,6 +4508,8 @@ var WorldOrbit = (() => {
|
|
|
3282
4508
|
return {
|
|
3283
4509
|
kind: "viewpoint",
|
|
3284
4510
|
viewpoint,
|
|
4511
|
+
sourceSchemaVersion,
|
|
4512
|
+
diagnostics,
|
|
3285
4513
|
seenFields: /* @__PURE__ */ new Set(),
|
|
3286
4514
|
inFilter: false,
|
|
3287
4515
|
filterIndent: null,
|
|
@@ -3315,7 +4543,107 @@ var WorldOrbit = (() => {
|
|
|
3315
4543
|
seenFields: /* @__PURE__ */ new Set()
|
|
3316
4544
|
};
|
|
3317
4545
|
}
|
|
3318
|
-
function
|
|
4546
|
+
function startGroupSection(tokens, line, groups, groupIds) {
|
|
4547
|
+
if (tokens.length !== 2) {
|
|
4548
|
+
throw new WorldOrbitError("Invalid group declaration", line, tokens[0]?.column ?? 1);
|
|
4549
|
+
}
|
|
4550
|
+
const id = normalizeIdentifier2(tokens[1].value);
|
|
4551
|
+
if (!id) {
|
|
4552
|
+
throw new WorldOrbitError("Group id must not be empty", line, tokens[1].column);
|
|
4553
|
+
}
|
|
4554
|
+
if (groupIds.has(id)) {
|
|
4555
|
+
throw new WorldOrbitError(`Duplicate group id "${id}"`, line, tokens[1].column);
|
|
4556
|
+
}
|
|
4557
|
+
const group = {
|
|
4558
|
+
id,
|
|
4559
|
+
label: humanizeIdentifier3(id),
|
|
4560
|
+
summary: "",
|
|
4561
|
+
color: null,
|
|
4562
|
+
tags: [],
|
|
4563
|
+
hidden: false
|
|
4564
|
+
};
|
|
4565
|
+
groups.push(group);
|
|
4566
|
+
groupIds.add(id);
|
|
4567
|
+
return {
|
|
4568
|
+
kind: "group",
|
|
4569
|
+
group,
|
|
4570
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
4571
|
+
};
|
|
4572
|
+
}
|
|
4573
|
+
function startRelationSection(tokens, line, relations, relationIds) {
|
|
4574
|
+
if (tokens.length !== 2) {
|
|
4575
|
+
throw new WorldOrbitError("Invalid relation declaration", line, tokens[0]?.column ?? 1);
|
|
4576
|
+
}
|
|
4577
|
+
const id = normalizeIdentifier2(tokens[1].value);
|
|
4578
|
+
if (!id) {
|
|
4579
|
+
throw new WorldOrbitError("Relation id must not be empty", line, tokens[1].column);
|
|
4580
|
+
}
|
|
4581
|
+
if (relationIds.has(id)) {
|
|
4582
|
+
throw new WorldOrbitError(`Duplicate relation id "${id}"`, line, tokens[1].column);
|
|
4583
|
+
}
|
|
4584
|
+
const relation = {
|
|
4585
|
+
id,
|
|
4586
|
+
from: "",
|
|
4587
|
+
to: "",
|
|
4588
|
+
kind: "",
|
|
4589
|
+
label: null,
|
|
4590
|
+
summary: null,
|
|
4591
|
+
tags: [],
|
|
4592
|
+
color: null,
|
|
4593
|
+
hidden: false
|
|
4594
|
+
};
|
|
4595
|
+
relations.push(relation);
|
|
4596
|
+
relationIds.add(id);
|
|
4597
|
+
return {
|
|
4598
|
+
kind: "relation",
|
|
4599
|
+
relation,
|
|
4600
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
4601
|
+
};
|
|
4602
|
+
}
|
|
4603
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
4604
|
+
if (tokens.length !== 2) {
|
|
4605
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
4606
|
+
}
|
|
4607
|
+
const id = normalizeIdentifier2(tokens[1].value);
|
|
4608
|
+
if (!id) {
|
|
4609
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
4610
|
+
}
|
|
4611
|
+
if (eventIds.has(id)) {
|
|
4612
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
4613
|
+
}
|
|
4614
|
+
const event = {
|
|
4615
|
+
id,
|
|
4616
|
+
kind: "",
|
|
4617
|
+
label: humanizeIdentifier3(id),
|
|
4618
|
+
summary: null,
|
|
4619
|
+
targetObjectId: null,
|
|
4620
|
+
participantObjectIds: [],
|
|
4621
|
+
timing: null,
|
|
4622
|
+
visibility: null,
|
|
4623
|
+
tags: [],
|
|
4624
|
+
color: null,
|
|
4625
|
+
hidden: false,
|
|
4626
|
+
positions: []
|
|
4627
|
+
};
|
|
4628
|
+
const rawPoses = [];
|
|
4629
|
+
events.push(event);
|
|
4630
|
+
eventPoseNodes.set(id, rawPoses);
|
|
4631
|
+
eventIds.add(id);
|
|
4632
|
+
return {
|
|
4633
|
+
kind: "event",
|
|
4634
|
+
event,
|
|
4635
|
+
sourceSchemaVersion,
|
|
4636
|
+
diagnostics,
|
|
4637
|
+
seenFields: /* @__PURE__ */ new Set(),
|
|
4638
|
+
rawPoses,
|
|
4639
|
+
inPositions: false,
|
|
4640
|
+
positionsIndent: null,
|
|
4641
|
+
activePose: null,
|
|
4642
|
+
poseIndent: null,
|
|
4643
|
+
activePoseSeenFields: /* @__PURE__ */ new Set()
|
|
4644
|
+
};
|
|
4645
|
+
}
|
|
4646
|
+
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
3319
4647
|
if (tokens.length < 3) {
|
|
3320
4648
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
3321
4649
|
}
|
|
@@ -3326,12 +4654,11 @@ var WorldOrbit = (() => {
|
|
|
3326
4654
|
throw new WorldOrbitError(`Unknown object type "${objectTypeToken.value}"`, line, objectTypeToken.column);
|
|
3327
4655
|
}
|
|
3328
4656
|
const objectNode = {
|
|
3329
|
-
type: "object",
|
|
3330
4657
|
objectType,
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
blockFields: [],
|
|
4658
|
+
id: idToken.value,
|
|
4659
|
+
fields: parseInlineObjectFields(tokens.slice(3), line, objectType, sourceSchemaVersion, diagnostics),
|
|
3334
4660
|
infoEntries: [],
|
|
4661
|
+
typedBlockEntries: {},
|
|
3335
4662
|
location: {
|
|
3336
4663
|
line,
|
|
3337
4664
|
column: objectTypeToken.column
|
|
@@ -3341,8 +4668,12 @@ var WorldOrbit = (() => {
|
|
|
3341
4668
|
return {
|
|
3342
4669
|
kind: "object",
|
|
3343
4670
|
objectNode,
|
|
3344
|
-
|
|
3345
|
-
|
|
4671
|
+
sourceSchemaVersion,
|
|
4672
|
+
diagnostics,
|
|
4673
|
+
activeBlock: null,
|
|
4674
|
+
blockIndent: null,
|
|
4675
|
+
seenInfoKeys: /* @__PURE__ */ new Set(),
|
|
4676
|
+
seenTypedBlockKeys: {}
|
|
3346
4677
|
};
|
|
3347
4678
|
}
|
|
3348
4679
|
function handleSectionLine(section, indent, tokens, line) {
|
|
@@ -3362,6 +4693,15 @@ var WorldOrbit = (() => {
|
|
|
3362
4693
|
case "annotation":
|
|
3363
4694
|
applyAnnotationField(section, tokens, line);
|
|
3364
4695
|
return;
|
|
4696
|
+
case "group":
|
|
4697
|
+
applyGroupField(section, tokens, line);
|
|
4698
|
+
return;
|
|
4699
|
+
case "relation":
|
|
4700
|
+
applyRelationField(section, tokens, line);
|
|
4701
|
+
return;
|
|
4702
|
+
case "event":
|
|
4703
|
+
applyEventField(section, indent, tokens, line);
|
|
4704
|
+
return;
|
|
3365
4705
|
case "object":
|
|
3366
4706
|
applyObjectField(section, indent, tokens, line);
|
|
3367
4707
|
return;
|
|
@@ -3369,10 +4709,35 @@ var WorldOrbit = (() => {
|
|
|
3369
4709
|
}
|
|
3370
4710
|
function applySystemField(section, tokens, line) {
|
|
3371
4711
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
3372
|
-
|
|
3373
|
-
|
|
4712
|
+
const value = joinFieldValue(tokens, line);
|
|
4713
|
+
switch (key) {
|
|
4714
|
+
case "title":
|
|
4715
|
+
section.system.title = value;
|
|
4716
|
+
return;
|
|
4717
|
+
case "description":
|
|
4718
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
4719
|
+
line,
|
|
4720
|
+
column: tokens[0].column
|
|
4721
|
+
});
|
|
4722
|
+
section.system.description = value;
|
|
4723
|
+
return;
|
|
4724
|
+
case "epoch":
|
|
4725
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
4726
|
+
line,
|
|
4727
|
+
column: tokens[0].column
|
|
4728
|
+
});
|
|
4729
|
+
section.system.epoch = value;
|
|
4730
|
+
return;
|
|
4731
|
+
case "referenceplane":
|
|
4732
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "referencePlane", {
|
|
4733
|
+
line,
|
|
4734
|
+
column: tokens[0].column
|
|
4735
|
+
});
|
|
4736
|
+
section.system.referencePlane = value;
|
|
4737
|
+
return;
|
|
4738
|
+
default:
|
|
4739
|
+
throw new WorldOrbitError(`Unknown system atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3374
4740
|
}
|
|
3375
|
-
section.system.title = joinFieldValue(tokens, line);
|
|
3376
4741
|
}
|
|
3377
4742
|
function applyDefaultsField(section, tokens, line) {
|
|
3378
4743
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
@@ -3403,14 +4768,11 @@ var WorldOrbit = (() => {
|
|
|
3403
4768
|
section.metadataIndent = null;
|
|
3404
4769
|
}
|
|
3405
4770
|
if (section.inMetadata) {
|
|
3406
|
-
|
|
3407
|
-
|
|
4771
|
+
const entry = parseInfoLikeEntry(tokens, line, "Invalid atlas metadata entry");
|
|
4772
|
+
if (entry.key in section.system.atlasMetadata) {
|
|
4773
|
+
throw new WorldOrbitError(`Duplicate atlas metadata key "${entry.key}"`, line, tokens[0].column);
|
|
3408
4774
|
}
|
|
3409
|
-
|
|
3410
|
-
if (key in section.system.atlasMetadata) {
|
|
3411
|
-
throw new WorldOrbitError(`Duplicate atlas metadata key "${key}"`, line, tokens[0].column);
|
|
3412
|
-
}
|
|
3413
|
-
section.system.atlasMetadata[key] = joinFieldValue(tokens, line);
|
|
4775
|
+
section.system.atlasMetadata[entry.key] = entry.value;
|
|
3414
4776
|
return;
|
|
3415
4777
|
}
|
|
3416
4778
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "metadata") {
|
|
@@ -3466,7 +4828,14 @@ var WorldOrbit = (() => {
|
|
|
3466
4828
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
3467
4829
|
return;
|
|
3468
4830
|
case "layers":
|
|
3469
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
4831
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
4832
|
+
return;
|
|
4833
|
+
case "events":
|
|
4834
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
4835
|
+
line,
|
|
4836
|
+
column: tokens[0].column
|
|
4837
|
+
});
|
|
4838
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
3470
4839
|
return;
|
|
3471
4840
|
default:
|
|
3472
4841
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
@@ -3512,21 +4881,202 @@ var WorldOrbit = (() => {
|
|
|
3512
4881
|
throw new WorldOrbitError(`Unknown annotation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3513
4882
|
}
|
|
3514
4883
|
}
|
|
3515
|
-
function
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
4884
|
+
function applyGroupField(section, tokens, line) {
|
|
4885
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4886
|
+
switch (key) {
|
|
4887
|
+
case "label":
|
|
4888
|
+
section.group.label = joinFieldValue(tokens, line);
|
|
4889
|
+
return;
|
|
4890
|
+
case "summary":
|
|
4891
|
+
section.group.summary = joinFieldValue(tokens, line);
|
|
4892
|
+
return;
|
|
4893
|
+
case "color":
|
|
4894
|
+
section.group.color = joinFieldValue(tokens, line);
|
|
4895
|
+
return;
|
|
4896
|
+
case "tags":
|
|
4897
|
+
section.group.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4898
|
+
return;
|
|
4899
|
+
case "hidden":
|
|
4900
|
+
section.group.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4901
|
+
line,
|
|
4902
|
+
column: tokens[0].column
|
|
4903
|
+
});
|
|
4904
|
+
return;
|
|
4905
|
+
default:
|
|
4906
|
+
throw new WorldOrbitError(`Unknown group field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
function applyRelationField(section, tokens, line) {
|
|
4910
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4911
|
+
switch (key) {
|
|
4912
|
+
case "from":
|
|
4913
|
+
section.relation.from = joinFieldValue(tokens, line);
|
|
4914
|
+
return;
|
|
4915
|
+
case "to":
|
|
4916
|
+
section.relation.to = joinFieldValue(tokens, line);
|
|
4917
|
+
return;
|
|
4918
|
+
case "kind":
|
|
4919
|
+
section.relation.kind = joinFieldValue(tokens, line);
|
|
4920
|
+
return;
|
|
4921
|
+
case "label":
|
|
4922
|
+
section.relation.label = joinFieldValue(tokens, line);
|
|
4923
|
+
return;
|
|
4924
|
+
case "summary":
|
|
4925
|
+
section.relation.summary = joinFieldValue(tokens, line);
|
|
4926
|
+
return;
|
|
4927
|
+
case "tags":
|
|
4928
|
+
section.relation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4929
|
+
return;
|
|
4930
|
+
case "color":
|
|
4931
|
+
section.relation.color = joinFieldValue(tokens, line);
|
|
4932
|
+
return;
|
|
4933
|
+
case "hidden":
|
|
4934
|
+
section.relation.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4935
|
+
line,
|
|
4936
|
+
column: tokens[0].column
|
|
4937
|
+
});
|
|
4938
|
+
return;
|
|
4939
|
+
default:
|
|
4940
|
+
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4941
|
+
}
|
|
4942
|
+
}
|
|
4943
|
+
function applyEventField(section, indent, tokens, line) {
|
|
4944
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
4945
|
+
section.activePose = null;
|
|
4946
|
+
section.poseIndent = null;
|
|
4947
|
+
section.activePoseSeenFields.clear();
|
|
4948
|
+
}
|
|
4949
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
4950
|
+
section.inPositions = false;
|
|
4951
|
+
section.positionsIndent = null;
|
|
4952
|
+
}
|
|
4953
|
+
if (section.activePose) {
|
|
4954
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4955
|
+
return;
|
|
4956
|
+
}
|
|
4957
|
+
if (section.inPositions) {
|
|
4958
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
4959
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
4960
|
+
}
|
|
4961
|
+
const objectId = tokens[1].value;
|
|
4962
|
+
if (!objectId.trim()) {
|
|
4963
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
4964
|
+
}
|
|
4965
|
+
const rawPose = {
|
|
4966
|
+
objectId,
|
|
4967
|
+
fields: [],
|
|
4968
|
+
location: { line, column: tokens[0].column }
|
|
4969
|
+
};
|
|
4970
|
+
section.rawPoses.push(rawPose);
|
|
4971
|
+
section.activePose = rawPose;
|
|
4972
|
+
section.poseIndent = indent;
|
|
4973
|
+
section.activePoseSeenFields = /* @__PURE__ */ new Set();
|
|
3519
4974
|
return;
|
|
3520
4975
|
}
|
|
3521
|
-
if (
|
|
3522
|
-
section.
|
|
3523
|
-
|
|
4976
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
4977
|
+
if (section.seenFields.has("positions")) {
|
|
4978
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
4979
|
+
}
|
|
4980
|
+
section.seenFields.add("positions");
|
|
4981
|
+
section.inPositions = true;
|
|
4982
|
+
section.positionsIndent = indent;
|
|
4983
|
+
return;
|
|
4984
|
+
}
|
|
4985
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4986
|
+
switch (key) {
|
|
4987
|
+
case "kind":
|
|
4988
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
4989
|
+
return;
|
|
4990
|
+
case "label":
|
|
4991
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
4992
|
+
return;
|
|
4993
|
+
case "summary":
|
|
4994
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
4995
|
+
return;
|
|
4996
|
+
case "target":
|
|
4997
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
4998
|
+
return;
|
|
4999
|
+
case "participants":
|
|
5000
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
5001
|
+
return;
|
|
5002
|
+
case "timing":
|
|
5003
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
5004
|
+
return;
|
|
5005
|
+
case "visibility":
|
|
5006
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
5007
|
+
return;
|
|
5008
|
+
case "tags":
|
|
5009
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
5010
|
+
return;
|
|
5011
|
+
case "color":
|
|
5012
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
5013
|
+
return;
|
|
5014
|
+
case "hidden":
|
|
5015
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
5016
|
+
line,
|
|
5017
|
+
column: tokens[0].column
|
|
5018
|
+
});
|
|
5019
|
+
return;
|
|
5020
|
+
default:
|
|
5021
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
5025
|
+
if (tokens.length < 2) {
|
|
5026
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
5027
|
+
}
|
|
5028
|
+
const key = tokens[0].value;
|
|
5029
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
5030
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
5031
|
+
}
|
|
5032
|
+
if (seenFields.has(key)) {
|
|
5033
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
5034
|
+
}
|
|
5035
|
+
seenFields.add(key);
|
|
5036
|
+
return {
|
|
5037
|
+
type: "field",
|
|
5038
|
+
key,
|
|
5039
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
5040
|
+
location: { line, column: tokens[0].column }
|
|
5041
|
+
};
|
|
5042
|
+
}
|
|
5043
|
+
function applyObjectField(section, indent, tokens, line) {
|
|
5044
|
+
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
5045
|
+
section.activeBlock = null;
|
|
5046
|
+
section.blockIndent = null;
|
|
5047
|
+
}
|
|
5048
|
+
if (tokens.length === 1) {
|
|
5049
|
+
const blockName = tokens[0].value.toLowerCase();
|
|
5050
|
+
if (blockName === "info" || STRUCTURED_TYPED_BLOCKS.has(blockName)) {
|
|
5051
|
+
if (blockName !== "info") {
|
|
5052
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, blockName, { line, column: tokens[0].column });
|
|
5053
|
+
}
|
|
5054
|
+
section.activeBlock = blockName;
|
|
5055
|
+
section.blockIndent = indent;
|
|
5056
|
+
return;
|
|
5057
|
+
}
|
|
3524
5058
|
}
|
|
3525
|
-
if (section.
|
|
3526
|
-
|
|
5059
|
+
if (section.activeBlock) {
|
|
5060
|
+
const entry = parseInfoLikeEntry(tokens, line, `Invalid ${section.activeBlock} entry`);
|
|
5061
|
+
if (section.activeBlock === "info") {
|
|
5062
|
+
if (section.seenInfoKeys.has(entry.key)) {
|
|
5063
|
+
throw new WorldOrbitError(`Duplicate info key "${entry.key}"`, line, tokens[0].column);
|
|
5064
|
+
}
|
|
5065
|
+
section.seenInfoKeys.add(entry.key);
|
|
5066
|
+
section.objectNode.infoEntries.push(entry);
|
|
5067
|
+
return;
|
|
5068
|
+
}
|
|
5069
|
+
const typedBlock = section.activeBlock;
|
|
5070
|
+
const seenKeys = section.seenTypedBlockKeys[typedBlock] ?? (section.seenTypedBlockKeys[typedBlock] = /* @__PURE__ */ new Set());
|
|
5071
|
+
if (seenKeys.has(entry.key)) {
|
|
5072
|
+
throw new WorldOrbitError(`Duplicate ${typedBlock} key "${entry.key}"`, line, tokens[0].column);
|
|
5073
|
+
}
|
|
5074
|
+
seenKeys.add(entry.key);
|
|
5075
|
+
const entries = section.objectNode.typedBlockEntries[typedBlock] ?? (section.objectNode.typedBlockEntries[typedBlock] = []);
|
|
5076
|
+
entries.push(entry);
|
|
3527
5077
|
return;
|
|
3528
5078
|
}
|
|
3529
|
-
section.objectNode.
|
|
5079
|
+
section.objectNode.fields.push(parseObjectField(tokens, line, section.objectNode.objectType, section.sourceSchemaVersion, section.diagnostics));
|
|
3530
5080
|
}
|
|
3531
5081
|
function requireUniqueField(tokens, seenFields, line) {
|
|
3532
5082
|
if (tokens.length < 2) {
|
|
@@ -3546,50 +5096,46 @@ var WorldOrbit = (() => {
|
|
|
3546
5096
|
return tokens.slice(1).map((token) => token.value).join(" ").trim();
|
|
3547
5097
|
}
|
|
3548
5098
|
function parseObjectTypeTokens(tokens, line) {
|
|
3549
|
-
|
|
3550
|
-
throw new WorldOrbitError("Missing value for atlas field", line);
|
|
3551
|
-
}
|
|
3552
|
-
return tokens.map((token) => {
|
|
3553
|
-
const value = token.value;
|
|
3554
|
-
if (value !== "star" && value !== "planet" && value !== "moon" && value !== "belt" && value !== "asteroid" && value !== "comet" && value !== "ring" && value !== "structure" && value !== "phenomenon") {
|
|
3555
|
-
throw new WorldOrbitError(`Unknown viewpoint object type "${token.value}"`, line, token.column);
|
|
3556
|
-
}
|
|
3557
|
-
return value;
|
|
3558
|
-
});
|
|
5099
|
+
return parseTokenList(tokens, line, "objectTypes").filter((value) => value === "star" || value === "planet" || value === "moon" || value === "belt" || value === "asteroid" || value === "comet" || value === "ring" || value === "structure" || value === "phenomenon");
|
|
3559
5100
|
}
|
|
3560
|
-
function
|
|
3561
|
-
|
|
3562
|
-
|
|
5101
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
5102
|
+
const layers = {};
|
|
5103
|
+
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
5104
|
+
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
5105
|
+
const raw = token.replace(/^[-!]+/, "").toLowerCase();
|
|
5106
|
+
if (raw === "orbits") {
|
|
5107
|
+
layers["orbits-back"] = enabled;
|
|
5108
|
+
layers["orbits-front"] = enabled;
|
|
5109
|
+
continue;
|
|
5110
|
+
}
|
|
5111
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
5112
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
5113
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
5114
|
+
line,
|
|
5115
|
+
column: tokens[0]?.column ?? 1
|
|
5116
|
+
});
|
|
5117
|
+
}
|
|
5118
|
+
layers[raw] = enabled;
|
|
5119
|
+
}
|
|
3563
5120
|
}
|
|
3564
|
-
return
|
|
5121
|
+
return layers;
|
|
3565
5122
|
}
|
|
3566
|
-
function
|
|
5123
|
+
function parseTokenList(tokens, line, fieldName) {
|
|
3567
5124
|
if (tokens.length === 0) {
|
|
3568
|
-
throw new WorldOrbitError(
|
|
5125
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, 1);
|
|
3569
5126
|
}
|
|
3570
|
-
const
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
const rawLayer = token.value.replace(/^[-!]+/, "").toLowerCase();
|
|
3574
|
-
if (rawLayer === "orbits") {
|
|
3575
|
-
next["orbits-back"] = enabled;
|
|
3576
|
-
next["orbits-front"] = enabled;
|
|
3577
|
-
continue;
|
|
3578
|
-
}
|
|
3579
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
3580
|
-
next[rawLayer] = enabled;
|
|
3581
|
-
continue;
|
|
3582
|
-
}
|
|
3583
|
-
throw new WorldOrbitError(`Unknown layer token "${token.value}"`, line, token.column);
|
|
5127
|
+
const values = tokens.map((token) => token.value).filter(Boolean);
|
|
5128
|
+
if (values.length === 0) {
|
|
5129
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, tokens[0]?.column ?? 1);
|
|
3584
5130
|
}
|
|
3585
|
-
return
|
|
5131
|
+
return values;
|
|
3586
5132
|
}
|
|
3587
5133
|
function parseProjectionValue(value, line, column) {
|
|
3588
5134
|
const normalized = value.toLowerCase();
|
|
3589
|
-
if (normalized
|
|
3590
|
-
|
|
5135
|
+
if (normalized !== "topdown" && normalized !== "isometric") {
|
|
5136
|
+
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
3591
5137
|
}
|
|
3592
|
-
|
|
5138
|
+
return normalized;
|
|
3593
5139
|
}
|
|
3594
5140
|
function parsePresetValue(value, line, column) {
|
|
3595
5141
|
const normalized = value.toLowerCase();
|
|
@@ -3599,16 +5145,16 @@ var WorldOrbit = (() => {
|
|
|
3599
5145
|
throw new WorldOrbitError(`Unknown render preset "${value}"`, line, column);
|
|
3600
5146
|
}
|
|
3601
5147
|
function parsePositiveNumber2(value, line, column, field) {
|
|
3602
|
-
const parsed =
|
|
3603
|
-
if (
|
|
3604
|
-
throw new WorldOrbitError(`Field "${field}"
|
|
5148
|
+
const parsed = parseFiniteNumber2(value, line, column, field);
|
|
5149
|
+
if (parsed <= 0) {
|
|
5150
|
+
throw new WorldOrbitError(`Field "${field}" must be greater than zero`, line, column);
|
|
3605
5151
|
}
|
|
3606
5152
|
return parsed;
|
|
3607
5153
|
}
|
|
3608
5154
|
function parseFiniteNumber2(value, line, column, field) {
|
|
3609
5155
|
const parsed = Number(value);
|
|
3610
5156
|
if (!Number.isFinite(parsed)) {
|
|
3611
|
-
throw new WorldOrbitError(`
|
|
5157
|
+
throw new WorldOrbitError(`Invalid numeric value "${value}" for "${field}"`, line, column);
|
|
3612
5158
|
}
|
|
3613
5159
|
return parsed;
|
|
3614
5160
|
}
|
|
@@ -3620,28 +5166,43 @@ var WorldOrbit = (() => {
|
|
|
3620
5166
|
groupIds: []
|
|
3621
5167
|
};
|
|
3622
5168
|
}
|
|
3623
|
-
function
|
|
5169
|
+
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3624
5170
|
const fields = [];
|
|
3625
5171
|
let index = 0;
|
|
3626
5172
|
while (index < tokens.length) {
|
|
3627
5173
|
const keyToken = tokens[index];
|
|
3628
|
-
const
|
|
3629
|
-
if (!
|
|
5174
|
+
const spec = getDraftObjectFieldSpec(keyToken.value);
|
|
5175
|
+
if (!spec) {
|
|
3630
5176
|
throw new WorldOrbitError(`Unknown field "${keyToken.value}"`, line, keyToken.column);
|
|
3631
5177
|
}
|
|
5178
|
+
if (spec.version === "2.1") {
|
|
5179
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, keyToken.value, {
|
|
5180
|
+
line,
|
|
5181
|
+
column: keyToken.column
|
|
5182
|
+
});
|
|
5183
|
+
}
|
|
3632
5184
|
index++;
|
|
3633
5185
|
const valueTokens = [];
|
|
3634
|
-
if (
|
|
3635
|
-
while (index < tokens.length && !isKnownFieldKey(tokens[index].value)) {
|
|
3636
|
-
valueTokens.push(tokens[index]);
|
|
3637
|
-
index++;
|
|
3638
|
-
}
|
|
3639
|
-
} else {
|
|
5186
|
+
if (spec.inlineMode === "single") {
|
|
3640
5187
|
const nextToken = tokens[index];
|
|
3641
5188
|
if (nextToken) {
|
|
3642
5189
|
valueTokens.push(nextToken);
|
|
3643
5190
|
index++;
|
|
3644
5191
|
}
|
|
5192
|
+
} else if (spec.inlineMode === "pair") {
|
|
5193
|
+
for (let count = 0; count < 2; count++) {
|
|
5194
|
+
const nextToken = tokens[index];
|
|
5195
|
+
if (!nextToken) {
|
|
5196
|
+
break;
|
|
5197
|
+
}
|
|
5198
|
+
valueTokens.push(nextToken);
|
|
5199
|
+
index++;
|
|
5200
|
+
}
|
|
5201
|
+
} else {
|
|
5202
|
+
while (index < tokens.length && !DRAFT_OBJECT_FIELD_KEYS.has(tokens[index].value)) {
|
|
5203
|
+
valueTokens.push(tokens[index]);
|
|
5204
|
+
index++;
|
|
5205
|
+
}
|
|
3645
5206
|
}
|
|
3646
5207
|
if (valueTokens.length === 0) {
|
|
3647
5208
|
throw new WorldOrbitError(`Missing value for field "${keyToken.value}"`, line, keyToken.column);
|
|
@@ -3653,25 +5214,35 @@ var WorldOrbit = (() => {
|
|
|
3653
5214
|
location: { line, column: keyToken.column }
|
|
3654
5215
|
});
|
|
3655
5216
|
}
|
|
5217
|
+
validateDraftObjectFieldCompatibility(fields, objectType);
|
|
3656
5218
|
return fields;
|
|
3657
5219
|
}
|
|
3658
|
-
function
|
|
5220
|
+
function parseObjectField(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3659
5221
|
if (tokens.length < 2) {
|
|
3660
5222
|
throw new WorldOrbitError("Invalid field line", line, tokens[0]?.column ?? 1);
|
|
3661
5223
|
}
|
|
3662
|
-
|
|
5224
|
+
const spec = getDraftObjectFieldSpec(tokens[0].value);
|
|
5225
|
+
if (!spec) {
|
|
3663
5226
|
throw new WorldOrbitError(`Unknown field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3664
5227
|
}
|
|
3665
|
-
|
|
5228
|
+
if (spec.version === "2.1") {
|
|
5229
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, tokens[0].value, {
|
|
5230
|
+
line,
|
|
5231
|
+
column: tokens[0].column
|
|
5232
|
+
});
|
|
5233
|
+
}
|
|
5234
|
+
const field = {
|
|
3666
5235
|
type: "field",
|
|
3667
5236
|
key: tokens[0].value,
|
|
3668
5237
|
values: tokens.slice(1).map((token) => token.value),
|
|
3669
5238
|
location: { line, column: tokens[0].column }
|
|
3670
5239
|
};
|
|
5240
|
+
validateDraftObjectFieldCompatibility([field], objectType);
|
|
5241
|
+
return field;
|
|
3671
5242
|
}
|
|
3672
|
-
function
|
|
5243
|
+
function parseInfoLikeEntry(tokens, line, errorMessage) {
|
|
3673
5244
|
if (tokens.length < 2) {
|
|
3674
|
-
throw new WorldOrbitError(
|
|
5245
|
+
throw new WorldOrbitError(errorMessage, line, tokens[0]?.column ?? 1);
|
|
3675
5246
|
}
|
|
3676
5247
|
return {
|
|
3677
5248
|
type: "info-entry",
|
|
@@ -3680,23 +5251,374 @@ var WorldOrbit = (() => {
|
|
|
3680
5251
|
location: { line, column: tokens[0].column }
|
|
3681
5252
|
};
|
|
3682
5253
|
}
|
|
3683
|
-
function
|
|
3684
|
-
|
|
5254
|
+
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
5255
|
+
const fieldMap = collectDraftFields(node.fields);
|
|
5256
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
5257
|
+
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
5258
|
+
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
5259
|
+
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
5260
|
+
const referencePlane = parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0]);
|
|
5261
|
+
const tidalLock = fieldMap.has("tidalLock") ? parseAtlasBoolean(singleFieldValue2(fieldMap.get("tidalLock")[0]), "tidalLock", fieldMap.get("tidalLock")[0].location) : void 0;
|
|
5262
|
+
const resonance = fieldMap.has("resonance") ? parseResonanceField(fieldMap.get("resonance")[0]) : void 0;
|
|
5263
|
+
const renderHints = extractRenderHints(fieldMap);
|
|
5264
|
+
const deriveRules = fieldMap.get("derive")?.map((field) => parseDeriveField(field));
|
|
5265
|
+
const validationRules = fieldMap.get("validate")?.map((field) => ({
|
|
5266
|
+
rule: singleFieldValue2(field)
|
|
5267
|
+
}));
|
|
5268
|
+
const lockedFields = fieldMap.has("locked") ? [...new Set(fieldMap.get("locked").flatMap((field) => field.values))] : void 0;
|
|
5269
|
+
const tolerances = fieldMap.get("tolerance")?.map((field) => parseToleranceField(field));
|
|
5270
|
+
const typedBlocks = normalizeTypedBlocks(node.typedBlockEntries);
|
|
5271
|
+
const info2 = normalizeInfoEntries(node.infoEntries, "info");
|
|
5272
|
+
const object = {
|
|
5273
|
+
type: node.objectType,
|
|
5274
|
+
id: node.id,
|
|
5275
|
+
properties,
|
|
5276
|
+
placement,
|
|
5277
|
+
info: info2
|
|
5278
|
+
};
|
|
5279
|
+
if (groups.length > 0)
|
|
5280
|
+
object.groups = groups;
|
|
5281
|
+
if (epoch)
|
|
5282
|
+
object.epoch = epoch;
|
|
5283
|
+
if (referencePlane)
|
|
5284
|
+
object.referencePlane = referencePlane;
|
|
5285
|
+
if (tidalLock !== void 0)
|
|
5286
|
+
object.tidalLock = tidalLock;
|
|
5287
|
+
if (resonance)
|
|
5288
|
+
object.resonance = resonance;
|
|
5289
|
+
if (renderHints)
|
|
5290
|
+
object.renderHints = renderHints;
|
|
5291
|
+
if (deriveRules?.length)
|
|
5292
|
+
object.deriveRules = deriveRules;
|
|
5293
|
+
if (validationRules?.length)
|
|
5294
|
+
object.validationRules = validationRules;
|
|
5295
|
+
if (lockedFields?.length)
|
|
5296
|
+
object.lockedFields = lockedFields;
|
|
5297
|
+
if (tolerances?.length)
|
|
5298
|
+
object.tolerances = tolerances;
|
|
5299
|
+
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
5300
|
+
object.typedBlocks = typedBlocks;
|
|
5301
|
+
if (sourceSchemaVersion !== "2.1") {
|
|
5302
|
+
if (object.groups || object.epoch || object.referencePlane || object.tidalLock !== void 0 || object.resonance || object.renderHints || object.deriveRules?.length || object.validationRules?.length || object.lockedFields?.length || object.tolerances?.length || object.typedBlocks) {
|
|
5303
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
return object;
|
|
3685
5307
|
}
|
|
3686
|
-
function
|
|
3687
|
-
return
|
|
5308
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
5309
|
+
return {
|
|
5310
|
+
...event,
|
|
5311
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
5312
|
+
tags: [...new Set(event.tags)],
|
|
5313
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
|
|
5314
|
+
};
|
|
5315
|
+
}
|
|
5316
|
+
function normalizeDraftEventPose(rawPose) {
|
|
5317
|
+
const fieldMap = collectDraftFields(rawPose.fields);
|
|
5318
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
5319
|
+
return {
|
|
5320
|
+
objectId: rawPose.objectId,
|
|
5321
|
+
placement,
|
|
5322
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
5323
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer")
|
|
5324
|
+
};
|
|
5325
|
+
}
|
|
5326
|
+
function collectDraftFields(fields) {
|
|
5327
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
5328
|
+
for (const field of fields) {
|
|
5329
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
5330
|
+
if (!spec) {
|
|
5331
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
5332
|
+
}
|
|
5333
|
+
if (!spec.allowRepeat && grouped.has(field.key)) {
|
|
5334
|
+
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
5335
|
+
}
|
|
5336
|
+
const existing = grouped.get(field.key) ?? [];
|
|
5337
|
+
existing.push(field);
|
|
5338
|
+
grouped.set(field.key, existing);
|
|
5339
|
+
}
|
|
5340
|
+
return grouped;
|
|
5341
|
+
}
|
|
5342
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
5343
|
+
const orbitField = fieldMap.get("orbit")?.[0];
|
|
5344
|
+
const atField = fieldMap.get("at")?.[0];
|
|
5345
|
+
const surfaceField = fieldMap.get("surface")?.[0];
|
|
5346
|
+
const freeField = fieldMap.get("free")?.[0];
|
|
5347
|
+
const count = [orbitField, atField, surfaceField, freeField].filter(Boolean).length;
|
|
5348
|
+
if (count > 1) {
|
|
5349
|
+
const conflictingField = orbitField ?? atField ?? surfaceField ?? freeField;
|
|
5350
|
+
throw WorldOrbitError.fromLocation("Object has multiple placement modes", conflictingField?.location);
|
|
5351
|
+
}
|
|
5352
|
+
if (orbitField) {
|
|
5353
|
+
return {
|
|
5354
|
+
mode: "orbit",
|
|
5355
|
+
target: singleFieldValue2(orbitField),
|
|
5356
|
+
distance: parseOptionalUnitField(fieldMap.get("distance")?.[0], "distance"),
|
|
5357
|
+
semiMajor: parseOptionalUnitField(fieldMap.get("semiMajor")?.[0], "semiMajor"),
|
|
5358
|
+
eccentricity: parseOptionalNumberField(fieldMap.get("eccentricity")?.[0], "eccentricity"),
|
|
5359
|
+
period: parseOptionalUnitField(fieldMap.get("period")?.[0], "period"),
|
|
5360
|
+
angle: parseOptionalUnitField(fieldMap.get("angle")?.[0], "angle"),
|
|
5361
|
+
inclination: parseOptionalUnitField(fieldMap.get("inclination")?.[0], "inclination"),
|
|
5362
|
+
phase: parseOptionalUnitField(fieldMap.get("phase")?.[0], "phase")
|
|
5363
|
+
};
|
|
5364
|
+
}
|
|
5365
|
+
if (atField) {
|
|
5366
|
+
const target = singleFieldValue2(atField);
|
|
5367
|
+
return {
|
|
5368
|
+
mode: "at",
|
|
5369
|
+
target,
|
|
5370
|
+
reference: parseAtlasAtReference(target, atField.location)
|
|
5371
|
+
};
|
|
5372
|
+
}
|
|
5373
|
+
if (surfaceField) {
|
|
5374
|
+
return {
|
|
5375
|
+
mode: "surface",
|
|
5376
|
+
target: singleFieldValue2(surfaceField)
|
|
5377
|
+
};
|
|
5378
|
+
}
|
|
5379
|
+
if (freeField) {
|
|
5380
|
+
const raw = singleFieldValue2(freeField);
|
|
5381
|
+
const distance = tryParseAtlasUnitValue(raw);
|
|
5382
|
+
return {
|
|
5383
|
+
mode: "free",
|
|
5384
|
+
distance: distance ?? void 0,
|
|
5385
|
+
descriptor: distance ? void 0 : raw
|
|
5386
|
+
};
|
|
5387
|
+
}
|
|
5388
|
+
return null;
|
|
5389
|
+
}
|
|
5390
|
+
function normalizeDraftProperties(objectType, fieldMap) {
|
|
5391
|
+
const properties = {};
|
|
5392
|
+
for (const [key, fields] of fieldMap.entries()) {
|
|
5393
|
+
const field = fields[0];
|
|
5394
|
+
const spec = getDraftObjectFieldSpec(key);
|
|
5395
|
+
if (!field || !spec?.legacySchema || spec.legacySchema.placement) {
|
|
5396
|
+
continue;
|
|
5397
|
+
}
|
|
5398
|
+
ensureAtlasFieldSupported(key, objectType, field.location);
|
|
5399
|
+
properties[key] = normalizeLegacyScalarValue(key, field.values, field.location);
|
|
5400
|
+
}
|
|
5401
|
+
return properties;
|
|
5402
|
+
}
|
|
5403
|
+
function normalizeInfoEntries(entries, label) {
|
|
5404
|
+
const normalized = {};
|
|
5405
|
+
for (const entry of entries) {
|
|
5406
|
+
if (entry.key in normalized) {
|
|
5407
|
+
throw WorldOrbitError.fromLocation(`Duplicate ${label} key "${entry.key}"`, entry.location);
|
|
5408
|
+
}
|
|
5409
|
+
normalized[entry.key] = entry.value;
|
|
5410
|
+
}
|
|
5411
|
+
return normalized;
|
|
5412
|
+
}
|
|
5413
|
+
function normalizeTypedBlocks(typedBlockEntries) {
|
|
5414
|
+
const typedBlocks = {};
|
|
5415
|
+
for (const blockName of Object.keys(typedBlockEntries)) {
|
|
5416
|
+
const entries = typedBlockEntries[blockName];
|
|
5417
|
+
if (entries?.length) {
|
|
5418
|
+
typedBlocks[blockName] = normalizeInfoEntries(entries, blockName);
|
|
5419
|
+
}
|
|
5420
|
+
}
|
|
5421
|
+
return typedBlocks;
|
|
5422
|
+
}
|
|
5423
|
+
function extractRenderHints(fieldMap) {
|
|
5424
|
+
const renderHints = {};
|
|
5425
|
+
const renderLabelField = fieldMap.get("renderLabel")?.[0];
|
|
5426
|
+
const renderOrbitField = fieldMap.get("renderOrbit")?.[0];
|
|
5427
|
+
const renderPriorityField = fieldMap.get("renderPriority")?.[0];
|
|
5428
|
+
if (renderLabelField) {
|
|
5429
|
+
renderHints.renderLabel = parseAtlasBoolean(singleFieldValue2(renderLabelField), "renderLabel", renderLabelField.location);
|
|
5430
|
+
}
|
|
5431
|
+
if (renderOrbitField) {
|
|
5432
|
+
renderHints.renderOrbit = parseAtlasBoolean(singleFieldValue2(renderOrbitField), "renderOrbit", renderOrbitField.location);
|
|
5433
|
+
}
|
|
5434
|
+
if (renderPriorityField) {
|
|
5435
|
+
renderHints.renderPriority = parseAtlasNumber(singleFieldValue2(renderPriorityField), "renderPriority", renderPriorityField.location);
|
|
5436
|
+
}
|
|
5437
|
+
return Object.keys(renderHints).length > 0 ? renderHints : void 0;
|
|
5438
|
+
}
|
|
5439
|
+
function parseResonanceField(field) {
|
|
5440
|
+
if (field.values.length !== 2) {
|
|
5441
|
+
throw WorldOrbitError.fromLocation('Field "resonance" expects "<targetObjectId> <ratio>"', field.location);
|
|
5442
|
+
}
|
|
5443
|
+
const ratio = field.values[1];
|
|
5444
|
+
if (!/^\d+:\d+$/.test(ratio)) {
|
|
5445
|
+
throw WorldOrbitError.fromLocation(`Invalid resonance ratio "${ratio}"`, field.location);
|
|
5446
|
+
}
|
|
5447
|
+
return {
|
|
5448
|
+
targetObjectId: field.values[0],
|
|
5449
|
+
ratio
|
|
5450
|
+
};
|
|
5451
|
+
}
|
|
5452
|
+
function parseDeriveField(field) {
|
|
5453
|
+
if (field.values.length !== 2) {
|
|
5454
|
+
throw WorldOrbitError.fromLocation('Field "derive" expects "<field> <strategy>"', field.location);
|
|
5455
|
+
}
|
|
5456
|
+
return {
|
|
5457
|
+
field: field.values[0],
|
|
5458
|
+
strategy: field.values[1]
|
|
5459
|
+
};
|
|
5460
|
+
}
|
|
5461
|
+
function parseToleranceField(field) {
|
|
5462
|
+
if (field.values.length !== 2) {
|
|
5463
|
+
throw WorldOrbitError.fromLocation('Field "tolerance" expects "<field> <value>"', field.location);
|
|
5464
|
+
}
|
|
5465
|
+
const rawValue = field.values[1];
|
|
5466
|
+
const unitValue = tryParseAtlasUnitValue(rawValue);
|
|
5467
|
+
const numericValue = Number(rawValue);
|
|
5468
|
+
return {
|
|
5469
|
+
field: field.values[0],
|
|
5470
|
+
value: unitValue ?? (Number.isFinite(numericValue) ? numericValue : rawValue)
|
|
5471
|
+
};
|
|
5472
|
+
}
|
|
5473
|
+
function parseOptionalTokenList(field) {
|
|
5474
|
+
return field ? [...new Set(field.values)] : [];
|
|
5475
|
+
}
|
|
5476
|
+
function parseOptionalJoinedValue(field) {
|
|
5477
|
+
if (!field) {
|
|
5478
|
+
return null;
|
|
5479
|
+
}
|
|
5480
|
+
return field.values.join(" ").trim() || null;
|
|
5481
|
+
}
|
|
5482
|
+
function parseOptionalUnitField(field, key) {
|
|
5483
|
+
return field ? parseAtlasUnitValue(singleFieldValue2(field), field.location, key) : void 0;
|
|
5484
|
+
}
|
|
5485
|
+
function parseOptionalNumberField(field, key) {
|
|
5486
|
+
return field ? parseAtlasNumber(singleFieldValue2(field), key, field.location) : void 0;
|
|
5487
|
+
}
|
|
5488
|
+
function singleFieldValue2(field) {
|
|
5489
|
+
return singleAtlasValue(field.values, field.key, field.location);
|
|
5490
|
+
}
|
|
5491
|
+
function getDraftObjectFieldSpec(key) {
|
|
5492
|
+
return DRAFT_OBJECT_FIELD_SPECS.get(key);
|
|
5493
|
+
}
|
|
5494
|
+
function validateDraftObjectFieldCompatibility(fields, objectType) {
|
|
5495
|
+
for (const field of fields) {
|
|
5496
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
5497
|
+
if (!spec) {
|
|
5498
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
5499
|
+
}
|
|
5500
|
+
if (spec.legacySchema) {
|
|
5501
|
+
ensureAtlasFieldSupported(field.key, objectType, field.location);
|
|
5502
|
+
continue;
|
|
5503
|
+
}
|
|
5504
|
+
if ((field.key === "renderLabel" || field.key === "renderOrbit" || field.key === "tidalLock") && field.values.length !== 1) {
|
|
5505
|
+
throw WorldOrbitError.fromLocation(`Field "${field.key}" expects exactly one value`, field.location);
|
|
5506
|
+
}
|
|
5507
|
+
}
|
|
5508
|
+
}
|
|
5509
|
+
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
5510
|
+
if (sourceSchemaVersion === "2.1") {
|
|
5511
|
+
return;
|
|
5512
|
+
}
|
|
5513
|
+
diagnostics.push({
|
|
5514
|
+
code: "parse.schema21.featureCompatibility",
|
|
5515
|
+
severity: "warning",
|
|
5516
|
+
source: "parse",
|
|
5517
|
+
message: `Feature "${featureName}" requires schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
5518
|
+
line: location.line,
|
|
5519
|
+
column: location.column
|
|
5520
|
+
});
|
|
5521
|
+
}
|
|
5522
|
+
function preprocessAtlasSource(source) {
|
|
5523
|
+
const chars = [...source];
|
|
5524
|
+
const comments = [];
|
|
5525
|
+
let inString = false;
|
|
5526
|
+
let inBlockComment = false;
|
|
5527
|
+
let blockCommentStart = null;
|
|
5528
|
+
let line = 1;
|
|
5529
|
+
let column = 1;
|
|
5530
|
+
for (let index = 0; index < chars.length; index++) {
|
|
5531
|
+
const ch = chars[index];
|
|
5532
|
+
const next = chars[index + 1];
|
|
5533
|
+
if (inBlockComment) {
|
|
5534
|
+
if (ch === "*" && next === "/") {
|
|
5535
|
+
chars[index] = " ";
|
|
5536
|
+
chars[index + 1] = " ";
|
|
5537
|
+
inBlockComment = false;
|
|
5538
|
+
blockCommentStart = null;
|
|
5539
|
+
index++;
|
|
5540
|
+
column += 2;
|
|
5541
|
+
continue;
|
|
5542
|
+
}
|
|
5543
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
5544
|
+
chars[index] = " ";
|
|
5545
|
+
}
|
|
5546
|
+
if (ch === "\n") {
|
|
5547
|
+
line++;
|
|
5548
|
+
column = 1;
|
|
5549
|
+
} else {
|
|
5550
|
+
column++;
|
|
5551
|
+
}
|
|
5552
|
+
continue;
|
|
5553
|
+
}
|
|
5554
|
+
if (!inString && ch === "/" && next === "*") {
|
|
5555
|
+
comments.push({ kind: "block", line, column });
|
|
5556
|
+
chars[index] = " ";
|
|
5557
|
+
chars[index + 1] = " ";
|
|
5558
|
+
inBlockComment = true;
|
|
5559
|
+
blockCommentStart = { line, column };
|
|
5560
|
+
index++;
|
|
5561
|
+
column += 2;
|
|
5562
|
+
continue;
|
|
5563
|
+
}
|
|
5564
|
+
if (!inString && ch === "#" && !isHexColorLiteral(chars, index)) {
|
|
5565
|
+
comments.push({ kind: "line", line, column });
|
|
5566
|
+
chars[index] = " ";
|
|
5567
|
+
let inner = index + 1;
|
|
5568
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
5569
|
+
chars[inner] = " ";
|
|
5570
|
+
inner++;
|
|
5571
|
+
}
|
|
5572
|
+
column += inner - index;
|
|
5573
|
+
index = inner - 1;
|
|
5574
|
+
continue;
|
|
5575
|
+
}
|
|
5576
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
5577
|
+
inString = !inString;
|
|
5578
|
+
}
|
|
5579
|
+
if (ch === "\n") {
|
|
5580
|
+
line++;
|
|
5581
|
+
column = 1;
|
|
5582
|
+
} else {
|
|
5583
|
+
column++;
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
if (inBlockComment) {
|
|
5587
|
+
throw WorldOrbitError.fromLocation("Unclosed block comment", blockCommentStart ?? void 0);
|
|
5588
|
+
}
|
|
5589
|
+
return {
|
|
5590
|
+
source: chars.join(""),
|
|
5591
|
+
comments
|
|
5592
|
+
};
|
|
5593
|
+
}
|
|
5594
|
+
function isHexColorLiteral(chars, start) {
|
|
5595
|
+
let index = start + 1;
|
|
5596
|
+
let length = 0;
|
|
5597
|
+
while (index < chars.length && /[0-9a-f]/i.test(chars[index] ?? "")) {
|
|
5598
|
+
index++;
|
|
5599
|
+
length++;
|
|
5600
|
+
}
|
|
5601
|
+
if (![3, 4, 6, 8].includes(length)) {
|
|
5602
|
+
return false;
|
|
5603
|
+
}
|
|
5604
|
+
const next = chars[index];
|
|
5605
|
+
return next === void 0 || next === " " || next === " " || next === "\r" || next === "\n";
|
|
3688
5606
|
}
|
|
3689
5607
|
|
|
3690
5608
|
// packages/core/dist/atlas-edit.js
|
|
3691
|
-
function createEmptyAtlasDocument(systemId = "WorldOrbit") {
|
|
5609
|
+
function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.0") {
|
|
3692
5610
|
return {
|
|
3693
5611
|
format: "worldorbit",
|
|
3694
|
-
version
|
|
5612
|
+
version,
|
|
5613
|
+
schemaVersion: version,
|
|
3695
5614
|
sourceVersion: "1.0",
|
|
3696
5615
|
system: {
|
|
3697
5616
|
type: "system",
|
|
3698
5617
|
id: systemId,
|
|
3699
5618
|
title: systemId,
|
|
5619
|
+
description: null,
|
|
5620
|
+
epoch: null,
|
|
5621
|
+
referencePlane: null,
|
|
3700
5622
|
defaults: {
|
|
3701
5623
|
view: "topdown",
|
|
3702
5624
|
scale: null,
|
|
@@ -3708,6 +5630,9 @@ var WorldOrbit = (() => {
|
|
|
3708
5630
|
viewpoints: [],
|
|
3709
5631
|
annotations: []
|
|
3710
5632
|
},
|
|
5633
|
+
groups: [],
|
|
5634
|
+
relations: [],
|
|
5635
|
+
events: [],
|
|
3711
5636
|
objects: [],
|
|
3712
5637
|
diagnostics: []
|
|
3713
5638
|
};
|
|
@@ -3721,14 +5646,26 @@ var WorldOrbit = (() => {
|
|
|
3721
5646
|
for (const key of Object.keys(document.system.atlasMetadata).sort()) {
|
|
3722
5647
|
paths.push({ kind: "metadata", key });
|
|
3723
5648
|
}
|
|
3724
|
-
for (const viewpoint of [...document.system.viewpoints].sort(
|
|
5649
|
+
for (const viewpoint of [...document.system.viewpoints].sort(compareIdLike2)) {
|
|
3725
5650
|
paths.push({ kind: "viewpoint", id: viewpoint.id });
|
|
3726
5651
|
}
|
|
3727
|
-
for (const annotation of [...document.system.annotations].sort(
|
|
5652
|
+
for (const annotation of [...document.system.annotations].sort(compareIdLike2)) {
|
|
3728
5653
|
paths.push({ kind: "annotation", id: annotation.id });
|
|
3729
5654
|
}
|
|
3730
5655
|
}
|
|
3731
|
-
for (const
|
|
5656
|
+
for (const group of [...document.groups].sort(compareIdLike2)) {
|
|
5657
|
+
paths.push({ kind: "group", id: group.id });
|
|
5658
|
+
}
|
|
5659
|
+
for (const relation of [...document.relations].sort(compareIdLike2)) {
|
|
5660
|
+
paths.push({ kind: "relation", id: relation.id });
|
|
5661
|
+
}
|
|
5662
|
+
for (const event of [...document.events].sort(compareIdLike2)) {
|
|
5663
|
+
paths.push({ kind: "event", id: event.id });
|
|
5664
|
+
for (const pose of [...event.positions].sort(comparePoseObjectId2)) {
|
|
5665
|
+
paths.push({ kind: "event-pose", id: event.id, key: pose.objectId });
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
for (const object of [...document.objects].sort(compareIdLike2)) {
|
|
3732
5669
|
paths.push({ kind: "object", id: object.id });
|
|
3733
5670
|
}
|
|
3734
5671
|
return paths;
|
|
@@ -3741,12 +5678,20 @@ var WorldOrbit = (() => {
|
|
|
3741
5678
|
return document.system?.defaults ?? null;
|
|
3742
5679
|
case "metadata":
|
|
3743
5680
|
return path.key ? document.system?.atlasMetadata[path.key] ?? null : null;
|
|
5681
|
+
case "group":
|
|
5682
|
+
return path.id ? findGroup(document, path.id) : null;
|
|
5683
|
+
case "event":
|
|
5684
|
+
return path.id ? findEvent(document, path.id) : null;
|
|
5685
|
+
case "event-pose":
|
|
5686
|
+
return path.id && path.key ? findEventPose(document, path.id, path.key) : null;
|
|
3744
5687
|
case "object":
|
|
3745
5688
|
return path.id ? findObject(document, path.id) : null;
|
|
3746
5689
|
case "viewpoint":
|
|
3747
5690
|
return path.id ? findViewpoint(document.system, path.id) : null;
|
|
3748
5691
|
case "annotation":
|
|
3749
5692
|
return path.id ? findAnnotation(document.system, path.id) : null;
|
|
5693
|
+
case "relation":
|
|
5694
|
+
return path.id ? findRelation(document, path.id) : null;
|
|
3750
5695
|
}
|
|
3751
5696
|
}
|
|
3752
5697
|
function upsertAtlasDocumentNode(document, path, value) {
|
|
@@ -3772,6 +5717,24 @@ var WorldOrbit = (() => {
|
|
|
3772
5717
|
system.atlasMetadata[path.key] = String(value);
|
|
3773
5718
|
}
|
|
3774
5719
|
return next;
|
|
5720
|
+
case "group":
|
|
5721
|
+
if (!path.id) {
|
|
5722
|
+
throw new Error('Group updates require an "id" value.');
|
|
5723
|
+
}
|
|
5724
|
+
upsertById(next.groups, value);
|
|
5725
|
+
return next;
|
|
5726
|
+
case "event":
|
|
5727
|
+
if (!path.id) {
|
|
5728
|
+
throw new Error('Event updates require an "id" value.');
|
|
5729
|
+
}
|
|
5730
|
+
upsertById(next.events, value);
|
|
5731
|
+
return next;
|
|
5732
|
+
case "event-pose":
|
|
5733
|
+
if (!path.id || !path.key) {
|
|
5734
|
+
throw new Error('Event pose updates require an event "id" and pose "key" value.');
|
|
5735
|
+
}
|
|
5736
|
+
upsertEventPose(next.events, path.id, value);
|
|
5737
|
+
return next;
|
|
3775
5738
|
case "object":
|
|
3776
5739
|
if (!path.id) {
|
|
3777
5740
|
throw new Error('Object updates require an "id" value.');
|
|
@@ -3790,6 +5753,12 @@ var WorldOrbit = (() => {
|
|
|
3790
5753
|
}
|
|
3791
5754
|
upsertById(system.annotations, value);
|
|
3792
5755
|
return next;
|
|
5756
|
+
case "relation":
|
|
5757
|
+
if (!path.id) {
|
|
5758
|
+
throw new Error('Relation updates require an "id" value.');
|
|
5759
|
+
}
|
|
5760
|
+
upsertById(next.relations, value);
|
|
5761
|
+
return next;
|
|
3793
5762
|
}
|
|
3794
5763
|
}
|
|
3795
5764
|
function updateAtlasDocumentNode(document, path, updater) {
|
|
@@ -3809,6 +5778,24 @@ var WorldOrbit = (() => {
|
|
|
3809
5778
|
next.objects = next.objects.filter((object) => object.id !== path.id);
|
|
3810
5779
|
}
|
|
3811
5780
|
return next;
|
|
5781
|
+
case "group":
|
|
5782
|
+
if (path.id) {
|
|
5783
|
+
next.groups = next.groups.filter((group) => group.id !== path.id);
|
|
5784
|
+
}
|
|
5785
|
+
return next;
|
|
5786
|
+
case "event":
|
|
5787
|
+
if (path.id) {
|
|
5788
|
+
next.events = next.events.filter((event) => event.id !== path.id);
|
|
5789
|
+
}
|
|
5790
|
+
return next;
|
|
5791
|
+
case "event-pose":
|
|
5792
|
+
if (path.id && path.key) {
|
|
5793
|
+
const event = findEvent(next, path.id);
|
|
5794
|
+
if (event) {
|
|
5795
|
+
event.positions = event.positions.filter((pose) => pose.objectId !== path.key);
|
|
5796
|
+
}
|
|
5797
|
+
}
|
|
5798
|
+
return next;
|
|
3812
5799
|
case "viewpoint":
|
|
3813
5800
|
if (path.id) {
|
|
3814
5801
|
system.viewpoints = system.viewpoints.filter((viewpoint) => viewpoint.id !== path.id);
|
|
@@ -3819,6 +5806,11 @@ var WorldOrbit = (() => {
|
|
|
3819
5806
|
system.annotations = system.annotations.filter((annotation) => annotation.id !== path.id);
|
|
3820
5807
|
}
|
|
3821
5808
|
return next;
|
|
5809
|
+
case "relation":
|
|
5810
|
+
if (path.id) {
|
|
5811
|
+
next.relations = next.relations.filter((relation) => relation.id !== path.id);
|
|
5812
|
+
}
|
|
5813
|
+
return next;
|
|
3822
5814
|
default:
|
|
3823
5815
|
return next;
|
|
3824
5816
|
}
|
|
@@ -3836,6 +5828,15 @@ var WorldOrbit = (() => {
|
|
|
3836
5828
|
id: diagnostic.objectId
|
|
3837
5829
|
};
|
|
3838
5830
|
}
|
|
5831
|
+
if (diagnostic.field?.startsWith("group.")) {
|
|
5832
|
+
const parts = diagnostic.field.split(".");
|
|
5833
|
+
if (parts[1] && findGroup(document, parts[1])) {
|
|
5834
|
+
return {
|
|
5835
|
+
kind: "group",
|
|
5836
|
+
id: parts[1]
|
|
5837
|
+
};
|
|
5838
|
+
}
|
|
5839
|
+
}
|
|
3839
5840
|
if (diagnostic.field?.startsWith("viewpoint.")) {
|
|
3840
5841
|
const parts = diagnostic.field.split(".");
|
|
3841
5842
|
if (parts[1] && findViewpoint(document.system, parts[1])) {
|
|
@@ -3854,6 +5855,31 @@ var WorldOrbit = (() => {
|
|
|
3854
5855
|
};
|
|
3855
5856
|
}
|
|
3856
5857
|
}
|
|
5858
|
+
if (diagnostic.field?.startsWith("relation.")) {
|
|
5859
|
+
const parts = diagnostic.field.split(".");
|
|
5860
|
+
if (parts[1] && findRelation(document, parts[1])) {
|
|
5861
|
+
return {
|
|
5862
|
+
kind: "relation",
|
|
5863
|
+
id: parts[1]
|
|
5864
|
+
};
|
|
5865
|
+
}
|
|
5866
|
+
}
|
|
5867
|
+
if (diagnostic.field?.startsWith("event.")) {
|
|
5868
|
+
const parts = diagnostic.field.split(".");
|
|
5869
|
+
if (parts[1] && findEvent(document, parts[1])) {
|
|
5870
|
+
if (parts[2] === "pose" && parts[3] && findEventPose(document, parts[1], parts[3])) {
|
|
5871
|
+
return {
|
|
5872
|
+
kind: "event-pose",
|
|
5873
|
+
id: parts[1],
|
|
5874
|
+
key: parts[3]
|
|
5875
|
+
};
|
|
5876
|
+
}
|
|
5877
|
+
return {
|
|
5878
|
+
kind: "event",
|
|
5879
|
+
id: parts[1]
|
|
5880
|
+
};
|
|
5881
|
+
}
|
|
5882
|
+
}
|
|
3857
5883
|
if (diagnostic.field && diagnostic.field in ensureSystem(document).atlasMetadata) {
|
|
3858
5884
|
return {
|
|
3859
5885
|
kind: "metadata",
|
|
@@ -3863,9 +5889,11 @@ var WorldOrbit = (() => {
|
|
|
3863
5889
|
return null;
|
|
3864
5890
|
}
|
|
3865
5891
|
function validateAtlasDocumentWithDiagnostics(document) {
|
|
3866
|
-
const
|
|
3867
|
-
|
|
3868
|
-
|
|
5892
|
+
const diagnostics = [
|
|
5893
|
+
...document.diagnostics,
|
|
5894
|
+
...collectAtlasDiagnostics(document, document.version)
|
|
5895
|
+
];
|
|
5896
|
+
return resolveAtlasDiagnostics(document, diagnostics);
|
|
3869
5897
|
}
|
|
3870
5898
|
function ensureSystem(document) {
|
|
3871
5899
|
if (document.system) {
|
|
@@ -3877,6 +5905,18 @@ var WorldOrbit = (() => {
|
|
|
3877
5905
|
function findObject(document, objectId) {
|
|
3878
5906
|
return document.objects.find((object) => object.id === objectId) ?? null;
|
|
3879
5907
|
}
|
|
5908
|
+
function findGroup(document, groupId) {
|
|
5909
|
+
return document.groups.find((group) => group.id === groupId) ?? null;
|
|
5910
|
+
}
|
|
5911
|
+
function findRelation(document, relationId) {
|
|
5912
|
+
return document.relations.find((relation) => relation.id === relationId) ?? null;
|
|
5913
|
+
}
|
|
5914
|
+
function findEvent(document, eventId) {
|
|
5915
|
+
return document.events.find((event) => event.id === eventId) ?? null;
|
|
5916
|
+
}
|
|
5917
|
+
function findEventPose(document, eventId, objectId) {
|
|
5918
|
+
return findEvent(document, eventId)?.positions.find((pose) => pose.objectId === objectId) ?? null;
|
|
5919
|
+
}
|
|
3880
5920
|
function findViewpoint(system, viewpointId) {
|
|
3881
5921
|
return system?.viewpoints.find((viewpoint) => viewpoint.id === viewpointId) ?? null;
|
|
3882
5922
|
}
|
|
@@ -3887,20 +5927,37 @@ var WorldOrbit = (() => {
|
|
|
3887
5927
|
const index = items.findIndex((item) => item.id === value.id);
|
|
3888
5928
|
if (index === -1) {
|
|
3889
5929
|
items.push(value);
|
|
3890
|
-
items.sort(
|
|
5930
|
+
items.sort(compareIdLike2);
|
|
3891
5931
|
return;
|
|
3892
5932
|
}
|
|
3893
5933
|
items[index] = value;
|
|
3894
5934
|
}
|
|
3895
|
-
function
|
|
5935
|
+
function upsertEventPose(events, eventId, value) {
|
|
5936
|
+
const event = events.find((entry) => entry.id === eventId);
|
|
5937
|
+
if (!event) {
|
|
5938
|
+
throw new Error(`Unknown event "${eventId}" for pose update.`);
|
|
5939
|
+
}
|
|
5940
|
+
const index = event.positions.findIndex((entry) => entry.objectId === value.objectId);
|
|
5941
|
+
if (index === -1) {
|
|
5942
|
+
event.positions.push(value);
|
|
5943
|
+
event.positions.sort(comparePoseObjectId2);
|
|
5944
|
+
return;
|
|
5945
|
+
}
|
|
5946
|
+
event.positions[index] = value;
|
|
5947
|
+
}
|
|
5948
|
+
function compareIdLike2(left, right) {
|
|
3896
5949
|
return left.id.localeCompare(right.id);
|
|
3897
5950
|
}
|
|
5951
|
+
function comparePoseObjectId2(left, right) {
|
|
5952
|
+
return left.objectId.localeCompare(right.objectId);
|
|
5953
|
+
}
|
|
3898
5954
|
|
|
3899
5955
|
// packages/core/dist/load.js
|
|
3900
|
-
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0)?$/i;
|
|
5956
|
+
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|
|
5957
|
+
var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
3901
5958
|
var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
3902
5959
|
function detectWorldOrbitSchemaVersion(source) {
|
|
3903
|
-
for (const line of source.split(/\r?\n/)) {
|
|
5960
|
+
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
3904
5961
|
const trimmed = line.trim();
|
|
3905
5962
|
if (!trimmed) {
|
|
3906
5963
|
continue;
|
|
@@ -3908,6 +5965,9 @@ var WorldOrbit = (() => {
|
|
|
3908
5965
|
if (LEGACY_DRAFT_SCHEMA_PATTERN.test(trimmed)) {
|
|
3909
5966
|
return "2.0-draft";
|
|
3910
5967
|
}
|
|
5968
|
+
if (ATLAS_SCHEMA_21_PATTERN.test(trimmed)) {
|
|
5969
|
+
return "2.1";
|
|
5970
|
+
}
|
|
3911
5971
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
3912
5972
|
return "2.0";
|
|
3913
5973
|
}
|
|
@@ -3915,6 +5975,49 @@ var WorldOrbit = (() => {
|
|
|
3915
5975
|
}
|
|
3916
5976
|
return "1.0";
|
|
3917
5977
|
}
|
|
5978
|
+
function stripCommentsForSchemaDetection(source) {
|
|
5979
|
+
const chars = [...source];
|
|
5980
|
+
let inString = false;
|
|
5981
|
+
let inBlockComment = false;
|
|
5982
|
+
for (let index = 0; index < chars.length; index++) {
|
|
5983
|
+
const ch = chars[index];
|
|
5984
|
+
const next = chars[index + 1];
|
|
5985
|
+
if (inBlockComment) {
|
|
5986
|
+
if (ch === "*" && next === "/") {
|
|
5987
|
+
chars[index] = " ";
|
|
5988
|
+
chars[index + 1] = " ";
|
|
5989
|
+
inBlockComment = false;
|
|
5990
|
+
index++;
|
|
5991
|
+
continue;
|
|
5992
|
+
}
|
|
5993
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
5994
|
+
chars[index] = " ";
|
|
5995
|
+
}
|
|
5996
|
+
continue;
|
|
5997
|
+
}
|
|
5998
|
+
if (!inString && ch === "/" && next === "*") {
|
|
5999
|
+
chars[index] = " ";
|
|
6000
|
+
chars[index + 1] = " ";
|
|
6001
|
+
inBlockComment = true;
|
|
6002
|
+
index++;
|
|
6003
|
+
continue;
|
|
6004
|
+
}
|
|
6005
|
+
if (!inString && ch === "#") {
|
|
6006
|
+
chars[index] = " ";
|
|
6007
|
+
let inner = index + 1;
|
|
6008
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
6009
|
+
chars[inner] = " ";
|
|
6010
|
+
inner++;
|
|
6011
|
+
}
|
|
6012
|
+
index = inner - 1;
|
|
6013
|
+
continue;
|
|
6014
|
+
}
|
|
6015
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
6016
|
+
inString = !inString;
|
|
6017
|
+
}
|
|
6018
|
+
}
|
|
6019
|
+
return chars.join("");
|
|
6020
|
+
}
|
|
3918
6021
|
function loadWorldOrbitSource(source) {
|
|
3919
6022
|
const result = loadWorldOrbitSourceWithDiagnostics(source);
|
|
3920
6023
|
if (!result.ok || !result.value) {
|
|
@@ -3925,36 +6028,36 @@ var WorldOrbit = (() => {
|
|
|
3925
6028
|
}
|
|
3926
6029
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
3927
6030
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
3928
|
-
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft") {
|
|
6031
|
+
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1") {
|
|
3929
6032
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
3930
6033
|
}
|
|
3931
6034
|
let ast;
|
|
3932
6035
|
try {
|
|
3933
6036
|
ast = parseWorldOrbit(source);
|
|
3934
|
-
} catch (
|
|
6037
|
+
} catch (error2) {
|
|
3935
6038
|
return {
|
|
3936
6039
|
ok: false,
|
|
3937
6040
|
value: null,
|
|
3938
|
-
diagnostics: [diagnosticFromError(
|
|
6041
|
+
diagnostics: [diagnosticFromError(error2, "parse")]
|
|
3939
6042
|
};
|
|
3940
6043
|
}
|
|
3941
6044
|
let document;
|
|
3942
6045
|
try {
|
|
3943
6046
|
document = normalizeDocument(ast);
|
|
3944
|
-
} catch (
|
|
6047
|
+
} catch (error2) {
|
|
3945
6048
|
return {
|
|
3946
6049
|
ok: false,
|
|
3947
6050
|
value: null,
|
|
3948
|
-
diagnostics: [diagnosticFromError(
|
|
6051
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
3949
6052
|
};
|
|
3950
6053
|
}
|
|
3951
6054
|
try {
|
|
3952
6055
|
validateDocument(document);
|
|
3953
|
-
} catch (
|
|
6056
|
+
} catch (error2) {
|
|
3954
6057
|
return {
|
|
3955
6058
|
ok: false,
|
|
3956
6059
|
value: null,
|
|
3957
|
-
diagnostics: [diagnosticFromError(
|
|
6060
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
3958
6061
|
};
|
|
3959
6062
|
}
|
|
3960
6063
|
return {
|
|
@@ -3974,30 +6077,29 @@ var WorldOrbit = (() => {
|
|
|
3974
6077
|
let atlasDocument;
|
|
3975
6078
|
try {
|
|
3976
6079
|
atlasDocument = parseWorldOrbitAtlas(source);
|
|
3977
|
-
} catch (
|
|
6080
|
+
} catch (error2) {
|
|
3978
6081
|
return {
|
|
3979
6082
|
ok: false,
|
|
3980
6083
|
value: null,
|
|
3981
|
-
diagnostics: [diagnosticFromError(
|
|
6084
|
+
diagnostics: [diagnosticFromError(error2, "parse", "load.atlas.failed")]
|
|
3982
6085
|
};
|
|
3983
6086
|
}
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
document = materializeAtlasDocument(atlasDocument);
|
|
3987
|
-
} catch (error) {
|
|
6087
|
+
const atlasDiagnostics = [...atlasDocument.diagnostics];
|
|
6088
|
+
if (atlasDiagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
3988
6089
|
return {
|
|
3989
6090
|
ok: false,
|
|
3990
6091
|
value: null,
|
|
3991
|
-
diagnostics:
|
|
6092
|
+
diagnostics: atlasDiagnostics
|
|
3992
6093
|
};
|
|
3993
6094
|
}
|
|
6095
|
+
let document;
|
|
3994
6096
|
try {
|
|
3995
|
-
|
|
3996
|
-
} catch (
|
|
6097
|
+
document = materializeAtlasDocument(atlasDocument);
|
|
6098
|
+
} catch (error2) {
|
|
3997
6099
|
return {
|
|
3998
6100
|
ok: false,
|
|
3999
6101
|
value: null,
|
|
4000
|
-
diagnostics: [diagnosticFromError(
|
|
6102
|
+
diagnostics: [diagnosticFromError(error2, "normalize", "load.atlas.materialize.failed")]
|
|
4001
6103
|
};
|
|
4002
6104
|
}
|
|
4003
6105
|
const loaded = {
|
|
@@ -4006,12 +6108,12 @@ var WorldOrbit = (() => {
|
|
|
4006
6108
|
document,
|
|
4007
6109
|
atlasDocument,
|
|
4008
6110
|
draftDocument: atlasDocument,
|
|
4009
|
-
diagnostics:
|
|
6111
|
+
diagnostics: atlasDiagnostics
|
|
4010
6112
|
};
|
|
4011
6113
|
return {
|
|
4012
6114
|
ok: true,
|
|
4013
6115
|
value: loaded,
|
|
4014
|
-
diagnostics:
|
|
6116
|
+
diagnostics: atlasDiagnostics
|
|
4015
6117
|
};
|
|
4016
6118
|
}
|
|
4017
6119
|
|
|
@@ -4077,5 +6179,5 @@ var WorldOrbit = (() => {
|
|
|
4077
6179
|
function stringify(document, options = {}) {
|
|
4078
6180
|
return formatDocument(document, options);
|
|
4079
6181
|
}
|
|
4080
|
-
return __toCommonJS(
|
|
6182
|
+
return __toCommonJS(index_exports);
|
|
4081
6183
|
})();
|