Browse Source

MeasureTool drag

master
修宁 7 months ago
parent
commit
b17ebea94e
  1. 6
      src/designer/model2DEditor/EsDragControls.ts
  2. 285
      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) { switch (e.object.userData.type) {
case Constract.MeasureMarker: case Constract.MeasureMarker:
this.viewport.measure.redraw(e.object) this.viewport.measure.dragPointStart(e.object)
break break
} }
} }
@ -109,8 +109,8 @@ export default class EsDragControls {
} }
switch (e.object.userData.type) { switch (e.object.userData.type) {
case 'measure-marker': case Constract.MeasureMarker:
this.viewport.measure.redrawComplete() this.viewport.measure.dragPointComplete()
break break
} }
} }

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