還存在一些問題 需要不斷的優化
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();