@ifc-lite/create 2.8.0 → 3.1.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 (159) hide show
  1. package/README.md +7 -0
  2. package/dist/ifc-creator-alignment-referents.d.ts +35 -0
  3. package/dist/ifc-creator-alignment-referents.d.ts.map +1 -0
  4. package/dist/ifc-creator-alignment-referents.js +89 -0
  5. package/dist/ifc-creator-alignment-referents.js.map +1 -0
  6. package/dist/ifc-creator-alignment-vertical.d.ts +40 -0
  7. package/dist/ifc-creator-alignment-vertical.d.ts.map +1 -0
  8. package/dist/ifc-creator-alignment-vertical.js +182 -0
  9. package/dist/ifc-creator-alignment-vertical.js.map +1 -0
  10. package/dist/ifc-creator-alignment.d.ts +45 -0
  11. package/dist/ifc-creator-alignment.d.ts.map +1 -0
  12. package/dist/ifc-creator-alignment.js +173 -0
  13. package/dist/ifc-creator-alignment.js.map +1 -0
  14. package/dist/ifc-creator-header.d.ts +2 -0
  15. package/dist/ifc-creator-header.d.ts.map +1 -0
  16. package/dist/ifc-creator-header.js +22 -0
  17. package/dist/ifc-creator-header.js.map +1 -0
  18. package/dist/ifc-creator-math.d.ts +37 -5
  19. package/dist/ifc-creator-math.d.ts.map +1 -1
  20. package/dist/ifc-creator-math.js +93 -4
  21. package/dist/ifc-creator-math.js.map +1 -1
  22. package/dist/ifc-creator-relationships.d.ts +43 -0
  23. package/dist/ifc-creator-relationships.d.ts.map +1 -0
  24. package/dist/ifc-creator-relationships.js +38 -0
  25. package/dist/ifc-creator-relationships.js.map +1 -0
  26. package/dist/ifc-creator-styles.d.ts +22 -0
  27. package/dist/ifc-creator-styles.d.ts.map +1 -0
  28. package/dist/ifc-creator-styles.js +50 -0
  29. package/dist/ifc-creator-styles.js.map +1 -0
  30. package/dist/ifc-creator-terrain.d.ts +170 -0
  31. package/dist/ifc-creator-terrain.d.ts.map +1 -0
  32. package/dist/ifc-creator-terrain.js +180 -0
  33. package/dist/ifc-creator-terrain.js.map +1 -0
  34. package/dist/ifc-creator.d.ts +21 -7
  35. package/dist/ifc-creator.d.ts.map +1 -1
  36. package/dist/ifc-creator.js +93 -97
  37. package/dist/ifc-creator.js.map +1 -1
  38. package/dist/in-store/_emit-helpers.d.ts +2 -1
  39. package/dist/in-store/_emit-helpers.d.ts.map +1 -1
  40. package/dist/in-store/_emit-helpers.js +7 -7
  41. package/dist/in-store/_emit-helpers.js.map +1 -1
  42. package/dist/in-store/anchor.d.ts +2 -0
  43. package/dist/in-store/anchor.d.ts.map +1 -1
  44. package/dist/in-store/anchor.js.map +1 -1
  45. package/dist/in-store/apply-style.d.ts +3 -6
  46. package/dist/in-store/apply-style.d.ts.map +1 -1
  47. package/dist/in-store/apply-style.js +3 -77
  48. package/dist/in-store/apply-style.js.map +1 -1
  49. package/dist/in-store/column.d.ts.map +1 -1
  50. package/dist/in-store/column.js +2 -0
  51. package/dist/in-store/column.js.map +1 -1
  52. package/dist/in-store/door.d.ts.map +1 -1
  53. package/dist/in-store/door.js +2 -0
  54. package/dist/in-store/door.js.map +1 -1
  55. package/dist/in-store/extract-walls.d.ts +1 -1
  56. package/dist/in-store/extract-walls.d.ts.map +1 -1
  57. package/dist/in-store/extract-walls.js +37 -55
  58. package/dist/in-store/extract-walls.js.map +1 -1
  59. package/dist/in-store/generate-spaces-all.d.ts +6 -2
  60. package/dist/in-store/generate-spaces-all.d.ts.map +1 -1
  61. package/dist/in-store/generate-spaces-all.js +33 -9
  62. package/dist/in-store/generate-spaces-all.js.map +1 -1
  63. package/dist/in-store/generate-spaces.js +1 -1
  64. package/dist/in-store/generate-spaces.js.map +1 -1
  65. package/dist/in-store/placement-frame.d.ts +8 -0
  66. package/dist/in-store/placement-frame.d.ts.map +1 -1
  67. package/dist/in-store/placement-frame.js.map +1 -1
  68. package/dist/in-store/plate.d.ts.map +1 -1
  69. package/dist/in-store/plate.js +4 -0
  70. package/dist/in-store/plate.js.map +1 -1
  71. package/dist/in-store/resolve-anchor.d.ts +4 -2
  72. package/dist/in-store/resolve-anchor.d.ts.map +1 -1
  73. package/dist/in-store/resolve-anchor.js +79 -92
  74. package/dist/in-store/resolve-anchor.js.map +1 -1
  75. package/dist/in-store/resolve-source.d.ts +2 -1
  76. package/dist/in-store/resolve-source.d.ts.map +1 -1
  77. package/dist/in-store/resolve-source.js +49 -49
  78. package/dist/in-store/resolve-source.js.map +1 -1
  79. package/dist/in-store/roof.d.ts.map +1 -1
  80. package/dist/in-store/roof.js +4 -0
  81. package/dist/in-store/roof.js.map +1 -1
  82. package/dist/in-store/slab.d.ts.map +1 -1
  83. package/dist/in-store/slab.js +4 -0
  84. package/dist/in-store/slab.js.map +1 -1
  85. package/dist/in-store/space.d.ts.map +1 -1
  86. package/dist/in-store/space.js +4 -0
  87. package/dist/in-store/space.js.map +1 -1
  88. package/dist/in-store/spatial-children.d.ts +52 -0
  89. package/dist/in-store/spatial-children.d.ts.map +1 -0
  90. package/dist/in-store/spatial-children.js +112 -0
  91. package/dist/in-store/spatial-children.js.map +1 -0
  92. package/dist/in-store/spatial-zone.d.ts.map +1 -1
  93. package/dist/in-store/spatial-zone.js +5 -5
  94. package/dist/in-store/spatial-zone.js.map +1 -1
  95. package/dist/in-store/style-entity-reader.d.ts +14 -0
  96. package/dist/in-store/style-entity-reader.d.ts.map +1 -0
  97. package/dist/in-store/style-entity-reader.js +58 -0
  98. package/dist/in-store/style-entity-reader.js.map +1 -0
  99. package/dist/in-store/wall.d.ts.map +1 -1
  100. package/dist/in-store/wall.js +4 -14
  101. package/dist/in-store/wall.js.map +1 -1
  102. package/dist/in-store/window.d.ts.map +1 -1
  103. package/dist/in-store/window.js +2 -0
  104. package/dist/in-store/window.js.map +1 -1
  105. package/dist/index.d.ts +12 -1
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +5 -0
  108. package/dist/index.js.map +1 -1
  109. package/dist/landxml/alignment-mapping.d.ts +98 -0
  110. package/dist/landxml/alignment-mapping.d.ts.map +1 -0
  111. package/dist/landxml/alignment-mapping.js +282 -0
  112. package/dist/landxml/alignment-mapping.js.map +1 -0
  113. package/dist/landxml/alignment-record.d.ts +18 -0
  114. package/dist/landxml/alignment-record.d.ts.map +1 -0
  115. package/dist/landxml/alignment-record.js +63 -0
  116. package/dist/landxml/alignment-record.js.map +1 -0
  117. package/dist/landxml/coordinate-plausibility.d.ts +54 -0
  118. package/dist/landxml/coordinate-plausibility.d.ts.map +1 -0
  119. package/dist/landxml/coordinate-plausibility.js +59 -0
  120. package/dist/landxml/coordinate-plausibility.js.map +1 -0
  121. package/dist/landxml/landxml-to-ifc.d.ts +45 -0
  122. package/dist/landxml/landxml-to-ifc.d.ts.map +1 -0
  123. package/dist/landxml/landxml-to-ifc.js +203 -0
  124. package/dist/landxml/landxml-to-ifc.js.map +1 -0
  125. package/dist/landxml/profile-geometry.d.ts +50 -0
  126. package/dist/landxml/profile-geometry.d.ts.map +1 -0
  127. package/dist/landxml/profile-geometry.js +221 -0
  128. package/dist/landxml/profile-geometry.js.map +1 -0
  129. package/dist/landxml/profile-mapping.d.ts +36 -0
  130. package/dist/landxml/profile-mapping.d.ts.map +1 -0
  131. package/dist/landxml/profile-mapping.js +181 -0
  132. package/dist/landxml/profile-mapping.js.map +1 -0
  133. package/dist/landxml/profile-record.d.ts +46 -0
  134. package/dist/landxml/profile-record.d.ts.map +1 -0
  135. package/dist/landxml/profile-record.js +38 -0
  136. package/dist/landxml/profile-record.js.map +1 -0
  137. package/dist/landxml/refusals.d.ts +45 -0
  138. package/dist/landxml/refusals.d.ts.map +1 -0
  139. package/dist/landxml/refusals.js +141 -0
  140. package/dist/landxml/refusals.js.map +1 -0
  141. package/dist/landxml/result-types.d.ts +78 -0
  142. package/dist/landxml/result-types.d.ts.map +1 -0
  143. package/dist/landxml/result-types.js +5 -0
  144. package/dist/landxml/result-types.js.map +1 -0
  145. package/dist/landxml/source-types.d.ts +169 -0
  146. package/dist/landxml/source-types.d.ts.map +1 -0
  147. package/dist/landxml/source-types.js +5 -0
  148. package/dist/landxml/source-types.js.map +1 -0
  149. package/dist/landxml/station-equations.d.ts +69 -0
  150. package/dist/landxml/station-equations.d.ts.map +1 -0
  151. package/dist/landxml/station-equations.js +140 -0
  152. package/dist/landxml/station-equations.js.map +1 -0
  153. package/dist/landxml/writers.d.ts +33 -0
  154. package/dist/landxml/writers.d.ts.map +1 -0
  155. package/dist/landxml/writers.js +160 -0
  156. package/dist/landxml/writers.js.map +1 -0
  157. package/dist/types.d.ts +13 -2
  158. package/dist/types.d.ts.map +1 -1
  159. package/package.json +6 -6
package/README.md CHANGED
@@ -29,6 +29,13 @@ const { content } = creator.toIfc(); // IFC STEP text
29
29
  - Property sets, element quantities, materials, and colors
30
30
  - 4D scheduling entities: IfcWorkSchedule, IfcTask, IfcRelSequence
31
31
  - In-store builders (`addWallToStore`, `addSlabToStore`, ...) that emit elements into an existing parsed model
32
+ - `resolveSpatialAnchor(store, storeyId, view)` reads the live mutation view when
33
+ authoring into an edited model. Pass the same view as the `StoreEditor` so a
34
+ created storey or placement, and deletions or retypes of source anchors, are
35
+ reflected before an element is emitted. Omitting `view` reads the parsed model.
36
+ - `applyStylesInStore` reads styled items and representation chains from the
37
+ editor's live overlay, so a deleted style can be replaced and an authored
38
+ style is found before adding another one to the same representation item.
32
39
  - Loaded-model cost builders (`addCostScheduleToStore`, `addCostItemToStore`, `addCostValueToStore`,
33
40
  `addCostQuantityToStore`) plus relationship helpers for nesting, schedule/object assignment, value lists,
34
41
  and safe removal. They require a `CostAnchor` for schema/owner-history/GUID allocation, accept existing
@@ -0,0 +1,35 @@
1
+ import { type HorizontalSegment } from './landxml/alignment-mapping.js';
2
+ /** One station equation (§14.1): all lengths in the file's length unit. */
3
+ export interface StationEquationParams {
4
+ /** Distance along the alignment's basis curve from its start. */
5
+ DistanceAlong: number;
6
+ /** `Pset_Stationing.Station` — the station from here on. */
7
+ Station: number;
8
+ /** `Pset_Stationing.IncomingStation` — the station arriving here. */
9
+ IncomingStation: number;
10
+ /** `Pset_Stationing.HasIncreasingStation`; omitted when `null` or absent. */
11
+ HasIncreasingStation?: boolean | null;
12
+ /** GlobalId seed role; defaults to `station-equation:<n>` (1-based). */
13
+ Role?: string;
14
+ }
15
+ export interface StationingContext {
16
+ emit: (type: string, attrs: string) => number;
17
+ ownerRef: string;
18
+ guid: (role: string) => string;
19
+ }
20
+ export interface StationingParams {
21
+ alignmentId: number;
22
+ compositeCurveId: number;
23
+ segments: readonly HorizontalSegment[];
24
+ startStation: number;
25
+ equations: readonly StationEquationParams[];
26
+ }
27
+ /** `0+123.456` — kilometres and metres, the usual stationing label. */
28
+ export declare function stationLabel(station: number): string;
29
+ /**
30
+ * Write the start referent (distance 0) and one referent per station
31
+ * equation, nest them under the alignment in order along it, and position
32
+ * the alignment by the start referent. Returns the referent ids, start first.
33
+ */
34
+ export declare function emitStationing(params: StationingParams, ctx: StationingContext): number[];
35
+ //# sourceMappingURL=ifc-creator-alignment-referents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc-creator-alignment-referents.d.ts","sourceRoot":"","sources":["../src/ifc-creator-alignment-referents.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEzF,2EAA2E;AAC3E,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,eAAe,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,oBAAoB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACtC,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC7C;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMpD;AAmDD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAoCzF"}
@@ -0,0 +1,89 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * An alignment's stationing: `IfcReferent`s / `.STATION.` carrying
6
+ * `Pset_Stationing`, nested under the alignment in order along it (mapping
7
+ * spec §11.1, §14).
8
+ *
9
+ * Each referent is placed the way IfcOpenShell 0.8.5's
10
+ * `add_stationing_referent` places one: an `IfcLinearPlacement` whose
11
+ * `IfcPointByDistanceExpression` measures `DistanceAlong` on the alignment's
12
+ * own composite curve, with the evaluated point and tangent as its
13
+ * `CartesianPosition`.
14
+ */
15
+ import { esc, num } from './ifc-creator-math.js';
16
+ import { evaluateSegment } from './landxml/alignment-mapping.js';
17
+ /** `0+123.456` — kilometres and metres, the usual stationing label. */
18
+ export function stationLabel(station) {
19
+ const sign = station < 0 ? '-' : '';
20
+ const abs = Math.abs(station);
21
+ const km = Math.floor(abs / 1000);
22
+ const m = (abs - km * 1000).toFixed(3).padStart(7, '0');
23
+ return `${sign}${km}+${m}`;
24
+ }
25
+ /** Point and tangent direction at `distance` along the layout's segments. */
26
+ function pointAlong(segments, distance) {
27
+ let remaining = distance;
28
+ for (let index = 0; index < segments.length; index += 1) {
29
+ const segment = segments[index];
30
+ if (remaining <= segment.length || index === segments.length - 1) {
31
+ return evaluateSegment(segment.start, segment.direction, segment.startCurvature, segment.endCurvature, segment.length, Math.min(remaining, segment.length));
32
+ }
33
+ remaining -= segment.length;
34
+ }
35
+ throw new Error('addAlignment: cannot place a referent on an alignment with no segments');
36
+ }
37
+ function linearPlacement(ctx, compositeCurveId, distance, at) {
38
+ const along = ctx.emit('IFCPOINTBYDISTANCEEXPRESSION', `IFCLENGTHMEASURE(${num(distance)}),$,$,$,#${compositeCurveId}`);
39
+ const linear = ctx.emit('IFCAXIS2PLACEMENTLINEAR', `#${along},$,$`);
40
+ const point = ctx.emit('IFCCARTESIANPOINT', `(${num(at.point[0])},${num(at.point[1])},0.)`);
41
+ const up = ctx.emit('IFCDIRECTION', '(0.,0.,1.)');
42
+ const ahead = ctx.emit('IFCDIRECTION', `(${num(Math.cos(at.direction))},${num(Math.sin(at.direction))},0.)`);
43
+ const cartesian = ctx.emit('IFCAXIS2PLACEMENT3D', `#${point},#${up},#${ahead}`);
44
+ return ctx.emit('IFCLINEARPLACEMENT', `$,#${linear},#${cartesian}`);
45
+ }
46
+ function stationReferent(ctx, placement, station, roles, extra = []) {
47
+ const referentId = ctx.emit('IFCREFERENT', `'${ctx.guid(roles.referent)}',${ctx.ownerRef},'${esc(stationLabel(station))}',$,$,#${placement},$,.STATION.`);
48
+ const properties = [
49
+ ctx.emit('IFCPROPERTYSINGLEVALUE', `'Station',$,IFCLENGTHMEASURE(${num(station)}),$`),
50
+ ...extra.map((attrs) => ctx.emit('IFCPROPERTYSINGLEVALUE', attrs)),
51
+ ];
52
+ const pset = ctx.emit('IFCPROPERTYSET', `'${ctx.guid(roles.pset)}',${ctx.ownerRef},'Pset_Stationing',$,(${properties.map((id) => `#${id}`).join(',')})`);
53
+ ctx.emit('IFCRELDEFINESBYPROPERTIES', `'${ctx.guid(roles.rel)}',${ctx.ownerRef},$,$,(#${referentId}),#${pset}`);
54
+ return referentId;
55
+ }
56
+ /**
57
+ * Write the start referent (distance 0) and one referent per station
58
+ * equation, nest them under the alignment in order along it, and position
59
+ * the alignment by the start referent. Returns the referent ids, start first.
60
+ */
61
+ export function emitStationing(params, ctx) {
62
+ const first = params.segments[0];
63
+ const startPlacement = linearPlacement(ctx, params.compositeCurveId, 0, { point: first.start, direction: first.direction });
64
+ const startId = stationReferent(ctx, startPlacement, params.startStation, {
65
+ referent: 'referent:start', pset: 'pset:stationing', rel: 'rel:stationing',
66
+ });
67
+ let previous = 0;
68
+ const equationIds = params.equations.map((equation, index) => {
69
+ if (!(equation.DistanceAlong > previous)) {
70
+ throw new Error(`addAlignment: station equation ${index + 1} is at ${equation.DistanceAlong} along the alignment, `
71
+ + 'not after the previous referent; referents are nested in order along it');
72
+ }
73
+ previous = equation.DistanceAlong;
74
+ const role = equation.Role ?? `station-equation:${index + 1}`;
75
+ const placement = linearPlacement(ctx, params.compositeCurveId, equation.DistanceAlong, pointAlong(params.segments, equation.DistanceAlong));
76
+ const extra = [`'IncomingStation',$,IFCLENGTHMEASURE(${num(equation.IncomingStation)}),$`];
77
+ if (equation.HasIncreasingStation !== null && equation.HasIncreasingStation !== undefined) {
78
+ extra.push(`'HasIncreasingStation',$,IFCBOOLEAN(${equation.HasIncreasingStation ? '.T.' : '.F.'}),$`);
79
+ }
80
+ return stationReferent(ctx, placement, equation.Station, {
81
+ referent: role, pset: `${role}:pset`, rel: `${role}:rel`,
82
+ }, extra);
83
+ });
84
+ const referents = [startId, ...equationIds];
85
+ ctx.emit('IFCRELNESTS', `'${ctx.guid('nests:referents')}',${ctx.ownerRef},$,$,#${params.alignmentId},(${referents.map((id) => `#${id}`).join(',')})`);
86
+ ctx.emit('IFCRELPOSITIONS', `'${ctx.guid('positions')}',${ctx.ownerRef},$,$,#${startId},(#${params.alignmentId})`);
87
+ return referents;
88
+ }
89
+ //# sourceMappingURL=ifc-creator-alignment-referents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc-creator-alignment-referents.js","sourceRoot":"","sources":["../src/ifc-creator-alignment-referents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type VerticalSegment } from './landxml/profile-geometry.js';
2
+ /** The creator hooks this emitter needs (a subset of `AlignmentContext`). */
3
+ export interface VerticalContext {
4
+ emit: (type: string, attrs: string) => number;
5
+ ownerRef: string;
6
+ }
7
+ /** A vertical layout for `AlignmentParams.Vertical`. Distances and heights in metres. */
8
+ export interface AlignmentVerticalParams {
9
+ Name?: string;
10
+ GlobalId?: string;
11
+ /** In order along the alignment; the zero-length terminator is added here. */
12
+ Segments: readonly VerticalSegment[];
13
+ }
14
+ /**
15
+ * Arc length of `A + Bx + Cx²` over `[0, L]`.
16
+ *
17
+ * IfcOpenShell's `_polynomial_length` closed form, where it is well
18
+ * conditioned. Its terms grow like `1/C` and cancel, so as `C·L` shrinks the
19
+ * result loses digits (1e-9 relative by `C·L = 1e-7`) and at `C ≈ 1e-19`
20
+ * returns 0 for an 80 m curve (#5930 review). Below `|C·L| = 1e-5` — where the
21
+ * closed form is still good to ~1e-11 — the nearly constant integrand
22
+ * `sqrt(1 + (B + 2Cx)²)` is integrated by Simpson's rule instead, exact to
23
+ * rounding for so gentle a curve.
24
+ */
25
+ export declare function polynomialLength(B: number, C: number, L: number): number;
26
+ /**
27
+ * The `IfcGradientCurve` over `compositeCurveId`, one curve segment per layout
28
+ * segment, the last `DISCONTINUOUS` (`IfcCompositeCurve.CurveContinuous`).
29
+ */
30
+ export declare function emitGradientCurve(ctx: VerticalContext, params: AlignmentVerticalParams, compositeCurveId: number): number;
31
+ /**
32
+ * The semantic layout: `IfcAlignmentVertical` and its segments, nested in
33
+ * order. The caller nests the layout itself under the alignment, beside the
34
+ * horizontal one.
35
+ */
36
+ export declare function emitVerticalLayout(ctx: VerticalContext, params: AlignmentVerticalParams, guid: (role: string) => string): {
37
+ verticalId: number;
38
+ segmentIds: number[];
39
+ };
40
+ //# sourceMappingURL=ifc-creator-alignment-vertical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc-creator-alignment-vertical.d.ts","sourceRoot":"","sources":["../src/ifc-creator-alignment-vertical.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEvF,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,yFAAyF;AACzF,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CACtC;AAyBD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAuBxE;AA4FD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAMzH;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GACpF;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAgB9C"}
@@ -0,0 +1,182 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * `IfcAlignmentVertical` emitter (mapping spec §12) — the vertical half of an
6
+ * `IfcAlignment`, called from `emitAlignment`.
7
+ *
8
+ * Writes both halves IFC 4.3 defines: the semantic layout (`IfcAlignmentVertical`
9
+ * nesting `IfcAlignmentSegment`s) and the geometry (`IfcGradientCurve` over the
10
+ * horizontal `IfcCompositeCurve`). Each `IfcCurveSegment` follows IfcOpenShell
11
+ * 0.8.5's `_map_alignment_vertical_segment` exactly, computed from the design
12
+ * parameters alone, so the geometry is the one a consumer derives from the
13
+ * semantics.
14
+ */
15
+ import { esc, num } from './ifc-creator-math.js';
16
+ import { ALIGNMENT_POSITION_TOLERANCE_M } from './landxml/alignment-mapping.js';
17
+ import { evaluateVertical } from './landxml/profile-geometry.js';
18
+ const allclose = (a, b) => Math.abs(a - b) <= 1e-8 + 1e-5 * Math.abs(b);
19
+ /** Curvature of the distance/height curve: `y'' / (1 + y'²)^1.5` for a parabola. */
20
+ function curvature(segment, x) {
21
+ if (segment.type === 'CONSTANTGRADIENT' || segment.horizontalLength === 0)
22
+ return 0;
23
+ if (segment.type === 'CIRCULARARC')
24
+ return 1 / (segment.radiusOfCurvature ?? Infinity);
25
+ const g = evaluateVertical(segment, x).gradient;
26
+ const second = (segment.endGradient - segment.startGradient) / segment.horizontalLength;
27
+ return second / (1 + g * g) ** 1.5;
28
+ }
29
+ function transitionCode(segment, next) {
30
+ const end = evaluateVertical(segment, segment.horizontalLength);
31
+ const samePosition = Math.abs(segment.startDistAlong + segment.horizontalLength - next.startDistAlong) <= ALIGNMENT_POSITION_TOLERANCE_M
32
+ && Math.abs(end.height - next.startHeight) <= ALIGNMENT_POSITION_TOLERANCE_M;
33
+ if (!samePosition)
34
+ return '.DISCONTINUOUS.';
35
+ const a = Math.atan(end.gradient);
36
+ const b = Math.atan(next.startGradient);
37
+ if (!(allclose(Math.cos(a), Math.cos(b)) && allclose(Math.sin(a), Math.sin(b))))
38
+ return '.CONTINUOUS.';
39
+ return allclose(curvature(segment, segment.horizontalLength), curvature(next, 0))
40
+ ? '.CONTSAMEGRADIENTSAMECURVATURE.' : '.CONTSAMEGRADIENT.';
41
+ }
42
+ /**
43
+ * Arc length of `A + Bx + Cx²` over `[0, L]`.
44
+ *
45
+ * IfcOpenShell's `_polynomial_length` closed form, where it is well
46
+ * conditioned. Its terms grow like `1/C` and cancel, so as `C·L` shrinks the
47
+ * result loses digits (1e-9 relative by `C·L = 1e-7`) and at `C ≈ 1e-19`
48
+ * returns 0 for an 80 m curve (#5930 review). Below `|C·L| = 1e-5` — where the
49
+ * closed form is still good to ~1e-11 — the nearly constant integrand
50
+ * `sqrt(1 + (B + 2Cx)²)` is integrated by Simpson's rule instead, exact to
51
+ * rounding for so gentle a curve.
52
+ */
53
+ export function polynomialLength(B, C, L) {
54
+ if (Math.abs(C * L) < 1e-5) {
55
+ const steps = 64;
56
+ const h = L / steps;
57
+ let sum = 0;
58
+ for (let i = 0; i <= steps; i += 1) {
59
+ const weight = i === 0 || i === steps ? 1 : i % 2 === 1 ? 4 : 2;
60
+ const slope = B + 2 * C * i * h;
61
+ sum += weight * Math.sqrt(1 + slope * slope);
62
+ }
63
+ return (sum * h) / 3;
64
+ }
65
+ const a = 4 * C * C;
66
+ const b = 4 * B * C;
67
+ const c = B * B + 1;
68
+ const fn = (x) => {
69
+ const v1 = (b + 2 * a * x) / (4 * a);
70
+ const v2 = Math.sqrt(a * x * x + b * x + c);
71
+ const v3 = (4 * a * c - b * b) / (8 * a ** 1.5);
72
+ const v4 = Math.log(Math.abs(2 * a * x + b + 2 * Math.sqrt(a * (a * x * x + b * x + c))));
73
+ return v1 * v2 + v3 * v4;
74
+ };
75
+ return fn(L) - fn(0);
76
+ }
77
+ function point2d(ctx, x, y) {
78
+ return ctx.emit('IFCCARTESIANPOINT', `(${num(x)},${num(y)})`);
79
+ }
80
+ function direction2d(ctx, x, y) {
81
+ return ctx.emit('IFCDIRECTION', `(${num(x)},${num(y)})`);
82
+ }
83
+ /** `IfcCurveSegment` for one vertical segment — IfcOpenShell's mapping, term for term. */
84
+ function curveSegment(ctx, segment, transition) {
85
+ const { startDistAlong: d, horizontalLength: L, startHeight: h, startGradient: g0, endGradient: g1 } = segment;
86
+ const placement = ctx.emit('IFCAXIS2PLACEMENT2D', `#${point2d(ctx, d, h)},#${direction2d(ctx, Math.cos(Math.atan(g0)), Math.sin(Math.atan(g0)))}`);
87
+ let parent;
88
+ let segmentStart = 0;
89
+ let segmentLength;
90
+ if (segment.type === 'CONSTANTGRADIENT') {
91
+ const vector = ctx.emit('IFCVECTOR', `#${direction2d(ctx, 1, 0)},1.`);
92
+ parent = ctx.emit('IFCLINE', `#${point2d(ctx, 0, 0)},#${vector}`);
93
+ segmentLength = L / Math.cos(Math.atan(g0));
94
+ }
95
+ else if (segment.type === 'PARABOLICARC') {
96
+ const C = (g1 - g0) / (2 * L);
97
+ const position = ctx.emit('IFCAXIS2PLACEMENT2D', `#${point2d(ctx, 0, 0)},#${direction2d(ctx, 1, 0)}`);
98
+ parent = ctx.emit('IFCPOLYNOMIALCURVE', `#${position},(0.,1.),(${num(h)},${num(g0)},${num(C)}),$`);
99
+ segmentLength = polynomialLength(g0, C, L);
100
+ }
101
+ else {
102
+ let startAngle = Math.atan(g0);
103
+ let endAngle = Math.atan(g1);
104
+ let radius;
105
+ let x;
106
+ let y;
107
+ if (startAngle < endAngle) {
108
+ radius = L / (Math.sin(endAngle) - Math.sin(startAngle));
109
+ x = -radius * Math.sin(startAngle);
110
+ y = radius * Math.cos(startAngle);
111
+ startAngle += (3 * Math.PI) / 2;
112
+ endAngle += (3 * Math.PI) / 2;
113
+ }
114
+ else {
115
+ radius = L / (Math.sin(startAngle) - Math.sin(endAngle));
116
+ x = radius * Math.sin(startAngle);
117
+ y = -radius * Math.cos(startAngle);
118
+ startAngle += Math.PI / 2;
119
+ endAngle += Math.PI / 2;
120
+ }
121
+ const position = ctx.emit('IFCAXIS2PLACEMENT2D', `#${point2d(ctx, x, y)},#${direction2d(ctx, 1, 0)}`);
122
+ parent = ctx.emit('IFCCIRCLE', `#${position},${num(radius)}`);
123
+ segmentStart = radius * startAngle;
124
+ segmentLength = radius * (endAngle - startAngle);
125
+ }
126
+ return ctx.emit('IFCCURVESEGMENT', `${transition},#${placement},IFCLENGTHMEASURE(${num(segmentStart)}),IFCLENGTHMEASURE(${num(segmentLength)}),#${parent}`);
127
+ }
128
+ /** The zero-length `CONSTANTGRADIENT` IFC 4.3 requires at the end of every layout. */
129
+ function terminator(last) {
130
+ const end = evaluateVertical(last, last.horizontalLength);
131
+ return {
132
+ sourceId: `${last.sourceId}:end`, type: 'CONSTANTGRADIENT',
133
+ startDistAlong: last.startDistAlong + last.horizontalLength, horizontalLength: 0,
134
+ startHeight: end.height, startGradient: end.gradient, endGradient: end.gradient, radiusOfCurvature: null,
135
+ };
136
+ }
137
+ function layoutOf(params) {
138
+ if (params.Segments.length === 0) {
139
+ throw new Error('addAlignment: Vertical.Segments is empty — a vertical layout needs at least one segment');
140
+ }
141
+ // As `emitAlignment` does for the horizontal: a gap would be a mid-curve
142
+ // `.DISCONTINUOUS.`, which `IfcCompositeCurve.CurveContinuous` forbids for an
143
+ // open curve (exactly one, the last).
144
+ params.Segments.slice(1).forEach((next, index) => {
145
+ const previous = params.Segments[index];
146
+ const end = evaluateVertical(previous, previous.horizontalLength);
147
+ const distGap = Math.abs(previous.startDistAlong + previous.horizontalLength - next.startDistAlong);
148
+ const heightGap = Math.abs(end.height - next.startHeight);
149
+ if (distGap > ALIGNMENT_POSITION_TOLERANCE_M || heightGap > ALIGNMENT_POSITION_TOLERANCE_M) {
150
+ throw new Error(`addAlignment: vertical segment ${index + 2} starts ${distGap.toFixed(3)} m along and `
151
+ + `${heightGap.toFixed(3)} m in height from where segment ${index + 1} ends; `
152
+ + 'an open IfcGradientCurve may be discontinuous only at its last segment');
153
+ }
154
+ });
155
+ return [...params.Segments, terminator(params.Segments[params.Segments.length - 1])];
156
+ }
157
+ /**
158
+ * The `IfcGradientCurve` over `compositeCurveId`, one curve segment per layout
159
+ * segment, the last `DISCONTINUOUS` (`IfcCompositeCurve.CurveContinuous`).
160
+ */
161
+ export function emitGradientCurve(ctx, params, compositeCurveId) {
162
+ const layout = layoutOf(params);
163
+ const segments = layout.map((segment, index) => curveSegment(ctx, segment, index === layout.length - 1 ? '.DISCONTINUOUS.' : transitionCode(segment, layout[index + 1])));
164
+ return ctx.emit('IFCGRADIENTCURVE', `(${segments.map((id) => `#${id}`).join(',')}),.F.,#${compositeCurveId},$`);
165
+ }
166
+ /**
167
+ * The semantic layout: `IfcAlignmentVertical` and its segments, nested in
168
+ * order. The caller nests the layout itself under the alignment, beside the
169
+ * horizontal one.
170
+ */
171
+ export function emitVerticalLayout(ctx, params, guid) {
172
+ const verticalId = ctx.emit('IFCALIGNMENTVERTICAL', `'${params.GlobalId ?? guid('vertical')}',${ctx.ownerRef},${params.Name !== undefined ? `'${esc(params.Name)}'` : '$'},$,$,$,$`);
173
+ const segmentIds = layoutOf(params).map((segment, index) => {
174
+ const design = ctx.emit('IFCALIGNMENTVERTICALSEGMENT', `$,$,${num(segment.startDistAlong)},${num(segment.horizontalLength)},${num(segment.startHeight)},`
175
+ + `${num(segment.startGradient)},${num(segment.endGradient)},`
176
+ + `${segment.radiusOfCurvature === null ? '$' : num(segment.radiusOfCurvature)},.${segment.type}.`);
177
+ return ctx.emit('IFCALIGNMENTSEGMENT', `'${guid(`vertical:segment:${index}`)}',${ctx.ownerRef},$,$,$,$,$,#${design}`);
178
+ });
179
+ ctx.emit('IFCRELNESTS', `'${guid('nests:vertical-segments')}',${ctx.ownerRef},$,$,#${verticalId},(${segmentIds.map((id) => `#${id}`).join(',')})`);
180
+ return { verticalId, segmentIds };
181
+ }
182
+ //# sourceMappingURL=ifc-creator-alignment-vertical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc-creator-alignment-vertical.js","sourceRoot":"","sources":["../src/ifc-creator-alignment-vertical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { type HorizontalSegment } from './landxml/alignment-mapping.js';
2
+ import { type AlignmentVerticalParams } from './ifc-creator-alignment-vertical.js';
3
+ import { type StationEquationParams } from './ifc-creator-alignment-referents.js';
4
+ /** The creator hooks this emitter needs. */
5
+ export interface AlignmentContext {
6
+ emit: (type: string, attrs: string) => number;
7
+ newGlobalId: () => string;
8
+ ownerRef: string;
9
+ /** `#<id>` of the `'Axis'` representation subcontext. */
10
+ axisContextRef: string;
11
+ /** `#<id>` of the world placement the alignment hangs from. */
12
+ placementRef: string;
13
+ }
14
+ export interface AlignmentParams {
15
+ Name: string;
16
+ GlobalId?: string;
17
+ /** Station at distance 0, metres — written to the start referent's `Pset_Stationing`. */
18
+ StartStation: number;
19
+ Segments: readonly HorizontalSegment[];
20
+ /**
21
+ * The vertical layout (mapping spec §12). When present the alignment also
22
+ * gets an `IfcAlignmentVertical` and an `IfcGradientCurve` 'Axis'
23
+ * representation, and the composite curve moves to 'FootPrint'.
24
+ */
25
+ Vertical?: AlignmentVerticalParams;
26
+ /** Station equations (§14), in order along the alignment; each becomes an `IfcReferent`. */
27
+ StationEquations?: readonly StationEquationParams[];
28
+ /** Deterministic GlobalId seed for this alignment's owned entities. */
29
+ guidFor?: (role: string) => string;
30
+ }
31
+ export interface AlignmentResult {
32
+ alignmentId: number;
33
+ horizontalId: number;
34
+ compositeCurveId: number;
35
+ /** `IfcAlignmentSegment` ids in order, including the terminating one. */
36
+ segmentIds: number[];
37
+ referentId: number;
38
+ /** Present when `Vertical` was given. */
39
+ verticalId?: number;
40
+ gradientCurveId?: number;
41
+ /** One `IfcReferent` per station equation, in order along the alignment. */
42
+ equationReferentIds: number[];
43
+ }
44
+ export declare function emitAlignment(params: AlignmentParams, ctx: AlignmentContext): AlignmentResult;
45
+ //# sourceMappingURL=ifc-creator-alignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc-creator-alignment.d.ts","sourceRoot":"","sources":["../src/ifc-creator-alignment.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAkC,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAyC,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAC1H,OAAO,EAAkB,KAAK,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAElG,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,WAAW,EAAE,MAAM,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yFAAyF;IACzF,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACpD,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AAoHD,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,gBAAgB,GAAG,eAAe,CA8D7F"}
@@ -0,0 +1,173 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * `IfcAlignment` emitter — horizontal layout (mapping spec §11), plus the
6
+ * vertical layout from `ifc-creator-alignment-vertical.ts` when given (§12).
7
+ *
8
+ * Writes BOTH halves IFC 4.3 defines for an alignment: the semantic layout
9
+ * (`IfcAlignmentHorizontal` nesting `IfcAlignmentSegment`s) and the geometry
10
+ * (`IfcCompositeCurve` of `IfcCurveSegment`s). The structure mirrors what
11
+ * IfcOpenShell 0.8.5's `alignment` API writes for the same input, and each
12
+ * `IfcCurveSegment` follows its `_map_alignment_horizontal_segment` exactly —
13
+ * so the geometry is the one a consumer would derive from the semantics.
14
+ *
15
+ * Parameters arrive already mapped (`landxml/alignment-mapping.ts`): metres,
16
+ * radians counter-clockwise from +X, radii positive for a counter-clockwise
17
+ * turn and `0` for infinite.
18
+ */
19
+ import { esc, num } from './ifc-creator-math.js';
20
+ import { ALIGNMENT_POSITION_TOLERANCE_M } from './landxml/alignment-mapping.js';
21
+ import { emitGradientCurve, emitVerticalLayout } from './ifc-creator-alignment-vertical.js';
22
+ import { emitStationing } from './ifc-creator-alignment-referents.js';
23
+ /**
24
+ * Direction and curvature equality for the transition code use the
25
+ * `numpy.allclose` defaults, as IfcOpenShell's
26
+ * `get_curve_segment_transition_code` does. Position does NOT use its 1 mm:
27
+ * authored LandXML joins reproduce only to a few millimetres (lengths and
28
+ * radii are rounded independently of the coordinates), so 1 mm would mark
29
+ * an ordinary join `.DISCONTINUOUS.` in mid-curve, which
30
+ * `IfcCompositeCurve.CurveContinuous` forbids for an open curve (exactly one,
31
+ * the last). Joins are compared at the mapping's own tolerance instead, and
32
+ * a real gap beyond it is refused before anything is written (#5370 review).
33
+ */
34
+ const POSITION_ATOL = ALIGNMENT_POSITION_TOLERANCE_M;
35
+ const allclose = (a, b) => Math.abs(a - b) <= 1e-8 + 1e-5 * Math.abs(b);
36
+ function transitionCode(segment, next) {
37
+ const samePosition = Math.hypot(segment.end[0] - next.start[0], segment.end[1] - next.start[1]) <= POSITION_ATOL;
38
+ if (!samePosition)
39
+ return '.DISCONTINUOUS.';
40
+ const sameGradient = allclose(Math.cos(segment.endDirection), Math.cos(next.direction))
41
+ && allclose(Math.sin(segment.endDirection), Math.sin(next.direction));
42
+ if (!sameGradient)
43
+ return '.CONTINUOUS.';
44
+ return allclose(segment.endCurvature, next.startCurvature) ? '.CONTSAMEGRADIENTSAMECURVATURE.' : '.CONTSAMEGRADIENT.';
45
+ }
46
+ function point2d(ctx, [x, y]) {
47
+ return ctx.emit('IFCCARTESIANPOINT', `(${num(x)},${num(y)})`);
48
+ }
49
+ function placement2d(ctx, at, direction) {
50
+ const location = point2d(ctx, at);
51
+ const ref = ctx.emit('IFCDIRECTION', `(${num(Math.cos(direction))},${num(Math.sin(direction))})`);
52
+ return ctx.emit('IFCAXIS2PLACEMENT2D', `#${location},#${ref}`);
53
+ }
54
+ /** A parent-curve `Position` at the origin along +X, as IfcOpenShell writes it. */
55
+ function originPlacement(ctx) {
56
+ return placement2d(ctx, [0, 0], 0);
57
+ }
58
+ function unitLine(ctx) {
59
+ const origin = point2d(ctx, [0, 0]);
60
+ const dir = ctx.emit('IFCDIRECTION', '(1.,0.)');
61
+ const vector = ctx.emit('IFCVECTOR', `#${dir},1.`);
62
+ return ctx.emit('IFCLINE', `#${origin},#${vector}`);
63
+ }
64
+ /**
65
+ * `IfcCurveSegment` for one horizontal segment — IfcOpenShell's mapping.
66
+ *
67
+ * - LINE: `IfcLine` at the origin; `SegmentLength = L`.
68
+ * - CIRCULARARC: `IfcCircle` of radius `|R|`; `SegmentLength = L · sign(R)` —
69
+ * a negative length traverses the circle clockwise.
70
+ * - CLOTHOID: `IfcClothoid` with `A = L / sqrt(|f|) · sign(f)`, where
71
+ * `f = L/R_end − L/R_start`, and a `SegmentStart` offset so a spiral that
72
+ * does not begin at infinite radius starts at the right point on the curve.
73
+ */
74
+ function curveSegment(ctx, segment, transition) {
75
+ const placement = placement2d(ctx, segment.start, segment.direction);
76
+ const L = segment.length;
77
+ let parent;
78
+ let segmentStart = 0;
79
+ let segmentLength = L;
80
+ if (segment.type === 'LINE') {
81
+ parent = unitLine(ctx);
82
+ }
83
+ else if (segment.type === 'CIRCULARARC') {
84
+ parent = ctx.emit('IFCCIRCLE', `#${originPlacement(ctx)},${num(Math.abs(segment.startRadius))}`);
85
+ segmentLength = L * Math.sign(segment.startRadius);
86
+ }
87
+ else {
88
+ const r0 = segment.startRadius;
89
+ const r1 = segment.endRadius;
90
+ const f = (r1 === 0 ? 0 : L / r1) - (r0 === 0 ? 0 : L / r0);
91
+ const A = (L / Math.sqrt(Math.abs(f))) * Math.sign(f);
92
+ parent = ctx.emit('IFCCLOTHOID', `#${originPlacement(ctx)},${num(A)}`);
93
+ if ((Math.abs(r0) < Math.abs(r1) && r0 !== 0) || r1 === 0) {
94
+ segmentStart = -L - (r1 !== 0 ? (L * r0) / (r1 - r0) : 0);
95
+ }
96
+ else {
97
+ segmentStart = r0 !== 0 ? (L * r1) / (r0 - r1) : 0;
98
+ }
99
+ }
100
+ return ctx.emit('IFCCURVESEGMENT', `${transition},#${placement},IFCLENGTHMEASURE(${num(segmentStart)}),IFCLENGTHMEASURE(${num(segmentLength)}),#${parent}`);
101
+ }
102
+ function designParameters(ctx, segment) {
103
+ return ctx.emit('IFCALIGNMENTHORIZONTALSEGMENT', `$,$,#${point2d(ctx, segment.start)},${num(segment.direction)},${num(segment.startRadius)},`
104
+ + `${num(segment.endRadius)},${num(segment.length)},$,.${segment.type}.`);
105
+ }
106
+ /**
107
+ * The zero-length `LINE` IFC 4.3 requires at the end of every layout, placed at
108
+ * the alignment's end along its end tangent.
109
+ */
110
+ function terminator(last) {
111
+ return {
112
+ sourceId: `${last.sourceId}:end`,
113
+ type: 'LINE',
114
+ start: last.end,
115
+ direction: last.endDirection,
116
+ startRadius: 0,
117
+ endRadius: 0,
118
+ length: 0,
119
+ end: last.end,
120
+ endDirection: last.endDirection,
121
+ startCurvature: 0,
122
+ endCurvature: 0,
123
+ };
124
+ }
125
+ export function emitAlignment(params, ctx) {
126
+ if (params.Segments.length === 0) {
127
+ throw new Error('addAlignment: Segments is empty — an alignment needs at least one horizontal segment');
128
+ }
129
+ const guid = (role) => params.guidFor?.(role) ?? ctx.newGlobalId();
130
+ const layout = [...params.Segments, terminator(params.Segments[params.Segments.length - 1])];
131
+ params.Segments.slice(1).forEach((next, index) => {
132
+ const previous = params.Segments[index];
133
+ const gap = Math.hypot(previous.end[0] - next.start[0], previous.end[1] - next.start[1]);
134
+ if (gap > POSITION_ATOL) {
135
+ throw new Error(`addAlignment: segment ${index + 2} starts ${gap.toFixed(3)} m from where segment ${index + 1} ends; `
136
+ + 'an open IfcCompositeCurve may be discontinuous only at its last segment');
137
+ }
138
+ });
139
+ // Geometry: one curve segment per layout segment, the last DISCONTINUOUS —
140
+ // `IfcCompositeCurve.CurveContinuous` requires exactly one for an open curve.
141
+ const curveSegments = layout.map((segment, index) => curveSegment(ctx, segment, index === layout.length - 1 ? '.DISCONTINUOUS.' : transitionCode(segment, layout[index + 1])));
142
+ const compositeCurveId = ctx.emit('IFCCOMPOSITECURVE', `(${curveSegments.map((id) => `#${id}`).join(',')}),.F.`);
143
+ // With a vertical layout: the composite curve as 'FootPrint' first, the
144
+ // gradient curve as 'Axis' — IfcOpenShell's horizontal + vertical case (§12.1).
145
+ const gradientCurveId = params.Vertical ? emitGradientCurve(ctx, params.Vertical, compositeCurveId) : undefined;
146
+ const representations = gradientCurveId === undefined
147
+ ? [ctx.emit('IFCSHAPEREPRESENTATION', `${ctx.axisContextRef},'Axis','Curve2D',(#${compositeCurveId})`)]
148
+ : [
149
+ ctx.emit('IFCSHAPEREPRESENTATION', `${ctx.axisContextRef},'FootPrint','Curve2D',(#${compositeCurveId})`),
150
+ ctx.emit('IFCSHAPEREPRESENTATION', `${ctx.axisContextRef},'Axis','Curve3D',(#${gradientCurveId})`),
151
+ ];
152
+ const shape = ctx.emit('IFCPRODUCTDEFINITIONSHAPE', `$,$,(${representations.map((id) => `#${id}`).join(',')})`);
153
+ const alignmentId = ctx.emit('IFCALIGNMENT', `'${params.GlobalId ?? guid('alignment')}',${ctx.ownerRef},'${esc(params.Name)}',$,$,${ctx.placementRef},#${shape},$`);
154
+ // Semantics: horizontal layout nested under the alignment, segments nested
155
+ // in order under the layout.
156
+ const horizontalId = ctx.emit('IFCALIGNMENTHORIZONTAL', `'${guid('horizontal')}',${ctx.ownerRef},$,$,$,$,$`);
157
+ const vertical = params.Vertical ? emitVerticalLayout(ctx, params.Vertical, guid) : undefined;
158
+ const layouts = vertical ? `#${horizontalId},#${vertical.verticalId}` : `#${horizontalId}`;
159
+ ctx.emit('IFCRELNESTS', `'${guid('nests:layouts')}',${ctx.ownerRef},$,$,#${alignmentId},(${layouts})`);
160
+ const segmentIds = layout.map((segment, index) => ctx.emit('IFCALIGNMENTSEGMENT', `'${guid(`segment:${index}`)}',${ctx.ownerRef},$,$,$,$,$,#${designParameters(ctx, segment)}`));
161
+ ctx.emit('IFCRELNESTS', `'${guid('nests:segments')}',${ctx.ownerRef},$,$,#${horizontalId},(${segmentIds.map((id) => `#${id}`).join(',')})`);
162
+ // Stationing (§11.1, §14): the start referent, then one per station
163
+ // equation, nested in order along the alignment.
164
+ const [referentId, ...equationReferentIds] = emitStationing({
165
+ alignmentId, compositeCurveId, segments: params.Segments, startStation: params.StartStation,
166
+ equations: params.StationEquations ?? [],
167
+ }, { emit: ctx.emit, ownerRef: ctx.ownerRef, guid });
168
+ return {
169
+ alignmentId, horizontalId, compositeCurveId, segmentIds, referentId, equationReferentIds,
170
+ ...(vertical ? { verticalId: vertical.verticalId, gradientCurveId } : {}),
171
+ };
172
+ }
173
+ //# sourceMappingURL=ifc-creator-alignment.js.map