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
|
@@ -61,6 +61,7 @@ var WorldOrbit = (() => {
|
|
|
61
61
|
background: true,
|
|
62
62
|
guides: true,
|
|
63
63
|
relations: true,
|
|
64
|
+
events: true,
|
|
64
65
|
orbits: true,
|
|
65
66
|
objects: true,
|
|
66
67
|
labels: true,
|
|
@@ -210,14 +211,17 @@ var WorldOrbit = (() => {
|
|
|
210
211
|
}
|
|
211
212
|
function createAtlasStateSnapshot(viewerState, renderOptions, filter, viewpointId) {
|
|
212
213
|
return {
|
|
213
|
-
version: "2.
|
|
214
|
+
version: "2.5",
|
|
214
215
|
viewpointId,
|
|
216
|
+
activeEventId: renderOptions.activeEventId ?? null,
|
|
215
217
|
viewerState: { ...viewerState },
|
|
216
218
|
renderOptions: {
|
|
217
219
|
preset: renderOptions.preset,
|
|
218
220
|
projection: renderOptions.projection,
|
|
221
|
+
camera: renderOptions.camera ? { ...renderOptions.camera } : null,
|
|
219
222
|
layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
|
|
220
|
-
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0
|
|
223
|
+
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0,
|
|
224
|
+
activeEventId: renderOptions.activeEventId ?? null
|
|
221
225
|
},
|
|
222
226
|
filter: normalizeViewerFilter(filter)
|
|
223
227
|
};
|
|
@@ -228,8 +232,9 @@ var WorldOrbit = (() => {
|
|
|
228
232
|
function deserializeViewerAtlasState(serialized) {
|
|
229
233
|
const raw = JSON.parse(decodeURIComponent(serialized));
|
|
230
234
|
return {
|
|
231
|
-
version: "2.0",
|
|
235
|
+
version: raw.version === "2.0" ? "2.0" : "2.5",
|
|
232
236
|
viewpointId: raw.viewpointId ?? null,
|
|
237
|
+
activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null,
|
|
233
238
|
viewerState: {
|
|
234
239
|
scale: raw.viewerState?.scale ?? 1,
|
|
235
240
|
rotationDeg: raw.viewerState?.rotationDeg ?? 0,
|
|
@@ -240,8 +245,10 @@ var WorldOrbit = (() => {
|
|
|
240
245
|
renderOptions: {
|
|
241
246
|
preset: raw.renderOptions?.preset,
|
|
242
247
|
projection: raw.renderOptions?.projection,
|
|
248
|
+
camera: raw.renderOptions?.camera ? { ...raw.renderOptions.camera } : null,
|
|
243
249
|
layers: raw.renderOptions?.layers ? { ...raw.renderOptions.layers } : void 0,
|
|
244
|
-
scaleModel: raw.renderOptions?.scaleModel ? { ...raw.renderOptions.scaleModel } : void 0
|
|
250
|
+
scaleModel: raw.renderOptions?.scaleModel ? { ...raw.renderOptions.scaleModel } : void 0,
|
|
251
|
+
activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null
|
|
245
252
|
},
|
|
246
253
|
filter: normalizeViewerFilter(raw.filter ?? null)
|
|
247
254
|
};
|
|
@@ -256,8 +263,10 @@ var WorldOrbit = (() => {
|
|
|
256
263
|
viewerState: { ...atlasState.viewerState },
|
|
257
264
|
renderOptions: {
|
|
258
265
|
...atlasState.renderOptions,
|
|
266
|
+
camera: atlasState.renderOptions.camera ? { ...atlasState.renderOptions.camera } : null,
|
|
259
267
|
layers: atlasState.renderOptions.layers ? { ...atlasState.renderOptions.layers } : void 0,
|
|
260
|
-
scaleModel: atlasState.renderOptions.scaleModel ? { ...atlasState.renderOptions.scaleModel } : void 0
|
|
268
|
+
scaleModel: atlasState.renderOptions.scaleModel ? { ...atlasState.renderOptions.scaleModel } : void 0,
|
|
269
|
+
activeEventId: atlasState.renderOptions.activeEventId ?? null
|
|
261
270
|
},
|
|
262
271
|
filter: atlasState.filter ? { ...atlasState.filter } : null
|
|
263
272
|
}
|
|
@@ -275,6 +284,7 @@ var WorldOrbit = (() => {
|
|
|
275
284
|
background: viewpoint.layers.background,
|
|
276
285
|
guides: viewpoint.layers.guides,
|
|
277
286
|
relations: viewpoint.layers.relations,
|
|
287
|
+
events: viewpoint.layers.events,
|
|
278
288
|
orbits: viewpoint.layers["orbits-front"] === void 0 && viewpoint.layers["orbits-back"] === void 0 ? void 0 : viewpoint.layers["orbits-front"] !== false || viewpoint.layers["orbits-back"] !== false,
|
|
279
289
|
objects: viewpoint.layers.objects,
|
|
280
290
|
labels: viewpoint.layers.labels,
|
|
@@ -922,6 +932,7 @@ var WorldOrbit = (() => {
|
|
|
922
932
|
system,
|
|
923
933
|
groups: [],
|
|
924
934
|
relations: [],
|
|
935
|
+
events: [],
|
|
925
936
|
objects
|
|
926
937
|
};
|
|
927
938
|
}
|
|
@@ -1301,12 +1312,16 @@ var WorldOrbit = (() => {
|
|
|
1301
1312
|
const height = frame.height;
|
|
1302
1313
|
const padding = frame.padding;
|
|
1303
1314
|
const layoutPreset = resolveLayoutPreset(document2);
|
|
1304
|
-
const
|
|
1315
|
+
const schemaProjection = resolveProjection(document2, options.projection);
|
|
1316
|
+
const camera = normalizeViewCamera(options.camera ?? null);
|
|
1317
|
+
const renderProjection = resolveRenderProjection(schemaProjection, camera);
|
|
1305
1318
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
1306
1319
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
1307
1320
|
const systemId = document2.system?.id ?? null;
|
|
1308
|
-
const
|
|
1309
|
-
const
|
|
1321
|
+
const activeEventId = options.activeEventId ?? null;
|
|
1322
|
+
const effectiveObjects = createEffectiveObjects(document2.objects, document2.events ?? [], activeEventId);
|
|
1323
|
+
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
1324
|
+
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
1310
1325
|
const positions = /* @__PURE__ */ new Map();
|
|
1311
1326
|
const orbitDrafts = [];
|
|
1312
1327
|
const leaderDrafts = [];
|
|
@@ -1315,7 +1330,7 @@ var WorldOrbit = (() => {
|
|
|
1315
1330
|
const atObjects = [];
|
|
1316
1331
|
const surfaceChildren = /* @__PURE__ */ new Map();
|
|
1317
1332
|
const orbitChildren = /* @__PURE__ */ new Map();
|
|
1318
|
-
for (const object of
|
|
1333
|
+
for (const object of effectiveObjects) {
|
|
1319
1334
|
const placement = object.placement;
|
|
1320
1335
|
if (!placement) {
|
|
1321
1336
|
rootObjects.push(object);
|
|
@@ -1342,7 +1357,7 @@ var WorldOrbit = (() => {
|
|
|
1342
1357
|
surfaceChildren,
|
|
1343
1358
|
objectMap,
|
|
1344
1359
|
spacingFactor,
|
|
1345
|
-
projection,
|
|
1360
|
+
projection: renderProjection,
|
|
1346
1361
|
scaleModel
|
|
1347
1362
|
};
|
|
1348
1363
|
const primaryRoot = rootObjects.find((object) => object.type === "star") ?? rootObjects[0] ?? null;
|
|
@@ -1354,7 +1369,7 @@ var WorldOrbit = (() => {
|
|
|
1354
1369
|
const rootRingRadius = Math.min(width, height) * 0.28 * spacingFactor * scaleModel.orbitDistanceMultiplier;
|
|
1355
1370
|
secondaryRoots.forEach((object, index) => {
|
|
1356
1371
|
const angle = angleForIndex(index, secondaryRoots.length, -Math.PI / 2);
|
|
1357
|
-
const offset = projectPolarOffset(angle, rootRingRadius,
|
|
1372
|
+
const offset = projectPolarOffset(angle, rootRingRadius, renderProjection, 1);
|
|
1358
1373
|
placeObject(object, centerX + offset.x, centerY + offset.y, 0, positions, orbitDrafts, leaderDrafts, context);
|
|
1359
1374
|
});
|
|
1360
1375
|
}
|
|
@@ -1410,38 +1425,48 @@ var WorldOrbit = (() => {
|
|
|
1410
1425
|
const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
|
|
1411
1426
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1412
1427
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1413
|
-
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1428
|
+
const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
|
|
1414
1429
|
const relations = createSceneRelations(document2, objects);
|
|
1415
|
-
const
|
|
1416
|
-
const
|
|
1430
|
+
const events = createSceneEvents(document2.events ?? [], objects, activeEventId);
|
|
1431
|
+
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1432
|
+
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1417
1433
|
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1418
|
-
const viewpoints = createSceneViewpoints(document2,
|
|
1419
|
-
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1434
|
+
const viewpoints = createSceneViewpoints(document2, schemaProjection, frame.preset, relationships, objectMap);
|
|
1435
|
+
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1420
1436
|
return {
|
|
1421
1437
|
width,
|
|
1422
1438
|
height,
|
|
1423
1439
|
padding,
|
|
1424
1440
|
renderPreset: frame.preset,
|
|
1425
|
-
projection,
|
|
1441
|
+
projection: schemaProjection,
|
|
1442
|
+
renderProjection,
|
|
1443
|
+
camera,
|
|
1426
1444
|
scaleModel,
|
|
1427
1445
|
title: String(document2.system?.title ?? document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1428
|
-
subtitle:
|
|
1446
|
+
subtitle: buildSceneSubtitle(schemaProjection, renderProjection, layoutPreset, camera),
|
|
1429
1447
|
systemId,
|
|
1430
|
-
viewMode:
|
|
1448
|
+
viewMode: schemaProjection,
|
|
1431
1449
|
layoutPreset,
|
|
1432
1450
|
metadata: {
|
|
1433
1451
|
format: document2.format,
|
|
1434
1452
|
version: document2.version,
|
|
1435
|
-
view:
|
|
1453
|
+
view: schemaProjection,
|
|
1454
|
+
renderProjection,
|
|
1436
1455
|
scale: String(document2.system?.properties.scale ?? layoutPreset),
|
|
1437
1456
|
units: String(document2.system?.properties.units ?? "mixed"),
|
|
1438
|
-
preset: frame.preset ?? "custom"
|
|
1457
|
+
preset: frame.preset ?? "custom",
|
|
1458
|
+
...camera?.azimuth !== null ? { "camera.azimuth": String(camera?.azimuth) } : {},
|
|
1459
|
+
...camera?.elevation !== null ? { "camera.elevation": String(camera?.elevation) } : {},
|
|
1460
|
+
...camera?.roll !== null ? { "camera.roll": String(camera?.roll) } : {},
|
|
1461
|
+
...camera?.distance !== null ? { "camera.distance": String(camera?.distance) } : {}
|
|
1439
1462
|
},
|
|
1440
1463
|
contentBounds,
|
|
1441
1464
|
layers,
|
|
1442
1465
|
groups,
|
|
1443
1466
|
semanticGroups,
|
|
1444
1467
|
viewpoints,
|
|
1468
|
+
events,
|
|
1469
|
+
activeEventId,
|
|
1445
1470
|
objects,
|
|
1446
1471
|
orbitVisuals,
|
|
1447
1472
|
relations,
|
|
@@ -1460,6 +1485,56 @@ var WorldOrbit = (() => {
|
|
|
1460
1485
|
y: center.y + dx * sin + dy * cos
|
|
1461
1486
|
};
|
|
1462
1487
|
}
|
|
1488
|
+
function createEffectiveObjects(objects, events, activeEventId) {
|
|
1489
|
+
const cloned = objects.map((object) => structuredClone(object));
|
|
1490
|
+
if (!activeEventId) {
|
|
1491
|
+
return cloned;
|
|
1492
|
+
}
|
|
1493
|
+
const activeEvent = events.find((event) => event.id === activeEventId);
|
|
1494
|
+
if (!activeEvent) {
|
|
1495
|
+
return cloned;
|
|
1496
|
+
}
|
|
1497
|
+
const objectMap = new Map(cloned.map((object) => [object.id, object]));
|
|
1498
|
+
const referencedIds = /* @__PURE__ */ new Set([
|
|
1499
|
+
...activeEvent.targetObjectId ? [activeEvent.targetObjectId] : [],
|
|
1500
|
+
...activeEvent.participantObjectIds,
|
|
1501
|
+
...activeEvent.positions.map((pose) => pose.objectId)
|
|
1502
|
+
]);
|
|
1503
|
+
for (const objectId of referencedIds) {
|
|
1504
|
+
const object = objectMap.get(objectId);
|
|
1505
|
+
if (!object) {
|
|
1506
|
+
continue;
|
|
1507
|
+
}
|
|
1508
|
+
if (activeEvent.epoch) {
|
|
1509
|
+
object.epoch = activeEvent.epoch;
|
|
1510
|
+
}
|
|
1511
|
+
if (activeEvent.referencePlane) {
|
|
1512
|
+
object.referencePlane = activeEvent.referencePlane;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
for (const pose of activeEvent.positions) {
|
|
1516
|
+
const object = objectMap.get(pose.objectId);
|
|
1517
|
+
if (!object) {
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
if (pose.placement) {
|
|
1521
|
+
object.placement = structuredClone(pose.placement);
|
|
1522
|
+
}
|
|
1523
|
+
if (pose.inner) {
|
|
1524
|
+
object.properties.inner = { ...pose.inner };
|
|
1525
|
+
}
|
|
1526
|
+
if (pose.outer) {
|
|
1527
|
+
object.properties.outer = { ...pose.outer };
|
|
1528
|
+
}
|
|
1529
|
+
if (pose.epoch) {
|
|
1530
|
+
object.epoch = pose.epoch;
|
|
1531
|
+
}
|
|
1532
|
+
if (pose.referencePlane) {
|
|
1533
|
+
object.referencePlane = pose.referencePlane;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return cloned;
|
|
1537
|
+
}
|
|
1463
1538
|
function resolveLayoutPreset(document2) {
|
|
1464
1539
|
const rawScale = String(document2.system?.properties.scale ?? "balanced").toLowerCase();
|
|
1465
1540
|
switch (rawScale) {
|
|
@@ -1496,10 +1571,59 @@ var WorldOrbit = (() => {
|
|
|
1496
1571
|
}
|
|
1497
1572
|
}
|
|
1498
1573
|
function resolveProjection(document2, projection) {
|
|
1499
|
-
if (projection === "topdown" || projection === "isometric") {
|
|
1574
|
+
if (projection === "topdown" || projection === "isometric" || projection === "orthographic" || projection === "perspective") {
|
|
1500
1575
|
return projection;
|
|
1501
1576
|
}
|
|
1502
|
-
|
|
1577
|
+
const documentView = String(document2.system?.properties.view ?? "topdown").toLowerCase();
|
|
1578
|
+
return parseViewProjection(documentView) ?? "topdown";
|
|
1579
|
+
}
|
|
1580
|
+
function resolveRenderProjection(projection, camera) {
|
|
1581
|
+
switch (projection) {
|
|
1582
|
+
case "topdown":
|
|
1583
|
+
return "topdown";
|
|
1584
|
+
case "isometric":
|
|
1585
|
+
return "isometric";
|
|
1586
|
+
case "orthographic":
|
|
1587
|
+
return camera && (camera.azimuth !== null || camera.elevation !== null || camera.roll !== null) ? "isometric" : "topdown";
|
|
1588
|
+
case "perspective":
|
|
1589
|
+
return "isometric";
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
function normalizeViewCamera(camera) {
|
|
1593
|
+
if (!camera) {
|
|
1594
|
+
return null;
|
|
1595
|
+
}
|
|
1596
|
+
const normalized = {
|
|
1597
|
+
azimuth: normalizeFiniteCameraValue(camera.azimuth),
|
|
1598
|
+
elevation: normalizeFiniteCameraValue(camera.elevation),
|
|
1599
|
+
roll: normalizeFiniteCameraValue(camera.roll),
|
|
1600
|
+
distance: normalizePositiveCameraDistance(camera.distance)
|
|
1601
|
+
};
|
|
1602
|
+
return normalized.azimuth !== null || normalized.elevation !== null || normalized.roll !== null || normalized.distance !== null ? normalized : null;
|
|
1603
|
+
}
|
|
1604
|
+
function normalizeFiniteCameraValue(value) {
|
|
1605
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1606
|
+
}
|
|
1607
|
+
function normalizePositiveCameraDistance(value) {
|
|
1608
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
|
1609
|
+
}
|
|
1610
|
+
function buildSceneSubtitle(projection, renderProjection, layoutPreset, camera) {
|
|
1611
|
+
const parts = [`${capitalizeLabel(projection)} view`, `${capitalizeLabel(layoutPreset)} layout`];
|
|
1612
|
+
if (projection !== renderProjection) {
|
|
1613
|
+
parts.push(`2D ${renderProjection} fallback`);
|
|
1614
|
+
}
|
|
1615
|
+
if (camera) {
|
|
1616
|
+
const cameraParts = [
|
|
1617
|
+
camera.azimuth !== null ? `az ${camera.azimuth}` : null,
|
|
1618
|
+
camera.elevation !== null ? `el ${camera.elevation}` : null,
|
|
1619
|
+
camera.roll !== null ? `roll ${camera.roll}` : null,
|
|
1620
|
+
camera.distance !== null ? `dist ${camera.distance}` : null
|
|
1621
|
+
].filter(Boolean);
|
|
1622
|
+
if (cameraParts.length > 0) {
|
|
1623
|
+
parts.push(`camera ${cameraParts.join(" / ")}`);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
return parts.join(" - ");
|
|
1503
1627
|
}
|
|
1504
1628
|
function resolveScaleModel(layoutPreset, overrides) {
|
|
1505
1629
|
const defaults = defaultScaleModel(layoutPreset);
|
|
@@ -1615,24 +1739,14 @@ var WorldOrbit = (() => {
|
|
|
1615
1739
|
hidden: draft.object.properties.hidden === true
|
|
1616
1740
|
};
|
|
1617
1741
|
}
|
|
1618
|
-
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1742
|
+
function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1619
1743
|
const labels = [];
|
|
1620
1744
|
const occupied = [];
|
|
1621
|
-
const
|
|
1745
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1746
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
|
|
1622
1747
|
for (const object of visibleObjects) {
|
|
1623
|
-
const
|
|
1624
|
-
|
|
1625
|
-
let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
|
|
1626
|
-
let secondaryY = labelY + direction * (16 * labelMultiplier);
|
|
1627
|
-
let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1628
|
-
let attempts = 0;
|
|
1629
|
-
while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
|
|
1630
|
-
labelY += direction * 14 * labelMultiplier;
|
|
1631
|
-
secondaryY += direction * 14 * labelMultiplier;
|
|
1632
|
-
bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1633
|
-
attempts += 1;
|
|
1634
|
-
}
|
|
1635
|
-
occupied.push(bounds);
|
|
1748
|
+
const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
|
|
1749
|
+
occupied.push(createLabelRect(object, placement, labelMultiplier));
|
|
1636
1750
|
labels.push({
|
|
1637
1751
|
renderId: `${object.renderId}-label`,
|
|
1638
1752
|
objectId: object.objectId,
|
|
@@ -1641,17 +1755,128 @@ var WorldOrbit = (() => {
|
|
|
1641
1755
|
semanticGroupIds: [...object.semanticGroupIds],
|
|
1642
1756
|
label: object.label,
|
|
1643
1757
|
secondaryLabel: object.secondaryLabel,
|
|
1644
|
-
x:
|
|
1645
|
-
y: labelY,
|
|
1646
|
-
secondaryY,
|
|
1647
|
-
textAnchor:
|
|
1648
|
-
direction: direction
|
|
1758
|
+
x: placement.x,
|
|
1759
|
+
y: placement.labelY,
|
|
1760
|
+
secondaryY: placement.secondaryY,
|
|
1761
|
+
textAnchor: placement.textAnchor,
|
|
1762
|
+
direction: placement.direction,
|
|
1649
1763
|
hidden: object.hidden
|
|
1650
1764
|
});
|
|
1651
1765
|
}
|
|
1652
1766
|
return labels;
|
|
1653
1767
|
}
|
|
1654
|
-
function
|
|
1768
|
+
function compareLabelPlacementOrder(left, right) {
|
|
1769
|
+
const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
|
|
1770
|
+
if (priorityDiff !== 0) {
|
|
1771
|
+
return priorityDiff;
|
|
1772
|
+
}
|
|
1773
|
+
const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
|
|
1774
|
+
if (renderPriorityDiff !== 0) {
|
|
1775
|
+
return renderPriorityDiff;
|
|
1776
|
+
}
|
|
1777
|
+
return left.sortKey - right.sortKey;
|
|
1778
|
+
}
|
|
1779
|
+
function labelPlacementPriority(object) {
|
|
1780
|
+
switch (object.object.type) {
|
|
1781
|
+
case "star":
|
|
1782
|
+
return 0;
|
|
1783
|
+
case "planet":
|
|
1784
|
+
return 1;
|
|
1785
|
+
case "moon":
|
|
1786
|
+
return 2;
|
|
1787
|
+
case "belt":
|
|
1788
|
+
case "ring":
|
|
1789
|
+
return 3;
|
|
1790
|
+
case "asteroid":
|
|
1791
|
+
case "comet":
|
|
1792
|
+
return 4;
|
|
1793
|
+
case "structure":
|
|
1794
|
+
case "phenomenon":
|
|
1795
|
+
return 5;
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1799
|
+
for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
|
|
1800
|
+
const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
|
|
1801
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
|
|
1802
|
+
const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
|
|
1803
|
+
const rect = createLabelRect(object, placement, labelMultiplier);
|
|
1804
|
+
if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
|
|
1805
|
+
return placement;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
return null;
|
|
1810
|
+
}
|
|
1811
|
+
function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
|
|
1812
|
+
const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
|
|
1813
|
+
const vertical = defaultVerticalDirection(object, parent, sceneHeight);
|
|
1814
|
+
const oppositeVertical = vertical === "below" ? "above" : "below";
|
|
1815
|
+
const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
|
|
1816
|
+
const oppositeHorizontal = horizontal === "right" ? "left" : "right";
|
|
1817
|
+
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";
|
|
1818
|
+
return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
|
|
1819
|
+
}
|
|
1820
|
+
function defaultVerticalDirection(object, parent, sceneHeight) {
|
|
1821
|
+
if (parent && Math.abs(object.y - parent.y) > 6) {
|
|
1822
|
+
return object.y >= parent.y ? "below" : "above";
|
|
1823
|
+
}
|
|
1824
|
+
return object.y > sceneHeight * 0.62 ? "above" : "below";
|
|
1825
|
+
}
|
|
1826
|
+
function defaultHorizontalDirection(object, parent, sceneWidth) {
|
|
1827
|
+
if (parent && Math.abs(object.x - parent.x) > 6) {
|
|
1828
|
+
return object.x >= parent.x ? "right" : "left";
|
|
1829
|
+
}
|
|
1830
|
+
return object.x >= sceneWidth / 2 ? "right" : "left";
|
|
1831
|
+
}
|
|
1832
|
+
function createLabelPlacement(object, direction, attempt, labelMultiplier) {
|
|
1833
|
+
const step = 14 * labelMultiplier;
|
|
1834
|
+
switch (direction) {
|
|
1835
|
+
case "above": {
|
|
1836
|
+
const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
|
|
1837
|
+
return {
|
|
1838
|
+
x: object.x,
|
|
1839
|
+
labelY,
|
|
1840
|
+
secondaryY: labelY - 16 * labelMultiplier,
|
|
1841
|
+
textAnchor: "middle",
|
|
1842
|
+
direction
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
case "below": {
|
|
1846
|
+
const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
|
|
1847
|
+
return {
|
|
1848
|
+
x: object.x,
|
|
1849
|
+
labelY,
|
|
1850
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1851
|
+
textAnchor: "middle",
|
|
1852
|
+
direction
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
case "left": {
|
|
1856
|
+
const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
|
|
1857
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1858
|
+
return {
|
|
1859
|
+
x,
|
|
1860
|
+
labelY,
|
|
1861
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1862
|
+
textAnchor: "end",
|
|
1863
|
+
direction
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
case "right": {
|
|
1867
|
+
const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
|
|
1868
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1869
|
+
return {
|
|
1870
|
+
x,
|
|
1871
|
+
labelY,
|
|
1872
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1873
|
+
textAnchor: "start",
|
|
1874
|
+
direction
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
|
|
1655
1880
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1656
1881
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1657
1882
|
return [
|
|
@@ -1666,6 +1891,10 @@ var WorldOrbit = (() => {
|
|
|
1666
1891
|
id: "relations",
|
|
1667
1892
|
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1668
1893
|
},
|
|
1894
|
+
{
|
|
1895
|
+
id: "events",
|
|
1896
|
+
renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
|
|
1897
|
+
},
|
|
1669
1898
|
{
|
|
1670
1899
|
id: "objects",
|
|
1671
1900
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1677,7 +1906,7 @@ var WorldOrbit = (() => {
|
|
|
1677
1906
|
{ id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
|
|
1678
1907
|
];
|
|
1679
1908
|
}
|
|
1680
|
-
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
|
|
1909
|
+
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
|
|
1681
1910
|
const groups = /* @__PURE__ */ new Map();
|
|
1682
1911
|
const ensureGroup = (groupId) => {
|
|
1683
1912
|
if (!groupId) {
|
|
@@ -1726,7 +1955,7 @@ var WorldOrbit = (() => {
|
|
|
1726
1955
|
}
|
|
1727
1956
|
}
|
|
1728
1957
|
for (const group of groups.values()) {
|
|
1729
|
-
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
|
|
1958
|
+
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
|
|
1730
1959
|
}
|
|
1731
1960
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1732
1961
|
}
|
|
@@ -1760,6 +1989,29 @@ var WorldOrbit = (() => {
|
|
|
1760
1989
|
};
|
|
1761
1990
|
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1762
1991
|
}
|
|
1992
|
+
function createSceneEvents(events, objects, activeEventId) {
|
|
1993
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1994
|
+
return events.map((event) => {
|
|
1995
|
+
const objectIds = [.../* @__PURE__ */ new Set([
|
|
1996
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
1997
|
+
...event.participantObjectIds
|
|
1998
|
+
])];
|
|
1999
|
+
const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
|
|
2000
|
+
const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
|
|
2001
|
+
const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
|
|
2002
|
+
return {
|
|
2003
|
+
renderId: `${createRenderId(event.id)}-event`,
|
|
2004
|
+
eventId: event.id,
|
|
2005
|
+
event,
|
|
2006
|
+
objectIds,
|
|
2007
|
+
participantIds: [...event.participantObjectIds],
|
|
2008
|
+
targetObjectId: event.targetObjectId,
|
|
2009
|
+
x: centroidX,
|
|
2010
|
+
y: centroidY,
|
|
2011
|
+
hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
|
|
2012
|
+
};
|
|
2013
|
+
}).sort((left, right) => left.event.id.localeCompare(right.event.id));
|
|
2014
|
+
}
|
|
1763
2015
|
function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
|
|
1764
2016
|
const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
|
|
1765
2017
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1807,13 +2059,18 @@ var WorldOrbit = (() => {
|
|
|
1807
2059
|
function createGeneratedOverviewViewpoint(document2, projection, preset) {
|
|
1808
2060
|
const title = document2.system?.title ?? document2.system?.properties.title;
|
|
1809
2061
|
const label = title ? `${String(title)} Overview` : "Overview";
|
|
2062
|
+
const camera = normalizeViewCamera(null);
|
|
2063
|
+
const renderProjection = resolveRenderProjection(projection, camera);
|
|
1810
2064
|
return {
|
|
1811
2065
|
id: "overview",
|
|
1812
2066
|
label,
|
|
1813
2067
|
summary: "Fit the whole system with the current atlas defaults.",
|
|
1814
2068
|
objectId: null,
|
|
1815
2069
|
selectedObjectId: null,
|
|
2070
|
+
eventIds: [],
|
|
1816
2071
|
projection,
|
|
2072
|
+
renderProjection,
|
|
2073
|
+
camera,
|
|
1817
2074
|
preset,
|
|
1818
2075
|
rotationDeg: 0,
|
|
1819
2076
|
scale: null,
|
|
@@ -1849,6 +2106,9 @@ var WorldOrbit = (() => {
|
|
|
1849
2106
|
draft.select = normalizedValue;
|
|
1850
2107
|
}
|
|
1851
2108
|
return;
|
|
2109
|
+
case "events":
|
|
2110
|
+
draft.eventIds = splitListValue(normalizedValue);
|
|
2111
|
+
return;
|
|
1852
2112
|
case "projection":
|
|
1853
2113
|
case "view":
|
|
1854
2114
|
draft.projection = parseViewProjection(normalizedValue) ?? projection;
|
|
@@ -1860,6 +2120,30 @@ var WorldOrbit = (() => {
|
|
|
1860
2120
|
case "angle":
|
|
1861
2121
|
draft.rotationDeg = parseFiniteNumber(normalizedValue) ?? draft.rotationDeg ?? 0;
|
|
1862
2122
|
return;
|
|
2123
|
+
case "camera.azimuth":
|
|
2124
|
+
draft.camera = {
|
|
2125
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
2126
|
+
azimuth: parseFiniteNumber(normalizedValue)
|
|
2127
|
+
};
|
|
2128
|
+
return;
|
|
2129
|
+
case "camera.elevation":
|
|
2130
|
+
draft.camera = {
|
|
2131
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
2132
|
+
elevation: parseFiniteNumber(normalizedValue)
|
|
2133
|
+
};
|
|
2134
|
+
return;
|
|
2135
|
+
case "camera.roll":
|
|
2136
|
+
draft.camera = {
|
|
2137
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
2138
|
+
roll: parseFiniteNumber(normalizedValue)
|
|
2139
|
+
};
|
|
2140
|
+
return;
|
|
2141
|
+
case "camera.distance":
|
|
2142
|
+
draft.camera = {
|
|
2143
|
+
...draft.camera ?? createEmptyViewCamera(),
|
|
2144
|
+
distance: parsePositiveNumber(normalizedValue)
|
|
2145
|
+
};
|
|
2146
|
+
return;
|
|
1863
2147
|
case "zoom":
|
|
1864
2148
|
case "scale":
|
|
1865
2149
|
draft.scale = parsePositiveNumber(normalizedValue);
|
|
@@ -1899,13 +2183,19 @@ var WorldOrbit = (() => {
|
|
|
1899
2183
|
const selectedObjectId = draft.select && objectMap.has(draft.select) ? draft.select : objectId;
|
|
1900
2184
|
const filter = normalizeViewpointFilter(draft.filter);
|
|
1901
2185
|
const label = draft.label?.trim() || humanizeIdentifier(draft.id);
|
|
2186
|
+
const resolvedProjection = draft.projection ?? projection;
|
|
2187
|
+
const camera = normalizeViewCamera(draft.camera ?? null);
|
|
2188
|
+
const renderProjection = resolveRenderProjection(resolvedProjection, camera);
|
|
1902
2189
|
return {
|
|
1903
2190
|
id: draft.id,
|
|
1904
2191
|
label,
|
|
1905
2192
|
summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
|
|
1906
2193
|
objectId,
|
|
1907
2194
|
selectedObjectId,
|
|
1908
|
-
|
|
2195
|
+
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
2196
|
+
projection: resolvedProjection,
|
|
2197
|
+
renderProjection,
|
|
2198
|
+
camera,
|
|
1909
2199
|
preset: draft.preset ?? preset,
|
|
1910
2200
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
1911
2201
|
scale: draft.scale ?? null,
|
|
@@ -1922,6 +2212,14 @@ var WorldOrbit = (() => {
|
|
|
1922
2212
|
groupIds: []
|
|
1923
2213
|
};
|
|
1924
2214
|
}
|
|
2215
|
+
function createEmptyViewCamera() {
|
|
2216
|
+
return {
|
|
2217
|
+
azimuth: null,
|
|
2218
|
+
elevation: null,
|
|
2219
|
+
roll: null,
|
|
2220
|
+
distance: null
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
1925
2223
|
function normalizeViewpointFilter(filter) {
|
|
1926
2224
|
if (!filter) {
|
|
1927
2225
|
return null;
|
|
@@ -1935,7 +2233,18 @@ var WorldOrbit = (() => {
|
|
|
1935
2233
|
return normalized.query || normalized.objectTypes.length > 0 || normalized.tags.length > 0 || normalized.groupIds.length > 0 ? normalized : null;
|
|
1936
2234
|
}
|
|
1937
2235
|
function parseViewProjection(value) {
|
|
1938
|
-
|
|
2236
|
+
switch (value.toLowerCase()) {
|
|
2237
|
+
case "topdown":
|
|
2238
|
+
return "topdown";
|
|
2239
|
+
case "isometric":
|
|
2240
|
+
return "isometric";
|
|
2241
|
+
case "orthographic":
|
|
2242
|
+
return "orthographic";
|
|
2243
|
+
case "perspective":
|
|
2244
|
+
return "perspective";
|
|
2245
|
+
default:
|
|
2246
|
+
return null;
|
|
2247
|
+
}
|
|
1939
2248
|
}
|
|
1940
2249
|
function parseRenderPreset(value) {
|
|
1941
2250
|
const normalized = value.toLowerCase();
|
|
@@ -1962,7 +2271,7 @@ var WorldOrbit = (() => {
|
|
|
1962
2271
|
next["orbits-front"] = enabled;
|
|
1963
2272
|
continue;
|
|
1964
2273
|
}
|
|
1965
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
2274
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1966
2275
|
next[rawLayer] = enabled;
|
|
1967
2276
|
}
|
|
1968
2277
|
}
|
|
@@ -1973,7 +2282,7 @@ var WorldOrbit = (() => {
|
|
|
1973
2282
|
}
|
|
1974
2283
|
function parseViewpointGroups(value, document2, relationships, objectMap) {
|
|
1975
2284
|
return splitListValue(value).map((entry) => {
|
|
1976
|
-
if (document2.schemaVersion === "2.1" || document2.groups.some((group) => group.id === entry)) {
|
|
2285
|
+
if (document2.schemaVersion === "2.1" || document2.schemaVersion === "2.5" || document2.groups.some((group) => group.id === entry)) {
|
|
1977
2286
|
return entry;
|
|
1978
2287
|
}
|
|
1979
2288
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
@@ -2010,7 +2319,7 @@ var WorldOrbit = (() => {
|
|
|
2010
2319
|
}
|
|
2011
2320
|
return parts.join(" - ");
|
|
2012
2321
|
}
|
|
2013
|
-
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
|
|
2322
|
+
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2014
2323
|
let minX = Number.POSITIVE_INFINITY;
|
|
2015
2324
|
let minY = Number.POSITIVE_INFINITY;
|
|
2016
2325
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2040,7 +2349,7 @@ var WorldOrbit = (() => {
|
|
|
2040
2349
|
for (const label of labels) {
|
|
2041
2350
|
if (label.hidden)
|
|
2042
2351
|
continue;
|
|
2043
|
-
includeLabelBounds(label, include);
|
|
2352
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2044
2353
|
}
|
|
2045
2354
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
2046
2355
|
return createBounds(0, 0, width, height);
|
|
@@ -2078,13 +2387,10 @@ var WorldOrbit = (() => {
|
|
|
2078
2387
|
include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
|
|
2079
2388
|
include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
|
|
2080
2389
|
}
|
|
2081
|
-
function includeLabelBounds(label, include) {
|
|
2082
|
-
const
|
|
2083
|
-
|
|
2084
|
-
include(
|
|
2085
|
-
include(label.x + labelHalfWidth, label.y + 8);
|
|
2086
|
-
include(label.x - labelHalfWidth, label.secondaryY - 14);
|
|
2087
|
-
include(label.x + labelHalfWidth, label.secondaryY + 8);
|
|
2390
|
+
function includeLabelBounds(label, include, labelMultiplier) {
|
|
2391
|
+
const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
|
|
2392
|
+
include(bounds.left, bounds.top);
|
|
2393
|
+
include(bounds.right, bounds.bottom);
|
|
2088
2394
|
}
|
|
2089
2395
|
function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
|
|
2090
2396
|
if (positions.has(object.id)) {
|
|
@@ -2474,7 +2780,7 @@ var WorldOrbit = (() => {
|
|
|
2474
2780
|
return null;
|
|
2475
2781
|
}
|
|
2476
2782
|
}
|
|
2477
|
-
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
|
|
2783
|
+
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2478
2784
|
let minX = Number.POSITIVE_INFINITY;
|
|
2479
2785
|
let minY = Number.POSITIVE_INFINITY;
|
|
2480
2786
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2503,7 +2809,7 @@ var WorldOrbit = (() => {
|
|
|
2503
2809
|
}
|
|
2504
2810
|
for (const label of labels) {
|
|
2505
2811
|
if (!label.hidden && group.labelIds.includes(label.objectId)) {
|
|
2506
|
-
includeLabelBounds(label, include);
|
|
2812
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2507
2813
|
}
|
|
2508
2814
|
}
|
|
2509
2815
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
@@ -2528,12 +2834,28 @@ var WorldOrbit = (() => {
|
|
|
2528
2834
|
}
|
|
2529
2835
|
return current.id;
|
|
2530
2836
|
}
|
|
2531
|
-
function createLabelRect(
|
|
2837
|
+
function createLabelRect(object, placement, labelMultiplier) {
|
|
2838
|
+
return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
|
|
2839
|
+
}
|
|
2840
|
+
function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
|
|
2841
|
+
const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
|
|
2842
|
+
const labelWidth = labelHalfWidth * 2;
|
|
2843
|
+
const topPadding = direction === "above" ? 18 : 12;
|
|
2844
|
+
const bottomPadding = direction === "above" ? 8 : 12;
|
|
2845
|
+
let left = x - labelHalfWidth;
|
|
2846
|
+
let right = x + labelHalfWidth;
|
|
2847
|
+
if (textAnchor === "start") {
|
|
2848
|
+
left = x;
|
|
2849
|
+
right = x + labelWidth;
|
|
2850
|
+
} else if (textAnchor === "end") {
|
|
2851
|
+
left = x - labelWidth;
|
|
2852
|
+
right = x;
|
|
2853
|
+
}
|
|
2532
2854
|
return {
|
|
2533
|
-
left
|
|
2534
|
-
right
|
|
2535
|
-
top: Math.min(labelY, secondaryY) -
|
|
2536
|
-
bottom: Math.max(labelY, secondaryY) +
|
|
2855
|
+
left,
|
|
2856
|
+
right,
|
|
2857
|
+
top: Math.min(labelY, secondaryY) - topPadding,
|
|
2858
|
+
bottom: Math.max(labelY, secondaryY) + bottomPadding
|
|
2537
2859
|
};
|
|
2538
2860
|
}
|
|
2539
2861
|
function rectsOverlap(left, right) {
|
|
@@ -2720,11 +3042,6 @@ var WorldOrbit = (() => {
|
|
|
2720
3042
|
function customColorFor(value) {
|
|
2721
3043
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2722
3044
|
}
|
|
2723
|
-
function estimateLabelHalfWidth(object, labelMultiplier) {
|
|
2724
|
-
const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
|
|
2725
|
-
const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
2726
|
-
return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
|
|
2727
|
-
}
|
|
2728
3045
|
function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
|
|
2729
3046
|
const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
|
|
2730
3047
|
const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
@@ -2741,7 +3058,7 @@ var WorldOrbit = (() => {
|
|
|
2741
3058
|
}
|
|
2742
3059
|
|
|
2743
3060
|
// packages/core/dist/draft.js
|
|
2744
|
-
function materializeAtlasDocument(document2) {
|
|
3061
|
+
function materializeAtlasDocument(document2, options = {}) {
|
|
2745
3062
|
const system = document2.system ? {
|
|
2746
3063
|
type: "system",
|
|
2747
3064
|
id: document2.system.id,
|
|
@@ -2752,6 +3069,8 @@ var WorldOrbit = (() => {
|
|
|
2752
3069
|
properties: materializeDraftSystemProperties(document2.system),
|
|
2753
3070
|
info: materializeDraftSystemInfo(document2.system)
|
|
2754
3071
|
} : null;
|
|
3072
|
+
const objects = document2.objects.map(cloneWorldOrbitObject);
|
|
3073
|
+
applyEventPoseOverrides(objects, document2.events ?? [], options.activeEventId ?? null);
|
|
2755
3074
|
return {
|
|
2756
3075
|
format: "worldorbit",
|
|
2757
3076
|
version: "1.0",
|
|
@@ -2759,7 +3078,8 @@ var WorldOrbit = (() => {
|
|
|
2759
3078
|
system,
|
|
2760
3079
|
groups: structuredClone(document2.groups ?? []),
|
|
2761
3080
|
relations: structuredClone(document2.relations ?? []),
|
|
2762
|
-
|
|
3081
|
+
events: document2.events.map(cloneWorldOrbitEvent),
|
|
3082
|
+
objects
|
|
2763
3083
|
};
|
|
2764
3084
|
}
|
|
2765
3085
|
function cloneWorldOrbitObject(object) {
|
|
@@ -2781,6 +3101,75 @@ var WorldOrbit = (() => {
|
|
|
2781
3101
|
info: { ...object.info }
|
|
2782
3102
|
};
|
|
2783
3103
|
}
|
|
3104
|
+
function cloneWorldOrbitEvent(event) {
|
|
3105
|
+
return {
|
|
3106
|
+
...event,
|
|
3107
|
+
participantObjectIds: [...event.participantObjectIds],
|
|
3108
|
+
tags: [...event.tags],
|
|
3109
|
+
positions: event.positions.map(cloneWorldOrbitEventPose)
|
|
3110
|
+
};
|
|
3111
|
+
}
|
|
3112
|
+
function cloneWorldOrbitEventPose(pose) {
|
|
3113
|
+
return {
|
|
3114
|
+
objectId: pose.objectId,
|
|
3115
|
+
placement: clonePlacement(pose.placement),
|
|
3116
|
+
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
3117
|
+
outer: pose.outer ? { ...pose.outer } : void 0,
|
|
3118
|
+
epoch: pose.epoch ?? null,
|
|
3119
|
+
referencePlane: pose.referencePlane ?? null
|
|
3120
|
+
};
|
|
3121
|
+
}
|
|
3122
|
+
function clonePlacement(placement) {
|
|
3123
|
+
return placement ? structuredClone(placement) : null;
|
|
3124
|
+
}
|
|
3125
|
+
function applyEventPoseOverrides(objects, events, activeEventId) {
|
|
3126
|
+
if (!activeEventId) {
|
|
3127
|
+
return;
|
|
3128
|
+
}
|
|
3129
|
+
const event = events.find((entry) => entry.id === activeEventId);
|
|
3130
|
+
if (!event) {
|
|
3131
|
+
return;
|
|
3132
|
+
}
|
|
3133
|
+
const objectMap = new Map(objects.map((object) => [object.id, object]));
|
|
3134
|
+
const referencedIds = /* @__PURE__ */ new Set([
|
|
3135
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
3136
|
+
...event.participantObjectIds,
|
|
3137
|
+
...event.positions.map((pose) => pose.objectId)
|
|
3138
|
+
]);
|
|
3139
|
+
for (const objectId of referencedIds) {
|
|
3140
|
+
const object = objectMap.get(objectId);
|
|
3141
|
+
if (!object) {
|
|
3142
|
+
continue;
|
|
3143
|
+
}
|
|
3144
|
+
if (event.epoch) {
|
|
3145
|
+
object.epoch = event.epoch;
|
|
3146
|
+
}
|
|
3147
|
+
if (event.referencePlane) {
|
|
3148
|
+
object.referencePlane = event.referencePlane;
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
for (const pose of event.positions) {
|
|
3152
|
+
const object = objectMap.get(pose.objectId);
|
|
3153
|
+
if (!object) {
|
|
3154
|
+
continue;
|
|
3155
|
+
}
|
|
3156
|
+
if (pose.placement) {
|
|
3157
|
+
object.placement = clonePlacement(pose.placement);
|
|
3158
|
+
}
|
|
3159
|
+
if (pose.inner) {
|
|
3160
|
+
object.properties.inner = { ...pose.inner };
|
|
3161
|
+
}
|
|
3162
|
+
if (pose.outer) {
|
|
3163
|
+
object.properties.outer = { ...pose.outer };
|
|
3164
|
+
}
|
|
3165
|
+
if (pose.epoch) {
|
|
3166
|
+
object.epoch = pose.epoch;
|
|
3167
|
+
}
|
|
3168
|
+
if (pose.referencePlane) {
|
|
3169
|
+
object.referencePlane = pose.referencePlane;
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
2784
3173
|
function cloneProperties(properties) {
|
|
2785
3174
|
const next = {};
|
|
2786
3175
|
for (const [key, value] of Object.entries(properties)) {
|
|
@@ -2853,6 +3242,18 @@ var WorldOrbit = (() => {
|
|
|
2853
3242
|
if (viewpoint.rotationDeg !== 0) {
|
|
2854
3243
|
info2[`${prefix}.rotation`] = String(viewpoint.rotationDeg);
|
|
2855
3244
|
}
|
|
3245
|
+
if (viewpoint.camera?.azimuth !== null) {
|
|
3246
|
+
info2[`${prefix}.camera.azimuth`] = String(viewpoint.camera?.azimuth);
|
|
3247
|
+
}
|
|
3248
|
+
if (viewpoint.camera?.elevation !== null) {
|
|
3249
|
+
info2[`${prefix}.camera.elevation`] = String(viewpoint.camera?.elevation);
|
|
3250
|
+
}
|
|
3251
|
+
if (viewpoint.camera?.roll !== null) {
|
|
3252
|
+
info2[`${prefix}.camera.roll`] = String(viewpoint.camera?.roll);
|
|
3253
|
+
}
|
|
3254
|
+
if (viewpoint.camera?.distance !== null) {
|
|
3255
|
+
info2[`${prefix}.camera.distance`] = String(viewpoint.camera?.distance);
|
|
3256
|
+
}
|
|
2856
3257
|
const serializedLayers = serializeViewpointLayers(viewpoint.layers);
|
|
2857
3258
|
if (serializedLayers) {
|
|
2858
3259
|
info2[`${prefix}.layers`] = serializedLayers;
|
|
@@ -2869,6 +3270,9 @@ var WorldOrbit = (() => {
|
|
|
2869
3270
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2870
3271
|
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2871
3272
|
}
|
|
3273
|
+
if (viewpoint.events.length > 0) {
|
|
3274
|
+
info2[`${prefix}.events`] = viewpoint.events.join(" ");
|
|
3275
|
+
}
|
|
2872
3276
|
}
|
|
2873
3277
|
for (const annotation of system.annotations) {
|
|
2874
3278
|
const prefix = `annotation.${annotation.id}`;
|
|
@@ -2893,7 +3297,7 @@ var WorldOrbit = (() => {
|
|
|
2893
3297
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2894
3298
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2895
3299
|
}
|
|
2896
|
-
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
3300
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
2897
3301
|
if (layers[key] !== void 0) {
|
|
2898
3302
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2899
3303
|
}
|
|
@@ -3067,6 +3471,7 @@ var WorldOrbit = (() => {
|
|
|
3067
3471
|
const diagnostics = [];
|
|
3068
3472
|
const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
|
|
3069
3473
|
const groupIds = new Set(document2.groups.map((group) => group.id));
|
|
3474
|
+
const eventIds = new Set(document2.events.map((event) => event.id));
|
|
3070
3475
|
if (!document2.system) {
|
|
3071
3476
|
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
3072
3477
|
}
|
|
@@ -3076,6 +3481,7 @@ var WorldOrbit = (() => {
|
|
|
3076
3481
|
["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
3077
3482
|
["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
3078
3483
|
["relation", document2.relations.map((relation) => relation.id)],
|
|
3484
|
+
["event", document2.events.map((event) => event.id)],
|
|
3079
3485
|
["object", document2.objects.map((object) => object.id)]
|
|
3080
3486
|
]) {
|
|
3081
3487
|
for (const id of ids) {
|
|
@@ -3091,11 +3497,14 @@ var WorldOrbit = (() => {
|
|
|
3091
3497
|
validateRelation(relation, objectMap, diagnostics);
|
|
3092
3498
|
}
|
|
3093
3499
|
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
3094
|
-
|
|
3500
|
+
validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap);
|
|
3095
3501
|
}
|
|
3096
3502
|
for (const object of document2.objects) {
|
|
3097
3503
|
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
3098
3504
|
}
|
|
3505
|
+
for (const event of document2.events) {
|
|
3506
|
+
validateEvent(event, document2.system, objectMap, diagnostics);
|
|
3507
|
+
}
|
|
3099
3508
|
return diagnostics;
|
|
3100
3509
|
}
|
|
3101
3510
|
function validateRelation(relation, objectMap, diagnostics) {
|
|
@@ -3113,15 +3522,24 @@ var WorldOrbit = (() => {
|
|
|
3113
3522
|
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
3114
3523
|
}
|
|
3115
3524
|
}
|
|
3116
|
-
function
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3525
|
+
function validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap) {
|
|
3526
|
+
const filter = viewpoint.filter;
|
|
3527
|
+
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5") {
|
|
3528
|
+
if (filter) {
|
|
3529
|
+
for (const groupId of filter.groupIds) {
|
|
3530
|
+
if (!groupIds.has(groupId)) {
|
|
3531
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpoint.id}".`, void 0, `viewpoint.${viewpoint.id}.groups`));
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
for (const eventId of viewpoint.events ?? []) {
|
|
3536
|
+
if (!eventIds.has(eventId)) {
|
|
3537
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpoint.id}".`, void 0, `viewpoint.${viewpoint.id}.events`));
|
|
3538
|
+
}
|
|
3123
3539
|
}
|
|
3124
3540
|
}
|
|
3541
|
+
validateProjection(viewpoint.projection, diagnostics, `viewpoint.${viewpoint.id}.projection`, viewpoint.id);
|
|
3542
|
+
validateCamera(viewpoint.camera, viewpoint.projection, viewpoint.rotationDeg, diagnostics, viewpoint.id, viewpoint.focusObjectId, viewpoint.selectedObjectId, filter, objectMap);
|
|
3125
3543
|
}
|
|
3126
3544
|
function validateObject(object, system, objectMap, groupIds, diagnostics) {
|
|
3127
3545
|
const placement = object.placement;
|
|
@@ -3134,6 +3552,12 @@ var WorldOrbit = (() => {
|
|
|
3134
3552
|
}
|
|
3135
3553
|
}
|
|
3136
3554
|
}
|
|
3555
|
+
if (typeof object.epoch === "string" && !object.epoch.trim()) {
|
|
3556
|
+
diagnostics.push(warn("validate.epoch.empty", `Object "${object.id}" defines an empty epoch string.`, object.id, "epoch"));
|
|
3557
|
+
}
|
|
3558
|
+
if (typeof object.referencePlane === "string" && !object.referencePlane.trim()) {
|
|
3559
|
+
diagnostics.push(warn("validate.referencePlane.empty", `Object "${object.id}" defines an empty reference plane string.`, object.id, "referencePlane"));
|
|
3560
|
+
}
|
|
3137
3561
|
if (orbitPlacement) {
|
|
3138
3562
|
if (!objectMap.has(orbitPlacement.target)) {
|
|
3139
3563
|
diagnostics.push(error("validate.orbit.target.unknown", `Unknown placement target "${orbitPlacement.target}" on "${object.id}".`, object.id, "orbit"));
|
|
@@ -3205,6 +3629,122 @@ var WorldOrbit = (() => {
|
|
|
3205
3629
|
}
|
|
3206
3630
|
}
|
|
3207
3631
|
}
|
|
3632
|
+
function validateEvent(event, system, objectMap, diagnostics) {
|
|
3633
|
+
const fieldPrefix = `event.${event.id}`;
|
|
3634
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
3635
|
+
if (!event.kind.trim()) {
|
|
3636
|
+
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
3637
|
+
}
|
|
3638
|
+
if (typeof event.epoch === "string" && !event.epoch.trim()) {
|
|
3639
|
+
diagnostics.push(warn("validate.event.epoch.empty", `Event "${event.id}" defines an empty epoch string.`, void 0, `${fieldPrefix}.epoch`));
|
|
3640
|
+
}
|
|
3641
|
+
if (typeof event.referencePlane === "string" && !event.referencePlane.trim()) {
|
|
3642
|
+
diagnostics.push(warn("validate.event.referencePlane.empty", `Event "${event.id}" defines an empty reference plane string.`, void 0, `${fieldPrefix}.referencePlane`));
|
|
3643
|
+
}
|
|
3644
|
+
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3645
|
+
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3646
|
+
}
|
|
3647
|
+
if (event.targetObjectId) {
|
|
3648
|
+
referencedIds.add(event.targetObjectId);
|
|
3649
|
+
if (!objectMap.has(event.targetObjectId)) {
|
|
3650
|
+
diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
const seenParticipants = /* @__PURE__ */ new Set();
|
|
3654
|
+
for (const participantId of event.participantObjectIds) {
|
|
3655
|
+
referencedIds.add(participantId);
|
|
3656
|
+
if (seenParticipants.has(participantId)) {
|
|
3657
|
+
diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
|
|
3658
|
+
continue;
|
|
3659
|
+
}
|
|
3660
|
+
seenParticipants.add(participantId);
|
|
3661
|
+
if (!objectMap.has(participantId)) {
|
|
3662
|
+
diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
|
|
3666
|
+
diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
|
|
3667
|
+
}
|
|
3668
|
+
if (event.positions.length === 0) {
|
|
3669
|
+
diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
|
|
3670
|
+
}
|
|
3671
|
+
if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
|
|
3672
|
+
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`));
|
|
3673
|
+
}
|
|
3674
|
+
const poseIds = /* @__PURE__ */ new Set();
|
|
3675
|
+
for (const pose of event.positions) {
|
|
3676
|
+
const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
|
|
3677
|
+
if (poseIds.has(pose.objectId)) {
|
|
3678
|
+
diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
|
|
3679
|
+
continue;
|
|
3680
|
+
}
|
|
3681
|
+
poseIds.add(pose.objectId);
|
|
3682
|
+
const object = objectMap.get(pose.objectId);
|
|
3683
|
+
if (!object) {
|
|
3684
|
+
diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
|
|
3685
|
+
continue;
|
|
3686
|
+
}
|
|
3687
|
+
if (!referencedIds.has(pose.objectId)) {
|
|
3688
|
+
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
3689
|
+
}
|
|
3690
|
+
validateEventPose(pose, object, event, system, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
3691
|
+
}
|
|
3692
|
+
const missingPoseIds = [...referencedIds].filter((objectId) => !poseIds.has(objectId));
|
|
3693
|
+
if (event.positions.length > 0 && missingPoseIds.length > 0) {
|
|
3694
|
+
diagnostics.push(warn("validate.event.positions.partial", `Event "${event.id}" leaves ${missingPoseIds.length} referenced object(s) on their base placement.`, void 0, `${fieldPrefix}.positions`));
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
function validateEventPose(pose, object, event, system, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3698
|
+
const placement = pose.placement;
|
|
3699
|
+
if (!placement) {
|
|
3700
|
+
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
3701
|
+
return;
|
|
3702
|
+
}
|
|
3703
|
+
if (placement.mode === "orbit") {
|
|
3704
|
+
if (!objectMap.has(placement.target)) {
|
|
3705
|
+
diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
|
|
3706
|
+
}
|
|
3707
|
+
if (placement.distance && placement.semiMajor) {
|
|
3708
|
+
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
3709
|
+
}
|
|
3710
|
+
if (placement.phase && !resolveEffectiveEpoch(system, object, event, pose)) {
|
|
3711
|
+
diagnostics.push(warn("validate.event.pose.phase.epochMissing", `Event "${eventId}" pose "${pose.objectId}" sets "phase" without an effective epoch.`, void 0, `${fieldPrefix}.phase`));
|
|
3712
|
+
}
|
|
3713
|
+
if (placement.inclination && !resolveEffectiveReferencePlane(system, object, event, pose)) {
|
|
3714
|
+
diagnostics.push(warn("validate.event.pose.inclination.referencePlaneMissing", `Event "${eventId}" pose "${pose.objectId}" sets "inclination" without an effective reference plane.`, void 0, `${fieldPrefix}.inclination`));
|
|
3715
|
+
}
|
|
3716
|
+
if (placement.period && !massInSolar(objectMap.get(placement.target)?.properties.mass)) {
|
|
3717
|
+
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`));
|
|
3718
|
+
}
|
|
3719
|
+
return;
|
|
3720
|
+
}
|
|
3721
|
+
if (placement.mode === "surface") {
|
|
3722
|
+
const target = objectMap.get(placement.target);
|
|
3723
|
+
if (!target) {
|
|
3724
|
+
diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
|
|
3725
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3726
|
+
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`));
|
|
3727
|
+
}
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
if (placement.mode === "at") {
|
|
3731
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3732
|
+
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`));
|
|
3733
|
+
}
|
|
3734
|
+
const reference = placement.reference;
|
|
3735
|
+
if (reference.kind === "named" && !objectMap.has(reference.name)) {
|
|
3736
|
+
diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3737
|
+
} else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
|
|
3738
|
+
diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3739
|
+
} else if (reference.kind === "lagrange") {
|
|
3740
|
+
if (!objectMap.has(reference.primary)) {
|
|
3741
|
+
diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3742
|
+
} else if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3743
|
+
diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3208
3748
|
function validateAtTarget(object, objectMap, diagnostics) {
|
|
3209
3749
|
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
3210
3750
|
if (!reference) {
|
|
@@ -3310,6 +3850,52 @@ var WorldOrbit = (() => {
|
|
|
3310
3850
|
return null;
|
|
3311
3851
|
}
|
|
3312
3852
|
}
|
|
3853
|
+
function validateProjection(projection, diagnostics, field, viewpointId) {
|
|
3854
|
+
if (projection !== "topdown" && projection !== "isometric" && projection !== "orthographic" && projection !== "perspective") {
|
|
3855
|
+
diagnostics.push(error("validate.viewpoint.projection.invalid", `Unknown projection "${String(projection)}" in viewpoint "${viewpointId}".`, void 0, field));
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
function validateCamera(camera, projection, rotationDeg, diagnostics, viewpointId, focusObjectId, selectedObjectId, filter, objectMap) {
|
|
3859
|
+
if (!camera) {
|
|
3860
|
+
return;
|
|
3861
|
+
}
|
|
3862
|
+
const prefix = `viewpoint.${viewpointId}.camera`;
|
|
3863
|
+
for (const [key, value] of [
|
|
3864
|
+
["azimuth", camera.azimuth],
|
|
3865
|
+
["elevation", camera.elevation],
|
|
3866
|
+
["roll", camera.roll],
|
|
3867
|
+
["distance", camera.distance]
|
|
3868
|
+
]) {
|
|
3869
|
+
if (value !== null && (!Number.isFinite(value) || key === "distance" && value <= 0)) {
|
|
3870
|
+
diagnostics.push(error("validate.viewpoint.camera.invalid", `Invalid camera ${key} "${String(value)}" in viewpoint "${viewpointId}".`, void 0, `${prefix}.${key}`));
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
if (camera.distance !== null && projection !== "perspective") {
|
|
3874
|
+
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`));
|
|
3875
|
+
}
|
|
3876
|
+
if (projection === "topdown" && (camera.elevation !== null || camera.roll !== null)) {
|
|
3877
|
+
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));
|
|
3878
|
+
}
|
|
3879
|
+
if (projection === "isometric" && camera.elevation !== null) {
|
|
3880
|
+
diagnostics.push(info("validate.viewpoint.camera.isometricStored", `Camera elevation on isometric viewpoint "${viewpointId}" is preserved semantically for future 3D rendering.`, void 0, `${prefix}.elevation`));
|
|
3881
|
+
}
|
|
3882
|
+
if (camera.azimuth !== null && camera.azimuth !== 0 && rotationDeg !== 0) {
|
|
3883
|
+
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`));
|
|
3884
|
+
}
|
|
3885
|
+
const hasAnchor = focusObjectId !== null && objectMap.has(focusObjectId) || selectedObjectId !== null && objectMap.has(selectedObjectId) || !!filter;
|
|
3886
|
+
if (!hasAnchor) {
|
|
3887
|
+
diagnostics.push(info("validate.viewpoint.camera.anchorMissing", `Viewpoint "${viewpointId}" stores camera settings without a focus object, selection, or filter anchor.`, void 0, prefix));
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
function resolveEffectiveEpoch(system, object, event, pose) {
|
|
3891
|
+
return normalizeOptionalContextString(pose?.epoch) ?? normalizeOptionalContextString(event?.epoch) ?? normalizeOptionalContextString(object.epoch) ?? normalizeOptionalContextString(system?.epoch) ?? null;
|
|
3892
|
+
}
|
|
3893
|
+
function resolveEffectiveReferencePlane(system, object, event, pose) {
|
|
3894
|
+
return normalizeOptionalContextString(pose?.referencePlane) ?? normalizeOptionalContextString(event?.referencePlane) ?? normalizeOptionalContextString(object.referencePlane) ?? normalizeOptionalContextString(system?.referencePlane) ?? null;
|
|
3895
|
+
}
|
|
3896
|
+
function normalizeOptionalContextString(value) {
|
|
3897
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
3898
|
+
}
|
|
3313
3899
|
function toleranceForField(object, field) {
|
|
3314
3900
|
const tolerance = object.tolerances?.find((entry) => entry.field === field)?.value;
|
|
3315
3901
|
if (typeof tolerance === "number") {
|
|
@@ -3405,6 +3991,23 @@ var WorldOrbit = (() => {
|
|
|
3405
3991
|
});
|
|
3406
3992
|
}
|
|
3407
3993
|
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
3994
|
+
var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
3995
|
+
"orbit",
|
|
3996
|
+
"distance",
|
|
3997
|
+
"semiMajor",
|
|
3998
|
+
"eccentricity",
|
|
3999
|
+
"period",
|
|
4000
|
+
"angle",
|
|
4001
|
+
"inclination",
|
|
4002
|
+
"phase",
|
|
4003
|
+
"at",
|
|
4004
|
+
"surface",
|
|
4005
|
+
"free",
|
|
4006
|
+
"inner",
|
|
4007
|
+
"outer",
|
|
4008
|
+
"epoch",
|
|
4009
|
+
"referencePlane"
|
|
4010
|
+
]);
|
|
3408
4011
|
function parseWorldOrbitAtlas(source) {
|
|
3409
4012
|
return parseAtlasSource(source);
|
|
3410
4013
|
}
|
|
@@ -3419,12 +4022,15 @@ var WorldOrbit = (() => {
|
|
|
3419
4022
|
const objectNodes = [];
|
|
3420
4023
|
const groups = [];
|
|
3421
4024
|
const relations = [];
|
|
4025
|
+
const events = [];
|
|
4026
|
+
const eventPoseNodes = /* @__PURE__ */ new Map();
|
|
3422
4027
|
let sawDefaults = false;
|
|
3423
4028
|
let sawAtlas = false;
|
|
3424
4029
|
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3425
4030
|
const annotationIds = /* @__PURE__ */ new Set();
|
|
3426
4031
|
const groupIds = /* @__PURE__ */ new Set();
|
|
3427
4032
|
const relationIds = /* @__PURE__ */ new Set();
|
|
4033
|
+
const eventIds = /* @__PURE__ */ new Set();
|
|
3428
4034
|
for (let index = 0; index < lines.length; index++) {
|
|
3429
4035
|
const rawLine = lines[index];
|
|
3430
4036
|
const lineNumber = index + 1;
|
|
@@ -3442,7 +4048,7 @@ var WorldOrbit = (() => {
|
|
|
3442
4048
|
if (!sawSchemaHeader) {
|
|
3443
4049
|
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
3444
4050
|
sawSchemaHeader = true;
|
|
3445
|
-
if (prepared.comments.length > 0 && sourceSchemaVersion
|
|
4051
|
+
if (prepared.comments.length > 0 && isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
3446
4052
|
diagnostics.push({
|
|
3447
4053
|
code: "parse.schema21.commentCompatibility",
|
|
3448
4054
|
severity: "warning",
|
|
@@ -3455,7 +4061,7 @@ var WorldOrbit = (() => {
|
|
|
3455
4061
|
continue;
|
|
3456
4062
|
}
|
|
3457
4063
|
if (indent === 0) {
|
|
3458
|
-
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
4064
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
3459
4065
|
if (section.kind === "system") {
|
|
3460
4066
|
system = section.system;
|
|
3461
4067
|
} else if (section.kind === "defaults") {
|
|
@@ -3474,6 +4080,7 @@ var WorldOrbit = (() => {
|
|
|
3474
4080
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3475
4081
|
}
|
|
3476
4082
|
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
4083
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
3477
4084
|
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3478
4085
|
const baseDocument = {
|
|
3479
4086
|
format: "worldorbit",
|
|
@@ -3481,6 +4088,7 @@ var WorldOrbit = (() => {
|
|
|
3481
4088
|
system,
|
|
3482
4089
|
groups,
|
|
3483
4090
|
relations,
|
|
4091
|
+
events: normalizedEvents,
|
|
3484
4092
|
objects,
|
|
3485
4093
|
diagnostics
|
|
3486
4094
|
};
|
|
@@ -3510,13 +4118,13 @@ var WorldOrbit = (() => {
|
|
|
3510
4118
|
return document2;
|
|
3511
4119
|
}
|
|
3512
4120
|
function assertDraftSchemaHeader(tokens, line) {
|
|
3513
|
-
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1"].includes(tokens[1].value.toLowerCase())) {
|
|
3514
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
4121
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1", "2.5"].includes(tokens[1].value.toLowerCase())) {
|
|
4122
|
+
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);
|
|
3515
4123
|
}
|
|
3516
4124
|
const version = tokens[1].value.toLowerCase();
|
|
3517
|
-
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
4125
|
+
return version === "2.5" ? "2.5" : version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3518
4126
|
}
|
|
3519
|
-
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
4127
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3520
4128
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
3521
4129
|
switch (keyword) {
|
|
3522
4130
|
case "system":
|
|
@@ -3534,6 +4142,8 @@ var WorldOrbit = (() => {
|
|
|
3534
4142
|
return {
|
|
3535
4143
|
kind: "defaults",
|
|
3536
4144
|
system,
|
|
4145
|
+
sourceSchemaVersion,
|
|
4146
|
+
diagnostics,
|
|
3537
4147
|
seenFields: /* @__PURE__ */ new Set()
|
|
3538
4148
|
};
|
|
3539
4149
|
case "atlas":
|
|
@@ -3553,7 +4163,7 @@ var WorldOrbit = (() => {
|
|
|
3553
4163
|
if (!system) {
|
|
3554
4164
|
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
3555
4165
|
}
|
|
3556
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
4166
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
3557
4167
|
case "annotation":
|
|
3558
4168
|
if (!system) {
|
|
3559
4169
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -3565,6 +4175,9 @@ var WorldOrbit = (() => {
|
|
|
3565
4175
|
case "relation":
|
|
3566
4176
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
3567
4177
|
return startRelationSection(tokens, line, relations, relationIds);
|
|
4178
|
+
case "event":
|
|
4179
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
4180
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
3568
4181
|
case "object":
|
|
3569
4182
|
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3570
4183
|
default:
|
|
@@ -3601,7 +4214,7 @@ var WorldOrbit = (() => {
|
|
|
3601
4214
|
seenFields: /* @__PURE__ */ new Set()
|
|
3602
4215
|
};
|
|
3603
4216
|
}
|
|
3604
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
4217
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
3605
4218
|
if (tokens.length !== 2) {
|
|
3606
4219
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
3607
4220
|
}
|
|
@@ -3618,10 +4231,12 @@ var WorldOrbit = (() => {
|
|
|
3618
4231
|
summary: "",
|
|
3619
4232
|
focusObjectId: null,
|
|
3620
4233
|
selectedObjectId: null,
|
|
4234
|
+
events: [],
|
|
3621
4235
|
projection: system.defaults.view,
|
|
3622
4236
|
preset: system.defaults.preset,
|
|
3623
4237
|
zoom: null,
|
|
3624
4238
|
rotationDeg: 0,
|
|
4239
|
+
camera: null,
|
|
3625
4240
|
layers: {},
|
|
3626
4241
|
filter: null
|
|
3627
4242
|
};
|
|
@@ -3630,10 +4245,15 @@ var WorldOrbit = (() => {
|
|
|
3630
4245
|
return {
|
|
3631
4246
|
kind: "viewpoint",
|
|
3632
4247
|
viewpoint,
|
|
4248
|
+
sourceSchemaVersion,
|
|
4249
|
+
diagnostics,
|
|
3633
4250
|
seenFields: /* @__PURE__ */ new Set(),
|
|
3634
4251
|
inFilter: false,
|
|
3635
4252
|
filterIndent: null,
|
|
3636
|
-
seenFilterFields: /* @__PURE__ */ new Set()
|
|
4253
|
+
seenFilterFields: /* @__PURE__ */ new Set(),
|
|
4254
|
+
inCamera: false,
|
|
4255
|
+
cameraIndent: null,
|
|
4256
|
+
seenCameraFields: /* @__PURE__ */ new Set()
|
|
3637
4257
|
};
|
|
3638
4258
|
}
|
|
3639
4259
|
function startAnnotationSection(tokens, line, system, annotationIds) {
|
|
@@ -3720,6 +4340,51 @@ var WorldOrbit = (() => {
|
|
|
3720
4340
|
seenFields: /* @__PURE__ */ new Set()
|
|
3721
4341
|
};
|
|
3722
4342
|
}
|
|
4343
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
4344
|
+
if (tokens.length !== 2) {
|
|
4345
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
4346
|
+
}
|
|
4347
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
4348
|
+
if (!id) {
|
|
4349
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
4350
|
+
}
|
|
4351
|
+
if (eventIds.has(id)) {
|
|
4352
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
4353
|
+
}
|
|
4354
|
+
const event = {
|
|
4355
|
+
id,
|
|
4356
|
+
kind: "",
|
|
4357
|
+
label: humanizeIdentifier2(id),
|
|
4358
|
+
summary: null,
|
|
4359
|
+
targetObjectId: null,
|
|
4360
|
+
participantObjectIds: [],
|
|
4361
|
+
timing: null,
|
|
4362
|
+
visibility: null,
|
|
4363
|
+
epoch: null,
|
|
4364
|
+
referencePlane: null,
|
|
4365
|
+
tags: [],
|
|
4366
|
+
color: null,
|
|
4367
|
+
hidden: false,
|
|
4368
|
+
positions: []
|
|
4369
|
+
};
|
|
4370
|
+
const rawPoses = [];
|
|
4371
|
+
events.push(event);
|
|
4372
|
+
eventPoseNodes.set(id, rawPoses);
|
|
4373
|
+
eventIds.add(id);
|
|
4374
|
+
return {
|
|
4375
|
+
kind: "event",
|
|
4376
|
+
event,
|
|
4377
|
+
sourceSchemaVersion,
|
|
4378
|
+
diagnostics,
|
|
4379
|
+
seenFields: /* @__PURE__ */ new Set(),
|
|
4380
|
+
rawPoses,
|
|
4381
|
+
inPositions: false,
|
|
4382
|
+
positionsIndent: null,
|
|
4383
|
+
activePose: null,
|
|
4384
|
+
poseIndent: null,
|
|
4385
|
+
activePoseSeenFields: /* @__PURE__ */ new Set()
|
|
4386
|
+
};
|
|
4387
|
+
}
|
|
3723
4388
|
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
3724
4389
|
if (tokens.length < 3) {
|
|
3725
4390
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
@@ -3776,6 +4441,9 @@ var WorldOrbit = (() => {
|
|
|
3776
4441
|
case "relation":
|
|
3777
4442
|
applyRelationField(section, tokens, line);
|
|
3778
4443
|
return;
|
|
4444
|
+
case "event":
|
|
4445
|
+
applyEventField(section, indent, tokens, line);
|
|
4446
|
+
return;
|
|
3779
4447
|
case "object":
|
|
3780
4448
|
applyObjectField(section, indent, tokens, line);
|
|
3781
4449
|
return;
|
|
@@ -3818,6 +4486,12 @@ var WorldOrbit = (() => {
|
|
|
3818
4486
|
const value = joinFieldValue(tokens, line);
|
|
3819
4487
|
switch (key) {
|
|
3820
4488
|
case "view":
|
|
4489
|
+
if (isSchema25Projection(value)) {
|
|
4490
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "defaults.view", {
|
|
4491
|
+
line,
|
|
4492
|
+
column: tokens[0].column
|
|
4493
|
+
});
|
|
4494
|
+
}
|
|
3821
4495
|
section.system.defaults.view = parseProjectionValue(value, line, tokens[0].column);
|
|
3822
4496
|
return;
|
|
3823
4497
|
case "scale":
|
|
@@ -3857,14 +4531,36 @@ var WorldOrbit = (() => {
|
|
|
3857
4531
|
throw new WorldOrbitError(`Unknown atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3858
4532
|
}
|
|
3859
4533
|
function applyViewpointField2(section, indent, tokens, line) {
|
|
4534
|
+
if (section.inCamera && indent <= (section.cameraIndent ?? 0)) {
|
|
4535
|
+
section.inCamera = false;
|
|
4536
|
+
section.cameraIndent = null;
|
|
4537
|
+
}
|
|
3860
4538
|
if (section.inFilter && indent <= (section.filterIndent ?? 0)) {
|
|
3861
4539
|
section.inFilter = false;
|
|
3862
4540
|
section.filterIndent = null;
|
|
3863
4541
|
}
|
|
4542
|
+
if (section.inCamera) {
|
|
4543
|
+
applyViewpointCameraField(section, tokens, line);
|
|
4544
|
+
return;
|
|
4545
|
+
}
|
|
3864
4546
|
if (section.inFilter) {
|
|
3865
4547
|
applyViewpointFilterField(section, tokens, line);
|
|
3866
4548
|
return;
|
|
3867
4549
|
}
|
|
4550
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "camera") {
|
|
4551
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.camera", {
|
|
4552
|
+
line,
|
|
4553
|
+
column: tokens[0].column
|
|
4554
|
+
});
|
|
4555
|
+
if (section.seenFields.has("camera")) {
|
|
4556
|
+
throw new WorldOrbitError('Duplicate viewpoint field "camera"', line, tokens[0].column);
|
|
4557
|
+
}
|
|
4558
|
+
section.seenFields.add("camera");
|
|
4559
|
+
section.inCamera = true;
|
|
4560
|
+
section.cameraIndent = indent;
|
|
4561
|
+
section.viewpoint.camera = section.viewpoint.camera ?? createEmptyViewCamera2();
|
|
4562
|
+
return;
|
|
4563
|
+
}
|
|
3868
4564
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "filter") {
|
|
3869
4565
|
if (section.seenFields.has("filter")) {
|
|
3870
4566
|
throw new WorldOrbitError('Duplicate viewpoint field "filter"', line, tokens[0].column);
|
|
@@ -3890,6 +4586,12 @@ var WorldOrbit = (() => {
|
|
|
3890
4586
|
section.viewpoint.selectedObjectId = value;
|
|
3891
4587
|
return;
|
|
3892
4588
|
case "projection":
|
|
4589
|
+
if (isSchema25Projection(value)) {
|
|
4590
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "projection", {
|
|
4591
|
+
line,
|
|
4592
|
+
column: tokens[0].column
|
|
4593
|
+
});
|
|
4594
|
+
}
|
|
3893
4595
|
section.viewpoint.projection = parseProjectionValue(value, line, tokens[0].column);
|
|
3894
4596
|
return;
|
|
3895
4597
|
case "preset":
|
|
@@ -3901,13 +4603,49 @@ var WorldOrbit = (() => {
|
|
|
3901
4603
|
case "rotation":
|
|
3902
4604
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
3903
4605
|
return;
|
|
4606
|
+
case "camera":
|
|
4607
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.camera", {
|
|
4608
|
+
line,
|
|
4609
|
+
column: tokens[0].column
|
|
4610
|
+
});
|
|
4611
|
+
section.viewpoint.camera = parseInlineViewCamera(tokens.slice(1), line, section.viewpoint.camera);
|
|
4612
|
+
return;
|
|
3904
4613
|
case "layers":
|
|
3905
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
4614
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
4615
|
+
return;
|
|
4616
|
+
case "events":
|
|
4617
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
4618
|
+
line,
|
|
4619
|
+
column: tokens[0].column
|
|
4620
|
+
});
|
|
4621
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
3906
4622
|
return;
|
|
3907
4623
|
default:
|
|
3908
4624
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3909
4625
|
}
|
|
3910
4626
|
}
|
|
4627
|
+
function applyViewpointCameraField(section, tokens, line) {
|
|
4628
|
+
const key = requireUniqueField(tokens, section.seenCameraFields, line);
|
|
4629
|
+
const value = joinFieldValue(tokens, line);
|
|
4630
|
+
const camera = section.viewpoint.camera ?? createEmptyViewCamera2();
|
|
4631
|
+
switch (key) {
|
|
4632
|
+
case "azimuth":
|
|
4633
|
+
camera.azimuth = parseFiniteNumber2(value, line, tokens[0].column, "camera.azimuth");
|
|
4634
|
+
break;
|
|
4635
|
+
case "elevation":
|
|
4636
|
+
camera.elevation = parseFiniteNumber2(value, line, tokens[0].column, "camera.elevation");
|
|
4637
|
+
break;
|
|
4638
|
+
case "roll":
|
|
4639
|
+
camera.roll = parseFiniteNumber2(value, line, tokens[0].column, "camera.roll");
|
|
4640
|
+
break;
|
|
4641
|
+
case "distance":
|
|
4642
|
+
camera.distance = parsePositiveNumber2(value, line, tokens[0].column, "camera.distance");
|
|
4643
|
+
break;
|
|
4644
|
+
default:
|
|
4645
|
+
throw new WorldOrbitError(`Unknown viewpoint camera field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4646
|
+
}
|
|
4647
|
+
section.viewpoint.camera = camera;
|
|
4648
|
+
}
|
|
3911
4649
|
function applyViewpointFilterField(section, tokens, line) {
|
|
3912
4650
|
const key = requireUniqueField(tokens, section.seenFilterFields, line);
|
|
3913
4651
|
const filter = section.viewpoint.filter ?? createEmptyViewpointFilter2();
|
|
@@ -4007,6 +4745,126 @@ var WorldOrbit = (() => {
|
|
|
4007
4745
|
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4008
4746
|
}
|
|
4009
4747
|
}
|
|
4748
|
+
function applyEventField(section, indent, tokens, line) {
|
|
4749
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
4750
|
+
section.activePose = null;
|
|
4751
|
+
section.poseIndent = null;
|
|
4752
|
+
section.activePoseSeenFields.clear();
|
|
4753
|
+
}
|
|
4754
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
4755
|
+
section.inPositions = false;
|
|
4756
|
+
section.positionsIndent = null;
|
|
4757
|
+
}
|
|
4758
|
+
if (section.activePose) {
|
|
4759
|
+
if (tokens[0]?.value === "epoch" || tokens[0]?.value === "referencePlane") {
|
|
4760
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, `pose.${tokens[0].value}`, {
|
|
4761
|
+
line,
|
|
4762
|
+
column: tokens[0]?.column ?? 1
|
|
4763
|
+
});
|
|
4764
|
+
}
|
|
4765
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4766
|
+
return;
|
|
4767
|
+
}
|
|
4768
|
+
if (section.inPositions) {
|
|
4769
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
4770
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
4771
|
+
}
|
|
4772
|
+
const objectId = tokens[1].value;
|
|
4773
|
+
if (!objectId.trim()) {
|
|
4774
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
4775
|
+
}
|
|
4776
|
+
const rawPose = {
|
|
4777
|
+
objectId,
|
|
4778
|
+
fields: [],
|
|
4779
|
+
location: { line, column: tokens[0].column }
|
|
4780
|
+
};
|
|
4781
|
+
section.rawPoses.push(rawPose);
|
|
4782
|
+
section.activePose = rawPose;
|
|
4783
|
+
section.poseIndent = indent;
|
|
4784
|
+
section.activePoseSeenFields = /* @__PURE__ */ new Set();
|
|
4785
|
+
return;
|
|
4786
|
+
}
|
|
4787
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
4788
|
+
if (section.seenFields.has("positions")) {
|
|
4789
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
4790
|
+
}
|
|
4791
|
+
section.seenFields.add("positions");
|
|
4792
|
+
section.inPositions = true;
|
|
4793
|
+
section.positionsIndent = indent;
|
|
4794
|
+
return;
|
|
4795
|
+
}
|
|
4796
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4797
|
+
switch (key) {
|
|
4798
|
+
case "kind":
|
|
4799
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
4800
|
+
return;
|
|
4801
|
+
case "label":
|
|
4802
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
4803
|
+
return;
|
|
4804
|
+
case "summary":
|
|
4805
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
4806
|
+
return;
|
|
4807
|
+
case "target":
|
|
4808
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
4809
|
+
return;
|
|
4810
|
+
case "participants":
|
|
4811
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
4812
|
+
return;
|
|
4813
|
+
case "timing":
|
|
4814
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
4815
|
+
return;
|
|
4816
|
+
case "visibility":
|
|
4817
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
4818
|
+
return;
|
|
4819
|
+
case "epoch":
|
|
4820
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "event.epoch", {
|
|
4821
|
+
line,
|
|
4822
|
+
column: tokens[0].column
|
|
4823
|
+
});
|
|
4824
|
+
section.event.epoch = joinFieldValue(tokens, line);
|
|
4825
|
+
return;
|
|
4826
|
+
case "referenceplane":
|
|
4827
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "event.referencePlane", {
|
|
4828
|
+
line,
|
|
4829
|
+
column: tokens[0].column
|
|
4830
|
+
});
|
|
4831
|
+
section.event.referencePlane = joinFieldValue(tokens, line);
|
|
4832
|
+
return;
|
|
4833
|
+
case "tags":
|
|
4834
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4835
|
+
return;
|
|
4836
|
+
case "color":
|
|
4837
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
4838
|
+
return;
|
|
4839
|
+
case "hidden":
|
|
4840
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4841
|
+
line,
|
|
4842
|
+
column: tokens[0].column
|
|
4843
|
+
});
|
|
4844
|
+
return;
|
|
4845
|
+
default:
|
|
4846
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
4850
|
+
if (tokens.length < 2) {
|
|
4851
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
4852
|
+
}
|
|
4853
|
+
const key = tokens[0].value;
|
|
4854
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
4855
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
4856
|
+
}
|
|
4857
|
+
if (seenFields.has(key)) {
|
|
4858
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
4859
|
+
}
|
|
4860
|
+
seenFields.add(key);
|
|
4861
|
+
return {
|
|
4862
|
+
type: "field",
|
|
4863
|
+
key,
|
|
4864
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
4865
|
+
location: { line, column: tokens[0].column }
|
|
4866
|
+
};
|
|
4867
|
+
}
|
|
4010
4868
|
function applyObjectField(section, indent, tokens, line) {
|
|
4011
4869
|
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
4012
4870
|
section.activeBlock = null;
|
|
@@ -4065,7 +4923,7 @@ var WorldOrbit = (() => {
|
|
|
4065
4923
|
function parseObjectTypeTokens(tokens, line) {
|
|
4066
4924
|
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");
|
|
4067
4925
|
}
|
|
4068
|
-
function parseLayerTokens(tokens, line) {
|
|
4926
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
4069
4927
|
const layers = {};
|
|
4070
4928
|
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
4071
4929
|
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
@@ -4075,7 +4933,13 @@ var WorldOrbit = (() => {
|
|
|
4075
4933
|
layers["orbits-front"] = enabled;
|
|
4076
4934
|
continue;
|
|
4077
4935
|
}
|
|
4078
|
-
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4936
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4937
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
4938
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
4939
|
+
line,
|
|
4940
|
+
column: tokens[0]?.column ?? 1
|
|
4941
|
+
});
|
|
4942
|
+
}
|
|
4079
4943
|
layers[raw] = enabled;
|
|
4080
4944
|
}
|
|
4081
4945
|
}
|
|
@@ -4093,11 +4957,15 @@ var WorldOrbit = (() => {
|
|
|
4093
4957
|
}
|
|
4094
4958
|
function parseProjectionValue(value, line, column) {
|
|
4095
4959
|
const normalized = value.toLowerCase();
|
|
4096
|
-
if (normalized !== "topdown" && normalized !== "isometric") {
|
|
4960
|
+
if (normalized !== "topdown" && normalized !== "isometric" && normalized !== "orthographic" && normalized !== "perspective") {
|
|
4097
4961
|
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
4098
4962
|
}
|
|
4099
4963
|
return normalized;
|
|
4100
4964
|
}
|
|
4965
|
+
function isSchema25Projection(value) {
|
|
4966
|
+
const normalized = value.toLowerCase();
|
|
4967
|
+
return normalized === "orthographic" || normalized === "perspective";
|
|
4968
|
+
}
|
|
4101
4969
|
function parsePresetValue(value, line, column) {
|
|
4102
4970
|
const normalized = value.toLowerCase();
|
|
4103
4971
|
if (normalized === "diagram" || normalized === "presentation" || normalized === "atlas-card" || normalized === "markdown") {
|
|
@@ -4127,6 +4995,48 @@ var WorldOrbit = (() => {
|
|
|
4127
4995
|
groupIds: []
|
|
4128
4996
|
};
|
|
4129
4997
|
}
|
|
4998
|
+
function createEmptyViewCamera2() {
|
|
4999
|
+
return {
|
|
5000
|
+
azimuth: null,
|
|
5001
|
+
elevation: null,
|
|
5002
|
+
roll: null,
|
|
5003
|
+
distance: null
|
|
5004
|
+
};
|
|
5005
|
+
}
|
|
5006
|
+
function parseInlineViewCamera(tokens, line, current) {
|
|
5007
|
+
if (tokens.length === 0 || tokens.length % 2 !== 0) {
|
|
5008
|
+
throw new WorldOrbitError('Field "camera" expects "<field> <value>" pairs', line, tokens[0]?.column ?? 1);
|
|
5009
|
+
}
|
|
5010
|
+
const camera = current ? { ...current } : createEmptyViewCamera2();
|
|
5011
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5012
|
+
for (let index = 0; index < tokens.length; index += 2) {
|
|
5013
|
+
const fieldToken = tokens[index];
|
|
5014
|
+
const valueToken = tokens[index + 1];
|
|
5015
|
+
const key = fieldToken.value.toLowerCase();
|
|
5016
|
+
if (seen.has(key)) {
|
|
5017
|
+
throw new WorldOrbitError(`Duplicate viewpoint camera field "${fieldToken.value}"`, line, fieldToken.column);
|
|
5018
|
+
}
|
|
5019
|
+
seen.add(key);
|
|
5020
|
+
const value = valueToken.value;
|
|
5021
|
+
switch (key) {
|
|
5022
|
+
case "azimuth":
|
|
5023
|
+
camera.azimuth = parseFiniteNumber2(value, line, fieldToken.column, "camera.azimuth");
|
|
5024
|
+
break;
|
|
5025
|
+
case "elevation":
|
|
5026
|
+
camera.elevation = parseFiniteNumber2(value, line, fieldToken.column, "camera.elevation");
|
|
5027
|
+
break;
|
|
5028
|
+
case "roll":
|
|
5029
|
+
camera.roll = parseFiniteNumber2(value, line, fieldToken.column, "camera.roll");
|
|
5030
|
+
break;
|
|
5031
|
+
case "distance":
|
|
5032
|
+
camera.distance = parsePositiveNumber2(value, line, fieldToken.column, "camera.distance");
|
|
5033
|
+
break;
|
|
5034
|
+
default:
|
|
5035
|
+
throw new WorldOrbitError(`Unknown viewpoint camera field "${fieldToken.value}"`, line, fieldToken.column);
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
5038
|
+
return camera;
|
|
5039
|
+
}
|
|
4130
5040
|
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
4131
5041
|
const fields = [];
|
|
4132
5042
|
let index = 0;
|
|
@@ -4214,7 +5124,7 @@ var WorldOrbit = (() => {
|
|
|
4214
5124
|
}
|
|
4215
5125
|
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
4216
5126
|
const fieldMap = collectDraftFields(node.fields);
|
|
4217
|
-
const placement =
|
|
5127
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4218
5128
|
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
4219
5129
|
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
4220
5130
|
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
@@ -4259,21 +5169,41 @@ var WorldOrbit = (() => {
|
|
|
4259
5169
|
object.tolerances = tolerances;
|
|
4260
5170
|
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
4261
5171
|
object.typedBlocks = typedBlocks;
|
|
4262
|
-
if (sourceSchemaVersion
|
|
5172
|
+
if (isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
4263
5173
|
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) {
|
|
4264
5174
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
4265
5175
|
}
|
|
4266
5176
|
}
|
|
4267
5177
|
return object;
|
|
4268
5178
|
}
|
|
4269
|
-
function
|
|
5179
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
5180
|
+
return {
|
|
5181
|
+
...event,
|
|
5182
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
5183
|
+
tags: [...new Set(event.tags)],
|
|
5184
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
|
|
5185
|
+
};
|
|
5186
|
+
}
|
|
5187
|
+
function normalizeDraftEventPose(rawPose) {
|
|
5188
|
+
const fieldMap = collectDraftFields(rawPose.fields, "event-pose");
|
|
5189
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
5190
|
+
return {
|
|
5191
|
+
objectId: rawPose.objectId,
|
|
5192
|
+
placement,
|
|
5193
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
5194
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer"),
|
|
5195
|
+
epoch: parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]),
|
|
5196
|
+
referencePlane: parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0])
|
|
5197
|
+
};
|
|
5198
|
+
}
|
|
5199
|
+
function collectDraftFields(fields, _mode = "object") {
|
|
4270
5200
|
const grouped = /* @__PURE__ */ new Map();
|
|
4271
5201
|
for (const field of fields) {
|
|
4272
5202
|
const spec = getDraftObjectFieldSpec(field.key);
|
|
4273
|
-
if (!spec) {
|
|
5203
|
+
if (!spec && !EVENT_POSE_FIELD_KEYS.has(field.key)) {
|
|
4274
5204
|
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4275
5205
|
}
|
|
4276
|
-
if (!spec
|
|
5206
|
+
if (!spec?.allowRepeat && grouped.has(field.key)) {
|
|
4277
5207
|
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
4278
5208
|
}
|
|
4279
5209
|
const existing = grouped.get(field.key) ?? [];
|
|
@@ -4282,7 +5212,7 @@ var WorldOrbit = (() => {
|
|
|
4282
5212
|
}
|
|
4283
5213
|
return grouped;
|
|
4284
5214
|
}
|
|
4285
|
-
function
|
|
5215
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
4286
5216
|
const orbitField = fieldMap.get("orbit")?.[0];
|
|
4287
5217
|
const atField = fieldMap.get("at")?.[0];
|
|
4288
5218
|
const surfaceField = fieldMap.get("surface")?.[0];
|
|
@@ -4450,7 +5380,7 @@ var WorldOrbit = (() => {
|
|
|
4450
5380
|
}
|
|
4451
5381
|
}
|
|
4452
5382
|
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
4453
|
-
if (sourceSchemaVersion
|
|
5383
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
4454
5384
|
return;
|
|
4455
5385
|
}
|
|
4456
5386
|
diagnostics.push({
|
|
@@ -4462,6 +5392,34 @@ var WorldOrbit = (() => {
|
|
|
4462
5392
|
column: location.column
|
|
4463
5393
|
});
|
|
4464
5394
|
}
|
|
5395
|
+
function warnIfSchema25Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
5396
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "2.5")) {
|
|
5397
|
+
return;
|
|
5398
|
+
}
|
|
5399
|
+
diagnostics.push({
|
|
5400
|
+
code: "parse.schema25.featureCompatibility",
|
|
5401
|
+
severity: "warning",
|
|
5402
|
+
source: "parse",
|
|
5403
|
+
message: `Feature "${featureName}" requires schema 2.5; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
5404
|
+
line: location.line,
|
|
5405
|
+
column: location.column
|
|
5406
|
+
});
|
|
5407
|
+
}
|
|
5408
|
+
function isSchemaOlderThan(sourceSchemaVersion, requiredVersion) {
|
|
5409
|
+
return schemaVersionRank(sourceSchemaVersion) < schemaVersionRank(requiredVersion);
|
|
5410
|
+
}
|
|
5411
|
+
function schemaVersionRank(version) {
|
|
5412
|
+
switch (version) {
|
|
5413
|
+
case "2.0-draft":
|
|
5414
|
+
return 0;
|
|
5415
|
+
case "2.0":
|
|
5416
|
+
return 1;
|
|
5417
|
+
case "2.1":
|
|
5418
|
+
return 2;
|
|
5419
|
+
case "2.5":
|
|
5420
|
+
return 3;
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
4465
5423
|
function preprocessAtlasSource(source) {
|
|
4466
5424
|
const chars = [...source];
|
|
4467
5425
|
const comments = [];
|
|
@@ -4549,8 +5507,9 @@ var WorldOrbit = (() => {
|
|
|
4549
5507
|
}
|
|
4550
5508
|
|
|
4551
5509
|
// packages/core/dist/load.js
|
|
4552
|
-
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|
|
5510
|
+
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1|\.5)?$/i;
|
|
4553
5511
|
var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
5512
|
+
var ATLAS_SCHEMA_25_PATTERN = /^schema\s+2\.5$/i;
|
|
4554
5513
|
var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
4555
5514
|
function detectWorldOrbitSchemaVersion(source) {
|
|
4556
5515
|
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
@@ -4564,6 +5523,9 @@ var WorldOrbit = (() => {
|
|
|
4564
5523
|
if (ATLAS_SCHEMA_21_PATTERN.test(trimmed)) {
|
|
4565
5524
|
return "2.1";
|
|
4566
5525
|
}
|
|
5526
|
+
if (ATLAS_SCHEMA_25_PATTERN.test(trimmed)) {
|
|
5527
|
+
return "2.5";
|
|
5528
|
+
}
|
|
4567
5529
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
4568
5530
|
return "2.0";
|
|
4569
5531
|
}
|
|
@@ -4624,7 +5586,7 @@ var WorldOrbit = (() => {
|
|
|
4624
5586
|
}
|
|
4625
5587
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
4626
5588
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
4627
|
-
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1") {
|
|
5589
|
+
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1" || schemaVersion === "2.5") {
|
|
4628
5590
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
4629
5591
|
}
|
|
4630
5592
|
let ast;
|
|
@@ -4893,6 +5855,7 @@ var WorldOrbit = (() => {
|
|
|
4893
5855
|
const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
|
|
4894
5856
|
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("") : "";
|
|
4895
5857
|
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("") : "";
|
|
5858
|
+
const eventMarkup = layers.events ? scene.events.filter((event) => !event.hidden).map((event) => renderSceneEventOverlay(scene, event, visibleObjectIds, theme)).join("") : "";
|
|
4896
5859
|
const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
|
|
4897
5860
|
const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
|
|
4898
5861
|
const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
|
|
@@ -4928,6 +5891,9 @@ var WorldOrbit = (() => {
|
|
|
4928
5891
|
.wo-orbit-front { opacity: 0.9; }
|
|
4929
5892
|
.wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
|
|
4930
5893
|
.wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
|
|
5894
|
+
.wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
|
|
5895
|
+
.wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
|
|
5896
|
+
.wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
4931
5897
|
.wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
|
|
4932
5898
|
.wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
|
|
4933
5899
|
.wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
|
|
@@ -4962,6 +5928,7 @@ var WorldOrbit = (() => {
|
|
|
4962
5928
|
${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
|
|
4963
5929
|
${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
|
|
4964
5930
|
${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
|
|
5931
|
+
${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
|
|
4965
5932
|
${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
|
|
4966
5933
|
${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
|
|
4967
5934
|
${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
|
|
@@ -4969,6 +5936,20 @@ var WorldOrbit = (() => {
|
|
|
4969
5936
|
</g>
|
|
4970
5937
|
</g>
|
|
4971
5938
|
</svg>`;
|
|
5939
|
+
}
|
|
5940
|
+
function renderSceneEventOverlay(scene, event, visibleObjectIds, theme) {
|
|
5941
|
+
const participants = event.objectIds.filter((objectId) => visibleObjectIds.has(objectId)).map((objectId) => scene.objects.find((object) => object.objectId === objectId && !object.hidden)).filter(Boolean);
|
|
5942
|
+
if (participants.length === 0) {
|
|
5943
|
+
return "";
|
|
5944
|
+
}
|
|
5945
|
+
const stroke = event.event.color || theme.accent;
|
|
5946
|
+
const label = event.event.label || event.event.id;
|
|
5947
|
+
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("");
|
|
5948
|
+
return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
|
|
5949
|
+
${lineMarkup}
|
|
5950
|
+
<circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
|
|
5951
|
+
<text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
|
|
5952
|
+
</g>`;
|
|
4972
5953
|
}
|
|
4973
5954
|
function renderDocumentToSvg(document2, options = {}) {
|
|
4974
5955
|
return renderSceneToSvg(renderDocumentToScene(document2, options), options);
|
|
@@ -5568,6 +6549,13 @@ var WorldOrbit = (() => {
|
|
|
5568
6549
|
value: `${details.object.resonance.targetObjectId} ${details.object.resonance.ratio}`
|
|
5569
6550
|
});
|
|
5570
6551
|
}
|
|
6552
|
+
if (details.relatedEvents.length > 0) {
|
|
6553
|
+
fields.set("events", {
|
|
6554
|
+
key: "events",
|
|
6555
|
+
label: "Events",
|
|
6556
|
+
value: details.relatedEvents.map((event) => event.event.label || event.event.id).join(", ")
|
|
6557
|
+
});
|
|
6558
|
+
}
|
|
5571
6559
|
if (placement?.mode === "at") {
|
|
5572
6560
|
fields.set("placement", {
|
|
5573
6561
|
key: "placement",
|
|
@@ -5672,6 +6660,7 @@ var WorldOrbit = (() => {
|
|
|
5672
6660
|
padding: options.padding,
|
|
5673
6661
|
preset: options.preset,
|
|
5674
6662
|
projection: options.projection,
|
|
6663
|
+
camera: options.camera ? { ...options.camera } : null,
|
|
5675
6664
|
scaleModel: options.scaleModel ? { ...options.scaleModel } : void 0,
|
|
5676
6665
|
theme: options.theme,
|
|
5677
6666
|
layers: options.layers,
|
|
@@ -5960,6 +6949,11 @@ var WorldOrbit = (() => {
|
|
|
5960
6949
|
if (currentInput.kind !== "scene" && viewpoint.projection !== scene.projection) {
|
|
5961
6950
|
nextRenderOptions.projection = viewpoint.projection;
|
|
5962
6951
|
}
|
|
6952
|
+
if (viewpoint.camera) {
|
|
6953
|
+
nextRenderOptions.camera = { ...viewpoint.camera };
|
|
6954
|
+
} else if (renderOptions.camera) {
|
|
6955
|
+
nextRenderOptions.camera = null;
|
|
6956
|
+
}
|
|
5963
6957
|
if (viewpointLayers) {
|
|
5964
6958
|
nextRenderOptions.layers = viewpointLayers;
|
|
5965
6959
|
}
|
|
@@ -5982,6 +6976,12 @@ var WorldOrbit = (() => {
|
|
|
5982
6976
|
emitAtlasStateChange();
|
|
5983
6977
|
return true;
|
|
5984
6978
|
},
|
|
6979
|
+
getActiveEventId() {
|
|
6980
|
+
return renderOptions.activeEventId ?? null;
|
|
6981
|
+
},
|
|
6982
|
+
setActiveEvent(id) {
|
|
6983
|
+
api.setRenderOptions({ activeEventId: id });
|
|
6984
|
+
},
|
|
5985
6985
|
search(query, limit = 12) {
|
|
5986
6986
|
return searchSceneObjects(scene, query, limit);
|
|
5987
6987
|
},
|
|
@@ -6246,6 +7246,7 @@ var WorldOrbit = (() => {
|
|
|
6246
7246
|
orbit: scene.orbitVisuals.find((orbit) => orbit.objectId === renderObject.objectId && !orbit.hidden) ?? null,
|
|
6247
7247
|
relatedOrbits: scene.orbitVisuals.filter((orbit) => !orbit.hidden && (orbit.objectId === renderObject.objectId || renderObject.ancestorIds.includes(orbit.objectId) || renderObject.childIds.includes(orbit.objectId))),
|
|
6248
7248
|
relations: scene.relations.filter((relation) => !relation.hidden && (relation.fromObjectId === renderObject.objectId || relation.toObjectId === renderObject.objectId)),
|
|
7249
|
+
relatedEvents: scene.events.filter((event) => !event.hidden && (event.targetObjectId === renderObject.objectId || event.objectIds.includes(renderObject.objectId))),
|
|
6249
7250
|
parent: getObjectById(renderObject.parentId),
|
|
6250
7251
|
children: renderObject.childIds.map((childId) => getObjectById(childId)).filter(Boolean),
|
|
6251
7252
|
ancestors: renderObject.ancestorIds.map((ancestorId) => getObjectById(ancestorId)).filter(Boolean),
|
|
@@ -6559,16 +7560,19 @@ var WorldOrbit = (() => {
|
|
|
6559
7560
|
function cloneRenderOptions(renderOptions) {
|
|
6560
7561
|
return {
|
|
6561
7562
|
...renderOptions,
|
|
7563
|
+
camera: renderOptions.camera ? { ...renderOptions.camera } : null,
|
|
6562
7564
|
filter: renderOptions.filter ? { ...renderOptions.filter } : void 0,
|
|
6563
7565
|
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0,
|
|
6564
7566
|
layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
|
|
6565
|
-
theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme
|
|
7567
|
+
theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme,
|
|
7568
|
+
activeEventId: renderOptions.activeEventId ?? null
|
|
6566
7569
|
};
|
|
6567
7570
|
}
|
|
6568
7571
|
function mergeRenderOptions(current, next) {
|
|
6569
7572
|
return {
|
|
6570
7573
|
...current,
|
|
6571
7574
|
...next,
|
|
7575
|
+
camera: next.camera !== void 0 ? next.camera ? { ...next.camera } : null : current.camera ? { ...current.camera } : null,
|
|
6572
7576
|
filter: next.filter !== void 0 ? normalizeViewerFilter(next.filter) : current.filter ? { ...current.filter } : void 0,
|
|
6573
7577
|
scaleModel: next.scaleModel ? {
|
|
6574
7578
|
...current.scaleModel ?? {},
|
|
@@ -6582,7 +7586,7 @@ var WorldOrbit = (() => {
|
|
|
6582
7586
|
};
|
|
6583
7587
|
}
|
|
6584
7588
|
function hasSceneAffectingRenderOptions(options) {
|
|
6585
|
-
return options.width !== void 0 || options.height !== void 0 || options.padding !== void 0 || options.preset !== void 0 || options.projection !== void 0 || options.scaleModel !== void 0;
|
|
7589
|
+
return options.width !== void 0 || options.height !== void 0 || options.padding !== void 0 || options.preset !== void 0 || options.projection !== void 0 || options.camera !== void 0 || options.scaleModel !== void 0 || options.activeEventId !== void 0;
|
|
6586
7590
|
}
|
|
6587
7591
|
function resolveSourceRenderOptions2(loaded, renderOptions) {
|
|
6588
7592
|
const atlasDocument = loaded.atlasDocument ?? loaded.draftDocument;
|
|
@@ -7179,6 +8183,8 @@ var WorldOrbit = (() => {
|
|
|
7179
8183
|
}
|
|
7180
8184
|
function buildInspectorSnapshot() {
|
|
7181
8185
|
const activeViewer = requireViewer();
|
|
8186
|
+
const scene = activeViewer.getScene();
|
|
8187
|
+
const camera = scene.camera;
|
|
7182
8188
|
return {
|
|
7183
8189
|
selection: activeViewer.getSelectionDetails(),
|
|
7184
8190
|
activeViewpoint: activeViewer.getActiveViewpoint(),
|
|
@@ -7186,13 +8192,21 @@ var WorldOrbit = (() => {
|
|
|
7186
8192
|
atlasState: activeViewer.getAtlasState(),
|
|
7187
8193
|
visibleObjectIds: activeViewer.getVisibleObjects().map((object) => object.objectId),
|
|
7188
8194
|
scene: {
|
|
7189
|
-
title:
|
|
7190
|
-
projection:
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
8195
|
+
title: scene.title,
|
|
8196
|
+
projection: scene.projection,
|
|
8197
|
+
renderProjection: scene.renderProjection,
|
|
8198
|
+
camera: camera ? {
|
|
8199
|
+
azimuth: camera.azimuth,
|
|
8200
|
+
elevation: camera.elevation,
|
|
8201
|
+
roll: camera.roll,
|
|
8202
|
+
distance: camera.distance
|
|
8203
|
+
} : null,
|
|
8204
|
+
renderPreset: scene.renderPreset,
|
|
8205
|
+
groupCount: scene.groups.length,
|
|
8206
|
+
semanticGroupCount: scene.semanticGroups.length,
|
|
8207
|
+
relationCount: scene.relations.length,
|
|
8208
|
+
eventCount: scene.events.length,
|
|
8209
|
+
viewpointCount: scene.viewpoints.length
|
|
7196
8210
|
}
|
|
7197
8211
|
};
|
|
7198
8212
|
}
|