8 changed files with 730 additions and 44 deletions
@ -0,0 +1,211 @@ |
|||||
|
import { |
||||
|
EventDispatcher, |
||||
|
Matrix4, |
||||
|
Plane, |
||||
|
Raycaster, |
||||
|
Vector2, |
||||
|
Vector3 |
||||
|
} from 'three'; |
||||
|
|
||||
|
const _plane = new Plane(); |
||||
|
const _raycaster = new Raycaster(); |
||||
|
|
||||
|
const _pointer = new Vector2(); |
||||
|
const _offset = new Vector3(); |
||||
|
const _intersection = new Vector3(); |
||||
|
const _worldPosition = new Vector3(); |
||||
|
const _inverseMatrix = new Matrix4(); |
||||
|
|
||||
|
class DragControls extends EventDispatcher { |
||||
|
constructor( _objects, _camera, _domElement ) { |
||||
|
super(); |
||||
|
|
||||
|
_domElement.style.touchAction = 'none'; // disable touch scroll
|
||||
|
|
||||
|
let _selected = null, _hovered = null; |
||||
|
|
||||
|
const _intersections = []; |
||||
|
|
||||
|
//
|
||||
|
|
||||
|
let isMove = false; |
||||
|
|
||||
|
const scope = this; |
||||
|
|
||||
|
function activate() { |
||||
|
_domElement.addEventListener( 'pointermove', onPointerMove ); |
||||
|
_domElement.addEventListener( 'pointerdown', onPointerDown ); |
||||
|
_domElement.addEventListener( 'pointerup', onPointerCancel ); |
||||
|
_domElement.addEventListener( 'pointerleave', onPointerCancel ); |
||||
|
} |
||||
|
|
||||
|
function deactivate() { |
||||
|
_domElement.removeEventListener( 'pointermove', onPointerMove ); |
||||
|
_domElement.removeEventListener( 'pointerdown', onPointerDown ); |
||||
|
_domElement.removeEventListener( 'pointerup', onPointerCancel ); |
||||
|
_domElement.removeEventListener( 'pointerleave', onPointerCancel ); |
||||
|
|
||||
|
_domElement.style.cursor = ''; |
||||
|
} |
||||
|
|
||||
|
function dispose() { |
||||
|
deactivate(); |
||||
|
} |
||||
|
|
||||
|
function setObjects( objects ) { |
||||
|
_objects = objects; |
||||
|
} |
||||
|
|
||||
|
function getObjects() { |
||||
|
return _objects; |
||||
|
} |
||||
|
|
||||
|
function getRaycaster() { |
||||
|
return _raycaster; |
||||
|
} |
||||
|
|
||||
|
function onPointerMove( event ) { |
||||
|
|
||||
|
if ( !scope.enabled || !scope.enabledMove) return; |
||||
|
|
||||
|
isMove = true; |
||||
|
|
||||
|
updatePointer( event ); |
||||
|
|
||||
|
_raycaster.setFromCamera( _pointer, _camera ); |
||||
|
|
||||
|
if ( _selected ) { |
||||
|
|
||||
|
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
|
||||
|
_selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) ); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
scope.dispatchEvent( { type: 'drag', object: _selected } ); |
||||
|
|
||||
|
return; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// hover support
|
||||
|
|
||||
|
if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) { |
||||
|
|
||||
|
_intersections.length = 0; |
||||
|
|
||||
|
_raycaster.setFromCamera( _pointer, _camera ); |
||||
|
_raycaster.intersectObjects( _objects, true, _intersections ); |
||||
|
|
||||
|
if ( _intersections.length > 0 ) { |
||||
|
|
||||
|
const object = _intersections[ 0 ].object; |
||||
|
|
||||
|
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) ); |
||||
|
|
||||
|
if ( _hovered !== object && _hovered !== null ) { |
||||
|
|
||||
|
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
||||
|
|
||||
|
_domElement.style.cursor = 'auto'; |
||||
|
_hovered = null; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
if ( _hovered !== object ) { |
||||
|
|
||||
|
scope.dispatchEvent( { type: 'hoveron', object: object } ); |
||||
|
|
||||
|
_domElement.style.cursor = 'pointer'; |
||||
|
_hovered = object; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
if ( _hovered !== null ) { |
||||
|
|
||||
|
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
||||
|
|
||||
|
_domElement.style.cursor = 'auto'; |
||||
|
_hovered = null; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
function onPointerDown( event ) { |
||||
|
if (scope.enabled === false) return; |
||||
|
|
||||
|
updatePointer(event); |
||||
|
|
||||
|
_intersections.length = 0; |
||||
|
|
||||
|
_raycaster.setFromCamera( _pointer, _camera ); |
||||
|
let objects = _objects; |
||||
|
|
||||
|
_raycaster.intersectObjects( objects, true, _intersections ); |
||||
|
|
||||
|
if (_intersections.length > 0) { |
||||
|
_selected = (scope.transformGroup === true) ? _objects[ 0 ] : _intersections[0].object; |
||||
|
|
||||
|
if(scope.enabledMove) { |
||||
|
_plane.setFromNormalAndCoplanarPoint(_camera.getWorldDirection(_plane.normal), _worldPosition.setFromMatrixPosition(_selected.matrixWorld)); |
||||
|
if (_raycaster.ray.intersectPlane(_plane, _intersection)) { |
||||
|
_inverseMatrix.copy(_selected.parent.matrixWorld).invert(); |
||||
|
_offset.copy(_intersection).sub(_worldPosition.setFromMatrixPosition(_selected.matrixWorld)); |
||||
|
} |
||||
|
|
||||
|
_domElement.style.cursor = 'move'; |
||||
|
} |
||||
|
scope.dispatchEvent( { type: 'dragstart', object: _selected,e:event } ); |
||||
|
} |
||||
|
|
||||
|
isMove = false; |
||||
|
} |
||||
|
|
||||
|
function onPointerCancel(event) { |
||||
|
if ( scope.enabled === false ) return; |
||||
|
|
||||
|
if ( _selected ) { |
||||
|
scope.dispatchEvent( { type: 'dragend', object: _selected,e:event } ); |
||||
|
_selected = null; |
||||
|
}else if(!isMove){ |
||||
|
// 添加点击空白处的事件
|
||||
|
scope.dispatchEvent( { type: 'clickblank',e:event } ); |
||||
|
} |
||||
|
|
||||
|
_domElement.style.cursor = _hovered ? 'pointer' : 'auto'; |
||||
|
} |
||||
|
|
||||
|
function updatePointer( event ) { |
||||
|
const rect = _domElement.getBoundingClientRect(); |
||||
|
|
||||
|
_pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1; |
||||
|
_pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1; |
||||
|
} |
||||
|
|
||||
|
activate(); |
||||
|
|
||||
|
// API
|
||||
|
|
||||
|
this.enabled = true; |
||||
|
this.enabledMove = true; |
||||
|
this.transformGroup = false; |
||||
|
|
||||
|
this.activate = activate; |
||||
|
this.deactivate = deactivate; |
||||
|
this.dispose = dispose; |
||||
|
this.setObjects = setObjects; |
||||
|
this.getObjects = getObjects; |
||||
|
this.getRaycaster = getRaycaster; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
export { DragControls }; |
||||
@ -0,0 +1,129 @@ |
|||||
|
import { DragControls } from './DragControls.js' |
||||
|
import * as THREE from 'three' |
||||
|
import type Viewport from '@/designer/Viewport.ts' |
||||
|
|
||||
|
// dragControls 绑定函数
|
||||
|
let dragStartFn, dragFn, dragEndFn, clickblankFn |
||||
|
|
||||
|
export default class EsDragControls { |
||||
|
protected _dragObjects: THREE.Object3D[] = [] // 拖拽对象
|
||||
|
dragControls: any |
||||
|
private onDownPosition: { x: number; y: number } = { x: -1, y: -1 } |
||||
|
|
||||
|
viewport: Viewport |
||||
|
isDragging = false |
||||
|
|
||||
|
constructor(viewport) { |
||||
|
this.viewport = viewport |
||||
|
|
||||
|
// 物体拖拽控制器
|
||||
|
this.dragControls = new DragControls(this._dragObjects, viewport.camera, viewport.renderer.domElement) |
||||
|
this.dragControls.deactivate() // 默认禁用
|
||||
|
dragStartFn = this.dragControlsStart.bind(this) |
||||
|
this.dragControls.addEventListener('dragstart', dragStartFn) |
||||
|
dragFn = this.drag.bind(this) |
||||
|
this.dragControls.addEventListener('drag', dragFn) |
||||
|
dragEndFn = this.dragControlsEnd.bind(this) |
||||
|
this.dragControls.addEventListener('dragend', dragEndFn) |
||||
|
// 点击可拖拽物体之外
|
||||
|
clickblankFn = this.clickblank.bind(this) |
||||
|
this.dragControls.addEventListener('clickblank', clickblankFn) |
||||
|
} |
||||
|
|
||||
|
set domElement(element: HTMLElement) { |
||||
|
this.dragControls.setDomElement(element) |
||||
|
} |
||||
|
|
||||
|
setDragObjects(objects: THREE.Object3D[], type: 'eq' | 'push' | 'remove' = 'eq') { |
||||
|
// 当前拖拽对象为空时加入对象需激活控制器
|
||||
|
if (this._dragObjects.length === 0) { |
||||
|
if (objects.length > 0) { |
||||
|
this.dragControls.activate() |
||||
|
} |
||||
|
|
||||
|
this._dragObjects = objects |
||||
|
} else { |
||||
|
// 当前拖拽对象不为空时
|
||||
|
if (type === 'eq') { |
||||
|
// 是清空拖拽对象的设置,则禁用控制器
|
||||
|
if (objects.length === 0) { |
||||
|
this.dragControls.deactivate() |
||||
|
} |
||||
|
|
||||
|
this._dragObjects = objects |
||||
|
} else if (type === 'push') { |
||||
|
this._dragObjects.push(...objects) |
||||
|
} else if (type === 'remove') { |
||||
|
this._dragObjects = this._dragObjects.filter((item) => !objects.includes(item)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.dragControls.setObjects(this._dragObjects) |
||||
|
} |
||||
|
|
||||
|
// 拖拽开始
|
||||
|
dragControlsStart(e) { |
||||
|
// 右键拖拽不响应
|
||||
|
if (e.e.button === 2 || !e.object.userData.type || !e.object.visible) return |
||||
|
|
||||
|
e.e.preventDefault() |
||||
|
|
||||
|
// 拖拽时禁用其他控制器
|
||||
|
this.viewport.controls.enabled = false |
||||
|
|
||||
|
this.isDragging = true |
||||
|
|
||||
|
// 记录拖拽按下的位置和对象
|
||||
|
this.onDownPosition = { x: e.e.clientX, y: e.e.clientY } |
||||
|
|
||||
|
// switch (e.object.userData.type) {
|
||||
|
// case 'measure-marker':
|
||||
|
// this.viewport.modules.measure.redraw(e.object)
|
||||
|
// break
|
||||
|
// }
|
||||
|
} |
||||
|
|
||||
|
// 拖拽中
|
||||
|
drag(e) { |
||||
|
this.viewport.dispatchSignal('objectChanged', e.object) |
||||
|
} |
||||
|
|
||||
|
// 拖拽结束
|
||||
|
dragControlsEnd(e) { |
||||
|
// 右键拖拽不响应
|
||||
|
if (e.e.button === 2 || !e.object.visible) return |
||||
|
|
||||
|
// 拖拽结束启用其他控制器
|
||||
|
this.viewport.controls.enabled = true |
||||
|
|
||||
|
this.isDragging = false |
||||
|
|
||||
|
if (!e.object.userData.type) return |
||||
|
|
||||
|
// 判断位置是否有变化,没有变化则为点击
|
||||
|
if (this.onDownPosition.x === e.e.clientX && this.onDownPosition.y === e.e.clientY) { |
||||
|
if (e.object.userData.onClick) { |
||||
|
e.object.userData.onClick(e) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// switch (e.object.userData.type) {
|
||||
|
// case 'measure-marker':
|
||||
|
// this.viewport.modules.measure.redrawComplete()
|
||||
|
// break
|
||||
|
// }
|
||||
|
} |
||||
|
|
||||
|
// 点击可拖拽物体之外
|
||||
|
clickblank(e) { |
||||
|
if (e.e.button === 2) return |
||||
|
} |
||||
|
|
||||
|
dispose() { |
||||
|
this._dragObjects = [] |
||||
|
|
||||
|
this.dragControls.removeEventListener('dragstart', dragStartFn) |
||||
|
this.dragControls.removeEventListener('dragend', dragEndFn) |
||||
|
this.dragControls.dispose() |
||||
|
} |
||||
|
} |
||||
@ -1,29 +0,0 @@ |
|||||
import type { ITool } from '@/designer/model2DEditor/tools/ITool.ts' |
|
||||
import Viewport from '@/designer/Viewport.ts' |
|
||||
|
|
||||
export default class RulerInspect implements ITool { |
|
||||
viewport: Viewport |
|
||||
|
|
||||
mouseMove(event: MouseEvent) { |
|
||||
const viewer = document.querySelector('.viewer') as HTMLElement |
|
||||
const rect = viewer.getBoundingClientRect() |
|
||||
|
|
||||
const mouseX = event.clientX - rect.left |
|
||||
const mouseY = event.clientY - rect.top |
|
||||
|
|
||||
console.log(`Mouse Position: (${mouseX}, ${mouseY})`) |
|
||||
} |
|
||||
|
|
||||
init(viewport: Viewport) { |
|
||||
this.viewport = viewport |
|
||||
const viewerDom = this.viewport.viewerDom |
|
||||
|
|
||||
system.msg('进入鼠标测距模式') |
|
||||
} |
|
||||
|
|
||||
destory(): void { |
|
||||
const viewerDom = this.viewport.viewerDom |
|
||||
viewerDom.removeEventListener('mousemove', this.mouseMove) |
|
||||
system.msg('退出鼠标测距模式') |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,318 @@ |
|||||
|
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 { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' |
||||
|
import { Vector3 } from 'three' |
||||
|
|
||||
|
let pdFn, pmFn, puFn, kdFn |
||||
|
|
||||
|
export default class RulerTool implements ITool { |
||||
|
static OBJ_NAME = 'object_for_measure' |
||||
|
static LABEL_NAME = 'label_for_measure' |
||||
|
static MAX_DISTANCE = 500 //当相交物体的距离太远时,忽略它
|
||||
|
|
||||
|
viewport: Viewport |
||||
|
// 当前测绘内容组
|
||||
|
group: THREE.Group |
||||
|
isCompleted = false |
||||
|
mouseMoved = false |
||||
|
canvas: HTMLCanvasElement |
||||
|
|
||||
|
// 用户在测量时绘制的线的当前实例
|
||||
|
protected polyline?: THREE.Line |
||||
|
|
||||
|
// 用于存储临时点
|
||||
|
protected tempPointMarker?: THREE.Mesh |
||||
|
|
||||
|
// 用于存储临时线条,用于在鼠标移动时绘制线条/区域/角度
|
||||
|
protected tempLine?: THREE.Line |
||||
|
|
||||
|
// 用于在鼠标移动时存储临时标签,只有测量距离时才有
|
||||
|
protected tempLabel?: CSS2DObject |
||||
|
|
||||
|
// 存储点
|
||||
|
protected pointArray: THREE.Vector3[] = [] |
||||
|
|
||||
|
//保存上次点击时间,以便检测双击事件
|
||||
|
protected lastClickTime: number = 0 |
||||
|
|
||||
|
|
||||
|
static LINE_MATERIAL = new THREE.LineBasicMaterial({ |
||||
|
color: 0xE63C17, |
||||
|
linewidth: 2, |
||||
|
opacity: 0.9, |
||||
|
transparent: true, |
||||
|
side: THREE.DoubleSide, |
||||
|
depthWrite: false, |
||||
|
depthTest: false |
||||
|
}) |
||||
|
|
||||
|
init(viewport: Viewport) { |
||||
|
this.viewport = viewport |
||||
|
const viewerDom = this.viewport.viewerDom |
||||
|
this.canvas = $(viewerDom).children('canvas')[0] as HTMLCanvasElement |
||||
|
|
||||
|
pdFn = this.mousedown.bind(this) |
||||
|
this.canvas.addEventListener('pointerdown', pdFn) |
||||
|
pmFn = this.mousemove.bind(this) |
||||
|
this.canvas.addEventListener('pointermove', pmFn) |
||||
|
puFn = this.mouseup.bind(this) |
||||
|
this.canvas.addEventListener('pointerup', puFn) |
||||
|
|
||||
|
// 初始化group
|
||||
|
this.group = new THREE.Group() |
||||
|
this.group.name = `${RulerTool.OBJ_NAME}_group` |
||||
|
this.group.userData = { |
||||
|
mode: this.viewport.state.cursorMode |
||||
|
} |
||||
|
this.viewport.scene.add(this.group) |
||||
|
|
||||
|
// 测量距离、面积和角度需要折线
|
||||
|
this.polyline = this.createLine() |
||||
|
this.group.add(this.polyline) |
||||
|
this.isCompleted = false |
||||
|
this.viewport.viewerDom.style.cursor = 'crosshair' |
||||
|
|
||||
|
// 当次绘制点
|
||||
|
this.pointArray = [] |
||||
|
|
||||
|
// 测量距离、面积和角度需要折线
|
||||
|
this.polyline = this.createLine() |
||||
|
this.group.add(this.polyline) |
||||
|
|
||||
|
this.viewport.viewerDom.style.cursor = 'crosshair' |
||||
|
|
||||
|
system.msg('进入鼠标测距模式') |
||||
|
} |
||||
|
|
||||
|
|
||||
|
destory(): void { |
||||
|
system.msg('退出鼠标测距模式') |
||||
|
|
||||
|
const viewerDom = this.viewport.viewerDom |
||||
|
|
||||
|
this.isCompleted = true |
||||
|
viewerDom.style.cursor = '' |
||||
|
|
||||
|
this.canvas.removeEventListener('pointerdown', pdFn) |
||||
|
pdFn = undefined |
||||
|
this.canvas.removeEventListener('pointermove', pmFn) |
||||
|
pmFn = undefined |
||||
|
this.canvas.removeEventListener('pointerup', puFn) |
||||
|
puFn = undefined |
||||
|
|
||||
|
this.tempPointMarker && this.viewport.scene.remove(this.tempPointMarker) |
||||
|
this.tempLine && this.viewport.scene.remove(this.tempLine) |
||||
|
this.tempLabel && this.viewport.scene.remove(this.tempLabel) |
||||
|
this.tempPointMarker = undefined |
||||
|
this.tempLine = undefined |
||||
|
this.tempLabel = undefined |
||||
|
} |
||||
|
|
||||
|
mousedown = () => { |
||||
|
this.mouseMoved = false |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// 鼠标移动,创建对应的临时点与线
|
||||
|
mousemove = (e: MouseEvent) => { |
||||
|
if (this.isCompleted) return |
||||
|
|
||||
|
this.mouseMoved = true |
||||
|
|
||||
|
const point = this.getClosestIntersection(e) |
||||
|
if (!point) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// 在鼠标移动时绘制临时点
|
||||
|
if (this.tempPointMarker) { |
||||
|
this.tempPointMarker.position.set(point.x, point.y, point.z) |
||||
|
} else { |
||||
|
this.tempPointMarker = this.createPointMarker(point) |
||||
|
this.viewport.scene.add(this.tempPointMarker) |
||||
|
} |
||||
|
|
||||
|
// 移动时绘制临时线
|
||||
|
if (this.pointArray.length > 0) { |
||||
|
const p0 = this.pointArray[this.pointArray.length - 1] // 获取最后一个点
|
||||
|
const line = this.tempLine || this.createLine() |
||||
|
const geom = line.geometry |
||||
|
const startPoint = this.pointArray[0] |
||||
|
const lastPoint = this.pointArray[this.pointArray.length - 1] |
||||
|
if (this.viewport.state.cursorMode === 'RulerArea') { |
||||
|
geom.setFromPoints([lastPoint, point, startPoint]) |
||||
|
} else { |
||||
|
geom.setFromPoints([lastPoint, point]) |
||||
|
} |
||||
|
if (this.viewport.state.cursorMode === 'Ruler') { |
||||
|
const dist = p0.distanceTo(point) |
||||
|
const label = `${numberToString(dist)} ${getUnitString(this.viewport.state.cursorMode)}` |
||||
|
const position = new THREE.Vector3((point.x + p0.x) / 2, (point.y + p0.y) / 2, (point.z + p0.z) / 2) |
||||
|
this.addOrUpdateTempLabel(label, position) |
||||
|
} |
||||
|
// tempLine 只需添加到场景一次
|
||||
|
if (!this.tempLine) { |
||||
|
this.viewport.scene.add(line) |
||||
|
this.tempLine = line |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// this.viewport.dispatchSignal('sceneGraphChanged')
|
||||
|
} |
||||
|
|
||||
|
mouseup = (e: MouseEvent) => { |
||||
|
// 如果mouseMoved是true,那么它可能在移动,而不是点击
|
||||
|
if (!this.mouseMoved) { |
||||
|
// 右键点击表示完成绘图操作
|
||||
|
if (e.button === 2) { |
||||
|
this.viewport.state.cursorMode = 'normal' |
||||
|
|
||||
|
} else if (e.button === 0) { // 左键点击表示添加点
|
||||
|
this.onMouseClicked(e) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMouseClicked = (e: MouseEvent) => { |
||||
|
if (this.isCompleted) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
const point = this.getClosestIntersection(e) |
||||
|
if (!point) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// 双击触发两次点击事件,我们需要避免这里的第二次点击
|
||||
|
const now = Date.now() |
||||
|
if (this.lastClickTime && (now - this.lastClickTime < 100)) return |
||||
|
|
||||
|
this.lastClickTime = now |
||||
|
|
||||
|
this.pointArray.push(point) |
||||
|
console.log('pointArray', this.pointArray) |
||||
|
|
||||
|
const count = this.pointArray.length |
||||
|
const marker = this.createPointMarker(point) |
||||
|
marker.userData.point = point |
||||
|
marker.userData.pointIndex = count - 1 |
||||
|
this.group.add(marker) |
||||
|
// 把点加入拖拽控制器
|
||||
|
this.viewport.dragControl.setDragObjects([marker], 'push') |
||||
|
|
||||
|
if (this.polyline) { |
||||
|
this.polyline.geometry.setFromPoints(this.pointArray) |
||||
|
if (this.tempLabel && count > 1) { |
||||
|
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.group.add(this.tempLabel) |
||||
|
|
||||
|
// 创建距离测量线时,此处的 临时label 将作为正式的使用,不在this.clearTemp()中清除,故置为undefined
|
||||
|
this.tempLabel = undefined |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// this.viewport.dispatchSignal('sceneGraphChanged')
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Creates THREE.Line |
||||
|
*/ |
||||
|
private createLine(): THREE.Line { |
||||
|
const geom = new THREE.BufferGeometry() |
||||
|
const obj = new THREE.Line(geom, RulerTool.LINE_MATERIAL) |
||||
|
obj.frustumCulled = false |
||||
|
obj.name = RulerTool.OBJ_NAME |
||||
|
obj.userData = { |
||||
|
type: 'line' |
||||
|
} |
||||
|
return obj |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建点标记 |
||||
|
*/ |
||||
|
createPointMarker(position?: THREE.Vector3): THREE.Mesh { |
||||
|
const p = position |
||||
|
const scale = 0.25 |
||||
|
|
||||
|
const tt = new THREE.BoxGeometry(1, 1, 1) |
||||
|
const t2 = new THREE.MeshBasicMaterial({ color: 0x303133, transparent: true, opacity: 0.9 }) |
||||
|
const obj = new THREE.Mesh(tt, t2) |
||||
|
obj.scale.set(scale, 0.1, scale) |
||||
|
if (p) { |
||||
|
obj.position.set(p.x, p.y, p.z) |
||||
|
} |
||||
|
|
||||
|
obj.name = RulerTool.OBJ_NAME |
||||
|
|
||||
|
obj.userData = { |
||||
|
mode: this.viewport.state.cursorMode, |
||||
|
type: 'measure-marker' |
||||
|
} |
||||
|
return obj |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取按下对应三维位置 |
||||
|
*/ |
||||
|
getClosestIntersection(e: MouseEvent) { |
||||
|
const _point = new THREE.Vector2() |
||||
|
_point.x = e.offsetX / this.viewport.renderer.domElement.offsetWidth |
||||
|
_point.y = e.offsetY / this.viewport.renderer.domElement.offsetHeight |
||||
|
|
||||
|
const intersects = this.viewport.getIntersects(_point) |
||||
|
if (intersects && intersects.length > 2) { |
||||
|
if (intersects.length > 0 && intersects[0].distance < RulerTool.MAX_DISTANCE) { |
||||
|
return new Vector3( |
||||
|
intersects[0].point.x, |
||||
|
0.1, |
||||
|
intersects[1].point.z |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 添加或更新临时标签和位置 |
||||
|
*/ |
||||
|
addOrUpdateTempLabel(label: string, position: THREE.Vector3) { |
||||
|
if (!this.tempLabel) { |
||||
|
this.tempLabel = this.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 = RulerTool.LABEL_NAME |
||||
|
obj.userData = { |
||||
|
type: 'label' |
||||
|
} |
||||
|
return obj |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
type CursorMode = |
||||
|
'normal' |
||||
|
| 'ALink' |
||||
|
| 'SLink' |
||||
|
| 'PointCallback' |
||||
|
| 'PointAdd' |
||||
|
| 'LinkAdd' |
||||
|
| 'LinkAdd2' |
||||
|
| 'Ruler' |
||||
|
| 'RulerArea' |
||||
|
| 'RulerAngle' |
||||
|
| 'selectByRec' |
||||
Loading…
Reference in new issue