10

What is the simplest way to create AffineTransform which maps coordinates from one rectangle to another (float/double rectangles are given)?

UPDATE 1

Rectangles can be absolutely different. For example [(0,0)-(1,1)] and [(150,-14)-(-1000,-14.1)]. And transformation should transform uniformly. For example, rectangle corners should be transformed one to one. For example coordinates (0,0) should turn to (150,-14).

UPDATE 2

I need AffineTransform object, not just calculation. Because I want to apply it to Graphics object. Also I would like to have in the form of some concatenation of simple transforms.

UPDATE 3

All the following 3 tests are failed:

public class RectangleTransformTest {

    private static final double delta = 0.001;

    Rectangle2D r1 = new Rectangle2D.Double(-1, 0, 2, 0.01);
    Rectangle2D r2 = new Rectangle2D.Double(10, 20, 400, 300);

    AffineTransform t;

    Point2D src;
    Point2D dst1, dst2;

    @Test
    public void test1() {

        t = new AffineTransform();
        t.translate(+r2.getMinX()-r1.getMinX(), +r2.getMinY()-r1.getMinY());
        t.scale(r2.getWidth()/r1.getWidth(), r2.getHeight()/r1.getHeight());

    }

    @Test
    public void test2() {

        t = new AffineTransform();

        t.scale(r2.getWidth()/r1.getWidth(), r2.getHeight()/r1.getHeight());
        t.translate(+r2.getMinX()-r1.getMinX(), +r2.getMinY()-r1.getMinY());

    }

    @Test
    public void test3() {

        t = new AffineTransform();

        t.scale((r2.getMaxX()-r2.getMinX())/(r1.getMaxX()-r1.getMinX()), (r2.getMaxY()-r2.getMinY())/(r1.getMaxY()-r1.getMinY()));
        t.translate(+r2.getMinX()-r1.getMinX(), +r2.getMinY()-r1.getMinY());

    }

    @After
    public void comparePoints() {

        src = new Point2D.Double(r1.getMinX(), r1.getMinY());
        dst1 =  new Point2D.Double();
        t.transform(src, dst1);
        dst2 = new Point2D.Double(r2.getMinX(), r2.getMinY());

        assertEquals(dst2.getX(), dst1.getX(), delta);
        assertEquals(dst2.getY(), dst1.getY(), delta);

        src = new Point2D.Double(r1.getMinX(), r1.getMaxY());
        dst1 =  new Point2D.Double();
        t.transform(src, dst1);
        dst2 = new Point2D.Double(r2.getMinX(), r2.getMaxY());

        assertEquals(dst2.getX(), dst1.getX(), delta);
        assertEquals(dst2.getY(), dst1.getY(), delta);

        src = new Point2D.Double(r1.getMaxX(), r1.getMinY());
        dst1 =  new Point2D.Double();
        t.transform(src, dst1);
        dst2 = new Point2D.Double(r2.getMaxX(), r2.getMinY());

        assertEquals(dst2.getX(), dst1.getX(), delta);
        assertEquals(dst2.getY(), dst1.getY(), delta);

        src = new Point2D.Double(r1.getMaxX(), r1.getMaxY());
        dst1 =  new Point2D.Double();
        t.transform(src, dst1);
        dst2 = new Point2D.Double(r2.getMaxX(), r2.getMaxY());

        assertEquals(dst2.getX(), dst1.getX(), delta);
        assertEquals(dst2.getY(), dst1.getY(), delta);

    }

}
Dims
  • 47,675
  • 117
  • 331
  • 600
  • [`AffineTransform#getTranslateInstance(double, double)`](http://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.html#getTranslateInstance%28double,%20double%29) ... You question is a little vague on details – MadProgrammer Dec 23 '12 at 23:33
  • Do you mean you have two *given* rectangles and want do derive the transformation between them? - Which transformation(s) will be needed, translation, rotation, scaling? – JimmyB Dec 23 '12 at 23:55
  • @Hanno I will need all transformations required by rectangles. For example if rectangles are equal, then it should be `Identity` transformation. – Dims Dec 24 '12 at 00:15
  • @MadProgrammer, this is just translation. I need also the scale if rectangles are of different size. – Dims Dec 24 '12 at 00:15
  • "all transformations required by rectangles" - this includes rotation since a rotated rectangle is still a rectangle, whereas, for example, a sheared rectangle is not a rectangle after the transformation. – JimmyB Dec 24 '12 at 00:24

1 Answers1

17

To transform from [(a,b)-(c,d)] to [(e,f)-(g,h)] you can perform the following computation:

x' = e + (x - a) * (g - e) / (c - a);
y' = f + (y - b) * (h - f) / (d - b);

Here is the corresponding AffineTransform code, where r1 is being transformed to r2:

t = new AffineTransform();
t.translate(r2.getMinX(), r2.getMinY());
t.scale(r2.getWidth()/r1.getWidth(), r2.getHeight()/r1.getHeight());    
t.translate(-r1.getMinX(), -r1.getMinY());
APerson
  • 8,140
  • 8
  • 35
  • 49
sam hocevar
  • 11,853
  • 5
  • 49
  • 68
  • I need `AffineTransform` object. – Dims Dec 24 '12 at 00:11
  • Then you need to concatenate a `getScaleInstance((g - e) / (c - a), (h - f) / (d - b))` and a `getTranslateInstance( e-a, f-b )`. – JimmyB Dec 24 '12 at 00:21
  • @Sam ah great I didn't think about such variant. Note that your exact version does not work, you should inverse location of translates. – Dims Dec 24 '12 at 00:51
  • @Dims Thanks, I'll fix it. It's also possible to do it with only one translate but I really don't think it's worth the complexity. – sam hocevar Dec 24 '12 at 00:55
  • What is the x and y in the input, and the x' and Y' in the computation at the start @samhocevar ? – Robben_Ford_Fan_boy Jun 28 '16 at 14:53
  • @Robben_Ford_Fan_boy *(x,y)* are the coordinates of any point inside the initial rectangle, and *(x',y')* are the coordinates of the transformed point in the destination rectangle. – sam hocevar Jun 28 '16 at 22:02
  • Has anyone had rounding errors using the computation method? I am using this and I am finding that sometimes I need to Round Up to get the correct Point, and sometimes I need to round down. Should a scaling factor be used? – Robben_Ford_Fan_boy Jul 12 '16 at 15:44