landxml 0.4.2 → 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 +11 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +69 -17
- package/dist/index.mjs +69 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
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
|
+
|
|
3
14
|
## 0.4.2
|
|
4
15
|
|
|
5
16
|
### 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) => {
|
|
@@ -325,29 +330,76 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
325
330
|
[Infinity, -Infinity]
|
|
326
331
|
);
|
|
327
332
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
328
|
-
const elevationPolylines = elevations.map((e) =>
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
+
});
|
|
339
346
|
return constructGeojson(elevationPolylines);
|
|
340
347
|
});
|
|
341
348
|
var get_contours_default = getContours;
|
|
342
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
|
+
|
|
343
390
|
// src/public/to-geojson-contours.ts
|
|
344
|
-
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* () {
|
|
345
392
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
346
393
|
const contours = yield Promise.all(
|
|
347
394
|
requestedParsedSurfaces.map(
|
|
348
395
|
(surface) => new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
349
396
|
try {
|
|
350
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
|
+
}
|
|
351
403
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
352
404
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
353
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) => {
|
|
@@ -290,29 +295,76 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
290
295
|
[Infinity, -Infinity]
|
|
291
296
|
);
|
|
292
297
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
293
|
-
const elevationPolylines = elevations.map((e) =>
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
+
});
|
|
304
311
|
return constructGeojson(elevationPolylines);
|
|
305
312
|
});
|
|
306
313
|
var get_contours_default = getContours;
|
|
307
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
|
+
|
|
308
355
|
// src/public/to-geojson-contours.ts
|
|
309
|
-
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* () {
|
|
310
357
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
311
358
|
const contours = yield Promise.all(
|
|
312
359
|
requestedParsedSurfaces.map(
|
|
313
360
|
(surface) => new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
314
361
|
try {
|
|
315
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
|
+
}
|
|
316
368
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
317
369
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
318
370
|
geojson
|