Converted turf-voronoi to Typescript (#2655)

Converted turf-voronoi to Typescript. Minor changes to code to make more clear what types are being passed where. Fixed some type errors in tests and benchmarks, and where we were trying to find the bbox in the wrong spot.

---------

Co-authored-by: Tim Welch <tim.j.welch@gmail.com>
This commit is contained in:
James Beard 2024-07-23 21:28:13 +10:00 committed by GitHub
parent 584acbc287
commit 499c8d5063
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 122 additions and 50 deletions

View File

@ -4,32 +4,32 @@
## voronoi
Takes a FeatureCollection of points, and a bounding box, and returns a FeatureCollection
Takes a collection of points and a bounding box, and returns a collection
of Voronoi polygons.
The Voronoi algorithim used comes from the d3-voronoi package.
### Parameters
* `points` **[FeatureCollection][1]<[Point][2]>** to find the Voronoi polygons around.
* `points` **[FeatureCollection][1]<[Point][2]>** points around which to calculate the Voronoi polygons
* `options` **[Object][3]** Optional parameters (optional, default `{}`)
* `options.bbox` **[Array][4]<[number][5]>** clipping rectangle, in \[minX, minY, maxX, MaxY] order. (optional, default `[-180,-85,180,-85]`)
* `options.bbox` **[BBox][4]** clipping rectangle, in \[minX, minY, maxX, MaxY] order (optional, default `[-180,-85,180,-85]`)
### Examples
```javascript
var options = {
const options = {
bbox: [-70, 40, -60, 60]
};
var points = turf.randomPoint(100, options);
var voronoiPolygons = turf.voronoi(points, options);
const points = turf.randomPoint(100, options);
const voronoiPolygons = turf.voronoi(points, options);
//addToMap
var addToMap = [voronoiPolygons, points];
const addToMap = [voronoiPolygons, points];
```
Returns **[FeatureCollection][1]<[Polygon][6]>** a set of polygons, one per input point.
Returns **[FeatureCollection][1]<[Polygon][5]>** a set of polygons, one per input point
[1]: https://tools.ietf.org/html/rfc7946#section-3.3
@ -37,11 +37,9 @@ Returns **[FeatureCollection][1]<[Polygon][6]>** a set of polygons, one per inpu
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
[4]: https://tools.ietf.org/html/rfc7946#section-5
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[6]: https://tools.ietf.org/html/rfc7946#section-3.1.6
[5]: https://tools.ietf.org/html/rfc7946#section-3.1.6
<!-- This file is automatically generated. Please don't edit it directly. If you find an error, edit the source file of the module in question (likely index.js or index.ts), and re-run "yarn docs" from the root of the turf project. -->

View File

@ -1,4 +1,5 @@
import Benchmark from "benchmark";
import Benchmark, { Event } from "benchmark";
import { FeatureCollection, Point } from "geojson";
import path from "path";
import { fileURLToPath } from "url";
import fs from "fs";
@ -12,7 +13,7 @@ const fixtures = fs.readdirSync(directory).map((filename) => {
return {
filename,
name: path.parse(filename).name,
geojson: loadJsonFileSync(directory + filename),
geojson: loadJsonFileSync(directory + filename) as FeatureCollection<Point>,
};
});
@ -23,7 +24,7 @@ const fixtures = fs.readdirSync(directory).map((filename) => {
*/
const suite = new Benchmark.Suite("turf-voronoi");
for (const { name, geojson } of fixtures) {
suite.add(name, () => voronoi(geojson, geojson.features[0].properties.bbox));
suite.add(name, () => voronoi(geojson, { bbox: geojson.bbox }));
}
suite.on("cycle", (e) => console.log(String(e.target))).run();
suite.on("cycle", (e: Event) => console.log(String(e.target))).run();

View File

@ -1,12 +0,0 @@
import { FeatureCollection, BBox, Point, Polygon } from "geojson";
/**
* http://turfjs.org/docs/#voronoi
*/
declare function voronoi(
points: FeatureCollection<Point>,
options?: { bbox: BBox }
): FeatureCollection<Polygon>;
export { voronoi };
export default voronoi;

View File

@ -1,45 +1,58 @@
import {
BBox,
Feature,
FeatureCollection,
Point,
Polygon,
Position,
} from "geojson";
import { polygon, featureCollection, isObject } from "@turf/helpers";
import { collectionOf } from "@turf/invariant";
import { cloneProperties } from "@turf/clone";
import * as d3voronoi from "d3-voronoi";
/**
* Creates a polygon from a list of coordinates. Ensures the polygon is closed.
*
* @private
* @param {Array<Array<number>>} coords representing a polygon
* @param {Position[]} coords representing a polygon
* @returns {Feature<Polygon>} polygon
*/
function coordsToPolygon(coords) {
function coordsToPolygon(coords: Position[]) {
coords = coords.slice();
coords.push(coords[0]);
return polygon([coords]);
}
/**
* Takes a FeatureCollection of points, and a bounding box, and returns a FeatureCollection
* Takes a collection of points and a bounding box, and returns a collection
* of Voronoi polygons.
*
* The Voronoi algorithim used comes from the d3-voronoi package.
*
* @name voronoi
* @param {FeatureCollection<Point>} points to find the Voronoi polygons around.
* @param {FeatureCollection<Point>} points points around which to calculate the Voronoi polygons
* @param {Object} [options={}] Optional parameters
* @param {number[]} [options.bbox=[-180, -85, 180, -85]] clipping rectangle, in [minX, minY, maxX, MaxY] order.
* @returns {FeatureCollection<Polygon>} a set of polygons, one per input point.
* @param {BBox} [options.bbox=[-180, -85, 180, -85]] clipping rectangle, in [minX, minY, maxX, MaxY] order
* @returns {FeatureCollection<Polygon>} a set of polygons, one per input point
* @example
* var options = {
* const options = {
* bbox: [-70, 40, -60, 60]
* };
* var points = turf.randomPoint(100, options);
* var voronoiPolygons = turf.voronoi(points, options);
* const points = turf.randomPoint(100, options);
* const voronoiPolygons = turf.voronoi(points, options);
*
* //addToMap
* var addToMap = [voronoiPolygons, points];
* const addToMap = [voronoiPolygons, points];
*/
function voronoi(points, options) {
function voronoi(
points: FeatureCollection<Point>,
options?: { bbox?: BBox }
): FeatureCollection<Polygon> {
// Optional params
options = options || {};
if (!isObject(options)) throw new Error("options is invalid");
var bbox = options.bbox || [-180, -85, 180, 85];
const bbox = options.bbox || [-180, -85, 180, 85];
// Input Validation
if (!points) throw new Error("points is required");
@ -49,13 +62,9 @@ function voronoi(points, options) {
// Main
return featureCollection(
d3voronoi
.voronoi()
.x(function (feature) {
return feature.geometry.coordinates[0];
})
.y(function (feature) {
return feature.geometry.coordinates[1];
})
.voronoi<Feature<Point>>()
.x((feature) => feature.geometry.coordinates[0])
.y((feature) => feature.geometry.coordinates[1])
.extent([
[bbox[0], bbox[1]],
[bbox[2], bbox[3]],

View File

@ -67,12 +67,16 @@
"tape": "^5.7.2",
"tsup": "^8.0.1",
"tsx": "^4.6.2",
"typescript": "^5.2.2",
"write-json-file": "^5.0.0"
},
"dependencies": {
"@turf/clone": "workspace:^",
"@turf/helpers": "workspace:^",
"@turf/invariant": "workspace:^",
"d3-voronoi": "1.1.2"
"@types/d3-voronoi": "^1.1.12",
"@types/geojson": "7946.0.8",
"d3-voronoi": "1.1.2",
"tslib": "^2.6.2"
}
}

View File

@ -5,6 +5,7 @@ import { fileURLToPath } from "url";
import { loadJsonFileSync } from "load-json-file";
import { writeJsonFileSync } from "write-json-file";
import { voronoi } from "./index.js";
import { FeatureCollection, Point } from "geojson";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@ -13,7 +14,7 @@ test("turf-voronoi", (t) => {
.sync(path.join(__dirname, "test", "in", "*.json"))
.forEach((filepath) => {
const { name } = path.parse(filepath);
const geojson = loadJsonFileSync(filepath);
const geojson = loadJsonFileSync(filepath) as FeatureCollection<Point>;
const results = voronoi(geojson, { bbox: geojson.bbox });
const out = filepath.replace(

73
pnpm-lock.yaml generated
View File

@ -6175,9 +6175,18 @@ importers:
'@turf/invariant':
specifier: workspace:^
version: link:../turf-invariant
'@types/d3-voronoi':
specifier: ^1.1.12
version: 1.1.12
'@types/geojson':
specifier: 7946.0.8
version: 7946.0.8
d3-voronoi:
specifier: 1.1.2
version: 1.1.2
tslib:
specifier: ^2.6.2
version: 2.6.2
devDependencies:
'@types/benchmark':
specifier: ^2.1.5
@ -6202,10 +6211,13 @@ importers:
version: 5.7.2
tsup:
specifier: ^8.0.1
version: 8.0.1(ts-node@9.1.1)(typescript@5.3.3)
version: 8.0.1(typescript@5.3.3)
tsx:
specifier: ^4.6.2
version: 4.6.2
typescript:
specifier: ^5.2.2
version: 5.3.3
write-json-file:
specifier: ^5.0.0
version: 5.0.0
@ -8935,6 +8947,10 @@ packages:
resolution: {integrity: sha512-3shTHRmSStvc+91qrFlQv2UmrOB0sZ6biDQo7YzY+9tV1mNLpdzuZal4D3hTYXYWig49K01lCvYDpnh+txToXw==}
dev: true
/@types/d3-voronoi@1.1.12:
resolution: {integrity: sha512-DauBl25PKZZ0WVJr42a6CNvI6efsdzofl9sajqZr2Gf5Gu733WkDdUGiPkUHXiUvYGzNNlFQde2wdZdfQPG+yw==}
dev: false
/@types/estree@1.0.5:
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
dev: true
@ -15268,6 +15284,22 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/postcss-load-config@4.0.2:
resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
engines: {node: '>= 14'}
peerDependencies:
postcss: '>=8.0.9'
ts-node: '>=9.0.0'
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
dependencies:
lilconfig: 3.0.0
yaml: 2.3.4
dev: true
/postcss-load-config@4.0.2(ts-node@9.1.1):
resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
engines: {node: '>= 14'}
@ -17117,6 +17149,45 @@ packages:
- ts-node
dev: true
/tsup@8.0.1(typescript@5.3.3):
resolution: {integrity: sha512-hvW7gUSG96j53ZTSlT4j/KL0q1Q2l6TqGBFc6/mu/L46IoNWqLLUzLRLP1R8Q7xrJTmkDxxDoojV5uCVs1sVOg==}
engines: {node: '>=18'}
hasBin: true
peerDependencies:
'@microsoft/api-extractor': ^7.36.0
'@swc/core': ^1
postcss: ^8.4.12
typescript: '>=4.5.0'
peerDependenciesMeta:
'@microsoft/api-extractor':
optional: true
'@swc/core':
optional: true
postcss:
optional: true
typescript:
optional: true
dependencies:
bundle-require: 4.0.2(esbuild@0.19.11)
cac: 6.7.14
chokidar: 3.5.3
debug: 4.3.4
esbuild: 0.19.11
execa: 5.1.1
globby: 11.1.0
joycon: 3.1.1
postcss-load-config: 4.0.2
resolve-from: 5.0.0
rollup: 4.9.0
source-map: 0.8.0-beta.0
sucrase: 3.34.0
tree-kill: 1.2.2
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
- ts-node
dev: true
/tsutils@3.21.0(typescript@3.9.10):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}