From f42ff05cb5aa8b0f661162b5b3cdf53616caa9ce Mon Sep 17 00:00:00 2001 From: Jonas Date: Fri, 8 Nov 2024 15:48:29 +0100 Subject: [PATCH 1/3] simplify and densify topology utils --- src/utils.js | 1 + src/utils/topology.js | 131 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/src/utils.js b/src/utils.js index 32b882a2e..5f1dca50b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -126,4 +126,5 @@ export default { }; export { default as slugify } from './utils/slugify'; +export { default as topology } from './utils/topology.js'; export { default as exportToFile } from './utils/exporttofile'; diff --git a/src/utils/topology.js b/src/utils/topology.js index f4920ef36..995adac9e 100644 --- a/src/utils/topology.js +++ b/src/utils/topology.js @@ -152,6 +152,137 @@ const topology = { default: valid = true; } return valid; + }, + + /** + * Densifies a geometry by adding points along segments. + * @param {any} geom The geometry to densify + * @param {double} multiple Higher value means more breakpoints + * @returns {any} geom The densified geometry + */ + densify: function densify(geom, multiple = 1) { + + function densifyGeom(geometry, mult) { + let maxLength = 100; + const lineCoords = []; + let length = geometry.getLength(); + if (length < 100) { + maxLength = 5 / mult; + } else if (length < 1000) { + maxLength = 25 / mult; + } else if (length < 10000) { + maxLength = 50 / mult; + } + if (maxLength < 1) { maxLength = 1 } + let coords = geometry.getCoordinates(); + lineCoords.push(coords[0]); + geometry.forEachSegment(function (start, end) { + const segment = new LineString([start, end]); + const segmentLength = segment.getLength(); + var splits = Math.ceil(segmentLength / maxLength); + for (let i = 1; i < splits; i++) { + const fraction = i / splits; + const pt = segment.getCoordinateAt(fraction) + lineCoords.push(pt); + } + lineCoords.push(end); + }); + return lineCoords; + } + + const densified = geom.clone() + const densifiedCoords = densifyGeom(geom, multiple); + if (densifiedCoords) { + densified.setCoordinates(densifiedCoords); + } + return densified; + }, + + /** + * Simplifies a line geometry. + * @param {any} geom The line geometry to simplify + * @param {double} tolerance + * @returns {any} geom The simplified geometry + */ + simplify: function simplify(geom, tolerance = 1) { + + function sqSegDist(p, p1, p2) { + let x0 = p[0], + x1 = p1[0], + x2 = p2[0], + y0 = p[1], + y1 = p1[1], + y2 = p2[1], + z0 = p[2] || 0, + z1 = p1[2] || 0, + z2 = p2[2] || 0, + dx = x2 - x1, + dy = y2 - y1, + dz = z2 - z1; + if (dx !== 0 || dy !== 0 || dz !== 0) { + const t = ((x0 - x1) * dx + (y0 - y1) * dy + (z0 - z1) * dz) / (dx * dx + dy * dy + dz * dz); + if (t > 1) { + x1 = x2; + y1 = y2; + z1 = z2; + } else if (t > 0) { + x1 += dx * t; + y1 += dy * t; + z1 += dz * t; + } + } + dx = x0 - x1; + dy = y0 - y1; + dz = z0 - z1; + return dx * dx + dy * dy + dz * dz; + } + + function simplifyDouglasPeucker(geometry, sqTolerance) { + const points = geometry.getCoordinates(); + let len = points.length, + pArr = new Array(len), + first = 0, + last = len - 1, + stack = [], + newPoints = [], + i, maxSqDist, sqDist, index; + pArr[first] = pArr[last] = 1; + while (last) { + maxSqDist = 0; + for (i = first + 1; i < last; i++) { + sqDist = sqSegDist(points[i], points[first], points[last]); + if (sqDist > maxSqDist) { + index = i; + maxSqDist = sqDist; + } + } + if (maxSqDist > sqTolerance) { + pArr[index] = 1; + stack.push(first, index, index, last); + } + last = stack.pop(); + first = stack.pop(); + } + for (i = 0; i < len; i++) { + if (pArr[i]) { + newPoints.push(points[i]); + } + } + return newPoints; + } + + function simplifyGeom(geometry, tol) { + const sqTolerance = tol * tol || 1; + const points = simplifyDouglasPeucker(geometry, sqTolerance); + return points; + } + + const simplified = geom.clone(); + const simplifiedCoords = simplifyGeom(geom, tolerance); + if (simplifiedCoords) { + simplified.setCoordinates(simplifiedCoords); + } + return simplified; } }; From acdea5df6b5df1b02e46c217783e57a86783cccf Mon Sep 17 00:00:00 2001 From: Jonas Date: Fri, 8 Nov 2024 15:59:50 +0100 Subject: [PATCH 2/3] Update utils.js --- src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.js b/src/utils.js index 5f1dca50b..aac771037 100644 --- a/src/utils.js +++ b/src/utils.js @@ -126,5 +126,5 @@ export default { }; export { default as slugify } from './utils/slugify'; -export { default as topology } from './utils/topology.js'; +export { default as topology } from './utils/topology'; export { default as exportToFile } from './utils/exporttofile'; From 9ced8dc464cba882728b7b0875f5f9c4bc8dcce8 Mon Sep 17 00:00:00 2001 From: Jonas Date: Fri, 8 Nov 2024 16:21:04 +0100 Subject: [PATCH 3/3] Update topology.js --- src/utils/topology.js | 67 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/utils/topology.js b/src/utils/topology.js index 995adac9e..f8022665e 100644 --- a/src/utils/topology.js +++ b/src/utils/topology.js @@ -161,11 +161,10 @@ const topology = { * @returns {any} geom The densified geometry */ densify: function densify(geom, multiple = 1) { - function densifyGeom(geometry, mult) { let maxLength = 100; const lineCoords = []; - let length = geometry.getLength(); + const length = geometry.getLength(); if (length < 100) { maxLength = 5 / mult; } else if (length < 1000) { @@ -173,16 +172,16 @@ const topology = { } else if (length < 10000) { maxLength = 50 / mult; } - if (maxLength < 1) { maxLength = 1 } - let coords = geometry.getCoordinates(); + if (maxLength < 1) { maxLength = 1; } + const coords = geometry.getCoordinates(); lineCoords.push(coords[0]); - geometry.forEachSegment(function (start, end) { + geometry.forEachSegment((start, end) => { const segment = new LineString([start, end]); const segmentLength = segment.getLength(); - var splits = Math.ceil(segmentLength / maxLength); - for (let i = 1; i < splits; i++) { + const splits = Math.ceil(segmentLength / maxLength); + for (let i = 1; i < splits; i += 1) { const fraction = i / splits; - const pt = segment.getCoordinateAt(fraction) + const pt = segment.getCoordinateAt(fraction); lineCoords.push(pt); } lineCoords.push(end); @@ -190,7 +189,7 @@ const topology = { return lineCoords; } - const densified = geom.clone() + const densified = geom.clone(); const densifiedCoords = densifyGeom(geom, multiple); if (densifiedCoords) { densified.setCoordinates(densifiedCoords); @@ -205,20 +204,19 @@ const topology = { * @returns {any} geom The simplified geometry */ simplify: function simplify(geom, tolerance = 1) { - function sqSegDist(p, p1, p2) { - let x0 = p[0], - x1 = p1[0], - x2 = p2[0], - y0 = p[1], - y1 = p1[1], - y2 = p2[1], - z0 = p[2] || 0, - z1 = p1[2] || 0, - z2 = p2[2] || 0, - dx = x2 - x1, - dy = y2 - y1, - dz = z2 - z1; + const x0 = p[0]; + const x2 = p2[0]; + const y0 = p[1]; + const y2 = p2[1]; + const z0 = p[2] || 0; + const z2 = p2[2] || 0; + let x1 = p1[0]; + let y1 = p1[1]; + let z1 = p1[2] || 0; + let dx = x2 - x1; + let dy = y2 - y1; + let dz = z2 - z1; if (dx !== 0 || dy !== 0 || dz !== 0) { const t = ((x0 - x1) * dx + (y0 - y1) * dy + (z0 - z1) * dz) / (dx * dx + dy * dy + dz * dz); if (t > 1) { @@ -239,17 +237,22 @@ const topology = { function simplifyDouglasPeucker(geometry, sqTolerance) { const points = geometry.getCoordinates(); - let len = points.length, - pArr = new Array(len), - first = 0, - last = len - 1, - stack = [], - newPoints = [], - i, maxSqDist, sqDist, index; - pArr[first] = pArr[last] = 1; + const len = points.length; + const pArr = new Array(len); + const stack = []; + const newPoints = []; + let first = 0; + let last = len - 1; + let i; + let maxSqDist; + let sqDist; + let index; + pArr[first] = 1; + pArr[last] = 1; + while (last) { maxSqDist = 0; - for (i = first + 1; i < last; i++) { + for (i = first + 1; i < last; i += 1) { sqDist = sqSegDist(points[i], points[first], points[last]); if (sqDist > maxSqDist) { index = i; @@ -263,7 +266,7 @@ const topology = { last = stack.pop(); first = stack.pop(); } - for (i = 0; i < len; i++) { + for (i = 0; i < len; i += 1) { if (pArr[i]) { newPoints.push(points[i]); }