landxml 0.6.6 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # landxml
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6a4a531: Modified "auto" behavior on LandXML files with multiple surfaces to create a combined center (rather than each surface its own cetner)
8
+
9
+ ## 0.7.1
10
+
11
+ ### Patch Changes
12
+
13
+ - b200147: Updated publish workflow
14
+ - eec1ceb: Struggling with CI/CD #2
15
+ - b80d579: Struggling with CI/CD #1
16
+
17
+ ## 0.7.0
18
+
19
+ ### Minor Changes
20
+
21
+ - 23cc669: Ai performance optimizations
22
+
3
23
  ## 0.6.6
4
24
 
5
25
  ### Patch Changes
package/README.md CHANGED
@@ -1,48 +1,196 @@
1
- # LandXML Parser for Contour Geojson and 3D Models
1
+ # LandXML Parser for Contour GeoJSON and 3D Models
2
2
 
3
- Easily transform LandXML surfaces into stunning GeoJSON contours or immersive GLB models to explore within threeJS or any popular 3D software.
3
+ Easily transform LandXML surfaces into GeoJSON contours or GLB 3D models for use in ThreeJS, Cesium, QGIS, or any popular 3D/GIS software.
4
4
 
5
- ### Features
5
+ ---
6
6
 
7
- - **toGlb:** Generate GLB models from LandXML surfaces.
8
- - **toGeojsonContours:** Convert LandXML data into detailed contour GeoJSON representations.
9
- - **reprojectGeojson:** Effortlessly reproject GeoJSON data to desired projection using `proj4`
7
+ ## Features
10
8
 
11
- ### Example: Retrieve GeoJSON Contours
9
+ - **`toGlbAndContours`** Generate both a GLB model and GeoJSON contours in a single pass (fastest when you need both outputs).
10
+ - **`toGlb`** — Generate a GLB 3D model from LandXML surfaces.
11
+ - **`toGeojsonContours`** — Convert LandXML surfaces into contour line GeoJSON.
12
+ - **`reprojectGeoJson`** — Reproject GeoJSON coordinates to any projection using `proj4`.
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install landxml
20
+ ```
21
+
22
+ ## Examples
23
+
24
+ ### Get contours and a GLB model together (recommended)
25
+
26
+ When you need both outputs, use `toGlbAndContours` — it parses the XML once and shares computed data between both outputs, making it significantly faster than calling `toGlb` and `toGeojsonContours` separately.
27
+
28
+ ```typescript
29
+ import { toGlbAndContours, reprojectGeoJson } from "landxml";
30
+
31
+ const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;
32
+
33
+ const surfaces = await toGlbAndContours(
34
+ landXmlString,
35
+ 2, // contour interval (LandXML units)
36
+ true, // generate outline
37
+ "auto", // GLB center: "auto" | "origin" | [x, y]
38
+ );
39
+
40
+ const { glb, center, geojson, wktString, download } = surfaces[0];
41
+
42
+ // Download the GLB file in the browser
43
+ download();
44
+
45
+ // Reproject contours from the LandXML CRS to WGS84
46
+ const reprojected = reprojectGeoJson(geojson, wktString, "WGS84", false);
47
+ ```
48
+
49
+ ---
50
+
51
+ ### Get GeoJSON contours only
12
52
 
13
53
  ```typescript
14
54
  import { toGeojsonContours, reprojectGeoJson } from "landxml";
15
55
 
16
- const loadGeojson = async () => {
17
- const landXmlString = "<?xml version="1.0"?>...</LandXML>";
18
- const contourInterval = 2;
19
- const geojsonSurfaces = await toGeojsonContours(landXmlString, contourInterval);
56
+ const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;
57
+
58
+ const surfaces = await toGeojsonContours(
59
+ landXmlString,
60
+ 2, // contour interval (LandXML units)
61
+ true, // include surface outline as a z=0 feature
62
+ );
63
+
64
+ const { geojson, wktString } = surfaces[0];
20
65
 
21
- // Retrieve geojson with raw LandXML coordinates
22
- let { geojson, wktString } = geojsonSurfaces[0];
66
+ // Reproject from the LandXML coordinate system to WGS84 for web mapping
67
+ const reprojected = reprojectGeoJson(geojson, wktString ?? "WGS84", "WGS84", false);
23
68
 
24
- // Reproject GeoJSON to a desired coordinate system (e.g., WGS84)
25
- const targetCoordinateSystem = wktString || "WGS84";
26
- const keepOriginalGeometryAsFeatureProperties = false;
27
- return reprojectGeoJson(geojson, wktString, targetCoordinateSystem, keepOriginalGeometryAsFeatureProperties);
28
- }
69
+ console.log(reprojected.features.length); // number of contour + outline features
29
70
  ```
30
71
 
31
- ### Example: Convert to GLB 3D model
72
+ ---
73
+
74
+ ### Convert to a GLB 3D model
32
75
 
33
76
  ```typescript
34
77
  import { toGlb } from "landxml";
35
78
 
36
- const LandXml2GlbModel = async () => {
37
- const landXmlString = "<?xml version="1.0"?>...</LandXML>";
79
+ const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;
80
+
81
+ const surfaces = await toGlb(
82
+ landXmlString,
83
+ "auto", // centre strategy: "auto" | "origin" | [x, y]
84
+ );
85
+
86
+ const { glb, center, download } = surfaces[0];
87
+
88
+ // Trigger a browser download of the .glb file
89
+ download();
90
+
91
+ // Or use the raw binary (Uint8Array) directly — e.g. load into Three.js
92
+ const loader = new GLTFLoader();
93
+ loader.parse(glb.buffer, "", (gltf) => {
94
+ scene.add(gltf.scene);
95
+ });
96
+ ```
97
+
98
+ ---
99
+
100
+ ### Work with a specific surface in a multi-surface LandXML
101
+
102
+ LandXML files can contain multiple surfaces. Use `surfaceId` to select one by name or by index.
103
+
104
+ ```typescript
105
+ import { toGeojsonContours } from "landxml";
38
106
 
39
- // Define how the model's origin should be positioned (options: "origin" | "auto" | [x: number, y: number])
40
- const center = "auto";
41
- const glbSurfaces = await toGlb(landXmlString, center);
107
+ const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;
42
108
 
43
- let { download, glb } = glbSurfaces[0];
44
- download()
109
+ // By name
110
+ const byName = await toGeojsonContours(landXmlString, 2, true, "ExistingGround");
45
111
 
46
- // Alternatively, process the raw binary data from the 'glb' variable (Uint8Array)
47
- }
112
+ // By index (0-based)
113
+ const byIndex = await toGeojsonContours(landXmlString, 2, true, 1);
48
114
  ```
115
+
116
+ ---
117
+
118
+ ### Reproject GeoJSON
119
+
120
+ `reprojectGeoJson` wraps `proj4` and works with both WKT strings (exported by Civil 3D when a drawing is geo-referenced) and standard proj4 definition strings.
121
+
122
+ ```typescript
123
+ import { reprojectGeoJson } from "landxml";
124
+
125
+ // wktString is available on every surface returned by toGeojsonContours / toGlbAndContours
126
+ const reprojected = reprojectGeoJson(
127
+ geojson,
128
+ wktString, // source CRS — WKT or proj4 string
129
+ "WGS84", // target CRS (default)
130
+ true, // keep original geometry as feature property "_rawGeometry"
131
+ );
132
+ ```
133
+
134
+ ---
135
+
136
+ ## API Reference
137
+
138
+ ### `toGlbAndContours(landXmlString, contourInterval?, generateOutline?, center?, surfaceId?)`
139
+
140
+ | Parameter | Type | Default | Description |
141
+ | ----------------- | ------------------------------ | -------- | -------------------------------------------------- |
142
+ | `landXmlString` | `string` | — | Raw LandXML XML string |
143
+ | `contourInterval` | `number` | `2` | Vertical interval between contour lines |
144
+ | `generateOutline` | `boolean` | `true` | Append surface boundary as a `z=0` GeoJSON feature |
145
+ | `center` | `"auto" \| "origin" \| [x, y]` | `"auto"` | GLB model origin strategy |
146
+ | `surfaceId` | `string \| number` | `-1` | Surface name or index; `-1` returns all surfaces |
147
+
148
+ Returns `Promise<GlbAndContoursResult[]>` where each element contains `name`, `description`, `sourceFile`, `timeStamp`, `wktString`, `glb`, `center`, `download`, and `geojson`.
149
+
150
+ ---
151
+
152
+ ### `toGeojsonContours(landXmlString, contourInterval?, generateOutline?, surfaceId?)`
153
+
154
+ | Parameter | Type | Default | Description |
155
+ | ----------------- | ------------------ | ------- | -------------------------------------------------- |
156
+ | `landXmlString` | `string` | — | Raw LandXML XML string |
157
+ | `contourInterval` | `number` | `2` | Vertical interval between contour lines |
158
+ | `generateOutline` | `boolean` | `true` | Append surface boundary as a `z=0` GeoJSON feature |
159
+ | `surfaceId` | `string \| number` | `-1` | Surface name or index; `-1` returns all surfaces |
160
+
161
+ Returns `Promise<{ name, description, sourceFile, timeStamp, wktString?, geojson }[]>`.
162
+
163
+ ---
164
+
165
+ ### `toGlb(landXmlString, center?, surfaceId?)`
166
+
167
+ | Parameter | Type | Default | Description |
168
+ | --------------- | ------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------- |
169
+ | `landXmlString` | `string` | — | Raw LandXML XML string |
170
+ | `center` | `"auto" \| "origin" \| [x, y]` | `"auto"` | GLB model origin strategy. 3D models are sensitive to large coordinates — `"auto"` offsets to the XY median |
171
+ | `surfaceId` | `string \| number` | `-1` | Surface name or index; `-1` returns all surfaces |
172
+
173
+ Returns `Promise<{ name, description, sourceFile, timeStamp, glb, center, download }[]>`.
174
+
175
+ ---
176
+
177
+ ### `reprojectGeoJson(geojson, sourceProjection, targetProjection?, keepOriginalGeometry?)`
178
+
179
+ | Parameter | Type | Default | Description |
180
+ | ---------------------- | ------------------- | --------- | ------------------------------------------------------------------ |
181
+ | `geojson` | `FeatureCollection` | — | GeoJSON to reproject |
182
+ | `sourceProjection` | `string` | — | Proj4 or WKT string of the source CRS |
183
+ | `targetProjection` | `string` | `"WGS84"` | Proj4 or WKT string of the target CRS |
184
+ | `keepOriginalGeometry` | `boolean` | `true` | Store original coordinates under `feature.properties._rawGeometry` |
185
+
186
+ Returns the mutated `FeatureCollection` with updated coordinates.
187
+
188
+ ---
189
+
190
+ ## Multi-surface center behaviour
191
+
192
+ When a LandXML file contains multiple surfaces and `center` is set to `"auto"` (the default), the package computes a **single shared median center** across all surfaces' points. Every GLB produced in that call is offset by the same origin, so the surfaces remain correctly positioned relative to each other in your 3D scene. This happens automatically — no extra configuration is needed.
193
+
194
+ If you need each surface to be individually centered (e.g. you are processing them in isolation), pass an explicit `[x, y]` pair instead.
195
+
196
+ ---
package/dist/index.d.mts CHANGED
@@ -3,7 +3,9 @@ import { FeatureCollection, LineString } from 'geojson';
3
3
 
4
4
  /**
5
5
  * @param landXmlString
6
- * @param center 3D models don't work well when they're far from origin (coordinate `[0,0,0]`), therefore by default your center is moved to the median of x and y axis of your surface
6
+ * @param center 3D models don't work well when they're far from origin (coordinate `[0,0,0]`), therefore by default your center is moved to the median of x and y axis of your surface.
7
+ * When processing multiple surfaces with `"auto"`, a **single shared center** is computed
8
+ * from all surfaces combined so they remain correctly positioned relative to each other.
7
9
  * @param surfaceId Surface name or index if your LandXML contains multiple surfaces. By default all surfaces are converted and returns an array of glb Uint8Array
8
10
  * @returns {Object[]} glbs - Array of processed glbs (will also return an array when just one surface has been processed)
9
11
  * @returns {string} glbs[].name - Name of surface as defined in LandXML
@@ -11,7 +13,7 @@ import { FeatureCollection, LineString } from 'geojson';
11
13
  * @returns {string} glbs[].sourceFile - Source file of where the LandXML was generated from.
12
14
  * @returns {string} glbs[].timeStamp - Timestamp of when the surface was exported into LandXML
13
15
  * @returns {Uint8Array} glbs[].glb - Uint8Array binary data of glb
14
- * @returns {[number, number]} glbs[].center - Offset center of the processed glb
16
+ * @returns {[number, number]} glbs[].center - Shared offset center applied to all GLBs
15
17
  * @returns {function(): void} glbs[].download - Convenient way to download the GLB, within the filename the new center will be appended.
16
18
  */
17
19
  declare const toGlb: (landXmlString: string, center?: "auto" | "origin" | [
@@ -59,4 +61,73 @@ declare const toGeojsonContours: (landXmlString: string, contourInterval?: numbe
59
61
  */
60
62
  declare const reprojectGeoJson: (geojson: FeatureCollection, sourceProjection: string, targetProjection?: string, keepOriginalGeometryAsFeatureProperty?: boolean) => FeatureCollection<geojson.Geometry, geojson.GeoJsonProperties>;
61
63
 
62
- export { reprojectGeoJson, toGeojsonContours, toGlb };
64
+ type GlbAndContoursResult = {
65
+ name: string;
66
+ description: string;
67
+ sourceFile: string;
68
+ timeStamp: string;
69
+ wktString?: string;
70
+ /** Binary GLB data */
71
+ glb: Uint8Array;
72
+ /** Shared XY center used to offset all GLB models from origin */
73
+ center: [x: number, y: number];
74
+ /** Convenience download trigger (browser only) */
75
+ download: () => void;
76
+ /** Contour lines + optional outline as a GeoJSON FeatureCollection */
77
+ geojson: FeatureCollection<LineString, {
78
+ z: number;
79
+ }>;
80
+ };
81
+ /**
82
+ * Converts a LandXML string into **both** a GLB 3-D model and GeoJSON contour
83
+ * lines in a single pass — the XML is parsed once and the triangle/elevation
84
+ * data computed once and shared between both outputs.
85
+ *
86
+ * Use this instead of calling `toGlb` + `toGeojsonContours` separately when
87
+ * you need both outputs, as it eliminates all redundant work.
88
+ *
89
+ * When processing multiple surfaces with `center: "auto"`, a **single shared
90
+ * center** is computed from all surfaces combined, so every GLB is offset by
91
+ * the same origin and surfaces remain correctly positioned relative to each other.
92
+ *
93
+ * @param landXmlString Raw LandXML string
94
+ * @param contourInterval Vertical interval between contour lines (default 2)
95
+ * @param generateOutline When true, the outline of each surface is appended to
96
+ * the GeoJSON as a z=0 feature (default true)
97
+ * @param center GLB origin strategy: "auto" (combined median XY of all surfaces),
98
+ * "origin" ([0,0]), or an explicit [x, y] pair (default "auto")
99
+ * @param surfaceId Surface name or 0-based index to process a single
100
+ * surface; -1 processes all surfaces (default -1)
101
+ */
102
+ declare const toGlbAndContours: (landXmlString: string, contourInterval?: number, generateOutline?: boolean, center?: "auto" | "origin" | [
103
+ x: number,
104
+ y: number
105
+ ], surfaceId?: string | number) => Promise<GlbAndContoursResult[]>;
106
+
107
+ type ParsedSurface = {
108
+ sourceFile: string;
109
+ timeStamp: string;
110
+ name: string;
111
+ description: string;
112
+ wktString?: string;
113
+ surfaceDefinition: {
114
+ points: [x: number, y: number, z: number][];
115
+ faces: [vertIndexA: number, vertIndexB: number, vertIndexC: number][];
116
+ faceNeighbors: [faceIndex: number, faceIndex: number, faceIndex: number][];
117
+ };
118
+ };
119
+
120
+ /**
121
+ * Derives the triangle list and elevation range from a ParsedSurface.
122
+ * Call this once and pass the result to both getContours() and getGlb() when
123
+ * you need both outputs for the same surface — avoids double-traversal of the
124
+ * (potentially large) faces/points arrays.
125
+ */
126
+ type PrecomputedSurfaceData = {
127
+ triangles: [x: number, y: number, z: number][][];
128
+ minElevation: number;
129
+ maxElevation: number;
130
+ };
131
+ declare const precomputeSurfaceData: (data: ParsedSurface) => PrecomputedSurfaceData;
132
+
133
+ export { type GlbAndContoursResult, type PrecomputedSurfaceData, precomputeSurfaceData, reprojectGeoJson, toGeojsonContours, toGlb, toGlbAndContours };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,9 @@ import { FeatureCollection, LineString } from 'geojson';
3
3
 
4
4
  /**
5
5
  * @param landXmlString
6
- * @param center 3D models don't work well when they're far from origin (coordinate `[0,0,0]`), therefore by default your center is moved to the median of x and y axis of your surface
6
+ * @param center 3D models don't work well when they're far from origin (coordinate `[0,0,0]`), therefore by default your center is moved to the median of x and y axis of your surface.
7
+ * When processing multiple surfaces with `"auto"`, a **single shared center** is computed
8
+ * from all surfaces combined so they remain correctly positioned relative to each other.
7
9
  * @param surfaceId Surface name or index if your LandXML contains multiple surfaces. By default all surfaces are converted and returns an array of glb Uint8Array
8
10
  * @returns {Object[]} glbs - Array of processed glbs (will also return an array when just one surface has been processed)
9
11
  * @returns {string} glbs[].name - Name of surface as defined in LandXML
@@ -11,7 +13,7 @@ import { FeatureCollection, LineString } from 'geojson';
11
13
  * @returns {string} glbs[].sourceFile - Source file of where the LandXML was generated from.
12
14
  * @returns {string} glbs[].timeStamp - Timestamp of when the surface was exported into LandXML
13
15
  * @returns {Uint8Array} glbs[].glb - Uint8Array binary data of glb
14
- * @returns {[number, number]} glbs[].center - Offset center of the processed glb
16
+ * @returns {[number, number]} glbs[].center - Shared offset center applied to all GLBs
15
17
  * @returns {function(): void} glbs[].download - Convenient way to download the GLB, within the filename the new center will be appended.
16
18
  */
17
19
  declare const toGlb: (landXmlString: string, center?: "auto" | "origin" | [
@@ -59,4 +61,73 @@ declare const toGeojsonContours: (landXmlString: string, contourInterval?: numbe
59
61
  */
60
62
  declare const reprojectGeoJson: (geojson: FeatureCollection, sourceProjection: string, targetProjection?: string, keepOriginalGeometryAsFeatureProperty?: boolean) => FeatureCollection<geojson.Geometry, geojson.GeoJsonProperties>;
61
63
 
62
- export { reprojectGeoJson, toGeojsonContours, toGlb };
64
+ type GlbAndContoursResult = {
65
+ name: string;
66
+ description: string;
67
+ sourceFile: string;
68
+ timeStamp: string;
69
+ wktString?: string;
70
+ /** Binary GLB data */
71
+ glb: Uint8Array;
72
+ /** Shared XY center used to offset all GLB models from origin */
73
+ center: [x: number, y: number];
74
+ /** Convenience download trigger (browser only) */
75
+ download: () => void;
76
+ /** Contour lines + optional outline as a GeoJSON FeatureCollection */
77
+ geojson: FeatureCollection<LineString, {
78
+ z: number;
79
+ }>;
80
+ };
81
+ /**
82
+ * Converts a LandXML string into **both** a GLB 3-D model and GeoJSON contour
83
+ * lines in a single pass — the XML is parsed once and the triangle/elevation
84
+ * data computed once and shared between both outputs.
85
+ *
86
+ * Use this instead of calling `toGlb` + `toGeojsonContours` separately when
87
+ * you need both outputs, as it eliminates all redundant work.
88
+ *
89
+ * When processing multiple surfaces with `center: "auto"`, a **single shared
90
+ * center** is computed from all surfaces combined, so every GLB is offset by
91
+ * the same origin and surfaces remain correctly positioned relative to each other.
92
+ *
93
+ * @param landXmlString Raw LandXML string
94
+ * @param contourInterval Vertical interval between contour lines (default 2)
95
+ * @param generateOutline When true, the outline of each surface is appended to
96
+ * the GeoJSON as a z=0 feature (default true)
97
+ * @param center GLB origin strategy: "auto" (combined median XY of all surfaces),
98
+ * "origin" ([0,0]), or an explicit [x, y] pair (default "auto")
99
+ * @param surfaceId Surface name or 0-based index to process a single
100
+ * surface; -1 processes all surfaces (default -1)
101
+ */
102
+ declare const toGlbAndContours: (landXmlString: string, contourInterval?: number, generateOutline?: boolean, center?: "auto" | "origin" | [
103
+ x: number,
104
+ y: number
105
+ ], surfaceId?: string | number) => Promise<GlbAndContoursResult[]>;
106
+
107
+ type ParsedSurface = {
108
+ sourceFile: string;
109
+ timeStamp: string;
110
+ name: string;
111
+ description: string;
112
+ wktString?: string;
113
+ surfaceDefinition: {
114
+ points: [x: number, y: number, z: number][];
115
+ faces: [vertIndexA: number, vertIndexB: number, vertIndexC: number][];
116
+ faceNeighbors: [faceIndex: number, faceIndex: number, faceIndex: number][];
117
+ };
118
+ };
119
+
120
+ /**
121
+ * Derives the triangle list and elevation range from a ParsedSurface.
122
+ * Call this once and pass the result to both getContours() and getGlb() when
123
+ * you need both outputs for the same surface — avoids double-traversal of the
124
+ * (potentially large) faces/points arrays.
125
+ */
126
+ type PrecomputedSurfaceData = {
127
+ triangles: [x: number, y: number, z: number][][];
128
+ minElevation: number;
129
+ maxElevation: number;
130
+ };
131
+ declare const precomputeSurfaceData: (data: ParsedSurface) => PrecomputedSurfaceData;
132
+
133
+ export { type GlbAndContoursResult, type PrecomputedSurfaceData, precomputeSurfaceData, reprojectGeoJson, toGeojsonContours, toGlb, toGlbAndContours };