landxml 0.6.6 → 0.7.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 +14 -0
- package/README.md +168 -28
- package/dist/index.d.mts +66 -1
- package/dist/index.d.ts +66 -1
- package/dist/index.js +240 -218
- package/dist/index.mjs +237 -217
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -79,9 +79,11 @@ var __async = (__this, __arguments, generator) => {
|
|
|
79
79
|
// src/index.ts
|
|
80
80
|
var index_exports = {};
|
|
81
81
|
__export(index_exports, {
|
|
82
|
+
precomputeSurfaceData: () => precomputeSurfaceData,
|
|
82
83
|
reprojectGeoJson: () => reproject_geojson_default,
|
|
83
84
|
toGeojsonContours: () => to_geojson_contours_default,
|
|
84
|
-
toGlb: () => to_glb_default
|
|
85
|
+
toGlb: () => to_glb_default,
|
|
86
|
+
toGlbAndContours: () => to_glb_and_contours_default
|
|
85
87
|
});
|
|
86
88
|
module.exports = __toCommonJS(index_exports);
|
|
87
89
|
|
|
@@ -113,18 +115,30 @@ var findXYAxisMedians = (vertices) => {
|
|
|
113
115
|
};
|
|
114
116
|
var getGlb = (data, customCenter) => __async(null, null, function* () {
|
|
115
117
|
const center = customCenter || findXYAxisMedians(data.surfaceDefinition.points);
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
const pts = data.surfaceDefinition.points;
|
|
119
|
+
const facesFlat = data.surfaceDefinition.faces;
|
|
120
|
+
const vertexBuffer = new Float32Array(pts.length * 3);
|
|
121
|
+
for (let i = 0; i < pts.length; i++) {
|
|
122
|
+
const [x, y, z] = pts[i];
|
|
123
|
+
vertexBuffer[i * 3] = x - center[0];
|
|
124
|
+
vertexBuffer[i * 3 + 1] = z;
|
|
125
|
+
vertexBuffer[i * 3 + 2] = -(y - center[1]);
|
|
126
|
+
}
|
|
127
|
+
const indexBuffer = new Uint32Array(facesFlat.length * 3);
|
|
128
|
+
for (let i = 0; i < facesFlat.length; i++) {
|
|
129
|
+
const [a, b, c] = facesFlat[i];
|
|
130
|
+
indexBuffer[i * 3] = a;
|
|
131
|
+
indexBuffer[i * 3 + 1] = b;
|
|
132
|
+
indexBuffer[i * 3 + 2] = c;
|
|
133
|
+
}
|
|
120
134
|
const doc = new import_core.Document();
|
|
121
135
|
const buffer = doc.createBuffer();
|
|
122
|
-
const position = doc.createAccessor().setType("VEC3").setArray(
|
|
123
|
-
const indices = doc.createAccessor().setType("SCALAR").setArray(
|
|
136
|
+
const position = doc.createAccessor().setType("VEC3").setArray(vertexBuffer).setBuffer(buffer);
|
|
137
|
+
const indices = doc.createAccessor().setType("SCALAR").setArray(indexBuffer).setBuffer(buffer);
|
|
124
138
|
const prim = doc.createPrimitive().setAttribute("POSITION", position).setIndices(indices);
|
|
125
139
|
const mesh = doc.createMesh().addPrimitive(prim);
|
|
126
140
|
const node = doc.createNode().setMesh(mesh);
|
|
127
|
-
|
|
141
|
+
doc.createScene().addChild(node);
|
|
128
142
|
const glb = yield new import_core.WebIO().writeBinary(doc);
|
|
129
143
|
return { glb, center };
|
|
130
144
|
});
|
|
@@ -168,14 +182,29 @@ var surfaceDefWorker = (0, import_easy_web_worker.createEasyWebWorker)(
|
|
|
168
182
|
})
|
|
169
183
|
);
|
|
170
184
|
} else if (task === "find-neighboring-faces") {
|
|
171
|
-
const { faces
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
const { faces } = message.payload;
|
|
186
|
+
const edgeMap = /* @__PURE__ */ new Map();
|
|
187
|
+
const edgeKey = (a, b) => a < b ? `${a},${b}` : `${b},${a}`;
|
|
188
|
+
for (let i = 0; i < faces.length; i++) {
|
|
189
|
+
const [v0, v1, v2] = faces[i];
|
|
190
|
+
for (const key of [edgeKey(v0, v1), edgeKey(v1, v2), edgeKey(v0, v2)]) {
|
|
191
|
+
const existing = edgeMap.get(key);
|
|
192
|
+
if (!existing) {
|
|
193
|
+
edgeMap.set(key, [i]);
|
|
194
|
+
} else if (existing.length === 1) {
|
|
195
|
+
existing.push(i);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const faceNeighbors = new Array(faces.length);
|
|
200
|
+
for (let i = 0; i < faces.length; i++) {
|
|
201
|
+
const [v0, v1, v2] = faces[i];
|
|
202
|
+
const resolve = (key) => {
|
|
203
|
+
const pair = edgeMap.get(key);
|
|
204
|
+
if (!pair || pair.length < 2) return -1;
|
|
205
|
+
return pair[0] === i ? pair[1] : pair[0];
|
|
206
|
+
};
|
|
207
|
+
faceNeighbors[i] = [resolve(edgeKey(v0, v1)), resolve(edgeKey(v1, v2)), resolve(edgeKey(v0, v2))];
|
|
179
208
|
}
|
|
180
209
|
message.resolve(faceNeighbors);
|
|
181
210
|
}
|
|
@@ -186,116 +215,73 @@ var surfaceDefWorker = (0, import_easy_web_worker.createEasyWebWorker)(
|
|
|
186
215
|
},
|
|
187
216
|
{ maxWorkers: 16 }
|
|
188
217
|
);
|
|
189
|
-
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
198
|
-
throw new Error("LandXML doesn't contain any surfaces");
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
202
|
-
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
203
|
-
}
|
|
204
|
-
let sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
205
|
-
let timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
206
|
-
let wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
207
|
-
const surfaces = parsed.LandXML.Surfaces.Surface.map(
|
|
208
|
-
(surface) => __async(null, null, function* () {
|
|
209
|
-
return new Promise((resolve2, reject2) => __async(null, null, function* () {
|
|
210
|
-
const { name, desc } = surface.attr;
|
|
211
|
-
const Pnts = surface.Definition.Pnts.P;
|
|
212
|
-
const Faces = surface.Definition.Faces.F;
|
|
213
|
-
let ptsIdArray = [];
|
|
214
|
-
let faces = [];
|
|
215
|
-
let faceNeighbors = [];
|
|
216
|
-
if (Pnts.length > 1e4) {
|
|
217
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Pnts.length / 20 * i));
|
|
218
|
-
ptsIdArray = (yield Promise.all(
|
|
219
|
-
sliceIndexes.map(
|
|
220
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(null, null, function* () {
|
|
221
|
-
const pts = yield surfaceDefWorker.send({
|
|
222
|
-
task: "parse-surface-points",
|
|
223
|
-
points: Pnts.slice(a[i], a[i + 1] || Pnts.length)
|
|
224
|
-
});
|
|
225
|
-
resolve3(pts);
|
|
226
|
-
}))
|
|
227
|
-
)
|
|
228
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
229
|
-
} else {
|
|
230
|
-
ptsIdArray = yield surfaceDefWorker.send({ task: "parse-surface-points", points: Pnts });
|
|
231
|
-
}
|
|
232
|
-
const points = ptsIdArray.map((v) => v[1]);
|
|
233
|
-
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
234
|
-
if (Faces.length > 1e4) {
|
|
235
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Faces.length / 20 * i));
|
|
236
|
-
faces = (yield Promise.all(
|
|
237
|
-
sliceIndexes.map(
|
|
238
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(null, null, function* () {
|
|
239
|
-
const fcs = yield surfaceDefWorker.send({
|
|
240
|
-
task: "parse-surface-faces",
|
|
241
|
-
faces: Faces.slice(a[i], a[i + 1] || Faces.length),
|
|
242
|
-
idMap: pointsIdMap
|
|
243
|
-
});
|
|
244
|
-
resolve3(fcs);
|
|
245
|
-
}))
|
|
246
|
-
)
|
|
247
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
248
|
-
} else {
|
|
249
|
-
faces = yield surfaceDefWorker.send({
|
|
250
|
-
task: "parse-surface-faces",
|
|
251
|
-
faces: Faces,
|
|
252
|
-
idMap: pointsIdMap
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
if (Faces.length > 1e4) {
|
|
256
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round((faces.length - 1) / 20 * i));
|
|
257
|
-
faceNeighbors = (yield Promise.all(
|
|
258
|
-
sliceIndexes.map(
|
|
259
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(null, null, function* () {
|
|
260
|
-
const fcs = yield surfaceDefWorker.send({
|
|
261
|
-
task: "find-neighboring-faces",
|
|
262
|
-
faces,
|
|
263
|
-
range: {
|
|
264
|
-
start: a[i],
|
|
265
|
-
end: a[i + 1] || faces.length
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
resolve3(fcs);
|
|
269
|
-
}))
|
|
270
|
-
)
|
|
271
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
272
|
-
} else {
|
|
273
|
-
faceNeighbors = yield surfaceDefWorker.send({
|
|
274
|
-
task: "find-neighboring-faces",
|
|
275
|
-
faces,
|
|
276
|
-
range: {
|
|
277
|
-
start: 0,
|
|
278
|
-
end: faces.length
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
resolve2({
|
|
283
|
-
sourceFile,
|
|
284
|
-
timeStamp: timeStamp || "",
|
|
285
|
-
name,
|
|
286
|
-
description: desc || "",
|
|
287
|
-
wktString,
|
|
288
|
-
surfaceDefinition: {
|
|
289
|
-
points,
|
|
290
|
-
faces,
|
|
291
|
-
faceNeighbors
|
|
292
|
-
}
|
|
293
|
-
});
|
|
294
|
-
}));
|
|
218
|
+
function parallelChunks(items, count, makePayload) {
|
|
219
|
+
return __async(this, null, function* () {
|
|
220
|
+
const sliceIndexes = [...Array(count).keys()].map((i) => Math.round(items.length / count * i));
|
|
221
|
+
const chunks = yield Promise.all(
|
|
222
|
+
sliceIndexes.map((start, i, arr) => {
|
|
223
|
+
var _a;
|
|
224
|
+
const end = (_a = arr[i + 1]) != null ? _a : items.length;
|
|
225
|
+
return surfaceDefWorker.send(makePayload(items.slice(start, end), start, end));
|
|
295
226
|
})
|
|
296
227
|
);
|
|
297
|
-
|
|
228
|
+
return chunks.reduce((acc, c) => acc.concat(c), []);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
var CHUNK_THRESHOLD = 1e4;
|
|
232
|
+
var CHUNK_COUNT = 20;
|
|
233
|
+
var parseXML = (xmlString) => __async(null, null, function* () {
|
|
234
|
+
var _a, _b, _c, _d, _e;
|
|
235
|
+
const parsed = import_xml_js.default.xml2js(xmlString, {
|
|
236
|
+
compact: true,
|
|
237
|
+
attributesKey: "attr",
|
|
238
|
+
textKey: "content"
|
|
239
|
+
});
|
|
240
|
+
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
241
|
+
throw new Error("LandXML doesn't contain any surfaces");
|
|
242
|
+
}
|
|
243
|
+
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
244
|
+
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
245
|
+
}
|
|
246
|
+
const sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
247
|
+
const timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
248
|
+
const wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
249
|
+
const surfaces = parsed.LandXML.Surfaces.Surface.map((surface) => __async(null, null, function* () {
|
|
250
|
+
const { name, desc } = surface.attr;
|
|
251
|
+
const Pnts = surface.Definition.Pnts.P;
|
|
252
|
+
const Faces = surface.Definition.Faces.F;
|
|
253
|
+
const ptsIdArray = Pnts.length > CHUNK_THRESHOLD ? yield parallelChunks(Pnts, CHUNK_COUNT, (chunk) => ({
|
|
254
|
+
task: "parse-surface-points",
|
|
255
|
+
points: chunk
|
|
256
|
+
})) : yield surfaceDefWorker.send({
|
|
257
|
+
task: "parse-surface-points",
|
|
258
|
+
points: Pnts
|
|
259
|
+
});
|
|
260
|
+
const points = ptsIdArray.map((v) => v[1]);
|
|
261
|
+
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
262
|
+
const faces = Faces.length > CHUNK_THRESHOLD ? yield parallelChunks(Faces, CHUNK_COUNT, (chunk) => ({
|
|
263
|
+
task: "parse-surface-faces",
|
|
264
|
+
faces: chunk,
|
|
265
|
+
idMap: pointsIdMap
|
|
266
|
+
})) : yield surfaceDefWorker.send({
|
|
267
|
+
task: "parse-surface-faces",
|
|
268
|
+
faces: Faces,
|
|
269
|
+
idMap: pointsIdMap
|
|
270
|
+
});
|
|
271
|
+
const faceNeighbors = yield surfaceDefWorker.send({
|
|
272
|
+
task: "find-neighboring-faces",
|
|
273
|
+
faces
|
|
274
|
+
});
|
|
275
|
+
return {
|
|
276
|
+
sourceFile,
|
|
277
|
+
timeStamp,
|
|
278
|
+
name,
|
|
279
|
+
description: desc || "",
|
|
280
|
+
wktString,
|
|
281
|
+
surfaceDefinition: { points, faces, faceNeighbors }
|
|
282
|
+
};
|
|
298
283
|
}));
|
|
284
|
+
return Promise.all(surfaces);
|
|
299
285
|
});
|
|
300
286
|
var parse_xml_default = parseXML;
|
|
301
287
|
|
|
@@ -334,49 +320,45 @@ var contoursWorker = (0, import_easy_web_worker2.createEasyWebWorker)(
|
|
|
334
320
|
let vertsAtElevation = 0;
|
|
335
321
|
let line = [];
|
|
336
322
|
for (let i = 0; i < face.length; i++) {
|
|
337
|
-
|
|
338
|
-
|
|
323
|
+
const vertex1 = face[i];
|
|
324
|
+
const vertex2 = face[(i + 1) % face.length];
|
|
339
325
|
if (vertex1[2] === z) vertsAtElevation++;
|
|
340
326
|
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
341
|
-
|
|
327
|
+
const t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
342
328
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
343
329
|
}
|
|
344
330
|
}
|
|
345
331
|
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length) return void 0;
|
|
346
|
-
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
347
|
-
return void 0;
|
|
332
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1]) return void 0;
|
|
348
333
|
if (line.length > 2) {
|
|
349
334
|
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
350
335
|
}
|
|
351
336
|
return line.length > 0 ? line : void 0;
|
|
352
337
|
};
|
|
353
338
|
const linesToPolyLines3 = (lineSegments) => {
|
|
354
|
-
|
|
355
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
356
|
-
return [];
|
|
357
|
-
}
|
|
339
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
358
340
|
const segmentsMapIndexes = {};
|
|
359
341
|
const polylines = [];
|
|
360
|
-
const parsedSegmentIndexes =
|
|
342
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
361
343
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
362
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
363
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
364
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
365
|
-
});
|
|
366
344
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
367
|
-
|
|
368
|
-
|
|
345
|
+
const [start, end] = lineSegmentStrings[i];
|
|
346
|
+
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start], i] : [i];
|
|
347
|
+
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end], i] : [i];
|
|
348
|
+
}
|
|
349
|
+
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
350
|
+
if (parsedSegmentIndexes.has(i)) continue;
|
|
351
|
+
parsedSegmentIndexes.add(i);
|
|
369
352
|
let [start, end] = lineSegmentStrings[i];
|
|
370
|
-
|
|
353
|
+
const polyline = [start, end];
|
|
371
354
|
while (start && segmentsMapIndexes[start]) {
|
|
372
|
-
const nextLineIndex =
|
|
373
|
-
(
|
|
355
|
+
const nextLineIndex = segmentsMapIndexes[start].find(
|
|
356
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
374
357
|
);
|
|
375
|
-
if (nextLineIndex) {
|
|
376
|
-
parsedSegmentIndexes.
|
|
377
|
-
const
|
|
378
|
-
const
|
|
379
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
358
|
+
if (nextLineIndex !== void 0) {
|
|
359
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
360
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
361
|
+
const newPoint = a === start ? b : a;
|
|
380
362
|
polyline.unshift(newPoint);
|
|
381
363
|
start = newPoint;
|
|
382
364
|
} else {
|
|
@@ -384,14 +366,13 @@ var contoursWorker = (0, import_easy_web_worker2.createEasyWebWorker)(
|
|
|
384
366
|
}
|
|
385
367
|
}
|
|
386
368
|
while (end && segmentsMapIndexes[end]) {
|
|
387
|
-
const nextLineIndex =
|
|
388
|
-
(
|
|
369
|
+
const nextLineIndex = segmentsMapIndexes[end].find(
|
|
370
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
389
371
|
);
|
|
390
|
-
if (nextLineIndex) {
|
|
391
|
-
parsedSegmentIndexes.
|
|
392
|
-
const
|
|
393
|
-
const
|
|
394
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
372
|
+
if (nextLineIndex !== void 0) {
|
|
373
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
374
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
375
|
+
const newPoint = a === end ? b : a;
|
|
395
376
|
polyline.push(newPoint);
|
|
396
377
|
end = newPoint;
|
|
397
378
|
} else {
|
|
@@ -404,66 +385,51 @@ var contoursWorker = (0, import_easy_web_worker2.createEasyWebWorker)(
|
|
|
404
385
|
};
|
|
405
386
|
onMessage((message) => {
|
|
406
387
|
const { triangles, elevation } = message.payload;
|
|
407
|
-
const
|
|
388
|
+
const linesAtElevation = triangles.reduce((prev, curr) => {
|
|
408
389
|
const line = contourLineOnFace(curr, elevation);
|
|
409
390
|
if (line) prev.push(line);
|
|
410
391
|
return prev;
|
|
411
392
|
}, []);
|
|
412
|
-
message.resolve({
|
|
413
|
-
elevation,
|
|
414
|
-
polylines: linesToPolyLines3(linesAtElevationE)
|
|
415
|
-
});
|
|
393
|
+
message.resolve({ elevation, polylines: linesToPolyLines3(linesAtElevation) });
|
|
416
394
|
});
|
|
417
395
|
},
|
|
418
396
|
{ maxWorkers: 10 }
|
|
419
397
|
);
|
|
420
398
|
var linesToPolyLines = (lineSegments) => {
|
|
421
|
-
|
|
422
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
423
|
-
return [];
|
|
424
|
-
}
|
|
399
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
425
400
|
const segmentsMapIndexes = {};
|
|
426
401
|
const polylines = [];
|
|
427
|
-
const parsedSegmentIndexes =
|
|
402
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
428
403
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
429
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
430
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
431
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
432
|
-
});
|
|
433
404
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
434
|
-
|
|
435
|
-
|
|
405
|
+
const [start, end] = lineSegmentStrings[i];
|
|
406
|
+
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start], i] : [i];
|
|
407
|
+
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end], i] : [i];
|
|
408
|
+
}
|
|
409
|
+
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
410
|
+
if (parsedSegmentIndexes.has(i)) continue;
|
|
411
|
+
parsedSegmentIndexes.add(i);
|
|
436
412
|
let [start, end] = lineSegmentStrings[i];
|
|
437
|
-
|
|
413
|
+
const polyline = [start, end];
|
|
438
414
|
while (start && segmentsMapIndexes[start]) {
|
|
439
|
-
const nextLineIndex =
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
445
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === start ? 1 : 0;
|
|
446
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
415
|
+
const nextLineIndex = segmentsMapIndexes[start].find((li) => !parsedSegmentIndexes.has(li));
|
|
416
|
+
if (nextLineIndex !== void 0) {
|
|
417
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
418
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
419
|
+
const newPoint = a === start ? b : a;
|
|
447
420
|
polyline.unshift(newPoint);
|
|
448
421
|
start = newPoint;
|
|
449
|
-
} else
|
|
450
|
-
start = null;
|
|
451
|
-
}
|
|
422
|
+
} else start = null;
|
|
452
423
|
}
|
|
453
424
|
while (end && segmentsMapIndexes[end]) {
|
|
454
|
-
const nextLineIndex =
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
460
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === end ? 1 : 0;
|
|
461
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
425
|
+
const nextLineIndex = segmentsMapIndexes[end].find((li) => !parsedSegmentIndexes.has(li));
|
|
426
|
+
if (nextLineIndex !== void 0) {
|
|
427
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
428
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
429
|
+
const newPoint = a === end ? b : a;
|
|
462
430
|
polyline.push(newPoint);
|
|
463
431
|
end = newPoint;
|
|
464
|
-
} else
|
|
465
|
-
end = null;
|
|
466
|
-
}
|
|
432
|
+
} else end = null;
|
|
467
433
|
}
|
|
468
434
|
polylines.push(polyline.map((coord) => coord.split(",").map((v) => parseFloat(v))));
|
|
469
435
|
}
|
|
@@ -477,10 +443,10 @@ var contourElevations = (minElevation, maxElevation, interval) => {
|
|
|
477
443
|
throw new Error(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
478
444
|
}
|
|
479
445
|
const elevations = [];
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
446
|
+
const firstStep = Math.ceil(minElevation / interval);
|
|
447
|
+
const lastStep = Math.ceil(maxElevation / interval) - 1;
|
|
448
|
+
for (let step = firstStep; step <= lastStep; step++) {
|
|
449
|
+
elevations.push(step * interval);
|
|
484
450
|
}
|
|
485
451
|
return elevations;
|
|
486
452
|
};
|
|
@@ -490,31 +456,55 @@ var constructGeojson = (elevationData) => {
|
|
|
490
456
|
return prev.concat(
|
|
491
457
|
polylines.map((polyline) => ({
|
|
492
458
|
type: "Feature",
|
|
493
|
-
geometry: {
|
|
494
|
-
|
|
495
|
-
coordinates: polyline
|
|
496
|
-
},
|
|
497
|
-
properties: {
|
|
498
|
-
z: elevation
|
|
499
|
-
}
|
|
459
|
+
geometry: { type: "LineString", coordinates: polyline },
|
|
460
|
+
properties: { z: elevation }
|
|
500
461
|
}))
|
|
501
462
|
);
|
|
502
463
|
}, []);
|
|
503
|
-
return {
|
|
504
|
-
type: "FeatureCollection",
|
|
505
|
-
features
|
|
506
|
-
};
|
|
464
|
+
return { type: "FeatureCollection", features };
|
|
507
465
|
};
|
|
508
|
-
var
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
const
|
|
513
|
-
([
|
|
514
|
-
[
|
|
515
|
-
|
|
466
|
+
var precomputeSurfaceData = (data) => {
|
|
467
|
+
const { points, faces } = data.surfaceDefinition;
|
|
468
|
+
let minElevation = Infinity;
|
|
469
|
+
let maxElevation = -Infinity;
|
|
470
|
+
for (const pt of points) {
|
|
471
|
+
if (pt[2] < minElevation) minElevation = pt[2];
|
|
472
|
+
if (pt[2] > maxElevation) maxElevation = pt[2];
|
|
473
|
+
}
|
|
474
|
+
const triangles = faces.map((face) => face.map((vert) => points[vert]));
|
|
475
|
+
return { triangles, minElevation, maxElevation };
|
|
476
|
+
};
|
|
477
|
+
var bucketTrianglesByElevation = (triangles, elevations, interval) => {
|
|
478
|
+
const trianglesByElevation = /* @__PURE__ */ new Map();
|
|
479
|
+
for (const e of elevations) trianglesByElevation.set(e, []);
|
|
480
|
+
for (const tri of triangles) {
|
|
481
|
+
const zMin = Math.min(tri[0][2], tri[1][2], tri[2][2]);
|
|
482
|
+
const zMax = Math.max(tri[0][2], tri[1][2], tri[2][2]);
|
|
483
|
+
const firstStep = Math.ceil(zMin / interval);
|
|
484
|
+
const lastStep = Math.floor(zMax / interval);
|
|
485
|
+
for (let step = firstStep; step <= lastStep; step++) {
|
|
486
|
+
const rounded = step * interval;
|
|
487
|
+
const bucket = trianglesByElevation.get(rounded);
|
|
488
|
+
if (bucket) bucket.push(tri);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return trianglesByElevation;
|
|
492
|
+
};
|
|
493
|
+
var getContours = (data, interval = 2, precomputed) => __async(null, null, function* () {
|
|
494
|
+
const { triangles, minElevation, maxElevation } = precomputed != null ? precomputed : precomputeSurfaceData(data);
|
|
516
495
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
517
|
-
const
|
|
496
|
+
const trianglesByElevation = bucketTrianglesByElevation(triangles, elevations, interval);
|
|
497
|
+
const elevationPolylines = yield Promise.all(
|
|
498
|
+
elevations.map(
|
|
499
|
+
(elevation) => {
|
|
500
|
+
var _a;
|
|
501
|
+
return contoursWorker.send({
|
|
502
|
+
triangles: (_a = trianglesByElevation.get(elevation)) != null ? _a : [],
|
|
503
|
+
elevation
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
)
|
|
507
|
+
);
|
|
518
508
|
return constructGeojson(elevationPolylines);
|
|
519
509
|
});
|
|
520
510
|
var get_contours_default = getContours;
|
|
@@ -597,9 +587,41 @@ var reprojectGeoJson = (geojson, sourceProjection, targetProjection = "WGS84", k
|
|
|
597
587
|
return geojson;
|
|
598
588
|
};
|
|
599
589
|
var reproject_geojson_default = reprojectGeoJson;
|
|
590
|
+
|
|
591
|
+
// src/public/to-glb-and-contours.ts
|
|
592
|
+
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
|
+
const requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
595
|
+
const results = yield Promise.all(
|
|
596
|
+
requestedParsedSurfaces.map((surface) => __async(null, null, function* () {
|
|
597
|
+
const precomputed = precomputeSurfaceData(surface);
|
|
598
|
+
const [{ glb, center: resolvedCenter }, geojson] = yield Promise.all([
|
|
599
|
+
get_glb_default(surface, requestedCenter),
|
|
600
|
+
get_contours_default(surface, contourInterval, precomputed)
|
|
601
|
+
]);
|
|
602
|
+
if (generateOutline) {
|
|
603
|
+
const outlineGeojson = get_outline_default(surface);
|
|
604
|
+
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
605
|
+
}
|
|
606
|
+
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
607
|
+
return __spreadProps(__spreadValues({}, rest), {
|
|
608
|
+
glb,
|
|
609
|
+
center: resolvedCenter,
|
|
610
|
+
download: () => {
|
|
611
|
+
download_glb_default(glb, surface.name.replace(/\.xml$/, `${JSON.stringify(resolvedCenter)}.glb`));
|
|
612
|
+
},
|
|
613
|
+
geojson
|
|
614
|
+
});
|
|
615
|
+
}))
|
|
616
|
+
);
|
|
617
|
+
return results;
|
|
618
|
+
});
|
|
619
|
+
var to_glb_and_contours_default = toGlbAndContours;
|
|
600
620
|
// Annotate the CommonJS export names for ESM import in node:
|
|
601
621
|
0 && (module.exports = {
|
|
622
|
+
precomputeSurfaceData,
|
|
602
623
|
reprojectGeoJson,
|
|
603
624
|
toGeojsonContours,
|
|
604
|
-
toGlb
|
|
625
|
+
toGlb,
|
|
626
|
+
toGlbAndContours
|
|
605
627
|
});
|