@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.
- package/README.md +7 -0
- package/dist/ifc-creator-alignment-referents.d.ts +35 -0
- package/dist/ifc-creator-alignment-referents.d.ts.map +1 -0
- package/dist/ifc-creator-alignment-referents.js +89 -0
- package/dist/ifc-creator-alignment-referents.js.map +1 -0
- package/dist/ifc-creator-alignment-vertical.d.ts +40 -0
- package/dist/ifc-creator-alignment-vertical.d.ts.map +1 -0
- package/dist/ifc-creator-alignment-vertical.js +182 -0
- package/dist/ifc-creator-alignment-vertical.js.map +1 -0
- package/dist/ifc-creator-alignment.d.ts +45 -0
- package/dist/ifc-creator-alignment.d.ts.map +1 -0
- package/dist/ifc-creator-alignment.js +173 -0
- package/dist/ifc-creator-alignment.js.map +1 -0
- package/dist/ifc-creator-header.d.ts +2 -0
- package/dist/ifc-creator-header.d.ts.map +1 -0
- package/dist/ifc-creator-header.js +22 -0
- package/dist/ifc-creator-header.js.map +1 -0
- package/dist/ifc-creator-math.d.ts +37 -5
- package/dist/ifc-creator-math.d.ts.map +1 -1
- package/dist/ifc-creator-math.js +93 -4
- package/dist/ifc-creator-math.js.map +1 -1
- package/dist/ifc-creator-relationships.d.ts +43 -0
- package/dist/ifc-creator-relationships.d.ts.map +1 -0
- package/dist/ifc-creator-relationships.js +38 -0
- package/dist/ifc-creator-relationships.js.map +1 -0
- package/dist/ifc-creator-styles.d.ts +22 -0
- package/dist/ifc-creator-styles.d.ts.map +1 -0
- package/dist/ifc-creator-styles.js +50 -0
- package/dist/ifc-creator-styles.js.map +1 -0
- package/dist/ifc-creator-terrain.d.ts +170 -0
- package/dist/ifc-creator-terrain.d.ts.map +1 -0
- package/dist/ifc-creator-terrain.js +180 -0
- package/dist/ifc-creator-terrain.js.map +1 -0
- package/dist/ifc-creator.d.ts +21 -7
- package/dist/ifc-creator.d.ts.map +1 -1
- package/dist/ifc-creator.js +93 -97
- package/dist/ifc-creator.js.map +1 -1
- package/dist/in-store/_emit-helpers.d.ts +2 -1
- package/dist/in-store/_emit-helpers.d.ts.map +1 -1
- package/dist/in-store/_emit-helpers.js +7 -7
- package/dist/in-store/_emit-helpers.js.map +1 -1
- package/dist/in-store/anchor.d.ts +2 -0
- package/dist/in-store/anchor.d.ts.map +1 -1
- package/dist/in-store/anchor.js.map +1 -1
- package/dist/in-store/apply-style.d.ts +3 -6
- package/dist/in-store/apply-style.d.ts.map +1 -1
- package/dist/in-store/apply-style.js +3 -77
- package/dist/in-store/apply-style.js.map +1 -1
- package/dist/in-store/column.d.ts.map +1 -1
- package/dist/in-store/column.js +2 -0
- package/dist/in-store/column.js.map +1 -1
- package/dist/in-store/door.d.ts.map +1 -1
- package/dist/in-store/door.js +2 -0
- package/dist/in-store/door.js.map +1 -1
- package/dist/in-store/extract-walls.d.ts +1 -1
- package/dist/in-store/extract-walls.d.ts.map +1 -1
- package/dist/in-store/extract-walls.js +37 -55
- package/dist/in-store/extract-walls.js.map +1 -1
- package/dist/in-store/generate-spaces-all.d.ts +6 -2
- package/dist/in-store/generate-spaces-all.d.ts.map +1 -1
- package/dist/in-store/generate-spaces-all.js +33 -9
- package/dist/in-store/generate-spaces-all.js.map +1 -1
- package/dist/in-store/generate-spaces.js +1 -1
- package/dist/in-store/generate-spaces.js.map +1 -1
- package/dist/in-store/placement-frame.d.ts +8 -0
- package/dist/in-store/placement-frame.d.ts.map +1 -1
- package/dist/in-store/placement-frame.js.map +1 -1
- package/dist/in-store/plate.d.ts.map +1 -1
- package/dist/in-store/plate.js +4 -0
- package/dist/in-store/plate.js.map +1 -1
- package/dist/in-store/resolve-anchor.d.ts +4 -2
- package/dist/in-store/resolve-anchor.d.ts.map +1 -1
- package/dist/in-store/resolve-anchor.js +79 -92
- package/dist/in-store/resolve-anchor.js.map +1 -1
- package/dist/in-store/resolve-source.d.ts +2 -1
- package/dist/in-store/resolve-source.d.ts.map +1 -1
- package/dist/in-store/resolve-source.js +49 -49
- package/dist/in-store/resolve-source.js.map +1 -1
- package/dist/in-store/roof.d.ts.map +1 -1
- package/dist/in-store/roof.js +4 -0
- package/dist/in-store/roof.js.map +1 -1
- package/dist/in-store/slab.d.ts.map +1 -1
- package/dist/in-store/slab.js +4 -0
- package/dist/in-store/slab.js.map +1 -1
- package/dist/in-store/space.d.ts.map +1 -1
- package/dist/in-store/space.js +4 -0
- package/dist/in-store/space.js.map +1 -1
- package/dist/in-store/spatial-children.d.ts +52 -0
- package/dist/in-store/spatial-children.d.ts.map +1 -0
- package/dist/in-store/spatial-children.js +112 -0
- package/dist/in-store/spatial-children.js.map +1 -0
- package/dist/in-store/spatial-zone.d.ts.map +1 -1
- package/dist/in-store/spatial-zone.js +5 -5
- package/dist/in-store/spatial-zone.js.map +1 -1
- package/dist/in-store/style-entity-reader.d.ts +14 -0
- package/dist/in-store/style-entity-reader.d.ts.map +1 -0
- package/dist/in-store/style-entity-reader.js +58 -0
- package/dist/in-store/style-entity-reader.js.map +1 -0
- package/dist/in-store/wall.d.ts.map +1 -1
- package/dist/in-store/wall.js +4 -14
- package/dist/in-store/wall.js.map +1 -1
- package/dist/in-store/window.d.ts.map +1 -1
- package/dist/in-store/window.js +2 -0
- package/dist/in-store/window.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/landxml/alignment-mapping.d.ts +98 -0
- package/dist/landxml/alignment-mapping.d.ts.map +1 -0
- package/dist/landxml/alignment-mapping.js +282 -0
- package/dist/landxml/alignment-mapping.js.map +1 -0
- package/dist/landxml/alignment-record.d.ts +18 -0
- package/dist/landxml/alignment-record.d.ts.map +1 -0
- package/dist/landxml/alignment-record.js +63 -0
- package/dist/landxml/alignment-record.js.map +1 -0
- package/dist/landxml/coordinate-plausibility.d.ts +54 -0
- package/dist/landxml/coordinate-plausibility.d.ts.map +1 -0
- package/dist/landxml/coordinate-plausibility.js +59 -0
- package/dist/landxml/coordinate-plausibility.js.map +1 -0
- package/dist/landxml/landxml-to-ifc.d.ts +45 -0
- package/dist/landxml/landxml-to-ifc.d.ts.map +1 -0
- package/dist/landxml/landxml-to-ifc.js +203 -0
- package/dist/landxml/landxml-to-ifc.js.map +1 -0
- package/dist/landxml/profile-geometry.d.ts +50 -0
- package/dist/landxml/profile-geometry.d.ts.map +1 -0
- package/dist/landxml/profile-geometry.js +221 -0
- package/dist/landxml/profile-geometry.js.map +1 -0
- package/dist/landxml/profile-mapping.d.ts +36 -0
- package/dist/landxml/profile-mapping.d.ts.map +1 -0
- package/dist/landxml/profile-mapping.js +181 -0
- package/dist/landxml/profile-mapping.js.map +1 -0
- package/dist/landxml/profile-record.d.ts +46 -0
- package/dist/landxml/profile-record.d.ts.map +1 -0
- package/dist/landxml/profile-record.js +38 -0
- package/dist/landxml/profile-record.js.map +1 -0
- package/dist/landxml/refusals.d.ts +45 -0
- package/dist/landxml/refusals.d.ts.map +1 -0
- package/dist/landxml/refusals.js +141 -0
- package/dist/landxml/refusals.js.map +1 -0
- package/dist/landxml/result-types.d.ts +78 -0
- package/dist/landxml/result-types.d.ts.map +1 -0
- package/dist/landxml/result-types.js +5 -0
- package/dist/landxml/result-types.js.map +1 -0
- package/dist/landxml/source-types.d.ts +169 -0
- package/dist/landxml/source-types.d.ts.map +1 -0
- package/dist/landxml/source-types.js +5 -0
- package/dist/landxml/source-types.js.map +1 -0
- package/dist/landxml/station-equations.d.ts +69 -0
- package/dist/landxml/station-equations.d.ts.map +1 -0
- package/dist/landxml/station-equations.js +140 -0
- package/dist/landxml/station-equations.js.map +1 -0
- package/dist/landxml/writers.d.ts +33 -0
- package/dist/landxml/writers.d.ts.map +1 -0
- package/dist/landxml/writers.js +160 -0
- package/dist/landxml/writers.js.map +1 -0
- package/dist/types.d.ts +13 -2
- package/dist/types.d.ts.map +1 -1
- 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
|