|
|
|
|
@ -1,17 +1,23 @@
|
|
|
|
|
package com.actionsoft.apps.coe.method.process.subprocess.graph;
|
|
|
|
|
|
|
|
|
|
import com.actionsoft.apps.coe.method.process.subprocess.constant.LinkerDefConstant;
|
|
|
|
|
import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst;
|
|
|
|
|
import com.actionsoft.apps.coe.method.process.subprocess.mode.Node;
|
|
|
|
|
import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager;
|
|
|
|
|
import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel;
|
|
|
|
|
import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.cache.DesignerShapeRelationCache;
|
|
|
|
|
import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel;
|
|
|
|
|
import com.actionsoft.apps.coe.pal.pal.repository.designer.util.CoeDesignerUtil;
|
|
|
|
|
import com.actionsoft.apps.coe.pal.pal.repository.designer.util.ShapeUtil;
|
|
|
|
|
import com.actionsoft.bpms.util.ConsolePrinter;
|
|
|
|
|
import com.actionsoft.bpms.util.UUIDGener;
|
|
|
|
|
import com.actionsoft.bpms.util.UtilString;
|
|
|
|
|
import com.actionsoft.exception.AWSException;
|
|
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 图节点展开处理
|
|
|
|
|
@ -22,46 +28,59 @@ public class GraphNodeExpandHandle {
|
|
|
|
|
private String shapeId; // 总图中当前要展开的子流程图形ID
|
|
|
|
|
private String relationFileId; // 当前要展开的子流程图形所标识模型文件ID
|
|
|
|
|
private CoeDesignerAPIManager apiManager;
|
|
|
|
|
private String childProcessDefine; // 要展开的子流程模型信息
|
|
|
|
|
private String endToEndProcessDefine; // 总图的模型信息
|
|
|
|
|
private JSONObject childProcessDefine; // 要展开的子流程模型信息
|
|
|
|
|
private JSONObject endToEndProcessDefine; // 总图的模型信息
|
|
|
|
|
private JSONObject scopeLimitationShape; // 范围标注框
|
|
|
|
|
|
|
|
|
|
public GraphNodeExpandHandle(String repositoryId, String shapeId) {
|
|
|
|
|
private double[] scopeLimitationShapeBeforePoi;
|
|
|
|
|
|
|
|
|
|
private final ReentrantLock lock = new ReentrantLock();
|
|
|
|
|
|
|
|
|
|
public GraphNodeExpandHandle(String repositoryId, String shapeId) throws AWSException{
|
|
|
|
|
this.repositoryId = repositoryId;
|
|
|
|
|
this.shapeId = shapeId;
|
|
|
|
|
|
|
|
|
|
apiManager = CoeDesignerAPIManager.getInstance();
|
|
|
|
|
|
|
|
|
|
readChildProcessDefine();
|
|
|
|
|
readCurrentProcessDefine();
|
|
|
|
|
try {
|
|
|
|
|
readChildProcessDefine();
|
|
|
|
|
readCurrentProcessDefine();
|
|
|
|
|
toAssembleScopeLimitationShape();
|
|
|
|
|
} catch (AWSException e) {
|
|
|
|
|
throw new AWSException(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 读取子流程节点的存储信息
|
|
|
|
|
* @throws AWSException
|
|
|
|
|
*/
|
|
|
|
|
public void readChildProcessDefine() throws AWSException{
|
|
|
|
|
private void readChildProcessDefine() throws AWSException{
|
|
|
|
|
List<DesignerShapeRelationModel> childProcessModelList = DesignerShapeRelationCache.getListByAttrId(repositoryId, shapeId, SubProcessConst.CHILD_PROCESS);
|
|
|
|
|
DesignerShapeRelationModel relationModel = childProcessModelList.stream().findFirst().orElse(null);
|
|
|
|
|
if (relationModel == null)
|
|
|
|
|
throw new AWSException("未找到当前节点所标识的子流程文件信息");
|
|
|
|
|
relationFileId = relationModel.getRelationFileId();
|
|
|
|
|
// 先去与总图存储的同级目录下读取 如果为空说明是初次读取
|
|
|
|
|
childProcessDefine = apiManager.getChildProcessDefine(repositoryId, 0, relationFileId);
|
|
|
|
|
if (UtilString.isEmpty(childProcessDefine)){ // 初次读取 去源文件目录读取
|
|
|
|
|
String childProcessDefineStr = apiManager.getChildProcessDefine(repositoryId, 0, relationFileId);
|
|
|
|
|
if (UtilString.isEmpty(childProcessDefineStr)){ // 初次读取 去源文件目录读取
|
|
|
|
|
BaseModel childProcessBaseModel = apiManager.getDefinition(relationFileId, 0);
|
|
|
|
|
childProcessDefine = childProcessBaseModel.getDefinition();
|
|
|
|
|
if (childProcessBaseModel == null)
|
|
|
|
|
throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开");
|
|
|
|
|
childProcessDefineStr = childProcessBaseModel.getDefinition();
|
|
|
|
|
}
|
|
|
|
|
childProcessDefine = JSONObject.parseObject(childProcessDefineStr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 读取当前总图的存储信息
|
|
|
|
|
* @throws AWSException
|
|
|
|
|
*/
|
|
|
|
|
public void readCurrentProcessDefine() throws AWSException{
|
|
|
|
|
private void readCurrentProcessDefine() throws AWSException{
|
|
|
|
|
BaseModel baseModel = apiManager.getDefinition(repositoryId, 0);
|
|
|
|
|
if (baseModel == null)
|
|
|
|
|
throw new AWSException("未找到当前总图存储的模型信息");
|
|
|
|
|
endToEndProcessDefine = baseModel.getDefinition();
|
|
|
|
|
endToEndProcessDefine = JSONObject.parseObject(baseModel.getDefinition());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -69,16 +88,40 @@ public class GraphNodeExpandHandle {
|
|
|
|
|
* @return 范围标注框
|
|
|
|
|
* @throws AWSException
|
|
|
|
|
*/
|
|
|
|
|
private JSONObject toAssembleScopeLimitationShape() throws AWSException{
|
|
|
|
|
private void toAssembleScopeLimitationShape() throws AWSException{
|
|
|
|
|
JSONObject scopeLimitationShape = ShapeUtil.getProcessShapeDefinition(SubProcessConst.SUB_PROCESS_METHOD_ID, "展开范围标注");
|
|
|
|
|
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefine);
|
|
|
|
|
JSONObject childProcessPage = childProcessDefineObj.getJSONObject("page");
|
|
|
|
|
JSONObject childProcessPage = childProcessDefine.getJSONObject("page");
|
|
|
|
|
JSONObject childProcessElements = childProcessDefine.getJSONObject("elements");
|
|
|
|
|
JSONObject childProcessEleMaxX = childProcessElements.keySet()
|
|
|
|
|
.stream()
|
|
|
|
|
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
|
|
|
|
|
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
|
|
|
|
|
.max((o1, o2) -> Double.compare(o1.getDoubleValue("x"), o2.getDoubleValue("x"))).get();
|
|
|
|
|
JSONObject childProcessEleMixX = childProcessElements.keySet()
|
|
|
|
|
.stream()
|
|
|
|
|
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
|
|
|
|
|
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
|
|
|
|
|
.min((o1, o2) -> Double.compare(o1.getDoubleValue("x"), o2.getDoubleValue("x"))).get();
|
|
|
|
|
JSONObject childProcessEleMaxY = childProcessElements.keySet()
|
|
|
|
|
.stream()
|
|
|
|
|
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
|
|
|
|
|
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
|
|
|
|
|
.max((o1, o2) -> Double.compare(o1.getDoubleValue("y"), o2.getDoubleValue("y"))).get();
|
|
|
|
|
JSONObject childProcessEleMinY = childProcessElements.keySet()
|
|
|
|
|
.stream()
|
|
|
|
|
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
|
|
|
|
|
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
|
|
|
|
|
.min((o1, o2) -> Double.compare(o1.getDoubleValue("y"), o2.getDoubleValue("y"))).get();
|
|
|
|
|
// 当前节点所标识的子流程文件的 画布宽度与高度 减去边距
|
|
|
|
|
double childProcessPageWidth = childProcessPage.getDoubleValue("width") - childProcessPage.getDoubleValue("padding") * 2;
|
|
|
|
|
double childProcessPageHeight = childProcessPage.getDoubleValue("height") - childProcessPage.getDoubleValue("padding") * 2;
|
|
|
|
|
// double childProcessPageWidth = childProcessPage.getDoubleValue("width") - childProcessPage.getDoubleValue("padding") * 2;
|
|
|
|
|
// double childProcessPageHeight = childProcessPage.getDoubleValue("height") - childProcessPage.getDoubleValue("padding") * 2;
|
|
|
|
|
double scopeShapeW = childProcessEleMaxX.getDoubleValue("x") + childProcessEleMaxX.getDoubleValue("w") - childProcessEleMixX.getDoubleValue("x") + SubProcessConst.SCOPE_SHAPE_PADDING;
|
|
|
|
|
double scopeShapeH = childProcessEleMaxY.getDoubleValue("y") + childProcessEleMaxY.getDoubleValue("h") - childProcessEleMinY.getDoubleValue("y") + SubProcessConst.SCOPE_SHAPE_PADDING;
|
|
|
|
|
|
|
|
|
|
JSONObject endToEndProcessDefineObj = JSONObject.parseObject(endToEndProcessDefine);
|
|
|
|
|
JSONObject elements = endToEndProcessDefineObj.getJSONObject("elements");
|
|
|
|
|
// 计算下范围选择框在子流程所代表的模型文件的坐标
|
|
|
|
|
scopeLimitationShapeBeforePoi = new double[]{childProcessEleMixX.getDoubleValue("x") - SubProcessConst.SCOPE_SHAPE_PADDING / 2, childProcessEleMinY.getDoubleValue("y") - SubProcessConst.SCOPE_SHAPE_PADDING / 2};
|
|
|
|
|
|
|
|
|
|
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
|
|
|
|
|
// 找到当前要展开的子流程节点
|
|
|
|
|
JSONObject currentExpandShape = elements.getJSONObject(shapeId);
|
|
|
|
|
if (currentExpandShape == null)
|
|
|
|
|
@ -87,47 +130,196 @@ public class GraphNodeExpandHandle {
|
|
|
|
|
double x = props.getDoubleValue("x");
|
|
|
|
|
double y = props.getDoubleValue("y");
|
|
|
|
|
// 当前要展开的子流程节点的坐标赋给范围标注框
|
|
|
|
|
scopeLimitationShape.put("id", shapeId);
|
|
|
|
|
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
|
|
|
|
|
scopeShapeProps.put("x", x);
|
|
|
|
|
scopeShapeProps.put("y", y);
|
|
|
|
|
scopeShapeProps.put("w", childProcessPageWidth);
|
|
|
|
|
scopeShapeProps.put("h", childProcessPageHeight);
|
|
|
|
|
scopeShapeProps.put("w", scopeShapeW);
|
|
|
|
|
scopeShapeProps.put("h", scopeShapeH);
|
|
|
|
|
scopeShapeProps.put("zindex", 1);
|
|
|
|
|
return scopeLimitationShape;
|
|
|
|
|
this.scopeLimitationShape = scopeLimitationShape;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理子流程中所有节点的坐标
|
|
|
|
|
* 节点展开
|
|
|
|
|
* @param direction 排布方向
|
|
|
|
|
* @throws Exception
|
|
|
|
|
* @return 节点展开后的模型存储信息
|
|
|
|
|
*/
|
|
|
|
|
public void handleRelationModelNodePosition(){
|
|
|
|
|
public String handleNodeExpand(String direction) throws Exception{
|
|
|
|
|
|
|
|
|
|
// Thread t1 = new Thread(() -> {
|
|
|
|
|
// // 1、总图节点以及连线处理
|
|
|
|
|
// handleEndToEndGraphNodeAndLinker(direction);
|
|
|
|
|
// });
|
|
|
|
|
// t1.start();
|
|
|
|
|
//
|
|
|
|
|
// Thread t2 = new Thread(() -> {
|
|
|
|
|
// // 2、子流程节点内部元素处理
|
|
|
|
|
// handleRelationModelNodePosition();
|
|
|
|
|
// });
|
|
|
|
|
// t2.start();
|
|
|
|
|
//
|
|
|
|
|
// t1.join();
|
|
|
|
|
// t2.join();
|
|
|
|
|
|
|
|
|
|
// 1、总图节点以及连线处理
|
|
|
|
|
handleEndToEndGraphNodeAndLinker(direction);
|
|
|
|
|
|
|
|
|
|
// 2、子流程节点内部元素处理
|
|
|
|
|
handleRelationModelNodePosition();
|
|
|
|
|
|
|
|
|
|
// 6、保存总图模型信息 以及 子流程模型信息备份
|
|
|
|
|
// BaseModel baseModel = apiManager.getDefinition(repositoryId, 0);
|
|
|
|
|
// baseModel.setDefinition(endToEndProcessDefine.toJSONString());
|
|
|
|
|
// apiManager.storeDefinition(baseModel);
|
|
|
|
|
// apiManager.storeChildProcessDefine(baseModel, relationFileId, childProcessDefine.toJSONString());
|
|
|
|
|
return endToEndProcessDefine.toJSONString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理总图中的节点与连线
|
|
|
|
|
* 1、删除待展开的节点
|
|
|
|
|
* 2、替换为范围选择框
|
|
|
|
|
* 3、节点x > 范围标注框x || 节点y < 范围标注框y 针对符合条件的节点 进行坐标调整
|
|
|
|
|
* 4、根据旧有连线关系构建邻接矩阵
|
|
|
|
|
* 5、获取当前总图中的所有节点的坐标
|
|
|
|
|
* 6、删除旧有连线关系
|
|
|
|
|
* 7、构建新的连线关系
|
|
|
|
|
*/
|
|
|
|
|
private void handleEndToEndGraphNodeAndLinker(String direction){
|
|
|
|
|
// 1、删除当前要展开的节点
|
|
|
|
|
removeEndToEndGraphElements(shapeId);
|
|
|
|
|
|
|
|
|
|
// 2、添加到总图中
|
|
|
|
|
addEndToEndGraphElements(scopeLimitationShape);
|
|
|
|
|
|
|
|
|
|
// 3、总图中符合范围选择框条件的节点 坐标更新
|
|
|
|
|
handleEndToEndGraphNodeExcluedExpandNode();
|
|
|
|
|
|
|
|
|
|
// 4、构建邻接矩阵
|
|
|
|
|
NodeExpandAdjMatrix expandAdjMatrix = buildEndToEndGraphAdjMatrix();
|
|
|
|
|
expandAdjMatrix.buildAdjMatrix();
|
|
|
|
|
// 5、删除节点展开前的连线
|
|
|
|
|
removeEndToEndGraphOldLinker();
|
|
|
|
|
// 6、获取所有节点坐标
|
|
|
|
|
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
|
|
|
|
|
double[][] vertexPosition = expandAdjMatrix.getVertexPosition(elements);
|
|
|
|
|
// 7、构建新的连线
|
|
|
|
|
NodeExpandLinkerRender linkerRender = new NodeExpandLinkerRender(vertexPosition, expandAdjMatrix, scopeLimitationShape);
|
|
|
|
|
JSONArray linkers = linkerRender.toAssembleLinker(direction, shapeId);
|
|
|
|
|
for (Object o : linkers) {
|
|
|
|
|
JSONObject linker = (JSONObject) o;
|
|
|
|
|
addEndToEndGraphElements(linker);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理待展开节点所代表的流程文件中的节点的坐标
|
|
|
|
|
*/
|
|
|
|
|
private void handleRelationModelNodePosition(){
|
|
|
|
|
// 范围标注框 坐标
|
|
|
|
|
JSONObject scopeLimitationShape = toAssembleScopeLimitationShape();
|
|
|
|
|
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
|
|
|
|
|
double scopeShapeX = scopeShapeProps.getDoubleValue("x");
|
|
|
|
|
double scopeShapeY = scopeShapeProps.getDoubleValue("y");
|
|
|
|
|
|
|
|
|
|
double distanceX = scopeShapeX - scopeLimitationShapeBeforePoi[0];
|
|
|
|
|
double distanceY = scopeShapeY - scopeLimitationShapeBeforePoi[1];
|
|
|
|
|
|
|
|
|
|
// 根据范围标注框的坐标 调整子流程所有元素的坐标
|
|
|
|
|
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefine);
|
|
|
|
|
JSONObject elements = childProcessDefineObj.getJSONObject("elements");
|
|
|
|
|
JSONObject elements = childProcessDefine.getJSONObject("elements");
|
|
|
|
|
for (String key : elements.keySet()) {
|
|
|
|
|
JSONObject ele = elements.getJSONObject(key);
|
|
|
|
|
JSONObject props = ele.getJSONObject("props");
|
|
|
|
|
props.put("x", scopeShapeX + props.getDoubleValue("x"));
|
|
|
|
|
props.put("y", scopeShapeY + props.getDoubleValue("y"));
|
|
|
|
|
// 元素分为两类 一类为图形 一类为连线
|
|
|
|
|
if ("linker".equals(ele.getString("name"))){ // 连线的话折点需要额外处理
|
|
|
|
|
if ("linker".equals(ele.getString("name"))){ // 连线
|
|
|
|
|
JSONObject from = ele.getJSONObject("from");
|
|
|
|
|
from.put("x", distanceX + from.getDoubleValue("x"));
|
|
|
|
|
from.put("y", distanceY + from.getDoubleValue("y"));
|
|
|
|
|
JSONObject to = ele.getJSONObject("to");
|
|
|
|
|
to.put("x", distanceX + to.getDoubleValue("x"));
|
|
|
|
|
to.put("y", distanceY + to.getDoubleValue("y"));
|
|
|
|
|
// 连线的话折点也需要处理
|
|
|
|
|
JSONArray points = ele.getJSONArray("points");
|
|
|
|
|
for (Object p : points) {
|
|
|
|
|
JSONObject point = (JSONObject) p;
|
|
|
|
|
point.put("x", point.getDoubleValue("x") + scopeShapeX);
|
|
|
|
|
point.put("y", point.getDoubleValue("y") + scopeShapeY);
|
|
|
|
|
point.put("x", point.getDoubleValue("x") + distanceX);
|
|
|
|
|
point.put("y", point.getDoubleValue("y") + distanceY);
|
|
|
|
|
}
|
|
|
|
|
}else { // 图形
|
|
|
|
|
JSONObject props = ele.getJSONObject("props");
|
|
|
|
|
props.put("x", distanceX + props.getDoubleValue("x"));
|
|
|
|
|
props.put("y", distanceY + props.getDoubleValue("y"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addEndToEndGraphElements(ele);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理总图中的节点
|
|
|
|
|
* 节点x > 范围标注框x || 节点y < 范围标注框y
|
|
|
|
|
* 针对符合条件的节点 进行坐标调整
|
|
|
|
|
*/
|
|
|
|
|
private void handleEndToEndGraphNodeExcluedExpandNode(){
|
|
|
|
|
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
|
|
|
|
|
// 范围标注框 大小 位置
|
|
|
|
|
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
|
|
|
|
|
double scopeShapeX = scopeShapeProps.getDoubleValue("x");
|
|
|
|
|
double scopeShapeY = scopeShapeProps.getDoubleValue("y");
|
|
|
|
|
double scopeShapeW = scopeShapeProps.getDoubleValue("w");
|
|
|
|
|
double scopeShapeH = scopeShapeProps.getDoubleValue("h");
|
|
|
|
|
|
|
|
|
|
for (String key : elements.keySet()) {
|
|
|
|
|
JSONObject ele = elements.getJSONObject(key);
|
|
|
|
|
if ("linker".equals(ele.getString("name"))) continue; // 连线先不处理
|
|
|
|
|
JSONObject props = ele.getJSONObject("props");
|
|
|
|
|
if (props.getDoubleValue("x") > scopeShapeX) { // 当前元素在待展开节点的右侧
|
|
|
|
|
props.put("x", props.getDoubleValue("x") + scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W);
|
|
|
|
|
}
|
|
|
|
|
if (props.getDoubleValue("y") > scopeShapeY) { // 当前元素在待展开节点的下侧
|
|
|
|
|
props.put("y", props.getDoubleValue("y") + scopeShapeH - SubProcessConst.SUB_PROCESS_SHAPE_H);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addEndToEndGraphElements(ele);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 构建节点展开前 端到端总图的邻接矩阵
|
|
|
|
|
* 方便后续节点展开或者闭合进行重新连线
|
|
|
|
|
*/
|
|
|
|
|
private NodeExpandAdjMatrix buildEndToEndGraphAdjMatrix(){
|
|
|
|
|
|
|
|
|
|
List<String> nodeIdList = new ArrayList<>();
|
|
|
|
|
List<JSONObject> linkerList = new ArrayList<>();
|
|
|
|
|
JSONObject endToEndProcessElements = endToEndProcessDefine.getJSONObject("elements");
|
|
|
|
|
for (String key : endToEndProcessElements.keySet()) {
|
|
|
|
|
JSONObject ele = endToEndProcessElements.getJSONObject(key);
|
|
|
|
|
if ("linker".equals(ele.getString("name"))) {
|
|
|
|
|
linkerList.add(ele);
|
|
|
|
|
}else {
|
|
|
|
|
nodeIdList.add(key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NodeExpandAdjMatrix expandAdjMatrix = new NodeExpandAdjMatrix(nodeIdList, linkerList);
|
|
|
|
|
return expandAdjMatrix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找到总图中 x坐标 >= 范围标注框x坐标 y坐标 >= 范围标注框y坐标 的图形
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 删除总图中节点展开前的连线
|
|
|
|
|
*/
|
|
|
|
|
private void removeEndToEndGraphOldLinker(){
|
|
|
|
|
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
|
|
|
|
|
Set<String> eleKeys = new HashSet<>();
|
|
|
|
|
for (String key : elements.keySet()) {
|
|
|
|
|
JSONObject ele = elements.getJSONObject(key);
|
|
|
|
|
if ("linker".equals(ele.getString("name"))){
|
|
|
|
|
eleKeys.add(key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (String eleKey : eleKeys) {
|
|
|
|
|
removeEndToEndGraphElements(eleKey);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -136,6 +328,404 @@ public class GraphNodeExpandHandle {
|
|
|
|
|
*/
|
|
|
|
|
public void storeChildProcessDefine(){
|
|
|
|
|
BaseModel baseModel = apiManager.getDefinition(relationFileId, 0);
|
|
|
|
|
apiManager.storeChildProcessDefine(baseModel, relationFileId, childProcessDefine);
|
|
|
|
|
apiManager.storeChildProcessDefine(baseModel, relationFileId, childProcessDefine.toJSONString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 总图中添加元素
|
|
|
|
|
* @param ele
|
|
|
|
|
*/
|
|
|
|
|
private void addEndToEndGraphElements(JSONObject ele){
|
|
|
|
|
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
|
|
|
|
|
String id = ele.getString("id");
|
|
|
|
|
lock.lock();
|
|
|
|
|
try{
|
|
|
|
|
elements.put(id, ele);
|
|
|
|
|
}finally {
|
|
|
|
|
lock.unlock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 总图中删除元素
|
|
|
|
|
* @param key
|
|
|
|
|
*/
|
|
|
|
|
private void removeEndToEndGraphElements(String key){
|
|
|
|
|
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
|
|
|
|
|
lock.lock();
|
|
|
|
|
try{
|
|
|
|
|
elements.remove(key);
|
|
|
|
|
}finally {
|
|
|
|
|
lock.unlock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 节点展开的邻接矩阵
|
|
|
|
|
*/
|
|
|
|
|
class NodeExpandAdjMatrix{
|
|
|
|
|
|
|
|
|
|
private int[][] adjMatrix;
|
|
|
|
|
private List<String> nodeIds;
|
|
|
|
|
private List<JSONObject> linkerList;
|
|
|
|
|
|
|
|
|
|
public NodeExpandAdjMatrix(List<String> nodeIds, List<JSONObject> linkerList) {
|
|
|
|
|
this.adjMatrix = new int[nodeIds.size()][nodeIds.size()];
|
|
|
|
|
this.nodeIds = nodeIds;
|
|
|
|
|
this.linkerList = linkerList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 添加一条从顶点 u 到顶点 v 的有向边。
|
|
|
|
|
*/
|
|
|
|
|
public void addEdge(int u, int v) {
|
|
|
|
|
adjMatrix[u][v] = 1; // 设置邻接矩阵中相应的位置为 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取从顶点 u 出发可以到达的所有顶点。
|
|
|
|
|
*/
|
|
|
|
|
public List<Integer> getNeighbors(int u) {
|
|
|
|
|
List<Integer> neighbors = new ArrayList<>();
|
|
|
|
|
for (int i = 0; i < nodeIds.size(); i++) {
|
|
|
|
|
if (adjMatrix[u][i] == 1) {
|
|
|
|
|
neighbors.add(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return neighbors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 判断从顶点 u 是否可以到达顶点 v。
|
|
|
|
|
*/
|
|
|
|
|
public boolean hasEdge(int u, int v) {
|
|
|
|
|
return adjMatrix[u][v] == 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取邻接矩阵
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public int[][] getAdjMatrix(){
|
|
|
|
|
return adjMatrix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<String> getNodeIds() {
|
|
|
|
|
return nodeIds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<JSONObject> getLinkerList() {
|
|
|
|
|
return linkerList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 构建邻接矩阵
|
|
|
|
|
*/
|
|
|
|
|
public void buildAdjMatrix(){
|
|
|
|
|
for (JSONObject linker : linkerList) {
|
|
|
|
|
JSONObject from = linker.getJSONObject("from");
|
|
|
|
|
JSONObject to = linker.getJSONObject("to");
|
|
|
|
|
int fromIndex = nodeIds.indexOf(from.getString("id"));
|
|
|
|
|
int toIndex = nodeIds.indexOf(to.getString("id"));
|
|
|
|
|
addEdge(fromIndex, toIndex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 输出邻接矩阵
|
|
|
|
|
public void printAdjMatrix() {
|
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
|
for (int i = 0; i < nodeIds.size(); i++) {
|
|
|
|
|
for (int j = 0; j < nodeIds.size(); j++) {
|
|
|
|
|
sb.append(adjMatrix[i][j]).append(" ");
|
|
|
|
|
}
|
|
|
|
|
sb.append("\n");
|
|
|
|
|
}
|
|
|
|
|
System.out.println(sb.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取总图中节点展开前的所有节点坐标
|
|
|
|
|
* @param elements
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public double[][] getVertexPosition(JSONObject elements){
|
|
|
|
|
double[][] position = new double[nodeIds.size()][2];
|
|
|
|
|
for (int i = 0; i < nodeIds.size(); i++) {
|
|
|
|
|
JSONObject shape = elements.getJSONObject(nodeIds.get(i));
|
|
|
|
|
JSONObject props = shape.getJSONObject("props");
|
|
|
|
|
double x = props.getDoubleValue("x");
|
|
|
|
|
double y = props.getDoubleValue("y");
|
|
|
|
|
position[i][0] = x;
|
|
|
|
|
position[i][1] = y;
|
|
|
|
|
}
|
|
|
|
|
return position;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 节点展开后连线重构
|
|
|
|
|
*/
|
|
|
|
|
class NodeExpandLinkerRender{
|
|
|
|
|
|
|
|
|
|
private List<String> nodeIds; // 图形节点ID集合
|
|
|
|
|
private double[][] vertexPosition; // 所有节点的坐标
|
|
|
|
|
private NodeExpandAdjMatrix expandAdjMatrix; // 节点矩阵
|
|
|
|
|
private JSONObject scopeLimitationShape; // 范围标注框
|
|
|
|
|
|
|
|
|
|
public NodeExpandLinkerRender(double[][] vertexPosition, NodeExpandAdjMatrix expandAdjMatrix, JSONObject scopeLimitationShape) {
|
|
|
|
|
this.nodeIds = expandAdjMatrix.getNodeIds();
|
|
|
|
|
this.vertexPosition = vertexPosition;
|
|
|
|
|
this.expandAdjMatrix = expandAdjMatrix;
|
|
|
|
|
this.scopeLimitationShape = scopeLimitationShape;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据连线方向 组装连线
|
|
|
|
|
* @param direction 连线方向
|
|
|
|
|
* @param shapeId 当前待展开节点ID
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public JSONArray toAssembleLinker(String direction, String shapeId){
|
|
|
|
|
JSONArray linkers = new JSONArray();
|
|
|
|
|
int index = nodeIds.indexOf(shapeId);
|
|
|
|
|
for (int i = 0; i < vertexPosition.length; i++) {
|
|
|
|
|
boolean currentExpandNodeIsStart = false;
|
|
|
|
|
if (i == index){
|
|
|
|
|
currentExpandNodeIsStart = true; // 当前待展开的节点此处应是范围选择框为连线的出发点
|
|
|
|
|
}
|
|
|
|
|
double[] fromPoi = vertexPosition[i];
|
|
|
|
|
List<Integer> nextNodeIndex = expandAdjMatrix.getNeighbors(i);
|
|
|
|
|
if (nextNodeIndex.size() > 0){ // 说明当前节点有连线
|
|
|
|
|
for (Integer nodeIndex : nextNodeIndex) {
|
|
|
|
|
boolean currentExpandNodeIsEnd = false;
|
|
|
|
|
if (nodeIndex.intValue() == index){
|
|
|
|
|
currentExpandNodeIsEnd = true; // 当前待展开的节点 此处应是范围选择框为连线的终点
|
|
|
|
|
}
|
|
|
|
|
double[] toPoi = vertexPosition[nodeIndex];
|
|
|
|
|
double[][] turnPoi = "horizontal".equals(direction)
|
|
|
|
|
? calculationLinkerPointInHorizLayOut(fromPoi, toPoi, currentExpandNodeIsStart, currentExpandNodeIsEnd)
|
|
|
|
|
: calculationLinkerPointInVertLayOut(fromPoi, toPoi, currentExpandNodeIsStart, currentExpandNodeIsEnd);
|
|
|
|
|
double[] angleArr = calculationLinkerAngle(fromPoi, toPoi, turnPoi[1], turnPoi[turnPoi.length - 2]);
|
|
|
|
|
// 构建连线
|
|
|
|
|
JSONObject linkerObj = JSONObject.parseObject(LinkerDefConstant.linker);
|
|
|
|
|
linkerObj.put("id", UUIDGener.getObjectId());
|
|
|
|
|
// 折点
|
|
|
|
|
JSONArray points = new JSONArray();
|
|
|
|
|
for (int j = 0; j < turnPoi.length; j++) {
|
|
|
|
|
if (j > 0 && j < turnPoi.length - 1){
|
|
|
|
|
JSONObject pointObj = new JSONObject();
|
|
|
|
|
pointObj.put("x", turnPoi[j][0]);
|
|
|
|
|
pointObj.put("y", turnPoi[j][1]);
|
|
|
|
|
points.add(pointObj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
linkerObj.put("points", points);
|
|
|
|
|
// 起点与终点
|
|
|
|
|
JSONObject fromObj = new JSONObject();
|
|
|
|
|
fromObj.put("x", turnPoi[0][0]);
|
|
|
|
|
fromObj.put("y", turnPoi[0][1]);
|
|
|
|
|
fromObj.put("angle", angleArr[0]);
|
|
|
|
|
fromObj.put("id", nodeIds.get(i));
|
|
|
|
|
linkerObj.put("from", fromObj);
|
|
|
|
|
JSONObject toObj = new JSONObject();
|
|
|
|
|
toObj.put("x", turnPoi[turnPoi.length - 1][0]);
|
|
|
|
|
toObj.put("y", turnPoi[turnPoi.length - 1][1]);
|
|
|
|
|
toObj.put("angle", angleArr[1]);
|
|
|
|
|
toObj.put("id", nodeIds.get(nodeIndex.intValue()));
|
|
|
|
|
linkerObj.put("to", toObj);
|
|
|
|
|
|
|
|
|
|
linkers.add(linkerObj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return linkers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double[][] calculationLinkerPointInVertLayOut(double[] fromPoi, double[] toPoi, boolean currentExpandNodeIsStart, boolean currentExpandNodeIsEnd) {
|
|
|
|
|
double fromX = fromPoi[0],fromY = fromPoi[1],toX = toPoi[0],toY = toPoi[1];
|
|
|
|
|
double scopeShapeW = scopeLimitationShape.getDoubleValue("w"), scopeShapeH = scopeLimitationShape.getDoubleValue("h");
|
|
|
|
|
if (fromY == toY){ // 水平 分析可知 水平方向上不会出现 从左到右直连的情况 只有 右边节点右侧锚点出 向上走 左折 连到左侧节点上方锚点
|
|
|
|
|
double[] startPoi = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
double[] turnPoi1 = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
double[] turnPoi2 = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2};
|
|
|
|
|
double[] turnPoi3 = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2};
|
|
|
|
|
double[] endPoi = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
|
|
|
|
|
return new double[][]{startPoi, turnPoi1, turnPoi2, turnPoi3, endPoi};
|
|
|
|
|
}else if (fromX == toX){ // 垂直 分析可知 垂直方向上应该不会有 toY < fromY 的情况 鉴于数据不确定性 先写上
|
|
|
|
|
double[] startPoi = fromY < toY
|
|
|
|
|
? new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)}
|
|
|
|
|
: new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
double[] endPoi = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
|
|
|
|
|
return fromY < toY
|
|
|
|
|
? new double[][]{
|
|
|
|
|
startPoi,
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
endPoi}
|
|
|
|
|
: new double[][]{
|
|
|
|
|
startPoi,
|
|
|
|
|
{fromX + ((currentExpandNodeIsStart || currentExpandNodeIsEnd) ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + ((currentExpandNodeIsStart || currentExpandNodeIsEnd) ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
endPoi};
|
|
|
|
|
}else { // 分布在四个象限内
|
|
|
|
|
if (fromX > toX && fromY > toY){ // 目标节点在第二象限
|
|
|
|
|
return new double[][]{
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
|
|
|
|
|
};
|
|
|
|
|
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限
|
|
|
|
|
return toY - fromY == SubProcessConst.SHAPE_VERT_INTERVAL
|
|
|
|
|
? new double[][]
|
|
|
|
|
{
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
|
|
|
|
|
}
|
|
|
|
|
: new double[][]
|
|
|
|
|
{
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
|
|
|
|
|
};
|
|
|
|
|
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
|
|
|
|
|
return new double[][]{
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
|
|
|
|
|
};
|
|
|
|
|
}else {
|
|
|
|
|
// fromX < toX && fromY > toY 目标节点在第一象限 分析可知 纵向排布的情况下 应该不会出现目标节点在第一象限的情况
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return new double[2][2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double[][] calculationLinkerPointInHorizLayOut(double[] fromPoi, double[] toPoi, boolean currentExpandNodeIsStart, boolean currentExpandNodeIsEnd) {
|
|
|
|
|
double fromX = fromPoi[0],fromY = fromPoi[1],toX = toPoi[0],toY = toPoi[1];
|
|
|
|
|
double scopeShapeW = scopeLimitationShape.getDoubleValue("w"), scopeShapeH = scopeLimitationShape.getDoubleValue("h");
|
|
|
|
|
if (fromY == toY) { // 水平 方向上 存在从左向右直连的情况 但不存在从右向左直连的情况 水平方向上 从左向右 应是 右出 向上 左折 向下
|
|
|
|
|
return fromX < toX
|
|
|
|
|
? new double[][]
|
|
|
|
|
{
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{toX - SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2}
|
|
|
|
|
}
|
|
|
|
|
: new double[][]
|
|
|
|
|
{
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
|
|
|
|
|
};
|
|
|
|
|
}else if (fromX == toX) { // 垂直
|
|
|
|
|
// 节点横向分布 连线按照大原则 垂直 不存在 fromY < toY 的情况 也就是不存在 连线从上到下直连的情况
|
|
|
|
|
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
|
|
|
|
|
return new double[][]{startPoint,
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
endPoint};
|
|
|
|
|
}else {
|
|
|
|
|
if (fromX < toX && fromY > toY){ // 目标节点在第一象限
|
|
|
|
|
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
double turnPointX = fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
|
|
|
|
|
if (fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
|
|
|
|
|
double[] endPoint = new double[]{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
return new double[][]{startPoint,{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},{turnPointX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2}, endPoint};
|
|
|
|
|
}else { // 不相邻节点 存在三个折点
|
|
|
|
|
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
|
|
|
|
|
return new double[][]{
|
|
|
|
|
startPoint,
|
|
|
|
|
{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{turnPointX, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
endPoint
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}else if (fromX > toX && fromY > toY) { // 目标节点在第二象限 无论节点是否相邻 都按照三个折点走
|
|
|
|
|
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
|
|
|
|
|
return new double[][]{
|
|
|
|
|
startPoint,
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
endPoint
|
|
|
|
|
};
|
|
|
|
|
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
|
|
|
|
|
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
if (fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
|
|
|
|
|
double turnPointX = fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
|
|
|
|
|
double[] endPoint = new double[]{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
|
|
|
|
|
return new double[][]{
|
|
|
|
|
startPoint,
|
|
|
|
|
{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{turnPointX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
endPoint
|
|
|
|
|
};
|
|
|
|
|
}else { // 不相邻节点 存在三个折点
|
|
|
|
|
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
|
|
|
|
|
return new double[][]{
|
|
|
|
|
startPoint,
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
|
|
|
|
|
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
|
|
|
|
endPoint
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 横向布局的情况下 应该不会出现目标节点在第三象限的情况
|
|
|
|
|
ConsolePrinter.warn("[端到端功能][节点展开模块]处理连线时目标节点在[横向布局]的情况下出现在了第三象限");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return new double[2][2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 计算angle值
|
|
|
|
|
* @param fromPoi 起始节点坐标
|
|
|
|
|
* @param toPoi 结束节点坐标
|
|
|
|
|
* @param firstTurnPoi 连线第一个折点坐标
|
|
|
|
|
* @param lastTurnPoi 连线最后一个折点坐标
|
|
|
|
|
* @return [0]: from的angle [1]: to的angle
|
|
|
|
|
*/
|
|
|
|
|
private double[] calculationLinkerAngle(double[] fromPoi, double[] toPoi, double[] firstTurnPoi, double[] lastTurnPoi){
|
|
|
|
|
double fromX = fromPoi[0], fromY = fromPoi[1];
|
|
|
|
|
double toX = toPoi[0], toY = toPoi[1];
|
|
|
|
|
double firstTurnX = firstTurnPoi[0], firstTurnY = firstTurnPoi[1];
|
|
|
|
|
double lastTurnX = lastTurnPoi[0], lastTurnY = lastTurnPoi[1];
|
|
|
|
|
|
|
|
|
|
if (fromY == toY){ // 水平
|
|
|
|
|
return fromX < toX ? new double[]{LinkerDefConstant.ANGLE_LEFT, LinkerDefConstant.ANGLE_RIGHT} : new double[]{LinkerDefConstant.ANGLE_RIGHT, LinkerDefConstant.ANGLE_LEFT};
|
|
|
|
|
}else if (fromX == toX){ // 垂直
|
|
|
|
|
return fromY < toY ? new double[]{LinkerDefConstant.ANGLE_UP, LinkerDefConstant.ANGLE_DOWN} : new double[]{LinkerDefConstant.ANGLE_DOWN, LinkerDefConstant.ANGLE_UP};
|
|
|
|
|
}else {
|
|
|
|
|
double fromAngle = 0.0;
|
|
|
|
|
if (fromY == firstTurnY){ // 水平
|
|
|
|
|
fromAngle = fromX < firstTurnX ? LinkerDefConstant.ANGLE_LEFT : LinkerDefConstant.ANGLE_RIGHT;
|
|
|
|
|
}else if (fromX == firstTurnX){ // 垂直
|
|
|
|
|
fromAngle = fromY < firstTurnY ? LinkerDefConstant.ANGLE_UP : LinkerDefConstant.ANGLE_DOWN;
|
|
|
|
|
}
|
|
|
|
|
double toAngle = 0.0;
|
|
|
|
|
if (toY == lastTurnY){ // 水平
|
|
|
|
|
toAngle = toX < lastTurnX ? LinkerDefConstant.ANGLE_LEFT : LinkerDefConstant.ANGLE_RIGHT;
|
|
|
|
|
}else if (toX == lastTurnX){ // 垂直
|
|
|
|
|
toAngle = toY < lastTurnY ? LinkerDefConstant.ANGLE_UP : LinkerDefConstant.ANGLE_DOWN;
|
|
|
|
|
}
|
|
|
|
|
return new double[]{fromAngle, toAngle};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|