"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.LinearSweep = void 0;
const LineString3d_1 = require("../curve/LineString3d");
const Loop_1 = require("../curve/Loop");
const Path_1 = require("../curve/Path");
const Point3dVector3d_1 = require("../geometry3d/Point3dVector3d");
const PolygonOps_1 = require("../geometry3d/PolygonOps");
const Transform_1 = require("../geometry3d/Transform");
const SolidPrimitive_1 = require("./SolidPrimitive");
const SweepContour_1 = require("./SweepContour");
/**
 * A LinearSweep is a `SolidPrimitive` defined by:
 * * A set of curves (any Loop, Path, or parityRegion). If the object is "capped", the curves must be planar.
 * * A sweep vector
 * @public
 */
class LinearSweep extends SolidPrimitive_1.SolidPrimitive {
    /** String name for schema properties */
    solidPrimitiveType = "linearSweep";
    _contour;
    _direction;
    constructor(contour, direction, capped) {
        super(capped);
        this._contour = contour;
        this._direction = direction;
    }
    /**
     * Create a sweep of a starting contour.
     * @param contour contour to be swept, CAPTURED
     * @param direction sweep vector.  The contour is swept the full length of the vector.
     * @param capped true to include end caps
     */
    static create(contour, direction, capped) {
        const sweepable = SweepContour_1.SweepContour.createForLinearSweep(contour, direction);
        if (!sweepable)
            return undefined;
        return new LinearSweep(sweepable, direction, capped);
    }
    /** Create a z-direction sweep of the polyline or polygon given as xy linestring values.
     * * If not capped, the xyPoints array is always used unchanged.
     * * If capped but the xyPoints array does not close, exact closure will be enforced by one of these:
     * * * If the final point is almost equal to the first, it is replaced by the exact first point.
     * * * if the final point is not close to the first an extra point is added.
     * * If capped, the point order will be reversed if necessary to produce positive volume.
     * @param xyPoints array of xy coordinates
     * @param z z value to be used for all coordinates
     * @param zSweep the sweep distance in the z direction.
     * @param capped true if caps are to be added.
     */
    static createZSweep(xyPoints, z, zSweep, capped) {
        const xyz = LineString3d_1.LineString3d.createXY(xyPoints, z, capped);
        if (capped) {
            xyz.addClosurePoint();
            const area = PolygonOps_1.PolygonOps.areaXY(xyz.points);
            if (area * zSweep < 0.0)
                xyz.points.reverse();
        }
        const contour = capped ? Loop_1.Loop.create(xyz) : Path_1.Path.create(xyz);
        return LinearSweep.create(contour, Point3dVector3d_1.Vector3d.create(0, 0, zSweep), capped);
    }
    /** get a reference to the swept curves */
    getCurvesRef() { return this._contour.curves; }
    /** Get a reference to the `SweepContour` carrying the plane of the curves */
    getSweepContourRef() { return this._contour; }
    /** return a clone of the sweep vector */
    cloneSweepVector() { return this._direction.clone(); }
    /** Test if `other` is also an instance of `LinearSweep` */
    isSameGeometryClass(other) { return other instanceof LinearSweep; }
    /** Return a deep clone */
    clone() {
        return new LinearSweep(this._contour.clone(), this._direction.clone(), this.capped);
    }
    /**
     * Apply a transform to the curves and sweep vector
     * * This fails if the transformation is singular.
     */
    tryTransformInPlace(transform) {
        if (transform.matrix.isSingular())
            return false;
        if (!this._contour.tryTransformInPlace(transform))
            return false;
        transform.multiplyVector(this._direction, this._direction);
        if (transform.matrix.determinant() < 0.0) {
            // if mirror, reverse the sweep (origin and direction) to preserve outward normals
            if (!this._contour.tryTransformInPlace(Transform_1.Transform.createTranslation(this._direction)))
                return false;
            this._direction.scaleInPlace(-1.0);
        }
        return true;
    }
    /** Return a coordinate frame (right handed unit vectors)
     * * origin on base contour
     * * x, y directions from base contour.
     * * z direction perpendicular
     */
    getConstructiveFrame() {
        return this._contour.localToWorld.cloneRigid();
    }
    /**
     * Return a transformed clone.
     * * This fails if the transformation is singular.
     */
    cloneTransformed(transform) {
        const result = this.clone();
        return result.tryTransformInPlace(transform) ? result : undefined;
    }
    /** Test for near-equality of coordinates in `other` */
    isAlmostEqual(other) {
        if (other instanceof LinearSweep) {
            return this._contour.isAlmostEqual(other._contour)
                && this._direction.isAlmostEqual(other._direction)
                && this.capped === other.capped;
        }
        return false;
    }
    /** Invoke strongly typed `handler.handleLinearSweep(this)` */
    dispatchToGeometryHandler(handler) {
        return handler.handleLinearSweep(this);
    }
    /**
     * Return the curves at a fraction along the sweep direction.
     * @param vFraction fractional position along the sweep direction
     */
    constantVSection(vFraction) {
        const section = this._contour.curves.clone();
        if (section && vFraction !== 0.0)
            section.tryTransformInPlace(Transform_1.Transform.createTranslation(this._direction.scale(vFraction)));
        return section;
    }
    /** Extend `rangeToExtend` to include this geometry. */
    extendRange(rangeToExtend, transform) {
        const contourRange = this._contour.curves.range(transform);
        rangeToExtend.extendRange(contourRange);
        if (transform) {
            const transformedDirection = transform.multiplyVector(this._direction);
            contourRange.low.addInPlace(transformedDirection);
            contourRange.high.addInPlace(transformedDirection);
        }
        else {
            contourRange.low.addInPlace(this._direction);
            contourRange.high.addInPlace(this._direction);
        }
        rangeToExtend.extendRange(contourRange);
    }
    /**
     * @return true if this is a closed volume.
     */
    get isClosedVolume() {
        return this.capped && this._contour.curves.isAnyRegionType;
    }
}
exports.LinearSweep = LinearSweep;
//# sourceMappingURL=LinearSweep.js.map