'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var three = require('three');
var xaop = require('xaop');
var mobx = require('mobx');
var LineMaterial = require('three/examples/jsm/lines/LineMaterial');
var Line2 = require('three/examples/jsm/lines/Line2');
var LineGeometry = require('three/examples/jsm/lines/LineGeometry');

/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */

function __decorate(decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
}

let HostApplicationServices = { ShowHistoryLog: true };

/**
 * 销毁Object对象的Geometry,并不会销毁材质.
 */
function DisposeThreeObj(obj) {
    for (let o of obj.children) {
        let oany = o;
        //文字的geometry缓存保留下来
        if (oany.geometry && oany.geometry.name !== "Text")
            oany.geometry.dispose();
        DisposeThreeObj(o);
        o.parent = null;
        o.dispatchEvent({ type: "removed" });
    }
    obj.children.length = 0;
    return obj;
}
function Object3DRemoveAll(obj) {
    for (let o of obj.children) {
        o.parent = null;
        o.dispatchEvent({ type: "removed" });
    }
    obj.children.length = 0;
    return obj;
}

/**
 * 坐标系运算.
 */
class CoordinateSystem {
    constructor(postion, xAxis, yAxis, zAxis) {
        this.Postion = postion || new three.Vector3(0, 0, 0);
        this.XAxis = xAxis || new three.Vector3(1, 0, 0);
        this.YAxis = yAxis || new three.Vector3(0, 1, 0);
        this.ZAxis = zAxis || new three.Vector3(0, 0, 1);
    }
    applyMatrix4(mat4) {
        this.Postion.applyMatrix4(mat4);
        let roMat = mat4.clone().setPosition(new three.Vector3());
        this.XAxis.applyMatrix4(roMat);
        this.YAxis.applyMatrix4(roMat);
        this.ZAxis.applyMatrix4(roMat);
        return this;
    }
    getMatrix4() {
        let m = new three.Matrix4();
        m.makeBasis(this.XAxis, this.YAxis, this.ZAxis);
        m.setPosition(this.Postion);
        return m;
    }
    CopyForm(mat4) {
        this.Postion.setFromMatrixPosition(mat4);
        mat4.extractBasis(this.XAxis, this.YAxis, this.ZAxis);
        return this;
    }
    extractBasis(xAxisA, yAxisA, zAxisA) {
        xAxisA.copy(this.XAxis);
        yAxisA.copy(this.YAxis);
        zAxisA.copy(this.ZAxis);
    }
    copy(cs) {
        this.Postion.copy(cs.Postion);
        this.XAxis.copy(cs.XAxis);
        this.YAxis.copy(cs.YAxis);
        this.ZAxis.copy(cs.ZAxis);
        return this;
    }
    clone() {
        let r = new CoordinateSystem();
        r.Postion = this.Postion.clone();
        r.XAxis = this.XAxis.clone();
        r.YAxis = this.YAxis.clone();
        r.ZAxis = this.ZAxis.clone();
        return r;
    }
}

const IdentityMtx4 = new three.Matrix4();
const ZeroVec = new three.Vector3();
const XAxis = new three.Vector3(1, 0, 0);
const XAxisN = new three.Vector3(-1, 0, 0);
const YAxis = new three.Vector3(0, 1, 0);
const YAxisN = new three.Vector3(0, -1, 0);
const ZAxis = new three.Vector3(0, 0, 1);
function AsVector2(p) {
    return new three.Vector2(p.x, p.y);
}
function AsVector3(p) {
    return new three.Vector3(p.x, p.y, p.z);
}
/**
 * 旋转一个点,旋转中心在原点
 * @param {Vector3} p 点
 * @param {number} a 角度.
 * @returns {Vector3} 返回pt不拷贝.
 */
function rotatePoint(p, a) {
    let s = Math.sin(a);
    let c = Math.cos(a);
    let x = p.x * c - p.y * s;
    let y = p.x * s + p.y * c;
    p.x = x;
    p.y = y;
    return p;
}
function equaln(v1, v2, fuzz = 1e-5) {
    return Math.abs(v1 - v2) <= fuzz;
}
function equalv3(v1, v2, fuzz = 1e-8) {
    return equaln(v1.x, v2.x, fuzz) && equaln(v1.y, v2.y, fuzz) && equaln(v1.z, v2.z, fuzz);
}
function equalv2(v1, v2, fuzz = 1e-8) {
    return equaln(v1.x, v2.x, fuzz) && equaln(v1.y, v2.y, fuzz);
}
/**
 * 按照极坐标的方式移动一个点
 *
 * @export
 * @template
 * @param {T} v 向量(2d,3d)
 * @param {number} an 角度
 * @param {number} dis 距离
 * @returns {T}
 */
function polar(v, an, dis) {
    v.x += Math.cos(an) * dis;
    v.y += Math.sin(an) * dis;
    return v;
}
function angle(v) {
    let angle = Math.atan2(v.y, v.x);
    if (equaln(angle, 0, 1e-8))
        return 0;
    if (angle < 0)
        angle += Math.PI * 2;
    return angle;
}
/**
 * 求两个向量的夹角,顺时针为负,逆时针为正
 *
 * @param {Vector3} v1
 * @param {Vector3} v2
 * @param {Vector3} [ref] 参考向量,如果为世界坐标系则为0,0,1
 * @returns
 */
function angleTo(v1, v2, ref = new three.Vector3(0, 0, 1)) {
    if (!ref.equals(new three.Vector3(0, 0, 1))) {
        ref = ref.clone();
        v1 = v1.clone();
        v2 = v2.clone();
        //任意轴坐标系. 使用相机的构造矩阵.
        ref.multiplyScalar(-1);
        let up = getLoocAtUpVec(ref);
        let refOcs = new three.Matrix4();
        refOcs.lookAt(ZeroVec, ref, up);
        let refOcsInv = new three.Matrix4().getInverse(refOcs);
        v1.applyMatrix4(refOcsInv);
        v2.applyMatrix4(refOcsInv);
        v1.z = 0;
        v2.z = 0;
    }
    if (v1.equals(ZeroVec) || v2.equals(ZeroVec))
        return 0;
    let cv = new three.Vector3().crossVectors(v1, v2).normalize();
    return cv.z === 0 ? v1.angleTo(v2) : v1.angleTo(v2) * cv.z;
}
function getLoocAtUpVec(dir) {
    if (dir.equals(ZeroVec)) {
        throw ("zero vector");
    }
    let norm = dir.clone().normalize();
    if (norm.equals(ZAxis)) {
        return new three.Vector3(0, 1, 0);
    }
    else if (norm.equals(ZAxis.clone().negate())) {
        return new three.Vector3(0, -1, 0);
    }
    else {
        let xv = new three.Vector3();
        xv.crossVectors(ZAxis, norm);
        let up = new three.Vector3();
        up.crossVectors(norm, xv);
        return up;
    }
}
/**
 * 判断2个向量是不是平行,尽量传入单位向量,才能保证计算精度
 */
function isParallelTo(v1, v2, fuzz = 1e-8) {
    return v1.clone().cross(v2).lengthSq() < fuzz;
}
function midPoint(v1, v2) {
    return v1.clone().add(v2).multiplyScalar(0.5);
}
function MoveMatrix(v) {
    return new three.Matrix4().setPosition(v);
}
/**
 * 将角度调整为0-2pi之间
 */
function clampRad(an) {
    an = an % (Math.PI * 2);
    if (an < 0)
        an += Math.PI * 2;
    return an;
}
function updateGeometry(l, geometry) {
    let geo = l.geometry;
    geo.dispose();
    l.geometry = geometry;
    geometry.computeBoundingSphere();
}
function UpdateBoundingSphere(obj) {
    //@ts-ignore
    let geo = obj.geometry;
    if (geo)
        geo.computeBoundingSphere();
}
const comparePointCache = new Map();
/**
 * 构建返回一个用来排序的函数.根据key创建排序规则.
 *
 * 当key = "xyz" 时,点集按 x从小到大,y从小到大 z从小到大
 *   key = "X"   时,点集按 x从大到小
 * 以此类推.
 *
 * 例子:
 * let pts:Vector3[] =...;
 * pts.sort(comparePoint("x")); //x从小到大排序
 * pts.sort(comparePoint("zX")); //z从小到大 x从大到小
 *
 * @export
 * @param {string} sortKey
 * @returns {compareVectorFn}
 */
function comparePoint(sortKey) {
    if (comparePointCache.has(sortKey))
        return comparePointCache.get(sortKey);
    let sortIndex = [];
    const keys = ['x', 'X', 'y', 'Y', 'z', 'Z'];
    for (let char of sortKey) {
        let index = keys.indexOf(char);
        let i2 = index / 2;
        let ci = Math.floor(i2);
        sortIndex.push([ci, i2 > ci ? 1 : -1]);
    }
    let compareFunction = (v1, v2) => {
        if (!v1)
            return -1;
        if (!v2)
            return 1;
        for (let s of sortIndex) {
            let vv1 = v1.getComponent(s[0]);
            let vv2 = v2.getComponent(s[0]);
            if (equaln(vv1, vv2))
                continue;
            if (vv2 > vv1)
                return s[1];
            else
                return -s[1];
        }
        return 0;
    };
    comparePointCache.set(sortKey, compareFunction);
    return compareFunction;
}
function SelectNearP(pts, refPt) {
    if (pts.length > 1) {
        let dist1 = refPt.distanceToSquared(pts[0]);
        let dist2 = refPt.distanceToSquared(pts[1]);
        return dist1 <= dist2 ? pts[0] : pts[1];
    }
    return pts[0];
}

/**
 * 设置矩阵的某列的向量
 * @param {Matrix4} mat 矩阵
 * @param {number} col 列索引,0x 1y 2z 3org
 * @param {Vector3} v 向量或点
 */
function matrixSetVector(mat, col, v) {
    let index = col * 4;
    mat.elements[index] = v.x;
    mat.elements[index + 1] = v.y;
    mat.elements[index + 2] = v.z;
}
/**
 * 返回矩阵，该坐标系将坐标系与原点的坐标系映射为坐标系，
 * 并将坐标系与X轴坐标系，
 * Y轴坐标轴以及Z轴坐标系统之间的坐标系统坐标系统的原点坐标系和原点坐标系统坐标轴的坐标系分别设置为XAxis，YAxis和ZAxis
 * @returns {Matrix4} 返回新的矩阵
 */
function matrixAlignCoordSys(matrixFrom, matrixTo) {
    return new three.Matrix4().getInverse(matrixTo).multiply(matrixFrom);
}
/**
 * 判断2个矩形共面
 * @param {Matrix4} matrixFrom
 * @param {Matrix4} matrixTo
 * @returns {boolean} 2个矩阵共面
 */
function matrixIsCoplane(matrixFrom, matrixTo, fuzz = 1e-5) {
    let nor1 = new three.Vector3().setFromMatrixColumn(matrixFrom, 2);
    let nor2 = new three.Vector3().setFromMatrixColumn(matrixTo, 2);
    //法线共面
    if (!isParallelTo(nor1, nor2))
        return false;
    //高共面
    let pt = new three.Vector3().setFromMatrixPosition(matrixTo);
    //变换到自身对象坐标系.
    pt.applyMatrix4(new three.Matrix4().getInverse(matrixFrom));
    return equaln(pt.z, 0, fuzz);
}
/**
 * 修正镜像后矩阵
 */
function reviseMirrorMatrix(mtx) {
    let cs = new CoordinateSystem().applyMatrix4(mtx);
    cs.YAxis.negate();
    mtx.copy(cs.getMatrix4());
    return mtx;
}
/**
 * 把变换矩阵展平成2d矩阵,避免出现三维坐标.
 */
function MatrixPlanarizere(mtx, z0 = true) {
    mtx.elements[2] = 0;
    mtx.elements[6] = 0;
    mtx.elements[8] = 0;
    mtx.elements[9] = 0;
    mtx.elements[10] = Math.sign(mtx.elements[10]);
    if (z0)
        mtx.elements[14] = 0;
    return mtx;
}
const tempMatrix1 = new three.Matrix4;

var Status;
(function (Status) {
    Status[Status["False"] = 0] = "False";
    Status[Status["True"] = 1] = "True";
    Status[Status["Canel"] = -1] = "Canel";
    Status[Status["ConverToCircle"] = 101] = "ConverToCircle";
    Status[Status["DuplicateRecordName"] = 102] = "DuplicateRecordName";
})(Status || (Status = {}));
var UpdateDraw;
(function (UpdateDraw) {
    UpdateDraw[UpdateDraw["None"] = 0] = "None";
    UpdateDraw[UpdateDraw["Matrix"] = 1] = "Matrix";
    UpdateDraw[UpdateDraw["Geometry"] = 2] = "Geometry";
    UpdateDraw[UpdateDraw["Material"] = 4] = "Material";
    UpdateDraw[UpdateDraw["All"] = 63] = "All";
})(UpdateDraw || (UpdateDraw = {}));
/**
 * WblockClne时,遇到重复记录的操作方式
 */
var DuplicateRecordCloning;
(function (DuplicateRecordCloning) {
    DuplicateRecordCloning[DuplicateRecordCloning["Ignore"] = 1] = "Ignore";
    DuplicateRecordCloning[DuplicateRecordCloning["Replace"] = 2] = "Replace";
    DuplicateRecordCloning[DuplicateRecordCloning["Rename"] = 3] = "Rename";
})(DuplicateRecordCloning || (DuplicateRecordCloning = {}));

/**
 * 场景的渲染类型.
 *
 * @export
 * @enum {number}
 */
var RenderType;
(function (RenderType) {
    /**
     * 线框模式
     */
    RenderType[RenderType["Wireframe"] = 1] = "Wireframe";
    /**
     * 概念
     */
    RenderType[RenderType["Conceptual"] = 2] = "Conceptual";
    /**
     * 物理着色PBR
     */
    RenderType[RenderType["Physical"] = 3] = "Physical";
    RenderType[RenderType["Jig"] = 4] = "Jig";
    RenderType[RenderType["Print"] = 5] = "Print";
    /**物理带线框 */
    RenderType[RenderType["Physical2"] = 6] = "Physical2";
})(RenderType || (RenderType = {}));

var StoreageKeys;
(function (StoreageKeys) {
    StoreageKeys["IsLogin"] = "isLogin";
    StoreageKeys["PlatSession"] = "platSession";
    StoreageKeys["PlatToken"] = "platToken";
    StoreageKeys["UserName"] = "userName";
    StoreageKeys["UserPhone"] = "userPhone";
    StoreageKeys["RenderType"] = "renderType";
    StoreageKeys["ExactDrill"] = "openExactDrill";
    StoreageKeys["ConfigName"] = "configName_";
    StoreageKeys["IsNewErp"] = "isNewErp";
    StoreageKeys["RoomName"] = "roomName";
    StoreageKeys["LastOpenFileId"] = "lastfid";
    StoreageKeys["Uid"] = "uid";
    StoreageKeys["Goods"] = "Goods_";
    StoreageKeys["DrillTemp"] = "drilltemp_";
    StoreageKeys["DrillReactor"] = "drillRreactor";
    StoreageKeys["kjlConfig"] = "kjl";
})(StoreageKeys || (StoreageKeys = {}));

var AAType;
(function (AAType) {
    AAType[AAType["FXAA"] = 0] = "FXAA";
    AAType[AAType["SMAA"] = 1] = "SMAA";
})(AAType || (AAType = {}));
var ViewDirType;
(function (ViewDirType) {
    ViewDirType[ViewDirType["FS"] = 0] = "FS";
    ViewDirType[ViewDirType["YAS"] = 1] = "YAS";
    ViewDirType[ViewDirType["ZS"] = 2] = "ZS";
    ViewDirType[ViewDirType["YS"] = 3] = "YS";
    ViewDirType[ViewDirType["QS"] = 4] = "QS";
    ViewDirType[ViewDirType["HS"] = 5] = "HS";
    ViewDirType[ViewDirType["XN"] = 6] = "XN";
})(ViewDirType || (ViewDirType = {}));

class UserConfig {
    constructor() {
        this._version = 10;
        this._renderType = RenderType.Wireframe;
        this.maxSize = {
            isShow: false,
            height: 2440,
            width: 1220,
        };
        this._drillConfigs = new Map();
        this.openDrillingReactor = true;
        this.openAutoCuttingReactor = true;
        /**打开将检测排钻是否在板件内*/
        this.openExactDrill = true;
        this.userConfigName = {};
        this.modeling2HoleRad = 20; //圆造型小于等于该值拆成孔数据
        this.isAdmin = false;
        this.kjlConfig = {
            grooveAddLength: "0",
            grooveAddWidth: "0",
            grooveAddDepth: "1",
        };
        this.SystemConfig = {
            maxHightightCount: 15000,
            snapSize: 15,
            aaType: AAType.FXAA
        };
        this.viewDirType = ViewDirType.XN;
        this.useCtrlRotate = true;
        this.cursorSize = {
            D2: 1000,
            D3: 100,
        };
        this.autoSaveConfig = {
            enable: true,
            time: 1,
        };
        this.showLines = false;
        this.keepConfig = false;
        this.autoClearHistory = true;
        this.chaidanOption = {
            changXiuBian: 6,
            duanXiuBian: 6,
            useDefaultRad: false,
            radius: 2.5,
            modeling2HoleRad: 20,
            isCheckInterfere: false,
        };
        this.autoLines = false;
        this.dimTextHeight = 60;
        this.configName = "default";
        this.configsNames = [];
        this.Init();
    }
    Init() {
        let type = localStorage.getItem(StoreageKeys.RenderType);
        if (type)
            this._renderType = parseFloat(type);
    }
    set RenderType(t) {
        if (t !== this._renderType) {
            this._renderType = t;
            this.SetRenderTypeEvent();
            localStorage.setItem(StoreageKeys.RenderType, t.toString());
        }
    }
    get RenderType() { return this._renderType; }
    SetRenderTypeEvent() { }
    get DrillConfigs() {
        return this._drillConfigs || new Map();
    }
    set DrillConfigs(config) {
        mobx.observable(this._drillConfigs).replace(config);
        this.SetDrillConfigsEvent();
    }
    SetDrillConfigsEvent() { }
    InitOption() {
        this.openDrillingReactor = true;
        this.openAutoCuttingReactor = true;
        Object.assign(this.maxSize, {
            height: 2440,
            width: 1220
        });
        Object.assign(this.kjlConfig, {
            grooveAddLength: "0",
            grooveAddWidth: "0",
            grooveAddDepth: "1"
        });
        Object.assign(this.chaidanOption, {
            changXiuBian: 6,
            duanXiuBian: 6,
            useDefaultRad: false,
            radius: 2.5,
            modeling2HoleRad: 20,
        });
        this.dimTextHeight = 60;
    }
    SaveConfig() {
        return {
            option: {
                version: this._version,
                openDrillingReactor: this.openDrillingReactor,
                openAutoCuttingReactor: this.openAutoCuttingReactor,
                maxSize: mobx.toJS(this.maxSize),
                kjlConfig: mobx.toJS(this.kjlConfig),
                systemConfig: mobx.toJS(this.SystemConfig),
                viewDirType: this.viewDirType,
                useCtrlRotate: this.useCtrlRotate,
                cursorSize: mobx.toJS(this.cursorSize),
                autoSaveConfig: mobx.toJS(this.autoSaveConfig),
                showLines: this.showLines,
                keepConfig: this.keepConfig,
                autoClearHistory: this.autoClearHistory,
                chaidanOption: mobx.toJS(this.chaidanOption),
                autoLines: this.autoLines,
                dimTextHeight: this.dimTextHeight,
            }
        };
    }
    UpdateOption(config) {
        this.openDrillingReactor = config.option.openDrillingReactor;
        this.openAutoCuttingReactor = config.option.openAutoCuttingReactor;
        Object.assign(this.maxSize, config.option.maxSize);
        Object.assign(this.kjlConfig, config.option.kjlConfig);
        this.modeling2HoleRad = config.option.modeling2HoleRad;
        if (config.option.version > 1) {
            Object.assign(this.SystemConfig, config.option.systemConfig);
        }
        if (config.option.version > 2) {
            this.viewDirType = config.option.viewDirType;
            this.useCtrlRotate = config.option.useCtrlRotate;
        }
        if (config.option.version > 3) {
            Object.assign(this.cursorSize, config.option.cursorSize);
        }
        if (config.option.version > 4) {
            Object.assign(this.autoSaveConfig, config.option.autoSaveConfig);
        }
        if (config.option.version > 5) {
            this.showLines = config.option.showLines;
        }
        if (config.option.version > 6) {
            this.keepConfig = config.option.keepConfig;
        }
        if (config.option.version > 7) {
            this.autoClearHistory = config.option.autoClearHistory;
        }
        if (config.option.version > 8) {
            Object.assign(this.chaidanOption, config.option.chaidanOption);
            this.autoLines = config.option.autoLines;
        }
        else
            this.chaidanOption.modeling2HoleRad = this.modeling2HoleRad;
        if (config.option.version > 9)
            this.dimTextHeight = config.option.dimTextHeight;
    }
}
__decorate([
    mobx.observable
], UserConfig.prototype, "maxSize", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "_drillConfigs", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "openDrillingReactor", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "openAutoCuttingReactor", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "openExactDrill", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "isAdmin", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "kjlConfig", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "SystemConfig", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "viewDirType", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "useCtrlRotate", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "cursorSize", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "autoSaveConfig", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "showLines", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "keepConfig", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "autoClearHistory", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "chaidanOption", void 0);
__decorate([
    mobx.observable
], UserConfig.prototype, "autoLines", void 0);
const userConfig = new UserConfig();

/**
 * 盒子的切割类型
 */
var SplitType;
(function (SplitType) {
    SplitType[SplitType["X"] = 0] = "X";
    SplitType[SplitType["Y"] = 1] = "Y";
    SplitType[SplitType["Z"] = 2] = "Z";
})(SplitType || (SplitType = {}));
/**
 * 扩展Box3,添加切割方法,体积等
 */
class Box3Ext extends three.Box3 {
    get Volume() {
        let size = this.getSize(new three.Vector3());
        return size.x * size.y * size.z;
    }
    //每个轴的大小必须大于最小的size
    isSolid(minSize = 1) {
        return this.getSize(new three.Vector3()).toArray().every(x => x > minSize);
    }
    substract(b, spaceType) {
        let interBox = this.clone().intersect(b);
        if (interBox.isEmpty() || !interBox.isSolid())
            return [this];
        let p1 = interBox.min.clone().setComponent(spaceType, this.min.getComponent(spaceType));
        let p2 = interBox.max.clone().setComponent(spaceType, interBox.min.getComponent(spaceType));
        let p3 = interBox.min.clone().setComponent(spaceType, interBox.max.getComponent(spaceType));
        let p4 = interBox.max.clone().setComponent(spaceType, this.max.getComponent(spaceType));
        return [
            new Box3Ext(p1, p2),
            new Box3Ext(p3, p4)
        ].filter(b => b.isSolid());
    }
    clampSpace(b2, splitType) {
        let interBox = this.clone();
        interBox.min.max(b2.min);
        interBox.max.min(b2.max);
        interBox.min.setComponent(splitType, Math.min(this.max.getComponent(splitType), b2.max.getComponent(splitType)));
        interBox.max.setComponent(splitType, Math.max(this.min.getComponent(splitType), b2.min.getComponent(splitType)));
        return interBox;
    }
    intersectsBox(box, fuzz = 1e-8) {
        return IntersectsBox(this, box, fuzz);
    }
}
function IntersectsBox(box1, box2, fuzz = 1e-6) {
    return box2.max.x < box1.min.x - fuzz || box2.min.x > box1.max.x + fuzz ||
        box2.max.y < box1.min.y - fuzz || box2.min.y > box1.max.y + fuzz ||
        box2.max.z < box1.min.z - fuzz || box2.min.z > box1.max.z + fuzz ? false : true;
}
/**盒子二维面是否相交 */
function IntersectBox2(box1, box2, fuzz = 1e-3) {
    return box2.max.x < box1.min.x - fuzz || box2.min.x > box1.max.x + fuzz ||
        box2.max.y < box1.min.y - fuzz || box2.min.y > box1.max.y + fuzz ? false : true;
}

const ISPROXYKEY = "_isProxy";
/**
 * 自动对CADObject的属性添加属性记录器,自动调用 `WriteAllObjectRecord`
 * 如果属性是数组,那么自动添加`Proxy`.
 * 可以使用`ISPROXYKEY`覆盖这个函数的代理行为(使用CADObject.CreateProxyArray快速覆盖)
 *
 * @param target
 * @param property
 * @param [descriptor]
 */
function AutoRecord(target, property, descriptor) {
    let privateKey = '__' + property;
    Object.defineProperty(target, property, {
        set: function (value) {
            if (value instanceof Array) {
                if (!this[privateKey]) {
                    if (value[ISPROXYKEY])
                        this[privateKey] = value;
                    else
                        this[privateKey] = new Proxy(value, {
                            set: (target, key, value, receiver) => {
                                if (Reflect.get(target, key, receiver) !== value)
                                    this.WriteAllObjectRecord();
                                return Reflect.set(target, key, value, receiver);
                            },
                            get: (target, key, receiver) => {
                                if (key === ISPROXYKEY)
                                    return true;
                                //实体先被删除后在触发length = xxx
                                if (key === "splice" || key === "pop" || key === "shift")
                                    this.WriteAllObjectRecord();
                                return Reflect.get(target, key, receiver);
                            }
                        });
                }
                else {
                    let arr = this[privateKey];
                    arr.length = 0;
                    arr.push(...value);
                }
            }
            else {
                let oldv = this[privateKey];
                if (oldv !== value) {
                    this.WriteAllObjectRecord();
                    this[privateKey] = value;
                }
            }
        },
        get: function () {
            return this[privateKey];
        },
        enumerable: true,
        configurable: true
    });
}

/**
 * CAD对象工厂,通过注册 和暴露的创建方法,动态创建对象
 */
class CADFactory {
    constructor() {
        this.objectNameMap = new Map();
    }
    static RegisterObject(C) {
        this.factory.objectNameMap.set(C.name, C);
    }
    static RegisterObjectAlias(C, name) {
        this.factory.objectNameMap.set(name, C);
    }
    static CreateObject(name) {
        let C = this.factory.objectNameMap.get(name);
        if (C)
            return new C();
    }
}
CADFactory.factory = new CADFactory();
//可以通过添加装饰器 在类前面(@Factory),自动注册工厂的序列化
function Factory(target) {
    CADFactory.RegisterObject(target);
}

var RelevancyType;
(function (RelevancyType) {
    RelevancyType[RelevancyType["General"] = 0] = "General";
    RelevancyType[RelevancyType["Soft"] = 1] = "Soft";
    RelevancyType[RelevancyType["Hard"] = 2] = "Hard";
})(RelevancyType || (RelevancyType = {}));
/*
CADObject对象拥有Id属性,用来记录引用关系.
通过id可以得到对应的关联实体,或者记录实体的关联关系.

ObjectId必须使用 Database分配(db里面会存id的列表,以便同时更新id指向实体)

*/
class ObjectId {
    constructor(index = 0, obj) {
        this.index = index;
        this.obj = obj;
        this._RelevancyType = RelevancyType.General;
    }
    get IsErase() {
        return !this.obj || this.obj.IsErase;
    }
    set Object(obj) {
        this.obj = obj;
    }
    get Object() {
        return this.obj;
    }
    get Index() {
        return this.index;
    }
    set Index(index) {
        this.index = index;
    }
}

/**
 * CAD文件数据
 */
class CADFiler {
    constructor(_datas = []) {
        this._datas = _datas;
        this.readIndex = 0;
    }
    Destroy() {
        delete this._datas;
        delete this.readIndex;
    }
    get Data() {
        return this._datas;
    }
    set Data(data) {
        this._datas = data;
        this.Reset();
    }
    Clear() {
        this._datas.length = 0;
        return this.Reset();
    }
    Reset() {
        this.readIndex = 0;
        return this;
    }
    WriteString(str) {
        this._datas.push(str);
        return this;
    }
    ReadString() {
        return this._datas[this.readIndex++];
    }
    WriteObject(obj) {
        if (!obj) {
            this.Write("");
            return;
        }
        this.WriteString(obj.constructor.name);
        obj.WriteFile(this);
        return this;
    }
    ReadObject(obj) {
        let className = this.ReadString();
        if (className) {
            if (obj === undefined) {
                obj = CADFactory.CreateObject(className);
                if (this.database !== undefined && obj instanceof CADObject)
                    obj.SetDefaultDb(this.database);
            }
            obj.ReadFile(this);
            return obj;
        }
    }
    CloneObjects(objects, clonedObjects = []) {
        for (let o of objects)
            this.WriteObject(o);
        let count = objects.length;
        for (let i = 0; i < count; i++) {
            let obj = this.ReadObject();
            if (obj instanceof Entity)
                obj.CloneDrawObject(objects[i]);
            clonedObjects.push(obj);
        }
        return clonedObjects;
    }
    Write(data) {
        if (data instanceof ObjectId)
            this._datas.push(data.Index);
        else
            this._datas.push(data);
        return this;
    }
    Read() {
        return this._datas[this.readIndex++];
    }
    ReadArray(count) {
        let arr = this._datas.slice(this.readIndex, this.readIndex + count);
        this.readIndex += count;
        return arr;
    }
    //------------------------ID序列化------------------------
    /*
     Id关联分为三种情况:
      1.普通关联:关联对象未被拷贝时,关联到空对象.
      2.软关联  :关联对象未被拷贝时,关联到原先的对象.
      3.硬关联  :对象被拷贝时,被关联的对象必须也被拷贝.
    */
    //-------1.普通关联
    WriteObjectId(id) {
        if (id)
            this.Write(id.Index);
        else
            this.Write(0);
        return this;
    }
    ReadObjectId() {
        let index = this.Read();
        if (this.database)
            return this.database.GetObjectId(index, true);
    }
    //-------2.软关联
    WriteSoftObjectId(id) {
        return this.WriteObjectId(id);
    }
    ReadSoftObjectId() {
        return this.ReadObjectId();
    }
    //-------3.硬关联
    WriteHardObjectId(id) {
        return this.WriteObjectId(id);
    }
    ReadHardObjectId() {
        return this.ReadObjectId();
    }
    //序列化
    ToString() {
        return JSON.stringify(this._datas);
    }
    FromString(str) {
        this._datas = JSON.parse(str);
    }
}

/**
 * 保存对象创建或者修改时的所有数据记录
 */
let AllObjectData = class AllObjectData {
    constructor(obj) {
        this.file = new CADFiler();
        if (obj)
            obj.WriteFile(this.file);
    }
    //#region -------------------------File-------------------------
    //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
    //对象从文件中读取数据,初始化自身
    ReadFile(file) {
        let ver = file.Read();
        let data = file.Read();
        this.file.Data = data;
        return this;
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        file.Write(1);
        file.Write(this.file.Data);
        return this;
    }
};
AllObjectData = __decorate([
    Factory
], AllObjectData);

let EraseEntityData = class EraseEntityData {
    constructor(isErase = true) {
        this.isErase = isErase;
    }
    ReadFile(file) {
        this.isErase = file.Read();
        return this;
    }
    WriteFile(file) {
        file.Write(this.isErase);
        return this;
    }
};
EraseEntityData = __decorate([
    Factory
], EraseEntityData);

class CADObject {
    constructor() {
        //-------------------------DB End-------------------------
        // -------------------------isErase-------------------------
        this._isErase = false;
    }
    set Owner(owner) {
        this._Owner = owner;
    }
    get Owner() {
        return this._Owner;
    }
    Destroy() {
        //在效果图同步反应器中，需要知道被删除的实体的id,所以不删除这个属性
        // this.objectId = undefined;
        this._db = undefined;
    }
    //对象被彻底遗弃
    GoodBye() {
        this.Destroy();
        this.Erase(true);
    }
    /**
    * 当实体异步更新绘制实体完成后触发这个函数.
    * Application通过注入的方式得知这个事件,刷新视图显示.
    */
    AsyncUpdated() {
    }
    get Db() {
        return this._db;
    }
    //对象在加入数据库时,必须指定一个源数据库,否则无法读取引用id.
    SetDefaultDb(db) {
        if (!this._db)
            this._db = db;
        else
            console.warn("重复设置默认Database!");
        return this;
    }
    //private 私有的方法,暴露给Db的添加对象,方法使用.
    //只用对象加入到db中,我们才初始化ObjectId.
    //从db池中分配id给自身使用. 除非你创建对象往db里面加,否则不要调用该方法
    SetOwnerDatabase(db) {
        if (!this._db) {
            this._db = db;
            this.objectId = db.AllocateId();
            this.objectId.Object = this;
        }
        else
            console.warn("重复设置源Database!");
        return this;
    }
    /**
     * WblockClone 的时候,id是db分配的,此刻我们只需要设置它的db
     */
    SetDatabase(db) {
        this._db = db;
    }
    get IsErase() {
        return this._isErase;
    }
    Erase(isErase = true) {
        if (isErase === this._isErase)
            return;
        let undoData = this.UndoRecord();
        if (undoData)
            undoData.CreateEraseHistory(this, isErase);
        this._isErase = isErase;
    }
    get Id() {
        return this.objectId;
    }
    // -------------------------id End-------------------------
    // -------------------------File-------------------------
    //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
    //对象从文件中读取数据,初始化自身
    ReadFile(file) {
        let ver = file.Read();
        //write Id;
        let id = file.ReadObjectId();
        if (!this.objectId && id) //避免CopyFrom时错误的修改自身Id
         {
            this.objectId = id;
            id.Object = this;
        }
        this._isErase = file.Read();
        if (ver > 1)
            this.Owner = file.ReadObjectId();
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        file.Write(2);
        file.WriteObjectId(this.objectId);
        file.Write(this._isErase);
        file.WriteObjectId(this.Owner);
    }
    //局部撤销
    ApplyPartialUndo(undoData) {
        if (undoData instanceof AllObjectData) {
            undoData.file.database = this._db;
            undoData.file.Reset();
            this.ReadFile(undoData.file);
        }
        else if (undoData instanceof EraseEntityData) {
            this.Erase(undoData.isErase);
        }
    }
    //撤销所保存的位置
    UndoRecord() {
        if (this._db && this.objectId)
            return this._db.hm.UndoData;
    }
    //写入所有的对象数据  以便还原对象
    WriteAllObjectRecord() {
        let undoData = this.UndoRecord();
        if (undoData) {
            undoData.WriteObjectSnapshoot(this);
            return true;
        }
        return false;
    }
    //复制出一个实体,如果存在关联，则指向原关联实体
    Clone() {
        let newObject = CADFactory.CreateObject(this.constructor.name);
        //备份
        let bakId = this.objectId;
        this.objectId = undefined;
        let file = new CADFiler();
        file.database = this._db;
        this.WriteFile(file);
        file.Reset();
        newObject.ReadFile(file);
        newObject.objectId = undefined;
        newObject._db = undefined;
        this.objectId = bakId;
        return newObject;
    }
    DeepClone(ownerObject, cloneObejct, idMaping = undefined, isPrimary = true) {
        return this;
    }
    //从一个实体拷贝数据,实体类型必须相同.
    CopyFrom(obj) {
        let idBak = this.objectId;
        let ownerBak = this._Owner;
        this.WriteAllObjectRecord();
        let f = new CADFiler();
        obj.WriteFile(f);
        this.ReadFile(f);
        this.objectId = idBak;
        this._Owner = ownerBak;
    }
    //-------------------------File End-------------------------
    //Utils
    /**
     * 配合 `@AutoRecord` 使用
     * 使用这个方法来覆盖AutoRecord的监听行为.
     * 这个行为只能用来监听实体添加和实体修改.
     * 实体删除行为暂时无法监听
     * @param setCallback 设置新的实体到数组时的回调函数
     */
    CreateProxyArray(setCallback) {
        return new Proxy([], {
            set: (target, key, value, receiver) => {
                if (Reflect.get(target, key, receiver) !== value) {
                    this.WriteAllObjectRecord();
                    setCallback(value);
                }
                return Reflect.set(target, key, value, receiver);
            },
            get: (target, key, receiver) => {
                if (key === ISPROXYKEY)
                    return true;
                //实体先被删除后在触发length = xxx
                if (key === "splice" || key === "pop" || key === "shift") {
                    this.WriteAllObjectRecord();
                    setCallback(undefined);
                }
                return Reflect.get(target, key, receiver);
            }
        });
    }
}
__decorate([
    xaop.iaop
], CADObject.prototype, "AsyncUpdated", null);

var Entity_1;
/**
 * Entity 是所有图元的基类,绘制的实体都集成该类.
 */
let Entity = Entity_1 = class Entity extends CADObject {
    constructor() {
        super(...arguments);
        this.IsEmbedEntity = false;
        /**
         * 该实体的只有一个渲染类型,任何渲染类型都一个样
         */
        this.OnlyRenderType = false;
        this._CacheDrawObject = new Map();
        this._Color = 7;
        //自身坐标系
        this._Matrix = new three.Matrix4();
        //模块空间的标系
        this._SpaceOCS = new three.Matrix4();
        this._Visible = true;
        //加工组
        this.ProcessingGroupList = [];
        /**
         * 当AutoUpdate为false时,记录需要更新的标志.
         * 以便延迟更新时找到相应的更新标志.
         */
        this.NeedUpdateFlag = UpdateDraw.None;
        this.AutoUpdate = true;
        //实体绘制更新版本号
        this.__UpdateVersion__ = 0;
        //#endregion
    }
    get SpaceOCS() {
        return this._SpaceOCS.clone();
    }
    get SpaceOCSInv() {
        return new three.Matrix4().getInverse(this._SpaceOCS);
    }
    set SpaceOCS(m) {
        this.WriteAllObjectRecord();
        this._SpaceOCS.copy(m);
    }
    set Material(materialId) {
        this.WriteAllObjectRecord();
        this.materialId = materialId;
        this.Update();
    }
    get Material() {
        return this.materialId;
    }
    set ColorIndex(color) {
        if (color !== this._Color) {
            this.WriteAllObjectRecord();
            this._Color = color;
            this.Update(UpdateDraw.Material);
        }
    }
    get ColorIndex() {
        return this._Color;
    }
    /**
     * 炸开实体
     */
    Explode() { return []; }
    /**
     * 返回对象的包围框.
     */
    get BoundingBox() {
        return new three.Box3();
    }
    /**
     * 返回对象在自身坐标系下的Box
     */
    get BoundingBoxInOCS() {
        let mtxBak = this._Matrix;
        this._Matrix = IdentityMtx4;
        let box = this.BoundingBox;
        this._Matrix = mtxBak;
        return new Box3Ext().copy(box);
    }
    GetBoundingBoxInMtx(mtx) {
        return this.BoundingBoxInOCS.applyMatrix4(this.OCS.premultiply(mtx));
    }
    get BoundingBoxInSpaceCS() {
        return this.GetBoundingBoxInMtx(this.SpaceOCSInv);
    }
    get OCS() {
        return this._Matrix.clone();
    }
    get OCSNoClone() {
        return this._Matrix;
    }
    //直接设置实体的矩阵,谨慎使用该函数,没有更新实体.
    set OCS(mat4) {
        this._Matrix.copy(mat4);
    }
    get Normal() {
        return new three.Vector3().setFromMatrixColumn(this._Matrix, 2);
    }
    get Position() {
        return new three.Vector3().setFromMatrixPosition(this._Matrix);
    }
    set Position(pt) {
        this.WriteAllObjectRecord();
        let moveX = pt.x - this._Matrix.elements[12];
        let moveY = pt.y - this._Matrix.elements[13];
        let moveZ = pt.z - this._Matrix.elements[14];
        this._Matrix.setPosition(pt);
        this._SpaceOCS.elements[12] += moveX;
        this._SpaceOCS.elements[13] += moveY;
        this._SpaceOCS.elements[14] += moveZ;
        this.Update(UpdateDraw.Matrix);
    }
    //Z轴归0
    Z0() {
        this.WriteAllObjectRecord();
        this._Matrix.elements[14] = 0;
        this.Update(UpdateDraw.Matrix);
        return this;
    }
    //坐标系二维化
    MatrixPlanarizere() {
        let z = this._Matrix.elements[10];
        if (equaln(Math.abs(z), 1, 1e-4)) {
            this.WriteAllObjectRecord();
            MatrixPlanarizere(this._Matrix, false);
        }
        return this;
    }
    get OCSInv() {
        return new three.Matrix4().getInverse(this._Matrix);
    }
    /**
    * 与指定实体是否共面.
    */
    IsCoplaneTo(e) {
        return matrixIsCoplane(this._Matrix, e.OCS, 1e-4);
    }
    /**
     * 测试两个实体的包围盒是否相交.
     */
    BoundingBoxIntersectWith(en) {
        let box = this.BoundingBox;
        let box2 = en.BoundingBox;
        return box && box2 && box.intersectsBox(box2);
    }
    //#region Draw
    ClearDraw() {
        if (this._drawObject) {
            DisposeThreeObj(this._drawObject);
            this._drawObject = undefined;
        }
        for (let [, obj] of this._CacheDrawObject)
            DisposeThreeObj(obj);
        this._CacheDrawObject.clear();
        return this;
    }
    ClearDrawOfJig() {
        let jig = this._CacheDrawObject.get(RenderType.Jig);
        if (jig)
            this._CacheDrawObject.delete(RenderType.Jig);
        for (let [type, obj] of this._CacheDrawObject)
            DisposeThreeObj(obj);
        this._CacheDrawObject.clear();
        if (jig)
            this._CacheDrawObject.set(RenderType.Jig, jig);
    }
    get DrawObject() {
        var _a;
        if (this._drawObject)
            return this._drawObject;
        this._drawObject = new three.Object3D();
        if (!this.IsEmbedEntity)
            this._drawObject.userData.Entity = this;
        if (this.IsVisible) {
            let obj = this.GetDrawObjectFromRenderType((_a = this.__CacheRenderType__) !== null && _a !== void 0 ? _a : userConfig.RenderType);
            if (obj)
                this._drawObject.add(obj);
        }
        else
            this._drawObject.visible = false;
        return this._drawObject;
    }
    get JigObject() {
        let obj = this.GetDrawObjectFromRenderType(RenderType.Jig);
        if (obj && !this.IsEmbedEntity)
            obj.userData.Entity = this;
        return obj;
    }
    DestroyJigObject() {
        let obj = this._CacheDrawObject.get(RenderType.Jig);
        if (obj) {
            this._CacheDrawObject.delete(RenderType.Jig);
            DisposeThreeObj(obj);
            if (obj.parent)
                obj.parent.remove(obj);
        }
    }
    UpdateRenderType(type) {
        if ((this.OnlyRenderType && this.DrawObject.children.length > 0) || !this.Visible)
            return;
        Object3DRemoveAll(this.DrawObject);
        let obj = this.GetDrawObjectFromRenderType(type);
        if (obj)
            this.DrawObject.add(obj);
    }
    GetDrawObjectFromRenderType(renderType = RenderType.Wireframe) {
        var _a;
        if (this.OnlyRenderType) {
            if (renderType === RenderType.Jig)
                return;
            renderType = (_a = this.__CacheRenderType__) !== null && _a !== void 0 ? _a : userConfig.RenderType;
        }
        if (this._CacheDrawObject.has(renderType)) {
            return this._CacheDrawObject.get(renderType);
        }
        else {
            let drawObj = this.InitDrawObject(renderType);
            if (drawObj === undefined)
                return;
            //矩阵直接使用指针,因为已经关闭自动更新,所以矩阵不会被Object3D修改.
            drawObj.matrixAutoUpdate = false;
            drawObj.matrix = this._Matrix;
            drawObj.updateMatrixWorld(true);
            drawObj.traverse(UpdateBoundingSphere);
            if (!this.IsEmbedEntity)
                drawObj.userData.Entity = this;
            this._CacheDrawObject.set(renderType, drawObj);
            return drawObj;
        }
    }
    /**
     * 初始化绘制的threejs实体,子类型重载该函数初始化绘制实体.
     */
    InitDrawObject(renderType = RenderType.Wireframe) {
        return undefined;
    }
    /**
     * 当实体数据改变时,绘制的实体必须做出改变.供框架调用
     */
    Update(mode = UpdateDraw.All) {
        this.__UpdateVersion__++;
        this.NeedUpdateFlag |= mode;
        if (this.AutoUpdate)
            this.DeferUpdate();
    }
    //三维实体总是一起生成线框实体和网格实体,这个通知更新,然后统一更新就好了
    //避免重复更新
    UpdateDrawGeometry() { }
    DeferUpdate() {
        let mode = this.NeedUpdateFlag;
        if (mode === 0)
            return;
        if (mode & UpdateDraw.Geometry && this._CacheDrawObject.size > 0)
            this.UpdateDrawGeometry();
        this.UpdateVisible();
        let isJigIng = this._CacheDrawObject.has(RenderType.Jig);
        for (let [type, obj] of this._CacheDrawObject) {
            if (isJigIng && type !== RenderType.Jig)
                continue;
            if (mode & UpdateDraw.Geometry) {
                if (obj.userData.IsClone) {
                    let parent = obj.parent;
                    DisposeThreeObj(obj);
                    this._CacheDrawObject.delete(type);
                    let newObj = this.GetDrawObjectFromRenderType(type);
                    if (parent) {
                        parent.remove(obj);
                        parent.add(newObj);
                    }
                    obj = newObj;
                }
                else
                    this.UpdateDrawObject(type, obj);
            }
            if (mode & UpdateDraw.Material)
                this.UpdateDrawObjectMaterial(type, obj);
            if (mode & UpdateDraw.Matrix || mode & UpdateDraw.Geometry) {
                obj.updateMatrixWorld(true);
                obj.traverse(UpdateBoundingSphere);
            }
        }
        this.NeedUpdateFlag = UpdateDraw.None;
    }
    /**
     * 当实体需要更新时,需要重载该方法,实现实体更新
     */
    UpdateDrawObject(type, en) {
    }
    /**
     * 当实体需要被更新时,更新实体材质
     */
    UpdateDrawObjectMaterial(type, obj, material) {
    }
    get MeshMaterial() {
        if (this.materialId && this.materialId.Object)
            return this.materialId.Object.Material;
        return HostApplicationServices.DefaultMeshMaterial;
    }
    /**
     * 更新实体Jig状态时的材质
     */
    UpdateJigMaterial(color = 8) {
    }
    RestoreJigMaterial() {
        for (let [type, en] of this._CacheDrawObject)
            this.UpdateDrawObjectMaterial(type, en);
    }
    get Visible() {
        return this._Visible;
    }
    set Visible(v) {
        if (v !== this._Visible) {
            this.WriteAllObjectRecord();
            this._Visible = v;
            this.UpdateVisible();
        }
    }
    get IsVisible() {
        return !this._isErase && this._Visible;
    }
    UpdateVisible() {
        var _a;
        if (this._drawObject) {
            this._drawObject.visible = this.IsVisible;
            if (this.IsVisible)
                this.UpdateRenderType((_a = this.__CacheRenderType__) !== null && _a !== void 0 ? _a : userConfig.RenderType);
        }
    }
    //#endregion
    GoodBye() {
        super.GoodBye();
        if (this._drawObject && this._drawObject.parent)
            this._drawObject.parent.remove(this._drawObject);
        this.ClearDraw();
    }
    Erase(isErase = true) {
        if (isErase === this._isErase)
            return;
        this.__UpdateVersion__++;
        super.Erase(isErase);
        this.UpdateVisible();
        this.EraseEvent(isErase);
    }
    EraseEvent(isErase) {
    }
    /**
      * 使用统一的方法设置对象的矩阵.
      * 需要对缩放矩形进行重载.避免对象矩阵不是单位矩阵
      */
    ApplyMatrix(m) {
        this.WriteAllObjectRecord();
        if (equaln(m.getMaxScaleOnAxis(), 1)) {
            let xA = new three.Vector3();
            let yA = new three.Vector3();
            let zA = new three.Vector3();
            m.extractBasis(xA, yA, zA);
            this._Matrix.multiplyMatrices(m, this._Matrix);
            this._SpaceOCS.multiplyMatrices(m, this._SpaceOCS);
            if (!equalv3(xA.clone().cross(yA).normalize(), zA))
                this.ApplyMirrorMatrix(m);
            else
                this.Update(UpdateDraw.Matrix);
        }
        else {
            this.ApplyScaleMatrix(m);
        }
        return this;
    }
    ApplyScaleMatrix(m) {
        return this;
    }
    ApplyMirrorMatrix(m) {
        return this;
    }
    GetGripPoints() {
        return [];
    }
    MoveGripPoints(indexList, vec) {
    }
    /**
     *
     * @param snapMode 捕捉模式(单一)
     * @param pickPoint const
     * @param lastPoint const
     * @param viewXform const 最近点捕捉需要这个变量
     * @returns object snap points
     */
    GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
        return [];
    }
    GetStretchPoints() {
        return [];
    }
    /**
     * 拉伸夹点,用于Stretch命令
     *
     * @param {Array<number>} indexList 拉伸点索引列表.
     * @param {Vector3} vec 移动向量
     * @memberof Entity
     */
    MoveStretchPoints(indexList, vec) {
    }
    IntersectWith(curve, intType) { return; }
    //#region -------------------------File-------------------------
    Clone() {
        let ent = super.Clone();
        ent.Template = undefined;
        ent.CloneDrawObject(this);
        return ent;
    }
    CloneDrawObject(from) {
        for (let [type, obj] of from._CacheDrawObject) {
            let oldUserDaata = obj.userData;
            obj.traverse(o => o.userData = {});
            let newObj = obj.clone();
            obj.userData = oldUserDaata;
            obj.userData.IsClone = true;
            newObj.matrix = this._Matrix;
            newObj.userData = { Entity: this };
            newObj.userData.IsClone = true;
            this._CacheDrawObject.set(type, newObj);
        }
        this.NeedUpdateFlag = UpdateDraw.None;
    }
    get ReadFileIng() {
        return this.__ReadFileIng__ || Entity_1.__ReadFileIng__;
    }
    ReadFile(file) {
        this.__ReadFileIng__ = true;
        this._ReadFile(file);
        this.Update();
        this.__ReadFileIng__ = false;
    }
    //对象从文件中读取数据,初始化自身
    _ReadFile(file) {
        let ver = file.Read();
        super.ReadFile(file);
        this._Color = file.Read();
        this.materialId = file.ReadHardObjectId();
        this._Matrix.fromArray(file.Read());
        if (ver === 2)
            this.Owner = file.ReadObjectId();
        if (ver > 3)
            this.Template = file.ReadObjectId();
        if (ver > 4)
            this.GroupId = file.ReadHardObjectId();
        if (ver > 5)
            this._Visible = file.Read();
        if (ver > 6)
            this._SpaceOCS.fromArray(file.Read());
        if (ver > 7) {
            let count = file.Read();
            this.ProcessingGroupList.length = 0;
            for (let i = 0; i < count; i++)
                this.ProcessingGroupList.push(file.ReadHardObjectId());
        }
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        file.Write(8);
        super.WriteFile(file);
        file.Write(this._Color);
        file.WriteHardObjectId(this.materialId);
        file.Write(this._Matrix.toArray());
        file.WriteObjectId(this.Template);
        file.WriteHardObjectId(this.GroupId);
        file.Write(this._Visible);
        file.Write(this._SpaceOCS.toArray());
        file.Write(this.ProcessingGroupList.length);
        for (let id of this.ProcessingGroupList)
            file.WriteHardObjectId(id);
    }
    //局部撤销
    ApplyPartialUndo(undoData) {
        super.ApplyPartialUndo(undoData);
    }
    CopyFrom(obj) {
        let templateIdBak = this.Template;
        super.CopyFrom(obj);
        this.Update();
        this.Template = templateIdBak;
    }
};
__decorate([
    AutoRecord
], Entity.prototype, "GroupId", void 0);
__decorate([
    AutoRecord
], Entity.prototype, "Template", void 0);
__decorate([
    AutoRecord
], Entity.prototype, "ProcessingGroupList", void 0);
__decorate([
    xaop.iaop
], Entity.prototype, "Update", null);
__decorate([
    xaop.iaop
], Entity.prototype, "EraseEvent", null);
Entity = Entity_1 = __decorate([
    Factory
], Entity);

function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
}
function FixIndex(index, arr) {
    let count = (arr instanceof Array) ? arr.length : arr;
    if (index < 0)
        return count + index;
    else if (index >= count)
        return index - count;
    else
        return index;
}

class Shape2 extends three.Shape {
    getPoints(divisions = 12) {
        divisions = divisions || 12;
        let points = [], last;
        for (let i = 0, curves = this.curves; i < curves.length; i++) {
            let curve = curves[i];
            //@ts-ignore
            let resolution = (curve && curve.isEllipseCurve) ? clamp(curve.getLength() / 20, divisions * 2, 60)
                //@ts-ignore
                : (curve && (curve.isLineCurve || curve.isLineCurve3)) ? 1
                    //@ts-ignore
                    : (curve && curve.isSplineCurve) ? divisions * curve.points.length
                        : divisions;
            let pts = curve.getPoints(resolution);
            for (let j = 0; j < pts.length; j++) {
                let point = pts[j];
                if (last && equalv2(last, point, 1e-4))
                    continue; // ensures no consecutive points are duplicates
                points.push(point);
                last = point;
                if (j === pts.length - 1)
                    point["_mask_"] = true;
            }
        }
        if (this.autoClose
            && points.length > 1
            && !points[points.length - 1].equals(points[0])) {
            points.push(points[0]);
        }
        return points;
    }
    absellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation) {
        let curve = new three.EllipseCurve(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation);
        /*
        if (this.curves.length > 0)
        {
            // if a previous curve is present, attempt to join
            let firstPoint = curve.getPoint(0);
            if (!equalv2(firstPoint, this.currentPoint))
            {
                this.lineTo(firstPoint.x, firstPoint.y);
            }
        }
        */
        this.curves.push(curve);
        let lastPoint = curve.getPoint(1);
        this.currentPoint.copy(lastPoint);
        return this;
    }
}

class Matrix2 {
    constructor() {
        //column-major
        this.el = [1, 0, 0, 1]; //ix iy jx jy   [a c b d]
    }
    set(ix, iy, jx, jy) {
        this.el[0] = ix;
        this.el[1] = iy;
        this.el[2] = jx;
        this.el[3] = jy;
    }
    applyVector(vec) {
        let x = vec.x;
        let y = vec.y;
        let e = this.el;
        vec.x = e[0] * x + e[2] * y;
        vec.y = e[1] * x + e[3] * y;
        return this;
    }
    fromMatrix4(mtx4) {
        this.set(mtx4.elements[0], mtx4.elements[1], mtx4.elements[3], mtx4.elements[4]);
    }
    setRotate(theta) {
        let c = Math.cos(theta);
        let s = Math.sin(theta);
        this.set(c, s, -s, c);
        return this;
    }
    //自我求逆矩阵,返回自身
    invert() {
        //ref:https://www.mathsisfun.com/algebra/matrix-inverse.html
        let [a, c, b, d] = this.el;
        let det = 1 / (a * d - b * c);
        this.set(d * det, -c * det, -b * det, a * det);
        return this;
    }
}

let r = new Matrix2();
function RotateUVs(geo) {
    r.set(0, -1, 1, 0);
    for (let uvs of geo.faceVertexUvs) {
        for (let uv of uvs) {
            for (let v of uv)
                r.applyVector(v);
        }
    }
    geo.uvsNeedUpdate = true;
}

var CreateBoardUtil;
(function (CreateBoardUtil) {
    //解析二维圆弧
    class Arc2d {
        constructor(p1, p2, bul) {
            this._StartPoint = p1.clone();
            this._EndPoint = p2.clone();
            let vec = p2.clone().sub(p1);
            let len = vec.length();
            let an = vec.angle();
            this._Radius = len / Math.sin(2 * Math.atan(bul)) / 2;
            let delDis = bul * len / 2;
            let toDis = this._Radius - delDis;
            an += Math.PI * 0.5;
            this._Center = p1.clone().add(p2);
            this._Center.multiplyScalar(0.5);
            polar(this._Center, an, toDis);
            this._StartAn = p1.clone().sub(this._Center).angle();
            this._EndAn = p2.clone().sub(this._Center).angle();
            if (bul < 0) {
                //一个神奇的特性 它需要这么做
                this._StartAn -= Math.PI;
                this._EndAn -= Math.PI;
            }
        }
    }
    CreateBoardUtil.Arc2d = Arc2d;
    //创建轮廓 通过点表和凸度
    function CreatePath(pts, buls) {
        let shape = new Shape2();
        if (pts.length === 0)
            return shape;
        let firstPt = pts[0];
        shape.moveTo(firstPt.x, firstPt.y);
        for (let i = 0; i < pts.length - 1; i++) {
            let nextPt = pts[i + 1];
            if (equaln(buls[i], 0, 1e-8)) {
                shape.lineTo(nextPt.x, nextPt.y);
            }
            else {
                let pt = pts[i];
                //参考
                //http://www.dorodnic.com/blog/tag/three-js/ 绘制一个齿轮
                //https://www.kirupa.com/html5/drawing_circles_canvas.htm //html5
                let arc2 = new Arc2d(pt, nextPt, buls[i]);
                let cen = arc2._Center;
                shape.absarc(cen.x, cen.y, arc2._Radius, arc2._StartAn, arc2._EndAn, buls[i] < 0);
            }
        }
        return shape;
    }
    CreateBoardUtil.CreatePath = CreatePath;
    //创建板件 暂时这么写
    function createBoard(boardData) {
        var pts = new Array();
        var buls = new Array();
        var boardPts = boardData["Pts"];
        var boardBuls = boardData["Buls"];
        let boardHeight = boardData["H"];
        var boardMat = new three.Matrix4();
        var matInv = new three.Matrix4();
        //InitBoardMat
        {
            var xD = AsVector3(boardData["XVec"]);
            var yD = AsVector3(boardData["YVec"]);
            var ZD = AsVector3(boardData["ZVec"]);
            var pBase = AsVector3(boardData["BasePoint"]).multiplyScalar(0.001);
            boardMat.makeBasis(xD, yD, ZD);
            boardMat.setPosition(pBase);
            matInv.getInverse(boardMat);
        }
        for (let i = 0; i < boardPts.length; i++) {
            var pt = AsVector3(boardPts[i]).multiplyScalar(0.001);
            pt.applyMatrix4(matInv);
            pts.push(new three.Vector2(pt.x, pt.y));
            buls.push(boardBuls[i]);
        }
        var sp = CreatePath(pts, buls);
        var extrudeSettings = {
            steps: 1,
            bevelEnabled: false,
            amount: boardHeight * 0.001
        };
        var ext = new three.ExtrudeGeometry(sp, extrudeSettings);
        ext.translate(0, 0, -boardHeight * 0.001);
        ext.applyMatrix4(boardMat);
        if (boardData["BoardName"] === "地脚线") {
            RotateUVs(ext);
        }
        var mesh = new three.Mesh(ext);
        return mesh;
    }
    CreateBoardUtil.createBoard = createBoard;
})(CreateBoardUtil || (CreateBoardUtil = {}));

/**
 * 删除数组中指定的元素,返回数组本身
 * @param {Array<any>} arr 需要操作的数组
 * @param {*} el 需要移除的元素
 */
function arrayRemoveOnce(arr, el) {
    let index = arr.indexOf(el);
    if (index !== -1)
        arr.splice(index, 1);
    return arr;
}
/**
 * 删除通过函数校验的元素
 * @param {(e: T) => boolean} checkFuntion 校验函数
 */
function arrayRemoveIf(arr, checkFuntion) {
    let j = 0;
    for (let i = 0, l = arr.length; i < l; i++) {
        if (!checkFuntion(arr[i])) {
            arr[j++] = arr[i];
        }
    }
    arr.length = j;
    return arr;
}
function arrayLast(arr) {
    return arr[arr.length - 1];
}
/**
 * 根据数值从小到大排序数组
 * @param {Array<T>} arr
 * @returns {Array<T>} 返回自身
 */
function arraySortByNumber(arr) {
    arr.sort(sortNumberCompart);
    return arr;
}
/**
 * 对排序好的数组进行去重操作
 * @param {(e1, e2) => boolean} [checkFuction] 校验对象相等函数
 * @returns {Array<T>} 返回自身
 */
function arrayRemoveDuplicateBySort(arr, checkFuction = checkEqual) {
    if (arr.length < 2)
        return arr;
    let j = 1;
    for (let i = 1, l = arr.length; i < l; i++)
        if (!checkFuction(arr[j - 1], arr[i]))
            arr[j++] = arr[i];
    arr.length = j;
    return arr;
}
function sortNumberCompart(e1, e2) {
    return e1 - e2;
}
function checkEqual(e1, e2) {
    return e1 === e2;
}
/**
 * 改变数组的值顺序
 * @param arr 需要改变初始值位置的数组
 * @param index  //将index位置以后的值放到起始位置
 */
function changeArrayStartIndex(arr, index) {
    arr.unshift(...arr.splice(index));
    return arr;
}
function equalArray(a, b, checkF = checkEqual) {
    if (a === b)
        return true;
    if (a.length !== b.length)
        return false;
    for (var i = 0; i < a.length; ++i)
        if (!checkF(a[i], b[i]))
            return false;
    return true;
}

function GetGoodShaderSimple(color = new three.Vector3) {
    return {
        uniforms: {
            "SurfaceColor": { value: color }
        },
        vertexShader: require("./GoodchSimple.vs"),
        fragmentShader: require("./GoodchSimple.fs"),
        polygonOffset: true,
        polygonOffsetFactor: 1,
        polygonOffsetUnits: 1
    };
}

const ColorPalette = [
    [255, 0, 0, 255],
    //[255, 255, 255, 255],//----- 0 - ByBlock - White
    [255, 0, 0, 255],
    // [255, 0, 0, 255],    //----- 1 - Red
    [255, 255, 0, 255],
    [0, 255, 0, 255],
    [0, 255, 255, 255],
    [0, 0, 255, 255],
    [255, 0, 255, 255],
    // [255, 0, 0, 255],    //----- 7 - More red Red
    // [255, 0, 0, 255],    //----- 8 - More red Red
    // [255, 0, 0, 255],    //----- 9 - More red Red
    [255, 255, 255, 255],
    [128, 128, 128, 255],
    [192, 192, 192, 255],
    [255, 0, 0, 255],
    [255, 127, 127, 255],
    [165, 0, 0, 255],
    [165, 82, 82, 255],
    [127, 0, 0, 255],
    [127, 63, 63, 255],
    [76, 0, 0, 255],
    [76, 38, 38, 255],
    [38, 0, 0, 255],
    [38, 19, 19, 255],
    [255, 63, 0, 255],
    [255, 159, 127, 255],
    [165, 41, 0, 255],
    [165, 103, 82, 255],
    [127, 31, 0, 255],
    [127, 79, 63, 255],
    [76, 19, 0, 255],
    [76, 47, 38, 255],
    [38, 9, 0, 255],
    [38, 23, 19, 255],
    [255, 127, 0, 255],
    [255, 191, 127, 255],
    [165, 82, 0, 255],
    [165, 124, 82, 255],
    [127, 63, 0, 255],
    [127, 95, 63, 255],
    [76, 38, 0, 255],
    [76, 57, 38, 255],
    [38, 19, 0, 255],
    [38, 28, 19, 255],
    [255, 191, 0, 255],
    [255, 223, 127, 255],
    [165, 124, 0, 255],
    [165, 145, 82, 255],
    [127, 95, 0, 255],
    [127, 111, 63, 255],
    [76, 57, 0, 255],
    [76, 66, 38, 255],
    [38, 28, 0, 255],
    [38, 33, 19, 255],
    [255, 255, 0, 255],
    [255, 255, 127, 255],
    [165, 165, 0, 255],
    [165, 165, 82, 255],
    [127, 127, 0, 255],
    [127, 127, 63, 255],
    [76, 76, 0, 255],
    [76, 76, 38, 255],
    [38, 38, 0, 255],
    [38, 38, 19, 255],
    [191, 255, 0, 255],
    [223, 255, 127, 255],
    [124, 165, 0, 255],
    [145, 165, 82, 255],
    [95, 127, 0, 255],
    [111, 127, 63, 255],
    [57, 76, 0, 255],
    [66, 76, 38, 255],
    [28, 38, 0, 255],
    [33, 38, 19, 255],
    [127, 255, 0, 255],
    [191, 255, 127, 255],
    [82, 165, 0, 255],
    [124, 165, 82, 255],
    [63, 127, 0, 255],
    [95, 127, 63, 255],
    [38, 76, 0, 255],
    [57, 76, 38, 255],
    [19, 38, 0, 255],
    [28, 38, 19, 255],
    [63, 255, 0, 255],
    [159, 255, 127, 255],
    [41, 165, 0, 255],
    [103, 165, 82, 255],
    [31, 127, 0, 255],
    [79, 127, 63, 255],
    [19, 76, 0, 255],
    [47, 76, 38, 255],
    [9, 38, 0, 255],
    [23, 38, 19, 255],
    [0, 255, 0, 255],
    [127, 255, 127, 255],
    [0, 165, 0, 255],
    [82, 165, 82, 255],
    [0, 127, 0, 255],
    [63, 127, 63, 255],
    [0, 76, 0, 255],
    [38, 76, 38, 255],
    [0, 38, 0, 255],
    [19, 38, 19, 255],
    [0, 255, 63, 255],
    [127, 255, 159, 255],
    [0, 165, 41, 255],
    [82, 165, 103, 255],
    [0, 127, 31, 255],
    [63, 127, 79, 255],
    [0, 76, 19, 255],
    [38, 76, 47, 255],
    [0, 38, 9, 255],
    [19, 38, 23, 255],
    [0, 255, 127, 255],
    [127, 255, 191, 255],
    [0, 165, 82, 255],
    [82, 165, 124, 255],
    [0, 127, 63, 255],
    [63, 127, 95, 255],
    [0, 76, 38, 255],
    [38, 76, 57, 255],
    [0, 38, 19, 255],
    [19, 38, 28, 255],
    [0, 255, 191, 255],
    [127, 255, 223, 255],
    [0, 165, 124, 255],
    [82, 165, 145, 255],
    [0, 127, 95, 255],
    [63, 127, 111, 255],
    [0, 76, 57, 255],
    [38, 76, 66, 255],
    [0, 38, 28, 255],
    [19, 38, 33, 255],
    [0, 255, 255, 255],
    [127, 255, 255, 255],
    [0, 165, 165, 255],
    [82, 165, 165, 255],
    [0, 127, 127, 255],
    [63, 127, 127, 255],
    [0, 76, 76, 255],
    [38, 76, 76, 255],
    [0, 38, 38, 255],
    [19, 38, 38, 255],
    [0, 191, 255, 255],
    [127, 223, 255, 255],
    [0, 124, 165, 255],
    [82, 145, 165, 255],
    [0, 95, 127, 255],
    [63, 111, 127, 255],
    [0, 57, 76, 255],
    [38, 66, 76, 255],
    [0, 28, 38, 255],
    [19, 33, 38, 255],
    [0, 127, 255, 255],
    [127, 191, 255, 255],
    [0, 82, 165, 255],
    [82, 124, 165, 255],
    [0, 63, 127, 255],
    [63, 95, 127, 255],
    [0, 38, 76, 255],
    [38, 57, 76, 255],
    [0, 19, 38, 255],
    [19, 28, 38, 255],
    [0, 63, 255, 255],
    [127, 159, 255, 255],
    [0, 41, 165, 255],
    [82, 103, 165, 255],
    [0, 31, 127, 255],
    [63, 79, 127, 255],
    [0, 19, 76, 255],
    [38, 47, 76, 255],
    [0, 9, 38, 255],
    [19, 23, 38, 255],
    [0, 0, 255, 255],
    [127, 127, 255, 255],
    [0, 0, 165, 255],
    [82, 82, 165, 255],
    [0, 0, 127, 255],
    [63, 63, 127, 255],
    [0, 0, 76, 255],
    [38, 38, 76, 255],
    [0, 0, 38, 255],
    [19, 19, 38, 255],
    [63, 0, 255, 255],
    [159, 127, 255, 255],
    [41, 0, 165, 255],
    [103, 82, 165, 255],
    [31, 0, 127, 255],
    [79, 63, 127, 255],
    [19, 0, 76, 255],
    [47, 38, 76, 255],
    [9, 0, 38, 255],
    [23, 19, 38, 255],
    [127, 0, 255, 255],
    [191, 127, 255, 255],
    [82, 0, 165, 255],
    [124, 82, 165, 255],
    [63, 0, 127, 255],
    [95, 63, 127, 255],
    [38, 0, 76, 255],
    [57, 38, 76, 255],
    [19, 0, 38, 255],
    [28, 19, 38, 255],
    [191, 0, 255, 255],
    [223, 127, 255, 255],
    [124, 0, 165, 255],
    [145, 82, 165, 255],
    [95, 0, 127, 255],
    [111, 63, 127, 255],
    [57, 0, 76, 255],
    [66, 38, 76, 255],
    [28, 0, 38, 255],
    [33, 19, 38, 255],
    [255, 0, 255, 255],
    [255, 127, 255, 255],
    [165, 0, 165, 255],
    [165, 82, 165, 255],
    [127, 0, 127, 255],
    [127, 63, 127, 255],
    [76, 0, 76, 255],
    [76, 38, 76, 255],
    [38, 0, 38, 255],
    [38, 19, 38, 255],
    [255, 0, 191, 255],
    [255, 127, 223, 255],
    [165, 0, 124, 255],
    [165, 82, 145, 255],
    [127, 0, 95, 255],
    [127, 63, 111, 255],
    [76, 0, 57, 255],
    [76, 38, 66, 255],
    [38, 0, 28, 255],
    [38, 19, 33, 255],
    [255, 0, 127, 255],
    [255, 127, 191, 255],
    [165, 0, 82, 255],
    [165, 82, 124, 255],
    [127, 0, 63, 255],
    [127, 63, 95, 255],
    [76, 0, 38, 255],
    [76, 38, 57, 255],
    [38, 0, 19, 255],
    [38, 19, 28, 255],
    [255, 0, 63, 255],
    [255, 127, 159, 255],
    [165, 0, 41, 255],
    [165, 82, 103, 255],
    [127, 0, 31, 255],
    [127, 63, 79, 255],
    [76, 0, 19, 255],
    [76, 38, 47, 255],
    [38, 0, 9, 255],
    [38, 19, 23, 255],
    [84, 84, 84, 255],
    [118, 118, 118, 255],
    [152, 152, 152, 255],
    [186, 186, 186, 255],
    [220, 220, 220, 255],
    [255, 255, 255, 255],
    [0, 0, 0, 0] //----- ByLayer - White
];
const LINE_WIDTH = 2;
//颜色材质,对于二维图像来说可能有用,应该不对三维对象使用该材质
class ColorMaterial {
    constructor() { }
    static GetLineMaterial(color) {
        if (this._LineMaterialMap.has(color))
            return this._LineMaterialMap.get(color);
        let mat = new three.LineBasicMaterial({ color: this.GetColor(color) });
        this._LineMaterialMap.set(color, mat);
        return mat;
    }
    static GetBasicMaterial(color) {
        if (this._BasicMaterialMap.has(color))
            return this._BasicMaterialMap.get(color);
        let mtl = new three.MeshBasicMaterial({ color: this.GetColor(color) });
        this._BasicMaterialMap.set(color, mtl);
        return mtl;
    }
    static GetBasicMaterialDoubleSide(color) {
        if (this._BasicDoubleSideMaterialMap.has(color))
            return this._BasicDoubleSideMaterialMap.get(color);
        let mtl = new three.MeshBasicMaterial({ color: this.GetColor(color), side: three.DoubleSide });
        this._BasicDoubleSideMaterialMap.set(color, mtl);
        return mtl;
    }
    static GetConceptualMaterial(color) {
        if (this._ConceptualMaterial.has(color))
            return this._ConceptualMaterial.get(color);
        let shaderParams = GetGoodShaderSimple(new three.Vector3().fromArray(this.GetColor(color).toArray()));
        let mtl = new three.ShaderMaterial(shaderParams);
        this._ConceptualMaterial.set(color, mtl);
        return mtl;
    }
    static GetPrintConceptualMaterial() {
        if (!this._printConceptualMaterial) {
            this._printConceptualMaterial = new three.ShaderMaterial({
                uniforms: {
                    "SurfaceColor": { value: [1.0, 1.0, 1.0] }
                },
                vertexShader: require("../GLSL/GoodchSimple.vs"),
                fragmentShader: require("../GLSL/GoodchSimple2.fs"),
                polygonOffset: true,
                polygonOffsetFactor: 1,
                polygonOffsetUnits: LINE_WIDTH
            });
        }
        return this._printConceptualMaterial;
    }
    static GetBasicMaterialTransparent(color, opacity) {
        let key = `${color},${opacity}`;
        let mat = this._BasicTransparentMaterialMap.get(key);
        if (mat)
            return mat;
        mat = new three.MeshBasicMaterial({ transparent: true, opacity: opacity, side: three.DoubleSide });
        this._BasicTransparentMaterialMap.set(key, mat);
        return mat;
    }
    static GetBasicMaterialTransparent2(color, opacity) {
        let key = `${color},${opacity}`;
        let mat = this._BasicTransparentMaterialMap2.get(key);
        if (mat)
            return mat;
        mat = new three.MeshBasicMaterial({ transparent: true, opacity: opacity });
        this._BasicTransparentMaterialMap2.set(key, mat);
        return mat;
    }
    static GetColor(color) {
        let rgb = ColorPalette[color];
        if (rgb)
            return new three.Color(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255);
    }
}
ColorMaterial._LineMaterialMap = new Map();
ColorMaterial._BasicMaterialMap = new Map();
ColorMaterial._BasicDoubleSideMaterialMap = new Map();
ColorMaterial._ConceptualMaterial = new Map();
ColorMaterial._BasicTransparentMaterialMap = new Map();
ColorMaterial._BasicTransparentMaterialMap2 = new Map();
//橡皮筋材质: 黄色 点划线
ColorMaterial.RubberBandMaterial = new three.LineDashedMaterial({
    color: 0xF0B41E,
    dashSize: 20,
    gapSize: 8,
});
//极轴材质: 绿色 点划线
ColorMaterial.SnapAxisMaterial = new three.LineDashedMaterial({
    color: 0x008B00,
    dashSize: 5,
    gapSize: 5
});
ColorMaterial.PrintLineMatrial = new LineMaterial.LineMaterial({
    color: 0x000000,
    linewidth: LINE_WIDTH / 1000,
    dashed: false
});
ColorMaterial.GrayTransparentMeshMaterial = new three.MeshBasicMaterial({
    color: 0xcccccc,
    transparent: true,
    opacity: 0.3,
});
ColorMaterial.TransparentMeshMaterial = new three.MeshBasicMaterial({
    transparent: true,
    opacity: 0,
});
ColorMaterial.TransparentLineMaterial = new three.MeshBasicMaterial({
    transparent: true,
    opacity: 0,
});

/**
 * OSMODE
 */
var ObjectSnapMode;
(function (ObjectSnapMode) {
    ObjectSnapMode[ObjectSnapMode["None"] = 0] = "None";
    ObjectSnapMode[ObjectSnapMode["End"] = 1] = "End";
    ObjectSnapMode[ObjectSnapMode["Mid"] = 2] = "Mid";
    ObjectSnapMode[ObjectSnapMode["Cen"] = 4] = "Cen";
    ObjectSnapMode[ObjectSnapMode["Node"] = 8] = "Node";
    ObjectSnapMode[ObjectSnapMode["Qua"] = 16] = "Qua";
    ObjectSnapMode[ObjectSnapMode["Int"] = 32] = "Int";
    ObjectSnapMode[ObjectSnapMode["Ins"] = 64] = "Ins";
    ObjectSnapMode[ObjectSnapMode["Per"] = 128] = "Per";
    ObjectSnapMode[ObjectSnapMode["Tan"] = 256] = "Tan";
    ObjectSnapMode[ObjectSnapMode["Nea"] = 512] = "Nea";
    ObjectSnapMode[ObjectSnapMode["NotEntitySnap"] = 1024] = "NotEntitySnap";
    ObjectSnapMode[ObjectSnapMode["App"] = 2048] = "App";
    ObjectSnapMode[ObjectSnapMode["Ext"] = 4096] = "Ext";
    ObjectSnapMode[ObjectSnapMode["Par"] = 8192] = "Par";
    ObjectSnapMode[ObjectSnapMode["Axis"] = 16384] = "Axis";
    ObjectSnapMode[ObjectSnapMode["All"] = 31743] = "All";
})(ObjectSnapMode || (ObjectSnapMode = {}));

var BufferGeometryUtils;
(function (BufferGeometryUtils) {
    function CreateFromPts(pts) {
        return new three.BufferGeometry().setFromPoints(pts);
    }
    BufferGeometryUtils.CreateFromPts = CreateFromPts;
    /**
     * 更新BufferGeometry的顶点
     * @param geo
     * @param pts
     * @returns 当成功时返回true,更新失败时返回false
     */
    function UpdatePts(geo, pts) {
        let bf = geo.getAttribute("position");
        if (bf === undefined)
            geo.setFromPoints(pts);
        else if (bf.count >= pts.length) {
            bf.copyVector3sArray(pts);
            bf.needsUpdate = true;
            geo.drawRange.count = pts.length;
        }
        else
            return false;
        return true;
    }
    BufferGeometryUtils.UpdatePts = UpdatePts;
    let arrowGeometry;
    function ArrowGeometry() {
        if (arrowGeometry)
            return arrowGeometry;
        else {
            let arrowShape = new three.Shape();
            arrowShape.lineTo(-0.5, -1.8);
            arrowShape.lineTo(0.5, -1.8);
            arrowGeometry = new three.ShapeGeometry(arrowShape);
            arrowGeometry.computeBoundingBox();
            return arrowGeometry;
        }
    }
    BufferGeometryUtils.ArrowGeometry = ArrowGeometry;
    function MergeBufferGeometries(geometries, useGroups = false) {
        if (geometries.length === 0)
            return new three.BufferGeometry();
        let isIndexed = geometries[0].index !== null;
        let attributesUsed = new Set(Object.keys(geometries[0].attributes));
        let morphAttributesUsed = new Set(Object.keys(geometries[0].morphAttributes));
        let attributes = {};
        let morphAttributes = {};
        let morphTargetsRelative = geometries[0].morphTargetsRelative;
        let mergedGeometry = new three.BufferGeometry();
        let offset = 0;
        for (let i = 0; i < geometries.length; ++i) {
            let geometry = geometries[i];
            // ensure that all geometries are indexed, or none
            if (isIndexed !== (geometry.index !== null))
                return null;
            // gather attributes, exit early if they're different
            for (let name in geometry.attributes) {
                if (!attributesUsed.has(name))
                    continue;
                if (attributes[name] === undefined)
                    attributes[name] = [];
                attributes[name].push(geometry.attributes[name]);
            }
            // gather morph attributes, exit early if they're different
            if (morphTargetsRelative !== geometry.morphTargetsRelative)
                return null;
            for (let name in geometry.morphAttributes) {
                if (!morphAttributesUsed.has(name))
                    continue;
                if (morphAttributes[name] === undefined)
                    morphAttributes[name] = [];
                morphAttributes[name].push(geometry.morphAttributes[name]);
            }
            // gather .userData
            mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
            mergedGeometry.userData.mergedUserData.push(geometry.userData);
            if (useGroups) {
                let count;
                if (isIndexed) {
                    count = geometry.index.count;
                }
                else if (geometry.attributes.position !== undefined) {
                    count = geometry.attributes.position.count;
                }
                else {
                    return null;
                }
                mergedGeometry.addGroup(offset, count, i);
                offset += count;
            }
        }
        // merge indices
        if (isIndexed) {
            let indexOffset = 0;
            let mergedIndex = [];
            for (let i = 0; i < geometries.length; ++i) {
                let index = geometries[i].index;
                for (let j = 0; j < index.count; ++j) {
                    mergedIndex.push(index.getX(j) + indexOffset);
                }
                indexOffset += geometries[i].attributes.position.count;
            }
            mergedGeometry.setIndex(mergedIndex);
        }
        // merge attributes
        for (let name in attributes) {
            let mergedAttribute = MergeBufferAttributes(attributes[name]);
            if (!mergedAttribute)
                return null;
            mergedGeometry.setAttribute(name, mergedAttribute);
        }
        // merge morph attributes
        for (let name in morphAttributes) {
            let numMorphTargets = morphAttributes[name][0].length;
            if (numMorphTargets === 0)
                break;
            mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
            mergedGeometry.morphAttributes[name] = [];
            for (let i = 0; i < numMorphTargets; ++i) {
                let morphAttributesToMerge = [];
                for (let j = 0; j < morphAttributes[name].length; ++j) {
                    morphAttributesToMerge.push(morphAttributes[name][j][i]);
                }
                let mergedMorphAttribute = MergeBufferAttributes(morphAttributesToMerge);
                if (!mergedMorphAttribute)
                    return null;
                mergedGeometry.morphAttributes[name].push(mergedMorphAttribute);
            }
        }
        return mergedGeometry;
    }
    BufferGeometryUtils.MergeBufferGeometries = MergeBufferGeometries;
    function MergeBufferAttributes(attributes) {
        let TypedArray;
        let itemSize;
        let normalized;
        let arrayLength = 0;
        for (let i = 0; i < attributes.length; ++i) {
            let attribute = attributes[i];
            if (TypedArray === undefined)
                TypedArray = attribute.array.constructor;
            if (TypedArray !== attribute.array.constructor)
                return null;
            if (itemSize === undefined)
                itemSize = attribute.itemSize;
            if (itemSize !== attribute.itemSize)
                return null;
            if (normalized === undefined)
                normalized = attribute.normalized;
            if (normalized !== attribute.normalized)
                return null;
            arrayLength += attribute.array.length;
        }
        let array = new TypedArray(arrayLength);
        let offset = 0;
        for (let i = 0; i < attributes.length; ++i) {
            array.set(attributes[i].array, offset);
            offset += attributes[i].array.length;
        }
        return new three.BufferAttribute(array, itemSize, normalized);
    }
    BufferGeometryUtils.MergeBufferAttributes = MergeBufferAttributes;
})(BufferGeometryUtils || (BufferGeometryUtils = {}));

/**
 * 相交延伸选项.
 *
 * @export
 * @enum {number}
 */
var IntersectOption;
(function (IntersectOption) {
    /**
     * 两者都不延伸
     */
    IntersectOption[IntersectOption["OnBothOperands"] = 0] = "OnBothOperands";
    /**
     * 延伸自身
     */
    IntersectOption[IntersectOption["ExtendThis"] = 1] = "ExtendThis";
    /**
     * 延伸参数
     */
    IntersectOption[IntersectOption["ExtendArg"] = 2] = "ExtendArg";
    /**
     * 延伸两者
     */
    IntersectOption[IntersectOption["ExtendBoth"] = 3] = "ExtendBoth";
})(IntersectOption || (IntersectOption = {}));
//延伸自身还是参数反转
function reverseIntersectOption(intType) {
    if (intType === IntersectOption.ExtendThis)
        intType = IntersectOption.ExtendArg;
    else if (intType === IntersectOption.ExtendArg)
        intType = IntersectOption.ExtendThis;
    return intType;
}
/**
 * 校验相交点是否满足延伸选项
 * 算法会计算无限延伸状态下的曲线交点,调用该方法进行校验返回校验后的点表
 *
 * @param {Vector3[]} intRes 相交点.曲线当作完全状态下的相交点
 * @param {Curve} c1 曲线1 由this参数传入
 * @param {Curve} c2 曲线2 由arg 参数传入
 * @param {Intersect} extType 延伸选项.
 * @returns {Array<Vector3>} 校验完成后的点表
 */
function CheckPointOnCurve(intRes, c1, c2, extType, tolerance = 1e-6) {
    return intRes.filter(r => {
        if (!(extType & IntersectOption.ExtendThis))
            if (!c1.ParamOnCurve(r.thisParam, tolerance))
                return false;
        if (!(extType & IntersectOption.ExtendArg))
            if (!c2.ParamOnCurve(r.argParam, tolerance))
                return false;
        return true;
    });
}
function IntersectCircleAndCircle(cu1, cu2) {
    if (!cu1.IsCoplaneTo(cu2))
        return [];
    let c1OcsInv = cu1.OCSInv;
    let c1Ocs = cu1.OCS;
    let center1 = cu1.Center.applyMatrix4(c1OcsInv);
    let center2 = cu2.Center.applyMatrix4(c1OcsInv);
    let radius1 = cu1.Radius;
    let radius2 = cu2.Radius;
    let pts = [];
    let dist = center2.distanceTo(center1);
    if (dist < Math.abs(radius1 - radius2) - 1e-3
        || dist > (radius1 + radius2 + 1e-3))
        return pts;
    if (equaln(dist, 0, 1e-6))
        return pts;
    let dstsqr = dist * dist;
    let r1sqr = radius1 * radius1;
    let r2sqr = radius2 * radius2;
    let a = (dstsqr - r2sqr + r1sqr) / (2 * dist);
    let h = Math.sqrt(Math.abs(r1sqr - (a * a)));
    let ratio_a = a / dist;
    let ratio_h = h / dist;
    let dx = center2.x - center1.x;
    let dy = center2.y - center1.y;
    let phix = center1.x + (ratio_a * dx);
    let phiy = center1.y + (ratio_a * dy);
    dx *= ratio_h;
    dy *= ratio_h;
    let p1 = new three.Vector3(phix + dy, phiy - dx);
    let p2 = new three.Vector3(phix - dy, phiy + dx);
    p1.applyMatrix4(c1Ocs);
    p2.applyMatrix4(c1Ocs);
    pts.push({
        pt: p1,
        thisParam: cu1.GetParamAtPoint(p1),
        argParam: cu2.GetParamAtPoint(p1),
    });
    if (!equalv3(p1, p2)) //防止点重复
        pts.push({
            pt: p2,
            thisParam: cu1.GetParamAtPoint(p2),
            argParam: cu2.GetParamAtPoint(p2),
        });
    return pts;
}
/**
 * 计算圆与圆弧的交点.
 *
 * @export
 * @param {Circle} circle 圆
 * @param {Arc} arc 圆弧
 * @param {IntersectOption} extType 延伸选项
 * @returns 交点集合
 */
function IntersectCircleAndArc(circle, arc, extType, tolerance = 1e-6) {
    let pts = IntersectCircleAndCircle(circle, arc);
    return CheckPointOnCurve(pts, circle, arc, extType | IntersectOption.ExtendThis, tolerance);
}
/**
 * 计算圆弧与圆弧的交点
 *
 * @export
 * @param {Arc} arc1 圆弧
 * @param {Arc} arc2 圆弧
 * @param {IntersectOption} extType 延伸选项
 * @returns 交点集合
 */
function IntersectArcAndArc(arc1, arc2, extType, tolerance = 1e-6) {
    let pts = IntersectCircleAndCircle(arc1, arc2);
    return CheckPointOnCurve(pts, arc1, arc2, extType, tolerance);
}
function IntersectEllipseAndLine(l, el, extType, tolerance = 1e-6) {
    let pts = IntersectLineAndEllipseFor2D(l, el);
    return CheckPointOnCurve(pts, l, el, extType, tolerance);
}
/**
 * 通用方法:计算直线与圆的交点,默认延伸全部
 *
 * @export
 * @param {Line} line 直线
 * @param {(Circle | Arc)} circle 圆或圆弧
 * @returns 交点集合
 */
function IntersectLineAndCircleOrArc(line, circle) {
    let lineOrg = line.StartPoint;
    let lineDirection = line.EndPoint.sub(lineOrg);
    let dirLen = lineDirection.length();
    if (equaln(dirLen, 0))
        return [];
    lineDirection.divideScalar(dirLen);
    let diff = lineOrg.clone().sub(circle.Center);
    let a0 = diff.dot(diff) - circle.Radius ** 2;
    let a1 = lineDirection.dot(diff);
    let discr = a1 ** 2 - a0;
    if (equaln(discr, 0, 1e-7)) {
        let pt = lineOrg.add(lineDirection.multiplyScalar(-a1));
        return [{
                pt,
                thisParam: -a1 / dirLen,
                argParam: circle.GetParamAtPoint(pt)
            }];
    }
    else if (discr > 0) {
        let root = Math.sqrt(discr);
        let p1 = lineOrg.clone().add(lineDirection.clone().multiplyScalar(-a1 + root));
        let p2 = lineOrg.add(lineDirection.multiplyScalar(-a1 - root));
        return [
            {
                pt: p1,
                thisParam: (-a1 + root) / dirLen,
                argParam: circle.GetParamAtPoint(p1)
            }, {
                pt: p2,
                thisParam: (-a1 - root) / dirLen,
                argParam: circle.GetParamAtPoint(p2)
            }
        ];
    }
    return [];
}
//直线和圆
function IntersectLineAndCircle(line, circle, extType, tolerance = 1e-6) {
    let ptArr = IntersectLineAndCircleOrArc(line, circle);
    return CheckPointOnCurve(ptArr, line, circle, extType | IntersectOption.ExtendArg);
}
//直线和圆弧
function IntersectLineAndArc(line, arc, extType, tolerance = 1e-6) {
    let ptArr = IntersectLineAndCircleOrArc(line, arc);
    return CheckPointOnCurve(ptArr, line, arc, extType, tolerance);
}
function IntersectLAndLFor2D2(p1, p2, p3, p4) {
    let dx1 = p1.x - p2.x;
    let dx2 = p3.x - p4.x;
    let dx3 = p4.x - p2.x;
    let dy1 = p1.y - p2.y;
    let dy2 = p3.y - p4.y;
    let dy3 = p4.y - p2.y;
    let det = (dx2 * dy1) - (dy2 * dx1);
    if (equaln(det, 0.0, 1e-5)) {
        if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))
            return [p1, p2, p3, p4];
        return [];
    }
    let pt = new three.Vector3;
    let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;
    pt.x = (ratio * dx2) + p4.x;
    pt.y = (ratio * dy2) + p4.y;
    return [pt];
}
/**
 * 三维中两行之间最短的直线
 * ref:https://stackoverflow.com/questions/2316490/the-algorithm-to-find-the-point-of-intersection-of-two-3d-line-segment
 * ref:http://paulbourke.net/geometry/pointlineplane/
 * ref:http://paulbourke.net/geometry/pointlineplane/calclineline.cs
 *
 * @export
 * @param {Vector3} p1 l1.start
 * @param {Vector3} p2 l1.end
 * @param {Vector3} p3 l2.start
 * @param {Vector3} p4 l2.end
 * @returns 交点集合
 */
function ShortestLine3AndLine3(p1, p2, p3, p4, epsilon = 1e-6) {
    let p43 = p4.clone().sub(p3);
    if (p43.lengthSq() < epsilon)
        return;
    let p21 = p2.clone().sub(p1);
    if (p21.lengthSq() < epsilon)
        return;
    let p13 = p1.clone().sub(p3);
    let d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z;
    let d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z;
    let d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z;
    let d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z;
    let d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z;
    let denom = d2121 * d4343 - d4321 * d4321;
    if (Math.abs(denom) < epsilon)
        return;
    let numer = d1343 * d4321 - d1321 * d4343;
    let mua = numer / denom;
    let mub = (d1343 + d4321 * (mua)) / d4343;
    let resultSegmentPoint1 = new three.Vector3();
    resultSegmentPoint1.x = p1.x + mua * p21.x;
    resultSegmentPoint1.y = p1.y + mua * p21.y;
    resultSegmentPoint1.z = p1.z + mua * p21.z;
    let resultSegmentPoint2 = new three.Vector3();
    resultSegmentPoint2.x = p3.x + mub * p43.x;
    resultSegmentPoint2.y = p3.y + mub * p43.y;
    resultSegmentPoint2.z = p3.z + mub * p43.z;
    return [resultSegmentPoint1, resultSegmentPoint2];
}
//直线和直线
function IntersectLineAndLine(l1, l2, extType, fuzz = 1e-4) {
    let [pt1, pt2, pt3, pt4] = [l1.StartPoint, l1.EndPoint, l2.StartPoint, l2.EndPoint];
    let ipts;
    if (equaln(pt1.z, 0, fuzz) && equaln(pt2.z, 0, fuzz) && equaln(pt3.z, 0, fuzz) && equaln(pt4.z, 0, fuzz)) {
        ipts = IntersectLAndLFor2D2(pt1, pt2, pt3, pt4);
        ipts.sort(comparePoint("xy"));
        arrayRemoveDuplicateBySort(ipts, (p1, p2) => equalv3(p1, p2, fuzz));
    }
    else {
        ipts = ShortestLine3AndLine3(pt1, pt2, pt3, pt4);
        if (!ipts)
            return [];
        if (ipts.length === 2)
            ipts.pop();
    }
    let ints = [];
    for (let pt of ipts) {
        let { closestPt: p1, param: param1 } = l1.GetClosestAtPoint(pt, true);
        if (!equalv3(pt, p1, fuzz))
            return [];
        if (!(extType & IntersectOption.ExtendThis))
            if (!(l1.ParamOnCurve(param1, 0) || equalv3(pt1, pt, fuzz) || equalv3(pt2, pt, fuzz)))
                return [];
        let { closestPt: p2, param: param2 } = l2.GetClosestAtPoint(pt, true);
        if (!equalv3(pt, p2, fuzz))
            return [];
        if (!(extType & IntersectOption.ExtendArg))
            if (!(l2.ParamOnCurve(param2, 0) || equalv3(pt3, pt, fuzz) || equalv3(pt4, pt, fuzz)))
                return [];
        ints.push({ pt, thisParam: param1, argParam: param2 });
    }
    return ints;
}
function IntersectPolylineAndCurve(pl, cu, extType, tolerance = 1e-6) {
    let cus = pl.Explode();
    let cus2;
    if (cu instanceof exports.Polyline)
        cus2 = cu.Explode();
    else
        cus2 = [cu];
    let intRes = [];
    for (let i = 0; i < cus.length; i++) {
        let cu1 = cus[i];
        for (let j = 0; j < cus2.length; j++) {
            let cu2 = cus2[j];
            let ext = extType;
            let isStart = i === 0;
            let isEnd = i === cus.length - 1;
            let isStart2 = j === 0;
            let isEnd2 = j === cus2.length - 1;
            //当曲线闭合时,或者当前的子曲线不是起始和不是结束,那么不延伸曲线.
            if (pl.CloseMark || !(isStart || isEnd))
                ext = ext & ~IntersectOption.ExtendThis;
            if ((cu instanceof exports.Polyline && cu.CloseMark) || !(isStart2 || isEnd2))
                ext = ext & ~IntersectOption.ExtendArg;
            let ptPars = cu1.IntersectWith2(cu2, ext, tolerance).filter(r1 => intRes.every(r2 => !equalv3(r1.pt, r2.pt)));
            //校验延伸
            if (IntersectOption.ExtendThis & ext) {
                //如果曲线是起始又是结束,那么不校验.
                if (isStart && isEnd) ;
                else if (isStart) {
                    ptPars = ptPars.filter(res => res.thisParam <= 1);
                }
                else if (isEnd) {
                    ptPars = ptPars.filter(res => res.thisParam >= 0);
                }
            }
            if (IntersectOption.ExtendArg & ext) {
                //如果曲线是起始又是结束,那么不校验.
                if (isStart2 && isEnd2) ;
                else if (isStart2) {
                    ptPars = ptPars.filter(res => res.argParam + j <= cu2.EndParam);
                }
                else if (isEnd2) {
                    ptPars = ptPars.filter(res => res.argParam + j >= 0);
                }
            }
            intRes.push(...ptPars.map(r => {
                return {
                    pt: r.pt,
                    thisParam: i + r.thisParam,
                    argParam: j + r.argParam,
                };
            }));
        }
    }
    return intRes;
}
function IntersectLineAndEllipseFor2D(l, el) {
    if (!l.IsCoplaneTo(el))
        return [];
    let mat = new three.Matrix4().makeRotationZ(-el.Rotation).multiply(el.OCSInv);
    let a = el.RadX;
    let b = el.RadY;
    let sp = l.StartPoint.applyMatrix4(mat);
    let ep = l.EndPoint.applyMatrix4(mat);
    let pts = [];
    if (equaln(sp.x, ep.x)) {
        let c = sp.x;
        let j = (b ** 2) * (1 - (c ** 2) / (a ** 2));
        if (equaln(j, 0)) {
            pts = [new three.Vector3(sp.x, 0)];
        }
        else if (j < 0)
            return [];
        else {
            let y1 = Math.sqrt(j);
            let y2 = -Math.sqrt(j);
            pts = [
                new three.Vector3(c, y1),
                new three.Vector3(c, y2)
            ];
        }
    }
    else {
        let k = (sp.y - ep.y) / (sp.x - ep.x);
        let c = sp.y - sp.x * k;
        let j = (2 * a * a * k * c) * (2 * a * a * k * c) - 4 * (b * b + a * a * k * k) * a * a * (c * c - b * b);
        if (equaln(j, 0)) {
            let x1 = -2 * k * c * a * a / (2 * (b * b + a * a * k * k));
            let y1 = k * x1 + c;
            pts = [new three.Vector3(x1, y1)];
        }
        else if (j < 0)
            return [];
        else {
            let x1 = (-2 * k * c * a * a + Math.sqrt(j)) / (2 * (b * b + a * a * k * k));
            let y1 = k * x1 + c;
            let x2 = (-2 * k * c * a * a - Math.sqrt(j)) / (2 * (b * b + a * a * k * k));
            let y2 = k * x2 + c;
            pts = [
                new three.Vector3(x1, y1),
                new three.Vector3(x2, y2)
            ];
        }
    }
    let matInv = new three.Matrix4().getInverse(mat);
    return pts.map(p => {
        let pt = p.applyMatrix4(matInv);
        return {
            pt,
            thisParam: l.GetParamAtPoint(pt),
            argParam: el.GetParamAtPoint(pt)
        };
    });
}
function IntersectEllipseAndCircleOrArc(el, cir, type) {
    if (!el.IsCoplaneTo(cir))
        return [];
    let a = Math.max(el.RadX, el.RadY);
    let dist = el.Center.distanceTo(cir.Center);
    let disVail = dist > (a + cir.Radius);
    if (disVail)
        return [];
    if (equalv3(el.Center, cir.Center)) {
        let a = el.RadX;
        let b = el.RadY;
        let r = cir.Radius;
        let j = ((a * b) ** 2 - (b * r) ** 2) / (a ** 2 - b ** 2);
        let pts = [];
        if (equaln(j, 0) || equaln(j, r ** 2)) {
            if (equaln(j, 0))
                pts = [
                    new three.Vector3(a, 0),
                    new three.Vector3(-a, 0)
                ];
            else
                pts = [
                    new three.Vector3(0, r),
                    new three.Vector3(0, -r)
                ];
        }
        else if (j < 0)
            return [];
        else {
            let y1 = Math.sqrt(j);
            let y2 = -Math.sqrt(j);
            let n = r ** 2 - j;
            let x1 = Math.sqrt(n);
            let x2 = -Math.sqrt(n);
            pts = [
                new three.Vector3(x1, y1),
                new three.Vector3(x1, y2),
                new three.Vector3(x2, y1),
                new three.Vector3(x2, y2),
            ];
        }
        let ro = new three.Matrix4().makeRotationZ(el.Rotation);
        let res = pts.map(p => {
            let pt = p.applyMatrix4(ro).applyMatrix4(el.OCS);
            return {
                pt,
                thisParam: el.GetParamAtPoint(pt),
                argParam: cir.GetParamAtPoint(pt)
            };
        });
        return CheckPointOnCurve(res, el, cir, type);
    }
    else {
        let pts = el.Shape.getPoints(60);
        let lineData = pts.map(p => {
            return { pt: p, bul: 0 };
        });
        let pl = new exports.Polyline(lineData);
        let cirClone = cir.Clone().ApplyMatrix(el.OCSInv);
        if (type === IntersectOption.ExtendBoth)
            type = IntersectOption.ExtendArg;
        else if (type !== IntersectOption.ExtendArg)
            type = IntersectOption.OnBothOperands;
        let intPts = IntersectPolylineAndCurve(pl, cirClone, type);
        intPts.forEach(r => r.pt.applyMatrix4(el.OCS));
        return intPts;
    }
}
function IntersectEllipse(el1, el2, type) {
    if (!el1.IsCoplaneTo(el2))
        return [];
    let isEqul = equalv3(el1.Center, el2.Center)
        && equaln(el1.RadX, el2.RadX)
        && equaln(el1.RadY, el2.RadY)
        && equalv3(el1.StartPoint, el2.StartPoint);
    if (isEqul)
        return [];
    let a1 = Math.max(el1.RadX, el1.RadY);
    let a2 = Math.max(el2.RadX, el2.RadY);
    let dist = el1.Center.distanceToSquared(el2.Center);
    if (dist > (a1 + a2) ** 2) {
        return [];
    }
    if (!el1.BoundingBox.intersectsBox(el2.BoundingBox))
        return [];
    let diffMat = el1.OCSInv.multiply(el2.OCS);
    let pts1 = el1.Shape.getPoints(60);
    let pts2 = el2.Shape.getPoints(60);
    let lineData1 = pts1.map(p => {
        return { pt: p, bul: 0 };
    });
    let lineData2 = pts2.map(p => {
        return { pt: p, bul: 0 };
    });
    let pl1 = new exports.Polyline(lineData1);
    let pl2 = new exports.Polyline(lineData2).ApplyMatrix(diffMat);
    let intPts = pl1.IntersectWith2(pl2, 0);
    intPts.forEach(r => r.pt.applyMatrix4(el1.OCS));
    return intPts;
}

var ExtendType;
(function (ExtendType) {
    /**
     * 前后都不延伸
     */
    ExtendType[ExtendType["None"] = 0] = "None";
    /**
     * 只允许延伸前面
     */
    ExtendType[ExtendType["Front"] = 1] = "Front";
    /**
     * 只允许延伸后面
     */
    ExtendType[ExtendType["Back"] = 2] = "Back";
    /**
     * 前后延伸
     */
    ExtendType[ExtendType["Both"] = 3] = "Both";
})(ExtendType || (ExtendType = {}));
/**
 * 曲线的基类,子类请实现以下方法.
 */
let Curve = class Curve extends Entity {
    constructor() {
        super();
        //------------------绘制相关------------------
        //重载
        this.OnlyRenderType = true;
    }
    get Is2D() {
        return equaln(this._Matrix.elements[14], 0);
    }
    get StartPoint() { return; }
    set StartPoint(v) { return; }
    get StartParam() { return; }
    get EndPoint() { return; }
    set EndPoint(v) { return; }
    /** 曲线中点 */
    get Midpoint() {
        return this.GetPointAtParam(this.MidParam);
    }
    get MidParam() {
        if (this.EndParam === 1)
            return 0.5;
        else
            return this.GetParamAtDist(this.Length * 0.5);
    }
    get EndParam() { return; }
    get Area() { return 0; }
    /**
     *获得曲线的面积,逆时针为正,顺时针为负.
     */
    get Area2() { return 0; }
    get Length() { return 0; }
    get IsClose() { return false; }
    /** 曲线为顺时针 */
    get IsClockWise() { return this.Area2 < 0; }
    GetPointAtParam(param) { return; }
    GetPointAtDistance(distance) { return; }
    GetDistAtParam(param) { return; }
    GetDistAtPoint(pt) { return; }
    GetParamAtPoint(pt) { return; }
    GetParamAtPoint2(pt) { return this.GetParamAtPoint(pt); }
    GetParamAtDist(d) { return; }
    /**
     * 返回曲线在指定位置的一阶导数(在wcs内)
     *
     * @param {(number | Vector3)} param
     * @returns {Vector3}
     * @memberof Curve
     */
    GetFistDeriv(param) { return; }
    GetFistDerivAngle(param) {
        let d = this.GetFistDeriv(param);
        return Math.atan2(d.y, d.x);
    }
    /**
     * 返回切割曲线后的结果.总是从起点开始切割,并且按顺序返回曲线.
     * @param {(number[] | number)} param
     * @returns {Array<Curve>}
     */
    GetSplitCurves(param) { return; }
    //未完善
    GetCurveAtParamRange(startParam, EndParam) { return; }
    GetSplitCurvesByPts(pt) {
        let pts = Array.isArray(pt) ? pt : [pt];
        let pars = pts.map(p => this.GetParamAtPoint(p));
        return this.GetSplitCurves(pars);
    }
    SplitParamSort(param) {
        if (Array.isArray(param)) {
            param = param.filter(p => this.ParamOnCurve(p));
            if (param.length === 0)
                return [];
            param.push(0, this.EndParam);
            arraySortByNumber(param);
            arrayRemoveDuplicateBySort(param, (e1, e2) => equaln(e1, e2, 1e-7));
            return param;
        }
        else if (this.ParamOnCurve(param))
            return [0, param, this.EndParam];
        else
            return [];
    }
    Extend(newParam) { }
    /**
    * 连接曲线到本曲线,如果成功返回true
    * @param {Curve} cu 需要连接的曲线
    * @returns {boolean} 连接成功
    * @memberof Curve
    */
    Join(cu, allowGap = false, tolerance = 1e-4) { return Status.False; }
    //翻转曲线.首尾调换.
    Reverse() { return this; }
    //点在曲线上
    PtOnCurve(pt, fuzz = 1e-6) {
        return equalv3(this.StartPoint, pt, fuzz) || equalv3(this.EndPoint, pt, fuzz) || this.ParamOnCurve(this.GetParamAtPoint(pt));
    }
    //点在曲线中,不在起点或者终点.
    PtOnCurve2(pt) {
        return !(equalv3(this.StartPoint, pt, 1e-6) || equalv3(this.EndPoint, pt, 1e-6)) && this.ParamOnCurve(this.GetParamAtPoint(pt), 0);
    }
    //点在曲线上,已经确定点在曲线的延伸线上
    PtOnCurve3(p, fuzz = 1e-6) {
        return this.PtOnCurve(p, fuzz);
    }
    //参数在曲线上 容差,1e-6
    ParamOnCurve(param, fuzz = 1e-6) { return !isNaN(param) && param >= -fuzz && param <= this.EndParam + fuzz; }
    GetOffsetCurves(offsetDist) { return; }
    GetClosestPointTo(pt, extend) { return; }
    /**
     * 曲线相交点
     */
    IntersectWith(curve, intType, tolerance = 1e-6) {
        return this.IntersectWith2(curve, intType, tolerance).map(r => r.pt);
    }
    /**
     * 曲线相交点和点的参数
     */
    IntersectWith2(curve, intType, tolerance = 1e-6) { return []; }
    /**
     * 拽托点个数
     */
    GetDragPointCount(drag) { return 0; }
    /**
     * 重载:更新实体材质
     */
    UpdateDrawObjectMaterial(type, obj, material) {
        let m = obj;
        m.material = material || ColorMaterial.GetLineMaterial(this._Color);
    }
    UpdateJigMaterial(color = 8) {
        for (let [type, obj] of this._CacheDrawObject) {
            this.UpdateDrawObjectMaterial(type, obj, ColorMaterial.GetLineMaterial(color));
        }
    }
};
Curve = __decorate([
    Factory
], Curve);

var DragPointType;
(function (DragPointType) {
    DragPointType[DragPointType["Grip"] = 0] = "Grip";
    DragPointType[DragPointType["Stretch"] = 1] = "Stretch";
})(DragPointType || (DragPointType = {}));

class PlaneExt extends three.Plane {
    constructor(normal = new three.Vector3(0, 0, 1), constant) {
        super(normal);
        if (typeof constant === "number")
            this.constant = constant;
        else if (constant)
            this.constant = -this.normal.dot(constant);
    }
    intersectLine(line, optionalTarget = new three.Vector3(), extendLine = false) {
        let v1 = new three.Vector3();
        let direction = line.delta(v1);
        let denominator = this.normal.dot(direction);
        if (denominator === 0) {
            // line is coplanar, return origin
            if (this.distanceToPoint(line.start) === 0) {
                return optionalTarget.copy(line.start);
            }
            // Unsure if this is the correct method to handle this case.
            return undefined;
        }
        let t = -(line.start.dot(this.normal) + this.constant) / denominator;
        //If you not extendLine,check intersect point in Line
        if (!extendLine && (t < -1e-6 || t > 1)) {
            return undefined;
        }
        return optionalTarget.copy(direction).multiplyScalar(t).add(line.start);
    }
    intersectRay(ray, optionalTarget, extendLine) {
        // 从射线初始位置
        let line = new three.Line3(ray.origin.clone(), ray.origin.clone().add(ray.direction));
        return this.intersectLine(line, optionalTarget, extendLine);
    }
}

var Line_1;
let Line = Line_1 = class Line extends Curve {
    constructor(sp, ep) {
        super();
        this._StartPoint = sp || new three.Vector3(0, 0, 0);
        this._EndPoint = ep || new three.Vector3(0, 0, 0);
    }
    get Is2D() {
        return super.Is2D && equaln(this._StartPoint.z, 0) && equaln(this._EndPoint.z, 0);
    }
    get Shape() {
        return new three.Shape([AsVector2(this._StartPoint), AsVector2(this._EndPoint)]);
    }
    Z0() {
        this.WriteAllObjectRecord();
        this.StartPoint = this.StartPoint.setZ(0);
        this.EndPoint = this.EndPoint.setZ(0);
        return this;
    }
    ApplyScaleMatrix(m) {
        this.WriteAllObjectRecord();
        this.StartPoint = this.StartPoint.applyMatrix4(m);
        this.EndPoint = this.EndPoint.applyMatrix4(m);
        return this;
    }
    ApplyMirrorMatrix(m) {
        this.WriteAllObjectRecord();
        let sp = this.StartPoint;
        let ep = this.EndPoint;
        reviseMirrorMatrix(this._Matrix);
        this.StartPoint = sp;
        this.EndPoint = ep;
        return this;
    }
    InitDrawObject(renderType = RenderType.Wireframe) {
        let geo = BufferGeometryUtils.CreateFromPts([this._StartPoint, this._EndPoint]);
        if (renderType === RenderType.Print) {
            var geometry = new LineGeometry.LineGeometry();
            geometry.setPositions(geo.attributes.position.array);
            return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
        }
        return new three.Line(geo, ColorMaterial.GetLineMaterial(this.ColorIndex));
    }
    UpdateDrawObject(type, lineObj) {
        BufferGeometryUtils.UpdatePts(lineObj.geometry, [this._StartPoint, this._EndPoint]);
    }
    GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
        switch (snapMode) {
            case ObjectSnapMode.End:
                return [this.StartPoint, this.EndPoint];
            case ObjectSnapMode.Mid:
                return [this.GetPointAtParam(0.5)];
            case ObjectSnapMode.Nea:
                {
                    let derv = this.GetFistDeriv(0).normalize();
                    let viewNormal = new three.Vector3().fromArray(viewXform.elements, 2 * 3);
                    //平行不捕捉
                    if (isParallelTo(viewNormal, derv))
                        return [];
                    let fNormal = new three.Vector3().crossVectors(viewNormal, derv);
                    fNormal.crossVectors(derv, fNormal);
                    let plane = new PlaneExt(fNormal, this.StartPoint);
                    let plocal = plane.intersectLine(new three.Line3(pickPoint, pickPoint.clone().add(viewNormal)), new three.Vector3(), true);
                    let pclosest = this.GetClosestPointTo(plocal, false);
                    return [pclosest];
                }
            case ObjectSnapMode.Ext:
                return [this.GetClosestPointTo(pickPoint, true)];
            case ObjectSnapMode.Per:
                if (lastPoint) {
                    let { closestPt, param } = this.GetClosestAtPoint(lastPoint, true);
                    if (this.ParamOnCurve(param))
                        return [closestPt];
                }
        }
        return [];
    }
    GetGripPoints() {
        return [this.StartPoint, this.GetPointAtParam(0.5), this.EndPoint];
    }
    MoveGripPoints(indexList, vec) {
        this.WriteAllObjectRecord();
        for (let index of indexList) {
            if (index === 0)
                this.StartPoint = this.StartPoint.add(vec);
            else if (index === 2)
                this.EndPoint = this.EndPoint.add(vec);
            else {
                let m = MoveMatrix(vec);
                this.ApplyMatrix(m);
            }
        }
    }
    GetStretchPoints() {
        return [this.StartPoint, this.EndPoint];
    }
    MoveStretchPoints(indexList, vec) {
        this.WriteAllObjectRecord();
        for (let index of indexList) {
            if (index === 0)
                this.StartPoint = this.StartPoint.add(vec);
            else
                this.EndPoint = this.EndPoint.add(vec);
        }
    }
    GetFistDeriv(param) {
        return this.EndPoint.sub(this.StartPoint);
    }
    IntersectWith2(curve, intType, tolerance = 1e-4) {
        if (curve instanceof Line_1) {
            return IntersectLineAndLine(this, curve, intType, tolerance);
        }
        if (curve instanceof Arc) {
            return IntersectLineAndArc(this, curve, intType, tolerance);
        }
        if (curve instanceof Circle) {
            return IntersectLineAndCircle(this, curve, intType, tolerance);
        }
        if (curve instanceof exports.Polyline) {
            return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType), tolerance));
        }
        if (curve instanceof Ellipse)
            return IntersectEllipseAndLine(this, curve, intType, tolerance);
        //其他的尚未实现.
        return [];
    }
    //Param
    GetPointAtParam(param) {
        return this.StartPoint.add(this.GetFistDeriv(0).multiplyScalar(param));
    }
    GetParamAtPoint(pt) {
        let { closestPt, param } = this.GetClosestAtPoint(pt, true);
        if (!equalv3(closestPt, pt, 1e-5))
            return NaN;
        return param;
    }
    GetParamAtDist(d) {
        return d / this.Length;
    }
    GetPointAtDistance(distance) {
        return this.GetPointAtParam(this.GetParamAtDist(distance));
    }
    GetDistAtParam(param) {
        return this.Length * param;
    }
    GetDistAtPoint(pt) {
        return this.GetDistAtParam(this.GetParamAtPoint(pt));
    }
    GetSplitCurves(param) {
        let params = this.SplitParamSort(param);
        let pts = params.map(param => this.GetPointAtParam(param));
        let ret = new Array();
        if (pts.length >= 2) {
            for (let i = 0; i < pts.length - 1; i++) {
                let newLine = this.Clone();
                newLine.StartPoint = pts[i];
                newLine.EndPoint = pts[i + 1];
                ret.push(newLine);
            }
        }
        return ret;
    }
    GetParamAtPoint2(pt) {
        let { param } = this.GetClosestAtPoint(pt, true);
        return param;
    }
    //点在曲线上,已经确定点在曲线的延伸线上
    PtOnCurve3(p, fuzz = 1e-6) {
        let { param } = this.GetClosestAtPoint(p, true);
        return this.ParamOnCurve(param, fuzz);
    }
    GetClosestAtPoint(pt, extend) {
        let sp = this.StartPoint;
        let ep = this.EndPoint;
        if (equalv3(pt, sp, 1e-8))
            return { closestPt: sp, param: 0 };
        else if (equalv3(pt, ep, 1e-8))
            return { closestPt: ep, param: 1 };
        let direction = this.GetFistDeriv(0);
        let length = direction.length();
        if (length === 0) {
            let param = NaN;
            if (equalv3(pt, this.StartPoint, 1e-6))
                param = 0;
            return { closestPt: sp, param: param };
        }
        direction.divideScalar(length);
        let diff = pt.clone().sub(sp);
        let param = direction.dot(diff);
        let closestPt;
        if (extend)
            closestPt = sp.add(direction.multiplyScalar(param));
        else if (param < 0) {
            closestPt = sp;
            param = 0;
        }
        else if (param > length) {
            closestPt = this.EndPoint;
            param = length;
        }
        else
            closestPt = sp.add(direction.multiplyScalar(param));
        return {
            closestPt: closestPt,
            param: param / length
        };
    }
    GetClosestPointTo(pt, extend) {
        return this.GetClosestAtPoint(pt, extend).closestPt;
    }
    Extend(newParam) {
        this.WriteAllObjectRecord();
        if (newParam < this.StartParam) {
            this.StartPoint = this.GetPointAtParam(newParam);
        }
        else if (newParam > this.EndParam) {
            this.EndPoint = this.GetPointAtParam(newParam);
        }
    }
    Join(cu, allowGap = false, tolerance = 1e-5) {
        if (cu instanceof Line_1) {
            //平行
            if (!isParallelTo(this.GetFistDeriv(0).normalize(), cu.GetFistDeriv(0).normalize()))
                return Status.False;
            let sp = cu.StartPoint;
            let { closestPt: cp1, param: param1 } = this.GetClosestAtPoint(sp, true);
            if (!equalv3(sp, cp1, tolerance)) //点在曲线上,允许较低的精度
                return Status.False;
            let ep = cu.EndPoint;
            let { closestPt: cp2, param: param2 } = this.GetClosestAtPoint(ep, true);
            if (!equalv3(ep, cp2, tolerance))
                return Status.False;
            if (param1 > param2) {
                [param1, param2] = [param2, param1];
                [sp, ep] = [ep, sp];
            }
            if (allowGap || Math.max(0, param1) < Math.min(1, param2) + tolerance) {
                if (param1 < 0)
                    this.StartPoint = sp;
                if (param2 > 1)
                    this.EndPoint = ep;
                return Status.True;
            }
        }
        return Status.False;
    }
    Reverse() {
        this.WriteAllObjectRecord();
        [this._StartPoint, this._EndPoint] = [this._EndPoint, this._StartPoint];
        return this;
    }
    GetOffsetCurves(offsetDist) {
        let derv = this.GetFistDeriv(0).normalize().multiplyScalar(offsetDist);
        derv.applyMatrix4(new three.Matrix4().makeRotationAxis(this.Normal, -Math.PI / 2));
        let newLine = this.Clone();
        newLine.StartPoint = this.StartPoint.add(derv);
        newLine.EndPoint = this.EndPoint.add(derv);
        return [newLine];
    }
    get BoundingBox() {
        return new three.Box3().setFromPoints([this.StartPoint, this.EndPoint]);
    }
    get StartParam() {
        return 0;
    }
    get EndParam() {
        return 1;
    }
    //属性
    get Length() { return this._StartPoint.distanceTo(this._EndPoint); }
    //#region -----------------------------File-----------------------------
    //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
    //对象从文件中读取数据,初始化自身
    _ReadFile(file) {
        super._ReadFile(file);
        let ver = file.Read(); //1
        this._StartPoint.fromArray(file.Read());
        this._EndPoint.fromArray(file.Read());
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        super.WriteFile(file);
        file.Write(1); //ver
        file.Write(this._StartPoint.toArray());
        file.Write(this._EndPoint.toArray());
    }
    //#endregion-----------------------------File End-----------------------------
    //#region 属性
    set StartPoint(p) {
        this.WriteAllObjectRecord();
        this._StartPoint.copy(p).applyMatrix4(this.OCSInv);
        this.Update();
    }
    get StartPoint() {
        return this._StartPoint.clone().applyMatrix4(this.OCS);
    }
    get EndPoint() {
        return this._EndPoint.clone().applyMatrix4(this.OCS);
    }
    set EndPoint(p) {
        this.WriteAllObjectRecord();
        this._EndPoint.copy(p).applyMatrix4(this.OCSInv);
        this.Update();
    }
};
Line = Line_1 = __decorate([
    Factory
], Line);

var Ellipse_1;
let Ellipse = Ellipse_1 = class Ellipse extends Curve {
    constructor(center, radX = 1e-3, radY = 1e-3, angle = 0) {
        super();
        this._startAngle = 0;
        this._endAngle = Math.PI * 2;
        center && this._Matrix.setPosition(center);
        this._radX = radX;
        this._radY = radY;
        this._rotate = angle;
    }
    get StartParam() {
        return 0;
    }
    get EndParam() {
        return 1;
    }
    get StartPoint() {
        return this.GetPointAtParam(0);
    }
    get EndPoint() {
        return this.GetPointAtParam(1);
    }
    get Shape() {
        let sp = new three.Shape();
        sp.ellipse(0, 0, this._radX, this._radY, this._startAngle, this._endAngle, false, this._rotate);
        return sp;
    }
    get IsClose() {
        return equaln(this.TotalAngle, Math.PI * 2);
    }
    get Center() {
        return new three.Vector3().setFromMatrixPosition(this._Matrix);
    }
    set Center(v) {
        this.WriteAllObjectRecord();
        this._Matrix.setPosition(v);
        this.Update();
    }
    get RadX() {
        return this._radX;
    }
    set RadX(v) {
        this.WriteAllObjectRecord();
        this._radX = v;
        this.Update();
    }
    get RadY() {
        return this._radY;
    }
    set RadY(v) {
        this.WriteAllObjectRecord();
        this._radY = v;
        this.Update();
    }
    get Rotation() {
        return this._rotate;
    }
    set Rotation(v) {
        this.WriteAllObjectRecord();
        this._rotate = v;
        this.Update();
    }
    get StartAngle() {
        return this._startAngle;
    }
    get EndAngle() {
        return this._startAngle;
    }
    set StartAngle(v) {
        this.WriteAllObjectRecord();
        this._startAngle = v;
        this.Update();
    }
    set EndAngle(v) {
        this.WriteAllObjectRecord();
        this._endAngle = v;
        this.Update();
    }
    get Length() {
        let a = this._radX;
        let b = this._radY;
        return Math.PI * Math.abs(3 * (a + b) - Math.sqrt((3 * a + b) * (a + 3 * b))) * this.TotalAngle / Math.PI * 0.5;
    }
    get Area() {
        let area = Math.PI * this._radX * this._radY;
        let an = this._endAngle - this._startAngle;
        if (an < 0)
            an = Math.PI * 2 + an;
        area *= an / Math.PI * 0.5;
        let area2 = Math.abs(getDeterminantFor2V(AsVector2(this.StartPoint.sub(this.Center)), AsVector2(this.EndPoint.sub(this.Center)))) / 2;
        if (an < Math.PI)
            area -= area2;
        else
            area += area2;
        return area;
    }
    get TotalAngle() {
        let totolAngle = this._endAngle - this._startAngle;
        if (totolAngle < 0)
            totolAngle = Math.PI * 2 + totolAngle;
        return totolAngle;
    }
    get BoundingBox() {
        return new three.Box3().setFromPoints(this.GetGripPoints());
    }
    PtInCurve(pt) {
        let p = rotatePoint(pt.clone().sub(this.Center), -this.Rotation);
        return p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2 < 1;
    }
    PtOnCurve(pt) {
        if (this.PtOnEllipse(pt)) {
            let a = this.GetCircleAngleAtPoint(pt);
            return a <= this.TotalAngle + 1e-6;
        }
        return false;
    }
    PtOnEllipse(pt) {
        let p = rotatePoint(pt.clone().applyMatrix4(this.OCSInv), -this.Rotation);
        return equaln(p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2, 1, 1e-3);
    }
    GetPointAtParam(param) {
        let an = this.TotalAngle * param + this._startAngle;
        if (an > Math.PI)
            an -= 2 * Math.PI;
        let a = this.RadX;
        let b = this.RadY;
        let pt = new three.Vector3(a * Math.cos(an), b * Math.sin(an), 0);
        pt.applyMatrix4(new three.Matrix4().makeRotationZ(this._rotate));
        return pt.applyMatrix4(this.OCS);
    }
    GetParamAtPoint(pt) {
        if (!this.PtOnEllipse(pt)) {
            return NaN;
        }
        let an = this.GetCircleAngleAtPoint(pt);
        let par = an / this.TotalAngle;
        if (this.IsClose || par < 1 + 1e-6)
            return par;
        else {
            let diffPar = Math.PI * 2 / this.TotalAngle - 1;
            if (par - 1 < diffPar / 2)
                return par;
            else
                return par - 1 - diffPar;
        }
    }
    GetPointAtDistance(distance) {
        let param = distance / this.Length;
        return this.GetPointAtParam(param);
    }
    GetDistAtParam(param) {
        return this.Length * param;
    }
    GetDistAtPoint(pt) {
        let param = this.GetParamAtPoint(pt);
        return this.GetDistAtParam(param);
    }
    GetParamAtDist(d) {
        return d / this.Length;
    }
    GetAngleAtParam(par) {
        let pt = this.GetPointAtParam(par).applyMatrix4(this.OCSInv).applyMatrix4(new three.Matrix4().makeRotationZ(-this.Rotation));
        return angle(pt) + this._startAngle;
    }
    GetCircleAngleAtPoint(pt) {
        pt = pt.clone().applyMatrix4(this.OCSInv);
        let an = angle(pt) - this._rotate;
        if (an < 0)
            an = Math.PI * 2 - an;
        if (an > Math.PI * 2)
            an -= Math.PI * 2;
        let dist = pt.length();
        let k = dist * Math.cos(an) / this._radX;
        if (Math.abs(k) > 1)
            k = Math.floor(Math.abs(k)) * Math.sign(k);
        if (Math.abs(an) <= Math.PI)
            an = Math.acos(k);
        else
            an = Math.PI * 2 - Math.acos(k);
        an -= this._startAngle;
        if (an < 0)
            an = Math.PI * 2 + an;
        return an;
    }
    GetFistDeriv(pt) {
        if (typeof pt === "number")
            pt = this.GetPointAtParam(pt);
        else
            pt = pt.clone();
        let refPts = this.GetGripPoints();
        let p = pt.clone().applyMatrix4(this.OCSInv).applyMatrix4(new three.Matrix4().makeRotationZ(-this._rotate));
        let vec = new three.Vector3();
        if (equalv3(pt, refPts[0]))
            vec.set(0, 1, 0);
        else if (equalv3(pt, refPts[1])) {
            vec.set(0, -1, 0);
        }
        else if (p.y > 0) {
            let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);
            vec.set(-1, -k, 0);
        }
        else {
            let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);
            vec.set(1, k, 0);
        }
        vec.applyMatrix4(new three.Matrix4().makeRotationZ(this._rotate));
        return vec.applyMatrix4(new three.Matrix4().extractRotation(this.OCS));
    }
    GetClosestPointTo(p, extend) {
        //参考:https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/
        let ro = new three.Matrix4().makeRotationZ(this._rotate);
        let roInv = new three.Matrix4().getInverse(ro);
        let pt = p.clone().applyMatrix4(this.OCSInv).setZ(0).applyMatrix4(roInv);
        let px = pt.x;
        let py = pt.y;
        let t = angle(pt);
        let a = this._radX;
        let b = this._radY;
        let x, y;
        for (let i = 0; i < 3; i++) {
            x = a * Math.cos(t);
            y = b * Math.sin(t);
            let ex = (a ** 2 - b ** 2) * Math.cos(t) ** 3 / a;
            let ey = (b * b - a * a) * Math.sin(t) ** 3 / b;
            let rx = x - ex;
            let ry = y - ey;
            let qx = px - ex;
            let qy = py - ey;
            let r = Math.sqrt(ry ** 2 + rx ** 2);
            let q = Math.sqrt(qy ** 2 + qx ** 2);
            let dc = r * Math.asin((rx * qy - ry * qx) / (r * q));
            let dt = dc / Math.sqrt(a * a + b * b - x * x - y * y);
            t += dt;
        }
        let retPt = new three.Vector3(x, y).applyMatrix4(ro).applyMatrix4(this.OCS);
        if (this.IsClose || extend) {
            return retPt;
        }
        else if (this.PtOnCurve(retPt)) {
            return retPt;
        }
        else {
            let d1 = p.distanceToSquared(this.StartPoint);
            let d2 = p.distanceToSquared(this.EndPoint);
            return d1 < d2 ? this.StartPoint : this.EndPoint;
        }
    }
    GetOffsetCurves(offsetDist) {
        if ((offsetDist + Math.min(this._radX, this._radY)) > 0) {
            let el = this.Clone();
            el.RadX = this._radX + offsetDist;
            el.RadY = this._radY + offsetDist;
            return [el];
        }
        return [];
    }
    GetSplitCurves(param) {
        let params;
        if (param instanceof Array) {
            params = param.filter(p => this.ParamOnCurve(p));
            params.sort((a1, a2) => a2 - a1); //从大到小
        }
        else
            params = [param];
        //补上最后一个到第一个的弧
        if (this.IsClose)
            params.unshift(arrayLast(params));
        else {
            params.unshift(1);
            params.push(0);
        }
        arrayRemoveDuplicateBySort(params);
        let anglelist = params.map(param => this.TotalAngle * param + this._startAngle);
        let elllist = [];
        for (let i = 0; i < anglelist.length - 1; i++) {
            let sa = anglelist[i];
            let ea = anglelist[i + 1];
            let el = this.Clone();
            if (!equaln(sa, ea, 1e-6)) {
                el.StartAngle = ea;
                el.EndAngle = equaln(sa, 0) ? Math.PI * 2 : sa;
                elllist.push(el);
            }
        }
        return elllist;
    }
    Join(el) {
        if (this.IsClose || el.IsClose || !this.IsCoplaneTo(el) || !equalv3(el.Center, this.Center))
            return Status.False;
        let status = Status.False;
        if (equaln(this._endAngle, this._startAngle)) {
            this.EndAngle = this._endAngle;
            status = Status.True;
        }
        else if (equaln(this._startAngle, el._endAngle)) {
            this.StartAngle = el._startAngle;
            status = Status.True;
        }
        if (status === Status.True && !this.IsClose && equaln(this._startAngle, this._endAngle)) {
            this.StartAngle = 0;
            this.EndAngle = Math.PI * 2;
        }
        return status;
    }
    GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
        switch (snapMode) {
            case ObjectSnapMode.End:
                {
                    let pts = this.GetGripPoints();
                    return pts;
                }
            case ObjectSnapMode.Cen:
                return [this.Center];
            case ObjectSnapMode.Nea:
                {
                    return getArcOrCirNearPts(this, pickPoint, viewXform);
                }
            case ObjectSnapMode.Per:
                if (lastPoint) {
                    if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))
                        return [];
                    return [this.GetClosestPointTo(lastPoint, false)];
                }
            case ObjectSnapMode.Tan:
                {
                    //TODO:过某点获取椭圆全部切点
                    if (lastPoint) {
                        return getTanPtsOnEllipse();
                    }
                }
            default:
                return [];
        }
    }
    IntersectWith2(curve, intType) {
        //TODO:优化椭圆和椭圆,椭圆和圆相交
        if (curve instanceof Line) {
            return SwapParam(IntersectEllipseAndLine(curve, this, reverseIntersectOption(intType)));
        }
        else if (curve instanceof Circle || curve instanceof Arc) {
            return IntersectEllipseAndCircleOrArc(this, curve, intType);
        }
        else if (curve instanceof exports.Polyline) {
            return SwapParam(IntersectPolylineAndCurve(curve, this, intType));
        }
        else if (curve instanceof Ellipse_1) {
            return IntersectEllipse(this, curve);
        }
        else
            return [];
    }
    InitDrawObject(renderType = RenderType.Wireframe) {
        let line = new three.Line(this.UpdateGeometry(), ColorMaterial.GetLineMaterial(this._Color));
        this.UpdateDrawObject(renderType, line);
        return line;
    }
    UpdateDrawObject(type, obj) {
        let geo = obj.geometry;
        this.UpdateGeometry(geo);
    }
    //更新Geometry
    UpdateGeometry(geo) {
        if (!geo)
            geo = new three.BufferGeometry();
        let curve = this.Shape;
        geo.setFromPoints(curve.getPoints(60));
        return geo;
    }
    GetStretchPoints() {
        return this.GetGripPoints();
    }
    GetGripPoints() {
        let tmpMat4 = new three.Matrix4().makeRotationZ(this.Rotation);
        let pts = [
            new three.Vector3(this._radX, 0),
            new three.Vector3(-this._radX, 0),
            new three.Vector3(0, this._radY),
            new three.Vector3(0, -this._radY)
        ].map(p => p.applyMatrix4(tmpMat4).applyMatrix4(this.OCS));
        if (!equaln(0, this._startAngle))
            pts.push(this.StartPoint);
        if (!equaln(0, this._endAngle))
            pts.push(this.EndPoint);
        pts.push(this.Center);
        return pts;
    }
    MoveStretchPoints(indexList, vec) {
        this.ApplyMatrix(MoveMatrix(vec));
    }
    MoveGripPoints(indexList, vec) {
        let pts = this.GetStretchPoints();
        if (indexList.length > 0) {
            let p = pts[indexList[0]].clone();
            p.add(vec);
            if (indexList[0] <= 1)
                this.RadX = p.distanceTo(this.Center);
            else if (indexList[0] <= 3)
                this.RadY = p.distanceTo(this.Center);
            else {
                let p1 = pts[indexList[0]];
                //TODO:跟cad不一致待优化
                if (equalv3(p1, this.StartPoint)) {
                    let v1 = p1.clone().sub(this.Center);
                    let v2 = p.clone().sub(this.Center);
                    let an = angleTo(v1, v2);
                    this.StartAngle = this.StartAngle + an;
                }
                else if (equalv3(p1, this.EndPoint)) {
                    let v1 = p1.clone().sub(this.Center);
                    let v2 = p.clone().sub(this.Center);
                    let an = angleTo(v2, v1);
                    this.EndAngle = this.EndAngle + an;
                }
                else
                    this.Center = p;
            }
        }
    }
    Convert2Polyline(count = 0) {
        const MIN_LEN = 80;
        const par = this.TotalAngle / Math.PI * 0.5;
        if (!count) {
            count = Math.floor(this.Length / par / MIN_LEN);
            count = three.MathUtils.clamp(count, 15, 80);
        }
        count = Math.floor(count * par);
        if ((count & 1) === 0)
            count++;
        let pts = this.Shape.getPoints(count);
        if (this.IsClose)
            pts.pop();
        let pl = Pts2Polyline(pts, this.IsClose);
        pl.ApplyMatrix(this.OCS);
        if (this.IsClose)
            pl.CloseMark = true;
        return pl;
    }
    _ReadFile(file) {
        super._ReadFile(file);
        let ver = file.Read();
        this._radX = file.Read();
        this._radY = file.Read();
        this._rotate = file.Read();
        this._startAngle = file.Read();
        this._endAngle = file.Read();
        this.Update();
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        super.WriteFile(file);
        file.Write(1);
        file.Write(this.RadX);
        file.Write(this.RadY);
        file.Write(this.Rotation);
        file.Write(this._startAngle);
        file.Write(this._endAngle);
    }
};
Ellipse = Ellipse_1 = __decorate([
    Factory
], Ellipse);

var Circle_1;
let circleGeometry;
function GetCircleGeometry() {
    if (!circleGeometry)
        circleGeometry = BufferGeometryUtils.CreateFromPts(new three.EllipseCurve(0, 0, 1, 1, 0, 2 * Math.PI, false, 0).getPoints(360).map(AsVector3));
    return circleGeometry;
}
let Circle = Circle_1 = class Circle extends Curve {
    constructor(center, radius = 1e-6) {
        super();
        center && this._Matrix.setPosition(center);
        this._Radius = radius;
    }
    get Shape() {
        let sp = new Shape2();
        sp.ellipse(0, 0, this._Radius, this._Radius, 0, 2 * Math.PI, false, 0);
        return sp;
    }
    get Center() {
        return new three.Vector3().setFromMatrixPosition(this._Matrix);
    }
    set Center(v) {
        this.WriteAllObjectRecord();
        this._Matrix.setPosition(v);
        this.Update();
    }
    get Radius() {
        return this._Radius;
    }
    set Radius(v) {
        this.WriteAllObjectRecord();
        this._Radius = clamp(v, 1e-9, 1e19);
        this.Update();
    }
    ApplyScaleMatrix(m) {
        this.WriteAllObjectRecord();
        this.Center = this.Center.applyMatrix4(m);
        this.Radius = this.Radius * m.getMaxScaleOnAxis();
        return this;
    }
    ApplyMirrorMatrix(m) {
        this.WriteAllObjectRecord();
        reviseMirrorMatrix(this._Matrix);
        return this;
    }
    //******************** Curve function start*****************//
    get StartPoint() {
        return this.GetPointAtParam(0);
    }
    get StartParam() {
        return 0;
    }
    get EndPoint() {
        return this.GetPointAtParam(0);
    }
    get EndParam() {
        return 1;
    }
    PtInCurve(pt) {
        return pt.distanceToSquared(this.Center) < Math.pow(this.Radius, 2);
    }
    get Area() {
        return Math.PI * this._Radius ** 2;
    }
    get Area2() {
        return Math.PI * this._Radius ** 2;
    }
    get Length() {
        return Math.PI * 2 * this._Radius;
    }
    get IsClose() {
        return true;
    }
    //曲线为顺时针
    get IsClockWise() { return false; }
    GetPointAtParam(param) {
        return polar(new three.Vector3(), param * 2 * Math.PI, this._Radius).applyMatrix4(this._Matrix);
    }
    GetPointAtDistance(distance) {
        let param = distance / (Math.PI * 2 * this._Radius);
        return this.GetPointAtParam(param);
    }
    GetDistAtParam(param) {
        return Math.PI * 2 * this._Radius * param;
    }
    GetDistAtPoint(pt) {
        let param = this.GetParamAtPoint(pt);
        return this.GetDistAtParam(param);
    }
    GetParamAtDist(d) {
        return d / (Math.PI * 2 * this._Radius);
    }
    GetSplitCurves(param) {
        let params;
        if (param instanceof Array) {
            params = param.filter(p => this.ParamOnCurve(p));
            params.sort((a1, a2) => a2 - a1); //从大到小
            arrayRemoveDuplicateBySort(params);
            if (params.length < 2)
                return [];
        }
        else //圆不能被单个参数切割
            return [];
        //补上最后一个到第一个的弧
        params.unshift(arrayLast(params));
        let anglelist = params.map(param => Math.PI * 2 * param);
        let curvelist = new Array();
        for (let i = 0; i < anglelist.length - 1; i++) {
            let sa = anglelist[i];
            let ea = anglelist[i + 1];
            if (!equaln(sa, ea, 1e-6)) {
                let arc = new Arc(new three.Vector3(), this._Radius, ea, sa, false);
                arc.ApplyMatrix(this.OCS);
                curvelist.push(arc);
            }
        }
        return curvelist;
    }
    GetParamAtPoint(pt) {
        if (!this.PtOnCurve(pt))
            return NaN;
        return angle(pt.clone().applyMatrix4(this.OCSInv)) / (Math.PI * 2);
    }
    PtOnCurve(pt) {
        return equaln(pt.distanceToSquared(this.Center), this._Radius * this._Radius, 1e-5);
    }
    GetOffsetCurves(offsetDist) {
        if ((offsetDist + this._Radius) > 0) {
            let circle = this.Clone();
            circle.Radius = this._Radius + offsetDist;
            return [circle];
        }
        return [];
    }
    IntersectWith2(curve, intType) {
        if (curve instanceof Arc) {
            return IntersectCircleAndArc(this, curve, intType);
        }
        if (curve instanceof Line) {
            return SwapParam(IntersectLineAndCircle(curve, this, reverseIntersectOption(intType)));
        }
        if (curve instanceof Circle_1) {
            return IntersectCircleAndCircle(this, curve);
        }
        if (curve instanceof Ellipse) {
            return SwapParam(IntersectEllipseAndCircleOrArc(curve, this, intType));
        }
        if (curve instanceof exports.Polyline)
            return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType)));
        return [];
    }
    //******************** Curve function end*****************//
    get BoundingBox() {
        return new three.Box3().setFromPoints(this.GetGripPoints());
    }
    InitDrawObject(renderType = RenderType.Wireframe) {
        let cirGeo = GetCircleGeometry();
        if (renderType === RenderType.Print) {
            var geometry = new LineGeometry.LineGeometry().setPositions(cirGeo.attributes.position.array);
            geometry.scale(this._Radius, this._Radius, this._Radius);
            return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
        }
        let line = new three.Line(cirGeo, ColorMaterial.GetLineMaterial(this._Color));
        let obj = new three.Object3D().add(line);
        this.UpdateDrawObject(renderType, obj);
        return obj;
    }
    UpdateDrawObject(type, obj) {
        obj.children[0].scale.set(this._Radius, this._Radius, this._Radius);
        obj.children[0].updateMatrix();
    }
    UpdateDrawObjectMaterial(type, obj, material) {
        let m = obj.children[0];
        m.material = material ? material : ColorMaterial.GetLineMaterial(this._Color);
    }
    GetDragPointCount(drag) {
        if (drag === DragPointType.Grip)
            return 5;
        else
            return 1;
    }
    GetGripPoints() {
        let pts = [
            new three.Vector3(),
            new three.Vector3(0, this._Radius),
            new three.Vector3(0, -this._Radius),
            new three.Vector3(-this._Radius, 0),
            new three.Vector3(this._Radius, 0),
        ];
        let ocs = this.OCS;
        pts.forEach(p => p.applyMatrix4(ocs));
        return pts;
    }
    GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
        switch (snapMode) {
            case ObjectSnapMode.Nea:
                {
                    return getArcOrCirNearPts(this, pickPoint, viewXform);
                }
            case ObjectSnapMode.Cen:
                return [this.Center];
            case ObjectSnapMode.Per:
                if (lastPoint) {
                    if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))
                        return [];
                    let l = new Line(this.Center, lastPoint);
                    return l.IntersectWith(this, IntersectOption.ExtendBoth);
                }
            case ObjectSnapMode.Tan:
                let pts = GetTanPtsOnArcOrCircle(this, lastPoint);
                if (pts)
                    return pts;
            case ObjectSnapMode.End:
                {
                    let pts = this.GetGripPoints();
                    pts.shift();
                    return pts;
                }
        }
        return [];
    }
    MoveGripPoints(indexList, vec) {
        let pts = this.GetGripPoints();
        if (indexList.length > 0) {
            let index = indexList[0];
            let p = pts[index];
            if (p) {
                if (index > 0) {
                    p.add(vec);
                    this.Radius = p.distanceTo(this.Center);
                }
                else {
                    this.Center = this.Center.add(vec);
                }
            }
        }
    }
    GetStretchPoints() {
        let pts = [new three.Vector3()];
        let ocs = this.OCS;
        pts.forEach(p => p.applyMatrix4(ocs));
        return pts;
    }
    MoveStretchPoints(indexList, vec) {
        if (indexList.length > 0) {
            let mat = MoveMatrix(vec);
            this.ApplyMatrix(mat);
        }
    }
    GetFistDeriv(pt) {
        if (typeof pt === "number")
            pt = this.GetPointAtParam(pt);
        else
            pt = pt.clone();
        pt.applyMatrix4(this.OCSInv);
        let an = angle(pt) + Math.PI * 0.5;
        return polar(new three.Vector3(), an, 1).applyMatrix4(new three.Matrix4().extractRotation(this.OCS));
    }
    GetClosestPointTo(pt, extend) {
        pt = pt.clone().applyMatrix4(this.OCSInv).setZ(0).applyMatrix4(this.OCS);
        if (equaln(pt.distanceToSquared(this.Center), 0, 1e-10))
            return this.GetPointAtParam(0);
        let l = new Line(this.Center, pt);
        let pts = l.IntersectWith(this, IntersectOption.ExtendBoth);
        pts.sort((p1, p2) => {
            return p1.distanceToSquared(pt) - p2.distanceToSquared(pt);
        });
        return pts[0];
    }
    //#region -------------------------File-------------------------
    //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
    //对象从文件中读取数据,初始化自身
    _ReadFile(file) {
        super._ReadFile(file);
        let ver = file.Read();
        this._Radius = file.Read();
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        super.WriteFile(file);
        file.Write(1);
        file.Write(this._Radius);
    }
};
Circle = Circle_1 = __decorate([
    Factory
], Circle);

var Arc_1;
/**
 * 圆弧实体类
 * 与ACAD不同,这个类加入了时针变量,并且默认构造的圆弧为顺时针圆弧.
 *
 * 关于时针圆弧:
 * 起始圆弧到终止圆弧总是在0-2PI之间.(一个完整的圆).
 * 圆弧的绘制从起始圆弧绘制到终止圆弧. 按照时针绘制.
 * 参考计算圆弧的完整角度方法查看该计算方式.
 */
let Arc = Arc_1 = class Arc extends Curve {
    constructor(center = new three.Vector3(), radius = 0.1, startAngle = 0.1, endAngle = 0, clockwise = true) {
        super();
        /**
         * 曲线为顺时针
         */
        this.m_Clockwise = true;
        this._Matrix.setPosition(center);
        this.m_Radius = radius;
        this.m_StartAngle = clampRad(startAngle);
        this.m_EndAngle = clampRad(endAngle);
        this.m_Clockwise = clockwise;
    }
    get Shape() {
        let sp = new three.Shape();
        sp.absarc(0, 0, this.m_Radius, this.m_StartAngle, this.m_EndAngle, this.m_Clockwise);
        return sp;
    }
    get Center() {
        return this.Position;
    }
    set Center(v) {
        this.Position = v;
    }
    get Normal() {
        return new three.Vector3().setFromMatrixColumn(this._Matrix, 2);
    }
    set Normal(v) {
        this.WriteAllObjectRecord();
        matrixSetVector(this._Matrix, 2, v);
        this.Update();
    }
    get Area() {
        return 0.5 * this.AllAngle * this.Radius * this.Radius;
    }
    //获得曲线的面积,逆时针为正,顺时针为负.
    get Area2() {
        let clockwise = this.m_Clockwise ? -1 : 1;
        return 0.5 * this.AllAngle * this.Radius * this.Radius * clockwise;
    }
    get IsClose() {
        return false;
    }
    get BoundingBox() {
        let pts = [this.StartPoint, this.EndPoint];
        //TODO:考虑三维圆弧.
        let addPts = [
            this.Center.add(new three.Vector3(this.m_Radius, 0)),
            this.Center.add(new three.Vector3(0, this.m_Radius)),
            this.Center.add(new three.Vector3(-this.m_Radius, 0)),
            this.Center.add(new three.Vector3(0, -this.m_Radius)),
        ];
        addPts.forEach(p => {
            if (this.PtOnCurve(p))
                pts.push(p);
        });
        return new three.Box3().setFromPoints(pts);
    }
    get Radius() {
        return this.m_Radius;
    }
    set Radius(v) {
        this.WriteAllObjectRecord();
        this.m_Radius = v <= 0 ? 1e-19 : v;
        this.Update();
    }
    get IsClockWise() {
        return this.m_Clockwise;
    }
    set IsClockWise(v) {
        if (v !== this.m_Clockwise) {
            this.WriteAllObjectRecord();
            this.m_Clockwise = v;
            this.Update();
        }
    }
    get StartAngle() {
        return this.m_StartAngle;
    }
    set StartAngle(v) {
        this.WriteAllObjectRecord();
        this.m_StartAngle = v;
        this.Update();
    }
    get EndAngle() {
        return this.m_EndAngle;
    }
    set EndAngle(v) {
        this.WriteAllObjectRecord();
        this.m_EndAngle = v;
        this.Update();
    }
    //******************** Curve function start*****************//
    get StartPoint() {
        return polar(new three.Vector3(), this.m_StartAngle, this.m_Radius).applyMatrix4(this.OCS);
    }
    set StartPoint(v) {
        let vTemp = v.clone().applyMatrix4(this.OCSInv);
        this.StartAngle = angle(vTemp);
    }
    get EndPoint() {
        return polar(new three.Vector3(), this.m_EndAngle, this.m_Radius).applyMatrix4(this.OCS);
    }
    set EndPoint(v) {
        let vTemp = v.clone().applyMatrix4(this.OCSInv);
        this.EndAngle = angle(vTemp);
    }
    get StartParam() {
        return 0;
    }
    get EndParam() {
        return 1;
    }
    get Length() {
        return this.AllAngle * this.m_Radius;
    }
    GetParamAtPoint2(pt) {
        return this.GetParamAtAngle(this.GetAngleAtPoint(pt));
    }
    //点在曲线上,已经确定点在曲线的延伸线上
    PtOnCurve3(p, fuzz = 1e-6) {
        let param = this.GetParamAtPoint2(p);
        return this.ParamOnCurve(param, fuzz);
    }
    ApplyScaleMatrix(m) {
        this.WriteAllObjectRecord();
        this.Center = this.Center.applyMatrix4(m);
        this.Radius = this.Radius * m.getMaxScaleOnAxis();
        return this;
    }
    ApplyMirrorMatrix(m) {
        this.WriteAllObjectRecord();
        let sp = this.StartPoint;
        let ep = this.EndPoint;
        reviseMirrorMatrix(this._Matrix);
        this.m_Clockwise = !this.m_Clockwise;
        this.StartPoint = sp;
        this.EndPoint = ep;
        return this;
    }
    GetPointAtParam(param) {
        let an = this.GetAngleAtParam(param);
        return polar(new three.Vector3(), an, this.m_Radius).applyMatrix4(this.OCS);
    }
    GetPointAtDistance(distance) {
        let len = this.Length;
        if (len == 0)
            return;
        return this.GetPointAtParam(distance / len);
    }
    GetDistAtParam(param) {
        return Math.abs(param * this.Length);
    }
    GetDistAtPoint(pt) {
        let param = this.GetParamAtPoint(pt);
        return this.GetDistAtParam(param);
    }
    GetParamAtPoint(pt) {
        if (this.m_Radius == 0 ||
            this.AllAngle == 0 ||
            !equaln(pt.distanceTo(this.Center), this.m_Radius, 1e-6))
            return NaN;
        return this.GetParamAtAngle(this.GetAngleAtPoint(pt));
    }
    /**
     * 利用角度计算该角度在圆弧中代表的参数.
     * 如果角度在圆弧内,那么返回0-1
     * 如果角度不在圆弧内,那么尝试返回离圆弧起始或者结束的较近的参数
     *
     * @param {number} an
     * @returns
     * @memberof Arc
     */
    GetParamAtAngle(an) {
        //如果以pt为终点,那么所有的角度为
        let ptAllAn = this.ComputeAnlge(an);
        let allAn = this.AllAngle;
        //减去圆弧角度,剩余角度的一半
        let surplusAngleHalf = Math.PI - allAn / 2;
        if (ptAllAn > allAn + surplusAngleHalf) //返回负数
         {
            return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn;
        }
        else //返回正数
            return ptAllAn / allAn;
    }
    /**
     * Gets param at angle2
     * @param an
     * @param [isStart] true:返回负数，false 返回正数
     * @returns
     */
    GetParamAtAngle2(an, isStart = true) {
        //如果以pt为终点,那么所有的角度为
        let ptAllAn = this.ComputeAnlge(an);
        let allAn = this.AllAngle;
        //减去圆弧角度,剩余角度的一半
        let surplusAngleHalf = Math.PI - allAn / 2;
        if (isStart) //返回负数
         {
            return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn;
        }
        else //返回正数
            return ptAllAn / allAn;
    }
    GetAngleAtPoint(pt) {
        let ptTmp = pt.clone().applyMatrix4(this.OCSInv);
        return angle(ptTmp);
    }
    GetAngleAtParam(param) {
        return clampRad(this.m_StartAngle + param * this.AllAngle * (this.m_Clockwise ? -1 : 1));
    }
    GetSplitCurves(param) {
        let params = this.SplitParamSort(param);
        //角度列表
        let ans = params.map(p => this.GetAngleAtParam(p));
        //返回圆弧表
        let arcs = [];
        for (let i = 0; i < ans.length - 1; i++) {
            let arc = this.Clone();
            arc.StartAngle = ans[i];
            arc.EndAngle = ans[i + 1];
            arcs.push(arc);
        }
        return arcs;
    }
    GetOffsetCurves(offsetDist) {
        if (this.m_Clockwise)
            offsetDist *= -1;
        if ((offsetDist + this.m_Radius) > 0) {
            let arc = this.Clone();
            arc.Radius = offsetDist + this.m_Radius;
            return [arc];
        }
        return [];
    }
    Extend(newParam) {
        this.WriteAllObjectRecord();
        if (newParam < 0) {
            this.m_StartAngle = this.GetAngleAtParam(newParam);
        }
        else if (newParam > 1) {
            this.m_EndAngle = this.GetAngleAtParam(newParam);
        }
        this.Update();
    }
    Join(cu) {
        if (cu instanceof Arc_1) {
            if (equalv3(cu.Center, this.Center) && equaln(cu.m_Radius, this.m_Radius)) {
                this.WriteAllObjectRecord();
                let [sa, ea] = [cu.StartAngle, cu.EndAngle];
                if (cu.m_Clockwise != this.m_Clockwise)
                    [sa, ea] = [ea, sa];
                let allAn = this.AllAngle;
                let saAllan = this.ComputeAnlge(sa);
                let eaAllan = this.ComputeAnlge(ea);
                if (equaln(sa, this.m_StartAngle)) //this起点对起点
                 {
                    if (eaAllan > allAn)
                        this.EndAngle = ea;
                    return Status.True;
                }
                else if (equaln(sa, this.m_EndAngle)) //this终点对起点
                 {
                    if (eaAllan < allAn || equaln(ea, this.m_StartAngle))
                        return Status.ConverToCircle;
                    else
                        this.EndAngle = ea;
                    return Status.True;
                }
                else if (equaln(ea, this.StartAngle)) //this起点对终点
                 {
                    if (saAllan < allAn)
                        return Status.ConverToCircle;
                    else
                        this.StartAngle = sa;
                    return Status.True;
                }
                else if (equaln(ea, this.m_EndAngle)) //this终点对终点
                 {
                    if (saAllan > allAn)
                        this.StartAngle = sa;
                    return Status.True;
                }
                else if (this.ParamOnCurve(this.GetParamAtAngle(sa))) {
                    if (eaAllan < saAllan)
                        return Status.ConverToCircle;
                    else if (eaAllan > allAn)
                        this.EndAngle = ea;
                    return Status.True;
                }
                else if (this.ParamOnCurve(this.GetParamAtAngle(ea))) {
                    this.StartAngle = sa;
                    return Status.True;
                }
                //使用按负方向去计算它的参数
                let saParam;
                if (saAllan > allAn)
                    saParam = (saAllan - Math.PI * 2) / allAn;
                else
                    saParam = saAllan / allAn;
                let eaParam;
                if (eaAllan > saAllan && saAllan > allAn)
                    eaParam = (eaAllan - Math.PI * 2) / allAn;
                else
                    eaParam = eaAllan / allAn;
                let pMin = Math.max(0, saParam);
                let pMax = Math.min(1, eaParam);
                if (pMin <= pMax + 1e-5) {
                    if (saParam < 0)
                        this.StartAngle = sa;
                    if (eaParam > 1)
                        this.EndAngle = ea;
                    return Status.True;
                }
            }
        }
        return Status.False;
    }
    Reverse() {
        this.WriteAllObjectRecord();
        this.m_Clockwise = !this.m_Clockwise;
        [this.m_StartAngle, this.m_EndAngle] = [this.m_EndAngle, this.m_StartAngle];
        return this;
    }
    IntersectWith2(curve, intType, tolerance = 1e-4) {
        if (curve instanceof Arc_1) {
            return IntersectArcAndArc(this, curve, intType);
        }
        if (curve instanceof Line) {
            return SwapParam(IntersectLineAndArc(curve, this, reverseIntersectOption(intType), tolerance));
        }
        if (curve instanceof Circle) {
            return SwapParam(IntersectCircleAndArc(curve, this, reverseIntersectOption(intType), tolerance));
        }
        if (curve instanceof exports.Polyline)
            return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType), tolerance));
        if (curve instanceof Ellipse)
            return SwapParam(IntersectEllipseAndCircleOrArc(curve, this, intType));
        return [];
    }
    /**
     * 计算出圆弧所包含的角度
     *
     * @readonly
     * @type {number}
     * @memberof Arc
     */
    get AllAngle() {
        return this.ComputeAnlge(this.m_EndAngle);
    }
    get Bul() {
        if (equaln(this.AllAngle, Math.PI * 2))
            return 1;
        return Math.tan(this.AllAngle * 0.25) * (this.IsClockWise ? -1 : 1);
    }
    /**
     * 计算所包含的角度
     *
     * @private
     * @param {number} endAngle 结束的角度
     * @returns
     * @memberof Arc
     */
    ComputeAnlge(endAngle) {
        //顺时针
        if (this.m_Clockwise) {
            if (this.m_StartAngle > endAngle)
                return this.StartAngle - endAngle;
            else //越过0点绘制圆弧
                return (Math.PI * 2) - (endAngle - this.m_StartAngle);
        }
        else {
            if (endAngle > this.m_StartAngle)
                return endAngle - this.m_StartAngle;
            else
                return (Math.PI * 2) - (this.m_StartAngle - endAngle);
        }
    }
    /**
     * 解析两点和凸度所构成的圆弧
     *
     * @param {Vector2} p1
     * @param {Vector2} p2
     * @param {number} bul 凸度,在cad中,凸度为 <(四分之一圆心角)的正切值>
     */
    ParseFromBul(p1, p2, bul) {
        if (p1 instanceof three.Vector2)
            p1 = AsVector3(p1);
        if (p2 instanceof three.Vector2)
            p2 = AsVector3(p2);
        let ocsInv = this.OCSInv;
        p1 = p1.clone().applyMatrix4(ocsInv);
        p2 = p2.clone().applyMatrix4(ocsInv);
        //弦向量
        let chordV = p2.clone().sub(p1);
        //弦角度
        let chordAn = angle(chordV);
        //弦长度/2
        let chordLengthHalf = chordV.length() / 2;
        let allAngle = Math.atan(bul) * 4;
        let HalfAngle = allAngle * 0.5;
        //半径
        this.m_Radius = chordLengthHalf / Math.sin(HalfAngle);
        //指向圆心的角度
        let toCenterAn = chordAn + Math.PI * 0.5; //弦角度转90
        //圆心
        let center = midPoint(p1, p2);
        polar(center, toCenterAn, this.m_Radius - (bul * chordLengthHalf));
        this.Center = center.clone().applyMatrix4(this.OCS);
        this.m_Radius = Math.abs(this.m_Radius);
        this.m_StartAngle = angle(p1.clone().sub(center));
        this.m_EndAngle = angle(p2.clone().sub(center));
        this.m_Clockwise = bul < 0;
        return this;
    }
    FromThreePoint(pt1, pt2, pt3) {
        if (!(pt1 && pt2 && pt3))
            return;
        let ocsInv = this.OCSInv;
        pt1 = pt1.clone().applyMatrix4(ocsInv);
        pt2 = pt2.clone().applyMatrix4(ocsInv);
        pt3 = pt3.clone().applyMatrix4(ocsInv);
        let center = getCircleCenter(pt1, pt2, pt3);
        this.Center = center.clone().applyMatrix4(this.OCS);
        //用圆心和其中一个点求距离得到半径：
        this.m_Radius = center.distanceTo(pt1);
        //起始角度 端点角度
        this.m_StartAngle = angle(pt1.clone().sub(center));
        this.m_EndAngle = angle(pt3.clone().sub(center));
        //求出向量p1->p2,p1->p3
        let p1 = pt2.clone().sub(pt1);
        let p2 = pt3.clone().sub(pt1);
        this.m_Clockwise = p1.cross(p2).z < 0;
        return this;
    }
    /**
     * 重载: 初始化绘制实体.
     *
     * @param {RenderType} [renderType=RenderType.Wireframe]
     */
    InitDrawObject(renderType = RenderType.Wireframe) {
        let geo = BufferGeometryUtils.CreateFromPts(this.Shape.getPoints(60).map(AsVector3));
        if (renderType === RenderType.Print) {
            var geometry = new LineGeometry.LineGeometry();
            geometry.setPositions(geo.attributes.position.array);
            return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
        }
        return new three.Line(geo, ColorMaterial.GetLineMaterial(this._Color));
    }
    //更新Geometry
    UpdateGeometry(geo) {
        let pts = this.Shape.getPoints(60).map(AsVector3);
        BufferGeometryUtils.UpdatePts(geo, pts);
    }
    /**
     * 重载:更新绘制的实体
     *
     * @param {RenderType} type
     * @param {Object3D} obj
     * @memberof Arc
     */
    UpdateDrawObject(type, obj) {
        let geo = obj["geometry"];
        this.UpdateGeometry(geo);
    }
    GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
        switch (snapMode) {
            case ObjectSnapMode.End:
                return [this.StartPoint, this.EndPoint];
            case ObjectSnapMode.Mid:
                return [this.GetPointAtParam(0.5)];
            case ObjectSnapMode.Nea:
                return getArcOrCirNearPts(this, pickPoint, viewXform)
                    .filter(p => this.PtOnCurve(p));
            case ObjectSnapMode.Ext:
                return [this.GetClosestPointTo(pickPoint, true)];
            case ObjectSnapMode.Cen:
                return [this.Center];
            case ObjectSnapMode.Per:
                if (lastPoint) {
                    if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))
                        return [];
                    let l = new Line(this.Center, lastPoint);
                    return l.IntersectWith(this, IntersectOption.ExtendBoth).filter(p => this.PtOnCurve(p));
                }
            case ObjectSnapMode.Tan:
                let pts = GetTanPtsOnArcOrCircle(this, lastPoint);
                if (pts)
                    return pts.filter(p => this.PtOnCurve(p));
        }
        return [];
    }
    GetGripPoints() {
        return [
            this.StartPoint,
            this.GetPointAtParam(0.5),
            this.EndPoint,
            this.Center.clone(),
        ];
    }
    MoveGripPoints(indexList, vec) {
        if (indexList.length > 0) {
            this.WriteAllObjectRecord();
            let ptsArr = this.GetGripPoints();
            let index = indexList[0];
            let p = ptsArr[index];
            if (p) {
                p.add(vec);
                if (index > 2)
                    this.Center = this.Center.add(vec);
                else
                    this.FromThreePoint(ptsArr[0], ptsArr[1], ptsArr[2]);
                this.Update();
            }
        }
    }
    GetStretchPoints() {
        return [this.StartPoint, this.EndPoint];
    }
    MoveStretchPoints(indexList, vec) {
        if (indexList.length === 0)
            return;
        this.WriteAllObjectRecord();
        if (indexList.length === 2)
            this.ApplyMatrix(MoveMatrix(vec));
        else
            for (let index of indexList) {
                let pts = [this.StartPoint, this.EndPoint];
                let [sp, ep] = pts;
                let oldChordLengthHalf = sp.distanceTo(ep) * 0.5;
                let arcHeight = oldChordLengthHalf * this.Bul;
                pts[index].add(vec);
                let newChordLengthHalf = sp.distanceTo(ep) * 0.5;
                let newBul = arcHeight / newChordLengthHalf;
                //根据凸度构造新的弧
                this.ParseFromBul(sp, ep, newBul);
                this.Update();
            }
    }
    GetParamAtDist(d) {
        return d / this.Length;
    }
    GetFistDeriv(pt) {
        let an;
        if (typeof pt === "number")
            an = this.GetAngleAtParam(pt);
        else
            an = angle(pt.clone().applyMatrix4(this.OCSInv));
        an += Math.PI * 0.5 * (this.m_Clockwise ? -1 : 1);
        let ocs = new three.Matrix4().extractRotation(this.OCS);
        return polar(new three.Vector3(), an, this.m_Radius).applyMatrix4(ocs);
    }
    GetClosestPointTo(pt, extend) {
        let l = new Line(this.Center, pt);
        let inPts = this.IntersectWith(l, extend ? IntersectOption.ExtendBoth : IntersectOption.ExtendArg);
        if (inPts.length < 2)
            inPts.push(this.StartPoint, this.EndPoint);
        return inPts.reduce((p1, p2) => p1.distanceToSquared(pt) < p2.distanceToSquared(pt) ? p1 : p2);
    }
    //#region -------------------------File-------------------------
    //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
    //对象从文件中读取数据,初始化自身
    _ReadFile(file) {
        super._ReadFile(file);
        let ver = file.Read();
        if (ver === 1) {
            this.Center = new three.Vector3().fromArray(file.Read());
            this.Normal = new three.Vector3().fromArray(file.Read());
        }
        this.m_Radius = file.Read();
        this.m_StartAngle = file.Read();
        this.m_EndAngle = file.Read();
        this.m_Clockwise = file.Read();
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        super.WriteFile(file);
        file.Write(2);
        file.Write(this.m_Radius);
        file.Write(this.m_StartAngle);
        file.Write(this.m_EndAngle);
        file.Write(this.m_Clockwise);
    }
};
Arc = Arc_1 = __decorate([
    Factory
], Arc);

/**
 * 判断点在多段线内外
 * @param pl 多段线
 * @param pt 点
 * @returns 点在多段线内部
 */
function IsPointInPolyLine(pl, pt) {
    let crossings = 0;
    let insLine = new Line(pt, pt.clone().add(new three.Vector3(0, 10, 0)));
    for (let i = 0; i < pl.EndParam; i++) {
        if (equaln(pl.GetBuilgeAt(i), 0, 5e-6)) //直线
         {
            let sp = pl.GetPointAtParam(i);
            let ep = pl.GetPointAtParam(i + 1);
            //点位于线上面
            if (pt.y > Math.max(sp.y, ep.y))
                continue;
            //线垂直Y轴
            let derX = ep.x - sp.x;
            if (equaln(derX, 0, 5e-6))
                continue;
            //起点
            if (equaln(sp.x, pt.x, 5e-6)) {
                if (sp.y > pt.y && derX < 0)
                    crossings++;
                continue;
            }
            //终点
            if (equaln(ep.x, pt.x, 5e-6)) {
                if (ep.y > pt.y && derX > 0)
                    crossings++;
                continue;
            }
            //快速求交,只验证有没有交点
            let [x1, x2] = sp.x > ep.x ? [ep.x, sp.x] : [sp.x, ep.x];
            if (pt.x > x1 && pt.x < x2) {
                let derY = ep.y - sp.y;
                let k = derY / derX;
                if ((pt.x - sp.x) * k + sp.y > pt.y)
                    crossings++;
            }
        }
        else //圆弧
         {
            let arc = pl.GetCurveAtIndex(i);
            let sp = arc.StartPoint;
            let ep = arc.EndPoint;
            //如果相切
            if (equaln(Math.abs(pt.x - arc.Center.x), arc.Radius)) {
                //当点和起点或者终点和点相切时
                if (equaln(sp.x, pt.x) && sp.y > pt.y) {
                    if (ep.x - sp.x < -1e-5)
                        crossings++;
                }
                else if (equaln(ep.x, pt.x) && ep.y > pt.y) {
                    if (ep.x - sp.x > 1e-5)
                        crossings++;
                }
                continue;
            }
            if (equaln(sp.x, pt.x) && sp.y > pt.y) {
                let der = arc.GetFistDeriv(0);
                if (der.x < -1e-5)
                    crossings++;
            }
            if (equaln(ep.x, pt.x) && ep.y > pt.y) {
                let der = arc.GetFistDeriv(1);
                if (der.x > 1e-5)
                    crossings++;
            }
            for (let pti of arc.IntersectWith(insLine, IntersectOption.ExtendArg)) {
                if (pti.y < pt.y || equalv3(sp, pti, 1e-5) || equalv3(ep, pti, 1e-5))
                    continue;
                let der = arc.GetFistDeriv(pti);
                if (!equaln(der.x, 0)) //相切.
                    crossings++;
            }
        }
    }
    return (crossings % 2) === 1;
}

/**
 * 一个简单的计数器实现,本质是使用一个Map来保存元素的个数
 *
 * 例:
 * let count = new Count();
 * count.AddCount("Test", 1);
 * count.GetCount("Test");//现在 Test 的个数为1
 */
class Count {
    constructor() {
        this.m_CountMap = new WeakMap();
    }
    GetCount(obj) {
        let count = this.m_CountMap.get(obj);
        if (!count) {
            this.m_CountMap.set(obj, 0);
            count = 0;
        }
        return count;
    }
    AddCount(obj, add) {
        this.m_CountMap.set(obj, this.GetCount(obj) + add);
    }
}

/**
 * 曲线连接图
 * 所有的顶点和边的关系
 */
class CurveMap {
    constructor(numdimensions = 4, _RemoveSortLine = false, multiplier = 10 ** numdimensions) {
        this.numdimensions = numdimensions;
        this._RemoveSortLine = _RemoveSortLine;
        this.multiplier = multiplier;
        /*
        节点图.
        每个节点对应下一个路口的路线表.
        路口表使用逆时针排序,起始角度使用正x轴.
        */
        this._VerticeMap = new Map();
        this._Vertices = [];
        this._LookupTable = {};
    }
    /**
     * 得到节点图的所有站点列表
     */
    get Stands() {
        return this._Vertices;
    }
    /**
     * @param curve
     * @param [isArc=curve instanceof Arc]
     * @param [removeDuplicate=false]
     * @returns 加入成功?
     */
    AddCurveToMap(curve, isArc = curve instanceof Arc, removeDuplicate = false, parseAngle = false) {
        let sp = curve.StartPoint;
        let ep = curve.EndPoint;
        let startS = this.GetOnlyVertice(sp);
        let endS = this.GetOnlyVertice(ep);
        //在面域分析中,路线指向同一个顶点已经没有意义了
        if (this._RemoveSortLine && startS === endS)
            return false;
        if (removeDuplicate) //删除重复
         {
            let index = startS.routes.findIndex(r => {
                if (r.to === endS && r.curve.constructor.name === curve.constructor.name) {
                    if (isArc)
                        return equalv3(curve.GetPointAtParam(0.5), r.curve.GetPointAtParam(0.5));
                    return true;
                }
            });
            if (index !== -1)
                return false;
        }
        let length = curve.Length;
        curve.TempData = 0;
        let routeS2E = { curve, isReverse: false, length, from: startS, to: endS, s: sp, e: ep };
        let routeE2S = { curve, isReverse: true, length, from: endS, to: startS, e: sp, s: ep };
        if (!isArc && parseAngle) {
            let an = angle(endS.position.clone().sub(startS.position));
            routeS2E.an = an;
            routeE2S.an = clampRad(an + Math.PI);
        }
        startS.routes.push(routeS2E);
        endS.routes.push(routeE2S);
        return true;
    }
    /**
    * 获得唯一的顶点
    */
    GetOnlyVertice(p) {
        let gp = this.GenerateP(p);
        if (this._VerticeMap.has(gp))
            return this._VerticeMap.get(gp);
        let vertice = { position: gp, routes: [] };
        this._VerticeMap.set(p, vertice);
        this._Vertices.push(vertice);
        return vertice;
    }
    /**
     * 生成一个唯一的向量.
     */
    GenerateP(p) {
        let key = "";
        let els = p.toArray();
        for (let n of els) {
            let valueQuantized = Math.round(n * this.multiplier);
            key += valueQuantized + '/';
        }
        if (key in this._LookupTable)
            return this._LookupTable[key];
        let hashparts = els.map((el) => {
            let q0 = Math.floor(el * this.multiplier);
            let q1 = q0 + 1;
            return ['' + q0 + '/', '' + q1 + '/'];
        });
        let numelements = els.length;
        let numhashes = 1 << numelements;
        for (let hashmask = 0; hashmask < numhashes; ++hashmask) {
            let hashmaskShifted = hashmask;
            key = '';
            hashparts.forEach(function (hashpart) {
                key += hashpart[hashmaskShifted & 1];
                hashmaskShifted >>= 1;
            });
            this._LookupTable[key] = p;
        }
        return p;
    }
}

/**
 * 轨道控制的数学类,观察向量和角度的互相转换
 * 当x当抬头或者低头到90度时,触发万向锁.
 */
class Orbit {
    constructor() {
        //抬头低头 正数抬头 负数低头
        this.phi = 0; //Φ
        //身体旋转 0为正右边 逆时针旋转
        this.theta = 0; //θ
    }
    get RoX() {
        return this.phi;
    }
    set RoX(v) {
        this.phi = three.MathUtils.clamp(v, Math.PI * -0.49, Math.PI * 0.49);
    }
    /**
     * 使用旋转角度 计算观察向量
     * @param [outDirection] 引用传入,如果传入,那么就不构造新的向量
     * @returns 返回观察向量
     */
    UpdateDirection(outDirection = new three.Vector3()) {
        outDirection.z = Math.sin(this.phi);
        //归一化专用.
        let d = Math.abs(Math.cos(this.phi));
        outDirection.x = Math.cos(this.theta) * d;
        outDirection.y = Math.sin(this.theta) * d;
        return outDirection;
    }
    /**
     * 使用观察向量,计算旋转角度
     * @param dir 这个向量会被修改成单位向量.
     */
    SetFromDirection(dir) {
        dir.normalize();
        this.phi = Math.asin(dir.z);
        if (equaln(dir.x, 0) && equaln(dir.y, 0))
            if (dir.z > 0)
                this.theta = Math.PI * -0.5;
            else
                this.theta = Math.PI * 0.5;
        else
            this.theta = Math.atan2(dir.y, dir.x);
    }
    /**
     * 参考任意轴坐标系算法.
     * http://help.autodesk.com/view/ACD/2017/CHS/?guid=GUID-E19E5B42-0CC7-4EBA-B29F-5E1D595149EE
     */
    static ComputUpDirection(n, ay = new three.Vector3(), ax = new three.Vector3()) {
        n.normalize();
        if (Math.abs(n.x) < 0.015625 && Math.abs(n.y) < 0.015625)
            ax.crossVectors(YAxis, n);
        else
            ax.crossVectors(ZAxis, n);
        ay.crossVectors(n, ax);
        ax.normalize();
        ay.normalize();
        return ay;
    }
}

/**
面域分析,基于最小循环图重新实现的版本，拓展了实现求最大轮廓。
当最大轮廓=最小轮廓时，只绘制最大轮廓（独立轮廓无分裂）。

算法只实现去重模式,业务场景应该没有非去重模式。
如果需要非去重模式，那么应该获取到多个CurveMap，然后对多个CurveMap进行面域分析，得出多个重叠的面域。
 */
class RegionParse {
    /**
     * @param cuList 请不要传递圆和椭圆.
     * @param [numDimensions=3] 精度:小数点后个数
     * @param [removeDuplicate=true] 删除重复(现在必须是true,请不要修改它)
     */
    constructor(cuList, numDimensions = 3, removeDuplicate = true) {
        this.numDimensions = numDimensions;
        this.removeDuplicate = removeDuplicate;
        //区域列表 通常是外轮廓
        this.RegionsOutline = [];
        //区域列表 通常是内轮廓
        this.RegionsInternal = [];
        //碎线 曲线进入到这里会被炸开.
        this.ExpLineMap = new Map();
        //需要搜索的站
        let vertices = this.GenerateVerticeMap(cuList);
        //移除细丝
        while (true) {
            let v = vertices.find(v => v.routes.length < 2);
            if (v)
                this.RemoveFilamentAt(v, vertices);
            else
                break;
        }
        let lowerVertice;
        while (vertices.length > 0) {
            lowerVertice = (lowerVertice === null || lowerVertice === void 0 ? void 0 : lowerVertice.routes.length) > 1 ? lowerVertice : this.FindLowerLeftStand(vertices);
            let minWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Min);
            let maxWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Max);
            this.RemoveEdge(minWalk[0]);
            this.RemoveFilamentAt(minWalk[0].from, vertices);
            this.RemoveFilamentAt(minWalk[0].to, vertices);
            minWalk = ReduceWalk(minWalk);
            maxWalk = ReduceWalk(maxWalk);
            if (maxWalk.length > 1) {
                this.RegionsOutline.push(maxWalk);
                if (minWalk.length === maxWalk.length && minWalk.every((w1, index) => w1 === maxWalk[index])) //大小重叠
                 {
                    //直接remove,不用计算引用个数
                    for (let w of minWalk) {
                        this.RemoveEdge(w);
                        this.RemoveFilamentAt(w.from, vertices);
                        this.RemoveFilamentAt(w.to, vertices);
                    }
                    continue; //继续循环
                }
                else
                    for (let w of maxWalk)
                        w.curve.TempData = 1;
            }
            if (minWalk.length > 1) // && minWalk.every(w => <number>(w.curve.TempData) < 2)  没有重复线应该不会被用2次
             {
                this.RegionsInternal.push(minWalk);
                for (let w of minWalk) {
                    w.curve.TempData++;
                    if (w.curve.TempData === 2) {
                        this.RemoveEdge(w);
                        this.RemoveFilamentAt(w.from, vertices);
                        this.RemoveFilamentAt(w.to, vertices);
                    }
                }
            }
        }
    }
    RemoveFilamentAt(v, vertices) {
        let current = v;
        while (current && current.routes.length < 2) {
            vertices = arrayRemoveOnce(vertices, current);
            let r = current.routes[0];
            if (r) {
                this.RemoveEdge(r);
                current = r.to;
            }
            else
                current = undefined;
        }
    }
    RemoveEdge(r) {
        let index = r.from.routes.findIndex(rr => rr.curve === r.curve);
        if (index !== -1)
            r.from.routes.splice(index, 1);
        index = r.to.routes.findIndex(rr => rr.curve === r.curve);
        if (index !== -1)
            r.to.routes.splice(index, 1);
    }
    /**
     * 找到最下方并且最左边的站 yx
     */
    FindLowerLeftStand(vertices) {
        return vertices.reduce((m, v) => {
            let dy = v.position.y - m.position.y;
            if (dy < 0)
                return v;
            if (dy > 0)
                return m;
            return v.position.x - m.position.x < 0 ? v : m;
        });
    }
    /**
     * 构造路线图. 每个节点对应下一个路口的路线表. 路口表使用逆时针排序,起始角度使用正x轴.
     * @returns 所有的顶点
     */
    GenerateVerticeMap(curveList) {
        let curveMap = new CurveMap(this.numDimensions, true);
        //将多段线炸开
        let plcus = [];
        arrayRemoveIf(curveList, c => {
            if (c instanceof exports.Polyline) {
                let cus = c.Explode();
                //如果为圆弧,提前打断
                let arcs = [];
                arrayRemoveIf(cus, c => {
                    if (c.Length < 1e-5)
                        return true;
                    if (c instanceof Arc) {
                        let arcBrs = this.BreakArc(c);
                        for (let arc of arcBrs)
                            arcs.push(arc);
                    }
                    return false;
                });
                //加入到计算
                cus.push(...arcs);
                this.ExpLineMap.set(c, cus);
                plcus.push(...cus);
                return true;
            }
            return false;
        });
        curveList.push(...plcus);
        this._CurveCount = curveList.length;
        for (let cu of curveList) {
            //由于圆弧可能导致最低点计算错误的问题.
            if (cu instanceof Arc) {
                let arcs = this.BreakArc(cu);
                if (arcs.length > 1) {
                    arcs.forEach(a => curveMap.AddCurveToMap(a, true, this.removeDuplicate, true));
                    this.ExpLineMap.set(cu, arcs);
                    continue;
                }
                else
                    curveMap.AddCurveToMap(cu, true, this.removeDuplicate, true);
            }
            else
                curveMap.AddCurveToMap(cu, false, this.removeDuplicate, true);
        }
        //排序,根据角度逆时针排序.
        for (let v of curveMap._Vertices) {
            let minLength = Infinity;
            for (let r of v.routes)
                if (r.length < minLength)
                    minLength = r.length;
            for (let r of v.routes)
                CalcRouteAngle(r, minLength * 0.2);
            v.routes.sort((r1, r2) => r1.an - r2.an);
        }
        return curveMap.Stands;
    }
    BreakArc(arc) {
        let underPt = arc.Center.add(new three.Vector3(0, -arc.Radius));
        let param = arc.GetParamAtPoint(underPt);
        if (param > 0.01 && param < 0.99)
            return arc.GetSplitCurves(param);
        else
            return [arc];
    }
    /**
     * 曲线是否已经被算法使用
     */
    GetCueveUsed(cu) {
        if (this.ExpLineMap.has(cu)) {
            let use = this.ExpLineMap.get(cu).some(c => c.TempData > 0);
            if (!use)
                this.ExpLineMap.delete(cu);
            return use;
        }
        else
            return cu.TempData > 0;
    }
}
function CalcRouteAngle(r, length) {
    if (r.an !== undefined)
        return;
    let cu = r.curve;
    let p = r.isReverse ?
        cu.GetPointAtParam(cu.GetParamAtDist(r.length - length))
        : cu.GetPointAtParam(cu.GetParamAtDist(length));
    r.an = angle(p.sub(r.from.position));
}
var WalkType;
(function (WalkType) {
    WalkType[WalkType["Min"] = 1] = "Min";
    WalkType[WalkType["Max"] = -1] = "Max";
})(WalkType || (WalkType = {}));
function ClosedWalkFrom(startVertice, maxRoute, type = WalkType.Min) {
    let walk = [];
    let curVertice = startVertice;
    let preRoute;
    // console.log("start", type, startVertice.position.toArray());
    do {
        let route = GetNextRoute(curVertice, preRoute, type);
        if (type === WalkType.Max && route.curve.TempData > 0)
            return [];
        // console.log(route.to.position.toArray());
        walk.push(route);
        [curVertice, preRoute] = [route.to, route];
        if (walk.length > maxRoute * 2)
            throw "超过计算次数限制";
    } while (curVertice !== startVertice);
    return walk;
}
/**
 * 删除中途回路
 */
function ReduceWalk(w) {
    if (w.length === 0)
        return w;
    //未构成回路,直接回家
    if (w[0].curve === arrayLast(w).curve)
        return [];
    for (let i = 0; i < w.length; i++) {
        let r1 = w[i];
        for (let j = w.length; j--;) {
            if (i === j)
                break;
            let r2 = w[j];
            if (r1.to === r2.to) {
                if (j > i)
                    w.splice(i + 1, j - i);
                break;
            }
        }
    }
    return w;
}
function GetNextRoute(v, prev, type = WalkType.Min) {
    if (!prev)
        return arrayLast(v.routes); //顺时针 cw \|/ 从左往右
    //逆时针 ccw 往左
    let index = v.routes.findIndex(r => r.curve === prev.curve);
    let newIndex = FixIndex(index + 1 * type, v.routes);
    return v.routes[newIndex];
}

var BoolOpeartionType;
(function (BoolOpeartionType) {
    BoolOpeartionType[BoolOpeartionType["Intersection"] = 0] = "Intersection";
    BoolOpeartionType[BoolOpeartionType["Union"] = 1] = "Union";
    BoolOpeartionType[BoolOpeartionType["Subtract"] = 2] = "Subtract";
})(BoolOpeartionType || (BoolOpeartionType = {}));
const fuzz = 1e-3;
let fuzzV3 = new three.Vector3(fuzz, fuzz, fuzz);
//判断曲线是否在源封闭曲线内
function isTargetCurInOrOnSourceCur(sourceCur, targetCur) {
    if (!sourceCur.BoundingBox.expandByVector(fuzzV3).containsBox(targetCur.BoundingBox))
        return false;
    let cus = [];
    if (targetCur instanceof exports.Polyline)
        cus = targetCur.Explode();
    else
        cus = [targetCur];
    return cus.every(c => {
        let pts = getIntPtContextPts(sourceCur, c);
        if (pts.length <= 1)
            pts.push(c.StartPoint, c.EndPoint);
        return IsPtsAllInOrOnReg(sourceCur, pts);
    });
}
//获取交点处上下距0.01par的点
function getIntPtContextPts(sourceCur, cu, pts = []) {
    let interPts = cu.IntersectWith(sourceCur, IntersectOption.OnBothOperands);
    if (interPts.length > 0) {
        let pars = interPts.map(pt => cu.GetParamAtPoint(pt));
        for (let par of pars) {
            if (par >= 0.02)
                pts.push(cu.GetPointAtParam(par - 0.01));
            if (par <= (cu.EndParam - 0.02))
                pts.push(cu.GetPointAtParam(par + 0.01));
        }
    }
    return pts;
}
//判断点点是否全部都在封闭区域内或者在曲线上
function IsPtsAllInOrOnReg(sourceReg, pts) {
    return pts.every(pt => {
        //是否点在封闭曲线内
        return sourceReg.PtOnCurve(pt) || sourceReg.PtInCurve(pt);
    });
}

let cache = new WeakMap();
class Contour {
    SetCurve(cu) {
        if (cu instanceof exports.Polyline) {
            if (cu.Area2 < 0)
                cu.Reverse();
        }
        this._Curve = cu;
    }
    /**会将传入的闭合轮廓改为逆时针 */
    static CreateContour(cus, needLink = true) {
        if (cus instanceof Curve) {
            if (cus.IsClose) {
                let c = new Contour();
                c.SetCurve(cus);
                return c;
            }
            return;
        }
        let closeCurve = Contour.Combine(cus, needLink, 1e-2);
        if (closeCurve && closeCurve.IsClose) {
            if (closeCurve instanceof exports.Polyline && closeCurve.CloseMark === false) {
                closeCurve.CloseMark = true;
                closeCurve.RemoveVertexAt(closeCurve.NumberOfVertices - 1);
            }
            let c = new Contour();
            c.SetCurve(closeCurve);
            return c;
        }
    }
    get Curve() {
        return this._Curve;
    }
    get Area() {
        return this._Curve.Area;
    }
    get BoundingBox() {
        return this._Curve.BoundingBox;
    }
    /**
     * 不等比例缩放
     * @param {number} ref 缩放参考值,大于该值的点缩放
     * @param {number} dist 缩放距离
     * @param {string} dir x y z
     */
    UnEqualProportionScale(ref, dist, dir) {
        let cu = this._Curve;
        if (cu instanceof exports.Polyline) {
            let lineData = cu.LineData;
            let length = lineData.length;
            let p = cu.Position[dir];
            let moveIndexs = [];
            for (let i = 0; i < length; i++) {
                if (lineData[i].pt[dir] + p > ref)
                    moveIndexs.push(i);
            }
            let moveVec = new three.Vector3();
            moveVec[dir] = dist;
            cu.MoveStretchPoints(moveIndexs, moveVec);
            return true;
        }
        return false;
    }
    Clone() {
        return Contour.CreateContour([this._Curve.Clone()]);
    }
    //交集:结果数组为空则失败
    IntersectionBoolOperation(target) {
        if (!IntersectBox2(this.BoundingBox, target.BoundingBox))
            return [];
        let resultCus = this.GetIntersetAndUnionList(target);
        return Contour.GetAllContour(resultCus.intersectionList);
    }
    //并集:结果轮廓数组长度大于2,则失败.等于1则成功.
    UnionBoolOperation(target) {
        let resultCus = this.GetIntersetAndUnionList(target);
        //快速
        if (resultCus.unionList.every(c => c.IsClose))
            return {
                contours: Contour.GetAllContour(resultCus.unionList),
                holes: [],
            };
        //并集后的线段表如果有共线的直接合并起来
        let cus = [];
        for (let pl of resultCus.unionList) {
            if (pl instanceof exports.Polyline)
                cus.push(...pl.Explode());
            else
                cus.push(pl);
        }
        let cuGroups = curveLinkGroup(cus);
        for (let g of cuGroups) {
            for (let i = 0; i < g.length; i++) {
                let c1 = g[i];
                let nextI = FixIndex(i + 1, g);
                let c2 = g[nextI];
                let status = c1.Join(c2);
                if (status === Status.True) {
                    g.splice(nextI, 1);
                    i--;
                }
                else if (status === Status.ConverToCircle) {
                    g.length = 0;
                    let a = c1;
                    g.push(new Circle(a.Center, a.Radius));
                    break;
                }
            }
        }
        let allContour = Contour.GetAllContour(cuGroups);
        if (allContour.length < 2) {
            return {
                contours: allContour,
                holes: [],
            };
        }
        else {
            let cache = new WeakMap();
            for (let c of allContour)
                cache.set(c, c.Area);
            allContour.sort((a, b) => cache.get(b) - cache.get(a));
            return {
                contours: [allContour[0]],
                holes: allContour.slice(1)
            };
        }
    }
    //差集:等于0完全被减去
    SubstactBoolOperation(target) {
        let subtractList = this.GetSubtractList(target);
        //纯网洞
        if (subtractList.every(c => c.IsClose))
            return Contour.GetAllContour(subtractList);
        let regParse = new RegionParse(subtractList, 2);
        let contours = [];
        //分析封闭包围区域
        const parseRoute = (routeSet) => {
            for (let routes of routeSet) {
                let cs = routes.map(r => r.curve);
                let c = Contour.CreateContour(cs, false);
                if (c
                    && !equalCurve(c.Curve, this.Curve)
                    && !equalCurve(c.Curve, target.Curve)
                    && c.Area > 1e-3)
                    contours.push(c);
            }
        };
        parseRoute(regParse.RegionsOutline);
        parseRoute(regParse.RegionsInternal);
        return contours;
    }
    /**
     * 计算与目标轮廓布尔运算后的结果曲线.
     */
    GetIntersetAndUnionList(target) {
        let intersectionList = [];
        let unionList = [];
        let sourceOutline = this._Curve;
        let targetOutline = target.Curve;
        let isEqualNormal = equalv3(sourceOutline.Normal, targetOutline.Normal, 1e-3);
        let interPts = sourceOutline.IntersectWith2(targetOutline, IntersectOption.OnBothOperands);
        let sourceContainerTarget = this.CuInOutline(targetOutline);
        let targetContainerSource = target.CuInOutline(sourceOutline);
        //包含.相交.分离(三种状态)
        if (sourceContainerTarget) //源包含目标
         {
            intersectionList.push(targetOutline);
            unionList.push(sourceOutline);
        }
        else if (targetContainerSource) //目标包含源
         {
            unionList.push(targetOutline);
            intersectionList.push(sourceOutline);
        }
        else if (interPts.length <= 1) //分离
         {
            unionList.push(sourceOutline, targetOutline);
        }
        else //相交 interPts.length > 0
         {
            let pars1 = interPts.map(r => r.thisParam);
            let pars2 = interPts.map(r => r.argParam);
            let sourceCus = sourceOutline.GetSplitCurves(pars1);
            let targetCus = targetOutline.GetSplitCurves(pars2);
            for (let pl of sourceCus) {
                let hasEqualCus = false;
                for (let i = 0; i < targetCus.length; i++) {
                    let cu = targetCus[i];
                    hasEqualCus = fastEqualCurve(cu, pl);
                    if (hasEqualCus) {
                        //方向相同
                        if (equalv3(cu.GetFistDeriv(cu.EndParam * 0.5).normalize(), pl.GetFistDeriv(pl.EndParam * 0.5).normalize(), 1e-3)
                            === isEqualNormal) {
                            unionList.push(pl);
                            intersectionList.push(pl);
                        }
                        targetCus.splice(i, 1);
                        break;
                    }
                }
                if (hasEqualCus)
                    continue;
                if (target.CuInOutline(pl))
                    intersectionList.push(pl);
                else
                    unionList.push(pl);
            }
            for (let pl of targetCus) {
                if (this.CuInOutline(pl))
                    intersectionList.push(pl);
                else
                    unionList.push(pl);
            }
            //特殊的分离
            if (intersectionList.length === 0 && unionList.length === (sourceCus.length + targetCus.length)) {
                return { intersectionList, unionList: [sourceOutline, targetOutline] };
            }
        }
        return { intersectionList, unionList };
    }
    GetSubtractList(target) {
        let sourceOutline = this._Curve;
        let targetOutline = target.Curve;
        let isEqualNormal = equalv3(sourceOutline.Normal, targetOutline.Normal, 1e-3);
        let interPts = sourceOutline.IntersectWith2(targetOutline, IntersectOption.OnBothOperands, 1e-3);
        if (interPts.length <= 1) {
            //反包含
            if (fastCurveInCurve2(targetOutline, sourceOutline) || equalCurve(targetOutline, sourceOutline))
                return [];
            //包含
            if (fastCurveInCurve2(sourceOutline, targetOutline))
                return [sourceOutline, targetOutline];
            else //分离
                return [sourceOutline];
        }
        //相交
        let subtractList = [];
        let sourceCus = sourceOutline.GetSplitCurves(interPts.map(r => r.thisParam));
        let targetCus = targetOutline.GetSplitCurves(interPts.map(r => r.argParam));
        for (let pl of sourceCus) {
            let plMidParam = pl.MidParam;
            let plDir = pl.GetFistDeriv(plMidParam).normalize();
            let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl));
            if (index !== -1) {
                let cu = targetCus[index];
                let cuMidParam = cu.MidParam;
                let cuDir = cu.GetFistDeriv(cuMidParam).normalize();
                if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3)) //不同向
                    subtractList.push(pl);
                targetCus.splice(index, 1);
                continue;
            }
            if (!fastCurveInCurve(targetOutline, pl))
                subtractList.push(pl);
        }
        //源对象没有被破坏
        let sourceNotBreak = subtractList.length === sourceCus.length;
        for (let pl of targetCus)
            if (fastCurveInCurve(sourceOutline, pl))
                subtractList.push(pl);
        if (sourceNotBreak && subtractList.length === sourceCus.length)
            return [sourceOutline];
        return subtractList;
    }
    GetSubtractListByMoreTargets(targets) {
        let { holes, subtractList } = this.GetSubListWithCus(targets);
        //纯网洞
        if (subtractList.every(c => c.IsClose))
            return {
                holes: holes.map(h => Contour.CreateContour(h)),
                outlines: Contour.GetAllContour(subtractList)
            };
        let regParse = new RegionParse(subtractList, 2);
        let contours = [];
        //分析封闭包围区域
        const parseRoute = (routeSet) => {
            for (let routes of routeSet) {
                let cs = routes.map(r => r.curve);
                let c = Contour.CreateContour(cs, false);
                if (c
                    && !equalCurve(c.Curve, this.Curve)
                    && targets.every(target => !equalCurve(c.Curve, target.Curve))
                    && c.Area > 1e-3)
                    contours.push(c);
            }
        };
        parseRoute(regParse.RegionsOutline);
        parseRoute(regParse.RegionsInternal);
        return {
            holes: holes.map(h => Contour.CreateContour(h)),
            outlines: contours
        };
    }
    GetSubListWithCus(targets) {
        let sourceOutline = this._Curve;
        let subtractList = [];
        let holes = [];
        let intPars = [];
        let cuMap = new Map();
        let outBox = sourceOutline.BoundingBox;
        for (let con of targets) {
            const targetOutline = con.Curve;
            if (!IntersectBox2(outBox, targetOutline.BoundingBox))
                continue;
            let pts = sourceOutline.IntersectWith2(con.Curve, IntersectOption.OnBothOperands, 1e-3);
            if (pts.length <= 1) {
                //反包含
                if (fastCurveInCurve2(targetOutline, sourceOutline) || equalCurve(targetOutline, sourceOutline))
                    return { holes, subtractList };
                //包含
                if (fastCurveInCurve2(sourceOutline, targetOutline))
                    holes.push(targetOutline);
            }
            else {
                intPars.push(...pts.map(r => r.thisParam));
                cuMap.set(targetOutline, pts.map(r => r.argParam));
            }
        }
        intPars.sort((a, b) => a - b);
        arrayRemoveDuplicateBySort(intPars, (e1, e2) => equaln(e1, e2, 1e-8));
        let sourceCus = sourceOutline.GetSplitCurves(intPars);
        let targetCus = [];
        let targetMap = new WeakMap();
        let isEqualNormal;
        for (let [c, pars] of cuMap) {
            let cus = c.GetSplitCurves(pars);
            cus.forEach(cu => targetMap.set(cu, c));
            targetCus.push(...cus);
        }
        for (let pl of sourceCus) {
            let plMidParam = pl.MidParam;
            let plDir = pl.GetFistDeriv(plMidParam).normalize();
            let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl, 0.05));
            if (index !== -1) {
                let cu = targetCus[index];
                isEqualNormal = equalv3(sourceOutline.Normal, targetMap.get(cu).Normal, 1e-3);
                let cuMidParam = cu.MidParam;
                let cuDir = cu.GetFistDeriv(cuMidParam).normalize();
                if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3)) //不同向
                    subtractList.push(pl);
                targetCus.splice(index, 1);
                continue;
            }
            if (targets.every(t => !fastCurveInCurve(t.Curve, pl)))
                subtractList.push(pl);
        }
        //源对象没有被破坏
        let sourceNotBreak = subtractList.length === sourceCus.length;
        for (let pl of targetCus)
            if (fastCurveInCurve(sourceOutline, pl))
                subtractList.push(pl);
        if (sourceNotBreak && subtractList.length === sourceCus.length)
            return { subtractList: [sourceOutline], holes };
        return { subtractList, holes };
    }
    /**
     * 获得全部闭合曲线
     * @若传入二维曲线数据,将默认子数组为闭合曲线段
     */
    static GetAllContour(cus) {
        if (cus.length === 0)
            return [];
        let cuGroups;
        if (Array.isArray(cus[0]))
            cuGroups = cus;
        else
            cuGroups = curveLinkGroup(cus);
        let contours = [];
        for (let g of cuGroups)
            contours.push(Contour.CreateContour(g, false));
        return contours.filter(c => c !== undefined && !equaln(c.Area, 0, 1e-6));
    }
    /**
     * 合并曲线组成为多段线
     * @param cus 曲线组
     * @param [needLink=true] 需要解析成首尾连接状态
     * @returns 单一曲线,如果返回超过1个,其他的将被遗弃.
     */
    static Combine(cus, needLink = true, tolerance = 1e-3) {
        if (cus.length === 0)
            return undefined;
        let groups = needLink ? curveLinkGroup(cus) : [cus];
        for (let g of groups) {
            if (g.length === 1)
                return g[0].Clone();
            else {
                if (cache.has(g))
                    return cache.get(g);
                let gclone = g.map(c => c.Clone());
                arrayRemoveDuplicateBySort(gclone, (cu1, cu2) => cu1.Join(cu2, false, tolerance) === Status.True);
                if (gclone.length > 1 && gclone[0].Join(arrayLast(gclone), false, tolerance))
                    gclone.pop();
                let pl = exports.Polyline.Combine(gclone, tolerance);
                cache.set(g, pl);
                return pl;
            }
        }
    }
    get Shape() {
        return this._Curve.Shape;
    }
    CuInOutline(targetCur) {
        return isTargetCurInOrOnSourceCur(this._Curve, targetCur);
    }
    Equal(tar) {
        return equalCurve(this._Curve, tar._Curve);
    }
}
/**
 * 对于轮廓切割后的曲线判断相同,使用这个函数进行快速判断
 */
function fastEqualCurve(c1, c2, tolerance = 1e-3) {
    let sp1 = c1.StartPoint;
    let ep1 = c1.EndPoint;
    let sp2 = c2.StartPoint;
    let ep2 = c2.EndPoint;
    if (!((equalv3(sp1, sp2, tolerance) && equalv3(ep1, ep2, tolerance))
        || (equalv3(sp1, ep2, tolerance) && equalv3(ep1, sp2, tolerance))))
        return false;
    return equalv3(c1.Midpoint, c2.Midpoint, tolerance);
}
//对于双多段线互相切割后的结果,快速判断曲线是否在另一条曲线内部
function fastCurveInCurve(sourceCu, targetCu) {
    return sourceCu.PtInCurve(targetCu.GetPointAtParam(targetCu.EndParam * 0.5));
}
function fastCurveInCurve2(sourceCu, targetCu) {
    return sourceCu.PtInCurve(targetCu.StartPoint) &&
        sourceCu.PtInCurve(targetCu.GetPointAtParam(targetCu.EndParam * 0.5));
}

/**
 * 根据盒子x排序盒子
 * @param {EBox[]} arr
 */
function SortEntityByBox(arr, sort = true) {
    let boxMap = new Map();
    arr.forEach(e => boxMap.set(e, e.BoundingBox));
    if (sort)
        arr.sort((e1, e2) => {
            let b1 = boxMap.get(e1);
            let b2 = boxMap.get(e2);
            if (!equaln(b1.min.x, b2.min.x))
                return b1.min.x - b2.min.x;
            else {
                return b2.min.y - b1.min.y;
            }
        });
    return boxMap;
}

class CurveTreeNode {
    constructor(curve, box) {
        this.curve = curve;
        this.box = box || curve.BoundingBox;
    }
    TrimBy(contour, box) {
        if (IntersectsBox(box, this.box)) {
            if (this.children !== undefined) {
                for (let c of this.children)
                    c.TrimBy(contour, box);
            }
            else {
                if (contour.Curve instanceof Circle && this.curve instanceof Arc) {
                    if (equalv3(contour.Curve.Center, this.curve.Center)) {
                        if (contour.Curve.Radius > this.curve.Radius + 1e-4)
                            this.children = [];
                        return;
                    }
                }
                //交点参数列表
                let iParams = this.curve.IntersectWith(contour.Curve, IntersectOption.OnBothOperands)
                    .map(p => this.curve.GetParamAtPoint2(p));
                let cus = this.curve.GetSplitCurves(iParams);
                if (cus.length === 0) {
                    let p = this.curve.GetPointAtParam(0.5);
                    if ((contour.Curve.PtInCurve(p) && !contour.Curve.PtOnCurve(p)))
                        this.children = [];
                }
                else {
                    this.children = [];
                    for (let c of cus) {
                        let p = c.GetPointAtParam(0.5);
                        if (c.Length > 1e-5 && (!contour.Curve.PtInCurve(p) || contour.Curve.PtOnCurve(p)))
                            this.children.push(new CurveTreeNode(c));
                    }
                    if (this.children.length === cus.length)
                        this.children = undefined;
                }
            }
        }
    }
    get Nodes() {
        if (!this.children)
            return [this];
        else {
            let cus = [];
            for (let c of this.children)
                cus.push(...c.Nodes);
            return cus;
        }
    }
}
class OffsetPolyline {
    constructor(_Polyline, _OffsetDist, _ToolPath = false, _OffsetDistSq = (_OffsetDist ** 2) * 2.1 //对直角走刀不进行圆弧过度
    ) {
        this._Polyline = _Polyline;
        this._OffsetDist = _OffsetDist;
        this._ToolPath = _ToolPath;
        this._OffsetDistSq = _OffsetDistSq;
    }
    Do() {
        this._OffsetDistSign = Math.sign(this._OffsetDist);
        this._TrimPolylineContours = [];
        this._TrimCircleContours = [];
        this._TrimArcContours = [];
        this._RetCurves = [];
        this._CurveTreeNodes = [];
        this.InitSubCurves();
        if (this._SubCurves.length === 0)
            return this._RetCurves;
        this.GeneralCirclesAndVertexs();
        this.OffsetSubCurves();
        this.LinkSubCurves();
        if (this._SubOffsetedCurves.length === 0) {
            this._SubOffsetedCurves.push({ curve: this._Circles[0], index: 0, paddingCurve: this._Circles.slice(1) });
            this._TrimPolylineContours.push(...this._Circles.map(c => Contour.CreateContour(c, false)), ...this._SubCurves.map(c => Contour.CreateContour([c, new Line(c.StartPoint, c.EndPoint)], false)));
        }
        else
            this.GeneralTrimContours();
        this.TrimByContours();
        this.FilterInvalidCurve();
        this.JoinCollinear();
        this.LinkResultPolyline();
        return this._RetCurves;
    }
    InitSubCurves() {
        this._CacheOCS = this._Polyline.OCS;
        this._IsClose = this._Polyline.IsClose;
        this._Polyline.OCS = IdentityMtx4;
        this._SubCurves = this._Polyline.Explode().filter(c => c.Length > 1e-4);
        this._Polyline.OCS = this._CacheOCS;
        return this;
    }
    GeneralCirclesAndVertexs() {
        this._Vertexs = this._SubCurves.map(c => c.StartPoint);
        let lastCu = arrayLast(this._SubCurves);
        if (!equalv3(lastCu.EndPoint, this._Vertexs[0], 1e-3))
            this._Vertexs.push(lastCu.EndPoint);
        let radius = Math.abs(this._OffsetDist);
        this._Circles = this._Vertexs.map(p => new Circle(p, radius));
    }
    OffsetSubCurves() {
        this._SubOffsetedCurves = [];
        for (let index = 0; index < this._SubCurves.length; index++) {
            let curveOld = this._SubCurves[index];
            if (curveOld.Length > 1e-6) {
                let curve = curveOld.GetOffsetCurves(this._OffsetDist)[0];
                if (curve)
                    this._SubOffsetedCurves.push({ curve, index });
                else
                    this._TrimArcContours.push(Contour.CreateContour([curveOld, new Line(curveOld.StartPoint, curveOld.EndPoint)], false));
            }
        }
    }
    //连接(延伸)曲线,或者补(圆弧,直线)
    LinkSubCurves() {
        let count = this._SubOffsetedCurves.length;
        if (!this._IsClose)
            count--;
        for (let i = 0; i < count; i++) {
            let curveResNow = this._SubOffsetedCurves[i];
            let iNext = FixIndex(i + 1, this._SubOffsetedCurves);
            let curveResNext = this._SubOffsetedCurves[iNext];
            let curveNow = curveResNow.curve;
            let curveNext = curveResNext.curve;
            let isNeighbor = FixIndex(curveResNow.index + 1, this._SubCurves) === curveResNext.index;
            if (isNeighbor) {
                let sp = curveNow.EndPoint;
                let ep = curveNext.StartPoint;
                //直连
                if (equalv3(sp, ep, 1e-3))
                    continue;
                let iPts = curveNow.IntersectWith(curveNext, IntersectOption.ExtendBoth);
                let tPts = iPts.filter(p => curveNow.PtOnCurve3(p) && curveNext.PtOnCurve3(p));
                let code = EntityEncode2(curveNow, curveNext);
                let tp;
                if (code === 1) {
                    if (tPts.length > 0) //不走刀或者有真交点 this._ToolPath === false ||
                        tp = iPts[0];
                    else {
                        if (iPts.length > 0 && curveNow.GetParamAtPoint(iPts[0]) > 1) {
                            let refP = this._Vertexs[curveResNext.index];
                            let distSq = iPts[0].distanceToSquared(refP);
                            if (this._ToolPath && distSq > this._OffsetDistSq) {
                                curveResNow.paddingCurve = [this.CreateArc(refP, sp, ep)];
                                this._TrimCircleContours.push(this._Circles[curveResNext.index]);
                            }
                            else
                                tp = iPts[0];
                        }
                        // else
                        // curveResNow.paddingCurve = [new Line(sp, ep)];
                    }
                }
                else {
                    let refP = this._Vertexs[curveResNext.index];
                    if (tPts.length > 0) //ipts = 1 or ipts = 2
                        tp = SelectNearP(iPts, refP);
                    else //补单圆 或者尝试连接
                     {
                        let arc = this.CreateArc(refP, sp, ep);
                        if (iPts.length > 0 && !this._ToolPath && this.IsSharpCorner(curveResNow, curveResNext, refP)) {
                            //设置新的连接点,并且备份旧点
                            let oldp;
                            if (curveResNow.sp) {
                                oldp = curveNow.StartPoint;
                                curveNow.StartPoint = curveResNow.sp;
                            }
                            let oldp2;
                            if (curveResNext.ep) {
                                oldp2 = curveNext.EndPoint;
                                curveNext.EndPoint = curveResNext.ep;
                            }
                            let p;
                            if (code === 2 && iPts.length === 2) {
                                let c = curveNow;
                                let minArc = new Arc(c.Center, c.Radius, c.EndAngle, 0, c.IsClockWise);
                                let p1 = iPts[0];
                                let a1 = minArc.GetAngleAtPoint(p1);
                                let anAll1 = c.ParamOnCurve(c.GetParamAtAngle(a1)) ? Infinity : minArc.ComputeAnlge(a1);
                                let p2 = iPts[1];
                                let a2 = minArc.GetAngleAtPoint(p2);
                                let anAll2 = c.ParamOnCurve(c.GetParamAtAngle(a2)) ? Infinity : minArc.ComputeAnlge(a2);
                                if (anAll2 < anAll1)
                                    p = p2;
                                else
                                    p = p1;
                            }
                            else
                                p = SelectNearP(iPts, refP);
                            let onPre;
                            let param = curveNow.GetParamAtPoint2(p);
                            if (curveNow instanceof Line)
                                onPre = param > 1;
                            else
                                onPre = param < 0 || param > 1;
                            let onNext = false;
                            if (onPre) {
                                let param2 = curveNext.GetParamAtPoint2(p);
                                if (curveNext instanceof Line)
                                    onNext = param2 < 0;
                                else
                                    onNext = param2 < 0 || param2 > 1;
                            }
                            if (curveResNow.sp)
                                curveNow.StartPoint = oldp;
                            if (curveResNext.ep)
                                curveNext.EndPoint = oldp2;
                            if (onPre && onNext)
                                tp = p;
                            else
                                curveResNow.paddingCurve = [arc];
                        }
                        else
                            curveResNow.paddingCurve = [arc];
                        this._TrimCircleContours.push(this._Circles[curveResNext.index]);
                    }
                }
                if (tp) {
                    curveResNow.ep = tp;
                    curveResNext.sp = tp;
                    curveResNow.nextArc = curveNext;
                    curveResNext.preArc = curveNow;
                }
            }
            else {
                let padCirs = [];
                for (let s = FixIndex(curveResNow.index + 1, this._Circles);; s = FixIndex(s + 1, this._Circles)) {
                    let c = this._Circles[s];
                    this._TrimCircleContours.push(c);
                    padCirs.push(c);
                    if (s === curveResNext.index)
                        break;
                }
                curveResNow.paddingCurve = padCirs;
            }
        }
    }
    IsSharpCorner(curveResNow, curveResNext, refP) {
        let v1 = this._SubCurves[curveResNow.index].GetPointAtParam(0.9);
        let v2 = this._SubCurves[curveResNext.index].GetPointAtParam(0.1);
        v1.subVectors(refP, v1);
        v2.sub(refP);
        v1.cross(v2);
        return Math.sign(v1.z) === this._OffsetDistSign;
    }
    GeneralTrimContours() {
        for (let d of this._SubOffsetedCurves) {
            let cu2 = d.curve;
            if (d.sp && d.ep) {
                let param1 = cu2.GetParamAtPoint(d.sp);
                let param2 = cu2.GetParamAtPoint(d.ep);
                if (cu2.ParamOnCurve(param1) && cu2.ParamOnCurve(param2) && param1 > param2)
                    [d.sp, d.ep] = [d.ep, d.sp];
            }
            if (d.sp)
                cu2.StartPoint = d.sp;
            if (d.ep)
                cu2.EndPoint = d.ep;
        }
        for (let d of this._SubOffsetedCurves) {
            let cu1 = this._SubCurves[d.index];
            let cu2 = d.curve;
            let [p1, p2, p3, p4] = [cu1.StartPoint, cu2.StartPoint, cu1.EndPoint, cu2.EndPoint];
            let l1 = new Line(p1, p2);
            let l2 = new Line(p3, p4);
            let ipts = l1.IntersectWith(l2, IntersectOption.OnBothOperands, 1e-8);
            if (ipts.length > 0) {
                let p = ipts[0];
                l1.EndPoint = p;
                l2.EndPoint = p;
                let cus = [cu1, l1, l2];
                let contour = Contour.CreateContour(cus, false);
                if (contour) {
                    this._TrimPolylineContours.push(contour);
                    continue;
                }
                else {
                    console.error("未预料到的错误,构建轮廓失败" + this._OffsetDist);
                }
            }
            //真理1:针脚线不可能同时被两个圆弧所切割
            let l1Intact = true;
            let l2Intact = true;
            if (cu2 instanceof Arc) {
                if (Math.sign(cu2.Bul) !== this._OffsetDistSign) {
                    let ipts1 = cu2.IntersectWith(l1, IntersectOption.OnBothOperands);
                    let ipts2 = cu2.IntersectWith(l2, IntersectOption.OnBothOperands);
                    let sp;
                    let ep;
                    if (ipts1.length === 2)
                        sp = SelectNearP(ipts1, p1);
                    if (ipts2.length === 2)
                        ep = SelectNearP(ipts2, p3);
                    if (sp || ep)
                        cu2 = cu2.Clone();
                    if (sp) {
                        l1.EndPoint = sp;
                        cu2.StartPoint = sp;
                        l1Intact = false;
                    }
                    if (ep) {
                        l2.EndPoint = ep;
                        cu2.EndPoint = ep;
                        l2Intact = false;
                    }
                }
            }
            let l1PadArc;
            let l2PadArc;
            //真理2:隔壁的圆弧不可能破坏当前的圆弧,只能破坏当前的针脚
            if (l1Intact && d.preArc && d.preArc instanceof Arc) {
                let a = d.preArc;
                if (Math.sign(a.Bul) !== this._OffsetDistSign) {
                    let ipts = a.IntersectWith(l1, IntersectOption.OnBothOperands);
                    if (ipts.length === 2) {
                        let sp = SelectNearP(ipts, p1);
                        l1.EndPoint = sp;
                        l1PadArc = a.Clone();
                        l1PadArc.StartPoint = sp;
                    }
                }
            }
            if (l2Intact && d.nextArc && d.nextArc instanceof Arc) {
                let a = d.nextArc;
                if (Math.sign(a.Bul) !== this._OffsetDistSign) {
                    let ipts = a.IntersectWith(l2, IntersectOption.OnBothOperands);
                    if (ipts.length === 2) {
                        let ep = SelectNearP(ipts, p3);
                        l2.EndPoint = ep;
                        l2PadArc = a.Clone();
                        l2PadArc.EndPoint = ep;
                    }
                }
            }
            let pl = new exports.Polyline();
            let cus = [cu1, l1];
            if (l1PadArc)
                cus.push(l1PadArc);
            cus.push(cu2, l2);
            if (l2PadArc)
                cus.push(l2PadArc);
            for (let c of cus)
                pl.Join(c);
            let contour = Contour.CreateContour(pl, false);
            if (contour)
                this._TrimPolylineContours.push(contour);
            else
                console.error("未预料到的错误,构建轮廓失败" + this._OffsetDist);
        }
        if (!this._IsClose) {
            if (this._TrimCircleContours[0] !== this._Circles[0])
                this._TrimCircleContours.push(this._Circles[0]);
            let lastTrimCircle = arrayLast(this._TrimCircleContours);
            let lastCircle = arrayLast(this._Circles);
            if (lastTrimCircle !== lastCircle)
                this._TrimCircleContours.push(lastCircle);
            if (this._SubOffsetedCurves[0].index !== 0)
                this._TrimCircleContours.push(this._Circles[this._SubOffsetedCurves[0].index]);
            let lastIndex = this._Circles.length - 1;
            let lastD = arrayLast(this._SubOffsetedCurves);
            if (lastIndex !== lastD.index)
                this._TrimCircleContours.push(this._Circles[lastD.index + 1]);
        }
        this._TrimPolylineContours.push(...this._TrimCircleContours.map(c => Contour.CreateContour(c, false)), ...this._TrimArcContours);
    }
    // 通过构建的轮廓对偏移曲线进行裁剪
    TrimByContours() {
        for (let d of this._SubOffsetedCurves) {
            let c = d.curve;
            this._CurveTreeNodes.push(new CurveTreeNode(c));
            if (d.paddingCurve)
                this._CurveTreeNodes.push(...d.paddingCurve.map(c => new CurveTreeNode(c)));
        }
        let boxContours = SortEntityByBox(this._TrimPolylineContours, false);
        for (let i = 0; i < this._TrimPolylineContours.length; i++) {
            let c = this._TrimPolylineContours[i];
            for (let curveNode of this._CurveTreeNodes) {
                curveNode.TrimBy(c, boxContours.get(c));
            }
        }
    }
    //过滤方向相反和0长度线
    FilterInvalidCurve() {
        this._CurveTrimedTreeNodes = [];
        for (let n of this._CurveTreeNodes) {
            let ns = n.Nodes;
            for (let sn of ns) {
                let p = sn.curve.GetPointAtParam(0.5);
                if (sn.curve.Length > 1e-5 && this.CheckPointDir(p))
                    this._CurveTrimedTreeNodes.push(sn);
            }
        }
    }
    //合并共线
    JoinCollinear() {
        for (let i = 0; i < this._CurveTrimedTreeNodes.length; i++) {
            let n = this._CurveTrimedTreeNodes[i];
            if (n.used)
                continue;
            let sp = n.curve.StartPoint;
            for (let j = i + 1; j < this._CurveTrimedTreeNodes.length; j++) {
                let n2 = this._CurveTrimedTreeNodes[j];
                if (n2.used)
                    continue;
                let status = n.curve.Join(n2.curve);
                if (status === Status.ConverToCircle) {
                    n.used = true;
                    n2.used = true;
                    let circle = new Circle(n.curve.Center, n.curve.Radius);
                    n.curve = circle;
                    this._RetCurves.push(ConverCircleToPolyline(circle).ApplyMatrix(this._CacheOCS));
                }
                else if (status === Status.True) {
                    if (equalv3(sp, n.curve.StartPoint))
                        n2.used = true;
                    else {
                        n.used = true;
                        n2.curve = n.curve;
                        break;
                    }
                }
            }
        }
    }
    //连接结果曲线,返回最终多段线
    LinkResultPolyline() {
        let used = new Set();
        let cuMap = new CurveMap(1);
        for (let n of this._CurveTrimedTreeNodes) {
            if (!n.used)
                cuMap.AddCurveToMap(n.curve);
        }
        let preP;
        let searchNext = (s, pl) => {
            let minDist = Infinity;
            let minR;
            for (let r of s.routes) {
                if (used.has(r.curve))
                    continue;
                if (preP) {
                    let d = r.s.distanceToSquared(preP);
                    if (d < minDist) {
                        minR = r;
                        minDist = d;
                    }
                }
                else {
                    minR = r;
                    break;
                }
            }
            if (minR) {
                used.add(minR.curve);
                preP = minR.e;
                let status = pl.Join(minR.curve, false, 5e-2);
                if (status !== Status.True)
                    console.warn("连接失败");
                return minR.to;
            }
        };
        for (let s of cuMap.Stands) {
            preP = undefined;
            let pl = new exports.Polyline();
            let ss = s;
            while (ss && !pl.IsClose)
                ss = searchNext(ss, pl);
            ss = s;
            while (ss && !pl.IsClose)
                ss = searchNext(ss, pl);
            if (pl.NumberOfVertices > 0) {
                let d = pl.LineData;
                let ld = arrayLast(d);
                if (equalv2(d[0].pt, ld.pt, 1e-2))
                    ld.pt.copy(d[0].pt);
                this._RetCurves.push(pl.ApplyMatrix(this._CacheOCS));
            }
        }
    }
    CheckPointDir(pt) {
        return this.GetPointAtCurveDir(pt) === this._OffsetDistSign;
    }
    GetPointAtCurveDir(pt) {
        let minIndex = Infinity;
        let minDist = Infinity;
        let minCp;
        for (let i = 0; i < this._SubCurves.length; i++) {
            let c = this._SubCurves[i];
            let cp = c.GetClosestPointTo(pt, false);
            if (equalv3(cp, pt, 1e-5))
                return 0;
            let dist = cp.distanceToSquared(pt);
            if (dist < minDist) {
                minDist = dist;
                minIndex = i;
                minCp = cp;
            }
        }
        let c = this._SubCurves[minIndex];
        let param = c.GetParamAtPoint(minCp);
        if (equaln(param, 0) && ((minIndex === 0) ? this._IsClose : true)) {
            let preIndex = FixIndex(minIndex - 1, this._SubCurves);
            let preCurve = this._SubCurves[preIndex];
            if (!equalv3(c.GetFistDeriv(0).normalize(), preCurve.GetFistDeriv(1).normalize())) {
                let p = c.StartPoint;
                let l1 = c.Length;
                let l2 = preCurve.Length;
                let minLength = Math.min(l1, l2) * 0.2;
                let nextP;
                let preP;
                if (c instanceof Arc)
                    nextP = c.GetPointAtDistance(minLength);
                else
                    nextP = c.EndPoint;
                if (preCurve instanceof Arc)
                    preP = preCurve.GetPointAtDistance(l2 - minLength);
                else
                    preP = preCurve.StartPoint;
                let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p)));
                let dir = arc.PtOnCurve3(pt) ? -1 : 1;
                return dir;
            }
        }
        else if (equaln(param, 1) && ((minIndex === this._SubCurves.length - 1) ? this._IsClose : true)) {
            let nextIndex = FixIndex(minIndex + 1, this._SubCurves);
            let nextCurve = this._SubCurves[nextIndex];
            if (!equalv3(c.GetFistDeriv(1).normalize(), nextCurve.GetFistDeriv(0).normalize())) {
                let p = c.EndPoint;
                let l1 = c.Length;
                let l2 = nextCurve.Length;
                let minLength = Math.min(l1, l2) * 0.2;
                let nextP;
                let preP;
                if (c instanceof Arc)
                    preP = c.GetPointAtDistance(l1 - minLength);
                else
                    preP = c.StartPoint;
                if (nextCurve instanceof Arc)
                    nextP = nextCurve.GetPointAtDistance(minLength);
                else
                    nextP = nextCurve.EndPoint;
                let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p)));
                let dir = arc.PtOnCurve3(pt) ? -1 : 1;
                return dir;
            }
        }
        let dri = c.GetFistDeriv(param);
        let cross = dri.cross(pt.clone().sub(minCp));
        return -Math.sign(cross.z);
    }
    CreateArc(center, startP, endP) {
        let sa = angle(startP.clone().sub(center));
        let ea = endP ? angle(endP.clone().sub(center)) : sa;
        let arc = new Arc(center, Math.abs(this._OffsetDist), sa, ea, this._OffsetDist < 0);
        return arc;
    }
}
function EntityEncode(c) {
    if (c instanceof Line)
        return 1;
    else
        return 2;
}
function EntityEncode2(c1, c2) {
    return EntityEncode(c1) & EntityEncode(c2);
}

//3点获取圆心
function getCircleCenter(pt1, pt2, pt3) {
    if (!(pt1 && pt2 && pt3))
        return;
    let A1 = pt1.x - pt2.x;
    let B1 = pt1.y - pt2.y;
    let C1 = (Math.pow(pt1.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt1.y, 2) - Math.pow(pt2.y, 2)) / 2;
    let A2 = pt3.x - pt2.x;
    let B2 = pt3.y - pt2.y;
    let C2 = (Math.pow(pt3.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt3.y, 2) - Math.pow(pt2.y, 2)) / 2;
    //令temp = A1*B2 - A2*B1
    let temp = A1 * B2 - A2 * B1;
    let center = new three.Vector3();
    //判断三点是否共线
    if (temp === 0) {
        //共线则将第一个点pt1作为圆心
        center.x = pt1.x;
        center.y = pt1.y;
    }
    else {
        //不共线则求出圆心：
        center.x = (C1 * B2 - C2 * B1) / temp;
        center.y = (A1 * C2 - A2 * C1) / temp;
    }
    return center;
}
//行列式
function getDeterminantFor2V(v1, v2) {
    return v1.x * v2.y - v1.y * v2.x;
}
/**
 * 曲线根据连接来分组,每组都是一条首尾相连的曲线表.
 *
 * @export
 * @param {Curve[]} cus 传入的分组的曲线表
 * @returns {Array<Array<Curve>>} 返回如下
 * [
 *   [c1,c2,c3...],//后面的曲线的起点总是等于上一个曲线的终点
 *   [c1,c2,c3...],
 * ]
 */
function curveLinkGroup(cus) {
    //返回的曲线组
    let groupCus = new Array();
    //将封闭的曲线先提取出来
    cus = cus.filter(c => {
        let isClose = c.IsClose;
        if (isClose)
            groupCus.push([c]);
        return !isClose;
    });
    if (cus.length === 0)
        return groupCus;
    //曲线节点图
    let cuMap = new CurveMap();
    cus.forEach(c => cuMap.AddCurveToMap(c));
    //曲线站点表
    let stands = cuMap.Stands;
    //曲线使用计数
    let cuCount = new Count();
    /**
     * 从站点的路线中任意取一条,加入到曲线数组中.
     *
     * @param {Curve[]} cus 已经连接的曲线列表
     * @param {boolean} isEndSeach true:从终点搜索,false:从起点搜索
     * @returns {Stand} 如果站点中存在可以取得的曲线,返回下个站点,否则返回undefined
     */
    function linkCurve(stand, cus, isEndSeach) {
        for (let route of stand.routes) {
            let cu = route.curve;
            if (cuCount.GetCount(cu) === 0) {
                if (isEndSeach) {
                    //保证曲线总是从起点连接到终点
                    if (!equalv3(cu.StartPoint, stand.position))
                        cu.Reverse();
                    cus.push(cu);
                }
                else {
                    //保证曲线总是从起点连接到终点
                    if (!equalv3(cu.EndPoint, stand.position))
                        cu.Reverse();
                    cus.unshift(cu);
                }
                cuCount.AddCount(cu, 1);
                return route.to;
            }
        }
    }
    for (let stand of stands) {
        let startStand = stand;
        let cus = []; //形成合并轮廓的曲线组
        while (startStand)
            startStand = linkCurve(startStand, cus, true);
        if (cus.length > 0) {
            startStand = cuMap.GetOnlyVertice(cus[0].StartPoint);
            while (startStand)
                startStand = linkCurve(startStand, cus, false);
        }
        if (cus.length > 0)
            groupCus.push(cus);
    }
    return groupCus;
}
function equalCurve(cu1, cu2, tolerance = 1e-4) {
    if ((cu1 instanceof exports.Polyline) && (cu2 instanceof exports.Polyline)) {
        if (cu1.IsClose !== cu2.IsClose || !isParallelTo(cu1.Normal, cu2.Normal))
            return false;
        let area1 = cu1.Area2;
        let area2 = cu2.Area2;
        if (!equaln(Math.abs(area1), Math.abs(area2), 0.1))
            return false;
        let ptsBuls1 = cu1.PtsBuls;
        let ptsBuls2 = cu2.PtsBuls;
        let pts1 = ptsBuls1.pts;
        let pts2 = ptsBuls2.pts;
        let buls1 = ptsBuls1.buls;
        let buls2 = ptsBuls2.buls;
        let isEqualArea = equaln(area1, area2, 0.1);
        if (!equalv3(cu1.Normal, cu2.Normal)) {
            if (isEqualArea) {
                pts2.reverse();
                buls2.reverse();
                buls2.push(buls2.shift());
            }
            else
                buls2 = buls2.map(bul => -bul);
        }
        else if (!isEqualArea) {
            pts2.reverse();
            buls2.reverse();
            buls2 = buls2.map(bul => -bul);
            buls2.push(buls2.shift());
        }
        if (cu1.IsClose && equalv2(pts1[0], arrayLast(pts1), tolerance)) {
            pts1.pop();
            buls1.pop();
        }
        if (cu2.IsClose && equalv2(pts2[0], arrayLast(pts2), tolerance)) {
            pts2.pop();
            buls2.pop();
        }
        let cu1Sp = AsVector2(cu1.StartPoint.applyMatrix4(cu2.OCSInv));
        let index = pts2.findIndex(p => equalv2(cu1Sp, p, tolerance));
        changeArrayStartIndex(buls2, index);
        changeArrayStartIndex(pts2, index);
        return equalArray(buls1, buls2, equaln) &&
            equalArray(pts1, pts2, (p1, p2) => equalv3(AsVector3(p1).applyMatrix4(cu1.OCS), AsVector3(p2).applyMatrix4(cu2.OCS), tolerance));
    }
    else if (cu1 instanceof Circle && cu2 instanceof Circle) {
        return equalv3(cu1.Center, cu2.Center) && equaln(cu1.Radius, cu2.Radius, 1e-6);
    }
    else if (cu1 instanceof Arc && cu2 instanceof Arc) {
        if (!equalv3(cu1.StartPoint, cu2.EndPoint))
            cu1.Reverse();
        return equalv3(cu1.Center, cu2.Center)
            && equaln(cu1.Radius, cu2.Radius, 1e-6)
            && equaln(cu1.StartAngle, cu2.StartAngle)
            && equaln(cu1.EndAngle, cu2.EndAngle);
    }
    else if (cu1 instanceof Ellipse && cu2 instanceof Ellipse) {
        return equalv3(cu1.Center, cu2.Center)
            && equaln(cu1.RadX, cu2.RadX)
            && equaln(cu1.RadY, cu2.RadY)
            && equalv3(cu1.StartPoint, cu2.StartPoint);
    }
    else if (cu1 instanceof Line && cu2 instanceof Line) {
        let ps1 = [cu1.StartPoint, cu1.EndPoint];
        let ps2 = [cu2.StartPoint, cu2.EndPoint];
        return ps1.every(p => ps2.some(p1 => equalv3(p1, p)));
    }
    return false;
}
function ConverCircleToPolyline(cir) {
    //该写法不支持三维坐标系
    // let pl = new Polyline();
    // let bul = Math.tan(Math.PI * 0.125);
    // for (let i = 0; i < 4; i++)
    // {
    //     let p = cir.GetPointAtParam(i * 0.25);
    //     pl.AddVertexAt(i, Vec3DTo2D(p));
    //     pl.SetBulgeAt(i, bul);
    // }
    // pl.CloseMark = true;
    // return pl;
    let arcs = cir.GetSplitCurves([0, 0.5]);
    let pl = new exports.Polyline();
    pl.OCS = cir.OCS;
    pl.Join(arcs[0]);
    pl.Join(arcs[1]);
    return pl;
}
function GetTanPtsOnArcOrCircle(cu, lastPoint) {
    if (lastPoint) {
        //ref:wykobi
        let ocsInv = cu.OCSInv;
        let v = lastPoint.clone().applyMatrix4(ocsInv);
        let lengthSq = v.lengthSq();
        let radiusSq = cu.Radius ** 2;
        if (lengthSq >= radiusSq) {
            let ratio = 1 / lengthSq;
            let deltaDist = Math.sqrt(lengthSq - radiusSq);
            let pts = [
                new three.Vector3(cu.Radius * (cu.Radius * v.x - v.y * deltaDist) * ratio, cu.Radius * (cu.Radius * v.y + v.x * deltaDist) * ratio),
                new three.Vector3(cu.Radius * (cu.Radius * v.x + v.y * deltaDist) * ratio, cu.Radius * (cu.Radius * v.y - v.x * deltaDist) * ratio),
            ];
            for (let p of pts)
                p.applyMatrix4(cu.OCS);
            return pts;
        }
    }
}
function getArcOrCirNearPts(cu, pickPoint, viewXform) {
    let viewNormal = new three.Vector3().fromArray(viewXform.elements, 2 * 3);
    let plane = new PlaneExt(cu.Normal, cu.Center);
    let pickLocal = plane.intersectLine(new three.Line3(pickPoint, pickPoint.clone().add(viewNormal)), new three.Vector3(), true);
    if (pickLocal) {
        let x = new three.Vector3().fromArray(viewXform.elements, 0).add(pickLocal);
        let y = new three.Vector3().fromArray(viewXform.elements, 3).add(pickLocal);
        x = plane.intersectLine(new three.Line3(x, x.clone().add(viewNormal)), new three.Vector3(), true);
        y = plane.intersectLine(new three.Line3(y, y.clone().add(viewNormal)), new three.Vector3(), true);
        let lx = new Line(pickLocal, x);
        let ly = new Line(pickLocal, y);
        let ins = cu.IntersectWith(lx, IntersectOption.ExtendBoth);
        ins.push(...cu.IntersectWith(ly, IntersectOption.ExtendBoth));
        return ins;
    }
    else {
        let ptLocal = plane.projectPoint(pickPoint, new three.Vector3());
        let lz = new Line(ptLocal, ptLocal.clone().add(viewNormal));
        return cu.IntersectWith(lz, IntersectOption.ExtendBoth);
    }
}
function getTanPtsOnEllipse(cu, lastPoint) {
    return [];
}
function SwapParam(res) {
    for (let r of res) {
        let p = r.thisParam;
        r.thisParam = r.argParam;
        r.argParam = p;
    }
    return res;
}
function ComputerCurvesNormalOCS(curves, allowAutoCalc = true) {
    if (!curves || curves.length === 0)
        return;
    //准备计算多段线的法向量
    let normal;
    let firstV;
    for (let c of curves) {
        if (c instanceof Arc) {
            normal = c.Normal;
            break;
        }
        else if (firstV) {
            let v = c.GetFistDeriv(0);
            v.cross(firstV);
            if (!equalv3(v, ZeroVec)) {
                normal = v.normalize();
                break;
            }
        }
        else {
            let cus = c.Explode();
            let ocs = ComputerCurvesNormalOCS(cus, false);
            if (ocs)
                return ocs;
            firstV = c.GetFistDeriv(0);
        }
    }
    if (!normal && !allowAutoCalc)
        return;
    let x = new three.Vector3();
    let y = new three.Vector3();
    if (!normal) {
        normal = firstV.normalize();
        Orbit.ComputUpDirection(normal, y, x);
        [x, y, normal] = [normal, x, y];
    }
    else {
        if (equalv3(normal, curves[0].Normal.negate()))
            normal.negate();
        Orbit.ComputUpDirection(normal, y, x);
    }
    return new three.Matrix4().makeBasis(x, y, normal).setPosition(curves[0].StartPoint);
}
function Pts2Polyline(pts, isClose) {
    let pl = new exports.Polyline();
    for (let i = 0; i < pts.length; i += 2) {
        let p1 = AsVector3(pts[i]);
        let arc;
        let p2;
        let p3;
        if (isClose) {
            p2 = AsVector3(pts[FixIndex(i + 1, pts.length)]);
            p3 = AsVector3(pts[FixIndex(i + 2, pts.length)]);
        }
        else {
            if (i >= pts.length - 2)
                break;
            p2 = AsVector3(pts[i + 1]);
            p3 = AsVector3(pts[i + 2]);
        }
        let v1 = p1.clone().sub(p2);
        let v2 = p2.clone().sub(p3);
        if (equaln(v1.angleTo(v2), 0))
            arc = new Line(p1, p3);
        else
            arc = new Arc().FromThreePoint(p1, p2, p3);
        pl.Join(arc);
    }
    return pl;
}

var Polyline_1;
exports.Polyline = Polyline_1 = class Polyline extends Curve {
    constructor(_LineData = []) {
        super();
        this._LineData = _LineData;
        this._ClosedMark = false;
    }
    UpdateMatrixTo(m) {
        this.WriteAllObjectRecord();
        let p = new three.Vector3().setFromMatrixPosition(m);
        p.applyMatrix4(this.OCSInv);
        if (equaln(p.z, 0)) {
            let dir = Math.sign(this.Area2);
            let tm = matrixAlignCoordSys(this.OCS, m);
            for (let p of this._LineData) {
                let p3 = AsVector3(p.pt);
                p3.applyMatrix4(tm);
                p.pt.set(p3.x, p3.y);
            }
            this.OCS = m;
            let newDir = Math.sign(this.Area2);
            if (dir !== newDir)
                for (let p of this._LineData)
                    p.bul *= -1;
        }
    }
    /**
     * 原地翻转,仅改变法向量
     */
    Flip() {
        this.WriteAllObjectRecord();
        let x = new three.Vector3();
        let y = new three.Vector3();
        let z = new three.Vector3();
        this._Matrix.extractBasis(x, y, z);
        z.negate();
        y.crossVectors(z, x);
        let p = this.Position;
        this._Matrix.makeBasis(x, y, z).setPosition(p);
        for (let d of this._LineData) {
            d.pt.y *= -1;
            d.bul *= -1;
        }
        this.Update();
        return this;
    }
    //翻转曲线,首尾调换
    Reverse() {
        if (this._LineData.length === 0)
            return this;
        this.WriteAllObjectRecord();
        let pts = [];
        let buls = [];
        for (let data of this._LineData) {
            pts.push(data.pt);
            buls.push(-data.bul);
        }
        let lastBul = buls.pop();
        buls.reverse();
        buls.push(lastBul);
        pts.reverse();
        if (this._ClosedMark && !equalv2(pts[0], arrayLast(pts))) {
            pts.unshift(pts.pop());
            buls.unshift(buls.pop());
        }
        for (let i = 0; i < pts.length; i++) {
            let d = this._LineData[i];
            d.pt = pts[i];
            d.bul = buls[i];
        }
        return this;
    }
    set LineData(data) {
        this.WriteAllObjectRecord();
        this._LineData = data;
        this.Update();
    }
    get LineData() {
        return this._LineData;
    }
    get NumberOfVertices() {
        return this._LineData.length;
    }
    /**
     * 在指定位置插入点.
     * 例如:
     * pl.AddVertexAt(pl.NumberOfVerticesk,p);//在末尾插入一个点
     *
     * @param {number} index 索引位置
     * @param {Vector2} pt 点
     * @returns {this}
     * @memberof Polyline
     */
    AddVertexAt(index, pt) {
        this.WriteAllObjectRecord();
        let pts;
        if (Array.isArray(pt)) {
            pts = pt.map(p => {
                return {
                    pt: p.clone(),
                    bul: 0
                };
            });
        }
        else
            pts = [{ pt: pt.clone(), bul: 0 }];
        this._LineData.splice(index, 0, ...pts);
        this.Update();
        return this;
    }
    RemoveVertexAt(index) {
        if (index < this._LineData.length) {
            this.WriteAllObjectRecord();
            this._LineData.splice(index, 1);
            this.Update();
        }
        return this;
    }
    RemoveVertexIn(from, to) {
        if (from + 1 < this._LineData.length && to > from) {
            this.WriteAllObjectRecord();
            this._LineData.splice(from + 1, to - from - 1);
            this.Update();
        }
        return this;
    }
    /**
     * 重设闭合多段线的起点
     * @param index 起始index,如果index非整数,将用最接近的整数作为起始索引
     */
    ResetStartPoint(index) {
        if (!this.IsClose || index >= this.EndParam)
            return false;
        if (equalv2(this._LineData[0].pt, arrayLast(this._LineData).pt))
            this._LineData.pop();
        changeArrayStartIndex(this._LineData, Math.floor(index + 0.5));
        this._LineData.push({
            pt: this._LineData[0].pt.clone(),
            bul: 0
        });
        return true;
    }
    GetPoint2dAt(index) {
        if (index >= 0 && this._LineData.length > index)
            return this._LineData[index].pt.clone();
    }
    /**
     * 设置指定点的位置
     *
     * @param {number} index
     * @param {Vector2} pt
     * @memberof Polyline
     */
    SetPointAt(index, pt) {
        let d = this._LineData[index];
        if (d) {
            this.WriteAllObjectRecord();
            d.pt.copy(pt);
            this.Update();
        }
        return this;
    }
    ApplyScaleMatrix(m) {
        this.WriteAllObjectRecord();
        for (let i = 0; i <= this.EndParam; i++) {
            let p = this.GetPointAtParam(i);
            p.applyMatrix4(m).applyMatrix4(this.OCSInv);
            this.SetPointAt(i, AsVector2(p));
        }
        return this;
    }
    ApplyMirrorMatrix(m) {
        this.WriteAllObjectRecord();
        let oldPts = this.GetStretchPoints();
        reviseMirrorMatrix(this._Matrix);
        for (let i = 0; i < oldPts.length; i++) {
            let newP = oldPts[i].applyMatrix4(this.OCSInv);
            let newBul = -this.GetBuilgeAt(i);
            this.SetPointAt(i, AsVector2(newP));
            this.SetBulgeAt(i, newBul);
        }
        this.Reverse();
        return this;
    }
    SetBulgeAt(index, bul) {
        let d = this._LineData[index];
        if (d) {
            this.WriteAllObjectRecord();
            d.bul = bul;
            this.Update();
        }
        return this;
    }
    GetBuilgeAt(index) {
        return this._LineData[index].bul;
    }
    Rectangle(length, height) {
        this.LineData = [
            { pt: new three.Vector2(), bul: 0 },
            { pt: new three.Vector2(length), bul: 0 },
            { pt: new three.Vector2(length, height), bul: 0 },
            { pt: new three.Vector2(0, height), bul: 0 }
        ];
        this.CloseMark = true;
        return this;
    }
    RectangleFrom2Pt(p1, p2) {
        let box = new three.Box3();
        box.setFromPoints([p2, p1].map((p) => p.clone().applyMatrix4(this.OCSInv)));
        let px1 = AsVector2(box.min);
        let px3 = AsVector2(box.max);
        let px2 = new three.Vector2(px3.x, px1.y);
        let px4 = new three.Vector2(px1.x, px3.y);
        this.LineData = [
            { pt: px1, bul: 0 },
            { pt: px2, bul: 0 },
            { pt: px3, bul: 0 },
            { pt: px4, bul: 0 }
        ];
        this.CloseMark = true;
        return this;
    }
    //多段线起点
    get StartPoint() {
        if (this._LineData.length > 0)
            return AsVector3(this._LineData[0].pt).applyMatrix4(this.OCS);
        return new three.Vector3();
    }
    set StartPoint(p) {
        this.WriteAllObjectRecord();
        p = p.clone().applyMatrix4(this.OCSInv);
        if (this._LineData.length === 0)
            this.AddVertexAt(0, AsVector2(p));
        else if (this._LineData.length === 1)
            this.SetPointAt(0, AsVector2(p));
        else {
            let bul = this.GetBuilgeAt(0);
            if (bul !== 0) {
                let arc = this.GetCurveAtParam(0);
                arc.StartPoint = p;
                //前面线的凸度调整
                this.SetBulgeAt(0, Math.tan(arc.AllAngle / 4) * Math.sign(bul));
            }
            this.SetPointAt(0, AsVector2(p));
        }
    }
    get EndPoint() {
        if (this._ClosedMark)
            return this.StartPoint;
        if (this._LineData.length > 0)
            return AsVector3(this._LineData[this.EndParam].pt).applyMatrix4(this.OCS);
        return new three.Vector3();
    }
    set EndPoint(p) {
        if (this._LineData.length < 2 || this.CloseMark)
            return;
        this.WriteAllObjectRecord();
        p = p.clone().applyMatrix4(this.OCSInv);
        let bul = this.GetBuilgeAt(this.EndParam - 1);
        if (bul !== 0) {
            let arc = this.GetCurveAtParam(this.EndParam - 1);
            arc.ApplyMatrix(this.OCSInv);
            arc.EndPoint = p;
            //前面线的凸度调整
            this.SetBulgeAt(this.EndParam - 1, Math.tan(arc.AllAngle / 4) * Math.sign(bul));
        }
        this.SetPointAt(this.EndParam, AsVector2(p));
    }
    get CurveCount() {
        return this.EndParam;
    }
    get StartParam() {
        return 0;
    }
    /**
     * 表示最后一条曲线的终止参数,使用该参数可以直接遍历到多段线的所有子线段. for(i<EndParam)...
     */
    get EndParam() {
        if (this._LineData.length === 0)
            return 0;
        //闭合且起点不等于终点
        if (this._ClosedMark &&
            !equalv2(this._LineData[0].pt, arrayLast(this._LineData).pt))
            return this._LineData.length;
        return this._LineData.length - 1;
    }
    get Area2() {
        if (this.EndParam < 2)
            return 0;
        let { pts, buls } = this.PtsBuls;
        let area = 0;
        for (let i = 0; i < pts.length - 1; i++) {
            let startV = pts[i];
            let endV = pts[i + 1];
            let det = getDeterminantFor2V(startV, endV);
            let bul = buls[i];
            if (bul !== 0) {
                let arc = new Arc().ParseFromBul(startV, endV, bul);
                let rSq = arc.Radius ** 2;
                //弓形面积
                let arcArea = rSq * arc.AllAngle * 0.5 - 0.5 * rSq * Math.sin(arc.AllAngle);
                //我们可以知道 正的凸度总是增加逆时针的面积, 负的凸度总是增加顺时针的面积
                det += arcArea * Math.sign(bul) * 2;
            }
            area += det;
        }
        return area / 2;
    }
    get Area() {
        return Math.abs(this.Area2);
    }
    //闭合标志
    get CloseMark() {
        return this._ClosedMark;
    }
    //曲线是否闭合
    get IsClose() {
        return this.CloseMark || (this.EndParam > 1 && (equalv3(this.StartPoint, this.EndPoint, 1e-4)));
    }
    set CloseMark(v) {
        this.WriteAllObjectRecord();
        this._ClosedMark = v;
        this.Update();
    }
    DigestionCloseMark() {
        if (this._ClosedMark && this._LineData.length > 1) {
            this.WriteAllObjectRecord();
            this._ClosedMark = false;
            if (!equalv2(this._LineData[0].pt, arrayLast(this._LineData).pt))
                this._LineData.push({ pt: AsVector2(this._LineData[0].pt), bul: 0 });
        }
    }
    get Length() {
        return this.Explode().reduce((l, cu) => l + cu.Length, 0);
    }
    /**
     * 获得指定参数所在的点.
     * 当曲线存在闭合标志时,参数必须在曲线内部.
     * 当曲线不存在闭合标志时,参数允许延伸出曲线.
     *
     * @param {number} param 参数
     * @returns {Vector3} 三维点,可为空
     * @memberof Polyline
     */
    GetPointAtParam(param) {
        if (param === Math.floor(param) && this.ParamOnCurve(param))
            return AsVector3(this.GetPoint2dAt(FixIndex(param, this.NumberOfVertices))).applyMatrix4(this.OCS);
        let cu = this.GetCurveAtParam(param);
        if (cu)
            return cu.GetPointAtParam(this.GetCurveParamAtParam(param));
        return undefined;
    }
    GetDistAtParam(param) {
        if (this._ClosedMark && !this.ParamOnCurve(param))
            return NaN;
        //参数 整数
        let paramFloor = Math.floor(param);
        //需要计算的曲线个数
        let cuCout = paramFloor > this.EndParam ? this.EndParam : paramFloor;
        let dist = 0;
        //首先计算完整曲线的长度
        for (let i = 0; i < cuCout; i++) {
            dist += this.GetCurveAtIndex(i).Length;
        }
        //参数已经大于索引,证明参数在线外.
        if (paramFloor !== cuCout) {
            dist += this.GetCurveAtParam(param).GetDistAtParam(param - cuCout);
        }
        else if (param > paramFloor) {
            let lastParam = param - paramFloor;
            dist += this.GetCurveAtParam(param).GetDistAtParam(lastParam);
        }
        return dist;
    }
    GetPointAtDistance(dist) {
        let param = this.GetParamAtDist(dist);
        return this.GetPointAtParam(param);
    }
    /**
     * 返回参数所在的点. 如果曲线不闭合,会试图返回延伸点参数
     *
     * @param {Vector3} pt
     * @returns {number}
     * @memberof Polyline
     */
    GetParamAtPoint(pt) {
        let cus = this.Explode();
        if (cus.length === 0)
            return NaN;
        for (let i = 0; i < cus.length; i++) {
            let cu = cus[i];
            let param = cu.GetParamAtPoint(pt);
            if (cu.ParamOnCurve(param))
                return i + param; //返回点在曲线内部的参数
        }
        //当曲线闭合时,不需要延伸首尾去判断参数
        if (this._ClosedMark)
            return NaN;
        //起点终点参数集合
        let seParams = [];
        //点在第一条曲线上的参数
        let startParam = cus[0].GetParamAtPoint(pt);
        if (!isNaN(startParam) && startParam < 0)
            seParams.push(startParam);
        //点在最后一条线上的参数
        let endParam = cus[cus.length - 1].GetParamAtPoint(pt);
        if (!isNaN(endParam) && endParam > 0)
            seParams.push(endParam + this.EndParam - 1);
        if (seParams.length == 1) {
            return seParams[0];
        }
        else if (seParams.length == 2) {
            //返回较近的参数
            if (pt.distanceToSquared(this.StartPoint)
                < pt.distanceToSquared(this.EndPoint))
                return seParams[0];
            else
                return seParams[1];
        }
        return NaN;
    }
    GetParamAtDist(dist) {
        let cus = this.Explode();
        for (let i = 0; i < cus.length; i++) {
            let cu = cus[i];
            let len = cu.Length;
            if (dist <= len)
                return i + cu.GetParamAtDist(dist);
            else if (equaln(dist, len, 1e-8))
                return i + 1;
            dist -= len;
        }
        if (!this._ClosedMark)
            return cus.length + cus[cus.length - 1].GetParamAtDist(dist);
        return NaN;
    }
    GetDistAtPoint(pt) {
        let param = this.GetParamAtPoint(pt);
        if (!this.ParamOnCurve(param))
            return NaN;
        return this.GetDistAtParam(param);
    }
    /**
     * 返回曲线的一阶导数.
     * 当曲线闭合(标志)且点不在曲线上.
     * 或者曲线不闭合(标志) 且点不在曲线上也不在延伸上
     *
     * @param {(number | Vector3)} param
     * @returns {Vector3}
     * @memberof Polyline
     */
    GetFistDeriv(param) {
        if (param instanceof three.Vector3)
            param = this.GetParamAtPoint(param);
        if (isNaN(param))
            return undefined;
        let cu = this.GetCurveAtParam(param);
        if (!cu)
            return undefined;
        return cu.GetFistDeriv(this.GetCurveParamAtParam(param));
    }
    GetSplitCurves(param) {
        //参数需要转化为参数数组
        let params;
        if (typeof param == "number")
            params = [param];
        else
            params = param;
        //校验参数在曲线中,修正参数
        let endParam = this.EndParam;
        params = params.filter(p => this.ParamOnCurve(p) && p > -1e-6)
            .map(a => {
            if (a < 0)
                return 0;
            if (a > endParam)
                return endParam;
            if (equaln(a, Math.floor(a + 0.5), 1e-8))
                return Math.floor(a + 0.5);
            return a;
        });
        //排序
        params.sort((a, b) => a - b);
        let hasEndParam = arrayLast(params) === this.EndParam;
        //必须加入最后一个参数,保证切割后的曲线完整
        if (!hasEndParam)
            params.push(this.EndParam);
        arrayRemoveDuplicateBySort(params, (e1, e2) => equaln(e1, e2, 1e-8));
        params = params.filter(p => this.ParamOnCurve(p));
        if (params.length === 0)
            return [];
        //判断是否存在0参数
        let hasZeroParam = params[0] === 0;
        if (hasZeroParam)
            params.shift();
        let { pts, buls } = this.PtsBuls;
        //返回的多段线集合
        let pls = [];
        let len = 0; //已经走过的参数长度(整数)
        //上一个切割参数的位置 0-1
        let prePa = 0;
        for (let pa of params) {
            //参数所在点
            let pt = AsVector2(this.GetPointAtParam(pa).applyMatrix4(this.OCSInv));
            pa -= len;
            let pafloor = Math.floor(pa);
            len += pafloor;
            let plData = [];
            //添加点
            for (let i = 0; i < pafloor; i++) {
                if (i === 0 && !equaln(buls[0], 0, 1e-8)) {
                    buls[0] = Math.tan((1 - prePa) * Math.atan(buls[0]));
                }
                plData.push({ pt: pts[0], bul: buls[0] });
                pts.shift();
                buls.shift();
            }
            if (equaln(pa, pafloor, 1e-8)) //如果pa在点上
             {
                plData.push({ pt: pts[0].clone(), bul: buls[0] });
            }
            else //在曲线上
             {
                let bul = buls[0];
                if (!equaln(bul, 0, 1e-6))
                    bul = Math.tan((pa - pafloor - (0 === pafloor ? prePa : 0)) * Math.atan(buls[0])); //->凸度
                //加入顶点+凸度
                plData.push({ pt: pts[0].clone(), bul });
                //终点
                plData.push({ pt, bul: 0 });
                //修正剩余的点表和凸度表
                pts[0].copy(pt);
            }
            prePa = pa - pafloor;
            if (plData.length > 1)
                pls.push(new Polyline_1(plData).ApplyMatrix(this.OCS));
        }
        //当曲线为闭合曲线,并且不存在0切割参数时,首尾连接曲线
        if (this._ClosedMark && !hasZeroParam && !hasEndParam) {
            let lastPl = pls[pls.length - 1];
            if (equalv2(arrayLast(lastPl._LineData).pt, pls[0]._LineData[0].pt))
                lastPl._LineData.pop();
            lastPl._LineData.push(...pls[0]._LineData);
            pls.shift();
        }
        return pls;
    }
    //未完善
    GetCurveAtParamRange(startParam, endParam) {
        let sfloor = Math.floor(startParam + 0.5);
        if (equaln(sfloor, startParam, 1e-8))
            startParam = sfloor;
        else
            sfloor = Math.floor(startParam);
        let efloor = Math.floor(endParam + 0.5);
        if (equaln(efloor, endParam, 1e-8))
            endParam = efloor;
        else
            efloor = Math.floor(efloor);
        const GetCurve = (index) => {
            let d = this._LineData[index];
            let next = this._LineData[index + 1];
            if (!equaln(d.bul, 0, 1e-8))
                return new Arc().ParseFromBul(d.pt, next.pt, d.bul);
            else
                return new Line(AsVector3(d.pt), AsVector3(next.pt));
        };
        let lined = [];
        if (startParam === sfloor) {
            let d = this._LineData[sfloor];
            lined.push({ pt: d.pt.clone(), bul: d.bul });
        }
        else {
            let d = this._LineData[sfloor];
            let cu = GetCurve(sfloor);
            let remParam = startParam - sfloor;
            let p = cu.GetPointAtParam(remParam);
            let bul = d.bul;
            if (!equaln(bul, 0))
                bul = Math.tan(Math.atan(bul) * (1 - remParam));
            lined.push({ pt: AsVector2(p), bul: bul });
        }
        for (let i = sfloor + 1; i < efloor; i++) {
            let d = this._LineData[i];
            lined.push({ pt: d.pt.clone(), bul: d.bul });
        }
        if (efloor !== endParam) {
            let d = this.LineData[efloor];
            let remParam = endParam - efloor;
            let cu = GetCurve(efloor);
            let p = cu.GetPointAtParam(remParam);
            let bul = d.bul;
            if (!equaln(bul, 0)) {
                arrayLast(lined).bul = Math.tan(Math.atan(bul) * remParam);
                bul = Math.tan(Math.atan(bul) * (1 - remParam));
            }
            lined.push({ pt: AsVector2(p), bul });
        }
        let pl = new Polyline_1(lined);
        pl.OCS = this.OCSNoClone;
        return;
    }
    Extend(newParam) {
        if (this.CloseMark || this.ParamOnCurve(newParam))
            return;
        this.WriteAllObjectRecord();
        let ptIndex;
        let bulIndex;
        if (newParam < 0) {
            ptIndex = 0;
            bulIndex = 0;
        }
        else if (newParam > this.EndParam) {
            ptIndex = this.EndParam;
            bulIndex = ptIndex - 1;
        }
        //修改顶点
        this._LineData[ptIndex].pt = AsVector2(this.GetPointAtParam(newParam).applyMatrix4(this.OCSInv));
        //修改凸度
        let oldBul = this._LineData[bulIndex].bul;
        if (oldBul != 0)
            this._LineData[bulIndex].bul = Math.tan(Math.atan(oldBul) * (1 + newParam - ptIndex));
        this.Update();
    }
    //const this
    MatrixAlignTo2(toMatrix) {
        if (!matrixIsCoplane(this._Matrix, toMatrix, 1e-4))
            return this.PtsBuls;
        let m = matrixAlignCoordSys(this._Matrix, toMatrix);
        let z1 = this.Normal;
        let z2 = new three.Vector3().setFromMatrixColumn(toMatrix, 2);
        let isMirror = equalv3(z1, z2.negate());
        let pts = [];
        let buls = [];
        for (let d of this._LineData) {
            let p = AsVector2(AsVector3(d.pt).applyMatrix4(m));
            pts.push(p);
            buls.push(isMirror ? -d.bul : d.bul);
        }
        return { pts, buls };
    }
    Join(cu, allowGap = false, tolerance = 1e-4) {
        this.WriteAllObjectRecord();
        if (this._ClosedMark)
            return Status.False;
        let [sp, ep, cuSp, cuEp] = [this.StartPoint, this.EndPoint, cu.StartPoint, cu.EndPoint];
        let ocsInv = this.OCSInv;
        let [cuSp2, cuEp2] = [cuSp, cuEp].map(p => AsVector2(p.clone().applyMatrix4(ocsInv)));
        if (this._LineData.length === 0) {
            if (cu instanceof Line) {
                this._LineData.push({ pt: cuSp2, bul: 0 });
                this._LineData.push({ pt: cuEp2, bul: 0 });
            }
            else if (cu instanceof Arc) {
                this._LineData.push({ pt: cuSp2, bul: cu.Bul });
                this._LineData.push({ pt: cuEp2, bul: 0 });
            }
            else if (cu instanceof Polyline_1) {
                let f = new CADFiler();
                cu.WriteFile(f);
                this.ReadFile(f);
            }
            else
                return Status.False;
        }
        else {
            let LinkType;
            (function (LinkType) {
                LinkType[LinkType["None"] = 0] = "None";
                LinkType[LinkType["SpSp"] = 1] = "SpSp";
                LinkType[LinkType["SpEp"] = 2] = "SpEp";
                LinkType[LinkType["EpSp"] = 3] = "EpSp";
                LinkType[LinkType["EpEp"] = 4] = "EpEp";
            })(LinkType || (LinkType = {}));
            let spspDisSq = cuSp.distanceToSquared(sp);
            let spepDisSq = cuSp.distanceToSquared(ep);
            let epspDisSq = cuEp.distanceToSquared(sp);
            let epepDisSq = cuEp.distanceToSquared(ep);
            let minDis = tolerance * tolerance;
            let linkType = LinkType.None;
            if (spspDisSq < minDis) {
                linkType = LinkType.SpSp;
                minDis = spspDisSq;
            }
            if (spepDisSq < minDis) {
                linkType = LinkType.SpEp;
                minDis = spepDisSq;
            }
            if (epspDisSq < minDis) {
                linkType = LinkType.EpSp;
                minDis = epspDisSq;
            }
            if (epepDisSq < minDis)
                linkType = LinkType.EpEp;
            if (linkType === LinkType.None)
                return Status.False;
            if (cu instanceof Line) {
                if (linkType === LinkType.SpSp) {
                    this._LineData.unshift({ pt: cuEp2, bul: 0 });
                }
                else if (linkType === LinkType.SpEp) {
                    this._LineData.push({ pt: cuEp2, bul: 0 });
                }
                else if (linkType === LinkType.EpSp) {
                    this._LineData.unshift({ pt: cuSp2, bul: 0 });
                }
                else if (linkType === LinkType.EpEp) {
                    this._LineData.push({ pt: cuSp2, bul: 0 });
                }
            }
            else if (cu instanceof Arc) {
                let dir = equalv3(this.Normal, cu.Normal.negate()) ? -1 : 1;
                let bul = cu.Bul * dir;
                if (linkType === LinkType.SpSp) {
                    this._LineData.unshift({ pt: cuEp2, bul: -bul });
                }
                else if (linkType === LinkType.SpEp) {
                    arrayLast(this._LineData).bul = bul;
                    this._LineData.push({ pt: cuEp2, bul: 0 });
                }
                else if (linkType === LinkType.EpSp) {
                    this._LineData.unshift({ pt: cuSp2, bul: bul });
                }
                else if (linkType === LinkType.EpEp) {
                    arrayLast(this._LineData).bul = -bul;
                    this._LineData.push({ pt: cuSp2, bul: 0 });
                }
            }
            else if (cu instanceof Polyline_1) {
                if (cu.CloseMark)
                    return Status.False;
                let { pts, buls } = this.PtsBuls;
                if (linkType === LinkType.SpSp) {
                    cu.Reverse();
                    let cuPtsBul = cu.MatrixAlignTo2(this.OCS);
                    cuPtsBul.pts.pop();
                    cuPtsBul.buls.pop();
                    pts = cuPtsBul.pts.concat(pts);
                    buls = cuPtsBul.buls.concat(buls);
                }
                else if (linkType === LinkType.SpEp) {
                    pts.pop();
                    buls.pop();
                    let cuPtsBul = cu.MatrixAlignTo2(this.OCS);
                    pts = pts.concat(cuPtsBul.pts);
                    buls = buls.concat(cuPtsBul.buls);
                }
                else if (linkType === LinkType.EpSp) {
                    let cuPtsBul = cu.MatrixAlignTo2(this.OCS);
                    cuPtsBul.pts.pop();
                    cuPtsBul.buls.pop();
                    pts = cuPtsBul.pts.concat(pts);
                    buls = cuPtsBul.buls.concat(buls);
                }
                else if (linkType === LinkType.EpEp) {
                    pts.pop();
                    buls.pop();
                    cu.Reverse();
                    let cuPtsBul = cu.MatrixAlignTo2(this.OCS);
                    pts = pts.concat(cuPtsBul.pts);
                    buls = buls.concat(cuPtsBul.buls);
                }
                this._LineData.length = 0;
                for (let i = 0; i < pts.length; i++) {
                    this._LineData.push({ pt: pts[i], bul: buls[i] });
                }
            }
            else
                return Status.False;
        }
        //在上面的其他分支已经返回了假 所以这里直接返回真.
        this.Update();
        return Status.True;
    }
    /**
     * 将曲线数组组合成多段线
     * @param curves 已经使用CurveLinked的数组,总是首尾相连
     * @returns
     */
    static Combine(curves, tolerance = 1e-5) {
        if (!curves || curves.length === 0)
            return;
        let pl = new Polyline_1;
        pl.OCS = ComputerCurvesNormalOCS(curves);
        for (let cu of curves)
            pl.Join(cu, false, tolerance);
        let d = pl.LineData;
        if (d.length > 1) {
            let ld = arrayLast(d).pt;
            if (equalv2(d[0].pt, ld, tolerance))
                ld.copy(d[0].pt);
        }
        return pl;
    }
    PtOnCurve(pt) {
        for (let i = 0; i < this.EndParam; i++) {
            let c = this.GetCurveAtIndex(i);
            if (c.PtOnCurve(pt))
                return true;
        }
        return false;
    }
    //点在曲线上,已经确定点在曲线的延伸线上
    PtOnCurve3(p, fuzz = 1e-6) {
        for (let i = 0; i < this.EndParam; i++) {
            let c = this.GetCurveAtIndex(i);
            if (c.PtOnCurve3(p, fuzz))
                return true;
        }
        return false;
    }
    PtInCurve(pt) {
        return this.IsClose && IsPointInPolyLine(this, pt);
    }
    GetClosestPointTo(pt, extend) {
        return this.GetClosestPointTo2(pt, extend ? ExtendType.Both : ExtendType.None);
    }
    GetClosestPointTo2(pt, extType) {
        //当曲线空时,返回空
        if (this.EndParam < 1)
            return undefined;
        //当有闭合标志时,曲线在任何位置都不延伸
        if (this._ClosedMark)
            extType = ExtendType.None;
        //最近点
        let ptC = undefined;
        //最近点的距离
        let ptCDist = Infinity;
        for (let i = 0; i < this.EndParam; i++) {
            let cu = this.GetCurveAtIndex(i);
            //前延伸
            if (i === 0 && (extType & ExtendType.Front) > 0) {
                let ptCFirst = cu.GetClosestPointTo(pt, true);
                if (cu.GetParamAtPoint(ptCFirst) <= 1) {
                    ptC = ptCFirst;
                    ptCDist = ptC.distanceToSquared(pt);
                }
                if (extType === ExtendType.Front)
                    continue;
            }
            let ptCloseNew; //新的最近点
            //后延伸  (此处与前延伸分开if 如果线只有一段,那么前后延伸都能同时触发)
            if (i === (this.EndParam - 1) && (extType & ExtendType.Back) > 0) {
                let ptCLast = cu.GetClosestPointTo(pt, true);
                if (cu.GetParamAtPoint(ptCLast) >= 0)
                    ptCloseNew = ptCLast;
                else //如果延伸之后并不在曲线或者曲线的后延伸上
                    ptCloseNew = cu.EndPoint;
            }
            else {
                ptCloseNew = cu.GetClosestPointTo(pt, false);
            }
            let newDist = ptCloseNew.distanceToSquared(pt);
            if (newDist < ptCDist) {
                ptC = ptCloseNew;
                ptCDist = newDist;
            }
        }
        return ptC;
    }
    //偏移
    GetOffsetCurves(offsetDist) {
        if (equaln(offsetDist, 0))
            return [];
        let polyOffestUtil = new OffsetPolyline(this, offsetDist);
        let curves = polyOffestUtil.Do();
        for (let cu of curves)
            cu.ColorIndex = this.ColorIndex;
        return curves;
    }
    GetFeedingToolPath(offsetDist) {
        if (equaln(offsetDist, 0))
            return [];
        let polyOffestUtil = new OffsetPolyline(this, offsetDist, true);
        return polyOffestUtil.Do();
    }
    /**
     * 分解
     */
    Explode() {
        let exportCus = [];
        for (let i = 0; i < this.EndParam; i++) {
            exportCus.push(this.GetCurveAtIndex(i));
        }
        return exportCus;
    }
    /**
     * 根据参数得到参数所在的子曲线.
     *
     * 当曲线存在闭合标志时,参数必须在曲线内部,否则返回空.
     *
     * @param {number} param 参数值
     * @returns {Curve} 曲线(直线或者圆弧) 或空
     * @memberof Polyline
     */
    GetCurveAtParam(param) {
        if (this._ClosedMark && !this.ParamOnCurve(param))
            return undefined;
        if (param < 0)
            return this.GetCurveAtIndex(0);
        else if (param >= this.EndParam)
            return this.GetCurveAtIndex(this.EndParam - 1);
        else
            return this.GetCurveAtIndex(Math.floor(param));
    }
    /**
     * 得到参数在子曲线中的表示
     *
     * @param {number} param 参数在多段线中表示
     * @returns {number} 参数在子曲线中表示
     * @memberof Polyline
     */
    GetCurveParamAtParam(param) {
        if (param >= this.EndParam)
            param -= this.EndParam - 1;
        else if (param > 0)
            param -= Math.floor(param);
        return param;
    }
    /**
     * 获得曲线,来自索引位置.
     * @param {number} i 索引位置 整数
     */
    GetCurveAtIndex(i) {
        if (i >= this._LineData.length)
            return undefined;
        if (!this.ParamOnCurve(i))
            return undefined;
        if (!this._ClosedMark && i === this._LineData.length - 1)
            return undefined;
        let d1 = this._LineData[i];
        let d2 = this._LineData[FixIndex(i + 1, this._LineData)];
        let curve;
        if (equaln(d1.bul, 0, 1e-8))
            curve = new Line(AsVector3(d1.pt), AsVector3(d2.pt)).ApplyMatrix(this.OCS);
        else
            curve = new Arc().ParseFromBul(d1.pt, d2.pt, d1.bul).ApplyMatrix(this.OCS);
        curve.ColorIndex = this._Color;
        return curve;
    }
    IntersectWith2(curve, intType, tolerance = 1e-5) {
        return IntersectPolylineAndCurve(this, curve, intType, tolerance);
    }
    //计算自交点.
    IntersectSelf() {
        let cus = this.Explode();
        if (cus.length === 0)
            return [];
        let intParams = [];
        for (let i = 0; i < cus.length; i++) {
            let c = cus[i];
            for (let j = i + 2; j < cus.length; j++) {
                let c2 = cus[j];
                let pts = c.IntersectWith(c2, IntersectOption.OnBothOperands);
                for (let p of pts) {
                    intParams.push(i + c.GetParamAtPoint(p));
                    intParams.push(j + c2.GetParamAtPoint(p));
                }
            }
        }
        return intParams;
    }
    get BoundingBox() {
        let box = new three.Box3();
        for (let i = 0; i < this.EndParam; i++) {
            let cu = this.GetCurveAtIndex(i);
            box.union(cu.BoundingBox);
        }
        return box;
    }
    /**
     * 得到曲线有用的点表和凸度(闭合曲线首尾重复)
     */
    get PtsBuls() {
        let pts = [];
        let buls = [];
        if (this._LineData.length === 0)
            return { pts, buls };
        for (let data of this._LineData) {
            pts.push(data.pt.clone());
            buls.push(data.bul);
        }
        //闭合且起点不等于终点
        if (this._ClosedMark &&
            !this._LineData[0].pt.equals(arrayLast(this._LineData).pt)) {
            pts.push(pts[0].clone());
            buls.push(buls[0]);
        }
        return { pts, buls };
    }
    get IsBulge() {
        if (!this.IsClose)
            return false;
        let refDir = Math.sign(this.Area2);
        let c1;
        let c2;
        for (let i = 0; i < this.EndParam; i++) {
            c1 = this.GetCurveAtIndex(i);
            c2 = this.GetCurveAtIndex(FixIndex(i + 1, this.EndParam));
            let len1 = c1.Length;
            let len2 = c2.Length;
            let minLen = Math.min(len1, len2) * 0.2;
            let p = c1.EndPoint;
            let p1;
            let p2;
            if (c1 instanceof Arc) {
                let dir = c1.IsClockWise ? -1 : 1;
                if (dir !== refDir)
                    return false;
                p1 = c1.GetPointAtDistance(len1 - minLen);
            }
            else
                p1 = c1.StartPoint;
            if (c2 instanceof Arc) {
                let dir = c2.IsClockWise ? -1 : 1;
                if (dir !== refDir)
                    return false;
                p2 = c2.GetPointAtDistance(minLen);
            }
            else
                p2 = c2.EndPoint;
            let vec1 = p.clone().sub(p1);
            let vec2 = p2.sub(p);
            let dir = Math.sign(vec1.cross(vec2).z);
            if (dir !== 0 && dir !== refDir)
                return false;
        }
        return true;
    }
    get Shape() {
        let { pts, buls } = this.PtsBuls;
        let curve = CreateBoardUtil.CreatePath(pts, buls);
        return curve;
    }
    get SVG() {
        let sp = this.StartPoint;
        let str = `M${sp.x} ${sp.y} `;
        for (let i = 1; i <= this.EndParam; i++) {
            let bul = this.GetBuilgeAt(i - 1);
            let p = this.GetPointAtParam(i);
            if (bul === 0)
                str += `L${p.x} ${p.y} `;
            else {
                let arc = this.GetCurveAtIndex(i - 1);
                str += `A ${arc.Radius} ${arc.Radius} 0 ${Math.abs(bul) >= 1 ? 1 : 0} ${arc.IsClockWise ? 0 : 1} ${p.x} ${p.y}`;
            }
        }
        return str;
    }
    InitDrawObject(renderType = RenderType.Wireframe) {
        let shape = this.Shape;
        let geo = BufferGeometryUtils.CreateFromPts(shape.getPoints(50).map(AsVector3));
        if (renderType === RenderType.Print) {
            var geometry = new LineGeometry.LineGeometry().setPositions(geo.attributes.position.array);
            return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
        }
        let obj = new three.Line(geo, ColorMaterial.GetLineMaterial(this._Color));
        return obj;
    }
    UpdateDrawObject(type, en) {
        let shape = this.Shape;
        let pts = shape.getPoints(50).map(AsVector3);
        let plObj = en;
        let geo = plObj.geometry;
        if (!BufferGeometryUtils.UpdatePts(geo, pts)) {
            updateGeometry(plObj, BufferGeometryUtils.CreateFromPts(pts));
        }
    }
    GetDragPointCount(drag) {
        if (drag === DragPointType.Grip) {
            let count = this.EndParam * 2 + 1;
            if (this.CloseMark)
                count--;
            return count;
        }
        else {
            return this._LineData.length;
        }
    }
    GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
        switch (snapMode) {
            case ObjectSnapMode.End:
                return this.GetStretchPoints();
            case ObjectSnapMode.Mid:
                let midPts = [];
                let enParam = this.EndParam;
                for (let i = 0.5; i < enParam; i++) {
                    let p = this.GetPointAtParam(i);
                    p && midPts.push(p);
                }
                return midPts;
            case ObjectSnapMode.Nea:
                {
                    let nea = [];
                    for (let cu of this.Explode()) {
                        let neaa = cu.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform);
                        if (neaa)
                            nea.push(...neaa);
                    }
                    return nea;
                }
            case ObjectSnapMode.Ext:
                {
                    let cp = this.GetClosestPointTo(pickPoint, true);
                    if (cp)
                        return [cp];
                    break;
                }
            case ObjectSnapMode.Cen:
                let cenPts = [];
                for (let i = 0; i < this._LineData.length; i++) {
                    let data = this._LineData[i];
                    if (!equaln(data.bul, 0)) {
                        let cu = this.GetCurveAtIndex(i);
                        if (cu) //end bul !== 0 但是并没有圆弧
                            cenPts.push(cu.Center);
                    }
                }
                return cenPts;
            case ObjectSnapMode.Per:
                if (lastPoint) {
                    let cp = this.GetClosestPointTo(pickPoint, false);
                    if (!cp)
                        return [];
                    let cparam = this.GetParamAtPoint(cp);
                    let cu = this.GetCurveAtParam(cparam);
                    if (cu) {
                        let closestPt = cu.GetClosestPointTo(lastPoint, true);
                        if (closestPt && this.PtOnCurve(closestPt))
                            return [closestPt];
                    }
                }
            case ObjectSnapMode.Tan:
                if (lastPoint) {
                    let clostPt = this.GetClosestPointTo(pickPoint, false);
                    if (!clostPt)
                        return [];
                    let par = this.GetParamAtPoint(clostPt);
                    let cu = this.GetCurveAtParam(par);
                    if (cu instanceof Arc)
                        return cu.GetObjectSnapPoints(snapMode, pickPoint, lastPoint);
                    return [];
                }
        }
        return [];
    }
    GetGripPoints() {
        let ptList = [];
        if (this._LineData.length < 2)
            return ptList;
        let enParam = this.EndParam;
        if (this.CloseMark)
            enParam -= 0.5;
        for (let i = 0; i < enParam + 0.5; i += 0.5) {
            let p = this.GetPointAtParam(i);
            ptList.push(p);
        }
        return ptList;
    }
    MoveGripPoints(indexList, moveVec) {
        this.WriteAllObjectRecord();
        let moveVLoc = AsVector2(moveVec.clone().applyMatrix4(new three.Matrix4().extractRotation(this.OCSInv)));
        let calcIndexList = indexList;
        if (indexList.length > 1) {
            let centerIndexes = indexList.filter(i => i % 2 === 0);
            if (centerIndexes.length > 0)
                calcIndexList = centerIndexes;
        }
        for (let index of calcIndexList) {
            if (index % 2 === 0) {
                let cuIndex = index / 2;
                let ptCout = this._LineData.length;
                let frontIndex = cuIndex - 1;
                if (this._ClosedMark)
                    frontIndex = FixIndex(frontIndex, ptCout);
                if (frontIndex >= 0 && this.GetBuilgeAt(frontIndex)) {
                    let arc = this.GetCurveAtIndex(frontIndex);
                    arc.MoveGripPoints([2], moveVec);
                    this._LineData[frontIndex].bul = arc.Bul;
                }
                if ((cuIndex !== ptCout - 1) && this.GetBuilgeAt(cuIndex)) {
                    let arc = this.GetCurveAtIndex(cuIndex);
                    arc.MoveGripPoints([0], moveVec);
                    this._LineData[cuIndex].bul = arc.Bul;
                }
                this._LineData[cuIndex].pt.add(moveVLoc);
            }
            else {
                let ptIndex = (index - 1) / 2;
                let nextIndex = (FixIndex(ptIndex + 1, this._LineData));
                let d = this._LineData[ptIndex];
                if (d.bul == 0) {
                    this._LineData[ptIndex].pt.add(moveVLoc);
                    this._LineData[nextIndex].pt.add(moveVLoc);
                }
                else {
                    let arc = this.GetCurveAtIndex(ptIndex);
                    arc.MoveGripPoints([1], moveVec);
                    this._LineData[ptIndex].bul = arc.Bul;
                }
            }
        }
        this.Update();
    }
    GetStretchPoints() {
        let ocs = this.OCS;
        let ptList = [];
        for (let data of this._LineData) {
            ptList.push(AsVector3(data.pt).applyMatrix4(ocs));
        }
        return ptList;
    }
    /**
     * 范围拉伸(stretch),对夹点进行拉伸.
     * 如果对圆弧的一侧进行拉伸,那么修改bul
     *
     * @param {Array<number>} indexList
     * @param {Vector3} vec
     * @memberof Polyline
     */
    MoveStretchPoints(indexList, vec) {
        this.WriteAllObjectRecord();
        //本地坐标系移动向量
        let moveVLoc = vec.clone().applyMatrix4(new three.Matrix4().extractRotation(this.OCSInv));
        let ptCout = this._LineData.length;
        for (let index of indexList) {
            let frontIndex = index - 1;
            let nextIndex = index + 1;
            if (this._ClosedMark) {
                frontIndex = FixIndex(frontIndex, ptCout);
                nextIndex = FixIndex(nextIndex, ptCout);
            }
            /**
             * 根据新的拉伸点修改凸度.
             *
             * @param {number} nextIndex 隔壁点索引
             * @param {number} bulIndex 需要修改凸度位置的索引
             * @returns
             */
            const ChangeBul = (nextIndex, bulIndex) => {
                //需要修改的点的数据
                let d = this._LineData[bulIndex];
                if (d === undefined || d.bul == 0)
                    return;
                //如果隔壁点不在拉伸列表中
                if (indexList.indexOf(nextIndex) === -1) {
                    let needChangeP = this.GetPointAtParam(index);
                    let notChangeP = this.GetPointAtParam(nextIndex);
                    //原先的弦长的一半
                    let oldChordLengthHalf = needChangeP.distanceTo(notChangeP) * 0.5;
                    //弓高
                    let arcHeight = oldChordLengthHalf * d.bul;
                    needChangeP.add(vec);
                    let newChordLengthHalf = needChangeP.distanceTo(notChangeP) * 0.5;
                    d.bul = arcHeight / newChordLengthHalf;
                }
            };
            ChangeBul(frontIndex, frontIndex);
            ChangeBul(nextIndex, index);
            //修改顶点
            this._LineData[index].pt.add(AsVector2(moveVLoc));
        }
        this.Update();
    }
    _ReadFile(file) {
        super._ReadFile(file);
        let ver = file.Read();
        this._LineData.length = 0;
        let cout = file.Read();
        for (let i = 0; i < cout; i++) {
            let v = new three.Vector2().fromArray(file.Read());
            let bul = file.Read();
            this._LineData.push({ pt: v, bul: bul });
        }
        if (ver > 1)
            this._ClosedMark = file.Read();
    }
    //对象将自身数据写入到文件.
    WriteFile(file) {
        super.WriteFile(file);
        file.Write(2);
        file.Write(this._LineData.length);
        for (let l of this._LineData) {
            file.Write(l.pt.toArray());
            file.Write(l.bul);
        }
        file.Write(this._ClosedMark);
    }
};
exports.Polyline = Polyline_1 = __decorate([
    Factory
], exports.Polyline);
const TempPolyline = new exports.Polyline();

exports.TempPolyline = TempPolyline;
//# sourceMappingURL=api.cjs.js.map
