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.mjs
CHANGED
|
@@ -78,18 +78,30 @@ var findXYAxisMedians = (vertices) => {
|
|
|
78
78
|
};
|
|
79
79
|
var getGlb = (data, customCenter) => __async(null, null, function* () {
|
|
80
80
|
const center = customCenter || findXYAxisMedians(data.surfaceDefinition.points);
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
const pts = data.surfaceDefinition.points;
|
|
82
|
+
const facesFlat = data.surfaceDefinition.faces;
|
|
83
|
+
const vertexBuffer = new Float32Array(pts.length * 3);
|
|
84
|
+
for (let i = 0; i < pts.length; i++) {
|
|
85
|
+
const [x, y, z] = pts[i];
|
|
86
|
+
vertexBuffer[i * 3] = x - center[0];
|
|
87
|
+
vertexBuffer[i * 3 + 1] = z;
|
|
88
|
+
vertexBuffer[i * 3 + 2] = -(y - center[1]);
|
|
89
|
+
}
|
|
90
|
+
const indexBuffer = new Uint32Array(facesFlat.length * 3);
|
|
91
|
+
for (let i = 0; i < facesFlat.length; i++) {
|
|
92
|
+
const [a, b, c] = facesFlat[i];
|
|
93
|
+
indexBuffer[i * 3] = a;
|
|
94
|
+
indexBuffer[i * 3 + 1] = b;
|
|
95
|
+
indexBuffer[i * 3 + 2] = c;
|
|
96
|
+
}
|
|
85
97
|
const doc = new Document();
|
|
86
98
|
const buffer = doc.createBuffer();
|
|
87
|
-
const position = doc.createAccessor().setType("VEC3").setArray(
|
|
88
|
-
const indices = doc.createAccessor().setType("SCALAR").setArray(
|
|
99
|
+
const position = doc.createAccessor().setType("VEC3").setArray(vertexBuffer).setBuffer(buffer);
|
|
100
|
+
const indices = doc.createAccessor().setType("SCALAR").setArray(indexBuffer).setBuffer(buffer);
|
|
89
101
|
const prim = doc.createPrimitive().setAttribute("POSITION", position).setIndices(indices);
|
|
90
102
|
const mesh = doc.createMesh().addPrimitive(prim);
|
|
91
103
|
const node = doc.createNode().setMesh(mesh);
|
|
92
|
-
|
|
104
|
+
doc.createScene().addChild(node);
|
|
93
105
|
const glb = yield new WebIO().writeBinary(doc);
|
|
94
106
|
return { glb, center };
|
|
95
107
|
});
|
|
@@ -133,14 +145,29 @@ var surfaceDefWorker = createEasyWebWorker(
|
|
|
133
145
|
})
|
|
134
146
|
);
|
|
135
147
|
} else if (task === "find-neighboring-faces") {
|
|
136
|
-
const { faces
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
const { faces } = message.payload;
|
|
149
|
+
const edgeMap = /* @__PURE__ */ new Map();
|
|
150
|
+
const edgeKey = (a, b) => a < b ? `${a},${b}` : `${b},${a}`;
|
|
151
|
+
for (let i = 0; i < faces.length; i++) {
|
|
152
|
+
const [v0, v1, v2] = faces[i];
|
|
153
|
+
for (const key of [edgeKey(v0, v1), edgeKey(v1, v2), edgeKey(v0, v2)]) {
|
|
154
|
+
const existing = edgeMap.get(key);
|
|
155
|
+
if (!existing) {
|
|
156
|
+
edgeMap.set(key, [i]);
|
|
157
|
+
} else if (existing.length === 1) {
|
|
158
|
+
existing.push(i);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const faceNeighbors = new Array(faces.length);
|
|
163
|
+
for (let i = 0; i < faces.length; i++) {
|
|
164
|
+
const [v0, v1, v2] = faces[i];
|
|
165
|
+
const resolve = (key) => {
|
|
166
|
+
const pair = edgeMap.get(key);
|
|
167
|
+
if (!pair || pair.length < 2) return -1;
|
|
168
|
+
return pair[0] === i ? pair[1] : pair[0];
|
|
169
|
+
};
|
|
170
|
+
faceNeighbors[i] = [resolve(edgeKey(v0, v1)), resolve(edgeKey(v1, v2)), resolve(edgeKey(v0, v2))];
|
|
144
171
|
}
|
|
145
172
|
message.resolve(faceNeighbors);
|
|
146
173
|
}
|
|
@@ -151,116 +178,73 @@ var surfaceDefWorker = createEasyWebWorker(
|
|
|
151
178
|
},
|
|
152
179
|
{ maxWorkers: 16 }
|
|
153
180
|
);
|
|
154
|
-
|
|
155
|
-
return
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
163
|
-
throw new Error("LandXML doesn't contain any surfaces");
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
167
|
-
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
168
|
-
}
|
|
169
|
-
let sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
170
|
-
let timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
171
|
-
let wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
172
|
-
const surfaces = parsed.LandXML.Surfaces.Surface.map(
|
|
173
|
-
(surface) => __async(null, null, function* () {
|
|
174
|
-
return new Promise((resolve2, reject2) => __async(null, null, function* () {
|
|
175
|
-
const { name, desc } = surface.attr;
|
|
176
|
-
const Pnts = surface.Definition.Pnts.P;
|
|
177
|
-
const Faces = surface.Definition.Faces.F;
|
|
178
|
-
let ptsIdArray = [];
|
|
179
|
-
let faces = [];
|
|
180
|
-
let faceNeighbors = [];
|
|
181
|
-
if (Pnts.length > 1e4) {
|
|
182
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Pnts.length / 20 * i));
|
|
183
|
-
ptsIdArray = (yield Promise.all(
|
|
184
|
-
sliceIndexes.map(
|
|
185
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(null, null, function* () {
|
|
186
|
-
const pts = yield surfaceDefWorker.send({
|
|
187
|
-
task: "parse-surface-points",
|
|
188
|
-
points: Pnts.slice(a[i], a[i + 1] || Pnts.length)
|
|
189
|
-
});
|
|
190
|
-
resolve3(pts);
|
|
191
|
-
}))
|
|
192
|
-
)
|
|
193
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
194
|
-
} else {
|
|
195
|
-
ptsIdArray = yield surfaceDefWorker.send({ task: "parse-surface-points", points: Pnts });
|
|
196
|
-
}
|
|
197
|
-
const points = ptsIdArray.map((v) => v[1]);
|
|
198
|
-
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
199
|
-
if (Faces.length > 1e4) {
|
|
200
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Faces.length / 20 * i));
|
|
201
|
-
faces = (yield Promise.all(
|
|
202
|
-
sliceIndexes.map(
|
|
203
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(null, null, function* () {
|
|
204
|
-
const fcs = yield surfaceDefWorker.send({
|
|
205
|
-
task: "parse-surface-faces",
|
|
206
|
-
faces: Faces.slice(a[i], a[i + 1] || Faces.length),
|
|
207
|
-
idMap: pointsIdMap
|
|
208
|
-
});
|
|
209
|
-
resolve3(fcs);
|
|
210
|
-
}))
|
|
211
|
-
)
|
|
212
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
213
|
-
} else {
|
|
214
|
-
faces = yield surfaceDefWorker.send({
|
|
215
|
-
task: "parse-surface-faces",
|
|
216
|
-
faces: Faces,
|
|
217
|
-
idMap: pointsIdMap
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
if (Faces.length > 1e4) {
|
|
221
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round((faces.length - 1) / 20 * i));
|
|
222
|
-
faceNeighbors = (yield Promise.all(
|
|
223
|
-
sliceIndexes.map(
|
|
224
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(null, null, function* () {
|
|
225
|
-
const fcs = yield surfaceDefWorker.send({
|
|
226
|
-
task: "find-neighboring-faces",
|
|
227
|
-
faces,
|
|
228
|
-
range: {
|
|
229
|
-
start: a[i],
|
|
230
|
-
end: a[i + 1] || faces.length
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
resolve3(fcs);
|
|
234
|
-
}))
|
|
235
|
-
)
|
|
236
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
237
|
-
} else {
|
|
238
|
-
faceNeighbors = yield surfaceDefWorker.send({
|
|
239
|
-
task: "find-neighboring-faces",
|
|
240
|
-
faces,
|
|
241
|
-
range: {
|
|
242
|
-
start: 0,
|
|
243
|
-
end: faces.length
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
resolve2({
|
|
248
|
-
sourceFile,
|
|
249
|
-
timeStamp: timeStamp || "",
|
|
250
|
-
name,
|
|
251
|
-
description: desc || "",
|
|
252
|
-
wktString,
|
|
253
|
-
surfaceDefinition: {
|
|
254
|
-
points,
|
|
255
|
-
faces,
|
|
256
|
-
faceNeighbors
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
}));
|
|
181
|
+
function parallelChunks(items, count, makePayload) {
|
|
182
|
+
return __async(this, null, function* () {
|
|
183
|
+
const sliceIndexes = [...Array(count).keys()].map((i) => Math.round(items.length / count * i));
|
|
184
|
+
const chunks = yield Promise.all(
|
|
185
|
+
sliceIndexes.map((start, i, arr) => {
|
|
186
|
+
var _a;
|
|
187
|
+
const end = (_a = arr[i + 1]) != null ? _a : items.length;
|
|
188
|
+
return surfaceDefWorker.send(makePayload(items.slice(start, end), start, end));
|
|
260
189
|
})
|
|
261
190
|
);
|
|
262
|
-
|
|
191
|
+
return chunks.reduce((acc, c) => acc.concat(c), []);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
var CHUNK_THRESHOLD = 1e4;
|
|
195
|
+
var CHUNK_COUNT = 20;
|
|
196
|
+
var parseXML = (xmlString) => __async(null, null, function* () {
|
|
197
|
+
var _a, _b, _c, _d, _e;
|
|
198
|
+
const parsed = convert.xml2js(xmlString, {
|
|
199
|
+
compact: true,
|
|
200
|
+
attributesKey: "attr",
|
|
201
|
+
textKey: "content"
|
|
202
|
+
});
|
|
203
|
+
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
204
|
+
throw new Error("LandXML doesn't contain any surfaces");
|
|
205
|
+
}
|
|
206
|
+
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
207
|
+
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
208
|
+
}
|
|
209
|
+
const sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
210
|
+
const timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
211
|
+
const wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
212
|
+
const surfaces = parsed.LandXML.Surfaces.Surface.map((surface) => __async(null, null, function* () {
|
|
213
|
+
const { name, desc } = surface.attr;
|
|
214
|
+
const Pnts = surface.Definition.Pnts.P;
|
|
215
|
+
const Faces = surface.Definition.Faces.F;
|
|
216
|
+
const ptsIdArray = Pnts.length > CHUNK_THRESHOLD ? yield parallelChunks(Pnts, CHUNK_COUNT, (chunk) => ({
|
|
217
|
+
task: "parse-surface-points",
|
|
218
|
+
points: chunk
|
|
219
|
+
})) : yield surfaceDefWorker.send({
|
|
220
|
+
task: "parse-surface-points",
|
|
221
|
+
points: Pnts
|
|
222
|
+
});
|
|
223
|
+
const points = ptsIdArray.map((v) => v[1]);
|
|
224
|
+
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
225
|
+
const faces = Faces.length > CHUNK_THRESHOLD ? yield parallelChunks(Faces, CHUNK_COUNT, (chunk) => ({
|
|
226
|
+
task: "parse-surface-faces",
|
|
227
|
+
faces: chunk,
|
|
228
|
+
idMap: pointsIdMap
|
|
229
|
+
})) : yield surfaceDefWorker.send({
|
|
230
|
+
task: "parse-surface-faces",
|
|
231
|
+
faces: Faces,
|
|
232
|
+
idMap: pointsIdMap
|
|
233
|
+
});
|
|
234
|
+
const faceNeighbors = yield surfaceDefWorker.send({
|
|
235
|
+
task: "find-neighboring-faces",
|
|
236
|
+
faces
|
|
237
|
+
});
|
|
238
|
+
return {
|
|
239
|
+
sourceFile,
|
|
240
|
+
timeStamp,
|
|
241
|
+
name,
|
|
242
|
+
description: desc || "",
|
|
243
|
+
wktString,
|
|
244
|
+
surfaceDefinition: { points, faces, faceNeighbors }
|
|
245
|
+
};
|
|
263
246
|
}));
|
|
247
|
+
return Promise.all(surfaces);
|
|
264
248
|
});
|
|
265
249
|
var parse_xml_default = parseXML;
|
|
266
250
|
|
|
@@ -299,49 +283,45 @@ var contoursWorker = createEasyWebWorker2(
|
|
|
299
283
|
let vertsAtElevation = 0;
|
|
300
284
|
let line = [];
|
|
301
285
|
for (let i = 0; i < face.length; i++) {
|
|
302
|
-
|
|
303
|
-
|
|
286
|
+
const vertex1 = face[i];
|
|
287
|
+
const vertex2 = face[(i + 1) % face.length];
|
|
304
288
|
if (vertex1[2] === z) vertsAtElevation++;
|
|
305
289
|
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
306
|
-
|
|
290
|
+
const t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
307
291
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
308
292
|
}
|
|
309
293
|
}
|
|
310
294
|
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length) return void 0;
|
|
311
|
-
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
312
|
-
return void 0;
|
|
295
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1]) return void 0;
|
|
313
296
|
if (line.length > 2) {
|
|
314
297
|
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
315
298
|
}
|
|
316
299
|
return line.length > 0 ? line : void 0;
|
|
317
300
|
};
|
|
318
301
|
const linesToPolyLines3 = (lineSegments) => {
|
|
319
|
-
|
|
320
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
321
|
-
return [];
|
|
322
|
-
}
|
|
302
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
323
303
|
const segmentsMapIndexes = {};
|
|
324
304
|
const polylines = [];
|
|
325
|
-
const parsedSegmentIndexes =
|
|
305
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
326
306
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
327
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
328
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
329
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
330
|
-
});
|
|
331
307
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
332
|
-
|
|
333
|
-
|
|
308
|
+
const [start, end] = lineSegmentStrings[i];
|
|
309
|
+
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start], i] : [i];
|
|
310
|
+
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end], i] : [i];
|
|
311
|
+
}
|
|
312
|
+
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
313
|
+
if (parsedSegmentIndexes.has(i)) continue;
|
|
314
|
+
parsedSegmentIndexes.add(i);
|
|
334
315
|
let [start, end] = lineSegmentStrings[i];
|
|
335
|
-
|
|
316
|
+
const polyline = [start, end];
|
|
336
317
|
while (start && segmentsMapIndexes[start]) {
|
|
337
|
-
const nextLineIndex =
|
|
338
|
-
(
|
|
318
|
+
const nextLineIndex = segmentsMapIndexes[start].find(
|
|
319
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
339
320
|
);
|
|
340
|
-
if (nextLineIndex) {
|
|
341
|
-
parsedSegmentIndexes.
|
|
342
|
-
const
|
|
343
|
-
const
|
|
344
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
321
|
+
if (nextLineIndex !== void 0) {
|
|
322
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
323
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
324
|
+
const newPoint = a === start ? b : a;
|
|
345
325
|
polyline.unshift(newPoint);
|
|
346
326
|
start = newPoint;
|
|
347
327
|
} else {
|
|
@@ -349,14 +329,13 @@ var contoursWorker = createEasyWebWorker2(
|
|
|
349
329
|
}
|
|
350
330
|
}
|
|
351
331
|
while (end && segmentsMapIndexes[end]) {
|
|
352
|
-
const nextLineIndex =
|
|
353
|
-
(
|
|
332
|
+
const nextLineIndex = segmentsMapIndexes[end].find(
|
|
333
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
354
334
|
);
|
|
355
|
-
if (nextLineIndex) {
|
|
356
|
-
parsedSegmentIndexes.
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
335
|
+
if (nextLineIndex !== void 0) {
|
|
336
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
337
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
338
|
+
const newPoint = a === end ? b : a;
|
|
360
339
|
polyline.push(newPoint);
|
|
361
340
|
end = newPoint;
|
|
362
341
|
} else {
|
|
@@ -369,66 +348,51 @@ var contoursWorker = createEasyWebWorker2(
|
|
|
369
348
|
};
|
|
370
349
|
onMessage((message) => {
|
|
371
350
|
const { triangles, elevation } = message.payload;
|
|
372
|
-
const
|
|
351
|
+
const linesAtElevation = triangles.reduce((prev, curr) => {
|
|
373
352
|
const line = contourLineOnFace(curr, elevation);
|
|
374
353
|
if (line) prev.push(line);
|
|
375
354
|
return prev;
|
|
376
355
|
}, []);
|
|
377
|
-
message.resolve({
|
|
378
|
-
elevation,
|
|
379
|
-
polylines: linesToPolyLines3(linesAtElevationE)
|
|
380
|
-
});
|
|
356
|
+
message.resolve({ elevation, polylines: linesToPolyLines3(linesAtElevation) });
|
|
381
357
|
});
|
|
382
358
|
},
|
|
383
359
|
{ maxWorkers: 10 }
|
|
384
360
|
);
|
|
385
361
|
var linesToPolyLines = (lineSegments) => {
|
|
386
|
-
|
|
387
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
388
|
-
return [];
|
|
389
|
-
}
|
|
362
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
390
363
|
const segmentsMapIndexes = {};
|
|
391
364
|
const polylines = [];
|
|
392
|
-
const parsedSegmentIndexes =
|
|
365
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
393
366
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
394
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
395
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
396
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
397
|
-
});
|
|
398
367
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
399
|
-
|
|
400
|
-
|
|
368
|
+
const [start, end] = lineSegmentStrings[i];
|
|
369
|
+
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start], i] : [i];
|
|
370
|
+
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end], i] : [i];
|
|
371
|
+
}
|
|
372
|
+
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
373
|
+
if (parsedSegmentIndexes.has(i)) continue;
|
|
374
|
+
parsedSegmentIndexes.add(i);
|
|
401
375
|
let [start, end] = lineSegmentStrings[i];
|
|
402
|
-
|
|
376
|
+
const polyline = [start, end];
|
|
403
377
|
while (start && segmentsMapIndexes[start]) {
|
|
404
|
-
const nextLineIndex =
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
410
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === start ? 1 : 0;
|
|
411
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
378
|
+
const nextLineIndex = segmentsMapIndexes[start].find((li) => !parsedSegmentIndexes.has(li));
|
|
379
|
+
if (nextLineIndex !== void 0) {
|
|
380
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
381
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
382
|
+
const newPoint = a === start ? b : a;
|
|
412
383
|
polyline.unshift(newPoint);
|
|
413
384
|
start = newPoint;
|
|
414
|
-
} else
|
|
415
|
-
start = null;
|
|
416
|
-
}
|
|
385
|
+
} else start = null;
|
|
417
386
|
}
|
|
418
387
|
while (end && segmentsMapIndexes[end]) {
|
|
419
|
-
const nextLineIndex =
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
425
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === end ? 1 : 0;
|
|
426
|
-
const newPoint = nextLineSegment[nextLineSegmentPointIndex];
|
|
388
|
+
const nextLineIndex = segmentsMapIndexes[end].find((li) => !parsedSegmentIndexes.has(li));
|
|
389
|
+
if (nextLineIndex !== void 0) {
|
|
390
|
+
parsedSegmentIndexes.add(nextLineIndex);
|
|
391
|
+
const [a, b] = lineSegmentStrings[nextLineIndex];
|
|
392
|
+
const newPoint = a === end ? b : a;
|
|
427
393
|
polyline.push(newPoint);
|
|
428
394
|
end = newPoint;
|
|
429
|
-
} else
|
|
430
|
-
end = null;
|
|
431
|
-
}
|
|
395
|
+
} else end = null;
|
|
432
396
|
}
|
|
433
397
|
polylines.push(polyline.map((coord) => coord.split(",").map((v) => parseFloat(v))));
|
|
434
398
|
}
|
|
@@ -442,10 +406,10 @@ var contourElevations = (minElevation, maxElevation, interval) => {
|
|
|
442
406
|
throw new Error(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
443
407
|
}
|
|
444
408
|
const elevations = [];
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
409
|
+
const firstStep = Math.ceil(minElevation / interval);
|
|
410
|
+
const lastStep = Math.ceil(maxElevation / interval) - 1;
|
|
411
|
+
for (let step = firstStep; step <= lastStep; step++) {
|
|
412
|
+
elevations.push(step * interval);
|
|
449
413
|
}
|
|
450
414
|
return elevations;
|
|
451
415
|
};
|
|
@@ -455,31 +419,55 @@ var constructGeojson = (elevationData) => {
|
|
|
455
419
|
return prev.concat(
|
|
456
420
|
polylines.map((polyline) => ({
|
|
457
421
|
type: "Feature",
|
|
458
|
-
geometry: {
|
|
459
|
-
|
|
460
|
-
coordinates: polyline
|
|
461
|
-
},
|
|
462
|
-
properties: {
|
|
463
|
-
z: elevation
|
|
464
|
-
}
|
|
422
|
+
geometry: { type: "LineString", coordinates: polyline },
|
|
423
|
+
properties: { z: elevation }
|
|
465
424
|
}))
|
|
466
425
|
);
|
|
467
426
|
}, []);
|
|
468
|
-
return {
|
|
469
|
-
type: "FeatureCollection",
|
|
470
|
-
features
|
|
471
|
-
};
|
|
427
|
+
return { type: "FeatureCollection", features };
|
|
472
428
|
};
|
|
473
|
-
var
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
([
|
|
479
|
-
[
|
|
480
|
-
|
|
429
|
+
var precomputeSurfaceData = (data) => {
|
|
430
|
+
const { points, faces } = data.surfaceDefinition;
|
|
431
|
+
let minElevation = Infinity;
|
|
432
|
+
let maxElevation = -Infinity;
|
|
433
|
+
for (const pt of points) {
|
|
434
|
+
if (pt[2] < minElevation) minElevation = pt[2];
|
|
435
|
+
if (pt[2] > maxElevation) maxElevation = pt[2];
|
|
436
|
+
}
|
|
437
|
+
const triangles = faces.map((face) => face.map((vert) => points[vert]));
|
|
438
|
+
return { triangles, minElevation, maxElevation };
|
|
439
|
+
};
|
|
440
|
+
var bucketTrianglesByElevation = (triangles, elevations, interval) => {
|
|
441
|
+
const trianglesByElevation = /* @__PURE__ */ new Map();
|
|
442
|
+
for (const e of elevations) trianglesByElevation.set(e, []);
|
|
443
|
+
for (const tri of triangles) {
|
|
444
|
+
const zMin = Math.min(tri[0][2], tri[1][2], tri[2][2]);
|
|
445
|
+
const zMax = Math.max(tri[0][2], tri[1][2], tri[2][2]);
|
|
446
|
+
const firstStep = Math.ceil(zMin / interval);
|
|
447
|
+
const lastStep = Math.floor(zMax / interval);
|
|
448
|
+
for (let step = firstStep; step <= lastStep; step++) {
|
|
449
|
+
const rounded = step * interval;
|
|
450
|
+
const bucket = trianglesByElevation.get(rounded);
|
|
451
|
+
if (bucket) bucket.push(tri);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return trianglesByElevation;
|
|
455
|
+
};
|
|
456
|
+
var getContours = (data, interval = 2, precomputed) => __async(null, null, function* () {
|
|
457
|
+
const { triangles, minElevation, maxElevation } = precomputed != null ? precomputed : precomputeSurfaceData(data);
|
|
481
458
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
482
|
-
const
|
|
459
|
+
const trianglesByElevation = bucketTrianglesByElevation(triangles, elevations, interval);
|
|
460
|
+
const elevationPolylines = yield Promise.all(
|
|
461
|
+
elevations.map(
|
|
462
|
+
(elevation) => {
|
|
463
|
+
var _a;
|
|
464
|
+
return contoursWorker.send({
|
|
465
|
+
triangles: (_a = trianglesByElevation.get(elevation)) != null ? _a : [],
|
|
466
|
+
elevation
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
)
|
|
470
|
+
);
|
|
483
471
|
return constructGeojson(elevationPolylines);
|
|
484
472
|
});
|
|
485
473
|
var get_contours_default = getContours;
|
|
@@ -562,8 +550,40 @@ var reprojectGeoJson = (geojson, sourceProjection, targetProjection = "WGS84", k
|
|
|
562
550
|
return geojson;
|
|
563
551
|
};
|
|
564
552
|
var reproject_geojson_default = reprojectGeoJson;
|
|
553
|
+
|
|
554
|
+
// src/public/to-glb-and-contours.ts
|
|
555
|
+
var toGlbAndContours = (landXmlString, contourInterval = 2, generateOutline = true, center = "auto", surfaceId = -1) => __async(null, null, function* () {
|
|
556
|
+
const requestedCenter = center === "origin" ? [0, 0] : center === "auto" ? void 0 : center;
|
|
557
|
+
const requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
558
|
+
const results = yield Promise.all(
|
|
559
|
+
requestedParsedSurfaces.map((surface) => __async(null, null, function* () {
|
|
560
|
+
const precomputed = precomputeSurfaceData(surface);
|
|
561
|
+
const [{ glb, center: resolvedCenter }, geojson] = yield Promise.all([
|
|
562
|
+
get_glb_default(surface, requestedCenter),
|
|
563
|
+
get_contours_default(surface, contourInterval, precomputed)
|
|
564
|
+
]);
|
|
565
|
+
if (generateOutline) {
|
|
566
|
+
const outlineGeojson = get_outline_default(surface);
|
|
567
|
+
geojson.features = [...geojson.features, ...outlineGeojson.features];
|
|
568
|
+
}
|
|
569
|
+
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
570
|
+
return __spreadProps(__spreadValues({}, rest), {
|
|
571
|
+
glb,
|
|
572
|
+
center: resolvedCenter,
|
|
573
|
+
download: () => {
|
|
574
|
+
download_glb_default(glb, surface.name.replace(/\.xml$/, `${JSON.stringify(resolvedCenter)}.glb`));
|
|
575
|
+
},
|
|
576
|
+
geojson
|
|
577
|
+
});
|
|
578
|
+
}))
|
|
579
|
+
);
|
|
580
|
+
return results;
|
|
581
|
+
});
|
|
582
|
+
var to_glb_and_contours_default = toGlbAndContours;
|
|
565
583
|
export {
|
|
584
|
+
precomputeSurfaceData,
|
|
566
585
|
reproject_geojson_default as reprojectGeoJson,
|
|
567
586
|
to_geojson_contours_default as toGeojsonContours,
|
|
568
|
-
to_glb_default as toGlb
|
|
587
|
+
to_glb_default as toGlb,
|
|
588
|
+
to_glb_and_contours_default as toGlbAndContours
|
|
569
589
|
};
|