@ifc-lite/create 2.8.0 → 2.9.2
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.d.ts +30 -0
- package/dist/ifc-creator-alignment.d.ts.map +1 -0
- package/dist/ifc-creator-alignment.js +174 -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 +15 -5
- package/dist/ifc-creator-math.d.ts.map +1 -1
- package/dist/ifc-creator-math.js +25 -2
- 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 +95 -95
- package/dist/ifc-creator.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 +28 -54
- 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/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/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 +8 -0
- 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 +197 -0
- package/dist/landxml/landxml-to-ifc.js.map +1 -0
- package/dist/landxml/refusals.d.ts +41 -0
- package/dist/landxml/refusals.d.ts.map +1 -0
- package/dist/landxml/refusals.js +118 -0
- package/dist/landxml/refusals.js.map +1 -0
- package/dist/landxml/result-types.d.ts +73 -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/writers.d.ts +31 -0
- package/dist/landxml/writers.d.ts.map +1 -0
- package/dist/landxml/writers.js +143 -0
- package/dist/landxml/writers.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The northing/easting transposition check (§2.2, §9.1 of the mapping spec).
|
|
3
|
+
*
|
|
4
|
+
* LandXML `<P>`/`<CgPoint>` element text is *northing easting elevation*. A
|
|
5
|
+
* producer that writes it easting-first is a real, observed defect, and it is
|
|
6
|
+
* silent by construction: a transpose is a reflection, so the surface is still
|
|
7
|
+
* well-formed, still renders, and passes every count-based assertion. It is
|
|
8
|
+
* simply in the wrong place.
|
|
9
|
+
*
|
|
10
|
+
* This warns. It never refuses and never corrects:
|
|
11
|
+
*
|
|
12
|
+
* - A bounds test is a *plausibility* argument, not a proof. Refusing on it
|
|
13
|
+
* would block legitimate data at the edge of a zone.
|
|
14
|
+
* - Auto-correcting would silently move a correct dataset, which is the same
|
|
15
|
+
* class of failure it is meant to catch, in the opposite direction.
|
|
16
|
+
*
|
|
17
|
+
* It also never infers from magnitude alone. Without declared bounds there is
|
|
18
|
+
* no test — `checkCoordinateOrder` returns `null` and the caller says so.
|
|
19
|
+
*/
|
|
20
|
+
import type { LandXmlIfcWarning } from './result-types.js';
|
|
21
|
+
/** Inclusive metre bounds for a projected CRS's two horizontal axes. */
|
|
22
|
+
export interface CrsPlausibilityBounds {
|
|
23
|
+
easting: readonly [number, number];
|
|
24
|
+
northing: readonly [number, number];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Bounds shared by every Transverse-Mercator-family projected CRS (UTM zones,
|
|
28
|
+
* national TM grids such as SWEREF99 TM).
|
|
29
|
+
*
|
|
30
|
+
* The false easting is 500 000 m and a zone is ±500 km wide, so an easting
|
|
31
|
+
* lives in roughly 0…1 000 000 m; a northing runs the length of the hemisphere,
|
|
32
|
+
* to ~10 000 000 m. That asymmetry is the whole discriminating power of the
|
|
33
|
+
* test, and it is a property of the projection family rather than of any one
|
|
34
|
+
* EPSG code — which is why this needs no EPSG table and why §4.2's rule that
|
|
35
|
+
* the exporter must not start resolving EPSG codes is not violated.
|
|
36
|
+
*
|
|
37
|
+
* Callers opt in by passing this; nothing here sniffs a CRS name for 'UTM'.
|
|
38
|
+
*/
|
|
39
|
+
export declare const TRANSVERSE_MERCATOR_BOUNDS: CrsPlausibilityBounds;
|
|
40
|
+
/**
|
|
41
|
+
* Test the coordinates as they are about to be written, in metres.
|
|
42
|
+
*
|
|
43
|
+
* Returns a warning only when the pair is implausible as written **and**
|
|
44
|
+
* swapping the two axes would make it plausible. Both halves matter: the first
|
|
45
|
+
* alone fires on any out-of-zone data, which is a different problem and not one
|
|
46
|
+
* this check can diagnose; the second is what makes the message's claim — that
|
|
47
|
+
* the source may be written easting-first — an inference the evidence supports.
|
|
48
|
+
*
|
|
49
|
+
* @param samples `(easting, northing)` metre pairs in the order they will be
|
|
50
|
+
* written to `IfcCartesianPointList3D`, i.e. already converted from LandXML's
|
|
51
|
+
* northing-first authored order.
|
|
52
|
+
*/
|
|
53
|
+
export declare function checkCoordinateOrder(samples: Iterable<readonly [number, number]>, bounds: CrsPlausibilityBounds, crsName: string): LandXmlIfcWarning | null;
|
|
54
|
+
//# sourceMappingURL=coordinate-plausibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinate-plausibility.d.ts","sourceRoot":"","sources":["../../src/landxml/coordinate-plausibility.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,wEAAwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,0BAA0B,EAAE,qBAGxC,CAAC;AAMF;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC5C,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,MAAM,GACd,iBAAiB,GAAG,IAAI,CAoB1B"}
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
* Bounds shared by every Transverse-Mercator-family projected CRS (UTM zones,
|
|
6
|
+
* national TM grids such as SWEREF99 TM).
|
|
7
|
+
*
|
|
8
|
+
* The false easting is 500 000 m and a zone is ±500 km wide, so an easting
|
|
9
|
+
* lives in roughly 0…1 000 000 m; a northing runs the length of the hemisphere,
|
|
10
|
+
* to ~10 000 000 m. That asymmetry is the whole discriminating power of the
|
|
11
|
+
* test, and it is a property of the projection family rather than of any one
|
|
12
|
+
* EPSG code — which is why this needs no EPSG table and why §4.2's rule that
|
|
13
|
+
* the exporter must not start resolving EPSG codes is not violated.
|
|
14
|
+
*
|
|
15
|
+
* Callers opt in by passing this; nothing here sniffs a CRS name for 'UTM'.
|
|
16
|
+
*/
|
|
17
|
+
export const TRANSVERSE_MERCATOR_BOUNDS = {
|
|
18
|
+
easting: [0, 1_000_000],
|
|
19
|
+
northing: [0, 10_000_000],
|
|
20
|
+
};
|
|
21
|
+
function within(value, [low, high]) {
|
|
22
|
+
return value >= low && value <= high;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Test the coordinates as they are about to be written, in metres.
|
|
26
|
+
*
|
|
27
|
+
* Returns a warning only when the pair is implausible as written **and**
|
|
28
|
+
* swapping the two axes would make it plausible. Both halves matter: the first
|
|
29
|
+
* alone fires on any out-of-zone data, which is a different problem and not one
|
|
30
|
+
* this check can diagnose; the second is what makes the message's claim — that
|
|
31
|
+
* the source may be written easting-first — an inference the evidence supports.
|
|
32
|
+
*
|
|
33
|
+
* @param samples `(easting, northing)` metre pairs in the order they will be
|
|
34
|
+
* written to `IfcCartesianPointList3D`, i.e. already converted from LandXML's
|
|
35
|
+
* northing-first authored order.
|
|
36
|
+
*/
|
|
37
|
+
export function checkCoordinateOrder(samples, bounds, crsName) {
|
|
38
|
+
for (const [easting, northing] of samples) {
|
|
39
|
+
if (!Number.isFinite(easting) || !Number.isFinite(northing))
|
|
40
|
+
continue;
|
|
41
|
+
const plausibleAsWritten = within(easting, bounds.easting) && within(northing, bounds.northing);
|
|
42
|
+
if (plausibleAsWritten)
|
|
43
|
+
continue;
|
|
44
|
+
const plausibleSwapped = within(northing, bounds.easting) && within(easting, bounds.northing);
|
|
45
|
+
if (!plausibleSwapped)
|
|
46
|
+
continue;
|
|
47
|
+
return {
|
|
48
|
+
code: 'LXIFC-COORD-ORDER',
|
|
49
|
+
message: `Coordinate order looks transposed. Easting ${easting} is outside ${crsName}'s easting range `
|
|
50
|
+
+ `[${bounds.easting[0]}, ${bounds.easting[1]}], but would be a valid northing — and northing `
|
|
51
|
+
+ `${northing} would be a valid easting. LandXML point text is northing-first; a producer that `
|
|
52
|
+
+ 'writes it easting-first yields a mirrored surface that still renders and still passes every '
|
|
53
|
+
+ 'count check. Verify the source before relying on this export, or re-export it with the '
|
|
54
|
+
+ 'coordinate-order override if you know the producer is at fault.',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=coordinate-plausibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinate-plausibility.js","sourceRoot":"","sources":["../../src/landxml/coordinate-plausibility.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AA8B/D;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAA0B;IAC/D,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC;IACvB,QAAQ,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC;CAC1B,CAAC;AAEF,SAAS,MAAM,CAAC,KAAa,EAAE,CAAC,GAAG,EAAE,IAAI,CAA4B;IACnE,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,IAAI,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAA4C,EAC5C,MAA6B,EAC7B,OAAe;IAEf,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,OAAO,EAAE,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,SAAS;QACtE,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChG,IAAI,kBAAkB;YAAE,SAAS;QACjC,MAAM,gBAAgB,GAAG,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9F,IAAI,CAAC,gBAAgB;YAAE,SAAS;QAEhC,OAAO;YACL,IAAI,EAAE,mBAAmB;YACzB,OAAO,EACL,8CAA8C,OAAO,eAAe,OAAO,mBAAmB;kBAC5F,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,kDAAkD;kBAC7F,GAAG,QAAQ,mFAAmF;kBAC9F,8FAA8F;kBAC9F,yFAAyF;kBACzF,iEAAiE;SACtE,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type CrsPlausibilityBounds } from './coordinate-plausibility.js';
|
|
2
|
+
import type { LandXmlIfcSource } from './source-types.js';
|
|
3
|
+
import type { LandXmlIfcResult } from './result-types.js';
|
|
4
|
+
/** The mapping-document version this converter implements. */
|
|
5
|
+
export declare const LANDXML_IFC_MAPPING_VERSION = "1.1";
|
|
6
|
+
export interface LandXmlIfcOptions {
|
|
7
|
+
/** Recorded as provenance (§7); never used to decide anything. */
|
|
8
|
+
sourceFileName?: string;
|
|
9
|
+
sourceHash?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Written as `IfcProjectedCRS` + `IfcMapConversion` (§4.2). Omit where the
|
|
12
|
+
* source declares no CRS: §4.2 forbids a placeholder, because a wrong CRS is
|
|
13
|
+
* worse than none.
|
|
14
|
+
*/
|
|
15
|
+
crs?: {
|
|
16
|
+
Name: string;
|
|
17
|
+
Description?: string;
|
|
18
|
+
GeodeticDatum?: string;
|
|
19
|
+
VerticalDatum?: string;
|
|
20
|
+
MapProjection?: string;
|
|
21
|
+
MapZone?: string;
|
|
22
|
+
/** Enables the transposition check (§9.1). Without it there is no test. */
|
|
23
|
+
Bounds?: CrsPlausibilityBounds;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Operator-confirmed northing/easting swap for a known-faulty producer
|
|
27
|
+
* (§2.2 item 2). Recorded as provenance, exactly like the units override.
|
|
28
|
+
*/
|
|
29
|
+
swapNorthingEasting?: boolean;
|
|
30
|
+
/** Fixed epoch-ms, for byte-deterministic output. */
|
|
31
|
+
timestampMs?: number;
|
|
32
|
+
Author?: string;
|
|
33
|
+
Organization?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Deterministic GlobalId from a LandXML source id (§4.3, §10). */
|
|
36
|
+
export declare function landXmlGlobalId(sourceId: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Convert a parsed LandXML document to an IFC4X3 STEP file.
|
|
39
|
+
*
|
|
40
|
+
* Returns `{ status: 'refused' }` — with the refusal list intact — when the
|
|
41
|
+
* source carries nothing the mapping covers. That is not an error case to be
|
|
42
|
+
* caught; it is the honest answer for the alignment-only files §9.4 discusses.
|
|
43
|
+
*/
|
|
44
|
+
export declare function landXmlToIfc(source: LandXmlIfcSource, options?: LandXmlIfcOptions): LandXmlIfcResult;
|
|
45
|
+
//# sourceMappingURL=landxml-to-ifc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"landxml-to-ifc.d.ts","sourceRoot":"","sources":["../../src/landxml/landxml-to-ifc.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAwB,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAIhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EACgC,gBAAgB,EAC3D,MAAM,mBAAmB,CAAC;AAE3B,8DAA8D;AAC9D,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,GAAG,CAAC,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,2EAA2E;QAC3E,MAAM,CAAC,EAAE,qBAAqB,CAAC;KAChC,CAAC;IACF;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CA+HxG"}
|
|
@@ -0,0 +1,197 @@
|
|
|
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
|
+
* LandXML → IFC4X3, v1.
|
|
6
|
+
*
|
|
7
|
+
* Implements `docs/architecture/landxml-to-ifc-mapping.md` v1.0. That document
|
|
8
|
+
* is the contract; anything not written there is not in v1, and a change to the
|
|
9
|
+
* mapping is a change to that document first.
|
|
10
|
+
*
|
|
11
|
+
* Three properties this file exists to guarantee, each of which fails silently
|
|
12
|
+
* if it is got wrong:
|
|
13
|
+
*
|
|
14
|
+
* 1. **Axis order.** LandXML authors `<P>` text as *northing easting
|
|
15
|
+
* elevation*. IFC `CoordList` entries are `(X, Y, Z)` = *easting northing
|
|
16
|
+
* elevation*. The swap happens here, once, at {@link toIfcVertex}.
|
|
17
|
+
* 2. **Units.** Output is always metres, with `linearScaleToMeters` applied to
|
|
18
|
+
* the plan axes and `elevationScaleToMeters` to the elevation — LandXML may
|
|
19
|
+
* declare a different unit for each, and applying one scale to all three is
|
|
20
|
+
* a mistake that looks fine on the common metric file.
|
|
21
|
+
* 3. **Nothing is dropped in silence.** Every out-of-scope record family is
|
|
22
|
+
* counted and named, and a source with no mappable record refuses outright
|
|
23
|
+
* rather than producing a valid, empty, useless IFC.
|
|
24
|
+
*/
|
|
25
|
+
import { uuidFromSeed, uuidToIfcGuid } from '@ifc-lite/encoding';
|
|
26
|
+
import { IfcCreator } from '../ifc-creator.js';
|
|
27
|
+
import { checkCoordinateOrder } from './coordinate-plausibility.js';
|
|
28
|
+
import { collectRefusals, isMappableSurface, refusalReason } from './refusals.js';
|
|
29
|
+
import { cogoPointResolver, mapAlignments } from './alignment-mapping.js';
|
|
30
|
+
import { writeAlignments, writeSurfaces, writeSurveyPoints } from './writers.js';
|
|
31
|
+
/** The mapping-document version this converter implements. */
|
|
32
|
+
export const LANDXML_IFC_MAPPING_VERSION = '1.1';
|
|
33
|
+
/** Deterministic GlobalId from a LandXML source id (§4.3, §10). */
|
|
34
|
+
export function landXmlGlobalId(sourceId) {
|
|
35
|
+
return uuidToIfcGuid(uuidFromSeed(sourceId));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Convert a parsed LandXML document to an IFC4X3 STEP file.
|
|
39
|
+
*
|
|
40
|
+
* Returns `{ status: 'refused' }` — with the refusal list intact — when the
|
|
41
|
+
* source carries nothing the mapping covers. That is not an error case to be
|
|
42
|
+
* caught; it is the honest answer for the alignment-only files §9.4 discusses.
|
|
43
|
+
*/
|
|
44
|
+
export function landXmlToIfc(source, options = {}) {
|
|
45
|
+
const swap = options.swapNorthingEasting === true;
|
|
46
|
+
// Mapped once, and the same mapping decides both what is written and what
|
|
47
|
+
// the refusal list says was not — two passes could disagree.
|
|
48
|
+
const alignmentMapping = mapAlignments(source.alignments, source.units, swap, cogoPointResolver(source.plan?.cogoPoints));
|
|
49
|
+
const refusals = collectRefusals(source, alignmentMapping);
|
|
50
|
+
const warnings = [];
|
|
51
|
+
const mappableSurfaces = source.surfaces.filter(isMappableSurface);
|
|
52
|
+
const cogoPoints = (source.plan?.cogoPoints ?? []).filter((point) => point.point !== null);
|
|
53
|
+
const units = source.units;
|
|
54
|
+
if (units === null) {
|
|
55
|
+
// Distinct from an empty source: the file may hold a perfectly good TIN, and
|
|
56
|
+
// the operator needs to know the fix is units, not content.
|
|
57
|
+
return {
|
|
58
|
+
status: 'refused',
|
|
59
|
+
reason: 'This LandXML file declares no LandXML/Units element, so no coordinate can be scaled to '
|
|
60
|
+
+ 'metres. Load it with an explicit assumed linear unit, or export the original LandXML file instead.',
|
|
61
|
+
refusals,
|
|
62
|
+
warnings,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (mappableSurfaces.length === 0 && cogoPoints.length === 0 && alignmentMapping.mapped.length === 0) {
|
|
66
|
+
return { status: 'refused', reason: refusalReason(refusals), refusals, warnings };
|
|
67
|
+
}
|
|
68
|
+
if (units.assumed) {
|
|
69
|
+
warnings.push({
|
|
70
|
+
code: 'LXIFC-ASSUMED-UNIT',
|
|
71
|
+
message: `Every coordinate in this export is scaled by an ASSUMED linear unit ('${units.linearUnit}'). `
|
|
72
|
+
+ 'The source declares no LandXML/Units element, so the scale was chosen by an operator, not read '
|
|
73
|
+
+ 'from the file. The geometry is at that operator-chosen scale and nothing in the IFC records '
|
|
74
|
+
+ 'otherwise except this file\'s provenance property set.',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (!options.crs) {
|
|
78
|
+
warnings.push({
|
|
79
|
+
code: 'LXIFC-NO-CRS',
|
|
80
|
+
message: 'No coordinate reference system is declared, so no IfcProjectedCRS or IfcMapConversion is written '
|
|
81
|
+
+ 'and the coordinate-order plausibility check cannot run. The coordinates are written as authored.',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (options.swapNorthingEasting) {
|
|
85
|
+
warnings.push({
|
|
86
|
+
code: 'LXIFC-COORD-SWAPPED',
|
|
87
|
+
message: 'A coordinate-order override is in force: the source\'s point text is being read as '
|
|
88
|
+
+ 'easting-first rather than LandXML\'s northing-first order. This is an operator assertion about '
|
|
89
|
+
+ 'the producer, not something read from the file.',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const creator = new IfcCreator({
|
|
93
|
+
// Declared as `IFC4X3_ADD2` by `IfcCreator` itself, like all IFC4X3
|
|
94
|
+
// output (`fileSchemaIdentifier`, #5351).
|
|
95
|
+
Schema: 'IFC4X3',
|
|
96
|
+
Name: options.sourceFileName ?? 'LandXML conversion',
|
|
97
|
+
Description: `Derived from LandXML ${source.schema} by the ifc-lite LandXML→IFC mapping v${LANDXML_IFC_MAPPING_VERSION}`,
|
|
98
|
+
LengthUnit: 'METRE',
|
|
99
|
+
...(options.timestampMs === undefined ? {} : { Timestamp: options.timestampMs }),
|
|
100
|
+
...(options.Author === undefined ? {} : { Author: options.Author }),
|
|
101
|
+
...(options.Organization === undefined ? {} : { Organization: options.Organization }),
|
|
102
|
+
// Content hash first: two different files exported without a name must not
|
|
103
|
+
// share project/site/relationship GlobalIds, or federating them collides.
|
|
104
|
+
GuidSource: deterministicGuidSource(options.sourceHash ?? options.sourceFileName ?? source.schema),
|
|
105
|
+
});
|
|
106
|
+
const terrain = creator.terrain();
|
|
107
|
+
if (options.crs) {
|
|
108
|
+
terrain.setGeoreferencing({
|
|
109
|
+
Name: options.crs.Name,
|
|
110
|
+
Description: options.crs.Description,
|
|
111
|
+
GeodeticDatum: options.crs.GeodeticDatum ?? source.coordinateSystem?.horizontalDatum,
|
|
112
|
+
VerticalDatum: options.crs.VerticalDatum ?? source.coordinateSystem?.verticalDatum,
|
|
113
|
+
MapProjection: options.crs.MapProjection,
|
|
114
|
+
MapZone: options.crs.MapZone,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const surfaceResult = writeSurfaces(terrain, source.surfaces, units, swap, landXmlGlobalId);
|
|
118
|
+
const pointResult = writeSurveyPoints(terrain, cogoPoints, units, swap, landXmlGlobalId);
|
|
119
|
+
const alignmentSamples = writeAlignments(terrain, alignmentMapping.mapped, landXmlGlobalId);
|
|
120
|
+
if (options.crs?.Bounds) {
|
|
121
|
+
const warning = checkCoordinateOrder([...surfaceResult.samples, ...pointResult.samples, ...alignmentSamples], options.crs.Bounds, options.crs.Name);
|
|
122
|
+
if (warning)
|
|
123
|
+
warnings.push(warning);
|
|
124
|
+
}
|
|
125
|
+
const coverage = {
|
|
126
|
+
surfaces: surfaceResult.surfaces,
|
|
127
|
+
surveyPoints: pointResult.count,
|
|
128
|
+
vertices: surfaceResult.vertices,
|
|
129
|
+
triangles: surfaceResult.triangles,
|
|
130
|
+
alignments: alignmentMapping.mapped.length,
|
|
131
|
+
};
|
|
132
|
+
if (coverage.surfaces === 0 && coverage.surveyPoints === 0 && (coverage.alignments ?? 0) === 0) {
|
|
133
|
+
return { status: 'refused', reason: refusalReason(refusals), refusals, warnings };
|
|
134
|
+
}
|
|
135
|
+
const provenance = {
|
|
136
|
+
sourceFileName: options.sourceFileName ?? null,
|
|
137
|
+
sourceHash: options.sourceHash ?? null,
|
|
138
|
+
mappingVersion: LANDXML_IFC_MAPPING_VERSION,
|
|
139
|
+
landXmlSchema: source.schema,
|
|
140
|
+
units,
|
|
141
|
+
assumedLinearUnit: units.assumed ? units.linearUnit : null,
|
|
142
|
+
coordinateOrderSwapped: swap,
|
|
143
|
+
refusedFamilies: refusals.map((refusal) => refusal.family),
|
|
144
|
+
};
|
|
145
|
+
writeProvenance(terrain, provenance, coverage);
|
|
146
|
+
return {
|
|
147
|
+
status: 'exported',
|
|
148
|
+
content: creator.toIfc().content,
|
|
149
|
+
coverage,
|
|
150
|
+
provenance,
|
|
151
|
+
refusals,
|
|
152
|
+
warnings,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* GlobalIds for the entities that have no LandXML source id of their own — the
|
|
157
|
+
* project, site, building, contexts and every relationship row.
|
|
158
|
+
*
|
|
159
|
+
* Seeded from the source name and a counter so two exports of one source are
|
|
160
|
+
* byte-identical (§8.4). A random source would make every export differ, which
|
|
161
|
+
* would make `ifc-lite diff` between two conversions meaningless.
|
|
162
|
+
*/
|
|
163
|
+
function deterministicGuidSource(seed) {
|
|
164
|
+
let ordinal = 0;
|
|
165
|
+
return () => {
|
|
166
|
+
ordinal += 1;
|
|
167
|
+
return landXmlGlobalId(`landxml-ifc:${seed}:${ordinal}`);
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* §7 — what the file says about where it came from, as a property set on the
|
|
172
|
+
* site. It records the assumption, not just the result: an export made under an
|
|
173
|
+
* assumed unit or a coordinate-order override is indistinguishable from a
|
|
174
|
+
* declared one by its geometry alone.
|
|
175
|
+
*/
|
|
176
|
+
function writeProvenance(terrain, provenance, coverage) {
|
|
177
|
+
const properties = [
|
|
178
|
+
{ Name: 'DerivedConversion', Value: 'true' },
|
|
179
|
+
{ Name: 'MappingVersion', Value: provenance.mappingVersion },
|
|
180
|
+
{ Name: 'LandXmlSchema', Value: provenance.landXmlSchema },
|
|
181
|
+
{ Name: 'SourceFileName', Value: provenance.sourceFileName ?? '' },
|
|
182
|
+
{ Name: 'SourceHash', Value: provenance.sourceHash ?? '' },
|
|
183
|
+
{ Name: 'LinearUnit', Value: provenance.units?.linearUnit ?? '' },
|
|
184
|
+
{ Name: 'ElevationUnit', Value: provenance.units?.elevationUnit ?? '' },
|
|
185
|
+
{ Name: 'AssumedLinearUnit', Value: provenance.assumedLinearUnit ?? '' },
|
|
186
|
+
{ Name: 'CoordinateOrderSwapped', Value: String(provenance.coordinateOrderSwapped) },
|
|
187
|
+
{ Name: 'RefusedRecordFamilies', Value: provenance.refusedFamilies.join(', ') },
|
|
188
|
+
{ Name: 'ExportedSurfaces', Value: String(coverage.surfaces) },
|
|
189
|
+
{ Name: 'ExportedSurveyPoints', Value: String(coverage.surveyPoints) },
|
|
190
|
+
{ Name: 'ExportedAlignments', Value: String(coverage.alignments ?? 0) },
|
|
191
|
+
];
|
|
192
|
+
terrain.addPropertySet(terrain.siteId, {
|
|
193
|
+
Name: 'LandXML_Conversion',
|
|
194
|
+
Properties: properties,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=landxml-to-ifc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"landxml-to-ifc.js","sourceRoot":"","sources":["../../src/landxml/landxml-to-ifc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enumerate the LandXML record families a source carries that v1 does not map.
|
|
3
|
+
*
|
|
4
|
+
* §5 of the mapping spec: named, never silently dropped. The point of counting
|
|
5
|
+
* them is that "this file has 14 alignments and none of them are in your IFC"
|
|
6
|
+
* is actionable, while a missing record is not even noticeable.
|
|
7
|
+
*/
|
|
8
|
+
import type { LandXmlIfcSource, LandXmlIfcSurface } from './source-types.js';
|
|
9
|
+
import type { LandXmlRefusal } from './result-types.js';
|
|
10
|
+
import { type AlignmentMapping, type RefusedAlignment } from './alignment-mapping.js';
|
|
11
|
+
/**
|
|
12
|
+
* A surface v1 can write: a rendered TIN with vertices and at least one
|
|
13
|
+
* VISIBLE face. A surface whose every face is an authored `<F i="true">` draws
|
|
14
|
+
* nothing, so it is refused by name like any other non-rendered surface rather
|
|
15
|
+
* than vanishing from an otherwise successful export.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isMappableSurface(surface: LandXmlIfcSurface): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Every out-of-scope family the source actually contains, with its count.
|
|
20
|
+
*
|
|
21
|
+
* A family with zero records is absent from the list rather than present with
|
|
22
|
+
* `count: 0` — a refusal the user cannot act on is noise, and "0 parcels were
|
|
23
|
+
* not exported" is exactly that.
|
|
24
|
+
*/
|
|
25
|
+
/** The alignment mapping for a source, computed the one way both the plan and the export use. */
|
|
26
|
+
export declare function alignmentMappingOf(source: LandXmlIfcSource): AlignmentMapping;
|
|
27
|
+
export declare function collectRefusals(source: LandXmlIfcSource, alignmentMapping?: AlignmentMapping): LandXmlRefusal[];
|
|
28
|
+
/**
|
|
29
|
+
* Name each refused alignment and why. A count alone ("2 alignments") leaves
|
|
30
|
+
* the operator unable to tell a spiral type from a gap from a sign problem.
|
|
31
|
+
*/
|
|
32
|
+
export declare function alignmentRefusalMessage(refused: readonly RefusedAlignment[]): string;
|
|
33
|
+
/**
|
|
34
|
+
* The sentence shown when nothing in the source is mappable.
|
|
35
|
+
*
|
|
36
|
+
* It names what the file *does* hold. A bare "nothing to export" leaves the
|
|
37
|
+
* operator to guess whether the file is empty, unsupported, or broken — and
|
|
38
|
+
* for the alignment-only files §9.4 is about, the answer is none of those.
|
|
39
|
+
*/
|
|
40
|
+
export declare function refusalReason(refusals: readonly LandXmlRefusal[]): string;
|
|
41
|
+
//# sourceMappingURL=refusals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refusals.d.ts","sourceRoot":"","sources":["../../src/landxml/refusals.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EACgD,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAClG,MAAM,wBAAwB,CAAC;AAmChC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAIrE;AAED;;;;;;GAMG;AACH,iGAAiG;AACjG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAE7E;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,GAAE,gBAA6C,GACxF,cAAc,EAAE,CAoClB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAOpF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,CAOzE"}
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
import { cogoPointResolver, isAlignmentRecord, mapAlignments, } from './alignment-mapping.js';
|
|
5
|
+
/**
|
|
6
|
+
* Why each family is out of scope, in the operator's terms.
|
|
7
|
+
*
|
|
8
|
+
* Kept as one table rather than inline strings so the export dialog, the
|
|
9
|
+
* provenance property set and the refusal report cannot drift apart on what
|
|
10
|
+
* the same family is called.
|
|
11
|
+
*/
|
|
12
|
+
const FAMILY_REASONS = {
|
|
13
|
+
alignments: 'an alignment is written only when every horizontal segment is a line, circular arc or clothoid that reproduces its authored end point; one that does not is refused whole, because a gap would make every later station wrong',
|
|
14
|
+
profiles: 'vertical profiles and their grade lines and vertical curves have no v1 mapping — they describe geometry along an alignment, which v1 does not carry',
|
|
15
|
+
'cross-sections': 'cross sections have no v1 mapping — they are sampled along an alignment, which v1 does not carry',
|
|
16
|
+
roadways: 'roadways have no v1 mapping — they compose alignments and surfaces, and v1 carries only the surfaces',
|
|
17
|
+
parcels: 'parcel boundaries have no v1 mapping',
|
|
18
|
+
monuments: 'survey monuments have no v1 mapping; only CgPoints become IfcAnnotation/.SURVEY.',
|
|
19
|
+
'plan-features': 'plan features have no v1 mapping',
|
|
20
|
+
'pipe-networks': 'pipe networks, structures and pipes have no v1 mapping',
|
|
21
|
+
'surface-boundaries': 'surface boundary polylines are not written; only the triangulated surface itself is',
|
|
22
|
+
'surface-breaklines': 'surface breaklines are not written; only the triangulated surface itself is',
|
|
23
|
+
'surface-contours': 'surface contour lines are not written; only the triangulated surface itself is',
|
|
24
|
+
'non-rendered-surfaces': 'surfaces that carry no numeric, renderable triangulation (or whose every face is hidden) cannot become an IfcTriangulatedIrregularNetwork',
|
|
25
|
+
'unlocated-cgpoints': 'CgPoints that carry only a point reference and no coordinates of their own have nothing to place',
|
|
26
|
+
'station-equations': 'station equations are not written; the alignment carries its start station only',
|
|
27
|
+
cant: 'cant (rail superelevation) has no mapping; the alignment is written with its horizontal layout only',
|
|
28
|
+
superelevation: 'road superelevation has no mapping; the alignment is written with its horizontal layout only',
|
|
29
|
+
};
|
|
30
|
+
function countAcrossSurfaces(surfaces, pick) {
|
|
31
|
+
return surfaces.reduce((total, surface) => total + (pick(surface)?.length ?? 0), 0);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A surface v1 can write: a rendered TIN with vertices and at least one
|
|
35
|
+
* VISIBLE face. A surface whose every face is an authored `<F i="true">` draws
|
|
36
|
+
* nothing, so it is refused by name like any other non-rendered surface rather
|
|
37
|
+
* than vanishing from an otherwise successful export.
|
|
38
|
+
*/
|
|
39
|
+
export function isMappableSurface(surface) {
|
|
40
|
+
return surface.renderState === 'rendered'
|
|
41
|
+
&& surface.points.length > 0
|
|
42
|
+
&& surface.faces.some((_, ordinal) => surface.faceVisibility?.[ordinal] !== false);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Every out-of-scope family the source actually contains, with its count.
|
|
46
|
+
*
|
|
47
|
+
* A family with zero records is absent from the list rather than present with
|
|
48
|
+
* `count: 0` — a refusal the user cannot act on is noise, and "0 parcels were
|
|
49
|
+
* not exported" is exactly that.
|
|
50
|
+
*/
|
|
51
|
+
/** The alignment mapping for a source, computed the one way both the plan and the export use. */
|
|
52
|
+
export function alignmentMappingOf(source) {
|
|
53
|
+
return mapAlignments(source.alignments, source.units, false, cogoPointResolver(source.plan?.cogoPoints));
|
|
54
|
+
}
|
|
55
|
+
export function collectRefusals(source, alignmentMapping = alignmentMappingOf(source)) {
|
|
56
|
+
// Only the alignments that are WRITTEN carry these on into the IFC; a
|
|
57
|
+
// refused alignment takes its station equations and cant with it, and
|
|
58
|
+
// counting them twice would misstate what is missing.
|
|
59
|
+
const written = new Set(alignmentMapping.mapped.map((alignment) => alignment.sourceId));
|
|
60
|
+
const writtenAlignments = (source.alignments ?? [])
|
|
61
|
+
.filter(isAlignmentRecord)
|
|
62
|
+
.filter((alignment) => written.has(alignment.sourceId));
|
|
63
|
+
const counts = [
|
|
64
|
+
['alignments', alignmentMapping.refused.length],
|
|
65
|
+
['station-equations', writtenAlignments.reduce((n, a) => n + (a.stationEquations?.length ?? 0), 0)],
|
|
66
|
+
['cant', writtenAlignments.filter((a) => a.cant || (a.cantStations?.length ?? 0) > 0).length],
|
|
67
|
+
['superelevation', writtenAlignments.reduce((n, a) => n + (a.superelevations?.length ?? 0), 0)],
|
|
68
|
+
['profiles', source.profiles?.length ?? 0],
|
|
69
|
+
['cross-sections', (source.crossSections?.length ?? 0) + (source.crossSectionSurfaces?.length ?? 0)],
|
|
70
|
+
['roadways', source.roadways?.length ?? 0],
|
|
71
|
+
['parcels', source.plan?.parcels?.length ?? 0],
|
|
72
|
+
['monuments', source.plan?.monuments?.length ?? 0],
|
|
73
|
+
['plan-features', source.plan?.planFeatures?.length ?? 0],
|
|
74
|
+
['pipe-networks', source.pipeNetworks?.networks?.length ?? 0],
|
|
75
|
+
['surface-boundaries', countAcrossSurfaces(source.surfaces, (s) => s.boundaries)],
|
|
76
|
+
['surface-breaklines', countAcrossSurfaces(source.surfaces, (s) => s.breaklines)],
|
|
77
|
+
['surface-contours', countAcrossSurfaces(source.surfaces, (s) => s.contours)],
|
|
78
|
+
['non-rendered-surfaces', source.surfaces.filter((s) => !isMappableSurface(s)).length],
|
|
79
|
+
['unlocated-cgpoints', (source.plan?.cogoPoints ?? []).filter((point) => point.point === null).length],
|
|
80
|
+
];
|
|
81
|
+
return counts
|
|
82
|
+
.filter(([, count]) => count > 0)
|
|
83
|
+
.map(([family, count]) => ({
|
|
84
|
+
family,
|
|
85
|
+
count,
|
|
86
|
+
message: family === 'alignments'
|
|
87
|
+
? alignmentRefusalMessage(alignmentMapping.refused)
|
|
88
|
+
: `${count} ${family.replace(/-/g, ' ')} record${count === 1 ? '' : 's'} will not be included: ${FAMILY_REASONS[family]}.`,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Name each refused alignment and why. A count alone ("2 alignments") leaves
|
|
93
|
+
* the operator unable to tell a spiral type from a gap from a sign problem.
|
|
94
|
+
*/
|
|
95
|
+
export function alignmentRefusalMessage(refused) {
|
|
96
|
+
// Every one is named: an alignment left out as "and N more" is one the
|
|
97
|
+
// operator cannot find or fix (#5370 review).
|
|
98
|
+
const count = refused.length;
|
|
99
|
+
const named = refused.map((entry) => `'${entry.name}': ${entry.reason}`);
|
|
100
|
+
return `${count} alignment record${count === 1 ? '' : 's'} will not be included (${named.join('; ')}). `
|
|
101
|
+
+ `${FAMILY_REASONS.alignments}.`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The sentence shown when nothing in the source is mappable.
|
|
105
|
+
*
|
|
106
|
+
* It names what the file *does* hold. A bare "nothing to export" leaves the
|
|
107
|
+
* operator to guess whether the file is empty, unsupported, or broken — and
|
|
108
|
+
* for the alignment-only files §9.4 is about, the answer is none of those.
|
|
109
|
+
*/
|
|
110
|
+
export function refusalReason(refusals) {
|
|
111
|
+
if (refusals.length === 0) {
|
|
112
|
+
return 'This LandXML file carries no triangulated surface, no CgPoints and no alignment, so there is nothing the IFC mapping can write.';
|
|
113
|
+
}
|
|
114
|
+
const families = refusals.map((refusal) => `${refusal.count} ${refusal.family.replace(/-/g, ' ')}`).join(', ');
|
|
115
|
+
return `This LandXML file carries no record the IFC mapping covers. It contains ${families}, `
|
|
116
|
+
+ 'none of which has a v1 mapping. Export the original LandXML file instead.';
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=refusals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../src/landxml/refusals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a LandXML→IFC conversion returns.
|
|
3
|
+
*
|
|
4
|
+
* The result is a discriminated union rather than a string plus an error
|
|
5
|
+
* channel, because §6 of the mapping makes refusal a first-class outcome: a
|
|
6
|
+
* source with no in-scope record must refuse outright, not hand back a valid,
|
|
7
|
+
* empty, useless IFC. A caller cannot reach `content` without having seen
|
|
8
|
+
* which of the two happened.
|
|
9
|
+
*/
|
|
10
|
+
import type { LandXmlIfcUnits } from './source-types.js';
|
|
11
|
+
/**
|
|
12
|
+
* A LandXML record family the v1 mapping does not cover (§5).
|
|
13
|
+
*
|
|
14
|
+
* Named, never silently dropped — the family names are the vocabulary the
|
|
15
|
+
* export dialog shows the user before they commit.
|
|
16
|
+
*/
|
|
17
|
+
export type LandXmlRefusedFamily = 'alignments' | 'profiles' | 'cross-sections' | 'roadways' | 'parcels' | 'monuments' | 'plan-features' | 'pipe-networks' | 'surface-boundaries' | 'surface-breaklines' | 'surface-contours' | 'non-rendered-surfaces' | 'unlocated-cgpoints' | 'station-equations' | 'cant' | 'superelevation';
|
|
18
|
+
export interface LandXmlRefusal {
|
|
19
|
+
family: LandXmlRefusedFamily;
|
|
20
|
+
/** How many records of this family the source holds. Always ≥ 1. */
|
|
21
|
+
count: number;
|
|
22
|
+
/** One sentence, addressed to the operator, saying what is left out and why. */
|
|
23
|
+
message: string;
|
|
24
|
+
}
|
|
25
|
+
/** A condition worth surfacing that does not stop the export (§9.1). */
|
|
26
|
+
export interface LandXmlIfcWarning {
|
|
27
|
+
/** Stable code so the UI can style or suppress by kind, never by text. */
|
|
28
|
+
code: 'LXIFC-COORD-ORDER' | 'LXIFC-ASSUMED-UNIT' | 'LXIFC-NO-CRS' | 'LXIFC-COORD-SWAPPED';
|
|
29
|
+
message: string;
|
|
30
|
+
}
|
|
31
|
+
export interface LandXmlIfcCoverage {
|
|
32
|
+
/** TIN surfaces written as `IfcGeographicElement`/`.TERRAIN.`. */
|
|
33
|
+
surfaces: number;
|
|
34
|
+
/** `<CgPoint>` records written as `IfcAnnotation`/`.SURVEY.`. */
|
|
35
|
+
surveyPoints: number;
|
|
36
|
+
/** Vertices across all written surfaces. */
|
|
37
|
+
vertices: number;
|
|
38
|
+
/** Triangles across all written surfaces. */
|
|
39
|
+
triangles: number;
|
|
40
|
+
/**
|
|
41
|
+
* Horizontal alignments written as `IfcAlignment` (§11). `landXmlToIfc`
|
|
42
|
+
* always sets it; it is optional only so that adding it is not a breaking
|
|
43
|
+
* change to an interface v1.0 may already have published (#5370 review) —
|
|
44
|
+
* read it as `coverage.alignments ?? 0`.
|
|
45
|
+
*/
|
|
46
|
+
alignments?: number;
|
|
47
|
+
}
|
|
48
|
+
/** What the produced file records about where it came from (§7). */
|
|
49
|
+
export interface LandXmlIfcProvenance {
|
|
50
|
+
sourceFileName: string | null;
|
|
51
|
+
sourceHash: string | null;
|
|
52
|
+
mappingVersion: string;
|
|
53
|
+
landXmlSchema: string;
|
|
54
|
+
units: LandXmlIfcUnits | null;
|
|
55
|
+
assumedLinearUnit: string | null;
|
|
56
|
+
coordinateOrderSwapped: boolean;
|
|
57
|
+
refusedFamilies: readonly LandXmlRefusedFamily[];
|
|
58
|
+
}
|
|
59
|
+
export type LandXmlIfcResult = {
|
|
60
|
+
status: 'exported';
|
|
61
|
+
content: string;
|
|
62
|
+
coverage: LandXmlIfcCoverage;
|
|
63
|
+
provenance: LandXmlIfcProvenance;
|
|
64
|
+
refusals: readonly LandXmlRefusal[];
|
|
65
|
+
warnings: readonly LandXmlIfcWarning[];
|
|
66
|
+
} | {
|
|
67
|
+
status: 'refused';
|
|
68
|
+
/** Why nothing could be written, naming what the source does contain. */
|
|
69
|
+
reason: string;
|
|
70
|
+
refusals: readonly LandXmlRefusal[];
|
|
71
|
+
warnings: readonly LandXmlIfcWarning[];
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=result-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-types.d.ts","sourceRoot":"","sources":["../../src/landxml/result-types.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC5B,YAAY,GACZ,UAAU,GACV,gBAAgB,GAChB,UAAU,GACV,SAAS,GACT,WAAW,GACX,eAAe,GACf,eAAe,GACf,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,uBAAuB,GACvB,oBAAoB,GACpB,mBAAmB,GACnB,MAAM,GACN,gBAAgB,CAAC;AAErB,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wEAAwE;AACxE,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,IAAI,EAAE,mBAAmB,GAAG,oBAAoB,GAAG,cAAc,GAAG,qBAAqB,CAAC;IAC1F,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,oEAAoE;AACpE,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,sBAAsB,EAAE,OAAO,CAAC;IAChC,eAAe,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAClD;AAED,MAAM,MAAM,gBAAgB,GACxB;IACA,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,oBAAoB,CAAC;IACjC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACxC,GACC;IACA,MAAM,EAAE,SAAS,CAAC;IAClB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACxC,CAAC"}
|