Browse Source

MeasureTool drag

master
修宁 7 months ago
parent
commit
b17ebea94e
  1. 6
      src/designer/model2DEditor/EsDragControls.ts
  2. 287
      src/designer/model2DEditor/tools/MeasureTool.ts

6
src/designer/model2DEditor/EsDragControls.ts

@ -79,7 +79,7 @@ export default class EsDragControls {
switch (e.object.userData.type) {
case Constract.MeasureMarker:
this.viewport.measure.redraw(e.object)
this.viewport.measure.dragPointStart(e.object)
break
}
}
@ -109,8 +109,8 @@ export default class EsDragControls {
}
switch (e.object.userData.type) {
case 'measure-marker':
this.viewport.measure.redrawComplete()
case Constract.MeasureMarker:
this.viewport.measure.dragPointComplete()
break
}
}

287
src/designer/model2DEditor/tools/MeasureTool.ts

@ -1,11 +1,7 @@
import _ from 'lodash'
import PointPng from '@/assets/images/logo.png'
import * as THREE from 'three'
import type { ITool } from '@/designer/model2DEditor/tools/ITool.ts'
import Viewport from '@/designer/Viewport.ts'
import { numberToString, getUnitString } from '@/utils/webutils'
import { getUnitString, numberToString } from '@/utils/webutils'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
import { Vector3 } from 'three'
import Constract from '@/designer/Constract.ts'
import type { ICursorTool } from '@/designer/model2DEditor/tools/CursorTool.ts'
@ -20,29 +16,66 @@ export default class MeasureTool implements ICursorTool {
static LINE_NAME = 'measure_line'
static MAX_DISTANCE = 500 //当相交物体的距离太远时,忽略它
/**
* Three.js .
* :
* - viewport.scene
* - viewport.renderer
* - viewport.controls
* - viewport.camera
* - viewport.raycaster 线
* - viewport.dragControl
* - viewport.measure
*/
viewport: Viewport
// 当前测绘内容组
/**
* , 线. 线
*/
group: THREE.Group
/**
*
*/
isCompleted = false
/**
*
*/
mouseMoved = false
/**
* , viewport.renderer.domElement
*/
canvas: HTMLCanvasElement
// 用于存储临时点
protected tempPointMarker?: THREE.Mesh
/**
*
*/
tempPointMarker?: THREE.Mesh
// 用于存储临时线条,用于在鼠标移动时绘制线条/区域/角度
protected tempLine?: THREE.Line
/**
* 线
*/
tempLine?: THREE.Line
// 用于在鼠标移动时存储临时标签,只有测量距离时才有
protected tempLabel?: CSS2DObject
/**
* ,
*/
tempLabel?: CSS2DObject
// 当次绘制点
protected pointArray: THREE.Vector3[] = []
/**
* ,
*/
pointArray: THREE.Vector3[] = []
//保存上次点击时间,以便检测双击事件
protected lastClickTime: number = 0
/**
* 便
* @protected
*/
lastClickTime: number = 0
/**
* 线
*/
static LINE_MATERIAL = new THREE.LineBasicMaterial({
color: 0xE63C17,
linewidth: 2,
@ -53,20 +86,26 @@ export default class MeasureTool implements ICursorTool {
depthTest: false
})
mode: CursorMode
/**
*
*/
init(viewport: Viewport) {
this.viewport = viewport
const viewerDom = this.viewport.viewerDom
this.canvas = this.viewport.renderer.domElement as HTMLCanvasElement
// 初始化group
this.group = new THREE.Group()
this.group.name = `${MeasureTool.OBJ_NAME}_group`
this.group.userData = {
mode: this.viewport.state.cursorMode
mode: Constract.CursorModeMeasure
}
this.viewport.scene.add(this.group)
}
/**
* , ,
*/
start() {
pdFn = this.mousedown.bind(this)
this.canvas.addEventListener('pointerdown', pdFn)
@ -79,9 +118,14 @@ export default class MeasureTool implements ICursorTool {
this.viewport.viewerDom.style.cursor = 'crosshair'
this.pointArray = []
this.mode = this.viewport.state.cursorMode
system.msg('进入测量模式')
}
/**
* , 线.
*/
stop(): void {
system.msg('退出测量模式')
@ -106,14 +150,22 @@ export default class MeasureTool implements ICursorTool {
this.tempLabel = undefined
}
/**
* ,
*/
destory() {
}
/**
*
*/
mousedown() {
this.mouseMoved = false
}
// 鼠标移动,创建对应的临时点与线
/**
* 线
*/
mousemove(e: MouseEvent) {
if (this.isCompleted) return
@ -146,15 +198,15 @@ export default class MeasureTool implements ICursorTool {
const geom = line.geometry
const startPoint = this.pointArray[0]
const lastPoint = this.pointArray[this.pointArray.length - 1]
if (this.viewport.state.cursorMode === Constract.CursorModeMeasureArea) {
if (this.mode === Constract.CursorModeMeasureArea) {
geom.setFromPoints([lastPoint, point, startPoint])
} else {
geom.setFromPoints([lastPoint, point])
}
if (this.viewport.state.cursorMode === Constract.CursorModeMeasure) {
if (this.mode === Constract.CursorModeMeasure) {
const dist = p0.distanceTo(point)
const label = `${numberToString(dist)} ${getUnitString(this.viewport.state.cursorMode)}`
const label = `${numberToString(dist)} ${getUnitString(this.mode)}`
const position = new THREE.Vector3((point.x + p0.x) / 2, (point.y + p0.y) / 2, (point.z + p0.z) / 2)
this.addOrUpdateTempLabel(label, position)
}
@ -163,6 +215,9 @@ export default class MeasureTool implements ICursorTool {
// this.viewport.dispatchSignal('sceneGraphChanged')
}
/**
*
*/
mouseup(e: MouseEvent) {
// 如果mouseMoved是true,那么它可能在移动,而不是点击
if (!this.mouseMoved) {
@ -179,7 +234,7 @@ export default class MeasureTool implements ICursorTool {
}
}
onMouseClicked(e: MouseEvent) {
private onMouseClicked(e: MouseEvent) {
if (this.isCompleted) {
return
}
@ -214,11 +269,13 @@ export default class MeasureTool implements ICursorTool {
const p0 = this.pointArray[count - 2]
this.tempLabel.position.set((p0.x + point.x) / 2, (p0.y + point.y) / 2, (p0.z + point.z) / 2)
this.tempLabel.userData.pointIndices = [count - 2, count - 1]
this.group.add(this.tempLabel)
this.tempLabel = undefined
// 临时线
this.tempLine.geometry.setFromPoints([p0, point])
this.tempLine.userData.pointIndices = [count - 2, count - 1]
this.group.add(this.tempLine)
this.tempLine = undefined
}
@ -227,7 +284,7 @@ export default class MeasureTool implements ICursorTool {
}
/**
* Creates THREE.Line
* 线
*/
private createLine(): THREE.Line {
const geom = new THREE.BufferGeometry()
@ -258,7 +315,7 @@ export default class MeasureTool implements ICursorTool {
obj.name = MeasureTool.OBJ_NAME
obj.userData = {
mode: this.viewport.state.cursorMode,
mode: this.mode,
type: Constract.MeasureMarker
}
return obj
@ -278,7 +335,6 @@ export default class MeasureTool implements ICursorTool {
this.tempLabel.element.innerHTML = label
}
/**
*
*/
@ -303,37 +359,60 @@ export default class MeasureTool implements ICursorTool {
return obj
}
private draggingIndex: number = -1
private connectedLines: THREE.Line[] = []
private connectedLabels: CSS2DObject[] = []
private originalPosition: THREE.Vector3 = new THREE.Vector3()
/**
* ,
* DragControls
* description:
* 线
* 线
* move方法线
* @param point .
*/
redraw(point: THREE.Mesh) {
// 当次绘制点
this.pointArray = [];
(point.parent as THREE.Group).children.forEach(child => {
switch (child.userData.type) {
case Constract.MeasureMarker:
// 当前点正在操作,不加入
if (child.uuid !== point.uuid) {
this.pointArray[child.userData.pointIndex] = child.userData.point
} else {
this.tempPointMarker = child as THREE.Mesh
}
break
case Constract.MeasureLine:
this.tempLine = this.createLine()
this.group.add(this.tempLine)
break
dragPointStart(point: THREE.Mesh) {
this.group = point.parent as THREE.Group
this.isCompleted = false
// 获取当前拖拽点的索引
this.draggingIndex = point.userData.pointIndex
this.originalPosition.copy(point.position)
// 收集相关联的线段和标签
this.connectedLines = []
this.connectedLabels = []
// 遍历group查找相关线段和标签
this.group.children.forEach(child => {
// 处理线段
if (child.name === MeasureTool.LINE_NAME && child.userData.pointIndices) {
const [startIdx, endIdx] = child.userData.pointIndices
if (startIdx === this.draggingIndex || endIdx === this.draggingIndex) {
this.connectedLines.push(child as THREE.Line)
}
}
// 处理标签
if (child.name === MeasureTool.LABEL_NAME && child.userData.pointIndices) {
const [startIdx, endIdx] = child.userData.pointIndices
if (startIdx === this.draggingIndex || endIdx === this.draggingIndex) {
this.connectedLabels.push(child as CSS2DObject)
}
}
})
// 重写move事件
// 监听move事件
pmFn = this.redrawMousemove.bind(this)
this.canvas.addEventListener('pointermove', pmFn)
this.group = point.parent as THREE.Group
this.isCompleted = false
console.log('connectedLines:', this.connectedLines)
console.log('connectedLabels:', this.connectedLabels)
// 这个方法会在拖拽开始时被调用,记录当前点的索引和位置,
// 需要找到与这个点相关的所有测量点、线、标签,并将它们添加到临时数组中。
// 并创建临时线条用于连接前后点。
}
@ -341,77 +420,61 @@ export default class MeasureTool implements ICursorTool {
*
*/
redrawMousemove(e: MouseEvent) {
let point = this.viewport.getClosestIntersection(e)
if (!point && this.tempPointMarker) {
this.tempPointMarker.position.set(this.tempPointMarker.userData.point.x, this.tempPointMarker.userData.point.y, this.tempPointMarker.userData.point.z)
return
}
if (!point || !this.tempPointMarker) return
// 在鼠标移动时绘制临时点
this.tempPointMarker.position.set(point.x, point.y, point.z)
this.tempPointMarker.userData.point = point
// 当前点的索引
const cIndex = this.tempPointMarker.userData.pointIndex
if (this.draggingIndex === -1) return
let newPosition = this.viewport.getClosestIntersection(e)
// 更新点数组中的坐标
this.pointArray[this.draggingIndex].copy(newPosition)
// 更新所有相关线段
this.connectedLines.forEach(line => {
const [startIdx, endIdx] = line.userData.pointIndices
const startPoint = this.pointArray[startIdx]
const endPoint = this.pointArray[endIdx]
// 更新线段几何体
const geometry = line.geometry as THREE.BufferGeometry
geometry.setFromPoints([startPoint, endPoint])
geometry.attributes.position.needsUpdate = true
})
// 移动时绘制临时线
if (this.pointArray.length > 0) {
const line = this.tempLine || this.createLine()
const geom = line.geometry
let startPoint = this.pointArray[cIndex + 1]
let lastPoint = this.pointArray[cIndex - 1]
// 更新所有相关标签
this.connectedLabels.forEach(label => {
const [startIdx, endIdx] = label.userData.pointIndices
const startPoint = this.pointArray[startIdx]
const endPoint = this.pointArray[endIdx]
// 计算中间位置和距离
const midPoint = new THREE.Vector3()
.addVectors(startPoint, endPoint)
.multiplyScalar(0.5)
const distance = startPoint.distanceTo(endPoint)
// 更新标签位置和内容
label.position.copy(midPoint)
label.element.innerHTML = `${numberToString(distance)} ${getUnitString(this.mode)}`
})
if (startPoint && lastPoint) {
geom.setFromPoints([lastPoint, point, startPoint])
} else {
geom.setFromPoints([startPoint || lastPoint, point])
}
// 更新点的可视化位置
const pointObj = this.group.children.find(child =>
child.userData.pointIndex === this.draggingIndex
) as THREE.Mesh
if (pointObj) {
pointObj.position.copy(newPosition)
}
// 在拖拽过程中,监听鼠标move方法
// 更新临时点的位置,并根据当前点的索引更新临时线条的几何体、重新计算长度、更新标签位置等
}
/**
*
* DragControls
*/
redrawComplete() {
if (!this.tempPointMarker) return
dragPointComplete() {
const point = this.tempPointMarker.userData.point
this.pointArray[this.tempPointMarker.userData.pointIndex] = point
const count = this.pointArray.length
// 将临时点、线、标签添加到 group 中, 变成正式的测量
// 如果是距离测量,则清除group中已有的label,再重新创建
if (this.viewport.state.cursorMode === 'Measure' && count > 1) {
this.clearCurrentLabel()
// 绘制label
for (let i = 0; i < count - 1; i++) {
const p0 = this.pointArray[i]
const p1 = this.pointArray[i + 1]
if (!p0 || !p1) continue
const dist = p0.distanceTo(p1)
const label = `${numberToString(dist)} ${getUnitString(this.viewport.state.cursorMode)}`
const position = new THREE.Vector3((p0.x + p1.x) / 2, (p0.y + p1.y) / 2, (p0.z + p1.z) / 2)
const labelObj = this.createLabel(label)
labelObj.position.set(position.x, position.y, position.z)
labelObj.element.innerHTML = label
this.group.add(labelObj)
}
}
// this.destory()
}
/**
* group label
*/
clearCurrentLabel() {
for (let i = this.group.children.length - 1; i >= 0; i--) {
const c = this.group.children[i]
if (c.userData.type === 'label') {
this.group.remove(c)
}
}
// 删除鼠标事件监听
this.canvas.removeEventListener('pointermove', pmFn)
pmFn = undefined
}
}
Loading…
Cancel
Save