diff --git a/src/core/manager/WorldModel.ts b/src/core/manager/WorldModel.ts index 88fe815..56044eb 100644 --- a/src/core/manager/WorldModel.ts +++ b/src/core/manager/WorldModel.ts @@ -121,7 +121,8 @@ export default class WorldModel { import('../../modules/carton'), import('../../modules/amr/ptr/cl2'), import('../../modules/amr/ptr/clx'), - import('../../modules/charger') + import('../../modules/charger'), + import('../../modules/bracket') ]).then((configRes) => { console.log('世界模型初始化完成') diff --git a/src/modules/bracket/Bracket3dObject.ts b/src/modules/bracket/Bracket3dObject.ts new file mode 100644 index 0000000..4235541 --- /dev/null +++ b/src/modules/bracket/Bracket3dObject.ts @@ -0,0 +1,219 @@ +import * as THREE from 'three' +import {mergeGeometries} from 'three/addons/utils/BufferGeometryUtils.js' +import {BufferGeometry, MathUtils} from "three"; +import {Material} from "three/src/materials/Material"; +import storageBar_PNG from "@/assets/Models/storageBar.png"; +import Plastic_Rough_JPG from "@/assets/Models/Plastic_Rough.jpg"; +import {InstancedMesh} from "three/src/objects/InstancedMesh"; +import {decimalSumBy, resetUVs} from "@/core/ModelUtils"; + +export default class Bracket3dObject extends THREE.Object3D { + + + private bracketVerticalBarLength = 0.32 + private bracketHorizontalBarWidth = 0.85 + + private static bracketColor = 0xFF666666 + private static bracketBarGeometryMap: Map = new Map() + private static bracketBarMaterial: Material = null + + private static bracketCenterPlateGeometry: BufferGeometry = null + + private static barSectionPoints = [ + {x: -0.015, y: -0.012}, + {x: -0.012, y: -0.015}, + {x: 0.012, y: -0.015}, + {x: 0.015, y: -0.012}, + {x: 0.015, y: 0.012}, + {x: 0.012, y: 0.015}, + {x: -0.012, y: 0.015}, + {x: -0.015, y: 0.012} + ] + + private static centerSectionPoints = [ + {x: -0.1, y: -0.1}, + {x: -0.1, y: 0.1}, + {x: 0.1, y: 0.1}, + {x: 0.1, y: -0.1} + ] + + + private createBracketBar(length): THREE.BufferGeometry { + + // 创建一个形状 柱子的截面形状 + const shape = new THREE.Shape() + shape.moveTo(Bracket3dObject.barSectionPoints[0].x, Bracket3dObject.barSectionPoints[0].y) + for (let i = 1; i < Bracket3dObject.barSectionPoints.length; i++) { + shape.lineTo(Bracket3dObject.barSectionPoints[i].x, Bracket3dObject.barSectionPoints[i].y) + } + shape.closePath() + + // 拉伸轨迹线 + const curve = new THREE.CatmullRomCurve3( + [new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, length, 0)], + false, // 闭合曲线 + 'catmullrom', + 0 + ) + + // 挤出几何图形 参数 + const options = { + steps: 1, + bevelEnabled: false, + extrudePath: curve // 设置挤出轨迹 + } + // 创建挤出几何体 + const geometry = new THREE.ExtrudeGeometry(shape, options) + // 调整uv方便正确贴图 + resetUVs(geometry) + return geometry + } + + private createBracketBarMaterial(): THREE.Material { + + let textureLoader = new THREE.TextureLoader() + + // 加载纹理 + const textureMaterial = textureLoader.load(Plastic_Rough_JPG) // 表面材质 + + textureMaterial.repeat.set(2, 2) // X轴重复,Y轴重复 + // textureHole.offset.set(0.5, 0) + // textureHole.center.set(0.5, 0) + + + textureMaterial.wrapS = THREE.RepeatWrapping + textureMaterial.wrapT = THREE.RepeatWrapping + + const material = new THREE.MeshPhongMaterial() + material.normalMap = textureMaterial + material.color.setHex(Bracket3dObject.bracketColor, 'srgb') + material.specular.setHex(0xff6d6d6d, 'srgb') + material.transparent = true + material.needsUpdate = true + + return material + } + + + private createCenterPlate(length): THREE.BufferGeometry { + + // 创建一个形状 柱子的截面形状 + const shape = new THREE.Shape() + shape.moveTo(Bracket3dObject.centerSectionPoints[0].x, Bracket3dObject.centerSectionPoints[0].y) + for (let i = 1; i < Bracket3dObject.centerSectionPoints.length; i++) { + shape.lineTo(Bracket3dObject.centerSectionPoints[i].x, Bracket3dObject.centerSectionPoints[i].y) + } + shape.closePath() + + // 拉伸轨迹线 + const curve = new THREE.CatmullRomCurve3( + [new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0.005, 0)], + false, // 闭合曲线 + 'catmullrom', + 0 + ) + + // 挤出几何图形 参数 + const options = { + steps: 1, + bevelEnabled: false, + extrudePath: curve // 设置挤出轨迹 + } + // 创建挤出几何体 + const geometry = new THREE.ExtrudeGeometry(shape, options) + + return geometry + } + + constructor(item: ItemJson, option?: RendererCudOption) { + super(); + const width = 0.85 + const depth = 0.85 + const height = 0.35 + + if (!Bracket3dObject.bracketBarGeometryMap.get(this.bracketVerticalBarLength)) { + Bracket3dObject.bracketBarGeometryMap.set(this.bracketVerticalBarLength, this.createBracketBar(this.bracketVerticalBarLength)) + } + if (!Bracket3dObject.bracketBarGeometryMap.get(this.bracketHorizontalBarWidth)) { + Bracket3dObject.bracketBarGeometryMap.set(this.bracketHorizontalBarWidth, this.createBracketBar(this.bracketHorizontalBarWidth)) + } + if (!Bracket3dObject.bracketBarMaterial) { + Bracket3dObject.bracketBarMaterial = this.createBracketBarMaterial() + } + if (!Bracket3dObject.bracketCenterPlateGeometry) { + Bracket3dObject.bracketCenterPlateGeometry = this.createCenterPlate(height) + } + + const vBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] + const hBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] + + vBarMatrix.push({x: 0.41, y: 0, z: 0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) + vBarMatrix.push({x: 0.41, y: 0, z: -0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) + vBarMatrix.push({x: -0.41, y: 0, z: -0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) + vBarMatrix.push({x: -0.41, y: 0, z: 0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) + + hBarMatrix.push({x: -0.41, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + hBarMatrix.push({x: -0.1, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + hBarMatrix.push({x: 0.1, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + hBarMatrix.push({x: 0.41, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + + hBarMatrix.push({x: width/2, y: 0.335, z: -0.41, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + hBarMatrix.push({x: width/2, y: 0.335, z: -0.1, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + hBarMatrix.push({x: width/2, y: 0.335, z: 0.1, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + hBarMatrix.push({x: width/2, y: 0.335, z: 0.41, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) + + + const meshes: InstancedMesh[] = [] + const bracketVerticalBarGeometry = Bracket3dObject.bracketBarGeometryMap.get(this.bracketVerticalBarLength) + const vBarMesh = new THREE.InstancedMesh(bracketVerticalBarGeometry, Bracket3dObject.bracketBarMaterial, vBarMatrix.length) + + const bracketHorizontalBarGeometry = Bracket3dObject.bracketBarGeometryMap.get(this.bracketHorizontalBarWidth) + const hBarMesh = new THREE.InstancedMesh(bracketHorizontalBarGeometry, Bracket3dObject.bracketBarMaterial, hBarMatrix.length) + + const centerMesh = new THREE.Mesh(Bracket3dObject.bracketCenterPlateGeometry, Bracket3dObject.bracketBarMaterial) + + + const dummy = new THREE.Object3D() + for (let i = 0; i < vBarMatrix.length; i++) { + const vp = vBarMatrix[i] + dummy.position.set(vp.x, vp.y, vp.z) + dummy.rotation.set(vp.rx, vp.ry, vp.rz) + dummy.scale.set(vp.sx, vp.sy, vp.sz) + dummy.updateMatrix() + vBarMesh.setMatrixAt(i, dummy.matrix) + } + meshes.push(vBarMesh) + for (let i = 0; i < hBarMatrix.length; i++) { + const vp = hBarMatrix[i] + dummy.position.set(vp.x, vp.y, vp.z) + dummy.rotation.set(vp.rx, vp.ry, vp.rz) + dummy.scale.set(vp.sx, vp.sy, vp.sz) + dummy.updateMatrix() + hBarMesh.setMatrixAt(i, dummy.matrix) + } + meshes.push(hBarMesh) + + meshes.forEach(mesh => { + this.add(mesh) + mesh.instanceMatrix.needsUpdate = true + }) + this.add(centerMesh) + centerMesh.position.set(0, 0.325, 0) + } + + +} + +class LinkBarKey { + height: number + depth: number + + constructor(height: number, depth: number) { + this.height = height + this.depth = depth + } + + equals(other: LinkBarKey): boolean { + return this.height == other.height && this.depth == other.depth + } +} diff --git a/src/modules/bracket/BracketEntity.ts b/src/modules/bracket/BracketEntity.ts new file mode 100644 index 0000000..ad4f25a --- /dev/null +++ b/src/modules/bracket/BracketEntity.ts @@ -0,0 +1,5 @@ +import BaseEntity from '@/core/base/BaseItemEntity.ts' + +export default class BracketEntity extends BaseEntity { + +} diff --git a/src/modules/bracket/BracketInteraction.ts b/src/modules/bracket/BracketInteraction.ts new file mode 100644 index 0000000..aa3e305 --- /dev/null +++ b/src/modules/bracket/BracketInteraction.ts @@ -0,0 +1,22 @@ +import BaseInteraction from '@/core/base/BaseInteraction.ts' +import * as THREE from 'three' + +export default class BracketInteraction extends BaseInteraction { + + get isSinglePointMode(): boolean { + return true + } + + constructor(itemTypeName: string) { + super(itemTypeName) + } + + createPointOfItem(item: ItemJson, point: THREE.Vector3): ItemJson { + item = super.createPointOfItem(item, point) + + // 创建一个地堆货架 + item.dt.rackWidth = 3 // 宽度 + item.dt.rackDepth = 1 // 深度 + return item + } +} diff --git a/src/modules/bracket/BracketPropertySetter.ts b/src/modules/bracket/BracketPropertySetter.ts new file mode 100644 index 0000000..93a56dd --- /dev/null +++ b/src/modules/bracket/BracketPropertySetter.ts @@ -0,0 +1,35 @@ +import type { PropertySetter } from "@/core/base/PropertyTypes.ts"; +import { basicFieldsSetter } from "@/editor/widgets/property/PropertyPanelConstant.ts"; + +const propertySetter: PropertySetter = { + flatten: { + fields: [ + ...basicFieldsSetter + ] + }, + groups: [ + { + title: '存储位置', expand: true, size: 'small', + fields: [ + { + dataPath: 'dt.storeAt.item', label: '货架', input: 'Input', + inputProps: {} + }, + { + dataPath: 'dt.storeAt.bay', label: '列', input: 'InputNumber', + inputProps: {} + }, + { + dataPath: 'dt.storeAt.level', label: '层', input: 'InputNumber', + inputProps: {} + }, + { + dataPath: 'dt.storeAt.cell', label: '格', input: 'InputNumber', + inputProps: {} + } + ] + } + ] +}; + +export default propertySetter; diff --git a/src/modules/bracket/BracketRenderer.ts b/src/modules/bracket/BracketRenderer.ts new file mode 100644 index 0000000..5372465 --- /dev/null +++ b/src/modules/bracket/BracketRenderer.ts @@ -0,0 +1,128 @@ +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 Bracket3dObject from "@/modules/bracket/Bracket3dObject"; + +/** + * 货架货位渲染器 + */ +export default class BracketRenderer extends BaseRenderer { + static POINT_NAME = 'bracket' + + 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.') + } + + getStorePlacement(me: ItemJson, bay = 0, level = 0, cell = 0): { position: [number, number, number], rotation: [number, number, number] } { + // 将这个物品添加到库存中 + // const me = viewport.entityManager.findItemById(item.dt.storeAt.item) + return { position: me.tf[0], rotation: me.tf[1] } + } + + 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] = 0.85 + item.tf[2][1] = 0.35 + item.tf[2][3] = 0.85 + + + // 更新放在内部的所有箱子 + 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 { + // 创建几何体 + const group = new Bracket3dObject(item, option) + group.name = BracketRenderer.POINT_NAME + + // 设置位置 + 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]) + ) + + return group + } + + dispose() { + super.dispose() + this.pointMaterial?.dispose() + } +} diff --git a/src/modules/bracket/index.ts b/src/modules/bracket/index.ts new file mode 100644 index 0000000..a4335f4 --- /dev/null +++ b/src/modules/bracket/index.ts @@ -0,0 +1,13 @@ +import { defineModule } from '@/core/manager/ModuleManager.ts' +import BracketRenderer from './BracketRenderer.ts' +import BracketInteraction from './BracketInteraction.ts' +import propertySetter from './BracketPropertySetter.ts' +import Bracket3dObject from "@/modules/bracket/Bracket3dObject"; + +export const ITEM_TYPE_NAME = 'bracket' + +export default defineModule(ITEM_TYPE_NAME, () => ({ + renderer: new BracketRenderer(ITEM_TYPE_NAME), + interaction: new BracketInteraction(ITEM_TYPE_NAME), + setter: propertySetter +}))