You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

217 lines
6.2 KiB

import type Viewport from '@/core/engine/Viewport'
import * as THREE from 'three'
import { getLineId } from '@/core/ModelUtils.ts'
import { Line2 } from 'three/examples/jsm/lines/Line2'
/**
* 基本渲染器基类
* 定义了点 / 线如何渲染到 Three.js 场景中
*/
export default abstract class BaseRenderer {
/**
* 每次 beginUpdate 时记录临时 viewport, endUpdate 之后要马上删除, 因为 BaseRenderer 全局只有一个实例, 而 viewport 有多个
*/
tempViewport?: Viewport = undefined
/**
* 开始更新
* @param viewport 当前视口
*/
beginRendererUpdate(viewport: Viewport): void {
this.tempViewport = viewport
}
/**
* 创建一个最基本的点对象, 不用管 item 的 name / id / 位置 / 转换 / 大小 和 userData, 除非有明确定义
*/
abstract createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D[]
/**
* 创建测量线
*/
abstract createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D[]
fillObjectUserDataFromItem(item: ItemJson, ...objects: THREE.Object3D[]) {
_.forEach(objects, (object) => {
if (!object.name && item.name) {
object.name = item.name
}
object.userData = {
...object.userData,
createType: 'point',
entityId: item.id,
t: item.t
}
})
}
fillObjectUserDataFromLine(start: ItemJson, end: ItemJson, type: LinkType, ...objects: THREE.Object3D[]) {
const id = getLineId(start.id, end.id, type)
_.forEach(objects, (object) => {
if (!object.name) {
object.name = id
}
object.userData = {
...object.userData,
createType: 'line',
entityId: getLineId(start.id, end.id, type),
t: start.t
}
})
}
/**
* 将对象添加到当前视口的场景中
*/
appendToScene(...objects: THREE.Object3D[]) {
if (!this.tempViewport || !this.tempViewport.scene) {
console.warn('No active viewport to append objects to.')
return
}
this.tempViewport.scene.add(...objects)
}
/**
* 创建一个点
* @param item 点的定义
* @param option 渲染选项
*/
createPoint(item: ItemJson, option?: RendererCudOption) {
// 由基础类创造一个属于自己的点演示
const points = this.createPointBasic(item, option)
_.forEach(points, (point) => {
if (item.name) {
point.name = item.name
}
point.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
point.rotation.set(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2])
)
point.scale.set(item.tf[2][0], item.tf[2][1], item.tf[2][2])
})
this.fillObjectUserDataFromItem(item, ...points)
this.tempViewport.entityManager.appendObject(item.id, points)
this.appendToScene(...points)
}
/**
* 删除一个点
* @param id 点的唯一标识
* @param option 渲染选项
*/
deletePoint(id: string, option?: RendererCudOption) {
const objects = this.tempViewport.entityManager.findObjectsById(id)
if (objects) {
this.tempViewport.scene.remove(...objects)
}
this.tempViewport.entityManager.deleteEntityOnly(id)
this.tempViewport.entityManager.deleteObjectsOnly(id)
}
/**
* 更新一个点
* @param item 点的定义
* @param option 渲染选项
*/
updatePoint(item: ItemJson, option?: RendererCudOption) {
const objects = this.tempViewport.entityManager.findObjectsById(item.id)
if (!objects || objects.length === 0) {
console.warn(`Point with ID "${item.id}" does not exist.`)
return
}
_.forEach(objects, (point) => {
point.name = item.name || point.name
point.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
point.rotation.set(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2])
)
point.scale.set(item.tf[2][0], item.tf[2][1], item.tf[2][2])
})
}
/**
* 创建一根线
* @param start 起点
* @param end 终点
* @param type 线的类型
* @param option 渲染选项
*/
createLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
const lines = this.createLineBasic(start, end, type)
const id = getLineId(start.id, end.id, type)
const startPoint = this.tempViewport.entityManager.findObjectsById(start.id)?.[0]
const endPoint = this.tempViewport.entityManager.findObjectsById(end.id)?.[0]
_.forEach(lines, (line) => {
this.tempViewport.entityManager.findObjectsById(id)
const geom = line.geometry
geom.setFromPoints([startPoint.position, endPoint.position])
})
this.fillObjectUserDataFromLine(start, end, type, ...lines)
this.tempViewport.entityManager.appendLineObject(id, lines)
this.appendToScene(...lines)
}
/**
* 更新一根线
* @param start 起点
* @param end 终点
* @param type 线的类型
* @param option 渲染选项
*/
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
const lineId = getLineId(start.id, end.id, type)
const lines = this.tempViewport.entityManager.findLineObjectsById(lineId)
_.forEach(lines, (line: THREE.Object3D) => {
const startPoint = this.tempViewport.entityManager.findObjectsById(start.id)?.[0]
const endPoint = this.tempViewport.entityManager.findObjectsById(end.id)?.[0]
if (line instanceof Line2) {
const geom = line.geometry
geom.setFromPoints([startPoint.position, endPoint.position])
}
})
}
/**
* 删除一根线
* @param start 起点
* @param end 终点
* @param option 渲染选项
*/
deleteLine(start: ItemJson, end: ItemJson, option?: RendererCudOption) {
const id = getLineId(start.id, end.id, 'center')
const lines = this.tempViewport.entityManager.findLineObjectsById(id)
if (lines) {
this.tempViewport.scene.remove(...lines)
}
this.tempViewport.entityManager.deleteLineObjectOnly(id)
}
/**
* 结束更新
*/
endRendererUpdate(): void {
this.tempViewport = undefined
}
}