@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.
- package/LICENSE +373 -0
- package/README.md +32 -0
- package/dist/adapters/ifcx.d.ts +44 -0
- package/dist/adapters/ifcx.d.ts.map +1 -0
- package/dist/adapters/ifcx.js +198 -0
- package/dist/adapters/ifcx.js.map +1 -0
- package/dist/adapters/step.d.ts +42 -0
- package/dist/adapters/step.d.ts.map +1 -0
- package/dist/adapters/step.js +77 -0
- package/dist/adapters/step.js.map +1 -0
- package/dist/bcf-bridge.d.ts +51 -0
- package/dist/bcf-bridge.d.ts.map +1 -0
- package/dist/bcf-bridge.js +298 -0
- package/dist/bcf-bridge.js.map +1 -0
- package/dist/deterministic-uuid.d.ts +9 -0
- package/dist/deterministic-uuid.d.ts.map +1 -0
- package/dist/deterministic-uuid.js +87 -0
- package/dist/deterministic-uuid.js.map +1 -0
- package/dist/disciplines.d.ts +33 -0
- package/dist/disciplines.d.ts.map +1 -0
- package/dist/disciplines.js +148 -0
- package/dist/disciplines.js.map +1 -0
- package/dist/engine-ts/broad.d.ts +11 -0
- package/dist/engine-ts/broad.d.ts.map +1 -0
- package/dist/engine-ts/broad.js +61 -0
- package/dist/engine-ts/broad.js.map +1 -0
- package/dist/engine-ts/index.d.ts +16 -0
- package/dist/engine-ts/index.d.ts.map +1 -0
- package/dist/engine-ts/index.js +17 -0
- package/dist/engine-ts/index.js.map +1 -0
- package/dist/engine-ts/kernel.d.ts +50 -0
- package/dist/engine-ts/kernel.d.ts.map +1 -0
- package/dist/engine-ts/kernel.js +5 -0
- package/dist/engine-ts/kernel.js.map +1 -0
- package/dist/engine-ts/narrow.d.ts +23 -0
- package/dist/engine-ts/narrow.d.ts.map +1 -0
- package/dist/engine-ts/narrow.js +127 -0
- package/dist/engine-ts/narrow.js.map +1 -0
- package/dist/engine-ts/orchestrator.d.ts +11 -0
- package/dist/engine-ts/orchestrator.d.ts.map +1 -0
- package/dist/engine-ts/orchestrator.js +127 -0
- package/dist/engine-ts/orchestrator.js.map +1 -0
- package/dist/engine-ts/tri-mesh.d.ts +33 -0
- package/dist/engine-ts/tri-mesh.d.ts.map +1 -0
- package/dist/engine-ts/tri-mesh.js +125 -0
- package/dist/engine-ts/tri-mesh.js.map +1 -0
- package/dist/engine-ts/ts-kernel.d.ts +14 -0
- package/dist/engine-ts/ts-kernel.d.ts.map +1 -0
- package/dist/engine-ts/ts-kernel.js +85 -0
- package/dist/engine-ts/ts-kernel.js.map +1 -0
- package/dist/engine-wasm/index.d.ts +21 -0
- package/dist/engine-wasm/index.d.ts.map +1 -0
- package/dist/engine-wasm/index.js +40 -0
- package/dist/engine-wasm/index.js.map +1 -0
- package/dist/engine-wasm/wasm-kernel.d.ts +20 -0
- package/dist/engine-wasm/wasm-kernel.d.ts.map +1 -0
- package/dist/engine-wasm/wasm-kernel.js +106 -0
- package/dist/engine-wasm/wasm-kernel.js.map +1 -0
- package/dist/engine.d.ts +14 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +20 -0
- package/dist/engine.js.map +1 -0
- package/dist/exclude.d.ts +15 -0
- package/dist/exclude.d.ts.map +1 -0
- package/dist/exclude.js +38 -0
- package/dist/exclude.js.map +1 -0
- package/dist/grouping.d.ts +16 -0
- package/dist/grouping.d.ts.map +1 -0
- package/dist/grouping.js +311 -0
- package/dist/grouping.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +41 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +70 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/math/aabb.d.ts +27 -0
- package/dist/math/aabb.d.ts.map +1 -0
- package/dist/math/aabb.js +127 -0
- package/dist/math/aabb.js.map +1 -0
- package/dist/math/triangle-distance.d.ts +29 -0
- package/dist/math/triangle-distance.d.ts.map +1 -0
- package/dist/math/triangle-distance.js +149 -0
- package/dist/math/triangle-distance.js.map +1 -0
- package/dist/math/triangle-intersect.d.ts +13 -0
- package/dist/math/triangle-intersect.d.ts.map +1 -0
- package/dist/math/triangle-intersect.js +55 -0
- package/dist/math/triangle-intersect.js.map +1 -0
- package/dist/math/vec3.d.ts +11 -0
- package/dist/math/vec3.d.ts.map +1 -0
- package/dist/math/vec3.js +38 -0
- package/dist/math/vec3.js.map +1 -0
- package/dist/selectors.d.ts +12 -0
- package/dist/selectors.d.ts.map +1 -0
- package/dist/selectors.js +53 -0
- package/dist/selectors.js.map +1 -0
- package/dist/triage.d.ts +19 -0
- package/dist/triage.d.ts.map +1 -0
- package/dist/triage.js +99 -0
- package/dist/triage.js.map +1 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ClashEngine } from './engine-ts/index.js';
|
|
2
|
+
export type { ClashEngine };
|
|
3
|
+
export type ClashBackend = 'ts' | 'wasm' | 'auto';
|
|
4
|
+
export interface CreateClashEngineOptions {
|
|
5
|
+
/** `ts` reference engine (default for now). `wasm`/`auto` land in Phase 3. */
|
|
6
|
+
backend?: ClashBackend;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a clash engine. Phase 0 ships the TypeScript reference engine; the
|
|
10
|
+
* Rust→WASM backend and `auto` selection arrive in Phase 3 behind this same
|
|
11
|
+
* interface.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createClashEngine(options?: CreateClashEngineOptions): ClashEngine;
|
|
14
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEvE,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,WAAW,CAWrF"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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 { TsClashEngine } from './engine-ts/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Create a clash engine. Phase 0 ships the TypeScript reference engine; the
|
|
7
|
+
* Rust→WASM backend and `auto` selection arrive in Phase 3 behind this same
|
|
8
|
+
* interface.
|
|
9
|
+
*/
|
|
10
|
+
export function createClashEngine(options = {}) {
|
|
11
|
+
const backend = options.backend ?? 'auto';
|
|
12
|
+
if (backend === 'wasm') {
|
|
13
|
+
throw new Error('Import { WasmClashEngine } from "@ifc-lite/clash/wasm" instead — the WASM backend ' +
|
|
14
|
+
'needs async init and is kept off the core import graph (subpath-only).');
|
|
15
|
+
}
|
|
16
|
+
// 'auto' resolves to the in-process TS engine. The Rust/WASM backend is opt-in
|
|
17
|
+
// via @ifc-lite/clash/wasm (it requires an async module init before use).
|
|
18
|
+
return new TsClashEngine();
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,OAAO,EAAE,aAAa,EAAoB,MAAM,sBAAsB,CAAC;AAWvE;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAoC,EAAE;IACtE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC;IAC1C,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,oFAAoF;YAClF,wEAAwE,CAC3E,CAAC;IACJ,CAAC;IACD,+EAA+E;IAC/E,0EAA0E;IAC1E,OAAO,IAAI,aAAa,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ExclusionSet } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Federation-safe element identity: a model-qualified key. Element identity is
|
|
4
|
+
* `(model, key)` everywhere in the engine, so exclusions must be namespaced by
|
|
5
|
+
* model too — otherwise two models that both contain element "42" collide and
|
|
6
|
+
* can hide valid cross-model clashes.
|
|
7
|
+
*/
|
|
8
|
+
export declare function qualifiedKey(model: string, key: string): string;
|
|
9
|
+
/** Order-independent key for a pair of (already model-qualified) element keys. */
|
|
10
|
+
export declare function pairKey(a: string, b: string): string;
|
|
11
|
+
/** Build an exclusion set from qualified-key pairs (voids/hosts/assemblies). */
|
|
12
|
+
export declare function makeExclusionSet(pairs?: Iterable<[string, string]>): ExclusionSet;
|
|
13
|
+
/** Whether the pair (a, b) — both model-qualified keys — is excluded. */
|
|
14
|
+
export declare function isExcluded(set: ExclusionSet, a: string, b: string): boolean;
|
|
15
|
+
//# sourceMappingURL=exclude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclude.d.ts","sourceRoot":"","sources":["../src/exclude.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAW/C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,GAAG,YAAY,CAMrF;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAE3E"}
|
package/dist/exclude.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
* Length-prefix encode a string so concatenations are unambiguous regardless of
|
|
6
|
+
* the content (model ids, IfcGUIDs and USD prim paths are all free-form). All
|
|
7
|
+
* output is printable ASCII — no separators to collide with, no control bytes.
|
|
8
|
+
*/
|
|
9
|
+
function encode(value) {
|
|
10
|
+
return `${value.length}:${value}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Federation-safe element identity: a model-qualified key. Element identity is
|
|
14
|
+
* `(model, key)` everywhere in the engine, so exclusions must be namespaced by
|
|
15
|
+
* model too — otherwise two models that both contain element "42" collide and
|
|
16
|
+
* can hide valid cross-model clashes.
|
|
17
|
+
*/
|
|
18
|
+
export function qualifiedKey(model, key) {
|
|
19
|
+
return encode(model) + encode(key);
|
|
20
|
+
}
|
|
21
|
+
/** Order-independent key for a pair of (already model-qualified) element keys. */
|
|
22
|
+
export function pairKey(a, b) {
|
|
23
|
+
const [lo, hi] = a < b ? [a, b] : [b, a];
|
|
24
|
+
return encode(lo) + encode(hi);
|
|
25
|
+
}
|
|
26
|
+
/** Build an exclusion set from qualified-key pairs (voids/hosts/assemblies). */
|
|
27
|
+
export function makeExclusionSet(pairs = []) {
|
|
28
|
+
const set = new Set();
|
|
29
|
+
for (const [a, b] of pairs) {
|
|
30
|
+
set.add(pairKey(a, b));
|
|
31
|
+
}
|
|
32
|
+
return set;
|
|
33
|
+
}
|
|
34
|
+
/** Whether the pair (a, b) — both model-qualified keys — is excluded. */
|
|
35
|
+
export function isExcluded(set, a, b) {
|
|
36
|
+
return set.has(pairKey(a, b));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=exclude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclude.js","sourceRoot":"","sources":["../src/exclude.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAI/D;;;;GAIG;AACH,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,GAAW;IACrD,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,OAAO,CAAC,CAAS,EAAE,CAAS;IAC1C,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,QAAoC,EAAE;IACrE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;QAC3B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,UAAU,CAAC,GAAiB,EAAE,CAAS,EAAE,CAAS;IAChE,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { center } from './math/aabb.js';
|
|
2
|
+
import type { ClashGroup, ClashResult } from './types.js';
|
|
3
|
+
/** How to partition a `ClashResult` into groups. */
|
|
4
|
+
export interface GroupOptions {
|
|
5
|
+
by: 'cluster' | 'rule' | 'typePair' | 'element' | 'storey';
|
|
6
|
+
/** Cluster radius in metres for `by: 'cluster'`. Defaults to 1.5 m. */
|
|
7
|
+
epsilon?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Group a clash result. `Clash` carries no storey, so `by: 'storey'` falls back
|
|
11
|
+
* to rule grouping (see module notes / report) rather than inventing a field.
|
|
12
|
+
*/
|
|
13
|
+
export declare function groupClashes(result: ClashResult, opts: GroupOptions): ClashGroup[];
|
|
14
|
+
/** Re-exported for callers that want the cluster centre of a group's bounds. */
|
|
15
|
+
export { center as groupCenter };
|
|
16
|
+
//# sourceMappingURL=grouping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grouping.d.ts","sourceRoot":"","sources":["../src/grouping.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAIxC,OAAO,KAAK,EAGV,UAAU,EACV,WAAW,EAGZ,MAAM,YAAY,CAAC;AAEpB,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3D,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA6RD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,GAAG,UAAU,EAAE,CAqClF;AAED,gFAAgF;AAChF,OAAO,EAAE,MAAM,IAAI,WAAW,EAAE,CAAC"}
|
package/dist/grouping.js
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
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 { center } from './math/aabb.js';
|
|
5
|
+
import { distSq } from './math/vec3.js';
|
|
6
|
+
import { CLASH_RULE_PRESETS, DISCIPLINES } from './disciplines.js';
|
|
7
|
+
import { qualifiedKey } from './exclude.js';
|
|
8
|
+
const DEFAULT_EPSILON = 1.5;
|
|
9
|
+
const SEVERITY_RANK = {
|
|
10
|
+
critical: 0,
|
|
11
|
+
major: 1,
|
|
12
|
+
minor: 2,
|
|
13
|
+
info: 3,
|
|
14
|
+
};
|
|
15
|
+
/** Stable 32-bit FNV-1a hash of a string, hex-encoded. Purely input-derived. */
|
|
16
|
+
function fnv1a(input) {
|
|
17
|
+
let hash = 0x811c9dc5;
|
|
18
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
19
|
+
const code = input.charCodeAt(i);
|
|
20
|
+
// Fold both bytes of each UTF-16 code unit so non-ASCII ids cannot collide.
|
|
21
|
+
// 32-bit FNV prime multiply via shifts to stay in unsigned range.
|
|
22
|
+
hash ^= code & 0xff;
|
|
23
|
+
hash = (hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24))) >>> 0;
|
|
24
|
+
hash ^= (code >>> 8) & 0xff;
|
|
25
|
+
hash = (hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24))) >>> 0;
|
|
26
|
+
}
|
|
27
|
+
return hash.toString(16).padStart(8, '0');
|
|
28
|
+
}
|
|
29
|
+
/** Union of two axis-aligned boxes. */
|
|
30
|
+
function unionBounds(a, b) {
|
|
31
|
+
return {
|
|
32
|
+
min: [
|
|
33
|
+
Math.min(a.min[0], b.min[0]),
|
|
34
|
+
Math.min(a.min[1], b.min[1]),
|
|
35
|
+
Math.min(a.min[2], b.min[2]),
|
|
36
|
+
],
|
|
37
|
+
max: [
|
|
38
|
+
Math.max(a.max[0], b.max[0]),
|
|
39
|
+
Math.max(a.max[1], b.max[1]),
|
|
40
|
+
Math.max(a.max[2], b.max[2]),
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Union of all member bounds. `members` is assumed non-empty. */
|
|
45
|
+
function unionOfBounds(members) {
|
|
46
|
+
let acc = members[0].bounds;
|
|
47
|
+
for (let i = 1; i < members.length; i += 1) {
|
|
48
|
+
acc = unionBounds(acc, members[i].bounds);
|
|
49
|
+
}
|
|
50
|
+
return acc;
|
|
51
|
+
}
|
|
52
|
+
/** Mean of member points. `members` is assumed non-empty. */
|
|
53
|
+
function meanPoint(members) {
|
|
54
|
+
let x = 0;
|
|
55
|
+
let y = 0;
|
|
56
|
+
let z = 0;
|
|
57
|
+
for (const m of members) {
|
|
58
|
+
x += m.point[0];
|
|
59
|
+
y += m.point[1];
|
|
60
|
+
z += m.point[2];
|
|
61
|
+
}
|
|
62
|
+
const n = members.length;
|
|
63
|
+
return [x / n, y / n, z / n];
|
|
64
|
+
}
|
|
65
|
+
/** Most severe severity among members (critical wins). Assumes non-empty. */
|
|
66
|
+
function maxSeverity(members) {
|
|
67
|
+
let best = members[0].severity;
|
|
68
|
+
for (let i = 1; i < members.length; i += 1) {
|
|
69
|
+
if (SEVERITY_RANK[members[i].severity] < SEVERITY_RANK[best]) {
|
|
70
|
+
best = members[i].severity;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return best;
|
|
74
|
+
}
|
|
75
|
+
/** Sorted, separator-joined member ids — the basis for the stable group id. */
|
|
76
|
+
function memberIdSignature(members) {
|
|
77
|
+
const ids = members.map((m) => m.id).sort();
|
|
78
|
+
// Newline separates ids: it cannot occur inside an engine clash id (a single
|
|
79
|
+
// line of space-separated GUID/path tokens), so the join stays injective even
|
|
80
|
+
// if a model name or key contains spaces.
|
|
81
|
+
return ids.join('\n');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Stable group id. `discriminator` distinguishes groups that share a member set
|
|
85
|
+
* but mean different things — notably element-mode groups, where two elements
|
|
86
|
+
* that clash only with each other would otherwise collide on an identical id
|
|
87
|
+
* (and downstream produce duplicate BCF topic GUIDs).
|
|
88
|
+
*/
|
|
89
|
+
function groupId(members, discriminator = '') {
|
|
90
|
+
return `grp-${fnv1a(`${discriminator}\n${memberIdSignature(members)}`)}`;
|
|
91
|
+
}
|
|
92
|
+
/** Sorted type-pair key, order-independent: `IfcBeam|IfcPipeSegment`. */
|
|
93
|
+
function typePairKey(clash) {
|
|
94
|
+
const [first, second] = clash.a.tag <= clash.b.tag ? [clash.a.tag, clash.b.tag] : [clash.b.tag, clash.a.tag];
|
|
95
|
+
return `${first}|${second}`;
|
|
96
|
+
}
|
|
97
|
+
/** Discipline label for a rule, via presets then the discipline table. */
|
|
98
|
+
function disciplineForRule(rule) {
|
|
99
|
+
const preset = CLASH_RULE_PRESETS.find((p) => p.id === rule);
|
|
100
|
+
if (preset) {
|
|
101
|
+
return preset.name;
|
|
102
|
+
}
|
|
103
|
+
const upper = rule.toUpperCase();
|
|
104
|
+
for (const info of Object.values(DISCIPLINES)) {
|
|
105
|
+
if (upper === info.code) {
|
|
106
|
+
return info.label;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
/** Human-readable title for a rule-based group. */
|
|
112
|
+
function ruleTitle(rule) {
|
|
113
|
+
const label = disciplineForRule(rule);
|
|
114
|
+
return label ? `${label} (${rule})` : `Rule ${rule}`;
|
|
115
|
+
}
|
|
116
|
+
function makeGroup(members, title, discipline, discriminator = '') {
|
|
117
|
+
const group = {
|
|
118
|
+
id: groupId(members, discriminator),
|
|
119
|
+
title,
|
|
120
|
+
members,
|
|
121
|
+
bounds: unionOfBounds(members),
|
|
122
|
+
representativePoint: meanPoint(members),
|
|
123
|
+
severity: maxSeverity(members),
|
|
124
|
+
};
|
|
125
|
+
if (discipline !== undefined) {
|
|
126
|
+
group.discipline = discipline;
|
|
127
|
+
}
|
|
128
|
+
return group;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Spatial DBSCAN-style clustering: two clashes join iff they share the same
|
|
132
|
+
* `rule` AND the same sorted type-pair AND their `point`s are within `epsilon`
|
|
133
|
+
* (transitively). Partitioning by (rule, type-pair) first keeps unrelated
|
|
134
|
+
* conflicts apart even when co-located. O(n^2) within each partition.
|
|
135
|
+
*/
|
|
136
|
+
function clusterGroups(clashes, epsilon) {
|
|
137
|
+
const partitions = new Map();
|
|
138
|
+
for (const clash of clashes) {
|
|
139
|
+
const key = `${clash.rule}\n${typePairKey(clash)}`;
|
|
140
|
+
const bucket = partitions.get(key);
|
|
141
|
+
if (bucket) {
|
|
142
|
+
bucket.push(clash);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
partitions.set(key, [clash]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const epsilonSq = epsilon * epsilon;
|
|
149
|
+
const groups = [];
|
|
150
|
+
for (const bucket of partitions.values()) {
|
|
151
|
+
const n = bucket.length;
|
|
152
|
+
const parent = new Array(n);
|
|
153
|
+
for (let i = 0; i < n; i += 1) {
|
|
154
|
+
parent[i] = i;
|
|
155
|
+
}
|
|
156
|
+
const find = (i) => {
|
|
157
|
+
let root = i;
|
|
158
|
+
while (parent[root] !== root) {
|
|
159
|
+
root = parent[root];
|
|
160
|
+
}
|
|
161
|
+
// Path compression keeps repeated lookups flat; deterministic.
|
|
162
|
+
let cur = i;
|
|
163
|
+
while (parent[cur] !== root) {
|
|
164
|
+
const next = parent[cur];
|
|
165
|
+
parent[cur] = root;
|
|
166
|
+
cur = next;
|
|
167
|
+
}
|
|
168
|
+
return root;
|
|
169
|
+
};
|
|
170
|
+
const union = (i, j) => {
|
|
171
|
+
const ri = find(i);
|
|
172
|
+
const rj = find(j);
|
|
173
|
+
if (ri !== rj) {
|
|
174
|
+
// Attach the higher-index root under the lower to keep ids stable.
|
|
175
|
+
if (ri < rj) {
|
|
176
|
+
parent[rj] = ri;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
parent[ri] = rj;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
for (let i = 0; i < n; i += 1) {
|
|
184
|
+
for (let j = i + 1; j < n; j += 1) {
|
|
185
|
+
if (distSq(bucket[i].point, bucket[j].point) <= epsilonSq) {
|
|
186
|
+
union(i, j);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const byRoot = new Map();
|
|
191
|
+
for (let i = 0; i < n; i += 1) {
|
|
192
|
+
const root = find(i);
|
|
193
|
+
const members = byRoot.get(root);
|
|
194
|
+
if (members) {
|
|
195
|
+
members.push(bucket[i]);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
byRoot.set(root, [bucket[i]]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
for (const members of byRoot.values()) {
|
|
202
|
+
const sample = members[0];
|
|
203
|
+
const discipline = disciplineForRule(sample.rule);
|
|
204
|
+
const title = `${typePairKey(sample).replaceAll('|', ' vs ')} (${sample.rule})`;
|
|
205
|
+
groups.push(makeGroup(members, title, discipline));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return groups;
|
|
209
|
+
}
|
|
210
|
+
function ruleGroups(clashes) {
|
|
211
|
+
const byRule = new Map();
|
|
212
|
+
for (const clash of clashes) {
|
|
213
|
+
const bucket = byRule.get(clash.rule);
|
|
214
|
+
if (bucket) {
|
|
215
|
+
bucket.push(clash);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
byRule.set(clash.rule, [clash]);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const groups = [];
|
|
222
|
+
for (const [rule, members] of byRule) {
|
|
223
|
+
groups.push(makeGroup(members, ruleTitle(rule), disciplineForRule(rule)));
|
|
224
|
+
}
|
|
225
|
+
return groups;
|
|
226
|
+
}
|
|
227
|
+
function typePairGroups(clashes) {
|
|
228
|
+
const byPair = new Map();
|
|
229
|
+
for (const clash of clashes) {
|
|
230
|
+
const key = typePairKey(clash);
|
|
231
|
+
const bucket = byPair.get(key);
|
|
232
|
+
if (bucket) {
|
|
233
|
+
bucket.push(clash);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
byPair.set(key, [clash]);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const groups = [];
|
|
240
|
+
for (const [key, members] of byPair) {
|
|
241
|
+
groups.push(makeGroup(members, key.replaceAll('|', ' vs '), undefined));
|
|
242
|
+
}
|
|
243
|
+
return groups;
|
|
244
|
+
}
|
|
245
|
+
function elementGroups(clashes) {
|
|
246
|
+
// Each clash contributes to BOTH participating elements, keyed by (model, key)
|
|
247
|
+
// so federated elements that share a key do not collide into one group.
|
|
248
|
+
const byElement = new Map();
|
|
249
|
+
for (const clash of clashes) {
|
|
250
|
+
for (const ref of [clash.a, clash.b]) {
|
|
251
|
+
const k = qualifiedKey(ref.model, ref.key);
|
|
252
|
+
const bucket = byElement.get(k);
|
|
253
|
+
if (bucket) {
|
|
254
|
+
bucket.members.push(clash);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
byElement.set(k, { ref, members: [clash] });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const groups = [];
|
|
262
|
+
for (const [k, { ref, members }] of byElement) {
|
|
263
|
+
const label = ref.name ?? ref.key;
|
|
264
|
+
groups.push(makeGroup(members, `Clashes on ${ref.tag} ${label}`, undefined, `elem:${k}`));
|
|
265
|
+
}
|
|
266
|
+
return groups;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Group a clash result. `Clash` carries no storey, so `by: 'storey'` falls back
|
|
270
|
+
* to rule grouping (see module notes / report) rather than inventing a field.
|
|
271
|
+
*/
|
|
272
|
+
export function groupClashes(result, opts) {
|
|
273
|
+
const clashes = result.clashes;
|
|
274
|
+
let groups;
|
|
275
|
+
switch (opts.by) {
|
|
276
|
+
case 'cluster':
|
|
277
|
+
groups = clusterGroups(clashes, opts.epsilon ?? DEFAULT_EPSILON);
|
|
278
|
+
break;
|
|
279
|
+
case 'rule':
|
|
280
|
+
groups = ruleGroups(clashes);
|
|
281
|
+
break;
|
|
282
|
+
case 'typePair':
|
|
283
|
+
groups = typePairGroups(clashes);
|
|
284
|
+
break;
|
|
285
|
+
case 'element':
|
|
286
|
+
groups = elementGroups(clashes);
|
|
287
|
+
break;
|
|
288
|
+
case 'storey':
|
|
289
|
+
// Clash carries no storey; degrade to rule grouping. See notes.
|
|
290
|
+
groups = ruleGroups(clashes);
|
|
291
|
+
break;
|
|
292
|
+
default: {
|
|
293
|
+
const exhaustive = opts.by;
|
|
294
|
+
throw new Error(`Unknown grouping mode: ${String(exhaustive)}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Severity (critical first), then member count desc, tie-break by id asc.
|
|
298
|
+
groups.sort((a, b) => {
|
|
299
|
+
const sev = SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];
|
|
300
|
+
if (sev !== 0)
|
|
301
|
+
return sev;
|
|
302
|
+
const count = b.members.length - a.members.length;
|
|
303
|
+
if (count !== 0)
|
|
304
|
+
return count;
|
|
305
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
306
|
+
});
|
|
307
|
+
return groups;
|
|
308
|
+
}
|
|
309
|
+
/** Re-exported for callers that want the cluster centre of a group's bounds. */
|
|
310
|
+
export { center as groupCenter };
|
|
311
|
+
//# sourceMappingURL=grouping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grouping.js","sourceRoot":"","sources":["../src/grouping.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ifc-lite/clash — representation-agnostic clash detection core.
|
|
3
|
+
*
|
|
4
|
+
* This entry point depends only on `@ifc-lite/spatial` and geometry *types*.
|
|
5
|
+
* Source adapters (STEP, IFCx) and the BCF bridge live behind subpath exports
|
|
6
|
+
* (`@ifc-lite/clash/step`, …) so the core import graph stays free of
|
|
7
|
+
* version-specific dependencies — the boundary that keeps IFC5 a new adapter
|
|
8
|
+
* rather than a rewrite.
|
|
9
|
+
*/
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
export { matchesSelector } from './selectors.js';
|
|
12
|
+
export { DISCIPLINES, CLASH_RULE_PRESETS, inferClashSeverity, disciplineMatrixRules, rulesFromPresets, type Discipline, type DisciplineInfo, type ClashRulePreset, } from './disciplines.js';
|
|
13
|
+
export { createClashEngine, type ClashEngine, type ClashBackend, type CreateClashEngineOptions } from './engine.js';
|
|
14
|
+
export { makeExclusionSet, isExcluded, pairKey } from './exclude.js';
|
|
15
|
+
export { buildTriageSystemPrompt, buildTriageUserMessage, parseTriageResponse, type ClashTriageResult, } from './triage.js';
|
|
16
|
+
export { groupClashes, type GroupOptions } from './grouping.js';
|
|
17
|
+
export { compareClashRuns, type ClashRevisionDiff } from './lifecycle.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
* @ifc-lite/clash — representation-agnostic clash detection core.
|
|
6
|
+
*
|
|
7
|
+
* This entry point depends only on `@ifc-lite/spatial` and geometry *types*.
|
|
8
|
+
* Source adapters (STEP, IFCx) and the BCF bridge live behind subpath exports
|
|
9
|
+
* (`@ifc-lite/clash/step`, …) so the core import graph stays free of
|
|
10
|
+
* version-specific dependencies — the boundary that keeps IFC5 a new adapter
|
|
11
|
+
* rather than a rewrite.
|
|
12
|
+
*/
|
|
13
|
+
export * from './types.js';
|
|
14
|
+
export { matchesSelector } from './selectors.js';
|
|
15
|
+
export { DISCIPLINES, CLASH_RULE_PRESETS, inferClashSeverity, disciplineMatrixRules, rulesFromPresets, } from './disciplines.js';
|
|
16
|
+
export { createClashEngine } from './engine.js';
|
|
17
|
+
export { makeExclusionSet, isExcluded, pairKey } from './exclude.js';
|
|
18
|
+
export { buildTriageSystemPrompt, buildTriageUserMessage, parseTriageResponse, } from './triage.js';
|
|
19
|
+
export { groupClashes } from './grouping.js';
|
|
20
|
+
export { compareClashRuns } from './lifecycle.js';
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;GAQG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,GAIjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAsE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAqB,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAA0B,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clash lifecycle across model revisions (Phase 5).
|
|
3
|
+
*
|
|
4
|
+
* Compares two clash runs and partitions their clashes into added / resolved /
|
|
5
|
+
* persistent buckets. Matching is by the stable `clash.id`, which is durable
|
|
6
|
+
* across revisions because it derives from the elements' durable keys
|
|
7
|
+
* (IfcGUID / USD prim path) plus the rule id — not from runtime refs that
|
|
8
|
+
* change between loads. This makes the diff stable: a clash that survives a
|
|
9
|
+
* revision keeps its id and is reported as `persistent` rather than as a
|
|
10
|
+
* resolve-plus-add churn.
|
|
11
|
+
*/
|
|
12
|
+
import type { Clash, ClashResult } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* The result of comparing a previous clash run to a later ("next") one.
|
|
15
|
+
*
|
|
16
|
+
* - `added` clashes present in `next` but not in `previous` (new issues)
|
|
17
|
+
* - `persistent` clashes present in both runs (still open; the `next` Clash)
|
|
18
|
+
* - `resolved` clashes present in `previous` but not in `next` (fixed/removed)
|
|
19
|
+
*
|
|
20
|
+
* Each array is sorted by `clash.id` for deterministic, diff-friendly output.
|
|
21
|
+
*/
|
|
22
|
+
export interface ClashRevisionDiff {
|
|
23
|
+
added: Clash[];
|
|
24
|
+
persistent: Clash[];
|
|
25
|
+
resolved: Clash[];
|
|
26
|
+
summary: {
|
|
27
|
+
added: number;
|
|
28
|
+
persistent: number;
|
|
29
|
+
resolved: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Compare two clash runs and partition their clashes by lifecycle state.
|
|
34
|
+
*
|
|
35
|
+
* Pure and deterministic: the output depends only on the two inputs, never on
|
|
36
|
+
* the clock or any randomness. The `persistent` bucket returns the `next` run's
|
|
37
|
+
* Clash (the current geometry/point/distance for a still-open issue), so a
|
|
38
|
+
* caller can render the up-to-date state. Each array is sorted by id.
|
|
39
|
+
*/
|
|
40
|
+
export declare function compareClashRuns(previous: ClashResult, next: ClashResult): ClashRevisionDiff;
|
|
41
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAClE;AAyBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAsC5F"}
|
|
@@ -0,0 +1,70 @@
|
|
|
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
|
+
/** Stable string compare for ids (ASCII/Unicode code-point order). */
|
|
5
|
+
function byId(a, b) {
|
|
6
|
+
if (a.id < b.id)
|
|
7
|
+
return -1;
|
|
8
|
+
if (a.id > b.id)
|
|
9
|
+
return 1;
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Index a run's clashes by their stable id for O(1) membership checks. The
|
|
14
|
+
* engine dedups clash ids within a run, so ids are unique here. If a caller
|
|
15
|
+
* passed a hand-built run with a repeated id, the map keeps the last occurrence
|
|
16
|
+
* for membership tests, while the added/persistent/resolved buckets below
|
|
17
|
+
* iterate the raw clash arrays — so a duplicate id would appear once per
|
|
18
|
+
* occurrence in its bucket and in the counts.
|
|
19
|
+
*/
|
|
20
|
+
function indexById(run) {
|
|
21
|
+
const byKey = new Map();
|
|
22
|
+
for (const clash of run.clashes) {
|
|
23
|
+
byKey.set(clash.id, clash);
|
|
24
|
+
}
|
|
25
|
+
return byKey;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compare two clash runs and partition their clashes by lifecycle state.
|
|
29
|
+
*
|
|
30
|
+
* Pure and deterministic: the output depends only on the two inputs, never on
|
|
31
|
+
* the clock or any randomness. The `persistent` bucket returns the `next` run's
|
|
32
|
+
* Clash (the current geometry/point/distance for a still-open issue), so a
|
|
33
|
+
* caller can render the up-to-date state. Each array is sorted by id.
|
|
34
|
+
*/
|
|
35
|
+
export function compareClashRuns(previous, next) {
|
|
36
|
+
const prevById = indexById(previous);
|
|
37
|
+
const nextById = indexById(next);
|
|
38
|
+
const added = [];
|
|
39
|
+
const persistent = [];
|
|
40
|
+
const resolved = [];
|
|
41
|
+
for (const clash of next.clashes) {
|
|
42
|
+
if (prevById.has(clash.id)) {
|
|
43
|
+
// Present in both runs: still open. Report the next run's Clash so the
|
|
44
|
+
// caller sees current geometry, not the stale previous-revision copy.
|
|
45
|
+
persistent.push(clash);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
added.push(clash);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const clash of previous.clashes) {
|
|
52
|
+
if (!nextById.has(clash.id)) {
|
|
53
|
+
resolved.push(clash);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
added.sort(byId);
|
|
57
|
+
persistent.sort(byId);
|
|
58
|
+
resolved.sort(byId);
|
|
59
|
+
return {
|
|
60
|
+
added,
|
|
61
|
+
persistent,
|
|
62
|
+
resolved,
|
|
63
|
+
summary: {
|
|
64
|
+
added: added.length,
|
|
65
|
+
persistent: persistent.length,
|
|
66
|
+
resolved: resolved.length,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAgC/D,sEAAsE;AACtE,SAAS,IAAI,CAAC,CAAQ,EAAE,CAAQ;IAC9B,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,SAAS,CAAC,GAAgB;IACjC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiB,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAChC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAqB,EAAE,IAAiB;IACvE,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAEjC,MAAM,KAAK,GAAY,EAAE,CAAC;IAC1B,MAAM,UAAU,GAAY,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAY,EAAE,CAAC;IAE7B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3B,uEAAuE;YACvE,sEAAsE;YACtE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEpB,OAAO;QACL,KAAK;QACL,UAAU;QACV,QAAQ;QACR,OAAO,EAAE;YACP,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,UAAU,EAAE,UAAU,CAAC,MAAM;YAC7B,QAAQ,EAAE,QAAQ,CAAC,MAAM;SAC1B;KACF,CAAC;AACJ,CAAC"}
|