I have used several java.awt.Rectangle, java.awt.Polygon, and java.awt.geom.Ellipse2D shapes together and I want to rotate them with eachother and I also want to have them keep their location on the JFrame. When I use g2D.rotate(Math.toRadians(rotation)), the shapes move on the JFrame and they are no longer close together. How can I make it so that all of the shapes keep their position relative to eachother and their position on the JFrame? Thank you in advance.
CodePudding user response:
If you want to be able to rotate the shapes together and keep their position on the JFrame I would recommend that you use the form of g2D.rotate that uses x and y coordinates to rotate with. You should make a standard x and y coordinate to draw each shapes position from so that when you use these standard x and y coordinates to rotate from all of the shapes will rotate together. It would probably look something like this:
// imports
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Container;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JComponent;
public class GraphicsRotate extends JComponent implements ActionListener {
// JFrame and Container
JFrame frame = new JFrame("Graphics Rotate");
Container container = frame.getContentPane();
public int standardX = 100;
public int standardY = 100;
public int rotation = 0;
public static void main(String[] args) {
GraphicsRotate graphicsRotate = new GraphicsRotate();
graphicsRotate.setup();
}
public void setup() {
container.setBackground(Color.BLACK);
container.add(this);
KeyListener kl = new KeyListener() {
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_LEFT) {
rotation -= 10;
repaint();
}
if (code == KeyEvent.VK_RIGHT) {
rotation = 10;
repaint();
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
};
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addKeyListener(kl);
frame.setFocusable(true);
frame.requestFocus();
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.GREEN);
g2.rotate(Math.toRadians(rotation), standardX, standardY);
Rectangle rect = new Rectangle(standardX 10, standardY 10, 5,
5);
Ellipse2D ellipse = new Ellipse2D.Double(standardX 13, standardY
5, 10, 10);
g2.fill(ellipse);
g2.fill(rect);
}
@Override
public void actionPerformed(ActionEvent e) {
}
}
This could be implemented on a much larger scale, and if you wanted the shapes to rotate around the center of the larger shape that you have made with them, then you could do the necessary calculations to figure out the center and do something like g2.rotate(Math.toRadians(rotation), standardX middleX, standardY middleY).
I hope that this answered your question.
CodePudding user response:
It's really important to remember, transformations are compounding. So you can't simply apply a new rotation to the Graphics
context for each object, instead, you need to reset the state between transformations
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 {
private List<Shape> shapes = new ArrayList<>(4);
private double angle = 0;
public TestPane() {
shapes.add(new Rectangle2D.Double(50, 50, 100, 100));
shapes.add(new Rectangle2D.Double(250, 50, 100, 100));
shapes.add(new Rectangle2D.Double(50, 250, 100, 100));
shapes.add(new Rectangle2D.Double(250, 250, 100, 100));
Timer timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
angle = 1;
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Shape shape : shapes) {
Graphics2D g2d = (Graphics2D) g.create();
Rectangle bounds = shape.getBounds();
int midx = bounds.x (bounds.width / 2);
int midy = bounds.y (bounds.height / 2);
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(angle), midx, midy));
g2d.draw(shape);
g2d.dispose();
}
}
}
}
You could also transform the shape directly, for example...
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Shape shape : shapes) {
Rectangle bounds = shape.getBounds();
int midx = bounds.x (bounds.width / 2);
int midy = bounds.y (bounds.height / 2);
Path2D.Double rotatedShape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(angle), midx, midy));
g2d.draw(rotatedShape);
}
g2d.dispose();
}