"use strict";
/*
 * @Author       : 赵耀圣
 * @Date         : 2020-12-10 15:01:42
 * @QQ           : 549184003
 * @LastEditTime : 2021-09-07 15:40:10
 * @FilePath     : \cesium-taji-dabaod:\github\cga.js\src\struct\3d\Path.ts
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Path = void 0;
var Vec3_1 = require("../../math/Vec3");
var Math_1 = require("../../math/Math");
var types_1 = require("../../utils/types");
var ArrayList_1 = require("../data/ArrayList");
var pointset_1 = require("../../alg/pointset");
var common_1 = require("../../alg/common");
var Path = /** @class */ (function (_super) {
    __extends(Path, _super);
    /**
     *
     * @param vs  假定是没有重复的点集
     * @param closed
     * @param calcNormal
     */
    function Path(vs, closed, calcNormal) {
        if (closed === void 0) { closed = false; }
        if (calcNormal === void 0) { calcNormal = false; }
        var _this = _super.call(this, vs) || this;
        _this._calcNoraml = false;
        _this._closed = closed;
        _this.init(calcNormal);
        return _this;
    }
    Path.prototype.init = function (calcNormal) {
        if (this.length === 0)
            return;
        this.get(0).len = 0;
        this.get(0).tlen = 0;
        var end = this.length;
        for (var i = 0; i < end; i++) {
            var e = this.get(i);
            if (i !== 0) {
                e.len = this.get(i).distanceTo(this.get(i - 1));
                e.tlen = this.get(i - 1).tlen + e.len;
            }
            this.get(i).direction = this.get((i + 1) % this.length).clone().sub(this.get(i)).normalize();
        }
        if (!this._closed) {
            this.get(-1).direction.copy(this.get(-2).direction);
        }
        if (calcNormal) {
            for (var i = 0; i < end; i++) {
                var d1 = this.get(i - 1).direction;
                var d2 = this.get(i).direction;
                // if (Math.abs(d1.dot(d2) - 1) > delta6) {
                //应该同时考虑长度差        
                //normal是两条线段所在的平面的法线
                //bdirection是两条方向线的等分线
                //TODO
                var normal = new Vec3_1.Vec3();
                normal.crossVecs(d1, d2).normalize();
                this.get(i).normal = normal;
                var bdir = (0, Vec3_1.v3)().addVecs(d1, d2).normalize();
                this.get(i).bdirection = bdir;
                this.get(i).bnormal = (0, Vec3_1.v3)().crossVecs(bdir, normal).normalize();
                // }
            }
            if (!this._closed) { //不闭合路径 最后一个点没有
                this.get(-1).bdirection = (0, Vec3_1.v3)();
                this.get(-1).normal = (0, Vec3_1.v3)();
                this.get(-1).bnormal = (0, Vec3_1.v3)();
            }
            if (!this._closed) {
                // 不闭合的情况下怎么样去计算端点的up和normal
                this.get(0).normal.copy(this.get(1).normal);
                this.get(0).bdirection.copy(this.get(0).direction);
                var bdir = this.get(0).bdirection;
                this.get(0).bnormal.crossVecs(bdir, this.get(0).normal);
                this.get(-1).normal.copy(this.get(-2).normal);
                this.get(-1).bdirection.copy(this.get(-1).direction);
                bdir = this.get(-1).bdirection;
                this.get(-1).bnormal.crossVecs(bdir, this.get(-1).normal).normalize();
            }
        }
    };
    Object.defineProperty(Path.prototype, "closed", {
        get: function () {
            return this._closed;
        },
        set: function (val) {
            this._closed = val;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Path.prototype, "tlen", {
        get: function () {
            if (this.length === 0)
                return 0;
            return Math.max(this.get(-1).tlen, this.get(0).tlen);
        },
        enumerable: false,
        configurable: true
    });
    Path.prototype.applyMat4 = function (mat4) {
        (0, pointset_1.applyMat4)(this._array, mat4);
    };
    Path.prototype.scale = function (x, y, z) {
        (0, common_1.scale)(this._array, (0, Vec3_1.v3)(x, y, z), true);
    };
    /**
     * 截取一段从from到to的path
     * @param {Number} from
     * @param {Number} to
     */
    Path.prototype.splitByFromToDistance = function (from, to) {
        if (from === void 0) { from = 0; }
        if (to === void 0) { to = 0; }
        if (to <= from)
            return null;
        var newPath = new Path([]);
        for (var i = 0; i < this.length - 1; i++) {
            var pt = this.get(i);
            var ptnext = this.get(i + 1);
            if (pt.tlen <= from && ptnext.tlen >= from) {
                var v3 = new Vec3_1.Vec3().lerpVecs(pt, ptnext, (from - pt.tlen) / (ptnext.tlen - pt.tlen));
                newPath.add(v3);
            }
            if (pt.tlen > from && pt.tlen < to) {
                newPath.add(pt.clone());
            }
            if (pt.tlen <= to && ptnext.tlen >= to) {
                var v3 = new Vec3_1.Vec3().lerpVecs(pt, ptnext, (to - pt.tlen) / (ptnext.tlen - pt.tlen));
                newPath.add(v3);
                return newPath;
            }
        }
        return newPath;
    };
    /**
     * 从起点出发到距离等于distance位置  的坐标 二分查找
     * @param {Number} distance
     */
    Path.prototype.getPointByDistance = function (arg_distance, left, right) {
        if (left === void 0) { left = 0; }
        if (right === void 0) { right = this.length - 1; }
        var distance = (0, Math_1.clamp)(arg_distance, 0, this.get(-1).tlen);
        if (distance !== arg_distance)
            return null;
        if (right - left === 1) {
            return {
                isNode: false,
                point: new Vec3_1.Vec3().lerpVecs(this.get(left), this.get(right), (distance - this.get(left).tlen) / this.get(right).len),
                direction: this.get(left).direction,
            };
        }
        var mid = (left + right) >> 1;
        if (this.get(mid).tlen > distance)
            return this.getPointByDistance(distance, left, mid);
        else if (this.get(mid).tlen < distance)
            return this.getPointByDistance(distance, mid, right);
        else
            return {
                isNode: true,
                point: new Vec3_1.Vec3().lerpVecs(this.get(left), this.get(right), (distance - this.get(left).tlen) / this.get(right).len),
                direction: this.get(left).direction
            };
    };
    /**
     * 从起点出发到距离等于distance位置  的坐标 二分查找
     * @param {Number} distance
     */
    Path.prototype.getPointByDistancePure = function (arg_distance, left, right) {
        if (left === void 0) { left = 0; }
        if (right === void 0) { right = this.length - 1; }
        var distance = (0, Math_1.clamp)(arg_distance, 0, this.get(-1).tlen);
        if (distance !== arg_distance)
            return null;
        if (right - left === 1) {
            return new Vec3_1.Vec3().lerpVecs(this.get(left), this.get(right), (distance - this.get(left).tlen) / this.get(right).len);
        }
        var mid = (left + right) >> 1;
        if (this.get(mid).tlen > distance)
            return this.getPointByDistancePure(distance, left, mid);
        else if (this.get(mid).tlen < distance)
            return this.getPointByDistancePure(distance, mid, right);
        else
            return this.get(mid).clone();
    };
    /**
     * 平均切割为 splitCount 段
     * @param {Number} splitCount
     * @returns {Path} 新的path
     */
    Path.prototype.splitAverage = function (splitCount) {
        var tlen = this.last.tlen;
        var perlen = tlen / splitCount;
        var res = [];
        var curJ = 0;
        for (var i = 0; i <= splitCount; i++) {
            var plen = i * perlen;
            for (var j = curJ; j < this.length - 1; j++) {
                if (this.get(j).tlen <= plen && this.get(j + 1).tlen >= plen) {
                    var p = new Vec3_1.Vec3().lerpVecs(this.get(j), this.get(j + 1), (plen - this.get(j).tlen) / (this.get(j + 1).len));
                    res.push(p);
                    curJ = j;
                    break;
                }
            }
        }
        return new Path(res);
    };
    /**
     * 通过测试
    * 平均切割为 splitCount 段
    * @param {Number} splitCount
    * @param {Boolean} integer 是否取整
    * @returns {Path} 新的path
    */
    Path.prototype.splitAverageLength = function (splitLength, integer) {
        if (integer === void 0) { integer = true; }
        var tlen = this.last.tlen;
        var count = tlen / splitLength;
        if (integer)
            count = Math.round(count);
        return this.splitAverage(count);
    };
    /**
     *
     * @param  {...any} ps
     */
    Path.prototype.add = function () {
        var ps = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            ps[_i] = arguments[_i];
        }
        if (this.length == 0) {
            var firstpt = ps.shift();
            this.push(firstpt);
            this.get(0).len = 0;
            this.get(0).tlen = 0;
        }
        for (var i = 0; i < ps.length; i++) {
            var pt = ps[i];
            pt.len = pt.distanceTo(this.get(-1));
            pt.tlen = this.get(-1).tlen + pt.len;
            pt.direction = pt.clone().sub(this.get(-1)).normalize();
            if (!this.get(-1).direction)
                this.get(-1).direction = pt.clone().sub(this.get(-1)).normalize();
            else
                this.get(-1).direction.copy(pt.direction);
            this.push(pt);
        }
    };
    /**
     * @description : 计算一段线段的总长度
     * @param        {ArrayLike} ps
     * @return       {number}   总长度
     */
    Path.totalMileages = function (ps) {
        var alldisance = 0;
        for (var i = 0, len = ps.length - 1; i < len; i++) {
            alldisance += ps[i + 1].distanceTo(ps[i]);
        }
        return alldisance;
    };
    /**
     * @description : 获取没一点的里程  里程是指从第一个点出发的长度
     * @param        {ArrayLike} ps 里程上的点集
     * @param        {boolean} normalize 是否归一化
     * @return       {number[]}  每一个点的里程数组
     * @example     :
     */
    Path.getPerMileages = function (ps, normalize, totalMileage) {
        if (normalize === void 0) { normalize = false; }
        var res = [];
        var mileages = 0;
        res.push(mileages);
        for (var i = 0, len = ps.length - 1; i < len; i++) {
            mileages += ps[i + 1].distanceTo(ps[i]);
            res.push(mileages);
        }
        if (normalize) {
            var tl = (0, types_1.isDefined)(totalMileage) ? totalMileage : this.totalMileages(ps);
            for (var i = 0, len = ps.length; i < len; i++) {
                res[i] /= tl;
            }
        }
        return res;
    };
    return Path;
}(ArrayList_1.ArrayList));
exports.Path = Path;
