brepjs-bim 0.25.0 → 0.26.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.
@@ -9,8 +9,8 @@ import { BimError } from '../errors/bimError.js';
9
9
  * geometry (corner at 0,0,0).
10
10
  */
11
11
  export interface CurtainWallComponent {
12
- readonly origin: [number, number, number];
13
- readonly size: [number, number, number];
12
+ readonly origin: readonly [number, number, number];
13
+ readonly size: readonly [number, number, number];
14
14
  readonly solid: ValidSolid;
15
15
  }
16
16
  /** A curtain wall decomposed into glazing panels (plates) and mullions (members). */
@@ -18,15 +18,5 @@ export interface CurtainWallGrid {
18
18
  readonly panels: readonly CurtainWallComponent[];
19
19
  readonly mullions: readonly CurtainWallComponent[];
20
20
  }
21
- /**
22
- * Decomposes a curtain wall spec into its panel (plate) and mullion (member)
23
- * geometry. Mullions run along every vertical grid line (columns + 1 of them)
24
- * and every horizontal grid line (rows + 1); panels fill the cells between
25
- * adjacent mullions. The mullion section is centred on each grid line.
26
- *
27
- * Geometry is laid out in the wall's local frame: X across the wall, Z up, Y
28
- * through the depth. Each component's local-origin solid is returned alongside
29
- * its placement origin so the IFC writer can emit one IfcLocalPlacement per
30
- * component.
31
- */
21
+ /** Generate owned components, releasing every partial output on failure or failed temporary cleanup. */
32
22
  export declare function curtainWallToGrid(spec: CurtainWallSpec): Result<CurtainWallGrid, BimError>;
@@ -0,0 +1,8 @@
1
+ import { Result, ValidSolid } from 'brepjs';
2
+ import { BimError } from '../errors/bimError.js';
3
+ /** Borrow the host; retain one independent solid only after all temporary cleanup succeeds. */
4
+ export declare function cutOpeningSolid(input: {
5
+ readonly host: ValidSolid;
6
+ readonly makeTool: () => Result<ValidSolid, BimError>;
7
+ readonly hostKind: 'WALL' | 'SLAB';
8
+ }): Result<ValidSolid, BimError>;
@@ -2,11 +2,6 @@ import { ValidSolid, Result } from 'brepjs';
2
2
  import { AnyBimElement } from '../types/bimTypes.js';
3
3
  import { BimError } from '../errors/bimError.js';
4
4
  import { FrameInput } from '../placementFrame.js';
5
- export interface PlacedGeometryTestHooks {
6
- readonly afterPlaced?: ((solid: ValidSolid) => void) | undefined;
7
- }
8
- /** Package-internal deterministic failure seam for placement ownership tests. */
9
- export declare function setPlacedGeometryTestHooksForTesting(hooks: PlacedGeometryTestHooks | null): void;
10
5
  export interface PlacedSolidsOptions {
11
6
  /**
12
7
  * Cumulative frame of the element's containing spatial structure. Element
@@ -0,0 +1,7 @@
1
+ import { Result, Solid, ValidSolid } from 'brepjs';
2
+ import { BimError } from '../errors/bimError.js';
3
+ /** Validate a candidate already owned by the surrounding generation scope. */
4
+ export declare function validateGeneratedSolid(solid: Solid, context: {
5
+ readonly code: string;
6
+ readonly message: string;
7
+ }): Result<ValidSolid, BimError>;
@@ -15,9 +15,9 @@ export interface FamiliesToBimOptions {
15
15
  * returns FAMILIES_PRODUCT_BODY_EVALUATOR_REQUIRED with the element path and
16
16
  * mapped category, and does not fall back to a parametric envelope.
17
17
  * Conventional archetype walls and railings stay specification-authoritative
18
- * and do not require an evaluator. When present, civil walls and railings
19
- * compare the evaluated Body with their post-opening parametric Body and
20
- * retain the authored Body when they differ. Supplying this option does not
18
+ * and do not require an evaluator. Civil walls and railings always retain
19
+ * independent authored items as AUTHORITATIVE, including when coincident
20
+ * with the post-opening candidate. Supplying this option does not
21
21
  * opt unsupported products into the proxy fallback.
22
22
  */
23
23
  readonly bodyEvaluator?: csg.Evaluator | undefined;
@@ -1,40 +1,18 @@
1
- import { Result, Solid, ValidSolid, csg } from 'brepjs';
1
+ import { Result, csg } from 'brepjs';
2
2
  import { ResolvedElement } from 'brepjs-families';
3
3
  import { BimError } from './errors/bimError.js';
4
4
  import { ProductBody } from './types/productBody.js';
5
5
  import { RigidFrame } from './placementFrame.js';
6
- type ExactProductBody = Extract<ProductBody, {
7
- readonly kind: 'EXACT';
8
- }>;
9
- type ParametricProductBody = Extract<ProductBody, {
10
- readonly kind: 'PARAMETRIC';
11
- }>;
12
- export type CivilProductBodySelection = {
13
- readonly kind: 'PARAMETRIC';
14
- } | {
15
- readonly kind: 'EXACT';
16
- readonly body: ExactProductBody;
17
- };
18
6
  export interface CivilProductBodyInput {
19
7
  readonly element: ResolvedElement;
20
8
  readonly category: 'WALL' | 'RAILING';
21
9
  readonly evaluator: csg.Evaluator;
22
10
  readonly productWorldFrame: RigidFrame;
23
- /** Borrowed model-owned comparison candidate after registered openings. */
24
- readonly parametricBody: ParametricProductBody;
25
11
  }
26
- export interface FamiliesProductBodyTestHooks {
27
- readonly afterCopy?: ((itemIndex: number, solid: Solid, source: Solid) => void) | undefined;
28
- readonly beforeLocalize?: ((itemIndex: number, solid: ValidSolid) => void) | undefined;
29
- readonly afterLocalized?: ((itemIndex: number, solid: ValidSolid) => void) | undefined;
30
- readonly beforeCoincidence?: ((exact: ExactProductBody, parametric: ParametricProductBody) => void) | undefined;
31
- }
32
- /** Package-internal deterministic failure seams for exact ownership tests. */
33
- export declare function setFamiliesProductBodyTestHooksForTesting(hooks: FamiliesProductBodyTestHooks | null): void;
34
12
  /**
35
- * Evaluates a civil Product Body, clones and localizes every borrowed source,
36
- * then proves whether the registered-opening parametric Body is coincident.
37
- * An EXACT result is caller-owned until takeExactProductBody() succeeds.
13
+ * Borrow evaluator parents, then copy and inverse-localize in item order.
14
+ * Every successful result is AUTHORITATIVE and caller-owned until COMMITTED.
38
15
  */
39
- export declare function selectCivilProductBody(input: CivilProductBodyInput): Result<CivilProductBodySelection, BimError>;
40
- export {};
16
+ export declare function prepareCivilProductBody(input: CivilProductBodyInput): Result<Extract<ProductBody, {
17
+ kind: 'AUTHORITATIVE';
18
+ }>, BimError>;
@@ -0,0 +1,26 @@
1
+ import { Result } from 'brepjs';
2
+ import { BimError } from './errors/bimError.js';
3
+ import { CleanupReport, OwnedBodyResource } from './productBodyCleanup.js';
4
+ export type OwnGeneratedResource = <T extends Disposable>(resource: T) => T;
5
+ export interface UncertainGeneratedResource {
6
+ readonly handle: Disposable;
7
+ readonly resource: object | undefined;
8
+ readonly itemIndex: number;
9
+ }
10
+ export interface GeneratedResource extends OwnedBodyResource {
11
+ nativeResource: object | undefined;
12
+ }
13
+ /** Already-attempted resources, with identities captured before any release. Never retry them. */
14
+ export declare function uncertainGeneratedResources(error: BimError): readonly UncertainGeneratedResource[];
15
+ /** Item positions must be unique within this generator-owned cleanup group. */
16
+ export declare function failedResources(report: CleanupReport, owned: readonly GeneratedResource[]): readonly UncertainGeneratedResource[];
17
+ export declare function generationFailure(error: BimError, uncertain: readonly UncertainGeneratedResource[]): Result<never, BimError>;
18
+ /**
19
+ * A recipe owns every allocation until all temporary cleanup has succeeded.
20
+ * Register each fresh result before validation or another native call. Cleanup
21
+ * runs in reverse allocation order, once per resource, even if releases throw.
22
+ */
23
+ export declare function generateGeometry<T extends Disposable>(context: {
24
+ readonly operation: string;
25
+ readonly codePrefix: string;
26
+ }, build: (own: OwnGeneratedResource) => Result<T, BimError>): Result<T, BimError>;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- export { BimModel, type ElementIdentityOptions, type OpeningIdentityOptions, } from './model/bimModel.js';
1
+ export { BimModel, type BodyCommitReceipt, type ElementIdentityOptions, type OpeningIdentityOptions, } from './model/bimModel.js';
2
2
  export type { BimTreeNode, BimTreeSummary } from './model/treeSummary.js';
3
3
  export { placedSolids } from './elementFns/placedGeometry.js';
4
- export { bodySolids } from './types/productBody.js';
5
- export type { NonEmpty, ProductBody } from './types/productBody.js';
4
+ export { bodySolids, validateProductBody, copyProductBody, transformProductBody, productBodyBounds, measureProductBodyMaterial, disposeProductBody, } from './types/productBody.js';
5
+ export type { NonEmpty, ProductBody, ProductBodyError, ProductBodyOperation, ProductBodyBounds, ProductBodySpace, CleanupReport, GeometryCleanupDiagnostic, } from './types/productBody.js';
6
6
  export type { PlacedSolidsOptions } from './elementFns/placedGeometry.js';
7
- export type { FrameInput } from './placementFrame.js';
7
+ export type { FrameInput, RigidFrame, Mat4x4 } from './placementFrame.js';
8
+ export { frameFromPlacement, frameFromMatrix, frameMul, frameInverse, translationFrame, rotationFrame, IDENTITY_FRAME, } from './placementFrame.js';
8
9
  export { toIfc, toIfcValidated } from './serialize/toIfc.js';
9
10
  export type { ValidatedIfcResult } from './serialize/toIfc.js';
10
11
  export { setIfcWasmLocateFile } from './ifcRuntime.js';
@@ -1,4 +1,5 @@
1
1
  import { Result } from 'brepjs';
2
+ import { IfcGuid } from '../identity/ifcGuid.js';
2
3
  import { LocalId } from '../identity/localId.js';
3
4
  import { BimError } from '../errors/bimError.js';
4
5
  import { AnyBimElement, BimElement } from '../types/bimTypes.js';
@@ -25,6 +26,13 @@ import { SurfaceStyleSpec } from '../ifc-writer/styleWriter.js';
25
26
  import { ProjectSpec, SiteSpec, BuildingSpec, StoreySpec } from '../specs/spatialSpec.js';
26
27
  import { BridgePartSpec, BridgeSpec, EarthworksFillSpec } from '../specs/infrastructureSpec.js';
27
28
  import { ProductBody } from '../types/productBody.js';
29
+ import { CleanupReport, GeometryCleanupDiagnostic } from '../productBodyCleanup.js';
30
+ export interface BodyCommitReceipt {
31
+ readonly kind: 'COMMITTED';
32
+ readonly localId: LocalId;
33
+ readonly guid: IfcGuid;
34
+ readonly cleanup: CleanupReport;
35
+ }
28
36
  /** Optional identity override for created elements: a stable key (e.g. a
29
37
  * families key path) that replaces the positional GlobalId derivation. */
30
38
  export interface ElementIdentityOptions {
@@ -37,6 +45,7 @@ export interface OpeningIdentityOptions extends ElementIdentityOptions {
37
45
  }
38
46
  export declare class BimModel {
39
47
  #private;
48
+ getGeometryCleanupDiagnostics(): readonly GeometryCleanupDiagnostic[];
40
49
  init(spec: ProjectSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
41
50
  [Symbol.dispose](): void;
42
51
  addSite(spec: SiteSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
@@ -68,14 +77,11 @@ export declare class BimModel {
68
77
  */
69
78
  addRamp(spec: RampSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
70
79
  addRailing(spec: RailingSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
71
- /**
72
- * Atomically replaces a parametric wall or railing Body with authoritative,
73
- * caller-owned exact solids. Success transfers every supplied handle to this
74
- * model. Failure leaves both the model and all supplied handles unchanged.
75
- */
76
- takeExactProductBody(localId: LocalId, body: Extract<ProductBody, {
77
- readonly kind: 'EXACT';
78
- }>): Result<void, BimError>;
80
+ /** Ownership transfers only on COMMITTED, including when retirement reports failure. */
81
+ replaceProductBody(input: {
82
+ readonly localId: LocalId;
83
+ readonly body: ProductBody;
84
+ }): Result<BodyCommitReceipt, BimError>;
79
85
  /**
80
86
  * Adds an IfcCovering. When `hostLocalId` is supplied, an
81
87
  * IfcRelCoversBldgElements linking the covering to its host (e.g. a slab it
@@ -155,6 +161,8 @@ export declare class BimModel {
155
161
  placeIn(elementId: LocalId, containerId: LocalId): void;
156
162
  getProject(): BimElement<'PROJECT'> | null;
157
163
  getElement(id: LocalId): AnyBimElement | null;
164
+ /** Whether recipe commands still justify this element's recipe-derived quantities. */
165
+ isRecipeQuantityEligible(id: LocalId): boolean;
158
166
  /**
159
167
  * A serializable summary of the model's structure, rooted at the project and
160
168
  * walking the IFC spatial hierarchy (AGGREGATES: project → site → building →
@@ -0,0 +1,10 @@
1
+ import { Result, ValidSolid } from 'brepjs';
2
+ import { BimError } from '../errors/bimError.js';
3
+ import { AnyBimElement, BimCategory, BimElement } from '../types/bimTypes.js';
4
+ export type ElementFields = {
5
+ [C in BimCategory]: Pick<BimElement<C>, 'category' | 'spec' | 'geometry'>;
6
+ }[BimCategory];
7
+ /** Transitional enumeration of current record storage. Step 2 converges these forms. */
8
+ export declare function retainedSolids(element: ElementFields): readonly ValidSolid[];
9
+ /** Snapshot ownership-bearing descriptors only; never freeze or clone native handles. */
10
+ export declare function protectElement(element: AnyBimElement): Result<AnyBimElement, BimError>;
@@ -0,0 +1,7 @@
1
+ import { getKernel, Solid } from 'brepjs';
2
+ interface ExtractedSolidOwner extends Disposable {
3
+ readonly wrapped: Parameters<ReturnType<typeof getKernel>['dispose']>[0];
4
+ }
5
+ /** Register every eager iterator allocation before wrapping any child. */
6
+ export declare function ownSolidChildren(parent: Solid['wrapped'], own: (resource: ExtractedSolidOwner, itemIndex: number) => void): readonly Solid[];
7
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { BimError } from './errors/bimError.js';
2
2
  import { Result, ValidSolid, measureVolume, getBounds } from 'brepjs';
3
- export type BodyNativeStep = 'validate' | 'union' | 'measure' | 'bounds';
3
+ export type BodyNativeStep = 'validate' | 'copy' | 'transform' | 'union' | 'measure' | 'bounds';
4
4
  export interface BodyNativeEvent {
5
5
  readonly step: BodyNativeStep;
6
6
  readonly itemIndex: number;
@@ -1,4 +1,6 @@
1
- import { AnyShape, Dimension } from 'brepjs';
1
+ import { AnyShape, Dimension, ComposedTransform } from 'brepjs';
2
2
  import { RigidFrame } from './placementFrame.js';
3
3
  /** Applies a rigid placement as a location so the source BRep is not rebuilt. */
4
4
  export declare function locateShapeInFrame<T extends AnyShape<Dimension>>(shape: T, frame: RigidFrame): T;
5
+ /** The caller owns this temporary and must observe any failure from its cleanup. */
6
+ export declare function composeFrameTransform(frame: RigidFrame): ComposedTransform;
@@ -1,29 +1,67 @@
1
+ import { z } from 'zod';
1
2
  import { Bounds3D, Result, ValidSolid } from 'brepjs';
2
3
  import { BimError } from '../errors/bimError.js';
4
+ import { RigidFrame } from '../placementFrame.js';
3
5
  import { CleanupReport } from '../productBodyCleanup.js';
6
+ export type { CleanupReport, GeometryCleanupDiagnostic } from '../productBodyCleanup.js';
4
7
  export type NonEmpty<T> = readonly [T, ...T[]];
5
8
  export type ProductBody = {
6
9
  readonly kind: 'PARAMETRIC';
7
- readonly solid: ValidSolid;
10
+ readonly solids: NonEmpty<ValidSolid>;
8
11
  } | {
9
- readonly kind: 'EXACT';
12
+ readonly kind: 'AUTHORITATIVE';
10
13
  readonly solids: NonEmpty<ValidSolid>;
11
14
  };
12
- /** Returns borrowed Product-local solids. The model retains ownership. */
13
- export declare function bodySolids(body: ProductBody): NonEmpty<ValidSolid>;
14
- /** Model-owner cleanup. Borrowers must use {@link bodySolids} without disposing its items. */
15
- export declare function disposeProductBody(body: ProductBody): void;
16
- export type ProductBodyOperation = 'productBodyBounds' | 'measureProductBodyMaterial';
15
+ export type ProductBodyOperation = 'validateProductBody' | 'copyProductBody' | 'transformProductBody' | 'productBodyBounds' | 'measureProductBodyMaterial';
17
16
  export interface ProductBodyError extends BimError {
18
17
  readonly operation: ProductBodyOperation;
19
18
  readonly itemIndex?: number;
20
19
  readonly cleanup: CleanupReport;
21
20
  }
21
+ export type ProductBodySpace = {
22
+ readonly kind: 'LOCAL';
23
+ } | {
24
+ readonly kind: 'RESOLVED';
25
+ readonly tag: string;
26
+ readonly frame: RigidFrame;
27
+ };
28
+ export interface ProductBodyBounds {
29
+ readonly space: {
30
+ readonly kind: 'LOCAL';
31
+ } | {
32
+ readonly kind: 'RESOLVED';
33
+ readonly tag: string;
34
+ };
35
+ readonly bounds: Readonly<Bounds3D>;
36
+ }
37
+ declare const descriptorSchema: z.ZodObject<{
38
+ kind: z.ZodEnum<{
39
+ PARAMETRIC: "PARAMETRIC";
40
+ AUTHORITATIVE: "AUTHORITATIVE";
41
+ }>;
42
+ solids: z.ZodCustom<readonly unknown[], readonly unknown[]>;
43
+ }, z.core.$strip>;
22
44
  /** @internal Exact resource object identity only, without native topology queries. */
23
45
  export declare function wrappedResourceObject(solid: unknown): object | undefined;
46
+ /** @internal Capture opaque items before any native query, so owners can reject retired aliases. */
47
+ export declare function snapshotProductBodyInput(input: unknown): Result<z.infer<typeof descriptorSchema>, ProductBodyError>;
48
+ /** Borrow only. Reject duplicate handles and exact wrapped resource objects.
49
+ * Independent copies may share topology. Other external aliases remain a caller
50
+ * ownership precondition; rejection does not disable an alias's disposer/finalizer.
51
+ * Freezing a descriptor/collection neither clones nor transfers native handles.
52
+ */
53
+ export declare function validateProductBody(input: unknown): Result<ProductBody, ProductBodyError>;
54
+ /** Borrow protected Product-local items. Borrowers must not dispose the retained handles. */
55
+ export declare function bodySolids(body: ProductBody): NonEmpty<ValidSolid>;
56
+ /** Owner-only cleanup. COMPLETE means no failure was observable at the BIM boundary.
57
+ * A FAILED release must not be retried: its native-release outcome can be unknown.
58
+ */
59
+ export declare function disposeProductBody(body: ProductBody): CleanupReport;
60
+ /** Borrow a Body; return a fresh independently owned copy with unchanged authority/order. */
61
+ export declare function copyProductBody(body: ProductBody): Result<ProductBody, ProductBodyError>;
62
+ /** Borrow inputs; even identity placement returns fresh, independently disposable items. */
63
+ export declare function transformProductBody(body: ProductBody, frame: RigidFrame): Result<ProductBody, ProductBodyError>;
24
64
  /** Occupied material in mm³. Borrowed imported items need no authored Body descriptor. */
25
65
  export declare function measureProductBodyMaterial(solids: NonEmpty<ValidSolid>): Result<number, ProductBodyError>;
26
- /** Borrow all items and query their tight bounds in their existing coordinates. */
27
- export declare function productBodyBounds(solids: NonEmpty<ValidSolid>): Result<{
28
- readonly bounds: Readonly<Bounds3D>;
29
- }, ProductBodyError>;
66
+ /** All-item tight bounds. A resolved tag belongs to the caller, not a document identity. */
67
+ export declare function productBodyBounds(body: ProductBody | NonEmpty<ValidSolid>, space?: ProductBodySpace): Result<ProductBodyBounds, ProductBodyError>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs-bim",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "BIM layer for brepjs — IFC4-aligned parametric building elements",
5
5
  "keywords": [
6
6
  "bim",
@@ -44,7 +44,8 @@
44
44
  "typecheck": "tsgo --noEmit",
45
45
  "test": "vitest run",
46
46
  "test:coverage": "vitest run --coverage",
47
- "lint": "eslint src tests"
47
+ "lint": "eslint src tests",
48
+ "typecheck:consumers": "tsgo -p tsconfig.test.json --noEmit"
48
49
  },
49
50
  "peerDependencies": {
50
51
  "brepjs": ">=19.0.5",