@ifc-lite/clash 1.1.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 (107) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +32 -0
  3. package/dist/adapters/ifcx.d.ts +44 -0
  4. package/dist/adapters/ifcx.d.ts.map +1 -0
  5. package/dist/adapters/ifcx.js +198 -0
  6. package/dist/adapters/ifcx.js.map +1 -0
  7. package/dist/adapters/step.d.ts +42 -0
  8. package/dist/adapters/step.d.ts.map +1 -0
  9. package/dist/adapters/step.js +77 -0
  10. package/dist/adapters/step.js.map +1 -0
  11. package/dist/bcf-bridge.d.ts +51 -0
  12. package/dist/bcf-bridge.d.ts.map +1 -0
  13. package/dist/bcf-bridge.js +298 -0
  14. package/dist/bcf-bridge.js.map +1 -0
  15. package/dist/deterministic-uuid.d.ts +9 -0
  16. package/dist/deterministic-uuid.d.ts.map +1 -0
  17. package/dist/deterministic-uuid.js +87 -0
  18. package/dist/deterministic-uuid.js.map +1 -0
  19. package/dist/disciplines.d.ts +33 -0
  20. package/dist/disciplines.d.ts.map +1 -0
  21. package/dist/disciplines.js +148 -0
  22. package/dist/disciplines.js.map +1 -0
  23. package/dist/engine-ts/broad.d.ts +11 -0
  24. package/dist/engine-ts/broad.d.ts.map +1 -0
  25. package/dist/engine-ts/broad.js +61 -0
  26. package/dist/engine-ts/broad.js.map +1 -0
  27. package/dist/engine-ts/index.d.ts +16 -0
  28. package/dist/engine-ts/index.d.ts.map +1 -0
  29. package/dist/engine-ts/index.js +17 -0
  30. package/dist/engine-ts/index.js.map +1 -0
  31. package/dist/engine-ts/kernel.d.ts +50 -0
  32. package/dist/engine-ts/kernel.d.ts.map +1 -0
  33. package/dist/engine-ts/kernel.js +5 -0
  34. package/dist/engine-ts/kernel.js.map +1 -0
  35. package/dist/engine-ts/narrow.d.ts +23 -0
  36. package/dist/engine-ts/narrow.d.ts.map +1 -0
  37. package/dist/engine-ts/narrow.js +127 -0
  38. package/dist/engine-ts/narrow.js.map +1 -0
  39. package/dist/engine-ts/orchestrator.d.ts +11 -0
  40. package/dist/engine-ts/orchestrator.d.ts.map +1 -0
  41. package/dist/engine-ts/orchestrator.js +127 -0
  42. package/dist/engine-ts/orchestrator.js.map +1 -0
  43. package/dist/engine-ts/tri-mesh.d.ts +33 -0
  44. package/dist/engine-ts/tri-mesh.d.ts.map +1 -0
  45. package/dist/engine-ts/tri-mesh.js +125 -0
  46. package/dist/engine-ts/tri-mesh.js.map +1 -0
  47. package/dist/engine-ts/ts-kernel.d.ts +14 -0
  48. package/dist/engine-ts/ts-kernel.d.ts.map +1 -0
  49. package/dist/engine-ts/ts-kernel.js +85 -0
  50. package/dist/engine-ts/ts-kernel.js.map +1 -0
  51. package/dist/engine-wasm/index.d.ts +21 -0
  52. package/dist/engine-wasm/index.d.ts.map +1 -0
  53. package/dist/engine-wasm/index.js +40 -0
  54. package/dist/engine-wasm/index.js.map +1 -0
  55. package/dist/engine-wasm/wasm-kernel.d.ts +20 -0
  56. package/dist/engine-wasm/wasm-kernel.d.ts.map +1 -0
  57. package/dist/engine-wasm/wasm-kernel.js +106 -0
  58. package/dist/engine-wasm/wasm-kernel.js.map +1 -0
  59. package/dist/engine.d.ts +14 -0
  60. package/dist/engine.d.ts.map +1 -0
  61. package/dist/engine.js +20 -0
  62. package/dist/engine.js.map +1 -0
  63. package/dist/exclude.d.ts +15 -0
  64. package/dist/exclude.d.ts.map +1 -0
  65. package/dist/exclude.js +38 -0
  66. package/dist/exclude.js.map +1 -0
  67. package/dist/grouping.d.ts +16 -0
  68. package/dist/grouping.d.ts.map +1 -0
  69. package/dist/grouping.js +311 -0
  70. package/dist/grouping.js.map +1 -0
  71. package/dist/index.d.ts +18 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +21 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/lifecycle.d.ts +41 -0
  76. package/dist/lifecycle.d.ts.map +1 -0
  77. package/dist/lifecycle.js +70 -0
  78. package/dist/lifecycle.js.map +1 -0
  79. package/dist/math/aabb.d.ts +27 -0
  80. package/dist/math/aabb.d.ts.map +1 -0
  81. package/dist/math/aabb.js +127 -0
  82. package/dist/math/aabb.js.map +1 -0
  83. package/dist/math/triangle-distance.d.ts +29 -0
  84. package/dist/math/triangle-distance.d.ts.map +1 -0
  85. package/dist/math/triangle-distance.js +149 -0
  86. package/dist/math/triangle-distance.js.map +1 -0
  87. package/dist/math/triangle-intersect.d.ts +13 -0
  88. package/dist/math/triangle-intersect.d.ts.map +1 -0
  89. package/dist/math/triangle-intersect.js +55 -0
  90. package/dist/math/triangle-intersect.js.map +1 -0
  91. package/dist/math/vec3.d.ts +11 -0
  92. package/dist/math/vec3.d.ts.map +1 -0
  93. package/dist/math/vec3.js +38 -0
  94. package/dist/math/vec3.js.map +1 -0
  95. package/dist/selectors.d.ts +12 -0
  96. package/dist/selectors.d.ts.map +1 -0
  97. package/dist/selectors.js +53 -0
  98. package/dist/selectors.js.map +1 -0
  99. package/dist/triage.d.ts +19 -0
  100. package/dist/triage.d.ts.map +1 -0
  101. package/dist/triage.js +99 -0
  102. package/dist/triage.js.map +1 -0
  103. package/dist/types.d.ts +145 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +8 -0
  106. package/dist/types.js.map +1 -0
  107. package/package.json +72 -0
@@ -0,0 +1,42 @@
1
+ /**
2
+ * STEP / IFC2x3 / IFC4 source adapter: turn an `IfcDataStore` plus its meshes
3
+ * into representation-agnostic `ClashElement`s, and precompute the
4
+ * void/host/assembly pair exclusions from IFC relationships.
5
+ *
6
+ * This module is the only part of the package that depends on
7
+ * `@ifc-lite/parser` / `@ifc-lite/query`; it is reached via the
8
+ * `@ifc-lite/clash/step` subpath so the core stays version-neutral.
9
+ */
10
+ import type { IfcDataStore } from '@ifc-lite/parser';
11
+ import type { MeshData } from '@ifc-lite/geometry';
12
+ import type { ClashElement, ExclusionSet, Mat4 } from '../types.js';
13
+ /** Minimal federation contract — pass an `@ifc-lite/renderer` `FederationRegistry`. */
14
+ export interface FederationLike {
15
+ toGlobalId(modelId: string, expressId: number): number;
16
+ }
17
+ export interface StepAdapterOptions {
18
+ store: IfcDataStore;
19
+ meshes: MeshData[];
20
+ /** Model/file id (federation). */
21
+ modelId: string;
22
+ /** When provided, `ref` is the federated globalId; otherwise the expressId. */
23
+ federation?: FederationLike;
24
+ /** Aligns this model into the common world frame (RTC + building rotation). */
25
+ worldTransform?: Mat4;
26
+ /** Precompute void/host/assembly exclusions. Default true. */
27
+ buildExclusions?: boolean;
28
+ }
29
+ export interface StepAdapterResult {
30
+ elements: ClashElement[];
31
+ exclusions: ExclusionSet;
32
+ }
33
+ export declare function elementsFromStep(options: StepAdapterOptions): StepAdapterResult;
34
+ /**
35
+ * Pair-exclusions from IFC relationships, using cached `EntityNode` getters
36
+ * (never `extractEntityAttributesOnDemand` in a loop, per AGENTS.md):
37
+ * - host vs the filler of its opening (wall vs door/window)
38
+ * - element vs its own (meshed) opening
39
+ * - members of the same `IfcRelAggregates` assembly
40
+ */
41
+ export declare function buildStepExclusions(store: IfcDataStore, byExpressId: Map<number, ClashElement>): ExclusionSet;
42
+ //# sourceMappingURL=step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/adapters/step.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEpE,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CACxD;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,8DAA8D;IAC9D,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAqC/E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GACrC,YAAY,CAiCd"}
@@ -0,0 +1,77 @@
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 { EntityNode } from '@ifc-lite/query';
5
+ import { makeExclusionSet, qualifiedKey } from '../exclude.js';
6
+ import { fromPositions } from '../math/aabb.js';
7
+ export function elementsFromStep(options) {
8
+ const { store, meshes, modelId, federation, worldTransform, buildExclusions = true } = options;
9
+ const elements = [];
10
+ const byExpressId = new Map();
11
+ for (const mesh of meshes) {
12
+ if (!mesh.positions || mesh.positions.length === 0)
13
+ continue;
14
+ const expressId = mesh.expressId;
15
+ const node = new EntityNode(store, expressId);
16
+ // Fall back to a model-scoped synthetic key rather than dropping geometry:
17
+ // malformed IFC roots / fallback-only elements still participate in clashes.
18
+ const key = node.globalId || `expressid:${expressId}`;
19
+ const element = {
20
+ key,
21
+ ref: federation ? federation.toGlobalId(modelId, expressId) : expressId,
22
+ model: modelId,
23
+ tag: node.type || mesh.ifcType || 'IfcProduct',
24
+ name: node.name || undefined,
25
+ storey: node.storey()?.name || undefined,
26
+ bounds: fromPositions(mesh.positions, worldTransform),
27
+ positions: mesh.positions,
28
+ indices: mesh.indices,
29
+ transform: worldTransform,
30
+ };
31
+ elements.push(element);
32
+ byExpressId.set(expressId, element);
33
+ }
34
+ const exclusions = buildExclusions
35
+ ? buildStepExclusions(store, byExpressId)
36
+ : makeExclusionSet();
37
+ return { elements, exclusions };
38
+ }
39
+ /**
40
+ * Pair-exclusions from IFC relationships, using cached `EntityNode` getters
41
+ * (never `extractEntityAttributesOnDemand` in a loop, per AGENTS.md):
42
+ * - host vs the filler of its opening (wall vs door/window)
43
+ * - element vs its own (meshed) opening
44
+ * - members of the same `IfcRelAggregates` assembly
45
+ */
46
+ export function buildStepExclusions(store, byExpressId) {
47
+ const pairs = [];
48
+ for (const [expressId, element] of byExpressId) {
49
+ const node = new EntityNode(store, expressId);
50
+ const ek = qualifiedKey(element.model, element.key);
51
+ for (const opening of node.voids()) {
52
+ const openingElement = byExpressId.get(opening.expressId);
53
+ if (openingElement) {
54
+ pairs.push([ek, qualifiedKey(openingElement.model, openingElement.key)]);
55
+ }
56
+ for (const filler of opening.filledBy()) {
57
+ const fillerElement = byExpressId.get(filler.expressId);
58
+ if (fillerElement) {
59
+ pairs.push([ek, qualifiedKey(fillerElement.model, fillerElement.key)]);
60
+ }
61
+ }
62
+ }
63
+ const parent = node.decomposedBy();
64
+ if (parent) {
65
+ for (const sibling of parent.decomposes()) {
66
+ if (sibling.expressId === expressId)
67
+ continue;
68
+ const siblingElement = byExpressId.get(sibling.expressId);
69
+ if (siblingElement) {
70
+ pairs.push([ek, qualifiedKey(siblingElement.model, siblingElement.key)]);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ return makeExclusionSet(pairs);
76
+ }
77
+ //# sourceMappingURL=step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.js","sourceRoot":"","sources":["../../src/adapters/step.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Clash <-> BCF bridge.
3
+ *
4
+ * Turns grouped clash results into a BCF 2.1 project (one topic per clash
5
+ * group, with a framing viewpoint, selection and coloring) and reads such a
6
+ * project back into a map of clash-id -> { topicGuid, status } for status
7
+ * round-tripping. Topic GUIDs are a deterministic function of the group id, so
8
+ * topic identity is stable across re-exports (timestamps and viewpoint guids
9
+ * come from @ifc-lite/bcf and are not deterministic, so the archive bytes are
10
+ * not identical — but the clash<->topic anchoring is).
11
+ *
12
+ * Transparency is a first-class concern: when the group count exceeds the cap,
13
+ * we never silently drop the overflow. We emit the top topics and one extra
14
+ * marker topic that records exactly how many groups were not exported.
15
+ */
16
+ import { type BCFProject } from '@ifc-lite/bcf';
17
+ import type { ClashGroup, ClashResult } from './types.js';
18
+ export interface ClashBcfOptions {
19
+ author: string;
20
+ status?: string;
21
+ projectName?: string;
22
+ maxTopics?: number;
23
+ maxMembersPerTopic?: number;
24
+ cameraDistanceFactor?: number;
25
+ snapshotProvider?: (group: ClashGroup) => Promise<Uint8Array | undefined>;
26
+ }
27
+ /**
28
+ * Build a BCF 2.1 project from a clash result and its precomputed groups.
29
+ *
30
+ * Groups are sorted (critical first, then larger groups), capped at
31
+ * `maxTopics`, and any overflow is recorded in one transparency topic.
32
+ */
33
+ export declare function createBCFFromClashResult(result: ClashResult, groups: ClashGroup[], opts: ClashBcfOptions): Promise<BCFProject>;
34
+ /**
35
+ * Read a BCF project back into a map of clash-id -> [{ topicGuid, status }, ...].
36
+ *
37
+ * Parses the machine-readable `clash-ids:` line that `createBCFFromClashResult`
38
+ * embeds in each topic description. Topics without that line (e.g. the overflow
39
+ * marker, or unrelated topics) are skipped.
40
+ *
41
+ * A clash id can legitimately appear in more than one topic: element-mode
42
+ * grouping (see `groupClashes(result, { by: 'element' })`) emits one group per
43
+ * participating element, so a clash between two elements lands in two topics.
44
+ * We therefore accumulate one entry per topic the id appears in rather than
45
+ * overwriting, so no topic mapping is silently lost.
46
+ */
47
+ export declare function mapBcfToClashes(project: BCFProject): Map<string, Array<{
48
+ topicGuid: string;
49
+ status: string;
50
+ }>>;
51
+ //# sourceMappingURL=bcf-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bcf-bridge.d.ts","sourceRoot":"","sources":["../src/bcf-bridge.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAOL,KAAK,UAAU,EAIhB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAe,UAAU,EAAE,WAAW,EAAuB,MAAM,YAAY,CAAC;AAG5F,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;CAC3E;AAuMD;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAAE,EACpB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,UAAU,CAAC,CAkDrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,UAAU,GAClB,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAmB3D"}
@@ -0,0 +1,298 @@
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
+ * Clash <-> BCF bridge.
6
+ *
7
+ * Turns grouped clash results into a BCF 2.1 project (one topic per clash
8
+ * group, with a framing viewpoint, selection and coloring) and reads such a
9
+ * project back into a map of clash-id -> { topicGuid, status } for status
10
+ * round-tripping. Topic GUIDs are a deterministic function of the group id, so
11
+ * topic identity is stable across re-exports (timestamps and viewpoint guids
12
+ * come from @ifc-lite/bcf and are not deterministic, so the archive bytes are
13
+ * not identical — but the clash<->topic anchoring is).
14
+ *
15
+ * Transparency is a first-class concern: when the group count exceeds the cap,
16
+ * we never silently drop the overflow. We emit the top topics and one extra
17
+ * marker topic that records exactly how many groups were not exported.
18
+ */
19
+ import { createBCFProject, createBCFTopic, createViewpoint, addViewpointToTopic, addTopicToProject, toARGBColor, } from '@ifc-lite/bcf';
20
+ import { uuidFromSeed } from './deterministic-uuid.js';
21
+ const DEFAULT_MAX_TOPICS = 1000;
22
+ const DEFAULT_MAX_MEMBERS = 50;
23
+ const DEFAULT_CAMERA_DISTANCE_FACTOR = 2.5;
24
+ /** Minimum eye-to-target standoff (m) so the camera is never coincident with the target. */
25
+ const STANDOFF_FLOOR = 1e-3;
26
+ const CLASH_IDS_PREFIX = 'clash-ids: ';
27
+ const SEVERITY_RANK = {
28
+ critical: 0,
29
+ major: 1,
30
+ minor: 2,
31
+ info: 3,
32
+ };
33
+ const SEVERITY_PRIORITY = {
34
+ critical: 'High',
35
+ major: 'Normal',
36
+ minor: 'Low',
37
+ info: 'Low',
38
+ };
39
+ /** Deterministic sort: severity (critical first), then member count desc, then id. */
40
+ function sortGroups(groups) {
41
+ return [...groups].sort((a, b) => {
42
+ const sevDiff = SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];
43
+ if (sevDiff !== 0)
44
+ return sevDiff;
45
+ const countDiff = b.members.length - a.members.length;
46
+ if (countDiff !== 0)
47
+ return countDiff;
48
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
49
+ });
50
+ }
51
+ /** Unique, insertion-ordered list of values. */
52
+ function unique(values) {
53
+ const seen = new Set();
54
+ const out = [];
55
+ for (const v of values) {
56
+ if (!seen.has(v)) {
57
+ seen.add(v);
58
+ out.push(v);
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+ function midpoint(b) {
64
+ return [
65
+ (b.min[0] + b.max[0]) / 2,
66
+ (b.min[1] + b.max[1]) / 2,
67
+ (b.min[2] + b.max[2]) / 2,
68
+ ];
69
+ }
70
+ function diagonalLength(b) {
71
+ const dx = b.max[0] - b.min[0];
72
+ const dy = b.max[1] - b.min[1];
73
+ const dz = b.max[2] - b.min[2];
74
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
75
+ }
76
+ function toViewerBounds(b) {
77
+ return {
78
+ min: { x: b.min[0], y: b.min[1], z: b.min[2] },
79
+ max: { x: b.max[0], y: b.max[1], z: b.max[2] },
80
+ };
81
+ }
82
+ /** Frame `bounds` from a fixed oblique direction so the group is fully in view. */
83
+ function cameraForBounds(bounds, distanceFactor) {
84
+ const centerPt = midpoint(bounds);
85
+ const radius = 0.5 * diagonalLength(bounds);
86
+ // normalize([1, 0.7, 1])
87
+ const dirLen = Math.sqrt(1 * 1 + 0.7 * 0.7 + 1 * 1);
88
+ const dir = [1 / dirLen, 0.7 / dirLen, 1 / dirLen];
89
+ // Degenerate bounds (single point) -> use a fixed standoff so the camera is
90
+ // never coincident with the target.
91
+ const standoff = Math.max(radius > 0 ? radius * distanceFactor : distanceFactor, STANDOFF_FLOOR);
92
+ const position = [
93
+ centerPt[0] + dir[0] * standoff,
94
+ centerPt[1] + dir[1] * standoff,
95
+ centerPt[2] + dir[2] * standoff,
96
+ ];
97
+ return {
98
+ position: { x: position[0], y: position[1], z: position[2] },
99
+ target: { x: centerPt[0], y: centerPt[1], z: centerPt[2] },
100
+ up: { x: 0, y: 1, z: 0 },
101
+ fov: 0.9,
102
+ };
103
+ }
104
+ /** Count members by a string-valued key. */
105
+ function tally(members, pick) {
106
+ const out = {};
107
+ for (const m of members) {
108
+ const k = pick(m);
109
+ out[k] = (out[k] ?? 0) + 1;
110
+ }
111
+ return out;
112
+ }
113
+ function formatCounts(counts) {
114
+ const keys = Object.keys(counts).sort();
115
+ return keys.map((k) => `${k}: ${counts[k]}`).join(', ');
116
+ }
117
+ /** A readable, human-facing summary plus the machine-readable clash-ids line. */
118
+ function buildDescription(group, maxMembers) {
119
+ const lines = [];
120
+ lines.push(`Clash group "${group.title}" with ${group.members.length} member(s).`);
121
+ if (group.discipline)
122
+ lines.push(`Discipline: ${group.discipline}`);
123
+ if (group.storey)
124
+ lines.push(`Storey: ${group.storey}`);
125
+ lines.push(`Severity: ${group.severity}`);
126
+ lines.push(`By status: ${formatCounts(tally(group.members, (c) => c.status))}`);
127
+ lines.push(`By severity: ${formatCounts(tally(group.members, (c) => c.severity))}`);
128
+ const typePairs = tally(group.members, (c) => {
129
+ const ta = c.a.tag;
130
+ const tb = c.b.tag;
131
+ return ta < tb ? `${ta} x ${tb}` : `${tb} x ${ta}`;
132
+ });
133
+ lines.push(`Type pairs: ${formatCounts(typePairs)}`);
134
+ lines.push('');
135
+ lines.push('Members:');
136
+ const shown = group.members.slice(0, maxMembers);
137
+ for (const m of shown) {
138
+ const nameA = m.a.name ? ` (${m.a.name})` : '';
139
+ const nameB = m.b.name ? ` (${m.b.name})` : '';
140
+ lines.push(`- [${m.rule}/${m.status}] ${m.a.tag}${nameA} ${m.a.key} <-> ${m.b.tag}${nameB} ${m.b.key} | gap ${m.distance.toFixed(4)}`);
141
+ }
142
+ const remaining = group.members.length - shown.length;
143
+ if (remaining > 0) {
144
+ lines.push(`...and ${remaining} more`);
145
+ }
146
+ lines.push('');
147
+ // Machine-readable, uncapped: every member id so the round-trip recovers all.
148
+ // Ids are percent-encoded so commas inside a model name / rule id cannot break
149
+ // the comma-delimited list (clash ids are otherwise free-form strings).
150
+ lines.push(`${CLASH_IDS_PREFIX}${group.members.map((m) => encodeURIComponent(m.id)).join(',')}`);
151
+ return lines.join('\n');
152
+ }
153
+ /** Build the topic + framing viewpoint for one group. */
154
+ async function buildTopicForGroup(project, group, opts, maxMembers, cameraDistanceFactor) {
155
+ const description = buildDescription(group, maxMembers);
156
+ const priority = SEVERITY_PRIORITY[group.severity];
157
+ const labels = [group.discipline, 'Clash'].filter((l) => Boolean(l));
158
+ const topic = createBCFTopic({
159
+ title: group.title,
160
+ description,
161
+ author: opts.author,
162
+ topicType: 'Clash',
163
+ topicStatus: opts.status ?? 'Open',
164
+ priority,
165
+ labels,
166
+ });
167
+ // Deterministic guid: stable function of the group id (input-only).
168
+ topic.guid = uuidFromSeed(group.id);
169
+ const selectedGuids = unique(group.members.flatMap((m) => [m.a.key, m.b.key]));
170
+ const coloredGuids = [
171
+ { color: toARGBColor(255, 51, 51), guids: unique(group.members.map((m) => m.a.key)) },
172
+ { color: toARGBColor(255, 165, 0), guids: unique(group.members.map((m) => m.b.key)) },
173
+ ];
174
+ const camera = cameraForBounds(group.bounds, cameraDistanceFactor);
175
+ const bounds = toViewerBounds(group.bounds);
176
+ const snapshotData = opts.snapshotProvider ? await opts.snapshotProvider(group) : undefined;
177
+ const viewpoint = createViewpoint({
178
+ camera,
179
+ bounds,
180
+ selectedGuids,
181
+ coloredGuids,
182
+ snapshotData,
183
+ });
184
+ addViewpointToTopic(topic, viewpoint);
185
+ addTopicToProject(project, topic);
186
+ }
187
+ /**
188
+ * Build a BCF 2.1 project from a clash result and its precomputed groups.
189
+ *
190
+ * Groups are sorted (critical first, then larger groups), capped at
191
+ * `maxTopics`, and any overflow is recorded in one transparency topic.
192
+ */
193
+ export async function createBCFFromClashResult(result, groups, opts) {
194
+ // `result` carries run-level settings; reference it so the summary in the
195
+ // overflow topic can quote the real total even when groups are partial.
196
+ const totalClashes = result.summary.total;
197
+ const project = createBCFProject({
198
+ name: opts.projectName ?? 'Clash report',
199
+ version: '2.1',
200
+ });
201
+ const maxTopics = opts.maxTopics ?? DEFAULT_MAX_TOPICS;
202
+ const maxMembers = opts.maxMembersPerTopic ?? DEFAULT_MAX_MEMBERS;
203
+ const cameraDistanceFactor = opts.cameraDistanceFactor ?? DEFAULT_CAMERA_DISTANCE_FACTOR;
204
+ const sorted = sortGroups(groups);
205
+ const exported = sorted.slice(0, maxTopics);
206
+ const droppedCount = sorted.length - exported.length;
207
+ for (const group of exported) {
208
+ await buildTopicForGroup(project, group, opts, maxMembers, cameraDistanceFactor);
209
+ }
210
+ if (droppedCount > 0) {
211
+ // Transparency: never silently drop. One marker topic records the overflow.
212
+ const overflowTitle = `... ${droppedCount} more clash groups not exported`;
213
+ const overflowDescription = [
214
+ `${droppedCount} clash group(s) exceeded the maxTopics cap of ${maxTopics} and were not exported.`,
215
+ `Total clash groups: ${sorted.length}. Exported: ${exported.length}.`,
216
+ `Total clashes in result: ${totalClashes}.`,
217
+ 'Increase maxTopics to export the remaining groups.',
218
+ ].join('\n');
219
+ const overflowTopic = createBCFTopic({
220
+ title: overflowTitle,
221
+ description: overflowDescription,
222
+ author: opts.author,
223
+ topicType: 'Clash',
224
+ topicStatus: opts.status ?? 'Open',
225
+ priority: 'Low',
226
+ labels: ['Clash'],
227
+ });
228
+ // Stable guid for the overflow marker too, keyed off the project name and
229
+ // count so a re-run with the same overflow is idempotent.
230
+ overflowTopic.guid = uuidFromSeed(`overflow:${opts.projectName ?? 'Clash report'}:${maxTopics}:${droppedCount}`);
231
+ addTopicToProject(project, overflowTopic);
232
+ }
233
+ return project;
234
+ }
235
+ /**
236
+ * Read a BCF project back into a map of clash-id -> [{ topicGuid, status }, ...].
237
+ *
238
+ * Parses the machine-readable `clash-ids:` line that `createBCFFromClashResult`
239
+ * embeds in each topic description. Topics without that line (e.g. the overflow
240
+ * marker, or unrelated topics) are skipped.
241
+ *
242
+ * A clash id can legitimately appear in more than one topic: element-mode
243
+ * grouping (see `groupClashes(result, { by: 'element' })`) emits one group per
244
+ * participating element, so a clash between two elements lands in two topics.
245
+ * We therefore accumulate one entry per topic the id appears in rather than
246
+ * overwriting, so no topic mapping is silently lost.
247
+ */
248
+ export function mapBcfToClashes(project) {
249
+ const map = new Map();
250
+ for (const topic of project.topics.values()) {
251
+ const ids = extractClashIds(topic);
252
+ if (ids.length === 0)
253
+ continue;
254
+ const status = topic.topicStatus ?? 'Open';
255
+ for (const id of ids) {
256
+ const entry = { topicGuid: topic.guid, status };
257
+ const existing = map.get(id);
258
+ if (existing) {
259
+ existing.push(entry);
260
+ }
261
+ else {
262
+ map.set(id, [entry]);
263
+ }
264
+ }
265
+ }
266
+ return map;
267
+ }
268
+ /** decodeURIComponent that tolerates malformed input (keeps the raw token). */
269
+ function safeDecode(token) {
270
+ try {
271
+ return decodeURIComponent(token);
272
+ }
273
+ catch (err) {
274
+ console.warn('[clash/bcf] malformed clash-id token; keeping it raw', token, err);
275
+ return token;
276
+ }
277
+ }
278
+ /** Pull the comma-separated ids out of a topic's `clash-ids:` line. */
279
+ function extractClashIds(topic) {
280
+ const description = topic.description;
281
+ if (!description)
282
+ return [];
283
+ for (const line of description.split('\n')) {
284
+ const trimmed = line.trim();
285
+ if (trimmed.startsWith(CLASH_IDS_PREFIX.trim())) {
286
+ const payload = trimmed.slice(CLASH_IDS_PREFIX.trim().length).trim();
287
+ if (payload.length === 0)
288
+ return [];
289
+ return payload
290
+ .split(',')
291
+ .map((s) => s.trim())
292
+ .filter((s) => s.length > 0)
293
+ .map((s) => safeDecode(s));
294
+ }
295
+ }
296
+ return [];
297
+ }
298
+ //# sourceMappingURL=bcf-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bcf-bridge.js","sourceRoot":"","sources":["../src/bcf-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Stable RFC-4122-shaped UUID derived purely from `seed`.
3
+ *
4
+ * - 8-4-4-4-12 lowercase hex
5
+ * - version nibble fixed to '4'
6
+ * - variant nibble in {8, 9, a, b}
7
+ */
8
+ export declare function uuidFromSeed(seed: string): string;
9
+ //# sourceMappingURL=deterministic-uuid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic-uuid.d.ts","sourceRoot":"","sources":["../src/deterministic-uuid.ts"],"names":[],"mappings":"AAqDA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqCjD"}
@@ -0,0 +1,87 @@
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
+ * Deterministic, input-only UUID generation.
6
+ *
7
+ * Produces an RFC-4122-shaped identifier (8-4-4-4-12 lowercase hex) whose 128
8
+ * bits are derived purely from a seed string. The same seed always yields the
9
+ * same UUID, with no dependence on the system clock or any random source. This
10
+ * is what lets a BCF topic guid be a stable function of a clash-group id, so a
11
+ * re-run of the same coordination produces byte-identical topic guids and the
12
+ * round-trip back to clashes stays anchored.
13
+ *
14
+ * The 128 bits are filled from four 32-bit words. Each word starts from an
15
+ * FNV-1a hash of the seed mixed with a distinct salt, then is run through a
16
+ * short xorshift cascade so adjacent seeds (e.g. "g1" vs "g2") diffuse into
17
+ * fully different words rather than differing in only a few low bits.
18
+ */
19
+ const FNV_OFFSET_BASIS = 0x811c9dc5;
20
+ const FNV_PRIME = 0x01000193;
21
+ /** 32-bit FNV-1a over the UTF-8-ish code units of `input`, seeded with `salt`. */
22
+ function fnv1a(input, salt) {
23
+ let hash = (FNV_OFFSET_BASIS ^ salt) >>> 0;
24
+ for (let i = 0; i < input.length; i += 1) {
25
+ const code = input.charCodeAt(i);
26
+ // Fold the full 16-bit code unit in two byte-sized steps so non-ASCII
27
+ // comment-free seeds still contribute every bit.
28
+ hash = (hash ^ (code & 0xff)) >>> 0;
29
+ hash = Math.imul(hash, FNV_PRIME) >>> 0;
30
+ hash = (hash ^ ((code >>> 8) & 0xff)) >>> 0;
31
+ hash = Math.imul(hash, FNV_PRIME) >>> 0;
32
+ }
33
+ return hash >>> 0;
34
+ }
35
+ /** A short xorshift cascade to diffuse a 32-bit word. */
36
+ function xorshift32(value) {
37
+ let x = value >>> 0;
38
+ x ^= x << 13;
39
+ x >>>= 0;
40
+ x ^= x >>> 17;
41
+ x ^= x << 5;
42
+ return x >>> 0;
43
+ }
44
+ /** Left-pad a non-negative 32-bit word to 8 lowercase hex chars. */
45
+ function hex32(value) {
46
+ return (value >>> 0).toString(16).padStart(8, '0');
47
+ }
48
+ /**
49
+ * Stable RFC-4122-shaped UUID derived purely from `seed`.
50
+ *
51
+ * - 8-4-4-4-12 lowercase hex
52
+ * - version nibble fixed to '4'
53
+ * - variant nibble in {8, 9, a, b}
54
+ */
55
+ export function uuidFromSeed(seed) {
56
+ // Four independent 32-bit words, each its own salt then xorshift-mixed.
57
+ const w0 = xorshift32(fnv1a(seed, 0x9e3779b1));
58
+ const w1 = xorshift32(fnv1a(seed, 0x85ebca77));
59
+ const w2 = xorshift32(fnv1a(seed, 0xc2b2ae3d));
60
+ const w3 = xorshift32(fnv1a(seed, 0x27d4eb2f));
61
+ // Cross-mix so each output nibble depends on the whole seed, not one word.
62
+ const a = xorshift32(w0 ^ Math.imul(w3, FNV_PRIME)) >>> 0;
63
+ const b = xorshift32(w1 ^ Math.imul(w0, FNV_PRIME)) >>> 0;
64
+ const c = xorshift32(w2 ^ Math.imul(w1, FNV_PRIME)) >>> 0;
65
+ const d = xorshift32(w3 ^ Math.imul(w2, FNV_PRIME)) >>> 0;
66
+ const hexA = hex32(a);
67
+ const hexB = hex32(b);
68
+ const hexC = hex32(c);
69
+ const hexD = hex32(d);
70
+ // Layout: AAAAAAAA-BBBB-4BBB-VCCC-CCCCDDDDDDDD
71
+ // time_low = hexA (8)
72
+ // time_mid = hexB[0..4) (4)
73
+ // time_hi_ver = '4' + hexB[4..7) (4, version nibble forced to 4)
74
+ // clock_variant = variant + hexC[1..4) (4)
75
+ // node = hexC[4..8) + hexD (12)
76
+ const timeLow = hexA;
77
+ const timeMid = hexB.slice(0, 4);
78
+ const timeHiAndVersion = `4${hexB.slice(4, 7)}`;
79
+ // Variant nibble: high two bits must be '10' -> one of 8, 9, a, b.
80
+ // Derive it from the top nibble of hexC so it is still seed-dependent.
81
+ const variantSource = parseInt(hexC[0], 16);
82
+ const variantNibble = ((variantSource & 0x3) | 0x8).toString(16);
83
+ const clockSeqAndVariant = `${variantNibble}${hexC.slice(1, 4)}`;
84
+ const node = `${hexC.slice(4, 8)}${hexD}`;
85
+ return `${timeLow}-${timeMid}-${timeHiAndVersion}-${clockSeqAndVariant}-${node}`;
86
+ }
87
+ //# sourceMappingURL=deterministic-uuid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic-uuid.js","sourceRoot":"","sources":["../src/deterministic-uuid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { ClashMode, ClashRule, ClashSeverity } from './types.js';
2
+ export type Discipline = 'ARCH' | 'STR' | 'MEP' | 'HVAC' | 'ELEC' | 'FIRE' | 'GEO';
3
+ export interface DisciplineInfo {
4
+ code: Discipline;
5
+ label: string;
6
+ selector: string;
7
+ }
8
+ export declare const DISCIPLINES: Record<Discipline, DisciplineInfo>;
9
+ export interface ClashRulePreset {
10
+ id: string;
11
+ name: string;
12
+ description: string;
13
+ severity: ClashSeverity;
14
+ selectorA: string;
15
+ selectorB: string;
16
+ }
17
+ export declare const CLASH_RULE_PRESETS: ClashRulePreset[];
18
+ /**
19
+ * Infer severity for a clash from the IFC types of the two elements, by matching
20
+ * against the discipline-pair presets. Returns the most severe matching rule.
21
+ */
22
+ export declare function inferClashSeverity(typeA: string, typeB: string): ClashSeverity;
23
+ /** Turn the discipline presets into runnable clash rules (the clash matrix). */
24
+ /**
25
+ * Turn an arbitrary list of rule presets into runnable `ClashRule`s. Used by the
26
+ * built-in discipline matrix below and by the viewer to run a user-edited preset
27
+ * set. `clearance` is threaded onto each rule only in clearance mode (narrow.ts
28
+ * only reports clearance violations when `rule.clearance != null`); `reportTouch`
29
+ * is threaded onto every rule when set.
30
+ */
31
+ export declare function rulesFromPresets(presets: ClashRulePreset[], mode?: ClashMode, clearance?: number, reportTouch?: boolean): ClashRule[];
32
+ export declare function disciplineMatrixRules(mode?: ClashMode, clearance?: number): ClashRule[];
33
+ //# sourceMappingURL=disciplines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disciplines.d.ts","sourceRoot":"","sources":["../src/disciplines.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAEnF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,cAAc,CAoC1D,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,EAAE,eAAe,EAyD/C,CAAC;AASF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAe9E;AAED,gFAAgF;AAChF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EAAE,EAC1B,IAAI,GAAE,SAAkB,EACxB,SAAS,CAAC,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,OAAO,GACpB,SAAS,EAAE,CAWb;AAED,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,SAAkB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAE/F"}