@ifc-lite/renderer 2.0.1 → 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 (180) hide show
  1. package/README.md +11 -1
  2. package/dist/appearance-batch-cohorts.d.ts +33 -0
  3. package/dist/appearance-batch-cohorts.d.ts.map +1 -0
  4. package/dist/appearance-batch-cohorts.js +126 -0
  5. package/dist/appearance-batch-cohorts.js.map +1 -0
  6. package/dist/appearance-companions.d.ts +30 -0
  7. package/dist/appearance-companions.d.ts.map +1 -0
  8. package/dist/appearance-companions.js +138 -0
  9. package/dist/appearance-companions.js.map +1 -0
  10. package/dist/appearance-partition.d.ts +32 -0
  11. package/dist/appearance-partition.d.ts.map +1 -0
  12. package/dist/appearance-partition.js +122 -0
  13. package/dist/appearance-partition.js.map +1 -0
  14. package/dist/appearance-preview.d.ts +97 -0
  15. package/dist/appearance-preview.d.ts.map +1 -0
  16. package/dist/appearance-preview.js +276 -0
  17. package/dist/appearance-preview.js.map +1 -0
  18. package/dist/appearance-uvs.d.ts +13 -0
  19. package/dist/appearance-uvs.d.ts.map +1 -0
  20. package/dist/appearance-uvs.js +136 -0
  21. package/dist/appearance-uvs.js.map +1 -0
  22. package/dist/bvh.d.ts.map +1 -1
  23. package/dist/bvh.js +3 -0
  24. package/dist/bvh.js.map +1 -1
  25. package/dist/deviation/deviation-computer.js +1 -1
  26. package/dist/deviation/deviation-computer.js.map +1 -1
  27. package/dist/index.d.ts +60 -18
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +186 -233
  30. package/dist/index.js.map +1 -1
  31. package/dist/merged-mesh-extract.d.ts +18 -0
  32. package/dist/merged-mesh-extract.d.ts.map +1 -0
  33. package/dist/merged-mesh-extract.js +73 -0
  34. package/dist/merged-mesh-extract.js.map +1 -0
  35. package/dist/model-bounds-tracker.d.ts +1 -1
  36. package/dist/model-bounds-tracker.d.ts.map +1 -1
  37. package/dist/model-bounds-tracker.js +3 -2
  38. package/dist/model-bounds-tracker.js.map +1 -1
  39. package/dist/model-placement-bounds.d.ts +29 -0
  40. package/dist/model-placement-bounds.d.ts.map +1 -0
  41. package/dist/model-placement-bounds.js +55 -0
  42. package/dist/model-placement-bounds.js.map +1 -0
  43. package/dist/model-translation.d.ts +57 -0
  44. package/dist/model-translation.d.ts.map +1 -0
  45. package/dist/model-translation.js +223 -0
  46. package/dist/model-translation.js.map +1 -0
  47. package/dist/partial-batch-cache.d.ts +65 -0
  48. package/dist/partial-batch-cache.d.ts.map +1 -0
  49. package/dist/partial-batch-cache.js +88 -0
  50. package/dist/partial-batch-cache.js.map +1 -0
  51. package/dist/partial-batch-requests.d.ts +77 -0
  52. package/dist/partial-batch-requests.d.ts.map +1 -0
  53. package/dist/partial-batch-requests.js +97 -0
  54. package/dist/partial-batch-requests.js.map +1 -0
  55. package/dist/picking-manager.js +2 -2
  56. package/dist/picking-manager.js.map +1 -1
  57. package/dist/point-picker.d.ts +2 -2
  58. package/dist/point-picker.d.ts.map +1 -1
  59. package/dist/point-picker.js +27 -21
  60. package/dist/point-picker.js.map +1 -1
  61. package/dist/pointcloud/point-cloud-node.d.ts +2 -0
  62. package/dist/pointcloud/point-cloud-node.d.ts.map +1 -1
  63. package/dist/pointcloud/point-cloud-node.js +12 -0
  64. package/dist/pointcloud/point-cloud-node.js.map +1 -1
  65. package/dist/pointcloud/point-cloud-placement.d.ts +20 -0
  66. package/dist/pointcloud/point-cloud-placement.d.ts.map +1 -0
  67. package/dist/pointcloud/point-cloud-placement.js +69 -0
  68. package/dist/pointcloud/point-cloud-placement.js.map +1 -0
  69. package/dist/pointcloud/point-cloud-renderer.d.ts +14 -14
  70. package/dist/pointcloud/point-cloud-renderer.d.ts.map +1 -1
  71. package/dist/pointcloud/point-cloud-renderer.js +47 -63
  72. package/dist/pointcloud/point-cloud-renderer.js.map +1 -1
  73. package/dist/raycast-engine.d.ts +11 -13
  74. package/dist/raycast-engine.d.ts.map +1 -1
  75. package/dist/raycast-engine.js +28 -56
  76. package/dist/raycast-engine.js.map +1 -1
  77. package/dist/raycaster.d.ts +7 -1
  78. package/dist/raycaster.d.ts.map +1 -1
  79. package/dist/raycaster.js +20 -5
  80. package/dist/raycaster.js.map +1 -1
  81. package/dist/reference-image-hit.d.ts +5 -0
  82. package/dist/reference-image-hit.d.ts.map +1 -0
  83. package/dist/reference-image-hit.js +28 -0
  84. package/dist/reference-image-hit.js.map +1 -0
  85. package/dist/reference-image-host.d.ts +5 -0
  86. package/dist/reference-image-host.d.ts.map +1 -0
  87. package/dist/reference-image-host.js +26 -0
  88. package/dist/reference-image-host.js.map +1 -0
  89. package/dist/reference-image-pipeline.d.ts +15 -0
  90. package/dist/reference-image-pipeline.d.ts.map +1 -0
  91. package/dist/reference-image-pipeline.js +104 -0
  92. package/dist/reference-image-pipeline.js.map +1 -0
  93. package/dist/reference-image-types.d.ts +27 -0
  94. package/dist/reference-image-types.d.ts.map +1 -0
  95. package/dist/reference-image-types.js +5 -0
  96. package/dist/reference-image-types.js.map +1 -0
  97. package/dist/reference-images.d.ts +27 -0
  98. package/dist/reference-images.d.ts.map +1 -0
  99. package/dist/reference-images.js +134 -0
  100. package/dist/reference-images.js.map +1 -0
  101. package/dist/renderer-viewport.d.ts +3 -0
  102. package/dist/renderer-viewport.d.ts.map +1 -0
  103. package/dist/renderer-viewport.js +20 -0
  104. package/dist/renderer-viewport.js.map +1 -0
  105. package/dist/rgba-texture-pool.d.ts +12 -0
  106. package/dist/rgba-texture-pool.d.ts.map +1 -0
  107. package/dist/rgba-texture-pool.js +51 -0
  108. package/dist/rgba-texture-pool.js.map +1 -0
  109. package/dist/scene-appearance-buckets.d.ts +41 -0
  110. package/dist/scene-appearance-buckets.d.ts.map +1 -0
  111. package/dist/scene-appearance-buckets.js +164 -0
  112. package/dist/scene-appearance-buckets.js.map +1 -0
  113. package/dist/scene-appearance-instances.d.ts +42 -0
  114. package/dist/scene-appearance-instances.d.ts.map +1 -0
  115. package/dist/scene-appearance-instances.js +143 -0
  116. package/dist/scene-appearance-instances.js.map +1 -0
  117. package/dist/scene-appearance-preview.d.ts +30 -0
  118. package/dist/scene-appearance-preview.d.ts.map +1 -0
  119. package/dist/scene-appearance-preview.js +149 -0
  120. package/dist/scene-appearance-preview.js.map +1 -0
  121. package/dist/scene-appearance-resources.d.ts +16 -0
  122. package/dist/scene-appearance-resources.d.ts.map +1 -0
  123. package/dist/scene-appearance-resources.js +41 -0
  124. package/dist/scene-appearance-resources.js.map +1 -0
  125. package/dist/scene-authored-owner.d.ts +9 -0
  126. package/dist/scene-authored-owner.d.ts.map +1 -0
  127. package/dist/scene-authored-owner.js +73 -0
  128. package/dist/scene-authored-owner.js.map +1 -0
  129. package/dist/scene-batch-upload.d.ts +12 -0
  130. package/dist/scene-batch-upload.d.ts.map +1 -0
  131. package/dist/scene-batch-upload.js +147 -0
  132. package/dist/scene-batch-upload.js.map +1 -0
  133. package/dist/scene-contents.d.ts +41 -0
  134. package/dist/scene-contents.d.ts.map +1 -1
  135. package/dist/scene-geometry.d.ts +16 -0
  136. package/dist/scene-geometry.d.ts.map +1 -1
  137. package/dist/scene-geometry.js +26 -0
  138. package/dist/scene-geometry.js.map +1 -1
  139. package/dist/scene-instance-materialization.d.ts +18 -0
  140. package/dist/scene-instance-materialization.d.ts.map +1 -0
  141. package/dist/scene-instance-materialization.js +57 -0
  142. package/dist/scene-instance-materialization.js.map +1 -0
  143. package/dist/scene-instance-suppression.d.ts +22 -0
  144. package/dist/scene-instance-suppression.d.ts.map +1 -0
  145. package/dist/scene-instance-suppression.js +100 -0
  146. package/dist/scene-instance-suppression.js.map +1 -0
  147. package/dist/scene-instance-types.d.ts +57 -0
  148. package/dist/scene-instance-types.d.ts.map +1 -0
  149. package/dist/scene-instance-types.js +2 -0
  150. package/dist/scene-instance-types.js.map +1 -0
  151. package/dist/scene-model-translation.d.ts +49 -0
  152. package/dist/scene-model-translation.d.ts.map +1 -0
  153. package/dist/scene-model-translation.js +100 -0
  154. package/dist/scene-model-translation.js.map +1 -0
  155. package/dist/scene-stream-split.d.ts +4 -0
  156. package/dist/scene-stream-split.d.ts.map +1 -0
  157. package/dist/scene-stream-split.js +54 -0
  158. package/dist/scene-stream-split.js.map +1 -0
  159. package/dist/scene.d.ts +105 -85
  160. package/dist/scene.d.ts.map +1 -1
  161. package/dist/scene.js +447 -583
  162. package/dist/scene.js.map +1 -1
  163. package/dist/shadow-occluders.d.ts.map +1 -1
  164. package/dist/shadow-occluders.js +13 -9
  165. package/dist/shadow-occluders.js.map +1 -1
  166. package/dist/snap-detector.d.ts +1 -1
  167. package/dist/snap-detector.d.ts.map +1 -1
  168. package/dist/snap-detector.js +5 -2
  169. package/dist/snap-detector.js.map +1 -1
  170. package/dist/textured-vertices.d.ts +9 -0
  171. package/dist/textured-vertices.d.ts.map +1 -0
  172. package/dist/textured-vertices.js +40 -0
  173. package/dist/textured-vertices.js.map +1 -0
  174. package/dist/types.d.ts +11 -9
  175. package/dist/types.d.ts.map +1 -1
  176. package/dist/xray-alpha.d.ts +131 -0
  177. package/dist/xray-alpha.d.ts.map +1 -0
  178. package/dist/xray-alpha.js +266 -0
  179. package/dist/xray-alpha.js.map +1 -0
  180. package/package.json +3 -3
package/README.md CHANGED
@@ -43,7 +43,7 @@ canvas.addEventListener('click', async (e) => {
43
43
  });
44
44
  ```
45
45
 
46
- For exact world-space hits with surface normals, use `raycastScene(x, y)` — slower but returns the precise intersection point + normal.
46
+ For exact world-space hits with surface normals, use `raycastScene(x, y)` — slower but returns the precise intersection point, normal and, where provenance is unambiguous, the federation model, representation item and canonical evaluated-surface triangle.
47
47
 
48
48
  ## Section planes
49
49
 
@@ -108,3 +108,13 @@ See the [Rendering Guide](https://ifclite.dev/docs/guide/rendering/) and [API Re
108
108
  ## License
109
109
 
110
110
  [MPL-2.0](../../LICENSE)
111
+
112
+ Registered raster references are available through `renderer.getReferenceImages()`; see the [rendering guide](../../docs/guide/rendering.md#registered-raster-references) for identity, coordinates, resource ownership and picking.
113
+
114
+ ### Exact surface tools and clipping
115
+
116
+ `renderer.hasActiveClipping()` reports whether the last rendered frame applied
117
+ section, terrain or box clipping. It reads the retained render snapshot, so
118
+ mutating a previous options object does not change the answer.
119
+ `raycastScene()` applies that same clip state while walking triangles, so a
120
+ clipped front face cannot hide a visible face behind it.
@@ -0,0 +1,33 @@
1
+ import type { MeshData } from '@ifc-lite/geometry';
2
+ import type { AppearanceOwner } from './appearance-preview.js';
3
+ import type { AppearanceBucket } from './scene-appearance-buckets.js';
4
+ interface Cohort {
5
+ id: number;
6
+ live: Set<AppearanceBucket>;
7
+ slots: Set<string>;
8
+ active: Set<string>;
9
+ vertexLimit: number;
10
+ indexLimit: number;
11
+ }
12
+ /** Metadata only: original GPU resources and source arrays are never retained.
13
+ * Only buckets descended from the same original batch can be rejoined. */
14
+ export declare class AppearanceBatchCohorts {
15
+ private readonly parts;
16
+ private sequence;
17
+ private slots;
18
+ private buckets;
19
+ private cohorts;
20
+ constructor(parts: (id: number) => readonly MeshData[] | undefined);
21
+ private slot;
22
+ register(bucket: AppearanceBucket): void;
23
+ inherit(from: AppearanceBucket, to: AppearanceBucket): void;
24
+ group(part: MeshData, index: number): Cohort | undefined;
25
+ assign(bucket: AppearanceBucket, cohort: Cohort | undefined): void;
26
+ attach(bucket: AppearanceBucket): void;
27
+ detach(bucket: AppearanceBucket): void;
28
+ begin(owner: AppearanceOwner): void;
29
+ finish(owner: AppearanceOwner, rebuild: (old: AppearanceBucket[], parts: MeshData[]) => AppearanceBucket): void;
30
+ forget(expressId?: number): void;
31
+ }
32
+ export {};
33
+ //# sourceMappingURL=appearance-batch-cohorts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appearance-batch-cohorts.d.ts","sourceRoot":"","sources":["../src/appearance-batch-cohorts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,UAAU,MAAM;IACd,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC5B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAUD;0EAC0E;AAC1E,qBAAa,sBAAsB;IAM/B,OAAO,CAAC,QAAQ,CAAC,KAAK;IALxB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,OAAO,CAAqB;gBAEjB,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,SAAS,QAAQ,EAAE,GAAG,SAAS;IAGzE,OAAO,CAAC,IAAI;IAMZ,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAexC,OAAO,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE,gBAAgB,GAAG,IAAI;IAI3D,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAGxD,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAGlE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAGtC,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAGtC,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAKnC,MAAM,CACJ,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,CAAC,GAAG,EAAE,gBAAgB,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,gBAAgB,GACxE,IAAI;IAkCP,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;CAuBjC"}
@@ -0,0 +1,126 @@
1
+ import { BATCH_CONSTANTS } from './constants.js';
2
+ const ownerKey = (owner) => `${owner.modelIndex}:${owner.expressId}:`;
3
+ const meshOwner = (part) => ({
4
+ expressId: part.expressId,
5
+ modelIndex: part.modelIndex ?? 0,
6
+ });
7
+ const vertexBytes = (part) => (part.positions.length / 3) * BATCH_CONSTANTS.BYTES_PER_VERTEX;
8
+ /** Metadata only: original GPU resources and source arrays are never retained.
9
+ * Only buckets descended from the same original batch can be rejoined. */
10
+ export class AppearanceBatchCohorts {
11
+ parts;
12
+ sequence = 0;
13
+ slots = new Map();
14
+ buckets = new WeakMap();
15
+ cohorts = new Set();
16
+ constructor(parts) {
17
+ this.parts = parts;
18
+ }
19
+ slot(part) {
20
+ const index = this.parts(part.expressId)?.indexOf(part) ?? -1;
21
+ if (index < 0)
22
+ throw new Error('Appearance batch lost its source part identity');
23
+ return ownerKey(meshOwner(part)) + index;
24
+ }
25
+ register(bucket) {
26
+ if (this.buckets.has(bucket))
27
+ return;
28
+ const slots = bucket.meshData.map((part) => this.slot(part));
29
+ const cohort = {
30
+ id: ++this.sequence,
31
+ live: new Set([bucket]),
32
+ slots: new Set(slots),
33
+ active: new Set(),
34
+ vertexLimit: bucket.meshData.reduce((n, p) => n + vertexBytes(p), 0),
35
+ indexLimit: bucket.meshData.reduce((n, p) => n + p.indices.byteLength, 0),
36
+ };
37
+ for (const slot of slots)
38
+ this.slots.set(slot, cohort);
39
+ this.buckets.set(bucket, cohort);
40
+ this.cohorts.add(cohort);
41
+ }
42
+ inherit(from, to) {
43
+ const cohort = this.buckets.get(from);
44
+ if (cohort)
45
+ this.buckets.set(to, cohort);
46
+ }
47
+ group(part, index) {
48
+ return this.slots.get(ownerKey(meshOwner(part)) + index);
49
+ }
50
+ assign(bucket, cohort) {
51
+ if (cohort)
52
+ this.buckets.set(bucket, cohort);
53
+ }
54
+ attach(bucket) {
55
+ this.buckets.get(bucket)?.live.add(bucket);
56
+ }
57
+ detach(bucket) {
58
+ this.buckets.get(bucket)?.live.delete(bucket);
59
+ }
60
+ begin(owner) {
61
+ const prefix = ownerKey(owner);
62
+ for (const [slot, cohort] of this.slots)
63
+ if (slot.startsWith(prefix))
64
+ cohort.active.add(prefix);
65
+ }
66
+ finish(owner, rebuild) {
67
+ const prefix = ownerKey(owner);
68
+ const affected = new Set();
69
+ for (const [slot, cohort] of this.slots)
70
+ if (slot.startsWith(prefix)) {
71
+ cohort.active.delete(prefix);
72
+ affected.add(cohort);
73
+ }
74
+ for (const cohort of affected) {
75
+ if (cohort.active.size || cohort.live.size < 2)
76
+ continue;
77
+ // Restore within original allocation bounds; changed colors remain distinct.
78
+ const colors = new Map();
79
+ for (const bucket of cohort.live) {
80
+ const key = bucket.meshData[0].color.join(',');
81
+ const group = colors.get(key) ?? [];
82
+ group.push(bucket);
83
+ colors.set(key, group);
84
+ }
85
+ for (const group of colors.values()) {
86
+ const parts = group.flatMap((bucket) => bucket.meshData);
87
+ if (group.length < 2 ||
88
+ parts.reduce((n, p) => n + vertexBytes(p), 0) > cohort.vertexLimit ||
89
+ parts.reduce((n, p) => n + p.indices.byteLength, 0) >
90
+ cohort.indexLimit)
91
+ continue;
92
+ const replacement = rebuild(group, parts);
93
+ for (const old of group)
94
+ cohort.live.delete(old);
95
+ this.buckets.set(replacement, cohort);
96
+ cohort.live.add(replacement);
97
+ }
98
+ }
99
+ }
100
+ forget(expressId) {
101
+ if (expressId === undefined) {
102
+ this.slots.clear();
103
+ this.cohorts.clear();
104
+ this.buckets = new WeakMap();
105
+ return;
106
+ }
107
+ for (const [slot, cohort] of this.slots) {
108
+ if (Number(slot.split(':')[1]) !== expressId)
109
+ continue;
110
+ this.slots.delete(slot);
111
+ cohort.slots.delete(slot);
112
+ cohort.active.delete(slot.slice(0, slot.lastIndexOf(':') + 1));
113
+ }
114
+ for (const cohort of this.cohorts) {
115
+ for (const bucket of cohort.live) {
116
+ if (bucket.meshData.some((part) => part.expressId === expressId)) {
117
+ this.buckets.delete(bucket);
118
+ cohort.live.delete(bucket);
119
+ }
120
+ }
121
+ if (!cohort.slots.size)
122
+ this.cohorts.delete(cohort);
123
+ }
124
+ }
125
+ }
126
+ //# sourceMappingURL=appearance-batch-cohorts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appearance-batch-cohorts.js","sourceRoot":"","sources":["../src/appearance-batch-cohorts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { MeshData } from '@ifc-lite/geometry';
2
+ import type { AppearanceOwner } from './appearance-preview.js';
3
+ /** Companion transitions change presence only, never geometry or appearance. */
4
+ export declare function sameCompanionParts(a: readonly MeshData[], b: readonly MeshData[]): boolean;
5
+ interface CompanionRecord {
6
+ owner: AppearanceOwner;
7
+ originals: readonly MeshData[];
8
+ sources: readonly MeshData[];
9
+ absent: boolean;
10
+ hidden: boolean;
11
+ drafts: number;
12
+ history: number;
13
+ }
14
+ /** Tombstones prove that missing geometry was removed by this transaction.
15
+ * They do not authorize restoring an arbitrary unloaded or replaced owner. */
16
+ export declare class AppearanceCompanions {
17
+ private records;
18
+ get(owner: AppearanceOwner): CompanionRecord | undefined;
19
+ capture(owner: AppearanceOwner, expected: readonly MeshData[], current: readonly MeshData[] | undefined, source: (part: MeshData) => MeshData, hidden?: boolean): CompanionRecord;
20
+ validate(owner: AppearanceOwner, current: readonly MeshData[] | undefined): void;
21
+ install(owner: AppearanceOwner, parts: readonly MeshData[]): void;
22
+ finish(owner: AppearanceOwner, expected?: CompanionRecord): void;
23
+ retain(owner: AppearanceOwner): () => void;
24
+ private collect;
25
+ retained(geometry: readonly MeshData[], models: ReadonlySet<number>): Set<number>;
26
+ forget(id?: number): void;
27
+ forgetExcept(retained: ReadonlySet<number>): void;
28
+ }
29
+ export {};
30
+ //# sourceMappingURL=appearance-companions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appearance-companions.d.ts","sourceRoot":"","sources":["../src/appearance-companions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAS/D,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,SAAS,QAAQ,EAAE,EAAE,CAAC,EAAE,SAAS,QAAQ,EAAE,GAAG,OAAO,CAa1F;AAQD,UAAU,eAAe;IACvB,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC/B,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;8EAC8E;AAC9E,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,OAAO,CAAsC;IACrD,GAAG,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,GAAG,SAAS;IAKxD,OAAO,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,QAAQ,EAAE,EAAE,OAAO,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,EACrG,MAAM,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,QAAQ,EAAE,MAAM,UAAQ,GAAG,eAAe;IAmCxE,QAAQ,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,GAAG,IAAI;IAMhF,OAAO,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,IAAI;IAMjE,MAAM,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI;IAMhE,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,IAAI;IAO1C,OAAO,CAAC,OAAO;IAGf,QAAQ,CAAC,QAAQ,EAAE,SAAS,QAAQ,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC;IAMjF,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IACzB,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI;CAClD"}
@@ -0,0 +1,138 @@
1
+ function sameNumbers(a, b) {
2
+ if (a === undefined || b === undefined)
3
+ return a === b;
4
+ if (a.length !== b.length)
5
+ return false;
6
+ for (let index = 0; index < a.length; index++)
7
+ if (a[index] !== b[index])
8
+ return false;
9
+ return true;
10
+ }
11
+ /** Companion transitions change presence only, never geometry or appearance. */
12
+ export function sameCompanionParts(a, b) {
13
+ return a.length === b.length && a.every((part, index) => {
14
+ const other = b[index];
15
+ return part.expressId === other.expressId && (part.modelIndex ?? 0) === (other.modelIndex ?? 0)
16
+ && part.geometryItemId === other.geometryItemId && !part.entityIds && !other.entityIds
17
+ && ['positions', 'normals', 'indices', 'localToWorld', 'shadingColor'].every(key => {
18
+ return sameNumbers(part[key], other[key]);
19
+ })
20
+ && sameNumbers(part.origin ?? [0, 0, 0], other.origin ?? [0, 0, 0])
21
+ && part.color.every((value, axis) => value === other.color[axis])
22
+ && part.texture === other.texture
23
+ && part.textureRef === other.textureRef && part.textureBitmap === other.textureBitmap && part.uvs === other.uvs;
24
+ });
25
+ }
26
+ function snapshot(part) {
27
+ return Object.freeze({ ...part, positions: part.positions.slice(), normals: part.normals.slice(), indices: part.indices.slice(),
28
+ color: [...part.color],
29
+ ...(part.shadingColor ? { shadingColor: [...part.shadingColor] } : {}),
30
+ ...(part.origin ? { origin: [...part.origin] } : {}),
31
+ ...(part.localToWorld ? { localToWorld: [...part.localToWorld] } : {}) });
32
+ }
33
+ /** Tombstones prove that missing geometry was removed by this transaction.
34
+ * They do not authorize restoring an arbitrary unloaded or replaced owner. */
35
+ export class AppearanceCompanions {
36
+ records = new Map();
37
+ get(owner) {
38
+ const record = this.records.get(owner.expressId);
39
+ if (record && record.owner.modelIndex !== owner.modelIndex)
40
+ throw new Error('Companion model ownership changed.');
41
+ return record;
42
+ }
43
+ capture(owner, expected, current, source, hidden = false) {
44
+ let record = this.get(owner);
45
+ let vertices = 0, corners = 0;
46
+ if (expected.length > 10_000)
47
+ throw new Error('Companion geometry exceeds its snapshot budget.');
48
+ for (const part of expected) {
49
+ vertices += part.positions.length / 3;
50
+ corners += part.indices.length;
51
+ if (!Number.isSafeInteger(vertices) || vertices > 2_000_000 || corners > 1_500_000
52
+ || part.positions.length / 3 > 1_000_000)
53
+ throw new Error('Companion geometry exceeds its snapshot budget.');
54
+ }
55
+ if (!expected.length || expected.some(part => part.expressId !== owner.expressId
56
+ || (part.modelIndex ?? 0) !== owner.modelIndex || !part.geometryItemId || part.entityIds
57
+ || !part.positions.length || !part.indices.length || part.texture || part.textureRef || part.textureBitmap || part.uvs)) {
58
+ throw new Error('Companion removal requires original untextured owner geometry.');
59
+ }
60
+ if (record) {
61
+ if (!sameCompanionParts(expected, record.originals)
62
+ || (record.absent ? !!current?.length : current?.length ? !sameCompanionParts(current, record.originals) : !record.hidden)) {
63
+ throw new Error('Companion geometry changed since preparation.');
64
+ }
65
+ }
66
+ else {
67
+ if ((!current?.length && !hidden) || (current?.length && !sameCompanionParts(current, expected)))
68
+ throw new Error('Companion original geometry is missing or changed.');
69
+ const resident = current?.length ? current : expected;
70
+ const originals = resident.map(snapshot);
71
+ const sources = resident.map((part, index) => {
72
+ const raw = source(part);
73
+ return raw === part ? originals[index] : snapshot(raw);
74
+ });
75
+ record = { owner: Object.freeze({ ...owner }), originals: Object.freeze(originals),
76
+ sources: Object.freeze(sources), absent: false, hidden, drafts: 0, history: 0 };
77
+ this.records.set(owner.expressId, record);
78
+ }
79
+ record.hidden = hidden && !current?.length;
80
+ record.drafts++;
81
+ return record;
82
+ }
83
+ validate(owner, current) {
84
+ const record = this.get(owner);
85
+ if (record && (record.absent ? !!current?.length : current?.length ? !sameCompanionParts(current, record.originals) : !record.hidden)) {
86
+ throw new Error('Companion geometry changed during the appearance transaction.');
87
+ }
88
+ }
89
+ install(owner, parts) {
90
+ const record = this.get(owner);
91
+ if (!record)
92
+ return;
93
+ if (parts.length && !sameCompanionParts(parts, record.originals))
94
+ throw new Error('Companion restoration changed its original geometry.');
95
+ record.absent = !parts.length;
96
+ }
97
+ finish(owner, expected) {
98
+ const record = this.get(owner);
99
+ if (!record || (expected && record !== expected))
100
+ return;
101
+ record.drafts = Math.max(0, record.drafts - 1);
102
+ this.collect(record);
103
+ }
104
+ retain(owner) {
105
+ const record = this.get(owner);
106
+ if (!record)
107
+ return () => { };
108
+ record.history++;
109
+ let released = false;
110
+ return () => { if (!released) {
111
+ released = true;
112
+ record.history--;
113
+ this.collect(record);
114
+ } };
115
+ }
116
+ collect(record) {
117
+ if (!record.drafts && !record.history && this.records.get(record.owner.expressId) === record)
118
+ this.records.delete(record.owner.expressId);
119
+ }
120
+ retained(geometry, models) {
121
+ const byOwner = new Map();
122
+ for (const part of geometry) {
123
+ const parts = byOwner.get(part.expressId) ?? [];
124
+ parts.push(part);
125
+ byOwner.set(part.expressId, parts);
126
+ }
127
+ return new Set([...this.records].filter(([id, record]) => record.history > 0 && models.has(record.owner.modelIndex)
128
+ && (record.absent ? !byOwner.get(id)?.length : sameCompanionParts(byOwner.get(id) ?? [], record.sources))).map(([id]) => id));
129
+ }
130
+ forget(id) { if (id === undefined)
131
+ this.records.clear();
132
+ else
133
+ this.records.delete(id); }
134
+ forgetExcept(retained) { for (const id of this.records.keys())
135
+ if (!retained.has(id))
136
+ this.records.delete(id); }
137
+ }
138
+ //# sourceMappingURL=appearance-companions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appearance-companions.js","sourceRoot":"","sources":["../src/appearance-companions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { MeshData } from '@ifc-lite/geometry';
2
+ /** One item on either side of a partition: the triangle ordinals of a shared
3
+ * reference surface it carries, in its own triangle order. */
4
+ export interface AppearancePartitionPart {
5
+ /** Unique within this side; geometryItemId may repeat across fragments. */
6
+ readonly partId: number;
7
+ readonly geometryItemId: number;
8
+ readonly triangles: readonly number[];
9
+ }
10
+ /**
11
+ * A face-masked appearance replaces one owner's items with several items that
12
+ * together carry exactly the same triangle corners (#4404): the textured face
13
+ * set and the retained face set of an evaluated occurrence. Both sides name
14
+ * every ordinal of one reference surface exactly once, so the same record
15
+ * inverted describes the join that Undo performs.
16
+ */
17
+ export interface AppearancePartition {
18
+ /** Canonical full surface whose triangle ordinals every side partitions. */
19
+ readonly sourceGeometryItemId: number;
20
+ readonly triangleCount: number;
21
+ readonly before: readonly AppearancePartitionPart[];
22
+ readonly after: readonly AppearancePartitionPart[];
23
+ }
24
+ export declare function invertAppearancePartition(partition: AppearancePartition): AppearancePartition;
25
+ export declare function freezeAppearancePartition(partition: AppearancePartition): AppearancePartition;
26
+ /**
27
+ * Exact corner-for-corner equivalence between the two sides. Positions, the
28
+ * placement frame, ownership and the reference coverage must be identical;
29
+ * only shading normals and appearance attributes may differ.
30
+ */
31
+ export declare function validateAppearancePartition(partition: AppearancePartition, before: readonly MeshData[], after: readonly MeshData[]): void;
32
+ //# sourceMappingURL=appearance-partition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appearance-partition.d.ts","sourceRoot":"","sources":["../src/appearance-partition.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAKnD;8DAC8D;AAC9D,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AACD;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACpD;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,mBAAmB,GAAG,mBAAmB,CAE7F;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,mBAAmB,GAAG,mBAAmB,CAK7F;AA2ED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,mBAAmB,EAAE,MAAM,EAAE,SAAS,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,IAAI,CAuBzI"}
@@ -0,0 +1,122 @@
1
+ /** Matches the native face-mask plan's aggregate ordinal budget. */
2
+ const MAX_PARTITION_TRIANGLES = 500_000;
3
+ export function invertAppearancePartition(partition) {
4
+ return { ...partition, before: partition.after, after: partition.before };
5
+ }
6
+ export function freezeAppearancePartition(partition) {
7
+ const side = (parts) => Object.freeze(parts.map(part => Object.freeze({ partId: part.partId, geometryItemId: part.geometryItemId, triangles: Object.freeze([...part.triangles]) })));
8
+ return Object.freeze({ sourceGeometryItemId: partition.sourceGeometryItemId, triangleCount: partition.triangleCount,
9
+ before: side(partition.before), after: side(partition.after) });
10
+ }
11
+ function sameFrame(a, b) {
12
+ for (const key of ['origin', 'localToWorld']) {
13
+ const av = a[key], bv = b[key];
14
+ if (av === undefined || bv === undefined) {
15
+ if (av !== bv)
16
+ return false;
17
+ }
18
+ else if (av.length !== bv.length || av.some((value, i) => value !== bv[i]))
19
+ return false;
20
+ }
21
+ return true;
22
+ }
23
+ /** Items appear in declaration order; part identity, rather than IFC item id, is unique. */
24
+ function checkSide(side, parts, label, triangleCount, referenceSource) {
25
+ if (!side.length || side.length !== parts.length)
26
+ throw new Error(`Appearance partition ${label} does not name every part`);
27
+ const seen = new Set();
28
+ let work = 0;
29
+ side.forEach((entry, index) => {
30
+ if (!Number.isSafeInteger(entry.partId) || entry.partId < 0 || seen.has(entry.partId)
31
+ || !Number.isSafeInteger(entry.geometryItemId) || entry.geometryItemId <= 0
32
+ || parts[index].geometryItemId !== entry.geometryItemId)
33
+ throw new Error(`Appearance partition ${label} item identity does not match its part`);
34
+ seen.add(entry.partId);
35
+ if (entry.triangles.length * 3 !== parts[index].indices.length)
36
+ throw new Error(`Appearance partition ${label} triangle count does not match its part`);
37
+ const source = parts[index].appearanceSource;
38
+ if (!source || source.indices !== parts[index].indices || source.sourceIndices.length !== triangleCount * 3
39
+ || source.cornerIndices && source.cornerIndices.length !== parts[index].indices.length) {
40
+ throw new Error(`Appearance partition ${label} has invalid full-surface provenance`);
41
+ }
42
+ if (!entry.triangles.length || entry.triangles.length > triangleCount - work) {
43
+ throw new Error(`Appearance partition ${label} exceeds its triangle work budget`);
44
+ }
45
+ work += entry.triangles.length;
46
+ entry.triangles.forEach((ordinal, triangle) => {
47
+ if (!Number.isSafeInteger(ordinal) || ordinal < 0 || ordinal >= triangleCount) {
48
+ throw new Error(`Appearance partition ${label} names an invalid triangle`);
49
+ }
50
+ for (let corner = 0; corner < 3; corner++) {
51
+ const canonicalCorner = ordinal * 3 + corner;
52
+ if ((source.cornerIndices?.[triangle * 3 + corner] ?? triangle * 3 + corner) !== canonicalCorner
53
+ || source.sourceIndices[canonicalCorner] !== referenceSource[canonicalCorner]) {
54
+ throw new Error(`Appearance partition ${label} part identity does not match its canonical triangles`);
55
+ }
56
+ }
57
+ });
58
+ });
59
+ if (work !== triangleCount)
60
+ throw new Error(`Appearance partition ${label} does not cover the full surface`);
61
+ }
62
+ /** Write or compare reference-corner positions using a fixed-size allocation. */
63
+ function referenceCorners(side, parts, label, triangleCount, expected) {
64
+ const corners = expected ?? new Float32Array(triangleCount * 9);
65
+ const seen = new Uint8Array(triangleCount * 3);
66
+ side.forEach((entry, index) => {
67
+ const part = parts[index];
68
+ entry.triangles.forEach((ordinal, triangle) => {
69
+ for (let corner = 0; corner < 3; corner++) {
70
+ const reference = ordinal * 3 + corner;
71
+ if (seen[reference])
72
+ throw new Error(`Appearance partition ${label} names a triangle twice`);
73
+ seen[reference] = 1;
74
+ const vertex = part.indices[triangle * 3 + corner] * 3;
75
+ if (vertex + 2 >= part.positions.length)
76
+ throw new Error(`Appearance partition ${label} part index is out of range`);
77
+ const output = reference * 3;
78
+ for (let axis = 0; axis < 3; axis++) {
79
+ const value = part.positions[vertex + axis];
80
+ if (expected && expected[output + axis] !== value)
81
+ throw new Error('Appearance partition changes triangle geometry');
82
+ corners[output + axis] = value;
83
+ }
84
+ }
85
+ });
86
+ });
87
+ if (seen.some(value => value !== 1))
88
+ throw new Error(`Appearance partition ${label} does not provide complete coverage`);
89
+ return corners;
90
+ }
91
+ /**
92
+ * Exact corner-for-corner equivalence between the two sides. Positions, the
93
+ * placement frame, ownership and the reference coverage must be identical;
94
+ * only shading normals and appearance attributes may differ.
95
+ */
96
+ export function validateAppearancePartition(partition, before, after) {
97
+ if (!Number.isSafeInteger(partition.sourceGeometryItemId) || partition.sourceGeometryItemId <= 0
98
+ || !Number.isSafeInteger(partition.triangleCount) || partition.triangleCount <= 0
99
+ || partition.triangleCount > MAX_PARTITION_TRIANGLES
100
+ || partition.before.length > partition.triangleCount || partition.after.length > partition.triangleCount) {
101
+ throw new Error('Appearance partition full-surface identity is invalid');
102
+ }
103
+ const sourceSide = before.every(part => part.geometryItemId === partition.sourceGeometryItemId) ? before
104
+ : after.every(part => part.geometryItemId === partition.sourceGeometryItemId) ? after : undefined;
105
+ const sourceIndices = sourceSide?.[0].appearanceSource?.sourceIndices;
106
+ if (!sourceIndices || sourceIndices.length !== partition.triangleCount * 3) {
107
+ throw new Error('Appearance partition full-surface provenance does not match its source item');
108
+ }
109
+ checkSide(partition.before, before, 'original', partition.triangleCount, sourceIndices);
110
+ checkSide(partition.after, after, 'replacement', partition.triangleCount, sourceIndices);
111
+ const owner = before[0];
112
+ for (const part of [...before, ...after]) {
113
+ if (part.expressId !== owner.expressId || (part.modelIndex ?? 0) !== (owner.modelIndex ?? 0) || part.entityIds
114
+ || !sameFrame(part, owner))
115
+ throw new Error('Appearance partition cannot change ownership or placement');
116
+ if (part.normals.length !== part.positions.length || !part.normals.every(Number.isFinite))
117
+ throw new Error('Appearance partition part normals are invalid');
118
+ }
119
+ const original = referenceCorners(partition.before, before, 'original', partition.triangleCount);
120
+ referenceCorners(partition.after, after, 'replacement', partition.triangleCount, original);
121
+ }
122
+ //# sourceMappingURL=appearance-partition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appearance-partition.js","sourceRoot":"","sources":["../src/appearance-partition.ts"],"names":[],"mappings":"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"}