X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fadapter%2FRouteGraphUtils.java;h=3ff98cd0b1cc115d33687764e650282c707623bb;hp=99d9acb705388a6b85f242ec5485c08d1dcdc208;hb=e3f46ffc9d4a6930adc83ebb8e6730f19708cc94;hpb=e1ec84d6bf6180c486a7c63ae9379d9f32577a23 diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java index 99d9acb70..3ff98cd0b 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java @@ -20,6 +20,7 @@ import java.awt.geom.AffineTransform; 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; @@ -31,21 +32,25 @@ import org.simantics.db.Statement; 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.diagram.connection.rendering.StyledRouteGraphRenderer; import org.simantics.diagram.connection.rendering.arrows.ArrowLineEndStyle; import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle; import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle; import org.simantics.diagram.content.EdgeResource; +import org.simantics.diagram.content.ResourceTerminal; import org.simantics.diagram.content.TerminalMap; import org.simantics.diagram.query.DiagramRequests; import org.simantics.diagram.stubs.DiagramResource; @@ -55,12 +60,16 @@ import org.simantics.diagram.synchronization.graph.RouteGraphConnection; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.impl.CanvasContext; import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.diagram.handler.DataElementMap; import org.simantics.g2d.diagram.handler.Topology.Connection; +import org.simantics.g2d.diagram.handler.Topology.Terminal; import org.simantics.g2d.diagram.impl.ElementDiagram; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; 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; @@ -93,10 +102,10 @@ public class RouteGraphUtils { Layer0 L0 = Layer0.getInstance(graph); Resource diagramResource = graph.getPossibleObject(connection, L0.PartOf); IModelingRules modelingRules = graph.syncRequest(DiagramRequests.getModelingRules(diagramResource, null), TransientCacheListener.instance()); - return load(graph, diagramRuntime, connection, canvas, diagram, modelingRules, null); + return load(graph, diagramRuntime, connection, canvas, diagram, null, modelingRules, null); } - public static RouteGraph load(ReadGraph graph, Resource diagramRuntime, Resource connection, ICanvasContext canvas, IDiagram diagram, IModelingRules modelingRules, Set backendConnections) throws DatabaseException { + public static RouteGraph load(ReadGraph graph, Resource diagramRuntime, Resource connection, ICanvasContext canvas, IDiagram diagram, IElement element, IModelingRules modelingRules, Set backendConnections) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); @@ -104,12 +113,21 @@ public class RouteGraphUtils { RouteGraph rg = new RouteGraph(); // Default capacity should be enough for common cases. - Set links = new THashSet(); - Map nodeByData = new THashMap(); + Set links = new THashSet<>(); + Map 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 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); @@ -117,7 +135,7 @@ public class RouteGraphUtils { 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)) { @@ -171,7 +189,7 @@ public class RouteGraphUtils { connectorToModeledAttachment = new THashMap(toConnectorStatements.size()); connectorToModeledAttachment.put(connector, attachment); if (DEBUG) - System.out.println("modeling rules decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")"); + LOGGER.debug("modeling rules decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")"); } else if (graph.isInstanceOf(terminalElement, DIA.Flag)) { // Secondary: believe flag type attachment = resolveFlagAttachment(graph, connection, terminalElement, modelingRules, DIA); @@ -180,7 +198,7 @@ public class RouteGraphUtils { connectorToModeledAttachment = new THashMap(toConnectorStatements.size()); connectorToModeledAttachment.put(connector, attachment); if (DEBUG) - System.out.println("flag type decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")"); + LOGGER.debug("flag type decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")"); } } } @@ -193,17 +211,18 @@ public class RouteGraphUtils { if (terminalCount == 2 && connectorToModeledAttachment.size() == 1) { forcedAttachmentRelation = getInverseAttachment(graph, connectorToModeledAttachment.values().iterator().next(), DIA); if (DEBUG) - System.out.println("set forced attachment: " + NameUtils.getSafeLabel(graph, forcedAttachmentRelation)); + LOGGER.debug("set forced attachment: " + NameUtils.getSafeLabel(graph, forcedAttachmentRelation)); } Resource connectionType = graph.getPossibleObject(connection, STR.HasConnectionType); + DataElementMap diagramDataElementMap = diagram.getDiagramClass().getSingleItem(DataElementMap.class); // Load all node terminal connections as RouteTerminals for (Statement toConnector : toConnectorStatements) { Resource connector = toConnector.getObject(); Resource attachmentRelation = toConnector.getPredicate(); if (DEBUG) - System.out.println("original attachment relation: " + NameUtils.getSafeLabel(graph, attachmentRelation)); + LOGGER.debug("original attachment relation: " + NameUtils.getSafeLabel(graph, attachmentRelation)); Statement terminalStm = findTerminalStatement(graph, connection, connector, STR); if (terminalStm == null) @@ -237,19 +256,18 @@ public class RouteGraphUtils { if (position.length != 2) position = new double[] { 0, 0 }; + AffineTransform terminalTr = DiagramGraphUtil.getDynamicWorldTransform(graph, diagramRuntime, terminalElement); + final AffineTransform terminalElementTransform = new AffineTransform(terminalTr); + if (DEBUG) { - System.out.println("terminalStm: " + NameUtils.toString(graph, terminalStm)); - System.out.println("terminal: " + graph.getURI(terminalStm.getPredicate())); + LOGGER.debug("terminalStm: " + NameUtils.toString(graph, terminalStm)); + LOGGER.debug("terminal: " + NameUtils.getURIOrSafeNameInternal(graph, terminalStm.getPredicate())); + LOGGER.debug("terminalElement: " + NameUtils.getURIOrSafeNameInternal(graph, terminalElement) + " : " + NameUtils.getURIOrSafeNameInternal(graph, terminalElementType)); + LOGGER.debug("terminalElementTr: " + terminalTr); } - AffineTransform terminalElementTr = diagramRuntime != null ? - DiagramGraphUtil.getDynamicWorldTransform(graph, diagramRuntime, terminalElement) : - DiagramGraphUtil.getWorldTransform(graph, terminalElement); - if (DEBUG) - System.out.println("terminalElementTr: " + terminalElementTr); - - double x = terminalElementTr.getTranslateX(); - double y = terminalElementTr.getTranslateY(); + double x = terminalTr.getTranslateX(); + double y = terminalTr.getTranslateY(); double minx = x-1, miny = y-1, maxx = x+1, maxy = y+1; int direction = 0x0; @@ -259,20 +277,20 @@ public class RouteGraphUtils { if (att != null) { attachmentRelation = att; if (DEBUG) - System.out.println("modeling rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation)); + LOGGER.debug("modeling rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation)); } else if (forcedAttachmentRelation != null) { attachmentRelation = forcedAttachmentRelation; if (DEBUG) - System.out.println("forced rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation)); + LOGGER.debug("forced rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation)); } if (DEBUG) - System.out.println("decided attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation)); + LOGGER.debug("decided attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation)); // Get element bounds to decide allowed terminal direction(s) IElement te = graph.syncRequest(DiagramRequests.getElement(canvas, diagram, terminalElement, null)); ElementUtils.getElementBounds(te, bounds); { - Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(bounds, terminalElementTr); + Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(bounds, terminalTr); bounds.setFrame(shp.getBounds2D()); } @@ -285,28 +303,26 @@ public class RouteGraphUtils { maxx = bounds.getMaxX(); maxy = bounds.getMaxY(); - AffineTransform terminalPos = DiagramGraphUtil.getDynamicAffineTransform(graph, terminalElement, terminal); - //AffineTransform terminalPos2 = DiagramGraphUtil.getAffineTransform(graph, terminal); + final ResourceTerminal rt = new ResourceTerminal(terminal); + final TerminalLayout tl = te.getElementClass().getSingleItem(TerminalLayout.class); + AffineTransform terminalPos = tl.getTerminalPosition(te, rt); + if (terminalPos != null) { - if (DEBUG) { - System.out.println("terminalPos: " + terminalPos); - //System.out.println("terminalPos2: " + terminalPos2); - } - terminalElementTr.concatenate(terminalPos); + terminalTr.concatenate(terminalPos); + x = terminalTr.getTranslateX(); + y = terminalTr.getTranslateY(); if (DEBUG) - System.out.println("terminalElementTr: " + terminalElementTr); - x = terminalElementTr.getTranslateX(); - y = terminalElementTr.getTranslateY(); + LOGGER.debug("terminalPos/Tr: " + terminalPos + ", " + terminalTr); } Integer allowedDirections = graph.getPossibleRelatedValue(terminal, DIA.Terminal_AllowedDirections, Bindings.INTEGER); if (allowedDirections != null) { direction |= allowedDirections; - direction = rotateDirection(direction, terminalElementTr); + direction = rotateDirection(direction, terminalTr); } else { direction |= RouteGraphConnectionClass.shortestDirectionOutOfBounds(x, y, bounds); } - //System.out.println("DIR(" + x + ", " + y + ", " + bounds + "): " + Integer.toHexString(direction)); + //LOGGER.debug("DIR(" + x + ", " + y + ", " + bounds + "): " + Integer.toHexString(direction)); if (backendConnections != null) { backendConnections.add( @@ -326,10 +342,11 @@ public class RouteGraphUtils { // FIXME: routegraph crashes if this is done for all terminals regardless of the amount of terminals. if (DEBUG) - System.out.println("load line style: " + NameUtils.getSafeLabel(graph, attachmentRelation)); + LOGGER.debug("load line style: " + NameUtils.getSafeLabel(graph, attachmentRelation)); ILineEndStyle endStyle = loadLineEndStyle(graph, attachmentRelation, connectionType, TAIL); - RouteTerminal routeTerminal = rg.addTerminal(x, y, minx, miny, maxx, maxy, direction, endStyle); + RouteTerminal routeTerminal = rg.addTerminal(x, y, minx, miny, maxx, maxy, direction, endStyle, + new RouteTerminalPositionImpl(diagram, diagramDataElementMap, terminalElement, terminalElementTransform, tl, rt)); routeTerminal.setData( RouteGraphConnection.serialize(graph, connector) ); nodeByData.put( connector, routeTerminal ); @@ -519,6 +536,8 @@ public class RouteGraphUtils { } } + private static final ConnectionStyle DEFAULT_CONNECTION_STYLE = new BasicConnectionStyle(Color.BLACK, Color.BLACK, 3, ExampleConnectionStyle.SOLID, ExampleConnectionStyle.SOLID, 8); + /** * @param graph * @param canvas @@ -527,13 +546,30 @@ public class RouteGraphUtils { * @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 readConnectionStyleFromConnectionType(graph, connectionType); + 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 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 { @@ -562,9 +598,9 @@ public class RouteGraphUtils { // 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; if (lineColor == null) lineColor = Color.DARK_GRAY; @@ -572,6 +608,8 @@ public class RouteGraphUtils { if (lineStroke == 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, @@ -579,7 +617,9 @@ public class RouteGraphUtils { branchPointRadius, lineStroke, routeLineStroke, - degenerateLineLength); + degenerateLineLength, + rounding, + offset); } public static void scheduleSynchronize(Session session, Resource connection, RouteGraphChangeEvent event) { @@ -703,4 +743,50 @@ public class RouteGraphUtils { } } + private static class RouteTerminalPositionImpl implements RouteTerminalPosition { + + private IDiagram diagram; + private DataElementMap dataElementMap; + private Resource element; + private AffineTransform elementTransform; + private TerminalLayout terminalLayout; + private Terminal elementTerminal; + + private transient AffineTransform lastTerminalTr; + private transient AffineTransform transform; + + public RouteTerminalPositionImpl(IDiagram diagram, DataElementMap dem, Resource element, AffineTransform elementTransform, TerminalLayout terminalLayout, Terminal terminal) { + this.diagram = diagram; + this.dataElementMap = dem; + this.element = element; + this.elementTransform = elementTransform; + this.terminalLayout = terminalLayout; + this.elementTerminal = terminal; + } + + @Override + public AffineTransform getTransform() { + IElement actualElement = dataElementMap.getElement(diagram, element); + AffineTransform terminalTr = actualElement != null ? terminalLayout.getTerminalPosition(actualElement, elementTerminal) : null; + if (terminalTr == null) + return elementTransform; + + // Return cached transform if terminal transform has not changed. + AffineTransform result = this.transform; + AffineTransform lastTerminalTr = this.lastTerminalTr; + if (lastTerminalTr != null) { + if (terminalTr.equals(lastTerminalTr)) + return result; + lastTerminalTr.setTransform(terminalTr); + } else { + lastTerminalTr = this.lastTerminalTr = new AffineTransform(terminalTr); + result = this.transform = new AffineTransform(); + } + + result.setTransform(elementTransform); + result.concatenate(terminalTr); + return result; + } + + } }