端到端功能 范围框内外元素 连线处理
This commit is contained in:
		
							parent
							
								
									99edb3460c
								
							
						
					
					
						commit
						18018f8c7b
					
				
										
											Binary file not shown.
										
									
								
							| @ -38,4 +38,23 @@ public interface SubProcessConst { | |||||||
| 
 | 
 | ||||||
|     // 范围选择框内边距 |     // 范围选择框内边距 | ||||||
|     double SCOPE_SHAPE_PADDING = 300; |     double SCOPE_SHAPE_PADDING = 300; | ||||||
|  | 
 | ||||||
|  |     // 子流程节点上扩展的属性名 用来存储当前子流程节点标识的模型文件信息 | ||||||
|  |     String EXTEND_ATTR = "extendAttr"; | ||||||
|  | 
 | ||||||
|  |     // 节点展开时 范围框上扩镇的属性名 用来存储自身内部元素 | ||||||
|  |     String INNER_ELEMENTS = "innerElements"; | ||||||
|  | 
 | ||||||
|  |     // 流程接口图形的唯一标识 | ||||||
|  |     String SHAPE_NAME_PROCEDURE = "procedure"; | ||||||
|  | 
 | ||||||
|  |     // 范围框 内部前置或者后置流程接口元素 的特殊属性名 | ||||||
|  |     String SHAPE_PROCEDURE_ATTR_MARK = "attrMark"; | ||||||
|  | 
 | ||||||
|  |     // 水平布局 | ||||||
|  |     String DIRECTION_H = "horizontal"; | ||||||
|  | 
 | ||||||
|  |     // 垂直布局 | ||||||
|  |     String DIRECTION_V = "vertically"; | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,229 @@ | |||||||
|  | package com.actionsoft.apps.coe.method.process.subprocess.graph; | ||||||
|  | 
 | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType; | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.LinkerPointCalculationHandle; | ||||||
|  | import com.alibaba.fastjson.JSONArray; | ||||||
|  | import com.alibaba.fastjson.JSONObject; | ||||||
|  | 
 | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author oYang | ||||||
|  |  * @Description 端到端总图 连线后置处理 | ||||||
|  |  *              针对展开或者闭合节点上的连线进行后置处理 | ||||||
|  |  *              此时总图的状态是节点展开或者闭合已经处理 | ||||||
|  |  *              展开的话连线此时是连在了范围框上 此处处理的是将范围框上的连线连到内部节点上(如果此节点存在的话) | ||||||
|  |  *              闭合的话连线此时是连在了范围框的内部节点上(也有可能是在范围框上 范围框上不处理) 此处处理的是将内部节点的连线连到闭合后的子流程节点上 | ||||||
|  |  * @createTime 2023年06月28日 13:47:00 | ||||||
|  |  */ | ||||||
|  | public class ExpandOrCloseShapeLinkerConvertHandle { | ||||||
|  | 
 | ||||||
|  |     private AbstractDefinitionHandle definitionHandle; // 总图的存储模型define处理器 | ||||||
|  |     private LinkerPointCalculationHandle linkerPointCalculationHandle; // 连线上起始点以及折点处理器 | ||||||
|  |     private String direction; // 当前布局方式 | ||||||
|  | 
 | ||||||
|  |     public ExpandOrCloseShapeLinkerConvertHandle(AbstractDefinitionHandle definitionHandle) { | ||||||
|  |         this.definitionHandle = definitionHandle; | ||||||
|  | 
 | ||||||
|  |         this.linkerPointCalculationHandle = new LinkerPointCalculationHandle(definitionHandle); | ||||||
|  | 
 | ||||||
|  |         JSONObject processProperties = definitionHandle.getProcessProperties(); | ||||||
|  |         this.direction = processProperties.getString("direction"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public void scopeShapeLinkerHandle(){ | ||||||
|  | 
 | ||||||
|  |         Set<String> scopeShapeIds = definitionHandle.getElements().keySet().stream().filter(key -> definitionHandle.getElementTypeByKey(key).name().equals(ElementType.SCOPE_NODE.name())).collect(Collectors.toSet()); | ||||||
|  |         if (scopeShapeIds.size() > 0){ | ||||||
|  |             for (String shapeId : scopeShapeIds) { | ||||||
|  |                 // 1、准备当前展开的子流程节点的前置连线与后置连线 | ||||||
|  |                 JSONArray linkers = definitionHandle.getLinkers(); | ||||||
|  |                 // 2、准备当前展开的子流程节点的内部元素中的流程接口 其中代表前置/后置流程文件属性的流程接口上会有 attrMark 属性 | ||||||
|  |                 JSONObject scopeShape = definitionHandle.getShapeByKey(shapeId); | ||||||
|  |                 JSONArray innerEleKeyArr = scopeShape.getJSONArray(SubProcessConst.INNER_ELEMENTS); | ||||||
|  |                 // 获取当前范围框 内部前置或者后置流程接口元素集合 | ||||||
|  |                 JSONArray procedureArr = innerEleKeyArr | ||||||
|  |                         .stream() | ||||||
|  |                         .filter(innerEleKey -> definitionHandle.getElementTypeByKey(innerEleKey.toString()).name().equals(ElementType.INNER_NODE.name())) | ||||||
|  |                         .filter(innerEleKey -> SubProcessConst.SHAPE_NAME_PROCEDURE.equals(definitionHandle.getShapeByKey(innerEleKey.toString()).getString("name"))) | ||||||
|  |                         .filter(innerEleKey -> definitionHandle.getShapeByKey(innerEleKey.toString()).containsKey(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK)) | ||||||
|  |                         .map(innerEleKey -> definitionHandle.getShapeByKey(innerEleKey.toString())) | ||||||
|  |                         .collect(Collectors.toCollection(JSONArray::new)); | ||||||
|  | 
 | ||||||
|  |                 // 3、找到当前节点的所有前置连线 | ||||||
|  |                 JSONArray leadNodeLinkers = linkers | ||||||
|  |                         .stream() | ||||||
|  |                         .filter(l -> shapeId.equals(((JSONObject) l).getJSONObject("to").getString("id"))) | ||||||
|  |                         .collect(Collectors.toCollection(JSONArray::new)); | ||||||
|  |                 // 3.1、判断当前展开的子流程节点的内部元素中的流程接口上的文件标识 是否存在  前置子流程节点所代表的子流程文件 如果有将当前前置连线转为 与内部流程接口相连 | ||||||
|  |                 for (Object o1 : leadNodeLinkers) { | ||||||
|  |                     JSONObject leadNodeLinker = (JSONObject) o1; | ||||||
|  |                     String leadNodeId = leadNodeLinker.getJSONObject("from").getString("id"); | ||||||
|  |                     ElementType leadNodeType = definitionHandle.getElementTypeByKey(leadNodeId); | ||||||
|  |                     JSONObject leadNode = definitionHandle.getShapeByKey(leadNodeId); | ||||||
|  |                     if (procedureArr.size() > 0){ // 范围框内部存在前置或者后置流程接口 | ||||||
|  |                         // 判断当前前置节点的类型 如果未展开 继续判断内部节点是否与其有关联 如果有重新渲染连线 没有不处理 | ||||||
|  |                         if (leadNodeType.name().equals(ElementType.OUTER_NODE.name()) || leadNodeType.name().equals(ElementType.SCOPE_NODE.name())){ | ||||||
|  |                             // 获取前置节点的扩展属性 | ||||||
|  |                             JSONObject extendAttr = leadNode.getJSONObject(SubProcessConst.EXTEND_ATTR); | ||||||
|  |                             // 当前前置节点 所代表的子流程文件ID | ||||||
|  |                             String leadNodeRelationId = extendAttr.getString("id"); | ||||||
|  |                             // 1、未展开 子流程节点 | ||||||
|  |                             // 2、此时前置节点为范围框 同时说明之前范围框内部没有节点与当前节点有关联关系 | ||||||
|  |                             //    判断当前节点内部是否有流程接口 与范围框有关联关系 因为范围框本身也是一个文件 | ||||||
|  |                             for (Object o2 : procedureArr) { | ||||||
|  |                                 JSONObject procedure = (JSONObject) o2; | ||||||
|  |                                 JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK); | ||||||
|  |                                 String procedureNodeRelationId = attrMark.getString("id"); | ||||||
|  |                                 if (leadNodeRelationId.equals(procedureNodeRelationId)){ // 前置节点与内部流程接口有关联关系 | ||||||
|  |                                     // 删除当前 前置节点与范围框上的连线 | ||||||
|  |                                     definitionHandle.removeShape(leadNodeLinker.getString("id")); | ||||||
|  |                                     // 重新渲染当前 前置节点与范围框的连线 | ||||||
|  |                                     String procedureId = procedure.getString("id"); | ||||||
|  |                                     double[] fromBounding = new double[]{definitionHandle.getShapeX(leadNodeId), definitionHandle.getShapeY(leadNodeId), definitionHandle.getShapeW(leadNodeId), definitionHandle.getShapeH(leadNodeId)}; | ||||||
|  |                                     double[] toBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)}; | ||||||
|  |                                     JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, leadNodeId, procedureId, fromBounding, toBounding); | ||||||
|  |                                     // 连线属于内外交叉连线 加个特殊标识属性 | ||||||
|  |                                     linker.put("elementType", ElementType.CROSS_LINKER.name()); | ||||||
|  |                                     definitionHandle.addEle(linker.getString("id"), linker); | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         }else { // 已展开 内部节点 | ||||||
|  |                             // 此时前置节点为某一个范围框的内部节点 找到当前内部节点归属哪个范围框 判断当前范围框是否与当前展开的内部流程接口有关联 | ||||||
|  |                             String scopeShapeId = leadNode.getString("scopeShapeId"); | ||||||
|  |                             for (Object o2 : procedureArr) { | ||||||
|  |                                 JSONObject procedure = (JSONObject) o2; | ||||||
|  |                                 JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK); | ||||||
|  |                                 String procedureNodeRelationId = attrMark.getString("id"); | ||||||
|  |                                 if (procedureNodeRelationId.equals(scopeShapeId)){ // 前置内部节点所在的范围框 与 内部流程接口有关联关系 | ||||||
|  |                                     String procedureId = procedure.getString("id"); | ||||||
|  |                                     double[] fromBounding = new double[]{definitionHandle.getShapeX(scopeShapeId), definitionHandle.getShapeY(scopeShapeId), definitionHandle.getShapeW(scopeShapeId), definitionHandle.getShapeH(scopeShapeId)}; | ||||||
|  |                                     double[] toBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)}; | ||||||
|  |                                     JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, scopeShapeId, procedureId, fromBounding, toBounding); | ||||||
|  |                                     // 连线属于内外交叉连线 加个特殊标识属性 | ||||||
|  |                                     linker.put("elementType", ElementType.CROSS_LINKER.name()); | ||||||
|  |                                     definitionHandle.addEle(linker.getString("id"), linker); | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 // 4、根据后置连线找到后置子流程节点 | ||||||
|  |                 JSONArray rearNodeLinkers = linkers | ||||||
|  |                         .stream() | ||||||
|  |                         .filter(l -> shapeId.equals(((JSONObject) l).getJSONObject("from").getString("id"))) | ||||||
|  |                         .collect(Collectors.toCollection(JSONArray::new)); | ||||||
|  |                 // 4.1、同3.1 | ||||||
|  |                 for (Object o1 : rearNodeLinkers) { | ||||||
|  |                     JSONObject rearNodeLinker = (JSONObject) o1; | ||||||
|  |                     String rearNodeId = rearNodeLinker.getJSONObject("to").getString("id"); | ||||||
|  |                     ElementType rearNodeType = definitionHandle.getElementTypeByKey(rearNodeId); | ||||||
|  |                     JSONObject rearNode = definitionHandle.getShapeByKey(rearNodeId); | ||||||
|  |                     if (procedureArr.size() > 0){ // 范围框内部存在前置或者后置流程接口 | ||||||
|  |                         if (rearNodeType.name().equals(ElementType.OUTER_NODE.name()) || rearNodeType.name().equals(ElementType.SCOPE_NODE.name())){ | ||||||
|  |                             JSONObject extendAttr = rearNode.getJSONObject(SubProcessConst.EXTEND_ATTR); | ||||||
|  |                             // 当前后置节点 所代表的子流程文件ID | ||||||
|  |                             String rearNodeRelationId = extendAttr.getString("id"); | ||||||
|  |                             for (Object o2 : procedureArr) { | ||||||
|  |                                 JSONObject procedure = (JSONObject) o2; | ||||||
|  |                                 JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK); | ||||||
|  |                                 String procedureNodeRelationId = attrMark.getString("id"); | ||||||
|  |                                 if (rearNodeRelationId.equals(procedureNodeRelationId)){ // 后置节点与内部流程接口有关联关系 | ||||||
|  |                                     definitionHandle.removeShape(rearNodeLinker.getString("id")); | ||||||
|  |                                     // 重新渲染当前 前置节点与范围框的连线 | ||||||
|  |                                     String procedureId = procedure.getString("id"); | ||||||
|  |                                     double[] fromBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)}; | ||||||
|  |                                     double[] toBounding = new double[]{definitionHandle.getShapeX(rearNodeId), definitionHandle.getShapeY(rearNodeId), definitionHandle.getShapeW(rearNodeId), definitionHandle.getShapeH(rearNodeId)}; | ||||||
|  |                                     JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, procedureId, rearNodeId, fromBounding, toBounding); | ||||||
|  |                                     // 连线属于内外交叉连线 加个特殊标识属性 | ||||||
|  |                                     linker.put("elementType", ElementType.CROSS_LINKER.name()); | ||||||
|  |                                     definitionHandle.addEle(linker.getString("id"), linker); | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         }else { | ||||||
|  |                             // 此时后置节点为某一个范围框的内部节点 找到当前内部节点归属哪个范围框 判断当前范围框是否与当前展开的内部流程接口有关联 | ||||||
|  |                             String scopeShapeId = rearNode.getString("scopeShapeId"); | ||||||
|  |                             for (Object o2 : procedureArr) { | ||||||
|  |                                 JSONObject procedure = (JSONObject) o2; | ||||||
|  |                                 JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK); | ||||||
|  |                                 String procedureNodeRelationId = attrMark.getString("id"); | ||||||
|  |                                 if (procedureNodeRelationId.equals(scopeShapeId)){ // 前置内部节点所在的范围框 与 内部流程接口有关联关系 | ||||||
|  |                                     String procedureId = procedure.getString("id"); | ||||||
|  |                                     double[] fromBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)}; | ||||||
|  |                                     double[] toBounding = new double[]{definitionHandle.getShapeX(scopeShapeId), definitionHandle.getShapeY(scopeShapeId), definitionHandle.getShapeW(scopeShapeId), definitionHandle.getShapeH(scopeShapeId)}; | ||||||
|  |                                     JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, procedureId, scopeShapeId, fromBounding, toBounding); | ||||||
|  |                                     // 连线属于内外交叉连线 加个特殊标识属性 | ||||||
|  |                                     linker.put("elementType", ElementType.CROSS_LINKER.name()); | ||||||
|  |                                     definitionHandle.addEle(linker.getString("id"), linker); | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 针对闭合的节点相关连线 后置处理 | ||||||
|  |      */ | ||||||
|  |     public void closeShapeLinkerConvertHandle(){ | ||||||
|  | //        JSONObject subProcessNode = definitionHandle.getShapeByKey(shapeId); | ||||||
|  | //        JSONObject extendAttr = subProcessNode.getJSONObject(SubProcessConst.EXTEND_ATTR); | ||||||
|  | //        JSONArray linkers = definitionHandle.getLinkers(); | ||||||
|  | //        // 当前节点的前置节点 | ||||||
|  | //        JSONArray leadNodeArr = extendAttr.getJSONArray("leadNodeArr"); | ||||||
|  | //        if (leadNodeArr.size() > 0){ | ||||||
|  | //            for (Object o : leadNodeArr) { | ||||||
|  | //                String leadNodeId = (String) o; | ||||||
|  | //                Set<String> linkerIds = linkers.stream() | ||||||
|  | //                        .filter(l -> ((JSONObject) l).getJSONObject("from").getString("id").equals(leadNodeId) && ((JSONObject) l).getJSONObject("to").getString("id").equals(shapeId)) | ||||||
|  | //                        .map(l -> ((JSONObject) l).getString("id")) | ||||||
|  | //                        .collect(Collectors.toSet()); | ||||||
|  | //                if (linkerIds.size() > 0){ | ||||||
|  | //                    for (String linkerId : linkerIds) { | ||||||
|  | //                        definitionHandle.removeShape(linkerId); | ||||||
|  | //                    } | ||||||
|  | //                } | ||||||
|  | //                // 生成连线 | ||||||
|  | //                double[] fromBounding = new double[]{definitionHandle.getShapeX(leadNodeId), definitionHandle.getShapeY(leadNodeId), definitionHandle.getShapeW(leadNodeId), definitionHandle.getShapeH(leadNodeId)}; | ||||||
|  | //                double[] toBounding = new double[]{definitionHandle.getShapeX(shapeId), definitionHandle.getShapeY(shapeId), definitionHandle.getShapeW(shapeId), definitionHandle.getShapeH(shapeId)}; | ||||||
|  | //                JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, leadNodeId, shapeId, fromBounding, toBounding); | ||||||
|  | // | ||||||
|  | //                linker.put("elementType", ElementType.OUTER_LINKER.name()); | ||||||
|  | //                definitionHandle.addEle(linker.getString("id"), linker); | ||||||
|  | //            } | ||||||
|  | //        } | ||||||
|  | //        // 当前节点的后置节点 | ||||||
|  | //        JSONArray rearNodeArr = extendAttr.getJSONArray("rearNodeArr"); | ||||||
|  | //        if (rearNodeArr.size() > 0){ | ||||||
|  | //            for (Object o : rearNodeArr) { | ||||||
|  | //                String rearNodeId = (String) o; | ||||||
|  | //                Set<String> linkerIds = linkers.stream() | ||||||
|  | //                        .filter(l -> ((JSONObject) l).getJSONObject("from").getString("id").equals(shapeId) && ((JSONObject) l).getJSONObject("to").getString("id").equals(rearNodeId)) | ||||||
|  | //                        .map(l -> ((JSONObject) l).getString("id")) | ||||||
|  | //                        .collect(Collectors.toSet()); | ||||||
|  | //                if (linkerIds.size() > 0){ | ||||||
|  | //                    for (String linkerId : linkerIds) { | ||||||
|  | //                        definitionHandle.removeShape(linkerId); | ||||||
|  | //                    } | ||||||
|  | //                } | ||||||
|  | //                // 生成连线 | ||||||
|  | //                double[] fromBounding = new double[]{definitionHandle.getShapeX(shapeId), definitionHandle.getShapeY(shapeId), definitionHandle.getShapeW(shapeId), definitionHandle.getShapeH(shapeId)}; | ||||||
|  | //                double[] toBounding = new double[]{definitionHandle.getShapeX(rearNodeId), definitionHandle.getShapeY(rearNodeId), definitionHandle.getShapeW(rearNodeId), definitionHandle.getShapeH(rearNodeId)}; | ||||||
|  | //                JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, shapeId, rearNodeId, fromBounding, toBounding); | ||||||
|  | // | ||||||
|  | //                linker.put("elementType", ElementType.OUTER_LINKER.name()); | ||||||
|  | //                definitionHandle.addEle(linker.getString("id"), linker); | ||||||
|  | //            } | ||||||
|  | //        } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -130,10 +130,10 @@ public class GraphLayout { | |||||||
|         this.canvasHeight = h + 200.0; |         this.canvasHeight = h + 200.0; | ||||||
| 
 | 
 | ||||||
|         // 打印节点坐标与画布大小 |         // 打印节点坐标与画布大小 | ||||||
|         System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight); |         // System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight); | ||||||
|         for (int i = 0; i < position.length; i++) { |         // for (int i = 0; i < position.length; i++) { | ||||||
|             System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]); |            //  System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]); | ||||||
|         } |         // } | ||||||
| 
 | 
 | ||||||
|         return position; |         return position; | ||||||
|     } |     } | ||||||
| @ -205,10 +205,10 @@ public class GraphLayout { | |||||||
|         this.canvasHeight = h + 200.0; |         this.canvasHeight = h + 200.0; | ||||||
| 
 | 
 | ||||||
|         // 打印节点坐标与画布大小 |         // 打印节点坐标与画布大小 | ||||||
|         System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight); |         // System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight); | ||||||
|         for (int i = 0; i < position.length; i++) { |         // for (int i = 0; i < position.length; i++) { | ||||||
|             System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]); |            // System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]); | ||||||
|         } |         // } | ||||||
| 
 | 
 | ||||||
|         return position; |         return position; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -7,23 +7,19 @@ import com.actionsoft.apps.coe.method.process.subprocess.graph.component.Abstrac | |||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionThreadUnSafe; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionThreadUnSafe; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject; | import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject; | ||||||
| import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; | import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; | ||||||
| import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager; | 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.ShapeUtil; | import com.actionsoft.apps.coe.pal.pal.repository.designer.util.ShapeUtil; | ||||||
| import com.actionsoft.bpms.util.ConsolePrinter; | import com.actionsoft.bpms.util.ConsolePrinter; | ||||||
| import com.actionsoft.bpms.util.UUIDGener; | import com.actionsoft.bpms.util.UUIDGener; | ||||||
| import com.actionsoft.bpms.util.UtilString; |  | ||||||
| import com.actionsoft.exception.AWSException; | import com.actionsoft.exception.AWSException; | ||||||
| import com.alibaba.fastjson.JSONArray; | import com.alibaba.fastjson.JSONArray; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| 
 | 
 | ||||||
| import java.util.*; | import java.util.*; | ||||||
| import java.util.concurrent.locks.ReentrantLock; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 图节点关闭处理 |  * 图节点关闭处理 | ||||||
| @ -40,6 +36,8 @@ public class GraphNodeCloseHandle { | |||||||
|     private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器 |     private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器 | ||||||
|     private NodeSubject nodeSubject; // 当前操作的节点主题类 |     private NodeSubject nodeSubject; // 当前操作的节点主题类 | ||||||
| 
 | 
 | ||||||
|  |     private ExpandOrCloseShapeLinkerConvertHandle linkerConvertHandle; // 范围框内元素与外部元素连线处理器 | ||||||
|  | 
 | ||||||
|     public GraphNodeCloseHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) throws AWSException{ |     public GraphNodeCloseHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) throws AWSException{ | ||||||
|         this.repositoryId = repositoryId; |         this.repositoryId = repositoryId; | ||||||
|         this.shapeId = shapeId; |         this.shapeId = shapeId; | ||||||
| @ -62,6 +60,8 @@ public class GraphNodeCloseHandle { | |||||||
|             nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "close"); |             nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "close"); | ||||||
|             nodeSubject.buildObservers(); |             nodeSubject.buildObservers(); | ||||||
| 
 | 
 | ||||||
|  |             linkerConvertHandle = new ExpandOrCloseShapeLinkerConvertHandle(definitionHandle); | ||||||
|  | 
 | ||||||
|         } catch (AWSException e) { |         } catch (AWSException e) { | ||||||
|             throw new AWSException(e); |             throw new AWSException(e); | ||||||
|         } |         } | ||||||
| @ -74,15 +74,19 @@ public class GraphNodeCloseHandle { | |||||||
|      */ |      */ | ||||||
|     public String handleNodeClose() throws AWSException { |     public String handleNodeClose() throws AWSException { | ||||||
| 
 | 
 | ||||||
|  |         // 删除现有连线 | ||||||
|  |         removeEndToEndGraphOldLinker(); | ||||||
| 
 | 
 | ||||||
|         // 1、处理范围选择框及其内部节点 |         // 处理范围选择框及其内部节点 | ||||||
|         removeScopeShapeAndInRangeEle(); |         removeScopeShapeAndInRangeEle(); | ||||||
| 
 | 
 | ||||||
|         // 2、处理总图中的节点与连线 |         // 处理总图中的节点与连线 | ||||||
|         handleEndToEndGraphNodeAndLinker(); |         handleEndToEndGraphNodeAndLinker(); | ||||||
| 
 | 
 | ||||||
|         scopeShapeMonitor.updateScopeShapeInnerEle(); |         scopeShapeMonitor.updateScopeShapeInnerEle(); | ||||||
| 
 | 
 | ||||||
|  |         linkerConvertHandle.scopeShapeLinkerHandle(); | ||||||
|  | 
 | ||||||
|         return definitionHandle.getDefine().toJSONString(); |         return definitionHandle.getDefine().toJSONString(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -91,22 +95,27 @@ public class GraphNodeCloseHandle { | |||||||
|         JSONObject subProcessNode = buildSubProcessNode(shapeId, scopeLimitationShape); |         JSONObject subProcessNode = buildSubProcessNode(shapeId, scopeLimitationShape); | ||||||
|         definitionHandle.addEle(shapeId, subProcessNode); |         definitionHandle.addEle(shapeId, subProcessNode); | ||||||
| 
 | 
 | ||||||
|  |         // 范围框闭合 将扩展属性复制到新的子流程节点上 | ||||||
|  |         subProcessNode.put(SubProcessConst.EXTEND_ATTR, scopeLimitationShape.getJSONObject(SubProcessConst.EXTEND_ATTR)); | ||||||
|  | 
 | ||||||
|         // 通知其它节点位置更新 |         // 通知其它节点位置更新 | ||||||
|         nodeSubject.setScopeW(subProcessNode.getJSONObject("props").getDoubleValue("w")); |         nodeSubject.setScopeW(subProcessNode.getJSONObject("props").getDoubleValue("w")); | ||||||
|         nodeSubject.setScopeH(subProcessNode.getJSONObject("props").getDoubleValue("h")); |         nodeSubject.setScopeH(subProcessNode.getJSONObject("props").getDoubleValue("h")); | ||||||
| 
 | 
 | ||||||
|         // 2、根据现有连线关系创建邻接矩阵 |         // 2、根据现有连线关系创建邻接矩阵 | ||||||
|         NodeCloseAdjMatrix closeAdjMatrix = buildEndToEndGraphAdjMatrix(); |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         List<JSONObject> nodeList = elements.keySet().stream() | ||||||
|  |                 .filter(key -> definitionHandle.getElementTypeByKey(key).name().equals(ElementType.OUTER_NODE.name()) || definitionHandle.getElementTypeByKey(key).name().equals(ElementType.SCOPE_NODE.name())) | ||||||
|  |                 .map(key -> definitionHandle.getShapeByKey(key)) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |         NodeCloseAdjMatrix closeAdjMatrix = new NodeCloseAdjMatrix(nodeList); | ||||||
|         closeAdjMatrix.buildAdjMatrix(); |         closeAdjMatrix.buildAdjMatrix(); | ||||||
| 
 | 
 | ||||||
|         JSONObject elements = definitionHandle.getElements(); |  | ||||||
|         // 更新因节点展开后 坐标发生变化的节点坐标 |         // 更新因节点展开后 坐标发生变化的节点坐标 | ||||||
|         String direction = definitionHandle.getProcessProperties().getString("direction"); |         String direction = definitionHandle.getProcessProperties().getString("direction"); | ||||||
|         // graphPartNodePoiRenderAgain(elements, direction, subProcessNode); |  | ||||||
|         // 3、收集现有元素坐标 |         // 3、收集现有元素坐标 | ||||||
|         double[][] vertexBounding = closeAdjMatrix.getVertexBounding(elements); |         double[][] vertexBounding = closeAdjMatrix.getVertexBounding(elements); | ||||||
|         // 4、删除现有连线 | 
 | ||||||
|         removeEndToEndGraphOldLinker(); |  | ||||||
|         // 5、构建新的连线 |         // 5、构建新的连线 | ||||||
|         NodeCloseLinkerRender linkerRender = new NodeCloseLinkerRender(vertexBounding, closeAdjMatrix, definitionHandle); |         NodeCloseLinkerRender linkerRender = new NodeCloseLinkerRender(vertexBounding, closeAdjMatrix, definitionHandle); | ||||||
|         JSONArray linkers = linkerRender.toAssembleLinker(direction); |         JSONArray linkers = linkerRender.toAssembleLinker(direction); | ||||||
| @ -126,76 +135,6 @@ public class GraphNodeCloseHandle { | |||||||
|         page.put("height", h + 300); |         page.put("height", h + 300); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * 节点闭合 部分节点坐标再次更新 |  | ||||||
|      */ |  | ||||||
|     private void graphPartNodePoiRenderAgain(JSONObject elements, String direction, JSONObject subProcessNode){ |  | ||||||
|         // 闭合节点的位置 及大小 |  | ||||||
|         JSONObject props = subProcessNode.getJSONObject("props"); |  | ||||||
|         double x = props.getDoubleValue("x"); |  | ||||||
|         double y = props.getDoubleValue("y"); |  | ||||||
| 
 |  | ||||||
|         // 当前关闭的节点范围标识框的位置与大小 |  | ||||||
|         double[] scope = SubProcessNodeDefineUtil.calculateSubProcessNodeExpandScope(subProcessNodeDefineHandle); |  | ||||||
| 
 |  | ||||||
|         // double[] scopeShapeBounding = new double[]{x, y, scope[2], scope[3]}; |  | ||||||
| 
 |  | ||||||
|         // boolean yIsMove = checkShapeYIsMove(elements, scopeShapeBounding); |  | ||||||
| 
 |  | ||||||
|         for (String key : elements.keySet()) { |  | ||||||
|             JSONObject ele = elements.getJSONObject(key); |  | ||||||
|             if ("linker".equals(ele.getString("name"))) continue; |  | ||||||
|             if (ele.getString("id").equals(subProcessNode.getString("id"))) continue; |  | ||||||
|             if (scopeShapeMonitor.checkShapeIsScopeInRange(key)) continue; |  | ||||||
|             JSONObject eleProps = ele.getJSONObject("props"); |  | ||||||
|             if ("vertically".equals(direction)){ // 垂直布局 |  | ||||||
|                 if (x + scope[2] < eleProps.getDoubleValue("x")) { |  | ||||||
|                     double xMoveDistance = -scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W; |  | ||||||
|                     eleProps.put("x", eleProps.getDoubleValue("x") - scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W); |  | ||||||
|                     if (scopeShapeMonitor.checkShapeIsScopeShape(key)){ |  | ||||||
|                         scopeShapeMonitor.updateMonitorXInfo(key, true, xMoveDistance); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 if (y +scope[3] < eleProps.getDoubleValue("y")){ |  | ||||||
|                     double yMoveDistance = -scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H; |  | ||||||
|                     eleProps.put("y", eleProps.getDoubleValue("y") - scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H); |  | ||||||
|                     if (scopeShapeMonitor.checkShapeIsScopeShape(key)){ |  | ||||||
|                         scopeShapeMonitor.updateMonitorYInfo(key, true, yMoveDistance); |  | ||||||
|                     } |  | ||||||
|                 }else if (y < eleProps.getDoubleValue("y") && eleProps.getDoubleValue("y") < y + scope[3]){ |  | ||||||
|                     eleProps.put("y", y); |  | ||||||
|                     double yMoveDistance = y - eleProps.getDoubleValue("y"); |  | ||||||
|                     if (scopeShapeMonitor.checkShapeIsScopeShape(key)){ |  | ||||||
|                         scopeShapeMonitor.updateMonitorYInfo(key, true, yMoveDistance); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             }else { // 横向布局 |  | ||||||
|                 if (x + scope[2] < eleProps.getDoubleValue("x")){ // 节点在范围框右侧的节点 |  | ||||||
|                     double xMoveDistance = -scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W; |  | ||||||
|                     eleProps.put("x", eleProps.getDoubleValue("x") - scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W); |  | ||||||
|                     if (scopeShapeMonitor.checkShapeIsScopeShape(key)){ |  | ||||||
|                         scopeShapeMonitor.updateMonitorXInfo(key, true, xMoveDistance); |  | ||||||
|                     } |  | ||||||
|                 }else if (x < eleProps.getDoubleValue("x") |  | ||||||
|                         && eleProps.getDoubleValue("x") < x + scope[2] |  | ||||||
|                         && y + scope[3] < eleProps.getDoubleValue("y")){ |  | ||||||
|                     double xMoveDistance = x - eleProps.getDoubleValue("x"); |  | ||||||
|                     eleProps.put("x", x); |  | ||||||
|                     if (scopeShapeMonitor.checkShapeIsScopeShape(key)){ |  | ||||||
|                         scopeShapeMonitor.updateMonitorXInfo(key, true, xMoveDistance); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 if (y + scope[3] < eleProps.getDoubleValue("y")){ // 节点在范围框下方的节点 |  | ||||||
|                     double yMoveDistance = -scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H; |  | ||||||
|                     eleProps.put("y", eleProps.getDoubleValue("y") - scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H); |  | ||||||
|                     if (scopeShapeMonitor.checkShapeIsScopeShape(key)){ |  | ||||||
|                         scopeShapeMonitor.updateMonitorYInfo(key, true, yMoveDistance); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 在节点闭合的时候 检查当前闭合的节点的下方节点是否需要上下移动 |      * 在节点闭合的时候 检查当前闭合的节点的下方节点是否需要上下移动 | ||||||
|      * @param elements |      * @param elements | ||||||
| @ -251,41 +190,15 @@ public class GraphNodeCloseHandle { | |||||||
|      */ |      */ | ||||||
|     private void removeEndToEndGraphOldLinker(){ |     private void removeEndToEndGraphOldLinker(){ | ||||||
|         JSONObject elements = definitionHandle.getElements(); |         JSONObject elements = definitionHandle.getElements(); | ||||||
|         Set<String> eleKeys = new HashSet<>(); |         Set<String> linkerIds = elements.keySet() | ||||||
|         for (String key : elements.keySet()) { |                 .stream() | ||||||
|             JSONObject ele = elements.getJSONObject(key); |                 .filter(key -> definitionHandle.getElementTypeByKey(key).equals(ElementType.OUTER_LINKER) || definitionHandle.getElementTypeByKey(key).equals(ElementType.CROSS_LINKER)) | ||||||
|             if ("linker".equals(ele.getString("name")) && !scopeShapeMonitor.checkShapeIsScopeInRange(key)){ |                 .collect(Collectors.toSet()); | ||||||
|                 eleKeys.add(key); |         for (String eleKey : linkerIds) { | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         for (String eleKey : eleKeys) { |  | ||||||
|             definitionHandle.removeShape(eleKey); |             definitionHandle.removeShape(eleKey); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 构建节点展开前 端到端总图的邻接矩阵 |  | ||||||
|      * 方便后续节点展开或者闭合进行重新连线 |  | ||||||
|      */ |  | ||||||
|     private NodeCloseAdjMatrix buildEndToEndGraphAdjMatrix(){ |  | ||||||
| 
 |  | ||||||
|         List<String> nodeIdList = new ArrayList<>(); |  | ||||||
|         List<JSONObject> linkerList = new ArrayList<>(); |  | ||||||
|         JSONObject endToEndProcessElements = definitionHandle.getElements(); |  | ||||||
|         for (String key : endToEndProcessElements.keySet()) { |  | ||||||
|             if (scopeShapeMonitor.checkShapeIsScopeInRange(key)) continue; |  | ||||||
|             JSONObject ele = endToEndProcessElements.getJSONObject(key); |  | ||||||
|             if ("linker".equals(ele.getString("name"))) { |  | ||||||
|                 linkerList.add(ele); |  | ||||||
|             }else { |  | ||||||
|                 nodeIdList.add(key); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         NodeCloseAdjMatrix closeAdjMatrix = new NodeCloseAdjMatrix(nodeIdList, linkerList); |  | ||||||
|         return closeAdjMatrix; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 构建子流程节点 |      * 构建子流程节点 | ||||||
|      * @param shapeId |      * @param shapeId | ||||||
| @ -312,7 +225,8 @@ public class GraphNodeCloseHandle { | |||||||
|      */ |      */ | ||||||
|     private void removeScopeShapeAndInRangeEle(){ |     private void removeScopeShapeAndInRangeEle(){ | ||||||
| 
 | 
 | ||||||
|         Set<String> keys = SubProcessNodeDefineUtil.getInScopeLimitationRangeEles(shapeId, definitionHandle, subProcessNodeDefineHandle); |         JSONArray innerEleKeySet = scopeLimitationShape.getJSONArray(SubProcessConst.INNER_ELEMENTS); | ||||||
|  |         Set<String> keys = innerEleKeySet.stream().map(o -> o.toString()).collect(Collectors.toSet()); | ||||||
|         for (String key : keys) { |         for (String key : keys) { | ||||||
|             definitionHandle.removeShape(key); |             definitionHandle.removeShape(key); | ||||||
|         } |         } | ||||||
| @ -329,32 +243,42 @@ public class GraphNodeCloseHandle { | |||||||
| class NodeCloseAdjMatrix extends AbstractAdjMatrix { | class NodeCloseAdjMatrix extends AbstractAdjMatrix { | ||||||
| 
 | 
 | ||||||
|     private List<String> nodeIds; |     private List<String> nodeIds; | ||||||
|     private List<JSONObject> linkerList; |     private List<JSONObject> nodeList; // 当前画布中所有子流程节点以及范围框节点 不包含内部节点与连线 | ||||||
| 
 | 
 | ||||||
|     public NodeCloseAdjMatrix(List<String> nodeIds, List<JSONObject> linkerList) { |     public NodeCloseAdjMatrix(List<JSONObject> nodeList) { | ||||||
|         super(nodeIds.size()); |         super(nodeList.size()); | ||||||
|         this.nodeIds = nodeIds; |         this.nodeList = nodeList; | ||||||
|         this.linkerList = linkerList; | 
 | ||||||
|  |         this.nodeIds = nodeList.stream().map(o -> o.getString("id")).collect(Collectors.toList()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public List<String> getNodeIds() { |     public List<String> getNodeIds() { | ||||||
|         return nodeIds; |         return nodeIds; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public List<JSONObject> getLinkerList() { |  | ||||||
|         return linkerList; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 构建邻接矩阵 |      * 构建邻接矩阵 | ||||||
|      */ |      */ | ||||||
|     public void buildAdjMatrix(){ |     public void buildAdjMatrix(){ | ||||||
|         for (JSONObject linker : linkerList) { |         for (JSONObject node : nodeList) { | ||||||
|             JSONObject from = linker.getJSONObject("from"); |             String currentNodeId = node.getString("id"); | ||||||
|             JSONObject to = linker.getJSONObject("to"); |             JSONObject extendAttr = node.getJSONObject(SubProcessConst.EXTEND_ATTR); | ||||||
|             int fromIndex = nodeIds.indexOf(from.getString("id")); |             // 当前节点的前置节点 | ||||||
|             int toIndex = nodeIds.indexOf(to.getString("id")); |             JSONArray leadNodeArr = extendAttr.getJSONArray("leadNodeArr"); | ||||||
|             addEdge(fromIndex, toIndex); |             if (leadNodeArr.size() > 0){ | ||||||
|  |                 for (Object o : leadNodeArr) { | ||||||
|  |                     String leadNodeId = (String) o; | ||||||
|  |                     addEdge(nodeIds.indexOf(leadNodeId), nodeIds.indexOf(currentNodeId)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // 当前节点的后置节点 | ||||||
|  |             JSONArray rearNodeArr = extendAttr.getJSONArray("rearNodeArr"); | ||||||
|  |             if (rearNodeArr.size() > 0){ | ||||||
|  |                 for (Object o : rearNodeArr) { | ||||||
|  |                     String rearNodeId = (String) o; | ||||||
|  |                     addEdge(nodeIds.indexOf(currentNodeId), nodeIds.indexOf(rearNodeId)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,25 +7,20 @@ import com.actionsoft.apps.coe.method.process.subprocess.graph.component.Abstrac | |||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionThreadUnSafe; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionThreadUnSafe; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.mode.Node; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; |  | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject; | import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject; | ||||||
| import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; | import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; | ||||||
| import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager; | 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.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.apps.coe.pal.pal.repository.designer.util.ShapeUtil; | ||||||
| import com.actionsoft.bpms.util.ConsolePrinter; | import com.actionsoft.bpms.util.ConsolePrinter; | ||||||
| import com.actionsoft.bpms.util.UUIDGener; | import com.actionsoft.bpms.util.UUIDGener; | ||||||
| import com.actionsoft.bpms.util.UtilString; |  | ||||||
| import com.actionsoft.exception.AWSException; | import com.actionsoft.exception.AWSException; | ||||||
| import com.alibaba.fastjson.JSONArray; | import com.alibaba.fastjson.JSONArray; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| 
 | 
 | ||||||
| import java.util.*; | import java.util.*; | ||||||
| import java.util.concurrent.locks.ReentrantLock; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 图节点展开处理 |  * 图节点展开处理 | ||||||
| @ -42,6 +37,8 @@ public class GraphNodeExpandHandle { | |||||||
|     private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器 |     private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器 | ||||||
|     private NodeSubject nodeSubject; // 当前操作的节点主题类 |     private NodeSubject nodeSubject; // 当前操作的节点主题类 | ||||||
| 
 | 
 | ||||||
|  |     private ExpandOrCloseShapeLinkerConvertHandle linkerConvertHandle; // 范围框内元素与外部元素连线处理器 | ||||||
|  | 
 | ||||||
|     private double[] scopeLimitationShapeBeforePoi; // 范围选择框在子流程文件中的坐标 |     private double[] scopeLimitationShapeBeforePoi; // 范围选择框在子流程文件中的坐标 | ||||||
| 
 | 
 | ||||||
|     public GraphNodeExpandHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) throws AWSException{ |     public GraphNodeExpandHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) throws AWSException{ | ||||||
| @ -58,12 +55,13 @@ public class GraphNodeExpandHandle { | |||||||
|             subProcessNodeDefineHandle = new DefinitionThreadUnSafe(SubProcessNodeDefineUtil.readSubProcessNodeDefine(repositoryId, shapeId)); |             subProcessNodeDefineHandle = new DefinitionThreadUnSafe(SubProcessNodeDefineUtil.readSubProcessNodeDefine(repositoryId, shapeId)); | ||||||
| 
 | 
 | ||||||
|             scopeShapeMonitor = new ScopeShapeMonitor(definitionHandle); |             scopeShapeMonitor = new ScopeShapeMonitor(definitionHandle); | ||||||
|             // 1、构建范围框监视器模型 并关联内部元素 |  | ||||||
|             scopeShapeMonitor.buildScopeShapeMonitors(); |             scopeShapeMonitor.buildScopeShapeMonitors(); | ||||||
| 
 | 
 | ||||||
|             nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "expand"); |             nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "expand"); | ||||||
|             nodeSubject.buildObservers(); |             nodeSubject.buildObservers(); | ||||||
| 
 | 
 | ||||||
|  |             linkerConvertHandle = new ExpandOrCloseShapeLinkerConvertHandle(definitionHandle); | ||||||
|  | 
 | ||||||
|             toAssembleScopeLimitationShape(); |             toAssembleScopeLimitationShape(); | ||||||
|         } catch (Exception e) { |         } catch (Exception e) { | ||||||
|             throw new AWSException(e); |             throw new AWSException(e); | ||||||
| @ -113,6 +111,9 @@ public class GraphNodeExpandHandle { | |||||||
|         minRange.put("y2", y + scope[3]); |         minRange.put("y2", y + scope[3]); | ||||||
|         scopeLimitationShape.put("minRange", minRange); |         scopeLimitationShape.put("minRange", minRange); | ||||||
| 
 | 
 | ||||||
|  |         // 扩展属性 extendAttr 存储的是关联的文件信息 | ||||||
|  |         scopeLimitationShape.put(SubProcessConst.EXTEND_ATTR, currentExpandShape.getJSONObject(SubProcessConst.EXTEND_ATTR)); | ||||||
|  | 
 | ||||||
|         this.scopeLimitationShape = scopeLimitationShape; |         this.scopeLimitationShape = scopeLimitationShape; | ||||||
| 
 | 
 | ||||||
|         // 通知其它节点位置更新 |         // 通知其它节点位置更新 | ||||||
| @ -128,15 +129,17 @@ public class GraphNodeExpandHandle { | |||||||
|      */ |      */ | ||||||
|     public String handleNodeExpand() throws AWSException{ |     public String handleNodeExpand() throws AWSException{ | ||||||
| 
 | 
 | ||||||
|         // 2、总图节点以及连线处理 |         // 总图节点以及连线处理 | ||||||
|         handleEndToEndGraphNodeAndLinker(); |         handleEndToEndGraphNodeAndLinker(); | ||||||
| 
 | 
 | ||||||
|         // 3、当前展开的子流程节点内部元素 以及 范围框处理 |         // 当前展开的子流程节点内部元素 以及 范围框处理 | ||||||
|         handleRelationModelNodePosition(); |         handleRelationModelNodePosition(); | ||||||
| 
 | 
 | ||||||
|         // 4、范围框内的元素 坐标更新 |         // 当前节点展开前已存在的其它范围框内的元素 坐标更新 | ||||||
|         scopeShapeMonitor.updateScopeShapeInnerEle(); |         scopeShapeMonitor.updateScopeShapeInnerEle(); | ||||||
| 
 | 
 | ||||||
|  |         linkerConvertHandle.scopeShapeLinkerHandle(); | ||||||
|  | 
 | ||||||
|         return definitionHandle.getDefine().toJSONString(); |         return definitionHandle.getDefine().toJSONString(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -157,17 +160,20 @@ public class GraphNodeExpandHandle { | |||||||
|         // 2、添加到总图中 |         // 2、添加到总图中 | ||||||
|         definitionHandle.addEle(shapeId, scopeLimitationShape); |         definitionHandle.addEle(shapeId, scopeLimitationShape); | ||||||
| 
 | 
 | ||||||
|         // 3、总图中符合范围选择框条件的节点 坐标更新 |  | ||||||
|         // handleEndToEndGraphNodeExcluedExpandNode(); |  | ||||||
| 
 |  | ||||||
|         // 4、构建邻接矩阵 |  | ||||||
|         NodeExpandAdjMatrix expandAdjMatrix = buildEndToEndGraphAdjMatrix(); |  | ||||||
|         expandAdjMatrix.buildAdjMatrix(); |  | ||||||
|         // expandAdjMatrix.printAdjMatrix(); |  | ||||||
|         // 5、删除节点展开前的连线 |         // 5、删除节点展开前的连线 | ||||||
|         removeEndToEndGraphOldLinker(); |         removeEndToEndGraphOldLinker(); | ||||||
|         // 6、获取所有节点坐标 | 
 | ||||||
|  |         // 4、构建邻接矩阵 | ||||||
|         JSONObject elements = definitionHandle.getElements(); |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         List<JSONObject> nodeList = elements.keySet().stream() | ||||||
|  |                 .filter(key -> definitionHandle.getElementTypeByKey(key).name().equals(ElementType.OUTER_NODE.name()) || definitionHandle.getElementTypeByKey(key).name().equals(ElementType.SCOPE_NODE.name())) | ||||||
|  |                 .map(key -> definitionHandle.getShapeByKey(key)) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |         NodeExpandAdjMatrix expandAdjMatrix = new NodeExpandAdjMatrix(nodeList); | ||||||
|  | 
 | ||||||
|  |         expandAdjMatrix.buildAdjMatrix(); | ||||||
|  | 
 | ||||||
|  |         // 6、获取所有节点坐标 | ||||||
|         double[][] vertexBounding = expandAdjMatrix.getVertexBounding(elements); |         double[][] vertexBounding = expandAdjMatrix.getVertexBounding(elements); | ||||||
|         // 7、构建新的连线 |         // 7、构建新的连线 | ||||||
|         JSONObject processProperties = definitionHandle.getProcessProperties(); |         JSONObject processProperties = definitionHandle.getProcessProperties(); | ||||||
| @ -204,6 +210,7 @@ public class GraphNodeExpandHandle { | |||||||
| 
 | 
 | ||||||
|         // 根据范围标注框的坐标 调整子流程所有元素的坐标 |         // 根据范围标注框的坐标 调整子流程所有元素的坐标 | ||||||
|         JSONObject elements = subProcessNodeDefineHandle.getElements(); |         JSONObject elements = subProcessNodeDefineHandle.getElements(); | ||||||
|  |         JSONArray innerEleKeyArr = new JSONArray(); | ||||||
|         for (String key : elements.keySet()) { |         for (String key : elements.keySet()) { | ||||||
|             JSONObject ele = elements.getJSONObject(key); |             JSONObject ele = elements.getJSONObject(key); | ||||||
|             // 元素分为两类 一类为图形 一类为连线 |             // 元素分为两类 一类为图形 一类为连线 | ||||||
| @ -231,8 +238,15 @@ public class GraphNodeExpandHandle { | |||||||
|                 ele.put("elementType", ElementType.INNER_NODE.name()); |                 ele.put("elementType", ElementType.INNER_NODE.name()); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             // 指向范围框 | ||||||
|  |             ele.put("scopeShapeId", scopeLimitationShape.getString("id")); | ||||||
|  | 
 | ||||||
|  |             // 存入内部元素 | ||||||
|  |             innerEleKeyArr.add(key); | ||||||
|  | 
 | ||||||
|             definitionHandle.addEle(key, ele); |             definitionHandle.addEle(key, ele); | ||||||
|         } |         } | ||||||
|  |         scopeLimitationShape.put(SubProcessConst.INNER_ELEMENTS, innerEleKeyArr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -324,41 +338,16 @@ public class GraphNodeExpandHandle { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * 构建节点展开前 端到端总图的邻接矩阵 |  | ||||||
|      * 方便后续节点展开或者闭合进行重新连线 |  | ||||||
|      */ |  | ||||||
|     private NodeExpandAdjMatrix buildEndToEndGraphAdjMatrix(){ |  | ||||||
| 
 |  | ||||||
|         List<String> nodeIdList = new ArrayList<>(); |  | ||||||
|         List<JSONObject> linkerList = new ArrayList<>(); |  | ||||||
|         JSONObject endToEndProcessElements = definitionHandle.getElements(); |  | ||||||
|         for (String key : endToEndProcessElements.keySet()) { |  | ||||||
|             if (scopeShapeMonitor.checkShapeIsScopeInRange(key)) continue; // 范围框内的元素 暂不处理 |  | ||||||
|             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; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 删除总图中节点展开前的连线 |      * 删除总图中节点展开前的连线 | ||||||
|      */ |      */ | ||||||
|     private void removeEndToEndGraphOldLinker(){ |     private void removeEndToEndGraphOldLinker(){ | ||||||
|         JSONObject elements = definitionHandle.getElements(); |         JSONObject elements = definitionHandle.getElements(); | ||||||
|         Set<String> eleKeys = new HashSet<>(); |         Set<String> linkerIds = elements.keySet() | ||||||
|         for (String key : elements.keySet()) { |                 .stream() | ||||||
|             JSONObject ele = elements.getJSONObject(key); |                 .filter(key -> definitionHandle.getElementTypeByKey(key).equals(ElementType.OUTER_LINKER) || definitionHandle.getElementTypeByKey(key).equals(ElementType.CROSS_LINKER)) | ||||||
|             if ("linker".equals(ele.getString("name")) && !scopeShapeMonitor.checkShapeIsScopeInRange(key)){ |                 .collect(Collectors.toSet()); | ||||||
|                 eleKeys.add(key); |         for (String eleKey : linkerIds) { | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         for (String eleKey : eleKeys) { |  | ||||||
|             definitionHandle.removeShape(eleKey); |             definitionHandle.removeShape(eleKey); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -380,32 +369,42 @@ public class GraphNodeExpandHandle { | |||||||
| class NodeExpandAdjMatrix extends AbstractAdjMatrix { | class NodeExpandAdjMatrix extends AbstractAdjMatrix { | ||||||
| 
 | 
 | ||||||
|     private List<String> nodeIds; |     private List<String> nodeIds; | ||||||
|     private List<JSONObject> linkerList; |     private List<JSONObject> nodeList; // 当前画布中所有子流程节点以及范围框节点 不包含内部节点与连线 | ||||||
| 
 | 
 | ||||||
|     public NodeExpandAdjMatrix(List<String> nodeIds, List<JSONObject> linkerList) { |     public NodeExpandAdjMatrix(List<JSONObject> nodeList) { | ||||||
|         super(nodeIds.size()); |         super(nodeList.size()); | ||||||
|         this.nodeIds = nodeIds; |         this.nodeList = nodeList; | ||||||
|         this.linkerList = linkerList; | 
 | ||||||
|  |         this.nodeIds = nodeList.stream().map(o -> o.getString("id")).collect(Collectors.toList()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public List<String> getNodeIds() { |     public List<String> getNodeIds() { | ||||||
|         return nodeIds; |         return nodeIds; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public List<JSONObject> getLinkerList() { |  | ||||||
|         return linkerList; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 构建邻接矩阵 |      * 构建邻接矩阵 | ||||||
|      */ |      */ | ||||||
|     public void buildAdjMatrix(){ |     public void buildAdjMatrix(){ | ||||||
|         for (JSONObject linker : linkerList) { |         for (JSONObject node : nodeList) { | ||||||
|             JSONObject from = linker.getJSONObject("from"); |             String currentNodeId = node.getString("id"); | ||||||
|             JSONObject to = linker.getJSONObject("to"); |             JSONObject extendAttr = node.getJSONObject(SubProcessConst.EXTEND_ATTR); | ||||||
|             int fromIndex = nodeIds.indexOf(from.getString("id")); |             // 当前节点的前置节点 | ||||||
|             int toIndex = nodeIds.indexOf(to.getString("id")); |             JSONArray leadNodeArr = extendAttr.getJSONArray("leadNodeArr"); | ||||||
|             addEdge(fromIndex, toIndex); |             if (leadNodeArr.size() > 0){ | ||||||
|  |                 for (Object o : leadNodeArr) { | ||||||
|  |                     String leadNodeId = (String) o; | ||||||
|  |                     addEdge(nodeIds.indexOf(leadNodeId), nodeIds.indexOf(currentNodeId)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // 当前节点的后置节点 | ||||||
|  |             JSONArray rearNodeArr = extendAttr.getJSONArray("rearNodeArr"); | ||||||
|  |             if (rearNodeArr.size() > 0){ | ||||||
|  |                 for (Object o : rearNodeArr) { | ||||||
|  |                     String rearNodeId = (String) o; | ||||||
|  |                     addEdge(nodeIds.indexOf(currentNodeId), nodeIds.indexOf(rearNodeId)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -20,10 +20,8 @@ import com.actionsoft.exception.AWSException; | |||||||
| import com.alibaba.fastjson.JSONArray; | import com.alibaba.fastjson.JSONArray; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| 
 | 
 | ||||||
| import java.util.HashMap; | import java.util.*; | ||||||
| import java.util.List; | import java.util.stream.Collectors; | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Optional; |  | ||||||
| 
 | 
 | ||||||
| public class GraphRender { | public class GraphRender { | ||||||
| 
 | 
 | ||||||
| @ -79,6 +77,11 @@ public class GraphRender { | |||||||
|             subProcessNode.put("text", repositoryModel.getName()); |             subProcessNode.put("text", repositoryModel.getName()); | ||||||
|             // 增加元素类型属性 |             // 增加元素类型属性 | ||||||
|             subProcessNode.put("elementType", ElementType.OUTER_NODE.name()); |             subProcessNode.put("elementType", ElementType.OUTER_NODE.name()); | ||||||
|  |             // 增加关联文件的标识 | ||||||
|  |             JSONObject extendAttr = new JSONObject(); | ||||||
|  |             extendAttr.put("id", nodeList.get(i).getId()); | ||||||
|  |             extendAttr.put("name", repositoryModel.getName()); | ||||||
|  |             subProcessNode.put(SubProcessConst.EXTEND_ATTR, extendAttr); | ||||||
| 
 | 
 | ||||||
|             // 处理子流程模型节点形状属性 |             // 处理子流程模型节点形状属性 | ||||||
|             JSONArray dataAttributes = subProcessNode.getJSONArray("dataAttributes"); |             JSONArray dataAttributes = subProcessNode.getJSONArray("dataAttributes"); | ||||||
| @ -194,4 +197,41 @@ public class GraphRender { | |||||||
|         this.baseModel.setDefinition(defineJsonObj.toJSONString()); |         this.baseModel.setDefinition(defineJsonObj.toJSONString()); | ||||||
|         CoeDesignerAPIManager.getInstance().storeDefinition(this.baseModel); |         CoeDesignerAPIManager.getInstance().storeDefinition(this.baseModel); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 依据生成后的总图的连线关系 在子流程节点属性中加入 前置节点与后置节点信息 | ||||||
|  |      */ | ||||||
|  |     public void addLeadAndRearInfoToElements(){ | ||||||
|  |         JSONObject defineJsonObj = JSONObject.parseObject(this.baseModel.getDefinition()); | ||||||
|  |         JSONObject elements = defineJsonObj.getJSONObject("elements"); | ||||||
|  | 
 | ||||||
|  |         Set<String> subProcessNodeKeySet = elements.keySet().stream().filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name"))).collect(Collectors.toSet()); | ||||||
|  |         for (String subProcessNodeKey : subProcessNodeKeySet) { | ||||||
|  |             JSONObject subProcessNode = elements.getJSONObject(subProcessNodeKey); | ||||||
|  |             JSONObject extendAttr = subProcessNode.getJSONObject(SubProcessConst.EXTEND_ATTR); | ||||||
|  | 
 | ||||||
|  |             // 当前节点的前置节点 | ||||||
|  |             JSONArray leadNodeKeyArr = elements.keySet().stream() | ||||||
|  |                     .filter(key -> "linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                     .map(key -> elements.getJSONObject(key)) | ||||||
|  |                     .filter(l -> ((JSONObject)l).getJSONObject("to").getString("id").equals(subProcessNodeKey)) | ||||||
|  |                     .map(l -> ((JSONObject)l).getJSONObject("from").getString("id")) | ||||||
|  |                     .collect(Collectors.toCollection(JSONArray::new)); | ||||||
|  | 
 | ||||||
|  |             extendAttr.put("leadNodeArr", leadNodeKeyArr); | ||||||
|  | 
 | ||||||
|  |             // 当前节点的后置节点 | ||||||
|  |             JSONArray rearNodeKeyArr = elements.keySet().stream() | ||||||
|  |                     .filter(key -> "linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                     .map(key -> elements.getJSONObject(key)) | ||||||
|  |                     .filter(l -> ((JSONObject)l).getJSONObject("from").getString("id").equals(subProcessNodeKey)) | ||||||
|  |                     .map(l -> ((JSONObject)l).getJSONObject("to").getString("id")) | ||||||
|  |                     .collect(Collectors.toCollection(JSONArray::new)); | ||||||
|  | 
 | ||||||
|  |             extendAttr.put("rearNodeArr", rearNodeKeyArr); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.baseModel.setDefinition(defineJsonObj.toJSONString()); | ||||||
|  |         CoeDesignerAPIManager.getInstance().storeDefinition(this.baseModel); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,12 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.graph.component; | package com.actionsoft.apps.coe.method.process.subprocess.graph.component; | ||||||
| 
 | 
 | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType; | ||||||
|  | import com.actionsoft.exception.AWSException; | ||||||
|  | import com.alibaba.fastjson.JSONArray; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| 
 | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * @author oYang |  * @author oYang | ||||||
|  * @Description TODO |  * @Description TODO | ||||||
| @ -99,9 +104,62 @@ public abstract class AbstractDefinitionHandle { | |||||||
|      */ |      */ | ||||||
|     public abstract void updateShapeH(String shapeKey, double h); |     public abstract void updateShapeH(String shapeKey, double h); | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取图形的 x坐标 | ||||||
|  |      * @param shapeKey | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     public abstract double getShapeX(String shapeKey); |     public abstract double getShapeX(String shapeKey); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取图形的 y坐标 | ||||||
|  |      * @param shapeKey | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     public abstract double getShapeY(String shapeKey); |     public abstract double getShapeY(String shapeKey); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取图形的 w宽度 | ||||||
|  |      * @param shapeKey | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     public abstract double getShapeW(String shapeKey); |     public abstract double getShapeW(String shapeKey); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取图形的 h高度 | ||||||
|  |      * @param shapeKey | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     public abstract double getShapeH(String shapeKey); |     public abstract double getShapeH(String shapeKey); | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取所有连线 | ||||||
|  |      * @return | ||||||
|  |      * @throws AWSException | ||||||
|  |      */ | ||||||
|  |     public abstract JSONArray getLinkers() throws AWSException; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取指定的连线 | ||||||
|  |      * @param key | ||||||
|  |      * @return | ||||||
|  |      * @throws AWSException | ||||||
|  |      */ | ||||||
|  |     public abstract JSONObject getLinkerByKey(String key) throws AWSException; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取指定元素的元素类型 | ||||||
|  |      * @param key | ||||||
|  |      * @return | ||||||
|  |      * @throws AWSException | ||||||
|  |      */ | ||||||
|  |     public abstract ElementType getElementTypeByKey(String key) throws AWSException; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取元素类型为 SCOPE_NODE 的元素ID集合 | ||||||
|  |      * @return | ||||||
|  |      * @throws AWSException | ||||||
|  |      */ | ||||||
|  |     public abstract List<String> getScopeNodeIds() throws AWSException; | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +1,14 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.graph.util; | package com.actionsoft.apps.coe.method.process.subprocess.graph.util; | ||||||
| 
 | 
 | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
|  | import com.actionsoft.exception.AWSException; | ||||||
|  | import com.alibaba.fastjson.JSONArray; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| 
 | 
 | ||||||
|  | import java.util.List; | ||||||
| import java.util.concurrent.locks.ReentrantLock; | import java.util.concurrent.locks.ReentrantLock; | ||||||
|  | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @author oYang |  * @author oYang | ||||||
| @ -178,4 +183,61 @@ public class DefinitionThreadSafe extends AbstractDefinitionHandle { | |||||||
|             lock.unlock(); |             lock.unlock(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public JSONArray getLinkers() throws AWSException { | ||||||
|  |         lock.lock(); | ||||||
|  |         try{ | ||||||
|  |             JSONObject elements = getElements(); | ||||||
|  |             JSONArray linkers = elements.keySet() | ||||||
|  |                     .stream() | ||||||
|  |                     .filter(key -> "linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                     .map(key -> elements.getJSONObject(key)) | ||||||
|  |                     .collect(Collectors.toCollection(JSONArray::new)); | ||||||
|  |             return linkers; | ||||||
|  |         }finally { | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public JSONObject getLinkerByKey(String key) throws AWSException { | ||||||
|  |         lock.lock(); | ||||||
|  |         try{ | ||||||
|  |             JSONObject elements = getElements(); | ||||||
|  |             JSONObject ele = elements.getJSONObject(key); | ||||||
|  |             if (!"linker".equals(ele.getString("name"))){ | ||||||
|  |                 throw new AWSException("不存在指定的连线"); | ||||||
|  |             } | ||||||
|  |             return ele; | ||||||
|  |         }finally { | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public ElementType getElementTypeByKey(String key) throws AWSException { | ||||||
|  |         lock.lock(); | ||||||
|  |         try { | ||||||
|  |             JSONObject ele = getShapeByKey(key); | ||||||
|  |             if (ele == null){ | ||||||
|  |                 throw new AWSException("不存在指定的元素"); | ||||||
|  |             } | ||||||
|  |             return ElementType.valueOf(ele.getString("elementType")); | ||||||
|  |         } finally { | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<String> getScopeNodeIds() throws AWSException { | ||||||
|  |         lock.lock(); | ||||||
|  |         try { | ||||||
|  |             JSONObject elements = getElements(); | ||||||
|  |             List<String> scopeShapeIds = elements.keySet().stream().filter(key -> elements.getJSONObject(key).getString("elementType").equals(ElementType.SCOPE_NODE.name())).collect(Collectors.toList()); | ||||||
|  |             return scopeShapeIds; | ||||||
|  |         } finally { | ||||||
|  |             lock.unlock(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,8 +1,15 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.graph.util; | package com.actionsoft.apps.coe.method.process.subprocess.graph.util; | ||||||
| 
 | 
 | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
|  | import com.actionsoft.exception.AWSException; | ||||||
|  | import com.alibaba.fastjson.JSONArray; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| 
 | 
 | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * @author oYang |  * @author oYang | ||||||
|  * @Description 操作 definition 工具类 线程不安全 |  * @Description 操作 definition 工具类 线程不安全 | ||||||
| @ -98,4 +105,41 @@ public class DefinitionThreadUnSafe extends AbstractDefinitionHandle { | |||||||
|     public double getShapeH(String shapeKey) { |     public double getShapeH(String shapeKey) { | ||||||
|         return getShapeByProps(shapeKey).getDoubleValue("h"); |         return getShapeByProps(shapeKey).getDoubleValue("h"); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public JSONArray getLinkers() throws AWSException { | ||||||
|  |         JSONObject elements = getElements(); | ||||||
|  |         JSONArray linkers = elements.keySet() | ||||||
|  |                 .stream() | ||||||
|  |                 .filter(key -> "linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                 .map(key -> elements.getJSONObject(key)) | ||||||
|  |                 .collect(Collectors.toCollection(JSONArray::new)); | ||||||
|  |         return linkers; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public JSONObject getLinkerByKey(String key) throws AWSException { | ||||||
|  |         JSONObject elements = getElements(); | ||||||
|  |         JSONObject ele = elements.getJSONObject(key); | ||||||
|  |         if (!"linker".equals(ele.getString("name"))){ | ||||||
|  |             throw new AWSException("不存在指定的连线"); | ||||||
|  |         } | ||||||
|  |         return ele; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public ElementType getElementTypeByKey(String key) throws AWSException { | ||||||
|  |         JSONObject ele = getShapeByKey(key); | ||||||
|  |         if (ele == null){ | ||||||
|  |             throw new AWSException("不存在指定的元素"); | ||||||
|  |         } | ||||||
|  |         return ElementType.valueOf(ele.getString("elementType")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<String> getScopeNodeIds() throws AWSException { | ||||||
|  |         JSONObject elements = getElements(); | ||||||
|  |         List<String> scopeShapeIds = elements.keySet().stream().filter(key -> elements.getJSONObject(key).getString("elementType").equals(ElementType.SCOPE_NODE.name())).collect(Collectors.toList()); | ||||||
|  |         return scopeShapeIds; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +0,0 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.graph.util; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @author oYang |  | ||||||
|  * @Description TODO |  | ||||||
|  * @createTime 2023年06月09日 16:26:00 |  | ||||||
|  */ |  | ||||||
| public class GraphNodeCloseUtil { |  | ||||||
| } |  | ||||||
| @ -0,0 +1,452 @@ | |||||||
|  | package com.actionsoft.apps.coe.method.process.subprocess.graph.util; | ||||||
|  | 
 | ||||||
|  | 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.graph.component.AbstractDefinitionHandle; | ||||||
|  | import com.actionsoft.bpms.util.ConsolePrinter; | ||||||
|  | import com.actionsoft.bpms.util.UUIDGener; | ||||||
|  | import com.alibaba.fastjson.JSONArray; | ||||||
|  | import com.alibaba.fastjson.JSONObject; | ||||||
|  | 
 | ||||||
|  | import java.util.Comparator; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author oYang | ||||||
|  |  * @Description 连线上所有关键节点(包括起始点以及折点)计算处理 | ||||||
|  |  *              类比起始图形作为直角坐标系的原点 目标图形的位置大体在四个象限内 | ||||||
|  |  * @createTime 2023年06月28日 17:56:00 | ||||||
|  |  */ | ||||||
|  | public class LinkerPointCalculationHandle { | ||||||
|  | 
 | ||||||
|  |     private AbstractDefinitionHandle definitionHandle; | ||||||
|  | 
 | ||||||
|  |     public LinkerPointCalculationHandle(AbstractDefinitionHandle definitionHandle) { | ||||||
|  |         this.definitionHandle = definitionHandle; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 根据布局方向 组装连线 | ||||||
|  |      * @param direction 布局方向 | ||||||
|  |      * @param fromId 起点节点ID | ||||||
|  |      * @param toId 终点节点ID | ||||||
|  |      * @param fromBounding 起点节点边框信息 | ||||||
|  |      * @param toBounding 终点节点边框信息 | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     public JSONObject toAssembleLinker(String direction, String fromId, String toId, double[] fromBounding, double[] toBounding){ | ||||||
|  |         double[][] turnPoi = direction.equals(SubProcessConst.DIRECTION_H) ? horizLayOut(fromBounding, toBounding) : vertLayOut(fromBounding, toBounding); | ||||||
|  |         double[] angleArr = calculationLinkerAngle(turnPoi[0], turnPoi[turnPoi.length - 1], 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", fromId); | ||||||
|  |         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", toId); | ||||||
|  |         linkerObj.put("to", toObj); | ||||||
|  | 
 | ||||||
|  |         return linkerObj; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 节点水平布局下计算连线 | ||||||
|  |      * @param fromBounding | ||||||
|  |      * @param toBounding | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     public double[][] horizLayOut(double[] fromBounding, double[] toBounding){ | ||||||
|  |         double fromX = fromBounding[0],fromY = fromBounding[1], fromW = fromBounding[2], fromH = fromBounding[3]; | ||||||
|  |         double toX = toBounding[0], toY = toBounding[1], toW = toBounding[2], toH = toBounding[3]; | ||||||
|  |         if (fromY == toY) { | ||||||
|  |             return fromX < toX | ||||||
|  |                     ? new double[][] | ||||||
|  |                     { | ||||||
|  |                             {fromX + fromW, fromY + fromH / 2}, | ||||||
|  |                             {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}, | ||||||
|  |                             {toX - rowNodeDistanceWrapper(getNearLeftNodeDistance(toBounding)) / 2, toY + toH / 2}, | ||||||
|  |                             {toX, toY + toH / 2} | ||||||
|  |                     } | ||||||
|  |                     : new double[][] | ||||||
|  |                     { | ||||||
|  |                             {fromX + fromW, fromY + fromH / 2}, | ||||||
|  |                             {fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}, | ||||||
|  |                             {fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY - colNodeDistanceWrapper(getNearTopNodeDistance(fromBounding)) / 2}, | ||||||
|  |                             {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                             {toX + toW / 2, toY} | ||||||
|  |                     }; | ||||||
|  |         }else if (fromX == toX) { // 垂直 | ||||||
|  |             // 节点横向分布 连线按照大原则 垂直 不存在 fromY < toY 的情况 也就是不存在 连线从上到下直连的情况 | ||||||
|  |             double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; | ||||||
|  |             double[] endPoint = new double[]{toX + toW / 2, toY}; | ||||||
|  |             return new double[][]{startPoint, | ||||||
|  |                     {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}, | ||||||
|  |                     {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                     {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                     endPoint}; | ||||||
|  |         }else { | ||||||
|  |             if (fromX < toX && fromY > toY){ // 目标节点在第一象限 | ||||||
|  |                 double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; | ||||||
|  |                 double turnPointX = fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2; | ||||||
|  |                 if (fromX + getCurrentColMaxW(fromX) + getNearRightNodeDistance(fromBounding) == toX){ // 相邻节点 存在两个折点 | ||||||
|  |                     double[] endPoint = new double[]{toX, toY + toH / 2}; | ||||||
|  |                     return new double[][]{startPoint,{turnPointX, fromY + fromH / 2},{turnPointX, toY + toH / 2}, endPoint}; | ||||||
|  |                 }else { // 不相邻节点 存在三个折点 | ||||||
|  |                     double[] endPoint = new double[]{toX + toW / 2, toY}; | ||||||
|  |                     return new double[][]{ | ||||||
|  |                             startPoint, | ||||||
|  |                             {turnPointX, fromY + fromH / 2}, | ||||||
|  |                             {turnPointX, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                             {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                             endPoint | ||||||
|  |                     }; | ||||||
|  |                 } | ||||||
|  |             }else if (fromX > toX && fromY > toY) { // 目标节点在第二象限 无论节点是否相邻 都按照三个折点走 | ||||||
|  |                 double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; | ||||||
|  |                 double[] endPoint = new double[]{toX + toW / 2, toY}; | ||||||
|  |                 return new double[][]{ | ||||||
|  |                         startPoint, | ||||||
|  |                         {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}, | ||||||
|  |                         {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                         {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                         endPoint | ||||||
|  |                 }; | ||||||
|  |             }else if (fromX < toX && fromY < toY){ // 目标节点在第四象限 | ||||||
|  |                 double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; | ||||||
|  |                 if (fromX + getCurrentColMaxW(fromX) + getNearRightNodeDistance(fromBounding) == toX){ // 相邻节点 存在两个折点 | ||||||
|  |                     double turnPointX = fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2; | ||||||
|  |                     double[] endPoint = new double[]{toX, toY + toH / 2}; | ||||||
|  |                     return new double[][]{ | ||||||
|  |                             startPoint, | ||||||
|  |                             {turnPointX, fromY + fromH / 2}, | ||||||
|  |                             {turnPointX, toY + toH / 2}, | ||||||
|  |                             endPoint | ||||||
|  |                     }; | ||||||
|  |                 }else { // 不相邻节点 存在三个折点 | ||||||
|  |                     double[] endPoint = new double[]{toX + toW / 2, toY}; | ||||||
|  |                     return new double[][]{ | ||||||
|  |                             startPoint, | ||||||
|  |                             {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}, | ||||||
|  |                             {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                             {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                             endPoint | ||||||
|  |                     }; | ||||||
|  |                 } | ||||||
|  |             }else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 横向布局的情况下 应该不会出现目标节点在第三象限的情况 | ||||||
|  |                 ConsolePrinter.warn("[端到端功能][节点展开模块]处理连线时目标节点在[横向布局]的情况下出现在了第三象限"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return new double[2][2]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 节点垂直布局下计算连线 | ||||||
|  |      * @param fromBounding | ||||||
|  |      * @param toBounding | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     public double[][] vertLayOut(double[] fromBounding, double[] toBounding){ | ||||||
|  |         double fromX = fromBounding[0],fromY = fromBounding[1], fromW = fromBounding[2], fromH = fromBounding[3]; | ||||||
|  |         double toX = toBounding[0], toY = toBounding[1], toW = toBounding[2], toH = toBounding[3]; | ||||||
|  |         if (fromY == toY){ // 水平 分析可知 水平方向上不会出现 从左到右直连的情况 只有 右边节点右侧锚点出 向上走 左折 连到左侧节点上方锚点 | ||||||
|  |             double[] startPoi = new double[]{fromX + fromW, fromY + fromH / 2}; | ||||||
|  |             double[] turnPoi1 = new double[]{fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}; | ||||||
|  |             double[] turnPoi2 = new double[]{fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}; | ||||||
|  |             double[] turnPoi3 = new double[]{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}; | ||||||
|  |             double[] endPoi = new double[]{toX + toW / 2, toY}; | ||||||
|  |             return new double[][]{startPoi, turnPoi1, turnPoi2, turnPoi3, endPoi}; | ||||||
|  |         }else if (fromX == toX){ // 垂直 分析可知 垂直方向上应该不会有 toY < fromY 的情况 鉴于数据不确定性 先写上 | ||||||
|  |             double[] startPoi = fromY < toY | ||||||
|  |                     ? new double[]{fromX + fromW / 2, fromY + fromH} | ||||||
|  |                     : new double[]{fromX +fromW, fromY + fromH / 2}; | ||||||
|  |             double[] endPoi = new double[]{toX + toW / 2, toY}; | ||||||
|  |             return fromY < toY | ||||||
|  |                     ? new double[][]{ | ||||||
|  |                     startPoi, | ||||||
|  |                     {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2}, | ||||||
|  |                     {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                     endPoi} | ||||||
|  |                     : new double[][]{ | ||||||
|  |                     startPoi, | ||||||
|  |                     {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}, | ||||||
|  |                     {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                     {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                     endPoi}; | ||||||
|  |         }else { // 分布在四个象限内 | ||||||
|  |             if (fromX > toX && fromY > toY){ // 目标节点在第二象限 | ||||||
|  |                 return new double[][]{ | ||||||
|  |                         {fromX + fromW, fromY + fromH / 2}, | ||||||
|  |                         {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2}, | ||||||
|  |                         {fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                         {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                         {toX + toW / 2, toY} | ||||||
|  |                 }; | ||||||
|  |             }else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 | ||||||
|  |                 return toY -  getCurrentRowMaxH(fromY) == getNearBootomNodeDistance(fromBounding) // 相邻行节点 | ||||||
|  |                         ? new double[][] | ||||||
|  |                         { | ||||||
|  |                                 {fromX + fromW / 2, fromY + fromH}, | ||||||
|  |                                 {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2}, | ||||||
|  |                                 {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                                 {toX + toW / 2, toY} | ||||||
|  |                         } | ||||||
|  |                         : new double[][] | ||||||
|  |                         { | ||||||
|  |                                 {fromX + fromW / 2, fromY + fromH}, | ||||||
|  |                                 {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2}, | ||||||
|  |                                 {toX + toW + rowNodeDistanceWrapper(getNearRightNodeDistance(toBounding)) / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2}, | ||||||
|  |                                 {toX + toW + rowNodeDistanceWrapper(getNearRightNodeDistance(toBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                                 {toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2}, | ||||||
|  |                                 {toX + toW / 2, toY} | ||||||
|  |                         }; | ||||||
|  |             }else if (fromX < toX && fromY < toY){ // 目标节点在第四象限 | ||||||
|  |                 return new double[][]{ | ||||||
|  |                         {fromX + fromW / 2, fromY + fromH}, | ||||||
|  |                         {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2}, | ||||||
|  |                         {toX + toW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2}, | ||||||
|  |                         {toX + toW / 2, toY} | ||||||
|  |                 }; | ||||||
|  |             }else { | ||||||
|  |                 // fromX < toX && fromY > toY 目标节点在第一象限 分析可知 纵向排布的情况下 应该不会出现目标节点在第一象限的情况 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return new double[2][2]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前同一列图形的最大宽度 在水平布局中 | ||||||
|  |      * @param fromShapeX 当前图形的 x 坐标 | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double getCurrentColMaxW(double shapeX){ | ||||||
|  |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         JSONObject props = elements.keySet().stream() | ||||||
|  |                 .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && shapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) | ||||||
|  |                 .map(key -> elements.getJSONObject(key).getJSONObject("props")) | ||||||
|  |                 .max(Comparator.comparing(o -> o.getDoubleValue("w"))).get(); | ||||||
|  |         return props.getDoubleValue("w"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前同一行图形的最大高度 在垂直布局中 | ||||||
|  |      * @param fromShapeY | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double getCurrentRowMaxH(double shapeY){ | ||||||
|  |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         JSONObject props = elements.keySet().stream() | ||||||
|  |                 .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && shapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) | ||||||
|  |                 .map(key -> elements.getJSONObject(key).getJSONObject("props")) | ||||||
|  |                 .max(Comparator.comparing(o -> o.getDoubleValue("h"))).get(); | ||||||
|  |         return props.getDoubleValue("h"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 水平方向上 左侧相邻节点 可能为空 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return JSONObject shape | ||||||
|  |      */ | ||||||
|  |     private JSONObject getNearLeftNode(double[] shapeBounding){ | ||||||
|  |         double shapeX = shapeBounding[0], shapeY = shapeBounding[1]; | ||||||
|  |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         JSONObject leftNode = elements.keySet().stream() | ||||||
|  |                 .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                 .filter(key -> shapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) | ||||||
|  |                 .filter(key -> shapeX > elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) | ||||||
|  |                 .map(key -> elements.getJSONObject(key)) | ||||||
|  |                 .max(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("x"))).orElse(null); | ||||||
|  |         return leftNode; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 水平方向上 与左侧相邻节点的间距 如果为空 则返回默认间距 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double getNearLeftNodeDistance(double[] shapeBounding){ | ||||||
|  |         JSONObject nearLeftNode = getNearLeftNode(shapeBounding); | ||||||
|  |         if (nearLeftNode == null){ | ||||||
|  |             return SubProcessConst.SHAPE_HORIZ_INTERVAL; | ||||||
|  |         } | ||||||
|  |         double shapeX = shapeBounding[0]; | ||||||
|  |         JSONObject props = nearLeftNode.getJSONObject("props"); | ||||||
|  |         return shapeX - props.getDoubleValue("x") + props.getDoubleValue("w"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 水平方向上 右侧相邻节点 可能为空 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private JSONObject getNearRightNode(double[] shapeBounding){ | ||||||
|  |         double shapeX = shapeBounding[0], shapeY = shapeBounding[1]; | ||||||
|  |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         JSONObject rightNode = elements.keySet().stream() | ||||||
|  |                 .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                 .filter(key -> shapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) | ||||||
|  |                 .filter(key -> shapeX < elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) | ||||||
|  |                 .map(key -> elements.getJSONObject(key)) | ||||||
|  |                 .min(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("x"))).orElse(null); | ||||||
|  |         return rightNode; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 水平方向上 与右侧相邻节点的间距 如果为空 则返回默认间距 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double getNearRightNodeDistance(double[] shapeBounding){ | ||||||
|  |         JSONObject nearRightNode = getNearRightNode(shapeBounding); | ||||||
|  |         if (nearRightNode == null){ | ||||||
|  |             return SubProcessConst.SHAPE_HORIZ_INTERVAL; | ||||||
|  |         } | ||||||
|  |         double shapeX = shapeBounding[0], shapeW = shapeBounding[2]; | ||||||
|  |         JSONObject props = nearRightNode.getJSONObject("props"); | ||||||
|  |         return props.getDoubleValue("x") - shapeX + shapeW; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 垂直方向上 与上侧相邻节点 可能为空 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private JSONObject getNearTopNode(double[] shapeBounding){ | ||||||
|  |         double shapeX = shapeBounding[0], shapeY = shapeBounding[1]; | ||||||
|  |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         JSONObject topNode = elements.keySet().stream() | ||||||
|  |                 .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                 .filter(key -> shapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) | ||||||
|  |                 .filter(key -> shapeY > elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) | ||||||
|  |                 .map(key -> elements.getJSONObject(key)) | ||||||
|  |                 .max(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("y"))).orElse(null); | ||||||
|  |         return topNode; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 垂直方向上 与上侧相邻节点的间距 如果为空 则返回默认间距 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double getNearTopNodeDistance(double[] shapeBounding){ | ||||||
|  |         JSONObject nearTopNode = getNearTopNode(shapeBounding); | ||||||
|  |         if (nearTopNode == null){ | ||||||
|  |             return SubProcessConst.SHAPE_VERT_INTERVAL; | ||||||
|  |         } | ||||||
|  |         JSONObject props = nearTopNode.getJSONObject("props"); | ||||||
|  |         double shapeY = shapeBounding[1]; | ||||||
|  |         return shapeY - props.getDoubleValue("y") + props.getDoubleValue("h"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 垂直方向上 与下侧相邻节点 可能为空 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private JSONObject getNearBootomNode(double[] shapeBounding){ | ||||||
|  |         double shapeX = shapeBounding[0], shapeY = shapeBounding[1]; | ||||||
|  |         JSONObject elements = definitionHandle.getElements(); | ||||||
|  |         JSONObject bottomNode = elements.keySet().stream() | ||||||
|  |                 .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name"))) | ||||||
|  |                 .filter(key -> shapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) | ||||||
|  |                 .filter(key -> shapeY < elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) | ||||||
|  |                 .map(key -> elements.getJSONObject(key)) | ||||||
|  |                 .min(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("y"))).orElse(null); | ||||||
|  |         return bottomNode; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取当前图形 垂直方向上 与下侧相邻节点的间距 如果为空 则返回默认间距 | ||||||
|  |      * @param shapeBounding [x, y, w, h] | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double getNearBootomNodeDistance(double[] shapeBounding){ | ||||||
|  |         JSONObject nearBootomNode = getNearBootomNode(shapeBounding); | ||||||
|  |         if (nearBootomNode == null){ | ||||||
|  |             return SubProcessConst.SHAPE_VERT_INTERVAL; | ||||||
|  |         } | ||||||
|  |         JSONObject props = nearBootomNode.getJSONObject("props"); | ||||||
|  |         double shapeY = shapeBounding[1], shapeH = shapeBounding[3]; | ||||||
|  |         return props.getDoubleValue("y") - shapeY + shapeH; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 如果水平方向上节点间距大于默认间距 返回默认间距 否则返回实际间距 | ||||||
|  |      * @param distance | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double rowNodeDistanceWrapper(double distance){ | ||||||
|  |         if (distance > SubProcessConst.SHAPE_HORIZ_INTERVAL){ | ||||||
|  |             return SubProcessConst.SHAPE_HORIZ_INTERVAL; | ||||||
|  |         } | ||||||
|  |         return distance; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 如果垂直方向上节点间距大于默认间距 返回默认间距 否则返回实际间距 | ||||||
|  |      * @param distance | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     private double colNodeDistanceWrapper(double distance){ | ||||||
|  |         if (distance > SubProcessConst.SHAPE_VERT_INTERVAL){ | ||||||
|  |             return SubProcessConst.SHAPE_VERT_INTERVAL; | ||||||
|  |         } | ||||||
|  |         return distance; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 计算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}; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,20 +1,20 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.mode; | package com.actionsoft.apps.coe.method.process.subprocess.graph.util; | ||||||
| 
 | 
 | ||||||
|  | import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; | ||||||
| import com.actionsoft.exception.AWSException; | import com.actionsoft.exception.AWSException; | ||||||
| import com.alibaba.fastjson.JSONArray; | import com.alibaba.fastjson.JSONArray; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| 
 | 
 | ||||||
| import java.util.HashMap; | import java.util.*; | ||||||
| import java.util.HashSet; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Set; |  | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @author oYang |  * @author oYang | ||||||
|  * @Description 构建虚线范围框监视器模型且关联其内部元素 方便最后调整范围框内的元素 |  * @Description 构建总图中已存在的范围框监视器模型且关联其内部元素 | ||||||
|  |  *              方便最后调整范围框内的元素位置 | ||||||
|  |  *              内部元素只包含元素类型为 ElementType.INNER_NODE ElementType.INNER_LINKER | ||||||
|  * @createTime 2023年06月13日 14:46:00 |  * @createTime 2023年06月13日 14:46:00 | ||||||
|  */ |  */ | ||||||
| public class ScopeShapeMonitor { | public class ScopeShapeMonitor { | ||||||
| @ -34,43 +34,34 @@ public class ScopeShapeMonitor { | |||||||
|      */ |      */ | ||||||
|     public void buildScopeShapeMonitors(){ |     public void buildScopeShapeMonitors(){ | ||||||
|         JSONObject elements = definitionHandle.getElements(); |         JSONObject elements = definitionHandle.getElements(); | ||||||
|         Set<String> scopeShapeKeySet = elements.keySet().stream().filter(key -> "scopeLimitation".equals(elements.getJSONObject(key).getString("name"))).collect(Collectors.toSet()); |         // 获取总图中已存在的范围框图形ID集合 | ||||||
|  |         List<String> scopeShapeKeySet = definitionHandle.getScopeNodeIds(); | ||||||
|         if (scopeShapeKeySet.size() == 0) return; |         if (scopeShapeKeySet.size() == 0) return; | ||||||
| 
 | 
 | ||||||
|         Map<String, MonitorInfo> scopeShapeMonitorMap = new HashMap<>(); |         Map<String, MonitorInfo> scopeShapeMonitorMap = new HashMap<>(); | ||||||
|         for (String scopeShapeKey : scopeShapeKeySet) { |         for (String scopeShapeKey : scopeShapeKeySet) { | ||||||
|             JSONObject props = definitionHandle.getShapeByProps(scopeShapeKey); |             JSONObject scopeShape = definitionHandle.getShapeByKey(scopeShapeKey); | ||||||
|             double scopeX = props.getDoubleValue("x"), scopeY = props.getDoubleValue("y"), scopeW = props.getDoubleValue("w"), scopeH = props.getDoubleValue("h"); |             // 获取范围框内部元素 | ||||||
|             // 判断当前元素是否在范围选择框的范围内 |             JSONArray innerEleIds = scopeShape.getJSONArray(SubProcessConst.INNER_ELEMENTS); | ||||||
|             Set<String> inRangeEleKeySet = new HashSet<>(); |             Set<String> inRangeEleKeySet = innerEleIds.stream().map(o -> o.toString()).collect(Collectors.toSet()); | ||||||
|             for (String key : elements.keySet()) { |  | ||||||
|                 if (scopeShapeKey.equals(key)) continue; // 范围框本身不算作其内部元素 |  | ||||||
|                 JSONObject shape = definitionHandle.getShapeByKey(key); |  | ||||||
|                 if ("linker".equals(shape.getString("name"))){ // 连线 |  | ||||||
|                     JSONObject from = shape.getJSONObject("from"); |  | ||||||
|                     JSONObject to = shape.getJSONObject("to"); |  | ||||||
|                     double fromX = from.getDoubleValue("x"), fromY = from.getDoubleValue("y"), toX = to.getDoubleValue("x"), toY = to.getDoubleValue("y"); |  | ||||||
|                     if ((scopeX < fromX && fromX < scopeX + scopeW && scopeY < fromY && fromY < scopeY + scopeH) || (scopeX < toX && toX < scopeX + scopeW && scopeY < toY && toY < scopeY + scopeH)){ |  | ||||||
|                         inRangeEleKeySet.add(key); |  | ||||||
|                     } |  | ||||||
|                 }else { |  | ||||||
|                     double x = definitionHandle.getShapeByProps(key).getDoubleValue("x"); |  | ||||||
|                     double y = definitionHandle.getShapeByProps(key).getDoubleValue("y"); |  | ||||||
|                     if (scopeX <= x && x < scopeX + scopeW && scopeY <= y && y < scopeY + scopeH){ |  | ||||||
|                         inRangeEleKeySet.add(key); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             MonitorInfo monitorInfo = new MonitorInfo(scopeShapeKey, false, 0.0, false, 0.0, inRangeEleKeySet); |             MonitorInfo monitorInfo = new MonitorInfo(scopeShapeKey, false, 0.0, false, 0.0, inRangeEleKeySet); | ||||||
|             scopeShapeMonitorMap.put(scopeShapeKey, monitorInfo); |             scopeShapeMonitorMap.put(scopeShapeKey, monitorInfo); | ||||||
|         } |         } | ||||||
|         this.scopeShapeMonitorMap = scopeShapeMonitorMap; |         this.scopeShapeMonitorMap = scopeShapeMonitorMap; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 返回所有的范围框监视器数据模型 | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     public Map<String, MonitorInfo> getScopeShapeMonitorMap() { |     public Map<String, MonitorInfo> getScopeShapeMonitorMap() { | ||||||
|         return scopeShapeMonitorMap; |         return scopeShapeMonitorMap; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 移除指定的范围框监视器数据模型 | ||||||
|  |      * @param scopeShapeId | ||||||
|  |      */ | ||||||
|     public void removeScopeShapeByKey(String scopeShapeId){ |     public void removeScopeShapeByKey(String scopeShapeId){ | ||||||
|         if (scopeShapeMonitorMap.containsKey(scopeShapeId)){ |         if (scopeShapeMonitorMap.containsKey(scopeShapeId)){ | ||||||
|             scopeShapeMonitorMap.remove(scopeShapeId); |             scopeShapeMonitorMap.remove(scopeShapeId); | ||||||
| @ -78,7 +69,7 @@ public class ScopeShapeMonitor { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 更新范围框的监视属性信息 |      * 更新指定范围框内部元素在x方向上的位置信息 | ||||||
|      * @param scopeShapeId 当前范围框图形ID |      * @param scopeShapeId 当前范围框图形ID | ||||||
|      * @param isRightMove 是否右移 |      * @param isRightMove 是否右移 | ||||||
|      * @param rightMoveDistance 右移动距离 |      * @param rightMoveDistance 右移动距离 | ||||||
| @ -94,7 +85,7 @@ public class ScopeShapeMonitor { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 更新范围框的监视属性信息 |      * 更新指定范围框内部元素在y方向上的位置信息 | ||||||
|      * @param scopeShapeId 当前范围框图形ID |      * @param scopeShapeId 当前范围框图形ID | ||||||
|      * @param isBottomMove 是否下移 |      * @param isBottomMove 是否下移 | ||||||
|      * @param bottomMoveDistance 下移距离 |      * @param bottomMoveDistance 下移距离 | ||||||
| @ -194,7 +185,6 @@ public class ScopeShapeMonitor { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     public class MonitorInfo { |     public class MonitorInfo { | ||||||
| 
 | 
 | ||||||
|         private String scopeShapeId; // 当前虚线范围框的图形ID |         private String scopeShapeId; // 当前虚线范围框的图形ID | ||||||
| @ -36,6 +36,11 @@ public class SubProcessNodeDefineUtil { | |||||||
|             if (childProcessBaseModel == null) |             if (childProcessBaseModel == null) | ||||||
|                 throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开"); |                 throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开"); | ||||||
|             subProcessNodeDefineStr = childProcessBaseModel.getDefinition(); |             subProcessNodeDefineStr = childProcessBaseModel.getDefinition(); | ||||||
|  |             JSONObject defineObj = JSONObject.parseObject(subProcessNodeDefineStr); | ||||||
|  |             JSONObject elements = defineObj.getJSONObject("elements"); | ||||||
|  |             if (elements.size() == 0){ | ||||||
|  |                 throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开"); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         return subProcessNodeDefineStr; |         return subProcessNodeDefineStr; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,9 +1,8 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.observers.node; | package com.actionsoft.apps.coe.method.process.subprocess.observers.node; | ||||||
| 
 | 
 | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer; | import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer; | ||||||
| import com.alibaba.fastjson.JSONObject; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @author oYang |  * @author oYang | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ package com.actionsoft.apps.coe.method.process.subprocess.observers.node; | |||||||
| 
 | 
 | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; | import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; | import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer; | import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer; | ||||||
| import com.actionsoft.apps.coe.method.process.subprocess.observers.Subject; | import com.actionsoft.apps.coe.method.process.subprocess.observers.Subject; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
|  | |||||||
| @ -1,22 +0,0 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.uitl; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @author oYang |  | ||||||
|  * @create 2023-05-11 13:57 |  | ||||||
|  */ |  | ||||||
| public class Node { |  | ||||||
| 
 |  | ||||||
|     public int id; // 节点id |  | ||||||
|     public double x; // 节点x坐标 |  | ||||||
|     public double y; // 节点y坐标 |  | ||||||
|     public double displaceX; // x方向移动位移 |  | ||||||
|     public double displaceY; // y方向移动位移 |  | ||||||
| 
 |  | ||||||
|     public Node(int id) { |  | ||||||
|         this.id = id; |  | ||||||
|         this.x = 0; |  | ||||||
|         this.y = 0; |  | ||||||
|         this.displaceX = 0; |  | ||||||
|         this.displaceY = 0; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,113 +0,0 @@ | |||||||
| package com.actionsoft.apps.coe.method.process.subprocess.uitl; |  | ||||||
| 
 |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Random; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @author oYang |  | ||||||
|  * @create 2023-05-11 13:53 |  | ||||||
|  */ |  | ||||||
| public class UtilTestGraph { |  | ||||||
| 
 |  | ||||||
|     private final int width; // 布局区域宽度 |  | ||||||
|     private final int height; // 布局区域高度 |  | ||||||
|     private final double k; // 弹性系数 |  | ||||||
|     private final double k2; // 斥力系数 |  | ||||||
|     private final double damping; // 阻尼系数 |  | ||||||
|     private final double maxDisplace; // 最大移动距离 |  | ||||||
|     private final int maxIterations; // 最大迭代次数 |  | ||||||
| 
 |  | ||||||
|     // 存储每个节点的位置信息 |  | ||||||
|     private ArrayList<Node> nodes; |  | ||||||
| 
 |  | ||||||
|     // 存储每个节点之间的连线信息(邻接矩阵) |  | ||||||
|     private int[][] adjacencyMatrix; |  | ||||||
| 
 |  | ||||||
|     public UtilTestGraph(int width, int height, double k, double k2, double damping, double maxDisplace, int maxIterations, int nodeCount) { |  | ||||||
|         this.width = width; |  | ||||||
|         this.height = height; |  | ||||||
|         this.k = k; |  | ||||||
|         this.k2 = k2; |  | ||||||
|         this.damping = damping; |  | ||||||
|         this.maxDisplace = maxDisplace; |  | ||||||
|         this.maxIterations = maxIterations; |  | ||||||
| 
 |  | ||||||
|         // 初始化节点数组 |  | ||||||
|         this.nodes = new ArrayList<>(nodeCount); |  | ||||||
|         for (int i = 0; i < nodeCount; i++) { |  | ||||||
|             Node node = new Node(i); |  | ||||||
|             node.x = Math.random() * this.width; |  | ||||||
|             node.y = Math.random() * this.height; |  | ||||||
|             nodes.add(node); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // 初始化邻接矩阵 |  | ||||||
|         this.adjacencyMatrix = new int[nodeCount][nodeCount]; |  | ||||||
|         Random random = new Random(); |  | ||||||
|         for (int i = 0; i < nodeCount; i++) { |  | ||||||
|             for (int j = i + 1; j < nodeCount; j++) { |  | ||||||
|                 // 随机生成一个有连线的概率 |  | ||||||
|                 double p = random.nextDouble(); |  | ||||||
|                 if (p < 0.3) { |  | ||||||
|                     adjacencyMatrix[i][j] = 1; |  | ||||||
|                     adjacencyMatrix[j][i] = 1; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // 执行布局操作 |  | ||||||
|     public void executeLayout() { |  | ||||||
|         for (int i = 0; i < maxIterations; i++) { |  | ||||||
|             for (int j = 0; j < nodes.size(); j++) { |  | ||||||
|                 Node node = nodes.get(j); |  | ||||||
|                 node.displaceX = 0; |  | ||||||
|                 node.displaceY = 0; |  | ||||||
|                 for (int k = 0; k < nodes.size(); k++) { |  | ||||||
|                     if (j == k) continue; |  | ||||||
|                     Node other = nodes.get(k); |  | ||||||
|                     double dx = other.x - node.x; |  | ||||||
|                     double dy = other.y - node.y; |  | ||||||
|                     double distanceSquared = dx * dx + dy * dy; |  | ||||||
|                     if (distanceSquared == 0) { |  | ||||||
|                         dx = randomDisplacement(); |  | ||||||
|                         dy = randomDisplacement(); |  | ||||||
|                         distanceSquared = dx * dx + dy * dy; |  | ||||||
|                     } |  | ||||||
|                     double distance = Math.sqrt(distanceSquared); |  | ||||||
|                     double force = (k * k / distance) - (k2 * distance); |  | ||||||
|                     node.displaceX += (dx / distance) * force; |  | ||||||
|                     node.displaceY += (dy / distance) * force; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // 移动节点的位置 |  | ||||||
|             for (Node node : nodes) { |  | ||||||
|                 double xDisplace = node.displaceX * damping; |  | ||||||
|                 double yDisplace = node.displaceY * damping; |  | ||||||
|                 double displace = Math.sqrt(xDisplace * xDisplace + yDisplace * yDisplace); |  | ||||||
|                 if (displace > maxDisplace) { |  | ||||||
|                     xDisplace *= maxDisplace / displace; |  | ||||||
|                     yDisplace *= maxDisplace / displace; |  | ||||||
|                 } |  | ||||||
|                 node.x += xDisplace; |  | ||||||
|                 node.y += yDisplace; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // 随机生成一个小的位移量 |  | ||||||
|     private double randomDisplacement() { |  | ||||||
|         return (Math.random() - 0.5) * 0.1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         UtilTestGraph layout = new UtilTestGraph(800, 600, 5.0, 0.1, 0.9, 5.0, 100, 20); |  | ||||||
|         layout.executeLayout(); |  | ||||||
| 
 |  | ||||||
|         // 输出节点的最终位置 |  | ||||||
|         for (Node node : layout.nodes) { |  | ||||||
|             System.out.println("Node " + node.id + ": (" + node.x + ", " + node.y + ")"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -306,6 +306,8 @@ public class SubProcessWeb extends ActionWeb { | |||||||
|         // 流程属性中加入布局方向 |         // 流程属性中加入布局方向 | ||||||
|         graphRender.addDirectionToProcessProperties(direction); |         graphRender.addDirectionToProcessProperties(direction); | ||||||
| 
 | 
 | ||||||
|  |         graphRender.addLeadAndRearInfoToElements(); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -324,6 +326,7 @@ public class SubProcessWeb extends ActionWeb { | |||||||
|             ro.setData(define); |             ro.setData(define); | ||||||
|             return ro.toString(); |             return ro.toString(); | ||||||
|         } catch (AWSException e) { |         } catch (AWSException e) { | ||||||
|  |             e.printStackTrace(); | ||||||
|             return ResponseObject.newErrResponse(e.getMessage()).toString(); |             return ResponseObject.newErrResponse(e.getMessage()).toString(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -343,6 +346,7 @@ public class SubProcessWeb extends ActionWeb { | |||||||
|             ro.setData(define); |             ro.setData(define); | ||||||
|             return ro.toString(); |             return ro.toString(); | ||||||
|         } catch (AWSException e) { |         } catch (AWSException e) { | ||||||
|  |             e.printStackTrace(); | ||||||
|             return ResponseObject.newErrResponse(e.getMessage()).toString(); |             return ResponseObject.newErrResponse(e.getMessage()).toString(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 qinoy
						qinoy