|  |  | 
 |  |  | package com.zt.life.modules.mainPart.taskReliability.service; | 
 |  |  |  | 
 |  |  | import cn.hutool.core.convert.Convert; | 
 |  |  | import cn.hutool.json.JSONArray; | 
 |  |  | import cn.hutool.json.JSONObject; | 
 |  |  | import com.zt.common.service.BaseService; | 
 |  |  | 
 |  |  | import com.zt.life.modules.mainPart.basicInfo.dao.XhProductModelDao; | 
 |  |  | import com.zt.life.modules.mainPart.basicInfo.model.ProductImg; | 
 |  |  | import com.zt.life.modules.mainPart.taskReliability.dao.*; | 
 |  |  | import com.zt.life.modules.mainPart.taskReliability.dto.ModelLinePairDto; | 
 |  |  | import com.zt.life.modules.mainPart.taskReliability.model.*; | 
 |  |  | import org.apache.commons.lang3.StringUtils; | 
 |  |  | import org.slf4j.Logger; | 
 |  |  | 
 |  |  |     public static final String OPE_TYPE_SWITCH = "switch"; | 
 |  |  |     public static final String OPE_TYPE_VOTE = "vote"; | 
 |  |  |     public static final String OPE_TYPE_BRIDGE = "bridge"; | 
 |  |  |  | 
 |  |  |     // 节点 | 
 |  |  |     /* 自动布局:start与end的大小 */ | 
 |  |  |     public static final int LAYOUT_START_END_SIZE_X = 60; | 
 |  |  |     public static final int LAYOUT_START_END_SIZE_Y = 40; | 
 |  |  |     /* 自动布局:虚框的大小 */ | 
 |  |  |     public static final int LAYOUT_DASHED_BOX_SIZE_X = 60; | 
 |  |  |     public static final int LAYOUT_DASHED_BOX_SIZE_Y = 40; | 
 |  |  |     /* 自动布局:逻辑运算符的大小 */ | 
 |  |  |     public static final int LAYOUT_OPE_NODE_SIZE_X = 50; | 
 |  |  |     public static final int LAYOUT_OPE_NODE_SIZE_Y = 50; | 
 |  |  |     /* 自动布局:设备节点的大小 */ | 
 |  |  |     public static final int LAYOUT_DEVICE_NODE_SIZE_X = 60; | 
 |  |  |     public static final int LAYOUT_DEVICE_NODE_SIZE_Y = 60; | 
 |  |  |     /* 自动布局:connect的大小 */ | 
 |  |  |     public static final int LAYOUT_CONNECT_SIZE_X = 10; | 
 |  |  |     public static final int LAYOUT_CONNECT_SIZE_Y = 10; | 
 |  |  |  | 
 |  |  |     // 单元格(存放节点) | 
 |  |  |     /* 自动布局:单元格大小 */ | 
 |  |  |     public static final int LAYOUT_CELL_SIZE_X = 120; | 
 |  |  |     public static final int LAYOUT_CELL_SIZE_Y = 120; | 
 |  |  |     /* 自动布局:节点占据单元格数量 */ | 
 |  |  |     public static final int LAYOUT_CELL_NUM_NODE_X = 1; | 
 |  |  |     public static final int LAYOUT_CELL_NUM_NODE_Y = 1; | 
 |  |  |     public static final int LAYOUT_CELL_NUM_CONNECT_X = 1; | 
 |  |  |     public static final int LAYOUT_CELL_NUM_CONNECT_Y = 1; | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     private ModelLineDao modelLineDao; | 
 |  |  | 
 |  |  |  | 
 |  |  |         // 1. 解析出节点与边 | 
 |  |  |         getNodeAndLineFromRbd(modelRbd.getId(), rbdJsonArray, modelNodeList, modelLineList, productImgList); | 
 |  |  |  | 
 |  |  |         // 2. 转换为树型结构 | 
 |  |  |         RbdTreeNode root = recognizeRbd(modelNodeList, modelLineList); | 
 |  |  |         // 3. 递归计算RBD的布局空间大小 | 
 |  |  |         // 3. 将桥联转换为3支路的并联 | 
 |  |  |         convertBridgeToThreeBranchParallel(root); | 
 |  |  |         // 4. 递归计算RBD的布局空间大小 | 
 |  |  |         calcLayoutSize(root); | 
 |  |  |  | 
 |  |  |         // 4. 递归计算RBD的布局空间参数(x、y坐标) | 
 |  |  |         // 5. 递归计算RBD的布局空间参数(x、y坐标) | 
 |  |  |         root.setBlockX(0); | 
 |  |  |         root.setBlockY(0); | 
 |  |  |         Map<String, RbdTreeNode> nodeMap = new HashMap<>(); | 
 |  |  |         calcPosition(rbdJsonArray, root, nodeMap, false); | 
 |  |  |         setEdgeRouter(rbdJsonArray, nodeMap); | 
 |  |  |  | 
 |  |  |         // 5. 保存自动布局模型 | 
 |  |  |         // 6. 保存自动布局模型 | 
 |  |  |         JSONObject jsonObject = new JSONObject(); | 
 |  |  |         jsonObject.put("cells", rbdJsonArray); | 
 |  |  |         modelRbd.setContent(jsonObject.toString()); | 
 |  |  |         modelRbdDao.updateById(modelRbd); | 
 |  |  |  | 
 |  |  |         return result; | 
 |  |  | /* | 
 |  |  |         // 3. 复制产品节点(node)到list | 
 |  |  |         List<ModelNode> modelNodeAndVnodeList = modelNodeList.stream().filter(item -> | 
 |  |  |                 "node".equals(item.getNodeType())).collect(Collectors.toList()); | 
 |  |  |         // 4. 不断将基本模型(串联、并联、旁联、表决、桥联)替换为虚节点而简化图形,直至无法简化为止。 | 
 |  |  | //        result = getAlgorithmFromRbd(modelRbd, modelNodeList, modelLineList, algorithmList, modelNodeAndVnodeList); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |         // 6. 递归计算RBD的布局空间大小 | 
 |  |  |         calcLayoutSize(modelRbd, algorithmList, modelNodeAndVnodeList); | 
 |  |  |         Collections.reverse(algorithmList); | 
 |  |  |         RbdTreeNode root2 = listToTree(algorithmList.get(0).getComputerList(), algorithmList, modelNodeAndVnodeList); | 
 |  |  |     private void calcPosition(JSONArray rbdJsonArray, RbdTreeNode block, Map<String, RbdTreeNode> nodeMap, Boolean lastIsSeries) { | 
 |  |  |         if ("node,start,end,connect,parallel,switch,vote,bridge".contains(block.getNodeType())) { | 
 |  |  |             setNodePositionXY(rbdJsonArray, block, nodeMap); | 
 |  |  |         } else { | 
 |  |  |  | 
 |  |  |         RbdTreeNode root = new RbdTreeNode(); | 
 |  |  |             Double descentWidth = block.getDescentWidth(); | 
 |  |  |             if (descentWidth == null || descentWidth == 0.0) { | 
 |  |  |                 descentWidth = block.getBlockWidth(); | 
 |  |  |             } | 
 |  |  |             Double descentHeight = block.getDescentHeight(); | 
 |  |  |             if (descentHeight == null || descentHeight == 0.0) { | 
 |  |  |                 descentHeight = block.getBlockHeight(); | 
 |  |  |             } | 
 |  |  |             List<RbdTreeNode> children = block.getChildren(); | 
 |  |  |             if (OPE_TYPE_SERIES.equals(block.getAlgorithmType())) { | 
 |  |  |                 Double subBlockX = block.getBlockX(); | 
 |  |  |                 for (RbdTreeNode child : children) { | 
 |  |  |  | 
 |  |  |         root.setId(Convert.toLong("20000")); | 
 |  |  |                     double selfBlockWidth = child.getBlockWidth() * descentWidth / block.getBlockWidth(); | 
 |  |  |                     child.setDescentWidth(selfBlockWidth); | 
 |  |  |                     child.setBlockWidth(selfBlockWidth); | 
 |  |  |                     if (lastIsSeries) | 
 |  |  |                         child.setDescentHeight(descentHeight); | 
 |  |  |                     else | 
 |  |  |                         child.setDescentHeight(block.getBlockHeight()); | 
 |  |  |  | 
 |  |  |         root.setName("end"); | 
 |  |  |         root.setNodeType("vnode"); | 
 |  |  |         root.setAlgorithmType("parallel"); | 
 |  |  |         root.setPicId("20000"); | 
 |  |  |         root.setPairStartNodeId("10000"); | 
 |  |  |                     child.setBlockHeight(block.getBlockHeight() ); | 
 |  |  |                     child.setBlockY(block.getBlockY()); | 
 |  |  |                     child.setBlockX(subBlockX); | 
 |  |  |                     calcPosition(rbdJsonArray, child, nodeMap,true); | 
 |  |  |                     subBlockX = subBlockX + selfBlockWidth; | 
 |  |  |                 } | 
 |  |  |             } else { | 
 |  |  |                 Double subBlockY = block.getBlockY() + (descentHeight - block.getObjectHeight())/ 2; | 
 |  |  |                 for (RbdTreeNode child : children) { | 
 |  |  |                     child.setDescentWidth(block.getBlockWidth()); | 
 |  |  |                     child.setDescentHeight(block.getBlockHeight()); | 
 |  |  |  | 
 |  |  |         root.setBlockWidthNum(root2.getBlockWidthNum() + 2); | 
 |  |  |         root.setBlockHeightNum(root2.getBlockHeightNum()); | 
 |  |  |         root.getChildren().add(root2); | 
 |  |  |                     if (!"vnode".equals(child.getNodeType())) { | 
 |  |  |                         child.setBlockWidth(block.getBlockWidth()); | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |         // 7. 递归计算RBD的布局空间参数(x、y坐标) | 
 |  |  |         root.setBlockX(0); | 
 |  |  |         root.setBlockY(0); | 
 |  |  |                     child.setBlockX(block.getBlockX()); | 
 |  |  |                     child.setBlockY(subBlockY); | 
 |  |  |                     calcPosition(rbdJsonArray, child, nodeMap, false); | 
 |  |  |                     subBlockY = subBlockY + child.getBlockHeight(); | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |         Map<String, RbdTreeNode> nodeMap = new HashMap<>(); | 
 |  |  |         calcPosition(rbdJsonArray, root, nodeMap); | 
 |  |  |         setEdgeRouter(rbdJsonArray, nodeMap); | 
 |  |  |     private void setNodePositionXY(JSONArray rbdJsonArray, RbdTreeNode block, Map<String, RbdTreeNode> nodeMap) { | 
 |  |  |         Double x = block.getBlockX() + (block.getBlockWidth() - block.getObjectWidth()) / 2; | 
 |  |  |         Double y = block.getBlockY() + (block.getBlockHeight() - block.getObjectHeight()) / 2; | 
 |  |  |         block.setX(x); | 
 |  |  |         block.setY(y); | 
 |  |  |         nodeMap.put(block.getPicId(), block); | 
 |  |  |         setRbdNodePosition(rbdJsonArray, block.getPicId(), x, y); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |         JSONObject jsonObject = new JSONObject(); | 
 |  |  |         jsonObject.put("cells", rbdJsonArray); | 
 |  |  |         modelRbd.setContent(jsonObject.toString()); | 
 |  |  |         //        calcLayoutPosition(modelRbd, algorithmList, modelNodeAndVnodeList); | 
 |  |  |     private void setRbdNodePosition(JSONArray rbdJsonArray, | 
 |  |  |                                     String id, | 
 |  |  |                                     double x, | 
 |  |  |                                     double y) { | 
 |  |  |         for (int i = 0; i < rbdJsonArray.size(); i++) { | 
 |  |  |             JSONObject jsonObject = rbdJsonArray.getJSONObject(i); | 
 |  |  |             if (id.equals(jsonObject.get("id").toString())) { | 
 |  |  |                 JsonUtils2.setJsonValueByPath(jsonObject, "position/x".split("/"), x); | 
 |  |  |                 JsonUtils2.setJsonValueByPath(jsonObject, "position/y".split("/"), y); | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |         // 8. 保存自动布局模型 | 
 |  |  |         // 更新RBD数据 | 
 |  |  | //        modelRbd.setAutoLayoutContent("测试文字"); | 
 |  |  | //        modelRbdDao.updateById(modelRbd); | 
 |  |  | */ | 
 |  |  |     private void setEdgeRouter(JSONArray rbdJsonArray, Map<String, RbdTreeNode> nodeMap) { | 
 |  |  |         for (int i = 0; i < rbdJsonArray.size(); i++ | 
 |  |  |         ) { | 
 |  |  |             JSONObject jsonObject = rbdJsonArray.getJSONObject(i); | 
 |  |  |             if (jsonObject.get("shape").equals("edge")) { | 
 |  |  |                 String sourceId = JsonUtils2.getJsonValueByPath(jsonObject, "source/cell".split("/")).toString(); | 
 |  |  |                 String targetId = JsonUtils2.getJsonValueByPath(jsonObject, "target/cell".split("/")).toString(); | 
 |  |  |                 RbdTreeNode sourceNode = nodeMap.get(sourceId); | 
 |  |  |                 RbdTreeNode targetNode = nodeMap.get(targetId); | 
 |  |  |                 if (sourceNode != null) { | 
 |  |  |                     if ("connect".equals(sourceNode.getNodeType()) && !"10000".equals(sourceId)) { | 
 |  |  |                         if (sourceNode.getY() + sourceNode.getObjectHeight() / 2 == targetNode.getY() + targetNode.getObjectHeight() / 2) { | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"), "right".split(",")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"), "left".split(",")); | 
 |  |  |                         } else { | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"), "top,bottom".split(",")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"), "left".split(",")); | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |                 if (targetNode != null) { | 
 |  |  |                     if ("parallel,vote,switch,bridge".contains(targetNode.getNodeType())) { | 
 |  |  |                         if (sourceNode.getY() + sourceNode.getObjectHeight() / 2 == targetNode.getY() + targetNode.getObjectHeight() / 2) { | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"), "right".split("")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"), "left".split("")); | 
 |  |  |                         } else { | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"), "right".split("")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"), "top,bottom".split("")); | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void calcLayoutSize(RbdTreeNode root) { | 
 |  |  |         double childrenWidth = 0.0; | 
 |  |  |         double childrenHeight = 0.0; | 
 |  |  |         double lineWidth = 120; | 
 |  |  |         double lineHeight = 90; | 
 |  |  |         if (!"vnode".equals(root.getNodeType())) { | 
 |  |  |             root.setBlockWidth(root.getObjectWidth() + lineWidth); | 
 |  |  |             root.setBlockHeight(root.getObjectHeight() + lineHeight); | 
 |  |  |         } else { | 
 |  |  |             for (RbdTreeNode treeNode : root.getChildren()) { | 
 |  |  |                 calcLayoutSize(treeNode); | 
 |  |  |                 if ("series".equals(root.getAlgorithmType())) { | 
 |  |  |                     childrenWidth += treeNode.getBlockWidth(); | 
 |  |  |                     childrenHeight = Math.max(childrenHeight, treeNode.getBlockHeight()); | 
 |  |  |                 } else if ("parallel,switch,vote".contains(root.getAlgorithmType())) { | 
 |  |  |                     childrenWidth = Math.max(childrenWidth, treeNode.getBlockWidth()); | 
 |  |  |                     childrenHeight += treeNode.getBlockHeight(); | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |             if ("bridge".equals(root.getAlgorithmType())) { | 
 |  |  |                 childrenWidth = Math.max(root.getChildren().get(0).getBlockWidth() + root.getChildren().get(1).getBlockWidth(), | 
 |  |  |                         root.getChildren().get(2).getBlockWidth()); | 
 |  |  |                 childrenWidth = Math.max(root.getChildren().get(3).getBlockWidth() + root.getChildren().get(4).getBlockWidth(), | 
 |  |  |                         childrenWidth); | 
 |  |  |                 childrenHeight += Math.max(root.getChildren().get(0).getBlockHeight(), root.getChildren().get(1).getBlockHeight()); | 
 |  |  |                 childrenHeight += root.getChildren().get(2).getBlockHeight(); | 
 |  |  |                 childrenHeight += Math.max(root.getChildren().get(3).getBlockHeight(), root.getChildren().get(4).getBlockHeight()); | 
 |  |  |             } | 
 |  |  |             root.setObjectWidth(childrenWidth); | 
 |  |  |             root.setObjectHeight(childrenHeight); | 
 |  |  |             root.setBlockWidth(childrenWidth); | 
 |  |  |             root.setBlockHeight(childrenHeight); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void getNodeAndLineFromRbd(Long modelId, | 
 |  |  | 
 |  |  |                     String productType = JsonUtils2.getJsonValueByPath(jsonObject, "data/productType".split("/")).toString(); | 
 |  |  |                     productImg.setProductType(productType); | 
 |  |  |                     if ("product_sb".equals(productType)) { | 
 |  |  |                         jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/deviceNo".split("/")); | 
 |  |  |                         if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) { | 
 |  |  |                             modelNode.setDeviceNo(Integer.valueOf(jsonValue.toString())); | 
 |  |  |                         } else { | 
 |  |  |                             modelNode.setDeviceNo(0); | 
 |  |  |                         } | 
 |  |  |                         jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/reliabDistribType".split("/")); | 
 |  |  |                         if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) { | 
 |  |  |                             productImg.setReliabDistribType(Integer.valueOf(jsonValue.toString())); | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private RbdTreeNode recognizeRbd(List<ModelNode> modelNodeList, | 
 |  |  |                               List<ModelLine> modelLineList) { | 
 |  |  |                                      List<ModelLine> modelLineList) { | 
 |  |  |         Map<String, Integer> vnodeCounter = new HashMap<>(); | 
 |  |  |         vnodeCounter.put("vnodeCounter", 0); | 
 |  |  |         RbdTreeNode root = new RbdTreeNode(); | 
 |  |  | 
 |  |  |         endNode.setNodeType("end"); | 
 |  |  |         endNode.setPicId(end.getPicId()); | 
 |  |  |         endNode.setPairStartNodeId(end.getPairStartNodeId()); | 
 |  |  |         endNode.setMyWidth(end.getWidth()); | 
 |  |  |         endNode.setMyHeight(end.getHeight()); | 
 |  |  |         endNode.setObjectWidth(end.getWidth()); | 
 |  |  |         endNode.setObjectHeight(end.getHeight()); | 
 |  |  |         root.getChildren().add(endNode); | 
 |  |  |         ModelLine lineRight = modelLineList.stream().filter(item -> | 
 |  |  |                 item.getEndCell().equals(end.getPicId())).collect(Collectors.toList()).get(0); | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void recognizeOneBranch(RbdTreeNode parent, | 
 |  |  |                                  ModelLine lineRight, // 串联的起始线(右边) | 
 |  |  |                                  ModelLine lineLeft, // 串联的结束线(左边) | 
 |  |  |                                  List<ModelNode> modelNodeList, | 
 |  |  |                                  List<ModelLine> modelLineList, | 
 |  |  |                                  Map<String, Integer> vnodeCounter) { | 
 |  |  |                                     ModelLine lineRight, // 串联的起始线(右边) | 
 |  |  |                                     ModelLine lineLeft, // 串联的结束线(左边) | 
 |  |  |                                     List<ModelNode> modelNodeList, | 
 |  |  |                                     List<ModelLine> modelLineList, | 
 |  |  |                                     Map<String, Integer> vnodeCounter) { | 
 |  |  |         ModelLine inLine = lineRight; | 
 |  |  |         for (;;) { | 
 |  |  |         for (; ; ) { | 
 |  |  |             ModelLine searchLine = inLine; | 
 |  |  |             ModelNode node = modelNodeList.stream().filter(item -> | 
 |  |  |                     searchLine.getBeginCell().equals(item.getPicId())).collect(Collectors.toList()).get(0); | 
 |  |  | 
 |  |  |                 treeNode.setNodeType(node.getNodeType()); | 
 |  |  |                 treeNode.setPicId(node.getPicId()); | 
 |  |  |                 treeNode.setDataId(node.getDataId()); | 
 |  |  |                 treeNode.setMyWidth(node.getWidth()); | 
 |  |  |                 treeNode.setMyHeight(node.getHeight()); | 
 |  |  |                 treeNode.setDeviceNo(node.getDeviceNo()); | 
 |  |  |                 treeNode.setObjectWidth(node.getWidth()); | 
 |  |  |                 treeNode.setObjectHeight(node.getHeight()); | 
 |  |  |                 parent.getChildren().add(treeNode); | 
 |  |  |                 inLine = modelLineList.stream().filter(item -> | 
 |  |  |                         item.getEndCell().equals(node.getPicId())).collect(Collectors.toList()).get(0); | 
 |  |  | 
 |  |  |                 treeNode.setName(node.getNodeType()); | 
 |  |  |                 treeNode.setNodeType(node.getNodeType()); | 
 |  |  |                 treeNode.setPicId(node.getPicId()); | 
 |  |  |                 treeNode.setMyWidth(node.getWidth()); | 
 |  |  |                 treeNode.setMyHeight(node.getHeight()); | 
 |  |  |                 treeNode.setObjectWidth(node.getWidth()); | 
 |  |  |                 treeNode.setObjectHeight(node.getHeight()); | 
 |  |  |                 parent.getChildren().add(treeNode); | 
 |  |  |                 break; | 
 |  |  |             } else if ("connect".equals(node.getNodeType())) { | 
 |  |  | 
 |  |  |                 treeNode.setName(connect.getNodeType()); | 
 |  |  |                 treeNode.setNodeType(connect.getNodeType()); | 
 |  |  |                 treeNode.setPicId(connect.getPicId()); | 
 |  |  |                 treeNode.setMyWidth(connect.getWidth()); | 
 |  |  |                 treeNode.setMyHeight(connect.getHeight()); | 
 |  |  |                 treeNode.setObjectWidth(connect.getWidth()); | 
 |  |  |                 treeNode.setObjectHeight(connect.getHeight()); | 
 |  |  |                 subNode.getChildren().add(treeNode); | 
 |  |  |                 RbdTreeNode subNodeOpe = new RbdTreeNode(); | 
 |  |  |                 subNodeOpe.setAlgorithmType(node.getNodeType()); | 
 |  |  | 
 |  |  |                 treeNode.setNodeType(node.getNodeType()); | 
 |  |  |                 treeNode.setPicId(node.getPicId()); | 
 |  |  |                 treeNode.setPairStartNodeId(node.getPairStartNodeId()); | 
 |  |  |                 treeNode.setMyWidth(node.getWidth()); | 
 |  |  |                 treeNode.setMyHeight(node.getHeight()); | 
 |  |  |                 treeNode.setObjectWidth(node.getWidth()); | 
 |  |  |                 treeNode.setObjectHeight(node.getHeight()); | 
 |  |  |                 subNode.getChildren().add(treeNode); | 
 |  |  |                 recognizeOpeBlock(subNodeOpe, | 
 |  |  |                         node, | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void recognizeOpeBlock(RbdTreeNode parent, | 
 |  |  |                                         ModelNode rightNode, // rbd中的右节点(包括end及4种运算符) | 
 |  |  |                                         List<ModelNode> modelNodeList, | 
 |  |  |                                         List<ModelLine> modelLineList, | 
 |  |  |                                         Map<String, Integer> vnodeCounter) { | 
 |  |  |                                    ModelNode rightNode, // rbd中的右节点(包括end及4种运算符) | 
 |  |  |                                    List<ModelNode> modelNodeList, | 
 |  |  |                                    List<ModelLine> modelLineList, | 
 |  |  |                                    Map<String, Integer> vnodeCounter) { | 
 |  |  |         if ("parallel,vote,switch".contains(parent.getAlgorithmType())) { | 
 |  |  |             ModelNode searchNode = rightNode; | 
 |  |  |             List<ModelLine> lines = modelLineList.stream().filter(item -> | 
 |  |  | 
 |  |  |                     parent.getChildren().add(subNode); | 
 |  |  |                     recognizeOneBranch(subNode, line, null, modelNodeList, modelLineList, vnodeCounter); | 
 |  |  |                 } else { | 
 |  |  |                     recognizeOneBranch(parent, line,null, modelNodeList, modelLineList, vnodeCounter); | 
 |  |  |                     recognizeOneBranch(parent, line, null, modelNodeList, modelLineList, vnodeCounter); | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } else if ("bridge".contains(parent.getAlgorithmType())) { | 
 |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 按自上而下的顺序排序 | 
 |  |  |       */ | 
 |  |  |      */ | 
 |  |  |     private List<ModelLine> sortLine(List<ModelLine> lines, | 
 |  |  |                                      List<ModelNode> modelNodeList) { | 
 |  |  |         for (ModelLine line : lines) { | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void createAlgorithm(Long modelId, | 
 |  |  |                                     RbdTreeNode root, | 
 |  |  |                                     List<Algorithm> algorithmList, | 
 |  |  |                                     List<ModelNode> modelNodeAndVnodeList) { | 
 |  |  |                                  RbdTreeNode root, | 
 |  |  |                                  List<Algorithm> algorithmList, | 
 |  |  |                                  List<ModelNode> modelNodeAndVnodeList) { | 
 |  |  |         List<RbdTreeNode> children = root.getChildren(); | 
 |  |  |         if (children.size() == 0) { | 
 |  |  |             ModelNode node = new ModelNode(); | 
 |  |  | 
 |  |  |             node.setId(root.getId()); | 
 |  |  |             node.setPicId(root.getPicId()); | 
 |  |  |             node.setDataId(root.getDataId()); | 
 |  |  |             node.setDeviceNo(root.getDeviceNo()); | 
 |  |  |             node.setNodeType(root.getNodeType()); | 
 |  |  |             node.setName(root.getName()); | 
 |  |  |             node.setVoteNum(root.getVoteNum()); | 
 |  |  | 
 |  |  |      * 对树形结构进行预处理,包括: | 
 |  |  |      * 1)将root的algorithmType替换为end,并去掉start和end节点 | 
 |  |  |      * 2)start与end间只有1个逻辑运算块,则去掉最外层的series | 
 |  |  |      * | 
 |  |  |      * @param root | 
 |  |  |      */ | 
 |  |  |     private void deleteStartEnd(RbdTreeNode root) { | 
 |  |  |         root.setAlgorithmType("end"); | 
 |  |  |         List<RbdTreeNode> children = root.getChildren(); | 
 |  |  |         children.remove(children.size()-1); | 
 |  |  |         children.remove(children.size() - 1); | 
 |  |  |         children.remove(0); | 
 |  |  |         if (children.size()>1 || | 
 |  |  |         if (children.size() > 1 || | 
 |  |  |                 !"vnode".equals(children.get(0).getNodeType())) { | 
 |  |  |             RbdTreeNode subNode = new RbdTreeNode(); | 
 |  |  |             subNode.setAlgorithmType("series"); | 
 |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 对树形结构进行预处理: | 
 |  |  |      *      去掉逻辑运算块中用于排版的外层series | 
 |  |  |      * 去掉逻辑运算块中用于排版的外层series | 
 |  |  |      * | 
 |  |  |      * @param root | 
 |  |  |      */ | 
 |  |  |     private void deleteSeriesForAutoArrange(RbdTreeNode root) { | 
 |  |  | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void setEdgeRouter(JSONArray rbdJsonArray, Map<String, RbdTreeNode> nodeMap) { | 
 |  |  |         for (int i = 0; i < rbdJsonArray.size(); i++ | 
 |  |  |         ) { | 
 |  |  |             JSONObject jsonObject = rbdJsonArray.getJSONObject(i); | 
 |  |  |             if (jsonObject.get("shape").equals("edge")) { | 
 |  |  |                 String sourceId = JsonUtils2.getJsonValueByPath(jsonObject, "source/cell".split("/")).toString(); | 
 |  |  |                 String targetId = JsonUtils2.getJsonValueByPath(jsonObject, "target/cell".split("/")).toString(); | 
 |  |  |                 RbdTreeNode sourceNode = nodeMap.get(sourceId); | 
 |  |  |                 RbdTreeNode targetNode = nodeMap.get(targetId); | 
 |  |  |                 if (sourceNode != null) { | 
 |  |  |                     if ("connect".equals(sourceNode.getNodeType()) && !"10000".equals(sourceId)){ | 
 |  |  |                         if (sourceNode.getY()+sourceNode.getMyHeight()/2 == targetNode.getY()+targetNode.getMyHeight()/2){ | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"),"right".split(",")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"),"left".split(",")); | 
 |  |  |                         }else{ | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"),"top,bottom".split(",")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"),"left".split(",")); | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |                 if (targetNode != null) { | 
 |  |  |                     if ("parallel,vote".contains(targetNode.getNodeType())){ | 
 |  |  |                         if (sourceNode.getY()+sourceNode.getMyHeight()/2 == targetNode.getY()+targetNode.getMyHeight()/2){ | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"),"right".split("")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"),"left".split("")); | 
 |  |  |                         }else{ | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/startDirections".split("/"),"right".split("")); | 
 |  |  |                             JsonUtils2.setJsonValueByPath(jsonObject, "router/args/endDirections".split("/"),"top,bottom".split("")); | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |     /** | 
 |  |  |      * 用于自动排版:将桥联转换为3支路的并联 | 
 |  |  |      * @param root | 
 |  |  |      * @return | 
 |  |  |      */ | 
 |  |  |     private void convertBridgeToThreeBranchParallel(RbdTreeNode root) { | 
 |  |  |         List<RbdTreeNode> children = root.getChildren(); | 
 |  |  |         for (RbdTreeNode treeNode : children) { | 
 |  |  |             if ("bridge".equals(treeNode.getAlgorithmType())) { | 
 |  |  |                 treeNode.setAlgorithmType("parallel"); | 
 |  |  |                 List<RbdTreeNode> list = new ArrayList<>(); | 
 |  |  |                 RbdTreeNode subNode = new RbdTreeNode(); | 
 |  |  |                 subNode.setAlgorithmType("series"); | 
 |  |  |                 subNode.setId(UUIDUtil.generateId()); | 
 |  |  |                 subNode.setName("v10000"); | 
 |  |  |                 subNode.setNodeType("vnode"); | 
 |  |  |                 subNode.getChildren().add(treeNode.getChildren().get(0)); | 
 |  |  |                 subNode.getChildren().add(treeNode.getChildren().get(1)); | 
 |  |  |                 list.add(subNode); | 
 |  |  |                 list.add(treeNode.getChildren().get(2)); | 
 |  |  |                 subNode = new RbdTreeNode(); | 
 |  |  |                 subNode.setAlgorithmType("series"); | 
 |  |  |                 subNode.setId(UUIDUtil.generateId()); | 
 |  |  |                 subNode.setName("v10001"); | 
 |  |  |                 subNode.setNodeType("vnode"); | 
 |  |  |                 subNode.getChildren().add(treeNode.getChildren().get(3)); | 
 |  |  |                 subNode.getChildren().add(treeNode.getChildren().get(4)); | 
 |  |  |                 list.add(subNode); | 
 |  |  |                 treeNode.setChildren(list); | 
 |  |  |             } | 
 |  |  |             convertBridgeToThreeBranchParallel(treeNode); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void setNodePositionXY(JSONArray rbdJsonArray, RbdTreeNode block, Map<String, RbdTreeNode> nodeMap) { | 
 |  |  |         Double x = block.getBlockX() + (block.getBlockWidth() - block.getMyWidth()) / 2; | 
 |  |  |         Double y = block.getBlockY() + (block.getBlockHeight() - block.getMyHeight()) / 2; | 
 |  |  |         block.setX(x); | 
 |  |  |         block.setY(y); | 
 |  |  |         nodeMap.put(block.getPicId(),block); | 
 |  |  |         setRbdNodePosition(rbdJsonArray, block.getPicId(), x, y); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  | /* | 
 |  |  |     private void calcPosition(JSONArray rbdJsonArray, RbdTreeNode block, Map<String, RbdTreeNode> nodeMap) { | 
 |  |  |         if (block.getNodeType().equals("node")) { | 
 |  |  |             setNodePositionXY(rbdJsonArray, block,nodeMap); | 
 |  |  | 
 |  |  |  | 
 |  |  |                 // 设置connect的位置 | 
 |  |  |                 RbdTreeNode connectBlock = new RbdTreeNode(); | 
 |  |  |                 connectBlock.setMyWidth(getRbdNodeInfo(rbdJsonArray, block.getPairStartNodeId(), "size/width")); | 
 |  |  |                 connectBlock.setMyHeight(getRbdNodeInfo(rbdJsonArray, block.getPairStartNodeId(), "size/height")); | 
 |  |  |                 connectBlock.setObjectWidth(getRbdNodeInfo(rbdJsonArray, block.getPairStartNodeId(), "size/width")); | 
 |  |  |                 connectBlock.setObjectHeight(getRbdNodeInfo(rbdJsonArray, block.getPairStartNodeId(), "size/height")); | 
 |  |  |                 connectBlock.setNodeType("connect"); | 
 |  |  |                 connectBlock.setPicId(block.getPairStartNodeId()); | 
 |  |  |                 connectBlock.setBlockX(block.getBlockX()); | 
 |  |  | 
 |  |  |  | 
 |  |  |                 opeBlock.setPicId(block.getPicId()); | 
 |  |  |                 opeBlock.setNodeType("parallel"); | 
 |  |  |                 opeBlock.setMyWidth(getRbdNodeInfo(rbdJsonArray, block.getPicId(), "size/width")); | 
 |  |  |                 opeBlock.setMyHeight(getRbdNodeInfo(rbdJsonArray, block.getPicId(), "size/height")); | 
 |  |  |                 opeBlock.setObjectWidth(getRbdNodeInfo(rbdJsonArray, block.getPicId(), "size/width")); | 
 |  |  |                 opeBlock.setObjectHeight(getRbdNodeInfo(rbdJsonArray, block.getPicId(), "size/height")); | 
 |  |  |                 opeBlock.setBlockX(block.getBlockX() + blockWidth - LAYOUT_CELL_SIZE_X); | 
 |  |  |                 opeBlock.setBlockY(firstSubBlockY); | 
 |  |  |                 opeBlock.setBlockWidth(LAYOUT_CELL_SIZE_X); | 
 |  |  | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private RbdTreeNode listToTree(String id, | 
 |  |  |                                    List<Algorithm> algorithmList, | 
 |  |  |                                    List<ModelNode> modelNodeAndVnodeList) { | 
 |  |  |  | 
 |  |  |         List<Algorithm> algos = algorithmList.stream().filter(item -> | 
 |  |  |                 id.equals(item.getId().toString())).collect(Collectors.toList()); | 
 |  |  |  | 
 |  |  |         RbdTreeNode subNode = new RbdTreeNode(); | 
 |  |  |         subNode.setId(Convert.toLong(id)); | 
 |  |  |         ModelNode nd = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                 id.equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |         subNode.setName(nd.getName()); | 
 |  |  |         subNode.setNodeType(nd.getNodeType()); | 
 |  |  |         subNode.setPicId(nd.getPicId()); | 
 |  |  |  | 
 |  |  |         if (!"vnode".equals(nd.getNodeType())) { | 
 |  |  |             subNode.setMyWidth(nd.getWidth()); | 
 |  |  |             subNode.setMyHeight(nd.getHeight()); | 
 |  |  |         } | 
 |  |  |         subNode.setBlockWidthNum(nd.getVnodeCellNumX()); | 
 |  |  |         subNode.setBlockHeightNum(nd.getVnodeCellNumY()); | 
 |  |  |         subNode.setPairStartNodeId(nd.getPairStartNodeId()); | 
 |  |  |         subNode.setPairEndNodeId(nd.getPairEndNodeId()); | 
 |  |  |         if (algos.size() > 0) { | 
 |  |  |             Algorithm algo = algos.get(0); | 
 |  |  |             subNode.setAlgorithmType(algo.getAlgorithmType()); | 
 |  |  |             String str = algo.getComputerList(); | 
 |  |  |             String[] ids = str.split(","); | 
 |  |  |             for (String subId : ids) { | 
 |  |  |                 subNode.getChildren().add(listToTree(subId, algorithmList, modelNodeAndVnodeList)); | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |         return subNode; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /* | 
 |  |  |      */ | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 根据顶层RBD的位置(x,y),自顶向下递归计算各个节点的位置(x,y) | 
 |  |  |      * | 
 |  |  |      * @param modelRbd | 
 |  |  |      * @param algorithmList | 
 |  |  |      * @param modelNodeAndVnodeList | 
 |  |  |      *//* | 
 |  |  |  | 
 |  |  |     private void calcLayoutPosition(ModelRbd modelRbd, | 
 |  |  |                                     List<Algorithm> algorithmList, | 
 |  |  |                                     List<ModelNode> modelNodeAndVnodeList) { | 
 |  |  |         String rbdsonStr = modelRbd.getContent(); | 
 |  |  |         JSONArray rbdJsonArray = new JSONObject(rbdsonStr).getJSONArray("cells"); | 
 |  |  |         Algorithm endAlgo = algorithmList.stream().filter(item -> | 
 |  |  |                 "end".equals(item.getAlgorithmType())).collect(Collectors.toList()).get(0); | 
 |  |  |         ModelNode topNode = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                 endAlgo.getComputerList().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |         Algorithm topAlgo = algorithmList.stream().filter(item -> | 
 |  |  |                 endAlgo.getComputerList().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |         // 将topNode的坐标定为Cell(0,0),反算所有节点的坐标 | 
 |  |  |         // 1. 计算节点的Cell位置 | 
 |  |  |         calcNodeLayoutPositionCell(rbdJsonArray, algorithmList, modelNodeAndVnodeList, topNode, topAlgo, 0, 0, | 
 |  |  |                 topNode.getVnodeCellNumX(), topNode.getVnodeCellNumY()); | 
 |  |  |         // 2. 计算节点的x,y坐标位置 | 
 |  |  |         calcNodeLayoutPosition(rbdJsonArray, algorithmList, modelNodeAndVnodeList, topNode, topAlgo); | 
 |  |  |         // 3. 设置start的位置 | 
 |  |  |         double distance = 200.0; | 
 |  |  |         double y = (topNode.getPositionCellY() + topNode.getVnodeCellNumY() / 2) * LAYOUT_CELL_SIZE_Y + (LAYOUT_CELL_SIZE_Y - LAYOUT_START_END_SIZE_Y) / 2; | 
 |  |  |         setRbdNodePosition(rbdJsonArray, "10000", 0 - distance, y); | 
 |  |  |         // 4. 设置end的位置 | 
 |  |  |         double x = topNode.getVnodeCellNumX() * LAYOUT_CELL_SIZE_X + distance - LAYOUT_START_END_SIZE_X; | 
 |  |  |         setRbdNodePosition(rbdJsonArray, "20000", x, y); | 
 |  |  |         JSONObject jsonObject = new JSONObject(); | 
 |  |  |         jsonObject.put("cells", rbdJsonArray); | 
 |  |  |         modelRbd.setContent(jsonObject.toString()); | 
 |  |  |     } | 
 |  |  | */ | 
 |  |  |  | 
 |  |  | /* | 
 |  |  |     // 递归函数(计算各节点的x,y坐标位置) | 
 |  |  |     private void calcNodeLayoutPosition(JSONArray rbdJsonArray, | 
 |  |  |                                         List<Algorithm> algorithmList, | 
 |  |  |                                         List<ModelNode> modelNodeAndVnodeList, | 
 |  |  |                                         ModelNode node, | 
 |  |  |                                         Algorithm algo) { | 
 |  |  |         // 未使用设备的实际宽、高 | 
 |  |  |         double x; | 
 |  |  |         double y; | 
 |  |  |         if ("node".equals(node.getNodeType())) { | 
 |  |  |             x = node.getPositionCellX() * LAYOUT_CELL_SIZE_X + (LAYOUT_CELL_SIZE_X - LAYOUT_DEVICE_NODE_SIZE_X) / 2; | 
 |  |  |             y = node.getPositionCellY() * LAYOUT_CELL_SIZE_Y + (LAYOUT_CELL_SIZE_Y - LAYOUT_DEVICE_NODE_SIZE_Y) / 2; | 
 |  |  |             node.setPositionX(x); | 
 |  |  |             node.setPositionY(y); | 
 |  |  |             setRbdNodePosition(rbdJsonArray, node.getPicId(), node.getPositionX(), node.getPositionY()); | 
 |  |  |         } else if ("vnode".equals(node.getNodeType())) { | 
 |  |  |             String[] computerNodeListStr = algo.getComputerList().split(","); | 
 |  |  |             switch (algo.getAlgorithmType()) { | 
 |  |  |                 case OPE_TYPE_SERIES: | 
 |  |  |                 case OPE_TYPE_PARALLEL: | 
 |  |  |                 case OPE_TYPE_SWITCH: | 
 |  |  |                 case OPE_TYPE_VOTE: | 
 |  |  |                     for (String nodeStr : computerNodeListStr) { | 
 |  |  |                         ModelNode childNode = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                                 nodeStr.equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                         List<Algorithm> childAlgos = algorithmList.stream().filter(item -> | 
 |  |  |                                 childNode.getId().equals(item.getId())).collect(Collectors.toList()); | 
 |  |  |                         Algorithm childAlgo = childAlgos.size() > 0 ? childAlgos.get(0) : null; | 
 |  |  |                         calcNodeLayoutPosition(rbdJsonArray, | 
 |  |  |                                 algorithmList, | 
 |  |  |                                 modelNodeAndVnodeList, | 
 |  |  |                                 childNode, | 
 |  |  |                                 childAlgo); | 
 |  |  |                     } | 
 |  |  |                     if (OPE_TYPE_PARALLEL.equals(algo.getAlgorithmType()) | 
 |  |  |                             || OPE_TYPE_SWITCH.equals(algo.getAlgorithmType()) | 
 |  |  |                             || OPE_TYPE_VOTE.equals(algo.getAlgorithmType())) { | 
 |  |  |                         // 设置connect的位置 | 
 |  |  |                         x = node.getPositionCellX() * LAYOUT_CELL_SIZE_X + (LAYOUT_CELL_SIZE_X - LAYOUT_CONNECT_SIZE_X) / 2; | 
 |  |  |                         y = (node.getPositionCellY() + node.getVnodeCellNumY() / 2) * LAYOUT_CELL_SIZE_Y + (LAYOUT_CELL_SIZE_Y - LAYOUT_CONNECT_SIZE_Y) / 2; | 
 |  |  |                         setRbdNodePosition(rbdJsonArray, node.getPairStartNodeId(), x, y); | 
 |  |  |                         // 设置运算符的位置 | 
 |  |  |                         x = (node.getPositionCellX() + node.getVnodeCellNumX() - 1) * LAYOUT_CELL_SIZE_X + (LAYOUT_CELL_SIZE_X - LAYOUT_OPE_NODE_SIZE_X) / 2; | 
 |  |  |                         y = (node.getPositionCellY() + node.getVnodeCellNumY() / 2) * LAYOUT_CELL_SIZE_Y + (LAYOUT_CELL_SIZE_Y - LAYOUT_OPE_NODE_SIZE_Y) / 2; | 
 |  |  |                         setRbdNodePosition(rbdJsonArray, node.getPicId(), x, y); | 
 |  |  |                     } | 
 |  |  |                     break; | 
 |  |  |                 case OPE_TYPE_BRIDGE: | 
 |  |  |                     break; | 
 |  |  |                 default: | 
 |  |  |                     break; | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     // 递归函数(计算各节点的Cell位置,以左上角为Cell位置0,0) | 
 |  |  |     private void calcNodeLayoutPositionCell(JSONArray rbdJsonArray, | 
 |  |  |                                             List<Algorithm> algorithmList, | 
 |  |  |                                             List<ModelNode> modelNodeAndVnodeList, | 
 |  |  |                                             ModelNode node, | 
 |  |  |                                             Algorithm algo, | 
 |  |  |                                             double originCellX, | 
 |  |  |                                             double originCellY, | 
 |  |  |                                             double maxX, | 
 |  |  |                                             double maxY) { | 
 |  |  |         if ("node".equals(node.getNodeType())) { | 
 |  |  |             //设置node(设备节点)Cell位置 | 
 |  |  |             double width = LAYOUT_DEVICE_NODE_SIZE_X * maxX; | 
 |  |  |             double hight = LAYOUT_DEVICE_NODE_SIZE_Y * maxY; | 
 |  |  |             double x = originCellX + (width - LAYOUT_DEVICE_NODE_SIZE_X) / 2; | 
 |  |  |             double y = originCellY + (hight - LAYOUT_DEVICE_NODE_SIZE_Y) / 2; | 
 |  |  |             node.setPositionCellX(x); | 
 |  |  |             node.setPositionCellY(y); | 
 |  |  |         } else if ("vnode".equals(node.getNodeType())) { | 
 |  |  |             String[] computerNodeListStr = algo.getComputerList().split(","); | 
 |  |  |             switch (algo.getAlgorithmType()) { | 
 |  |  |                 case OPE_TYPE_SERIES: | 
 |  |  |                 case OPE_TYPE_PARALLEL: | 
 |  |  |                 case OPE_TYPE_SWITCH: | 
 |  |  |                 case OPE_TYPE_VOTE: | 
 |  |  |                     double preNodeCellX = 0.0; | 
 |  |  |                     double preNodeCellY = 0.0; | 
 |  |  |                     for (String nodeStr : computerNodeListStr) { | 
 |  |  |                         ModelNode childNode = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                                 nodeStr.equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                         List<Algorithm> childAlgos = algorithmList.stream().filter(item -> | 
 |  |  |                                 childNode.getId().equals(item.getId())).collect(Collectors.toList()); | 
 |  |  |                         Algorithm childAlgo = childAlgos.size() > 0 ? childAlgos.get(0) : null; | 
 |  |  |                         if (OPE_TYPE_SERIES.equals(algo.getAlgorithmType())) { | 
 |  |  |                             calcNodeLayoutPositionCell(rbdJsonArray, | 
 |  |  |                                     algorithmList, | 
 |  |  |                                     modelNodeAndVnodeList, | 
 |  |  |                                     childNode, | 
 |  |  |                                     childAlgo, | 
 |  |  |                                     originCellX + preNodeCellX, | 
 |  |  |                                     originCellY, node.getVnodeCellNumX(), node.getVnodeCellNumY() | 
 |  |  |                             ); | 
 |  |  |                             preNodeCellX += childNode.getVnodeCellNumX(); | 
 |  |  |                         } else { | 
 |  |  |                             calcNodeLayoutPositionCell(rbdJsonArray, | 
 |  |  |                                     algorithmList, | 
 |  |  |                                     modelNodeAndVnodeList, | 
 |  |  |                                     childNode, | 
 |  |  |                                     childAlgo, | 
 |  |  |                                     originCellX + 1, | 
 |  |  |                                     originCellY + preNodeCellY, node.getVnodeCellNumX(), node.getVnodeCellNumY()); | 
 |  |  |                             preNodeCellY += childNode.getVnodeCellNumY(); | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  | */ | 
 |  |  | /* | 
 |  |  |                     // 设置运算符的Cell位置 | 
 |  |  |                     if (OPE_TYPE_SERIES.equals(algo.getAlgorithmType())) { | 
 |  |  |                         node.setPositionCellX(originCellX); | 
 |  |  |                     } else { | 
 |  |  |                         node.setPositionCellX(originCellX + node.getVnodeCellNumX() - 1); | 
 |  |  |                     } | 
 |  |  |                     node.setPositionCellY(originCellY + node.getVnodeCellNumY()/2); | 
 |  |  | *//* | 
 |  |  |  | 
 |  |  |                     // 需节点代表整个逻辑单元,因此其坐标为originCellX和originCellX | 
 |  |  |                     node.setPositionCellX(originCellX); | 
 |  |  |                     node.setPositionCellY(originCellX); | 
 |  |  |                     break; | 
 |  |  |                 case OPE_TYPE_BRIDGE: | 
 |  |  | */ | 
 |  |  | /* | 
 |  |  |                     ModelNode node1 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                             computerNodeListStr[0].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     ModelNode node2 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                             computerNodeListStr[1].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     ModelNode node3 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                             computerNodeListStr[2].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     ModelNode node4 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                             computerNodeListStr[3].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     ModelNode node5 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                             computerNodeListStr[4].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     Algorithm algo1 = algorithmList.stream().filter(item -> | 
 |  |  |                             node1.getId().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     Algorithm algo2 = algorithmList.stream().filter(item -> | 
 |  |  |                             node2.getId().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     Algorithm algo3 = algorithmList.stream().filter(item -> | 
 |  |  |                             node3.getId().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     Algorithm algo4 = algorithmList.stream().filter(item -> | 
 |  |  |                             node4.getId().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     Algorithm algo5 = algorithmList.stream().filter(item -> | 
 |  |  |                             node5.getId().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                     // 1,计算三行的总高度 | 
 |  |  |                     // 1.1 计算第一行两个节点的高度 | 
 |  |  |                     int firstRowCellNumY = Math.max(node1.getVnodeCellNumY(), node2.getVnodeCellNumY()); | 
 |  |  |                     // 1.2 计算第二行桥联节点的高度 | 
 |  |  |                     int secondRowCellNumY = node3.getVnodeCellNumY(); | 
 |  |  |                     // 1.3 计算第三行两个节点的高度 | 
 |  |  |                     int thirdRowCellNumY = Math.max(node4.getVnodeCellNumY(), node5.getVnodeCellNumY()); | 
 |  |  | //                    int totalCellNumY = firstRowCellNumY + secondRowCellNumY + thirdRowCellNumY; | 
 |  |  |                     // 2. 计算三行各节点的坐标 | 
 |  |  |                     // 2.1 计算第一行两个节点的坐标 | 
 |  |  |                     calcNodeLayoutPositionCell(rbdJsonArray, | 
 |  |  |                             algorithmList, | 
 |  |  |                             modelNodeAndVnodeList, | 
 |  |  |                             node1, | 
 |  |  |                             algo1, | 
 |  |  |                             originCellX + 1, | 
 |  |  |                             originCellY); | 
 |  |  |                     calcNodeLayoutPositionCell(rbdJsonArray, | 
 |  |  |                             algorithmList, | 
 |  |  |                             modelNodeAndVnodeList, | 
 |  |  |                             node2, | 
 |  |  |                             algo2, | 
 |  |  |                             originCellX + 1 + node1.getPositionCellX(), | 
 |  |  |                             originCellY); | 
 |  |  |                     // 2.2 计算第二行桥联节点的坐标 | 
 |  |  |                     calcNodeLayoutPositionCell(rbdJsonArray, | 
 |  |  |                             algorithmList, | 
 |  |  |                             modelNodeAndVnodeList, | 
 |  |  |                             node3, | 
 |  |  |                             algo3, | 
 |  |  |                             originCellX + 1, | 
 |  |  |                             originCellY + firstRowCellNumY); | 
 |  |  |                     // 2.3 计算第三行两个节点的坐标 | 
 |  |  |                     calcNodeLayoutPositionCell(rbdJsonArray, | 
 |  |  |                             algorithmList, | 
 |  |  |                             modelNodeAndVnodeList, | 
 |  |  |                             node4, | 
 |  |  |                             algo4, | 
 |  |  |                             originCellX + 1, | 
 |  |  |                             originCellY + firstRowCellNumY + secondRowCellNumY); | 
 |  |  |                     calcNodeLayoutPositionCell(rbdJsonArray, | 
 |  |  |                             algorithmList, | 
 |  |  |                             modelNodeAndVnodeList, | 
 |  |  |                             node5, | 
 |  |  |                             algo5, | 
 |  |  |                             originCellX + 1 + node4.getPositionCellX(), | 
 |  |  |                             originCellY + firstRowCellNumY + secondRowCellNumY); | 
 |  |  |                     // 2.4 计算桥联运算符的坐标 | 
 |  |  |                     node.setPositionCellX(originCellX + 1); | 
 |  |  |                     node.setPositionCellY(originCellY + node.getVnodeCellNumY()/2); | 
 |  |  | *//* | 
 |  |  |  | 
 |  |  |                     break; | 
 |  |  |                 default: | 
 |  |  |                     break; | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  | */ | 
 |  |  |     private void setRbdNodePosition(JSONArray rbdJsonArray, | 
 |  |  |                                     String id, | 
 |  |  |                                     double x, | 
 |  |  |                                     double y) { | 
 |  |  |         for (int i = 0; i < rbdJsonArray.size(); i++) { | 
 |  |  |             JSONObject jsonObject = rbdJsonArray.getJSONObject(i); | 
 |  |  |             if (id.equals(jsonObject.get("id").toString())) { | 
 |  |  |                 JsonUtils2.setJsonValueByPath(jsonObject, "position/x".split("/"), x); | 
 |  |  |                 JsonUtils2.setJsonValueByPath(jsonObject, "position/y".split("/"), y); | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private Double getRbdNodeInfo(JSONArray rbdJsonArray, | 
 |  |  |                                   String picId, | 
 |  |  |                                   String path) { | 
 |  |  |         for (int i = 0; i < rbdJsonArray.size(); i++) { | 
 |  |  |             JSONObject jsonObject = rbdJsonArray.getJSONObject(i); | 
 |  |  |             if (picId.equals(jsonObject.get("id").toString())) { | 
 |  |  |                 return Convert.toDouble(JsonUtils2.getJsonValueByPath(jsonObject, path.split("/"))); | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |         return null; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 自底向上递归合计出整个RBD的大小(横向及纵向所占单元格的数量) | 
 |  |  |      * | 
 |  |  |      * @param modelRbd | 
 |  |  |      * @param algorithmList | 
 |  |  |      * @param modelNodeAndVnodeList | 
 |  |  |      */ | 
 |  |  |     private void calcLayoutSize( | 
 |  |  |             ModelRbd modelRbd, | 
 |  |  |             List<Algorithm> algorithmList, | 
 |  |  |             List<ModelNode> modelNodeAndVnodeList) { | 
 |  |  |         Algorithm endAlgo = algorithmList.stream().filter(item -> | 
 |  |  |                 "end".equals(item.getAlgorithmType())).collect(Collectors.toList()).get(0); | 
 |  |  |         ModelNode topNode = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                 endAlgo.getComputerList().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |         Algorithm topAlgo = algorithmList.stream().filter(item -> | 
 |  |  |                 endAlgo.getComputerList().equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |         calcNodeLayoutSize(algorithmList, modelNodeAndVnodeList, topNode, topAlgo); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     // 递归函数 | 
 |  |  |     private void calcNodeLayoutSize(List<Algorithm> algorithmList, | 
 |  |  |                                     List<ModelNode> modelNodeAndVnodeList, | 
 |  |  |                                     ModelNode node, | 
 |  |  |                                     Algorithm algo) { | 
 |  |  |         if ("node".equals(node.getNodeType())) { | 
 |  |  |             //设置node(设备节点)布局信息 | 
 |  |  | //            node.setWidth(LAYOUT_DEVICE_NODE_SIZE_X); | 
 |  |  | //            node.setHeight(LAYOUT_DEVICE_NODE_SIZE_Y); | 
 |  |  |             node.setCellNumX(LAYOUT_CELL_NUM_NODE_X); | 
 |  |  |             node.setCellNumY(LAYOUT_CELL_NUM_NODE_Y); | 
 |  |  |             node.setVnodeCellNumX(node.getCellNumX()); | 
 |  |  |             node.setVnodeCellNumY(node.getCellNumY()); | 
 |  |  |         } else if ("vnode".equals(node.getNodeType())) { | 
 |  |  |             // 1. 设置vnode(运算节点)布局信息(其实串联没有运算符,不需要设置,但是设置了也没有坏处,所以不作区分) | 
 |  |  | //            node.setWidth(LAYOUT_OPE_NODE_SIZE_X); | 
 |  |  | //            node.setHeight(LAYOUT_OPE_NODE_SIZE_Y); | 
 |  |  |             node.setCellNumX(LAYOUT_CELL_NUM_NODE_X); | 
 |  |  |             node.setCellNumY(LAYOUT_CELL_NUM_NODE_Y); | 
 |  |  |  | 
 |  |  |             // 2. 设置虚节点布局信息 | 
 |  |  |             // 2.1 设置虚节点内各运算对象的布局信息 | 
 |  |  |             String[] computerNodeListStr = algo.getComputerList().split(","); | 
 |  |  |             for (String nodeStr : computerNodeListStr) { | 
 |  |  |                 ModelNode childNode = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                         nodeStr.equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |                 List<Algorithm> childAlgos = algorithmList.stream().filter(item -> | 
 |  |  |                         childNode.getId().equals(item.getId())).collect(Collectors.toList()); | 
 |  |  |                 Algorithm childAlgo = childAlgos.size() > 0 ? childAlgos.get(0) : null; | 
 |  |  |                 calcNodeLayoutSize(algorithmList, | 
 |  |  |                         modelNodeAndVnodeList, | 
 |  |  |                         childNode, | 
 |  |  |                         childAlgo); | 
 |  |  |             } | 
 |  |  |             // 2.2 设置虚节点总的布局信息到运算节点中 | 
 |  |  |             setVnodeLayoutNum(computerNodeListStr, modelNodeAndVnodeList, node, algo); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void setVnodeLayoutNum(String[] computerNodeListStr, | 
 |  |  |                                    List<ModelNode> modelNodeAndVnodeList, | 
 |  |  |                                    ModelNode vnode, | 
 |  |  |                                    Algorithm algo) { | 
 |  |  |         int numX = 0; | 
 |  |  |         int numY = 0; | 
 |  |  |         // 1. 计算串、并、旁联、表决 | 
 |  |  |         for (String nodeStr : computerNodeListStr) { | 
 |  |  |             ModelNode childNode = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                     nodeStr.equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |             switch (algo.getAlgorithmType()) { | 
 |  |  |                 case OPE_TYPE_SERIES: | 
 |  |  |                     numX += childNode.getVnodeCellNumX(); | 
 |  |  |                     numY = childNode.getVnodeCellNumY() > numY ? childNode.getVnodeCellNumY() : numY; | 
 |  |  |                     break; | 
 |  |  |                 case OPE_TYPE_PARALLEL: | 
 |  |  |                 case OPE_TYPE_SWITCH: | 
 |  |  |                 case OPE_TYPE_VOTE: | 
 |  |  |                     numX = childNode.getVnodeCellNumX() > numX ? childNode.getVnodeCellNumX() : numX; | 
 |  |  |                     numY += childNode.getVnodeCellNumY(); | 
 |  |  |                     break; | 
 |  |  |                 default: | 
 |  |  |                     break; | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |         if (OPE_TYPE_PARALLEL.equals(algo.getAlgorithmType()) | 
 |  |  |                 || OPE_TYPE_SWITCH.equals(algo.getAlgorithmType()) | 
 |  |  |                 || OPE_TYPE_VOTE.equals(algo.getAlgorithmType())) { | 
 |  |  |             // 加上connect的大小 | 
 |  |  |             numX += LAYOUT_CELL_NUM_CONNECT_X; | 
 |  |  |             numX += vnode.getCellNumX(); | 
 |  |  |         } | 
 |  |  |         // 2. 计算桥联 | 
 |  |  |         if (OPE_TYPE_BRIDGE.equals(algo.getAlgorithmType())) { | 
 |  |  |             // 桥联支路算一行,整个桥联共3行 | 
 |  |  |             // 2.1 计算第一行 | 
 |  |  |             ModelNode node1 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                     computerNodeListStr[0].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |             ModelNode node2 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                     computerNodeListStr[1].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |             ModelNode node3 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                     computerNodeListStr[2].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |             ModelNode node4 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                     computerNodeListStr[3].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |             ModelNode node5 = modelNodeAndVnodeList.stream().filter(item -> | 
 |  |  |                     computerNodeListStr[4].equals(item.getId().toString())).collect(Collectors.toList()).get(0); | 
 |  |  |             int numX1 = node1.getCellNumX() + node2.getCellNumX(); | 
 |  |  |             int numY1 = node1.getCellNumY() > node2.getCellNumY() ? node1.getCellNumY() : node2.getCellNumY(); | 
 |  |  |             // 2.2 计算第二行(桥联支路,横向画图) | 
 |  |  |             int numX2 = node3.getCellNumX(); | 
 |  |  |             int numY2 = node3.getCellNumY(); | 
 |  |  |             // 2.3 计算第三行 | 
 |  |  |             int numX3 = node4.getCellNumX() + node5.getCellNumX(); | 
 |  |  |             int numY3 = node4.getCellNumY() > node5.getCellNumY() ? node4.getCellNumY() : node5.getCellNumY(); | 
 |  |  |             numX = Math.max(Math.max(numX1, numX2), numX3); | 
 |  |  |             numY = numY1 + numY2 + numY3; | 
 |  |  |             // 2.4 加上connect的大小 | 
 |  |  |             numX += LAYOUT_CELL_NUM_CONNECT_X; | 
 |  |  |             numX += vnode.getCellNumX(); | 
 |  |  |         } | 
 |  |  |         vnode.setVnodeCellNumX(numX); | 
 |  |  |         vnode.setVnodeCellNumY(numY); | 
 |  |  |     } | 
 |  |  | } |