import java.awt.Color;
import java.awt.Graphics2D;
+import java.awt.RenderingHints;
import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
import java.io.Serializable;
/**
final double branchPointRadius;
final Stroke lineStroke;
final Stroke routeLineStroke;
- final double degenerateLineLength;
+ final double degenerateLineLength;
+ final double rounding;
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) {
+ public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength,
+ double rounding) {
this.lineColor = lineColor;
this.branchPointColor = branchPointColor;
this.branchPointRadius = branchPointRadius;
this.lineStroke = lineStroke;
this.routeLineStroke = routeLineStroke;
this.degenerateLineLength = degenerateLineLength;
+ this.rounding = rounding;
+ }
+
+ public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength) {
+ this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, 0.0);
}
public Color getLineColor() {
g.setColor(lineColor);
if (lineStroke != null)
g.setStroke(lineStroke);
- g.draw(path);
+ if(rounding > 0.0) {
+ Object oldRenderingHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g.draw(round(path));
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldRenderingHint);
+ }
+ else
+ g.draw(path);
+ }
+
+ private Path2D round(Path2D path) {
+ Path2D newPath = new Path2D.Double();
+ PathIterator it = path.getPathIterator(new AffineTransform());
+ double[] coords = new double[6];
+ double newX=0.0, newY=0.0;
+ double curX=0.0, curY=0.0;
+ double oldX=0.0, oldY=0.0;
+ int state = 0;
+ while(!it.isDone()) {
+ int type = it.currentSegment(coords);
+ if(type == PathIterator.SEG_LINETO) {
+ newX = coords[0];
+ newY = coords[1];
+ if(state == 1) {
+ double dx1 = curX-oldX;
+ double dy1 = curY-oldY;
+ double dx2 = curX-newX;
+ double dy2 = curY-newY;
+ double maxRadius = 0.5 * Math.min(Math.sqrt(dx1*dx1 + dy1*dy1), Math.sqrt(dx2*dx2 + dy2*dy2));
+ double radius = Math.min(rounding, maxRadius);
+ newPath.lineTo(curX + radius*Math.signum(oldX-curX), curY + radius*Math.signum(oldY-curY));
+ newPath.curveTo(curX, curY,
+ curX, curY,
+ curX + radius*Math.signum(newX-curX), curY + radius*Math.signum(newY-curY));
+
+ //newPath.lineTo(curX + round*Math.signum(oldX-curX), curY + round*Math.signum(oldY-curY));
+ //newPath.lineTo(curX + round*Math.signum(newX-curX), curY + round*Math.signum(newY-curY));
+ //newPath.lineTo(curX, curY);
+ }
+ else
+ ++state;
+ oldX = curX;
+ oldY = curY;
+ curX = newX;
+ curY = newY;
+ }
+ else {
+ if(state > 0) {
+ newPath.lineTo(curX, curY);
+ state = 0;
+ }
+ switch(type) {
+ case PathIterator.SEG_MOVETO:
+ curX = coords[0];
+ curY = coords[1];
+ newPath.moveTo(curX, curY);
+ break;
+ case PathIterator.SEG_QUADTO:
+ curX = coords[2];
+ curY = coords[3];
+ newPath.quadTo(coords[0], coords[1], coords[2], coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ curX = coords[4];
+ curY = coords[5];
+ newPath.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ newPath.closePath();
+ break;
+ }
+ }
+ it.next();
+ }
+ if(state > 0)
+ newPath.lineTo(curX, curY);
+ return newPath;
}
@Override
return true;
}
+ public double getRounding() {
+ return rounding;
+ }
+
}
Color branchPointColor = Color.BLACK;
double branchPointRadius = 0.5;
double degenerateLineLength = 0.8;
-
+
Color lineColor = cv != null ? cv.toColor() : null;
if (lineColor == null)
lineColor = Color.DARK_GRAY;
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;
return new BasicConnectionStyle(
lineColor,
branchPointRadius,
lineStroke,
routeLineStroke,
- degenerateLineLength);
+ degenerateLineLength,
+ rounding);
}
public static void scheduleSynchronize(Session session, Resource connection, RouteGraphChangeEvent event) {
public final float[] color;
public final StrokeType strokeType;
public final Stroke stroke;
+ public final Double rounding;
- public ConnectionVisuals(float[] color, StrokeType strokeType, Stroke stroke) {
+ public ConnectionVisuals(float[] color, StrokeType strokeType, Stroke stroke, Double rounding) {
if (color != null && color.length < 3)
throw new IllegalArgumentException("colors must have at least 3 components (rgb), got " + color.length);
this.color = color;
this.strokeType = strokeType;
this.stroke = stroke;
+ this.rounding = rounding;
}
public Color toColor() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(color);
+ result = prime * result + ((rounding == null) ? 0 : rounding.hashCode());
result = prime * result + ((stroke == null) ? 0 : stroke.hashCode());
result = prime * result + ((strokeType == null) ? 0 : strokeType.hashCode());
return result;
return true;
if (obj == null)
return false;
- if (!(obj instanceof ConnectionVisuals))
+ if (getClass() != obj.getClass())
return false;
ConnectionVisuals other = (ConnectionVisuals) obj;
if (!Arrays.equals(color, other.color))
return false;
+ if (rounding == null) {
+ if (other.rounding != null)
+ return false;
+ } else if (!rounding.equals(other.rounding))
+ return false;
if (stroke == null) {
if (other.stroke != null)
return false;
} else if (!stroke.equals(other.stroke))
return false;
- if (strokeType == null) {
- if (other.strokeType != null)
- return false;
- } else if (!strokeType.equals(other.strokeType))
+ if (strokeType != other.strokeType)
return false;
return true;
}
StrokeType strokeType = toStrokeType(g.getPossibleObject(structuralConnectionType, g2d.HasStrokeType));
Stroke stroke = G2DUtils.getStroke(g, g.getPossibleObject(structuralConnectionType, g2d.HasStroke));
-
- return new ConnectionVisuals(color, strokeType, stroke);
+ Double rounding = g.getPossibleRelatedValue(structuralConnectionType, g2d.HasRounding, Bindings.DOUBLE);
+
+ return new ConnectionVisuals(color, strokeType, stroke, rounding);
}
StrokeType toStrokeType(Resource strokeType) {
@L0.tag L0.Enumeration
G2D.StrokeType.Scaling : G2D.StrokeType
G2D.StrokeType.Nonscaling : G2D.StrokeType
+G2D.HasRounding <R L0.HasProperty : L0.FunctionalRelation
+ --> L0.Double
G2D.LineEnd <T L0.Property
@L0.optionalProperty G2D.HasLineEndStyle
@L0.singleProperty G2D.HasSize
public final Resource HasRadii_Inverse;
public final Resource HasRasterImage;
public final Resource HasRasterImage_Inverse;
+ public final Resource HasRounding;
+ public final Resource HasRounding_Inverse;
public final Resource HasSVGDocument;
public final Resource HasSVGDocument_Inverse;
public final Resource HasSVGScript;
public static final String HasRadii_Inverse = "http://www.simantics.org/G2D-1.1/HasRadii/Inverse";
public static final String HasRasterImage = "http://www.simantics.org/G2D-1.1/HasRasterImage";
public static final String HasRasterImage_Inverse = "http://www.simantics.org/G2D-1.1/HasRasterImage/Inverse";
+ public static final String HasRounding = "http://www.simantics.org/G2D-1.1/HasRounding";
+ public static final String HasRounding_Inverse = "http://www.simantics.org/G2D-1.1/HasRounding/Inverse";
public static final String HasSVGDocument = "http://www.simantics.org/G2D-1.1/HasSVGDocument";
public static final String HasSVGDocument_Inverse = "http://www.simantics.org/G2D-1.1/HasSVGDocument/Inverse";
public static final String HasSVGScript = "http://www.simantics.org/G2D-1.1/HasSVGScript";
HasRadii_Inverse = getResourceOrNull(graph, URIs.HasRadii_Inverse);
HasRasterImage = getResourceOrNull(graph, URIs.HasRasterImage);
HasRasterImage_Inverse = getResourceOrNull(graph, URIs.HasRasterImage_Inverse);
+ HasRounding = getResourceOrNull(graph, URIs.HasRounding);
+ HasRounding_Inverse = getResourceOrNull(graph, URIs.HasRounding_Inverse);
HasSVGDocument = getResourceOrNull(graph, URIs.HasSVGDocument);
HasSVGDocument_Inverse = getResourceOrNull(graph, URIs.HasSVGDocument_Inverse);
HasSVGScript = getResourceOrNull(graph, URIs.HasSVGScript);
baseStyle.getBranchPointColor(), baseStyle.getBranchPointRadius(),
dynamicStroke != null ? dynamicStroke : baseStyle.getLineStroke(),
dynamicStroke != null ? dynamicStroke : baseStyle.getRouteLineStroke(),
- baseStyle.getDegeneratedLineLength()));
+ 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.getDegeneratedLineLength(), baseStyle.getRounding()));
}
G2DSceneGraph sg;
RouteGraph rg;
RouteGraphNode rgn;
- BasicConnectionStyle style = new BasicConnectionStyle(LINE_COLOR1, Color.BLACK, 3.0, LINE_STROKE, ROUTE_LINE_STROKE, 8);
+ BasicConnectionStyle style = new BasicConnectionStyle(LINE_COLOR1, Color.BLACK, 3.0, LINE_STROKE, ROUTE_LINE_STROKE, 8, 0.0);
Timer timer = new Timer();
TimerTask task = new TimerTask() {