|
|
|
@ -3,6 +3,7 @@ import type Viewport from '@/core/engine/Viewport' |
|
|
|
import type BaseRenderer from '@/core/base/BaseRenderer' |
|
|
|
import { getRenderer } from './ModuleManager' |
|
|
|
import { getLineId, parseLineId } from '@/core/ModelUtils' |
|
|
|
import { Vector2 } from 'three' |
|
|
|
|
|
|
|
/** |
|
|
|
* 实体管理器 |
|
|
|
@ -24,6 +25,9 @@ export default class EntityManager { |
|
|
|
// 所有 THREEJS "点"对象, 检索值是"点实体"的 id, 值是 THREE.Object3D 数组
|
|
|
|
private readonly objects = new Map<string, THREE.Object3D[]>() |
|
|
|
|
|
|
|
// 所有 THREEJS "可选中"对象, 检索值是"点实体"的 id, 值是 THREE.Object3D 数组
|
|
|
|
private readonly _selectableObjects: THREE.Object3D[] = [] |
|
|
|
|
|
|
|
// 所有 THREEJS "线"对象, 检索值是"线实体"的 id, 取值方式是 {type}${startId}${endId}, 值是 THREE.Object3D 数组
|
|
|
|
private readonly lines = new Map<string, THREE.Object3D[]>() |
|
|
|
|
|
|
|
@ -404,70 +408,70 @@ export default class EntityManager { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 重命名一个点 |
|
|
|
* 注意, 不能在更新时刻改名. 所有的关系节点都应该改名 |
|
|
|
*/ |
|
|
|
renamePoint(newId: string, originId: string) { |
|
|
|
if (this.isUpdating) { |
|
|
|
throw new Error('Cannot rename point during update') |
|
|
|
} |
|
|
|
const entity = this.entities.get(originId) |
|
|
|
if (!entity) { |
|
|
|
throw new Error(`Entity with id ${originId} does not exist`) |
|
|
|
} |
|
|
|
if (this.entities.has(newId)) { |
|
|
|
throw new Error(`Entity with id ${newId} already exists`) |
|
|
|
} |
|
|
|
entity.id = newId |
|
|
|
this.entities.set(newId, entity) |
|
|
|
this.entities.delete(originId) |
|
|
|
this.objects.set(newId, this.objects.get(originId) || []) |
|
|
|
this.objects.delete(originId) |
|
|
|
|
|
|
|
// 更新关系索引
|
|
|
|
const relations = this.relationIndex.get(originId) |
|
|
|
if (relations) { |
|
|
|
this.relationIndex.delete(originId) |
|
|
|
|
|
|
|
// 更新所有关系中的 id
|
|
|
|
relations.center.forEach((relatedId) => { |
|
|
|
const rev = this.relationIndex.get(relatedId) |
|
|
|
if (rev && rev.delete('center', originId)) { |
|
|
|
rev.add('center', newId) |
|
|
|
} |
|
|
|
}) |
|
|
|
relations.input.forEach((relatedId) => { |
|
|
|
const rev = this.relationIndex.get(relatedId) |
|
|
|
if (rev && rev.delete('out', originId)) { |
|
|
|
rev.add('out', newId) |
|
|
|
} |
|
|
|
}) |
|
|
|
relations.output.forEach((relatedId) => { |
|
|
|
const rev = this.relationIndex.get(relatedId) |
|
|
|
if (rev && rev.delete('in', originId)) { |
|
|
|
rev.add('in', newId) |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
this.relationIndex.set(newId, relations) |
|
|
|
} |
|
|
|
|
|
|
|
// 更新所有线段数据
|
|
|
|
for (const [lineId, lineObjects] of this.lines.entries()) { |
|
|
|
const [type, startId, endId] = parseLineId(lineId) |
|
|
|
if (startId === originId) { |
|
|
|
const newLineId = getLineId(newId, endId, type) |
|
|
|
this.lines.set(newLineId, lineObjects) |
|
|
|
this.lines.delete(lineId) |
|
|
|
|
|
|
|
} else if (endId === originId) { |
|
|
|
const newLineId = getLineId(startId, newId, type) |
|
|
|
this.lines.set(newLineId, lineObjects) |
|
|
|
this.lines.delete(lineId) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// /**
|
|
|
|
// * 重命名一个点
|
|
|
|
// * 注意, 不能在更新时刻改名. 所有的关系节点都应该改名
|
|
|
|
// */
|
|
|
|
// renamePoint(newId: string, originId: string) {
|
|
|
|
// if (this.isUpdating) {
|
|
|
|
// throw new Error('Cannot rename point during update')
|
|
|
|
// }
|
|
|
|
// const entity = this.entities.get(originId)
|
|
|
|
// if (!entity) {
|
|
|
|
// throw new Error(`Entity with id ${originId} does not exist`)
|
|
|
|
// }
|
|
|
|
// if (this.entities.has(newId)) {
|
|
|
|
// throw new Error(`Entity with id ${newId} already exists`)
|
|
|
|
// }
|
|
|
|
// entity.id = newId
|
|
|
|
// this.entities.set(newId, entity)
|
|
|
|
// this.entities.delete(originId)
|
|
|
|
// this.objects.set(newId, this.objects.get(originId) || [])
|
|
|
|
// this.objects.delete(originId)
|
|
|
|
//
|
|
|
|
// // 更新关系索引
|
|
|
|
// const relations = this.relationIndex.get(originId)
|
|
|
|
// if (relations) {
|
|
|
|
// this.relationIndex.delete(originId)
|
|
|
|
//
|
|
|
|
// // 更新所有关系中的 id
|
|
|
|
// relations.center.forEach((relatedId) => {
|
|
|
|
// const rev = this.relationIndex.get(relatedId)
|
|
|
|
// if (rev && rev.delete('center', originId)) {
|
|
|
|
// rev.add('center', newId)
|
|
|
|
// }
|
|
|
|
// })
|
|
|
|
// relations.input.forEach((relatedId) => {
|
|
|
|
// const rev = this.relationIndex.get(relatedId)
|
|
|
|
// if (rev && rev.delete('out', originId)) {
|
|
|
|
// rev.add('out', newId)
|
|
|
|
// }
|
|
|
|
// })
|
|
|
|
// relations.output.forEach((relatedId) => {
|
|
|
|
// const rev = this.relationIndex.get(relatedId)
|
|
|
|
// if (rev && rev.delete('in', originId)) {
|
|
|
|
// rev.add('in', newId)
|
|
|
|
// }
|
|
|
|
// })
|
|
|
|
//
|
|
|
|
// this.relationIndex.set(newId, relations)
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // 更新所有线段数据
|
|
|
|
// for (const [lineId, lineObjects] of this.lines.entries()) {
|
|
|
|
// const [type, startId, endId] = parseLineId(lineId)
|
|
|
|
// if (startId === originId) {
|
|
|
|
// const newLineId = getLineId(newId, endId, type)
|
|
|
|
// this.lines.set(newLineId, lineObjects)
|
|
|
|
// this.lines.delete(lineId)
|
|
|
|
//
|
|
|
|
// } else if (endId === originId) {
|
|
|
|
// const newLineId = getLineId(startId, newId, type)
|
|
|
|
// this.lines.set(newLineId, lineObjects)
|
|
|
|
// this.lines.delete(lineId)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
deleteEntityOnly(id: string) { |
|
|
|
return this.entities.delete(id) |
|
|
|
@ -478,15 +482,28 @@ export default class EntityManager { |
|
|
|
} |
|
|
|
|
|
|
|
deleteObjectsOnly(id: string) { |
|
|
|
// 删除对象时,也需要从 _selectableObjects 中移除
|
|
|
|
const rel = this.objects.get(id) |
|
|
|
if (rel) { |
|
|
|
_.remove(this._selectableObjects, obj => !rel.includes(obj)) |
|
|
|
} |
|
|
|
return this.objects.delete(id) |
|
|
|
} |
|
|
|
|
|
|
|
appendObject(id: string, points: THREE.Object3D[]) { |
|
|
|
this.objects.set(id, points) |
|
|
|
// 如果是可选中对象,添加到 _selectableObjects 中
|
|
|
|
if (points.some(obj => obj.userData.selectable !== false)) { |
|
|
|
this._selectableObjects.push(...points) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
appendLineObject(id: string, lines: THREE.Object3D[]) { |
|
|
|
this.lines.set(id, lines) |
|
|
|
// 如果是可选中对象,添加到 _selectableObjects 中
|
|
|
|
if (lines.some(obj => obj.userData.selectable !== false)) { |
|
|
|
this._selectableObjects.push(...lines) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
findLineObjectsById(lineId: string): THREE.Object3D[] { |
|
|
|
@ -494,6 +511,11 @@ export default class EntityManager { |
|
|
|
} |
|
|
|
|
|
|
|
deleteLineObjectOnly(id: string) { |
|
|
|
// 删除线对象时,也需要从 _selectableObjects 中移除
|
|
|
|
const rel = this.lines.get(id) |
|
|
|
if (rel) { |
|
|
|
_.remove(this._selectableObjects, obj => !rel.includes(obj)) |
|
|
|
} |
|
|
|
return this.lines.delete(id) |
|
|
|
} |
|
|
|
|
|
|
|
@ -507,8 +529,23 @@ export default class EntityManager { |
|
|
|
return this.entities.get(linkStartPointId) |
|
|
|
} |
|
|
|
|
|
|
|
getEntityMap() { |
|
|
|
return this.entities |
|
|
|
getObjectByCanvasMouse(event: MouseEvent): THREE.Object3D[] { |
|
|
|
const _domElement = this.viewport.renderer.domElement |
|
|
|
const rect = _domElement.getBoundingClientRect() |
|
|
|
const _pointer = new Vector2() |
|
|
|
_pointer.x = (event.clientX - rect.left) / rect.width * 2 - 1 |
|
|
|
_pointer.y = -(event.clientY - rect.top) / rect.height * 2 + 1 |
|
|
|
this.viewport.raycaster.setFromCamera(_pointer, this.viewport.camera) |
|
|
|
const _intersections = this.viewport.raycaster.intersectObjects(this._selectableObjects, true) |
|
|
|
|
|
|
|
if (!_intersections || _intersections.length === 0) { |
|
|
|
return [] |
|
|
|
} |
|
|
|
// 根据距离排序射线命中的对象集
|
|
|
|
return _.map( |
|
|
|
_intersections.sort((a, b) => a.distance - b.distance), |
|
|
|
r => r.object |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|