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

Diverged Fork #1

Closed
wants to merge 4 commits into from
Closed
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
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
debug
debug
readme-imgs
3 changes: 0 additions & 3 deletions .travis.yml

This file was deleted.

3 changes: 1 addition & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2014-2020, Andrii Heonia
Copyright (c) 2014-2024, Andrii Heonia
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand All @@ -25,4 +25,3 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR 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.

84 changes: 53 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
Hull.js - JavaScript library that builds concave hull by set of points.

[![Build Status](https://travis-ci.org/AndriiHeonia/hull.svg?branch=master)](https://travis-ci.org/AndriiHeonia/hull)
Hull.js is a JavaScript library that builds concave hull by a set of points.

## Examples

Expand All @@ -12,8 +10,8 @@ See live examples <a target="_blank" href="http://andriiheonia.github.io/hull/">
hull(points, 50); // returns points of the hull (in clockwise order)

## Params
* 1st param - array of coordinates in format: `[[x1, y1], [x2, y2], ..., [xn, yn]]`;
* 2nd param - concavity. `1` - thin shape. `Infinity` - convex hull. By default `20`;
* 1st param - array of coordinates in format: `[[x1, y1], [x2, y2], ..., [xn, yn]]`.
* 2nd param - concavity. `1` - thin shape. `Infinity` - convex hull. By default `20`.
* 3rd param - points format. For example: `['.lng', '.lat']` if you have `{lng: x, lat: y}` points. By default you can use `[x, y]` points.

## How it works
Expand Down Expand Up @@ -44,70 +42,94 @@ Let's see step by step what happens when you call `hull()` function:

## Limitations
This library relies on ES6. The ES6 features used are:
- `new Set(null)`, `Set#add`, `Set#has`
- `let`, `const`
- `Math.trunc` (if available)
- `new Set(null)`, `Set#add`, `Set#has`.
- `let`, `const`.
- `Math.trunc` (if available).

You may use [polyfills](https://www.npmjs.com/package/core-js) for `Set` and compile with [babel](https://babeljs.io/) to continue to support old browsers.

## NPM package

This library is not hosted on npmjs.com, but you can use [GitHub URL](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#github-urls) as a dependency, e.g.:

```
"dependencies": {
"hull.js": "andriiheonia/hull"
}
```

## Development
npm install # install dependencies
npm test # build dist file and run tests
npm run-script watch # watch ./src dir and rebuild dist file
npm install # install dependencies
npm test # build dist file and run tests
npm run watch # watch ./src dir and rebuild dist file

## TypeScript

You can find TypeScript type definitions in `src` folder.

## Contribute

If you want to get involved with Hull.js development, just use <a href="https://guides.github.com/introduction/flow/index.html" target="_blank">github flow</a> and feel free to contribute!

## To-do

* think about holes;
* think about holes.
* think about automatic `concavity` adjustment based on density.

## Related papers

* <a target="_blank" href="http://www.it.uu.se/edu/course/homepage/projektTDB/ht13/project10/Project-10-report.pdf">Implementation of a fast and efficient concave hull algorithm</a>;
* <a target="_blank" href="http://www.cs.jhu.edu/~misha/Fall05/09.13.05.pdf">Computational Geometry: Convex Hulls</a>;
* <a target="_blank" href="https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain">Andrew's monotone chain convex hull algorithm</a>;
* <a target="_blank" href="http://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/">Line Segment Intersection Algorithm</a>;
* <a target="_blank" href="http://allenchou.net/2013/07/cross-product-of-2d-vectors/">Game Math: "Cross Product" of 2D Vectors</a>;
* <a target="_blank" href="http://users.livejournal.com/_winnie/237714.html">Угол между двумя векторами</a>;
* <a target="_blank" href="http://www.it.uu.se/edu/course/homepage/projektTDB/ht13/project10/Project-10-report.pdf">Implementation of a fast and efficient concave hull algorithm</a>.
* <a target="_blank" href="http://www.cs.jhu.edu/~misha/Fall05/09.13.05.pdf">Computational Geometry: Convex Hulls</a>.
* <a target="_blank" href="https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain">Andrew's monotone chain convex hull algorithm</a>.
* <a target="_blank" href="http://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/">Line Segment Intersection Algorithm</a>.
* <a target="_blank" href="http://allenchou.net/2013/07/cross-product-of-2d-vectors/">Game Math: "Cross Product" of 2D Vectors</a>.
* <a target="_blank" href="http://users.livejournal.com/_winnie/237714.html">Угол между двумя векторами</a>.
* <a target="_blank" href="http://habrahabr.ru/post/105882/">Когда не нужна тригонометрия</a>.

## Changelog

<details>
<summary>Expand</summary>

### 1.0.8 - 31.05.2024
- Deprecate library on [npmjs registry](https://docs.npmjs.com/cli/v10/using-npm/registry).
### 1.0.7 - 03.05.2024
This release squashes former 1.0.3, 1.0.4, 1.0.5 and 1.0.6 releases into one reasonable commit with the following minor changes:
- Fix issue with formatting when users pass less than 4 points as an input.
- Remove bower and travis files as they are deprecated.
### 1.0.2 — 26.09.2021
- Clean up .gitignore.
- Add "debug" folder to .npmignore to reduce tarball size.
### 1.0.1 — 24.10.2020
Introduce fix that avoids hitting stack size limit on large arrays.
- Fix that avoids hitting stack size limit on large arrays.
### 1.0.0 — 28.06.2019
- Change language level to ES6.
- Performance improvements.
### 0.2.11 — 05.05.2019
Return the first point as the last point when fewer than 4 unique points are provided.
- Minor changes: return the first point as the last point when fewer than 4 unique points are provided.
### 0.2.10 — 04.09.2016
Fix missing "var" declaration.
- Minor changes: fix missing "var" declaration.
### 0.2.9 — 28.07.2016
- Fix modification of the initial array.
- Add filtration of the duplicates.
### 0.2.8 — 01.04.2016
Add edgeSkipList to increase performance of the highly accurate shapes (with the small `concavity` number) + refactoring.
- Add edgeSkipList to increase performance of the highly accurate shapes (with the small `concavity` number) + some refactoring.
### 0.2.7 — 01.05.2015
Fix bower.json.
- Minor changes: fix bower.json.
### 0.2.6 — 01.05.2015
Fix bower.json.
- Minor changes: fix bower.json.
### 0.2.5 — 01.05.2015
Bower support.
- Minor changes: Bower support.
### 0.2.4 — 23.03.2015
Minor fixes (copyrights).
- Minor changes: copyrights.
### 0.2.3 — 04.02.2015
Minor fixes (readme, package.json).
- Minor changes: readme, package.json.
### 0.2.2 — 04.02.2015
Configurable point formats, now you can use points like `{x: 10, y: 10}` and `{lat: 52, lng: 82}`.
- Configurable point format, now you can use points like `{x: 10, y: 10}` and `{lat: 52, lng: 82}`.
### 0.2.1 — 21.10.2014
Some minor updates (doc, package.json, etc.).
- Minor changes: doc, package.json, etc.
### 0.2.0 — 20.10.2014
Second version with better performance inspired by <a href="http://www.it.uu.se/edu/course/homepage/projektTDB/ht13/project10/Project-10-report.pdf" target="_blank">this</a> article.
- Second version with better performance inspired by <a href="http://www.it.uu.se/edu/course/homepage/projektTDB/ht13/project10/Project-10-report.pdf" target="_blank">this</a> article.
### 0.1.0 — 06.09.2014
First version based on Delaunay triangulation.
- First version based on Delaunay triangulation.
</details>
32 changes: 0 additions & 32 deletions bower.json

This file was deleted.

13 changes: 5 additions & 8 deletions dist/hull.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ function grid(points, cellSize) {
module.exports = grid;
},{}],4:[function(require,module,exports){
/*
(c) 2014-2020, Andrii Heonia
Hull.js, a JavaScript library for concave hull generation by set of points.
(c) 2014-2024, Andrii Heonia
Hull.js, a JavaScript library for concave hull generation by the set of points.
https://github.com/AndriiHeonia/hull
*/

Expand Down Expand Up @@ -321,7 +321,8 @@ function hull(pointset, concavity, format) {
const points = _filterDuplicates(_sortByX(formatUtil.toXy(pointset, format)));

if (points.length < 4) {
return points.concat([points[0]]);
const concave = points.concat([points[0]]);
return format ? formatUtil.fromXy(concave, format) : concave;
}

const occupiedArea = _occupiedArea(points);
Expand All @@ -341,11 +342,7 @@ function hull(pointset, concavity, format) {
convex, Math.pow(maxEdgeLen, 2),
maxSearchArea, grid(innerPoints, cellSize), new Set());

if (format) {
return formatUtil.fromXy(concave, format);
} else {
return concave;
}
return format ? formatUtil.fromXy(concave, format) : concave;
}

const MAX_CONCAVE_ANGLE_COS = Math.cos(90 / (180 / Math.PI)); // angle = 90 deg
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"name": "hull.js",
"version": "1.0.2",
"description": "JavaScript library that builds concave hulls (shapes) by set of points",
"version": "1.0.8",
"description": "JavaScript library that builds concave hulls (shapes) by the set of points",
"homepage": "https://github.com/AndriiHeonia/hull",
"keywords": [
"geometry",
"concave-hull",
"math",
"alpha-shape",
"algorithm"
],
"author": "Andrii Heonia <a.heonia@gmail.com>",
"author": "Andrii Heonia",
"repository": {
"type": "git",
"url": "git://github.com/AndriiHeonia/hull.git"
},
"main": "./src/hull.js",
"types": "./src/hull.d.ts",
"devDependencies": {
"nodemon": "~1.18.0",
"mocha": "~6.0.2",
Expand Down
12 changes: 12 additions & 0 deletions src/hull.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Builds concave hull by the set of points.
*
* @param pointset - An array of coordinates in format: `[[x1, y1], [x2, y2], ..., [xn, yn]]`.
* @param concavity - 1 - thin shape. Infinity - convex hull. By default 20.
* @param format - Points format, for example: `['.lng', '.lat']` if you have `{lng: x, lat: y}` points. By default you can use `[x, y]` points.
*
* @returns An array of coordinates in the same format as the given `pointset`.
*/
declare function hull(pointset: number[][] | object[], concavity?: number, format?: string[]): number[][] | object[];

export = hull;
13 changes: 5 additions & 8 deletions src/hull.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
(c) 2014-2021, Andrii Heonia
Hull.js, a JavaScript library for concave hull generation by set of points.
(c) 2014-2024, Andrii Heonia
Hull.js, a JavaScript library for concave hull generation by the set of points.
https://github.com/AndriiHeonia/hull
*/

Expand Down Expand Up @@ -166,7 +166,8 @@ function hull(pointset, concavity, format) {
const points = _filterDuplicates(_sortByX(formatUtil.toXy(pointset, format)));

if (points.length < 4) {
return points.concat([points[0]]);
const concave = points.concat([points[0]]);
return format ? formatUtil.fromXy(concave, format) : concave;
}

const occupiedArea = _occupiedArea(points);
Expand All @@ -186,11 +187,7 @@ function hull(pointset, concavity, format) {
convex, Math.pow(maxEdgeLen, 2),
maxSearchArea, grid(innerPoints, cellSize), new Set());

if (format) {
return formatUtil.fromXy(concave, format);
} else {
return concave;
}
return format ? formatUtil.fromXy(concave, format) : concave;
}

const MAX_CONCAVE_ANGLE_COS = Math.cos(90 / (180 / Math.PI)); // angle = 90 deg
Expand Down
11 changes: 9 additions & 2 deletions test/hull.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ module.exports = function() {
});

it('should return concave hull with lngs and lats', function() {
const points = [{lng:-0.206792373176235, lat:51.4911165465815 }, {lng:-0.207062672933557, lat:51.4915703125214 }, {lng:-0.207465840096923, lat:51.4912077781219 }, {lng:-0.210193421020222, lat:51.4918159814458 }, {lng:-0.214944392455692, lat:51.4929945001276 }, {lng:-0.208133371509344, lat:51.4910830915252 }, {lng:-0.214162055384851, lat:51.4905275966855 }, {lng:-0.208161917730384, lat:51.4903551232517 }, {lng:-0.209680931181673, lat:51.4901894811742 }, {lng:-0.212571431609104, lat:51.4903145141462 }, {lng:-0.216849005460861, lat:51.4921781720221}];
const expected = [{lng: -0.206792373176235, lat: 51.4911165465815 }, {lng: -0.207062672933557, lat: 51.4915703125214 }, {lng: -0.207465840096923, lat: 51.4912077781219 }, {lng: -0.210193421020222, lat: 51.4918159814458 }, {lng: -0.214944392455692, lat: 51.4929945001276 }, {lng: -0.216849005460861, lat: 51.4921781720221 }, {lng: -0.214162055384851, lat: 51.4905275966855 }, {lng: -0.212571431609104, lat: 51.4903145141462 }, {lng: -0.209680931181673, lat: 51.4901894811742 }, {lng: -0.208161917730384, lat: 51.4903551232517 }, {lng: -0.208133371509344, lat: 51.4910830915252 }, {lng: -0.206792373176235, lat: 51.4911165465815}];
let points,
expected;

points = [{lng:-0.206792373176235, lat:51.4911165465815 }, {lng:-0.207062672933557, lat:51.4915703125214 }, {lng:-0.207465840096923, lat:51.4912077781219 }, {lng:-0.210193421020222, lat:51.4918159814458 }, {lng:-0.214944392455692, lat:51.4929945001276 }, {lng:-0.208133371509344, lat:51.4910830915252 }, {lng:-0.214162055384851, lat:51.4905275966855 }, {lng:-0.208161917730384, lat:51.4903551232517 }, {lng:-0.209680931181673, lat:51.4901894811742 }, {lng:-0.212571431609104, lat:51.4903145141462 }, {lng:-0.216849005460861, lat:51.4921781720221}];
expected = [{lng: -0.206792373176235, lat: 51.4911165465815 }, {lng: -0.207062672933557, lat: 51.4915703125214 }, {lng: -0.207465840096923, lat: 51.4912077781219 }, {lng: -0.210193421020222, lat: 51.4918159814458 }, {lng: -0.214944392455692, lat: 51.4929945001276 }, {lng: -0.216849005460861, lat: 51.4921781720221 }, {lng: -0.214162055384851, lat: 51.4905275966855 }, {lng: -0.212571431609104, lat: 51.4903145141462 }, {lng: -0.209680931181673, lat: 51.4901894811742 }, {lng: -0.208161917730384, lat: 51.4903551232517 }, {lng: -0.208133371509344, lat: 51.4910830915252 }, {lng: -0.206792373176235, lat: 51.4911165465815}];
assert.deepEqual(hull(points, 0.0011, ['.lng', '.lat']), expected);

points = [{lat: 10, lng: 10}, {lat: 100, lng: 10}, {lat: 100, lng: 100}];
expected = [{lat: 10, lng: 10}, {lat: 100, lng: 10}, {lat: 100, lng: 100}, {lat: 10, lng: 10}];
assert.deepEqual(hull(points, 10, ['.lng', '.lat']), expected);
});

it('should append the first point', function() {
Expand Down