worldorbit 2.5.16 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -15
- package/dist/browser/core/dist/index.js +1228 -110
- package/dist/browser/editor/dist/index.js +1896 -180
- package/dist/browser/markdown/dist/index.js +1071 -99
- package/dist/browser/viewer/dist/index.js +1127 -113
- package/dist/unpkg/core/dist/index.js +1228 -110
- package/dist/unpkg/editor/dist/index.js +1896 -180
- package/dist/unpkg/markdown/dist/index.js +1071 -99
- package/dist/unpkg/viewer/dist/index.js +1127 -113
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +295 -203
- package/dist/unpkg/worldorbit-markdown.min.js +66 -58
- package/dist/unpkg/worldorbit-viewer.min.js +84 -76
- package/dist/unpkg/worldorbit.js +1304 -124
- package/dist/unpkg/worldorbit.min.js +88 -80
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.js +75 -1
- package/packages/core/dist/atlas-validate.js +211 -8
- package/packages/core/dist/draft-parse.js +401 -22
- package/packages/core/dist/draft.d.ts +5 -2
- package/packages/core/dist/draft.js +103 -8
- package/packages/core/dist/format.js +99 -6
- package/packages/core/dist/load.js +9 -2
- package/packages/core/dist/normalize.js +1 -0
- package/packages/core/dist/scene.js +400 -64
- package/packages/core/dist/types.d.ts +60 -4
- package/packages/editor/dist/editor.js +702 -65
- package/packages/editor/dist/types.d.ts +3 -1
- package/packages/viewer/dist/atlas-state.js +11 -2
- package/packages/viewer/dist/atlas-viewer.js +19 -7
- package/packages/viewer/dist/render.js +31 -2
- package/packages/viewer/dist/theme.js +1 -0
- package/packages/viewer/dist/tooltip.js +9 -0
- package/packages/viewer/dist/types.d.ts +12 -2
- package/packages/viewer/dist/viewer.js +28 -1
|
@@ -74,6 +74,23 @@ for (const spec of [
|
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
const DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
77
|
+
const EVENT_POSE_FIELD_KEYS = new Set([
|
|
78
|
+
"orbit",
|
|
79
|
+
"distance",
|
|
80
|
+
"semiMajor",
|
|
81
|
+
"eccentricity",
|
|
82
|
+
"period",
|
|
83
|
+
"angle",
|
|
84
|
+
"inclination",
|
|
85
|
+
"phase",
|
|
86
|
+
"at",
|
|
87
|
+
"surface",
|
|
88
|
+
"free",
|
|
89
|
+
"inner",
|
|
90
|
+
"outer",
|
|
91
|
+
"epoch",
|
|
92
|
+
"referencePlane",
|
|
93
|
+
]);
|
|
77
94
|
export function parseWorldOrbitAtlas(source) {
|
|
78
95
|
return parseAtlasSource(source);
|
|
79
96
|
}
|
|
@@ -91,12 +108,15 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
91
108
|
const objectNodes = [];
|
|
92
109
|
const groups = [];
|
|
93
110
|
const relations = [];
|
|
111
|
+
const events = [];
|
|
112
|
+
const eventPoseNodes = new Map();
|
|
94
113
|
let sawDefaults = false;
|
|
95
114
|
let sawAtlas = false;
|
|
96
115
|
const viewpointIds = new Set();
|
|
97
116
|
const annotationIds = new Set();
|
|
98
117
|
const groupIds = new Set();
|
|
99
118
|
const relationIds = new Set();
|
|
119
|
+
const eventIds = new Set();
|
|
100
120
|
for (let index = 0; index < lines.length; index++) {
|
|
101
121
|
const rawLine = lines[index];
|
|
102
122
|
const lineNumber = index + 1;
|
|
@@ -114,7 +134,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
114
134
|
if (!sawSchemaHeader) {
|
|
115
135
|
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
116
136
|
sawSchemaHeader = true;
|
|
117
|
-
if (prepared.comments.length > 0 && sourceSchemaVersion
|
|
137
|
+
if (prepared.comments.length > 0 && isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
118
138
|
diagnostics.push({
|
|
119
139
|
code: "parse.schema21.commentCompatibility",
|
|
120
140
|
severity: "warning",
|
|
@@ -127,7 +147,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
127
147
|
continue;
|
|
128
148
|
}
|
|
129
149
|
if (indent === 0) {
|
|
130
|
-
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
150
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
131
151
|
if (section.kind === "system") {
|
|
132
152
|
system = section.system;
|
|
133
153
|
}
|
|
@@ -148,6 +168,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
148
168
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
149
169
|
}
|
|
150
170
|
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
171
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
151
172
|
const outputVersion = forcedOutputVersion ??
|
|
152
173
|
(sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
153
174
|
const baseDocument = {
|
|
@@ -156,6 +177,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
156
177
|
system,
|
|
157
178
|
groups,
|
|
158
179
|
relations,
|
|
180
|
+
events: normalizedEvents,
|
|
159
181
|
objects,
|
|
160
182
|
diagnostics,
|
|
161
183
|
};
|
|
@@ -187,17 +209,19 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
187
209
|
function assertDraftSchemaHeader(tokens, line) {
|
|
188
210
|
if (tokens.length !== 2 ||
|
|
189
211
|
tokens[0].value.toLowerCase() !== "schema" ||
|
|
190
|
-
!["2.0-draft", "2.0", "2.1"].includes(tokens[1].value.toLowerCase())) {
|
|
191
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
212
|
+
!["2.0-draft", "2.0", "2.1", "2.5"].includes(tokens[1].value.toLowerCase())) {
|
|
213
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
192
214
|
}
|
|
193
215
|
const version = tokens[1].value.toLowerCase();
|
|
194
|
-
return version === "2.
|
|
195
|
-
? "2.
|
|
196
|
-
: version === "2.
|
|
197
|
-
? "2.
|
|
198
|
-
: "2.0"
|
|
216
|
+
return version === "2.5"
|
|
217
|
+
? "2.5"
|
|
218
|
+
: version === "2.1"
|
|
219
|
+
? "2.1"
|
|
220
|
+
: version === "2.0-draft"
|
|
221
|
+
? "2.0-draft"
|
|
222
|
+
: "2.0";
|
|
199
223
|
}
|
|
200
|
-
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
224
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
201
225
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
202
226
|
switch (keyword) {
|
|
203
227
|
case "system":
|
|
@@ -215,6 +239,8 @@ function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, sy
|
|
|
215
239
|
return {
|
|
216
240
|
kind: "defaults",
|
|
217
241
|
system,
|
|
242
|
+
sourceSchemaVersion,
|
|
243
|
+
diagnostics,
|
|
218
244
|
seenFields: new Set(),
|
|
219
245
|
};
|
|
220
246
|
case "atlas":
|
|
@@ -234,7 +260,7 @@ function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, sy
|
|
|
234
260
|
if (!system) {
|
|
235
261
|
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
236
262
|
}
|
|
237
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
263
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
238
264
|
case "annotation":
|
|
239
265
|
if (!system) {
|
|
240
266
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -246,6 +272,9 @@ function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, sy
|
|
|
246
272
|
case "relation":
|
|
247
273
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
248
274
|
return startRelationSection(tokens, line, relations, relationIds);
|
|
275
|
+
case "event":
|
|
276
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
277
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
249
278
|
case "object":
|
|
250
279
|
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
251
280
|
default:
|
|
@@ -282,7 +311,7 @@ function startSystemSection(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
|
282
311
|
seenFields: new Set(),
|
|
283
312
|
};
|
|
284
313
|
}
|
|
285
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
314
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
286
315
|
if (tokens.length !== 2) {
|
|
287
316
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
288
317
|
}
|
|
@@ -299,10 +328,12 @@ function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
|
299
328
|
summary: "",
|
|
300
329
|
focusObjectId: null,
|
|
301
330
|
selectedObjectId: null,
|
|
331
|
+
events: [],
|
|
302
332
|
projection: system.defaults.view,
|
|
303
333
|
preset: system.defaults.preset,
|
|
304
334
|
zoom: null,
|
|
305
335
|
rotationDeg: 0,
|
|
336
|
+
camera: null,
|
|
306
337
|
layers: {},
|
|
307
338
|
filter: null,
|
|
308
339
|
};
|
|
@@ -311,10 +342,15 @@ function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
|
311
342
|
return {
|
|
312
343
|
kind: "viewpoint",
|
|
313
344
|
viewpoint,
|
|
345
|
+
sourceSchemaVersion,
|
|
346
|
+
diagnostics,
|
|
314
347
|
seenFields: new Set(),
|
|
315
348
|
inFilter: false,
|
|
316
349
|
filterIndent: null,
|
|
317
350
|
seenFilterFields: new Set(),
|
|
351
|
+
inCamera: false,
|
|
352
|
+
cameraIndent: null,
|
|
353
|
+
seenCameraFields: new Set(),
|
|
318
354
|
};
|
|
319
355
|
}
|
|
320
356
|
function startAnnotationSection(tokens, line, system, annotationIds) {
|
|
@@ -401,6 +437,51 @@ function startRelationSection(tokens, line, relations, relationIds) {
|
|
|
401
437
|
seenFields: new Set(),
|
|
402
438
|
};
|
|
403
439
|
}
|
|
440
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
441
|
+
if (tokens.length !== 2) {
|
|
442
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
443
|
+
}
|
|
444
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
445
|
+
if (!id) {
|
|
446
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
447
|
+
}
|
|
448
|
+
if (eventIds.has(id)) {
|
|
449
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
450
|
+
}
|
|
451
|
+
const event = {
|
|
452
|
+
id,
|
|
453
|
+
kind: "",
|
|
454
|
+
label: humanizeIdentifier(id),
|
|
455
|
+
summary: null,
|
|
456
|
+
targetObjectId: null,
|
|
457
|
+
participantObjectIds: [],
|
|
458
|
+
timing: null,
|
|
459
|
+
visibility: null,
|
|
460
|
+
epoch: null,
|
|
461
|
+
referencePlane: null,
|
|
462
|
+
tags: [],
|
|
463
|
+
color: null,
|
|
464
|
+
hidden: false,
|
|
465
|
+
positions: [],
|
|
466
|
+
};
|
|
467
|
+
const rawPoses = [];
|
|
468
|
+
events.push(event);
|
|
469
|
+
eventPoseNodes.set(id, rawPoses);
|
|
470
|
+
eventIds.add(id);
|
|
471
|
+
return {
|
|
472
|
+
kind: "event",
|
|
473
|
+
event,
|
|
474
|
+
sourceSchemaVersion,
|
|
475
|
+
diagnostics,
|
|
476
|
+
seenFields: new Set(),
|
|
477
|
+
rawPoses,
|
|
478
|
+
inPositions: false,
|
|
479
|
+
positionsIndent: null,
|
|
480
|
+
activePose: null,
|
|
481
|
+
poseIndent: null,
|
|
482
|
+
activePoseSeenFields: new Set(),
|
|
483
|
+
};
|
|
484
|
+
}
|
|
404
485
|
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
405
486
|
if (tokens.length < 3) {
|
|
406
487
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
@@ -457,6 +538,9 @@ function handleSectionLine(section, indent, tokens, line) {
|
|
|
457
538
|
case "relation":
|
|
458
539
|
applyRelationField(section, tokens, line);
|
|
459
540
|
return;
|
|
541
|
+
case "event":
|
|
542
|
+
applyEventField(section, indent, tokens, line);
|
|
543
|
+
return;
|
|
460
544
|
case "object":
|
|
461
545
|
applyObjectField(section, indent, tokens, line);
|
|
462
546
|
return;
|
|
@@ -499,6 +583,12 @@ function applyDefaultsField(section, tokens, line) {
|
|
|
499
583
|
const value = joinFieldValue(tokens, line);
|
|
500
584
|
switch (key) {
|
|
501
585
|
case "view":
|
|
586
|
+
if (isSchema25Projection(value)) {
|
|
587
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "defaults.view", {
|
|
588
|
+
line,
|
|
589
|
+
column: tokens[0].column,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
502
592
|
section.system.defaults.view = parseProjectionValue(value, line, tokens[0].column);
|
|
503
593
|
return;
|
|
504
594
|
case "scale":
|
|
@@ -538,14 +628,36 @@ function applyAtlasField(section, indent, tokens, line) {
|
|
|
538
628
|
throw new WorldOrbitError(`Unknown atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
539
629
|
}
|
|
540
630
|
function applyViewpointField(section, indent, tokens, line) {
|
|
631
|
+
if (section.inCamera && indent <= (section.cameraIndent ?? 0)) {
|
|
632
|
+
section.inCamera = false;
|
|
633
|
+
section.cameraIndent = null;
|
|
634
|
+
}
|
|
541
635
|
if (section.inFilter && indent <= (section.filterIndent ?? 0)) {
|
|
542
636
|
section.inFilter = false;
|
|
543
637
|
section.filterIndent = null;
|
|
544
638
|
}
|
|
639
|
+
if (section.inCamera) {
|
|
640
|
+
applyViewpointCameraField(section, tokens, line);
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
545
643
|
if (section.inFilter) {
|
|
546
644
|
applyViewpointFilterField(section, tokens, line);
|
|
547
645
|
return;
|
|
548
646
|
}
|
|
647
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "camera") {
|
|
648
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.camera", {
|
|
649
|
+
line,
|
|
650
|
+
column: tokens[0].column,
|
|
651
|
+
});
|
|
652
|
+
if (section.seenFields.has("camera")) {
|
|
653
|
+
throw new WorldOrbitError('Duplicate viewpoint field "camera"', line, tokens[0].column);
|
|
654
|
+
}
|
|
655
|
+
section.seenFields.add("camera");
|
|
656
|
+
section.inCamera = true;
|
|
657
|
+
section.cameraIndent = indent;
|
|
658
|
+
section.viewpoint.camera = section.viewpoint.camera ?? createEmptyViewCamera();
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
549
661
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "filter") {
|
|
550
662
|
if (section.seenFields.has("filter")) {
|
|
551
663
|
throw new WorldOrbitError('Duplicate viewpoint field "filter"', line, tokens[0].column);
|
|
@@ -571,6 +683,12 @@ function applyViewpointField(section, indent, tokens, line) {
|
|
|
571
683
|
section.viewpoint.selectedObjectId = value;
|
|
572
684
|
return;
|
|
573
685
|
case "projection":
|
|
686
|
+
if (isSchema25Projection(value)) {
|
|
687
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "projection", {
|
|
688
|
+
line,
|
|
689
|
+
column: tokens[0].column,
|
|
690
|
+
});
|
|
691
|
+
}
|
|
574
692
|
section.viewpoint.projection = parseProjectionValue(value, line, tokens[0].column);
|
|
575
693
|
return;
|
|
576
694
|
case "preset":
|
|
@@ -582,13 +700,49 @@ function applyViewpointField(section, indent, tokens, line) {
|
|
|
582
700
|
case "rotation":
|
|
583
701
|
section.viewpoint.rotationDeg = parseFiniteNumber(value, line, tokens[0].column, "rotation");
|
|
584
702
|
return;
|
|
703
|
+
case "camera":
|
|
704
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.camera", {
|
|
705
|
+
line,
|
|
706
|
+
column: tokens[0].column,
|
|
707
|
+
});
|
|
708
|
+
section.viewpoint.camera = parseInlineViewCamera(tokens.slice(1), line, section.viewpoint.camera);
|
|
709
|
+
return;
|
|
585
710
|
case "layers":
|
|
586
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
711
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
712
|
+
return;
|
|
713
|
+
case "events":
|
|
714
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
715
|
+
line,
|
|
716
|
+
column: tokens[0].column,
|
|
717
|
+
});
|
|
718
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
587
719
|
return;
|
|
588
720
|
default:
|
|
589
721
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
590
722
|
}
|
|
591
723
|
}
|
|
724
|
+
function applyViewpointCameraField(section, tokens, line) {
|
|
725
|
+
const key = requireUniqueField(tokens, section.seenCameraFields, line);
|
|
726
|
+
const value = joinFieldValue(tokens, line);
|
|
727
|
+
const camera = section.viewpoint.camera ?? createEmptyViewCamera();
|
|
728
|
+
switch (key) {
|
|
729
|
+
case "azimuth":
|
|
730
|
+
camera.azimuth = parseFiniteNumber(value, line, tokens[0].column, "camera.azimuth");
|
|
731
|
+
break;
|
|
732
|
+
case "elevation":
|
|
733
|
+
camera.elevation = parseFiniteNumber(value, line, tokens[0].column, "camera.elevation");
|
|
734
|
+
break;
|
|
735
|
+
case "roll":
|
|
736
|
+
camera.roll = parseFiniteNumber(value, line, tokens[0].column, "camera.roll");
|
|
737
|
+
break;
|
|
738
|
+
case "distance":
|
|
739
|
+
camera.distance = parsePositiveNumber(value, line, tokens[0].column, "camera.distance");
|
|
740
|
+
break;
|
|
741
|
+
default:
|
|
742
|
+
throw new WorldOrbitError(`Unknown viewpoint camera field "${tokens[0].value}"`, line, tokens[0].column);
|
|
743
|
+
}
|
|
744
|
+
section.viewpoint.camera = camera;
|
|
745
|
+
}
|
|
592
746
|
function applyViewpointFilterField(section, tokens, line) {
|
|
593
747
|
const key = requireUniqueField(tokens, section.seenFilterFields, line);
|
|
594
748
|
const filter = section.viewpoint.filter ?? createEmptyViewpointFilter();
|
|
@@ -688,6 +842,127 @@ function applyRelationField(section, tokens, line) {
|
|
|
688
842
|
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
689
843
|
}
|
|
690
844
|
}
|
|
845
|
+
function applyEventField(section, indent, tokens, line) {
|
|
846
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
847
|
+
section.activePose = null;
|
|
848
|
+
section.poseIndent = null;
|
|
849
|
+
section.activePoseSeenFields.clear();
|
|
850
|
+
}
|
|
851
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
852
|
+
section.inPositions = false;
|
|
853
|
+
section.positionsIndent = null;
|
|
854
|
+
}
|
|
855
|
+
if (section.activePose) {
|
|
856
|
+
if (tokens[0]?.value === "epoch" ||
|
|
857
|
+
tokens[0]?.value === "referencePlane") {
|
|
858
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, `pose.${tokens[0].value}`, {
|
|
859
|
+
line,
|
|
860
|
+
column: tokens[0]?.column ?? 1,
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (section.inPositions) {
|
|
867
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
868
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
869
|
+
}
|
|
870
|
+
const objectId = tokens[1].value;
|
|
871
|
+
if (!objectId.trim()) {
|
|
872
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
873
|
+
}
|
|
874
|
+
const rawPose = {
|
|
875
|
+
objectId,
|
|
876
|
+
fields: [],
|
|
877
|
+
location: { line, column: tokens[0].column },
|
|
878
|
+
};
|
|
879
|
+
section.rawPoses.push(rawPose);
|
|
880
|
+
section.activePose = rawPose;
|
|
881
|
+
section.poseIndent = indent;
|
|
882
|
+
section.activePoseSeenFields = new Set();
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
886
|
+
if (section.seenFields.has("positions")) {
|
|
887
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
888
|
+
}
|
|
889
|
+
section.seenFields.add("positions");
|
|
890
|
+
section.inPositions = true;
|
|
891
|
+
section.positionsIndent = indent;
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
895
|
+
switch (key) {
|
|
896
|
+
case "kind":
|
|
897
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
898
|
+
return;
|
|
899
|
+
case "label":
|
|
900
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
901
|
+
return;
|
|
902
|
+
case "summary":
|
|
903
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
904
|
+
return;
|
|
905
|
+
case "target":
|
|
906
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
907
|
+
return;
|
|
908
|
+
case "participants":
|
|
909
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
910
|
+
return;
|
|
911
|
+
case "timing":
|
|
912
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
913
|
+
return;
|
|
914
|
+
case "visibility":
|
|
915
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
916
|
+
return;
|
|
917
|
+
case "epoch":
|
|
918
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "event.epoch", {
|
|
919
|
+
line,
|
|
920
|
+
column: tokens[0].column,
|
|
921
|
+
});
|
|
922
|
+
section.event.epoch = joinFieldValue(tokens, line);
|
|
923
|
+
return;
|
|
924
|
+
case "referenceplane":
|
|
925
|
+
warnIfSchema25Feature(section.sourceSchemaVersion, section.diagnostics, "event.referencePlane", {
|
|
926
|
+
line,
|
|
927
|
+
column: tokens[0].column,
|
|
928
|
+
});
|
|
929
|
+
section.event.referencePlane = joinFieldValue(tokens, line);
|
|
930
|
+
return;
|
|
931
|
+
case "tags":
|
|
932
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
933
|
+
return;
|
|
934
|
+
case "color":
|
|
935
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
936
|
+
return;
|
|
937
|
+
case "hidden":
|
|
938
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
939
|
+
line,
|
|
940
|
+
column: tokens[0].column,
|
|
941
|
+
});
|
|
942
|
+
return;
|
|
943
|
+
default:
|
|
944
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
948
|
+
if (tokens.length < 2) {
|
|
949
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
950
|
+
}
|
|
951
|
+
const key = tokens[0].value;
|
|
952
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
953
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
954
|
+
}
|
|
955
|
+
if (seenFields.has(key)) {
|
|
956
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
957
|
+
}
|
|
958
|
+
seenFields.add(key);
|
|
959
|
+
return {
|
|
960
|
+
type: "field",
|
|
961
|
+
key,
|
|
962
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
963
|
+
location: { line, column: tokens[0].column },
|
|
964
|
+
};
|
|
965
|
+
}
|
|
691
966
|
function applyObjectField(section, indent, tokens, line) {
|
|
692
967
|
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
693
968
|
section.activeBlock = null;
|
|
@@ -760,7 +1035,7 @@ function parseObjectTypeTokens(tokens, line) {
|
|
|
760
1035
|
value === "structure" ||
|
|
761
1036
|
value === "phenomenon");
|
|
762
1037
|
}
|
|
763
|
-
function parseLayerTokens(tokens, line) {
|
|
1038
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
764
1039
|
const layers = {};
|
|
765
1040
|
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
766
1041
|
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
@@ -775,9 +1050,16 @@ function parseLayerTokens(tokens, line) {
|
|
|
775
1050
|
raw === "orbits-back" ||
|
|
776
1051
|
raw === "orbits-front" ||
|
|
777
1052
|
raw === "relations" ||
|
|
1053
|
+
raw === "events" ||
|
|
778
1054
|
raw === "objects" ||
|
|
779
1055
|
raw === "labels" ||
|
|
780
1056
|
raw === "metadata") {
|
|
1057
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
1058
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
1059
|
+
line,
|
|
1060
|
+
column: tokens[0]?.column ?? 1,
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
781
1063
|
layers[raw] = enabled;
|
|
782
1064
|
}
|
|
783
1065
|
}
|
|
@@ -795,11 +1077,18 @@ function parseTokenList(tokens, line, fieldName) {
|
|
|
795
1077
|
}
|
|
796
1078
|
function parseProjectionValue(value, line, column) {
|
|
797
1079
|
const normalized = value.toLowerCase();
|
|
798
|
-
if (normalized !== "topdown" &&
|
|
1080
|
+
if (normalized !== "topdown" &&
|
|
1081
|
+
normalized !== "isometric" &&
|
|
1082
|
+
normalized !== "orthographic" &&
|
|
1083
|
+
normalized !== "perspective") {
|
|
799
1084
|
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
800
1085
|
}
|
|
801
1086
|
return normalized;
|
|
802
1087
|
}
|
|
1088
|
+
function isSchema25Projection(value) {
|
|
1089
|
+
const normalized = value.toLowerCase();
|
|
1090
|
+
return normalized === "orthographic" || normalized === "perspective";
|
|
1091
|
+
}
|
|
803
1092
|
function parsePresetValue(value, line, column) {
|
|
804
1093
|
const normalized = value.toLowerCase();
|
|
805
1094
|
if (normalized === "diagram" ||
|
|
@@ -832,6 +1121,48 @@ function createEmptyViewpointFilter() {
|
|
|
832
1121
|
groupIds: [],
|
|
833
1122
|
};
|
|
834
1123
|
}
|
|
1124
|
+
function createEmptyViewCamera() {
|
|
1125
|
+
return {
|
|
1126
|
+
azimuth: null,
|
|
1127
|
+
elevation: null,
|
|
1128
|
+
roll: null,
|
|
1129
|
+
distance: null,
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
function parseInlineViewCamera(tokens, line, current) {
|
|
1133
|
+
if (tokens.length === 0 || tokens.length % 2 !== 0) {
|
|
1134
|
+
throw new WorldOrbitError('Field "camera" expects "<field> <value>" pairs', line, tokens[0]?.column ?? 1);
|
|
1135
|
+
}
|
|
1136
|
+
const camera = current ? { ...current } : createEmptyViewCamera();
|
|
1137
|
+
const seen = new Set();
|
|
1138
|
+
for (let index = 0; index < tokens.length; index += 2) {
|
|
1139
|
+
const fieldToken = tokens[index];
|
|
1140
|
+
const valueToken = tokens[index + 1];
|
|
1141
|
+
const key = fieldToken.value.toLowerCase();
|
|
1142
|
+
if (seen.has(key)) {
|
|
1143
|
+
throw new WorldOrbitError(`Duplicate viewpoint camera field "${fieldToken.value}"`, line, fieldToken.column);
|
|
1144
|
+
}
|
|
1145
|
+
seen.add(key);
|
|
1146
|
+
const value = valueToken.value;
|
|
1147
|
+
switch (key) {
|
|
1148
|
+
case "azimuth":
|
|
1149
|
+
camera.azimuth = parseFiniteNumber(value, line, fieldToken.column, "camera.azimuth");
|
|
1150
|
+
break;
|
|
1151
|
+
case "elevation":
|
|
1152
|
+
camera.elevation = parseFiniteNumber(value, line, fieldToken.column, "camera.elevation");
|
|
1153
|
+
break;
|
|
1154
|
+
case "roll":
|
|
1155
|
+
camera.roll = parseFiniteNumber(value, line, fieldToken.column, "camera.roll");
|
|
1156
|
+
break;
|
|
1157
|
+
case "distance":
|
|
1158
|
+
camera.distance = parsePositiveNumber(value, line, fieldToken.column, "camera.distance");
|
|
1159
|
+
break;
|
|
1160
|
+
default:
|
|
1161
|
+
throw new WorldOrbitError(`Unknown viewpoint camera field "${fieldToken.value}"`, line, fieldToken.column);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return camera;
|
|
1165
|
+
}
|
|
835
1166
|
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
836
1167
|
const fields = [];
|
|
837
1168
|
let index = 0;
|
|
@@ -921,7 +1252,7 @@ function parseInfoLikeEntry(tokens, line, errorMessage) {
|
|
|
921
1252
|
}
|
|
922
1253
|
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
923
1254
|
const fieldMap = collectDraftFields(node.fields);
|
|
924
|
-
const placement =
|
|
1255
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
925
1256
|
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
926
1257
|
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
927
1258
|
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
@@ -972,7 +1303,7 @@ function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
|
972
1303
|
object.tolerances = tolerances;
|
|
973
1304
|
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
974
1305
|
object.typedBlocks = typedBlocks;
|
|
975
|
-
if (sourceSchemaVersion
|
|
1306
|
+
if (isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
976
1307
|
if (object.groups ||
|
|
977
1308
|
object.epoch ||
|
|
978
1309
|
object.referencePlane ||
|
|
@@ -989,14 +1320,34 @@ function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
|
989
1320
|
}
|
|
990
1321
|
return object;
|
|
991
1322
|
}
|
|
992
|
-
function
|
|
1323
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
1324
|
+
return {
|
|
1325
|
+
...event,
|
|
1326
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
1327
|
+
tags: [...new Set(event.tags)],
|
|
1328
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose)),
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
function normalizeDraftEventPose(rawPose) {
|
|
1332
|
+
const fieldMap = collectDraftFields(rawPose.fields, "event-pose");
|
|
1333
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
1334
|
+
return {
|
|
1335
|
+
objectId: rawPose.objectId,
|
|
1336
|
+
placement,
|
|
1337
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
1338
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer"),
|
|
1339
|
+
epoch: parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]),
|
|
1340
|
+
referencePlane: parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0]),
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
function collectDraftFields(fields, _mode = "object") {
|
|
993
1344
|
const grouped = new Map();
|
|
994
1345
|
for (const field of fields) {
|
|
995
1346
|
const spec = getDraftObjectFieldSpec(field.key);
|
|
996
|
-
if (!spec) {
|
|
1347
|
+
if (!spec && !EVENT_POSE_FIELD_KEYS.has(field.key)) {
|
|
997
1348
|
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
998
1349
|
}
|
|
999
|
-
if (!spec
|
|
1350
|
+
if (!spec?.allowRepeat && grouped.has(field.key)) {
|
|
1000
1351
|
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
1001
1352
|
}
|
|
1002
1353
|
const existing = grouped.get(field.key) ?? [];
|
|
@@ -1005,7 +1356,7 @@ function collectDraftFields(fields) {
|
|
|
1005
1356
|
}
|
|
1006
1357
|
return grouped;
|
|
1007
1358
|
}
|
|
1008
|
-
function
|
|
1359
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
1009
1360
|
const orbitField = fieldMap.get("orbit")?.[0];
|
|
1010
1361
|
const atField = fieldMap.get("at")?.[0];
|
|
1011
1362
|
const surfaceField = fieldMap.get("surface")?.[0];
|
|
@@ -1174,7 +1525,7 @@ function validateDraftObjectFieldCompatibility(fields, objectType) {
|
|
|
1174
1525
|
}
|
|
1175
1526
|
}
|
|
1176
1527
|
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
1177
|
-
if (sourceSchemaVersion
|
|
1528
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "2.1")) {
|
|
1178
1529
|
return;
|
|
1179
1530
|
}
|
|
1180
1531
|
diagnostics.push({
|
|
@@ -1186,6 +1537,34 @@ function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, lo
|
|
|
1186
1537
|
column: location.column,
|
|
1187
1538
|
});
|
|
1188
1539
|
}
|
|
1540
|
+
function warnIfSchema25Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
1541
|
+
if (!isSchemaOlderThan(sourceSchemaVersion, "2.5")) {
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
diagnostics.push({
|
|
1545
|
+
code: "parse.schema25.featureCompatibility",
|
|
1546
|
+
severity: "warning",
|
|
1547
|
+
source: "parse",
|
|
1548
|
+
message: `Feature "${featureName}" requires schema 2.5; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
1549
|
+
line: location.line,
|
|
1550
|
+
column: location.column,
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
function isSchemaOlderThan(sourceSchemaVersion, requiredVersion) {
|
|
1554
|
+
return schemaVersionRank(sourceSchemaVersion) < schemaVersionRank(requiredVersion);
|
|
1555
|
+
}
|
|
1556
|
+
function schemaVersionRank(version) {
|
|
1557
|
+
switch (version) {
|
|
1558
|
+
case "2.0-draft":
|
|
1559
|
+
return 0;
|
|
1560
|
+
case "2.0":
|
|
1561
|
+
return 1;
|
|
1562
|
+
case "2.1":
|
|
1563
|
+
return 2;
|
|
1564
|
+
case "2.5":
|
|
1565
|
+
return 3;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1189
1568
|
function preprocessAtlasSource(source) {
|
|
1190
1569
|
const chars = [...source];
|
|
1191
1570
|
const comments = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SceneRenderOptions, WorldOrbitAtlasDocument, WorldOrbitAtlasSystem, WorldOrbitDiagnostic, WorldOrbitDocument, WorldOrbitObject } from "./types.js";
|
|
1
|
+
import type { SceneRenderOptions, WorldOrbitAtlasDocument, WorldOrbitEvent, WorldOrbitAtlasSystem, WorldOrbitDiagnostic, WorldOrbitDocument, WorldOrbitObject } from "./types.js";
|
|
2
2
|
interface UpgradeOptions extends Pick<SceneRenderOptions, "preset" | "projection"> {
|
|
3
3
|
}
|
|
4
4
|
export declare function upgradeDocumentToV2(document: WorldOrbitDocument, options?: UpgradeOptions): WorldOrbitAtlasDocument;
|
|
@@ -10,9 +10,12 @@ export declare function upgradeDocumentToDraftV2(document: WorldOrbitDocument, o
|
|
|
10
10
|
system: WorldOrbitAtlasSystem | null;
|
|
11
11
|
groups: import("./types.js").WorldOrbitGroup[];
|
|
12
12
|
relations: import("./types.js").WorldOrbitRelation[];
|
|
13
|
+
events: WorldOrbitEvent[];
|
|
13
14
|
objects: WorldOrbitObject[];
|
|
14
15
|
diagnostics: WorldOrbitDiagnostic[];
|
|
15
16
|
};
|
|
16
|
-
export declare function materializeAtlasDocument(document: WorldOrbitAtlasDocument
|
|
17
|
+
export declare function materializeAtlasDocument(document: WorldOrbitAtlasDocument, options?: {
|
|
18
|
+
activeEventId?: string | null;
|
|
19
|
+
}): WorldOrbitDocument;
|
|
17
20
|
export declare function materializeDraftDocument(document: WorldOrbitAtlasDocument): WorldOrbitDocument;
|
|
18
21
|
export {};
|