@ifc-lite/geometry 7.2.0 → 7.3.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.
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Moving already-loaded models onto the federation's RTC anchor (#4897).
3
+ *
4
+ * A model with small coordinates gets no `wasmRtcOffset` at load and is meshed
5
+ * raw. When a model that needs a real RTC anchor joins the federation, that
6
+ * anchor becomes the shared frame (`chooseSharedRtcOffset`, `world-frame.ts`),
7
+ * so every model meshed before it — and any model that finished loading in
8
+ * parallel against a different frame — has to move onto it, or it renders in a
9
+ * frame nothing else shares.
10
+ *
11
+ * This is a plain axis-aligned translation, not a CRS reprojection: both
12
+ * anchors are metres in the same IFC axes, so there is no rotation or unit
13
+ * conversion to apply.
14
+ *
15
+ * PRECISION. The translation goes into each mesh's f64 `origin`, never into its
16
+ * f32 `positions`. The delta is the anchor itself when a raw model moves, i.e.
17
+ * map-coordinate magnitude (Swiss LV95 ~2.6e6 m, UTM northings ~5e6 m), where
18
+ * one f32 ULP is 0.25-0.5 m: baking it into the vertices collapses millimetre
19
+ * detail to zero. Moving the origin keeps `positions` bit-identical and leaves
20
+ * the mesh in exactly the shape the wasm mesher produces when the anchor was
21
+ * already known at load (f64 origin = element centre minus the RTC, small f32
22
+ * local detail), so both load orders render from the same kind of data.
23
+ */
24
+ import type { CoordinateInfo, Vec3 } from './coordinate-types.js';
25
+ type Origin = [number, number, number];
26
+ /**
27
+ * The render-frame (Y-up) translation that turns a mesh produced against
28
+ * `fromOffset` (IFC Z-up; absent means the raw frame) into one produced
29
+ * against `toOffset`. Render-frame coordinates are `world - offset`, so the
30
+ * mesh moves by `-delta`.
31
+ */
32
+ export declare function rtcRebaseDeltaYup(fromOffset: Readonly<Vec3> | null | undefined, toOffset: Readonly<Vec3>): Vec3;
33
+ /**
34
+ * A mesh origin moved by `-delta`, as a NEW array (origins may be shared
35
+ * between pieces, so never write through the old one). An absent origin means
36
+ * the positions are absolute render-frame values, which is origin `[0,0,0]`.
37
+ */
38
+ export declare function rebaseOriginByRtcDelta(origin: Readonly<Origin> | null | undefined, delta: Readonly<Vec3>): Origin;
39
+ /** {@link rtcRebaseDeltaYup} from the frame `info` records to `anchor`. */
40
+ export declare function rtcRebaseDeltaFor(info: CoordinateInfo, anchor: Readonly<Vec3>): Vec3;
41
+ /** Whether `info` is already drawn against `anchor` (same IFC offset, exactly). */
42
+ export declare function isOnRtcAnchor(info: CoordinateInfo, anchor: Readonly<Vec3>): boolean;
43
+ /**
44
+ * `info` re-expressed against `anchor`: both render-frame boxes move with the
45
+ * geometry, `wasmRtcOffset` records the new anchor, and `wasmRtcFrame` is
46
+ * replaced by the frame the geometry is now actually in. Keeping the old
47
+ * `wasmRtcFrame` would leave `needsShift: false` beside a set `wasmRtcOffset`,
48
+ * which the cache serialiser rejects and auxiliary parsers would trust.
49
+ *
50
+ * `originShift` is copied through: every render-frame value here is relative
51
+ * to `originShift + ifcToViewerAxes(wasmRtcOffset)` and only the second term
52
+ * changes, so the change in the total is exactly the RTC delta.
53
+ *
54
+ * Absolute-world fields are NOT in `CoordinateInfo` and are not touched by
55
+ * the caller either: `MeshData.geometryAabb` has the RTC folded back in and
56
+ * `MeshData.localToWorld` is the pre-RTC placement chain, both RTC-invariant.
57
+ */
58
+ export declare function rebaseCoordinateInfoOntoRtcAnchor(info: CoordinateInfo, anchor: Readonly<Vec3>): CoordinateInfo;
59
+ /** What {@link convergeGeometryOntoRtcAnchor} reads and rewrites per model. */
60
+ export interface RtcRebaseGeometry {
61
+ coordinateInfo: CoordinateInfo;
62
+ meshes: ReadonlyArray<{
63
+ origin?: Origin;
64
+ geometryClass?: number;
65
+ }>;
66
+ /** Present on a `GeometryResult`; read only by {@link carriesGpuInstancedGeometry}. */
67
+ instancedGeometryAabbs?: ReadonlyMap<number, unknown> | null;
68
+ /** Streamed point clouds: GPU-resident, never meshed against an RTC anchor. */
69
+ pointClouds?: ReadonlyArray<unknown> | null;
70
+ }
71
+ /**
72
+ * Whether a model carries GPU-instanced geometry, which this module cannot
73
+ * move: instanced occurrences are a class-2 template plus per-occurrence
74
+ * transforms decoded straight into renderer-owned instance buffers, and the
75
+ * content-version rebuild keeps the templates of a model that is still
76
+ * present. Moving the flat meshes anyway would split one model across two
77
+ * frames. Two signals, because `instancedGeometryAabbs` is absent when
78
+ * hashing is off and a class-2 template can be absent when hashing is on.
79
+ */
80
+ export declare function carriesGpuInstancedGeometry(geometry: RtcRebaseGeometry): boolean;
81
+ export interface RtcConvergeResult<T> {
82
+ /** Geometries moved onto the anchor (need a GPU rebuild and a spatial reindex). */
83
+ moved: T[];
84
+ /** Geometries NOT on the anchor that could not be moved (GPU-instanced). */
85
+ refused: T[];
86
+ }
87
+ /**
88
+ * Move every geometry that is not yet drawn against `anchor` onto it, in
89
+ * place: each mesh's `origin` and the `CoordinateInfo` frame fields change,
90
+ * `positions` never do. Geometries already on the anchor and point clouds are
91
+ * left alone; GPU-instanced geometries are reported in `refused` and left
92
+ * untouched, so the caller can tell the user which models stay split.
93
+ *
94
+ * Idempotent: a second call with the same anchor moves nothing.
95
+ */
96
+ export declare function convergeGeometryOntoRtcAnchor<T extends RtcRebaseGeometry>(geometries: readonly T[], anchor: Readonly<Vec3>,
97
+ /** Extra instancing evidence the caller holds outside the geometry (e.g.
98
+ * shards already handed to the renderer); `true` refuses the geometry. */
99
+ hasOtherInstancedGeometry?: (geometry: T) => boolean): RtcConvergeResult<T>;
100
+ export {};
101
+ //# sourceMappingURL=rtc-rebase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtc-rebase.d.ts","sourceRoot":"","sources":["../src/rtc-rebase.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAQ,cAAc,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAMxE,KAAK,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,EAC7C,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,GACvB,IAAI,CAQN;AAMD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAGjH;AAaD,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAEpF;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAEnF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,cAAc,CAS9G;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,aAAa,CAAC;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnE,uFAAuF;IACvF,sBAAsB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7D,+EAA+E;IAC/E,WAAW,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAGhF;AAWD,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,mFAAmF;IACnF,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,4EAA4E;IAC5E,OAAO,EAAE,CAAC,EAAE,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,CAAC,SAAS,iBAAiB,EACvE,UAAU,EAAE,SAAS,CAAC,EAAE,EACxB,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC;AACtB;2EAC2E;AAC3E,yBAAyB,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,OAAO,GACnD,iBAAiB,CAAC,CAAC,CAAC,CAqBtB"}
@@ -0,0 +1,135 @@
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
+ import { GEOM_CLASS_INSTANCED_TYPE, geometryClassOf } from './geometry-class.js';
5
+ import { ifcToViewerAxes } from './world-frame.js';
6
+ const ZERO = { x: 0, y: 0, z: 0 };
7
+ /**
8
+ * The render-frame (Y-up) translation that turns a mesh produced against
9
+ * `fromOffset` (IFC Z-up; absent means the raw frame) into one produced
10
+ * against `toOffset`. Render-frame coordinates are `world - offset`, so the
11
+ * mesh moves by `-delta`.
12
+ */
13
+ export function rtcRebaseDeltaYup(fromOffset, toOffset) {
14
+ const fromYup = ifcToViewerAxes(fromOffset ?? ZERO);
15
+ const toYup = ifcToViewerAxes(toOffset);
16
+ return {
17
+ x: toYup.x - fromYup.x,
18
+ y: toYup.y - fromYup.y,
19
+ z: toYup.z - fromYup.z,
20
+ };
21
+ }
22
+ function isZero(delta) {
23
+ return delta.x === 0 && delta.y === 0 && delta.z === 0;
24
+ }
25
+ /**
26
+ * A mesh origin moved by `-delta`, as a NEW array (origins may be shared
27
+ * between pieces, so never write through the old one). An absent origin means
28
+ * the positions are absolute render-frame values, which is origin `[0,0,0]`.
29
+ */
30
+ export function rebaseOriginByRtcDelta(origin, delta) {
31
+ const base = origin ?? [0, 0, 0];
32
+ return [base[0] - delta.x, base[1] - delta.y, base[2] - delta.z];
33
+ }
34
+ /**
35
+ * Shifting the two corners is sound only because this is a pure translation:
36
+ * every corner moves by the same vector, so the minimum corner stays minimum.
37
+ */
38
+ function shiftBounds(bounds, delta) {
39
+ return {
40
+ min: { x: bounds.min.x - delta.x, y: bounds.min.y - delta.y, z: bounds.min.z - delta.z },
41
+ max: { x: bounds.max.x - delta.x, y: bounds.max.y - delta.y, z: bounds.max.z - delta.z },
42
+ };
43
+ }
44
+ /** {@link rtcRebaseDeltaYup} from the frame `info` records to `anchor`. */
45
+ export function rtcRebaseDeltaFor(info, anchor) {
46
+ return rtcRebaseDeltaYup(info.wasmRtcOffset, anchor);
47
+ }
48
+ /** Whether `info` is already drawn against `anchor` (same IFC offset, exactly). */
49
+ export function isOnRtcAnchor(info, anchor) {
50
+ return isZero(rtcRebaseDeltaFor(info, anchor));
51
+ }
52
+ /**
53
+ * `info` re-expressed against `anchor`: both render-frame boxes move with the
54
+ * geometry, `wasmRtcOffset` records the new anchor, and `wasmRtcFrame` is
55
+ * replaced by the frame the geometry is now actually in. Keeping the old
56
+ * `wasmRtcFrame` would leave `needsShift: false` beside a set `wasmRtcOffset`,
57
+ * which the cache serialiser rejects and auxiliary parsers would trust.
58
+ *
59
+ * `originShift` is copied through: every render-frame value here is relative
60
+ * to `originShift + ifcToViewerAxes(wasmRtcOffset)` and only the second term
61
+ * changes, so the change in the total is exactly the RTC delta.
62
+ *
63
+ * Absolute-world fields are NOT in `CoordinateInfo` and are not touched by
64
+ * the caller either: `MeshData.geometryAabb` has the RTC folded back in and
65
+ * `MeshData.localToWorld` is the pre-RTC placement chain, both RTC-invariant.
66
+ */
67
+ export function rebaseCoordinateInfoOntoRtcAnchor(info, anchor) {
68
+ const delta = rtcRebaseDeltaFor(info, anchor);
69
+ return {
70
+ ...info,
71
+ originalBounds: shiftBounds(info.originalBounds, delta),
72
+ shiftedBounds: shiftBounds(info.shiftedBounds, delta),
73
+ wasmRtcOffset: { ...anchor },
74
+ wasmRtcFrame: { x: anchor.x, y: anchor.y, z: anchor.z, needsShift: true },
75
+ };
76
+ }
77
+ /**
78
+ * Whether a model carries GPU-instanced geometry, which this module cannot
79
+ * move: instanced occurrences are a class-2 template plus per-occurrence
80
+ * transforms decoded straight into renderer-owned instance buffers, and the
81
+ * content-version rebuild keeps the templates of a model that is still
82
+ * present. Moving the flat meshes anyway would split one model across two
83
+ * frames. Two signals, because `instancedGeometryAabbs` is absent when
84
+ * hashing is off and a class-2 template can be absent when hashing is on.
85
+ */
86
+ export function carriesGpuInstancedGeometry(geometry) {
87
+ if (geometry.instancedGeometryAabbs != null && geometry.instancedGeometryAabbs.size > 0)
88
+ return true;
89
+ return geometry.meshes.some((mesh) => geometryClassOf(mesh) === GEOM_CLASS_INSTANCED_TYPE);
90
+ }
91
+ /**
92
+ * Point clouds never take part in the RTC frame: the ingest registers them
93
+ * raw in every load order (the georeference alignment is their only frame
94
+ * move), so they are neither moved nor refused.
95
+ */
96
+ function isPointCloudOnly(geometry) {
97
+ return (geometry.pointClouds?.length ?? 0) > 0 && geometry.meshes.length === 0;
98
+ }
99
+ /**
100
+ * Move every geometry that is not yet drawn against `anchor` onto it, in
101
+ * place: each mesh's `origin` and the `CoordinateInfo` frame fields change,
102
+ * `positions` never do. Geometries already on the anchor and point clouds are
103
+ * left alone; GPU-instanced geometries are reported in `refused` and left
104
+ * untouched, so the caller can tell the user which models stay split.
105
+ *
106
+ * Idempotent: a second call with the same anchor moves nothing.
107
+ */
108
+ export function convergeGeometryOntoRtcAnchor(geometries, anchor,
109
+ /** Extra instancing evidence the caller holds outside the geometry (e.g.
110
+ * shards already handed to the renderer); `true` refuses the geometry. */
111
+ hasOtherInstancedGeometry) {
112
+ const moved = [];
113
+ const refused = [];
114
+ const seenMeshes = new Set();
115
+ for (const geometry of new Set(geometries)) {
116
+ if (isPointCloudOnly(geometry) || isOnRtcAnchor(geometry.coordinateInfo, anchor))
117
+ continue;
118
+ if (carriesGpuInstancedGeometry(geometry) || hasOtherInstancedGeometry?.(geometry) === true) {
119
+ refused.push(geometry);
120
+ continue;
121
+ }
122
+ const delta = rtcRebaseDeltaFor(geometry.coordinateInfo, anchor);
123
+ for (const mesh of geometry.meshes) {
124
+ // A MeshData object shared between two results must move once.
125
+ if (seenMeshes.has(mesh))
126
+ continue;
127
+ seenMeshes.add(mesh);
128
+ mesh.origin = rebaseOriginByRtcDelta(mesh.origin, delta);
129
+ }
130
+ geometry.coordinateInfo = rebaseCoordinateInfoOntoRtcAnchor(geometry.coordinateInfo, anchor);
131
+ moved.push(geometry);
132
+ }
133
+ return { moved, refused };
134
+ }
135
+ //# sourceMappingURL=rtc-rebase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtc-rebase.js","sourceRoot":"","sources":["../src/rtc-rebase.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -174,9 +174,12 @@ export interface MeshData {
174
174
  max: [number, number, number];
175
175
  };
176
176
  /** The resolved `IfcLocalPlacement` chain applied to this mesh (issue
177
- * #1474): row-major 4x4, 16 numbers, WebGL Y-up metres (same frame as
178
- * `positions`). Absent when not captured. All of one entity's `MeshData`
179
- * pieces share the same value (one placement per element). */
177
+ * #1474): row-major 4x4, 16 numbers, WebGL Y-up axis convention — but its
178
+ * translation is the placement's PRE-RTC absolute origin, not the frame
179
+ * `positions` render in (`mesh_world.rs` assigns this before subtracting
180
+ * the model's RTC offset). Do NOT shift it when RTC changes. Absent when
181
+ * not captured. All of one entity's `MeshData` pieces share the same
182
+ * value (one placement per element). */
180
183
  localToWorld?: number[];
181
184
  }
182
185
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAwW/D,8EAA8E;AAC9E,gCAAgC;AAChC,2EAA2E;AAC3E,8EAA8E;AAE9E,kFAAkF;AAClF,6EAA6E;AAC7E,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AA2W/D,8EAA8E;AAC9E,gCAAgC;AAChC,2EAA2E;AAC3E,8EAA8E;AAE9E,kFAAkF;AAClF,6EAA6E;AAC7E,cAAc,qBAAqB,CAAC"}
@@ -42,8 +42,10 @@ export declare function totalYupOffset(info?: RenderFrameInfo | null): Vec3;
42
42
  export declare function renderFrameWorldOffset(info?: RenderFrameInfo | null): Vec3;
43
43
  /** A loaded model as far as the federation frame rule is concerned. */
44
44
  export interface FrameCandidate {
45
- /** Load order; the earliest-loaded model owns the shared frame. */
45
+ /** Load order; the earliest-loaded anchored model owns the shared frame. */
46
46
  loadedAt: number;
47
+ /** A model still loading, or failed, has not been converged onto, so it cannot define the frame. */
48
+ loadState?: string;
47
49
  geometryResult?: {
48
50
  coordinateInfo?: CoordinateInfo | null;
49
51
  } | null;
@@ -51,12 +53,49 @@ export interface FrameCandidate {
51
53
  /**
52
54
  * The `CoordinateInfo` whose frame a set of loaded models is drawn in.
53
55
  *
54
- * A federation is aligned to the earliest-loaded model's RTC frame at load,
55
- * so that model's offsets ARE the scene's offsets; reading a later model's
56
- * would describe a frame nothing is drawn in. `fallback` covers a single
57
- * model loaded without a federation entry. Null when nothing has geometry.
56
+ * The rule is the anchor rule (#4897): the earliest-loaded model that HAS a
57
+ * `wasmRtcOffset` defines the frame; only when no model has one does the
58
+ * earliest-loaded model with any `coordinateInfo` answer (every model is then
59
+ * raw). The federation loader converges every other meshed model onto that
60
+ * same anchor after each load (`rtc-rebase.ts`, via the viewer's
61
+ * `federationRtcRebase.ts`), so in either load order this returns the frame the
62
+ * geometry is actually in. The earlier "earliest model with any
63
+ * `coordinateInfo`" rule reported a near-origin model's raw frame whenever it
64
+ * was loaded first, including for a raw point cloud, which never joins the
65
+ * RTC frame.
66
+ *
67
+ * Models whose `loadState` is `pending`, `streaming-geometry` or `error` are
68
+ * only considered when no settled model has a frame. The same set the
69
+ * convergence treats as settled: until such a load settles the other models
70
+ * have not been converged onto its anchor, so the settled frame stays the
71
+ * reported one.
72
+ *
73
+ * `fallback` covers a single model loaded without a federation entry. Null
74
+ * when nothing has geometry. The one case where the geometry does NOT all
75
+ * match is a GPU-instanced model the loader could not move; the viewer
76
+ * reports that to the user instead of leaving it silent.
58
77
  */
59
78
  export declare function federationFrameInfo(models: Iterable<FrameCandidate>, fallback?: {
60
79
  coordinateInfo?: CoordinateInfo | null;
61
80
  } | null): CoordinateInfo | null;
81
+ /**
82
+ * The real `wasmRtcOffset` a single model carries, or `null` if it has none
83
+ * (still meshed raw). The single-candidate counterpart to
84
+ * {@link chooseSharedRtcOffset}: callers that need one specific model's own
85
+ * anchor — e.g. to decide whether it just introduced the federation's
86
+ * first real anchor — read it through here rather than destructuring
87
+ * `geometryResult.coordinateInfo.wasmRtcOffset` themselves.
88
+ */
89
+ export declare function realRtcAnchorOf(candidate?: FrameCandidate | null): Readonly<Vec3> | null;
90
+ /**
91
+ * The `sharedRtcOffset` a newly-loading model should be given: the earliest
92
+ * already-loaded model's `wasmRtcOffset`, or `undefined` when no
93
+ * already-loaded model has one yet (including when there is no earlier
94
+ * model at all) — the loading model is then free to detect its own.
95
+ *
96
+ * The same rule picks the anchor every already-loaded model is converged onto
97
+ * after a load (`rtc-rebase.ts`), so a model loaded before the first anchored
98
+ * one is moved onto it rather than left in the raw frame it was meshed in.
99
+ */
100
+ export declare function chooseSharedRtcOffset(existingModels: Iterable<FrameCandidate>): Vec3 | undefined;
62
101
  //# sourceMappingURL=world-frame.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"world-frame.d.ts","sourceRoot":"","sources":["../src/world-frame.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAIlE,gFAAgF;AAChF,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpC,aAAa,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAE3D;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAE3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAQlE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAG1E;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACpE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,QAAQ,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,GAC3D,cAAc,GAAG,IAAI,CAWvB"}
1
+ {"version":3,"file":"world-frame.d.ts","sourceRoot":"","sources":["../src/world-frame.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAIlE,gFAAgF;AAChF,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpC,aAAa,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAE3D;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAE3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAQlE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAG1E;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,oGAAoG;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,QAAQ,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,GAC3D,cAAc,GAAG,IAAI,CAIvB;AAuBD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAExF;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,IAAI,GAAG,SAAS,CAWhG"}
@@ -39,21 +39,85 @@ export function renderFrameWorldOffset(info) {
39
39
  /**
40
40
  * The `CoordinateInfo` whose frame a set of loaded models is drawn in.
41
41
  *
42
- * A federation is aligned to the earliest-loaded model's RTC frame at load,
43
- * so that model's offsets ARE the scene's offsets; reading a later model's
44
- * would describe a frame nothing is drawn in. `fallback` covers a single
45
- * model loaded without a federation entry. Null when nothing has geometry.
42
+ * The rule is the anchor rule (#4897): the earliest-loaded model that HAS a
43
+ * `wasmRtcOffset` defines the frame; only when no model has one does the
44
+ * earliest-loaded model with any `coordinateInfo` answer (every model is then
45
+ * raw). The federation loader converges every other meshed model onto that
46
+ * same anchor after each load (`rtc-rebase.ts`, via the viewer's
47
+ * `federationRtcRebase.ts`), so in either load order this returns the frame the
48
+ * geometry is actually in. The earlier "earliest model with any
49
+ * `coordinateInfo`" rule reported a near-origin model's raw frame whenever it
50
+ * was loaded first, including for a raw point cloud, which never joins the
51
+ * RTC frame.
52
+ *
53
+ * Models whose `loadState` is `pending`, `streaming-geometry` or `error` are
54
+ * only considered when no settled model has a frame. The same set the
55
+ * convergence treats as settled: until such a load settles the other models
56
+ * have not been converged onto its anchor, so the settled frame stays the
57
+ * reported one.
58
+ *
59
+ * `fallback` covers a single model loaded without a federation entry. Null
60
+ * when nothing has geometry. The one case where the geometry does NOT all
61
+ * match is a GPU-instanced model the loader could not move; the viewer
62
+ * reports that to the user instead of leaving it silent.
46
63
  */
47
64
  export function federationFrameInfo(models, fallback) {
65
+ const all = [...models];
66
+ const settled = all.filter((model) => model.loadState !== 'pending' && model.loadState !== 'streaming-geometry' && model.loadState !== 'error');
67
+ return frameOf(settled) ?? frameOf(all) ?? fallback?.coordinateInfo ?? null;
68
+ }
69
+ /** The anchor rule over one candidate set: earliest anchored, else earliest with a frame. */
70
+ function frameOf(models) {
48
71
  let earliest = Infinity;
72
+ let earliestAnchored = Infinity;
49
73
  let info = null;
74
+ let anchoredInfo = null;
50
75
  for (const model of models) {
51
76
  const candidate = model.geometryResult?.coordinateInfo;
52
- if (candidate && model.loadedAt < earliest) {
77
+ if (!candidate)
78
+ continue;
79
+ if (model.loadedAt < earliest) {
53
80
  earliest = model.loadedAt;
54
81
  info = candidate;
55
82
  }
83
+ if (candidate.wasmRtcOffset != null && model.loadedAt < earliestAnchored) {
84
+ earliestAnchored = model.loadedAt;
85
+ anchoredInfo = candidate;
86
+ }
87
+ }
88
+ return anchoredInfo ?? info;
89
+ }
90
+ /**
91
+ * The real `wasmRtcOffset` a single model carries, or `null` if it has none
92
+ * (still meshed raw). The single-candidate counterpart to
93
+ * {@link chooseSharedRtcOffset}: callers that need one specific model's own
94
+ * anchor — e.g. to decide whether it just introduced the federation's
95
+ * first real anchor — read it through here rather than destructuring
96
+ * `geometryResult.coordinateInfo.wasmRtcOffset` themselves.
97
+ */
98
+ export function realRtcAnchorOf(candidate) {
99
+ return candidate?.geometryResult?.coordinateInfo?.wasmRtcOffset ?? null;
100
+ }
101
+ /**
102
+ * The `sharedRtcOffset` a newly-loading model should be given: the earliest
103
+ * already-loaded model's `wasmRtcOffset`, or `undefined` when no
104
+ * already-loaded model has one yet (including when there is no earlier
105
+ * model at all) — the loading model is then free to detect its own.
106
+ *
107
+ * The same rule picks the anchor every already-loaded model is converged onto
108
+ * after a load (`rtc-rebase.ts`), so a model loaded before the first anchored
109
+ * one is moved onto it rather than left in the raw frame it was meshed in.
110
+ */
111
+ export function chooseSharedRtcOffset(existingModels) {
112
+ let earliestOffsetAt = Infinity;
113
+ let earliestOffset = null;
114
+ for (const model of existingModels) {
115
+ const offset = model.geometryResult?.coordinateInfo?.wasmRtcOffset;
116
+ if (offset != null && model.loadedAt < earliestOffsetAt) {
117
+ earliestOffsetAt = model.loadedAt;
118
+ earliestOffset = offset;
119
+ }
56
120
  }
57
- return info ?? fallback?.coordinateInfo ?? null;
121
+ return earliestOffset ? { ...earliestOffset } : undefined;
58
122
  }
59
123
  //# sourceMappingURL=world-frame.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"world-frame.js","sourceRoot":"","sources":["../src/world-frame.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAsB/D,MAAM,IAAI,GAAS,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AAQxC;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAA6B;IAC1D,MAAM,KAAK,GAAG,IAAI,EAAE,WAAW,IAAI,IAAI,CAAC;IACxC,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,EAAE,aAAa,IAAI,IAAI,CAAC,CAAC;IAC5D,OAAO;QACL,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QACrB,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QACrB,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;KACtB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAA6B;IAClE,MAAM,MAAM,GAAG,eAAe,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,OAAO,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;AAC/D,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAgC,EAChC,QAA4D;IAE5D,IAAI,QAAQ,GAAG,QAAQ,CAAC;IACxB,IAAI,IAAI,GAA0B,IAAI,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,cAAc,EAAE,cAAc,CAAC;QACvD,IAAI,SAAS,IAAI,KAAK,CAAC,QAAQ,GAAG,QAAQ,EAAE,CAAC;YAC3C,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YAC1B,IAAI,GAAG,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,IAAI,QAAQ,EAAE,cAAc,IAAI,IAAI,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"world-frame.js","sourceRoot":"","sources":["../src/world-frame.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifc-lite/geometry",
3
- "version": "7.2.0",
3
+ "version": "7.3.0",
4
4
  "description": "Geometry processing bridge for IFC-Lite - exact-arithmetic CSG, streamed across workers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,10 +20,15 @@
20
20
  "types": "./dist/world-frame.d.ts",
21
21
  "import": "./dist/world-frame.js",
22
22
  "default": "./dist/world-frame.js"
23
+ },
24
+ "./rtc-rebase": {
25
+ "types": "./dist/rtc-rebase.d.ts",
26
+ "import": "./dist/rtc-rebase.js",
27
+ "default": "./dist/rtc-rebase.js"
23
28
  }
24
29
  },
25
30
  "dependencies": {
26
- "@ifc-lite/data": "^4.4.0",
31
+ "@ifc-lite/data": "^4.5.0",
27
32
  "@ifc-lite/wasm": "^9.1.0",
28
33
  "@ifc-lite/wasm-lifecycle": "^0.2.0"
29
34
  },