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/markdown/dist/index.js
|
|
22
|
-
var
|
|
23
|
-
__export(
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
24
|
rehypeWorldOrbit: () => rehypeWorldOrbit,
|
|
25
25
|
remarkWorldOrbit: () => remarkWorldOrbit,
|
|
26
26
|
renderWorldOrbitBlock: () => renderWorldOrbitBlock,
|
|
@@ -329,13 +329,13 @@ var WorldOrbit = (() => {
|
|
|
329
329
|
function unitFamilyAllowsUnit(family, unit) {
|
|
330
330
|
switch (family) {
|
|
331
331
|
case "distance":
|
|
332
|
-
return unit === null || ["au", "km", "re", "sol"].includes(unit);
|
|
332
|
+
return unit === null || ["au", "km", "m", "ly", "pc", "kpc", "re", "sol"].includes(unit);
|
|
333
333
|
case "radius":
|
|
334
|
-
return unit === null || ["km", "re", "sol"].includes(unit);
|
|
334
|
+
return unit === null || ["km", "m", "re", "rj", "sol"].includes(unit);
|
|
335
335
|
case "mass":
|
|
336
|
-
return unit === null || ["me", "sol"].includes(unit);
|
|
336
|
+
return unit === null || ["me", "mj", "sol"].includes(unit);
|
|
337
337
|
case "duration":
|
|
338
|
-
return unit === null || ["h", "d", "y"].includes(unit);
|
|
338
|
+
return unit === null || ["s", "min", "h", "d", "y", "ky", "my", "gy"].includes(unit);
|
|
339
339
|
case "angle":
|
|
340
340
|
return unit === null || unit === "deg";
|
|
341
341
|
case "generic":
|
|
@@ -539,7 +539,7 @@ var WorldOrbit = (() => {
|
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
// packages/core/dist/normalize.js
|
|
542
|
-
var UNIT_PATTERN = /^(-?\d+(?:\.\d+)?)(au|km|re|sol|
|
|
542
|
+
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)?$/;
|
|
543
543
|
var BOOLEAN_VALUES = /* @__PURE__ */ new Map([
|
|
544
544
|
["true", true],
|
|
545
545
|
["false", false],
|
|
@@ -564,7 +564,11 @@ var WorldOrbit = (() => {
|
|
|
564
564
|
return {
|
|
565
565
|
format: "worldorbit",
|
|
566
566
|
version: "1.0",
|
|
567
|
+
schemaVersion: "1.0",
|
|
567
568
|
system,
|
|
569
|
+
groups: [],
|
|
570
|
+
relations: [],
|
|
571
|
+
events: [],
|
|
568
572
|
objects
|
|
569
573
|
};
|
|
570
574
|
}
|
|
@@ -574,13 +578,17 @@ var WorldOrbit = (() => {
|
|
|
574
578
|
const fieldMap = collectFields(mergedFields);
|
|
575
579
|
const placement = extractPlacement(node.objectType, fieldMap);
|
|
576
580
|
const properties = normalizeProperties(fieldMap);
|
|
577
|
-
const
|
|
581
|
+
const info2 = normalizeInfo(node.infoEntries);
|
|
578
582
|
if (node.objectType === "system") {
|
|
579
583
|
return {
|
|
580
584
|
type: "system",
|
|
581
585
|
id: node.name,
|
|
586
|
+
title: typeof properties.title === "string" ? properties.title : null,
|
|
587
|
+
description: null,
|
|
588
|
+
epoch: null,
|
|
589
|
+
referencePlane: null,
|
|
582
590
|
properties,
|
|
583
|
-
info
|
|
591
|
+
info: info2
|
|
584
592
|
};
|
|
585
593
|
}
|
|
586
594
|
return {
|
|
@@ -588,7 +596,7 @@ var WorldOrbit = (() => {
|
|
|
588
596
|
id: node.name,
|
|
589
597
|
properties,
|
|
590
598
|
placement,
|
|
591
|
-
info
|
|
599
|
+
info: info2
|
|
592
600
|
};
|
|
593
601
|
}
|
|
594
602
|
function validateFieldCompatibility(objectType, fields) {
|
|
@@ -718,14 +726,14 @@ var WorldOrbit = (() => {
|
|
|
718
726
|
}
|
|
719
727
|
}
|
|
720
728
|
function normalizeInfo(entries) {
|
|
721
|
-
const
|
|
729
|
+
const info2 = {};
|
|
722
730
|
for (const entry of entries) {
|
|
723
|
-
if (entry.key in
|
|
731
|
+
if (entry.key in info2) {
|
|
724
732
|
throw WorldOrbitError.fromLocation(`Duplicate info key "${entry.key}"`, entry.location);
|
|
725
733
|
}
|
|
726
|
-
|
|
734
|
+
info2[entry.key] = entry.value;
|
|
727
735
|
}
|
|
728
|
-
return
|
|
736
|
+
return info2;
|
|
729
737
|
}
|
|
730
738
|
function parseAtReference(target, location) {
|
|
731
739
|
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
@@ -896,37 +904,41 @@ var WorldOrbit = (() => {
|
|
|
896
904
|
}
|
|
897
905
|
|
|
898
906
|
// packages/core/dist/diagnostics.js
|
|
899
|
-
function diagnosticFromError(
|
|
900
|
-
if (
|
|
907
|
+
function diagnosticFromError(error2, source, code = `${source}.failed`) {
|
|
908
|
+
if (error2 instanceof WorldOrbitError) {
|
|
901
909
|
return {
|
|
902
910
|
code,
|
|
903
911
|
severity: "error",
|
|
904
912
|
source,
|
|
905
|
-
message:
|
|
906
|
-
line:
|
|
907
|
-
column:
|
|
913
|
+
message: error2.message,
|
|
914
|
+
line: error2.line,
|
|
915
|
+
column: error2.column
|
|
908
916
|
};
|
|
909
917
|
}
|
|
910
|
-
if (
|
|
918
|
+
if (error2 instanceof Error) {
|
|
911
919
|
return {
|
|
912
920
|
code,
|
|
913
921
|
severity: "error",
|
|
914
922
|
source,
|
|
915
|
-
message:
|
|
923
|
+
message: error2.message
|
|
916
924
|
};
|
|
917
925
|
}
|
|
918
926
|
return {
|
|
919
927
|
code,
|
|
920
928
|
severity: "error",
|
|
921
929
|
source,
|
|
922
|
-
message: String(
|
|
930
|
+
message: String(error2)
|
|
923
931
|
};
|
|
924
932
|
}
|
|
925
933
|
|
|
926
934
|
// packages/core/dist/scene.js
|
|
927
935
|
var AU_IN_KM = 1495978707e-1;
|
|
928
936
|
var EARTH_RADIUS_IN_KM = 6371;
|
|
937
|
+
var JUPITER_RADIUS_IN_KM = 71492;
|
|
929
938
|
var SOLAR_RADIUS_IN_KM = 695700;
|
|
939
|
+
var LY_IN_AU = 63241.077;
|
|
940
|
+
var PC_IN_AU = 206264.806;
|
|
941
|
+
var KPC_IN_AU = 206264806;
|
|
930
942
|
var ISO_FLATTENING = 0.68;
|
|
931
943
|
var MIN_ISO_MINOR_SCALE = 0.2;
|
|
932
944
|
var ARC_SAMPLE_COUNT = 28;
|
|
@@ -940,8 +952,10 @@ var WorldOrbit = (() => {
|
|
|
940
952
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
941
953
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
942
954
|
const systemId = document2.system?.id ?? null;
|
|
943
|
-
const
|
|
944
|
-
const
|
|
955
|
+
const activeEventId = options.activeEventId ?? null;
|
|
956
|
+
const effectiveObjects = createEffectiveObjects(document2.objects, document2.events ?? [], activeEventId);
|
|
957
|
+
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
958
|
+
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
945
959
|
const positions = /* @__PURE__ */ new Map();
|
|
946
960
|
const orbitDrafts = [];
|
|
947
961
|
const leaderDrafts = [];
|
|
@@ -950,7 +964,7 @@ var WorldOrbit = (() => {
|
|
|
950
964
|
const atObjects = [];
|
|
951
965
|
const surfaceChildren = /* @__PURE__ */ new Map();
|
|
952
966
|
const orbitChildren = /* @__PURE__ */ new Map();
|
|
953
|
-
for (const object of
|
|
967
|
+
for (const object of effectiveObjects) {
|
|
954
968
|
const placement = object.placement;
|
|
955
969
|
if (!placement) {
|
|
956
970
|
rootObjects.push(object);
|
|
@@ -1045,11 +1059,14 @@ var WorldOrbit = (() => {
|
|
|
1045
1059
|
const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
|
|
1046
1060
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1047
1061
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1048
|
-
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1049
|
-
const
|
|
1050
|
-
const
|
|
1062
|
+
const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
|
|
1063
|
+
const relations = createSceneRelations(document2, objects);
|
|
1064
|
+
const events = createSceneEvents(document2.events ?? [], objects, activeEventId);
|
|
1065
|
+
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1066
|
+
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1067
|
+
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1051
1068
|
const viewpoints = createSceneViewpoints(document2, projection, frame.preset, relationships, objectMap);
|
|
1052
|
-
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1069
|
+
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1053
1070
|
return {
|
|
1054
1071
|
width,
|
|
1055
1072
|
height,
|
|
@@ -1057,7 +1074,7 @@ var WorldOrbit = (() => {
|
|
|
1057
1074
|
renderPreset: frame.preset,
|
|
1058
1075
|
projection,
|
|
1059
1076
|
scaleModel,
|
|
1060
|
-
title: String(document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1077
|
+
title: String(document2.system?.title ?? document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1061
1078
|
subtitle: `${capitalizeLabel(projection)} view - ${capitalizeLabel(layoutPreset)} layout`,
|
|
1062
1079
|
systemId,
|
|
1063
1080
|
viewMode: projection,
|
|
@@ -1073,13 +1090,46 @@ var WorldOrbit = (() => {
|
|
|
1073
1090
|
contentBounds,
|
|
1074
1091
|
layers,
|
|
1075
1092
|
groups,
|
|
1093
|
+
semanticGroups,
|
|
1076
1094
|
viewpoints,
|
|
1095
|
+
events,
|
|
1096
|
+
activeEventId,
|
|
1077
1097
|
objects,
|
|
1078
1098
|
orbitVisuals,
|
|
1099
|
+
relations,
|
|
1079
1100
|
leaders,
|
|
1080
1101
|
labels
|
|
1081
1102
|
};
|
|
1082
1103
|
}
|
|
1104
|
+
function createEffectiveObjects(objects, events, activeEventId) {
|
|
1105
|
+
const cloned = objects.map((object) => structuredClone(object));
|
|
1106
|
+
if (!activeEventId) {
|
|
1107
|
+
return cloned;
|
|
1108
|
+
}
|
|
1109
|
+
const activeEvent = events.find((event) => event.id === activeEventId);
|
|
1110
|
+
if (!activeEvent) {
|
|
1111
|
+
return cloned;
|
|
1112
|
+
}
|
|
1113
|
+
const objectMap = new Map(cloned.map((object) => [object.id, object]));
|
|
1114
|
+
for (const pose of activeEvent.positions) {
|
|
1115
|
+
const object = objectMap.get(pose.objectId);
|
|
1116
|
+
if (!object) {
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
object.placement = pose.placement ? structuredClone(pose.placement) : null;
|
|
1120
|
+
if (pose.inner) {
|
|
1121
|
+
object.properties.inner = { ...pose.inner };
|
|
1122
|
+
} else {
|
|
1123
|
+
delete object.properties.inner;
|
|
1124
|
+
}
|
|
1125
|
+
if (pose.outer) {
|
|
1126
|
+
object.properties.outer = { ...pose.outer };
|
|
1127
|
+
} else {
|
|
1128
|
+
delete object.properties.outer;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
return cloned;
|
|
1132
|
+
}
|
|
1083
1133
|
function resolveLayoutPreset(document2) {
|
|
1084
1134
|
const rawScale = String(document2.system?.properties.scale ?? "balanced").toLowerCase();
|
|
1085
1135
|
switch (rawScale) {
|
|
@@ -1174,6 +1224,7 @@ var WorldOrbit = (() => {
|
|
|
1174
1224
|
}
|
|
1175
1225
|
function createSceneObject(position, scaleModel, relationships) {
|
|
1176
1226
|
const { object, x, y, radius, sortKey, anchorX, anchorY } = position;
|
|
1227
|
+
const renderPriority = object.renderHints?.renderPriority ?? 0;
|
|
1177
1228
|
return {
|
|
1178
1229
|
renderId: createRenderId(object.id),
|
|
1179
1230
|
objectId: object.id,
|
|
@@ -1182,11 +1233,12 @@ var WorldOrbit = (() => {
|
|
|
1182
1233
|
ancestorIds: relationships.ancestorIds.get(object.id) ?? [],
|
|
1183
1234
|
childIds: relationships.childIds.get(object.id) ?? [],
|
|
1184
1235
|
groupId: relationships.groupIds.get(object.id) ?? null,
|
|
1236
|
+
semanticGroupIds: [...object.groups ?? []],
|
|
1185
1237
|
x,
|
|
1186
1238
|
y,
|
|
1187
1239
|
radius,
|
|
1188
1240
|
visualRadius: visualExtentForObject(object, radius, scaleModel),
|
|
1189
|
-
sortKey,
|
|
1241
|
+
sortKey: sortKey + renderPriority * 1e-3,
|
|
1190
1242
|
anchorX,
|
|
1191
1243
|
anchorY,
|
|
1192
1244
|
label: object.id,
|
|
@@ -1203,6 +1255,7 @@ var WorldOrbit = (() => {
|
|
|
1203
1255
|
object: draft.object,
|
|
1204
1256
|
parentId: draft.parentId,
|
|
1205
1257
|
groupId,
|
|
1258
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1206
1259
|
kind: draft.kind,
|
|
1207
1260
|
cx: draft.cx,
|
|
1208
1261
|
cy: draft.cy,
|
|
@@ -1214,7 +1267,7 @@ var WorldOrbit = (() => {
|
|
|
1214
1267
|
bandThickness: draft.bandThickness,
|
|
1215
1268
|
frontArcPath: draft.frontArcPath,
|
|
1216
1269
|
backArcPath: draft.backArcPath,
|
|
1217
|
-
hidden: draft.object.properties.hidden === true
|
|
1270
|
+
hidden: draft.object.properties.hidden === true || draft.object.renderHints?.renderOrbit === false
|
|
1218
1271
|
};
|
|
1219
1272
|
}
|
|
1220
1273
|
function createLeaderLine(draft) {
|
|
@@ -1223,6 +1276,7 @@ var WorldOrbit = (() => {
|
|
|
1223
1276
|
objectId: draft.object.id,
|
|
1224
1277
|
object: draft.object,
|
|
1225
1278
|
groupId: draft.groupId,
|
|
1279
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1226
1280
|
x1: draft.x1,
|
|
1227
1281
|
y1: draft.y1,
|
|
1228
1282
|
x2: draft.x2,
|
|
@@ -1231,42 +1285,144 @@ var WorldOrbit = (() => {
|
|
|
1231
1285
|
hidden: draft.object.properties.hidden === true
|
|
1232
1286
|
};
|
|
1233
1287
|
}
|
|
1234
|
-
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1288
|
+
function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1235
1289
|
const labels = [];
|
|
1236
1290
|
const occupied = [];
|
|
1237
|
-
const
|
|
1291
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1292
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
|
|
1238
1293
|
for (const object of visibleObjects) {
|
|
1239
|
-
const
|
|
1240
|
-
|
|
1241
|
-
let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
|
|
1242
|
-
let secondaryY = labelY + direction * (16 * labelMultiplier);
|
|
1243
|
-
let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1244
|
-
let attempts = 0;
|
|
1245
|
-
while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
|
|
1246
|
-
labelY += direction * 14 * labelMultiplier;
|
|
1247
|
-
secondaryY += direction * 14 * labelMultiplier;
|
|
1248
|
-
bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1249
|
-
attempts += 1;
|
|
1250
|
-
}
|
|
1251
|
-
occupied.push(bounds);
|
|
1294
|
+
const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
|
|
1295
|
+
occupied.push(createLabelRect(object, placement, labelMultiplier));
|
|
1252
1296
|
labels.push({
|
|
1253
1297
|
renderId: `${object.renderId}-label`,
|
|
1254
1298
|
objectId: object.objectId,
|
|
1255
1299
|
object: object.object,
|
|
1256
1300
|
groupId: object.groupId,
|
|
1301
|
+
semanticGroupIds: [...object.semanticGroupIds],
|
|
1257
1302
|
label: object.label,
|
|
1258
1303
|
secondaryLabel: object.secondaryLabel,
|
|
1259
|
-
x:
|
|
1260
|
-
y: labelY,
|
|
1261
|
-
secondaryY,
|
|
1262
|
-
textAnchor:
|
|
1263
|
-
direction: direction
|
|
1304
|
+
x: placement.x,
|
|
1305
|
+
y: placement.labelY,
|
|
1306
|
+
secondaryY: placement.secondaryY,
|
|
1307
|
+
textAnchor: placement.textAnchor,
|
|
1308
|
+
direction: placement.direction,
|
|
1264
1309
|
hidden: object.hidden
|
|
1265
1310
|
});
|
|
1266
1311
|
}
|
|
1267
1312
|
return labels;
|
|
1268
1313
|
}
|
|
1269
|
-
function
|
|
1314
|
+
function compareLabelPlacementOrder(left, right) {
|
|
1315
|
+
const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
|
|
1316
|
+
if (priorityDiff !== 0) {
|
|
1317
|
+
return priorityDiff;
|
|
1318
|
+
}
|
|
1319
|
+
const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
|
|
1320
|
+
if (renderPriorityDiff !== 0) {
|
|
1321
|
+
return renderPriorityDiff;
|
|
1322
|
+
}
|
|
1323
|
+
return left.sortKey - right.sortKey;
|
|
1324
|
+
}
|
|
1325
|
+
function labelPlacementPriority(object) {
|
|
1326
|
+
switch (object.object.type) {
|
|
1327
|
+
case "star":
|
|
1328
|
+
return 0;
|
|
1329
|
+
case "planet":
|
|
1330
|
+
return 1;
|
|
1331
|
+
case "moon":
|
|
1332
|
+
return 2;
|
|
1333
|
+
case "belt":
|
|
1334
|
+
case "ring":
|
|
1335
|
+
return 3;
|
|
1336
|
+
case "asteroid":
|
|
1337
|
+
case "comet":
|
|
1338
|
+
return 4;
|
|
1339
|
+
case "structure":
|
|
1340
|
+
case "phenomenon":
|
|
1341
|
+
return 5;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1345
|
+
for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
|
|
1346
|
+
const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
|
|
1347
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
|
|
1348
|
+
const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
|
|
1349
|
+
const rect = createLabelRect(object, placement, labelMultiplier);
|
|
1350
|
+
if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
|
|
1351
|
+
return placement;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
return null;
|
|
1356
|
+
}
|
|
1357
|
+
function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
|
|
1358
|
+
const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
|
|
1359
|
+
const vertical = defaultVerticalDirection(object, parent, sceneHeight);
|
|
1360
|
+
const oppositeVertical = vertical === "below" ? "above" : "below";
|
|
1361
|
+
const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
|
|
1362
|
+
const oppositeHorizontal = horizontal === "right" ? "left" : "right";
|
|
1363
|
+
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";
|
|
1364
|
+
return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
|
|
1365
|
+
}
|
|
1366
|
+
function defaultVerticalDirection(object, parent, sceneHeight) {
|
|
1367
|
+
if (parent && Math.abs(object.y - parent.y) > 6) {
|
|
1368
|
+
return object.y >= parent.y ? "below" : "above";
|
|
1369
|
+
}
|
|
1370
|
+
return object.y > sceneHeight * 0.62 ? "above" : "below";
|
|
1371
|
+
}
|
|
1372
|
+
function defaultHorizontalDirection(object, parent, sceneWidth) {
|
|
1373
|
+
if (parent && Math.abs(object.x - parent.x) > 6) {
|
|
1374
|
+
return object.x >= parent.x ? "right" : "left";
|
|
1375
|
+
}
|
|
1376
|
+
return object.x >= sceneWidth / 2 ? "right" : "left";
|
|
1377
|
+
}
|
|
1378
|
+
function createLabelPlacement(object, direction, attempt, labelMultiplier) {
|
|
1379
|
+
const step = 14 * labelMultiplier;
|
|
1380
|
+
switch (direction) {
|
|
1381
|
+
case "above": {
|
|
1382
|
+
const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
|
|
1383
|
+
return {
|
|
1384
|
+
x: object.x,
|
|
1385
|
+
labelY,
|
|
1386
|
+
secondaryY: labelY - 16 * labelMultiplier,
|
|
1387
|
+
textAnchor: "middle",
|
|
1388
|
+
direction
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
case "below": {
|
|
1392
|
+
const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
|
|
1393
|
+
return {
|
|
1394
|
+
x: object.x,
|
|
1395
|
+
labelY,
|
|
1396
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1397
|
+
textAnchor: "middle",
|
|
1398
|
+
direction
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
case "left": {
|
|
1402
|
+
const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
|
|
1403
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1404
|
+
return {
|
|
1405
|
+
x,
|
|
1406
|
+
labelY,
|
|
1407
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1408
|
+
textAnchor: "end",
|
|
1409
|
+
direction
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
case "right": {
|
|
1413
|
+
const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
|
|
1414
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1415
|
+
return {
|
|
1416
|
+
x,
|
|
1417
|
+
labelY,
|
|
1418
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1419
|
+
textAnchor: "start",
|
|
1420
|
+
direction
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
|
|
1270
1426
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1271
1427
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1272
1428
|
return [
|
|
@@ -1277,6 +1433,14 @@ var WorldOrbit = (() => {
|
|
|
1277
1433
|
},
|
|
1278
1434
|
{ id: "orbits-back", renderIds: backOrbitIds },
|
|
1279
1435
|
{ id: "orbits-front", renderIds: frontOrbitIds },
|
|
1436
|
+
{
|
|
1437
|
+
id: "relations",
|
|
1438
|
+
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
id: "events",
|
|
1442
|
+
renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
|
|
1443
|
+
},
|
|
1280
1444
|
{
|
|
1281
1445
|
id: "objects",
|
|
1282
1446
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1288,7 +1452,7 @@ var WorldOrbit = (() => {
|
|
|
1288
1452
|
{ id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
|
|
1289
1453
|
];
|
|
1290
1454
|
}
|
|
1291
|
-
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
|
|
1455
|
+
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
|
|
1292
1456
|
const groups = /* @__PURE__ */ new Map();
|
|
1293
1457
|
const ensureGroup = (groupId) => {
|
|
1294
1458
|
if (!groupId) {
|
|
@@ -1337,10 +1501,63 @@ var WorldOrbit = (() => {
|
|
|
1337
1501
|
}
|
|
1338
1502
|
}
|
|
1339
1503
|
for (const group of groups.values()) {
|
|
1340
|
-
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
|
|
1504
|
+
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
|
|
1341
1505
|
}
|
|
1342
1506
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1343
1507
|
}
|
|
1508
|
+
function createSceneSemanticGroups(document2, objects) {
|
|
1509
|
+
return [...document2.groups].map((group) => ({
|
|
1510
|
+
id: group.id,
|
|
1511
|
+
label: group.label,
|
|
1512
|
+
summary: group.summary,
|
|
1513
|
+
color: group.color,
|
|
1514
|
+
tags: [...group.tags],
|
|
1515
|
+
hidden: group.hidden,
|
|
1516
|
+
objectIds: objects.filter((object) => !object.hidden && object.semanticGroupIds.includes(group.id)).map((object) => object.objectId)
|
|
1517
|
+
})).sort((left, right) => left.label.localeCompare(right.label));
|
|
1518
|
+
}
|
|
1519
|
+
function createSceneRelations(document2, objects) {
|
|
1520
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1521
|
+
return document2.relations.map((relation) => {
|
|
1522
|
+
const from = objectMap.get(relation.from);
|
|
1523
|
+
const to = objectMap.get(relation.to);
|
|
1524
|
+
return {
|
|
1525
|
+
renderId: `${createRenderId(relation.id)}-relation`,
|
|
1526
|
+
relationId: relation.id,
|
|
1527
|
+
relation,
|
|
1528
|
+
fromObjectId: relation.from,
|
|
1529
|
+
toObjectId: relation.to,
|
|
1530
|
+
x1: from?.x ?? 0,
|
|
1531
|
+
y1: from?.y ?? 0,
|
|
1532
|
+
x2: to?.x ?? 0,
|
|
1533
|
+
y2: to?.y ?? 0,
|
|
1534
|
+
hidden: relation.hidden || !from || !to || from.hidden || to.hidden
|
|
1535
|
+
};
|
|
1536
|
+
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1537
|
+
}
|
|
1538
|
+
function createSceneEvents(events, objects, activeEventId) {
|
|
1539
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1540
|
+
return events.map((event) => {
|
|
1541
|
+
const objectIds = [.../* @__PURE__ */ new Set([
|
|
1542
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
1543
|
+
...event.participantObjectIds
|
|
1544
|
+
])];
|
|
1545
|
+
const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
|
|
1546
|
+
const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
|
|
1547
|
+
const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
|
|
1548
|
+
return {
|
|
1549
|
+
renderId: `${createRenderId(event.id)}-event`,
|
|
1550
|
+
eventId: event.id,
|
|
1551
|
+
event,
|
|
1552
|
+
objectIds,
|
|
1553
|
+
participantIds: [...event.participantObjectIds],
|
|
1554
|
+
targetObjectId: event.targetObjectId,
|
|
1555
|
+
x: centroidX,
|
|
1556
|
+
y: centroidY,
|
|
1557
|
+
hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
|
|
1558
|
+
};
|
|
1559
|
+
}).sort((left, right) => left.event.id.localeCompare(right.event.id));
|
|
1560
|
+
}
|
|
1344
1561
|
function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
|
|
1345
1562
|
const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
|
|
1346
1563
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1358,7 +1575,7 @@ var WorldOrbit = (() => {
|
|
|
1358
1575
|
}
|
|
1359
1576
|
const field = fieldParts.join(".").toLowerCase();
|
|
1360
1577
|
const draft = drafts.get(id) ?? { id };
|
|
1361
|
-
applyViewpointField(draft, field, value, projection, preset, relationships, objectMap);
|
|
1578
|
+
applyViewpointField(draft, field, value, document2, projection, preset, relationships, objectMap);
|
|
1362
1579
|
drafts.set(id, draft);
|
|
1363
1580
|
}
|
|
1364
1581
|
const viewpoints = [...drafts.values()].map((draft) => finalizeViewpointDraft(draft, projection, preset, objectMap)).filter(Boolean);
|
|
@@ -1386,13 +1603,15 @@ var WorldOrbit = (() => {
|
|
|
1386
1603
|
});
|
|
1387
1604
|
}
|
|
1388
1605
|
function createGeneratedOverviewViewpoint(document2, projection, preset) {
|
|
1389
|
-
const
|
|
1606
|
+
const title = document2.system?.title ?? document2.system?.properties.title;
|
|
1607
|
+
const label = title ? `${String(title)} Overview` : "Overview";
|
|
1390
1608
|
return {
|
|
1391
1609
|
id: "overview",
|
|
1392
1610
|
label,
|
|
1393
1611
|
summary: "Fit the whole system with the current atlas defaults.",
|
|
1394
1612
|
objectId: null,
|
|
1395
1613
|
selectedObjectId: null,
|
|
1614
|
+
eventIds: [],
|
|
1396
1615
|
projection,
|
|
1397
1616
|
preset,
|
|
1398
1617
|
rotationDeg: 0,
|
|
@@ -1402,7 +1621,7 @@ var WorldOrbit = (() => {
|
|
|
1402
1621
|
generated: true
|
|
1403
1622
|
};
|
|
1404
1623
|
}
|
|
1405
|
-
function applyViewpointField(draft, field, value, projection, preset, relationships, objectMap) {
|
|
1624
|
+
function applyViewpointField(draft, field, value, document2, projection, preset, relationships, objectMap) {
|
|
1406
1625
|
const normalizedValue = value.trim();
|
|
1407
1626
|
switch (field) {
|
|
1408
1627
|
case "label":
|
|
@@ -1429,6 +1648,9 @@ var WorldOrbit = (() => {
|
|
|
1429
1648
|
draft.select = normalizedValue;
|
|
1430
1649
|
}
|
|
1431
1650
|
return;
|
|
1651
|
+
case "events":
|
|
1652
|
+
draft.eventIds = splitListValue(normalizedValue);
|
|
1653
|
+
return;
|
|
1432
1654
|
case "projection":
|
|
1433
1655
|
case "view":
|
|
1434
1656
|
draft.projection = parseViewProjection(normalizedValue) ?? projection;
|
|
@@ -1469,7 +1691,7 @@ var WorldOrbit = (() => {
|
|
|
1469
1691
|
case "groups":
|
|
1470
1692
|
draft.filter = {
|
|
1471
1693
|
...draft.filter ?? createEmptyViewpointFilter(),
|
|
1472
|
-
groupIds: parseViewpointGroups(normalizedValue, relationships, objectMap)
|
|
1694
|
+
groupIds: parseViewpointGroups(normalizedValue, document2, relationships, objectMap)
|
|
1473
1695
|
};
|
|
1474
1696
|
return;
|
|
1475
1697
|
}
|
|
@@ -1485,6 +1707,7 @@ var WorldOrbit = (() => {
|
|
|
1485
1707
|
summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
|
|
1486
1708
|
objectId,
|
|
1487
1709
|
selectedObjectId,
|
|
1710
|
+
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
1488
1711
|
projection: draft.projection ?? projection,
|
|
1489
1712
|
preset: draft.preset ?? preset,
|
|
1490
1713
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
@@ -1542,7 +1765,7 @@ var WorldOrbit = (() => {
|
|
|
1542
1765
|
next["orbits-front"] = enabled;
|
|
1543
1766
|
continue;
|
|
1544
1767
|
}
|
|
1545
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1768
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1546
1769
|
next[rawLayer] = enabled;
|
|
1547
1770
|
}
|
|
1548
1771
|
}
|
|
@@ -1551,8 +1774,11 @@ var WorldOrbit = (() => {
|
|
|
1551
1774
|
function parseViewpointObjectTypes(value) {
|
|
1552
1775
|
return splitListValue(value).filter((entry) => entry === "star" || entry === "planet" || entry === "moon" || entry === "belt" || entry === "asteroid" || entry === "comet" || entry === "ring" || entry === "structure" || entry === "phenomenon");
|
|
1553
1776
|
}
|
|
1554
|
-
function parseViewpointGroups(value, relationships, objectMap) {
|
|
1777
|
+
function parseViewpointGroups(value, document2, relationships, objectMap) {
|
|
1555
1778
|
return splitListValue(value).map((entry) => {
|
|
1779
|
+
if (document2.schemaVersion === "2.1" || document2.groups.some((group) => group.id === entry)) {
|
|
1780
|
+
return entry;
|
|
1781
|
+
}
|
|
1556
1782
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
1557
1783
|
return entry;
|
|
1558
1784
|
}
|
|
@@ -1587,7 +1813,7 @@ var WorldOrbit = (() => {
|
|
|
1587
1813
|
}
|
|
1588
1814
|
return parts.join(" - ");
|
|
1589
1815
|
}
|
|
1590
|
-
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
|
|
1816
|
+
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
1591
1817
|
let minX = Number.POSITIVE_INFINITY;
|
|
1592
1818
|
let minY = Number.POSITIVE_INFINITY;
|
|
1593
1819
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -1617,7 +1843,7 @@ var WorldOrbit = (() => {
|
|
|
1617
1843
|
for (const label of labels) {
|
|
1618
1844
|
if (label.hidden)
|
|
1619
1845
|
continue;
|
|
1620
|
-
includeLabelBounds(label, include);
|
|
1846
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
1621
1847
|
}
|
|
1622
1848
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
1623
1849
|
return createBounds(0, 0, width, height);
|
|
@@ -1655,13 +1881,10 @@ var WorldOrbit = (() => {
|
|
|
1655
1881
|
include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
|
|
1656
1882
|
include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
|
|
1657
1883
|
}
|
|
1658
|
-
function includeLabelBounds(label, include) {
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
include(
|
|
1662
|
-
include(label.x + labelHalfWidth, label.y + 8);
|
|
1663
|
-
include(label.x - labelHalfWidth, label.secondaryY - 14);
|
|
1664
|
-
include(label.x + labelHalfWidth, label.secondaryY + 8);
|
|
1884
|
+
function includeLabelBounds(label, include, labelMultiplier) {
|
|
1885
|
+
const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
|
|
1886
|
+
include(bounds.left, bounds.top);
|
|
1887
|
+
include(bounds.right, bounds.bottom);
|
|
1665
1888
|
}
|
|
1666
1889
|
function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
|
|
1667
1890
|
if (positions.has(object.id)) {
|
|
@@ -1683,8 +1906,9 @@ var WorldOrbit = (() => {
|
|
|
1683
1906
|
}
|
|
1684
1907
|
const orbiting = [...context.orbitChildren.get(object.id) ?? []].sort(compareOrbiting);
|
|
1685
1908
|
const orbitMetricContext = computeOrbitMetricContext(orbiting, parent.radius, context.spacingFactor, context.scaleModel);
|
|
1909
|
+
const orbitRadiiPx = resolveOrbitRadiiPx(orbiting, orbitMetricContext);
|
|
1686
1910
|
orbiting.forEach((child, index) => {
|
|
1687
|
-
const orbitGeometry = resolveOrbitGeometry(child, index, orbiting.length, parent, orbitMetricContext, context);
|
|
1911
|
+
const orbitGeometry = resolveOrbitGeometry(child, index, orbiting.length, parent, orbitMetricContext, orbitRadiiPx[index] ?? orbitMetricContext.innerPx, context);
|
|
1688
1912
|
orbitDrafts.push({
|
|
1689
1913
|
object: child,
|
|
1690
1914
|
parentId: object.id,
|
|
@@ -1758,7 +1982,8 @@ var WorldOrbit = (() => {
|
|
|
1758
1982
|
metricSpread: 0,
|
|
1759
1983
|
innerPx,
|
|
1760
1984
|
stepPx,
|
|
1761
|
-
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx)
|
|
1985
|
+
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
1986
|
+
minimumGapPx: stepPx * 0.42
|
|
1762
1987
|
};
|
|
1763
1988
|
}
|
|
1764
1989
|
const minMetric = Math.min(...presentMetrics);
|
|
@@ -1771,10 +1996,11 @@ var WorldOrbit = (() => {
|
|
|
1771
1996
|
metricSpread,
|
|
1772
1997
|
innerPx,
|
|
1773
1998
|
stepPx,
|
|
1774
|
-
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx)
|
|
1999
|
+
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
2000
|
+
minimumGapPx: stepPx * 0.42
|
|
1775
2001
|
};
|
|
1776
2002
|
}
|
|
1777
|
-
function resolveOrbitGeometry(object, index, count, parent, metricContext, context) {
|
|
2003
|
+
function resolveOrbitGeometry(object, index, count, parent, metricContext, orbitRadiusPx, context) {
|
|
1778
2004
|
const placement = object.placement;
|
|
1779
2005
|
const band = object.type === "belt" || object.type === "ring";
|
|
1780
2006
|
if (!placement || placement.mode !== "orbit") {
|
|
@@ -1792,7 +2018,7 @@ var WorldOrbit = (() => {
|
|
|
1792
2018
|
};
|
|
1793
2019
|
}
|
|
1794
2020
|
const eccentricity = clampNumber(typeof placement.eccentricity === "number" ? placement.eccentricity : 0, 0, 0.92);
|
|
1795
|
-
const semiMajor =
|
|
2021
|
+
const semiMajor = orbitRadiusPx;
|
|
1796
2022
|
const baseMinor = Math.max(semiMajor * Math.sqrt(1 - eccentricity * eccentricity), semiMajor * 0.18);
|
|
1797
2023
|
const inclinationDeg = unitValueToDegrees(placement.inclination) ?? 0;
|
|
1798
2024
|
const inclinationScale = context.projection === "isometric" ? Math.max(MIN_ISO_MINOR_SCALE, Math.cos(degreesToRadians(inclinationDeg))) * ISO_FLATTENING : 1;
|
|
@@ -1822,15 +2048,19 @@ var WorldOrbit = (() => {
|
|
|
1822
2048
|
objectY: objectPoint.y
|
|
1823
2049
|
};
|
|
1824
2050
|
}
|
|
1825
|
-
function resolveOrbitRadiusPx(
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
2051
|
+
function resolveOrbitRadiusPx(metric, metricContext) {
|
|
2052
|
+
return metricContext.innerPx + metricContext.stepPx * log2(Math.max(metric, 0) + 1);
|
|
2053
|
+
}
|
|
2054
|
+
function resolveOrbitRadiiPx(objects, metricContext) {
|
|
2055
|
+
const radii = [];
|
|
2056
|
+
objects.forEach((object, index) => {
|
|
2057
|
+
const metric = orbitMetric(object);
|
|
2058
|
+
const fallbackRadius = metricContext.innerPx + index * metricContext.stepPx;
|
|
2059
|
+
const baseRadius = metric === null ? fallbackRadius : resolveOrbitRadiusPx(metric, metricContext);
|
|
2060
|
+
const minimumRadius = index === 0 ? metricContext.innerPx : (radii[index - 1] ?? metricContext.innerPx) + metricContext.minimumGapPx;
|
|
2061
|
+
radii.push(Math.max(baseRadius, minimumRadius));
|
|
2062
|
+
});
|
|
2063
|
+
return radii;
|
|
1834
2064
|
}
|
|
1835
2065
|
function orbitMetric(object) {
|
|
1836
2066
|
if (!object.placement || object.placement.mode !== "orbit") {
|
|
@@ -1838,6 +2068,9 @@ var WorldOrbit = (() => {
|
|
|
1838
2068
|
}
|
|
1839
2069
|
return toDistanceMetric(object.placement.semiMajor ?? object.placement.distance ?? null);
|
|
1840
2070
|
}
|
|
2071
|
+
function log2(value) {
|
|
2072
|
+
return Math.log(value) / Math.log(2);
|
|
2073
|
+
}
|
|
1841
2074
|
function resolveOrbitPhase(phase, index, count) {
|
|
1842
2075
|
const degreeValue = phase ? unitValueToDegrees(phase) : null;
|
|
1843
2076
|
if (degreeValue !== null) {
|
|
@@ -2041,7 +2274,7 @@ var WorldOrbit = (() => {
|
|
|
2041
2274
|
return null;
|
|
2042
2275
|
}
|
|
2043
2276
|
}
|
|
2044
|
-
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
|
|
2277
|
+
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2045
2278
|
let minX = Number.POSITIVE_INFINITY;
|
|
2046
2279
|
let minY = Number.POSITIVE_INFINITY;
|
|
2047
2280
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2070,7 +2303,7 @@ var WorldOrbit = (() => {
|
|
|
2070
2303
|
}
|
|
2071
2304
|
for (const label of labels) {
|
|
2072
2305
|
if (!label.hidden && group.labelIds.includes(label.objectId)) {
|
|
2073
|
-
includeLabelBounds(label, include);
|
|
2306
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2074
2307
|
}
|
|
2075
2308
|
}
|
|
2076
2309
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
@@ -2095,12 +2328,28 @@ var WorldOrbit = (() => {
|
|
|
2095
2328
|
}
|
|
2096
2329
|
return current.id;
|
|
2097
2330
|
}
|
|
2098
|
-
function createLabelRect(
|
|
2331
|
+
function createLabelRect(object, placement, labelMultiplier) {
|
|
2332
|
+
return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
|
|
2333
|
+
}
|
|
2334
|
+
function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
|
|
2335
|
+
const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
|
|
2336
|
+
const labelWidth = labelHalfWidth * 2;
|
|
2337
|
+
const topPadding = direction === "above" ? 18 : 12;
|
|
2338
|
+
const bottomPadding = direction === "above" ? 8 : 12;
|
|
2339
|
+
let left = x - labelHalfWidth;
|
|
2340
|
+
let right = x + labelHalfWidth;
|
|
2341
|
+
if (textAnchor === "start") {
|
|
2342
|
+
left = x;
|
|
2343
|
+
right = x + labelWidth;
|
|
2344
|
+
} else if (textAnchor === "end") {
|
|
2345
|
+
left = x - labelWidth;
|
|
2346
|
+
right = x;
|
|
2347
|
+
}
|
|
2099
2348
|
return {
|
|
2100
|
-
left
|
|
2101
|
-
right
|
|
2102
|
-
top: Math.min(labelY, secondaryY) -
|
|
2103
|
-
bottom: Math.max(labelY, secondaryY) +
|
|
2349
|
+
left,
|
|
2350
|
+
right,
|
|
2351
|
+
top: Math.min(labelY, secondaryY) - topPadding,
|
|
2352
|
+
bottom: Math.max(labelY, secondaryY) + bottomPadding
|
|
2104
2353
|
};
|
|
2105
2354
|
}
|
|
2106
2355
|
function rectsOverlap(left, right) {
|
|
@@ -2161,8 +2410,18 @@ var WorldOrbit = (() => {
|
|
|
2161
2410
|
return value.value;
|
|
2162
2411
|
case "km":
|
|
2163
2412
|
return value.value / AU_IN_KM;
|
|
2413
|
+
case "m":
|
|
2414
|
+
return value.value / 1e3 / AU_IN_KM;
|
|
2415
|
+
case "ly":
|
|
2416
|
+
return value.value * LY_IN_AU;
|
|
2417
|
+
case "pc":
|
|
2418
|
+
return value.value * PC_IN_AU;
|
|
2419
|
+
case "kpc":
|
|
2420
|
+
return value.value * KPC_IN_AU;
|
|
2164
2421
|
case "re":
|
|
2165
2422
|
return value.value * EARTH_RADIUS_IN_KM / AU_IN_KM;
|
|
2423
|
+
case "rj":
|
|
2424
|
+
return value.value * JUPITER_RADIUS_IN_KM / AU_IN_KM;
|
|
2166
2425
|
case "sol":
|
|
2167
2426
|
return value.value * SOLAR_RADIUS_IN_KM / AU_IN_KM;
|
|
2168
2427
|
default:
|
|
@@ -2277,11 +2536,6 @@ var WorldOrbit = (() => {
|
|
|
2277
2536
|
function customColorFor(value) {
|
|
2278
2537
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2279
2538
|
}
|
|
2280
|
-
function estimateLabelHalfWidth(object, labelMultiplier) {
|
|
2281
|
-
const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
|
|
2282
|
-
const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
2283
|
-
return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
|
|
2284
|
-
}
|
|
2285
2539
|
function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
|
|
2286
2540
|
const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
|
|
2287
2541
|
const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
@@ -2298,28 +2552,95 @@ var WorldOrbit = (() => {
|
|
|
2298
2552
|
}
|
|
2299
2553
|
|
|
2300
2554
|
// packages/core/dist/draft.js
|
|
2301
|
-
function materializeAtlasDocument(document2) {
|
|
2555
|
+
function materializeAtlasDocument(document2, options = {}) {
|
|
2302
2556
|
const system = document2.system ? {
|
|
2303
2557
|
type: "system",
|
|
2304
2558
|
id: document2.system.id,
|
|
2559
|
+
title: document2.system.title,
|
|
2560
|
+
description: document2.system.description,
|
|
2561
|
+
epoch: document2.system.epoch,
|
|
2562
|
+
referencePlane: document2.system.referencePlane,
|
|
2305
2563
|
properties: materializeDraftSystemProperties(document2.system),
|
|
2306
2564
|
info: materializeDraftSystemInfo(document2.system)
|
|
2307
2565
|
} : null;
|
|
2566
|
+
const objects = document2.objects.map(cloneWorldOrbitObject);
|
|
2567
|
+
applyEventPoseOverrides(objects, document2.events ?? [], options.activeEventId ?? null);
|
|
2308
2568
|
return {
|
|
2309
2569
|
format: "worldorbit",
|
|
2310
2570
|
version: "1.0",
|
|
2571
|
+
schemaVersion: document2.version,
|
|
2311
2572
|
system,
|
|
2312
|
-
|
|
2573
|
+
groups: structuredClone(document2.groups ?? []),
|
|
2574
|
+
relations: structuredClone(document2.relations ?? []),
|
|
2575
|
+
events: document2.events.map(cloneWorldOrbitEvent),
|
|
2576
|
+
objects
|
|
2313
2577
|
};
|
|
2314
2578
|
}
|
|
2315
2579
|
function cloneWorldOrbitObject(object) {
|
|
2316
2580
|
return {
|
|
2317
2581
|
...object,
|
|
2582
|
+
groups: object.groups ? [...object.groups] : void 0,
|
|
2583
|
+
resonance: object.resonance ? { ...object.resonance } : object.resonance,
|
|
2584
|
+
renderHints: object.renderHints ? { ...object.renderHints } : object.renderHints,
|
|
2585
|
+
deriveRules: object.deriveRules ? object.deriveRules.map((rule) => ({ ...rule })) : void 0,
|
|
2586
|
+
validationRules: object.validationRules ? object.validationRules.map((rule) => ({ ...rule })) : void 0,
|
|
2587
|
+
lockedFields: object.lockedFields ? [...object.lockedFields] : void 0,
|
|
2588
|
+
tolerances: object.tolerances ? object.tolerances.map((entry) => ({
|
|
2589
|
+
field: entry.field,
|
|
2590
|
+
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
|
|
2591
|
+
})) : void 0,
|
|
2592
|
+
typedBlocks: object.typedBlocks ? Object.fromEntries(Object.entries(object.typedBlocks).map(([key, block]) => [key, { ...block ?? {} }])) : void 0,
|
|
2318
2593
|
properties: cloneProperties(object.properties),
|
|
2319
2594
|
placement: object.placement ? structuredClone(object.placement) : null,
|
|
2320
2595
|
info: { ...object.info }
|
|
2321
2596
|
};
|
|
2322
2597
|
}
|
|
2598
|
+
function cloneWorldOrbitEvent(event) {
|
|
2599
|
+
return {
|
|
2600
|
+
...event,
|
|
2601
|
+
participantObjectIds: [...event.participantObjectIds],
|
|
2602
|
+
tags: [...event.tags],
|
|
2603
|
+
positions: event.positions.map(cloneWorldOrbitEventPose)
|
|
2604
|
+
};
|
|
2605
|
+
}
|
|
2606
|
+
function cloneWorldOrbitEventPose(pose) {
|
|
2607
|
+
return {
|
|
2608
|
+
objectId: pose.objectId,
|
|
2609
|
+
placement: clonePlacement(pose.placement),
|
|
2610
|
+
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
2611
|
+
outer: pose.outer ? { ...pose.outer } : void 0
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
function clonePlacement(placement) {
|
|
2615
|
+
return placement ? structuredClone(placement) : null;
|
|
2616
|
+
}
|
|
2617
|
+
function applyEventPoseOverrides(objects, events, activeEventId) {
|
|
2618
|
+
if (!activeEventId) {
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
const event = events.find((entry) => entry.id === activeEventId);
|
|
2622
|
+
if (!event) {
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
const objectMap = new Map(objects.map((object) => [object.id, object]));
|
|
2626
|
+
for (const pose of event.positions) {
|
|
2627
|
+
const object = objectMap.get(pose.objectId);
|
|
2628
|
+
if (!object) {
|
|
2629
|
+
continue;
|
|
2630
|
+
}
|
|
2631
|
+
object.placement = clonePlacement(pose.placement);
|
|
2632
|
+
if (pose.inner) {
|
|
2633
|
+
object.properties.inner = { ...pose.inner };
|
|
2634
|
+
} else {
|
|
2635
|
+
delete object.properties.inner;
|
|
2636
|
+
}
|
|
2637
|
+
if (pose.outer) {
|
|
2638
|
+
object.properties.outer = { ...pose.outer };
|
|
2639
|
+
} else {
|
|
2640
|
+
delete object.properties.outer;
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2323
2644
|
function cloneProperties(properties) {
|
|
2324
2645
|
const next = {};
|
|
2325
2646
|
for (const [key, value] of Object.entries(properties)) {
|
|
@@ -2350,71 +2671,83 @@ var WorldOrbit = (() => {
|
|
|
2350
2671
|
if (system.defaults.units) {
|
|
2351
2672
|
properties.units = system.defaults.units;
|
|
2352
2673
|
}
|
|
2674
|
+
if (system.description) {
|
|
2675
|
+
properties.description = system.description;
|
|
2676
|
+
}
|
|
2677
|
+
if (system.epoch) {
|
|
2678
|
+
properties.epoch = system.epoch;
|
|
2679
|
+
}
|
|
2680
|
+
if (system.referencePlane) {
|
|
2681
|
+
properties.referencePlane = system.referencePlane;
|
|
2682
|
+
}
|
|
2353
2683
|
return properties;
|
|
2354
2684
|
}
|
|
2355
2685
|
function materializeDraftSystemInfo(system) {
|
|
2356
|
-
const
|
|
2686
|
+
const info2 = {
|
|
2357
2687
|
...system.atlasMetadata
|
|
2358
2688
|
};
|
|
2359
2689
|
if (system.defaults.theme) {
|
|
2360
|
-
|
|
2690
|
+
info2["atlas.theme"] = system.defaults.theme;
|
|
2361
2691
|
}
|
|
2362
2692
|
for (const viewpoint of system.viewpoints) {
|
|
2363
2693
|
const prefix = `viewpoint.${viewpoint.id}`;
|
|
2364
|
-
|
|
2694
|
+
info2[`${prefix}.label`] = viewpoint.label;
|
|
2365
2695
|
if (viewpoint.summary) {
|
|
2366
|
-
|
|
2696
|
+
info2[`${prefix}.summary`] = viewpoint.summary;
|
|
2367
2697
|
}
|
|
2368
2698
|
if (viewpoint.focusObjectId) {
|
|
2369
|
-
|
|
2699
|
+
info2[`${prefix}.focus`] = viewpoint.focusObjectId;
|
|
2370
2700
|
}
|
|
2371
2701
|
if (viewpoint.selectedObjectId) {
|
|
2372
|
-
|
|
2702
|
+
info2[`${prefix}.select`] = viewpoint.selectedObjectId;
|
|
2373
2703
|
}
|
|
2374
2704
|
if (viewpoint.projection) {
|
|
2375
|
-
|
|
2705
|
+
info2[`${prefix}.projection`] = viewpoint.projection;
|
|
2376
2706
|
}
|
|
2377
2707
|
if (viewpoint.preset) {
|
|
2378
|
-
|
|
2708
|
+
info2[`${prefix}.preset`] = viewpoint.preset;
|
|
2379
2709
|
}
|
|
2380
2710
|
if (viewpoint.zoom !== null) {
|
|
2381
|
-
|
|
2711
|
+
info2[`${prefix}.zoom`] = String(viewpoint.zoom);
|
|
2382
2712
|
}
|
|
2383
2713
|
if (viewpoint.rotationDeg !== 0) {
|
|
2384
|
-
|
|
2714
|
+
info2[`${prefix}.rotation`] = String(viewpoint.rotationDeg);
|
|
2385
2715
|
}
|
|
2386
2716
|
const serializedLayers = serializeViewpointLayers(viewpoint.layers);
|
|
2387
2717
|
if (serializedLayers) {
|
|
2388
|
-
|
|
2718
|
+
info2[`${prefix}.layers`] = serializedLayers;
|
|
2389
2719
|
}
|
|
2390
2720
|
if (viewpoint.filter?.query) {
|
|
2391
|
-
|
|
2721
|
+
info2[`${prefix}.query`] = viewpoint.filter.query;
|
|
2392
2722
|
}
|
|
2393
2723
|
if ((viewpoint.filter?.objectTypes.length ?? 0) > 0) {
|
|
2394
|
-
|
|
2724
|
+
info2[`${prefix}.types`] = viewpoint.filter?.objectTypes.join(" ") ?? "";
|
|
2395
2725
|
}
|
|
2396
2726
|
if ((viewpoint.filter?.tags.length ?? 0) > 0) {
|
|
2397
|
-
|
|
2727
|
+
info2[`${prefix}.tags`] = viewpoint.filter?.tags.join(" ") ?? "";
|
|
2398
2728
|
}
|
|
2399
2729
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2400
|
-
|
|
2730
|
+
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2731
|
+
}
|
|
2732
|
+
if (viewpoint.events.length > 0) {
|
|
2733
|
+
info2[`${prefix}.events`] = viewpoint.events.join(" ");
|
|
2401
2734
|
}
|
|
2402
2735
|
}
|
|
2403
2736
|
for (const annotation of system.annotations) {
|
|
2404
2737
|
const prefix = `annotation.${annotation.id}`;
|
|
2405
|
-
|
|
2738
|
+
info2[`${prefix}.label`] = annotation.label;
|
|
2406
2739
|
if (annotation.targetObjectId) {
|
|
2407
|
-
|
|
2740
|
+
info2[`${prefix}.target`] = annotation.targetObjectId;
|
|
2408
2741
|
}
|
|
2409
|
-
|
|
2742
|
+
info2[`${prefix}.body`] = annotation.body;
|
|
2410
2743
|
if (annotation.tags.length > 0) {
|
|
2411
|
-
|
|
2744
|
+
info2[`${prefix}.tags`] = annotation.tags.join(" ");
|
|
2412
2745
|
}
|
|
2413
2746
|
if (annotation.sourceObjectId) {
|
|
2414
|
-
|
|
2747
|
+
info2[`${prefix}.source`] = annotation.sourceObjectId;
|
|
2415
2748
|
}
|
|
2416
2749
|
}
|
|
2417
|
-
return
|
|
2750
|
+
return info2;
|
|
2418
2751
|
}
|
|
2419
2752
|
function serializeViewpointLayers(layers) {
|
|
2420
2753
|
const tokens = [];
|
|
@@ -2423,7 +2756,7 @@ var WorldOrbit = (() => {
|
|
|
2423
2756
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2424
2757
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2425
2758
|
}
|
|
2426
|
-
for (const key of ["background", "guides", "objects", "labels", "metadata"]) {
|
|
2759
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
2427
2760
|
if (layers[key] !== void 0) {
|
|
2428
2761
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2429
2762
|
}
|
|
@@ -2431,171 +2764,838 @@ var WorldOrbit = (() => {
|
|
|
2431
2764
|
return tokens.join(" ");
|
|
2432
2765
|
}
|
|
2433
2766
|
|
|
2434
|
-
// packages/core/dist/
|
|
2435
|
-
|
|
2436
|
-
|
|
2767
|
+
// packages/core/dist/atlas-utils.js
|
|
2768
|
+
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)?$/;
|
|
2769
|
+
var BOOLEAN_VALUES2 = /* @__PURE__ */ new Map([
|
|
2770
|
+
["true", true],
|
|
2771
|
+
["false", false],
|
|
2772
|
+
["yes", true],
|
|
2773
|
+
["no", false]
|
|
2774
|
+
]);
|
|
2775
|
+
var URL_SCHEME_PATTERN2 = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
2776
|
+
function normalizeIdentifier(value) {
|
|
2777
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2437
2778
|
}
|
|
2438
|
-
function
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
let sawDefaults = false;
|
|
2446
|
-
let sawAtlas = false;
|
|
2447
|
-
const viewpointIds = /* @__PURE__ */ new Set();
|
|
2448
|
-
const annotationIds = /* @__PURE__ */ new Set();
|
|
2449
|
-
for (let index = 0; index < lines.length; index++) {
|
|
2450
|
-
const rawLine = lines[index];
|
|
2451
|
-
const lineNumber = index + 1;
|
|
2452
|
-
if (!rawLine.trim()) {
|
|
2453
|
-
continue;
|
|
2454
|
-
}
|
|
2455
|
-
const indent = getIndent(rawLine);
|
|
2456
|
-
const tokens = tokenizeLineDetailed(rawLine.slice(indent), {
|
|
2457
|
-
line: lineNumber,
|
|
2458
|
-
columnOffset: indent
|
|
2459
|
-
});
|
|
2460
|
-
if (tokens.length === 0) {
|
|
2461
|
-
continue;
|
|
2462
|
-
}
|
|
2463
|
-
if (!sawSchemaHeader) {
|
|
2464
|
-
schemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
2465
|
-
sawSchemaHeader = true;
|
|
2466
|
-
continue;
|
|
2467
|
-
}
|
|
2468
|
-
if (indent === 0) {
|
|
2469
|
-
section = startTopLevelSection(tokens, lineNumber, system, objectNodes, viewpointIds, annotationIds, {
|
|
2470
|
-
sawDefaults,
|
|
2471
|
-
sawAtlas
|
|
2472
|
-
});
|
|
2473
|
-
if (section.kind === "system") {
|
|
2474
|
-
system = section.system;
|
|
2475
|
-
} else if (section.kind === "defaults") {
|
|
2476
|
-
sawDefaults = true;
|
|
2477
|
-
} else if (section.kind === "atlas") {
|
|
2478
|
-
sawAtlas = true;
|
|
2479
|
-
}
|
|
2480
|
-
continue;
|
|
2481
|
-
}
|
|
2482
|
-
if (!section) {
|
|
2483
|
-
throw new WorldOrbitError("Indented line without parent atlas section", lineNumber, indent + 1);
|
|
2484
|
-
}
|
|
2485
|
-
handleSectionLine(section, indent, tokens, lineNumber);
|
|
2486
|
-
}
|
|
2487
|
-
if (!sawSchemaHeader) {
|
|
2488
|
-
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
2779
|
+
function humanizeIdentifier2(value) {
|
|
2780
|
+
return value.split(/[-_]+/).filter(Boolean).map((segment) => segment[0].toUpperCase() + segment.slice(1)).join(" ");
|
|
2781
|
+
}
|
|
2782
|
+
function parseAtlasUnitValue(input, location, fieldKey) {
|
|
2783
|
+
const match = input.match(UNIT_PATTERN2);
|
|
2784
|
+
if (!match) {
|
|
2785
|
+
throw WorldOrbitError.fromLocation(`Invalid unit value "${input}"`, location);
|
|
2489
2786
|
}
|
|
2490
|
-
const
|
|
2491
|
-
|
|
2492
|
-
|
|
2787
|
+
const unitValue = {
|
|
2788
|
+
value: Number(match[1]),
|
|
2789
|
+
unit: match[2] ?? null
|
|
2493
2790
|
};
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
system: null,
|
|
2499
|
-
objects: normalizedObjects
|
|
2500
|
-
});
|
|
2501
|
-
const diagnostics = schemaVersion === "2.0-draft" && outputVersion === "2.0" ? [
|
|
2502
|
-
{
|
|
2503
|
-
code: "load.schema.deprecatedDraft",
|
|
2504
|
-
severity: "warning",
|
|
2505
|
-
source: "upgrade",
|
|
2506
|
-
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
2791
|
+
if (fieldKey) {
|
|
2792
|
+
const schema = getFieldSchema(fieldKey);
|
|
2793
|
+
if (schema?.unitFamily && !unitFamilyAllowsUnit(schema.unitFamily, unitValue.unit)) {
|
|
2794
|
+
throw WorldOrbitError.fromLocation(`Unit "${unitValue.unit ?? "none"}" is not valid for "${fieldKey}"`, location);
|
|
2507
2795
|
}
|
|
2508
|
-
|
|
2796
|
+
}
|
|
2797
|
+
return unitValue;
|
|
2798
|
+
}
|
|
2799
|
+
function tryParseAtlasUnitValue(input) {
|
|
2800
|
+
const match = input.match(UNIT_PATTERN2);
|
|
2801
|
+
if (!match) {
|
|
2802
|
+
return null;
|
|
2803
|
+
}
|
|
2509
2804
|
return {
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
sourceVersion: "1.0",
|
|
2513
|
-
system,
|
|
2514
|
-
objects: normalizedObjects,
|
|
2515
|
-
diagnostics
|
|
2805
|
+
value: Number(match[1]),
|
|
2806
|
+
unit: match[2] ?? null
|
|
2516
2807
|
};
|
|
2517
2808
|
}
|
|
2518
|
-
function
|
|
2519
|
-
|
|
2520
|
-
|
|
2809
|
+
function parseAtlasNumber(input, key, location) {
|
|
2810
|
+
const value = Number(input);
|
|
2811
|
+
if (!Number.isFinite(value)) {
|
|
2812
|
+
throw WorldOrbitError.fromLocation(`Invalid numeric value "${input}" for "${key}"`, location);
|
|
2521
2813
|
}
|
|
2522
|
-
return
|
|
2814
|
+
return value;
|
|
2523
2815
|
}
|
|
2524
|
-
function
|
|
2525
|
-
const
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
if (system) {
|
|
2529
|
-
throw new WorldOrbitError('Atlas section "system" may only appear once', line, tokens[0].column);
|
|
2530
|
-
}
|
|
2531
|
-
return startSystemSection(tokens, line);
|
|
2532
|
-
case "defaults":
|
|
2533
|
-
if (!system) {
|
|
2534
|
-
throw new WorldOrbitError('Atlas section "defaults" requires a preceding system declaration', line, tokens[0].column);
|
|
2535
|
-
}
|
|
2536
|
-
if (flags.sawDefaults) {
|
|
2537
|
-
throw new WorldOrbitError('Atlas section "defaults" may only appear once', line, tokens[0].column);
|
|
2538
|
-
}
|
|
2539
|
-
return {
|
|
2540
|
-
kind: "defaults",
|
|
2541
|
-
system,
|
|
2542
|
-
seenFields: /* @__PURE__ */ new Set()
|
|
2543
|
-
};
|
|
2544
|
-
case "atlas":
|
|
2545
|
-
if (!system) {
|
|
2546
|
-
throw new WorldOrbitError('Atlas section "atlas" requires a preceding system declaration', line, tokens[0].column);
|
|
2547
|
-
}
|
|
2548
|
-
if (flags.sawAtlas) {
|
|
2549
|
-
throw new WorldOrbitError('Atlas section "atlas" may only appear once', line, tokens[0].column);
|
|
2550
|
-
}
|
|
2551
|
-
return {
|
|
2552
|
-
kind: "atlas",
|
|
2553
|
-
system,
|
|
2554
|
-
inMetadata: false,
|
|
2555
|
-
metadataIndent: null
|
|
2556
|
-
};
|
|
2557
|
-
case "viewpoint":
|
|
2558
|
-
if (!system) {
|
|
2559
|
-
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
2560
|
-
}
|
|
2561
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
2562
|
-
case "annotation":
|
|
2563
|
-
if (!system) {
|
|
2564
|
-
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
2565
|
-
}
|
|
2566
|
-
return startAnnotationSection(tokens, line, system, annotationIds);
|
|
2567
|
-
case "object":
|
|
2568
|
-
return startObjectSection(tokens, line, objectNodes);
|
|
2569
|
-
default:
|
|
2570
|
-
throw new WorldOrbitError(`Unknown atlas section "${tokens[0]?.value ?? ""}"`, line, tokens[0]?.column ?? 1);
|
|
2816
|
+
function parseAtlasBoolean(input, key, location) {
|
|
2817
|
+
const parsed = BOOLEAN_VALUES2.get(input.toLowerCase());
|
|
2818
|
+
if (parsed === void 0) {
|
|
2819
|
+
throw WorldOrbitError.fromLocation(`Invalid boolean value "${input}" for "${key}"`, location);
|
|
2571
2820
|
}
|
|
2821
|
+
return parsed;
|
|
2572
2822
|
}
|
|
2573
|
-
function
|
|
2574
|
-
if (
|
|
2575
|
-
throw
|
|
2823
|
+
function parseAtlasAtReference(target, location) {
|
|
2824
|
+
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
2825
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
2576
2826
|
}
|
|
2577
|
-
const
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2827
|
+
const pairedMatch = target.match(/^([A-Za-z0-9._-]+)-([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
2828
|
+
if (pairedMatch) {
|
|
2829
|
+
return {
|
|
2830
|
+
kind: "lagrange",
|
|
2831
|
+
primary: pairedMatch[1],
|
|
2832
|
+
secondary: pairedMatch[2],
|
|
2833
|
+
point: pairedMatch[3]
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
const simpleMatch = target.match(/^([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
2837
|
+
if (simpleMatch) {
|
|
2838
|
+
return {
|
|
2839
|
+
kind: "lagrange",
|
|
2840
|
+
primary: simpleMatch[1],
|
|
2841
|
+
secondary: null,
|
|
2842
|
+
point: simpleMatch[2]
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
if (/^[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
2846
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
2847
|
+
}
|
|
2848
|
+
const anchorMatch = target.match(/^([A-Za-z0-9._-]+):([A-Za-z0-9._-]+)$/);
|
|
2849
|
+
if (anchorMatch) {
|
|
2850
|
+
return {
|
|
2851
|
+
kind: "anchor",
|
|
2852
|
+
objectId: anchorMatch[1],
|
|
2853
|
+
anchor: anchorMatch[2]
|
|
2854
|
+
};
|
|
2855
|
+
}
|
|
2856
|
+
return {
|
|
2857
|
+
kind: "named",
|
|
2858
|
+
name: target
|
|
2859
|
+
};
|
|
2860
|
+
}
|
|
2861
|
+
function validateAtlasImageSource(value, location) {
|
|
2862
|
+
if (!value) {
|
|
2863
|
+
throw WorldOrbitError.fromLocation('Field "image" must not be empty', location);
|
|
2864
|
+
}
|
|
2865
|
+
if (value.startsWith("//")) {
|
|
2866
|
+
throw WorldOrbitError.fromLocation('Field "image" must use a relative path, root-relative path, or an http/https URL', location);
|
|
2867
|
+
}
|
|
2868
|
+
const schemeMatch = value.match(URL_SCHEME_PATTERN2);
|
|
2869
|
+
if (!schemeMatch) {
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
const scheme = schemeMatch[0].slice(0, -1).toLowerCase();
|
|
2873
|
+
if (scheme !== "http" && scheme !== "https") {
|
|
2874
|
+
throw WorldOrbitError.fromLocation(`Field "image" does not support the "${scheme}" scheme`, location);
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
function normalizeLegacyScalarValue(key, values, location) {
|
|
2878
|
+
const schema = getFieldSchema(key);
|
|
2879
|
+
if (!schema) {
|
|
2880
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
2881
|
+
}
|
|
2882
|
+
if (schema.arity === "single" && values.length !== 1) {
|
|
2883
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
2884
|
+
}
|
|
2885
|
+
switch (schema.kind) {
|
|
2886
|
+
case "list":
|
|
2887
|
+
return values;
|
|
2888
|
+
case "boolean":
|
|
2889
|
+
return parseAtlasBoolean(singleAtlasValue(values, key, location), key, location);
|
|
2890
|
+
case "number":
|
|
2891
|
+
return parseAtlasNumber(singleAtlasValue(values, key, location), key, location);
|
|
2892
|
+
case "unit":
|
|
2893
|
+
return parseAtlasUnitValue(singleAtlasValue(values, key, location), location, key);
|
|
2894
|
+
case "string": {
|
|
2895
|
+
const value = values.join(" ").trim();
|
|
2896
|
+
if (key === "image") {
|
|
2897
|
+
validateAtlasImageSource(value, location);
|
|
2898
|
+
}
|
|
2899
|
+
return value;
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
function ensureAtlasFieldSupported(key, objectType, location) {
|
|
2904
|
+
const schema = getFieldSchema(key);
|
|
2905
|
+
if (!schema) {
|
|
2906
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
2907
|
+
}
|
|
2908
|
+
if (!schema.objectTypes.includes(objectType)) {
|
|
2909
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" is not valid on "${objectType}"`, location);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
function singleAtlasValue(values, key, location) {
|
|
2913
|
+
if (values.length !== 1) {
|
|
2914
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
2915
|
+
}
|
|
2916
|
+
return values[0];
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
// packages/core/dist/atlas-validate.js
|
|
2920
|
+
var SURFACE_TARGET_TYPES2 = /* @__PURE__ */ new Set(["star", "planet", "moon", "asteroid", "comet"]);
|
|
2921
|
+
var EARTH_MASSES_PER_SOLAR = 332946.0487;
|
|
2922
|
+
var JUPITER_MASSES_PER_SOLAR = 1047.3486;
|
|
2923
|
+
var AU_IN_KM2 = 1495978707e-1;
|
|
2924
|
+
var EARTH_RADIUS_IN_KM2 = 6371;
|
|
2925
|
+
var SOLAR_RADIUS_IN_KM2 = 695700;
|
|
2926
|
+
var LY_IN_AU2 = 63241.077;
|
|
2927
|
+
var PC_IN_AU2 = 206264.806;
|
|
2928
|
+
var KPC_IN_AU2 = 206264806;
|
|
2929
|
+
function collectAtlasDiagnostics(document2, sourceSchemaVersion) {
|
|
2930
|
+
const diagnostics = [];
|
|
2931
|
+
const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
|
|
2932
|
+
const groupIds = new Set(document2.groups.map((group) => group.id));
|
|
2933
|
+
const eventIds = new Set(document2.events.map((event) => event.id));
|
|
2934
|
+
if (!document2.system) {
|
|
2935
|
+
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
2936
|
+
}
|
|
2937
|
+
const knownIds = /* @__PURE__ */ new Map();
|
|
2938
|
+
for (const [kind, ids] of [
|
|
2939
|
+
["group", document2.groups.map((group) => group.id)],
|
|
2940
|
+
["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
2941
|
+
["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
2942
|
+
["relation", document2.relations.map((relation) => relation.id)],
|
|
2943
|
+
["event", document2.events.map((event) => event.id)],
|
|
2944
|
+
["object", document2.objects.map((object) => object.id)]
|
|
2945
|
+
]) {
|
|
2946
|
+
for (const id of ids) {
|
|
2947
|
+
const previous = knownIds.get(id);
|
|
2948
|
+
if (previous) {
|
|
2949
|
+
diagnostics.push(error("validate.id.duplicate", `Duplicate ${kind} id "${id}" already used by ${previous}.`));
|
|
2950
|
+
} else {
|
|
2951
|
+
knownIds.set(id, kind);
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
for (const relation of document2.relations) {
|
|
2956
|
+
validateRelation(relation, objectMap, diagnostics);
|
|
2957
|
+
}
|
|
2958
|
+
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
2959
|
+
validateViewpoint(viewpoint.filter, viewpoint.events ?? [], groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpoint.id);
|
|
2960
|
+
}
|
|
2961
|
+
for (const object of document2.objects) {
|
|
2962
|
+
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
2963
|
+
}
|
|
2964
|
+
for (const event of document2.events) {
|
|
2965
|
+
validateEvent(event, objectMap, diagnostics);
|
|
2966
|
+
}
|
|
2967
|
+
return diagnostics;
|
|
2968
|
+
}
|
|
2969
|
+
function validateRelation(relation, objectMap, diagnostics) {
|
|
2970
|
+
if (!relation.from) {
|
|
2971
|
+
diagnostics.push(error("validate.relation.from.required", `Relation "${relation.id}" is missing a "from" target.`));
|
|
2972
|
+
} else if (!objectMap.has(relation.from)) {
|
|
2973
|
+
diagnostics.push(error("validate.relation.from.unknown", `Unknown relation source "${relation.from}" on "${relation.id}".`));
|
|
2974
|
+
}
|
|
2975
|
+
if (!relation.to) {
|
|
2976
|
+
diagnostics.push(error("validate.relation.to.required", `Relation "${relation.id}" is missing a "to" target.`));
|
|
2977
|
+
} else if (!objectMap.has(relation.to)) {
|
|
2978
|
+
diagnostics.push(error("validate.relation.to.unknown", `Unknown relation target "${relation.to}" on "${relation.id}".`));
|
|
2979
|
+
}
|
|
2980
|
+
if (!relation.kind) {
|
|
2981
|
+
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
function validateViewpoint(filter, eventRefs, groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpointId) {
|
|
2985
|
+
if (sourceSchemaVersion === "2.1") {
|
|
2986
|
+
if (filter) {
|
|
2987
|
+
for (const groupId of filter.groupIds) {
|
|
2988
|
+
if (!groupIds.has(groupId)) {
|
|
2989
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.groups`));
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
for (const eventId of eventRefs) {
|
|
2994
|
+
if (!eventIds.has(eventId)) {
|
|
2995
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.events`));
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
function validateObject(object, system, objectMap, groupIds, diagnostics) {
|
|
3001
|
+
const placement = object.placement;
|
|
3002
|
+
const orbitPlacement = placement?.mode === "orbit" ? placement : null;
|
|
3003
|
+
const parentObject = placement?.mode === "orbit" ? objectMap.get(placement.target) ?? null : null;
|
|
3004
|
+
if (object.groups) {
|
|
3005
|
+
for (const groupId of object.groups) {
|
|
3006
|
+
if (!groupIds.has(groupId)) {
|
|
3007
|
+
diagnostics.push(warn("validate.group.unknown", `Unknown group "${groupId}" on "${object.id}".`, object.id, "groups"));
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
if (orbitPlacement) {
|
|
3012
|
+
if (!objectMap.has(orbitPlacement.target)) {
|
|
3013
|
+
diagnostics.push(error("validate.orbit.target.unknown", `Unknown placement target "${orbitPlacement.target}" on "${object.id}".`, object.id, "orbit"));
|
|
3014
|
+
}
|
|
3015
|
+
if (orbitPlacement.distance && orbitPlacement.semiMajor) {
|
|
3016
|
+
diagnostics.push(error("validate.orbit.distanceConflict", `Object "${object.id}" cannot declare both "distance" and "semiMajor".`, object.id, "distance"));
|
|
3017
|
+
}
|
|
3018
|
+
if (orbitPlacement.phase && !object.epoch && !system?.epoch) {
|
|
3019
|
+
diagnostics.push(warn("validate.phase.epochMissing", `Object "${object.id}" sets "phase" without an object or system epoch.`, object.id, "phase"));
|
|
3020
|
+
}
|
|
3021
|
+
if (orbitPlacement.inclination && !object.referencePlane && !system?.referencePlane) {
|
|
3022
|
+
diagnostics.push(warn("validate.inclination.referencePlaneMissing", `Object "${object.id}" sets "inclination" without an object or system reference plane.`, object.id, "inclination"));
|
|
3023
|
+
}
|
|
3024
|
+
if (orbitPlacement.period && !massInSolar(parentObject?.properties.mass)) {
|
|
3025
|
+
diagnostics.push(warn("validate.period.massMissing", `Object "${object.id}" sets "period" but its central mass cannot be derived.`, object.id, "period"));
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
if (placement?.mode === "surface") {
|
|
3029
|
+
const target = objectMap.get(placement.target);
|
|
3030
|
+
if (!target) {
|
|
3031
|
+
diagnostics.push(error("validate.surface.target.unknown", `Unknown placement target "${placement.target}" on "${object.id}".`, object.id, "surface"));
|
|
3032
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3033
|
+
diagnostics.push(error("validate.surface.target.invalid", `Surface target "${placement.target}" on "${object.id}" is not surface-capable.`, object.id, "surface"));
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
if (placement?.mode === "at") {
|
|
3037
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3038
|
+
diagnostics.push(error("validate.at.objectType", `Only structures and phenomena may use "at" placement; found "${object.type}" on "${object.id}".`, object.id, "at"));
|
|
3039
|
+
}
|
|
3040
|
+
if (!validateAtTarget(object, objectMap, diagnostics)) {
|
|
3041
|
+
diagnostics.push(error("validate.at.target.unknown", `Unknown at-reference target "${placement.target}" on "${object.id}".`, object.id, "at"));
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
if (object.resonance) {
|
|
3045
|
+
const target = objectMap.get(object.resonance.targetObjectId);
|
|
3046
|
+
if (!target) {
|
|
3047
|
+
diagnostics.push(error("validate.resonance.target.unknown", `Unknown resonance target "${object.resonance.targetObjectId}" on "${object.id}".`, object.id, "resonance"));
|
|
3048
|
+
} else if (object.placement?.mode !== "orbit" || target.placement?.mode !== "orbit" || object.placement.target !== target.placement.target) {
|
|
3049
|
+
diagnostics.push(warn("validate.resonance.orbitMismatch", `Resonance target "${object.resonance.targetObjectId}" on "${object.id}" does not share a compatible orbital parent.`, object.id, "resonance"));
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
for (const rule of object.deriveRules ?? []) {
|
|
3053
|
+
if (rule.field !== "period" || rule.strategy !== "kepler") {
|
|
3054
|
+
diagnostics.push(warn("validate.derive.unsupported", `Unsupported derive rule "${rule.field} ${rule.strategy}" on "${object.id}".`, object.id, "derive"));
|
|
3055
|
+
continue;
|
|
3056
|
+
}
|
|
3057
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3058
|
+
if (derivedPeriodDays === null) {
|
|
3059
|
+
diagnostics.push(warn("validate.derive.inputsMissing", `Object "${object.id}" requests "derive period kepler" but lacks enough input data.`, object.id, "derive"));
|
|
3060
|
+
continue;
|
|
3061
|
+
}
|
|
3062
|
+
if (!orbitPlacement?.period) {
|
|
3063
|
+
diagnostics.push(info("validate.derive.period.available", `Object "${object.id}" can derive a Kepler period of ${formatDays(derivedPeriodDays)}.`, object.id, "derive"));
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
for (const rule of object.validationRules ?? []) {
|
|
3067
|
+
if (rule.rule !== "kepler") {
|
|
3068
|
+
diagnostics.push(warn("validate.rule.unsupported", `Unsupported validation rule "${rule.rule}" on "${object.id}".`, object.id, "validate"));
|
|
3069
|
+
continue;
|
|
3070
|
+
}
|
|
3071
|
+
const actualPeriodDays = durationInDays(orbitPlacement?.period);
|
|
3072
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3073
|
+
if (actualPeriodDays === null || derivedPeriodDays === null) {
|
|
3074
|
+
continue;
|
|
3075
|
+
}
|
|
3076
|
+
const toleranceDays = toleranceForField(object, "period");
|
|
3077
|
+
if (Math.abs(actualPeriodDays - derivedPeriodDays) > toleranceDays) {
|
|
3078
|
+
diagnostics.push(error("validate.kepler.mismatch", `Object "${object.id}" fails Kepler validation for "period".`, object.id, "validate"));
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
function validateEvent(event, objectMap, diagnostics) {
|
|
3083
|
+
const fieldPrefix = `event.${event.id}`;
|
|
3084
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
3085
|
+
if (!event.kind.trim()) {
|
|
3086
|
+
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
3087
|
+
}
|
|
3088
|
+
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3089
|
+
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3090
|
+
}
|
|
3091
|
+
if (event.targetObjectId) {
|
|
3092
|
+
referencedIds.add(event.targetObjectId);
|
|
3093
|
+
if (!objectMap.has(event.targetObjectId)) {
|
|
3094
|
+
diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
const seenParticipants = /* @__PURE__ */ new Set();
|
|
3098
|
+
for (const participantId of event.participantObjectIds) {
|
|
3099
|
+
referencedIds.add(participantId);
|
|
3100
|
+
if (seenParticipants.has(participantId)) {
|
|
3101
|
+
diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
|
|
3102
|
+
continue;
|
|
3103
|
+
}
|
|
3104
|
+
seenParticipants.add(participantId);
|
|
3105
|
+
if (!objectMap.has(participantId)) {
|
|
3106
|
+
diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
|
|
3110
|
+
diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
|
|
3111
|
+
}
|
|
3112
|
+
if (event.positions.length === 0) {
|
|
3113
|
+
diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
|
|
3114
|
+
}
|
|
3115
|
+
if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
|
|
3116
|
+
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`));
|
|
3117
|
+
}
|
|
3118
|
+
const poseIds = /* @__PURE__ */ new Set();
|
|
3119
|
+
for (const pose of event.positions) {
|
|
3120
|
+
const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
|
|
3121
|
+
if (poseIds.has(pose.objectId)) {
|
|
3122
|
+
diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
|
|
3123
|
+
continue;
|
|
3124
|
+
}
|
|
3125
|
+
poseIds.add(pose.objectId);
|
|
3126
|
+
const object = objectMap.get(pose.objectId);
|
|
3127
|
+
if (!object) {
|
|
3128
|
+
diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
|
|
3129
|
+
continue;
|
|
3130
|
+
}
|
|
3131
|
+
if (!referencedIds.has(pose.objectId)) {
|
|
3132
|
+
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
3133
|
+
}
|
|
3134
|
+
validateEventPose(pose, object, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
function validateEventPose(pose, object, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3138
|
+
const placement = pose.placement;
|
|
3139
|
+
if (!placement) {
|
|
3140
|
+
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
3143
|
+
if (placement.mode === "orbit") {
|
|
3144
|
+
if (!objectMap.has(placement.target)) {
|
|
3145
|
+
diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
|
|
3146
|
+
}
|
|
3147
|
+
if (placement.distance && placement.semiMajor) {
|
|
3148
|
+
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
3149
|
+
}
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
if (placement.mode === "surface") {
|
|
3153
|
+
const target = objectMap.get(placement.target);
|
|
3154
|
+
if (!target) {
|
|
3155
|
+
diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
|
|
3156
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3157
|
+
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`));
|
|
3158
|
+
}
|
|
3159
|
+
return;
|
|
3160
|
+
}
|
|
3161
|
+
if (placement.mode === "at") {
|
|
3162
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3163
|
+
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`));
|
|
3164
|
+
}
|
|
3165
|
+
const reference = placement.reference;
|
|
3166
|
+
if (reference.kind === "named" && !objectMap.has(reference.name)) {
|
|
3167
|
+
diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3168
|
+
} else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
|
|
3169
|
+
diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3170
|
+
} else if (reference.kind === "lagrange") {
|
|
3171
|
+
if (!objectMap.has(reference.primary)) {
|
|
3172
|
+
diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3173
|
+
} else if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3174
|
+
diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
function validateAtTarget(object, objectMap, diagnostics) {
|
|
3180
|
+
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
3181
|
+
if (!reference) {
|
|
3182
|
+
return true;
|
|
3183
|
+
}
|
|
3184
|
+
if (reference.kind === "named") {
|
|
3185
|
+
return objectMap.has(reference.name);
|
|
3186
|
+
}
|
|
3187
|
+
if (reference.kind === "anchor") {
|
|
3188
|
+
if (!objectMap.has(reference.objectId)) {
|
|
3189
|
+
diagnostics.push(error("validate.anchor.target.unknown", `Unknown anchor target "${reference.objectId}" on "${object.id}".`, object.id, "at"));
|
|
3190
|
+
return false;
|
|
3191
|
+
}
|
|
3192
|
+
return true;
|
|
3193
|
+
}
|
|
3194
|
+
if (!objectMap.has(reference.primary)) {
|
|
3195
|
+
diagnostics.push(error("validate.lagrange.primary.unknown", `Unknown Lagrange reference "${reference.primary}" on "${object.id}".`, object.id, "at"));
|
|
3196
|
+
return false;
|
|
3197
|
+
}
|
|
3198
|
+
if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3199
|
+
diagnostics.push(error("validate.lagrange.secondary.unknown", `Unknown Lagrange reference "${reference.secondary}" on "${object.id}".`, object.id, "at"));
|
|
3200
|
+
return false;
|
|
3201
|
+
}
|
|
3202
|
+
return true;
|
|
3203
|
+
}
|
|
3204
|
+
function keplerPeriodDays(object, parentObject) {
|
|
3205
|
+
const placement = object.placement;
|
|
3206
|
+
if (!placement || placement.mode !== "orbit") {
|
|
3207
|
+
return null;
|
|
3208
|
+
}
|
|
3209
|
+
const semiMajorAu = distanceInAu(placement.semiMajor ?? placement.distance);
|
|
3210
|
+
const centralMassSolar = massInSolar(parentObject?.properties.mass);
|
|
3211
|
+
if (semiMajorAu === null || centralMassSolar === null || centralMassSolar <= 0) {
|
|
3212
|
+
return null;
|
|
3213
|
+
}
|
|
3214
|
+
const periodYears = Math.sqrt(semiMajorAu ** 3 / centralMassSolar);
|
|
3215
|
+
return periodYears * 365.25;
|
|
3216
|
+
}
|
|
3217
|
+
function distanceInAu(value) {
|
|
3218
|
+
if (!value)
|
|
3219
|
+
return null;
|
|
3220
|
+
switch (value.unit) {
|
|
3221
|
+
case null:
|
|
3222
|
+
case "au":
|
|
3223
|
+
return value.value;
|
|
3224
|
+
case "km":
|
|
3225
|
+
return value.value / AU_IN_KM2;
|
|
3226
|
+
case "m":
|
|
3227
|
+
return value.value / (AU_IN_KM2 * 1e3);
|
|
3228
|
+
case "ly":
|
|
3229
|
+
return value.value * LY_IN_AU2;
|
|
3230
|
+
case "pc":
|
|
3231
|
+
return value.value * PC_IN_AU2;
|
|
3232
|
+
case "kpc":
|
|
3233
|
+
return value.value * KPC_IN_AU2;
|
|
3234
|
+
case "re":
|
|
3235
|
+
return value.value * EARTH_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
3236
|
+
case "sol":
|
|
3237
|
+
return value.value * SOLAR_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
3238
|
+
default:
|
|
3239
|
+
return null;
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
function massInSolar(value) {
|
|
3243
|
+
if (!value || typeof value !== "object" || !("value" in value)) {
|
|
3244
|
+
return null;
|
|
3245
|
+
}
|
|
3246
|
+
const unitValue = value;
|
|
3247
|
+
switch (unitValue.unit) {
|
|
3248
|
+
case null:
|
|
3249
|
+
case "sol":
|
|
3250
|
+
return unitValue.value;
|
|
3251
|
+
case "me":
|
|
3252
|
+
return unitValue.value / EARTH_MASSES_PER_SOLAR;
|
|
3253
|
+
case "mj":
|
|
3254
|
+
return unitValue.value / JUPITER_MASSES_PER_SOLAR;
|
|
3255
|
+
default:
|
|
3256
|
+
return null;
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
function durationInDays(value) {
|
|
3260
|
+
if (!value)
|
|
3261
|
+
return null;
|
|
3262
|
+
switch (value.unit) {
|
|
3263
|
+
case null:
|
|
3264
|
+
case "d":
|
|
3265
|
+
return value.value;
|
|
3266
|
+
case "s":
|
|
3267
|
+
return value.value / 86400;
|
|
3268
|
+
case "min":
|
|
3269
|
+
return value.value / 1440;
|
|
3270
|
+
case "h":
|
|
3271
|
+
return value.value / 24;
|
|
3272
|
+
case "y":
|
|
3273
|
+
return value.value * 365.25;
|
|
3274
|
+
case "ky":
|
|
3275
|
+
return value.value * 365250;
|
|
3276
|
+
case "my":
|
|
3277
|
+
return value.value * 36525e4;
|
|
3278
|
+
case "gy":
|
|
3279
|
+
return value.value * 36525e7;
|
|
3280
|
+
default:
|
|
3281
|
+
return null;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
function toleranceForField(object, field) {
|
|
3285
|
+
const tolerance = object.tolerances?.find((entry) => entry.field === field)?.value;
|
|
3286
|
+
if (typeof tolerance === "number") {
|
|
3287
|
+
return tolerance;
|
|
3288
|
+
}
|
|
3289
|
+
if (tolerance && typeof tolerance === "object" && "value" in tolerance) {
|
|
3290
|
+
return durationInDays(tolerance) ?? 0;
|
|
3291
|
+
}
|
|
3292
|
+
return 0;
|
|
3293
|
+
}
|
|
3294
|
+
function formatDays(days) {
|
|
3295
|
+
return `${Math.round(days * 100) / 100}d`;
|
|
3296
|
+
}
|
|
3297
|
+
function error(code, message, objectId, field) {
|
|
3298
|
+
return { code, severity: "error", source: "validate", message, objectId, field };
|
|
3299
|
+
}
|
|
3300
|
+
function warn(code, message, objectId, field) {
|
|
3301
|
+
return { code, severity: "warning", source: "validate", message, objectId, field };
|
|
3302
|
+
}
|
|
3303
|
+
function info(code, message, objectId, field) {
|
|
3304
|
+
return { code, severity: "info", source: "validate", message, objectId, field };
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3307
|
+
// packages/core/dist/draft-parse.js
|
|
3308
|
+
var STRUCTURED_TYPED_BLOCKS = /* @__PURE__ */ new Set([
|
|
3309
|
+
"climate",
|
|
3310
|
+
"habitability",
|
|
3311
|
+
"settlement"
|
|
3312
|
+
]);
|
|
3313
|
+
var DRAFT_OBJECT_FIELD_SPECS = /* @__PURE__ */ new Map();
|
|
3314
|
+
for (const key of [
|
|
3315
|
+
"orbit",
|
|
3316
|
+
"distance",
|
|
3317
|
+
"semiMajor",
|
|
3318
|
+
"eccentricity",
|
|
3319
|
+
"period",
|
|
3320
|
+
"angle",
|
|
3321
|
+
"inclination",
|
|
3322
|
+
"phase",
|
|
3323
|
+
"at",
|
|
3324
|
+
"surface",
|
|
3325
|
+
"free",
|
|
3326
|
+
"kind",
|
|
3327
|
+
"class",
|
|
3328
|
+
"culture",
|
|
3329
|
+
"tags",
|
|
3330
|
+
"color",
|
|
3331
|
+
"image",
|
|
3332
|
+
"hidden",
|
|
3333
|
+
"radius",
|
|
3334
|
+
"mass",
|
|
3335
|
+
"density",
|
|
3336
|
+
"gravity",
|
|
3337
|
+
"temperature",
|
|
3338
|
+
"albedo",
|
|
3339
|
+
"atmosphere",
|
|
3340
|
+
"inner",
|
|
3341
|
+
"outer",
|
|
3342
|
+
"on",
|
|
3343
|
+
"source",
|
|
3344
|
+
"cycle"
|
|
3345
|
+
]) {
|
|
3346
|
+
const schema = getFieldSchema(key);
|
|
3347
|
+
if (schema) {
|
|
3348
|
+
DRAFT_OBJECT_FIELD_SPECS.set(key, {
|
|
3349
|
+
key,
|
|
3350
|
+
version: "2.0",
|
|
3351
|
+
inlineMode: schema.arity === "multiple" ? "multiple" : "single",
|
|
3352
|
+
allowRepeat: false,
|
|
3353
|
+
legacySchema: schema
|
|
3354
|
+
});
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
for (const spec of [
|
|
3358
|
+
{ key: "groups", inlineMode: "multiple", allowRepeat: false },
|
|
3359
|
+
{ key: "epoch", inlineMode: "single", allowRepeat: false },
|
|
3360
|
+
{ key: "referencePlane", inlineMode: "single", allowRepeat: false },
|
|
3361
|
+
{ key: "tidalLock", inlineMode: "single", allowRepeat: false },
|
|
3362
|
+
{ key: "renderLabel", inlineMode: "single", allowRepeat: false },
|
|
3363
|
+
{ key: "renderOrbit", inlineMode: "single", allowRepeat: false },
|
|
3364
|
+
{ key: "renderPriority", inlineMode: "single", allowRepeat: false },
|
|
3365
|
+
{ key: "resonance", inlineMode: "pair", allowRepeat: false },
|
|
3366
|
+
{ key: "derive", inlineMode: "pair", allowRepeat: true },
|
|
3367
|
+
{ key: "validate", inlineMode: "single", allowRepeat: true },
|
|
3368
|
+
{ key: "locked", inlineMode: "multiple", allowRepeat: false },
|
|
3369
|
+
{ key: "tolerance", inlineMode: "pair", allowRepeat: true }
|
|
3370
|
+
]) {
|
|
3371
|
+
DRAFT_OBJECT_FIELD_SPECS.set(spec.key, {
|
|
3372
|
+
key: spec.key,
|
|
3373
|
+
version: "2.1",
|
|
3374
|
+
inlineMode: spec.inlineMode,
|
|
3375
|
+
allowRepeat: spec.allowRepeat
|
|
3376
|
+
});
|
|
3377
|
+
}
|
|
3378
|
+
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
3379
|
+
var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
3380
|
+
"orbit",
|
|
3381
|
+
"distance",
|
|
3382
|
+
"semiMajor",
|
|
3383
|
+
"eccentricity",
|
|
3384
|
+
"period",
|
|
3385
|
+
"angle",
|
|
3386
|
+
"inclination",
|
|
3387
|
+
"phase",
|
|
3388
|
+
"at",
|
|
3389
|
+
"surface",
|
|
3390
|
+
"free",
|
|
3391
|
+
"inner",
|
|
3392
|
+
"outer"
|
|
3393
|
+
]);
|
|
3394
|
+
function parseWorldOrbitAtlas(source) {
|
|
3395
|
+
return parseAtlasSource(source);
|
|
3396
|
+
}
|
|
3397
|
+
function parseAtlasSource(source, forcedOutputVersion) {
|
|
3398
|
+
const prepared = preprocessAtlasSource(source);
|
|
3399
|
+
const lines = prepared.source.split(/\r?\n/);
|
|
3400
|
+
const diagnostics = [];
|
|
3401
|
+
let sawSchemaHeader = false;
|
|
3402
|
+
let sourceSchemaVersion = "2.0";
|
|
3403
|
+
let system = null;
|
|
3404
|
+
let section = null;
|
|
3405
|
+
const objectNodes = [];
|
|
3406
|
+
const groups = [];
|
|
3407
|
+
const relations = [];
|
|
3408
|
+
const events = [];
|
|
3409
|
+
const eventPoseNodes = /* @__PURE__ */ new Map();
|
|
3410
|
+
let sawDefaults = false;
|
|
3411
|
+
let sawAtlas = false;
|
|
3412
|
+
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3413
|
+
const annotationIds = /* @__PURE__ */ new Set();
|
|
3414
|
+
const groupIds = /* @__PURE__ */ new Set();
|
|
3415
|
+
const relationIds = /* @__PURE__ */ new Set();
|
|
3416
|
+
const eventIds = /* @__PURE__ */ new Set();
|
|
3417
|
+
for (let index = 0; index < lines.length; index++) {
|
|
3418
|
+
const rawLine = lines[index];
|
|
3419
|
+
const lineNumber = index + 1;
|
|
3420
|
+
if (!rawLine.trim()) {
|
|
3421
|
+
continue;
|
|
3422
|
+
}
|
|
3423
|
+
const indent = getIndent(rawLine);
|
|
3424
|
+
const tokens = tokenizeLineDetailed(rawLine.slice(indent), {
|
|
3425
|
+
line: lineNumber,
|
|
3426
|
+
columnOffset: indent
|
|
3427
|
+
});
|
|
3428
|
+
if (tokens.length === 0) {
|
|
3429
|
+
continue;
|
|
3430
|
+
}
|
|
3431
|
+
if (!sawSchemaHeader) {
|
|
3432
|
+
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
3433
|
+
sawSchemaHeader = true;
|
|
3434
|
+
if (prepared.comments.length > 0 && sourceSchemaVersion !== "2.1") {
|
|
3435
|
+
diagnostics.push({
|
|
3436
|
+
code: "parse.schema21.commentCompatibility",
|
|
3437
|
+
severity: "warning",
|
|
3438
|
+
source: "parse",
|
|
3439
|
+
message: `Comments require schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
3440
|
+
line: prepared.comments[0].line,
|
|
3441
|
+
column: prepared.comments[0].column
|
|
3442
|
+
});
|
|
3443
|
+
}
|
|
3444
|
+
continue;
|
|
3445
|
+
}
|
|
3446
|
+
if (indent === 0) {
|
|
3447
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
3448
|
+
if (section.kind === "system") {
|
|
3449
|
+
system = section.system;
|
|
3450
|
+
} else if (section.kind === "defaults") {
|
|
3451
|
+
sawDefaults = true;
|
|
3452
|
+
} else if (section.kind === "atlas") {
|
|
3453
|
+
sawAtlas = true;
|
|
3454
|
+
}
|
|
3455
|
+
continue;
|
|
3456
|
+
}
|
|
3457
|
+
if (!section) {
|
|
3458
|
+
throw new WorldOrbitError("Indented line without parent atlas section", lineNumber, indent + 1);
|
|
3459
|
+
}
|
|
3460
|
+
handleSectionLine(section, indent, tokens, lineNumber);
|
|
3461
|
+
}
|
|
3462
|
+
if (!sawSchemaHeader) {
|
|
3463
|
+
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3464
|
+
}
|
|
3465
|
+
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
3466
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
3467
|
+
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3468
|
+
const baseDocument = {
|
|
3469
|
+
format: "worldorbit",
|
|
3470
|
+
sourceVersion: "1.0",
|
|
3471
|
+
system,
|
|
3472
|
+
groups,
|
|
3473
|
+
relations,
|
|
3474
|
+
events: normalizedEvents,
|
|
3475
|
+
objects,
|
|
3476
|
+
diagnostics
|
|
3477
|
+
};
|
|
3478
|
+
if (outputVersion === "2.0-draft") {
|
|
3479
|
+
const document3 = {
|
|
3480
|
+
...baseDocument,
|
|
3481
|
+
version: "2.0-draft",
|
|
3482
|
+
schemaVersion: "2.0-draft"
|
|
3483
|
+
};
|
|
3484
|
+
document3.diagnostics.push(...collectAtlasDiagnostics(document3, sourceSchemaVersion));
|
|
3485
|
+
return document3;
|
|
3486
|
+
}
|
|
3487
|
+
const document2 = {
|
|
3488
|
+
...baseDocument,
|
|
3489
|
+
version: outputVersion,
|
|
3490
|
+
schemaVersion: outputVersion
|
|
3491
|
+
};
|
|
3492
|
+
if (sourceSchemaVersion === "2.0-draft") {
|
|
3493
|
+
document2.diagnostics.push({
|
|
3494
|
+
code: "load.schema.deprecatedDraft",
|
|
3495
|
+
severity: "warning",
|
|
3496
|
+
source: "upgrade",
|
|
3497
|
+
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
3498
|
+
});
|
|
3499
|
+
}
|
|
3500
|
+
document2.diagnostics.push(...collectAtlasDiagnostics(document2, sourceSchemaVersion));
|
|
3501
|
+
return document2;
|
|
3502
|
+
}
|
|
3503
|
+
function assertDraftSchemaHeader(tokens, line) {
|
|
3504
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1"].includes(tokens[1].value.toLowerCase())) {
|
|
3505
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
3506
|
+
}
|
|
3507
|
+
const version = tokens[1].value.toLowerCase();
|
|
3508
|
+
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3509
|
+
}
|
|
3510
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3511
|
+
const keyword = tokens[0]?.value.toLowerCase();
|
|
3512
|
+
switch (keyword) {
|
|
3513
|
+
case "system":
|
|
3514
|
+
if (system) {
|
|
3515
|
+
throw new WorldOrbitError('Atlas section "system" may only appear once', line, tokens[0].column);
|
|
3516
|
+
}
|
|
3517
|
+
return startSystemSection(tokens, line, sourceSchemaVersion, diagnostics);
|
|
3518
|
+
case "defaults":
|
|
3519
|
+
if (!system) {
|
|
3520
|
+
throw new WorldOrbitError('Atlas section "defaults" requires a preceding system declaration', line, tokens[0].column);
|
|
3521
|
+
}
|
|
3522
|
+
if (flags.sawDefaults) {
|
|
3523
|
+
throw new WorldOrbitError('Atlas section "defaults" may only appear once', line, tokens[0].column);
|
|
3524
|
+
}
|
|
3525
|
+
return {
|
|
3526
|
+
kind: "defaults",
|
|
3527
|
+
system,
|
|
3528
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
3529
|
+
};
|
|
3530
|
+
case "atlas":
|
|
3531
|
+
if (!system) {
|
|
3532
|
+
throw new WorldOrbitError('Atlas section "atlas" requires a preceding system declaration', line, tokens[0].column);
|
|
3533
|
+
}
|
|
3534
|
+
if (flags.sawAtlas) {
|
|
3535
|
+
throw new WorldOrbitError('Atlas section "atlas" may only appear once', line, tokens[0].column);
|
|
3536
|
+
}
|
|
3537
|
+
return {
|
|
3538
|
+
kind: "atlas",
|
|
3539
|
+
system,
|
|
3540
|
+
inMetadata: false,
|
|
3541
|
+
metadataIndent: null
|
|
3542
|
+
};
|
|
3543
|
+
case "viewpoint":
|
|
3544
|
+
if (!system) {
|
|
3545
|
+
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
3546
|
+
}
|
|
3547
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
3548
|
+
case "annotation":
|
|
3549
|
+
if (!system) {
|
|
3550
|
+
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
3551
|
+
}
|
|
3552
|
+
return startAnnotationSection(tokens, line, system, annotationIds);
|
|
3553
|
+
case "group":
|
|
3554
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "group", { line, column: tokens[0].column });
|
|
3555
|
+
return startGroupSection(tokens, line, groups, groupIds);
|
|
3556
|
+
case "relation":
|
|
3557
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
3558
|
+
return startRelationSection(tokens, line, relations, relationIds);
|
|
3559
|
+
case "event":
|
|
3560
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
3561
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
3562
|
+
case "object":
|
|
3563
|
+
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3564
|
+
default:
|
|
3565
|
+
throw new WorldOrbitError(`Unknown atlas section "${tokens[0]?.value ?? ""}"`, line, tokens[0]?.column ?? 1);
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3568
|
+
function startSystemSection(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
3569
|
+
if (tokens.length !== 2) {
|
|
3570
|
+
throw new WorldOrbitError("Invalid atlas system declaration", line, tokens[0]?.column ?? 1);
|
|
3571
|
+
}
|
|
3572
|
+
const system = {
|
|
3573
|
+
type: "system",
|
|
3574
|
+
id: tokens[1].value,
|
|
3575
|
+
title: null,
|
|
3576
|
+
description: null,
|
|
3577
|
+
epoch: null,
|
|
3578
|
+
referencePlane: null,
|
|
3579
|
+
defaults: {
|
|
3580
|
+
view: "topdown",
|
|
3581
|
+
scale: null,
|
|
3582
|
+
units: null,
|
|
3583
|
+
preset: null,
|
|
3584
|
+
theme: null
|
|
3585
|
+
},
|
|
3586
|
+
atlasMetadata: {},
|
|
3587
|
+
viewpoints: [],
|
|
3588
|
+
annotations: []
|
|
3589
|
+
};
|
|
3590
|
+
return {
|
|
3591
|
+
kind: "system",
|
|
3592
|
+
system,
|
|
3593
|
+
sourceSchemaVersion,
|
|
3594
|
+
diagnostics,
|
|
2595
3595
|
seenFields: /* @__PURE__ */ new Set()
|
|
2596
3596
|
};
|
|
2597
3597
|
}
|
|
2598
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
3598
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
2599
3599
|
if (tokens.length !== 2) {
|
|
2600
3600
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
2601
3601
|
}
|
|
@@ -2612,6 +3612,7 @@ var WorldOrbit = (() => {
|
|
|
2612
3612
|
summary: "",
|
|
2613
3613
|
focusObjectId: null,
|
|
2614
3614
|
selectedObjectId: null,
|
|
3615
|
+
events: [],
|
|
2615
3616
|
projection: system.defaults.view,
|
|
2616
3617
|
preset: system.defaults.preset,
|
|
2617
3618
|
zoom: null,
|
|
@@ -2624,6 +3625,8 @@ var WorldOrbit = (() => {
|
|
|
2624
3625
|
return {
|
|
2625
3626
|
kind: "viewpoint",
|
|
2626
3627
|
viewpoint,
|
|
3628
|
+
sourceSchemaVersion,
|
|
3629
|
+
diagnostics,
|
|
2627
3630
|
seenFields: /* @__PURE__ */ new Set(),
|
|
2628
3631
|
inFilter: false,
|
|
2629
3632
|
filterIndent: null,
|
|
@@ -2657,7 +3660,107 @@ var WorldOrbit = (() => {
|
|
|
2657
3660
|
seenFields: /* @__PURE__ */ new Set()
|
|
2658
3661
|
};
|
|
2659
3662
|
}
|
|
2660
|
-
function
|
|
3663
|
+
function startGroupSection(tokens, line, groups, groupIds) {
|
|
3664
|
+
if (tokens.length !== 2) {
|
|
3665
|
+
throw new WorldOrbitError("Invalid group declaration", line, tokens[0]?.column ?? 1);
|
|
3666
|
+
}
|
|
3667
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
3668
|
+
if (!id) {
|
|
3669
|
+
throw new WorldOrbitError("Group id must not be empty", line, tokens[1].column);
|
|
3670
|
+
}
|
|
3671
|
+
if (groupIds.has(id)) {
|
|
3672
|
+
throw new WorldOrbitError(`Duplicate group id "${id}"`, line, tokens[1].column);
|
|
3673
|
+
}
|
|
3674
|
+
const group = {
|
|
3675
|
+
id,
|
|
3676
|
+
label: humanizeIdentifier2(id),
|
|
3677
|
+
summary: "",
|
|
3678
|
+
color: null,
|
|
3679
|
+
tags: [],
|
|
3680
|
+
hidden: false
|
|
3681
|
+
};
|
|
3682
|
+
groups.push(group);
|
|
3683
|
+
groupIds.add(id);
|
|
3684
|
+
return {
|
|
3685
|
+
kind: "group",
|
|
3686
|
+
group,
|
|
3687
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
function startRelationSection(tokens, line, relations, relationIds) {
|
|
3691
|
+
if (tokens.length !== 2) {
|
|
3692
|
+
throw new WorldOrbitError("Invalid relation declaration", line, tokens[0]?.column ?? 1);
|
|
3693
|
+
}
|
|
3694
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
3695
|
+
if (!id) {
|
|
3696
|
+
throw new WorldOrbitError("Relation id must not be empty", line, tokens[1].column);
|
|
3697
|
+
}
|
|
3698
|
+
if (relationIds.has(id)) {
|
|
3699
|
+
throw new WorldOrbitError(`Duplicate relation id "${id}"`, line, tokens[1].column);
|
|
3700
|
+
}
|
|
3701
|
+
const relation = {
|
|
3702
|
+
id,
|
|
3703
|
+
from: "",
|
|
3704
|
+
to: "",
|
|
3705
|
+
kind: "",
|
|
3706
|
+
label: null,
|
|
3707
|
+
summary: null,
|
|
3708
|
+
tags: [],
|
|
3709
|
+
color: null,
|
|
3710
|
+
hidden: false
|
|
3711
|
+
};
|
|
3712
|
+
relations.push(relation);
|
|
3713
|
+
relationIds.add(id);
|
|
3714
|
+
return {
|
|
3715
|
+
kind: "relation",
|
|
3716
|
+
relation,
|
|
3717
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
3718
|
+
};
|
|
3719
|
+
}
|
|
3720
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
3721
|
+
if (tokens.length !== 2) {
|
|
3722
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
3723
|
+
}
|
|
3724
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
3725
|
+
if (!id) {
|
|
3726
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
3727
|
+
}
|
|
3728
|
+
if (eventIds.has(id)) {
|
|
3729
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
3730
|
+
}
|
|
3731
|
+
const event = {
|
|
3732
|
+
id,
|
|
3733
|
+
kind: "",
|
|
3734
|
+
label: humanizeIdentifier2(id),
|
|
3735
|
+
summary: null,
|
|
3736
|
+
targetObjectId: null,
|
|
3737
|
+
participantObjectIds: [],
|
|
3738
|
+
timing: null,
|
|
3739
|
+
visibility: null,
|
|
3740
|
+
tags: [],
|
|
3741
|
+
color: null,
|
|
3742
|
+
hidden: false,
|
|
3743
|
+
positions: []
|
|
3744
|
+
};
|
|
3745
|
+
const rawPoses = [];
|
|
3746
|
+
events.push(event);
|
|
3747
|
+
eventPoseNodes.set(id, rawPoses);
|
|
3748
|
+
eventIds.add(id);
|
|
3749
|
+
return {
|
|
3750
|
+
kind: "event",
|
|
3751
|
+
event,
|
|
3752
|
+
sourceSchemaVersion,
|
|
3753
|
+
diagnostics,
|
|
3754
|
+
seenFields: /* @__PURE__ */ new Set(),
|
|
3755
|
+
rawPoses,
|
|
3756
|
+
inPositions: false,
|
|
3757
|
+
positionsIndent: null,
|
|
3758
|
+
activePose: null,
|
|
3759
|
+
poseIndent: null,
|
|
3760
|
+
activePoseSeenFields: /* @__PURE__ */ new Set()
|
|
3761
|
+
};
|
|
3762
|
+
}
|
|
3763
|
+
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
2661
3764
|
if (tokens.length < 3) {
|
|
2662
3765
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
2663
3766
|
}
|
|
@@ -2668,12 +3771,11 @@ var WorldOrbit = (() => {
|
|
|
2668
3771
|
throw new WorldOrbitError(`Unknown object type "${objectTypeToken.value}"`, line, objectTypeToken.column);
|
|
2669
3772
|
}
|
|
2670
3773
|
const objectNode = {
|
|
2671
|
-
type: "object",
|
|
2672
3774
|
objectType,
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
blockFields: [],
|
|
3775
|
+
id: idToken.value,
|
|
3776
|
+
fields: parseInlineObjectFields(tokens.slice(3), line, objectType, sourceSchemaVersion, diagnostics),
|
|
2676
3777
|
infoEntries: [],
|
|
3778
|
+
typedBlockEntries: {},
|
|
2677
3779
|
location: {
|
|
2678
3780
|
line,
|
|
2679
3781
|
column: objectTypeToken.column
|
|
@@ -2683,8 +3785,12 @@ var WorldOrbit = (() => {
|
|
|
2683
3785
|
return {
|
|
2684
3786
|
kind: "object",
|
|
2685
3787
|
objectNode,
|
|
2686
|
-
|
|
2687
|
-
|
|
3788
|
+
sourceSchemaVersion,
|
|
3789
|
+
diagnostics,
|
|
3790
|
+
activeBlock: null,
|
|
3791
|
+
blockIndent: null,
|
|
3792
|
+
seenInfoKeys: /* @__PURE__ */ new Set(),
|
|
3793
|
+
seenTypedBlockKeys: {}
|
|
2688
3794
|
};
|
|
2689
3795
|
}
|
|
2690
3796
|
function handleSectionLine(section, indent, tokens, line) {
|
|
@@ -2704,6 +3810,15 @@ var WorldOrbit = (() => {
|
|
|
2704
3810
|
case "annotation":
|
|
2705
3811
|
applyAnnotationField(section, tokens, line);
|
|
2706
3812
|
return;
|
|
3813
|
+
case "group":
|
|
3814
|
+
applyGroupField(section, tokens, line);
|
|
3815
|
+
return;
|
|
3816
|
+
case "relation":
|
|
3817
|
+
applyRelationField(section, tokens, line);
|
|
3818
|
+
return;
|
|
3819
|
+
case "event":
|
|
3820
|
+
applyEventField(section, indent, tokens, line);
|
|
3821
|
+
return;
|
|
2707
3822
|
case "object":
|
|
2708
3823
|
applyObjectField(section, indent, tokens, line);
|
|
2709
3824
|
return;
|
|
@@ -2711,10 +3826,35 @@ var WorldOrbit = (() => {
|
|
|
2711
3826
|
}
|
|
2712
3827
|
function applySystemField(section, tokens, line) {
|
|
2713
3828
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
2714
|
-
|
|
2715
|
-
|
|
3829
|
+
const value = joinFieldValue(tokens, line);
|
|
3830
|
+
switch (key) {
|
|
3831
|
+
case "title":
|
|
3832
|
+
section.system.title = value;
|
|
3833
|
+
return;
|
|
3834
|
+
case "description":
|
|
3835
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
3836
|
+
line,
|
|
3837
|
+
column: tokens[0].column
|
|
3838
|
+
});
|
|
3839
|
+
section.system.description = value;
|
|
3840
|
+
return;
|
|
3841
|
+
case "epoch":
|
|
3842
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
3843
|
+
line,
|
|
3844
|
+
column: tokens[0].column
|
|
3845
|
+
});
|
|
3846
|
+
section.system.epoch = value;
|
|
3847
|
+
return;
|
|
3848
|
+
case "referenceplane":
|
|
3849
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "referencePlane", {
|
|
3850
|
+
line,
|
|
3851
|
+
column: tokens[0].column
|
|
3852
|
+
});
|
|
3853
|
+
section.system.referencePlane = value;
|
|
3854
|
+
return;
|
|
3855
|
+
default:
|
|
3856
|
+
throw new WorldOrbitError(`Unknown system atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
2716
3857
|
}
|
|
2717
|
-
section.system.title = joinFieldValue(tokens, line);
|
|
2718
3858
|
}
|
|
2719
3859
|
function applyDefaultsField(section, tokens, line) {
|
|
2720
3860
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
@@ -2745,14 +3885,11 @@ var WorldOrbit = (() => {
|
|
|
2745
3885
|
section.metadataIndent = null;
|
|
2746
3886
|
}
|
|
2747
3887
|
if (section.inMetadata) {
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
const key = tokens[0].value;
|
|
2752
|
-
if (key in section.system.atlasMetadata) {
|
|
2753
|
-
throw new WorldOrbitError(`Duplicate atlas metadata key "${key}"`, line, tokens[0].column);
|
|
3888
|
+
const entry = parseInfoLikeEntry(tokens, line, "Invalid atlas metadata entry");
|
|
3889
|
+
if (entry.key in section.system.atlasMetadata) {
|
|
3890
|
+
throw new WorldOrbitError(`Duplicate atlas metadata key "${entry.key}"`, line, tokens[0].column);
|
|
2754
3891
|
}
|
|
2755
|
-
section.system.atlasMetadata[key] =
|
|
3892
|
+
section.system.atlasMetadata[entry.key] = entry.value;
|
|
2756
3893
|
return;
|
|
2757
3894
|
}
|
|
2758
3895
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "metadata") {
|
|
@@ -2808,7 +3945,14 @@ var WorldOrbit = (() => {
|
|
|
2808
3945
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
2809
3946
|
return;
|
|
2810
3947
|
case "layers":
|
|
2811
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
3948
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
3949
|
+
return;
|
|
3950
|
+
case "events":
|
|
3951
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
3952
|
+
line,
|
|
3953
|
+
column: tokens[0].column
|
|
3954
|
+
});
|
|
3955
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
2812
3956
|
return;
|
|
2813
3957
|
default:
|
|
2814
3958
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
@@ -2833,42 +3977,223 @@ var WorldOrbit = (() => {
|
|
|
2833
3977
|
default:
|
|
2834
3978
|
throw new WorldOrbitError(`Unknown viewpoint filter field "${tokens[0].value}"`, line, tokens[0].column);
|
|
2835
3979
|
}
|
|
2836
|
-
section.viewpoint.filter = filter;
|
|
2837
|
-
}
|
|
2838
|
-
function applyAnnotationField(section, tokens, line) {
|
|
3980
|
+
section.viewpoint.filter = filter;
|
|
3981
|
+
}
|
|
3982
|
+
function applyAnnotationField(section, tokens, line) {
|
|
3983
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
3984
|
+
switch (key) {
|
|
3985
|
+
case "label":
|
|
3986
|
+
section.annotation.label = joinFieldValue(tokens, line);
|
|
3987
|
+
return;
|
|
3988
|
+
case "target":
|
|
3989
|
+
section.annotation.targetObjectId = joinFieldValue(tokens, line);
|
|
3990
|
+
return;
|
|
3991
|
+
case "body":
|
|
3992
|
+
section.annotation.body = joinFieldValue(tokens, line);
|
|
3993
|
+
return;
|
|
3994
|
+
case "tags":
|
|
3995
|
+
section.annotation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
3996
|
+
return;
|
|
3997
|
+
default:
|
|
3998
|
+
throw new WorldOrbitError(`Unknown annotation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
function applyGroupField(section, tokens, line) {
|
|
4002
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4003
|
+
switch (key) {
|
|
4004
|
+
case "label":
|
|
4005
|
+
section.group.label = joinFieldValue(tokens, line);
|
|
4006
|
+
return;
|
|
4007
|
+
case "summary":
|
|
4008
|
+
section.group.summary = joinFieldValue(tokens, line);
|
|
4009
|
+
return;
|
|
4010
|
+
case "color":
|
|
4011
|
+
section.group.color = joinFieldValue(tokens, line);
|
|
4012
|
+
return;
|
|
4013
|
+
case "tags":
|
|
4014
|
+
section.group.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4015
|
+
return;
|
|
4016
|
+
case "hidden":
|
|
4017
|
+
section.group.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4018
|
+
line,
|
|
4019
|
+
column: tokens[0].column
|
|
4020
|
+
});
|
|
4021
|
+
return;
|
|
4022
|
+
default:
|
|
4023
|
+
throw new WorldOrbitError(`Unknown group field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
function applyRelationField(section, tokens, line) {
|
|
4027
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4028
|
+
switch (key) {
|
|
4029
|
+
case "from":
|
|
4030
|
+
section.relation.from = joinFieldValue(tokens, line);
|
|
4031
|
+
return;
|
|
4032
|
+
case "to":
|
|
4033
|
+
section.relation.to = joinFieldValue(tokens, line);
|
|
4034
|
+
return;
|
|
4035
|
+
case "kind":
|
|
4036
|
+
section.relation.kind = joinFieldValue(tokens, line);
|
|
4037
|
+
return;
|
|
4038
|
+
case "label":
|
|
4039
|
+
section.relation.label = joinFieldValue(tokens, line);
|
|
4040
|
+
return;
|
|
4041
|
+
case "summary":
|
|
4042
|
+
section.relation.summary = joinFieldValue(tokens, line);
|
|
4043
|
+
return;
|
|
4044
|
+
case "tags":
|
|
4045
|
+
section.relation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4046
|
+
return;
|
|
4047
|
+
case "color":
|
|
4048
|
+
section.relation.color = joinFieldValue(tokens, line);
|
|
4049
|
+
return;
|
|
4050
|
+
case "hidden":
|
|
4051
|
+
section.relation.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4052
|
+
line,
|
|
4053
|
+
column: tokens[0].column
|
|
4054
|
+
});
|
|
4055
|
+
return;
|
|
4056
|
+
default:
|
|
4057
|
+
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
function applyEventField(section, indent, tokens, line) {
|
|
4061
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
4062
|
+
section.activePose = null;
|
|
4063
|
+
section.poseIndent = null;
|
|
4064
|
+
section.activePoseSeenFields.clear();
|
|
4065
|
+
}
|
|
4066
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
4067
|
+
section.inPositions = false;
|
|
4068
|
+
section.positionsIndent = null;
|
|
4069
|
+
}
|
|
4070
|
+
if (section.activePose) {
|
|
4071
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4072
|
+
return;
|
|
4073
|
+
}
|
|
4074
|
+
if (section.inPositions) {
|
|
4075
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
4076
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
4077
|
+
}
|
|
4078
|
+
const objectId = tokens[1].value;
|
|
4079
|
+
if (!objectId.trim()) {
|
|
4080
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
4081
|
+
}
|
|
4082
|
+
const rawPose = {
|
|
4083
|
+
objectId,
|
|
4084
|
+
fields: [],
|
|
4085
|
+
location: { line, column: tokens[0].column }
|
|
4086
|
+
};
|
|
4087
|
+
section.rawPoses.push(rawPose);
|
|
4088
|
+
section.activePose = rawPose;
|
|
4089
|
+
section.poseIndent = indent;
|
|
4090
|
+
section.activePoseSeenFields = /* @__PURE__ */ new Set();
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
4093
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
4094
|
+
if (section.seenFields.has("positions")) {
|
|
4095
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
4096
|
+
}
|
|
4097
|
+
section.seenFields.add("positions");
|
|
4098
|
+
section.inPositions = true;
|
|
4099
|
+
section.positionsIndent = indent;
|
|
4100
|
+
return;
|
|
4101
|
+
}
|
|
2839
4102
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
2840
4103
|
switch (key) {
|
|
4104
|
+
case "kind":
|
|
4105
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
4106
|
+
return;
|
|
2841
4107
|
case "label":
|
|
2842
|
-
section.
|
|
4108
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
4109
|
+
return;
|
|
4110
|
+
case "summary":
|
|
4111
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
2843
4112
|
return;
|
|
2844
4113
|
case "target":
|
|
2845
|
-
section.
|
|
4114
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
2846
4115
|
return;
|
|
2847
|
-
case "
|
|
2848
|
-
section.
|
|
4116
|
+
case "participants":
|
|
4117
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
4118
|
+
return;
|
|
4119
|
+
case "timing":
|
|
4120
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
4121
|
+
return;
|
|
4122
|
+
case "visibility":
|
|
4123
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
2849
4124
|
return;
|
|
2850
4125
|
case "tags":
|
|
2851
|
-
section.
|
|
4126
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4127
|
+
return;
|
|
4128
|
+
case "color":
|
|
4129
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
4130
|
+
return;
|
|
4131
|
+
case "hidden":
|
|
4132
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4133
|
+
line,
|
|
4134
|
+
column: tokens[0].column
|
|
4135
|
+
});
|
|
2852
4136
|
return;
|
|
2853
4137
|
default:
|
|
2854
|
-
throw new WorldOrbitError(`Unknown
|
|
4138
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
2855
4139
|
}
|
|
2856
4140
|
}
|
|
2857
|
-
function
|
|
2858
|
-
if (tokens.length
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
4141
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
4142
|
+
if (tokens.length < 2) {
|
|
4143
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
4144
|
+
}
|
|
4145
|
+
const key = tokens[0].value;
|
|
4146
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
4147
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
2862
4148
|
}
|
|
2863
|
-
if (
|
|
2864
|
-
|
|
2865
|
-
|
|
4149
|
+
if (seenFields.has(key)) {
|
|
4150
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
4151
|
+
}
|
|
4152
|
+
seenFields.add(key);
|
|
4153
|
+
return {
|
|
4154
|
+
type: "field",
|
|
4155
|
+
key,
|
|
4156
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
4157
|
+
location: { line, column: tokens[0].column }
|
|
4158
|
+
};
|
|
4159
|
+
}
|
|
4160
|
+
function applyObjectField(section, indent, tokens, line) {
|
|
4161
|
+
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
4162
|
+
section.activeBlock = null;
|
|
4163
|
+
section.blockIndent = null;
|
|
4164
|
+
}
|
|
4165
|
+
if (tokens.length === 1) {
|
|
4166
|
+
const blockName = tokens[0].value.toLowerCase();
|
|
4167
|
+
if (blockName === "info" || STRUCTURED_TYPED_BLOCKS.has(blockName)) {
|
|
4168
|
+
if (blockName !== "info") {
|
|
4169
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, blockName, { line, column: tokens[0].column });
|
|
4170
|
+
}
|
|
4171
|
+
section.activeBlock = blockName;
|
|
4172
|
+
section.blockIndent = indent;
|
|
4173
|
+
return;
|
|
4174
|
+
}
|
|
2866
4175
|
}
|
|
2867
|
-
if (section.
|
|
2868
|
-
|
|
4176
|
+
if (section.activeBlock) {
|
|
4177
|
+
const entry = parseInfoLikeEntry(tokens, line, `Invalid ${section.activeBlock} entry`);
|
|
4178
|
+
if (section.activeBlock === "info") {
|
|
4179
|
+
if (section.seenInfoKeys.has(entry.key)) {
|
|
4180
|
+
throw new WorldOrbitError(`Duplicate info key "${entry.key}"`, line, tokens[0].column);
|
|
4181
|
+
}
|
|
4182
|
+
section.seenInfoKeys.add(entry.key);
|
|
4183
|
+
section.objectNode.infoEntries.push(entry);
|
|
4184
|
+
return;
|
|
4185
|
+
}
|
|
4186
|
+
const typedBlock = section.activeBlock;
|
|
4187
|
+
const seenKeys = section.seenTypedBlockKeys[typedBlock] ?? (section.seenTypedBlockKeys[typedBlock] = /* @__PURE__ */ new Set());
|
|
4188
|
+
if (seenKeys.has(entry.key)) {
|
|
4189
|
+
throw new WorldOrbitError(`Duplicate ${typedBlock} key "${entry.key}"`, line, tokens[0].column);
|
|
4190
|
+
}
|
|
4191
|
+
seenKeys.add(entry.key);
|
|
4192
|
+
const entries = section.objectNode.typedBlockEntries[typedBlock] ?? (section.objectNode.typedBlockEntries[typedBlock] = []);
|
|
4193
|
+
entries.push(entry);
|
|
2869
4194
|
return;
|
|
2870
4195
|
}
|
|
2871
|
-
section.objectNode.
|
|
4196
|
+
section.objectNode.fields.push(parseObjectField(tokens, line, section.objectNode.objectType, section.sourceSchemaVersion, section.diagnostics));
|
|
2872
4197
|
}
|
|
2873
4198
|
function requireUniqueField(tokens, seenFields, line) {
|
|
2874
4199
|
if (tokens.length < 2) {
|
|
@@ -2888,50 +4213,46 @@ var WorldOrbit = (() => {
|
|
|
2888
4213
|
return tokens.slice(1).map((token) => token.value).join(" ").trim();
|
|
2889
4214
|
}
|
|
2890
4215
|
function parseObjectTypeTokens(tokens, line) {
|
|
2891
|
-
|
|
2892
|
-
throw new WorldOrbitError("Missing value for atlas field", line);
|
|
2893
|
-
}
|
|
2894
|
-
return tokens.map((token) => {
|
|
2895
|
-
const value = token.value;
|
|
2896
|
-
if (value !== "star" && value !== "planet" && value !== "moon" && value !== "belt" && value !== "asteroid" && value !== "comet" && value !== "ring" && value !== "structure" && value !== "phenomenon") {
|
|
2897
|
-
throw new WorldOrbitError(`Unknown viewpoint object type "${token.value}"`, line, token.column);
|
|
2898
|
-
}
|
|
2899
|
-
return value;
|
|
2900
|
-
});
|
|
4216
|
+
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");
|
|
2901
4217
|
}
|
|
2902
|
-
function
|
|
2903
|
-
|
|
2904
|
-
|
|
4218
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
4219
|
+
const layers = {};
|
|
4220
|
+
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
4221
|
+
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
4222
|
+
const raw = token.replace(/^[-!]+/, "").toLowerCase();
|
|
4223
|
+
if (raw === "orbits") {
|
|
4224
|
+
layers["orbits-back"] = enabled;
|
|
4225
|
+
layers["orbits-front"] = enabled;
|
|
4226
|
+
continue;
|
|
4227
|
+
}
|
|
4228
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4229
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
4230
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
4231
|
+
line,
|
|
4232
|
+
column: tokens[0]?.column ?? 1
|
|
4233
|
+
});
|
|
4234
|
+
}
|
|
4235
|
+
layers[raw] = enabled;
|
|
4236
|
+
}
|
|
2905
4237
|
}
|
|
2906
|
-
return
|
|
4238
|
+
return layers;
|
|
2907
4239
|
}
|
|
2908
|
-
function
|
|
4240
|
+
function parseTokenList(tokens, line, fieldName) {
|
|
2909
4241
|
if (tokens.length === 0) {
|
|
2910
|
-
throw new WorldOrbitError(
|
|
4242
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, 1);
|
|
2911
4243
|
}
|
|
2912
|
-
const
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
const rawLayer = token.value.replace(/^[-!]+/, "").toLowerCase();
|
|
2916
|
-
if (rawLayer === "orbits") {
|
|
2917
|
-
next["orbits-back"] = enabled;
|
|
2918
|
-
next["orbits-front"] = enabled;
|
|
2919
|
-
continue;
|
|
2920
|
-
}
|
|
2921
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
2922
|
-
next[rawLayer] = enabled;
|
|
2923
|
-
continue;
|
|
2924
|
-
}
|
|
2925
|
-
throw new WorldOrbitError(`Unknown layer token "${token.value}"`, line, token.column);
|
|
4244
|
+
const values = tokens.map((token) => token.value).filter(Boolean);
|
|
4245
|
+
if (values.length === 0) {
|
|
4246
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, tokens[0]?.column ?? 1);
|
|
2926
4247
|
}
|
|
2927
|
-
return
|
|
4248
|
+
return values;
|
|
2928
4249
|
}
|
|
2929
4250
|
function parseProjectionValue(value, line, column) {
|
|
2930
4251
|
const normalized = value.toLowerCase();
|
|
2931
|
-
if (normalized
|
|
2932
|
-
|
|
4252
|
+
if (normalized !== "topdown" && normalized !== "isometric") {
|
|
4253
|
+
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
2933
4254
|
}
|
|
2934
|
-
|
|
4255
|
+
return normalized;
|
|
2935
4256
|
}
|
|
2936
4257
|
function parsePresetValue(value, line, column) {
|
|
2937
4258
|
const normalized = value.toLowerCase();
|
|
@@ -2941,16 +4262,16 @@ var WorldOrbit = (() => {
|
|
|
2941
4262
|
throw new WorldOrbitError(`Unknown render preset "${value}"`, line, column);
|
|
2942
4263
|
}
|
|
2943
4264
|
function parsePositiveNumber2(value, line, column, field) {
|
|
2944
|
-
const parsed =
|
|
2945
|
-
if (
|
|
2946
|
-
throw new WorldOrbitError(`Field "${field}"
|
|
4265
|
+
const parsed = parseFiniteNumber2(value, line, column, field);
|
|
4266
|
+
if (parsed <= 0) {
|
|
4267
|
+
throw new WorldOrbitError(`Field "${field}" must be greater than zero`, line, column);
|
|
2947
4268
|
}
|
|
2948
4269
|
return parsed;
|
|
2949
4270
|
}
|
|
2950
4271
|
function parseFiniteNumber2(value, line, column, field) {
|
|
2951
4272
|
const parsed = Number(value);
|
|
2952
4273
|
if (!Number.isFinite(parsed)) {
|
|
2953
|
-
throw new WorldOrbitError(`
|
|
4274
|
+
throw new WorldOrbitError(`Invalid numeric value "${value}" for "${field}"`, line, column);
|
|
2954
4275
|
}
|
|
2955
4276
|
return parsed;
|
|
2956
4277
|
}
|
|
@@ -2962,28 +4283,43 @@ var WorldOrbit = (() => {
|
|
|
2962
4283
|
groupIds: []
|
|
2963
4284
|
};
|
|
2964
4285
|
}
|
|
2965
|
-
function
|
|
4286
|
+
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
2966
4287
|
const fields = [];
|
|
2967
4288
|
let index = 0;
|
|
2968
4289
|
while (index < tokens.length) {
|
|
2969
4290
|
const keyToken = tokens[index];
|
|
2970
|
-
const
|
|
2971
|
-
if (!
|
|
4291
|
+
const spec = getDraftObjectFieldSpec(keyToken.value);
|
|
4292
|
+
if (!spec) {
|
|
2972
4293
|
throw new WorldOrbitError(`Unknown field "${keyToken.value}"`, line, keyToken.column);
|
|
2973
4294
|
}
|
|
4295
|
+
if (spec.version === "2.1") {
|
|
4296
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, keyToken.value, {
|
|
4297
|
+
line,
|
|
4298
|
+
column: keyToken.column
|
|
4299
|
+
});
|
|
4300
|
+
}
|
|
2974
4301
|
index++;
|
|
2975
4302
|
const valueTokens = [];
|
|
2976
|
-
if (
|
|
2977
|
-
while (index < tokens.length && !isKnownFieldKey(tokens[index].value)) {
|
|
2978
|
-
valueTokens.push(tokens[index]);
|
|
2979
|
-
index++;
|
|
2980
|
-
}
|
|
2981
|
-
} else {
|
|
4303
|
+
if (spec.inlineMode === "single") {
|
|
2982
4304
|
const nextToken = tokens[index];
|
|
2983
4305
|
if (nextToken) {
|
|
2984
4306
|
valueTokens.push(nextToken);
|
|
2985
4307
|
index++;
|
|
2986
4308
|
}
|
|
4309
|
+
} else if (spec.inlineMode === "pair") {
|
|
4310
|
+
for (let count = 0; count < 2; count++) {
|
|
4311
|
+
const nextToken = tokens[index];
|
|
4312
|
+
if (!nextToken) {
|
|
4313
|
+
break;
|
|
4314
|
+
}
|
|
4315
|
+
valueTokens.push(nextToken);
|
|
4316
|
+
index++;
|
|
4317
|
+
}
|
|
4318
|
+
} else {
|
|
4319
|
+
while (index < tokens.length && !DRAFT_OBJECT_FIELD_KEYS.has(tokens[index].value)) {
|
|
4320
|
+
valueTokens.push(tokens[index]);
|
|
4321
|
+
index++;
|
|
4322
|
+
}
|
|
2987
4323
|
}
|
|
2988
4324
|
if (valueTokens.length === 0) {
|
|
2989
4325
|
throw new WorldOrbitError(`Missing value for field "${keyToken.value}"`, line, keyToken.column);
|
|
@@ -2995,25 +4331,35 @@ var WorldOrbit = (() => {
|
|
|
2995
4331
|
location: { line, column: keyToken.column }
|
|
2996
4332
|
});
|
|
2997
4333
|
}
|
|
4334
|
+
validateDraftObjectFieldCompatibility(fields, objectType);
|
|
2998
4335
|
return fields;
|
|
2999
4336
|
}
|
|
3000
|
-
function
|
|
4337
|
+
function parseObjectField(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3001
4338
|
if (tokens.length < 2) {
|
|
3002
4339
|
throw new WorldOrbitError("Invalid field line", line, tokens[0]?.column ?? 1);
|
|
3003
4340
|
}
|
|
3004
|
-
|
|
4341
|
+
const spec = getDraftObjectFieldSpec(tokens[0].value);
|
|
4342
|
+
if (!spec) {
|
|
3005
4343
|
throw new WorldOrbitError(`Unknown field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3006
4344
|
}
|
|
3007
|
-
|
|
4345
|
+
if (spec.version === "2.1") {
|
|
4346
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, tokens[0].value, {
|
|
4347
|
+
line,
|
|
4348
|
+
column: tokens[0].column
|
|
4349
|
+
});
|
|
4350
|
+
}
|
|
4351
|
+
const field = {
|
|
3008
4352
|
type: "field",
|
|
3009
4353
|
key: tokens[0].value,
|
|
3010
4354
|
values: tokens.slice(1).map((token) => token.value),
|
|
3011
4355
|
location: { line, column: tokens[0].column }
|
|
3012
4356
|
};
|
|
4357
|
+
validateDraftObjectFieldCompatibility([field], objectType);
|
|
4358
|
+
return field;
|
|
3013
4359
|
}
|
|
3014
|
-
function
|
|
4360
|
+
function parseInfoLikeEntry(tokens, line, errorMessage) {
|
|
3015
4361
|
if (tokens.length < 2) {
|
|
3016
|
-
throw new WorldOrbitError(
|
|
4362
|
+
throw new WorldOrbitError(errorMessage, line, tokens[0]?.column ?? 1);
|
|
3017
4363
|
}
|
|
3018
4364
|
return {
|
|
3019
4365
|
type: "info-entry",
|
|
@@ -3022,18 +4368,366 @@ var WorldOrbit = (() => {
|
|
|
3022
4368
|
location: { line, column: tokens[0].column }
|
|
3023
4369
|
};
|
|
3024
4370
|
}
|
|
3025
|
-
function
|
|
3026
|
-
|
|
4371
|
+
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
4372
|
+
const fieldMap = collectDraftFields(node.fields);
|
|
4373
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4374
|
+
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
4375
|
+
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
4376
|
+
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
4377
|
+
const referencePlane = parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0]);
|
|
4378
|
+
const tidalLock = fieldMap.has("tidalLock") ? parseAtlasBoolean(singleFieldValue2(fieldMap.get("tidalLock")[0]), "tidalLock", fieldMap.get("tidalLock")[0].location) : void 0;
|
|
4379
|
+
const resonance = fieldMap.has("resonance") ? parseResonanceField(fieldMap.get("resonance")[0]) : void 0;
|
|
4380
|
+
const renderHints = extractRenderHints(fieldMap);
|
|
4381
|
+
const deriveRules = fieldMap.get("derive")?.map((field) => parseDeriveField(field));
|
|
4382
|
+
const validationRules = fieldMap.get("validate")?.map((field) => ({
|
|
4383
|
+
rule: singleFieldValue2(field)
|
|
4384
|
+
}));
|
|
4385
|
+
const lockedFields = fieldMap.has("locked") ? [...new Set(fieldMap.get("locked").flatMap((field) => field.values))] : void 0;
|
|
4386
|
+
const tolerances = fieldMap.get("tolerance")?.map((field) => parseToleranceField(field));
|
|
4387
|
+
const typedBlocks = normalizeTypedBlocks(node.typedBlockEntries);
|
|
4388
|
+
const info2 = normalizeInfoEntries(node.infoEntries, "info");
|
|
4389
|
+
const object = {
|
|
4390
|
+
type: node.objectType,
|
|
4391
|
+
id: node.id,
|
|
4392
|
+
properties,
|
|
4393
|
+
placement,
|
|
4394
|
+
info: info2
|
|
4395
|
+
};
|
|
4396
|
+
if (groups.length > 0)
|
|
4397
|
+
object.groups = groups;
|
|
4398
|
+
if (epoch)
|
|
4399
|
+
object.epoch = epoch;
|
|
4400
|
+
if (referencePlane)
|
|
4401
|
+
object.referencePlane = referencePlane;
|
|
4402
|
+
if (tidalLock !== void 0)
|
|
4403
|
+
object.tidalLock = tidalLock;
|
|
4404
|
+
if (resonance)
|
|
4405
|
+
object.resonance = resonance;
|
|
4406
|
+
if (renderHints)
|
|
4407
|
+
object.renderHints = renderHints;
|
|
4408
|
+
if (deriveRules?.length)
|
|
4409
|
+
object.deriveRules = deriveRules;
|
|
4410
|
+
if (validationRules?.length)
|
|
4411
|
+
object.validationRules = validationRules;
|
|
4412
|
+
if (lockedFields?.length)
|
|
4413
|
+
object.lockedFields = lockedFields;
|
|
4414
|
+
if (tolerances?.length)
|
|
4415
|
+
object.tolerances = tolerances;
|
|
4416
|
+
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
4417
|
+
object.typedBlocks = typedBlocks;
|
|
4418
|
+
if (sourceSchemaVersion !== "2.1") {
|
|
4419
|
+
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) {
|
|
4420
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
4421
|
+
}
|
|
4422
|
+
}
|
|
4423
|
+
return object;
|
|
3027
4424
|
}
|
|
3028
|
-
function
|
|
3029
|
-
return
|
|
4425
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
4426
|
+
return {
|
|
4427
|
+
...event,
|
|
4428
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
4429
|
+
tags: [...new Set(event.tags)],
|
|
4430
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
|
|
4431
|
+
};
|
|
4432
|
+
}
|
|
4433
|
+
function normalizeDraftEventPose(rawPose) {
|
|
4434
|
+
const fieldMap = collectDraftFields(rawPose.fields);
|
|
4435
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4436
|
+
return {
|
|
4437
|
+
objectId: rawPose.objectId,
|
|
4438
|
+
placement,
|
|
4439
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
4440
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer")
|
|
4441
|
+
};
|
|
4442
|
+
}
|
|
4443
|
+
function collectDraftFields(fields) {
|
|
4444
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4445
|
+
for (const field of fields) {
|
|
4446
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
4447
|
+
if (!spec) {
|
|
4448
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4449
|
+
}
|
|
4450
|
+
if (!spec.allowRepeat && grouped.has(field.key)) {
|
|
4451
|
+
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
4452
|
+
}
|
|
4453
|
+
const existing = grouped.get(field.key) ?? [];
|
|
4454
|
+
existing.push(field);
|
|
4455
|
+
grouped.set(field.key, existing);
|
|
4456
|
+
}
|
|
4457
|
+
return grouped;
|
|
4458
|
+
}
|
|
4459
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
4460
|
+
const orbitField = fieldMap.get("orbit")?.[0];
|
|
4461
|
+
const atField = fieldMap.get("at")?.[0];
|
|
4462
|
+
const surfaceField = fieldMap.get("surface")?.[0];
|
|
4463
|
+
const freeField = fieldMap.get("free")?.[0];
|
|
4464
|
+
const count = [orbitField, atField, surfaceField, freeField].filter(Boolean).length;
|
|
4465
|
+
if (count > 1) {
|
|
4466
|
+
const conflictingField = orbitField ?? atField ?? surfaceField ?? freeField;
|
|
4467
|
+
throw WorldOrbitError.fromLocation("Object has multiple placement modes", conflictingField?.location);
|
|
4468
|
+
}
|
|
4469
|
+
if (orbitField) {
|
|
4470
|
+
return {
|
|
4471
|
+
mode: "orbit",
|
|
4472
|
+
target: singleFieldValue2(orbitField),
|
|
4473
|
+
distance: parseOptionalUnitField(fieldMap.get("distance")?.[0], "distance"),
|
|
4474
|
+
semiMajor: parseOptionalUnitField(fieldMap.get("semiMajor")?.[0], "semiMajor"),
|
|
4475
|
+
eccentricity: parseOptionalNumberField(fieldMap.get("eccentricity")?.[0], "eccentricity"),
|
|
4476
|
+
period: parseOptionalUnitField(fieldMap.get("period")?.[0], "period"),
|
|
4477
|
+
angle: parseOptionalUnitField(fieldMap.get("angle")?.[0], "angle"),
|
|
4478
|
+
inclination: parseOptionalUnitField(fieldMap.get("inclination")?.[0], "inclination"),
|
|
4479
|
+
phase: parseOptionalUnitField(fieldMap.get("phase")?.[0], "phase")
|
|
4480
|
+
};
|
|
4481
|
+
}
|
|
4482
|
+
if (atField) {
|
|
4483
|
+
const target = singleFieldValue2(atField);
|
|
4484
|
+
return {
|
|
4485
|
+
mode: "at",
|
|
4486
|
+
target,
|
|
4487
|
+
reference: parseAtlasAtReference(target, atField.location)
|
|
4488
|
+
};
|
|
4489
|
+
}
|
|
4490
|
+
if (surfaceField) {
|
|
4491
|
+
return {
|
|
4492
|
+
mode: "surface",
|
|
4493
|
+
target: singleFieldValue2(surfaceField)
|
|
4494
|
+
};
|
|
4495
|
+
}
|
|
4496
|
+
if (freeField) {
|
|
4497
|
+
const raw = singleFieldValue2(freeField);
|
|
4498
|
+
const distance = tryParseAtlasUnitValue(raw);
|
|
4499
|
+
return {
|
|
4500
|
+
mode: "free",
|
|
4501
|
+
distance: distance ?? void 0,
|
|
4502
|
+
descriptor: distance ? void 0 : raw
|
|
4503
|
+
};
|
|
4504
|
+
}
|
|
4505
|
+
return null;
|
|
4506
|
+
}
|
|
4507
|
+
function normalizeDraftProperties(objectType, fieldMap) {
|
|
4508
|
+
const properties = {};
|
|
4509
|
+
for (const [key, fields] of fieldMap.entries()) {
|
|
4510
|
+
const field = fields[0];
|
|
4511
|
+
const spec = getDraftObjectFieldSpec(key);
|
|
4512
|
+
if (!field || !spec?.legacySchema || spec.legacySchema.placement) {
|
|
4513
|
+
continue;
|
|
4514
|
+
}
|
|
4515
|
+
ensureAtlasFieldSupported(key, objectType, field.location);
|
|
4516
|
+
properties[key] = normalizeLegacyScalarValue(key, field.values, field.location);
|
|
4517
|
+
}
|
|
4518
|
+
return properties;
|
|
4519
|
+
}
|
|
4520
|
+
function normalizeInfoEntries(entries, label) {
|
|
4521
|
+
const normalized = {};
|
|
4522
|
+
for (const entry of entries) {
|
|
4523
|
+
if (entry.key in normalized) {
|
|
4524
|
+
throw WorldOrbitError.fromLocation(`Duplicate ${label} key "${entry.key}"`, entry.location);
|
|
4525
|
+
}
|
|
4526
|
+
normalized[entry.key] = entry.value;
|
|
4527
|
+
}
|
|
4528
|
+
return normalized;
|
|
4529
|
+
}
|
|
4530
|
+
function normalizeTypedBlocks(typedBlockEntries) {
|
|
4531
|
+
const typedBlocks = {};
|
|
4532
|
+
for (const blockName of Object.keys(typedBlockEntries)) {
|
|
4533
|
+
const entries = typedBlockEntries[blockName];
|
|
4534
|
+
if (entries?.length) {
|
|
4535
|
+
typedBlocks[blockName] = normalizeInfoEntries(entries, blockName);
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
return typedBlocks;
|
|
4539
|
+
}
|
|
4540
|
+
function extractRenderHints(fieldMap) {
|
|
4541
|
+
const renderHints = {};
|
|
4542
|
+
const renderLabelField = fieldMap.get("renderLabel")?.[0];
|
|
4543
|
+
const renderOrbitField = fieldMap.get("renderOrbit")?.[0];
|
|
4544
|
+
const renderPriorityField = fieldMap.get("renderPriority")?.[0];
|
|
4545
|
+
if (renderLabelField) {
|
|
4546
|
+
renderHints.renderLabel = parseAtlasBoolean(singleFieldValue2(renderLabelField), "renderLabel", renderLabelField.location);
|
|
4547
|
+
}
|
|
4548
|
+
if (renderOrbitField) {
|
|
4549
|
+
renderHints.renderOrbit = parseAtlasBoolean(singleFieldValue2(renderOrbitField), "renderOrbit", renderOrbitField.location);
|
|
4550
|
+
}
|
|
4551
|
+
if (renderPriorityField) {
|
|
4552
|
+
renderHints.renderPriority = parseAtlasNumber(singleFieldValue2(renderPriorityField), "renderPriority", renderPriorityField.location);
|
|
4553
|
+
}
|
|
4554
|
+
return Object.keys(renderHints).length > 0 ? renderHints : void 0;
|
|
4555
|
+
}
|
|
4556
|
+
function parseResonanceField(field) {
|
|
4557
|
+
if (field.values.length !== 2) {
|
|
4558
|
+
throw WorldOrbitError.fromLocation('Field "resonance" expects "<targetObjectId> <ratio>"', field.location);
|
|
4559
|
+
}
|
|
4560
|
+
const ratio = field.values[1];
|
|
4561
|
+
if (!/^\d+:\d+$/.test(ratio)) {
|
|
4562
|
+
throw WorldOrbitError.fromLocation(`Invalid resonance ratio "${ratio}"`, field.location);
|
|
4563
|
+
}
|
|
4564
|
+
return {
|
|
4565
|
+
targetObjectId: field.values[0],
|
|
4566
|
+
ratio
|
|
4567
|
+
};
|
|
4568
|
+
}
|
|
4569
|
+
function parseDeriveField(field) {
|
|
4570
|
+
if (field.values.length !== 2) {
|
|
4571
|
+
throw WorldOrbitError.fromLocation('Field "derive" expects "<field> <strategy>"', field.location);
|
|
4572
|
+
}
|
|
4573
|
+
return {
|
|
4574
|
+
field: field.values[0],
|
|
4575
|
+
strategy: field.values[1]
|
|
4576
|
+
};
|
|
4577
|
+
}
|
|
4578
|
+
function parseToleranceField(field) {
|
|
4579
|
+
if (field.values.length !== 2) {
|
|
4580
|
+
throw WorldOrbitError.fromLocation('Field "tolerance" expects "<field> <value>"', field.location);
|
|
4581
|
+
}
|
|
4582
|
+
const rawValue = field.values[1];
|
|
4583
|
+
const unitValue = tryParseAtlasUnitValue(rawValue);
|
|
4584
|
+
const numericValue2 = Number(rawValue);
|
|
4585
|
+
return {
|
|
4586
|
+
field: field.values[0],
|
|
4587
|
+
value: unitValue ?? (Number.isFinite(numericValue2) ? numericValue2 : rawValue)
|
|
4588
|
+
};
|
|
4589
|
+
}
|
|
4590
|
+
function parseOptionalTokenList(field) {
|
|
4591
|
+
return field ? [...new Set(field.values)] : [];
|
|
4592
|
+
}
|
|
4593
|
+
function parseOptionalJoinedValue(field) {
|
|
4594
|
+
if (!field) {
|
|
4595
|
+
return null;
|
|
4596
|
+
}
|
|
4597
|
+
return field.values.join(" ").trim() || null;
|
|
4598
|
+
}
|
|
4599
|
+
function parseOptionalUnitField(field, key) {
|
|
4600
|
+
return field ? parseAtlasUnitValue(singleFieldValue2(field), field.location, key) : void 0;
|
|
4601
|
+
}
|
|
4602
|
+
function parseOptionalNumberField(field, key) {
|
|
4603
|
+
return field ? parseAtlasNumber(singleFieldValue2(field), key, field.location) : void 0;
|
|
4604
|
+
}
|
|
4605
|
+
function singleFieldValue2(field) {
|
|
4606
|
+
return singleAtlasValue(field.values, field.key, field.location);
|
|
4607
|
+
}
|
|
4608
|
+
function getDraftObjectFieldSpec(key) {
|
|
4609
|
+
return DRAFT_OBJECT_FIELD_SPECS.get(key);
|
|
4610
|
+
}
|
|
4611
|
+
function validateDraftObjectFieldCompatibility(fields, objectType) {
|
|
4612
|
+
for (const field of fields) {
|
|
4613
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
4614
|
+
if (!spec) {
|
|
4615
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4616
|
+
}
|
|
4617
|
+
if (spec.legacySchema) {
|
|
4618
|
+
ensureAtlasFieldSupported(field.key, objectType, field.location);
|
|
4619
|
+
continue;
|
|
4620
|
+
}
|
|
4621
|
+
if ((field.key === "renderLabel" || field.key === "renderOrbit" || field.key === "tidalLock") && field.values.length !== 1) {
|
|
4622
|
+
throw WorldOrbitError.fromLocation(`Field "${field.key}" expects exactly one value`, field.location);
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4625
|
+
}
|
|
4626
|
+
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
4627
|
+
if (sourceSchemaVersion === "2.1") {
|
|
4628
|
+
return;
|
|
4629
|
+
}
|
|
4630
|
+
diagnostics.push({
|
|
4631
|
+
code: "parse.schema21.featureCompatibility",
|
|
4632
|
+
severity: "warning",
|
|
4633
|
+
source: "parse",
|
|
4634
|
+
message: `Feature "${featureName}" requires schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
4635
|
+
line: location.line,
|
|
4636
|
+
column: location.column
|
|
4637
|
+
});
|
|
4638
|
+
}
|
|
4639
|
+
function preprocessAtlasSource(source) {
|
|
4640
|
+
const chars = [...source];
|
|
4641
|
+
const comments = [];
|
|
4642
|
+
let inString = false;
|
|
4643
|
+
let inBlockComment = false;
|
|
4644
|
+
let blockCommentStart = null;
|
|
4645
|
+
let line = 1;
|
|
4646
|
+
let column = 1;
|
|
4647
|
+
for (let index = 0; index < chars.length; index++) {
|
|
4648
|
+
const ch = chars[index];
|
|
4649
|
+
const next = chars[index + 1];
|
|
4650
|
+
if (inBlockComment) {
|
|
4651
|
+
if (ch === "*" && next === "/") {
|
|
4652
|
+
chars[index] = " ";
|
|
4653
|
+
chars[index + 1] = " ";
|
|
4654
|
+
inBlockComment = false;
|
|
4655
|
+
blockCommentStart = null;
|
|
4656
|
+
index++;
|
|
4657
|
+
column += 2;
|
|
4658
|
+
continue;
|
|
4659
|
+
}
|
|
4660
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
4661
|
+
chars[index] = " ";
|
|
4662
|
+
}
|
|
4663
|
+
if (ch === "\n") {
|
|
4664
|
+
line++;
|
|
4665
|
+
column = 1;
|
|
4666
|
+
} else {
|
|
4667
|
+
column++;
|
|
4668
|
+
}
|
|
4669
|
+
continue;
|
|
4670
|
+
}
|
|
4671
|
+
if (!inString && ch === "/" && next === "*") {
|
|
4672
|
+
comments.push({ kind: "block", line, column });
|
|
4673
|
+
chars[index] = " ";
|
|
4674
|
+
chars[index + 1] = " ";
|
|
4675
|
+
inBlockComment = true;
|
|
4676
|
+
blockCommentStart = { line, column };
|
|
4677
|
+
index++;
|
|
4678
|
+
column += 2;
|
|
4679
|
+
continue;
|
|
4680
|
+
}
|
|
4681
|
+
if (!inString && ch === "#" && !isHexColorLiteral(chars, index)) {
|
|
4682
|
+
comments.push({ kind: "line", line, column });
|
|
4683
|
+
chars[index] = " ";
|
|
4684
|
+
let inner = index + 1;
|
|
4685
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
4686
|
+
chars[inner] = " ";
|
|
4687
|
+
inner++;
|
|
4688
|
+
}
|
|
4689
|
+
column += inner - index;
|
|
4690
|
+
index = inner - 1;
|
|
4691
|
+
continue;
|
|
4692
|
+
}
|
|
4693
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
4694
|
+
inString = !inString;
|
|
4695
|
+
}
|
|
4696
|
+
if (ch === "\n") {
|
|
4697
|
+
line++;
|
|
4698
|
+
column = 1;
|
|
4699
|
+
} else {
|
|
4700
|
+
column++;
|
|
4701
|
+
}
|
|
4702
|
+
}
|
|
4703
|
+
if (inBlockComment) {
|
|
4704
|
+
throw WorldOrbitError.fromLocation("Unclosed block comment", blockCommentStart ?? void 0);
|
|
4705
|
+
}
|
|
4706
|
+
return {
|
|
4707
|
+
source: chars.join(""),
|
|
4708
|
+
comments
|
|
4709
|
+
};
|
|
4710
|
+
}
|
|
4711
|
+
function isHexColorLiteral(chars, start) {
|
|
4712
|
+
let index = start + 1;
|
|
4713
|
+
let length = 0;
|
|
4714
|
+
while (index < chars.length && /[0-9a-f]/i.test(chars[index] ?? "")) {
|
|
4715
|
+
index++;
|
|
4716
|
+
length++;
|
|
4717
|
+
}
|
|
4718
|
+
if (![3, 4, 6, 8].includes(length)) {
|
|
4719
|
+
return false;
|
|
4720
|
+
}
|
|
4721
|
+
const next = chars[index];
|
|
4722
|
+
return next === void 0 || next === " " || next === " " || next === "\r" || next === "\n";
|
|
3030
4723
|
}
|
|
3031
4724
|
|
|
3032
4725
|
// packages/core/dist/load.js
|
|
3033
|
-
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0)?$/i;
|
|
4726
|
+
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|
|
4727
|
+
var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
3034
4728
|
var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
3035
4729
|
function detectWorldOrbitSchemaVersion(source) {
|
|
3036
|
-
for (const line of source.split(/\r?\n/)) {
|
|
4730
|
+
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
3037
4731
|
const trimmed = line.trim();
|
|
3038
4732
|
if (!trimmed) {
|
|
3039
4733
|
continue;
|
|
@@ -3041,6 +4735,9 @@ var WorldOrbit = (() => {
|
|
|
3041
4735
|
if (LEGACY_DRAFT_SCHEMA_PATTERN.test(trimmed)) {
|
|
3042
4736
|
return "2.0-draft";
|
|
3043
4737
|
}
|
|
4738
|
+
if (ATLAS_SCHEMA_21_PATTERN.test(trimmed)) {
|
|
4739
|
+
return "2.1";
|
|
4740
|
+
}
|
|
3044
4741
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
3045
4742
|
return "2.0";
|
|
3046
4743
|
}
|
|
@@ -3048,6 +4745,49 @@ var WorldOrbit = (() => {
|
|
|
3048
4745
|
}
|
|
3049
4746
|
return "1.0";
|
|
3050
4747
|
}
|
|
4748
|
+
function stripCommentsForSchemaDetection(source) {
|
|
4749
|
+
const chars = [...source];
|
|
4750
|
+
let inString = false;
|
|
4751
|
+
let inBlockComment = false;
|
|
4752
|
+
for (let index = 0; index < chars.length; index++) {
|
|
4753
|
+
const ch = chars[index];
|
|
4754
|
+
const next = chars[index + 1];
|
|
4755
|
+
if (inBlockComment) {
|
|
4756
|
+
if (ch === "*" && next === "/") {
|
|
4757
|
+
chars[index] = " ";
|
|
4758
|
+
chars[index + 1] = " ";
|
|
4759
|
+
inBlockComment = false;
|
|
4760
|
+
index++;
|
|
4761
|
+
continue;
|
|
4762
|
+
}
|
|
4763
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
4764
|
+
chars[index] = " ";
|
|
4765
|
+
}
|
|
4766
|
+
continue;
|
|
4767
|
+
}
|
|
4768
|
+
if (!inString && ch === "/" && next === "*") {
|
|
4769
|
+
chars[index] = " ";
|
|
4770
|
+
chars[index + 1] = " ";
|
|
4771
|
+
inBlockComment = true;
|
|
4772
|
+
index++;
|
|
4773
|
+
continue;
|
|
4774
|
+
}
|
|
4775
|
+
if (!inString && ch === "#") {
|
|
4776
|
+
chars[index] = " ";
|
|
4777
|
+
let inner = index + 1;
|
|
4778
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
4779
|
+
chars[inner] = " ";
|
|
4780
|
+
inner++;
|
|
4781
|
+
}
|
|
4782
|
+
index = inner - 1;
|
|
4783
|
+
continue;
|
|
4784
|
+
}
|
|
4785
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
4786
|
+
inString = !inString;
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
return chars.join("");
|
|
4790
|
+
}
|
|
3051
4791
|
function loadWorldOrbitSource(source) {
|
|
3052
4792
|
const result = loadWorldOrbitSourceWithDiagnostics(source);
|
|
3053
4793
|
if (!result.ok || !result.value) {
|
|
@@ -3058,36 +4798,36 @@ var WorldOrbit = (() => {
|
|
|
3058
4798
|
}
|
|
3059
4799
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
3060
4800
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
3061
|
-
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft") {
|
|
4801
|
+
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1") {
|
|
3062
4802
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
3063
4803
|
}
|
|
3064
4804
|
let ast;
|
|
3065
4805
|
try {
|
|
3066
4806
|
ast = parseWorldOrbit(source);
|
|
3067
|
-
} catch (
|
|
4807
|
+
} catch (error2) {
|
|
3068
4808
|
return {
|
|
3069
4809
|
ok: false,
|
|
3070
4810
|
value: null,
|
|
3071
|
-
diagnostics: [diagnosticFromError(
|
|
4811
|
+
diagnostics: [diagnosticFromError(error2, "parse")]
|
|
3072
4812
|
};
|
|
3073
4813
|
}
|
|
3074
4814
|
let document2;
|
|
3075
4815
|
try {
|
|
3076
4816
|
document2 = normalizeDocument(ast);
|
|
3077
|
-
} catch (
|
|
4817
|
+
} catch (error2) {
|
|
3078
4818
|
return {
|
|
3079
4819
|
ok: false,
|
|
3080
4820
|
value: null,
|
|
3081
|
-
diagnostics: [diagnosticFromError(
|
|
4821
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
3082
4822
|
};
|
|
3083
4823
|
}
|
|
3084
4824
|
try {
|
|
3085
4825
|
validateDocument(document2);
|
|
3086
|
-
} catch (
|
|
4826
|
+
} catch (error2) {
|
|
3087
4827
|
return {
|
|
3088
4828
|
ok: false,
|
|
3089
4829
|
value: null,
|
|
3090
|
-
diagnostics: [diagnosticFromError(
|
|
4830
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
3091
4831
|
};
|
|
3092
4832
|
}
|
|
3093
4833
|
return {
|
|
@@ -3107,30 +4847,29 @@ var WorldOrbit = (() => {
|
|
|
3107
4847
|
let atlasDocument;
|
|
3108
4848
|
try {
|
|
3109
4849
|
atlasDocument = parseWorldOrbitAtlas(source);
|
|
3110
|
-
} catch (
|
|
4850
|
+
} catch (error2) {
|
|
3111
4851
|
return {
|
|
3112
4852
|
ok: false,
|
|
3113
4853
|
value: null,
|
|
3114
|
-
diagnostics: [diagnosticFromError(
|
|
4854
|
+
diagnostics: [diagnosticFromError(error2, "parse", "load.atlas.failed")]
|
|
3115
4855
|
};
|
|
3116
4856
|
}
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
document2 = materializeAtlasDocument(atlasDocument);
|
|
3120
|
-
} catch (error) {
|
|
4857
|
+
const atlasDiagnostics = [...atlasDocument.diagnostics];
|
|
4858
|
+
if (atlasDiagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
3121
4859
|
return {
|
|
3122
4860
|
ok: false,
|
|
3123
4861
|
value: null,
|
|
3124
|
-
diagnostics:
|
|
4862
|
+
diagnostics: atlasDiagnostics
|
|
3125
4863
|
};
|
|
3126
4864
|
}
|
|
4865
|
+
let document2;
|
|
3127
4866
|
try {
|
|
3128
|
-
|
|
3129
|
-
} catch (
|
|
4867
|
+
document2 = materializeAtlasDocument(atlasDocument);
|
|
4868
|
+
} catch (error2) {
|
|
3130
4869
|
return {
|
|
3131
4870
|
ok: false,
|
|
3132
4871
|
value: null,
|
|
3133
|
-
diagnostics: [diagnosticFromError(
|
|
4872
|
+
diagnostics: [diagnosticFromError(error2, "normalize", "load.atlas.materialize.failed")]
|
|
3134
4873
|
};
|
|
3135
4874
|
}
|
|
3136
4875
|
const loaded = {
|
|
@@ -3139,12 +4878,12 @@ var WorldOrbit = (() => {
|
|
|
3139
4878
|
document: document2,
|
|
3140
4879
|
atlasDocument,
|
|
3141
4880
|
draftDocument: atlasDocument,
|
|
3142
|
-
diagnostics:
|
|
4881
|
+
diagnostics: atlasDiagnostics
|
|
3143
4882
|
};
|
|
3144
4883
|
return {
|
|
3145
4884
|
ok: true,
|
|
3146
4885
|
value: loaded,
|
|
3147
|
-
diagnostics:
|
|
4886
|
+
diagnostics: atlasDiagnostics
|
|
3148
4887
|
};
|
|
3149
4888
|
}
|
|
3150
4889
|
|
|
@@ -3152,6 +4891,8 @@ var WorldOrbit = (() => {
|
|
|
3152
4891
|
var DEFAULT_LAYERS = {
|
|
3153
4892
|
background: true,
|
|
3154
4893
|
guides: true,
|
|
4894
|
+
relations: true,
|
|
4895
|
+
events: true,
|
|
3155
4896
|
orbits: true,
|
|
3156
4897
|
objects: true,
|
|
3157
4898
|
labels: true,
|
|
@@ -3166,6 +4907,7 @@ var WorldOrbit = (() => {
|
|
|
3166
4907
|
backgroundGlow: "rgba(240, 180, 100, 0.18)",
|
|
3167
4908
|
panel: "rgba(7, 17, 27, 0.9)",
|
|
3168
4909
|
panelLine: "rgba(168, 207, 242, 0.18)",
|
|
4910
|
+
relation: "rgba(240, 180, 100, 0.42)",
|
|
3169
4911
|
orbit: "rgba(163, 209, 255, 0.24)",
|
|
3170
4912
|
orbitBand: "rgba(255, 190, 120, 0.28)",
|
|
3171
4913
|
guide: "rgba(255, 255, 255, 0.04)",
|
|
@@ -3188,6 +4930,7 @@ var WorldOrbit = (() => {
|
|
|
3188
4930
|
backgroundGlow: "rgba(120, 255, 215, 0.16)",
|
|
3189
4931
|
panel: "rgba(7, 20, 30, 0.9)",
|
|
3190
4932
|
panelLine: "rgba(120, 255, 215, 0.16)",
|
|
4933
|
+
relation: "rgba(156, 231, 255, 0.42)",
|
|
3191
4934
|
orbit: "rgba(120, 255, 215, 0.2)",
|
|
3192
4935
|
orbitBand: "rgba(137, 185, 255, 0.24)",
|
|
3193
4936
|
guide: "rgba(255, 255, 255, 0.035)",
|
|
@@ -3210,6 +4953,7 @@ var WorldOrbit = (() => {
|
|
|
3210
4953
|
backgroundGlow: "rgba(255, 127, 95, 0.18)",
|
|
3211
4954
|
panel: "rgba(24, 9, 13, 0.9)",
|
|
3212
4955
|
panelLine: "rgba(255, 166, 149, 0.16)",
|
|
4956
|
+
relation: "rgba(255, 178, 125, 0.42)",
|
|
3213
4957
|
orbit: "rgba(255, 188, 164, 0.22)",
|
|
3214
4958
|
orbitBand: "rgba(255, 214, 139, 0.24)",
|
|
3215
4959
|
guide: "rgba(255, 255, 255, 0.03)",
|
|
@@ -3291,7 +5035,11 @@ var WorldOrbit = (() => {
|
|
|
3291
5035
|
return false;
|
|
3292
5036
|
}
|
|
3293
5037
|
if (filter.groupIds?.length && (!object.groupId || !filter.groupIds.includes(object.groupId))) {
|
|
3294
|
-
|
|
5038
|
+
const hasSemanticMatch = object.semanticGroupIds.length > 0 && filter.groupIds.some((groupId) => object.semanticGroupIds.includes(groupId));
|
|
5039
|
+
const hasLegacyMatch = Boolean(object.groupId && filter.groupIds.includes(object.groupId));
|
|
5040
|
+
if (!hasSemanticMatch && !hasLegacyMatch) {
|
|
5041
|
+
return false;
|
|
5042
|
+
}
|
|
3295
5043
|
}
|
|
3296
5044
|
if (filter.tags?.length) {
|
|
3297
5045
|
const objectTags = Array.isArray(object.object.properties.tags) ? object.object.properties.tags.filter((entry) => typeof entry === "string") : [];
|
|
@@ -3347,6 +5095,8 @@ var WorldOrbit = (() => {
|
|
|
3347
5095
|
const imageDefinitions = buildImageDefinitions(visibleObjects);
|
|
3348
5096
|
const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
|
|
3349
5097
|
const leaderMarkup = layers.guides ? scene.leaders.filter((leader) => !leader.hidden).filter((leader) => visibleObjectIds.has(leader.objectId)).filter((leader) => layers.structures || !isStructureLike(leader.object)).map((leader) => `<line class="wo-leader wo-leader-${leader.mode}" x1="${leader.x1}" y1="${leader.y1}" x2="${leader.x2}" y2="${leader.y2}" data-render-id="${escapeXml(leader.renderId)}" data-group-id="${escapeAttribute(leader.groupId ?? "")}" />`).join("") : "";
|
|
5098
|
+
const relationMarkup = layers.relations ? scene.relations.filter((relation) => !relation.hidden).filter((relation) => visibleObjectIds.has(relation.fromObjectId) && visibleObjectIds.has(relation.toObjectId)).map((relation) => `<line class="wo-relation" x1="${relation.x1}" y1="${relation.y1}" x2="${relation.x2}" y2="${relation.y2}" data-render-id="${escapeXml(relation.renderId)}" data-relation-id="${escapeAttribute(relation.relationId)}" />`).join("") : "";
|
|
5099
|
+
const eventMarkup = layers.events ? scene.events.filter((event) => !event.hidden).map((event) => renderSceneEventOverlay(scene, event, visibleObjectIds, theme)).join("") : "";
|
|
3350
5100
|
const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
|
|
3351
5101
|
const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
|
|
3352
5102
|
const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
|
|
@@ -3381,6 +5131,10 @@ var WorldOrbit = (() => {
|
|
|
3381
5131
|
.wo-orbit-back { opacity: 0.38; stroke-dasharray: 8 6; }
|
|
3382
5132
|
.wo-orbit-front { opacity: 0.9; }
|
|
3383
5133
|
.wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
|
|
5134
|
+
.wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
|
|
5135
|
+
.wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
|
|
5136
|
+
.wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
|
|
5137
|
+
.wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
3384
5138
|
.wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
|
|
3385
5139
|
.wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
|
|
3386
5140
|
.wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
|
|
@@ -3414,6 +5168,8 @@ var WorldOrbit = (() => {
|
|
|
3414
5168
|
<g data-worldorbit-world-content="true">
|
|
3415
5169
|
${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
|
|
3416
5170
|
${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
|
|
5171
|
+
${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
|
|
5172
|
+
${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
|
|
3417
5173
|
${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
|
|
3418
5174
|
${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
|
|
3419
5175
|
${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
|
|
@@ -3421,6 +5177,20 @@ var WorldOrbit = (() => {
|
|
|
3421
5177
|
</g>
|
|
3422
5178
|
</g>
|
|
3423
5179
|
</svg>`;
|
|
5180
|
+
}
|
|
5181
|
+
function renderSceneEventOverlay(scene, event, visibleObjectIds, theme) {
|
|
5182
|
+
const participants = event.objectIds.filter((objectId) => visibleObjectIds.has(objectId)).map((objectId) => scene.objects.find((object) => object.objectId === objectId && !object.hidden)).filter(Boolean);
|
|
5183
|
+
if (participants.length === 0) {
|
|
5184
|
+
return "";
|
|
5185
|
+
}
|
|
5186
|
+
const stroke = event.event.color || theme.accent;
|
|
5187
|
+
const label = event.event.label || event.event.id;
|
|
5188
|
+
const lineMarkup = participants.map((object) => `<line class="wo-event-line" x1="${event.x}" y1="${event.y}" x2="${object.x}" y2="${object.y}" stroke="${escapeAttribute(stroke)}" data-event-id="${escapeAttribute(event.eventId)}" data-object-id="${escapeAttribute(object.objectId)}" />`).join("");
|
|
5189
|
+
return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
|
|
5190
|
+
${lineMarkup}
|
|
5191
|
+
<circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
|
|
5192
|
+
<text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
|
|
5193
|
+
</g>`;
|
|
3424
5194
|
}
|
|
3425
5195
|
function renderOrbitLayer(scene, visibleObjectIds, includeStructures) {
|
|
3426
5196
|
const backParts = [];
|
|
@@ -3457,10 +5227,11 @@ var WorldOrbit = (() => {
|
|
|
3457
5227
|
function renderSceneObject(sceneObject, selectedObjectId, theme) {
|
|
3458
5228
|
const { object, x, y, radius, visualRadius } = sceneObject;
|
|
3459
5229
|
const selectionClass = selectedObjectId === sceneObject.objectId ? " wo-object-selected" : "";
|
|
5230
|
+
const kindClass = object.properties.kind ? ` wo-kind-${String(object.properties.kind).toLowerCase().replace(/[^a-z0-9-]/g, "-")}` : "";
|
|
3460
5231
|
const palette = resolveObjectPalette(sceneObject, theme);
|
|
3461
5232
|
const imageMarkup = renderObjectImage(sceneObject);
|
|
3462
5233
|
const outlineMarkup = imageMarkup ? renderObjectBody(object, x, y, radius, palette, { outlineOnly: true }) : "";
|
|
3463
|
-
return `<g class="wo-object wo-object-${object.type}${selectionClass}" data-object-id="${escapeXml(sceneObject.objectId)}" data-parent-id="${escapeAttribute(sceneObject.parentId ?? "")}" data-group-id="${escapeAttribute(sceneObject.groupId ?? "")}" data-render-id="${escapeXml(sceneObject.renderId)}" tabindex="0" role="button" aria-label="${escapeXml(`${object.type} ${sceneObject.objectId}`)}">
|
|
5234
|
+
return `<g class="wo-object wo-object-${object.type}${kindClass}${selectionClass}" data-object-id="${escapeXml(sceneObject.objectId)}" data-parent-id="${escapeAttribute(sceneObject.parentId ?? "")}" data-group-id="${escapeAttribute(sceneObject.groupId ?? "")}" data-render-id="${escapeXml(sceneObject.renderId)}" tabindex="0" role="button" aria-label="${escapeXml(`${object.type} ${sceneObject.objectId}`)}">
|
|
3464
5235
|
<circle class="wo-selection-ring" cx="${x}" cy="${y}" r="${visualRadius + 8}" />
|
|
3465
5236
|
${renderAtmosphere(sceneObject, palette)}
|
|
3466
5237
|
${renderObjectBody(object, x, y, radius, palette)}
|
|
@@ -3494,8 +5265,33 @@ var WorldOrbit = (() => {
|
|
|
3494
5265
|
<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
3495
5266
|
case "structure":
|
|
3496
5267
|
return `<polygon points="${diamondPoints(x, y, radius)}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
3497
|
-
case "phenomenon":
|
|
5268
|
+
case "phenomenon": {
|
|
5269
|
+
const kind = String(object.properties.kind ?? "").toLowerCase().replace(/_/g, "-");
|
|
5270
|
+
if (options.outlineOnly) {
|
|
5271
|
+
if (kind === "black-hole" || kind === "nebula" || kind === "galaxy" || kind === "dwarf-galaxy") {
|
|
5272
|
+
return `<circle cx="${x}" cy="${y}" r="${radius}" fill="transparent" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
5273
|
+
}
|
|
5274
|
+
return `<polygon points="${phenomenonPoints(x, y, radius)}" fill="transparent" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
5275
|
+
}
|
|
5276
|
+
if (kind === "black-hole") {
|
|
5277
|
+
return `<ellipse cx="${x}" cy="${y}" rx="${radius * 2.4}" ry="${radius * 0.55}" fill="none" stroke="${palette.accentRing ?? palette.stroke}" stroke-width="3.5" />
|
|
5278
|
+
<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" stroke="${palette.stroke}" stroke-width="2" />`;
|
|
5279
|
+
}
|
|
5280
|
+
if (kind === "galaxy") {
|
|
5281
|
+
return `<ellipse cx="${x}" cy="${y}" rx="${radius * 2.6}" ry="${radius}" fill="${palette.halo ?? "none"}" stroke="none" />
|
|
5282
|
+
<ellipse cx="${x}" cy="${y}" rx="${radius * 1.5}" ry="${radius * 0.42}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.2" />
|
|
5283
|
+
<circle cx="${x}" cy="${y}" r="${radius * 0.28}" fill="${palette.core ?? "#fff"}" stroke="none" />`;
|
|
5284
|
+
}
|
|
5285
|
+
if (kind === "dwarf-galaxy") {
|
|
5286
|
+
return `<ellipse cx="${x}" cy="${y}" rx="${radius * 1.6}" ry="${radius * 0.55}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1" />
|
|
5287
|
+
<circle cx="${x}" cy="${y}" r="${radius * 0.25}" fill="${palette.core ?? "#fff"}" stroke="none" />`;
|
|
5288
|
+
}
|
|
5289
|
+
if (kind === "nebula") {
|
|
5290
|
+
return `<circle cx="${x}" cy="${y}" r="${radius * 2.2}" fill="${palette.halo ?? "none"}" stroke="none" />
|
|
5291
|
+
<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1" />`;
|
|
5292
|
+
}
|
|
3498
5293
|
return `<polygon points="${phenomenonPoints(x, y, radius)}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
5294
|
+
}
|
|
3499
5295
|
}
|
|
3500
5296
|
}
|
|
3501
5297
|
function renderAtmosphere(sceneObject, palette) {
|
|
@@ -3564,7 +5360,8 @@ var WorldOrbit = (() => {
|
|
|
3564
5360
|
}
|
|
3565
5361
|
}
|
|
3566
5362
|
function resolveObjectPalette(sceneObject, theme) {
|
|
3567
|
-
const
|
|
5363
|
+
const kind = String(sceneObject.object.properties.kind ?? "").toLowerCase().replace(/_/g, "-");
|
|
5364
|
+
const base = basePaletteForType(sceneObject.object.type, kind, theme);
|
|
3568
5365
|
const customFill = sceneObject.fillColor && isColorLike(sceneObject.fillColor) ? sceneObject.fillColor : base.fill;
|
|
3569
5366
|
const albedo = numericValue(sceneObject.object.properties.albedo);
|
|
3570
5367
|
const temperature = numericValue(sceneObject.object.properties.temperature);
|
|
@@ -3580,7 +5377,7 @@ var WorldOrbit = (() => {
|
|
|
3580
5377
|
tail: sceneObject.object.type === "comet" ? rgbaString(mixColors(fill, "#ffffff", 0.5) ?? fill, 0.72) : void 0
|
|
3581
5378
|
};
|
|
3582
5379
|
}
|
|
3583
|
-
function basePaletteForType(type, theme) {
|
|
5380
|
+
function basePaletteForType(type, kind, theme) {
|
|
3584
5381
|
switch (type) {
|
|
3585
5382
|
case "star":
|
|
3586
5383
|
return {
|
|
@@ -3602,8 +5399,26 @@ var WorldOrbit = (() => {
|
|
|
3602
5399
|
case "structure":
|
|
3603
5400
|
return { fill: theme.accentStrong, stroke: "#fff2ea" };
|
|
3604
5401
|
case "phenomenon":
|
|
3605
|
-
return
|
|
5402
|
+
return kindPhenomenonPalette(kind);
|
|
5403
|
+
}
|
|
5404
|
+
}
|
|
5405
|
+
function kindPhenomenonPalette(kind) {
|
|
5406
|
+
if (kind === "galaxy") {
|
|
5407
|
+
return { fill: "rgba(165,125,255,0.55)", stroke: "rgba(210,185,255,0.75)", halo: "rgba(160,120,255,0.10)", core: "#ede0ff" };
|
|
5408
|
+
}
|
|
5409
|
+
if (kind === "dwarf-galaxy") {
|
|
5410
|
+
return { fill: "rgba(190,165,255,0.45)", stroke: "rgba(220,205,255,0.75)", core: "#ddd0ff" };
|
|
5411
|
+
}
|
|
5412
|
+
if (kind === "black-hole") {
|
|
5413
|
+
return { fill: "#040408", stroke: "#ff6a00", accentRing: "rgba(255,140,20,0.72)" };
|
|
5414
|
+
}
|
|
5415
|
+
if (kind === "nebula") {
|
|
5416
|
+
return { fill: "rgba(105,205,255,0.45)", stroke: "rgba(180,235,255,0.72)", halo: "rgba(100,200,255,0.08)" };
|
|
5417
|
+
}
|
|
5418
|
+
if (kind === "void") {
|
|
5419
|
+
return { fill: "#05080f", stroke: "rgba(130,160,255,0.4)" };
|
|
3606
5420
|
}
|
|
5421
|
+
return { fill: "#78ffd7", stroke: "#e9fff7" };
|
|
3607
5422
|
}
|
|
3608
5423
|
function applyTemperatureAndAlbedo(baseColor, temperature, albedo, type) {
|
|
3609
5424
|
let nextColor = baseColor;
|
|
@@ -3870,11 +5685,11 @@ var WorldOrbit = (() => {
|
|
|
3870
5685
|
});
|
|
3871
5686
|
}
|
|
3872
5687
|
return `<figure class="${escapeAttribute3(options.className ?? "worldorbit-block worldorbit-static")}">${renderSceneToSvg(scene, options)}</figure>`;
|
|
3873
|
-
} catch (
|
|
5688
|
+
} catch (error2) {
|
|
3874
5689
|
if (options.strict) {
|
|
3875
|
-
throw
|
|
5690
|
+
throw error2;
|
|
3876
5691
|
}
|
|
3877
|
-
return renderWorldOrbitError(
|
|
5692
|
+
return renderWorldOrbitError(error2 instanceof Error ? error2.message : String(error2));
|
|
3878
5693
|
}
|
|
3879
5694
|
}
|
|
3880
5695
|
function renderWorldOrbitError(message) {
|
|
@@ -3975,5 +5790,5 @@ var WorldOrbit = (() => {
|
|
|
3975
5790
|
}
|
|
3976
5791
|
return (node.children ?? []).map((child) => collectText(child)).join("");
|
|
3977
5792
|
}
|
|
3978
|
-
return __toCommonJS(
|
|
5793
|
+
return __toCommonJS(index_exports);
|
|
3979
5794
|
})();
|