|
|
|
@ -4,6 +4,9 @@ import { getUnitString, numberToString } from '@/utils/webutils' |
|
|
|
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' |
|
|
|
import Constract from '@/designer/Constract.ts' |
|
|
|
import type { ICursorTool } from '@/designer/model2DEditor/tools/CursorTool.ts' |
|
|
|
import type Measure from '@/model/itemType/measure/Measure.ts' |
|
|
|
import { getItemTypeByName } from '@/runtime/DefineItemType.ts' |
|
|
|
import { LABEL_NAME, LINE_NAME } from '@/model/itemType/measure/Measure.ts' |
|
|
|
|
|
|
|
let pdFn, pmFn, puFn, kdFn |
|
|
|
|
|
|
|
@ -11,11 +14,6 @@ let pdFn, pmFn, puFn, kdFn |
|
|
|
* 用于在 threejs 中创建一系列的 object_for_measure 点,并标记他的距离 |
|
|
|
*/ |
|
|
|
export default class MeasureTool implements ICursorTool { |
|
|
|
static OBJ_NAME = 'measure_' |
|
|
|
static LABEL_NAME = 'measure_label' |
|
|
|
static LINE_NAME = 'measure_line' |
|
|
|
static MAX_DISTANCE = 500 //当相交物体的距离太远时,忽略它
|
|
|
|
|
|
|
|
/** |
|
|
|
* 测量工具所在的视图窗口,从这里可以取到 所有 Three.js 相关的对象. |
|
|
|
* 比如: |
|
|
|
@ -32,7 +30,8 @@ export default class MeasureTool implements ICursorTool { |
|
|
|
/** |
|
|
|
* 当前测绘内容组, 所有测量点、线、标签都在这个组中. 但不包括临时点、线 |
|
|
|
*/ |
|
|
|
group: THREE.Group |
|
|
|
measure: Measure |
|
|
|
|
|
|
|
/** |
|
|
|
* 是否完成测量 |
|
|
|
*/ |
|
|
|
@ -88,6 +87,11 @@ export default class MeasureTool implements ICursorTool { |
|
|
|
|
|
|
|
mode: CursorMode |
|
|
|
|
|
|
|
private draggingIndex: number = -1 |
|
|
|
private connectedLines: THREE.Line[] = [] |
|
|
|
private connectedLabels: CSS2DObject[] = [] |
|
|
|
private originalPosition: THREE.Vector3 = new THREE.Vector3() |
|
|
|
|
|
|
|
/** |
|
|
|
* 测量工具初始化 |
|
|
|
*/ |
|
|
|
@ -95,12 +99,7 @@ export default class MeasureTool implements ICursorTool { |
|
|
|
this.viewport = viewport |
|
|
|
this.canvas = this.viewport.renderer.domElement as HTMLCanvasElement |
|
|
|
|
|
|
|
this.group = new THREE.Group() |
|
|
|
this.group.name = `${MeasureTool.OBJ_NAME}_group` |
|
|
|
this.group.userData = { |
|
|
|
mode: Constract.CursorModeMeasure |
|
|
|
} |
|
|
|
this.viewport.scene.add(this.group) |
|
|
|
this.measure = getItemTypeByName('measure')!.clazz |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -204,12 +203,10 @@ export default class MeasureTool implements ICursorTool { |
|
|
|
geom.setFromPoints([lastPoint, point]) |
|
|
|
} |
|
|
|
|
|
|
|
if (this.mode === Constract.CursorModeMeasure) { |
|
|
|
const dist = p0.distanceTo(point) |
|
|
|
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) |
|
|
|
} |
|
|
|
const dist = p0.distanceTo(point) |
|
|
|
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) |
|
|
|
} |
|
|
|
|
|
|
|
// this.viewport.dispatchSignal('sceneGraphChanged')
|
|
|
|
@ -259,7 +256,7 @@ export default class MeasureTool implements ICursorTool { |
|
|
|
const marker = this.createPointMarker(point) |
|
|
|
marker.userData.point = point |
|
|
|
marker.userData.pointIndex = count - 1 |
|
|
|
this.group.add(marker) |
|
|
|
this.measure.group.add(marker) |
|
|
|
|
|
|
|
// 把点加入拖拽控制器
|
|
|
|
this.viewport.dragControl.setDragObjects([marker], 'push') |
|
|
|
@ -270,13 +267,13 @@ export default class MeasureTool implements ICursorTool { |
|
|
|
|
|
|
|
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.measure.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.measure.group.add(this.tempLine) |
|
|
|
this.tempLine = undefined |
|
|
|
} |
|
|
|
|
|
|
|
@ -327,154 +324,12 @@ export default class MeasureTool implements ICursorTool { |
|
|
|
*/ |
|
|
|
addOrUpdateTempLabel(label: string, position: THREE.Vector3) { |
|
|
|
if (!this.tempLabel) { |
|
|
|
this.tempLabel = this.createLabel(label) |
|
|
|
console.log('addOrUpdateTempLabel', label, position) |
|
|
|
this.tempLabel = this.measure.createLabel(label) |
|
|
|
this.viewport.scene.add(this.tempLabel) |
|
|
|
} |
|
|
|
this.tempLabel.position.set(position.x, position.y, position.z) |
|
|
|
this.tempLabel.element.innerHTML = label |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 创建标签 |
|
|
|
*/ |
|
|
|
createLabel(text: string): CSS2DObject { |
|
|
|
const div = document.createElement('div') |
|
|
|
div.className = 'css2dObjectLabel' |
|
|
|
div.innerHTML = text |
|
|
|
div.style.padding = '5px 8px' |
|
|
|
div.style.color = '#fff' |
|
|
|
div.style.fontSize = '14px' |
|
|
|
div.style.position = 'absolute' |
|
|
|
div.style.backgroundColor = 'rgba(25, 25, 25, 0.3)' |
|
|
|
div.style.borderRadius = '12px' |
|
|
|
div.style.top = '0px' |
|
|
|
div.style.left = '0px' |
|
|
|
// div.style.pointerEvents = 'none' //避免HTML元素影响场景的鼠标事件
|
|
|
|
const obj = new CSS2DObject(div) |
|
|
|
obj.name = MeasureTool.LABEL_NAME |
|
|
|
obj.userData = { |
|
|
|
type: Constract.MeasureLabel |
|
|
|
} |
|
|
|
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 拖拽的点. |
|
|
|
*/ |
|
|
|
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事件
|
|
|
|
pmFn = this.redrawMousemove.bind(this) |
|
|
|
this.canvas.addEventListener('pointermove', pmFn) |
|
|
|
|
|
|
|
console.log('connectedLines:', this.connectedLines) |
|
|
|
console.log('connectedLabels:', this.connectedLabels) |
|
|
|
|
|
|
|
// 这个方法会在拖拽开始时被调用,记录当前点的索引和位置,
|
|
|
|
// 需要找到与这个点相关的所有测量点、线、标签,并将它们添加到临时数组中。
|
|
|
|
// 并创建临时线条用于连接前后点。
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 重绘监听鼠标移动 |
|
|
|
*/ |
|
|
|
redrawMousemove(e: MouseEvent) { |
|
|
|
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 |
|
|
|
}) |
|
|
|
|
|
|
|
// 更新所有相关标签
|
|
|
|
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)}` |
|
|
|
}) |
|
|
|
|
|
|
|
// 更新点的可视化位置
|
|
|
|
const pointObj = this.group.children.find(child => |
|
|
|
child.userData.pointIndex === this.draggingIndex |
|
|
|
) as THREE.Mesh |
|
|
|
if (pointObj) { |
|
|
|
pointObj.position.copy(newPosition) |
|
|
|
} |
|
|
|
// 在拖拽过程中,监听鼠标move方法
|
|
|
|
// 更新临时点的位置,并根据当前点的索引更新临时线条的几何体、重新计算长度、更新标签位置等
|
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 测量点被 DragControls 拖拽完成后触发这个方法 |
|
|
|
*/ |
|
|
|
dragPointComplete() { |
|
|
|
|
|
|
|
// 将临时点、线、标签添加到 group 中, 变成正式的测量
|
|
|
|
|
|
|
|
// 删除鼠标事件监听
|
|
|
|
this.canvas.removeEventListener('pointermove', pmFn) |
|
|
|
pmFn = undefined |
|
|
|
} |
|
|
|
} |