@bitbybit-dev/ifc 0.0.0-stage → 1.5.0-rc.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 +21 -0
- package/NOTICE +42 -0
- package/README.md +92 -2
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/lib/api/dto-registry.d.ts +8 -0
- package/lib/api/dto-registry.js +109 -0
- package/lib/api/ifc-service.d.ts +109 -0
- package/lib/api/ifc-service.js +55 -0
- package/lib/api/inputs/base-inputs.d.ts +5 -0
- package/lib/api/inputs/base-inputs.js +5 -0
- package/lib/api/inputs/ifc-inputs.d.ts +2727 -0
- package/lib/api/inputs/ifc-inputs.js +2498 -0
- package/lib/api/inputs/index.d.ts +3 -0
- package/lib/api/inputs/index.js +3 -0
- package/lib/api/resolved-inputs/index.d.ts +70 -0
- package/lib/api/resolved-inputs/index.js +1 -0
- package/lib/api/services/assemblies.d.ts +28 -0
- package/lib/api/services/assemblies.js +49 -0
- package/lib/api/services/beams.d.ts +33 -0
- package/lib/api/services/beams.js +59 -0
- package/lib/api/services/columns.d.ts +26 -0
- package/lib/api/services/columns.js +56 -0
- package/lib/api/services/defaults.constants.d.ts +44 -0
- package/lib/api/services/defaults.constants.js +44 -0
- package/lib/api/services/doors.d.ts +45 -0
- package/lib/api/services/doors.js +94 -0
- package/lib/api/services/geometry.d.ts +51 -0
- package/lib/api/services/geometry.js +87 -0
- package/lib/api/services/index.d.ts +17 -0
- package/lib/api/services/index.js +17 -0
- package/lib/api/services/materials.d.ts +46 -0
- package/lib/api/services/materials.js +86 -0
- package/lib/api/services/member-support.d.ts +7 -0
- package/lib/api/services/member-support.js +29 -0
- package/lib/api/services/members.d.ts +24 -0
- package/lib/api/services/members.js +51 -0
- package/lib/api/services/model.d.ts +244 -0
- package/lib/api/services/model.js +409 -0
- package/lib/api/services/openings.d.ts +57 -0
- package/lib/api/services/openings.js +102 -0
- package/lib/api/services/properties.d.ts +89 -0
- package/lib/api/services/properties.js +142 -0
- package/lib/api/services/quantities.d.ts +38 -0
- package/lib/api/services/quantities.js +51 -0
- package/lib/api/services/roofs.d.ts +24 -0
- package/lib/api/services/roofs.js +52 -0
- package/lib/api/services/service-support.d.ts +8 -0
- package/lib/api/services/service-support.js +37 -0
- package/lib/api/services/service-types.d.ts +3 -0
- package/lib/api/services/service-types.js +1 -0
- package/lib/api/services/site.d.ts +37 -0
- package/lib/api/services/site.js +80 -0
- package/lib/api/services/slabs.d.ts +31 -0
- package/lib/api/services/slabs.js +59 -0
- package/lib/api/services/spaces.d.ts +36 -0
- package/lib/api/services/spaces.js +64 -0
- package/lib/api/services/spatial.d.ts +54 -0
- package/lib/api/services/spatial.js +75 -0
- package/lib/api/services/walls.d.ts +140 -0
- package/lib/api/services/walls.js +268 -0
- package/lib/api/services/windows.d.ts +46 -0
- package/lib/api/services/windows.js +76 -0
- package/lib/build/assemblies.d.ts +4 -0
- package/lib/build/assemblies.js +45 -0
- package/lib/build/build-types.d.ts +345 -0
- package/lib/build/build-types.js +1 -0
- package/lib/build/checks.d.ts +6 -0
- package/lib/build/checks.js +32 -0
- package/lib/build/constants.d.ts +27 -0
- package/lib/build/constants.js +43 -0
- package/lib/build/contexts.d.ts +9 -0
- package/lib/build/contexts.js +52 -0
- package/lib/build/curves.d.ts +3 -0
- package/lib/build/curves.js +23 -0
- package/lib/build/entity-writer.d.ts +23 -0
- package/lib/build/entity-writer.js +97 -0
- package/lib/build/fillings.d.ts +7 -0
- package/lib/build/fillings.js +182 -0
- package/lib/build/georeference.d.ts +5 -0
- package/lib/build/georeference.js +44 -0
- package/lib/build/materials.d.ts +18 -0
- package/lib/build/materials.js +166 -0
- package/lib/build/math.d.ts +10 -0
- package/lib/build/math.js +47 -0
- package/lib/build/measure.d.ts +9 -0
- package/lib/build/measure.js +195 -0
- package/lib/build/moving.d.ts +4 -0
- package/lib/build/moving.js +61 -0
- package/lib/build/openings.d.ts +12 -0
- package/lib/build/openings.js +156 -0
- package/lib/build/outlines.d.ts +4 -0
- package/lib/build/outlines.js +40 -0
- package/lib/build/placement.d.ts +16 -0
- package/lib/build/placement.js +106 -0
- package/lib/build/profiles.d.ts +4 -0
- package/lib/build/profiles.js +35 -0
- package/lib/build/project.d.ts +11 -0
- package/lib/build/project.js +134 -0
- package/lib/build/properties.d.ts +10 -0
- package/lib/build/properties.js +182 -0
- package/lib/build/quantities.d.ts +7 -0
- package/lib/build/quantities.js +262 -0
- package/lib/build/relationships.d.ts +9 -0
- package/lib/build/relationships.js +67 -0
- package/lib/build/removal.d.ts +3 -0
- package/lib/build/removal.js +106 -0
- package/lib/build/representations.d.ts +6 -0
- package/lib/build/representations.js +46 -0
- package/lib/build/roof-clipping.d.ts +5 -0
- package/lib/build/roof-clipping.js +79 -0
- package/lib/build/roofs.d.ts +4 -0
- package/lib/build/roofs.js +131 -0
- package/lib/build/site.d.ts +7 -0
- package/lib/build/site.js +112 -0
- package/lib/build/slab-openings.d.ts +4 -0
- package/lib/build/slab-openings.js +71 -0
- package/lib/build/slabs-columns-beams.d.ts +8 -0
- package/lib/build/slabs-columns-beams.js +73 -0
- package/lib/build/solids.d.ts +5 -0
- package/lib/build/solids.js +33 -0
- package/lib/build/spaces.d.ts +6 -0
- package/lib/build/spaces.js +55 -0
- package/lib/build/spatial.d.ts +17 -0
- package/lib/build/spatial.js +111 -0
- package/lib/build/type-objects.d.ts +4 -0
- package/lib/build/type-objects.js +9 -0
- package/lib/build/wall-edits.d.ts +5 -0
- package/lib/build/wall-edits.js +138 -0
- package/lib/build/wall-geometry.d.ts +15 -0
- package/lib/build/wall-geometry.js +159 -0
- package/lib/build/wall-parameters.d.ts +3 -0
- package/lib/build/wall-parameters.js +47 -0
- package/lib/build/walls.d.ts +12 -0
- package/lib/build/walls.js +238 -0
- package/lib/geometry/advanced.d.ts +27 -0
- package/lib/geometry/advanced.js +292 -0
- package/lib/geometry/colours.d.ts +3 -0
- package/lib/geometry/colours.js +109 -0
- package/lib/geometry/curves.d.ts +32 -0
- package/lib/geometry/curves.js +370 -0
- package/lib/geometry/edges.constants.d.ts +5 -0
- package/lib/geometry/edges.constants.js +5 -0
- package/lib/geometry/edges.d.ts +21 -0
- package/lib/geometry/edges.js +164 -0
- package/lib/geometry/elements.d.ts +3 -0
- package/lib/geometry/elements.js +152 -0
- package/lib/geometry/errors.d.ts +3 -0
- package/lib/geometry/errors.js +6 -0
- package/lib/geometry/faceted.d.ts +31 -0
- package/lib/geometry/faceted.js +214 -0
- package/lib/geometry/geometry-types.d.ts +103 -0
- package/lib/geometry/geometry-types.js +1 -0
- package/lib/geometry/groups.d.ts +21 -0
- package/lib/geometry/groups.js +106 -0
- package/lib/geometry/items.d.ts +34 -0
- package/lib/geometry/items.js +313 -0
- package/lib/geometry/operators.d.ts +3 -0
- package/lib/geometry/operators.js +65 -0
- package/lib/geometry/profiles.d.ts +4 -0
- package/lib/geometry/profiles.js +277 -0
- package/lib/geometry/recipe-builder.d.ts +14 -0
- package/lib/geometry/recipe-builder.js +48 -0
- package/lib/geometry/references.d.ts +4 -0
- package/lib/geometry/references.js +17 -0
- package/lib/geometry/regions.d.ts +4 -0
- package/lib/geometry/regions.js +26 -0
- package/lib/geometry/surfaces.constants.d.ts +17 -0
- package/lib/geometry/surfaces.constants.js +17 -0
- package/lib/geometry/surfaces.d.ts +6 -0
- package/lib/geometry/surfaces.js +306 -0
- package/lib/geometry/swept-solids.constants.d.ts +7 -0
- package/lib/geometry/swept-solids.constants.js +6 -0
- package/lib/geometry/swept-solids.d.ts +25 -0
- package/lib/geometry/swept-solids.js +243 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/model/constants.d.ts +30 -0
- package/lib/model/constants.js +30 -0
- package/lib/model/entity-lookup.d.ts +9 -0
- package/lib/model/entity-lookup.js +20 -0
- package/lib/model/guid.d.ts +7 -0
- package/lib/model/guid.js +60 -0
- package/lib/model/id-map.d.ts +10 -0
- package/lib/model/id-map.js +80 -0
- package/lib/model/index.d.ts +4 -0
- package/lib/model/index.js +2 -0
- package/lib/model/io.d.ts +6 -0
- package/lib/model/io.js +136 -0
- package/lib/model/is-model.d.ts +9 -0
- package/lib/model/is-model.js +11 -0
- package/lib/model/model-types.d.ts +111 -0
- package/lib/model/model-types.js +1 -0
- package/lib/model/overlay-indexes.d.ts +17 -0
- package/lib/model/overlay-indexes.js +69 -0
- package/lib/model/references.d.ts +2 -0
- package/lib/model/references.js +51 -0
- package/lib/model/rows-by-id.d.ts +8 -0
- package/lib/model/rows-by-id.js +39 -0
- package/lib/model/snapshot.d.ts +36 -0
- package/lib/model/snapshot.js +144 -0
- package/lib/model/source.d.ts +29 -0
- package/lib/model/source.js +172 -0
- package/lib/model/transaction.d.ts +39 -0
- package/lib/model/transaction.js +250 -0
- package/lib/model/upgrade.d.ts +2 -0
- package/lib/model/upgrade.js +78 -0
- package/lib/schema/constants.d.ts +3 -0
- package/lib/schema/constants.js +3 -0
- package/lib/schema/generated/ifc4.d.ts +2 -0
- package/lib/schema/generated/ifc4.js +1204 -0
- package/lib/schema/generated/ifc4x3.d.ts +2 -0
- package/lib/schema/generated/ifc4x3.js +1325 -0
- package/lib/schema/registry.d.ts +7 -0
- package/lib/schema/registry.js +37 -0
- package/lib/schema/schema-types.d.ts +45 -0
- package/lib/schema/schema-types.js +1 -0
- package/lib/schema/schema.d.ts +23 -0
- package/lib/schema/schema.js +136 -0
- package/lib/step/constants.d.ts +48 -0
- package/lib/step/constants.js +48 -0
- package/lib/step/encoder.d.ts +21 -0
- package/lib/step/encoder.js +321 -0
- package/lib/step/errors.d.ts +39 -0
- package/lib/step/errors.js +45 -0
- package/lib/step/file-index.d.ts +2 -0
- package/lib/step/file-index.js +221 -0
- package/lib/step/header.d.ts +4 -0
- package/lib/step/header.js +52 -0
- package/lib/step/numbers.d.ts +3 -0
- package/lib/step/numbers.js +73 -0
- package/lib/step/reader.d.ts +2 -0
- package/lib/step/reader.js +160 -0
- package/lib/step/scanner.d.ts +13 -0
- package/lib/step/scanner.js +203 -0
- package/lib/step/step-types.d.ts +170 -0
- package/lib/step/step-types.js +1 -0
- package/lib/step/strings.d.ts +2 -0
- package/lib/step/strings.js +150 -0
- package/lib/step/values.d.ts +13 -0
- package/lib/step/values.js +51 -0
- package/package.json +51 -5
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Base } from "@bitbybit-dev/base";
|
|
2
|
+
import type { IfcAttributes } from "../model/model-types";
|
|
3
|
+
import type { IfcTransaction } from "../model/transaction";
|
|
4
|
+
import type { Outline2 } from "./build-types";
|
|
5
|
+
import type { Frame3 } from "./build-types";
|
|
6
|
+
export declare class EntityWriter {
|
|
7
|
+
readonly tx: IfcTransaction;
|
|
8
|
+
constructor(tx: IfcTransaction);
|
|
9
|
+
create(type: string, attributes?: IfcAttributes): number;
|
|
10
|
+
point(point: Base.Point2 | Base.Point3): number;
|
|
11
|
+
direction(vector: Base.Vector2 | Base.Vector3): number;
|
|
12
|
+
placement3(frame: Frame3): number;
|
|
13
|
+
placement2(origin: Base.Point2, xAxis?: Base.Vector2): number;
|
|
14
|
+
localPlacement(relativeTo: number | undefined, frame: Frame3): number;
|
|
15
|
+
polyCurve2(points: readonly Base.Point2[], closed: boolean): number;
|
|
16
|
+
profile(outline: Outline2, name?: string): number;
|
|
17
|
+
extrusion(profile: number, position: Frame3, depth: number, direction?: Base.Vector3): number;
|
|
18
|
+
shapeRepresentation(context: number, identifier: string, type: string, items: readonly number[]): number;
|
|
19
|
+
productShape(representations: readonly number[]): number;
|
|
20
|
+
halfSpace(origin: Base.Point3, normal: Base.Vector3, xHint: Base.Vector3): number;
|
|
21
|
+
clipping(first: number, second: number): number;
|
|
22
|
+
}
|
|
23
|
+
export declare function planeFrame(origin: Base.Point3, normal: Base.Vector3, xHint: Base.Vector3): Frame3;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { dot3, length3, scale3, subtract3 } from "@bitbybit-dev/base/lib/api/services/helpers/vectors";
|
|
2
|
+
import { enumValue, ref } from "../step/values";
|
|
3
|
+
import { frameFrom, normalize3 } from "./math";
|
|
4
|
+
const AXIS_TOLERANCE = 1e-12;
|
|
5
|
+
function isUnit(vector, axis) {
|
|
6
|
+
return vector.every((value, index) => Math.abs(value - (index === axis ? 1 : 0)) <= AXIS_TOLERANCE);
|
|
7
|
+
}
|
|
8
|
+
function coordinates(values) {
|
|
9
|
+
return values.map((value) => (Object.is(value, -0) ? 0 : value));
|
|
10
|
+
}
|
|
11
|
+
export class EntityWriter {
|
|
12
|
+
constructor(tx) {
|
|
13
|
+
this.tx = tx;
|
|
14
|
+
}
|
|
15
|
+
create(type, attributes = {}) {
|
|
16
|
+
return this.tx.create(type, attributes);
|
|
17
|
+
}
|
|
18
|
+
point(point) {
|
|
19
|
+
return this.create("IfcCartesianPoint", { Coordinates: coordinates(point) });
|
|
20
|
+
}
|
|
21
|
+
direction(vector) {
|
|
22
|
+
return this.create("IfcDirection", { DirectionRatios: coordinates(vector) });
|
|
23
|
+
}
|
|
24
|
+
placement3(frame) {
|
|
25
|
+
const standardAxes = isUnit(frame.z, 2) && isUnit(frame.x, 0);
|
|
26
|
+
return this.create("IfcAxis2Placement3D", {
|
|
27
|
+
Location: ref(this.point(frame.origin)),
|
|
28
|
+
Axis: standardAxes ? null : ref(this.direction(frame.z)),
|
|
29
|
+
RefDirection: standardAxes ? null : ref(this.direction(frame.x)),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
placement2(origin, xAxis) {
|
|
33
|
+
return this.create("IfcAxis2Placement2D", {
|
|
34
|
+
Location: ref(this.point(origin)),
|
|
35
|
+
RefDirection: xAxis === undefined ? null : ref(this.direction(xAxis)),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
localPlacement(relativeTo, frame) {
|
|
39
|
+
return this.create("IfcLocalPlacement", {
|
|
40
|
+
PlacementRelTo: relativeTo === undefined ? null : ref(relativeTo),
|
|
41
|
+
RelativePlacement: ref(this.placement3(frame)),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
polyCurve2(points, closed) {
|
|
45
|
+
const list = this.create("IfcCartesianPointList2D", { CoordList: points.map((point) => coordinates(point)) });
|
|
46
|
+
const indices = points.map((_, index) => index + 1);
|
|
47
|
+
return this.create("IfcIndexedPolyCurve", {
|
|
48
|
+
Points: ref(list),
|
|
49
|
+
Segments: [{ type: "IfcLineIndex", value: closed ? [...indices, 1] : indices }],
|
|
50
|
+
SelfIntersect: false,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
profile(outline, name) {
|
|
54
|
+
const outer = ref(this.polyCurve2(outline.outer, true));
|
|
55
|
+
if (!outline.holes.length) {
|
|
56
|
+
return this.create("IfcArbitraryClosedProfileDef", { ProfileType: enumValue("AREA"), ProfileName: name !== null && name !== void 0 ? name : null, OuterCurve: outer });
|
|
57
|
+
}
|
|
58
|
+
return this.create("IfcArbitraryProfileDefWithVoids", {
|
|
59
|
+
ProfileType: enumValue("AREA"),
|
|
60
|
+
ProfileName: name !== null && name !== void 0 ? name : null,
|
|
61
|
+
OuterCurve: outer,
|
|
62
|
+
InnerCurves: outline.holes.map((hole) => ref(this.polyCurve2(hole, true))),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
extrusion(profile, position, depth, direction = [0, 0, 1]) {
|
|
66
|
+
return this.create("IfcExtrudedAreaSolid", {
|
|
67
|
+
SweptArea: ref(profile),
|
|
68
|
+
Position: ref(this.placement3(position)),
|
|
69
|
+
ExtrudedDirection: ref(this.direction(direction)),
|
|
70
|
+
Depth: depth,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
shapeRepresentation(context, identifier, type, items) {
|
|
74
|
+
return this.create("IfcShapeRepresentation", {
|
|
75
|
+
ContextOfItems: ref(context),
|
|
76
|
+
RepresentationIdentifier: identifier,
|
|
77
|
+
RepresentationType: type,
|
|
78
|
+
Items: items.map(ref),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
productShape(representations) {
|
|
82
|
+
return this.create("IfcProductDefinitionShape", { Representations: representations.map(ref) });
|
|
83
|
+
}
|
|
84
|
+
halfSpace(origin, normal, xHint) {
|
|
85
|
+
const plane = this.create("IfcPlane", { Position: ref(this.placement3(planeFrame(origin, normal, xHint))) });
|
|
86
|
+
return this.create("IfcHalfSpaceSolid", { BaseSurface: ref(plane), AgreementFlag: false });
|
|
87
|
+
}
|
|
88
|
+
clipping(first, second) {
|
|
89
|
+
return this.create("IfcBooleanClippingResult", { Operator: enumValue("DIFFERENCE"), FirstOperand: ref(first), SecondOperand: ref(second) });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export function planeFrame(origin, normal, xHint) {
|
|
93
|
+
const z = normalize3(normal);
|
|
94
|
+
const projected = subtract3(xHint, scale3(z, dot3(xHint, z)));
|
|
95
|
+
const fallback = Math.abs(z[0]) < Math.abs(z[1]) ? [1, 0, 0] : [0, 1, 0];
|
|
96
|
+
return frameFrom(origin, z, length3(projected) > AXIS_TOLERANCE ? projected : fallback);
|
|
97
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IfcTransaction } from "../model/transaction";
|
|
2
|
+
import type { DoorTypeSpec, FillingSpec, ModelReader, TypeBounds, WindowTypeSpec } from "./build-types";
|
|
3
|
+
import type { EntityWriter } from "./entity-writer";
|
|
4
|
+
export declare function createDoorType(tx: IfcTransaction, writer: EntityWriter, spec: DoorTypeSpec): number;
|
|
5
|
+
export declare function createWindowType(tx: IfcTransaction, writer: EntityWriter, spec: WindowTypeSpec): number;
|
|
6
|
+
export declare function typeBounds(reader: ModelReader, type: number, map: number): TypeBounds;
|
|
7
|
+
export declare function createFilling(tx: IfcTransaction, writer: EntityWriter, kind: "IfcDoor" | "IfcWindow", spec: FillingSpec, tolerance: number): number;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { WORLD_AXES, pointToWorld } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
|
|
2
|
+
import { enumValue, isList, isReference, ref } from "../step/values";
|
|
3
|
+
import { requirePositive } from "./checks";
|
|
4
|
+
import { bodyContext } from "./contexts";
|
|
5
|
+
import { extrusionCorners, frameOf } from "./solids";
|
|
6
|
+
import { dressParts, materialsOfParts } from "./materials";
|
|
7
|
+
import { createWallOpening } from "./openings";
|
|
8
|
+
import { containIn, containerOf, describeObject } from "./spatial";
|
|
9
|
+
import { declareInProject, defineByType } from "./type-objects";
|
|
10
|
+
import * as Inputs from "../api/inputs";
|
|
11
|
+
const RIGHT_HINGE = "_RIGHT";
|
|
12
|
+
const PULL_BAR_SHARE_OF_HEIGHT = 0.45;
|
|
13
|
+
function box(writer, min, max) {
|
|
14
|
+
const width = max[0] - min[0];
|
|
15
|
+
const depth = max[1] - min[1];
|
|
16
|
+
const profile = writer.create("IfcRectangleProfileDef", {
|
|
17
|
+
ProfileType: enumValue("AREA"),
|
|
18
|
+
Position: ref(writer.placement2([min[0] + width / 2, min[1] + depth / 2])),
|
|
19
|
+
XDim: width,
|
|
20
|
+
YDim: depth,
|
|
21
|
+
});
|
|
22
|
+
return writer.extrusion(profile, Object.assign(Object.assign({}, WORLD_AXES), { origin: [0, 0, min[2]] }), max[2] - min[2]);
|
|
23
|
+
}
|
|
24
|
+
function positiveSizes(sizes) {
|
|
25
|
+
Object.entries(sizes).forEach(([name, value]) => requirePositive(value, name));
|
|
26
|
+
}
|
|
27
|
+
function handleEdge(spec) {
|
|
28
|
+
const reach = spec.liningThickness + spec.hardware.inset;
|
|
29
|
+
return spec.operation.endsWith(RIGHT_HINGE) ? reach : spec.width - reach;
|
|
30
|
+
}
|
|
31
|
+
function handleItems(writer, spec, panelFront) {
|
|
32
|
+
if (spec.handle === Inputs.IFC.doorHandleEnum.none) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const size = spec.hardware;
|
|
36
|
+
const edge = handleEdge(spec);
|
|
37
|
+
const inwards = edge < spec.width / 2 ? 1 : -1;
|
|
38
|
+
const outwardOf = (face, side, from, to) => {
|
|
39
|
+
const ends = [face + side * from, face + side * to];
|
|
40
|
+
return [Math.min(...ends), Math.max(...ends)];
|
|
41
|
+
};
|
|
42
|
+
const items = [];
|
|
43
|
+
for (const [face, side] of [[panelFront, -1], [panelFront + spec.panelThickness, 1]]) {
|
|
44
|
+
if (spec.handle === Inputs.IFC.doorHandleEnum.lever) {
|
|
45
|
+
const z = Math.min(size.leverHeight, spec.height - spec.liningThickness - size.leverSection);
|
|
46
|
+
const [neckFrom, neckTo] = outwardOf(face, side, 0, size.leverStandoff);
|
|
47
|
+
const [barFrom, barTo] = outwardOf(face, side, size.leverStandoff, size.leverStandoff + size.leverSection);
|
|
48
|
+
const [x0, x1] = [edge - inwards * size.leverSection / 2, edge + inwards * size.leverLength].sort((a, b) => a - b);
|
|
49
|
+
items.push(box(writer, [edge - size.leverSection / 2, neckFrom, z - size.leverSection / 2], [edge + size.leverSection / 2, neckTo, z + size.leverSection / 2]));
|
|
50
|
+
items.push(box(writer, [x0, barFrom, z - size.leverSection / 2], [x1, barTo, z + size.leverSection / 2]));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const length = Math.min(size.pullBarLength, spec.height * PULL_BAR_SHARE_OF_HEIGHT);
|
|
54
|
+
const middle = Math.min(size.pullBarMiddle, spec.height / 2);
|
|
55
|
+
const [postFrom, postTo] = outwardOf(face, side, 0, size.pullBarStandoff);
|
|
56
|
+
const [barFrom, barTo] = outwardOf(face, side, size.pullBarStandoff, size.pullBarStandoff + size.pullBarSection);
|
|
57
|
+
for (const end of [-1, 1]) {
|
|
58
|
+
const z = middle + end * (length / 2 - size.pullBarPostInset);
|
|
59
|
+
items.push(box(writer, [edge - size.pullBarPost / 2, postFrom, z - size.pullBarPost / 2], [edge + size.pullBarPost / 2, postTo, z + size.pullBarPost / 2]));
|
|
60
|
+
}
|
|
61
|
+
items.push(box(writer, [edge - size.pullBarSection / 2, barFrom, middle - length / 2], [edge + size.pullBarSection / 2, barTo, middle + length / 2]));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return items;
|
|
65
|
+
}
|
|
66
|
+
function representationMap(writer, items) {
|
|
67
|
+
const body = writer.shapeRepresentation(bodyContext(writer.tx, writer), "Body", "SweptSolid", items);
|
|
68
|
+
return writer.create("IfcRepresentationMap", { MappingOrigin: ref(writer.placement3(WORLD_AXES)), MappedRepresentation: ref(body) });
|
|
69
|
+
}
|
|
70
|
+
export function createDoorType(tx, writer, spec) {
|
|
71
|
+
positiveSizes({ width: spec.width, height: spec.height, "lining thickness": spec.liningThickness, "lining depth": spec.liningDepth, "panel thickness": spec.panelThickness });
|
|
72
|
+
const lining = spec.liningThickness;
|
|
73
|
+
if (2 * lining >= spec.width || lining >= spec.height || spec.panelThickness > spec.liningDepth) {
|
|
74
|
+
throw new Error("The door's lining and panel do not fit inside its width, height and depth");
|
|
75
|
+
}
|
|
76
|
+
const panelFront = (spec.liningDepth - spec.panelThickness) / 2;
|
|
77
|
+
const linings = [
|
|
78
|
+
box(writer, [0, 0, 0], [lining, spec.liningDepth, spec.height]),
|
|
79
|
+
box(writer, [spec.width - lining, 0, 0], [spec.width, spec.liningDepth, spec.height]),
|
|
80
|
+
box(writer, [lining, 0, spec.height - lining], [spec.width - lining, spec.liningDepth, spec.height]),
|
|
81
|
+
];
|
|
82
|
+
const panel = box(writer, [lining, panelFront, 0], [spec.width - lining, panelFront + spec.panelThickness, spec.height - lining]);
|
|
83
|
+
const handles = handleItems(writer, spec, panelFront);
|
|
84
|
+
const parts = [
|
|
85
|
+
{ name: "Lining", items: linings, material: spec.liningMaterial },
|
|
86
|
+
{ name: "Panel", items: [panel], material: spec.panelMaterial },
|
|
87
|
+
...(handles.length ? [{ name: "Hardware", items: handles, material: spec.handleMaterial }] : []),
|
|
88
|
+
];
|
|
89
|
+
const materials = materialsOfParts(tx, parts);
|
|
90
|
+
const type = writer.create("IfcDoorType", {
|
|
91
|
+
GlobalId: tx.globalId(spec.id),
|
|
92
|
+
Name: spec.name,
|
|
93
|
+
RepresentationMaps: [ref(representationMap(writer, [...linings, panel, ...handles]))],
|
|
94
|
+
PredefinedType: enumValue("DOOR"),
|
|
95
|
+
OperationType: enumValue(spec.operation),
|
|
96
|
+
});
|
|
97
|
+
dressParts(tx, writer, type, parts, materials);
|
|
98
|
+
declareInProject(tx, writer, type);
|
|
99
|
+
return type;
|
|
100
|
+
}
|
|
101
|
+
export function createWindowType(tx, writer, spec) {
|
|
102
|
+
positiveSizes({ width: spec.width, height: spec.height, "frame thickness": spec.frameThickness, "frame depth": spec.frameDepth, "glass thickness": spec.glassThickness });
|
|
103
|
+
const frame = spec.frameThickness;
|
|
104
|
+
if (2 * frame >= spec.width || 2 * frame >= spec.height || spec.glassThickness > spec.frameDepth) {
|
|
105
|
+
throw new Error("The window's frame and glass do not fit inside its width, height and depth");
|
|
106
|
+
}
|
|
107
|
+
const glassFront = (spec.frameDepth - spec.glassThickness) / 2;
|
|
108
|
+
const frames = [
|
|
109
|
+
box(writer, [0, 0, 0], [frame, spec.frameDepth, spec.height]),
|
|
110
|
+
box(writer, [spec.width - frame, 0, 0], [spec.width, spec.frameDepth, spec.height]),
|
|
111
|
+
box(writer, [frame, 0, 0], [spec.width - frame, spec.frameDepth, frame]),
|
|
112
|
+
box(writer, [frame, 0, spec.height - frame], [spec.width - frame, spec.frameDepth, spec.height]),
|
|
113
|
+
];
|
|
114
|
+
const glass = box(writer, [frame, glassFront, frame], [spec.width - frame, glassFront + spec.glassThickness, spec.height - frame]);
|
|
115
|
+
const parts = [{ name: "Framing", items: frames, material: spec.frameMaterial }, { name: "Glazing", items: [glass], material: spec.glassMaterial }];
|
|
116
|
+
const materials = materialsOfParts(tx, parts);
|
|
117
|
+
const type = writer.create("IfcWindowType", {
|
|
118
|
+
GlobalId: tx.globalId(spec.id),
|
|
119
|
+
Name: spec.name,
|
|
120
|
+
RepresentationMaps: [ref(representationMap(writer, [...frames, glass]))],
|
|
121
|
+
PredefinedType: enumValue("WINDOW"),
|
|
122
|
+
PartitioningType: enumValue("SINGLE_PANEL"),
|
|
123
|
+
});
|
|
124
|
+
dressParts(tx, writer, type, parts, materials);
|
|
125
|
+
declareInProject(tx, writer, type);
|
|
126
|
+
return type;
|
|
127
|
+
}
|
|
128
|
+
function bodyMapOf(reader, type) {
|
|
129
|
+
var _a;
|
|
130
|
+
const maps = reader.attribute(type, "RepresentationMaps");
|
|
131
|
+
const all = (isList(maps) ? maps : []).filter(isReference).map((map) => map.ref);
|
|
132
|
+
const isBody = (map) => {
|
|
133
|
+
const representation = reader.attribute(map, "MappedRepresentation");
|
|
134
|
+
return isReference(representation) && reader.attribute(representation.ref, "RepresentationIdentifier") === "Body";
|
|
135
|
+
};
|
|
136
|
+
return (_a = all.find(isBody)) !== null && _a !== void 0 ? _a : all[0];
|
|
137
|
+
}
|
|
138
|
+
export function typeBounds(reader, type, map) {
|
|
139
|
+
const origin = frameOf(reader, reader.attribute(map, "MappingOrigin"));
|
|
140
|
+
const representation = reader.attribute(map, "MappedRepresentation");
|
|
141
|
+
const items = isReference(representation) ? reader.attribute(representation.ref, "Items") : null;
|
|
142
|
+
const corners = (isList(items) ? items : []).filter(isReference).flatMap((item) => extrusionCorners(reader, item.ref)).map((corner) => pointToWorld(origin, corner));
|
|
143
|
+
if (!corners.length) {
|
|
144
|
+
throw new Error(`${describeObject(reader, type)} has no geometry this library can size, so it cannot be placed in a wall`);
|
|
145
|
+
}
|
|
146
|
+
const along = (axis) => corners.map((corner) => corner[axis]);
|
|
147
|
+
return {
|
|
148
|
+
min: [Math.min(...along(0)), Math.min(...along(1)), Math.min(...along(2))],
|
|
149
|
+
max: [Math.max(...along(0)), Math.max(...along(1)), Math.max(...along(2))],
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
export function createFilling(tx, writer, kind, spec, tolerance) {
|
|
153
|
+
var _a;
|
|
154
|
+
const map = bodyMapOf(tx, spec.type);
|
|
155
|
+
if (map === undefined) {
|
|
156
|
+
throw new Error(`${describeObject(tx, spec.type)} has no representation map`);
|
|
157
|
+
}
|
|
158
|
+
const { min, max } = typeBounds(tx, spec.type, map);
|
|
159
|
+
const width = max[0] - min[0];
|
|
160
|
+
const height = max[2] - min[2];
|
|
161
|
+
const depth = max[1] - min[1];
|
|
162
|
+
const opening = createWallOpening(tx, writer, { wall: spec.wall, id: undefined, name: undefined, offset: spec.offset, sill: spec.sill, width, height }, tolerance);
|
|
163
|
+
const placement = writer.localPlacement(opening.placement, Object.assign(Object.assign({}, WORLD_AXES), { origin: [-min[0], opening.wallFace + (opening.thickness - depth) / 2 - min[1], -min[2]] }));
|
|
164
|
+
const operator = writer.create("IfcCartesianTransformationOperator3D", { LocalOrigin: ref(writer.point([0, 0, 0])) });
|
|
165
|
+
const mapped = writer.create("IfcMappedItem", { MappingSource: ref(map), MappingTarget: ref(operator) });
|
|
166
|
+
const body = writer.shapeRepresentation(bodyContext(tx, writer), "Body", "MappedRepresentation", [mapped]);
|
|
167
|
+
const element = writer.create(kind, {
|
|
168
|
+
GlobalId: tx.globalId(spec.id),
|
|
169
|
+
Name: (_a = spec.name) !== null && _a !== void 0 ? _a : null,
|
|
170
|
+
ObjectPlacement: ref(placement),
|
|
171
|
+
Representation: ref(writer.productShape([body])),
|
|
172
|
+
OverallHeight: height,
|
|
173
|
+
OverallWidth: width,
|
|
174
|
+
});
|
|
175
|
+
writer.create("IfcRelFillsElement", { GlobalId: tx.globalId(undefined), RelatingOpeningElement: ref(opening.opening), RelatedBuildingElement: ref(element) });
|
|
176
|
+
const storey = containerOf(tx, spec.wall);
|
|
177
|
+
if (storey !== undefined) {
|
|
178
|
+
containIn(tx, writer, storey, element);
|
|
179
|
+
}
|
|
180
|
+
defineByType(tx, writer, element, spec.type);
|
|
181
|
+
return element;
|
|
182
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type * as Inputs from "../api/inputs";
|
|
2
|
+
import type { IfcValue } from "../step/step-types";
|
|
3
|
+
import type { ModelReader } from "./build-types";
|
|
4
|
+
export declare function decimalDegrees(value: IfcValue): number | undefined;
|
|
5
|
+
export declare function georeferenceOf(model: ModelReader): Inputs.IFC.GeoreferenceDto;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isList, isReference, textValue } from "../step/values";
|
|
2
|
+
import { COMPOUND_ANGLE_PARTS, MILLIONTHS_PER_SECOND, MINUTES_PER_DEGREE, SECONDS_PER_DEGREE } from "./constants";
|
|
3
|
+
const MODEL_CONTEXT = "Model";
|
|
4
|
+
function numberOr(value, fallback) {
|
|
5
|
+
return typeof value === "number" ? value : fallback;
|
|
6
|
+
}
|
|
7
|
+
export function decimalDegrees(value) {
|
|
8
|
+
if (!isList(value) || value.length < COMPOUND_ANGLE_PARTS || !value.every((part) => typeof part === "number")) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
const [degrees, minutes, seconds, millionths = 0] = value;
|
|
12
|
+
return degrees + minutes / MINUTES_PER_DEGREE + (seconds + millionths / MILLIONTHS_PER_SECOND) / SECONDS_PER_DEGREE;
|
|
13
|
+
}
|
|
14
|
+
function mapConversionOf(model) {
|
|
15
|
+
const conversions = model.byType("IfcMapConversion").map((conversion) => conversion.id);
|
|
16
|
+
const ofModel = conversions.find((conversion) => {
|
|
17
|
+
const source = model.attribute(conversion, "SourceCRS");
|
|
18
|
+
return isReference(source) && model.attribute(source.ref, "ContextType") === MODEL_CONTEXT;
|
|
19
|
+
});
|
|
20
|
+
return ofModel !== null && ofModel !== void 0 ? ofModel : conversions[0];
|
|
21
|
+
}
|
|
22
|
+
export function georeferenceOf(model) {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
const conversion = mapConversionOf(model);
|
|
25
|
+
const target = conversion === undefined ? null : model.attribute(conversion, "TargetCRS");
|
|
26
|
+
const site = (_a = model.byType("IfcSite")[0]) === null || _a === void 0 ? void 0 : _a.id;
|
|
27
|
+
const latitude = site === undefined ? undefined : decimalDegrees(model.attribute(site, "RefLatitude"));
|
|
28
|
+
const longitude = site === undefined ? undefined : decimalDegrees(model.attribute(site, "RefLongitude"));
|
|
29
|
+
const located = latitude !== undefined && longitude !== undefined;
|
|
30
|
+
return {
|
|
31
|
+
mapped: conversion !== undefined,
|
|
32
|
+
crs: isReference(target) ? (_b = textValue(model.attribute(target.ref, "Name"))) !== null && _b !== void 0 ? _b : "" : "",
|
|
33
|
+
eastings: conversion === undefined ? 0 : numberOr(model.attribute(conversion, "Eastings"), 0),
|
|
34
|
+
northings: conversion === undefined ? 0 : numberOr(model.attribute(conversion, "Northings"), 0),
|
|
35
|
+
orthogonalHeight: conversion === undefined ? 0 : numberOr(model.attribute(conversion, "OrthogonalHeight"), 0),
|
|
36
|
+
xAxisAbscissa: conversion === undefined ? 1 : numberOr(model.attribute(conversion, "XAxisAbscissa"), 1),
|
|
37
|
+
xAxisOrdinate: conversion === undefined ? 0 : numberOr(model.attribute(conversion, "XAxisOrdinate"), 0),
|
|
38
|
+
scale: conversion === undefined ? 1 : numberOr(model.attribute(conversion, "Scale"), 1),
|
|
39
|
+
located,
|
|
40
|
+
latitude: located ? latitude : 0,
|
|
41
|
+
longitude: located ? longitude : 0,
|
|
42
|
+
elevation: site === undefined ? 0 : numberOr(model.attribute(site, "RefElevation"), 0),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IfcTransaction } from "../model/transaction";
|
|
2
|
+
import type { LayerSpec, MaterialPart, ModelReader, SurfaceColour } from "./build-types";
|
|
3
|
+
import type { EntityWriter } from "./entity-writer";
|
|
4
|
+
export declare function findMaterial(reader: ModelReader, name: string): number | undefined;
|
|
5
|
+
export declare function findLayerSet(reader: ModelReader, name: string): number | undefined;
|
|
6
|
+
export declare function requireMaterial(reader: ModelReader, name: string): number;
|
|
7
|
+
export declare function requireLayerSet(reader: ModelReader, name: string): number;
|
|
8
|
+
export declare function materialStyle(reader: ModelReader, material: number): number | undefined;
|
|
9
|
+
export declare function createMaterial(tx: IfcTransaction, writer: EntityWriter, name: string, category: string | undefined, colour: SurfaceColour | undefined): number;
|
|
10
|
+
export declare function createLayerSet(tx: IfcTransaction, writer: EntityWriter, name: string, layers: readonly LayerSpec[]): number;
|
|
11
|
+
export declare function layerSetThickness(reader: ModelReader, layerSet: number): number;
|
|
12
|
+
export declare function layerSetFor(tx: IfcTransaction, writer: EntityWriter, named: string | undefined, thickness: number, kind: string): number;
|
|
13
|
+
export declare function associateMaterial(tx: IfcTransaction, writer: EntityWriter, objects: readonly number[], material: number): void;
|
|
14
|
+
export declare function associateNewMaterial(tx: IfcTransaction, writer: EntityWriter, objects: readonly number[], material: number): void;
|
|
15
|
+
export declare function materialOf(reader: ModelReader, object: number): number | undefined;
|
|
16
|
+
export declare function layerSetUsage(writer: EntityWriter, layerSet: number, direction: "AXIS2" | "AXIS3", sense: "POSITIVE" | "NEGATIVE", offset: number): number;
|
|
17
|
+
export declare function materialsOfParts(tx: IfcTransaction, parts: readonly MaterialPart[]): (number | undefined)[];
|
|
18
|
+
export declare function dressParts(tx: IfcTransaction, writer: EntityWriter, type: number, parts: readonly MaterialPart[], materials: readonly (number | undefined)[]): void;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { enumValue, isList, isReference, ref } from "../step/values";
|
|
2
|
+
import { MATERIAL_ASSOCIATION } from "./constants";
|
|
3
|
+
import { bodyContext } from "./contexts";
|
|
4
|
+
import { appendToRelationship, relate, relatingOf } from "./relationships";
|
|
5
|
+
const MATERIAL = { type: "IfcMaterial", name: "Name", what: "material" };
|
|
6
|
+
const LAYER_SET = { type: "IfcMaterialLayerSet", name: "LayerSetName", what: "layer set" };
|
|
7
|
+
const MATERIAL_REPRESENTATION = "IfcMaterialDefinitionRepresentation";
|
|
8
|
+
function findNamed(reader, type, nameAttribute, name) {
|
|
9
|
+
var _a;
|
|
10
|
+
return (_a = reader.byType(type).find((entity) => reader.attribute(entity.id, nameAttribute) === name)) === null || _a === void 0 ? void 0 : _a.id;
|
|
11
|
+
}
|
|
12
|
+
export function findMaterial(reader, name) {
|
|
13
|
+
return findNamed(reader, MATERIAL.type, MATERIAL.name, name);
|
|
14
|
+
}
|
|
15
|
+
export function findLayerSet(reader, name) {
|
|
16
|
+
return findNamed(reader, LAYER_SET.type, LAYER_SET.name, name);
|
|
17
|
+
}
|
|
18
|
+
export function requireMaterial(reader, name) {
|
|
19
|
+
const material = findMaterial(reader, name);
|
|
20
|
+
if (material === undefined) {
|
|
21
|
+
throw new Error(`The model has no ${MATERIAL.what} named '${name}'`);
|
|
22
|
+
}
|
|
23
|
+
return material;
|
|
24
|
+
}
|
|
25
|
+
export function requireLayerSet(reader, name) {
|
|
26
|
+
const layerSet = findLayerSet(reader, name);
|
|
27
|
+
if (layerSet === undefined) {
|
|
28
|
+
throw new Error(`The model has no ${LAYER_SET.what} named '${name}'`);
|
|
29
|
+
}
|
|
30
|
+
return layerSet;
|
|
31
|
+
}
|
|
32
|
+
function surfaceStyle(writer, name, colour) {
|
|
33
|
+
const rgb = writer.create("IfcColourRgb", { Red: colour.red, Green: colour.green, Blue: colour.blue });
|
|
34
|
+
const shading = writer.create("IfcSurfaceStyleShading", { SurfaceColour: ref(rgb), Transparency: colour.transparency > 0 ? colour.transparency : null });
|
|
35
|
+
return writer.create("IfcSurfaceStyle", { Name: name, Side: enumValue("BOTH"), Styles: [ref(shading)] });
|
|
36
|
+
}
|
|
37
|
+
export function materialStyle(reader, material) {
|
|
38
|
+
for (const user of reader.referencesTo(material)) {
|
|
39
|
+
if (reader.typeOf(user) !== MATERIAL_REPRESENTATION) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const representations = reader.attribute(user, "Representations");
|
|
43
|
+
for (const representation of (isList(representations) ? representations : []).filter(isReference)) {
|
|
44
|
+
const items = reader.attribute(representation.ref, "Items");
|
|
45
|
+
for (const item of (isList(items) ? items : []).filter(isReference)) {
|
|
46
|
+
const styles = reader.attribute(item.ref, "Styles");
|
|
47
|
+
const style = (isList(styles) ? styles : []).find(isReference);
|
|
48
|
+
if (style) {
|
|
49
|
+
return style.ref;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
export function createMaterial(tx, writer, name, category, colour) {
|
|
57
|
+
if (findMaterial(tx, name) !== undefined) {
|
|
58
|
+
throw new Error(`The model already has a material named '${name}'`);
|
|
59
|
+
}
|
|
60
|
+
const material = writer.create("IfcMaterial", { Name: name, Category: category !== null && category !== void 0 ? category : null });
|
|
61
|
+
if (colour) {
|
|
62
|
+
const styled = writer.create("IfcStyledItem", { Styles: [ref(surfaceStyle(writer, name, colour))], Name: name });
|
|
63
|
+
const representation = writer.create("IfcStyledRepresentation", {
|
|
64
|
+
ContextOfItems: ref(bodyContext(tx, writer)),
|
|
65
|
+
RepresentationIdentifier: "Style",
|
|
66
|
+
RepresentationType: "Material",
|
|
67
|
+
Items: [ref(styled)],
|
|
68
|
+
});
|
|
69
|
+
writer.create("IfcMaterialDefinitionRepresentation", { Representations: [ref(representation)], RepresentedMaterial: ref(material) });
|
|
70
|
+
}
|
|
71
|
+
return material;
|
|
72
|
+
}
|
|
73
|
+
export function createLayerSet(tx, writer, name, layers) {
|
|
74
|
+
if (!layers.length) {
|
|
75
|
+
throw new Error("A layer set needs at least one layer");
|
|
76
|
+
}
|
|
77
|
+
if (findLayerSet(tx, name) !== undefined) {
|
|
78
|
+
throw new Error(`The model already has a layer set named '${name}'`);
|
|
79
|
+
}
|
|
80
|
+
const layerIds = layers.map((layer) => {
|
|
81
|
+
var _a;
|
|
82
|
+
if (!(layer.thickness >= 0) || !Number.isFinite(layer.thickness)) {
|
|
83
|
+
throw new Error(`A layer's thickness must be zero or more, got ${layer.thickness}`);
|
|
84
|
+
}
|
|
85
|
+
return writer.create("IfcMaterialLayer", {
|
|
86
|
+
Material: layer.material === undefined ? null : ref(requireMaterial(tx, layer.material)),
|
|
87
|
+
LayerThickness: layer.thickness,
|
|
88
|
+
Name: (_a = layer.name) !== null && _a !== void 0 ? _a : null,
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
return writer.create("IfcMaterialLayerSet", { MaterialLayers: layerIds.map(ref), LayerSetName: name });
|
|
92
|
+
}
|
|
93
|
+
export function layerSetThickness(reader, layerSet) {
|
|
94
|
+
const layers = reader.attribute(layerSet, "MaterialLayers");
|
|
95
|
+
let total = 0;
|
|
96
|
+
for (const layer of isList(layers) ? layers : []) {
|
|
97
|
+
if (isReference(layer)) {
|
|
98
|
+
const thickness = reader.attribute(layer.ref, "LayerThickness");
|
|
99
|
+
total += typeof thickness === "number" ? thickness : 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return total;
|
|
103
|
+
}
|
|
104
|
+
function isPlainLayerSet(reader, layerSet, thickness) {
|
|
105
|
+
const layers = reader.attribute(layerSet, "MaterialLayers");
|
|
106
|
+
const only = isList(layers) && layers.length === 1 ? layers[0] : undefined;
|
|
107
|
+
return isReference(only) && reader.attribute(only.ref, "Material") === null && layerSetThickness(reader, layerSet) === thickness;
|
|
108
|
+
}
|
|
109
|
+
export function layerSetFor(tx, writer, named, thickness, kind) {
|
|
110
|
+
if (named !== undefined) {
|
|
111
|
+
return requireLayerSet(tx, named);
|
|
112
|
+
}
|
|
113
|
+
if (!(thickness > 0) || !Number.isFinite(thickness)) {
|
|
114
|
+
throw new RangeError(`A ${kind.toLowerCase()}'s thickness must be more than zero, got ${thickness}`);
|
|
115
|
+
}
|
|
116
|
+
let name = `${kind} ${thickness}`;
|
|
117
|
+
for (let copy = 2;; copy++) {
|
|
118
|
+
const existing = findLayerSet(tx, name);
|
|
119
|
+
if (existing === undefined) {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
if (isPlainLayerSet(tx, existing, thickness)) {
|
|
123
|
+
return existing;
|
|
124
|
+
}
|
|
125
|
+
name = `${kind} ${thickness} (${copy})`;
|
|
126
|
+
}
|
|
127
|
+
const layer = writer.create("IfcMaterialLayer", { LayerThickness: thickness });
|
|
128
|
+
return writer.create("IfcMaterialLayerSet", { MaterialLayers: [ref(layer)], LayerSetName: name });
|
|
129
|
+
}
|
|
130
|
+
export function associateMaterial(tx, writer, objects, material) {
|
|
131
|
+
appendToRelationship(tx, writer, MATERIAL_ASSOCIATION, material, objects);
|
|
132
|
+
}
|
|
133
|
+
export function associateNewMaterial(tx, writer, objects, material) {
|
|
134
|
+
relate(tx, writer, MATERIAL_ASSOCIATION, material, objects);
|
|
135
|
+
}
|
|
136
|
+
export function materialOf(reader, object) {
|
|
137
|
+
return relatingOf(reader, MATERIAL_ASSOCIATION, object);
|
|
138
|
+
}
|
|
139
|
+
export function layerSetUsage(writer, layerSet, direction, sense, offset) {
|
|
140
|
+
return writer.create("IfcMaterialLayerSetUsage", {
|
|
141
|
+
ForLayerSet: ref(layerSet),
|
|
142
|
+
LayerSetDirection: enumValue(direction),
|
|
143
|
+
DirectionSense: enumValue(sense),
|
|
144
|
+
OffsetFromReferenceLine: offset,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
export function materialsOfParts(tx, parts) {
|
|
148
|
+
return parts.map((part) => (part.material === undefined ? undefined : requireMaterial(tx, part.material)));
|
|
149
|
+
}
|
|
150
|
+
export function dressParts(tx, writer, type, parts, materials) {
|
|
151
|
+
const constituents = [];
|
|
152
|
+
parts.forEach((part, index) => {
|
|
153
|
+
const material = materials[index];
|
|
154
|
+
if (material === undefined) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const style = materialStyle(tx, material);
|
|
158
|
+
if (style !== undefined) {
|
|
159
|
+
part.items.forEach((item) => writer.create("IfcStyledItem", { Item: ref(item), Styles: [ref(style)], Name: null }));
|
|
160
|
+
}
|
|
161
|
+
constituents.push(writer.create("IfcMaterialConstituent", { Name: part.name, Material: ref(material), Category: part.name }));
|
|
162
|
+
});
|
|
163
|
+
if (constituents.length) {
|
|
164
|
+
associateNewMaterial(tx, writer, [type], writer.create("IfcMaterialConstituentSet", { MaterialConstituents: constituents.map(ref) }));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Base } from "@bitbybit-dev/base";
|
|
2
|
+
import type { Frame3, Line2 } from "./build-types";
|
|
3
|
+
export declare function normalize2(a: Base.Vector2): Base.Vector2;
|
|
4
|
+
export declare function normalize3(a: Base.Vector3): Base.Vector3;
|
|
5
|
+
export declare function frameFrom(origin: Base.Point3, zAxis: Base.Vector3, xHint: Base.Vector3): Frame3;
|
|
6
|
+
export declare function intersectLines(first: Line2, second: Line2, parallelTolerance: number): Base.Point2 | undefined;
|
|
7
|
+
export declare function distanceToLine(point: Base.Point2, line: Line2): number;
|
|
8
|
+
export declare function distanceToSegment(point: Base.Point2, start: Base.Point2, end: Base.Point2): number;
|
|
9
|
+
export declare function parameterOnLine(point: Base.Point2, line: Line2): number;
|
|
10
|
+
export declare function placedOnPlan(frame: Frame3, point: Base.Point2): Base.Point2;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { pointToWorld } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
|
|
2
|
+
import { add2, cross2, cross3, dot2, dot3, length2, length3, scale2, scale3, subtract2, subtract3 } from "@bitbybit-dev/base/lib/api/services/helpers/vectors";
|
|
3
|
+
const ZERO_LENGTH = "A direction of zero length has no direction";
|
|
4
|
+
export function normalize2(a) {
|
|
5
|
+
const length = length2(a);
|
|
6
|
+
if (!(length > 0)) {
|
|
7
|
+
throw new RangeError(ZERO_LENGTH);
|
|
8
|
+
}
|
|
9
|
+
return [a[0] / length, a[1] / length];
|
|
10
|
+
}
|
|
11
|
+
export function normalize3(a) {
|
|
12
|
+
const length = length3(a);
|
|
13
|
+
if (!(length > 0)) {
|
|
14
|
+
throw new RangeError(ZERO_LENGTH);
|
|
15
|
+
}
|
|
16
|
+
return [a[0] / length, a[1] / length, a[2] / length];
|
|
17
|
+
}
|
|
18
|
+
export function frameFrom(origin, zAxis, xHint) {
|
|
19
|
+
const z = normalize3(zAxis);
|
|
20
|
+
const x = normalize3(subtract3(xHint, scale3(z, dot3(xHint, z))));
|
|
21
|
+
return { origin, x, y: cross3(z, x), z };
|
|
22
|
+
}
|
|
23
|
+
export function intersectLines(first, second, parallelTolerance) {
|
|
24
|
+
const denominator = cross2(first.direction, second.direction);
|
|
25
|
+
if (Math.abs(denominator) <= parallelTolerance) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const along = cross2(subtract2(second.point, first.point), second.direction) / denominator;
|
|
29
|
+
return add2(first.point, scale2(first.direction, along));
|
|
30
|
+
}
|
|
31
|
+
export function distanceToLine(point, line) {
|
|
32
|
+
return cross2(line.direction, subtract2(point, line.point));
|
|
33
|
+
}
|
|
34
|
+
export function distanceToSegment(point, start, end) {
|
|
35
|
+
const along = subtract2(end, start);
|
|
36
|
+
const squared = dot2(along, along);
|
|
37
|
+
const offset = subtract2(point, start);
|
|
38
|
+
const fraction = squared > 0 ? Math.min(1, Math.max(0, dot2(offset, along) / squared)) : 0;
|
|
39
|
+
return length2(subtract2(point, add2(start, scale2(along, fraction))));
|
|
40
|
+
}
|
|
41
|
+
export function parameterOnLine(point, line) {
|
|
42
|
+
return dot2(subtract2(point, line.point), line.direction);
|
|
43
|
+
}
|
|
44
|
+
export function placedOnPlan(frame, point) {
|
|
45
|
+
const [x, y] = pointToWorld(frame, [point[0], point[1], 0]);
|
|
46
|
+
return [x, y];
|
|
47
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Base } from "@bitbybit-dev/base";
|
|
2
|
+
import type { Bounds, ExtrudedBody, Linear2, ModelReader, Plane3, ProfileShape } from "./build-types";
|
|
3
|
+
export declare function profileShape(reader: ModelReader, profile: number): ProfileShape | undefined;
|
|
4
|
+
export declare function volumeBetween(footprint: readonly Base.Point2[], bounds: Bounds): number;
|
|
5
|
+
export declare function areaWithin(footprint: readonly Base.Point2[], sides: readonly Linear2[]): number;
|
|
6
|
+
export declare function areaBetween(start: Base.Point2, end: Base.Point2, bounds: Bounds): number;
|
|
7
|
+
export declare function withLevels(bounds: Bounds, bottom: number, top: number): Bounds;
|
|
8
|
+
export declare function boundsOf(base: number, top: number, planes: readonly Plane3[]): Bounds;
|
|
9
|
+
export declare function extrudedBodyOf(reader: ModelReader, product: number): ExtrudedBody | undefined;
|