diff --git a/src/core/manager/EntityManager.ts b/src/core/manager/EntityManager.ts index cf8f008..79822da 100644 --- a/src/core/manager/EntityManager.ts +++ b/src/core/manager/EntityManager.ts @@ -4,6 +4,34 @@ import type BaseRenderer from '@/core/base/BaseRenderer' import { getRenderer } from './ModuleManager' import { getLineId, parseLineId } from '@/core/ModelUtils' +export class Relation { + center = new Set() + input = new Set() + output = new Set() + + add(type: LinkType, id: string) { + if (type === 'in') + return this.input.add(id) + else if (type === 'out') + return this.output.add(id) + else if (type === 'center') + return this.center.add(id) + else + throw new Error(`Unknown link type: ${type}`) + } + + delete(type: LinkType, id: string) { + if (type === 'in') + return this.input.delete(id) + else if (type === 'out') + return this.output.delete(id) + else if (type === 'center') + return this.center.delete(id) + else + throw new Error(`Unknown link type: ${type}`) + } +} + /** * 实体管理器 * 缓存所有 数据(ItemJson)和他们的关系, 以及渲染对象 THREE.Object3D @@ -112,11 +140,28 @@ export default class EntityManager { option.originEntity = _.cloneDeep(entity) - this.entities.delete(id) - this.removeRelations(id) + // 先生成线差量,再清理关系 + this.generateLineDiffsForDelete(id) + this.removeRelations(id) // 清理关系 + this.entities.delete(id) // 删除实体 + this.getDiffRenderer(entity.t).deletePoint(id, option) } + generateLineDiffsForDelete(id: string): void { + const relations = this.relationIndex.get(id) + if (!relations) return + + const removeLine = (relatedId: string, type: LinkType) => { + const lineId = getLineId(id, relatedId, type) + this.lineDiffs.delete.set(lineId, { startId: id, endId: relatedId, type }) + } + + relations.center.forEach(relatedId => removeLine(relatedId, 'center')) + relations.input.forEach(relatedId => removeLine(relatedId, 'in')) + relations.output.forEach(relatedId => removeLine(relatedId, 'out')) + } + /** * 批量更新结束, 结束后会触发视窗的渲染 * 这个方法最重要的是进行连线逻辑的处理 @@ -127,9 +172,17 @@ export default class EntityManager { */ endEntityUpdate(): void { for (const [itemTypeName, renderer] of this.diffRenderer.entries()) { + // "线"创建 for (const [lineId, lineDiffItem] of this.lineDiffs.create.entries()) { const start = this.entities.get(lineDiffItem.startId) const end = this.entities.get(lineDiffItem.endId) + + // 添加存在性检查 + if (!start || !end) { + console.warn(`无法创建线 ${lineId}, 起点或终点不存在`) + continue + } + if (start.t !== itemTypeName) { // 只通知起点对应的渲染器 continue @@ -137,9 +190,17 @@ export default class EntityManager { renderer.createLine(start, end, lineDiffItem.type) } + // "线"更新 for (const [lineId, lineDiffItem] of this.lineDiffs.update.entries()) { const start = this.entities.get(lineDiffItem.startId) const end = this.entities.get(lineDiffItem.endId) + + // 添加存在性检查 + if (!start || !end) { + console.warn(`无法更新线 ${lineId}, 起点或终点不存在`) + continue + } + if (start.t !== itemTypeName) { // 只通知起点对应的渲染器 continue @@ -147,13 +208,26 @@ export default class EntityManager { renderer.updateLine(start, end, lineDiffItem.type) } + // "线"删除 for (const [lineId, lineDiffItem] of this.lineDiffs.delete.entries()) { const start = this.entities.get(lineDiffItem.startId) const end = this.entities.get(lineDiffItem.endId) + + if (!start || !end) { + // 即使实体不存在也要处理删除 + renderer.deleteLine( + start || { id: lineDiffItem.startId, t: 'unknown' } as ItemJson, + end || { id: lineDiffItem.endId, t: 'unknown' } as ItemJson, + lineDiffItem.type) + continue + } + if (start.t !== itemTypeName) { // 只通知起点对应的渲染器 continue } + + // 使用安全删除方法, 即使实体不存在也要处理删除 renderer.deleteLine(start, end, lineDiffItem.type) } @@ -197,6 +271,11 @@ export default class EntityManager { } private updateReverseRelations(id: string, oldIds: Set, newIds: Set, relationType: LinkType) { + // 确保关系索引存在 + if (!this.relationIndex.has(id)) { + this.relationIndex.set(id, new Relation()) + } + // 移除旧关系 for (const relatedId of oldIds) { if (!newIds.has(relatedId)) { @@ -219,6 +298,9 @@ export default class EntityManager { } private calculateLineDiffs(id: string, oldIds: Set, newIds: Set, lineType: LinkType) { + // 确保关系索引存在 + if (!this.relationIndex.has(id)) return + // 删除被移除的线 for (const relatedId of oldIds) { if (!newIds.has(relatedId)) { @@ -236,6 +318,43 @@ export default class EntityManager { } } + + /** + * 删除关系关系网, 计算出差值, 可以临时放在 diffRenderer 中, 等待 commitUpdate 时统一处理 + */ + private removeRelations(id: string): void { + const relations = this.relationIndex.get(id) + if (!relations) return + + relations.center.forEach(relatedId => { + const rev = this.relationIndex.get(relatedId) + if (rev) rev.center.delete(id) + }) + + relations.input.forEach(relatedId => { + const rev = this.relationIndex.get(relatedId) + if (rev) rev.output.delete(id) + }) + + relations.output.forEach(relatedId => { + const rev = this.relationIndex.get(relatedId) + if (rev) rev.input.delete(id) + }) + + this.relationIndex.delete(id) + } + + private getDiffRenderer(type: string) { + let renderer = this.diffRenderer.get(type) + if (typeof renderer === 'undefined') { + renderer = getRenderer(type) + renderer.beginRendererUpdate(this.viewport) + this.diffRenderer.set(type, renderer) + } + return renderer + } + + /** * 重命名一个点 * 注意, 不能在更新时刻改名. 所有的关系节点都应该改名 @@ -301,46 +420,6 @@ export default class EntityManager { } } - /** - * 删除关系关系网, 计算出差值, 可以临时放在 diffRenderer 中, 等待 commitUpdate 时统一处理 - */ - private removeRelations(id: string): void { - const relations = this.relationIndex.get(id) - if (!relations) return - - const removeLine = (relatedId: string, type: LinkType) => { - const lineId = getLineId(id, relatedId, type) - this.lineDiffs.delete.set(lineId, { startId: id, endId: relatedId, type }) - } - - relations.center.forEach((relatedId) => { - this.relationIndex.get(relatedId)?.center.delete(id) - removeLine(relatedId, 'center') - }) - - relations.input.forEach((relatedId) => { - this.relationIndex.get(relatedId)?.output.delete(id) - removeLine(relatedId, 'in') - }) - - relations.output.forEach((relatedId) => { - this.relationIndex.get(relatedId)?.input.delete(id) - removeLine(relatedId, 'out') - }) - - this.relationIndex.delete(id) - } - - private getDiffRenderer(type: string) { - let renderer = this.diffRenderer.get(type) - if (typeof renderer === 'undefined') { - renderer = getRenderer(type) - renderer.beginRendererUpdate(this.viewport) - this.diffRenderer.set(type, renderer) - } - return renderer - } - deleteEntityOnly(id: string) { return this.entities.delete(id) } @@ -376,30 +455,3 @@ interface LineDiffItem { type: LinkType } -export class Relation { - center = new Set() - input = new Set() - output = new Set() - - add(type: LinkType, id: string) { - if (type === 'in') - return this.input.add(id) - else if (type === 'out') - return this.output.add(id) - else if (type === 'center') - return this.center.add(id) - else - throw new Error(`Unknown link type: ${type}`) - } - - delete(type: LinkType, id: string) { - if (type === 'in') - return this.input.delete(id) - else if (type === 'out') - return this.output.delete(id) - else if (type === 'center') - return this.center.delete(id) - else - throw new Error(`Unknown link type: ${type}`) - } -} \ No newline at end of file diff --git a/src/core/manager/StateManager.ts b/src/core/manager/StateManager.ts index a2e7193..43b3c6c 100644 --- a/src/core/manager/StateManager.ts +++ b/src/core/manager/StateManager.ts @@ -40,11 +40,7 @@ interface HistoryStep { * stateManager.redo() * * // 用例2 添加 - * stateManager.beginStateUpdate(); - * stateManager.vdata.items[3].dt.center.push('p5'); - * stateManager.vdata.items.push({ id: 'p5', t: 'measure', tf: [[-6.0, 0, 8], [0, 0, 0], [0.25, 0.1, 0.25]], dt: { center: ['p4'] } }); - * stateManager.endStateUpdate(); - * + * stateManager.beginStateUpdate();stateManager.vdata.items[3].dt.center.push('p5');stateManager.vdata.items.push({ id: 'p5', t: 'measure', tf: [[-6.0, 0, 8], [0, 0, 0], [0.25, 0.1, 0.25]], dt: { center: ['p4'] } });stateManager.endStateUpdate(); * stateManager.undo(); * stateManager.redo(); * @@ -233,11 +229,6 @@ export default class StateManager { this.entityManager.beginEntityUpdate() - // 处理删除 - for (const item of diff.removed) { - this.entityManager.deleteEntity(item.id) - } - for (const item of diff.added) { this.entityManager.createOrUpdateEntity(item) } @@ -246,6 +237,11 @@ export default class StateManager { this.entityManager.createOrUpdateEntity(after) } + // 最后处理删除 + for (const item of diff.removed) { + this.entityManager.deleteEntity(item.id) + } + this.entityManager.endEntityUpdate() }