@math.gl/polygon 3.5.6 → 3.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cut-by-grid.d.ts +20 -0
- package/dist/cut-by-grid.d.ts.map +1 -0
- package/dist/cut-by-grid.js +216 -0
- package/dist/cut-by-mercator-bounds.d.ts +16 -0
- package/dist/cut-by-mercator-bounds.d.ts.map +1 -0
- package/dist/cut-by-mercator-bounds.js +145 -0
- package/dist/{esm/earcut.d.ts → earcut.d.ts} +4 -2
- package/dist/earcut.d.ts.map +1 -0
- package/dist/earcut.js +611 -0
- package/dist/es5/cut-by-grid.js +70 -79
- package/dist/es5/cut-by-grid.js.map +1 -1
- package/dist/es5/cut-by-mercator-bounds.js +55 -87
- package/dist/es5/cut-by-mercator-bounds.js.map +1 -1
- package/dist/es5/earcut.js +97 -102
- package/dist/es5/earcut.js.map +1 -1
- package/dist/es5/index.js +14 -14
- package/dist/es5/index.js.map +1 -1
- package/dist/es5/lineclip.js +38 -41
- package/dist/es5/lineclip.js.map +1 -1
- package/dist/es5/polygon-utils.js +61 -69
- package/dist/es5/polygon-utils.js.map +1 -1
- package/dist/es5/polygon.js +35 -43
- package/dist/es5/polygon.js.map +1 -1
- package/dist/es5/utils.js +11 -12
- package/dist/es5/utils.js.map +1 -1
- package/dist/esm/cut-by-grid.js +4 -4
- package/dist/esm/cut-by-grid.js.map +1 -1
- package/dist/esm/cut-by-mercator-bounds.js +5 -5
- package/dist/esm/cut-by-mercator-bounds.js.map +1 -1
- package/dist/esm/earcut.js +9 -10
- package/dist/esm/earcut.js.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lineclip.js +5 -5
- package/dist/esm/lineclip.js.map +1 -1
- package/dist/esm/polygon-utils.js +7 -4
- package/dist/esm/polygon-utils.js.map +1 -1
- package/dist/esm/polygon.js +7 -0
- package/dist/esm/polygon.js.map +1 -1
- package/dist/esm/utils.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/lineclip.d.ts +31 -0
- package/dist/lineclip.d.ts.map +1 -0
- package/dist/lineclip.js +178 -0
- package/dist/{es5/polygon-utils.d.ts → polygon-utils.d.ts} +28 -64
- package/dist/polygon-utils.d.ts.map +1 -0
- package/dist/polygon-utils.js +140 -0
- package/dist/polygon.d.ts +40 -0
- package/dist/polygon.d.ts.map +1 -0
- package/dist/polygon.js +67 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +34 -0
- package/package.json +4 -3
- package/src/{cut-by-grid.js → cut-by-grid.ts} +32 -4
- package/src/{cut-by-mercator-bounds.js → cut-by-mercator-bounds.ts} +26 -7
- package/src/{earcut.js → earcut.ts} +25 -13
- package/src/{index.js → index.ts} +0 -0
- package/src/{lineclip.js → lineclip.ts} +48 -20
- package/src/polygon-utils.ts +225 -0
- package/src/{polygon.js → polygon.ts} +40 -9
- package/src/{utils.js → utils.ts} +0 -0
- package/dist/es5/cut-by-grid.d.ts +0 -24
- package/dist/es5/cut-by-mercator-bounds.d.ts +0 -23
- package/dist/es5/earcut.d.ts +0 -9
- package/dist/es5/lineclip.d.ts +0 -25
- package/dist/es5/polygon.d.ts +0 -36
- package/dist/esm/cut-by-grid.d.ts +0 -24
- package/dist/esm/cut-by-mercator-bounds.d.ts +0 -23
- package/dist/esm/lineclip.d.ts +0 -25
- package/dist/esm/polygon-utils.d.ts +0 -117
- package/dist/esm/polygon.d.ts +0 -36
- package/src/cut-by-grid.d.ts +0 -24
- package/src/cut-by-mercator-bounds.d.ts +0 -23
- package/src/earcut.d.ts +0 -9
- package/src/lineclip.d.ts +0 -25
- package/src/polygon-utils.d.ts +0 -117
- package/src/polygon-utils.js +0 -127
- package/src/polygon.d.ts +0 -36
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/* eslint-disable max-statements, max-depth, complexity, no-unused-expressions */
|
|
2
|
+
import { equals } from '@math.gl/core';
|
|
3
|
+
export var WINDING;
|
|
4
|
+
(function (WINDING) {
|
|
5
|
+
WINDING[WINDING["CLOCKWISE"] = 1] = "CLOCKWISE";
|
|
6
|
+
WINDING[WINDING["COUNTER_CLOCKWISE"] = -1] = "COUNTER_CLOCKWISE";
|
|
7
|
+
})(WINDING || (WINDING = {}));
|
|
8
|
+
/**
|
|
9
|
+
* Checks winding direction of the polygon and reverses the polygon in case of opposite winding direction.
|
|
10
|
+
* Note: points are modified in-place.
|
|
11
|
+
* @param points An array that represents points of the polygon.
|
|
12
|
+
* @param direction Requested winding direction. 1 is for clockwise, -1 for counterclockwise winding direction.
|
|
13
|
+
* @param options Parameters of the polygon.
|
|
14
|
+
* @return Returns true if the winding direction was changed.
|
|
15
|
+
*/
|
|
16
|
+
export function modifyPolygonWindingDirection(points, direction, options = {}) {
|
|
17
|
+
const windingDirection = getPolygonWindingDirection(points, options);
|
|
18
|
+
if (windingDirection !== direction) {
|
|
19
|
+
reversePolygon(points, options);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns winding direction of the polygon.
|
|
26
|
+
* @param points An array that represents points of the polygon.
|
|
27
|
+
* @param options Parameters of the polygon.
|
|
28
|
+
* @returns Winding direction of the polygon.
|
|
29
|
+
*/
|
|
30
|
+
export function getPolygonWindingDirection(points, options = {}) {
|
|
31
|
+
return Math.sign(getPolygonSignedArea(points, options));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns signed area of the polygon.
|
|
35
|
+
* @param points An array that represents points of the polygon.
|
|
36
|
+
* @param options Parameters of the polygon.
|
|
37
|
+
* @returns Signed area of the polygon.
|
|
38
|
+
* https://en.wikipedia.org/wiki/Shoelace_formula
|
|
39
|
+
*/
|
|
40
|
+
export function getPolygonSignedArea(points, options = {}) {
|
|
41
|
+
const { start = 0, end = points.length } = options;
|
|
42
|
+
const dim = options.size || 2;
|
|
43
|
+
let area = 0;
|
|
44
|
+
for (let i = start, j = end - dim; i < end; i += dim) {
|
|
45
|
+
area += (points[i] - points[j]) * (points[i + 1] + points[j + 1]);
|
|
46
|
+
j = i;
|
|
47
|
+
}
|
|
48
|
+
return area / 2;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Calls the visitor callback for each segment in the polygon.
|
|
52
|
+
* @param points An array that represents points of the polygon
|
|
53
|
+
* @param visitor A callback to call for each segment.
|
|
54
|
+
* @param options Parameters of the polygon.
|
|
55
|
+
*/
|
|
56
|
+
export function forEachSegmentInPolygon(points, visitor, options = {}) {
|
|
57
|
+
const { start = 0, end = points.length, size = 2, isClosed } = options;
|
|
58
|
+
const numPoints = (end - start) / size;
|
|
59
|
+
for (let i = 0; i < numPoints - 1; ++i) {
|
|
60
|
+
visitor(points[start + i * size], points[start + i * size + 1], points[start + (i + 1) * size], points[start + (i + 1) * size + 1], i, i + 1);
|
|
61
|
+
}
|
|
62
|
+
const endPointIndex = start + (numPoints - 1) * size;
|
|
63
|
+
const isClosedEx = isClosed ||
|
|
64
|
+
(equals(points[start], points[endPointIndex]) &&
|
|
65
|
+
equals(points[start + 1], points[endPointIndex + 1]));
|
|
66
|
+
if (!isClosedEx) {
|
|
67
|
+
visitor(points[endPointIndex], points[endPointIndex + 1], points[start], points[start + 1], numPoints - 1, 0);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function reversePolygon(points, options) {
|
|
71
|
+
const { start = 0, end = points.length, size = 2 } = options;
|
|
72
|
+
const numPoints = (end - start) / size;
|
|
73
|
+
const numSwaps = Math.floor(numPoints / 2);
|
|
74
|
+
for (let i = 0; i < numSwaps; ++i) {
|
|
75
|
+
const b1 = start + i * size;
|
|
76
|
+
const b2 = start + (numPoints - 1 - i) * size;
|
|
77
|
+
for (let j = 0; j < size; ++j) {
|
|
78
|
+
const tmp = points[b1 + j];
|
|
79
|
+
points[b1 + j] = points[b2 + j];
|
|
80
|
+
points[b2 + j] = tmp;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Checks winding direction of the polygon and reverses the polygon in case of opposite winding direction.
|
|
86
|
+
* Note: points are modified in-place.
|
|
87
|
+
* @param points Array of points that represent the polygon.
|
|
88
|
+
* @param direction Requested winding direction. 1 is for clockwise, -1 for counterclockwise winding direction.
|
|
89
|
+
* @param options Parameters of the polygon.
|
|
90
|
+
* @return Returns true if the winding direction was changed.
|
|
91
|
+
*/
|
|
92
|
+
export function modifyPolygonWindingDirectionPoints(points, direction, options = {}) {
|
|
93
|
+
const currentDirection = getPolygonWindingDirectionPoints(points, options);
|
|
94
|
+
if (currentDirection !== direction) {
|
|
95
|
+
points.reverse();
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns winding direction of the polygon.
|
|
102
|
+
* @param points Array of points that represent the polygon.
|
|
103
|
+
* @param options Parameters of the polygon.
|
|
104
|
+
* @returns Winding direction of the polygon.
|
|
105
|
+
*/
|
|
106
|
+
export function getPolygonWindingDirectionPoints(points, options = {}) {
|
|
107
|
+
return Math.sign(getPolygonSignedAreaPoints(points, options));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns signed area of the polygon.
|
|
111
|
+
* @param points Array of points that represent the polygon.
|
|
112
|
+
* @param options Parameters of the polygon.
|
|
113
|
+
* @returns Signed area of the polygon.
|
|
114
|
+
*/
|
|
115
|
+
export function getPolygonSignedAreaPoints(points, options = {}) {
|
|
116
|
+
// https://en.wikipedia.org/wiki/Shoelace_formula
|
|
117
|
+
const { start = 0, end = points.length } = options;
|
|
118
|
+
let area = 0;
|
|
119
|
+
for (let i = start, j = end - 1; i < end; ++i) {
|
|
120
|
+
area += (points[i][0] - points[j][0]) * (points[i][1] + points[j][1]);
|
|
121
|
+
j = i;
|
|
122
|
+
}
|
|
123
|
+
return area / 2;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Calls visitor callback for each segment in the polygon.
|
|
127
|
+
* @param points Array of points that represent the polygon.
|
|
128
|
+
* @param visitor A callback to call for each segment.
|
|
129
|
+
* @param options Parameters of the polygon.
|
|
130
|
+
*/
|
|
131
|
+
export function forEachSegmentInPolygonPoints(points, visitor, options = {}) {
|
|
132
|
+
const { start = 0, end = points.length, isClosed } = options;
|
|
133
|
+
for (let i = start; i < end - 1; ++i) {
|
|
134
|
+
visitor(points[i], points[i + 1], i, i + 1);
|
|
135
|
+
}
|
|
136
|
+
const isClosedEx = isClosed || equals(points[end - 1], points[0]);
|
|
137
|
+
if (!isClosedEx) {
|
|
138
|
+
visitor(points[end - 1], points[0], end - 1, 0);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { SegmentVisitorPoints } from './polygon-utils';
|
|
2
|
+
export declare type PolygonOptions = {
|
|
3
|
+
start?: number;
|
|
4
|
+
end?: number;
|
|
5
|
+
size?: number;
|
|
6
|
+
isClosed?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export default class Polygon {
|
|
9
|
+
points: any;
|
|
10
|
+
isFlatArray: boolean;
|
|
11
|
+
options: PolygonOptions;
|
|
12
|
+
constructor(points: any, options?: PolygonOptions);
|
|
13
|
+
/**
|
|
14
|
+
* Returns signed area of the polygon.
|
|
15
|
+
* @returns Signed area of the polygon.
|
|
16
|
+
*/
|
|
17
|
+
getSignedArea(): number;
|
|
18
|
+
/**
|
|
19
|
+
* Returns absolute area of the polygon.
|
|
20
|
+
* @returns Absolute area of the polygon.
|
|
21
|
+
*/
|
|
22
|
+
getArea(): number;
|
|
23
|
+
/**
|
|
24
|
+
* Returns winding direction of the polygon.
|
|
25
|
+
* @returns Winding direction of the polygon. 1 is for clockwise, -1 for counterclockwise winding direction.
|
|
26
|
+
*/
|
|
27
|
+
getWindingDirection(): number;
|
|
28
|
+
/**
|
|
29
|
+
* Calls the visitor callback for each segment in the polygon.
|
|
30
|
+
* @param visitor A callback to call for each segment.
|
|
31
|
+
*/
|
|
32
|
+
forEachSegment(visitor: SegmentVisitorPoints): void;
|
|
33
|
+
/**
|
|
34
|
+
* Checks winding direction of the polygon and reverses the polygon in case of opposite winding direction.
|
|
35
|
+
* @param direction Requested winding direction. 1 is for clockwise, -1 for counterclockwise winding direction.
|
|
36
|
+
* @return Returns true if the winding direction was changed.
|
|
37
|
+
*/
|
|
38
|
+
modifyWindingDirection(direction: number): boolean;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=polygon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon.d.ts","sourceRoot":"","sources":["../src/polygon.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAW1D,oBAAY,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,OAAO;IAC1B,MAAM,MAAC;IACP,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,cAAc,CAAC;gBAEZ,MAAM,KAAA,EAAmB,OAAO,GAAE,cAAmB;IAcjE;;;OAGG;IACH,aAAa,IAAI,MAAM;IAMvB;;;OAGG;IACH,OAAO,IAAI,MAAM;IAIjB;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IAI7B;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI;IAgBnD;;;;OAIG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAMnD"}
|
package/dist/polygon.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* eslint-disable no-undef, no-console */
|
|
2
|
+
import { isArray } from '@math.gl/core';
|
|
3
|
+
import { getPolygonSignedArea, forEachSegmentInPolygon, modifyPolygonWindingDirection, getPolygonSignedAreaPoints, forEachSegmentInPolygonPoints, modifyPolygonWindingDirectionPoints } from './polygon-utils';
|
|
4
|
+
export default class Polygon {
|
|
5
|
+
constructor(points /* : number[] */, options = {}) {
|
|
6
|
+
this.points = points;
|
|
7
|
+
this.isFlatArray = !isArray(points[0]);
|
|
8
|
+
this.options = {
|
|
9
|
+
start: options.start || 0,
|
|
10
|
+
end: options.end || points.length,
|
|
11
|
+
size: options.size || 2,
|
|
12
|
+
isClosed: options.isClosed
|
|
13
|
+
};
|
|
14
|
+
Object.freeze(this);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Returns signed area of the polygon.
|
|
18
|
+
* @returns Signed area of the polygon.
|
|
19
|
+
*/
|
|
20
|
+
getSignedArea() {
|
|
21
|
+
if (this.isFlatArray)
|
|
22
|
+
return getPolygonSignedArea(this.points, this.options);
|
|
23
|
+
return getPolygonSignedAreaPoints(this.points, this.options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns absolute area of the polygon.
|
|
27
|
+
* @returns Absolute area of the polygon.
|
|
28
|
+
*/
|
|
29
|
+
getArea() {
|
|
30
|
+
return Math.abs(this.getSignedArea());
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns winding direction of the polygon.
|
|
34
|
+
* @returns Winding direction of the polygon. 1 is for clockwise, -1 for counterclockwise winding direction.
|
|
35
|
+
*/
|
|
36
|
+
getWindingDirection() {
|
|
37
|
+
return Math.sign(this.getSignedArea());
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Calls the visitor callback for each segment in the polygon.
|
|
41
|
+
* @param visitor A callback to call for each segment.
|
|
42
|
+
*/
|
|
43
|
+
forEachSegment(visitor) {
|
|
44
|
+
if (this.isFlatArray) {
|
|
45
|
+
forEachSegmentInPolygon(this.points,
|
|
46
|
+
// eslint-disable-next-line max-params
|
|
47
|
+
(x1, y1, x2, y2, i1, i2) => {
|
|
48
|
+
// TODO @igorDykhta original visitor uses arrays for each point, but with flat arrays performance degrades if we allocate points for each segment
|
|
49
|
+
visitor([x1, y1], [x2, y2], i1, i2);
|
|
50
|
+
}, this.options);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
forEachSegmentInPolygonPoints(this.points, visitor, this.options);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Checks winding direction of the polygon and reverses the polygon in case of opposite winding direction.
|
|
58
|
+
* @param direction Requested winding direction. 1 is for clockwise, -1 for counterclockwise winding direction.
|
|
59
|
+
* @return Returns true if the winding direction was changed.
|
|
60
|
+
*/
|
|
61
|
+
modifyWindingDirection(direction) {
|
|
62
|
+
if (this.isFlatArray) {
|
|
63
|
+
return modifyPolygonWindingDirection(this.points, direction, this.options);
|
|
64
|
+
}
|
|
65
|
+
return modifyPolygonWindingDirectionPoints(this.points, direction, this.options);
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function push(target: any, source: any): boolean;
|
|
2
|
+
export declare function copy(target: any, source: any): void;
|
|
3
|
+
export declare function getPointAtIndex(positions: any, index: any, size: any, offset: any, out?: any[]): any[];
|
|
4
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,MAAM,KAAA,EAAE,MAAM,KAAA,WAsBlC;AAED,wBAAgB,IAAI,CAAC,MAAM,KAAA,EAAE,MAAM,KAAA,QAKlC;AAED,wBAAgB,eAAe,CAAC,SAAS,KAAA,EAAE,KAAK,KAAA,EAAE,IAAI,KAAA,EAAE,MAAM,KAAA,EAAE,GAAG,QAAK,SAMvE"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function push(target, source) {
|
|
2
|
+
const size = source.length;
|
|
3
|
+
const startIndex = target.length;
|
|
4
|
+
// dedupe, if source is the same point as the last vertex
|
|
5
|
+
if (startIndex > 0) {
|
|
6
|
+
let isDuplicate = true;
|
|
7
|
+
for (let i = 0; i < size; i++) {
|
|
8
|
+
if (target[startIndex - size + i] !== source[i]) {
|
|
9
|
+
isDuplicate = false;
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (isDuplicate) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (let i = 0; i < size; i++) {
|
|
18
|
+
target[startIndex + i] = source[i];
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
export function copy(target, source) {
|
|
23
|
+
const size = source.length;
|
|
24
|
+
for (let i = 0; i < size; i++) {
|
|
25
|
+
target[i] = source[i];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function getPointAtIndex(positions, index, size, offset, out = []) {
|
|
29
|
+
const startI = offset + index * size;
|
|
30
|
+
for (let i = 0; i < size; i++) {
|
|
31
|
+
out[i] = positions[startI + i];
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
-
"version": "3.
|
|
8
|
+
"version": "3.6.0-alpha.1",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"webgl",
|
|
11
11
|
"javascript",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "https://github.com/uber-web/math.gl.git"
|
|
19
19
|
},
|
|
20
|
+
"types": "dist/index.d.ts",
|
|
20
21
|
"main": "dist/es5/index.js",
|
|
21
22
|
"module": "dist/esm/index.js",
|
|
22
23
|
"files": [
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
"src"
|
|
25
26
|
],
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"@math.gl/core": "3.
|
|
28
|
+
"@math.gl/core": "3.6.0-alpha.1"
|
|
28
29
|
},
|
|
29
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "45386981340895bf201c2ebb76257c9bbffd8ff6"
|
|
30
31
|
}
|
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
import {bitCode, intersect} from './lineclip';
|
|
3
3
|
import {getPointAtIndex, copy, push} from './utils';
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export type Polygon = {
|
|
6
|
+
positions: Array<number>;
|
|
7
|
+
holeIndices?: Array<number>;
|
|
8
|
+
vertexTypes?: Array<number>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function cutPolylineByGrid(
|
|
12
|
+
positions: Array<number>,
|
|
13
|
+
options?: {
|
|
14
|
+
size?: number;
|
|
15
|
+
broken?: boolean;
|
|
16
|
+
gridResolution?: number;
|
|
17
|
+
gridOffset?: [number, number];
|
|
18
|
+
startIndex?: number;
|
|
19
|
+
endIndex?: number;
|
|
20
|
+
}
|
|
21
|
+
): Array<number> | Array<Array<number>> {
|
|
6
22
|
const {
|
|
7
23
|
size = 2,
|
|
8
24
|
broken = false,
|
|
@@ -10,7 +26,7 @@ export function cutPolylineByGrid(positions, options = {}) {
|
|
|
10
26
|
gridOffset = [0, 0],
|
|
11
27
|
startIndex = 0,
|
|
12
28
|
endIndex = positions.length
|
|
13
|
-
} = options;
|
|
29
|
+
} = options || {};
|
|
14
30
|
const numPoints = (endIndex - startIndex) / size;
|
|
15
31
|
let part = [];
|
|
16
32
|
const result = [part];
|
|
@@ -64,12 +80,21 @@ function concatInPlace(arr1, arr2) {
|
|
|
64
80
|
return arr1;
|
|
65
81
|
}
|
|
66
82
|
|
|
67
|
-
export function cutPolygonByGrid(
|
|
83
|
+
export function cutPolygonByGrid(
|
|
84
|
+
positions: Array<number>,
|
|
85
|
+
holeIndices: Array<number> | null = null,
|
|
86
|
+
options?: {
|
|
87
|
+
size?: number;
|
|
88
|
+
gridResolution?: number;
|
|
89
|
+
gridOffset?: [number, number];
|
|
90
|
+
edgeTypes?: boolean;
|
|
91
|
+
}
|
|
92
|
+
): Array<Polygon> {
|
|
68
93
|
if (!positions.length) {
|
|
69
94
|
// input is empty
|
|
70
95
|
return [];
|
|
71
96
|
}
|
|
72
|
-
const {size = 2, gridResolution = 10, gridOffset = [0, 0], edgeTypes = false} = options;
|
|
97
|
+
const {size = 2, gridResolution = 10, gridOffset = [0, 0], edgeTypes = false} = options || {};
|
|
73
98
|
const result = [];
|
|
74
99
|
const queue = [
|
|
75
100
|
{
|
|
@@ -88,6 +113,7 @@ export function cutPolygonByGrid(positions, holeIndices, options = {}) {
|
|
|
88
113
|
// Get the bounding box of the outer polygon
|
|
89
114
|
getBoundingBox(pos, size, holes[0] || pos.length, bbox);
|
|
90
115
|
cell = getGridCell(bbox[0], gridResolution, gridOffset, cell);
|
|
116
|
+
// @ts-expect-error
|
|
91
117
|
const code = bitCode(bbox[1], cell);
|
|
92
118
|
|
|
93
119
|
if (code) {
|
|
@@ -120,9 +146,11 @@ export function cutPolygonByGrid(positions, holeIndices, options = {}) {
|
|
|
120
146
|
// Polygon fits in a single cell, no more processing required
|
|
121
147
|
const polygon = {positions: pos};
|
|
122
148
|
if (edgeTypes) {
|
|
149
|
+
// @ts-expect-error
|
|
123
150
|
polygon.edgeTypes = types;
|
|
124
151
|
}
|
|
125
152
|
if (holes.length) {
|
|
153
|
+
// @ts-expect-error
|
|
126
154
|
polygon.holeIndices = holes;
|
|
127
155
|
}
|
|
128
156
|
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import {cutPolylineByGrid, cutPolygonByGrid} from './cut-by-grid';
|
|
2
2
|
import {getPointAtIndex, push} from './utils';
|
|
3
|
+
import type {Polygon} from './cut-by-grid';
|
|
3
4
|
|
|
4
5
|
// https://en.wikipedia.org/wiki/Web_Mercator_projection
|
|
5
6
|
const DEFAULT_MAX_LATITUDE = 85.051129;
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
export function cutPolylineByMercatorBounds(
|
|
9
|
-
|
|
8
|
+
/** https://user-images.githubusercontent.com/2059298/78465769-938b7a00-76ae-11ea-9b95-1f4c26425ab9.png */
|
|
9
|
+
export function cutPolylineByMercatorBounds(
|
|
10
|
+
positions: Array<number>,
|
|
11
|
+
options?: {
|
|
12
|
+
size?: number;
|
|
13
|
+
startIndex?: number;
|
|
14
|
+
endIndex?: number;
|
|
15
|
+
normalize?: boolean;
|
|
16
|
+
}
|
|
17
|
+
): Array<number> {
|
|
18
|
+
const {size = 2, startIndex = 0, endIndex = positions.length, normalize = true} = options || {};
|
|
10
19
|
|
|
11
20
|
// Remap longitudes so that each segment takes the shorter path
|
|
12
21
|
const newPositions = positions.slice(startIndex, endIndex);
|
|
@@ -26,12 +35,22 @@ export function cutPolylineByMercatorBounds(positions, options = {}) {
|
|
|
26
35
|
shiftLongitudesIntoRange(part, size);
|
|
27
36
|
}
|
|
28
37
|
}
|
|
38
|
+
// @ts-expect-error
|
|
29
39
|
return parts;
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
export function cutPolygonByMercatorBounds(
|
|
34
|
-
|
|
42
|
+
/** https://user-images.githubusercontent.com/2059298/78465770-94241080-76ae-11ea-809a-6a8534dac1d9.png */
|
|
43
|
+
export function cutPolygonByMercatorBounds(
|
|
44
|
+
positions: Array<number>,
|
|
45
|
+
holeIndices: Array<number> | null = null,
|
|
46
|
+
options?: {
|
|
47
|
+
size?: number;
|
|
48
|
+
normalize?: boolean;
|
|
49
|
+
maxLatitude?: number;
|
|
50
|
+
edgeTypes?: boolean;
|
|
51
|
+
}
|
|
52
|
+
): Array<Polygon> {
|
|
53
|
+
const {size = 2, normalize = true, edgeTypes = false} = options || {};
|
|
35
54
|
holeIndices = holeIndices || [];
|
|
36
55
|
const newPositions = [];
|
|
37
56
|
const newHoleIndices = [];
|
|
@@ -59,7 +78,7 @@ export function cutPolygonByMercatorBounds(positions, holeIndices, options = {})
|
|
|
59
78
|
wrapLongitudesForShortestPath(newPositions, size, targetStartIndex, targetIndex);
|
|
60
79
|
|
|
61
80
|
// Handle the case when the ring contains a pole
|
|
62
|
-
insertPoleVertices(newPositions, size, targetStartIndex, targetIndex, options
|
|
81
|
+
insertPoleVertices(newPositions, size, targetStartIndex, targetIndex, options?.maxLatitude);
|
|
63
82
|
|
|
64
83
|
srcStartIndex = srcEndIndex;
|
|
65
84
|
newHoleIndices[ringIndex] = targetIndex;
|
|
@@ -26,12 +26,24 @@
|
|
|
26
26
|
|
|
27
27
|
import {getPolygonSignedArea} from './polygon-utils';
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Computes a triangulation of a polygon
|
|
31
|
+
* @param positions a flat array of the vertex positions that define the polygon.
|
|
32
|
+
* @param holeIndices an array of hole indices if any (e.g. [5, 8] for a 12-vertex input would mean one hole with vertices 5–7 and another with 8–11).
|
|
33
|
+
* @param dim the number of elements in each vertex. Size `2` will interpret `positions` as `[x0, y0, x1, y1, ...]` and size `3` will interpret `positions` as `[x0, y0, z0, x1, y1, z1, ...]`. Default `2`.
|
|
34
|
+
* @param areas areas of outer polygon and holes as computed by `getPolygonSignedArea()`. Can be optionally supplied to speed up triangulation
|
|
35
|
+
* @returns array of indices into the `positions` array that describes the triangulation of the polygon
|
|
36
|
+
* Adapted from https://github.com/mapbox/earcut
|
|
37
|
+
*/
|
|
38
|
+
export function earcut(
|
|
39
|
+
positions: number[],
|
|
40
|
+
holeIndices?: number[],
|
|
41
|
+
dim: number = 2,
|
|
42
|
+
areas?: number[]
|
|
43
|
+
): number[] {
|
|
32
44
|
const hasHoles = holeIndices && holeIndices.length;
|
|
33
|
-
const outerLen = hasHoles ? holeIndices[0] * dim :
|
|
34
|
-
let outerNode = linkedList(
|
|
45
|
+
const outerLen = hasHoles ? holeIndices[0] * dim : positions.length;
|
|
46
|
+
let outerNode = linkedList(positions, 0, outerLen, dim, true, areas && areas[0]);
|
|
35
47
|
const triangles = [];
|
|
36
48
|
|
|
37
49
|
if (!outerNode || outerNode.next === outerNode.prev) return triangles;
|
|
@@ -44,16 +56,16 @@ export function earcut(data, holeIndices, dim, areas) {
|
|
|
44
56
|
let x;
|
|
45
57
|
let y;
|
|
46
58
|
|
|
47
|
-
if (hasHoles) outerNode = eliminateHoles(
|
|
59
|
+
if (hasHoles) outerNode = eliminateHoles(positions, holeIndices, outerNode, dim, areas);
|
|
48
60
|
|
|
49
61
|
// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
|
|
50
|
-
if (
|
|
51
|
-
minX = maxX =
|
|
52
|
-
minY = maxY =
|
|
62
|
+
if (positions.length > 80 * dim) {
|
|
63
|
+
minX = maxX = positions[0];
|
|
64
|
+
minY = maxY = positions[1];
|
|
53
65
|
|
|
54
66
|
for (let i = dim; i < outerLen; i += dim) {
|
|
55
|
-
x =
|
|
56
|
-
y =
|
|
67
|
+
x = positions[i];
|
|
68
|
+
y = positions[i + 1];
|
|
57
69
|
if (x < minX) minX = x;
|
|
58
70
|
if (y < minY) minY = y;
|
|
59
71
|
if (x > maxX) maxX = x;
|
|
@@ -96,7 +108,7 @@ function linkedList(data, start, end, dim, clockwise, area) {
|
|
|
96
108
|
}
|
|
97
109
|
|
|
98
110
|
// eliminate colinear or duplicate points
|
|
99
|
-
function filterPoints(start, end) {
|
|
111
|
+
function filterPoints(start, end?) {
|
|
100
112
|
if (!start) return start;
|
|
101
113
|
if (!end) end = start;
|
|
102
114
|
|
|
@@ -119,7 +131,7 @@ function filterPoints(start, end) {
|
|
|
119
131
|
}
|
|
120
132
|
|
|
121
133
|
// main ear slicing loop which triangulates a polygon (given as a linked list)
|
|
122
|
-
function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
|
|
134
|
+
function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass?) {
|
|
123
135
|
if (!ear) return;
|
|
124
136
|
|
|
125
137
|
// interlink polygon nodes in z-order
|
|
File without changes
|
|
@@ -20,14 +20,26 @@
|
|
|
20
20
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
/* eslint-disable max-statements, max-depth */
|
|
23
|
+
/* eslint-disable max-statements, max-depth, complexity */
|
|
24
24
|
|
|
25
25
|
import {push, copy, getPointAtIndex} from './utils';
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
type BoundingBox = [number, number, number, number];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Cohen-Sutherland line clipping algorithm, adapted to efficiently
|
|
31
|
+
* handle polylines rather than just segments
|
|
32
|
+
*/
|
|
33
|
+
export function clipPolyline(
|
|
34
|
+
positions: number[],
|
|
35
|
+
bbox: BoundingBox,
|
|
36
|
+
options?: {
|
|
37
|
+
size?: number;
|
|
38
|
+
startIndex?: number;
|
|
39
|
+
endIndex?: number;
|
|
40
|
+
}
|
|
41
|
+
): number[][] {
|
|
42
|
+
const {size = 2, startIndex = 0, endIndex = positions.length} = options || {};
|
|
31
43
|
const numPoints = (endIndex - startIndex) / size;
|
|
32
44
|
const result = [];
|
|
33
45
|
let part = [];
|
|
@@ -86,11 +98,21 @@ export function clipPolyline(positions, bbox, options = {}) {
|
|
|
86
98
|
return result;
|
|
87
99
|
}
|
|
88
100
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Sutherland-Hodgeman polygon clipping algorithm
|
|
103
|
+
* polygon must be closed (first vertex == last vertex)
|
|
104
|
+
*/
|
|
105
|
+
export function clipPolygon(
|
|
106
|
+
positions: number[],
|
|
107
|
+
bbox: BoundingBox,
|
|
108
|
+
options?: {
|
|
109
|
+
size?: number;
|
|
110
|
+
startIndex?: number;
|
|
111
|
+
endIndex?: number;
|
|
112
|
+
}
|
|
113
|
+
): number[] {
|
|
114
|
+
const {size = 2, endIndex = positions.length} = options || {};
|
|
115
|
+
let {startIndex = 0} = options || {};
|
|
94
116
|
let numPoints = (endIndex - startIndex) / size;
|
|
95
117
|
let result;
|
|
96
118
|
let p;
|
|
@@ -128,9 +150,15 @@ export function clipPolygon(positions, bbox, options = {}) {
|
|
|
128
150
|
return result;
|
|
129
151
|
}
|
|
130
152
|
|
|
131
|
-
|
|
153
|
+
/** intersect a segment against one of the 4 lines that make up the bbox */
|
|
132
154
|
|
|
133
|
-
export function intersect(
|
|
155
|
+
export function intersect(
|
|
156
|
+
a: number[],
|
|
157
|
+
b: number[],
|
|
158
|
+
edge: number,
|
|
159
|
+
bbox: BoundingBox,
|
|
160
|
+
out: number[] = []
|
|
161
|
+
): number[] {
|
|
134
162
|
let t;
|
|
135
163
|
// Forces out[snapI] to be on the bbox edge
|
|
136
164
|
// Interpolation introduces precision issue which may cause lineclip to be
|
|
@@ -161,14 +189,14 @@ export function intersect(a, b, edge, bbox, out = []) {
|
|
|
161
189
|
return out;
|
|
162
190
|
}
|
|
163
191
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
export function bitCode(p, bbox) {
|
|
192
|
+
/**
|
|
193
|
+
* bit code reflects the point position relative to the bbox:
|
|
194
|
+
* left mid right
|
|
195
|
+
* top 1001 1000 1010
|
|
196
|
+
* mid 0001 0000 0010
|
|
197
|
+
* bottom 0101 0100 0110
|
|
198
|
+
*/
|
|
199
|
+
export function bitCode(p: number[], bbox: BoundingBox): number {
|
|
172
200
|
let code = 0;
|
|
173
201
|
|
|
174
202
|
if (p[0] < bbox[0]) code |= 1;
|