@ifc-lite/create 2.8.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +7 -0
  2. package/dist/ifc-creator-alignment-referents.d.ts +35 -0
  3. package/dist/ifc-creator-alignment-referents.d.ts.map +1 -0
  4. package/dist/ifc-creator-alignment-referents.js +89 -0
  5. package/dist/ifc-creator-alignment-referents.js.map +1 -0
  6. package/dist/ifc-creator-alignment-vertical.d.ts +40 -0
  7. package/dist/ifc-creator-alignment-vertical.d.ts.map +1 -0
  8. package/dist/ifc-creator-alignment-vertical.js +182 -0
  9. package/dist/ifc-creator-alignment-vertical.js.map +1 -0
  10. package/dist/ifc-creator-alignment.d.ts +45 -0
  11. package/dist/ifc-creator-alignment.d.ts.map +1 -0
  12. package/dist/ifc-creator-alignment.js +173 -0
  13. package/dist/ifc-creator-alignment.js.map +1 -0
  14. package/dist/ifc-creator-header.d.ts +2 -0
  15. package/dist/ifc-creator-header.d.ts.map +1 -0
  16. package/dist/ifc-creator-header.js +22 -0
  17. package/dist/ifc-creator-header.js.map +1 -0
  18. package/dist/ifc-creator-math.d.ts +37 -5
  19. package/dist/ifc-creator-math.d.ts.map +1 -1
  20. package/dist/ifc-creator-math.js +93 -4
  21. package/dist/ifc-creator-math.js.map +1 -1
  22. package/dist/ifc-creator-relationships.d.ts +43 -0
  23. package/dist/ifc-creator-relationships.d.ts.map +1 -0
  24. package/dist/ifc-creator-relationships.js +38 -0
  25. package/dist/ifc-creator-relationships.js.map +1 -0
  26. package/dist/ifc-creator-styles.d.ts +22 -0
  27. package/dist/ifc-creator-styles.d.ts.map +1 -0
  28. package/dist/ifc-creator-styles.js +50 -0
  29. package/dist/ifc-creator-styles.js.map +1 -0
  30. package/dist/ifc-creator-terrain.d.ts +170 -0
  31. package/dist/ifc-creator-terrain.d.ts.map +1 -0
  32. package/dist/ifc-creator-terrain.js +180 -0
  33. package/dist/ifc-creator-terrain.js.map +1 -0
  34. package/dist/ifc-creator.d.ts +21 -7
  35. package/dist/ifc-creator.d.ts.map +1 -1
  36. package/dist/ifc-creator.js +93 -97
  37. package/dist/ifc-creator.js.map +1 -1
  38. package/dist/in-store/_emit-helpers.d.ts +2 -1
  39. package/dist/in-store/_emit-helpers.d.ts.map +1 -1
  40. package/dist/in-store/_emit-helpers.js +7 -7
  41. package/dist/in-store/_emit-helpers.js.map +1 -1
  42. package/dist/in-store/anchor.d.ts +2 -0
  43. package/dist/in-store/anchor.d.ts.map +1 -1
  44. package/dist/in-store/anchor.js.map +1 -1
  45. package/dist/in-store/apply-style.d.ts +3 -6
  46. package/dist/in-store/apply-style.d.ts.map +1 -1
  47. package/dist/in-store/apply-style.js +3 -77
  48. package/dist/in-store/apply-style.js.map +1 -1
  49. package/dist/in-store/column.d.ts.map +1 -1
  50. package/dist/in-store/column.js +2 -0
  51. package/dist/in-store/column.js.map +1 -1
  52. package/dist/in-store/door.d.ts.map +1 -1
  53. package/dist/in-store/door.js +2 -0
  54. package/dist/in-store/door.js.map +1 -1
  55. package/dist/in-store/extract-walls.d.ts +1 -1
  56. package/dist/in-store/extract-walls.d.ts.map +1 -1
  57. package/dist/in-store/extract-walls.js +37 -55
  58. package/dist/in-store/extract-walls.js.map +1 -1
  59. package/dist/in-store/generate-spaces-all.d.ts +6 -2
  60. package/dist/in-store/generate-spaces-all.d.ts.map +1 -1
  61. package/dist/in-store/generate-spaces-all.js +33 -9
  62. package/dist/in-store/generate-spaces-all.js.map +1 -1
  63. package/dist/in-store/generate-spaces.js +1 -1
  64. package/dist/in-store/generate-spaces.js.map +1 -1
  65. package/dist/in-store/placement-frame.d.ts +8 -0
  66. package/dist/in-store/placement-frame.d.ts.map +1 -1
  67. package/dist/in-store/placement-frame.js.map +1 -1
  68. package/dist/in-store/plate.d.ts.map +1 -1
  69. package/dist/in-store/plate.js +4 -0
  70. package/dist/in-store/plate.js.map +1 -1
  71. package/dist/in-store/resolve-anchor.d.ts +4 -2
  72. package/dist/in-store/resolve-anchor.d.ts.map +1 -1
  73. package/dist/in-store/resolve-anchor.js +79 -92
  74. package/dist/in-store/resolve-anchor.js.map +1 -1
  75. package/dist/in-store/resolve-source.d.ts +2 -1
  76. package/dist/in-store/resolve-source.d.ts.map +1 -1
  77. package/dist/in-store/resolve-source.js +49 -49
  78. package/dist/in-store/resolve-source.js.map +1 -1
  79. package/dist/in-store/roof.d.ts.map +1 -1
  80. package/dist/in-store/roof.js +4 -0
  81. package/dist/in-store/roof.js.map +1 -1
  82. package/dist/in-store/slab.d.ts.map +1 -1
  83. package/dist/in-store/slab.js +4 -0
  84. package/dist/in-store/slab.js.map +1 -1
  85. package/dist/in-store/space.d.ts.map +1 -1
  86. package/dist/in-store/space.js +4 -0
  87. package/dist/in-store/space.js.map +1 -1
  88. package/dist/in-store/spatial-children.d.ts +52 -0
  89. package/dist/in-store/spatial-children.d.ts.map +1 -0
  90. package/dist/in-store/spatial-children.js +112 -0
  91. package/dist/in-store/spatial-children.js.map +1 -0
  92. package/dist/in-store/spatial-zone.d.ts.map +1 -1
  93. package/dist/in-store/spatial-zone.js +5 -5
  94. package/dist/in-store/spatial-zone.js.map +1 -1
  95. package/dist/in-store/style-entity-reader.d.ts +14 -0
  96. package/dist/in-store/style-entity-reader.d.ts.map +1 -0
  97. package/dist/in-store/style-entity-reader.js +58 -0
  98. package/dist/in-store/style-entity-reader.js.map +1 -0
  99. package/dist/in-store/wall.d.ts.map +1 -1
  100. package/dist/in-store/wall.js +4 -14
  101. package/dist/in-store/wall.js.map +1 -1
  102. package/dist/in-store/window.d.ts.map +1 -1
  103. package/dist/in-store/window.js +2 -0
  104. package/dist/in-store/window.js.map +1 -1
  105. package/dist/index.d.ts +12 -1
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +5 -0
  108. package/dist/index.js.map +1 -1
  109. package/dist/landxml/alignment-mapping.d.ts +98 -0
  110. package/dist/landxml/alignment-mapping.d.ts.map +1 -0
  111. package/dist/landxml/alignment-mapping.js +282 -0
  112. package/dist/landxml/alignment-mapping.js.map +1 -0
  113. package/dist/landxml/alignment-record.d.ts +18 -0
  114. package/dist/landxml/alignment-record.d.ts.map +1 -0
  115. package/dist/landxml/alignment-record.js +63 -0
  116. package/dist/landxml/alignment-record.js.map +1 -0
  117. package/dist/landxml/coordinate-plausibility.d.ts +54 -0
  118. package/dist/landxml/coordinate-plausibility.d.ts.map +1 -0
  119. package/dist/landxml/coordinate-plausibility.js +59 -0
  120. package/dist/landxml/coordinate-plausibility.js.map +1 -0
  121. package/dist/landxml/landxml-to-ifc.d.ts +45 -0
  122. package/dist/landxml/landxml-to-ifc.d.ts.map +1 -0
  123. package/dist/landxml/landxml-to-ifc.js +203 -0
  124. package/dist/landxml/landxml-to-ifc.js.map +1 -0
  125. package/dist/landxml/profile-geometry.d.ts +50 -0
  126. package/dist/landxml/profile-geometry.d.ts.map +1 -0
  127. package/dist/landxml/profile-geometry.js +221 -0
  128. package/dist/landxml/profile-geometry.js.map +1 -0
  129. package/dist/landxml/profile-mapping.d.ts +36 -0
  130. package/dist/landxml/profile-mapping.d.ts.map +1 -0
  131. package/dist/landxml/profile-mapping.js +181 -0
  132. package/dist/landxml/profile-mapping.js.map +1 -0
  133. package/dist/landxml/profile-record.d.ts +46 -0
  134. package/dist/landxml/profile-record.d.ts.map +1 -0
  135. package/dist/landxml/profile-record.js +38 -0
  136. package/dist/landxml/profile-record.js.map +1 -0
  137. package/dist/landxml/refusals.d.ts +45 -0
  138. package/dist/landxml/refusals.d.ts.map +1 -0
  139. package/dist/landxml/refusals.js +141 -0
  140. package/dist/landxml/refusals.js.map +1 -0
  141. package/dist/landxml/result-types.d.ts +78 -0
  142. package/dist/landxml/result-types.d.ts.map +1 -0
  143. package/dist/landxml/result-types.js +5 -0
  144. package/dist/landxml/result-types.js.map +1 -0
  145. package/dist/landxml/source-types.d.ts +169 -0
  146. package/dist/landxml/source-types.d.ts.map +1 -0
  147. package/dist/landxml/source-types.js +5 -0
  148. package/dist/landxml/source-types.js.map +1 -0
  149. package/dist/landxml/station-equations.d.ts +69 -0
  150. package/dist/landxml/station-equations.d.ts.map +1 -0
  151. package/dist/landxml/station-equations.js +140 -0
  152. package/dist/landxml/station-equations.js.map +1 -0
  153. package/dist/landxml/writers.d.ts +33 -0
  154. package/dist/landxml/writers.d.ts.map +1 -0
  155. package/dist/landxml/writers.js +160 -0
  156. package/dist/landxml/writers.js.map +1 -0
  157. package/dist/types.d.ts +13 -2
  158. package/dist/types.d.ts.map +1 -1
  159. package/package.json +6 -6
@@ -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.3";
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;AAMhG,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,CAoIxG"}
@@ -0,0 +1,203 @@
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 { mapProfiles } from './profile-mapping.js';
31
+ import { stationEquationsOf } from './station-equations.js';
32
+ import { writeAlignments, writeSurfaces, writeSurveyPoints } from './writers.js';
33
+ /** The mapping-document version this converter implements. */
34
+ export const LANDXML_IFC_MAPPING_VERSION = '1.3';
35
+ /** Deterministic GlobalId from a LandXML source id (§4.3, §10). */
36
+ export function landXmlGlobalId(sourceId) {
37
+ return uuidToIfcGuid(uuidFromSeed(sourceId));
38
+ }
39
+ /**
40
+ * Convert a parsed LandXML document to an IFC4X3 STEP file.
41
+ *
42
+ * Returns `{ status: 'refused' }` — with the refusal list intact — when the
43
+ * source carries nothing the mapping covers. That is not an error case to be
44
+ * caught; it is the honest answer for the alignment-only files §9.4 discusses.
45
+ */
46
+ export function landXmlToIfc(source, options = {}) {
47
+ const swap = options.swapNorthingEasting === true;
48
+ // Mapped once, and the same mapping decides both what is written and what
49
+ // the refusal list says was not — two passes could disagree.
50
+ const alignmentMapping = mapAlignments(source.alignments, source.units, swap, cogoPointResolver(source.plan?.cogoPoints));
51
+ const stationing = stationEquationsOf(source, alignmentMapping);
52
+ const profileMapping = mapProfiles(source.profiles, source.alignments, alignmentMapping, source.units, stationing);
53
+ const refusals = collectRefusals(source, alignmentMapping, profileMapping, stationing);
54
+ const warnings = [];
55
+ const mappableSurfaces = source.surfaces.filter(isMappableSurface);
56
+ const cogoPoints = (source.plan?.cogoPoints ?? []).filter((point) => point.point !== null);
57
+ const units = source.units;
58
+ if (units === null) {
59
+ // Distinct from an empty source: the file may hold a perfectly good TIN, and
60
+ // the operator needs to know the fix is units, not content.
61
+ return {
62
+ status: 'refused',
63
+ reason: 'This LandXML file declares no LandXML/Units element, so no coordinate can be scaled to '
64
+ + 'metres. Load it with an explicit assumed linear unit, or export the original LandXML file instead.',
65
+ refusals,
66
+ warnings,
67
+ };
68
+ }
69
+ if (mappableSurfaces.length === 0 && cogoPoints.length === 0 && alignmentMapping.mapped.length === 0) {
70
+ return { status: 'refused', reason: refusalReason(refusals), refusals, warnings };
71
+ }
72
+ if (units.assumed) {
73
+ warnings.push({
74
+ code: 'LXIFC-ASSUMED-UNIT',
75
+ message: `Every coordinate in this export is scaled by an ASSUMED linear unit ('${units.linearUnit}'). `
76
+ + 'The source declares no LandXML/Units element, so the scale was chosen by an operator, not read '
77
+ + 'from the file. The geometry is at that operator-chosen scale and nothing in the IFC records '
78
+ + 'otherwise except this file\'s provenance property set.',
79
+ });
80
+ }
81
+ if (!options.crs) {
82
+ warnings.push({
83
+ code: 'LXIFC-NO-CRS',
84
+ message: 'No coordinate reference system is declared, so no IfcProjectedCRS or IfcMapConversion is written '
85
+ + 'and the coordinate-order plausibility check cannot run. The coordinates are written as authored.',
86
+ });
87
+ }
88
+ if (options.swapNorthingEasting) {
89
+ warnings.push({
90
+ code: 'LXIFC-COORD-SWAPPED',
91
+ message: 'A coordinate-order override is in force: the source\'s point text is being read as '
92
+ + 'easting-first rather than LandXML\'s northing-first order. This is an operator assertion about '
93
+ + 'the producer, not something read from the file.',
94
+ });
95
+ }
96
+ const creator = new IfcCreator({
97
+ // Declared as `IFC4X3_ADD2` by `IfcCreator` itself, like all IFC4X3
98
+ // output (`fileSchemaIdentifier`, #5351).
99
+ Schema: 'IFC4X3',
100
+ Name: options.sourceFileName ?? 'LandXML conversion',
101
+ Description: `Derived from LandXML ${source.schema} by the ifc-lite LandXML→IFC mapping v${LANDXML_IFC_MAPPING_VERSION}`,
102
+ LengthUnit: 'METRE',
103
+ ...(options.timestampMs === undefined ? {} : { Timestamp: options.timestampMs }),
104
+ ...(options.Author === undefined ? {} : { Author: options.Author }),
105
+ ...(options.Organization === undefined ? {} : { Organization: options.Organization }),
106
+ // Content hash first: two different files exported without a name must not
107
+ // share project/site/relationship GlobalIds, or federating them collides.
108
+ GuidSource: deterministicGuidSource(options.sourceHash ?? options.sourceFileName ?? source.schema),
109
+ });
110
+ const terrain = creator.terrain();
111
+ if (options.crs) {
112
+ terrain.setGeoreferencing({
113
+ Name: options.crs.Name,
114
+ Description: options.crs.Description,
115
+ GeodeticDatum: options.crs.GeodeticDatum ?? source.coordinateSystem?.horizontalDatum,
116
+ VerticalDatum: options.crs.VerticalDatum ?? source.coordinateSystem?.verticalDatum,
117
+ MapProjection: options.crs.MapProjection,
118
+ MapZone: options.crs.MapZone,
119
+ });
120
+ }
121
+ const surfaceResult = writeSurfaces(terrain, source.surfaces, units, swap, landXmlGlobalId);
122
+ const pointResult = writeSurveyPoints(terrain, cogoPoints, units, swap, landXmlGlobalId);
123
+ const alignmentSamples = writeAlignments(terrain, alignmentMapping.mapped, landXmlGlobalId, profileMapping.mapped, stationing);
124
+ if (options.crs?.Bounds) {
125
+ const warning = checkCoordinateOrder([...surfaceResult.samples, ...pointResult.samples, ...alignmentSamples], options.crs.Bounds, options.crs.Name);
126
+ if (warning)
127
+ warnings.push(warning);
128
+ }
129
+ const coverage = {
130
+ surfaces: surfaceResult.surfaces,
131
+ surveyPoints: pointResult.count,
132
+ vertices: surfaceResult.vertices,
133
+ triangles: surfaceResult.triangles,
134
+ alignments: alignmentMapping.mapped.length,
135
+ profiles: profileMapping.mapped.length,
136
+ };
137
+ if (coverage.surfaces === 0 && coverage.surveyPoints === 0 && (coverage.alignments ?? 0) === 0) {
138
+ return { status: 'refused', reason: refusalReason(refusals), refusals, warnings };
139
+ }
140
+ const provenance = {
141
+ sourceFileName: options.sourceFileName ?? null,
142
+ sourceHash: options.sourceHash ?? null,
143
+ mappingVersion: LANDXML_IFC_MAPPING_VERSION,
144
+ landXmlSchema: source.schema,
145
+ units,
146
+ assumedLinearUnit: units.assumed ? units.linearUnit : null,
147
+ coordinateOrderSwapped: swap,
148
+ refusedFamilies: refusals.map((refusal) => refusal.family),
149
+ };
150
+ writeProvenance(terrain, provenance, coverage);
151
+ return {
152
+ status: 'exported',
153
+ content: creator.toIfc().content,
154
+ coverage,
155
+ provenance,
156
+ refusals,
157
+ warnings,
158
+ };
159
+ }
160
+ /**
161
+ * GlobalIds for the entities that have no LandXML source id of their own — the
162
+ * project, site, building, contexts and every relationship row.
163
+ *
164
+ * Seeded from the source name and a counter so two exports of one source are
165
+ * byte-identical (§8.4). A random source would make every export differ, which
166
+ * would make `ifc-lite diff` between two conversions meaningless.
167
+ */
168
+ function deterministicGuidSource(seed) {
169
+ let ordinal = 0;
170
+ return () => {
171
+ ordinal += 1;
172
+ return landXmlGlobalId(`landxml-ifc:${seed}:${ordinal}`);
173
+ };
174
+ }
175
+ /**
176
+ * §7 — what the file says about where it came from, as a property set on the
177
+ * site. It records the assumption, not just the result: an export made under an
178
+ * assumed unit or a coordinate-order override is indistinguishable from a
179
+ * declared one by its geometry alone.
180
+ */
181
+ function writeProvenance(terrain, provenance, coverage) {
182
+ const properties = [
183
+ { Name: 'DerivedConversion', Value: 'true' },
184
+ { Name: 'MappingVersion', Value: provenance.mappingVersion },
185
+ { Name: 'LandXmlSchema', Value: provenance.landXmlSchema },
186
+ { Name: 'SourceFileName', Value: provenance.sourceFileName ?? '' },
187
+ { Name: 'SourceHash', Value: provenance.sourceHash ?? '' },
188
+ { Name: 'LinearUnit', Value: provenance.units?.linearUnit ?? '' },
189
+ { Name: 'ElevationUnit', Value: provenance.units?.elevationUnit ?? '' },
190
+ { Name: 'AssumedLinearUnit', Value: provenance.assumedLinearUnit ?? '' },
191
+ { Name: 'CoordinateOrderSwapped', Value: String(provenance.coordinateOrderSwapped) },
192
+ { Name: 'RefusedRecordFamilies', Value: provenance.refusedFamilies.join(', ') },
193
+ { Name: 'ExportedSurfaces', Value: String(coverage.surfaces) },
194
+ { Name: 'ExportedSurveyPoints', Value: String(coverage.surveyPoints) },
195
+ { Name: 'ExportedAlignments', Value: String(coverage.alignments ?? 0) },
196
+ { Name: 'ExportedProfiles', Value: String(coverage.profiles ?? 0) },
197
+ ];
198
+ terrain.addPropertySet(terrain.siteId, {
199
+ Name: 'LandXML_Conversion',
200
+ Properties: properties,
201
+ });
202
+ }
203
+ //# 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,50 @@
1
+ import type { LandXmlIfcVerticalCurve } from './profile-record.js';
2
+ export type VerticalSegmentType = 'CONSTANTGRADIENT' | 'PARABOLICARC' | 'CIRCULARARC';
3
+ /** One `IfcAlignmentVerticalSegment`, in metres. */
4
+ export interface VerticalSegment {
5
+ sourceId: string;
6
+ type: VerticalSegmentType;
7
+ startDistAlong: number;
8
+ horizontalLength: number;
9
+ startHeight: number;
10
+ startGradient: number;
11
+ endGradient: number;
12
+ /** Signed: positive for a sag (counter-clockwise in distance/height), negative for a crest; `null` for a grade. */
13
+ radiusOfCurvature: number | null;
14
+ }
15
+ /** A PVI in metres: distance along the horizontal, and height. */
16
+ export interface ProfileVertex {
17
+ sourceId: string;
18
+ distAlong: number;
19
+ height: number;
20
+ }
21
+ export declare class ProfileRefusal extends Error {
22
+ }
23
+ export declare function refuseProfile(message: string): never;
24
+ /**
25
+ * Height and gradient `x` metres into a segment (0 ≤ x ≤ horizontalLength).
26
+ * The circle is evaluated from its centre, which sits `R` to the left of the
27
+ * start tangent for a sag and to the right for a crest.
28
+ */
29
+ export declare function evaluateVertical(segment: VerticalSegment, x: number): {
30
+ height: number;
31
+ gradient: number;
32
+ };
33
+ /** Height of the whole profile at a distance along, or `null` outside it. */
34
+ export declare function profileHeightAt(segments: readonly VerticalSegment[], distAlong: number): number | null;
35
+ /**
36
+ * The segments that round off one PVI, in order — none for an equal-grade
37
+ * parabola, whose curve is the grade itself (§12.4).
38
+ */
39
+ export declare function curveSegments(curve: LandXmlIfcVerticalCurve, pvi: ProfileVertex, gradeIn: number, gradeOut: number, units: {
40
+ linearScaleToMeters: number;
41
+ elevationScaleToMeters: number;
42
+ }, label: string): VerticalSegment[];
43
+ /**
44
+ * Assemble grades and curves between the PVIs. `curves[i]` holds the
45
+ * segments rounding off PVI `i` (empty for a bare grade break).
46
+ */
47
+ export declare function assembleProfile(profileSourceId: string, vertices: readonly ProfileVertex[], curves: readonly VerticalSegment[][]): VerticalSegment[];
48
+ /** §12.5: joins are continuous, and the profile passes through what it must. */
49
+ export declare function checkProfile(segments: readonly VerticalSegment[], vertices: readonly ProfileVertex[], curves: readonly VerticalSegment[][]): void;
50
+ //# sourceMappingURL=profile-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-geometry.d.ts","sourceRoot":"","sources":["../../src/landxml/profile-geometry.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG,cAAc,GAAG,aAAa,CAAC;AAEtF,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,mHAAmH;IACnH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAE5C,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAEpD;AAKD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAe1G;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQtG;AAcD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,uBAAuB,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EACrF,KAAK,EAAE;IAAE,mBAAmB,EAAE,MAAM,CAAC;IAAC,sBAAsB,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,MAAM,GACpF,eAAe,EAAE,CAqEnB;AAUD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,aAAa,EAAE,EAAE,MAAM,EAAE,SAAS,eAAe,EAAE,EAAE,GAChG,eAAe,EAAE,CAgCnB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,SAAS,eAAe,EAAE,EAAE,QAAQ,EAAE,SAAS,aAAa,EAAE,EAAE,MAAM,EAAE,SAAS,eAAe,EAAE,EAAE,GAC7G,IAAI,CAiCN"}
@@ -0,0 +1,221 @@
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
+ * A LandXML design profile → `IfcAlignmentVerticalSegment` parameters
6
+ * (mapping spec §12.3–§12.5). Pure numbers: metres of distance along and of
7
+ * height, gradients as rise/run.
8
+ *
9
+ * The profile is authored as PVIs — tangent intersections — with a vertical
10
+ * curve at some of them. IFC wants the segments BETWEEN: grades, and the curves
11
+ * that round the PVIs off. This module turns the one into the other and then
12
+ * checks that the result passes through every authored point it should
13
+ * (§12.5), which is where a sign or a half-length error shows.
14
+ */
15
+ import { ALIGNMENT_POSITION_TOLERANCE_M } from './alignment-mapping.js';
16
+ export class ProfileRefusal extends Error {
17
+ }
18
+ export function refuseProfile(message) {
19
+ throw new ProfileRefusal(message);
20
+ }
21
+ /** A grade or curve joins its neighbours to well under this; floating noise only. */
22
+ const JOIN_EPSILON_M = 1e-6;
23
+ /**
24
+ * Height and gradient `x` metres into a segment (0 ≤ x ≤ horizontalLength).
25
+ * The circle is evaluated from its centre, which sits `R` to the left of the
26
+ * start tangent for a sag and to the right for a crest.
27
+ */
28
+ export function evaluateVertical(segment, x) {
29
+ const { startHeight: h0, startGradient: g0, endGradient: g1, horizontalLength: L } = segment;
30
+ if (segment.type === 'CONSTANTGRADIENT' || L === 0)
31
+ return { height: h0 + g0 * x, gradient: g0 };
32
+ if (segment.type === 'PARABOLICARC') {
33
+ return { height: h0 + g0 * x + ((g1 - g0) * x * x) / (2 * L), gradient: g0 + ((g1 - g0) * x) / L };
34
+ }
35
+ const radius = Math.abs(segment.radiusOfCurvature ?? 0);
36
+ const sag = g1 > g0;
37
+ const theta = Math.atan(g0);
38
+ const side = sag ? 1 : -1;
39
+ const cx = -side * radius * Math.sin(theta);
40
+ const cy = side * radius * Math.cos(theta);
41
+ const dx = x - cx;
42
+ const root = Math.sqrt(Math.max(0, radius * radius - dx * dx));
43
+ return { height: h0 + cy - side * root, gradient: side * dx / root };
44
+ }
45
+ /** Height of the whole profile at a distance along, or `null` outside it. */
46
+ export function profileHeightAt(segments, distAlong) {
47
+ for (const segment of segments) {
48
+ const x = distAlong - segment.startDistAlong;
49
+ if (x >= -JOIN_EPSILON_M && x <= segment.horizontalLength + JOIN_EPSILON_M) {
50
+ return evaluateVertical(segment, Math.min(Math.max(x, 0), segment.horizontalLength)).height;
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ function positive(value, scale, what) {
56
+ if (value === null || !Number.isFinite(value) || value <= 0)
57
+ refuseProfile(`${what} is missing or not positive`);
58
+ return value * scale;
59
+ }
60
+ /**
61
+ * A grade change at or below this is no change: two grades computed from PVIs
62
+ * on one straight line differ by rounding (3.5e-17 for 0.001, #5930 review),
63
+ * and a "curve" between them has no representable curvature.
64
+ */
65
+ const GRADE_EPSILON = 1e-9;
66
+ /**
67
+ * The segments that round off one PVI, in order — none for an equal-grade
68
+ * parabola, whose curve is the grade itself (§12.4).
69
+ */
70
+ export function curveSegments(curve, pvi, gradeIn, gradeOut, units, label) {
71
+ const scale = units.linearScaleToMeters;
72
+ const rawDelta = gradeOut - gradeIn;
73
+ const delta = Math.abs(rawDelta) <= GRADE_EPSILON ? 0 : rawDelta;
74
+ const { distAlong: d, height: h } = pvi;
75
+ switch (curve.kind) {
76
+ case 'parabolic': {
77
+ const L = positive(curve.length, scale, `${label}'s length`);
78
+ if (delta === 0)
79
+ return [];
80
+ return [{
81
+ sourceId: curve.sourceId, type: 'PARABOLICARC', startDistAlong: d - L / 2, horizontalLength: L,
82
+ startHeight: h - (gradeIn * L) / 2, startGradient: gradeIn, endGradient: gradeOut, radiusOfCurvature: L / delta,
83
+ }];
84
+ }
85
+ case 'unsymmetrical_parabolic': {
86
+ const lengthIn = positive(curve.lengthIn, scale, `${label}'s lengthIn`);
87
+ const lengthOut = positive(curve.lengthOut, scale, `${label}'s lengthOut`);
88
+ if (delta === 0)
89
+ return [];
90
+ // Two parabolas sharing height and gradient at the PVI station (§12.3).
91
+ const middle = gradeIn + (delta * lengthOut) / (lengthIn + lengthOut);
92
+ const startHeight = h - gradeIn * lengthIn;
93
+ return [
94
+ {
95
+ sourceId: `${curve.sourceId}:in`, type: 'PARABOLICARC', startDistAlong: d - lengthIn,
96
+ horizontalLength: lengthIn, startHeight, startGradient: gradeIn, endGradient: middle,
97
+ radiusOfCurvature: lengthIn / (middle - gradeIn),
98
+ },
99
+ {
100
+ sourceId: `${curve.sourceId}:out`, type: 'PARABOLICARC', startDistAlong: d, horizontalLength: lengthOut,
101
+ startHeight: startHeight + ((gradeIn + middle) / 2) * lengthIn, startGradient: middle,
102
+ endGradient: gradeOut, radiusOfCurvature: lengthOut / (gradeOut - middle),
103
+ },
104
+ ];
105
+ }
106
+ case 'circular': {
107
+ if (units.linearScaleToMeters !== units.elevationScaleToMeters) {
108
+ refuseProfile(`${label} is a circular curve in a file whose elevation unit differs from its linear unit, so its radius has no single unit`);
109
+ }
110
+ if (delta === 0)
111
+ refuseProfile(`${label} is a circular curve between two equal grades`);
112
+ // Some producers sign the radius, negative for a crest (§12.4). A sign
113
+ // that contradicts the grades is refused rather than trusted either way.
114
+ if (curve.radius !== null && curve.radius < 0 && delta > 0) {
115
+ refuseProfile(`${label} declares a negative (crest) radius, but its grades make a sag`);
116
+ }
117
+ const radius = positive(curve.radius === null ? null : Math.abs(curve.radius), scale, `${label}'s radius`);
118
+ const t1 = Math.atan(gradeIn);
119
+ const t2 = Math.atan(gradeOut);
120
+ const tangent = radius * Math.tan(Math.abs(t2 - t1) / 2);
121
+ const horizontal = radius * Math.abs(Math.sin(t2) - Math.sin(t1));
122
+ const arc = radius * Math.abs(t2 - t1);
123
+ // Radius and grades fix the curve; the declared length only confirms
124
+ // them. Producers differ on which length they mean (§12.4), so either
125
+ // agreeing is agreement, and neither is a contradiction.
126
+ const declared = positive(curve.length, scale, `${label}'s length`);
127
+ if (Math.min(Math.abs(declared - horizontal), Math.abs(declared - arc)) > ALIGNMENT_POSITION_TOLERANCE_M) {
128
+ refuseProfile(`${label} declares a length of ${declared.toFixed(3)} m, but its radius and grades give an arc length of `
129
+ + `${arc.toFixed(3)} m (horizontal length ${horizontal.toFixed(3)} m)`);
130
+ }
131
+ return [{
132
+ sourceId: curve.sourceId, type: 'CIRCULARARC', startDistAlong: d - tangent * Math.cos(t1),
133
+ horizontalLength: horizontal, startHeight: h - tangent * Math.sin(t1), startGradient: gradeIn,
134
+ endGradient: gradeOut, radiusOfCurvature: Math.sign(delta) * radius,
135
+ }];
136
+ }
137
+ default:
138
+ return refuseProfile(`${label} has an unrecognised vertical curve type`);
139
+ }
140
+ }
141
+ function grade(sourceId, from, to, a, b) {
142
+ const g = (b.height - a.height) / (b.distAlong - a.distAlong);
143
+ return {
144
+ sourceId, type: 'CONSTANTGRADIENT', startDistAlong: from, horizontalLength: to - from,
145
+ startHeight: a.height + g * (from - a.distAlong), startGradient: g, endGradient: g, radiusOfCurvature: null,
146
+ };
147
+ }
148
+ /**
149
+ * Assemble grades and curves between the PVIs. `curves[i]` holds the
150
+ * segments rounding off PVI `i` (empty for a bare grade break).
151
+ */
152
+ export function assembleProfile(profileSourceId, vertices, curves) {
153
+ const segments = [];
154
+ let cursor = vertices[0].distAlong;
155
+ const addGrade = (to, leg) => {
156
+ const length = to - cursor;
157
+ if (length < -JOIN_EPSILON_M) {
158
+ refuseProfile(`the vertical curve at PVI ${leg + 1} starts ${(-length).toFixed(3)} m before the previous one ends`);
159
+ }
160
+ if (length > JOIN_EPSILON_M) {
161
+ segments.push(grade(`${profileSourceId}:grade:${segments.length}`, cursor, to, vertices[leg - 1], vertices[leg]));
162
+ }
163
+ cursor = Math.max(cursor, to);
164
+ };
165
+ for (let index = 1; index < vertices.length; index += 1) {
166
+ const pieces = curves[index] ?? [];
167
+ if (pieces.length === 0) {
168
+ addGrade(vertices[index].distAlong, index);
169
+ continue;
170
+ }
171
+ addGrade(pieces[0].startDistAlong, index);
172
+ const last = pieces[pieces.length - 1];
173
+ const end = last.startDistAlong + last.horizontalLength;
174
+ if (end > vertices[index + 1].distAlong + JOIN_EPSILON_M) {
175
+ refuseProfile(`the vertical curve at PVI ${index + 1} ends ${(end - vertices[index + 1].distAlong).toFixed(3)} m past PVI ${index + 2}`);
176
+ }
177
+ // A join closer than the epsilon is the same point: snap the curve onto
178
+ // the cursor so no sub-micrometre gap reaches the written curve.
179
+ if (Math.abs(pieces[0].startDistAlong - cursor) <= JOIN_EPSILON_M)
180
+ pieces[0].startDistAlong = cursor;
181
+ segments.push(...pieces);
182
+ cursor = end;
183
+ }
184
+ return segments;
185
+ }
186
+ /** §12.5: joins are continuous, and the profile passes through what it must. */
187
+ export function checkProfile(segments, vertices, curves) {
188
+ const tolerance = ALIGNMENT_POSITION_TOLERANCE_M;
189
+ segments.slice(1).forEach((next, index) => {
190
+ const previous = segments[index];
191
+ const end = evaluateVertical(previous, previous.horizontalLength);
192
+ const heightGap = Math.abs(end.height - next.startHeight);
193
+ const gradeGap = Math.abs(end.gradient - next.startGradient);
194
+ const distGap = Math.abs(previous.startDistAlong + previous.horizontalLength - next.startDistAlong);
195
+ // Only a bare grade break (two grades meeting at a PVI) may change gradient.
196
+ const gradeBreak = previous.type === 'CONSTANTGRADIENT' && next.type === 'CONSTANTGRADIENT';
197
+ if (distGap > tolerance || heightGap > tolerance || (gradeGap > 1e-6 && !gradeBreak)) {
198
+ refuseProfile(`vertical segment ${index + 2} does not continue segment ${index + 1} (height gap ${heightGap.toFixed(4)} m)`);
199
+ }
200
+ });
201
+ vertices.forEach((vertex, index) => {
202
+ const pieces = curves[index] ?? [];
203
+ if (pieces.length === 0) {
204
+ const height = profileHeightAt(segments, vertex.distAlong);
205
+ if (height === null || Math.abs(height - vertex.height) > tolerance) {
206
+ refuseProfile(`the profile misses PVI ${index + 1} (${height === null ? 'not reached' : `${Math.abs(height - vertex.height).toFixed(4)} m`})`);
207
+ }
208
+ return;
209
+ }
210
+ // A curve's PVI is a tangent intersection: both tangents, extended, meet it.
211
+ const first = pieces[0];
212
+ const last = pieces[pieces.length - 1];
213
+ const lastEnd = evaluateVertical(last, last.horizontalLength);
214
+ const back = first.startHeight + first.startGradient * (vertex.distAlong - first.startDistAlong);
215
+ const ahead = lastEnd.height - last.endGradient * (last.startDistAlong + last.horizontalLength - vertex.distAlong);
216
+ if (Math.abs(back - vertex.height) > tolerance || Math.abs(ahead - vertex.height) > tolerance) {
217
+ refuseProfile(`the tangents of the vertical curve at PVI ${index + 1} do not meet at its authored point`);
218
+ }
219
+ });
220
+ }
221
+ //# sourceMappingURL=profile-geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-geometry.js","sourceRoot":"","sources":["../../src/landxml/profile-geometry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Which LandXML profiles become an `IfcAlignmentVertical`, and which are
3
+ * refused by name (mapping spec §12.2).
4
+ *
5
+ * Like `alignment-mapping.ts`, no STEP is written here, so the export dialog's
6
+ * pre-flight and the export itself give the same answer. The geometry lives in
7
+ * `profile-geometry.ts`; this module decides linkage and runs the mapping.
8
+ */
9
+ import { type AlignmentMapping } from './alignment-mapping.js';
10
+ import { type VerticalSegment } from './profile-geometry.js';
11
+ import type { LandXmlIfcUnits } from './source-types.js';
12
+ import { type StationEquationMapping } from './station-equations.js';
13
+ /** A design profile mapped onto a written alignment. */
14
+ export interface MappedProfile {
15
+ sourceId: string;
16
+ name: string;
17
+ alignmentSourceId: string;
18
+ segments: VerticalSegment[];
19
+ }
20
+ export interface RefusedProfile {
21
+ sourceId: string;
22
+ name: string;
23
+ reason: string;
24
+ }
25
+ export interface ProfileMapping {
26
+ mapped: MappedProfile[];
27
+ refused: RefusedProfile[];
28
+ }
29
+ /**
30
+ * Map every profile onto the alignments `alignmentMapping` writes, and refuse
31
+ * the rest by name (§12.2). `alignments` is the source's raw list — a
32
+ * profile's link is checked against it, not only against the written ones, so
33
+ * a profile of a refused alignment says so rather than reading as unlinked.
34
+ */
35
+ export declare function mapProfiles(profiles: readonly unknown[] | undefined, alignments: readonly unknown[] | undefined, alignmentMapping: AlignmentMapping, units: LandXmlIfcUnits | null, stationing?: ReadonlyMap<string, StationEquationMapping>): ProfileMapping;
36
+ //# sourceMappingURL=profile-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-mapping.d.ts","sourceRoot":"","sources":["../../src/landxml/profile-mapping.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,EAAqD,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAClH,OAAO,EAC4F,KAAK,eAAe,EACtH,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAuB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAK1F,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAmDD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,EAAE,UAAU,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,EACpF,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,EACjE,UAAU,GAAE,WAAW,CAAC,MAAM,EAAE,sBAAsB,CAAa,GAClE,cAAc,CAkFhB"}