@itwin/core-common
Version:
iTwin.js components common to frontend and backend
188 lines • 9.99 kB
JavaScript
"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.FeatureTable = exports.BatchType = exports.PackedFeature = exports.ModelFeature = exports.Feature = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const GeometryParams_1 = require("./GeometryParams");
const PackedFeatureTable_1 = require("./internal/PackedFeatureTable");
/** Describes a discrete entity within a batched [RenderGraphic]($frontend) that can be
* grouped with other such entities in a [[FeatureTable]].
* Features roughly correlate to elements: a [Tile]($frontend)'s graphics combines geometry from every
* [GeometricElement]($backend) that intersects the tile's volume, so each element produces at least one feature.
* However, an element's geometry stream can contain geometry belonging to multiple different combinations of [SubCategory]($backend) and
* [[GeometryClass]], so an individual element may produce more than one feature.
* @see [[FeatureOverrides]] for customizing the appearance of individual features.
* @public
*/
class Feature {
elementId;
subCategoryId;
geometryClass;
constructor(elementId = core_bentley_1.Id64.invalid, subCategoryId = core_bentley_1.Id64.invalid, geometryClass = GeometryParams_1.GeometryClass.Primary) {
this.elementId = elementId;
this.subCategoryId = subCategoryId;
this.geometryClass = geometryClass;
}
get isDefined() { return !core_bentley_1.Id64.isInvalid(this.elementId) || !core_bentley_1.Id64.isInvalid(this.subCategoryId) || this.geometryClass !== GeometryParams_1.GeometryClass.Primary; }
get isUndefined() { return !this.isDefined; }
/** Returns true if this feature is equivalent to the supplied feature. */
equals(other) { return 0 === this.compare(other); }
/** Performs ordinal comparison of this feature with another.
* @param rhs The feature to compare with.
* @returns zero if the features are equivalent, a negative value if this feature compares as "less than" `rhs`, or a positive value if this feature compares "greater than" `rhs`.
*/
compare(rhs) {
if (this === rhs)
return 0;
let cmp = (0, core_bentley_1.compareNumbers)(this.geometryClass, rhs.geometryClass);
if (0 === cmp) {
cmp = (0, core_bentley_1.compareStrings)(this.elementId, rhs.elementId);
if (0 === cmp) {
cmp = (0, core_bentley_1.compareStrings)(this.subCategoryId, rhs.subCategoryId);
}
}
return cmp;
}
}
exports.Feature = Feature;
/** @public */
var ModelFeature;
(function (ModelFeature) {
/** Create a ModelFeature of [[GeometryClass.Primary]] with all invalid Ids.
* This is primarily useful for creating a `result` argument for [[RenderFeatureTable.findFeature]] and [[RenderFeatureTable.getFeature]].
*/
function create() {
return {
modelId: core_bentley_1.Id64.invalid,
elementId: core_bentley_1.Id64.invalid,
subCategoryId: core_bentley_1.Id64.invalid,
geometryClass: GeometryParams_1.GeometryClass.Primary,
};
}
ModelFeature.create = create;
/** Returns `true` if any of `feature`'s properties differ from the defaults (invalid Ids and [[GeometryClass.Primary]]). */
function isDefined(feature) {
return !core_bentley_1.Id64.isInvalid(feature.modelId) || !core_bentley_1.Id64.isInvalid(feature.elementId) || !core_bentley_1.Id64.isInvalid(feature.subCategoryId) || feature.geometryClass !== GeometryParams_1.GeometryClass.Primary;
}
ModelFeature.isDefined = isDefined;
/** @alpha */
function unpack(packed, result, unpackedModelId) {
result.modelId = unpackedModelId ?? core_bentley_1.Id64.fromUint32PairObject(packed.modelId);
result.elementId = core_bentley_1.Id64.fromUint32PairObject(packed.elementId);
result.subCategoryId = core_bentley_1.Id64.fromUint32PairObject(packed.subCategoryId);
result.geometryClass = packed.geometryClass;
return result;
}
ModelFeature.unpack = unpack;
})(ModelFeature || (exports.ModelFeature = ModelFeature = {}));
/** @public */
var PackedFeature;
(function (PackedFeature) {
/** Create a PackedFeature of [[GeometryClass.Primary]] with all invalid Ids.
* This is primarily useful for creating a `result` argument for [[RenderFeatureTable.getPackedFeature]].
*/
function create() {
const pair = { upper: 0, lower: 0 };
return {
modelId: { ...pair },
elementId: { ...pair },
subCategoryId: { ...pair },
geometryClass: GeometryParams_1.GeometryClass.Primary,
animationNodeId: 0,
};
}
PackedFeature.create = create;
/** Create a PackedFeatureWithIndex of [[GeometryClass.Primary]] with all invalid Ids and an index of zero.
* This is primarily useful for creating a reusable `output` argument for [[RenderFeatureTable.iterable]].
*/
function createWithIndex() {
const result = create();
result.index = 0;
return result;
}
PackedFeature.createWithIndex = createWithIndex;
})(PackedFeature || (exports.PackedFeature = PackedFeature = {}));
/** Describes the type of a 'batch' of graphics representing multiple [[Feature]]s.
* The most commonly-encountered batches are Tiles, which can be of either Primary or
* Classifier type.
* @public
* @extensions
*/
var BatchType;
(function (BatchType) {
/** This batch contains graphics derived from a model's visible geometry. */
BatchType[BatchType["Primary"] = 0] = "Primary";
/**
* This batch contains color volumes which are used to classify a model's visible geometry.
* The graphics themselves are not rendered to the screen; instead they are rendered to the stencil buffer
* to resymbolize the primary geometry.
*/
BatchType[BatchType["VolumeClassifier"] = 1] = "VolumeClassifier";
/**
* This batch contains planar graphics which are used to classify a model's visible geometry.
* The graphics themselves are not rendered to the screen; instead they are rendered to a texture buffer
* to resymbolize the primary geometry.
*/
BatchType[BatchType["PlanarClassifier"] = 2] = "PlanarClassifier";
})(BatchType || (exports.BatchType = BatchType = {}));
/** Defines a look-up table for [[Feature]]s within a batched [RenderGraphic]($frontend). Consecutive 32-bit
* indices are assigned to each unique Feature. Primitives within the RenderGraphic can
* use per-vertex indices to specify the distribution of Features within the primitive. The appearance of individual
* features can be customized using [[FeatureOverrides]]. Typically a [Tile]($frontend) will contain a feature table
* identifying the elements whose geometry appears within that tile.
* @see [[FeatureOverrides]] for customizing the appearance of individual features.
* @public
*/
class FeatureTable extends core_bentley_1.IndexMap {
modelId;
type;
/** Construct an empty FeatureTable. */
constructor(maxFeatures, modelId = core_bentley_1.Id64.invalid, type = BatchType.Primary) {
super((lhs, rhs) => lhs.compare(rhs), maxFeatures);
this.modelId = modelId;
this.type = type;
}
/** Returns the maximum number of [[Feature]]s this FeatureTable can contain. */
get maxFeatures() { return this._maximumSize; }
/** Returns true if this table contains at least one [[Feature]] with a valid element and/or subcategory Id. */
get anyDefined() { return this.length > 1 || (1 === this.length && this._array[0].value.isDefined); }
/** Returns true if this FeatureTable contains exactly one [[Feature]]. */
get isUniform() { return 1 === this.length; }
/** If this FeatureTable contains exactly one [[Feature]], returns that Feature; otherwise returns undefined. */
get uniform() { return 1 === this.length ? this._array[0].value : undefined; }
/** Returns true if this FeatureTable is associated with [[BatchType.VolumeClassifier]] geometry. */
get isVolumeClassifier() { return BatchType.VolumeClassifier === this.type; }
/** Returns true if this FeatureTable is associated with [[BatchType.PlanarClassifier]] geometry. */
get isPlanarClassifier() { return BatchType.PlanarClassifier === this.type; }
/** Returns the Feature corresponding to the specified index, or undefined if the index is not present. */
findFeature(index) {
for (const entry of this._array)
if (entry.index === index)
return entry.value;
return undefined;
}
/** Inserts the specified [[Feature]] at the specified index. This is really only useful when reconstructing a previously-create feature table
* for which you know the index assigned to each feature.
*/
insertWithIndex(feature, index) {
const bound = this.lowerBound(feature);
(0, core_bentley_1.assert)(!bound.equal);
(0, core_bentley_1.assert)(!this.isFull);
const entry = new core_bentley_1.IndexedValue(feature, index);
this._array.splice(bound.index, 0, entry);
}
/** Access the underlying array containing the table's current contents. */
getArray() { return this._array; }
/** Convert this feature table to a representation that can be supplied to [RenderSystem.createBatch]($frontend). */
pack() {
return PackedFeatureTable_1.PackedFeatureTable.pack(this);
}
}
exports.FeatureTable = FeatureTable;
//# sourceMappingURL=FeatureTable.js.map