Using "Affine Transformation" I can rotate imageA easily. As well, imageA will move along with imageB. However, I cannot seem to find a way to move imageA back to its original position after I have rotated it.
(I have done some research on some sites and apparently the best method is to move the image back to its original position so that it looks like its rotating from an anchor point.)
Heres my code so far:
public void paintComponent(Graphics g) {
super.paintComponent(g);
AffineTransform af = new AffineTransform();
Graphics2D g2d = (Graphics2D) g;
af.translate(imageBx, imageBy); // moves ImageA to imageb's position
af.rotate(Math.toRadians(angle), imageB.getHeight(this) / 2, imageB.getWidth(this) / 2);
g2d.drawImage(imageA, af, null);
g2d.drawImage(imageB, imageBx, imageBy, null);
}
If anyone can help me move imageA back to its original position (which is right on imageB) that would extremely helpful!
I looked that over, but the code rotates the entire panel; I just want to rotate one Image on a fixed rotate point.
Two things may help guide your understanding:
The example cited uses rotate(double theta); it is preceeded by a translation to the origin and succeeded by a translation the panel's center. Note that the operations are performed in the apparent reverse of the declared order. Your example (may have meant to) invoke rotate(double theta, double anchorx, double anchory). The two effect the same result, the latter being a convenient alternative to the former.
This example contrasts how one can transform the graphics context (g2d) or the image itself. Your example invokes drawImage(Image img, AffineTransform xform, ImageObserver obs), which concatenates xform to the existing graphics transform; this affects all subsequent drawing. It may be easier to keep them separate.
Related
I have a rather pressing question in regards to Swing, which I haven't touched for many years.
I have a code that allows the user to draw different rectangles on the pdf document (contained within JPanel). I draw them, move them, resize them, select them, and even write text on them. What I can't do is to keep them consistent when I zoom the document. As the document gets bigger, the rectangles I've drawn stay at the same position and the same size.
I was wondering if there's a relatively easy logic to track the zooming level and, most importantly, update the rectangles accordingly. I can retrieve zoom factor, it's a float, but, unfortunately, I'm using Rectangle object, which uses int for x, y, height, and width. It will be a hassle to convert it to Rectangle.Float, and I wanted to save it for a last resort.
I've tried to use AffineTransform, but I'm not quite familiar with it, for some reason I'm getting the wrong coordinates for y. Can anyone explain to me:
What's the best way to control the Rectangle object, as the pdf document gets zoomed in and out?
If AffineTransform is the best way, how should I handle it (maybe there's a link to a good explanation, if so - I couldn't find it)?
This is the only issue I've been struggling with and it's getting a bit frustrating now.
To scale using an AffineTransform:
Get the transform T of the Graphics object G
Create an AffineTransform object A
Set the scale of A
Set the transform of the G to A
Draw the shapes
Set the transform of G back to T
Translated into code - assuming scale is the value to scale by:
#Override
protected void paintComponent(Graphics gr){
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
AffineTransform prevTransform = g.getTransform();
AffineTransform at = new AffineTransform(prevTransform);
at.scale(scale, scale);
g.setTransform(at);
g.drawRect(...);
g.setTransform(prevTransform);
}
The Java API doesn't really explain this very well and I'm still unsure.
What is the difference between these two Graphics2d overloaded method calls?
public abstract void rotate(double theta)
and
public abstract void rotate(double theta,
double x,
double y)
The Java Doc is here:
http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#translate%28int,%20int%29
What I got from the documentation, was that the second rotate method translates the graphics object, rotates it, and translates it back. My confusion is about where drawing graphics fits in if it is already translated back to the previous origin.
If the graphics is rotated, can I go off the previous coordinate system (with the origin at (0,0)) and have everything end up where I'd expect?
My goal is to rotate the graphics around the center of a image (thus the translation), and then rotate and redraw the image. After that, I'd like to reset the graphics back to normal (or simply discard that version of graphics?).
Thanks in advance for any help.
If I remember right, Graphics2D#rotate(double) rotates around the top/left corner of the Graphics context (based on it's current transformation), where as Graphics2D#rotate(double, double, double) allows you to define the anchor point around which the Graphics context will be rotated. Sometimes, you just have to give it a try
I am doing a project in which I need to print the label/description of the line (drawn using graphics) with respect to orientation of the line.
Does anyone know how to do it?
Look to the Graphics2D methods such as rotate(), scale() & translate() - as well as the more general translate(AffineTransform) method.
See Transforming Shapes, Text, and Images in the Java tutorial for more details and working examples, especially of using an AffineTransform (which can concatenate scale, rotate, transform & shear operations).
You do not mention how you obtain the Graphics object. The Graphics object passed to Swing components in paintComponent(Graphics) will generally be a Graphics2D instance, and can be cast to one. To get a Graphics2D instance from a BufferedImage, call createGraphics().
Make a class called "Labelled line" and make it something like this
class LabeledLine {
private int x1, y1, x2, y2;
private String label;
public void drawOn(Graphics g) {
// need more features? thickness, etc? add it
g.drawLine(x1,y1,x2,y2);
// compute size of text, position of text, angle of text
// draw that text
}
}
A quick google for drawing angled text gave me a couple results, so that should be easy to do.
I've create a SWING component JImageEditor which simply displays a picture. The idea is to add more functionality to the component further down the road.
One functionality which I've already implemented is zooming. Right now, this part is taken care of in the paintComponent() method. However, somehow I suspect that this might be a bad idea as this means the image will be scaled from the original size to the current "zoom size" each and every time paintComponent() is invoked. The paintComponent code goes as follows :
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
int w = getWidth();
int h = getHeight();
double imageWidth = scale * image.getWidth();
double imageHeight = scale * image.getHeight();
double x = (w - imageWidth) / 2;
double y = (h - imageHeight) / 2;
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
}
Now, what I though of as an alternative was to keep two instances of BufferedImage where one is the original and one is the current "view". That way I could handle the actual zooming/scaling whenever the setScale() method is invoked, instead of scaling in paintComponent(). However, the drawback is that i need to keep two instances of BufferedImage which will lead to higher memory consumption depending on the image size. It is, of course, impossible to predict how large images any given user will open using the component.
What I'm looking for is either a thumbs up if I am on the right track with my work, or thumbs down If it's bad design and some other solution should be considered. I appreciate all input, and will reward all answers which enlightens me :-)
I'd say put a timing section in your paintComponent to measure how long it takes. Get your base measure from what you have now. Then implement the optimized method with the extra BufferedImage. Compare the measurements and pick the one that is smaller. I have a feeling your intuition is correct that doing the affine transform every paint cycle is slow, and by creating a double buffer for the scaled image and the source will be faster. Although I can't find any thing out there that confirms or denies this, and it could be affected by hardware acceleration.
If you extracted that section of code into a ZoomableBufferedImage class you could easily turn on or off the optimized/unoptimized versions. The ZoomableBufferedImage would hold a reference to the source image, and contain a extra buffered image that it can keep the scaled version in. As you zoom in/out the ZoomableBufferedImage draws to the buffer or not based on its settings, then in it's paint method it can draw either from the buffer or by applying the AffineTransform to the source and drawing that based on it's settings.
Are there any in-built methods in the Java API which would allow me to resize a polygon?
Would it be quite a simple task to write my own method, or are there any others already made?
No, nothing built in, altho, when you draw the polygon, you can draw the polygon with a transformation matrix applied which could scale the polygon for you. (or rotate, skew, etc, etc).
see
Graphics2D.setTransform(transform);
Lets assume you are drawing the polygon in a JPanel, and you have overridden the paintComponent method of JPanel. Cast the Graphics object to a Graphics2D object, and use transforms to scale it as appropriate:
public void paintComponent(Graphic g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform saveTransform = g2d.getTransform();
try {
AffineTransform scaleMatrix = new AffineTransform();
scaleMatrix.scale(1.5, 1.5);
//or whatever you want
g2d.setTransform(scaleMatrix);
g2d.drawPolygon(myPolygon);
} finally {
g2d.setTransform(saveTransform);
}
}
Chances are you can set up the transformation matrix elsewhere (once) instead of each time in the paintComponent method, but i did here to show how to do it.
Also note, that this will move the polygon, you would probably want apply this to the transform:
add a translate to move the polygon to the origin
add a scale
add a translate to move the polygon back to the original position
in this way, the object doesn't move it just scales.
Yes, AffineTransform.createTransformedShape(Shape) will create a transformed copy of any Shape (which may be a Polygon or Path2D.)