"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.RegionMomentsXY = void 0;
const Angle_1 = require("../geometry3d/Angle");
const GeometryHandler_1 = require("../geometry3d/GeometryHandler");
const Point3dVector3d_1 = require("../geometry3d/Point3dVector3d");
const MomentData_1 = require("../geometry4d/MomentData");
const LineString3d_1 = require("./LineString3d");
const Loop_1 = require("./Loop");
const ParityRegion_1 = require("./ParityRegion");
const RegionOps_1 = require("./RegionOps");
const StrokeOptions_1 = require("./StrokeOptions");
/**
 * Implementation class for computing XY area moments.
 * @internal
 */
class RegionMomentsXY extends GeometryHandler_1.NullGeometryHandler {
    _activeMomentData;
    _point0 = Point3dVector3d_1.Point3d.create();
    _point1 = Point3dVector3d_1.Point3d.create();
    /**
     * Accumulate (independent) integrations over:
     * * The area between the arc and the chord connecting its endpoints.
     * * The triangle with vertices: origin, arc start, arc end.
     */
    handleArc3d(arc) {
        const momentData = this._activeMomentData;
        const sweepRadians = arc.sweep.sweepRadians;
        const alphaRadians = sweepRadians * 0.5;
        let s = Math.sin(alphaRadians);
        let c = Math.cos(alphaRadians);
        let s1 = Math.sin(sweepRadians);
        if (Angle_1.Angle.isFullCircleRadians(sweepRadians)) {
            s = 0.0;
            c = -1.0;
            s1 = 0.0;
        }
        const q = 2 * s * s * s * c / (alphaRadians - s * c);
        const s3 = s * s * s;
        const s6 = s3 * s3;
        const area = 0.5 * (sweepRadians - s1);
        const inertiaXX = 0.25 * area * (1.0 - q / 3.0);
        const inertiaYY1 = 0.25 * area * (1.0 + q);
        const inertiaYY = inertiaYY1 - 4.0 * s6 / (9.0 * area);
        const productXX = inertiaYY;
        const productYY = inertiaXX;
        const centerToCentroid = 4.0 * s * s * s / (3.0 * (sweepRadians - s1));
        const midRadians = arc.sweep.fractionToRadians(0.5);
        const centralPlane = arc.radiansToRotatedBasis(midRadians);
        const centroid = centralPlane.origin.plusScaled(centralPlane.vectorU, centerToCentroid);
        momentData.accumulateXYProductsInCentroidalFrame(productXX, 0.0, productYY, area, centroid, centralPlane.vectorU, centralPlane.vectorV);
        const pointB = arc.fractionToPoint(0.0);
        const pointC = arc.fractionToPoint(1.0);
        momentData.accumulateTriangleMomentsXY(undefined, pointB, pointC);
    }
    /** Accumulate integrals over the (triangular) areas from the origin to each line segment. */
    handleLineString3d(ls) {
        const momentData = this._activeMomentData;
        momentData.accumulateTriangleToLineStringMomentsXY(undefined, ls.packedPoints);
    }
    /** Accumulate integrals over the (triangular) area from the origin to this line segment. */
    handleLineSegment3d(segment) {
        const momentData = this._activeMomentData;
        segment.startPoint(this._point0);
        segment.endPoint(this._point1);
        momentData.accumulateTriangleMomentsXY(undefined, this._point0, this._point1);
    }
    /** Accumulate integrals from origin to all primitives in the loop. */
    handleLoop(loop) {
        const momentData = this._activeMomentData = MomentData_1.MomentData.create();
        momentData.needOrigin = false;
        for (const child of loop.children)
            child.dispatchToGeometryHandler(this);
        this._activeMomentData = undefined;
        return momentData;
    }
    handleAnyRegion(region) {
        // guarantee there are no overlapping children and parity loops have been properly oriented
        const merged = RegionOps_1.RegionOps.regionBooleanXY(region, undefined, RegionOps_1.RegionBinaryOpType.Union);
        if (!merged)
            return undefined;
        if (merged instanceof Loop_1.Loop)
            return this.handleLoop(merged);
        const summedMoments = MomentData_1.MomentData.create();
        for (const child of merged.children) {
            const childMoments = child.dispatchToGeometryHandler(this);
            if (childMoments) {
                // parity region hole sums subtract; all other regions add
                const scale = (merged instanceof ParityRegion_1.ParityRegion && childMoments.quantitySum < 0) ? -1.0 : 1.0;
                const sign0 = childMoments.signFactor(scale);
                summedMoments.accumulateProducts(childMoments, sign0);
            }
        }
        return summedMoments;
    }
    /** Accumulate integrals from origin to the components of the parity region. */
    handleParityRegion(region) {
        return this.handleAnyRegion(region);
    }
    /** Accumulate integrals from origin to the components of the union region. */
    handleUnionRegion(region) {
        return this.handleAnyRegion(region);
    }
    _strokeOptions; // TODO: expose to callers in RegionOps
    getStrokeOptions() {
        if (this._strokeOptions)
            return this._strokeOptions;
        const options = StrokeOptions_1.StrokeOptions.createForCurves();
        // this is unusually fine for stroking, but appropriate for sum.
        options.angleTol = Angle_1.Angle.createDegrees(5.0);
        this._strokeOptions = options;
        return options;
    }
    /**
     * Handle a single curve primitive (not loop).
     * * Stroke the curve and accumulate stroke array.
     */
    handleCurvePrimitive(cp) {
        const strokes = LineString3d_1.LineString3d.create();
        const options = this.getStrokeOptions();
        cp.emitStrokes(strokes, options);
        this.handleLineString3d(strokes);
    }
    /** Handle strongly typed  BSplineCurve3d  as generic curve primitive. */
    handleBSplineCurve3d(g) {
        this.handleCurvePrimitive(g);
    }
    /** Handle strongly typed  BSplineCurve3dH  as generic curve primitive. */
    handleBSplineCurve3dH(g) {
        this.handleCurvePrimitive(g);
    }
    /** Handle strongly typed  TransitionSpiral as generic curve primitive. */
    handleTransitionSpiral(g) {
        this.handleCurvePrimitive(g);
    }
}
exports.RegionMomentsXY = RegionMomentsXY;
//# sourceMappingURL=RegionMomentsXY.js.map