diff --git a/src/editor/propEditors/PtrController.vue b/src/editor/propEditors/PtrController.vue
index 423b11c..ebe10da 100644
--- a/src/editor/propEditors/PtrController.vue
+++ b/src/editor/propEditors/PtrController.vue
@@ -6,7 +6,7 @@ import { CopyDocument, Delete } from "@element-plus/icons-vue";
import { Typeof } from "@ease-forge/shared";
import type Viewport from "@/core/engine/Viewport";
import {BayEditorProps} from "@/editor/propEditors/BayEditor.vue";
-import Cl23dObject from "@/modules/cl2/Cl23dObject";
+import PtrObject from "@/modules/amr/ptr/PtrObject";
defineOptions({
name: 'PtrController',
@@ -18,9 +18,16 @@ function start() {
const viewport: Viewport = window['viewport']
// viewport.envManager.client.publish('/agv_robot/status', '')
const item = viewport.state.selectedItem
- const object3D: Cl23dObject = viewport.state.selectedObject as Cl23dObject
- console.log(item, object3D)
- object3D.boot()
+ const ptrObject: PtrObject = viewport.state.selectedObject as PtrObject
+ ptrObject.boot()
+}
+
+function stop() {
+ const viewport: Viewport = window['viewport']
+ // viewport.envManager.client.publish('/agv_robot/status', '')
+ const item = viewport.state.selectedItem
+ const ptrObject: PtrObject = viewport.state.selectedObject as PtrObject
+ ptrObject.shutdown()
}
@@ -29,6 +36,7 @@ function start() {
启动
+ 关闭
diff --git a/src/modules/amr/ptr/PtrObject.ts b/src/modules/amr/ptr/PtrObject.ts
new file mode 100644
index 0000000..59a90c6
--- /dev/null
+++ b/src/modules/amr/ptr/PtrObject.ts
@@ -0,0 +1,828 @@
+import * as THREE from "three";
+import {
+ AmrErrorCode,
+ AmrMsg, AmrMsg10010, AmrMsg10050, AmrMsg10060, AmrMsg10110, AmrMsg10120, AmrMsg20010,
+ AmrMsg20011, AmrMsg20020, AmrMsg20050, AmrMsg20060, AmrMsg20100,
+ AmrMsg20147,
+ AmrMsg20148, AmrMsg20149, AmrMsg20150, AmrMsg20250,
+ type CEventId,
+ type COperationType,
+ type CPickMode,
+ type CTaskMode, CurBatteryData,
+ type LogicDirection,
+ TaskCompletedData,
+ TaskModeChangeData,
+ TaskStatusChangeData,
+ TaskTypeChangeData
+} from "@/core/manager/amr/AmrMessageDefine";
+import {worldModel} from "@/core/manager/WorldModel";
+import Viewport from "@/core/engine/Viewport";
+import {Euler} from "three/src/math/Euler";
+import gsap from "gsap";
+
+
+type CStepTaskType = "MOVE" | "MOVE_BACKWARD" | "ROTATION" | "LOAD" | "UNLOAD" | "CHARGE"
+
+export interface StepTask {
+ SeqNo: number;
+ StepTaskType: CStepTaskType;
+ OperationType: 0 | 1 | 2 | 3 | 4 | 5 | 135 | 136;
+ PickMode: 0 | 1 | 2 | 3 | 4 | 5 | 6;
+ X: number;
+ Y: number;
+ Speed: number;
+ EndDirection: 0 | 1 | 2 | 3 | 15;
+ ChargeLocation: number;
+ GoodsSlotHeight: number;
+ position: THREE.Vector3;
+ isCompleted: boolean;
+}
+
+export default class PtrObject extends THREE.Object3D {
+
+ public item: ItemJson
+ public readonly viewport: Viewport
+
+ public currentLogicX: number = -1
+ public currentLogicY: number = -1
+ public currentDirection: LogicDirection = 15
+ public currentOrientation: number = 0
+ public sendMessageQueue: AmrMsg[] = []
+
+ public Battery: number = 100
+
+ public vehicleId: number
+
+ public clock = new THREE.Clock()
+
+ override AGVModel = ""
+ override AGVFnModel = ""
+
+ private currentStepTaskList: StepTask[] = []
+ private runningStepTask: StepTask = null
+ public runningStepTaskList: StepTask[] = []
+
+ public travelAnimation: core.Tween = null
+
+ // 心跳间隔 UInt32 单位: s
+ private heartBeatInterval: number = 0
+ // 小车所有上报消息重试间隔(未收到应答消息时重发消息) UInt32 单位: s
+ private mqRetryInterval: number = 3
+
+ private __TaskMode: CTaskMode = 0
+ private __OperationType: COperationType = 0
+ private __TaskStatus: CEventId = 0
+ private __PickMode: CPickMode = 0
+
+
+ get TaskMode(): CTaskMode {
+ return this.__TaskMode
+ }
+
+ set TaskMode(value: CTaskMode) {
+ if (this.__TaskMode != value) {
+ const info = new TaskModeChangeData(this.__TaskMode, value)
+ const msg = new AmrMsg20011(this.vehicleId, info)
+ msg.TaskMode = value
+ this.send20011(msg)
+ }
+ this.__TaskMode = value
+ }
+
+ get OperationType(): COperationType {
+ return this.__OperationType
+ }
+
+ set OperationType(value: COperationType) {
+ if (this.__OperationType != value) {
+ const info = new TaskTypeChangeData(this.__OperationType, value)
+ const msg = new AmrMsg20011(this.vehicleId, info)
+ msg.TaskMode = this.TaskMode
+ this.send20011(msg)
+ }
+ this.__OperationType = value
+ }
+
+ get TaskStatus(): CEventId {
+ return this.__TaskStatus
+ }
+
+ set TaskStatus(value: CEventId) {
+ if (this.__TaskStatus != value) {
+
+ if (value != 1 && value != 4 && value != 8) {
+ const info = new TaskStatusChangeData(this.OperationType)
+ const msg = new AmrMsg20011(this.vehicleId, info)
+ msg.TaskMode = this.TaskMode
+ msg.EventId = value
+ this.send20011(msg)
+ } else if (value == 4) {
+
+ const info = new TaskCompletedData(this.OperationType)
+ info.Battery = this.Battery
+ info.OperationResult = 0
+ info.CurLogicX = this.currentLogicX
+ info.CurLogicY = this.currentLogicY
+ info.CurX = this.currentLogicX
+ info.CurY = this.currentLogicY
+ info.CurDirection = this.currentDirection
+ info.CurOrientation = this.currentOrientation
+ const msg = new AmrMsg20011(this.vehicleId, info)
+ msg.TaskMode = this.TaskMode
+ this.send20011(msg)
+ }
+
+ }
+ }
+
+ get PickMode(): CPickMode {
+ return this.__PickMode
+ }
+ set PickMode(value: CPickMode) {
+ if (this.__PickMode !== value) {
+ this.__PickMode = value
+ }
+ }
+
+ private bootTime: number = 0
+
+ private heartBeatTimeCount: number = 0
+ private mqRetryTimeCount: number = 0
+
+ constructor(item: ItemJson, viewport: Viewport) {
+ super();
+ this.viewport = viewport
+ this.item = item
+ this.vehicleId = parseInt(item.id)
+
+ this.viewport.addFrameTimerCallback(this.item.id, this.onFrameTimer.bind(this))
+ if (!worldModel.state.runState.isVirtual) {
+ this.subscribeMessage('/wcs_server/' + this.item.id)
+ this.subscribeMessage('/agv_robot/status')
+ }
+ }
+
+ protected onFrameTimer() {
+ if (!worldModel.state.runState.isVirtual) {
+ return
+ }
+ const delta = this.clock.getDelta()
+ this.mqRetryTimeCount += delta
+ if (this.mqRetryInterval > 0 && this.mqRetryTimeCount >= this.mqRetryInterval) {
+ this.mqRetryTimeCount = 0
+ // 在此处理消息重试
+ if (this.sendMessageQueue.length > 0) {
+ this.sendMessage(this.sendMessageQueue[0])
+ }
+ }
+ this.heartBeatTimeCount += delta
+ if (this.heartBeatInterval > 0 && this.heartBeatTimeCount >= this.heartBeatInterval) {
+ this.heartBeatTimeCount = 0
+ // 在此处发送心跳报文
+ this.sendHeartBeat()
+ }
+ }
+
+ // 开机
+ boot() {
+ this.bootTime = Date.now();
+ this.computeLogicXYAndDirection();
+
+ if (!worldModel.state.runState.isVirtual) {
+ return
+ }
+ this.subscribeMessage('/wcs_server/' + this.vehicleId)
+ this.send20147()
+ setTimeout(() => {
+ this.send20149()
+ this.TaskMode = 1
+ // 检查当前所在位置和方向 根据车当前所在的xz坐标获取地标
+ setTimeout(() => {
+ this.sendCurrentPositionAndDirection()
+ setTimeout(() => {
+ this.send20150()
+ }, 1000)
+ }, 1000)
+ }, 2000)
+
+ }
+
+ // 关机
+ shutdown() {
+ if (!worldModel.state.runState.isVirtual) {
+ return
+ }
+ const content = new AmrMsg20148(this.vehicleId)
+ // 电量
+ content.Battery = 100
+ content.CreateMonoTime = Date.now() - this.bootTime
+ content.Uptime = content.CreateMonoTime
+ const m20148 = new AmrMsg(content)
+ this.sendMessage(m20148)
+ }
+
+ // 开机上报
+ send20147() {
+ const content = new AmrMsg20147(this.vehicleId)
+ content.AGVModel = this.AGVModel
+ content.AGVFnModel = this.AGVFnModel
+ // 电量
+ content.Battery = 100
+ content.CreateMonoTime = Date.now() - this.bootTime
+ const m20147 = new AmrMsg(content)
+ this.sendMessage(m20147)
+ }
+
+ // 主程序启动上报
+ send20149() {
+ const content = new AmrMsg20149(this.vehicleId)
+ content.AGVModel = this.AGVModel
+ content.AGVFnModel = this.AGVFnModel
+ // 电量
+ content.Battery = 100
+ content.CreateMonoTime = Date.now() - this.bootTime
+ const m20149 = new AmrMsg(content)
+ this.sendMessage(m20149)
+ }
+
+ // 上线上报
+ send20150() {
+ const content = new AmrMsg20150(this.vehicleId)
+ content.AGVModel = this.AGVModel
+ content.AGVFnModel = this.AGVFnModel
+ content.Battery = 100
+ content.CreateMonoTime = Date.now() - this.bootTime
+ const m20150 = new AmrMsg(content)
+ this.sendMessage(m20150)
+ }
+
+ // 上报当前位姿,地标和方向
+ sendCurrentPositionAndDirection() {
+ if (this.currentLogicX <= 0 || this.currentLogicY <= 0) {
+ // 当前车辆所在位置未找到
+ const content = new AmrMsg20250(this.vehicleId)
+ content.Duration = 0
+ content.ErrCode = 5
+ content.ErrCodeName = AmrErrorCode[5].ErrCodeName
+ content.ErrEvtType = 1
+ content.ErrLevel = 14
+ content.ErrLifecycle = 2
+ content.CreateMonoTime = Date.now() - this.bootTime
+ const m20250 = new AmrMsg(content)
+ this.sendMessage(m20250)
+ } else {
+ // 发送正常地标信息
+ const content = new AmrMsg20020(this.vehicleId)
+ content.CurDirection = this.currentDirection
+ content.CurOrientation = this.currentOrientation
+ content.CurLogicX = this.currentLogicX
+ content.CurLogicY = this.currentLogicY
+ content.CurX = this.currentLogicX
+ content.CurY = this.currentLogicY
+ content.CreateMonoTime = Date.now() - this.bootTime
+ const m20020 = new AmrMsg(content)
+ this.sendMessage(m20020)
+ }
+ }
+
+ send20010() {
+ const content: AmrMsg20010 = new AmrMsg20010(this.vehicleId)
+ content.CurX = this.currentLogicX
+ content.CurY = this.currentLogicY
+ content.CurDirection = this.currentDirection
+ content.OperationType = this.OperationType
+ content.Battery = this.Battery
+ content.OperationResult = 0
+ content.Summary = {
+ ActuatorsData: [
+ {
+ MechNo: 1,
+ Name: "Mech1",
+ PickMode: this.PickMode
+ }
+ ]
+ }
+
+
+ const m20010 = new AmrMsg(content)
+ this.sendMessage(m20010)
+ }
+
+ send20011(content: AmrMsg20011) {
+ const m20011 = new AmrMsg>(content)
+ this.sendMessage(m20011)
+ }
+
+ send20020(content: AmrMsg20020) {
+ const m20020 = new AmrMsg(content)
+ this.sendMessage(m20020)
+ }
+
+ send20060() {
+ const content = new AmrMsg20060(this.vehicleId)
+ content.CreateMonoTime = Date.now() - this.bootTime
+ content.CurBattery = new CurBatteryData()
+ content.CurLogicX = this.currentLogicX
+ content.CurLogicY = this.currentLogicY
+ content.CurOrientation = this.currentOrientation
+ content.CurX = this.position.x;
+ content.CurY = this.position.z;
+ content.X = this.position.x;
+ content.Y = this.position.z;
+ const m20060 = new AmrMsg(content)
+ this.sendMessage(m20060)
+ }
+
+ send20250(content: AmrMsg20250) {
+ this.sendMessage(new AmrMsg(content))
+ }
+
+ subscribeMessage(topic: string) {
+ worldModel.envManager.client.subscribe(topic, {qos: 0})
+ }
+
+ sendMessage(msg: AmrMsg) {
+ if (!worldModel.state.runState.isVirtual) {
+ return
+ }
+ console.log('send message:', JSON.stringify(msg))
+ if (this.sendMessageQueue.indexOf(msg) < 0) {
+ this.sendMessageQueue.push(msg)
+ }
+ if (this.sendMessageQueue.length <= 0) {
+ this.mqRetryTimeCount = 0
+ }
+ worldModel.envManager.client.publish('/agv_robot/status', JSON.stringify(msg))
+ this.heartBeatTimeCount = 0
+ }
+
+ sendHeartBeat() {
+ if (!worldModel.state.runState.isVirtual) {
+ return
+ }
+ const content = new AmrMsg20100(this.vehicleId)
+ content.Temperature = {Battery: this.Battery}
+ const m20100 = new AmrMsg(content)
+ worldModel.envManager.client.publish('/agv_robot/status', JSON.stringify(m20100))
+ }
+
+ sendAck(seqNo: number, vehicleId: number) {
+ if (!worldModel.state.runState.isVirtual) {
+ return
+ }
+ const msg20050 = new AmrMsg20050(seqNo, vehicleId)
+ const ack = new AmrMsg(msg20050)
+ this.heartBeatTimeCount = 0
+ worldModel.envManager.client.publish('/agv_robot/status', JSON.stringify(ack))
+ }
+
+ /*==========RCS消息处理============*/
+ // 处理任务
+ handle10010Message(data: AmrMsg10010) {
+ if (this.currentStepTaskList.length > 0) {
+ if (this.runningStepTask.OperationType == 0 && this.runningStepTask.X == data.StartX && this.runningStepTask.Y == data.StartY) {
+ // this.currentStepTaskList = []
+ this.makeStepTask(data)
+ this.executeTask()
+ } else {
+ // 此处应该有错误处理
+ }
+ } else {
+ this.makeStepTask(data)
+ this.executeTask()
+ }
+ }
+
+ handle10050Message(data: AmrMsg) {
+ if (this.sendMessageQueue.length > 0 && data.content.SeqNo === this.sendMessageQueue[0].content.SeqNo) {
+ this.mqRetryTimeCount = 0
+ this.sendMessageQueue.shift()
+ }
+ }
+
+ handle10060Message(data: AmrMsg) {
+ this.mqRetryInterval = data.content.MqRetryTime
+ this.heartBeatInterval = data.content.HeartBeat
+ this.TaskMode = 0
+ }
+
+ // 处理状态查询
+ handle10110Message(data: AmrMsg) {
+ this.send20060()
+ }
+
+ // 取消任务
+ handle10120Message(data: AmrMsg) {
+
+ }
+
+
+ /*==========真车消息处理============*/
+
+ // 计算逻辑方向
+ computeLogicXYAndDirection() {
+ let ra = this.rotation.y
+ while (ra > Math.PI * 2) {
+ ra -= Math.PI * 2
+ }
+ while (ra < 0) {
+ ra += Math.PI * 2
+ }
+ const ddra = Math.PI / 8
+ if (ra >= ddra * 7 || ra < ddra) {
+ this.currentDirection = 0;
+
+ } else if (ra >= ddra && ra < ddra * 3) {
+ this.currentDirection = 3;
+
+ } else if (ra >= ddra * 3 && ra < ddra * 5) {
+ this.currentDirection = 2;
+
+ } else if (ra >= ddra * 5 && ra < ddra * 7) {
+ this.currentDirection = 1;
+ } else {
+ this.currentDirection = 15;
+ }
+
+ const pointItem = Model.getItemByXYZ(this.position.x, this.position.y, this.position.z)
+ if (!pointItem || !pointItem.logicX || !pointItem.logicY) {
+ this.currentLogicX = -1;
+ this.currentLogicY = -1;
+ } else {
+ this.currentLogicX = pointItem.logicX;
+ this.currentLogicY = pointItem.logicY;
+ }
+ this.currentOrientation = this.getAmrOrientation(this.rotation.y)
+ }
+
+ makeStepTask(data: AmrMsg10010) {
+
+ let currentStepTask: StepTask = this.runningStepTask
+ if (currentStepTask == null) {
+
+ currentStepTask = {
+ SeqNo: 0,
+ StepTaskType: "MOVE",
+ OperationType: 0,
+ PickMode: 0,
+ X: this.currentLogicX,
+ Y: this.currentLogicY,
+ Speed: 1000,
+ EndDirection: this.currentDirection,
+ ChargeLocation: 0,
+ GoodsSlotHeight: 0,
+ position: this.position,
+ isCompleted: true
+ }
+ }
+ let endDirection = currentStepTask.EndDirection
+
+ if (data.Link.length > 0) {
+ for (let i = 0; i < data.Link.length; i++) {
+ const link = data.Link[i]
+ if ((currentStepTask.X == link.X && currentStepTask.Y == link.Y)
+ || (currentStepTask.X != link.X && currentStepTask.Y != link.Y)) {
+ continue
+ } else if (currentStepTask.X < link.X) {
+ if (link.Speed > 0) {
+ endDirection = 0
+ } else {
+ endDirection = 2
+ }
+ } else if (currentStepTask.X > link.X) {
+ if (link.Speed > 0) {
+ endDirection = 2
+ } else {
+ endDirection = 0
+ }
+ } else if (currentStepTask.Y < link.Y) {
+ if (link.Speed > 0) {
+ endDirection = 1
+ } else {
+ endDirection = 3
+ }
+ } else if (currentStepTask.Y > link.Y) {
+ if (link.Speed > 0) {
+ endDirection = 3
+ } else {
+ endDirection = 1
+ }
+ }
+
+ if (endDirection != currentStepTask.EndDirection) {
+ const stepTask: StepTask = {
+ SeqNo: data.SeqNo,
+ StepTaskType: "ROTATION",
+ OperationType: 0,
+ PickMode: 0,
+ X: link.X,
+ Y: link.Y,
+ Speed: link.Speed,
+ EndDirection: endDirection,
+ ChargeLocation: data.ChargeLocation,
+ GoodsSlotHeight: data.GoodsSlotHeight,
+ position: Model.getPositionByLogicXY(link.X, link.Y) as THREE.Vector3,
+ isCompleted: false
+ }
+ currentStepTask = stepTask
+ this.currentStepTaskList.push(stepTask)
+ }
+
+ const stepTask: StepTask = {
+ SeqNo: data.SeqNo,
+ StepTaskType: link.Speed > 0 ? "MOVE" : "MOVE_BACKWARD",
+ OperationType: 0,
+ PickMode: 0,
+ X: link.X,
+ Y: link.Y,
+ Speed: link.Speed,
+ EndDirection: endDirection,
+ ChargeLocation: data.ChargeLocation,
+ GoodsSlotHeight: data.GoodsSlotHeight,
+ position: Model.getPositionByLogicXY(link.X, link.Y) as THREE.Vector3,
+ isCompleted: false
+ }
+ currentStepTask = stepTask
+ this.currentStepTaskList.push(stepTask)
+ }
+ }
+
+
+ if (data.OperationType == 0 && data.EndDirection >= 0 && data.EndDirection <= 3) {
+ 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) {
+ if (data.GoodsSlotDirection == 0) {
+ endDirection = 3
+ } else {
+ endDirection = (data.GoodsSlotDirection - 1) as LogicDirection
+ }
+ }
+ if (endDirection != currentStepTask.EndDirection) {
+ const stepTask: StepTask = {
+ SeqNo: data.SeqNo,
+ StepTaskType: "ROTATION",
+ OperationType: 0,
+ 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 = {
+ SeqNo: data.SeqNo,
+ StepTaskType: "CHARGE",
+ OperationType: 3,
+ 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 == 4) {
+
+ const stepTask: StepTask = {
+ SeqNo: data.SeqNo,
+ StepTaskType: data.PickMode == 1 ? "LOAD" : "UNLOAD",
+ OperationType: 4,
+ PickMode: data.PickMode,
+ 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 {
+
+ }
+
+ }
+
+ executeTask() {
+ this.TaskMode = 2
+ while (this.currentStepTaskList.length > 0) {
+ const stepTask = this.currentStepTaskList[0]
+ if (this.runningStepTask) {
+ if ((stepTask.StepTaskType == "MOVE" || stepTask.StepTaskType == "MOVE_BACKWARD")
+ && stepTask.EndDirection == this.runningStepTask.EndDirection
+ && (stepTask.Speed > 0) == (this.runningStepTask.Speed > 0)) {
+ this.runningStepTask = stepTask
+ this.currentStepTaskList.shift()
+ this.runningStepTaskList.push(stepTask)
+
+ this.addTravel(stepTask.X, stepTask.Y, stepTask.Speed/1000)
+
+ } else {
+ break
+ }
+ } else {
+ this.runningStepTask = stepTask
+ this.currentStepTaskList.shift()
+ this.runningStepTaskList.push(stepTask)
+ if (stepTask.StepTaskType == "MOVE" || stepTask.StepTaskType == "MOVE_BACKWARD") {
+ this.addTravel(stepTask.X, stepTask.Y, stepTask.Speed/1000)
+ } else if (stepTask.StepTaskType == "ROTATION") {
+ this.addRotation(stepTask.EndDirection)
+ } else if (stepTask.StepTaskType == "LOAD") {
+ this.addLoad(stepTask.GoodsSlotHeight/1000)
+ } else if (stepTask.StepTaskType == "UNLOAD") {
+ this.addUnload(stepTask.GoodsSlotHeight/1000)
+ }
+ }
+ }
+ }
+
+ onActionCompleted() {
+ this.runningStepTaskList = []
+ this.runningStepTask = null
+ this.computeLogicXYAndDirection()
+ // 当前所有动作执行完毕
+ if (this.currentStepTaskList.length <= 0) {
+ this.send20010()
+ }
+ this.PickMode = 0
+ this.OperationType = 0
+ this.TaskMode = 0
+ this.executeTask()
+ }
+
+ /*==========动作处理============*/
+ // 转
+ addRotation(direction: number): Promise {
+ let rad = 0
+ switch (direction) {
+ case 1:
+ rad = Math.PI / 2 * 3
+ break
+ case 2:
+ rad = Math.PI
+ break
+ case 3:
+ rad = Math.PI / 2
+ break
+ default:
+ rad = 0
+ }
+ const quat1 = new THREE.Quaternion().setFromEuler(this.rotation)
+ const euler: Euler = new Euler(this.rotation.x, rad, this.rotation.z)
+ const quat2 = new THREE.Quaternion().setFromEuler(euler)
+ const angleDiff = quat1.angleTo(quat2)
+ console.log(rad, this.rotation.y, angleDiff)
+ const tr = this.rotation.y + angleDiff
+ let time = Math.abs(angleDiff) / (Math.PI / 7)
+ const duration = time
+
+ return new Promise(resolve => {
+ gsap.to(this.rotation, {
+ y: tr,
+ duration,
+ ease: 'none',
+ onComplete: ()=>{
+ resolve()
+ this.onActionCompleted()
+ }
+ })
+ })
+ }
+
+ // 走
+ addTravel(logicX: number, logicY: number, speed: number = 1): Promise {
+ this.OperationType = 0
+ this.PickMode = 0
+ const pos = Model.getPositionByLogicXY(logicX, logicY)
+
+ const fromPos = this.position
+ const toPos = pos as THREE.Vector3
+ const distance = fromPos.distanceTo(toPos)
+ const duration = Math.max(1.0, distance / speed)
+
+ if (!this.travelAnimation) {
+ return new Promise(resolve => {
+ this.travelAnimation = gsap.fromTo(this.position, {
+ x: fromPos.x,
+ y: fromPos.y,
+ z: fromPos.z,
+ }, {
+ x: toPos.x,
+ y: toPos.y,
+ z: toPos.z,
+ duration,
+ ease: 'power2.inOut',
+ onComplete: () => {
+ this.travelAnimation = null
+ resolve()
+ this.onActionCompleted()
+ },
+ onUpdate: () => {
+
+ for (let i = 0; i < this.runningStepTaskList.length; i++) {
+ const task = this.runningStepTaskList[i]
+ if (task.isCompleted == false) {
+ if (this.position.distanceTo(task.position) < 0.1) {
+ task.isCompleted = true
+ this.runningStepTaskList.splice(0, i + 1)
+ const content: AmrMsg20020 = new AmrMsg20020(this.vehicleId)
+ content.CurLogicX = task.X
+ content.CurLogicY = task.Y
+ content.CurX = task.X
+ content.CurY = task.Y
+ content.CurOrientation = task.EndDirection * 90
+ content.CurDirection = task.EndDirection
+ this.send20020(content)
+ break
+ }
+ }
+ }
+ }
+ })
+ })
+ } else {
+ this.travelAnimation.vars.x = toPos.x
+ this.travelAnimation.vars.y = toPos.y
+ this.travelAnimation.vars.z = toPos.z
+ const tt = this.travelAnimation.duration()
+ this.travelAnimation.duration(tt + duration)
+ this.travelAnimation.invalidate().restart();
+ }
+
+ }
+
+ // 取货
+ addLoad(height: number): void {
+ this.PickMode = 1
+ this.OperationType = 4
+ this.animationUpFork(height).then(
+ () => this.animationShowFork(1.4).then(
+ ()=>this.animationUpFork(height + 0.2).then(
+ ()=>this.animationHideFork().then(
+ ()=>this.animationDownFork().then(()=>{
+ this.onActionCompleted()
+ })
+ )
+ )
+ )
+ )
+ }
+ // 卸货
+ addUnload(height: number): void {
+ this.PickMode = 2
+ this.OperationType = 4
+ this.animationUpFork(height + 0.2).then(
+ () => this.animationShowFork(1.4).then(
+ ()=>this.animationUpFork(height).then(
+ ()=>this.animationHideFork().then(
+ ()=>this.animationDownFork().then(()=>{
+ this.onActionCompleted()
+ })
+ )
+ )
+ )
+ )
+ }
+
+ override animationShowFork(z: number): Promise{
+ return null
+ };
+ override animationHideFork(): Promise {
+ return null
+ }
+ override animationUpFork(y: number, time?: number = 3): Promise {
+ return null
+ }
+ override animationDownFork(): Promise {
+ return null
+ }
+
+ //获取ptr的角度朝向
+ getAmrOrientation(radY: number) {
+ radY = radY + Math.PI
+ while (radY < 0) {
+ radY += Math.PI * 2
+ }
+ while (radY > Math.PI * 2) {
+ radY -= Math.PI * 2
+ }
+ return THREE.MathUtils.radToDeg(radY)
+ }
+
+}
diff --git a/src/modules/amr/ptr/cl2/Cl23dObject.ts b/src/modules/amr/ptr/cl2/Cl23dObject.ts
index a4f6184..1ca81c4 100644
--- a/src/modules/amr/ptr/cl2/Cl23dObject.ts
+++ b/src/modules/amr/ptr/cl2/Cl23dObject.ts
@@ -24,124 +24,13 @@ import {
type LogicDirection, TaskCompletedData, TaskModeChangeData, TaskStatusChangeData, TaskTypeChangeData, AmrMsg20010
} from "@/core/manager/amr/AmrMessageDefine";
import {worldModel} from "@/core/manager/WorldModel";
+import PtrObject from "../PtrObject";
+import Viewport from "@/core/engine/Viewport";
-
-type CStepTaskType = "MOVE" | "MOVE_BACKWARD" | "ROTATION" | "LOAD" | "UNLOAD" | "CHARGE"
-
-interface StepTask {
- SeqNo: number;
- StepTaskType: CStepTaskType;
- OperationType: 0 | 1 | 2 | 3 | 4 | 5 | 135 | 136;
- PickMode: 0 | 1 | 2 | 3 | 4 | 5 | 6;
- X: number;
- Y: number;
- Speed: number;
- EndDirection: 0 | 1 | 2 | 3 | 15;
- ChargeLocation: number;
- GoodsSlotHeight: number;
- position: THREE.Vector3;
- isCompleted: boolean;
-}
-
-export default class Cl23dObject extends THREE.Object3D {
-
- private item: ItemJson
+export default class Cl23dObject extends PtrObject {
private _cl2Entity: Cl2Entity = null
- private currentStepTaskList: StepTask[] = []
- private runningStepTask: StepTask = null
- private runningStepTaskList: StepTask[] = []
- private travelAnimation: core.Tween = null
-
- private currentLogicX: number = -1
- private currentLogicY: number = -1
- private currentDirection: LogicDirection = 15
- private sendMessageQueue: AmrMsg[] = []
-
- public Battery: number = 100
-
- private __TaskMode: CTaskMode = 0
- private __OperationType: COperationType = 0
- private __TaskStatus: CEventId = 0
- private __PickMode: CPickMode = 0
-
- get TaskMode(): CTaskMode {
- return this.__TaskMode
- }
-
- set TaskMode(value: CTaskMode) {
- if (this.__TaskMode != value) {
- const info = new TaskModeChangeData(this.__TaskMode, value)
- const msg = new AmrMsg20011(this.vehicleId, info)
- msg.TaskMode = value
- this.send20011(msg)
- }
- this.__TaskMode = value
- }
-
- get OperationType(): COperationType {
- return this.__OperationType
- }
-
- set OperationType(value: COperationType) {
- if (this.__OperationType != value) {
- const info = new TaskTypeChangeData(this.__OperationType, value)
- const msg = new AmrMsg20011(this.vehicleId, info)
- msg.TaskMode = this.TaskMode
- this.send20011(msg)
- }
- this.__OperationType = value
- }
-
- get TaskStatus(): CEventId {
- return this.__TaskStatus
- }
-
- set TaskStatus(value: CEventId) {
- if (this.__TaskStatus != value) {
-
- if (value != 1 && value != 4 && value != 8) {
- const info = new TaskStatusChangeData(this.OperationType)
- const msg = new AmrMsg20011(this.vehicleId, info)
- msg.TaskMode = this.TaskMode
- msg.EventId = value
- this.send20011(msg)
- } else if (value == 4) {
-
- const info = new TaskCompletedData(this.OperationType)
- info.Battery = this.Battery
- info.OperationResult = 0
- info.CurLogicX = this.currentLogicX
- info.CurLogicY = this.currentLogicY
- info.CurX = this.currentLogicX
- info.CurY = this.currentLogicY
- info.CurDirection = this.currentDirection
- info.CurOrientation = THREE.MathUtils.radToDeg(this.rotation.y)
- const msg = new AmrMsg20011(this.vehicleId, info)
- msg.TaskMode = this.TaskMode
- this.send20011(msg)
- }
-
- }
- }
-
- get PickMode(): CPickMode {
- return this.__PickMode
- }
- set PickMode(value: CPickMode) {
- if (this.__PickMode !== value) {
- this.__PickMode = value
- }
- }
-
- private bootTime: number = 0
-
- // 心跳间隔 UInt32 单位: s
- private heartBeatInterval: number = 0
- // 小车所有上报消息重试间隔(未收到应答消息时重发消息) UInt32 单位: s
- private mqRetryInterval: number = 3
-
public get cl2Entity(): Cl2Entity {
if (!this._cl2Entity) {
const cl2: Cl2Entity = Model.getCl2(this.item.id) as Cl2Entity
@@ -150,13 +39,9 @@ export default class Cl23dObject extends THREE.Object3D {
return this._cl2Entity
}
- public vehicleId: number
+ constructor(item: ItemJson, viewport: Viewport, option?: RendererCudOption) {
+ super(item, viewport)
- private clock = new THREE.Clock()
-
- constructor(item: ItemJson, option?: RendererCudOption) {
- super()
- this.item = item
if (!Cl23DGraphics.ptrPedestalGeometry) {
Cl23DGraphics.ptrPedestalGeometry = Cl23DGraphics.createPtrPedestal()
}
@@ -187,661 +72,13 @@ export default class Cl23dObject extends THREE.Object3D {
groupPillar.add(ptrPillarMesh)
groupPillar.add(ptrForkMesh)
this.add(groupPillar)
-
- this.vehicleId = parseInt(this.cl2Entity.id)
- this.cl2Entity.viewport.addFrameTimerCallback(this.cl2Entity.id, this.onFrameTimer.bind(this))
- if (!worldModel.state.runState.isVirtual) {
- this.subscribeMessage('/wcs_server/' + this.cl2Entity.id)
- this.subscribeMessage('/agv_robot/status')
- }
- }
-
- private AGVModel = "CYBER-LIFT-A_V1.0"
- private AGVFnModel = "FITBOTS-CYBER-LIFT-1000_V1.0"
-
-
- private heartBeatTimeCount: number = 0
- private mqRetryTimeCount: number = 0
-
- private onFrameTimer() {
- if (!worldModel.state.runState.isVirtual) {
- return
- }
- const delta = this.clock.getDelta()
- this.mqRetryTimeCount += delta
- if (this.mqRetryInterval > 0 && this.mqRetryTimeCount >= this.mqRetryInterval) {
- this.mqRetryTimeCount = 0
- // 在此处理消息重试
- if (this.sendMessageQueue.length > 0) {
- this.sendMessage(this.sendMessageQueue[0])
- }
- }
- this.heartBeatTimeCount += delta
- if (this.heartBeatInterval > 0 && this.heartBeatTimeCount >= this.heartBeatInterval) {
- this.heartBeatTimeCount = 0
- // 在此处发送心跳报文
- this.sendHeartBeat()
- }
- }
-
-
- // 开机
- boot() {
- this.bootTime = Date.now();
- this.computeLogicXYAndDirection();
-
- if (!worldModel.state.runState.isVirtual) {
- return
- }
- this.subscribeMessage('/wcs_server/' + this.cl2Entity.id)
- this.send20147()
- setTimeout(() => {
- this.send20149()
- this.TaskMode = 1
- // 检查当前所在位置和方向 根据车当前所在的xz坐标获取地标
- setTimeout(() => {
- this.sendCurrentPositionAndDirection()
- setTimeout(() => {
- this.send20150()
- }, 1000)
- }, 1000)
- }, 2000)
-
- }
-
- // 关机
- shutdown() {
- if (!worldModel.state.runState.isVirtual) {
- return
- }
- const content = new AmrMsg20148(this.vehicleId)
- // 电量
- content.Battery = 100
- content.CreateMonoTime = Date.now() - this.bootTime
- content.Uptime = content.CreateMonoTime
- const m20148 = new AmrMsg(content)
- this.sendMessage(m20148)
- }
-
- // 开机上报
- send20147() {
- const content = new AmrMsg20147(this.vehicleId)
- content.AGVModel = this.AGVModel
- content.AGVFnModel = this.AGVFnModel
- // 电量
- content.Battery = 100
- content.CreateMonoTime = Date.now() - this.bootTime
- const m20147 = new AmrMsg(content)
- this.sendMessage(m20147)
- }
-
- // 主程序启动上报
- send20149() {
- const content = new AmrMsg20149(this.vehicleId)
- content.AGVModel = this.AGVModel
- content.AGVFnModel = this.AGVFnModel
- // 电量
- content.Battery = 100
- content.CreateMonoTime = Date.now() - this.bootTime
- const m20149 = new AmrMsg(content)
- this.sendMessage(m20149)
- }
-
- // 上线上报
- send20150() {
- const content = new AmrMsg20150(this.vehicleId)
- content.AGVModel = this.AGVModel
- content.AGVFnModel = this.AGVFnModel
- content.Battery = 100
- content.CreateMonoTime = Date.now() - this.bootTime
- const m20150 = new AmrMsg(content)
- this.sendMessage(m20150)
- }
-
- // 上报当前位姿,地标和方向
- sendCurrentPositionAndDirection() {
- if (this.currentLogicX <= 0 || this.currentLogicY <= 0) {
- // 当前车辆所在位置未找到
- const content = new AmrMsg20250(this.vehicleId)
- content.Duration = 0
- content.ErrCode = 5
- content.ErrCodeName = AmrErrorCode[5].ErrCodeName
- content.ErrEvtType = 1
- content.ErrLevel = 14
- content.ErrLifecycle = 2
- content.CreateMonoTime = Date.now() - this.bootTime
- const m20250 = new AmrMsg(content)
- this.sendMessage(m20250)
- } else {
- // 发送正常地标信息
- const content = new AmrMsg20020(this.vehicleId)
- content.CurDirection = this.currentDirection
- content.CurLogicX = this.currentLogicX
- content.CurLogicY = this.currentLogicY
- content.CurX = this.currentLogicX
- content.CurY = this.currentLogicY
- content.CreateMonoTime = Date.now() - this.bootTime
- const m20020 = new AmrMsg(content)
- this.sendMessage(m20020)
- }
- }
-
- send20010() {
- const content: AmrMsg20010 = new AmrMsg20010(this.vehicleId)
- content.CurX = this.currentLogicX
- content.CurY = this.currentLogicY
- content.CurDirection = this.currentDirection
- content.OperationType = this.OperationType
- content.Battery = this.Battery
- content.OperationResult = 0
- content.Summary = {
- ActuatorsData: [
- {
- MechNo: 1,
- Name: "Mech1",
- PickMode: this.PickMode
- }
- ]
- }
-
-
- const m20010 = new AmrMsg(content)
- this.sendMessage(m20010)
- }
-
- send20011(content: AmrMsg20011) {
- const m20011 = new AmrMsg>(content)
- this.sendMessage(m20011)
- }
-
- send20020(content: AmrMsg20020) {
- const m20020 = new AmrMsg(content)
- this.sendMessage(m20020)
- }
-
- send20060() {
- const content = new AmrMsg20060(this.vehicleId)
- content.CreateMonoTime = Date.now() - this.bootTime
- content.CurBattery = new CurBatteryData()
- content.CurLogicX = this.currentLogicX
- content.CurLogicY = this.currentLogicY
- content.CurOrientation = THREE.MathUtils.radToDeg(this.rotation.y);
- content.CurX = this.position.x;
- content.CurY = this.position.z;
- content.X = this.position.x;
- content.Y = this.position.z;
- const m20060 = new AmrMsg(content)
- this.sendMessage(m20060)
- }
-
- send20250(content: AmrMsg20250) {
- this.sendMessage(new AmrMsg(content))
- }
-
- subscribeMessage(topic: string) {
- worldModel.envManager.client.subscribe(topic, {qos: 0})
- }
-
- sendMessage(msg: AmrMsg) {
- if (!worldModel.state.runState.isVirtual) {
- return
- }
- console.log('send message:', JSON.stringify(msg))
- if (this.sendMessageQueue.indexOf(msg) < 0) {
- this.sendMessageQueue.push(msg)
- }
- if (this.sendMessageQueue.length <= 0) {
- this.mqRetryTimeCount = 0
- }
- worldModel.envManager.client.publish('/agv_robot/status', JSON.stringify(msg))
- this.heartBeatTimeCount = 0
- }
-
- sendHeartBeat() {
- if (!worldModel.state.runState.isVirtual) {
- return
- }
- const content = new AmrMsg20100(this.vehicleId)
- content.Temperature = {Battery: this.Battery}
- const m20100 = new AmrMsg(content)
- worldModel.envManager.client.publish('/agv_robot/status', JSON.stringify(m20100))
- }
-
- sendAck(seqNo: number, vehicleId: number) {
- if (!worldModel.state.runState.isVirtual) {
- return
- }
- const msg20050 = new AmrMsg20050(seqNo, vehicleId)
- const ack = new AmrMsg(msg20050)
- this.heartBeatTimeCount = 0
- worldModel.envManager.client.publish('/agv_robot/status', JSON.stringify(ack))
- }
-
- /*==========RCS消息处理============*/
- // 处理任务
- handle10010Message(data: AmrMsg10010) {
- if (this.currentStepTaskList.length > 0) {
- if (this.runningStepTask.OperationType == 0 && this.runningStepTask.X == data.StartX && this.runningStepTask.Y == data.StartY) {
- // this.currentStepTaskList = []
- this.makeStepTask(data)
- this.executeTask()
- } else {
- // 此处应该有错误处理
- }
- } else {
- this.makeStepTask(data)
- this.executeTask()
- }
- }
-
- handle10050Message(data: AmrMsg) {
- if (this.sendMessageQueue.length > 0 && data.content.SeqNo === this.sendMessageQueue[0].content.SeqNo) {
- this.mqRetryTimeCount = 0
- this.sendMessageQueue.shift()
- }
- }
-
- handle10060Message(data: AmrMsg) {
- this.mqRetryInterval = data.content.MqRetryTime
- this.heartBeatInterval = data.content.HeartBeat
- this.TaskMode = 0
- }
-
- // 处理状态查询
- handle10110Message(data: AmrMsg) {
- this.send20060()
- }
-
- // 取消任务
- handle10120Message(data: AmrMsg) {
-
- }
-
- /*==========真车消息处理============*/
-
- // 计算逻辑方向
- computeLogicXYAndDirection() {
- let ra = this.rotation.y
- while (ra > Math.PI * 2) {
- ra -= Math.PI * 2
- }
- while (ra < 0) {
- ra += Math.PI * 2
- }
- const ddra = Math.PI / 8
- if (ra >= ddra * 7 || ra < ddra) {
- this.currentDirection = 0;
-
- } else if (ra >= ddra && ra < ddra * 3) {
- this.currentDirection = 3;
-
- } else if (ra >= ddra * 3 && ra < ddra * 5) {
- this.currentDirection = 2;
-
- } else if (ra >= ddra * 5 && ra < ddra * 7) {
- this.currentDirection = 1;
- } else {
- this.currentDirection = 15;
- }
-
- const pointItem = Model.getItemByXYZ(this.position.x, this.position.y, this.position.z)
- if (!pointItem || !pointItem.logicX || !pointItem.logicY) {
- this.currentLogicX = -1;
- this.currentLogicY = -1;
- } else {
- this.currentLogicX = pointItem.logicX;
- this.currentLogicY = pointItem.logicY;
- }
-
- }
-
- makeStepTask(data: AmrMsg10010) {
-
- let currentStepTask: StepTask = this.runningStepTask
- if (currentStepTask == null) {
-
- currentStepTask = {
- SeqNo: 0,
- StepTaskType: "MOVE",
- OperationType: 0,
- PickMode: 0,
- X: this.currentLogicX,
- Y: this.currentLogicY,
- Speed: 1000,
- EndDirection: this.currentDirection,
- ChargeLocation: 0,
- GoodsSlotHeight: 0,
- position: this.position,
- isCompleted: true
- }
- }
- let endDirection = currentStepTask.EndDirection
-
- if (data.Link.length > 0) {
- for (let i = 0; i < data.Link.length; i++) {
- const link = data.Link[i]
- if ((currentStepTask.X == link.X && currentStepTask.Y == link.Y)
- || (currentStepTask.X != link.X && currentStepTask.Y != link.Y)) {
- continue
- } else if (currentStepTask.X < link.X) {
- if (link.Speed > 0) {
- endDirection = 0
- } else {
- endDirection = 2
- }
- } else if (currentStepTask.X > link.X) {
- if (link.Speed > 0) {
- endDirection = 2
- } else {
- endDirection = 0
- }
- } else if (currentStepTask.Y < link.Y) {
- if (link.Speed > 0) {
- endDirection = 1
- } else {
- endDirection = 3
- }
- } else if (currentStepTask.Y > link.Y) {
- if (link.Speed > 0) {
- endDirection = 3
- } else {
- endDirection = 1
- }
- }
-
- if (endDirection != currentStepTask.EndDirection) {
- const stepTask: StepTask = {
- SeqNo: data.SeqNo,
- StepTaskType: "ROTATION",
- OperationType: 0,
- PickMode: 0,
- X: link.X,
- Y: link.Y,
- Speed: link.Speed,
- EndDirection: endDirection,
- ChargeLocation: data.ChargeLocation,
- GoodsSlotHeight: data.GoodsSlotHeight,
- position: Model.getPositionByLogicXY(link.X, link.Y) as THREE.Vector3,
- isCompleted: false
- }
- currentStepTask = stepTask
- this.currentStepTaskList.push(stepTask)
- }
-
- const stepTask: StepTask = {
- SeqNo: data.SeqNo,
- StepTaskType: link.Speed > 0 ? "MOVE" : "MOVE_BACKWARD",
- OperationType: 0,
- PickMode: 0,
- X: link.X,
- Y: link.Y,
- Speed: link.Speed,
- EndDirection: endDirection,
- ChargeLocation: data.ChargeLocation,
- GoodsSlotHeight: data.GoodsSlotHeight,
- position: Model.getPositionByLogicXY(link.X, link.Y) as THREE.Vector3,
- isCompleted: false
- }
- currentStepTask = stepTask
- this.currentStepTaskList.push(stepTask)
- }
- }
-
-
- if (data.OperationType == 0 && data.EndDirection >= 0 && data.EndDirection <= 3) {
- 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) {
- if (data.GoodsSlotDirection == 0) {
- endDirection = 3
- } else {
- endDirection = (data.GoodsSlotDirection - 1) as LogicDirection
- }
- }
- if (endDirection != currentStepTask.EndDirection) {
- const stepTask: StepTask = {
- SeqNo: data.SeqNo,
- StepTaskType: "ROTATION",
- OperationType: 0,
- 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 = {
- SeqNo: data.SeqNo,
- StepTaskType: "CHARGE",
- OperationType: 3,
- 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 == 4) {
-
- const stepTask: StepTask = {
- SeqNo: data.SeqNo,
- StepTaskType: data.PickMode == 1 ? "LOAD" : "UNLOAD",
- OperationType: 4,
- PickMode: data.PickMode,
- 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 {
-
- }
-
- }
-
- executeTask() {
- this.TaskMode = 2
- while (this.currentStepTaskList.length > 0) {
- const stepTask = this.currentStepTaskList[0]
- if (this.runningStepTask) {
- if ((stepTask.StepTaskType == "MOVE" || stepTask.StepTaskType == "MOVE_BACKWARD")
- && stepTask.EndDirection == this.runningStepTask.EndDirection
- && (stepTask.Speed > 0) == (this.runningStepTask.Speed > 0)) {
- this.runningStepTask = stepTask
- this.currentStepTaskList.shift()
- this.runningStepTaskList.push(stepTask)
-
- this.addTravel(stepTask.X, stepTask.Y, stepTask.Speed/1000)
-
- } else {
- break
- }
- } else {
- this.runningStepTask = stepTask
- this.currentStepTaskList.shift()
- this.runningStepTaskList.push(stepTask)
- if (stepTask.StepTaskType == "MOVE" || stepTask.StepTaskType == "MOVE_BACKWARD") {
- this.addTravel(stepTask.X, stepTask.Y, stepTask.Speed/1000)
- } else if (stepTask.StepTaskType == "ROTATION") {
- this.addRotation(stepTask.EndDirection)
- } else if (stepTask.StepTaskType == "LOAD") {
- this.addLoad(stepTask.GoodsSlotHeight/1000)
- } else if (stepTask.StepTaskType == "UNLOAD") {
- this.addUnload(stepTask.GoodsSlotHeight/1000)
- }
- }
- }
- }
-
- onActionCompleted() {
- this.runningStepTaskList = []
- this.runningStepTask = null
- this.computeLogicXYAndDirection()
- // 当前所有动作执行完毕
- if (this.currentStepTaskList.length <= 0) {
- this.send20010()
- }
- this.PickMode = 0
- this.OperationType = 0
- this.TaskMode = 0
- this.executeTask()
}
/*==========动画处理============*/
- // 转
- addRotation(direction: number): Promise {
- let rad = 0
- switch (direction) {
- case 1:
- rad = Math.PI / 2 * 3
- break
- case 2:
- rad = Math.PI
- break
- case 3:
- rad = Math.PI / 2
- break
- default:
- rad = 0
- }
- const quat1 = new THREE.Quaternion().setFromEuler(this.rotation)
- const euler: Euler = new Euler(this.rotation.x, rad, this.rotation.z)
- const quat2 = new THREE.Quaternion().setFromEuler(euler)
- const angleDiff = quat1.angleTo(quat2)
- console.log(rad, this.rotation.y, angleDiff)
- const tr = this.rotation.y + angleDiff
- let time = Math.abs(angleDiff) / (Math.PI / 7)
- const duration = time
-
- return new Promise(resolve => {
- gsap.to(this.rotation, {
- y: tr,
- duration,
- ease: 'none',
- onComplete: ()=>{
- resolve()
- this.onActionCompleted()
- }
- })
- })
- }
-
- // 走
- addTravel(logicX: number, logicY: number, speed: number = 1): Promise {
- this.OperationType = 0
- this.PickMode = 0
- const pos = Model.getPositionByLogicXY(logicX, logicY)
-
- const fromPos = this.position
- const toPos = pos as THREE.Vector3
- const distance = fromPos.distanceTo(toPos)
- const duration = Math.max(1.0, distance / speed)
-
- if (!this.travelAnimation) {
- return new Promise(resolve => {
- this.travelAnimation = gsap.fromTo(this.position, {
- x: fromPos.x,
- y: fromPos.y,
- z: fromPos.z,
- }, {
- x: toPos.x,
- y: toPos.y,
- z: toPos.z,
- duration,
- ease: 'power2.inOut',
- onComplete: () => {
- this.travelAnimation = null
- resolve()
- this.onActionCompleted()
- },
- onUpdate: () => {
- for (let i = 0; i < this.runningStepTaskList.length; i++) {
- const task = this.runningStepTaskList[i]
- if (task.isCompleted == false) {
- if (this.position.distanceTo(task.position) < 0.1) {
- task.isCompleted = true
- this.runningStepTaskList.splice(0, i + 1)
- const content: AmrMsg20020 = new AmrMsg20020(this.vehicleId)
- content.CurLogicX = task.X
- content.CurLogicY = task.Y
- content.CurX = task.X
- content.CurY = task.Y
- // content.CurOrientation = task.Orientation
- content.CurDirection = task.EndDirection
- this.send20020(content)
- break
- }
- }
- }
- }
- })
- })
- } else {
- this.travelAnimation.vars.x = toPos.x
- this.travelAnimation.vars.y = toPos.y
- this.travelAnimation.vars.z = toPos.z
- const tt = this.travelAnimation.duration()
- this.travelAnimation.duration(tt + duration)
- this.travelAnimation.invalidate().restart();
- }
-
- }
-
- // 取货
- addLoad(height: number): void {
- this.PickMode = 1
- this.OperationType = 4
- this.animationUpFork(height).then(
- () => this.animationShowFork(1.4).then(
- ()=>this.animationUpFork(height + 0.2).then(
- ()=>this.animationHideFork().then(
- ()=>this.animationDownFork().then(()=>{
- this.onActionCompleted()
- })
- )
- )
- )
- )
- }
- // 卸货
- addUnload(height: number): void {
- this.PickMode = 2
- this.OperationType = 4
- this.animationUpFork(height + 0.2).then(
- () => this.animationShowFork(1.4).then(
- ()=>this.animationUpFork(height).then(
- ()=>this.animationHideFork().then(
- ()=>this.animationDownFork().then(()=>{
- this.onActionCompleted()
- })
- )
- )
- )
- )
- }
- animationShowFork(z: number): Promise {
+ override animationShowFork(z: number): Promise {
const ptrPillar = this.getObjectByName('ptrPillar')
const time = 3
@@ -857,11 +94,11 @@ export default class Cl23dObject extends THREE.Object3D {
}
- animationHideFork(): Promise {
+ override animationHideFork(): Promise {
return this.animationShowFork(0)
}
- animationUpFork(y: number, time?: number = 3): Promise {
+ override animationUpFork(y: number, time?: number = 3): Promise {
const ptrFork = this.getObjectByName('ptrFork')
const ptrPillar = this.getObjectByName('ptrPillar')
const pz = ptrPillar.position.z
@@ -895,7 +132,7 @@ export default class Cl23dObject extends THREE.Object3D {
})
}
- animationDownFork(): Promise {
+ override animationDownFork(): Promise {
return this.animationUpFork(0)
}
}
diff --git a/src/modules/amr/ptr/cl2/Cl2Renderer.ts b/src/modules/amr/ptr/cl2/Cl2Renderer.ts
index 333ba87..bc8daf5 100644
--- a/src/modules/amr/ptr/cl2/Cl2Renderer.ts
+++ b/src/modules/amr/ptr/cl2/Cl2Renderer.ts
@@ -55,7 +55,7 @@ export default class PtrRenderer extends BaseRenderer {
return null
}
- const group = new Cl23dObject(item, option)
+ const group = new Cl23dObject(item, this.tempViewport, option)
group.name = PtrRenderer.POINT_NAME
// 设置位置
diff --git a/src/modules/amr/ptr/clx/Clx3DGraphics.ts b/src/modules/amr/ptr/clx/Clx3DGraphics.ts
new file mode 100644
index 0000000..e4190e1
--- /dev/null
+++ b/src/modules/amr/ptr/clx/Clx3DGraphics.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 Clx3DGraphics {
+
+ // 创建clx的底座
+ static createClxPedestal(): 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
+ }
+
+ // 创建clx的立柱
+ static createClxPillar(): 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)
+
+ }
+
+ // 创建clx的叉
+ static createClxFork(): 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
+ }
+
+ // 创建clx的铰链
+ static createClxGemel(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)
+ }
+
+ // 创建clx叉的背板
+ static createClxForkBasePlate(): 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, 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 clxPedestalGeometry: THREE.BufferGeometry = null
+ static clxPillarGeometry: THREE.BufferGeometry = null
+ static clxForkGeometry: THREE.BufferGeometry = null
+ static clxGemelGeometryL: THREE.BufferGeometry = null
+ static clxGemelGeometryR: THREE.BufferGeometry = null
+ static clxForkBasePlateGeometry: THREE.BufferGeometry = null
+}
diff --git a/src/modules/amr/ptr/clx/Clx3dObject.ts b/src/modules/amr/ptr/clx/Clx3dObject.ts
index 222ef39..f1be300 100644
--- a/src/modules/amr/ptr/clx/Clx3dObject.ts
+++ b/src/modules/amr/ptr/clx/Clx3dObject.ts
@@ -3,437 +3,47 @@ import {CSG} from 'three-csg-ts'
import gsap from 'gsap'
//@ts-ignore
import {mergeGeometries} from 'three/addons/utils/BufferGeometryUtils.js'
+import Clx3DGraphics from "@/modules/amr/ptr/clx/Clx3DGraphics";
+import Viewport from "@/core/engine/Viewport";
+import PtrObject from "@/modules/amr/ptr/PtrObject";
-export default class Clx3dObject extends THREE.Object3D {
-
- // 创建clx的底座
- private static createClxPedestal(): 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
- }
-
- // 创建clx的立柱
- private static createClxPillar(): 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)
-
- }
-
- // 创建clx的叉
- private static createClxFork(): 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
- }
-
- // 创建clx的铰链
- private static createClxGemel(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)
- }
-
- // 创建clx叉的背板
- private static createClxForkBasePlate(): 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, 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)
- }
-
- private static clxPedestalGeometry: THREE.BufferGeometry = null
- private static clxPillarGeometry: THREE.BufferGeometry = null
- private static clxForkGeometry: THREE.BufferGeometry = null
- private static clxGemelGeometryL: THREE.BufferGeometry = null
- private static clxGemelGeometryR: THREE.BufferGeometry = null
- private static clxForkBasePlateGeometry: THREE.BufferGeometry = null
+export default class Clx3dObject extends PtrObject {
- constructor(item: ItemJson, option?: RendererCudOption) {
- super()
+ constructor(item: ItemJson, viewport: Viewport, option?: RendererCudOption) {
+ super(item, viewport)
- if (!Clx3dObject.clxPedestalGeometry) {
- Clx3dObject.clxPedestalGeometry = Clx3dObject.createClxPedestal()
+ if (!Clx3DGraphics.clxPedestalGeometry) {
+ Clx3DGraphics.clxPedestalGeometry = Clx3DGraphics.createClxPedestal()
}
- const clxPedestalGeometry = Clx3dObject.clxPedestalGeometry
+ const clxPedestalGeometry = Clx3DGraphics.clxPedestalGeometry
const clxPedestalMaterial = new THREE.MeshPhongMaterial({color: 0xffdddbca})
const clxPedestalMesh = new THREE.Mesh(clxPedestalGeometry, clxPedestalMaterial)
- if (!Clx3dObject.clxPillarGeometry) {
- Clx3dObject.clxPillarGeometry = Clx3dObject.createClxPillar()
+ if (!Clx3DGraphics.clxPillarGeometry) {
+ Clx3DGraphics.clxPillarGeometry = Clx3DGraphics.createClxPillar()
}
- const clxPillarGeometry = Clx3dObject.clxPillarGeometry
+ const clxPillarGeometry = Clx3DGraphics.clxPillarGeometry
const clxPillarMaterial = new THREE.MeshPhongMaterial({color: 0xff6c6956})
const clxPillarMesh = new THREE.Mesh(clxPillarGeometry, clxPillarMaterial)
- if (!Clx3dObject.clxForkGeometry) {
- Clx3dObject.clxForkGeometry = Clx3dObject.createClxFork()
+ if (!Clx3DGraphics.clxForkGeometry) {
+ Clx3DGraphics.clxForkGeometry = Clx3DGraphics.createClxFork()
}
- const clxForkGeometry = Clx3dObject.clxForkGeometry
+ const clxForkGeometry = Clx3DGraphics.clxForkGeometry
const clxForkMaterial = new THREE.MeshPhongMaterial({color: 0xff444444})
const clxForkMesh = new THREE.Mesh(clxForkGeometry, clxForkMaterial)
clxForkMesh.name = 'clxFork'
- if (!Clx3dObject.clxGemelGeometryL) {
- Clx3dObject.clxGemelGeometryL = Clx3dObject.createClxGemel(true)
+ if (!Clx3DGraphics.clxGemelGeometryL) {
+ Clx3DGraphics.clxGemelGeometryL = Clx3DGraphics.createClxGemel(true)
}
- const clxGemelGeometryL = Clx3dObject.clxGemelGeometryL
+ const clxGemelGeometryL = Clx3DGraphics.clxGemelGeometryL
- if (!Clx3dObject.clxGemelGeometryR) {
- Clx3dObject.clxGemelGeometryR = Clx3dObject.createClxGemel(false)
+ if (!Clx3DGraphics.clxGemelGeometryR) {
+ Clx3DGraphics.clxGemelGeometryR = Clx3DGraphics.createClxGemel(false)
}
- const clxGemelGeometryR = Clx3dObject.clxGemelGeometryR
+ const clxGemelGeometryR = Clx3DGraphics.clxGemelGeometryR
const clxGemelMaterial = new THREE.MeshPhongMaterial({color: 0xff555555})
const clxGemelMeshL1 = new THREE.Mesh(clxGemelGeometryL, clxGemelMaterial)
@@ -445,10 +55,10 @@ export default class Clx3dObject extends THREE.Object3D {
const clxGemelMeshR2 = new THREE.Mesh(clxGemelGeometryR, clxGemelMaterial)
clxGemelMeshR2.name = 'clxGemelMeshR2'
- if (!Clx3dObject.clxForkBasePlateGeometry) {
- Clx3dObject.clxForkBasePlateGeometry = Clx3dObject.createClxForkBasePlate()
+ if (!Clx3DGraphics.clxForkBasePlateGeometry) {
+ Clx3DGraphics.clxForkBasePlateGeometry = Clx3DGraphics.createClxForkBasePlate()
}
- const clxForkBasePlateGeometry = Clx3dObject.clxForkBasePlateGeometry
+ const clxForkBasePlateGeometry = Clx3DGraphics.clxForkBasePlateGeometry
const clxForkBasePlateMesh = new THREE.Mesh(clxForkBasePlateGeometry, clxGemelMaterial)
clxForkBasePlateMesh.name = 'clxForkBasePlateMesh'
@@ -485,7 +95,7 @@ export default class Clx3dObject extends THREE.Object3D {
this.add(clxForkBasePlateMesh)
}
- animationShowFork(z: number): Promise {
+ override animationShowFork(z: number): Promise {
const clxFork = this.getObjectByName('clxFork')
const clxGemelMeshL1 = this.getObjectByName('clxGemelMeshL1')
const clxGemelMeshL2 = this.getObjectByName('clxGemelMeshL2')
@@ -585,11 +195,11 @@ export default class Clx3dObject extends THREE.Object3D {
}
- animationHideFork(): Promise {
+ override animationHideFork(): Promise {
return this.animationShowFork(0)
}
- animationUpFork(y: number, time?: number = 3): Promise {
+ override animationUpFork(y: number, time?: number = 3): Promise {
const clxFork = this.getObjectByName('clxFork')
const clxGemelMeshL1 = this.getObjectByName('clxGemelMeshL1')
const clxGemelMeshL2 = this.getObjectByName('clxGemelMeshL2')
@@ -660,7 +270,7 @@ export default class Clx3dObject extends THREE.Object3D {
})
}
- animationDownFork(): Promise {
+ override animationDownFork(): Promise {
return this.animationUpFork(0)
}
diff --git a/src/modules/amr/ptr/clx/ClxPropertySetter.ts b/src/modules/amr/ptr/clx/ClxPropertySetter.ts
index 5390c94..bebf4ab 100644
--- a/src/modules/amr/ptr/clx/ClxPropertySetter.ts
+++ b/src/modules/amr/ptr/clx/ClxPropertySetter.ts
@@ -13,6 +13,10 @@ const propertySetter: PropertySetter = {
dataPath: 'dt.clxDepth', label: 'CLX深度', input: 'InputNumber',
inputProps: {},
},
+ {
+ dataPath: 'state', label: 'ptr控制', input: 'PtrController',
+ inputProps: {},
+ },
],
},
};
diff --git a/src/modules/amr/ptr/clx/ClxRenderer.ts b/src/modules/amr/ptr/clx/ClxRenderer.ts
index 58268eb..e10d10b 100644
--- a/src/modules/amr/ptr/clx/ClxRenderer.ts
+++ b/src/modules/amr/ptr/clx/ClxRenderer.ts
@@ -51,7 +51,7 @@ export default class ClxRenderer extends BaseRenderer {
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
// 创建平面几何体
- const group = new Clx3dObject(item, option)
+ const group = new Clx3dObject(item, this.tempViewport, option)
group.name = ClxRenderer.POINT_NAME
// 设置位置