"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module CartesianGeometry
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.AngleSweep = void 0;
const Geometry_1 = require("../Geometry");
const Angle_1 = require("./Angle");
/**
 * An `AngleSweep` is a pair of angles at start and end of an interval.
 *
 * * For stroking purposes, the "included interval" is all angles numerically reached
 * by `theta = start + f * (end - start)`, where `0 <= f <= 1`.
 * * This stroking formula is simple numbers -- 2PI shifts are not involved.
 * * 2PI shifts do become important in the reverse mapping of an angle to a fraction.
 * * Angles greater than 360 and less than 0 are fine as endpoints.
 * * An AngleSweep determines orientation only _in concert with a reference vector_, e.g., a plane normal like (0,0,1).
 *   * Be careful reading orientation from an AngleSweep without a reference vector!
 *   * If "start < end" the angles in the sweep proceed counterclockwise around the reference vector.
 *   * If "start > end" the angles in the sweep proceed clockwise around the reference vector.
 *   * (350,370) covers the same angles as (-10,10), and both sweeps are counterclockwise around the reference vector.
 *   * (370,350) covers the same angles as (10,-10), and both sweeps are clockwise around the reference vector.
 *   * (370,350) covers the same angles as (-10,10), but the sweeps have opposite orientation.
 * * Math details can be found at docs/learning/geometry/Angle.md .
 * * Visualization can be found at https://www.itwinjs.org/sandbox/SaeedTorabi/AngleSweep .
 * @public
 */
class AngleSweep {
    _radians0;
    _radians1;
    /** Read-property for degrees at the start of this AngleSweep. */
    get startDegrees() {
        return Angle_1.Angle.radiansToDegrees(this._radians0);
    }
    /** Read-property for degrees at the end of this AngleSweep. */
    get endDegrees() {
        return Angle_1.Angle.radiansToDegrees(this._radians1);
    }
    /** Read-property for signed start-to-end sweep in degrees. */
    get sweepDegrees() {
        return Angle_1.Angle.radiansToDegrees(this.sweepRadians);
    }
    /** Read-property for degrees at the start of this AngleSweep. */
    get startRadians() {
        return this._radians0;
    }
    /** Read-property for degrees at the end of this AngleSweep. */
    get endRadians() {
        return this._radians1;
    }
    /** Read-property for signed start-to-end sweep in radians. */
    get sweepRadians() {
        return this._radians1 - this._radians0;
    }
    /** Whether the sweep angles are within smallAngle tolerance, without period shift. */
    get isEmpty() {
        return Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(0, this.sweepRadians);
    }
    /** Return the (strongly typed) start angle */
    get startAngle() {
        return Angle_1.Angle.createRadians(this._radians0);
    }
    /** Return the (strongly typed) end angle */
    get endAngle() {
        return Angle_1.Angle.createRadians(this._radians1);
    }
    /**
     * Create a sweep as one of
     * * A clone of a given sweep
     * * 0 to given angle
     * * full circle if no arg given (sweep 0 to 360 degrees)
     */
    static create(data) {
        if (data instanceof AngleSweep)
            return data.clone();
        if (data instanceof Angle_1.Angle)
            return new AngleSweep(0, data.radians);
        return AngleSweep.create360();
    }
    /**
     * (private) constructor with start and end angles in radians.
     * * Use explicitly named static methods to clarify intent and units of inputs:
     *
     * * createStartEndRadians (startRadians:number, endRadians:number)
     * * createStartEndDegrees (startDegrees:number, endDegrees:number)
     * * createStartEnd (startAngle:Angle, endAngle:Angle)
     * * createStartSweepRadians (startRadians:number, sweepRadians:number)
     * * createStartSweepDegrees (startDegrees:number, sweepDegrees:number)
     * * createStartSweep (startAngle:Angle, sweepAngle:Angle)
     */
    constructor(startRadians = 0, endRadians = 0) {
        this._radians0 = startRadians;
        this._radians1 = endRadians;
    }
    /**
     * Directly set the start and end angles in radians
     * * If the difference between startRadians and endRadians is greater than 360, the function limits the angle sweep to 360.
     */
    setStartEndRadians(startRadians = 0, endRadians = 2.0 * Math.PI) {
        const delta = endRadians - startRadians;
        if (Angle_1.Angle.isFullCircleRadians(delta)) {
            endRadians = startRadians + (delta > 0 ? 2.0 : -2.0) * Math.PI;
        }
        this._radians0 = startRadians;
        this._radians1 = endRadians;
    }
    /** Directly set the start and end angles in degrees */
    setStartEndDegrees(startDegrees = 0, endDegrees = 360.0) {
        this.setStartEndRadians(Angle_1.Angle.degreesToRadians(startDegrees), Angle_1.Angle.degreesToRadians(endDegrees));
    }
    /**
     * Create an AngleSweep from start and end angles given in radians.
     * * If the difference between startRadians and endRadians is greater than 360, the function limits the angle sweep to 360.
     */
    static createStartEndRadians(startRadians = 0, endRadians = 2.0 * Math.PI, result) {
        result = result ? result : new AngleSweep();
        result.setStartEndRadians(startRadians, endRadians);
        return result;
    }
    /** Return the AngleSweep obtained by subtracting radians from the start and end angles of this sweep. */
    cloneMinusRadians(radians) {
        return new AngleSweep(this._radians0 - radians, this._radians1 - radians);
    }
    /** Create an AngleSweep from start and end angles given in degrees. */
    static createStartEndDegrees(startDegrees = 0, endDegrees = 360, result) {
        return AngleSweep.createStartEndRadians(Angle_1.Angle.degreesToRadians(startDegrees), Angle_1.Angle.degreesToRadians(endDegrees), result);
    }
    /** Create an angle sweep from strongly typed start and end angles */
    static createStartEnd(startAngle, endAngle, result) {
        result = result ? result : new AngleSweep();
        result.setStartEndRadians(startAngle.radians, endAngle.radians);
        return result;
    }
    /** Create an AngleSweep from start and end angles given in radians. */
    static createStartSweepRadians(startRadians = 0, sweepRadians = Math.PI, result) {
        result = result ? result : new AngleSweep();
        result.setStartEndRadians(startRadians, startRadians + sweepRadians);
        return result;
    }
    /** Create an AngleSweep from start and sweep given in degrees.  */
    static createStartSweepDegrees(startDegrees = 0, sweepDegrees = 360, result) {
        return AngleSweep.createStartEndRadians(Angle_1.Angle.degreesToRadians(startDegrees), Angle_1.Angle.degreesToRadians(startDegrees + sweepDegrees), result);
    }
    /** Create an angle sweep with limits given as (strongly typed) angles for start and sweep */
    static createStartSweep(startAngle, sweepAngle, result) {
        return AngleSweep.createStartSweepRadians(startAngle.radians, sweepAngle.radians, result);
    }
    /** Return a sweep with limits interpolated between this and other. */
    interpolate(fraction, other) {
        return new AngleSweep(Geometry_1.Geometry.interpolate(this._radians0, fraction, other._radians0), Geometry_1.Geometry.interpolate(this._radians1, fraction, other._radians1));
    }
    /** Copy from other AngleSweep. */
    setFrom(other) {
        this._radians0 = other._radians0;
        this._radians1 = other._radians1;
    }
    /**
     * Create a full circle sweep (CCW).
     * @param startRadians start angle in radians. Defaults to 0.
     * @param result optional preallocated object to populate and return.
     */
    static create360(startRadians, result) {
        startRadians = startRadians ? startRadians : 0.0;
        const endRadians = startRadians + 2.0 * Math.PI;
        if (result) {
            result.setStartEndRadians(startRadians, endRadians);
            return result;
        }
        return new AngleSweep(startRadians, endRadians);
    }
    /** Create a sweep from the south pole to the north pole (-90 to +90). */
    static createFullLatitude() {
        return AngleSweep.createStartEndRadians(-0.5 * Math.PI, 0.5 * Math.PI);
    }
    /** Reverse the start and end angle in place. */
    reverseInPlace() {
        const tmp = this._radians0;
        this._radians0 = this._radians1;
        this._radians1 = tmp;
    }
    /**
     * Return a sweep for the "other" part of the circle.
     * @param reverseDirection true to move backwards (CW) from start to end, false to more forwards (CCW) from start to end.
     */
    cloneComplement(reverseDirection = false, result) {
        const s = this.sweepRadians >= 0 ? 2.0 : -2.0;
        if (reverseDirection)
            return AngleSweep.createStartEndRadians(this.startRadians, this.endRadians - s * Math.PI, result);
        else
            return AngleSweep.createStartEndRadians(this.endRadians, this.startRadians + s * Math.PI, result);
    }
    /** Restrict start and end angles to the degree range [-90,+90]. */
    capLatitudeInPlace() {
        const limit = 0.5 * Math.PI;
        this._radians0 = Geometry_1.Geometry.clampToStartEnd(this._radians0, -limit, limit);
        this._radians1 = Geometry_1.Geometry.clampToStartEnd(this._radians1, -limit, limit);
    }
    /**
     * Restrict [[sweepDegrees]] to the range [-360, 360].
     * The start angle and sign of the sweep angle are unchanged.
     */
    clampToFullCircle(result) {
        result = result ?? new AngleSweep();
        const sweepRadians = Geometry_1.Geometry.clampToStartEnd(this.sweepRadians, -Angle_1.Angle.pi2Radians, Angle_1.Angle.pi2Radians);
        result.setStartEndRadians(this._radians0, this._radians0 + sweepRadians);
        return result;
    }
    /** Ask if the sweep is counterclockwise, i.e. positive sweep. */
    get isCCW() {
        return this._radians1 >= this._radians0;
    }
    /** Ask if the sweep is a full circle. */
    get isFullCircle() {
        return Angle_1.Angle.isFullCircleRadians(this.sweepRadians);
    }
    /** Ask if the sweep is a full sweep from south pole to north pole. */
    get isFullLatitudeSweep() {
        const a = Math.PI * 0.5;
        return Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(this._radians0, -a)
            && Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1, a);
    }
    /** Return a clone of this sweep. */
    clone() {
        return new AngleSweep(this._radians0, this._radians1);
    }
    /** Convert fractional position in the sweep to radians. */
    fractionToRadians(fraction) {
        return fraction < 0.5 ?
            this._radians0 + fraction * this.sweepRadians :
            this._radians1 + (fraction - 1.0) * this.sweepRadians;
    }
    /** Convert fractional position in the sweep to strongly typed Angle object. */
    fractionToAngle(fraction) {
        return Angle_1.Angle.createRadians(this.fractionToRadians(fraction));
    }
    /**
     * Return 2PI divided by the sweep radians.
     * * This is the number of fractional intervals required to cover a whole circle.
     * @returns period of the sweep, or 1 if sweep is empty.
     */
    fractionPeriod() {
        return this.isEmpty ? 1.0 : Angle_1.Angle.pi2Radians / Math.abs(this.sweepRadians);
    }
    /**
     * Return the fractionalized position of the given angle (as Angle) computed without consideration of
     * 2PI period and without consideration of angle sweep direction (CW or CCW).
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  negative fraction for angles "before" the start angle if start < end
     * *  fraction larger than one for angles "after" the end angle if start < end
     * *  fraction larger than one for angles "before" the start angle if start > end
     * *  negative fraction for angles "after" the end angle if start > end
     * *  does not allow period shift
     * @returns unbounded fraction, or 1 if sweep is empty.
     */
    angleToUnboundedFraction(theta) {
        return this.isEmpty ? 1.0 : (theta.radians - this._radians0) / this.sweepRadians;
    }
    /**
     * Convert a sweep fraction to the equivalent period-shifted fraction inside the sweep, or within one period of zero
     * on the desired side.
     * @param fraction fraction of the sweep.
     * @param radians0 start angle of sweep (in radians).
     * @param radians1 end angle of sweep (in radians).
     * @param toNegativeFraction exterior fraction handling:
     * * if true, return `fraction` period-shifted to within one period of the start
     * * if false, return `fraction` period-shifted to within one period of the end
     * * if undefined, return the period-shift of `fraction` closest to [0,1].
     * @returns period-shifted fraction. If `fraction` is already in [0,1], or the sweep is empty, then `fraction` is
     * returned unchanged.
     */
    static fractionToSignedPeriodicFractionStartEnd(fraction, radians0, radians1, toNegativeFraction) {
        const sweep = radians1 - radians0;
        if (Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(0, sweep))
            return fraction; // empty sweep
        if (Geometry_1.Geometry.isIn01(fraction))
            return fraction;
        const period = Angle_1.Angle.pi2Radians / Math.abs(sweep);
        fraction = fraction % period; // period-shifted equivalent fraction closest to 0 with same sign as fraction
        if (fraction + period < 1)
            fraction += period; // it's really an interior fraction
        if (Geometry_1.Geometry.isIn01(fraction))
            return fraction;
        if (toNegativeFraction === true)
            return fraction < 0 ? fraction : fraction - period;
        if (toNegativeFraction === false)
            return fraction > 1 ? fraction : fraction + period;
        const fractionDistFrom01 = fraction < 0 ? -fraction : fraction - 1;
        const fraction2 = fraction < 0 ? fraction + period : fraction - period; // period-shift with opposite sign
        const fraction2DistFrom01 = fraction2 < 0 ? -fraction2 : fraction2 - 1;
        return fractionDistFrom01 < fraction2DistFrom01 ? fraction : fraction2; // choose the period-shift closer to [0,1]
    }
    /**
     * Convert a sweep fraction to the equivalent period-shifted fraction inside this sweep, or within one period of
     * zero on the desired side.
     * @param fraction fraction of the sweep.
     * @param toNegativeFraction exterior fraction handling:
     * * if true, return `fraction` period-shifted to within one period of the start
     * * if false, return `fraction` period-shifted to within one period of the end
     * * if undefined, return the period-shift of `fraction` closest to [0,1].
     * @returns period-shifted fraction. If `fraction` is already in [0,1], or the sweep is empty, then `fraction` is
     * returned unchanged.
     */
    fractionToSignedPeriodicFraction(fraction, toNegativeFraction) {
        return AngleSweep.fractionToSignedPeriodicFractionStartEnd(fraction, this._radians0, this._radians1, toNegativeFraction);
    }
    /**
     * Return the fractionalized position of the given angle (as radians), computed with consideration of 2PI period.
     * *  consider radians0 as `start` angle of the sweep and radians1 as `end` angle of the sweep
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  all exterior angles are at fractions greater than 1
     * *  allows period shift
     * @param radians input angle (in radians)
     * @param radians0 start angle of sweep (in radians)
     * @param radians1 end angle of sweep (in radians)
     * @param zeroSweepDefault return value when the sweep is empty (default 0)
     * @returns nonnegative fraction, or `zeroSweepDefault` if the sweep is empty.
     */
    static radiansToPositivePeriodicFractionStartEnd(radians, radians0, radians1, zeroSweepDefault = 0.0) {
        const zeroSweepMarker = Geometry_1.Geometry.largeCoordinateResult;
        let fraction = this.radiansToSignedPeriodicFractionStartEnd(radians, radians0, radians1, zeroSweepMarker);
        if (fraction === zeroSweepMarker)
            return zeroSweepDefault;
        if (fraction < 0) {
            const period = Angle_1.Angle.pi2Radians / Math.abs(radians1 - radians0);
            fraction += period;
        }
        return fraction;
    }
    /**
     * Return the fractionalized position of the given angle (as radians), computed with consideration of 2PI period.
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  all exterior angles are at fractions greater than 1
     * *  allows period shift
     * @param radians input angle (in radians)
     * @param zeroSweepDefault return value when this sweep is empty (default 0)
     * @returns nonnegative fraction, or `zeroSweepDefault` if the sweep is empty.
     */
    radiansToPositivePeriodicFraction(radians, zeroSweepDefault = 0.0) {
        return AngleSweep.radiansToPositivePeriodicFractionStartEnd(radians, this._radians0, this._radians1, zeroSweepDefault);
    }
    /**
     * Return the fractionalized position of the given angle (as Angle), computed with consideration of 2PI period.
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  all exterior angles are at fractions greater than 1
     * *  allows period shift
     * @param theta input angle
     * @param zeroSweepDefault return value when this sweep is empty (default 0)
     * @returns nonnegative fraction, or `zeroSweepDefault` if the sweep is empty.
     */
    angleToPositivePeriodicFraction(theta, zeroSweepDefault = 0.0) {
        return this.radiansToPositivePeriodicFraction(theta.radians, zeroSweepDefault);
    }
    /**
     * Return the fractionalized position of the given array of angles (as radian), computed with consideration of 2PI period.
     * *  fraction is always positive
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  all exterior angles are at fractions greater than 1
     * *  allows period shift
     */
    radiansArrayToPositivePeriodicFractions(data) {
        const n = data.length;
        for (let i = 0; i < n; i++) {
            data.reassign(i, this.radiansToPositivePeriodicFraction(data.atUncheckedIndex(i)));
        }
    }
    /**
     * Return the fractionalized position of the given angle (as radians) computed with consideration of
     * 2PI period and with consideration of angle sweep direction (CW or CCW).
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  negative fraction for angles "before" the start angle
     * *  fraction larger than one for angles "after" the end angle
     * *  allows period shift
     * @param radians input angle (in radians)
     * @param radians0 start angle of sweep (in radians)
     * @param radians1 end angle of sweep (in radians)
     * @param zeroSweepDefault return value when the sweep is empty (default 0)
     * @returns fraction, or `zeroSweepDefault` if the sweep is empty.
     */
    static radiansToSignedPeriodicFractionStartEnd(radians, radians0, radians1, zeroSweepDefault = 0.0) {
        const sweep = radians1 - radians0;
        if (Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(0, sweep))
            return zeroSweepDefault;
        if (Angle_1.Angle.isAlmostEqualRadiansAllowPeriodShift(radians0, radians1)) {
            // for sweep = 2nPi !== 0, allow matching without period shift, else we never return 1.0
            if (Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(radians, radians0))
                return 0.0;
            if (Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(radians, radians1))
                return 1.0;
        }
        else {
            if (Angle_1.Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0))
                return 0.0;
            if (Angle_1.Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians1))
                return 1.0;
        }
        const fraction = (radians - radians0) / sweep;
        return this.fractionToSignedPeriodicFractionStartEnd(fraction, radians0, radians1, fraction < 0);
    }
    /**
     * Return the fractionalized position of the given angle (as radians) computed with consideration of
     * 2PI period and with consideration of angle sweep direction (CW or CCW).
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  negative fraction for angles "before" the start angle
     * *  fraction larger than one for angles "after" the end angle
     * *  allows period shift
     * @param radians input angle (in radians)
     * @param zeroSweepDefault return value when this sweep is empty (default 0)
     * @returns fraction, or `zeroSweepDefault` if this sweep is empty.
     */
    radiansToSignedPeriodicFraction(radians, zeroSweepDefault = 0.0) {
        return AngleSweep.radiansToSignedPeriodicFractionStartEnd(radians, this._radians0, this._radians1, zeroSweepDefault);
    }
    /**
     * Return the fractionalized position of the given angle (as Angle) computed with consideration of
     * 2PI period and with consideration of angle sweep direction (CW or CCW).
     * *  the start angle is at fraction 0
     * *  the end angle is at fraction 1
     * *  interior angles are between 0 and 1
     * *  negative fraction for angles "before" the start angle
     * *  fraction larger than one for angles "after" the end angle
     * *  allows period shift
     * @param theta input angle
     * @param zeroSweepDefault return value when this sweep is empty (default 0)
     * @returns fraction, or `zeroSweepDefault` if this sweep is empty.
     */
    angleToSignedPeriodicFraction(theta, zeroSweepDefault = 0.0) {
        return this.radiansToSignedPeriodicFraction(theta.radians, zeroSweepDefault);
    }
    /**
     * Return the fractionalized position of the given radian angle with respect to the sweep.
     * * The start angle returns fraction 0
     * * The end angle returns fraction 1
     * * Interior angles (and their multiples of 2PI) return fractions in [0,1].
     * * Exterior angles return fractions outside [0,1] according to `toNegativeFraction`.
     * @param radians input angle (in radians)
     * @param radians0 start angle of sweep (in radians)
     * @param radians1 end angle of sweep (in radians)
     * @param toNegativeFraction convert an exterior angle to a negative number (true), or to
     * a number greater than one (false, default). If false, this is just [[radiansToPositivePeriodicFractionStartEnd]].
     * @param zeroSweepDefault return value when the sweep is empty (default 0).
     * @returns fraction, or `zeroSweepDefault` if the sweep is empty
     */
    static radiansToSignedFractionStartEnd(radians, radians0, radians1, toNegativeFraction = false, zeroSweepDefault = 0.0) {
        const zeroSweepMarker = Geometry_1.Geometry.largeCoordinateResult;
        let fraction = this.radiansToSignedPeriodicFractionStartEnd(radians, radians0, radians1, zeroSweepMarker);
        if (fraction === zeroSweepMarker)
            return zeroSweepDefault;
        if ((toNegativeFraction && fraction > 1) || (!toNegativeFraction && fraction < 0)) {
            let period = Angle_1.Angle.pi2Radians / Math.abs(radians1 - radians0);
            if (toNegativeFraction)
                period = -period;
            fraction += period;
        }
        return fraction;
    }
    /**
     * Return the fractionalized position of the given radian angle with respect to this sweep.
     * * The start angle returns fraction 0
     * * The end angle returns fraction 1
     * * Interior angles (and their multiples of 2PI) return fractions in [0,1].
     * * Exterior angles return fractions outside [0,1] according to `toNegativeFraction`.
     * @param radians input angle (in radians)
     * @param toNegativeFraction convert an exterior angle to a negative number (true), or to
     * a number greater than one (false, default). If false, this is just [[radiansToPositivePeriodicFraction]].
     * @param zeroSweepDefault return value when this sweep is empty (default 0).
     * @returns fraction, or `zeroSweepDefault` if this sweep is empty
     */
    radiansToSignedFraction(radians, toNegativeFraction = false, zeroSweepDefault = 0.0) {
        return AngleSweep.radiansToSignedFractionStartEnd(radians, this._radians0, this._radians1, toNegativeFraction, zeroSweepDefault);
    }
    /**
     * Return the fractionalized position of the given angle with respect to this sweep.
     * * The start angle returns fraction 0
     * * The end angle returns fraction 1
     * * Interior angles (and their multiples of 2PI) return fractions in [0,1].
     * * Exterior angles return fractions outside [0,1] according to `toNegativeFraction`.
     * @param theta input angle
     * @param toNegativeFraction convert an exterior angle to a negative number (true), or to
     * a number greater than one (false, default). If false, this is just [[angleToPositivePeriodicFraction]].
     * @param zeroSweepDefault return value when this sweep is empty (default 0).
     * @returns fraction, or `zeroSweepDefault` if this sweep is empty
     */
    angleToSignedFraction(theta, toNegativeFraction = false, zeroSweepDefault = 0.0) {
        return this.radiansToSignedFraction(theta.radians, toNegativeFraction, zeroSweepDefault);
    }
    /** Test if the given angle (as radians) is within sweep (between radians0 and radians1)   */
    static isRadiansInStartEnd(radians, radians0, radians1, allowPeriodShift = true) {
        const delta0 = radians - radians0;
        const delta1 = radians - radians1;
        if (delta0 * delta1 <= 0.0)
            return true;
        if (radians0 === radians1)
            return allowPeriodShift ? Angle_1.Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0) : Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(radians, radians0);
        return allowPeriodShift ? this.radiansToPositivePeriodicFractionStartEnd(radians, radians0, radians1, 1000.0) <= 1.0 : false;
    }
    /** Test if the given angle (as radians) is within sweep  */
    isRadiansInSweep(radians, allowPeriodShift = true) {
        return AngleSweep.isRadiansInStartEnd(radians, this.startRadians, this.endRadians, allowPeriodShift);
    }
    /** Test if the given angle (as Angle) is within the sweep */
    isAngleInSweep(angle) {
        return this.isRadiansInSweep(angle.radians);
    }
    /**
     * Set this AngleSweep from various sources:
     * * if json is undefined, a full-circle sweep is returned.
     * * If json is an AngleSweep object, it is cloned
     * * If json is an array of 2 numbers, those numbers are start and end angles in degrees.
     * * If `json.degrees` is an array of 2 numbers, those numbers are start and end angles in degrees.
     * * If `json.radians` is an array of 2 numbers, those numbers are start and end angles in radians.
     * * Otherwise, a full-circle sweep is returned.
     */
    setFromJSON(json) {
        if (!json)
            this.setStartEndRadians(); // default full circle
        else if (json instanceof AngleSweep)
            this.setFrom(json);
        else if (Geometry_1.Geometry.isNumberArray(json.degrees, 2))
            this.setStartEndDegrees(json.degrees[0], json.degrees[1]);
        else if (Geometry_1.Geometry.isNumberArray(json.radians, 2))
            this.setStartEndRadians(json.radians[0], json.radians[1]);
        else if (Geometry_1.Geometry.isNumberArray(json, 2))
            this.setStartEndDegrees(json[0], json[1]);
        else
            this.setStartEndRadians(); // default full circle
    }
    /** Create an AngleSweep from a json object. */
    static fromJSON(json) {
        const result = AngleSweep.create360();
        result.setFromJSON(json);
        return result;
    }
    /**
     * Convert an AngleSweep to a JSON object.
     * @return {*} [startAngleInDegrees, endAngleInDegrees]
     */
    toJSON() {
        return [this.startDegrees, this.endDegrees];
    }
    /**
     * Test if two angle sweeps match within the given tolerance.
     * * Period shifts are allowed, but orientations must be the same.
     * @param other sweep to compare to this instance
     * @param radianTol optional radian tolerance, default value `Geometry.smallAngleRadians`
     */
    isAlmostEqualAllowPeriodShift(other, radianTol = Geometry_1.Geometry.smallAngleRadians) {
        return this.isCCW === other.isCCW // this rules out equating opposite sweeps like [0,-100] and [0,260]
            && Angle_1.Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians0, other._radians0, radianTol)
            && Angle_1.Angle.isAlmostEqualRadiansAllowPeriodShift(this.sweepRadians, other.sweepRadians, radianTol);
    }
    /**
     * Test if two angle sweeps match within the given tolerance.
     * * Period shifts are not allowed.
     * @param other sweep to compare to this instance
     * @param radianTol optional radian tolerance, default value `Geometry.smallAngleRadians`
     */
    isAlmostEqualNoPeriodShift(other, radianTol = Geometry_1.Geometry.smallAngleRadians) {
        return Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(this._radians0, other._radians0, radianTol)
            && Angle_1.Angle.isAlmostEqualRadiansNoPeriodShift(this.sweepRadians, other.sweepRadians, radianTol);
    }
    /**
     * Test if start and end angles match with radians tolerance.
     * * Period shifts are not allowed.
     * * This function is equivalent to isAlmostEqualNoPeriodShift. It is present for consistency with other classes.
     * However, it is recommended to use isAlmostEqualNoPeriodShift which has a clearer name.
     */
    isAlmostEqual(other) {
        return this.isAlmostEqualNoPeriodShift(other);
    }
}
exports.AngleSweep = AngleSweep;
//# sourceMappingURL=AngleSweep.js.map