GEF連線優化 支持額外檢測功能的存儲線路徑的PointList(合併同終點線,分離重合線)

還存在一些問題  需要不斷的優化

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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章