【仿真建模-anylogic】动态生成ConveyorCustomStation

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);
相关推荐
zjw_rp2 分钟前
Spring-AOP
java·后端·spring·spring-aop
kaixin_learn_qt_ing6 分钟前
了解RPC
网络·网络协议·rpc
Oneforlove_twoforjob15 分钟前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
向宇it32 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行34 分钟前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
安全小王子1 小时前
Kali操作系统简单介绍
网络·web安全
星河梦瑾1 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富1 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想2 小时前
JMeter 使用详解
java·jmeter
言、雲2 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库