From 64e6741db8b03a27ff2b3b16dd57fe7b229737b3 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Tue, 27 May 2025 21:58:05 +0800 Subject: [PATCH] =?UTF-8?q?Conveyor=20=E8=BE=93=E9=80=81=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/designer/Constract.ts | 2 + src/designer/Viewport.ts | 5 +- src/designer/model2DEditor/Model2DEditor.vue | 4 + src/model/ModelUtils.ts | 154 +++++++++++---------- src/model/WorldModel.ts | 4 +- src/model/itemType/Toolbox.ts | 1 - src/model/itemType/line/conveyor/Conveyor.ts | 82 +++++++++++ src/model/itemType/line/conveyor/ConveyorMeta.ts | 9 ++ .../itemType/line/conveyor/ConveyorToolbox.ts | 16 +++ 9 files changed, 199 insertions(+), 78 deletions(-) create mode 100644 src/model/itemType/line/conveyor/Conveyor.ts create mode 100644 src/model/itemType/line/conveyor/ConveyorMeta.ts create mode 100644 src/model/itemType/line/conveyor/ConveyorToolbox.ts diff --git a/src/designer/Constract.ts b/src/designer/Constract.ts index 8a10162..afd4a7e 100644 --- a/src/designer/Constract.ts +++ b/src/designer/Constract.ts @@ -13,6 +13,8 @@ export default Object.freeze({ // 测量相关的光标模式 CursorModeMeasure: 'measure', + CursorModeConveyor: 'conveyor', + // 选择模式 CursorModeSelectByRec: 'selectByRec' }) \ No newline at end of file diff --git a/src/designer/Viewport.ts b/src/designer/Viewport.ts index f58d2bd..8c742b4 100644 --- a/src/designer/Viewport.ts +++ b/src/designer/Viewport.ts @@ -33,6 +33,8 @@ export default class Viewport { dragControl: EsDragControls animationFrameId: any = null + //搭配 state.cursorMode = xxx 之后, currentTool.start(第一个参数) 使用 + toolStartObject: THREE.Object3D | null = null currentTool: Toolbox | null = null tools: ITool[] = [ new MouseMoveInspect() @@ -223,7 +225,8 @@ export default class Viewport { } if (this.currentTool) { - this.currentTool.start() + this.currentTool.start(this.toolStartObject) + this.toolStartObject = null } })) diff --git a/src/designer/model2DEditor/Model2DEditor.vue b/src/designer/model2DEditor/Model2DEditor.vue index c4c5999..44dfac4 100644 --- a/src/designer/model2DEditor/Model2DEditor.vue +++ b/src/designer/model2DEditor/Model2DEditor.vue @@ -37,6 +37,10 @@ + +
{ // 判断 object 是否是有效的 Object3D, 并且是当前 viewport 的对象 @@ -40,76 +42,78 @@ export function quickCopyByMouse() { const distance = object.position.distanceTo(new THREE.Vector3(x, 0, z)) if (distance < 0.2) { // 找到一个有效点,执行复制操作 - toolbox.start(object) - system.msg('复制成功') + viewport.toolStartObject = object + viewport.state.cursorMode = object.userData.type + // toolbox.start(object) + system.msg('连线成功') return true } } return false }) - */ -} - -/** - * 查找射线周围指定半径内的对象 - */ -export function findObjectsInRadius(viewport: Viewport, - point: THREE.Vector2, - radius: number, - lines: { object: THREE.Object3D, distance: number }[], - points: { object: THREE.Object3D, distance: number }[] -): void { - const ray = new THREE.Raycaster() - ray.setFromCamera(point, viewport.camera) - - viewport.dragControl._dragObjects.forEach(obj => { - if (obj instanceof THREE.Points) { - // 处理点云:遍历每个点 - const distance = distanceToRay(ray, point) - if (distance <= radius) { - points.push({ object: obj, distance }) - } - - } else if (obj instanceof THREE.Line) { - // 处理线段:计算线段到射线的最近距离 - const distance = getLineDistanceToRay(ray, obj) - if (distance <= radius) { - lines.push({ object: obj, distance }) - } - } - }) -} - -/** - * 计算点到射线的最短距离 - */ -function distanceToRay(ray: THREE.Raycaster, point: THREE.Vector2) { - const closestPoint = new THREE.Vector3() - ray.closestPointToPoint(point, closestPoint) - return point.distanceTo(closestPoint) } -/** - * 计算线段到射线的最短距离 - */ -function getLineDistanceToRay(ray: THREE.Raycaster, line: THREE.Line) { - const lineStart = new THREE.Vector3() - const lineEnd = new THREE.Vector3() - line.geometry.attributes.position.getXYZ(0, lineStart) - line.geometry.attributes.position.getXYZ(1, lineEnd) - line.localToWorld(lineStart) - line.localToWorld(lineEnd) - - const lineSegment = new THREE.Line3(lineStart, lineEnd) - const closestOnRay = new THREE.Vector3() - const closestOnLine = new THREE.Vector3() - THREE.Line3.prototype.closestPointsRayLine ??= function(ray, line, closestOnRay, closestOnLine) { - // 实现射线与线段最近点计算(需自定义或使用数学库) - } - - lineSegment.closestPointsRayLine(ray, true, closestOnRay, closestOnLine) - return closestOnRay.distanceTo(closestOnLine) -} +// +// /** +// * 查找射线周围指定半径内的对象 +// */ +// export function findObjectsInRadius(viewport: Viewport, +// point: THREE.Vector2, +// radius: number, +// lines: { object: THREE.Object3D, distance: number }[], +// points: { object: THREE.Object3D, distance: number }[] +// ): void { +// const ray = new THREE.Raycaster() +// ray.setFromCamera(point, viewport.camera) +// +// viewport.dragControl._dragObjects.forEach(obj => { +// if (obj instanceof THREE.Points) { +// // 处理点云:遍历每个点 +// const distance = distanceToRay(ray, point) +// if (distance <= radius) { +// points.push({ object: obj, distance }) +// } +// +// } else if (obj instanceof THREE.Line) { +// // 处理线段:计算线段到射线的最近距离 +// const distance = getLineDistanceToRay(ray, obj) +// if (distance <= radius) { +// lines.push({ object: obj, distance }) +// } +// } +// }) +// } +// +// /** +// * 计算点到射线的最短距离 +// */ +// function distanceToRay(ray: THREE.Raycaster, point: THREE.Vector2) { +// const closestPoint = new THREE.Vector3() +// ray.closestPointToPoint(point, closestPoint) +// return point.distanceTo(closestPoint) +// } +// +// /** +// * 计算线段到射线的最短距离 +// */ +// function getLineDistanceToRay(ray: THREE.Raycaster, line: THREE.Line) { +// const lineStart = new THREE.Vector3() +// const lineEnd = new THREE.Vector3() +// line.geometry.attributes.position.getXYZ(0, lineStart) +// line.geometry.attributes.position.getXYZ(1, lineEnd) +// line.localToWorld(lineStart) +// line.localToWorld(lineEnd) +// +// const lineSegment = new THREE.Line3(lineStart, lineEnd) +// const closestOnRay = new THREE.Vector3() +// const closestOnLine = new THREE.Vector3() +// THREE.Line3.prototype.closestPointsRayLine ??= function(ray, line, closestOnRay, closestOnLine) { +// // 实现射线与线段最近点计算(需自定义或使用数学库) +// } +// +// lineSegment.closestPointsRayLine(ray, true, closestOnRay, closestOnLine) +// return closestOnRay.distanceTo(closestOnLine) +// } /** * 考虑吸附的情况下计算鼠标事件位置 diff --git a/src/model/WorldModel.ts b/src/model/WorldModel.ts index 11829a8..86a2d72 100644 --- a/src/model/WorldModel.ts +++ b/src/model/WorldModel.ts @@ -7,6 +7,7 @@ import type Viewport from '@/designer/Viewport.ts' import { loadSceneFromJson } from '@/model/ModelUtils.ts' import MeasureMeta from './itemType/measure/MeasureMeta' +import ConveyorMeta from './itemType/line/conveyor/ConveyorMeta' import type { IGridHelper } from '@/model/WorldModelType.ts' /** @@ -53,7 +54,8 @@ export default class WorldModel { init() { return Promise.all([ - MeasureMeta.clazz.init(this) + MeasureMeta.clazz.init(this), + ConveyorMeta.clazz.init(this) ]).then(() => { console.log('世界模型初始化完成') diff --git a/src/model/itemType/Toolbox.ts b/src/model/itemType/Toolbox.ts index 4e59f07..96d217f 100644 --- a/src/model/itemType/Toolbox.ts +++ b/src/model/itemType/Toolbox.ts @@ -218,7 +218,6 @@ export default abstract class Toolbox { if (e.button === 2) { // 右键点击, 完成绘图操作 this.viewport.state.cursorMode = 'normal' - this.stop() } else if (e.button === 0) { // 左键点击, 添加点 diff --git a/src/model/itemType/line/conveyor/Conveyor.ts b/src/model/itemType/line/conveyor/Conveyor.ts new file mode 100644 index 0000000..d631c8a --- /dev/null +++ b/src/model/itemType/line/conveyor/Conveyor.ts @@ -0,0 +1,82 @@ +import * as THREE from 'three' +import { Material } from 'three' +import ItemTypeLine from '@/model/itemType/ItemTypeLine.ts' +import WorldModel from '@/model/WorldModel.ts' +import Viewport from '@/designer/Viewport.ts' +import ToolboxLine from '@/model/itemType/ToolboxLine.ts' +import ConveyorToolbox from './ConveyorToolbox.ts' +import { Line2 } from 'three/examples/jsm/lines/Line2.js' +import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js' +import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js' + +export default class Conveyor extends ItemTypeLine { + defaultScale: THREE.Vector3 = new THREE.Vector3(0.25, 0.1, 0.25) + defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0) + + pointMaterial!: Material + + lineMaterial!: LineMaterial + + static POINT_NAME = 'conveyor_point' + static LINE_NAME = 'conveyor_line' + + override init(worldModel: WorldModel): Promise { + super.init(worldModel) + + this.lineMaterial = new LineMaterial({ + color: 0xE63C17, // 主颜色 + linewidth: 2, // 实际可用的线宽 + vertexColors: true, // 启用顶点颜色 + dashed: false, + alphaToCoverage: true + }) + + this.pointMaterial = new THREE.MeshBasicMaterial({ color: 0x303133, transparent: true, opacity: 0.9 }) + + return Promise.resolve() + } + + getDefaultScale(): THREE.Vector3 { + return this.defaultScale + } + + getDefaultRotation(): THREE.Vector3 { + return this.defaultRotation + } + + createToolbox(viewport: Viewport): ToolboxLine { + const toolbox = new ConveyorToolbox() + toolbox.init(viewport, this) + //@ts-ignore + return toolbox + } + + /** + * 创建测量点 + */ + createPointBasic(position?: THREE.Vector3): THREE.Object3D { + const p = position + const scale = 0.25 + + const tt = new THREE.BoxGeometry(1, 1, 1) + const obj = new THREE.Mesh(tt, this.pointMaterial) + obj.scale.set(scale, 0.1, scale) + if (p) { + obj.position.set(p.x, p.y, p.z) + } + obj.name = Conveyor.POINT_NAME + return obj + } + + /** + * 创建测量线 + */ + createLineBasic(): Line2 { + const geom = new LineGeometry() + const obj = new Line2(geom, this.lineMaterial) + obj.frustumCulled = false + obj.name = Conveyor.LINE_NAME + obj.uuid = THREE.MathUtils.generateUUID() + return obj + } +} \ No newline at end of file diff --git a/src/model/itemType/line/conveyor/ConveyorMeta.ts b/src/model/itemType/line/conveyor/ConveyorMeta.ts new file mode 100644 index 0000000..f5f600b --- /dev/null +++ b/src/model/itemType/line/conveyor/ConveyorMeta.ts @@ -0,0 +1,9 @@ +import { defineItemType } from '@/runtime/DefineItemType.ts' +import Conveyor from './Conveyor.ts' + +export default defineItemType({ + name: 'conveyor', + label: '输送线', + actionType: 'ln', + clazz: new Conveyor() +}) \ No newline at end of file diff --git a/src/model/itemType/line/conveyor/ConveyorToolbox.ts b/src/model/itemType/line/conveyor/ConveyorToolbox.ts new file mode 100644 index 0000000..1e62d44 --- /dev/null +++ b/src/model/itemType/line/conveyor/ConveyorToolbox.ts @@ -0,0 +1,16 @@ +import ToolboxLine from '@/model/itemType/ToolboxLine.ts' +import type Conveyor from './Conveyor.ts' + +/** + * 测量工具箱,用于处理测量相关的操作 + */ +export default class ConveyorToolbox extends ToolboxLine { + + constructor() { + super() + } + + get conveyor(): Conveyor { + return this._itemType + } +} \ No newline at end of file