Browse Source

属性编辑器. destory 统一命名为 dispose

master
修宁 7 months ago
parent
commit
6e5b91e429
  1. 2
      src/core/base/BaseInteraction.ts
  2. 12
      src/core/base/BaseRenderer.ts
  3. 7
      src/core/base/IMeta.ts
  4. 24
      src/core/controls/EsDragControls.ts
  5. 2
      src/core/controls/IControls.ts
  6. 2
      src/core/controls/MouseMoveInspect.ts
  7. 18
      src/core/controls/SelectInspect.ts
  8. 2
      src/core/engine/SceneHelp.ts
  9. 42
      src/core/engine/Viewport.ts
  10. 118
      src/core/manager/EntityManager.ts
  11. 6
      src/core/manager/InteractionManager.ts
  12. 15
      src/core/manager/StateManager.ts
  13. 4
      src/editor/Model2DEditor.vue
  14. 6
      src/editor/propEditors/IMetaProp.ts
  15. 3
      src/editor/widgets/property/PropertyView.vue
  16. 32
      src/modules/measure/MeasureMeta.ts
  17. 12
      src/modules/measure/MeasureRenderer.ts
  18. 2
      src/runtime/EventBus.ts

2
src/core/base/BaseInteraction.ts

@ -98,8 +98,6 @@ export default abstract class BaseInteraction {
}
// 提交状态管理器
console.log('drag from ', [this.dragItem.tf[0][0], this.dragItem.tf[0][2]], 'to', [CurrentMouseInfo.x, CurrentMouseInfo.z])
const stateManager = this.viewport.stateManager
stateManager.beginStateUpdate({ createFromInteraction: true })
this.dragItem.tf[0][0] = CurrentMouseInfo.x

12
src/core/base/BaseRenderer.ts

@ -229,6 +229,7 @@ export default abstract class BaseRenderer {
*/
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
const lineId = getLineId(start.id, end.id, type)
console.log('updateline ', lineId)
const lines = this.tempViewport.entityManager.findLineObjectsById(lineId)
_.forEach(lines, (line: THREE.Object3D) => {
@ -251,15 +252,20 @@ export default abstract class BaseRenderer {
* @param option
*/
deleteLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
const id = getLineId(start.id, end.id, type)
const lines = this.tempViewport.entityManager.findLineObjectsById(id)
const lineId = getLineId(start.id, end.id, type)
console.log('deleteline ', lineId)
const lines = this.tempViewport.entityManager.findLineObjectsById(lineId)
if (lines) {
this.removeFromScene(...lines)
}
this.tempViewport.entityManager.deleteLineObjectOnly(id)
this.tempViewport.entityManager.deleteLineObjectOnly(lineId)
this.afterDeleteLine(start, end, type, option, lines)
}
dispose() {
// 清理资源
this.isUpdating = false
}
}

7
src/core/base/IMeta.ts

@ -35,11 +35,7 @@ export const BASIC_META_OF_LINE2: ItemTypeMeta = []
/**
* , category, tabName, MetaItem
*/
export interface IMeta {
[key: string]: {
[tabName: string]: MetaItem[]
}
}
export type IMeta = MetaItem[]
/**
* PropertyPanelConfig interface
@ -50,6 +46,7 @@ export interface MetaItem {
editor: string;
label?: string;
readonly?: boolean;
category?: string;
[key: string]: any;
}

24
src/core/controls/EsDragControls.ts

@ -5,7 +5,7 @@ import { getItemTypeByName } from '@/model/itemType/ItemTypeDefine'
import type { ItemTypeDefineOption } from '@/model/itemType/ItemTypeDefine'
import { markRaw } from 'vue'
import EventBus from '@/runtime/EventBus'
import { getInteraction } from '@/core/manager/ModuleManager.ts'
import { getInteraction, getMeta } from '@/core/manager/ModuleManager.ts'
import type BaseInteraction from '@/core/base/BaseInteraction.ts'
// dragControls 绑定函数
@ -114,10 +114,6 @@ export default class EsDragControls {
// 拖拽中
drag(e) {
this.currentInteraction?.dragPointMove(this.viewport, e)
EventBus.dispatch('objectChanged', {
viewport: this,
object: e.object
})
}
// 拖拽结束
@ -131,14 +127,26 @@ export default class EsDragControls {
if (e.object.userData.onClick) {
e.object.userData.onClick(e)
}
if (e.object.userData.selectable) {
if (e.object.userData?.entityId) {
const entityId = e.object.userData.entityId
const item = this.viewport.entityManager.findItemById(entityId)
const itemTypeName = e.object.userData.t
if (item.dt.protected !== true) {
this.viewport.state.selectedObject = markRaw(e.object)
EventBus.dispatch('objectChanged', {
this.viewport.state.selectedItem = markRaw(item)
this.viewport.state.selectedEntityId = entityId
this.viewport.state.selectedObjectMeta = getMeta(itemTypeName)
EventBus.dispatch('selectedObjectChanged', {
viewport: this,
object: e.object
selectedObject: this.viewport.state.selectedObject,
selectedItem: this.viewport.state.selectedItem,
selectedEntityId: this.viewport.state.selectedEntityId,
selectedObjectMeta: this.viewport.state.selectedObjectMeta
})
}
}
}
const ret = this.currentInteraction?.dragPointComplete(this.viewport, e)
if (!ret) return

2
src/core/controls/IControls.ts

@ -1,7 +1,7 @@
export default interface IControls {
init(viewport: any): void
destory(): void
dispose(): void
animate?: () => void;
}

2
src/core/controls/MouseMoveInspect.ts

@ -26,7 +26,7 @@ export default class MouseMoveInspect implements IControls {
this.canvas.addEventListener('mouseleave', lvFn)
}
destory() {
dispose() {
this.canvas.removeEventListener('pointermove', pmFn)
pmFn = undefined
this.canvas.removeEventListener('pointerout', otFn)

18
src/core/controls/SelectInspect.ts

@ -63,8 +63,7 @@ export default class SelectInspect implements IControls {
puFn = this.onMouseUp.bind(this)
this.canvas.addEventListener('pointerup', puFn)
this.viewport.watchList.push(watch(() => this.viewport.state.selectedObject, this.updateSelectionBox.bind(this)))
EventBus.on('objectChanged', (data) => {
EventBus.on('selectedObjectChanged', (data) => {
this.updateSelectionBox(this.viewport.state.selectedObject)
})
}
@ -74,13 +73,6 @@ export default class SelectInspect implements IControls {
*/
updateSelectionBox(selectedObject: THREE.Object3D) {
this.disposeSelectionBox()
this.viewport.state.selectedObjectMeta = null // 清除之前的元数据
if (selectedObject?.userData?.type) {
const type = selectedObject.userData.type
const itemTypeDefine = getItemTypeByName(type)
if (itemTypeDefine) {
this.viewport.state.selectedObjectMeta = itemTypeDefine.getMeta(selectedObject)
const expandAmount = 0.2 // 扩展包围盒的大小
// 避免某些蒙皮网格的帧延迟效应(e.g. Michelle.glb)
@ -110,14 +102,12 @@ export default class SelectInspect implements IControls {
selectionBox.name = 'selectionBox'
this.selectionBox = selectionBox
this.viewport.scene.add(selectionBox)
console.log('selectedItem', this.viewport.state.selectedItem)
this.viewport.scene.add(selectionBox)
}
}
}
destory() {
dispose() {
this.canvas.removeEventListener('pointerdown', pdFn)
pdFn = undefined
this.canvas.removeEventListener('pointermove', pmFn)

2
src/core/engine/SceneHelp.ts

@ -95,7 +95,7 @@ export default class SceneHelp {
/**
* , WebGL
*/
destory() {
dispose() {
// 移除旧模型
if (!this.scene) {
return

42
src/core/engine/Viewport.ts

@ -4,7 +4,7 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import Stats from 'three/examples/jsm/libs/stats.module'
import type WorldModel from '../manager/WorldModel'
import $ from 'jquery'
import { reactive, toRaw, watch } from 'vue'
import { markRaw, reactive, toRaw, watch } from 'vue'
import type IControls from '../controls/IControls'
import { CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer'
import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
@ -20,6 +20,7 @@ import InteractionManager from '@/core/manager/InteractionManager'
import { calcPositionUseSnap } from '@/core/ModelUtils'
import StateManager from '@/core/manager/StateManager.ts'
import EventBus from '@/runtime/EventBus.ts'
import type { IMeta } from '@/core/base/IMeta.ts'
/**
*
@ -376,7 +377,7 @@ export default class Viewport {
this.gridHelper.visible = opacity > 0
}
destroy() {
dispose() {
this.state.isReady = false
if (this.animationFrameId !== null) {
@ -395,8 +396,8 @@ export default class Viewport {
if (this.tools) {
for (const tool of this.tools) {
if (tool.destory) {
tool.destory()
if (tool.dispose) {
tool.dispose()
}
}
this.tools = []
@ -418,6 +419,31 @@ export default class Viewport {
console.log('WebGL disposed, memory:', this.renderer.info.memory)
this.renderer.domElement = null
}
if (this.controls) {
this.controls.dispose()
this.controls = null
}
if (this.dragControl) {
this.dragControl.dispose()
this.dragControl = null
}
if (this.interactionManager) {
this.interactionManager.dispose()
this.interactionManager = null
}
if (this.stateManager) {
this.stateManager.dispose()
this.stateManager = null
}
if (this.entityManager) {
this.entityManager.dispose()
this.entityManager = null
}
}
getIntersects(point: THREE.Vector2) {
@ -461,12 +487,16 @@ export interface ViewportState {
/**
*
*/
selectedObject: THREE.Object3D | null
selectedObject: THREE.Object3D | undefined
selectedItem: ItemJson | undefined
selectedEntityId: string | undefined
/**
*
*/
selectedObjectMeta: ItemTypeMeta | null
selectedObjectMeta: IMeta | undefined
/**
*

118
src/core/manager/EntityManager.ts

@ -4,36 +4,6 @@ import type BaseRenderer from '@/core/base/BaseRenderer'
import { getRenderer } from './ModuleManager'
import { getLineId, parseLineId } from '@/core/ModelUtils'
/**
*
*/
export class Relation {
center = new Set<string>()
input = new Set<string>()
output = new Set<string>()
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}`)
}
}
/**
*
@ -66,10 +36,37 @@ export default class EntityManager {
update: new Map<string, LineDiffItem>(),
delete: new Map<string, LineDiffItem>()
}
// 记录所有发生过变化的实体, 用于在 endEntityUpdate 时进行写回给 StateManager
private readonly writeBackEntities = new Set<string>()
isUpdating = false
getAllEntities(): Map<string, ItemJson> {
return this.entities
dispose() {
// 清理所有差量渲染器
for (const renderer of this.diffRenderer.values()) {
renderer.dispose()
}
this.diffRenderer.clear()
// 清理所有实体和关系索引
this.entities.clear()
this.relationIndex.clear()
this.objects.clear()
this.lines.clear()
this.writeBackEntities.clear()
}
/**
*
*/
cloneWriteBackEntities(): Map<string, ItemJson> {
const entities = new Map<string, ItemJson>()
for (const id of this.writeBackEntities) {
const entity = this.entities.get(id)
if (!entity) continue
entities.set(id, _.cloneDeep(entity))
}
console.log('需要回写', entities.size, '行数据')
return entities
}
init(viewport: Viewport) {
@ -82,6 +79,7 @@ export default class EntityManager {
beginEntityUpdate(): void {
this.isUpdating = true
this.viewport.beginViewUpdate()
this.writeBackEntities.clear()
this.diffRenderer.clear()
this.lineDiffs.create.clear()
this.lineDiffs.update.clear()
@ -96,25 +94,26 @@ export default class EntityManager {
throw new Error('Entity must have an id')
}
const entity = _.cloneDeep(entityRaw) as ItemJson
const originEntity = this.entities.get(entity.id)
// 找到这个数据的渲染器
const renderer = this.getDiffRenderer(entity.t)
const originEntity = this.entities.get(entity.id)
// 先判断坐标是否变化
const coordinateChanged = originEntity?.tf && entity?.tf && !_.isEqual(originEntity.tf[0], entity.tf[0])
this.entities.set(entity.id, entity)
// 更新关系网
this.updateRelations(entity, originEntity)
// 判断坐标是否变化
if (originEntity?.tf && entity?.tf && !_.isEqual(originEntity.tf[0], entity.tf[0])) {
if (coordinateChanged) {
this.writeBackEntities.add(entity.id)
// 点的坐标发生变化, 要通知所有关联线更新
const relations = this.relationIndex.get(entity.id)
if (!relations) return
const relation = this.relationIndex.get(entity.id)
if (relation) {
for (const type of (['center', 'in', 'out'] as LinkType[])) {
const relatedIds = relations[type]
const relatedIds = relation[type]
if (!relatedIds) continue
for (const relatedId of relatedIds) {
@ -128,6 +127,7 @@ export default class EntityManager {
}
}
}
}
if (typeof originEntity === 'undefined') {
renderer.createPoint(entity, option as RendererCudOption)
@ -146,6 +146,7 @@ export default class EntityManager {
if (!entity) return
option.originEntity = _.cloneDeep(entity)
this.writeBackEntities.add(entity.id)
// 先生成线差量,再清理关系
this.generateLineDiffsForDelete(id)
@ -210,6 +211,7 @@ export default class EntityManager {
if (start.t !== itemTypeName) {
// 只通知起点对应的渲染器
console.error(`Line ${lineId} start point type mismatch: expected ${itemTypeName}, got ${start.t}`)
continue
}
renderer.updateLine(start, end, lineDiffItem.type)
@ -312,6 +314,7 @@ export default class EntityManager {
if (!newIds.has(relatedId)) {
const rev = this.relationIndex.get(relatedId)
rev.delete(relationType, id)
this.writeBackEntities.add(id)
}
}
@ -324,6 +327,7 @@ export default class EntityManager {
this.relationIndex.set(relatedId, rev)
}
rev.add(relationType, id)
this.writeBackEntities.add(id)
}
}
}
@ -360,16 +364,19 @@ export default class EntityManager {
relations.center.forEach(relatedId => {
const rev = this.relationIndex.get(relatedId)
if (rev) rev.center.delete(id)
this.writeBackEntities.add(relatedId)
})
relations.input.forEach(relatedId => {
const rev = this.relationIndex.get(relatedId)
if (rev) rev.output.delete(id)
this.writeBackEntities.add(relatedId)
})
relations.output.forEach(relatedId => {
const rev = this.relationIndex.get(relatedId)
if (rev) rev.input.delete(id)
this.writeBackEntities.add(relatedId)
})
this.relationIndex.delete(id)
@ -496,3 +503,34 @@ interface LineDiffItem {
type: LinkType
}
/**
*
*/
export class Relation {
center = new Set<string>()
input = new Set<string>()
output = new Set<string>()
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}`)
}
}

6
src/core/manager/InteractionManager.ts

@ -54,7 +54,7 @@ export default class InteractionManager implements IControls {
this.viewport.state.cursorMode = 'normal'
this.viewport.dragControl.dragControls.enabled = true
debugger
this.viewport.viewerDom.style.cursor = ''
system.msg('退出新建模式')
}
@ -92,7 +92,7 @@ export default class InteractionManager implements IControls {
// 初始化交互
this.currentTool = interaction
this.viewport.dragControl.dragControls.enabled = false
debugger
this.currentTool.start(this.viewport, { startPoint: this.toolStartObject })
// 更新 UI 状态
@ -101,7 +101,7 @@ export default class InteractionManager implements IControls {
system.msg(`enter [${mode}] interaction`)
}
destory(): void {
dispose(): void {
this.exitInteraction()
}
}

15
src/core/manager/StateManager.ts

@ -262,9 +262,14 @@ export default class StateManager {
this.entityManager.endEntityUpdate()
// 从实体管理器中获取最新数据
const updatedItems = this.entityManager.getAllEntities()
this.vdata.items = Array.from(updatedItems.values())
// 获取被改过的数据, 覆盖之前的数据
const writeBackMap = this.entityManager.cloneWriteBackEntities()
for (let i = 0; i < this.vdata.items.length; i++) {
const item = this.vdata.items[i]
if (writeBackMap.has(item.id)) {
this.vdata.items[i] = writeBackMap.get(item.id)
}
}
}
/**
@ -351,7 +356,7 @@ export default class StateManager {
}
await this.saveToLocalstore()
}, 5000)
}, 2500)
}
/**
@ -494,7 +499,7 @@ export default class StateManager {
/**
*
*/
destroy() {
dispose() {
// 清理引用
delete this.vdata
delete this.historySteps

4
src/editor/Model2DEditor.vue

@ -110,12 +110,12 @@ export default defineComponent({
},
destroyScene() {
if (this.viewport) {
this.viewport.destroy()
this.viewport.dispose()
this.viewport = null
delete window['viewport']
}
if (this.scene) {
this.scene.destory()
this.scene.dispose()
this.scene = null
delete window['scene']
}

6
src/editor/propEditors/IMetaProp.ts

@ -1,16 +1,16 @@
import * as THREE from 'three'
import { type ItemTypeMetaItem } from '@/model/itemType/ItemTypeDefine'
import { defineComponent, type PropType } from 'vue'
import type Viewport from '@/core/engine/Viewport'
import EventBus from '@/runtime/EventBus'
import type { MetaItem } from '@/core/base/IMeta.ts'
export default defineComponent({
props: {
prop: Object as PropType<ItemTypeMetaItem>,
prop: Object as PropType<MetaItem>,
viewport: Object as PropType<Viewport>
},
mounted() {
EventBus.on('objectChanged', (data) => {
EventBus.on('selectedObjectChanged', (data) => {
//@ts-ignore
if (typeof this.refreshValue === 'function') {
//@ts-ignore

3
src/editor/widgets/property/PropertyView.vue

@ -19,7 +19,7 @@
<TextInput v-else-if="itemMeta.editor === 'TextInput'"
:prop="itemMeta" :viewport="viewport" />
<Transform v-else-if="itemMeta.editor === 'Transform'"
<Transform v-else-if="itemMeta.editor === 'TransformEditor'"
:prop="itemMeta" :viewport="viewport" />
<SwitchItem v-else-if="itemMeta.editor === 'Switch'"
@ -38,7 +38,6 @@
未知编辑器: {{ itemMeta.editor }}
</template>
</template>
</el-form>
</div>

32
src/modules/measure/MeasureMeta.ts

@ -1,23 +1,15 @@
import type { IMeta } from '@/core/base/IMeta.ts'
const MeasureMeta: IMeta = {
// "点"属性面板
point: {
// 基础面板
basic: [
{ field: 'uuid', editor: 'UUID', label: 'uuid', readonly: true },
{ field: 'name', editor: 'TextInput', label: '名称' },
{ field: 'dt.label', editor: 'TextInput', label: '标签' },
{ editor: 'TransformEditor' },
{ field: 'dt.color', editor: 'Color', label: '颜色' },
{ editor: '-' },
{ field: 'tf', editor: 'InOutCenterEditor' },
{ field: 'dt.selectable', editor: 'Switch', label: '可选中' },
{ field: 'dt.protected', editor: 'Switch', label: '受保护' },
{ field: 'visible', editor: 'Switch', label: '可见' }
]
},
// "线"属性面板
line: {}
}
const MeasureMeta: IMeta = [
{ field: 'uuid', editor: 'UUID', label: 'uuid', readonly: true, category: 'basic' },
{ field: 'name', editor: 'TextInput', label: '名称', category: 'basic' },
{ field: 'dt.label', editor: 'TextInput', label: '标签', category: 'basic' },
{ editor: 'TransformEditor', category: 'basic' },
{ field: 'dt.color', editor: 'Color', label: '颜色', category: 'basic' },
{ editor: '-', category: 'basic' },
{ field: 'tf', editor: 'InOutCenterEditor', category: 'basic' },
{ field: 'dt.selectable', editor: 'Switch', label: '可选中', category: 'basic' },
{ field: 'dt.protected', editor: 'Switch', label: '受保护', category: 'basic' },
{ field: 'visible', editor: 'Switch', label: '可见', category: 'basic' }
]
export default MeasureMeta

12
src/modules/measure/MeasureRenderer.ts

@ -171,4 +171,16 @@ export default class MeasureRenderer extends BaseRenderer {
getDefaultRotation(): THREE.Vector3 {
return this.defaultRotation
}
dispose() {
super.dispose()
if (this.group && this.group.parent) {
this.group.parent.remove(this.group)
}
this.group = undefined
this.pointMaterial.dispose()
this.lineMaterial.dispose()
}
}

2
src/runtime/EventBus.ts

@ -2,7 +2,7 @@ import mitt from 'mitt'
const instance = mitt()
export type DispatchNames = 'objectChanged' | 'catalogChanged' | 'dataLoadComplete'
export type DispatchNames = 'selectedObjectChanged' | 'catalogChanged' | 'dataLoadComplete'
export default {
dispatch(name: DispatchNames, data?: any) {

Loading…
Cancel
Save