13 changed files with 394 additions and 616 deletions
@ -1,211 +1,214 @@ |
|||||
import { |
import { |
||||
EventDispatcher, |
EventDispatcher, |
||||
Matrix4, |
Matrix4, |
||||
Plane, |
Plane, |
||||
Raycaster, |
Raycaster, |
||||
Vector2, |
Vector2, |
||||
Vector3 |
Vector3 |
||||
} from 'three'; |
} from 'three' |
||||
|
import { calcPositionUseSnap } from '@/model/ModelUtils.js' |
||||
const _plane = new Plane(); |
|
||||
const _raycaster = new Raycaster(); |
const _plane = new Plane() |
||||
|
const _raycaster = new Raycaster() |
||||
const _pointer = new Vector2(); |
|
||||
const _offset = new Vector3(); |
const _pointer = new Vector2() |
||||
const _intersection = new Vector3(); |
const _offset = new Vector3() |
||||
const _worldPosition = new Vector3(); |
const _intersection = new Vector3() |
||||
const _inverseMatrix = new Matrix4(); |
const _worldPosition = new Vector3() |
||||
|
const _inverseMatrix = new Matrix4() |
||||
|
|
||||
class DragControls extends EventDispatcher { |
class DragControls extends EventDispatcher { |
||||
constructor( _objects, _camera, _domElement ) { |
constructor(_objects, _camera, _domElement) { |
||||
super(); |
super() |
||||
|
|
||||
_domElement.style.touchAction = 'none'; // disable touch scroll
|
_domElement.style.touchAction = 'none' // disable touch scroll
|
||||
|
|
||||
let _selected = null, _hovered = null; |
let _selected = null, _hovered = null |
||||
|
|
||||
const _intersections = []; |
const _intersections = [] |
||||
|
|
||||
//
|
//
|
||||
|
|
||||
let isMove = false; |
let isMove = false |
||||
|
|
||||
const scope = this; |
const scope = this |
||||
|
|
||||
function activate() { |
function activate() { |
||||
_domElement.addEventListener( 'pointermove', onPointerMove ); |
_domElement.addEventListener('pointermove', onPointerMove) |
||||
_domElement.addEventListener( 'pointerdown', onPointerDown ); |
_domElement.addEventListener('pointerdown', onPointerDown) |
||||
_domElement.addEventListener( 'pointerup', onPointerCancel ); |
_domElement.addEventListener('pointerup', onPointerCancel) |
||||
_domElement.addEventListener( 'pointerleave', onPointerCancel ); |
_domElement.addEventListener('pointerleave', onPointerCancel) |
||||
} |
} |
||||
|
|
||||
function deactivate() { |
function deactivate() { |
||||
_domElement.removeEventListener( 'pointermove', onPointerMove ); |
_domElement.removeEventListener('pointermove', onPointerMove) |
||||
_domElement.removeEventListener( 'pointerdown', onPointerDown ); |
_domElement.removeEventListener('pointerdown', onPointerDown) |
||||
_domElement.removeEventListener( 'pointerup', onPointerCancel ); |
_domElement.removeEventListener('pointerup', onPointerCancel) |
||||
_domElement.removeEventListener( 'pointerleave', onPointerCancel ); |
_domElement.removeEventListener('pointerleave', onPointerCancel) |
||||
|
|
||||
_domElement.style.cursor = ''; |
_domElement.style.cursor = '' |
||||
} |
} |
||||
|
|
||||
function dispose() { |
function dispose() { |
||||
deactivate(); |
deactivate() |
||||
} |
} |
||||
|
|
||||
function setObjects( objects ) { |
function setObjects(objects) { |
||||
_objects = objects; |
_objects = objects |
||||
} |
} |
||||
|
|
||||
function getObjects() { |
function getObjects() { |
||||
return _objects; |
return _objects |
||||
} |
} |
||||
|
|
||||
function getRaycaster() { |
function getRaycaster() { |
||||
return _raycaster; |
return _raycaster |
||||
} |
} |
||||
|
|
||||
function onPointerMove( event ) { |
function onPointerMove(event) { |
||||
|
|
||||
if ( !scope.enabled || !scope.enabledMove) return; |
if (!scope.enabled || !scope.enabledMove) return |
||||
|
|
||||
isMove = true; |
isMove = true |
||||
|
|
||||
updatePointer( event ); |
updatePointer(event) |
||||
|
|
||||
_raycaster.setFromCamera( _pointer, _camera ); |
_raycaster.setFromCamera(_pointer, _camera) |
||||
|
|
||||
if ( _selected ) { |
if (_selected) { |
||||
|
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
if (_raycaster.ray.intersectPlane(_plane, _intersection)) { |
||||
|
|
||||
_selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) ); |
const pos = _intersection.sub(_offset).applyMatrix4(_inverseMatrix) |
||||
|
const newIntersection = calcPositionUseSnap(event, pos) |
||||
|
_selected.position.copy(newIntersection) |
||||
|
|
||||
} |
} |
||||
|
|
||||
scope.dispatchEvent( { type: 'drag', object: _selected } ); |
scope.dispatchEvent({ type: 'drag', object: _selected }) |
||||
|
|
||||
return; |
return |
||||
|
|
||||
} |
} |
||||
|
|
||||
// hover support
|
// hover support
|
||||
|
|
||||
if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) { |
if (event.pointerType === 'mouse' || event.pointerType === 'pen') { |
||||
|
|
||||
_intersections.length = 0; |
_intersections.length = 0 |
||||
|
|
||||
_raycaster.setFromCamera( _pointer, _camera ); |
_raycaster.setFromCamera(_pointer, _camera) |
||||
_raycaster.intersectObjects( _objects, true, _intersections ); |
_raycaster.intersectObjects(_objects, true, _intersections) |
||||
|
|
||||
if ( _intersections.length > 0 ) { |
if (_intersections.length > 0) { |
||||
|
|
||||
const object = _intersections[ 0 ].object; |
const object = _intersections[0].object |
||||
|
|
||||
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) ); |
_plane.setFromNormalAndCoplanarPoint(_camera.getWorldDirection(_plane.normal), _worldPosition.setFromMatrixPosition(object.matrixWorld)) |
||||
|
|
||||
if ( _hovered !== object && _hovered !== null ) { |
if (_hovered !== object && _hovered !== null) { |
||||
|
|
||||
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
scope.dispatchEvent({ type: 'hoveroff', object: _hovered }) |
||||
|
|
||||
_domElement.style.cursor = 'auto'; |
_domElement.style.cursor = 'auto' |
||||
_hovered = null; |
_hovered = null |
||||
|
|
||||
} |
} |
||||
|
|
||||
if ( _hovered !== object ) { |
if (_hovered !== object) { |
||||
|
|
||||
scope.dispatchEvent( { type: 'hoveron', object: object } ); |
scope.dispatchEvent({ type: 'hoveron', object: object }) |
||||
|
|
||||
_domElement.style.cursor = 'pointer'; |
_domElement.style.cursor = 'pointer' |
||||
_hovered = object; |
_hovered = object |
||||
|
|
||||
} |
} |
||||
|
|
||||
} else { |
} else { |
||||
|
|
||||
if ( _hovered !== null ) { |
if (_hovered !== null) { |
||||
|
|
||||
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
scope.dispatchEvent({ type: 'hoveroff', object: _hovered }) |
||||
|
|
||||
_domElement.style.cursor = 'auto'; |
_domElement.style.cursor = 'auto' |
||||
_hovered = null; |
_hovered = null |
||||
|
|
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|
||||
function onPointerDown( event ) { |
function onPointerDown(event) { |
||||
if (scope.enabled === false) return; |
if (scope.enabled === false) return |
||||
|
|
||||
updatePointer(event); |
updatePointer(event) |
||||
|
|
||||
_intersections.length = 0; |
_intersections.length = 0 |
||||
|
|
||||
_raycaster.setFromCamera( _pointer, _camera ); |
_raycaster.setFromCamera(_pointer, _camera) |
||||
let objects = _objects; |
let objects = _objects |
||||
|
|
||||
_raycaster.intersectObjects( objects, true, _intersections ); |
_raycaster.intersectObjects(objects, true, _intersections) |
||||
|
|
||||
if (_intersections.length > 0) { |
if (_intersections.length > 0) { |
||||
_selected = (scope.transformGroup === true) ? _objects[ 0 ] : _intersections[0].object; |
_selected = (scope.transformGroup === true) ? _objects[0] : _intersections[0].object |
||||
|
|
||||
if(scope.enabledMove) { |
if (scope.enabledMove) { |
||||
_plane.setFromNormalAndCoplanarPoint(_camera.getWorldDirection(_plane.normal), _worldPosition.setFromMatrixPosition(_selected.matrixWorld)); |
_plane.setFromNormalAndCoplanarPoint(_camera.getWorldDirection(_plane.normal), _worldPosition.setFromMatrixPosition(_selected.matrixWorld)) |
||||
if (_raycaster.ray.intersectPlane(_plane, _intersection)) { |
if (_raycaster.ray.intersectPlane(_plane, _intersection)) { |
||||
_inverseMatrix.copy(_selected.parent.matrixWorld).invert(); |
_inverseMatrix.copy(_selected.parent.matrixWorld).invert() |
||||
_offset.copy(_intersection).sub(_worldPosition.setFromMatrixPosition(_selected.matrixWorld)); |
_offset.copy(_intersection).sub(_worldPosition.setFromMatrixPosition(_selected.matrixWorld)) |
||||
} |
} |
||||
|
|
||||
_domElement.style.cursor = 'move'; |
_domElement.style.cursor = 'move' |
||||
} |
} |
||||
scope.dispatchEvent( { type: 'dragstart', object: _selected,e:event } ); |
scope.dispatchEvent({ type: 'dragstart', object: _selected, e: event }) |
||||
} |
} |
||||
|
|
||||
isMove = false; |
isMove = false |
||||
} |
} |
||||
|
|
||||
function onPointerCancel(event) { |
function onPointerCancel(event) { |
||||
if ( scope.enabled === false ) return; |
if (scope.enabled === false) return |
||||
|
|
||||
if ( _selected ) { |
if (_selected) { |
||||
scope.dispatchEvent( { type: 'dragend', object: _selected,e:event } ); |
scope.dispatchEvent({ type: 'dragend', object: _selected, e: event }) |
||||
_selected = null; |
_selected = null |
||||
}else if(!isMove){ |
} else if (!isMove) { |
||||
// 添加点击空白处的事件
|
// 添加点击空白处的事件
|
||||
scope.dispatchEvent( { type: 'clickblank',e:event } ); |
scope.dispatchEvent({ type: 'clickblank', e: event }) |
||||
} |
} |
||||
|
|
||||
_domElement.style.cursor = _hovered ? 'pointer' : 'auto'; |
_domElement.style.cursor = _hovered ? 'pointer' : 'auto' |
||||
} |
} |
||||
|
|
||||
function updatePointer( event ) { |
function updatePointer(event) { |
||||
const rect = _domElement.getBoundingClientRect(); |
const rect = _domElement.getBoundingClientRect() |
||||
|
|
||||
_pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1; |
_pointer.x = (event.clientX - rect.left) / rect.width * 2 - 1 |
||||
_pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1; |
_pointer.y = -(event.clientY - rect.top) / rect.height * 2 + 1 |
||||
} |
} |
||||
|
|
||||
activate(); |
activate() |
||||
|
|
||||
// API
|
// API
|
||||
|
|
||||
this.enabled = true; |
this.enabled = true |
||||
this.enabledMove = true; |
this.enabledMove = true |
||||
this.transformGroup = false; |
this.transformGroup = false |
||||
|
|
||||
this.activate = activate; |
this.activate = activate |
||||
this.deactivate = deactivate; |
this.deactivate = deactivate |
||||
this.dispose = dispose; |
this.dispose = dispose |
||||
this.setObjects = setObjects; |
this.setObjects = setObjects |
||||
this.getObjects = getObjects; |
this.getObjects = getObjects |
||||
this.getRaycaster = getRaycaster; |
this.getRaycaster = getRaycaster |
||||
|
|
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|
||||
export { DragControls }; |
export { DragControls } |
||||
|
|||||
@ -1,22 +0,0 @@ |
|||||
export interface ICursorTool { |
|
||||
|
|
||||
/** |
|
||||
* 初始化工具 |
|
||||
*/ |
|
||||
init(viewport: any): void |
|
||||
|
|
||||
/** |
|
||||
* 开始运行工具, 进入 cursor 状态 |
|
||||
*/ |
|
||||
start(): void |
|
||||
|
|
||||
/** |
|
||||
* 停止运行工具, 鼠标点击右键, 或者 ESC 退出 cursor 状态 |
|
||||
*/ |
|
||||
stop(): void |
|
||||
|
|
||||
/** |
|
||||
* 销毁工具, 释放资源 |
|
||||
*/ |
|
||||
destory():void |
|
||||
} |
|
||||
@ -1,321 +0,0 @@ |
|||||
import * as THREE from 'three' |
|
||||
import Viewport from '@/designer/Viewport.ts' |
|
||||
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 { LINE_NAME } from '@/model/itemType/measure/Measure.ts' |
|
||||
import type { ItemJson } from '@/model/itemType/ItemTypeDefine.ts' |
|
||||
|
|
||||
let pdFn, pmFn, puFn, kdFn |
|
||||
|
|
||||
const TEMP_POINT_NAME = '_measure_temp_point' |
|
||||
const TMP_LABEL_NAME = '_measure_temp_label' |
|
||||
const TMP_TYPE = '_TMP' |
|
||||
|
|
||||
/** |
|
||||
* 用于在 threejs 中创建一系列的 object_for_measure 点,并标记他的距离 |
|
||||
*/ |
|
||||
export default class MeasureTool implements ICursorTool { |
|
||||
/** |
|
||||
* 测量工具所在的视图窗口,从这里可以取到 所有 Three.js 相关的对象. |
|
||||
* 比如: |
|
||||
* - viewport.scene 场景 |
|
||||
* - viewport.renderer 渲染器 |
|
||||
* - viewport.controls 控制器 |
|
||||
* - viewport.camera 摄像机 |
|
||||
* - viewport.raycaster 射线投射器 |
|
||||
* - viewport.dragControl 拖拽控制器 |
|
||||
* - viewport.measure 测量工具 |
|
||||
*/ |
|
||||
viewport: Viewport |
|
||||
|
|
||||
/** |
|
||||
* 当前测绘内容组, 所有测量点、线、标签都在这个组中. 但不包括临时点、线 |
|
||||
*/ |
|
||||
measure: Measure |
|
||||
|
|
||||
/** |
|
||||
* 是否完成测量 |
|
||||
*/ |
|
||||
isCompleted = false |
|
||||
/** |
|
||||
* 是否鼠标移动事件 |
|
||||
*/ |
|
||||
mouseMoved = false |
|
||||
|
|
||||
/** |
|
||||
* 当前鼠标所在的画布, 对应 viewport.renderer.domElement |
|
||||
*/ |
|
||||
canvas: HTMLCanvasElement |
|
||||
|
|
||||
/** |
|
||||
* 用于存储临时点 |
|
||||
*/ |
|
||||
tempPointMarker?: THREE.Mesh |
|
||||
|
|
||||
/** |
|
||||
* 临时线条 |
|
||||
*/ |
|
||||
tempLine?: THREE.Line |
|
||||
|
|
||||
/** |
|
||||
* 临时标签对象, 用于在鼠标移动时显示距离 |
|
||||
*/ |
|
||||
tempLabel?: CSS2DObject |
|
||||
|
|
||||
/** |
|
||||
* 保存上次点击时间,以便检测双击事件 |
|
||||
* @protected |
|
||||
*/ |
|
||||
lastClickTime: number = 0 |
|
||||
|
|
||||
/** |
|
||||
* 测量起始点 |
|
||||
*/ |
|
||||
startPoint?: THREE.Object3D = undefined |
|
||||
|
|
||||
/** |
|
||||
* 上次鼠标移动位置 |
|
||||
*/ |
|
||||
lastMovePosition: THREE.Vector3 | undefined = undefined |
|
||||
|
|
||||
mode: CursorMode |
|
||||
|
|
||||
/** |
|
||||
* 测量工具初始化 |
|
||||
*/ |
|
||||
init(viewport: Viewport) { |
|
||||
this.viewport = viewport |
|
||||
this.canvas = this.viewport.renderer.domElement as HTMLCanvasElement |
|
||||
|
|
||||
this.measure = getItemTypeByName('measure')!.clazz |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 测量工具开始, 监听鼠标事件, 变量初始化等 |
|
||||
*/ |
|
||||
start(startPoint?: THREE.Object3D) { |
|
||||
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) |
|
||||
|
|
||||
this.isCompleted = false |
|
||||
this.viewport.viewerDom.style.cursor = 'crosshair' |
|
||||
|
|
||||
this.mode = this.viewport.state.cursorMode |
|
||||
this.startPoint = startPoint |
|
||||
|
|
||||
system.msg('进入测量模式') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 停止测量模式, 清除所有临时点、线、标签. 停止所有鼠标事件监听 |
|
||||
*/ |
|
||||
stop(): 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 |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 销毁测量工具, 当视图窗口被销毁时调用 |
|
||||
*/ |
|
||||
destory() { |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 鼠标按下事件 |
|
||||
*/ |
|
||||
mousedown() { |
|
||||
this.mouseMoved = false |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 鼠标移动,创建对应的临时点与线 |
|
||||
*/ |
|
||||
mousemove(e: MouseEvent) { |
|
||||
if (this.isCompleted) return |
|
||||
|
|
||||
this.mouseMoved = true |
|
||||
|
|
||||
// 当前鼠标所在的点
|
|
||||
const point = this.viewport.getClosestIntersection(e) |
|
||||
if (!point) { |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
this.lastMovePosition = point |
|
||||
|
|
||||
// 在鼠标移动时绘制临时点
|
|
||||
if (this.tempPointMarker) { |
|
||||
this.tempPointMarker.position.set(point.x, point.y, point.z) |
|
||||
} else { |
|
||||
this.tempPointMarker = this.createTempPointMarker(point) |
|
||||
this.viewport.scene.add(this.tempPointMarker) |
|
||||
} |
|
||||
|
|
||||
// 移动时绘制临时线
|
|
||||
if (this.startPoint) { |
|
||||
// 获取最后一个点
|
|
||||
if (!this.tempLine) { |
|
||||
this.tempLine = this.measure.createLineBasic() |
|
||||
this.viewport.scene.add(this.tempLine) |
|
||||
} |
|
||||
|
|
||||
const p0 = this.startPoint.position |
|
||||
const line = this.tempLine |
|
||||
const geom = line.geometry |
|
||||
geom.setFromPoints([p0, point]) |
|
||||
|
|
||||
const dist = p0.distanceTo(point) |
|
||||
const label = `${numberToString(dist)} ${getUnitString(this.mode)}` |
|
||||
const position = new THREE.Vector3().addVectors(p0, point).multiplyScalar(0.5) |
|
||||
this.addOrUpdateTempLabel(label, position) |
|
||||
} |
|
||||
|
|
||||
// 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) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private onMouseClicked(e: MouseEvent) { |
|
||||
if (this.isCompleted) { |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
// 获取鼠标点击位置的三维坐标
|
|
||||
const point = this.lastMovePosition |
|
||||
if (!point) { |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
// 双击触发两次点击事件,我们需要避免这里的第二次点击
|
|
||||
const now = Date.now() |
|
||||
if (this.lastClickTime && (now - this.lastClickTime < 50)) { |
|
||||
return |
|
||||
} |
|
||||
this.lastClickTime = now |
|
||||
|
|
||||
// 添加正式点
|
|
||||
const itemJson = { |
|
||||
t: this.measure.name, |
|
||||
a: 'ln', |
|
||||
tf: [ |
|
||||
[point.x, point.y, point.z], |
|
||||
[this.measure.defaultRotation.x, this.measure.defaultRotation.y, this.measure.defaultRotation.z], |
|
||||
[this.measure.defaultScale.x, this.measure.defaultScale.y, this.measure.defaultScale.z] |
|
||||
], |
|
||||
dt: { |
|
||||
link: [] as string[] |
|
||||
} |
|
||||
} as ItemJson |
|
||||
const marker = this.measure.createPoint(point, itemJson) |
|
||||
this.measure.group.add(marker) |
|
||||
|
|
||||
// 把点加入拖拽控制器
|
|
||||
this.viewport.dragControl.setDragObjects([marker], 'push') |
|
||||
|
|
||||
if (this.startPoint) { |
|
||||
// 如果起始点存在,则将新点添加到起始点的链接中
|
|
||||
this.startPoint.userData.link.push(marker.uuid) |
|
||||
this.measure.createLine(this.viewport.scene, this.startPoint, marker) |
|
||||
} |
|
||||
|
|
||||
// 更新起始点为新添加的点
|
|
||||
this.startPoint = marker |
|
||||
|
|
||||
// 删除临时线
|
|
||||
this.tempPointMarker && this.viewport.scene.remove(this.tempPointMarker) |
|
||||
this.tempPointMarker = undefined |
|
||||
|
|
||||
this.tempLabel && this.viewport.scene.remove(this.tempLabel) |
|
||||
this.tempLabel = undefined |
|
||||
|
|
||||
this.tempLine && this.viewport.scene.remove(this.tempLabel) |
|
||||
this.tempLine = undefined |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 创建点标记 |
|
||||
*/ |
|
||||
createTempPointMarker(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 = TEMP_POINT_NAME |
|
||||
obj.userData = { |
|
||||
mode: this.mode, |
|
||||
type: TMP_TYPE |
|
||||
} |
|
||||
return obj |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 添加或更新临时标签和位置 |
|
||||
*/ |
|
||||
addOrUpdateTempLabel(label: string, position: THREE.Vector3) { |
|
||||
if (!this.tempLabel) { |
|
||||
this.tempLabel = this.measure.createLabel(label) |
|
||||
this.tempLabel.name = TMP_LABEL_NAME |
|
||||
this.tempLabel.userData = { |
|
||||
mode: this.mode, |
|
||||
type: TMP_TYPE |
|
||||
} |
|
||||
this.viewport.scene.add(this.tempLabel) |
|
||||
} |
|
||||
this.tempLabel.position.set(position.x, position.y, position.z) |
|
||||
this.tempLabel.element.innerHTML = label |
|
||||
} |
|
||||
|
|
||||
|
|
||||
} |
|
||||
@ -0,0 +1,160 @@ |
|||||
|
import type { ActionType } from '@/model/itemType/ItemTypeDefine.ts' |
||||
|
|
||||
|
export interface IGridHelper { |
||||
|
/** |
||||
|
* 启用坐标轴 |
||||
|
*/ |
||||
|
axesEnabled: boolean; |
||||
|
/** |
||||
|
* 坐标轴大小, 单位米 |
||||
|
*/ |
||||
|
axesSize: number; |
||||
|
/** |
||||
|
* 坐标轴分割数 |
||||
|
*/ |
||||
|
axesDivisions: number; |
||||
|
/** |
||||
|
* 坐标轴颜色, 十六进制颜色值 |
||||
|
*/ |
||||
|
axesColor: number; |
||||
|
/** |
||||
|
* 坐标轴透明度 |
||||
|
*/ |
||||
|
axesOpacity: number; |
||||
|
|
||||
|
/** |
||||
|
* 启用网格 |
||||
|
*/ |
||||
|
gridEnabled: boolean; |
||||
|
/** |
||||
|
* 网格大小, 单位米 |
||||
|
*/ |
||||
|
gridSize: number; |
||||
|
/** |
||||
|
* 网格分割数 |
||||
|
*/ |
||||
|
gridDivisions: number; |
||||
|
/** |
||||
|
* 网格颜色, 十六进制颜色值 |
||||
|
*/ |
||||
|
gridColor: number; |
||||
|
/** |
||||
|
* 网格透明度 |
||||
|
*/ |
||||
|
gridOpacity: number; |
||||
|
|
||||
|
/** |
||||
|
* 启用吸附 |
||||
|
*/ |
||||
|
snapEnabled: boolean; |
||||
|
/** |
||||
|
* 吸附距离, 单位米 |
||||
|
*/ |
||||
|
snapDistance: number; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 定义物体类型的元数据 |
||||
|
* 举例: |
||||
|
* { |
||||
|
* id: 'p1', // 物体ID, 唯一标识, 需保证唯一, three.js 中的 uuid
|
||||
|
* t: 'measure', // 物体类型, measure表示测量, 需交给 itemType.name == 'measure' 的组件处理
|
||||
|
* a: 'ln', // 交互类型, ln表示线点操作, pt 表示点操作
|
||||
|
* l: '测量1', // 标签名称, 显示用
|
||||
|
* c: '#ff0000', // 颜色, 显示用. 十六进制颜色值, three.js 中的材质颜色
|
||||
|
* tf: [ // 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系
|
||||
|
* [-9.0, 0, -1.0], // 平移向量 position
|
||||
|
* [0, 0, 0], // 旋转向量 rotation, 表示绕Y轴旋转的角度, 单位为度。对应 three.js 应进行"角度"转"弧度"的换算
|
||||
|
* [0.25, 0.1, 0.25] // 缩放向量 scale
|
||||
|
* ], |
||||
|
* dt: { // 用户数据, 可自定义, 一般用在 three.js 的 userData 中
|
||||
|
* link: ['p2'], // 用于 a='ln' 的测量线段, 关联的点对象(uuid)
|
||||
|
* center: [], // 物流关联对象(uuid)
|
||||
|
* in: [], // 物流入方向关联的对象(uuid)
|
||||
|
* out: [] // 物流出方向关联的对象(uuid)
|
||||
|
* } |
||||
|
* } |
||||
|
*/ |
||||
|
export interface ItemJson { |
||||
|
/** |
||||
|
* 物体名称, 显示用, 最后初始化到 three.js 的 name 中, 可以不设置, 可以不唯一 |
||||
|
*/ |
||||
|
name?: string |
||||
|
|
||||
|
/** |
||||
|
* 对应 three.js 中的 uuid, 物体ID, 唯一标识, 需保证唯一 |
||||
|
*/ |
||||
|
id?: string |
||||
|
|
||||
|
/** |
||||
|
* 物体类型, 对应 defineItemType.name |
||||
|
*/ |
||||
|
t: string |
||||
|
|
||||
|
/** |
||||
|
* 交互类型 |
||||
|
*/ |
||||
|
a: ActionType |
||||
|
|
||||
|
/** |
||||
|
* 标签名称, 显示用, 最后初始化到 three.js 的 userData.label 中 |
||||
|
*/ |
||||
|
l?: string |
||||
|
|
||||
|
/** |
||||
|
* 颜色, 最后初始化到 three.js 的 userData.color 中 |
||||
|
*/ |
||||
|
c?: string |
||||
|
|
||||
|
/** |
||||
|
* 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系 |
||||
|
*/ |
||||
|
tf: [ |
||||
|
/** |
||||
|
* 平移向量 position, 三维坐标 |
||||
|
*/ |
||||
|
[number, number, number], |
||||
|
/** |
||||
|
* 旋转向量 rotation, 表示绕Y轴旋转的角度, 单位为度。对应 three.js 应进行"角度"转"弧度"的换算 |
||||
|
*/ |
||||
|
[number, number, number], |
||||
|
/** |
||||
|
* 缩放向量 scale, 三维缩放比例 |
||||
|
*/ |
||||
|
[number, number, number], |
||||
|
] |
||||
|
|
||||
|
/** |
||||
|
* 用户数据, 可自定义, 一般用在 three.js 的 userData 中 |
||||
|
*/ |
||||
|
dt: { |
||||
|
/** |
||||
|
* 测量线段关联的点对象(uuid), 仅在 a='ln' 时有效 |
||||
|
*/ |
||||
|
link?: string[] |
||||
|
|
||||
|
/** |
||||
|
* 物流关联对象(uuid) |
||||
|
*/ |
||||
|
center?: string[] |
||||
|
/** |
||||
|
* 物流入方向关联的对象(uuid) |
||||
|
*/ |
||||
|
in?: string[] |
||||
|
/** |
||||
|
* 物流出方向关联的对象(uuid) |
||||
|
*/ |
||||
|
out?: string[] |
||||
|
|
||||
|
/** |
||||
|
* 其他自定义数据, 可以存储任何数据 |
||||
|
*/ |
||||
|
[key: string]: any |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 子元素, 用于分组等, 可以为空数组 |
||||
|
*/ |
||||
|
items: ItemJson[] |
||||
|
} |
||||
Loading…
Reference in new issue