@ifc-lite/bcf 2.0.0 → 3.0.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.
Files changed (41) hide show
  1. package/README.md +12 -1
  2. package/dist/ids-camera.d.ts +115 -0
  3. package/dist/ids-camera.d.ts.map +1 -0
  4. package/dist/ids-camera.js +266 -0
  5. package/dist/ids-camera.js.map +1 -0
  6. package/dist/ids-reporter.d.ts +17 -13
  7. package/dist/ids-reporter.d.ts.map +1 -1
  8. package/dist/ids-reporter.js +32 -64
  9. package/dist/ids-reporter.js.map +1 -1
  10. package/dist/numeric.d.ts +64 -1
  11. package/dist/numeric.d.ts.map +1 -1
  12. package/dist/numeric.js +81 -1
  13. package/dist/numeric.js.map +1 -1
  14. package/dist/reader-components.d.ts +1 -1
  15. package/dist/reader-components.d.ts.map +1 -1
  16. package/dist/reader-components.js +49 -10
  17. package/dist/reader-components.js.map +1 -1
  18. package/dist/reader.js +28 -30
  19. package/dist/reader.js.map +1 -1
  20. package/dist/types.d.ts +30 -8
  21. package/dist/types.d.ts.map +1 -1
  22. package/dist/viewpoint.d.ts +10 -0
  23. package/dist/viewpoint.d.ts.map +1 -1
  24. package/dist/viewpoint.js +12 -0
  25. package/dist/viewpoint.js.map +1 -1
  26. package/dist/writer-camera.d.ts +46 -0
  27. package/dist/writer-camera.d.ts.map +1 -0
  28. package/dist/writer-camera.js +131 -0
  29. package/dist/writer-camera.js.map +1 -0
  30. package/dist/writer.d.ts.map +1 -1
  31. package/dist/writer.js +118 -198
  32. package/dist/writer.js.map +1 -1
  33. package/dist/xml-text.d.ts +62 -5
  34. package/dist/xml-text.d.ts.map +1 -1
  35. package/dist/xml-text.js +131 -8
  36. package/dist/xml-text.js.map +1 -1
  37. package/dist/xsd-required-string.d.ts +38 -0
  38. package/dist/xsd-required-string.d.ts.map +1 -0
  39. package/dist/xsd-required-string.js +158 -0
  40. package/dist/xsd-required-string.js.map +1 -0
  41. package/package.json +3 -3
package/README.md CHANGED
@@ -54,7 +54,12 @@ const url = URL.createObjectURL(blob);
54
54
  ## Add a viewpoint with selection
55
55
 
56
56
  ```typescript
57
- import { createViewpoint, addViewpointToTopic } from '@ifc-lite/bcf';
57
+ import { createBCFTopic, createViewpoint, addViewpointToTopic } from '@ifc-lite/bcf';
58
+
59
+ const topic = createBCFTopic({
60
+ title: 'Missing fire rating on east-facade walls',
61
+ author: 'reviewer@example.com',
62
+ });
58
63
 
59
64
  const viewpoint = createViewpoint({
60
65
  camera: {
@@ -62,6 +67,12 @@ const viewpoint = createViewpoint({
62
67
  target: { x: 0, y: 0, z: 0 },
63
68
  up: { x: 0, y: 0, z: 1 },
64
69
  fov: Math.PI / 3, // field of view in radians (60 degrees)
70
+ // Required for BCF 3.0 (viewport width / height, must be > 0). v3_0's
71
+ // visinfo.xsd makes `<AspectRatio>` mandatory on every camera and this
72
+ // package will not invent one, so `writeBCF` throws for the whole archive
73
+ // on the first camera that lacks it. Omit it only when writing 2.1, which
74
+ // has no such element.
75
+ aspectRatio: 16 / 9,
65
76
  },
66
77
  // Highlight specific entities by their IFC GlobalId
67
78
  selectedGuids: ['1abc2def3GhI4jKlM5nOpQ', '2bcd3efg4HiJ5kLmN6oPqR'],
@@ -0,0 +1,115 @@
1
+ /**
2
+ * The camera half of the IDS to BCF reporter.
3
+ *
4
+ * Split out of `ids-reporter.ts` because BCF 3.0's camera rules are a policy
5
+ * of their own: `v3_0/visinfo.xsd` declares `OrthogonalCamera` and
6
+ * `PerspectiveCamera` as an `xs:choice` with the default `minOccurs`/
7
+ * `maxOccurs` of 1 (exactly one camera per viewpoint, required), and makes
8
+ * `<AspectRatio>` a required child of both. The reporter builds its own
9
+ * viewpoints rather than going through `createViewpoint`, so nothing else in
10
+ * this package enforced either rule for it -- both violations surfaced only
11
+ * from `writeBCF`, whole archives at a time, with no way back to the export
12
+ * option that caused them (#3849).
13
+ */
14
+ import type { BCFPerspectiveCamera, BCFProject } from './types.js';
15
+ /** Bounds for an entity, used for camera computation (viewer Y-up coords) */
16
+ export interface EntityBoundsInput {
17
+ min: {
18
+ x: number;
19
+ y: number;
20
+ z: number;
21
+ };
22
+ max: {
23
+ x: number;
24
+ y: number;
25
+ z: number;
26
+ };
27
+ }
28
+ /**
29
+ * Aspect ratio a computed camera gets when the caller names none.
30
+ *
31
+ * There is no viewport behind an IDS report -- the camera is derived from
32
+ * entity bounds, headlessly, and may never have been on screen. 16/9 is the
33
+ * convention for "no viewport existed": it is what the BCF sample files and
34
+ * the common desktop viewports use, and a viewer restoring the viewpoint
35
+ * re-frames to its own aspect anyway. This is the one place in the package
36
+ * that invents an aspect ratio, and it does so because a computed camera has
37
+ * no captured value to preserve; `writer-camera.ts` still refuses to invent
38
+ * one for a camera the CALLER supplied.
39
+ */
40
+ export declare const DEFAULT_ASPECT_RATIO: number;
41
+ /**
42
+ * Refuse an `aspectRatio` export option that no camera could carry.
43
+ *
44
+ * `visinfo.xsd` types `AspectRatio` as `PositiveDouble` -- `xs:double` with
45
+ * `minExclusive value="0"` -- so `0`, a negative number, `NaN` and `Infinity`
46
+ * are all invalid, and `writer-camera.ts` already rejects them. It can only
47
+ * name the viewpoint GUID it was writing, though: a value this package
48
+ * generated, for whichever topic came first, traceable to nothing the caller
49
+ * typed. Checking the option where the caller set it is the difference
50
+ * between "fix this argument" and "bisect your report".
51
+ *
52
+ * Checked for BOTH versions even though 2.1 emits no `AspectRatio`: the value
53
+ * is still wrong, it still lands on every camera in the project, and
54
+ * `readBCF` + re-export is how a 2.1 project becomes a 3.0 one.
55
+ */
56
+ export declare function requireAspectRatioOption(aspectRatio: number): number;
57
+ /**
58
+ * Slack left around the framed box, as a multiple of the fitted distance.
59
+ *
60
+ * The fit below puts the worst corner exactly on the frustum edge, which
61
+ * reads as a crop in any viewer that letterboxes or draws a border.
62
+ *
63
+ * Exported so the tests can take the padding back out and assert the fit
64
+ * underneath it is TIGHT. `cornersOutsideFrustum` is monotone in distance, so
65
+ * without that the whole corner-fit suite would pass on a camera parked
66
+ * arbitrarily far away.
67
+ */
68
+ export declare const FRAMING_PADDING = 1.5;
69
+ /**
70
+ * Compute a BCF perspective camera from entity bounds.
71
+ *
72
+ * Bounds are in viewer coordinates (Y-up).
73
+ * BCF uses Z-up, so we convert:
74
+ * BCF.x = Viewer.x
75
+ * BCF.y = -Viewer.z
76
+ * BCF.z = Viewer.y
77
+ *
78
+ * Camera is placed at a southeast-isometric angle from the entity center,
79
+ * at a distance that frames the entity's bounding box with padding.
80
+ *
81
+ * @param aspectRatio - viewport ratio (width / height) written to
82
+ * `AspectRatio` under BCF 3.0. 2.1 has no such element and the writer emits
83
+ * none there, so one value serves both versions.
84
+ */
85
+ export declare function computeCameraFromBounds(bounds: EntityBoundsInput, aspectRatio?: number): BCFPerspectiveCamera;
86
+ /**
87
+ * The union of the boxes for EVERY key given, or `undefined` if any key has
88
+ * none.
89
+ *
90
+ * All-or-nothing for the reason {@link unionBounds} documents: the
91
+ * per-specification viewpoint frames a whole group of entities, and a union
92
+ * over the subset that happened to have bounds is a camera that leaves the
93
+ * rest off screen while looking entirely plausible. `undefined` leaves the
94
+ * viewpoint camera-less, which {@link requireCamerasForVersion} turns into a
95
+ * 3.0 refusal naming the topic and the missing option (#3849).
96
+ */
97
+ export declare function unionBoundsForEveryKey(keys: readonly string[], entityBounds: Map<string, EntityBoundsInput> | undefined): EntityBoundsInput | undefined;
98
+ /**
99
+ * Refuse a 3.0 project whose viewpoints have no camera, naming the topic.
100
+ *
101
+ * The reporter can only give a viewpoint a camera when the caller supplied
102
+ * bounds for the entities in it. Without them there is nothing to compute
103
+ * from, and inventing a framing would assert a view of the model nobody has
104
+ * -- the same policy `writer-camera.ts` applies to a missing `AspectRatio`.
105
+ * So we refuse; the only question is WHERE.
106
+ *
107
+ * Here, rather than in `writeBCF`, because the caller's mistake is an export
108
+ * OPTION (`version: '3.0'` with no `entityBounds`), and `writeBCF` can only
109
+ * report the viewpoint GUID of whichever topic it reached first -- a GUID this
110
+ * function generated moments earlier, which appears in nothing the caller
111
+ * wrote. Naming the topic, and the option that fixes it, is the difference
112
+ * between an error the caller can act on and one they have to bisect.
113
+ */
114
+ export declare function requireCamerasForVersion(project: BCFProject): void;
115
+ //# sourceMappingURL=ids-camera.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids-camera.d.ts","sourceRoot":"","sources":["../src/ids-camera.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEnE,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAa3C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAUpE;AAqBD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AAgEnC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,iBAAiB,EACzB,WAAW,GAAE,MAA6B,GACzC,oBAAoB,CAsCtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,SAAS,GACvD,iBAAiB,GAAG,SAAS,CAQ/B;AAqCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAelE"}
@@ -0,0 +1,266 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Aspect ratio a computed camera gets when the caller names none.
6
+ *
7
+ * There is no viewport behind an IDS report -- the camera is derived from
8
+ * entity bounds, headlessly, and may never have been on screen. 16/9 is the
9
+ * convention for "no viewport existed": it is what the BCF sample files and
10
+ * the common desktop viewports use, and a viewer restoring the viewpoint
11
+ * re-frames to its own aspect anyway. This is the one place in the package
12
+ * that invents an aspect ratio, and it does so because a computed camera has
13
+ * no captured value to preserve; `writer-camera.ts` still refuses to invent
14
+ * one for a camera the CALLER supplied.
15
+ */
16
+ export const DEFAULT_ASPECT_RATIO = 16 / 9;
17
+ /**
18
+ * Vertical field of view of every computed camera, in degrees.
19
+ *
20
+ * Inside BCF 3.0's `(0, 180)` exclusive facet and BCF 2.1's `[45, 60]` one, so
21
+ * one value is writable under both.
22
+ */
23
+ const FIELD_OF_VIEW_DEGREES = 60;
24
+ /** How {@link DEFAULT_ASPECT_RATIO} reads in an error message. */
25
+ const DEFAULT_ASPECT_RATIO_TEXT = '16/9';
26
+ /**
27
+ * Refuse an `aspectRatio` export option that no camera could carry.
28
+ *
29
+ * `visinfo.xsd` types `AspectRatio` as `PositiveDouble` -- `xs:double` with
30
+ * `minExclusive value="0"` -- so `0`, a negative number, `NaN` and `Infinity`
31
+ * are all invalid, and `writer-camera.ts` already rejects them. It can only
32
+ * name the viewpoint GUID it was writing, though: a value this package
33
+ * generated, for whichever topic came first, traceable to nothing the caller
34
+ * typed. Checking the option where the caller set it is the difference
35
+ * between "fix this argument" and "bisect your report".
36
+ *
37
+ * Checked for BOTH versions even though 2.1 emits no `AspectRatio`: the value
38
+ * is still wrong, it still lands on every camera in the project, and
39
+ * `readBCF` + re-export is how a 2.1 project becomes a 3.0 one.
40
+ */
41
+ export function requireAspectRatioOption(aspectRatio) {
42
+ if (!Number.isFinite(aspectRatio) || aspectRatio <= 0) {
43
+ throw new Error(`createBCFFromIDSReport's aspectRatio option must be a finite number ` +
44
+ `greater than 0 (got ${aspectRatio}). BCF 3.0's visinfo.xsd types ` +
45
+ `AspectRatio as PositiveDouble, so this value could not be written; ` +
46
+ `omit the option to use the ${DEFAULT_ASPECT_RATIO_TEXT} default.`);
47
+ }
48
+ return aspectRatio;
49
+ }
50
+ function dot(a, b) {
51
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
52
+ }
53
+ function cross(a, b) {
54
+ return [
55
+ a[1] * b[2] - a[2] * b[1],
56
+ a[2] * b[0] - a[0] * b[2],
57
+ a[0] * b[1] - a[1] * b[0],
58
+ ];
59
+ }
60
+ function normalize(v) {
61
+ const len = Math.sqrt(dot(v, v));
62
+ return [v[0] / len, v[1] / len, v[2] / len];
63
+ }
64
+ /**
65
+ * Slack left around the framed box, as a multiple of the fitted distance.
66
+ *
67
+ * The fit below puts the worst corner exactly on the frustum edge, which
68
+ * reads as a crop in any viewer that letterboxes or draws a border.
69
+ *
70
+ * Exported so the tests can take the padding back out and assert the fit
71
+ * underneath it is TIGHT. `cornersOutsideFrustum` is monotone in distance, so
72
+ * without that the whole corner-fit suite would pass on a camera parked
73
+ * arbitrarily far away.
74
+ */
75
+ export const FRAMING_PADDING = 1.5;
76
+ /**
77
+ * Floor on the FITTED distance for a box with no size, in model units.
78
+ *
79
+ * A point fits at every distance including zero, which would put the camera
80
+ * inside the entity it is meant to be looking at. Floored before
81
+ * {@link FRAMING_PADDING} applies, so the standoff such a box actually gets is
82
+ * this times the padding.
83
+ */
84
+ const MIN_FRAMED_DISTANCE = 0.1;
85
+ /**
86
+ * The southeast-isometric camera basis, in viewer coordinates (Y-up).
87
+ *
88
+ * Fixed for every computed camera, so it is derived once here rather than per
89
+ * call. The camera sits at `center + CAMERA_OFFSET * distance` and looks back
90
+ * along `CAMERA_FORWARD`; `CAMERA_RIGHT` and `CAMERA_UP` are perpendicular to
91
+ * that, which is why the standoff cancels out of a corner's sideways offsets
92
+ * in the fit below and appears only in its depth.
93
+ */
94
+ const CAMERA_OFFSET = normalize([0.6, 0.5, 0.6]);
95
+ const CAMERA_FORWARD = [-CAMERA_OFFSET[0], -CAMERA_OFFSET[1], -CAMERA_OFFSET[2]];
96
+ const CAMERA_RIGHT = normalize(cross(CAMERA_FORWARD, [0, 1, 0]));
97
+ const CAMERA_UP = cross(CAMERA_RIGHT, CAMERA_FORWARD);
98
+ /**
99
+ * The smallest standoff along {@link CAMERA_OFFSET} that puts every corner of
100
+ * `bounds` inside both half-angles, before padding.
101
+ *
102
+ * The distance used to come from the largest SIDE of the box, which is not
103
+ * what the projection sees: down this isometric axis a box projects wider than
104
+ * any of its sides, so a unit cube's worst corner sat at a vertical slope of
105
+ * 0.837 against the tan(30 deg) = 0.577 limit at 16/9, and overran
106
+ * horizontally at 9/16 (#3882). Only the corners answer the question, so all
107
+ * eight are walked.
108
+ *
109
+ * A corner's sideways offsets `h` and `v` do not depend on the standoff, and
110
+ * its depth is `dot(corner, CAMERA_FORWARD) + distance`. It is inside when
111
+ * `h <= tanH * depth` and `v <= tanV * depth`; solving each for `distance` and
112
+ * taking the largest satisfies all sixteen constraints at once, because
113
+ * growing the distance only ever relaxes them.
114
+ */
115
+ function fitCornersInFrustum(bounds, center, tanH, tanV) {
116
+ let distance = 0;
117
+ for (const x of [bounds.min.x, bounds.max.x]) {
118
+ for (const y of [bounds.min.y, bounds.max.y]) {
119
+ for (const z of [bounds.min.z, bounds.max.z]) {
120
+ const corner = [x - center[0], y - center[1], z - center[2]];
121
+ const depthAtCenter = dot(corner, CAMERA_FORWARD);
122
+ const h = Math.abs(dot(corner, CAMERA_RIGHT)) / tanH;
123
+ const v = Math.abs(dot(corner, CAMERA_UP)) / tanV;
124
+ distance = Math.max(distance, h - depthAtCenter, v - depthAtCenter);
125
+ }
126
+ }
127
+ }
128
+ return distance;
129
+ }
130
+ /**
131
+ * Compute a BCF perspective camera from entity bounds.
132
+ *
133
+ * Bounds are in viewer coordinates (Y-up).
134
+ * BCF uses Z-up, so we convert:
135
+ * BCF.x = Viewer.x
136
+ * BCF.y = -Viewer.z
137
+ * BCF.z = Viewer.y
138
+ *
139
+ * Camera is placed at a southeast-isometric angle from the entity center,
140
+ * at a distance that frames the entity's bounding box with padding.
141
+ *
142
+ * @param aspectRatio - viewport ratio (width / height) written to
143
+ * `AspectRatio` under BCF 3.0. 2.1 has no such element and the writer emits
144
+ * none there, so one value serves both versions.
145
+ */
146
+ export function computeCameraFromBounds(bounds, aspectRatio = DEFAULT_ASPECT_RATIO) {
147
+ // Center in viewer coords (Y-up)
148
+ const center = [
149
+ (bounds.min.x + bounds.max.x) / 2,
150
+ (bounds.min.y + bounds.max.y) / 2,
151
+ (bounds.min.z + bounds.max.z) / 2,
152
+ ];
153
+ // `FieldOfView` is the VERTICAL angle in BCF, and the horizontal one follows
154
+ // from the aspect ratio: tan(hHalf) = aspectRatio * tan(vHalf). Both bound
155
+ // every corner below, so neither a portrait nor a landscape viewport crops
156
+ // the box.
157
+ const tanV = Math.tan((FIELD_OF_VIEW_DEGREES * Math.PI) / 360);
158
+ const tanH = aspectRatio * tanV;
159
+ const distance = Math.max(fitCornersInFrustum(bounds, center, tanH, tanV), MIN_FRAMED_DISTANCE) *
160
+ FRAMING_PADDING;
161
+ // Southeast-isometric position in viewer coords (Y-up).
162
+ const camX = center[0] + CAMERA_OFFSET[0] * distance;
163
+ const camY = center[1] + CAMERA_OFFSET[1] * distance;
164
+ const camZ = center[2] + CAMERA_OFFSET[2] * distance;
165
+ // Convert to BCF coords (Z-up)
166
+ // Viewer (x, y, z) → BCF (x, -z, y). The camera sits on the +CAMERA_OFFSET
167
+ // ray from the center, so it looks back along CAMERA_FORWARD exactly.
168
+ return {
169
+ cameraViewPoint: { x: camX, y: -camZ, z: camY },
170
+ cameraDirection: {
171
+ x: CAMERA_FORWARD[0],
172
+ y: -CAMERA_FORWARD[2],
173
+ z: CAMERA_FORWARD[1],
174
+ },
175
+ cameraUpVector: { x: 0, y: 0, z: 1 }, // BCF Z-up
176
+ fieldOfView: FIELD_OF_VIEW_DEGREES,
177
+ aspectRatio,
178
+ };
179
+ }
180
+ /**
181
+ * The union of the boxes for EVERY key given, or `undefined` if any key has
182
+ * none.
183
+ *
184
+ * All-or-nothing for the reason {@link unionBounds} documents: the
185
+ * per-specification viewpoint frames a whole group of entities, and a union
186
+ * over the subset that happened to have bounds is a camera that leaves the
187
+ * rest off screen while looking entirely plausible. `undefined` leaves the
188
+ * viewpoint camera-less, which {@link requireCamerasForVersion} turns into a
189
+ * 3.0 refusal naming the topic and the missing option (#3849).
190
+ */
191
+ export function unionBoundsForEveryKey(keys, entityBounds) {
192
+ const boxes = [];
193
+ for (const key of keys) {
194
+ const box = entityBounds?.get(key);
195
+ if (!box)
196
+ return undefined;
197
+ boxes.push(box);
198
+ }
199
+ return unionBounds(boxes);
200
+ }
201
+ /**
202
+ * The box containing every bound given, or `undefined` when none were.
203
+ *
204
+ * CONTRACT: the caller must pass a box for EVERY entity the viewpoint frames.
205
+ * A union over a subset is not a smaller mistake than no camera at all -- it
206
+ * is a camera that looks convincing and leaves the uncovered entities off
207
+ * screen, with nothing in the file saying so. `buildTopicsPerSpecification`
208
+ * therefore passes `undefined` unless it has bounds for all of them, which
209
+ * makes {@link requireCamerasForVersion} refuse the 3.0 export by name rather
210
+ * than write a partial frame.
211
+ *
212
+ * Per-specification grouping puts many entities in ONE viewpoint, so no single
213
+ * entity's box is the right frame for it. Framing the union is what lets that
214
+ * grouping produce a 3.0-writable camera at all -- otherwise `entityBounds`
215
+ * would be an option that fixes per-entity and per-requirement exports while
216
+ * leaving the third grouping permanently unwritable, and the refusal below
217
+ * would be naming a remedy that does not work for it.
218
+ */
219
+ function unionBounds(boxes) {
220
+ if (boxes.length === 0)
221
+ return undefined;
222
+ const min = { ...boxes[0].min };
223
+ const max = { ...boxes[0].max };
224
+ for (const box of boxes.slice(1)) {
225
+ min.x = Math.min(min.x, box.min.x);
226
+ min.y = Math.min(min.y, box.min.y);
227
+ min.z = Math.min(min.z, box.min.z);
228
+ max.x = Math.max(max.x, box.max.x);
229
+ max.y = Math.max(max.y, box.max.y);
230
+ max.z = Math.max(max.z, box.max.z);
231
+ }
232
+ return { min, max };
233
+ }
234
+ /**
235
+ * Refuse a 3.0 project whose viewpoints have no camera, naming the topic.
236
+ *
237
+ * The reporter can only give a viewpoint a camera when the caller supplied
238
+ * bounds for the entities in it. Without them there is nothing to compute
239
+ * from, and inventing a framing would assert a view of the model nobody has
240
+ * -- the same policy `writer-camera.ts` applies to a missing `AspectRatio`.
241
+ * So we refuse; the only question is WHERE.
242
+ *
243
+ * Here, rather than in `writeBCF`, because the caller's mistake is an export
244
+ * OPTION (`version: '3.0'` with no `entityBounds`), and `writeBCF` can only
245
+ * report the viewpoint GUID of whichever topic it reached first -- a GUID this
246
+ * function generated moments earlier, which appears in nothing the caller
247
+ * wrote. Naming the topic, and the option that fixes it, is the difference
248
+ * between an error the caller can act on and one they have to bisect.
249
+ */
250
+ export function requireCamerasForVersion(project) {
251
+ if (project.version !== '3.0')
252
+ return;
253
+ for (const topic of project.topics.values()) {
254
+ for (const viewpoint of topic.viewpoints) {
255
+ if (viewpoint.perspectiveCamera || viewpoint.orthogonalCamera)
256
+ continue;
257
+ throw new Error(`BCF 3.0 requires exactly one camera per viewpoint, and topic ` +
258
+ `"${topic.title}" (${topic.guid}) has a viewpoint with none. ` +
259
+ `createBCFFromIDSReport computes a camera only from entityBounds, ` +
260
+ `so pass entityBounds covering every reported entity ` +
261
+ `(keyed "modelId:expressId"), or export version "2.1" and set an ` +
262
+ `explicit camera on each viewpoint before writing 3.0.`);
263
+ }
264
+ }
265
+ }
266
+ //# sourceMappingURL=ids-camera.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids-camera.js","sourceRoot":"","sources":["../src/ids-camera.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,8 @@
17
17
  * - Configurable grouping strategies
18
18
  */
19
19
  import type { BCFProject } from './types.js';
20
+ import type { EntityBoundsInput } from './ids-camera.js';
21
+ export type { EntityBoundsInput } from './ids-camera.js';
20
22
  /** Input for the BCF reporter — structurally matches IDSValidationReport */
21
23
  export interface IDSReportInput {
22
24
  /** IDS document title */
@@ -63,19 +65,6 @@ export interface IDSEntityResultInput {
63
65
  passed: boolean;
64
66
  requirementResults: IDSRequirementResultInput[];
65
67
  }
66
- /** Bounds for an entity — used for camera computation in viewpoints (Y-up viewer coords) */
67
- export interface EntityBoundsInput {
68
- min: {
69
- x: number;
70
- y: number;
71
- z: number;
72
- };
73
- max: {
74
- x: number;
75
- y: number;
76
- z: number;
77
- };
78
- }
79
68
  /** Requirement result — structurally matches IDSRequirementResult */
80
69
  export interface IDSRequirementResultInput {
81
70
  status: 'pass' | 'fail' | 'not_applicable';
@@ -116,6 +105,21 @@ export interface IDSBCFExportOptions {
116
105
  * When provided, viewpoints will include a perspective camera framing the entity.
117
106
  */
118
107
  entityBounds?: Map<string, EntityBoundsInput>;
108
+ /**
109
+ * Viewport aspect ratio (width / height) for computed cameras.
110
+ *
111
+ * BCF 3.0's `visinfo.xsd` requires `<AspectRatio>` on every camera, and an
112
+ * IDS export is headless -- the camera is derived from entity bounds, so
113
+ * there is no viewport to read one from. Defaults to 16/9, the convention
114
+ * when no viewport exists; pass the real viewport ratio when the export runs
115
+ * beside one. 2.1 has no such element, so this changes nothing there.
116
+ *
117
+ * The viewer's own IDS export (`apps/viewer/src/hooks/useIDS.ts`, where it
118
+ * builds `exportOptions` for `createBCFFromIDSReport`) sets none today; it
119
+ * is the call site to wire `Camera.getAspect()` into if that dialog ever
120
+ * offers 3.0, which it currently does not.
121
+ */
122
+ aspectRatio?: number;
119
123
  /**
120
124
  * Entity snapshot map for attaching screenshots to viewpoints.
121
125
  * Key: "modelId:expressId", Value: data URL (PNG).
@@ -1 +1 @@
1
- {"version":3,"file":"ids-reporter.d.ts","sourceRoot":"","sources":["../src/ids-reporter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ids-reporter.d.ts","sourceRoot":"","sources":["../src/ids-reporter.ts"],"names":[],"mappings":"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"}