@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.
Files changed (242) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +42 -0
  3. package/README.md +92 -2
  4. package/index.d.ts +1 -0
  5. package/index.js +1 -0
  6. package/lib/api/dto-registry.d.ts +8 -0
  7. package/lib/api/dto-registry.js +109 -0
  8. package/lib/api/ifc-service.d.ts +109 -0
  9. package/lib/api/ifc-service.js +55 -0
  10. package/lib/api/inputs/base-inputs.d.ts +5 -0
  11. package/lib/api/inputs/base-inputs.js +5 -0
  12. package/lib/api/inputs/ifc-inputs.d.ts +2727 -0
  13. package/lib/api/inputs/ifc-inputs.js +2498 -0
  14. package/lib/api/inputs/index.d.ts +3 -0
  15. package/lib/api/inputs/index.js +3 -0
  16. package/lib/api/resolved-inputs/index.d.ts +70 -0
  17. package/lib/api/resolved-inputs/index.js +1 -0
  18. package/lib/api/services/assemblies.d.ts +28 -0
  19. package/lib/api/services/assemblies.js +49 -0
  20. package/lib/api/services/beams.d.ts +33 -0
  21. package/lib/api/services/beams.js +59 -0
  22. package/lib/api/services/columns.d.ts +26 -0
  23. package/lib/api/services/columns.js +56 -0
  24. package/lib/api/services/defaults.constants.d.ts +44 -0
  25. package/lib/api/services/defaults.constants.js +44 -0
  26. package/lib/api/services/doors.d.ts +45 -0
  27. package/lib/api/services/doors.js +94 -0
  28. package/lib/api/services/geometry.d.ts +51 -0
  29. package/lib/api/services/geometry.js +87 -0
  30. package/lib/api/services/index.d.ts +17 -0
  31. package/lib/api/services/index.js +17 -0
  32. package/lib/api/services/materials.d.ts +46 -0
  33. package/lib/api/services/materials.js +86 -0
  34. package/lib/api/services/member-support.d.ts +7 -0
  35. package/lib/api/services/member-support.js +29 -0
  36. package/lib/api/services/members.d.ts +24 -0
  37. package/lib/api/services/members.js +51 -0
  38. package/lib/api/services/model.d.ts +244 -0
  39. package/lib/api/services/model.js +409 -0
  40. package/lib/api/services/openings.d.ts +57 -0
  41. package/lib/api/services/openings.js +102 -0
  42. package/lib/api/services/properties.d.ts +89 -0
  43. package/lib/api/services/properties.js +142 -0
  44. package/lib/api/services/quantities.d.ts +38 -0
  45. package/lib/api/services/quantities.js +51 -0
  46. package/lib/api/services/roofs.d.ts +24 -0
  47. package/lib/api/services/roofs.js +52 -0
  48. package/lib/api/services/service-support.d.ts +8 -0
  49. package/lib/api/services/service-support.js +37 -0
  50. package/lib/api/services/service-types.d.ts +3 -0
  51. package/lib/api/services/service-types.js +1 -0
  52. package/lib/api/services/site.d.ts +37 -0
  53. package/lib/api/services/site.js +80 -0
  54. package/lib/api/services/slabs.d.ts +31 -0
  55. package/lib/api/services/slabs.js +59 -0
  56. package/lib/api/services/spaces.d.ts +36 -0
  57. package/lib/api/services/spaces.js +64 -0
  58. package/lib/api/services/spatial.d.ts +54 -0
  59. package/lib/api/services/spatial.js +75 -0
  60. package/lib/api/services/walls.d.ts +140 -0
  61. package/lib/api/services/walls.js +268 -0
  62. package/lib/api/services/windows.d.ts +46 -0
  63. package/lib/api/services/windows.js +76 -0
  64. package/lib/build/assemblies.d.ts +4 -0
  65. package/lib/build/assemblies.js +45 -0
  66. package/lib/build/build-types.d.ts +345 -0
  67. package/lib/build/build-types.js +1 -0
  68. package/lib/build/checks.d.ts +6 -0
  69. package/lib/build/checks.js +32 -0
  70. package/lib/build/constants.d.ts +27 -0
  71. package/lib/build/constants.js +43 -0
  72. package/lib/build/contexts.d.ts +9 -0
  73. package/lib/build/contexts.js +52 -0
  74. package/lib/build/curves.d.ts +3 -0
  75. package/lib/build/curves.js +23 -0
  76. package/lib/build/entity-writer.d.ts +23 -0
  77. package/lib/build/entity-writer.js +97 -0
  78. package/lib/build/fillings.d.ts +7 -0
  79. package/lib/build/fillings.js +182 -0
  80. package/lib/build/georeference.d.ts +5 -0
  81. package/lib/build/georeference.js +44 -0
  82. package/lib/build/materials.d.ts +18 -0
  83. package/lib/build/materials.js +166 -0
  84. package/lib/build/math.d.ts +10 -0
  85. package/lib/build/math.js +47 -0
  86. package/lib/build/measure.d.ts +9 -0
  87. package/lib/build/measure.js +195 -0
  88. package/lib/build/moving.d.ts +4 -0
  89. package/lib/build/moving.js +61 -0
  90. package/lib/build/openings.d.ts +12 -0
  91. package/lib/build/openings.js +156 -0
  92. package/lib/build/outlines.d.ts +4 -0
  93. package/lib/build/outlines.js +40 -0
  94. package/lib/build/placement.d.ts +16 -0
  95. package/lib/build/placement.js +106 -0
  96. package/lib/build/profiles.d.ts +4 -0
  97. package/lib/build/profiles.js +35 -0
  98. package/lib/build/project.d.ts +11 -0
  99. package/lib/build/project.js +134 -0
  100. package/lib/build/properties.d.ts +10 -0
  101. package/lib/build/properties.js +182 -0
  102. package/lib/build/quantities.d.ts +7 -0
  103. package/lib/build/quantities.js +262 -0
  104. package/lib/build/relationships.d.ts +9 -0
  105. package/lib/build/relationships.js +67 -0
  106. package/lib/build/removal.d.ts +3 -0
  107. package/lib/build/removal.js +106 -0
  108. package/lib/build/representations.d.ts +6 -0
  109. package/lib/build/representations.js +46 -0
  110. package/lib/build/roof-clipping.d.ts +5 -0
  111. package/lib/build/roof-clipping.js +79 -0
  112. package/lib/build/roofs.d.ts +4 -0
  113. package/lib/build/roofs.js +131 -0
  114. package/lib/build/site.d.ts +7 -0
  115. package/lib/build/site.js +112 -0
  116. package/lib/build/slab-openings.d.ts +4 -0
  117. package/lib/build/slab-openings.js +71 -0
  118. package/lib/build/slabs-columns-beams.d.ts +8 -0
  119. package/lib/build/slabs-columns-beams.js +73 -0
  120. package/lib/build/solids.d.ts +5 -0
  121. package/lib/build/solids.js +33 -0
  122. package/lib/build/spaces.d.ts +6 -0
  123. package/lib/build/spaces.js +55 -0
  124. package/lib/build/spatial.d.ts +17 -0
  125. package/lib/build/spatial.js +111 -0
  126. package/lib/build/type-objects.d.ts +4 -0
  127. package/lib/build/type-objects.js +9 -0
  128. package/lib/build/wall-edits.d.ts +5 -0
  129. package/lib/build/wall-edits.js +138 -0
  130. package/lib/build/wall-geometry.d.ts +15 -0
  131. package/lib/build/wall-geometry.js +159 -0
  132. package/lib/build/wall-parameters.d.ts +3 -0
  133. package/lib/build/wall-parameters.js +47 -0
  134. package/lib/build/walls.d.ts +12 -0
  135. package/lib/build/walls.js +238 -0
  136. package/lib/geometry/advanced.d.ts +27 -0
  137. package/lib/geometry/advanced.js +292 -0
  138. package/lib/geometry/colours.d.ts +3 -0
  139. package/lib/geometry/colours.js +109 -0
  140. package/lib/geometry/curves.d.ts +32 -0
  141. package/lib/geometry/curves.js +370 -0
  142. package/lib/geometry/edges.constants.d.ts +5 -0
  143. package/lib/geometry/edges.constants.js +5 -0
  144. package/lib/geometry/edges.d.ts +21 -0
  145. package/lib/geometry/edges.js +164 -0
  146. package/lib/geometry/elements.d.ts +3 -0
  147. package/lib/geometry/elements.js +152 -0
  148. package/lib/geometry/errors.d.ts +3 -0
  149. package/lib/geometry/errors.js +6 -0
  150. package/lib/geometry/faceted.d.ts +31 -0
  151. package/lib/geometry/faceted.js +214 -0
  152. package/lib/geometry/geometry-types.d.ts +103 -0
  153. package/lib/geometry/geometry-types.js +1 -0
  154. package/lib/geometry/groups.d.ts +21 -0
  155. package/lib/geometry/groups.js +106 -0
  156. package/lib/geometry/items.d.ts +34 -0
  157. package/lib/geometry/items.js +313 -0
  158. package/lib/geometry/operators.d.ts +3 -0
  159. package/lib/geometry/operators.js +65 -0
  160. package/lib/geometry/profiles.d.ts +4 -0
  161. package/lib/geometry/profiles.js +277 -0
  162. package/lib/geometry/recipe-builder.d.ts +14 -0
  163. package/lib/geometry/recipe-builder.js +48 -0
  164. package/lib/geometry/references.d.ts +4 -0
  165. package/lib/geometry/references.js +17 -0
  166. package/lib/geometry/regions.d.ts +4 -0
  167. package/lib/geometry/regions.js +26 -0
  168. package/lib/geometry/surfaces.constants.d.ts +17 -0
  169. package/lib/geometry/surfaces.constants.js +17 -0
  170. package/lib/geometry/surfaces.d.ts +6 -0
  171. package/lib/geometry/surfaces.js +306 -0
  172. package/lib/geometry/swept-solids.constants.d.ts +7 -0
  173. package/lib/geometry/swept-solids.constants.js +6 -0
  174. package/lib/geometry/swept-solids.d.ts +25 -0
  175. package/lib/geometry/swept-solids.js +243 -0
  176. package/lib/index.d.ts +6 -0
  177. package/lib/index.js +6 -0
  178. package/lib/model/constants.d.ts +30 -0
  179. package/lib/model/constants.js +30 -0
  180. package/lib/model/entity-lookup.d.ts +9 -0
  181. package/lib/model/entity-lookup.js +20 -0
  182. package/lib/model/guid.d.ts +7 -0
  183. package/lib/model/guid.js +60 -0
  184. package/lib/model/id-map.d.ts +10 -0
  185. package/lib/model/id-map.js +80 -0
  186. package/lib/model/index.d.ts +4 -0
  187. package/lib/model/index.js +2 -0
  188. package/lib/model/io.d.ts +6 -0
  189. package/lib/model/io.js +136 -0
  190. package/lib/model/is-model.d.ts +9 -0
  191. package/lib/model/is-model.js +11 -0
  192. package/lib/model/model-types.d.ts +111 -0
  193. package/lib/model/model-types.js +1 -0
  194. package/lib/model/overlay-indexes.d.ts +17 -0
  195. package/lib/model/overlay-indexes.js +69 -0
  196. package/lib/model/references.d.ts +2 -0
  197. package/lib/model/references.js +51 -0
  198. package/lib/model/rows-by-id.d.ts +8 -0
  199. package/lib/model/rows-by-id.js +39 -0
  200. package/lib/model/snapshot.d.ts +36 -0
  201. package/lib/model/snapshot.js +144 -0
  202. package/lib/model/source.d.ts +29 -0
  203. package/lib/model/source.js +172 -0
  204. package/lib/model/transaction.d.ts +39 -0
  205. package/lib/model/transaction.js +250 -0
  206. package/lib/model/upgrade.d.ts +2 -0
  207. package/lib/model/upgrade.js +78 -0
  208. package/lib/schema/constants.d.ts +3 -0
  209. package/lib/schema/constants.js +3 -0
  210. package/lib/schema/generated/ifc4.d.ts +2 -0
  211. package/lib/schema/generated/ifc4.js +1204 -0
  212. package/lib/schema/generated/ifc4x3.d.ts +2 -0
  213. package/lib/schema/generated/ifc4x3.js +1325 -0
  214. package/lib/schema/registry.d.ts +7 -0
  215. package/lib/schema/registry.js +37 -0
  216. package/lib/schema/schema-types.d.ts +45 -0
  217. package/lib/schema/schema-types.js +1 -0
  218. package/lib/schema/schema.d.ts +23 -0
  219. package/lib/schema/schema.js +136 -0
  220. package/lib/step/constants.d.ts +48 -0
  221. package/lib/step/constants.js +48 -0
  222. package/lib/step/encoder.d.ts +21 -0
  223. package/lib/step/encoder.js +321 -0
  224. package/lib/step/errors.d.ts +39 -0
  225. package/lib/step/errors.js +45 -0
  226. package/lib/step/file-index.d.ts +2 -0
  227. package/lib/step/file-index.js +221 -0
  228. package/lib/step/header.d.ts +4 -0
  229. package/lib/step/header.js +52 -0
  230. package/lib/step/numbers.d.ts +3 -0
  231. package/lib/step/numbers.js +73 -0
  232. package/lib/step/reader.d.ts +2 -0
  233. package/lib/step/reader.js +160 -0
  234. package/lib/step/scanner.d.ts +13 -0
  235. package/lib/step/scanner.js +203 -0
  236. package/lib/step/step-types.d.ts +170 -0
  237. package/lib/step/step-types.js +1 -0
  238. package/lib/step/strings.d.ts +2 -0
  239. package/lib/step/strings.js +150 -0
  240. package/lib/step/values.d.ts +13 -0
  241. package/lib/step/values.js +51 -0
  242. package/package.json +51 -5
@@ -0,0 +1,152 @@
1
+ import { axesToMatrix, relativeAxes } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
2
+ import { absoluteFrame, objectPlacementOf } from "../build/placement";
3
+ import { isList, isReference } from "../step/values";
4
+ import { colourOf } from "./colours";
5
+ import { ItemConverter } from "./items";
6
+ import { RecipeGroups } from "./groups";
7
+ import { RecipeBuilder } from "./recipe-builder";
8
+ const BODY = "Body";
9
+ const PRODUCT = "IfcProduct";
10
+ const VOIDS = "IfcRelVoidsElement";
11
+ const MODEL_CONTEXT = "Model";
12
+ const SUB_CONTEXT = "IfcGeometricRepresentationSubContext";
13
+ const REACH_MILLIMETRES = 1e6;
14
+ const NO_BODY = `The element has no '${BODY}' representation in a '${MODEL_CONTEXT}' context`;
15
+ const SKIPPED = {
16
+ IfcOpeningElement: "is cut from the element it voids, not described on its own",
17
+ IfcSpatialElement: "is a spatial element, which a recipe does not describe",
18
+ IfcAnnotation: "is an annotation, which a recipe does not describe",
19
+ };
20
+ function skipReason(model, type) {
21
+ for (const [skipped, reason] of Object.entries(SKIPPED)) {
22
+ if (model.schema.isSubtypeOf(type, skipped)) {
23
+ return `An ${type} ${reason}`;
24
+ }
25
+ }
26
+ return undefined;
27
+ }
28
+ function isModelContext(model, context) {
29
+ const own = model.attribute(context, "ContextType");
30
+ if (typeof own === "string" || !model.schema.isSubtypeOf(model.entity(context).type, SUB_CONTEXT)) {
31
+ return own === MODEL_CONTEXT;
32
+ }
33
+ const parent = model.attribute(context, "ParentContext");
34
+ return isReference(parent) && model.attribute(parent.ref, "ContextType") === MODEL_CONTEXT;
35
+ }
36
+ function bodyOf(model, product) {
37
+ const shape = model.attribute(product, "Representation");
38
+ if (!isReference(shape)) {
39
+ return undefined;
40
+ }
41
+ const representations = model.attribute(shape.ref, "Representations");
42
+ for (const representation of isList(representations) ? representations : []) {
43
+ if (!isReference(representation) || model.attribute(representation.ref, "RepresentationIdentifier") !== BODY) {
44
+ continue;
45
+ }
46
+ const context = model.attribute(representation.ref, "ContextOfItems");
47
+ if (isReference(context) && isModelContext(model, context.ref)) {
48
+ return representation.ref;
49
+ }
50
+ }
51
+ return undefined;
52
+ }
53
+ function addOpening(openings, model, rel) {
54
+ const host = model.attribute(rel, "RelatingBuildingElement");
55
+ const opening = model.attribute(rel, "RelatedOpeningElement");
56
+ if (!isReference(host) || !isReference(opening)) {
57
+ return;
58
+ }
59
+ const known = openings.get(host.ref);
60
+ if (known) {
61
+ known.push(opening.ref);
62
+ }
63
+ else {
64
+ openings.set(host.ref, [opening.ref]);
65
+ }
66
+ }
67
+ function openingsOf(model, products) {
68
+ const openings = new Map();
69
+ if (products === undefined) {
70
+ model.byType(VOIDS).forEach((rel) => addOpening(openings, model, rel.id));
71
+ return openings;
72
+ }
73
+ for (const product of products) {
74
+ const voids = model.referencesTo(product.id).filter((user) => { var _a; return model.schema.isSubtypeOf((_a = model.typeOf(user)) !== null && _a !== void 0 ? _a : "", VOIDS); });
75
+ voids.forEach((rel) => addOpening(openings, model, rel));
76
+ }
77
+ return openings;
78
+ }
79
+ function productsOf(model, wanted) {
80
+ if (wanted === undefined) {
81
+ return model.byType(PRODUCT);
82
+ }
83
+ const ids = new Set([...wanted].flatMap((globalId) => model.globalIdOwners(globalId)));
84
+ return [...ids].filter((id) => { var _a; return model.schema.isSubtypeOf((_a = model.typeOf(id)) !== null && _a !== void 0 ? _a : "", PRODUCT); }).sort((a, b) => a - b).map((id) => model.entity(id));
85
+ }
86
+ function frameOf(model, product, known) {
87
+ return absoluteFrame(model, objectPlacementOf(model, product), known);
88
+ }
89
+ function precisionOf(model, fallback) {
90
+ for (const context of model.byType("IfcGeometricRepresentationContext", false)) {
91
+ const precision = model.attribute(context.id, "Precision");
92
+ if (model.attribute(context.id, "ContextType") === MODEL_CONTEXT && typeof precision === "number" && precision > 0) {
93
+ return precision;
94
+ }
95
+ }
96
+ return fallback;
97
+ }
98
+ export function modelRecipe(model, globalIds, millimetresPerUnit, fallbackTolerance, isGroupedByClass = true) {
99
+ var _a, _b;
100
+ const builder = new RecipeBuilder();
101
+ const groups = new RecipeGroups(model, isGroupedByClass);
102
+ const converter = new ItemConverter(model, builder, REACH_MILLIMETRES / millimetresPerUnit);
103
+ const colours = new Map();
104
+ const frames = new Map();
105
+ const problems = [];
106
+ const wanted = globalIds === undefined ? undefined : new Set(globalIds);
107
+ const products = productsOf(model, wanted);
108
+ const openings = openingsOf(model, wanted === undefined ? undefined : products);
109
+ for (const product of products) {
110
+ const globalId = model.attribute(product.id, "GlobalId");
111
+ if (typeof globalId !== "string" || (wanted && !wanted.has(globalId))) {
112
+ continue;
113
+ }
114
+ const skipped = skipReason(model, product.type);
115
+ if (skipped !== undefined) {
116
+ if (wanted) {
117
+ problems.push({ globalId, type: product.type, message: skipped });
118
+ }
119
+ continue;
120
+ }
121
+ try {
122
+ const body = bodyOf(model, product.id);
123
+ if (body === undefined) {
124
+ if (wanted) {
125
+ problems.push({ globalId, type: product.type, message: NO_BODY });
126
+ }
127
+ continue;
128
+ }
129
+ const frame = frameOf(model, product.id, frames);
130
+ const parts = converter.parts(body);
131
+ const cuts = ((_a = openings.get(product.id)) !== null && _a !== void 0 ? _a : []).flatMap((opening) => {
132
+ const openingBody = bodyOf(model, opening);
133
+ if (openingBody === undefined) {
134
+ return [];
135
+ }
136
+ const matrix = axesToMatrix(relativeAxes(frame, frameOf(model, opening, frames)));
137
+ return [builder.node({ op: "transform", of: converter.representation(openingBody), matrix })];
138
+ });
139
+ const name = model.attribute(product.id, "Name");
140
+ const material = parts.some((part) => !part.rgba) ? colourOf(model, colours, product.id) : undefined;
141
+ const group = groups.groupOf(product.id);
142
+ for (const part of parts) {
143
+ const rgba = (_b = part.rgba) !== null && _b !== void 0 ? _b : material;
144
+ builder.root(Object.assign({ node: cuts.length ? builder.node({ op: "voids", host: part.node, openings: cuts }) : part.node, matrix: axesToMatrix(frame), tag: Object.assign({ globalId, type: product.type, name: typeof name === "string" ? name : "" }, (rgba ? { rgba: [...rgba] } : {})) }, (group === undefined ? {} : { group })));
145
+ }
146
+ }
147
+ catch (error) {
148
+ problems.push({ globalId, type: product.type, message: error instanceof Error ? error.message : String(error) });
149
+ }
150
+ }
151
+ return { recipe: builder.build(millimetresPerUnit, precisionOf(model, fallbackTolerance), groups.list()), problems };
152
+ }
@@ -0,0 +1,3 @@
1
+ export declare class UnsupportedGeometryError extends Error {
2
+ constructor(message: string);
3
+ }
@@ -0,0 +1,6 @@
1
+ export class UnsupportedGeometryError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "UnsupportedGeometryError";
5
+ }
6
+ }
@@ -0,0 +1,31 @@
1
+ import type { ModelSnapshot } from "../model/snapshot";
2
+ import type { IfcValue } from "../step/step-types";
3
+ import type { TriangleMesh } from "./geometry-types";
4
+ export declare const OUTWARD = 1;
5
+ export declare const INWARD = -1;
6
+ export declare const UNORIENTED = 0;
7
+ export declare function zeroBased(value: IfcValue, count: number, what: string, of: string): number[];
8
+ export declare function concatenated(meshes: readonly TriangleMesh[]): TriangleMesh;
9
+ export declare class MeshCollector {
10
+ private readonly model;
11
+ private readonly positions;
12
+ private readonly indices;
13
+ private readonly vertexOfPoint;
14
+ private readonly vertexAt;
15
+ private advanced;
16
+ constructor(model: ModelSnapshot);
17
+ get mesh(): TriangleMesh;
18
+ shell(shell: number, sense: number): void;
19
+ triangulatedFaces(item: number): void;
20
+ polygonalFaces(item: number): void;
21
+ private indexedPoints;
22
+ private references;
23
+ private face;
24
+ private loopTypeOf;
25
+ private surfaceMesh;
26
+ private loop;
27
+ private vertex;
28
+ private welded;
29
+ private add;
30
+ private orient;
31
+ }
@@ -0,0 +1,214 @@
1
+ import { signedVolumeOf } from "@bitbybit-dev/base/lib/api/services/helpers/mesh-measures";
2
+ import { newellNormal, triangulateFace } from "@bitbybit-dev/base/lib/api/services/helpers/triangulation";
3
+ import { POINT3_SIZE } from "../build/constants";
4
+ import { numbersOf } from "../build/placement";
5
+ import { isList, isReference } from "../step/values";
6
+ import { AdvancedFaces, faceBounds } from "./advanced";
7
+ import { CurveSampler } from "./curves";
8
+ import { EdgeSampler } from "./edges";
9
+ import { referencesIn, referencesOf } from "./references";
10
+ import { UnsupportedGeometryError } from "./errors";
11
+ export const OUTWARD = 1;
12
+ export const INWARD = -1;
13
+ export const UNORIENTED = 0;
14
+ const TRIANGLE_CORNERS = 3;
15
+ const OUTER_BOUND = "IfcFaceOuterBound";
16
+ const POLY_LOOP = "IfcPolyLoop";
17
+ const FACE_WITH_VOIDS = "IfcIndexedPolygonalFaceWithVoids";
18
+ const SURFACE_FACES = new Set(["IfcAdvancedFace", "IfcFaceSurface"]);
19
+ export function zeroBased(value, count, what, of) {
20
+ if (!isList(value) || !value.every((index) => typeof index === "number" && Number.isSafeInteger(index))) {
21
+ throw new UnsupportedGeometryError(`${what} is not a list of indices`);
22
+ }
23
+ return value.map((index) => {
24
+ if (index < 1 || index > count) {
25
+ throw new UnsupportedGeometryError(`${what} names ${index}, outside the ${count} ${of}`);
26
+ }
27
+ return index - 1;
28
+ });
29
+ }
30
+ export function concatenated(meshes) {
31
+ const positions = [];
32
+ const indices = [];
33
+ for (const mesh of meshes) {
34
+ const offset = positions.length / POINT3_SIZE;
35
+ for (const value of mesh.positions) {
36
+ positions.push(value);
37
+ }
38
+ for (const vertex of mesh.indices) {
39
+ indices.push(vertex + offset);
40
+ }
41
+ }
42
+ return { positions, indices };
43
+ }
44
+ function isPointIndex(value) {
45
+ return isList(value) && value.length > 0 && !value.some(isList);
46
+ }
47
+ export class MeshCollector {
48
+ constructor(model) {
49
+ this.positions = [];
50
+ this.indices = [];
51
+ this.vertexOfPoint = new Map();
52
+ this.vertexAt = new Map();
53
+ this.model = model;
54
+ }
55
+ get mesh() {
56
+ return { positions: this.positions, indices: this.indices };
57
+ }
58
+ shell(shell, sense) {
59
+ const first = this.indices.length;
60
+ for (const face of this.references(shell, "CfsFaces")) {
61
+ this.face(face);
62
+ }
63
+ this.orient(first, sense);
64
+ }
65
+ triangulatedFaces(item) {
66
+ const entity = this.model.peek(item);
67
+ const vertices = this.indexedPoints(item, entity);
68
+ const first = this.indices.length;
69
+ const triangles = this.model.valueOf(entity, "CoordIndex");
70
+ (isList(triangles) ? triangles : []).forEach((triangle, at) => {
71
+ const what = `#${item} triangle ${at}`;
72
+ const corners = vertices(triangle, what);
73
+ if (corners.length !== TRIANGLE_CORNERS) {
74
+ throw new UnsupportedGeometryError(`${what} has ${corners.length} corners, not ${TRIANGLE_CORNERS}`);
75
+ }
76
+ this.add(corners);
77
+ });
78
+ this.orient(first, this.model.valueOf(entity, "Closed") === true ? OUTWARD : UNORIENTED);
79
+ }
80
+ polygonalFaces(item) {
81
+ const entity = this.model.peek(item);
82
+ const vertices = this.indexedPoints(item, entity);
83
+ const first = this.indices.length;
84
+ for (const face of referencesOf(this.model.valueOf(entity, "Faces"), `#${item} Faces`)) {
85
+ const faceEntity = this.model.peek(face);
86
+ const outer = vertices(this.model.valueOf(faceEntity, "CoordIndex"), `#${face} CoordIndex`);
87
+ const inner = this.model.schema.isSubtypeOf(faceEntity.type, FACE_WITH_VOIDS) ? this.model.valueOf(faceEntity, "InnerCoordIndices") : null;
88
+ const holes = (isList(inner) ? inner : []).map((hole, at) => vertices(hole, `#${face} inner loop ${at}`));
89
+ this.add(triangulateFace(this.positions, [outer, ...holes]));
90
+ }
91
+ this.orient(first, this.model.valueOf(entity, "Closed") === true ? OUTWARD : UNORIENTED);
92
+ }
93
+ indexedPoints(item, entity) {
94
+ const coordinates = this.model.valueOf(entity, "Coordinates");
95
+ if (!isReference(coordinates)) {
96
+ throw new UnsupportedGeometryError(`#${item} has no coordinates`);
97
+ }
98
+ const list = this.model.valueOf(this.model.peek(coordinates.ref), "CoordList");
99
+ const points = isList(list) ? list : [];
100
+ const offset = this.positions.length / POINT3_SIZE;
101
+ points.forEach((point, index) => {
102
+ var _a, _b, _c;
103
+ const numbers = numbersOf(point, `#${coordinates.ref} point ${index}`);
104
+ this.positions.push((_a = numbers[0]) !== null && _a !== void 0 ? _a : 0, (_b = numbers[1]) !== null && _b !== void 0 ? _b : 0, (_c = numbers[2]) !== null && _c !== void 0 ? _c : 0);
105
+ });
106
+ const pointIndex = this.model.valueOf(entity, "PnIndex");
107
+ const lookup = isPointIndex(pointIndex) ? zeroBased(pointIndex, points.length, `#${item} PnIndex`, "points") : undefined;
108
+ return (value, what) => (lookup
109
+ ? zeroBased(value, lookup.length, what, "entries of PnIndex").map((entry) => lookup[entry] + offset)
110
+ : zeroBased(value, points.length, what, "points").map((index) => index + offset));
111
+ }
112
+ references(id, attribute) {
113
+ return referencesIn(this.model, id, attribute);
114
+ }
115
+ face(face) {
116
+ var _a, _b;
117
+ const bounds = faceBounds(this.model, face);
118
+ if (SURFACE_FACES.has((_a = this.model.typeOf(face)) !== null && _a !== void 0 ? _a : "") || bounds.some((bound) => this.loopTypeOf(bound) !== POLY_LOOP)) {
119
+ if (!this.advanced) {
120
+ const curves = new CurveSampler(this.model);
121
+ this.advanced = new AdvancedFaces(this.model, curves, new EdgeSampler(this.model, curves));
122
+ }
123
+ this.surfaceMesh(this.advanced.face(face, bounds));
124
+ return;
125
+ }
126
+ const loops = [];
127
+ let outer = -1;
128
+ for (const bound of bounds) {
129
+ const boundEntity = this.model.peek(bound);
130
+ const loop = this.model.valueOf(boundEntity, "Bound");
131
+ if (!isReference(loop)) {
132
+ throw new UnsupportedGeometryError(`#${bound} has no loop`);
133
+ }
134
+ const vertices = this.loop(loop.ref);
135
+ if (this.model.valueOf(boundEntity, "Orientation") === false) {
136
+ vertices.reverse();
137
+ }
138
+ if (outer < 0 && this.model.schema.isSubtypeOf(boundEntity.type, OUTER_BOUND)) {
139
+ outer = loops.length;
140
+ }
141
+ loops.push(vertices);
142
+ }
143
+ if (outer < 0) {
144
+ const spans = loops.map((loop) => Math.hypot(...newellNormal(this.positions, loop)));
145
+ outer = spans.indexOf(Math.max(...spans));
146
+ }
147
+ this.add(triangulateFace(this.positions, [(_b = loops[outer]) !== null && _b !== void 0 ? _b : [], ...loops.filter((_, at) => at !== outer)]));
148
+ }
149
+ loopTypeOf(bound) {
150
+ const loop = this.model.valueOf(this.model.peek(bound), "Bound");
151
+ return isReference(loop) ? this.model.typeOf(loop.ref) : undefined;
152
+ }
153
+ surfaceMesh(mesh) {
154
+ const vertices = mesh.positions.map(([x, y, z]) => this.welded(x, y, z));
155
+ for (let at = 0; at + 2 < mesh.triangles.length; at += TRIANGLE_CORNERS) {
156
+ const [a, b, c] = [vertices[mesh.triangles[at]], vertices[mesh.triangles[at + 1]], vertices[mesh.triangles[at + 2]]];
157
+ if (a !== b && b !== c && c !== a) {
158
+ this.indices.push(a, b, c);
159
+ }
160
+ }
161
+ }
162
+ loop(loop) {
163
+ const type = this.model.typeOf(loop);
164
+ if (type !== POLY_LOOP) {
165
+ throw new UnsupportedGeometryError(`A face bounded by an ${type !== null && type !== void 0 ? type : `unknown #${loop}`} is not supported yet`);
166
+ }
167
+ return this.references(loop, "Polygon").map((point) => this.vertex(point));
168
+ }
169
+ vertex(point) {
170
+ var _a, _b, _c;
171
+ const known = this.vertexOfPoint.get(point);
172
+ if (known !== undefined) {
173
+ return known;
174
+ }
175
+ const coordinates = numbersOf(this.model.valueOf(this.model.peek(point), "Coordinates"), `#${point} Coordinates`);
176
+ const vertex = this.welded((_a = coordinates[0]) !== null && _a !== void 0 ? _a : 0, (_b = coordinates[1]) !== null && _b !== void 0 ? _b : 0, (_c = coordinates[2]) !== null && _c !== void 0 ? _c : 0);
177
+ this.vertexOfPoint.set(point, vertex);
178
+ return vertex;
179
+ }
180
+ welded(x, y, z) {
181
+ let byY = this.vertexAt.get(x);
182
+ if (!byY) {
183
+ byY = new Map();
184
+ this.vertexAt.set(x, byY);
185
+ }
186
+ let byZ = byY.get(y);
187
+ if (!byZ) {
188
+ byZ = new Map();
189
+ byY.set(y, byZ);
190
+ }
191
+ let vertex = byZ.get(z);
192
+ if (vertex === undefined) {
193
+ vertex = this.positions.length / POINT3_SIZE;
194
+ this.positions.push(x, y, z);
195
+ byZ.set(z, vertex);
196
+ }
197
+ return vertex;
198
+ }
199
+ add(triangles) {
200
+ for (const vertex of triangles) {
201
+ this.indices.push(vertex);
202
+ }
203
+ }
204
+ orient(first, sense) {
205
+ if (sense === UNORIENTED || signedVolumeOf(this.positions, this.indices, first) * sense >= 0) {
206
+ return;
207
+ }
208
+ for (let at = first; at < this.indices.length; at += POINT3_SIZE) {
209
+ const second = this.indices[at + 1];
210
+ this.indices[at + 1] = this.indices[at + 2];
211
+ this.indices[at + 2] = second;
212
+ }
213
+ }
214
+ }
@@ -0,0 +1,103 @@
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 * as Inputs from "../api/inputs";
4
+ export type ProfileRegion = PolygonRegion | CircleRegion | CompositeRegion;
5
+ export interface PolygonRegion {
6
+ readonly kind: "polygon";
7
+ readonly outer: Base.Point2[];
8
+ readonly holes: Base.Point2[][];
9
+ readonly plane?: FrameAxes;
10
+ }
11
+ export interface CircleRegion {
12
+ readonly kind: "circle";
13
+ readonly center: Base.Point2;
14
+ readonly radius: number;
15
+ readonly innerRadius: number;
16
+ }
17
+ export interface CompositeRegion {
18
+ readonly kind: "composite";
19
+ readonly parts: readonly ProfileRegion[];
20
+ }
21
+ export interface ProfileCorner {
22
+ readonly point: Base.Point2;
23
+ readonly radius: number;
24
+ }
25
+ export interface ModelRecipe {
26
+ readonly recipe: Base.Recipe;
27
+ readonly problems: Inputs.IFC.GeometryProblemDto[];
28
+ }
29
+ export interface DescribedModel {
30
+ readonly key: string;
31
+ readonly described: ModelRecipe;
32
+ }
33
+ export interface TriangleMesh {
34
+ readonly positions: readonly number[];
35
+ readonly indices: readonly number[];
36
+ }
37
+ export interface CurveTrim {
38
+ readonly point: Base.Point3 | undefined;
39
+ readonly parameter: number | undefined;
40
+ }
41
+ export interface ParametricSurface {
42
+ readonly periods: readonly [number | undefined, number | undefined];
43
+ point(u: number, v: number): Base.Point3;
44
+ parameters(point: Base.Point3, near: Base.Point2 | undefined): Base.Point2;
45
+ pole(axis: number, side: number): number | undefined;
46
+ }
47
+ export interface SurfaceFit {
48
+ readonly uv: Base.Point2;
49
+ readonly miss: number;
50
+ }
51
+ export interface PolePoint {
52
+ readonly axis: number;
53
+ readonly at: number;
54
+ }
55
+ export interface CutEdge {
56
+ readonly uv: Base.Point2[];
57
+ readonly points: Base.Point3[];
58
+ }
59
+ export interface FaceLoop {
60
+ readonly points: readonly Base.Point3[];
61
+ readonly uv: readonly Base.Point2[];
62
+ readonly winding: readonly [number, number];
63
+ }
64
+ export interface BoundLoop extends FaceLoop {
65
+ readonly outer: boolean;
66
+ }
67
+ export interface AssembledFace {
68
+ readonly uv: Base.Point2[];
69
+ readonly positions: Base.Point3[];
70
+ readonly indices: number[][];
71
+ }
72
+ export interface ProfilePolyline {
73
+ readonly points: readonly Base.Point3[];
74
+ readonly lengths: readonly number[];
75
+ readonly closed: boolean;
76
+ }
77
+ export interface BSplineCurve {
78
+ readonly degree: number;
79
+ readonly points: readonly Base.Point3[];
80
+ readonly weights: readonly number[] | undefined;
81
+ readonly knots: readonly number[];
82
+ }
83
+ export interface ConicFrame {
84
+ readonly origin: Base.Point3;
85
+ readonly x: Base.Vector3;
86
+ readonly y: Base.Vector3;
87
+ readonly radii: readonly [number, number];
88
+ }
89
+ export interface RecipePart {
90
+ readonly node: number;
91
+ readonly rgba: readonly number[] | undefined;
92
+ }
93
+ export interface ItemEntry {
94
+ readonly item: number;
95
+ }
96
+ export interface NodeEntry {
97
+ readonly node: number;
98
+ }
99
+ export type PartEntry = ItemEntry | NodeEntry;
100
+ export interface PartGroup {
101
+ readonly rgba: readonly number[] | undefined;
102
+ readonly entries: PartEntry[];
103
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import type { Base } from "@bitbybit-dev/base";
2
+ import type { ModelSnapshot } from "../model/snapshot";
3
+ export declare function classLabelOf(type: string): string;
4
+ export declare class RecipeGroups {
5
+ private readonly model;
6
+ private readonly isByClass;
7
+ private readonly groups;
8
+ private readonly ofObject;
9
+ private readonly ofClass;
10
+ constructor(model: ModelSnapshot, isByClass: boolean);
11
+ groupOf(element: number): number | undefined;
12
+ list(): Base.RecipeGroup[];
13
+ private groupAt;
14
+ private isSpatial;
15
+ private add;
16
+ private nameOf;
17
+ private tagOf;
18
+ private spatialGroup;
19
+ private wholeGroup;
20
+ private classGroup;
21
+ }
@@ -0,0 +1,106 @@
1
+ import { containerOf } from "../build/spatial";
2
+ import { relatingOf } from "../build/relationships";
3
+ import { AGGREGATION } from "../build/constants";
4
+ import { textValue } from "../step/values";
5
+ const PROJECT = "IfcProject";
6
+ const SPATIAL_ELEMENT = "IfcSpatialElement";
7
+ const IFC_PREFIX = "Ifc";
8
+ const UNCOUNTED = new Set(["Furniture", "Equipment"]);
9
+ const MAX_NESTING = 64;
10
+ function pluralOf(words) {
11
+ var _a;
12
+ const last = (_a = words.split(" ").at(-1)) !== null && _a !== void 0 ? _a : words;
13
+ if (UNCOUNTED.has(last.charAt(0).toUpperCase() + last.slice(1))) {
14
+ return words;
15
+ }
16
+ if (/[^aeiou]y$/.test(words)) {
17
+ return `${words.slice(0, -1)}ies`;
18
+ }
19
+ return /(s|x|ch|sh)$/.test(words) ? `${words}es` : `${words}s`;
20
+ }
21
+ function wordsOf(type) {
22
+ const bare = type.startsWith(IFC_PREFIX) ? type.slice(IFC_PREFIX.length) : type;
23
+ const words = bare.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
24
+ return words.charAt(0).toUpperCase() + words.slice(1);
25
+ }
26
+ export function classLabelOf(type) {
27
+ return pluralOf(wordsOf(type));
28
+ }
29
+ export class RecipeGroups {
30
+ constructor(model, isByClass) {
31
+ this.model = model;
32
+ this.isByClass = isByClass;
33
+ this.groups = [];
34
+ this.ofObject = new Map();
35
+ this.ofClass = new Map();
36
+ }
37
+ groupOf(element) {
38
+ return this.groupAt(element, 0);
39
+ }
40
+ list() {
41
+ return this.groups;
42
+ }
43
+ groupAt(element, depth) {
44
+ var _a;
45
+ const whole = relatingOf(this.model, AGGREGATION, element);
46
+ if (whole !== undefined && !this.isSpatial(whole) && depth < MAX_NESTING) {
47
+ return this.wholeGroup(whole, depth);
48
+ }
49
+ const container = (_a = containerOf(this.model, element)) !== null && _a !== void 0 ? _a : whole;
50
+ const structure = container === undefined ? undefined : this.spatialGroup(container, depth);
51
+ return this.isByClass ? this.classGroup(structure, this.model.entity(element).type) : structure;
52
+ }
53
+ isSpatial(object) {
54
+ return this.model.schema.isSubtypeOf(this.model.entity(object).type, SPATIAL_ELEMENT);
55
+ }
56
+ add(group) {
57
+ this.groups.push(group);
58
+ return this.groups.length - 1;
59
+ }
60
+ nameOf(object) {
61
+ var _a;
62
+ return ((_a = textValue(this.model.attribute(object, "Name"))) === null || _a === void 0 ? void 0 : _a.trim()) || wordsOf(this.model.entity(object).type);
63
+ }
64
+ tagOf(object) {
65
+ var _a, _b;
66
+ return {
67
+ globalId: (_a = textValue(this.model.attribute(object, "GlobalId"))) !== null && _a !== void 0 ? _a : "",
68
+ type: this.model.entity(object).type,
69
+ name: (_b = textValue(this.model.attribute(object, "Name"))) !== null && _b !== void 0 ? _b : "",
70
+ };
71
+ }
72
+ spatialGroup(structure, depth) {
73
+ if (this.ofObject.has(structure)) {
74
+ return this.ofObject.get(structure);
75
+ }
76
+ if (this.model.schema.isSubtypeOf(this.model.entity(structure).type, PROJECT) || depth >= MAX_NESTING) {
77
+ this.ofObject.set(structure, undefined);
78
+ return undefined;
79
+ }
80
+ const holder = relatingOf(this.model, AGGREGATION, structure);
81
+ const parent = holder === undefined ? undefined : this.spatialGroup(holder, depth + 1);
82
+ const group = this.add(Object.assign(Object.assign({ name: this.nameOf(structure) }, (parent === undefined ? {} : { parent })), { tag: this.tagOf(structure) }));
83
+ this.ofObject.set(structure, group);
84
+ return group;
85
+ }
86
+ wholeGroup(whole, depth) {
87
+ const known = this.ofObject.get(whole);
88
+ if (known !== undefined) {
89
+ return known;
90
+ }
91
+ const parent = this.groupAt(whole, depth + 1);
92
+ const group = this.add(Object.assign(Object.assign({ name: this.nameOf(whole) }, (parent === undefined ? {} : { parent })), { tag: this.tagOf(whole) }));
93
+ this.ofObject.set(whole, group);
94
+ return group;
95
+ }
96
+ classGroup(structure, type) {
97
+ const key = `${structure !== null && structure !== void 0 ? structure : "top"}:${type}`;
98
+ const known = this.ofClass.get(key);
99
+ if (known !== undefined) {
100
+ return known;
101
+ }
102
+ const group = this.add(Object.assign(Object.assign({ name: classLabelOf(type) }, (structure === undefined ? {} : { parent: structure })), { tag: { type } }));
103
+ this.ofClass.set(key, group);
104
+ return group;
105
+ }
106
+ }
@@ -0,0 +1,34 @@
1
+ import type { ModelSnapshot } from "../model/snapshot";
2
+ import type { RecipePart } from "./geometry-types";
3
+ import type { RecipeBuilder } from "./recipe-builder";
4
+ export declare class ItemConverter {
5
+ private readonly model;
6
+ private readonly builder;
7
+ private readonly curves;
8
+ private readonly reach;
9
+ private readonly items;
10
+ private readonly maps;
11
+ private readonly representations;
12
+ private readonly itemColours;
13
+ private readonly solids;
14
+ constructor(model: ModelSnapshot, builder: RecipeBuilder, reach: number);
15
+ representation(representation: number): number;
16
+ parts(representation: number): readonly RecipePart[];
17
+ item(item: number): number;
18
+ private convert;
19
+ private placedBy;
20
+ private extrusion;
21
+ private extruded;
22
+ private boolean;
23
+ private tool;
24
+ private boundedHalfSpace;
25
+ private halfSpace;
26
+ private joined;
27
+ private groupNode;
28
+ private mapped;
29
+ private mappedParts;
30
+ private meshNode;
31
+ private meshOf;
32
+ private facetedBrep;
33
+ private surfaceModel;
34
+ }