【仿真建模-anylogic】动态生成轨道网络

Author:赵志乾
Date:2024-06-07
Declaration:All Right Reserved!!!

**问题:**anylogic支持在图形编辑界面以拖拽方式搭建轨道网络,以该方法搭建的模型复用性低。

**解决方案:**轨道布局以配置文件进行描述,模型启动时依据配置文件动态绘制轨道网络。

// step1: 定义配置文件数据结构
{
    "points": [
        {
            "code": "位置点编码",
            "name": "位置点名称",
            "x": 0, // 位置点坐标, 单位:米
            "y": 0, // 位置点坐标, 单位:米
            "z": 0  // 位置点坐标, 单位:米
        }
    ],
    "tracks": [
        {
            "code": "轨道编码",
            "name": "轨道名称",
            "pointCodes": [ // 轨道从起点至终点所经历的位置点编码
                "位置点编码" 
            ]
        }
    ]
}

// step2: 定义解析类
public class PointDefinition implements Serializable {
	private String code;
	private String name;
	private Double x;
	private Double y;
	private Double z;
    // setter、getter、constructor
}
public class TrackDefinition implements Serializable {
	 private String code;
	 private String name;
	 private List<String> pointCodes;
     // setter、getter、constructor
}
public class LayoutDefinition implements Serializable {
	private List<PointDefinition> points;
	private List<TrackDefinition> tracks;
    // setter、getter、constructor
}


// step3: 容器智能体中完成轨道绘制
Map<String,PointDefinition> codeToPointDefinitionMap = layoutDefinition.getPoints()
	.stream()
	.collect(Collectors.toMap(PointDefinition::getCode, Function.identity(), (a,b)->b));

RailwayNetwork rn = new RailwayNetwork(this, "railwayNetwork",SHAPE_DRAW_2D3D, 0);
Map<String,List<TrackDefinition>> switchCodeToTrackDefinitionsMap = new HashMap<>();
Map<TrackDefinition,RailwayTrack> trackDefinitionToRailwayTrackMap = new HashMap<>();
// 3.1: 轨道绘制
for(TrackDefinition trackDefinition : layoutDefinition.getTracks()){
	String startPointCode = trackDefinition.getPointCodes().get(0);
	List<TrackDefinition> trackDefinitions = switchCodeToTrackDefinitionsMap.getOrDefault(startPointCode, new ArrayList<>());
	trackDefinitions.add(trackDefinition);
	switchCodeToTrackDefinitionsMap.put(startPointCode, trackDefinitions);
	
	String endPointCode = trackDefinition.getPointCodes().get(trackDefinition.getPointCodes().size()-1);
	trackDefinitions = switchCodeToTrackDefinitionsMap.getOrDefault(endPointCode, new ArrayList<>());
	trackDefinitions.add(trackDefinition);
	switchCodeToTrackDefinitionsMap.put(endPointCode, trackDefinitions);
	
	RailwayTrack rt = new RailwayTrack();
	rt.setWidth(1, METER);
	rn.add(rt);
	trackDefinitionToRailwayTrackMap.put(trackDefinition,rt);
	for(int index = 0; index<trackDefinition.getPointCodes().size(); index++){
		String pointCode = trackDefinition.getPointCodes().get(index);
		PointDefinition pointDefinition = codeToPointDefinitionMap.get(pointCode);
		if(pointDefinition==null){
			error("轨道定义中包含未知点! trackCode="+trackDefinition.getCode()+" pointCode="+pointCode);
		}
		
		double x = scale.pixelsPerUnit(METER)*pointDefinition.getX();
		double y = scale.pixelsPerUnit(METER)*pointDefinition.getY();
		double z = scale.pixelsPerUnit(METER)*pointDefinition.getZ();
		if(index==0){
			rt.startDrawing(x, y, z);
		}else{
			rt.lineTo(x, y, z);
		}
	}
}
// 3.2: switch绘制
for(Map.Entry<String,List<TrackDefinition>> entry : switchCodeToTrackDefinitionsMap.entrySet()){
	List<TrackDefinition> trackDefinitions = entry.getValue();
	
	RailwaySwitch rs = new RailwaySwitch(this, SHAPE_DRAW_2D3D, true);
	rs.setRadius(scale.pixelsPerUnit(METER)*1);
	
	RailwayTrack[] tracks;
	if(trackDefinitions.size()>1){
		tracks = new RailwayTrack[trackDefinitions.size()];
		for(int index = 0; index<trackDefinitions.size(); index++){
			tracks[index] = trackDefinitionToRailwayTrackMap.get(trackDefinitions.get(index));
		}
	}else{
		rs.setVisible(false);
		tracks = new RailwayTrack[2];
		tracks[0] = trackDefinitionToRailwayTrackMap.get(trackDefinitions.get(0));
		String switchCode = entry.getKey();
		PointDefinition switchPointDefinition = codeToPointDefinitionMap.get(switchCode);
		
        // 额外添加轨道,自动解决后续开发轨道的路由问题
		RailwayTrack rt = new RailwayTrack();
		rt.setWidth(1, METER);
		rn.add(rt);
		
		double x = scale.pixelsPerUnit(METER)*switchPointDefinition.getX();
		double y = scale.pixelsPerUnit(METER)*switchPointDefinition.getY();
		double z = scale.pixelsPerUnit(METER)*switchPointDefinition.getZ();
		rt.startDrawing(x, y, z);
		
		PointDefinition endPointDefinition;
		if(trackDefinitions.get(0).getPointCodes().get(0).equals(switchCode)){
			endPointDefinition = codeToPointDefinitionMap.get(trackDefinitions.get(0).getPointCodes().get(1));
		}else{
			endPointDefinition = codeToPointDefinitionMap.get(trackDefinitions.get(0).getPointCodes().get(trackDefinitions.get(0).getPointCodes().size()-2));
		}
		
		double endX = scale.pixelsPerUnit(METER)*endPointDefinition.getX();
		double endY = scale.pixelsPerUnit(METER)*endPointDefinition.getY();
		double endZ = scale.pixelsPerUnit(METER)*endPointDefinition.getZ();
		rt.lineTo(2*x-endX, 2*y-endY, 2*z-endZ);
		rt.setVisible(false);
		
		tracks[1] = rt;
	}
	
	rs.setTracks(tracks);
	rs.setAllToAllType();
	rn.add(rs);	
}

// 3.3: 添加至演示
Level customLevel = new Level(this, "customLevel", SHAPE_DRAW_2D3D, 0);
customLevel.add(rn);
customLevel.initialize();
presentation.add(customLevel);

// 3.4: 解决图形覆盖问题
for(RailwaySwitch rs : rn.getSwitches()){
	presentation.remove(rs);
	presentation.insert(0,rs);
}
for(RailwayTrack track : rn.getTracks()){
	presentation.remove(track);
	presentation.insert(0,track);
}
相关推荐
雅典没有娜6 天前
QT/C++与LUA交互过程中,利用ZeroBraneStudio对LUA脚本进行仿真调试
c++·qt·lua·调试·仿真·zerobranestudio
夜间去看海15 天前
62 基于单片机的智能饮水机
单片机·嵌入式硬件·串口·仿真·智能·饮水机
夜间去看海23 天前
51-基于单片机的智能语音识别与处理系统设计
单片机·嵌入式硬件·proteus·串口·仿真·语音
FastCAE20221 个月前
【应用介绍】FastCAE-PHengLEI流体仿真
c++·mfc·仿真·流体·风雷
小孟boy2 个月前
HFSS 3D Layout中Design setting各个选项的解释
信号完整性·pcb工艺·仿真·ansys·传输线
木头人的学习生活之旅2 个月前
02-二自由度机械臂—运动学分析
matlab·机器人·仿真·solidworks·运动学·simscape
通信仿真实验室2 个月前
(51)MATLAB迫零均衡器系统建模与性能仿真
matlab·信号处理·仿真·通信系统·均衡·通信算法
即安莉2 个月前
Quartus Ⅱ仿真 2.三人表决电路
仿真
即安莉2 个月前
Quartus Ⅱ仿真 1.半加器
仿真·quartus
edadoc20132 个月前
把根留住,PCB的字符设计为什么比失恋更痛苦
云计算·智能路由器·仿真·电路板