]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Improvements to styling of connection lines 38/4138/1
authorJussi Koskela <jussi.koskela@semantum.fi>
Tue, 14 Apr 2020 09:41:45 +0000 (12:41 +0300)
committerJussi Koskela <jussi.koskela@semantum.fi>
Tue, 14 Apr 2020 09:41:45 +0000 (12:41 +0300)
gitlab #519

Change-Id: Ic08546e5aab985d6e4c365dc9877a692829b0ab2

bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/AggregateConnectionStyle.java [new file with mode: 0644]
bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/BasicConnectionStyle.java
bundles/org.simantics.diagram.ontology/graph/Diagram.pgraph
bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphConnectionClassFactory.java
bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java
bundles/org.simantics.diagram/src/org/simantics/diagram/connection/ConnectionVisuals.java
bundles/org.simantics.diagram/src/org/simantics/diagram/query/ConnectionVisualsRequest.java
bundles/org.simantics.g2d.ontology/graph/G2D.pgraph
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/RouteGraphNode.java

diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/AggregateConnectionStyle.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/AggregateConnectionStyle.java
new file mode 100644 (file)
index 0000000..7bf7624
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.connection.rendering;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Path2D;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class AggregateConnectionStyle implements ConnectionStyle, Serializable{
+
+    private static final long serialVersionUID = 5888959070127628457L;
+    private List<ConnectionStyle> styles = new ArrayList<>();
+    
+    public void addStyle(ConnectionStyle style) {
+        styles.add(style);
+    }
+    
+    @Override
+    public void drawBranchPoint(Graphics2D g, double x, double y) {
+        for (ConnectionStyle style : styles) {
+            style.drawBranchPoint(g, x, y);
+        }
+    }
+
+    @Override
+    public void drawLine(Graphics2D g, double x1, double y1, double x2, double y2, boolean isTransient) {
+        for (ConnectionStyle style : styles) {
+            style.drawLine(g, x1, y1, x2, y2, isTransient);
+        }
+    }
+
+    @Override
+    public void drawPath(Graphics2D g, Path2D path, boolean isTransient) {
+        for (ConnectionStyle style : styles) {
+            style.drawPath(g, path, isTransient);
+        }
+    }
+
+    @Override
+    public void drawDegeneratedLine(Graphics2D g, double x, double y, boolean isHorizontal, boolean isTransient) {
+        for (ConnectionStyle style : styles) {
+            style.drawDegeneratedLine(g, x, y, isHorizontal, isTransient);
+        }
+    }
+
+    @Override
+    public double getDegeneratedLineLength() {
+        double max = 0;
+        for (ConnectionStyle style : styles) {
+            max = Math.max(max, style.getDegeneratedLineLength());
+        }
+        return max;
+    }
+
+}
index 2f218d8fab325c4c0f7e082a3f977a74fa798486..94de76bb447af1a435a8323ea7d24c4187ab7b4a 100644 (file)
@@ -17,9 +17,11 @@ import java.awt.RenderingHints;
 import java.awt.Stroke;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Ellipse2D;
+import java.awt.geom.FlatteningPathIterator;
 import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
 import java.io.Serializable;
 
 /**
@@ -37,12 +39,13 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable {
     final Stroke                    routeLineStroke;
     final double                    degenerateLineLength;
     final double                    rounding;
+    final double                    offset;
 
     transient Line2D          line             = new Line2D.Double();
     transient Ellipse2D       ellipse          = new Ellipse2D.Double();
 
     public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength,
-            double rounding) {
+            double rounding, double offset) {
         this.lineColor = lineColor;
         this.branchPointColor = branchPointColor;
         this.branchPointRadius = branchPointRadius;
@@ -50,10 +53,16 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable {
         this.routeLineStroke = routeLineStroke;
         this.degenerateLineLength = degenerateLineLength;
         this.rounding = rounding;
+        this.offset = offset;
+    }
+
+    public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength,
+            double rounding) {
+        this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, rounding, 0.0);
     }
     
     public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength) {
-        this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, 0.0);
+        this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, 0.0, 0.0);
     }
 
     public Color getLineColor() {
@@ -101,11 +110,101 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable {
         if(rounding > 0.0) {
             Object oldRenderingHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
             g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            g.draw(round(path));
+            path = round(path);
+            if (offset != 0) {
+                path = offsetPath(path, offset);
+            }
+            g.draw(path);
             g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldRenderingHint);
         }
-        else
+        else {
+            if (offset != 0) {
+                path = offsetPath(path, offset);
+            }
             g.draw(path);
+        }
+    }
+    
+    private static Point2D getNormal(Point2D dir) {
+        return new Point2D.Double(-dir.getY(), dir.getX());
+    }
+    
+    private static Point2D normalize(Point2D v) {
+        double d = Math.sqrt(v.getX() * v.getX() + v.getY() * v.getY());
+        v.setLocation(v.getX() / d, v.getY() / d);
+        return v;
+    }
+    
+    private static Path2D offsetPath(Path2D path, double offset) {
+        Path2D result = new Path2D.Double();
+        PathIterator iter = new FlatteningPathIterator(path.getPathIterator(null), 0.05, 10);
+
+        double c[] = new double[6];
+        double initialX = 0;
+        double initialY = 0;
+        boolean first = true;
+        Point2D prevDir = null;
+        Point2D prevPos = null;
+
+        while (!iter.isDone()) {
+            int i = iter.currentSegment(c);
+            switch (i) {
+            case PathIterator.SEG_MOVETO:
+                if (first) {
+                    initialX = c[0];
+                    initialY = c[1];
+                    first = false;
+                }
+                if (prevDir != null) {
+                    Point2D N = normalize(getNormal(prevDir)); 
+                    result.lineTo(prevPos.getX() + N.getX() * offset , prevPos.getY() + N.getY() * offset);
+                }
+                prevPos = new Point2D.Double(c[0], c[1]);
+                prevDir = null;
+                break;
+            case PathIterator.SEG_LINETO:
+            case PathIterator.SEG_CLOSE:
+                if (i == PathIterator.SEG_CLOSE) {
+                    c[0] = initialX;
+                    c[1] = initialY;
+                }
+                Point2D currentDir = new Point2D.Double(c[0] - prevPos.getX(), c[1] - prevPos.getY());
+                if (currentDir.getX() == 0.0 && currentDir.getY() == 0) break;
+                
+                if (prevDir == null) {
+                    Point2D N = normalize(getNormal(currentDir)); 
+                    result.moveTo(prevPos.getX() + N.getX() * offset, prevPos.getY() + N.getY() * offset);
+                    prevPos = new Point2D.Double(c[0], c[i]);
+                    prevDir = currentDir;
+                } else {
+                    Point2D N1 = normalize(getNormal(prevDir));
+                    Point2D N2 = normalize(getNormal(currentDir));
+                    Point2D N = normalize(new Point2D.Double(N1.getX() + N2.getX(), N1.getY() + N2.getY()));
+                    double dot = N1.getX() * N.getX() + N1.getY() * N.getY();
+
+                    if (!Double.isFinite(dot) || Math.abs(dot) < 0.1) {
+                        result.lineTo(prevPos.getX() + (N1.getX() + N1.getY()) * offset, prevPos.getY() + (N1.getY() - N1.getX()) * offset);
+                        result.lineTo(prevPos.getX() + (N2.getX() + N1.getY()) * offset, prevPos.getY() + (N2.getY() - N1.getX()) * offset);
+                        prevPos = new Point2D.Double(c[0], c[i]);
+                        prevDir = currentDir;
+                    } else {
+                        double Nx = N.getX() * offset / dot;
+                        double Ny = N.getY() * offset / dot;
+                        result.lineTo(prevPos.getX() + Nx, prevPos.getY() + Ny);
+                        prevPos = new Point2D.Double(c[0], c[i]);
+                        prevDir = currentDir;
+                    }
+                }
+
+                break;
+            }
+            iter.next();
+        }
+        if (prevDir != null) {
+            Point2D N = normalize(getNormal(prevDir)); 
+            result.lineTo(prevPos.getX() + N.getX() * offset , prevPos.getY() + N.getY() * offset);
+        }
+        return result;
     }
     
     private Path2D round(Path2D path) {
@@ -266,4 +365,7 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable {
         return rounding;
     }
 
+    public double getOffset() {
+        return offset;
+    }
 }
index 6ea207f88d754cd59825b9c2e533fadc6190cb4a..a38de5bc95db19a77f425d3d8ea2e09087c3789f 100644 (file)
@@ -173,4 +173,10 @@ DIA.ConnectionCrossingStyle.Type <T L0.Value
 DIA.ConnectionCrossingStyle.Type.Arc : DIA.ConnectionCrossingStyle.Type
 DIA.ConnectionCrossingStyle.Type.Square : DIA.ConnectionCrossingStyle.Type
 DIA.ConnectionCrossingStyle.Type.Gap : DIA.ConnectionCrossingStyle.Type
-DIA.ConnectionCrossingStyle.Type.None : DIA.ConnectionCrossingStyle.Type
\ No newline at end of file
+DIA.ConnectionCrossingStyle.Type.None : DIA.ConnectionCrossingStyle.Type
+
+DIA.ConnectionStyle <T L0.Entity
+DIA.ConnectionLineStyle <T L0.Entity
+
+DIA.HasConnectionStyle <R L0.IsRelatedTo : L0.FunctionalRelation
+    L0.HasRange DIA.ConnectionStyle
index a3d9074827f57b94f402448c071b6e4e1d07d478..4e15608a61e0e4da754eea6f9b1d5c3628ade90b 100644 (file)
@@ -100,7 +100,7 @@ public class RouteGraphConnectionClassFactory extends SyncElementFactory {
         RouteGraph rg = RouteGraphUtils.load(graph, diagramRuntime, connection, canvas, diagram, element, modelingRules, backendConnections);
 
         // Load connection line style.
-        ConnectionStyle style = RouteGraphUtils.readConnectionStyle(graph, modelingRules, connection, STR);
+        ConnectionStyle style = RouteGraphUtils.readConnectionStyle(graph, modelingRules, connection, STR, DIA);
         StyledRouteGraphRenderer renderer = RouteGraphUtils.getRenderer(graph, style);
 
         // Finish element load
index d6a59a0cbc26a9284e0e656c2062c3b6fae4a2a1..3ff98cd0b1cc115d33687764e650282c707623bb 100644 (file)
@@ -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,6 +32,7 @@ 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;
@@ -39,6 +41,7 @@ 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;
@@ -65,8 +68,8 @@ 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.RouteGraphConnectionClass;
 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;
@@ -543,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 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 {
@@ -589,6 +609,7 @@ public class RouteGraphUtils {
             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,
@@ -597,7 +618,8 @@ public class RouteGraphUtils {
                 lineStroke,
                 routeLineStroke,
                 degenerateLineLength,
-                rounding);
+                rounding,
+                offset);
     }
 
     public static void scheduleSynchronize(Session session, Resource connection, RouteGraphChangeEvent event) {
index 802881e1610efa52d787e0670edddb4c291e45de..e7a31692b5ea2cb22a5bda1bd044bdd3a199ad8c 100644 (file)
@@ -27,12 +27,17 @@ public class ConnectionVisuals {
     public final Stroke stroke;
     public final Double branchPointRadius;
     public final Double rounding;
+    public final Double offset;
 
     public ConnectionVisuals(float[] color, StrokeType strokeType, Stroke stroke, Double rounding) {
        this(color, strokeType, stroke, null, rounding);
     }
 
     public ConnectionVisuals(float[] color, StrokeType strokeType, Stroke stroke, Double branchPointRadius, Double rounding) {
+        this(color, strokeType, stroke, null, rounding, null);
+    }
+
+    public ConnectionVisuals(float[] color, StrokeType strokeType, Stroke stroke, Double branchPointRadius, Double rounding, Double offset) {
         if (color != null && color.length < 3)
             throw new IllegalArgumentException("colors must have at least 3 components (rgb), got " + color.length);
         this.color = color;
@@ -40,6 +45,7 @@ public class ConnectionVisuals {
         this.stroke = stroke;
         this.branchPointRadius = branchPointRadius;
         this.rounding = rounding;
+        this.offset = offset;
     }
 
     public Color toColor() {
@@ -57,6 +63,7 @@ public class ConnectionVisuals {
         result = prime * result + ((branchPointRadius == null) ? 0 : branchPointRadius.hashCode());
         result = prime * result + Arrays.hashCode(color);
         result = prime * result + ((rounding == null) ? 0 : rounding.hashCode());
+        result = prime * result + ((offset == null) ? 0 : offset.hashCode());
         result = prime * result + ((stroke == null) ? 0 : stroke.hashCode());
         result = prime * result + ((strokeType == null) ? 0 : strokeType.hashCode());
         return result;
@@ -83,6 +90,11 @@ public class ConnectionVisuals {
                 return false;
         } else if (!rounding.equals(other.rounding))
             return false;
+        if (offset == null) {
+            if (other.offset != null)
+                return false;
+        } else if (!offset.equals(other.offset))
+            return false;
         if (stroke == null) {
             if (other.stroke != null)
                 return false;
index 73e3615cee0589fd7f3fa42f98cb3a7d4cca2c69..619e913f041c5554f9082e98893cb800b8edf6d0 100644 (file)
@@ -54,8 +54,9 @@ public class ConnectionVisualsRequest extends ResourceRead<ConnectionVisuals> {
         Stroke stroke = G2DUtils.getStroke(g, g.getPossibleObject(structuralConnectionType, g2d.HasStroke));
         Double branchPointRadius = g.getPossibleRelatedValue(structuralConnectionType, g2d.HasBranchPointRadius, Bindings.DOUBLE);
         Double rounding = g.getPossibleRelatedValue(structuralConnectionType, g2d.HasRounding, Bindings.DOUBLE);
+        Double offset = g.getPossibleRelatedValue(structuralConnectionType, g2d.HasOffset, Bindings.DOUBLE);
         
-        return new ConnectionVisuals(color, strokeType, stroke, branchPointRadius, rounding);
+        return new ConnectionVisuals(color, strokeType, stroke, branchPointRadius, rounding, offset);
     }
 
     StrokeType toStrokeType(Resource strokeType) {
index ce06a4109e47fe1c9b94b25e6cfd0f267554264a..4c44b6152372a26490808edc8da6251fad824e70 100644 (file)
@@ -94,6 +94,8 @@ G2D.StrokeType.Scaling : G2D.StrokeType
 G2D.StrokeType.Nonscaling : G2D.StrokeType
 G2D.HasRounding <R L0.HasProperty : L0.FunctionalRelation
     --> L0.Double
+G2D.HasOffset <R L0.HasProperty : L0.FunctionalRelation
+    --> L0.Double
 G2D.HasBranchPointRadius <R L0.HasProperty : L0.FunctionalRelation
     --> L0.Double
 G2D.LineEnd <T L0.Property
index b0e9147f63134e5c2af5dee0c2436efbdbc016e3..3c7b9bad85be182d92cca5637f2fddfcd390169f 100644 (file)
@@ -288,6 +288,7 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
                  selectionStroke = new BasicStroke(width, BasicStroke.CAP_BUTT, stroke.getLineJoin());
              }
          } else {
+             // TODO: support AggregateConnectionStyle
              selectionStroke = SELECTION_STROKE;
          }
     }
@@ -301,24 +302,28 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
         
         if(dynamicColor != null || dynamicStroke != null) {
             BasicConnectionStyle baseStyle = (BasicConnectionStyle)tryGetStyle(baseRenderer);
-            try {
-               Constructor<? extends BasicConnectionStyle> c = baseStyle.getClass().getConstructor(Color.class, Color.class, double.class, Stroke.class, Stroke.class, double.class, double.class);
-               renderer = new StyledRouteGraphRenderer(c.newInstance(
-                        dynamicColor != null ? dynamicColor : baseStyle.getLineColor(),
-                                baseStyle.getBranchPointColor(), baseStyle.getBranchPointRadius(),
-                                    dynamicStroke != null ? dynamicStroke : baseStyle.getLineStroke(), 
-                                            dynamicStroke != null ? dynamicStroke : baseStyle.getRouteLineStroke(),
-                                                    baseStyle.getDegeneratedLineLength(), baseStyle.getRounding()));
-            } catch (Exception e) {
-               renderer = new StyledRouteGraphRenderer(new BasicConnectionStyle(
-                        dynamicColor != null ? dynamicColor : baseStyle.getLineColor(),
-                                baseStyle.getBranchPointColor(), baseStyle.getBranchPointRadius(),
-                                    dynamicStroke != null ? dynamicStroke : baseStyle.getLineStroke(), 
-                                            dynamicStroke != null ? dynamicStroke : baseStyle.getRouteLineStroke(),
-                                                    baseStyle.getDegeneratedLineLength(), baseStyle.getRounding()));
+            if (baseStyle != null) {
+                try {
+                    Constructor<? extends BasicConnectionStyle> c = baseStyle.getClass().getConstructor(Color.class, Color.class, double.class, Stroke.class, Stroke.class, double.class, double.class, double.class);
+                    renderer = new StyledRouteGraphRenderer(c.newInstance(
+                            dynamicColor != null ? dynamicColor : baseStyle.getLineColor(),
+                                    baseStyle.getBranchPointColor(), baseStyle.getBranchPointRadius(),
+                                        dynamicStroke != null ? dynamicStroke : baseStyle.getLineStroke(), 
+                                                dynamicStroke != null ? dynamicStroke : baseStyle.getRouteLineStroke(),
+                                                        baseStyle.getDegeneratedLineLength(), baseStyle.getRounding(), baseStyle.getOffset()));
+                } catch (Exception e) {
+                    renderer = new StyledRouteGraphRenderer(new BasicConnectionStyle(
+                            dynamicColor != null ? dynamicColor : baseStyle.getLineColor(),
+                                    baseStyle.getBranchPointColor(), baseStyle.getBranchPointRadius(),
+                                        dynamicStroke != null ? dynamicStroke : baseStyle.getLineStroke(), 
+                                                dynamicStroke != null ? dynamicStroke : baseStyle.getRouteLineStroke(),
+                                                        baseStyle.getDegeneratedLineLength(), baseStyle.getRounding(), baseStyle.getOffset()));
+                }
+            } else {
+                // TODO: support AggregateConnectionStyle
+                renderer = baseRenderer;
             }
             
-            
         } else {
             renderer = baseRenderer;
         }