package com.zt.life.modules.mainPart.taskReliability.service;
|
|
import cn.hutool.json.JSONArray;
|
import cn.hutool.json.JSONObject;
|
import com.zt.common.service.BaseService;
|
import com.zt.common.utils.JsonUtils2;
|
import com.zt.common.utils.UUIDUtil;
|
import com.zt.life.modules.mainPart.basicInfo.dao.ParamDataDao;
|
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.model.*;
|
import org.apache.commons.lang3.StringUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import com.zt.common.db.query.QueryFilter;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
|
/**
|
* model_line
|
*
|
* @author zt generator
|
* @since 1.0.0 2024-02-28
|
*/
|
@Service
|
public class ModelLineService extends BaseService<ModelLineDao, ModelLine> {
|
private static final Logger logger = LoggerFactory.getLogger(ModelLineService.class);
|
|
// 运算
|
public static final String OPE_TYPE_SERIES = "series";
|
public static final String OPE_TYPE_PARALLEL = "parallel";
|
public static final String OPE_TYPE_SWITCH = "switch";
|
public static final String OPE_TYPE_VOTE = "vote";
|
public static final String OPE_TYPE_BRIDGE = "bridge";
|
|
@Autowired
|
private ModelLineDao modelLineDao;
|
@Autowired
|
private ModelNodeDao modelNodeDao;
|
@Autowired
|
private ModelRbdDao modelRbdDao;
|
@Autowired
|
private AlgorithmDao algorithmDao;
|
@Autowired
|
private ModelNodeAlgorithmDao modelNodeAlgorithmDao;
|
@Autowired
|
private XhProductModelDao xhProductModelDao;
|
@Autowired
|
private ParamDataDao paramDataDao;
|
|
/**
|
* 分页查询
|
*
|
* @param queryFilter
|
* @return
|
*/
|
public List<ModelLine> page(QueryFilter queryFilter) {
|
return baseDao.getList(queryFilter.getQueryParams());
|
}
|
|
public ModelRbd getDiagram(Long modelId) {
|
return modelRbdDao.getDiagram(modelId);
|
}
|
|
/**
|
* 删除
|
*
|
* @param ids
|
*/
|
public void delete(Long[] ids) {
|
super.deleteLogic(ids);
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void insert(ModelRbd modelRbd) {
|
if (modelRbd == null) return;
|
if (modelRbd.getId() == null) return;
|
Long modelId = modelRbd.getId();
|
|
// 删除既有数据
|
modelRbdDao.deleteByModelId(modelId);
|
|
// 插入数据
|
modelRbd.setId(UUIDUtil.generateId());
|
modelRbdDao.insert(modelRbd);
|
}
|
|
|
@Transactional(rollbackFor = Exception.class)
|
public void update(ModelRbd modelRbd) {
|
if (modelRbd == null) return;
|
if (modelRbd.getId() == null) return;
|
Long modelId = modelRbd.getId();
|
|
// 删除既有数据
|
modelRbdDao.deleteByModelId(modelId);
|
|
modelRbdDao.insert(modelRbd);
|
}
|
|
// 自动排版RBD
|
@Transactional(rollbackFor = Exception.class)
|
public boolean layout(ModelRbd modelRbd) {
|
boolean result = true;
|
if (modelRbd == null) return result;
|
Long modelId = modelRbd.getId();
|
result = layoutRbd(modelRbd);
|
return result;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public boolean analyze(ModelRbd modelRbd) {
|
boolean result = true;
|
if (modelRbd == null) return result;
|
Long modelId = modelRbd.getId();
|
result = analyzeRbd(modelRbd, true);
|
return result;
|
}
|
|
private boolean layoutRbd(ModelRbd modelRbd) {
|
boolean result = true;
|
String rbdsonStr = modelRbd.getContent();
|
|
JSONArray rbdJsonArray = new JSONObject(rbdsonStr).getJSONArray("cells");
|
if (rbdJsonArray == null) return result;
|
|
// 解析结果存放list
|
List<ModelNode> modelNodeList = new ArrayList<>();
|
List<ModelLine> modelLineList = new ArrayList<>();
|
List<Algorithm> algorithmList = new ArrayList<>();
|
List<ProductImg> productImgList = new ArrayList<>(); // 暂不使用(而使用数据库中的可靠性参数)
|
|
// 1. 解析出节点与边
|
getNodeAndLineFromRbd(modelRbd.getId(), rbdJsonArray, modelNodeList, modelLineList, productImgList);
|
|
// 2. 转换为树型结构
|
RbdTreeNode root = recognizeRbd(modelNodeList, modelLineList);
|
// 3. 将桥联转换为3支路的并联
|
convertBridgeToThreeBranchParallel(root);
|
// 4. 递归计算RBD的布局空间大小
|
calcLayoutSize(root);
|
|
// 5. 递归计算RBD的布局空间参数(x、y坐标)
|
root.setBlockX(0);
|
root.setBlockY(0);
|
Map<String, RbdTreeNode> nodeMap = new HashMap<>();
|
calcPosition(rbdJsonArray, root, nodeMap, false);
|
setEdgeRouter(rbdJsonArray, nodeMap);
|
|
// 6. 保存自动布局模型
|
JSONObject jsonObject = new JSONObject();
|
jsonObject.put("cells", rbdJsonArray);
|
modelRbd.setContent(jsonObject.toString());
|
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,
|
JSONArray rbdJsonArray,
|
List<ModelNode> modelNodeList,
|
List<ModelLine> modelLineList,
|
List<ProductImg> productImgList) {
|
Object jsonValue = null;
|
for (int i = 0; i < rbdJsonArray.size(); i++) {
|
JSONObject jsonObject = rbdJsonArray.getJSONObject(i);
|
String shape = jsonObject.get("shape").toString();
|
if ("edge".equals(shape)) {
|
ModelLine modelLine = new ModelLine();
|
modelLine.setId(UUIDUtil.generateId());
|
modelLine.setModelId(modelId);
|
modelLine.setPicId(jsonObject.get("id").toString());
|
modelLine.setBeginCell(JsonUtils2.getJsonValueByPath(jsonObject, "source/cell".split("/")).toString());
|
modelLine.setEndCell(JsonUtils2.getJsonValueByPath(jsonObject, "target/cell".split("/")).toString());
|
modelLineList.add(modelLine);
|
} else if ("image".equals(shape)) {
|
ModelNode modelNode = new ModelNode();
|
modelNode.setId(UUIDUtil.generateId());
|
modelNode.setModelId(modelId);
|
modelNode.setPicId(jsonObject.get("id").toString());
|
modelNode.setNodeType(JsonUtils2.getJsonValueByPath(jsonObject, "data/nodeType".split("/")).toString());
|
modelNode.setPositionX(Double.valueOf(JsonUtils2.getJsonValueByPath(jsonObject, "position/x".split("/")).toString()));
|
modelNode.setPositionY(Double.valueOf(JsonUtils2.getJsonValueByPath(jsonObject, "position/y".split("/")).toString()));
|
modelNode.setWidth(new Double(JsonUtils2.getJsonValueByPath(jsonObject, "size/width".split("/")).toString()));
|
modelNode.setHeight(new Double(JsonUtils2.getJsonValueByPath(jsonObject, "size/height".split("/")).toString()));
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/voteNum".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
modelNode.setVoteNum(Integer.valueOf(jsonValue.toString()));
|
}
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/startNodeId".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
modelNode.setPairStartNodeId(jsonValue.toString());
|
}
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/endNodeId".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
modelNode.setPairEndNodeId(jsonValue.toString());
|
}
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/edgeTopId".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
modelNode.setBridgeEdgeTopId(jsonValue.toString());
|
}
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/edgeBottomId".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
modelNode.setBridgeEdgeBottomId(jsonValue.toString());
|
}
|
if ("dashedBox".equals(modelNode.getNodeType())) {
|
modelNode.setNodeType("node");
|
} else if ("node".equals(modelNode.getNodeType())) {
|
ProductImg productImg = new ProductImg();
|
String dataId = JsonUtils2.getJsonValueByPath(jsonObject, "data/dataId".split("/")).toString();
|
modelNode.setDataId(Long.valueOf(dataId));
|
modelNode.setNodeTypeExt(JsonUtils2.getJsonValueByPath(jsonObject, "data/nodeTypeExt".split("/")).toString());
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "attrs/text/text".split("/"));
|
modelNode.setName(jsonValue == null ? "" : jsonValue.toString());
|
|
productImg.setDataId(dataId);
|
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()));
|
if (3 == productImg.getReliabDistribType()) {
|
// 二项分布
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/simulatTimes".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
productImg.setBinomialTotalNum(Integer.valueOf(jsonValue.toString()));
|
modelNode.setBinomialTotalNum(Integer.valueOf(jsonValue.toString()));
|
}
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/successTimes".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
productImg.setBinomialSuccessNum(Integer.valueOf(jsonValue.toString()));
|
modelNode.setBinomialSuccessNum(Integer.valueOf(jsonValue.toString()));
|
}
|
}
|
}
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/taskMtbcf".split("/"));
|
if (null != jsonValue) productImg.setTaskMtbcf(jsonValue.toString());
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/taskMtbcfOtherParams2".split("/"));
|
if (null != jsonValue) productImg.setTaskMtbcfOtherParams2(jsonValue.toString());
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/taskMtbcfOtherParams3".split("/"));
|
if (null != jsonValue) productImg.setTaskMtbcfOtherParams3(jsonValue.toString());
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/isRepair".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString()) && !"null".equals(jsonValue.toString())) {
|
productImg.setIsRepair(Integer.valueOf(jsonValue.toString()));
|
} else {
|
productImg.setIsRepair(0);
|
}
|
if (1 == productImg.getIsRepair()) {
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/repairDistribType".split("/"));
|
if (jsonValue != null && StringUtils.isNotBlank(jsonValue.toString())) {
|
productImg.setRepairDistribType(Integer.valueOf(jsonValue.toString()));
|
}
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/repairMttcr".split("/"));
|
if (null != jsonValue) productImg.setRepairMttcr(jsonValue.toString());
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/repairMttcrOtherParams2".split("/"));
|
if (null != jsonValue) productImg.setRepairMttcrOtherParams2(jsonValue.toString());
|
jsonValue = JsonUtils2.getJsonValueByPath(jsonObject, "data/repairMttcrOtherParams3".split("/"));
|
if (null != jsonValue) productImg.setRepairMttcrOtherParams3(jsonValue.toString());
|
}
|
}
|
productImgList.add(productImg);
|
}
|
modelNodeList.add(modelNode);
|
}
|
}
|
}
|
|
private void saveModel(ModelRbd modelRbd,
|
List<Algorithm> algoList,
|
List<ModelNode> modelNodeAndVnodeList) {
|
// 删除既有数据
|
algorithmDao.deleteByModelId(modelRbd.getId());
|
modelNodeAlgorithmDao.deleteByModelId(modelRbd.getId());
|
|
// 插入数据
|
for (Algorithm algorithm : algoList) {
|
algorithmDao.insert(algorithm);
|
}
|
for (ModelNode modelNode : modelNodeAndVnodeList) {
|
modelNodeAlgorithmDao.insert(ModelNodeAlgorithm.from(modelNode));
|
}
|
|
// 更新RBD数据
|
modelRbd.setPublishedContent(modelRbd.getContent());
|
modelRbdDao.updateById(modelRbd);
|
}
|
|
private RbdTreeNode recognizeRbd(List<ModelNode> modelNodeList,
|
List<ModelLine> modelLineList) {
|
Map<String, Integer> vnodeCounter = new HashMap<>();
|
vnodeCounter.put("vnodeCounter", 0);
|
RbdTreeNode root = new RbdTreeNode();
|
root.setAlgorithmType("series");
|
root.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
root.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
root.setNodeType("vnode");
|
|
ModelNode end = modelNodeList.stream().filter(item ->
|
"end".equals(item.getNodeType())).collect(Collectors.toList()).get(0);
|
RbdTreeNode endNode = new RbdTreeNode();
|
endNode.setId(end.getId());
|
endNode.setName("end");
|
endNode.setNodeType("end");
|
endNode.setPicId(end.getPicId());
|
endNode.setPairStartNodeId(end.getPairStartNodeId());
|
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);
|
recognizeOneBranch(root,
|
lineRight,
|
null,
|
modelNodeList,
|
modelLineList,
|
vnodeCounter);
|
|
return root;
|
}
|
|
private void recognizeOneBranch(RbdTreeNode parent,
|
ModelLine lineRight, // 串联的起始线(右边)
|
ModelLine lineLeft, // 串联的结束线(左边)
|
List<ModelNode> modelNodeList,
|
List<ModelLine> modelLineList,
|
Map<String, Integer> vnodeCounter) {
|
ModelLine inLine = lineRight;
|
for (; ; ) {
|
ModelLine searchLine = inLine;
|
ModelNode node = modelNodeList.stream().filter(item ->
|
searchLine.getBeginCell().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
if ("node".equals(node.getNodeType())) {
|
RbdTreeNode treeNode = new RbdTreeNode();
|
treeNode.setId(node.getId());
|
treeNode.setName(node.getName());
|
treeNode.setNodeType(node.getNodeType());
|
treeNode.setPicId(node.getPicId());
|
treeNode.setDataId(node.getDataId());
|
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);
|
} else if ("start".equals(node.getNodeType())) {
|
RbdTreeNode treeNode = new RbdTreeNode();
|
treeNode.setId(node.getId());
|
treeNode.setName(node.getNodeType());
|
treeNode.setNodeType(node.getNodeType());
|
treeNode.setPicId(node.getPicId());
|
treeNode.setObjectWidth(node.getWidth());
|
treeNode.setObjectHeight(node.getHeight());
|
parent.getChildren().add(treeNode);
|
break;
|
} else if ("connect".equals(node.getNodeType())) {
|
break;
|
} else if ("parallel,vote,switch,bridge".contains(node.getNodeType())) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
subNode.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNode.setNodeType("vnode");
|
parent.getChildren().add(subNode);
|
ModelNode connect = modelNodeList.stream().filter(item ->
|
node.getPairStartNodeId().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
RbdTreeNode treeNode = new RbdTreeNode();
|
treeNode.setId(connect.getId());
|
treeNode.setName(connect.getNodeType());
|
treeNode.setNodeType(connect.getNodeType());
|
treeNode.setPicId(connect.getPicId());
|
treeNode.setObjectWidth(connect.getWidth());
|
treeNode.setObjectHeight(connect.getHeight());
|
subNode.getChildren().add(treeNode);
|
RbdTreeNode subNodeOpe = new RbdTreeNode();
|
subNodeOpe.setAlgorithmType(node.getNodeType());
|
subNodeOpe.setId(UUIDUtil.generateId());
|
counter = vnodeCounter.get("vnodeCounter");
|
subNodeOpe.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNodeOpe.setNodeType("vnode");
|
subNodeOpe.setVoteNum(node.getVoteNum());
|
subNode.getChildren().add(subNodeOpe);
|
treeNode = new RbdTreeNode();
|
treeNode.setId(node.getId());
|
treeNode.setName(node.getNodeType());
|
treeNode.setNodeType(node.getNodeType());
|
treeNode.setPicId(node.getPicId());
|
treeNode.setPairStartNodeId(node.getPairStartNodeId());
|
treeNode.setObjectWidth(node.getWidth());
|
treeNode.setObjectHeight(node.getHeight());
|
subNode.getChildren().add(treeNode);
|
recognizeOpeBlock(subNodeOpe,
|
node,
|
modelNodeList,
|
modelLineList,
|
vnodeCounter);
|
inLine = modelLineList.stream().filter(item ->
|
item.getEndCell().equals(connect.getPicId())).collect(Collectors.toList()).get(0);
|
}
|
|
if (null != lineLeft) {
|
if (inLine.getPicId().equals(lineLeft.getPicId())) break;
|
}
|
}
|
if ("series".equals(parent.getAlgorithmType())) Collections.reverse(parent.getChildren());
|
}
|
|
private void recognizeOpeBlock(RbdTreeNode parent,
|
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 ->
|
item.getEndCell().equals(searchNode.getPicId())).collect(Collectors.toList());
|
List<ModelLine> sortedLines = sortLine(lines, modelNodeList);
|
for (ModelLine line : sortedLines) {
|
boolean isSeries = isSeriesBranch(rightNode, line, modelNodeList, modelLineList);
|
if (isSeries) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
subNode.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNode.setNodeType("vnode");
|
parent.getChildren().add(subNode);
|
recognizeOneBranch(subNode, line, null, modelNodeList, modelLineList, vnodeCounter);
|
} else {
|
recognizeOneBranch(parent, line, null, modelNodeList, modelLineList, vnodeCounter);
|
}
|
}
|
} else if ("bridge".contains(parent.getAlgorithmType())) {
|
ModelNode searchNode = rightNode;
|
List<ModelLine> linesRight = modelLineList.stream().filter(item ->
|
item.getEndCell().equals(searchNode.getPicId())).collect(Collectors.toList());
|
List<ModelLine> sortedLinesRight = sortLine(linesRight, modelNodeList);
|
List<ModelLine> linesLeft = modelLineList.stream().filter(item ->
|
item.getBeginCell().equals(searchNode.getPairStartNodeId())).collect(Collectors.toList());
|
List<ModelLine> sortedLinesLeft = sortLine(linesLeft, modelNodeList);
|
ModelLine lineTop = modelLineList.stream().filter(item ->
|
item.getPicId().equals(searchNode.getBridgeEdgeTopId())).collect(Collectors.toList()).get(0);
|
ModelLine lineBottom = modelLineList.stream().filter(item ->
|
item.getPicId().equals(searchNode.getBridgeEdgeBottomId())).collect(Collectors.toList()).get(0);
|
ModelLine verticalLineUpper = modelLineList.stream().filter(item ->
|
item.getBeginCell().equals(searchNode.getBridgeEdgeTopId())).collect(Collectors.toList()).get(0);
|
ModelLine verticalLineLower = modelLineList.stream().filter(item ->
|
item.getEndCell().equals(searchNode.getBridgeEdgeBottomId())).collect(Collectors.toList()).get(0);
|
// 桥联的第1个支路
|
if (isSeriesBranch(lineTop, sortedLinesLeft.get(0), modelNodeList, modelLineList)) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
subNode.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNode.setNodeType("vnode");
|
parent.getChildren().add(subNode);
|
recognizeOneBranch(subNode, lineTop, sortedLinesLeft.get(0), modelNodeList, modelLineList, vnodeCounter);
|
} else {
|
recognizeOneBranch(parent, lineTop, sortedLinesLeft.get(0), modelNodeList, modelLineList, vnodeCounter);
|
}
|
// 桥联的第2个支路
|
if (isSeriesBranch(sortedLinesRight.get(0), lineTop, modelNodeList, modelLineList)) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
subNode.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNode.setNodeType("vnode");
|
parent.getChildren().add(subNode);
|
recognizeOneBranch(subNode, sortedLinesRight.get(0), lineTop, modelNodeList, modelLineList, vnodeCounter);
|
} else {
|
recognizeOneBranch(parent, sortedLinesRight.get(0), lineTop, modelNodeList, modelLineList, vnodeCounter);
|
}
|
// 桥联的第3个支路
|
if (isSeriesBranch(verticalLineLower, verticalLineUpper, modelNodeList, modelLineList)) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
subNode.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNode.setNodeType("vnode");
|
parent.getChildren().add(subNode);
|
recognizeOneBranch(subNode, verticalLineLower, verticalLineUpper, modelNodeList, modelLineList, vnodeCounter);
|
} else {
|
recognizeOneBranch(parent, verticalLineLower, verticalLineUpper, modelNodeList, modelLineList, vnodeCounter);
|
}
|
// 桥联的第4个支路
|
if (isSeriesBranch(lineBottom, sortedLinesLeft.get(1), modelNodeList, modelLineList)) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
subNode.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNode.setNodeType("vnode");
|
parent.getChildren().add(subNode);
|
recognizeOneBranch(subNode, lineBottom, sortedLinesLeft.get(1), modelNodeList, modelLineList, vnodeCounter);
|
} else {
|
recognizeOneBranch(parent, lineBottom, sortedLinesLeft.get(1), modelNodeList, modelLineList, vnodeCounter);
|
}
|
// 桥联的第5个支路
|
if (isSeriesBranch(sortedLinesRight.get(1), lineBottom, modelNodeList, modelLineList)) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
int counter = vnodeCounter.get("vnodeCounter");
|
subNode.setName("v" + counter);
|
counter++;
|
vnodeCounter.put("vnodeCounter", counter);
|
subNode.setNodeType("vnode");
|
parent.getChildren().add(subNode);
|
recognizeOneBranch(subNode, sortedLinesRight.get(1), lineBottom, modelNodeList, modelLineList, vnodeCounter);
|
} else {
|
recognizeOneBranch(parent, sortedLinesRight.get(1), lineBottom, modelNodeList, modelLineList, vnodeCounter);
|
}
|
}
|
}
|
|
/**
|
* 按自上而下的顺序排序
|
*/
|
private List<ModelLine> sortLine(List<ModelLine> lines,
|
List<ModelNode> modelNodeList) {
|
for (ModelLine line : lines) {
|
ModelNode node = modelNodeList.stream().filter(item ->
|
line.getBeginCell().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
line.setBeginY(node.getPositionY());
|
}
|
lines.sort(Comparator.comparing(ModelLine::getBeginY));
|
|
return lines;
|
}
|
|
private boolean isSeriesBranch(ModelNode rightNode, // rbd中的右节点(包括end及4种运算符)
|
ModelLine line, // 右节点的入口线
|
List<ModelNode> modelNodeList,
|
List<ModelLine> modelLineList) {
|
boolean result = false;
|
ModelNode node = modelNodeList.stream().filter(item ->
|
line.getBeginCell().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
if ("node".equals(node.getNodeType())) {
|
ModelLine line1 = modelLineList.stream().filter(item ->
|
item.getEndCell().equals(node.getPicId())).collect(Collectors.toList()).get(0);
|
ModelNode node1 = modelNodeList.stream().filter(item ->
|
line1.getBeginCell().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
result = !node1.getPicId().equals(rightNode.getPairStartNodeId());
|
} else {
|
ModelNode node2 = modelNodeList.stream().filter(item ->
|
node.getPairStartNodeId().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
ModelLine line2 = modelLineList.stream().filter(item ->
|
item.getEndCell().equals(node2.getPicId())).collect(Collectors.toList()).get(0);
|
ModelNode node3 = modelNodeList.stream().filter(item ->
|
line2.getBeginCell().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
result = !node3.getPicId().equals(rightNode.getPairStartNodeId());
|
}
|
|
return result;
|
}
|
|
private boolean isSeriesBranch(ModelLine lineRight, // 串联的起始线(右边)
|
ModelLine lineLeft, // 串联的结束线(左边)
|
List<ModelNode> modelNodeList,
|
List<ModelLine> modelLineList) {
|
boolean result = false;
|
ModelNode node = modelNodeList.stream().filter(item ->
|
lineRight.getBeginCell().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
if ("node".equals(node.getNodeType())) {
|
ModelLine line1 = modelLineList.stream().filter(item ->
|
item.getEndCell().equals(node.getPicId())).collect(Collectors.toList()).get(0);
|
result = !line1.getPicId().equals(lineLeft.getPicId());
|
} else {
|
ModelNode node1 = modelNodeList.stream().filter(item ->
|
node.getPairStartNodeId().equals(item.getPicId())).collect(Collectors.toList()).get(0);
|
ModelLine line2 = modelLineList.stream().filter(item ->
|
item.getEndCell().equals(node1.getPicId())).collect(Collectors.toList()).get(0);
|
result = !line2.getPicId().equals(lineLeft.getPicId());
|
}
|
|
return result;
|
}
|
|
private boolean analyzeRbd(ModelRbd modelRbd, boolean saveFlag) {
|
boolean result = true;
|
String rbdsonStr = modelRbd.getContent();
|
|
JSONArray rbdJsonArray = new JSONObject(rbdsonStr).getJSONArray("cells");
|
if (rbdJsonArray == null) return result;
|
|
// 解析结果存放list
|
List<ModelNode> modelNodeList = new ArrayList<>();
|
List<ModelLine> modelLineList = new ArrayList<>();
|
List<Algorithm> algorithmList = new ArrayList<>();
|
List<ProductImg> productImgList = new ArrayList<>(); // 暂不使用(而使用数据库中的可靠性参数)
|
List<ModelNode> modelNodeAndVnodeList = new ArrayList<>();
|
|
// 1. 解析出节点与边
|
getNodeAndLineFromRbd(modelRbd.getId(), rbdJsonArray, modelNodeList, modelLineList, productImgList);
|
// 2. 转换为树型结构
|
RbdTreeNode root = recognizeRbd(modelNodeList, modelLineList);
|
// 3. 预处理
|
deleteSeriesForAutoArrange(root);
|
deleteStartEnd(root);
|
// 3. 生成算法
|
createAlgorithm(modelRbd.getId(), root, algorithmList, modelNodeAndVnodeList);
|
// 4. 保存模型
|
if (saveFlag) saveModel(modelRbd, algorithmList, modelNodeAndVnodeList);
|
|
return result;
|
}
|
|
private void createAlgorithm(Long modelId,
|
RbdTreeNode root,
|
List<Algorithm> algorithmList,
|
List<ModelNode> modelNodeAndVnodeList) {
|
List<RbdTreeNode> children = root.getChildren();
|
if (children.size() == 0) {
|
ModelNode node = new ModelNode();
|
node.setModelId(modelId);
|
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());
|
modelNodeAndVnodeList.add(node);
|
} else {
|
Algorithm algo = new Algorithm();
|
algo.setModelId(modelId);
|
algo.setId(root.getId());
|
algo.setComputerId(algo.getId());
|
algo.setAlgorithmType(root.getAlgorithmType());
|
algo.setModelType(algo.getAlgorithmType());
|
algo.setStep(Integer.valueOf(root.getName().substring(1)));
|
algo.setVoteNum(root.getVoteNum());
|
algo.setObjectList(root.getChildren().stream().map(item ->
|
item.getName()).collect(Collectors.joining(",")));
|
algo.setComputerList(root.getChildren().stream().map(item ->
|
item.getId().toString()).collect(Collectors.joining(",")));
|
algorithmList.add(algo);
|
ModelNode node = new ModelNode();
|
node.setModelId(modelId);
|
node.setId(root.getId());
|
node.setPicId(root.getPicId());
|
node.setDataId(root.getDataId());
|
node.setNodeType(root.getNodeType());
|
node.setName(root.getName());
|
node.setVoteNum(root.getVoteNum());
|
modelNodeAndVnodeList.add(node);
|
for (RbdTreeNode treeNode : root.getChildren()) {
|
createAlgorithm(modelId, treeNode, algorithmList, modelNodeAndVnodeList);
|
}
|
}
|
}
|
|
/**
|
* 对树形结构进行预处理,包括:
|
* 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(0);
|
if (children.size() > 1 ||
|
!"vnode".equals(children.get(0).getNodeType())) {
|
RbdTreeNode subNode = new RbdTreeNode();
|
subNode.setAlgorithmType("series");
|
subNode.setId(UUIDUtil.generateId());
|
subNode.setName("v0");
|
subNode.setNodeType("vnode");
|
subNode.getChildren().addAll(children);
|
List<RbdTreeNode> list = new ArrayList<>();
|
list.add(subNode);
|
root.setChildren(list);
|
}
|
}
|
|
/**
|
* 对树形结构进行预处理:
|
* 去掉逻辑运算块中用于排版的外层series
|
*
|
* @param root
|
*/
|
private void deleteSeriesForAutoArrange(RbdTreeNode root) {
|
List<RbdTreeNode> children = root.getChildren();
|
for (int i = 0; i < children.size(); i++) {
|
RbdTreeNode treeNode = children.get(i);
|
if ("vnode".equals(treeNode.getNodeType()) &&
|
"series".equals(treeNode.getAlgorithmType()) &&
|
"connect".equals(treeNode.getChildren().get(0).getNodeType())) {
|
children.set(i, treeNode.getChildren().get(1));
|
}
|
deleteSeriesForAutoArrange(children.get(i));
|
}
|
}
|
|
/**
|
* 用于自动排版:将桥联转换为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 calcPosition(JSONArray rbdJsonArray, RbdTreeNode block, Map<String, RbdTreeNode> nodeMap) {
|
if (block.getNodeType().equals("node")) {
|
setNodePositionXY(rbdJsonArray, block,nodeMap);
|
} else {
|
double blockWidth = block.getBlockWidthNum() * LAYOUT_CELL_SIZE_X;
|
double blockHeight = block.getBlockHeightNum() * LAYOUT_CELL_SIZE_Y;
|
|
Double descentWidth = block.getDescentWidth();
|
if (descentWidth == null || descentWidth == 0.0) {
|
descentWidth = blockWidth;
|
}
|
Double descentHeight = block.getDescentHeight();
|
if (descentHeight == null || descentHeight == 0.0) {
|
descentHeight = blockHeight;
|
}
|
|
block.setBlockWidth(blockWidth);
|
block.setBlockHeight(blockHeight);
|
List<RbdTreeNode> children = block.getChildren();
|
|
if (OPE_TYPE_SERIES.equals(block.getAlgorithmType())) {
|
Double subBlockX = block.getBlockX();
|
for (RbdTreeNode child : children) {
|
|
child.setDescentWidth(blockWidth);
|
child.setDescentHeight(blockHeight);
|
|
double selfWidth = child.getBlockWidthNum() * LAYOUT_CELL_SIZE_X * descentWidth / blockWidth;
|
child.setBlockWidth(selfWidth);
|
child.setBlockHeight(blockHeight);
|
|
child.setBlockY(block.getBlockY());
|
child.setBlockX(subBlockX);
|
calcPosition(rbdJsonArray, child, nodeMap);
|
subBlockX = subBlockX + selfWidth;
|
|
}
|
} else {
|
|
Double subBlockY = block.getBlockY() + (descentHeight - blockHeight) / 2;
|
Double firstSubBlockY = subBlockY;
|
|
// 设置connect的位置
|
RbdTreeNode connectBlock = new RbdTreeNode();
|
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());
|
connectBlock.setBlockY(firstSubBlockY);
|
connectBlock.setBlockWidth(LAYOUT_CELL_SIZE_X);
|
connectBlock.setBlockHeight(blockHeight);
|
setNodePositionXY(rbdJsonArray, connectBlock, nodeMap);
|
|
for (RbdTreeNode child : children) {
|
child.setDescentWidth(block.getBlockWidth() - 2 * LAYOUT_CELL_SIZE_X);
|
child.setDescentHeight(blockHeight);
|
|
child.setBlockWidth(block.getBlockWidth() - 2 * LAYOUT_CELL_SIZE_X);
|
child.setBlockHeight(child.getBlockHeightNum() * LAYOUT_CELL_SIZE_Y);
|
|
child.setBlockX(block.getBlockX() + LAYOUT_CELL_SIZE_X);
|
child.setBlockY(subBlockY);
|
subBlockY = subBlockY + child.getBlockHeightNum() * LAYOUT_CELL_SIZE_Y;
|
calcPosition(rbdJsonArray, child, nodeMap);
|
}
|
|
// 设置运算符的位置
|
RbdTreeNode opeBlock = new RbdTreeNode();
|
|
opeBlock.setPicId(block.getPicId());
|
opeBlock.setNodeType("parallel");
|
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);
|
opeBlock.setBlockHeight(blockHeight);
|
setNodePositionXY(rbdJsonArray, opeBlock, nodeMap);
|
}
|
}
|
|
}
|
*/
|
|
}
|