@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,243 @@
1
+ import { axesToMatrix, vectorToWorld } from "@bitbybit-dev/base/lib/api/services/helpers/frame-axes";
2
+ import { pathTangents, roundedPath3, sweepMatrices, transportedAxes } from "@bitbybit-dev/base/lib/api/services/helpers/paths";
3
+ import { cross3, dot3, length3, scale3, subtract3 } from "@bitbybit-dev/base/lib/api/services/helpers/vectors";
4
+ import { PARALLEL_TOLERANCE } from "../build/constants";
5
+ import { axisPlacementFrame, directionOf, pointOf } from "../build/placement";
6
+ import { radiansPerUnit } from "../build/project";
7
+ import { isReference } from "../step/values";
8
+ import { arcSegments } from "./curves";
9
+ import { UnsupportedGeometryError } from "./errors";
10
+ import { profileRegion } from "./profiles";
11
+ import { profileNode, regionSolid } from "./regions";
12
+ import { FULL_TURN, IDENTITY_MATRIX, PARAMETER_RATIO, PYRAMID_TRIANGLES, TURN_SLACK, Y_TO_Z } from "./swept-solids.constants";
13
+ const Z_AXIS = [0, 0, 1];
14
+ const NO_AXIS = [0, 0, 0];
15
+ function squared(vector, to) {
16
+ const across = subtract3(vector, scale3(to, dot3(vector, to)));
17
+ const length = length3(across);
18
+ return length > PARALLEL_TOLERANCE ? scale3(across, 1 / length) : undefined;
19
+ }
20
+ function moved(offset) {
21
+ return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, offset[0], offset[1], offset[2], 1];
22
+ }
23
+ export class SweptSolids {
24
+ constructor(model, builder, curves) {
25
+ this.model = model;
26
+ this.builder = builder;
27
+ this.curves = curves;
28
+ }
29
+ revolved(item) {
30
+ const region = this.region(item, "SweptArea");
31
+ const axis = this.model.attribute(item, "Axis");
32
+ if (!isReference(axis)) {
33
+ throw new UnsupportedGeometryError(`#${item} has no axis`);
34
+ }
35
+ const origin = pointOf(this.model, this.model.attribute(axis.ref, "Location"));
36
+ const direction = directionOf(this.model, this.model.attribute(axis.ref, "Axis"), Z_AXIS);
37
+ const length = length3(direction);
38
+ if (!(length > 0) || Math.abs(direction[2]) > PARALLEL_TOLERANCE * length || Math.abs(origin[2]) > PARALLEL_TOLERANCE * Math.max(1, length3(origin))) {
39
+ throw new UnsupportedGeometryError(`#${item} turns about an axis outside its profile's plane`);
40
+ }
41
+ const turn = this.number(item, "Angle") * radiansPerUnit(this.model);
42
+ const sign = Math.sign(turn);
43
+ const angle = Math.min(Math.abs(turn), FULL_TURN);
44
+ if (!(angle > 0) || Math.abs(turn) > FULL_TURN * (1 + TURN_SLACK)) {
45
+ throw new UnsupportedGeometryError(`#${item} turns by an angle that is not above zero and at most a whole turn`);
46
+ }
47
+ const solid = regionSolid(this.builder, region, this.flat(item, (profile) => this.builder.node({
48
+ op: "revolve", profile, origin: [origin[0], origin[1]], direction: [sign * direction[0], sign * direction[1]], angle,
49
+ })));
50
+ return this.placed(item, solid);
51
+ }
52
+ tapered(item) {
53
+ const start = this.region(item, "SweptArea");
54
+ const end = this.region(item, "EndSweptArea");
55
+ const depth = this.number(item, "Depth");
56
+ if (depth === 0) {
57
+ throw new UnsupportedGeometryError(`#${item} has no depth`);
58
+ }
59
+ const direction = directionOf(this.model, this.model.attribute(item, "ExtrudedDirection"), Z_AXIS);
60
+ const along = scale3(direction, depth / length3(direction));
61
+ if (!(Math.abs(along[2]) > PARALLEL_TOLERANCE * Math.abs(depth))) {
62
+ throw new UnsupportedGeometryError(`#${item} tapers along its profile's plane`);
63
+ }
64
+ const frames = this.builder.numbers([...IDENTITY_MATRIX, ...moved(along)]);
65
+ const loft = (first, second) => this.builder.node({ op: "loft", profiles: [first, second], frames });
66
+ return this.placed(item, this.taperBetween(item, start, end, loft));
67
+ }
68
+ sweptDisk(item, polygonal) {
69
+ const radius = this.number(item, "Radius");
70
+ const inner = this.model.attribute(item, "InnerRadius") === null ? 0 : this.number(item, "InnerRadius");
71
+ if (!(radius > 0) || !(inner >= 0) || !(inner < radius)) {
72
+ throw new UnsupportedGeometryError(`#${item} has a radius that is not above zero or an inner radius not inside it`);
73
+ }
74
+ let points = this.sweptPath(item);
75
+ const fillet = polygonal && this.model.attribute(item, "FilletRadius") !== null ? this.number(item, "FilletRadius") : 0;
76
+ if (fillet > 0) {
77
+ points = roundedPath3(points, fillet, arcSegments);
78
+ }
79
+ const tangents = pathTangents(points, ...this.endsOf(item));
80
+ const frames = this.builder.numbers(sweepMatrices(points, tangents, transportedAxes(points, tangents, NO_AXIS)).flat());
81
+ const loft = (size) => this.builder.node({ op: "loft", profiles: [this.builder.node({ op: "circle", center: [0, 0], radius: size })], frames });
82
+ const solid = loft(radius);
83
+ return inner > 0 ? this.builder.node({ op: "difference", of: solid, tools: [loft(inner)] }) : solid;
84
+ }
85
+ areaSweep(item, fixed) {
86
+ const region = this.region(item, "SweptArea");
87
+ const points = this.sweptPath(item);
88
+ const tangents = pathTangents(points, ...this.endsOf(item));
89
+ const axes = fixed ? this.fixedAxes(item, tangents) : this.surfaceAxes(item, points, tangents, region);
90
+ const frames = this.builder.numbers(sweepMatrices(points, tangents, axes).flat());
91
+ const solid = regionSolid(this.builder, region, this.flat(item, (profile) => this.builder.node({ op: "loft", profiles: [profile], frames })));
92
+ return this.placed(item, solid);
93
+ }
94
+ primitive(item, type) {
95
+ switch (type) {
96
+ case "IfcBlock": {
97
+ const [x, y, z] = [this.number(item, "XLength"), this.number(item, "YLength"), this.number(item, "ZLength")];
98
+ const profile = this.builder.node({ op: "polygon", points: this.builder.numbers([0, 0, x, 0, x, y, 0, y]), holes: [] });
99
+ return this.placed(item, this.builder.node({ op: "extrude", profile, direction: Z_AXIS, depth: z }));
100
+ }
101
+ case "IfcRightCircularCylinder": {
102
+ const profile = this.builder.node({ op: "circle", center: [0, 0], radius: this.number(item, "Radius") });
103
+ return this.placed(item, this.builder.node({ op: "extrude", profile, direction: Z_AXIS, depth: this.number(item, "Height") }));
104
+ }
105
+ case "IfcRightCircularCone": {
106
+ const [radius, height] = [this.number(item, "BottomRadius"), this.number(item, "Height")];
107
+ const profile = this.builder.node({ op: "polygon", points: this.builder.numbers([0, 0, radius, 0, 0, height]), holes: [] });
108
+ const cone = this.builder.node({ op: "revolve", profile, origin: [0, 0], direction: [0, 1], angle: FULL_TURN });
109
+ return this.placed(item, this.builder.node({ op: "transform", of: cone, matrix: Y_TO_Z }));
110
+ }
111
+ case "IfcSphere": {
112
+ const radius = this.number(item, "Radius");
113
+ const segments = arcSegments(Math.PI);
114
+ const half = Array.from({ length: segments + 1 }, (_, at) => {
115
+ const angle = -Math.PI / 2 + (Math.PI * at) / segments;
116
+ return [radius * Math.cos(angle), radius * Math.sin(angle)];
117
+ }).flat();
118
+ const profile = this.builder.node({ op: "polygon", points: this.builder.numbers(half), holes: [] });
119
+ return this.placed(item, this.builder.node({ op: "revolve", profile, origin: [0, 0], direction: [0, 1], angle: FULL_TURN }));
120
+ }
121
+ default:
122
+ return this.placed(item, this.pyramid(item));
123
+ }
124
+ }
125
+ pyramid(item) {
126
+ const [x, y, height] = [this.number(item, "XLength"), this.number(item, "YLength"), this.number(item, "Height")];
127
+ const positions = [0, 0, 0, x, 0, 0, x, y, 0, 0, y, 0, x / 2, y / 2, height];
128
+ return this.builder.node({ op: "triangles", positions: this.builder.numbers(positions), indices: this.builder.indices(PYRAMID_TRIANGLES) });
129
+ }
130
+ taperBetween(item, start, end, loft) {
131
+ if (start.kind === "circle" && end.kind === "circle") {
132
+ const outer = loft(profileNode(this.builder, start), profileNode(this.builder, end));
133
+ if (!(start.innerRadius > 0) && !(end.innerRadius > 0)) {
134
+ return outer;
135
+ }
136
+ if (!(start.innerRadius > 0) || !(end.innerRadius > 0)) {
137
+ throw new UnsupportedGeometryError(`#${item} tapers between a hollow and a solid circle`);
138
+ }
139
+ const inner = loft(profileNode(this.builder, start, start.innerRadius), profileNode(this.builder, end, end.innerRadius));
140
+ return this.builder.node({ op: "difference", of: outer, tools: [inner] });
141
+ }
142
+ if (start.kind !== "polygon" || end.kind !== "polygon" || start.plane !== undefined || end.plane !== undefined) {
143
+ throw new UnsupportedGeometryError(`#${item} tapers between profiles of different kinds, which is not supported yet`);
144
+ }
145
+ return loft(profileNode(this.builder, start), profileNode(this.builder, end));
146
+ }
147
+ fixedAxes(item, tangents) {
148
+ const reference = directionOf(this.model, this.model.attribute(item, "FixedReference"), [1, 0, 0]);
149
+ return tangents.map((tangent) => {
150
+ const axis = squared(reference, tangent);
151
+ if (axis === undefined) {
152
+ throw new UnsupportedGeometryError(`#${item} has a fixed reference along its directrix`);
153
+ }
154
+ return axis;
155
+ });
156
+ }
157
+ surfaceAxes(item, points, tangents, region) {
158
+ const surface = this.model.attribute(item, "ReferenceSurface");
159
+ const type = isReference(surface) ? this.model.entity(surface.ref).type : "";
160
+ const normalAt = this.surfaceNormal(isReference(surface) ? surface.ref : 0, type);
161
+ if (normalAt === undefined) {
162
+ if (region.kind === "circle" && region.center[0] === 0 && region.center[1] === 0) {
163
+ return transportedAxes(points, tangents, NO_AXIS);
164
+ }
165
+ throw new UnsupportedGeometryError(`A sweep on an ${type || "unnamed"} reference surface is not supported yet`);
166
+ }
167
+ return tangents.map((tangent) => {
168
+ const axis = squared(normalAt(tangent), tangent);
169
+ if (axis === undefined) {
170
+ throw new UnsupportedGeometryError(`#${item}'s directrix runs along the normal of its reference surface`);
171
+ }
172
+ return axis;
173
+ });
174
+ }
175
+ surfaceNormal(surface, type) {
176
+ const position = surface === 0 ? null : this.model.attribute(surface, "Position");
177
+ const frame = isReference(position) ? axisPlacementFrame(this.model, position.ref) : undefined;
178
+ if (type === "IfcPlane" && frame) {
179
+ return () => frame.z;
180
+ }
181
+ if (type !== "IfcSurfaceOfLinearExtrusion") {
182
+ return undefined;
183
+ }
184
+ const direction = directionOf(this.model, this.model.attribute(surface, "ExtrudedDirection"), Z_AXIS);
185
+ const extruded = frame ? vectorToWorld(frame, direction) : direction;
186
+ return (tangent) => cross3(tangent, extruded);
187
+ }
188
+ endsOf(item) {
189
+ const directrix = this.model.attribute(item, "Directrix");
190
+ return isReference(directrix) ? this.curves.endTangents(directrix.ref) : [undefined, undefined];
191
+ }
192
+ sweptPath(item) {
193
+ const directrix = this.model.attribute(item, "Directrix");
194
+ if (!isReference(directrix)) {
195
+ throw new UnsupportedGeometryError(`#${item} has no directrix`);
196
+ }
197
+ const points = this.curves.path(directrix.ref);
198
+ if (points.length < 2) {
199
+ throw new UnsupportedGeometryError(`#${item} sweeps along a directrix of no length`);
200
+ }
201
+ const start = this.model.attribute(item, "StartParam");
202
+ const end = this.model.attribute(item, "EndParam");
203
+ if (start === null && end === null) {
204
+ return points;
205
+ }
206
+ const span = this.curves.parameterSpan(directrix.ref);
207
+ const from = typeof start === "number" ? start : 0;
208
+ const to = typeof end === "number" ? end : span;
209
+ if (span !== undefined && to !== undefined && Math.abs(to - from - span) <= PARAMETER_RATIO * Math.max(1, span)) {
210
+ return points;
211
+ }
212
+ throw new UnsupportedGeometryError(`#${item} sweeps along part of its directrix, which is not supported yet`);
213
+ }
214
+ flat(item, make) {
215
+ return (profile, part) => {
216
+ if (part.kind === "polygon" && part.plane !== undefined) {
217
+ throw new UnsupportedGeometryError(`#${item} sweeps a profile written off its own plane`);
218
+ }
219
+ return make(profile);
220
+ };
221
+ }
222
+ region(item, name) {
223
+ const area = this.model.attribute(item, name);
224
+ if (!isReference(area)) {
225
+ throw new UnsupportedGeometryError(`#${item} has no ${name}`);
226
+ }
227
+ return profileRegion(this.model, area.ref, this.curves);
228
+ }
229
+ number(item, name) {
230
+ const value = this.model.attribute(item, name);
231
+ if (typeof value !== "number" || !Number.isFinite(value)) {
232
+ throw new UnsupportedGeometryError(`#${item} has no finite ${name}`);
233
+ }
234
+ return value;
235
+ }
236
+ placed(item, solid) {
237
+ const position = this.model.attribute(item, "Position");
238
+ if (!isReference(position)) {
239
+ return solid;
240
+ }
241
+ return this.builder.node({ op: "transform", of: solid, matrix: axesToMatrix(axisPlacementFrame(this.model, position.ref)) });
242
+ }
243
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./api/inputs";
2
+ export * from "./api/ifc-service";
3
+ export * from "./api/services";
4
+ export * from "./api/dto-registry";
5
+ export * as Resolved from "./api/resolved-inputs";
6
+ export * from "./model";
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./api/inputs";
2
+ export * from "./api/ifc-service";
3
+ export * from "./api/services";
4
+ export * from "./api/dto-registry";
5
+ export * as Resolved from "./api/resolved-inputs";
6
+ export * from "./model";
@@ -0,0 +1,30 @@
1
+ export declare const GUID_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
2
+ export declare const GUID_BYTES = 16;
3
+ export declare const BYTE_RANGE = 256;
4
+ export declare const FIRST_BYTE_DIGITS = 2;
5
+ export declare const THREE_BYTE_DIGITS = 4;
6
+ export declare const BYTES_PER_GROUP = 3;
7
+ export declare const HASH_BYTES_USED = 6;
8
+ export declare const VERSION_BYTE = 6;
9
+ export declare const VERSION_MASK = 15;
10
+ export declare const VERSION_BITS = 64;
11
+ export declare const VARIANT_BYTE = 8;
12
+ export declare const VARIANT_MASK = 63;
13
+ export declare const VARIANT_BITS = 128;
14
+ export declare const KEY_DOMAIN = "key";
15
+ export declare const AUTOMATIC_DOMAIN = "automatic";
16
+ export declare const STRUCTURE_DOMAIN = "structure";
17
+ export declare const PROJECT_KEY = "project";
18
+ export declare const TRIE_BITS = 5;
19
+ export declare const TRIE_WIDTH: number;
20
+ export declare const TRIE_MASK: number;
21
+ export declare const TRIE_LEVELS = 7;
22
+ export declare const PRUNABLE_TYPES: readonly ["IfcRepresentation", "IfcRepresentationItem", "IfcProductRepresentation", "IfcObjectPlacement", "IfcProfileDef", "IfcMaterialUsageDefinition", "IfcRepresentationMap", "IfcPropertySetDefinition", "IfcProperty", "IfcPhysicalQuantity"];
23
+ export declare const LONGEST_STRING: number;
24
+ export declare const TEXT_PER_CHUNK: number;
25
+ export declare const LINE_BREAK = "\n";
26
+ export declare const WINDOWS_LINE_BREAK = "\r\n";
27
+ export declare const LINE_FEED = 10;
28
+ export declare const CARRIAGE_RETURN = 13;
29
+ export declare const IFC_EXTENSION = ".ifc";
30
+ export declare const ARCHIVE_RESOURCE_FOLDER = "__MACOSX/";
@@ -0,0 +1,30 @@
1
+ export const GUID_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
2
+ export const GUID_BYTES = 16;
3
+ export const BYTE_RANGE = 256;
4
+ export const FIRST_BYTE_DIGITS = 2;
5
+ export const THREE_BYTE_DIGITS = 4;
6
+ export const BYTES_PER_GROUP = 3;
7
+ export const HASH_BYTES_USED = 6;
8
+ export const VERSION_BYTE = 6;
9
+ export const VERSION_MASK = 0x0f;
10
+ export const VERSION_BITS = 0x40;
11
+ export const VARIANT_BYTE = 8;
12
+ export const VARIANT_MASK = 0x3f;
13
+ export const VARIANT_BITS = 0x80;
14
+ export const KEY_DOMAIN = "key";
15
+ export const AUTOMATIC_DOMAIN = "automatic";
16
+ export const STRUCTURE_DOMAIN = "structure";
17
+ export const PROJECT_KEY = "project";
18
+ export const TRIE_BITS = 5;
19
+ export const TRIE_WIDTH = Math.pow(2, TRIE_BITS);
20
+ export const TRIE_MASK = TRIE_WIDTH - 1;
21
+ export const TRIE_LEVELS = 7;
22
+ export const PRUNABLE_TYPES = ["IfcRepresentation", "IfcRepresentationItem", "IfcProductRepresentation", "IfcObjectPlacement", "IfcProfileDef", "IfcMaterialUsageDefinition", "IfcRepresentationMap", "IfcPropertySetDefinition", "IfcProperty", "IfcPhysicalQuantity"];
23
+ export const LONGEST_STRING = Math.pow(2, 29) - 24;
24
+ export const TEXT_PER_CHUNK = Math.pow(2, 24);
25
+ export const LINE_BREAK = "\n";
26
+ export const WINDOWS_LINE_BREAK = "\r\n";
27
+ export const LINE_FEED = 0x0a;
28
+ export const CARRIAGE_RETURN = 0x0d;
29
+ export const IFC_EXTENSION = ".ifc";
30
+ export const ARCHIVE_RESOURCE_FOLDER = "__MACOSX/";
@@ -0,0 +1,9 @@
1
+ import type { IfcSchema } from "../schema/schema";
2
+ import type { IfcEntity, IfcValue } from "../step/step-types";
3
+ export declare abstract class EntityLookup {
4
+ abstract readonly schema: IfcSchema;
5
+ abstract get(id: number): IfcEntity | undefined;
6
+ entity(id: number): IfcEntity;
7
+ attribute(id: number, name: string): IfcValue;
8
+ valueOf(entity: IfcEntity, name: string): IfcValue;
9
+ }
@@ -0,0 +1,20 @@
1
+ export class EntityLookup {
2
+ entity(id) {
3
+ const entity = this.get(id);
4
+ if (!entity) {
5
+ throw new Error(`The model has no entity #${id}`);
6
+ }
7
+ return entity;
8
+ }
9
+ attribute(id, name) {
10
+ return this.valueOf(this.entity(id), name);
11
+ }
12
+ valueOf(entity, name) {
13
+ var _a;
14
+ const position = this.schema.entity(entity.type).positions.get(name);
15
+ if (position === undefined) {
16
+ throw new Error(`${entity.type} has no attribute ${name}`);
17
+ }
18
+ return (_a = entity.args[position]) !== null && _a !== void 0 ? _a : null;
19
+ }
20
+ }
@@ -0,0 +1,7 @@
1
+ export declare function isGlobalId(text: string): boolean;
2
+ export declare function compressBytes(bytes: Uint8Array): string;
3
+ export declare function randomGlobalId(): string;
4
+ export declare function projectGlobalId(seed: string): string;
5
+ export declare function keyGlobalId(seed: string, key: string): string;
6
+ export declare function automaticGlobalId(seed: string, counter: string): string;
7
+ export declare function structureGlobalId(seed: string, name: string): string;
@@ -0,0 +1,60 @@
1
+ import { hashOfText } from "@bitbybit-dev/base";
2
+ import { GLOBAL_ID_PATTERN } from "../schema/constants";
3
+ import { AUTOMATIC_DOMAIN, BYTES_PER_GROUP, BYTE_RANGE, FIRST_BYTE_DIGITS, GUID_ALPHABET, GUID_BYTES, HASH_BYTES_USED, KEY_DOMAIN, PROJECT_KEY, STRUCTURE_DOMAIN, THREE_BYTE_DIGITS, VARIANT_BITS, VARIANT_BYTE, VARIANT_MASK, VERSION_BITS, VERSION_BYTE, VERSION_MASK, } from "./constants";
4
+ const RADIX = GUID_ALPHABET.length;
5
+ function digits(value, count) {
6
+ let out = "";
7
+ let rest = value;
8
+ for (let index = 0; index < count; index++) {
9
+ out = GUID_ALPHABET[rest % RADIX] + out;
10
+ rest = Math.floor(rest / RADIX);
11
+ }
12
+ return out;
13
+ }
14
+ function stamped(bytes) {
15
+ const out = Uint8Array.from(bytes);
16
+ out[VERSION_BYTE] = (out[VERSION_BYTE] & VERSION_MASK) | VERSION_BITS;
17
+ out[VARIANT_BYTE] = (out[VARIANT_BYTE] & VARIANT_MASK) | VARIANT_BITS;
18
+ return out;
19
+ }
20
+ function seeded(seed, key) {
21
+ const bytes = new Uint8Array(GUID_BYTES);
22
+ for (let part = 0, at = 0; at < GUID_BYTES; part++) {
23
+ let hash = hashOfText(`${seed}\u0000${key}\u0000${part}`);
24
+ for (let index = 0; index < HASH_BYTES_USED && at < GUID_BYTES; index++, at++) {
25
+ bytes[at] = hash % BYTE_RANGE;
26
+ hash = Math.floor(hash / BYTE_RANGE);
27
+ }
28
+ }
29
+ return compressBytes(stamped(bytes));
30
+ }
31
+ export function isGlobalId(text) {
32
+ return GLOBAL_ID_PATTERN.test(text);
33
+ }
34
+ export function compressBytes(bytes) {
35
+ if (bytes.length !== GUID_BYTES) {
36
+ throw new RangeError(`A GlobalId holds ${GUID_BYTES} bytes, got ${bytes.length}`);
37
+ }
38
+ let out = digits(bytes[0], FIRST_BYTE_DIGITS);
39
+ for (let index = 1; index < GUID_BYTES; index += BYTES_PER_GROUP) {
40
+ out += digits(bytes[index] * BYTE_RANGE * BYTE_RANGE + bytes[index + 1] * BYTE_RANGE + bytes[index + 2], THREE_BYTE_DIGITS);
41
+ }
42
+ return out;
43
+ }
44
+ export function randomGlobalId() {
45
+ const bytes = new Uint8Array(GUID_BYTES);
46
+ globalThis.crypto.getRandomValues(bytes);
47
+ return compressBytes(stamped(bytes));
48
+ }
49
+ export function projectGlobalId(seed) {
50
+ return seeded(seed, PROJECT_KEY);
51
+ }
52
+ export function keyGlobalId(seed, key) {
53
+ return seeded(seed, `${KEY_DOMAIN}\u0000${key}`);
54
+ }
55
+ export function automaticGlobalId(seed, counter) {
56
+ return seeded(seed, `${AUTOMATIC_DOMAIN}\u0000${counter}`);
57
+ }
58
+ export function structureGlobalId(seed, name) {
59
+ return seeded(seed, `${STRUCTURE_DOMAIN}\u0000${name}`);
60
+ }
@@ -0,0 +1,10 @@
1
+ export declare class IdMap<V> {
2
+ readonly size: number;
3
+ private readonly root;
4
+ private constructor();
5
+ static empty<V>(): IdMap<V>;
6
+ get(id: number): V | undefined;
7
+ has(id: number): boolean;
8
+ withChanges(changes: Iterable<readonly [number, V | undefined]>): IdMap<V>;
9
+ forEach(each: (value: V, id: number) => void): void;
10
+ }
@@ -0,0 +1,80 @@
1
+ import { TRIE_LEVELS, TRIE_MASK, TRIE_WIDTH } from "./constants";
2
+ function slotAt(id, level) {
3
+ return Math.floor(id / Math.pow(TRIE_WIDTH, level)) & TRIE_MASK;
4
+ }
5
+ function writable(node, level, owner) {
6
+ if ((node === null || node === void 0 ? void 0 : node.owner) === owner) {
7
+ return node;
8
+ }
9
+ if (!node) {
10
+ return level === 0 ? { owner, children: [], values: new Array(TRIE_WIDTH) } : { owner, children: new Array(TRIE_WIDTH), values: [] };
11
+ }
12
+ return { owner, children: level === 0 ? node.children : node.children.slice(), values: level === 0 ? node.values.slice() : node.values };
13
+ }
14
+ function valueAt(root, id) {
15
+ let node = root;
16
+ for (let level = TRIE_LEVELS - 1; level > 0 && node; level--) {
17
+ node = node.children[slotAt(id, level)];
18
+ }
19
+ return node === null || node === void 0 ? void 0 : node.values[id & TRIE_MASK];
20
+ }
21
+ function visit(node, level, prefix, each) {
22
+ for (let slot = 0; slot < TRIE_WIDTH; slot++) {
23
+ const id = prefix * TRIE_WIDTH + slot;
24
+ if (level === 0) {
25
+ const value = node.values[slot];
26
+ if (value !== undefined) {
27
+ each(value, id);
28
+ }
29
+ }
30
+ else {
31
+ const child = node.children[slot];
32
+ if (child) {
33
+ visit(child, level - 1, id, each);
34
+ }
35
+ }
36
+ }
37
+ }
38
+ export class IdMap {
39
+ constructor(root, size) {
40
+ this.root = root;
41
+ this.size = size;
42
+ }
43
+ static empty() {
44
+ return new IdMap(undefined, 0);
45
+ }
46
+ get(id) {
47
+ return valueAt(this.root, id);
48
+ }
49
+ has(id) {
50
+ return this.get(id) !== undefined;
51
+ }
52
+ withChanges(changes) {
53
+ const owner = {};
54
+ let root = this.root;
55
+ let size = this.size;
56
+ for (const [id, value] of changes) {
57
+ if (value === undefined && valueAt(root, id) === undefined) {
58
+ continue;
59
+ }
60
+ root = writable(root, TRIE_LEVELS - 1, owner);
61
+ let node = root;
62
+ for (let level = TRIE_LEVELS - 1; level > 0; level--) {
63
+ const slot = slotAt(id, level);
64
+ const child = writable(node.children[slot], level - 1, owner);
65
+ node.children[slot] = child;
66
+ node = child;
67
+ }
68
+ const slot = id & TRIE_MASK;
69
+ const before = node.values[slot];
70
+ node.values[slot] = value;
71
+ size += (value === undefined ? 0 : 1) - (before === undefined ? 0 : 1);
72
+ }
73
+ return root === this.root ? this : new IdMap(root, size);
74
+ }
75
+ forEach(each) {
76
+ if (this.root) {
77
+ visit(this.root, TRIE_LEVELS - 1, 0, each);
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,4 @@
1
+ export type { IfcModel } from "./model-types";
2
+ export type { IfcEntity, IfcValue, IfcReference, IfcEnumerationValue, IfcTypedValue, IfcBinaryValue, IfcDerivedValue, IfcFileHeader } from "../step/step-types";
3
+ export { StepSyntaxError, IfcValueError } from "../step/errors";
4
+ export { isIfcModel } from "./is-model";
@@ -0,0 +1,2 @@
1
+ export { StepSyntaxError, IfcValueError } from "../step/errors";
2
+ export { isIfcModel } from "./is-model";
@@ -0,0 +1,6 @@
1
+ import type { IfcFileHeader } from "../step/step-types";
2
+ import { ModelSnapshot } from "./snapshot";
3
+ export declare function readModel(input: Uint8Array | ArrayBuffer | string): ModelSnapshot;
4
+ export declare function emptyModel(schemaName: string, header: IfcFileHeader): ModelSnapshot;
5
+ export declare function writeModel(model: ModelSnapshot, header?: IfcFileHeader, longest?: number): string;
6
+ export declare function writeModelBytes(model: ModelSnapshot, header?: IfcFileHeader, textPerChunk?: number): Uint8Array;