landxml 0.6.4 → 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 +21 -0
- package/README.md +168 -28
- package/dist/index.d.mts +66 -1
- package/dist/index.d.ts +66 -1
- package/dist/index.js +257 -246
- package/dist/index.mjs +251 -242
- package/package.json +10 -11
package/dist/index.js
CHANGED
|
@@ -77,21 +77,22 @@ var __async = (__this, __arguments, generator) => {
|
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
// src/index.ts
|
|
80
|
-
var
|
|
81
|
-
__export(
|
|
80
|
+
var index_exports = {};
|
|
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
|
-
module.exports = __toCommonJS(
|
|
88
|
+
module.exports = __toCommonJS(index_exports);
|
|
87
89
|
|
|
88
90
|
// src/private/filter-by-surfaceId.ts
|
|
89
91
|
var filterBySurfaceId = (parsedSurfaces, surfaceId) => {
|
|
90
92
|
let filtered = [...parsedSurfaces];
|
|
91
93
|
if (typeof surfaceId === "string") {
|
|
92
94
|
filtered = filtered.filter((s) => s.name === surfaceId);
|
|
93
|
-
if (filtered.length === 0)
|
|
94
|
-
throw "Provided SurfaceId doesn't exist within provided LandXML";
|
|
95
|
+
if (filtered.length === 0) throw "Provided SurfaceId doesn't exist within provided LandXML";
|
|
95
96
|
}
|
|
96
97
|
if (typeof surfaceId === "number" && surfaceId > 0) {
|
|
97
98
|
if (!filtered[surfaceId])
|
|
@@ -112,20 +113,32 @@ var findXYAxisMedians = (vertices) => {
|
|
|
112
113
|
const medianY = (_b = vertices.slice().sort((a, b) => a[1] - b[1])[middleIndex]) == null ? void 0 : _b[1];
|
|
113
114
|
return [medianX, medianY];
|
|
114
115
|
};
|
|
115
|
-
var getGlb = (data, customCenter) => __async(
|
|
116
|
+
var getGlb = (data, customCenter) => __async(null, null, function* () {
|
|
116
117
|
const center = customCenter || findXYAxisMedians(data.surfaceDefinition.points);
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
+
}
|
|
121
134
|
const doc = new import_core.Document();
|
|
122
135
|
const buffer = doc.createBuffer();
|
|
123
|
-
const position = doc.createAccessor().setType("VEC3").setArray(
|
|
124
|
-
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);
|
|
125
138
|
const prim = doc.createPrimitive().setAttribute("POSITION", position).setIndices(indices);
|
|
126
139
|
const mesh = doc.createMesh().addPrimitive(prim);
|
|
127
140
|
const node = doc.createNode().setMesh(mesh);
|
|
128
|
-
|
|
141
|
+
doc.createScene().addChild(node);
|
|
129
142
|
const glb = yield new import_core.WebIO().writeBinary(doc);
|
|
130
143
|
return { glb, center };
|
|
131
144
|
});
|
|
@@ -164,20 +177,34 @@ var surfaceDefWorker = (0, import_easy_web_worker.createEasyWebWorker)(
|
|
|
164
177
|
var _a;
|
|
165
178
|
if (typeof f === "string")
|
|
166
179
|
return [f.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
167
|
-
if (((_a = f == null ? void 0 : f.attr) == null ? void 0 : _a.i) === "1")
|
|
168
|
-
return [];
|
|
180
|
+
if (((_a = f == null ? void 0 : f.attr) == null ? void 0 : _a.i) === "1") return [];
|
|
169
181
|
return [f.content.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
170
182
|
})
|
|
171
183
|
);
|
|
172
184
|
} else if (task === "find-neighboring-faces") {
|
|
173
|
-
const { faces
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
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))];
|
|
181
208
|
}
|
|
182
209
|
message.resolve(faceNeighbors);
|
|
183
210
|
}
|
|
@@ -188,126 +215,83 @@ var surfaceDefWorker = (0, import_easy_web_worker.createEasyWebWorker)(
|
|
|
188
215
|
},
|
|
189
216
|
{ maxWorkers: 16 }
|
|
190
217
|
);
|
|
191
|
-
|
|
192
|
-
return
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
200
|
-
throw new Error("LandXML doesn't contain any surfaces");
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
204
|
-
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
205
|
-
}
|
|
206
|
-
let sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
207
|
-
let timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
208
|
-
let wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
209
|
-
const surfaces = parsed.LandXML.Surfaces.Surface.map(
|
|
210
|
-
(surface) => __async(void 0, null, function* () {
|
|
211
|
-
return new Promise((resolve2, reject2) => __async(void 0, null, function* () {
|
|
212
|
-
const { name, desc } = surface.attr;
|
|
213
|
-
const Pnts = surface.Definition.Pnts.P;
|
|
214
|
-
const Faces = surface.Definition.Faces.F;
|
|
215
|
-
let ptsIdArray = [];
|
|
216
|
-
let faces = [];
|
|
217
|
-
let faceNeighbors = [];
|
|
218
|
-
if (Pnts.length > 1e4) {
|
|
219
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Pnts.length / 20 * i));
|
|
220
|
-
ptsIdArray = (yield Promise.all(
|
|
221
|
-
sliceIndexes.map(
|
|
222
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
223
|
-
const pts = yield surfaceDefWorker.send({
|
|
224
|
-
task: "parse-surface-points",
|
|
225
|
-
points: Pnts.slice(a[i], a[i + 1] || Pnts.length)
|
|
226
|
-
});
|
|
227
|
-
resolve3(pts);
|
|
228
|
-
}))
|
|
229
|
-
)
|
|
230
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
231
|
-
} else {
|
|
232
|
-
ptsIdArray = yield surfaceDefWorker.send({ task: "parse-surface-points", points: Pnts });
|
|
233
|
-
}
|
|
234
|
-
const points = ptsIdArray.map((v) => v[1]);
|
|
235
|
-
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
236
|
-
if (Faces.length > 1e4) {
|
|
237
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Faces.length / 20 * i));
|
|
238
|
-
faces = (yield Promise.all(
|
|
239
|
-
sliceIndexes.map(
|
|
240
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
241
|
-
const fcs = yield surfaceDefWorker.send({
|
|
242
|
-
task: "parse-surface-faces",
|
|
243
|
-
faces: Faces.slice(a[i], a[i + 1] || Faces.length),
|
|
244
|
-
idMap: pointsIdMap
|
|
245
|
-
});
|
|
246
|
-
resolve3(fcs);
|
|
247
|
-
}))
|
|
248
|
-
)
|
|
249
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
250
|
-
} else {
|
|
251
|
-
faces = yield surfaceDefWorker.send({
|
|
252
|
-
task: "parse-surface-faces",
|
|
253
|
-
faces: Faces,
|
|
254
|
-
idMap: pointsIdMap
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
if (Faces.length > 1e4) {
|
|
258
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round((faces.length - 1) / 20 * i));
|
|
259
|
-
faceNeighbors = (yield Promise.all(
|
|
260
|
-
sliceIndexes.map(
|
|
261
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
262
|
-
const fcs = yield surfaceDefWorker.send({
|
|
263
|
-
task: "find-neighboring-faces",
|
|
264
|
-
faces,
|
|
265
|
-
range: {
|
|
266
|
-
start: a[i],
|
|
267
|
-
end: a[i + 1] || faces.length
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
resolve3(fcs);
|
|
271
|
-
}))
|
|
272
|
-
)
|
|
273
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
274
|
-
} else {
|
|
275
|
-
faceNeighbors = yield surfaceDefWorker.send({
|
|
276
|
-
task: "find-neighboring-faces",
|
|
277
|
-
faces,
|
|
278
|
-
range: {
|
|
279
|
-
start: 0,
|
|
280
|
-
end: faces.length
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
resolve2({
|
|
285
|
-
sourceFile,
|
|
286
|
-
timeStamp: timeStamp || "",
|
|
287
|
-
name,
|
|
288
|
-
description: desc || "",
|
|
289
|
-
wktString,
|
|
290
|
-
surfaceDefinition: {
|
|
291
|
-
points,
|
|
292
|
-
faces,
|
|
293
|
-
faceNeighbors
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
}));
|
|
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));
|
|
297
226
|
})
|
|
298
227
|
);
|
|
299
|
-
|
|
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
|
+
};
|
|
300
283
|
}));
|
|
284
|
+
return Promise.all(surfaces);
|
|
301
285
|
});
|
|
302
286
|
var parse_xml_default = parseXML;
|
|
303
287
|
|
|
304
288
|
// src/public/to-glb.ts
|
|
305
|
-
var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(
|
|
289
|
+
var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(null, null, function* () {
|
|
306
290
|
const requestedCenter = center == "origin" ? [0, 0] : center === "auto" ? void 0 : center;
|
|
307
291
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
308
292
|
const glbs = yield Promise.all(
|
|
309
293
|
requestedParsedSurfaces.map(
|
|
310
|
-
(surface) => new Promise((resolve, reject) => __async(
|
|
294
|
+
(surface) => new Promise((resolve, reject) => __async(null, null, function* () {
|
|
311
295
|
try {
|
|
312
296
|
const { glb, center: center2 } = yield get_glb_default(surface, requestedCenter);
|
|
313
297
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
@@ -336,52 +320,45 @@ var contoursWorker = (0, import_easy_web_worker2.createEasyWebWorker)(
|
|
|
336
320
|
let vertsAtElevation = 0;
|
|
337
321
|
let line = [];
|
|
338
322
|
for (let i = 0; i < face.length; i++) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (vertex1[2] === z)
|
|
342
|
-
vertsAtElevation++;
|
|
323
|
+
const vertex1 = face[i];
|
|
324
|
+
const vertex2 = face[(i + 1) % face.length];
|
|
325
|
+
if (vertex1[2] === z) vertsAtElevation++;
|
|
343
326
|
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
344
|
-
|
|
327
|
+
const t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
345
328
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
346
329
|
}
|
|
347
330
|
}
|
|
348
|
-
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length)
|
|
349
|
-
|
|
350
|
-
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
351
|
-
return void 0;
|
|
331
|
+
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length) return void 0;
|
|
332
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1]) return void 0;
|
|
352
333
|
if (line.length > 2) {
|
|
353
334
|
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
354
335
|
}
|
|
355
336
|
return line.length > 0 ? line : void 0;
|
|
356
337
|
};
|
|
357
338
|
const linesToPolyLines3 = (lineSegments) => {
|
|
358
|
-
|
|
359
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
360
|
-
return [];
|
|
361
|
-
}
|
|
339
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
362
340
|
const segmentsMapIndexes = {};
|
|
363
341
|
const polylines = [];
|
|
364
|
-
const parsedSegmentIndexes =
|
|
342
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
365
343
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
366
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
367
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
368
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
369
|
-
});
|
|
370
344
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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);
|
|
374
352
|
let [start, end] = lineSegmentStrings[i];
|
|
375
|
-
|
|
353
|
+
const polyline = [start, end];
|
|
376
354
|
while (start && segmentsMapIndexes[start]) {
|
|
377
|
-
const nextLineIndex =
|
|
378
|
-
(
|
|
355
|
+
const nextLineIndex = segmentsMapIndexes[start].find(
|
|
356
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
379
357
|
);
|
|
380
|
-
if (nextLineIndex) {
|
|
381
|
-
parsedSegmentIndexes.
|
|
382
|
-
const
|
|
383
|
-
const
|
|
384
|
-
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;
|
|
385
362
|
polyline.unshift(newPoint);
|
|
386
363
|
start = newPoint;
|
|
387
364
|
} else {
|
|
@@ -389,14 +366,13 @@ var contoursWorker = (0, import_easy_web_worker2.createEasyWebWorker)(
|
|
|
389
366
|
}
|
|
390
367
|
}
|
|
391
368
|
while (end && segmentsMapIndexes[end]) {
|
|
392
|
-
const nextLineIndex =
|
|
393
|
-
(
|
|
369
|
+
const nextLineIndex = segmentsMapIndexes[end].find(
|
|
370
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
394
371
|
);
|
|
395
|
-
if (nextLineIndex) {
|
|
396
|
-
parsedSegmentIndexes.
|
|
397
|
-
const
|
|
398
|
-
const
|
|
399
|
-
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;
|
|
400
376
|
polyline.push(newPoint);
|
|
401
377
|
end = newPoint;
|
|
402
378
|
} else {
|
|
@@ -409,68 +385,51 @@ var contoursWorker = (0, import_easy_web_worker2.createEasyWebWorker)(
|
|
|
409
385
|
};
|
|
410
386
|
onMessage((message) => {
|
|
411
387
|
const { triangles, elevation } = message.payload;
|
|
412
|
-
const
|
|
388
|
+
const linesAtElevation = triangles.reduce((prev, curr) => {
|
|
413
389
|
const line = contourLineOnFace(curr, elevation);
|
|
414
|
-
if (line)
|
|
415
|
-
prev.push(line);
|
|
390
|
+
if (line) prev.push(line);
|
|
416
391
|
return prev;
|
|
417
392
|
}, []);
|
|
418
|
-
message.resolve({
|
|
419
|
-
elevation,
|
|
420
|
-
polylines: linesToPolyLines3(linesAtElevationE)
|
|
421
|
-
});
|
|
393
|
+
message.resolve({ elevation, polylines: linesToPolyLines3(linesAtElevation) });
|
|
422
394
|
});
|
|
423
395
|
},
|
|
424
396
|
{ maxWorkers: 10 }
|
|
425
397
|
);
|
|
426
398
|
var linesToPolyLines = (lineSegments) => {
|
|
427
|
-
|
|
428
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
429
|
-
return [];
|
|
430
|
-
}
|
|
399
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
431
400
|
const segmentsMapIndexes = {};
|
|
432
401
|
const polylines = [];
|
|
433
|
-
const parsedSegmentIndexes =
|
|
402
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
434
403
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
435
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
436
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
437
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
438
|
-
});
|
|
439
404
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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);
|
|
443
412
|
let [start, end] = lineSegmentStrings[i];
|
|
444
|
-
|
|
413
|
+
const polyline = [start, end];
|
|
445
414
|
while (start && segmentsMapIndexes[start]) {
|
|
446
|
-
const nextLineIndex =
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
452
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === start ? 1 : 0;
|
|
453
|
-
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;
|
|
454
420
|
polyline.unshift(newPoint);
|
|
455
421
|
start = newPoint;
|
|
456
|
-
} else
|
|
457
|
-
start = null;
|
|
458
|
-
}
|
|
422
|
+
} else start = null;
|
|
459
423
|
}
|
|
460
424
|
while (end && segmentsMapIndexes[end]) {
|
|
461
|
-
const nextLineIndex =
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
467
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === end ? 1 : 0;
|
|
468
|
-
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;
|
|
469
430
|
polyline.push(newPoint);
|
|
470
431
|
end = newPoint;
|
|
471
|
-
} else
|
|
472
|
-
end = null;
|
|
473
|
-
}
|
|
432
|
+
} else end = null;
|
|
474
433
|
}
|
|
475
434
|
polylines.push(polyline.map((coord) => coord.split(",").map((v) => parseFloat(v))));
|
|
476
435
|
}
|
|
@@ -484,10 +443,10 @@ var contourElevations = (minElevation, maxElevation, interval) => {
|
|
|
484
443
|
throw new Error(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
485
444
|
}
|
|
486
445
|
const elevations = [];
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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);
|
|
491
450
|
}
|
|
492
451
|
return elevations;
|
|
493
452
|
};
|
|
@@ -497,31 +456,55 @@ var constructGeojson = (elevationData) => {
|
|
|
497
456
|
return prev.concat(
|
|
498
457
|
polylines.map((polyline) => ({
|
|
499
458
|
type: "Feature",
|
|
500
|
-
geometry: {
|
|
501
|
-
|
|
502
|
-
coordinates: polyline
|
|
503
|
-
},
|
|
504
|
-
properties: {
|
|
505
|
-
z: elevation
|
|
506
|
-
}
|
|
459
|
+
geometry: { type: "LineString", coordinates: polyline },
|
|
460
|
+
properties: { z: elevation }
|
|
507
461
|
}))
|
|
508
462
|
);
|
|
509
463
|
}, []);
|
|
510
|
-
return {
|
|
511
|
-
type: "FeatureCollection",
|
|
512
|
-
features
|
|
513
|
-
};
|
|
464
|
+
return { type: "FeatureCollection", features };
|
|
514
465
|
};
|
|
515
|
-
var
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
const
|
|
520
|
-
([
|
|
521
|
-
[
|
|
522
|
-
|
|
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);
|
|
523
495
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
524
|
-
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
|
+
);
|
|
525
508
|
return constructGeojson(elevationPolylines);
|
|
526
509
|
});
|
|
527
510
|
var get_contours_default = getContours;
|
|
@@ -531,12 +514,9 @@ var getOutline = (surface) => {
|
|
|
531
514
|
const vertexIndexPairEdges = [];
|
|
532
515
|
surface.surfaceDefinition.faces.forEach((f, i) => {
|
|
533
516
|
const neighbors = surface.surfaceDefinition.faceNeighbors[i];
|
|
534
|
-
if (neighbors[0] === -1)
|
|
535
|
-
|
|
536
|
-
if (neighbors[
|
|
537
|
-
vertexIndexPairEdges.push([f[1], f[2]]);
|
|
538
|
-
if (neighbors[2] === -1)
|
|
539
|
-
vertexIndexPairEdges.push([f[0], f[2]]);
|
|
517
|
+
if (neighbors[0] === -1) vertexIndexPairEdges.push([f[0], f[1]]);
|
|
518
|
+
if (neighbors[1] === -1) vertexIndexPairEdges.push([f[1], f[2]]);
|
|
519
|
+
if (neighbors[2] === -1) vertexIndexPairEdges.push([f[0], f[2]]);
|
|
540
520
|
});
|
|
541
521
|
const edges = [];
|
|
542
522
|
vertexIndexPairEdges.map((pair) => {
|
|
@@ -549,11 +529,11 @@ var getOutline = (surface) => {
|
|
|
549
529
|
var get_outline_default = getOutline;
|
|
550
530
|
|
|
551
531
|
// src/public/to-geojson-contours.ts
|
|
552
|
-
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(
|
|
532
|
+
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(null, null, function* () {
|
|
553
533
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
554
534
|
const contours = yield Promise.all(
|
|
555
535
|
requestedParsedSurfaces.map(
|
|
556
|
-
(surface) => new Promise((resolve, reject) => __async(
|
|
536
|
+
(surface) => new Promise((resolve, reject) => __async(null, null, function* () {
|
|
557
537
|
try {
|
|
558
538
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
559
539
|
if (generateOutline) {
|
|
@@ -591,8 +571,7 @@ var reprojectGeoJson = (geojson, sourceProjection, targetProjection = "WGS84", k
|
|
|
591
571
|
throw new Error("Invalid GeoJSON or source projection.");
|
|
592
572
|
}
|
|
593
573
|
geojson.features.forEach((feature) => {
|
|
594
|
-
if (keepOriginalGeometryAsFeatureProperty)
|
|
595
|
-
feature.properties = feature.properties || {};
|
|
574
|
+
if (keepOriginalGeometryAsFeatureProperty) feature.properties = feature.properties || {};
|
|
596
575
|
if (feature.geometry) {
|
|
597
576
|
if (keepOriginalGeometryAsFeatureProperty && feature.properties)
|
|
598
577
|
feature.properties._rawGeometry = __spreadValues({}, feature.geometry);
|
|
@@ -608,9 +587,41 @@ var reprojectGeoJson = (geojson, sourceProjection, targetProjection = "WGS84", k
|
|
|
608
587
|
return geojson;
|
|
609
588
|
};
|
|
610
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;
|
|
611
620
|
// Annotate the CommonJS export names for ESM import in node:
|
|
612
621
|
0 && (module.exports = {
|
|
622
|
+
precomputeSurfaceData,
|
|
613
623
|
reprojectGeoJson,
|
|
614
624
|
toGeojsonContours,
|
|
615
|
-
toGlb
|
|
625
|
+
toGlb,
|
|
626
|
+
toGlbAndContours
|
|
616
627
|
});
|