/**
 * Calculate the inset of any non-self-overlapping polygon.
 *
 * The polygon may be
 *  - convex or non-convex
 *  - self-intersecting
 *
 * The algorithms will
 *  - first construct a general offset polygon which may be corrupt due to ouf-of-bounds or in illegal-area problems.
 *  - then dissect the possibly self-intersecting inset polygon into separate simple polygons.
 *  - then detect for each if it's out of bounds or in some illegal area.
 *  - keeping only the valid ones.
 *
 * @required sutherlandHodgman
 * @required splitPolygonToNonIntersecting
 *
 * @author   Ikaros Kappler
 * @date     2024-11-04 Ported the script to a class.
 * @modified 2024-12-02 Ported to Typescript.
 */
import { Line } from "../../Line";
import { Polygon } from "../../Polygon";
import { Vertex } from "../../Vertex";
export interface IPolygonInsetOptions {
    innerPolygonOffset: number;
    maxPolygonSplitDepth?: number;
    intersectionEpsilon?: number;
    removeEars?: boolean;
}
export declare class PolygonInset {
    /**
     * The polygon to work with.
     */
    readonly polygon: Polygon;
    /**
     * The input polygon, but without ear edges.
     */
    optimizedPolygon: Polygon;
    /**
     * The original polygon as a sequence of line objects. This is easier to use than a list of points.
     */
    originalPolygonLines: Array<Line>;
    /**
     * The simple inset lines, directly generated by offsetting the original polygon lines by the given amount.
     */
    insetLines: Array<Line>;
    /**
     * The cropped inset lines that makes up the first direct iteration of the inset polygon.
     * This one will probably be self-intersecting.
     */
    insetPolygonLines: Array<Line>;
    /**
     * The inset polygon lines resembling an actual polygon instance (not just a sequence of lines).
     */
    insetPolygon: Polygon;
    /**
     * Each polygon line and it's offsetted inset-line resemble a rectangular polygon.
     * Array<Polygon> with 4 vertices each
     **/
    insetRectanglePolygons: Array<Polygon>;
    /**
     * The inset polygon split up into simple non-self-intersecting polygons.
     * Represented as a list of vertex-lists. Each sub-list represents a single polygon.
     */
    splitPolygons: Array<Array<Vertex>>;
    /**
     * The final result: all valid split-polygons. These are making up the actual polygon inset.
     * Note: list may be empty. Depending on the offset amount there is not a guaranteed offset polygon existing.
     */
    filteredSplitPolygons: Array<Array<Vertex>>;
    /**
     * Constructs a new PolygonInset instance with the underlying given polygon to work with.
     *
     * Please note that the algorithm will reverse the vertex order if the given polygon
     * is not clockwise.
     *
     * @param {Polygon} polygon - The polygon to calculate the offset for.
     */
    constructor(polygon: Polygon);
    /**
     * This is the main method.
     *
     * Call this with the required option params to compute your desired offset polygon(s).
     *
     * @param {number} options.innerPolygonOffset - The offset to use. Should be a positive number. Correct result for negative numbers are not guaranteed.
     * @param {number?} options.maxPolygonSplitDepth - (default is the number of polygon.vertices) The maximum amount of recursive stepts to simplify the complex first iteration of the offset polygon.
     * @param {number?} options.intersectionEpsilon - (default is 1.0) The epsilon to use for detecting overlapping polygons. This indicates a tolerance value, because directly adjecent polygons may have a little arithmetic intersection area.
     * @returns {Array<Array<Vertex>>} A list of vertex-lists, each one representing a simple polygon from the offset-polygons.
     */
    computeOutputPolygons(options: IPolygonInsetOptions): Array<Array<Vertex>>;
    /**
     * This method transforms each polygon line into a new line
     * by moving it to the inside direction of the polygon (by the given `insetAmount`).
     *
     * @param {Array<Line>} polygonLines
     * @param {number} insetAmount
     * @return {Array<Line>} The transformed lines. The result array has the same length and order as the input array.
     */
    private _collectInsetLines;
    /**
     * For a sequence of inset polygon lines get the inset polygon by detecting
     * useful intersections (by cropping or extending them).
     *
     * The returned lines resemble a new polygon.
     *
     * Please note that the returned polygon can be self-intersecting!
     *
     * @param {Array<Line>} insetLines
     * @returns {Array<Line>} The cropped or exented inset polygon lines.
     */
    private _collectInsetPolygonLines;
    /**
     * Converts two lists (same length) of original polygon lines and inset lines (interpreted as
     * pairs) to a list of rectangular polyons.
     *
     * @static
     * @param {Array<Line>} originalPolygonLines
     * @param {Array<Line>} insetLines
     * @returns {Array<Polygon>} A list of rectangular polygons; each returned polyon has exactly four vertices.
     */
    private _collectRectangularPolygonInsets;
    /**
     * Converts a sequence of (hopefully adjacent) lines to a polygon by using all second line vertices `b`.
     *
     * @static
     * @param insetPolygonLines
     * @returns
     */
    private static convertToBasicInsetPolygon;
    /**
     * Optimize the inset polygon by removing critical `ear` edges.
     * Such an is identified by: the edge itself is completely located inside its neighbours inset rectangle.
     *
     * In this process multiple edges from the ear might be dropped and two adjacent edges get a new
     * common intersection point.
     *
     * Note: this method is not working as expected in all cases and quite experimental.
     *
     * @param insetPolygon
     * @param insetRectangles
     */
    private static _optimizeInsetPolygon;
    private static _locateExcessiveEarEdge;
    private static _rectangleFullyContainsLine;
    /**
     * Filter split polygons: only keep those whose vertices are all contained inside the original polygon.
     * Reason: scaling too much will result in excessive translation beyond the opposite bounds of the polygon (like more than 200% of possible insetting).
     *
     * @param {Array<Array<Vertex>>} splitPolygonsVertices
     * @param {Polygon} originalPolygon
     * @return {Array<Array<Vertex>>} The filtered polygon list.
     */
    private static _filterInnerSplitPolygonsByOriginalBounds;
    /**
     * Filter split polygons: only keep those that do not (signifiantly) interset with any rectangles.
     *
     * @static
     * @param {Array<Array<Vertex>>} splitPolygonsVertices
     * @param {Array<Polygon>} insetRectanglePolygons
     * @param {number?=1.0} intersectionEpsilon - (optional, default is 1.0) A epsislon to define a tolerance for checking if two polygons intersect.
     */
    private static _filterInnerSplitPolygonsByCoverage;
    /**
     * This private method will reverse each polygon's vertex order that's not clockwise.
     *
     * @param {Array<Vertex[]>} polygons
     */
    private static _assertAllPolygonsAreClockwise;
    /**
     * This private method will revert the vertex order if the polygon is not clockwise.
     *
     * @param {Vertex[]} polygonVerts
     */
    private static _assertPolygonIsClockwise;
    /**
     * For simplification I'm using a callback generator function here.
     *
     * @param splitPolyVerts
     * @param eps
     * @param _splitPolyIndex
     * @returns {Function} The callback for an `Array.some` parameter.
     */
    private static _hasIntersectionCallback;
}
