【仿真建模-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);
相关推荐
一 乐10 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
卓怡学长10 小时前
w214基于jsp知道特产网
java·intellij-idea
步行cgn10 小时前
Spring 注解使用详解
java·spring
一条小小yu11 小时前
Spring IoC的理解
java·后端·spring
落魄实习生11 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
旺仔学长 哈哈11 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
自强的小白13 小时前
核心功能(Service接口)
java·mybatis
梦帮科技13 小时前
领域认知知识库图谱注入:从双式记账图网络到高质量问答对自动化合成流水线
运维·网络·数据库·人工智能·矩阵·架构·自动化
乌暮13 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习