wente
2024-12-05 17ce02ec6fefa4e8b9ac870e2b52dea0942f5597
modules/mainPart/src/main/java/com/zt/life/modules/mainPart/taskReliability/service/ModelLineService.java
@@ -1,6 +1,5 @@
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;
@@ -10,7 +9,6 @@
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;
@@ -40,33 +38,6 @@
    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;
@@ -167,63 +138,171 @@
        // 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. 保存自动布局模型
        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);
        RbdTreeNode root = new RbdTreeNode();
        root.setId(Convert.toLong("20000"));
        root.setName("end");
        root.setNodeType("vnode");
        root.setAlgorithmType("parallel");
        root.setPicId("20000");
        root.setPairStartNodeId("10000");
        root.setBlockWidthNum(root2.getBlockWidthNum() + 2);
        root.setBlockHeightNum(root2.getBlockHeightNum());
        root.getChildren().add(root2);
        // 7. 递归计算RBD的布局空间参数(x、y坐标)
        // 5. 递归计算RBD的布局空间参数(x、y坐标)
        root.setBlockX(0);
        root.setBlockY(0);
        Map<String, RbdTreeNode> nodeMap = new HashMap<>();
        calcPosition(rbdJsonArray, root, nodeMap);
        calcPosition(rbdJsonArray, root, nodeMap, false);
        setEdgeRouter(rbdJsonArray, nodeMap);
        // 6. 保存自动布局模型
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("cells", rbdJsonArray);
        modelRbd.setContent(jsonObject.toString());
        //        calcLayoutPosition(modelRbd, algorithmList, modelNodeAndVnodeList);
        // 8. 保存自动布局模型
        // 更新RBD数据
//        modelRbd.setAutoLayoutContent("测试文字");
//        modelRbdDao.updateById(modelRbd);
*/
        return result;
    }
    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 {
            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) {
                    double selfBlockWidth = child.getBlockWidth() * descentWidth / block.getBlockWidth();
                    child.setDescentWidth(selfBlockWidth);
                    child.setBlockWidth(selfBlockWidth);
                    if (lastIsSeries)
                        child.setDescentHeight(descentHeight);
                    else
                        child.setDescentHeight(block.getBlockHeight());
                    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());
                    if (!"vnode".equals(child.getNodeType())) {
                        child.setBlockWidth(block.getBlockWidth());
                    }
                    child.setBlockX(block.getBlockX());
                    child.setBlockY(subBlockY);
                    calcPosition(rbdJsonArray, child, nodeMap, false);
                    subBlockY = subBlockY + child.getBlockHeight();
                }
            }
        }
    }
    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);
    }
    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 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,
@@ -287,6 +366,12 @@
                    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()));
@@ -357,7 +442,7 @@
    }
    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();
@@ -377,8 +462,8 @@
        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);
@@ -393,13 +478,13 @@
    }
    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);
@@ -410,8 +495,9 @@
                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);
@@ -421,8 +507,8 @@
                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())) {
@@ -444,8 +530,8 @@
                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());
@@ -463,8 +549,8 @@
                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,
@@ -483,10 +569,10 @@
    }
    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 ->
@@ -506,7 +592,7 @@
                    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())) {
@@ -605,7 +691,7 @@
    /**
     * 按自上而下的顺序排序
      */
     */
    private List<ModelLine> sortLine(List<ModelLine> lines,
                                     List<ModelNode> modelNodeList) {
        for (ModelLine line : lines) {
@@ -696,9 +782,9 @@
    }
    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();
@@ -706,6 +792,7 @@
            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());
@@ -743,14 +830,15 @@
     * 对树形结构进行预处理,包括:
     * 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");
@@ -766,7 +854,8 @@
    /**
     * 对树形结构进行预处理:
     *      去掉逻辑运算块中用于排版的外层series
     * 去掉逻辑运算块中用于排版的外层series
     *
     * @param root
     */
    private void deleteSeriesForAutoArrange(RbdTreeNode root) {
@@ -782,50 +871,41 @@
        }
    }
    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);
@@ -870,8 +950,8 @@
                // 设置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());
@@ -898,8 +978,8 @@
                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);
@@ -909,435 +989,6 @@
        }
    }
    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);
    }
}