Browse Source

连线布局逻辑优化完善

zhaoyk 3 years ago
parent
commit
2091a26b9d

+ 2 - 1
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DiagramBuilder.java

@@ -65,7 +65,7 @@ public class DiagramBuilder {
 			}
 		});
 		//记录干管中已使用的数据id
-		if(template.getMainPipes() != null) {
+		if(template != null && template.getMainPipes() != null) {
 			template.getMainPipes().forEach(mainPipe -> {
 				if(StrUtil.isNotBlank(mainPipe.getDataObjectId())) {
 					equipMap.put(mainPipe.getDataObjectId(), mainPipe);
@@ -328,6 +328,7 @@ public class DiagramBuilder {
 						line.setTo(to);
 						line.setRelType(relType);
 						line.setDataObject(rel);
+						line.setDataObjectId(rel.get("id").asText());
 
 						addLine(line);
 					}

+ 10 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DiagramDataLoader.java

@@ -7,6 +7,8 @@ import com.persagy.adm.diagram.core.model.EquipmentNode;
 import com.persagy.adm.diagram.core.model.Line;
 import com.persagy.adm.diagram.core.model.base.Container;
 import com.persagy.adm.diagram.core.model.template.MainPipe;
+import com.persagy.dmp.common.constant.ValidEnum;
+import com.persagy.dmp.digital.entity.ObjectRelation;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -99,6 +101,7 @@ public class DiagramDataLoader {
 				ObjectNode rel = relMap.get(line.getDataObjectId());
 				if(rel != null) {
 					line.setDataObject(rel);
+					line.setDataObjectId(rel.get("id").asText());
 				}
 			}
 		}
@@ -127,6 +130,7 @@ public class DiagramDataLoader {
 		//TODO 打包设备查询性能优化
 		if(equipTypes.size() > 0) {
 			optionalObjs = dataStrategy.loadObjectsByType(new ArrayList<>(equipTypes), diagram.getProjectId(), diagram.getSystemId(), diagram.getGroupCode());
+			optionalObjs = filterValid(optionalObjs);
 		} else {
 			optionalObjs = new ArrayList<>();
 		}
@@ -145,6 +149,7 @@ public class DiagramDataLoader {
 		//TODO 关系查询,需要区分打包设备
 		if(objIds.size() > 0 && relTypes.size() > 0) {
 			optionalRels = dataStrategy.loadRelationsByType(relTypes, objIds, diagram.getProjectId(), diagram.getGroupCode());
+			optionalRels = filterValid(optionalRels);
 		} else {
 			optionalRels = new ArrayList<>();
 		}
@@ -158,4 +163,9 @@ public class DiagramDataLoader {
 		builder.buildLines(optionalRels);
 	}
 
+	private List<ObjectNode> filterValid(List<ObjectNode> list){
+		return list.stream().filter(obj ->
+				obj.get(ObjectRelation.PROP_VALID) == null || obj.get(ObjectRelation.PROP_VALID).asInt() == ValidEnum.TRUE.getType()).collect(Collectors.toList());
+	}
+
 }

+ 37 - 7
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/LineLayoutManager.java

@@ -11,7 +11,9 @@ import com.persagy.adm.diagram.core.util.GeomUtil;
 import org.locationtech.jts.geom.Point;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 连线布局计算
@@ -23,6 +25,8 @@ public class LineLayoutManager {
 
 	private List<Block> blocks = new ArrayList<>();
 
+	private Map<Line, ConnectPoint[]> lines = new HashMap<>();
+
 	public LineLayoutManager(DiagramBuilder diagramBuilder) {
 		this.diagramBuilder = diagramBuilder;
 		initBlocks();
@@ -40,6 +44,9 @@ public class LineLayoutManager {
 		ConnectPoint p1 = line.getFrom();
 		ConnectPoint p2 = line.getTo();
 
+		p1.layout();
+		p2.layout();
+
 		boolean exchange = false;
 		//先计算点模型的终点
 		if(p1.getEquipmentNode() == null) {
@@ -54,9 +61,16 @@ public class LineLayoutManager {
 			exchange = true;
 		}
 
-		LineEnd[] arr = buildLineEnd(p1, p2);
-		PathBuilder pb = new PathBuilder(line, arr[0], arr[1], exchange);
-		return pb.calcPath(blocks);
+		if(checkLine(p1, p2)) {
+			lines.put(line, new ConnectPoint[]{p1, p2});
+
+			LineEnd[] arr = buildLineEnd(p1, p2);
+			PathBuilder pb = new PathBuilder(line, arr[0], arr[1], exchange);
+			return pb.calcPath(blocks);
+		} else {
+			line.setFlag(Line.FLAG_DUPLICATE);
+			return buildDuplicateMark(p1, p2);
+		}
 	}
 
 	private LineEnd[] buildLineEnd(ConnectPoint p1, ConnectPoint p2) {
@@ -115,10 +129,6 @@ public class LineLayoutManager {
 	 * 锚点出线
 	 */
 	private XY anchorEmerge(ConnectPoint point){
-		if(point.getLocation() == null) {
-			point.layout();
-		}
-
 		XY xy = new XY(point.getLocation());
 		switch (point.getAnchorCode().charAt(0)) {
 			case 'T':
@@ -138,6 +148,26 @@ public class LineLayoutManager {
 		return xy;
 	}
 
+	private boolean checkLine(ConnectPoint p1, ConnectPoint p2){
+		for(ConnectPoint[] points : lines.values()) {
+			if(p1.sameWith(points[0]) && p2.sameWith(points[1])){
+				return false;
+			}
+		}
+		return true;
+	}
+
+	private List<XY> buildDuplicateMark(ConnectPoint p1, ConnectPoint p2){
+		ArrayList<XY> markPath = new ArrayList<>();
+		markPath.add(p1.getLocation());
+		if(p2.getEquipmentNode() != null){
+			markPath.add(p2.getLocation());
+		} else {
+			markPath.add(p2.getMainPipe().getLocationPath().get(0).get(0));
+		}
+		return markPath;
+	}
+
 	public List<Block> getBlocks() {
 		return blocks;
 	}

+ 54 - 33
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/PathBuilder.java

@@ -92,7 +92,7 @@ public class PathBuilder {
         return points;
     }
 
-    private void findPath(List<Block> blocks) {
+    private boolean findPath(List<Block> blocks) {
         Block rectArea = buildRectArea();
         List<Block> currentBlocks = blocks.stream().filter(block -> block.getRect().intersects(rectArea.getRect())).collect(Collectors.toList());
 
@@ -125,16 +125,26 @@ public class PathBuilder {
                 if (Math.abs(move) <= edge) {
                     continue;
                 }
+
+                //预留边缘距离
+                if (stopPos > pos) {
+                    stopPos -= edge;
+                } else {
+                    stopPos += edge;
+                }
             }
 
             List<int[]> nonBlockRoads = getNonBlockRoads(blockLines, rectArea, vDirection);
+            if(reverse) {
+                Collections.reverse(nonBlockRoads);
+            }
             int[] nbr = findNonBlockRoad(nonBlockRoads, trackPos);
 
             if (nbr != null) {
                 //检查终点是否在同一个无阻挡通道中
                 if (checkEnd(nbr, vDirection)) {
                     connectEnd(direction, nbr, vDirection);
-                    return;
+                    return true;
                 }
             }
 
@@ -149,13 +159,16 @@ public class PathBuilder {
             boolean crossReverse = crossDirection == D_LEFT || crossDirection == D_UP;
             List<BlockLine> crossBlockLines = buildBlockLines(currentBlocks, crossDirection);
             List<int[]> crossNonBlockRoads = getNonBlockRoads(crossBlockLines, rectArea, !vDirection);
+            if(reverse) {
+                Collections.reverse(crossNonBlockRoads);
+            }
 
             //位于垂直参考方向上的无阻挡通道中
             int[] crossNbr = findNonBlockRoad(crossNonBlockRoads, pos);
             if (crossNbr != null) {
                 if (checkEnd(crossNbr, !vDirection)) {
                     connectEnd(crossDirection, crossNbr, !vDirection);
-                    return;
+                    return true;
                 }
             }
 
@@ -165,47 +178,41 @@ public class PathBuilder {
                     boolean valid = !reverse ? crossRoad[0] > pos : crossRoad[1] < pos;
                     if (valid && checkEnd(crossRoad, !vDirection)) {
                         connectEnd(direction, crossRoad, !vDirection);
-                        return;
+                        return true;
                     }
                 }
             }
             if (crossNbr != null) {
                 for (int[] road : nonBlockRoads) {
-                    boolean valid = !crossReverse ? road[0] > pos : road[1] < pos;
+                    boolean valid = !crossReverse ? road[0] > trackPos : road[1] < trackPos;
                     if (valid && checkEnd(road, vDirection)) {
                         connectEnd(crossDirection, road, vDirection);
-                        return;
+                        return true;
                     }
                 }
             }
 
-            //移动到垂直参考方向上的无阻挡通道位置
+            //移动到垂直参考方向上的第一个无阻挡通道位置
             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;
+            for (int[] crossRoad : crossNonBlockRoads) {
+                boolean flag = !reverse ? crossRoad[0] > pos : crossRoad[1] < pos;
+                if (flag) {
+                    targetPos = crossRoad[0] + (crossRoad[1] - crossRoad[0]) / 2; //TODO 调整&避免重叠
+
+                    if(stopPos != -1) {
+                        boolean valid = !reverse ? targetPos < stopPos : targetPos > stopPos;
+                        if (!valid) {
+                            targetPos = -1;
+                        }
                     }
+
+                    break;
                 }
             }
-            //垂直参考方向方向上没有通道
+            //垂直参考方向方向上没有找到通道
             if (targetPos == -1) {
-                if (stopPos != -1) {    // 移动到stopPos
-                    if (stopPos > pos) {
-                        targetPos = stopPos - edge;
-                    } else {
-                        targetPos = stopPos + edge;
-                    }
+                if (stopPos != -1) { // 移动到stopPos
+                    targetPos = stopPos;
                 } else { //移动到垂直参考方向上blockLine变化的位置
                     for (BlockLine crossBl : crossBlockLines) {
                         boolean valid = !crossReverse ? crossBl.base > trackPos : crossBl.base < targetPos;
@@ -224,10 +231,14 @@ public class PathBuilder {
                     }
                 }
             }
-            setCurrentPoint(vDirection ? new XY(trackPos, targetPos) : new XY(targetPos, trackPos));
+            moveTo(targetPos, vDirection);
             fromDirection = direction > 2 ? direction - 2 : direction + 2; //取反向
-            findPath(blocks); //递归调用路径计算
+            //递归调用路径计算
+            if(findPath(blocks)){
+                return true;
+            }
         }
+        return false;
     }
 
     private Block buildRectArea() {
@@ -514,10 +525,20 @@ public class PathBuilder {
             int[] lineScope = end2.getLineScope();
 
             if (vDirection == vEndNbr) { //当前方向与终点通道方向相同
-                if (vEndNbr == hLine) { //垂直相交
+                if (vEndNbr == hLine) { //endLine与通道垂直
                     moveTo(lineTrackPos, hLine); //线横向时做纵向移动
-                } else {
-                    //TODO 平行连接
+                } else { //endLine与通道平行
+                    //TODO 可能需要调整,避免和线水平连接
+                    int target1 = hLine ? currentPoint.x : currentPoint.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);
                 }
             } else { //当前方向与终点通道方向垂直,折线连接
                 if (vEndNbr == hLine) { //endLine与通道垂直

+ 10 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/AbstractLine.java

@@ -15,6 +15,8 @@ abstract public class AbstractLine {
 	@Expose
 	protected String name;
 
+	protected String compType;
+
 	@Expose
 	protected LineStyle lineStyle;
 
@@ -53,6 +55,14 @@ abstract public class AbstractLine {
 		this.name = name;
 	}
 
+	public String getCompType() {
+		return compType;
+	}
+
+	public void setCompType(String compType) {
+		this.compType = compType;
+	}
+
 	public LineStyle getLineStyle() {
 		return lineStyle;
 	}

+ 18 - 6
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/ConnectPoint.java

@@ -6,6 +6,8 @@ import com.persagy.adm.diagram.core.model.base.XY;
 import com.persagy.adm.diagram.core.model.legend.Anchor;
 import com.persagy.adm.diagram.core.model.template.MainPipe;
 
+import java.util.Objects;
+
 /**
  * 线和图例的连接点
  * @author zhaoyk
@@ -43,6 +45,9 @@ public class ConnectPoint {
 	@JsonIgnore
 	private XY location;
 
+	@JsonIgnore
+	private boolean layoutFlag;
+
 	/**
 	 * 连接对象,运行时
 	 */
@@ -70,15 +75,22 @@ public class ConnectPoint {
 	}
 
 	public void layout() {
-		if(hostObj instanceof EquipmentNode) {
-			EquipmentNode en = (EquipmentNode)hostObj;
-			location = en.locationToRoot();
-			XY anchorLocation = en.getAnchorLocations().get(anchorCode);
-			location.x += anchorLocation.x;
-			location.y += anchorLocation.y;
+		if(!layoutFlag) {
+			if(hostObj instanceof EquipmentNode) {
+				EquipmentNode en = (EquipmentNode)hostObj;
+				location = en.locationToRoot();
+				XY anchorLocation = en.getAnchorLocations().get(anchorCode);
+				location.x += anchorLocation.x;
+				location.y += anchorLocation.y;
+			}
+			layoutFlag = true;
 		}
 	}
 
+	public boolean sameWith(ConnectPoint other) {
+		return hostType.equals(other.hostType) && hostId.equals(other.hostId) && Objects.equals(anchorCode, other.anchorCode);
+	}
+
 	public String getHostType() {
 		return hostType;
 	}

+ 17 - 19
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/Diagram.java

@@ -111,34 +111,32 @@ public class Diagram {
 	}
 
 	public void layout(DiagramBuilder builder){
-		this.layout(builder, false);
-	}
-
-	public void layout(DiagramBuilder builder, boolean absoluteLocation){
-		template.layout(new XY(0, 0));
+		if(template != null) {
+			template.layout(new XY(0, 0));
+		}
 
 		LineLayoutManager lineLayoutManager = new LineLayoutManager(builder);
 		for(Line line : lines) {
 			line.layout(lineLayoutManager);
 		}
+	}
 
-		if(absoluteLocation) {
-			for (DiagramNode node : nodes) {
-				node.setLocation(node.locationToRoot());
-				if(node instanceof EquipmentNode) {
-					EquipmentNode en = (EquipmentNode) node;
-					if(en.getAnchorLocations() != null) {
-						for(XY point : en.getAnchorLocations().values()){
-							point.x += en.getLocation().x;
-							point.y += en.getLocation().y;
-						}
-					}
-					if(en.getLabel() != null) {
-						XY point = en.getLabel().getLocation();
+	public void toAbsoluteLocation(){
+		for (DiagramNode node : nodes) {
+			node.setLocation(node.locationToRoot());
+			if(node instanceof EquipmentNode) {
+				EquipmentNode en = (EquipmentNode) node;
+				if(en.getAnchorLocations() != null) {
+					for(XY point : en.getAnchorLocations().values()){
 						point.x += en.getLocation().x;
 						point.y += en.getLocation().y;
 					}
 				}
+				if(en.getLabel() != null) {
+					XY point = en.getLabel().getLocation();
+					point.x += en.getLocation().x;
+					point.y += en.getLocation().y;
+				}
 			}
 		}
 	}
@@ -150,7 +148,7 @@ public class Diagram {
 				ids.add(((EquipmentNode) node).getObjId());
 			}
 		}
-		if(template.getMainPipes() != null) {
+		if(template != null && template.getMainPipes() != null) {
 			for(MainPipe mainPipe : template.getMainPipes()) {
 				if(mainPipe.isBindEquipment() && StrUtil.isNotBlank(mainPipe.getDataObjectId())) {
 					ids.add(mainPipe.getDataObjectId());

+ 24 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/Line.java

@@ -12,6 +12,13 @@ import java.util.List;
  */
 public class Line extends AbstractLine {
 
+	public static final String TYPE = "line";
+
+	/**
+	 * 线标记,重复的连线
+	 */
+	public static final String FLAG_DUPLICATE = "duplicate";
+
 	/**
 	 * 连线的方向(1:from->to, 0:无方向, -1:to->from)
 	 */
@@ -53,6 +60,15 @@ public class Line extends AbstractLine {
 	 */
 	private List<XY> locationPath;
 
+	/**
+	 * 连线的状态标记
+	 */
+	private String flag;
+
+	public Line() {
+		this.compType = TYPE;
+	}
+
 	@Override
 	public void layout(Object layoutContext) {
 		LineLayoutManager layoutManager = (LineLayoutManager) layoutContext;
@@ -115,6 +131,14 @@ public class Line extends AbstractLine {
 		this.locationPath = locationPath;
 	}
 
+	public void setFlag(String flag) {
+		this.flag = flag;
+	}
+
+	public String getFlag() {
+		return flag;
+	}
+
 	public static class PassingMainPipe {
 
 		/**

+ 2 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/base/AbstractComponent.java

@@ -11,6 +11,7 @@ import java.util.Map;
  * @author zhaoyk
  */
 abstract public class AbstractComponent implements IComponent {
+
 	/**
 	 * 使用gson保存文件
 	 */
@@ -22,6 +23,7 @@ abstract public class AbstractComponent implements IComponent {
 
 	@Expose
 	protected String compType;
+
 	/**
 	 * 使用jackson输出到web端
 	 */

+ 13 - 2
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/base/Container.java

@@ -83,8 +83,19 @@ public class Container extends AbstractComponent implements IContainer {
 		for(IComponent comp : getArrangedElements()){
 			if(comp.isHidden()) {
 				if(comp instanceof Container) {
-					//给定一个位置,方便计算干管
-					comp.setLocation(new XY(p.x, p.y));
+					//给定一个位置和占位,方便计算干管
+					int hiddenSpace = 3;
+					if(row){
+						if(idx != 0) {
+							p.y += hiddenSpace;
+						}
+					} else {
+						if(idx != 0) {
+							p.x += hiddenSpace;
+						}
+					}
+
+					comp.setLocation(p.copy());
 					((Container) comp).setSize(new XY(0, 0));
 				}
 				continue;

+ 16 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/template/MainPipe.java

@@ -50,6 +50,10 @@ public class MainPipe extends AbstractLine implements IEquipHolder {
 	 */
 	private List<List<XY>> locationPath;
 
+	public MainPipe() {
+		this.compType = TYPE;
+	}
+
 	@Override
 	public String getId() {
 		return id;
@@ -157,6 +161,18 @@ public class MainPipe extends AbstractLine implements IEquipHolder {
 				if(container != null && !container.isAbsolutePosition()) {
 					ContainerRefPoint rp = ContainerRefPoint.getRefPoint(container, p.getRefPointName(), container.locationToRoot());
 					list.add(new XY(rp.getLocation().x + p.getOffset().x , rp.getLocation().y + p.getOffset().y));
+				} else {
+					//参考点丢失,给出指示线
+					if(list.size() > 0) {
+						XY mark = new XY(list.get(list.size() - 1));
+						if(mark.y != -10) {
+							mark.y = -10;
+						} else {
+							mark.x += 50;
+						}
+						list.add(mark);
+					} else
+						list.add(new XY(-10, -10));
 				}
 			}
 		}