@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,409 @@
1
+ import { resolveDto } from "@bitbybit-dev/base";
2
+ import { WORLD_AXES, vectorToWorld } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
3
+ import { textValue } from "../../step/values";
4
+ import { createProject, DESIGN_TRANSFER_VIEW, millimetresPerUnit, projectOf, SCHEMA_FOR_NEW_MODELS } from "../../build/project";
5
+ import { keyGlobalId } from "../../model/guid";
6
+ import { readModel, writeModel, writeModelBytes } from "../../model/io";
7
+ import { upgradeToIfc4 } from "../../model/upgrade";
8
+ import { DEFAULT_IMPLEMENTATION_LEVEL } from "../../step/constants";
9
+ import { isList, isReference } from "../../step/values";
10
+ import * as Inputs from "../inputs";
11
+ import { editModel, lengthTolerance, modelOf, oneOf, resolveId } from "./service-support";
12
+ import { PARALLEL_TOLERANCE, POINT3_SIZE } from "../../build/constants";
13
+ import { moveElement } from "../../build/moving";
14
+ import { removeObject } from "../../build/removal";
15
+ import { requireFinite, requirePoint } from "../../build/checks";
16
+ import { standingIn, storeyFrame, storeyOf, storeysOf } from "../../build/spatial";
17
+ import { georeferenceOf } from "../../build/georeference";
18
+ const LIBRARY = "@bitbybit-dev/ifc";
19
+ const ISO_SECONDS = 19;
20
+ const MAX_PART_DEPTH = 32;
21
+ function headerFor(model, resolved) {
22
+ var _a;
23
+ return Object.assign(Object.assign({}, model.header), { name: resolved.fileName, timeStamp: (_a = resolved.timeStamp) !== null && _a !== void 0 ? _a : new Date().toISOString().slice(0, ISO_SECONDS) });
24
+ }
25
+ function relatedPairs(model, relationship, relating, related) {
26
+ return model.byType(relationship).flatMap((rel) => {
27
+ const whole = model.attribute(rel.id, relating);
28
+ const parts = model.attribute(rel.id, related);
29
+ return isReference(whole) ? (isList(parts) ? parts : []).filter(isReference).map((part) => [part.ref, whole.ref]) : [];
30
+ });
31
+ }
32
+ function containers(model) {
33
+ var _a;
34
+ const container = new Map(relatedPairs(model, "IfcRelContainedInSpatialStructure", "RelatingStructure", "RelatedElements"));
35
+ const wholeOf = new Map(relatedPairs(model, "IfcRelAggregates", "RelatingObject", "RelatedObjects"));
36
+ for (const part of wholeOf.keys()) {
37
+ let whole = wholeOf.get(part);
38
+ for (let step = 0; whole !== undefined && !container.has(part) && step < MAX_PART_DEPTH; step++) {
39
+ const holder = container.get(whole);
40
+ if (holder !== undefined && !model.schema.isSubtypeOf((_a = model.typeOf(whole)) !== null && _a !== void 0 ? _a : "", "IfcSpatialElement")) {
41
+ container.set(part, holder);
42
+ }
43
+ whole = wholeOf.get(whole);
44
+ }
45
+ }
46
+ return container;
47
+ }
48
+ function infoOf(model, id, storey) {
49
+ var _a, _b;
50
+ const name = model.attribute(id, "Name");
51
+ const storeyGlobalId = storey === undefined ? null : model.attribute(storey, "GlobalId");
52
+ return {
53
+ globalId: (_a = textValue(model.attribute(id, "GlobalId"))) !== null && _a !== void 0 ? _a : "",
54
+ type: (_b = model.typeOf(id)) !== null && _b !== void 0 ? _b : "",
55
+ name: typeof name === "string" ? name : "",
56
+ storey: typeof storeyGlobalId === "string" ? storeyGlobalId : "",
57
+ };
58
+ }
59
+ /**
60
+ * Creates, reads, writes and inspects whole IFC models. A model is a value: every method that
61
+ * changes one returns a new model and leaves the one it was given as it was, so a change can be
62
+ * undone by keeping the earlier model.
63
+ *
64
+ * Objects are found by their GlobalId or by the id given when they were added, such as `north-wall`,
65
+ * which the model turns into a GlobalId of its own. Storeys are in `spatial`, building elements in
66
+ * `walls`, `slabs`, `doors` and the rest.
67
+ * @beta
68
+ */
69
+ export class IFCModels {
70
+ /**
71
+ * Starts a new IFC4 model with a project, its site and one building, ready for storeys.
72
+ *
73
+ * Every length later given to the model is in `lengthUnit`, millimetres by default. With a
74
+ * `seed`, the same calls always write the same file; without one, the GlobalIds are random.
75
+ * @param inputs - The project's name, the site and building names, the length unit and a seed
76
+ * @returns A new model
77
+ * @group create
78
+ * @shortname create model
79
+ * @drawable false
80
+ * @example
81
+ * ```typescript
82
+ * let model = await bitbybit.ifc.model.create({ name: "House", seed: "house-1" });
83
+ * model = await bitbybit.ifc.spatial.addStorey({ model, id: "ground", name: "Ground floor", elevation: 0 });
84
+ * ```
85
+ */
86
+ create(inputs) {
87
+ var _a, _b;
88
+ const resolved = resolveDto(Inputs.IFC.CreateModelDto, inputs);
89
+ return createProject({
90
+ name: resolved.name,
91
+ siteName: resolved.siteName,
92
+ buildingName: resolved.buildingName,
93
+ lengthUnit: oneOf(resolved.lengthUnit, Inputs.IFC.lengthUnitEnum, "length unit"),
94
+ seed: resolved.seed,
95
+ header: {
96
+ description: [DESIGN_TRANSFER_VIEW],
97
+ implementationLevel: DEFAULT_IMPLEMENTATION_LEVEL,
98
+ name: "",
99
+ timeStamp: "",
100
+ author: [(_a = resolved.author) !== null && _a !== void 0 ? _a : ""],
101
+ organization: [(_b = resolved.organization) !== null && _b !== void 0 ? _b : ""],
102
+ preprocessorVersion: LIBRARY,
103
+ originatingSystem: LIBRARY,
104
+ authorization: "",
105
+ schemaIdentifiers: [SCHEMA_FOR_NEW_MODELS],
106
+ },
107
+ });
108
+ }
109
+ /**
110
+ * Reads an IFC file into a model to inspect, change and write back.
111
+ *
112
+ * Entities are decoded only when asked for, and unchanged ones are written back exactly as read.
113
+ * An IFC2X3 file is read through IFC4, to be shown and queried; `upgradeToIfc4` makes it
114
+ * editable. An `.ifczip` archive is read from the `.ifc` file it holds.
115
+ * @param inputs - The file's text or bytes
116
+ * @returns The model the file holds
117
+ * @group io
118
+ * @shortname read ifc
119
+ * @drawable false
120
+ * @example
121
+ * ```typescript
122
+ * const model = await bitbybit.ifc.model.read({ data: ifcText });
123
+ * const summary = await bitbybit.ifc.model.summary({ model });
124
+ * ```
125
+ */
126
+ read(inputs) {
127
+ if (typeof inputs.data !== "string" && !(inputs.data instanceof Uint8Array) && !(inputs.data instanceof ArrayBuffer)) {
128
+ throw new TypeError("Expected the IFC file as a text, a Uint8Array or an ArrayBuffer");
129
+ }
130
+ return readModel(inputs.data);
131
+ }
132
+ /**
133
+ * Turns a model read from an IFC2X3 file into an IFC4 model, which can be changed and is
134
+ * written as IFC4.
135
+ *
136
+ * New attributes stay unset, a newly required enumeration takes `NOTDEFINED`, sets lose repeats
137
+ * and a merged entity becomes its parent; other rows are written as read. Anything else stops
138
+ * the upgrade, naming the entity.
139
+ * @param inputs - The model
140
+ * @returns The upgraded model
141
+ * @group io
142
+ * @shortname upgrade to ifc4
143
+ * @drawable false
144
+ * @example
145
+ * ```typescript
146
+ * const old = await bitbybit.ifc.model.read({ data: ifc2x3Bytes });
147
+ * const model = await bitbybit.ifc.model.upgradeToIfc4({ model: old });
148
+ * ```
149
+ */
150
+ upgradeToIfc4(inputs) {
151
+ return upgradeToIfc4(modelOf(inputs.model));
152
+ }
153
+ /**
154
+ * Writes a model as the text of an `.ifc` file.
155
+ *
156
+ * The header records `fileName` and `timeStamp`; give a fixed `timeStamp` to write the same text
157
+ * every time. Entities read from a file and left unchanged are written as they were read, character
158
+ * for character.
159
+ * @param inputs - The model, the file name and the time stamp
160
+ * @returns The text of the IFC file
161
+ * @group io
162
+ * @shortname write ifc
163
+ * @drawable false
164
+ * @example
165
+ * ```typescript
166
+ * const text = await bitbybit.ifc.model.write({ model, fileName: "house.ifc" });
167
+ * ```
168
+ */
169
+ write(inputs) {
170
+ const resolved = resolveDto(Inputs.IFC.WriteModelDto, inputs);
171
+ const model = modelOf(resolved.model);
172
+ return writeModel(model, headerFor(model, resolved));
173
+ }
174
+ /**
175
+ * Writes a model as the bytes of an `.ifc` file, at any size.
176
+ *
177
+ * The header records `fileName` and `timeStamp`, as `model.write`'s does. Entities read from a file
178
+ * and left unchanged are copied byte for byte, so a file of hundreds of megabytes writes in a moment,
179
+ * where its text would not fit one JavaScript string.
180
+ * @param inputs - The model, the file name and the time stamp
181
+ * @returns The bytes of the IFC file
182
+ * @group io
183
+ * @shortname write ifc bytes
184
+ * @drawable false
185
+ * @example
186
+ * ```typescript
187
+ * const bytes = await bitbybit.ifc.model.writeBytes({ model, fileName: "house.ifc" });
188
+ * ```
189
+ */
190
+ writeBytes(inputs) {
191
+ const resolved = resolveDto(Inputs.IFC.WriteModelDto, inputs);
192
+ const model = modelOf(resolved.model);
193
+ return writeModelBytes(model, headerFor(model, resolved));
194
+ }
195
+ /**
196
+ * Describes what a model holds: its schema, its project, its unit, its storeys and how many
197
+ * elements of each type.
198
+ * @param inputs - The model
199
+ * @returns The model's summary
200
+ * @group query
201
+ * @shortname summary
202
+ * @drawable false
203
+ * @example
204
+ * ```typescript
205
+ * const summary = await bitbybit.ifc.model.summary({ model });
206
+ * console.log(summary.elementCounts.IfcWall);
207
+ * ```
208
+ */
209
+ summary(inputs) {
210
+ var _a;
211
+ const model = modelOf(inputs.model);
212
+ const counts = {};
213
+ for (const element of model.byType("IfcElement")) {
214
+ counts[element.type] = ((_a = counts[element.type]) !== null && _a !== void 0 ? _a : 0) + 1;
215
+ }
216
+ const project = model.attribute(projectOf(model), "Name");
217
+ return {
218
+ schema: model.schemaName,
219
+ editable: model.editable,
220
+ project: typeof project === "string" ? project : "",
221
+ millimetresPerUnit: millimetresPerUnit(model),
222
+ entities: model.size,
223
+ storeys: storeysOf(model),
224
+ elementCounts: counts,
225
+ };
226
+ }
227
+ /**
228
+ * Reads where a model sits on the Earth: the map conversion that places its coordinates in a
229
+ * projected coordinate reference system, and its site's reference latitude, longitude and
230
+ * elevation. A file without them gives the defaults, with `mapped` and `located` false.
231
+ * @param inputs - The model
232
+ * @returns The model's georeference
233
+ * @group query
234
+ * @shortname georeference
235
+ * @drawable false
236
+ * @example
237
+ * ```typescript
238
+ * const georeference = await bitbybit.ifc.model.georeference({ model });
239
+ * console.log(georeference.crs, georeference.eastings, georeference.northings);
240
+ * ```
241
+ */
242
+ georeference(inputs) {
243
+ return georeferenceOf(modelOf(inputs.model));
244
+ }
245
+ /**
246
+ * Lists the objects of one IFC type, its subtypes included, optionally only those standing in
247
+ * one storey or other spatial element. An aggregate's part stands where its whole stands.
248
+ *
249
+ * `type` is any type with a GlobalId, such as `IfcWall`, `IfcDoor` or `IfcElement` for every
250
+ * building element. The list is in the order the model holds them.
251
+ * @param inputs - The model, the type and an optional storey
252
+ * @returns Each object's GlobalId, type, name and the spatial element it stands in
253
+ * @group query
254
+ * @shortname elements
255
+ * @drawable false
256
+ * @example
257
+ * ```typescript
258
+ * const walls = await bitbybit.ifc.model.elements({ model, type: "IfcWall", storey: "ground" });
259
+ * ```
260
+ */
261
+ elements(inputs) {
262
+ const resolved = resolveDto(Inputs.IFC.ElementsDto, inputs);
263
+ const model = modelOf(resolved.model);
264
+ if (!model.schema.hasEntity(resolved.type) || !model.schema.isSubtypeOf(resolved.type, "IfcRoot")) {
265
+ throw new Error(`${resolved.type} is not an IFC type with a GlobalId`);
266
+ }
267
+ const storey = resolved.storey === undefined ? undefined : resolveId(model, resolved.storey, "IfcSpatialElement", "storey");
268
+ const container = containers(model);
269
+ return model.byType(resolved.type)
270
+ .filter((entity) => storey === undefined || container.get(entity.id) === storey)
271
+ .map((entity) => infoOf(model, entity.id, container.get(entity.id)));
272
+ }
273
+ /**
274
+ * Describes one object of a model: its GlobalId, its type, its name and the spatial element it
275
+ * stands in.
276
+ * @param inputs - The model and the object
277
+ * @returns The object's GlobalId, type, name and the spatial element it stands in
278
+ * @group query
279
+ * @shortname element
280
+ * @drawable false
281
+ * @example
282
+ * ```typescript
283
+ * const wall = await bitbybit.ifc.model.element({ model, element: "north-wall" });
284
+ * ```
285
+ */
286
+ element(inputs) {
287
+ const model = modelOf(inputs.model);
288
+ const element = resolveId(model, inputs.element, "IfcRoot", "object");
289
+ return infoOf(model, element, standingIn(model, element));
290
+ }
291
+ /**
292
+ * Removes an element, an empty storey or space, or a type nothing is of, with what only it uses.
293
+ * A wall takes its openings with their doors and windows, and the walls it was joined to are
294
+ * trimmed again; a door or window leaves its opening; an opening takes its doors and windows.
295
+ * @param inputs - The model and the object
296
+ * @returns A new model without the object
297
+ * @group edit
298
+ * @shortname remove
299
+ * @drawable false
300
+ * @example
301
+ * ```typescript
302
+ * model = await bitbybit.ifc.model.remove({ model, element: "partition" });
303
+ * ```
304
+ */
305
+ remove(inputs) {
306
+ const model = modelOf(inputs.model);
307
+ const object = resolveId(model, inputs.element, "IfcObjectDefinition", "object");
308
+ return editModel(model, (tx, writer) => {
309
+ removeObject(tx, writer, object, lengthTolerance(model), PARALLEL_TOLERANCE);
310
+ });
311
+ }
312
+ /**
313
+ * Moves an element or a space, and turns it about the vertical through its own origin; what is
314
+ * placed on it, such as a wall's openings, moves with it. A joined wall moves with `walls.edit`,
315
+ * and an opening, door or window with `openings.edit`.
316
+ * @param inputs - The model, the element, how far to move it and how far to turn it
317
+ * @returns A new model with the element moved
318
+ * @group edit
319
+ * @shortname move
320
+ * @drawable false
321
+ * @example
322
+ * ```typescript
323
+ * model = await bitbybit.ifc.model.move({ model, element: "column-1", translation: [500, 0, 0], rotation: 45 });
324
+ * ```
325
+ */
326
+ move(inputs) {
327
+ const resolved = resolveDto(Inputs.IFC.MoveElementDto, inputs);
328
+ const model = modelOf(resolved.model);
329
+ requirePoint(resolved.translation, POINT3_SIZE, "translation");
330
+ requireFinite(resolved.rotation, "rotation in degrees");
331
+ const element = resolveId(model, resolved.element, "IfcProduct", "element");
332
+ const storey = storeyOf(model, element);
333
+ const plan = storey === undefined ? WORLD_AXES : storeyFrame(model, storey);
334
+ return editModel(model, (tx, writer) => {
335
+ moveElement(tx, writer, element, vectorToWorld(plan, resolved.translation), resolved.rotation);
336
+ });
337
+ }
338
+ /**
339
+ * Sets one attribute of an object to a text, a number, true or false, such as a wall's `Name`,
340
+ * `Description` or `Tag`.
341
+ *
342
+ * The value is checked against the IFC schema, and an attribute that holds a reference, a derived
343
+ * attribute or the `GlobalId` cannot be set this way.
344
+ * @param inputs - The model, the object, the attribute's name and the new value
345
+ * @returns A new model with the attribute set
346
+ * @group edit
347
+ * @shortname set attribute
348
+ * @drawable false
349
+ * @example
350
+ * ```typescript
351
+ * model = await bitbybit.ifc.model.setAttribute({ model, element: "north-wall", attribute: "Description", value: "Load bearing" });
352
+ * ```
353
+ */
354
+ setAttribute(inputs) {
355
+ const resolved = resolveDto(Inputs.IFC.SetAttributeDto, inputs);
356
+ const model = modelOf(resolved.model);
357
+ if (resolved.attribute === "GlobalId") {
358
+ throw new Error("An object's GlobalId identifies it and cannot be changed");
359
+ }
360
+ if (typeof resolved.value !== "string" && typeof resolved.value !== "number" && typeof resolved.value !== "boolean") {
361
+ throw new TypeError("An attribute is set to a text, a number, or true or false");
362
+ }
363
+ const element = resolveId(model, resolved.element, "IfcRoot", "object");
364
+ return editModel(model, (tx) => tx.update(element, { [resolved.attribute]: resolved.value }));
365
+ }
366
+ /**
367
+ * Reads one attribute of an object, such as a wall's `Name`, `Description` or `Tag`.
368
+ *
369
+ * The value comes back as the model holds it: a text, a number, true or false, `null` when the
370
+ * attribute is unset, `{ enum }` for an enumeration value, `{ type, value }` for a typed value,
371
+ * `{ ref }` for a reference to another entity, or a list of these.
372
+ * @param inputs - The model, the object and the attribute's name
373
+ * @returns The attribute's value
374
+ * @group query
375
+ * @shortname get attribute
376
+ * @drawable false
377
+ * @example
378
+ * ```typescript
379
+ * const description = await bitbybit.ifc.model.getAttribute({ model, element: "north-wall", attribute: "Description" });
380
+ * ```
381
+ */
382
+ getAttribute(inputs) {
383
+ const resolved = resolveDto(Inputs.IFC.GetAttributeDto, inputs);
384
+ const model = modelOf(resolved.model);
385
+ return model.attribute(resolveId(model, resolved.element, "IfcRoot", "object"), resolved.attribute);
386
+ }
387
+ /**
388
+ * Says which GlobalId an id stands for in a model: the GlobalId itself, or the one the model
389
+ * derives from an id of your own such as `north-wall`.
390
+ *
391
+ * The answer does not depend on whether the model holds such an object yet.
392
+ * @param inputs - The model and the id
393
+ * @returns The GlobalId, 22 characters
394
+ * @group query
395
+ * @shortname global id of
396
+ * @drawable false
397
+ * @example
398
+ * ```typescript
399
+ * const globalId = await bitbybit.ifc.model.globalIdOf({ model, id: "north-wall" });
400
+ * ```
401
+ */
402
+ globalIdOf(inputs) {
403
+ const model = modelOf(inputs.model);
404
+ if (typeof inputs.id !== "string" || inputs.id.length === 0) {
405
+ throw new TypeError("Expected an id as a text");
406
+ }
407
+ return model.byGlobalId(inputs.id) !== undefined ? inputs.id : keyGlobalId(model.keySeed, inputs.id);
408
+ }
409
+ }
@@ -0,0 +1,57 @@
1
+ import type { IfcModel } from "../../model/model-types";
2
+ import * as Inputs from "../inputs";
3
+ /**
4
+ * Openings: voids cut through walls and slabs, the holes doors and windows sit in. Doors and windows
5
+ * cut their own openings, so this is for an opening that stays empty, such as a pass-through or a
6
+ * stairwell, and for moving an opening along its wall.
7
+ * @beta
8
+ */
9
+ export declare class IFCOpenings {
10
+ /**
11
+ * Cuts a rectangular opening through a wall, `offset` along its axis from its start and `sill`
12
+ * above its base.
13
+ *
14
+ * The opening goes through the wall's whole thickness and stays with the wall when its joins
15
+ * change. It must fit along the wall.
16
+ * @param inputs - The model, the wall, and the opening's position and size
17
+ * @returns A new model with the wall cut
18
+ * @group create
19
+ * @shortname add opening in wall
20
+ * @drawable false
21
+ * @example
22
+ * ```typescript
23
+ * model = await bitbybit.ifc.openings.add({ model, wall: "inner", offset: 1500, width: 1200, height: 2200 });
24
+ * ```
25
+ */
26
+ add(inputs: Inputs.IFC.AddOpeningDto<IfcModel>): IfcModel;
27
+ /**
28
+ * Moves an opening along its wall or up and down it, or resizes it. Given a door or window, it
29
+ * moves it with the opening it is in, which keeps its size. A door or window placed elsewhere than
30
+ * on its opening or wall is refused, as it would stay behind.
31
+ * @param inputs - The model, the opening or the door or window in it, and its new position or size
32
+ * @returns A new model with the opening moved or resized
33
+ * @group edit
34
+ * @shortname edit opening
35
+ * @drawable false
36
+ * @example
37
+ * ```typescript
38
+ * model = await bitbybit.ifc.openings.edit({ model, opening: "front-door", offset: 2500 });
39
+ * ```
40
+ */
41
+ edit(inputs: Inputs.IFC.EditOpeningDto<IfcModel>): IfcModel;
42
+ /**
43
+ * Cuts an opening of any outline, such as a stairwell or a shaft, through a slab's whole thickness.
44
+ * The outline is given in the plan of the slab's storey and must lie inside the slab's outline or on
45
+ * its edge, which is checked when that outline is a polyline, as in the slabs this library adds.
46
+ * @param inputs - The model, the slab and the opening's outline
47
+ * @returns A new model with the slab cut
48
+ * @group create
49
+ * @shortname add opening in slab
50
+ * @drawable false
51
+ * @example
52
+ * ```typescript
53
+ * model = await bitbybit.ifc.openings.addInSlab({ model, slab: "first-floor", outline: [[1000, 1000], [3500, 1000], [3500, 2200], [1000, 2200]] });
54
+ * ```
55
+ */
56
+ addInSlab(inputs: Inputs.IFC.AddSlabOpeningDto<IfcModel>): IfcModel;
57
+ }
@@ -0,0 +1,102 @@
1
+ import { resolveDto } from "@bitbybit-dev/base";
2
+ import { WORLD_AXES, pointToLocal, pointToWorld } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
3
+ import { requireOutline } from "../../build/checks";
4
+ import { createWallOpening, editWallOpening } from "../../build/openings";
5
+ import { absoluteFrame, objectPlacementOf } from "../../build/placement";
6
+ import { createSlabOpening } from "../../build/slab-openings";
7
+ import { containerOf, storeyFrame } from "../../build/spatial";
8
+ import * as Inputs from "../inputs";
9
+ import { DEFAULT_MILLIMETRES } from "./defaults.constants";
10
+ import { editModel, lengthIn, lengthTolerance, modelOf, resolveId } from "./service-support";
11
+ /**
12
+ * Openings: voids cut through walls and slabs, the holes doors and windows sit in. Doors and windows
13
+ * cut their own openings, so this is for an opening that stays empty, such as a pass-through or a
14
+ * stairwell, and for moving an opening along its wall.
15
+ * @beta
16
+ */
17
+ export class IFCOpenings {
18
+ /**
19
+ * Cuts a rectangular opening through a wall, `offset` along its axis from its start and `sill`
20
+ * above its base.
21
+ *
22
+ * The opening goes through the wall's whole thickness and stays with the wall when its joins
23
+ * change. It must fit along the wall.
24
+ * @param inputs - The model, the wall, and the opening's position and size
25
+ * @returns A new model with the wall cut
26
+ * @group create
27
+ * @shortname add opening in wall
28
+ * @drawable false
29
+ * @example
30
+ * ```typescript
31
+ * model = await bitbybit.ifc.openings.add({ model, wall: "inner", offset: 1500, width: 1200, height: 2200 });
32
+ * ```
33
+ */
34
+ add(inputs) {
35
+ const resolved = resolveDto(Inputs.IFC.AddOpeningDto, inputs);
36
+ const model = modelOf(resolved.model);
37
+ const wall = resolveId(model, resolved.wall, "IfcWall", "wall");
38
+ return editModel(model, (tx, writer) => {
39
+ createWallOpening(tx, writer, {
40
+ wall,
41
+ id: resolved.id,
42
+ name: resolved.name,
43
+ offset: lengthIn(model, resolved.offset, DEFAULT_MILLIMETRES.openingOffset),
44
+ sill: resolved.sill,
45
+ width: lengthIn(model, resolved.width, DEFAULT_MILLIMETRES.openingWidth),
46
+ height: lengthIn(model, resolved.height, DEFAULT_MILLIMETRES.openingHeight),
47
+ }, lengthTolerance(model));
48
+ });
49
+ }
50
+ /**
51
+ * Moves an opening along its wall or up and down it, or resizes it. Given a door or window, it
52
+ * moves it with the opening it is in, which keeps its size. A door or window placed elsewhere than
53
+ * on its opening or wall is refused, as it would stay behind.
54
+ * @param inputs - The model, the opening or the door or window in it, and its new position or size
55
+ * @returns A new model with the opening moved or resized
56
+ * @group edit
57
+ * @shortname edit opening
58
+ * @drawable false
59
+ * @example
60
+ * ```typescript
61
+ * model = await bitbybit.ifc.openings.edit({ model, opening: "front-door", offset: 2500 });
62
+ * ```
63
+ */
64
+ edit(inputs) {
65
+ const resolved = resolveDto(Inputs.IFC.EditOpeningDto, inputs);
66
+ const model = modelOf(resolved.model);
67
+ const element = resolveId(model, resolved.opening, "IfcElement", "opening");
68
+ return editModel(model, (tx, writer) => {
69
+ editWallOpening(tx, writer, element, { offset: resolved.offset, sill: resolved.sill, width: resolved.width, height: resolved.height }, lengthTolerance(model));
70
+ });
71
+ }
72
+ /**
73
+ * Cuts an opening of any outline, such as a stairwell or a shaft, through a slab's whole thickness.
74
+ * The outline is given in the plan of the slab's storey and must lie inside the slab's outline or on
75
+ * its edge, which is checked when that outline is a polyline, as in the slabs this library adds.
76
+ * @param inputs - The model, the slab and the opening's outline
77
+ * @returns A new model with the slab cut
78
+ * @group create
79
+ * @shortname add opening in slab
80
+ * @drawable false
81
+ * @example
82
+ * ```typescript
83
+ * model = await bitbybit.ifc.openings.addInSlab({ model, slab: "first-floor", outline: [[1000, 1000], [3500, 1000], [3500, 2200], [1000, 2200]] });
84
+ * ```
85
+ */
86
+ addInSlab(inputs) {
87
+ const resolved = resolveDto(Inputs.IFC.AddSlabOpeningDto, inputs);
88
+ const model = modelOf(resolved.model);
89
+ requireOutline(resolved.outline, "outline");
90
+ const slab = resolveId(model, resolved.slab, "IfcSlab", "slab");
91
+ const storey = containerOf(model, slab);
92
+ const plan = storey === undefined ? WORLD_AXES : storeyFrame(model, storey);
93
+ const slabFrame = absoluteFrame(model, objectPlacementOf(model, slab));
94
+ const outline = resolved.outline.map((point) => {
95
+ const local = pointToLocal(slabFrame, pointToWorld(plan, [point[0], point[1], 0]));
96
+ return [local[0], local[1]];
97
+ });
98
+ return editModel(model, (tx, writer) => {
99
+ createSlabOpening(tx, writer, { slab, id: resolved.id, name: resolved.name, outline }, lengthTolerance(model));
100
+ });
101
+ }
102
+ }
@@ -0,0 +1,89 @@
1
+ import type { IfcModel } from "../../model/model-types";
2
+ import * as Inputs from "../inputs";
3
+ /**
4
+ * Properties: named sets of values attached to elements and types, such as `Pset_WallCommon` with
5
+ * `IsExternal` and `FireRating`, which other tools list, filter and schedule by.
6
+ * @beta
7
+ */
8
+ export declare class IFCProperties {
9
+ /**
10
+ * Attaches a property set to one or more objects: walls, doors, types or any object with a
11
+ * GlobalId.
12
+ *
13
+ * Each value is written as its `type`, or as a label, an integer, a real or a boolean by the
14
+ * kind of value. One set is shared by every object it is attached to.
15
+ * @param inputs - The model, the objects, the set's name and its properties
16
+ * @returns A new model with the property set
17
+ * @group properties
18
+ * @shortname add property set
19
+ * @drawable false
20
+ * @example
21
+ * ```typescript
22
+ * model = await bitbybit.ifc.properties.addSet({
23
+ * model,
24
+ * elements: ["south", "east"],
25
+ * name: "Pset_WallCommon",
26
+ * properties: [{ name: "IsExternal", value: true }, { name: "FireRating", value: "REI 60" }],
27
+ * });
28
+ * ```
29
+ */
30
+ addSet(inputs: Inputs.IFC.AddPropertySetDto<IfcModel>): IfcModel;
31
+ /**
32
+ * Reads the property sets attached to an object, with each single value by name.
33
+ *
34
+ * Values of other kinds of property, such as lists and tables, and logical values that are
35
+ * unknown are left out.
36
+ * @param inputs - The model and the object
37
+ * @returns The object's property sets
38
+ * @group properties
39
+ * @shortname get property sets
40
+ * @drawable false
41
+ * @example
42
+ * ```typescript
43
+ * const sets = await bitbybit.ifc.properties.getSets({ model, element: "south" });
44
+ * ```
45
+ */
46
+ getSets(inputs: Inputs.IFC.ElementDto<IfcModel>): Inputs.IFC.PropertySetInfoDto[];
47
+ /**
48
+ * Sets property values of one object, in its property set of the given name, and makes the set
49
+ * when the object has none. A set the object shares with other objects is copied first, so only
50
+ * this object's values change.
51
+ * @param inputs - The model, the object, the set's name and the properties
52
+ * @returns A new model with the values set
53
+ * @group properties
54
+ * @shortname set property values
55
+ * @drawable false
56
+ * @example
57
+ * ```typescript
58
+ * model = await bitbybit.ifc.properties.setValues({ model, element: "south", name: "Pset_WallCommon", properties: [{ name: "FireRating", value: "REI 90" }] });
59
+ * ```
60
+ */
61
+ setValues(inputs: Inputs.IFC.SetPropertyValuesDto<IfcModel>): IfcModel;
62
+ /**
63
+ * Takes properties out of one object's property set; the set goes when none are left. A set the
64
+ * object shares with other objects is copied first, so the others keep their values.
65
+ * @param inputs - The model, the object, the set's name and the names of the properties
66
+ * @returns A new model without the properties
67
+ * @group properties
68
+ * @shortname remove property values
69
+ * @drawable false
70
+ * @example
71
+ * ```typescript
72
+ * model = await bitbybit.ifc.properties.removeValues({ model, element: "south", name: "Pset_WallCommon", names: ["FireRating"] });
73
+ * ```
74
+ */
75
+ removeValues(inputs: Inputs.IFC.RemovePropertyValuesDto<IfcModel>): IfcModel;
76
+ /**
77
+ * Takes a property set away from one object. Other objects that share the set keep it.
78
+ * @param inputs - The model, the object and the set's name
79
+ * @returns A new model without the set on the object
80
+ * @group properties
81
+ * @shortname remove property set
82
+ * @drawable false
83
+ * @example
84
+ * ```typescript
85
+ * model = await bitbybit.ifc.properties.removeSet({ model, element: "south", name: "Pset_WallCommon" });
86
+ * ```
87
+ */
88
+ removeSet(inputs: Inputs.IFC.RemovePropertySetDto<IfcModel>): IfcModel;
89
+ }