Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(waypoints): consider split/merge gateways for edge direction #72

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ else if (positionFrom.getY() == positionTo.getY()) {
.stream()
.filter(p -> p.getY() == positionFrom.getY())
.anyMatch(p -> p.getX() == positionFrom.getX() + 1);
edgeDirection = shapeExistAtRightPositionFrom || (isGatewayAt(positionFrom) && !isGatewayAt(positionTo)) ? EdgeDirection.TopLeftToBottomRight_FirstVertical : EdgeDirection.TopLeftToBottomRight_FirstHorizontal;
edgeDirection = shapeExistAtRightPositionFrom || (isGatewayAt(positionFrom) && (!isGatewayAt(positionTo) || isGatewaySplitAt(positionTo))) ? EdgeDirection.TopLeftToBottomRight_FirstVertical : EdgeDirection.TopLeftToBottomRight_FirstHorizontal;
}
else {
if (isGatewayAt(positionFrom)) {
edgeDirection = isGatewayAt(positionTo) ? EdgeDirection.BottomLeftToTopRight_FirstHorizontal : EdgeDirection.BottomLeftToTopRight_FirstVertical;
edgeDirection = !isGatewaySplitAt(positionFrom) || isGatewayAt(positionTo) && !isGatewaySplitAt(positionTo) ? EdgeDirection.BottomLeftToTopRight_FirstHorizontal : EdgeDirection.BottomLeftToTopRight_FirstVertical;
} else {
boolean shapeExistAbovePositionFrom = grid.getPositions()
.stream()
Expand Down Expand Up @@ -246,6 +246,10 @@ private static boolean isGatewayAt(Position position) {
return ShapeType.GATEWAY.equals(position.getShapeType());
}

private static boolean isGatewaySplitAt(Position position) {
return isGatewayAt(position) && position.isSplitGateway();
}

// visible for testing
static enum EdgeDirection {
HorizontalLeftToRight,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@ public Diagram toAlgoModel(TDefinitions definitions) {
// visible for testing
static Shape toShape(TFlowElement flowNode) {
ShapeType shapeType = ACTIVITY;
boolean isSplitGateway = false;
if (flowNode instanceof TGateway) {
shapeType = GATEWAY;
isSplitGateway = ((TGateway) flowNode).getOutgoing().size() > 1;
} else if (flowNode instanceof TEvent) {
shapeType = EVENT;
}
return new Shape(flowNode.getId(), flowNode.getName(), shapeType);
return new Shape(flowNode.getId(), flowNode.getName(), shapeType, isSplitGateway);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ public class Position {
private final String shape;
private final String shapeName;
private final ShapeType shapeType;
private final boolean isSplitGateway;

private final int x;
private final int y;

public static Position position(Shape shape, int x, int y) {
return new Position(shape.getId(), shape.getName(), shape.getType(), x, y);
return new Position(shape.getId(), shape.getName(), shape.getType(), shape.isSplitGateway(), x, y);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ public class Shape {
private final String id; // the bpmnElement id
private final String name;
private final ShapeType type;
private final boolean isSplitGateway;

public static Shape shape(String name) {
return new Shape(name, name, ACTIVITY);
return new Shape(name, name, ACTIVITY, false);
}

public static Shape shape(String id, String name) {
return new Shape(id, name, ACTIVITY);
return new Shape(id, name, ACTIVITY, false);
}

public static Shape shape(String id, String name, ShapeType type) {
return new Shape(id, name, type, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,13 @@
public class AppFromBpmnTest {

@Test
public void main_generates_bpmn_output_file_for_A_2_0() throws Exception {
runAndCheckBPMNGeneration("bpmn/A.2.0.bpmn.xml", "A.2.0_with_diagram.bpmn.xml");
public void main_generates_output_files_for_A_2_0() throws Exception {
runAndCheckBpmnAndSvgGeneration("bpmn/A.2.0.bpmn.xml", "A.2.0_with_diagram.bpmn");
}

@Test
public void main_generates_bpmn_output_file_for_A_2_1() throws Exception {
runAndCheckBPMNGeneration("bpmn/A.2.1.bpmn.xml", "A.2.1_with_diagram.bpmn.xml");
}

@Test
public void main_generates_svg_output_file_for_A_2_0() throws Exception {
runAndCheckSvgGeneration("bpmn/A.2.0.bpmn.xml", "A.2.0_with_diagram.bpmn.svg");
public void main_generates_output_files_for_A_2_1() throws Exception {
runAndCheckBpmnAndSvgGeneration("bpmn/A.2.1.bpmn.xml", "A.2.1_with_diagram.bpmn");
}

@Test
Expand All @@ -54,21 +49,26 @@ public void main_generates_ascii_output_file() throws Exception {

@Test
public void main_generates_output_files_for_waypoints_positions_for_gateways() throws Exception {
runAndCheckBPMNGeneration("bpmn/waypoints-positions-gateways.bpmn.xml", "waypoints-positions_with_diagram.bpmn.xml");
runAndCheckSvgGeneration("bpmn/waypoints-positions-gateways.bpmn.xml", "waypoints-positions_with_diagram.bpmn.svg");
runAndCheckBpmnAndSvgGeneration("bpmn/waypoints-positions-gateways.bpmn.xml",
"waypoints-positions_with_diagram.bpmn");
}

@Test
public void main_generates_output_files_for_waypoints_positions_for_gateways_split_merge() throws Exception {
runAndCheckBPMNGeneration("bpmn/waypoints-positions-gateways_split_merge.bpmn.xml", "waypoints-positions-gateways_split_merge.bpmn.xml");
runAndCheckSvgGeneration("bpmn/waypoints-positions-gateways_split_merge.bpmn.xml", "waypoints-positions-gateways_split_merge.bpmn.svg");
runAndCheckBpmnAndSvgGeneration("bpmn/waypoints-positions-gateways_split_merge.bpmn.xml",
"waypoints-positions-gateways_split_merge.bpmn");
}

// =================================================================================================================
// UTILS
// =================================================================================================================

private static void runAndCheckBPMNGeneration(String inputFileName, String outputFileName) throws IOException {
private static void runAndCheckBpmnAndSvgGeneration(String inputFileName, String outputFileBaseName) throws IOException {
runAndCheckBpmnGeneration(inputFileName, outputFileBaseName + ".xml");
runAndCheckSvgGeneration(inputFileName, outputFileBaseName + ".svg");
}

private static void runAndCheckBpmnGeneration(String inputFileName, String outputFileName) throws IOException {
String outputPath = outputPath(outputFileName);
runApp(input(inputFileName), "-o", outputPath);
assertBpmnOutFile(outputPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.junit.jupiter.api.Test;

import static io.process.analytics.tools.bpmn.generator.converter.AlgoToDisplayModelConverter.EdgeDirection.*;
import static io.process.analytics.tools.bpmn.generator.model.Shape.shape;
import static org.assertj.core.api.Assertions.assertThat;

class AlgoToDisplayModelConverterTest {
Expand Down Expand Up @@ -93,47 +94,77 @@ public void computeEdgeDirection_no_elements_between_from_and_top_with_from_on_b
// =================================================================================================================

@Test
public void computeEdgeDirection_from_gateway_on_bottom_left_to_on_top_right() {
// +-----------------+
// | to |
// | from-gw |
// +-----------------+
assertThat(computeEdgeDirection(positionGateway(10, 100), position(50, 50)))
public void computeEdgeDirection_from_split_gateway_on_bottom_left_to_on_top_right() {
// +---------------------+
// | to |
// | from-gw-split |
// +---------------------+
assertThat(computeEdgeDirection(positionGatewaySplit(10, 100), position(50, 50)))
.isEqualTo(BottomLeftToTopRight_FirstVertical);
}

@Test
public void computeEdgeDirection_from_gateway_on_bottom_left_to_gateway_on_top_right() {
// +-----------------+
// | to-gw |
// | from-gw |
// +-----------------+
assertThat(computeEdgeDirection(positionGateway(10, 100), positionGateway(50, 50)))
public void computeEdgeDirection_from_merge_gateway_on_bottom_left_to_on_top_right() {
// +---------------------+
// | to |
// | from-gw-merge |
// +---------------------+
assertThat(computeEdgeDirection(positionGatewayMerge(10, 100), position(50, 50)))
.isEqualTo(BottomLeftToTopRight_FirstHorizontal);
}

@Test
public void computeEdgeDirection_from_gateway_on_bottom_left_to_gateway_merge_on_top_right() {
// +-----------------------+
// | to-gw-merge |
// | from-gw | --> merge gateway
// +-----------------------+
assertThat(computeEdgeDirection(positionGateway(10, 100), positionGatewayMerge(50, 50)))
.isEqualTo(BottomLeftToTopRight_FirstHorizontal);
}

@Test
public void computeEdgeDirection_from_gateway_on_bottom_left_to_gateway_split_on_top_right() {
// +-----------------------------+
// | to-gw-split |
// | from-gw-split |
// +-----------------------------+
assertThat(computeEdgeDirection(positionGatewaySplit(10, 100), positionGatewaySplit(50, 50)))
.isEqualTo(BottomLeftToTopRight_FirstVertical);
}

@Test
public void computeEdgeDirection_from_gateway_on_top_left_to_on_bottom_right() {
// +-----------------+
// | from-gw |
// | from-gw | --> split gateway
// | to |
// +-----------------+
assertThat(computeEdgeDirection(positionGateway(10, 10), position(50, 50)))
.isEqualTo(TopLeftToBottomRight_FirstVertical);
}

@Test
public void computeEdgeDirection_from_gateway_on_top_left_to_on_bottom_right_is_gateway() {
// +-----------------+
// | from-gw |
// | to-gw |
// +-----------------+
assertThat(computeEdgeDirection(positionGateway(10, 10), positionGateway(50, 50)))
public void computeEdgeDirection_from_gateway_on_top_left_to_gateway_merge_on_bottom_right() {
// +-----------------------+
// | from-gw | --> split gateway
// | to-gw-merge |
// +-----------------------+
assertThat(computeEdgeDirection(positionGateway(10, 10), positionGatewayMerge(50, 50)))
.isEqualTo(TopLeftToBottomRight_FirstHorizontal);
}

@Test
public void computeEdgeDirection_from_gateway_on_top_left_to_on_bottom_right_is_gateway_with_element_on_top_left() {
public void computeEdgeDirection_from_gateway_on_top_left_to_gateway_split_on_bottom_right() {
// +-----------------------+
// | from-gw | --> split gateway
// | to-gw-split |
// +-----------------------+
assertThat(computeEdgeDirection(positionGateway(10, 10), positionGatewaySplit(50, 50)))
.isEqualTo(TopLeftToBottomRight_FirstVertical);
}

@Test
public void computeEdgeDirection_from_gateway_on_top_left_to_gateway_on_bottom_right_with_element_on_top_left() {
// +-----------------+
// | from-gw elt |
// | to-gw |
Expand All @@ -146,7 +177,7 @@ public void computeEdgeDirection_from_gateway_on_top_left_to_on_bottom_right_is_
public void computeEdgeDirection_from_on_top_left_to_gateway_on_bottom_right() {
// +-----------------+
// | from |
// | to-gw |
// | to-gw | --> merge gateway
// +-----------------+
assertThat(computeEdgeDirection(position(10, 10), positionGateway(50, 50)))
.isEqualTo(TopLeftToBottomRight_FirstHorizontal);
Expand All @@ -155,7 +186,7 @@ public void computeEdgeDirection_from_on_top_left_to_gateway_on_bottom_right() {
@Test
public void computeEdgeDirection_from_on_bottom_left_to_gateway_on_top_right() {
// +-----------------+
// | to-gw |
// | to-gw | --> merge gateway
// | from |
// +-----------------+
assertThat(computeEdgeDirection(position(10, 100), positionGateway(50, 50)))
Expand Down Expand Up @@ -271,7 +302,15 @@ private static Position position(int x, int y) {
}

private static Position positionGateway(int x, int y) {
return Position.position(new Shape(null, null, ShapeType.GATEWAY), x, y);
return Position.position(shape(null, null, ShapeType.GATEWAY), x, y);
}

private static Position positionGatewaySplit(int x, int y) {
return Position.position(new Shape(null, null, ShapeType.GATEWAY, true), x, y);
}

private static Position positionGatewayMerge(int x, int y) {
return Position.position(new Shape(null, null, ShapeType.GATEWAY, false), x, y);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static io.process.analytics.tools.bpmn.generator.internal.SemanticTest.definitionsFromBpmnFile;
import static io.process.analytics.tools.bpmn.generator.model.Edge.edge;
import static io.process.analytics.tools.bpmn.generator.model.Shape.shape;
import static io.process.analytics.tools.bpmn.generator.model.ShapeType.*;
import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -47,9 +48,9 @@ public void convertBpmnFlowNodesIntoDiagram() {
Diagram diagram = new BpmnToAlgoModelConverter().toAlgoModel(definitions);

assertThat(diagram.getShapes()).containsOnly(
new Shape("startEvent_1", "Start Event", EVENT),
new Shape("task_1", "Task 1", ACTIVITY),
new Shape("endEvent_1", "End Event", EVENT));
shape("startEvent_1", "Start Event", EVENT),
shape("task_1", "Task 1", ACTIVITY),
shape("endEvent_1", "End Event", EVENT));
assertThat(diagram.getEdges()).containsOnly(
edge("sequenceFlow_1", "startEvent_1", "task_1"),
edge("sequenceFlow_2", "task_1", "endEvent_1"));
Expand All @@ -58,7 +59,7 @@ public void convertBpmnFlowNodesIntoDiagram() {
@Test
void should_convert_activities_to_shape() {
assertThat(toShape(new TUserTask(), new TSendTask(), new TSubProcess()))
.containsOnly(new Shape("bpmn_id", "bpmn_name", ACTIVITY));
.containsOnly(shape("bpmn_id", "bpmn_name", ACTIVITY));
}

private static Stream<Shape> toShape(TFlowNode... flowNodes) {
Expand All @@ -75,13 +76,13 @@ private static TFlowNode setBaseFields(TFlowNode flowNode) {
@Test
void should_convert_events_to_shape() {
assertThat(toShape(new TStartEvent(), new TIntermediateCatchEvent(), new TEndEvent()))
.containsOnly(new Shape("bpmn_id", "bpmn_name", EVENT));
.containsOnly(shape("bpmn_id", "bpmn_name", EVENT));
}

@Test
void should_convert_gateways_to_shape() {
assertThat(toShape(new TParallelGateway(), new TComplexGateway()))
.containsOnly(new Shape("bpmn_id", "bpmn_name", GATEWAY));
.containsOnly(shape("bpmn_id", "bpmn_name", GATEWAY));
}

}