Browse Source

Conveyor 输送线

master
修宁 7 months ago
parent
commit
64e6741db8
  1. 2
      src/designer/Constract.ts
  2. 5
      src/designer/Viewport.ts
  3. 4
      src/designer/model2DEditor/Model2DEditor.vue
  4. 154
      src/model/ModelUtils.ts
  5. 4
      src/model/WorldModel.ts
  6. 1
      src/model/itemType/Toolbox.ts
  7. 82
      src/model/itemType/line/conveyor/Conveyor.ts
  8. 9
      src/model/itemType/line/conveyor/ConveyorMeta.ts
  9. 16
      src/model/itemType/line/conveyor/ConveyorToolbox.ts

2
src/designer/Constract.ts

@ -13,6 +13,8 @@ export default Object.freeze({
// 测量相关的光标模式 // 测量相关的光标模式
CursorModeMeasure: 'measure', CursorModeMeasure: 'measure',
CursorModeConveyor: 'conveyor',
// 选择模式 // 选择模式
CursorModeSelectByRec: 'selectByRec' CursorModeSelectByRec: 'selectByRec'
}) })

5
src/designer/Viewport.ts

@ -33,6 +33,8 @@ export default class Viewport {
dragControl: EsDragControls dragControl: EsDragControls
animationFrameId: any = null animationFrameId: any = null
//搭配 state.cursorMode = xxx 之后, currentTool.start(第一个参数) 使用
toolStartObject: THREE.Object3D | null = null
currentTool: Toolbox | null = null currentTool: Toolbox | null = null
tools: ITool[] = [ tools: ITool[] = [
new MouseMoveInspect() new MouseMoveInspect()
@ -223,7 +225,8 @@ export default class Viewport {
} }
if (this.currentTool) { if (this.currentTool) {
this.currentTool.start() this.currentTool.start(this.toolStartObject)
this.toolStartObject = null
} }
})) }))

4
src/designer/model2DEditor/Model2DEditor.vue

@ -37,6 +37,10 @@
<el-button title="测量工具" :icon="renderIcon('fa Ruler')" link <el-button title="测量工具" :icon="renderIcon('fa Ruler')" link
:type="state.cursorMode===Constract.CursorModeMeasure?'primary':''" :type="state.cursorMode===Constract.CursorModeMeasure?'primary':''"
@click="()=>state.cursorMode = Constract.CursorModeMeasure"></el-button> @click="()=>state.cursorMode = Constract.CursorModeMeasure"></el-button>
<span class="section-toolbar-line"></span>
<el-button title="输送线" :icon="renderIcon('fa Line')" link
:type="state.cursorMode===Constract.CursorModeConveyor?'primary':''"
@click="()=>state.cursorMode = Constract.CursorModeConveyor"></el-button>
</div> </div>
<div class="section-toolbar-right"> <div class="section-toolbar-right">
<el-input v-model="searchKeyword" size="small" style="width: 110px; margin-right: 5px;" <el-input v-model="searchKeyword" size="small" style="width: 110px; margin-right: 5px;"

154
src/model/ModelUtils.ts

@ -5,6 +5,7 @@ import { getAllItemTypes, getItemTypeByName } from '@/runtime/DefineItemType.ts'
import type Viewport from '@/designer/Viewport.ts' import type Viewport from '@/designer/Viewport.ts'
import { computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh' import { computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh'
import { Vector2 } from 'three/src/math/Vector2' import { Vector2 } from 'three/src/math/Vector2'
import type Toolbox from '@/model/itemType/Toolbox.ts'
export function quickCopyByMouse() { export function quickCopyByMouse() {
// 获取鼠标位置,查看鼠标是否在某个 viewport 的画布上,并取得该 viewport // 获取鼠标位置,查看鼠标是否在某个 viewport 的画布上,并取得该 viewport
@ -14,20 +15,21 @@ export function quickCopyByMouse() {
return return
} }
const x = currentMouseInfo.x
const z = currentMouseInfo.z
const viewport: Viewport = currentMouseInfo.viewport const viewport: Viewport = currentMouseInfo.viewport
const point: THREE.Vector2 = currentMouseInfo.mouse // const point: THREE.Vector2 = currentMouseInfo.mouse
//
// const ray = new THREE.Raycaster()
// ray.setFromCamera(point, viewport.camera)
// const intersections = ray.intersectObjects(viewport.dragControl._dragObjects, true)
//
// if (intersections.length === 0) {
// system.msg('没有找到可复制的对象')
// return
// }
// console.log('intersections:', intersections)
const ray = new THREE.Raycaster()
ray.setFromCamera(point, viewport.camera)
const intersections = ray.intersectObjects(viewport.dragControl._dragObjects, true)
if (intersections.length === 0) {
system.msg('没有找到可复制的对象')
return
}
console.log('intersections:', intersections)
/*
// 如果不在线上,查找0.2米内的有效点 Object3D, 如果有,则以这个点为起点, 延伸同类型的点,并让他们相连 // 如果不在线上,查找0.2米内的有效点 Object3D, 如果有,则以这个点为起点, 延伸同类型的点,并让他们相连
findObject3DByCondition(viewport.scene, object => { findObject3DByCondition(viewport.scene, object => {
// 判断 object 是否是有效的 Object3D, 并且是当前 viewport 的对象 // 判断 object 是否是有效的 Object3D, 并且是当前 viewport 的对象
@ -40,76 +42,78 @@ export function quickCopyByMouse() {
const distance = object.position.distanceTo(new THREE.Vector3(x, 0, z)) const distance = object.position.distanceTo(new THREE.Vector3(x, 0, z))
if (distance < 0.2) { if (distance < 0.2) {
// 找到一个有效点,执行复制操作 // 找到一个有效点,执行复制操作
toolbox.start(object) viewport.toolStartObject = object
system.msg('复制成功') viewport.state.cursorMode = object.userData.type
// toolbox.start(object)
system.msg('连线成功')
return true return true
} }
} }
return false return false
}) })
*/
} }
/** //
* 线 // /**
*/ // * 查找射线周围指定半径内的对象
export function findObjectsInRadius(viewport: Viewport, // */
point: THREE.Vector2, // export function findObjectsInRadius(viewport: Viewport,
radius: number, // point: THREE.Vector2,
lines: { object: THREE.Object3D, distance: number }[], // radius: number,
points: { object: THREE.Object3D, distance: number }[] // lines: { object: THREE.Object3D, distance: number }[],
): void { // points: { object: THREE.Object3D, distance: number }[]
const ray = new THREE.Raycaster() // ): void {
ray.setFromCamera(point, viewport.camera) // const ray = new THREE.Raycaster()
// ray.setFromCamera(point, viewport.camera)
viewport.dragControl._dragObjects.forEach(obj => { //
if (obj instanceof THREE.Points) { // viewport.dragControl._dragObjects.forEach(obj => {
// 处理点云:遍历每个点 // if (obj instanceof THREE.Points) {
const distance = distanceToRay(ray, point) // // 处理点云:遍历每个点
if (distance <= radius) { // const distance = distanceToRay(ray, point)
points.push({ object: obj, distance }) // if (distance <= radius) {
} // points.push({ object: obj, distance })
// }
} else if (obj instanceof THREE.Line) { //
// 处理线段:计算线段到射线的最近距离 // } else if (obj instanceof THREE.Line) {
const distance = getLineDistanceToRay(ray, obj) // // 处理线段:计算线段到射线的最近距离
if (distance <= radius) { // const distance = getLineDistanceToRay(ray, obj)
lines.push({ object: obj, distance }) // if (distance <= radius) {
} // lines.push({ object: obj, distance })
} // }
}) // }
} // })
// }
/** //
* 线 // /**
*/ // * 计算点到射线的最短距离
function distanceToRay(ray: THREE.Raycaster, point: THREE.Vector2) { // */
const closestPoint = new THREE.Vector3() // function distanceToRay(ray: THREE.Raycaster, point: THREE.Vector2) {
ray.closestPointToPoint(point, closestPoint) // const closestPoint = new THREE.Vector3()
return point.distanceTo(closestPoint) // ray.closestPointToPoint(point, closestPoint)
} // return point.distanceTo(closestPoint)
// }
/** //
* 线线 // /**
*/ // * 计算线段到射线的最短距离
function getLineDistanceToRay(ray: THREE.Raycaster, line: THREE.Line) { // */
const lineStart = new THREE.Vector3() // function getLineDistanceToRay(ray: THREE.Raycaster, line: THREE.Line) {
const lineEnd = new THREE.Vector3() // const lineStart = new THREE.Vector3()
line.geometry.attributes.position.getXYZ(0, lineStart) // const lineEnd = new THREE.Vector3()
line.geometry.attributes.position.getXYZ(1, lineEnd) // line.geometry.attributes.position.getXYZ(0, lineStart)
line.localToWorld(lineStart) // line.geometry.attributes.position.getXYZ(1, lineEnd)
line.localToWorld(lineEnd) // line.localToWorld(lineStart)
// line.localToWorld(lineEnd)
const lineSegment = new THREE.Line3(lineStart, lineEnd) //
const closestOnRay = new THREE.Vector3() // const lineSegment = new THREE.Line3(lineStart, lineEnd)
const closestOnLine = new THREE.Vector3() // const closestOnRay = new THREE.Vector3()
THREE.Line3.prototype.closestPointsRayLine ??= function(ray, line, closestOnRay, closestOnLine) { // const closestOnLine = new THREE.Vector3()
// 实现射线与线段最近点计算(需自定义或使用数学库) // THREE.Line3.prototype.closestPointsRayLine ??= function(ray, line, closestOnRay, closestOnLine) {
} // // 实现射线与线段最近点计算(需自定义或使用数学库)
// }
lineSegment.closestPointsRayLine(ray, true, closestOnRay, closestOnLine) //
return closestOnRay.distanceTo(closestOnLine) // lineSegment.closestPointsRayLine(ray, true, closestOnRay, closestOnLine)
} // return closestOnRay.distanceTo(closestOnLine)
// }
/** /**
* *

4
src/model/WorldModel.ts

@ -7,6 +7,7 @@ import type Viewport from '@/designer/Viewport.ts'
import { loadSceneFromJson } from '@/model/ModelUtils.ts' import { loadSceneFromJson } from '@/model/ModelUtils.ts'
import MeasureMeta from './itemType/measure/MeasureMeta' import MeasureMeta from './itemType/measure/MeasureMeta'
import ConveyorMeta from './itemType/line/conveyor/ConveyorMeta'
import type { IGridHelper } from '@/model/WorldModelType.ts' import type { IGridHelper } from '@/model/WorldModelType.ts'
/** /**
@ -53,7 +54,8 @@ export default class WorldModel {
init() { init() {
return Promise.all([ return Promise.all([
MeasureMeta.clazz.init(this) MeasureMeta.clazz.init(this),
ConveyorMeta.clazz.init(this)
]).then(() => { ]).then(() => {
console.log('世界模型初始化完成') console.log('世界模型初始化完成')

1
src/model/itemType/Toolbox.ts

@ -218,7 +218,6 @@ export default abstract class Toolbox {
if (e.button === 2) { if (e.button === 2) {
// 右键点击, 完成绘图操作 // 右键点击, 完成绘图操作
this.viewport.state.cursorMode = 'normal' this.viewport.state.cursorMode = 'normal'
this.stop()
} else if (e.button === 0) { } else if (e.button === 0) {
// 左键点击, 添加点 // 左键点击, 添加点

82
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<void> {
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
}
}

9
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()
})

16
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
}
}
Loading…
Cancel
Save