worldorbit 2.5.16 → 2.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/browser/core/dist/index.js +750 -73
- package/dist/browser/editor/dist/index.js +1303 -135
- package/dist/browser/markdown/dist/index.js +631 -72
- package/dist/browser/viewer/dist/index.js +658 -77
- package/dist/unpkg/core/dist/index.js +750 -73
- package/dist/unpkg/editor/dist/index.js +1303 -135
- package/dist/unpkg/markdown/dist/index.js +631 -72
- package/dist/unpkg/viewer/dist/index.js +658 -77
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +284 -202
- package/dist/unpkg/worldorbit-markdown.min.js +66 -58
- package/dist/unpkg/worldorbit-viewer.min.js +76 -68
- package/dist/unpkg/worldorbit.js +797 -78
- package/dist/unpkg/worldorbit.min.js +80 -72
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.js +74 -0
- package/packages/core/dist/atlas-validate.js +122 -8
- package/packages/core/dist/draft-parse.js +212 -8
- package/packages/core/dist/draft.d.ts +5 -2
- package/packages/core/dist/draft.js +59 -3
- package/packages/core/dist/format.js +63 -1
- package/packages/core/dist/normalize.js +1 -0
- package/packages/core/dist/scene.js +248 -46
- package/packages/core/dist/types.d.ts +41 -2
- package/packages/editor/dist/editor.js +597 -61
- package/packages/editor/dist/types.d.ts +3 -1
- package/packages/viewer/dist/atlas-state.js +6 -0
- package/packages/viewer/dist/atlas-viewer.js +1 -0
- package/packages/viewer/dist/render.js +31 -2
- package/packages/viewer/dist/theme.js +1 -0
- package/packages/viewer/dist/tooltip.js +9 -0
- package/packages/viewer/dist/types.d.ts +8 -1
- package/packages/viewer/dist/viewer.js +12 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
background: true,
|
|
6
6
|
guides: true,
|
|
7
7
|
relations: true,
|
|
8
|
+
events: true,
|
|
8
9
|
orbits: true,
|
|
9
10
|
objects: true,
|
|
10
11
|
labels: true,
|
|
@@ -156,12 +157,14 @@
|
|
|
156
157
|
return {
|
|
157
158
|
version: "2.0",
|
|
158
159
|
viewpointId,
|
|
160
|
+
activeEventId: renderOptions.activeEventId ?? null,
|
|
159
161
|
viewerState: { ...viewerState },
|
|
160
162
|
renderOptions: {
|
|
161
163
|
preset: renderOptions.preset,
|
|
162
164
|
projection: renderOptions.projection,
|
|
163
165
|
layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
|
|
164
|
-
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0
|
|
166
|
+
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0,
|
|
167
|
+
activeEventId: renderOptions.activeEventId ?? null
|
|
165
168
|
},
|
|
166
169
|
filter: normalizeViewerFilter(filter)
|
|
167
170
|
};
|
|
@@ -174,6 +177,7 @@
|
|
|
174
177
|
return {
|
|
175
178
|
version: "2.0",
|
|
176
179
|
viewpointId: raw.viewpointId ?? null,
|
|
180
|
+
activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null,
|
|
177
181
|
viewerState: {
|
|
178
182
|
scale: raw.viewerState?.scale ?? 1,
|
|
179
183
|
rotationDeg: raw.viewerState?.rotationDeg ?? 0,
|
|
@@ -185,7 +189,8 @@
|
|
|
185
189
|
preset: raw.renderOptions?.preset,
|
|
186
190
|
projection: raw.renderOptions?.projection,
|
|
187
191
|
layers: raw.renderOptions?.layers ? { ...raw.renderOptions.layers } : void 0,
|
|
188
|
-
scaleModel: raw.renderOptions?.scaleModel ? { ...raw.renderOptions.scaleModel } : void 0
|
|
192
|
+
scaleModel: raw.renderOptions?.scaleModel ? { ...raw.renderOptions.scaleModel } : void 0,
|
|
193
|
+
activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null
|
|
189
194
|
},
|
|
190
195
|
filter: normalizeViewerFilter(raw.filter ?? null)
|
|
191
196
|
};
|
|
@@ -201,7 +206,8 @@
|
|
|
201
206
|
renderOptions: {
|
|
202
207
|
...atlasState.renderOptions,
|
|
203
208
|
layers: atlasState.renderOptions.layers ? { ...atlasState.renderOptions.layers } : void 0,
|
|
204
|
-
scaleModel: atlasState.renderOptions.scaleModel ? { ...atlasState.renderOptions.scaleModel } : void 0
|
|
209
|
+
scaleModel: atlasState.renderOptions.scaleModel ? { ...atlasState.renderOptions.scaleModel } : void 0,
|
|
210
|
+
activeEventId: atlasState.renderOptions.activeEventId ?? null
|
|
205
211
|
},
|
|
206
212
|
filter: atlasState.filter ? { ...atlasState.filter } : null
|
|
207
213
|
}
|
|
@@ -219,6 +225,7 @@
|
|
|
219
225
|
background: viewpoint.layers.background,
|
|
220
226
|
guides: viewpoint.layers.guides,
|
|
221
227
|
relations: viewpoint.layers.relations,
|
|
228
|
+
events: viewpoint.layers.events,
|
|
222
229
|
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,
|
|
223
230
|
objects: viewpoint.layers.objects,
|
|
224
231
|
labels: viewpoint.layers.labels,
|
|
@@ -866,6 +873,7 @@
|
|
|
866
873
|
system,
|
|
867
874
|
groups: [],
|
|
868
875
|
relations: [],
|
|
876
|
+
events: [],
|
|
869
877
|
objects
|
|
870
878
|
};
|
|
871
879
|
}
|
|
@@ -1249,8 +1257,10 @@
|
|
|
1249
1257
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
1250
1258
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
1251
1259
|
const systemId = document2.system?.id ?? null;
|
|
1252
|
-
const
|
|
1253
|
-
const
|
|
1260
|
+
const activeEventId = options.activeEventId ?? null;
|
|
1261
|
+
const effectiveObjects = createEffectiveObjects(document2.objects, document2.events ?? [], activeEventId);
|
|
1262
|
+
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
1263
|
+
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
1254
1264
|
const positions = /* @__PURE__ */ new Map();
|
|
1255
1265
|
const orbitDrafts = [];
|
|
1256
1266
|
const leaderDrafts = [];
|
|
@@ -1259,7 +1269,7 @@
|
|
|
1259
1269
|
const atObjects = [];
|
|
1260
1270
|
const surfaceChildren = /* @__PURE__ */ new Map();
|
|
1261
1271
|
const orbitChildren = /* @__PURE__ */ new Map();
|
|
1262
|
-
for (const object of
|
|
1272
|
+
for (const object of effectiveObjects) {
|
|
1263
1273
|
const placement = object.placement;
|
|
1264
1274
|
if (!placement) {
|
|
1265
1275
|
rootObjects.push(object);
|
|
@@ -1354,13 +1364,14 @@
|
|
|
1354
1364
|
const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
|
|
1355
1365
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1356
1366
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1357
|
-
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1367
|
+
const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
|
|
1358
1368
|
const relations = createSceneRelations(document2, objects);
|
|
1359
|
-
const
|
|
1360
|
-
const
|
|
1369
|
+
const events = createSceneEvents(document2.events ?? [], objects, activeEventId);
|
|
1370
|
+
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1371
|
+
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1361
1372
|
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1362
1373
|
const viewpoints = createSceneViewpoints(document2, projection, frame.preset, relationships, objectMap);
|
|
1363
|
-
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1374
|
+
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1364
1375
|
return {
|
|
1365
1376
|
width,
|
|
1366
1377
|
height,
|
|
@@ -1386,6 +1397,8 @@
|
|
|
1386
1397
|
groups,
|
|
1387
1398
|
semanticGroups,
|
|
1388
1399
|
viewpoints,
|
|
1400
|
+
events,
|
|
1401
|
+
activeEventId,
|
|
1389
1402
|
objects,
|
|
1390
1403
|
orbitVisuals,
|
|
1391
1404
|
relations,
|
|
@@ -1404,6 +1417,35 @@
|
|
|
1404
1417
|
y: center.y + dx * sin + dy * cos
|
|
1405
1418
|
};
|
|
1406
1419
|
}
|
|
1420
|
+
function createEffectiveObjects(objects, events, activeEventId) {
|
|
1421
|
+
const cloned = objects.map((object) => structuredClone(object));
|
|
1422
|
+
if (!activeEventId) {
|
|
1423
|
+
return cloned;
|
|
1424
|
+
}
|
|
1425
|
+
const activeEvent = events.find((event) => event.id === activeEventId);
|
|
1426
|
+
if (!activeEvent) {
|
|
1427
|
+
return cloned;
|
|
1428
|
+
}
|
|
1429
|
+
const objectMap = new Map(cloned.map((object) => [object.id, object]));
|
|
1430
|
+
for (const pose of activeEvent.positions) {
|
|
1431
|
+
const object = objectMap.get(pose.objectId);
|
|
1432
|
+
if (!object) {
|
|
1433
|
+
continue;
|
|
1434
|
+
}
|
|
1435
|
+
object.placement = pose.placement ? structuredClone(pose.placement) : null;
|
|
1436
|
+
if (pose.inner) {
|
|
1437
|
+
object.properties.inner = { ...pose.inner };
|
|
1438
|
+
} else {
|
|
1439
|
+
delete object.properties.inner;
|
|
1440
|
+
}
|
|
1441
|
+
if (pose.outer) {
|
|
1442
|
+
object.properties.outer = { ...pose.outer };
|
|
1443
|
+
} else {
|
|
1444
|
+
delete object.properties.outer;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
return cloned;
|
|
1448
|
+
}
|
|
1407
1449
|
function resolveLayoutPreset(document2) {
|
|
1408
1450
|
const rawScale = String(document2.system?.properties.scale ?? "balanced").toLowerCase();
|
|
1409
1451
|
switch (rawScale) {
|
|
@@ -1559,24 +1601,14 @@
|
|
|
1559
1601
|
hidden: draft.object.properties.hidden === true
|
|
1560
1602
|
};
|
|
1561
1603
|
}
|
|
1562
|
-
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1604
|
+
function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1563
1605
|
const labels = [];
|
|
1564
1606
|
const occupied = [];
|
|
1565
|
-
const
|
|
1607
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1608
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
|
|
1566
1609
|
for (const object of visibleObjects) {
|
|
1567
|
-
const
|
|
1568
|
-
|
|
1569
|
-
let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
|
|
1570
|
-
let secondaryY = labelY + direction * (16 * labelMultiplier);
|
|
1571
|
-
let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1572
|
-
let attempts = 0;
|
|
1573
|
-
while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
|
|
1574
|
-
labelY += direction * 14 * labelMultiplier;
|
|
1575
|
-
secondaryY += direction * 14 * labelMultiplier;
|
|
1576
|
-
bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1577
|
-
attempts += 1;
|
|
1578
|
-
}
|
|
1579
|
-
occupied.push(bounds);
|
|
1610
|
+
const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
|
|
1611
|
+
occupied.push(createLabelRect(object, placement, labelMultiplier));
|
|
1580
1612
|
labels.push({
|
|
1581
1613
|
renderId: `${object.renderId}-label`,
|
|
1582
1614
|
objectId: object.objectId,
|
|
@@ -1585,17 +1617,128 @@
|
|
|
1585
1617
|
semanticGroupIds: [...object.semanticGroupIds],
|
|
1586
1618
|
label: object.label,
|
|
1587
1619
|
secondaryLabel: object.secondaryLabel,
|
|
1588
|
-
x:
|
|
1589
|
-
y: labelY,
|
|
1590
|
-
secondaryY,
|
|
1591
|
-
textAnchor:
|
|
1592
|
-
direction: direction
|
|
1620
|
+
x: placement.x,
|
|
1621
|
+
y: placement.labelY,
|
|
1622
|
+
secondaryY: placement.secondaryY,
|
|
1623
|
+
textAnchor: placement.textAnchor,
|
|
1624
|
+
direction: placement.direction,
|
|
1593
1625
|
hidden: object.hidden
|
|
1594
1626
|
});
|
|
1595
1627
|
}
|
|
1596
1628
|
return labels;
|
|
1597
1629
|
}
|
|
1598
|
-
function
|
|
1630
|
+
function compareLabelPlacementOrder(left, right) {
|
|
1631
|
+
const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
|
|
1632
|
+
if (priorityDiff !== 0) {
|
|
1633
|
+
return priorityDiff;
|
|
1634
|
+
}
|
|
1635
|
+
const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
|
|
1636
|
+
if (renderPriorityDiff !== 0) {
|
|
1637
|
+
return renderPriorityDiff;
|
|
1638
|
+
}
|
|
1639
|
+
return left.sortKey - right.sortKey;
|
|
1640
|
+
}
|
|
1641
|
+
function labelPlacementPriority(object) {
|
|
1642
|
+
switch (object.object.type) {
|
|
1643
|
+
case "star":
|
|
1644
|
+
return 0;
|
|
1645
|
+
case "planet":
|
|
1646
|
+
return 1;
|
|
1647
|
+
case "moon":
|
|
1648
|
+
return 2;
|
|
1649
|
+
case "belt":
|
|
1650
|
+
case "ring":
|
|
1651
|
+
return 3;
|
|
1652
|
+
case "asteroid":
|
|
1653
|
+
case "comet":
|
|
1654
|
+
return 4;
|
|
1655
|
+
case "structure":
|
|
1656
|
+
case "phenomenon":
|
|
1657
|
+
return 5;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1661
|
+
for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
|
|
1662
|
+
const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
|
|
1663
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
|
|
1664
|
+
const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
|
|
1665
|
+
const rect = createLabelRect(object, placement, labelMultiplier);
|
|
1666
|
+
if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
|
|
1667
|
+
return placement;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
return null;
|
|
1672
|
+
}
|
|
1673
|
+
function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
|
|
1674
|
+
const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
|
|
1675
|
+
const vertical = defaultVerticalDirection(object, parent, sceneHeight);
|
|
1676
|
+
const oppositeVertical = vertical === "below" ? "above" : "below";
|
|
1677
|
+
const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
|
|
1678
|
+
const oppositeHorizontal = horizontal === "right" ? "left" : "right";
|
|
1679
|
+
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";
|
|
1680
|
+
return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
|
|
1681
|
+
}
|
|
1682
|
+
function defaultVerticalDirection(object, parent, sceneHeight) {
|
|
1683
|
+
if (parent && Math.abs(object.y - parent.y) > 6) {
|
|
1684
|
+
return object.y >= parent.y ? "below" : "above";
|
|
1685
|
+
}
|
|
1686
|
+
return object.y > sceneHeight * 0.62 ? "above" : "below";
|
|
1687
|
+
}
|
|
1688
|
+
function defaultHorizontalDirection(object, parent, sceneWidth) {
|
|
1689
|
+
if (parent && Math.abs(object.x - parent.x) > 6) {
|
|
1690
|
+
return object.x >= parent.x ? "right" : "left";
|
|
1691
|
+
}
|
|
1692
|
+
return object.x >= sceneWidth / 2 ? "right" : "left";
|
|
1693
|
+
}
|
|
1694
|
+
function createLabelPlacement(object, direction, attempt, labelMultiplier) {
|
|
1695
|
+
const step = 14 * labelMultiplier;
|
|
1696
|
+
switch (direction) {
|
|
1697
|
+
case "above": {
|
|
1698
|
+
const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
|
|
1699
|
+
return {
|
|
1700
|
+
x: object.x,
|
|
1701
|
+
labelY,
|
|
1702
|
+
secondaryY: labelY - 16 * labelMultiplier,
|
|
1703
|
+
textAnchor: "middle",
|
|
1704
|
+
direction
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
case "below": {
|
|
1708
|
+
const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
|
|
1709
|
+
return {
|
|
1710
|
+
x: object.x,
|
|
1711
|
+
labelY,
|
|
1712
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1713
|
+
textAnchor: "middle",
|
|
1714
|
+
direction
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
case "left": {
|
|
1718
|
+
const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
|
|
1719
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1720
|
+
return {
|
|
1721
|
+
x,
|
|
1722
|
+
labelY,
|
|
1723
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1724
|
+
textAnchor: "end",
|
|
1725
|
+
direction
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
case "right": {
|
|
1729
|
+
const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
|
|
1730
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1731
|
+
return {
|
|
1732
|
+
x,
|
|
1733
|
+
labelY,
|
|
1734
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1735
|
+
textAnchor: "start",
|
|
1736
|
+
direction
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
|
|
1599
1742
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1600
1743
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1601
1744
|
return [
|
|
@@ -1610,6 +1753,10 @@
|
|
|
1610
1753
|
id: "relations",
|
|
1611
1754
|
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1612
1755
|
},
|
|
1756
|
+
{
|
|
1757
|
+
id: "events",
|
|
1758
|
+
renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
|
|
1759
|
+
},
|
|
1613
1760
|
{
|
|
1614
1761
|
id: "objects",
|
|
1615
1762
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1621,7 +1768,7 @@
|
|
|
1621
1768
|
{ id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
|
|
1622
1769
|
];
|
|
1623
1770
|
}
|
|
1624
|
-
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
|
|
1771
|
+
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
|
|
1625
1772
|
const groups = /* @__PURE__ */ new Map();
|
|
1626
1773
|
const ensureGroup = (groupId) => {
|
|
1627
1774
|
if (!groupId) {
|
|
@@ -1670,7 +1817,7 @@
|
|
|
1670
1817
|
}
|
|
1671
1818
|
}
|
|
1672
1819
|
for (const group of groups.values()) {
|
|
1673
|
-
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
|
|
1820
|
+
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
|
|
1674
1821
|
}
|
|
1675
1822
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1676
1823
|
}
|
|
@@ -1704,6 +1851,29 @@
|
|
|
1704
1851
|
};
|
|
1705
1852
|
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1706
1853
|
}
|
|
1854
|
+
function createSceneEvents(events, objects, activeEventId) {
|
|
1855
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1856
|
+
return events.map((event) => {
|
|
1857
|
+
const objectIds = [.../* @__PURE__ */ new Set([
|
|
1858
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
1859
|
+
...event.participantObjectIds
|
|
1860
|
+
])];
|
|
1861
|
+
const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
|
|
1862
|
+
const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
|
|
1863
|
+
const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
|
|
1864
|
+
return {
|
|
1865
|
+
renderId: `${createRenderId(event.id)}-event`,
|
|
1866
|
+
eventId: event.id,
|
|
1867
|
+
event,
|
|
1868
|
+
objectIds,
|
|
1869
|
+
participantIds: [...event.participantObjectIds],
|
|
1870
|
+
targetObjectId: event.targetObjectId,
|
|
1871
|
+
x: centroidX,
|
|
1872
|
+
y: centroidY,
|
|
1873
|
+
hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
|
|
1874
|
+
};
|
|
1875
|
+
}).sort((left, right) => left.event.id.localeCompare(right.event.id));
|
|
1876
|
+
}
|
|
1707
1877
|
function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
|
|
1708
1878
|
const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
|
|
1709
1879
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1757,6 +1927,7 @@
|
|
|
1757
1927
|
summary: "Fit the whole system with the current atlas defaults.",
|
|
1758
1928
|
objectId: null,
|
|
1759
1929
|
selectedObjectId: null,
|
|
1930
|
+
eventIds: [],
|
|
1760
1931
|
projection,
|
|
1761
1932
|
preset,
|
|
1762
1933
|
rotationDeg: 0,
|
|
@@ -1793,6 +1964,9 @@
|
|
|
1793
1964
|
draft.select = normalizedValue;
|
|
1794
1965
|
}
|
|
1795
1966
|
return;
|
|
1967
|
+
case "events":
|
|
1968
|
+
draft.eventIds = splitListValue(normalizedValue);
|
|
1969
|
+
return;
|
|
1796
1970
|
case "projection":
|
|
1797
1971
|
case "view":
|
|
1798
1972
|
draft.projection = parseViewProjection(normalizedValue) ?? projection;
|
|
@@ -1849,6 +2023,7 @@
|
|
|
1849
2023
|
summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
|
|
1850
2024
|
objectId,
|
|
1851
2025
|
selectedObjectId,
|
|
2026
|
+
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
1852
2027
|
projection: draft.projection ?? projection,
|
|
1853
2028
|
preset: draft.preset ?? preset,
|
|
1854
2029
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
@@ -1906,7 +2081,7 @@
|
|
|
1906
2081
|
next["orbits-front"] = enabled;
|
|
1907
2082
|
continue;
|
|
1908
2083
|
}
|
|
1909
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
2084
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1910
2085
|
next[rawLayer] = enabled;
|
|
1911
2086
|
}
|
|
1912
2087
|
}
|
|
@@ -1954,7 +2129,7 @@
|
|
|
1954
2129
|
}
|
|
1955
2130
|
return parts.join(" - ");
|
|
1956
2131
|
}
|
|
1957
|
-
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
|
|
2132
|
+
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
1958
2133
|
let minX = Number.POSITIVE_INFINITY;
|
|
1959
2134
|
let minY = Number.POSITIVE_INFINITY;
|
|
1960
2135
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -1984,7 +2159,7 @@
|
|
|
1984
2159
|
for (const label of labels) {
|
|
1985
2160
|
if (label.hidden)
|
|
1986
2161
|
continue;
|
|
1987
|
-
includeLabelBounds(label, include);
|
|
2162
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
1988
2163
|
}
|
|
1989
2164
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
1990
2165
|
return createBounds(0, 0, width, height);
|
|
@@ -2022,13 +2197,10 @@
|
|
|
2022
2197
|
include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
|
|
2023
2198
|
include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
|
|
2024
2199
|
}
|
|
2025
|
-
function includeLabelBounds(label, include) {
|
|
2026
|
-
const
|
|
2027
|
-
|
|
2028
|
-
include(
|
|
2029
|
-
include(label.x + labelHalfWidth, label.y + 8);
|
|
2030
|
-
include(label.x - labelHalfWidth, label.secondaryY - 14);
|
|
2031
|
-
include(label.x + labelHalfWidth, label.secondaryY + 8);
|
|
2200
|
+
function includeLabelBounds(label, include, labelMultiplier) {
|
|
2201
|
+
const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
|
|
2202
|
+
include(bounds.left, bounds.top);
|
|
2203
|
+
include(bounds.right, bounds.bottom);
|
|
2032
2204
|
}
|
|
2033
2205
|
function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
|
|
2034
2206
|
if (positions.has(object.id)) {
|
|
@@ -2418,7 +2590,7 @@
|
|
|
2418
2590
|
return null;
|
|
2419
2591
|
}
|
|
2420
2592
|
}
|
|
2421
|
-
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
|
|
2593
|
+
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2422
2594
|
let minX = Number.POSITIVE_INFINITY;
|
|
2423
2595
|
let minY = Number.POSITIVE_INFINITY;
|
|
2424
2596
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2447,7 +2619,7 @@
|
|
|
2447
2619
|
}
|
|
2448
2620
|
for (const label of labels) {
|
|
2449
2621
|
if (!label.hidden && group.labelIds.includes(label.objectId)) {
|
|
2450
|
-
includeLabelBounds(label, include);
|
|
2622
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2451
2623
|
}
|
|
2452
2624
|
}
|
|
2453
2625
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
@@ -2472,12 +2644,28 @@
|
|
|
2472
2644
|
}
|
|
2473
2645
|
return current.id;
|
|
2474
2646
|
}
|
|
2475
|
-
function createLabelRect(
|
|
2647
|
+
function createLabelRect(object, placement, labelMultiplier) {
|
|
2648
|
+
return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
|
|
2649
|
+
}
|
|
2650
|
+
function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
|
|
2651
|
+
const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
|
|
2652
|
+
const labelWidth = labelHalfWidth * 2;
|
|
2653
|
+
const topPadding = direction === "above" ? 18 : 12;
|
|
2654
|
+
const bottomPadding = direction === "above" ? 8 : 12;
|
|
2655
|
+
let left = x - labelHalfWidth;
|
|
2656
|
+
let right = x + labelHalfWidth;
|
|
2657
|
+
if (textAnchor === "start") {
|
|
2658
|
+
left = x;
|
|
2659
|
+
right = x + labelWidth;
|
|
2660
|
+
} else if (textAnchor === "end") {
|
|
2661
|
+
left = x - labelWidth;
|
|
2662
|
+
right = x;
|
|
2663
|
+
}
|
|
2476
2664
|
return {
|
|
2477
|
-
left
|
|
2478
|
-
right
|
|
2479
|
-
top: Math.min(labelY, secondaryY) -
|
|
2480
|
-
bottom: Math.max(labelY, secondaryY) +
|
|
2665
|
+
left,
|
|
2666
|
+
right,
|
|
2667
|
+
top: Math.min(labelY, secondaryY) - topPadding,
|
|
2668
|
+
bottom: Math.max(labelY, secondaryY) + bottomPadding
|
|
2481
2669
|
};
|
|
2482
2670
|
}
|
|
2483
2671
|
function rectsOverlap(left, right) {
|
|
@@ -2664,11 +2852,6 @@
|
|
|
2664
2852
|
function customColorFor(value) {
|
|
2665
2853
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2666
2854
|
}
|
|
2667
|
-
function estimateLabelHalfWidth(object, labelMultiplier) {
|
|
2668
|
-
const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
|
|
2669
|
-
const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
2670
|
-
return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
|
|
2671
|
-
}
|
|
2672
2855
|
function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
|
|
2673
2856
|
const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
|
|
2674
2857
|
const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
@@ -2685,7 +2868,7 @@
|
|
|
2685
2868
|
}
|
|
2686
2869
|
|
|
2687
2870
|
// packages/core/dist/draft.js
|
|
2688
|
-
function materializeAtlasDocument(document2) {
|
|
2871
|
+
function materializeAtlasDocument(document2, options = {}) {
|
|
2689
2872
|
const system = document2.system ? {
|
|
2690
2873
|
type: "system",
|
|
2691
2874
|
id: document2.system.id,
|
|
@@ -2696,6 +2879,8 @@
|
|
|
2696
2879
|
properties: materializeDraftSystemProperties(document2.system),
|
|
2697
2880
|
info: materializeDraftSystemInfo(document2.system)
|
|
2698
2881
|
} : null;
|
|
2882
|
+
const objects = document2.objects.map(cloneWorldOrbitObject);
|
|
2883
|
+
applyEventPoseOverrides(objects, document2.events ?? [], options.activeEventId ?? null);
|
|
2699
2884
|
return {
|
|
2700
2885
|
format: "worldorbit",
|
|
2701
2886
|
version: "1.0",
|
|
@@ -2703,7 +2888,8 @@
|
|
|
2703
2888
|
system,
|
|
2704
2889
|
groups: structuredClone(document2.groups ?? []),
|
|
2705
2890
|
relations: structuredClone(document2.relations ?? []),
|
|
2706
|
-
|
|
2891
|
+
events: document2.events.map(cloneWorldOrbitEvent),
|
|
2892
|
+
objects
|
|
2707
2893
|
};
|
|
2708
2894
|
}
|
|
2709
2895
|
function cloneWorldOrbitObject(object) {
|
|
@@ -2725,6 +2911,52 @@
|
|
|
2725
2911
|
info: { ...object.info }
|
|
2726
2912
|
};
|
|
2727
2913
|
}
|
|
2914
|
+
function cloneWorldOrbitEvent(event) {
|
|
2915
|
+
return {
|
|
2916
|
+
...event,
|
|
2917
|
+
participantObjectIds: [...event.participantObjectIds],
|
|
2918
|
+
tags: [...event.tags],
|
|
2919
|
+
positions: event.positions.map(cloneWorldOrbitEventPose)
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
function cloneWorldOrbitEventPose(pose) {
|
|
2923
|
+
return {
|
|
2924
|
+
objectId: pose.objectId,
|
|
2925
|
+
placement: clonePlacement(pose.placement),
|
|
2926
|
+
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
2927
|
+
outer: pose.outer ? { ...pose.outer } : void 0
|
|
2928
|
+
};
|
|
2929
|
+
}
|
|
2930
|
+
function clonePlacement(placement) {
|
|
2931
|
+
return placement ? structuredClone(placement) : null;
|
|
2932
|
+
}
|
|
2933
|
+
function applyEventPoseOverrides(objects, events, activeEventId) {
|
|
2934
|
+
if (!activeEventId) {
|
|
2935
|
+
return;
|
|
2936
|
+
}
|
|
2937
|
+
const event = events.find((entry) => entry.id === activeEventId);
|
|
2938
|
+
if (!event) {
|
|
2939
|
+
return;
|
|
2940
|
+
}
|
|
2941
|
+
const objectMap = new Map(objects.map((object) => [object.id, object]));
|
|
2942
|
+
for (const pose of event.positions) {
|
|
2943
|
+
const object = objectMap.get(pose.objectId);
|
|
2944
|
+
if (!object) {
|
|
2945
|
+
continue;
|
|
2946
|
+
}
|
|
2947
|
+
object.placement = clonePlacement(pose.placement);
|
|
2948
|
+
if (pose.inner) {
|
|
2949
|
+
object.properties.inner = { ...pose.inner };
|
|
2950
|
+
} else {
|
|
2951
|
+
delete object.properties.inner;
|
|
2952
|
+
}
|
|
2953
|
+
if (pose.outer) {
|
|
2954
|
+
object.properties.outer = { ...pose.outer };
|
|
2955
|
+
} else {
|
|
2956
|
+
delete object.properties.outer;
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2728
2960
|
function cloneProperties(properties) {
|
|
2729
2961
|
const next = {};
|
|
2730
2962
|
for (const [key, value] of Object.entries(properties)) {
|
|
@@ -2813,6 +3045,9 @@
|
|
|
2813
3045
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2814
3046
|
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2815
3047
|
}
|
|
3048
|
+
if (viewpoint.events.length > 0) {
|
|
3049
|
+
info2[`${prefix}.events`] = viewpoint.events.join(" ");
|
|
3050
|
+
}
|
|
2816
3051
|
}
|
|
2817
3052
|
for (const annotation of system.annotations) {
|
|
2818
3053
|
const prefix = `annotation.${annotation.id}`;
|
|
@@ -2837,7 +3072,7 @@
|
|
|
2837
3072
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2838
3073
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2839
3074
|
}
|
|
2840
|
-
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
3075
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
2841
3076
|
if (layers[key] !== void 0) {
|
|
2842
3077
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2843
3078
|
}
|
|
@@ -3011,6 +3246,7 @@
|
|
|
3011
3246
|
const diagnostics = [];
|
|
3012
3247
|
const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
|
|
3013
3248
|
const groupIds = new Set(document2.groups.map((group) => group.id));
|
|
3249
|
+
const eventIds = new Set(document2.events.map((event) => event.id));
|
|
3014
3250
|
if (!document2.system) {
|
|
3015
3251
|
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
3016
3252
|
}
|
|
@@ -3020,6 +3256,7 @@
|
|
|
3020
3256
|
["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
3021
3257
|
["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
3022
3258
|
["relation", document2.relations.map((relation) => relation.id)],
|
|
3259
|
+
["event", document2.events.map((event) => event.id)],
|
|
3023
3260
|
["object", document2.objects.map((object) => object.id)]
|
|
3024
3261
|
]) {
|
|
3025
3262
|
for (const id of ids) {
|
|
@@ -3035,11 +3272,14 @@
|
|
|
3035
3272
|
validateRelation(relation, objectMap, diagnostics);
|
|
3036
3273
|
}
|
|
3037
3274
|
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
3038
|
-
|
|
3275
|
+
validateViewpoint(viewpoint.filter, viewpoint.events ?? [], groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpoint.id);
|
|
3039
3276
|
}
|
|
3040
3277
|
for (const object of document2.objects) {
|
|
3041
3278
|
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
3042
3279
|
}
|
|
3280
|
+
for (const event of document2.events) {
|
|
3281
|
+
validateEvent(event, objectMap, diagnostics);
|
|
3282
|
+
}
|
|
3043
3283
|
return diagnostics;
|
|
3044
3284
|
}
|
|
3045
3285
|
function validateRelation(relation, objectMap, diagnostics) {
|
|
@@ -3057,13 +3297,19 @@
|
|
|
3057
3297
|
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
3058
3298
|
}
|
|
3059
3299
|
}
|
|
3060
|
-
function
|
|
3061
|
-
if (
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3300
|
+
function validateViewpoint(filter, eventRefs, groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpointId) {
|
|
3301
|
+
if (sourceSchemaVersion === "2.1") {
|
|
3302
|
+
if (filter) {
|
|
3303
|
+
for (const groupId of filter.groupIds) {
|
|
3304
|
+
if (!groupIds.has(groupId)) {
|
|
3305
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.groups`));
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
for (const eventId of eventRefs) {
|
|
3310
|
+
if (!eventIds.has(eventId)) {
|
|
3311
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.events`));
|
|
3312
|
+
}
|
|
3067
3313
|
}
|
|
3068
3314
|
}
|
|
3069
3315
|
}
|
|
@@ -3149,6 +3395,103 @@
|
|
|
3149
3395
|
}
|
|
3150
3396
|
}
|
|
3151
3397
|
}
|
|
3398
|
+
function validateEvent(event, objectMap, diagnostics) {
|
|
3399
|
+
const fieldPrefix = `event.${event.id}`;
|
|
3400
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
3401
|
+
if (!event.kind.trim()) {
|
|
3402
|
+
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
3403
|
+
}
|
|
3404
|
+
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3405
|
+
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3406
|
+
}
|
|
3407
|
+
if (event.targetObjectId) {
|
|
3408
|
+
referencedIds.add(event.targetObjectId);
|
|
3409
|
+
if (!objectMap.has(event.targetObjectId)) {
|
|
3410
|
+
diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
const seenParticipants = /* @__PURE__ */ new Set();
|
|
3414
|
+
for (const participantId of event.participantObjectIds) {
|
|
3415
|
+
referencedIds.add(participantId);
|
|
3416
|
+
if (seenParticipants.has(participantId)) {
|
|
3417
|
+
diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
|
|
3418
|
+
continue;
|
|
3419
|
+
}
|
|
3420
|
+
seenParticipants.add(participantId);
|
|
3421
|
+
if (!objectMap.has(participantId)) {
|
|
3422
|
+
diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
|
|
3426
|
+
diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
|
|
3427
|
+
}
|
|
3428
|
+
if (event.positions.length === 0) {
|
|
3429
|
+
diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
|
|
3430
|
+
}
|
|
3431
|
+
if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
|
|
3432
|
+
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`));
|
|
3433
|
+
}
|
|
3434
|
+
const poseIds = /* @__PURE__ */ new Set();
|
|
3435
|
+
for (const pose of event.positions) {
|
|
3436
|
+
const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
|
|
3437
|
+
if (poseIds.has(pose.objectId)) {
|
|
3438
|
+
diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
|
|
3439
|
+
continue;
|
|
3440
|
+
}
|
|
3441
|
+
poseIds.add(pose.objectId);
|
|
3442
|
+
const object = objectMap.get(pose.objectId);
|
|
3443
|
+
if (!object) {
|
|
3444
|
+
diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
|
|
3445
|
+
continue;
|
|
3446
|
+
}
|
|
3447
|
+
if (!referencedIds.has(pose.objectId)) {
|
|
3448
|
+
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
3449
|
+
}
|
|
3450
|
+
validateEventPose(pose, object, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
function validateEventPose(pose, object, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3454
|
+
const placement = pose.placement;
|
|
3455
|
+
if (!placement) {
|
|
3456
|
+
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
3457
|
+
return;
|
|
3458
|
+
}
|
|
3459
|
+
if (placement.mode === "orbit") {
|
|
3460
|
+
if (!objectMap.has(placement.target)) {
|
|
3461
|
+
diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
|
|
3462
|
+
}
|
|
3463
|
+
if (placement.distance && placement.semiMajor) {
|
|
3464
|
+
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
3465
|
+
}
|
|
3466
|
+
return;
|
|
3467
|
+
}
|
|
3468
|
+
if (placement.mode === "surface") {
|
|
3469
|
+
const target = objectMap.get(placement.target);
|
|
3470
|
+
if (!target) {
|
|
3471
|
+
diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
|
|
3472
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3473
|
+
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`));
|
|
3474
|
+
}
|
|
3475
|
+
return;
|
|
3476
|
+
}
|
|
3477
|
+
if (placement.mode === "at") {
|
|
3478
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3479
|
+
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`));
|
|
3480
|
+
}
|
|
3481
|
+
const reference = placement.reference;
|
|
3482
|
+
if (reference.kind === "named" && !objectMap.has(reference.name)) {
|
|
3483
|
+
diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3484
|
+
} else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
|
|
3485
|
+
diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3486
|
+
} else if (reference.kind === "lagrange") {
|
|
3487
|
+
if (!objectMap.has(reference.primary)) {
|
|
3488
|
+
diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3489
|
+
} else if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3490
|
+
diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3152
3495
|
function validateAtTarget(object, objectMap, diagnostics) {
|
|
3153
3496
|
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
3154
3497
|
if (!reference) {
|
|
@@ -3349,6 +3692,21 @@
|
|
|
3349
3692
|
});
|
|
3350
3693
|
}
|
|
3351
3694
|
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
3695
|
+
var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
3696
|
+
"orbit",
|
|
3697
|
+
"distance",
|
|
3698
|
+
"semiMajor",
|
|
3699
|
+
"eccentricity",
|
|
3700
|
+
"period",
|
|
3701
|
+
"angle",
|
|
3702
|
+
"inclination",
|
|
3703
|
+
"phase",
|
|
3704
|
+
"at",
|
|
3705
|
+
"surface",
|
|
3706
|
+
"free",
|
|
3707
|
+
"inner",
|
|
3708
|
+
"outer"
|
|
3709
|
+
]);
|
|
3352
3710
|
function parseWorldOrbitAtlas(source) {
|
|
3353
3711
|
return parseAtlasSource(source);
|
|
3354
3712
|
}
|
|
@@ -3363,12 +3721,15 @@
|
|
|
3363
3721
|
const objectNodes = [];
|
|
3364
3722
|
const groups = [];
|
|
3365
3723
|
const relations = [];
|
|
3724
|
+
const events = [];
|
|
3725
|
+
const eventPoseNodes = /* @__PURE__ */ new Map();
|
|
3366
3726
|
let sawDefaults = false;
|
|
3367
3727
|
let sawAtlas = false;
|
|
3368
3728
|
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3369
3729
|
const annotationIds = /* @__PURE__ */ new Set();
|
|
3370
3730
|
const groupIds = /* @__PURE__ */ new Set();
|
|
3371
3731
|
const relationIds = /* @__PURE__ */ new Set();
|
|
3732
|
+
const eventIds = /* @__PURE__ */ new Set();
|
|
3372
3733
|
for (let index = 0; index < lines.length; index++) {
|
|
3373
3734
|
const rawLine = lines[index];
|
|
3374
3735
|
const lineNumber = index + 1;
|
|
@@ -3399,7 +3760,7 @@
|
|
|
3399
3760
|
continue;
|
|
3400
3761
|
}
|
|
3401
3762
|
if (indent === 0) {
|
|
3402
|
-
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
3763
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
3403
3764
|
if (section.kind === "system") {
|
|
3404
3765
|
system = section.system;
|
|
3405
3766
|
} else if (section.kind === "defaults") {
|
|
@@ -3418,6 +3779,7 @@
|
|
|
3418
3779
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3419
3780
|
}
|
|
3420
3781
|
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
3782
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
3421
3783
|
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3422
3784
|
const baseDocument = {
|
|
3423
3785
|
format: "worldorbit",
|
|
@@ -3425,6 +3787,7 @@
|
|
|
3425
3787
|
system,
|
|
3426
3788
|
groups,
|
|
3427
3789
|
relations,
|
|
3790
|
+
events: normalizedEvents,
|
|
3428
3791
|
objects,
|
|
3429
3792
|
diagnostics
|
|
3430
3793
|
};
|
|
@@ -3460,7 +3823,7 @@
|
|
|
3460
3823
|
const version = tokens[1].value.toLowerCase();
|
|
3461
3824
|
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3462
3825
|
}
|
|
3463
|
-
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
3826
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3464
3827
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
3465
3828
|
switch (keyword) {
|
|
3466
3829
|
case "system":
|
|
@@ -3497,7 +3860,7 @@
|
|
|
3497
3860
|
if (!system) {
|
|
3498
3861
|
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
3499
3862
|
}
|
|
3500
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
3863
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
3501
3864
|
case "annotation":
|
|
3502
3865
|
if (!system) {
|
|
3503
3866
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -3509,6 +3872,9 @@
|
|
|
3509
3872
|
case "relation":
|
|
3510
3873
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
3511
3874
|
return startRelationSection(tokens, line, relations, relationIds);
|
|
3875
|
+
case "event":
|
|
3876
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
3877
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
3512
3878
|
case "object":
|
|
3513
3879
|
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3514
3880
|
default:
|
|
@@ -3545,7 +3911,7 @@
|
|
|
3545
3911
|
seenFields: /* @__PURE__ */ new Set()
|
|
3546
3912
|
};
|
|
3547
3913
|
}
|
|
3548
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
3914
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
3549
3915
|
if (tokens.length !== 2) {
|
|
3550
3916
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
3551
3917
|
}
|
|
@@ -3562,6 +3928,7 @@
|
|
|
3562
3928
|
summary: "",
|
|
3563
3929
|
focusObjectId: null,
|
|
3564
3930
|
selectedObjectId: null,
|
|
3931
|
+
events: [],
|
|
3565
3932
|
projection: system.defaults.view,
|
|
3566
3933
|
preset: system.defaults.preset,
|
|
3567
3934
|
zoom: null,
|
|
@@ -3574,6 +3941,8 @@
|
|
|
3574
3941
|
return {
|
|
3575
3942
|
kind: "viewpoint",
|
|
3576
3943
|
viewpoint,
|
|
3944
|
+
sourceSchemaVersion,
|
|
3945
|
+
diagnostics,
|
|
3577
3946
|
seenFields: /* @__PURE__ */ new Set(),
|
|
3578
3947
|
inFilter: false,
|
|
3579
3948
|
filterIndent: null,
|
|
@@ -3664,6 +4033,49 @@
|
|
|
3664
4033
|
seenFields: /* @__PURE__ */ new Set()
|
|
3665
4034
|
};
|
|
3666
4035
|
}
|
|
4036
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
4037
|
+
if (tokens.length !== 2) {
|
|
4038
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
4039
|
+
}
|
|
4040
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
4041
|
+
if (!id) {
|
|
4042
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
4043
|
+
}
|
|
4044
|
+
if (eventIds.has(id)) {
|
|
4045
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
4046
|
+
}
|
|
4047
|
+
const event = {
|
|
4048
|
+
id,
|
|
4049
|
+
kind: "",
|
|
4050
|
+
label: humanizeIdentifier2(id),
|
|
4051
|
+
summary: null,
|
|
4052
|
+
targetObjectId: null,
|
|
4053
|
+
participantObjectIds: [],
|
|
4054
|
+
timing: null,
|
|
4055
|
+
visibility: null,
|
|
4056
|
+
tags: [],
|
|
4057
|
+
color: null,
|
|
4058
|
+
hidden: false,
|
|
4059
|
+
positions: []
|
|
4060
|
+
};
|
|
4061
|
+
const rawPoses = [];
|
|
4062
|
+
events.push(event);
|
|
4063
|
+
eventPoseNodes.set(id, rawPoses);
|
|
4064
|
+
eventIds.add(id);
|
|
4065
|
+
return {
|
|
4066
|
+
kind: "event",
|
|
4067
|
+
event,
|
|
4068
|
+
sourceSchemaVersion,
|
|
4069
|
+
diagnostics,
|
|
4070
|
+
seenFields: /* @__PURE__ */ new Set(),
|
|
4071
|
+
rawPoses,
|
|
4072
|
+
inPositions: false,
|
|
4073
|
+
positionsIndent: null,
|
|
4074
|
+
activePose: null,
|
|
4075
|
+
poseIndent: null,
|
|
4076
|
+
activePoseSeenFields: /* @__PURE__ */ new Set()
|
|
4077
|
+
};
|
|
4078
|
+
}
|
|
3667
4079
|
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
3668
4080
|
if (tokens.length < 3) {
|
|
3669
4081
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
@@ -3720,6 +4132,9 @@
|
|
|
3720
4132
|
case "relation":
|
|
3721
4133
|
applyRelationField(section, tokens, line);
|
|
3722
4134
|
return;
|
|
4135
|
+
case "event":
|
|
4136
|
+
applyEventField(section, indent, tokens, line);
|
|
4137
|
+
return;
|
|
3723
4138
|
case "object":
|
|
3724
4139
|
applyObjectField(section, indent, tokens, line);
|
|
3725
4140
|
return;
|
|
@@ -3846,7 +4261,14 @@
|
|
|
3846
4261
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
3847
4262
|
return;
|
|
3848
4263
|
case "layers":
|
|
3849
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
4264
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
4265
|
+
return;
|
|
4266
|
+
case "events":
|
|
4267
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
4268
|
+
line,
|
|
4269
|
+
column: tokens[0].column
|
|
4270
|
+
});
|
|
4271
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
3850
4272
|
return;
|
|
3851
4273
|
default:
|
|
3852
4274
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
@@ -3951,6 +4373,106 @@
|
|
|
3951
4373
|
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3952
4374
|
}
|
|
3953
4375
|
}
|
|
4376
|
+
function applyEventField(section, indent, tokens, line) {
|
|
4377
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
4378
|
+
section.activePose = null;
|
|
4379
|
+
section.poseIndent = null;
|
|
4380
|
+
section.activePoseSeenFields.clear();
|
|
4381
|
+
}
|
|
4382
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
4383
|
+
section.inPositions = false;
|
|
4384
|
+
section.positionsIndent = null;
|
|
4385
|
+
}
|
|
4386
|
+
if (section.activePose) {
|
|
4387
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4388
|
+
return;
|
|
4389
|
+
}
|
|
4390
|
+
if (section.inPositions) {
|
|
4391
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
4392
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
4393
|
+
}
|
|
4394
|
+
const objectId = tokens[1].value;
|
|
4395
|
+
if (!objectId.trim()) {
|
|
4396
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
4397
|
+
}
|
|
4398
|
+
const rawPose = {
|
|
4399
|
+
objectId,
|
|
4400
|
+
fields: [],
|
|
4401
|
+
location: { line, column: tokens[0].column }
|
|
4402
|
+
};
|
|
4403
|
+
section.rawPoses.push(rawPose);
|
|
4404
|
+
section.activePose = rawPose;
|
|
4405
|
+
section.poseIndent = indent;
|
|
4406
|
+
section.activePoseSeenFields = /* @__PURE__ */ new Set();
|
|
4407
|
+
return;
|
|
4408
|
+
}
|
|
4409
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
4410
|
+
if (section.seenFields.has("positions")) {
|
|
4411
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
4412
|
+
}
|
|
4413
|
+
section.seenFields.add("positions");
|
|
4414
|
+
section.inPositions = true;
|
|
4415
|
+
section.positionsIndent = indent;
|
|
4416
|
+
return;
|
|
4417
|
+
}
|
|
4418
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4419
|
+
switch (key) {
|
|
4420
|
+
case "kind":
|
|
4421
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
4422
|
+
return;
|
|
4423
|
+
case "label":
|
|
4424
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
4425
|
+
return;
|
|
4426
|
+
case "summary":
|
|
4427
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
4428
|
+
return;
|
|
4429
|
+
case "target":
|
|
4430
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
4431
|
+
return;
|
|
4432
|
+
case "participants":
|
|
4433
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
4434
|
+
return;
|
|
4435
|
+
case "timing":
|
|
4436
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
4437
|
+
return;
|
|
4438
|
+
case "visibility":
|
|
4439
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
4440
|
+
return;
|
|
4441
|
+
case "tags":
|
|
4442
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4443
|
+
return;
|
|
4444
|
+
case "color":
|
|
4445
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
4446
|
+
return;
|
|
4447
|
+
case "hidden":
|
|
4448
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4449
|
+
line,
|
|
4450
|
+
column: tokens[0].column
|
|
4451
|
+
});
|
|
4452
|
+
return;
|
|
4453
|
+
default:
|
|
4454
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
4458
|
+
if (tokens.length < 2) {
|
|
4459
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
4460
|
+
}
|
|
4461
|
+
const key = tokens[0].value;
|
|
4462
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
4463
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
4464
|
+
}
|
|
4465
|
+
if (seenFields.has(key)) {
|
|
4466
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
4467
|
+
}
|
|
4468
|
+
seenFields.add(key);
|
|
4469
|
+
return {
|
|
4470
|
+
type: "field",
|
|
4471
|
+
key,
|
|
4472
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
4473
|
+
location: { line, column: tokens[0].column }
|
|
4474
|
+
};
|
|
4475
|
+
}
|
|
3954
4476
|
function applyObjectField(section, indent, tokens, line) {
|
|
3955
4477
|
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
3956
4478
|
section.activeBlock = null;
|
|
@@ -4009,7 +4531,7 @@
|
|
|
4009
4531
|
function parseObjectTypeTokens(tokens, line) {
|
|
4010
4532
|
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");
|
|
4011
4533
|
}
|
|
4012
|
-
function parseLayerTokens(tokens, line) {
|
|
4534
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
4013
4535
|
const layers = {};
|
|
4014
4536
|
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
4015
4537
|
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
@@ -4019,7 +4541,13 @@
|
|
|
4019
4541
|
layers["orbits-front"] = enabled;
|
|
4020
4542
|
continue;
|
|
4021
4543
|
}
|
|
4022
|
-
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4544
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4545
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
4546
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
4547
|
+
line,
|
|
4548
|
+
column: tokens[0]?.column ?? 1
|
|
4549
|
+
});
|
|
4550
|
+
}
|
|
4023
4551
|
layers[raw] = enabled;
|
|
4024
4552
|
}
|
|
4025
4553
|
}
|
|
@@ -4158,7 +4686,7 @@
|
|
|
4158
4686
|
}
|
|
4159
4687
|
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
4160
4688
|
const fieldMap = collectDraftFields(node.fields);
|
|
4161
|
-
const placement =
|
|
4689
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4162
4690
|
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
4163
4691
|
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
4164
4692
|
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
@@ -4210,6 +4738,24 @@
|
|
|
4210
4738
|
}
|
|
4211
4739
|
return object;
|
|
4212
4740
|
}
|
|
4741
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
4742
|
+
return {
|
|
4743
|
+
...event,
|
|
4744
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
4745
|
+
tags: [...new Set(event.tags)],
|
|
4746
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
|
|
4747
|
+
};
|
|
4748
|
+
}
|
|
4749
|
+
function normalizeDraftEventPose(rawPose) {
|
|
4750
|
+
const fieldMap = collectDraftFields(rawPose.fields);
|
|
4751
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4752
|
+
return {
|
|
4753
|
+
objectId: rawPose.objectId,
|
|
4754
|
+
placement,
|
|
4755
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
4756
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer")
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4213
4759
|
function collectDraftFields(fields) {
|
|
4214
4760
|
const grouped = /* @__PURE__ */ new Map();
|
|
4215
4761
|
for (const field of fields) {
|
|
@@ -4226,7 +4772,7 @@
|
|
|
4226
4772
|
}
|
|
4227
4773
|
return grouped;
|
|
4228
4774
|
}
|
|
4229
|
-
function
|
|
4775
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
4230
4776
|
const orbitField = fieldMap.get("orbit")?.[0];
|
|
4231
4777
|
const atField = fieldMap.get("at")?.[0];
|
|
4232
4778
|
const surfaceField = fieldMap.get("surface")?.[0];
|
|
@@ -4837,6 +5383,7 @@
|
|
|
4837
5383
|
const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
|
|
4838
5384
|
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("") : "";
|
|
4839
5385
|
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("") : "";
|
|
5386
|
+
const eventMarkup = layers.events ? scene.events.filter((event) => !event.hidden).map((event) => renderSceneEventOverlay(scene, event, visibleObjectIds, theme)).join("") : "";
|
|
4840
5387
|
const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
|
|
4841
5388
|
const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
|
|
4842
5389
|
const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
|
|
@@ -4872,6 +5419,9 @@
|
|
|
4872
5419
|
.wo-orbit-front { opacity: 0.9; }
|
|
4873
5420
|
.wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
|
|
4874
5421
|
.wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
|
|
5422
|
+
.wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
|
|
5423
|
+
.wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
|
|
5424
|
+
.wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
4875
5425
|
.wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
|
|
4876
5426
|
.wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
|
|
4877
5427
|
.wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
|
|
@@ -4906,6 +5456,7 @@
|
|
|
4906
5456
|
${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
|
|
4907
5457
|
${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
|
|
4908
5458
|
${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
|
|
5459
|
+
${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
|
|
4909
5460
|
${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
|
|
4910
5461
|
${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
|
|
4911
5462
|
${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
|
|
@@ -4913,6 +5464,20 @@
|
|
|
4913
5464
|
</g>
|
|
4914
5465
|
</g>
|
|
4915
5466
|
</svg>`;
|
|
5467
|
+
}
|
|
5468
|
+
function renderSceneEventOverlay(scene, event, visibleObjectIds, theme) {
|
|
5469
|
+
const participants = event.objectIds.filter((objectId) => visibleObjectIds.has(objectId)).map((objectId) => scene.objects.find((object) => object.objectId === objectId && !object.hidden)).filter(Boolean);
|
|
5470
|
+
if (participants.length === 0) {
|
|
5471
|
+
return "";
|
|
5472
|
+
}
|
|
5473
|
+
const stroke = event.event.color || theme.accent;
|
|
5474
|
+
const label = event.event.label || event.event.id;
|
|
5475
|
+
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("");
|
|
5476
|
+
return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
|
|
5477
|
+
${lineMarkup}
|
|
5478
|
+
<circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
|
|
5479
|
+
<text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
|
|
5480
|
+
</g>`;
|
|
4916
5481
|
}
|
|
4917
5482
|
function renderDocumentToSvg(document2, options = {}) {
|
|
4918
5483
|
return renderSceneToSvg(renderDocumentToScene(document2, options), options);
|
|
@@ -5512,6 +6077,13 @@
|
|
|
5512
6077
|
value: `${details.object.resonance.targetObjectId} ${details.object.resonance.ratio}`
|
|
5513
6078
|
});
|
|
5514
6079
|
}
|
|
6080
|
+
if (details.relatedEvents.length > 0) {
|
|
6081
|
+
fields.set("events", {
|
|
6082
|
+
key: "events",
|
|
6083
|
+
label: "Events",
|
|
6084
|
+
value: details.relatedEvents.map((event) => event.event.label || event.event.id).join(", ")
|
|
6085
|
+
});
|
|
6086
|
+
}
|
|
5515
6087
|
if (placement?.mode === "at") {
|
|
5516
6088
|
fields.set("placement", {
|
|
5517
6089
|
key: "placement",
|
|
@@ -5926,6 +6498,12 @@
|
|
|
5926
6498
|
emitAtlasStateChange();
|
|
5927
6499
|
return true;
|
|
5928
6500
|
},
|
|
6501
|
+
getActiveEventId() {
|
|
6502
|
+
return renderOptions.activeEventId ?? null;
|
|
6503
|
+
},
|
|
6504
|
+
setActiveEvent(id) {
|
|
6505
|
+
api.setRenderOptions({ activeEventId: id });
|
|
6506
|
+
},
|
|
5929
6507
|
search(query, limit = 12) {
|
|
5930
6508
|
return searchSceneObjects(scene, query, limit);
|
|
5931
6509
|
},
|
|
@@ -6190,6 +6768,7 @@
|
|
|
6190
6768
|
orbit: scene.orbitVisuals.find((orbit) => orbit.objectId === renderObject.objectId && !orbit.hidden) ?? null,
|
|
6191
6769
|
relatedOrbits: scene.orbitVisuals.filter((orbit) => !orbit.hidden && (orbit.objectId === renderObject.objectId || renderObject.ancestorIds.includes(orbit.objectId) || renderObject.childIds.includes(orbit.objectId))),
|
|
6192
6770
|
relations: scene.relations.filter((relation) => !relation.hidden && (relation.fromObjectId === renderObject.objectId || relation.toObjectId === renderObject.objectId)),
|
|
6771
|
+
relatedEvents: scene.events.filter((event) => !event.hidden && (event.targetObjectId === renderObject.objectId || event.objectIds.includes(renderObject.objectId))),
|
|
6193
6772
|
parent: getObjectById(renderObject.parentId),
|
|
6194
6773
|
children: renderObject.childIds.map((childId) => getObjectById(childId)).filter(Boolean),
|
|
6195
6774
|
ancestors: renderObject.ancestorIds.map((ancestorId) => getObjectById(ancestorId)).filter(Boolean),
|
|
@@ -6506,7 +7085,8 @@
|
|
|
6506
7085
|
filter: renderOptions.filter ? { ...renderOptions.filter } : void 0,
|
|
6507
7086
|
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0,
|
|
6508
7087
|
layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
|
|
6509
|
-
theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme
|
|
7088
|
+
theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme,
|
|
7089
|
+
activeEventId: renderOptions.activeEventId ?? null
|
|
6510
7090
|
};
|
|
6511
7091
|
}
|
|
6512
7092
|
function mergeRenderOptions(current, next) {
|
|
@@ -6526,7 +7106,7 @@
|
|
|
6526
7106
|
};
|
|
6527
7107
|
}
|
|
6528
7108
|
function hasSceneAffectingRenderOptions(options) {
|
|
6529
|
-
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;
|
|
7109
|
+
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 || options.activeEventId !== void 0;
|
|
6530
7110
|
}
|
|
6531
7111
|
function resolveSourceRenderOptions2(loaded, renderOptions) {
|
|
6532
7112
|
const atlasDocument = loaded.atlasDocument ?? loaded.draftDocument;
|
|
@@ -7136,6 +7716,7 @@
|
|
|
7136
7716
|
groupCount: activeViewer.getScene().groups.length,
|
|
7137
7717
|
semanticGroupCount: activeViewer.getScene().semanticGroups.length,
|
|
7138
7718
|
relationCount: activeViewer.getScene().relations.length,
|
|
7719
|
+
eventCount: activeViewer.getScene().events.length,
|
|
7139
7720
|
viewpointCount: activeViewer.getScene().viewpoints.length
|
|
7140
7721
|
}
|
|
7141
7722
|
};
|