I want to translate a rectangle 2D using a double x and double y. It seems that rectangle2D does not support the translate method. What is the appropriate method to use?
If you need it to remain a Rectangle2D, you might have to write your own custom method that just adds to the x and y.
You can also perform arbitrary transformations with an AffineTransform, but this will turn it into a generic Shape (since that transformation might make it no longer rectangular).
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
Shape transformed = at.createTransformedShape(rectangle);
You have to cast the old Graphics variable to Graphics2D which has double methods. Mostly double parameters are used.
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g.translate(3.0, 4.0);
Double rectangles are not available in Graphics2D (like in drawRect). They are available however for own programming as java.awt.geom.Rectangle2D.Double.
Related
I use NetBeans and the last version of JDK. For some reason there is no Graphics.draw() method, though java.awt.geom.Line2D and java.awt.Graphics2D are imported. How do I draw a Line2D.Double element?
Shape pLine;
private void playerDraw(){
Graphics g2 = getGraphics();
pLine = new Line2D.Double(px, py, Math.cos(angle)*10+px,Math.sin(angle)*10+py);
g2.drawRect(px-5, py-5, 10, 10);
g2.draw(pLine); //this doesn't compile(cannot find symbol)
}
Your main problem is that you're using a Graphics object as if it were a Graphics2D object, but it's not and as the Graphics class Java API entry will show you, the Graphics class does not have a draw method, while Graphics2D does. I think that you're missing a key line, something like:
Graphics g = getGraphics();
Graphics2D g2 = (Graphics2D) g; // the missing line
But having said that, you are using Graphics incorrectly as you should avoid getting it by calling getGraphics() on a Swing component since this gives you an unstable short-lived Graphics object whose use risks causing short-lived images or NullPointerExceptions, but rather you should do your drawing within the JComponent's paintComponent(Graphics g) method.
You missed to declare pLine variable in your Class:
Eg.
public class Example
{
public Line2D.Double pLine;
private void playerDraw(){
Graphics g2 = getGraphics();
pLine = new Line2D.Double(px, py,Math.cos(angle)*10+px,Math.sin(angle)*10+py);
g2.drawRect(px-5, py-5, 10, 10);
g2.draw(pLine); //this doesn't compile(cannot find symbol)
}
}
I want to be able to zoom in my project, and it is working perfectly with a combination of g.scale(x, x) and g.translate(x, y). However, I want something to not scale with everything else (a minimap).
Specifically, I am making a minimap that will show the whole screen and the units as 1x1 pixels.
for(Unit u : units) { //cycle through arraylist of units
u.drawUnit(g, selectedUnits.contains(u)); //draws the unit, scales perfectly
g.setColor(Color.blue);
g.fillOval(rnd((u.getX()/4)/scale), rnd((u.getY()/4)/scale), rnd(1 + 1/scale), rnd(1 + 1/scale));
//rnd() is just a shorter (int)Math.round()
//The minimap's dimensions are width/4 x height/4
}
So i'm wondering if I can do it an easier way because that makes it look really strange at certain scalings.
You can get/set the AffineTransform object associated with the Graphics2D object. This allows you to readily switch back and forth between two or more transforms without having to do the math through the Graphics2D object's scale/translate/rotate methods. For example:
//render something default transform
AffineTransform defaultTransform = g.getTransform();
AffineTransform newTransform = new AffineTransform(defaultTransform);
newTransform.setScale(xScale, yScale);
g.setTransform(newTransform);
//render something with the new transform
g.setTransform(oldTransform);
//render something with the original transform
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g; //
double r = 100; //the radius of the circle
//draw the circle
Ellipse2D.Double circle = new Ellipse2D.Double(0, 0, 2 * r, 2 * r);
g2.draw(circle);
This is part of a class within my program, my question lies in the
Graphics2D g2 = (Graphics2D)g;
Why must you include the "g" after the (Graphics2D), and what exactly does the "Graphics2D" Within the parenthesis mean, i am learning out of a book and neither of these were ever fully explained.
You are casting Graphics2D to the Graphics context g. Read more about casting here in Inheritance in the Casting section.
What this ultimately does is allot you use the available methods of Graphics2D with the Graphics context of the passed to the paintComponent method. Whitout the casting, you'd only be limited to the methods of the Graphics class
Graphics2D is a subclass of Graphics so by using Graphics2D you gain all the methods of Graphics while taking advantage of the methods in the Graphics2D class.
Side Notes
You shouldn't be override paint. Also if you are, you shouldn't be painting on top level containers like JApplet.
Instead paint on a JPanel or JComponent and override paintComponent instead of paint and call super.paintComponent. Then just add the JPanel to the parent container.
public DrawPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
}
}
See more at Custom Painting and Graphics2D
Yes, you must include the g.
When you enter your paint method you have an object g of type Graphics.
Then you are typecasting your Graphics object, g to a type of Graphics2D which is a type that extends Graphics.
You have to include the g so you have something to typecast. If you don't include object there you will get a compilation error because the statement isn't complete.
The reason you are typecasting g to a Graphics2D object is because you are telling the compiler, "This Graphics object is actually a Graphics2D object." that way you can perform functions that the Graphics2D Object has that the the Graphics object does not.
This stackoverflow answer explains casting variables in Java very well if you have more questions about that. And this stackoverflow answer explains why it is safe to cast from Graphics to Graphics2D
Is it possible to rotate the Rectangle object to a certain degree around it's axis? Is it as easy as Rectangle rect = new Rectangle(x,y,w,h,r)?
If it is not possible to rotate the object, what would be a way I could get similar results?
Edit: for clarity here is my dilemma, I have images that rotate but when they colide with other images the collisions only work at 90 and 180 degree rotations because their hit box Rectangle objects don't rotate.
Edit: for clarity here is my dilemma, I have images that rotate but when they colide with other images the collisions only work at 90 and 180 degree rotations because their hit box Rectangle objects don't rotate.
You can rotate a Shape-derived object, such as a Rectangle2D by using the AffineTransform method, createTransformedShape(...).
Rectangle2D myRect = new Rectangle2D.Double(100, 100, 200, 200);
AffineTransform at = AffineTransform.getRotateInstance(Math.PI / 4, 150, 150);
Shape rotatedRect = at.createTransformedShape(myRect);
Note: code not compiled nor tested.
To rotate the rectangle, you give the graphics context an AffineTransform for rotation. Here's an example:
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
AffineTransform oldTransform = g2d.getTransform();
g2d.setTransform(AffineTransform.getRotateInstance(radians);
g2d.draw(rectangle);
g2d.setTransform(oldTransform);
}
You can also use g2d.rotate(radians) for rotation.
Note that the angle must be in radians. To convert degrees into radians, use degrees * (Math.PI/180) for the angle.
There's also another way to do this (besides createTransformedShape) which creates fewer temporary objects, if that's desirable.
Instead of keeping a Rectangle2D for the bounding box, you can keep a Path2D and then do the transform in place, using Path2D.transform(AffineTransform):
import java.awt.geom.*;
public class Example {
private final Path2D hitBox;
public Example(Rectangle2D initialHitBox) {
this.hitBox = new Path2D.Double(initialHitBox);
}
public void transform(AffineTransform tx) {
path.transform(tx); // In-place transformation.
}
// ...
}
This is very similar to what AffineTransform actually does under the hood.
When I try and apply a rotation to the current g2d object, it doesn't rotate it, it renders it in the same place (in my context on top of the other). From what I understand of the rotate method, it applies a transformation to the current graphics context, transforming the pixels of any rendering that comes after it (this might be where I'm going wrong). Here's the code in question:
#Override
public void paint(final Graphics graphics) {
super.paint(graphics);
final Graphics2D g2d = (Graphics2D) graphics;
....
....
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(SMALL_LINE_THICKNESS));
if (isLattice1Drawn) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1));
// lattice1 and lattice2 are Polygon objects
g2d.draw(lattice1);
// This fades in the second Polygon over the first
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
// This line should rotate it, but doesn't
g2d.rotate(Math.toRadians(210));
g2d.draw(lattice2);
.....
Thanks, Mike
Edit 1
As a suggestion from Jeff, I tried having just the rotation and drawing in paint, leaving me with the following code:
#Override
public void paint(final Graphics graphics) {
super.paint(graphics);
final Graphics2D g2d = (Graphics2D) graphics;
g2d.rotate(Math.toRadians(210));
g2d.draw(lattice2);
return;
// Rest of paint .................
Unfortunately this did not help, any other suggestions would be most welcome.
Edit 2:
When I don't call rotate, the polygon is rendered, however when I do nothing happens. Can anyone explain this?
What I understand from Edit 2 is: the rotation actually works. However, since rotation is around origin the rotated coordinates of the polygon ends up outside of the visible area. You can test this by rotating smaller degrees.
Then, if the desired operation is to rotate a polygon around its center of mass, use the following Graphics2D method instead:
void rotate(double theta, double x, double y)