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
|
@@ -544,6 +544,7 @@
|
|
|
544
544
|
system,
|
|
545
545
|
groups: [],
|
|
546
546
|
relations: [],
|
|
547
|
+
events: [],
|
|
547
548
|
objects
|
|
548
549
|
};
|
|
549
550
|
}
|
|
@@ -1001,8 +1002,10 @@
|
|
|
1001
1002
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
1002
1003
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
1003
1004
|
const systemId = document.system?.id ?? null;
|
|
1004
|
-
const
|
|
1005
|
-
const
|
|
1005
|
+
const activeEventId = options.activeEventId ?? null;
|
|
1006
|
+
const effectiveObjects = createEffectiveObjects(document.objects, document.events ?? [], activeEventId);
|
|
1007
|
+
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
1008
|
+
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
1006
1009
|
const positions = /* @__PURE__ */ new Map();
|
|
1007
1010
|
const orbitDrafts = [];
|
|
1008
1011
|
const leaderDrafts = [];
|
|
@@ -1011,7 +1014,7 @@
|
|
|
1011
1014
|
const atObjects = [];
|
|
1012
1015
|
const surfaceChildren = /* @__PURE__ */ new Map();
|
|
1013
1016
|
const orbitChildren = /* @__PURE__ */ new Map();
|
|
1014
|
-
for (const object of
|
|
1017
|
+
for (const object of effectiveObjects) {
|
|
1015
1018
|
const placement = object.placement;
|
|
1016
1019
|
if (!placement) {
|
|
1017
1020
|
rootObjects.push(object);
|
|
@@ -1106,13 +1109,14 @@
|
|
|
1106
1109
|
const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
|
|
1107
1110
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1108
1111
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1109
|
-
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1112
|
+
const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
|
|
1110
1113
|
const relations = createSceneRelations(document, objects);
|
|
1111
|
-
const
|
|
1112
|
-
const
|
|
1114
|
+
const events = createSceneEvents(document.events ?? [], objects, activeEventId);
|
|
1115
|
+
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1116
|
+
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1113
1117
|
const semanticGroups = createSceneSemanticGroups(document, objects);
|
|
1114
1118
|
const viewpoints = createSceneViewpoints(document, projection, frame.preset, relationships, objectMap);
|
|
1115
|
-
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1119
|
+
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1116
1120
|
return {
|
|
1117
1121
|
width,
|
|
1118
1122
|
height,
|
|
@@ -1138,6 +1142,8 @@
|
|
|
1138
1142
|
groups,
|
|
1139
1143
|
semanticGroups,
|
|
1140
1144
|
viewpoints,
|
|
1145
|
+
events,
|
|
1146
|
+
activeEventId,
|
|
1141
1147
|
objects,
|
|
1142
1148
|
orbitVisuals,
|
|
1143
1149
|
relations,
|
|
@@ -1156,6 +1162,35 @@
|
|
|
1156
1162
|
y: center.y + dx * sin + dy * cos
|
|
1157
1163
|
};
|
|
1158
1164
|
}
|
|
1165
|
+
function createEffectiveObjects(objects, events, activeEventId) {
|
|
1166
|
+
const cloned = objects.map((object) => structuredClone(object));
|
|
1167
|
+
if (!activeEventId) {
|
|
1168
|
+
return cloned;
|
|
1169
|
+
}
|
|
1170
|
+
const activeEvent = events.find((event) => event.id === activeEventId);
|
|
1171
|
+
if (!activeEvent) {
|
|
1172
|
+
return cloned;
|
|
1173
|
+
}
|
|
1174
|
+
const objectMap = new Map(cloned.map((object) => [object.id, object]));
|
|
1175
|
+
for (const pose of activeEvent.positions) {
|
|
1176
|
+
const object = objectMap.get(pose.objectId);
|
|
1177
|
+
if (!object) {
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
object.placement = pose.placement ? structuredClone(pose.placement) : null;
|
|
1181
|
+
if (pose.inner) {
|
|
1182
|
+
object.properties.inner = { ...pose.inner };
|
|
1183
|
+
} else {
|
|
1184
|
+
delete object.properties.inner;
|
|
1185
|
+
}
|
|
1186
|
+
if (pose.outer) {
|
|
1187
|
+
object.properties.outer = { ...pose.outer };
|
|
1188
|
+
} else {
|
|
1189
|
+
delete object.properties.outer;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return cloned;
|
|
1193
|
+
}
|
|
1159
1194
|
function resolveLayoutPreset(document) {
|
|
1160
1195
|
const rawScale = String(document.system?.properties.scale ?? "balanced").toLowerCase();
|
|
1161
1196
|
switch (rawScale) {
|
|
@@ -1311,24 +1346,14 @@
|
|
|
1311
1346
|
hidden: draft.object.properties.hidden === true
|
|
1312
1347
|
};
|
|
1313
1348
|
}
|
|
1314
|
-
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1349
|
+
function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1315
1350
|
const labels = [];
|
|
1316
1351
|
const occupied = [];
|
|
1317
|
-
const
|
|
1352
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1353
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
|
|
1318
1354
|
for (const object of visibleObjects) {
|
|
1319
|
-
const
|
|
1320
|
-
|
|
1321
|
-
let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
|
|
1322
|
-
let secondaryY = labelY + direction * (16 * labelMultiplier);
|
|
1323
|
-
let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1324
|
-
let attempts = 0;
|
|
1325
|
-
while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
|
|
1326
|
-
labelY += direction * 14 * labelMultiplier;
|
|
1327
|
-
secondaryY += direction * 14 * labelMultiplier;
|
|
1328
|
-
bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1329
|
-
attempts += 1;
|
|
1330
|
-
}
|
|
1331
|
-
occupied.push(bounds);
|
|
1355
|
+
const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
|
|
1356
|
+
occupied.push(createLabelRect(object, placement, labelMultiplier));
|
|
1332
1357
|
labels.push({
|
|
1333
1358
|
renderId: `${object.renderId}-label`,
|
|
1334
1359
|
objectId: object.objectId,
|
|
@@ -1337,17 +1362,128 @@
|
|
|
1337
1362
|
semanticGroupIds: [...object.semanticGroupIds],
|
|
1338
1363
|
label: object.label,
|
|
1339
1364
|
secondaryLabel: object.secondaryLabel,
|
|
1340
|
-
x:
|
|
1341
|
-
y: labelY,
|
|
1342
|
-
secondaryY,
|
|
1343
|
-
textAnchor:
|
|
1344
|
-
direction: direction
|
|
1365
|
+
x: placement.x,
|
|
1366
|
+
y: placement.labelY,
|
|
1367
|
+
secondaryY: placement.secondaryY,
|
|
1368
|
+
textAnchor: placement.textAnchor,
|
|
1369
|
+
direction: placement.direction,
|
|
1345
1370
|
hidden: object.hidden
|
|
1346
1371
|
});
|
|
1347
1372
|
}
|
|
1348
1373
|
return labels;
|
|
1349
1374
|
}
|
|
1350
|
-
function
|
|
1375
|
+
function compareLabelPlacementOrder(left, right) {
|
|
1376
|
+
const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
|
|
1377
|
+
if (priorityDiff !== 0) {
|
|
1378
|
+
return priorityDiff;
|
|
1379
|
+
}
|
|
1380
|
+
const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
|
|
1381
|
+
if (renderPriorityDiff !== 0) {
|
|
1382
|
+
return renderPriorityDiff;
|
|
1383
|
+
}
|
|
1384
|
+
return left.sortKey - right.sortKey;
|
|
1385
|
+
}
|
|
1386
|
+
function labelPlacementPriority(object) {
|
|
1387
|
+
switch (object.object.type) {
|
|
1388
|
+
case "star":
|
|
1389
|
+
return 0;
|
|
1390
|
+
case "planet":
|
|
1391
|
+
return 1;
|
|
1392
|
+
case "moon":
|
|
1393
|
+
return 2;
|
|
1394
|
+
case "belt":
|
|
1395
|
+
case "ring":
|
|
1396
|
+
return 3;
|
|
1397
|
+
case "asteroid":
|
|
1398
|
+
case "comet":
|
|
1399
|
+
return 4;
|
|
1400
|
+
case "structure":
|
|
1401
|
+
case "phenomenon":
|
|
1402
|
+
return 5;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1406
|
+
for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
|
|
1407
|
+
const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
|
|
1408
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
|
|
1409
|
+
const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
|
|
1410
|
+
const rect = createLabelRect(object, placement, labelMultiplier);
|
|
1411
|
+
if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
|
|
1412
|
+
return placement;
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return null;
|
|
1417
|
+
}
|
|
1418
|
+
function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
|
|
1419
|
+
const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
|
|
1420
|
+
const vertical = defaultVerticalDirection(object, parent, sceneHeight);
|
|
1421
|
+
const oppositeVertical = vertical === "below" ? "above" : "below";
|
|
1422
|
+
const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
|
|
1423
|
+
const oppositeHorizontal = horizontal === "right" ? "left" : "right";
|
|
1424
|
+
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";
|
|
1425
|
+
return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
|
|
1426
|
+
}
|
|
1427
|
+
function defaultVerticalDirection(object, parent, sceneHeight) {
|
|
1428
|
+
if (parent && Math.abs(object.y - parent.y) > 6) {
|
|
1429
|
+
return object.y >= parent.y ? "below" : "above";
|
|
1430
|
+
}
|
|
1431
|
+
return object.y > sceneHeight * 0.62 ? "above" : "below";
|
|
1432
|
+
}
|
|
1433
|
+
function defaultHorizontalDirection(object, parent, sceneWidth) {
|
|
1434
|
+
if (parent && Math.abs(object.x - parent.x) > 6) {
|
|
1435
|
+
return object.x >= parent.x ? "right" : "left";
|
|
1436
|
+
}
|
|
1437
|
+
return object.x >= sceneWidth / 2 ? "right" : "left";
|
|
1438
|
+
}
|
|
1439
|
+
function createLabelPlacement(object, direction, attempt, labelMultiplier) {
|
|
1440
|
+
const step = 14 * labelMultiplier;
|
|
1441
|
+
switch (direction) {
|
|
1442
|
+
case "above": {
|
|
1443
|
+
const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
|
|
1444
|
+
return {
|
|
1445
|
+
x: object.x,
|
|
1446
|
+
labelY,
|
|
1447
|
+
secondaryY: labelY - 16 * labelMultiplier,
|
|
1448
|
+
textAnchor: "middle",
|
|
1449
|
+
direction
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
case "below": {
|
|
1453
|
+
const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
|
|
1454
|
+
return {
|
|
1455
|
+
x: object.x,
|
|
1456
|
+
labelY,
|
|
1457
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1458
|
+
textAnchor: "middle",
|
|
1459
|
+
direction
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
case "left": {
|
|
1463
|
+
const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
|
|
1464
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1465
|
+
return {
|
|
1466
|
+
x,
|
|
1467
|
+
labelY,
|
|
1468
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1469
|
+
textAnchor: "end",
|
|
1470
|
+
direction
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
case "right": {
|
|
1474
|
+
const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
|
|
1475
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1476
|
+
return {
|
|
1477
|
+
x,
|
|
1478
|
+
labelY,
|
|
1479
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1480
|
+
textAnchor: "start",
|
|
1481
|
+
direction
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
|
|
1351
1487
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1352
1488
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1353
1489
|
return [
|
|
@@ -1362,6 +1498,10 @@
|
|
|
1362
1498
|
id: "relations",
|
|
1363
1499
|
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1364
1500
|
},
|
|
1501
|
+
{
|
|
1502
|
+
id: "events",
|
|
1503
|
+
renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
|
|
1504
|
+
},
|
|
1365
1505
|
{
|
|
1366
1506
|
id: "objects",
|
|
1367
1507
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1373,7 +1513,7 @@
|
|
|
1373
1513
|
{ id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
|
|
1374
1514
|
];
|
|
1375
1515
|
}
|
|
1376
|
-
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
|
|
1516
|
+
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
|
|
1377
1517
|
const groups = /* @__PURE__ */ new Map();
|
|
1378
1518
|
const ensureGroup = (groupId) => {
|
|
1379
1519
|
if (!groupId) {
|
|
@@ -1422,7 +1562,7 @@
|
|
|
1422
1562
|
}
|
|
1423
1563
|
}
|
|
1424
1564
|
for (const group of groups.values()) {
|
|
1425
|
-
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
|
|
1565
|
+
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
|
|
1426
1566
|
}
|
|
1427
1567
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1428
1568
|
}
|
|
@@ -1456,6 +1596,29 @@
|
|
|
1456
1596
|
};
|
|
1457
1597
|
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1458
1598
|
}
|
|
1599
|
+
function createSceneEvents(events, objects, activeEventId) {
|
|
1600
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1601
|
+
return events.map((event) => {
|
|
1602
|
+
const objectIds = [.../* @__PURE__ */ new Set([
|
|
1603
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
1604
|
+
...event.participantObjectIds
|
|
1605
|
+
])];
|
|
1606
|
+
const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
|
|
1607
|
+
const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
|
|
1608
|
+
const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
|
|
1609
|
+
return {
|
|
1610
|
+
renderId: `${createRenderId(event.id)}-event`,
|
|
1611
|
+
eventId: event.id,
|
|
1612
|
+
event,
|
|
1613
|
+
objectIds,
|
|
1614
|
+
participantIds: [...event.participantObjectIds],
|
|
1615
|
+
targetObjectId: event.targetObjectId,
|
|
1616
|
+
x: centroidX,
|
|
1617
|
+
y: centroidY,
|
|
1618
|
+
hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
|
|
1619
|
+
};
|
|
1620
|
+
}).sort((left, right) => left.event.id.localeCompare(right.event.id));
|
|
1621
|
+
}
|
|
1459
1622
|
function createSceneViewpoints(document, projection, preset, relationships, objectMap) {
|
|
1460
1623
|
const generatedOverview = createGeneratedOverviewViewpoint(document, projection, preset);
|
|
1461
1624
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1509,6 +1672,7 @@
|
|
|
1509
1672
|
summary: "Fit the whole system with the current atlas defaults.",
|
|
1510
1673
|
objectId: null,
|
|
1511
1674
|
selectedObjectId: null,
|
|
1675
|
+
eventIds: [],
|
|
1512
1676
|
projection,
|
|
1513
1677
|
preset,
|
|
1514
1678
|
rotationDeg: 0,
|
|
@@ -1545,6 +1709,9 @@
|
|
|
1545
1709
|
draft.select = normalizedValue;
|
|
1546
1710
|
}
|
|
1547
1711
|
return;
|
|
1712
|
+
case "events":
|
|
1713
|
+
draft.eventIds = splitListValue(normalizedValue);
|
|
1714
|
+
return;
|
|
1548
1715
|
case "projection":
|
|
1549
1716
|
case "view":
|
|
1550
1717
|
draft.projection = parseViewProjection(normalizedValue) ?? projection;
|
|
@@ -1601,6 +1768,7 @@
|
|
|
1601
1768
|
summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
|
|
1602
1769
|
objectId,
|
|
1603
1770
|
selectedObjectId,
|
|
1771
|
+
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
1604
1772
|
projection: draft.projection ?? projection,
|
|
1605
1773
|
preset: draft.preset ?? preset,
|
|
1606
1774
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
@@ -1658,7 +1826,7 @@
|
|
|
1658
1826
|
next["orbits-front"] = enabled;
|
|
1659
1827
|
continue;
|
|
1660
1828
|
}
|
|
1661
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1829
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1662
1830
|
next[rawLayer] = enabled;
|
|
1663
1831
|
}
|
|
1664
1832
|
}
|
|
@@ -1706,7 +1874,7 @@
|
|
|
1706
1874
|
}
|
|
1707
1875
|
return parts.join(" - ");
|
|
1708
1876
|
}
|
|
1709
|
-
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
|
|
1877
|
+
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
1710
1878
|
let minX = Number.POSITIVE_INFINITY;
|
|
1711
1879
|
let minY = Number.POSITIVE_INFINITY;
|
|
1712
1880
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -1736,7 +1904,7 @@
|
|
|
1736
1904
|
for (const label of labels) {
|
|
1737
1905
|
if (label.hidden)
|
|
1738
1906
|
continue;
|
|
1739
|
-
includeLabelBounds(label, include);
|
|
1907
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
1740
1908
|
}
|
|
1741
1909
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
1742
1910
|
return createBounds(0, 0, width, height);
|
|
@@ -1774,13 +1942,10 @@
|
|
|
1774
1942
|
include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
|
|
1775
1943
|
include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
|
|
1776
1944
|
}
|
|
1777
|
-
function includeLabelBounds(label, include) {
|
|
1778
|
-
const
|
|
1779
|
-
|
|
1780
|
-
include(
|
|
1781
|
-
include(label.x + labelHalfWidth, label.y + 8);
|
|
1782
|
-
include(label.x - labelHalfWidth, label.secondaryY - 14);
|
|
1783
|
-
include(label.x + labelHalfWidth, label.secondaryY + 8);
|
|
1945
|
+
function includeLabelBounds(label, include, labelMultiplier) {
|
|
1946
|
+
const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
|
|
1947
|
+
include(bounds.left, bounds.top);
|
|
1948
|
+
include(bounds.right, bounds.bottom);
|
|
1784
1949
|
}
|
|
1785
1950
|
function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
|
|
1786
1951
|
if (positions.has(object.id)) {
|
|
@@ -2170,7 +2335,7 @@
|
|
|
2170
2335
|
return null;
|
|
2171
2336
|
}
|
|
2172
2337
|
}
|
|
2173
|
-
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
|
|
2338
|
+
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2174
2339
|
let minX = Number.POSITIVE_INFINITY;
|
|
2175
2340
|
let minY = Number.POSITIVE_INFINITY;
|
|
2176
2341
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2199,7 +2364,7 @@
|
|
|
2199
2364
|
}
|
|
2200
2365
|
for (const label of labels) {
|
|
2201
2366
|
if (!label.hidden && group.labelIds.includes(label.objectId)) {
|
|
2202
|
-
includeLabelBounds(label, include);
|
|
2367
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2203
2368
|
}
|
|
2204
2369
|
}
|
|
2205
2370
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
@@ -2224,12 +2389,28 @@
|
|
|
2224
2389
|
}
|
|
2225
2390
|
return current.id;
|
|
2226
2391
|
}
|
|
2227
|
-
function createLabelRect(
|
|
2392
|
+
function createLabelRect(object, placement, labelMultiplier) {
|
|
2393
|
+
return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
|
|
2394
|
+
}
|
|
2395
|
+
function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
|
|
2396
|
+
const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
|
|
2397
|
+
const labelWidth = labelHalfWidth * 2;
|
|
2398
|
+
const topPadding = direction === "above" ? 18 : 12;
|
|
2399
|
+
const bottomPadding = direction === "above" ? 8 : 12;
|
|
2400
|
+
let left = x - labelHalfWidth;
|
|
2401
|
+
let right = x + labelHalfWidth;
|
|
2402
|
+
if (textAnchor === "start") {
|
|
2403
|
+
left = x;
|
|
2404
|
+
right = x + labelWidth;
|
|
2405
|
+
} else if (textAnchor === "end") {
|
|
2406
|
+
left = x - labelWidth;
|
|
2407
|
+
right = x;
|
|
2408
|
+
}
|
|
2228
2409
|
return {
|
|
2229
|
-
left
|
|
2230
|
-
right
|
|
2231
|
-
top: Math.min(labelY, secondaryY) -
|
|
2232
|
-
bottom: Math.max(labelY, secondaryY) +
|
|
2410
|
+
left,
|
|
2411
|
+
right,
|
|
2412
|
+
top: Math.min(labelY, secondaryY) - topPadding,
|
|
2413
|
+
bottom: Math.max(labelY, secondaryY) + bottomPadding
|
|
2233
2414
|
};
|
|
2234
2415
|
}
|
|
2235
2416
|
function rectsOverlap(left, right) {
|
|
@@ -2416,11 +2597,6 @@
|
|
|
2416
2597
|
function customColorFor(value) {
|
|
2417
2598
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2418
2599
|
}
|
|
2419
|
-
function estimateLabelHalfWidth(object, labelMultiplier) {
|
|
2420
|
-
const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
|
|
2421
|
-
const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
2422
|
-
return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
|
|
2423
|
-
}
|
|
2424
2600
|
function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
|
|
2425
2601
|
const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
|
|
2426
2602
|
const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
@@ -2460,6 +2636,7 @@
|
|
|
2460
2636
|
system,
|
|
2461
2637
|
groups: structuredClone(document.groups ?? []),
|
|
2462
2638
|
relations: structuredClone(document.relations ?? []),
|
|
2639
|
+
events: structuredClone(document.events ?? []),
|
|
2463
2640
|
objects: document.objects.map(cloneWorldOrbitObject),
|
|
2464
2641
|
diagnostics
|
|
2465
2642
|
};
|
|
@@ -2467,7 +2644,7 @@
|
|
|
2467
2644
|
function upgradeDocumentToDraftV2(document, options = {}) {
|
|
2468
2645
|
return convertAtlasDocumentToLegacyDraft(upgradeDocumentToV2(document, options));
|
|
2469
2646
|
}
|
|
2470
|
-
function materializeAtlasDocument(document) {
|
|
2647
|
+
function materializeAtlasDocument(document, options = {}) {
|
|
2471
2648
|
const system = document.system ? {
|
|
2472
2649
|
type: "system",
|
|
2473
2650
|
id: document.system.id,
|
|
@@ -2478,6 +2655,8 @@
|
|
|
2478
2655
|
properties: materializeDraftSystemProperties(document.system),
|
|
2479
2656
|
info: materializeDraftSystemInfo(document.system)
|
|
2480
2657
|
} : null;
|
|
2658
|
+
const objects = document.objects.map(cloneWorldOrbitObject);
|
|
2659
|
+
applyEventPoseOverrides(objects, document.events ?? [], options.activeEventId ?? null);
|
|
2481
2660
|
return {
|
|
2482
2661
|
format: "worldorbit",
|
|
2483
2662
|
version: "1.0",
|
|
@@ -2485,7 +2664,8 @@
|
|
|
2485
2664
|
system,
|
|
2486
2665
|
groups: structuredClone(document.groups ?? []),
|
|
2487
2666
|
relations: structuredClone(document.relations ?? []),
|
|
2488
|
-
|
|
2667
|
+
events: document.events.map(cloneWorldOrbitEvent),
|
|
2668
|
+
objects
|
|
2489
2669
|
};
|
|
2490
2670
|
}
|
|
2491
2671
|
function materializeDraftDocument(document) {
|
|
@@ -2613,6 +2793,7 @@
|
|
|
2613
2793
|
summary: viewpoint.summary,
|
|
2614
2794
|
focusObjectId: viewpoint.objectId,
|
|
2615
2795
|
selectedObjectId: viewpoint.selectedObjectId,
|
|
2796
|
+
events: [...viewpoint.eventIds],
|
|
2616
2797
|
projection: viewpoint.projection,
|
|
2617
2798
|
preset: viewpoint.preset,
|
|
2618
2799
|
zoom: viewpoint.scale,
|
|
@@ -2645,6 +2826,52 @@
|
|
|
2645
2826
|
info: { ...object.info }
|
|
2646
2827
|
};
|
|
2647
2828
|
}
|
|
2829
|
+
function cloneWorldOrbitEvent(event) {
|
|
2830
|
+
return {
|
|
2831
|
+
...event,
|
|
2832
|
+
participantObjectIds: [...event.participantObjectIds],
|
|
2833
|
+
tags: [...event.tags],
|
|
2834
|
+
positions: event.positions.map(cloneWorldOrbitEventPose)
|
|
2835
|
+
};
|
|
2836
|
+
}
|
|
2837
|
+
function cloneWorldOrbitEventPose(pose) {
|
|
2838
|
+
return {
|
|
2839
|
+
objectId: pose.objectId,
|
|
2840
|
+
placement: clonePlacement(pose.placement),
|
|
2841
|
+
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
2842
|
+
outer: pose.outer ? { ...pose.outer } : void 0
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
function clonePlacement(placement) {
|
|
2846
|
+
return placement ? structuredClone(placement) : null;
|
|
2847
|
+
}
|
|
2848
|
+
function applyEventPoseOverrides(objects, events, activeEventId) {
|
|
2849
|
+
if (!activeEventId) {
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
const event = events.find((entry) => entry.id === activeEventId);
|
|
2853
|
+
if (!event) {
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2856
|
+
const objectMap = new Map(objects.map((object) => [object.id, object]));
|
|
2857
|
+
for (const pose of event.positions) {
|
|
2858
|
+
const object = objectMap.get(pose.objectId);
|
|
2859
|
+
if (!object) {
|
|
2860
|
+
continue;
|
|
2861
|
+
}
|
|
2862
|
+
object.placement = clonePlacement(pose.placement);
|
|
2863
|
+
if (pose.inner) {
|
|
2864
|
+
object.properties.inner = { ...pose.inner };
|
|
2865
|
+
} else {
|
|
2866
|
+
delete object.properties.inner;
|
|
2867
|
+
}
|
|
2868
|
+
if (pose.outer) {
|
|
2869
|
+
object.properties.outer = { ...pose.outer };
|
|
2870
|
+
} else {
|
|
2871
|
+
delete object.properties.outer;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2648
2875
|
function cloneProperties(properties) {
|
|
2649
2876
|
const next = {};
|
|
2650
2877
|
for (const [key, value] of Object.entries(properties)) {
|
|
@@ -2742,6 +2969,9 @@
|
|
|
2742
2969
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2743
2970
|
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2744
2971
|
}
|
|
2972
|
+
if (viewpoint.events.length > 0) {
|
|
2973
|
+
info2[`${prefix}.events`] = viewpoint.events.join(" ");
|
|
2974
|
+
}
|
|
2745
2975
|
}
|
|
2746
2976
|
for (const annotation of system.annotations) {
|
|
2747
2977
|
const prefix = `annotation.${annotation.id}`;
|
|
@@ -2766,7 +2996,7 @@
|
|
|
2766
2996
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2767
2997
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2768
2998
|
}
|
|
2769
|
-
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
2999
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
2770
3000
|
if (layers[key] !== void 0) {
|
|
2771
3001
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2772
3002
|
}
|
|
@@ -2870,6 +3100,10 @@
|
|
|
2870
3100
|
lines.push("");
|
|
2871
3101
|
lines.push(...formatAtlasRelation(relation));
|
|
2872
3102
|
}
|
|
3103
|
+
for (const event of [...document.events].sort(compareIdLike)) {
|
|
3104
|
+
lines.push("");
|
|
3105
|
+
lines.push(...formatAtlasEvent(event));
|
|
3106
|
+
}
|
|
2873
3107
|
const sortedObjects = [...document.objects].sort(compareObjects);
|
|
2874
3108
|
if (sortedObjects.length > 0 && lines.at(-1) !== "") {
|
|
2875
3109
|
lines.push("");
|
|
@@ -2900,6 +3134,10 @@
|
|
|
2900
3134
|
lines.push("");
|
|
2901
3135
|
lines.push(...formatAtlasRelation(relation));
|
|
2902
3136
|
}
|
|
3137
|
+
for (const event of [...legacy.events].sort(compareIdLike)) {
|
|
3138
|
+
lines.push("");
|
|
3139
|
+
lines.push(...formatAtlasEvent(event));
|
|
3140
|
+
}
|
|
2903
3141
|
const sortedObjects = [...legacy.objects].sort(compareObjects);
|
|
2904
3142
|
if (sortedObjects.length > 0 && lines.at(-1) !== "") {
|
|
2905
3143
|
lines.push("");
|
|
@@ -3111,6 +3349,9 @@
|
|
|
3111
3349
|
if (layerTokens.length > 0) {
|
|
3112
3350
|
lines.push(` layers ${layerTokens.join(" ")}`);
|
|
3113
3351
|
}
|
|
3352
|
+
if (viewpoint.events.length > 0) {
|
|
3353
|
+
lines.push(` events ${viewpoint.events.join(" ")}`);
|
|
3354
|
+
}
|
|
3114
3355
|
if (viewpoint.filter) {
|
|
3115
3356
|
lines.push(" filter");
|
|
3116
3357
|
if (viewpoint.filter.query) {
|
|
@@ -3183,6 +3424,54 @@
|
|
|
3183
3424
|
}
|
|
3184
3425
|
return lines;
|
|
3185
3426
|
}
|
|
3427
|
+
function formatAtlasEvent(event) {
|
|
3428
|
+
const lines = [`event ${event.id}`, ` kind ${quoteIfNeeded(event.kind)}`];
|
|
3429
|
+
if (event.label) {
|
|
3430
|
+
lines.push(` label ${quoteIfNeeded(event.label)}`);
|
|
3431
|
+
}
|
|
3432
|
+
if (event.summary) {
|
|
3433
|
+
lines.push(` summary ${quoteIfNeeded(event.summary)}`);
|
|
3434
|
+
}
|
|
3435
|
+
if (event.targetObjectId) {
|
|
3436
|
+
lines.push(` target ${event.targetObjectId}`);
|
|
3437
|
+
}
|
|
3438
|
+
if (event.participantObjectIds.length > 0) {
|
|
3439
|
+
lines.push(` participants ${event.participantObjectIds.join(" ")}`);
|
|
3440
|
+
}
|
|
3441
|
+
if (event.timing) {
|
|
3442
|
+
lines.push(` timing ${quoteIfNeeded(event.timing)}`);
|
|
3443
|
+
}
|
|
3444
|
+
if (event.visibility) {
|
|
3445
|
+
lines.push(` visibility ${quoteIfNeeded(event.visibility)}`);
|
|
3446
|
+
}
|
|
3447
|
+
if (event.tags.length > 0) {
|
|
3448
|
+
lines.push(` tags ${event.tags.map(quoteIfNeeded).join(" ")}`);
|
|
3449
|
+
}
|
|
3450
|
+
if (event.color) {
|
|
3451
|
+
lines.push(` color ${quoteIfNeeded(event.color)}`);
|
|
3452
|
+
}
|
|
3453
|
+
if (event.hidden) {
|
|
3454
|
+
lines.push(" hidden true");
|
|
3455
|
+
}
|
|
3456
|
+
if (event.positions.length > 0) {
|
|
3457
|
+
lines.push("");
|
|
3458
|
+
lines.push(" positions");
|
|
3459
|
+
for (const pose of [...event.positions].sort(comparePoseObjectId)) {
|
|
3460
|
+
lines.push(` pose ${pose.objectId}`);
|
|
3461
|
+
for (const fieldLine of formatEventPoseFields(pose)) {
|
|
3462
|
+
lines.push(` ${fieldLine}`);
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
return lines;
|
|
3467
|
+
}
|
|
3468
|
+
function formatEventPoseFields(pose) {
|
|
3469
|
+
return [
|
|
3470
|
+
...formatPlacement(pose.placement),
|
|
3471
|
+
...formatOptionalUnit("inner", pose.inner),
|
|
3472
|
+
...formatOptionalUnit("outer", pose.outer)
|
|
3473
|
+
];
|
|
3474
|
+
}
|
|
3186
3475
|
function formatValue(value) {
|
|
3187
3476
|
if (Array.isArray(value)) {
|
|
3188
3477
|
return value.map((item) => quoteIfNeeded(item)).join(" ");
|
|
@@ -3224,7 +3513,7 @@
|
|
|
3224
3513
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
3225
3514
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
3226
3515
|
}
|
|
3227
|
-
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
3516
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
3228
3517
|
if (layers[key] !== void 0) {
|
|
3229
3518
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
3230
3519
|
}
|
|
@@ -3252,6 +3541,9 @@
|
|
|
3252
3541
|
function compareIdLike(left, right) {
|
|
3253
3542
|
return left.id.localeCompare(right.id);
|
|
3254
3543
|
}
|
|
3544
|
+
function comparePoseObjectId(left, right) {
|
|
3545
|
+
return left.objectId.localeCompare(right.objectId);
|
|
3546
|
+
}
|
|
3255
3547
|
function objectTypeIndex(objectType) {
|
|
3256
3548
|
switch (objectType) {
|
|
3257
3549
|
case "star":
|
|
@@ -3447,6 +3739,7 @@
|
|
|
3447
3739
|
const diagnostics = [];
|
|
3448
3740
|
const objectMap = new Map(document.objects.map((object) => [object.id, object]));
|
|
3449
3741
|
const groupIds = new Set(document.groups.map((group) => group.id));
|
|
3742
|
+
const eventIds = new Set(document.events.map((event) => event.id));
|
|
3450
3743
|
if (!document.system) {
|
|
3451
3744
|
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
3452
3745
|
}
|
|
@@ -3456,6 +3749,7 @@
|
|
|
3456
3749
|
["viewpoint", document.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
3457
3750
|
["annotation", document.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
3458
3751
|
["relation", document.relations.map((relation) => relation.id)],
|
|
3752
|
+
["event", document.events.map((event) => event.id)],
|
|
3459
3753
|
["object", document.objects.map((object) => object.id)]
|
|
3460
3754
|
]) {
|
|
3461
3755
|
for (const id of ids) {
|
|
@@ -3471,11 +3765,14 @@
|
|
|
3471
3765
|
validateRelation(relation, objectMap, diagnostics);
|
|
3472
3766
|
}
|
|
3473
3767
|
for (const viewpoint of document.system?.viewpoints ?? []) {
|
|
3474
|
-
|
|
3768
|
+
validateViewpoint(viewpoint.filter, viewpoint.events ?? [], groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpoint.id);
|
|
3475
3769
|
}
|
|
3476
3770
|
for (const object of document.objects) {
|
|
3477
3771
|
validateObject(object, document.system, objectMap, groupIds, diagnostics);
|
|
3478
3772
|
}
|
|
3773
|
+
for (const event of document.events) {
|
|
3774
|
+
validateEvent(event, objectMap, diagnostics);
|
|
3775
|
+
}
|
|
3479
3776
|
return diagnostics;
|
|
3480
3777
|
}
|
|
3481
3778
|
function validateRelation(relation, objectMap, diagnostics) {
|
|
@@ -3493,13 +3790,19 @@
|
|
|
3493
3790
|
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
3494
3791
|
}
|
|
3495
3792
|
}
|
|
3496
|
-
function
|
|
3497
|
-
if (
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3793
|
+
function validateViewpoint(filter, eventRefs, groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpointId) {
|
|
3794
|
+
if (sourceSchemaVersion === "2.1") {
|
|
3795
|
+
if (filter) {
|
|
3796
|
+
for (const groupId of filter.groupIds) {
|
|
3797
|
+
if (!groupIds.has(groupId)) {
|
|
3798
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.groups`));
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
for (const eventId of eventRefs) {
|
|
3803
|
+
if (!eventIds.has(eventId)) {
|
|
3804
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.events`));
|
|
3805
|
+
}
|
|
3503
3806
|
}
|
|
3504
3807
|
}
|
|
3505
3808
|
}
|
|
@@ -3585,6 +3888,103 @@
|
|
|
3585
3888
|
}
|
|
3586
3889
|
}
|
|
3587
3890
|
}
|
|
3891
|
+
function validateEvent(event, objectMap, diagnostics) {
|
|
3892
|
+
const fieldPrefix = `event.${event.id}`;
|
|
3893
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
3894
|
+
if (!event.kind.trim()) {
|
|
3895
|
+
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
3896
|
+
}
|
|
3897
|
+
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3898
|
+
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3899
|
+
}
|
|
3900
|
+
if (event.targetObjectId) {
|
|
3901
|
+
referencedIds.add(event.targetObjectId);
|
|
3902
|
+
if (!objectMap.has(event.targetObjectId)) {
|
|
3903
|
+
diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
const seenParticipants = /* @__PURE__ */ new Set();
|
|
3907
|
+
for (const participantId of event.participantObjectIds) {
|
|
3908
|
+
referencedIds.add(participantId);
|
|
3909
|
+
if (seenParticipants.has(participantId)) {
|
|
3910
|
+
diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
|
|
3911
|
+
continue;
|
|
3912
|
+
}
|
|
3913
|
+
seenParticipants.add(participantId);
|
|
3914
|
+
if (!objectMap.has(participantId)) {
|
|
3915
|
+
diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
|
|
3919
|
+
diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
|
|
3920
|
+
}
|
|
3921
|
+
if (event.positions.length === 0) {
|
|
3922
|
+
diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
|
|
3923
|
+
}
|
|
3924
|
+
if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
|
|
3925
|
+
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`));
|
|
3926
|
+
}
|
|
3927
|
+
const poseIds = /* @__PURE__ */ new Set();
|
|
3928
|
+
for (const pose of event.positions) {
|
|
3929
|
+
const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
|
|
3930
|
+
if (poseIds.has(pose.objectId)) {
|
|
3931
|
+
diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
|
|
3932
|
+
continue;
|
|
3933
|
+
}
|
|
3934
|
+
poseIds.add(pose.objectId);
|
|
3935
|
+
const object = objectMap.get(pose.objectId);
|
|
3936
|
+
if (!object) {
|
|
3937
|
+
diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
|
|
3938
|
+
continue;
|
|
3939
|
+
}
|
|
3940
|
+
if (!referencedIds.has(pose.objectId)) {
|
|
3941
|
+
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
3942
|
+
}
|
|
3943
|
+
validateEventPose(pose, object, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
function validateEventPose(pose, object, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3947
|
+
const placement = pose.placement;
|
|
3948
|
+
if (!placement) {
|
|
3949
|
+
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
3950
|
+
return;
|
|
3951
|
+
}
|
|
3952
|
+
if (placement.mode === "orbit") {
|
|
3953
|
+
if (!objectMap.has(placement.target)) {
|
|
3954
|
+
diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
|
|
3955
|
+
}
|
|
3956
|
+
if (placement.distance && placement.semiMajor) {
|
|
3957
|
+
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
3958
|
+
}
|
|
3959
|
+
return;
|
|
3960
|
+
}
|
|
3961
|
+
if (placement.mode === "surface") {
|
|
3962
|
+
const target = objectMap.get(placement.target);
|
|
3963
|
+
if (!target) {
|
|
3964
|
+
diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
|
|
3965
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3966
|
+
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`));
|
|
3967
|
+
}
|
|
3968
|
+
return;
|
|
3969
|
+
}
|
|
3970
|
+
if (placement.mode === "at") {
|
|
3971
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3972
|
+
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`));
|
|
3973
|
+
}
|
|
3974
|
+
const reference = placement.reference;
|
|
3975
|
+
if (reference.kind === "named" && !objectMap.has(reference.name)) {
|
|
3976
|
+
diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3977
|
+
} else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
|
|
3978
|
+
diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3979
|
+
} else if (reference.kind === "lagrange") {
|
|
3980
|
+
if (!objectMap.has(reference.primary)) {
|
|
3981
|
+
diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3982
|
+
} else if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3983
|
+
diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3588
3988
|
function validateAtTarget(object, objectMap, diagnostics) {
|
|
3589
3989
|
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
3590
3990
|
if (!reference) {
|
|
@@ -3785,6 +4185,21 @@
|
|
|
3785
4185
|
});
|
|
3786
4186
|
}
|
|
3787
4187
|
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
4188
|
+
var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
4189
|
+
"orbit",
|
|
4190
|
+
"distance",
|
|
4191
|
+
"semiMajor",
|
|
4192
|
+
"eccentricity",
|
|
4193
|
+
"period",
|
|
4194
|
+
"angle",
|
|
4195
|
+
"inclination",
|
|
4196
|
+
"phase",
|
|
4197
|
+
"at",
|
|
4198
|
+
"surface",
|
|
4199
|
+
"free",
|
|
4200
|
+
"inner",
|
|
4201
|
+
"outer"
|
|
4202
|
+
]);
|
|
3788
4203
|
function parseWorldOrbitAtlas(source) {
|
|
3789
4204
|
return parseAtlasSource(source);
|
|
3790
4205
|
}
|
|
@@ -3802,12 +4217,15 @@
|
|
|
3802
4217
|
const objectNodes = [];
|
|
3803
4218
|
const groups = [];
|
|
3804
4219
|
const relations = [];
|
|
4220
|
+
const events = [];
|
|
4221
|
+
const eventPoseNodes = /* @__PURE__ */ new Map();
|
|
3805
4222
|
let sawDefaults = false;
|
|
3806
4223
|
let sawAtlas = false;
|
|
3807
4224
|
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3808
4225
|
const annotationIds = /* @__PURE__ */ new Set();
|
|
3809
4226
|
const groupIds = /* @__PURE__ */ new Set();
|
|
3810
4227
|
const relationIds = /* @__PURE__ */ new Set();
|
|
4228
|
+
const eventIds = /* @__PURE__ */ new Set();
|
|
3811
4229
|
for (let index = 0; index < lines.length; index++) {
|
|
3812
4230
|
const rawLine = lines[index];
|
|
3813
4231
|
const lineNumber = index + 1;
|
|
@@ -3838,7 +4256,7 @@
|
|
|
3838
4256
|
continue;
|
|
3839
4257
|
}
|
|
3840
4258
|
if (indent === 0) {
|
|
3841
|
-
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
4259
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
3842
4260
|
if (section.kind === "system") {
|
|
3843
4261
|
system = section.system;
|
|
3844
4262
|
} else if (section.kind === "defaults") {
|
|
@@ -3857,6 +4275,7 @@
|
|
|
3857
4275
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3858
4276
|
}
|
|
3859
4277
|
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
4278
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
3860
4279
|
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3861
4280
|
const baseDocument = {
|
|
3862
4281
|
format: "worldorbit",
|
|
@@ -3864,6 +4283,7 @@
|
|
|
3864
4283
|
system,
|
|
3865
4284
|
groups,
|
|
3866
4285
|
relations,
|
|
4286
|
+
events: normalizedEvents,
|
|
3867
4287
|
objects,
|
|
3868
4288
|
diagnostics
|
|
3869
4289
|
};
|
|
@@ -3899,7 +4319,7 @@
|
|
|
3899
4319
|
const version = tokens[1].value.toLowerCase();
|
|
3900
4320
|
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3901
4321
|
}
|
|
3902
|
-
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
4322
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3903
4323
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
3904
4324
|
switch (keyword) {
|
|
3905
4325
|
case "system":
|
|
@@ -3936,7 +4356,7 @@
|
|
|
3936
4356
|
if (!system) {
|
|
3937
4357
|
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
3938
4358
|
}
|
|
3939
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
4359
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
3940
4360
|
case "annotation":
|
|
3941
4361
|
if (!system) {
|
|
3942
4362
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -3948,6 +4368,9 @@
|
|
|
3948
4368
|
case "relation":
|
|
3949
4369
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
3950
4370
|
return startRelationSection(tokens, line, relations, relationIds);
|
|
4371
|
+
case "event":
|
|
4372
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
4373
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
3951
4374
|
case "object":
|
|
3952
4375
|
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3953
4376
|
default:
|
|
@@ -3984,7 +4407,7 @@
|
|
|
3984
4407
|
seenFields: /* @__PURE__ */ new Set()
|
|
3985
4408
|
};
|
|
3986
4409
|
}
|
|
3987
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
4410
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
3988
4411
|
if (tokens.length !== 2) {
|
|
3989
4412
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
3990
4413
|
}
|
|
@@ -4001,6 +4424,7 @@
|
|
|
4001
4424
|
summary: "",
|
|
4002
4425
|
focusObjectId: null,
|
|
4003
4426
|
selectedObjectId: null,
|
|
4427
|
+
events: [],
|
|
4004
4428
|
projection: system.defaults.view,
|
|
4005
4429
|
preset: system.defaults.preset,
|
|
4006
4430
|
zoom: null,
|
|
@@ -4013,6 +4437,8 @@
|
|
|
4013
4437
|
return {
|
|
4014
4438
|
kind: "viewpoint",
|
|
4015
4439
|
viewpoint,
|
|
4440
|
+
sourceSchemaVersion,
|
|
4441
|
+
diagnostics,
|
|
4016
4442
|
seenFields: /* @__PURE__ */ new Set(),
|
|
4017
4443
|
inFilter: false,
|
|
4018
4444
|
filterIndent: null,
|
|
@@ -4103,6 +4529,49 @@
|
|
|
4103
4529
|
seenFields: /* @__PURE__ */ new Set()
|
|
4104
4530
|
};
|
|
4105
4531
|
}
|
|
4532
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
4533
|
+
if (tokens.length !== 2) {
|
|
4534
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
4535
|
+
}
|
|
4536
|
+
const id = normalizeIdentifier2(tokens[1].value);
|
|
4537
|
+
if (!id) {
|
|
4538
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
4539
|
+
}
|
|
4540
|
+
if (eventIds.has(id)) {
|
|
4541
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
4542
|
+
}
|
|
4543
|
+
const event = {
|
|
4544
|
+
id,
|
|
4545
|
+
kind: "",
|
|
4546
|
+
label: humanizeIdentifier3(id),
|
|
4547
|
+
summary: null,
|
|
4548
|
+
targetObjectId: null,
|
|
4549
|
+
participantObjectIds: [],
|
|
4550
|
+
timing: null,
|
|
4551
|
+
visibility: null,
|
|
4552
|
+
tags: [],
|
|
4553
|
+
color: null,
|
|
4554
|
+
hidden: false,
|
|
4555
|
+
positions: []
|
|
4556
|
+
};
|
|
4557
|
+
const rawPoses = [];
|
|
4558
|
+
events.push(event);
|
|
4559
|
+
eventPoseNodes.set(id, rawPoses);
|
|
4560
|
+
eventIds.add(id);
|
|
4561
|
+
return {
|
|
4562
|
+
kind: "event",
|
|
4563
|
+
event,
|
|
4564
|
+
sourceSchemaVersion,
|
|
4565
|
+
diagnostics,
|
|
4566
|
+
seenFields: /* @__PURE__ */ new Set(),
|
|
4567
|
+
rawPoses,
|
|
4568
|
+
inPositions: false,
|
|
4569
|
+
positionsIndent: null,
|
|
4570
|
+
activePose: null,
|
|
4571
|
+
poseIndent: null,
|
|
4572
|
+
activePoseSeenFields: /* @__PURE__ */ new Set()
|
|
4573
|
+
};
|
|
4574
|
+
}
|
|
4106
4575
|
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
4107
4576
|
if (tokens.length < 3) {
|
|
4108
4577
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
@@ -4159,6 +4628,9 @@
|
|
|
4159
4628
|
case "relation":
|
|
4160
4629
|
applyRelationField(section, tokens, line);
|
|
4161
4630
|
return;
|
|
4631
|
+
case "event":
|
|
4632
|
+
applyEventField(section, indent, tokens, line);
|
|
4633
|
+
return;
|
|
4162
4634
|
case "object":
|
|
4163
4635
|
applyObjectField(section, indent, tokens, line);
|
|
4164
4636
|
return;
|
|
@@ -4285,7 +4757,14 @@
|
|
|
4285
4757
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
4286
4758
|
return;
|
|
4287
4759
|
case "layers":
|
|
4288
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
4760
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
4761
|
+
return;
|
|
4762
|
+
case "events":
|
|
4763
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
4764
|
+
line,
|
|
4765
|
+
column: tokens[0].column
|
|
4766
|
+
});
|
|
4767
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
4289
4768
|
return;
|
|
4290
4769
|
default:
|
|
4291
4770
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
@@ -4390,6 +4869,106 @@
|
|
|
4390
4869
|
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4391
4870
|
}
|
|
4392
4871
|
}
|
|
4872
|
+
function applyEventField(section, indent, tokens, line) {
|
|
4873
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
4874
|
+
section.activePose = null;
|
|
4875
|
+
section.poseIndent = null;
|
|
4876
|
+
section.activePoseSeenFields.clear();
|
|
4877
|
+
}
|
|
4878
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
4879
|
+
section.inPositions = false;
|
|
4880
|
+
section.positionsIndent = null;
|
|
4881
|
+
}
|
|
4882
|
+
if (section.activePose) {
|
|
4883
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4884
|
+
return;
|
|
4885
|
+
}
|
|
4886
|
+
if (section.inPositions) {
|
|
4887
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
4888
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
4889
|
+
}
|
|
4890
|
+
const objectId = tokens[1].value;
|
|
4891
|
+
if (!objectId.trim()) {
|
|
4892
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
4893
|
+
}
|
|
4894
|
+
const rawPose = {
|
|
4895
|
+
objectId,
|
|
4896
|
+
fields: [],
|
|
4897
|
+
location: { line, column: tokens[0].column }
|
|
4898
|
+
};
|
|
4899
|
+
section.rawPoses.push(rawPose);
|
|
4900
|
+
section.activePose = rawPose;
|
|
4901
|
+
section.poseIndent = indent;
|
|
4902
|
+
section.activePoseSeenFields = /* @__PURE__ */ new Set();
|
|
4903
|
+
return;
|
|
4904
|
+
}
|
|
4905
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
4906
|
+
if (section.seenFields.has("positions")) {
|
|
4907
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
4908
|
+
}
|
|
4909
|
+
section.seenFields.add("positions");
|
|
4910
|
+
section.inPositions = true;
|
|
4911
|
+
section.positionsIndent = indent;
|
|
4912
|
+
return;
|
|
4913
|
+
}
|
|
4914
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4915
|
+
switch (key) {
|
|
4916
|
+
case "kind":
|
|
4917
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
4918
|
+
return;
|
|
4919
|
+
case "label":
|
|
4920
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
4921
|
+
return;
|
|
4922
|
+
case "summary":
|
|
4923
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
4924
|
+
return;
|
|
4925
|
+
case "target":
|
|
4926
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
4927
|
+
return;
|
|
4928
|
+
case "participants":
|
|
4929
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
4930
|
+
return;
|
|
4931
|
+
case "timing":
|
|
4932
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
4933
|
+
return;
|
|
4934
|
+
case "visibility":
|
|
4935
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
4936
|
+
return;
|
|
4937
|
+
case "tags":
|
|
4938
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4939
|
+
return;
|
|
4940
|
+
case "color":
|
|
4941
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
4942
|
+
return;
|
|
4943
|
+
case "hidden":
|
|
4944
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4945
|
+
line,
|
|
4946
|
+
column: tokens[0].column
|
|
4947
|
+
});
|
|
4948
|
+
return;
|
|
4949
|
+
default:
|
|
4950
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4951
|
+
}
|
|
4952
|
+
}
|
|
4953
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
4954
|
+
if (tokens.length < 2) {
|
|
4955
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
4956
|
+
}
|
|
4957
|
+
const key = tokens[0].value;
|
|
4958
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
4959
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
4960
|
+
}
|
|
4961
|
+
if (seenFields.has(key)) {
|
|
4962
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
4963
|
+
}
|
|
4964
|
+
seenFields.add(key);
|
|
4965
|
+
return {
|
|
4966
|
+
type: "field",
|
|
4967
|
+
key,
|
|
4968
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
4969
|
+
location: { line, column: tokens[0].column }
|
|
4970
|
+
};
|
|
4971
|
+
}
|
|
4393
4972
|
function applyObjectField(section, indent, tokens, line) {
|
|
4394
4973
|
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
4395
4974
|
section.activeBlock = null;
|
|
@@ -4448,7 +5027,7 @@
|
|
|
4448
5027
|
function parseObjectTypeTokens(tokens, line) {
|
|
4449
5028
|
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");
|
|
4450
5029
|
}
|
|
4451
|
-
function parseLayerTokens(tokens, line) {
|
|
5030
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
4452
5031
|
const layers = {};
|
|
4453
5032
|
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
4454
5033
|
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
@@ -4458,7 +5037,13 @@
|
|
|
4458
5037
|
layers["orbits-front"] = enabled;
|
|
4459
5038
|
continue;
|
|
4460
5039
|
}
|
|
4461
|
-
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
5040
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
5041
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
5042
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
5043
|
+
line,
|
|
5044
|
+
column: tokens[0]?.column ?? 1
|
|
5045
|
+
});
|
|
5046
|
+
}
|
|
4462
5047
|
layers[raw] = enabled;
|
|
4463
5048
|
}
|
|
4464
5049
|
}
|
|
@@ -4597,7 +5182,7 @@
|
|
|
4597
5182
|
}
|
|
4598
5183
|
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
4599
5184
|
const fieldMap = collectDraftFields(node.fields);
|
|
4600
|
-
const placement =
|
|
5185
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4601
5186
|
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
4602
5187
|
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
4603
5188
|
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
@@ -4649,6 +5234,24 @@
|
|
|
4649
5234
|
}
|
|
4650
5235
|
return object;
|
|
4651
5236
|
}
|
|
5237
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
5238
|
+
return {
|
|
5239
|
+
...event,
|
|
5240
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
5241
|
+
tags: [...new Set(event.tags)],
|
|
5242
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
|
|
5243
|
+
};
|
|
5244
|
+
}
|
|
5245
|
+
function normalizeDraftEventPose(rawPose) {
|
|
5246
|
+
const fieldMap = collectDraftFields(rawPose.fields);
|
|
5247
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
5248
|
+
return {
|
|
5249
|
+
objectId: rawPose.objectId,
|
|
5250
|
+
placement,
|
|
5251
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
5252
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer")
|
|
5253
|
+
};
|
|
5254
|
+
}
|
|
4652
5255
|
function collectDraftFields(fields) {
|
|
4653
5256
|
const grouped = /* @__PURE__ */ new Map();
|
|
4654
5257
|
for (const field of fields) {
|
|
@@ -4665,7 +5268,7 @@
|
|
|
4665
5268
|
}
|
|
4666
5269
|
return grouped;
|
|
4667
5270
|
}
|
|
4668
|
-
function
|
|
5271
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
4669
5272
|
const orbitField = fieldMap.get("orbit")?.[0];
|
|
4670
5273
|
const atField = fieldMap.get("at")?.[0];
|
|
4671
5274
|
const surfaceField = fieldMap.get("surface")?.[0];
|
|
@@ -4958,6 +5561,7 @@
|
|
|
4958
5561
|
},
|
|
4959
5562
|
groups: [],
|
|
4960
5563
|
relations: [],
|
|
5564
|
+
events: [],
|
|
4961
5565
|
objects: [],
|
|
4962
5566
|
diagnostics: []
|
|
4963
5567
|
};
|
|
@@ -4984,6 +5588,12 @@
|
|
|
4984
5588
|
for (const relation of [...document.relations].sort(compareIdLike2)) {
|
|
4985
5589
|
paths.push({ kind: "relation", id: relation.id });
|
|
4986
5590
|
}
|
|
5591
|
+
for (const event of [...document.events].sort(compareIdLike2)) {
|
|
5592
|
+
paths.push({ kind: "event", id: event.id });
|
|
5593
|
+
for (const pose of [...event.positions].sort(comparePoseObjectId2)) {
|
|
5594
|
+
paths.push({ kind: "event-pose", id: event.id, key: pose.objectId });
|
|
5595
|
+
}
|
|
5596
|
+
}
|
|
4987
5597
|
for (const object of [...document.objects].sort(compareIdLike2)) {
|
|
4988
5598
|
paths.push({ kind: "object", id: object.id });
|
|
4989
5599
|
}
|
|
@@ -4999,6 +5609,10 @@
|
|
|
4999
5609
|
return path.key ? document.system?.atlasMetadata[path.key] ?? null : null;
|
|
5000
5610
|
case "group":
|
|
5001
5611
|
return path.id ? findGroup(document, path.id) : null;
|
|
5612
|
+
case "event":
|
|
5613
|
+
return path.id ? findEvent(document, path.id) : null;
|
|
5614
|
+
case "event-pose":
|
|
5615
|
+
return path.id && path.key ? findEventPose(document, path.id, path.key) : null;
|
|
5002
5616
|
case "object":
|
|
5003
5617
|
return path.id ? findObject(document, path.id) : null;
|
|
5004
5618
|
case "viewpoint":
|
|
@@ -5038,6 +5652,18 @@
|
|
|
5038
5652
|
}
|
|
5039
5653
|
upsertById(next.groups, value);
|
|
5040
5654
|
return next;
|
|
5655
|
+
case "event":
|
|
5656
|
+
if (!path.id) {
|
|
5657
|
+
throw new Error('Event updates require an "id" value.');
|
|
5658
|
+
}
|
|
5659
|
+
upsertById(next.events, value);
|
|
5660
|
+
return next;
|
|
5661
|
+
case "event-pose":
|
|
5662
|
+
if (!path.id || !path.key) {
|
|
5663
|
+
throw new Error('Event pose updates require an event "id" and pose "key" value.');
|
|
5664
|
+
}
|
|
5665
|
+
upsertEventPose(next.events, path.id, value);
|
|
5666
|
+
return next;
|
|
5041
5667
|
case "object":
|
|
5042
5668
|
if (!path.id) {
|
|
5043
5669
|
throw new Error('Object updates require an "id" value.');
|
|
@@ -5086,6 +5712,19 @@
|
|
|
5086
5712
|
next.groups = next.groups.filter((group) => group.id !== path.id);
|
|
5087
5713
|
}
|
|
5088
5714
|
return next;
|
|
5715
|
+
case "event":
|
|
5716
|
+
if (path.id) {
|
|
5717
|
+
next.events = next.events.filter((event) => event.id !== path.id);
|
|
5718
|
+
}
|
|
5719
|
+
return next;
|
|
5720
|
+
case "event-pose":
|
|
5721
|
+
if (path.id && path.key) {
|
|
5722
|
+
const event = findEvent(next, path.id);
|
|
5723
|
+
if (event) {
|
|
5724
|
+
event.positions = event.positions.filter((pose) => pose.objectId !== path.key);
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
5727
|
+
return next;
|
|
5089
5728
|
case "viewpoint":
|
|
5090
5729
|
if (path.id) {
|
|
5091
5730
|
system.viewpoints = system.viewpoints.filter((viewpoint) => viewpoint.id !== path.id);
|
|
@@ -5154,6 +5793,22 @@
|
|
|
5154
5793
|
};
|
|
5155
5794
|
}
|
|
5156
5795
|
}
|
|
5796
|
+
if (diagnostic.field?.startsWith("event.")) {
|
|
5797
|
+
const parts = diagnostic.field.split(".");
|
|
5798
|
+
if (parts[1] && findEvent(document, parts[1])) {
|
|
5799
|
+
if (parts[2] === "pose" && parts[3] && findEventPose(document, parts[1], parts[3])) {
|
|
5800
|
+
return {
|
|
5801
|
+
kind: "event-pose",
|
|
5802
|
+
id: parts[1],
|
|
5803
|
+
key: parts[3]
|
|
5804
|
+
};
|
|
5805
|
+
}
|
|
5806
|
+
return {
|
|
5807
|
+
kind: "event",
|
|
5808
|
+
id: parts[1]
|
|
5809
|
+
};
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5157
5812
|
if (diagnostic.field && diagnostic.field in ensureSystem(document).atlasMetadata) {
|
|
5158
5813
|
return {
|
|
5159
5814
|
kind: "metadata",
|
|
@@ -5185,6 +5840,12 @@
|
|
|
5185
5840
|
function findRelation(document, relationId) {
|
|
5186
5841
|
return document.relations.find((relation) => relation.id === relationId) ?? null;
|
|
5187
5842
|
}
|
|
5843
|
+
function findEvent(document, eventId) {
|
|
5844
|
+
return document.events.find((event) => event.id === eventId) ?? null;
|
|
5845
|
+
}
|
|
5846
|
+
function findEventPose(document, eventId, objectId) {
|
|
5847
|
+
return findEvent(document, eventId)?.positions.find((pose) => pose.objectId === objectId) ?? null;
|
|
5848
|
+
}
|
|
5188
5849
|
function findViewpoint(system, viewpointId) {
|
|
5189
5850
|
return system?.viewpoints.find((viewpoint) => viewpoint.id === viewpointId) ?? null;
|
|
5190
5851
|
}
|
|
@@ -5200,9 +5861,25 @@
|
|
|
5200
5861
|
}
|
|
5201
5862
|
items[index] = value;
|
|
5202
5863
|
}
|
|
5864
|
+
function upsertEventPose(events, eventId, value) {
|
|
5865
|
+
const event = events.find((entry) => entry.id === eventId);
|
|
5866
|
+
if (!event) {
|
|
5867
|
+
throw new Error(`Unknown event "${eventId}" for pose update.`);
|
|
5868
|
+
}
|
|
5869
|
+
const index = event.positions.findIndex((entry) => entry.objectId === value.objectId);
|
|
5870
|
+
if (index === -1) {
|
|
5871
|
+
event.positions.push(value);
|
|
5872
|
+
event.positions.sort(comparePoseObjectId2);
|
|
5873
|
+
return;
|
|
5874
|
+
}
|
|
5875
|
+
event.positions[index] = value;
|
|
5876
|
+
}
|
|
5203
5877
|
function compareIdLike2(left, right) {
|
|
5204
5878
|
return left.id.localeCompare(right.id);
|
|
5205
5879
|
}
|
|
5880
|
+
function comparePoseObjectId2(left, right) {
|
|
5881
|
+
return left.objectId.localeCompare(right.objectId);
|
|
5882
|
+
}
|
|
5206
5883
|
|
|
5207
5884
|
// packages/core/dist/load.js
|
|
5208
5885
|
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|