Skip to content

Commit

Permalink
refactor(waypoints): split code and remove duplications
Browse files Browse the repository at this point in the history
Extract code from WayPointsComputer: remove duplications and clarify
responsibilities. This class now only does the orchestration. The waypoints
description and conversion to display model are done in dedicated classes.

Move display model domain classes to a dedicated package (clarify and remove
cyclic dependencies).

Rename some methods and classes to better express their purpose.
  • Loading branch information
tbouffard committed Jun 21, 2021
1 parent 34da3bc commit 88f715e
Show file tree
Hide file tree
Showing 19 changed files with 1,109 additions and 949 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@
import static io.process.analytics.tools.bpmn.generator.converter.Configuration.CELL_HEIGHT;
import static io.process.analytics.tools.bpmn.generator.converter.Configuration.CELL_WIDTH;

import java.util.List;
import java.util.Collection;
import java.util.stream.Collectors;

import io.process.analytics.tools.bpmn.generator.converter.waypoint.WayPointsComputer;
import io.process.analytics.tools.bpmn.generator.model.*;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.Singular;
import lombok.ToString;
import io.process.analytics.tools.bpmn.generator.model.display.*;

public class AlgoToDisplayModelConverter {

Expand All @@ -37,131 +35,76 @@ public DisplayModel convert(Grid grid, Diagram diagram) {
// increase to display edges with extra paths to avoid shape overlapping
model.width(grid.width() * CELL_WIDTH).height((grid.height() + 1) * CELL_HEIGHT);

for (Position position : grid.getPositions()) {
int xOffset = position.getX() * CELL_WIDTH;
int yOffset = position.getY() * CELL_HEIGHT;
int nodeWidth = x(60);
int nodeHeight = y(60);

// TODO manage when not found (should not occur)
Shape shape = diagram.getShapes().stream()
.filter(s -> s.getId().equals(position.getShape()))
.findFirst().get();
String name = shape.getName();

// ensure to have a square shape (i.e. same width and height) for non activity elements
ShapeType shapeType = shape.getType();
if (shapeType == ShapeType.EVENT || shapeType == ShapeType.GATEWAY) {
int nodeDimension = Math.min(nodeWidth, nodeHeight);
if (shapeType == ShapeType.EVENT) {
nodeDimension /= 2;
}
nodeWidth = nodeDimension;
nodeHeight = nodeDimension;
}

int x = xOffset + (CELL_WIDTH - nodeWidth) / 2;
int y = yOffset + (CELL_HEIGHT - nodeHeight) / 2;
DisplayDimension flowNodeDimension = new DisplayDimension(x, y, nodeWidth, nodeHeight);

// Labels positions better work with the SVG export
// BPMN label positions are adjusted in BPMNDiagramRichBuilder
int labelX = xOffset + x(50);
int labelY = yOffset + y(50);
if (shapeType == ShapeType.EVENT) { // put the label under the shape
labelY = (int) (y + nodeHeight * 1.5);
} else if (shapeType == ShapeType.GATEWAY) { // put the label on the top left of the shape
labelX = (int) (x - nodeWidth * 0.5);
labelY = (int) (y - nodeHeight * 0.5);
}
Collection<DisplayFlowNode> flowNodes = grid.getPositions().stream()
.map(position -> toDisplayFlowNode(position, diagram))
.collect(Collectors.toList());
model.flowNodes(flowNodes);

DisplayDimension labelDimension = new DisplayDimension(labelX, labelY, nodeWidth, nodeHeight);
DisplayLabel label = new DisplayLabel(name, y(16), labelDimension);

model.flowNode(DisplayFlowNode.builder().bpmnElementId(shape.getId())
.dimension(flowNodeDimension)
.label(label)
.type(shapeType)
.rx(y(10)).strokeWidth(y(5)).build());
}

WayPointsComputer wayPointsComputer = new WayPointsComputer(grid, model.flowNodes);
WayPointsComputer wayPointsComputer = new WayPointsComputer(grid, flowNodes);
diagram.getEdges()
.stream()
.map(edge -> new DisplayEdge(edge.getId(), wayPointsComputer.inferWayPoints(edge)))
.map(edge -> new DisplayEdge(edge.getId(), wayPointsComputer.compute(edge)))
.forEach(model::edge);

return model.build();
}

private static int x(int percentage) {
return CELL_WIDTH * percentage / 100;
}

private static int y(int percentage) {
return CELL_HEIGHT * percentage / 100;
}


@RequiredArgsConstructor
@Builder
public static class DisplayModel {
public final int width;
public final int height;

@Singular
public final List<DisplayFlowNode> flowNodes;
@Singular
public final List<DisplayEdge> edges;

}

@RequiredArgsConstructor
@Builder
public static class DisplayFlowNode {

public final String bpmnElementId;
public final DisplayDimension dimension;
public final DisplayLabel label;
// for non BPMN exporters only
public final ShapeType type;
public final int rx;
public final int strokeWidth;

}

@RequiredArgsConstructor
@Builder
public static class DisplayEdge {

public final String bpmnElementId;
public final List<DisplayPoint> wayPoints;
private DisplayFlowNode toDisplayFlowNode(Position position, Diagram diagram) {
int xOffset = position.getX() * CELL_WIDTH;
int yOffset = position.getY() * CELL_HEIGHT;
int nodeWidth = x(60);
int nodeHeight = y(60);

// TODO manage when not found (should not occur)
Shape shape = diagram.getShapes().stream()
.filter(s -> s.getId().equals(position.getShape()))
.findFirst().get();
String name = shape.getName();

// ensure to have a square shape (i.e. same width and height) for non activity elements
ShapeType shapeType = shape.getType();
if (shapeType == ShapeType.EVENT || shapeType == ShapeType.GATEWAY) {
int nodeDimension = Math.min(nodeWidth, nodeHeight);
if (shapeType == ShapeType.EVENT) {
nodeDimension /= 2;
}
nodeWidth = nodeDimension;
nodeHeight = nodeDimension;
}

}
int x = xOffset + (CELL_WIDTH - nodeWidth) / 2;
int y = yOffset + (CELL_HEIGHT - nodeHeight) / 2;
DisplayDimension flowNodeDimension = new DisplayDimension(x, y, nodeWidth, nodeHeight);

// Labels positions better work with the SVG export
// BPMN label positions are adjusted in BPMNDiagramRichBuilder
int labelX = xOffset + x(50);
int labelY = yOffset + y(50);
if (shapeType == ShapeType.EVENT) { // put the label under the shape
labelY = (int) (y + nodeHeight * 1.5);
} else if (shapeType == ShapeType.GATEWAY) { // put the label on the top left of the shape
labelX = (int) (x - nodeWidth * 0.5);
labelY = (int) (y - nodeHeight * 0.5);
}

@RequiredArgsConstructor
public static class DisplayDimension {
DisplayDimension labelDimension = new DisplayDimension(labelX, labelY, nodeWidth, nodeHeight);
DisplayLabel label = new DisplayLabel(name, y(16), labelDimension);

public final int x;
public final int y;
public final int width;
public final int height;
return DisplayFlowNode.builder().bpmnElementId(shape.getId())
.dimension(flowNodeDimension)
.label(label)
.type(shapeType)
.rx(y(10))
.strokeWidth(y(5))
.build();
}

@RequiredArgsConstructor
public static class DisplayLabel {

public final String text; // for non BPMN exporters only
public final int fontSize;
public final DisplayDimension dimension;
private static int x(int percentage) {
return CELL_WIDTH * percentage / 100;
}

@RequiredArgsConstructor
@ToString
public static class DisplayPoint {

public final int x;
public final int y;
private static int y(int percentage) {
return CELL_HEIGHT * percentage / 100;
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
/*
* Copyright 2021 Bonitasoft S.A.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.process.analytics.tools.bpmn.generator.converter;

public class Configuration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
*/
package io.process.analytics.tools.bpmn.generator.converter.waypoint;

import io.process.analytics.tools.bpmn.generator.converter.AlgoToDisplayModelConverter.DisplayDimension;
import io.process.analytics.tools.bpmn.generator.converter.AlgoToDisplayModelConverter.DisplayPoint;
import io.process.analytics.tools.bpmn.generator.model.display.DisplayDimension;
import io.process.analytics.tools.bpmn.generator.model.display.DisplayPoint;

/**
* Compute coordinates of the terminal points (source or target) of an Edge.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
*/
package io.process.analytics.tools.bpmn.generator.converter.waypoint;

import java.util.List;
import java.util.stream.Collectors;

import io.process.analytics.tools.bpmn.generator.model.Edge;
import io.process.analytics.tools.bpmn.generator.model.Grid;
import io.process.analytics.tools.bpmn.generator.model.Position;
Expand Down Expand Up @@ -69,8 +66,8 @@ public boolean isShapeExistAbove(final Position positionFrom) {
.anyMatch(p -> p.getY() == positionFrom.getY() - 1);
}


public BendConfiguration searchEmptyRow(Position positionFrom, Position positionTo, BendDirection searchDirection) {
public BendConfiguration computeConfigurationToPassByEmptyRow(Position positionFrom, Position positionTo,
BendDirection searchDirection) {
int positionFromY = positionFrom.getY();
int offset = -1;
boolean isElementBetween = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
package io.process.analytics.tools.bpmn.generator.converter.waypoint;

import lombok.Builder;
import lombok.ToString;

@Builder
public class EdgeDirection {
@ToString
public class WayPointDescriptor {

public final Direction direction;
public final Orientation orientation;
Expand Down
Loading

0 comments on commit 88f715e

Please sign in to comment.