\r
import java.awt.BasicStroke;\r
import java.awt.Color;\r
+import java.awt.Font;\r
+import java.awt.font.FontRenderContext;\r
+import java.awt.font.TextLayout;\r
import java.awt.geom.AffineTransform;\r
import java.awt.geom.Path2D;\r
import java.awt.geom.Rectangle2D;\r
public static final Key KEY_ROTATED = new KeyOf(Boolean.class, "ROTATED");\r
\r
public static final double VALVE_SIZE = 1.5;\r
+ public static final double VALVE_TEXT_SHIFT_BOTTOM = 3.0;\r
\r
private static final BasicStroke STROKE = new BasicStroke(1f);\r
public static final Image VALVE_STATIC_IMAGE = new ShapeImage(createShape(VALVE_SIZE, false), null, STROKE, true);\r
String location = e.getHint(SysdynElementHints.KEY_LOCATION);\r
if(location != null) {\r
if(location.equals("Bottom")) {\r
- at2.translate(0, VALVE_SIZE + 3.0);\r
+ at2.translate(0, VALVE_SIZE + VALVE_TEXT_SHIFT_BOTTOM);\r
} else if(location.equals("Top")) {\r
at2.translate(0, -VALVE_SIZE - 1);\r
} else if(location.equals("Left")) {\r
return size;\r
}\r
\r
+ private Rectangle2D getBoundsText(IElement e, Rectangle2D size) {\r
+ HoverTextNode node = (HoverTextNode) e.getHint(SG_NODE);\r
+ if (size == null)\r
+ size = new Rectangle2D.Double();\r
+ if (node != null) {\r
+ Rectangle2D local = node.getBoundsInLocal();\r
+ local.setRect(local.getX(), \r
+ local.getY() + VALVE_SIZE + VALVE_TEXT_SHIFT_BOTTOM, \r
+ local.getWidth(), \r
+ local.getHeight());\r
+ size.setRect(local);\r
+ }\r
+ else {\r
+ String text = e.getHint(ElementHints.KEY_TEXT);\r
+ Font font = e.getHint(ElementHints.KEY_FONT);\r
+ if(text == null || font == null)\r
+ size.setFrame(0, 0, 0, 0);\r
+ else {\r
+ FontRenderContext FRC = new FontRenderContext(new AffineTransform(), true, true);\r
+ TextLayout tl = new TextLayout(text, font, FRC);\r
+ Rectangle2D bounds = tl.getLogicalHighlightShape(0, text.length()).getBounds2D(); \r
+ size.setFrame(\r
+ bounds.getX() * SCALE - paddingX,\r
+ (bounds.getY() + VALVE_SIZE) * SCALE - paddingY, \r
+ bounds.getWidth()* SCALE + paddingX + paddingX, \r
+ bounds.getHeight()* SCALE + paddingY + paddingY);\r
+ }\r
+ }\r
+ return size;\r
+ }\r
+ \r
+ public Path2D.Double getBoundsPath(IElement e, Path2D.Double size) {\r
+ if (size == null)\r
+ size = new Path2D.Double();\r
+\r
+ // Get the rectangles for the Valve symbol and the text field.\r
+ Rectangle2D valve = getBounds(e, new Rectangle2D.Double());\r
+ Rectangle2D text = getBoundsText(e, new Rectangle2D.Double());\r
+ \r
+ // Combine the two.\r
+ double xV = valve.getX();\r
+ double xVM = valve.getMaxX();\r
+ double yV = valve.getY();\r
+ double xT = text.getX();\r
+ double xTM = text.getMaxX();\r
+ double yT = text.getY();\r
+ double yTM = text.getMaxY();\r
+ size.moveTo(xV, yV);\r
+ size.lineTo(xVM, yV);\r
+ size.lineTo(xVM, yT);\r
+ size.lineTo(xTM, yT);\r
+ size.lineTo(xTM, yTM);\r
+ size.lineTo(xT, yTM);\r
+ size.lineTo(xT, yT);\r
+ size.lineTo(xV, yT);\r
+ size.closePath();\r
+ \r
+ return size;\r
+ }\r
+\r
}\r
\r
}\r
\r
}\r
}\r
+ \r
+ /**\r
+ * \r
+ * @param startX Start point x coord\r
+ * @param startY Start point y coord\r
+ * @param cx Center of the circle x coord\r
+ * @param cy Center of the circle y coord\r
+ * @param r Radius of the circle\r
+ * @param curAngle Start angle\r
+ * @param endBounds Shape\r
+ * @param dir direction to which is iterated\r
+ * @param move amount of which is iterated\r
+ * @param noOfIteration current number of itartion\r
+ * @param turn true iff we are increasing the angle\r
+ * @param crossed true if we have crossed the boundary we're targeting\r
+ * @return new angle\r
+ */\r
+ private static double iterateAngle(double startX, double startY, \r
+ double cx, double cy, double r,\r
+ double curAngle, Shape endBounds, boolean dir, double move,\r
+ int noOfIteration, boolean turn, boolean crossed) {\r
+ // Do this many steps\r
+ if (noOfIteration > 16)\r
+ return normalizeAngle(curAngle);\r
+ \r
+ if (crossed) // When we have crossed the boundary, start split half method\r
+ move *= 0.5;\r
+ double x_rad, y_rad;\r
+ if (dir != turn) { // The direction of iteration is based on dir and turn bits\r
+ x_rad = startX + (move * Math.sin(curAngle));\r
+ y_rad = startY + (move * Math.cos(curAngle));\r
+ } else {\r
+ x_rad = startX - (move * Math.sin(curAngle));\r
+ y_rad = startY - (move * Math.cos(curAngle));\r
+ }\r
+ curAngle = -Math.atan((y_rad-cy)/(x_rad-cx));\r
+ if (x_rad-cx < 0)\r
+ curAngle += Math.PI;\r
+ curAngle = normalizeAngle(curAngle);\r
+ \r
+ if (endBounds.contains(x_rad, y_rad)) {\r
+ return iterateAngle(x_rad, y_rad,\r
+ cx,cy,r,curAngle,endBounds,dir, move, noOfIteration+1, false, crossed);\r
+ }\r
+ else {\r
+ // Crossed is hereafter true\r
+ return iterateAngle(x_rad, y_rad,\r
+ cx,cy,r,curAngle,endBounds,dir, move, noOfIteration+1, true, true);\r
+ }\r
+ }\r
\r
- private static double updateBestNextAngle(double curAngle, double bestAngle, double newAngle) {\r
- if(newAngle < curAngle)\r
- newAngle += PI2;\r
- if(newAngle < bestAngle)\r
- return newAngle;\r
- return bestAngle; \r
- } \r
- \r
- private static double updateBestPrevAngle(double curAngle, double bestAngle, double newAngle) {\r
- if(newAngle > curAngle)\r
- newAngle -= PI2;\r
- if(newAngle > bestAngle)\r
- return newAngle;\r
- return bestAngle; \r
- } \r
- \r
+ /**\r
+ * \r
+ * @param cx x coord of the center point of the circle \r
+ * @param cy y coord of the center point of the circle\r
+ * @param r radius of the circle\r
+ * @param curAngle angle of the arc\r
+ * @param endBounds bounding shape\r
+ * @param dir direction of the arc\r
+ * @return\r
+ */\r
public static double nextIntersectingAngle(double cx, double cy, double r,\r
double curAngle, Shape endBounds, boolean dir) {\r
- if(!dir) {\r
- double bestAngle = curAngle + PI2;\r
- {\r
- double dx = endBounds.getBounds2D().getMinX() - cx;\r
- if(Math.abs(dx) < r) {\r
- double angle = normalizeAngle(Math.acos(dx / r));\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, -angle);\r
- }\r
- }\r
- {\r
- double dx = endBounds.getBounds2D().getMaxX() - cx;\r
- if(Math.abs(dx) < r) {\r
- double angle = normalizeAngle(Math.acos(dx / r));\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, -angle);\r
- }\r
- }\r
- {\r
- double dy = cy - endBounds.getBounds2D().getMinY();\r
- if(Math.abs(dy) < r) {\r
- double angle = Math.asin(dy / r);\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, \r
- normalizeAngle(Math.PI-angle));\r
- }\r
- }\r
- {\r
- double dy = cy - endBounds.getBounds2D().getMaxY();\r
- if(Math.abs(dy) < r) {\r
- double angle = Math.asin(dy / r);\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestNextAngle(curAngle, bestAngle, \r
- normalizeAngle(Math.PI-angle));\r
- }\r
- }\r
- return normalizeAngle(bestAngle);\r
- } \r
- else {\r
- double bestAngle = curAngle - PI2;\r
- {\r
- double dx = endBounds.getBounds2D().getMinX() - cx;\r
- if(Math.abs(dx) < r) {\r
- double angle = normalizeAngle(Math.acos(dx / r));\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, -angle);\r
- }\r
- }\r
- {\r
- double dx = endBounds.getBounds2D().getMaxX() - cx;\r
- if(Math.abs(dx) < r) {\r
- double angle = normalizeAngle(Math.acos(dx / r));\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, -angle);\r
- }\r
- }\r
- {\r
- double dy = cy - endBounds.getBounds2D().getMinY();\r
- if(Math.abs(dy) < r) {\r
- double angle = Math.asin(dy / r);\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, \r
- normalizeAngle(Math.PI-angle));\r
- }\r
- }\r
- {\r
- double dy = cy - endBounds.getBounds2D().getMaxY();\r
- if(Math.abs(dy) < r) {\r
- double angle = Math.asin(dy / r);\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
- bestAngle = updateBestPrevAngle(curAngle, bestAngle, \r
- normalizeAngle(Math.PI-angle));\r
- }\r
- }\r
- return normalizeAngle(bestAngle);\r
- }\r
+ // Move this much per iteration till the border is crossed.\r
+ double move = 3.0;\r
+ return iterateAngle(endBounds.getBounds2D().getCenterX(),\r
+ endBounds.getBounds2D().getCenterY(),\r
+ cx,cy,r,curAngle,endBounds,dir,move, 0, false, false);\r
}\r
\r
public static boolean hitTest(Shape beginBounds, Shape endBounds, double angle, double x, double y, double tolerance) {\r