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

earcut worker #20

Merged
merged 3 commits into from
Dec 1, 2023
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
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@geoarrow/geoarrow-js",
"version": "0.2.0",
"version": "0.3.0-beta.1",
"description": "TypeScript implementation of GeoArrow",
"source": "src/index.ts",
"umd:main": "dist/geoarrow.umd.js",
Expand All @@ -26,7 +26,9 @@
"license": "MIT",
"type": "module",
"scripts": {
"build": "rollup -c rollup.config.js",
"build:rollup": "rollup -c rollup.config.js",
"build:workers": "node ./worker-build.mjs",
"build": "yarn build:rollup && yarn build:workers",
"clean": "rimraf dist",
"docs:build": "typedoc",
"docs:publish": "gh-pages -d docs_build",
Expand All @@ -50,6 +52,7 @@
"@types/node": "^20.9.3",
"@types/proj4": "^2",
"apache-arrow": "^14",
"esbuild": "^0.19.8",
"gh-pages": "^6.1.0",
"prettier": "^3.1.0",
"rimraf": "^5.0.5",
Expand All @@ -66,6 +69,7 @@
},
"dependencies": {
"@math.gl/polygon": "^4.0.0",
"proj4": "^2.9.2"
"proj4": "^2.9.2",
"threads": "^1.7.0"
}
}
16 changes: 9 additions & 7 deletions src/child.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,37 @@
* Strongly typed accessors for children, since arrow.Data.children[] is untyped
*/

import * as arrow from "apache-arrow";
import { Data } from "apache-arrow/data";
import { Vector } from "apache-arrow/vector";
import { Float } from "apache-arrow/type";
import {
LineStringData,
MultiLineStringData,
MultiPointData,
MultiPolygonData,
PointData,
PolygonData,
} from "./data.js";
} from "./data";
import {
LineStringVector,
MultiLineStringVector,
MultiPointVector,
MultiPolygonVector,
PointVector,
PolygonVector,
} from "./vector.js";
} from "./vector";

export function getPointChild(input: PointData): arrow.Data<arrow.Float>;
export function getPointChild(input: PointVector): arrow.Vector<arrow.Float>;
export function getPointChild(input: PointData): Data<Float>;
export function getPointChild(input: PointVector): Vector<Float>;

export function getPointChild(
input: PointData | PointVector,
): arrow.Data<arrow.Float> | arrow.Vector<arrow.Float> {
): Data<Float> | Vector<Float> {
if ("data" in input) {
return input.getChildAt(0)!;
}

return input.children[0] as arrow.Data<arrow.Float>;
return input.children[0] as Data<Float>;
}

export function getLineStringChild(input: LineStringData): PointData;
Expand Down
30 changes: 14 additions & 16 deletions src/data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as arrow from "apache-arrow";
import { Data } from "apache-arrow/data";
import {
Point,
LineString,
Expand All @@ -12,14 +12,14 @@ import {
isMultiPoint,
isMultiLineString,
isMultiPolygon,
} from "./type.js";
} from "./type";

export type PointData = arrow.Data<Point>;
export type LineStringData = arrow.Data<LineString>;
export type PolygonData = arrow.Data<Polygon>;
export type MultiPointData = arrow.Data<MultiPoint>;
export type MultiLineStringData = arrow.Data<MultiLineString>;
export type MultiPolygonData = arrow.Data<MultiPolygon>;
export type PointData = Data<Point>;
export type LineStringData = Data<LineString>;
export type PolygonData = Data<Polygon>;
export type MultiPointData = Data<MultiPoint>;
export type MultiLineStringData = Data<MultiLineString>;
export type MultiPolygonData = Data<MultiPolygon>;
export type GeoArrowData =
| PointData
| LineStringData
Expand All @@ -28,28 +28,26 @@ export type GeoArrowData =
| MultiLineStringData
| MultiPolygonData;

export function isPointData(data: arrow.Data): data is PointData {
export function isPointData(data: Data): data is PointData {
return isPoint(data.type);
}

export function isLineStringData(data: arrow.Data): data is LineStringData {
export function isLineStringData(data: Data): data is LineStringData {
return isLineString(data.type);
}

export function isPolygonData(data: arrow.Data): data is PolygonData {
export function isPolygonData(data: Data): data is PolygonData {
return isPolygon(data.type);
}

export function isMultiPointData(data: arrow.Data): data is MultiPointData {
export function isMultiPointData(data: Data): data is MultiPointData {
return isMultiPoint(data.type);
}

export function isMultiLineStringData(
data: arrow.Data,
): data is MultiLineStringData {
export function isMultiLineStringData(data: Data): data is MultiLineStringData {
return isMultiLineString(data.type);
}

export function isMultiPolygonData(data: arrow.Data): data is MultiPolygonData {
export function isMultiPolygonData(data: Data): data is MultiPolygonData {
return isMultiPolygon(data.type);
}
58 changes: 31 additions & 27 deletions src/type.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
import * as arrow from "apache-arrow";
import {
Struct,
Float,
List,
FixedSizeList,
DataType,
} from "apache-arrow/type";

// Note: this apparently has to be arrow.Float and not arrow.Float64 to ensure
// that recreating a data instance with arrow.makeData type checks using the
// input's data type.
export type InterleavedCoord = arrow.FixedSizeList<arrow.Float>;
export type SeparatedCoord = arrow.Struct<{
x: arrow.Float;
y: arrow.Float;
export type InterleavedCoord = FixedSizeList<Float>;
export type SeparatedCoord = Struct<{
x: Float;
y: Float;
}>;
// TODO: support separated coords
export type Coord = InterleavedCoord; // | SeparatedCoord;
export type Point = Coord;
export type LineString = arrow.List<Coord>;
export type Polygon = arrow.List<arrow.List<Coord>>;
export type MultiPoint = arrow.List<Coord>;
export type MultiLineString = arrow.List<arrow.List<Coord>>;
export type MultiPolygon = arrow.List<arrow.List<arrow.List<Coord>>>;
export type LineString = List<Coord>;
export type Polygon = List<List<Coord>>;
export type MultiPoint = List<Coord>;
export type MultiLineString = List<List<Coord>>;
export type MultiPolygon = List<List<List<Coord>>>;
export type GeoArrowType =
| Point
| LineString
Expand All @@ -25,22 +31,22 @@ export type GeoArrowType =
| MultiPolygon;

/** Check that the given type is a Point data type */
export function isPoint(type: arrow.DataType): type is Point {
if (arrow.DataType.isFixedSizeList(type)) {
export function isPoint(type: DataType): type is Point {
if (DataType.isFixedSizeList(type)) {
// Check list size
if (![2, 3, 4].includes(type.listSize)) {
return false;
}

// Check child of FixedSizeList is floating type
if (!arrow.DataType.isFloat(type.children[0])) {
if (!DataType.isFloat(type.children[0])) {
return false;
}

return true;
}

if (arrow.DataType.isStruct(type)) {
if (DataType.isStruct(type)) {
// Check number of children
if (![2, 3, 4].includes(type.children.length)) {
return false;
Expand All @@ -53,7 +59,7 @@ export function isPoint(type: arrow.DataType): type is Point {
return false;
}

if (!type.children.every((field) => arrow.DataType.isFloat(field))) {
if (!type.children.every((field) => DataType.isFloat(field))) {
return false;
}

Expand All @@ -63,9 +69,9 @@ export function isPoint(type: arrow.DataType): type is Point {
return false;
}

export function isLineString(type: arrow.DataType): type is LineString {
export function isLineString(type: DataType): type is LineString {
// Check the outer type is a List
if (!arrow.DataType.isList(type)) {
if (!DataType.isList(type)) {
return false;
}

Expand All @@ -77,9 +83,9 @@ export function isLineString(type: arrow.DataType): type is LineString {
return true;
}

export function isPolygon(type: arrow.DataType): type is Polygon {
export function isPolygon(type: DataType): type is Polygon {
// Check the outer vector is a List
if (!arrow.DataType.isList(type)) {
if (!DataType.isList(type)) {
return false;
}

Expand All @@ -91,9 +97,9 @@ export function isPolygon(type: arrow.DataType): type is Polygon {
return true;
}

export function isMultiPoint(type: arrow.DataType): type is MultiPoint {
export function isMultiPoint(type: DataType): type is MultiPoint {
// Check the outer vector is a List
if (!arrow.DataType.isList(type)) {
if (!DataType.isList(type)) {
return false;
}

Expand All @@ -105,11 +111,9 @@ export function isMultiPoint(type: arrow.DataType): type is MultiPoint {
return true;
}

export function isMultiLineString(
type: arrow.DataType,
): type is MultiLineString {
export function isMultiLineString(type: DataType): type is MultiLineString {
// Check the outer vector is a List
if (!arrow.DataType.isList(type)) {
if (!DataType.isList(type)) {
return false;
}

Expand All @@ -121,9 +125,9 @@ export function isMultiLineString(
return true;
}

export function isMultiPolygon(type: arrow.DataType): type is MultiPolygon {
export function isMultiPolygon(type: DataType): type is MultiPolygon {
// Check the outer vector is a List
if (!arrow.DataType.isList(type)) {
if (!DataType.isList(type)) {
return false;
}

Expand Down
32 changes: 14 additions & 18 deletions src/vector.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as arrow from "apache-arrow";
import { Vector } from "apache-arrow/vector";
import {
Point,
LineString,
Expand All @@ -12,14 +12,14 @@ import {
isMultiPoint,
isMultiLineString,
isMultiPolygon,
} from "./type.js";
} from "./type";

export type PointVector = arrow.Vector<Point>;
export type LineStringVector = arrow.Vector<LineString>;
export type PolygonVector = arrow.Vector<Polygon>;
export type MultiPointVector = arrow.Vector<MultiPoint>;
export type MultiLineStringVector = arrow.Vector<MultiLineString>;
export type MultiPolygonVector = arrow.Vector<MultiPolygon>;
export type PointVector = Vector<Point>;
export type LineStringVector = Vector<LineString>;
export type PolygonVector = Vector<Polygon>;
export type MultiPointVector = Vector<MultiPoint>;
export type MultiLineStringVector = Vector<MultiLineString>;
export type MultiPolygonVector = Vector<MultiPolygon>;
export type GeoArrowVector =
| PointVector
| LineStringVector
Expand All @@ -28,34 +28,30 @@ export type GeoArrowVector =
| MultiLineStringVector
| MultiPolygonVector;

export function isPointVector(vector: arrow.Vector): vector is PointVector {
export function isPointVector(vector: Vector): vector is PointVector {
return isPoint(vector.type);
}

export function isLineStringVector(
vector: arrow.Vector,
): vector is LineStringVector {
export function isLineStringVector(vector: Vector): vector is LineStringVector {
return isLineString(vector.type);
}

export function isPolygonVector(vector: arrow.Vector): vector is PolygonVector {
export function isPolygonVector(vector: Vector): vector is PolygonVector {
return isPolygon(vector.type);
}

export function isMultiPointVector(
vector: arrow.Vector,
): vector is MultiPointVector {
export function isMultiPointVector(vector: Vector): vector is MultiPointVector {
return isMultiPoint(vector.type);
}

export function isMultiLineStringVector(
vector: arrow.Vector,
vector: Vector,
): vector is MultiLineStringVector {
return isMultiLineString(vector.type);
}

export function isMultiPolygonVector(
vector: arrow.Vector,
vector: Vector,
): vector is MultiPolygonVector {
return isMultiPolygon(vector.type);
}
20 changes: 20 additions & 0 deletions src/worker-bundle/earcut.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { TransferDescriptor } from "threads";
import { expose, Transfer } from "threads/worker";
import { PolygonData } from "../data";
import { earcut } from "../algorithm/earcut";

function earcutWorker(polygonData: PolygonData): TransferDescriptor {
// NOTE!! Here we don't reconstruct a full arrow.Data instance to save on
// bundle size! We rely on the fact that nothing in the `earcut` function uses
// any class methods, which is not an ideal/easy assumption. Ideally we'll
// have functions in the future to validate geometry `Data` instances and
// construct Data and Vector instances without bringing in all of Arrow JS.

// const rehydratedData = rehydratePolygonData(polygonData);
const earcutTriangles = earcut(polygonData);
return Transfer(earcutTriangles, [earcutTriangles.buffer]);
}

export type EarcutOnWorker = typeof earcutWorker;

expose(earcutWorker);
Loading