landxml 0.7.1 → 0.8.1
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 +12 -0
- package/README.md +12 -4
- package/dist/index.d.mts +11 -5
- package/dist/index.d.ts +11 -5
- package/dist/index.js +26 -8
- package/dist/index.mjs +26 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# landxml
|
|
2
2
|
|
|
3
|
+
## 0.8.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e886c37: Return empty geojson and console.warn rather than throwing error when generating contours.
|
|
8
|
+
|
|
9
|
+
## 0.8.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 6a4a531: Modified "auto" behavior on LandXML files with multiple surfaces to create a combined center (rather than each surface its own cetner)
|
|
14
|
+
|
|
3
15
|
## 0.7.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -19,8 +19,6 @@ Easily transform LandXML surfaces into GeoJSON contours or GLB 3D models for use
|
|
|
19
19
|
npm install landxml
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
---
|
|
23
|
-
|
|
24
22
|
## Examples
|
|
25
23
|
|
|
26
24
|
### Get contours and a GLB model together (recommended)
|
|
@@ -36,7 +34,7 @@ const surfaces = await toGlbAndContours(
|
|
|
36
34
|
landXmlString,
|
|
37
35
|
2, // contour interval (LandXML units)
|
|
38
36
|
true, // generate outline
|
|
39
|
-
"auto", // GLB
|
|
37
|
+
"auto", // GLB center: "auto" | "origin" | [x, y]
|
|
40
38
|
);
|
|
41
39
|
|
|
42
40
|
const { glb, center, geojson, wktString, download } = surfaces[0];
|
|
@@ -59,7 +57,7 @@ const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;
|
|
|
59
57
|
|
|
60
58
|
const surfaces = await toGeojsonContours(
|
|
61
59
|
landXmlString,
|
|
62
|
-
2, // contour interval (
|
|
60
|
+
2, // contour interval (LandXML units)
|
|
63
61
|
true, // include surface outline as a z=0 feature
|
|
64
62
|
);
|
|
65
63
|
|
|
@@ -186,3 +184,13 @@ Returns `Promise<{ name, description, sourceFile, timeStamp, glb, center, downlo
|
|
|
186
184
|
| `keepOriginalGeometry` | `boolean` | `true` | Store original coordinates under `feature.properties._rawGeometry` |
|
|
187
185
|
|
|
188
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 -
|
|
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" | [
|
|
@@ -67,7 +69,7 @@ type GlbAndContoursResult = {
|
|
|
67
69
|
wktString?: string;
|
|
68
70
|
/** Binary GLB data */
|
|
69
71
|
glb: Uint8Array;
|
|
70
|
-
/** XY center used to offset
|
|
72
|
+
/** Shared XY center used to offset all GLB models from origin */
|
|
71
73
|
center: [x: number, y: number];
|
|
72
74
|
/** Convenience download trigger (browser only) */
|
|
73
75
|
download: () => void;
|
|
@@ -84,12 +86,16 @@ type GlbAndContoursResult = {
|
|
|
84
86
|
* Use this instead of calling `toGlb` + `toGeojsonContours` separately when
|
|
85
87
|
* you need both outputs, as it eliminates all redundant work.
|
|
86
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
|
+
*
|
|
87
93
|
* @param landXmlString Raw LandXML string
|
|
88
94
|
* @param contourInterval Vertical interval between contour lines (default 2)
|
|
89
95
|
* @param generateOutline When true, the outline of each surface is appended to
|
|
90
96
|
* the GeoJSON as a z=0 feature (default true)
|
|
91
|
-
* @param center GLB origin strategy: "auto" (median XY
|
|
92
|
-
* or an explicit [x, y] pair (default "auto")
|
|
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")
|
|
93
99
|
* @param surfaceId Surface name or 0-based index to process a single
|
|
94
100
|
* surface; -1 processes all surfaces (default -1)
|
|
95
101
|
*/
|
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 -
|
|
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" | [
|
|
@@ -67,7 +69,7 @@ type GlbAndContoursResult = {
|
|
|
67
69
|
wktString?: string;
|
|
68
70
|
/** Binary GLB data */
|
|
69
71
|
glb: Uint8Array;
|
|
70
|
-
/** XY center used to offset
|
|
72
|
+
/** Shared XY center used to offset all GLB models from origin */
|
|
71
73
|
center: [x: number, y: number];
|
|
72
74
|
/** Convenience download trigger (browser only) */
|
|
73
75
|
download: () => void;
|
|
@@ -84,12 +86,16 @@ type GlbAndContoursResult = {
|
|
|
84
86
|
* Use this instead of calling `toGlb` + `toGeojsonContours` separately when
|
|
85
87
|
* you need both outputs, as it eliminates all redundant work.
|
|
86
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
|
+
*
|
|
87
93
|
* @param landXmlString Raw LandXML string
|
|
88
94
|
* @param contourInterval Vertical interval between contour lines (default 2)
|
|
89
95
|
* @param generateOutline When true, the outline of each surface is appended to
|
|
90
96
|
* the GeoJSON as a z=0 feature (default true)
|
|
91
|
-
* @param center GLB origin strategy: "auto" (median XY
|
|
92
|
-
* or an explicit [x, y] pair (default "auto")
|
|
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")
|
|
93
99
|
* @param surfaceId Surface name or 0-based index to process a single
|
|
94
100
|
* surface; -1 processes all surfaces (default -1)
|
|
95
101
|
*/
|
package/dist/index.js
CHANGED
|
@@ -287,19 +287,27 @@ var parse_xml_default = parseXML;
|
|
|
287
287
|
|
|
288
288
|
// src/public/to-glb.ts
|
|
289
289
|
var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(null, null, function* () {
|
|
290
|
-
const requestedCenter = center == "origin" ? [0, 0] : center === "auto" ? void 0 : center;
|
|
291
290
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
291
|
+
let resolvedCenter;
|
|
292
|
+
if (center === "origin") {
|
|
293
|
+
resolvedCenter = [0, 0];
|
|
294
|
+
} else if (center === "auto") {
|
|
295
|
+
const allPoints = requestedParsedSurfaces.flatMap((s) => s.surfaceDefinition.points);
|
|
296
|
+
resolvedCenter = findXYAxisMedians(allPoints);
|
|
297
|
+
} else {
|
|
298
|
+
resolvedCenter = center;
|
|
299
|
+
}
|
|
292
300
|
const glbs = yield Promise.all(
|
|
293
301
|
requestedParsedSurfaces.map(
|
|
294
302
|
(surface) => new Promise((resolve, reject) => __async(null, null, function* () {
|
|
295
303
|
try {
|
|
296
|
-
const { glb
|
|
304
|
+
const { glb } = yield get_glb_default(surface, resolvedCenter);
|
|
297
305
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
298
306
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
299
307
|
glb,
|
|
300
|
-
center:
|
|
308
|
+
center: resolvedCenter,
|
|
301
309
|
download: () => {
|
|
302
|
-
download_glb_default(glb, surface.name.replace(/\.xml$/, `${JSON.stringify(
|
|
310
|
+
download_glb_default(glb, surface.name.replace(/\.xml$/, `${JSON.stringify(resolvedCenter)}.glb`));
|
|
303
311
|
}
|
|
304
312
|
}));
|
|
305
313
|
} catch (e) {
|
|
@@ -440,7 +448,8 @@ var contourElevations = (minElevation, maxElevation, interval) => {
|
|
|
440
448
|
throw new Error("Contour elevations have to be finite numbers");
|
|
441
449
|
}
|
|
442
450
|
if (minElevation + interval > maxElevation) {
|
|
443
|
-
|
|
451
|
+
console.warn(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
452
|
+
return [];
|
|
444
453
|
}
|
|
445
454
|
const elevations = [];
|
|
446
455
|
const firstStep = Math.ceil(minElevation / interval);
|
|
@@ -493,6 +502,7 @@ var bucketTrianglesByElevation = (triangles, elevations, interval) => {
|
|
|
493
502
|
var getContours = (data, interval = 2, precomputed) => __async(null, null, function* () {
|
|
494
503
|
const { triangles, minElevation, maxElevation } = precomputed != null ? precomputed : precomputeSurfaceData(data);
|
|
495
504
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
505
|
+
if (elevations.length === 0) return constructGeojson([]);
|
|
496
506
|
const trianglesByElevation = bucketTrianglesByElevation(triangles, elevations, interval);
|
|
497
507
|
const elevationPolylines = yield Promise.all(
|
|
498
508
|
elevations.map(
|
|
@@ -590,13 +600,21 @@ var reproject_geojson_default = reprojectGeoJson;
|
|
|
590
600
|
|
|
591
601
|
// src/public/to-glb-and-contours.ts
|
|
592
602
|
var toGlbAndContours = (landXmlString, contourInterval = 2, generateOutline = true, center = "auto", surfaceId = -1) => __async(null, null, function* () {
|
|
593
|
-
const requestedCenter = center === "origin" ? [0, 0] : center === "auto" ? void 0 : center;
|
|
594
603
|
const requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
604
|
+
let resolvedCenter;
|
|
605
|
+
if (center === "origin") {
|
|
606
|
+
resolvedCenter = [0, 0];
|
|
607
|
+
} else if (center === "auto") {
|
|
608
|
+
const allPoints = requestedParsedSurfaces.flatMap((s) => s.surfaceDefinition.points);
|
|
609
|
+
resolvedCenter = findXYAxisMedians(allPoints);
|
|
610
|
+
} else {
|
|
611
|
+
resolvedCenter = center;
|
|
612
|
+
}
|
|
595
613
|
const results = yield Promise.all(
|
|
596
614
|
requestedParsedSurfaces.map((surface) => __async(null, null, function* () {
|
|
597
615
|
const precomputed = precomputeSurfaceData(surface);
|
|
598
|
-
const [{ glb
|
|
599
|
-
get_glb_default(surface,
|
|
616
|
+
const [{ glb }, geojson] = yield Promise.all([
|
|
617
|
+
get_glb_default(surface, resolvedCenter),
|
|
600
618
|
get_contours_default(surface, contourInterval, precomputed)
|
|
601
619
|
]);
|
|
602
620
|
if (generateOutline) {
|
package/dist/index.mjs
CHANGED
|
@@ -250,19 +250,27 @@ var parse_xml_default = parseXML;
|
|
|
250
250
|
|
|
251
251
|
// src/public/to-glb.ts
|
|
252
252
|
var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(null, null, function* () {
|
|
253
|
-
const requestedCenter = center == "origin" ? [0, 0] : center === "auto" ? void 0 : center;
|
|
254
253
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
254
|
+
let resolvedCenter;
|
|
255
|
+
if (center === "origin") {
|
|
256
|
+
resolvedCenter = [0, 0];
|
|
257
|
+
} else if (center === "auto") {
|
|
258
|
+
const allPoints = requestedParsedSurfaces.flatMap((s) => s.surfaceDefinition.points);
|
|
259
|
+
resolvedCenter = findXYAxisMedians(allPoints);
|
|
260
|
+
} else {
|
|
261
|
+
resolvedCenter = center;
|
|
262
|
+
}
|
|
255
263
|
const glbs = yield Promise.all(
|
|
256
264
|
requestedParsedSurfaces.map(
|
|
257
265
|
(surface) => new Promise((resolve, reject) => __async(null, null, function* () {
|
|
258
266
|
try {
|
|
259
|
-
const { glb
|
|
267
|
+
const { glb } = yield get_glb_default(surface, resolvedCenter);
|
|
260
268
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
261
269
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
262
270
|
glb,
|
|
263
|
-
center:
|
|
271
|
+
center: resolvedCenter,
|
|
264
272
|
download: () => {
|
|
265
|
-
download_glb_default(glb, surface.name.replace(/\.xml$/, `${JSON.stringify(
|
|
273
|
+
download_glb_default(glb, surface.name.replace(/\.xml$/, `${JSON.stringify(resolvedCenter)}.glb`));
|
|
266
274
|
}
|
|
267
275
|
}));
|
|
268
276
|
} catch (e) {
|
|
@@ -403,7 +411,8 @@ var contourElevations = (minElevation, maxElevation, interval) => {
|
|
|
403
411
|
throw new Error("Contour elevations have to be finite numbers");
|
|
404
412
|
}
|
|
405
413
|
if (minElevation + interval > maxElevation) {
|
|
406
|
-
|
|
414
|
+
console.warn(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
415
|
+
return [];
|
|
407
416
|
}
|
|
408
417
|
const elevations = [];
|
|
409
418
|
const firstStep = Math.ceil(minElevation / interval);
|
|
@@ -456,6 +465,7 @@ var bucketTrianglesByElevation = (triangles, elevations, interval) => {
|
|
|
456
465
|
var getContours = (data, interval = 2, precomputed) => __async(null, null, function* () {
|
|
457
466
|
const { triangles, minElevation, maxElevation } = precomputed != null ? precomputed : precomputeSurfaceData(data);
|
|
458
467
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
468
|
+
if (elevations.length === 0) return constructGeojson([]);
|
|
459
469
|
const trianglesByElevation = bucketTrianglesByElevation(triangles, elevations, interval);
|
|
460
470
|
const elevationPolylines = yield Promise.all(
|
|
461
471
|
elevations.map(
|
|
@@ -553,13 +563,21 @@ var reproject_geojson_default = reprojectGeoJson;
|
|
|
553
563
|
|
|
554
564
|
// src/public/to-glb-and-contours.ts
|
|
555
565
|
var toGlbAndContours = (landXmlString, contourInterval = 2, generateOutline = true, center = "auto", surfaceId = -1) => __async(null, null, function* () {
|
|
556
|
-
const requestedCenter = center === "origin" ? [0, 0] : center === "auto" ? void 0 : center;
|
|
557
566
|
const requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
567
|
+
let resolvedCenter;
|
|
568
|
+
if (center === "origin") {
|
|
569
|
+
resolvedCenter = [0, 0];
|
|
570
|
+
} else if (center === "auto") {
|
|
571
|
+
const allPoints = requestedParsedSurfaces.flatMap((s) => s.surfaceDefinition.points);
|
|
572
|
+
resolvedCenter = findXYAxisMedians(allPoints);
|
|
573
|
+
} else {
|
|
574
|
+
resolvedCenter = center;
|
|
575
|
+
}
|
|
558
576
|
const results = yield Promise.all(
|
|
559
577
|
requestedParsedSurfaces.map((surface) => __async(null, null, function* () {
|
|
560
578
|
const precomputed = precomputeSurfaceData(surface);
|
|
561
|
-
const [{ glb
|
|
562
|
-
get_glb_default(surface,
|
|
579
|
+
const [{ glb }, geojson] = yield Promise.all([
|
|
580
|
+
get_glb_default(surface, resolvedCenter),
|
|
563
581
|
get_contours_default(surface, contourInterval, precomputed)
|
|
564
582
|
]);
|
|
565
583
|
if (generateOutline) {
|