diff --git a/src/editor/Model2DEditor.vue b/src/editor/Model2DEditor.vue
index 2409868..cd10a4f 100644
--- a/src/editor/Model2DEditor.vue
+++ b/src/editor/Model2DEditor.vue
@@ -306,6 +306,19 @@ export default defineComponent({
taskManager.runTask()
},
addAmrMap(file) {
+ if (!this.viewport) {
+ system.showErrorDialog('请先加载地图')
+ return
+ }
+ if (!worldModel.state.isOpened) {
+ system.showErrorDialog('请先打开地图')
+ return
+ }
+ if (worldModel.state.runState.isRunning) {
+ system.showErrorDialog('请先停止地图运行')
+ return
+ }
+
if (!file) return
file = file.raw
if (!file) {
@@ -327,7 +340,25 @@ export default defineComponent({
system.showErrorDialog('无效的AMR地图文件')
return
}
- AmrMapConvert(this.viewport, jsonData)
+ const items = AmrMapConvert(jsonData)
+ if (!items || items.length === 0) {
+ system.showErrorDialog('AMR地图文件中没有有效的地图数据')
+ return
+ }
+ const viewport = this.viewport
+ // 清除当前地图
+ viewport.stateManager.update(({ deleteEntity }) => {
+ _.forEach(viewport.entityManager.getAllEntityForGrid(), item => {
+ deleteEntity(item.id)
+ })
+ })
+ // 添加新地图
+ viewport.stateManager.update(({ addEntity }) => {
+ items.forEach(item => {
+ addEntity(item)
+ })
+ })
+
system.showInfoDialog('AMR地图加载完毕')
} catch (error) {
diff --git a/src/editor/widgets/server/EnvSelectConnect.vue b/src/editor/widgets/server/EnvSelectConnect.vue
index 5dfda8c..4483d35 100644
--- a/src/editor/widgets/server/EnvSelectConnect.vue
+++ b/src/editor/widgets/server/EnvSelectConnect.vue
@@ -3,7 +3,8 @@
:disabled="worldModelState.runState.currentEnvId && worldModelState.runState.isRunning"
:model-value="worldModelState.runState.currentEnvId"
@change="setEnvId">
-
+
创建虚拟环境
diff --git a/src/utils/AmrMapConvert.md b/src/utils/AmrMapConvert.md
new file mode 100644
index 0000000..ae50f8d
--- /dev/null
+++ b/src/utils/AmrMapConvert.md
@@ -0,0 +1,930 @@
+## 源数据
+```js
+const dataFrom = {
+ "businessMap": [
+ {
+ "floorName": "默认楼层",
+ "mapData": [
+ {
+ "x": 684,
+ "y": 336.5,
+ "type": "CODE",
+ "id": 98,
+ "direction": [
+ "E",
+ "N"
+ ],
+ "attribute": [],
+ "propsValues": [
+ "CellTypeGeneralStation",
+ "CellTaskEnableRack",
+ "CellTypeCyBoard"
+ ],
+ "markerType": 1,
+ "logicX": 6, // 编号是 6_4
+ "logicY": 4,
+ "logicZ": 1,
+ "zoneId": 1,
+ "passingVehicle": [
+ "CY",
+ "CLX"
+ ],
+ "allowPassage": {
+ "long": 1500,
+ "width": 1850,
+ "height": 2000
+ },
+ "constraints": {
+ "CL2": [
+ 1
+ ],
+ "CLX": [
+ 1
+ ]
+ },
+ "isStartSite": false,
+ "uniqueName": "198488",
+ "turningQuadrantConstraints": [],
+ "rcsPrivate": {
+ "rackDirection": 3,
+ "parkingDirection": 0,
+ "roadway": -1
+ },
+ "inRoadDir": "W",
+ "yardDistances": [],
+ "goodsSlotOrientation": [
+ 1,
+ 1
+ ],
+ "goodsSlotLayerHeight": [
+ 1,
+ 1210
+ ],
+ "goodsSlotId": [
+ 21,
+ 22
+ ],
+ "phyX": 684,
+ "phyY": 336.5
+ },
+ {
+ "x": 794,
+ "y": 336.5,
+ "type": "CODE",
+ "id": 111,
+ "direction": [
+ "W",
+ "E",
+ "N"
+ ],
+ "attribute": [],
+ "propsValues": [
+ "CellTypeGeneralStation",
+ "CellTaskEnableRack",
+ "CellTypeCyBoard"
+ ],
+ "markerType": 1,
+ "logicX": 7,
+ "logicY": 4,
+ "logicZ": 1,
+ "zoneId": 1,
+ "passingVehicle": [
+ "CY",
+ "CLX"
+ ],
+ "allowPassage": {
+ "long": 1500,
+ "width": 1850,
+ "height": 2000
+ },
+ "constraints": {
+ "CL2": [
+ 1
+ ],
+ "CLX": [
+ 1
+ ]
+ },
+ "isStartSite": false,
+ "uniqueName": "224822",
+ "turningQuadrantConstraints": [],
+ "rcsPrivate": {
+ "rackDirection": -1,
+ "parkingDirection": -1,
+ "roadway": -1
+ },
+ "inRoadDir": "W",
+ "goodsSlotOrientation": [
+ 1,
+ 1
+ ],
+ "goodsSlotLayerHeight": [
+ 1,
+ 1210
+ ],
+ "goodsSlotId": [
+ 23,
+ 24
+ ],
+ "phyX": 794,
+ "phyY": 336.5,
+ "yardDistances": []
+ },
+ {
+ "x": 689,
+ "y": 341.5,
+ "endX": 799,
+ "endY": 341.5,
+ "type": "ROAD",
+ "lineCm": 1100, // 这是距离,用于计算宽度
+ "align": "Y",
+ "id": 117,
+ "direction": {
+ "id": 5,
+ "label": "右行"
+ },
+ "directionTwo": {},
+ "directionGroup": [ // 这是连接,要将 98 和 111 连起来, 98 对应的id=
+ {
+ "forwardDirectType": "TwoWay",
+ "id": 117,
+ "startSite": 98,
+ "endSite": 111
+ }
+ ],
+ "passingVehicle": [
+ "CY",
+ "CLX"
+ ],
+ "frontSpeed": 1,
+ "reverseSpeed": 1,
+ "reverseSpeedNoGoods": 1,
+ "frontSpeedNoGoods": 1,
+ "startStrategy": "",
+ "allowPassage": {
+ "long": 1500,
+ "width": 1850,
+ "height": 2000
+ },
+ "zoneId": 1,
+ "propsValues": [],
+ "additionalWeightBehind": "",
+ "additionalWeight": "",
+ "distanceWithoutNavigation": 0.3,
+ "biasAttr": {},
+ "isTwoPath": false,
+ "constraints": {
+ "CL2": [
+ 1
+ ],
+ "CLX": [
+ 1
+ ]
+ },
+ "isStandard": false,
+ "posType": "start",
+ "posDirection": "W"
+ },
+ {
+ "x": 1033.5,
+ "y": 386.5,
+ "type": "CODE",
+ "id": 148,
+ "direction": [
+ "N"
+ ],
+ "attribute": [
+ {
+ "direction": "C",
+ "attrName": "货位站点/输送线",
+ "attrValue": "CellTypePallet",
+ "attrDetail": [
+ {
+ "id": 1,
+ "val": 1,
+ "clearanceHeight": 630
+ }
+ ],
+ "rackTypeId": 2, // 这是一个地堆点位,对应 toolingData 中的 id 属性
+ "isChargingAllowed": "",
+ "priority": "",
+ "spaceHeight": 630,
+ "beamHeight": 0,
+ "goodsAllocationIds": [
+ 29
+ ],
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": -10
+ },
+ {
+ "value": -10
+ }
+ ],
+ "goodsPlacementOffset": 0,
+ "goodsStackId": 1,
+ "id": 29,
+ "localNumber": "1-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 980,
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": 0,
+ "layerHeight": 1,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": [],
+ "linkId": 90,
+ "goodsSlotStatusCheckHeight": null
+ }
+ ],
+ "goodsStackId": 1,
+ "toolId": 11,
+ "rack_orientation": 0
+ }
+ ],
+ "propsValues": [
+ "CellTypeGeneralStation",
+ "CellTaskEnableRack",
+ "CellTypePallet" // 这是一个地堆点位, 再去查看 attribute[0].rackTypeId 看具体是地堆还是货架
+ ],
+ "markerType": 1,
+ "logicX": 105,
+ "logicY": 105,
+ "logicZ": 1,
+ "zoneId": 1,
+ "passingVehicle": [
+ "CY",
+ "CLX"
+ ],
+ "allowPassage": {
+ "long": 1500,
+ "width": 1850,
+ "height": 2000
+ },
+ "constraints": {
+ "CL2": [
+ 1
+ ],
+ "CLX": [
+ 1
+ ]
+ },
+ "isStartSite": false,
+ "uniqueName": "",
+ "turningQuadrantConstraints": [],
+ "rcsPrivate": {
+ "rackDirection": -1,
+ "parkingDirection": -1,
+ "roadway": -1
+ },
+ "generationDir": "d", // 方向
+ "goodsSlotOrientation": [],
+ "goodsSlotLayerHeight": [],
+ "goodsSlotId": [],
+ "needOffset": false,
+ "CTPStartLogicY": 4,
+ "phyX": 1033.5,
+ "phyY": 386.5
+ },
+ ]
+ }
+ ],
+ "toolingData": [
+ {
+ "categoryId": 2, // 地堆
+ "uprightWidth": "",
+ "width": 1200,
+ "length": 1000,
+ "categoryName": "地面货位",
+ "topLayerClearance": 630,
+ "name": "地堆",
+ "id": 2, // 地堆类型ID
+ "layersHeight": [
+ {
+ "id": 1,
+ "layerHeight": 1,
+ "clearance": 630,
+ "layerGoodsAllocationGroup": {
+ "goodsAllocationNum": 1,
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": -10
+ },
+ {
+ "value": -10
+ }
+ ],
+ "goodsPlacementOffset": 0,
+ "goodsStackId": 1,
+ "id": 90,
+ "localNumber": "1-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 980,
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": 0,
+ "layerHeight": 1,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": []
+ }
+ ]
+ }
+ }
+ ],
+ "distanceToStation": 980,
+ "mobile": false,
+ "goodsStackId": 1,
+ "stacking": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": "",
+ "goodsAllocationNum": 1,
+ "beamHeight": 0,
+ "goodsAllocation": {
+ "goodsPlacementOffset": 0,
+ "goodsSlotFeatureType": "Default",
+ "goodsAllocationWidth": 1200,
+ "gaps": [
+ {
+ "value": 0
+ },
+ {
+ "value": 0
+ }
+ ]
+ },
+ "verticalGoodsSlotGroups": {
+ "v-1": [
+ "1-1"
+ ]
+ },
+ "horizontalGoodsSlotGroups": {
+ "h-1": [
+ "1-1"
+ ]
+ }
+ },
+ {
+ "categoryId": 1,
+ "uprightWidth": 90,
+ "width": 1000,
+ "length": 2480,
+ "categoryName": "货架",
+ "topLayerClearance": 2000,
+ "name": "矮层货架",
+ "id": 15,
+ "layersHeight": [
+ {
+ "id": 1,
+ "layerHeight": 1,
+ "clearance": 1079,
+ "layerGoodsAllocationGroup": {
+ "goodsAllocationNum": 2,
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "1-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1,
+ "clearance": 1079,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ },
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "1-2",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-2",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1,
+ "clearance": 1079,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ }
+ ]
+ },
+ "goodsStackId": 1
+ },
+ {
+ "id": 2,
+ "layerHeight": 1210,
+ "layerGoodsAllocationGroup": {
+ "goodsAllocationNum": 2,
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "2-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-2",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1210,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ },
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "2-2",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-2",
+ "horizontalGroupId": "h-2",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1210,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ }
+ ]
+ },
+ "clearance": 2000
+ }
+ ],
+ "positioningMarker": "NONE",
+ "distanceToStation": 990,
+ "mobile": false,
+ "goodsStackId": 1,
+ "stacking": false,
+ "slideChute": false,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": "",
+ "rackLegSideOffset": 0,
+ "rackLegFrontOffset": 0,
+ "goodsAllocationNum": 2,
+ "beamHeight": 130,
+ "goodsSlotFeatureType": "Default",
+ "goodsAllocation": {
+ "goodsPlacementOffset": 100,
+ "goodsSlotFeatureType": "Default",
+ "goodsAllocationWidth": 1000,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ]
+ },
+ "verticalGoodsSlotGroups": {
+ "v-1": [
+ "1-1",
+ "2-1"
+ ],
+ "v-2": [
+ "1-2",
+ "2-2"
+ ]
+ },
+ "horizontalGoodsSlotGroups": {
+ "h-1": [
+ "1-1",
+ "1-2"
+ ],
+ "h-2": [
+ "2-1",
+ "2-2"
+ ]
+ }
+ },
+ {
+ "categoryId": 1,
+ "uprightWidth": 90,
+ "width": 1000,
+ "length": 2480,
+ "categoryName": "货架",
+ "topLayerClearance": 2000,
+ "name": "高层货架",
+ "id": 19,
+ "layersHeight": [
+ {
+ "id": 1,
+ "layerHeight": 1,
+ "clearance": 2054,
+ "layerGoodsAllocationGroup": {
+ "goodsAllocationNum": 2,
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": "",
+ "id": 95,
+ "localNumber": "1-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": "",
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": "",
+ "layerHeight": 1,
+ "clearance": 2084,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ },
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": "",
+ "id": 96,
+ "localNumber": "1-2",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": "",
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-2",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": "",
+ "layerHeight": 1,
+ "clearance": 2084,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ }
+ ]
+ }
+ },
+ {
+ "id": 2,
+ "layerHeight": 2185,
+ "layerGoodsAllocationGroup": {
+ "goodsAllocationNum": 2,
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": "",
+ "id": 97,
+ "localNumber": "2-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": "",
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-2",
+ "displayNumber": "",
+ "beamHeight": 100,
+ "layerHeight": 2185,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ },
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": "",
+ "id": 98,
+ "localNumber": "2-2",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": "",
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-2",
+ "horizontalGroupId": "h-2",
+ "displayNumber": "",
+ "beamHeight": 100,
+ "layerHeight": 2185,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ }
+ ]
+ },
+ "clearance": 2000
+ }
+ ],
+ "positioningMarker": "NONE",
+ "distanceToStation": 990,
+ "mobile": false,
+ "goodsStackId": "",
+ "stacking": false,
+ "slideChute": false,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": "",
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": "",
+ "rackLegSideOffset": 0,
+ "rackLegFrontOffset": 0,
+ "goodsAllocationNum": 2,
+ "beamHeight": 130,
+ "goodsSlotFeatureType": "Default",
+ "goodsAllocation": {
+ "goodsPlacementOffset": 100,
+ "goodsSlotFeatureType": "Default",
+ "goodsAllocationWidth": 1000,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ]
+ },
+ "verticalGoodsSlotGroups": {
+ "v-1": [
+ "1-1",
+ "2-1"
+ ],
+ "v-2": [
+ "1-2",
+ "2-2"
+ ]
+ },
+ "horizontalGoodsSlotGroups": {
+ "h-1": [
+ "1-1",
+ "1-2"
+ ],
+ "h-2": [
+ "2-1",
+ "2-2"
+ ]
+ }
+ }
+ ],
+}
+```
+
+处理逻辑
+amrIdMap = Map
+lccMap = Map<`${logicX}_${logicY}`, json>
+- 读取 businessMap.mapData 中的每个点, 进行第一次循环迭代
+ - 如果 "type" === "CODE", 读取 propsValues 数组
+ - 不包含 CellTypePallet 则为 t=way 属性点,id= `${logicX}_${logicY}`
+ - 包含 CellTypePallet 则查找他的 attribute[0].rackTypeId 属性
+ - 如果关联的 toolingData 中的 categoryId === 2 则为 t="gstore" 地堆点位, id= `${logicX}_${logicY}`
+ - 否则为 t="rack" 货架点位, id= `${logicX}_${logicY}`
+ - 如果 "type" === "ROAD", 则为点位进行连接,
+ - 读取 directionGroup 中的 startSite 和 endSite, 连接两个点位
+转换为
+```js
+const data = [
+ {
+ 'id': '6_4',
+ 't': 'way',
+ 'v': true,
+ 'logicX': 6,
+ 'logicY': 4,
+ 'tf': [
+ [ 1, 0, 0 ],
+ [ 0, 0, 0 ],
+ [ 0.25, 0.1, 0.25 ]
+ ],
+ 'dt': {
+ 'qrCode': '198488',
+ 'in': [ '7_4' ],
+ 'out': [ '7_4' ],
+ 'center': [],
+ 'linkStore': [
+ {
+ 'item': 'rack1',
+ 'bay': 0,
+ 'direction': 'up'
+ }
+ ]
+ }
+ },
+ {
+ 'id': '7_4',
+ 't': 'way',
+ 'v': true,
+ 'logicX': 7,
+ 'logicY': 4,
+ 'tf': [
+ [ 2.1, 0, 0 ],
+ [ 0, 0, 0 ],
+ [ 0.25, 0.1, 0.25 ]
+ ],
+ 'dt': {
+ 'qrCode': '224822',
+ 'in': [ '6_4', '8_4' ],
+ 'out': [ '6_4', '8_4' ],
+ 'center': [],
+ 'linkStore': [
+ {
+ 'item': 'rack1',
+ 'bay': 1,
+ 'direction': 'up'
+ }
+ ]
+ }
+ }
+]
+```
diff --git a/src/utils/AmrMapConvert.ts b/src/utils/AmrMapConvert.ts
index 9ea69ab..3e7ebb1 100644
--- a/src/utils/AmrMapConvert.ts
+++ b/src/utils/AmrMapConvert.ts
@@ -1,6 +1,480 @@
import type Viewport from '@/core/engine/Viewport.ts'
+import AMR_1 from '../../../lcc-map/jx_test/floor/AMR_1.json'
+import Decimal from 'decimal.js'
-export function AmrMapConvert(viewport: Viewport, json: any) {
- console.log(json)
+export function AmrMapConvertDemo() {
+ const from: any = AMR_1
+ const result = AmrMapConvert(from)
+ console.log(result)
debugger
}
+
+window['AmrMapConvertDemo'] = AmrMapConvertDemo
+
+// AmrMapConvertDemo()
+
+export function AmrMapConvert(from: any): Array {
+ const d1000 = new Decimal(1000)
+ const d100 = new Decimal(100)
+ const storeType = new Map()
+ for (const td of from.toolingData) {
+ if (td.categoryId === 1) {
+ // 货架
+ /*
+ 根据 layersHeight 获取出
+ "layersHeight": [
+ {
+ "id": 1,
+ "layerHeight": 1,
+ "clearance": 1079,
+ "layerGoodsAllocationGroup": {
+ "goodsAllocationNum": 2,
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "1-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1,
+ "clearance": 1079,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ },
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "1-2",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-2",
+ "horizontalGroupId": "h-1",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1,
+ "clearance": 1079,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ }
+ ]
+ },
+ "goodsStackId": 1
+ },
+ {
+ "id": 2,
+ "layerHeight": 1210,
+ "layerGoodsAllocationGroup": {
+ "goodsAllocationNum": 2,
+ "goodsAllocation": [
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "2-1",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-1",
+ "horizontalGroupId": "h-2",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1210,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ },
+ {
+ "isSelected": false,
+ "gaps": [
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ },
+ {
+ "value": 100
+ }
+ ],
+ "goodsPlacementOffset": 100,
+ "goodsStackId": 1,
+ "id": 98,
+ "localNumber": "2-2",
+ "goodsSlotFeatureType": "Default",
+ "distanceToStation": 990,
+ "goodsSlotFeatureHeight": "",
+ "boxMarkerOffsetToBottom": 0,
+ "goodsSlotTelescopicDistanceToDetectFeature": "",
+ "verticalGroupId": "v-2",
+ "horizontalGroupId": "h-2",
+ "displayNumber": "",
+ "beamHeight": 130,
+ "layerHeight": 1210,
+ "clearance": 2000,
+ "width": 1000,
+ "orientation": [],
+ "slideChute": false,
+ "heightOverGoodsSlotWhenPut": null,
+ "heightOverGoodsSlotWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenGet": null,
+ "heightGapBetweenForkAndGoodsWhenPut": null,
+ "goodsSlotPillarHeight": null,
+ "goodsSlotStatusCheckHeight": ""
+ }
+ ]
+ },
+ "clearance": 2000
+ }
+ ],
+ */
+ const rackDepth = new Decimal(td.width).div(d1000).toNumber()
+ const levelHeight = td.layersHeight.map((lh: any) => new Decimal(lh.layerHeight).div(d1000).toNumber())
+ const levelCount = levelHeight.length
+ const width = new Decimal(td.length).div(td.goodsAllocationNum).div(d1000).toNumber()
+ storeType.set(td.id, {
+ 't': 'rack',
+ 'v': true,
+ 'tf': [
+ [0, 0, 0],
+ [0, 0, 0],
+ [width, 1.211, rackDepth]
+ ],
+ 'dt': {
+ 'rackDepth': rackDepth,
+ 'bottomBarHeight': 0.2,
+ 'bottomLinkHeight': 0.2,
+ 'topLinkDistance': 0.2,
+ 'levelCount': levelCount,
+ 'bayCount': 1,
+ 'hideFloor': 0,
+ 'extendColumns': 1,
+ 'columnSpacing': 1,
+ 'bays': [
+ {
+ 'bayWidth': width,
+ 'levelHeight': levelHeight,
+ 'topHeight': 2
+ }
+ ],
+ 'center': [],
+ 'in': [],
+ 'out': [],
+ 'rackWidth': width,
+ 'rackHeight': 1.211
+ }
+ })
+
+ } else if (td.categoryId === 2) {
+ // 地堆
+ storeType.set(td.id, {
+ 't': 'gstore',
+ 'v': true,
+ 'tf': [
+ [0, 0, 0],
+ [0, 0, 0],
+ [new Decimal(td.width).div(d1000).toNumber(), 0.01, new Decimal(td.length).div(d1000).toNumber()]
+ ],
+ 'dt': {
+ 'in': [],
+ 'out': [],
+ 'center': [],
+ 'strokeWidth': 0.1
+ }
+ })
+ }
+ }
+
+ // ====================== 第一次循环,建立点位 =========================
+ const amrIdMap = new Map()
+ const lccMap = new Map()
+ let maxX = NaN, maxY = NaN, minX = NaN, minY = NaN
+ for (const amrNode of from.businessMap[0].mapData) {
+ amrIdMap.set(amrNode.id, amrNode)
+ const lccId = amrNode.logicX + '_' + amrNode.logicY
+ // if (lccId === '105_105') {
+ // debugger
+ // }
+ let insertNode: any = null
+ if (amrNode.type === 'CODE') {
+ if (isStorePos(amrNode)) {
+ // =================== 这是一个存储位 =====================
+ const rackTypeId = amrNode.attribute[0].rackTypeId
+ insertNode = {
+ 'id': lccId,
+ ..._.cloneDeep(storeType.get(rackTypeId))
+ }
+
+
+ } else {
+ // =================== 这是一个路标 =====================
+ insertNode = {
+ 'id': lccId, 't': 'way', 'v': true,
+ 'tf': [
+ [0, 0, 0],
+ [0, 0, 0],
+ [0.25, 0.1, 0.25]
+ ],
+ 'dt': {
+ 'qrCode': amrNode.uniqueName,
+ 'in': [],
+ 'out': [],
+ 'center': []
+ }
+ }
+
+ // 旋转站
+ if (_.findIndex(amrNode.propsValues, v => v === 'CellTypePallet') >= 0) {
+ // 这是一个旋转站, 读取 constraints 所有的 key
+ const agvRotation = []
+ for (const key of Object.keys(amrNode.constraints)) {
+ agvRotation.push(key)
+ }
+ if (agvRotation.length > 0) {
+ lccMap.get(lccId).dt.agvRotation = agvRotation
+ }
+ }
+ }
+ }
+
+ if (insertNode) {
+ insertNode.originId = amrNode.id
+ insertNode.tf[0][0] = new Decimal(amrNode.x).div(d100).toNumber()
+ insertNode.tf[0][2] = new Decimal(amrNode.y).div(d100).toNumber()
+ insertNode.logicX = amrNode.logicX
+ insertNode.logicY = amrNode.logicY
+
+ if (isNaN(maxX) || insertNode.tf[0][0] > maxX) {
+ maxX = insertNode.tf[0][0]
+ }
+ if (isNaN(maxY) || insertNode.tf[0][2] > maxY) {
+ maxY = insertNode.tf[0][2]
+ }
+ if (isNaN(minX) || insertNode.tf[0][0] < minX) {
+ minX = insertNode.tf[0][0]
+ }
+ if (isNaN(minY) || insertNode.tf[0][2] < minY) {
+ minY = insertNode.tf[0][2]
+ }
+ lccMap.set(lccId, insertNode)
+ }
+ }
+
+ // ====================== 第二次循环,建立点位关联 =========================
+ for (const amrNode of from.businessMap[0].mapData) {
+ if (amrNode.type !== 'ROAD') {
+ continue
+ }
+ for (const dg of amrNode.directionGroup) {
+ // 从 dg.startSite 和 dg.endSite 中获取对应的点位
+ const startNode = amrIdMap.get(dg.startSite)
+ const endNode = amrIdMap.get(dg.endSite)
+
+ if (!startNode || !endNode) {
+ console.warn('未找到起点或终点节点', dg.startSite, dg.endSite)
+ continue
+ }
+
+ const startLccId = startNode.logicX + '_' + startNode.logicY
+ const endLccId = endNode.logicX + '_' + endNode.logicY
+ if (!lccMap.get(startLccId) || !lccMap.get(endLccId)) {
+ console.warn('未找到起点或终点 LCC 节点', startLccId, endLccId)
+ continue
+ }
+
+ if (lccMap.get(startLccId).t === 'way' && lccMap.get(endLccId).t === 'way') {
+ // 起点和终点都是路标
+ lccMap.get(startLccId).dt.in.push(endLccId)
+ lccMap.get(startLccId).dt.out.push(endLccId)
+ lccMap.get(endLccId).dt.in.push(startLccId)
+ lccMap.get(endLccId).dt.out.push(startLccId)
+
+ } else if (lccMap.get(startLccId).t === 'way' &&
+ (lccMap.get(endLccId).t === 'rack' || lccMap.get(endLccId).t === 'gstore')) {
+ // 起点是路标,终点是存储位
+ if (!lccMap.get(startLccId).dt.linkStore) {
+ lccMap.get(startLccId).dt.linkStore = []
+ }
+ const direction = convertAmrDirectToLinkStoreDirection(amrNode.direction?.id)
+ if (_.isArray(lccMap.get(endLccId).dt.bays?.[0]?.levelHeight)) {
+ for (let i = 0; i < lccMap.get(endLccId).dt.bays[0].levelHeight.length; i++) {
+ lccMap.get(startLccId).dt.linkStore.push({
+ 'item': endLccId,
+ 'bay': 0,
+ 'level': i,
+ 'cell': 0,
+ 'direction': direction
+ })
+ }
+
+ } else {
+ lccMap.get(startLccId).dt.linkStore.push({
+ 'item': endLccId,
+ 'bay': 0,
+ 'level': 0,
+ 'cell': 0,
+ 'direction': direction
+ })
+ }
+ convertLinkStoreDistance(direction, lccMap.get(endLccId))
+
+ } else if (lccMap.get(endLccId).t === 'way' &&
+ (lccMap.get(endLccId).t === 'rack' || lccMap.get(endLccId).t === 'gstore')) {
+ // 终点是路标,起点是存储位
+ if (!lccMap.get(endLccId).dt.linkStore) {
+ lccMap.get(endLccId).dt.linkStore = []
+ }
+ const direction = convertAmrDirectToLinkStoreDirection(amrNode.direction?.id)
+ if (_.isArray(lccMap.get(startLccId).dt.bays?.[0]?.levelHeight)) {
+ for (let i = 0; i < lccMap.get(startLccId).dt.bays[0].levelHeight.length; i++) {
+ lccMap.get(endLccId).dt.linkStore.push({
+ 'item': startLccId,
+ 'bay': 0,
+ 'level': i,
+ 'cell': 0,
+ 'direction': direction
+ })
+ }
+
+ } else {
+ lccMap.get(endLccId).dt.linkStore.push({
+ 'item': startLccId,
+ 'bay': 0,
+ 'level': 0,
+ 'cell': 0,
+ 'direction': direction
+ })
+ }
+
+ convertLinkStoreDistance(direction, lccMap.get(startLccId))
+ }
+ }
+ }
+
+ // ====================== 第三次循环,将所有点位移动到画面中心 =========================
+ const centerX = new Decimal((maxX + minX) / 2).toNumber()
+ const centerY = new Decimal((maxY + minY) / 2).toNumber()
+ for (const entry of lccMap.entries()) {
+ const node = entry[1]
+ if (node.tf) {
+ node.tf[0][0] = new Decimal(node.tf[0][0]).minus(centerX).toNumber()
+ node.tf[0][2] = new Decimal(node.tf[0][2]).minus(centerY).toNumber()
+ }
+ }
+
+ const planObj: Object = {}
+ for (const entry of lccMap.entries()) {
+ planObj[entry[0]] = entry[1]
+ }
+ // console.log(planObj)
+ // debugger
+ return Object.values(planObj) as Array
+}
+
+// 将 AMR 的方向转换为 LinkStore 的方向
+function convertAmrDirectToLinkStoreDirection(direct: number): string {
+ if (direct === 1) {
+ return 'up'
+ } else if (direct === 2) {
+ return 'down'
+ } else if (direct === 3) {
+ return 'right'
+ } else if (direct === 4) {
+ return 'left'
+ } else {
+ throw new Error('未知的方向: ' + direct)
+ }
+}
+
+// 判断点位是否为存储位
+function isStorePos(amrNode: any) {
+ return (_.findIndex(amrNode.propsValues, v => v === 'CellTypePallet') >= 0)
+}
+
+// 根据方向,调整存储位的距离
+function convertLinkStoreDistance(direction: string, storeNode: any) {
+ if (direction === 'up') {
+ storeNode.tf[0][2] -= 0.5
+
+ } else if (direction === 'down') {
+ storeNode.tf[0][2] += 0.5
+
+ } else if (direction === 'left') {
+ storeNode.tf[0][0] -= 0.5
+ storeNode.tf[1][1] = 90 // 90 度旋转
+
+ } else if (direction === 'right') {
+ storeNode.tf[0][0] += 0.5
+ storeNode.tf[1][1] = 90 // 90 度旋转
+ }
+}