worldorbit 2.5.13 → 2.5.16
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 +37 -11
- package/dist/browser/core/dist/index.js +1811 -386
- package/dist/browser/editor/dist/index.js +10534 -0
- package/dist/browser/markdown/dist/index.js +1477 -221
- package/dist/browser/viewer/dist/index.js +1569 -230
- package/dist/unpkg/core/dist/index.js +1814 -389
- package/dist/unpkg/editor/dist/index.js +10559 -0
- package/dist/unpkg/markdown/dist/index.js +1480 -224
- package/dist/unpkg/viewer/dist/index.js +1572 -233
- package/dist/unpkg/worldorbit-core.min.js +12 -5
- package/dist/unpkg/worldorbit-editor.min.js +812 -0
- package/dist/unpkg/worldorbit-markdown.min.js +32 -23
- package/dist/unpkg/worldorbit-viewer.min.js +55 -41
- package/dist/unpkg/worldorbit.js +1713 -231
- package/dist/unpkg/worldorbit.min.js +58 -44
- package/package.json +3 -2
- package/packages/core/README.md +5 -1
- package/packages/core/dist/atlas-edit.d.ts +2 -2
- package/packages/core/dist/atlas-edit.js +70 -7
- package/packages/core/dist/atlas-utils.d.ts +22 -0
- package/packages/core/dist/atlas-utils.js +189 -0
- package/packages/core/dist/atlas-validate.d.ts +2 -0
- package/packages/core/dist/atlas-validate.js +285 -0
- package/packages/core/dist/draft-parse.js +786 -153
- package/packages/core/dist/draft.d.ts +3 -0
- package/packages/core/dist/draft.js +47 -3
- package/packages/core/dist/format.js +165 -9
- package/packages/core/dist/load.js +58 -13
- package/packages/core/dist/normalize.js +7 -0
- package/packages/core/dist/scene.js +66 -13
- package/packages/core/dist/types.d.ts +97 -3
- package/packages/editor/dist/editor.js +44 -0
- package/packages/markdown/README.md +1 -1
- package/packages/viewer/README.md +2 -1
- package/packages/viewer/dist/atlas-state.js +7 -1
- package/packages/viewer/dist/atlas-viewer.js +35 -1
- package/packages/viewer/dist/render.js +16 -7
- package/packages/viewer/dist/theme.js +4 -0
- package/packages/viewer/dist/tooltip.js +35 -0
- package/packages/viewer/dist/types.d.ts +7 -0
- package/packages/viewer/dist/viewer.js +4 -0
|
@@ -19,8 +19,8 @@ var WorldOrbit = (() => {
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
|
|
21
21
|
// packages/viewer/dist/index.js
|
|
22
|
-
var
|
|
23
|
-
__export(
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
24
|
DEFAULT_VIEWER_STATE: () => DEFAULT_VIEWER_STATE,
|
|
25
25
|
WORLD_LAYER_ID: () => WORLD_LAYER_ID,
|
|
26
26
|
clampScale: () => clampScale,
|
|
@@ -60,6 +60,7 @@ var WorldOrbit = (() => {
|
|
|
60
60
|
var DEFAULT_LAYERS = {
|
|
61
61
|
background: true,
|
|
62
62
|
guides: true,
|
|
63
|
+
relations: true,
|
|
63
64
|
orbits: true,
|
|
64
65
|
objects: true,
|
|
65
66
|
labels: true,
|
|
@@ -74,6 +75,7 @@ var WorldOrbit = (() => {
|
|
|
74
75
|
backgroundGlow: "rgba(240, 180, 100, 0.18)",
|
|
75
76
|
panel: "rgba(7, 17, 27, 0.9)",
|
|
76
77
|
panelLine: "rgba(168, 207, 242, 0.18)",
|
|
78
|
+
relation: "rgba(240, 180, 100, 0.42)",
|
|
77
79
|
orbit: "rgba(163, 209, 255, 0.24)",
|
|
78
80
|
orbitBand: "rgba(255, 190, 120, 0.28)",
|
|
79
81
|
guide: "rgba(255, 255, 255, 0.04)",
|
|
@@ -96,6 +98,7 @@ var WorldOrbit = (() => {
|
|
|
96
98
|
backgroundGlow: "rgba(120, 255, 215, 0.16)",
|
|
97
99
|
panel: "rgba(7, 20, 30, 0.9)",
|
|
98
100
|
panelLine: "rgba(120, 255, 215, 0.16)",
|
|
101
|
+
relation: "rgba(156, 231, 255, 0.42)",
|
|
99
102
|
orbit: "rgba(120, 255, 215, 0.2)",
|
|
100
103
|
orbitBand: "rgba(137, 185, 255, 0.24)",
|
|
101
104
|
guide: "rgba(255, 255, 255, 0.035)",
|
|
@@ -118,6 +121,7 @@ var WorldOrbit = (() => {
|
|
|
118
121
|
backgroundGlow: "rgba(255, 127, 95, 0.18)",
|
|
119
122
|
panel: "rgba(24, 9, 13, 0.9)",
|
|
120
123
|
panelLine: "rgba(255, 166, 149, 0.16)",
|
|
124
|
+
relation: "rgba(255, 178, 125, 0.42)",
|
|
121
125
|
orbit: "rgba(255, 188, 164, 0.22)",
|
|
122
126
|
orbitBand: "rgba(255, 214, 139, 0.24)",
|
|
123
127
|
guide: "rgba(255, 255, 255, 0.03)",
|
|
@@ -270,6 +274,7 @@ var WorldOrbit = (() => {
|
|
|
270
274
|
return {
|
|
271
275
|
background: viewpoint.layers.background,
|
|
272
276
|
guides: viewpoint.layers.guides,
|
|
277
|
+
relations: viewpoint.layers.relations,
|
|
273
278
|
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,
|
|
274
279
|
objects: viewpoint.layers.objects,
|
|
275
280
|
labels: viewpoint.layers.labels,
|
|
@@ -307,7 +312,11 @@ var WorldOrbit = (() => {
|
|
|
307
312
|
return false;
|
|
308
313
|
}
|
|
309
314
|
if (filter.groupIds?.length && (!object.groupId || !filter.groupIds.includes(object.groupId))) {
|
|
310
|
-
|
|
315
|
+
const hasSemanticMatch = object.semanticGroupIds.length > 0 && filter.groupIds.some((groupId) => object.semanticGroupIds.includes(groupId));
|
|
316
|
+
const hasLegacyMatch = Boolean(object.groupId && filter.groupIds.includes(object.groupId));
|
|
317
|
+
if (!hasSemanticMatch && !hasLegacyMatch) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
311
320
|
}
|
|
312
321
|
if (filter.tags?.length) {
|
|
313
322
|
const objectTags = Array.isArray(object.object.properties.tags) ? object.object.properties.tags.filter((entry) => typeof entry === "string") : [];
|
|
@@ -674,13 +683,13 @@ var WorldOrbit = (() => {
|
|
|
674
683
|
function unitFamilyAllowsUnit(family, unit) {
|
|
675
684
|
switch (family) {
|
|
676
685
|
case "distance":
|
|
677
|
-
return unit === null || ["au", "km", "re", "sol"].includes(unit);
|
|
686
|
+
return unit === null || ["au", "km", "m", "ly", "pc", "kpc", "re", "sol"].includes(unit);
|
|
678
687
|
case "radius":
|
|
679
|
-
return unit === null || ["km", "re", "sol"].includes(unit);
|
|
688
|
+
return unit === null || ["km", "m", "re", "rj", "sol"].includes(unit);
|
|
680
689
|
case "mass":
|
|
681
|
-
return unit === null || ["me", "sol"].includes(unit);
|
|
690
|
+
return unit === null || ["me", "mj", "sol"].includes(unit);
|
|
682
691
|
case "duration":
|
|
683
|
-
return unit === null || ["h", "d", "y"].includes(unit);
|
|
692
|
+
return unit === null || ["s", "min", "h", "d", "y", "ky", "my", "gy"].includes(unit);
|
|
684
693
|
case "angle":
|
|
685
694
|
return unit === null || unit === "deg";
|
|
686
695
|
case "generic":
|
|
@@ -884,7 +893,7 @@ var WorldOrbit = (() => {
|
|
|
884
893
|
}
|
|
885
894
|
|
|
886
895
|
// packages/core/dist/normalize.js
|
|
887
|
-
var UNIT_PATTERN = /^(-?\d+(?:\.\d+)?)(au|km|re|sol|
|
|
896
|
+
var UNIT_PATTERN = /^(-?\d+(?:\.\d+)?)(kpc|min|mj|rj|ky|my|gy|au|km|me|re|pc|ly|deg|sol|K|m|s|h|d|y)?$/;
|
|
888
897
|
var BOOLEAN_VALUES = /* @__PURE__ */ new Map([
|
|
889
898
|
["true", true],
|
|
890
899
|
["false", false],
|
|
@@ -909,7 +918,10 @@ var WorldOrbit = (() => {
|
|
|
909
918
|
return {
|
|
910
919
|
format: "worldorbit",
|
|
911
920
|
version: "1.0",
|
|
921
|
+
schemaVersion: "1.0",
|
|
912
922
|
system,
|
|
923
|
+
groups: [],
|
|
924
|
+
relations: [],
|
|
913
925
|
objects
|
|
914
926
|
};
|
|
915
927
|
}
|
|
@@ -919,13 +931,17 @@ var WorldOrbit = (() => {
|
|
|
919
931
|
const fieldMap = collectFields(mergedFields);
|
|
920
932
|
const placement = extractPlacement(node.objectType, fieldMap);
|
|
921
933
|
const properties = normalizeProperties(fieldMap);
|
|
922
|
-
const
|
|
934
|
+
const info2 = normalizeInfo(node.infoEntries);
|
|
923
935
|
if (node.objectType === "system") {
|
|
924
936
|
return {
|
|
925
937
|
type: "system",
|
|
926
938
|
id: node.name,
|
|
939
|
+
title: typeof properties.title === "string" ? properties.title : null,
|
|
940
|
+
description: null,
|
|
941
|
+
epoch: null,
|
|
942
|
+
referencePlane: null,
|
|
927
943
|
properties,
|
|
928
|
-
info
|
|
944
|
+
info: info2
|
|
929
945
|
};
|
|
930
946
|
}
|
|
931
947
|
return {
|
|
@@ -933,7 +949,7 @@ var WorldOrbit = (() => {
|
|
|
933
949
|
id: node.name,
|
|
934
950
|
properties,
|
|
935
951
|
placement,
|
|
936
|
-
info
|
|
952
|
+
info: info2
|
|
937
953
|
};
|
|
938
954
|
}
|
|
939
955
|
function validateFieldCompatibility(objectType, fields) {
|
|
@@ -1063,14 +1079,14 @@ var WorldOrbit = (() => {
|
|
|
1063
1079
|
}
|
|
1064
1080
|
}
|
|
1065
1081
|
function normalizeInfo(entries) {
|
|
1066
|
-
const
|
|
1082
|
+
const info2 = {};
|
|
1067
1083
|
for (const entry of entries) {
|
|
1068
|
-
if (entry.key in
|
|
1084
|
+
if (entry.key in info2) {
|
|
1069
1085
|
throw WorldOrbitError.fromLocation(`Duplicate info key "${entry.key}"`, entry.location);
|
|
1070
1086
|
}
|
|
1071
|
-
|
|
1087
|
+
info2[entry.key] = entry.value;
|
|
1072
1088
|
}
|
|
1073
|
-
return
|
|
1089
|
+
return info2;
|
|
1074
1090
|
}
|
|
1075
1091
|
function parseAtReference(target, location) {
|
|
1076
1092
|
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
@@ -1241,37 +1257,41 @@ var WorldOrbit = (() => {
|
|
|
1241
1257
|
}
|
|
1242
1258
|
|
|
1243
1259
|
// packages/core/dist/diagnostics.js
|
|
1244
|
-
function diagnosticFromError(
|
|
1245
|
-
if (
|
|
1260
|
+
function diagnosticFromError(error2, source, code = `${source}.failed`) {
|
|
1261
|
+
if (error2 instanceof WorldOrbitError) {
|
|
1246
1262
|
return {
|
|
1247
1263
|
code,
|
|
1248
1264
|
severity: "error",
|
|
1249
1265
|
source,
|
|
1250
|
-
message:
|
|
1251
|
-
line:
|
|
1252
|
-
column:
|
|
1266
|
+
message: error2.message,
|
|
1267
|
+
line: error2.line,
|
|
1268
|
+
column: error2.column
|
|
1253
1269
|
};
|
|
1254
1270
|
}
|
|
1255
|
-
if (
|
|
1271
|
+
if (error2 instanceof Error) {
|
|
1256
1272
|
return {
|
|
1257
1273
|
code,
|
|
1258
1274
|
severity: "error",
|
|
1259
1275
|
source,
|
|
1260
|
-
message:
|
|
1276
|
+
message: error2.message
|
|
1261
1277
|
};
|
|
1262
1278
|
}
|
|
1263
1279
|
return {
|
|
1264
1280
|
code,
|
|
1265
1281
|
severity: "error",
|
|
1266
1282
|
source,
|
|
1267
|
-
message: String(
|
|
1283
|
+
message: String(error2)
|
|
1268
1284
|
};
|
|
1269
1285
|
}
|
|
1270
1286
|
|
|
1271
1287
|
// packages/core/dist/scene.js
|
|
1272
1288
|
var AU_IN_KM = 1495978707e-1;
|
|
1273
1289
|
var EARTH_RADIUS_IN_KM = 6371;
|
|
1290
|
+
var JUPITER_RADIUS_IN_KM = 71492;
|
|
1274
1291
|
var SOLAR_RADIUS_IN_KM = 695700;
|
|
1292
|
+
var LY_IN_AU = 63241.077;
|
|
1293
|
+
var PC_IN_AU = 206264.806;
|
|
1294
|
+
var KPC_IN_AU = 206264806;
|
|
1275
1295
|
var ISO_FLATTENING = 0.68;
|
|
1276
1296
|
var MIN_ISO_MINOR_SCALE = 0.2;
|
|
1277
1297
|
var ARC_SAMPLE_COUNT = 28;
|
|
@@ -1391,8 +1411,10 @@ var WorldOrbit = (() => {
|
|
|
1391
1411
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1392
1412
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1393
1413
|
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1394
|
-
const
|
|
1414
|
+
const relations = createSceneRelations(document2, objects);
|
|
1415
|
+
const layers = createSceneLayers(orbitVisuals, relations, leaders, objects, labels);
|
|
1395
1416
|
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships);
|
|
1417
|
+
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1396
1418
|
const viewpoints = createSceneViewpoints(document2, projection, frame.preset, relationships, objectMap);
|
|
1397
1419
|
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1398
1420
|
return {
|
|
@@ -1402,7 +1424,7 @@ var WorldOrbit = (() => {
|
|
|
1402
1424
|
renderPreset: frame.preset,
|
|
1403
1425
|
projection,
|
|
1404
1426
|
scaleModel,
|
|
1405
|
-
title: String(document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1427
|
+
title: String(document2.system?.title ?? document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1406
1428
|
subtitle: `${capitalizeLabel(projection)} view - ${capitalizeLabel(layoutPreset)} layout`,
|
|
1407
1429
|
systemId,
|
|
1408
1430
|
viewMode: projection,
|
|
@@ -1418,9 +1440,11 @@ var WorldOrbit = (() => {
|
|
|
1418
1440
|
contentBounds,
|
|
1419
1441
|
layers,
|
|
1420
1442
|
groups,
|
|
1443
|
+
semanticGroups,
|
|
1421
1444
|
viewpoints,
|
|
1422
1445
|
objects,
|
|
1423
1446
|
orbitVisuals,
|
|
1447
|
+
relations,
|
|
1424
1448
|
leaders,
|
|
1425
1449
|
labels
|
|
1426
1450
|
};
|
|
@@ -1530,6 +1554,7 @@ var WorldOrbit = (() => {
|
|
|
1530
1554
|
}
|
|
1531
1555
|
function createSceneObject(position, scaleModel, relationships) {
|
|
1532
1556
|
const { object, x, y, radius, sortKey, anchorX, anchorY } = position;
|
|
1557
|
+
const renderPriority = object.renderHints?.renderPriority ?? 0;
|
|
1533
1558
|
return {
|
|
1534
1559
|
renderId: createRenderId(object.id),
|
|
1535
1560
|
objectId: object.id,
|
|
@@ -1538,11 +1563,12 @@ var WorldOrbit = (() => {
|
|
|
1538
1563
|
ancestorIds: relationships.ancestorIds.get(object.id) ?? [],
|
|
1539
1564
|
childIds: relationships.childIds.get(object.id) ?? [],
|
|
1540
1565
|
groupId: relationships.groupIds.get(object.id) ?? null,
|
|
1566
|
+
semanticGroupIds: [...object.groups ?? []],
|
|
1541
1567
|
x,
|
|
1542
1568
|
y,
|
|
1543
1569
|
radius,
|
|
1544
1570
|
visualRadius: visualExtentForObject(object, radius, scaleModel),
|
|
1545
|
-
sortKey,
|
|
1571
|
+
sortKey: sortKey + renderPriority * 1e-3,
|
|
1546
1572
|
anchorX,
|
|
1547
1573
|
anchorY,
|
|
1548
1574
|
label: object.id,
|
|
@@ -1559,6 +1585,7 @@ var WorldOrbit = (() => {
|
|
|
1559
1585
|
object: draft.object,
|
|
1560
1586
|
parentId: draft.parentId,
|
|
1561
1587
|
groupId,
|
|
1588
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1562
1589
|
kind: draft.kind,
|
|
1563
1590
|
cx: draft.cx,
|
|
1564
1591
|
cy: draft.cy,
|
|
@@ -1570,7 +1597,7 @@ var WorldOrbit = (() => {
|
|
|
1570
1597
|
bandThickness: draft.bandThickness,
|
|
1571
1598
|
frontArcPath: draft.frontArcPath,
|
|
1572
1599
|
backArcPath: draft.backArcPath,
|
|
1573
|
-
hidden: draft.object.properties.hidden === true
|
|
1600
|
+
hidden: draft.object.properties.hidden === true || draft.object.renderHints?.renderOrbit === false
|
|
1574
1601
|
};
|
|
1575
1602
|
}
|
|
1576
1603
|
function createLeaderLine(draft) {
|
|
@@ -1579,6 +1606,7 @@ var WorldOrbit = (() => {
|
|
|
1579
1606
|
objectId: draft.object.id,
|
|
1580
1607
|
object: draft.object,
|
|
1581
1608
|
groupId: draft.groupId,
|
|
1609
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1582
1610
|
x1: draft.x1,
|
|
1583
1611
|
y1: draft.y1,
|
|
1584
1612
|
x2: draft.x2,
|
|
@@ -1590,7 +1618,7 @@ var WorldOrbit = (() => {
|
|
|
1590
1618
|
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1591
1619
|
const labels = [];
|
|
1592
1620
|
const occupied = [];
|
|
1593
|
-
const visibleObjects = [...objects].filter((object) => !object.hidden).sort((left, right) => left.sortKey - right.sortKey);
|
|
1621
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort((left, right) => left.sortKey - right.sortKey);
|
|
1594
1622
|
for (const object of visibleObjects) {
|
|
1595
1623
|
const direction = object.y > sceneHeight * 0.62 ? -1 : 1;
|
|
1596
1624
|
const labelHalfWidth = estimateLabelHalfWidth(object, labelMultiplier);
|
|
@@ -1610,6 +1638,7 @@ var WorldOrbit = (() => {
|
|
|
1610
1638
|
objectId: object.objectId,
|
|
1611
1639
|
object: object.object,
|
|
1612
1640
|
groupId: object.groupId,
|
|
1641
|
+
semanticGroupIds: [...object.semanticGroupIds],
|
|
1613
1642
|
label: object.label,
|
|
1614
1643
|
secondaryLabel: object.secondaryLabel,
|
|
1615
1644
|
x: object.x,
|
|
@@ -1622,7 +1651,7 @@ var WorldOrbit = (() => {
|
|
|
1622
1651
|
}
|
|
1623
1652
|
return labels;
|
|
1624
1653
|
}
|
|
1625
|
-
function createSceneLayers(orbitVisuals, leaders, objects, labels) {
|
|
1654
|
+
function createSceneLayers(orbitVisuals, relations, leaders, objects, labels) {
|
|
1626
1655
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1627
1656
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1628
1657
|
return [
|
|
@@ -1633,6 +1662,10 @@ var WorldOrbit = (() => {
|
|
|
1633
1662
|
},
|
|
1634
1663
|
{ id: "orbits-back", renderIds: backOrbitIds },
|
|
1635
1664
|
{ id: "orbits-front", renderIds: frontOrbitIds },
|
|
1665
|
+
{
|
|
1666
|
+
id: "relations",
|
|
1667
|
+
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1668
|
+
},
|
|
1636
1669
|
{
|
|
1637
1670
|
id: "objects",
|
|
1638
1671
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1697,6 +1730,36 @@ var WorldOrbit = (() => {
|
|
|
1697
1730
|
}
|
|
1698
1731
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1699
1732
|
}
|
|
1733
|
+
function createSceneSemanticGroups(document2, objects) {
|
|
1734
|
+
return [...document2.groups].map((group) => ({
|
|
1735
|
+
id: group.id,
|
|
1736
|
+
label: group.label,
|
|
1737
|
+
summary: group.summary,
|
|
1738
|
+
color: group.color,
|
|
1739
|
+
tags: [...group.tags],
|
|
1740
|
+
hidden: group.hidden,
|
|
1741
|
+
objectIds: objects.filter((object) => !object.hidden && object.semanticGroupIds.includes(group.id)).map((object) => object.objectId)
|
|
1742
|
+
})).sort((left, right) => left.label.localeCompare(right.label));
|
|
1743
|
+
}
|
|
1744
|
+
function createSceneRelations(document2, objects) {
|
|
1745
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1746
|
+
return document2.relations.map((relation) => {
|
|
1747
|
+
const from = objectMap.get(relation.from);
|
|
1748
|
+
const to = objectMap.get(relation.to);
|
|
1749
|
+
return {
|
|
1750
|
+
renderId: `${createRenderId(relation.id)}-relation`,
|
|
1751
|
+
relationId: relation.id,
|
|
1752
|
+
relation,
|
|
1753
|
+
fromObjectId: relation.from,
|
|
1754
|
+
toObjectId: relation.to,
|
|
1755
|
+
x1: from?.x ?? 0,
|
|
1756
|
+
y1: from?.y ?? 0,
|
|
1757
|
+
x2: to?.x ?? 0,
|
|
1758
|
+
y2: to?.y ?? 0,
|
|
1759
|
+
hidden: relation.hidden || !from || !to || from.hidden || to.hidden
|
|
1760
|
+
};
|
|
1761
|
+
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1762
|
+
}
|
|
1700
1763
|
function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
|
|
1701
1764
|
const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
|
|
1702
1765
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1714,7 +1777,7 @@ var WorldOrbit = (() => {
|
|
|
1714
1777
|
}
|
|
1715
1778
|
const field = fieldParts.join(".").toLowerCase();
|
|
1716
1779
|
const draft = drafts.get(id) ?? { id };
|
|
1717
|
-
applyViewpointField(draft, field, value, projection, preset, relationships, objectMap);
|
|
1780
|
+
applyViewpointField(draft, field, value, document2, projection, preset, relationships, objectMap);
|
|
1718
1781
|
drafts.set(id, draft);
|
|
1719
1782
|
}
|
|
1720
1783
|
const viewpoints = [...drafts.values()].map((draft) => finalizeViewpointDraft(draft, projection, preset, objectMap)).filter(Boolean);
|
|
@@ -1742,7 +1805,8 @@ var WorldOrbit = (() => {
|
|
|
1742
1805
|
});
|
|
1743
1806
|
}
|
|
1744
1807
|
function createGeneratedOverviewViewpoint(document2, projection, preset) {
|
|
1745
|
-
const
|
|
1808
|
+
const title = document2.system?.title ?? document2.system?.properties.title;
|
|
1809
|
+
const label = title ? `${String(title)} Overview` : "Overview";
|
|
1746
1810
|
return {
|
|
1747
1811
|
id: "overview",
|
|
1748
1812
|
label,
|
|
@@ -1758,7 +1822,7 @@ var WorldOrbit = (() => {
|
|
|
1758
1822
|
generated: true
|
|
1759
1823
|
};
|
|
1760
1824
|
}
|
|
1761
|
-
function applyViewpointField(draft, field, value, projection, preset, relationships, objectMap) {
|
|
1825
|
+
function applyViewpointField(draft, field, value, document2, projection, preset, relationships, objectMap) {
|
|
1762
1826
|
const normalizedValue = value.trim();
|
|
1763
1827
|
switch (field) {
|
|
1764
1828
|
case "label":
|
|
@@ -1825,7 +1889,7 @@ var WorldOrbit = (() => {
|
|
|
1825
1889
|
case "groups":
|
|
1826
1890
|
draft.filter = {
|
|
1827
1891
|
...draft.filter ?? createEmptyViewpointFilter(),
|
|
1828
|
-
groupIds: parseViewpointGroups(normalizedValue, relationships, objectMap)
|
|
1892
|
+
groupIds: parseViewpointGroups(normalizedValue, document2, relationships, objectMap)
|
|
1829
1893
|
};
|
|
1830
1894
|
return;
|
|
1831
1895
|
}
|
|
@@ -1898,7 +1962,7 @@ var WorldOrbit = (() => {
|
|
|
1898
1962
|
next["orbits-front"] = enabled;
|
|
1899
1963
|
continue;
|
|
1900
1964
|
}
|
|
1901
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1965
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1902
1966
|
next[rawLayer] = enabled;
|
|
1903
1967
|
}
|
|
1904
1968
|
}
|
|
@@ -1907,8 +1971,11 @@ var WorldOrbit = (() => {
|
|
|
1907
1971
|
function parseViewpointObjectTypes(value) {
|
|
1908
1972
|
return splitListValue(value).filter((entry) => entry === "star" || entry === "planet" || entry === "moon" || entry === "belt" || entry === "asteroid" || entry === "comet" || entry === "ring" || entry === "structure" || entry === "phenomenon");
|
|
1909
1973
|
}
|
|
1910
|
-
function parseViewpointGroups(value, relationships, objectMap) {
|
|
1974
|
+
function parseViewpointGroups(value, document2, relationships, objectMap) {
|
|
1911
1975
|
return splitListValue(value).map((entry) => {
|
|
1976
|
+
if (document2.schemaVersion === "2.1" || document2.groups.some((group) => group.id === entry)) {
|
|
1977
|
+
return entry;
|
|
1978
|
+
}
|
|
1912
1979
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
1913
1980
|
return entry;
|
|
1914
1981
|
}
|
|
@@ -2039,8 +2106,9 @@ var WorldOrbit = (() => {
|
|
|
2039
2106
|
}
|
|
2040
2107
|
const orbiting = [...context.orbitChildren.get(object.id) ?? []].sort(compareOrbiting);
|
|
2041
2108
|
const orbitMetricContext = computeOrbitMetricContext(orbiting, parent.radius, context.spacingFactor, context.scaleModel);
|
|
2109
|
+
const orbitRadiiPx = resolveOrbitRadiiPx(orbiting, orbitMetricContext);
|
|
2042
2110
|
orbiting.forEach((child, index) => {
|
|
2043
|
-
const orbitGeometry = resolveOrbitGeometry(child, index, orbiting.length, parent, orbitMetricContext, context);
|
|
2111
|
+
const orbitGeometry = resolveOrbitGeometry(child, index, orbiting.length, parent, orbitMetricContext, orbitRadiiPx[index] ?? orbitMetricContext.innerPx, context);
|
|
2044
2112
|
orbitDrafts.push({
|
|
2045
2113
|
object: child,
|
|
2046
2114
|
parentId: object.id,
|
|
@@ -2114,7 +2182,8 @@ var WorldOrbit = (() => {
|
|
|
2114
2182
|
metricSpread: 0,
|
|
2115
2183
|
innerPx,
|
|
2116
2184
|
stepPx,
|
|
2117
|
-
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx)
|
|
2185
|
+
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
2186
|
+
minimumGapPx: stepPx * 0.42
|
|
2118
2187
|
};
|
|
2119
2188
|
}
|
|
2120
2189
|
const minMetric = Math.min(...presentMetrics);
|
|
@@ -2127,10 +2196,11 @@ var WorldOrbit = (() => {
|
|
|
2127
2196
|
metricSpread,
|
|
2128
2197
|
innerPx,
|
|
2129
2198
|
stepPx,
|
|
2130
|
-
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx)
|
|
2199
|
+
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
2200
|
+
minimumGapPx: stepPx * 0.42
|
|
2131
2201
|
};
|
|
2132
2202
|
}
|
|
2133
|
-
function resolveOrbitGeometry(object, index, count, parent, metricContext, context) {
|
|
2203
|
+
function resolveOrbitGeometry(object, index, count, parent, metricContext, orbitRadiusPx, context) {
|
|
2134
2204
|
const placement = object.placement;
|
|
2135
2205
|
const band = object.type === "belt" || object.type === "ring";
|
|
2136
2206
|
if (!placement || placement.mode !== "orbit") {
|
|
@@ -2148,7 +2218,7 @@ var WorldOrbit = (() => {
|
|
|
2148
2218
|
};
|
|
2149
2219
|
}
|
|
2150
2220
|
const eccentricity = clampNumber(typeof placement.eccentricity === "number" ? placement.eccentricity : 0, 0, 0.92);
|
|
2151
|
-
const semiMajor =
|
|
2221
|
+
const semiMajor = orbitRadiusPx;
|
|
2152
2222
|
const baseMinor = Math.max(semiMajor * Math.sqrt(1 - eccentricity * eccentricity), semiMajor * 0.18);
|
|
2153
2223
|
const inclinationDeg = unitValueToDegrees(placement.inclination) ?? 0;
|
|
2154
2224
|
const inclinationScale = context.projection === "isometric" ? Math.max(MIN_ISO_MINOR_SCALE, Math.cos(degreesToRadians(inclinationDeg))) * ISO_FLATTENING : 1;
|
|
@@ -2178,15 +2248,19 @@ var WorldOrbit = (() => {
|
|
|
2178
2248
|
objectY: objectPoint.y
|
|
2179
2249
|
};
|
|
2180
2250
|
}
|
|
2181
|
-
function resolveOrbitRadiusPx(
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2251
|
+
function resolveOrbitRadiusPx(metric, metricContext) {
|
|
2252
|
+
return metricContext.innerPx + metricContext.stepPx * log2(Math.max(metric, 0) + 1);
|
|
2253
|
+
}
|
|
2254
|
+
function resolveOrbitRadiiPx(objects, metricContext) {
|
|
2255
|
+
const radii = [];
|
|
2256
|
+
objects.forEach((object, index) => {
|
|
2257
|
+
const metric = orbitMetric(object);
|
|
2258
|
+
const fallbackRadius = metricContext.innerPx + index * metricContext.stepPx;
|
|
2259
|
+
const baseRadius = metric === null ? fallbackRadius : resolveOrbitRadiusPx(metric, metricContext);
|
|
2260
|
+
const minimumRadius = index === 0 ? metricContext.innerPx : (radii[index - 1] ?? metricContext.innerPx) + metricContext.minimumGapPx;
|
|
2261
|
+
radii.push(Math.max(baseRadius, minimumRadius));
|
|
2262
|
+
});
|
|
2263
|
+
return radii;
|
|
2190
2264
|
}
|
|
2191
2265
|
function orbitMetric(object) {
|
|
2192
2266
|
if (!object.placement || object.placement.mode !== "orbit") {
|
|
@@ -2194,6 +2268,9 @@ var WorldOrbit = (() => {
|
|
|
2194
2268
|
}
|
|
2195
2269
|
return toDistanceMetric(object.placement.semiMajor ?? object.placement.distance ?? null);
|
|
2196
2270
|
}
|
|
2271
|
+
function log2(value) {
|
|
2272
|
+
return Math.log(value) / Math.log(2);
|
|
2273
|
+
}
|
|
2197
2274
|
function resolveOrbitPhase(phase, index, count) {
|
|
2198
2275
|
const degreeValue = phase ? unitValueToDegrees(phase) : null;
|
|
2199
2276
|
if (degreeValue !== null) {
|
|
@@ -2517,8 +2594,18 @@ var WorldOrbit = (() => {
|
|
|
2517
2594
|
return value.value;
|
|
2518
2595
|
case "km":
|
|
2519
2596
|
return value.value / AU_IN_KM;
|
|
2597
|
+
case "m":
|
|
2598
|
+
return value.value / 1e3 / AU_IN_KM;
|
|
2599
|
+
case "ly":
|
|
2600
|
+
return value.value * LY_IN_AU;
|
|
2601
|
+
case "pc":
|
|
2602
|
+
return value.value * PC_IN_AU;
|
|
2603
|
+
case "kpc":
|
|
2604
|
+
return value.value * KPC_IN_AU;
|
|
2520
2605
|
case "re":
|
|
2521
2606
|
return value.value * EARTH_RADIUS_IN_KM / AU_IN_KM;
|
|
2607
|
+
case "rj":
|
|
2608
|
+
return value.value * JUPITER_RADIUS_IN_KM / AU_IN_KM;
|
|
2522
2609
|
case "sol":
|
|
2523
2610
|
return value.value * SOLAR_RADIUS_IN_KM / AU_IN_KM;
|
|
2524
2611
|
default:
|
|
@@ -2658,19 +2745,37 @@ var WorldOrbit = (() => {
|
|
|
2658
2745
|
const system = document2.system ? {
|
|
2659
2746
|
type: "system",
|
|
2660
2747
|
id: document2.system.id,
|
|
2748
|
+
title: document2.system.title,
|
|
2749
|
+
description: document2.system.description,
|
|
2750
|
+
epoch: document2.system.epoch,
|
|
2751
|
+
referencePlane: document2.system.referencePlane,
|
|
2661
2752
|
properties: materializeDraftSystemProperties(document2.system),
|
|
2662
2753
|
info: materializeDraftSystemInfo(document2.system)
|
|
2663
2754
|
} : null;
|
|
2664
2755
|
return {
|
|
2665
2756
|
format: "worldorbit",
|
|
2666
2757
|
version: "1.0",
|
|
2758
|
+
schemaVersion: document2.version,
|
|
2667
2759
|
system,
|
|
2760
|
+
groups: structuredClone(document2.groups ?? []),
|
|
2761
|
+
relations: structuredClone(document2.relations ?? []),
|
|
2668
2762
|
objects: document2.objects.map(cloneWorldOrbitObject)
|
|
2669
2763
|
};
|
|
2670
2764
|
}
|
|
2671
2765
|
function cloneWorldOrbitObject(object) {
|
|
2672
2766
|
return {
|
|
2673
2767
|
...object,
|
|
2768
|
+
groups: object.groups ? [...object.groups] : void 0,
|
|
2769
|
+
resonance: object.resonance ? { ...object.resonance } : object.resonance,
|
|
2770
|
+
renderHints: object.renderHints ? { ...object.renderHints } : object.renderHints,
|
|
2771
|
+
deriveRules: object.deriveRules ? object.deriveRules.map((rule) => ({ ...rule })) : void 0,
|
|
2772
|
+
validationRules: object.validationRules ? object.validationRules.map((rule) => ({ ...rule })) : void 0,
|
|
2773
|
+
lockedFields: object.lockedFields ? [...object.lockedFields] : void 0,
|
|
2774
|
+
tolerances: object.tolerances ? object.tolerances.map((entry) => ({
|
|
2775
|
+
field: entry.field,
|
|
2776
|
+
value: entry.value && typeof entry.value === "object" && "value" in entry.value ? { value: entry.value.value, unit: entry.value.unit } : Array.isArray(entry.value) ? [...entry.value] : entry.value
|
|
2777
|
+
})) : void 0,
|
|
2778
|
+
typedBlocks: object.typedBlocks ? Object.fromEntries(Object.entries(object.typedBlocks).map(([key, block]) => [key, { ...block ?? {} }])) : void 0,
|
|
2674
2779
|
properties: cloneProperties(object.properties),
|
|
2675
2780
|
placement: object.placement ? structuredClone(object.placement) : null,
|
|
2676
2781
|
info: { ...object.info }
|
|
@@ -2706,71 +2811,80 @@ var WorldOrbit = (() => {
|
|
|
2706
2811
|
if (system.defaults.units) {
|
|
2707
2812
|
properties.units = system.defaults.units;
|
|
2708
2813
|
}
|
|
2814
|
+
if (system.description) {
|
|
2815
|
+
properties.description = system.description;
|
|
2816
|
+
}
|
|
2817
|
+
if (system.epoch) {
|
|
2818
|
+
properties.epoch = system.epoch;
|
|
2819
|
+
}
|
|
2820
|
+
if (system.referencePlane) {
|
|
2821
|
+
properties.referencePlane = system.referencePlane;
|
|
2822
|
+
}
|
|
2709
2823
|
return properties;
|
|
2710
2824
|
}
|
|
2711
2825
|
function materializeDraftSystemInfo(system) {
|
|
2712
|
-
const
|
|
2826
|
+
const info2 = {
|
|
2713
2827
|
...system.atlasMetadata
|
|
2714
2828
|
};
|
|
2715
2829
|
if (system.defaults.theme) {
|
|
2716
|
-
|
|
2830
|
+
info2["atlas.theme"] = system.defaults.theme;
|
|
2717
2831
|
}
|
|
2718
2832
|
for (const viewpoint of system.viewpoints) {
|
|
2719
2833
|
const prefix = `viewpoint.${viewpoint.id}`;
|
|
2720
|
-
|
|
2834
|
+
info2[`${prefix}.label`] = viewpoint.label;
|
|
2721
2835
|
if (viewpoint.summary) {
|
|
2722
|
-
|
|
2836
|
+
info2[`${prefix}.summary`] = viewpoint.summary;
|
|
2723
2837
|
}
|
|
2724
2838
|
if (viewpoint.focusObjectId) {
|
|
2725
|
-
|
|
2839
|
+
info2[`${prefix}.focus`] = viewpoint.focusObjectId;
|
|
2726
2840
|
}
|
|
2727
2841
|
if (viewpoint.selectedObjectId) {
|
|
2728
|
-
|
|
2842
|
+
info2[`${prefix}.select`] = viewpoint.selectedObjectId;
|
|
2729
2843
|
}
|
|
2730
2844
|
if (viewpoint.projection) {
|
|
2731
|
-
|
|
2845
|
+
info2[`${prefix}.projection`] = viewpoint.projection;
|
|
2732
2846
|
}
|
|
2733
2847
|
if (viewpoint.preset) {
|
|
2734
|
-
|
|
2848
|
+
info2[`${prefix}.preset`] = viewpoint.preset;
|
|
2735
2849
|
}
|
|
2736
2850
|
if (viewpoint.zoom !== null) {
|
|
2737
|
-
|
|
2851
|
+
info2[`${prefix}.zoom`] = String(viewpoint.zoom);
|
|
2738
2852
|
}
|
|
2739
2853
|
if (viewpoint.rotationDeg !== 0) {
|
|
2740
|
-
|
|
2854
|
+
info2[`${prefix}.rotation`] = String(viewpoint.rotationDeg);
|
|
2741
2855
|
}
|
|
2742
2856
|
const serializedLayers = serializeViewpointLayers(viewpoint.layers);
|
|
2743
2857
|
if (serializedLayers) {
|
|
2744
|
-
|
|
2858
|
+
info2[`${prefix}.layers`] = serializedLayers;
|
|
2745
2859
|
}
|
|
2746
2860
|
if (viewpoint.filter?.query) {
|
|
2747
|
-
|
|
2861
|
+
info2[`${prefix}.query`] = viewpoint.filter.query;
|
|
2748
2862
|
}
|
|
2749
2863
|
if ((viewpoint.filter?.objectTypes.length ?? 0) > 0) {
|
|
2750
|
-
|
|
2864
|
+
info2[`${prefix}.types`] = viewpoint.filter?.objectTypes.join(" ") ?? "";
|
|
2751
2865
|
}
|
|
2752
2866
|
if ((viewpoint.filter?.tags.length ?? 0) > 0) {
|
|
2753
|
-
|
|
2867
|
+
info2[`${prefix}.tags`] = viewpoint.filter?.tags.join(" ") ?? "";
|
|
2754
2868
|
}
|
|
2755
2869
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2756
|
-
|
|
2870
|
+
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2757
2871
|
}
|
|
2758
2872
|
}
|
|
2759
2873
|
for (const annotation of system.annotations) {
|
|
2760
2874
|
const prefix = `annotation.${annotation.id}`;
|
|
2761
|
-
|
|
2875
|
+
info2[`${prefix}.label`] = annotation.label;
|
|
2762
2876
|
if (annotation.targetObjectId) {
|
|
2763
|
-
|
|
2877
|
+
info2[`${prefix}.target`] = annotation.targetObjectId;
|
|
2764
2878
|
}
|
|
2765
|
-
|
|
2879
|
+
info2[`${prefix}.body`] = annotation.body;
|
|
2766
2880
|
if (annotation.tags.length > 0) {
|
|
2767
|
-
|
|
2881
|
+
info2[`${prefix}.tags`] = annotation.tags.join(" ");
|
|
2768
2882
|
}
|
|
2769
2883
|
if (annotation.sourceObjectId) {
|
|
2770
|
-
|
|
2884
|
+
info2[`${prefix}.source`] = annotation.sourceObjectId;
|
|
2771
2885
|
}
|
|
2772
2886
|
}
|
|
2773
|
-
return
|
|
2887
|
+
return info2;
|
|
2774
2888
|
}
|
|
2775
2889
|
function serializeViewpointLayers(layers) {
|
|
2776
2890
|
const tokens = [];
|
|
@@ -2779,7 +2893,7 @@ var WorldOrbit = (() => {
|
|
|
2779
2893
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2780
2894
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2781
2895
|
}
|
|
2782
|
-
for (const key of ["background", "guides", "objects", "labels", "metadata"]) {
|
|
2896
|
+
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
2783
2897
|
if (layers[key] !== void 0) {
|
|
2784
2898
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2785
2899
|
}
|
|
@@ -2787,21 +2901,530 @@ var WorldOrbit = (() => {
|
|
|
2787
2901
|
return tokens.join(" ");
|
|
2788
2902
|
}
|
|
2789
2903
|
|
|
2904
|
+
// packages/core/dist/atlas-utils.js
|
|
2905
|
+
var UNIT_PATTERN2 = /^(-?\d+(?:\.\d+)?)(kpc|min|mj|rj|ky|my|gy|au|km|me|re|pc|ly|deg|sol|K|m|s|h|d|y)?$/;
|
|
2906
|
+
var BOOLEAN_VALUES2 = /* @__PURE__ */ new Map([
|
|
2907
|
+
["true", true],
|
|
2908
|
+
["false", false],
|
|
2909
|
+
["yes", true],
|
|
2910
|
+
["no", false]
|
|
2911
|
+
]);
|
|
2912
|
+
var URL_SCHEME_PATTERN2 = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
2913
|
+
function normalizeIdentifier(value) {
|
|
2914
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2915
|
+
}
|
|
2916
|
+
function humanizeIdentifier2(value) {
|
|
2917
|
+
return value.split(/[-_]+/).filter(Boolean).map((segment) => segment[0].toUpperCase() + segment.slice(1)).join(" ");
|
|
2918
|
+
}
|
|
2919
|
+
function parseAtlasUnitValue(input, location, fieldKey) {
|
|
2920
|
+
const match = input.match(UNIT_PATTERN2);
|
|
2921
|
+
if (!match) {
|
|
2922
|
+
throw WorldOrbitError.fromLocation(`Invalid unit value "${input}"`, location);
|
|
2923
|
+
}
|
|
2924
|
+
const unitValue = {
|
|
2925
|
+
value: Number(match[1]),
|
|
2926
|
+
unit: match[2] ?? null
|
|
2927
|
+
};
|
|
2928
|
+
if (fieldKey) {
|
|
2929
|
+
const schema = getFieldSchema(fieldKey);
|
|
2930
|
+
if (schema?.unitFamily && !unitFamilyAllowsUnit(schema.unitFamily, unitValue.unit)) {
|
|
2931
|
+
throw WorldOrbitError.fromLocation(`Unit "${unitValue.unit ?? "none"}" is not valid for "${fieldKey}"`, location);
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
return unitValue;
|
|
2935
|
+
}
|
|
2936
|
+
function tryParseAtlasUnitValue(input) {
|
|
2937
|
+
const match = input.match(UNIT_PATTERN2);
|
|
2938
|
+
if (!match) {
|
|
2939
|
+
return null;
|
|
2940
|
+
}
|
|
2941
|
+
return {
|
|
2942
|
+
value: Number(match[1]),
|
|
2943
|
+
unit: match[2] ?? null
|
|
2944
|
+
};
|
|
2945
|
+
}
|
|
2946
|
+
function parseAtlasNumber(input, key, location) {
|
|
2947
|
+
const value = Number(input);
|
|
2948
|
+
if (!Number.isFinite(value)) {
|
|
2949
|
+
throw WorldOrbitError.fromLocation(`Invalid numeric value "${input}" for "${key}"`, location);
|
|
2950
|
+
}
|
|
2951
|
+
return value;
|
|
2952
|
+
}
|
|
2953
|
+
function parseAtlasBoolean(input, key, location) {
|
|
2954
|
+
const parsed = BOOLEAN_VALUES2.get(input.toLowerCase());
|
|
2955
|
+
if (parsed === void 0) {
|
|
2956
|
+
throw WorldOrbitError.fromLocation(`Invalid boolean value "${input}" for "${key}"`, location);
|
|
2957
|
+
}
|
|
2958
|
+
return parsed;
|
|
2959
|
+
}
|
|
2960
|
+
function parseAtlasAtReference(target, location) {
|
|
2961
|
+
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
2962
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
2963
|
+
}
|
|
2964
|
+
const pairedMatch = target.match(/^([A-Za-z0-9._-]+)-([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
2965
|
+
if (pairedMatch) {
|
|
2966
|
+
return {
|
|
2967
|
+
kind: "lagrange",
|
|
2968
|
+
primary: pairedMatch[1],
|
|
2969
|
+
secondary: pairedMatch[2],
|
|
2970
|
+
point: pairedMatch[3]
|
|
2971
|
+
};
|
|
2972
|
+
}
|
|
2973
|
+
const simpleMatch = target.match(/^([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
2974
|
+
if (simpleMatch) {
|
|
2975
|
+
return {
|
|
2976
|
+
kind: "lagrange",
|
|
2977
|
+
primary: simpleMatch[1],
|
|
2978
|
+
secondary: null,
|
|
2979
|
+
point: simpleMatch[2]
|
|
2980
|
+
};
|
|
2981
|
+
}
|
|
2982
|
+
if (/^[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
2983
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
2984
|
+
}
|
|
2985
|
+
const anchorMatch = target.match(/^([A-Za-z0-9._-]+):([A-Za-z0-9._-]+)$/);
|
|
2986
|
+
if (anchorMatch) {
|
|
2987
|
+
return {
|
|
2988
|
+
kind: "anchor",
|
|
2989
|
+
objectId: anchorMatch[1],
|
|
2990
|
+
anchor: anchorMatch[2]
|
|
2991
|
+
};
|
|
2992
|
+
}
|
|
2993
|
+
return {
|
|
2994
|
+
kind: "named",
|
|
2995
|
+
name: target
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
function validateAtlasImageSource(value, location) {
|
|
2999
|
+
if (!value) {
|
|
3000
|
+
throw WorldOrbitError.fromLocation('Field "image" must not be empty', location);
|
|
3001
|
+
}
|
|
3002
|
+
if (value.startsWith("//")) {
|
|
3003
|
+
throw WorldOrbitError.fromLocation('Field "image" must use a relative path, root-relative path, or an http/https URL', location);
|
|
3004
|
+
}
|
|
3005
|
+
const schemeMatch = value.match(URL_SCHEME_PATTERN2);
|
|
3006
|
+
if (!schemeMatch) {
|
|
3007
|
+
return;
|
|
3008
|
+
}
|
|
3009
|
+
const scheme = schemeMatch[0].slice(0, -1).toLowerCase();
|
|
3010
|
+
if (scheme !== "http" && scheme !== "https") {
|
|
3011
|
+
throw WorldOrbitError.fromLocation(`Field "image" does not support the "${scheme}" scheme`, location);
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
function normalizeLegacyScalarValue(key, values, location) {
|
|
3015
|
+
const schema = getFieldSchema(key);
|
|
3016
|
+
if (!schema) {
|
|
3017
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
3018
|
+
}
|
|
3019
|
+
if (schema.arity === "single" && values.length !== 1) {
|
|
3020
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
3021
|
+
}
|
|
3022
|
+
switch (schema.kind) {
|
|
3023
|
+
case "list":
|
|
3024
|
+
return values;
|
|
3025
|
+
case "boolean":
|
|
3026
|
+
return parseAtlasBoolean(singleAtlasValue(values, key, location), key, location);
|
|
3027
|
+
case "number":
|
|
3028
|
+
return parseAtlasNumber(singleAtlasValue(values, key, location), key, location);
|
|
3029
|
+
case "unit":
|
|
3030
|
+
return parseAtlasUnitValue(singleAtlasValue(values, key, location), location, key);
|
|
3031
|
+
case "string": {
|
|
3032
|
+
const value = values.join(" ").trim();
|
|
3033
|
+
if (key === "image") {
|
|
3034
|
+
validateAtlasImageSource(value, location);
|
|
3035
|
+
}
|
|
3036
|
+
return value;
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
function ensureAtlasFieldSupported(key, objectType, location) {
|
|
3041
|
+
const schema = getFieldSchema(key);
|
|
3042
|
+
if (!schema) {
|
|
3043
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
3044
|
+
}
|
|
3045
|
+
if (!schema.objectTypes.includes(objectType)) {
|
|
3046
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" is not valid on "${objectType}"`, location);
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
function singleAtlasValue(values, key, location) {
|
|
3050
|
+
if (values.length !== 1) {
|
|
3051
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
3052
|
+
}
|
|
3053
|
+
return values[0];
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
// packages/core/dist/atlas-validate.js
|
|
3057
|
+
var SURFACE_TARGET_TYPES2 = /* @__PURE__ */ new Set(["star", "planet", "moon", "asteroid", "comet"]);
|
|
3058
|
+
var EARTH_MASSES_PER_SOLAR = 332946.0487;
|
|
3059
|
+
var JUPITER_MASSES_PER_SOLAR = 1047.3486;
|
|
3060
|
+
var AU_IN_KM2 = 1495978707e-1;
|
|
3061
|
+
var EARTH_RADIUS_IN_KM2 = 6371;
|
|
3062
|
+
var SOLAR_RADIUS_IN_KM2 = 695700;
|
|
3063
|
+
var LY_IN_AU2 = 63241.077;
|
|
3064
|
+
var PC_IN_AU2 = 206264.806;
|
|
3065
|
+
var KPC_IN_AU2 = 206264806;
|
|
3066
|
+
function collectAtlasDiagnostics(document2, sourceSchemaVersion) {
|
|
3067
|
+
const diagnostics = [];
|
|
3068
|
+
const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
|
|
3069
|
+
const groupIds = new Set(document2.groups.map((group) => group.id));
|
|
3070
|
+
if (!document2.system) {
|
|
3071
|
+
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
3072
|
+
}
|
|
3073
|
+
const knownIds = /* @__PURE__ */ new Map();
|
|
3074
|
+
for (const [kind, ids] of [
|
|
3075
|
+
["group", document2.groups.map((group) => group.id)],
|
|
3076
|
+
["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
3077
|
+
["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
3078
|
+
["relation", document2.relations.map((relation) => relation.id)],
|
|
3079
|
+
["object", document2.objects.map((object) => object.id)]
|
|
3080
|
+
]) {
|
|
3081
|
+
for (const id of ids) {
|
|
3082
|
+
const previous = knownIds.get(id);
|
|
3083
|
+
if (previous) {
|
|
3084
|
+
diagnostics.push(error("validate.id.duplicate", `Duplicate ${kind} id "${id}" already used by ${previous}.`));
|
|
3085
|
+
} else {
|
|
3086
|
+
knownIds.set(id, kind);
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
for (const relation of document2.relations) {
|
|
3091
|
+
validateRelation(relation, objectMap, diagnostics);
|
|
3092
|
+
}
|
|
3093
|
+
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
3094
|
+
validateViewpointFilter(viewpoint.filter, groupIds, sourceSchemaVersion, diagnostics, viewpoint.id);
|
|
3095
|
+
}
|
|
3096
|
+
for (const object of document2.objects) {
|
|
3097
|
+
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
3098
|
+
}
|
|
3099
|
+
return diagnostics;
|
|
3100
|
+
}
|
|
3101
|
+
function validateRelation(relation, objectMap, diagnostics) {
|
|
3102
|
+
if (!relation.from) {
|
|
3103
|
+
diagnostics.push(error("validate.relation.from.required", `Relation "${relation.id}" is missing a "from" target.`));
|
|
3104
|
+
} else if (!objectMap.has(relation.from)) {
|
|
3105
|
+
diagnostics.push(error("validate.relation.from.unknown", `Unknown relation source "${relation.from}" on "${relation.id}".`));
|
|
3106
|
+
}
|
|
3107
|
+
if (!relation.to) {
|
|
3108
|
+
diagnostics.push(error("validate.relation.to.required", `Relation "${relation.id}" is missing a "to" target.`));
|
|
3109
|
+
} else if (!objectMap.has(relation.to)) {
|
|
3110
|
+
diagnostics.push(error("validate.relation.to.unknown", `Unknown relation target "${relation.to}" on "${relation.id}".`));
|
|
3111
|
+
}
|
|
3112
|
+
if (!relation.kind) {
|
|
3113
|
+
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
function validateViewpointFilter(filter, groupIds, sourceSchemaVersion, diagnostics, viewpointId) {
|
|
3117
|
+
if (!filter || sourceSchemaVersion !== "2.1") {
|
|
3118
|
+
return;
|
|
3119
|
+
}
|
|
3120
|
+
for (const groupId of filter.groupIds) {
|
|
3121
|
+
if (!groupIds.has(groupId)) {
|
|
3122
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`));
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
function validateObject(object, system, objectMap, groupIds, diagnostics) {
|
|
3127
|
+
const placement = object.placement;
|
|
3128
|
+
const orbitPlacement = placement?.mode === "orbit" ? placement : null;
|
|
3129
|
+
const parentObject = placement?.mode === "orbit" ? objectMap.get(placement.target) ?? null : null;
|
|
3130
|
+
if (object.groups) {
|
|
3131
|
+
for (const groupId of object.groups) {
|
|
3132
|
+
if (!groupIds.has(groupId)) {
|
|
3133
|
+
diagnostics.push(warn("validate.group.unknown", `Unknown group "${groupId}" on "${object.id}".`, object.id, "groups"));
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
if (orbitPlacement) {
|
|
3138
|
+
if (!objectMap.has(orbitPlacement.target)) {
|
|
3139
|
+
diagnostics.push(error("validate.orbit.target.unknown", `Unknown placement target "${orbitPlacement.target}" on "${object.id}".`, object.id, "orbit"));
|
|
3140
|
+
}
|
|
3141
|
+
if (orbitPlacement.distance && orbitPlacement.semiMajor) {
|
|
3142
|
+
diagnostics.push(error("validate.orbit.distanceConflict", `Object "${object.id}" cannot declare both "distance" and "semiMajor".`, object.id, "distance"));
|
|
3143
|
+
}
|
|
3144
|
+
if (orbitPlacement.phase && !object.epoch && !system?.epoch) {
|
|
3145
|
+
diagnostics.push(warn("validate.phase.epochMissing", `Object "${object.id}" sets "phase" without an object or system epoch.`, object.id, "phase"));
|
|
3146
|
+
}
|
|
3147
|
+
if (orbitPlacement.inclination && !object.referencePlane && !system?.referencePlane) {
|
|
3148
|
+
diagnostics.push(warn("validate.inclination.referencePlaneMissing", `Object "${object.id}" sets "inclination" without an object or system reference plane.`, object.id, "inclination"));
|
|
3149
|
+
}
|
|
3150
|
+
if (orbitPlacement.period && !massInSolar(parentObject?.properties.mass)) {
|
|
3151
|
+
diagnostics.push(warn("validate.period.massMissing", `Object "${object.id}" sets "period" but its central mass cannot be derived.`, object.id, "period"));
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
if (placement?.mode === "surface") {
|
|
3155
|
+
const target = objectMap.get(placement.target);
|
|
3156
|
+
if (!target) {
|
|
3157
|
+
diagnostics.push(error("validate.surface.target.unknown", `Unknown placement target "${placement.target}" on "${object.id}".`, object.id, "surface"));
|
|
3158
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3159
|
+
diagnostics.push(error("validate.surface.target.invalid", `Surface target "${placement.target}" on "${object.id}" is not surface-capable.`, object.id, "surface"));
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
if (placement?.mode === "at") {
|
|
3163
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3164
|
+
diagnostics.push(error("validate.at.objectType", `Only structures and phenomena may use "at" placement; found "${object.type}" on "${object.id}".`, object.id, "at"));
|
|
3165
|
+
}
|
|
3166
|
+
if (!validateAtTarget(object, objectMap, diagnostics)) {
|
|
3167
|
+
diagnostics.push(error("validate.at.target.unknown", `Unknown at-reference target "${placement.target}" on "${object.id}".`, object.id, "at"));
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
if (object.resonance) {
|
|
3171
|
+
const target = objectMap.get(object.resonance.targetObjectId);
|
|
3172
|
+
if (!target) {
|
|
3173
|
+
diagnostics.push(error("validate.resonance.target.unknown", `Unknown resonance target "${object.resonance.targetObjectId}" on "${object.id}".`, object.id, "resonance"));
|
|
3174
|
+
} else if (object.placement?.mode !== "orbit" || target.placement?.mode !== "orbit" || object.placement.target !== target.placement.target) {
|
|
3175
|
+
diagnostics.push(warn("validate.resonance.orbitMismatch", `Resonance target "${object.resonance.targetObjectId}" on "${object.id}" does not share a compatible orbital parent.`, object.id, "resonance"));
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
for (const rule of object.deriveRules ?? []) {
|
|
3179
|
+
if (rule.field !== "period" || rule.strategy !== "kepler") {
|
|
3180
|
+
diagnostics.push(warn("validate.derive.unsupported", `Unsupported derive rule "${rule.field} ${rule.strategy}" on "${object.id}".`, object.id, "derive"));
|
|
3181
|
+
continue;
|
|
3182
|
+
}
|
|
3183
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3184
|
+
if (derivedPeriodDays === null) {
|
|
3185
|
+
diagnostics.push(warn("validate.derive.inputsMissing", `Object "${object.id}" requests "derive period kepler" but lacks enough input data.`, object.id, "derive"));
|
|
3186
|
+
continue;
|
|
3187
|
+
}
|
|
3188
|
+
if (!orbitPlacement?.period) {
|
|
3189
|
+
diagnostics.push(info("validate.derive.period.available", `Object "${object.id}" can derive a Kepler period of ${formatDays(derivedPeriodDays)}.`, object.id, "derive"));
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
for (const rule of object.validationRules ?? []) {
|
|
3193
|
+
if (rule.rule !== "kepler") {
|
|
3194
|
+
diagnostics.push(warn("validate.rule.unsupported", `Unsupported validation rule "${rule.rule}" on "${object.id}".`, object.id, "validate"));
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
const actualPeriodDays = durationInDays(orbitPlacement?.period);
|
|
3198
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3199
|
+
if (actualPeriodDays === null || derivedPeriodDays === null) {
|
|
3200
|
+
continue;
|
|
3201
|
+
}
|
|
3202
|
+
const toleranceDays = toleranceForField(object, "period");
|
|
3203
|
+
if (Math.abs(actualPeriodDays - derivedPeriodDays) > toleranceDays) {
|
|
3204
|
+
diagnostics.push(error("validate.kepler.mismatch", `Object "${object.id}" fails Kepler validation for "period".`, object.id, "validate"));
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
function validateAtTarget(object, objectMap, diagnostics) {
|
|
3209
|
+
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
3210
|
+
if (!reference) {
|
|
3211
|
+
return true;
|
|
3212
|
+
}
|
|
3213
|
+
if (reference.kind === "named") {
|
|
3214
|
+
return objectMap.has(reference.name);
|
|
3215
|
+
}
|
|
3216
|
+
if (reference.kind === "anchor") {
|
|
3217
|
+
if (!objectMap.has(reference.objectId)) {
|
|
3218
|
+
diagnostics.push(error("validate.anchor.target.unknown", `Unknown anchor target "${reference.objectId}" on "${object.id}".`, object.id, "at"));
|
|
3219
|
+
return false;
|
|
3220
|
+
}
|
|
3221
|
+
return true;
|
|
3222
|
+
}
|
|
3223
|
+
if (!objectMap.has(reference.primary)) {
|
|
3224
|
+
diagnostics.push(error("validate.lagrange.primary.unknown", `Unknown Lagrange reference "${reference.primary}" on "${object.id}".`, object.id, "at"));
|
|
3225
|
+
return false;
|
|
3226
|
+
}
|
|
3227
|
+
if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3228
|
+
diagnostics.push(error("validate.lagrange.secondary.unknown", `Unknown Lagrange reference "${reference.secondary}" on "${object.id}".`, object.id, "at"));
|
|
3229
|
+
return false;
|
|
3230
|
+
}
|
|
3231
|
+
return true;
|
|
3232
|
+
}
|
|
3233
|
+
function keplerPeriodDays(object, parentObject) {
|
|
3234
|
+
const placement = object.placement;
|
|
3235
|
+
if (!placement || placement.mode !== "orbit") {
|
|
3236
|
+
return null;
|
|
3237
|
+
}
|
|
3238
|
+
const semiMajorAu = distanceInAu(placement.semiMajor ?? placement.distance);
|
|
3239
|
+
const centralMassSolar = massInSolar(parentObject?.properties.mass);
|
|
3240
|
+
if (semiMajorAu === null || centralMassSolar === null || centralMassSolar <= 0) {
|
|
3241
|
+
return null;
|
|
3242
|
+
}
|
|
3243
|
+
const periodYears = Math.sqrt(semiMajorAu ** 3 / centralMassSolar);
|
|
3244
|
+
return periodYears * 365.25;
|
|
3245
|
+
}
|
|
3246
|
+
function distanceInAu(value) {
|
|
3247
|
+
if (!value)
|
|
3248
|
+
return null;
|
|
3249
|
+
switch (value.unit) {
|
|
3250
|
+
case null:
|
|
3251
|
+
case "au":
|
|
3252
|
+
return value.value;
|
|
3253
|
+
case "km":
|
|
3254
|
+
return value.value / AU_IN_KM2;
|
|
3255
|
+
case "m":
|
|
3256
|
+
return value.value / (AU_IN_KM2 * 1e3);
|
|
3257
|
+
case "ly":
|
|
3258
|
+
return value.value * LY_IN_AU2;
|
|
3259
|
+
case "pc":
|
|
3260
|
+
return value.value * PC_IN_AU2;
|
|
3261
|
+
case "kpc":
|
|
3262
|
+
return value.value * KPC_IN_AU2;
|
|
3263
|
+
case "re":
|
|
3264
|
+
return value.value * EARTH_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
3265
|
+
case "sol":
|
|
3266
|
+
return value.value * SOLAR_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
3267
|
+
default:
|
|
3268
|
+
return null;
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
function massInSolar(value) {
|
|
3272
|
+
if (!value || typeof value !== "object" || !("value" in value)) {
|
|
3273
|
+
return null;
|
|
3274
|
+
}
|
|
3275
|
+
const unitValue = value;
|
|
3276
|
+
switch (unitValue.unit) {
|
|
3277
|
+
case null:
|
|
3278
|
+
case "sol":
|
|
3279
|
+
return unitValue.value;
|
|
3280
|
+
case "me":
|
|
3281
|
+
return unitValue.value / EARTH_MASSES_PER_SOLAR;
|
|
3282
|
+
case "mj":
|
|
3283
|
+
return unitValue.value / JUPITER_MASSES_PER_SOLAR;
|
|
3284
|
+
default:
|
|
3285
|
+
return null;
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
function durationInDays(value) {
|
|
3289
|
+
if (!value)
|
|
3290
|
+
return null;
|
|
3291
|
+
switch (value.unit) {
|
|
3292
|
+
case null:
|
|
3293
|
+
case "d":
|
|
3294
|
+
return value.value;
|
|
3295
|
+
case "s":
|
|
3296
|
+
return value.value / 86400;
|
|
3297
|
+
case "min":
|
|
3298
|
+
return value.value / 1440;
|
|
3299
|
+
case "h":
|
|
3300
|
+
return value.value / 24;
|
|
3301
|
+
case "y":
|
|
3302
|
+
return value.value * 365.25;
|
|
3303
|
+
case "ky":
|
|
3304
|
+
return value.value * 365250;
|
|
3305
|
+
case "my":
|
|
3306
|
+
return value.value * 36525e4;
|
|
3307
|
+
case "gy":
|
|
3308
|
+
return value.value * 36525e7;
|
|
3309
|
+
default:
|
|
3310
|
+
return null;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
function toleranceForField(object, field) {
|
|
3314
|
+
const tolerance = object.tolerances?.find((entry) => entry.field === field)?.value;
|
|
3315
|
+
if (typeof tolerance === "number") {
|
|
3316
|
+
return tolerance;
|
|
3317
|
+
}
|
|
3318
|
+
if (tolerance && typeof tolerance === "object" && "value" in tolerance) {
|
|
3319
|
+
return durationInDays(tolerance) ?? 0;
|
|
3320
|
+
}
|
|
3321
|
+
return 0;
|
|
3322
|
+
}
|
|
3323
|
+
function formatDays(days) {
|
|
3324
|
+
return `${Math.round(days * 100) / 100}d`;
|
|
3325
|
+
}
|
|
3326
|
+
function error(code, message, objectId, field) {
|
|
3327
|
+
return { code, severity: "error", source: "validate", message, objectId, field };
|
|
3328
|
+
}
|
|
3329
|
+
function warn(code, message, objectId, field) {
|
|
3330
|
+
return { code, severity: "warning", source: "validate", message, objectId, field };
|
|
3331
|
+
}
|
|
3332
|
+
function info(code, message, objectId, field) {
|
|
3333
|
+
return { code, severity: "info", source: "validate", message, objectId, field };
|
|
3334
|
+
}
|
|
3335
|
+
|
|
2790
3336
|
// packages/core/dist/draft-parse.js
|
|
3337
|
+
var STRUCTURED_TYPED_BLOCKS = /* @__PURE__ */ new Set([
|
|
3338
|
+
"climate",
|
|
3339
|
+
"habitability",
|
|
3340
|
+
"settlement"
|
|
3341
|
+
]);
|
|
3342
|
+
var DRAFT_OBJECT_FIELD_SPECS = /* @__PURE__ */ new Map();
|
|
3343
|
+
for (const key of [
|
|
3344
|
+
"orbit",
|
|
3345
|
+
"distance",
|
|
3346
|
+
"semiMajor",
|
|
3347
|
+
"eccentricity",
|
|
3348
|
+
"period",
|
|
3349
|
+
"angle",
|
|
3350
|
+
"inclination",
|
|
3351
|
+
"phase",
|
|
3352
|
+
"at",
|
|
3353
|
+
"surface",
|
|
3354
|
+
"free",
|
|
3355
|
+
"kind",
|
|
3356
|
+
"class",
|
|
3357
|
+
"culture",
|
|
3358
|
+
"tags",
|
|
3359
|
+
"color",
|
|
3360
|
+
"image",
|
|
3361
|
+
"hidden",
|
|
3362
|
+
"radius",
|
|
3363
|
+
"mass",
|
|
3364
|
+
"density",
|
|
3365
|
+
"gravity",
|
|
3366
|
+
"temperature",
|
|
3367
|
+
"albedo",
|
|
3368
|
+
"atmosphere",
|
|
3369
|
+
"inner",
|
|
3370
|
+
"outer",
|
|
3371
|
+
"on",
|
|
3372
|
+
"source",
|
|
3373
|
+
"cycle"
|
|
3374
|
+
]) {
|
|
3375
|
+
const schema = getFieldSchema(key);
|
|
3376
|
+
if (schema) {
|
|
3377
|
+
DRAFT_OBJECT_FIELD_SPECS.set(key, {
|
|
3378
|
+
key,
|
|
3379
|
+
version: "2.0",
|
|
3380
|
+
inlineMode: schema.arity === "multiple" ? "multiple" : "single",
|
|
3381
|
+
allowRepeat: false,
|
|
3382
|
+
legacySchema: schema
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
for (const spec of [
|
|
3387
|
+
{ key: "groups", inlineMode: "multiple", allowRepeat: false },
|
|
3388
|
+
{ key: "epoch", inlineMode: "single", allowRepeat: false },
|
|
3389
|
+
{ key: "referencePlane", inlineMode: "single", allowRepeat: false },
|
|
3390
|
+
{ key: "tidalLock", inlineMode: "single", allowRepeat: false },
|
|
3391
|
+
{ key: "renderLabel", inlineMode: "single", allowRepeat: false },
|
|
3392
|
+
{ key: "renderOrbit", inlineMode: "single", allowRepeat: false },
|
|
3393
|
+
{ key: "renderPriority", inlineMode: "single", allowRepeat: false },
|
|
3394
|
+
{ key: "resonance", inlineMode: "pair", allowRepeat: false },
|
|
3395
|
+
{ key: "derive", inlineMode: "pair", allowRepeat: true },
|
|
3396
|
+
{ key: "validate", inlineMode: "single", allowRepeat: true },
|
|
3397
|
+
{ key: "locked", inlineMode: "multiple", allowRepeat: false },
|
|
3398
|
+
{ key: "tolerance", inlineMode: "pair", allowRepeat: true }
|
|
3399
|
+
]) {
|
|
3400
|
+
DRAFT_OBJECT_FIELD_SPECS.set(spec.key, {
|
|
3401
|
+
key: spec.key,
|
|
3402
|
+
version: "2.1",
|
|
3403
|
+
inlineMode: spec.inlineMode,
|
|
3404
|
+
allowRepeat: spec.allowRepeat
|
|
3405
|
+
});
|
|
3406
|
+
}
|
|
3407
|
+
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
2791
3408
|
function parseWorldOrbitAtlas(source) {
|
|
2792
|
-
return parseAtlasSource(source
|
|
3409
|
+
return parseAtlasSource(source);
|
|
2793
3410
|
}
|
|
2794
|
-
function parseAtlasSource(source,
|
|
2795
|
-
const
|
|
3411
|
+
function parseAtlasSource(source, forcedOutputVersion) {
|
|
3412
|
+
const prepared = preprocessAtlasSource(source);
|
|
3413
|
+
const lines = prepared.source.split(/\r?\n/);
|
|
3414
|
+
const diagnostics = [];
|
|
2796
3415
|
let sawSchemaHeader = false;
|
|
2797
|
-
let
|
|
3416
|
+
let sourceSchemaVersion = "2.0";
|
|
2798
3417
|
let system = null;
|
|
2799
3418
|
let section = null;
|
|
2800
3419
|
const objectNodes = [];
|
|
3420
|
+
const groups = [];
|
|
3421
|
+
const relations = [];
|
|
2801
3422
|
let sawDefaults = false;
|
|
2802
3423
|
let sawAtlas = false;
|
|
2803
3424
|
const viewpointIds = /* @__PURE__ */ new Set();
|
|
2804
3425
|
const annotationIds = /* @__PURE__ */ new Set();
|
|
3426
|
+
const groupIds = /* @__PURE__ */ new Set();
|
|
3427
|
+
const relationIds = /* @__PURE__ */ new Set();
|
|
2805
3428
|
for (let index = 0; index < lines.length; index++) {
|
|
2806
3429
|
const rawLine = lines[index];
|
|
2807
3430
|
const lineNumber = index + 1;
|
|
@@ -2817,15 +3440,22 @@ var WorldOrbit = (() => {
|
|
|
2817
3440
|
continue;
|
|
2818
3441
|
}
|
|
2819
3442
|
if (!sawSchemaHeader) {
|
|
2820
|
-
|
|
3443
|
+
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
2821
3444
|
sawSchemaHeader = true;
|
|
3445
|
+
if (prepared.comments.length > 0 && sourceSchemaVersion !== "2.1") {
|
|
3446
|
+
diagnostics.push({
|
|
3447
|
+
code: "parse.schema21.commentCompatibility",
|
|
3448
|
+
severity: "warning",
|
|
3449
|
+
source: "parse",
|
|
3450
|
+
message: `Comments require schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
3451
|
+
line: prepared.comments[0].line,
|
|
3452
|
+
column: prepared.comments[0].column
|
|
3453
|
+
});
|
|
3454
|
+
}
|
|
2822
3455
|
continue;
|
|
2823
3456
|
}
|
|
2824
3457
|
if (indent === 0) {
|
|
2825
|
-
section = startTopLevelSection(tokens, lineNumber, system, objectNodes, viewpointIds, annotationIds, {
|
|
2826
|
-
sawDefaults,
|
|
2827
|
-
sawAtlas
|
|
2828
|
-
});
|
|
3458
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
2829
3459
|
if (section.kind === "system") {
|
|
2830
3460
|
system = section.system;
|
|
2831
3461
|
} else if (section.kind === "defaults") {
|
|
@@ -2843,48 +3473,57 @@ var WorldOrbit = (() => {
|
|
|
2843
3473
|
if (!sawSchemaHeader) {
|
|
2844
3474
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
2845
3475
|
}
|
|
2846
|
-
const
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
};
|
|
2850
|
-
const normalizedObjects = normalizeDocument(ast).objects;
|
|
2851
|
-
validateDocument({
|
|
2852
|
-
format: "worldorbit",
|
|
2853
|
-
version: "1.0",
|
|
2854
|
-
system: null,
|
|
2855
|
-
objects: normalizedObjects
|
|
2856
|
-
});
|
|
2857
|
-
const diagnostics = schemaVersion === "2.0-draft" && outputVersion === "2.0" ? [
|
|
2858
|
-
{
|
|
2859
|
-
code: "load.schema.deprecatedDraft",
|
|
2860
|
-
severity: "warning",
|
|
2861
|
-
source: "upgrade",
|
|
2862
|
-
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
2863
|
-
}
|
|
2864
|
-
] : [];
|
|
2865
|
-
return {
|
|
3476
|
+
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
3477
|
+
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3478
|
+
const baseDocument = {
|
|
2866
3479
|
format: "worldorbit",
|
|
2867
|
-
version: outputVersion,
|
|
2868
3480
|
sourceVersion: "1.0",
|
|
2869
3481
|
system,
|
|
2870
|
-
|
|
3482
|
+
groups,
|
|
3483
|
+
relations,
|
|
3484
|
+
objects,
|
|
2871
3485
|
diagnostics
|
|
2872
3486
|
};
|
|
3487
|
+
if (outputVersion === "2.0-draft") {
|
|
3488
|
+
const document3 = {
|
|
3489
|
+
...baseDocument,
|
|
3490
|
+
version: "2.0-draft",
|
|
3491
|
+
schemaVersion: "2.0-draft"
|
|
3492
|
+
};
|
|
3493
|
+
document3.diagnostics.push(...collectAtlasDiagnostics(document3, sourceSchemaVersion));
|
|
3494
|
+
return document3;
|
|
3495
|
+
}
|
|
3496
|
+
const document2 = {
|
|
3497
|
+
...baseDocument,
|
|
3498
|
+
version: outputVersion,
|
|
3499
|
+
schemaVersion: outputVersion
|
|
3500
|
+
};
|
|
3501
|
+
if (sourceSchemaVersion === "2.0-draft") {
|
|
3502
|
+
document2.diagnostics.push({
|
|
3503
|
+
code: "load.schema.deprecatedDraft",
|
|
3504
|
+
severity: "warning",
|
|
3505
|
+
source: "upgrade",
|
|
3506
|
+
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
3507
|
+
});
|
|
3508
|
+
}
|
|
3509
|
+
document2.diagnostics.push(...collectAtlasDiagnostics(document2, sourceSchemaVersion));
|
|
3510
|
+
return document2;
|
|
2873
3511
|
}
|
|
2874
3512
|
function assertDraftSchemaHeader(tokens, line) {
|
|
2875
|
-
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" ||
|
|
2876
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0" or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
3513
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1"].includes(tokens[1].value.toLowerCase())) {
|
|
3514
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
2877
3515
|
}
|
|
2878
|
-
|
|
3516
|
+
const version = tokens[1].value.toLowerCase();
|
|
3517
|
+
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
2879
3518
|
}
|
|
2880
|
-
function startTopLevelSection(tokens, line, system, objectNodes, viewpointIds, annotationIds, flags) {
|
|
3519
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
2881
3520
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
2882
3521
|
switch (keyword) {
|
|
2883
3522
|
case "system":
|
|
2884
3523
|
if (system) {
|
|
2885
3524
|
throw new WorldOrbitError('Atlas section "system" may only appear once', line, tokens[0].column);
|
|
2886
3525
|
}
|
|
2887
|
-
return startSystemSection(tokens, line);
|
|
3526
|
+
return startSystemSection(tokens, line, sourceSchemaVersion, diagnostics);
|
|
2888
3527
|
case "defaults":
|
|
2889
3528
|
if (!system) {
|
|
2890
3529
|
throw new WorldOrbitError('Atlas section "defaults" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -2920,13 +3559,19 @@ var WorldOrbit = (() => {
|
|
|
2920
3559
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
2921
3560
|
}
|
|
2922
3561
|
return startAnnotationSection(tokens, line, system, annotationIds);
|
|
3562
|
+
case "group":
|
|
3563
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "group", { line, column: tokens[0].column });
|
|
3564
|
+
return startGroupSection(tokens, line, groups, groupIds);
|
|
3565
|
+
case "relation":
|
|
3566
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
3567
|
+
return startRelationSection(tokens, line, relations, relationIds);
|
|
2923
3568
|
case "object":
|
|
2924
|
-
return startObjectSection(tokens, line, objectNodes);
|
|
3569
|
+
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
2925
3570
|
default:
|
|
2926
3571
|
throw new WorldOrbitError(`Unknown atlas section "${tokens[0]?.value ?? ""}"`, line, tokens[0]?.column ?? 1);
|
|
2927
3572
|
}
|
|
2928
3573
|
}
|
|
2929
|
-
function startSystemSection(tokens, line) {
|
|
3574
|
+
function startSystemSection(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
2930
3575
|
if (tokens.length !== 2) {
|
|
2931
3576
|
throw new WorldOrbitError("Invalid atlas system declaration", line, tokens[0]?.column ?? 1);
|
|
2932
3577
|
}
|
|
@@ -2934,6 +3579,9 @@ var WorldOrbit = (() => {
|
|
|
2934
3579
|
type: "system",
|
|
2935
3580
|
id: tokens[1].value,
|
|
2936
3581
|
title: null,
|
|
3582
|
+
description: null,
|
|
3583
|
+
epoch: null,
|
|
3584
|
+
referencePlane: null,
|
|
2937
3585
|
defaults: {
|
|
2938
3586
|
view: "topdown",
|
|
2939
3587
|
scale: null,
|
|
@@ -2948,6 +3596,8 @@ var WorldOrbit = (() => {
|
|
|
2948
3596
|
return {
|
|
2949
3597
|
kind: "system",
|
|
2950
3598
|
system,
|
|
3599
|
+
sourceSchemaVersion,
|
|
3600
|
+
diagnostics,
|
|
2951
3601
|
seenFields: /* @__PURE__ */ new Set()
|
|
2952
3602
|
};
|
|
2953
3603
|
}
|
|
@@ -3013,7 +3663,64 @@ var WorldOrbit = (() => {
|
|
|
3013
3663
|
seenFields: /* @__PURE__ */ new Set()
|
|
3014
3664
|
};
|
|
3015
3665
|
}
|
|
3016
|
-
function
|
|
3666
|
+
function startGroupSection(tokens, line, groups, groupIds) {
|
|
3667
|
+
if (tokens.length !== 2) {
|
|
3668
|
+
throw new WorldOrbitError("Invalid group declaration", line, tokens[0]?.column ?? 1);
|
|
3669
|
+
}
|
|
3670
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
3671
|
+
if (!id) {
|
|
3672
|
+
throw new WorldOrbitError("Group id must not be empty", line, tokens[1].column);
|
|
3673
|
+
}
|
|
3674
|
+
if (groupIds.has(id)) {
|
|
3675
|
+
throw new WorldOrbitError(`Duplicate group id "${id}"`, line, tokens[1].column);
|
|
3676
|
+
}
|
|
3677
|
+
const group = {
|
|
3678
|
+
id,
|
|
3679
|
+
label: humanizeIdentifier2(id),
|
|
3680
|
+
summary: "",
|
|
3681
|
+
color: null,
|
|
3682
|
+
tags: [],
|
|
3683
|
+
hidden: false
|
|
3684
|
+
};
|
|
3685
|
+
groups.push(group);
|
|
3686
|
+
groupIds.add(id);
|
|
3687
|
+
return {
|
|
3688
|
+
kind: "group",
|
|
3689
|
+
group,
|
|
3690
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
3691
|
+
};
|
|
3692
|
+
}
|
|
3693
|
+
function startRelationSection(tokens, line, relations, relationIds) {
|
|
3694
|
+
if (tokens.length !== 2) {
|
|
3695
|
+
throw new WorldOrbitError("Invalid relation declaration", line, tokens[0]?.column ?? 1);
|
|
3696
|
+
}
|
|
3697
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
3698
|
+
if (!id) {
|
|
3699
|
+
throw new WorldOrbitError("Relation id must not be empty", line, tokens[1].column);
|
|
3700
|
+
}
|
|
3701
|
+
if (relationIds.has(id)) {
|
|
3702
|
+
throw new WorldOrbitError(`Duplicate relation id "${id}"`, line, tokens[1].column);
|
|
3703
|
+
}
|
|
3704
|
+
const relation = {
|
|
3705
|
+
id,
|
|
3706
|
+
from: "",
|
|
3707
|
+
to: "",
|
|
3708
|
+
kind: "",
|
|
3709
|
+
label: null,
|
|
3710
|
+
summary: null,
|
|
3711
|
+
tags: [],
|
|
3712
|
+
color: null,
|
|
3713
|
+
hidden: false
|
|
3714
|
+
};
|
|
3715
|
+
relations.push(relation);
|
|
3716
|
+
relationIds.add(id);
|
|
3717
|
+
return {
|
|
3718
|
+
kind: "relation",
|
|
3719
|
+
relation,
|
|
3720
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
3721
|
+
};
|
|
3722
|
+
}
|
|
3723
|
+
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
3017
3724
|
if (tokens.length < 3) {
|
|
3018
3725
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
3019
3726
|
}
|
|
@@ -3024,12 +3731,11 @@ var WorldOrbit = (() => {
|
|
|
3024
3731
|
throw new WorldOrbitError(`Unknown object type "${objectTypeToken.value}"`, line, objectTypeToken.column);
|
|
3025
3732
|
}
|
|
3026
3733
|
const objectNode = {
|
|
3027
|
-
type: "object",
|
|
3028
3734
|
objectType,
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
blockFields: [],
|
|
3735
|
+
id: idToken.value,
|
|
3736
|
+
fields: parseInlineObjectFields(tokens.slice(3), line, objectType, sourceSchemaVersion, diagnostics),
|
|
3032
3737
|
infoEntries: [],
|
|
3738
|
+
typedBlockEntries: {},
|
|
3033
3739
|
location: {
|
|
3034
3740
|
line,
|
|
3035
3741
|
column: objectTypeToken.column
|
|
@@ -3039,8 +3745,12 @@ var WorldOrbit = (() => {
|
|
|
3039
3745
|
return {
|
|
3040
3746
|
kind: "object",
|
|
3041
3747
|
objectNode,
|
|
3042
|
-
|
|
3043
|
-
|
|
3748
|
+
sourceSchemaVersion,
|
|
3749
|
+
diagnostics,
|
|
3750
|
+
activeBlock: null,
|
|
3751
|
+
blockIndent: null,
|
|
3752
|
+
seenInfoKeys: /* @__PURE__ */ new Set(),
|
|
3753
|
+
seenTypedBlockKeys: {}
|
|
3044
3754
|
};
|
|
3045
3755
|
}
|
|
3046
3756
|
function handleSectionLine(section, indent, tokens, line) {
|
|
@@ -3060,6 +3770,12 @@ var WorldOrbit = (() => {
|
|
|
3060
3770
|
case "annotation":
|
|
3061
3771
|
applyAnnotationField(section, tokens, line);
|
|
3062
3772
|
return;
|
|
3773
|
+
case "group":
|
|
3774
|
+
applyGroupField(section, tokens, line);
|
|
3775
|
+
return;
|
|
3776
|
+
case "relation":
|
|
3777
|
+
applyRelationField(section, tokens, line);
|
|
3778
|
+
return;
|
|
3063
3779
|
case "object":
|
|
3064
3780
|
applyObjectField(section, indent, tokens, line);
|
|
3065
3781
|
return;
|
|
@@ -3067,10 +3783,35 @@ var WorldOrbit = (() => {
|
|
|
3067
3783
|
}
|
|
3068
3784
|
function applySystemField(section, tokens, line) {
|
|
3069
3785
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
3070
|
-
|
|
3071
|
-
|
|
3786
|
+
const value = joinFieldValue(tokens, line);
|
|
3787
|
+
switch (key) {
|
|
3788
|
+
case "title":
|
|
3789
|
+
section.system.title = value;
|
|
3790
|
+
return;
|
|
3791
|
+
case "description":
|
|
3792
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
3793
|
+
line,
|
|
3794
|
+
column: tokens[0].column
|
|
3795
|
+
});
|
|
3796
|
+
section.system.description = value;
|
|
3797
|
+
return;
|
|
3798
|
+
case "epoch":
|
|
3799
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
3800
|
+
line,
|
|
3801
|
+
column: tokens[0].column
|
|
3802
|
+
});
|
|
3803
|
+
section.system.epoch = value;
|
|
3804
|
+
return;
|
|
3805
|
+
case "referenceplane":
|
|
3806
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "referencePlane", {
|
|
3807
|
+
line,
|
|
3808
|
+
column: tokens[0].column
|
|
3809
|
+
});
|
|
3810
|
+
section.system.referencePlane = value;
|
|
3811
|
+
return;
|
|
3812
|
+
default:
|
|
3813
|
+
throw new WorldOrbitError(`Unknown system atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3072
3814
|
}
|
|
3073
|
-
section.system.title = joinFieldValue(tokens, line);
|
|
3074
3815
|
}
|
|
3075
3816
|
function applyDefaultsField(section, tokens, line) {
|
|
3076
3817
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
@@ -3101,14 +3842,11 @@ var WorldOrbit = (() => {
|
|
|
3101
3842
|
section.metadataIndent = null;
|
|
3102
3843
|
}
|
|
3103
3844
|
if (section.inMetadata) {
|
|
3104
|
-
|
|
3105
|
-
|
|
3845
|
+
const entry = parseInfoLikeEntry(tokens, line, "Invalid atlas metadata entry");
|
|
3846
|
+
if (entry.key in section.system.atlasMetadata) {
|
|
3847
|
+
throw new WorldOrbitError(`Duplicate atlas metadata key "${entry.key}"`, line, tokens[0].column);
|
|
3106
3848
|
}
|
|
3107
|
-
|
|
3108
|
-
if (key in section.system.atlasMetadata) {
|
|
3109
|
-
throw new WorldOrbitError(`Duplicate atlas metadata key "${key}"`, line, tokens[0].column);
|
|
3110
|
-
}
|
|
3111
|
-
section.system.atlasMetadata[key] = joinFieldValue(tokens, line);
|
|
3849
|
+
section.system.atlasMetadata[entry.key] = entry.value;
|
|
3112
3850
|
return;
|
|
3113
3851
|
}
|
|
3114
3852
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "metadata") {
|
|
@@ -3187,44 +3925,125 @@ var WorldOrbit = (() => {
|
|
|
3187
3925
|
filter.groupIds = parseTokenList(tokens.slice(1), line, "groups");
|
|
3188
3926
|
break;
|
|
3189
3927
|
default:
|
|
3190
|
-
throw new WorldOrbitError(`Unknown viewpoint filter field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3928
|
+
throw new WorldOrbitError(`Unknown viewpoint filter field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3929
|
+
}
|
|
3930
|
+
section.viewpoint.filter = filter;
|
|
3931
|
+
}
|
|
3932
|
+
function applyAnnotationField(section, tokens, line) {
|
|
3933
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
3934
|
+
switch (key) {
|
|
3935
|
+
case "label":
|
|
3936
|
+
section.annotation.label = joinFieldValue(tokens, line);
|
|
3937
|
+
return;
|
|
3938
|
+
case "target":
|
|
3939
|
+
section.annotation.targetObjectId = joinFieldValue(tokens, line);
|
|
3940
|
+
return;
|
|
3941
|
+
case "body":
|
|
3942
|
+
section.annotation.body = joinFieldValue(tokens, line);
|
|
3943
|
+
return;
|
|
3944
|
+
case "tags":
|
|
3945
|
+
section.annotation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
3946
|
+
return;
|
|
3947
|
+
default:
|
|
3948
|
+
throw new WorldOrbitError(`Unknown annotation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
function applyGroupField(section, tokens, line) {
|
|
3952
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
3953
|
+
switch (key) {
|
|
3954
|
+
case "label":
|
|
3955
|
+
section.group.label = joinFieldValue(tokens, line);
|
|
3956
|
+
return;
|
|
3957
|
+
case "summary":
|
|
3958
|
+
section.group.summary = joinFieldValue(tokens, line);
|
|
3959
|
+
return;
|
|
3960
|
+
case "color":
|
|
3961
|
+
section.group.color = joinFieldValue(tokens, line);
|
|
3962
|
+
return;
|
|
3963
|
+
case "tags":
|
|
3964
|
+
section.group.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
3965
|
+
return;
|
|
3966
|
+
case "hidden":
|
|
3967
|
+
section.group.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
3968
|
+
line,
|
|
3969
|
+
column: tokens[0].column
|
|
3970
|
+
});
|
|
3971
|
+
return;
|
|
3972
|
+
default:
|
|
3973
|
+
throw new WorldOrbitError(`Unknown group field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3191
3974
|
}
|
|
3192
|
-
section.viewpoint.filter = filter;
|
|
3193
3975
|
}
|
|
3194
|
-
function
|
|
3976
|
+
function applyRelationField(section, tokens, line) {
|
|
3195
3977
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
3196
3978
|
switch (key) {
|
|
3197
|
-
case "
|
|
3198
|
-
section.
|
|
3979
|
+
case "from":
|
|
3980
|
+
section.relation.from = joinFieldValue(tokens, line);
|
|
3199
3981
|
return;
|
|
3200
|
-
case "
|
|
3201
|
-
section.
|
|
3982
|
+
case "to":
|
|
3983
|
+
section.relation.to = joinFieldValue(tokens, line);
|
|
3202
3984
|
return;
|
|
3203
|
-
case "
|
|
3204
|
-
section.
|
|
3985
|
+
case "kind":
|
|
3986
|
+
section.relation.kind = joinFieldValue(tokens, line);
|
|
3987
|
+
return;
|
|
3988
|
+
case "label":
|
|
3989
|
+
section.relation.label = joinFieldValue(tokens, line);
|
|
3990
|
+
return;
|
|
3991
|
+
case "summary":
|
|
3992
|
+
section.relation.summary = joinFieldValue(tokens, line);
|
|
3205
3993
|
return;
|
|
3206
3994
|
case "tags":
|
|
3207
|
-
section.
|
|
3995
|
+
section.relation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
3996
|
+
return;
|
|
3997
|
+
case "color":
|
|
3998
|
+
section.relation.color = joinFieldValue(tokens, line);
|
|
3999
|
+
return;
|
|
4000
|
+
case "hidden":
|
|
4001
|
+
section.relation.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4002
|
+
line,
|
|
4003
|
+
column: tokens[0].column
|
|
4004
|
+
});
|
|
3208
4005
|
return;
|
|
3209
4006
|
default:
|
|
3210
|
-
throw new WorldOrbitError(`Unknown
|
|
4007
|
+
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3211
4008
|
}
|
|
3212
4009
|
}
|
|
3213
4010
|
function applyObjectField(section, indent, tokens, line) {
|
|
3214
|
-
if (
|
|
3215
|
-
section.
|
|
3216
|
-
section.
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
4011
|
+
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
4012
|
+
section.activeBlock = null;
|
|
4013
|
+
section.blockIndent = null;
|
|
4014
|
+
}
|
|
4015
|
+
if (tokens.length === 1) {
|
|
4016
|
+
const blockName = tokens[0].value.toLowerCase();
|
|
4017
|
+
if (blockName === "info" || STRUCTURED_TYPED_BLOCKS.has(blockName)) {
|
|
4018
|
+
if (blockName !== "info") {
|
|
4019
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, blockName, { line, column: tokens[0].column });
|
|
4020
|
+
}
|
|
4021
|
+
section.activeBlock = blockName;
|
|
4022
|
+
section.blockIndent = indent;
|
|
4023
|
+
return;
|
|
4024
|
+
}
|
|
3222
4025
|
}
|
|
3223
|
-
if (section.
|
|
3224
|
-
|
|
4026
|
+
if (section.activeBlock) {
|
|
4027
|
+
const entry = parseInfoLikeEntry(tokens, line, `Invalid ${section.activeBlock} entry`);
|
|
4028
|
+
if (section.activeBlock === "info") {
|
|
4029
|
+
if (section.seenInfoKeys.has(entry.key)) {
|
|
4030
|
+
throw new WorldOrbitError(`Duplicate info key "${entry.key}"`, line, tokens[0].column);
|
|
4031
|
+
}
|
|
4032
|
+
section.seenInfoKeys.add(entry.key);
|
|
4033
|
+
section.objectNode.infoEntries.push(entry);
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
const typedBlock = section.activeBlock;
|
|
4037
|
+
const seenKeys = section.seenTypedBlockKeys[typedBlock] ?? (section.seenTypedBlockKeys[typedBlock] = /* @__PURE__ */ new Set());
|
|
4038
|
+
if (seenKeys.has(entry.key)) {
|
|
4039
|
+
throw new WorldOrbitError(`Duplicate ${typedBlock} key "${entry.key}"`, line, tokens[0].column);
|
|
4040
|
+
}
|
|
4041
|
+
seenKeys.add(entry.key);
|
|
4042
|
+
const entries = section.objectNode.typedBlockEntries[typedBlock] ?? (section.objectNode.typedBlockEntries[typedBlock] = []);
|
|
4043
|
+
entries.push(entry);
|
|
3225
4044
|
return;
|
|
3226
4045
|
}
|
|
3227
|
-
section.objectNode.
|
|
4046
|
+
section.objectNode.fields.push(parseObjectField(tokens, line, section.objectNode.objectType, section.sourceSchemaVersion, section.diagnostics));
|
|
3228
4047
|
}
|
|
3229
4048
|
function requireUniqueField(tokens, seenFields, line) {
|
|
3230
4049
|
if (tokens.length < 2) {
|
|
@@ -3244,50 +4063,40 @@ var WorldOrbit = (() => {
|
|
|
3244
4063
|
return tokens.slice(1).map((token) => token.value).join(" ").trim();
|
|
3245
4064
|
}
|
|
3246
4065
|
function parseObjectTypeTokens(tokens, line) {
|
|
3247
|
-
|
|
3248
|
-
throw new WorldOrbitError("Missing value for atlas field", line);
|
|
3249
|
-
}
|
|
3250
|
-
return tokens.map((token) => {
|
|
3251
|
-
const value = token.value;
|
|
3252
|
-
if (value !== "star" && value !== "planet" && value !== "moon" && value !== "belt" && value !== "asteroid" && value !== "comet" && value !== "ring" && value !== "structure" && value !== "phenomenon") {
|
|
3253
|
-
throw new WorldOrbitError(`Unknown viewpoint object type "${token.value}"`, line, token.column);
|
|
3254
|
-
}
|
|
3255
|
-
return value;
|
|
3256
|
-
});
|
|
3257
|
-
}
|
|
3258
|
-
function parseTokenList(tokens, line, field) {
|
|
3259
|
-
if (tokens.length === 0) {
|
|
3260
|
-
throw new WorldOrbitError(`Missing value for field "${field}"`, line);
|
|
3261
|
-
}
|
|
3262
|
-
return tokens.map((token) => token.value);
|
|
4066
|
+
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");
|
|
3263
4067
|
}
|
|
3264
4068
|
function parseLayerTokens(tokens, line) {
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
if (rawLayer === "orbits") {
|
|
3273
|
-
next["orbits-back"] = enabled;
|
|
3274
|
-
next["orbits-front"] = enabled;
|
|
4069
|
+
const layers = {};
|
|
4070
|
+
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
4071
|
+
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
4072
|
+
const raw = token.replace(/^[-!]+/, "").toLowerCase();
|
|
4073
|
+
if (raw === "orbits") {
|
|
4074
|
+
layers["orbits-back"] = enabled;
|
|
4075
|
+
layers["orbits-front"] = enabled;
|
|
3275
4076
|
continue;
|
|
3276
4077
|
}
|
|
3277
|
-
if (
|
|
3278
|
-
|
|
3279
|
-
continue;
|
|
4078
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4079
|
+
layers[raw] = enabled;
|
|
3280
4080
|
}
|
|
3281
|
-
throw new WorldOrbitError(`Unknown layer token "${token.value}"`, line, token.column);
|
|
3282
4081
|
}
|
|
3283
|
-
return
|
|
4082
|
+
return layers;
|
|
4083
|
+
}
|
|
4084
|
+
function parseTokenList(tokens, line, fieldName) {
|
|
4085
|
+
if (tokens.length === 0) {
|
|
4086
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, 1);
|
|
4087
|
+
}
|
|
4088
|
+
const values = tokens.map((token) => token.value).filter(Boolean);
|
|
4089
|
+
if (values.length === 0) {
|
|
4090
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, tokens[0]?.column ?? 1);
|
|
4091
|
+
}
|
|
4092
|
+
return values;
|
|
3284
4093
|
}
|
|
3285
4094
|
function parseProjectionValue(value, line, column) {
|
|
3286
4095
|
const normalized = value.toLowerCase();
|
|
3287
|
-
if (normalized
|
|
3288
|
-
|
|
4096
|
+
if (normalized !== "topdown" && normalized !== "isometric") {
|
|
4097
|
+
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
3289
4098
|
}
|
|
3290
|
-
|
|
4099
|
+
return normalized;
|
|
3291
4100
|
}
|
|
3292
4101
|
function parsePresetValue(value, line, column) {
|
|
3293
4102
|
const normalized = value.toLowerCase();
|
|
@@ -3297,16 +4106,16 @@ var WorldOrbit = (() => {
|
|
|
3297
4106
|
throw new WorldOrbitError(`Unknown render preset "${value}"`, line, column);
|
|
3298
4107
|
}
|
|
3299
4108
|
function parsePositiveNumber2(value, line, column, field) {
|
|
3300
|
-
const parsed =
|
|
3301
|
-
if (
|
|
3302
|
-
throw new WorldOrbitError(`Field "${field}"
|
|
4109
|
+
const parsed = parseFiniteNumber2(value, line, column, field);
|
|
4110
|
+
if (parsed <= 0) {
|
|
4111
|
+
throw new WorldOrbitError(`Field "${field}" must be greater than zero`, line, column);
|
|
3303
4112
|
}
|
|
3304
4113
|
return parsed;
|
|
3305
4114
|
}
|
|
3306
4115
|
function parseFiniteNumber2(value, line, column, field) {
|
|
3307
4116
|
const parsed = Number(value);
|
|
3308
4117
|
if (!Number.isFinite(parsed)) {
|
|
3309
|
-
throw new WorldOrbitError(`
|
|
4118
|
+
throw new WorldOrbitError(`Invalid numeric value "${value}" for "${field}"`, line, column);
|
|
3310
4119
|
}
|
|
3311
4120
|
return parsed;
|
|
3312
4121
|
}
|
|
@@ -3318,28 +4127,43 @@ var WorldOrbit = (() => {
|
|
|
3318
4127
|
groupIds: []
|
|
3319
4128
|
};
|
|
3320
4129
|
}
|
|
3321
|
-
function
|
|
4130
|
+
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3322
4131
|
const fields = [];
|
|
3323
4132
|
let index = 0;
|
|
3324
4133
|
while (index < tokens.length) {
|
|
3325
4134
|
const keyToken = tokens[index];
|
|
3326
|
-
const
|
|
3327
|
-
if (!
|
|
4135
|
+
const spec = getDraftObjectFieldSpec(keyToken.value);
|
|
4136
|
+
if (!spec) {
|
|
3328
4137
|
throw new WorldOrbitError(`Unknown field "${keyToken.value}"`, line, keyToken.column);
|
|
3329
4138
|
}
|
|
4139
|
+
if (spec.version === "2.1") {
|
|
4140
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, keyToken.value, {
|
|
4141
|
+
line,
|
|
4142
|
+
column: keyToken.column
|
|
4143
|
+
});
|
|
4144
|
+
}
|
|
3330
4145
|
index++;
|
|
3331
4146
|
const valueTokens = [];
|
|
3332
|
-
if (
|
|
3333
|
-
while (index < tokens.length && !isKnownFieldKey(tokens[index].value)) {
|
|
3334
|
-
valueTokens.push(tokens[index]);
|
|
3335
|
-
index++;
|
|
3336
|
-
}
|
|
3337
|
-
} else {
|
|
4147
|
+
if (spec.inlineMode === "single") {
|
|
3338
4148
|
const nextToken = tokens[index];
|
|
3339
4149
|
if (nextToken) {
|
|
3340
4150
|
valueTokens.push(nextToken);
|
|
3341
4151
|
index++;
|
|
3342
4152
|
}
|
|
4153
|
+
} else if (spec.inlineMode === "pair") {
|
|
4154
|
+
for (let count = 0; count < 2; count++) {
|
|
4155
|
+
const nextToken = tokens[index];
|
|
4156
|
+
if (!nextToken) {
|
|
4157
|
+
break;
|
|
4158
|
+
}
|
|
4159
|
+
valueTokens.push(nextToken);
|
|
4160
|
+
index++;
|
|
4161
|
+
}
|
|
4162
|
+
} else {
|
|
4163
|
+
while (index < tokens.length && !DRAFT_OBJECT_FIELD_KEYS.has(tokens[index].value)) {
|
|
4164
|
+
valueTokens.push(tokens[index]);
|
|
4165
|
+
index++;
|
|
4166
|
+
}
|
|
3343
4167
|
}
|
|
3344
4168
|
if (valueTokens.length === 0) {
|
|
3345
4169
|
throw new WorldOrbitError(`Missing value for field "${keyToken.value}"`, line, keyToken.column);
|
|
@@ -3351,25 +4175,35 @@ var WorldOrbit = (() => {
|
|
|
3351
4175
|
location: { line, column: keyToken.column }
|
|
3352
4176
|
});
|
|
3353
4177
|
}
|
|
4178
|
+
validateDraftObjectFieldCompatibility(fields, objectType);
|
|
3354
4179
|
return fields;
|
|
3355
4180
|
}
|
|
3356
|
-
function
|
|
4181
|
+
function parseObjectField(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3357
4182
|
if (tokens.length < 2) {
|
|
3358
4183
|
throw new WorldOrbitError("Invalid field line", line, tokens[0]?.column ?? 1);
|
|
3359
4184
|
}
|
|
3360
|
-
|
|
4185
|
+
const spec = getDraftObjectFieldSpec(tokens[0].value);
|
|
4186
|
+
if (!spec) {
|
|
3361
4187
|
throw new WorldOrbitError(`Unknown field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3362
4188
|
}
|
|
3363
|
-
|
|
4189
|
+
if (spec.version === "2.1") {
|
|
4190
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, tokens[0].value, {
|
|
4191
|
+
line,
|
|
4192
|
+
column: tokens[0].column
|
|
4193
|
+
});
|
|
4194
|
+
}
|
|
4195
|
+
const field = {
|
|
3364
4196
|
type: "field",
|
|
3365
4197
|
key: tokens[0].value,
|
|
3366
4198
|
values: tokens.slice(1).map((token) => token.value),
|
|
3367
4199
|
location: { line, column: tokens[0].column }
|
|
3368
4200
|
};
|
|
4201
|
+
validateDraftObjectFieldCompatibility([field], objectType);
|
|
4202
|
+
return field;
|
|
3369
4203
|
}
|
|
3370
|
-
function
|
|
4204
|
+
function parseInfoLikeEntry(tokens, line, errorMessage) {
|
|
3371
4205
|
if (tokens.length < 2) {
|
|
3372
|
-
throw new WorldOrbitError(
|
|
4206
|
+
throw new WorldOrbitError(errorMessage, line, tokens[0]?.column ?? 1);
|
|
3373
4207
|
}
|
|
3374
4208
|
return {
|
|
3375
4209
|
type: "info-entry",
|
|
@@ -3378,18 +4212,348 @@ var WorldOrbit = (() => {
|
|
|
3378
4212
|
location: { line, column: tokens[0].column }
|
|
3379
4213
|
};
|
|
3380
4214
|
}
|
|
3381
|
-
function
|
|
3382
|
-
|
|
4215
|
+
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
4216
|
+
const fieldMap = collectDraftFields(node.fields);
|
|
4217
|
+
const placement = extractDraftPlacement(node.objectType, fieldMap);
|
|
4218
|
+
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
4219
|
+
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
4220
|
+
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
4221
|
+
const referencePlane = parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0]);
|
|
4222
|
+
const tidalLock = fieldMap.has("tidalLock") ? parseAtlasBoolean(singleFieldValue2(fieldMap.get("tidalLock")[0]), "tidalLock", fieldMap.get("tidalLock")[0].location) : void 0;
|
|
4223
|
+
const resonance = fieldMap.has("resonance") ? parseResonanceField(fieldMap.get("resonance")[0]) : void 0;
|
|
4224
|
+
const renderHints = extractRenderHints(fieldMap);
|
|
4225
|
+
const deriveRules = fieldMap.get("derive")?.map((field) => parseDeriveField(field));
|
|
4226
|
+
const validationRules = fieldMap.get("validate")?.map((field) => ({
|
|
4227
|
+
rule: singleFieldValue2(field)
|
|
4228
|
+
}));
|
|
4229
|
+
const lockedFields = fieldMap.has("locked") ? [...new Set(fieldMap.get("locked").flatMap((field) => field.values))] : void 0;
|
|
4230
|
+
const tolerances = fieldMap.get("tolerance")?.map((field) => parseToleranceField(field));
|
|
4231
|
+
const typedBlocks = normalizeTypedBlocks(node.typedBlockEntries);
|
|
4232
|
+
const info2 = normalizeInfoEntries(node.infoEntries, "info");
|
|
4233
|
+
const object = {
|
|
4234
|
+
type: node.objectType,
|
|
4235
|
+
id: node.id,
|
|
4236
|
+
properties,
|
|
4237
|
+
placement,
|
|
4238
|
+
info: info2
|
|
4239
|
+
};
|
|
4240
|
+
if (groups.length > 0)
|
|
4241
|
+
object.groups = groups;
|
|
4242
|
+
if (epoch)
|
|
4243
|
+
object.epoch = epoch;
|
|
4244
|
+
if (referencePlane)
|
|
4245
|
+
object.referencePlane = referencePlane;
|
|
4246
|
+
if (tidalLock !== void 0)
|
|
4247
|
+
object.tidalLock = tidalLock;
|
|
4248
|
+
if (resonance)
|
|
4249
|
+
object.resonance = resonance;
|
|
4250
|
+
if (renderHints)
|
|
4251
|
+
object.renderHints = renderHints;
|
|
4252
|
+
if (deriveRules?.length)
|
|
4253
|
+
object.deriveRules = deriveRules;
|
|
4254
|
+
if (validationRules?.length)
|
|
4255
|
+
object.validationRules = validationRules;
|
|
4256
|
+
if (lockedFields?.length)
|
|
4257
|
+
object.lockedFields = lockedFields;
|
|
4258
|
+
if (tolerances?.length)
|
|
4259
|
+
object.tolerances = tolerances;
|
|
4260
|
+
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
4261
|
+
object.typedBlocks = typedBlocks;
|
|
4262
|
+
if (sourceSchemaVersion !== "2.1") {
|
|
4263
|
+
if (object.groups || object.epoch || object.referencePlane || object.tidalLock !== void 0 || object.resonance || object.renderHints || object.deriveRules?.length || object.validationRules?.length || object.lockedFields?.length || object.tolerances?.length || object.typedBlocks) {
|
|
4264
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
return object;
|
|
4268
|
+
}
|
|
4269
|
+
function collectDraftFields(fields) {
|
|
4270
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4271
|
+
for (const field of fields) {
|
|
4272
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
4273
|
+
if (!spec) {
|
|
4274
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4275
|
+
}
|
|
4276
|
+
if (!spec.allowRepeat && grouped.has(field.key)) {
|
|
4277
|
+
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
4278
|
+
}
|
|
4279
|
+
const existing = grouped.get(field.key) ?? [];
|
|
4280
|
+
existing.push(field);
|
|
4281
|
+
grouped.set(field.key, existing);
|
|
4282
|
+
}
|
|
4283
|
+
return grouped;
|
|
3383
4284
|
}
|
|
3384
|
-
function
|
|
3385
|
-
|
|
4285
|
+
function extractDraftPlacement(objectType, fieldMap) {
|
|
4286
|
+
const orbitField = fieldMap.get("orbit")?.[0];
|
|
4287
|
+
const atField = fieldMap.get("at")?.[0];
|
|
4288
|
+
const surfaceField = fieldMap.get("surface")?.[0];
|
|
4289
|
+
const freeField = fieldMap.get("free")?.[0];
|
|
4290
|
+
const count = [orbitField, atField, surfaceField, freeField].filter(Boolean).length;
|
|
4291
|
+
if (count > 1) {
|
|
4292
|
+
const conflictingField = orbitField ?? atField ?? surfaceField ?? freeField;
|
|
4293
|
+
throw WorldOrbitError.fromLocation("Object has multiple placement modes", conflictingField?.location);
|
|
4294
|
+
}
|
|
4295
|
+
if (orbitField) {
|
|
4296
|
+
return {
|
|
4297
|
+
mode: "orbit",
|
|
4298
|
+
target: singleFieldValue2(orbitField),
|
|
4299
|
+
distance: parseOptionalUnitField(fieldMap.get("distance")?.[0], "distance"),
|
|
4300
|
+
semiMajor: parseOptionalUnitField(fieldMap.get("semiMajor")?.[0], "semiMajor"),
|
|
4301
|
+
eccentricity: parseOptionalNumberField(fieldMap.get("eccentricity")?.[0], "eccentricity"),
|
|
4302
|
+
period: parseOptionalUnitField(fieldMap.get("period")?.[0], "period"),
|
|
4303
|
+
angle: parseOptionalUnitField(fieldMap.get("angle")?.[0], "angle"),
|
|
4304
|
+
inclination: parseOptionalUnitField(fieldMap.get("inclination")?.[0], "inclination"),
|
|
4305
|
+
phase: parseOptionalUnitField(fieldMap.get("phase")?.[0], "phase")
|
|
4306
|
+
};
|
|
4307
|
+
}
|
|
4308
|
+
if (atField) {
|
|
4309
|
+
const target = singleFieldValue2(atField);
|
|
4310
|
+
return {
|
|
4311
|
+
mode: "at",
|
|
4312
|
+
target,
|
|
4313
|
+
reference: parseAtlasAtReference(target, atField.location)
|
|
4314
|
+
};
|
|
4315
|
+
}
|
|
4316
|
+
if (surfaceField) {
|
|
4317
|
+
return {
|
|
4318
|
+
mode: "surface",
|
|
4319
|
+
target: singleFieldValue2(surfaceField)
|
|
4320
|
+
};
|
|
4321
|
+
}
|
|
4322
|
+
if (freeField) {
|
|
4323
|
+
const raw = singleFieldValue2(freeField);
|
|
4324
|
+
const distance = tryParseAtlasUnitValue(raw);
|
|
4325
|
+
return {
|
|
4326
|
+
mode: "free",
|
|
4327
|
+
distance: distance ?? void 0,
|
|
4328
|
+
descriptor: distance ? void 0 : raw
|
|
4329
|
+
};
|
|
4330
|
+
}
|
|
4331
|
+
return null;
|
|
4332
|
+
}
|
|
4333
|
+
function normalizeDraftProperties(objectType, fieldMap) {
|
|
4334
|
+
const properties = {};
|
|
4335
|
+
for (const [key, fields] of fieldMap.entries()) {
|
|
4336
|
+
const field = fields[0];
|
|
4337
|
+
const spec = getDraftObjectFieldSpec(key);
|
|
4338
|
+
if (!field || !spec?.legacySchema || spec.legacySchema.placement) {
|
|
4339
|
+
continue;
|
|
4340
|
+
}
|
|
4341
|
+
ensureAtlasFieldSupported(key, objectType, field.location);
|
|
4342
|
+
properties[key] = normalizeLegacyScalarValue(key, field.values, field.location);
|
|
4343
|
+
}
|
|
4344
|
+
return properties;
|
|
4345
|
+
}
|
|
4346
|
+
function normalizeInfoEntries(entries, label) {
|
|
4347
|
+
const normalized = {};
|
|
4348
|
+
for (const entry of entries) {
|
|
4349
|
+
if (entry.key in normalized) {
|
|
4350
|
+
throw WorldOrbitError.fromLocation(`Duplicate ${label} key "${entry.key}"`, entry.location);
|
|
4351
|
+
}
|
|
4352
|
+
normalized[entry.key] = entry.value;
|
|
4353
|
+
}
|
|
4354
|
+
return normalized;
|
|
4355
|
+
}
|
|
4356
|
+
function normalizeTypedBlocks(typedBlockEntries) {
|
|
4357
|
+
const typedBlocks = {};
|
|
4358
|
+
for (const blockName of Object.keys(typedBlockEntries)) {
|
|
4359
|
+
const entries = typedBlockEntries[blockName];
|
|
4360
|
+
if (entries?.length) {
|
|
4361
|
+
typedBlocks[blockName] = normalizeInfoEntries(entries, blockName);
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
return typedBlocks;
|
|
4365
|
+
}
|
|
4366
|
+
function extractRenderHints(fieldMap) {
|
|
4367
|
+
const renderHints = {};
|
|
4368
|
+
const renderLabelField = fieldMap.get("renderLabel")?.[0];
|
|
4369
|
+
const renderOrbitField = fieldMap.get("renderOrbit")?.[0];
|
|
4370
|
+
const renderPriorityField = fieldMap.get("renderPriority")?.[0];
|
|
4371
|
+
if (renderLabelField) {
|
|
4372
|
+
renderHints.renderLabel = parseAtlasBoolean(singleFieldValue2(renderLabelField), "renderLabel", renderLabelField.location);
|
|
4373
|
+
}
|
|
4374
|
+
if (renderOrbitField) {
|
|
4375
|
+
renderHints.renderOrbit = parseAtlasBoolean(singleFieldValue2(renderOrbitField), "renderOrbit", renderOrbitField.location);
|
|
4376
|
+
}
|
|
4377
|
+
if (renderPriorityField) {
|
|
4378
|
+
renderHints.renderPriority = parseAtlasNumber(singleFieldValue2(renderPriorityField), "renderPriority", renderPriorityField.location);
|
|
4379
|
+
}
|
|
4380
|
+
return Object.keys(renderHints).length > 0 ? renderHints : void 0;
|
|
4381
|
+
}
|
|
4382
|
+
function parseResonanceField(field) {
|
|
4383
|
+
if (field.values.length !== 2) {
|
|
4384
|
+
throw WorldOrbitError.fromLocation('Field "resonance" expects "<targetObjectId> <ratio>"', field.location);
|
|
4385
|
+
}
|
|
4386
|
+
const ratio = field.values[1];
|
|
4387
|
+
if (!/^\d+:\d+$/.test(ratio)) {
|
|
4388
|
+
throw WorldOrbitError.fromLocation(`Invalid resonance ratio "${ratio}"`, field.location);
|
|
4389
|
+
}
|
|
4390
|
+
return {
|
|
4391
|
+
targetObjectId: field.values[0],
|
|
4392
|
+
ratio
|
|
4393
|
+
};
|
|
4394
|
+
}
|
|
4395
|
+
function parseDeriveField(field) {
|
|
4396
|
+
if (field.values.length !== 2) {
|
|
4397
|
+
throw WorldOrbitError.fromLocation('Field "derive" expects "<field> <strategy>"', field.location);
|
|
4398
|
+
}
|
|
4399
|
+
return {
|
|
4400
|
+
field: field.values[0],
|
|
4401
|
+
strategy: field.values[1]
|
|
4402
|
+
};
|
|
4403
|
+
}
|
|
4404
|
+
function parseToleranceField(field) {
|
|
4405
|
+
if (field.values.length !== 2) {
|
|
4406
|
+
throw WorldOrbitError.fromLocation('Field "tolerance" expects "<field> <value>"', field.location);
|
|
4407
|
+
}
|
|
4408
|
+
const rawValue = field.values[1];
|
|
4409
|
+
const unitValue = tryParseAtlasUnitValue(rawValue);
|
|
4410
|
+
const numericValue2 = Number(rawValue);
|
|
4411
|
+
return {
|
|
4412
|
+
field: field.values[0],
|
|
4413
|
+
value: unitValue ?? (Number.isFinite(numericValue2) ? numericValue2 : rawValue)
|
|
4414
|
+
};
|
|
4415
|
+
}
|
|
4416
|
+
function parseOptionalTokenList(field) {
|
|
4417
|
+
return field ? [...new Set(field.values)] : [];
|
|
4418
|
+
}
|
|
4419
|
+
function parseOptionalJoinedValue(field) {
|
|
4420
|
+
if (!field) {
|
|
4421
|
+
return null;
|
|
4422
|
+
}
|
|
4423
|
+
return field.values.join(" ").trim() || null;
|
|
4424
|
+
}
|
|
4425
|
+
function parseOptionalUnitField(field, key) {
|
|
4426
|
+
return field ? parseAtlasUnitValue(singleFieldValue2(field), field.location, key) : void 0;
|
|
4427
|
+
}
|
|
4428
|
+
function parseOptionalNumberField(field, key) {
|
|
4429
|
+
return field ? parseAtlasNumber(singleFieldValue2(field), key, field.location) : void 0;
|
|
4430
|
+
}
|
|
4431
|
+
function singleFieldValue2(field) {
|
|
4432
|
+
return singleAtlasValue(field.values, field.key, field.location);
|
|
4433
|
+
}
|
|
4434
|
+
function getDraftObjectFieldSpec(key) {
|
|
4435
|
+
return DRAFT_OBJECT_FIELD_SPECS.get(key);
|
|
4436
|
+
}
|
|
4437
|
+
function validateDraftObjectFieldCompatibility(fields, objectType) {
|
|
4438
|
+
for (const field of fields) {
|
|
4439
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
4440
|
+
if (!spec) {
|
|
4441
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4442
|
+
}
|
|
4443
|
+
if (spec.legacySchema) {
|
|
4444
|
+
ensureAtlasFieldSupported(field.key, objectType, field.location);
|
|
4445
|
+
continue;
|
|
4446
|
+
}
|
|
4447
|
+
if ((field.key === "renderLabel" || field.key === "renderOrbit" || field.key === "tidalLock") && field.values.length !== 1) {
|
|
4448
|
+
throw WorldOrbitError.fromLocation(`Field "${field.key}" expects exactly one value`, field.location);
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
4453
|
+
if (sourceSchemaVersion === "2.1") {
|
|
4454
|
+
return;
|
|
4455
|
+
}
|
|
4456
|
+
diagnostics.push({
|
|
4457
|
+
code: "parse.schema21.featureCompatibility",
|
|
4458
|
+
severity: "warning",
|
|
4459
|
+
source: "parse",
|
|
4460
|
+
message: `Feature "${featureName}" requires schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
4461
|
+
line: location.line,
|
|
4462
|
+
column: location.column
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4465
|
+
function preprocessAtlasSource(source) {
|
|
4466
|
+
const chars = [...source];
|
|
4467
|
+
const comments = [];
|
|
4468
|
+
let inString = false;
|
|
4469
|
+
let inBlockComment = false;
|
|
4470
|
+
let blockCommentStart = null;
|
|
4471
|
+
let line = 1;
|
|
4472
|
+
let column = 1;
|
|
4473
|
+
for (let index = 0; index < chars.length; index++) {
|
|
4474
|
+
const ch = chars[index];
|
|
4475
|
+
const next = chars[index + 1];
|
|
4476
|
+
if (inBlockComment) {
|
|
4477
|
+
if (ch === "*" && next === "/") {
|
|
4478
|
+
chars[index] = " ";
|
|
4479
|
+
chars[index + 1] = " ";
|
|
4480
|
+
inBlockComment = false;
|
|
4481
|
+
blockCommentStart = null;
|
|
4482
|
+
index++;
|
|
4483
|
+
column += 2;
|
|
4484
|
+
continue;
|
|
4485
|
+
}
|
|
4486
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
4487
|
+
chars[index] = " ";
|
|
4488
|
+
}
|
|
4489
|
+
if (ch === "\n") {
|
|
4490
|
+
line++;
|
|
4491
|
+
column = 1;
|
|
4492
|
+
} else {
|
|
4493
|
+
column++;
|
|
4494
|
+
}
|
|
4495
|
+
continue;
|
|
4496
|
+
}
|
|
4497
|
+
if (!inString && ch === "/" && next === "*") {
|
|
4498
|
+
comments.push({ kind: "block", line, column });
|
|
4499
|
+
chars[index] = " ";
|
|
4500
|
+
chars[index + 1] = " ";
|
|
4501
|
+
inBlockComment = true;
|
|
4502
|
+
blockCommentStart = { line, column };
|
|
4503
|
+
index++;
|
|
4504
|
+
column += 2;
|
|
4505
|
+
continue;
|
|
4506
|
+
}
|
|
4507
|
+
if (!inString && ch === "#" && !isHexColorLiteral(chars, index)) {
|
|
4508
|
+
comments.push({ kind: "line", line, column });
|
|
4509
|
+
chars[index] = " ";
|
|
4510
|
+
let inner = index + 1;
|
|
4511
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
4512
|
+
chars[inner] = " ";
|
|
4513
|
+
inner++;
|
|
4514
|
+
}
|
|
4515
|
+
column += inner - index;
|
|
4516
|
+
index = inner - 1;
|
|
4517
|
+
continue;
|
|
4518
|
+
}
|
|
4519
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
4520
|
+
inString = !inString;
|
|
4521
|
+
}
|
|
4522
|
+
if (ch === "\n") {
|
|
4523
|
+
line++;
|
|
4524
|
+
column = 1;
|
|
4525
|
+
} else {
|
|
4526
|
+
column++;
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
if (inBlockComment) {
|
|
4530
|
+
throw WorldOrbitError.fromLocation("Unclosed block comment", blockCommentStart ?? void 0);
|
|
4531
|
+
}
|
|
4532
|
+
return {
|
|
4533
|
+
source: chars.join(""),
|
|
4534
|
+
comments
|
|
4535
|
+
};
|
|
4536
|
+
}
|
|
4537
|
+
function isHexColorLiteral(chars, start) {
|
|
4538
|
+
let index = start + 1;
|
|
4539
|
+
let length = 0;
|
|
4540
|
+
while (index < chars.length && /[0-9a-f]/i.test(chars[index] ?? "")) {
|
|
4541
|
+
index++;
|
|
4542
|
+
length++;
|
|
4543
|
+
}
|
|
4544
|
+
if (![3, 4, 6, 8].includes(length)) {
|
|
4545
|
+
return false;
|
|
4546
|
+
}
|
|
4547
|
+
const next = chars[index];
|
|
4548
|
+
return next === void 0 || next === " " || next === " " || next === "\r" || next === "\n";
|
|
3386
4549
|
}
|
|
3387
4550
|
|
|
3388
4551
|
// packages/core/dist/load.js
|
|
3389
|
-
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0)?$/i;
|
|
4552
|
+
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|
|
4553
|
+
var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
3390
4554
|
var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
3391
4555
|
function detectWorldOrbitSchemaVersion(source) {
|
|
3392
|
-
for (const line of source.split(/\r?\n/)) {
|
|
4556
|
+
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
3393
4557
|
const trimmed = line.trim();
|
|
3394
4558
|
if (!trimmed) {
|
|
3395
4559
|
continue;
|
|
@@ -3397,6 +4561,9 @@ var WorldOrbit = (() => {
|
|
|
3397
4561
|
if (LEGACY_DRAFT_SCHEMA_PATTERN.test(trimmed)) {
|
|
3398
4562
|
return "2.0-draft";
|
|
3399
4563
|
}
|
|
4564
|
+
if (ATLAS_SCHEMA_21_PATTERN.test(trimmed)) {
|
|
4565
|
+
return "2.1";
|
|
4566
|
+
}
|
|
3400
4567
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
3401
4568
|
return "2.0";
|
|
3402
4569
|
}
|
|
@@ -3404,6 +4571,49 @@ var WorldOrbit = (() => {
|
|
|
3404
4571
|
}
|
|
3405
4572
|
return "1.0";
|
|
3406
4573
|
}
|
|
4574
|
+
function stripCommentsForSchemaDetection(source) {
|
|
4575
|
+
const chars = [...source];
|
|
4576
|
+
let inString = false;
|
|
4577
|
+
let inBlockComment = false;
|
|
4578
|
+
for (let index = 0; index < chars.length; index++) {
|
|
4579
|
+
const ch = chars[index];
|
|
4580
|
+
const next = chars[index + 1];
|
|
4581
|
+
if (inBlockComment) {
|
|
4582
|
+
if (ch === "*" && next === "/") {
|
|
4583
|
+
chars[index] = " ";
|
|
4584
|
+
chars[index + 1] = " ";
|
|
4585
|
+
inBlockComment = false;
|
|
4586
|
+
index++;
|
|
4587
|
+
continue;
|
|
4588
|
+
}
|
|
4589
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
4590
|
+
chars[index] = " ";
|
|
4591
|
+
}
|
|
4592
|
+
continue;
|
|
4593
|
+
}
|
|
4594
|
+
if (!inString && ch === "/" && next === "*") {
|
|
4595
|
+
chars[index] = " ";
|
|
4596
|
+
chars[index + 1] = " ";
|
|
4597
|
+
inBlockComment = true;
|
|
4598
|
+
index++;
|
|
4599
|
+
continue;
|
|
4600
|
+
}
|
|
4601
|
+
if (!inString && ch === "#") {
|
|
4602
|
+
chars[index] = " ";
|
|
4603
|
+
let inner = index + 1;
|
|
4604
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
4605
|
+
chars[inner] = " ";
|
|
4606
|
+
inner++;
|
|
4607
|
+
}
|
|
4608
|
+
index = inner - 1;
|
|
4609
|
+
continue;
|
|
4610
|
+
}
|
|
4611
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
4612
|
+
inString = !inString;
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
return chars.join("");
|
|
4616
|
+
}
|
|
3407
4617
|
function loadWorldOrbitSource(source) {
|
|
3408
4618
|
const result = loadWorldOrbitSourceWithDiagnostics(source);
|
|
3409
4619
|
if (!result.ok || !result.value) {
|
|
@@ -3414,36 +4624,36 @@ var WorldOrbit = (() => {
|
|
|
3414
4624
|
}
|
|
3415
4625
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
3416
4626
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
3417
|
-
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft") {
|
|
4627
|
+
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1") {
|
|
3418
4628
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
3419
4629
|
}
|
|
3420
4630
|
let ast;
|
|
3421
4631
|
try {
|
|
3422
4632
|
ast = parseWorldOrbit(source);
|
|
3423
|
-
} catch (
|
|
4633
|
+
} catch (error2) {
|
|
3424
4634
|
return {
|
|
3425
4635
|
ok: false,
|
|
3426
4636
|
value: null,
|
|
3427
|
-
diagnostics: [diagnosticFromError(
|
|
4637
|
+
diagnostics: [diagnosticFromError(error2, "parse")]
|
|
3428
4638
|
};
|
|
3429
4639
|
}
|
|
3430
4640
|
let document2;
|
|
3431
4641
|
try {
|
|
3432
4642
|
document2 = normalizeDocument(ast);
|
|
3433
|
-
} catch (
|
|
4643
|
+
} catch (error2) {
|
|
3434
4644
|
return {
|
|
3435
4645
|
ok: false,
|
|
3436
4646
|
value: null,
|
|
3437
|
-
diagnostics: [diagnosticFromError(
|
|
4647
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
3438
4648
|
};
|
|
3439
4649
|
}
|
|
3440
4650
|
try {
|
|
3441
4651
|
validateDocument(document2);
|
|
3442
|
-
} catch (
|
|
4652
|
+
} catch (error2) {
|
|
3443
4653
|
return {
|
|
3444
4654
|
ok: false,
|
|
3445
4655
|
value: null,
|
|
3446
|
-
diagnostics: [diagnosticFromError(
|
|
4656
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
3447
4657
|
};
|
|
3448
4658
|
}
|
|
3449
4659
|
return {
|
|
@@ -3463,30 +4673,29 @@ var WorldOrbit = (() => {
|
|
|
3463
4673
|
let atlasDocument;
|
|
3464
4674
|
try {
|
|
3465
4675
|
atlasDocument = parseWorldOrbitAtlas(source);
|
|
3466
|
-
} catch (
|
|
4676
|
+
} catch (error2) {
|
|
3467
4677
|
return {
|
|
3468
4678
|
ok: false,
|
|
3469
4679
|
value: null,
|
|
3470
|
-
diagnostics: [diagnosticFromError(
|
|
4680
|
+
diagnostics: [diagnosticFromError(error2, "parse", "load.atlas.failed")]
|
|
3471
4681
|
};
|
|
3472
4682
|
}
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
document2 = materializeAtlasDocument(atlasDocument);
|
|
3476
|
-
} catch (error) {
|
|
4683
|
+
const atlasDiagnostics = [...atlasDocument.diagnostics];
|
|
4684
|
+
if (atlasDiagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
3477
4685
|
return {
|
|
3478
4686
|
ok: false,
|
|
3479
4687
|
value: null,
|
|
3480
|
-
diagnostics:
|
|
4688
|
+
diagnostics: atlasDiagnostics
|
|
3481
4689
|
};
|
|
3482
4690
|
}
|
|
4691
|
+
let document2;
|
|
3483
4692
|
try {
|
|
3484
|
-
|
|
3485
|
-
} catch (
|
|
4693
|
+
document2 = materializeAtlasDocument(atlasDocument);
|
|
4694
|
+
} catch (error2) {
|
|
3486
4695
|
return {
|
|
3487
4696
|
ok: false,
|
|
3488
4697
|
value: null,
|
|
3489
|
-
diagnostics: [diagnosticFromError(
|
|
4698
|
+
diagnostics: [diagnosticFromError(error2, "normalize", "load.atlas.materialize.failed")]
|
|
3490
4699
|
};
|
|
3491
4700
|
}
|
|
3492
4701
|
const loaded = {
|
|
@@ -3495,12 +4704,12 @@ var WorldOrbit = (() => {
|
|
|
3495
4704
|
document: document2,
|
|
3496
4705
|
atlasDocument,
|
|
3497
4706
|
draftDocument: atlasDocument,
|
|
3498
|
-
diagnostics:
|
|
4707
|
+
diagnostics: atlasDiagnostics
|
|
3499
4708
|
};
|
|
3500
4709
|
return {
|
|
3501
4710
|
ok: true,
|
|
3502
4711
|
value: loaded,
|
|
3503
|
-
diagnostics:
|
|
4712
|
+
diagnostics: atlasDiagnostics
|
|
3504
4713
|
};
|
|
3505
4714
|
}
|
|
3506
4715
|
|
|
@@ -3683,6 +4892,7 @@ var WorldOrbit = (() => {
|
|
|
3683
4892
|
const imageDefinitions = buildImageDefinitions(visibleObjects);
|
|
3684
4893
|
const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
|
|
3685
4894
|
const leaderMarkup = layers.guides ? scene.leaders.filter((leader) => !leader.hidden).filter((leader) => visibleObjectIds.has(leader.objectId)).filter((leader) => layers.structures || !isStructureLike(leader.object)).map((leader) => `<line class="wo-leader wo-leader-${leader.mode}" x1="${leader.x1}" y1="${leader.y1}" x2="${leader.x2}" y2="${leader.y2}" data-render-id="${escapeXml(leader.renderId)}" data-group-id="${escapeAttribute(leader.groupId ?? "")}" />`).join("") : "";
|
|
4895
|
+
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("") : "";
|
|
3686
4896
|
const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
|
|
3687
4897
|
const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
|
|
3688
4898
|
const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
|
|
@@ -3717,6 +4927,7 @@ var WorldOrbit = (() => {
|
|
|
3717
4927
|
.wo-orbit-back { opacity: 0.38; stroke-dasharray: 8 6; }
|
|
3718
4928
|
.wo-orbit-front { opacity: 0.9; }
|
|
3719
4929
|
.wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
|
|
4930
|
+
.wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
|
|
3720
4931
|
.wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
|
|
3721
4932
|
.wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
|
|
3722
4933
|
.wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
|
|
@@ -3750,6 +4961,7 @@ var WorldOrbit = (() => {
|
|
|
3750
4961
|
<g data-worldorbit-world-content="true">
|
|
3751
4962
|
${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
|
|
3752
4963
|
${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
|
|
4964
|
+
${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
|
|
3753
4965
|
${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
|
|
3754
4966
|
${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
|
|
3755
4967
|
${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
|
|
@@ -3810,10 +5022,11 @@ var WorldOrbit = (() => {
|
|
|
3810
5022
|
function renderSceneObject(sceneObject, selectedObjectId, theme) {
|
|
3811
5023
|
const { object, x, y, radius, visualRadius } = sceneObject;
|
|
3812
5024
|
const selectionClass = selectedObjectId === sceneObject.objectId ? " wo-object-selected" : "";
|
|
5025
|
+
const kindClass = object.properties.kind ? ` wo-kind-${String(object.properties.kind).toLowerCase().replace(/[^a-z0-9-]/g, "-")}` : "";
|
|
3813
5026
|
const palette = resolveObjectPalette(sceneObject, theme);
|
|
3814
5027
|
const imageMarkup = renderObjectImage(sceneObject);
|
|
3815
5028
|
const outlineMarkup = imageMarkup ? renderObjectBody(object, x, y, radius, palette, { outlineOnly: true }) : "";
|
|
3816
|
-
return `<g class="wo-object wo-object-${object.type}${selectionClass}" data-object-id="${escapeXml(sceneObject.objectId)}" data-parent-id="${escapeAttribute(sceneObject.parentId ?? "")}" data-group-id="${escapeAttribute(sceneObject.groupId ?? "")}" data-render-id="${escapeXml(sceneObject.renderId)}" tabindex="0" role="button" aria-label="${escapeXml(`${object.type} ${sceneObject.objectId}`)}">
|
|
5029
|
+
return `<g class="wo-object wo-object-${object.type}${kindClass}${selectionClass}" data-object-id="${escapeXml(sceneObject.objectId)}" data-parent-id="${escapeAttribute(sceneObject.parentId ?? "")}" data-group-id="${escapeAttribute(sceneObject.groupId ?? "")}" data-render-id="${escapeXml(sceneObject.renderId)}" tabindex="0" role="button" aria-label="${escapeXml(`${object.type} ${sceneObject.objectId}`)}">
|
|
3817
5030
|
<circle class="wo-selection-ring" cx="${x}" cy="${y}" r="${visualRadius + 8}" />
|
|
3818
5031
|
${renderAtmosphere(sceneObject, palette)}
|
|
3819
5032
|
${renderObjectBody(object, x, y, radius, palette)}
|
|
@@ -3847,8 +5060,33 @@ var WorldOrbit = (() => {
|
|
|
3847
5060
|
<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
3848
5061
|
case "structure":
|
|
3849
5062
|
return `<polygon points="${diamondPoints(x, y, radius)}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
3850
|
-
case "phenomenon":
|
|
5063
|
+
case "phenomenon": {
|
|
5064
|
+
const kind = String(object.properties.kind ?? "").toLowerCase().replace(/_/g, "-");
|
|
5065
|
+
if (options.outlineOnly) {
|
|
5066
|
+
if (kind === "black-hole" || kind === "nebula" || kind === "galaxy" || kind === "dwarf-galaxy") {
|
|
5067
|
+
return `<circle cx="${x}" cy="${y}" r="${radius}" fill="transparent" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
5068
|
+
}
|
|
5069
|
+
return `<polygon points="${phenomenonPoints(x, y, radius)}" fill="transparent" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
5070
|
+
}
|
|
5071
|
+
if (kind === "black-hole") {
|
|
5072
|
+
return `<ellipse cx="${x}" cy="${y}" rx="${radius * 2.4}" ry="${radius * 0.55}" fill="none" stroke="${palette.accentRing ?? palette.stroke}" stroke-width="3.5" />
|
|
5073
|
+
<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" stroke="${palette.stroke}" stroke-width="2" />`;
|
|
5074
|
+
}
|
|
5075
|
+
if (kind === "galaxy") {
|
|
5076
|
+
return `<ellipse cx="${x}" cy="${y}" rx="${radius * 2.6}" ry="${radius}" fill="${palette.halo ?? "none"}" stroke="none" />
|
|
5077
|
+
<ellipse cx="${x}" cy="${y}" rx="${radius * 1.5}" ry="${radius * 0.42}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.2" />
|
|
5078
|
+
<circle cx="${x}" cy="${y}" r="${radius * 0.28}" fill="${palette.core ?? "#fff"}" stroke="none" />`;
|
|
5079
|
+
}
|
|
5080
|
+
if (kind === "dwarf-galaxy") {
|
|
5081
|
+
return `<ellipse cx="${x}" cy="${y}" rx="${radius * 1.6}" ry="${radius * 0.55}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1" />
|
|
5082
|
+
<circle cx="${x}" cy="${y}" r="${radius * 0.25}" fill="${palette.core ?? "#fff"}" stroke="none" />`;
|
|
5083
|
+
}
|
|
5084
|
+
if (kind === "nebula") {
|
|
5085
|
+
return `<circle cx="${x}" cy="${y}" r="${radius * 2.2}" fill="${palette.halo ?? "none"}" stroke="none" />
|
|
5086
|
+
<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1" />`;
|
|
5087
|
+
}
|
|
3851
5088
|
return `<polygon points="${phenomenonPoints(x, y, radius)}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
|
|
5089
|
+
}
|
|
3852
5090
|
}
|
|
3853
5091
|
}
|
|
3854
5092
|
function renderAtmosphere(sceneObject, palette) {
|
|
@@ -3917,7 +5155,8 @@ var WorldOrbit = (() => {
|
|
|
3917
5155
|
}
|
|
3918
5156
|
}
|
|
3919
5157
|
function resolveObjectPalette(sceneObject, theme) {
|
|
3920
|
-
const
|
|
5158
|
+
const kind = String(sceneObject.object.properties.kind ?? "").toLowerCase().replace(/_/g, "-");
|
|
5159
|
+
const base = basePaletteForType(sceneObject.object.type, kind, theme);
|
|
3921
5160
|
const customFill = sceneObject.fillColor && isColorLike(sceneObject.fillColor) ? sceneObject.fillColor : base.fill;
|
|
3922
5161
|
const albedo = numericValue(sceneObject.object.properties.albedo);
|
|
3923
5162
|
const temperature = numericValue(sceneObject.object.properties.temperature);
|
|
@@ -3933,7 +5172,7 @@ var WorldOrbit = (() => {
|
|
|
3933
5172
|
tail: sceneObject.object.type === "comet" ? rgbaString(mixColors(fill, "#ffffff", 0.5) ?? fill, 0.72) : void 0
|
|
3934
5173
|
};
|
|
3935
5174
|
}
|
|
3936
|
-
function basePaletteForType(type, theme) {
|
|
5175
|
+
function basePaletteForType(type, kind, theme) {
|
|
3937
5176
|
switch (type) {
|
|
3938
5177
|
case "star":
|
|
3939
5178
|
return {
|
|
@@ -3955,8 +5194,26 @@ var WorldOrbit = (() => {
|
|
|
3955
5194
|
case "structure":
|
|
3956
5195
|
return { fill: theme.accentStrong, stroke: "#fff2ea" };
|
|
3957
5196
|
case "phenomenon":
|
|
3958
|
-
return
|
|
5197
|
+
return kindPhenomenonPalette(kind);
|
|
5198
|
+
}
|
|
5199
|
+
}
|
|
5200
|
+
function kindPhenomenonPalette(kind) {
|
|
5201
|
+
if (kind === "galaxy") {
|
|
5202
|
+
return { fill: "rgba(165,125,255,0.55)", stroke: "rgba(210,185,255,0.75)", halo: "rgba(160,120,255,0.10)", core: "#ede0ff" };
|
|
5203
|
+
}
|
|
5204
|
+
if (kind === "dwarf-galaxy") {
|
|
5205
|
+
return { fill: "rgba(190,165,255,0.45)", stroke: "rgba(220,205,255,0.75)", core: "#ddd0ff" };
|
|
3959
5206
|
}
|
|
5207
|
+
if (kind === "black-hole") {
|
|
5208
|
+
return { fill: "#040408", stroke: "#ff6a00", accentRing: "rgba(255,140,20,0.72)" };
|
|
5209
|
+
}
|
|
5210
|
+
if (kind === "nebula") {
|
|
5211
|
+
return { fill: "rgba(105,205,255,0.45)", stroke: "rgba(180,235,255,0.72)", halo: "rgba(100,200,255,0.08)" };
|
|
5212
|
+
}
|
|
5213
|
+
if (kind === "void") {
|
|
5214
|
+
return { fill: "#05080f", stroke: "rgba(130,160,255,0.4)" };
|
|
5215
|
+
}
|
|
5216
|
+
return { fill: "#78ffd7", stroke: "#e9fff7" };
|
|
3960
5217
|
}
|
|
3961
5218
|
function applyTemperatureAndAlbedo(baseColor, temperature, albedo, type) {
|
|
3962
5219
|
let nextColor = baseColor;
|
|
@@ -4276,6 +5533,41 @@ var WorldOrbit = (() => {
|
|
|
4276
5533
|
});
|
|
4277
5534
|
}
|
|
4278
5535
|
const placement = details.object.placement;
|
|
5536
|
+
if (details.object.groups?.length) {
|
|
5537
|
+
fields.set("groups", {
|
|
5538
|
+
key: "groups",
|
|
5539
|
+
label: "Groups",
|
|
5540
|
+
value: details.object.groups.join(", ")
|
|
5541
|
+
});
|
|
5542
|
+
}
|
|
5543
|
+
if (details.object.epoch) {
|
|
5544
|
+
fields.set("epoch", {
|
|
5545
|
+
key: "epoch",
|
|
5546
|
+
label: "Epoch",
|
|
5547
|
+
value: details.object.epoch
|
|
5548
|
+
});
|
|
5549
|
+
}
|
|
5550
|
+
if (details.object.referencePlane) {
|
|
5551
|
+
fields.set("referencePlane", {
|
|
5552
|
+
key: "referencePlane",
|
|
5553
|
+
label: "Reference Plane",
|
|
5554
|
+
value: details.object.referencePlane
|
|
5555
|
+
});
|
|
5556
|
+
}
|
|
5557
|
+
if (details.object.tidalLock !== void 0) {
|
|
5558
|
+
fields.set("tidalLock", {
|
|
5559
|
+
key: "tidalLock",
|
|
5560
|
+
label: "Tidal Lock",
|
|
5561
|
+
value: details.object.tidalLock ? "true" : "false"
|
|
5562
|
+
});
|
|
5563
|
+
}
|
|
5564
|
+
if (details.object.resonance) {
|
|
5565
|
+
fields.set("resonance", {
|
|
5566
|
+
key: "resonance",
|
|
5567
|
+
label: "Resonance",
|
|
5568
|
+
value: `${details.object.resonance.targetObjectId} ${details.object.resonance.ratio}`
|
|
5569
|
+
});
|
|
5570
|
+
}
|
|
4279
5571
|
if (placement?.mode === "at") {
|
|
4280
5572
|
fields.set("placement", {
|
|
4281
5573
|
key: "placement",
|
|
@@ -4445,6 +5737,9 @@ var WorldOrbit = (() => {
|
|
|
4445
5737
|
touchPoints.set(event.pointerId, point);
|
|
4446
5738
|
if (touchPoints.size === 2) {
|
|
4447
5739
|
touchGesture = createTouchGestureState(scene, state, touchPoints);
|
|
5740
|
+
} else if (touchPoints.size === 1) {
|
|
5741
|
+
dragDistance = 0;
|
|
5742
|
+
suppressClick = false;
|
|
4448
5743
|
}
|
|
4449
5744
|
return;
|
|
4450
5745
|
}
|
|
@@ -4462,7 +5757,9 @@ var WorldOrbit = (() => {
|
|
|
4462
5757
|
if (!behavior.touch || !touchPoints.has(event.pointerId)) {
|
|
4463
5758
|
return;
|
|
4464
5759
|
}
|
|
4465
|
-
touchPoints.
|
|
5760
|
+
const prevPoint = touchPoints.get(event.pointerId);
|
|
5761
|
+
const nextPoint2 = getViewportPointFromClient(event.clientX, event.clientY);
|
|
5762
|
+
touchPoints.set(event.pointerId, nextPoint2);
|
|
4466
5763
|
if (touchPoints.size === 2) {
|
|
4467
5764
|
if (!touchGesture) {
|
|
4468
5765
|
touchGesture = createTouchGestureState(scene, state, touchPoints);
|
|
@@ -4473,6 +5770,14 @@ var WorldOrbit = (() => {
|
|
|
4473
5770
|
const deltaX2 = current.center.x - touchGesture.startViewportCenter.x;
|
|
4474
5771
|
const deltaY2 = current.center.y - touchGesture.startViewportCenter.y;
|
|
4475
5772
|
updateState(panViewerState(zoomedState, deltaX2, deltaY2));
|
|
5773
|
+
} else if (touchPoints.size === 1) {
|
|
5774
|
+
const deltaX2 = nextPoint2.x - prevPoint.x;
|
|
5775
|
+
const deltaY2 = nextPoint2.y - prevPoint.y;
|
|
5776
|
+
dragDistance += Math.abs(deltaX2) + Math.abs(deltaY2);
|
|
5777
|
+
if (dragDistance > 2) {
|
|
5778
|
+
suppressClick = true;
|
|
5779
|
+
}
|
|
5780
|
+
updateState(panViewerState(state, deltaX2, deltaY2));
|
|
4476
5781
|
}
|
|
4477
5782
|
return;
|
|
4478
5783
|
}
|
|
@@ -4937,8 +6242,10 @@ var WorldOrbit = (() => {
|
|
|
4937
6242
|
renderObject,
|
|
4938
6243
|
label: scene.labels.find((label) => label.objectId === renderObject.objectId && !label.hidden) ?? null,
|
|
4939
6244
|
group: scene.groups.find((group) => group.renderId === renderObject.groupId) ?? null,
|
|
6245
|
+
semanticGroups: scene.semanticGroups.filter((group) => renderObject.semanticGroupIds.includes(group.id)),
|
|
4940
6246
|
orbit: scene.orbitVisuals.find((orbit) => orbit.objectId === renderObject.objectId && !orbit.hidden) ?? null,
|
|
4941
6247
|
relatedOrbits: scene.orbitVisuals.filter((orbit) => !orbit.hidden && (orbit.objectId === renderObject.objectId || renderObject.ancestorIds.includes(orbit.objectId) || renderObject.childIds.includes(orbit.objectId))),
|
|
6248
|
+
relations: scene.relations.filter((relation) => !relation.hidden && (relation.fromObjectId === renderObject.objectId || relation.toObjectId === renderObject.objectId)),
|
|
4942
6249
|
parent: getObjectById(renderObject.parentId),
|
|
4943
6250
|
children: renderObject.childIds.map((childId) => getObjectById(childId)).filter(Boolean),
|
|
4944
6251
|
ancestors: renderObject.ancestorIds.map((ancestorId) => getObjectById(ancestorId)).filter(Boolean),
|
|
@@ -5563,6 +6870,7 @@ var WorldOrbit = (() => {
|
|
|
5563
6870
|
const controls = {
|
|
5564
6871
|
search: options.controls?.search ?? true,
|
|
5565
6872
|
typeFilter: options.controls?.typeFilter ?? true,
|
|
6873
|
+
groupFilter: options.controls?.groupFilter ?? true,
|
|
5566
6874
|
viewpointSelect: options.controls?.viewpointSelect ?? true,
|
|
5567
6875
|
inspector: options.controls?.inspector ?? true,
|
|
5568
6876
|
bookmarks: options.controls?.bookmarks ?? true
|
|
@@ -5572,6 +6880,7 @@ var WorldOrbit = (() => {
|
|
|
5572
6880
|
const toolbar = container.querySelector("[data-atlas-toolbar]");
|
|
5573
6881
|
const searchInput = container.querySelector("[data-atlas-search]");
|
|
5574
6882
|
const typeFilterSelect = container.querySelector("[data-atlas-type-filter]");
|
|
6883
|
+
const groupFilterSelect = container.querySelector("[data-atlas-group-filter]");
|
|
5575
6884
|
const viewpointSelect = container.querySelector("[data-atlas-viewpoint]");
|
|
5576
6885
|
const bookmarkButton = container.querySelector("[data-atlas-bookmark]");
|
|
5577
6886
|
const bookmarkList = container.querySelector("[data-atlas-bookmarks]");
|
|
@@ -5584,6 +6893,7 @@ var WorldOrbit = (() => {
|
|
|
5584
6893
|
const baseFilter = normalizeViewerFilter(options.initialFilter ?? null);
|
|
5585
6894
|
let searchQuery = options.initialQuery?.trim() ?? baseFilter?.query ?? "";
|
|
5586
6895
|
let objectTypeFilter = options.initialObjectType ?? (baseFilter?.objectTypes?.length === 1 ? baseFilter.objectTypes[0] : null);
|
|
6896
|
+
let groupFilter = baseFilter?.groupIds?.[0] ?? null;
|
|
5587
6897
|
let bookmarks = [];
|
|
5588
6898
|
let viewer;
|
|
5589
6899
|
viewer = createInteractiveViewer(stage, {
|
|
@@ -5631,6 +6941,7 @@ var WorldOrbit = (() => {
|
|
|
5631
6941
|
});
|
|
5632
6942
|
applyCurrentFilter();
|
|
5633
6943
|
populateViewpoints();
|
|
6944
|
+
populateGroups();
|
|
5634
6945
|
syncControlsFromFilter(viewer.getFilter());
|
|
5635
6946
|
renderBookmarks();
|
|
5636
6947
|
updateSearchResults();
|
|
@@ -5643,6 +6954,10 @@ var WorldOrbit = (() => {
|
|
|
5643
6954
|
objectTypeFilter = typeFilterSelect.value || null;
|
|
5644
6955
|
applyCurrentFilter();
|
|
5645
6956
|
});
|
|
6957
|
+
groupFilterSelect?.addEventListener("change", () => {
|
|
6958
|
+
groupFilter = groupFilterSelect.value || null;
|
|
6959
|
+
applyCurrentFilter();
|
|
6960
|
+
});
|
|
5646
6961
|
viewpointSelect?.addEventListener("change", () => {
|
|
5647
6962
|
const activeViewer = requireViewer();
|
|
5648
6963
|
if (!viewpointSelect.value) {
|
|
@@ -5784,6 +7099,7 @@ var WorldOrbit = (() => {
|
|
|
5784
7099
|
return api;
|
|
5785
7100
|
function refreshAfterInputChange() {
|
|
5786
7101
|
populateViewpoints();
|
|
7102
|
+
populateGroups();
|
|
5787
7103
|
applyCurrentFilter();
|
|
5788
7104
|
renderBookmarks();
|
|
5789
7105
|
updateSearchResults();
|
|
@@ -5800,19 +7116,23 @@ var WorldOrbit = (() => {
|
|
|
5800
7116
|
query: searchQuery || void 0,
|
|
5801
7117
|
objectTypes: objectTypeFilter ? [objectTypeFilter] : void 0,
|
|
5802
7118
|
tags: baseFilter?.tags,
|
|
5803
|
-
groupIds: baseFilter?.groupIds,
|
|
7119
|
+
groupIds: groupFilter ? [groupFilter] : baseFilter?.groupIds,
|
|
5804
7120
|
includeAncestors: baseFilter?.includeAncestors ?? true
|
|
5805
7121
|
});
|
|
5806
7122
|
}
|
|
5807
7123
|
function syncControlsFromFilter(filter) {
|
|
5808
7124
|
searchQuery = filter?.query?.trim() ?? "";
|
|
5809
7125
|
objectTypeFilter = filter?.objectTypes?.length === 1 ? filter.objectTypes[0] : null;
|
|
7126
|
+
groupFilter = filter?.groupIds?.length === 1 ? filter.groupIds[0] : null;
|
|
5810
7127
|
if (searchInput && document.activeElement !== searchInput) {
|
|
5811
7128
|
searchInput.value = searchQuery;
|
|
5812
7129
|
}
|
|
5813
7130
|
if (typeFilterSelect) {
|
|
5814
7131
|
typeFilterSelect.value = objectTypeFilter ?? "";
|
|
5815
7132
|
}
|
|
7133
|
+
if (groupFilterSelect) {
|
|
7134
|
+
groupFilterSelect.value = groupFilter ?? "";
|
|
7135
|
+
}
|
|
5816
7136
|
}
|
|
5817
7137
|
function populateViewpoints() {
|
|
5818
7138
|
if (!viewpointSelect) {
|
|
@@ -5826,6 +7146,17 @@ var WorldOrbit = (() => {
|
|
|
5826
7146
|
].join("");
|
|
5827
7147
|
viewpointSelect.value = active;
|
|
5828
7148
|
}
|
|
7149
|
+
function populateGroups() {
|
|
7150
|
+
if (!groupFilterSelect) {
|
|
7151
|
+
return;
|
|
7152
|
+
}
|
|
7153
|
+
const activeViewer = requireViewer();
|
|
7154
|
+
groupFilterSelect.innerHTML = [
|
|
7155
|
+
`<option value="">All groups</option>`,
|
|
7156
|
+
...activeViewer.getScene().semanticGroups.map((group) => `<option value="${escapeHtml2(group.id)}">${escapeHtml2(group.label)}</option>`)
|
|
7157
|
+
].join("");
|
|
7158
|
+
groupFilterSelect.value = groupFilter ?? "";
|
|
7159
|
+
}
|
|
5829
7160
|
function syncViewpointControl() {
|
|
5830
7161
|
if (!viewpointSelect) {
|
|
5831
7162
|
return;
|
|
@@ -5859,6 +7190,8 @@ var WorldOrbit = (() => {
|
|
|
5859
7190
|
projection: activeViewer.getScene().projection,
|
|
5860
7191
|
renderPreset: activeViewer.getScene().renderPreset,
|
|
5861
7192
|
groupCount: activeViewer.getScene().groups.length,
|
|
7193
|
+
semanticGroupCount: activeViewer.getScene().semanticGroups.length,
|
|
7194
|
+
relationCount: activeViewer.getScene().relations.length,
|
|
5862
7195
|
viewpointCount: activeViewer.getScene().viewpoints.length
|
|
5863
7196
|
}
|
|
5864
7197
|
};
|
|
@@ -5891,6 +7224,12 @@ var WorldOrbit = (() => {
|
|
|
5891
7224
|
<option value="phenomenon">Phenomenon</option>
|
|
5892
7225
|
</select>
|
|
5893
7226
|
</label>` : "",
|
|
7227
|
+
controls.groupFilter ? `<label class="wo-atlas-field">
|
|
7228
|
+
<span>Group</span>
|
|
7229
|
+
<select data-atlas-group-filter>
|
|
7230
|
+
<option value="">All groups</option>
|
|
7231
|
+
</select>
|
|
7232
|
+
</label>` : "",
|
|
5894
7233
|
controls.viewpointSelect ? `<label class="wo-atlas-field">
|
|
5895
7234
|
<span>Viewpoint</span>
|
|
5896
7235
|
<select data-atlas-viewpoint>
|
|
@@ -6034,5 +7373,5 @@ var WorldOrbit = (() => {
|
|
|
6034
7373
|
function parseSource(source) {
|
|
6035
7374
|
return loadWorldOrbitSource(source).document;
|
|
6036
7375
|
}
|
|
6037
|
-
return __toCommonJS(
|
|
7376
|
+
return __toCommonJS(index_exports);
|
|
6038
7377
|
})();
|