UNPKG

@mlightcad/data-model

Version:

The data-model package provides the core classes for interacting with AutoCAD's database and entities. This package mimics AutoCAD ObjectARX's AcDb (Database) classes and implements the drawing database structure that AutoCAD developers are familiar with.

334 lines 15.7 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; import { AcDbDatabaseConverter } from '../database/AcDbDatabaseConverter'; import { AcDbBatchProcessing } from './AcDbBatchProcessing'; /** * Database regenerator. * * This class extends AcDbDatabaseConverter so that it can leverage the existing * logic to open one database such as progress notification. However, it doesn't * really do any conversion tasks and just pass one database instance and * it. */ var AcDbRegenerator = /** @class */ (function (_super) { __extends(AcDbRegenerator, _super); function AcDbRegenerator(db) { var _this = _super.call(this, {}) || this; _this._database = db; return _this; } /** * Does nothing and always passes the database instance back. * @returns The database instance associated with this generator * */ AcDbRegenerator.prototype.parse = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, { model: this._database, data: { unknownEntityCount: 0 } }]; }); }); }; /** * Does nothing and always returns one empty array. * * @returns An empty array */ AcDbRegenerator.prototype.getFonts = function () { return []; }; /** * Processes entities in batches to maintain UI responsiveness. * * This method breaks up the entity processing work into smaller chunks that are * executed asynchronously. This is often referred to as "batch processing" or * "cooperative multitasking," where the time-consuming task is broken into * smaller pieces and executed in small intervals to allow the UI to remain responsive. * * @param source - Source database * @param target - Target database * @param minimumChunkSize - Minimum number of entities to process in each chunk * @param startPercentage - Object containing the starting percentage for progress tracking * @param progress - Optional callback for progress updates */ AcDbRegenerator.prototype.processEntities = function (source, target, minimumChunkSize, startPercentage, progress) { return __awaiter(this, void 0, void 0, function () { var entities, entityCount, batchProcessor, modelSpaceBlockTableRecord; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: entities = source.tables.blockTable.modelSpace.newIterator().toArray(); entityCount = entities.length; batchProcessor = new AcDbBatchProcessing(entityCount, 100 - startPercentage.value, minimumChunkSize); // Groups entities by their `type` property and flattens the result into a single array. if (this.config.convertByEntityType) { entities = this.groupAndFlattenByType(entities); } modelSpaceBlockTableRecord = target.tables.blockTable.modelSpace; return [4 /*yield*/, batchProcessor.processChunk(function (start, end) { return __awaiter(_this, void 0, void 0, function () { var dbEntities, entityType, i, entity, percentage; return __generator(this, function (_a) { switch (_a.label) { case 0: dbEntities = []; entityType = start < end ? entities[start].type : ''; for (i = start; i < end; i++) { entity = entities[i]; if (this.config.convertByEntityType && entity.type !== entityType) { this.triggerEvents(modelSpaceBlockTableRecord, dbEntities); dbEntities = []; entityType = entity.type; } dbEntities.push(entity); } // Use batch append to improve performance this.triggerEvents(modelSpaceBlockTableRecord, dbEntities); if (!progress) return [3 /*break*/, 2]; percentage = startPercentage.value + (end / entityCount) * (100 - startPercentage.value); if (percentage > 100) percentage = 100; return [4 /*yield*/, progress(percentage, 'ENTITY', 'IN-PROGRESS')]; case 1: _a.sent(); _a.label = 2; case 2: return [2 /*return*/]; } }); }); })]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Processes blocks. */ AcDbRegenerator.prototype.processBlocks = function () { var e_1, _a; var blocks = this._database.tables.blockTable.newIterator(); try { for (var blocks_1 = __values(blocks), blocks_1_1 = blocks_1.next(); !blocks_1_1.done; blocks_1_1 = blocks_1.next()) { var block = blocks_1_1.value; var entities = block.newIterator().toArray(); this.triggerEvents(block, entities); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (blocks_1_1 && !blocks_1_1.done && (_a = blocks_1.return)) _a.call(blocks_1); } finally { if (e_1) throw e_1.error; } } }; /** * Processes header variables. */ AcDbRegenerator.prototype.processHeader = function () { // Do nothing }; /** * Processes block table records. */ AcDbRegenerator.prototype.processBlockTables = function () { // Do nothing for now. Maybe it needs to trigger some events in the future. }; /** * Processes objects defined in database. * ``` */ AcDbRegenerator.prototype.processObjects = function () { var e_2, _a, e_3, _b; var layouts = this._database.dictionaries.layouts.newIterator(); try { for (var layouts_1 = __values(layouts), layouts_1_1 = layouts_1.next(); !layouts_1_1.done; layouts_1_1 = layouts_1.next()) { var layout = layouts_1_1.value; this._database.events.dictObjetSet.dispatch({ database: this._database, object: layout, key: layout.layoutName }); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (layouts_1_1 && !layouts_1_1.done && (_a = layouts_1.return)) _a.call(layouts_1); } finally { if (e_2) throw e_2.error; } } var imageDefs = this._database.dictionaries.imageDefs.newIterator(); try { for (var imageDefs_1 = __values(imageDefs), imageDefs_1_1 = imageDefs_1.next(); !imageDefs_1_1.done; imageDefs_1_1 = imageDefs_1.next()) { var imageDef = imageDefs_1_1.value; this._database.events.dictObjetSet.dispatch({ database: this._database, object: imageDef, key: imageDef.objectId }); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (imageDefs_1_1 && !imageDefs_1_1.done && (_b = imageDefs_1.return)) _b.call(imageDefs_1); } finally { if (e_3) throw e_3.error; } } }; /** * Processes viewport table records. */ AcDbRegenerator.prototype.processViewports = function () { // Do nothing for now. Maybe it needs to trigger some events in the future. }; /** * Processes layer table records. */ AcDbRegenerator.prototype.processLayers = function () { var _this = this; var layers = this._database.tables.layerTable.newIterator().toArray(); layers.forEach(function (layer) { _this._database.events.layerAppended.dispatch({ database: _this._database, layer: layer }); }); }; /** * Processes linetype table records. */ AcDbRegenerator.prototype.processLineTypes = function () { // Do nothing for now. Maybe it needs to trigger some events in the future. }; /** * Processes text style table records. */ AcDbRegenerator.prototype.processTextStyles = function () { // Do nothing for now. Maybe it needs to trigger some events in the future. }; /** * Processes text style table records. */ AcDbRegenerator.prototype.processDimStyles = function () { // Do nothing for now. Maybe it needs to trigger some events in the future. }; /** * Groups entities by their `type` property and flattens the result into a single array. * * The order of `type` groups follows the order in which they first appear in the input array. * Items within each group preserve their original order. * * This runs in O(n) time, which is generally faster than sorting when you * don't care about alphabetical order of types. * * @param entities - The array of entities to group and flatten. * * @returns A new array of entities grouped by their `type` property. */ AcDbRegenerator.prototype.groupAndFlattenByType = function (entities) { var e_4, _a; var groups = {}; var order = []; try { for (var entities_1 = __values(entities), entities_1_1 = entities_1.next(); !entities_1_1.done; entities_1_1 = entities_1.next()) { var entity = entities_1_1.value; if (!groups[entity.type]) { groups[entity.type] = []; order.push(entity.type); } groups[entity.type].push(entity); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (entities_1_1 && !entities_1_1.done && (_a = entities_1.return)) _a.call(entities_1); } finally { if (e_4) throw e_4.error; } } return order.flatMap(function (type) { return groups[type]; }); }; AcDbRegenerator.prototype.triggerEvents = function (btr, entities) { // When creating one block, it will also go to this function. But we don't want `entityAppended` event // tiggered in this case. So check whether the block name is name of the model space. if (btr.isModelSapce || btr.isPaperSapce) { btr.database.events.entityAppended.dispatch({ database: btr.database, entity: entities }); } }; return AcDbRegenerator; }(AcDbDatabaseConverter)); export { AcDbRegenerator }; //# sourceMappingURL=AcDbRegenerator.js.map