landxml 0.5.2 → 0.6.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/dist/index.js +198 -81
- package/dist/index.mjs +198 -81
- package/package.json +11 -5
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -145,47 +145,109 @@ var downloadGlb = (glbData, fileName) => {
|
|
|
145
145
|
var download_glb_default = downloadGlb;
|
|
146
146
|
|
|
147
147
|
// src/private/parse-xml.ts
|
|
148
|
+
var import_easy_web_worker = require("easy-web-worker");
|
|
148
149
|
var import_xml_js = __toESM(require("xml-js"));
|
|
149
|
-
var
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const { attr, content } = face;
|
|
169
|
-
if ((attr == null ? void 0 : attr.i) === "1")
|
|
170
|
-
return faceList;
|
|
171
|
-
const [a, b, c] = content.split(" ").map((v) => pointIdMap[v]);
|
|
172
|
-
if ([a, b, c].filter((v) => typeof v === "undefined").length > 0) {
|
|
173
|
-
throw `Invalid LandXML. A face is referencing a point that doesn't exist. Face is referencing points: ${content}`;
|
|
174
|
-
}
|
|
175
|
-
return faceList.concat([[a, b, c]]);
|
|
176
|
-
}, []);
|
|
177
|
-
return {
|
|
178
|
-
sourceFile: LandXML.Project.attr.name,
|
|
179
|
-
timeStamp: LandXML.Application.attr.timeStamp,
|
|
180
|
-
name: surface.attr.name,
|
|
181
|
-
description: surface.attr.desc,
|
|
182
|
-
wktString: (_b = (_a = LandXML.CoordinateSystem) == null ? void 0 : _a.attr) == null ? void 0 : _b.ogcWktCode,
|
|
183
|
-
surfaceDefinition: {
|
|
184
|
-
points,
|
|
185
|
-
faces
|
|
150
|
+
var surfaceDefWorker = (0, import_easy_web_worker.createEasyWebWorker)(
|
|
151
|
+
({ onMessage }) => {
|
|
152
|
+
onMessage((message) => {
|
|
153
|
+
const { isPoint, arr, idMap } = message.payload;
|
|
154
|
+
if (isPoint) {
|
|
155
|
+
message.resolve(
|
|
156
|
+
arr.map((pt) => [pt.attr.id, pt.content.split(" ").map(Number)]).map((v) => [v[0], [v[1][1], v[1][0], v[1][2]]])
|
|
157
|
+
);
|
|
158
|
+
} else {
|
|
159
|
+
message.resolve(
|
|
160
|
+
arr.flatMap((f) => {
|
|
161
|
+
var _a;
|
|
162
|
+
if (typeof f === "string")
|
|
163
|
+
return [f.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
164
|
+
if (((_a = f == null ? void 0 : f.attr) == null ? void 0 : _a.i) === "1")
|
|
165
|
+
return [];
|
|
166
|
+
return [f.content.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
167
|
+
})
|
|
168
|
+
);
|
|
186
169
|
}
|
|
187
|
-
};
|
|
188
|
-
}
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
{ maxWorkers: 10 }
|
|
173
|
+
);
|
|
174
|
+
var parseXML = (xmlString) => __async(void 0, null, function* () {
|
|
175
|
+
return new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
176
|
+
var _a, _b, _c, _d, _e;
|
|
177
|
+
const parsed = import_xml_js.default.xml2js(xmlString, {
|
|
178
|
+
compact: true,
|
|
179
|
+
attributesKey: "attr",
|
|
180
|
+
textKey: "content"
|
|
181
|
+
});
|
|
182
|
+
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
183
|
+
throw new Error("LandXML doesn't contain any surfaces");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
187
|
+
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
188
|
+
}
|
|
189
|
+
let sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
190
|
+
let timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
191
|
+
let wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
192
|
+
const surfaces = parsed.LandXML.Surfaces.Surface.map(
|
|
193
|
+
(surface) => __async(void 0, null, function* () {
|
|
194
|
+
return new Promise((resolve2, reject2) => __async(void 0, null, function* () {
|
|
195
|
+
const { name, desc } = surface.attr;
|
|
196
|
+
const Pnts = surface.Definition.Pnts.P;
|
|
197
|
+
const Faces = surface.Definition.Faces.F;
|
|
198
|
+
let ptsIdArray = [];
|
|
199
|
+
let faces = [];
|
|
200
|
+
if (Pnts.length > 1e4) {
|
|
201
|
+
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Pnts.length / 20 * i));
|
|
202
|
+
ptsIdArray = (yield Promise.all(
|
|
203
|
+
sliceIndexes.map(
|
|
204
|
+
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
205
|
+
const pts = yield surfaceDefWorker.send({
|
|
206
|
+
isPoint: true,
|
|
207
|
+
arr: Pnts.slice(a[i], a[i + 1] || Pnts.length)
|
|
208
|
+
});
|
|
209
|
+
resolve3(pts);
|
|
210
|
+
}))
|
|
211
|
+
)
|
|
212
|
+
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
213
|
+
} else {
|
|
214
|
+
ptsIdArray = yield surfaceDefWorker.send({ arr: Pnts, isPoint: true });
|
|
215
|
+
}
|
|
216
|
+
const points = ptsIdArray.map((v) => v[1]);
|
|
217
|
+
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
218
|
+
if (Faces.length > 1e4) {
|
|
219
|
+
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Faces.length / 20 * i));
|
|
220
|
+
faces = (yield Promise.all(
|
|
221
|
+
sliceIndexes.map(
|
|
222
|
+
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
223
|
+
const fcs = yield surfaceDefWorker.send({
|
|
224
|
+
isPoint: false,
|
|
225
|
+
arr: Faces.slice(a[i], a[i + 1] || Faces.length),
|
|
226
|
+
idMap: pointsIdMap
|
|
227
|
+
});
|
|
228
|
+
resolve3(fcs);
|
|
229
|
+
}))
|
|
230
|
+
)
|
|
231
|
+
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
232
|
+
} else {
|
|
233
|
+
faces = yield surfaceDefWorker.send({ arr: Faces, isPoint: false, idMap: pointsIdMap });
|
|
234
|
+
}
|
|
235
|
+
resolve2({
|
|
236
|
+
sourceFile,
|
|
237
|
+
timeStamp: timeStamp || "",
|
|
238
|
+
name,
|
|
239
|
+
description: desc || "",
|
|
240
|
+
wktString,
|
|
241
|
+
surfaceDefinition: {
|
|
242
|
+
points,
|
|
243
|
+
faces
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}));
|
|
247
|
+
})
|
|
248
|
+
);
|
|
249
|
+
resolve(yield Promise.all(surfaces));
|
|
250
|
+
}));
|
|
189
251
|
});
|
|
190
252
|
var parse_xml_default = parseXML;
|
|
191
253
|
|
|
@@ -217,32 +279,104 @@ var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(void 0,
|
|
|
217
279
|
var to_glb_default = toGlb;
|
|
218
280
|
|
|
219
281
|
// src/private/get-contours.ts
|
|
220
|
-
var
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
282
|
+
var import_easy_web_worker2 = require("easy-web-worker");
|
|
283
|
+
var contoursWorker = (0, import_easy_web_worker2.createEasyWebWorker)(
|
|
284
|
+
({ onMessage }) => {
|
|
285
|
+
const contourLineOnFace = (face, z) => {
|
|
286
|
+
let vertsAtElevation = 0;
|
|
287
|
+
let line = [];
|
|
288
|
+
for (let i = 0; i < face.length; i++) {
|
|
289
|
+
let vertex1 = face[i];
|
|
290
|
+
let vertex2 = face[(i + 1) % face.length];
|
|
291
|
+
if (vertex1[2] === z)
|
|
292
|
+
vertsAtElevation++;
|
|
293
|
+
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
294
|
+
let t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
295
|
+
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length)
|
|
299
|
+
return void 0;
|
|
300
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
301
|
+
return void 0;
|
|
302
|
+
if (line.length > 2) {
|
|
303
|
+
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
304
|
+
}
|
|
305
|
+
return line.length > 0 ? line : void 0;
|
|
306
|
+
};
|
|
307
|
+
const linesToPolyLines3 = (lineSegments) => {
|
|
308
|
+
var _a, _b;
|
|
309
|
+
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
310
|
+
return [];
|
|
311
|
+
}
|
|
312
|
+
const segmentsMapIndexes = {};
|
|
313
|
+
const polylines = [];
|
|
314
|
+
const parsedSegmentIndexes = [];
|
|
315
|
+
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
316
|
+
lineSegmentStrings.forEach(([start, end], i) => {
|
|
317
|
+
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
318
|
+
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
319
|
+
});
|
|
320
|
+
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
321
|
+
if (parsedSegmentIndexes.includes(i))
|
|
322
|
+
continue;
|
|
323
|
+
parsedSegmentIndexes.push(i);
|
|
324
|
+
let [start, end] = lineSegmentStrings[i];
|
|
325
|
+
let polyline = [start, end];
|
|
326
|
+
while (start && segmentsMapIndexes[start]) {
|
|
327
|
+
const nextLineIndex = (_a = segmentsMapIndexes[start]) == null ? void 0 : _a.find(
|
|
328
|
+
(lineIndex) => !parsedSegmentIndexes.includes(lineIndex)
|
|
329
|
+
);
|
|
330
|
+
if (nextLineIndex) {
|
|
331
|
+
parsedSegmentIndexes.push(nextLineIndex);
|
|
332
|
+
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
333
|
+
const nextLineSegmentPointIndex = nextLineSegment[0] === start ? 1 : 0;
|
|
334
|
+
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
335
|
+
polyline.unshift(newPoint);
|
|
336
|
+
start = newPoint;
|
|
337
|
+
} else {
|
|
338
|
+
start = null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
while (end && segmentsMapIndexes[end]) {
|
|
342
|
+
const nextLineIndex = (_b = segmentsMapIndexes[end]) == null ? void 0 : _b.find(
|
|
343
|
+
(lineIndex) => !parsedSegmentIndexes.includes(lineIndex)
|
|
344
|
+
);
|
|
345
|
+
if (nextLineIndex) {
|
|
346
|
+
parsedSegmentIndexes.push(nextLineIndex);
|
|
347
|
+
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
348
|
+
const nextLineSegmentPointIndex = nextLineSegment[0] === end ? 1 : 0;
|
|
349
|
+
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
350
|
+
polyline.push(newPoint);
|
|
351
|
+
end = newPoint;
|
|
352
|
+
} else {
|
|
353
|
+
end = null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
polylines.push(polyline.map((coord) => coord.split(",").map((v) => parseFloat(v))));
|
|
357
|
+
}
|
|
358
|
+
return polylines;
|
|
359
|
+
};
|
|
360
|
+
onMessage((message) => {
|
|
361
|
+
const { triangles, elevation } = message.payload;
|
|
362
|
+
const linesAtElevationE = triangles.reduce((prev, curr) => {
|
|
363
|
+
const line = contourLineOnFace(curr, elevation);
|
|
364
|
+
if (line)
|
|
365
|
+
prev.push(line);
|
|
366
|
+
return prev;
|
|
367
|
+
}, []);
|
|
368
|
+
message.resolve({
|
|
369
|
+
elevation,
|
|
370
|
+
polylines: linesToPolyLines3(linesAtElevationE)
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
{ maxWorkers: 10 }
|
|
375
|
+
);
|
|
242
376
|
var linesToPolyLines = (lineSegments) => {
|
|
243
377
|
var _a, _b;
|
|
244
|
-
if (!Array.isArray(lineSegments) || lineSegments.length === 0) {
|
|
245
|
-
|
|
378
|
+
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
379
|
+
return [];
|
|
246
380
|
}
|
|
247
381
|
const segmentsMapIndexes = {};
|
|
248
382
|
const polylines = [];
|
|
@@ -337,23 +471,7 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
337
471
|
[Infinity, -Infinity]
|
|
338
472
|
);
|
|
339
473
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
340
|
-
const elevationPolylines = elevations.map((
|
|
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
|
-
});
|
|
474
|
+
const elevationPolylines = yield Promise.all(elevations.map((elevation) => contoursWorker.send({ triangles, elevation })));
|
|
357
475
|
return constructGeojson(elevationPolylines);
|
|
358
476
|
});
|
|
359
477
|
var get_contours_default = getContours;
|
|
@@ -408,7 +526,6 @@ var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = t
|
|
|
408
526
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
409
527
|
if (generateOutline) {
|
|
410
528
|
const outlineGeojson = get_outline_default(surface);
|
|
411
|
-
console.log(outlineGeojson.features);
|
|
412
529
|
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
413
530
|
}
|
|
414
531
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
package/dist/index.mjs
CHANGED
|
@@ -110,47 +110,109 @@ var downloadGlb = (glbData, fileName) => {
|
|
|
110
110
|
var download_glb_default = downloadGlb;
|
|
111
111
|
|
|
112
112
|
// src/private/parse-xml.ts
|
|
113
|
+
import { createEasyWebWorker } from "easy-web-worker";
|
|
113
114
|
import convert from "xml-js";
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const { attr, content } = face;
|
|
134
|
-
if ((attr == null ? void 0 : attr.i) === "1")
|
|
135
|
-
return faceList;
|
|
136
|
-
const [a, b, c] = content.split(" ").map((v) => pointIdMap[v]);
|
|
137
|
-
if ([a, b, c].filter((v) => typeof v === "undefined").length > 0) {
|
|
138
|
-
throw `Invalid LandXML. A face is referencing a point that doesn't exist. Face is referencing points: ${content}`;
|
|
139
|
-
}
|
|
140
|
-
return faceList.concat([[a, b, c]]);
|
|
141
|
-
}, []);
|
|
142
|
-
return {
|
|
143
|
-
sourceFile: LandXML.Project.attr.name,
|
|
144
|
-
timeStamp: LandXML.Application.attr.timeStamp,
|
|
145
|
-
name: surface.attr.name,
|
|
146
|
-
description: surface.attr.desc,
|
|
147
|
-
wktString: (_b = (_a = LandXML.CoordinateSystem) == null ? void 0 : _a.attr) == null ? void 0 : _b.ogcWktCode,
|
|
148
|
-
surfaceDefinition: {
|
|
149
|
-
points,
|
|
150
|
-
faces
|
|
115
|
+
var surfaceDefWorker = createEasyWebWorker(
|
|
116
|
+
({ onMessage }) => {
|
|
117
|
+
onMessage((message) => {
|
|
118
|
+
const { isPoint, arr, idMap } = message.payload;
|
|
119
|
+
if (isPoint) {
|
|
120
|
+
message.resolve(
|
|
121
|
+
arr.map((pt) => [pt.attr.id, pt.content.split(" ").map(Number)]).map((v) => [v[0], [v[1][1], v[1][0], v[1][2]]])
|
|
122
|
+
);
|
|
123
|
+
} else {
|
|
124
|
+
message.resolve(
|
|
125
|
+
arr.flatMap((f) => {
|
|
126
|
+
var _a;
|
|
127
|
+
if (typeof f === "string")
|
|
128
|
+
return [f.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
129
|
+
if (((_a = f == null ? void 0 : f.attr) == null ? void 0 : _a.i) === "1")
|
|
130
|
+
return [];
|
|
131
|
+
return [f.content.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
132
|
+
})
|
|
133
|
+
);
|
|
151
134
|
}
|
|
152
|
-
};
|
|
153
|
-
}
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
{ maxWorkers: 10 }
|
|
138
|
+
);
|
|
139
|
+
var parseXML = (xmlString) => __async(void 0, null, function* () {
|
|
140
|
+
return new Promise((resolve, reject) => __async(void 0, null, function* () {
|
|
141
|
+
var _a, _b, _c, _d, _e;
|
|
142
|
+
const parsed = convert.xml2js(xmlString, {
|
|
143
|
+
compact: true,
|
|
144
|
+
attributesKey: "attr",
|
|
145
|
+
textKey: "content"
|
|
146
|
+
});
|
|
147
|
+
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
148
|
+
throw new Error("LandXML doesn't contain any surfaces");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
152
|
+
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
153
|
+
}
|
|
154
|
+
let sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
155
|
+
let timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
156
|
+
let wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
157
|
+
const surfaces = parsed.LandXML.Surfaces.Surface.map(
|
|
158
|
+
(surface) => __async(void 0, null, function* () {
|
|
159
|
+
return new Promise((resolve2, reject2) => __async(void 0, null, function* () {
|
|
160
|
+
const { name, desc } = surface.attr;
|
|
161
|
+
const Pnts = surface.Definition.Pnts.P;
|
|
162
|
+
const Faces = surface.Definition.Faces.F;
|
|
163
|
+
let ptsIdArray = [];
|
|
164
|
+
let faces = [];
|
|
165
|
+
if (Pnts.length > 1e4) {
|
|
166
|
+
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Pnts.length / 20 * i));
|
|
167
|
+
ptsIdArray = (yield Promise.all(
|
|
168
|
+
sliceIndexes.map(
|
|
169
|
+
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
170
|
+
const pts = yield surfaceDefWorker.send({
|
|
171
|
+
isPoint: true,
|
|
172
|
+
arr: Pnts.slice(a[i], a[i + 1] || Pnts.length)
|
|
173
|
+
});
|
|
174
|
+
resolve3(pts);
|
|
175
|
+
}))
|
|
176
|
+
)
|
|
177
|
+
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
178
|
+
} else {
|
|
179
|
+
ptsIdArray = yield surfaceDefWorker.send({ arr: Pnts, isPoint: true });
|
|
180
|
+
}
|
|
181
|
+
const points = ptsIdArray.map((v) => v[1]);
|
|
182
|
+
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
183
|
+
if (Faces.length > 1e4) {
|
|
184
|
+
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Faces.length / 20 * i));
|
|
185
|
+
faces = (yield Promise.all(
|
|
186
|
+
sliceIndexes.map(
|
|
187
|
+
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
188
|
+
const fcs = yield surfaceDefWorker.send({
|
|
189
|
+
isPoint: false,
|
|
190
|
+
arr: Faces.slice(a[i], a[i + 1] || Faces.length),
|
|
191
|
+
idMap: pointsIdMap
|
|
192
|
+
});
|
|
193
|
+
resolve3(fcs);
|
|
194
|
+
}))
|
|
195
|
+
)
|
|
196
|
+
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
197
|
+
} else {
|
|
198
|
+
faces = yield surfaceDefWorker.send({ arr: Faces, isPoint: false, idMap: pointsIdMap });
|
|
199
|
+
}
|
|
200
|
+
resolve2({
|
|
201
|
+
sourceFile,
|
|
202
|
+
timeStamp: timeStamp || "",
|
|
203
|
+
name,
|
|
204
|
+
description: desc || "",
|
|
205
|
+
wktString,
|
|
206
|
+
surfaceDefinition: {
|
|
207
|
+
points,
|
|
208
|
+
faces
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}));
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
resolve(yield Promise.all(surfaces));
|
|
215
|
+
}));
|
|
154
216
|
});
|
|
155
217
|
var parse_xml_default = parseXML;
|
|
156
218
|
|
|
@@ -182,32 +244,104 @@ var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(void 0,
|
|
|
182
244
|
var to_glb_default = toGlb;
|
|
183
245
|
|
|
184
246
|
// src/private/get-contours.ts
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
247
|
+
import { createEasyWebWorker as createEasyWebWorker2 } from "easy-web-worker";
|
|
248
|
+
var contoursWorker = createEasyWebWorker2(
|
|
249
|
+
({ onMessage }) => {
|
|
250
|
+
const contourLineOnFace = (face, z) => {
|
|
251
|
+
let vertsAtElevation = 0;
|
|
252
|
+
let line = [];
|
|
253
|
+
for (let i = 0; i < face.length; i++) {
|
|
254
|
+
let vertex1 = face[i];
|
|
255
|
+
let vertex2 = face[(i + 1) % face.length];
|
|
256
|
+
if (vertex1[2] === z)
|
|
257
|
+
vertsAtElevation++;
|
|
258
|
+
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
259
|
+
let t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
260
|
+
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length)
|
|
264
|
+
return void 0;
|
|
265
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
266
|
+
return void 0;
|
|
267
|
+
if (line.length > 2) {
|
|
268
|
+
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
269
|
+
}
|
|
270
|
+
return line.length > 0 ? line : void 0;
|
|
271
|
+
};
|
|
272
|
+
const linesToPolyLines3 = (lineSegments) => {
|
|
273
|
+
var _a, _b;
|
|
274
|
+
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
const segmentsMapIndexes = {};
|
|
278
|
+
const polylines = [];
|
|
279
|
+
const parsedSegmentIndexes = [];
|
|
280
|
+
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
281
|
+
lineSegmentStrings.forEach(([start, end], i) => {
|
|
282
|
+
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
283
|
+
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
284
|
+
});
|
|
285
|
+
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
286
|
+
if (parsedSegmentIndexes.includes(i))
|
|
287
|
+
continue;
|
|
288
|
+
parsedSegmentIndexes.push(i);
|
|
289
|
+
let [start, end] = lineSegmentStrings[i];
|
|
290
|
+
let polyline = [start, end];
|
|
291
|
+
while (start && segmentsMapIndexes[start]) {
|
|
292
|
+
const nextLineIndex = (_a = segmentsMapIndexes[start]) == null ? void 0 : _a.find(
|
|
293
|
+
(lineIndex) => !parsedSegmentIndexes.includes(lineIndex)
|
|
294
|
+
);
|
|
295
|
+
if (nextLineIndex) {
|
|
296
|
+
parsedSegmentIndexes.push(nextLineIndex);
|
|
297
|
+
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
298
|
+
const nextLineSegmentPointIndex = nextLineSegment[0] === start ? 1 : 0;
|
|
299
|
+
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
300
|
+
polyline.unshift(newPoint);
|
|
301
|
+
start = newPoint;
|
|
302
|
+
} else {
|
|
303
|
+
start = null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
while (end && segmentsMapIndexes[end]) {
|
|
307
|
+
const nextLineIndex = (_b = segmentsMapIndexes[end]) == null ? void 0 : _b.find(
|
|
308
|
+
(lineIndex) => !parsedSegmentIndexes.includes(lineIndex)
|
|
309
|
+
);
|
|
310
|
+
if (nextLineIndex) {
|
|
311
|
+
parsedSegmentIndexes.push(nextLineIndex);
|
|
312
|
+
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
313
|
+
const nextLineSegmentPointIndex = nextLineSegment[0] === end ? 1 : 0;
|
|
314
|
+
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
315
|
+
polyline.push(newPoint);
|
|
316
|
+
end = newPoint;
|
|
317
|
+
} else {
|
|
318
|
+
end = null;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
polylines.push(polyline.map((coord) => coord.split(",").map((v) => parseFloat(v))));
|
|
322
|
+
}
|
|
323
|
+
return polylines;
|
|
324
|
+
};
|
|
325
|
+
onMessage((message) => {
|
|
326
|
+
const { triangles, elevation } = message.payload;
|
|
327
|
+
const linesAtElevationE = triangles.reduce((prev, curr) => {
|
|
328
|
+
const line = contourLineOnFace(curr, elevation);
|
|
329
|
+
if (line)
|
|
330
|
+
prev.push(line);
|
|
331
|
+
return prev;
|
|
332
|
+
}, []);
|
|
333
|
+
message.resolve({
|
|
334
|
+
elevation,
|
|
335
|
+
polylines: linesToPolyLines3(linesAtElevationE)
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
{ maxWorkers: 10 }
|
|
340
|
+
);
|
|
207
341
|
var linesToPolyLines = (lineSegments) => {
|
|
208
342
|
var _a, _b;
|
|
209
|
-
if (!Array.isArray(lineSegments) || lineSegments.length === 0) {
|
|
210
|
-
|
|
343
|
+
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
344
|
+
return [];
|
|
211
345
|
}
|
|
212
346
|
const segmentsMapIndexes = {};
|
|
213
347
|
const polylines = [];
|
|
@@ -302,23 +436,7 @@ var getContours = (data, interval = 2) => __async(void 0, null, function* () {
|
|
|
302
436
|
[Infinity, -Infinity]
|
|
303
437
|
);
|
|
304
438
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
305
|
-
const elevationPolylines = elevations.map((
|
|
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
|
-
});
|
|
439
|
+
const elevationPolylines = yield Promise.all(elevations.map((elevation) => contoursWorker.send({ triangles, elevation })));
|
|
322
440
|
return constructGeojson(elevationPolylines);
|
|
323
441
|
});
|
|
324
442
|
var get_contours_default = getContours;
|
|
@@ -373,7 +491,6 @@ var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = t
|
|
|
373
491
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
374
492
|
if (generateOutline) {
|
|
375
493
|
const outlineGeojson = get_outline_default(surface);
|
|
376
|
-
console.log(outlineGeojson.features);
|
|
377
494
|
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
378
495
|
}
|
|
379
496
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "landxml",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Parse LandXML surfaces on the modern web.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"url": "https://github.com/abrman/landxml"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
|
-
"dev": "vitest",
|
|
16
|
-
"test": "vitest run",
|
|
15
|
+
"dev": "vitest --config ./vitest.config.ts --slow-test-threshold=0",
|
|
16
|
+
"test": "vitest --config ./vitest.config.ts run",
|
|
17
17
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
18
18
|
"lint": "tsc",
|
|
19
19
|
"ci": "npm run lint && npm run test && npm run build",
|
|
@@ -30,14 +30,20 @@
|
|
|
30
30
|
"@changesets/cli": "^2.26.2",
|
|
31
31
|
"@types/geojson": "^7946.0.13",
|
|
32
32
|
"@types/proj4": "^2.5.5",
|
|
33
|
+
"@types/sax": "^1.2.7",
|
|
33
34
|
"@types/xml2json": "^0.11.6",
|
|
35
|
+
"jsdom": "^24.0.0",
|
|
34
36
|
"tsup": "^8.0.0",
|
|
35
37
|
"typescript": "^5.2.2",
|
|
36
|
-
"vitest": "^
|
|
38
|
+
"vitest": "^1.6.0"
|
|
37
39
|
},
|
|
38
40
|
"dependencies": {
|
|
39
41
|
"@gltf-transform/core": "^3.9.0",
|
|
42
|
+
"@vitest/web-worker": "^1.6.0",
|
|
43
|
+
"easy-web-worker": "^6.2.0",
|
|
40
44
|
"proj4": "^2.9.2",
|
|
41
|
-
"
|
|
45
|
+
"sax": "^1.3.0",
|
|
46
|
+
"xml-js": "^1.6.11",
|
|
47
|
+
"xml2json": "^0.12.0"
|
|
42
48
|
}
|
|
43
49
|
}
|