端到端功能 连线相关代码提交
This commit is contained in:
parent
a46cba6ceb
commit
075507553c
Binary file not shown.
@ -0,0 +1,13 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.constant;
|
||||
|
||||
public class LinkerDefConstant {
|
||||
|
||||
// 构造连线时的几个固定参数
|
||||
public static final double ANGLE_RIGHT = 0;
|
||||
public static final double ANGLE_DOWN = 1.5707963267948968;
|
||||
public static final double ANGLE_LEFT = 3.141592653589793;
|
||||
public static final double ANGLE_UP = 4.71238898038469;
|
||||
|
||||
public static final String linker = "{\"fontStyle\":{\"fontFamily\":\"Arial\",\"size\":13,\"color\":\"50,50,50\",\"underline\":false,\"textAlign\":\"center\",\"bold\":false,\"italic\":false},\"points\":[],\"dataAttributes\":[{\"shapeDesc\":\"\",\"name\":\"AWSProperties\",\"id\":\"AWSPropertiesID\",\"type\":\"string\",\"category\":\"default\",\"value\":\"\"}],\"props\":{\"zindex\":0},\"linkerType\":\"broken\",\"lineStyle\":{\"lineStyle\":\"solid\",\"lineColor\":\"50,50,50\",\"beginArrowStyle\":\"none\",\"endArrowStyle\":\"solidArrow\",\"lineWidth\":1},\"name\":\"linker\",\"orderIndex\":0,\"from\":{\"x\":0,\"y\":0,\"angle\":0,\"id\":\"\"},\"id\":\"\",\"text\":\"\",\"to\":{\"x\":0,\"y\":0,\"angle\":0,\"id\":\"\"},\"locked\":false,\"group\":\"\"}";
|
||||
|
||||
}
|
||||
@ -20,4 +20,14 @@ public interface SubProcessConst {
|
||||
|
||||
// 后置流程属性key
|
||||
String REAR_PROCESS_ATTR_ID = "rear_process";
|
||||
|
||||
// 子流程图形宽度
|
||||
double SUB_PROCESS_SHAPE_W = 100.0;
|
||||
// 子流程图形高度
|
||||
double SUB_PROCESS_SHAPE_H = 70.0;
|
||||
|
||||
// 图形间垂直间隔
|
||||
double SHAPE_VERT_INTERVAL = 80.0;
|
||||
// 图形间水平间隔
|
||||
double SHAPE_HORIZ_INTERVAL = 80.0;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.mode.Node;
|
||||
|
||||
import java.util.*;
|
||||
@ -29,11 +30,11 @@ public class GraphLayout {
|
||||
this.nodeList = nodeList;
|
||||
this.isPosition = new boolean[nodeList.size()];
|
||||
|
||||
this.vertInterval = 50.0;
|
||||
this.horizInterval = 80.0;
|
||||
this.vertInterval = SubProcessConst.SHAPE_VERT_INTERVAL;
|
||||
this.horizInterval = SubProcessConst.SHAPE_HORIZ_INTERVAL;
|
||||
|
||||
this.shapeW = 100.0;
|
||||
this.shapeH = 70.0;
|
||||
this.shapeW = SubProcessConst.SUB_PROCESS_SHAPE_W;
|
||||
this.shapeH = SubProcessConst.SUB_PROCESS_SHAPE_H;
|
||||
|
||||
this.position = new double[nodeList.size()][2];
|
||||
}
|
||||
|
||||
@ -1,38 +1,287 @@
|
||||
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.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 图形节点连线渲染
|
||||
* 图形节点连线渲染的类
|
||||
*
|
||||
* 假设每一个节点以自己为中心 类比直角坐标系
|
||||
* 那么与其相连的其它节点位置大体分布在
|
||||
* 垂直方向的y轴、水平方向的x轴、第一象限、第二象限、第三象限、第四象限
|
||||
*
|
||||
* 以此为依据 连线大体分为两类 无明显折点、有明显折点
|
||||
* 其中有明显折点又细分出4种(仅限本次需求)
|
||||
*/
|
||||
public class GraphLinkerRender {
|
||||
|
||||
private String linkerId;
|
||||
private Node fromNode;
|
||||
private Node toNode;
|
||||
private double[] fromPoi;
|
||||
private double[] toPoi;
|
||||
private double[][] vertexPosition; // 所有节点的坐标
|
||||
private String linkerDefine;
|
||||
private final List<Node> nodeList; // 节点集合
|
||||
private final double[][] vertexPosition; // 所有节点的坐标
|
||||
private final GraphAdjMatrix graphAdjMatrix;
|
||||
|
||||
public GraphLinkerRender(double[][] vertexPosition) {
|
||||
public GraphLinkerRender(List<Node> nodeList, double[][] vertexPosition, GraphAdjMatrix graphAdjMatrix) {
|
||||
this.nodeList = nodeList;
|
||||
this.vertexPosition = vertexPosition;
|
||||
this.graphAdjMatrix = graphAdjMatrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染连线
|
||||
* @param linkerId
|
||||
* @return
|
||||
*/
|
||||
public JSONArray renderLinker(String linkerId){
|
||||
JSONArray linkers = new JSONArray();
|
||||
for (int i = 0; i < vertexPosition.length; i++) {
|
||||
double[] fromPoi = vertexPosition[i];
|
||||
List<Integer> nextNodeIndex = graphAdjMatrix.getNeighbors(i);
|
||||
if (nextNodeIndex.size() > 0){ // 说明当前节点有连线
|
||||
for (Integer nodeIndex : nextNodeIndex) {
|
||||
double[] toPoi = vertexPosition[nodeIndex];
|
||||
double[][] turnPoi = calculationStartAndEndAndTurningPoint(fromPoi, toPoi);
|
||||
double[] angleArr = calculationLinkerAngle(fromPoi, toPoi, turnPoi[1], turnPoi[turnPoi.length - 2]);
|
||||
// 构建连线
|
||||
JSONObject linkerObj = JSONObject.parseObject(LinkerDefConstant.linker);
|
||||
linkerObj.put("id", linkerId);
|
||||
// 折点
|
||||
JSONArray points = new JSONArray();
|
||||
for (double[] point : turnPoi) {
|
||||
JSONObject pointObj = new JSONObject();
|
||||
pointObj.put("x", point[0]);
|
||||
pointObj.put("y", point[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", nodeList.get(i).getId());
|
||||
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", nodeList.get(nodeIndex.intValue()).getId());
|
||||
|
||||
linkers.add(linkerObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return linkers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算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};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个坐标之间的折点
|
||||
* @param fromPoi
|
||||
* @param toPoi
|
||||
* @return
|
||||
* @param fromPoi 起始图形节点坐标(左上角)
|
||||
* @param toPoi 终点图形节点坐标(左上角)
|
||||
* @return [0]: 连线起始点坐标、[1]: 连线第一个折点、[2]: 连线第二个折点、[3]: 连线第三个折点(如果存在)、[n]: 最后一个为连线终点 中间都为折点
|
||||
*/
|
||||
private double[][] calculationTurningPoint(double[] fromPoi, double[] toPoi){
|
||||
double fromX = fromPoi[0];
|
||||
double fromY = fromPoi[1];
|
||||
|
||||
double toX = toPoi[0];
|
||||
double toY = toPoi[1];
|
||||
|
||||
|
||||
private double[][] calculationStartAndEndAndTurningPoint(double[] fromPoi, double[] toPoi){
|
||||
double fromX = fromPoi[0],fromY = fromPoi[1],toX = toPoi[0],toY = toPoi[1];
|
||||
if (fromY == toY) { // 水平
|
||||
double[] startPoint = (fromX < toX)
|
||||
? new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2}
|
||||
: new double[]{fromX, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
double turnPointX = (fromX < toX)
|
||||
? fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + (toX - (fromX + SubProcessConst.SUB_PROCESS_SHAPE_W)) / 2
|
||||
: toX + SubProcessConst.SUB_PROCESS_SHAPE_W + (fromX - (toX + SubProcessConst.SUB_PROCESS_SHAPE_W)) / 2;
|
||||
double[] endPoint = (fromX < toX)
|
||||
? new double[]{toX, toY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2}
|
||||
: new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W, toY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
return new double[][]{startPoint, {turnPointX, toY + (SubProcessConst.SUB_PROCESS_SHAPE_H / 2)},{turnPointX, toY + (SubProcessConst.SUB_PROCESS_SHAPE_H)}, endPoint};
|
||||
}else if (fromX == toX) { // 垂直
|
||||
double[] startPoint = (fromY < toY)
|
||||
? new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H}
|
||||
: new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, fromY};
|
||||
double turnPointY = (fromY < toY)
|
||||
? fromY + SubProcessConst.SUB_PROCESS_SHAPE_H + (toY - (fromY + SubProcessConst.SUB_PROCESS_SHAPE_H)) / 2
|
||||
: toY + SubProcessConst.SUB_PROCESS_SHAPE_H + (fromY - (toY + SubProcessConst.SUB_PROCESS_SHAPE_H)) / 2;
|
||||
double[] endPoint = (fromY < toY)
|
||||
? new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY}
|
||||
: new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
return new double[][]{startPoint, {fromX + (SubProcessConst.SUB_PROCESS_SHAPE_W / 2), turnPointY},{fromX + (SubProcessConst.SUB_PROCESS_SHAPE_W / 2), turnPointY}, endPoint};
|
||||
}else {
|
||||
if (fromX < toX && fromY > toY){ // 目标节点在第一象限
|
||||
double[] startPoint = new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
double turnPointX = fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
|
||||
if (fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
|
||||
double[] endPoint = new double[]{toX, toY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
return new double[][]{startPoint,{turnPointX, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2},{turnPointX, toY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2}, endPoint};
|
||||
}else { // 不相邻节点 存在三个折点
|
||||
double[] endPoint = new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{turnPointX, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2},
|
||||
{turnPointX, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
endPoint
|
||||
};
|
||||
}
|
||||
}else if (fromX > toX && fromY > toY){ // 目标节点在第二象限 无论节点是否相邻 都按照三个折点走
|
||||
double[] startPoint = new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
double[] endPoint = new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2},
|
||||
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
endPoint
|
||||
};
|
||||
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限
|
||||
double[] startPoint = new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H};
|
||||
double[] endPoint = new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
endPoint
|
||||
};
|
||||
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
|
||||
double[] startPoint = new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
if (fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
|
||||
double turnPointX = fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
|
||||
double[] endPoint = new double[]{toX, toY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{turnPointX, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2},
|
||||
{turnPointX, toY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2},
|
||||
endPoint
|
||||
};
|
||||
}else { // 不相邻节点 存在三个折点
|
||||
double[] endPoint = new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY + SubProcessConst.SUB_PROCESS_SHAPE_H};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2},
|
||||
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY + SubProcessConst.SUB_PROCESS_SHAPE_H + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
|
||||
endPoint
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return new double[2][2];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断连线是否与矩形节点相交
|
||||
*
|
||||
* @param startX 连线起点横坐标
|
||||
* @param startY 连线起点纵坐标
|
||||
* @param endX 连线终点横坐标
|
||||
* @param endY 连线终点纵坐标
|
||||
* @param rectX1 矩形左上角横坐标
|
||||
* @param rectY1 矩形左上角纵坐标
|
||||
* @param rectX2 矩形右下角横坐标
|
||||
* @param rectY2 矩形右下角纵坐标
|
||||
* @return true表示相交/false表示不相交
|
||||
*/
|
||||
public boolean isLineIntersectRect(double startX, double startY, double endX, double endY, double rectX1, double rectY1, double rectX2, double rectY2) {
|
||||
// 计算连线的斜率和截距
|
||||
double k = (endY - startY) / (endX - startX);
|
||||
double b = startY - k * startX;
|
||||
|
||||
// 判断连线是否在矩形外部
|
||||
if (endX < rectX1 || startX > rectX2 || endY < rectY1 || startY > rectY2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 判断连线是否从矩形内部穿过
|
||||
double[] xVals = new double[] { startX, endX };
|
||||
double[] yVals = new double[] { startY, endY };
|
||||
for (int i = 0; i < 2; i++) {
|
||||
double x = xVals[i], y = yVals[i];
|
||||
|
||||
// 判断交点是否在矩形有效范围内
|
||||
if (x >= rectX1 && x <= rectX2 && y >= rectY1 && y <= rectY2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 计算连线与矩形边界的交点
|
||||
double[] crossPoints = new double[4];
|
||||
crossPoints[0] = getXOnRectTop(k, b, rectY1); // 计算连线与矩形上边界的交点横坐标
|
||||
crossPoints[1] = getXOnRectBottom(k, b, rectY2); // 计算连线与矩形下边界的交点横坐标
|
||||
crossPoints[2] = getYOnRectLeft(k, b, rectX1); // 计算连线与矩形左边界的交点纵坐标
|
||||
crossPoints[3] = getYOnRectRight(k, b, rectX2); // 计算连线与矩形右边界的交点纵坐标
|
||||
|
||||
// 判断交点是否在连线的起止点之间
|
||||
for (double crossPoint : crossPoints) {
|
||||
if (crossPoint >= startX && crossPoint <= endX) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算连线与矩形上边界的交点横坐标
|
||||
*/
|
||||
private double getXOnRectTop(double k, double b, double y) {
|
||||
return (y - b) / k;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算连线与矩形下边界的交点横坐标
|
||||
*/
|
||||
private double getXOnRectBottom(double k, double b, double y) {
|
||||
return (y - b) / k;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算连线与矩形左边界的交点纵坐标
|
||||
*/
|
||||
private double getYOnRectLeft(double k, double b, double x) {
|
||||
return k * x + b;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
计算连线与矩形右边界的交点纵坐标
|
||||
*/
|
||||
private double getYOnRectRight(double k, double b, double x) {
|
||||
return k * x + b;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user