gpt4 book ai didi

java - 根据角度绕圆画一条线

转载 作者:行者123 更新时间:2023-12-01 18:07:40 25 4
gpt4 key购买 nike

我希望它看起来像:

enter image description here

圆圈随着箭头围绕中心圆移动。

目前情况如何:

enter image description here

我想在两个圆之间画两条线。然而这些圆圈在屏幕上到处移动,我不知道在它们之间画线的有条不紊的方法。例如,我总是有两个圆圈的左上角,我想在它们之间画一条线,但仅此而已。我需要帮助在java中画一条线,该线将根据其位置进行调整,以便线随着圆圈的移动而围绕边缘移动

      for (int z = 0; z < lines.size(); z++) {
if (lines.get(z).getfState().equals(states.get(a).getText()) && !lines.get(z).getfState().equals(lines.get(z).getnState())) {
transition.get(z).setIcon(null);
for (int x = 0; x < states.size(); x++) {
if (states.get(x).getText().equals(lines.get(z).getnState()) && states.get(a).getText().equals(lines.get(z).getfState())) {
int xbegin = (int) states.get(a).getBounds().getX();
int ybegin = (int) states.get(a).getBounds().getY();
int xend = (int) states.get(x).getBounds().getX();
int yend = (int) states.get(x).getBounds().getY();
if (xbegin > xend) {
Path2D.Double rect = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend, yend, 10, 7));
OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend + 30, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect.getBounds().x, rect.getBounds().y, rect.getBounds().width + 20, rect.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
} else {
if (xend - xbegin < 75) {
xbegin = xbegin - 20;
xend = xend - 20;
}
xbegin = xbegin + 5;
ybegin = ybegin + 25;
xend = xend + 5;
yend = yend + 25;
Path2D.Double rect = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7));
OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect.getBounds().x, rect.getBounds().y, rect.getBounds().width + 20, rect.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
}

}
}
} else if (lines.get(z).getnState().equals(states.get(a).getText()) && !lines.get(z).getfState().equals(lines.get(z).getnState())) {
transition.get(z).setIcon(null);
for (int x = 0; x < states.size(); x++) {
if (states.get(x).getText().equals(lines.get(z).getfState()) && states.get(a).getText().equals(lines.get(z).getnState())) {
int xend = (int) states.get(a).getBounds().getX();
int yend = (int) states.get(a).getBounds().getY();
int xbegin = (int) states.get(x).getBounds().getX();
int ybegin = (int) states.get(x).getBounds().getY();
if (xbegin > xend) {
Path2D.Double rect2 = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend, yend, 10, 7));

OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend + 30, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect2.getBounds().x, rect2.getBounds().y, rect2.getBounds().width + 20, rect2.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
} else {
if (xend - xbegin < 75) {
xbegin = xbegin + 20;
xend = xend + 20;
}
xbegin = xbegin + 5;
ybegin = ybegin + 25;
xend = xend + 5;
yend = yend + 25;
Path2D.Double rect2 = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7));
OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect2.getBounds().x, rect2.getBounds().y, rect2.getBounds().width + 20, rect2.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
}
}
}
public static Path2D.Double createArrowForLine(
int fromPointx,
int fromPointy,
double rotationDeg,
double length,
double wingsAngleDeg) {

double ax = fromPointx;
double ay = fromPointy;

double radB = Math.toRadians(-rotationDeg + wingsAngleDeg);
double radC = Math.toRadians(-rotationDeg - wingsAngleDeg);

Path2D resultPath = new Path2D.Double();
resultPath.moveTo(length * Math.cos(radB) + ax, length * Math.sin(radB) + ay);
resultPath.lineTo(ax, ay);
resultPath.lineTo(length * Math.cos(radC) + ax, length * Math.sin(radC) + ay);
return (Path2D.Double) resultPath;
}

最佳答案

虽然问题中出现了一些问题,并且到目前为止提供的代码看起来有问题,但现在问题的核心非常有趣......

解决这个问题有不同的选择。从您到目前为止提供的图像来看,圆圈看起来总是具有相同的大小,这使事情变得简单得多。对于不同大小的圆,您实际上必须在所需方向上计算圆的切线,同时考虑另一个圆的半径。当然,这是可能的,但有点不那么简单。

如果您有相同大小的圆圈,则可以

  • 计算两个圆心的差
  • 将其除以距离,以获得(标准化)方向
  • 将此方向旋转 90°
  • 按半径缩放旋转方向 vector
  • 将缩放和旋转的 vector 添加到圆心

这将产生这样一条线的一个端点。可以顺时针方向旋转一次,逆时针方向旋转一次约90°,分别获得直线的“上”和“下”端点。

LinesAtCircle

图像已通过编辑进行更新,请参见下文

实际计算是在 MCVEcomputeLine 方法中完成的以下。请注意,此示例使用“简单”方法,尽管它使用大小略有不同的圆圈。其效果是,当两个圆的大小差异太大时(基本上与圆之间的距离相比),直线可能会与圆稍微相交。但解决方案应该是简单性和普遍适用性之间的合理权衡。特别是,对于大小相等的圆,根本不会有交点。

代码已通过编辑进行更新,请参见下文

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class LinesAtCirclesTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{

@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel linesAtCirclesTestPanel = new LinesAtCirclesTestPanel();
f.getContentPane().add(linesAtCirclesTestPanel);
f.setSize(400,400);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}

class LinesAtCirclesTestPanel extends JPanel
implements MouseListener, MouseMotionListener
{
private Point2D draggedCenter;
private List<Point2D> centers = new ArrayList<Point2D>();
private List<Double> radii = new ArrayList<Double>();

public LinesAtCirclesTestPanel()
{
addMouseListener(this);
addMouseMotionListener(this);

addCircle(100, 100, 30);
addCircle(200, 300, 50);
addCircle(300, 200, 40);
}

private void addCircle(double x, double y, double radius)
{
centers.add(new Point2D.Double(x,y));
radii.add(radius);
}

@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

for (int i=0; i<centers.size(); i++)
{
Point2D center0 = centers.get(i);
double radius0 = radii.get(i);

Shape ellipse = new Ellipse2D.Double(
center0.getX() - radius0, center0.getY() - radius0,
radius0 + radius0, radius0 + radius0);

g.setColor(Color.LIGHT_GRAY);
g.fill(ellipse);
g.setColor(Color.BLACK);
g.draw(ellipse);
}

g.setColor(Color.RED);
for (int i=0; i<centers.size() - 1; i++)
{
Point2D center0 = centers.get(i);
double radius0 = radii.get(i);
Point2D center1 = centers.get(i+1);
double radius1 = radii.get(i+1);

g.draw(createArrow(computeLine(center0, radius0, center1, radius1, true)));
g.draw(createArrow(computeLine(center0, radius0, center1, radius1, false)));
}
}

private static Shape createArrow(Line2D line)
{
double dx = line.getX2() - line.getX1();
double dy = line.getY2() - line.getY1();
double angleToX = Math.atan2(dy, dx);
final double angleRad = Math.toRadians(30);
final double headLength = 20.0f;
double dxL = Math.cos(Math.PI + angleToX + angleRad) * headLength;
double dyL = Math.sin(Math.PI + angleToX + angleRad) * headLength;
double dxR = Math.cos(Math.PI + angleToX - angleRad) * headLength;
double dyR = Math.sin(Math.PI + angleToX - angleRad) * headLength;
Path2D arrow = new Path2D.Double();
arrow.moveTo(line.getX1(), line.getY1());
arrow.lineTo(line.getX2(), line.getY2());
arrow.lineTo(line.getX2() + dxL, line.getY2() + dyL);
arrow.moveTo(line.getX2(), line.getY2());
arrow.lineTo(line.getX2() + dxR, line.getY2() + dyR);
return arrow;
}

private static Line2D computeLine(
Point2D center0, double radius0,
Point2D center1, double radius1,
boolean upper)
{
double dx = center1.getX() - center0.getX();
double dy = center1.getY() - center0.getY();
double invLength = 1.0 / Math.hypot(dx, dy);
double dirX = dx * invLength;
double dirY = dy * invLength;

double rotDirX = dirY;
double rotDirY = -dirX;
if (upper)
{
rotDirX = -dirY;
rotDirY = dirX;
}

double x0 = center0.getX() + rotDirX * radius0;
double y0 = center0.getY() + rotDirY * radius0;

double x1 = center1.getX() + rotDirX * radius1;
double y1 = center1.getY() + rotDirY * radius1;

if (upper)
{
return new Line2D.Double(x1, y1, x0, y0);
}
return new Line2D.Double(x0, y0, x1, y1);
}

@Override
public void mousePressed(MouseEvent e)
{
draggedCenter = null;
for (int i=0; i<centers.size(); i++)
{
Point2D center = centers.get(i);
double radius = radii.get(i);
if (e.getPoint().distance(center) < radius)
{
draggedCenter = center;
}
}
}

@Override
public void mouseReleased(MouseEvent e)
{
draggedCenter = null;
}

@Override
public void mouseDragged(MouseEvent e)
{
if (draggedCenter == null)
{
return;
}
draggedCenter.setLocation(e.getPoint());
repaint();
}



@Override
public void mouseMoved(MouseEvent e)
{
// Not used
}

@Override
public void mouseClicked(MouseEvent e)
{
// Not used
}

@Override
public void mouseEntered(MouseEvent e)
{
// Not used
}

@Override
public void mouseExited(MouseEvent e)
{
// Not used
}
}
<小时/>

EDIT in response to the comment:

原始代码计算 Line2D 对象。在最简单的情况下,从直线创建箭头基本上是通过一些三角学来完成的,并且网络上存在许多这方面的资源。

为了回应评论,我扩展了示例以显示简单的箭头,如上图所示。

<小时/>

但是,当仔细观察时,人们可能会注意到这样的箭头有几个自由度:

  • 头部长度应该是绝对长度还是相对于箭头?
  • 头部宽度应该是绝对宽度还是相对于箭头?
  • (或者:箭头的角度应该是多少?)
  • 箭头应该填充还是由线条组成?
  • 箭头的“主干”应该是单线还是轮廓形状?
  • 树干的宽度应该是多少?
  • ...

为了涵盖其中一些自由度,我创建了一个 ArrowCreator前段时间上课,还有一个sample展示如何使用它。

关于java - 根据角度绕圆画一条线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35074321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com