|
@@ -1,7 +1,572 @@
|
|
|
package com.persagy.adm.diagram.core.line;
|
|
|
|
|
|
+import cn.hutool.core.util.ArrayUtil;
|
|
|
+import com.persagy.adm.diagram.core.model.Line;
|
|
|
+import com.persagy.adm.diagram.core.model.base.XY;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 连线路径计算
|
|
|
+ */
|
|
|
public class PathBuilder {
|
|
|
|
|
|
+ private static final int D_RIGHT = 1;
|
|
|
+
|
|
|
+ private static final int D_DOWN = 2;
|
|
|
+
|
|
|
+ private static final int D_LEFT = 3;
|
|
|
+
|
|
|
+ private static final int D_UP = 4;
|
|
|
+
|
|
|
+ private static int edge = 10;
|
|
|
+
|
|
|
+ private Line line;
|
|
|
+
|
|
|
+ private LineEnd end1;
|
|
|
+
|
|
|
+ private LineEnd end2;
|
|
|
+
|
|
|
+ private boolean exchange;
|
|
|
+
|
|
|
+ private List<XY> points = new ArrayList<>();
|
|
|
+
|
|
|
+ private XY currentPoint;
|
|
|
+
|
|
|
+ private int fromDirection;
|
|
|
+
|
|
|
+ private Random random = new Random();
|
|
|
+
|
|
|
+ public PathBuilder(Line line, LineEnd end1, LineEnd end2, boolean exchange) {
|
|
|
+ this.line = line;
|
|
|
+ this.end1 = end1;
|
|
|
+ this.end2 = end2;
|
|
|
+ this.exchange = exchange;
|
|
|
+
|
|
|
+ setCurrentPoint(end1.getPoint());
|
|
|
+ String fromAnchor = (!exchange ? line.getFrom() : line.getTo()).getAnchorCode();
|
|
|
+ switch (fromAnchor.charAt(0)) {
|
|
|
+ case 'T':
|
|
|
+ fromDirection = D_DOWN;
|
|
|
+ break;
|
|
|
+ case 'B':
|
|
|
+ fromDirection = D_UP;
|
|
|
+ break;
|
|
|
+ case 'L':
|
|
|
+ fromDirection = D_RIGHT;
|
|
|
+ break;
|
|
|
+ case 'R':
|
|
|
+ fromDirection = D_LEFT;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setCurrentPoint(XY point){
|
|
|
+ currentPoint = point;
|
|
|
+ points.add(currentPoint);
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<XY> calcPath(List<Block> blocks) {
|
|
|
+ findPath(blocks);
|
|
|
+
|
|
|
+ if(exchange)
|
|
|
+ Collections.reverse(points);
|
|
|
+
|
|
|
+ if(line.getFrom().getLocation() != null) {
|
|
|
+ points.add(0, line.getFrom().getLocation());
|
|
|
+ }
|
|
|
+ if(line.getTo().getLocation() != null) {
|
|
|
+ points.add(line.getTo().getLocation());
|
|
|
+ }
|
|
|
+
|
|
|
+ return points;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void findPath(List<Block> blocks) {
|
|
|
+ Block rectArea = buildRectArea();
|
|
|
+ List<Block> currentBlocks = blocks.stream().filter(block -> block.getRect().intersects(rectArea.getRect())).collect(Collectors.toList());
|
|
|
+
|
|
|
+ int[] directions = findDirection();
|
|
|
+
|
|
|
+ for(int direction : directions) {
|
|
|
+ if(direction == fromDirection)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ boolean vDirection = isVerticalDirection(direction);
|
|
|
+ int trackPos = vDirection ? currentPoint.x : currentPoint.y;
|
|
|
+ int pos = vDirection ? currentPoint.y : currentPoint.x;
|
|
|
+ boolean reverse = direction == D_LEFT || direction == D_UP;
|
|
|
+
|
|
|
+ List<BlockLine> blockLines = buildBlockLines(currentBlocks, direction);
|
|
|
+
|
|
|
+ int stopPos = -1;
|
|
|
+ for(BlockLine bl : blockLines) {
|
|
|
+ boolean valid = !reverse ? bl.base > pos : bl.base < pos;
|
|
|
+ if(valid && bl.begin <= trackPos && bl.end >= trackPos) {
|
|
|
+ stopPos = bl.base;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(stopPos != -1) {
|
|
|
+ int move = stopPos - pos;
|
|
|
+ if(Math.abs(move) <= edge) //当前方向被阻挡
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<int[]> nonBlockRoads = getNonBlockRoads(blockLines, rectArea, vDirection);
|
|
|
+ int[] nbr = findNonBlockRoad(nonBlockRoads, trackPos);
|
|
|
+
|
|
|
+ if(nbr != null) {
|
|
|
+ //检查终点是否在同一个无阻挡通道中
|
|
|
+ if (checkEnd(nbr, vDirection)) {
|
|
|
+ connectEnd(direction, nbr, vDirection);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取垂直参考方向
|
|
|
+ int crossDirection = 0;
|
|
|
+ for (int i = 0; i < directions.length; i++) {
|
|
|
+ if(isVerticalDirection(directions[i]) != vDirection) {
|
|
|
+ crossDirection = directions[i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ boolean crossReverse = crossDirection == D_LEFT || crossDirection == D_UP;
|
|
|
+ List<BlockLine> crossBlockLines = buildBlockLines(currentBlocks, crossDirection);
|
|
|
+ List<int[]> crossNonBlockRoads = getNonBlockRoads(crossBlockLines, rectArea, !vDirection);
|
|
|
+
|
|
|
+ //位于垂直参考方向上的无阻挡通道中
|
|
|
+ int[] crossNbr = findNonBlockRoad(crossNonBlockRoads, pos);
|
|
|
+ if(crossNbr != null) {
|
|
|
+ if (checkEnd(crossNbr, !vDirection)) {
|
|
|
+ connectEnd(crossDirection, crossNbr, !vDirection);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //折线直达
|
|
|
+ if(nbr != null) {
|
|
|
+ for(int[] crossRoad : crossNonBlockRoads) {
|
|
|
+ boolean valid = !reverse ? crossRoad[0] > pos : crossRoad[1] < pos;
|
|
|
+ if(valid && checkEnd(crossRoad, !vDirection)){
|
|
|
+ connectEnd(direction, crossRoad, !vDirection);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(crossNbr != null) {
|
|
|
+ for(int[] road : nonBlockRoads) {
|
|
|
+ boolean valid = !crossReverse ? road[0] > pos : road[1] < pos;
|
|
|
+ if(valid && checkEnd(road, vDirection)){
|
|
|
+ connectEnd(crossDirection, road, vDirection);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //移动到垂直参考方向上的无阻挡通道位置
|
|
|
+ int targetPos = -1;
|
|
|
+ if(!reverse) {
|
|
|
+ for (int i = 0; i < crossNonBlockRoads.size(); i++) {
|
|
|
+ int[] crossRoad = crossNonBlockRoads.get(i);
|
|
|
+ if(crossRoad[0] > pos){
|
|
|
+ targetPos = crossRoad[0] + (crossRoad[1] - crossRoad[0]) / 2; //TODO 调整&避免重叠
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (int i = crossNonBlockRoads.size() - 1; i >= 0; i--) {
|
|
|
+ int[] crossRoad = crossNonBlockRoads.get(i);
|
|
|
+ if(crossRoad[1] < pos){
|
|
|
+ targetPos = crossRoad[0] + (crossRoad[1] - crossRoad[0]) / 2; //TODO 调整&避免重叠
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //垂直参考方向方向上没有通道
|
|
|
+ if(targetPos == -1) {
|
|
|
+ if(stopPos != -1) { // 移动到stopPos
|
|
|
+ if(stopPos > pos) {
|
|
|
+ targetPos = stopPos - edge;
|
|
|
+ } else {
|
|
|
+ targetPos = stopPos + edge;
|
|
|
+ }
|
|
|
+ } else { //移动到垂直参考方向上blockLine变化的位置
|
|
|
+ for(BlockLine crossBl : crossBlockLines) {
|
|
|
+ boolean valid = !crossReverse ? crossBl.base > trackPos : crossBl.base < targetPos;
|
|
|
+ if(valid && crossBl.begin <= pos && crossBl.end >= pos) {
|
|
|
+ if(!reverse) {
|
|
|
+ targetPos = crossBl.end;
|
|
|
+ } else {
|
|
|
+ targetPos = crossBl.begin;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(targetPos == -1)//计算失败,尝试下一方向
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ setCurrentPoint(vDirection ? new XY(trackPos, targetPos) : new XY(targetPos, trackPos));
|
|
|
+ fromDirection = direction > 2 ? direction - 2 : direction + 2; //取反向
|
|
|
+ findPath(blocks); //递归调用路径计算
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Block buildRectArea() {
|
|
|
+ int[] xs;
|
|
|
+ int[] ys;
|
|
|
+ if(end2.getPoint() != null) {
|
|
|
+ xs = new int[] {currentPoint.x, end2.getPoint().x};
|
|
|
+ ys = new int[] {currentPoint.y, end2.getPoint().y};
|
|
|
+ } else {
|
|
|
+ xs = new int[] {currentPoint.x, end2.getLine()[0].x, end2.getLine()[1].x};
|
|
|
+ ys = new int[] {currentPoint.y, end2.getLine()[0].y, end2.getLine()[1].y};
|
|
|
+ }
|
|
|
+
|
|
|
+ XY location = new XY(ArrayUtil.min(xs), ArrayUtil.min(ys));
|
|
|
+ location.x -= edge;
|
|
|
+ location.y -= edge;
|
|
|
+ XY size = new XY(ArrayUtil.max(xs) - location.x, ArrayUtil.max(ys) - location.y);
|
|
|
+ size.x += edge;
|
|
|
+ size.y += edge;
|
|
|
+
|
|
|
+ return new Block(location, size);
|
|
|
+ }
|
|
|
+
|
|
|
+ private int[] findDirection(){
|
|
|
+ int[] rtn = new int[4];
|
|
|
+
|
|
|
+ if(end2.getPoint() != null) {
|
|
|
+ XY endPoint = end2.getPoint();
|
|
|
+ if (endPoint.x == currentPoint.x) {
|
|
|
+ setDirection(rtn, null, endPoint.y > currentPoint.y);
|
|
|
+ } else if (endPoint.y == currentPoint.y) {
|
|
|
+ setDirection(rtn, endPoint.x > currentPoint.x, null);
|
|
|
+ } else {
|
|
|
+ setDirection(rtn, endPoint.x > currentPoint.x, endPoint.y > currentPoint.y);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ int trackPos = end2.getLineTrackPos();
|
|
|
+ int[] scope = end2.getLineScope();
|
|
|
+ if(end2.isLineHorizontal()) {
|
|
|
+ boolean xMatch = scope[0] <= currentPoint.x && scope[1] >= currentPoint.x;
|
|
|
+ if (xMatch) {
|
|
|
+ setDirection(rtn, null, trackPos > currentPoint.y);
|
|
|
+ } else if (trackPos == currentPoint.y) {
|
|
|
+ //需要垂直交汇
|
|
|
+ rtn[0] = D_DOWN;
|
|
|
+ rtn[1] = D_UP;
|
|
|
+
|
|
|
+ boolean right = scope[0] > currentPoint.x;
|
|
|
+ rtn[2] = right ? D_RIGHT : D_LEFT;
|
|
|
+ rtn[3] = right ? D_LEFT : D_RIGHT;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ boolean yMatch = scope[0] <= currentPoint.y && scope[0] >= currentPoint.y;
|
|
|
+ if (yMatch) {
|
|
|
+ setDirection(rtn, trackPos > currentPoint.x, null);
|
|
|
+ } else if (trackPos == currentPoint.x) {
|
|
|
+ //需要垂直交汇
|
|
|
+ rtn[0] = D_RIGHT;
|
|
|
+ rtn[1] = D_LEFT;
|
|
|
+
|
|
|
+ boolean down = scope[0] > currentPoint.y;
|
|
|
+ rtn[2] = down ? D_DOWN : D_UP;
|
|
|
+ rtn[3] = down ? D_UP : D_DOWN;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(rtn[0] == 0) {
|
|
|
+ XY p0 = end2.getLine()[0];
|
|
|
+ setDirection(rtn, p0.x > currentPoint.x, p0.y > currentPoint.y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return rtn;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setDirection(int[] directions, Boolean right, Boolean down){
|
|
|
+ if (right != null && down != null) {
|
|
|
+ directions[0] = right ? D_RIGHT : D_LEFT;
|
|
|
+ directions[1] = down ? D_DOWN : D_UP;
|
|
|
+ directions[2] = right ? D_LEFT : D_RIGHT;
|
|
|
+ directions[3] = down ? D_UP : D_DOWN;
|
|
|
+ } else if(right != null) {
|
|
|
+ directions[0] = right ? D_RIGHT : D_LEFT;
|
|
|
+ directions[1] = D_DOWN;
|
|
|
+ directions[2] = D_UP;
|
|
|
+ directions[3] = right ? D_LEFT : D_RIGHT;
|
|
|
+ } else if(down != null) {
|
|
|
+ directions[0] = down ? D_DOWN : D_UP;
|
|
|
+ directions[1] = D_RIGHT;
|
|
|
+ directions[2] = D_LEFT;
|
|
|
+ directions[3] = down ? D_UP : D_DOWN;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<BlockLine> buildBlockLines(List<Block> currentBlocks, int direction) {
|
|
|
+ List<BlockLine> blockLines = new ArrayList<>();
|
|
|
+ for(Block block : currentBlocks) {
|
|
|
+ addBlockLine(block, direction, blockLines);
|
|
|
+ }
|
|
|
+
|
|
|
+ //合并相连的blockLine
|
|
|
+ Iterator<BlockLine> iter = blockLines.iterator();
|
|
|
+ BlockLine pre = null;
|
|
|
+ while (iter.hasNext()) {
|
|
|
+ BlockLine bl = iter.next();
|
|
|
+ if(pre != null) {
|
|
|
+ if(pre.end == bl.begin && pre.base == bl.base) {
|
|
|
+ pre.end = bl.end;
|
|
|
+ iter.remove();
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pre = bl;
|
|
|
+ }
|
|
|
+
|
|
|
+ return blockLines;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addBlockLine(Block block, int direction, List<BlockLine> blockLines) {
|
|
|
+ BlockLine toHandle = new BlockLine();
|
|
|
+ XY loc = block.getLocation();
|
|
|
+ XY size = block.getSize();
|
|
|
+ switch (direction) {
|
|
|
+ case D_UP:
|
|
|
+ if(currentPoint.y <= loc.y)
|
|
|
+ return;
|
|
|
+ toHandle.base = loc.y + size.y;
|
|
|
+ toHandle.begin = loc.x;
|
|
|
+ toHandle.end = loc.x + size.x;
|
|
|
+ break;
|
|
|
+ case D_DOWN:
|
|
|
+ if(currentPoint.y >= loc.y + size.y)
|
|
|
+ return;
|
|
|
+ toHandle.base = loc.y;
|
|
|
+ toHandle.begin = loc.x;
|
|
|
+ toHandle.end = loc.x + size.x;
|
|
|
+ break;
|
|
|
+ case D_LEFT:
|
|
|
+ if(currentPoint.x <= loc.x)
|
|
|
+ return;
|
|
|
+ toHandle.base = loc.x + size.x;
|
|
|
+ toHandle.begin = loc.y;
|
|
|
+ toHandle.end = loc.y + size.y;
|
|
|
+ break;
|
|
|
+ case D_RIGHT:
|
|
|
+ if(currentPoint.x >= loc.x + size.x)
|
|
|
+ return;
|
|
|
+ toHandle.base = loc.x;
|
|
|
+ toHandle.begin = loc.y;
|
|
|
+ toHandle.end = loc.y + size.y;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //使用toHandle的端点对blockLines中线段进行切分
|
|
|
+ int pos = toHandle.begin;
|
|
|
+ for (int i = 0; i < blockLines.size(); i++) {
|
|
|
+ BlockLine item = blockLines.get(i);
|
|
|
+ if (pos > item.begin && pos < item.end) {
|
|
|
+ blockLines.add(i + 1, new BlockLine(pos, item.end, item.base));
|
|
|
+ item.end = pos;
|
|
|
+
|
|
|
+ if(pos == toHandle.begin)
|
|
|
+ pos = toHandle.end;
|
|
|
+ else
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //使用blockLines中线段端点对toHandle进行切分
|
|
|
+ LinkedList<BlockLine> nls = new LinkedList<>();
|
|
|
+ boolean finish = false;
|
|
|
+ for(BlockLine item : blockLines) {
|
|
|
+ int[] posArr = new int[] {item.begin, item.end};
|
|
|
+ for(int p : posArr) {
|
|
|
+ if(p > toHandle.begin && p < toHandle.end) {
|
|
|
+ nls.add(new BlockLine(toHandle.begin, p, toHandle.base));
|
|
|
+ toHandle.begin = p;
|
|
|
+ } else if(p > toHandle.end) {
|
|
|
+ finish = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(finish)
|
|
|
+ break;;
|
|
|
+ }
|
|
|
+ nls.add(toHandle);
|
|
|
+
|
|
|
+ //合并blockLines并设置base
|
|
|
+ for (int i = 0; i < blockLines.size(); i++) {
|
|
|
+ if(nls.size() == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ BlockLine item = blockLines.get(i);
|
|
|
+ BlockLine nl = nls.getFirst();
|
|
|
+ if(nl.begin < item.begin){ //插入
|
|
|
+ blockLines.add(i, nl);
|
|
|
+
|
|
|
+ nls.removeFirst();
|
|
|
+ } else if(nl.begin == item.begin) { //重合
|
|
|
+ item.base = (direction == D_UP || direction == D_LEFT) ? Math.max(nl.base, item.base) : Math.min(nl.base, item.base);
|
|
|
+
|
|
|
+ nls.removeFirst();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(nls.size() > 0) {
|
|
|
+ blockLines.addAll(nls);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<int[]> getNonBlockRoads(List<BlockLine> blockLines, Block rectArea, boolean vDirection){
|
|
|
+ int from, to;
|
|
|
+ if(vDirection) {
|
|
|
+ from = rectArea.getLocation().x;
|
|
|
+ to = rectArea.getLocation().x + rectArea.getSize().x;
|
|
|
+ } else {
|
|
|
+ from = rectArea.getLocation().y;
|
|
|
+ to = rectArea.getLocation().y + rectArea.getSize().y;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<int[]> list = new ArrayList<>();
|
|
|
+ int tmp = from;
|
|
|
+ for(BlockLine bl : blockLines) {
|
|
|
+ if(tmp < bl.begin)
|
|
|
+ list.add(new int[]{tmp, bl.begin});
|
|
|
+ tmp = bl.end;
|
|
|
+ }
|
|
|
+ if(tmp < to)
|
|
|
+ list.add(new int[]{tmp, to});
|
|
|
+
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int[] findNonBlockRoad(List<int[]> nonBlockRoads, int pos) {
|
|
|
+ for(int[] road : nonBlockRoads) {
|
|
|
+ if(road[0] <= pos && road[1] >= pos) {
|
|
|
+ return road;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查终点是否在某个无阻挡通道上
|
|
|
+ */
|
|
|
+ private boolean checkEnd(int[] nonBlockRoad, boolean vDirection){
|
|
|
+ if(end2.getPoint() != null) {
|
|
|
+ int pos = vDirection ? end2.getPoint().x : end2.getPoint().y;
|
|
|
+ return nonBlockRoad[0] <= pos && nonBlockRoad[1] >= pos;
|
|
|
+ } else {
|
|
|
+ boolean hLine = end2.isLineHorizontal();
|
|
|
+ if(hLine == vDirection) { //垂直
|
|
|
+ int[] scope = end2.getLineScope();
|
|
|
+ boolean notJoin = scope[0] > nonBlockRoad[1] || nonBlockRoad[0] > scope[1];
|
|
|
+ return !notJoin;
|
|
|
+ } else { //平行
|
|
|
+ int trackPos = end2.getLineTrackPos();
|
|
|
+ return nonBlockRoad[0] <= trackPos && nonBlockRoad[1] >= trackPos;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void connectEnd(int direction, int[] endNbr, boolean vEndNbr) {
|
|
|
+ boolean vDirection = isVerticalDirection(direction);
|
|
|
+ if(end2.getPoint() != null) {
|
|
|
+ XY endPoint = end2.getPoint();
|
|
|
+ if(currentPoint.x != endPoint.x && currentPoint.y != endPoint.y) {
|
|
|
+ moveTo(vDirection ? endPoint.y : endPoint.x, vDirection);
|
|
|
+ }
|
|
|
+ points.add(endPoint);
|
|
|
+ } else {
|
|
|
+ //XY[] line = end2.getLine();
|
|
|
+ boolean hLine = end2.isLineHorizontal();
|
|
|
+ int lineTrackPos = end2.getLineTrackPos();
|
|
|
+ int[] lineScope = end2.getLineScope();
|
|
|
+
|
|
|
+ if(vDirection == vEndNbr) { //当前方向与终点通道方向相同
|
|
|
+ if(vEndNbr == hLine) { //垂直相交
|
|
|
+ moveTo(lineTrackPos, hLine); //线横向时做纵向移动
|
|
|
+ } else {
|
|
|
+ //TODO 平行连接
|
|
|
+ }
|
|
|
+ } else { //当前方向与终点通道方向垂直,折线连接
|
|
|
+ if(vEndNbr == hLine) { //endLine与通道垂直
|
|
|
+ int[] targetScope = new int[] {Math.max(lineScope[0], endNbr[0]), Math.min(lineScope[1], endNbr[1])};
|
|
|
+ int safeOffset = 5;//临时避免和节点边线重合
|
|
|
+ int target0 = targetScope[0] + safeOffset + random.nextInt(targetScope[1] - targetScope[0] - safeOffset * 2); //TODO 调整&避免重叠
|
|
|
+ moveTo(target0, vDirection);
|
|
|
+ moveTo(lineTrackPos, hLine);
|
|
|
+ } else { //endLine与通道平行
|
|
|
+ //TODO 调整&避免重叠
|
|
|
+ int target0;
|
|
|
+ if(endNbr[1] - lineTrackPos > lineTrackPos - endNbr[0]) {
|
|
|
+ target0 = lineTrackPos + LineEnd.offset;
|
|
|
+ } else {
|
|
|
+ target0 = lineTrackPos - LineEnd.offset;
|
|
|
+ }
|
|
|
+ if(target0 > endNbr[1]){
|
|
|
+ target0 = endNbr[1];
|
|
|
+ } else if(target0 < endNbr[0]) {
|
|
|
+ target0 = endNbr[0];
|
|
|
+ }
|
|
|
+ XY point0 = moveTo(target0, vDirection);
|
|
|
+
|
|
|
+ int target1 = hLine ? point0.x : point0.y;
|
|
|
+ int offset = random.nextInt((lineScope[1] - lineScope[0]) / 2);
|
|
|
+ if(Math.abs(lineScope[0] - target1) < Math.abs((lineScope[1] - target1))){
|
|
|
+ target1 = lineScope[0] + offset;
|
|
|
+ } else {
|
|
|
+ target1 = lineScope[1] - offset;
|
|
|
+ }
|
|
|
+ moveTo(target1, !vDirection);
|
|
|
+
|
|
|
+ moveTo(lineTrackPos, vDirection);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private XY moveTo(int targetPos, boolean vDirection) {
|
|
|
+ XY point = new XY(currentPoint);
|
|
|
+ if(vDirection)
|
|
|
+ point.y = targetPos;
|
|
|
+ else
|
|
|
+ point.x = targetPos;
|
|
|
+
|
|
|
+ //TODO 连线检查,处理重叠等
|
|
|
+
|
|
|
+ setCurrentPoint(point);
|
|
|
+ return point;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isVerticalDirection(int direction) {
|
|
|
+ return direction == D_DOWN || direction == D_UP;
|
|
|
+ }
|
|
|
+
|
|
|
+ class BlockLine {
|
|
|
+
|
|
|
+ BlockLine(){
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ BlockLine(int begin, int end, int base) {
|
|
|
+ this.begin = begin;
|
|
|
+ this.end = end;
|
|
|
+ this.base = base;
|
|
|
+ }
|
|
|
+
|
|
|
+ int begin;
|
|
|
+
|
|
|
+ int end;
|
|
|
+
|
|
|
+ int base;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
}
|