From d568d23103759bc9725a7d5e3a5245a04332b95e Mon Sep 17 00:00:00 2001 From: miettinen Date: Tue, 29 Oct 2013 14:30:55 +0000 Subject: [PATCH] Sysdyn dependency arrow to stop overlapping valve texts. (refs #4482) git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@28152 ac1ea38d-2e2b-0410-8846-a27921b304fc --- .../sysdyn/ui/elements/ValveFactory.java | 66 +++++++- .../sysdyn/ui/elements/ValveOutline.java | 15 +- .../sysdyn/ui/elements/connections/Arcs.java | 157 ++++++++---------- .../connections/DependencyEdgeClass.java | 4 +- .../elements/connections/DependencyNode.java | 4 +- 5 files changed, 143 insertions(+), 103 deletions(-) diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java index edc3785e..12ddbbd5 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java @@ -13,6 +13,9 @@ package org.simantics.sysdyn.ui.elements; import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; @@ -59,6 +62,7 @@ public class ValveFactory extends SysdynElementFactory { public static final Key KEY_ROTATED = new KeyOf(Boolean.class, "ROTATED"); public static final double VALVE_SIZE = 1.5; + public static final double VALVE_TEXT_SHIFT_BOTTOM = 3.0; private static final BasicStroke STROKE = new BasicStroke(1f); public static final Image VALVE_STATIC_IMAGE = new ShapeImage(createShape(VALVE_SIZE, false), null, STROKE, true); @@ -184,7 +188,7 @@ public class ValveFactory extends SysdynElementFactory { String location = e.getHint(SysdynElementHints.KEY_LOCATION); if(location != null) { if(location.equals("Bottom")) { - at2.translate(0, VALVE_SIZE + 3.0); + at2.translate(0, VALVE_SIZE + VALVE_TEXT_SHIFT_BOTTOM); } else if(location.equals("Top")) { at2.translate(0, -VALVE_SIZE - 1); } else if(location.equals("Left")) { @@ -240,6 +244,66 @@ public class ValveFactory extends SysdynElementFactory { return size; } + private Rectangle2D getBoundsText(IElement e, Rectangle2D size) { + HoverTextNode node = (HoverTextNode) e.getHint(SG_NODE); + if (size == null) + size = new Rectangle2D.Double(); + if (node != null) { + Rectangle2D local = node.getBoundsInLocal(); + local.setRect(local.getX(), + local.getY() + VALVE_SIZE + VALVE_TEXT_SHIFT_BOTTOM, + local.getWidth(), + local.getHeight()); + size.setRect(local); + } + else { + String text = e.getHint(ElementHints.KEY_TEXT); + Font font = e.getHint(ElementHints.KEY_FONT); + if(text == null || font == null) + size.setFrame(0, 0, 0, 0); + else { + FontRenderContext FRC = new FontRenderContext(new AffineTransform(), true, true); + TextLayout tl = new TextLayout(text, font, FRC); + Rectangle2D bounds = tl.getLogicalHighlightShape(0, text.length()).getBounds2D(); + size.setFrame( + bounds.getX() * SCALE - paddingX, + (bounds.getY() + VALVE_SIZE) * SCALE - paddingY, + bounds.getWidth()* SCALE + paddingX + paddingX, + bounds.getHeight()* SCALE + paddingY + paddingY); + } + } + return size; + } + + public Path2D.Double getBoundsPath(IElement e, Path2D.Double size) { + if (size == null) + size = new Path2D.Double(); + + // Get the rectangles for the Valve symbol and the text field. + Rectangle2D valve = getBounds(e, new Rectangle2D.Double()); + Rectangle2D text = getBoundsText(e, new Rectangle2D.Double()); + + // Combine the two. + double xV = valve.getX(); + double xVM = valve.getMaxX(); + double yV = valve.getY(); + double xT = text.getX(); + double xTM = text.getMaxX(); + double yT = text.getY(); + double yTM = text.getMaxY(); + size.moveTo(xV, yV); + size.lineTo(xVM, yV); + size.lineTo(xVM, yT); + size.lineTo(xTM, yT); + size.lineTo(xTM, yTM); + size.lineTo(xT, yTM); + size.lineTo(xT, yT); + size.lineTo(xV, yT); + size.closePath(); + + return size; + } + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java index 8e35e695..37b6969b 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java @@ -1,10 +1,13 @@ package org.simantics.sysdyn.ui.elements; -import java.awt.Polygon; import java.awt.Shape; +import java.awt.geom.Path2D; +import java.awt.geom.Rectangle2D; import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.InternalSize; import org.simantics.g2d.element.handler.impl.BoundsOutline; +import org.simantics.sysdyn.ui.elements.ValveFactory.ValveSceneGraph; public class ValveOutline extends BoundsOutline { @@ -18,10 +21,10 @@ public class ValveOutline extends BoundsOutline { @Override public Shape getElementShape(IElement e) { - return super.getElementShape(e); - /*int[] xs = {-5,5,5,20,20,-20,-20,-5}; - int[] ys = {-5,-5,5,5,15,15,5,5}; - Polygon poly = new Polygon(xs, ys, 8); - return poly;*/ + InternalSize b = e.getElementClass().getSingleItem(InternalSize.class); + if (b instanceof ValveSceneGraph) + return ((ValveSceneGraph)b).getBoundsPath(e, new Path2D.Double()); + else + return b.getBounds(e, new Rectangle2D.Double()); } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/Arcs.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/Arcs.java index 602796de..c054d41b 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/Arcs.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/Arcs.java @@ -66,101 +66,74 @@ public class Arcs { } } + + /** + * + * @param startX Start point x coord + * @param startY Start point y coord + * @param cx Center of the circle x coord + * @param cy Center of the circle y coord + * @param r Radius of the circle + * @param curAngle Start angle + * @param endBounds Shape + * @param dir direction to which is iterated + * @param move amount of which is iterated + * @param noOfIteration current number of itartion + * @param turn true iff we are increasing the angle + * @param crossed true if we have crossed the boundary we're targeting + * @return new angle + */ + private static double iterateAngle(double startX, double startY, + double cx, double cy, double r, + double curAngle, Shape endBounds, boolean dir, double move, + int noOfIteration, boolean turn, boolean crossed) { + // Do this many steps + if (noOfIteration > 16) + return normalizeAngle(curAngle); + + if (crossed) // When we have crossed the boundary, start split half method + move *= 0.5; + double x_rad, y_rad; + if (dir != turn) { // The direction of iteration is based on dir and turn bits + x_rad = startX + (move * Math.sin(curAngle)); + y_rad = startY + (move * Math.cos(curAngle)); + } else { + x_rad = startX - (move * Math.sin(curAngle)); + y_rad = startY - (move * Math.cos(curAngle)); + } + curAngle = -Math.atan((y_rad-cy)/(x_rad-cx)); + if (x_rad-cx < 0) + curAngle += Math.PI; + curAngle = normalizeAngle(curAngle); + + if (endBounds.contains(x_rad, y_rad)) { + return iterateAngle(x_rad, y_rad, + cx,cy,r,curAngle,endBounds,dir, move, noOfIteration+1, false, crossed); + } + else { + // Crossed is hereafter true + return iterateAngle(x_rad, y_rad, + cx,cy,r,curAngle,endBounds,dir, move, noOfIteration+1, true, true); + } + } - private static double updateBestNextAngle(double curAngle, double bestAngle, double newAngle) { - if(newAngle < curAngle) - newAngle += PI2; - if(newAngle < bestAngle) - return newAngle; - return bestAngle; - } - - private static double updateBestPrevAngle(double curAngle, double bestAngle, double newAngle) { - if(newAngle > curAngle) - newAngle -= PI2; - if(newAngle > bestAngle) - return newAngle; - return bestAngle; - } - + /** + * + * @param cx x coord of the center point of the circle + * @param cy y coord of the center point of the circle + * @param r radius of the circle + * @param curAngle angle of the arc + * @param endBounds bounding shape + * @param dir direction of the arc + * @return + */ public static double nextIntersectingAngle(double cx, double cy, double r, double curAngle, Shape endBounds, boolean dir) { - if(!dir) { - double bestAngle = curAngle + PI2; - { - double dx = endBounds.getBounds2D().getMinX() - cx; - if(Math.abs(dx) < r) { - double angle = normalizeAngle(Math.acos(dx / r)); - bestAngle = updateBestNextAngle(curAngle, bestAngle, angle); - bestAngle = updateBestNextAngle(curAngle, bestAngle, -angle); - } - } - { - double dx = endBounds.getBounds2D().getMaxX() - cx; - if(Math.abs(dx) < r) { - double angle = normalizeAngle(Math.acos(dx / r)); - bestAngle = updateBestNextAngle(curAngle, bestAngle, angle); - bestAngle = updateBestNextAngle(curAngle, bestAngle, -angle); - } - } - { - double dy = cy - endBounds.getBounds2D().getMinY(); - if(Math.abs(dy) < r) { - double angle = Math.asin(dy / r); - bestAngle = updateBestNextAngle(curAngle, bestAngle, angle); - bestAngle = updateBestNextAngle(curAngle, bestAngle, - normalizeAngle(Math.PI-angle)); - } - } - { - double dy = cy - endBounds.getBounds2D().getMaxY(); - if(Math.abs(dy) < r) { - double angle = Math.asin(dy / r); - bestAngle = updateBestNextAngle(curAngle, bestAngle, angle); - bestAngle = updateBestNextAngle(curAngle, bestAngle, - normalizeAngle(Math.PI-angle)); - } - } - return normalizeAngle(bestAngle); - } - else { - double bestAngle = curAngle - PI2; - { - double dx = endBounds.getBounds2D().getMinX() - cx; - if(Math.abs(dx) < r) { - double angle = normalizeAngle(Math.acos(dx / r)); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, -angle); - } - } - { - double dx = endBounds.getBounds2D().getMaxX() - cx; - if(Math.abs(dx) < r) { - double angle = normalizeAngle(Math.acos(dx / r)); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, -angle); - } - } - { - double dy = cy - endBounds.getBounds2D().getMinY(); - if(Math.abs(dy) < r) { - double angle = Math.asin(dy / r); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, - normalizeAngle(Math.PI-angle)); - } - } - { - double dy = cy - endBounds.getBounds2D().getMaxY(); - if(Math.abs(dy) < r) { - double angle = Math.asin(dy / r); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle); - bestAngle = updateBestPrevAngle(curAngle, bestAngle, - normalizeAngle(Math.PI-angle)); - } - } - return normalizeAngle(bestAngle); - } + // Move this much per iteration till the border is crossed. + double move = 3.0; + return iterateAngle(endBounds.getBounds2D().getCenterX(), + endBounds.getBounds2D().getCenterY(), + cx,cy,r,curAngle,endBounds,dir,move, 0, false, false); } public static boolean hitTest(Shape beginBounds, Shape endBounds, double angle, double x, double y, double tolerance) { diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyEdgeClass.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyEdgeClass.java index 385a4492..3e04c801 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyEdgeClass.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyEdgeClass.java @@ -210,8 +210,8 @@ public class DependencyEdgeClass { node.setEditable(false); node.setFont(font); - node.setBeginBounds(beginTerminalShape.getBounds2D()); - node.setEndBounds(endTerminalShape.getBounds2D()); + node.setBeginBounds(beginTerminalShape); + node.setEndBounds(endTerminalShape); node.setStroke(stroke); node.setColor(color); node.setShapes(DependencyRouter.createArrowShape(node.getShapes(), node.getBeginBounds(), node.getEndBounds(), node.getAngle())); diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyNode.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyNode.java index bfb4474b..24178b01 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyNode.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/DependencyNode.java @@ -124,13 +124,13 @@ public class DependencyNode extends TextNode implements ISelectionPainterNode { @PropertySetter("beginBounds") @SyncField("beginBounds") - public void setBeginBounds(Rectangle2D beginBounds) { + public void setBeginBounds(Shape beginBounds) { this.beginBounds = beginBounds; } @PropertySetter("endBounds") @SyncField("endBounds") - public void setEndBounds(Rectangle2D endBounds) { + public void setEndBounds(Shape endBounds) { this.endBounds = endBounds; } -- 2.47.1