Skip to content

Commit

Permalink
Clean up @turf/simplify (Turfjs#2561)
Browse files Browse the repository at this point in the history
* Clean up @turf/simplify

Rework the simplify-js library to actually just take number[] directly
Style cleanup around the type inference and passthrough functions

* Add note about 2d simplify-js
  • Loading branch information
mfedderly authored Dec 26, 2023
1 parent d0f5cd7 commit e455f4f
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 72 deletions.
2 changes: 1 addition & 1 deletion packages/turf-simplify/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## simplify

Takes a [GeoJSON][1] object and returns a simplified version. Internally uses
Takes a [GeoJSON][1] object and returns a simplified version. Internally uses the 2d version of
[simplify-js][2] to perform simplification using the Ramer-Douglas-Peucker algorithm.

### Parameters
Expand Down
73 changes: 17 additions & 56 deletions packages/turf-simplify/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { AllGeoJSON, isObject } from "@turf/helpers";
import { simplify as simplifyJS } from "./lib/simplify";

/**
* Takes a {@link GeoJSON} object and returns a simplified version. Internally uses
* Takes a {@link GeoJSON} object and returns a simplified version. Internally uses the 2d version of
* [simplify-js](http://mourner.github.io/simplify-js/) to perform simplification using the Ramer-Douglas-Peucker algorithm.
*
*
* @name simplify
* @param {GeoJSON} geojson object to be simplified
* @param {Object} [options={}] Optional parameters
Expand Down Expand Up @@ -54,9 +55,9 @@ function simplify<T extends AllGeoJSON>(
} = {}
): T {
// Optional parameters
options = options || {};
options = options ?? {};
if (!isObject(options)) throw new Error("options is invalid");
const tolerance = options.tolerance !== undefined ? options.tolerance : 1;
const tolerance = options.tolerance ?? 1;
const highQuality = options.highQuality ?? false;
const mutate = options.mutate ?? false;

Expand Down Expand Up @@ -96,66 +97,36 @@ function simplifyGeom(

if (type !== "GeometryCollection") {
// TODO should this cater for GeometryCollections too?
const coordinates = geometry.coordinates;
switch (type) {
case "LineString":
geometry.coordinates = simplifyLine(
coordinates as Position[],
geometry.coordinates = simplifyJS(
geometry.coordinates,
tolerance,
highQuality
);
break;
case "MultiLineString":
geometry.coordinates = (coordinates as Position[][]).map(
function (lines) {
return simplifyLine(lines, tolerance, highQuality);
}
geometry.coordinates = geometry.coordinates.map((lines) =>
simplifyJS(lines, tolerance, highQuality)
);
break;
case "Polygon":
geometry.coordinates = simplifyPolygon(
coordinates as Position[][],
geometry.coordinates,
tolerance,
highQuality
);
break;
case "MultiPolygon":
geometry.coordinates = (coordinates as Position[][][]).map(
function (rings) {
return simplifyPolygon(rings, tolerance, highQuality);
}
geometry.coordinates = geometry.coordinates.map((rings) =>
simplifyPolygon(rings, tolerance, highQuality)
);
}
}

return geometry;
}

/**
* Simplifies the coordinates of a LineString with simplify-js
*
* @private
* @param {Array<number>} coordinates to be processed
* @param {number} tolerance simplification tolerance
* @param {boolean} highQuality whether or not to spend more time to create a higher-quality
* @returns {Array<Array<number>>} simplified coords
*/
function simplifyLine(
coordinates: Position[],
tolerance: number,
highQuality: boolean
) {
return simplifyJS(
coordinates.map(function (coord) {
return { x: coord[0], y: coord[1], z: coord[2] };
}),
tolerance,
highQuality
).map(function (coords) {
return coords.z ? [coords.x, coords.y, coords.z] : [coords.x, coords.y];
});
}

/**
* Simplifies the coordinates of a Polygon with simplify-js
*
Expand All @@ -171,25 +142,15 @@ function simplifyPolygon(
highQuality: boolean
) {
return coordinates.map(function (ring) {
const pts = ring.map(function (coord) {
return { x: coord[0], y: coord[1] };
});
if (pts.length < 4) {
if (ring.length < 4) {
throw new Error("invalid polygon");
}
let simpleRing = simplifyJS(pts, tolerance, highQuality).map(
function (coords) {
return [coords.x, coords.y];
}
);
//remove 1 percent of tolerance until enough points to make a triangle
let ringTolerance = tolerance;
let simpleRing = simplifyJS(ring, ringTolerance, highQuality);
// remove 1 percent of tolerance until enough points to make a triangle
while (!checkValidity(simpleRing)) {
tolerance -= tolerance * 0.01;
simpleRing = simplifyJS(pts, tolerance, highQuality).map(
function (coords) {
return [coords.x, coords.y];
}
);
ringTolerance -= ringTolerance * 0.01;
simpleRing = simplifyJS(ring, ringTolerance, highQuality);
}
if (
simpleRing[simpleRing.length - 1][0] !== simpleRing[0][0] ||
Expand Down
5 changes: 1 addition & 4 deletions packages/turf-simplify/lib/simplify.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
interface Point {
x: number;
y: number;
}
type Point = number[]; // [number, number] | [number, number, number];

declare function simplify<T extends Point>(
points: T[],
Expand Down
22 changes: 11 additions & 11 deletions packages/turf-simplify/lib/simplify.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,33 @@

// square distance between 2 points
function getSqDist(p1, p2) {
var dx = p1.x - p2.x,
dy = p1.y - p2.y;
var dx = p1[0] - p2[0],
dy = p1[1] - p2[1];

return dx * dx + dy * dy;
}

// square distance from a point to a segment
function getSqSegDist(p, p1, p2) {
var x = p1.x,
y = p1.y,
dx = p2.x - x,
dy = p2.y - y;
var x = p1[0],
y = p1[1],
dx = p2[0] - x,
dy = p2[1] - y;

if (dx !== 0 || dy !== 0) {
var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
var t = ((p[0] - x) * dx + (p[1] - y) * dy) / (dx * dx + dy * dy);

if (t > 1) {
x = p2.x;
y = p2.y;
x = p2[0];
y = p2[1];
} else if (t > 0) {
x += dx * t;
y += dy * t;
}
}

dx = p.x - x;
dy = p.y - y;
dx = p[0] - x;
dy = p[1] - y;

return dx * dx + dy * dy;
}
Expand Down

0 comments on commit e455f4f

Please sign in to comment.