Search code examples
javaswinggraphics2d

How to setup desired Coordinates in Graphics2D


I want to set up a mathematical (where y grows up not down) coordinate space from (-1, -1) to (+1, +1) and have it fit in the window regardless of the window size.

I am using an anonymous JComponent subclass in Java SE 7 and casting the incoming Graphics in paintComponent to Graphics2D and then drawing on the Graphics2D

But the Graphics2D is set to a computer coordinate space that changes with the size of the window. How to get it to rescale according to window size and have Y go upwards? The following program should show a dark square in upper right quadrant.

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JComponent;
import javax.swing.JFrame;

public class G {
  public static void main (String [] args) {
    JFrame frame = new JFrame(G.class.getCanonicalName());
    frame.setUndecorated(true);
    JComponent component = new JComponent() {
      private static final long serialVersionUID = 1L;
      @Override
      protected void paintComponent (Graphics g) {
        super.paintComponent(g);
        paint2D((Graphics2D)g);
      }
      protected void paint2D (Graphics2D g2) {
        g2.draw(new Rectangle2D.Double(0.1, 0.1, 0.9, 0.9));
      }
    };
    frame.add(component);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 400);
    frame.setVisible(true);
  }
}

Solution

  • Setup the coordinate system how you want, using transform() and translate(). So:

    1. you want the origin to be at (0, height); bottom left.
    2. then you want to flip the Y axis.

    Example code:

    AffineTransform tform = AffineTransform.getTranslateInstance( 0, height);
    tform.scale( 1, -1);
    g2.setTransform( tform);
    

    [My edited version]:

    public static void main (String [] args) {
        JFrame frame = new JFrame( G2dTransform_Question.class.getCanonicalName());
        JComponent component = new JComponent() {
            private static final long serialVersionUID = 1L;
            @Override
            protected void paintComponent (Graphics g) {
                super.paintComponent(g);
                paint2D((Graphics2D)g);
            }
            protected void paint2D (Graphics2D g2) {
                AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
                tform.scale( getWidth(), -getHeight());    // NOTE -- to make 1.0 'full width'.
                g2.setTransform( tform);
    
                g2.setColor( Color.BLUE);  // NOTE -- so we can *see* something.
                g2.fill( new Rectangle2D.Double(0.1, 0.1, 0.8, 0.8));  // NOTE -- 'fill' works better than 'draw'.
            }
        };
    
        frame.setLayout( new BorderLayout());    // NOTE -- make the component size to frame.
        frame.add( component, BorderLayout.CENTER);
    
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        frame.setVisible(true);
    }
    

    [Hovercraft's version]: Thanks Hover!

    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.geom.AffineTransform;
    import java.awt.geom.Rectangle2D;
    
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    
    public class G {
      public static final int PREF_W = 400;
      public static final int PREF_H = PREF_W;
    
    public static void main (String [] args) {
        JFrame frame = new JFrame(G.class.getCanonicalName());
        frame.setUndecorated(true);
        JComponent component = new JComponent() {
          private static final long serialVersionUID = 1L;
          @Override
          protected void paintComponent (Graphics g) {
            super.paintComponent(g);
            AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
            tform.scale( 1, -1);
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setTransform( tform);
            paint2D(g2);
            g2.dispose();
          }
          protected void paint2D (Graphics2D g2) {
            g2.draw(new Rectangle2D.Double(10, 10, 20, 30));
          }
    
          @Override
          public Dimension getPreferredSize() {
             return new Dimension(PREF_W, PREF_H);
          }
        };
        frame.add(component);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
      }
    }