/*---------------------------------------------------------------------------------------------
* 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
 */
import { assert } from "@itwin/core-bentley";
import { PolyfaceBuilder, PolyfaceQuery, StrokeOptions, SweepContour, } from "@itwin/core-geometry";
import { DisplayParams } from "./DisplayParams";
import { PolyfacePrimitive, PolyfacePrimitiveList } from "./Polyface";
import { StrokesPrimitive, StrokesPrimitiveList, StrokesPrimitivePointList, StrokesPrimitivePointLists } from "./Strokes";
/** @internal */
export class Geometry {
    constructor(transform, tileRange, displayParams, feature) {
        this.transform = transform;
        this.tileRange = tileRange;
        this.displayParams = displayParams;
        this.feature = feature;
    }
    static createFromPointString(pts, tf, tileRange, params, feature) {
        return new PrimitivePointStringGeometry(pts, tf, tileRange, params, feature);
    }
    static createFromLineString(pts, tf, tileRange, params, feature) {
        return new PrimitiveLineStringGeometry(pts, tf, tileRange, params, feature);
    }
    static createFromLoop(loop, tf, tileRange, params, disjoint, feature) {
        return new PrimitiveLoopGeometry(loop, tf, tileRange, params, disjoint, feature);
    }
    static createFromSolidPrimitive(primitive, tf, tileRange, params, feature) {
        return new SolidPrimitiveGeometry(primitive, tf, tileRange, params, feature);
    }
    static createFromPath(path, tf, tileRange, params, disjoint, feature) {
        return new PrimitivePathGeometry(path, tf, tileRange, params, disjoint, feature);
    }
    static createFromPolyface(ipf, tf, tileRange, params, feature) {
        return new PrimitivePolyfaceGeometry(ipf, tf, tileRange, params, feature);
    }
    getPolyfaces(tolerance) {
        const facetOptions = StrokeOptions.createForFacets();
        facetOptions.chordTol = tolerance;
        if (this.displayParams.isTextured)
            facetOptions.needParams = true;
        if (!this.displayParams.ignoreLighting) // ###TODO don't generate normals for 2d views.
            facetOptions.needNormals = true;
        return this._getPolyfaces(facetOptions);
    }
    getStrokes(tolerance) {
        const strokeOptions = StrokeOptions.createForCurves();
        strokeOptions.chordTol = tolerance;
        return this._getStrokes(strokeOptions);
    }
    get hasTexture() { return this.displayParams.isTextured; }
    doDecimate() { return false; }
    doVertexCluster() { return true; }
    part() { return undefined; }
}
/** @internal */
export class PrimitivePathGeometry extends Geometry {
    constructor(path, tf, range, params, isDisjoint, feature) {
        super(tf, range, params, feature);
        this.path = path;
        this.isDisjoint = isDisjoint;
    }
    _getPolyfaces(_facetOptions) { return undefined; }
    _getStrokes(facetOptions) {
        return PrimitivePathGeometry.getStrokesForLoopOrPath(this.path, facetOptions, this.displayParams, this.isDisjoint, this.transform);
    }
    static getStrokesForLoopOrPath(loopOrPath, facetOptions, params, isDisjoint, transform) {
        const strksList = new StrokesPrimitiveList();
        if (!loopOrPath.isAnyRegionType || params.wantRegionOutline) {
            const strksPts = new StrokesPrimitivePointLists();
            PrimitivePathGeometry.collectCurveStrokes(strksPts, loopOrPath, facetOptions, transform);
            if (strksPts.length > 0) {
                const isPlanar = loopOrPath.isAnyRegionType;
                assert(isPlanar === params.wantRegionOutline);
                const strksPrim = StrokesPrimitive.create(params, isDisjoint, isPlanar);
                strksPrim.strokes = strksPts;
                strksList.push(strksPrim);
            }
        }
        return strksList;
    }
    static collectCurveStrokes(strksPts, loopOrPath, facetOptions, trans) {
        const strokes = loopOrPath.getPackedStrokes(facetOptions);
        if (undefined !== strokes) {
            const pts = strokes.getPoint3dArray();
            trans.multiplyPoint3dArrayInPlace(pts);
            strksPts.push(new StrokesPrimitivePointList(pts));
        }
    }
}
/** @internal */
export class PrimitivePointStringGeometry extends Geometry {
    constructor(pts, tf, range, params, feature) {
        super(tf, range, params, feature);
        this.pts = pts;
    }
    _getPolyfaces(_facetOptions) {
        return undefined;
    }
    _getStrokes(_facetOptions) {
        const strksList = new StrokesPrimitiveList();
        const strksPts = new StrokesPrimitivePointLists(new StrokesPrimitivePointList(this.pts));
        const strksPrim = StrokesPrimitive.create(this.displayParams, true, false);
        strksPrim.strokes = strksPts;
        strksPrim.transform(this.transform);
        strksList.push(strksPrim);
        return strksList;
    }
}
/** @internal */
export class PrimitiveLineStringGeometry extends Geometry {
    constructor(pts, tf, range, params, feature) {
        super(tf, range, params, feature);
        this.pts = pts;
    }
    _getPolyfaces(_facetOptions) {
        return undefined;
    }
    _getStrokes(_facetOptions) {
        const strksList = new StrokesPrimitiveList();
        const strksPts = new StrokesPrimitivePointLists(new StrokesPrimitivePointList(this.pts));
        const strksPrim = StrokesPrimitive.create(this.displayParams, false, false);
        strksPrim.strokes = strksPts;
        strksPrim.transform(this.transform);
        strksList.push(strksPrim);
        return strksList;
    }
}
/** @internal */
export class PrimitiveLoopGeometry extends Geometry {
    constructor(loop, tf, range, params, isDisjoint, feature) {
        super(tf, range, params, feature);
        this.loop = loop;
        this.isDisjoint = isDisjoint;
    }
    _getPolyfaces(facetOptions) {
        if (!this.loop.isAnyRegionType) {
            return undefined;
        }
        // The following is good for single loop things according to Earlin.
        const contour = SweepContour.createForLinearSweep(this.loop);
        if (contour !== undefined) {
            const pfBuilder = PolyfaceBuilder.create(facetOptions);
            contour.emitFacets(pfBuilder, false, this.transform); // build facets and emit them to the builder
            const polyface = pfBuilder.claimPolyface();
            const wantEdges = DisplayParams.RegionEdgeType.Default === this.displayParams.regionEdgeType;
            const isPlanar = true;
            return new PolyfacePrimitiveList(PolyfacePrimitive.create(this.displayParams, polyface, wantEdges, isPlanar));
        } // ###TODO: this approach might not work with holes
        return undefined;
    }
    _getStrokes(facetOptions) {
        return PrimitivePathGeometry.getStrokesForLoopOrPath(this.loop, facetOptions, this.displayParams, this.isDisjoint, this.transform);
    }
}
/** @internal */
export class PrimitivePolyfaceGeometry extends Geometry {
    constructor(polyface, tf, range, params, feature) {
        super(tf, range, params, feature);
        this.polyface = tf.isIdentity ? polyface : polyface.cloneTransformed(tf);
    }
    _getPolyfaces(facetOptions) {
        if (!this.hasTexture) {
            if (this.polyface.data.param)
                this.polyface.data.param.clear();
            if (this.polyface.data.paramIndex)
                this.polyface.data.paramIndex = [];
        }
        if (!facetOptions.needNormals) {
            if (this.polyface.data.normal)
                this.polyface.data.normal.clear();
            if (this.polyface.data.normalIndex)
                this.polyface.data.normalIndex = [];
        }
        else if (!this.polyface.data.normal || 0 === this.polyface.data.normal.length) {
            PolyfaceQuery.buildAverageNormals(this.polyface);
        }
        return new PolyfacePrimitiveList(PolyfacePrimitive.create(this.displayParams, this.polyface));
    }
    _getStrokes(_facetOptions) { return undefined; }
}
class SolidPrimitiveGeometry extends Geometry {
    constructor(primitive, tf, range, params, feature) {
        super(tf, range, params, feature);
        const xformPrim = tf.isIdentity ? primitive : primitive.cloneTransformed(tf);
        this._primitive = xformPrim !== undefined ? xformPrim : primitive;
    }
    _getStrokes() { return undefined; }
    _getPolyfaces(opts) {
        const builder = PolyfaceBuilder.create(opts);
        builder.addGeometryQuery(this._primitive);
        return new PolyfacePrimitiveList(PolyfacePrimitive.create(this.displayParams, builder.claimPolyface()));
    }
}
//# sourceMappingURL=GeometryPrimitives.js.map