import { Point } from '../../..';
import { Assert } from '../../../utils/assert';
import { PointComparer } from '../../rectilinear/PointComparer';
export class BundleBase {
    //  constructor
    constructor(count, boundaryCurve, position, belongsToRealNode) {
        this.BelongsToRealNode = belongsToRealNode;
        this.Curve = boundaryCurve;
        this.Position = position;
        this.points = new Array(count);
        this.tangents = new Array(count);
        this.OrientedHubSegments = new Array(count);
        this.ParameterSpan = this.Curve.parEnd - this.Curve.parStart;
    }
    get Count() {
        return this.points.length;
    }
    get CurveCenter() {
        return this.Curve.boundingBox.center;
    }
    get OppositeBase() {
        return this.OutgoingBundleInfo != null ? this.OutgoingBundleInfo.TargetBase : this.IncomingBundleInfo.SourceBase;
    }
    get length() {
        return this.points.length;
    }
    get Points() {
        return this.points;
    }
    get Tangents() {
        return this.tangents;
    }
    get InitialMidParameter() {
        return this.initialMidParameter;
    }
    set InitialMidParameter(value) {
        this.initialMidParameter = value;
        this.InitialMidPoint = this.Curve.value(value);
    }
    //  corresponds to the left point of the base
    get ParRight() {
        return this.parRight;
    }
    set ParRight(value) {
        this.parRight = value;
        this.RightPoint = this.Curve.value(this.parRight);
    }
    //  corresponds to the right point of the base
    get ParLeft() {
        return this.parLeft;
    }
    set ParLeft(value) {
        this.parLeft = value;
        this.LeftPoint = this.Curve.value(this.parLeft);
    }
    get ParMid() {
        return (this.parRight + this.parLeft) / 2;
    }
    get MidPoint() {
        return this.RightPoint.add(this.LeftPoint).div(2);
    }
    get Span() {
        return this.SpanBetweenTwoPoints(this.parRight, this.parLeft);
    }
    SpanBetweenTwoPoints(right, left) {
        return right <= left ? left - right : left - right + this.ParameterSpan;
    }
    RotateLeftPoint(rotationOfSourceLeftPoint, parameterChange) {
        if (rotationOfSourceLeftPoint == 0) {
            return this.LeftPoint;
        }
        return this.RotatePoint(rotationOfSourceLeftPoint, this.parLeft, parameterChange);
    }
    RotateRigthPoint(rotationOfSourceRightPoint, parameterChange) {
        if (rotationOfSourceRightPoint == 0) {
            return this.RightPoint;
        }
        return this.RotatePoint(rotationOfSourceRightPoint, this.parRight, parameterChange);
    }
    RotatePoint(rotation, t, parameterChange) {
        const change = this.ParameterSpan * parameterChange;
        t = t + rotation * change;
        t = this.AdjustParam(t);
        return this.Curve.value(t);
    }
    AdjustParam(t) {
        if (t > this.Curve.parEnd)
            t = this.Curve.parStart + (t - this.Curve.parEnd);
        else if (t < this.Curve.parStart)
            t = this.Curve.parEnd - (this.Curve.parStart - t);
        return t;
    }
    RotateBy(rotationOfRightPoint, rotationOfLeftPoint, parameterChange) {
        const change = this.ParameterSpan * parameterChange;
        if (rotationOfRightPoint != 0) {
            this.ParRight = this.AdjustParam(this.ParRight + rotationOfRightPoint * change);
        }
        if (rotationOfLeftPoint != 0) {
            this.ParLeft = this.AdjustParam(this.ParLeft + rotationOfLeftPoint * change);
        }
    }
    Intersect(other) {
        return this.IntersectNNNB(this.parRight, this.parLeft, other.parRight, other.parLeft);
    }
    IntersectNNNB(lParRight, lParLeft, rParRight, rParLeft) {
        if (lParRight > lParLeft) {
            return (this.IntersectNNNB(lParRight, this.Curve.parEnd, rParRight, rParLeft) ||
                this.IntersectNNNB(this.Curve.parStart, lParLeft, rParRight, rParLeft));
        }
        if (rParRight > rParLeft) {
            return (this.IntersectNNNB(lParRight, lParLeft, rParRight, this.Curve.parEnd) ||
                this.IntersectNNNB(lParRight, lParLeft, this.Curve.parStart, rParLeft));
        }
        Assert.assert(lParRight <= lParLeft);
        Assert.assert(rParRight <= rParLeft);
        if (PointComparer.LessOrEqual(lParLeft, rParRight)) {
            return false;
        }
        if (PointComparer.LessOrEqual(rParLeft, lParRight)) {
            return false;
        }
        return true;
    }
    RelativeOrderOfBasesIsPreserved(rotationOfRightPoint, rotationOfLeftPoint, parameterChange) {
        const change = this.ParameterSpan * parameterChange;
        //we do not swap parRight and parLeft
        const rnew = this.parRight + rotationOfRightPoint * change;
        const lnew = this.parRight < this.parLeft
            ? this.parLeft + rotationOfLeftPoint * change
            : this.parLeft + this.ParameterSpan + rotationOfLeftPoint * change;
        if (rnew > lnew)
            return false;
        //span could not be greater than pi
        if (this.SpanBetweenTwoPoints(rnew, lnew) > this.ParameterSpan / 2.0)
            return false;
        //the base is the only base in the hub
        if (this.Prev == null)
            return true;
        //distance between mid points is larger than parameterChange => we can't change the order
        if (this.SpanBetweenTwoPoints(this.Prev.ParMid, this.ParMid) > change &&
            this.SpanBetweenTwoPoints(this.ParMid, this.Next.ParMid) > change)
            return true;
        const rSoP = this.RotateLeftPoint(rotationOfLeftPoint, parameterChange);
        const lSoP = this.RotateRigthPoint(rotationOfRightPoint, parameterChange);
        const newMidPoint = Point.middle(rSoP, lSoP);
        const curMidPoint = this.MidPoint;
        //check Prev
        if (Point.getTriangleOrientation(this.CurveCenter, this.Prev.MidPoint, curMidPoint) !=
            Point.getTriangleOrientation(this.CurveCenter, this.Prev.MidPoint, newMidPoint))
            return false;
        //Next
        if (Point.getTriangleOrientation(this.CurveCenter, this.Next.MidPoint, curMidPoint) !=
            Point.getTriangleOrientation(this.CurveCenter, this.Next.MidPoint, newMidPoint))
            return false;
        return true;
    }
}
//# sourceMappingURL=BundleBase.js.map