worldorbit 2.5.16 → 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 +1228 -110
- package/dist/browser/editor/dist/index.js +1896 -180
- package/dist/browser/markdown/dist/index.js +1071 -99
- package/dist/browser/viewer/dist/index.js +1127 -113
- package/dist/unpkg/core/dist/index.js +1228 -110
- package/dist/unpkg/editor/dist/index.js +1896 -180
- package/dist/unpkg/markdown/dist/index.js +1071 -99
- package/dist/unpkg/viewer/dist/index.js +1127 -113
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +295 -203
- package/dist/unpkg/worldorbit-markdown.min.js +66 -58
- package/dist/unpkg/worldorbit-viewer.min.js +84 -76
- package/dist/unpkg/worldorbit.js +1304 -124
- package/dist/unpkg/worldorbit.min.js +88 -80
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.js +75 -1
- package/packages/core/dist/atlas-validate.js +211 -8
- package/packages/core/dist/draft-parse.js +401 -22
- package/packages/core/dist/draft.d.ts +5 -2
- package/packages/core/dist/draft.js +103 -8
- package/packages/core/dist/format.js +99 -6
- package/packages/core/dist/load.js +9 -2
- package/packages/core/dist/normalize.js +1 -0
- package/packages/core/dist/scene.js +400 -64
- package/packages/core/dist/types.d.ts +60 -4
- package/packages/editor/dist/editor.js +702 -65
- package/packages/editor/dist/types.d.ts +3 -1
- package/packages/viewer/dist/atlas-state.js +11 -2
- package/packages/viewer/dist/atlas-viewer.js +19 -7
- 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 +12 -2
- package/packages/viewer/dist/viewer.js +28 -1
|
@@ -568,6 +568,7 @@ var WorldOrbit = (() => {
|
|
|
568
568
|
system,
|
|
569
569
|
groups: [],
|
|
570
570
|
relations: [],
|
|
571
|
+
events: [],
|
|
571
572
|
objects
|
|
572
573
|
};
|
|
573
574
|
}
|
|
@@ -947,12 +948,16 @@ var WorldOrbit = (() => {
|
|
|
947
948
|
const height = frame.height;
|
|
948
949
|
const padding = frame.padding;
|
|
949
950
|
const layoutPreset = resolveLayoutPreset(document2);
|
|
950
|
-
const
|
|
951
|
+
const schemaProjection = resolveProjection(document2, options.projection);
|
|
952
|
+
const camera = normalizeViewCamera(options.camera ?? null);
|
|
953
|
+
const renderProjection = resolveRenderProjection(schemaProjection, camera);
|
|
951
954
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
952
955
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
953
956
|
const systemId = document2.system?.id ?? null;
|
|
954
|
-
const
|
|
955
|
-
const
|
|
957
|
+
const activeEventId = options.activeEventId ?? null;
|
|
958
|
+
const effectiveObjects = createEffectiveObjects(document2.objects, document2.events ?? [], activeEventId);
|
|
959
|
+
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
960
|
+
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
956
961
|
const positions = /* @__PURE__ */ new Map();
|
|
957
962
|
const orbitDrafts = [];
|
|
958
963
|
const leaderDrafts = [];
|
|
@@ -961,7 +966,7 @@ var WorldOrbit = (() => {
|
|
|
961
966
|
const atObjects = [];
|
|
962
967
|
const surfaceChildren = /* @__PURE__ */ new Map();
|
|
963
968
|
const orbitChildren = /* @__PURE__ */ new Map();
|
|
964
|
-
for (const object of
|
|
969
|
+
for (const object of effectiveObjects) {
|
|
965
970
|
const placement = object.placement;
|
|
966
971
|
if (!placement) {
|
|
967
972
|
rootObjects.push(object);
|
|
@@ -988,7 +993,7 @@ var WorldOrbit = (() => {
|
|
|
988
993
|
surfaceChildren,
|
|
989
994
|
objectMap,
|
|
990
995
|
spacingFactor,
|
|
991
|
-
projection,
|
|
996
|
+
projection: renderProjection,
|
|
992
997
|
scaleModel
|
|
993
998
|
};
|
|
994
999
|
const primaryRoot = rootObjects.find((object) => object.type === "star") ?? rootObjects[0] ?? null;
|
|
@@ -1000,7 +1005,7 @@ var WorldOrbit = (() => {
|
|
|
1000
1005
|
const rootRingRadius = Math.min(width, height) * 0.28 * spacingFactor * scaleModel.orbitDistanceMultiplier;
|
|
1001
1006
|
secondaryRoots.forEach((object, index) => {
|
|
1002
1007
|
const angle = angleForIndex(index, secondaryRoots.length, -Math.PI / 2);
|
|
1003
|
-
const offset = projectPolarOffset(angle, rootRingRadius,
|
|
1008
|
+
const offset = projectPolarOffset(angle, rootRingRadius, renderProjection, 1);
|
|
1004
1009
|
placeObject(object, centerX + offset.x, centerY + offset.y, 0, positions, orbitDrafts, leaderDrafts, context);
|
|
1005
1010
|
});
|
|
1006
1011
|
}
|
|
@@ -1056,38 +1061,48 @@ var WorldOrbit = (() => {
|
|
|
1056
1061
|
const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
|
|
1057
1062
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1058
1063
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1059
|
-
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1064
|
+
const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
|
|
1060
1065
|
const relations = createSceneRelations(document2, objects);
|
|
1061
|
-
const
|
|
1062
|
-
const
|
|
1066
|
+
const events = createSceneEvents(document2.events ?? [], objects, activeEventId);
|
|
1067
|
+
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1068
|
+
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1063
1069
|
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1064
|
-
const viewpoints = createSceneViewpoints(document2,
|
|
1065
|
-
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1070
|
+
const viewpoints = createSceneViewpoints(document2, schemaProjection, frame.preset, relationships, objectMap);
|
|
1071
|
+
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1066
1072
|
return {
|
|
1067
1073
|
width,
|
|
1068
1074
|
height,
|
|
1069
1075
|
padding,
|
|
1070
1076
|
renderPreset: frame.preset,
|
|
1071
|
-
projection,
|
|
1077
|
+
projection: schemaProjection,
|
|
1078
|
+
renderProjection,
|
|
1079
|
+
camera,
|
|
1072
1080
|
scaleModel,
|
|
1073
1081
|
title: String(document2.system?.title ?? document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1074
|
-
subtitle:
|
|
1082
|
+
subtitle: buildSceneSubtitle(schemaProjection, renderProjection, layoutPreset, camera),
|
|
1075
1083
|
systemId,
|
|
1076
|
-
viewMode:
|
|
1084
|
+
viewMode: schemaProjection,
|
|
1077
1085
|
layoutPreset,
|
|
1078
1086
|
metadata: {
|
|
1079
1087
|
format: document2.format,
|
|
1080
1088
|
version: document2.version,
|
|
1081
|
-
view:
|
|
1089
|
+
view: schemaProjection,
|
|
1090
|
+
renderProjection,
|
|
1082
1091
|
scale: String(document2.system?.properties.scale ?? layoutPreset),
|
|
1083
1092
|
units: String(document2.system?.properties.units ?? "mixed"),
|
|
1084
|
-
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) } : {}
|
|
1085
1098
|
},
|
|
1086
1099
|
contentBounds,
|
|
1087
1100
|
layers,
|
|
1088
1101
|
groups,
|
|
1089
1102
|
semanticGroups,
|
|
1090
1103
|
viewpoints,
|
|
1104
|
+
events,
|
|
1105
|
+
activeEventId,
|
|
1091
1106
|
objects,
|
|
1092
1107
|
orbitVisuals,
|
|
1093
1108
|
relations,
|
|
@@ -1095,6 +1110,56 @@ var WorldOrbit = (() => {
|
|
|
1095
1110
|
labels
|
|
1096
1111
|
};
|
|
1097
1112
|
}
|
|
1113
|
+
function createEffectiveObjects(objects, events, activeEventId) {
|
|
1114
|
+
const cloned = objects.map((object) => structuredClone(object));
|
|
1115
|
+
if (!activeEventId) {
|
|
1116
|
+
return cloned;
|
|
1117
|
+
}
|
|
1118
|
+
const activeEvent = events.find((event) => event.id === activeEventId);
|
|
1119
|
+
if (!activeEvent) {
|
|
1120
|
+
return cloned;
|
|
1121
|
+
}
|
|
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
|
+
}
|
|
1140
|
+
for (const pose of activeEvent.positions) {
|
|
1141
|
+
const object = objectMap.get(pose.objectId);
|
|
1142
|
+
if (!object) {
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
if (pose.placement) {
|
|
1146
|
+
object.placement = structuredClone(pose.placement);
|
|
1147
|
+
}
|
|
1148
|
+
if (pose.inner) {
|
|
1149
|
+
object.properties.inner = { ...pose.inner };
|
|
1150
|
+
}
|
|
1151
|
+
if (pose.outer) {
|
|
1152
|
+
object.properties.outer = { ...pose.outer };
|
|
1153
|
+
}
|
|
1154
|
+
if (pose.epoch) {
|
|
1155
|
+
object.epoch = pose.epoch;
|
|
1156
|
+
}
|
|
1157
|
+
if (pose.referencePlane) {
|
|
1158
|
+
object.referencePlane = pose.referencePlane;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
return cloned;
|
|
1162
|
+
}
|
|
1098
1163
|
function resolveLayoutPreset(document2) {
|
|
1099
1164
|
const rawScale = String(document2.system?.properties.scale ?? "balanced").toLowerCase();
|
|
1100
1165
|
switch (rawScale) {
|
|
@@ -1131,10 +1196,59 @@ var WorldOrbit = (() => {
|
|
|
1131
1196
|
}
|
|
1132
1197
|
}
|
|
1133
1198
|
function resolveProjection(document2, projection) {
|
|
1134
|
-
if (projection === "topdown" || projection === "isometric") {
|
|
1199
|
+
if (projection === "topdown" || projection === "isometric" || projection === "orthographic" || projection === "perspective") {
|
|
1135
1200
|
return projection;
|
|
1136
1201
|
}
|
|
1137
|
-
|
|
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(" - ");
|
|
1138
1252
|
}
|
|
1139
1253
|
function resolveScaleModel(layoutPreset, overrides) {
|
|
1140
1254
|
const defaults = defaultScaleModel(layoutPreset);
|
|
@@ -1250,24 +1364,14 @@ var WorldOrbit = (() => {
|
|
|
1250
1364
|
hidden: draft.object.properties.hidden === true
|
|
1251
1365
|
};
|
|
1252
1366
|
}
|
|
1253
|
-
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1367
|
+
function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1254
1368
|
const labels = [];
|
|
1255
1369
|
const occupied = [];
|
|
1256
|
-
const
|
|
1370
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1371
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
|
|
1257
1372
|
for (const object of visibleObjects) {
|
|
1258
|
-
const
|
|
1259
|
-
|
|
1260
|
-
let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
|
|
1261
|
-
let secondaryY = labelY + direction * (16 * labelMultiplier);
|
|
1262
|
-
let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1263
|
-
let attempts = 0;
|
|
1264
|
-
while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
|
|
1265
|
-
labelY += direction * 14 * labelMultiplier;
|
|
1266
|
-
secondaryY += direction * 14 * labelMultiplier;
|
|
1267
|
-
bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1268
|
-
attempts += 1;
|
|
1269
|
-
}
|
|
1270
|
-
occupied.push(bounds);
|
|
1373
|
+
const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
|
|
1374
|
+
occupied.push(createLabelRect(object, placement, labelMultiplier));
|
|
1271
1375
|
labels.push({
|
|
1272
1376
|
renderId: `${object.renderId}-label`,
|
|
1273
1377
|
objectId: object.objectId,
|
|
@@ -1276,17 +1380,128 @@ var WorldOrbit = (() => {
|
|
|
1276
1380
|
semanticGroupIds: [...object.semanticGroupIds],
|
|
1277
1381
|
label: object.label,
|
|
1278
1382
|
secondaryLabel: object.secondaryLabel,
|
|
1279
|
-
x:
|
|
1280
|
-
y: labelY,
|
|
1281
|
-
secondaryY,
|
|
1282
|
-
textAnchor:
|
|
1283
|
-
direction: direction
|
|
1383
|
+
x: placement.x,
|
|
1384
|
+
y: placement.labelY,
|
|
1385
|
+
secondaryY: placement.secondaryY,
|
|
1386
|
+
textAnchor: placement.textAnchor,
|
|
1387
|
+
direction: placement.direction,
|
|
1284
1388
|
hidden: object.hidden
|
|
1285
1389
|
});
|
|
1286
1390
|
}
|
|
1287
1391
|
return labels;
|
|
1288
1392
|
}
|
|
1289
|
-
function
|
|
1393
|
+
function compareLabelPlacementOrder(left, right) {
|
|
1394
|
+
const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
|
|
1395
|
+
if (priorityDiff !== 0) {
|
|
1396
|
+
return priorityDiff;
|
|
1397
|
+
}
|
|
1398
|
+
const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
|
|
1399
|
+
if (renderPriorityDiff !== 0) {
|
|
1400
|
+
return renderPriorityDiff;
|
|
1401
|
+
}
|
|
1402
|
+
return left.sortKey - right.sortKey;
|
|
1403
|
+
}
|
|
1404
|
+
function labelPlacementPriority(object) {
|
|
1405
|
+
switch (object.object.type) {
|
|
1406
|
+
case "star":
|
|
1407
|
+
return 0;
|
|
1408
|
+
case "planet":
|
|
1409
|
+
return 1;
|
|
1410
|
+
case "moon":
|
|
1411
|
+
return 2;
|
|
1412
|
+
case "belt":
|
|
1413
|
+
case "ring":
|
|
1414
|
+
return 3;
|
|
1415
|
+
case "asteroid":
|
|
1416
|
+
case "comet":
|
|
1417
|
+
return 4;
|
|
1418
|
+
case "structure":
|
|
1419
|
+
case "phenomenon":
|
|
1420
|
+
return 5;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1424
|
+
for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
|
|
1425
|
+
const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
|
|
1426
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
|
|
1427
|
+
const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
|
|
1428
|
+
const rect = createLabelRect(object, placement, labelMultiplier);
|
|
1429
|
+
if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
|
|
1430
|
+
return placement;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
return null;
|
|
1435
|
+
}
|
|
1436
|
+
function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
|
|
1437
|
+
const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
|
|
1438
|
+
const vertical = defaultVerticalDirection(object, parent, sceneHeight);
|
|
1439
|
+
const oppositeVertical = vertical === "below" ? "above" : "below";
|
|
1440
|
+
const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
|
|
1441
|
+
const oppositeHorizontal = horizontal === "right" ? "left" : "right";
|
|
1442
|
+
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";
|
|
1443
|
+
return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
|
|
1444
|
+
}
|
|
1445
|
+
function defaultVerticalDirection(object, parent, sceneHeight) {
|
|
1446
|
+
if (parent && Math.abs(object.y - parent.y) > 6) {
|
|
1447
|
+
return object.y >= parent.y ? "below" : "above";
|
|
1448
|
+
}
|
|
1449
|
+
return object.y > sceneHeight * 0.62 ? "above" : "below";
|
|
1450
|
+
}
|
|
1451
|
+
function defaultHorizontalDirection(object, parent, sceneWidth) {
|
|
1452
|
+
if (parent && Math.abs(object.x - parent.x) > 6) {
|
|
1453
|
+
return object.x >= parent.x ? "right" : "left";
|
|
1454
|
+
}
|
|
1455
|
+
return object.x >= sceneWidth / 2 ? "right" : "left";
|
|
1456
|
+
}
|
|
1457
|
+
function createLabelPlacement(object, direction, attempt, labelMultiplier) {
|
|
1458
|
+
const step = 14 * labelMultiplier;
|
|
1459
|
+
switch (direction) {
|
|
1460
|
+
case "above": {
|
|
1461
|
+
const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
|
|
1462
|
+
return {
|
|
1463
|
+
x: object.x,
|
|
1464
|
+
labelY,
|
|
1465
|
+
secondaryY: labelY - 16 * labelMultiplier,
|
|
1466
|
+
textAnchor: "middle",
|
|
1467
|
+
direction
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
case "below": {
|
|
1471
|
+
const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
|
|
1472
|
+
return {
|
|
1473
|
+
x: object.x,
|
|
1474
|
+
labelY,
|
|
1475
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1476
|
+
textAnchor: "middle",
|
|
1477
|
+
direction
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
case "left": {
|
|
1481
|
+
const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
|
|
1482
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1483
|
+
return {
|
|
1484
|
+
x,
|
|
1485
|
+
labelY,
|
|
1486
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1487
|
+
textAnchor: "end",
|
|
1488
|
+
direction
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
case "right": {
|
|
1492
|
+
const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
|
|
1493
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1494
|
+
return {
|
|
1495
|
+
x,
|
|
1496
|
+
labelY,
|
|
1497
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1498
|
+
textAnchor: "start",
|
|
1499
|
+
direction
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
|
|
1290
1505
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1291
1506
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1292
1507
|
return [
|
|
@@ -1301,6 +1516,10 @@ var WorldOrbit = (() => {
|
|
|
1301
1516
|
id: "relations",
|
|
1302
1517
|
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1303
1518
|
},
|
|
1519
|
+
{
|
|
1520
|
+
id: "events",
|
|
1521
|
+
renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
|
|
1522
|
+
},
|
|
1304
1523
|
{
|
|
1305
1524
|
id: "objects",
|
|
1306
1525
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1312,7 +1531,7 @@ var WorldOrbit = (() => {
|
|
|
1312
1531
|
{ id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
|
|
1313
1532
|
];
|
|
1314
1533
|
}
|
|
1315
|
-
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
|
|
1534
|
+
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
|
|
1316
1535
|
const groups = /* @__PURE__ */ new Map();
|
|
1317
1536
|
const ensureGroup = (groupId) => {
|
|
1318
1537
|
if (!groupId) {
|
|
@@ -1361,7 +1580,7 @@ var WorldOrbit = (() => {
|
|
|
1361
1580
|
}
|
|
1362
1581
|
}
|
|
1363
1582
|
for (const group of groups.values()) {
|
|
1364
|
-
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
|
|
1583
|
+
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
|
|
1365
1584
|
}
|
|
1366
1585
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1367
1586
|
}
|
|
@@ -1395,6 +1614,29 @@ var WorldOrbit = (() => {
|
|
|
1395
1614
|
};
|
|
1396
1615
|
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1397
1616
|
}
|
|
1617
|
+
function createSceneEvents(events, objects, activeEventId) {
|
|
1618
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1619
|
+
return events.map((event) => {
|
|
1620
|
+
const objectIds = [.../* @__PURE__ */ new Set([
|
|
1621
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
1622
|
+
...event.participantObjectIds
|
|
1623
|
+
])];
|
|
1624
|
+
const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
|
|
1625
|
+
const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
|
|
1626
|
+
const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
|
|
1627
|
+
return {
|
|
1628
|
+
renderId: `${createRenderId(event.id)}-event`,
|
|
1629
|
+
eventId: event.id,
|
|
1630
|
+
event,
|
|
1631
|
+
objectIds,
|
|
1632
|
+
participantIds: [...event.participantObjectIds],
|
|
1633
|
+
targetObjectId: event.targetObjectId,
|
|
1634
|
+
x: centroidX,
|
|
1635
|
+
y: centroidY,
|
|
1636
|
+
hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
|
|
1637
|
+
};
|
|
1638
|
+
}).sort((left, right) => left.event.id.localeCompare(right.event.id));
|
|
1639
|
+
}
|
|
1398
1640
|
function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
|
|
1399
1641
|
const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
|
|
1400
1642
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1442,13 +1684,18 @@ var WorldOrbit = (() => {
|
|
|
1442
1684
|
function createGeneratedOverviewViewpoint(document2, projection, preset) {
|
|
1443
1685
|
const title = document2.system?.title ?? document2.system?.properties.title;
|
|
1444
1686
|
const label = title ? `${String(title)} Overview` : "Overview";
|
|
1687
|
+
const camera = normalizeViewCamera(null);
|
|
1688
|
+
const renderProjection = resolveRenderProjection(projection, camera);
|
|
1445
1689
|
return {
|
|
1446
1690
|
id: "overview",
|
|
1447
1691
|
label,
|
|
1448
1692
|
summary: "Fit the whole system with the current atlas defaults.",
|
|
1449
1693
|
objectId: null,
|
|
1450
1694
|
selectedObjectId: null,
|
|
1695
|
+
eventIds: [],
|
|
1451
1696
|
projection,
|
|
1697
|
+
renderProjection,
|
|
1698
|
+
camera,
|
|
1452
1699
|
preset,
|
|
1453
1700
|
rotationDeg: 0,
|
|
1454
1701
|
scale: null,
|
|
@@ -1484,6 +1731,9 @@ var WorldOrbit = (() => {
|
|
|
1484
1731
|
draft.select = normalizedValue;
|
|
1485
1732
|
}
|
|
1486
1733
|
return;
|
|
1734
|
+
case "events":
|
|
1735
|
+
draft.eventIds = splitListValue(normalizedValue);
|
|
1736
|
+
return;
|
|
1487
1737
|
case "projection":
|
|
1488
1738
|
case "view":
|
|
1489
1739
|
draft.projection = parseViewProjection(normalizedValue) ?? projection;
|
|
@@ -1495,6 +1745,30 @@ var WorldOrbit = (() => {
|
|
|
1495
1745
|
case "angle":
|
|
1496
1746
|
draft.rotationDeg = parseFiniteNumber(normalizedValue) ?? draft.rotationDeg ?? 0;
|
|
1497
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;
|
|
1498
1772
|
case "zoom":
|
|
1499
1773
|
case "scale":
|
|
1500
1774
|
draft.scale = parsePositiveNumber(normalizedValue);
|
|
@@ -1534,13 +1808,19 @@ var WorldOrbit = (() => {
|
|
|
1534
1808
|
const selectedObjectId = draft.select && objectMap.has(draft.select) ? draft.select : objectId;
|
|
1535
1809
|
const filter = normalizeViewpointFilter(draft.filter);
|
|
1536
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);
|
|
1537
1814
|
return {
|
|
1538
1815
|
id: draft.id,
|
|
1539
1816
|
label,
|
|
1540
1817
|
summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
|
|
1541
1818
|
objectId,
|
|
1542
1819
|
selectedObjectId,
|
|
1543
|
-
|
|
1820
|
+
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
1821
|
+
projection: resolvedProjection,
|
|
1822
|
+
renderProjection,
|
|
1823
|
+
camera,
|
|
1544
1824
|
preset: draft.preset ?? preset,
|
|
1545
1825
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
1546
1826
|
scale: draft.scale ?? null,
|
|
@@ -1557,6 +1837,14 @@ var WorldOrbit = (() => {
|
|
|
1557
1837
|
groupIds: []
|
|
1558
1838
|
};
|
|
1559
1839
|
}
|
|
1840
|
+
function createEmptyViewCamera() {
|
|
1841
|
+
return {
|
|
1842
|
+
azimuth: null,
|
|
1843
|
+
elevation: null,
|
|
1844
|
+
roll: null,
|
|
1845
|
+
distance: null
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1560
1848
|
function normalizeViewpointFilter(filter) {
|
|
1561
1849
|
if (!filter) {
|
|
1562
1850
|
return null;
|
|
@@ -1570,7 +1858,18 @@ var WorldOrbit = (() => {
|
|
|
1570
1858
|
return normalized.query || normalized.objectTypes.length > 0 || normalized.tags.length > 0 || normalized.groupIds.length > 0 ? normalized : null;
|
|
1571
1859
|
}
|
|
1572
1860
|
function parseViewProjection(value) {
|
|
1573
|
-
|
|
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
|
+
}
|
|
1574
1873
|
}
|
|
1575
1874
|
function parseRenderPreset(value) {
|
|
1576
1875
|
const normalized = value.toLowerCase();
|
|
@@ -1597,7 +1896,7 @@ var WorldOrbit = (() => {
|
|
|
1597
1896
|
next["orbits-front"] = enabled;
|
|
1598
1897
|
continue;
|
|
1599
1898
|
}
|
|
1600
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1899
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1601
1900
|
next[rawLayer] = enabled;
|
|
1602
1901
|
}
|
|
1603
1902
|
}
|
|
@@ -1608,7 +1907,7 @@ var WorldOrbit = (() => {
|
|
|
1608
1907
|
}
|
|
1609
1908
|
function parseViewpointGroups(value, document2, relationships, objectMap) {
|
|
1610
1909
|
return splitListValue(value).map((entry) => {
|
|
1611
|
-
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)) {
|
|
1612
1911
|
return entry;
|
|
1613
1912
|
}
|
|
1614
1913
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
@@ -1645,7 +1944,7 @@ var WorldOrbit = (() => {
|
|
|
1645
1944
|
}
|
|
1646
1945
|
return parts.join(" - ");
|
|
1647
1946
|
}
|
|
1648
|
-
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
|
|
1947
|
+
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
1649
1948
|
let minX = Number.POSITIVE_INFINITY;
|
|
1650
1949
|
let minY = Number.POSITIVE_INFINITY;
|
|
1651
1950
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -1675,7 +1974,7 @@ var WorldOrbit = (() => {
|
|
|
1675
1974
|
for (const label of labels) {
|
|
1676
1975
|
if (label.hidden)
|
|
1677
1976
|
continue;
|
|
1678
|
-
includeLabelBounds(label, include);
|
|
1977
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
1679
1978
|
}
|
|
1680
1979
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
1681
1980
|
return createBounds(0, 0, width, height);
|
|
@@ -1713,13 +2012,10 @@ var WorldOrbit = (() => {
|
|
|
1713
2012
|
include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
|
|
1714
2013
|
include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
|
|
1715
2014
|
}
|
|
1716
|
-
function includeLabelBounds(label, include) {
|
|
1717
|
-
const
|
|
1718
|
-
|
|
1719
|
-
include(
|
|
1720
|
-
include(label.x + labelHalfWidth, label.y + 8);
|
|
1721
|
-
include(label.x - labelHalfWidth, label.secondaryY - 14);
|
|
1722
|
-
include(label.x + labelHalfWidth, label.secondaryY + 8);
|
|
2015
|
+
function includeLabelBounds(label, include, labelMultiplier) {
|
|
2016
|
+
const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
|
|
2017
|
+
include(bounds.left, bounds.top);
|
|
2018
|
+
include(bounds.right, bounds.bottom);
|
|
1723
2019
|
}
|
|
1724
2020
|
function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
|
|
1725
2021
|
if (positions.has(object.id)) {
|
|
@@ -2109,7 +2405,7 @@ var WorldOrbit = (() => {
|
|
|
2109
2405
|
return null;
|
|
2110
2406
|
}
|
|
2111
2407
|
}
|
|
2112
|
-
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
|
|
2408
|
+
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2113
2409
|
let minX = Number.POSITIVE_INFINITY;
|
|
2114
2410
|
let minY = Number.POSITIVE_INFINITY;
|
|
2115
2411
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2138,7 +2434,7 @@ var WorldOrbit = (() => {
|
|
|
2138
2434
|
}
|
|
2139
2435
|
for (const label of labels) {
|
|
2140
2436
|
if (!label.hidden && group.labelIds.includes(label.objectId)) {
|
|
2141
|
-
includeLabelBounds(label, include);
|
|
2437
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2142
2438
|
}
|
|
2143
2439
|
}
|
|
2144
2440
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
@@ -2163,12 +2459,28 @@ var WorldOrbit = (() => {
|
|
|
2163
2459
|
}
|
|
2164
2460
|
return current.id;
|
|
2165
2461
|
}
|
|
2166
|
-
function createLabelRect(
|
|
2462
|
+
function createLabelRect(object, placement, labelMultiplier) {
|
|
2463
|
+
return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
|
|
2464
|
+
}
|
|
2465
|
+
function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
|
|
2466
|
+
const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
|
|
2467
|
+
const labelWidth = labelHalfWidth * 2;
|
|
2468
|
+
const topPadding = direction === "above" ? 18 : 12;
|
|
2469
|
+
const bottomPadding = direction === "above" ? 8 : 12;
|
|
2470
|
+
let left = x - labelHalfWidth;
|
|
2471
|
+
let right = x + labelHalfWidth;
|
|
2472
|
+
if (textAnchor === "start") {
|
|
2473
|
+
left = x;
|
|
2474
|
+
right = x + labelWidth;
|
|
2475
|
+
} else if (textAnchor === "end") {
|
|
2476
|
+
left = x - labelWidth;
|
|
2477
|
+
right = x;
|
|
2478
|
+
}
|
|
2167
2479
|
return {
|
|
2168
|
-
left
|
|
2169
|
-
right
|
|
2170
|
-
top: Math.min(labelY, secondaryY) -
|
|
2171
|
-
bottom: Math.max(labelY, secondaryY) +
|
|
2480
|
+
left,
|
|
2481
|
+
right,
|
|
2482
|
+
top: Math.min(labelY, secondaryY) - topPadding,
|
|
2483
|
+
bottom: Math.max(labelY, secondaryY) + bottomPadding
|
|
2172
2484
|
};
|
|
2173
2485
|
}
|
|
2174
2486
|
function rectsOverlap(left, right) {
|
|
@@ -2355,11 +2667,6 @@ var WorldOrbit = (() => {
|
|
|
2355
2667
|
function customColorFor(value) {
|
|
2356
2668
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2357
2669
|
}
|
|
2358
|
-
function estimateLabelHalfWidth(object, labelMultiplier) {
|
|
2359
|
-
const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
|
|
2360
|
-
const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
2361
|
-
return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
|
|
2362
|
-
}
|
|
2363
2670
|
function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
|
|
2364
2671
|
const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
|
|
2365
2672
|
const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
@@ -2376,7 +2683,7 @@ var WorldOrbit = (() => {
|
|
|
2376
2683
|
}
|
|
2377
2684
|
|
|
2378
2685
|
// packages/core/dist/draft.js
|
|
2379
|
-
function materializeAtlasDocument(document2) {
|
|
2686
|
+
function materializeAtlasDocument(document2, options = {}) {
|
|
2380
2687
|
const system = document2.system ? {
|
|
2381
2688
|
type: "system",
|
|
2382
2689
|
id: document2.system.id,
|
|
@@ -2387,6 +2694,8 @@ var WorldOrbit = (() => {
|
|
|
2387
2694
|
properties: materializeDraftSystemProperties(document2.system),
|
|
2388
2695
|
info: materializeDraftSystemInfo(document2.system)
|
|
2389
2696
|
} : null;
|
|
2697
|
+
const objects = document2.objects.map(cloneWorldOrbitObject);
|
|
2698
|
+
applyEventPoseOverrides(objects, document2.events ?? [], options.activeEventId ?? null);
|
|
2390
2699
|
return {
|
|
2391
2700
|
format: "worldorbit",
|
|
2392
2701
|
version: "1.0",
|
|
@@ -2394,7 +2703,8 @@ var WorldOrbit = (() => {
|
|
|
2394
2703
|
system,
|
|
2395
2704
|
groups: structuredClone(document2.groups ?? []),
|
|
2396
2705
|
relations: structuredClone(document2.relations ?? []),
|
|
2397
|
-
|
|
2706
|
+
events: document2.events.map(cloneWorldOrbitEvent),
|
|
2707
|
+
objects
|
|
2398
2708
|
};
|
|
2399
2709
|
}
|
|
2400
2710
|
function cloneWorldOrbitObject(object) {
|
|
@@ -2416,6 +2726,75 @@ var WorldOrbit = (() => {
|
|
|
2416
2726
|
info: { ...object.info }
|
|
2417
2727
|
};
|
|
2418
2728
|
}
|
|
2729
|
+
function cloneWorldOrbitEvent(event) {
|
|
2730
|
+
return {
|
|
2731
|
+
...event,
|
|
2732
|
+
participantObjectIds: [...event.participantObjectIds],
|
|
2733
|
+
tags: [...event.tags],
|
|
2734
|
+
positions: event.positions.map(cloneWorldOrbitEventPose)
|
|
2735
|
+
};
|
|
2736
|
+
}
|
|
2737
|
+
function cloneWorldOrbitEventPose(pose) {
|
|
2738
|
+
return {
|
|
2739
|
+
objectId: pose.objectId,
|
|
2740
|
+
placement: clonePlacement(pose.placement),
|
|
2741
|
+
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
2742
|
+
outer: pose.outer ? { ...pose.outer } : void 0,
|
|
2743
|
+
epoch: pose.epoch ?? null,
|
|
2744
|
+
referencePlane: pose.referencePlane ?? null
|
|
2745
|
+
};
|
|
2746
|
+
}
|
|
2747
|
+
function clonePlacement(placement) {
|
|
2748
|
+
return placement ? structuredClone(placement) : null;
|
|
2749
|
+
}
|
|
2750
|
+
function applyEventPoseOverrides(objects, events, activeEventId) {
|
|
2751
|
+
if (!activeEventId) {
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
const event = events.find((entry) => entry.id === activeEventId);
|
|
2755
|
+
if (!event) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
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
|
+
}
|
|
2776
|
+
for (const pose of event.positions) {
|
|
2777
|
+
const object = objectMap.get(pose.objectId);
|
|
2778
|
+
if (!object) {
|
|
2779
|
+
continue;
|
|
2780
|
+
}
|
|
2781
|
+
if (pose.placement) {
|
|
2782
|
+
object.placement = clonePlacement(pose.placement);
|
|
2783
|
+
}
|
|
2784
|
+
if (pose.inner) {
|
|
2785
|
+
object.properties.inner = { ...pose.inner };
|
|
2786
|
+
}
|
|
2787
|
+
if (pose.outer) {
|
|
2788
|
+
object.properties.outer = { ...pose.outer };
|
|
2789
|
+
}
|
|
2790
|
+
if (pose.epoch) {
|
|
2791
|
+
object.epoch = pose.epoch;
|
|
2792
|
+
}
|
|
2793
|
+
if (pose.referencePlane) {
|
|
2794
|
+
object.referencePlane = pose.referencePlane;
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2419
2798
|
function cloneProperties(properties) {
|
|
2420
2799
|
const next = {};
|
|
2421
2800
|
for (const [key, value] of Object.entries(properties)) {
|
|
@@ -2488,6 +2867,18 @@ var WorldOrbit = (() => {
|
|
|
2488
2867
|
if (viewpoint.rotationDeg !== 0) {
|
|
2489
2868
|
info2[`${prefix}.rotation`] = String(viewpoint.rotationDeg);
|
|
2490
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
|
+
}
|
|
2491
2882
|
const serializedLayers = serializeViewpointLayers(viewpoint.layers);
|
|
2492
2883
|
if (serializedLayers) {
|
|
2493
2884
|
info2[`${prefix}.layers`] = serializedLayers;
|
|
@@ -2504,6 +2895,9 @@ var WorldOrbit = (() => {
|
|
|
2504
2895
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2505
2896
|
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2506
2897
|
}
|
|
2898
|
+
if (viewpoint.events.length > 0) {
|
|
2899
|
+
info2[`${prefix}.events`] = viewpoint.events.join(" ");
|
|
2900
|
+
}
|
|
2507
2901
|
}
|
|
2508
2902
|
for (const annotation of system.annotations) {
|
|
2509
2903
|
const prefix = `annotation.${annotation.id}`;
|
|
@@ -2528,7 +2922,7 @@ var WorldOrbit = (() => {
|
|
|
2528
2922
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2529
2923
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2530
2924
|
}
|
|
2531
|
-
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
2925
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
2532
2926
|
if (layers[key] !== void 0) {
|
|
2533
2927
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2534
2928
|
}
|
|
@@ -2702,6 +3096,7 @@ var WorldOrbit = (() => {
|
|
|
2702
3096
|
const diagnostics = [];
|
|
2703
3097
|
const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
|
|
2704
3098
|
const groupIds = new Set(document2.groups.map((group) => group.id));
|
|
3099
|
+
const eventIds = new Set(document2.events.map((event) => event.id));
|
|
2705
3100
|
if (!document2.system) {
|
|
2706
3101
|
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
2707
3102
|
}
|
|
@@ -2711,6 +3106,7 @@ var WorldOrbit = (() => {
|
|
|
2711
3106
|
["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
2712
3107
|
["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
2713
3108
|
["relation", document2.relations.map((relation) => relation.id)],
|
|
3109
|
+
["event", document2.events.map((event) => event.id)],
|
|
2714
3110
|
["object", document2.objects.map((object) => object.id)]
|
|
2715
3111
|
]) {
|
|
2716
3112
|
for (const id of ids) {
|
|
@@ -2726,11 +3122,14 @@ var WorldOrbit = (() => {
|
|
|
2726
3122
|
validateRelation(relation, objectMap, diagnostics);
|
|
2727
3123
|
}
|
|
2728
3124
|
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
2729
|
-
|
|
3125
|
+
validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap);
|
|
2730
3126
|
}
|
|
2731
3127
|
for (const object of document2.objects) {
|
|
2732
3128
|
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
2733
3129
|
}
|
|
3130
|
+
for (const event of document2.events) {
|
|
3131
|
+
validateEvent(event, document2.system, objectMap, diagnostics);
|
|
3132
|
+
}
|
|
2734
3133
|
return diagnostics;
|
|
2735
3134
|
}
|
|
2736
3135
|
function validateRelation(relation, objectMap, diagnostics) {
|
|
@@ -2748,15 +3147,24 @@ var WorldOrbit = (() => {
|
|
|
2748
3147
|
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
2749
3148
|
}
|
|
2750
3149
|
}
|
|
2751
|
-
function
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
3150
|
+
function validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap) {
|
|
3151
|
+
const filter = viewpoint.filter;
|
|
3152
|
+
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5") {
|
|
3153
|
+
if (filter) {
|
|
3154
|
+
for (const groupId of filter.groupIds) {
|
|
3155
|
+
if (!groupIds.has(groupId)) {
|
|
3156
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpoint.id}".`, void 0, `viewpoint.${viewpoint.id}.groups`));
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
for (const eventId of viewpoint.events ?? []) {
|
|
3161
|
+
if (!eventIds.has(eventId)) {
|
|
3162
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpoint.id}".`, void 0, `viewpoint.${viewpoint.id}.events`));
|
|
3163
|
+
}
|
|
2758
3164
|
}
|
|
2759
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);
|
|
2760
3168
|
}
|
|
2761
3169
|
function validateObject(object, system, objectMap, groupIds, diagnostics) {
|
|
2762
3170
|
const placement = object.placement;
|
|
@@ -2769,6 +3177,12 @@ var WorldOrbit = (() => {
|
|
|
2769
3177
|
}
|
|
2770
3178
|
}
|
|
2771
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
|
+
}
|
|
2772
3186
|
if (orbitPlacement) {
|
|
2773
3187
|
if (!objectMap.has(orbitPlacement.target)) {
|
|
2774
3188
|
diagnostics.push(error("validate.orbit.target.unknown", `Unknown placement target "${orbitPlacement.target}" on "${object.id}".`, object.id, "orbit"));
|
|
@@ -2840,6 +3254,122 @@ var WorldOrbit = (() => {
|
|
|
2840
3254
|
}
|
|
2841
3255
|
}
|
|
2842
3256
|
}
|
|
3257
|
+
function validateEvent(event, system, objectMap, diagnostics) {
|
|
3258
|
+
const fieldPrefix = `event.${event.id}`;
|
|
3259
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
3260
|
+
if (!event.kind.trim()) {
|
|
3261
|
+
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
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
|
+
}
|
|
3269
|
+
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3270
|
+
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3271
|
+
}
|
|
3272
|
+
if (event.targetObjectId) {
|
|
3273
|
+
referencedIds.add(event.targetObjectId);
|
|
3274
|
+
if (!objectMap.has(event.targetObjectId)) {
|
|
3275
|
+
diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
const seenParticipants = /* @__PURE__ */ new Set();
|
|
3279
|
+
for (const participantId of event.participantObjectIds) {
|
|
3280
|
+
referencedIds.add(participantId);
|
|
3281
|
+
if (seenParticipants.has(participantId)) {
|
|
3282
|
+
diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
|
|
3283
|
+
continue;
|
|
3284
|
+
}
|
|
3285
|
+
seenParticipants.add(participantId);
|
|
3286
|
+
if (!objectMap.has(participantId)) {
|
|
3287
|
+
diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
|
|
3291
|
+
diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
|
|
3292
|
+
}
|
|
3293
|
+
if (event.positions.length === 0) {
|
|
3294
|
+
diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
|
|
3295
|
+
}
|
|
3296
|
+
if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
|
|
3297
|
+
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`));
|
|
3298
|
+
}
|
|
3299
|
+
const poseIds = /* @__PURE__ */ new Set();
|
|
3300
|
+
for (const pose of event.positions) {
|
|
3301
|
+
const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
|
|
3302
|
+
if (poseIds.has(pose.objectId)) {
|
|
3303
|
+
diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
|
|
3304
|
+
continue;
|
|
3305
|
+
}
|
|
3306
|
+
poseIds.add(pose.objectId);
|
|
3307
|
+
const object = objectMap.get(pose.objectId);
|
|
3308
|
+
if (!object) {
|
|
3309
|
+
diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
|
|
3310
|
+
continue;
|
|
3311
|
+
}
|
|
3312
|
+
if (!referencedIds.has(pose.objectId)) {
|
|
3313
|
+
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
3314
|
+
}
|
|
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`));
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
function validateEventPose(pose, object, event, system, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3323
|
+
const placement = pose.placement;
|
|
3324
|
+
if (!placement) {
|
|
3325
|
+
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
3326
|
+
return;
|
|
3327
|
+
}
|
|
3328
|
+
if (placement.mode === "orbit") {
|
|
3329
|
+
if (!objectMap.has(placement.target)) {
|
|
3330
|
+
diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
|
|
3331
|
+
}
|
|
3332
|
+
if (placement.distance && placement.semiMajor) {
|
|
3333
|
+
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
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
|
+
}
|
|
3344
|
+
return;
|
|
3345
|
+
}
|
|
3346
|
+
if (placement.mode === "surface") {
|
|
3347
|
+
const target = objectMap.get(placement.target);
|
|
3348
|
+
if (!target) {
|
|
3349
|
+
diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
|
|
3350
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3351
|
+
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`));
|
|
3352
|
+
}
|
|
3353
|
+
return;
|
|
3354
|
+
}
|
|
3355
|
+
if (placement.mode === "at") {
|
|
3356
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3357
|
+
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`));
|
|
3358
|
+
}
|
|
3359
|
+
const reference = placement.reference;
|
|
3360
|
+
if (reference.kind === "named" && !objectMap.has(reference.name)) {
|
|
3361
|
+
diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3362
|
+
} else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
|
|
3363
|
+
diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3364
|
+
} else if (reference.kind === "lagrange") {
|
|
3365
|
+
if (!objectMap.has(reference.primary)) {
|
|
3366
|
+
diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3367
|
+
} else if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3368
|
+
diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
2843
3373
|
function validateAtTarget(object, objectMap, diagnostics) {
|
|
2844
3374
|
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
2845
3375
|
if (!reference) {
|
|
@@ -2945,6 +3475,52 @@ var WorldOrbit = (() => {
|
|
|
2945
3475
|
return null;
|
|
2946
3476
|
}
|
|
2947
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
|
+
}
|
|
2948
3524
|
function toleranceForField(object, field) {
|
|
2949
3525
|
const tolerance = object.tolerances?.find((entry) => entry.field === field)?.value;
|
|
2950
3526
|
if (typeof tolerance === "number") {
|
|
@@ -3040,6 +3616,23 @@ var WorldOrbit = (() => {
|
|
|
3040
3616
|
});
|
|
3041
3617
|
}
|
|
3042
3618
|
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
3619
|
+
var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
3620
|
+
"orbit",
|
|
3621
|
+
"distance",
|
|
3622
|
+
"semiMajor",
|
|
3623
|
+
"eccentricity",
|
|
3624
|
+
"period",
|
|
3625
|
+
"angle",
|
|
3626
|
+
"inclination",
|
|
3627
|
+
"phase",
|
|
3628
|
+
"at",
|
|
3629
|
+
"surface",
|
|
3630
|
+
"free",
|
|
3631
|
+
"inner",
|
|
3632
|
+
"outer",
|
|
3633
|
+
"epoch",
|
|
3634
|
+
"referencePlane"
|
|
3635
|
+
]);
|
|
3043
3636
|
function parseWorldOrbitAtlas(source) {
|
|
3044
3637
|
return parseAtlasSource(source);
|
|
3045
3638
|
}
|
|
@@ -3054,12 +3647,15 @@ var WorldOrbit = (() => {
|
|
|
3054
3647
|
const objectNodes = [];
|
|
3055
3648
|
const groups = [];
|
|
3056
3649
|
const relations = [];
|
|
3650
|
+
const events = [];
|
|
3651
|
+
const eventPoseNodes = /* @__PURE__ */ new Map();
|
|
3057
3652
|
let sawDefaults = false;
|
|
3058
3653
|
let sawAtlas = false;
|
|
3059
3654
|
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3060
3655
|
const annotationIds = /* @__PURE__ */ new Set();
|
|
3061
3656
|
const groupIds = /* @__PURE__ */ new Set();
|
|
3062
3657
|
const relationIds = /* @__PURE__ */ new Set();
|
|
3658
|
+
const eventIds = /* @__PURE__ */ new Set();
|
|
3063
3659
|
for (let index = 0; index < lines.length; index++) {
|
|
3064
3660
|
const rawLine = lines[index];
|
|
3065
3661
|
const lineNumber = index + 1;
|
|
@@ -3077,7 +3673,7 @@ var WorldOrbit = (() => {
|
|
|
3077
3673
|
if (!sawSchemaHeader) {
|
|
3078
3674
|
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
3079
3675
|
sawSchemaHeader = true;
|
|
3080
|
-
if (prepared.comments.length > 0 && sourceSchemaVersion
|
|
3676
|
+
if (prepared.comments.length > 0 && isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
3081
3677
|
diagnostics.push({
|
|
3082
3678
|
code: "parse.schema21.commentCompatibility",
|
|
3083
3679
|
severity: "warning",
|
|
@@ -3090,7 +3686,7 @@ var WorldOrbit = (() => {
|
|
|
3090
3686
|
continue;
|
|
3091
3687
|
}
|
|
3092
3688
|
if (indent === 0) {
|
|
3093
|
-
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
3689
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
3094
3690
|
if (section.kind === "system") {
|
|
3095
3691
|
system = section.system;
|
|
3096
3692
|
} else if (section.kind === "defaults") {
|
|
@@ -3109,6 +3705,7 @@ var WorldOrbit = (() => {
|
|
|
3109
3705
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3110
3706
|
}
|
|
3111
3707
|
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
3708
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
3112
3709
|
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3113
3710
|
const baseDocument = {
|
|
3114
3711
|
format: "worldorbit",
|
|
@@ -3116,6 +3713,7 @@ var WorldOrbit = (() => {
|
|
|
3116
3713
|
system,
|
|
3117
3714
|
groups,
|
|
3118
3715
|
relations,
|
|
3716
|
+
events: normalizedEvents,
|
|
3119
3717
|
objects,
|
|
3120
3718
|
diagnostics
|
|
3121
3719
|
};
|
|
@@ -3145,13 +3743,13 @@ var WorldOrbit = (() => {
|
|
|
3145
3743
|
return document2;
|
|
3146
3744
|
}
|
|
3147
3745
|
function assertDraftSchemaHeader(tokens, line) {
|
|
3148
|
-
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1"].includes(tokens[1].value.toLowerCase())) {
|
|
3149
|
-
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);
|
|
3150
3748
|
}
|
|
3151
3749
|
const version = tokens[1].value.toLowerCase();
|
|
3152
|
-
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";
|
|
3153
3751
|
}
|
|
3154
|
-
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
3752
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3155
3753
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
3156
3754
|
switch (keyword) {
|
|
3157
3755
|
case "system":
|
|
@@ -3169,6 +3767,8 @@ var WorldOrbit = (() => {
|
|
|
3169
3767
|
return {
|
|
3170
3768
|
kind: "defaults",
|
|
3171
3769
|
system,
|
|
3770
|
+
sourceSchemaVersion,
|
|
3771
|
+
diagnostics,
|
|
3172
3772
|
seenFields: /* @__PURE__ */ new Set()
|
|
3173
3773
|
};
|
|
3174
3774
|
case "atlas":
|
|
@@ -3188,7 +3788,7 @@ var WorldOrbit = (() => {
|
|
|
3188
3788
|
if (!system) {
|
|
3189
3789
|
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
3190
3790
|
}
|
|
3191
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
3791
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
3192
3792
|
case "annotation":
|
|
3193
3793
|
if (!system) {
|
|
3194
3794
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -3200,6 +3800,9 @@ var WorldOrbit = (() => {
|
|
|
3200
3800
|
case "relation":
|
|
3201
3801
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
3202
3802
|
return startRelationSection(tokens, line, relations, relationIds);
|
|
3803
|
+
case "event":
|
|
3804
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
3805
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
3203
3806
|
case "object":
|
|
3204
3807
|
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3205
3808
|
default:
|
|
@@ -3236,7 +3839,7 @@ var WorldOrbit = (() => {
|
|
|
3236
3839
|
seenFields: /* @__PURE__ */ new Set()
|
|
3237
3840
|
};
|
|
3238
3841
|
}
|
|
3239
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
3842
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
3240
3843
|
if (tokens.length !== 2) {
|
|
3241
3844
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
3242
3845
|
}
|
|
@@ -3253,10 +3856,12 @@ var WorldOrbit = (() => {
|
|
|
3253
3856
|
summary: "",
|
|
3254
3857
|
focusObjectId: null,
|
|
3255
3858
|
selectedObjectId: null,
|
|
3859
|
+
events: [],
|
|
3256
3860
|
projection: system.defaults.view,
|
|
3257
3861
|
preset: system.defaults.preset,
|
|
3258
3862
|
zoom: null,
|
|
3259
3863
|
rotationDeg: 0,
|
|
3864
|
+
camera: null,
|
|
3260
3865
|
layers: {},
|
|
3261
3866
|
filter: null
|
|
3262
3867
|
};
|
|
@@ -3265,10 +3870,15 @@ var WorldOrbit = (() => {
|
|
|
3265
3870
|
return {
|
|
3266
3871
|
kind: "viewpoint",
|
|
3267
3872
|
viewpoint,
|
|
3873
|
+
sourceSchemaVersion,
|
|
3874
|
+
diagnostics,
|
|
3268
3875
|
seenFields: /* @__PURE__ */ new Set(),
|
|
3269
3876
|
inFilter: false,
|
|
3270
3877
|
filterIndent: null,
|
|
3271
|
-
seenFilterFields: /* @__PURE__ */ new Set()
|
|
3878
|
+
seenFilterFields: /* @__PURE__ */ new Set(),
|
|
3879
|
+
inCamera: false,
|
|
3880
|
+
cameraIndent: null,
|
|
3881
|
+
seenCameraFields: /* @__PURE__ */ new Set()
|
|
3272
3882
|
};
|
|
3273
3883
|
}
|
|
3274
3884
|
function startAnnotationSection(tokens, line, system, annotationIds) {
|
|
@@ -3355,6 +3965,51 @@ var WorldOrbit = (() => {
|
|
|
3355
3965
|
seenFields: /* @__PURE__ */ new Set()
|
|
3356
3966
|
};
|
|
3357
3967
|
}
|
|
3968
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
3969
|
+
if (tokens.length !== 2) {
|
|
3970
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
3971
|
+
}
|
|
3972
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
3973
|
+
if (!id) {
|
|
3974
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
3975
|
+
}
|
|
3976
|
+
if (eventIds.has(id)) {
|
|
3977
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
3978
|
+
}
|
|
3979
|
+
const event = {
|
|
3980
|
+
id,
|
|
3981
|
+
kind: "",
|
|
3982
|
+
label: humanizeIdentifier2(id),
|
|
3983
|
+
summary: null,
|
|
3984
|
+
targetObjectId: null,
|
|
3985
|
+
participantObjectIds: [],
|
|
3986
|
+
timing: null,
|
|
3987
|
+
visibility: null,
|
|
3988
|
+
epoch: null,
|
|
3989
|
+
referencePlane: null,
|
|
3990
|
+
tags: [],
|
|
3991
|
+
color: null,
|
|
3992
|
+
hidden: false,
|
|
3993
|
+
positions: []
|
|
3994
|
+
};
|
|
3995
|
+
const rawPoses = [];
|
|
3996
|
+
events.push(event);
|
|
3997
|
+
eventPoseNodes.set(id, rawPoses);
|
|
3998
|
+
eventIds.add(id);
|
|
3999
|
+
return {
|
|
4000
|
+
kind: "event",
|
|
4001
|
+
event,
|
|
4002
|
+
sourceSchemaVersion,
|
|
4003
|
+
diagnostics,
|
|
4004
|
+
seenFields: /* @__PURE__ */ new Set(),
|
|
4005
|
+
rawPoses,
|
|
4006
|
+
inPositions: false,
|
|
4007
|
+
positionsIndent: null,
|
|
4008
|
+
activePose: null,
|
|
4009
|
+
poseIndent: null,
|
|
4010
|
+
activePoseSeenFields: /* @__PURE__ */ new Set()
|
|
4011
|
+
};
|
|
4012
|
+
}
|
|
3358
4013
|
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
3359
4014
|
if (tokens.length < 3) {
|
|
3360
4015
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
@@ -3411,6 +4066,9 @@ var WorldOrbit = (() => {
|
|
|
3411
4066
|
case "relation":
|
|
3412
4067
|
applyRelationField(section, tokens, line);
|
|
3413
4068
|
return;
|
|
4069
|
+
case "event":
|
|
4070
|
+
applyEventField(section, indent, tokens, line);
|
|
4071
|
+
return;
|
|
3414
4072
|
case "object":
|
|
3415
4073
|
applyObjectField(section, indent, tokens, line);
|
|
3416
4074
|
return;
|
|
@@ -3453,6 +4111,12 @@ var WorldOrbit = (() => {
|
|
|
3453
4111
|
const value = joinFieldValue(tokens, line);
|
|
3454
4112
|
switch (key) {
|
|
3455
4113
|
case "view":
|
|
4114
|
+
if (isSchema25Projection(value)) {
|
|
4115
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "defaults.view", {
|
|
4116
|
+
line,
|
|
4117
|
+
column: tokens[0].column
|
|
4118
|
+
});
|
|
4119
|
+
}
|
|
3456
4120
|
section.system.defaults.view = parseProjectionValue(value, line, tokens[0].column);
|
|
3457
4121
|
return;
|
|
3458
4122
|
case "scale":
|
|
@@ -3492,14 +4156,36 @@ var WorldOrbit = (() => {
|
|
|
3492
4156
|
throw new WorldOrbitError(`Unknown atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3493
4157
|
}
|
|
3494
4158
|
function applyViewpointField2(section, indent, tokens, line) {
|
|
4159
|
+
if (section.inCamera && indent <= (section.cameraIndent ?? 0)) {
|
|
4160
|
+
section.inCamera = false;
|
|
4161
|
+
section.cameraIndent = null;
|
|
4162
|
+
}
|
|
3495
4163
|
if (section.inFilter && indent <= (section.filterIndent ?? 0)) {
|
|
3496
4164
|
section.inFilter = false;
|
|
3497
4165
|
section.filterIndent = null;
|
|
3498
4166
|
}
|
|
4167
|
+
if (section.inCamera) {
|
|
4168
|
+
applyViewpointCameraField(section, tokens, line);
|
|
4169
|
+
return;
|
|
4170
|
+
}
|
|
3499
4171
|
if (section.inFilter) {
|
|
3500
4172
|
applyViewpointFilterField(section, tokens, line);
|
|
3501
4173
|
return;
|
|
3502
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
|
+
}
|
|
3503
4189
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "filter") {
|
|
3504
4190
|
if (section.seenFields.has("filter")) {
|
|
3505
4191
|
throw new WorldOrbitError('Duplicate viewpoint field "filter"', line, tokens[0].column);
|
|
@@ -3525,6 +4211,12 @@ var WorldOrbit = (() => {
|
|
|
3525
4211
|
section.viewpoint.selectedObjectId = value;
|
|
3526
4212
|
return;
|
|
3527
4213
|
case "projection":
|
|
4214
|
+
if (isSchema25Projection(value)) {
|
|
4215
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "projection", {
|
|
4216
|
+
line,
|
|
4217
|
+
column: tokens[0].column
|
|
4218
|
+
});
|
|
4219
|
+
}
|
|
3528
4220
|
section.viewpoint.projection = parseProjectionValue(value, line, tokens[0].column);
|
|
3529
4221
|
return;
|
|
3530
4222
|
case "preset":
|
|
@@ -3536,13 +4228,49 @@ var WorldOrbit = (() => {
|
|
|
3536
4228
|
case "rotation":
|
|
3537
4229
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
3538
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;
|
|
3539
4238
|
case "layers":
|
|
3540
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
4239
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
4240
|
+
return;
|
|
4241
|
+
case "events":
|
|
4242
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
4243
|
+
line,
|
|
4244
|
+
column: tokens[0].column
|
|
4245
|
+
});
|
|
4246
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
3541
4247
|
return;
|
|
3542
4248
|
default:
|
|
3543
4249
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3544
4250
|
}
|
|
3545
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
|
+
}
|
|
3546
4274
|
function applyViewpointFilterField(section, tokens, line) {
|
|
3547
4275
|
const key = requireUniqueField(tokens, section.seenFilterFields, line);
|
|
3548
4276
|
const filter = section.viewpoint.filter ?? createEmptyViewpointFilter2();
|
|
@@ -3642,6 +4370,126 @@ var WorldOrbit = (() => {
|
|
|
3642
4370
|
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3643
4371
|
}
|
|
3644
4372
|
}
|
|
4373
|
+
function applyEventField(section, indent, tokens, line) {
|
|
4374
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
4375
|
+
section.activePose = null;
|
|
4376
|
+
section.poseIndent = null;
|
|
4377
|
+
section.activePoseSeenFields.clear();
|
|
4378
|
+
}
|
|
4379
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
4380
|
+
section.inPositions = false;
|
|
4381
|
+
section.positionsIndent = null;
|
|
4382
|
+
}
|
|
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
|
+
}
|
|
4390
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4391
|
+
return;
|
|
4392
|
+
}
|
|
4393
|
+
if (section.inPositions) {
|
|
4394
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
4395
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
4396
|
+
}
|
|
4397
|
+
const objectId = tokens[1].value;
|
|
4398
|
+
if (!objectId.trim()) {
|
|
4399
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
4400
|
+
}
|
|
4401
|
+
const rawPose = {
|
|
4402
|
+
objectId,
|
|
4403
|
+
fields: [],
|
|
4404
|
+
location: { line, column: tokens[0].column }
|
|
4405
|
+
};
|
|
4406
|
+
section.rawPoses.push(rawPose);
|
|
4407
|
+
section.activePose = rawPose;
|
|
4408
|
+
section.poseIndent = indent;
|
|
4409
|
+
section.activePoseSeenFields = /* @__PURE__ */ new Set();
|
|
4410
|
+
return;
|
|
4411
|
+
}
|
|
4412
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
4413
|
+
if (section.seenFields.has("positions")) {
|
|
4414
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
4415
|
+
}
|
|
4416
|
+
section.seenFields.add("positions");
|
|
4417
|
+
section.inPositions = true;
|
|
4418
|
+
section.positionsIndent = indent;
|
|
4419
|
+
return;
|
|
4420
|
+
}
|
|
4421
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4422
|
+
switch (key) {
|
|
4423
|
+
case "kind":
|
|
4424
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
4425
|
+
return;
|
|
4426
|
+
case "label":
|
|
4427
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
4428
|
+
return;
|
|
4429
|
+
case "summary":
|
|
4430
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
4431
|
+
return;
|
|
4432
|
+
case "target":
|
|
4433
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
4434
|
+
return;
|
|
4435
|
+
case "participants":
|
|
4436
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
4437
|
+
return;
|
|
4438
|
+
case "timing":
|
|
4439
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
4440
|
+
return;
|
|
4441
|
+
case "visibility":
|
|
4442
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
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;
|
|
4458
|
+
case "tags":
|
|
4459
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4460
|
+
return;
|
|
4461
|
+
case "color":
|
|
4462
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
4463
|
+
return;
|
|
4464
|
+
case "hidden":
|
|
4465
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4466
|
+
line,
|
|
4467
|
+
column: tokens[0].column
|
|
4468
|
+
});
|
|
4469
|
+
return;
|
|
4470
|
+
default:
|
|
4471
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4472
|
+
}
|
|
4473
|
+
}
|
|
4474
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
4475
|
+
if (tokens.length < 2) {
|
|
4476
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
4477
|
+
}
|
|
4478
|
+
const key = tokens[0].value;
|
|
4479
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
4480
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
4481
|
+
}
|
|
4482
|
+
if (seenFields.has(key)) {
|
|
4483
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
4484
|
+
}
|
|
4485
|
+
seenFields.add(key);
|
|
4486
|
+
return {
|
|
4487
|
+
type: "field",
|
|
4488
|
+
key,
|
|
4489
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
4490
|
+
location: { line, column: tokens[0].column }
|
|
4491
|
+
};
|
|
4492
|
+
}
|
|
3645
4493
|
function applyObjectField(section, indent, tokens, line) {
|
|
3646
4494
|
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
3647
4495
|
section.activeBlock = null;
|
|
@@ -3700,7 +4548,7 @@ var WorldOrbit = (() => {
|
|
|
3700
4548
|
function parseObjectTypeTokens(tokens, line) {
|
|
3701
4549
|
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");
|
|
3702
4550
|
}
|
|
3703
|
-
function parseLayerTokens(tokens, line) {
|
|
4551
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
3704
4552
|
const layers = {};
|
|
3705
4553
|
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
3706
4554
|
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
@@ -3710,7 +4558,13 @@ var WorldOrbit = (() => {
|
|
|
3710
4558
|
layers["orbits-front"] = enabled;
|
|
3711
4559
|
continue;
|
|
3712
4560
|
}
|
|
3713
|
-
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4561
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4562
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
4563
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
4564
|
+
line,
|
|
4565
|
+
column: tokens[0]?.column ?? 1
|
|
4566
|
+
});
|
|
4567
|
+
}
|
|
3714
4568
|
layers[raw] = enabled;
|
|
3715
4569
|
}
|
|
3716
4570
|
}
|
|
@@ -3728,11 +4582,15 @@ var WorldOrbit = (() => {
|
|
|
3728
4582
|
}
|
|
3729
4583
|
function parseProjectionValue(value, line, column) {
|
|
3730
4584
|
const normalized = value.toLowerCase();
|
|
3731
|
-
if (normalized !== "topdown" && normalized !== "isometric") {
|
|
4585
|
+
if (normalized !== "topdown" && normalized !== "isometric" && normalized !== "orthographic" && normalized !== "perspective") {
|
|
3732
4586
|
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
3733
4587
|
}
|
|
3734
4588
|
return normalized;
|
|
3735
4589
|
}
|
|
4590
|
+
function isSchema25Projection(value) {
|
|
4591
|
+
const normalized = value.toLowerCase();
|
|
4592
|
+
return normalized === "orthographic" || normalized === "perspective";
|
|
4593
|
+
}
|
|
3736
4594
|
function parsePresetValue(value, line, column) {
|
|
3737
4595
|
const normalized = value.toLowerCase();
|
|
3738
4596
|
if (normalized === "diagram" || normalized === "presentation" || normalized === "atlas-card" || normalized === "markdown") {
|
|
@@ -3762,6 +4620,48 @@ var WorldOrbit = (() => {
|
|
|
3762
4620
|
groupIds: []
|
|
3763
4621
|
};
|
|
3764
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
|
+
}
|
|
3765
4665
|
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3766
4666
|
const fields = [];
|
|
3767
4667
|
let index = 0;
|
|
@@ -3849,7 +4749,7 @@ var WorldOrbit = (() => {
|
|
|
3849
4749
|
}
|
|
3850
4750
|
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
3851
4751
|
const fieldMap = collectDraftFields(node.fields);
|
|
3852
|
-
const placement =
|
|
4752
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
3853
4753
|
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
3854
4754
|
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
3855
4755
|
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
@@ -3894,21 +4794,41 @@ var WorldOrbit = (() => {
|
|
|
3894
4794
|
object.tolerances = tolerances;
|
|
3895
4795
|
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
3896
4796
|
object.typedBlocks = typedBlocks;
|
|
3897
|
-
if (sourceSchemaVersion
|
|
4797
|
+
if (isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
3898
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) {
|
|
3899
4799
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
3900
4800
|
}
|
|
3901
4801
|
}
|
|
3902
4802
|
return object;
|
|
3903
4803
|
}
|
|
3904
|
-
function
|
|
4804
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
4805
|
+
return {
|
|
4806
|
+
...event,
|
|
4807
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
4808
|
+
tags: [...new Set(event.tags)],
|
|
4809
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
|
|
4810
|
+
};
|
|
4811
|
+
}
|
|
4812
|
+
function normalizeDraftEventPose(rawPose) {
|
|
4813
|
+
const fieldMap = collectDraftFields(rawPose.fields, "event-pose");
|
|
4814
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4815
|
+
return {
|
|
4816
|
+
objectId: rawPose.objectId,
|
|
4817
|
+
placement,
|
|
4818
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
4819
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer"),
|
|
4820
|
+
epoch: parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]),
|
|
4821
|
+
referencePlane: parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0])
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
function collectDraftFields(fields, _mode = "object") {
|
|
3905
4825
|
const grouped = /* @__PURE__ */ new Map();
|
|
3906
4826
|
for (const field of fields) {
|
|
3907
4827
|
const spec = getDraftObjectFieldSpec(field.key);
|
|
3908
|
-
if (!spec) {
|
|
4828
|
+
if (!spec && !EVENT_POSE_FIELD_KEYS.has(field.key)) {
|
|
3909
4829
|
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
3910
4830
|
}
|
|
3911
|
-
if (!spec
|
|
4831
|
+
if (!spec?.allowRepeat && grouped.has(field.key)) {
|
|
3912
4832
|
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
3913
4833
|
}
|
|
3914
4834
|
const existing = grouped.get(field.key) ?? [];
|
|
@@ -3917,7 +4837,7 @@ var WorldOrbit = (() => {
|
|
|
3917
4837
|
}
|
|
3918
4838
|
return grouped;
|
|
3919
4839
|
}
|
|
3920
|
-
function
|
|
4840
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
3921
4841
|
const orbitField = fieldMap.get("orbit")?.[0];
|
|
3922
4842
|
const atField = fieldMap.get("at")?.[0];
|
|
3923
4843
|
const surfaceField = fieldMap.get("surface")?.[0];
|
|
@@ -4085,7 +5005,7 @@ var WorldOrbit = (() => {
|
|
|
4085
5005
|
}
|
|
4086
5006
|
}
|
|
4087
5007
|
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
4088
|
-
if (sourceSchemaVersion
|
|
5008
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
4089
5009
|
return;
|
|
4090
5010
|
}
|
|
4091
5011
|
diagnostics.push({
|
|
@@ -4097,6 +5017,34 @@ var WorldOrbit = (() => {
|
|
|
4097
5017
|
column: location.column
|
|
4098
5018
|
});
|
|
4099
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
|
+
}
|
|
4100
5048
|
function preprocessAtlasSource(source) {
|
|
4101
5049
|
const chars = [...source];
|
|
4102
5050
|
const comments = [];
|
|
@@ -4184,8 +5132,9 @@ var WorldOrbit = (() => {
|
|
|
4184
5132
|
}
|
|
4185
5133
|
|
|
4186
5134
|
// packages/core/dist/load.js
|
|
4187
|
-
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|
|
5135
|
+
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1|\.5)?$/i;
|
|
4188
5136
|
var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
5137
|
+
var ATLAS_SCHEMA_25_PATTERN = /^schema\s+2\.5$/i;
|
|
4189
5138
|
var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
4190
5139
|
function detectWorldOrbitSchemaVersion(source) {
|
|
4191
5140
|
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
@@ -4199,6 +5148,9 @@ var WorldOrbit = (() => {
|
|
|
4199
5148
|
if (ATLAS_SCHEMA_21_PATTERN.test(trimmed)) {
|
|
4200
5149
|
return "2.1";
|
|
4201
5150
|
}
|
|
5151
|
+
if (ATLAS_SCHEMA_25_PATTERN.test(trimmed)) {
|
|
5152
|
+
return "2.5";
|
|
5153
|
+
}
|
|
4202
5154
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
4203
5155
|
return "2.0";
|
|
4204
5156
|
}
|
|
@@ -4259,7 +5211,7 @@ var WorldOrbit = (() => {
|
|
|
4259
5211
|
}
|
|
4260
5212
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
4261
5213
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
4262
|
-
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") {
|
|
4263
5215
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
4264
5216
|
}
|
|
4265
5217
|
let ast;
|
|
@@ -4353,6 +5305,7 @@ var WorldOrbit = (() => {
|
|
|
4353
5305
|
background: true,
|
|
4354
5306
|
guides: true,
|
|
4355
5307
|
relations: true,
|
|
5308
|
+
events: true,
|
|
4356
5309
|
orbits: true,
|
|
4357
5310
|
objects: true,
|
|
4358
5311
|
labels: true,
|
|
@@ -4556,6 +5509,7 @@ var WorldOrbit = (() => {
|
|
|
4556
5509
|
const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
|
|
4557
5510
|
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("") : "";
|
|
4558
5511
|
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("") : "";
|
|
5512
|
+
const eventMarkup = layers.events ? scene.events.filter((event) => !event.hidden).map((event) => renderSceneEventOverlay(scene, event, visibleObjectIds, theme)).join("") : "";
|
|
4559
5513
|
const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
|
|
4560
5514
|
const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
|
|
4561
5515
|
const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
|
|
@@ -4591,6 +5545,9 @@ var WorldOrbit = (() => {
|
|
|
4591
5545
|
.wo-orbit-front { opacity: 0.9; }
|
|
4592
5546
|
.wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
|
|
4593
5547
|
.wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
|
|
5548
|
+
.wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
|
|
5549
|
+
.wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
|
|
5550
|
+
.wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
4594
5551
|
.wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
|
|
4595
5552
|
.wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
|
|
4596
5553
|
.wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
|
|
@@ -4625,6 +5582,7 @@ var WorldOrbit = (() => {
|
|
|
4625
5582
|
${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
|
|
4626
5583
|
${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
|
|
4627
5584
|
${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
|
|
5585
|
+
${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
|
|
4628
5586
|
${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
|
|
4629
5587
|
${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
|
|
4630
5588
|
${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
|
|
@@ -4632,6 +5590,20 @@ var WorldOrbit = (() => {
|
|
|
4632
5590
|
</g>
|
|
4633
5591
|
</g>
|
|
4634
5592
|
</svg>`;
|
|
5593
|
+
}
|
|
5594
|
+
function renderSceneEventOverlay(scene, event, visibleObjectIds, theme) {
|
|
5595
|
+
const participants = event.objectIds.filter((objectId) => visibleObjectIds.has(objectId)).map((objectId) => scene.objects.find((object) => object.objectId === objectId && !object.hidden)).filter(Boolean);
|
|
5596
|
+
if (participants.length === 0) {
|
|
5597
|
+
return "";
|
|
5598
|
+
}
|
|
5599
|
+
const stroke = event.event.color || theme.accent;
|
|
5600
|
+
const label = event.event.label || event.event.id;
|
|
5601
|
+
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("");
|
|
5602
|
+
return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
|
|
5603
|
+
${lineMarkup}
|
|
5604
|
+
<circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
|
|
5605
|
+
<text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
|
|
5606
|
+
</g>`;
|
|
4635
5607
|
}
|
|
4636
5608
|
function renderOrbitLayer(scene, visibleObjectIds, includeStructures) {
|
|
4637
5609
|
const backParts = [];
|