diff --git a/src/core/Constract.ts b/src/core/Constract.ts index 7c499f1..a0cc2b7 100644 --- a/src/core/Constract.ts +++ b/src/core/Constract.ts @@ -32,5 +32,8 @@ const Constract = Object.freeze({ HEIGHT_WAY: 0.01, HEIGHT_WAY_LABEL: 0.03, HEIGHT_WAY_LINE: 0.02, + + // 鼠标点击延迟 + MOUSE_CLICK_DELAY: 200 }) export default Constract diff --git a/src/core/ModelUtils.ts b/src/core/ModelUtils.ts index d3e3538..64d8e8a 100644 --- a/src/core/ModelUtils.ts +++ b/src/core/ModelUtils.ts @@ -3,7 +3,7 @@ import type Viewport from '@/core/engine/Viewport' import { Vector2 } from 'three/src/math/Vector2' import EventBus from '@/runtime/EventBus.ts' import Decimal from 'decimal.js' -import type { Object3DLike } from '@/types/ModelTypes.ts' +import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' import axios from 'axios' import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader' import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader' @@ -127,12 +127,9 @@ export function setUserDataForItem(item: ItemJson, object: Object3DLike) { } } -export function setUserDataForLine(start: ItemJson, end: ItemJson, type: LinkType, object: Object3DLike) { +export function setUserDataForLine(start: ItemJson, end: ItemJson, type: LinkType, object: LineLike) { const id = getLineId(start.id, end.id, type) - if (!object.name) { - object.name = id - } object.userData = { ...object.userData, createType: 'line', @@ -248,7 +245,7 @@ export function getClosestObject(viewport: Viewport, object: THREE.Object3D, ins if (object.userData && object.userData.t && object.userData.entityId) { // 找到第一个有效的业务 Object3D if (object instanceof THREE.InstancedMesh && instanceId >= 0) { - const manager = viewport.pointManagerMap.get(object.userData.t) + const manager = viewport.meshManager.get(object.userData.t) if (manager) { return manager.findByMeshInstanceId(object.userData.blockIndex, instanceId) } diff --git a/src/core/base/BaseRenderer.ts b/src/core/base/BaseRenderer.ts index 4d2516d..a7fd6ce 100644 --- a/src/core/base/BaseRenderer.ts +++ b/src/core/base/BaseRenderer.ts @@ -2,11 +2,10 @@ import type Viewport from '@/core/engine/Viewport' import * as THREE from 'three' import { getLineId, getMatrixFromTf, setUserDataForItem, setUserDataForLine } from '@/core/ModelUtils.ts' import { Line2 } from 'three/examples/jsm/lines/Line2' -import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts' -import Constract from '@/core/Constract.ts' -import LineSegmentManager, { LineManageWrap } from '@/core/manager/LineSegmentManager.ts' -import type { Object3DLike } from '@/types/ModelTypes.ts' -import { InstanceMeshWrap } from '@/core/manager/InstanceMeshManager.ts' +import { PointManageWrap } from '@/core/manager/InstancePointManager.ts' +import { LineWrap } from '@/core/manager/LineSegmentManager.ts' +import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' +import { MeshWrap } from '@/core/manager/InstanceMeshManager.ts' /** * 基本渲染器基类 @@ -59,7 +58,7 @@ export default abstract class BaseRenderer { /** * 创建测量线 */ - createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): Object3DLike { + createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): LineLike { throw new Error('createLineBasic method must be implemented in derived class.') } @@ -72,7 +71,7 @@ export default abstract class BaseRenderer { /** * 创建或更新线之后的回调 */ - afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: Object3DLike) { + afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: LineLike) { } /** @@ -98,7 +97,7 @@ export default abstract class BaseRenderer { this.tempViewport.scene.add(...objects) // const dragObjects = objects.filter(obj => !!obj.userData.draggable) - //this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') + //this.tempViewport.dragManager.setDragObjects(dragObjects, 'push') } removeFromScene(...objects: THREE.Object3D[]) { @@ -107,7 +106,7 @@ export default abstract class BaseRenderer { return } this.tempViewport.scene.remove(...objects) - //this.tempViewport.dragControl.setDragObjects(objects, 'remove') + //this.tempViewport.dragManager.setDragObjects(objects, 'remove') } createPointForEntity(item: ItemJson, option?: RendererCudOption): Object3DLike { @@ -156,17 +155,12 @@ export default abstract class BaseRenderer { if (object instanceof THREE.Object3D) { this.removeFromScene(object) - } else if (object instanceof PointManageWrap) { - // 如果是 PointManageWrap, 则需要调用管理器的删除方法 - object.manager.deletePoint(id) - - } else if (object instanceof InstanceMeshWrap) { + } else if (object instanceof MeshWrap) { // 如果是 PointManageWrap, 则需要调用管理器的删除方法 object.manager.delete(id) - } else if (object instanceof LineManageWrap) { - // 如果是 PointManageWrap, 则需要调用管理器的删除方法 - object.manager.deleteLine(id) + } else { + throw new Error('unkown Point type', object) } this.tempViewport.entityManager.deleteEntityOnly(id) @@ -240,8 +234,6 @@ export default abstract class BaseRenderer { if (line instanceof THREE.Object3D) { this.appendToScene(line) - } else if (line instanceof PointManageWrap) { - line.manager.syncMeshObject3D(line) } this.afterCreateOrUpdateLine(start, end, type, option, line) @@ -274,7 +266,7 @@ export default abstract class BaseRenderer { const geom = line.geometry geom.setFromPoints([startPoint.position, endPoint.position]) - } else if (line instanceof LineManageWrap) { + } else if (line instanceof LineWrap) { line.manager.updateLine(lineId, startPoint.position, endPoint.position, line.color) } } diff --git a/src/core/engine/SceneHelp.ts b/src/core/engine/SceneHelp.ts index 99ce47c..07738c0 100644 --- a/src/core/engine/SceneHelp.ts +++ b/src/core/engine/SceneHelp.ts @@ -4,8 +4,7 @@ import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial' import { Line2 } from 'three/examples/jsm/lines/Line2' import type { Object3DLike } from '@/types/ModelTypes.ts' -import { LineManageWrap } from '@/core/manager/LineSegmentManager.ts' -import { PointManageWrap } from '@/core/manager/InstancePointManager.ts' +import { LineWrap } from '@/core/manager/LineSegmentManager.ts' /** * 场景帮助类 @@ -86,6 +85,7 @@ export default class SceneHelp { // // const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1) // this.scene.add(hemisphereLight) + window['scene'] = this.scene } // /** @@ -114,9 +114,6 @@ export default class SceneHelp { if (obj instanceof THREE.Object3D) { this.scene.add(obj) - } else if (obj instanceof LineManageWrap) { - // 默认会合并到 LineSegmentManager 中 - } } } @@ -163,7 +160,8 @@ export default class SceneHelp { // 清空场景 this.scene.children = [] - this.scene = null + // this.scene = null + delete window['scene'] } } diff --git a/src/core/engine/Viewport.ts b/src/core/engine/Viewport.ts index e523ebe..7c5f448 100644 --- a/src/core/engine/Viewport.ts +++ b/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 { markRaw, reactive, toRaw, watch } from 'vue' +import { markRaw, reactive, watch } from 'vue' import { CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer' import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer' @@ -15,12 +15,10 @@ import EntityManager from '../manager/EntityManager' 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 Constract from '@/core/Constract.ts' import DragManager from '@/core/manager/DragManager.ts' import type { PropertySetter } from '@/core/base/PropertyTypes.ts' import LabelManager from '@/core/manager/LabelManager.ts' -import type InstancePointManager from '@/core/manager/InstancePointManager.ts' import type LineSegmentManager from '@/core/manager/LineSegmentManager.ts' import type { Object3DLike } from '@/types/ModelTypes.ts' import type InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' @@ -62,9 +60,6 @@ export default class Viewport { markRaw(this.interactionManager) ] - // 点实例管理器 moduleName -> InstancePointManager - pointManagerMap: Map = new Map() - // 对象实例管理器 moduleName -> InstanceMeshManager meshManager: Map = new Map() @@ -106,13 +101,14 @@ export default class Viewport { } }) - constructor(sceneHelp: SceneHelp, viewerDom: HTMLElement) { + constructor(sceneHelp: SceneHelp, viewerDom: HTMLElement, stateManager) { this.scene = sceneHelp this.viewerDom = viewerDom + this.stateManager = stateManager } /** - * 获取或创建点管理器 + * 获取或创建形状管理器 * @param typeName 点类型名称 * @param createFn 创建点管理器的函数 */ @@ -128,22 +124,6 @@ export default class Viewport { } /** - * 获取或创建点管理器 - * @param typeName 点类型名称 - * @param createFn 创建点管理器的函数 - */ - getOrCreatePointManager(typeName: string, createFn: () => InstancePointManager): InstancePointManager { - let pointManager = this.pointManagerMap.get(typeName) - if (!pointManager) { - pointManager = createFn() - if (pointManager) { - this.pointManagerMap.set(typeName, pointManager) - } - } - return pointManager - } - - /** * 获取或创建线段管理器 * @param typeName 线段类型名称 * @param createFn 创建线段管理器的函数 @@ -166,8 +146,8 @@ export default class Viewport { console.log('viewport on catelogCode: ' + this.scene.catalogCode) const viewerDom = this.viewerDom - // 管理器 - this.stateManager = new StateManager(option.stateManagerId, this) + // 状态管理器初始化 + this.stateManager.init(this) // 渲染器 const renderer = new THREE.WebGLRenderer({ @@ -264,27 +244,13 @@ export default class Viewport { this.animate() - try { - if (worldModel.state.isDraft) { - await this.stateManager.loadFromLocalstore() - EventBus.dispatch('dataLoadComplete', {}) - - } else { - // 不是从草稿读的数据, 就找服务器捞数据 - const vdata = await this.worldModel.getCatalogData(this.scene.catalogCode) - if (!vdata) { - return - } - if (!vdata.catalog) { - vdata.catalog = toRaw(this.worldModel.state.catalog) - } - await this.stateManager.load(vdata) - EventBus.dispatch('dataLoadComplete', {}) - } - - } finally { - this.state.isReady = true - } + window['viewport'] = this + window['stateManager'] = this.stateManager + window['entityManager'] = this.entityManager + window['renderer'] = this.renderer + window['camera'] = this.camera + window['renderer'] = this.renderer + window['controls'] = this.controls } /** @@ -294,6 +260,10 @@ export default class Viewport { if (this.camera) { this.scene.remove(this.camera) } + if (this.controls) { + this.controls.dispose() + this.controls = null + } // ============================ 创建透视相机 const viewerDom = this.viewerDom @@ -323,6 +293,9 @@ export default class Viewport { // this.renderer.render(this.scene, this.camera); // }); this.controls = controls + + window['camera'] = this.camera + window['controls'] = this.controls } /** @@ -332,6 +305,10 @@ export default class Viewport { if (this.camera) { this.scene.remove(this.camera) } + if (this.controls) { + this.controls.dispose() + this.controls = null + } // ============================ 创建正交相机 const viewerDom = this.viewerDom @@ -370,6 +347,9 @@ export default class Viewport { cameraNew.updateProjectionMatrix() + window['camera'] = this.camera + window['controls'] = this.controls + this.syncCameraState() } @@ -527,13 +507,18 @@ export default class Viewport { dispose() { this.state.isReady = false - if (this.pointManagerMap.size > 0) { - this.pointManagerMap.forEach((manager) => { + if (this.animationFrameId !== null) { + cancelAnimationFrame(this.animationFrameId) + this.animationFrameId = null + } + + if (this.meshManager.size > 0) { + this.meshManager.forEach((manager) => { if (manager.dispose) { manager.dispose() } }) - this.pointManagerMap.clear() + this.meshManager.clear() } if (this.lineSegmentManagerMap.size > 0) { this.lineSegmentManagerMap.forEach((manager) => { @@ -553,11 +538,6 @@ export default class Viewport { this.tools = [] } - if (this.animationFrameId !== null) { - cancelAnimationFrame(this.animationFrameId) - this.animationFrameId = null - } - if (this.watchList) { _.forEach(this.watchList, (unWatchFn => { if (typeof unWatchFn === 'function') { @@ -594,6 +574,14 @@ export default class Viewport { this.controls.dispose() this.controls = null } + + delete window['viewport'] + delete window['stateManager'] + delete window['entityManager'] + delete window['renderer'] + delete window['camera'] + delete window['renderer'] + delete window['controls'] } getIntersects(point: THREE.Vector2) { diff --git a/src/core/manager/DragManager.ts b/src/core/manager/DragManager.ts index 6c6a770..b733209 100644 --- a/src/core/manager/DragManager.ts +++ b/src/core/manager/DragManager.ts @@ -1,10 +1,9 @@ import * as THREE from 'three' import type Viewport from '@/core/engine/Viewport.ts' import { getClosestObject } from '@/core/ModelUtils.ts' -import EventBus from '@/runtime/EventBus.ts' import type { Object3DLike } from '@/types/ModelTypes.ts' -import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts' -import { LineManageWrap } from '@/core/manager/LineSegmentManager.ts' +import { PointManageWrap } from '@/core/manager/InstancePointManager.ts' +import Constract from '@/core/Constract.ts' /** * ThreeJS 拖拽管理器(仅限 X/Z 平面) @@ -64,6 +63,7 @@ export default class DragControl { */ private onPointerDown = (event: PointerEvent): void => { if (!this.enabled) return + if (event.button !== 0) return const mouse = this.getMousePosition(event.clientX, event.clientY) const intersected = this.getIntersectedDraggableObject(mouse) @@ -91,7 +91,7 @@ export default class DragControl { } }, 100) // 每100毫秒检查一次状态, 鼠标移出要主动清理 - }, 100) // 0.1秒延迟抓取 + }, Constract.MOUSE_CLICK_DELAY) // 0.1秒延迟抓取 } @@ -112,7 +112,7 @@ export default class DragControl { const intersected = this.getIntersectedDraggableObject(mouse) // ===================================== // const ids = this.viewport.itemFindManager.getItemsByPosition(CurrentMouseInfo.x, CurrentMouseInfo.z) - this.domElement.style.cursor = intersected ? 'grab' : 'auto' + this.domElement.style.cursor = intersected ? 'pointer' : 'auto' } } @@ -120,6 +120,7 @@ export default class DragControl { * pointerup 事件处理 */ private onPointerUp = (event: PointerEvent): void => { + if (event.button !== 0) return if (this.isDragging) { const startPos = this.dragStartMouse.clone() const targetPos = new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z) diff --git a/src/core/manager/EntityManager.ts b/src/core/manager/EntityManager.ts index b35bd84..d61d1f7 100644 --- a/src/core/manager/EntityManager.ts +++ b/src/core/manager/EntityManager.ts @@ -5,7 +5,7 @@ import { getRenderer } from './ModuleManager' import { getClosestObject, getLineId, parseLineId } from '@/core/ModelUtils' import { Vector2 } from 'three' import { getFreezeDeep } from '@/utils/webutils.ts' -import type { Object3DLike } from '@/types/ModelTypes.ts' +import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' /** * 实体管理器 @@ -33,7 +33,7 @@ export default class EntityManager { readonly _draggableObjects: THREE.Object3D[] = [] // 所有 THREEJS "线"对象, 检索值是"线实体"的 id, 取值方式是 {type}${startId}${endId}, 值是 THREE.Object3D 数组 - private readonly __lineMap = new Map() + private readonly __lineMap = new Map() // 差量渲染器 private readonly diffRenderer = new Map() @@ -468,11 +468,11 @@ export default class EntityManager { } } - appendLineObject(id: string, lines: Object3DLike) { + appendLineObject(id: string, lines: LineLike) { this.__lineMap.set(id, lines) } - findLineObjectById(lineId: string): Object3DLike | undefined { + findLineObjectById(lineId: string): LineLike | undefined { return this.__lineMap.get(lineId) } diff --git a/src/core/manager/InstanceMeshManager.ts b/src/core/manager/InstanceMeshManager.ts index 1406e2e..f60b014 100644 --- a/src/core/manager/InstanceMeshManager.ts +++ b/src/core/manager/InstanceMeshManager.ts @@ -5,7 +5,7 @@ import { PointManageWrap } from '@/core/manager/InstancePointManager.ts' import { Matrix4 } from 'three/src/math/Matrix4' export default class InstanceMeshManager { - private __uuidMap = new Map() + private __uuidMap = new Map() public readonly name: string public readonly viewport: Viewport @@ -34,7 +34,7 @@ export default class InstanceMeshManager { /** * 获取点实例数据 */ - findByMeshInstanceId(blockIndex: number, instanceId: number): InstanceMeshWrap { + findByMeshInstanceId(blockIndex: number, instanceId: number): MeshWrap { if (!this.blocks[blockIndex]) { console.error('InstancePointManager: Invalid blockIndex', blockIndex) return null @@ -44,7 +44,14 @@ export default class InstanceMeshManager { return this.__uuidMap.get(uuid) } - create(entityId: string, userData?: any): InstanceMeshWrap { + createByItem(item: ItemJson): MeshWrap { + return this.create(item.id, { + t: item.t, + entityId: item.id + }) + } + + create(entityId: string, userData?: any): MeshWrap { // 如果 entityId 存在,就替换 if (this.__uuidMap.has(entityId)) { const existingWrap = this.__uuidMap.get(entityId) @@ -76,11 +83,11 @@ export default class InstanceMeshManager { return null } - return new InstanceMeshWrap(entityId, this, blockIndex, meshIndex, userData) + return new MeshWrap(entityId, this, blockIndex, meshIndex, userData) } - delete(wrapOrId: InstanceMeshWrap | string) { - let wrap: InstanceMeshWrap + delete(wrapOrId: MeshWrap | string) { + let wrap: MeshWrap if (typeof wrapOrId === 'string') { wrap = this.__uuidMap.get(wrapOrId) if (!wrap) return @@ -123,7 +130,7 @@ export default class InstanceMeshManager { return block } - setBlockMatrixAt(wrap: InstanceMeshWrap, matrix: THREE.Matrix4) { + setBlockMatrixAt(wrap: MeshWrap, matrix: THREE.Matrix4) { const block = this.blocks[wrap.blockIndex] if (!block) { console.warn(`InstanceMeshManager: Block ${wrap.blockIndex} not found!`) @@ -132,6 +139,7 @@ export default class InstanceMeshManager { if (!block.__indexIdMap.has(wrap.meshIndex)) { this.__uuidMap.set(wrap.uuid, wrap) + block.__indexIdMap.set(wrap.meshIndex, wrap.uuid) wrap.parent = block.instancedMesh } block.instancedMesh.setMatrixAt(wrap.meshIndex, matrix) @@ -143,13 +151,12 @@ export default class InstanceMeshManager { block.dispose() } this.blocks.length = 0 // 清空 blocks 数组 - this.geometry.dispose() // 释放几何体资源 - this.material.dispose() // 释放材质资源 - console.log(`InstanceMeshManager ${this.name} disposed.`) + this.geometry?.dispose() // 释放几何体资源 + this.material?.dispose() // 释放材质资源 } } -export class InstanceMeshWrap { +export class MeshWrap { readonly entityId: string readonly manager: InstanceMeshManager readonly blockIndex: number @@ -180,7 +187,7 @@ export class InstanceMeshWrap { this.userData = userData } - setMatrix4(matrix: THREE.Matrix4): InstanceMeshWrap { + setMatrix4(matrix: THREE.Matrix4): MeshWrap { this.manager.setBlockMatrixAt(this, matrix) return this } @@ -196,7 +203,7 @@ export class InstanceMeshWrap { return matrix } - applyMatrix4(targetMatrix: THREE.Matrix4): InstanceMeshWrap { + applyMatrix4(targetMatrix: THREE.Matrix4): MeshWrap { const matrix = this.matrix const newMatrix = matrix.multiplyMatrices(targetMatrix, matrix) this.setMatrix4(newMatrix) diff --git a/src/core/manager/InstancePointManager.ts b/src/core/manager/InstancePointManager.ts index 40a0615..7135faa 100644 --- a/src/core/manager/InstancePointManager.ts +++ b/src/core/manager/InstancePointManager.ts @@ -3,7 +3,6 @@ import type Viewport from '@/core/engine/Viewport.ts' import { Vector3 } from 'three/src/math/Vector3' import InstanceMeshBlock from '@/core/manager/InstanceMeshBlock.ts' import { getMatrixFromTf } from '@/core/ModelUtils.ts' -import { InstanceMeshWrap } from '@/core/manager/InstanceMeshManager.ts' /** * 点实例管理器 diff --git a/src/core/manager/InteractionManager.ts b/src/core/manager/InteractionManager.ts index b7991c8..3f4374a 100644 --- a/src/core/manager/InteractionManager.ts +++ b/src/core/manager/InteractionManager.ts @@ -53,7 +53,7 @@ export default class InteractionManager implements IControls { } this.viewport.state.cursorMode = 'normal' - this.viewport.dragControl.enabled = true + this.viewport.dragManager.enabled = true this.viewport.viewerDom.style.cursor = '' this.option = undefined @@ -90,7 +90,7 @@ export default class InteractionManager implements IControls { // 初始化交互 this.currentTool = interaction - this.viewport.dragControl.enabled = false + this.viewport.dragManager.enabled = false this.currentTool.start(this.viewport, this.option) diff --git a/src/core/manager/LabelManager.ts b/src/core/manager/LabelManager.ts index e2713dd..2e5990c 100644 --- a/src/core/manager/LabelManager.ts +++ b/src/core/manager/LabelManager.ts @@ -1,41 +1,15 @@ import * as THREE from 'three' -import type IControls from '@/core/controls/IControls.ts' import type Viewport from '@/core/engine/Viewport.ts' import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' import { Text } from 'troika-three-text' import SimSunTTF from '@/assets/fonts/simsunb.ttf' -import type { Object3DLike } from '@/types/ModelTypes.ts' +import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' -export interface LabelOption { - /** - * 标签组件名称 - */ - name?: string - /** - * 是否使用 HTML 标签 - */ - useHtmlLabel: boolean - /** - * ex: css='14px', text=0.4 - */ - fontSize: number | string - /** - * ex: '#ffffff' - */ - color: string - /** - * ex: css='5px 8px', text=0.2 - */ - padding?: number | string - text?: string - - format?: (distance: number) => string -} /** * 标签管理器 */ -export default class LabelManager implements IControls { +export default class LabelManager { viewport: Viewport private labelMap: Map = new Map() private labelGroup: THREE.Group @@ -47,7 +21,7 @@ export default class LabelManager implements IControls { this.viewport.scene.add(this.labelGroup) } - createOrUpdateLabelByDistance(lineRef: Object3DLike, startPos: THREE.Vector3, endPos: THREE.Vector3, option: LabelOption): Text | CSS2DObject { + createOrUpdateLabelByDistance(lineRef: LineLike, startPos: THREE.Vector3, endPos: THREE.Vector3, option: LabelOption): Text | CSS2DObject { let labelObj = this.labelMap.get(lineRef.userData.labelObjectId) // 线段不存在 @@ -69,7 +43,7 @@ export default class LabelManager implements IControls { return labelObj } - createLabel(parentObj: Object3DLike, option: LabelOption): Text | CSS2DObject { + createLabel(parentObj: Object3DLike | LineLike, option: LabelOption): Text | CSS2DObject { const labelObj = this.createLabelObject(option) parentObj.userData.labelObjectId = labelObj.uuid @@ -89,7 +63,7 @@ export default class LabelManager implements IControls { } - updateLabel(parentObj: Object3DLike, text: string) { + updateLabel(parentObj: Object3DLike | LineLike, text: string) { const labelObj = this.labelMap.get(parentObj.userData.labelObjectId) if (labelObj) { if (labelObj instanceof CSS2DObject) { @@ -219,3 +193,29 @@ export default class LabelManager implements IControls { // } } + +export interface LabelOption { + /** + * 标签组件名称 + */ + name?: string + /** + * 是否使用 HTML 标签 + */ + useHtmlLabel: boolean + /** + * ex: css='14px', text=0.4 + */ + fontSize: number | string + /** + * ex: '#ffffff' + */ + color: string + /** + * ex: css='5px 8px', text=0.2 + */ + padding?: number | string + text?: string + + format?: (distance: number) => string +} diff --git a/src/core/manager/LineSegmentManager.ts b/src/core/manager/LineSegmentManager.ts index 99fa480..92ec5a7 100644 --- a/src/core/manager/LineSegmentManager.ts +++ b/src/core/manager/LineSegmentManager.ts @@ -1,24 +1,36 @@ import * as THREE from 'three' import type Viewport from '@/core/engine/Viewport.ts' -import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry' import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial' -import type { Object3DLike, Vector3Like } from '@/types/ModelTypes.ts' -import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry' +import type { Vector3Like } from '@/types/ModelTypes.ts' +import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry' /** * 线段管理器 */ export default class LineSegmentManager { private readonly viewport: Viewport - private readonly lineGeometry: LineGeometry // LineSegmentsGeometry + private readonly lineGeometry: LineSegmentsGeometry private readonly lineMaterial: LineMaterial private readonly lineSegments: LineSegments2 - private readonly segments: Map = new Map() + private readonly segments: Map = new Map() public needsUpdate: boolean = false private colorArray: Float32Array | null = null private positionArray: Float32Array | null = null + constructor(name: string, viewport: Viewport, lineMaterial: LineMaterial) { + this.viewport = viewport + this.lineMaterial = lineMaterial + + this.lineGeometry = new LineSegmentsGeometry() // new LineSegmentsGeometry() + + // 创建线段的渲染对象 + this.lineSegments = new LineSegments2(this.lineGeometry, this.lineMaterial) + this.lineSegments.name = name + this.lineSegments.frustumCulled = false + this.viewport.scene.add(this.lineSegments) + } + /** * 创建或更新线段 * @param lineId 线段唯一标识 @@ -26,8 +38,9 @@ export default class LineSegmentManager { * @param end 终点 * @param color 线段颜色 (可选) * @param userData 自定义数据 (可选) + * @param visible 可见 */ - createLine(lineId: string, start: Vector3Like, end: Vector3Like, color?: THREE.Color | number | string, userData: Partial = {}): LineManageWrap { + createOrUpdateLine(lineId: string, start: Vector3Like, end: Vector3Like, color?: THREE.Color | number | string, userData: Partial = {}, visible: boolean = true): LineWrap { const segment = this.segments.get(lineId) if (segment) { // console.error(`LineSegmentManager: Line with id ${lineId} already exists.`) @@ -52,15 +65,7 @@ export default class LineSegmentManager { colorObj = new THREE.Color(color) } - const result = new LineManageWrap(this, { - uuid: lineId, - visible: true, - userData: { - entityId: lineId, - createType: 'line', - ...userData - } - }, startVec, endVec, colorObj) + const result = new LineWrap(this, lineId, startVec, endVec, colorObj, visible) this.segments.set(lineId, result) result.parent = this.lineSegments @@ -68,7 +73,7 @@ export default class LineSegmentManager { return result } - updateLine(lineId: string, start?: Vector3Like, end?: Vector3Like, color?: THREE.Color | number | string): LineManageWrap { + updateLine(lineId: string, start?: Vector3Like, end?: Vector3Like, color?: THREE.Color | number | string, visible: boolean = true): LineWrap { const wrap = this.segments.get(lineId) if (!wrap) return @@ -94,66 +99,6 @@ export default class LineSegmentManager { return wrap } - // /** - // * 更新线段位置 - // * @param lineId 线段唯一标识 - // * @param start 新起点 - // * @param end 新终点 - // */ - // updateLinePosition(lineId: string, start: THREE.Vector3Like, end: THREE.Vector3Like): void { - // const segment = this.segments.get(lineId) - // if (!segment) return - // - // if (start instanceof THREE.Vector3) { - // segment.start.copy(start) - // } else { - // segment.start.set(start[0], start[1], start[2]) - // } - // - // if (end instanceof THREE.Vector3) { - // segment.end.copy(end) - // } else { - // segment.end.set(end[0], end[1], end[2]) - // } - // - // this.needsUpdate = true - // } - // - // /** - // * 更新线段颜色 - // * @param lineId 线段唯一标识 - // * @param color 新颜色 - // */ - // updateLineColor(lineId: string, color: THREE.Color | number | string): void { - // const segment = this.segments.get(lineId) - // if (!segment) return - // - // if (color instanceof THREE.Color) { - // segment.color = color - // } else if (typeof color === 'number') { - // segment.color = new THREE.Color(color) - // } else if (typeof color === 'string') { - // segment.color = new THREE.Color(color) - // } else { - // segment.color = undefined - // } - // - // this.needsUpdate = true - // } - // - // /** - // * 设置线段可见性 - // * @param lineId 线段唯一标识 - // * @param visible 是否可见 - // */ - // setLineVisible(lineId: string, visible: boolean): void { - // const segment = this.segments.get(lineId) - // if (segment && segment.visible !== visible) { - // segment.visible = visible - // this.needsUpdate = true - // } - // } - /** * 删除线段 * @param lineId 线段唯一标识 @@ -167,14 +112,6 @@ export default class LineSegmentManager { } /** - * 获取线段数据 - * @param lineId 线段唯一标识 - */ - getObject3DLike(lineId: string): Object3DLike { - return this.segments.get(lineId) - } - - /** * 更新几何体数据 (应在渲染循环中调用) */ updateGeometry(): void { @@ -247,26 +184,6 @@ export default class LineSegmentManager { this.needsUpdate = false } - /** - * 创建线段管理器实例 - */ - public static create(name: string, viewport: Viewport, lineMaterial: LineMaterial): LineSegmentManager { - return new LineSegmentManager(name, viewport, lineMaterial) - } - - private constructor(name: string, viewport: Viewport, lineMaterial: LineMaterial) { - this.viewport = viewport - this.lineMaterial = lineMaterial - - this.lineGeometry = new LineGeometry() // new LineSegmentsGeometry() - - // 创建线段的渲染对象 - this.lineSegments = new LineSegments2(this.lineGeometry, this.lineMaterial) - this.lineSegments.name = name - this.lineSegments.frustumCulled = false - this.viewport.scene.add(this.lineSegments) - } - dispose() { this.viewport.scene.remove(this.lineSegments) this.lineGeometry.dispose() @@ -287,25 +204,21 @@ export default class LineSegmentManager { } -export class LineManageWrap { +export class LineWrap { readonly manager: LineSegmentManager parent: THREE.Object3D | null = null + uuid: string start: THREE.Vector3 end: THREE.Vector3 color: THREE.Color - - uuid: string - name: string visible: boolean - readonly position = new THREE.Vector3() - readonly rotation = new THREE.Euler() - readonly scale = new THREE.Vector3(1, 1, 1) + //@ts-ignore userData: UserData = {} get type() { - return 'LineManageWrap' + return 'LineWrap' } get isObject3D() { @@ -315,12 +228,13 @@ export class LineManageWrap { updateWorldMatrix() { } - constructor(lineManager: LineSegmentManager, data: any, start: THREE.Vector3, end: THREE.Vector3, color: THREE.Color) { + constructor(lineManager: LineSegmentManager, uuid: string, start: THREE.Vector3, end: THREE.Vector3, color: THREE.Color, visible: boolean = true) { this.manager = lineManager - _.extend(this, data) + this.uuid = uuid this.start = start this.end = end this.color = color + this.visible = visible } dispose() { diff --git a/src/core/manager/SelectManager.ts b/src/core/manager/SelectManager.ts index 946df58..1361ee8 100644 --- a/src/core/manager/SelectManager.ts +++ b/src/core/manager/SelectManager.ts @@ -318,6 +318,7 @@ export default class SelectManager { } private onMouseDown = (event: MouseEvent) => { + if (event.button !== 0) return if (event.shiftKey) { // 记录鼠标按下位置 this.recStartPos = this.viewport.getClosestIntersection(event) @@ -342,10 +343,11 @@ export default class SelectManager { } private onMouseUp = (event: MouseEvent) => { + if (event.button !== 0) return this.disposeRect() const clickTime = this.clickTime this.clickTime = null - if (Date.now() - clickTime < 200) { + if (Date.now() - clickTime < Constract.MOUSE_CLICK_DELAY) { // 如果是点击事件,触发选中逻辑 const objects: Object3DLike[] = this.viewport.entityManager.getObjectByCanvasMouse(event) if (objects.length > 0 && objects[0]?.userData?.entityId && objects[0]?.userData?.createType !== 'line') { diff --git a/src/core/manager/StateManager.ts b/src/core/manager/StateManager.ts index 87414ed..e2ef597 100644 --- a/src/core/manager/StateManager.ts +++ b/src/core/manager/StateManager.ts @@ -53,9 +53,9 @@ export default class StateManager { /** * 实体对象, 用于同步当前场景的状态 */ - readonly entityManager: EntityManager + entityManager: EntityManager - readonly viewport: Viewport + viewport: Viewport /** * 是否发生了变化,通知外部是否需要保存数据 @@ -96,22 +96,26 @@ export default class StateManager { /** * @param id 唯一场景标识符, 用于做临时存储的 key - * @param viewport 视口对象, 用于获取、同步当前场景的状态 * @param maxHistorySteps 最大回撤步数 默认为 20 */ - constructor(id: string, viewport: Viewport, maxHistorySteps = 20) { + constructor(id: string, maxHistorySteps = 20) { this.id = id this.storeKey = `-tmp-yvan-lcc-${this.id}` - this.entityManager = viewport.entityManager - this.viewport = viewport this.maxHistorySteps = maxHistorySteps - this.historySteps = [] - this.pendingChanges = false this.isAutoSavingPaused = false } + init(viewport: Viewport) { + this.viewport = viewport + this.entityManager = viewport.entityManager + + _.defer(() => { + this.fullSync(false) + }) + } + // 差异反转方法 private invertDiff(diff: DataDiff): DataDiff { return { @@ -331,7 +335,7 @@ export default class StateManager { /** * 从外部加载数据 */ - async load(data: Partial) { + async load(data: VData) { this.isLoading.value = true this.historySteps = Array.from({ length: this.maxHistorySteps }, () => null) this.historyIndex = -1 @@ -340,16 +344,10 @@ export default class StateManager { // 停止自动保存,避免在加载过程中触发 this.stopAutoSave() - // 直接替换数组引用(避免响应式开销) - //@ts-ignore - this.___vdata = { - id: this.id, - isChanged: false, - ...data - } + this.___vdata = data // 同步到视口 - this.fullSync() + // this.fullSync() this.isChanged.value = false console.log('[StateManager] 加载完成,共', data.items.length, '个对象') @@ -358,6 +356,9 @@ export default class StateManager { await this.saveToLocalstore() } finally { + EventBus.dispatch('dataLoadComplete', { + stateManager: this + }) this.isLoading.value = false } } @@ -437,8 +438,8 @@ export default class StateManager { } this.isChanged.value = saved.isChanged || false - this.fullSync(false) // 同步到视口 - console.log('[StateManager] 从本地存储恢复', this.___vdata.items.length, '个对象') + // this.fullSync(false) // 同步到视口 + console.log('[StateManager] 从本地存储 [' + this.storeKey + '] 恢复', this.___vdata.items.length, '个对象') return true } @@ -450,6 +451,9 @@ export default class StateManager { } finally { this.isLoading.value = false + EventBus.dispatch('dataLoadComplete', { + stateManager: this + }) } } @@ -477,34 +481,18 @@ export default class StateManager { /** * 尝试从草稿中读取数据 */ - static async tryLoadCatalogFromLocalstore(): Promise<{ - success: boolean, - catalogCode?: string, - catalog?: Catalog, - stateManagerId?: string - }> { + static async tryLoadCatalogFromLocalstore(stateManagerId: string): Promise { // 获取 url 中的 stateManagerId // 从 localforage 中读取草稿数据 - const stateManagerId = getQueryParams()?.get('store') if (stateManagerId) { const storeKey = `-tmp-yvan-lcc-${stateManagerId}` const saved: VData = await localforage.getItem(storeKey) - if (saved && saved.catalog) { - const catalogCode = saved.catalogCode || '' - if (catalogCode) { - return { - success: true, - catalogCode, - catalog: saved.catalog, - stateManagerId - } - } + if (saved && saved.catalog && saved.catalogCode && saved.worldData) { + return saved } } - return { - success: false - } + return null } /** diff --git a/src/core/manager/WorldModel.ts b/src/core/manager/WorldModel.ts index 18f26f0..5d80020 100644 --- a/src/core/manager/WorldModel.ts +++ b/src/core/manager/WorldModel.ts @@ -1,4 +1,4 @@ -import _ from 'lodash' +import _, { cloneDeep } from 'lodash' import { reactive, watch } from 'vue' import EventBus from '@/runtime/EventBus' import Measure from '@/modules/measure' @@ -6,42 +6,58 @@ import Way from '@/modules/way' import Gstore from '@/modules/gstore' import Rack from '@/modules/rack' import ShuttleRack from '@/modules/shuttle_rack' -import Pallet from "@/modules/pallet" -import Tote from "@/modules/tote" -import Agv1 from "@/modules/agv1" -import Carton from "@/modules/carton" -import Ptr from "@/modules/ptr" -import Clx from "@/modules/clx" -import Charger from "@/modules/charger" +import Pallet from '@/modules/pallet' +import Tote from '@/modules/tote' +import Agv1 from '@/modules/agv1' +import Carton from '@/modules/carton' +import Ptr from '@/modules/ptr' +import Clx from '@/modules/clx' +import Charger from '@/modules/charger' import StateManager from '@/core/manager/StateManager.ts' +import { getQueryParams, setQueryParam } from '@/utils/webutils.ts' +import localforage from 'localforage' export interface WorldModelState { isOpened: boolean // 是否已打开世界模型 - catalog: Catalog // 世界模型目录数据 - isDraft: boolean // 是否是草稿数据, 如果是草稿数据, 则不需要再从服务器加载数据 + worldData: any // 世界模型数据, 包含排除 items 楼层数据之外的所有数据 + + infos: any // 当前楼层的其他数据 + isChanged: boolean // 当前楼层数据是否被修改 + catalog: Catalog // 当前世界模型目录数据 + server: string // 当前楼层服务器地址 + project_uuid: string // 当前楼层所在项目ID catalogCode: string // 当前楼层的目录代码 + stateManagerId: string // 当前楼层的状态管理器id + isDraft: boolean // 是否是草稿数据 } /** * 物流世界模型 */ export default class WorldModel { - data: any = null + currentStateManager: StateManager /** * 世界模型双向绑定的状态数据 */ state: WorldModelState = reactive({ isOpened: false, // 是否已打开世界模型 + worldData: null, // 世界模型数据, 包含排除 items 楼层数据之外的所有数据 + + infos: {} as any, // 楼层的其他数据 + isChanged: false, + catalog: [] as Catalog, // 世界模型目录 + server: '', + project_uuid: '', // 项目ID catalogCode: '', // 当前楼层的目录代码 - isDraft: false, // 是否是草稿数据, 如果是草稿数据, 则不需要再从服务器加载数据 + stateManagerId: '', // 当前楼层的状态管理器id, 一般是 项目ID+目录项ID - catalog: [] as Catalog // 世界模型目录 + isDraft: false // 是否是草稿数据, 如果是草稿数据, 则不需要再从服务器加载数据 }) get gridOption(): IGridHelper { - const data = _.get(this.data, 'Tool.gridHelper') + const data = _.get(this.state.worldData, 'Tool.gridHelper') return _.defaultsDeep(data, { axesEnabled: true, axesSize: 5, @@ -68,8 +84,6 @@ export default class WorldModel { */ init() { // 观察 this.state.catalogCode 的变化, 如果变化就调用 catalogCodeChange 方法 - watch(() => this.state.catalogCode, this.onCatalogCodeChanged.bind(this)) - return Promise.all([ Measure, Way, @@ -88,84 +102,111 @@ export default class WorldModel { console.log('世界模型初始化完成') // 尝试从草稿中加载数据 - StateManager.tryLoadCatalogFromLocalstore().then(data => { - if (data.success) { - this.state.catalog = data.catalog + const stateManagerId = getQueryParams()?.get('store') + + StateManager.tryLoadCatalogFromLocalstore(stateManagerId).then(data => { + if (data) { this.state.isOpened = true - this.state.catalogCode = data.catalogCode - this.state.stateManagerId = data.stateManagerId + this.state.worldData = data.worldData + + this.state.infos = data.infos + this.state.isChanged = data.isChanged + this.state.catalog = data.catalog + this.state.server = data.server + this.state.project_uuid = data.project_uuid this.state.isDraft = true + + this.tryOpenCatelog(data.catalogCode, true).then(() => { + this.state.catalogCode = data.catalogCode + this.state.stateManagerId = data.project_uuid + '_' + data.catalogCode + }) } }) }) } - /** - * 读取世界地图数据目录 - */ - loadCatalog(data: any) { - this.data = data - this.state.catalog = data.catalog - this.state.isOpened = true - } - - /** - * 当楼层发生改变时调用此方法, 将事件派发出去 - */ - onCatalogCodeChanged(catalogCode: string) { - if (this.state.isDraft) { - // 草稿数据, 不需要再从服务器加载数据, 放行 - EventBus.dispatch('catalogChanged', { - catalogCode: this.state.catalogCode, - stateManagerId: this.state.stateManagerId - }) - return - } - - + async tryOpenCatelog(catalogCode: string, isDraft: boolean = false) { if (!catalogCode) { - this.state.stateManagerId = '' - EventBus.dispatch('catalogChanged', { - catalogCode: this.state.catalogCode, - stateManagerId: this.state.stateManagerId - }) + // 没有地图 + this.clear() return } - const floor = _.find(this.data.items, r => r.catalogCode === catalogCode && r.t === 'floor') - if (!floor) { - system.msg('楼层不存在: ' + catalogCode) + if (!this.state.project_uuid) { + system.showErrorDialog('项目未初始化, 请先打开一个项目!') this.state.catalogCode = '' + this.state.stateManagerId = null return } - this.state.stateManagerId = this.data.project_uuid + '_' + catalogCode - EventBus.dispatch('catalogChanged', { - catalogCode: this.state.catalogCode, - stateManagerId: this.state.stateManagerId - }) + this.state.catalogCode = catalogCode + this.state.isDraft = isDraft + this.state.stateManagerId = this.state.project_uuid + '_' + catalogCode + const stateManager = new StateManager(this.state.stateManagerId) + + if (isDraft) { + // 从草稿捞数据 + await stateManager.loadFromLocalstore() + } else { + // 从服务器捞数据 + const vdata = await worldModel.getCatalogData(catalogCode) + await stateManager.load(vdata) + } + this.currentStateManager = stateManager + } + + /** + * 从远程服务器读取世界地图数据目录 + */ + async loadWorldFromRemoting(veryBigData) { + const worldData = veryBigData + const catalog = veryBigData.catalog + const items = veryBigData.items + delete veryBigData.catalog + delete veryBigData.items + + this.state.isOpened = true + this.state.worldData = worldData + + // 没有打开楼层,不加载 this.state.infos + // 没有打开楼层,不加载 this.state.isChanged + this.state.catalog = catalog + this.state.server = veryBigData.server + this.state.project_uuid = veryBigData.project_uuid + + // 没有打开楼层,不加载 this.state.catalogCode + this.state.isDraft = false + + await localforage.setItem('_____veryBigItemsData', items) } /** * 从服务器获取当前目录楼层的所有数据 */ - async getCatalogData(catalogCode: string): Promise> { - if (!this.data || !this.data.items) { + async getCatalogData(catalogCode: string): Promise { + const _____veryBigItemsData: any = await localforage.getItem('_____veryBigItemsData') + if (!_____veryBigItemsData) { return Promise.reject('楼层数据未加载, catalogCode=' + catalogCode) } - const floor = _.find(this.data.items, r => r.catalogCode === this.state.catalogCode && r.t === 'floor') + const floor = _.find(_____veryBigItemsData, r => r.catalogCode === this.state.catalogCode && r.t === 'floor') if (floor) { if (!floor.items) { floor.items = [] } - const vdata: Partial = { - items: _.cloneDeep(floor.items) as ItemJson[], + const items = _.cloneDeep(floor.items) + delete floor.items + + const vdata: VData = { + items: items as ItemJson[], + infos: floor, isChanged: false, - server: '', - projectId: '', - catalogCode: catalogCode + catalog: _.cloneDeep(this.state.catalog), + server: this.state.server, + project_uuid: this.state.project_uuid, + catalogCode: catalogCode, + worldData: _.cloneDeep(this.state.worldData) } console.log('从服务器返回数据, 一共' + vdata.items.length + '个') @@ -173,4 +214,14 @@ export default class WorldModel { } return Promise.reject('楼层不存在, catalogCode=' + catalogCode) } + + clear() { + this.currentStateManager = null + this.state.catalogCode = '' + this.state.stateManagerId = null + setQueryParam('store', '') + EventBus.dispatch('dataLoadComplete', { + stateManager: null + }) + } } diff --git a/src/editor/Model2DEditor.vue b/src/editor/Model2DEditor.vue index f3b5acc..f5dd2ab 100644 --- a/src/editor/Model2DEditor.vue +++ b/src/editor/Model2DEditor.vue @@ -4,10 +4,6 @@ - - - + 添加CAD图纸 @@ -30,9 +26,9 @@
-
+
@@ -109,9 +105,10 @@ import Constract from '@/core/Constract' import EventBus from '@/runtime/EventBus' import SceneHelp from '@/core/engine/SceneHelp' import BulkCopy from './BulkCopy.vue' -import lodash from "lodash"; -import { DXFViewer } from 'three-dxf-viewer'; -import cadFont from "@/assets/fonts/helvetiker_regular.typeface.json?url" +import lodash from 'lodash' +import { DXFViewer } from 'three-dxf-viewer' +import cadFont from '@/assets/fonts/helvetiker_regular.typeface.json?url' +import StateManager from '@/core/manager/StateManager.js' export default defineComponent({ @@ -124,17 +121,13 @@ export default defineComponent({ scene: null, viewport: null, currentStateManagerId: null, + currentStateManagerVersion: 0, searchKeyword: '' } }, mounted() { - if (worldModel.state.isDraft) { - // 如果是草稿状态, 则不加载视口 - this.initByFloor() - } - EventBus.on('catalogChanged', (floor) => { - // 当楼层加载完成后, 初始化视口 - this.initByFloor() + this.$nextTick(() => { + this.initByFloor(worldModel.currentStateManager) }) }, beforeUnmount() { @@ -142,20 +135,18 @@ export default defineComponent({ }, methods: { renderIcon, - getRandom() { - return Math.random().toString(36).substring(2, 15) - }, destroyScene() { - if (this.viewport) { - this.viewport.dispose() - this.viewport = null - delete window['viewport'] - } if (this.scene) { this.scene.dispose() this.scene = null delete window['scene'] } + if (this.viewport) { + this.viewport.dispose() + this.viewport = null + } + this.currentStateManagerId = null + this.currentStateManagerVersion++ this.isReady = false }, toFixed(num) { @@ -167,28 +158,21 @@ export default defineComponent({ } return parseFloat(num).toFixed(2) }, - initByFloor() { + initByFloor(stateManager) { this.destroyScene() if (!this.$el || this.$.isUnmounted) { // 检查组件是否已卸载, 幻影加载问题 + console.warn('Model2DEditor component is unmounted, skipping initialization.') return } - delete window['editor'] - delete window['viewport'] - delete window['scene'] - delete window['stateManager'] - delete window['entityManager'] - delete window['renderer'] - delete window['camera'] - delete window['renderer'] - delete window['controls'] - - const id = worldModel.state.stateManagerId + + const id = this.worldModelState.stateManagerId this.currentStateManagerId = id + this.currentStateManagerVersion++ - if (!worldModel.state.catalogCode || !worldModel.state.isOpened || !id) { + if (!this.worldModelState.catalogCode || !this.worldModelState.isOpened || !id) { // 放弃加载 setQueryParam('store', '') return @@ -212,7 +196,7 @@ export default defineComponent({ } const sceneHelp = new SceneHelp(worldModel, worldModel.state.catalogCode) - const viewport = new Viewport(sceneHelp, viewerDom) + const viewport = new Viewport(sceneHelp, viewerDom, stateManager) this.scene = markRaw(sceneHelp) this.viewport = markRaw(viewport) @@ -222,15 +206,7 @@ export default defineComponent({ setQueryParam('store', id) // window.history.replaceState({}, '', window.location.href + '?store=' + id) - window['viewport'] = viewport window['THREE'] = THREE - window['scene'] = sceneHelp.scene - window['stateManager'] = viewport.stateManager - window['entityManager'] = viewport.entityManager - window['renderer'] = viewport.renderer - window['camera'] = viewport.camera - window['renderer'] = viewport.renderer - window['controls'] = viewport.controls //@ts-ignore viewerDom.focus() @@ -249,6 +225,7 @@ export default defineComponent({ } else { console.error('Canvas container not found after retries') this.currentStateManagerId = '' + this.currentStateManagerVersion++ } } @@ -258,18 +235,18 @@ export default defineComponent({ }, showBulkCopy() { - const viewport = this.viewport; - const selectedItem = viewport?.state?.selectedItem; - if(!viewport || !selectedItem) return; + const viewport = this.viewport + const selectedItem = viewport?.state?.selectedItem + if (!viewport || !selectedItem) return const config = { numberOfRows: 1, numberOfColumns: 1, rowSpace: 0, columnSpacing: 0, - doubleRow: false, - }; + doubleRow: false + } system.showDialog(createVNode(BulkCopy, { - config, + config }), { title: '批量复制', width: 520, @@ -277,83 +254,64 @@ export default defineComponent({ showClose: true, showMax: true, showCancelButton: false, - showOkButton: true, + showOkButton: true }).then(() => { - if(!config.numberOfRows || !config.numberOfColumns) return; + if (!config.numberOfRows || !config.numberOfColumns) return viewport.stateManager.update(({ getEntity, addEntity }) => { - const xAxle = selectedItem.tf[0][0]; - const zAxle = selectedItem.tf[0][2]; - const xSize = selectedItem.tf[2][0]; - const zSize = selectedItem.tf[2][2]; - console.log("item", JSON.stringify(selectedItem.tf)); - for (let rCount = 0; rCount < config.numberOfRows; rCount++) { - for (let cCount = 0; cCount < config.numberOfColumns; cCount++) { - if(rCount===0 && cCount===0) continue; - const item = lodash.cloneDeep(selectedItem); - item.id = system.createUUID(); - item.tf[0][0] = xAxle + cCount * (xSize + config.columnSpacing); - item.tf[0][2] = zAxle + rCount * (zSize + config.rowSpace); - addEntity(item); - console.log("item", JSON.stringify(item.tf)); - } + const xAxle = selectedItem.tf[0][0] + const zAxle = selectedItem.tf[0][2] + const xSize = selectedItem.tf[2][0] + const zSize = selectedItem.tf[2][2] + console.log('item', JSON.stringify(selectedItem.tf)) + for (let rCount = 0; rCount < config.numberOfRows; rCount++) { + for (let cCount = 0; cCount < config.numberOfColumns; cCount++) { + if (rCount === 0 && cCount === 0) continue + const item = lodash.cloneDeep(selectedItem) + item.id = system.createUUID() + item.tf[0][0] = xAxle + cCount * (xSize + config.columnSpacing) + item.tf[0][2] = zAxle + rCount * (zSize + config.rowSpace) + addEntity(item) + console.log('item', JSON.stringify(item.tf)) } - }); - console.log("config", config, selectedItem); - }).finally(); + } + }) + console.log('config', config, selectedItem) + }).finally() }, async addCADDxf(file) { // 创建一个边长为 1 的红色立方体 - const geometry = new THREE.BoxGeometry(1, 1, 1); - const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); - const cube = new THREE.Mesh(geometry, material); - + const geometry = new THREE.BoxGeometry(1, 1, 1) + const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }) + const cube = new THREE.Mesh(geometry, material) console.log('file', file) if (!file) return file = file.raw - const viewer = new DXFViewer(); - let dxf = await viewer.getFromFile(file, cadFont); + const viewer = new DXFViewer() + let dxf = await viewer.getFromFile(file, cadFont) dxf.scale.set(0.001, 0.001, 0.001) dxf.rotation.x = -Math.PI / 2 // Add the geometry to the scene - const group = new THREE.Group(); - group.add(dxf); - this.scene.add(group); + const group = new THREE.Group() + group.add(dxf) + this.scene.add(group) } }, computed: { + worldModelState() { + return worldModel.state + }, state() { return this.viewport?.state }, - currentLevel: { - get() { - return worldModel.state.catalogCode - }, - set(newVal) { - worldModel.state.catalogCode = newVal - } - }, - calcCatalog() { - if (!worldModel.state.catalog || !worldModel.state.isOpened) { - return [] - } - return worldModel.state.catalog.map(group => ({ - value: group.label, - label: group.label, - children: group.items.map(item => ({ - value: item.catalogCode, - label: item.label - })) - })) - }, selectedObject() { - return this.state?.selectedObject; - }, + return this.state?.selectedObject + } } }) diff --git a/src/editor/ModelMain.vue b/src/editor/ModelMain.vue index eb87d2a..319b4bd 100644 --- a/src/editor/ModelMain.vue +++ b/src/editor/ModelMain.vue @@ -51,7 +51,8 @@
- + @@ -115,6 +116,7 @@ import { normalizeShortKey } from '@/utils/webutils.ts' import Logo from '@/assets/images/logo.png' import './ModelMain.less' +import EventBus from '@/runtime/EventBus.js' export default { components: { Model2DEditor, Model3DViewer, Split, SplitArea }, @@ -152,6 +154,15 @@ export default { } }) }) + EventBus.on('dataLoadComplete', (data) => { + const { stateManager } = data + if (stateManager) { + this.isShowEditor = true + } else { + this.isShowEditor = false + } + this.editorHash += 1 // 刷新编辑器 + }) }, unmounted() { ModelMainUnmounted() @@ -159,6 +170,8 @@ export default { data() { return { Logo, + isShowEditor: false, + editorHash: 0, currentViewport: null, calcRootMenu: getRootMenu(), bottomSize: 30, @@ -304,4 +317,4 @@ export default { } } } - \ No newline at end of file + diff --git a/src/editor/menus/FileMenu.ts b/src/editor/menus/FileMenu.ts index bcb6d20..5c1ff46 100644 --- a/src/editor/menus/FileMenu.ts +++ b/src/editor/menus/FileMenu.ts @@ -26,7 +26,7 @@ export default defineMenu((menus) => { const res = await import('@/example/example1') worldModel.state.isDraft = false - worldModel.loadCatalog(res.default) + await worldModel.loadWorldFromRemoting(res.default) } finally { system.clearLoading() @@ -49,4 +49,4 @@ export default defineMenu((menus) => { } ] ) -}) \ No newline at end of file +}) diff --git a/src/editor/widgets/modeltree/ModeltreeViewJs.js b/src/editor/widgets/modeltree/ModeltreeViewJs.js index 6268e09..a8ccb0b 100644 --- a/src/editor/widgets/modeltree/ModeltreeViewJs.js +++ b/src/editor/widgets/modeltree/ModeltreeViewJs.js @@ -45,7 +45,8 @@ export default defineComponent({ return worldModel.state.catalogCode }, set(newVal) { - worldModel.state.catalogCode = newVal + // worldModel.state.catalogCode = newVal + worldModel.tryOpenCatelog(newVal) } }, calcCatalog() { diff --git a/src/example/example1.js b/src/example/example1.js index f98951e..45a3bfd 100644 --- a/src/example/example1.js +++ b/src/example/example1.js @@ -2,6 +2,7 @@ import { buildAgvPerformanceData, buildCenterLinkPerformanceData, buildPointPerf export default { project_uuid: 'example1', + server: 'demo', Tool: { Group: [], // 分组 GlobalVariables: [], // 全局变量 @@ -325,13 +326,61 @@ export default { { catalogCode: 'f3', t: 'floor', items: [ + // { + // id: 'node1', + // // t: 'gstore', + // // t: 'carton', + // t: 'measure', + // v: true, + // tf: [[0, 0, 0], [0, 0, 0], [2, 0.05, 1]], + // dt: { in: [], out: [], center: [] } + // }, +// 双向连接路径 { - id: 'gstore1', - t: 'gstore', - // t: 'carton', + id: 'way11', + t: 'way', v: true, - tf: [[0, 0, 0], [0, 0, 0], [2, 0.05, 1]], - dt: { in: [], out: [], center: [] } + tf: [[2, 0.1, 1], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: ['way12'], out: ['way12'], center: [] } + }, + { + id: 'way12', + t: 'way', + v: true, + tf: [[5, 0.1, 1], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: ['way11'], out: ['way11'], center: [] } + }, + + // 21->22 单向连接路径 + { + id: 'way21', + t: 'way', + v: true, + tf: [[2, 0.1, 3], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: [], out: ['way22'], center: [] } + }, + { + id: 'way22', + t: 'way', + v: true, + tf: [[5, 0.1, 3], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: ['way21'], out: [], center: [] } + }, + + // 32->31 单向连接路径 + { + id: 'way31', + t: 'way', + v: true, + tf: [[2, 0.1, 5], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: ['way32'], out: [], center: [] } + }, + { + id: 'way32', + t: 'way', + v: true, + tf: [[5, 0.1, 5], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: [], out: ['way31'], center: [] } } ] }, @@ -403,6 +452,29 @@ export default { v: true, tf: [[5, 0, 5], [0, 0, 0], [2, 1, 1]], dt: { in: [], out: [], center: [] } + }, + + // 尺 + { + id: 'measure11', + t: 'measure', + v: true, + tf: [[2, 0.1, 1], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: [], out: [], center: ['measure12', 'measure13'] } + }, + { + id: 'measure12', + t: 'measure', + v: true, + tf: [[5, 0.1, 1], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: [], out: [], center: ['measure11'] } + }, + { + id: 'measure13', + t: 'measure', + v: true, + tf: [[2, 0.1, 3], [0, 0, 0], [1.0, 1.0, 1.0]], + dt: { in: [], out: [], center: ['measure22', 'measure11'] } } ] }, @@ -846,36 +918,36 @@ export default { } ] }, - { - catalogCode: 'flash1', t: 'floor', - items: [ - { - id: 'flash_rack1', - t: 'flash_rack', - dt: async () => import('./flash.js') - } - ] - }, - { - catalogCode: 'flash2', t: 'floor', - items: [ - { - id: 'flash_rack1', - t: 'flash_rack', - dt: async () => import('./flash.js') - } - ] - }, - { - catalogCode: 'flash3', t: 'floor', - items: [ - { - id: 'flash_rack1', - t: 'flash_rack', - dt: async () => import('./flash.js') - } - ] - }, + // { + // catalogCode: 'flash1', t: 'floor', + // items: [ + // { + // id: 'flash_rack1', + // t: 'flash_rack', + // dt: async () => import('./flash.js') + // } + // ] + // }, + // { + // catalogCode: 'flash2', t: 'floor', + // items: [ + // { + // id: 'flash_rack1', + // t: 'flash_rack', + // dt: async () => import('./flash.js') + // } + // ] + // }, + // { + // catalogCode: 'flash3', t: 'floor', + // items: [ + // { + // id: 'flash_rack1', + // t: 'flash_rack', + // dt: async () => import('./flash.js') + // } + // ] + // }, { catalogCode: 'de1', t: 'side', floorHeight: [ // 侧面视图的各层面高度 diff --git a/src/modules/carton/CartonRenderer.ts b/src/modules/carton/CartonRenderer.ts index 98d56f2..3e66a83 100644 --- a/src/modules/carton/CartonRenderer.ts +++ b/src/modules/carton/CartonRenderer.ts @@ -1,11 +1,11 @@ import * as THREE from 'three' import BaseRenderer from '@/core/base/BaseRenderer.ts' import Constract from '@/core/Constract.ts' -import InstancePointManager from '@/core/manager/InstancePointManager.ts' import type { Object3DLike } from '@/types/ModelTypes.ts' import MODULE_GLB_File from '@/assets/Models/carton.glb?url' import MODULE_3DS_TEX from '@/assets/Models/carton.jpg?url' import { loadGlbModule, loadTexture, processModel } from '@/core/ModelUtils.ts' +import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' /** * 货架货位渲染器 @@ -58,21 +58,21 @@ export default class PalletRenderer extends BaseRenderer { } createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike { - return this.pointManager.createPoint(item) + return this.pointManager.createByItem(item) } - get pointManager(): InstancePointManager { + get pointManager(): InstanceMeshManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } - return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () => + return this.tempViewport.getOrCreateMeshManager(this.itemTypeName, () => { // 构建 InstanceMesh 代理对象 - InstancePointManager.create(this.itemTypeName, + return new InstanceMeshManager(this.itemTypeName, this.tempViewport, this.cartonGeometry, this.cartonMaterial, true, true) - ) + }) } dispose() { diff --git a/src/modules/gstore/GstoreRenderer.ts b/src/modules/gstore/GstoreRenderer.ts index ae04c65..e05b5f5 100644 --- a/src/modules/gstore/GstoreRenderer.ts +++ b/src/modules/gstore/GstoreRenderer.ts @@ -2,11 +2,8 @@ import * as THREE from 'three' import BaseRenderer from '@/core/base/BaseRenderer.ts' import Constract from '@/core/Constract.ts' import { type Object3DLike } from '@/types/ModelTypes.ts' -import InstancePointManager from '@/core/manager/InstancePointManager.ts' -import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial' import { getMatrixFromTf } from '@/core/ModelUtils.ts' import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' -import { translate } from 'element-plus' /** * 地堆货位渲染器 @@ -49,7 +46,7 @@ export default class GstoreRenderer extends BaseRenderer { strokeGeometry = new THREE.BoxGeometry(1, 1, 1) createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike { - return this.pointManager.createPoint(item) + return this.pointManager.createByItem(item) } createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D { @@ -137,13 +134,13 @@ export default class GstoreRenderer extends BaseRenderer { // this.strokeMaterial.dispose() } - get pointManager(): InstancePointManager { + get pointManager(): InstanceMeshManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } - return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () => + return this.tempViewport.getOrCreateMeshManager(this.itemTypeName, () => // 构建 InstanceMesh 代理对象 - InstancePointManager.create(this.itemTypeName, + new InstanceMeshManager(this.itemTypeName, this.tempViewport, this.pointGeometry, this.pointMaterial, diff --git a/src/modules/measure/MeasureRenderer.ts b/src/modules/measure/MeasureRenderer.ts index e08e5c8..083e353 100644 --- a/src/modules/measure/MeasureRenderer.ts +++ b/src/modules/measure/MeasureRenderer.ts @@ -3,9 +3,9 @@ import BaseRenderer from '@/core/base/BaseRenderer.ts' import { getLineId } from '@/core/ModelUtils.ts' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js' import Constract from '@/core/Constract.ts' -import InstancePointManager from '@/core/manager/InstancePointManager.ts' -import LineSegmentManager from '@/core/manager/LineSegmentManager.ts' -import type { Object3DLike } from '@/types/ModelTypes.ts' +import LineSegmentManager, { LineWrap } from '@/core/manager/LineSegmentManager.ts' +import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' +import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' /** * 辅助测量工具渲染器 @@ -27,29 +27,13 @@ export default class MeasureRenderer extends BaseRenderer { lineMaterial: LineMaterial = new LineMaterial({ color: 0xFF8C00, linewidth: 1, - vertexColors: false, + vertexColors: true, dashed: false }) readonly defulePositionY = Constract.HEIGHT_MEASURE readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.25, 0.25, 0.1) readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(90, 0, 0) - /** - * 所有的点,必须使用同一个尺寸, 改属性也无效 - */ - override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, object: Object3DLike) { - super.afterCreateOrUpdatePoint(item, option, object) - - const point = object - - point.scale.set(this.defaultScale.x, this.defaultScale.y, this.defaultScale.z) - point.rotation.set( - THREE.MathUtils.degToRad(this.defaultRotation.x), - THREE.MathUtils.degToRad(this.defaultRotation.y), - THREE.MathUtils.degToRad(this.defaultRotation.z) - ) - } - createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike { // 不允许改变高度/角度/大小 item.tf = [ @@ -57,15 +41,16 @@ export default class MeasureRenderer extends BaseRenderer { [this.defaultRotation.x, this.defaultRotation.y, this.defaultRotation.z], [this.defaultScale.x, this.defaultScale.y, this.defaultScale.z] ] - return this.pointManager.createPoint(item) + const lm = this.lineSegmentManager + return this.pointManager.createByItem(item) } - createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): Object3DLike { + createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): LineLike { const lineId = getLineId(start.id, end.id, type) - return this.lineSegmentManager.createLine(lineId, start.tf[0], end.tf[0], this.lineMaterial.color) + return this.lineSegmentManager.createOrUpdateLine(lineId, start.tf[0], end.tf[0], this.lineMaterial.color) } - afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: Object3DLike) { + afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: LineLike) { super.afterCreateOrUpdateLine(start, end, type, option, object) const startPoint = this.tempViewport?.entityManager.findObjectById(start.id) @@ -81,16 +66,16 @@ export default class MeasureRenderer extends BaseRenderer { afterDeleteLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption) { const lineId = getLineId(start.id, end.id, type) const object = this.tempViewport.entityManager.findLineObjectById(lineId) - this.tempViewport.labelManager.removeLabel(object) + // this.tempViewport.labelManager.removeLabel(object) } - get pointManager(): InstancePointManager { + get pointManager(): InstanceMeshManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } - return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () => + return this.tempViewport.getOrCreateMeshManager(this.itemTypeName, () => // 构建 InstanceMesh 代理对象 - InstancePointManager.create(this.itemTypeName, + new InstanceMeshManager(this.itemTypeName, this.tempViewport, this.pointGeometry, this.pointMaterial, @@ -104,9 +89,7 @@ export default class MeasureRenderer extends BaseRenderer { } return this.tempViewport.getOrCreateLineManager(this.itemTypeName, () => // 构建 LineSegment.points 代理对象 - LineSegmentManager.create(this.itemTypeName, - this.tempViewport, - this.lineMaterial) + new LineSegmentManager(this.itemTypeName, this.tempViewport, this.lineMaterial) ) } diff --git a/src/modules/pallet/PalletRenderer.ts b/src/modules/pallet/PalletRenderer.ts index dff295e..8f2385b 100644 --- a/src/modules/pallet/PalletRenderer.ts +++ b/src/modules/pallet/PalletRenderer.ts @@ -6,6 +6,7 @@ import type { Object3DLike } from '@/types/ModelTypes.ts' import MODULE_GLB_File from '@/assets/Models/Pallet.glb?url' import MODULE_3DS_TEX from '@/assets/Models/Pallet.jpg?url' import { load3DModule, loadByUrl, loadGlbModule, loadTexture, processModel } from '@/core/ModelUtils.ts' +import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' /** * 货架货位渲染器 @@ -27,7 +28,6 @@ export default class PalletRenderer extends BaseRenderer { palletMaterial: THREE.Material - init() { return Promise.all([ super.init(), @@ -53,16 +53,16 @@ export default class PalletRenderer extends BaseRenderer { } createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike { - return this.pointManager.createPoint(item) + return this.pointManager.createByItem(item) } - get pointManager(): InstancePointManager { + get pointManager(): InstanceMeshManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } - return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () => + return this.tempViewport.getOrCreateMeshManager(this.itemTypeName, () => // 构建 InstanceMesh 代理对象 - InstancePointManager.create(this.itemTypeName, + new InstanceMeshManager(this.itemTypeName, this.tempViewport, this.palletGeometry, this.palletMaterial, diff --git a/src/modules/tote/ToteRenderer.ts b/src/modules/tote/ToteRenderer.ts index 58c7682..a6e8fda 100644 --- a/src/modules/tote/ToteRenderer.ts +++ b/src/modules/tote/ToteRenderer.ts @@ -6,6 +6,7 @@ import type { Object3DLike } from '@/types/ModelTypes.ts' import MODULE_3DS_File from '@/assets/Models/Tote.3ds?url' import MODULE_3DS_TEX from '@/assets/Models/ToteTex.png?url' import { load3DModule, loadByUrl, loadTexture, processModel } from '@/core/ModelUtils.ts' +import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' /** * 货架货位渲染器 @@ -96,16 +97,16 @@ export default class PalletRenderer extends BaseRenderer { } createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike { - return this.pointManager.createPoint(item) + return this.pointManager.createByItem(item) } - get pointManager(): InstancePointManager { + get pointManager(): InstanceMeshManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } - return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () => + return this.tempViewport.getOrCreateMeshManager(this.itemTypeName, () => // 构建 InstanceMesh 代理对象 - InstancePointManager.create(this.itemTypeName, + new InstanceMeshManager(this.itemTypeName, this.tempViewport, this.toteGeometry, this.toteMaterial, diff --git a/src/modules/way/WayRenderer.ts b/src/modules/way/WayRenderer.ts index f11ad2b..df00ef4 100644 --- a/src/modules/way/WayRenderer.ts +++ b/src/modules/way/WayRenderer.ts @@ -1,7 +1,7 @@ import * as THREE from 'three' import BaseRenderer from '@/core/base/BaseRenderer.ts' import MoveLinePointPng from '@/assets/images/moveline_point.png' -import { createLinkPlaneMatrix4, getCargoLineId, getLinkDirection } from '@/core/ModelUtils.ts' +import { createLinkPlaneMatrix4, getCargoLineId, getLinkDirection, getMatrixFromTf } from '@/core/ModelUtils.ts' import Constract from '@/core/Constract.ts' import InstancePointManager from '@/core/manager/InstancePointManager.ts' import type { Object3DLike } from '@/types/ModelTypes.ts' @@ -99,7 +99,7 @@ export default class WayRenderer extends BaseRenderer { [this.defaultRotation.x, this.defaultRotation.y, this.defaultRotation.z], [this.defaultScale.x, this.defaultScale.y, this.defaultScale.z] ] - return this.pointManager.createPoint(item) + return this.pointManager.createByItem(item) } createLine(start: ItemJson, end: ItemJson, type: LinkType): Object3DLike { @@ -128,14 +128,19 @@ export default class WayRenderer extends BaseRenderer { return } - const startPosition = new THREE.Vector3(start.tf[0][0], this.defulePositionY, start.tf[0][2]) - const endPosition = new THREE.Vector3(end.tf[0][0], this.defulePositionY, end.tf[0][2]) + const startMatrix = getMatrixFromTf(start.tf) // new THREE.Vector3(start.tf[0][0], this.defulePositionY, start.tf[0][2]) + const endMatrix = getMatrixFromTf(end.tf) // new THREE.Vector3(end.tf[0][0], this.defulePositionY, end.tf[0][2]) + const startPosition = new THREE.Vector3() + const endPosition = new THREE.Vector3() + + startMatrix.decompose(startPosition, new THREE.Quaternion(), new THREE.Vector3()) + endMatrix.decompose(endPosition, new THREE.Quaternion(), new THREE.Vector3()) + const wrap = this.guidewayManager.create(lineId, {}) wrap.uuid = lineId const matrix = createLinkPlaneMatrix4(startPosition, endPosition, this.rendererOption.lineWidth) wrap.setMatrix4(matrix) - const length = startPosition.distanceTo(endPosition) if (length < 0.1) { // 如果两点距离小于 0.1m,则不添加方向指示器 @@ -322,13 +327,13 @@ export default class WayRenderer extends BaseRenderer { }) } - get pointManager(): InstancePointManager { + get pointManager(): InstanceMeshManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } - return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () => + return this.tempViewport.getOrCreateMeshManager(this.itemTypeName, () => // 构建 InstanceMesh 代理对象 - InstancePointManager.create(this.itemTypeName, + new InstanceMeshManager(this.itemTypeName, this.tempViewport, this.pointGeometry, this.pointMaterial, diff --git a/src/runtime/EventBus.ts b/src/runtime/EventBus.ts index 815e664..5f488d2 100644 --- a/src/runtime/EventBus.ts +++ b/src/runtime/EventBus.ts @@ -3,7 +3,6 @@ import mitt from 'mitt' const instance = mitt() export type DispatchNames = 'selectedObjectChanged' | - 'catalogChanged' | 'dataLoadComplete' | 'selectedObjectPropertyChanged' | 'multiSelectedObjectsChanged' diff --git a/src/runtime/System.ts b/src/runtime/System.ts index a87f0c0..dc6c16b 100644 --- a/src/runtime/System.ts +++ b/src/runtime/System.ts @@ -250,8 +250,6 @@ export default class System { const _insId = _.uniqueId('_dlg') - console.trace() - console.time('showLoading') system.rootElementList.push({ cmp: markRaw(LoadingDialog), props: { @@ -269,7 +267,6 @@ export default class System { * 关闭 “正在载入...” 对话框 */ public clearLoading(): void { - console.timeEnd('showLoading') if (typeof this.globalLoadingHandle === 'function') { this.globalLoadingHandle() } diff --git a/src/types/ModelTypes.ts b/src/types/ModelTypes.ts index 2e2a70d..2aeb39e 100644 --- a/src/types/ModelTypes.ts +++ b/src/types/ModelTypes.ts @@ -1,8 +1,7 @@ import { Object3D } from 'three' -import LineSegmentManager, { LineManageWrap } from '@/core/manager/LineSegmentManager.ts' -import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts' import * as THREE from 'three' -import { InstanceMeshWrap } from '@/core/manager/InstanceMeshManager.ts' +import { MeshWrap } from '@/core/manager/InstanceMeshManager.ts' +import type { LineWrap } from '@/core/manager/LineSegmentManager.ts' // // /** // * 点数据接口, 用于平衡 Object3D 一致的取数方式 @@ -57,17 +56,9 @@ export const BasePlane = { } } -export interface LineManageReference { - manager: LineSegmentManager - id: string -} - -export interface PointManagerReference { - manager: InstancePointManager - id: string -} +export type Object3DLike = Object3D | MeshWrap -export type Object3DLike = Object3D | PointManageWrap | InstanceMeshWrap +export type LineLike = Object3D | LineWrap /** * 坐标的范指型, 可以是 THREE.Vector3 或者三元数组 diff --git a/src/types/Types.d.ts b/src/types/Types.d.ts index 4eb456d..d6d043f 100644 --- a/src/types/Types.d.ts +++ b/src/types/Types.d.ts @@ -19,14 +19,14 @@ interface VData { items: ItemJson[] /** - * 是否发生了变化,通知外部是否需要保存数据 + * 楼层的其他数据 */ - isChanged: boolean + infos: any /** - * 对应存储id + * 是否发生了变化,通知外部是否需要保存数据 */ - id: string + isChanged: boolean /** * 所有地图目录 @@ -41,12 +41,17 @@ interface VData { /** * 项目ID */ - projectId?: string + project_uuid?: string /** * 当前楼层代码 */ catalogCode: string + + /** + * 世界模型公共数据 + */ + worldData: any } interface CatalogItem {