import { StepIndexEntry } from "./parsing/step_parser.js"; import { StepBufferProvider, StepExternalByteStore } from "./step_buffer_provider.js"; import StepEntityBase from "./step_entity_base.js"; import StepEntitySchema from "./step_entity_schema.js"; import StepEntityInternalReference from "./step_entity_internal_reference.js"; import { IIndexSetCursor } from "../core/i_index_set_cursor.js"; import { MultiIndexSet } from "../indexing/multi_index_set.js"; import StepEntityConstructor, { StepEntityConstructorAbstract } from "./step_entity_constructor.js"; import { Model, ModelGeometry } from "../core/model.js"; import { ReadonlyUint32Array } from "../core/readonly_typed_array.js"; import { CanonicalMaterial } from "../core/canonical_material.js"; import { SceneNodeGeometry } from "../core/scene_node.js"; import { CanonicalMesh } from "../core/canonical_mesh.js"; import { ModelMaterials } from "../core/model_materials.js"; /** * The base for models parsed from STEP. */ export default abstract class StepModelBase = StepEntityBase> implements Iterable, Model { readonly schema: StepEntitySchema; private buffer_; abstract readonly typeIndex: MultiIndexSet; abstract readonly externalMappingType: StepEntityConstructor; private readonly vtableBuilder_; private readonly expressIDMap_; private readonly inlineAddressMap_; private readonly address_; private readonly length_; private readonly typeID_; private readonly expressID_; private readonly count_; private readonly firstInlineElement_; private descriptorCache_; private readonly complexEntries_?; private bufferProvider_; /** * Will this model memoize elements, set to false to disable, * true to enable. * * Note that during periods where element memoization is disabled, * it's not guaranteed element objects returned from this have referential * equality even if they have ID equality. */ elementMemoization: boolean; /** * When an atribute is parsed from an entity in the model that causes a recoverable * error, and the field is optional, return null instead of throwing an exception. */ nullOnErrors: boolean; abstract readonly materials?: ModelMaterials; abstract readonly geometry?: ModelGeometry; /** * Construct this step model with its matching schema, a buffer to read from and an element index. * * @param schema The Step schema this is based on. * @param buffer_ The buffer to read this from. Pass `undefined` together * with `provider` to build a model whose source is windowed from * construction (e.g. a streaming open — see buildModelStreaming); the * synchronous read paths (geometry extraction) then require the relevant * ranges to be resident, exactly as after `spillSourceToExternalStore`. * @param elementIndex The element index for this, parsed or deserialized - note this takes * ownership of this array in the sense it will modify values/unfold inline elements etc. * @param provider Optional pre-built buffer provider. When omitted, a * resident provider over `buffer_` is used (the classic path). */ constructor(schema: StepEntitySchema, buffer_: Uint8Array | undefined, elementIndex: StepIndexEntry[], provider?: StepBufferProvider); /** * Materialise the descriptor object for a local ID from the columns. Only the * persistent scalars are set; lazy fields (vtable, buffer, entity) are filled * in on demand by populateVtableEntry / entity construction. * * @param localID The local ID to build a descriptor for. * @return {StepEntityInternalReferencePrivate} The descriptor. */ private makeDescriptor; /** * Get the (cached or freshly materialised) descriptor for a local ID. The * same object is returned for repeated calls until invalidate(), so entities * built on it and populateVtableEntry() mutations agree. * * @param localID The local ID to get a descriptor for. * @return {StepEntityInternalReferencePrivate} The descriptor. */ private entry; /** * Invalidate the cache store for this, so new items will be created. * * @param dropVtable If true, remove the vtable entries for old entries as well, * freeing up the v-table space on garbage collection. */ invalidate(dropVtable?: boolean): void; /** * Populate a raw vtable entry for a particular element, extra * * @param element The raw elment to populate the vtable entry for. * @return {boolean} Did the vtable entry populate correctly? */ populateVtableEntryRaw(element: StepEntityInternalReference): boolean; /** * Force the population of the the vtable entry for a particular ID * (i.e. extracting the field locations) * * @param localID The id to fetch the vtable entry for. * @throws {Error} Throws an error if the ID is invalid. * @return {boolean} Did the vtable entry populate correctly? */ populateVtableEntry(localID: number): boolean; /** * Force the population of the the buffer entry for a particular element. * * @param localID The local id to fetch the buffer entry for. * @throws {Error} Throws an error if the ID is invalid. */ populateBufferEntry(localID: number): void; /** * Get the size in bytes of the backing buffer for this. * * @return {number} The number of elements. */ get bufferBytesize(): number; /** * Are the source bytes held externally (spilled), i.e. windowed in * on demand rather than fully resident? * * @return {boolean} True after a successful `spillSourceToExternalStore`. */ get isSourceExternal(): boolean; /** * Bytes of source currently held resident by the buffer provider * (the whole buffer before a spill; the windowed working set after). * * @return {number} The resident byte count. */ get residentSourceBytes(): number; /** * Release the resident source buffer and serve subsequent record * reads from fixed-size windows paged in from an external store. * * The store must contain EXACTLY the model's source bytes (same * length; byte-identical content is the caller's responsibility — * typically the original file already sitting in OPFS). All cached * descriptors/entities are invalidated, since they hold views over * the released buffer; they rematerialise on demand through the * windowed provider. * * After this, synchronous extraction of a record whose range isn't * resident throws StepBufferNotResidentError — async API surfaces * must call `ensureResidentByExpressID` / `ensureResidentByLocalID` * first. Parse and geometry extraction always run before any spill, * so those paths are unaffected. * * @param store The external store holding the source bytes. * @param chunkBytes Optional window size in bytes. * @param maxResidentChunks Optional residency cap in windows. */ spillSourceToExternalStore(store: StepExternalByteStore, chunkBytes?: number, maxResidentChunks?: number): void; /** * Page in the byte range(s) backing a record so following * synchronous extraction of it succeeds. Covers the record's own * range (which contains any inline elements) and, for complex / * external-mapped records, each mapped class record's range. * * No-op (fast resolved promise) while the source is fully resident. * * @param localID The local ID of the record. * @return {Promise< void >} Resolves when resident. */ ensureResidentByLocalID(localID: number): Promise; /** * Page in the byte range(s) backing a record by express ID — see * `ensureResidentByLocalID`. Unknown express IDs resolve silently * (the following read will surface the miss the same way it does * for a fully-resident model). * * @param expressID The express ID of the record. * @return {Promise< void >} Resolves when resident. */ ensureResidentByExpressID(expressID: number): Promise; /** * Get the number of elements/entities in this model. * * @return {number} The number of elements. */ get size(): number; /** * Get an inline element by address. * * @param address * @return {BaseEntity | undefined} The number of elements. */ getInlineElementByAddress(address: number | undefined): BaseEntity | undefined; /** * Get an inline element by address. * * @param address * @param type * @return {BaseEntity | undefined} The number of elements. */ getTypedInlineElementByAddress, O extends InstanceType & BaseEntity>(address: number | undefined, type: T): O | undefined; /** * Given an express ID, return the matching element if one exists. * * @param {number} expressID The express ID to fetch the element for. * @return {object | undefined} The element if one exists for that ID, * otherwise undefined. */ getElementByExpressID(expressID: number): BaseEntity | undefined; /** * Given an express ID, return the matching element if one exists. * * @param {number} expressID The express ID to fetch the element for. * @param {StepEntityConstructorAbstract} type The constructor matching the type * of the element to fetch. * @return {object | undefined} The element if one exists for that ID, * otherwise undefined. */ getTypedElementByExpressID, O extends InstanceType & BaseEntity>(expressID: number, type: T): O | undefined; /** * Given a local ID (i.e. dense index/reference), return the matching element if one * exists. * * @param {number} localID The local ID to fetch for. * @param {StepEntityConstructorAbstract} type The constructor matching the type * of the element to fetch. * @return {object | undefined} The matching element or undefined * if none exists. */ getTypedElementByLocalID, O extends InstanceType & BaseEntity>(localID: number, type: StepEntityConstructorAbstract): O | undefined; /** * Map an array of local IDs to their matching express IDs. * * @param from local ID array * @return {Uint32Array} express ID array */ mapLocalIDsToExpressIDs(from: ReadonlyUint32Array): Uint32Array; /** * Given an express ID, return the matching element if one exists. * * @param {number} localID The local ID to fetch the element for. * @return {number | undefined} The express ID if one exists for that local ID, * otherwise undefined. */ getExpressIDByLocalID(localID: number): number | undefined; /** * Given a local ID (i.e. dense index/reference), return the matching element if one * exists. * * @param {number} localID The local ID to fetch for. * @return {object | undefined} The matching element or undefined * if none exists. */ getElementByLocalID(localID: number): BaseEntity | undefined; /** * Use the type index to get set of entities of a set of types including sub-types, acts * as a union given the input type list, with lazy iteration over the set. * * @param types The list of types to return * @return {IterableIterator} An iterable corresponding to * the lazy set of items. */ types[]>(...types: T): IterableIterator>; /** * Count entities of a set of types (including sub-types) without iterating * or materializing them — reads the type index's prefix sums, so it's cheap * enough to call up front for progress totals (see core/progress.ts). * Multi-mapped elements can be counted once per matching mapping, so treat * this as an upper bound; see MultiIndexSet.count. * * @param types The list of types to count. * @return {number} The number of matching entities. */ typeCount[]>(...types: T): number; /** * Iterate the express IDs of entities of a set of types (including sub-types) * without materializing entity descriptors or touching the source buffer — * only the type index and the express ID column are read, so this stays cheap * and safe even when the model source has been spilled to an external store. * * Multi-mapped elements (e.g. complex/multi-entity mappings) may be yielded * once per matching mapping, so callers that need distinct IDs should dedupe. * * @param types The list of types to iterate. * @return {IterableIterator} A lazy iterator of express IDs for matching entities. * @yields {number} The express ID of each matching entity. */ expressIDsOfTypes[]>(...types: T): IterableIterator; /** * Get the non empty type IDs for this. * * @return {Set} The unique set of non empty type IDs for this model. */ nonEmptyTypeIDs(): Set; /** * Get the non empty type IDs for this without including sub-types, only direct instances. * * @return {IterableIterator} The unique set of non empty type IDs for this model. */ nonEmptyTypeIDNoSubtypes(): IterableIterator; /** * Use the type index to get set of entities of a set of types not including sub-types from * the list of type ids, acts as a union given the input type list, with lazy iteration over * the set. * * @param types The type ids for the types to get. * @return {IterableIterator} An iterable corresponding to the lazy set of items. */ typeIDs(...types: EntityTypeIDs[]): IterableIterator; /** * Use the type index to get set of entities of a set of types including sub-types from the * list of type ids, acts as a union given the input type list, with lazy * iteration over the set. * * @param types The type ids for the types to get. * @return {IterableIterator} An iterable corresponding to the lazy set of items. */ typesIDSNoSubtypes(...types: EntityTypeIDs[]): IterableIterator; /** * Given a cursor, get the matching entities for it as a lazy iterable iterator. * * @param cursor The cursor to iterate over. * @param freeCursor Should the cursor be freed after * @return {IterableIterator} The iterable iterator to allow lazy * iteration over a cursor. * @yields An element per iteration matching the ids in the cursor. */ from(cursor: IIndexSetCursor, freeCursor?: boolean): IterableIterator; /** * Extract a set of elements given a local ID iterator. * * @param from An iterable of local IDs * @return {IterableIterator} The iterable iterator to allow lazy * iteration over the elements matching the local ids. * @yields An element per iteration matching the ids in from. */ extract(from: Iterable): IterableIterator; /** * Iterate over all the elements in this. * * @return {IterableIterator} The iterable iterator to allow lazy * iteration over all the elements in this. * @yields An element per iteration for all the elements in this. */ [Symbol.iterator](): IterableIterator; /** * Get the material matching a geometry node. * * Geometry must have been extracted first. * * @param node The geometry node to match a material for. * @return {CanonicalMaterial | undefined} A material, or undefined if it is not found. */ getMaterialFromGeometryNode(node: SceneNodeGeometry): CanonicalMaterial | undefined; /** * Get the mesh matching a geometry node. * * Geometry must have been extracted first. * * @param node The geometry node to match a material for. * @return {CanonicalMesh | undefined} A mesh, or undefined if it is not found. */ getMeshFromGeometryNode(node: SceneNodeGeometry): CanonicalMesh | undefined; } //# sourceMappingURL=step_model_base.d.ts.map