import * as THREE from 'three' import BaseRenderer from '@/core/base/BaseRenderer.ts' import MoveLinePointPng from '@/assets/images/moveline_point.png' import { getLineId, linkPlaneByPoint } from '@/core/ModelUtils.ts' import Constract from '@/core/Constract.ts' import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts' import type { Object3DLike } from '@/types/ModelTypes.ts' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial' import LineSegmentManager from '@/core/manager/LineSegmentManager.ts' /** * AGV行走路线渲染器 point 是二维码站点 */ export default class WayRenderer extends BaseRenderer { static LABEL_NAME = 'way_label' static POINT_NAME = 'way_point' static LINE_NAME = 'way_line' pointGeometry: THREE.BufferGeometry pointMaterial: THREE.Material // lineMaterial: LineMaterial = new LineMaterial({ // color: 0xa0cfff, // linewidth: 0.8, // vertexColors: false, // dashed: false, // gapSize: 0, // worldUnits: true // }) lineGeometry: THREE.BufferGeometry = new THREE.PlaneGeometry(1, 1).rotateX(-Math.PI / 2) lineMaterial = new THREE.MeshBasicMaterial({ color: 0xa0cfff, transparent: true, opacity: 0.2, side: THREE.DoubleSide }) /** * 默认点的高度, 防止和地面重合 */ readonly defulePositionY: number = Constract.HEIGHT_WAY readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.5, 0.1, 0.5) readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0) readonly rendererOption = { lineWidth: 0.8 } async init() { return Promise.all([ super.init(), new THREE.TextureLoader().loadAsync(MoveLinePointPng) ]).then(([_, texture]) => { texture.flipY = false this.pointGeometry = new THREE.PlaneGeometry(1, 1).rotateX(-Math.PI / 2) this.pointGeometry.center() this.pointMaterial = new THREE.MeshBasicMaterial({ map: texture, transparent: true, depthWrite: false, side: THREE.DoubleSide }) this.pointMaterial.needsUpdate = true }) } 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) // 用 PlaneGeometry 替代线段 const startPosition = new THREE.Vector3(start.tf[0][0], this.defulePositionY, start.tf[0][2]) const endPosition = new THREE.Vector3(end.tf[0][0], this.defulePositionY, end.tf[0][2]) const wrap = this.lineManager.createPointSimple(lineId) const matrix = linkPlaneByPoint(startPosition, endPosition, this.rendererOption.lineWidth) wrap.applyMatrix4(matrix) return wrap } updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { const lineId = getLineId(start.id, end.id, type) const startPosition = new THREE.Vector3(start.tf[0][0], this.defulePositionY, start.tf[0][2]) const endPosition = new THREE.Vector3(end.tf[0][0], this.defulePositionY, end.tf[0][2]) const wrap = this.tempViewport.entityManager.findLineObjectById(lineId) as PointManageWrap const matrix = linkPlaneByPoint(startPosition, endPosition, this.rendererOption.lineWidth) wrap.applyMatrix4(matrix) } 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: false, fontSize: 0.2, color: '#333333', format: (distance) => { return (distance * 1000).toFixed(0) } }) } afterDeleteLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: Object3DLike) { super.afterDeleteLine(start, end, type, option, object) this.tempViewport.labelManager.removeLabel(object) } dispose() { super.dispose() this.pointMaterial?.dispose() this.lineMaterial?.dispose() } get lineManager(): InstancePointManager { if (!this.tempViewport) { throw new Error('tempViewport is not set.') } return this.tempViewport.getOrCreatePointManager(this.itemTypeName + '_line', () => // 构建 LineSegment.points 代理对象 InstancePointManager.create(this.itemTypeName + '_line', this.tempViewport, this.lineGeometry, this.lineMaterial, Constract.MAX_WAY_LINE_INSTANCES) ) } 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_WAY_INSTANCES) ) } }