"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Polygon = void 0;
var HVec3_1 = require("src/math/HVec3");
var decimal_js_1 = __importDefault(require("decimal.js"));
var EPSILON = new decimal_js_1.default(1e-15);
var Side;
(function (Side) {
    Side[Side["COPLANAR"] = 0] = "COPLANAR";
    Side[Side["FRONT"] = 1] = "FRONT";
    Side[Side["BACK"] = 2] = "BACK";
    Side[Side["SPANNING"] = 3] = "SPANNING";
})(Side || (Side = {}));
/*
 * @Description  : 高精度多边形
 * @Author       : 赵耀圣
 * @QQ           : 549184003
 * @Date         : 2021-08-03 11:11:59
 * @LastEditTime : 2021-08-03 15:49:25
 * @FilePath     : \cga.js\src\csg\polygon.ts
 */
var Polygon = /** @class */ (function () {
    function Polygon(vertices) {
        if (vertices === void 0) { vertices = []; }
        this.w = new decimal_js_1.default(0);
        this.normal = new HVec3_1.HVec3;
        this.vertices = vertices;
        this.vertices = vertices;
        if (vertices.length > 0) {
            this.calcPlane();
        }
    }
    Polygon.prototype.calcPlane = function () {
        var a = this.vertices[0], b = this.vertices[1], c = this.vertices[2];
        this.normal = b.clone().sub(a).cross(c.clone().sub(a)).normalize();
        this.w = this.normal.clone().dot(a);
        return this;
    };
    Polygon.prototype.flip = function () {
        this.normal.multiplyScalar(-1);
        this.w.mul(-1);
        this.vertices.reverse();
        return this;
    };
    /**
     * @description : 判断点与当前多边形所在的平面的位置关系
     * @param        {HVec3} vertex
     * @return       {*}
     * @example     :
     */
    Polygon.prototype.classifyVertex = function (vertex) {
        var side_value = this.normal.dot(vertex).sub(this.w);
        if (side_value.lessThan(-EPSILON)) {
            return Side.BACK;
        }
        else if (side_value > EPSILON) {
            return Side.FRONT;
        }
        else {
            return Side.COPLANAR;
        }
    };
    /**
     * @description : 判断另一个多边形与当前多边形的位置关系
     * @param        {Polygon} polygon
     * @return       {*}
     * @example     :
     */
    Polygon.prototype.classifySide = function (polygon) {
        var vertex, classification, num_positive = 0, num_negative = 0;
        var vslen = polygon.vertices.length;
        var i;
        for (i = 0; i < vslen; i++) {
            vertex = polygon.vertices[i];
            classification = this.classifyVertex(vertex);
            if (classification === Side.FRONT) {
                num_positive++;
            }
            else if (classification === Side.BACK) {
                num_negative++;
            }
        }
        if (num_positive === vslen && num_negative === 0) {
            return Side.FRONT;
        }
        else if (num_positive === 0 && num_negative === vslen) {
            return Side.BACK;
        }
        else if (num_positive > 0 && num_negative > 0) {
            return Side.SPANNING;
        }
        else {
            return Side.COPLANAR;
        }
    };
    /**
     * @description : 切割多边形
     * @param        {Polygon} polygon
     * @param        {Polygon} coplanar_front
     * @param        {Polygon} coplanar_back
     * @param        {Polygon} front
     * @param        {Polygon} back
     * @return       {*}
     * @example     :
     */
    Polygon.prototype.splitPolygon = function (polygon, coplanar_front, coplanar_back, front, back) {
        if (coplanar_front === void 0) { coplanar_front = []; }
        if (coplanar_back === void 0) { coplanar_back = []; }
        if (front === void 0) { front = []; }
        if (back === void 0) { back = []; }
        var classification = this.classifySide(polygon);
        if (classification === Side.COPLANAR) {
            (this.normal.dot(polygon.normal).greaterThan(0) ? coplanar_front : coplanar_back).push(polygon);
        }
        else if (classification === Side.FRONT) {
            front.push(polygon);
        }
        else if (classification === Side.BACK) {
            back.push(polygon);
        }
        else {
            var i, j, ti, tj, vi, vj, t, v, f = [], b = [];
            var vslen = void 0;
            for (i = 0, vslen = polygon.vertices.length; i < vslen; i++) {
                j = (i + 1) % vslen;
                vi = polygon.vertices[i];
                vj = polygon.vertices[j];
                ti = this.classifyVertex(vi);
                tj = this.classifyVertex(vj);
                if (ti != Side.BACK)
                    f.push(vi);
                if (ti != Side.FRONT)
                    b.push(vi);
                if ((ti | tj) === Side.SPANNING) {
                    t = (this.w.sub(this.normal.dot(vi))).div(this.normal.dot(vj.clone().sub(vi)));
                    v = vi.lerp(vj, t);
                    f.push(v);
                    b.push(v);
                }
            }
            if (f.length >= 3)
                front.push(new Polygon(f).calcPlane());
            if (b.length >= 3)
                back.push(new Polygon(b).calcPlane());
        }
    };
    Polygon.prototype.clone = function () {
        var i, vslen = this.vertices.length;
        var polygon = new Polygon();
        for (i = 0; i < vslen; i++) {
            polygon.vertices.push(this.vertices[i].clone());
        }
        polygon.calcPlane();
        return polygon;
    };
    return Polygon;
}());
exports.Polygon = Polygon;
