import * as THREE from 'three' import BaseRenderer from '@/core/base/BaseRenderer.ts' import { getLineId } from '@/core/ModelUtils.ts' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js' import Constract from '@/core/Constract.ts' import InstancePointManager from '@/core/manager/InstancePointManager.ts' import LineSegmentManager from '@/core/manager/LineSegmentManager.ts' import type { Object3DLike } from '@/types/ModelTypes.ts' /** * 辅助测量工具渲染器 * 支持 InstanceMesh 和 LineSegment */ export default class MeasureRenderer extends BaseRenderer { static LABEL_NAME = 'measure_label' static POINT_NAME = 'measure_point' public useHtmlLabel = false pointMaterial: THREE.Material = new THREE.MeshBasicMaterial({ color: 0xFFFF99, transparent: true, depthWrite: false, side: THREE.DoubleSide }) pointGeometry = new THREE.PlaneGeometry(1, 1) lineMaterial: LineMaterial = new LineMaterial({ color: 0xFF8C00, linewidth: 1, vertexColors: false, dashed: false }) readonly defulePositionY = Constract.HEIGHT_MEASURE readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.25, 0.25, 0.1) readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(90, 0, 0) /** * 所有的点,必须使用同一个尺寸, 改属性也无效 */ override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, object: Object3DLike) { super.afterCreateOrUpdatePoint(item, option, object) const point = object point.scale.set(this.defaultScale.x, this.defaultScale.y, this.defaultScale.z) point.rotation.set( THREE.MathUtils.degToRad(this.defaultRotation.x), THREE.MathUtils.degToRad(this.defaultRotation.y), THREE.MathUtils.degToRad(this.defaultRotation.z) ) } createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike { // 不允许改变高度/角度/大小 item.tf = [ [item.tf[0][0], this.defulePositionY, item.tf[0][2]], [this.defaultRotation.x, this.defaultRotation.y, this.defaultRotation.z], [this.defaultScale.x, this.defaultScale.y, this.defaultScale.z] ] return this.pointManager.createPoint(item) } createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): Object3DLike { const lineId = getLineId(start.id, end.id, type) return this.lineSegmentManager.createLine(lineId, start.tf[0], end.tf[0], this.lineMaterial.color) } afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: Object3DLike) { super.afterCreateOrUpdateLine(start, end, type, option, object) const startPoint = this.tempViewport?.entityManager.findObjectById(start.id) const endPoint = this.tempViewport?.entityManager.findObjectById(end.id) this.tempViewport.labelManager.createOrUpdateLabelByDistance(object, startPoint.position, endPoint.position, { useHtmlLabel: this.useHtmlLabel, fontSize: 0.4, color: '#333333' }) } afterDeleteLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: Object3DLike) { super.afterDeleteLine(start, end, type, option, object) this.tempViewport.labelManager.removeLabel(object) } get pointManager(): InstancePointManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () => // 构建 InstanceMesh 代理对象 InstancePointManager.create(this.itemTypeName, this.tempViewport, this.pointGeometry, this.pointMaterial, Constract.MAX_MEASURE_INSTANCES) ) } get lineSegmentManager(): LineSegmentManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } return this.tempViewport.getOrCreateLineManager(this.itemTypeName, () => // 构建 LineSegment.points 代理对象 LineSegmentManager.create(this.itemTypeName, this.tempViewport, this.lineMaterial) ) } dispose() { super.dispose() this.pointMaterial?.dispose() this.lineMaterial?.dispose() } }