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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值