The angle of rotation of the object is wrong - java

I'm trying to rotate an object in java but i noticed that something is wrong.
When i rotate it of 180 degrees,i get a value of the angle of '90°',so in order to get an angle of 360 degrees i have to rotate it twice.
What's wrong?
0°,90°,180°
The code:
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (rotate == true) {
ship.increaseDegress();
}
ship.draw(g);
}
Ship.java
public void increaseDegress() {
rotationAngle += 10;
if(rotationAngle>360) {
rotationAngle = 0;
}
}
public void draw(Graphics g) {
this.g = g;
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = new AffineTransform();
Rectangle rect = this.getBounds();
at.rotate(Math.toRadians(rotationAngle), rect.getX() + rect.getWidth() / 2, rect.getY() + rect.getHeight() / 2);
g2.setColor(Color.BLUE);
g2.setTransform(at);
g2.draw(at.createTransformedShape(this));
}

So, let's take a quick look at your code...
public void draw(Graphics g) {
this.g = g;
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = new AffineTransform();
Rectangle rect = this.getBounds();
at.rotate(Math.toRadians(rotationAngle), rect.getX() + rect.getWidth() / 2, rect.getY() + rect.getHeight() / 2);
g2.setColor(Color.BLUE);
g2.setTransform(at);
g2.draw(at.createTransformedShape(this));
}
So,
First you create AffineTransform, nice
You rotate the transformer, also nice
You apply the transformer to the Graphics context ... okay, there's a problem here, but let's move on
You apply the transformer to the shape!
So, on a single draw pass, you will rotate the shape by rotationAngle * 2! So, when the angle is 10°, the shape will be rendered at 20°, when it's 20°, it will rendered at 40°!
Okay, but there's another problem. Transformations applied to a Graphics context are compounding, this means, based on the available code, each time you call draw, the Graphics context is been rotated by rotationAngle. So if rotationAngle is 10°
On pass #1, the shape will be rotated to 20°
On pass #2, the shape will be rotated to 30°
On pass #3, the shape will be rotated to 40°
... so on and so forth ...
So, what's the answer?
When ever I pass a Graphics context off to some other method, I first create a copy it, because I don't trust anybody!
Graphics gCopy = g.create();
shape.draw(gCopy);
gCopy.dispose();
This ensures that the state of the Graphics context is returned to the state it was before I called draw, that will get rid of the compounding transformation.
The other solution is, don't transform the Graphics context. If you're transforming the shape, what's the point?
public void draw(Graphics g) {
this.g = g;
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = new AffineTransform();
Rectangle rect = this.getBounds();
at.rotate(Math.toRadians(rotationAngle), rect.getX() + rect.getWidth() / 2, rect.getY() + rect.getHeight() / 2);
g2.setColor(Color.BLUE);
g2.draw(at.createTransformedShape(this));
}

Related

drawArc() rendering is inconsistent when the arc length changes

I need to draw an arc around a volume knob, the arc length represents the volume.
I tried with Graphics.drawArc() and Arc2D.Double, but the result is not good: the path of the arc is not exactly the same for different extent values.
public class ArcComponent extends JComponent
{
private ImageIcon knobImage = new ImageIcon(ArcComponent.class.getResource("Knob-w37.png"));
int arcLength = 220; // Degrees
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Paint knob image
knobImage.paintIcon(this, g2, 20, 20);
// Add arc
var arc = new Arc2D.Double(22, 22, 32, 32, 220 - arcLength, arcLength, Arc2D.OPEN);
g2.setColor(Color.CYAN);
g2.setStroke(new BasicStroke(2));
g2.draw(arc);
g2.dispose();
}
void shorter()
{
arcLength -= 5;
if (arcLength < 0)
{
arcLength = 260;
}
repaint();
}
void longer()
{
arcLength += 5;
if (arcLength > 260)
{
arcLength = 0;
}
repaint();
}
}
How could I ensure that the path of the arc is always the same?
EDIT: added knob image painting
A dirty trick: draw the complete circle and ovewrite the part that you don't need with a shape, same color of background.
Something like this:
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Shape circle=new Ellipse2D.Double(20, 20, 30, 30);
g2.setColor(Color.CYAN);
g2.setStroke(new BasicStroke(2f));
g2.draw(circle);
Shape arc=new Arc2D.Double(10,10,50,50,230,360-arcLength,Arc2D.PIE);
g2.setColor(getBackground());
g2.fill(arc);
g2.dispose();
}
Unfortunately this requires the arc to be drawn before any other thing in the same area, but you can probably deal with this.
EDIT: For the additional constraint, the inconsistent rendering is actually due to the stroke, so try creating a thick shape and fill it, example:
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
double thickness=8.0; //This replaces your stroke width
GeneralPath shape=new GeneralPath();
shape.append(new Arc2D.Double(20-thickness/2,20-thickness/2, 30+thickness, 30+thickness, 230, -arcLength, Arc2D.OPEN),false);
shape.append(new Arc2D.Double(20+thickness/2,20+thickness/2, 30-thickness, 30-thickness, 230-arcLength, arcLength, Arc2D.OPEN),true);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.CYAN);
g2.fill(shape);
g2.dispose();
}
Simply draw a full circle and clip on the arc shape (with some padding to ensure everything gets drawn).
Graphics2D g2 = (Graphics2D) g.create();
Ellipse2D circle = new Ellipse2D.Double(20, 20, 30, 30);
int d = 2;
Arc2D arc = new Arc2D.Double(20 - d, 20 - d, 30 + 2 * d, 30 + 2 * d, 230, -arcLength, Arc2D.PIE);
g2.setColor(Color.CYAN);
g2.setClip(arc);
g2.setStroke(new BasicStroke(2f));
g2.draw(circle);
knobImage.paintIcon(this, g, 20, 20);

Java Animation Rotation

I have very little experience with Java, and I am an amateur programmer. So mind my vocabulary.
I want to be able to stick a static rectangle on top of a rotating rectangle.
So far when I try to add another object it spins with the other image. I have tried setting the rotation to zero but that doesn't seem to work. I have also tried to create another class that draws components separately and added them to the frame using frame.add. I have also tried creating another part to the Draw class that has no effect on the GUI. Here is my current Draw class. Any help is appreciated.
class DrawRectangle extends JPanel {
#Override
public void paintComponent(Graphics g) {
int h = this.getHeight();
int w = this.getWidth();
Graphics2D g2 = (Graphics2D) g;
//draw background
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, w, h);
//draw roatiing rectangle
g2.setColor(Color.CYAN);
Rectangle rRec = new Rectangle(w / 4, h / 4, 2 * w / 4, 2 * h / 4);
double wr = rRec.getX() + rRec.getWidth() / 2;
double hr = rRec.getY() + rRec.getHeight() / 2;
g2.rotate(Math.toRadians(count), wr, hr);
g2.fill(rRec);
g2.fillRect(w / 3, h / 3, 2 * w / 3, 2 * h / 3);
}
public void paintComponent2(Graphics g) {
int h = this.getHeight();
int w = this.getWidth();
Graphics2D g2 = (Graphics2D) g;
}
}
So far when I try to add another object it spins with the other image.
Create a separate Graphics object to do the rotation so you don't affect the properties of the Graphics object passed into the painting method:
//Graphics2D g2 = (Graphics2D) g;
Graphics2D g2 = (Graphics2D)g.create();
// painting code
g2.dispose();
Move your g2.fill(rRec); BEFORE the rotate call, and it should work (I just tested it out).
This way, you will draw your static rectangle before the rotation, perform the rotation, THEN draw your second rectangle. Assuming your count variable is incremented somewhere, it should show the second rectangle being rotated.

Current Coordinate of bufferedImage Object in java

Is there anyway to find the current position of a buffered image on jpanel?
I draw an image on buffer, named it currentImage. Now I want to move it around a Panel by using affine transform.
To do translation by using mouse, I have to know the current position, new position and update the new position.
But I have trouble in getting the current position of the BufferedImage. There is no method in the IDE's suggestion working.
Can anyone give me an idea how to do this ?? Thanks!
EDIT
this is my draw and paintComponent method:
private void draw(){
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC);
int w = this.getWidth(); int h = this.getHeight();
if (currentImage == null || width != w || height != h){
width = w;
height = h;
currentImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
graphics = currentImage.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
drawClearAndGradedArea(graphics);
drawActualRunway(graphics, width, height, width, height);
drawLeftToRight(graphics);
drawRightToLeft(graphics);
drawCentralLine(graphics);
graphics.setComposite(ac);
}
}
paintComponent()
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.clearRect(0,0, this.getWidth(), this.getHeight());
RenderingHints rh = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(rh);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
/*
* main components on panel
*/
this.draw();
this.animation();
g2d.drawImage(currentImage, transform, this);
drawNote(g2d);
g2d.dispose();
}

Get position image after Rotation with AffineTransform

I use an AffineTransform class to transform my image and I need to have a position of image after translation and rotation. How to achieve that?
public void rotateImage(ImageObserver o, Graphics g, int x, int y) {
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.rotate(Math.toRadians(deegres),ramie1.getWidth()/2,0);
Graphics2D g2 =(Graphics2D) g;
g2.drawImage(image, at, null);
}

drawRenderedImage(image, AffineTransform). How do I get the width and height of renderedImage

I'm drawing a transparent rendered image on top of a background image which is then displayed on a JPanel.
I need to get the bounds of the rendered image after it has been scaled and rotated.
So that the next time I call repaint it can be with
the clip of the rendered image.
Any ideas? thanks for your help.
#Override public void paintComponent(java.awt.Graphics g)
{
if(g != null)
{
g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), null);
Graphics2D g2 = (Graphics2D)g.create();
double cx = sprite.getWidth() / 2.0;
double cy = sprite.getHeight() / 2.0;
AffineTransform at = AffineTransform.getTranslateInstance(xPos, yPos);
at.concatenate(AffineTransform.getScaleInstance(scale, scale));
at.rotate(theta, cx, cy);
g2.drawRenderedImage(sprite, at);
//get width and height of rendered image here?
g2.dispose();
}
Something like
Rectangle resizedBounds = at.createTransformedShape(sprite.getBounds()).getBounds();

Categories

Resources