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.mjs
CHANGED
|
@@ -55,8 +55,7 @@ var filterBySurfaceId = (parsedSurfaces, surfaceId) => {
|
|
|
55
55
|
let filtered = [...parsedSurfaces];
|
|
56
56
|
if (typeof surfaceId === "string") {
|
|
57
57
|
filtered = filtered.filter((s) => s.name === surfaceId);
|
|
58
|
-
if (filtered.length === 0)
|
|
59
|
-
throw "Provided SurfaceId doesn't exist within provided LandXML";
|
|
58
|
+
if (filtered.length === 0) throw "Provided SurfaceId doesn't exist within provided LandXML";
|
|
60
59
|
}
|
|
61
60
|
if (typeof surfaceId === "number" && surfaceId > 0) {
|
|
62
61
|
if (!filtered[surfaceId])
|
|
@@ -77,20 +76,32 @@ var findXYAxisMedians = (vertices) => {
|
|
|
77
76
|
const medianY = (_b = vertices.slice().sort((a, b) => a[1] - b[1])[middleIndex]) == null ? void 0 : _b[1];
|
|
78
77
|
return [medianX, medianY];
|
|
79
78
|
};
|
|
80
|
-
var getGlb = (data, customCenter) => __async(
|
|
79
|
+
var getGlb = (data, customCenter) => __async(null, null, function* () {
|
|
81
80
|
const center = customCenter || findXYAxisMedians(data.surfaceDefinition.points);
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
+
}
|
|
86
97
|
const doc = new Document();
|
|
87
98
|
const buffer = doc.createBuffer();
|
|
88
|
-
const position = doc.createAccessor().setType("VEC3").setArray(
|
|
89
|
-
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);
|
|
90
101
|
const prim = doc.createPrimitive().setAttribute("POSITION", position).setIndices(indices);
|
|
91
102
|
const mesh = doc.createMesh().addPrimitive(prim);
|
|
92
103
|
const node = doc.createNode().setMesh(mesh);
|
|
93
|
-
|
|
104
|
+
doc.createScene().addChild(node);
|
|
94
105
|
const glb = yield new WebIO().writeBinary(doc);
|
|
95
106
|
return { glb, center };
|
|
96
107
|
});
|
|
@@ -129,20 +140,34 @@ var surfaceDefWorker = createEasyWebWorker(
|
|
|
129
140
|
var _a;
|
|
130
141
|
if (typeof f === "string")
|
|
131
142
|
return [f.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
132
|
-
if (((_a = f == null ? void 0 : f.attr) == null ? void 0 : _a.i) === "1")
|
|
133
|
-
return [];
|
|
143
|
+
if (((_a = f == null ? void 0 : f.attr) == null ? void 0 : _a.i) === "1") return [];
|
|
134
144
|
return [f.content.split(" ").map((id) => idMap == null ? void 0 : idMap.indexOf(id))];
|
|
135
145
|
})
|
|
136
146
|
);
|
|
137
147
|
} else if (task === "find-neighboring-faces") {
|
|
138
|
-
const { faces
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
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))];
|
|
146
171
|
}
|
|
147
172
|
message.resolve(faceNeighbors);
|
|
148
173
|
}
|
|
@@ -153,126 +178,83 @@ var surfaceDefWorker = createEasyWebWorker(
|
|
|
153
178
|
},
|
|
154
179
|
{ maxWorkers: 16 }
|
|
155
180
|
);
|
|
156
|
-
|
|
157
|
-
return
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (typeof ((_b = (_a = parsed.LandXML) == null ? void 0 : _a.Surfaces) == null ? void 0 : _b.Surface) === "undefined") {
|
|
165
|
-
throw new Error("LandXML doesn't contain any surfaces");
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (!Array.isArray(parsed.LandXML.Surfaces.Surface)) {
|
|
169
|
-
parsed.LandXML.Surfaces.Surface = [parsed.LandXML.Surfaces.Surface];
|
|
170
|
-
}
|
|
171
|
-
let sourceFile = parsed.LandXML.Project.attr.name || "Undefined source";
|
|
172
|
-
let timeStamp = parsed.LandXML.Application.attr.timeStamp || "";
|
|
173
|
-
let wktString = ((_e = (_d = (_c = parsed.LandXML) == null ? void 0 : _c.CoordinateSystem) == null ? void 0 : _d.attr) == null ? void 0 : _e.ogcWktCode) || void 0;
|
|
174
|
-
const surfaces = parsed.LandXML.Surfaces.Surface.map(
|
|
175
|
-
(surface) => __async(void 0, null, function* () {
|
|
176
|
-
return new Promise((resolve2, reject2) => __async(void 0, null, function* () {
|
|
177
|
-
const { name, desc } = surface.attr;
|
|
178
|
-
const Pnts = surface.Definition.Pnts.P;
|
|
179
|
-
const Faces = surface.Definition.Faces.F;
|
|
180
|
-
let ptsIdArray = [];
|
|
181
|
-
let faces = [];
|
|
182
|
-
let faceNeighbors = [];
|
|
183
|
-
if (Pnts.length > 1e4) {
|
|
184
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Pnts.length / 20 * i));
|
|
185
|
-
ptsIdArray = (yield Promise.all(
|
|
186
|
-
sliceIndexes.map(
|
|
187
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
188
|
-
const pts = yield surfaceDefWorker.send({
|
|
189
|
-
task: "parse-surface-points",
|
|
190
|
-
points: Pnts.slice(a[i], a[i + 1] || Pnts.length)
|
|
191
|
-
});
|
|
192
|
-
resolve3(pts);
|
|
193
|
-
}))
|
|
194
|
-
)
|
|
195
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
196
|
-
} else {
|
|
197
|
-
ptsIdArray = yield surfaceDefWorker.send({ task: "parse-surface-points", points: Pnts });
|
|
198
|
-
}
|
|
199
|
-
const points = ptsIdArray.map((v) => v[1]);
|
|
200
|
-
const pointsIdMap = ptsIdArray.map((v) => v[0]);
|
|
201
|
-
if (Faces.length > 1e4) {
|
|
202
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round(Faces.length / 20 * i));
|
|
203
|
-
faces = (yield Promise.all(
|
|
204
|
-
sliceIndexes.map(
|
|
205
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
206
|
-
const fcs = yield surfaceDefWorker.send({
|
|
207
|
-
task: "parse-surface-faces",
|
|
208
|
-
faces: Faces.slice(a[i], a[i + 1] || Faces.length),
|
|
209
|
-
idMap: pointsIdMap
|
|
210
|
-
});
|
|
211
|
-
resolve3(fcs);
|
|
212
|
-
}))
|
|
213
|
-
)
|
|
214
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
215
|
-
} else {
|
|
216
|
-
faces = yield surfaceDefWorker.send({
|
|
217
|
-
task: "parse-surface-faces",
|
|
218
|
-
faces: Faces,
|
|
219
|
-
idMap: pointsIdMap
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
if (Faces.length > 1e4) {
|
|
223
|
-
const sliceIndexes = [...Array(20).keys()].map((i) => Math.round((faces.length - 1) / 20 * i));
|
|
224
|
-
faceNeighbors = (yield Promise.all(
|
|
225
|
-
sliceIndexes.map(
|
|
226
|
-
(v, i, a) => new Promise((resolve3, reject3) => __async(void 0, null, function* () {
|
|
227
|
-
const fcs = yield surfaceDefWorker.send({
|
|
228
|
-
task: "find-neighboring-faces",
|
|
229
|
-
faces,
|
|
230
|
-
range: {
|
|
231
|
-
start: a[i],
|
|
232
|
-
end: a[i + 1] || faces.length
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
resolve3(fcs);
|
|
236
|
-
}))
|
|
237
|
-
)
|
|
238
|
-
)).reduce((prev, curr) => [...prev, ...curr], []);
|
|
239
|
-
} else {
|
|
240
|
-
faceNeighbors = yield surfaceDefWorker.send({
|
|
241
|
-
task: "find-neighboring-faces",
|
|
242
|
-
faces,
|
|
243
|
-
range: {
|
|
244
|
-
start: 0,
|
|
245
|
-
end: faces.length
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
resolve2({
|
|
250
|
-
sourceFile,
|
|
251
|
-
timeStamp: timeStamp || "",
|
|
252
|
-
name,
|
|
253
|
-
description: desc || "",
|
|
254
|
-
wktString,
|
|
255
|
-
surfaceDefinition: {
|
|
256
|
-
points,
|
|
257
|
-
faces,
|
|
258
|
-
faceNeighbors
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
}));
|
|
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));
|
|
262
189
|
})
|
|
263
190
|
);
|
|
264
|
-
|
|
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
|
+
};
|
|
265
246
|
}));
|
|
247
|
+
return Promise.all(surfaces);
|
|
266
248
|
});
|
|
267
249
|
var parse_xml_default = parseXML;
|
|
268
250
|
|
|
269
251
|
// src/public/to-glb.ts
|
|
270
|
-
var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(
|
|
252
|
+
var toGlb = (landXmlString, center = "auto", surfaceId = -1) => __async(null, null, function* () {
|
|
271
253
|
const requestedCenter = center == "origin" ? [0, 0] : center === "auto" ? void 0 : center;
|
|
272
254
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
273
255
|
const glbs = yield Promise.all(
|
|
274
256
|
requestedParsedSurfaces.map(
|
|
275
|
-
(surface) => new Promise((resolve, reject) => __async(
|
|
257
|
+
(surface) => new Promise((resolve, reject) => __async(null, null, function* () {
|
|
276
258
|
try {
|
|
277
259
|
const { glb, center: center2 } = yield get_glb_default(surface, requestedCenter);
|
|
278
260
|
const _a = surface, { surfaceDefinition } = _a, rest = __objRest(_a, ["surfaceDefinition"]);
|
|
@@ -301,52 +283,45 @@ var contoursWorker = createEasyWebWorker2(
|
|
|
301
283
|
let vertsAtElevation = 0;
|
|
302
284
|
let line = [];
|
|
303
285
|
for (let i = 0; i < face.length; i++) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (vertex1[2] === z)
|
|
307
|
-
vertsAtElevation++;
|
|
286
|
+
const vertex1 = face[i];
|
|
287
|
+
const vertex2 = face[(i + 1) % face.length];
|
|
288
|
+
if (vertex1[2] === z) vertsAtElevation++;
|
|
308
289
|
if ((vertex1[2] <= z && vertex2[2] >= z || vertex1[2] >= z && vertex2[2] <= z) && !Number.isNaN((z - vertex1[2]) / (vertex2[2] - vertex1[2]))) {
|
|
309
|
-
|
|
290
|
+
const t = (z - vertex1[2]) / (vertex2[2] - vertex1[2]);
|
|
310
291
|
line.push([vertex1[0] + t * (vertex2[0] - vertex1[0]), vertex1[1] + t * (vertex2[1] - vertex1[1])]);
|
|
311
292
|
}
|
|
312
293
|
}
|
|
313
|
-
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length)
|
|
314
|
-
|
|
315
|
-
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1])
|
|
316
|
-
return void 0;
|
|
294
|
+
if (vertsAtElevation >= 2 && face.map((f) => f[2]).reduce((a, b) => a + b) > z * face.length) return void 0;
|
|
295
|
+
if (line.length === 2 && line[0][0] === line[1][0] && line[0][1] === line[1][1]) return void 0;
|
|
317
296
|
if (line.length > 2) {
|
|
318
297
|
line = [...new Set(line.map((v) => JSON.stringify(v)))].map((s) => JSON.parse(s));
|
|
319
298
|
}
|
|
320
299
|
return line.length > 0 ? line : void 0;
|
|
321
300
|
};
|
|
322
301
|
const linesToPolyLines3 = (lineSegments) => {
|
|
323
|
-
|
|
324
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
325
|
-
return [];
|
|
326
|
-
}
|
|
302
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
327
303
|
const segmentsMapIndexes = {};
|
|
328
304
|
const polylines = [];
|
|
329
|
-
const parsedSegmentIndexes =
|
|
305
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
330
306
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
331
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
332
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
333
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
334
|
-
});
|
|
335
307
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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);
|
|
339
315
|
let [start, end] = lineSegmentStrings[i];
|
|
340
|
-
|
|
316
|
+
const polyline = [start, end];
|
|
341
317
|
while (start && segmentsMapIndexes[start]) {
|
|
342
|
-
const nextLineIndex =
|
|
343
|
-
(
|
|
318
|
+
const nextLineIndex = segmentsMapIndexes[start].find(
|
|
319
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
344
320
|
);
|
|
345
|
-
if (nextLineIndex) {
|
|
346
|
-
parsedSegmentIndexes.
|
|
347
|
-
const
|
|
348
|
-
const
|
|
349
|
-
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;
|
|
350
325
|
polyline.unshift(newPoint);
|
|
351
326
|
start = newPoint;
|
|
352
327
|
} else {
|
|
@@ -354,14 +329,13 @@ var contoursWorker = createEasyWebWorker2(
|
|
|
354
329
|
}
|
|
355
330
|
}
|
|
356
331
|
while (end && segmentsMapIndexes[end]) {
|
|
357
|
-
const nextLineIndex =
|
|
358
|
-
(
|
|
332
|
+
const nextLineIndex = segmentsMapIndexes[end].find(
|
|
333
|
+
(li) => !parsedSegmentIndexes.has(li)
|
|
359
334
|
);
|
|
360
|
-
if (nextLineIndex) {
|
|
361
|
-
parsedSegmentIndexes.
|
|
362
|
-
const
|
|
363
|
-
const
|
|
364
|
-
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;
|
|
365
339
|
polyline.push(newPoint);
|
|
366
340
|
end = newPoint;
|
|
367
341
|
} else {
|
|
@@ -374,68 +348,51 @@ var contoursWorker = createEasyWebWorker2(
|
|
|
374
348
|
};
|
|
375
349
|
onMessage((message) => {
|
|
376
350
|
const { triangles, elevation } = message.payload;
|
|
377
|
-
const
|
|
351
|
+
const linesAtElevation = triangles.reduce((prev, curr) => {
|
|
378
352
|
const line = contourLineOnFace(curr, elevation);
|
|
379
|
-
if (line)
|
|
380
|
-
prev.push(line);
|
|
353
|
+
if (line) prev.push(line);
|
|
381
354
|
return prev;
|
|
382
355
|
}, []);
|
|
383
|
-
message.resolve({
|
|
384
|
-
elevation,
|
|
385
|
-
polylines: linesToPolyLines3(linesAtElevationE)
|
|
386
|
-
});
|
|
356
|
+
message.resolve({ elevation, polylines: linesToPolyLines3(linesAtElevation) });
|
|
387
357
|
});
|
|
388
358
|
},
|
|
389
359
|
{ maxWorkers: 10 }
|
|
390
360
|
);
|
|
391
361
|
var linesToPolyLines = (lineSegments) => {
|
|
392
|
-
|
|
393
|
-
if (!Array.isArray(lineSegments) || (lineSegments == null ? void 0 : lineSegments.length) === 0) {
|
|
394
|
-
return [];
|
|
395
|
-
}
|
|
362
|
+
if (!Array.isArray(lineSegments) || lineSegments.length === 0) return [];
|
|
396
363
|
const segmentsMapIndexes = {};
|
|
397
364
|
const polylines = [];
|
|
398
|
-
const parsedSegmentIndexes =
|
|
365
|
+
const parsedSegmentIndexes = /* @__PURE__ */ new Set();
|
|
399
366
|
const lineSegmentStrings = lineSegments.map((v) => v.map((c) => c.join(",")));
|
|
400
|
-
lineSegmentStrings.forEach(([start, end], i) => {
|
|
401
|
-
segmentsMapIndexes[start] = segmentsMapIndexes[start] ? [...segmentsMapIndexes[start] || [], i] : [i];
|
|
402
|
-
segmentsMapIndexes[end] = segmentsMapIndexes[end] ? [...segmentsMapIndexes[end] || [], i] : [i];
|
|
403
|
-
});
|
|
404
367
|
for (let i = 0; i < lineSegmentStrings.length; i++) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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);
|
|
408
375
|
let [start, end] = lineSegmentStrings[i];
|
|
409
|
-
|
|
376
|
+
const polyline = [start, end];
|
|
410
377
|
while (start && segmentsMapIndexes[start]) {
|
|
411
|
-
const nextLineIndex =
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
417
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === start ? 1 : 0;
|
|
418
|
-
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;
|
|
419
383
|
polyline.unshift(newPoint);
|
|
420
384
|
start = newPoint;
|
|
421
|
-
} else
|
|
422
|
-
start = null;
|
|
423
|
-
}
|
|
385
|
+
} else start = null;
|
|
424
386
|
}
|
|
425
387
|
while (end && segmentsMapIndexes[end]) {
|
|
426
|
-
const nextLineIndex =
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const nextLineSegment = lineSegmentStrings[nextLineIndex];
|
|
432
|
-
const nextLineSegmentPointIndex = nextLineSegment[0] === end ? 1 : 0;
|
|
433
|
-
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;
|
|
434
393
|
polyline.push(newPoint);
|
|
435
394
|
end = newPoint;
|
|
436
|
-
} else
|
|
437
|
-
end = null;
|
|
438
|
-
}
|
|
395
|
+
} else end = null;
|
|
439
396
|
}
|
|
440
397
|
polylines.push(polyline.map((coord) => coord.split(",").map((v) => parseFloat(v))));
|
|
441
398
|
}
|
|
@@ -449,10 +406,10 @@ var contourElevations = (minElevation, maxElevation, interval) => {
|
|
|
449
406
|
throw new Error(`No contour lines at interval: ${interval} between elevation ${minElevation} and ${maxElevation}`);
|
|
450
407
|
}
|
|
451
408
|
const elevations = [];
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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);
|
|
456
413
|
}
|
|
457
414
|
return elevations;
|
|
458
415
|
};
|
|
@@ -462,31 +419,55 @@ var constructGeojson = (elevationData) => {
|
|
|
462
419
|
return prev.concat(
|
|
463
420
|
polylines.map((polyline) => ({
|
|
464
421
|
type: "Feature",
|
|
465
|
-
geometry: {
|
|
466
|
-
|
|
467
|
-
coordinates: polyline
|
|
468
|
-
},
|
|
469
|
-
properties: {
|
|
470
|
-
z: elevation
|
|
471
|
-
}
|
|
422
|
+
geometry: { type: "LineString", coordinates: polyline },
|
|
423
|
+
properties: { z: elevation }
|
|
472
424
|
}))
|
|
473
425
|
);
|
|
474
426
|
}, []);
|
|
475
|
-
return {
|
|
476
|
-
type: "FeatureCollection",
|
|
477
|
-
features
|
|
478
|
-
};
|
|
427
|
+
return { type: "FeatureCollection", features };
|
|
479
428
|
};
|
|
480
|
-
var
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
const
|
|
485
|
-
([
|
|
486
|
-
[
|
|
487
|
-
|
|
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);
|
|
488
458
|
const elevations = contourElevations(minElevation, maxElevation, interval);
|
|
489
|
-
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
|
+
);
|
|
490
471
|
return constructGeojson(elevationPolylines);
|
|
491
472
|
});
|
|
492
473
|
var get_contours_default = getContours;
|
|
@@ -496,12 +477,9 @@ var getOutline = (surface) => {
|
|
|
496
477
|
const vertexIndexPairEdges = [];
|
|
497
478
|
surface.surfaceDefinition.faces.forEach((f, i) => {
|
|
498
479
|
const neighbors = surface.surfaceDefinition.faceNeighbors[i];
|
|
499
|
-
if (neighbors[0] === -1)
|
|
500
|
-
|
|
501
|
-
if (neighbors[
|
|
502
|
-
vertexIndexPairEdges.push([f[1], f[2]]);
|
|
503
|
-
if (neighbors[2] === -1)
|
|
504
|
-
vertexIndexPairEdges.push([f[0], f[2]]);
|
|
480
|
+
if (neighbors[0] === -1) vertexIndexPairEdges.push([f[0], f[1]]);
|
|
481
|
+
if (neighbors[1] === -1) vertexIndexPairEdges.push([f[1], f[2]]);
|
|
482
|
+
if (neighbors[2] === -1) vertexIndexPairEdges.push([f[0], f[2]]);
|
|
505
483
|
});
|
|
506
484
|
const edges = [];
|
|
507
485
|
vertexIndexPairEdges.map((pair) => {
|
|
@@ -514,11 +492,11 @@ var getOutline = (surface) => {
|
|
|
514
492
|
var get_outline_default = getOutline;
|
|
515
493
|
|
|
516
494
|
// src/public/to-geojson-contours.ts
|
|
517
|
-
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(
|
|
495
|
+
var toGeojsonContours = (landXmlString, contourInterval = 2, generateOutline = true, surfaceId = -1) => __async(null, null, function* () {
|
|
518
496
|
let requestedParsedSurfaces = filter_by_surfaceId_default(yield parse_xml_default(landXmlString), surfaceId);
|
|
519
497
|
const contours = yield Promise.all(
|
|
520
498
|
requestedParsedSurfaces.map(
|
|
521
|
-
(surface) => new Promise((resolve, reject) => __async(
|
|
499
|
+
(surface) => new Promise((resolve, reject) => __async(null, null, function* () {
|
|
522
500
|
try {
|
|
523
501
|
const geojson = yield get_contours_default(surface, contourInterval);
|
|
524
502
|
if (generateOutline) {
|
|
@@ -556,8 +534,7 @@ var reprojectGeoJson = (geojson, sourceProjection, targetProjection = "WGS84", k
|
|
|
556
534
|
throw new Error("Invalid GeoJSON or source projection.");
|
|
557
535
|
}
|
|
558
536
|
geojson.features.forEach((feature) => {
|
|
559
|
-
if (keepOriginalGeometryAsFeatureProperty)
|
|
560
|
-
feature.properties = feature.properties || {};
|
|
537
|
+
if (keepOriginalGeometryAsFeatureProperty) feature.properties = feature.properties || {};
|
|
561
538
|
if (feature.geometry) {
|
|
562
539
|
if (keepOriginalGeometryAsFeatureProperty && feature.properties)
|
|
563
540
|
feature.properties._rawGeometry = __spreadValues({}, feature.geometry);
|
|
@@ -573,8 +550,40 @@ var reprojectGeoJson = (geojson, sourceProjection, targetProjection = "WGS84", k
|
|
|
573
550
|
return geojson;
|
|
574
551
|
};
|
|
575
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;
|
|
576
583
|
export {
|
|
584
|
+
precomputeSurfaceData,
|
|
577
585
|
reproject_geojson_default as reprojectGeoJson,
|
|
578
586
|
to_geojson_contours_default as toGeojsonContours,
|
|
579
|
-
to_glb_default as toGlb
|
|
587
|
+
to_glb_default as toGlb,
|
|
588
|
+
to_glb_and_contours_default as toGlbAndContours
|
|
580
589
|
};
|