Results 1 to 5 of 5
  1. #1
    tones is offline Member
    Join Date
    Dec 2008
    Posts
    2
    Rep Power
    0

    Default 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:

    Java 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

  2. #2
    Supamagier is offline Senior Member
    Join Date
    Aug 2008
    Posts
    384
    Rep Power
    6

    Default

    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
    Java Code:
    newY = -y + height/2;
    Or isn't that what your mean?
    I die a little on the inside...
    Every time I get shot.

  3. #3
    tones is offline Member
    Join Date
    Dec 2008
    Posts
    2
    Rep Power
    0

    Default

    Quote Originally Posted by Supamagier View Post
    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
    Java 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

    Java 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

    Java 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).

  4. #4
    xcallmejudasx's Avatar
    xcallmejudasx is offline Senior Member
    Join Date
    Oct 2008
    Location
    Houston, TX & Flint, MI
    Posts
    609
    Rep Power
    6

    Default

    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.
    Liberty has never come from the government.
    Liberty has always come from the subjects of government.
    The history of liberty is the history of resistance.
    The history of liberty is a history of the limitation of governmental power, not the increase of it.

  5. #5
    hardwired's Avatar
    hardwired is offline Senior Member
    Join Date
    Jul 2007
    Posts
    1,576
    Rep Power
    8

    Default

    Java 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();
            }
        };
    }

Similar Threads

  1. AffineTransform demo
    By Java Tip in forum java.awt
    Replies: 0
    Last Post: 06-22-2008, 10:59 PM
  2. affineTransform rotation
    By MichYer in forum AWT / Swing
    Replies: 0
    Last Post: 07-18-2007, 08:55 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •