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

Revamp grid modules #1029

Merged
merged 30 commits into from
Oct 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d7b7fd4
renames cellDiameter to cellSide; refactored tests;
stebogit Oct 11, 2017
b10f448
refactores square-grid test; uniforms params acrodd grid modules
stebogit Oct 15, 2017
fbff9e7
fixes hex-grid adjusts; fixes tests;
stebogit Oct 18, 2017
5707d95
adds forgotten parenthesis
stebogit Oct 18, 2017
2a5c4aa
fises hex-grid types
stebogit Oct 18, 2017
34b6fb9
adds big-bbox test to point-grid
stebogit Oct 18, 2017
5aaf371
set bbox type as array for grid modules; refactored test for point-grid;
stebogit Oct 19, 2017
018a988
refactores and fixes test for square-grid;
stebogit Oct 19, 2017
18fb02b
Merge branch 'master' into hex-grid
stebogit Oct 19, 2017
881b55b
Merge branch 'master' into hex-grid
DenisCarriere Oct 21, 2017
07cfbdc
Update typescript definition
DenisCarriere Oct 21, 2017
1e54867
Update cellSide param name & update docs
DenisCarriere Oct 21, 2017
7693fcd
Truncate test results
DenisCarriere Oct 21, 2017
2ea3973
Add options.mask validation
DenisCarriere Oct 21, 2017
7ebdd2a
merge maskIsPoly to Input validation
DenisCarriere Oct 21, 2017
d96213e
Replace inside with boolean-within
DenisCarriere Oct 21, 2017
3e7d840
square-grid - truncate results & add mask
DenisCarriere Oct 21, 2017
3ec679b
Update test fixtures
DenisCarriere Oct 21, 2017
9e45214
Refactor triangle-grid
DenisCarriere Oct 21, 2017
3a51a4c
Add boolean-overlap to triangle-grid
DenisCarriere Oct 22, 2017
8923345
Update hex-grid
DenisCarriere Oct 23, 2017
28a59ae
Add contains + overlap
DenisCarriere Oct 23, 2017
1788bf7
Add contains + overlap square grid
DenisCarriere Oct 23, 2017
c133d06
Switch contain + overlap => intersect
DenisCarriere Oct 23, 2017
5c20db3
Add intersect to hex-grid
DenisCarriere Oct 23, 2017
61686bc
Add outline to mask
DenisCarriere Oct 23, 2017
a2b1651
Update README's
DenisCarriere Oct 23, 2017
366eeed
Fix transform-scale hex output fixture
DenisCarriere Oct 23, 2017
49dfb65
Update interpolate fixtures
DenisCarriere Oct 23, 2017
bbdc218
Merge branch 'master' into hex-grid
DenisCarriere Oct 25, 2017
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
2 changes: 2 additions & 0 deletions packages/turf-convex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ implements a [monotone chain hull](http://en.wikibooks.org/wiki/Algorithm_Implem
**Parameters**

- `geojson` **[GeoJSON](http://geojson.org/geojson-spec.html#geojson-objects)** input Feature or FeatureCollection
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Optional parameters (optional, default `{}`)
- `options.concavity` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** 1 - thin shape. Infinity - convex hull. (optional, default `Infinity`)

**Examples**

Expand Down
10 changes: 7 additions & 3 deletions packages/turf-hex-grid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,22 @@ described in [Hexagonal Grids](http://www.redblobgames.com/grids/hexagons/).
**Parameters**

- `bbox` **[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)>** extent in [minX, minY, maxX, maxY] order
- `cellDiameter` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** diameter of the circumcircle of the hexagons, in specified units
- `cellSide` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** length of the side of the the hexagons or triangles, in units. It will also coincide with the
radius of the circumcircle of the hexagons.
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Optional parameters (optional, default `{}`)
- `options.units` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** used in calculating cell size, can be degrees, radians, miles, or kilometers (optional, default `'kilometers'`)
- `options.properties` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** passed to each hexagon or triangle of the grid (optional, default `{}`)
- `options.mask` **[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))>?** if passed a Polygon or MultiPolygon, the grid Points will be created only inside it
- `options.triangles` **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** whether to return as triangles instead of hexagons (optional, default `false`)

**Examples**

```javascript
var bbox = [-96,31,-84,40];
var cellDiameter = 50;
var cellSide = 50;
var options = {units: 'miles'};

var hexgrid = turf.hexGrid(bbox, cellDiameter, {units: 'miles'});
var hexgrid = turf.hexGrid(bbox, cellSide, options);

//addToMap
var addToMap = [hexgrid];
Expand Down
12 changes: 6 additions & 6 deletions packages/turf-hex-grid/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ var bbox = [
40.58058466412764
];

var lowres = grid(bbox, 100, 'miles').features.length;
var midres = grid(bbox, 10, 'miles').features.length;
var highres = grid(bbox, 1, 'miles').features.length;
var lowres = grid(bbox, 100, {units: 'miles'}).features.length;
var midres = grid(bbox, 10, {units: 'miles'}).features.length;
var highres = grid(bbox, 1, {units: 'miles'}).features.length;

var suite = new Benchmark.Suite('turf-hex-grid');
suite
.add('turf-hex-grid -- ' + lowres + ' cells', function () {
grid(bbox, 100, 'miles');
grid(bbox, 100, {units: 'miles'});
})
.add('turf-hex-grid -- ' + midres + ' cells', function () {
grid(bbox, 10, 'miles');
grid(bbox, 10, {units: 'miles'});
})
.add('turf-hex-grid -- ' + highres + ' cells', function () {
grid(bbox, 1, 'miles');
grid(bbox, 1, {units: 'miles'});
})
.on('cycle', function (event) {
console.log(String(event.target));
Expand Down
17 changes: 8 additions & 9 deletions packages/turf-hex-grid/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import {
Units,
BBox,
Polygon,
FeatureCollection
} from '@turf/helpers'
import { Units, BBox, Polygon, MultiPolygon, Feature, FeatureCollection, Point, Properties } from '@turf/helpers';

/**
* http://turfjs.org/docs/#hexgrid
*/
export default function hexGrid(
bbox: BBox,
cellDiameter: number,
units?: Units,
triangles?: boolean
cellSide: number,
options?: {
units?: Units,
triangles?: boolean,
properties?: Properties,
mask?: Feature<Polygon | MultiPolygon> | Polygon | MultiPolygon;
}
): FeatureCollection<Polygon>;
146 changes: 102 additions & 44 deletions packages/turf-hex-grid/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import distance from '@turf/distance';
import { point, polygon, featureCollection } from '@turf/helpers';

// Precompute cosines and sines of angles used in hexagon creation
// for performance gain
var cosines = [];
var sines = [];
for (var i = 0; i < 6; i++) {
var angle = 2 * Math.PI / 6 * i;
cosines.push(Math.cos(angle));
sines.push(Math.sin(angle));
}
import intersect from '@turf/intersect';
import {getType} from '@turf/invariant';
import {polygon, featureCollection, isObject, isNumber} from '@turf/helpers';

/**
* Takes a bounding box and the diameter of the cell and returns a {@link FeatureCollection} of flat-topped
Expand All @@ -18,25 +10,40 @@ for (var i = 0; i < 6; i++) {
*
* @name hexGrid
* @param {Array<number>} bbox extent in [minX, minY, maxX, maxY] order
* @param {number} cellDiameter diameter of the circumcircle of the hexagons, in specified units
* @param {number} cellSide length of the side of the the hexagons or triangles, in units. It will also coincide with the
* radius of the circumcircle of the hexagons.
* @param {Object} [options={}] Optional parameters
* @param {string} [options.units='kilometers'] used in calculating cell size, can be degrees, radians, miles, or kilometers
* @param {Object} [options.properties={}] passed to each hexagon or triangle of the grid
* @param {Feature<Polygon|MultiPolygon>} [options.mask] if passed a Polygon or MultiPolygon, the grid Points will be created only inside it
* @param {boolean} [options.triangles=false] whether to return as triangles instead of hexagons
* @returns {FeatureCollection<Polygon>} a hexagonal grid
* @example
* var bbox = [-96,31,-84,40];
* var cellDiameter = 50;
* var cellSide = 50;
* var options = {units: 'miles'};
*
* var hexgrid = turf.hexGrid(bbox, cellDiameter, {units: 'miles'});
* var hexgrid = turf.hexGrid(bbox, cellSide, options);
*
* //addToMap
* var addToMap = [hexgrid];
*/
function hexGrid(bbox, cellDiameter, options) {
function hexGrid(bbox, cellSide, options) {
// Optional parameters
options = options || {};
if (typeof options !== 'object') throw new Error('options is invalid');
if (!isObject(options)) throw new Error('options is invalid');
// var units = options.units;
var properties = options.properties || {};
var triangles = options.triangles;
var mask = options.mask;

// validation
if (cellSide === null || cellSide === undefined) throw new Error('cellSide is required');
if (!isNumber(cellSide)) throw new Error('cellSide is invalid');
if (!bbox) throw new Error('bbox is required');
if (!Array.isArray(bbox)) throw new Error('bbox must be array');
if (bbox.length !== 4) throw new Error('bbox must contain 4 numbers');
if (mask && ['Polygon', 'MultiPolygon'].indexOf(getType(mask)) === -1) throw new Error('options.mask must be a (Multi)Polygon');

var west = bbox[0];
var south = bbox[1];
Expand All @@ -46,9 +53,9 @@ function hexGrid(bbox, cellDiameter, options) {
var centerX = (west + east) / 2;

// https://github.com/Turfjs/turf/issues/758
var xFraction = cellDiameter / (distance(point([west, centerY]), point([east, centerY]), options));
var xFraction = cellSide * 2 / (distance([west, centerY], [east, centerY], options));
var cellWidth = xFraction * (east - west);
var yFraction = cellDiameter / (distance(point([centerX, south]), point([centerX, north]), options));
var yFraction = cellSide * 2 / (distance([centerX, south], [centerX, north], options));
var cellHeight = yFraction * (north - south);
var radius = cellWidth / 2;

Expand All @@ -61,15 +68,14 @@ function hexGrid(bbox, cellDiameter, options) {
var x_interval = 3 / 4 * hex_width;
var y_interval = hex_height;

var x_span = box_width / (hex_width - radius / 2);
var x_count = Math.ceil(x_span);
if (Math.round(x_span) === x_count) {
x_count++;
}
// adjust box_width so all hexagons will be inside the bbox
var x_span = (box_width - hex_width) / (hex_width - radius / 2);
var x_count = Math.floor(x_span);

var x_adjust = ((x_count * x_interval - radius / 2) - box_width) / 2 - radius / 2;
var x_adjust = ((x_count * x_interval - radius / 2) - box_width) / 2 - radius / 2 + x_interval / 2;

var y_count = Math.ceil(box_height / hex_height);
// adjust box_height so all hexagons will be inside the bbox
var y_count = Math.floor((box_height - hex_height) / hex_height);

var y_adjust = (box_height - y_count * hex_height) / 2;

Expand All @@ -78,38 +84,79 @@ function hexGrid(bbox, cellDiameter, options) {
y_adjust -= hex_height / 4;
}

var fc = featureCollection([]);
for (var x = 0; x < x_count; x++) {
// Precompute cosines and sines of angles used in hexagon creation for performance gain
var cosines = [];
var sines = [];
for (var i = 0; i < 6; i++) {
var angle = 2 * Math.PI / 6 * i;
cosines.push(Math.cos(angle));
sines.push(Math.sin(angle));
}

var results = [];
for (var x = 0; x <= x_count; x++) {
for (var y = 0; y <= y_count; y++) {

var isOdd = x % 2 === 1;
if (y === 0 && isOdd) {
continue;
}

if (y === 0 && hasOffsetY) {
continue;
}
if (y === 0 && isOdd) continue;
if (y === 0 && hasOffsetY) continue;

var center_x = x * x_interval + west - x_adjust;
var center_y = y * y_interval + south + y_adjust;

if (isOdd) {
center_y -= hex_height / 2;
}
if (triangles) {
fc.features.push.apply(fc.features, hexTriangles([center_x, center_y], cellWidth / 2, cellHeight / 2));

if (triangles === true) {
for (var triangle of hexTriangles(
[center_x, center_y],
cellWidth / 2,
cellHeight / 2,
properties,
cosines,
sines
)) {
if (mask) {
if (intersect(mask, triangle)) results.push(triangle);
} else {
results.push(triangle);
}
}
} else {
fc.features.push(hexagon([center_x, center_y], cellWidth / 2, cellHeight / 2));
var hex = hexagon(
[center_x, center_y],
cellWidth / 2,
cellHeight / 2,
properties,
cosines,
sines
);
if (mask) {
if (intersect(mask, hex)) results.push(hex);
} else {
results.push(hex);
}
}
}
}

return fc;
return featureCollection(results);
}

//Center should be [x, y]
function hexagon(center, rx, ry) {
/**
* Creates hexagon
*
* @private
* @param {Array<number>} center of the hexagon
* @param {number} rx half hexagon width
* @param {number} ry half hexagon height
* @param {Object} properties passed to each hexagon
* @param {Array<number>} cosines precomputed
* @param {Array<number>} sines precomputed
* @returns {Feature<Polygon>} hexagon
*/
function hexagon(center, rx, ry, properties, cosines, sines) {
var vertices = [];
for (var i = 0; i < 6; i++) {
var x = center[0] + rx * cosines[i];
Expand All @@ -118,11 +165,22 @@ function hexagon(center, rx, ry) {
}
//first and last vertex must be the same
vertices.push(vertices[0].slice());
return polygon([vertices]);
return polygon([vertices], properties);
}

//Center should be [x, y]
function hexTriangles(center, rx, ry) {
/**
* Creates triangles composing an hexagon
*
* @private
* @param {Array<number>} center of the hexagon
* @param {number} rx half triangle width
* @param {number} ry half triangle height
* @param {Object} properties passed to each triangle
* @param {Array<number>} cosines precomputed
* @param {Array<number>} sines precomputed
* @returns {Array<Feature<Polygon>>} triangles
*/
function hexTriangles(center, rx, ry, properties, cosines, sines) {
var triangles = [];
for (var i = 0; i < 6; i++) {
var vertices = [];
Expand All @@ -136,7 +194,7 @@ function hexTriangles(center, rx, ry) {
center[1] + ry * sines[(i + 1) % 6]
]);
vertices.push(center);
triangles.push(polygon([vertices]));
triangles.push(polygon([vertices], properties));
}
return triangles;
}
Expand Down
12 changes: 7 additions & 5 deletions packages/turf-hex-grid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,20 @@
},
"homepage": "https://github.com/Turfjs/turf",
"devDependencies": {
"@turf/centroid": "*",
"@std/esm": "*",
"@turf/bbox-polygon": "*",
"@turf/truncate": "*",
"benchmark": "*",
"load-json-file": "*",
"tape": "*",
"write-json-file": "*",
"rollup": "*",
"@std/esm": "*"
"tape": "*",
"write-json-file": "*"
},
"dependencies": {
"@turf/distance": "5.x",
"@turf/helpers": "5.x"
"@turf/helpers": "5.x",
"@turf/intersect": "^4.7.4",
"@turf/invariant": "5.x"
},
"@std/esm": {
"esm": "js",
Expand Down
Loading