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);
}