|
|
@ -6,30 +6,63 @@ import { Line2 } from 'three/examples/jsm/lines/Line2.js' |
|
|
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js' |
|
|
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js' |
|
|
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js' |
|
|
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js' |
|
|
|
|
|
|
|
|
|
|
|
let pdFn, pmFn, puFn |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 选择工具,用于在设计器中显示选中对象的包围盒 |
|
|
* 选择工具,用于在设计器中显示选中对象的包围盒 |
|
|
*/ |
|
|
*/ |
|
|
export default class SelectInspect implements ITool { |
|
|
export default class SelectInspect implements ITool { |
|
|
viewport: any |
|
|
viewport: Viewport |
|
|
material: LineMaterial |
|
|
/** |
|
|
|
|
|
* 线框材质,用于显示选中对象的包围盒 |
|
|
|
|
|
*/ |
|
|
|
|
|
material: LineMaterial = new LineMaterial({ color: 0xffff00, linewidth: 2 }) |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 矩形材质,用于显示鼠标拖拽选择的矩形区域 |
|
|
|
|
|
*/ |
|
|
|
|
|
rectMaterial: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({ |
|
|
|
|
|
color: 0x000000, |
|
|
|
|
|
opacity: 0.5, |
|
|
|
|
|
transparent: true |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 当前选中对象的矩形选择框 |
|
|
|
|
|
*/ |
|
|
|
|
|
rectangle: THREE.Mesh | null = null |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 当前选中对象的包围盒线框 |
|
|
|
|
|
*/ |
|
|
selectionBox: Line2 |
|
|
selectionBox: Line2 |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 当前鼠标所在的画布, 对应 viewport.renderer.domElement |
|
|
|
|
|
*/ |
|
|
|
|
|
canvas: HTMLCanvasElement |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 鼠标按下时记录的起始位置,用于绘制矩形选择框 |
|
|
|
|
|
*/ |
|
|
|
|
|
recStartPos: THREE.Vector3 | null |
|
|
|
|
|
|
|
|
constructor() { |
|
|
constructor() { |
|
|
// 颜色变成黄
|
|
|
|
|
|
const color = 0xffff00 // 0xff0000
|
|
|
|
|
|
const lineWidth = 2 |
|
|
|
|
|
this.material = new LineMaterial({ color, linewidth: lineWidth }) |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
init(viewport: Viewport) { |
|
|
init(viewport: Viewport) { |
|
|
this.viewport = viewport |
|
|
this.viewport = viewport |
|
|
|
|
|
this.canvas = this.viewport.renderer.domElement as HTMLCanvasElement |
|
|
|
|
|
|
|
|
|
|
|
pdFn = this.onMouseDown.bind(this) |
|
|
|
|
|
this.canvas.addEventListener('pointerdown', pdFn) |
|
|
|
|
|
pmFn = this.onMouseMove.bind(this) |
|
|
|
|
|
this.canvas.addEventListener('pointermove', pmFn) |
|
|
|
|
|
puFn = this.onMouseUp.bind(this) |
|
|
|
|
|
this.canvas.addEventListener('pointerup', puFn) |
|
|
|
|
|
|
|
|
this.viewport.watchList.push(watch(() => this.viewport.state.selectedObject, (selectedObject) => { |
|
|
this.viewport.watchList.push(watch(() => this.viewport.state.selectedObject, (selectedObject) => { |
|
|
if (this.selectionBox) { |
|
|
this.disposeSelectionBox() |
|
|
viewport.scene.remove(this.selectionBox) |
|
|
|
|
|
this.selectionBox.geometry.dispose() |
|
|
|
|
|
this.selectionBox = null |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const expandAmount = 0.2 // 扩展包围盒的大小
|
|
|
const expandAmount = 0.2 // 扩展包围盒的大小
|
|
|
if (selectedObject !== null) { |
|
|
if (selectedObject !== null) { |
|
|
@ -66,11 +99,97 @@ export default class SelectInspect implements ITool { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
destory() { |
|
|
destory() { |
|
|
|
|
|
|
|
|
|
|
|
this.canvas.removeEventListener('pointerdown', pdFn) |
|
|
|
|
|
pdFn = undefined |
|
|
|
|
|
this.canvas.removeEventListener('pointermove', pmFn) |
|
|
|
|
|
pmFn = undefined |
|
|
|
|
|
this.canvas.removeEventListener('pointerup', puFn) |
|
|
|
|
|
puFn = undefined |
|
|
|
|
|
|
|
|
// 销毁选择工具
|
|
|
// 销毁选择工具
|
|
|
|
|
|
this.disposeSelectionBox() |
|
|
|
|
|
this.disposeRect() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
disposeSelectionBox() { |
|
|
if (this.selectionBox) { |
|
|
if (this.selectionBox) { |
|
|
this.viewport.scene.remove(this.selectionBox) |
|
|
this.viewport.scene.remove(this.selectionBox) |
|
|
this.selectionBox.geometry.dispose() |
|
|
this.selectionBox.geometry.dispose() |
|
|
this.selectionBox = null |
|
|
this.selectionBox = null |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createRectangle() { |
|
|
|
|
|
if (this.rectangle !== null) { |
|
|
|
|
|
this.disposeRect() |
|
|
|
|
|
} |
|
|
|
|
|
if (this.recStartPos) { |
|
|
|
|
|
// 创建矩形
|
|
|
|
|
|
this.rectangle = new THREE.Mesh( |
|
|
|
|
|
new THREE.PlaneGeometry(1, 1), |
|
|
|
|
|
this.rectMaterial |
|
|
|
|
|
) |
|
|
|
|
|
this.rectangle.name = 'selectRectangle' |
|
|
|
|
|
this.rectangle.rotation.x = -Math.PI / 2 // 关键!让平面正对相机
|
|
|
|
|
|
this.rectangle.position.set( |
|
|
|
|
|
this.recStartPos.x, |
|
|
|
|
|
this.recStartPos.y, |
|
|
|
|
|
this.recStartPos.z |
|
|
|
|
|
) |
|
|
|
|
|
this.viewport.scene.add(this.rectangle) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
updateRectangle(position: THREE.Vector3) { |
|
|
|
|
|
if (!this.rectangle || !this.recStartPos) return |
|
|
|
|
|
// console.log('updateRectangle', this.recStartPos, position)
|
|
|
|
|
|
|
|
|
|
|
|
const width = position.x - this.recStartPos.x |
|
|
|
|
|
const height = position.z - this.recStartPos.z |
|
|
|
|
|
|
|
|
|
|
|
const newWidth = Math.abs(width) |
|
|
|
|
|
const newHeight = Math.abs(height) |
|
|
|
|
|
|
|
|
|
|
|
// 清理旧几何体
|
|
|
|
|
|
this.rectangle.geometry.dispose() |
|
|
|
|
|
this.rectangle.geometry = new THREE.PlaneGeometry(newWidth, newHeight) |
|
|
|
|
|
this.rectangle.position.set( |
|
|
|
|
|
this.recStartPos.x + width / 2, |
|
|
|
|
|
this.recStartPos.y, |
|
|
|
|
|
this.recStartPos.z + height / 2 |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
onMouseDown(event: MouseEvent) { |
|
|
|
|
|
if (event.shiftKey) { |
|
|
|
|
|
// 记录鼠标按下位置
|
|
|
|
|
|
this.recStartPos = this.viewport.getClosestIntersection(event) |
|
|
|
|
|
this.createRectangle() |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMouseMove(event: MouseEvent) { |
|
|
|
|
|
if (!this.recStartPos) { |
|
|
|
|
|
this.disposeRect() |
|
|
|
|
|
} |
|
|
|
|
|
// 更新矩形大小或重新生成矩形
|
|
|
|
|
|
const position = this.viewport.getClosestIntersection(event) |
|
|
|
|
|
if (!position) return |
|
|
|
|
|
this.updateRectangle(position) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
disposeRect() { |
|
|
|
|
|
if (this.rectangle !== null) { |
|
|
|
|
|
this.viewport.scene.remove(this.rectangle) |
|
|
|
|
|
this.rectangle.geometry.dispose() |
|
|
|
|
|
this.rectangle = null |
|
|
|
|
|
} |
|
|
|
|
|
this.recStartPos = null |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
onMouseUp(event: MouseEvent) { |
|
|
|
|
|
this.disposeRect() |
|
|
|
|
|
} |
|
|
} |
|
|
} |