landxml 0.4.2 → 0.5.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 +17 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +80 -17
- package/dist/index.mjs +80 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# landxml
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2d30d02: Fix: Edge case generating contour lines that are shared between multiple faces
|
|
8
|
+
|
|
9
|
+
## 0.5.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- df95e64: Added ability to generate surface outline geojson
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- df95e64: LandXML Face with with "i" attribute equal to "1" will now be correctly ignored
|
|
18
|
+
- df95e64: Improved contour generation algorithm
|
|
19
|
+
|
|
3
20
|
## 0.4.2
|
|
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,
|
|
@@ -216,15 +218,25 @@ var to_glb_default = toGlb;
|
|
|
216
218
|
|
|
217
219
|
// src/private/get-contours.ts
|
|
218
220
|
var contourLineOnFace = (face, z) => {
|
|
221
|
+
let vertsAtElevation = 0;
|
|
219
222
|
let line = [];
|
|
220
223
|
for (let i = 0; i < face.length; i++) {
|
|
221
224
|
let vertex1 = face[i];
|
|
222
225
|
let vertex2 = face[(i + 1) % face.length];
|
|
223
|
-
if (vertex1[2]
|
|
226
|
+
if (vertex1[2] === z)
|
|
227
|
+
vertsAtElevation++;
|
|
228
|
+
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
224
229
|
let t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
225
230
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
226
231
|
}
|
|
227
232
|
}
|
|
233
|
+
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length)
|
|
234
|
+
return void 0;
|
|
235
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
236
|
+
return void 0;
|
|
237
|
+
if (line.length > 2) {
|
|
238
|
+
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
239
|
+
}
|
|
228
240
|
return line.length > 0 ? line : void 0;
|
|
229
241
|
};
|
|
230
242
|
var linesToPolyLines = (lineSegments) => {
|
|
@@ -325,29 +337,80 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
325
337
|
[Infinity, -Infinity]
|
|
326
338
|
);
|
|
327
339
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
328
|
-
const elevationPolylines = elevations.map((e) =>
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
340
|
+
const elevationPolylines = elevations.map((e) => {
|
|
341
|
+
const linesAtElevationE = triangles.reduce((prev, curr) => {
|
|
342
|
+
const line = contourLineOnFace(curr, e);
|
|
343
|
+
if (line)
|
|
344
|
+
prev.push(line);
|
|
345
|
+
return prev;
|
|
346
|
+
}, []);
|
|
347
|
+
const polylinesAtElevationE = linesToPolyLines(linesAtElevationE);
|
|
348
|
+
if (e === 442) {
|
|
349
|
+
console.log("linesAtElevationE", JSON.stringify(linesAtElevationE));
|
|
350
|
+
console.log("polylinesAtElevationE", JSON.stringify(polylinesAtElevationE));
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
elevation: e,
|
|
354
|
+
polylines: polylinesAtElevationE
|
|
355
|
+
};
|
|
356
|
+
});
|
|
339
357
|
return constructGeojson(elevationPolylines);
|
|
340
358
|
});
|
|
341
359
|
var get_contours_default = getContours;
|
|
342
360
|
|
|
361
|
+
// src/private/get-outline.ts
|
|
362
|
+
var getOutline = (surface) => {
|
|
363
|
+
const triangleVertexIdEdgePairs = [];
|
|
364
|
+
let i = -1;
|
|
365
|
+
let pairs = [];
|
|
366
|
+
surface.surfaceDefinition.faces.forEach((f) => {
|
|
367
|
+
pairs = [];
|
|
368
|
+
[
|
|
369
|
+
[f[0], f[1]],
|
|
370
|
+
[f[1], f[2]],
|
|
371
|
+
[f[2], f[0]]
|
|
372
|
+
].forEach(([a, b]) => {
|
|
373
|
+
if (a < b) {
|
|
374
|
+
pairs.push(`${a};${b}`);
|
|
375
|
+
} else {
|
|
376
|
+
pairs.push(`${b};${a}`);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
pairs.forEach((pair) => {
|
|
380
|
+
i = triangleVertexIdEdgePairs.indexOf(pair);
|
|
381
|
+
if (i >= 0) {
|
|
382
|
+
triangleVertexIdEdgePairs.splice(i, 1);
|
|
383
|
+
} else {
|
|
384
|
+
triangleVertexIdEdgePairs.push(pair);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
const edges = [];
|
|
389
|
+
triangleVertexIdEdgePairs.map((pair) => {
|
|
390
|
+
const [v1, v2] = pair.split(";").map((v) => {
|
|
391
|
+
var _a;
|
|
392
|
+
return (_a = surface.surfaceDefinition.points[parseInt(v, 10)]) == null ? void 0 : _a.slice(0, 2);
|
|
393
|
+
});
|
|
394
|
+
if (v1 && v2)
|
|
395
|
+
edges.push([v1, v2]);
|
|
396
|
+
});
|
|
397
|
+
return constructGeojson([{ elevation: 0, polylines: linesToPolyLines(edges) }]);
|
|
398
|
+
};
|
|
399
|
+
var get_outline_default = getOutline;
|
|
400
|
+
|
|
343
401
|
// src/public/to-geojson-contours.ts
|
|
344
|
-
var toGeojsonContours = (landXmlString, contourInterval = 2, surfaceId = -1) => __async(void 0, null, function* () {
|
|
402
|
+
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(void 0, null, function* () {
|
|
345
403
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
346
404
|
const contours = yield Promise.all(
|
|
347
405
|
requestedParsedSurfaces.map(
|
|
348
406
|
(surface) => new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
349
407
|
try {
|
|
350
408
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
409
|
+
if (generateOutline) {
|
|
410
|
+
const outlineGeojson = get_outline_default(surface);
|
|
411
|
+
console.log(outlineGeojson.features);
|
|
412
|
+
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
413
|
+
}
|
|
351
414
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
352
415
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
353
416
|
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,
|
|
@@ -181,15 +183,25 @@ var to_glb_default = toGlb;
|
|
|
181
183
|
|
|
182
184
|
// src/private/get-contours.ts
|
|
183
185
|
var contourLineOnFace = (face, z) => {
|
|
186
|
+
let vertsAtElevation = 0;
|
|
184
187
|
let line = [];
|
|
185
188
|
for (let i = 0; i < face.length; i++) {
|
|
186
189
|
let vertex1 = face[i];
|
|
187
190
|
let vertex2 = face[(i + 1) % face.length];
|
|
188
|
-
if (vertex1[2]
|
|
191
|
+
if (vertex1[2] === z)
|
|
192
|
+
vertsAtElevation++;
|
|
193
|
+
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
189
194
|
let t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
190
195
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
191
196
|
}
|
|
192
197
|
}
|
|
198
|
+
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length)
|
|
199
|
+
return void 0;
|
|
200
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
201
|
+
return void 0;
|
|
202
|
+
if (line.length > 2) {
|
|
203
|
+
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
204
|
+
}
|
|
193
205
|
return line.length > 0 ? line : void 0;
|
|
194
206
|
};
|
|
195
207
|
var linesToPolyLines = (lineSegments) => {
|
|
@@ -290,29 +302,80 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
290
302
|
[Infinity, -Infinity]
|
|
291
303
|
);
|
|
292
304
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
293
|
-
const elevationPolylines = elevations.map((e) =>
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
305
|
+
const elevationPolylines = elevations.map((e) => {
|
|
306
|
+
const linesAtElevationE = triangles.reduce((prev, curr) => {
|
|
307
|
+
const line = contourLineOnFace(curr, e);
|
|
308
|
+
if (line)
|
|
309
|
+
prev.push(line);
|
|
310
|
+
return prev;
|
|
311
|
+
}, []);
|
|
312
|
+
const polylinesAtElevationE = linesToPolyLines(linesAtElevationE);
|
|
313
|
+
if (e === 442) {
|
|
314
|
+
console.log("linesAtElevationE", JSON.stringify(linesAtElevationE));
|
|
315
|
+
console.log("polylinesAtElevationE", JSON.stringify(polylinesAtElevationE));
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
elevation: e,
|
|
319
|
+
polylines: polylinesAtElevationE
|
|
320
|
+
};
|
|
321
|
+
});
|
|
304
322
|
return constructGeojson(elevationPolylines);
|
|
305
323
|
});
|
|
306
324
|
var get_contours_default = getContours;
|
|
307
325
|
|
|
326
|
+
// src/private/get-outline.ts
|
|
327
|
+
var getOutline = (surface) => {
|
|
328
|
+
const triangleVertexIdEdgePairs = [];
|
|
329
|
+
let i = -1;
|
|
330
|
+
let pairs = [];
|
|
331
|
+
surface.surfaceDefinition.faces.forEach((f) => {
|
|
332
|
+
pairs = [];
|
|
333
|
+
[
|
|
334
|
+
[f[0], f[1]],
|
|
335
|
+
[f[1], f[2]],
|
|
336
|
+
[f[2], f[0]]
|
|
337
|
+
].forEach(([a, b]) => {
|
|
338
|
+
if (a < b) {
|
|
339
|
+
pairs.push(`${a};${b}`);
|
|
340
|
+
} else {
|
|
341
|
+
pairs.push(`${b};${a}`);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
pairs.forEach((pair) => {
|
|
345
|
+
i = triangleVertexIdEdgePairs.indexOf(pair);
|
|
346
|
+
if (i >= 0) {
|
|
347
|
+
triangleVertexIdEdgePairs.splice(i, 1);
|
|
348
|
+
} else {
|
|
349
|
+
triangleVertexIdEdgePairs.push(pair);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
const edges = [];
|
|
354
|
+
triangleVertexIdEdgePairs.map((pair) => {
|
|
355
|
+
const [v1, v2] = pair.split(";").map((v) => {
|
|
356
|
+
var _a;
|
|
357
|
+
return (_a = surface.surfaceDefinition.points[parseInt(v, 10)]) == null ? void 0 : _a.slice(0, 2);
|
|
358
|
+
});
|
|
359
|
+
if (v1 && v2)
|
|
360
|
+
edges.push([v1, v2]);
|
|
361
|
+
});
|
|
362
|
+
return constructGeojson([{ elevation: 0, polylines: linesToPolyLines(edges) }]);
|
|
363
|
+
};
|
|
364
|
+
var get_outline_default = getOutline;
|
|
365
|
+
|
|
308
366
|
// src/public/to-geojson-contours.ts
|
|
309
|
-
var toGeojsonContours = (landXmlString, contourInterval = 2, surfaceId = -1) => __async(void 0, null, function* () {
|
|
367
|
+
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(void 0, null, function* () {
|
|
310
368
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
311
369
|
const contours = yield Promise.all(
|
|
312
370
|
requestedParsedSurfaces.map(
|
|
313
371
|
(surface) => new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
314
372
|
try {
|
|
315
373
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
374
|
+
if (generateOutline) {
|
|
375
|
+
const outlineGeojson = get_outline_default(surface);
|
|
376
|
+
console.log(outlineGeojson.features);
|
|
377
|
+
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
378
|
+
}
|
|
316
379
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
317
380
|
resolve(__spreadProps(__spreadValues({}, rest), {
|
|
318
381
|
geojson
|