我在JPanel中绘制了两个形状(圆圈),我需要用线连接它们。我这样做只是通过获得圆圈的中间点并相互连接,很容易。
问题是现在我需要制作单向线,它在末尾有一个“箭头”,指出线的方向。所以现在我不能使用圆圈的中点,因为我需要从边框到边框相互连接,所以“箭头”可以正确显示。
在我最后一次尝试结果时,没有什么好处:
PS:在截图中我不是为了看到线的确切位置而填充圆圈,但通常我会填充它。
我无法计算开始/结束我的线所需的边框的确切位置。任何人都知道如何做到这一点?
编辑:圆圈是可移动的,它们可以处于任何位置,因此该线条无论如何都应该有效。
答案 0 :(得分:4)
好的,基本上,我们可以将问题分解为基本问题:
这两个问题都难以解决(任何时候花在搜索互联网上都会提供解决方案 - 因为我从那里获得了解决方案;)
因此,两点之间的角度可以使用类似......
的方法计算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(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);
}
请注意,对结果进行了一些内部修改,以便在数学解决方案与Graphics
API绘制圆圈的方式之间产生差异
好的,你说这么大,这对我有什么帮助?好吧,我实际上很棒。
你计算得到的圆之间的角度(往返,你可以简单地反转一个角度,但我有可用的计算,所以我用它)。从那里,你可以计算线相交的每个圆的点,然后你只需要绘制它,就像......
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();
}
}
}
目的是将箭头视为一个单独的实体。原因是因为它的方式更简单,无论物体之间的距离如何,您都可以获得更一致的结果。
首先,我定义一个新的Shape
...
public class ArrowHead extends Path2D.Double {
public ArrowHead() {
int size = 10;
moveTo(0, size);
lineTo(size / 2, 0);
lineTo(size, size);
}
}
非常简单。它只会创建两条线,指向可用空间的中间。
然后在paintComponent
方法中,我们使用现有的可用信息执行一些AffineTransform
魔术,即
转换ArrowHead
形状......
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);
现在,因为我疯了,我还通过绘制指向源圈的箭头来测试代码,只是为了证明计算能够正常运行......
// This just proofs that the previous calculations weren't a fluke
// and that the arrow can be painted pointing to the source object as well
g2d.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);
答案 1 :(得分:1)
让第一个圆心坐标为AX,AY,半径AR,以及第二个圆圈的BX,BY,BR。
差异向量
...
blurMaskFilterText = (TextView)findViewById(R.id.textView1);
BlurMaskFilter filter = new BlurMaskFilter((blurMaskFilterText.getTextSize()/10),BlurMaskFilter.Blur.INNER);
blurMaskFilterText.getPaint().setMaskFilter(filter);
归一化的
D = (DX, DY) = (BX - AX, BY - AY)
箭头的起点
d = (dx, dy) = (DX / Length(D), DY / Length(D))
结束点
S = (sx, sy) = (AX + dx * AR, AY + dy * AR)
示例:
E = (ex, ey) = (BX - dx * BR, BY - dy * BR)
答案 2 :(得分:0)
查看Screenshot,我认为你需要找到圆圈A的右上角,然后将总距离的一半加到底部到y。接下来,找到圆圈B的右上角,并将左上角的一半距离添加到x。最后,做一条连接两者的线,并在它的末端渲染一个箭头 像这样:
private int x1, y1, x2, y2 width = 20, height = 20;
private void example(Graphics g) {
// Set x1, x2, y1, and y2 to something
g.drawOval(x1, y1, width, height);
g.drawOval(x2, y2, width, height);
g.drawLine(x1, y1 + (height/2), x2 + (width/2), y2);
g.drawImage(/*Image of an arrow*/, (x2 + width/2)-2, y2);
}
答案 3 :(得分:0)