From b82b68fba17d3c98a96420b55dc15c47a3363fbb Mon Sep 17 00:00:00 2001 From: luoyifan Date: Wed, 4 Jun 2025 15:06:56 +0800 Subject: [PATCH 1/3] gstore --- src/core/Constract.ts | 2 +- src/core/base/BaseInteraction.ts | 85 +++++++++++----- src/core/manager/WorldModel.ts | 4 +- src/editor/Model2DEditor.vue | 9 +- src/modules/gstore/GstoreEntity.ts | 5 + src/modules/gstore/GstoreInteraction.ts | 22 +++++ src/modules/gstore/GstoreMeta.ts | 14 +++ src/modules/gstore/GstoreRenderer.ts | 167 ++++++++++++++++++++++++++++++++ src/modules/gstore/index.ts | 15 +++ src/modules/measure/MeasureRenderer.ts | 2 +- 10 files changed, 298 insertions(+), 27 deletions(-) create mode 100644 src/modules/gstore/GstoreEntity.ts create mode 100644 src/modules/gstore/GstoreInteraction.ts create mode 100644 src/modules/gstore/GstoreMeta.ts create mode 100644 src/modules/gstore/GstoreRenderer.ts create mode 100644 src/modules/gstore/index.ts diff --git a/src/core/Constract.ts b/src/core/Constract.ts index a957ae6..b97c525 100644 --- a/src/core/Constract.ts +++ b/src/core/Constract.ts @@ -12,8 +12,8 @@ export default Object.freeze({ // 测量相关的光标模式 CursorModeMeasure: 'measure', - CursorModeWay: 'way', + CursorModeGstore: 'gstore', // 选择模式 CursorModeSelectByRec: 'selectByRec' diff --git a/src/core/base/BaseInteraction.ts b/src/core/base/BaseInteraction.ts index 05a4dc5..9255dfc 100644 --- a/src/core/base/BaseInteraction.ts +++ b/src/core/base/BaseInteraction.ts @@ -54,10 +54,41 @@ export default abstract class BaseInteraction { alphaToCoverage: true }) + /** + * 物品是否"单点", 不允许连线 + */ + get isSinglePointMode(): boolean { + return false + } + constructor(itemTypeName: string) { this.itemTypeName = itemTypeName } + createPointOfItem(catchPoint: ItemJson, point: THREE.Vector3): ItemJson { + const renderer = getRenderer(this.itemTypeName) + + const defaultScale = renderer.defaultScale + const defaultRotation = renderer.defaultRotation + + _.extend(catchPoint, { + id: system.createUUID(), + t: this.itemTypeName, + v: true, + tf: [ + [point.x, point.y, point.z], + [defaultRotation.x, defaultRotation.y, defaultRotation.z], + [defaultScale.x, defaultScale.y, defaultScale.z] + ], + dt: { + in: [] as string[], + out: [] as string[], + center: [] as string[] + } + }) + return catchPoint + } + /** * 拖拽点开始 */ @@ -125,7 +156,14 @@ export default abstract class BaseInteraction { } if (this.linkStartPointId) { - this.linkStartPointObject = this.viewport.entityManager.findObjectsById(this.linkStartPointId)?.[0] + if (this.isSinglePointMode) { + // 单点模式不需要起始点 + this.linkStartPointId = undefined + this.linkStartPointObject = undefined + + } else { + this.linkStartPointObject = this.viewport.entityManager.findObjectsById(this.linkStartPointId)?.[0] + } } pdFn = this.mousedown.bind(this) @@ -266,9 +304,29 @@ export default abstract class BaseInteraction { } this.lastClickTime = now + // 如果正式的点命中到同类型的节点上,则不添加新的点,只牵线到该点 let catchPoint: ItemJson | null = this.viewport.stateManager.findItemByPosition(point, this.itemTypeName) + + if (this.isSinglePointMode) { + // 单点模式,直接添加点 + if (catchPoint) { + // 如果已经有点了,则不再添加 + system.msg('Point already exists at this position.') + return + } + + // 则添加一个新的点 + const stateManager = this.viewport.stateManager + stateManager.beginStateUpdate({ createFromInteraction: true }) + catchPoint = {} as ItemJson + catchPoint = this.createPointOfItem(catchPoint, point) + stateManager.vdata.items.push(catchPoint) + stateManager.endStateUpdate() + return + } + let from: ItemJson | undefined = undefined if (this.linkStartPointId) { from = this.viewport.stateManager.findItemById(this.linkStartPointId) @@ -300,28 +358,9 @@ export default abstract class BaseInteraction { stateManager.endStateUpdate() } else { - const renderer = getRenderer(this.itemTypeName) - - const defaultScale = renderer.defaultScale - const defaultRotation = renderer.defaultRotation - // 添加正式点 - catchPoint = { - id: system.createUUID(), - t: this.itemTypeName, - v: true, - tf: [ - [point.x, point.y, point.z], - [defaultRotation.x, defaultRotation.y, defaultRotation.z], - [defaultScale.x, defaultScale.y, defaultScale.z] - ], - dt: { - in: [] as string[], - out: [] as string[], - center: [] as string[] - } - } as ItemJson - + catchPoint = {} as ItemJson + catchPoint = this.createPointOfItem(catchPoint, point) // 提交状态管理器 const stateManager = this.viewport.stateManager @@ -396,6 +435,8 @@ export default abstract class BaseInteraction { const obj = new CSS2DObject(div) return obj } + + } export interface DragOption { diff --git a/src/core/manager/WorldModel.ts b/src/core/manager/WorldModel.ts index 446fd8b..8b6f429 100644 --- a/src/core/manager/WorldModel.ts +++ b/src/core/manager/WorldModel.ts @@ -3,6 +3,7 @@ import { reactive, watch } from 'vue' import EventBus from '@/runtime/EventBus' import Measure from '@/modules/measure' import Way from '@/modules/way' +import Gstore from '@/modules/gstore' import StateManager from '@/core/manager/StateManager.ts' export interface WorldModelState { @@ -62,7 +63,8 @@ export default class WorldModel { return Promise.all([ Measure, - Way + Way, + Gstore ]).then(() => { console.log('世界模型初始化完成') diff --git a/src/editor/Model2DEditor.vue b/src/editor/Model2DEditor.vue index 527b932..364a4fd 100644 --- a/src/editor/Model2DEditor.vue +++ b/src/editor/Model2DEditor.vue @@ -32,13 +32,18 @@ :type="state?.cursorMode===Constract.CursorModeSLink?'primary':''" @click="()=>state.cursorMode = Constract.CursorModeSLink"> - - + + +
((resolve, reject) => { + new THREE.TextureLoader().load( + MoveLinePointPng, + (texture) => { + this.pointMaterial = new THREE.SpriteMaterial({ + map: texture, + transparent: true, + side: THREE.DoubleSide + }) + resolve() + }, + undefined, + function(err) { + reject(err) + } + ) + }) + } + + /** + * 所有的点,必须使用同一个尺寸, 改属性也无效 + */ + override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, objects: THREE.Object3D[]) { + super.afterCreateOrUpdatePoint(item, option, objects) + + const point = objects[0] + point.position.y = this.defulePositionY + 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) + ) + } + + + createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D[] { + const group = new THREE.Group() + const startPosition = new THREE.Vector3(start.tf[0][0], 0.01, start.tf[0][2]) + const endPosition = new THREE.Vector3(end.tf[0][0], 0.01, end.tf[0][2]) + const width = 1 + + const curve = new THREE.LineCurve3(startPosition, endPosition) + const tubeGeometry = new THREE.TubeGeometry(curve, 1, width / 2, 8, false) + const lineMesh = new THREE.Mesh(tubeGeometry, this.lineMaterial) + group.add(lineMesh) + + + const midPoint = new THREE.Vector3() + .addVectors(startPosition, endPosition) + .multiplyScalar(0.5) + + const distance = (startPosition.distanceTo(endPosition) * 1000).toFixed(0) + + const label = new Text() + label.text = distance + label.font = SimSunTTF + label.fontSize = 0.2 + label.color = '#5f5f5f' + label.opacity = 0.8 + label.anchorX = 'center' + label.anchorY = 'middle' + label.depthOffset = 1 + label.material.depthTest = false + label.name = GstoreRenderer.LABEL_NAME + label.quaternion.copy(this.tempViewport.camera.quaternion) + label.sync() + label.position.set(midPoint.x, midPoint.y, midPoint.z) + + group.add(label) + + return [group] + } + + updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { + super.updateLine(start, end, type, option) + + const startPosition = new THREE.Vector3(start.tf[0][0], 0.01, start.tf[0][2]) + const endPosition = new THREE.Vector3(end.tf[0][0], 0.01, end.tf[0][2]) + const width = 1 + + const lineId = getLineId(start.id, end.id, type) + const lines = this.tempViewport.entityManager.findLineObjectsById(lineId) + const group: THREE.Group = lines[0] as THREE.Group + + // 清空group里的元素 + const label: Text = group.children[1] + group.clear() + + const curve = new THREE.LineCurve3(startPosition, endPosition) + const tubeGeometry = new THREE.TubeGeometry(curve, 1, width / 2, 8, false) + const lineMesh = new THREE.Mesh(tubeGeometry, this.lineMaterial) + group.add(lineMesh) + + const midPoint = new THREE.Vector3() + .addVectors(startPosition, endPosition) + .multiplyScalar(0.5) + + const distance = (startPosition.distanceTo(endPosition) * 1000).toFixed(0) + label.text = distance + label.quaternion.copy(this.tempViewport.camera.quaternion) + label.sync() + label.position.set(midPoint.x, midPoint.y, midPoint.z) + group.add(label) + } + + createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] { + const obj = new THREE.Sprite(this.pointMaterial as THREE.SpriteMaterial) + obj.name = GstoreRenderer.POINT_NAME + return [obj] + } + + appendToScene(...objects: THREE.Object3D[]) { + const dragObjects = objects.filter(obj => !!obj.userData.draggable) + this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') + // this.tempViewport.dragControl.setDragObjects(objects, 'remove') + + this.tempViewport?.scene.add(...objects) + } + + dispose() { + super.dispose() + this.pointMaterial.dispose() + this.lineMaterial.dispose() + } +} \ No newline at end of file diff --git a/src/modules/gstore/index.ts b/src/modules/gstore/index.ts new file mode 100644 index 0000000..bbaefd9 --- /dev/null +++ b/src/modules/gstore/index.ts @@ -0,0 +1,15 @@ +import { defineModule } from '@/core/manager/ModuleManager.ts' +import GstoreRenderer from './GstoreRenderer.ts' +import GstoreEntity from './GstoreEntity.ts' +import GstoreMeta from './GstoreMeta.ts' +import GstoreInteraction from './GstoreInteraction.ts' + +export const ITEM_TYPE_NAME = 'gstore' + +export default defineModule({ + name: ITEM_TYPE_NAME, + renderer: new GstoreRenderer(ITEM_TYPE_NAME), + interaction: new GstoreInteraction(ITEM_TYPE_NAME), + meta: GstoreMeta, + entity: GstoreEntity +}) \ No newline at end of file diff --git a/src/modules/measure/MeasureRenderer.ts b/src/modules/measure/MeasureRenderer.ts index 7034b9a..f4f01b9 100644 --- a/src/modules/measure/MeasureRenderer.ts +++ b/src/modules/measure/MeasureRenderer.ts @@ -29,7 +29,7 @@ export default class MeasureRenderer extends BaseRenderer { lineMaterial: LineMaterial readonly defulePositionY = 0.01 - readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.25, 0.25, 0.1) + readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.1, 0.1, 0.1) readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(90, 0, 0) constructor(itemTypeName: string) { From a4668a619cb00adb4739490f6cf6b9da4262f37c Mon Sep 17 00:00:00 2001 From: luoyifan Date: Wed, 4 Jun 2025 15:32:33 +0800 Subject: [PATCH 2/3] gstore --- src/modules/gstore/GstoreInteraction.ts | 4 +- src/modules/gstore/GstoreRenderer.ts | 113 ++------------------------------ 2 files changed, 6 insertions(+), 111 deletions(-) diff --git a/src/modules/gstore/GstoreInteraction.ts b/src/modules/gstore/GstoreInteraction.ts index 56efc2c..2979e4a 100644 --- a/src/modules/gstore/GstoreInteraction.ts +++ b/src/modules/gstore/GstoreInteraction.ts @@ -15,8 +15,8 @@ export default class GstoreInteraction extends BaseInteraction { item = super.createPointOfItem(item, point) // 创建一个地堆货架 - item.dt.rackWidth = 1.2 // 宽度 - item.dt.rackDepth = 1.2 // 深度 + item.dt.storeWidth = 1.2 // 宽度 + item.dt.storeDepth = 1.2 // 深度 return item } } \ No newline at end of file diff --git a/src/modules/gstore/GstoreRenderer.ts b/src/modules/gstore/GstoreRenderer.ts index 3f50912..789b311 100644 --- a/src/modules/gstore/GstoreRenderer.ts +++ b/src/modules/gstore/GstoreRenderer.ts @@ -9,16 +9,9 @@ import { getLineId } from '@/core/ModelUtils.ts' * 辅助测量工具渲染器 */ export default class GstoreRenderer extends BaseRenderer { - static LABEL_NAME = 'way_label' static POINT_NAME = 'way_point' pointMaterial: THREE.Material - lineMaterial = new THREE.MeshBasicMaterial({ - color: 0xa0cfff, - transparent: true, - opacity: 0.2, - side: THREE.DoubleSide - }) /** * 默认点的高度, 防止和地面重合 @@ -31,42 +24,15 @@ export default class GstoreRenderer extends BaseRenderer { super(itemTypeName) } - async init() { - return Promise.all([ - super.init(), - this.loadFont() - ]) - } - - async loadFont() { - return new Promise((resolve, reject) => { - new THREE.TextureLoader().load( - MoveLinePointPng, - (texture) => { - this.pointMaterial = new THREE.SpriteMaterial({ - map: texture, - transparent: true, - side: THREE.DoubleSide - }) - resolve() - }, - undefined, - function(err) { - reject(err) - } - ) - }) - } - /** - * 所有的点,必须使用同一个尺寸, 改属性也无效 + * 所有的点,必须使用 storeWidth/storeDepth, 改TF无效 */ override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, objects: THREE.Object3D[]) { super.afterCreateOrUpdatePoint(item, option, objects) const point = objects[0] point.position.y = this.defulePositionY - point.scale.set(this.defaultScale.x, this.defaultScale.y, this.defaultScale.z) + point.scale.set(item.dt.storeWidth, this.defaultScale.y, item.dt.storeDepth) point.rotation.set( THREE.MathUtils.degToRad(this.defaultRotation.x), THREE.MathUtils.degToRad(this.defaultRotation.y), @@ -76,73 +42,11 @@ export default class GstoreRenderer extends BaseRenderer { createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D[] { - const group = new THREE.Group() - const startPosition = new THREE.Vector3(start.tf[0][0], 0.01, start.tf[0][2]) - const endPosition = new THREE.Vector3(end.tf[0][0], 0.01, end.tf[0][2]) - const width = 1 - - const curve = new THREE.LineCurve3(startPosition, endPosition) - const tubeGeometry = new THREE.TubeGeometry(curve, 1, width / 2, 8, false) - const lineMesh = new THREE.Mesh(tubeGeometry, this.lineMaterial) - group.add(lineMesh) - - - const midPoint = new THREE.Vector3() - .addVectors(startPosition, endPosition) - .multiplyScalar(0.5) - - const distance = (startPosition.distanceTo(endPosition) * 1000).toFixed(0) - - const label = new Text() - label.text = distance - label.font = SimSunTTF - label.fontSize = 0.2 - label.color = '#5f5f5f' - label.opacity = 0.8 - label.anchorX = 'center' - label.anchorY = 'middle' - label.depthOffset = 1 - label.material.depthTest = false - label.name = GstoreRenderer.LABEL_NAME - label.quaternion.copy(this.tempViewport.camera.quaternion) - label.sync() - label.position.set(midPoint.x, midPoint.y, midPoint.z) - - group.add(label) - - return [group] + throw new Error('not allow store line.') } updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { - super.updateLine(start, end, type, option) - - const startPosition = new THREE.Vector3(start.tf[0][0], 0.01, start.tf[0][2]) - const endPosition = new THREE.Vector3(end.tf[0][0], 0.01, end.tf[0][2]) - const width = 1 - - const lineId = getLineId(start.id, end.id, type) - const lines = this.tempViewport.entityManager.findLineObjectsById(lineId) - const group: THREE.Group = lines[0] as THREE.Group - - // 清空group里的元素 - const label: Text = group.children[1] - group.clear() - - const curve = new THREE.LineCurve3(startPosition, endPosition) - const tubeGeometry = new THREE.TubeGeometry(curve, 1, width / 2, 8, false) - const lineMesh = new THREE.Mesh(tubeGeometry, this.lineMaterial) - group.add(lineMesh) - - const midPoint = new THREE.Vector3() - .addVectors(startPosition, endPosition) - .multiplyScalar(0.5) - - const distance = (startPosition.distanceTo(endPosition) * 1000).toFixed(0) - label.text = distance - label.quaternion.copy(this.tempViewport.camera.quaternion) - label.sync() - label.position.set(midPoint.x, midPoint.y, midPoint.z) - group.add(label) + throw new Error('not allow store line.') } createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] { @@ -151,17 +55,8 @@ export default class GstoreRenderer extends BaseRenderer { return [obj] } - appendToScene(...objects: THREE.Object3D[]) { - const dragObjects = objects.filter(obj => !!obj.userData.draggable) - this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') - // this.tempViewport.dragControl.setDragObjects(objects, 'remove') - - this.tempViewport?.scene.add(...objects) - } - dispose() { super.dispose() this.pointMaterial.dispose() - this.lineMaterial.dispose() } } \ No newline at end of file From 86a11f09fe4afeb0b659bbbd586db1071dd7ecdc Mon Sep 17 00:00:00 2001 From: luoyifan Date: Wed, 4 Jun 2025 15:34:42 +0800 Subject: [PATCH 3/3] gstore --- src/example/example1.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/example/example1.js b/src/example/example1.js index 1e3358f..1d63ce4 100644 --- a/src/example/example1.js +++ b/src/example/example1.js @@ -112,6 +112,18 @@ export default { v: true, tf: [[5, 0.1, 2], [90, 0, 0], [0.25, 0.25, 0.1]], dt: { in: [], out: [], center: ['39zML1rnSOOQGQYQ2YUMGy'] } + }, { + id: '6UhIIw9QPYh6acwyW8OSGs', + t: 'gstore', + v: true, + tf: [[-1, 0.1, 0.75], [0, 0, 0], [1.5, 1.2, 0.1]], + dt: { in: [], out: [], center: [], storeWidth: 1.2, storeDepth: 1.2 } + }, { + id: '1D0WSRPj8JJJwIcmA0UMqG', + t: 'gstore', + v: true, + tf: [[0.75, 0.1, 0.75], [0, 0, 0], [1.5, 1.2, 0.1]], + dt: { in: [], out: [], center: [], storeWidth: 1.2, storeDepth: 1.2 } } ] }