"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.GrowableXYArray = void 0;
/** @packageDocumentation
 * @module ArraysAndInterfaces
 */
const Geometry_1 = require("../Geometry");
const GrowableXYZArray_1 = require("./GrowableXYZArray");
const IndexedXYCollection_1 = require("./IndexedXYCollection");
const Point2dVector2d_1 = require("./Point2dVector2d");
const Point3dVector3d_1 = require("./Point3dVector3d");
/**
 * `GrowableXYArray` manages a (possibly growing) Float64Array to pack xy coordinates.
 * @public
 */
class GrowableXYArray extends IndexedXYCollection_1.IndexedReadWriteXYCollection {
    /** Array of packed xy xy xy components. */
    _data;
    /** Number of xy tuples (not floats) in the array. */
    _xyInUse;
    /** Capacity in xy tuples. (not floats). */
    _xyCapacity;
    /** Multiplier used by ensureCapacity to expand requested reallocation size. */
    _growthFactor;
    /**
     * Construct a new GrowablePoint2d array.
     * @param numPoints initial capacity in xy tuples (default 8).
     * @param growthFactor used by ensureCapacity to expand requested reallocation size (default 1.5).
     * @param data optional pre-existing Float64Array to use as the backing memory. If supplied, numPoints is ignored.
     */
    constructor(numPoints = 8, growthFactor, data) {
        super();
        this._data = data || new Float64Array(numPoints * 2); // 2 values per point
        this._xyInUse = 0;
        this._xyCapacity = data ? data.length / 2 : numPoints;
        this._growthFactor = (undefined !== growthFactor && growthFactor >= 1.0) ? growthFactor : 1.5;
    }
    /**
     * Copy xy points from source array. Does not reallocate or change active point count.
     * @param source array to copy from.
     * @param sourceCount copy the first sourceCount points; all points if undefined.
     * @param destOffset copy to instance array starting at this point index; zero if undefined.
     * @return count and offset of points copied.
     */
    copyData(source, sourceCount, destOffset) {
        // validate inputs and convert from points to entries
        let myOffset = (undefined !== destOffset) ? destOffset * 2 : 0;
        if (myOffset < 0)
            myOffset = 0;
        if (myOffset >= this._data.length)
            return { count: 0, offset: 0 };
        let myCount = (undefined !== sourceCount) ? sourceCount * 2 : source.length;
        if (myCount > 0) {
            if (myCount > source.length)
                myCount = source.length;
            if (myOffset + myCount > this._data.length)
                myCount = this._data.length - myOffset;
            if (myCount % 2 !== 0)
                myCount -= myCount % 2;
        }
        if (myCount <= 0)
            return { count: 0, offset: 0 };
        if (myCount === source.length)
            this._data.set(source, myOffset);
        else if (source instanceof Float64Array)
            this._data.set(source.subarray(0, myCount), myOffset);
        else
            this._data.set(source.slice(0, myCount), myOffset);
        return { count: myCount / 2, offset: myOffset / 2 };
    }
    /** The number of points in use. When the length is increased, the array is padded with zeroes. */
    get length() {
        return this._xyInUse;
    }
    set length(newLength) {
        this.resize(newLength, true);
    }
    /** Return the number of float64 in use. */
    get float64Length() {
        return this._xyInUse * 2;
    }
    /**
     * Return the raw packed data.
     * * Note that the length of the returned Float64Array is a count of doubles, and includes the excess capacity
     */
    float64Data() {
        return this._data;
    }
    /** If necessary, increase the capacity to a new pointCount. Current coordinates and point count (length) are unchanged. */
    ensureCapacity(pointCapacity, applyGrowthFactor = true) {
        if (pointCapacity > this._xyCapacity) {
            if (applyGrowthFactor)
                pointCapacity = Math.trunc(pointCapacity * this._growthFactor);
            const prevData = this._data;
            if (this._data.buffer instanceof ArrayBuffer)
                this._data = new Float64Array(new ArrayBuffer(pointCapacity * 2 * this._data.BYTES_PER_ELEMENT));
            else
                this._data = new Float64Array(new SharedArrayBuffer(pointCapacity * 2 * this._data.BYTES_PER_ELEMENT));
            this.copyData(prevData, this._xyInUse);
            this._xyCapacity = pointCapacity;
        }
    }
    /**
     * Resize the internal storage to hold a new number of points.
     * * If pointCount is less than current length, just reset current length to pointCount, effectively trimming active
     * points but preserving original capacity.
     * * If pointCount is greater than current length, reallocate to exactly pointCount, copy existing points, and
     * optionally pad excess with zero.
     * @param pointCount new number of active points in array.
     * @param padWithZero when increasing point count, whether to zero out new points (default false).
     */
    resize(pointCount, padWithZero) {
        if (pointCount >= 0 && pointCount < this._xyInUse)
            this._xyInUse = pointCount;
        else if (pointCount > this._xyInUse) {
            this.ensureCapacity(pointCount, false);
            if (padWithZero ?? false)
                this._data.fill(0, this._xyInUse * 2);
            this._xyInUse = pointCount;
        }
    }
    /** Make a copy of the (active) points in this array (the clone does NOT get excess capacity). */
    clone() {
        const newPoints = new GrowableXYArray(this.length);
        newPoints.copyData(this._data, this.length);
        newPoints._xyInUse = this.length;
        return newPoints;
    }
    /**
     * Create an array by copying data from various point formats.
     * Valid inputs are:
     * * Point2d
     * * Point3d
     * * An array of 2 doubles
     * * An array of 3 doubles
     * * A GrowableXYZArray
     * * A GrowableXYArray
     * * Any json object satisfying Point3d.isXAndY
     * * A Float64Array of doubles, interpreted as xyxy
     * * An array of any of the above.
     * @param data source points.
     * @param result optional pre-allocated GrowableXYArray to clear and fill.
     */
    static create(data, result) {
        if (result) {
            result.clear();
        }
        else {
            const pointCount = typeof data[0] === "number" ? data.length / 2 : data.length;
            result = new GrowableXYArray(pointCount);
        }
        result.pushFrom(data);
        return result;
    }
    /**
     * Create a new GrowableXYArray capturing the provided data. The data is not copied, just referenced.
     * @param data source data to capture.
     * @returns a new GrowableXYArray object that references the provided data.
     */
    static createCapture(data) {
        return new GrowableXYArray(0, undefined, data);
    }
    /**
     * Restructure MultiLineStringDataVariant as array of GrowableXYZArray
     * @deprecated in 4.2.0 - will not be removed until after 2026-06-13. Moved to GrowableXYZArray class.
     */
    static createArrayOfGrowableXYZArray(data) {
        return GrowableXYZArray_1.GrowableXYZArray.createArrayOfGrowableXYZArray(data);
    }
    /** Push a point to the end of the array. */
    push(toPush) {
        this.pushXY(toPush.x, toPush.y);
    }
    /** Push all points of an array. */
    pushAll(points) {
        this.ensureCapacity(this._xyInUse + points.length, false);
        for (const p of points)
            this.push(p);
    }
    /** Push all points of an array. */
    pushAllXYAndZ(points) {
        this.ensureCapacity(this._xyInUse + points.length, false);
        if (points instanceof GrowableXYZArray_1.GrowableXYZArray) {
            const xyzBuffer = points.float64Data();
            const n = points.length * 3;
            for (let i = 0; i + 2 < n; i += 3)
                this.pushXY(xyzBuffer[i], xyzBuffer[i + 1]);
        }
        else {
            for (const p of points)
                this.pushXY(p.x, p.y);
        }
    }
    /**
     * Push copies of points from variant sources.
     * Valid inputs are:
     * * Point2d
     * * Point3d
     * * An array of 2 doubles
     * * A GrowableXYArray
     * * A GrowableXYZArray
     * * Any json object satisfying Point3d.isXAndY
     * * A Float64Array of doubles, interpreted as xyxy
     * * An array of any of the above.
     */
    pushFrom(p) {
        if (p instanceof Point3dVector3d_1.Point3d) {
            this.pushXY(p.x, p.y);
        }
        else if (p instanceof GrowableXYZArray_1.GrowableXYZArray) {
            this.pushAllXYAndZ(p);
        }
        else if (p instanceof Point2dVector2d_1.Point2d) {
            this.pushXY(p.x, p.y);
        }
        else if (Geometry_1.Geometry.isNumberArray(p, 3) || p instanceof Float64Array) {
            const xyToAdd = Math.trunc(p.length / 2);
            this.ensureCapacity(this._xyInUse + xyToAdd, false);
            this.copyData(p, xyToAdd, this._xyInUse);
            this._xyInUse += xyToAdd;
        }
        else if (Geometry_1.Geometry.isNumberArray(p, 2)) {
            this.pushXY(p[0], p[1]);
        }
        else if (Array.isArray(p)) {
            // direct recursion re-wraps p and goes infinite; unroll here.
            for (const q of p)
                this.pushFrom(q);
        }
        else if (Point3dVector3d_1.Point3d.isXAndY(p)) {
            this.pushXY(p.x, p.y);
        }
        else if (p instanceof IndexedXYCollection_1.IndexedXYCollection) {
            const n = p.length;
            this.ensureCapacity(this._xyInUse + n, false);
            for (let i = 0; i < n; i++)
                this.pushXY(p.getXAtUncheckedPointIndex(i), p.getYAtUncheckedPointIndex(i));
        }
    }
    /**
     * Replicate numWrap xy values from the front of the array as new values at the end.
     * @param numWrap number of xy values to replicate.
     */
    pushWrap(numWrap) {
        if (this._xyInUse >= numWrap) {
            this.ensureCapacity(this._xyInUse + numWrap, false);
            for (let i = 0; i < numWrap; i++) {
                const k = 2 * i;
                this.pushXY(this._data[k], this._data[k + 1]);
            }
        }
    }
    /** push a point given by x,y coordinates */
    pushXY(x, y) {
        this.ensureCapacity(this._xyInUse + 1);
        const index = this._xyInUse * 2;
        this._data[index] = x;
        this._data[index + 1] = y;
        this._xyInUse++;
    }
    /**
     * Remove one point from the back.
     * * NOTE that (in the manner of std::vector native) this is "just" removing the point -- no point is NOT returned.
     * * Use `back ()` to get the last x,y assembled into a `Point2d`.
     */
    pop() {
        if (this._xyInUse > 0)
            this._xyInUse--;
    }
    /**
     * Test if index is valid for an xy (point or vector) within this array.
     * @param index xy index to test.
     */
    isIndexValid(index) {
        if (index >= this._xyInUse || index < 0)
            return false;
        return true;
    }
    /** Clear all xy data, but leave capacity unchanged. */
    clear() {
        this._xyInUse = 0;
    }
    /**
     * Get a point by index, strongly typed as a `Point2d`. This is unchecked. Use atPoint2dIndex to have validity test.
     * @param pointIndex index to access.
     * @param result optional result.
     */
    getPoint2dAtUncheckedPointIndex(pointIndex, result) {
        const index = 2 * pointIndex;
        return Point2dVector2d_1.Point2d.create(this._data[index], this._data[index + 1], result);
    }
    /**
     * Get x coordinate by point index, with no index checking.
     * @param pointIndex index to access.
     */
    getXAtUncheckedPointIndex(pointIndex) {
        return this._data[2 * pointIndex];
    }
    /**
     * Get y coordinate by point index, with no index checking.
     * @param pointIndex index to access.
     */
    getYAtUncheckedPointIndex(pointIndex) {
        return this._data[2 * pointIndex + 1];
    }
    /** Gather all points as a Point2d[]. */
    getPoint2dArray() {
        const n = 2 * this._xyInUse;
        const result = [];
        const data = this._data;
        for (let i = 0; i < n; i += 2)
            result.push(Point2dVector2d_1.Point2d.create(data[i], data[i + 1]));
        return result;
    }
    /** Copy xy into strongly typed Point2d. */
    getPoint2dAtCheckedPointIndex(pointIndex, result) {
        if (this.isIndexValid(pointIndex)) {
            const index = 2 * pointIndex;
            return Point2dVector2d_1.Point2d.create(this._data[index], this._data[index + 1], result);
        }
        return undefined;
    }
    /** Copy xy into strongly typed Vector2d. */
    getVector2dAtCheckedVectorIndex(vectorIndex, result) {
        if (this.isIndexValid(vectorIndex)) {
            const index = 2 * vectorIndex;
            return Point2dVector2d_1.Vector2d.create(this._data[index], this._data[index + 1], result);
        }
        return undefined;
    }
    /**
     * Read coordinates from source array, place them at index within this array.
     * @param destIndex point index where coordinates are to be placed in this array.
     * @param source source array.
     * @param sourceIndex point index in source array.
     * @returns true if destIndex and sourceIndex are both valid.
     */
    transferFromGrowableXYArray(destIndex, source, sourceIndex) {
        if (this.isIndexValid(destIndex) && source.isIndexValid(sourceIndex)) {
            const i = destIndex * 2;
            const j = sourceIndex * 2;
            this._data[i] = source._data[j];
            this._data[i + 1] = source._data[j + 1];
            return true;
        }
        return false;
    }
    /**
     * Push coordinates from the source array to the end of this array.
     * @param source source array.
     * @param sourceIndex xy index within the source.  If undefined, push entire contents of source.
     * @returns number of points pushed.
     */
    pushFromGrowableXYArray(source, sourceIndex) {
        // full array push
        if (sourceIndex === undefined) {
            const numXYAdd = source.length;
            this.ensureCapacity(this.length + numXYAdd, false);
            this.copyData(source._data, numXYAdd, this.length);
            this._xyInUse += numXYAdd;
            return numXYAdd;
        }
        // single point push
        if (source.isIndexValid(sourceIndex)) {
            const j = sourceIndex * 2;
            this.pushXY(source._data[j], source._data[j + 1]);
            return 1;
        }
        return 0;
    }
    /**
     * * Compute a point at fractional coordinate between points i and j of source.
     * * Push onto this array.
     */
    pushInterpolatedFromGrowableXYArray(source, i, fraction, j) {
        if (source.isIndexValid(i) && source.isIndexValid(j)) {
            const fraction0 = 1.0 - fraction;
            const data = source._data;
            i = 2 * i;
            j = 2 * j;
            this.pushXY(fraction0 * data[i] + fraction * data[j], fraction0 * data[i + 1] + fraction * data[j + 1]);
        }
    }
    /**
     * Create an array of xy points from source xyz points.
     * @param source source array of xyz.
     * @param transform optional transform to apply to xyz points.
     * @param dest optional result.
     */
    static createFromGrowableXYZArray(source, transform, dest) {
        const numPoints = source.length;
        if (!dest)
            dest = new GrowableXYArray(numPoints);
        else {
            dest.ensureCapacity(numPoints, false);
            dest.clear();
        }
        if (transform) {
            const packedXYZ = source.float64Data();
            const nDouble = 3 * numPoints;
            let x, y, z;
            for (let i = 0; i < nDouble; i += 3) {
                x = packedXYZ[i];
                y = packedXYZ[i + 1];
                z = packedXYZ[i + 2];
                dest.pushXY(transform.multiplyComponentXYZ(0, x, y, z), transform.multiplyComponentXYZ(1, x, y, z));
            }
        }
        else {
            dest.pushAllXYAndZ(source);
        }
        return dest;
    }
    /** Return the first point, or undefined if the array is empty. */
    front(result) {
        if (this._xyInUse === 0)
            return undefined;
        return this.getPoint2dAtUncheckedPointIndex(0, result);
    }
    /** Return the last point, or undefined if the array is empty. */
    back(result) {
        if (this._xyInUse < 1)
            return undefined;
        return this.getPoint2dAtUncheckedPointIndex(this._xyInUse - 1, result);
    }
    /**
     * Set the coordinates of a single point.
     * @param pointIndex index of point to set.
     * @param value coordinates to set.
     */
    setAtCheckedPointIndex(pointIndex, value) {
        if (!this.isIndexValid(pointIndex))
            return false;
        const index = pointIndex * 2;
        this._data[index] = value.x;
        this._data[index + 1] = value.y;
        return true;
    }
    /**
     * Set the coordinates of a single point given as coordinates.
     * @param pointIndex index of point to set.
     * @param x x coordinate.
     * @param y y coordinate.
     */
    setXYAtCheckedPointIndex(pointIndex, x, y) {
        if (!this.isIndexValid(pointIndex))
            return false;
        const index = pointIndex * 2;
        this._data[index] = x;
        this._data[index + 1] = y;
        return true;
    }
    /** Copy all points into a simple array of Point3d with given z. */
    getPoint3dArray(z = 0) {
        const n = 2 * this._xyInUse;
        const result = [];
        const data = this._data;
        for (let i = 0; i < n; i += 2)
            result.push(Point3dVector3d_1.Point3d.create(data[i], data[i + 1], z));
        return result;
    }
    /** Reverse the order of points. */
    reverseInPlace() {
        const n = this.length;
        let j0, j1;
        let a;
        const data = this._data;
        for (let i0 = 0, i1 = n - 1; i0 < i1; i0++, i1--) {
            j0 = 2 * i0;
            j1 = 2 * i1;
            a = data[j0];
            data[j0] = data[j1];
            data[j1] = a;
            j0++;
            j1++;
            a = data[j0];
            data[j0] = data[j1];
            data[j1] = a;
        }
    }
    /** Multiply each point by the transform, replace values. */
    multiplyTransformInPlace(transform) {
        const data = this._data;
        const nDouble = this.float64Length;
        const coffs = transform.matrix.coffs;
        const origin = transform.origin;
        const x0 = origin.x;
        const y0 = origin.y;
        let x = 0;
        let y = 0;
        for (let i = 0; i + 1 < nDouble; i += 2) {
            x = data[i];
            y = data[i + 1];
            data[i] = coffs[0] * x + coffs[1] * y + x0;
            data[i + 1] = coffs[3] * x + coffs[4] * y + y0;
        }
    }
    /** Multiply each xy (as a vector) by matrix, replace values. */
    multiplyMatrix3dInPlace(matrix) {
        const data = this._data;
        const nDouble = this.float64Length;
        const coffs = matrix.coffs;
        let x = 0;
        let y = 0;
        for (let i = 0; i + 1 < nDouble; i += 2) {
            x = data[i];
            y = data[i + 1];
            data[i] = coffs[0] * x + coffs[1] * y;
            data[i + 1] = coffs[3] * x + coffs[4] * y;
        }
    }
    /** Multiply each point by the transform, replace values. */
    tryTransformInverseInPlace(transform) {
        const data = this._data;
        const nDouble = this.float64Length;
        const matrix = transform.matrix;
        matrix.computeCachedInverse(true);
        const coffs = matrix.inverseCoffs;
        if (!coffs)
            return false;
        const origin = transform.origin;
        const x0 = origin.x;
        const y0 = origin.y;
        let x = 0;
        let y = 0;
        for (let i = 0; i + 1 < nDouble; i += 2) {
            x = data[i] - x0;
            y = data[i + 1] - y0;
            data[i] = coffs[0] * x + coffs[1] * y;
            data[i + 1] = coffs[3] * x + coffs[4] * y;
        }
        return true;
    }
    /** Extend a `Range2d`, optionally transforming the points. */
    extendRange(rangeToExtend, transform) {
        const numDouble = this.float64Length;
        const data = this._data;
        if (transform) {
            for (let i = 0; i + 1 < numDouble; i += 2)
                rangeToExtend.extendTransformedXY(transform, data[i], data[i + 1]);
        }
        else {
            for (let i = 0; i + 1 < numDouble; i += 2)
                rangeToExtend.extendXY(data[i], data[i + 1]);
        }
    }
    /** Sum the lengths of segments between points. */
    sumLengths() {
        let sum = 0.0;
        const n = 2 * (this._xyInUse - 1); // Length already takes into account what specifically is in use
        const data = this._data;
        for (let i = 0; i < n; i += 2)
            sum += Geometry_1.Geometry.hypotenuseXY(data[i + 2] - data[i], data[i + 3] - data[i + 1]);
        return sum;
    }
    /**
     * Multiply each x,y by the scale factor.
     * @param factor scale factor.
     */
    scaleInPlace(factor) {
        if (this._data) {
            const numFloat = this.float64Length;
            for (let i = 0; i < numFloat; i++)
                this._data[i] = this._data[i] * factor;
        }
    }
    /** Compute a point at fractional coordinate between points i and j. */
    interpolate(i, fraction, j, result) {
        if (this.isIndexValid(i) && this.isIndexValid(j)) {
            const fraction0 = 1.0 - fraction;
            const data = this._data;
            i = 2 * i;
            j = 2 * j;
            return Point2dVector2d_1.Point2d.create(fraction0 * data[i] + fraction * data[j], fraction0 * data[i + 1] + fraction * data[j + 1], result);
        }
        return undefined;
    }
    /** Sum the signed areas of the projection to xy plane. */
    areaXY() {
        let area = 0.0;
        const n = 2 * this._xyInUse; // float count
        if (n > 4) {
            const x0 = this._data[n - 2];
            const y0 = this._data[n - 1];
            let dx1 = this._data[0] - x0;
            let dy1 = this._data[1] - y0;
            let dx2 = 0;
            let dy2 = 0;
            for (let i = 2; i < n; i += 2, dx1 = dx2, dy1 = dy2) {
                dx2 = this._data[i] - x0;
                dy2 = this._data[i + 1] - y0;
                area += Geometry_1.Geometry.crossProductXYXY(dx1, dy1, dx2, dy2);
            }
        }
        return 0.5 * area;
    }
    /** Compute a vector from index origin i to indexed target j. */
    vectorIndexIndex(i, j, result) {
        if (!this.isIndexValid(i) || !this.isIndexValid(j))
            return undefined;
        const data = this._data;
        i = 2 * i;
        j = 2 * j;
        return Point2dVector2d_1.Vector2d.create(data[j] - data[i], data[j + 1] - data[i + 1], result);
    }
    /** Compute a vector from origin to indexed target j. */
    vectorXAndYIndex(origin, j, result) {
        if (this.isIndexValid(j)) {
            const data = this._data;
            j = 2 * j;
            return Point2dVector2d_1.Vector2d.create(data[j] - origin.x, data[j + 1] - origin.y, result);
        }
        return undefined;
    }
    /** Compute the cross product of vectors from from indexed origin to indexed targets i and j. */
    crossProductIndexIndexIndex(originIndex, targetAIndex, targetBIndex) {
        if (this.isIndexValid(originIndex) && this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex)) {
            const i = originIndex * 2;
            const j = targetAIndex * 2;
            const k = targetBIndex * 2;
            const data = this._data;
            return Geometry_1.Geometry.crossProductXYXY(data[j] - data[i], data[j + 1] - data[i + 1], data[k] - data[i], data[k + 1] - data[i + 1]);
        }
        return undefined;
    }
    /** Compute the cross product of vectors from from origin to indexed targets i and j. */
    crossProductXAndYIndexIndex(origin, targetAIndex, targetBIndex) {
        if (this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex)) {
            const j = targetAIndex * 2;
            const k = targetBIndex * 2;
            const data = this._data;
            return Geometry_1.Geometry.crossProductXYXY(data[j] - origin.x, data[j + 1] - origin.y, data[k] - origin.x, data[k + 1] - origin.y);
        }
        return undefined;
    }
    /** Return the distance between two points in the array. */
    distance(i, j) {
        if (this.isIndexValid(i) && this.isIndexValid(j)) {
            const i0 = 2 * i;
            const j0 = 2 * j;
            return Geometry_1.Geometry.hypotenuseXY(this._data[j0] - this._data[i0], this._data[j0 + 1] - this._data[i0 + 1]);
        }
        return undefined;
    }
    /** Return the distance between an array point and the input point. */
    distanceIndexToPoint(i, spacePoint) {
        if (this.isIndexValid(i)) {
            const i0 = 2 * i;
            return Geometry_1.Geometry.hypotenuseXY(spacePoint.x - this._data[i0], spacePoint.y - this._data[i0 + 1]);
        }
        return undefined;
    }
    /** Test for nearly equal arrays. */
    static isAlmostEqual(dataA, dataB) {
        if (dataA && dataB) {
            if (dataA.length !== dataB.length)
                return false;
            for (let i = 0; i < dataA.length; i++)
                if (!dataA.getPoint2dAtUncheckedPointIndex(i).isAlmostEqual(dataB.getPoint2dAtUncheckedPointIndex(i)))
                    return false;
            return true;
        }
        // if both are null it is equal, otherwise unequal
        return (!dataA && !dataB);
    }
    /** Return an array of block indices sorted per compareLexicalBlock function. */
    sortIndicesLexical() {
        const n = this._xyInUse;
        // let numCompare = 0;
        const result = new Uint32Array(n);
        for (let i = 0; i < n; i++)
            result[i] = i;
        result.sort((blockIndexA, blockIndexB) => {
            // numCompare++;
            return this.compareLexicalBlock(blockIndexA, blockIndexB);
        });
        // console.log (n, numCompare);
        return result;
    }
    /** compare two blocks in simple lexical order. */
    compareLexicalBlock(ia, ib) {
        let ax = 0;
        let bx = 0;
        for (let i = 0; i < 2; i++) {
            ax = this._data[ia * 2 + i];
            bx = this._data[ib * 2 + i];
            if (ax > bx)
                return 1;
            if (ax < bx)
                return -1;
        }
        return ia - ib; // so original order is maintained among duplicates
    }
    /** Access a single double at offset within a block. This has no index checking. */
    component(pointIndex, componentIndex) {
        return this._data[2 * pointIndex + componentIndex];
    }
    /** Toleranced equality test. */
    isAlmostEqual(other, tolerance = Geometry_1.Geometry.smallMetricDistance) {
        const numXY = this._xyInUse;
        if (other._xyInUse !== numXY)
            return false;
        const dataA = this._data;
        const dataB = other._data;
        for (let i = 0; i < 2 * numXY; i++) {
            if (Math.abs(dataA[i] - dataB[i]) > tolerance)
                return false;
        }
        return true;
    }
}
exports.GrowableXYArray = GrowableXYArray;
//# sourceMappingURL=GrowableXYArray.js.map