Home > database >  Java awt draw elements around a circle
Java awt draw elements around a circle

Time:12-18

I'm currently writing a little game and I came over a problem. I need to draw 64 small circles at the border of a big circle. So I want something like this:

64 circles arranged around a big circle

How can this be done in java, using the java.awt.Component#paint() method and the java.awt.Graphics class?

Thanks.

CodePudding user response:

So, your basic problem comes down to "find a point on a circle based on a given angle"

A quick google will find resources like enter image description here

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);
        }
    }
}

So, about now, you should realise that my "squares" are, well, square, not "dimond" shaped like yours. This is where you're going to have to start doing some work.

If I was approaching this problem I might be tempted, to create a custom shape or, apply a 45 degree transformation to the box and the translate it's position to render it or just rotate the whole result by 45 degrees, but this brings a whole bag of other issues depending on what you want to do with it

CodePudding user response:

Here is one way to do it (most of this is boiler plate for setting up the containing frame and panel). It uses the sine and cosine methods to compute the points of a unit circle. These points are then adjusted by first multiplying by the radius of the desired larger circle and then centering it in the panel by adding the center x,y offsets.

The only really special things it contains is 1) that the outer circles are guaranteed to be spaced apart by a distance of one of their diameters. So if the number of circles decreases the size increases. This can be adjusted as you see fit. 2) I used RenderingHints to visually smooth out the curves. And finally 3) I added a simple WheelListener with arbitrary limits so you could see the changes when moving the mouse wheel up or down. This modifies NCIRCLES (something one should not do with constants) and then repaints the panel. It is easily removed.

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

  • Related