DaniWeb IT Discussion Community

DaniWeb IT Discussion Community (http://www.daniweb.com/forums/index.php)
-   Java (http://www.daniweb.com/forums/forum9.html)
-   -   Trying to draw text at an angle (http://www.daniweb.com/forums/thread141804.html)

VernonDozier Aug 23rd, 2008 12:31 pm
Re: Trying to draw text at an angle
 
Quote:

Originally Posted by sciwizeh (Post 676370)
yes, the blurry text is because of int rounding error. a better way to do it would be affinetransform, but i haven't used it much, and the sun tutorial confused me a bit, i think that this may also help.

Great. Thank you. I will check those links out.

Ezzaral Aug 25th, 2008 1:57 pm
Re: Trying to draw text at an angle
 
You have made this a bit more complex than need be. For simple transformations, the Graphics2D methods rotate() and translate() will suffice (they additively modify the current AffineTransform of the graphics context) without any need to obtain or work with an AffineTransform object directly.

I wrote this small example that might help
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TextExample extends JFrame {

    GraphicPanel gPanel;

    public TextExample() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        gPanel = new GraphicPanel();
        getContentPane().add(gPanel, BorderLayout.CENTER);
        setBounds(100, 100, 200, 200);
        setVisible(true);
    }

    class GraphicPanel extends JPanel {
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D)g;
            g2.setBackground(Color.BLACK);
            g2.clearRect(0, 0, getWidth(), getHeight());
            g2.setColor(Color.WHITE);
            String msg = "Hi Vernon";
            FontMetrics metrics = g2.getFontMetrics();
            // translate context to center of panel
            // the point 0,0 now resides here
            g2.translate(getWidth() / 2, getHeight() / 2);
            g2.drawString(msg, -metrics.stringWidth(msg) / 2,
              metrics.getMaxAscent() / 2);
            // rotate 45 deg
            g2.rotate(-Math.PI / 4);
            g2.setColor(Color.YELLOW);
            g2.drawString(msg, -metrics.stringWidth(msg) / 2,
              metrics.getMaxAscent() / 2);
            // rotate 45 deg again - these transforms are additive
            g2.rotate(-Math.PI / 4);
            g2.setColor(Color.ORANGE);
            g2.drawString(msg, -metrics.stringWidth(msg) / 2,
              metrics.getMaxAscent() / 2);
        }
    }

    public static void main(String... args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TextExample();
            }
        });
    }
}

VernonDozier Aug 25th, 2008 9:01 pm
Re: Trying to draw text at an angle
 
Quote:

Originally Posted by Ezzaral (Post 677790)
You have made this a bit more complex than need be. For simple transformations, the Graphics2D methods rotate() and translate() will suffice (they additively modify the current AffineTransform of the graphics context) without any need to obtain or work with an AffineTransform object directly.

I wrote this small example that might help
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TextExample extends JFrame {

    GraphicPanel gPanel;

    public TextExample() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        gPanel = new GraphicPanel();
        getContentPane().add(gPanel, BorderLayout.CENTER);
        setBounds(100, 100, 200, 200);
        setVisible(true);
    }

    class GraphicPanel extends JPanel {
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D)g;
            g2.setBackground(Color.BLACK);
            g2.clearRect(0, 0, getWidth(), getHeight());
            g2.setColor(Color.WHITE);
            String msg = "Hi Vernon";
            FontMetrics metrics = g2.getFontMetrics();
            // translate context to center of panel
            // the point 0,0 now resides here
            g2.translate(getWidth() / 2, getHeight() / 2);
            g2.drawString(msg, -metrics.stringWidth(msg) / 2,
              metrics.getMaxAscent() / 2);
            // rotate 45 deg
            g2.rotate(-Math.PI / 4);
            g2.setColor(Color.YELLOW);
            g2.drawString(msg, -metrics.stringWidth(msg) / 2,
              metrics.getMaxAscent() / 2);
            // rotate 45 deg again - these transforms are additive
            g2.rotate(-Math.PI / 4);
            g2.setColor(Color.ORANGE);
            g2.drawString(msg, -metrics.stringWidth(msg) / 2,
              metrics.getMaxAscent() / 2);
        }
    }

    public static void main(String... args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TextExample();
            }
        });
    }
}

Thank you. I will try that out. I sort of stumbled onto the knowledge that it wasn't nearly as difficult as I thought when I spent about two and a half hours going through the Java tutorial. I kept deleting things from their code till I got to the bare minimum, then finally realized that the bare minimum was only a couple of lines. But it took a while for me to keep deleting stuff from Sun's super cool example till I got to the part of it that I cared about. Thanks.

Ezzaral Aug 26th, 2008 12:42 pm
Re: Trying to draw text at an angle
 
Yes, some of their examples can be more complex than need be and obscure the usage they are trying to demonstrate. :(

One more thing worth noting with respect to AffineTransforms is that they represent the current state of the coordinate system within the graphics context. Since you can store references to as many AffineTransforms as you want, you can effectively "save" any state (translation, orientation, scale, and sheer) you wish and restore it at will. If you have many objects that render themselves independently, each can maintain it's own transform that it uses for rendering. When that object's turn to be rendered comes, you can save the current transform of your graphics context, apply that object's transform, render it, and then restore the original transform.

Here's an example of that:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TransformExample extends JFrame {

    GraphicPanel gPanel;

    public TransformExample() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        gPanel = new GraphicPanel();
        getContentPane().add(gPanel);
        setBounds(100, 100, 200, 200);
        setVisible(true);
    }

    class GraphicPanel extends JPanel {
        TextLabel label1;
        TextLabel label2;
        TextLabel label3;

        protected void paintComponent(Graphics g) {
            if (label1 == null) {
                // lazy initilization so I have dimensions to work with
                FontMetrics fm = g.getFontMetrics();
                int width = getWidth();
                int height = getHeight();
               
                label1 = new TextLabel("Hi Vernon", Color.YELLOW,
                  20, height/2, -Math.PI/2);
               
                String labelText = "I'm over here";
                int labelLen = fm.stringWidth(labelText);
                label2 = new TextLabel(labelText, Color.CYAN,
                  width-labelLen, height/2, -Math.PI/4);
               
                labelText = "Standing on my head";
                labelLen = fm.stringWidth(labelText);
                label3 = new TextLabel(labelText, Color.ORANGE,
                  (width+labelLen)/2, height-20, Math.PI);
            }
           
            Graphics2D g2 = (Graphics2D)g;
            g2.setBackground(Color.BLACK);
            g2.clearRect(0, 0, getWidth(), getHeight());
           
            label1.draw(g2);
            label2.draw(g2);
            label3.draw(g2);
        }
    }
   
    class TextLabel {
        private AffineTransform transform;
        private Point location;
        private double rotation;
        private String text;
        private Color color;
       
        public TextLabel(String text, Color color, int x, int y,
          double rotation) {

            this.text = text;
            this.color = color;
            this.location = new Point(x, y);
            this.rotation = rotation;
            transform = new AffineTransform();
            transform.translate(location.x, location.y);
            transform.rotate(rotation);
        }
       
        public void draw(Graphics2D g){
            // save current color and transform
            AffineTransform currentTransform = g.getTransform();
            Color currentColor = g.getColor();

            // apply my own color and transform
            g.setTransform(transform);
            g.setColor(color);
            // this will be left aligned at the origin
            // a parameter for left/center/right alignment
            // could be added easily
            g.drawString(text, 0, 0);
           
            // restore the original state
            g.setColor(currentColor);
            g.setTransform(currentTransform);
        }
    }

    public static void main(String... args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TransformExample();
            }
        });
    }
}

VernonDozier Aug 26th, 2008 9:28 pm
Re: Trying to draw text at an angle
 
Quote:

Originally Posted by Ezzaral (Post 678460)
Yes, some of their examples can be more complex than need be and obscure the usage they are trying to demonstrate. :(

One more thing worth noting with respect to AffineTransforms is that they represent the current state of the coordinate system within the graphics context. Since you can store references to as many AffineTransforms as you want, you can effectively "save" any state (translation, orientation, scale, and sheer) you wish and restore it at will. If you have many objects that render themselves independently, each can maintain it's own transform that it uses for rendering. When that object's turn to be rendered comes, you can save the current transform of your graphics context, apply that object's transform, render it, and then restore the original transform.

Here's an example of that:


Perfect! My project is a type of ColorForms/CAD program where the user can draw pentagons, ovals, rectangles, text, etc., on the screen and they can all be different sizes and different angles and I'm going to try to give the option where a user can spin one shape and/or piece of text and leave the others the same or spin them all or spin some but not others or change one or more sizes, etc. Potentially you could have hundreds or even thousands of objects on the screen, all with different sizes and different angles. To rotate a polygon, I was doing the math and changing the polygon coordinates myself, but the idea of keeping the same points and having a different AffineTransformation for each of them is very appealing and seems like less calculation for me. Plus the goal is to be able to tilt images too eventually. This method has fantastic potential compared to my earlier approach. Thanks again. As usual, you gave great sample code.


All times are GMT -4. The time now is 10:10 am.

Forum system based on vBulletin Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
©2003 - 2009 DaniWeb® LLC