还存在一些问题 需要不断的优化
PointList 是存储线路径的集合 也是寻路算法router的最终输出结果
如果额外考虑线与线之间的相互影响 则会进一步提高画面的显示效果
我原创的CheckPointList可以支持一些对线间关系的相互处理 注:只是针对于水平,竖直四方向的对线处理线
具体支持的机制如下:
1.支持同终点的连线如果在行进时如果靠的很近,则自动合并。
2.如果是终点不同的连线 则可以将重合的线 进行平移。
3.将直角弯进行圆弧处理,(现在的代码只是最后一个直角弯)
完整代码如下:
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
@SuppressWarnings("serial")
public class CheckedPointList2 extends PointList {
// 检测为重合的距离
private int CHECK_DISTANCE = 2;
// X方向重合 X方向偏转的距离
private int LINE_OFFSET_X = 1;
// Y方向重合和偏转距离
private int LINE_OFFSET_Y = 1;
// 机制开关
private boolean on_off = true;
// 顺路开关
private boolean on_the_way = false;
/****** shoulder *******************************************************/
// 肩膀开关
private boolean shoulder_on_off = true;
// shoulder x偏移量
private int SHOULDER_OFFSET_X = 3;
// shoulder y偏移量
private int SHOULDER_OFFSET_Y = 3;
/****** bridge *******************************************************/
// bridge 开关
private Connection conn;
// 其他的线
private List<Connection> othersConnections = new ArrayList<Connection>();
// 记录终点 为顺路提供服务 顺路开关关闭就无需关注了
private Point endPoint;
// 候选添加的点
private Point caditatePoint;
// 已经添加到List中的最后的点 这个点是可以改变的
private Point lastPoint;
public void setConn(Connection conn) {
this.conn = conn;
refreshConnections();
}
public void setOnOffMergeLine(boolean on_off_MergeLine) {
on_the_way = on_off_MergeLine;
}
public void setEndPoint(Point endPoint) {
this.endPoint = endPoint;
}
@SuppressWarnings("unchecked")
// 刷新其他线的数据
public void refreshConnections() {
othersConnections.clear();
List<Connection> allConnections = conn.getParent().getChildren();
for (int i = 0; i < allConnections.size(); i++) {
// 由于不能跟自己比较位置 所以移除自己
if (allConnections.get(i) != conn) {
othersConnections.add(allConnections.get(i));
}
}
}
// 添加候选点
public void addCandidatePoint(Point point) {
addCandidatePoint(point.x, point.y);
}
public void addCandidatePoint(int x, int y) {
caditatePoint = new Point(x, y);
// 如果这是增加的第一或者第二个点,就不用检测了
// 如果这是增加的第一条线就不用了
if (othersConnections.size() == 0 || size() < 2) {
addPoint(caditatePoint);
} else// 需要校验
{
// 取出最后一个
lastPoint = getLastPoint();
removePoint(size() - 1);
if (on_off) {
if (lastPoint.x == caditatePoint.x) {
checkCaditateX();
} else if (lastPoint.y == caditatePoint.y) {
checkCaditateY();
}
}
addCheckedPoints();
}
}
// 最后点和候选点通过了检验 添加到list中
private void addCheckedPoints() {
addPoint(lastPoint);
addPoint(caditatePoint);
}
// 检测准备添加的线的点是否和已有线重叠 X方向
private void checkCaditateX() {
// 由于线只有水平竖直两种情况 所以可以区分添加线的类型
// 遍历已有的线
for (int i = 0; i < othersConnections.size(); i++) {
Connection conn = othersConnections.get(i);
// 获取线的所有的点
PointList pointList = conn.getPoints();
// 遍历线的所有的点
// -1的原因是避免溢出 由于线是水平竖直的 所以相邻点必然是X相同,或是Y相同 我们关注的是两个点的X和检测的点的X相同
// 一个点命中无意义 所以无需检测最后一个
for (int j = 0; j < pointList.size() - 1; j++) {
// 由于只有x相同才可能存在重叠 更准确的说是两个相邻的点的x相同
if (Math.abs(pointList.getPoint(j).x - lastPoint.x) <= CHECK_DISTANCE
&& pointList.getPoint(j).x == pointList.getPoint(j + 1).x)// 这个判断是为了当线与桥重合时,不用来判断为重合
{
// 更加详细的判断
// 排序
int y1 = Math.min(pointList.getPoint(j).y, pointList.getPoint(j + 1).y);
int y2 = Math.max(pointList.getPoint(j).y, pointList.getPoint(j + 1).y);
int y3 = Math.min(lastPoint.y, caditatePoint.y);
int y4 = Math.max(lastPoint.y, caditatePoint.y);
// 竖直位置相同但不重叠
if (y1 > y4 || y2 < y3) {
break;
} else // 重叠调整位置
{
// 检测是否顺路 如果顺路就停止遍历 并且调整到已有路线的位置
if (on_the_way) {
if (endPoint.equals(pointList.getLastPoint().x, pointList.getLastPoint().y)) {
lastPoint.x = pointList.getPoint(j).x;
caditatePoint.x = pointList.getPoint(j).x;
return;
}
}
// 延续已有的方向 偏移
Point frontLastPoint = getLastPoint();
// x增大的趋势
if (frontLastPoint.x < lastPoint.x) {
// 右移
lastPoint.x += LINE_OFFSET_X;
caditatePoint.x += LINE_OFFSET_X;
} else {
// 左移
lastPoint.x -= LINE_OFFSET_X;
caditatePoint.x -= LINE_OFFSET_X;
}
// 递归检测新位置 是否有重叠
checkCaditateX();
}
}
}
}
}
// 检测准备添加的线的点是否和已有线重叠 Y方向
private void checkCaditateY() {
// 遍历已有的线
for (int i = 0; i < othersConnections.size(); i++) {
Connection conn = othersConnections.get(i);
// 判断已有的线是否存在重叠
PointList pointList = conn.getPoints();
// 遍历线的所有的点
for (int j = 0; j < pointList.size() - 1; j++) {
// 由于只有x相同才可能存在重叠 更准确的说是两个相邻的点的x相同
if (Math.abs(pointList.getPoint(j).y - lastPoint.y) <= CHECK_DISTANCE
&& pointList.getPoint(j).y == pointList.getPoint(j + 1).y) {
// 更加详细的判断
// 排序
int x1 = Math.min(pointList.getPoint(j).x, pointList.getPoint(j + 1).x);
int x2 = Math.max(pointList.getPoint(j).x, pointList.getPoint(j + 1).x);
int x3 = Math.min(lastPoint.x, caditatePoint.x);
int x4 = Math.max(lastPoint.x, caditatePoint.x);
// 竖直位置相同但不重叠
if (x1 > x4 || x2 < x3) {
break;
} else // 重叠调整位置
{
// 检测是否顺路 如果顺路就停止遍历 并且调整到已有路线的位置
if (on_the_way) {
if (endPoint.equals(pointList.getLastPoint().x, pointList.getLastPoint().y)) {
lastPoint.y = pointList.getPoint(j).y;
caditatePoint.y = pointList.getPoint(j).y;
return;
}
}
// 延续已有的方向 偏移
Point frontLastPoint = getLastPoint();
if (frontLastPoint.y < lastPoint.y) {
// 下移
lastPoint.y += LINE_OFFSET_Y;
caditatePoint.y += LINE_OFFSET_Y;
} else {
// 上移
lastPoint.y -= LINE_OFFSET_Y;
caditatePoint.y -= LINE_OFFSET_Y;
}
checkCaditateY();
}
}
}
}
}
// shoulder的意思是最后到达终点前避免直角弯 而且提供一个过渡
public void addShoulder() {
if (shoulder_on_off == false) {
return;
}
// 如果是直上直下则不用
if (size() > 2) {
// 取出后三个点 删除后两个点
int size = size();
Point frontPoint = getPoint(size - 3);
Point middlePoint = getPoint(size - 2);
Point lastPoint = getPoint(size - 1);
// 只有竖直进入的情况
if (lastPoint.x == middlePoint.x && Math.abs(frontPoint.x - middlePoint.x) >= SHOULDER_OFFSET_X) // 安全监测
{
Point middleFrontPoint = middlePoint.getCopy();
if (frontPoint.x < middlePoint.x) // "7"形状
{
// 左移动两个像素
middleFrontPoint.x = middlePoint.x - SHOULDER_OFFSET_X;
} else {
// 右移动两个像素
middleFrontPoint.x = middlePoint.x + SHOULDER_OFFSET_X;
}
// 移除原有拐点
removePoint(size - 2);
// 添加中前点
insertPoint(middleFrontPoint, size - 2);
Point middleNextPoint = middlePoint.getCopy();
middleNextPoint.y = middlePoint.y + SHOULDER_OFFSET_Y;
// 添加中后点
insertPoint(middleNextPoint, size - 1);
}
}
}
}
使用方式 和需要的基本数据
private CheckedPointList2 points = new CheckedPointList2();
@Override
public void route(Connection conn) {
// 1. prepare
startPoint = getStartPoint(conn).getCopy();
endPoint = getEndPoint(conn).getCopy();
points.removeAllPoints();
points.setConn(conn);
points.setOnOffMergeLine(on_off_MergeLine);
points.setEndPoint(endPoint);
points.addPoint(startPoint);
.....
}
添加需要进行检测的点
points.addCandidatePoint(x,y);//或 points.addCandidatePoint(new Point(x,y));
为最后直角弯添加 肩膀 发生在endPoint 已经被添加之后
points.addPoint(endPoint);
points.addShoulder();