"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 Rendering
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.GeometryAccumulator = void 0;
const core_geometry_1 = require("@itwin/core-geometry");
const MeshBuilderMap_1 = require("./MeshBuilderMap");
const MeshPrimitives_1 = require("./MeshPrimitives");
const GeometryList_1 = require("./GeometryList");
const GeometryPrimitives_1 = require("./GeometryPrimitives");
/** @internal */
class GeometryAccumulator {
    _transform;
    _surfacesOnly;
    _analysisDisplacement;
    tileRange;
    geometries = new GeometryList_1.GeometryList();
    currentFeature;
    get surfacesOnly() { return this._surfacesOnly; }
    get transform() { return this._transform; }
    get isEmpty() { return this.geometries.isEmpty; }
    get haveTransform() { return !this._transform.isIdentity; }
    constructor(options) {
        this.tileRange = options?.tileRange ?? core_geometry_1.Range3d.createNull();
        this._surfacesOnly = true === options?.surfacesOnly;
        this._transform = options?.transform ?? core_geometry_1.Transform.createIdentity();
        this._analysisDisplacement = options?.analysisStyleDisplacement;
        this.currentFeature = options?.feature;
    }
    getPrimitiveRange(geom) {
        const range = new core_geometry_1.Range3d();
        geom.range(undefined, range);
        return range.isNull ? undefined : range;
    }
    calculateTransform(transform, range) {
        if (this.haveTransform)
            transform = this._transform.multiplyTransformTransform(transform);
        transform.multiplyRange(range, range);
        return transform;
    }
    addLoop(loop, displayParams, transform, disjoint) {
        const range = this.getPrimitiveRange(loop);
        if (!range)
            return false;
        const xform = this.calculateTransform(transform, range);
        return this.addGeometry(GeometryPrimitives_1.Geometry.createFromLoop(loop, xform, range, displayParams, disjoint, this.currentFeature));
    }
    addLineString(pts, displayParams, transform) {
        // Do this.getPrimitiveRange() manually, so there is no need to create a PointString3d object just to find the range
        const range = core_geometry_1.Range3d.createNull();
        range.extendArray(pts, undefined);
        if (range.isNull)
            return false;
        const xform = this.calculateTransform(transform, range);
        return this.addGeometry(GeometryPrimitives_1.Geometry.createFromLineString(pts, xform, range, displayParams, this.currentFeature));
    }
    addPointString(pts, displayParams, transform) {
        // Do this.getPrimitiveRange() manually, so there is no need to create a PointString3d object just to find the range
        const range = core_geometry_1.Range3d.createNull();
        range.extendArray(pts, undefined);
        if (range.isNull)
            return false;
        const xform = this.calculateTransform(transform, range);
        return this.addGeometry(GeometryPrimitives_1.Geometry.createFromPointString(pts, xform, range, displayParams, this.currentFeature));
    }
    addPath(path, displayParams, transform, disjoint) {
        const range = this.getPrimitiveRange(path);
        if (!range)
            return false;
        const xform = this.calculateTransform(transform, range);
        return this.addGeometry(GeometryPrimitives_1.Geometry.createFromPath(path, xform, range, displayParams, disjoint, this.currentFeature));
    }
    addPolyface(pf, displayParams, transform) {
        // Adjust the mesh range based on displacements applied to vertices by analysis style, if applicable.
        let range;
        const analysisDisplacement = this._analysisDisplacement;
        if (analysisDisplacement) {
            const channel = pf.data.auxData?.channels.find((x) => x.name === analysisDisplacement.channelName);
            const displacementRange = channel?.computeDisplacementRange(analysisDisplacement.scale);
            if (displacementRange && !displacementRange.isNull) {
                range = core_geometry_1.Range3d.createNull();
                const pt = new core_geometry_1.Point3d();
                for (let i = 0; i < pf.data.point.length; i++) {
                    pf.data.point.getPoint3dAtUncheckedPointIndex(i, pt);
                    range.extendXYZ(pt.x + displacementRange.low.x, pt.y + displacementRange.low.y, pt.z + displacementRange.low.z);
                    range.extendXYZ(pt.x + displacementRange.high.x, pt.y + displacementRange.high.y, pt.z + displacementRange.high.z);
                }
            }
        }
        if (!range && !(range = this.getPrimitiveRange(pf)))
            return false;
        const xform = this.calculateTransform(transform, range);
        return this.addGeometry(GeometryPrimitives_1.Geometry.createFromPolyface(pf, xform, range, displayParams, this.currentFeature));
    }
    addSolidPrimitive(primitive, displayParams, transform) {
        const range = this.getPrimitiveRange(primitive);
        if (!range)
            return false;
        const xform = this.calculateTransform(transform, range);
        return this.addGeometry(GeometryPrimitives_1.Geometry.createFromSolidPrimitive(primitive, xform, range, displayParams, this.currentFeature));
    }
    addGeometry(geom) {
        this.geometries.push(geom);
        return true;
    }
    clear() { this.geometries.clear(); }
    /**
     * Generates a MeshBuilderMap
     * native: GeometryAccumulator::ToMeshBuilderMap(GeometryOptionsCR options, double tolerance, FeatureTableP featureTable, ViewContextR context) const
     * note  : removed featureTable, ViewContext
     * @param tolerance should derive from Viewport.getPixelSizeAtPoint
     */
    toMeshBuilderMap(options, tolerance, pickable) {
        const { geometries } = this; // declare internal dependencies
        const range = geometries.computeRange();
        const is2d = !range.isNull && range.isAlmostZeroZ;
        return MeshBuilderMap_1.MeshBuilderMap.createFromGeometries(geometries, tolerance, range, is2d, options, pickable);
    }
    toMeshes(options, tolerance, pickable) {
        if (this.geometries.isEmpty)
            return new MeshPrimitives_1.MeshList();
        const builderMap = this.toMeshBuilderMap(options, tolerance, pickable);
        return builderMap.toMeshes();
    }
}
exports.GeometryAccumulator = GeometryAccumulator;
//# sourceMappingURL=GeometryAccumulator.js.map