【问题标题】:Draw circle with lines in it using Java graphics使用 Java 图形绘制带有线条的圆圈
【发布时间】:2012-12-27 21:55:06
【问题描述】:

我有一个有趣的问题。使用Java图形,我想画一个圆圈,圆圈中有平行线,这些平行线之间有一些预先定义的间隙常数。圆具有已知的 x 和 y 位置以及半径。这些线应该从圆的中心开始,并且应该向外移动。例如,

我想最简单的方法是先画线以填满整个正方形,如下所示:

然后可能绘制 4 个多边形并用白色填充它们。 4个多边形标记如下:

如您所见,在这种情况下,多边形由左顶点 (x,y) 定义,宽度和高度边缘由圆的半径定义,然后是 (x+radius, y) 的弧+半径)。

需要反馈:

  1. 在Java中甚至可以绘制这样的多边形吗?
  2. 这个逻辑有意义吗?你觉得这更容易吗?
  3. 另一种方法是确定构成圆的像素并使用这些像素绘制线条。但这对我来说似乎很乱。你同意吗?
  4. 您能想到另一种方法吗?

重要提示:请注意,虽然此解决方案具有垂直线,但应根据某个角度 theta 定义这些线。也就是说,它们可以倾斜(但都相互平行)。

如果有人可以提供实际绘制此图的代码,我将永远感激不尽!! :)

public void draw(Graphics g, int x, int y, int radius, int lineGap, int lineThickness, int theta) {
   //g = the graphics object
   //x,y = the top left coordinate of the square
   //radius = the radius of the circle, the width of the rectangle, the height of the rectangle
   //lineGap = the gap in between each of the lines
   //lineThickness = the thickness of the lines in pixels
   //theta = the angle that the lines should be at, relative to the y axis
}

【问题讨论】:

  • 我不认为多边形是要走的路。相反,使用一点数学(三角学)来找到每条线所需的高度,基于它到中心的半径
  • 所以你的意思是对于我知道我的线落在的所有 x 点,使用圆的方程确定 y 位置?
  • 画线时设置圆形剪辑。
  • 那将是另一个合理的解决方案。

标签: java geometry awt java-2d


【解决方案1】:

使用 ol'Pythagorean Thereom,这个简单的代数如下......

r 是圆的半径。
x 是一个变量,您将在圆中迭代,您可以通过知道的增量轻松计算出半径和间距。

知道每条线的高度(以及它们的 x 位置),将平行于圆心的垂直线居中不会是一个挑战(如果您的放置坐标像通常那样指定左上角,您将想把它放在y = circle_center - (line_length / 2)

另请注意,如果您确实通过左上角指定垂直线的坐标,则在计算 x 坐标时需要考虑它们的粗细。
这非常简单,使用圆圈建议的x值。
true_x = suggested_x - (line_width / 2)

请参阅其他更明智的处理斜线的答案

这个过程仍然是为了展示使用剪辑而不是找到每行的确切域/范围的敏感性(因为我在这上面浪费了很多时间)。

这就是我的乐趣结束的地方。

哎呀!将最后一个 m 替换为 'tan(theta)'

【讨论】:

  • 但是如果线可以倾斜怎么办。这条线并不总是垂直的,而是由某个角度 theta 定义的。
  • 想象两个相同的图,除了一个有斜线。两个图将具有相同数量的线和它们之间的相同区域(数学上。以像素为单位,事情很糟糕)。之前,您遍历线 y = 0(x 轴)并制作垂直线(x = 常数)。在这种情况下,您可以遍历 y = mx 线(其中渐变 m - tan(90 - 角度))。您的线将垂直于该准轴(因此呈角度)。我会尽快写出详尽的解释(对于那些可以更快地写出来的人来说,这是一次头脑风暴)
  • 在我制作图片时添加图片,希望它们能激发一些想法。
  • 即使我没有做出错误的假设,当您考虑线条的宽度时,您的“预先确定的间隙大小”也不会保持不变(目前的数学形式并不'不承认)。这是一个非常有趣的问题,很抱歉我无法提供更多帮助。如果您需要工作,最可取的方法是采用 Andrews 和 MapProgrammers 的方法,绘制有角度的线,然后剪裁它们。
  • “采取 Andrews 和 MapProgrammers 的方法” 这是“懒人的方法”,这就是我喜欢它的原因。 ;) +1 为您深入处理问题,尤其是图纸。快乐 500 代表。 :)
【解决方案2】:

简单的改变图形剪裁...

public class SimplePaint02 {

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

    public SimplePaint02() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int radius = Math.min(getWidth(), getHeight());
            int x = (getWidth() - radius) / 2;
            int y = (getHeight()- radius) / 2;

            BufferedImage buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = buffer.createGraphics();

            Ellipse2D circle = new Ellipse2D.Float(0, 0, radius, radius);
            Shape clip = g2d.getClip();
            g2d.setClip(circle);
            int gap = getWidth() / 10;
            g2d.setColor(Color.RED);
            for (int index = 0; index < 10; index++) {

                g2d.drawLine(index * gap, 0, index * gap, radius);

            }
            g2d.setClip(clip);
            g2d.setColor(Color.BLUE);
            g2d.draw(circle);
            g2d.dispose();
            g.drawImage(buffer, x, y, this);
        }

    }

}

更新

我应该指出,您永远不应该修改任何正在渲染到屏幕的图形上下文的剪辑,这会严重破坏屏幕渲染;)

更新 #2

显示使用AffinTransformation 支持旋转的示例...

public class CirlceDraw {

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

    public CirlceDraw() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int radius = Math.min(getWidth(), getHeight());
            int x = (getWidth() - radius) / 2;
            int y = (getHeight() - radius) / 2;

            BufferedImage buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = buffer.createGraphics();

            Ellipse2D circle = new Ellipse2D.Float(0, 0, radius, radius);
            Shape clip = g2d.getClip();
            g2d.setClip(circle);
            AffineTransform at = g2d.getTransform();
            g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(33), radius / 2, radius / 2));
            int gap = getWidth() / 10;
            g2d.setColor(Color.RED);
            for (int index = 0; index < 10; index++) {

                g2d.drawLine(index * gap, 0, index * gap, radius);

            }
            g2d.setTransform(at);
            g2d.setClip(clip);
            g2d.setColor(Color.BLUE);
            g2d.draw(circle);
            g2d.dispose();
            g.drawImage(buffer, x, y, this);
        }

    }

}

【讨论】:

  • @Andrew 添加AffineTransformation,您也不必担心轮换结果:D
  • 如果线条不是直的,而是在某个定义的 theta 处倾斜怎么办?
  • @codeeguy 简单,简单地将 AffineTransformation 应用于代码的行部分
  • "simple 对线条应用 AffineTransformation" (笑)不确定与变换有关的很多东西是否“简单”。我总是需要稍微调整一下。 ;) OTOH 也许OvalGradientPaint 代码可以给 OP 一个开始。当然,将所有连接的转换换成AffineTransform.getRotateInstance(theta,anchorX,anchorY) - 也许会很简单.. :)
  • @AndrewThompson 虽然我喜欢所有的数学理论,但如果它是在完成工作或玩得开心之间;) - 此外,Graphics2D 有据可查,使其他开发人员更容易遵循 - 相信我,我已经与足够多的开发人员一起工作,他们喜欢自己开发复杂的算法,这很棒,直到其他人必须维护它 - 恕我直言
【解决方案3】:

我会使用三角函数。

直线的x 由与原点(圆心)夹角的余弦值给出。所以,arccos(x) 会告诉你哪个是角度。

一旦有了角度,就可以使用 sinus sin 函数获得其最大高度。

当然,所有 java trig 函数都使用弧度(360 度 = 2*PI 弧度)。

【讨论】:

  • 对不起,我没有关注。您能否澄清并写更多细节。 1)你说“你的线的x”......什么“线”? 2)你说 arccos(x) 会给你。给我什么?什么角度?
  • 每条垂直线的所有点都具有相同的x(否则它们不会是垂直的)。与参考半径的角度(3 点钟方向,逆时针方向)
  • 但是并不是所有的行都是垂直的。请看问题。
猜你喜欢
  • 2014-02-20
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-30
相关资源
最近更新 更多