# AffineTransform help

• 12-18-2008, 04:01 PM
tones
AffineTransform help
Hi Folks

Am new to java and this forum, and whilst I try to search and research before turning to forums, I am really struggling with AffineTransform.

I need to display a polyline whose values are supplied in a 'real world' coordinate system, eg:

Code:

```int[] xPoints = {126589, 124587, 122369}; int[] yPoints = {632547, 654235, 687954}; g2.drawPolyline(xPoints, yPoints, 2);```
At the moment I have a class that transforms these coordinates into pixel coordinates before sending to the draw method. The problem with my custom class is it uses math to work out the swing container width/height, calcualte the 'real world' height, and refactor based on these values. This seems overly clunky, and not very extensible if I wanted to display other coordinates outwith my hardcoded transform class.

The additional problem is the y coordinates origin is in the south rather than the computers north, so we have to do a bit of additional math here.

Is AffineTransformation a possible friend, and would anyone be able to provide a small snipet based on the above example? Most of the Affine examples I have looked at demo scaling images or flipping text.

Best wishes, tones
• 12-18-2008, 05:50 PM
Supamagier
So your problem is that the y coordinates go from up --> down instead of down --> up. If you want them to start in the middle of your frame/applet/anything, just use
Code:

`newY = -y + height/2;`
Or isn't that what your mean?
• 12-18-2008, 06:25 PM
tones
Quote:

Originally Posted by Supamagier
So your problem is that the y coordinates go from up --> down instead of down --> up. If you want them to start in the middle of your frame/applet/anything, just use
Code:

`newY = -y + height/2;`
Or isn't that what your mean?

Hi Supermaiger, thanks for replying.

I guess my problem has a few issues, some of which need solving by math, and others which require java knowledge.

I need to read a text file that has (british national grid) coordinates, so an example line such as

Code:

```int[] xPoints = {000000,100000, 200000, 300000}; int[] yPoints = {000000,100000, 200000, 300000};```
in the real world would go from bottom left to top right.

If I had a 300x300 px JPanel, then it would be easy enough to just divide each real world coordinate by 1000, and then do something like (jpanelHeight-(Y/1000).

However, problems arise if the window resizes, or we try to draw a line

Code:

```int[] xPoints = {400000, 500000, 600000, 700000}; int[] yPoints = {400000, 500000, 700000, 700000};```
As it now doesn't fit into my hardcoded transformation method, the origin of the new polyline is outside of the canvas.

I was hoping that Affine Transformation would help me so that I can just keep to parsing the real world coordinates and let java work out the canvas size, get the real world coordinates and work out where to put it.

Essentially what I would like is that if the window resizes, the graphics all move and repaint so that the line (in our example) stays bottom left to top right. The other requirement is that if I load a second poly outwith the original bounds, it repaints both graphics so that they fit in to the canvas still (i.e scaling).
• 12-18-2008, 06:59 PM
xcallmejudasx
You can fix the issue of window resize by disabling resize. If this is just an applet running through FF or IE or something then I don't think you have that option.

I believe there is a class dealing with the OS that will let you pull the windowLength, windowWidth variables to use but I'm not positive.
• 12-19-2008, 08:24 AM
hardwired
Code:

```import java.awt.*; import java.awt.event.*; import java.awt.font.*; import java.awt.geom.*; import java.util.Arrays; import javax.swing.*; public class ScaleToView extends JPanel {     int[] xPoints = { 400, 500 };     int[] yPoints = { 600, 400 };     final int HPAD = 30;     final int PAD  = 20;     final int SPAD = 2;     final int TICK = 3;     int[] scaledX;     int[] scaledY;     AffineTransform xform;     Point origin;     protected void paintComponent(Graphics g) {         super.paintComponent(g);         Graphics2D g2 = (Graphics2D)g;         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,                             RenderingHints.VALUE_ANTIALIAS_ON);         int w = getWidth();         int h = getHeight();         origin = new Point(HPAD, h-PAD);         if(xform == null) {             initTransform();         }         Color flatBlack = g2.getColor();         Color gridColor = new Color(200,230,240);         // Draw axes.         g2.draw(new Line2D.Double(HPAD, PAD, HPAD, h-PAD));         g2.draw(new Line2D.Double(HPAD, h-PAD, w-PAD, h-PAD));         // Draw axis tick marks and grid lines.         int[] maxVals = getMaxValues();         // Abcissa tick marks and vertical grid lines.         for(int i = 0; i <= maxVals[0]; i += 100) {             Point2D.Double p = new Point2D.Double(i, 0);             Point2D.Double xp = new Point2D.Double();             xform.transform(p, xp);             g2.setPaint(flatBlack);             g2.draw(new Line2D.Double(xp.x, xp.y, xp.x, xp.y+TICK));             if(i > 0) {  // vertical grid lines                 g2.setPaint(gridColor);                 g2.draw(new Line2D.Double(xp.x, PAD, xp.x, h-HPAD-1));             }         }         // Ordinate tick marks and horizontal grid lines.         for(int i = 0; i <= maxVals[1]; i += 100) {             Point2D.Double p = new Point2D.Double(0, i);             Point2D.Double xp = new Point2D.Double();             xform.transform(p, xp);             g2.setPaint(flatBlack);             g2.draw(new Line2D.Double(xp.x, xp.y, xp.x-TICK, xp.y));             if(i > 0) {  // horizontal grid lines                 g2.setPaint(gridColor);                 g2.draw(new Line2D.Double(xp.x+1, xp.y, w-HPAD, xp.y));             }         }         // Draw labels on axes.         g2.setPaint(flatBlack);         FontRenderContext frc = g2.getFontRenderContext();         Font font = g2.getFont();         LineMetrics lm = font.getLineMetrics("0", frc);         float height = lm.getAscent() + lm.getDescent();         // Label abcissa.         for(int i = 0; i <= maxVals[0]; i += 100) {             Point2D.Float p = new Point2D.Float(i, 0);             Point2D.Float xp = new Point2D.Float();             xform.transform(p, xp);             String s = String.valueOf(i);             float width = (float)font.getStringBounds(s, frc).getWidth();             float x = xp.x - width/2;             float y = xp.y + lm.getAscent() + TICK + SPAD;             g2.drawString(s, x, y);         }         // Label ordinate.         for(int i = 0; i <= maxVals[1]; i += 100) {             Point2D.Float p = new Point2D.Float(0, i);             Point2D.Float xp = new Point2D.Float();             xform.transform(p, xp);             String s = String.valueOf(i);             float width = (float)font.getStringBounds(s, frc).getWidth();             float x = xp.x - width - SPAD - TICK;             float y = xp.y - height/2 + lm.getAscent();             g2.drawString(s, x, y);         }         int numPts = xPoints.length;         // Draw raw data.         // Offscreen -> down and right.         g2.setPaint(Color.blue);         g2.drawPolyline(xPoints, yPoints, numPts);         // Draw transformed src points into view.         g2.setPaint(Color.red);         g2.drawPolyline(scaledX, scaledY, numPts);     }     private void initTransform() {         int[] maxVals = getMaxValues();         System.out.printf("maxVals = [%d, %d]%n",                           maxVals[0], maxVals[1]);         double[] scales = getScales(maxVals);         System.out.printf("scales = [%.1f, %.1f]%n",                           scales[0], scales[1]);         double xScale = scales[0];         double yScale = scales[1];         // Move to the origin.         xform = AffineTransform.getTranslateInstance(origin.x, origin.y);         // Scale data into (this component) view.         xform.scale(xScale, yScale);         int[][] coords = getScaledPoints();         scaledX = coords[0];         scaledY = coords[1];         System.out.printf("scaledX = %s%nscaledY = %s%n",                           Arrays.toString(scaledX),                           Arrays.toString(scaledY));     }     private int[] getMaxValues() {         int[] maxVals = new int[2];         for(int i = 0; i < xPoints.length; i++) {             if(xPoints[i] > maxVals[0]) {                 maxVals[0] = xPoints[i];             }             if(yPoints[i] > maxVals[1]) {                 maxVals[1] = yPoints[i];             }         }         return maxVals;     }     private double[] getScales(int[] maxima) {         int w = getWidth() - HPAD - PAD;         int h = getHeight() - 2*PAD;         double xScale =  (double)w / maxima[0];         double yScale = -(double)h / maxima[1];         return new double[] { xScale, yScale };     }     private int[][] getScaledPoints() {         int numPts = xPoints.length;         double[] srcPts = new double[2*numPts];         for(int i = 0, j = 0; i < srcPts.length; i += 2, j++) {             srcPts[i]  = xPoints[j];             srcPts[i+1] = yPoints[j];         }         double[] dstPts = new double[2*numPts];         xform.transform(srcPts, 0, dstPts, 0, numPts);         int[][] scaled = new int[2][numPts];         for(int i = 0, j = 0; i < numPts; i++) {             scaled[0][i] = (int)dstPts[j++];             scaled[1][i] = (int)dstPts[j++];         }         return scaled;     }     public static void main(String[] args) {         ScaleToView test = new ScaleToView();         JFrame f = new JFrame();         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);         f.add(test);         f.setSize(400,400);         f.setLocation(200,200);         f.setVisible(true);         test.addComponentListener(test.cl);     }     private ComponentListener cl = new ComponentAdapter() {         public void componentResized(ComponentEvent e) {             xform = null;             repaint();         }     }; }```