@math.gl/polygon
Version:
Polygon/polyline processing utilities
103 lines (89 loc) • 3.11 kB
text/typescript
// math.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
/* eslint-disable no-undef, no-console */
import {isArray} from '@math.gl/core';
import type {SegmentVisitorPoints} from './polygon-utils';
import type {NumericArray} from '@math.gl/core';
import {
getPolygonSignedArea,
forEachSegmentInPolygon,
modifyPolygonWindingDirection,
getPolygonSignedAreaPoints,
forEachSegmentInPolygonPoints,
modifyPolygonWindingDirectionPoints
} from './polygon-utils';
export type PolygonOptions = {
start?: number;
end?: number;
size?: number;
isClosed?: boolean;
};
export class Polygon {
points: NumericArray | number[][];
isFlatArray: boolean;
options: PolygonOptions;
constructor(points: NumericArray | number[][], options: PolygonOptions = {}) {
this.points = points;
this.isFlatArray = !isArray(points[0]);
this.options = {
start: options.start || 0,
end: options.end || points.length,
size: options.size || 2,
isClosed: options.isClosed
};
Object.freeze(this);
}
/**
* Returns signed area of the polygon.
* @returns Signed area of the polygon.
*/
getSignedArea(): number {
if (this.isFlatArray) return getPolygonSignedArea(this.points as NumericArray, this.options);
return getPolygonSignedAreaPoints(this.points as number[][], this.options);
}
/**
* Returns absolute area of the polygon.
* @returns Absolute area of the polygon.
*/
getArea(): number {
return Math.abs(this.getSignedArea());
}
/**
* Returns winding direction of the polygon.
* @returns Winding direction of the polygon. 1 is for clockwise, -1 for counterclockwise winding direction.
*/
getWindingDirection(): number {
return Math.sign(this.getSignedArea());
}
/**
* Calls the visitor callback for each segment in the polygon.
* @param visitor A callback to call for each segment.
*/
forEachSegment(visitor: SegmentVisitorPoints): void {
if (this.isFlatArray) {
forEachSegmentInPolygon(
this.points as NumericArray,
// eslint-disable-next-line max-params
(x1, y1, x2, y2, i1, i2) => {
// TODO @igorDykhta original visitor uses arrays for each point, but with flat arrays performance degrades if we allocate points for each segment
visitor([x1, y1], [x2, y2], i1, i2);
},
this.options
);
} else {
forEachSegmentInPolygonPoints(this.points as number[][], visitor, this.options);
}
}
/**
* Checks winding direction of the polygon and reverses the polygon in case of opposite winding direction.
* @param direction Requested winding direction. 1 is for clockwise, -1 for counterclockwise winding direction.
* @return Returns true if the winding direction was changed.
*/
modifyWindingDirection(direction: number): boolean {
if (this.isFlatArray) {
return modifyPolygonWindingDirection(this.points as NumericArray, direction, this.options);
}
return modifyPolygonWindingDirectionPoints(this.points as number[][], direction, this.options);
}
}