好的,基本上,我们可以将问题分解为基本问题:
- 获取两个圆之间的角度
- 从这个圆的圆周到另一个圆的圆周画一条线
这两个问题都不难解决(而且花在
互联网上的任何时间都会提供解决方案-因为那是我从中获得的;))
因此,两点之间的角度可以使用类似…的方法来计算
protected double angleBetween(Point2D from, Point2D to) { double x = from.getX(); double y = from.getY(); // This is the difference between the anchor point // and the mouse. Its important that this is done // within the local coordinate space of the component, // this means either the MouseMotionListener needs to // be registered to the component itself (preferably) // or the mouse coordinates need to be converted into // local coordinate space double deltaX = to.getX() - x; double deltaY = to.getY() - y; // Calculate the angle... // This is our "0" or start angle.. double rotation = -Math.atan2(deltaX, deltaY); rotation = Math.toRadians(Math.toDegrees(rotation) + 180); return rotation;}And the point on a circle can be calculated using something like…
protected Point2D getPointonCircle(Point2D center, double radians, double radius) { double x = center.getX(); double y = center.getY(); radians = radians - Math.toRadians(90.0); // 0 becomes the top // Calculate the outter point of the line double xPosy = Math.round((float) (x + Math.cos(radians) * radius)); double yPosy = Math.round((float) (y + Math.sin(radians) * radius)); return new Point2D.Double(xPosy, yPosy);}请注意,对结果进行了一些内部修改,以允许数学解决方案与
GraphicsAPI绘制圆圈的方式之间的差异
好的,您说的这么多,对我有什么帮助?好吧,我实际上很棒。
您可以计算到的圆之间的角度(来回之间,也许
可以简单地将一个角度反演,但是我有可用的计算方法,所以我
使用了它)。由此,您可以计算线将
在其上相交的每个圆的点,然后只需要绘制它,就像…
double from = angleBetween(circle1, circle2);double to = angleBetween(circle2, circle1);Point2D pointFrom = getPointonCircle(circle1, from);Point2D pointTo = getPointonCircle(circle2, to);Line2D line = new Line2D.Double(pointFrom, pointTo);g2d.draw(line);
可运行的例子
因为我将许多计算精简为公用属性,所以提供了测试代码作为可运行示例。所有的
计算都是基于动态值,没有什么是真正的硬编码。对于例如,你可以改变大小和圆的位置和计算应该继续工作......
import java.awt.Color;import java.awt.Dimension;import java.awt.EventQueue;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Shape;import java.awt.geom.Ellipse2D;import java.awt.geom.Line2D;import java.awt.geom.Point2D;import java.awt.geom.Rectangle2D;import javax.swing.Jframe;import javax.swing.JPanel;import javax.swing.UIManager;import javax.swing.UnsupportedLookAndFeelException;public class Test { public static void main(String[] args) { new Test(); } public Test() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } Jframe frame = new Jframe("Testing"); frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private Ellipse2D circle1; private Ellipse2D circle2; private Point2D drawTo; public TestPane() { circle1 = new Ellipse2D.Double(10, 10, 40, 40); circle2 = new Ellipse2D.Double(100, 150, 40, 40); //addMouseMotionListener(new MouseAdapter() { // @Override // public void mouseMoved(MouseEvent e) { // drawTo = new Point2D.Double(e.getPoint().x, e.getPoint().y); // repaint(); // } //}); } protected Point2D center(Rectangle2D bounds) { return new Point2D.Double(bounds.getCenterX(), bounds.getCenterY()); } protected double angleBetween(Shape from, Shape to) { return angleBetween(center(from.getBounds2D()), center(to.getBounds2D())); } protected double angleBetween(Point2D from, Point2D to) { double x = from.getX(); double y = from.getY(); // This is the difference between the anchor point // and the mouse. Its important that this is done // within the local coordinate space of the component, // this means either the MouseMotionListener needs to // be registered to the component itself (preferably) // or the mouse coordinates need to be converted into // local coordinate space double deltaX = to.getX() - x; double deltaY = to.getY() - y; // Calculate the angle... // This is our "0" or start angle.. double rotation = -Math.atan2(deltaX, deltaY); rotation = Math.toRadians(Math.toDegrees(rotation) + 180); return rotation; } protected Point2D getPointonCircle(Shape shape, double radians) { Rectangle2D bounds = shape.getBounds();// Point2D point = new Point2D.Double(bounds.getX(), bounds.getY()); Point2D point = center(bounds); return getPointonCircle(point, radians, Math.max(bounds.getWidth(), bounds.getHeight()) / 2d); } protected Point2D getPointonCircle(Point2D center, double radians, double radius) { double x = center.getX(); double y = center.getY(); radians = radians - Math.toRadians(90.0); // 0 becomes th?e top // Calculate the outter point of the line double xPosy = Math.round((float) (x + Math.cos(radians) * radius)); double yPosy = Math.round((float) (y + Math.sin(radians) * radius)); return new Point2D.Double(xPosy, yPosy); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.draw(circle1); g2d.draw(circle2); // This was used for testing, it will draw a line from circle1 to the // drawTo point, which, if enabled, is the last known position of the // mouse //if (drawTo != null) { // Point2D pointFrom = center(circle1.getBounds2D()); // g2d.setColor(Color.RED); // g2d.draw(new Line2D.Double(drawTo, pointFrom)); // // double from = angleBetween(pointFrom, drawTo); // System.out.println(NumberFormat.getNumberInstance().format(Math.toDegrees(from))); // // Point2D poc = getPointonCircle(circle1, from); // g2d.setColor(Color.BLUE); // g2d.draw(new Line2D.Double(poc, drawTo)); //} double from = angleBetween(circle1, circle2); double to = angleBetween(circle2, circle1); Point2D pointFrom = getPointonCircle(circle1, from); Point2D pointTo = getPointonCircle(circle2, to); g2d.setColor(Color.RED); Line2D line = new Line2D.Double(pointFrom, pointTo); g2d.draw(line); g2d.dispose(); } }}Arrow head
The intention is to treat the arrow head as a separate entity. The reason is
because it’s just simpler that way, you also get a more consistent result
regardless of the distance between the objects.
So, to start with, I define a new
Shape…
public class ArrowHead extends Path2D.Double { public ArrowHead() { int size = 10; moveTo(0, size); lineTo(size / 2, 0); lineTo(size, size); }}Pretty simple really. It just creates two lines, which point up, meeting in
the middle of the available space.
Then in the
paintComponentmethod, we perform some
AffineTransformmagic
using the available information we already have, namely
- The point on our target circles circumference
- The angle to our target circle
And transform the
ArrowHeadshape…
g2d.setColor(Color.MAGENTA);ArrowHead arrowHead = new ArrowHead();AffineTransform at = AffineTransform.getTranslateInstance( pointTo.getX() - (arrowHead.getBounds2D().getWidth() / 2d), pointTo.getY());at.rotate(from, arrowHead.getBounds2D().getCenterX(), 0);arrowHead.transform(at);g2d.draw(arrowHead);
Now, because I’m crazy, I also tested the pre by drawing an arrow pointing at
our source circle, just to prove that the calculations would work…
// This just proofs that the previous calculations weren't a fluke// and that the arrow can be painted pointing to the source object as wellg2d.setColor(Color.GREEN);arrowHead = new ArrowHead();at = AffineTransform.getTranslateInstance( pointFrom.getX() - (arrowHead.getBounds2D().getWidth() / 2d), pointFrom.getY());at.rotate(to, arrowHead.getBounds2D().getCenterX(), 0);arrowHead.transform(at);g2d.draw(arrowHead);



