Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverse winding @turf/rewind #741

Merged
merged 1 commit into from
May 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 3 additions & 25 deletions packages/turf-rewind/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

# rewind

Rewind [(Mutli)LineString](http://geojson.org/geojson-spec.html#linestring) or [(Multi)Polygon](http://geojson.org/geojson-spec.html#polygon) outer ring clockwise and inner rings counterclockwise (Uses [Shoelace Formula](http://en.wikipedia.org/wiki/Shoelace_formula)).
Rewind [(Multi)LineString](http://geojson.org/geojson-spec.html#linestring) or [(Multi)Polygon](http://geojson.org/geojson-spec.html#polygon) outer ring counterclockwise and inner rings clockwise (Uses [Shoelace Formula](http://en.wikipedia.org/wiki/Shoelace_formula)).

**Parameters**

- `geojson` **[Feature](http://geojson.org/geojson-spec.html#feature-objects)<([Polygon](http://geojson.org/geojson-spec.html#polygon) \| [MultiPolygon](http://geojson.org/geojson-spec.html#multipolygon) \| [LineString](http://geojson.org/geojson-spec.html#linestring) \| [MultiLineString](http://geojson.org/geojson-spec.html#multilinestring))>** input GeoJSON Polygon
- `geojson` **([FeatureCollection](http://geojson.org/geojson-spec.html#feature-collection-objects) \| [Geometry](http://geojson.org/geojson-spec.html#geometry) \| [Feature](http://geojson.org/geojson-spec.html#feature-objects)<([Polygon](http://geojson.org/geojson-spec.html#polygon) \| [MultiPolygon](http://geojson.org/geojson-spec.html#multipolygon) \| [LineString](http://geojson.org/geojson-spec.html#linestring) \| [MultiLineString](http://geojson.org/geojson-spec.html#multilinestring))>)** input GeoJSON Polygon
- `reverse` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** enable reverse winding (optional, default `false`)
- `mutate` **\[[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** allows GeoJSON input to be mutated (significant performance increase if true) (optional, default `false`)

Expand All @@ -29,29 +29,7 @@ var rewind = turf.rewind(polygon);
var addToMap = [rewind];
```

Returns **[Feature](http://geojson.org/geojson-spec.html#feature-objects)<([Polygon](http://geojson.org/geojson-spec.html#polygon) \| [MultiPolygon](http://geojson.org/geojson-spec.html#multipolygon) \| [LineString](http://geojson.org/geojson-spec.html#linestring) \| [MultiLineString](http://geojson.org/geojson-spec.html#multilinestring))>** rewind Polygon

# rewindLineString

Rewind LineString - outer ring clockwise

**Parameters**

- `coords` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>>** GeoJSON LineString geometry coordinates
- `reverse` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** enable reverse winding (optional, default `false`)

Returns **void** mutates coordinates

# rewindPolygon

Rewind Polygon - outer ring clockwise and inner rings counterclockwise.

**Parameters**

- `coords` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>>>** GeoJSON Polygon geometry coordinates
- `reverse` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** enable reverse winding (optional, default `false`)

Returns **void** mutates coordinates
Returns **([FeatureCollection](http://geojson.org/geojson-spec.html#feature-collection-objects) \| [Geometry](http://geojson.org/geojson-spec.html#geometry) \| [Feature](http://geojson.org/geojson-spec.html#feature-objects)<([Polygon](http://geojson.org/geojson-spec.html#polygon) \| [MultiPolygon](http://geojson.org/geojson-spec.html#multipolygon) \| [LineString](http://geojson.org/geojson-spec.html#linestring) \| [MultiLineString](http://geojson.org/geojson-spec.html#multilinestring))>)** rewind Polygon

<!-- This file is automatically generated. Please don't edit it directly:
if you find an error, edit the source file (likely index.js), and re-run
Expand Down
11 changes: 6 additions & 5 deletions packages/turf-rewind/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ let fixtures = fs.readdirSync(directory).map(filename => {
/**
* Benchmark Results
*
* geometry-polygon-counter-clockwise x 10,379,811 ops/sec ±0.84% (89 runs sampled)
* line-clockwise x 7,937,098 ops/sec ±1.13% (90 runs sampled)
* line-counter-clockwise x 6,324,221 ops/sec ±5.40% (74 runs sampled)
* polygon-clockwise x 8,941,337 ops/sec ±2.95% (81 runs sampled)
* polygon-counter-clockwise x 7,625,375 ops/sec ±12.27% (72 runs sampled)
* feature-collection x 2,476,533 ops/sec ±2.44% (80 runs sampled)
* geometry-polygon-counter-clockwise x 7,422,622 ops/sec ±1.79% (87 runs sampled)
* line-clockwise x 5,845,725 ops/sec ±1.55% (86 runs sampled)
* line-counter-clockwise x 5,889,989 ops/sec ±1.03% (88 runs sampled)
* polygon-clockwise x 4,898,849 ops/sec ±8.02% (75 runs sampled)
* polygon-counter-clockwise x 6,586,601 ops/sec ±6.10% (82 runs sampled)
*/
const suite = new Benchmark.Suite('turf-rewind');
for (const {name, geojson} of fixtures) {
Expand Down
19 changes: 13 additions & 6 deletions packages/turf-rewind/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
/// <reference types="geojson" />

type Polygon = GeoJSON.Feature<GeoJSON.Polygon> | GeoJSON.Polygon;
type LineString = GeoJSON.Feature<GeoJSON.LineString> | GeoJSON.LineString;
type MultiLineString = GeoJSON.Feature<GeoJSON.MultiLineString> | GeoJSON.MultiLineString;
type MultiPolygon = GeoJSON.Feature<GeoJSON.MultiPolygon> | GeoJSON.MultiPolygon;
type Rewind = Polygon | LineString | MultiLineString | MultiPolygon;
import {Units, FeatureGeometryCollection} from '@turf/helpers';

type LineString = GeoJSON.LineString;
type Polygon = GeoJSON.Polygon;
type MultiLineString = GeoJSON.MultiLineString;
type MultiPolygon = GeoJSON.MultiPolygon;
type GeometryObject = GeoJSON.GeometryObject;
type GeometryCollection = GeoJSON.GeometryCollection;
type Feature<Geom extends GeometryObject> = GeoJSON.Feature<Geom>;
type FeatureCollection<Geom extends GeometryObject> = GeoJSON.FeatureCollection<Geom>;
type Geoms = LineString|Polygon|MultiLineString|MultiPolygon;
type Input = FeatureCollection<Geoms> | Feature<Geoms> | Geoms | FeatureGeometryCollection;

/**
* http://turfjs.org/docs/#rewind
*/
declare function rewind<Input extends Rewind>(geojson: Input, reversed?: boolean, mutate?: boolean): Input;
declare function rewind<T extends Input>(geojson: T, reversed?: boolean, mutate?: boolean): T;
declare namespace rewind { }
export = rewind;
75 changes: 56 additions & 19 deletions packages/turf-rewind/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
var meta = require('@turf/meta');
var getCoords = require('@turf/invariant').getCoords;
var isClockWise = require('turf-is-clockwise');
var featureCollection = require('@turf/helpers').featureCollection;
var geomEach = meta.geomEach;
var featureEach = meta.featureEach;

/**
* Rewind {@link LineString|(Mutli)LineString} or {@link Polygon|(Multi)Polygon} outer ring clockwise and inner rings counterclockwise (Uses {@link http://en.wikipedia.org/wiki/Shoelace_formula|Shoelace Formula}).
* Rewind {@link LineString|(Multi)LineString} or {@link Polygon|(Multi)Polygon} outer ring counterclockwise and inner rings clockwise (Uses {@link http://en.wikipedia.org/wiki/Shoelace_formula|Shoelace Formula}).
*
* @name rewind
* @param {Feature<Polygon|MultiPolygon|LineString|MultiLineString>} geojson input GeoJSON Polygon
* @param {FeatureCollection|Geometry|Feature<Polygon|MultiPolygon|LineString|MultiLineString>} geojson input GeoJSON Polygon
* @param {Boolean} [reverse=false] enable reverse winding
* @param {boolean} [mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
* @returns {Feature<Polygon|MultiPolygon|LineString|MultiLineString>} rewind Polygon
* @returns {FeatureCollection|Geometry|Feature<Polygon|MultiPolygon|LineString|MultiLineString>} rewind Polygon
* @example
* var polygon = {
* "type": "Feature",
Expand Down Expand Up @@ -38,34 +42,70 @@ module.exports = function (geojson, reverse, mutate) {
// prevent input mutation
if (mutate === false || mutate === undefined) geojson = JSON.parse(JSON.stringify(geojson));

var coords = getCoords(geojson);
var type = getGeomType(geojson);
// Support Feature Collection or Geometry Collection
var results = [];
switch (geojson.type) {
case 'GeometryCollection':
geomEach(geojson, function (geometry) {
rewind(geometry, reverse);
});
return geojson;
case 'FeatureCollection':
featureEach(geojson, function (feature) {
featureEach(rewind(feature, reverse), function (result) {
results.push(result);
});
});
return featureCollection(results);
}
// Support Feature or Geometry Objects
return rewind(geojson, reverse);
};

/**
* Rewind
*
* @private
* @param {Geometry|Feature<any>} geojson Geometry or Feature
* @param {Boolean} [reverse=false] enable reverse winding
* @returns {Geometry|Feature<any>} rewind Geometry or Feature
*/
function rewind(geojson, reverse) {
var type = (geojson.type === 'Feature') ? geojson.geometry.type : geojson.type;

// Support all GeoJSON Geometry Objects
switch (type) {
case 'GeometryCollection':
geomEach(geojson, function (geometry) {
rewind(geometry, reverse);
});
return geojson;
case 'LineString':
rewindLineString(coords, reverse);
rewindLineString(getCoords(geojson), reverse);
return geojson;
case 'Polygon':
rewindPolygon(coords, reverse);
rewindPolygon(getCoords(geojson), reverse);
return geojson;
case 'MultiLineString':
coords.forEach(function (lineCoords) {
getCoords(geojson).forEach(function (lineCoords) {
rewindLineString(lineCoords, reverse);
});
return geojson;
case 'MultiPolygon':
coords.forEach(function (lineCoords) {
getCoords(geojson).forEach(function (lineCoords) {
rewindPolygon(lineCoords, reverse);
});
return geojson;
default:
throw new Error('geometry ' + type + ' type not supported');
case 'Point':
case 'MultiPoint':
return geojson;
}
};
}

/**
* Rewind LineString - outer ring clockwise
*
* @private
* @param {Array<Array<number>>} coords GeoJSON LineString geometry coordinates
* @param {Boolean} [reverse=false] enable reverse winding
* @returns {void} mutates coordinates
Expand All @@ -75,25 +115,22 @@ function rewindLineString(coords, reverse) {
}

/**
* Rewind Polygon - outer ring clockwise and inner rings counterclockwise.
* Rewind Polygon - outer ring counterclockwise and inner rings clockwise.
*
* @private
* @param {Array<Array<Array<number>>>} coords GeoJSON Polygon geometry coordinates
* @param {Boolean} [reverse=false] enable reverse winding
* @returns {void} mutates coordinates
*/
function rewindPolygon(coords, reverse) {
// outer ring
if (isClockWise(coords[0]) === reverse) {
if (isClockWise(coords[0]) !== reverse) {
coords[0].reverse();
}
// inner rings
for (var i = 1; i < coords.length; i++) {
if (isClockWise(coords[i]) !== reverse) {
if (isClockWise(coords[i]) === reverse) {
coords[i].reverse();
}
}
}

function getGeomType(feature) {
return (feature.geometry) ? feature.geometry.type : feature.type;
}
3 changes: 2 additions & 1 deletion packages/turf-rewind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@
},
"homepage": "https://github.com/Turfjs/turf",
"devDependencies": {
"@turf/helpers": "^4.3.0",
"benchmark": "^2.1.4",
"load-json-file": "^2.0.0",
"tape": "^4.6.3",
"write-json-file": "^2.0.0"
},
"dependencies": {
"@turf/helpers": "^4.3.0",
"@turf/invariant": "^4.3.0",
"@turf/meta": "^4.3.0",
"turf-is-clockwise": "^1.0.0"
}
}
29 changes: 28 additions & 1 deletion packages/turf-rewind/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const test = require('tape');
const path = require('path');
const load = require('load-json-file');
const write = require('write-json-file');
const {polygon, lineString, featureCollection, geometryCollection} = require('@turf/helpers');
const rewind = require('./');

const directories = {
Expand All @@ -17,7 +18,7 @@ let fixtures = fs.readdirSync(directories.in).map(filename => {
geojson: load.sync(directories.in + filename)
};
});
// fixtures = fixtures.filter(fixture => fixture.name === 'line-counter-clockwise');
// fixtures = fixtures.filter(fixture => fixture.name === 'polygon-clockwise');

test('turf-rewind', t => {
for (const {filename, name, geojson} of fixtures) {
Expand All @@ -29,3 +30,29 @@ test('turf-rewind', t => {
}
t.end();
});

test('turf-buffer - Support Geometry Objects', t => {
const line = lineString([[11, 0], [22, 4], [31, 0], [31, 11]]);
const poly = polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);
const gc = geometryCollection([poly.geometry, line.geometry]);
const fc = featureCollection([poly, line]);

t.assert(rewind(line.geometry), 'support LineString Geometry');
t.assert(rewind(poly.geometry), 'support Polygon Geometry');
t.assert(rewind(fc), 'support Feature Collection');
t.assert(rewind(gc), 'support Geometry Collection');
t.end();
});

test('turf-buffer - Prevent Input Mutation', t => {
const line = lineString([[11, 0], [22, 4], [31, 0], [31, 11]]);
const poly = polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);
const beforePoly = JSON.parse(JSON.stringify(poly));
const beforeLine = JSON.parse(JSON.stringify(line));
rewind(poly);
rewind(line);

t.deepEqual(poly, beforePoly, 'poly should not mutate');
t.deepEqual(line, beforeLine, 'line should not mutate');
t.end();
});
60 changes: 60 additions & 0 deletions packages/turf-rewind/test/in/feature-collection.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
130.1220703125,
-16.383391123608387
],
[
126.38671874999999,
-17.518344187852207
],
[
123.79394531249999,
-21.248422235627014
],
[
123.96972656249999,
-26.431228064506424
],
[
127.2216796875,
-29.80251790576445
],
[
132.5830078125,
-30.637912028341113
],
[
137.3291015625,
-28.92163128242129
],
[
140.09765625,
-25.403584973186703
],
[
140.18554687499997,
-20.097206227083888
],
[
137.1533203125,
-16.804541076383455
],
[
130.1220703125,
-16.383391123608387
]
]
]
}
}
]
}
25 changes: 1 addition & 24 deletions packages/turf-rewind/test/in/polygon-clockwise.geojson
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,6 @@
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
121.9921875,
-29.22889003019423
],
[
121.9921875,
-18.312810846425442
],
[
138.515625,
-18.312810846425442
],
[
138.515625,
-29.22889003019423
],
[
121.9921875,
-29.22889003019423
]
]
]
"coordinates": [[[0, 0], [1, 1], [1, 0], [0, 0]]]
}
}
Loading