UNPKG

@itwin/core-backend

Version:
307 lines • 13.7 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module ExportGraphics */ import { assert } from "@itwin/core-bentley"; import { IndexedPolyface, PolyfaceData } from "@itwin/core-geometry"; /** Provides utility functions for working with data generated by [IModelDb.exportGraphics]($core-backend) * @public */ export var ExportGraphics; (function (ExportGraphics) { /** Test if ExportPartDisplayInfos have exactly the same values. * @public */ function arePartDisplayInfosEqual(lhs, rhs) { if (lhs.categoryId !== rhs.categoryId) return false; if (lhs.subCategoryId !== rhs.subCategoryId) return false; if (lhs.materialId !== rhs.materialId) return false; if (lhs.elmTransparency !== rhs.elmTransparency) return false; if (lhs.lineColor !== rhs.lineColor) return false; return true; } ExportGraphics.arePartDisplayInfosEqual = arePartDisplayInfosEqual; /** * Convert an ExportGraphicsMesh to an IndexedPolyface usable by the geometry API. * @note The resulting IndexedPolyface may have duplicate points, normals and params. If problematic, call [PolyfaceData.compress]($core-geometry) * @public */ function convertToIndexedPolyface(mesh) { const polyface = IndexedPolyface.create(true, true, false, mesh.isTwoSided); const p = mesh.points; for (let i = 0; i < p.length; i += 3) polyface.data.point.pushXYZ(p[i], p[i + 1], p[i + 2]); const n = mesh.normals; assert(undefined !== polyface.data.normal); for (let i = 0; i < n.length; i += 3) polyface.data.normal.pushXYZ(n[i], n[i + 1], n[i + 2]); const uv = mesh.params; assert(undefined !== polyface.data.param); for (let i = 0; i < uv.length; i += 2) polyface.data.param.pushXY(uv[i], uv[i + 1]); const indices = mesh.indices; const addIndex = (idx) => { polyface.addPointIndex(idx, true); polyface.addNormalIndex(idx); polyface.addParamIndex(idx); }; for (let i = 0; i < indices.length; i += 3) { addIndex(indices[i]); addIndex(indices[i + 1]); addIndex(indices[i + 2]); polyface.terminateFacet(false); } return polyface; } ExportGraphics.convertToIndexedPolyface = convertToIndexedPolyface; })(ExportGraphics || (ExportGraphics = {})); /** * * Iterator to walk the facets of an ExportGraphicsMesh and present them to the world as if visiting a Polyface. * * Because the ExportGraphicsMesh has limited data: * * There is no auxData in this visitor. * * There is no color in this visitor. * * All edgeVisible are true. * @public */ export class ExportGraphicsMeshVisitor extends PolyfaceData { _currentFacetIndex; _nextFacetIndex; _numWrap; _polyface; constructor(facets, numWrap) { super(facets.normals.length > 0, facets.params.length > 0, false, facets.isTwoSided); this._polyface = facets; this._numWrap = numWrap; this._nextFacetIndex = 0; this._currentFacetIndex = -1; this.reset(); } /** Create a visitor for iterating the facets of `polyface`, with indicated number of points to be added to each facet to produce closed point arrays * Typical wrap counts are: * * 0 -- leave the point arrays with "missing final edge" (default) * * 1 -- add point 0 as closure point * * 2 -- add points 0 and 1 as closure and wrap point. This is useful when vertex visit requires two adjacent vectors, e.g. for cross products. */ static create(polyface, numWrap = 0) { return new ExportGraphicsMeshVisitor(polyface, numWrap); } /** Restart the visitor at the first facet. */ reset() { this.moveToReadIndex(0); this._nextFacetIndex = 0; // so immediate moveToNextFacet stays here } /** Select a facet by simple index. */ moveToReadIndex(facetIndex) { if (facetIndex < 0 || 2 + facetIndex * 3 >= this._polyface.indices.length) return false; if (this._currentFacetIndex !== facetIndex || 3 + this._numWrap !== this.point.length) { this._currentFacetIndex = facetIndex; this.point.length = 0; this.pointIndex.length = 0; this.edgeVisible.length = 0; const sourcePoints = this._polyface.points; const indices = this._polyface.indices; const i0 = 3 * facetIndex; for (let i = i0; i < i0 + 3; i++) { const k = 3 * indices[i]; this.pointIndex.push(indices[i]); this.point.pushXYZ(sourcePoints[k], sourcePoints[k + 1], sourcePoints[k + 2]); this.edgeVisible.push(true); } for (let i = 0; i < this._numWrap; i++) { this.point.pushFromGrowableXYZArray(this.point, i); } const sourceParams = this._polyface.params; if (sourceParams.length > 0 && this.paramIndex && this.param) { this.paramIndex.length = 0; this.param.length = 0; for (let i = i0; i < i0 + 3; i++) { const k = 2 * indices[i]; this.paramIndex.push(indices[i]); this.param.pushXY(sourceParams[k], sourceParams[k + 1]); } for (let i = 0; i < this._numWrap; i++) { this.param.pushFromGrowableXYArray(this.param, i); } } const sourceNormals = this._polyface.normals; if (sourceNormals.length > 0 && this.normalIndex && this.normal) { this.normalIndex.length = 0; this.normal.length = 0; for (let i = i0; i < i0 + 3; i++) { const k = 3 * indices[i]; this.normalIndex.push(indices[i]); this.normal.pushXYZ(sourceNormals[k], sourceNormals[k + 1], sourceNormals[k + 2]); } for (let i = 0; i < this._numWrap; i++) { this.normal.pushFromGrowableXYZArray(this.normal, i); } } } this._nextFacetIndex = facetIndex + 1; return true; } /** Load data for the next facet. */ moveToNextFacet() { if (this._nextFacetIndex !== this._currentFacetIndex) return this.moveToReadIndex(this._nextFacetIndex); this._nextFacetIndex++; return true; } /** Set the number of vertices to replicate in visitor arrays. */ setNumWrap(numWrap) { this._numWrap = numWrap; } /** Return the index (in the client polyface) of the current facet */ currentReadIndex() { return this._currentFacetIndex; } /** Return the point index of vertex i within the currently loaded facet */ clientPointIndex(i) { return this.pointIndex[i]; } /** Return the param index of vertex i within the currently loaded facet. * Use the artificial paramIndex, which matches pointIndex. */ clientParamIndex(i) { return this.paramIndex ? this.paramIndex[i] : -1; } /** Return the normal index of vertex i within the currently loaded facet. * Use the artificial paramIndex, which matches pointIndex. */ clientNormalIndex(i) { return this.normalIndex ? this.normalIndex[i] : -1; } /** Always returns -1 since we never have colors. */ clientColorIndex(_i) { return -1; } /** Always returns -1 since we never have auxiliary data. */ clientAuxIndex(_i) { return -1; } /** return the client polyface */ clientPolyface() { return undefined; } /** clear the contents of all arrays. Use this along with transferDataFrom methods to build up new facets */ clearArrays() { if (this.point !== undefined) this.point.length = 0; if (this.param !== undefined) this.param.length = 0; if (this.normal !== undefined) this.normal.length = 0; // ignore color and aux -- they never exist. } /** transfer interpolated data from the other visitor. * * all data values are interpolated at `fraction` between `other` values at index0 and index1. */ pushInterpolatedDataFrom(other, index0, fraction, index1) { this.point.pushInterpolatedFromGrowableXYZArray(other.point, index0, fraction, index1); if (this.param && other.param && index0 < other.param.length && index1 < other.param.length) this.param.pushInterpolatedFromGrowableXYArray(other.param, index0, fraction, index1); if (this.normal && other.normal && index0 < other.normal.length && index1 < other.normal.length) this.normal.pushInterpolatedFromGrowableXYZArray(other.normal, index0, fraction, index1); } /** transfer data from a specified index of the other visitor as new data in this visitor. */ pushDataFrom(other, index) { this.point.pushFromGrowableXYZArray(other.point, index); if (this.param && other.param && index < other.param.length) this.param.pushFromGrowableXYArray(other.param, index); if (this.normal && other.normal && index < other.normal.length) this.normal.pushFromGrowableXYZArray(other.normal, index); // ignore color and aux -- they never exist. } /** Return the number of facets this visitor is able to visit */ getVisitableFacetCount() { return Math.floor(this._polyface.indices.length / 3); } /** Create a visitor for a subset of the facets visitable by the instance. */ createSubsetVisitor(facetIndices, numWrap = 0) { return ExportGraphicsMeshSubsetVisitor.createSubsetVisitor(this._polyface, facetIndices, numWrap); } } /** * An `ExportGraphicsMeshSubsetVisitor` is an `ExportGraphicsMeshVisitor` which only visits a subset of the facets. * * The subset is defined by an array of facet indices provided when this visitor is created. * * Input indices (e.g., for `moveToReadIndex`) are understood to be indices into the subset array. * @public */ export class ExportGraphicsMeshSubsetVisitor extends ExportGraphicsMeshVisitor { _facetIndices; _currentSubsetIndex; // index within _facetIndices _nextSubsetIndex; // index within _facetIndices constructor(polyface, facetIndices, numWrap) { super(polyface, numWrap); this._facetIndices = facetIndices.slice(); this._currentSubsetIndex = -1; this._nextSubsetIndex = 0; this.reset(); } isValidSubsetIndex(index) { return index >= 0 && index < this._facetIndices.length; } /** * Create a visitor for iterating a subset of the facets of `polyface`. * @param polyface reference to the client polyface, supplying facets * @param facetIndices array of indices of facets in the client polyface to visit. This array is cloned. * @param numWrap number of vertices replicated in the visitor arrays to facilitate simpler caller code. Default is zero. */ static createSubsetVisitor(polyface, facetIndices, numWrap = 0) { return new ExportGraphicsMeshSubsetVisitor(polyface, facetIndices, numWrap); } /** * Advance the iterator to a particular facet in the subset of client polyface facets. * @param subsetIndex index into the subset array, not to be confused with the client facet index. * @return whether the iterator was successfully moved. */ moveToReadIndex(subsetIndex) { if (this.isValidSubsetIndex(subsetIndex)) { this._currentSubsetIndex = subsetIndex; this._nextSubsetIndex = subsetIndex + 1; return super.moveToReadIndex(this._facetIndices[subsetIndex]); } return false; } /** * Advance the iterator to the next facet in the subset of client polyface facets. * @return whether the iterator was successfully moved. */ moveToNextFacet() { if (this._nextSubsetIndex !== this._currentSubsetIndex) return this.moveToReadIndex(this._nextSubsetIndex); this._nextSubsetIndex++; return true; } /** Restart the visitor at the first facet. */ reset() { if (this._facetIndices) { // avoid crash during super ctor when we aren't yet initialized this.moveToReadIndex(0); this._nextSubsetIndex = 0; // so immediate moveToNextFacet stays here } } /** * Return the client polyface facet index (aka "readIndex") for the given subset index. * @param subsetIndex index into the subset array. Default is the subset index of the currently visited facet. * @return valid client polyface facet index, or `undefined` if invalid subset index. */ parentFacetIndex(subsetIndex) { if (undefined === subsetIndex) subsetIndex = this._currentSubsetIndex; return this.isValidSubsetIndex(subsetIndex) ? this._facetIndices[subsetIndex] : undefined; } /** Return the number of facets this visitor is able to visit. */ getVisitableFacetCount() { return this._facetIndices.length; } } //# sourceMappingURL=ExportGraphics.js.map