Browse Source

AmrMapConvert 从 AMR 地图转换为 LCC 地图

jx-test
修宁 5 months ago
parent
commit
98c142bbb1
  1. 33
      src/editor/Model2DEditor.vue
  2. 3
      src/editor/widgets/server/EnvSelectConnect.vue
  3. 930
      src/utils/AmrMapConvert.md
  4. 478
      src/utils/AmrMapConvert.ts

33
src/editor/Model2DEditor.vue

@ -306,6 +306,19 @@ export default defineComponent({
taskManager.runTask() taskManager.runTask()
}, },
addAmrMap(file) { 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 if (!file) return
file = file.raw file = file.raw
if (!file) { if (!file) {
@ -327,7 +340,25 @@ export default defineComponent({
system.showErrorDialog('无效的AMR地图文件') system.showErrorDialog('无效的AMR地图文件')
return 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地图加载完毕') system.showInfoDialog('AMR地图加载完毕')
} catch (error) { } catch (error) {

3
src/editor/widgets/server/EnvSelectConnect.vue

@ -3,7 +3,8 @@
:disabled="worldModelState.runState.currentEnvId && worldModelState.runState.isRunning" :disabled="worldModelState.runState.currentEnvId && worldModelState.runState.isRunning"
:model-value="worldModelState.runState.currentEnvId" :model-value="worldModelState.runState.currentEnvId"
@change="setEnvId"> @change="setEnvId">
<el-option v-for="env in envList" :key="env.envId" :label="env.envName" :value="env.envId"></el-option> <el-option v-for="env in envList" :key="env.envId"
:label="'('+env.envId+') '+ env.envName" :value="env.envId" />
<template #footer> <template #footer>
<el-button size="small" type="primary" @click="createEnv" plain>创建虚拟环境</el-button> <el-button size="small" type="primary" @click="createEnv" plain>创建虚拟环境</el-button>
<el-button size="small" :icon="renderIcon('Refresh')" @click="reloadEnvList" /> <el-button size="small" :icon="renderIcon('Refresh')" @click="reloadEnvList" />

930
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<id, json>
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'
}
]
}
}
]
```

478
src/utils/AmrMapConvert.ts

@ -1,6 +1,480 @@
import type Viewport from '@/core/engine/Viewport.ts' 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) { export function AmrMapConvertDemo() {
console.log(json) const from: any = AMR_1
const result = AmrMapConvert(from)
console.log(result)
debugger debugger
} }
window['AmrMapConvertDemo'] = AmrMapConvertDemo
// AmrMapConvertDemo()
export function AmrMapConvert(from: any): Array<ItemJson> {
const d1000 = new Decimal(1000)
const d100 = new Decimal(100)
const storeType = new Map<number, Object>()
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<number, any>()
const lccMap = new Map<string, any>()
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<ItemJson>
}
// 将 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 度旋转
}
}

Loading…
Cancel
Save