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:
I've already tried many things, but they didn't worked. How can this be done in java, using the java.awt.Component#paint() method and the java.awt.Graphics class?
Thanks.
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 Find the coordinates of a point on a circle , now, to be frank, I'm an idiot, so I'd narrow my search to include Java, which would give us something like How to calculate the coordinates of points in a circle using Java? - sweet.
So the basic calculation might look something like
double xPosy = Math.cos(rads) * radius);
double yPosy = Math.sin(rads) * radius);
Now, this solves the core aspect of your problem. The rest comes down to simply painting the results. See Performing Custom Painting and Painting in AWT and Swing as a starting point and 2D Graphics for a more detailed look into the API.
Now, taking all of the above, you might end up with a solution looking something like...
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
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();
}
}
Thanks to @MadProgrammer for his answer. I combined his code with the suggestion to use RenderingHints by @WJS and my own ideas and the following code worked for me.
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();
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.