import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import org.simantics.db.common.procedure.adapter.TransientCacheListener;
import org.simantics.db.common.request.ResourceRead2;
import org.simantics.db.common.request.UnaryRead;
+import org.simantics.db.common.utils.ListUtils;
import org.simantics.db.common.utils.NameUtils;
import org.simantics.db.exception.DatabaseException;
import org.simantics.diagram.connection.ConnectionVisuals;
import org.simantics.diagram.connection.RouteGraph;
-import org.simantics.diagram.connection.RouteGraphConnectionClass;
import org.simantics.diagram.connection.RouteLine;
import org.simantics.diagram.connection.RouteNode;
import org.simantics.diagram.connection.RouteTerminal;
import org.simantics.diagram.connection.RouteTerminalPosition;
+import org.simantics.diagram.connection.rendering.AggregateConnectionStyle;
import org.simantics.diagram.connection.rendering.BasicConnectionStyle;
import org.simantics.diagram.connection.rendering.ConnectionStyle;
import org.simantics.diagram.connection.rendering.ExampleConnectionStyle;
import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
import org.simantics.g2d.element.handler.TerminalLayout;
import org.simantics.g2d.elementclass.FlagClass.Type;
+import org.simantics.g2d.elementclass.RouteGraphConnectionClass;
import org.simantics.layer0.Layer0;
import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphChangeEvent;
import org.simantics.scenegraph.utils.GeometryUtils;
RouteGraph rg = new RouteGraph();
// Default capacity should be enough for common cases.
- Set<EdgeResource> links = new THashSet<EdgeResource>();
- Map<Object, RouteNode> nodeByData = new THashMap<Object, RouteNode>();
+ Set<EdgeResource> links = new THashSet<>();
+ Map<Object, RouteNode> nodeByData = new THashMap<>();
// Load all route graph interior RouteNodes: route lines and points
for (Resource interiorNode : graph.getObjects(connection, DIA.HasInteriorRouteNode)) {
if (graph.isInstanceOf(interiorNode, DIA.RouteLine)) {
+ Collection<Resource> areConnected = graph.getObjects(interiorNode, DIA.AreConnected);
+ if (areConnected.size() < 2) {
+ // Degenerated route line encountered, most likely due to a bug somewhere else.
+ // Ignoring them because adding them to the RouteGraph structure would cause
+ // problems during rendering.
+ LOGGER.warn("Stray RouteLine found: " + NameUtils.getSafeName(graph, interiorNode));
+ continue;
+ }
+
Boolean isHorizontal = graph.getRelatedValue(interiorNode, DIA.IsHorizontal, Bindings.BOOLEAN);
Double position = graph.getRelatedValue(interiorNode, DIA.HasPosition, Bindings.DOUBLE);
RouteLine line = rg.addLine(isHorizontal, position);
nodeByData.put( interiorNode, line );
- for (Resource connectedTo : graph.getObjects(interiorNode, DIA.AreConnected)) {
+ for (Resource connectedTo : areConnected) {
links.add( new EdgeResource(interiorNode, connectedTo) );
}
} else if (graph.isInstanceOf(interiorNode, DIA.RoutePoint)) {
final ResourceTerminal rt = new ResourceTerminal(terminal);
final TerminalLayout tl = te.getElementClass().getSingleItem(TerminalLayout.class);
- AffineTransform terminalPos = tl.getTerminalPosition(element, rt);
+ AffineTransform terminalPos = tl.getTerminalPosition(te, rt);
if (terminalPos != null) {
terminalTr.concatenate(terminalPos);
* @return
* @throws DatabaseException
*/
- protected static ConnectionStyle readConnectionStyle(ReadGraph graph, IModelingRules modelingRules, Resource connection, StructuralResource2 STR) throws DatabaseException {
+ protected static ConnectionStyle readConnectionStyle(ReadGraph graph, IModelingRules modelingRules, Resource connection, StructuralResource2 STR, DiagramResource DIA) throws DatabaseException {
+ Resource connectionStyle = graph.getPossibleObject(connection, DIA.HasConnectionStyle);
Resource connectionType = null;
- if (modelingRules != null)
- connectionType = modelingRules.getConnectionType(graph, connection);
- if (connectionType == null)
- connectionType = graph.getPossibleObject(connection, STR.HasConnectionType);
- return connectionType != null ? readConnectionStyleFromConnectionType(graph, connectionType) : DEFAULT_CONNECTION_STYLE;
+ if (connectionStyle == null) {
+ if (modelingRules != null)
+ connectionType = modelingRules.getConnectionType(graph, connection);
+ if (connectionType == null)
+ connectionType = graph.getPossibleObject(connection, STR.HasConnectionType);
+ connectionStyle = graph.getPossibleObject(connectionType, DIA.HasConnectionStyle);
+ }
+ if (connectionStyle != null) {
+ List<Resource> lineStyles = ListUtils.toList(graph, connectionStyle);
+ if (lineStyles.size() != 1) {
+ AggregateConnectionStyle aggregate = new AggregateConnectionStyle();
+ for (Resource connectionLine : ListUtils.toList(graph, connectionStyle)) {
+ aggregate.addStyle(readConnectionStyleFromConnectionType(graph, connectionLine));
+ }
+ return aggregate;
+ } else {
+ return readConnectionStyleFromConnectionType(graph, lineStyles.get(0));
+ }
+ } else {
+ return connectionType != null ? readConnectionStyleFromConnectionType(graph, connectionType) : DEFAULT_CONNECTION_STYLE;
+ }
}
protected static ConnectionStyle readConnectionStyleFromConnectionType(ReadGraph graph, Resource connectionType) throws DatabaseException {
// Fixed style settings
Color branchPointColor = Color.BLACK;
- double branchPointRadius = 0.5;
+ double branchPointRadius = cv != null && cv.branchPointRadius != null ? cv.branchPointRadius : 0.5;
double degenerateLineLength = 0.8;
Color lineColor = cv != null ? cv.toColor() : null;
lineStroke = new BasicStroke(0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 10, null, 0);
Stroke routeLineStroke = GeometryUtils.scaleStrokeWidth(lineStroke, 2);
double rounding = cv.rounding == null ? 0.0 : cv.rounding;
+ double offset = cv.offset == null ? 0.0 : cv.offset;
return new BasicConnectionStyle(
lineColor,
lineStroke,
routeLineStroke,
degenerateLineLength,
- rounding);
+ rounding,
+ offset);
}
public static void scheduleSynchronize(Session session, Resource connection, RouteGraphChangeEvent event) {