【问题标题】:Problem when drawing arrows. How do I set the coordinates correctly?绘制箭头时出现问题。如何正确设置坐标?
【发布时间】:2020-01-25 01:09:05
【问题描述】:
    Polygon arrow = new Polygon();
    arrow.addPoint(0, 5);
    arrow.addPoint(-5, -5);
    arrow.addPoint(5, -5);

    AffineTransform tx = new AffineTransform();
    double angle = Math.atan2(y2 - y1, x2 - x1);
    tx.translate(x2 + Config.VERTEX_RADIUS / 2, y2 + Config.VERTEX_RADIUS / 2);
    tx.rotate((angle - Math.PI / 2));

    graphics.setColor(Color.BLACK);
    graphics.draw(new Line2D.Double(x1, y1, x2, y2));
    graphics.setTransform(tx);
    graphics.fill(arrow);

屏幕:http://imglink.ru/show-image.php?id=254ac13712ad825a1a1b99181170f747

编辑 所以,我在 MadProgrammer 的建议下更改了代码,但是箭头出现了如此令人不快的变化。屏幕 -> http://www.imglink.ru/show-image.php?id=f1d6d3dfdb52972d731690e031af7d71

private void drawEdgeLine(Graphics2D graphics, double x1, double y1, double x2, double y2) {

    graphics.setColor(Color.BLACK);
    graphics.draw(new Line2D.Double(x1, y1, x2, y2));

    ArrowHead arrowHead = new ArrowHead();
    double length = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
    double t1 = Config.VERTEX_RADIUS / length;
    double t2 = (length - Config.VERTEX_RADIUS) / length;
    double arrowX, arrowY;
    if (t1 > t2) {
        arrowX = x1 + t1 * (x2 - x1);
        arrowY = y1 + t1 * (y2 - y1);
    } else {
        arrowX = x1 + t2 * (x2 - x1);
        arrowY = y1 + t2 * (y2 - y1);
    }

    double angle = Math.atan2(y2 - y1, x2 - x1);
    /*double angleDegrees = Math.toDegrees(angle + Math.PI);
    System.out.println(angleDegrees);
    if (angleDegrees > 90 && angleDegrees < 270) {
        arrowY += Config.ARROW_HEAD_SIZE / 2;
    } else {
        arrowX -= Config.ARROW_HEAD_SIZE / 2;
    }*/

    AffineTransform transform = AffineTransform.getTranslateInstance(arrowX, arrowY);
    transform.rotate(angle + Math.PI / 2);
    arrowHead.transform(transform);
    graphics.draw(arrowHead);
}

}

类 ArrowHead 扩展 Path2D.Double {

public ArrowHead() {
    double size = Config.ARROW_HEAD_SIZE;
    moveTo(0, size);
    lineTo(size / 2, 0);
    lineTo(size, size);
}

}

【问题讨论】:

  • 因此,旋转将发生在锚点的左上角(0x0)。我倾向于做的是将区域转换到我想要放置对象的位置,因此锚点变为0x0 围绕对象中心旋转,完成后记得撤消混乱

标签: java swing graph graphics graphics2d


【解决方案1】:

因此,旋转将发生在左上角(0x0 或“原点”)。对于一个组件,这已经被翻译到上/左角以供您说服。

您还需要考虑到转换是复合的,因此您需要确保在完成后撤消它们 - 尤其是因为 Swing 中的 Graphics 上下文是共享的……这真的会搞砸事情起来。

所以。基本思路是:

  • 将内容翻译到您想要绘制形状的位置
  • 围绕形状中心旋转上下文,这将“通常”产生所需的结果
  • 重置转换

以下示例演示基本思想并使用Timer 旋转形状

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ArrowHead extends Path2D.Double {

        public ArrowHead() {
            int size = 10;
            moveTo(0, size);
            lineTo(size / 2, 0);
            lineTo(size, size);
            closePath();
        }

    }

    public class TestPane extends JPanel {

        private ArrowHead arrow = new ArrowHead();
        private double angleOfAttack = 0;

        public TestPane() {
            Timer timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angleOfAttack += 0.5;
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // Snap shot the current context
            Graphics2D g2d = (Graphics2D) g.create();

            // Translate to somewhere you want the arrow painted ...
            g2d.translate(50, 50);
            // The bounding box of the arrow...
            Rectangle bounds = arrow.getBounds();

            // A guide, showing where the arrow is been painted without the rotation
            g2d.setColor(Color.RED);
            g2d.draw(bounds);

            // Rotate abount the middle of the arrow...
            g2d.rotate(Math.toRadians(angleOfAttack), bounds.width / 2, bounds.height / 2);
            g2d.setColor(Color.BLACK);
            // Draw the arrow
            g2d.fill(arrow);

            // Discard the transformations so we don't effect anyone else
            g2d.dispose();
        }

    }

}

您可能还想看看Connect two circles with a line,这是这个概念的一个更复杂的例子,但它似乎更符合您想要实现的目标

【讨论】:

  • 好的,看看我提供的,你有两个完整的例子,你可以运行和修改你的心内容,你可以看到代码是如何工作的,看看变化是如何影响它的.现在,看看你为我提供了什么——一些脱离上下文的 sn-ps,其中有很多关于状态和上下文的未回答的问题。你需要把你的问题提炼成minimal reproducible example,在你告诉我这“太难”之前——我已经做过两次了
猜你喜欢
  • 2012-07-15
  • 1970-01-01
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-07
  • 1970-01-01
相关资源
最近更新 更多