worldorbit 2.5.17 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -15
- package/dist/browser/core/dist/index.js +502 -61
- package/dist/browser/editor/dist/index.js +619 -71
- package/dist/browser/markdown/dist/index.js +464 -51
- package/dist/browser/viewer/dist/index.js +495 -62
- package/dist/unpkg/core/dist/index.js +502 -61
- package/dist/unpkg/editor/dist/index.js +619 -71
- package/dist/unpkg/markdown/dist/index.js +464 -51
- package/dist/unpkg/viewer/dist/index.js +495 -62
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +208 -198
- package/dist/unpkg/worldorbit-markdown.min.js +38 -38
- package/dist/unpkg/worldorbit-viewer.min.js +56 -56
- package/dist/unpkg/worldorbit.js +533 -72
- package/dist/unpkg/worldorbit.min.js +60 -60
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.js +1 -1
- package/packages/core/dist/atlas-validate.js +99 -10
- package/packages/core/dist/draft-parse.js +190 -15
- package/packages/core/dist/draft.js +50 -11
- package/packages/core/dist/format.js +36 -5
- package/packages/core/dist/load.js +9 -2
- package/packages/core/dist/scene.js +158 -24
- package/packages/core/dist/types.d.ts +19 -2
- package/packages/editor/dist/editor.js +105 -4
- package/packages/viewer/dist/atlas-state.js +5 -2
- package/packages/viewer/dist/atlas-viewer.js +19 -8
- package/packages/viewer/dist/types.d.ts +5 -2
- package/packages/viewer/dist/viewer.js +16 -0
|
@@ -948,7 +948,9 @@ var WorldOrbit = (() => {
|
|
|
948
948
|
const height = frame.height;
|
|
949
949
|
const padding = frame.padding;
|
|
950
950
|
const layoutPreset = resolveLayoutPreset(document2);
|
|
951
|
-
const
|
|
951
|
+
const schemaProjection = resolveProjection(document2, options.projection);
|
|
952
|
+
const camera = normalizeViewCamera(options.camera ?? null);
|
|
953
|
+
const renderProjection = resolveRenderProjection(schemaProjection, camera);
|
|
952
954
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
953
955
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
954
956
|
const systemId = document2.system?.id ?? null;
|
|
@@ -991,7 +993,7 @@ var WorldOrbit = (() => {
|
|
|
991
993
|
surfaceChildren,
|
|
992
994
|
objectMap,
|
|
993
995
|
spacingFactor,
|
|
994
|
-
projection,
|
|
996
|
+
projection: renderProjection,
|
|
995
997
|
scaleModel
|
|
996
998
|
};
|
|
997
999
|
const primaryRoot = rootObjects.find((object) => object.type === "star") ?? rootObjects[0] ?? null;
|
|
@@ -1003,7 +1005,7 @@ var WorldOrbit = (() => {
|
|
|
1003
1005
|
const rootRingRadius = Math.min(width, height) * 0.28 * spacingFactor * scaleModel.orbitDistanceMultiplier;
|
|
1004
1006
|
secondaryRoots.forEach((object, index) => {
|
|
1005
1007
|
const angle = angleForIndex(index, secondaryRoots.length, -Math.PI / 2);
|
|
1006
|
-
const offset = projectPolarOffset(angle, rootRingRadius,
|
|
1008
|
+
const offset = projectPolarOffset(angle, rootRingRadius, renderProjection, 1);
|
|
1007
1009
|
placeObject(object, centerX + offset.x, centerY + offset.y, 0, positions, orbitDrafts, leaderDrafts, context);
|
|
1008
1010
|
});
|
|
1009
1011
|
}
|
|
@@ -1065,27 +1067,34 @@ var WorldOrbit = (() => {
|
|
|
1065
1067
|
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1066
1068
|
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1067
1069
|
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1068
|
-
const viewpoints = createSceneViewpoints(document2,
|
|
1070
|
+
const viewpoints = createSceneViewpoints(document2, schemaProjection, frame.preset, relationships, objectMap);
|
|
1069
1071
|
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1070
1072
|
return {
|
|
1071
1073
|
width,
|
|
1072
1074
|
height,
|
|
1073
1075
|
padding,
|
|
1074
1076
|
renderPreset: frame.preset,
|
|
1075
|
-
projection,
|
|
1077
|
+
projection: schemaProjection,
|
|
1078
|
+
renderProjection,
|
|
1079
|
+
camera,
|
|
1076
1080
|
scaleModel,
|
|
1077
1081
|
title: String(document2.system?.title ?? document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1078
|
-
subtitle:
|
|
1082
|
+
subtitle: buildSceneSubtitle(schemaProjection, renderProjection, layoutPreset, camera),
|
|
1079
1083
|
systemId,
|
|
1080
|
-
viewMode:
|
|
1084
|
+
viewMode: schemaProjection,
|
|
1081
1085
|
layoutPreset,
|
|
1082
1086
|
metadata: {
|
|
1083
1087
|
format: document2.format,
|
|
1084
1088
|
version: document2.version,
|
|
1085
|
-
view:
|
|
1089
|
+
view: schemaProjection,
|
|
1090
|
+
renderProjection,
|
|
1086
1091
|
scale: String(document2.system?.properties.scale ?? layoutPreset),
|
|
1087
1092
|
units: String(document2.system?.properties.units ?? "mixed"),
|
|
1088
|
-
preset: frame.preset ?? "custom"
|
|
1093
|
+
preset: frame.preset ?? "custom",
|
|
1094
|
+
...camera?.azimuth !== null ? { "camera.azimuth": String(camera?.azimuth) } : {},
|
|
1095
|
+
...camera?.elevation !== null ? { "camera.elevation": String(camera?.elevation) } : {},
|
|
1096
|
+
...camera?.roll !== null ? { "camera.roll": String(camera?.roll) } : {},
|
|
1097
|
+
...camera?.distance !== null ? { "camera.distance": String(camera?.distance) } : {}
|
|
1089
1098
|
},
|
|
1090
1099
|
contentBounds,
|
|
1091
1100
|
layers,
|
|
@@ -1111,21 +1120,42 @@ var WorldOrbit = (() => {
|
|
|
1111
1120
|
return cloned;
|
|
1112
1121
|
}
|
|
1113
1122
|
const objectMap = new Map(cloned.map((object) => [object.id, object]));
|
|
1123
|
+
const referencedIds = /* @__PURE__ */ new Set([
|
|
1124
|
+
...activeEvent.targetObjectId ? [activeEvent.targetObjectId] : [],
|
|
1125
|
+
...activeEvent.participantObjectIds,
|
|
1126
|
+
...activeEvent.positions.map((pose) => pose.objectId)
|
|
1127
|
+
]);
|
|
1128
|
+
for (const objectId of referencedIds) {
|
|
1129
|
+
const object = objectMap.get(objectId);
|
|
1130
|
+
if (!object) {
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
if (activeEvent.epoch) {
|
|
1134
|
+
object.epoch = activeEvent.epoch;
|
|
1135
|
+
}
|
|
1136
|
+
if (activeEvent.referencePlane) {
|
|
1137
|
+
object.referencePlane = activeEvent.referencePlane;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1114
1140
|
for (const pose of activeEvent.positions) {
|
|
1115
1141
|
const object = objectMap.get(pose.objectId);
|
|
1116
1142
|
if (!object) {
|
|
1117
1143
|
continue;
|
|
1118
1144
|
}
|
|
1119
|
-
|
|
1145
|
+
if (pose.placement) {
|
|
1146
|
+
object.placement = structuredClone(pose.placement);
|
|
1147
|
+
}
|
|
1120
1148
|
if (pose.inner) {
|
|
1121
1149
|
object.properties.inner = { ...pose.inner };
|
|
1122
|
-
} else {
|
|
1123
|
-
delete object.properties.inner;
|
|
1124
1150
|
}
|
|
1125
1151
|
if (pose.outer) {
|
|
1126
1152
|
object.properties.outer = { ...pose.outer };
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1153
|
+
}
|
|
1154
|
+
if (pose.epoch) {
|
|
1155
|
+
object.epoch = pose.epoch;
|
|
1156
|
+
}
|
|
1157
|
+
if (pose.referencePlane) {
|
|
1158
|
+
object.referencePlane = pose.referencePlane;
|
|
1129
1159
|
}
|
|
1130
1160
|
}
|
|
1131
1161
|
return cloned;
|
|
@@ -1166,10 +1196,59 @@ var WorldOrbit = (() => {
|
|
|
1166
1196
|
}
|
|
1167
1197
|
}
|
|
1168
1198
|
function resolveProjection(document2, projection) {
|
|
1169
|
-
if (projection === "topdown" || projection === "isometric") {
|
|
1199
|
+
if (projection === "topdown" || projection === "isometric" || projection === "orthographic" || projection === "perspective") {
|
|
1170
1200
|
return projection;
|
|
1171
1201
|
}
|
|
1172
|
-
|
|
1202
|
+
const documentView = String(document2.system?.properties.view ?? "topdown").toLowerCase();
|
|
1203
|
+
return parseViewProjection(documentView) ?? "topdown";
|
|
1204
|
+
}
|
|
1205
|
+
function resolveRenderProjection(projection, camera) {
|
|
1206
|
+
switch (projection) {
|
|
1207
|
+
case "topdown":
|
|
1208
|
+
return "topdown";
|
|
1209
|
+
case "isometric":
|
|
1210
|
+
return "isometric";
|
|
1211
|
+
case "orthographic":
|
|
1212
|
+
return camera && (camera.azimuth !== null || camera.elevation !== null || camera.roll !== null) ? "isometric" : "topdown";
|
|
1213
|
+
case "perspective":
|
|
1214
|
+
return "isometric";
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
function normalizeViewCamera(camera) {
|
|
1218
|
+
if (!camera) {
|
|
1219
|
+
return null;
|
|
1220
|
+
}
|
|
1221
|
+
const normalized = {
|
|
1222
|
+
azimuth: normalizeFiniteCameraValue(camera.azimuth),
|
|
1223
|
+
elevation: normalizeFiniteCameraValue(camera.elevation),
|
|
1224
|
+
roll: normalizeFiniteCameraValue(camera.roll),
|
|
1225
|
+
distance: normalizePositiveCameraDistance(camera.distance)
|
|
1226
|
+
};
|
|
1227
|
+
return normalized.azimuth !== null || normalized.elevation !== null || normalized.roll !== null || normalized.distance !== null ? normalized : null;
|
|
1228
|
+
}
|
|
1229
|
+
function normalizeFiniteCameraValue(value) {
|
|
1230
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1231
|
+
}
|
|
1232
|
+
function normalizePositiveCameraDistance(value) {
|
|
1233
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
|
1234
|
+
}
|
|
1235
|
+
function buildSceneSubtitle(projection, renderProjection, layoutPreset, camera) {
|
|
1236
|
+
const parts = [`${capitalizeLabel(projection)} view`, `${capitalizeLabel(layoutPreset)} layout`];
|
|
1237
|
+
if (projection !== renderProjection) {
|
|
1238
|
+
parts.push(`2D ${renderProjection} fallback`);
|
|
1239
|
+
}
|
|
1240
|
+
if (camera) {
|
|
1241
|
+
const cameraParts = [
|
|
1242
|
+
camera.azimuth !== null ? `az ${camera.azimuth}` : null,
|
|
1243
|
+
camera.elevation !== null ? `el ${camera.elevation}` : null,
|
|
1244
|
+
camera.roll !== null ? `roll ${camera.roll}` : null,
|
|
1245
|
+
camera.distance !== null ? `dist ${camera.distance}` : null
|
|
1246
|
+
].filter(Boolean);
|
|
1247
|
+
if (cameraParts.length > 0) {
|
|
1248
|
+
parts.push(`camera ${cameraParts.join(" / ")}`);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return parts.join(" - ");
|
|
1173
1252
|
}
|
|
1174
1253
|
function resolveScaleModel(layoutPreset, overrides) {
|
|
1175
1254
|
const defaults = defaultScaleModel(layoutPreset);
|
|
@@ -1605,6 +1684,8 @@ var WorldOrbit = (() => {
|
|
|
1605
1684
|
function createGeneratedOverviewViewpoint(document2, projection, preset) {
|
|
1606
1685
|
const title = document2.system?.title ?? document2.system?.properties.title;
|
|
1607
1686
|
const label = title ? `${String(title)} Overview` : "Overview";
|
|
1687
|
+
const camera = normalizeViewCamera(null);
|
|
1688
|
+
const renderProjection = resolveRenderProjection(projection, camera);
|
|
1608
1689
|
return {
|
|
1609
1690
|
id: "overview",
|
|
1610
1691
|
label,
|
|
@@ -1613,6 +1694,8 @@ var WorldOrbit = (() => {
|
|
|
1613
1694
|
selectedObjectId: null,
|
|
1614
1695
|
eventIds: [],
|
|
1615
1696
|
projection,
|
|
1697
|
+
renderProjection,
|
|
1698
|
+
camera,
|
|
1616
1699
|
preset,
|
|
1617
1700
|
rotationDeg: 0,
|
|
1618
1701
|
scale: null,
|
|
@@ -1662,6 +1745,30 @@ var WorldOrbit = (() => {
|
|
|
1662
1745
|
case "angle":
|
|
1663
1746
|
draft.rotationDeg = parseFiniteNumber(normalizedValue) ?? draft.rotationDeg ?? 0;
|
|
1664
1747
|
return;
|
|
1748
|
+
case "camera.azimuth":
|
|
1749
|
+
draft.camera = {
|
|
1750
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
1751
|
+
azimuth: parseFiniteNumber(normalizedValue)
|
|
1752
|
+
};
|
|
1753
|
+
return;
|
|
1754
|
+
case "camera.elevation":
|
|
1755
|
+
draft.camera = {
|
|
1756
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
1757
|
+
elevation: parseFiniteNumber(normalizedValue)
|
|
1758
|
+
};
|
|
1759
|
+
return;
|
|
1760
|
+
case "camera.roll":
|
|
1761
|
+
draft.camera = {
|
|
1762
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
1763
|
+
roll: parseFiniteNumber(normalizedValue)
|
|
1764
|
+
};
|
|
1765
|
+
return;
|
|
1766
|
+
case "camera.distance":
|
|
1767
|
+
draft.camera = {
|
|
1768
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
1769
|
+
distance: parsePositiveNumber(normalizedValue)
|
|
1770
|
+
};
|
|
1771
|
+
return;
|
|
1665
1772
|
case "zoom":
|
|
1666
1773
|
case "scale":
|
|
1667
1774
|
draft.scale = parsePositiveNumber(normalizedValue);
|
|
@@ -1701,6 +1808,9 @@ var WorldOrbit = (() => {
|
|
|
1701
1808
|
const selectedObjectId = draft.select && objectMap.has(draft.select) ? draft.select : objectId;
|
|
1702
1809
|
const filter = normalizeViewpointFilter(draft.filter);
|
|
1703
1810
|
const label = draft.label?.trim() || humanizeIdentifier(draft.id);
|
|
1811
|
+
const resolvedProjection = draft.projection ?? projection;
|
|
1812
|
+
const camera = normalizeViewCamera(draft.camera ?? null);
|
|
1813
|
+
const renderProjection = resolveRenderProjection(resolvedProjection, camera);
|
|
1704
1814
|
return {
|
|
1705
1815
|
id: draft.id,
|
|
1706
1816
|
label,
|
|
@@ -1708,7 +1818,9 @@ var WorldOrbit = (() => {
|
|
|
1708
1818
|
objectId,
|
|
1709
1819
|
selectedObjectId,
|
|
1710
1820
|
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
1711
|
-
projection:
|
|
1821
|
+
projection: resolvedProjection,
|
|
1822
|
+
renderProjection,
|
|
1823
|
+
camera,
|
|
1712
1824
|
preset: draft.preset ?? preset,
|
|
1713
1825
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
1714
1826
|
scale: draft.scale ?? null,
|
|
@@ -1725,6 +1837,14 @@ var WorldOrbit = (() => {
|
|
|
1725
1837
|
groupIds: []
|
|
1726
1838
|
};
|
|
1727
1839
|
}
|
|
1840
|
+
function createEmptyViewCamera() {
|
|
1841
|
+
return {
|
|
1842
|
+
azimuth: null,
|
|
1843
|
+
elevation: null,
|
|
1844
|
+
roll: null,
|
|
1845
|
+
distance: null
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1728
1848
|
function normalizeViewpointFilter(filter) {
|
|
1729
1849
|
if (!filter) {
|
|
1730
1850
|
return null;
|
|
@@ -1738,7 +1858,18 @@ var WorldOrbit = (() => {
|
|
|
1738
1858
|
return normalized.query || normalized.objectTypes.length > 0 || normalized.tags.length > 0 || normalized.groupIds.length > 0 ? normalized : null;
|
|
1739
1859
|
}
|
|
1740
1860
|
function parseViewProjection(value) {
|
|
1741
|
-
|
|
1861
|
+
switch (value.toLowerCase()) {
|
|
1862
|
+
case "topdown":
|
|
1863
|
+
return "topdown";
|
|
1864
|
+
case "isometric":
|
|
1865
|
+
return "isometric";
|
|
1866
|
+
case "orthographic":
|
|
1867
|
+
return "orthographic";
|
|
1868
|
+
case "perspective":
|
|
1869
|
+
return "perspective";
|
|
1870
|
+
default:
|
|
1871
|
+
return null;
|
|
1872
|
+
}
|
|
1742
1873
|
}
|
|
1743
1874
|
function parseRenderPreset(value) {
|
|
1744
1875
|
const normalized = value.toLowerCase();
|
|
@@ -1776,7 +1907,7 @@ var WorldOrbit = (() => {
|
|
|
1776
1907
|
}
|
|
1777
1908
|
function parseViewpointGroups(value, document2, relationships, objectMap) {
|
|
1778
1909
|
return splitListValue(value).map((entry) => {
|
|
1779
|
-
if (document2.schemaVersion === "2.1" || document2.groups.some((group) => group.id === entry)) {
|
|
1910
|
+
if (document2.schemaVersion === "2.1" || document2.schemaVersion === "2.5" || document2.groups.some((group) => group.id === entry)) {
|
|
1780
1911
|
return entry;
|
|
1781
1912
|
}
|
|
1782
1913
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
@@ -2608,7 +2739,9 @@ var WorldOrbit = (() => {
|
|
|
2608
2739
|
objectId: pose.objectId,
|
|
2609
2740
|
placement: clonePlacement(pose.placement),
|
|
2610
2741
|
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
2611
|
-
outer: pose.outer ? { ...pose.outer } : void 0
|
|
2742
|
+
outer: pose.outer ? { ...pose.outer } : void 0,
|
|
2743
|
+
epoch: pose.epoch ?? null,
|
|
2744
|
+
referencePlane: pose.referencePlane ?? null
|
|
2612
2745
|
};
|
|
2613
2746
|
}
|
|
2614
2747
|
function clonePlacement(placement) {
|
|
@@ -2623,21 +2756,42 @@ var WorldOrbit = (() => {
|
|
|
2623
2756
|
return;
|
|
2624
2757
|
}
|
|
2625
2758
|
const objectMap = new Map(objects.map((object) => [object.id, object]));
|
|
2759
|
+
const referencedIds = /* @__PURE__ */ new Set([
|
|
2760
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
2761
|
+
...event.participantObjectIds,
|
|
2762
|
+
...event.positions.map((pose) => pose.objectId)
|
|
2763
|
+
]);
|
|
2764
|
+
for (const objectId of referencedIds) {
|
|
2765
|
+
const object = objectMap.get(objectId);
|
|
2766
|
+
if (!object) {
|
|
2767
|
+
continue;
|
|
2768
|
+
}
|
|
2769
|
+
if (event.epoch) {
|
|
2770
|
+
object.epoch = event.epoch;
|
|
2771
|
+
}
|
|
2772
|
+
if (event.referencePlane) {
|
|
2773
|
+
object.referencePlane = event.referencePlane;
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2626
2776
|
for (const pose of event.positions) {
|
|
2627
2777
|
const object = objectMap.get(pose.objectId);
|
|
2628
2778
|
if (!object) {
|
|
2629
2779
|
continue;
|
|
2630
2780
|
}
|
|
2631
|
-
|
|
2781
|
+
if (pose.placement) {
|
|
2782
|
+
object.placement = clonePlacement(pose.placement);
|
|
2783
|
+
}
|
|
2632
2784
|
if (pose.inner) {
|
|
2633
2785
|
object.properties.inner = { ...pose.inner };
|
|
2634
|
-
} else {
|
|
2635
|
-
delete object.properties.inner;
|
|
2636
2786
|
}
|
|
2637
2787
|
if (pose.outer) {
|
|
2638
2788
|
object.properties.outer = { ...pose.outer };
|
|
2639
|
-
}
|
|
2640
|
-
|
|
2789
|
+
}
|
|
2790
|
+
if (pose.epoch) {
|
|
2791
|
+
object.epoch = pose.epoch;
|
|
2792
|
+
}
|
|
2793
|
+
if (pose.referencePlane) {
|
|
2794
|
+
object.referencePlane = pose.referencePlane;
|
|
2641
2795
|
}
|
|
2642
2796
|
}
|
|
2643
2797
|
}
|
|
@@ -2713,6 +2867,18 @@ var WorldOrbit = (() => {
|
|
|
2713
2867
|
if (viewpoint.rotationDeg !== 0) {
|
|
2714
2868
|
info2[`${prefix}.rotation`] = String(viewpoint.rotationDeg);
|
|
2715
2869
|
}
|
|
2870
|
+
if (viewpoint.camera?.azimuth !== null) {
|
|
2871
|
+
info2[`${prefix}.camera.azimuth`] = String(viewpoint.camera?.azimuth);
|
|
2872
|
+
}
|
|
2873
|
+
if (viewpoint.camera?.elevation !== null) {
|
|
2874
|
+
info2[`${prefix}.camera.elevation`] = String(viewpoint.camera?.elevation);
|
|
2875
|
+
}
|
|
2876
|
+
if (viewpoint.camera?.roll !== null) {
|
|
2877
|
+
info2[`${prefix}.camera.roll`] = String(viewpoint.camera?.roll);
|
|
2878
|
+
}
|
|
2879
|
+
if (viewpoint.camera?.distance !== null) {
|
|
2880
|
+
info2[`${prefix}.camera.distance`] = String(viewpoint.camera?.distance);
|
|
2881
|
+
}
|
|
2716
2882
|
const serializedLayers = serializeViewpointLayers(viewpoint.layers);
|
|
2717
2883
|
if (serializedLayers) {
|
|
2718
2884
|
info2[`${prefix}.layers`] = serializedLayers;
|
|
@@ -2956,13 +3122,13 @@ var WorldOrbit = (() => {
|
|
|
2956
3122
|
validateRelation(relation, objectMap, diagnostics);
|
|
2957
3123
|
}
|
|
2958
3124
|
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
2959
|
-
validateViewpoint(viewpoint
|
|
3125
|
+
validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap);
|
|
2960
3126
|
}
|
|
2961
3127
|
for (const object of document2.objects) {
|
|
2962
3128
|
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
2963
3129
|
}
|
|
2964
3130
|
for (const event of document2.events) {
|
|
2965
|
-
validateEvent(event, objectMap, diagnostics);
|
|
3131
|
+
validateEvent(event, document2.system, objectMap, diagnostics);
|
|
2966
3132
|
}
|
|
2967
3133
|
return diagnostics;
|
|
2968
3134
|
}
|
|
@@ -2981,21 +3147,24 @@ var WorldOrbit = (() => {
|
|
|
2981
3147
|
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
2982
3148
|
}
|
|
2983
3149
|
}
|
|
2984
|
-
function validateViewpoint(
|
|
2985
|
-
|
|
3150
|
+
function validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap) {
|
|
3151
|
+
const filter = viewpoint.filter;
|
|
3152
|
+
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5") {
|
|
2986
3153
|
if (filter) {
|
|
2987
3154
|
for (const groupId of filter.groupIds) {
|
|
2988
3155
|
if (!groupIds.has(groupId)) {
|
|
2989
|
-
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${
|
|
3156
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpoint.id}".`, void 0, `viewpoint.${viewpoint.id}.groups`));
|
|
2990
3157
|
}
|
|
2991
3158
|
}
|
|
2992
3159
|
}
|
|
2993
|
-
for (const eventId of
|
|
3160
|
+
for (const eventId of viewpoint.events ?? []) {
|
|
2994
3161
|
if (!eventIds.has(eventId)) {
|
|
2995
|
-
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${
|
|
3162
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpoint.id}".`, void 0, `viewpoint.${viewpoint.id}.events`));
|
|
2996
3163
|
}
|
|
2997
3164
|
}
|
|
2998
3165
|
}
|
|
3166
|
+
validateProjection(viewpoint.projection, diagnostics, `viewpoint.${viewpoint.id}.projection`, viewpoint.id);
|
|
3167
|
+
validateCamera(viewpoint.camera, viewpoint.projection, viewpoint.rotationDeg, diagnostics, viewpoint.id, viewpoint.focusObjectId, viewpoint.selectedObjectId, filter, objectMap);
|
|
2999
3168
|
}
|
|
3000
3169
|
function validateObject(object, system, objectMap, groupIds, diagnostics) {
|
|
3001
3170
|
const placement = object.placement;
|
|
@@ -3008,6 +3177,12 @@ var WorldOrbit = (() => {
|
|
|
3008
3177
|
}
|
|
3009
3178
|
}
|
|
3010
3179
|
}
|
|
3180
|
+
if (typeof object.epoch === "string" && !object.epoch.trim()) {
|
|
3181
|
+
diagnostics.push(warn("validate.epoch.empty", `Object "${object.id}" defines an empty epoch string.`, object.id, "epoch"));
|
|
3182
|
+
}
|
|
3183
|
+
if (typeof object.referencePlane === "string" && !object.referencePlane.trim()) {
|
|
3184
|
+
diagnostics.push(warn("validate.referencePlane.empty", `Object "${object.id}" defines an empty reference plane string.`, object.id, "referencePlane"));
|
|
3185
|
+
}
|
|
3011
3186
|
if (orbitPlacement) {
|
|
3012
3187
|
if (!objectMap.has(orbitPlacement.target)) {
|
|
3013
3188
|
diagnostics.push(error("validate.orbit.target.unknown", `Unknown placement target "${orbitPlacement.target}" on "${object.id}".`, object.id, "orbit"));
|
|
@@ -3079,12 +3254,18 @@ var WorldOrbit = (() => {
|
|
|
3079
3254
|
}
|
|
3080
3255
|
}
|
|
3081
3256
|
}
|
|
3082
|
-
function validateEvent(event, objectMap, diagnostics) {
|
|
3257
|
+
function validateEvent(event, system, objectMap, diagnostics) {
|
|
3083
3258
|
const fieldPrefix = `event.${event.id}`;
|
|
3084
3259
|
const referencedIds = /* @__PURE__ */ new Set();
|
|
3085
3260
|
if (!event.kind.trim()) {
|
|
3086
3261
|
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
3087
3262
|
}
|
|
3263
|
+
if (typeof event.epoch === "string" && !event.epoch.trim()) {
|
|
3264
|
+
diagnostics.push(warn("validate.event.epoch.empty", `Event "${event.id}" defines an empty epoch string.`, void 0, `${fieldPrefix}.epoch`));
|
|
3265
|
+
}
|
|
3266
|
+
if (typeof event.referencePlane === "string" && !event.referencePlane.trim()) {
|
|
3267
|
+
diagnostics.push(warn("validate.event.referencePlane.empty", `Event "${event.id}" defines an empty reference plane string.`, void 0, `${fieldPrefix}.referencePlane`));
|
|
3268
|
+
}
|
|
3088
3269
|
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3089
3270
|
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3090
3271
|
}
|
|
@@ -3131,10 +3312,14 @@ var WorldOrbit = (() => {
|
|
|
3131
3312
|
if (!referencedIds.has(pose.objectId)) {
|
|
3132
3313
|
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
3133
3314
|
}
|
|
3134
|
-
validateEventPose(pose, object, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
3315
|
+
validateEventPose(pose, object, event, system, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
3316
|
+
}
|
|
3317
|
+
const missingPoseIds = [...referencedIds].filter((objectId) => !poseIds.has(objectId));
|
|
3318
|
+
if (event.positions.length > 0 && missingPoseIds.length > 0) {
|
|
3319
|
+
diagnostics.push(warn("validate.event.positions.partial", `Event "${event.id}" leaves ${missingPoseIds.length} referenced object(s) on their base placement.`, void 0, `${fieldPrefix}.positions`));
|
|
3135
3320
|
}
|
|
3136
3321
|
}
|
|
3137
|
-
function validateEventPose(pose, object, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3322
|
+
function validateEventPose(pose, object, event, system, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3138
3323
|
const placement = pose.placement;
|
|
3139
3324
|
if (!placement) {
|
|
3140
3325
|
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
@@ -3147,6 +3332,15 @@ var WorldOrbit = (() => {
|
|
|
3147
3332
|
if (placement.distance && placement.semiMajor) {
|
|
3148
3333
|
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
3149
3334
|
}
|
|
3335
|
+
if (placement.phase && !resolveEffectiveEpoch(system, object, event, pose)) {
|
|
3336
|
+
diagnostics.push(warn("validate.event.pose.phase.epochMissing", `Event "${eventId}" pose "${pose.objectId}" sets "phase" without an effective epoch.`, void 0, `${fieldPrefix}.phase`));
|
|
3337
|
+
}
|
|
3338
|
+
if (placement.inclination && !resolveEffectiveReferencePlane(system, object, event, pose)) {
|
|
3339
|
+
diagnostics.push(warn("validate.event.pose.inclination.referencePlaneMissing", `Event "${eventId}" pose "${pose.objectId}" sets "inclination" without an effective reference plane.`, void 0, `${fieldPrefix}.inclination`));
|
|
3340
|
+
}
|
|
3341
|
+
if (placement.period && !massInSolar(objectMap.get(placement.target)?.properties.mass)) {
|
|
3342
|
+
diagnostics.push(warn("validate.event.pose.period.massMissing", `Event "${eventId}" pose "${pose.objectId}" sets "period" but its central mass cannot be derived.`, void 0, `${fieldPrefix}.period`));
|
|
3343
|
+
}
|
|
3150
3344
|
return;
|
|
3151
3345
|
}
|
|
3152
3346
|
if (placement.mode === "surface") {
|
|
@@ -3281,6 +3475,52 @@ var WorldOrbit = (() => {
|
|
|
3281
3475
|
return null;
|
|
3282
3476
|
}
|
|
3283
3477
|
}
|
|
3478
|
+
function validateProjection(projection, diagnostics, field, viewpointId) {
|
|
3479
|
+
if (projection !== "topdown" && projection !== "isometric" && projection !== "orthographic" && projection !== "perspective") {
|
|
3480
|
+
diagnostics.push(error("validate.viewpoint.projection.invalid", `Unknown projection "${String(projection)}" in viewpoint "${viewpointId}".`, void 0, field));
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
function validateCamera(camera, projection, rotationDeg, diagnostics, viewpointId, focusObjectId, selectedObjectId, filter, objectMap) {
|
|
3484
|
+
if (!camera) {
|
|
3485
|
+
return;
|
|
3486
|
+
}
|
|
3487
|
+
const prefix = `viewpoint.${viewpointId}.camera`;
|
|
3488
|
+
for (const [key, value] of [
|
|
3489
|
+
["azimuth", camera.azimuth],
|
|
3490
|
+
["elevation", camera.elevation],
|
|
3491
|
+
["roll", camera.roll],
|
|
3492
|
+
["distance", camera.distance]
|
|
3493
|
+
]) {
|
|
3494
|
+
if (value !== null && (!Number.isFinite(value) || key === "distance" && value <= 0)) {
|
|
3495
|
+
diagnostics.push(error("validate.viewpoint.camera.invalid", `Invalid camera ${key} "${String(value)}" in viewpoint "${viewpointId}".`, void 0, `${prefix}.${key}`));
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
if (camera.distance !== null && projection !== "perspective") {
|
|
3499
|
+
diagnostics.push(warn("validate.viewpoint.camera.distance.partialEffect", `Camera "distance" only has a semantic effect in perspective viewpoints; "${viewpointId}" uses "${projection}".`, void 0, `${prefix}.distance`));
|
|
3500
|
+
}
|
|
3501
|
+
if (projection === "topdown" && (camera.elevation !== null || camera.roll !== null)) {
|
|
3502
|
+
diagnostics.push(warn("validate.viewpoint.camera.topdownPartial", `Camera elevation/roll on topdown viewpoint "${viewpointId}" are currently stored for future 3D use and only partially affect 2D rendering.`, void 0, prefix));
|
|
3503
|
+
}
|
|
3504
|
+
if (projection === "isometric" && camera.elevation !== null) {
|
|
3505
|
+
diagnostics.push(info("validate.viewpoint.camera.isometricStored", `Camera elevation on isometric viewpoint "${viewpointId}" is preserved semantically for future 3D rendering.`, void 0, `${prefix}.elevation`));
|
|
3506
|
+
}
|
|
3507
|
+
if (camera.azimuth !== null && camera.azimuth !== 0 && rotationDeg !== 0) {
|
|
3508
|
+
diagnostics.push(warn("validate.viewpoint.rotation.cameraOverlap", `Viewpoint "${viewpointId}" uses camera.azimuth; keep "rotation" only for 2D screen rotation to avoid ambiguity.`, void 0, `${prefix}.azimuth`));
|
|
3509
|
+
}
|
|
3510
|
+
const hasAnchor = focusObjectId !== null && objectMap.has(focusObjectId) || selectedObjectId !== null && objectMap.has(selectedObjectId) || !!filter;
|
|
3511
|
+
if (!hasAnchor) {
|
|
3512
|
+
diagnostics.push(info("validate.viewpoint.camera.anchorMissing", `Viewpoint "${viewpointId}" stores camera settings without a focus object, selection, or filter anchor.`, void 0, prefix));
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
function resolveEffectiveEpoch(system, object, event, pose) {
|
|
3516
|
+
return normalizeOptionalContextString(pose?.epoch) ?? normalizeOptionalContextString(event?.epoch) ?? normalizeOptionalContextString(object.epoch) ?? normalizeOptionalContextString(system?.epoch) ?? null;
|
|
3517
|
+
}
|
|
3518
|
+
function resolveEffectiveReferencePlane(system, object, event, pose) {
|
|
3519
|
+
return normalizeOptionalContextString(pose?.referencePlane) ?? normalizeOptionalContextString(event?.referencePlane) ?? normalizeOptionalContextString(object.referencePlane) ?? normalizeOptionalContextString(system?.referencePlane) ?? null;
|
|
3520
|
+
}
|
|
3521
|
+
function normalizeOptionalContextString(value) {
|
|
3522
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
3523
|
+
}
|
|
3284
3524
|
function toleranceForField(object, field) {
|
|
3285
3525
|
const tolerance = object.tolerances?.find((entry) => entry.field === field)?.value;
|
|
3286
3526
|
if (typeof tolerance === "number") {
|
|
@@ -3389,7 +3629,9 @@ var WorldOrbit = (() => {
|
|
|
3389
3629
|
"surface",
|
|
3390
3630
|
"free",
|
|
3391
3631
|
"inner",
|
|
3392
|
-
"outer"
|
|
3632
|
+
"outer",
|
|
3633
|
+
"epoch",
|
|
3634
|
+
"referencePlane"
|
|
3393
3635
|
]);
|
|
3394
3636
|
function parseWorldOrbitAtlas(source) {
|
|
3395
3637
|
return parseAtlasSource(source);
|
|
@@ -3431,7 +3673,7 @@ var WorldOrbit = (() => {
|
|
|
3431
3673
|
if (!sawSchemaHeader) {
|
|
3432
3674
|
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
3433
3675
|
sawSchemaHeader = true;
|
|
3434
|
-
if (prepared.comments.length > 0 && sourceSchemaVersion
|
|
3676
|
+
if (prepared.comments.length > 0 && isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
3435
3677
|
diagnostics.push({
|
|
3436
3678
|
code: "parse.schema21.commentCompatibility",
|
|
3437
3679
|
severity: "warning",
|
|
@@ -3501,11 +3743,11 @@ var WorldOrbit = (() => {
|
|
|
3501
3743
|
return document2;
|
|
3502
3744
|
}
|
|
3503
3745
|
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);
|
|
3746
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1", "2.5"].includes(tokens[1].value.toLowerCase())) {
|
|
3747
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
3506
3748
|
}
|
|
3507
3749
|
const version = tokens[1].value.toLowerCase();
|
|
3508
|
-
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3750
|
+
return version === "2.5" ? "2.5" : version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3509
3751
|
}
|
|
3510
3752
|
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3511
3753
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
@@ -3525,6 +3767,8 @@ var WorldOrbit = (() => {
|
|
|
3525
3767
|
return {
|
|
3526
3768
|
kind: "defaults",
|
|
3527
3769
|
system,
|
|
3770
|
+
sourceSchemaVersion,
|
|
3771
|
+
diagnostics,
|
|
3528
3772
|
seenFields: /* @__PURE__ */ new Set()
|
|
3529
3773
|
};
|
|
3530
3774
|
case "atlas":
|
|
@@ -3617,6 +3861,7 @@ var WorldOrbit = (() => {
|
|
|
3617
3861
|
preset: system.defaults.preset,
|
|
3618
3862
|
zoom: null,
|
|
3619
3863
|
rotationDeg: 0,
|
|
3864
|
+
camera: null,
|
|
3620
3865
|
layers: {},
|
|
3621
3866
|
filter: null
|
|
3622
3867
|
};
|
|
@@ -3630,7 +3875,10 @@ var WorldOrbit = (() => {
|
|
|
3630
3875
|
seenFields: /* @__PURE__ */ new Set(),
|
|
3631
3876
|
inFilter: false,
|
|
3632
3877
|
filterIndent: null,
|
|
3633
|
-
seenFilterFields: /* @__PURE__ */ new Set()
|
|
3878
|
+
seenFilterFields: /* @__PURE__ */ new Set(),
|
|
3879
|
+
inCamera: false,
|
|
3880
|
+
cameraIndent: null,
|
|
3881
|
+
seenCameraFields: /* @__PURE__ */ new Set()
|
|
3634
3882
|
};
|
|
3635
3883
|
}
|
|
3636
3884
|
function startAnnotationSection(tokens, line, system, annotationIds) {
|
|
@@ -3737,6 +3985,8 @@ var WorldOrbit = (() => {
|
|
|
3737
3985
|
participantObjectIds: [],
|
|
3738
3986
|
timing: null,
|
|
3739
3987
|
visibility: null,
|
|
3988
|
+
epoch: null,
|
|
3989
|
+
referencePlane: null,
|
|
3740
3990
|
tags: [],
|
|
3741
3991
|
color: null,
|
|
3742
3992
|
hidden: false,
|
|
@@ -3861,6 +4111,12 @@ var WorldOrbit = (() => {
|
|
|
3861
4111
|
const value = joinFieldValue(tokens, line);
|
|
3862
4112
|
switch (key) {
|
|
3863
4113
|
case "view":
|
|
4114
|
+
if (isSchema25Projection(value)) {
|
|
4115
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "defaults.view", {
|
|
4116
|
+
line,
|
|
4117
|
+
column: tokens[0].column
|
|
4118
|
+
});
|
|
4119
|
+
}
|
|
3864
4120
|
section.system.defaults.view = parseProjectionValue(value, line, tokens[0].column);
|
|
3865
4121
|
return;
|
|
3866
4122
|
case "scale":
|
|
@@ -3900,14 +4156,36 @@ var WorldOrbit = (() => {
|
|
|
3900
4156
|
throw new WorldOrbitError(`Unknown atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3901
4157
|
}
|
|
3902
4158
|
function applyViewpointField2(section, indent, tokens, line) {
|
|
4159
|
+
if (section.inCamera && indent <= (section.cameraIndent ?? 0)) {
|
|
4160
|
+
section.inCamera = false;
|
|
4161
|
+
section.cameraIndent = null;
|
|
4162
|
+
}
|
|
3903
4163
|
if (section.inFilter && indent <= (section.filterIndent ?? 0)) {
|
|
3904
4164
|
section.inFilter = false;
|
|
3905
4165
|
section.filterIndent = null;
|
|
3906
4166
|
}
|
|
4167
|
+
if (section.inCamera) {
|
|
4168
|
+
applyViewpointCameraField(section, tokens, line);
|
|
4169
|
+
return;
|
|
4170
|
+
}
|
|
3907
4171
|
if (section.inFilter) {
|
|
3908
4172
|
applyViewpointFilterField(section, tokens, line);
|
|
3909
4173
|
return;
|
|
3910
4174
|
}
|
|
4175
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "camera") {
|
|
4176
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.camera", {
|
|
4177
|
+
line,
|
|
4178
|
+
column: tokens[0].column
|
|
4179
|
+
});
|
|
4180
|
+
if (section.seenFields.has("camera")) {
|
|
4181
|
+
throw new WorldOrbitError('Duplicate viewpoint field "camera"', line, tokens[0].column);
|
|
4182
|
+
}
|
|
4183
|
+
section.seenFields.add("camera");
|
|
4184
|
+
section.inCamera = true;
|
|
4185
|
+
section.cameraIndent = indent;
|
|
4186
|
+
section.viewpoint.camera = section.viewpoint.camera ?? createEmptyViewCamera2();
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
3911
4189
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "filter") {
|
|
3912
4190
|
if (section.seenFields.has("filter")) {
|
|
3913
4191
|
throw new WorldOrbitError('Duplicate viewpoint field "filter"', line, tokens[0].column);
|
|
@@ -3933,6 +4211,12 @@ var WorldOrbit = (() => {
|
|
|
3933
4211
|
section.viewpoint.selectedObjectId = value;
|
|
3934
4212
|
return;
|
|
3935
4213
|
case "projection":
|
|
4214
|
+
if (isSchema25Projection(value)) {
|
|
4215
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "projection", {
|
|
4216
|
+
line,
|
|
4217
|
+
column: tokens[0].column
|
|
4218
|
+
});
|
|
4219
|
+
}
|
|
3936
4220
|
section.viewpoint.projection = parseProjectionValue(value, line, tokens[0].column);
|
|
3937
4221
|
return;
|
|
3938
4222
|
case "preset":
|
|
@@ -3944,6 +4228,13 @@ var WorldOrbit = (() => {
|
|
|
3944
4228
|
case "rotation":
|
|
3945
4229
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
3946
4230
|
return;
|
|
4231
|
+
case "camera":
|
|
4232
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.camera", {
|
|
4233
|
+
line,
|
|
4234
|
+
column: tokens[0].column
|
|
4235
|
+
});
|
|
4236
|
+
section.viewpoint.camera = parseInlineViewCamera(tokens.slice(1), line, section.viewpoint.camera);
|
|
4237
|
+
return;
|
|
3947
4238
|
case "layers":
|
|
3948
4239
|
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
3949
4240
|
return;
|
|
@@ -3958,6 +4249,28 @@ var WorldOrbit = (() => {
|
|
|
3958
4249
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3959
4250
|
}
|
|
3960
4251
|
}
|
|
4252
|
+
function applyViewpointCameraField(section, tokens, line) {
|
|
4253
|
+
const key = requireUniqueField(tokens, section.seenCameraFields, line);
|
|
4254
|
+
const value = joinFieldValue(tokens, line);
|
|
4255
|
+
const camera = section.viewpoint.camera ?? createEmptyViewCamera2();
|
|
4256
|
+
switch (key) {
|
|
4257
|
+
case "azimuth":
|
|
4258
|
+
camera.azimuth = parseFiniteNumber2(value, line, tokens[0].column, "camera.azimuth");
|
|
4259
|
+
break;
|
|
4260
|
+
case "elevation":
|
|
4261
|
+
camera.elevation = parseFiniteNumber2(value, line, tokens[0].column, "camera.elevation");
|
|
4262
|
+
break;
|
|
4263
|
+
case "roll":
|
|
4264
|
+
camera.roll = parseFiniteNumber2(value, line, tokens[0].column, "camera.roll");
|
|
4265
|
+
break;
|
|
4266
|
+
case "distance":
|
|
4267
|
+
camera.distance = parsePositiveNumber2(value, line, tokens[0].column, "camera.distance");
|
|
4268
|
+
break;
|
|
4269
|
+
default:
|
|
4270
|
+
throw new WorldOrbitError(`Unknown viewpoint camera field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4271
|
+
}
|
|
4272
|
+
section.viewpoint.camera = camera;
|
|
4273
|
+
}
|
|
3961
4274
|
function applyViewpointFilterField(section, tokens, line) {
|
|
3962
4275
|
const key = requireUniqueField(tokens, section.seenFilterFields, line);
|
|
3963
4276
|
const filter = section.viewpoint.filter ?? createEmptyViewpointFilter2();
|
|
@@ -4068,6 +4381,12 @@ var WorldOrbit = (() => {
|
|
|
4068
4381
|
section.positionsIndent = null;
|
|
4069
4382
|
}
|
|
4070
4383
|
if (section.activePose) {
|
|
4384
|
+
if (tokens[0]?.value === "epoch" || tokens[0]?.value === "referencePlane") {
|
|
4385
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, `pose.${tokens[0].value}`, {
|
|
4386
|
+
line,
|
|
4387
|
+
column: tokens[0]?.column ?? 1
|
|
4388
|
+
});
|
|
4389
|
+
}
|
|
4071
4390
|
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4072
4391
|
return;
|
|
4073
4392
|
}
|
|
@@ -4122,6 +4441,20 @@ var WorldOrbit = (() => {
|
|
|
4122
4441
|
case "visibility":
|
|
4123
4442
|
section.event.visibility = joinFieldValue(tokens, line);
|
|
4124
4443
|
return;
|
|
4444
|
+
case "epoch":
|
|
4445
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "event.epoch", {
|
|
4446
|
+
line,
|
|
4447
|
+
column: tokens[0].column
|
|
4448
|
+
});
|
|
4449
|
+
section.event.epoch = joinFieldValue(tokens, line);
|
|
4450
|
+
return;
|
|
4451
|
+
case "referenceplane":
|
|
4452
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "event.referencePlane", {
|
|
4453
|
+
line,
|
|
4454
|
+
column: tokens[0].column
|
|
4455
|
+
});
|
|
4456
|
+
section.event.referencePlane = joinFieldValue(tokens, line);
|
|
4457
|
+
return;
|
|
4125
4458
|
case "tags":
|
|
4126
4459
|
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4127
4460
|
return;
|
|
@@ -4249,11 +4582,15 @@ var WorldOrbit = (() => {
|
|
|
4249
4582
|
}
|
|
4250
4583
|
function parseProjectionValue(value, line, column) {
|
|
4251
4584
|
const normalized = value.toLowerCase();
|
|
4252
|
-
if (normalized !== "topdown" && normalized !== "isometric") {
|
|
4585
|
+
if (normalized !== "topdown" && normalized !== "isometric" && normalized !== "orthographic" && normalized !== "perspective") {
|
|
4253
4586
|
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
4254
4587
|
}
|
|
4255
4588
|
return normalized;
|
|
4256
4589
|
}
|
|
4590
|
+
function isSchema25Projection(value) {
|
|
4591
|
+
const normalized = value.toLowerCase();
|
|
4592
|
+
return normalized === "orthographic" || normalized === "perspective";
|
|
4593
|
+
}
|
|
4257
4594
|
function parsePresetValue(value, line, column) {
|
|
4258
4595
|
const normalized = value.toLowerCase();
|
|
4259
4596
|
if (normalized === "diagram" || normalized === "presentation" || normalized === "atlas-card" || normalized === "markdown") {
|
|
@@ -4283,6 +4620,48 @@ var WorldOrbit = (() => {
|
|
|
4283
4620
|
groupIds: []
|
|
4284
4621
|
};
|
|
4285
4622
|
}
|
|
4623
|
+
function createEmptyViewCamera2() {
|
|
4624
|
+
return {
|
|
4625
|
+
azimuth: null,
|
|
4626
|
+
elevation: null,
|
|
4627
|
+
roll: null,
|
|
4628
|
+
distance: null
|
|
4629
|
+
};
|
|
4630
|
+
}
|
|
4631
|
+
function parseInlineViewCamera(tokens, line, current) {
|
|
4632
|
+
if (tokens.length === 0 || tokens.length % 2 !== 0) {
|
|
4633
|
+
throw new WorldOrbitError('Field "camera" expects "<field> <value>" pairs', line, tokens[0]?.column ?? 1);
|
|
4634
|
+
}
|
|
4635
|
+
const camera = current ? { ...current } : createEmptyViewCamera2();
|
|
4636
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4637
|
+
for (let index = 0; index < tokens.length; index += 2) {
|
|
4638
|
+
const fieldToken = tokens[index];
|
|
4639
|
+
const valueToken = tokens[index + 1];
|
|
4640
|
+
const key = fieldToken.value.toLowerCase();
|
|
4641
|
+
if (seen.has(key)) {
|
|
4642
|
+
throw new WorldOrbitError(`Duplicate viewpoint camera field "${fieldToken.value}"`, line, fieldToken.column);
|
|
4643
|
+
}
|
|
4644
|
+
seen.add(key);
|
|
4645
|
+
const value = valueToken.value;
|
|
4646
|
+
switch (key) {
|
|
4647
|
+
case "azimuth":
|
|
4648
|
+
camera.azimuth = parseFiniteNumber2(value, line, fieldToken.column, "camera.azimuth");
|
|
4649
|
+
break;
|
|
4650
|
+
case "elevation":
|
|
4651
|
+
camera.elevation = parseFiniteNumber2(value, line, fieldToken.column, "camera.elevation");
|
|
4652
|
+
break;
|
|
4653
|
+
case "roll":
|
|
4654
|
+
camera.roll = parseFiniteNumber2(value, line, fieldToken.column, "camera.roll");
|
|
4655
|
+
break;
|
|
4656
|
+
case "distance":
|
|
4657
|
+
camera.distance = parsePositiveNumber2(value, line, fieldToken.column, "camera.distance");
|
|
4658
|
+
break;
|
|
4659
|
+
default:
|
|
4660
|
+
throw new WorldOrbitError(`Unknown viewpoint camera field "${fieldToken.value}"`, line, fieldToken.column);
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
return camera;
|
|
4664
|
+
}
|
|
4286
4665
|
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
4287
4666
|
const fields = [];
|
|
4288
4667
|
let index = 0;
|
|
@@ -4415,7 +4794,7 @@ var WorldOrbit = (() => {
|
|
|
4415
4794
|
object.tolerances = tolerances;
|
|
4416
4795
|
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
4417
4796
|
object.typedBlocks = typedBlocks;
|
|
4418
|
-
if (sourceSchemaVersion
|
|
4797
|
+
if (isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
4419
4798
|
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
4799
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
4421
4800
|
}
|
|
@@ -4431,23 +4810,25 @@ var WorldOrbit = (() => {
|
|
|
4431
4810
|
};
|
|
4432
4811
|
}
|
|
4433
4812
|
function normalizeDraftEventPose(rawPose) {
|
|
4434
|
-
const fieldMap = collectDraftFields(rawPose.fields);
|
|
4813
|
+
const fieldMap = collectDraftFields(rawPose.fields, "event-pose");
|
|
4435
4814
|
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4436
4815
|
return {
|
|
4437
4816
|
objectId: rawPose.objectId,
|
|
4438
4817
|
placement,
|
|
4439
4818
|
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
4440
|
-
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer")
|
|
4819
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer"),
|
|
4820
|
+
epoch: parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]),
|
|
4821
|
+
referencePlane: parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0])
|
|
4441
4822
|
};
|
|
4442
4823
|
}
|
|
4443
|
-
function collectDraftFields(fields) {
|
|
4824
|
+
function collectDraftFields(fields, _mode = "object") {
|
|
4444
4825
|
const grouped = /* @__PURE__ */ new Map();
|
|
4445
4826
|
for (const field of fields) {
|
|
4446
4827
|
const spec = getDraftObjectFieldSpec(field.key);
|
|
4447
|
-
if (!spec) {
|
|
4828
|
+
if (!spec && !EVENT_POSE_FIELD_KEYS.has(field.key)) {
|
|
4448
4829
|
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4449
4830
|
}
|
|
4450
|
-
if (!spec
|
|
4831
|
+
if (!spec?.allowRepeat && grouped.has(field.key)) {
|
|
4451
4832
|
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
4452
4833
|
}
|
|
4453
4834
|
const existing = grouped.get(field.key) ?? [];
|
|
@@ -4624,7 +5005,7 @@ var WorldOrbit = (() => {
|
|
|
4624
5005
|
}
|
|
4625
5006
|
}
|
|
4626
5007
|
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
4627
|
-
if (sourceSchemaVersion
|
|
5008
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
4628
5009
|
return;
|
|
4629
5010
|
}
|
|
4630
5011
|
diagnostics.push({
|
|
@@ -4636,6 +5017,34 @@ var WorldOrbit = (() => {
|
|
|
4636
5017
|
column: location.column
|
|
4637
5018
|
});
|
|
4638
5019
|
}
|
|
5020
|
+
function warnIfSchema25Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
5021
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "2.5")) {
|
|
5022
|
+
return;
|
|
5023
|
+
}
|
|
5024
|
+
diagnostics.push({
|
|
5025
|
+
code: "parse.schema25.featureCompatibility",
|
|
5026
|
+
severity: "warning",
|
|
5027
|
+
source: "parse",
|
|
5028
|
+
message: `Feature "${featureName}" requires schema 2.5; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
5029
|
+
line: location.line,
|
|
5030
|
+
column: location.column
|
|
5031
|
+
});
|
|
5032
|
+
}
|
|
5033
|
+
function isSchemaOlderThan(sourceSchemaVersion, requiredVersion) {
|
|
5034
|
+
return schemaVersionRank(sourceSchemaVersion) < schemaVersionRank(requiredVersion);
|
|
5035
|
+
}
|
|
5036
|
+
function schemaVersionRank(version) {
|
|
5037
|
+
switch (version) {
|
|
5038
|
+
case "2.0-draft":
|
|
5039
|
+
return 0;
|
|
5040
|
+
case "2.0":
|
|
5041
|
+
return 1;
|
|
5042
|
+
case "2.1":
|
|
5043
|
+
return 2;
|
|
5044
|
+
case "2.5":
|
|
5045
|
+
return 3;
|
|
5046
|
+
}
|
|
5047
|
+
}
|
|
4639
5048
|
function preprocessAtlasSource(source) {
|
|
4640
5049
|
const chars = [...source];
|
|
4641
5050
|
const comments = [];
|
|
@@ -4723,8 +5132,9 @@ var WorldOrbit = (() => {
|
|
|
4723
5132
|
}
|
|
4724
5133
|
|
|
4725
5134
|
// packages/core/dist/load.js
|
|
4726
|
-
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|
|
5135
|
+
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1|\.5)?$/i;
|
|
4727
5136
|
var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
5137
|
+
var ATLAS_SCHEMA_25_PATTERN = /^schema\s+2\.5$/i;
|
|
4728
5138
|
var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
4729
5139
|
function detectWorldOrbitSchemaVersion(source) {
|
|
4730
5140
|
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
@@ -4738,6 +5148,9 @@ var WorldOrbit = (() => {
|
|
|
4738
5148
|
if (ATLAS_SCHEMA_21_PATTERN.test(trimmed)) {
|
|
4739
5149
|
return "2.1";
|
|
4740
5150
|
}
|
|
5151
|
+
if (ATLAS_SCHEMA_25_PATTERN.test(trimmed)) {
|
|
5152
|
+
return "2.5";
|
|
5153
|
+
}
|
|
4741
5154
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
4742
5155
|
return "2.0";
|
|
4743
5156
|
}
|
|
@@ -4798,7 +5211,7 @@ var WorldOrbit = (() => {
|
|
|
4798
5211
|
}
|
|
4799
5212
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
4800
5213
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
4801
|
-
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1") {
|
|
5214
|
+
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1" || schemaVersion === "2.5") {
|
|
4802
5215
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
4803
5216
|
}
|
|
4804
5217
|
let ast;
|