UNPKG

@itwin/core-common

Version:

iTwin.js components common to frontend and backend

856 lines • 37.7 kB
"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 Geometry */ Object.defineProperty(exports, "__esModule", { value: true }); exports.QPoint3dBufferBuilder = exports.QPoint2dBufferBuilder = exports.QPoint3dList = exports.QPoint3dBuffer = exports.QPoint3d = exports.QParams3d = exports.QPoint2dList = exports.QPoint2dBuffer = exports.QPoint2d = exports.QParams2d = exports.Quantization = void 0; const core_bentley_1 = require("@itwin/core-bentley"); const core_geometry_1 = require("@itwin/core-geometry"); /** * Provides facilities for quantizing floating point values within a specified range into 16-bit unsigned integers. * This is a lossy compression technique. * Given a floating point range [min, max], a floating point value `x` within that range is quantized by subtracting * `min`, scaling the result according to `max`, and truncating the result to an integer. * Therefore min quantizes to 0, max to 0xffff, (min+max)/2 to 0x7fff, and so on. * These routines are chiefly used by classes like [[QPoint2d]] and [[QPoint3d]] to reduce the space required to store * coordinate values for [RenderGraphic]($frontend)s. * @public * @extensions */ var Quantization; (function (Quantization) { Quantization.rangeScale16 = 0xffff; Quantization.rangeScale8 = 0xff; /** Compute the scale factor required to quantize `extent` to `rangeScale` discrete values. */ function computeScale(extent, rangeScale = Quantization.rangeScale16) { return 0.0 === extent ? extent : rangeScale / extent; } Quantization.computeScale = computeScale; /** Returns true if the quantized value `qpos` fits within the specified range. */ function isInRange(qpos, rangeScale = Quantization.rangeScale16) { return qpos >= 0.0 && qpos < rangeScale + 1.0; } Quantization.isInRange = isInRange; /** Return `pos` quantized to the range [`origin`, `origin + rangeScale`]. * @see [[Quantization.unquantize]] for the inverse operation. */ function quantize(pos, origin, scale, rangeScale = Quantization.rangeScale16) { return Math.floor(Math.max(0.0, Math.min(rangeScale, 0.5 + (pos - origin) * scale))); } Quantization.quantize = quantize; /** Returns true if the value `pos` can be quantized to the specified range. */ function isQuantizable(pos, origin, scale, rangeScale = Quantization.rangeScale16) { return isInRange(quantize(pos, origin, scale, rangeScale)); } Quantization.isQuantizable = isQuantizable; /** Give `qpos` quantized to the range [`origin`, `origin + rangeScale`], return the unquantized value. * @see [[Quantization.quantize]] for the inverse operation. */ function unquantize(qpos, origin, scale) { return 0.0 === scale ? origin : origin + qpos / scale; } Quantization.unquantize = unquantize; /** Returns true if `qpos` is a valid quantized 16-bit value. */ function isQuantized(qpos) { return isInRange(qpos) && qpos === Math.floor(qpos); } Quantization.isQuantized = isQuantized; })(Quantization || (exports.Quantization = Quantization = {})); /** Parameters used for [[Quantization]] of 2d points such that the `x` and `y` components are each quantized to 16-bit unsigned integers. * @see [[QPoint2d]] for the quantized representation of a [Point2d]($core-geometry). * @see [[QPoint2dList]] for a list of [[QPoint2d]]s quantized using a [[QParams2d]]. * @public * @extensions */ class QParams2d { /** The origin of the quantization range. */ origin = new core_geometry_1.Point2d(); /** The scale applied to coordinates to quantize them. */ scale = new core_geometry_1.Point2d(); constructor(ox = 0, oy = 0, sx = 0, sy = 0) { this.setFrom(ox, oy, sx, sy); } setFrom(ox, oy, sx, sy) { this.origin.x = ox; this.origin.y = oy; this.scale.x = sx; this.scale.y = sy; } /** Set [[origin]] and [[scale]] from `src`. */ copyFrom(src) { this.setFrom(src.origin.x, src.origin.y, src.scale.x, src.scale.y); } /** Create a copy of these params. * @param out If supplied, these QParams2d will be modified and returned; otherwise a new QParams2d object will be created and returned. */ clone(out) { const result = undefined !== out ? out : new QParams2d(); result.copyFrom(this); return result; } /** Initialize these parameters to support quantization of values within the specified range. */ setFromRange(range, rangeScale = Quantization.rangeScale16) { if (!range.isNull) { this.setFrom(range.low.x, range.low.y, Quantization.computeScale(range.high.x - range.low.x, rangeScale), Quantization.computeScale(range.high.y - range.low.y, rangeScale)); } else { this.origin.x = this.origin.y = this.scale.x = this.scale.y = 0; } } /** Create parameters to support quantization of values within the specified range. */ static fromRange(range, out, rangeScale = Quantization.rangeScale16) { const params = undefined !== out ? out : new QParams2d(); params.setFromRange(range, rangeScale); return params; } /** Return the unquantized point for the input `x` and `y` components. If `out` is supplied, it will be modified to hold the result and returned. */ unquantize(x, y, out) { out = out ?? new core_geometry_1.Point2d(); out.x = Quantization.unquantize(x, this.origin.x, this.scale.x); out.y = Quantization.unquantize(y, this.origin.y, this.scale.y); return out; } /** Creates parameters supporting quantization of values within the range [-1.0, 1.0], appropriate for normalized 2d vectors. */ static fromNormalizedRange(rangeScale = Quantization.rangeScale16) { return QParams2d.fromRange(core_geometry_1.Range2d.createArray([core_geometry_1.Point2d.create(-1, -1), core_geometry_1.Point2d.create(1, 1)]), undefined, rangeScale); } /** Create parameters supporting quantization of values within the range [0.0, 1.0]. */ static fromZeroToOne(rangeScale = Quantization.rangeScale16) { return QParams2d.fromRange(core_geometry_1.Range2d.createArray([core_geometry_1.Point2d.create(0, 0), core_geometry_1.Point2d.create(1, 1)]), undefined, rangeScale); } /** Create parameters from origin and scale components */ static fromOriginAndScale(originX, originY, scaleX, scaleY) { return new QParams2d(originX, originY, scaleX, scaleY); } /** The diagonal of the unquantized range represented by these parameters. */ get rangeDiagonal() { return core_geometry_1.Vector2d.createFrom({ x: 0 === this.scale.x ? 0 : Quantization.rangeScale16 / this.scale.x, y: 0 === this.scale.y ? 0 : Quantization.rangeScale16 / this.scale.y }); } /** Return true if the point point is quantizable using these parameters. */ isQuantizable(point) { return Quantization.isQuantizable(point.x, this.origin.x, this.scale.x) && Quantization.isQuantizable(point.y, this.origin.y, this.scale.y); } /** @alpha */ toJSON() { return { origin: { x: this.origin.x, y: this.origin.y }, scale: { x: this.scale.x, y: this.scale.y }, }; } /** @alpha */ static fromJSON(src) { return this.fromOriginAndScale(src.origin.x, src.origin.y, src.scale.x, src.scale.y); } } exports.QParams2d = QParams2d; /** Represents a [Point2d]($core-geometry) compressed such that each component `x` and `y` is quantized to the 16-bit integer range [0, 0xffff]. * These are primarily used to reduce the space required for coordinates used by [RenderGraphic]($frontend)s. * @see [[QParams2d]] to define quantization parameters for a range of points. * @see [[QPoint2dList]] for a list of points all quantized to the same range. * @public * @extensions */ class QPoint2d { _x = 0; _y = 0; /** The quantized x component. */ get x() { return this._x; } set x(x) { (0, core_bentley_1.assert)(Quantization.isQuantized(x)); this._x = x; } /** The quantized y component. */ get y() { return this._y; } set y(y) { (0, core_bentley_1.assert)(Quantization.isQuantized(y)); this._y = y; } /** Construct with `x` and `y` initialized to zero. */ constructor() { } /** Initialize this point by quantizing the supplied { x, y } using the specified params */ init(pos, params) { this.x = Quantization.quantize(pos.x, params.origin.x, params.scale.x); this.y = Quantization.quantize(pos.y, params.origin.y, params.scale.y); } /** Create a quantized point from the supplied Point2d using the specified params */ static create(pos, params) { const qpt = new QPoint2d(); qpt.init(pos, params); return qpt; } /** Initialize `x` and `y` from `src`. */ copyFrom(src) { this.x = src.x; this.y = src.y; } /** Create a copy of this point. * @param out If supplied, it will be modified in-place and returned; otherwise a new QPoint2d will be allocated and returned. */ clone(out) { const result = undefined !== out ? out : new QPoint2d(); result.copyFrom(this); return result; } /** * Set the x and y components directly. * @param x Must be an integer in the range [0, 0xffff] * @param y Must be an integer in the range [0, 0xffff] */ setFromScalars(x, y) { this.x = x; this.y = y; } /** * Create a QPoint2d directly from x and y components. * @param x Must be an integer in the range [0, 0xffff] * @param y Must be an integer in the range [0, 0xffff] */ static fromScalars(x, y) { const pt = new QPoint2d(); pt.setFromScalars(x, y); return pt; } /** Return a Point2d unquantized according to the supplied `params`. If `out` is supplied, it will be modified in-place and returned. */ unquantize(params, out) { const pt = undefined !== out ? out : new core_geometry_1.Point2d(); pt.x = Quantization.unquantize(this.x, params.origin.x, params.scale.x); pt.y = Quantization.unquantize(this.y, params.origin.y, params.scale.y); return pt; } } exports.QPoint2d = QPoint2d; /** * @public * @extensions */ var QPoint2dBuffer; (function (QPoint2dBuffer) { const scratchQPoint2d = new QPoint2d(); /** Extracts the point at the specified index from a buffer. * @param points The buffer in which each consecutive pair of integers is a 2d quantized point. * @param pointIndex The index of the point to extract, ranging from zero to one less than the number of points in the buffer. * @param result If supplied, a preallocated [[QPoint2d]] to initialize with the result and return. * @returns The point at `pointIndex`. * @throws Error if `pointIndex` is out of bounds. */ function getQPoint(points, pointIndex, result) { const index = pointIndex * 2; const x = points[index + 0]; const y = points[index + 1]; if (undefined === x || undefined === y) throw new Error("Index out of range"); result = result ?? new QPoint2d(); result.setFromScalars(x, y); return result; } QPoint2dBuffer.getQPoint = getQPoint; /** Extracts and unquantizes the point at the specified index from a buffer. * @param buffer The array of points and the quantization parameters. * @param The index of the point to extract, ranging from zero to one less than the number of points in the buffer. * @param result If supplied, a preallocated [Point2d]($core-geometry) to initialize with the result and return. * @returns The point at `pointIndex`. * @throws Error if `pointIndex` is out of bounds. */ function unquantizePoint(buffer, pointIndex, result) { const qpt = getQPoint(buffer.points, pointIndex, scratchQPoint2d); return qpt.unquantize(buffer.params, result); } QPoint2dBuffer.unquantizePoint = unquantizePoint; })(QPoint2dBuffer || (exports.QPoint2dBuffer = QPoint2dBuffer = {})); /** A list of [[QPoint2d]]s all quantized to the same range. * @public * @extensions */ class QPoint2dList { /** Parameters used to quantize the points. */ params; _list = new Array(); /** The list of quantized points. */ get list() { return this._list; } /** Construct an empty list set up to use the supplied quantization parameters. */ constructor(params) { this.params = params.clone(); } /** Removes all points from the list. */ clear() { this._list.length = 0; } /** Removes all points from the list and change the quantization parameters. */ reset(params) { this.clear(); this.params.copyFrom(params); } /** Quantizes the supplied Point2d to this list's range and appends it to the list. */ add(pt) { this._list.push(QPoint2d.create(pt, this.params)); } /** Adds a previously-quantized point to this list. */ push(qpt) { this._list.push(qpt.clone()); } /** The number of points in the list. */ get length() { return this._list.length; } /** Returns the unquantized value of the point at the specified index in the list. */ unquantize(index, out) { (0, core_bentley_1.assert)(index < this.length); if (index < this.length) { return this._list[index].unquantize(this.params, out); } else { return undefined !== out ? out : new core_geometry_1.Point2d(); } } /** Changes the quantization parameters and requantizes all points in the list to the new range. * @note The loss of precision is compounded each time the points are requantized to a new range. */ requantize(params) { for (let i = 0; i < this.length; i++) { const pt = this.unquantize(i); this._list[i].init(pt, params); } this.params.copyFrom(params); } /** Extracts the current contents of the list as a Uint16Array such that the first element of the array corresponds to the first point's `x` component, * the second to the first point's `y` component, and so on. */ toTypedArray() { const array = new Uint16Array(this.length * 2); const pts = this._list; for (let i = 0; i < this.length; i++) { const pt = pts[i]; array[i * 2] = pt.x; array[i * 2 + 1] = pt.y; } return array; } /** Create from a Uint16Array laid out such that `array[0]` corresponds to the first point's `x` component, `array[1]` to the first point's `y` component, and so on. */ fromTypedArray(range, array) { this.params.setFromRange(range); this._list.length = array.length / 2; for (let i = 0, j = 0; i < this.list.length; i++) this._list[i] = QPoint2d.fromScalars(array[j++], array[j++]); } /** Construct a QPoint2dList containing all points in the supplied list, quantized to the range of those points. */ static fromPoints(points, out) { let qPoints; const qParams = QParams2d.fromRange(core_geometry_1.Range2d.createArray(points)); if (out) { qPoints = out; qPoints.reset(qParams); } else { qPoints = new QPoint2dList(qParams); } for (const point of points) qPoints.add(point); return qPoints; } } exports.QPoint2dList = QPoint2dList; /** Parameters used for [[Quantization]] of 3d points such that the `x`, `y`, and `z` components are each quantized to 16-bit unsigned integers. * @see [[QPoint3d]] for the quantized representation of a [Point3d]($core-geometry). * @see [[QPoint3dList]] for a list of [[QPoint3d]]s quantized using a [[QParams3d]]. * @public * @extensions */ class QParams3d { /** The origin of the quantization range. */ origin = new core_geometry_1.Point3d(); /** The scale applied to coordinates to quantize them. */ scale = new core_geometry_1.Point3d(); constructor(ox = 0, oy = 0, oz = 0, sx = 0, sy = 0, sz = 0) { this.setFrom(ox, oy, oz, sx, sy, sz); } setFrom(ox, oy, oz, sx, sy, sz) { this.origin.x = ox; this.origin.y = oy; this.origin.z = oz; this.scale.x = sx; this.scale.y = sy; this.scale.z = sz; } /** Set `x`, `y`, and `z` from `src. */ copyFrom(src) { this.setFrom(src.origin.x, src.origin.y, src.origin.z, src.scale.x, src.scale.y, src.scale.z); } /** Create a copy of these parameters. * @param out If supplied, it will be modified in-place and returned instead of allocating a new QParams3d. */ clone(out) { const result = undefined !== out ? out : new QParams3d(); result.copyFrom(this); return result; } /** Initialize from origin and scale */ setFromOriginAndScale(origin, scale) { this.setFrom(origin.x, origin.y, origin.z, scale.x, scale.y, scale.z); } /** Initialize these parameters to support quantization of values within the specified range. */ setFromRange(range, rangeScale = Quantization.rangeScale16) { if (!range.isNull) { this.setFrom(range.low.x, range.low.y, range.low.z, Quantization.computeScale(range.high.x - range.low.x, rangeScale), Quantization.computeScale(range.high.y - range.low.y, rangeScale), Quantization.computeScale(range.high.z - range.low.z, rangeScale)); } else { this.origin.x = this.origin.y = this.origin.z = 0; this.scale.x = this.scale.y = this.scale.z = 0; } } /** Return the unquantized point for the input components. * @param out If supplied, it will be modified in-place and returned instead of allocating a new Point3d. */ unquantize(x, y, z, out) { const pt = undefined !== out ? out : new core_geometry_1.Point3d(); pt.x = Quantization.unquantize(x, this.origin.x, this.scale.x); pt.y = Quantization.unquantize(y, this.origin.y, this.scale.y); pt.z = Quantization.unquantize(z, this.origin.z, this.scale.z); return pt; } /** Creates parameters to support quantization of values within the specified range. * If `out` is supplied, it will be modified in-place and returned instead of allocating a new QParams3d. */ static fromRange(range, out, rangeScale = Quantization.rangeScale16) { const params = undefined !== out ? out : new QParams3d(); params.setFromRange(range, rangeScale); return params; } /** Creates parameters supporting quantization of values within the range [-1.0, 1.0]. * If `out` is supplied, it will be modified in-place and returned instead of allocating a new QParams3d. */ static fromOriginAndScale(origin, scale, out) { const params = undefined !== out ? out : new QParams3d(); params.setFromOriginAndScale(origin, scale); return params; } /** Creates parameters supporting quantization of values within the range [-1.0, 1.0]. */ static fromNormalizedRange(rangeScale = Quantization.rangeScale16) { return QParams3d.fromRange(core_geometry_1.Range3d.createArray([core_geometry_1.Point3d.create(-1, -1, -1), core_geometry_1.Point3d.create(1, 1, 1)]), undefined, rangeScale); } /** Creates parameters supporting quantization of values within the range [0.0, 1.0]. */ static fromZeroToOne(rangeScale = Quantization.rangeScale16) { return QParams3d.fromRange(core_geometry_1.Range3d.createArray([core_geometry_1.Point3d.create(0, 0, 0), core_geometry_1.Point3d.create(1, 1, 1)]), undefined, rangeScale); } /** The diagonal of the unquantized range represented by these parameters. */ get rangeDiagonal() { return core_geometry_1.Vector3d.createFrom({ x: this.scale.x === 0 ? 0 : Quantization.rangeScale16 / this.scale.x, y: this.scale.y === 0 ? 0 : Quantization.rangeScale16 / this.scale.y, z: this.scale.z === 0 ? 0 : Quantization.rangeScale16 / this.scale.z, }); } /** Return true if the point point is quantizable using these parameters. */ isQuantizable(point) { return Quantization.isQuantizable(point.x, this.origin.x, this.scale.x) && Quantization.isQuantizable(point.y, this.origin.y, this.scale.y) && Quantization.isQuantizable(point.z, this.origin.z, this.scale.z); } /** Compute the range to which these parameters quantize. */ computeRange(out) { const range = core_geometry_1.Range3d.createNull(out); range.extendPoint(this.origin); range.extendPoint(this.origin.plus(this.rangeDiagonal)); return range; } /** @alpha */ toJSON() { return { origin: { x: this.origin.x, y: this.origin.y, z: this.origin.z }, scale: { x: this.scale.x, y: this.scale.y, z: this.scale.z }, }; } /** @alpha */ static fromJSON(src, out) { return this.fromOriginAndScale(core_geometry_1.Point3d.fromJSON(src.origin), core_geometry_1.Point3d.fromJSON(src.scale), out); } } exports.QParams3d = QParams3d; /** Represents a [Point3d]($core-geometry) compressed such that each component `x`, `y`, and `z` is quantized to the 16-bit integer range [0, 0xffff]. * These are primarily used to reduce the space required for coordinates used by [RenderGraphic]($frontend)s. * @see [[QParams3d]] to define quantization parameters for a range of points. * @see [[QPoint3dList]] for a list of points all quantized to the same range. * @public * @extensions */ class QPoint3d { _x = 0; _y = 0; _z = 0; /** The quantized x component. */ get x() { return this._x; } set x(x) { (0, core_bentley_1.assert)(Quantization.isQuantized(x)); this._x = x; } /** The quantized y component. */ get y() { return this._y; } set y(y) { (0, core_bentley_1.assert)(Quantization.isQuantized(y)); this._y = y; } /** The quantized z component. */ get z() { return this._z; } set z(z) { (0, core_bentley_1.assert)(Quantization.isQuantized(z)); this._z = z; } /** Construct with all components initialized to zero. */ constructor() { } /** Initialize this point by quantizing the supplied { x, y, z } using the specified params */ init(pos, params) { this.x = Quantization.quantize(pos.x, params.origin.x, params.scale.x); this.y = Quantization.quantize(pos.y, params.origin.y, params.scale.y); this.z = Quantization.quantize(pos.z, params.origin.z, params.scale.z); } /** Creates a quantized point from the supplied Point3d using the specified params */ static create(pos, params) { const qpt = new QPoint3d(); qpt.init(pos, params); return qpt; } /** Set this points components from `src`. */ copyFrom(src) { this.x = src.x; this.y = src.y; this.z = src.z; } /** Create a copy of this point. * @param out If supplied, it will be modified in-place instead of allocating a new QPoint3d. */ clone(out) { const result = undefined !== out ? out : new QPoint3d(); result.copyFrom(this); return result; } /** * Sets the x, y, and z components directly. * @param x Must be an integer in the range [0, 0xffff] * @param y Must be an integer in the range [0, 0xffff] * @param z Must be an integer in the range [0, 0xffff] */ setFromScalars(x, y, z) { this.x = x; this.y = y; this.z = z; } /** * Creates a QPoint3d directly from x, y, and z components. * @param x Must be an integer in the range [0, 0xffff] * @param y Must be an integer in the range [0, 0xffff] * @param z Must be an integer in the range [0, 0xffff] * @param out If supplied, it will be modified in-place instead of allocating a new QPoint3d. */ static fromScalars(x, y, z, out) { const pt = undefined === out ? new QPoint3d() : out; pt.setFromScalars(x, y, z); return pt; } /** Returns a Point3d unquantized according to the supplied params. * If `out` is supplied, it will be modified in-place instead of allocating a new Point3d. */ unquantize(params, out) { const pt = undefined !== out ? out : new core_geometry_1.Point3d(); pt.x = Quantization.unquantize(this.x, params.origin.x, params.scale.x); pt.y = Quantization.unquantize(this.y, params.origin.y, params.scale.y); pt.z = Quantization.unquantize(this.z, params.origin.z, params.scale.z); return pt; } /** Return true if this point's components are identical to the other point's components. */ equals(other) { return this.x === other.x && this.y === other.y && this.z === other.z; } /** Perform ordinal comparison to another point. The function returns: * - Zero if this point is identical to `rhs`; or * - A number less than zero if this point is ordered before `rhs`; or * - A number greater than zero if this point is ordered after `rhs`. * @see [OrderedComparator]($core-bentley). */ compare(rhs) { let diff = this.x - rhs.x; if (0 === diff) { diff = this.y - rhs.y; if (0 === diff) { diff = this.z - rhs.z; } } return diff; } } exports.QPoint3d = QPoint3d; /** @public * @extensions */ var QPoint3dBuffer; (function (QPoint3dBuffer) { const scratchQPoint3d = new QPoint3d(); /** Extracts the point at the specified index from a buffer. * @param points The buffer in which each consecutive pair of integers is a 3d quantized point. * @param pointIndex The index of the point to extract, ranging from zero to one less than the number of points in the buffer. * @param result If supplied, a preallocated [[QPoint3d]] to initialize with the result and return. * @returns The point at `pointIndex`. * @throws Error if `pointIndex` is out of bounds. */ function getQPoint(points, pointIndex, result) { const index = pointIndex * 3; const x = points[index + 0]; const y = points[index + 1]; const z = points[index + 2]; if (undefined === x || undefined === y || undefined === z) throw new Error("Index out of range"); result = result ?? new QPoint3d(); result.setFromScalars(x, y, z); return result; } QPoint3dBuffer.getQPoint = getQPoint; /** Extracts and unquantizes the point at the specified index from a buffer. * @param buffer The array of points and the quantization parameters. * @param buffer The index of the point to extract, ranging from zero to one less than the number of points in the buffer. * @param result If supplied, a preallocated [Point3d]($core-geometry) to initialize with the result and return. * @returns The point at `pointIndex`. * @throws Error if `pointIndex` is out of bounds. */ function unquantizePoint(buffer, pointIndex, result) { const qpt = getQPoint(buffer.points, pointIndex, scratchQPoint3d); return qpt.unquantize(buffer.params, result); } QPoint3dBuffer.unquantizePoint = unquantizePoint; })(QPoint3dBuffer || (exports.QPoint3dBuffer = QPoint3dBuffer = {})); /** A list of [[QPoint3d]]s all quantized to the same range. * @public * @extensions */ class QPoint3dList { /** Parameters used to quantize the points. */ params; _list = []; /** The list of quantized points. */ get list() { return this._list; } /** Construct an empty list set up to quantize to the supplied range. * @param params The quantization parameters. If omitted, a null range will be used. */ constructor(params) { this.params = params ? params.clone() : QParams3d.fromRange(core_geometry_1.Range3d.createNull()); } /** Construct a QPoint3dList containing all points in the supplied list, quantized to the range of those points. * @param points The points to quantize and add to the list. * @param out If supplied, it will be cleared, its parameters recomputed, and the points will be added to it; otherwise, a new QPoint3dList will be created and returned. */ static fromPoints(points, out) { let qPoints; const qParams = QParams3d.fromRange(core_geometry_1.Range3d.createArray(points)); if (out) { qPoints = out; qPoints.reset(qParams); } else { qPoints = new QPoint3dList(qParams); } for (const point of points) qPoints.add(point); return qPoints; } /** Removes all points from the list. */ clear() { this._list.length = 0; } /** Clears out the contents of the list and changes the quantization parameters. */ reset(params) { this.clear(); this.params.copyFrom(params); } /** Quantizes the supplied Point3d to this list's range and appends it to the list. */ add(pt) { this._list.push(QPoint3d.create(pt, this.params)); } /** Adds a previously-quantized point to this list. */ push(qpt) { this._list.push(qpt.clone()); } /** The number of points in the list. */ get length() { return this._list.length; } /** Returns the unquantized value of the point at the specified index in the list. */ unquantize(index, out) { (0, core_bentley_1.assert)(index < this.length); if (index < this.length) { return this._list[index].unquantize(this.params, out); } else { return undefined !== out ? out : new core_geometry_1.Point3d(); } } /** Changes the quantization parameters and requantizes all points in the list to the new range. * @note The loss of precision is compounded each time the points are requantized to a new range. */ requantize(params) { for (let i = 0; i < this.length; i++) { const pt = this.unquantize(i); this._list[i].init(pt, params); } this.params.copyFrom(params); } /** Extracts the current contents of the list as a Uint16Array such that the first 3 elements contain the first point's x, y, and z components, * the second three elements contain the second point's components, and so on. */ toTypedArray() { const array = new Uint16Array(this.length * 3); const pts = this._list; for (let i = 0; i < this.length; i++) { const pt = pts[i]; array[i * 3 + 0] = pt.x; array[i * 3 + 1] = pt.y; array[i * 3 + 2] = pt.z; } return array; } /** Reinitialize from a Uint16Array in which the first three elements specify the x, y, and z components of the first point, the second three elements specify the components * of the second point, and so on. */ fromTypedArray(range, array) { this.params.setFromRange(range); this._list.length = array.length / 3; for (let i = 0, j = 0; i < this.list.length; i++) this._list[i] = QPoint3d.fromScalars(array[j++], array[j++], array[j++]); } /** Construct a list containing all points in the supplied list, quantized using the supplied parameters. */ static createFrom(points, params) { const list = new QPoint3dList(params); for (const point of points) list.add(point); return list; } /** An iterator over the points in the list. */ [Symbol.iterator]() { return this.list[Symbol.iterator](); } } exports.QPoint3dList = QPoint3dList; /** Constructs a [[QPoint2dBuffer]] using a [Uint16ArrayBuilder]($bentley). * @public * @extensions */ class QPoint2dBufferBuilder { _scratchQPoint2d = new QPoint2d(); /** The parameters used to quantize the points in the [[buffer]]. */ params; /** The buffer that holds the points. */ buffer; /** Construct a new buffer with a [[length]] of zero. */ constructor(options) { this.params = QParams2d.fromRange(options.range); const initialCapacity = options.initialCapacity ?? 0; this.buffer = new core_bentley_1.Uint16ArrayBuilder({ growthFactor: options.growthFactor, initialCapacity: 2 * initialCapacity, }); } /** Append a point with the specified quantized coordinates. */ pushXY(x, y) { this.buffer.push(x); this.buffer.push(y); } /** Append a point with the specified quantized coordinates. */ push(pt) { this.pushXY(pt.x, pt.y); } /** The number of points currently in the [[buffer]]. */ get length() { const len = this.buffer.length; (0, core_bentley_1.assert)(len % 2 === 0); return len / 2; } /** Returns the quantized point at the specified index in [[buffer]]. * @param pointIndex The index of the point of interest, ranging from zero to one minus the number of points currently in the [[buffer]]. * @param result If supplied, a [[QPoint2d]] to initialize with the result and return. * @returns The quantized point at the specified index in [[buffer]]. * @throws Error if `pointIndex` is out of bounds. */ get(pointIndex, result) { return QPoint2dBuffer.getQPoint(this.buffer.toTypedArray(), pointIndex, result); } /** Returns the unquantized point at the specified index in [[buffer]]. * @param pointIndex The index of the point of interest, ranging from zero to one minus the number of points currently in the [[buffer]]. * @param result If supplied, a [Point2d]($core-geometry) to initialize with the result and return. * @returns The unquantized point at the specified index in [[buffer]]. * @throws Error if `pointIndex` is out of bounds. */ unquantize(pointIndex, result) { return this.get(pointIndex, this._scratchQPoint2d).unquantize(this.params, result); } /** Obtain a [[QPoint2dBuffer]] containing all of the points that have been appended by this builder. */ finish() { return { params: this.params, points: this.buffer.toTypedArray(), }; } } exports.QPoint2dBufferBuilder = QPoint2dBufferBuilder; /** Constructs a [[QPoint3dBuffer]] using a [Uint16ArrayBuilder]($bentley). * @public * @extensions */ class QPoint3dBufferBuilder { _scratchQPoint3d = new QPoint3d(); /** The parameters used to quantize the points in the [[buffer]]. */ params; /** The buffer that holds the points. */ buffer; /** Construct a new buffer with a [[length]] of zero. */ constructor(options) { this.params = QParams3d.fromRange(options.range); const initialCapacity = options.initialCapacity ?? 0; this.buffer = new core_bentley_1.Uint16ArrayBuilder({ growthFactor: options.growthFactor, initialCapacity: 3 * initialCapacity, }); } /** Append a point with the specified quantized coordinates. */ pushXYZ(x, y, z) { this.buffer.push(x); this.buffer.push(y); this.buffer.push(z); } /** Append a point with the specified quantized coordinates. */ push(pt) { this.pushXYZ(pt.x, pt.y, pt.z); } /** The number of points currently in the [[buffer]]. */ get length() { const len = this.buffer.length; (0, core_bentley_1.assert)(len % 3 === 0); return len / 3; } /** Returns the quantized point at the specified index in [[buffer]]. * @param pointIndex The index of the point of interest, ranging from zero to one minus the number of points currently in the [[buffer]]. * @param result If supplied, a [[QPoint3d]] to initialize with the result and return. * @returns The quantized point at the specified index in [[buffer]]. * @throws Error if `pointIndex` is out of bounds. */ get(pointIndex, result) { return QPoint3dBuffer.getQPoint(this.buffer.toTypedArray(), pointIndex, result); } /** Returns the unquantized point at the specified index in [[buffer]]. * @param pointIndex The index of the point of interest, ranging from zero to one minus the number of points currently in the [[buffer]]. * @param result If supplied, a [Point3d]($core-geometry) to initialize with the result and return. * @returns The unquantized point at the specified index in [[buffer]]. * @throws Error if `pointIndex` is out of bounds. */ unquantize(pointIndex, result) { return this.get(pointIndex, this._scratchQPoint3d).unquantize(this.params, result); } /** Obtain a [[QPoint3dBuffer]] containing all of the points that have been appended by this builder. */ finish() { return { params: this.params, points: this.buffer.toTypedArray(), }; } } exports.QPoint3dBufferBuilder = QPoint3dBufferBuilder; //# sourceMappingURL=QPoint.js.map