繁体   English   中英

Java awt 围绕圆圈绘制元素

[英]Java awt draw elements around a circle

我目前正在写一个小游戏,我遇到了一个问题。 我需要在一个大圆圈的边缘画 64 个小圆圈。 所以我想要这样的东西:

64个圆圈围绕一个大圆圈排列

我已经尝试了很多东西,但它们没有奏效。 How can this be done in java, using the java.awt.Component#paint() method and the java.awt.Graphics class?

谢谢。

因此,您的基本问题归结为“根据给定角度在圆上找到一个点”

一个快速的谷歌会找到像Find the coordinates of a point on a circle 之类的资源,坦率地说,我是个白痴,所以我会缩小搜索范围以包括 Java,这会给我们类似如何计算使用 Java 的圆中点的坐标? - 甜的。

所以基本计算可能看起来像

double xPosy = Math.cos(rads) * radius);
double yPosy = Math.sin(rads) * radius);

现在,这解决了您问题的核心方面。 rest 归结为简单地绘制结果。 请参阅在 AWT 和 Swing执行自定义绘画和绘画作为起点和2D 图形,以更详细地了解 API。

现在,考虑到上述所有因素,您最终可能会得到一个类似于...的解决方案

在此处输入图像描述

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test {

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

    public Test() {
        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 TestPane extends JPanel {

        public TestPane() {
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int midX = getWidth() / 2;
            int midY = getHeight() / 2;
            Dimension size = new Dimension(4, 4);
            g2d.setColor(Color.BLACK);
            for (int index = 0; index < 64; index++) {
                double angle = (360d / 64d) * index;
                Point2D poc = getPointOnCircle(angle, 100 - 4);
                Rectangle2D box = new Rectangle2D.Double(midX + poc.getX() - 2, midY + poc.getY() - 2, size.width, size.height);
                g2d.draw(box);
            }
            g2d.dispose();
        }

        protected Point2D getPointOnCircle(double degress, double radius) {
            double rads = Math.toRadians(degress - 90); // 0 becomes the top

            return new Point2D.Double(Math.cos(rads) * radius, Math.sin(rads) * radius);
        }
    }
}

所以,现在,你应该意识到我的“正方形”是正方形,而不是像你的“菱形”形状。 这是你必须开始做一些工作的地方。

如果我正在解决这个问题,我可能会想创建一个自定义形状,或者对box应用 45 度变换并将其转换为 position 以渲染它或将整个结果旋转 45 度,但这带来了一个完整的包其他问题取决于你想用它做什么

这是一种方法(其中大部分是用于设置包含框架和面板的样板)。 它使用sine and cosine方法来计算unit圆的点。 然后通过首先乘以所需较大圆的radius然后通过添加center x,y偏移量将其在面板中居中来调整这些点。

它包含的唯一真正特别的东西是 1) 保证外圆之间的间距为它们的直径之一。 因此,如果圈数减少,则尺寸会增加。 这可以根据您的需要进行调整。 2) 我使用RenderingHints在视觉上平滑曲线。 最后 3) 我添加了一个带有任意限制的简单WheelListener ,这样您就可以在上下移动鼠标滚轮时看到变化。 这会修改NCIRCLES (不应该对常量做的事情),然后重新绘制面板。 它很容易被移除。

public class CircleBorder extends JPanel {

    JFrame frame = new JFrame("Circle Border");
    static int BIG_RADIUS = 200;
    static int NCIRCLES = 60;
    static int WIDTH = 500;
    static int HEIGHT = 500;

    public static void main(String[] args ) {
        SwingUtilities.invokeLater(()->new CircleBorder().start());
    }
    public void start() {
     addMouseWheelListener((we)-> {
           int rot = we.getWheelRotation();
           if (NCIRCLES < 70 && rot > 0 || NCIRCLES > 7 && rot < 0) {
               NCIRCLES += rot;
           }
              
           repaint();
       });
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.add(this);
       frame.pack();
       // center on screen
       frame.setLocationRelativeTo(null);
       frame.setVisible(true);
    }
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(WIDTH,HEIGHT);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        
        int centerX = WIDTH/2;
        int centerY = HEIGHT/2;
        
        double angleIncrement = 2*Math.PI/NCIRCLES;
        g2d.setColor(Color.RED);
        
        // the next two lines adjusts the little radius so that each
        // outer circle will be one diameter apart.
        int bigD = (int)(Math.PI*2*BIG_RADIUS);
        int littleRadius = bigD/(NCIRCLES*4);
        
        // compute the x and y coordinates of the center of the outer circles.
        // and iterate once around the circle based on the computed angle above
        // to draw the circumference.  The little radius is subtracted to ensure
        // the center of those circles lies on the generated outer circle.

        double angle = 0;
        for (int i = 0; i < NCIRCLES; i++) {
              int x = (int)(centerX + Math.cos(angle)*BIG_RADIUS) - littleRadius;
              int y = (int)(centerY + Math.sin(angle)*BIG_RADIUS) - littleRadius;
              g2d.fillOval(x,y,littleRadius*2,littleRadius*2);
              angle += angleIncrement;
        }
        
        g2d.dispose();
    }
}

感谢@MadProgrammer 的回答。 我将他的代码与@WJS 使用 RenderingHints 的建议和我自己的想法结合起来,以下代码对我有用。

package gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

/**
 * Thanks to <a
 * href=https://stackoverflow.com/users/992484/madprogrammer>@MadProgrammer</a>
 * on StackOverflow for the geometry part (<a
 * href=https://stackoverflow.com/questions/70398744/java-awt-draw-elements-around-a-circle>Source
 * code</a>)
 */
public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setExtendedState(Frame.MAXIMIZED_BOTH);
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JComponent {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return getParent().getSize();
        }

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

            Graphics2D g2d = (Graphics2D) g.create();
            //Thanks to @WJS for the idea
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            int midX = getWidth() / 2;
            int midY = getHeight() / 2;
            int min = Math.min(getHeight() / 2, getWidth() / 2);
            Dimension size = new Dimension(min / 20, min / 20);
            double minsize = Math.min(size.getHeight(), size.getWidth());
            double radius = min - minsize;

            g2d.setColor(Color.BLACK);
            for (int index = 0; index < 64; index++) {
                double angle = (360d / 64d) * index;
                double rads = Math.toRadians(angle - 90); // 0 becomes the top
                Point2D poc = new Point2D.Double(Math.cos(rads) * radius, Math.sin(rads) * radius);
                g2d.fillOval((int) (midX + poc.getX() - 2), (int) (midY + poc.getY() - 2), size.width, size.height);
            }
            g2d.dispose();
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM