UNPKG

fvtt-types

Version:
204 lines (179 loc) 8.98 kB
import type { Brand, Identity, InexactPartial } from "#utils"; /** * An implementation of the Weiler Atherton algorithm for clipping polygons. * This currently only handles combinations that will not result in any holes. * Support may be added for holes in the future. * * This algorithm is faster than the Clipper library for this task because it relies on the unique properties of the * circle, ellipse, or convex simple clip object. * It is also more precise in that it uses the actual intersection points between the circle/ellipse and polygon, * instead of relying on the polygon approximation of the circle/ellipse to find the intersection points. * * For more explanation of the underlying algorithm, see: * {@link https://en.wikipedia.org/wiki/Weiler%E2%80%93Atherton_clipping_algorithm} * {@link https://www.geeksforgeeks.org/weiler-atherton-polygon-clipping-algorithm} * {@link https://h-educate.in/weiler-atherton-polygon-clipping-algorithm/} * * @throws If `!polygon.isPositive` * @remarks In Foundry usage the only thing that calls `new WeilerAthertonClipper` is the class's static methods */ declare class WeilerAthertonClipper { /** * Construct a WeilerAthertonClipper instance used to perform the calculation. * @param polygon - Polygon to clip * @param clipObject - Object used to clip the polygon * @param clipType - Type of clip to use (default: `0`) * @param clipOpts - Object passed to the {@linkcode WeilerAthertonClipper.ClipObject | clipObject} methods * {@linkcode WeilerAthertonClipper.ClipObject.toPolygon | toPolygon} and * {@linkcode WeilerAthertonClipper.ClipObject.pointsBetween | pointsBetween} (default: `{}`) */ constructor( polygon: PIXI.Polygon, clipObject: WeilerAthertonClipper.ClipObject, clipType?: WeilerAthertonClipper.CLIP_TYPES, clipOpts?: WeilerAthertonClipper.ClipOpts, ); /** * The supported clip types. * Values are equivalent to those in {@linkcode ClipperLib.ClipType}. */ static CLIP_TYPES: WeilerAthertonClipper.ClipTypes; /** * The supported intersection types. */ static INTERSECTION_TYPES: WeilerAthertonClipper.IntersectionTypes; polygon: PIXI.Polygon; clipObject: WeilerAthertonClipper.ClipObject; /** * Configuration settings */ config: WeilerAthertonClipper.Config; /** * Union a polygon and clipObject using the Weiler Atherton algorithm. * @param polygon - Polygon to clip * @param clipObject - Object to clip against the polygon * @param clipOpts - Object passed to the {@linkcode WeilerAthertonClipper.ClipObject | clipObject} methods * {@linkcode WeilerAthertonClipper.ClipObject.toPolygon | toPolygon} and * {@linkcode WeilerAthertonClipper.ClipObject.pointsBetween | pointsBetween} (default: `{}`) */ static union( polygon: PIXI.Polygon, clipObject: WeilerAthertonClipper.ClipObject, clipOpts?: WeilerAthertonClipper.ClipOpts, ): PIXI.Polygon[]; /** * Intersect a polygon and clipObject using the Weiler Atherton algorithm. * @param polygon - Polygon to clip * @param clipObject - Object to clip against the polygon * @param clipOpts - Object passed to the {@linkcode WeilerAthertonClipper.ClipObject | clipObject} methods * {@linkcode WeilerAthertonClipper.ClipObject.toPolygon | toPolygon} and * {@linkcode WeilerAthertonClipper.ClipObject.pointsBetween | pointsBetween} (default: `{}`) */ static intersect( polygon: PIXI.Polygon, clipObject: WeilerAthertonClipper.ClipObject, clipOpts?: WeilerAthertonClipper.ClipOpts, ): PIXI.Polygon[]; /** * Clip a given clipObject using the Weiler-Atherton algorithm. * * At the moment, this will return a single PIXI.Polygon in the array unless clipType is a union and the polygon * and clipObject do not overlap, in which case the [polygon, clipObject.toPolygon()] array will be returned. * If this algorithm is expanded in the future to handle holes, an array of polygons may be returned. * * @param polygon - Polygon to clip * @param clipObject - Object to clip against the polygon * @param options - Options which configure how the union or intersection is computed. Any additional properties * in `options` (besides `clipType` and `canMutate`) are captured by the rest operator (`...clipOpts`) and passed * to the {@linkcode WeilerAthertonClipper} constructor. * @returns Array of polygons and clipObjects */ static combine( polygon: PIXI.Polygon, clipObject: WeilerAthertonClipper.ClipObject, options: WeilerAthertonClipper.CombineOptions, ): PIXI.Polygon[]; /** * Test if one shape envelops the other. Assumes the shapes do not intersect. * 1. Polygon is contained within the clip object. Union: clip object; Intersect: polygon * 2. Clip object is contained with polygon. Union: polygon; Intersect: clip object * 3. Polygon and clip object are outside one another. Union: both; Intersect: null * @param polygon - Polygon to clip * @param clipObject - Object to clip against the polygon * @param clipType - One of {@linkcode WeilerAthertonClipper.ClipTypes | CLIP_TYPES} * @param clipOpts - Clip options which are forwarded to toPolygon methods * @returns Returns the polygon, the clipObject.toPolygon(), both, or neither. */ static testForEnvelopment( polygon: PIXI.Polygon, clipObject: WeilerAthertonClipper.ClipObject, clipType: WeilerAthertonClipper.CLIP_TYPES, clipOpts?: WeilerAthertonClipper.ClipOpts, ): PIXI.Polygon[]; #WeilerAthertonClipper: true; } declare namespace WeilerAthertonClipper { interface Any extends AnyWeilerAthertonClipper {} interface AnyConstructor extends Identity<typeof AnyWeilerAthertonClipper> {} type ClipObject = PIXI.Rectangle | PIXI.Circle; type CLIP_TYPES = Brand<number, "WeilerAthertonClipper.CLIP_TYPES">; interface ClipTypes { readonly INTERSECT: 0 & CLIP_TYPES; readonly UNION: 1 & CLIP_TYPES; } type INTERSECTION_TYPES = Brand<number, "WeilerAthertonClipper.INTERSECTION_TYPES">; interface IntersectionTypes { readonly OUT_IN: -1 & INTERSECTION_TYPES; readonly IN_OUT: 1 & INTERSECTION_TYPES; readonly TANGENT: 0 & INTERSECTION_TYPES; } /** Configuration settings */ interface Config { /** * One of {@linkcode WeilerAthertonClipper.ClipTypes | CLIP_TYPES} * @defaultValue {@linkcode WeilerAthertonClipper.CLIP_TYPES.INTERSECT} * @remarks Set to the value of the equivalent constructor parameter if provided, or the above default */ clipType: WeilerAthertonClipper.CLIP_TYPES; /** * Object passed to the Object passed to the {@linkcode WeilerAthertonClipper.ClipObject | clipObject} methods * {@linkcode WeilerAthertonClipper.ClipObject.toPolygon | toPolygon} and * {@linkcode WeilerAthertonClipper.ClipObject.pointsBetween | pointsBetween} * @defaultValue `{}` * @remarks Set to the value of the equivalent constructor parameter if provided, or the above default */ clipOpts: WeilerAthertonClipper.ClipOpts; } /** @internal */ type _CombineOptions = InexactPartial<{ /** * If the WeilerAtherton constructor could mutate or not the subject polygon points */ canMutate: boolean; }>; /** * @remarks See {@linkcode WeilerAthertonClipper.combine}'s `options` parameter description * @privateRemarks This interface does *not* contain: * - a `scalingFactor` property, despite one being passed in {@linkcode PIXI.Rectangle.intersectPolygon | PIXI.Rectangle#intersectPolygon} as of 13.1346 * - a `density` property, despite one being passed in {@linkcode PIXI.Circle.intersectPolygon | PIXI.Circle#intersectPolygon} as of 13.346 * as those are not used by {@linkcode WeilerAthertonClipper.combine} */ interface CombineOptions extends _CombineOptions, ClipOpts { /** * One of {@linkcode WeilerAthertonClipper.ClipTypes | CLIP_TYPES} * @privateRemarks This *could* have been optional, as it gets passed to `new WAC()`, where it has a default, but Foundry has a pair of `!==` checks in * {@linkcode WeilerAthertonClipper.combine} before that happens which make it required */ clipType: WeilerAthertonClipper.CLIP_TYPES; } /** * @remarks These are ultimately passed to {@linkcode PIXI.Rectangle.toPolygon | PIXI.Rectangle#toPolygon}, {@linkcode PIXI.Circle.toPolygon | PIXI.Circle#toPolygon}, * {@linkcode PIXI.Rectangle.pointsBetween | PIXI.Rectangle#pointsBetween}, or {@linkcode PIXI.Circle.pointsBetween | PIXI.Circle#pointsBetween}. Only the `Circle` * methods actually take options and those are only passed on to {@linkcode PIXI.Circle.pointsForArc | PIXI.Circle#pointsForArc}. */ type ClipOpts = PIXI.Circle.PointsForArcOptions; } export default WeilerAthertonClipper; declare abstract class AnyWeilerAthertonClipper extends WeilerAthertonClipper { constructor(...args: never); }