@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,292 @@
|
|
|
1
|
+
import { squareFrame } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
|
|
2
|
+
import { refinedSurfaceMesh } from "@bitbybit-dev/base/lib/api/services/helpers/surface-triangulation";
|
|
3
|
+
import { newellNormal } from "@bitbybit-dev/base/lib/api/services/helpers/triangulation";
|
|
4
|
+
import { cross3, dot3, length3, subtract3 } from "@bitbybit-dev/base/lib/api/services/helpers/vectors";
|
|
5
|
+
import { isList, isReference } from "../step/values";
|
|
6
|
+
import { UnsupportedGeometryError } from "./errors";
|
|
7
|
+
import { CUT_SAMPLES, CUT_TURN, FIT_PROBES, FIT_TOLERANCE, MIN_LOOP_POINTS, NORMAL_STEP, TRIANGLE_CORNERS } from "./surfaces.constants";
|
|
8
|
+
import { parametricSurface, plane } from "./surfaces";
|
|
9
|
+
const OUTER_BOUND = "IfcFaceOuterBound";
|
|
10
|
+
const FACE_SURFACE = "IfcFaceSurface";
|
|
11
|
+
function unwrapped(value, previous, period) {
|
|
12
|
+
return period === undefined ? value : value + period * Math.round((previous - value) / period);
|
|
13
|
+
}
|
|
14
|
+
function signedArea(uv) {
|
|
15
|
+
let twice = 0;
|
|
16
|
+
for (let at = 0, previous = uv.length - 1; at < uv.length; previous = at++) {
|
|
17
|
+
twice += uv[previous][0] * uv[at][1] - uv[at][0] * uv[previous][1];
|
|
18
|
+
}
|
|
19
|
+
return twice / 2;
|
|
20
|
+
}
|
|
21
|
+
function planeThrough(points) {
|
|
22
|
+
const normal = newellNormal(points.flat(), points.map((_, at) => at));
|
|
23
|
+
const frame = squareFrame(points[0], normal, subtract3(points[1], points[0]));
|
|
24
|
+
if (typeof frame === "string") {
|
|
25
|
+
throw new UnsupportedGeometryError("A face bounded by edges has no area");
|
|
26
|
+
}
|
|
27
|
+
return plane(frame);
|
|
28
|
+
}
|
|
29
|
+
export class AdvancedFaces {
|
|
30
|
+
constructor(model, curves, edges) {
|
|
31
|
+
this.surfaces = new Map();
|
|
32
|
+
this.model = model;
|
|
33
|
+
this.curves = curves;
|
|
34
|
+
this.edges = edges;
|
|
35
|
+
}
|
|
36
|
+
face(face, bounds) {
|
|
37
|
+
var _a, _b, _c;
|
|
38
|
+
const loops = bounds.map((bound) => this.bound(bound));
|
|
39
|
+
const surfaceValue = this.model.schema.isSubtypeOf((_a = this.model.typeOf(face)) !== null && _a !== void 0 ? _a : "", FACE_SURFACE) ? this.value(face, "FaceSurface") : null;
|
|
40
|
+
const surface = isReference(surfaceValue) ? this.fitting(surfaceValue.ref, loops) : planeThrough((_c = (_b = loops.find((loop) => loop.outer)) === null || _b === void 0 ? void 0 : _b.points) !== null && _c !== void 0 ? _c : loops[0].points);
|
|
41
|
+
const sameSense = !isReference(surfaceValue) || this.value(face, "SameSense") !== false;
|
|
42
|
+
const placed = loops.map((loop) => this.parameters(surface, loop));
|
|
43
|
+
const { uv, positions, indices } = this.assembled(surface, placed, sameSense);
|
|
44
|
+
const mesh = refinedSurfaceMesh(uv, positions, indices, (u, v) => surface.point(u, v));
|
|
45
|
+
return this.oriented(mesh, surface, uv, sameSense);
|
|
46
|
+
}
|
|
47
|
+
surface(surface) {
|
|
48
|
+
if (!this.surfaces.has(surface)) {
|
|
49
|
+
this.surfaces.set(surface, parametricSurface(this.model, this.curves, surface));
|
|
50
|
+
}
|
|
51
|
+
const known = this.surfaces.get(surface);
|
|
52
|
+
if (!known) {
|
|
53
|
+
throw new UnsupportedGeometryError(`A face on an ${this.model.entity(surface).type} is not supported yet`);
|
|
54
|
+
}
|
|
55
|
+
return known;
|
|
56
|
+
}
|
|
57
|
+
fitting(surface, loops) {
|
|
58
|
+
const written = this.surface(surface);
|
|
59
|
+
if (this.model.entity(surface).type !== "IfcRationalBSplineSurfaceWithKnots") {
|
|
60
|
+
return written;
|
|
61
|
+
}
|
|
62
|
+
const probes = loops.flatMap((loop) => loop.points).filter((_, at, all) => at % Math.max(1, Math.floor(all.length / FIT_PROBES)) === 0);
|
|
63
|
+
const missOf = (candidate) => Math.max(...probes.map((point) => {
|
|
64
|
+
const [u, v] = candidate.parameters(point, undefined);
|
|
65
|
+
return length3(subtract3(candidate.point(u, v), point));
|
|
66
|
+
}));
|
|
67
|
+
const reach = Math.max(1, ...probes.map(length3)) * FIT_TOLERANCE;
|
|
68
|
+
const asWritten = missOf(written);
|
|
69
|
+
if (asWritten <= reach) {
|
|
70
|
+
return written;
|
|
71
|
+
}
|
|
72
|
+
const divided = parametricSurface(this.model, this.curves, surface, true);
|
|
73
|
+
return divided && missOf(divided) < asWritten ? divided : written;
|
|
74
|
+
}
|
|
75
|
+
bound(bound) {
|
|
76
|
+
const loop = this.value(bound, "Bound");
|
|
77
|
+
if (!isReference(loop)) {
|
|
78
|
+
throw new UnsupportedGeometryError(`#${bound} has no loop`);
|
|
79
|
+
}
|
|
80
|
+
const points = this.edges.loop(loop.ref);
|
|
81
|
+
if (points.length < MIN_LOOP_POINTS) {
|
|
82
|
+
throw new UnsupportedGeometryError(`#${bound} bounds no area`);
|
|
83
|
+
}
|
|
84
|
+
return { points: this.value(bound, "Orientation") === false ? [...points].reverse() : points, uv: [], winding: [0, 0], outer: this.model.schema.isSubtypeOf(this.model.peek(bound).type, OUTER_BOUND) };
|
|
85
|
+
}
|
|
86
|
+
parameters(surface, loop) {
|
|
87
|
+
const uv = [];
|
|
88
|
+
const points = [];
|
|
89
|
+
let previous;
|
|
90
|
+
let pole;
|
|
91
|
+
const regular = loop.points.findIndex((point) => !surface.parameters(point, undefined).some(Number.isNaN));
|
|
92
|
+
const turned = regular > 0 ? [...loop.points.slice(regular), ...loop.points.slice(0, regular)] : loop.points;
|
|
93
|
+
turned.forEach((point) => {
|
|
94
|
+
const [u, v] = surface.parameters(point, previous);
|
|
95
|
+
const undefinedAxis = Number.isNaN(u) ? 0 : Number.isNaN(v) ? 1 : -1;
|
|
96
|
+
if (undefinedAxis >= 0 && previous) {
|
|
97
|
+
const arrival = undefinedAxis === 0 ? [previous[0], v] : [u, previous[1]];
|
|
98
|
+
pole !== null && pole !== void 0 ? pole : (pole = { axis: undefinedAxis, at: uv.length });
|
|
99
|
+
uv.push(arrival, arrival);
|
|
100
|
+
points.push(point, point);
|
|
101
|
+
previous = arrival;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const placed = previous ? [unwrapped(u, previous[0], surface.periods[0]), unwrapped(v, previous[1], surface.periods[1])] : [u, v];
|
|
105
|
+
if (pole && uv.length === pole.at + 2) {
|
|
106
|
+
const departure = pole.axis === 0 ? [placed[0], uv[pole.at][1]] : [uv[pole.at][0], placed[1]];
|
|
107
|
+
uv[pole.at + 1] = departure;
|
|
108
|
+
}
|
|
109
|
+
uv.push(placed);
|
|
110
|
+
points.push(point);
|
|
111
|
+
previous = placed;
|
|
112
|
+
});
|
|
113
|
+
if (pole) {
|
|
114
|
+
this.leastWound(surface, uv, pole.axis, pole.at + 1);
|
|
115
|
+
}
|
|
116
|
+
const winding = [0, 1].map((axis) => this.windingOf(surface, uv, axis));
|
|
117
|
+
return Object.assign(Object.assign({}, loop), { points, uv, winding });
|
|
118
|
+
}
|
|
119
|
+
windingOf(surface, uv, axis) {
|
|
120
|
+
const period = surface.periods[axis];
|
|
121
|
+
if (period === undefined) {
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
const first = uv[0];
|
|
125
|
+
const last = uv[uv.length - 1];
|
|
126
|
+
return Math.round((unwrapped(first[axis], last[axis], period) - first[axis]) / period);
|
|
127
|
+
}
|
|
128
|
+
leastWound(surface, uv, axis, from) {
|
|
129
|
+
const period = surface.periods[axis];
|
|
130
|
+
const winding = this.windingOf(surface, uv, axis);
|
|
131
|
+
if (period === undefined || winding === 0) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
for (let at = from; at < uv.length; at++) {
|
|
135
|
+
const point = uv[at];
|
|
136
|
+
uv[at] = axis === 0 ? [point[0] - winding * period, point[1]] : [point[0], point[1] - winding * period];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
assembled(surface, loops, sameSense) {
|
|
140
|
+
const winding = loops.filter((loop) => loop.winding[0] !== 0 || loop.winding[1] !== 0);
|
|
141
|
+
const plain = loops.filter((loop) => loop.winding[0] === 0 && loop.winding[1] === 0);
|
|
142
|
+
let outer;
|
|
143
|
+
let holes;
|
|
144
|
+
if (winding.length === 0) {
|
|
145
|
+
const flagged = plain.findIndex((loop) => loop.outer);
|
|
146
|
+
const largest = plain.map((loop) => Math.abs(signedArea(loop.uv))).reduce((best, area, at, areas) => (area > areas[best] ? at : best), 0);
|
|
147
|
+
const index = flagged >= 0 ? flagged : largest;
|
|
148
|
+
outer = plain[index];
|
|
149
|
+
holes = plain.filter((_, at) => at !== index);
|
|
150
|
+
}
|
|
151
|
+
else if (winding.length === 2) {
|
|
152
|
+
outer = this.stitched(surface, winding[0], winding[1]);
|
|
153
|
+
holes = plain;
|
|
154
|
+
}
|
|
155
|
+
else if (winding.length === 1) {
|
|
156
|
+
outer = this.closedAtPole(surface, winding[0], sameSense);
|
|
157
|
+
holes = plain;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
throw new UnsupportedGeometryError(`A face whose ${winding.length} loops wrap around its surface is not supported yet`);
|
|
161
|
+
}
|
|
162
|
+
const uv = [];
|
|
163
|
+
const positions = [];
|
|
164
|
+
const indices = [outer, ...holes.map((hole) => this.shiftedInto(surface, hole, outer))].map((loop) => loop.uv.map((point, at) => {
|
|
165
|
+
uv.push(point);
|
|
166
|
+
positions.push(loop.points[at]);
|
|
167
|
+
return uv.length - 1;
|
|
168
|
+
}));
|
|
169
|
+
return { uv, positions, indices };
|
|
170
|
+
}
|
|
171
|
+
shiftedInto(surface, hole, outer) {
|
|
172
|
+
const shift = [0, 1].map((axis) => {
|
|
173
|
+
const period = surface.periods[axis];
|
|
174
|
+
if (period === undefined) {
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
const low = Math.min(...outer.uv.map((point) => point[axis]));
|
|
178
|
+
const mean = hole.uv.reduce((sum, point) => sum + point[axis], 0) / hole.uv.length;
|
|
179
|
+
return -period * Math.floor((mean - low) / period);
|
|
180
|
+
});
|
|
181
|
+
return Object.assign(Object.assign({}, hole), { uv: hole.uv.map(([u, v]) => [u + shift[0], v + shift[1]]) });
|
|
182
|
+
}
|
|
183
|
+
stitched(surface, first, second) {
|
|
184
|
+
var _a;
|
|
185
|
+
const axis = first.winding[0] !== 0 ? 0 : 1;
|
|
186
|
+
const period = surface.periods[axis];
|
|
187
|
+
if (second.winding[axis] !== -first.winding[axis] || first.winding[1 - axis] !== 0 || second.winding[1 - axis] !== 0) {
|
|
188
|
+
throw new UnsupportedGeometryError("A face whose loops wrap around its surface the same way is not supported yet");
|
|
189
|
+
}
|
|
190
|
+
const shift = (point, by) => (axis === 0 ? [point[0] + by, point[1]] : [point[0], point[1] + by]);
|
|
191
|
+
const start = first.uv[0];
|
|
192
|
+
const closing = shift(start, first.winding[axis] * period);
|
|
193
|
+
const distances = second.uv.map((point) => {
|
|
194
|
+
const aligned = unwrapped(point[axis], closing[axis], period);
|
|
195
|
+
return Math.hypot(aligned - closing[axis], point[1 - axis] - closing[1 - axis]);
|
|
196
|
+
});
|
|
197
|
+
const join = distances.indexOf(Math.min(...distances));
|
|
198
|
+
const turned = [...second.uv.slice(join), ...second.uv.slice(0, join)];
|
|
199
|
+
const turnedPoints = [...second.points.slice(join), ...second.points.slice(0, join)];
|
|
200
|
+
const run = [];
|
|
201
|
+
for (const point of turned) {
|
|
202
|
+
const previous = (_a = run[run.length - 1]) !== null && _a !== void 0 ? _a : closing;
|
|
203
|
+
run.push(axis === 0 ? [unwrapped(point[0], previous[0], period), point[1]] : [point[0], unwrapped(point[1], previous[1], period)]);
|
|
204
|
+
}
|
|
205
|
+
const back = shift(run[0], second.winding[axis] * period);
|
|
206
|
+
const cut = this.across(surface, closing, run[0]);
|
|
207
|
+
const offset = second.winding[axis] * period;
|
|
208
|
+
const cutBack = [...cut.uv].reverse().map((point) => shift(point, offset));
|
|
209
|
+
return {
|
|
210
|
+
points: [...first.points, first.points[0], ...cut.points, ...turnedPoints, turnedPoints[0], ...[...cut.points].reverse()],
|
|
211
|
+
uv: [...first.uv, closing, ...cut.uv, ...run, back, ...cutBack],
|
|
212
|
+
winding: [0, 0],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
closedAtPole(surface, loop, sameSense) {
|
|
216
|
+
const axis = loop.winding[0] !== 0 ? 0 : 1;
|
|
217
|
+
const across = 1 - axis;
|
|
218
|
+
const direction = Math.sign(loop.winding[axis]);
|
|
219
|
+
const left = axis === 0 ? direction : -direction;
|
|
220
|
+
const pole = surface.pole(across, sameSense ? left : -left);
|
|
221
|
+
if (pole === undefined) {
|
|
222
|
+
throw new UnsupportedGeometryError("A face that wraps around its surface without closing over a pole is not supported yet");
|
|
223
|
+
}
|
|
224
|
+
const period = surface.periods[axis];
|
|
225
|
+
const start = loop.uv[0];
|
|
226
|
+
const end = axis === 0 ? [start[0] + loop.winding[0] * period, start[1]] : [start[0], start[1] + loop.winding[1] * period];
|
|
227
|
+
const atPole = (point) => (axis === 0 ? [point[0], pole] : [pole, point[1]]);
|
|
228
|
+
const poleUv = atPole(start);
|
|
229
|
+
const polePoint = surface.point(poleUv[0], poleUv[1]);
|
|
230
|
+
const up = this.across(surface, end, atPole(end));
|
|
231
|
+
const turn = loop.winding[axis] * period;
|
|
232
|
+
const down = [...up.uv].reverse().map(([u, v]) => (axis === 0 ? [u - turn, v] : [u, v - turn]));
|
|
233
|
+
return {
|
|
234
|
+
points: [...loop.points, loop.points[0], ...up.points, polePoint, polePoint, ...[...up.points].reverse()],
|
|
235
|
+
uv: [...loop.uv, end, ...up.uv, atPole(end), poleUv, ...down],
|
|
236
|
+
winding: [0, 0],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
across(surface, from, to) {
|
|
240
|
+
const at = (t) => [from[0] + (to[0] - from[0]) * t, from[1] + (to[1] - from[1]) * t];
|
|
241
|
+
let turned = 0;
|
|
242
|
+
let previous;
|
|
243
|
+
for (let step = 0; step <= CUT_SAMPLES; step++) {
|
|
244
|
+
const normal = this.surfaceNormal(surface, at(step / CUT_SAMPLES));
|
|
245
|
+
const length = length3(normal);
|
|
246
|
+
if (!(length > 0)) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
const unit = [normal[0] / length, normal[1] / length, normal[2] / length];
|
|
250
|
+
if (previous) {
|
|
251
|
+
turned += Math.acos(Math.max(-1, Math.min(1, dot3(previous, unit))));
|
|
252
|
+
}
|
|
253
|
+
previous = unit;
|
|
254
|
+
}
|
|
255
|
+
const segments = Math.min(CUT_SAMPLES, Math.max(1, Math.ceil(turned / CUT_TURN)));
|
|
256
|
+
const uv = Array.from({ length: segments - 1 }, (_, step) => at((step + 1) / segments));
|
|
257
|
+
return { uv, points: uv.map(([u, v]) => surface.point(u, v)) };
|
|
258
|
+
}
|
|
259
|
+
oriented(mesh, surface, uv, sameSense) {
|
|
260
|
+
let agreement = 0;
|
|
261
|
+
for (let at = 0; at + 2 < mesh.triangles.length; at += TRIANGLE_CORNERS) {
|
|
262
|
+
const [a, b, c] = [mesh.triangles[at], mesh.triangles[at + 1], mesh.triangles[at + 2]];
|
|
263
|
+
const normal = cross3(subtract3(mesh.positions[b], mesh.positions[a]), subtract3(mesh.positions[c], mesh.positions[a]));
|
|
264
|
+
if (a < uv.length && length3(normal) > 0) {
|
|
265
|
+
agreement += Math.sign(dot3(normal, this.surfaceNormal(surface, uv[a])));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if ((agreement >= 0) === sameSense) {
|
|
269
|
+
return mesh;
|
|
270
|
+
}
|
|
271
|
+
const triangles = [...mesh.triangles];
|
|
272
|
+
for (let at = 0; at + 2 < triangles.length; at += TRIANGLE_CORNERS) {
|
|
273
|
+
[triangles[at + 1], triangles[at + 2]] = [triangles[at + 2], triangles[at + 1]];
|
|
274
|
+
}
|
|
275
|
+
return { positions: mesh.positions, triangles };
|
|
276
|
+
}
|
|
277
|
+
surfaceNormal(surface, [u, v]) {
|
|
278
|
+
const step = NORMAL_STEP * Math.max(1, Math.abs(u), Math.abs(v));
|
|
279
|
+
return cross3(subtract3(surface.point(u + step, v), surface.point(u - step, v)), subtract3(surface.point(u, v + step), surface.point(u, v - step)));
|
|
280
|
+
}
|
|
281
|
+
value(id, name) {
|
|
282
|
+
return this.model.valueOf(this.model.peek(id), name);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
export function faceBounds(model, face) {
|
|
286
|
+
const known = model.referenceList(face);
|
|
287
|
+
if (known && model.typeOf(face) === "IfcFace") {
|
|
288
|
+
return known;
|
|
289
|
+
}
|
|
290
|
+
const bounds = model.valueOf(model.peek(face), "Bounds");
|
|
291
|
+
return (isList(bounds) ? bounds : []).filter(isReference).map((bound) => bound.ref);
|
|
292
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ModelSnapshot } from "../model/snapshot";
|
|
2
|
+
export declare function colourOf(model: ModelSnapshot, colours: Map<number, number[] | undefined>, product: number): number[] | undefined;
|
|
3
|
+
export declare function itemColour(model: ModelSnapshot, colours: Map<number, number[] | undefined>, item: number): number[] | undefined;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { materialOf } from "../build/materials";
|
|
2
|
+
import { isList, isReference } from "../step/values";
|
|
3
|
+
const OPAQUE = 1;
|
|
4
|
+
const MATERIAL_REPRESENTATION = "IfcMaterialDefinitionRepresentation";
|
|
5
|
+
const SURFACE_STYLE = "IfcSurfaceStyle";
|
|
6
|
+
const STYLE_ASSIGNMENT = "IfcPresentationStyleAssignment";
|
|
7
|
+
const STYLED_ITEM = "IfcStyledItem";
|
|
8
|
+
function materialsIn(model, definition) {
|
|
9
|
+
const type = model.entity(definition).type;
|
|
10
|
+
if (type === "IfcMaterial") {
|
|
11
|
+
return [definition];
|
|
12
|
+
}
|
|
13
|
+
if (type === "IfcMaterialLayerSetUsage") {
|
|
14
|
+
const set = model.attribute(definition, "ForLayerSet");
|
|
15
|
+
return isReference(set) ? materialsIn(model, set.ref) : [];
|
|
16
|
+
}
|
|
17
|
+
if (type === "IfcMaterialLayerSet") {
|
|
18
|
+
const layers = model.attribute(definition, "MaterialLayers");
|
|
19
|
+
return (isList(layers) ? layers : []).filter(isReference).flatMap((layer) => {
|
|
20
|
+
const material = model.attribute(layer.ref, "Material");
|
|
21
|
+
return isReference(material) ? [material.ref] : [];
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
function shadingColour(model, style) {
|
|
27
|
+
const styles = model.attribute(style, "Styles");
|
|
28
|
+
for (const element of isList(styles) ? styles : []) {
|
|
29
|
+
if (!isReference(element) || !model.schema.isSubtypeOf(model.entity(element.ref).type, "IfcSurfaceStyleShading")) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const colour = model.attribute(element.ref, "SurfaceColour");
|
|
33
|
+
if (!isReference(colour)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const channels = ["Red", "Green", "Blue"].map((name) => model.attribute(colour.ref, name));
|
|
37
|
+
const transparency = model.attribute(element.ref, "Transparency");
|
|
38
|
+
if (channels.every((channel) => typeof channel === "number")) {
|
|
39
|
+
return [...channels, OPAQUE - (typeof transparency === "number" ? transparency : 0)];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
function stylesColour(model, styles, insideAssignment = false) {
|
|
45
|
+
for (const style of (isList(styles) ? styles : []).filter(isReference)) {
|
|
46
|
+
const type = model.typeOf(style.ref);
|
|
47
|
+
const colour = type === SURFACE_STYLE
|
|
48
|
+
? shadingColour(model, style.ref)
|
|
49
|
+
: type === STYLE_ASSIGNMENT && !insideAssignment ? stylesColour(model, model.attribute(style.ref, "Styles"), true) : undefined;
|
|
50
|
+
if (colour) {
|
|
51
|
+
return colour;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
function representedColour(model, definition) {
|
|
57
|
+
const representations = model.attribute(definition, "Representations");
|
|
58
|
+
for (const representation of (isList(representations) ? representations : []).filter(isReference)) {
|
|
59
|
+
const items = model.attribute(representation.ref, "Items");
|
|
60
|
+
for (const item of (isList(items) ? items : []).filter(isReference)) {
|
|
61
|
+
const colour = stylesColour(model, model.attribute(item.ref, "Styles"));
|
|
62
|
+
if (colour) {
|
|
63
|
+
return colour;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
function colourOfMaterial(model, material) {
|
|
70
|
+
for (const user of model.referencesTo(material)) {
|
|
71
|
+
const represented = model.typeOf(user) === MATERIAL_REPRESENTATION ? model.attribute(user, "RepresentedMaterial") : null;
|
|
72
|
+
const colour = isReference(represented) && represented.ref === material ? representedColour(model, user) : undefined;
|
|
73
|
+
if (colour) {
|
|
74
|
+
return colour;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
export function colourOf(model, colours, product) {
|
|
80
|
+
const definition = materialOf(model, product);
|
|
81
|
+
if (definition === undefined) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
for (const material of materialsIn(model, definition)) {
|
|
85
|
+
if (!colours.has(material)) {
|
|
86
|
+
colours.set(material, colourOfMaterial(model, material));
|
|
87
|
+
}
|
|
88
|
+
const colour = colours.get(material);
|
|
89
|
+
if (colour) {
|
|
90
|
+
return colour;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
export function itemColour(model, colours, item) {
|
|
96
|
+
if (colours.has(item)) {
|
|
97
|
+
return colours.get(item);
|
|
98
|
+
}
|
|
99
|
+
let colour;
|
|
100
|
+
for (const user of model.referencesTo(item)) {
|
|
101
|
+
const styled = model.typeOf(user) === STYLED_ITEM ? model.attribute(user, "Item") : null;
|
|
102
|
+
colour = isReference(styled) && styled.ref === item ? stylesColour(model, model.attribute(user, "Styles")) : undefined;
|
|
103
|
+
if (colour) {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
colours.set(item, colour);
|
|
108
|
+
return colour;
|
|
109
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Base } from "@bitbybit-dev/base";
|
|
2
|
+
import { type FrameAxes } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
|
|
3
|
+
import type { ModelSnapshot } from "../model/snapshot";
|
|
4
|
+
import type { BSplineCurve, ConicFrame } from "./geometry-types";
|
|
5
|
+
export declare function arcSegments(sweep: number): number;
|
|
6
|
+
export declare function sweepBetween(start: number, end: number, counterClockwise: boolean): number;
|
|
7
|
+
export declare class CurveSampler {
|
|
8
|
+
private readonly model;
|
|
9
|
+
private readonly density;
|
|
10
|
+
private angleUnit;
|
|
11
|
+
constructor(model: ModelSnapshot, density?: number);
|
|
12
|
+
outline(curve: number, plane?: FrameAxes): Base.Point2[];
|
|
13
|
+
path(curve: number): Base.Point3[];
|
|
14
|
+
endTangents(curve: number, depth?: number): readonly [Base.Vector3 | undefined, Base.Vector3 | undefined];
|
|
15
|
+
parameterSpan(curve: number): number | undefined;
|
|
16
|
+
planeOf(curve: number): FrameAxes | undefined;
|
|
17
|
+
private get radiansPerUnit();
|
|
18
|
+
private sampled;
|
|
19
|
+
private polylinePoints;
|
|
20
|
+
private polylineIn;
|
|
21
|
+
private indexed;
|
|
22
|
+
private composite;
|
|
23
|
+
private trimOf;
|
|
24
|
+
private trimmed;
|
|
25
|
+
private linePoint;
|
|
26
|
+
private conicAngle;
|
|
27
|
+
conicFrame(conic: number): ConicFrame;
|
|
28
|
+
bspline(curve: number): BSplineCurve;
|
|
29
|
+
splinePoints(spline: BSplineCurve, from: number, to: number): Base.Point3[];
|
|
30
|
+
private conicTangent;
|
|
31
|
+
private conic;
|
|
32
|
+
}
|