【仿真建模-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);
相关推荐
海绵波波10737 分钟前
Webserver(4.3)TCP通信实现
服务器·网络·tcp/ip
阿伟*rui2 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
XiaoLeisj4 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck4 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei4 小时前
java的类加载机制的学习
java·学习
热爱跑步的恒川4 小时前
【论文复现】基于图卷积网络的轻量化推荐模型
网络·人工智能·开源·aigc·ai编程
云飞云共享云桌面4 小时前
8位机械工程师如何共享一台图形工作站算力?
linux·服务器·网络
Yaml45 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~5 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616886 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端