Author:赵志乾
Date:2024-06-18
Declaration:All Right Reserved!!!
0. 背景
直接使用Anylogic组件开发的模型无法动态改变运输网布局;目前需求是要将运输网布局配置化;运输网配置化的前提是将其标准化为仅包含辊道、自定义站点两种元素的网络;之后依据配置文件动态构建运输网;最后将自定义Agent逻辑关联到自定义站点实现流程串通;本次示例仅包含运输网中的辊道和自定义站点的动态生成以及组装过程;
1. 常用函数
函数 | 功能 |
---|---|
ConveyorCustomStation() | 构造函数 |
addVertex(double x, double y) | 添加点以构建2D图形,注意点:需要至少三个点,且连起的图形不得自身有交叉;通常会将CustomStation的图形隐藏,而将其内部自定义逻辑封装成Agent,用Agent的presentation替补CustomStation本身的图形; |
addConnection(ConveyorPath conveyor, PathType type) | 将CustomStation与conveyor连接起来 |
onEnter(T agent) | 根据需要定义子类覆写该方法;当所运输物料进入CustomStation时,会自动执行该方法; |
2. 数据结构定义
{
"points": [
{
"code": "", // 点编码
"name": "", // 点名称
"x": 0.0, // 点坐标
"y": 0.0,
"z": 0.0
}
],
"conveyors": [
{
"code": "", // 辊道编码
"name": "", // 辊道名称
"pointCodes": [] // 辊道从起点至终点所经历的位置点编码列表
}
],
"customStations": [
{
"code": "", // 自定义站点编码
"name": "", // 自定义站点名称
"inConveyorCodes": [], // 传入站点的辊道
"outConveyorCodes": [] // 传出站点的辊道
}
]
}
3. 代码实现
// ************************数据对象定义****************************
public class PointDefinition implements Serializable {
private String code;
private String name;
private Double x;
private Double y;
private Double z;
// setter、getter
}
public class ConveyorDefinition implements Serializable {
private String code;
private String name;
// setter、getter
}
public class LayoutDefinition implements Serializable {
private List<PointDefinition> points;
private List<ConveyorDefinition> conveyors;
private List<CustomStationDefinition> customStations;
// setter、getter
}
public class CustomStationDefinition implements Serializable {
private String code;
private String name;
private List<String> inConveyorCodes;
private List<String> outConveyorCodes;
// setter、getter
}
//******************************子类*******************************
public class CustomStation<T extends Agent> extends ConveyorCustomStation<T> {
// 持有站点定义,便于onEnter中依据站点不同做不同处理
CustomStationDefinition customStationDefinition;
public CustomStation(CustomStationDefinition customStationDefinition) {
super();
this.customStationDefinition = customStationDefinition;
}
public void onEnter(T agent ) {
// 自定义逻辑
}
}
//**************************动态生成过程******************************
// step1: 转map,方便后续使用
Map<String,PointDefinition> codeToPointDefinitionMap = layoutDefinition.getPoints()
.stream()
.collect(Collectors.toMap(PointDefinition::getCode, Function.identity(), (a,b)->b));
Map<String,ConveyorDefinition> codeToConveyorDefinitionMap = layoutDefinition.getConveyors()
.stream()
.collect(Collectors.toMap(ConveyorDefinition::getCode, Function.identity(), (a,b)->b));
Map<ConveyorDefinition,ConveyorPath> definitionToConveyorMap = new HashMap<>();
// step2: 定义网络对象
ConveyorNetwork conveyorNetwork = new ConveyorNetwork(this,"conveyorNetwork");
// step3: 向网络添加conveyor
for(ConveyorDefinition conveyorDefinition : layoutDefinition.getConveyors()){
ConveyorPath conveyor = new ConveyorPath();
// 每个conveyor由若干段组成
for(int index=0; index<conveyorDefinition.getPointCodes().size()-1; index++){
PointDefinition startPoint = codeToPointDefinitionMap.get(conveyorDefinition.getPointCodes().get(index));
PointDefinition endPoint = codeToPointDefinitionMap.get(conveyorDefinition.getPointCodes().get(index+1));
double startX = scale.pixelsPerUnit(METER)*startPoint.getX();
double startY = scale.pixelsPerUnit(METER)*startPoint.getY();
double startZ = scale.pixelsPerUnit(METER)*startPoint.getZ();
double endX = scale.pixelsPerUnit(METER)*endPoint.getX();
double endY = scale.pixelsPerUnit(METER)*endPoint.getY();
double endZ = scale.pixelsPerUnit(METER)*endPoint.getZ();
MarkupSegmentLine segment = new MarkupSegmentLine(startX, startY, startZ, endX, endY, endZ);
conveyor.addSegment(segment);
}
definitionToConveyorMap.put(conveyorDefinition, conveyor);
conveyorNetwork.add(conveyor);
}
// step4: 自定义站点添加
for(CustomStationDefinition customStationDefinition : layoutDefinition.getCustomStations()){
// step4.1: 站点创建
CustomStation<Agent> customStation = new CustomStation(customStationDefinition);
List<PointDefinition> points = new ArrayList<>();
// step4.2: 站点与辊道关联,并绘制站点图形
for(String conveyorCode : customStationDefinition.getInConveyorCodes()){
customStation.addConnection(definitionToConveyorMap.get(codeToConveyorDefinitionMap.get(conveyorCode)), PathEndType.END);
ConveyorDefinition conveyorDefinition = codeToConveyorDefinitionMap.get(conveyorCode);
PointDefinition pointDefinition = codeToPointDefinitionMap.get(conveyorDefinition.getPointCodes().get(conveyorDefinition.getPointCodes().size()-1));
points.add(pointDefinition);
customStation.addVertex(scale.pixelsPerUnit(METER)*pointDefinition.getX(), scale.pixelsPerUnit(METER)*pointDefinition.getY());
}
for(String conveyorCode : customStationDefinition.getOutConveyorCodes()){
customStation.addConnection(definitionToConveyorMap.get(codeToConveyorDefinitionMap.get(conveyorCode)), PathEndType.BEGIN);
ConveyorDefinition conveyorDefinition = codeToConveyorDefinitionMap.get(conveyorCode);
PointDefinition pointDefinition = codeToPointDefinitionMap.get(conveyorDefinition.getPointCodes().get(0));
points.add(pointDefinition);
customStation.addVertex(scale.pixelsPerUnit(METER)*pointDefinition.getX(), scale.pixelsPerUnit(METER)*pointDefinition.getY());
}
// step4.3: 站点图形补充
int conveyorNum = customStationDefinition.getInConveyorCodes().size()+customStationDefinition.getOutConveyorCodes().size();
if(conveyorNum==0){
error("不允许无连接辊道的ConveyorCustomStation");
}else if(conveyorNum==1){
// 已有一个点,需要额外补充两个点
customStation.addVertex(scale.pixelsPerUnit(METER)*(points.get(points.size()-1).getX()+0.1), scale.pixelsPerUnit(METER)*(points.get(points.size()-1).getY()+0.2));
customStation.addVertex(scale.pixelsPerUnit(METER)*(points.get(points.size()-1).getX()+0.1), scale.pixelsPerUnit(METER)*(points.get(points.size()-1).getY()+0.4));
}else if(conveyorNum==2){
// 已有一个点,需要额外补充一个点,借助两点的法线寻找第三点
double x1 = scale.pixelsPerUnit(METER)*points.get(0).getX();
double y1 = scale.pixelsPerUnit(METER)*points.get(0).getY();
double x2 = scale.pixelsPerUnit(METER)*points.get(points.size()-1).getX();
double y2 = scale.pixelsPerUnit(METER)*points.get(points.size()-1).getY();
double kAB;
if (x2 - x1 == 0) {
kAB = Double.POSITIVE_INFINITY;
} else {
kAB = (y2 - y1) / (x2 - x1);
}
double kPerp;
if (kAB == Double.POSITIVE_INFINITY || kAB == Double.NEGATIVE_INFINITY || kAB == 0) {
kPerp = kAB == 0 ? Double.POSITIVE_INFINITY : 0;
} else {
kPerp = -1 / kAB;
}
double xC = x1 + 0.5;
double yC;
if (kPerp == Double.POSITIVE_INFINITY || kPerp == Double.NEGATIVE_INFINITY) {
yC = y1;
} else {
yC = y1 + kPerp * (xC - x1);
}
customStation.addVertex(xC,yC);
}
conveyorNetwork.add(customStation);
}
// step5: 将生成的网络添加到演示中
Level customLevel = new Level(this,"customLevel",SHAPE_DRAW_2D3D,0);
customLevel.add(conveyorNetwork);
customLevel.initialize();
presentation.add(customLevel);