landxml 0.4.1 → 0.5.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 +17 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +74 -19
- package/dist/index.mjs +74 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# landxml
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- df95e64: Added ability to generate surface outline geojson
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- df95e64: LandXML Face with with "i" attribute equal to "1" will now be correctly ignored
|
|
12
|
+
- df95e64: Improved contour generation algorithm
|
|
13
|
+
|
|
14
|
+
## 0.4.2
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- fbd9682: Contour elevations from surface min/max elevations and increment are now calculated correctly (bugfix).
|
|
19
|
+
|
|
3
20
|
## 0.4.1
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -39,7 +39,7 @@ declare const toGlb: (landXmlString: string, center?: "auto" | "origin" | [
|
|
|
39
39
|
* @returns {string} surfaceContours[].wktString - WKT string of LandXML coordinate system projection
|
|
40
40
|
* @returns {Object} surfaceContours[].geojson - Geojson feature collection of contour lines
|
|
41
41
|
*/
|
|
42
|
-
declare const toGeojsonContours: (landXmlString: string, contourInterval?: number, surfaceId?: string | number) => Promise<{
|
|
42
|
+
declare const toGeojsonContours: (landXmlString: string, contourInterval?: number, generateOutline?: boolean, surfaceId?: string | number) => Promise<{
|
|
43
43
|
name: string;
|
|
44
44
|
description: string;
|
|
45
45
|
sourceFile: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ declare const toGlb: (landXmlString: string, center?: "auto" | "origin" | [
|
|
|
39
39
|
* @returns {string} surfaceContours[].wktString - WKT string of LandXML coordinate system projection
|
|
40
40
|
* @returns {Object} surfaceContours[].geojson - Geojson feature collection of contour lines
|
|
41
41
|
*/
|
|
42
|
-
declare const toGeojsonContours: (landXmlString: string, contourInterval?: number, surfaceId?: string | number) => Promise<{
|
|
42
|
+
declare const toGeojsonContours: (landXmlString: string, contourInterval?: number, generateOutline?: boolean, surfaceId?: string | number) => Promise<{
|
|
43
43
|
name: string;
|
|
44
44
|
description: string;
|
|
45
45
|
sourceFile: string;
|
package/dist/index.js
CHANGED
|
@@ -164,14 +164,16 @@ var parseXML = (xmlString) => __async(void 0, null, function* () {
|
|
|
164
164
|
points.push([x, y, z]);
|
|
165
165
|
pointIdMap[attr.id] = points.length - 1;
|
|
166
166
|
}, []);
|
|
167
|
-
faces = surface.Definition.Faces.F.
|
|
168
|
-
const { content } = face;
|
|
167
|
+
faces = surface.Definition.Faces.F.reduce((faceList, face) => {
|
|
168
|
+
const { attr, content } = face;
|
|
169
|
+
if (attr.i === "1")
|
|
170
|
+
return faceList;
|
|
169
171
|
const [a, b, c] = content.split(" ").map((v) => pointIdMap[v]);
|
|
170
172
|
if ([a, b, c].filter((v) => typeof v === "undefined").length > 0) {
|
|
171
173
|
throw `Invalid LandXML. A face is referencing a point that doesn't exist. Face is referencing points: ${content}`;
|
|
172
174
|
}
|
|
173
|
-
return [a, b, c];
|
|
174
|
-
});
|
|
175
|
+
return faceList.concat([[a, b, c]]);
|
|
176
|
+
}, []);
|
|
175
177
|
return {
|
|
176
178
|
sourceFile: LandXML.Project.attr.name,
|
|
177
179
|
timeStamp: LandXML.Application.attr.timeStamp,
|
|
@@ -220,11 +222,14 @@ var contourLineOnFace = (face, z) => {
|
|
|
220
222
|
for (let i = 0; i < face.length; i++) {
|
|
221
223
|
let vertex1 = face[i];
|
|
222
224
|
let vertex2 = face[(i + 1) % face.length];
|
|
223
|
-
if (vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) {
|
|
225
|
+
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
224
226
|
let t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
225
227
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
226
228
|
}
|
|
227
229
|
}
|
|
230
|
+
if (line.length > 2) {
|
|
231
|
+
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
232
|
+
}
|
|
228
233
|
return line.length > 0 ? line : void 0;
|
|
229
234
|
};
|
|
230
235
|
var linesToPolyLines = (lineSegments) => {
|
|
@@ -281,11 +286,14 @@ var linesToPolyLines = (lineSegments) => {
|
|
|
281
286
|
return polylines;
|
|
282
287
|
};
|
|
283
288
|
var contourElevations = (minElevation, maxElevation, interval) => {
|
|
284
|
-
if (maxElevation
|
|
289
|
+
if (!Number.isFinite(minElevation) || !Number.isFinite(maxElevation) || !Number.isFinite(interval)) {
|
|
285
290
|
throw new Error("Contour elevations have to be finite numbers");
|
|
286
291
|
}
|
|
292
|
+
if (minElevation + interval > maxElevation) {
|
|
293
|
+
throw new Error(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
294
|
+
}
|
|
287
295
|
const elevations = [];
|
|
288
|
-
let elevation = Math.ceil(minElevation
|
|
296
|
+
let elevation = Math.ceil(minElevation / interval) * interval;
|
|
289
297
|
while (elevation < maxElevation) {
|
|
290
298
|
elevations.push(elevation);
|
|
291
299
|
elevation += interval;
|
|
@@ -322,29 +330,76 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
322
330
|
[Infinity, -Infinity]
|
|
323
331
|
);
|
|
324
332
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
325
|
-
const elevationPolylines = elevations.map((e) =>
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
333
|
+
const elevationPolylines = elevations.map((e) => {
|
|
334
|
+
const linesAtElevationE = triangles.reduce((prev, curr) => {
|
|
335
|
+
const line = contourLineOnFace(curr, e);
|
|
336
|
+
if (line)
|
|
337
|
+
prev.push(line);
|
|
338
|
+
return prev;
|
|
339
|
+
}, []);
|
|
340
|
+
const polylinesAtElevationE = linesToPolyLines(linesAtElevationE);
|
|
341
|
+
return {
|
|
342
|
+
elevation: e,
|
|
343
|
+
polylines: polylinesAtElevationE
|
|
344
|
+
};
|
|
345
|
+
});
|
|
336
346
|
return constructGeojson(elevationPolylines);
|
|
337
347
|
});
|
|
338
348
|
var get_contours_default = getContours;
|
|
339
349
|
|
|
350
|
+
// src/private/get-outline.ts
|
|
351
|
+
var getOutline = (surface) => {
|
|
352
|
+
const triangleVertexIdEdgePairs = [];
|
|
353
|
+
let i = -1;
|
|
354
|
+
let pairs = [];
|
|
355
|
+
surface.surfaceDefinition.faces.forEach((f) => {
|
|
356
|
+
pairs = [];
|
|
357
|
+
[
|
|
358
|
+
[f[0], f[1]],
|
|
359
|
+
[f[1], f[2]],
|
|
360
|
+
[f[2], f[0]]
|
|
361
|
+
].forEach(([a, b]) => {
|
|
362
|
+
if (a < b) {
|
|
363
|
+
pairs.push(`${a};${b}`);
|
|
364
|
+
} else {
|
|
365
|
+
pairs.push(`${b};${a}`);
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
pairs.forEach((pair) => {
|
|
369
|
+
i = triangleVertexIdEdgePairs.indexOf(pair);
|
|
370
|
+
if (i >= 0) {
|
|
371
|
+
triangleVertexIdEdgePairs.splice(i, 1);
|
|
372
|
+
} else {
|
|
373
|
+
triangleVertexIdEdgePairs.push(pair);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
const edges = [];
|
|
378
|
+
triangleVertexIdEdgePairs.map((pair) => {
|
|
379
|
+
const [v1, v2] = pair.split(";").map((v) => {
|
|
380
|
+
var _a;
|
|
381
|
+
return (_a = surface.surfaceDefinition.points[parseInt(v, 10)]) == null ? void 0 : _a.slice(0, 2);
|
|
382
|
+
});
|
|
383
|
+
if (v1 && v2)
|
|
384
|
+
edges.push([v1, v2]);
|
|
385
|
+
});
|
|
386
|
+
return constructGeojson([{ elevation: 0, polylines: linesToPolyLines(edges) }]);
|
|
387
|
+
};
|
|
388
|
+
var get_outline_default = getOutline;
|
|
389
|
+
|
|
340
390
|
// src/public/to-geojson-contours.ts
|
|
341
|
-
var toGeojsonContours = (landXmlString, contourInterval = 2, surfaceId = -1) => __async(void 0, null, function* () {
|
|
391
|
+
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(void 0, null, function* () {
|
|
342
392
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
343
393
|
const contours = yield Promise.all(
|
|
344
394
|
requestedParsedSurfaces.map(
|
|
345
395
|
(surface) => new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
346
396
|
try {
|
|
347
397
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
398
|
+
if (generateOutline) {
|
|
399
|
+
const outlineGeojson = get_outline_default(surface);
|
|
400
|
+
console.log(outlineGeojson.features);
|
|
401
|
+
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
402
|
+
}
|
|
348
403
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
349
404
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
350
405
|
geojson
|
package/dist/index.mjs
CHANGED
|
@@ -129,14 +129,16 @@ var parseXML = (xmlString) => __async(void 0, null, function* () {
|
|
|
129
129
|
points.push([x, y, z]);
|
|
130
130
|
pointIdMap[attr.id] = points.length - 1;
|
|
131
131
|
}, []);
|
|
132
|
-
faces = surface.Definition.Faces.F.
|
|
133
|
-
const { content } = face;
|
|
132
|
+
faces = surface.Definition.Faces.F.reduce((faceList, face) => {
|
|
133
|
+
const { attr, content } = face;
|
|
134
|
+
if (attr.i === "1")
|
|
135
|
+
return faceList;
|
|
134
136
|
const [a, b, c] = content.split(" ").map((v) => pointIdMap[v]);
|
|
135
137
|
if ([a, b, c].filter((v) => typeof v === "undefined").length > 0) {
|
|
136
138
|
throw `Invalid LandXML. A face is referencing a point that doesn't exist. Face is referencing points: ${content}`;
|
|
137
139
|
}
|
|
138
|
-
return [a, b, c];
|
|
139
|
-
});
|
|
140
|
+
return faceList.concat([[a, b, c]]);
|
|
141
|
+
}, []);
|
|
140
142
|
return {
|
|
141
143
|
sourceFile: LandXML.Project.attr.name,
|
|
142
144
|
timeStamp: LandXML.Application.attr.timeStamp,
|
|
@@ -185,11 +187,14 @@ var contourLineOnFace = (face, z) => {
|
|
|
185
187
|
for (let i = 0; i < face.length; i++) {
|
|
186
188
|
let vertex1 = face[i];
|
|
187
189
|
let vertex2 = face[(i + 1) % face.length];
|
|
188
|
-
if (vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) {
|
|
190
|
+
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
189
191
|
let t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
190
192
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
191
193
|
}
|
|
192
194
|
}
|
|
195
|
+
if (line.length > 2) {
|
|
196
|
+
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
197
|
+
}
|
|
193
198
|
return line.length > 0 ? line : void 0;
|
|
194
199
|
};
|
|
195
200
|
var linesToPolyLines = (lineSegments) => {
|
|
@@ -246,11 +251,14 @@ var linesToPolyLines = (lineSegments) => {
|
|
|
246
251
|
return polylines;
|
|
247
252
|
};
|
|
248
253
|
var contourElevations = (minElevation, maxElevation, interval) => {
|
|
249
|
-
if (maxElevation
|
|
254
|
+
if (!Number.isFinite(minElevation) || !Number.isFinite(maxElevation) || !Number.isFinite(interval)) {
|
|
250
255
|
throw new Error("Contour elevations have to be finite numbers");
|
|
251
256
|
}
|
|
257
|
+
if (minElevation + interval > maxElevation) {
|
|
258
|
+
throw new Error(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
259
|
+
}
|
|
252
260
|
const elevations = [];
|
|
253
|
-
let elevation = Math.ceil(minElevation
|
|
261
|
+
let elevation = Math.ceil(minElevation / interval) * interval;
|
|
254
262
|
while (elevation < maxElevation) {
|
|
255
263
|
elevations.push(elevation);
|
|
256
264
|
elevation += interval;
|
|
@@ -287,29 +295,76 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
287
295
|
[Infinity, -Infinity]
|
|
288
296
|
);
|
|
289
297
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
290
|
-
const elevationPolylines = elevations.map((e) =>
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
298
|
+
const elevationPolylines = elevations.map((e) => {
|
|
299
|
+
const linesAtElevationE = triangles.reduce((prev, curr) => {
|
|
300
|
+
const line = contourLineOnFace(curr, e);
|
|
301
|
+
if (line)
|
|
302
|
+
prev.push(line);
|
|
303
|
+
return prev;
|
|
304
|
+
}, []);
|
|
305
|
+
const polylinesAtElevationE = linesToPolyLines(linesAtElevationE);
|
|
306
|
+
return {
|
|
307
|
+
elevation: e,
|
|
308
|
+
polylines: polylinesAtElevationE
|
|
309
|
+
};
|
|
310
|
+
});
|
|
301
311
|
return constructGeojson(elevationPolylines);
|
|
302
312
|
});
|
|
303
313
|
var get_contours_default = getContours;
|
|
304
314
|
|
|
315
|
+
// src/private/get-outline.ts
|
|
316
|
+
var getOutline = (surface) => {
|
|
317
|
+
const triangleVertexIdEdgePairs = [];
|
|
318
|
+
let i = -1;
|
|
319
|
+
let pairs = [];
|
|
320
|
+
surface.surfaceDefinition.faces.forEach((f) => {
|
|
321
|
+
pairs = [];
|
|
322
|
+
[
|
|
323
|
+
[f[0], f[1]],
|
|
324
|
+
[f[1], f[2]],
|
|
325
|
+
[f[2], f[0]]
|
|
326
|
+
].forEach(([a, b]) => {
|
|
327
|
+
if (a < b) {
|
|
328
|
+
pairs.push(`${a};${b}`);
|
|
329
|
+
} else {
|
|
330
|
+
pairs.push(`${b};${a}`);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
pairs.forEach((pair) => {
|
|
334
|
+
i = triangleVertexIdEdgePairs.indexOf(pair);
|
|
335
|
+
if (i >= 0) {
|
|
336
|
+
triangleVertexIdEdgePairs.splice(i, 1);
|
|
337
|
+
} else {
|
|
338
|
+
triangleVertexIdEdgePairs.push(pair);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
const edges = [];
|
|
343
|
+
triangleVertexIdEdgePairs.map((pair) => {
|
|
344
|
+
const [v1, v2] = pair.split(";").map((v) => {
|
|
345
|
+
var _a;
|
|
346
|
+
return (_a = surface.surfaceDefinition.points[parseInt(v, 10)]) == null ? void 0 : _a.slice(0, 2);
|
|
347
|
+
});
|
|
348
|
+
if (v1 && v2)
|
|
349
|
+
edges.push([v1, v2]);
|
|
350
|
+
});
|
|
351
|
+
return constructGeojson([{ elevation: 0, polylines: linesToPolyLines(edges) }]);
|
|
352
|
+
};
|
|
353
|
+
var get_outline_default = getOutline;
|
|
354
|
+
|
|
305
355
|
// src/public/to-geojson-contours.ts
|
|
306
|
-
var toGeojsonContours = (landXmlString, contourInterval = 2, surfaceId = -1) => __async(void 0, null, function* () {
|
|
356
|
+
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(void 0, null, function* () {
|
|
307
357
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
308
358
|
const contours = yield Promise.all(
|
|
309
359
|
requestedParsedSurfaces.map(
|
|
310
360
|
(surface) => new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
311
361
|
try {
|
|
312
362
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
363
|
+
if (generateOutline) {
|
|
364
|
+
const outlineGeojson = get_outline_default(surface);
|
|
365
|
+
console.log(outlineGeojson.features);
|
|
366
|
+
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
367
|
+
}
|
|
313
368
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
314
369
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
315
370
|
geojson
|