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.
 
 
 

207 lines
6.3 KiB

import * as THREE from 'three'
import BaseRenderer from '@/core/base/BaseRenderer.ts'
import { decimalSumBy } from '@/core/ModelUtils'
import Constract from '@/core/Constract.ts'
import type Viewport from '@/core/engine/Viewport.ts'
import Rack3dObject from '@/modules/rack/Rack3dObject'
/**
* 货架货位渲染器
*/
export default class RackRenderer extends BaseRenderer {
static POINT_NAME = 'rack'
pointMaterial: THREE.Material
/**
* 默认点的高度, 防止和地面重合
*/
readonly defulePositionY: number = Constract.HEIGHT_WAY
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1, 1, 1)
readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0)
readonly defaultLineWidth: number = 0.05
constructor(itemTypeName: string) {
super(itemTypeName)
}
/**
* 所有的点,必须使用 storeWidth/storeDepth, 改TF无效
*/
override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, object: THREE.Object3D) {
super.afterCreateOrUpdatePoint(item, option, object)
const point = object
point.position.y = this.defulePositionY
//point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth)
point.rotation.set(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2])
)
}
createLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
// throw new Error('not allow store line.')
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType) {
// throw new Error('not allow store line.')
}
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
// throw new Error('not allow store line.')
}
/**
* 获取物品存放在货架后的位置和旋转角度
* item.dt.storeAt 必须存在, 比如 { item:'货架ID', bay:0, level:1, cell:0 }
*/
getStorePlacement(rack: ItemJson, bay = 0, level = 0, cell = 0): { position: [number, number, number], rotation: [number, number, number] } {
// if (!item.dt?.storeAt?.item) {
// // 没有定义存储位置,返回空对象
// //@ts-ignore
// return {}
// }
//
// const bay = item.dt?.storeAt?.bay || 0
// const level = item.dt?.storeAt?.level || 0
// 暂时不用算格子 const cell = item.dt?.storeAt?.cell || 0
// 目标货架
// const rack = viewport.stateManager.findItemById(item.dt.storeAt.item)
const rackWidth = decimalSumBy(rack.dt.bays, (b: any) => b.bayWidth)
const bays = rack.dt.bays
const levelHeights = rack.dt.bays[bay]?.levelHeight
// 局部坐标系下的偏移量
let localX = 0
for (let i = 0; i < bay; i++) {
localX += bays[i]?.bayWidth || 0
}
localX += bays[bay].bayWidth / 2 // 居中
let localY = 0
for (let i = 0; i <= level; i++) {
localY += levelHeights[i]
}
// 构建局部偏移向量
const rackPos = new THREE.Vector3(...rack.tf[0])
const offset = new THREE.Vector3(
localX - rackWidth / 2, // 相对坐标从最左边开始,
localY, 0)
// 应用货架的旋转
const q = new THREE.Quaternion()
q.setFromEuler(new THREE.Euler(
THREE.MathUtils.degToRad(rack.tf[1][0]),
THREE.MathUtils.degToRad(rack.tf[1][1]),
THREE.MathUtils.degToRad(rack.tf[1][2])
))
offset.applyQuaternion(q)
const worldPosition = rackPos.clone().add(offset)
return {
position: [
worldPosition.x,
worldPosition.y + rack.dt.bottomBarHeight + 0.05, // 加上横梁高度
worldPosition.z
],
rotation: [
// 托盘旋转90度才能放进货架
rack.tf[1][0],
rack.tf[1][1] + 90,
rack.tf[1][2]
]
}
}
updatePoint(item: ItemJson, group: THREE.Group, option?: RendererCudOption): THREE.Group {
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
group.rotation.set(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2])
)
// group.scale 不允许修改!!
// 禁止缩放,
item.tf[2][0] = item.dt.rackWidth
item.tf[2][1] = item.dt.rackHeight
// 更新放在内部的所有箱子
const subItems = this.tempViewport.runtimeManager.getItemsByRack(item.id)
const viewport = this.tempViewport
if (subItems) {
_.defer(() => {
viewport.stateManager.update(({ getEntity, putEntity, deleteEntity, addEntity }) => {
for (const subItemId of subItems) {
const subItem = getEntity(subItemId)
if (subItem) {
const { position, rotation } = this.getStorePlacement(item, subItem.dt.storeAt.bay, subItem.dt.storeAt.level, subItem.dt.storeAt.cell)
if (position) {
subItem.tf[0][0] = position[0]
subItem.tf[0][1] = position[1]
subItem.tf[0][2] = position[2]
subItem.tf[1][0] = rotation[0]
subItem.tf[1][1] = rotation[1]
subItem.tf[1][2] = rotation[2]
putEntity(subItem)
}
}
}
})
})
}
return group
}
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
// 创建平面几何体
if (!item.dt.bays || !item.dt.rackDepth) {
system.showErrorDialog('RackRenderer field bays / rackDepth is null!')
return null
}
const group = new Rack3dObject(item, option)
group.name = RackRenderer.POINT_NAME
const rackWidth = decimalSumBy(item.dt.bays, (b: any) => b.bayWidth)
const heights = []
for (let i = 0; i < item.dt.bays.length; i++) {
const bay = item.dt.bays[i]
const bayHeight = decimalSumBy(bay.levelHeight)
heights.push(bayHeight)
}
const rackHeight = _.max(heights)
// 设置位置
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
group.rotation.set(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2])
)
item.dt.rackWidth = rackWidth
item.dt.rackHeight = rackHeight
item.tf[2][0] = item.dt.rackWidth
item.tf[2][1] = item.dt.rackHeight
return group
}
dispose() {
super.dispose()
this.pointMaterial?.dispose()
}
}