【问题标题】:Java awt draw elements around a circleJava awt 围绕一个圆圈绘制元素
【发布时间】:2022-01-20 17:00:02
【问题描述】:

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

我已经尝试了很多东西,但都没有奏效。如何在 java 中使用 java.awt.Component#paint() 方法和 java.awt.Graphics 类来实现这一点?

谢谢。

【问题讨论】:

  • 如果你想用 Java 进行任何严肃的 2D 图形绘制,那么 Java 教程的2D Graphics Trail 是必读的。
  • 你试过只画一个空心圆吗?不要指望人们来这里给你代码。您需要付出一些努力,并且您的问题没有发布任何代码。
  • 如果您正在编写游戏,我建议您使用 Java 版本的 openGL 而不是 AWT。还是你只想要圆圈圈?

标签: java graphics geometry awt


【解决方案1】:

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

一个快速的谷歌会找到像Find the coordinates of a point on a circle这样的资源,现在,坦率地说,我是个白痴,所以我会缩小搜索范围以包括Java,这会给我们像How to calculate the coordinates of points in a circle using Java?这样的东西 - 甜蜜。

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

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

现在,这解决了您问题的核心方面。剩下的就是简单地绘制结果。请参阅 Performing Custom PaintingPainting in AWT and Swing 作为起点,并参阅 2D Graphics 以更详细地了解 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 度变换并平移它的位置以呈现它,或者只是将整个结果旋转 45 度,但是这会带来一大堆其他问题,具体取决于您想用它做什么

【讨论】:

    【解决方案2】:

    这是一种方法(其中大部分是用于设置包含框架和面板的样板)。它使用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. Then iterate once around the circle based on the
            // computed angle above to draw the circumference. The little
            // radius is subtracted to ensure those circles are
            // centered on the large circles circumference.
    
            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();
        }
    }
    
    

    【讨论】:

      【解决方案3】:

      感谢@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();
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-10-25
        • 1970-01-01
        • 2019-09-04
        • 2014-06-06
        • 2013-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-25
        相关资源
        最近更新 更多