// Type definitions for flatten-js library
// Project: https://github.com/alexbol99/flatten-js
// Definitions by: Alex Bol

import IntervalTree from "@flatten-js/interval-tree";
/// <reference types="@flatten-js/interval-tree" />

declare namespace Flatten {
    interface SVGAttributes {
        r?: number,
        stroke?: string | number,
        strokeWidth?: number,
        fill?: string | number,
        fillRule?: "nonzero" | "evenodd",
        fillOpacity?: number,
        id? : string,
        className?: string
    }

    type Comparable = any;      // any object that implements operators '<' and '==' and 'max'
    type Value = any;

    interface Interval {
        low: Comparable;
        high: Comparable;

        readonly  max: Comparable;

        clone(): Interval;
        less_than(other_interval: Interval) : boolean;
        equal_to(other_interval: Interval) : boolean;
        intersect(other_interval: Interval) : boolean;
        not_intersect(other_interval: Interval) : boolean;
        output() : any;

        comparable_max(arg1: Comparable, arg2: Comparable) : Comparable;
        comparable_less_than(arg1: Comparable, arg2: Comparable ) : boolean;
    }

    class LinkedListElement {
        next: LinkedListElement | null;
        prev: LinkedListElement | null;
    }

    class LinkedList {
        // members
        first: LinkedListElement;
        last: LinkedListElement;

        // getters
        readonly size: number;

        // public methods
        append(element: LinkedListElement): LinkedList;
        insert(newElement: LinkedListElement, prevElement: LinkedListElement): LinkedList;
        remove(element: LinkedListElement): LinkedList;
        toArray(start?: LinkedListElement, end?: LinkedListElement): LinkedListElement[];
        isEmpty(): boolean;
        static testInfiniteLoop(first: LinkedListElement): undefined;
    }

    class CircularLinkedList extends LinkedList {}

    type DE9IM_element = Array<AnyShape> | undefined;
    /* Impossible to set length for tuple ? Really ? */
    type DE9IM_matrix = [
        DE9IM_element,DE9IM_element,DE9IM_element,
        DE9IM_element,DE9IM_element,DE9IM_element,
        DE9IM_element,DE9IM_element,DE9IM_element
    ];

    class DE9IM {
        // member
        m: DE9IM_matrix;

        get I2I();
        set I2I(geom: Array<AnyShape>);

        get I2B();
        set I2B(geom: Array<AnyShape>);

        get I2E();
        set I2E(geom: Array<AnyShape>);

        get B2I();
        set B2I(geom: Array<AnyShape>);

        get B2B();
        set B2B(geom: Array<AnyShape>);

        get B2E();
        set B2E(geom: Array<AnyShape>);

        get E2I();
        set E2I(geom: Array<AnyShape>);

        get E2B();
        set E2B(geom: Array<AnyShape>);

        get E2E();
        set E2E(geom: Array<AnyShape>);

        toString() : string;
    }

    const CCW = true;
    const CW = false;

    class Shape {
        translate(vec: Vector): Shape;
        translate(x:number, y:number): Shape;
        /**
         * Returns new shape rotated by given angle around given center point.
         * If center point is omitted, rotates around zero point (0,0).
         * Positive value of angle defines rotation in counterclockwise direction,
         * negative angle defines rotation in clockwise direction
         * @param {number} angle - angle in radians
         * @param {Point} [center=(0,0)] center
         * @returns {Shape}
         */
        rotate(angle: number, center?: Point): Shape;
        scale(scaleX: number, scaleY: number) : Shape;
        transform(matrix: Matrix): Shape;
    }
    class Arc extends Shape {
        counterClockwise: boolean;

        // members
        ps: Point;
        r: Number;
        startAngle: number;
        endAngle: number;

        constructor(
            pc?: Point,
            r?: number,
            startAngle?: number,
            endAngle?: number,
            counterClockwise?: boolean
        );

        // getters
        readonly start: Point;
        readonly end: Point;
        readonly center: Point;
        readonly length: number;
        readonly sweep: number;
        readonly vertices: [Point, Point];
        readonly box: Box;

        // public methods
        clone(): Arc;
        contains(pt: Point): boolean;
        split(pt: Point): [Arc | undefined, Arc | undefined];
        middle(): Point;
        pointAtLength(length: number): Point|null;
        chordHeight(): number;
        intersect(shape: AnyShape): Array<Point>;
        distanceTo(geom: AnyShape | PlanarSet): [number, Segment];
        breakToFunctional(): Array<Arc>;
        tangentInEnd(): Vector;
        tangentInStart(): Vector;
        reverse(): Arc;
        translate(vec: Vector): Arc;
        translate(x:number, y:number): Arc;
        rotate(angle: number, center?: Point): Arc;
        scale(scaleX: number, scaleY: number) : Arc;
        transform(matrix: Matrix): Arc;
        sortPoints(pts: Array<Point>): Array<Point>;
        toJSON() : Object;
        svg(attrs?: SVGAttributes): string;
    }

    class Box extends Shape implements Interval {
        constructor(xmin?: number, ymin?: number, xmax?: number, ymax?: number);

        //members
        xmin: number;
        ymin: number;
        xmax: number;
        ymax: number;

        // getters
        readonly center: Point;
        readonly high: Point;
        readonly low: Point;
        readonly max: Box;
        readonly width: number;
        readonly height: number;

        // public methods
        clone(): Box;
        not_intersect(box: Box): boolean;
        intersect(box: Box): boolean;
        contains(shape: AnyShape): boolean;
        merge(box: Box): Box;
        less_than(box: Box): boolean;
        equal_to(box: Box): boolean;
        set(xmin: number, ymin: number, xmax: number, ymax: number): void;
        toPoints() : Array<Point>;
        toSegments() : Array<Segment>;
        translate(vec: Vector): Box;
        translate(x:number, y:number): Box;
        rotate(angle: number, center?: Point): never;
        scale(scaleX: number, scaleY: number) : Box;
        transform(matrix: Matrix): Box;
        output(): Box;         // required by base type Interval
        svg(attrs?: SVGAttributes): string;

        comparable_max(arg1: Comparable, arg2: Comparable) : Comparable;
        comparable_less_than(arg1: Comparable, arg2: Comparable ) : boolean;
    }

    class Circle extends Shape {
        constructor(pc: Point, r: number);

        // members
        pc: Point;
        r: number;

        // getters
        readonly box: Box;
        readonly center: Point;

        // public methods
        clone(): Circle;
        contains(shape: AnyShape): boolean;
        toArc(counterclockwise?: boolean): Arc;
        intersect(shape: AnyShape): Array<Point>;
        distanceTo(geom: AnyShape | PlanarSet): [number, Segment];
        translate(vec: Vector): Circle;
        translate(x:number, y:number): Circle;
        rotate(angle: number, center?: Point): Circle;
        scale(scaleX: number, scaleY: number) : Circle | never;
        transform(matrix: Matrix): Circle;
        toJSON() : Object;
        svg(attrs?: SVGAttributes): string;
    }

    class Line extends Shape {
        constructor(pt?: Point, norm?: Vector);
        constructor(norm: Vector, pt: Point);
        constructor(pt1: Point, pt2: Point);

        // members
        pt: Point;
        norm: Vector;

        // getters
        readonly start: undefined;
        readonly end: undefined;
        readonly box: Box;
        readonly length: number;
        readonly slope: number;
        readonly standard: [number, number, number];

        // public methods
        clone(): Line;
        parallelTo(line: Line): boolean;
        incidentTo(line: Line): boolean;
        contains(pt: Point): boolean;
        coord(pt: Point): number;
        intersect(shape: AnyShape): Point[];
        distanceTo(shape: AnyShape): [number, Segment];
        split(pt: Point | Point[]): AnyShape[];
        sortPoints(points: Point[]): Point[];
        translate(vec: Vector): Line;
        translate(x:number, y:number): Line;
        rotate(angle: number, center?: Point): Line;
        scale(scaleX: number, scaleY: number) : Line;
        transform(matrix: Matrix): Line;
        toJSON() : Object;
        svg(box: Box, attrs?: SVGAttributes): string;
    }

    class Point extends Shape {
        constructor(x?: number, y?: number);
        constructor(arg?: [number, number]);

        // members
        x: number;
        y: number;

        //getters
        readonly box: Box;
        readonly vertices: [Point];

        // public methods
        clone(): Point;
        equalTo(pt: Point): boolean;
        lessThan(pt: Point): boolean;
        translate(vec: Vector): Point;
        translate(x: number, y: number): Point;
        rotate(angle: number, center?: Point): Point;
        scale(scaleX: number, scaleY: number) : Point;
        transform(matrix: Matrix): Point;
        projectionOn(line: Line): Point;
        distanceTo(geom: AnyShape | PlanarSet): [number, Segment];
        leftTo(line: Line): boolean;
        on(shape: Point | AnyShape): boolean;
        toJSON() : Object;
        svg(attrs?: SVGAttributes): string;
    }

    class Ray extends Shape {
        // members
        pt: Point;
        norm: Vector;

        // getters
        readonly start: Point;
        readonly box: Box;
        readonly slope: number;

        constructor(pt?: Point, norm?: Vector);

        // public methods
        clone(): Ray;
        contains(pt: Point): boolean;
        split(pt: Point[]): AnyShape[];
        intersect(shape: AnyShape): Point[];
        translate(vec: Vector): Ray;
        translate(x:number, y:number): Ray;
        rotate(angle: number, center?: Point): Ray;
        scale(scaleX: number, scaleY: number) : Ray;
        transform(matrix: Matrix): Ray;
        svg(box: Box, attrs?: SVGAttributes): string;
    }

    class Segment extends Shape {
        constructor(ps?: Point, pe?: Point);

        // members
        ps: Point;
        pe: Point;

        // getters
        readonly start: Point;
        readonly end: Point;
        readonly box: Box;
        readonly length: number;
        readonly slope: number;
        readonly vertices: [Point, Point];

        // public methods
        clone(): Segment;
        equalTo(seg: Segment): boolean;
        contains(pt: Point): boolean;
        intersect(shape: AnyShape): Point[];
        distanceTo(shape: AnyShape): [number, Segment];
        tangentInStart(): Vector;
        tangentInEnd(): Vector;
        reverse(): Segment;
        split(pt: Point): [Segment|null,Segment|null];
        middle(): Point;
        pointAtLength(length: number): Point|null;
        translate(vec: Vector): Segment;
        translate(x:number, y:number): Segment;
        rotate(angle: number, center?: Point): Segment;
        scale(scaleX: number, scaleY: number) : Segment;
        transform(matrix: Matrix): Segment;
        isZeroLength(): boolean;
        sortPoints(points: Array<Point>) : Array<Point>;
        toJSON() : Object;
        svg(attrs?: SVGAttributes): string;
    }

    class Vector extends Shape {
        constructor(x?: number, y?: number);
        constructor(ps: Point, pe: Point);

        // members
        x: number;
        y: number;

        // getters
        readonly length: number;
        readonly slope: number;

        // public methods
        clone(): Vector;
        equalTo(v: Vector): boolean;
        multiply(scalar: number): Vector;
        dot(v: Vector): number;
        cross(v: Vector): number;
        normalize(): Vector;
        rotate(angle: number): Vector;
        rotate90CCW(): Vector;
        rotate90CW(): Vector;
        translate(vec: Vector): Vector;
        translate(x:number, y:number): Vector;
        rotate(angle: number, center?: Point): Vector;
        scale(scaleX: number, scaleY: number) : Vector;
        transform(matrix: Matrix): Vector;
        invert(): Vector;
        add(v: Vector): Vector;
        subtract(v: Vector): Vector;
        angleTo(v: Vector): number;
        projectionOn(v: Vector): Vector;
        toJSON() : Object;
    }

    class Matrix {
        constructor(a?: number, b?: number, c?: number, d?: number, tx?: number, ty?: number);

        // members
        a: number;
        b: number;
        c: number;
        d: number;
        tx: number;
        ty: number;

        // public methods
        clone(): Matrix;
        equalTo(matrix: Matrix): boolean;
        multiply(matrix: Matrix): Matrix;
        rotate(angle: number, centerX?: number, centerY?: number): Matrix;
        scale(sx: number, sy: number): Matrix;
        transform(vector: [number,number]): [number, number];
        translate(tx: number, ty: number): Matrix;
        translate(vector: Vector) : Matrix;
    }

    type PlanarSetEntry = AnyShape | {key: Box, value: AnyShape}

    // @ts-ignore (Set)
    class PlanarSet extends Set {
        // @ts-ignore (Set)
        constructor(shapes?: PlanarSetEntry[] | Set<PlanarSetEntry>);

        // members
        index: IntervalTree;

        // public methods
        add(element: PlanarSetEntry): this;
        delete(element: PlanarSetEntry): boolean;
        clear() : void;
        hit(pt: Point): AnyShape[];
        search(box: Box): AnyShape[];
        svg(): string;
    }


    const INSIDE = 1;
    const OUTSIDE = 0;
    const BOUNDARY = 2;
    enum EdgeRelationType {INSIDE, OUTSIDE, BOUNDARY}
    const OVERLAP_SAME = 1;
    const OVERLAP_OPPOSITE = 2;
    enum EdgeOverlappingType {OVERLAP_SAME, OVERLAP_OPPOSITE}

    // Base class Edge for PolygonEdge and MultilineEdge
    class Edge {
        // members
        shape: any

        constructor(shape: any);
        face: Face;
        next: Edge;
        prev: Edge;
        bvStart: EdgeRelationType;
        bvEnd: EdgeRelationType;
        bv: EdgeRelationType;
        overlap: EdgeOverlappingType;
        arc_length: number;

        // getters
        readonly start: Point;
        readonly end: Point;
        readonly length: number;
        readonly box: Box;
        readonly isSegment: boolean;
        readonly isArc: boolean;
        readonly isLine: boolean;
        readonly isRay: boolean

        // public methods
        contains(pt: Point): boolean;
        middle(): Point;
        pointAtLength(length: number): Point|null;
        setInclusion(polygon: Polygon): EdgeRelationType;
        setOverlap(edge: Edge) : EdgeOverlappingType;
    }

    class PolygonEdge extends Edge {
        shape: Segment | Arc;
        constructor(shape: Segment | Arc);
    }

    class Face extends CircularLinkedList {
        // constructor is not documented and should not be called implicitly

        // members
        first: PolygonEdge;
        last: PolygonEdge;

        // getters
        readonly box: Box;
        readonly size: number;
        readonly length: number;
        readonly perimeter: number;
        readonly edges: PolygonEdge[];

        // public methods
        append(edge: PolygonEdge): Face;
        insert(element: PolygonEdge): Face;
        remove(element: PolygonEdge): Face;
        reverse(): void;
        setArcLength(): void;
        area(): number;
        signedArea(): number;
        orientation(): Flatten.ORIENTATION.PolygonOrientationType;
        isSimple(edges: PolygonEdge[]): boolean;
        findEdgeByPoint(pt: Point): PolygonEdge | undefined;
        pointAtLength(length: number): Point|null;
        toPolygon(): Polygon;
        svg(attrs?: SVGAttributes, pathDefined? : boolean): string;
    }

    type NumericPair = [number,number];
    type ConstructorEdgeShape = Point | Segment | Arc ;
    type LoopOfShapes = Array<ConstructorEdgeShape | NumericPair>;
    type MultiLoopOfShapes = Array<LoopOfShapes | Circle | Box>;

    class Polygon {
        constructor(args?: LoopOfShapes | Circle | Box | MultiLoopOfShapes);

        // members
        edges: PlanarSet;
        faces: PlanarSet;

        // getters
        readonly box: Box;
        readonly vertices: Point[];

        // public methods
        clone(): Polygon;
        isEmpty(): boolean;
        isValid(): boolean;
        area(): number;
        addFace(args: Array<Point> | Array<Segment | Arc> | Circle | Box): Face;
        addFace(edge_from: Edge, edge_to: Edge): Face;
        deleteFace(face: Face): boolean;
        recreateFaces(): void;
        removeChain(face: Face, edgeFrom: PolygonEdge, edgeTo: PolygonEdge): void;
        addVertex(pt: Point, edge: PolygonEdge): PolygonEdge;
        removeEndVertex(edge: Edge): void;
        cut(multiline: Multiline): Polygon[];
        cutWithLine(line: Line): Polygon;
        findEdgeByPoint(pt: Point): PolygonEdge;
        splitToIslands() : Polygon[];
        reverse(): Polygon;
        contains(shape: AnyShape): boolean;
        distanceTo(shape: AnyShape): [number, Segment];
        intersect(shape: AnyShape): Point[];
        rotate(angle?: number, center?: Point): Polygon;
        scale(sx: number, sy: number): Polygon;
        transform(matrix?: Matrix): Polygon;
        translate(vec: Vector): Polygon;
        toJSON() : Object;
        toArray() : Polygon[];
        svg(attrs?: SVGAttributes): string;
        /**
         * get the outer normalized normal vector
         * @param ver vertex index
         */
        computeNormal(ver: number): Vector;
    }

    type MultilineEdgeShape = Segment | Arc | Ray | Line;
    type MultilineShapes = Array<MultilineEdgeShape> | [Line]

    class MultilineEdge extends Edge {
        shape: MultilineEdgeShape;          // there may be only one line edge and only terminal ray edges
        constructor(shape: MultilineEdgeShape);
    }

    class Multiline extends LinkedList {
        constructor(args?: MultilineShapes);

        // getters
        get edges() : MultilineEdge[];
        get vertices(): Point[];
        get box(): Box;

        clone(): Multiline;
        addVertex(pt: Point, edge: MultilineEdge): MultilineEdge;
        split(ip: Point[]) : Multiline;
        findEdgeByPoint(pt: Point): MultilineEdge | undefined;
        rotate(angle?: number, center?: Point): Multiline;
        transform(matrix?: Matrix): Multiline;
        translate(vec: Vector): Multiline;
        toShapes(): MultilineShapes;
        toJSON() : Object;
        svg(attrs?: SVGAttributes): string;
    }

    class Inversion {
        circle: Circle;              // inversion circle
        constructor(circle: Circle);
        get inversion_circle() : Circle;
        inverse(Point: Point) : Point;
        inverse(Line: Line) : Line | Circle;
        inverse(Circle: Circle) : Line | Circle;
    }

    class Errors {
        readonly ILLEGAL_PARAMETERS: ReferenceError;
        readonly ZERO_DIVISION: Error;
        readonly UNRESOLVED_BOUNDARY_CONFLICT: Error;
        readonly INFINITE_LOOP: Error;
        readonly CANNOT_COMPLETE_BOOLEAN_OPERATION: Error;
        readonly CANNOT_INVOKE_ABSTRACT_METHOD: Error;
        readonly OPERATION_IS_NOT_SUPPORTED: Error;
    }

    type AnyShape = Point | Vector | Line | Ray | Circle | Box | Segment | Arc | Polygon;

    function point(x?: number, y?: number): Point;
    function point(arr?: [number, number]): Point;
    function circle(pc: Point, r: number) : Circle;
    function line(pt?: Point, norm?: Vector) : Line;
    function line(norm?: Vector, pt?: Point) : Line;
    function line(pt1?: Point, pt2?: Point) : Line;
    function segment(ps?: Point, pe?: Point) : Segment;
    function segment(arr: [number, number, number, number]) : Segment;
    function segment(psx: number, psy: number, pex: number, pey: number) : Segment;
    function arc(pc?: Point, r?: number, startAngle?: number, endAngle?: number, counterClockwise?: boolean) : Arc;
    function vector(x?: number, y?: number) : Vector;
    function vector(arr: [number, number]) : Vector;
    function vector(p1: Point, p2: Point) : Vector;
    function ray(pt?: Point) : Ray;
    function ray(x: number, y: number): Ray;
    function matrix(a: number, b: number, c: number, d: number, tx: number, ty: number) : Matrix;
}

declare namespace Flatten.ORIENTATION {
    const CCW: -1;
    const CW: 1;
    const NOT_ORIENTABLE: 0;
    enum PolygonOrientationType {CCW, CW, NOT_ORIENTABLE}
}

declare namespace Flatten.Utils {
    function getTolerance() : number;
    function setTolerance(tolerance: number): void;
    function EQ(x: number, y: number) : boolean;
    function EQ_0(x: number) : boolean;
    function GT(x: number, y: number) : boolean;
    function GE(x: number, y: number) : boolean;
    function LT(x: number, y: number) : boolean;
    function LE(x: number, y: number) : boolean;
}

declare namespace Flatten.BooleanOperations {
    function unify(polygon1: Polygon, polygon2: Polygon): Polygon;
    function subtract(polygon1: Polygon, polygon2: Polygon): Polygon;
    function intersect(polygon1: Polygon, polygon2: Polygon): Polygon;
    function innerClip(polygon1: Polygon, polygon2: Polygon): [AnyShape[], AnyShape[]];
    function outerClip(polygon1: Polygon, polygon2: Polygon): AnyShape[];
    function calculateIntersections(polygon1: Polygon, polygon2: Polygon): [Point[],Point[]];
}

declare namespace Flatten.Relations {
    function relate(shape1: AnyShape, shape2: AnyShape): DE9IM;
    function equal(shape1: AnyShape, shape2: AnyShape): boolean;
    function intersect(shape1: AnyShape, shape2: AnyShape): boolean;
    function touch(shape1: AnyShape, shape2: AnyShape): boolean;
    function disjoint(shape1: AnyShape, shape2: AnyShape): boolean;
    function inside(shape1: AnyShape, shape2: AnyShape): boolean;
    function covered(shape1: AnyShape, shape2: AnyShape): boolean;
    function cover(shape1: AnyShape, shape2: AnyShape): boolean;
}

export = Flatten;
export as namespace Flatten;

/**
 * ( interface Matrix<T> )
 */
export interface Matrix {
    /**
     * Array with matrix values.
     */
    elements: number[];

    /**
     * identity():T;
     */
    identity(): Matrix;

    /**
     * copy(m:T):T;
     */
    copy(m: this): this;

    /**
     * multiplyScalar(s:number):T;
     */
    multiplyScalar(s: number): Matrix;

    determinant(): number;

    /**
     * transpose():T;
     */
    transpose(): Matrix;

    /**
     * invert():T;
     */
    invert(): Matrix;

    /**
     * clone():T;
     */
    clone(): Matrix;
}

/**
 * ( class Matrix3 implements Matrix<Matrix3> )
 */
export class Matrix3 implements Matrix {
    readonly isMatrix3: true;

    /**
     * Creates an identity matrix.
     */
    constructor();
    /**
     * Creates a 3x3 matrix with the given arguments in row-major order.
     */
    constructor(
        n11: number,
        n12: number,
        n13: number,
        n21: number,
        n22: number,
        n23: number,
        n31: number,
        n32: number,
        n33: number,
    );

    /**
     * Array with matrix values.
     * @default [1, 0, 0, 0, 1, 0, 0, 0, 1]
     */
    elements: number[];

    set(
        n11: number,
        n12: number,
        n13: number,
        n21: number,
        n22: number,
        n23: number,
        n31: number,
        n32: number,
        n33: number,
    ): Matrix3;
    identity(): Matrix3;
    clone(): this;
    copy(m: Matrix3): this;
    extractBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3): Matrix3;
    setFromMatrix4(m: Matrix4): Matrix3;
    multiplyScalar(s: number): Matrix3;
    determinant(): number;

    /**
     * Inverts this matrix in place.
     */
    invert(): Matrix3;

    /**
     * Transposes this matrix in place.
     */
    transpose(): Matrix3;
    getNormalMatrix(matrix4: Matrix4): Matrix3;

    /**
     * Transposes this matrix into the supplied array r, and returns itself.
     */
    transposeIntoArray(r: number[]): Matrix3;

    setUvTransform(tx: number, ty: number, sx: number, sy: number, rotation: number, cx: number, cy: number): Matrix3;

    scale(sx: number, sy: number): Matrix3;

    /**
     * Sets this matrix as a 2D translation transform:
     *
     * ```
     * 1, 0, x,
     * 0, 1, y,
     * 0, 0, 1
     * ```
     *
     * @param x the amount to translate in the X axis.
     * @param y the amount to translate in the Y axis.
     */
    makeTranslation(v: Vector2): this;
    makeTranslation(x: number, y: number): this;

    /**
     * Sets this matrix as a 2D rotational transformation by theta radians. The resulting matrix will be:
     *
     * ```
     * cos(θ) -sin(θ) 0
     * sin(θ) cos(θ)  0
     * 0      0       1
     * ```
     *
     * @param theta Rotation angle in radians. Positive values rotate counterclockwise.
     */
    makeRotation(theta: number): this;
    makeRotation(theta: number): Matrix3;

    /**
     * Sets this matrix as a 2D scale transform:
     *
     * ```
     * x, 0, 0,
     * 0, y, 0,
     * 0, 0, 1
     * ```
     *
     * @param x the amount to scale in the X axis.
     * @param y the amount to scale in the Y axis.
     */
    makeScale(x: number, y: number): this;
    makeScale(x: number, y: number): Matrix3;

    rotate(theta: number): Matrix3;

    translate(tx: number, ty: number): Matrix3;

    equals(matrix: Matrix3): boolean;

    /**
     * Sets the values of this matrix from the provided array or array-like.
     * @param array the source array or array-like.
     * @param offset (optional) offset into the array-like. Default is 0.
     */
    fromArray(array: number[] | ArrayLike<number>, offset?: number): Matrix3;

    /**
     * Returns an array with the values of this matrix, or copies them into the provided array.
     * @param array (optional) array to store the matrix to. If this is not provided, a new array will be created.
     * @param offset (optional) optional offset into the array.
     * @return The created or provided array.
     */
    toArray(array?: number[], offset?: number): number[];
    toArray(array?: Matrix3Tuple, offset?: 0): Matrix3Tuple;

    /**
     * Copies he values of this matrix into the provided array-like.
     * @param array array-like to store the matrix to.
     * @param offset (optional) optional offset into the array-like.
     * @return The provided array-like.
     */
    toArray(array?: ArrayLike<number>, offset?: number): ArrayLike<number>;

    /**
     * Multiplies this matrix by m.
     */
    multiply(m: Matrix3): Matrix3;

    premultiply(m: Matrix3): Matrix3;

    /**
     * Sets this matrix to a x b.
     */
    multiplyMatrices(a: Matrix3, b: Matrix3): Matrix3;

    /**
     * @deprecated Use {@link Vector3.applyMatrix3 vector.applyMatrix3( matrix )} instead.
     */
    multiplyVector3(vector: Vector3): any;

    /**
     * @deprecated This method has been removed completely.
     */
    multiplyVector3Array(a: any): any;

    /**
     * @deprecated Use {@link Matrix3#invert .invert()} instead.
     */
    getInverse(matrix: Matrix4, throwOnDegenerate?: boolean): Matrix3;
    getInverse(matrix: Matrix): Matrix;

    /**
     * @deprecated Use {@link Matrix3#toArray .toArray()} instead.
     */
    flattenToArrayOffset(array: number[], offset: number): number[];
}