Browse Source

嘉兴测试

jx-test
yuliang 5 months ago
parent
commit
1d9c97b159
  1. 4
      src/core/manager/WorldModel.ts
  2. 5
      src/core/script/ModelManager.ts
  3. 400
      src/modules/amr/cc/cc5/CC53DGraphics.ts
  4. 305
      src/modules/amr/cc/cc5/CC53dObject.ts
  5. 11
      src/modules/amr/cc/cc5/CC5Entity.ts
  6. 22
      src/modules/amr/cc/cc5/CC5Interaction.ts
  7. 24
      src/modules/amr/cc/cc5/CC5PropertySetter.ts
  8. 119
      src/modules/amr/cc/cc5/CC5Renderer.ts
  9. 12
      src/modules/amr/cc/cc5/index.ts
  10. 198
      src/modules/amr/fm600/FM6003DGraphics.ts
  11. 157
      src/modules/amr/fm600/FM6003dObject.ts
  12. 120
      src/modules/amr/fm600/FM600Entity.ts
  13. 22
      src/modules/amr/fm600/FM600Interaction.ts
  14. 24
      src/modules/amr/fm600/FM600PropertySetter.ts
  15. 122
      src/modules/amr/fm600/FM600Renderer.ts
  16. 12
      src/modules/amr/fm600/index.ts
  17. 41
      src/modules/amr/ptr/PtrObject.ts
  18. 8
      src/types/Model.d.ts

4
src/core/manager/WorldModel.ts

@ -122,7 +122,9 @@ export default class WorldModel {
import('../../modules/amr/ptr/cl2'),
import('../../modules/amr/ptr/clx'),
import('../../modules/charger'),
import('../../modules/bracket')
import('../../modules/bracket'),
import('../../modules/amr/fm600'),
import('../../modules/amr/cc/cc5')
]).then((configRes) => {
console.log('世界模型初始化完成')

5
src/core/script/ModelManager.ts

@ -7,6 +7,7 @@ import TaskManager from '../manager/TaskManager.ts'
import Cl2Entity from '@/modules/amr/ptr/cl2/Cl2Entity.ts'
// import ClxEntity from '@/modules/amr/ptr/clx/ClxEntity.ts'
import { getRenderer } from '@/core/manager/ModuleManager.ts'
import FM600Entity from "@/modules/amr/fm600/FM600Entity";
export default class ModelManager implements IControls, Model {
private viewport: Viewport
@ -20,6 +21,10 @@ export default class ModelManager implements IControls, Model {
// return new ClxEntity(this.viewport, id)
}
getFm600(id: string): Fm600If {
return new FM600Entity(this.viewport, id)
}
createTask(agv: object): TaskManager {
if (TaskManager.taskMap.has(agv)) {
return TaskManager.taskMap.get(agv)

400
src/modules/amr/cc/cc5/CC53DGraphics.ts

@ -0,0 +1,400 @@
import * as THREE from "three";
import {CSG} from "three-csg-ts";
//@ts-ignore
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js'
export default class CC53DGraphics {
// 创建cc5的底座
static createCC5Pedestal(): THREE.BufferGeometry {
const width = 1.65
const depth = 1.65
const dd = 0.05
const bd = 0.175
const shape = new THREE.Shape()
shape.moveTo(-width / 2, -depth / 2 + bd)
shape.lineTo(-width / 2 + bd, -depth / 2)
shape.lineTo(width / 2 - bd, -depth / 2)
shape.lineTo(width / 2, -depth / 2 + bd)
shape.lineTo(width / 2, -0.285)
shape.lineTo(-0.475, -0.285)
shape.lineTo(-0.475, -0.125)
shape.lineTo(width / 2, -0.125)
shape.lineTo(width / 2, 0.125)
shape.lineTo(-0.475, 0.125)
shape.lineTo(-0.475, 0.285)
shape.lineTo(width / 2, 0.285)
shape.lineTo(width / 2, depth / 2 - bd)
shape.lineTo(width / 2 - bd, depth / 2)
shape.lineTo(-width / 2 + bd, depth / 2)
shape.lineTo(-width / 2, depth / 2 - bd)
shape.closePath() // 闭合路径
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 0.22, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelEnabled: false,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({color: 0xffdddbca})
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
// 倒角
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.02, -0.02)
shapeD.lineTo(0.02, 0.02)
shapeD.lineTo(-0.02, 0.02)
shapeD.closePath()
const shapeDW = new THREE.Shape()
shapeDW.moveTo(0.02, -0.02)
shapeDW.lineTo(0.02, 0.02)
shapeDW.lineTo(-0.02, 0.02)
shapeDW.closePath()
const shapeDW1 = new THREE.Shape()
shapeDW1.moveTo(-0.02, -0.02)
shapeDW1.lineTo(0.02, -0.02)
shapeDW1.lineTo(-0.02, 0.02)
shapeDW1.closePath()
const positionDs: THREE.Vector3[] = [
new THREE.Vector3(-width / 2, 0.20, -depth / 2 + bd),
new THREE.Vector3(-width / 2 + bd, 0.20, -depth / 2),
new THREE.Vector3(width / 2 - bd, 0.20, -depth / 2),
new THREE.Vector3(width / 2, 0.20, -depth / 2 + bd),
new THREE.Vector3(width / 2, 0.20, depth / 2 - bd),
new THREE.Vector3(width / 2 - bd, 0.20, depth / 2),
new THREE.Vector3(-width / 2 + bd, 0.20, depth / 2),
new THREE.Vector3(-width / 2, 0.20, depth / 2 - bd),
new THREE.Vector3(-width / 2, 0.20, -depth / 2 + bd)
]
let result: THREE.Mesh = mesh
for (let i = 0; i < positionDs.length - 1; i++) {
const curveD = new THREE.CatmullRomCurve3([positionDs[i], positionDs[i + 1]],
false,
'catmullrom',
0)
const optionsD = {
steps: 1,
bevelEnabled: false,
extrudePath: curveD
}
let geometryD: THREE.BufferGeometry = null
if (i == 1) {
geometryD = new THREE.ExtrudeGeometry(shapeDW, optionsD)
} else if (i == 5) {
geometryD = new THREE.ExtrudeGeometry(shapeDW1, optionsD)
} else {
geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
}
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
result = CSG.subtract(result, meshD)
}
return result.geometry
}
// 创建cc5的立柱
static createCC5Pillar(): THREE.BufferGeometry {
// 606.5
const width = 0.3
const depth = 1.188
const dd = 0.05
const shape = new THREE.Shape()
shape.moveTo(-0.744, -0.594 + dd)
shape.lineTo(-0.744 + dd, -0.594)
shape.lineTo(-0.744 + width - dd, -0.594)
shape.lineTo(-0.744 + width, -0.594 + dd)
shape.lineTo(-0.744 + width, -0.4)
shape.lineTo(-0.744 + width - 0.08, -0.4)
shape.lineTo(-0.744 + width - 0.08, 0.4)
shape.lineTo(-0.744 + width, 0.4)
shape.lineTo(-0.744 + width, -0.594 + depth - dd)
shape.lineTo(-0.744 + width - dd, -0.594 + depth)
shape.lineTo(-0.744 + dd, -0.594 + depth)
shape.lineTo(-0.744, -0.594 + depth - dd)
// shape.lineTo(-0.728, -0.594 + dd);
// shape.closePath()
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.22, 0), new THREE.Vector3(0, 3.357, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
// const material = new THREE.MeshBasicMaterial({color: 0xffdddbca});
// const mesh = new THREE.Mesh(geometry, material);
return new THREE.ExtrudeGeometry(shape, options)
}
// 创建cc5的叉
static createCC5Fork(): THREE.BufferGeometry {
// 606.5
const width = 0.3
const depth = 1.188
const dd = 0.05
const fdx = 0.06
const fdy = 0.03
const shape = new THREE.Shape()
shape.moveTo(-0.744 + width - 0.08, -0.4)
shape.lineTo(-0.744 + width + 0.02, -0.4)
shape.lineTo(-0.744 + width + 0.02, -0.275)
shape.lineTo(-0.744 + width + 0.02 + 1.24 - fdx, -0.275)
shape.lineTo(-0.744 + width + 0.02 + 1.24, -0.275 + fdy)
shape.lineTo(-0.744 + width + 0.02 + 1.24, -0.135 - fdy)
shape.lineTo(-0.744 + width + 0.02 + 1.24 - fdx, -0.135)
shape.lineTo(-0.744 + width + 0.02, -0.135)
shape.lineTo(-0.744 + width + 0.02, 0.135)
shape.lineTo(-0.744 + width + 0.02 + 1.24 - fdx, 0.135)
shape.lineTo(-0.744 + width + 0.02 + 1.24, 0.135 + fdy)
shape.lineTo(-0.744 + width + 0.02 + 1.24, 0.275 - fdy)
shape.lineTo(-0.744 + width + 0.02 + 1.24 - fdx, 0.275)
shape.lineTo(-0.744 + width + 0.02, 0.275)
shape.lineTo(-0.744 + width + 0.02, 0.4)
shape.lineTo(-0.744 + width - 0.08, 0.4)
shape.closePath()
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 1.287, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({color: 0xffdddbca})
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.744 + width + 0.02, -0.3)
shapeD.lineTo(-0.744 + width + 0.02 + 1.3, -0.3)
shapeD.lineTo(-0.744 + width + 0.02 + 1.3, 0.3)
shapeD.lineTo(-0.744 + width + 0.02, 0.3)
shape.closePath()
// 拉伸轨迹线
const curveD = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.07, 0), new THREE.Vector3(0, 1.3, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const optionsD = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curveD // 设置挤出轨迹
}
// 创建挤出几何体
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
// 布尔运算
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
// 创建cc5的铰链
static createCC5Gemel(isLeft: boolean = false) {
const width = 0.08
const depth = 0.9
const dd = 0.02
const shape = new THREE.Shape()
shape.moveTo(-width / 2, -depth / 2 + dd)
shape.lineTo(-width / 2 + dd, -depth / 2)
shape.lineTo(width / 2 - dd, -depth / 2)
shape.lineTo(width / 2, -depth / 2 + dd)
shape.lineTo(width / 2, depth / 2 - dd)
shape.lineTo(width / 2 - dd, depth / 2)
shape.lineTo(-width / 2 + dd, depth / 2)
shape.lineTo(-width / 2, depth / 2 - dd)
shape.closePath()
const shapeBar = new THREE.Shape()
shapeBar.moveTo(0, 0) // 起点在圆心
shapeBar.absarc(0, 0, 0.02, 0, Math.PI * 2, false) // 从0到π绘制半圆
shapeBar.closePath()
const geometries: THREE.BufferGeometry[] = []
const curveL1 = new THREE.CatmullRomCurve3(
[new THREE.Vector3(-0.35 + (isLeft ? 0.05 : 0), 0, 0), new THREE.Vector3(-0.30 + (isLeft ? 0.05 : 0), 0, 0)],
false, // 闭合曲线
'catmullrom',
0
)
const curveL2 = new THREE.CatmullRomCurve3(
[new THREE.Vector3(-0.15 + (isLeft ? 0.05 : 0), 0, 0), new THREE.Vector3(-0.1 + (isLeft ? 0.05 : 0), 0, 0)],
false, // 闭合曲线
'catmullrom',
0
)
const curveL3 = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0.15 - (isLeft ? 0.05 : 0), 0, 0), new THREE.Vector3(0.1 - (isLeft ? 0.05 : 0), 0, 0)],
false, // 闭合曲线
'catmullrom',
0
)
const curveL4 = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0.30 - (isLeft ? 0.05 : 0), 0, 0), new THREE.Vector3(0.35 - (isLeft ? 0.05 : 0), 0, 0)],
false, // 闭合曲线
'catmullrom',
0
)
if (!isLeft) {
const curveBar1 = new THREE.CatmullRomCurve3(
[new THREE.Vector3(-0.36, -0.4, 0), new THREE.Vector3(0.36, -0.4, 0)],
false, // 闭合曲线
'catmullrom',
0
)
const curveBar2 = new THREE.CatmullRomCurve3(
[new THREE.Vector3(-0.36, 0, 0), new THREE.Vector3(0.36, 0, 0)],
false, // 闭合曲线
'catmullrom',
0
)
const curveBar3 = new THREE.CatmullRomCurve3(
[new THREE.Vector3(-0.36, 0.4, 0), new THREE.Vector3(0.36, 0.4, 0)],
false, // 闭合曲线
'catmullrom',
0
)
geometries.push(new THREE.ExtrudeGeometry(shapeBar, {
steps: 1,
bevelEnabled: false,
extrudePath: curveBar1
}))
geometries.push(new THREE.ExtrudeGeometry(shapeBar, {
steps: 1,
bevelEnabled: false,
extrudePath: curveBar2
}))
geometries.push(new THREE.ExtrudeGeometry(shapeBar, {
steps: 1,
bevelEnabled: false,
extrudePath: curveBar3
}))
}
const geometryL1 = new THREE.ExtrudeGeometry(shape, {
steps: 1,
bevelEnabled: false,
extrudePath: curveL1
})
const geometryL2 = new THREE.ExtrudeGeometry(shape, {
steps: 1,
bevelEnabled: false,
extrudePath: curveL2
})
const geometryL3 = new THREE.ExtrudeGeometry(shape, {
steps: 1,
bevelEnabled: false,
extrudePath: curveL3
})
const geometryL4 = new THREE.ExtrudeGeometry(shape, {
steps: 1,
bevelEnabled: false,
extrudePath: curveL4
})
geometries.push(geometryL1, geometryL2, geometryL3, geometryL4)
return mergeGeometries(geometries)
}
// 创建cc5叉的背板
static createCC5ForkBasePlate(): THREE.BufferGeometry {
// 606.5
const width = 0.3
const depth = 1.188
const dd = 0.05
const fdx = 0.06
const fdy = 0.03
const shape = new THREE.Shape();
shape.moveTo(-0.744 + 0.1, -0.5);
shape.lineTo(-0.744 + 0.1, 0.5);
shape.lineTo(-0.744 + 0.2, 0.5);
shape.lineTo(-0.744 + 0.2, -0.5);
shape.closePath()
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, -1.5/*0.02*/, 0), new THREE.Vector3(0, 1.287, 0)],
false, // 闭合曲线
'catmullrom',
0
)
const options = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curve // 设置挤出轨迹
}
return new THREE.ExtrudeGeometry(shape, options)
}
static cc5PedestalGeometry: THREE.BufferGeometry = null
static cc5PillarGeometry: THREE.BufferGeometry = null
static cc5ForkGeometry: THREE.BufferGeometry = null
static cc5GemelGeometryL: THREE.BufferGeometry = null
static cc5GemelGeometryR: THREE.BufferGeometry = null
static cc5ForkBasePlateGeometry: THREE.BufferGeometry = null
}

305
src/modules/amr/cc/cc5/CC53dObject.ts

@ -0,0 +1,305 @@
import * as THREE from 'three'
import {CSG} from 'three-csg-ts'
import gsap from 'gsap'
//@ts-ignore
import {mergeGeometries} from 'three/addons/utils/BufferGeometryUtils.js'
import CC53DGraphics from "@/modules/amr/cc/cc5/CC53DGraphics";
import Viewport from "@/core/engine/Viewport";
import PtrObject from "@/modules/amr/ptr/PtrObject";
import {worldModel} from "@/core/manager/WorldModel";
export default class CC53dObject extends PtrObject {
override __rotationSpeed = (Math.PI / 10)
override __showForkSpeed: number = 0.15
override __upForkSpeed: number = 0.15
private get upForkSpeed() {
return this.__upForkSpeed * (worldModel.state.runState.timeRate ?? 1)
}
private get showForkSpeed() {
return this.__showForkSpeed * (worldModel.state.runState.timeRate ?? 1)
}
private get rotationSpeed() {
return this.__rotationSpeed * (worldModel.state.runState.timeRate ?? 1)
}
constructor(item: ItemJson, viewport: Viewport, option?: RendererCudOption) {
super(item, viewport)
if (!CC53DGraphics.cc5PedestalGeometry) {
CC53DGraphics.cc5PedestalGeometry = CC53DGraphics.createCC5Pedestal()
}
const cc5PedestalGeometry = CC53DGraphics.cc5PedestalGeometry
const cc5PedestalMaterial = new THREE.MeshPhongMaterial({color: 0xffdddbca})
const cc5PedestalMesh = new THREE.Mesh(cc5PedestalGeometry, cc5PedestalMaterial)
if (!CC53DGraphics.cc5PillarGeometry) {
CC53DGraphics.cc5PillarGeometry = CC53DGraphics.createCC5Pillar()
}
const cc5PillarGeometry = CC53DGraphics.cc5PillarGeometry
const cc5PillarMaterial = new THREE.MeshPhongMaterial({color: 0xff6c6956})
const cc5PillarMesh = new THREE.Mesh(cc5PillarGeometry, cc5PillarMaterial)
if (!CC53DGraphics.cc5ForkGeometry) {
CC53DGraphics.cc5ForkGeometry = CC53DGraphics.createCC5Fork()
}
const cc5ForkGeometry = CC53DGraphics.cc5ForkGeometry
const cc5ForkMaterial = new THREE.MeshPhongMaterial({color: 0xff444444})
const cc5ForkMesh = new THREE.Mesh(cc5ForkGeometry, cc5ForkMaterial)
cc5ForkMesh.name = 'cc5Fork'
if (!CC53DGraphics.cc5GemelGeometryL) {
CC53DGraphics.cc5GemelGeometryL = CC53DGraphics.createCC5Gemel(true)
}
const cc5GemelGeometryL = CC53DGraphics.cc5GemelGeometryL
if (!CC53DGraphics.cc5GemelGeometryR) {
CC53DGraphics.cc5GemelGeometryR = CC53DGraphics.createCC5Gemel(false)
}
const cc5GemelGeometryR = CC53DGraphics.cc5GemelGeometryR
const cc5GemelMaterial = new THREE.MeshPhongMaterial({color: 0xff555555})
const cc5GemelMeshL1 = new THREE.Mesh(cc5GemelGeometryL, cc5GemelMaterial)
cc5GemelMeshL1.name = 'cc5GemelMeshL1'
const cc5GemelMeshL2 = new THREE.Mesh(cc5GemelGeometryL, cc5GemelMaterial)
cc5GemelMeshL2.name = 'cc5GemelMeshL2'
const cc5GemelMeshR1 = new THREE.Mesh(cc5GemelGeometryR, cc5GemelMaterial)
cc5GemelMeshR1.name = 'cc5GemelMeshR1'
const cc5GemelMeshR2 = new THREE.Mesh(cc5GemelGeometryR, cc5GemelMaterial)
cc5GemelMeshR2.name = 'cc5GemelMeshR2'
if (!CC53DGraphics.cc5ForkBasePlateGeometry) {
CC53DGraphics.cc5ForkBasePlateGeometry = CC53DGraphics.createCC5ForkBasePlate()
}
const cc5ForkBasePlateGeometry = CC53DGraphics.cc5ForkBasePlateGeometry
const cc5ForkBasePlateMesh = new THREE.Mesh(cc5ForkBasePlateGeometry, cc5GemelMaterial)
cc5ForkBasePlateMesh.name = 'cc5ForkBasePlateMesh'
const d = 0
this.add(cc5PedestalMesh)
this.add(cc5PillarMesh)
this.add(cc5ForkMesh)
const ac = Math.asin(d / (2 * 0.8))
cc5GemelMeshL1.position.z = 0.5 - d / 4
cc5GemelMeshL1.position.y = 0.72
cc5GemelMeshL1.rotation.x = -ac
cc5GemelMeshL2.position.z = 0.5 - d / 4 * 3
cc5GemelMeshL2.position.y = 0.72
cc5GemelMeshL2.rotation.x = -ac
cc5GemelMeshR1.position.z = 0.5 - d / 4
cc5GemelMeshR1.position.y = 0.72
cc5GemelMeshR1.rotation.x = ac
cc5GemelMeshR2.position.z = 0.5 - d / 4 * 3
cc5GemelMeshR2.position.y = 0.72
cc5GemelMeshR2.rotation.x = ac
this.add(cc5GemelMeshL1)
this.add(cc5GemelMeshL2)
this.add(cc5GemelMeshR1)
this.add(cc5GemelMeshR2)
this.add(cc5ForkBasePlateMesh)
}
override animationShowFork(z: number): Promise<void> {
const cc5Fork = this.getObjectByName('cc5Fork')
const cc5GemelMeshL1 = this.getObjectByName('cc5GemelMeshL1')
const cc5GemelMeshL2 = this.getObjectByName('cc5GemelMeshL2')
const cc5GemelMeshR1 = this.getObjectByName('cc5GemelMeshR1')
const cc5GemelMeshR2 = this.getObjectByName('cc5GemelMeshR2')
const cc5ForkBasePlateMesh = this.getObjectByName('cc5ForkBasePlateMesh')
const fy = cc5Fork.position.y
const time = Math.abs((cc5Fork.position.z - z) / this.upForkSpeed)
const ac = Math.asin(z / (2 * 0.8))
// cc5GemelMeshL1.position.z = 0.5 - z/4
// cc5GemelMeshL1.position.y = fy + 0.72
// cc5GemelMeshL1.rotation.x = -ac
gsap.to(cc5GemelMeshL1.position, {
z: 0.5 - z / 4,
y: fy + 0.72,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
gsap.to(cc5GemelMeshL1.rotation, {
x: -ac,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
// cc5GemelMeshL2.position.z = 0.5 - z/4 * 3
// cc5GemelMeshL2.position.y = fy + 0.72
// cc5GemelMeshL2.rotation.x = -ac
gsap.to(cc5GemelMeshL2.position, {
z: 0.5 - z / 4 * 3,
y: fy + 0.72,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
gsap.to(cc5GemelMeshL2.rotation, {
x: -ac,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
// cc5GemelMeshR1.position.z = 0.5 - z/4
// cc5GemelMeshR1.position.y = fy + 0.72
// cc5GemelMeshR1.rotation.x = ac
gsap.to(cc5GemelMeshR1.position, {
z: 0.5 - z / 4,
y: fy + 0.72,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
gsap.to(cc5GemelMeshR1.rotation, {
x: ac,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
// cc5GemelMeshR2.position.z = 0.5 - z/4 * 3
// cc5GemelMeshR2.position.y = fy + 0.72
// cc5GemelMeshR2.rotation.x = ac
gsap.to(cc5GemelMeshR2.position, {
z: 0.5 - z / 4 * 3,
y: fy + 0.72,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
gsap.to(cc5GemelMeshR2.rotation, {
x: ac,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
gsap.to(cc5ForkBasePlateMesh.position, {
y: fy,
duration: time,
repeat: 0,
ease: 'power1.inOut'
})
return new Promise(resolve => {
this.actionAnimation = gsap.to(cc5Fork.position, {
z: -z,
duration: time,
repeat: 0,
ease: 'power1.inOut',
onComplete: ()=>{
setTimeout(() => {
resolve()
}, 1000 / (worldModel.state.runState.timeRate ?? 1))
},
})
})
}
override animationHideFork(): Promise<void> {
return this.animationShowFork(0)
}
override animationUpFork(y: number): Promise<void> {
const cc5Fork = this.getObjectByName('cc5Fork')
const cc5GemelMeshL1 = this.getObjectByName('cc5GemelMeshL1')
const cc5GemelMeshL2 = this.getObjectByName('cc5GemelMeshL2')
const cc5GemelMeshR1 = this.getObjectByName('cc5GemelMeshR1')
const cc5GemelMeshR2 = this.getObjectByName('cc5GemelMeshR2')
const cc5ForkBasePlateMesh = this.getObjectByName('cc5ForkBasePlateMesh')
const time = Math.abs((cc5Fork.position.y - y) / this.upForkSpeed)
gsap.to(cc5GemelMeshL1.position, {
y: y + 0.72,
duration: time,
repeat: 0,
ease: 'sine.inOut'
})
gsap.to(cc5GemelMeshL2.position, {
y: y + 0.72,
duration: time,
repeat: 0,
ease: 'sine.inOut'
})
gsap.to(cc5GemelMeshR1.position, {
y: y + 0.72,
duration: time,
repeat: 0,
ease: 'sine.inOut'
})
gsap.to(cc5GemelMeshR2.position, {
y: y + 0.72,
duration: time,
repeat: 0,
ease: 'sine.inOut'
})
gsap.to(cc5ForkBasePlateMesh.position, {
y: y,
duration: time,
repeat: 0,
ease: 'sine.inOut'
})
return new Promise(resolve => {
const bh = 0.22
const children = cc5Fork.children
this.actionAnimation = gsap.to(cc5Fork.position, {
y: y,
duration: time,
repeat: 0,
ease: 'sine.inOut',
onComplete: ()=>{
setTimeout(() => {
resolve()
}, 1000 / (worldModel.state.runState.timeRate ?? 1))
},
onUpdate: function() {
const a = this.targets()[0]
if (a.y < bh) {
if (a.z > -1) {
for (let i = 0; i < children.length; i++) {
const child = children[i]
child.position.y = bh - a.y
}
} else if (a.y < 0 ) {
for (let i = 0; i < children.length; i++) {
const child = children[i]
child.position.y = 0 - a.y
}
}
}
}
})
})
}
override animationDownFork(): Promise<void> {
return this.animationUpFork(0)
}
override getArmObject(): THREE.Object3D | undefined {
const cc5Fork = this.getObjectByName('cc5Fork')
return cc5Fork
}
}

11
src/modules/amr/cc/cc5/CC5Entity.ts

@ -0,0 +1,11 @@
import BaseEntity from '@/core/base/BaseItemEntity.ts'
import type Viewport from '@/core/engine/Viewport.ts'
import * as THREE from 'three'
import gsap from 'gsap'
import CC53dObject from './CC53dObject.ts'
export default class CC5Entity extends BaseEntity {
constructor(viewport: Viewport, id: string) {
super(viewport, id)
}
}

22
src/modules/amr/cc/cc5/CC5Interaction.ts

@ -0,0 +1,22 @@
import BaseInteraction from '@/core/base/BaseInteraction.ts'
import * as THREE from 'three'
export default class CC5Interaction 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.palletWidth = 1 // 宽度
item.dt.palletDepth = 1.2 // 深度
return item
}
}

24
src/modules/amr/cc/cc5/CC5PropertySetter.ts

@ -0,0 +1,24 @@
import type { PropertySetter } from "@/core/base/PropertyTypes.ts";
import { basicFieldsSetter } from "@/editor/widgets/property/PropertyPanelConstant.ts";
const propertySetter: PropertySetter = {
flatten: {
fields: [
...basicFieldsSetter,
{
dataPath: 'dt.clxWidth', label: 'CC5宽度', input: 'InputNumber',
inputProps: {},
},
{
dataPath: 'dt.clxDepth', label: 'CC5深度', input: 'InputNumber',
inputProps: {},
},
{
dataPath: 'state', label: 'CC5控制', input: 'PtrController',
inputProps: {},
},
],
},
};
export default propertySetter;

119
src/modules/amr/cc/cc5/CC5Renderer.ts

@ -0,0 +1,119 @@
import * as THREE from 'three'
import BaseRenderer from '@/core/base/BaseRenderer.ts'
import Constract from '@/core/Constract.ts'
import CC53dObject from './CC53dObject'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import Viewport from "@/core/engine/Viewport";
/**
* clx渲染器
*/
export default class CC5Renderer extends BaseRenderer {
static POINT_NAME = 'cc5'
pointMaterial: THREE.Material
/**
* ,
*/
readonly defulePositionY: number = Constract.HEIGHT_WAY
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1.65, 3.393, 1.65)
readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0)
readonly defaultLineWidth: number = 0.15
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])
)
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D {
throw new Error('not allow store line.')
}
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
throw new Error('not allow store line.')
}
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
// 创建平面几何体
const group = new CC53dObject(item, this.tempViewport, option)
group.name = CC5Renderer.POINT_NAME
// 设置位置
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
return group
}
/**
* Cl2 Position Rotation
*/
getStorePlacement(storeItem: ItemJson, bay = 0, level = 0, cell = 0)
: {
position: [number, number, number], rotation: [number, number, number],
getParentObject3D?: (viewport: Viewport, parent: THREE.Object3D) => THREE.Object3D
} {
return {
position: [0, 0.2, -0.15],
rotation: [0, 90, 0],
getParentObject3D: this.getArmObject.bind(this)
}
}
getArmObject(viewport: Viewport, item: ItemJson): THREE.Object3D {
// 获取机械臂对象
const object = viewport.entityManager.findObjectById(item.dt.storeAt?.item)
if (!object) {
console.warn('PtrRenderer: getArmObject failed, not found Cl2:', item.dt.storeAt?.item)
return
}
const agv = object as THREE.Group
const clxFork = agv.getObjectByName('clxFork')
return clxFork
}
updatePoint(item: ItemJson, object: Object3DLike, option?: RendererCudOption): Object3DLike {
const group: THREE.Group = object as 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])
)
// 禁止缩放,
item.tf[2][0] = this.defaultScale.x
item.tf[2][1] = this.defaultScale.y
item.tf[2][2] = this.defaultScale.z
return group
}
dispose() {
super.dispose()
this.pointMaterial?.dispose()
}
createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
throw new Error('Clx createPointBasic not allow!')
}
}

12
src/modules/amr/cc/cc5/index.ts

@ -0,0 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts'
import CC5Renderer from './CC5Renderer.ts'
import CC5Interaction from './CC5Interaction.ts'
import propertySetter from './CC5PropertySetter.ts'
export const ITEM_TYPE_NAME = 'cc5'
export default defineModule(ITEM_TYPE_NAME, () => ({
renderer: new CC5Renderer(ITEM_TYPE_NAME),
interaction: new CC5Interaction(ITEM_TYPE_NAME),
setter: propertySetter
}))

198
src/modules/amr/fm600/FM6003DGraphics.ts

@ -0,0 +1,198 @@
import * as THREE from "three";
import {CSG} from "three-csg-ts";
//@ts-ignore
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js'
export default class FM6003DGraphics {
// 创建ptr的底座
public static createFm600Pedestal(): THREE.BufferGeometry {
// 参数配置
const radius = 0.475 // 圆半径
const lineDist = 0.325 // 切割线距离圆心距离
const segments = 64 // 圆的分段精度
// 计算切割线与圆的交点
const intersectY = Math.sqrt(radius * radius - lineDist * lineDist)
const startAngle = Math.asin(intersectY / radius)
const endAngle = Math.PI - startAngle //Math.acos(intersectY / radius)
const shape = new THREE.Shape()
shape.moveTo(0, 0) // 起点在圆心
shape.absarc(0, 0, radius, startAngle, endAngle, false) // 从0到π绘制半圆
// shape.lineTo(-lineDist, intersectY)
shape.absarc(0, 0, radius, startAngle + Math.PI, endAngle + Math.PI, false)
// shape.lineTo(lineDist, -intersectY)
// shape.lineTo(-0.5, -intersectY + 0.17)
// shape.lineTo(0.75, -intersectY + 0.17)
// shape.lineTo(0.75, intersectY - 0.17)
// shape.lineTo(-0.5, intersectY - 0.17)
shape.closePath() // 闭合路径
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.025, 0), new THREE.Vector3(0, 0.235, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelEnabled: false,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({color: 0xffdddbca})
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
// 倒角
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.035, -0.02)
shapeD.lineTo(0.035, 0.02)
shapeD.lineTo(-0.035, 0.02)
shapeD.closePath()
const curveD = new THREE.EllipseCurve(
0, 0, radius, radius, 0, Math.PI * 2, false, 0
)
// 生成拉伸路径点
const pointsD = curveD.getPoints(segments).map(p =>
new THREE.Vector3(p.x, 0.200, p.y)
)
// 3. 挤出成型
const optionsD = {
steps: segments,
bevelEnabled: false,
// bevelSegments: 0.01,
extrudePath: new THREE.CatmullRomCurve3(pointsD)
}
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
// 布尔运算
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
// 创建fm600的顶盘
public static createFm600Plate(): THREE.BufferGeometry {
// 参数配置
const radius = 0.425 // 圆半径
const lineDist = 0.3 // 切割线距离圆心距离
const segments = 64 // 圆的分段精度
// 计算切割线与圆的交点
const intersectY = Math.sqrt(radius * radius - lineDist * lineDist)
const startAngle = Math.asin(intersectY / radius)
const endAngle = Math.PI - startAngle //Math.acos(intersectY / radius)
const shape = new THREE.Shape()
shape.moveTo(0, 0) // 起点在圆心
shape.absarc(0, 0, radius, startAngle, endAngle, false) // 从0到π绘制半圆
// shape.lineTo(-lineDist, intersectY)
shape.absarc(0, 0, radius, startAngle + Math.PI, endAngle + Math.PI, false)
shape.closePath() // 闭合路径
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.24, 0), new THREE.Vector3(0, 0.255, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelEnabled: false,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({color: 0xffdddbca})
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
const holeShape = new THREE.Shape()
holeShape.moveTo(0, 0)
holeShape.absarc(0, 0, 0.1, 0, Math.PI * 2, false) // 从0到π绘制半圆
// 拉伸轨迹线
const holeCurve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.24, 0), new THREE.Vector3(0, 0.255, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const holeOptions = {
steps: 1,
bevelEnabled: false,
extrudePath: holeCurve // 设置挤出轨迹
}
// 创建挤出几何体
const geometryD = new THREE.ExtrudeGeometry(holeShape, holeOptions)
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
// 布尔运算
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
public static createFm600Header(): THREE.BufferGeometry {
const radius = 0.475 // 圆半径
const lineDist = 0.325 // 切割线距离圆心距离
const segments = 64 // 圆的分段精度
// 计算切割线与圆的交点
const intersectY = Math.sqrt(radius * radius - lineDist * lineDist)
const startAngle = Math.asin(intersectY / radius)
const endAngle = Math.PI - startAngle //Math.acos(intersectY / radius)
const shapeH = new THREE.Shape()
shapeH.moveTo(-0.02, -0.02)
shapeH.lineTo(0.02, 0.02)
shapeH.lineTo(-0.02, 0.02)
shapeH.closePath()
const curveH = new THREE.EllipseCurve(
0, 0, radius-0.02, radius-0.02, Math.PI * 2 - startAngle + 0.1, startAngle - 0.1,false, 0
)
// 生成拉伸路径点
const pointsH = curveH.getPoints(segments).map(p =>
new THREE.Vector3(p.x, 0.210, p.y)
)
const optionsH = {
steps: segments,
bevelEnabled: false,
// bevelSegments: 0.01,
extrudePath: new THREE.CatmullRomCurve3(pointsH)
}
const geometryH = new THREE.ExtrudeGeometry(shapeH, optionsH)
return geometryH
}
public static fm600PedestalGeometry: THREE.BufferGeometry = null
public static fm600PlateGeometry: THREE.BufferGeometry = null
public static fm600HeaderGeometry: THREE.BufferGeometry = null
}

157
src/modules/amr/fm600/FM6003dObject.ts

@ -0,0 +1,157 @@
import * as THREE from 'three'
import {CSG} from 'three-csg-ts'
import gsap from 'gsap'
import mqtt from 'mqtt'
import {Euler} from 'three/src/math/Euler'
import FM600Entity from './FM600Entity'
import FM6003DGraphics from "./FM6003DGraphics"
import PtrObject from "@/modules/amr/ptr/PtrObject";
import Viewport from "@/core/engine/Viewport";
import {worldModel} from "@/core/manager/WorldModel";
export default class FM6003dObject extends PtrObject {
private _fm600Entity: FM600Entity = null
override __rotationSpeed = (Math.PI / 7)
override __showForkSpeed: number = 0.2
override __upForkSpeed: number = 0.05
private get upForkSpeed() {
return this.__upForkSpeed * (worldModel.state.runState.timeRate ?? 1)
}
private get rotationSpeed() {
return this.__rotationSpeed * (worldModel.state.runState.timeRate ?? 1)
}
public get fm600Entity(): FM600Entity {
if (!this._fm600Entity) {
const fm600: FM600Entity = Model.getFm600(this.item.id) as FM600Entity
this._fm600Entity = fm600
}
return this._fm600Entity
}
constructor(item: ItemJson, viewport: Viewport, option?: RendererCudOption) {
super(item, viewport)
if (!FM6003DGraphics.fm600PedestalGeometry) {
FM6003DGraphics.fm600PedestalGeometry = FM6003DGraphics.createFm600Pedestal()
}
// "#ff3232"
const fm600PedestalGeometry = FM6003DGraphics.fm600PedestalGeometry
const fm600PedestalMaterial = new THREE.MeshPhongMaterial({color: 0xffababab})
const fm600PedestalMesh = new THREE.Mesh(fm600PedestalGeometry, fm600PedestalMaterial)
const groupPedestal = new THREE.Group()
groupPedestal.name = 'fm600Pedestal'
groupPedestal.add(fm600PedestalMesh)
if (!FM6003DGraphics.fm600HeaderGeometry) {
FM6003DGraphics.fm600HeaderGeometry = FM6003DGraphics.createFm600Header()
}
const fm600HeaderGeometry = FM6003DGraphics.fm600HeaderGeometry
const fm600HeaderMaterial = new THREE.MeshPhongMaterial({color: 0xffff3232})
const fm600HeaderMesh = new THREE.Mesh(fm600HeaderGeometry, fm600HeaderMaterial)
groupPedestal.add(fm600HeaderMesh)
if (!FM6003DGraphics.fm600PlateGeometry) {
FM6003DGraphics.fm600PlateGeometry = FM6003DGraphics.createFm600Plate()
}
const fm600PlateGeometry = FM6003DGraphics.fm600PlateGeometry
// "#1f1d1d"
const fm600PlateMaterial = new THREE.MeshPhongMaterial({color: 0xff4d4d4d})
const pfm600PlateMesh = new THREE.Mesh(fm600PlateGeometry, fm600PlateMaterial)
pfm600PlateMesh.name = 'fm600Plate'
this.add(groupPedestal)
this.add(pfm600PlateMesh)
}
/*==========动画处理============*/
// 取货
override addLoad(height: number, goodsId: string): void {
this.actionAnimation = 'wq'
this.TaskMode = 2
this.OperationType = 1
this.animationUpPlate(0.1).then(
() => {
try {
// 将物品拾取到机械臂上
const mesh = this.pickupItem(goodsId)
mesh.position.set(0, 0, -0.15)
mesh.rotation.set(0, THREE.MathUtils.degToRad(90), 0)
this.getArmObject().add(mesh)
} catch (e) {
console.error(e)
}
}
)
}
// 卸货
override addUnload(height: number, goodsId: string): void {
this.actionAnimation = 'wq'
this.TaskMode = 2
this.OperationType = 2
this.animationDownPlate().then(
() => {
try {
const a = this.agvStatusVo.unloadBasLocationVo
// 将物品从机械臂上卸下
this.dropItem(goodsId, a.rack, a.bay, a.level, a.cell)
} catch (e) {
console.error(e)
}
}
)
}
animationUpPlate(y: number): Promise<void> {
const fm600Plate = this.getObjectByName('fm600Plate')
const time = Math.abs((fm600Plate.position.y - y) / this.upForkSpeed)
return new Promise(resolve => {
const bh = 0.32
const children = fm600Plate.children
this.actionAnimation = gsap.to(fm600Plate.position, {
y: y,
duration: time,
repeat: 0,
ease: 'sine.inOut',
onComplete: ()=>{
setTimeout(() => {
resolve()
}, 1000 / (worldModel.state.runState.timeRate ?? 1))
},
onUpdate: function () {
const a = this.targets()[0]
if (a.y < bh) {
if (a.y < 0) {
for (let i = 0; i < children.length; i++) {
const child = children[i]
child.position.y = 0 - a.y
}
}
}
}
})
})
}
override animationDownPlate(): Promise<void> {
return this.animationUpFork(0)
}
override getArmObject(): THREE.Object3D | undefined {
return this.getObjectByName('fm600Plate')
}
}

120
src/modules/amr/fm600/FM600Entity.ts

@ -0,0 +1,120 @@
import * as THREE from 'three'
import BaseEntity from '@/core/base/BaseItemEntity.ts'
import type Viewport from '@/core/engine/Viewport.ts'
import gsap from 'gsap'
import { nextTick } from 'vue'
import FM6003dObject from "./FM6003dObject";
/**
* CL2
* 0.4m/ss // a max 1.2m/s
* 90 = 3.5s cl2
* 90 = 5s // cLX
*/
export default class FM600Entity extends BaseEntity {
constructor(viewport: Viewport, id: string) {
super(viewport, id)
}
// 抬
addArmRaise(height: number) {
// super.addArmRaise(height)
this.taskQueue.add(this.createTask('ARM_RAISE',
() => this.cl2Object.animationUpFork(height)
))
}
// 降
addArmLower() {
// super.addArmLower()
this.taskQueue.add(this.createTask('ARM_LOWER',
() => this.cl2Object.animationDownFork()
))
}
// 伸
addArmExtender(z: number = 1.2) {
// super.addArmExtender()
this.taskQueue.add(this.createTask('ARM_EXTEND',
() => this.cl2Object.animationShowFork(z)
))
}
// 缩
addArmRetractor() {
// super.addArmRetractor()
this.taskQueue.add(this.createTask('ARM_RETRACT',
() => this.cl2Object.animationHideFork()
))
}
// 装
addLoad(item: string): void {
const ptrForkMesh = this.getArmObject()
this.taskQueue.add(this.createTask('LOAD', async () => {
// 实际业务中应包含装载逻辑
this.isCarrying = true
this.isLoading = true
// 将物品拾取到机械臂上
const mesh = this.pickupItem(item)
mesh.position.set(0, 0, -0.15)
mesh.rotation.set(0, THREE.MathUtils.degToRad(90), 0)
ptrForkMesh.add(mesh)
}))
this.taskQueue.add(this.createTask('ARM_RAISE',
()=>{
return new Promise(resolve => {
gsap.to(ptrForkMesh.position, {
y: ptrForkMesh.position.y + 0.2,
duration: 1,
ease: 'sine.inOut',
onComplete: () => {
this.isCarrying = true
this.isLoading = false
resolve()
}
})
})
}))
}
// 卸
addUnload(itemId: string, rackId: string, bay?: number, level?: number, cell?: number): void {
this.taskQueue.add(this.createTask('UNLOAD', async () => {
const item = this.viewport.entityManager.findItemById(itemId)
this.isCarrying = false
this.isUnloading = false
// 将物品从机械臂上卸下
this.dropItem(item, rackId, bay, level)
}))
}
// 帮助方法:获取机械臂对象
getArmObject(): THREE.Object3D | undefined {
const agv = this.object as THREE.Group
if (agv.children.length > 1) {
const pillar = agv.children[1]
if (pillar.children.length > 1) {
return pillar.children[1]
}
}
return undefined
}
// 帮助方法:获取机械臂立柱
getArmPillar(): THREE.Object3D | undefined {
const agv = this.object as THREE.Group
if (agv.children.length > 1) {
return agv.children[1]
}
return undefined
}
get cl2Object(): FM6003dObject {
return this.object as FM6003dObject
}
}

22
src/modules/amr/fm600/FM600Interaction.ts

@ -0,0 +1,22 @@
import BaseInteraction from '@/core/base/BaseInteraction.ts'
import * as THREE from 'three'
export default class FM600Interaction 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.palletWidth = 1 // 宽度
item.dt.palletDepth = 1.2 // 深度
return item
}
}

24
src/modules/amr/fm600/FM600PropertySetter.ts

@ -0,0 +1,24 @@
import type { PropertySetter } from "@/core/base/PropertyTypes.ts";
import { basicFieldsSetter } from "@/editor/widgets/property/PropertyPanelConstant.ts";
const propertySetter: PropertySetter = {
flatten: {
fields: [
...basicFieldsSetter,
{
dataPath: 'dt.palletWidth', label: '托盘宽度', input: 'InputNumber',
inputProps: {},
},
{
dataPath: 'dt.palletDepth', label: '托盘深度', input: 'InputNumber',
inputProps: {},
},
{
dataPath: 'state', label: 'ptr控制', input: 'PtrController',
inputProps: {},
},
],
},
};
export default propertySetter;

122
src/modules/amr/fm600/FM600Renderer.ts

@ -0,0 +1,122 @@
import * as THREE from 'three'
import BaseRenderer from '@/core/base/BaseRenderer.ts'
import Constract from '@/core/Constract.ts'
import FM6003dObject from './FM6003dObject'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import type Viewport from '@/core/engine/Viewport.ts'
/**
* ptr侧叉渲染器
*/
export default class FM600Renderer extends BaseRenderer {
static POINT_NAME = 'fm600'
pointMaterial: THREE.Material
/**
* ,
*/
readonly defulePositionY: number = Constract.HEIGHT_WAY
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1.5, 1.98, 1.5)
readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0)
constructor(itemTypeName: string) {
super(itemTypeName)
}
/**
* Cl2 Position Rotation
*/
getStorePlacement(storeItem: ItemJson, bay = 0, level = 0, cell = 0)
: {
position: [number, number, number], rotation: [number, number, number],
getParentObject3D?: (viewport: Viewport, parent: THREE.Object3D) => THREE.Object3D
} {
return {
position: [0, 0.2, -0.15],
rotation: [0, 90, 0],
getParentObject3D: this.getArmObject.bind(this)
}
}
getArmObject(viewport: Viewport, item: ItemJson): THREE.Object3D {
// 获取机械臂对象
const object = viewport.entityManager.findObjectById(item.dt.storeAt?.item)
if (!object) {
console.warn('PtrRenderer: getArmObject failed, not found Cl2:', item.dt.storeAt?.item)
return
}
const agv = object as THREE.Group
if (agv.children.length > 1) {
const pillar = agv.children[1]
if (pillar.children.length > 1) {
return pillar.children[1]
}
}
}
/**
* 使 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])
)
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D {
throw new Error('not allow store line.')
}
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
throw new Error('not allow store line.')
}
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
// 创建平面几何体
const group = new FM6003dObject(item, this.tempViewport, option)
group.name = FM600Renderer.POINT_NAME
// 设置位置
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
return group
}
updatePoint(item: ItemJson, object: Object3DLike, option?: RendererCudOption): Object3DLike {
const group: THREE.Group = object as 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])
)
// 禁止缩放,
item.tf[2][0] = this.defaultScale.x
item.tf[2][1] = this.defaultScale.y
item.tf[2][2] = this.defaultScale.z
return group
}
dispose() {
super.dispose()
this.pointMaterial?.dispose()
}
createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
throw new Error('Ptr createPointBasic not allow!')
}
}

12
src/modules/amr/fm600/index.ts

@ -0,0 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts'
import FM600Renderer from './FM600Renderer.ts'
import FM600Interaction from './FM600Interaction.ts'
import propertySetter from './FM600PropertySetter.ts'
export const ITEM_TYPE_NAME = 'fm600'
export default defineModule(ITEM_TYPE_NAME, () => ({
renderer: new FM600Renderer(ITEM_TYPE_NAME),
interaction: new FM600Interaction(ITEM_TYPE_NAME),
setter: propertySetter
}))

41
src/modules/amr/ptr/PtrObject.ts

@ -661,7 +661,7 @@ export default class PtrObject extends THREE.Object3D {
endDirection = data.EndDirection
} else if (data.OperationType == 3 && data.ChargeDirection >= 0 && data.ChargeDirection <= 3) {
endDirection = data.ChargeDirection
} else if (data.OperationType == 4 && data.GoodsSlotDirection >= 0 && data.GoodsSlotDirection <= 3) {
} else if ((data.OperationType == 1 || data.OperationType == 2 || data.OperationType == 4) && data.GoodsSlotDirection >= 0 && data.GoodsSlotDirection <= 3) {
if (data.GoodsSlotDirection == 0) {
endDirection = 3
} else {
@ -692,6 +692,41 @@ export default class PtrObject extends THREE.Object3D {
}
}
if (data.OperationType == 1) {
const stepTask: StepTask = {
SeqNo: data.SeqNo,
StepTaskType: 'LOAD',
OperationType: 1,
PickMode: 0,
X: data.EndX,
Y: data.EndY,
Speed: currentStepTask.Speed,
EndDirection: endDirection,
ChargeLocation: data.ChargeLocation,
GoodsSlotHeight: data.GoodsSlotHeight,
position: Model.getPositionByLogicXY(data.EndX, data.EndY) as THREE.Vector3,
isCompleted: false
}
this.currentStepTaskList.push(stepTask)
} else if (data.OperationType == 2) {
const stepTask: StepTask = {
SeqNo: data.SeqNo,
StepTaskType: 'UNLOAD',
OperationType: 2,
PickMode: 0,
X: data.EndX,
Y: data.EndY,
Speed: currentStepTask.Speed,
EndDirection: endDirection,
ChargeLocation: data.ChargeLocation,
GoodsSlotHeight: data.GoodsSlotHeight,
position: Model.getPositionByLogicXY(data.EndX, data.EndY) as THREE.Vector3,
isCompleted: false
}
this.currentStepTaskList.push(stepTask)
}
if (data.OperationType == 3) {
const stepTask: StepTask = {
@ -983,7 +1018,7 @@ export default class PtrObject extends THREE.Object3D {
}
// 取货
addLoad(height: number, goodsId: string): void {
override addLoad(height: number, goodsId: string): void {
this.actionAnimation = 'wq'
this.TaskMode = 2
this.PickMode = 1
@ -1015,7 +1050,7 @@ export default class PtrObject extends THREE.Object3D {
}
// 卸货
addUnload(height: number, goodsId: string): void {
override addUnload(height: number, goodsId: string): void {
this.actionAnimation = 'wq'
this.TaskMode = 2
this.PickMode = 2

8
src/types/Model.d.ts

@ -34,6 +34,11 @@ declare interface Model {
*/
getClx(id: string): ClxIf
/**
* ID获取 FM600
*/
getFm600(id: string): Fm600If
/**
*
@ -398,6 +403,9 @@ interface Cl2If extends EntityIf, Carry, Walk, ForkArm, LiftingArm {
interface ClxIf extends EntityIf, Carry, Walk, ForkArm, LiftingArm {
}
interface Fm600If extends EntityIf, Carry, Walk, ForkArm, LiftingArm {
}
interface CustomScript {
/**
*

Loading…
Cancel
Save