]> git.saurik.com Git - wxWidgets.git/commitdiff
Several fixes for wxAffineMatrix2D transformations.
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 25 May 2012 09:48:09 +0000 (09:48 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 25 May 2012 09:48:09 +0000 (09:48 +0000)
Correct errors in TransformPoint() and TransformDistance().

Change Rotate() to interpret positive angles as rotating clockwise, for
consistency with wxGraphicsContext::Rotate().

Improve the unit test to verify that all the transformations work correctly.

Closes #14334.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71555 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/affinematrix2d.h
interface/wx/affinematrix2d.h
interface/wx/affinematrix2dbase.h
interface/wx/graphics.h
src/common/affinematrix2d.cpp
tests/graphics/affinematrix.cpp

index 6516cd46f5b5c52af1313220ee040d0a12f2a106..28055f8d35f140d1636a0c461d77afd378a93cd3 100644 (file)
@@ -36,7 +36,7 @@ public:
     virtual bool IsEqual(const wxAffineMatrix2DBase& t) const;
     virtual void Translate(wxDouble dx, wxDouble dy);
     virtual void Scale(wxDouble xScale, wxDouble yScale);
-    virtual void Rotate(wxDouble ccRadians);
+    virtual void Rotate(wxDouble cRadians);
 
 protected:
     virtual wxPoint2DDouble DoTransformPoint(const wxPoint2DDouble& p) const;
index 340051fa3bcfa6fc61e73b9b6cf7758ffcfa3f46..b600494f4c05f3a13bb45d278409129d292e855c 100644 (file)
@@ -107,6 +107,12 @@ public:
             The translation in x direction.
         @param dy
             The translation in y direction.
+
+        @code
+        //           |  1   0   0 |   | m_11  m_12   0 |
+        // matrix' = |  0   1   0 | x | m_21  m_22   0 |
+        //           | dx  dy   1 |   | m_tx  m_ty   1 |
+        @endcode
     */
     void Translate(wxDouble dx, wxDouble dy);
 
@@ -117,6 +123,12 @@ public:
             Scaling in x direction.
         @param yScale
             Scaling in y direction.
+
+        @code
+        //           | xScale   0      0 |   | m_11  m_12   0 |
+        // matrix' = |   0    yScale   0 | x | m_21  m_22   0 |
+        //           |   0      0      1 |   | m_tx  m_ty   1 |
+        @endcode
     */
     void Scale(wxDouble xScale, wxDouble yScale);
 
@@ -130,12 +142,18 @@ public:
     void Mirror(int direction = wxHORIZONTAL);
 
     /**
-        Add counter clockwise rotation to this matrix.
+        Add clockwise rotation to this matrix.
 
-        @param ccRadians
-            Rotation angle in radians.
+        @param cRadians
+            Rotation angle in radians, clockwise.
+
+        @code
+        //           | cos    sin   0 |   | m_11  m_12   0 |
+        // matrix' = | -sin   cos   0 | x | m_21  m_22   0 |
+        //           |  0      0    1 |   | m_tx  m_ty   1 |
+        @endcode
     */
-    void Rotate(wxDouble ccRadians);
+    void Rotate(wxDouble cRadians);
 
     /**
         Applies this matrix to the point.
@@ -144,6 +162,12 @@ public:
             The point receiving the transformations.
 
         @return The point with the transformations applied.
+
+        @code
+        //                                    | m_11  m_12   0 |
+        // point' = | src.m_x  src._my  1 | x | m_21  m_22   0 |
+        //                                    | m_tx  m_ty   1 |
+        @endcode
     */
     wxPoint2DDouble TransformPoint(const wxPoint2DDouble& p) const;
     void TransformPoint(wxDouble* x, wxDouble* y) const;
@@ -155,6 +179,12 @@ public:
             The source receiving the transformations.
 
         @return The source with the transformations applied.
+
+        @code
+        //                                   | m_11  m_12   0 |
+        // dist' = | src.m_x  src._my  0 | x | m_21  m_22   0 |
+        //                                   | m_tx  m_ty   1 |
+        @endcode
     */
     wxPoint2DDouble TransformDistance(const wxPoint2DDouble& p) const;
     void TransformDistance(wxDouble* dx, wxDouble* dy) const;
index 630cbc87406c38eb3887390215b15b187f4bffcd..efbeb7bd186092a1aa475122314ac44021eafea4 100644 (file)
@@ -156,12 +156,12 @@ public:
     virtual void Scale(wxDouble xScale, wxDouble yScale) = 0;
 
     /**
-        Add counter clockwise rotation to this matrix.
+        Add clockwise rotation to this matrix.
 
-        @param ccRadians
-            Rotation angle in radians.
+        @param cRadians
+            Rotation angle in radians, clockwise.
     */    
-    virtual void Rotate(wxDouble ccRadians) = 0;
+    virtual void Rotate(wxDouble cRadians) = 0;
 
     /**
         Add mirroring to this matrix.
index 630662f47a30062da976248fc55ed30ebab17299..ac46f91a3135155f0cb71b76f9f4b0a3a8aaded1 100644 (file)
@@ -1299,7 +1299,10 @@ public:
     virtual bool IsIdentity() const;
 
     /**
-        Rotates this matrix (in radians).
+        Rotates this matrix clockwise (in radians).
+
+        @param radians
+            Rotation angle in radians, clockwise.
     */
     virtual void Rotate(wxDouble angle);
 
index 0b1b9207dc90758d44f24dcf7b6d2745b9324869..5013b31f15ee76f2e32ce70362d6929fa00e23c3 100644 (file)
@@ -127,19 +127,19 @@ void wxAffineMatrix2D::Scale(wxDouble xScale, wxDouble yScale)
     m_22 *= yScale;
 }
 
-// add the rotation to this matrix (counter clockwise, radians)
-// | cos   -sin   0 |   | m_11  m_12   0 |
-// | sin    cos   0 | x | m_21  m_22   0 |
+// add the rotation to this matrix (clockwise, radians)
+// | cos    sin   0 |   | m_11  m_12   0 |
+// | -sin   cos   0 | x | m_21  m_22   0 |
 // |  0      0    1 |   | m_tx  m_ty   1 |
-void wxAffineMatrix2D::Rotate(wxDouble ccRadians)
+void wxAffineMatrix2D::Rotate(wxDouble cRadians)
 {
-    wxDouble c = cos(ccRadians);
-    wxDouble s = sin(ccRadians);
+    wxDouble c = cos(cRadians);
+    wxDouble s = sin(cRadians);
 
-    wxDouble e11 = c*m_11 - s*m_21;
-    wxDouble e12 = c*m_12 - s*m_22;
-    m_21 = s*m_11 + c*m_21;
-    m_22 = s*m_12 + c*m_22;
+    wxDouble e11 = c*m_11 + s*m_21;
+    wxDouble e12 = c*m_12 + s*m_22;
+    m_21 = c*m_21 - s*m_11;
+    m_22 = c*m_22 - s*m_12;
     m_11 = e11;
     m_12 = e12;
 }
@@ -159,7 +159,7 @@ wxAffineMatrix2D::DoTransformPoint(const wxPoint2DDouble& src) const
         return src;
 
     return wxPoint2DDouble(src.m_x * m_11 + src.m_y * m_21 + m_tx,
-                           src.m_y * m_12 + src.m_y * m_22 + m_ty);
+                           src.m_x * m_12 + src.m_y * m_22 + m_ty);
 }
 
 // applies the matrix except for translations
@@ -173,7 +173,7 @@ wxAffineMatrix2D::DoTransformDistance(const wxPoint2DDouble& src) const
         return src;
 
     return wxPoint2DDouble(src.m_x * m_11 + src.m_y * m_21,
-                           src.m_y * m_12 + src.m_y * m_22);
+                           src.m_x * m_12 + src.m_y * m_22);
 }
 
 bool wxAffineMatrix2D::IsIdentity() const
index 90f56cc1a9ce150fbf1d2ea5f30bdf81fdcdcf65..22ade750333007793128ae708cfa90ff3f065d50 100644 (file)
@@ -16,6 +16,7 @@
     #pragma hdrstop
 #endif
 
+#include "wx/graphics.h"
 #include "wx/dcmemory.h"
 #include "wx/affinematrix2d.h"
 #include "wx/math.h"
@@ -42,6 +43,9 @@ private:
 #if wxUSE_DC_TRANSFORM_MATRIX
         CPPUNIT_TEST( VMirrorAndTranslate );
         CPPUNIT_TEST( Rotate90Clockwise );
+#if wxUSE_GRAPHICS_CONTEXT
+        CPPUNIT_TEST( CompareToGraphicsContext );
+#endif // wxUSE_GRAPHICS_CONTEXT
 #endif // wxUSE_DC_TRANSFORM_MATRIX
     CPPUNIT_TEST_SUITE_END();
 
@@ -49,6 +53,9 @@ private:
 #if wxUSE_DC_TRANSFORM_MATRIX
     void VMirrorAndTranslate();
     void Rotate90Clockwise();
+#if wxUSE_GRAPHICS_CONTEXT
+    void CompareToGraphicsContext();
+#endif // wxUSE_GRAPHICS_CONTEXT
 
     wxImage m_imgOrig;
     wxBitmap m_bmpOrig;
@@ -133,7 +140,7 @@ void AffineTransformTestCase::Rotate90Clockwise()
             return;
 
         wxAffineMatrix2D matrix;
-        matrix.Rotate(-0.5 * M_PI);
+        matrix.Rotate(0.5 * M_PI);
         matrix.Translate(0, -m_bmpOrig.GetHeight());
         dc.SetTransformMatrix(matrix);
         dc.DrawBitmap(m_bmpOrig, 0, 0);
@@ -143,4 +150,102 @@ void AffineTransformTestCase::Rotate90Clockwise()
                           m_imgOrig.Rotate90(true) );
 }
 
+#if wxUSE_GRAPHICS_CONTEXT
+void AffineTransformTestCase::CompareToGraphicsContext()
+{
+    wxPoint2DDouble pointA1(1.0, 3.0), pointA2(60.0, 50.0),
+                    pointG1(1.0, 3.0), pointG2(60.0, 50.0);
+
+    // Create affine matrix and transform it
+    wxAffineMatrix2D matrixA1, matrixA2;
+    matrixA2.Rotate(M_PI / 3);
+    matrixA1.Translate(-m_bmpOrig.GetWidth()/2, -m_bmpOrig.GetHeight()/2);
+    matrixA1.Rotate(-M_PI *2/ 6);
+    matrixA1.Translate(m_bmpOrig.GetWidth()/2, m_bmpOrig.GetHeight()/2);
+    matrixA1.Mirror(wxHORIZONTAL);
+    matrixA1.Concat(matrixA2);
+    matrixA1.Mirror(wxVERTICAL);
+    matrixA1.Translate(m_bmpOrig.GetWidth()/2, -m_bmpOrig.GetHeight()/2);
+    matrixA1.Scale(0.9, 0.9);
+    matrixA1.Invert();
+
+    // Create image using first matrix
+    wxBitmap bmpUsingMatrixA1(m_bmpOrig.GetHeight(), m_bmpOrig.GetWidth());
+
+    // Build the transformed image using the transformation matrix
+    {
+        wxMemoryDC dc(bmpUsingMatrixA1);
+
+        if ( !dc.CanUseTransformMatrix() )
+            return;
+
+        // Draw the bitmap
+        dc.SetTransformMatrix(matrixA1);
+        dc.DrawBitmap(m_bmpOrig, 0, 0);
+
+        // Draw a line
+        matrixA1.TransformPoint(&pointA1.m_x, &pointA1.m_y);
+        matrixA1.TransformDistance(&pointA2.m_x, &pointA2.m_y);
+
+        dc.DrawLine(wxRound(pointA1.m_x), wxRound(pointA1.m_y),
+            wxRound(pointA1.m_x + pointA2.m_x), wxRound(pointA1.m_x + pointA2.m_y));
+    }
+
+
+    // Create graphics matrix and transform it
+    wxMemoryDC mDc;
+    wxGraphicsContext* gDc = wxGraphicsContext::Create(mDc);
+    wxGraphicsMatrix matrixG1 = gDc->CreateMatrix();
+    wxGraphicsMatrix matrixG2 = gDc->CreateMatrix();
+    matrixG2.Rotate(M_PI / 3);
+    matrixG1.Translate(-m_bmpOrig.GetWidth()/2, -m_bmpOrig.GetHeight()/2);
+    matrixG1.Rotate(-M_PI*2 / 6);
+    matrixG1.Translate(m_bmpOrig.GetWidth()/2, m_bmpOrig.GetHeight()/2);
+    matrixG1.Scale(-1, 1);
+    matrixG1.Concat(matrixG2);
+    matrixG1.Scale(1, -1);
+    matrixG1.Translate(m_bmpOrig.GetWidth()/2, -m_bmpOrig.GetHeight()/2);
+    matrixG1.Scale(0.9, 0.9);
+    matrixG1.Invert();
+    // Create affine matrix from the graphics matrix
+    wxMatrix2D mat2D;
+    wxPoint2DDouble tr;
+    matrixG1.Get(&mat2D.m_11, &mat2D.m_12, &mat2D.m_21, &mat2D.m_22, &tr.m_x, &tr.m_y);
+    wxAffineMatrix2D matrixAG;
+    matrixAG.Set(mat2D, tr);
+
+    delete gDc;
+
+    // Create image using last matrix
+    wxBitmap bmpUsingMatrixAG(m_bmpOrig.GetHeight(), m_bmpOrig.GetWidth());
+
+    // Build the transformed image using the transformation matrix
+    {
+        wxMemoryDC dc(bmpUsingMatrixAG);
+
+        if ( !dc.CanUseTransformMatrix() )
+            return;
+
+        // Draw the bitmap
+        dc.SetTransformMatrix(matrixAG);
+        dc.DrawBitmap(m_bmpOrig, 0, 0);
+
+        // Draw a line
+        matrixG1.TransformPoint(&pointG1.m_x, &pointG1.m_y);
+        matrixG1.TransformDistance(&pointG2.m_x, &pointG2.m_y);
+
+        dc.DrawLine(wxRound(pointG1.m_x), wxRound(pointG1.m_y),
+            wxRound(pointG1.m_x + pointG2.m_x), wxRound(pointG1.m_x + pointG2.m_y));
+    }
+
+
+    CPPUNIT_ASSERT_EQUAL( bmpUsingMatrixA1.ConvertToImage(),
+                          bmpUsingMatrixAG.ConvertToImage() );
+
+    // Save the images to check that something _is_ inside the visible area.
+    //bmpUsingMatrixA1.SaveFile("matrixA1.jpg", wxBITMAP_TYPE_JPEG);
+    //bmpUsingMatrixAG.SaveFile("matrixAG.jpg", wxBITMAP_TYPE_JPEG);
+}
+#endif // wxUSE_GRAPHICS_CONTEXT
+
 #endif // wxUSE_DC_TRANSFORM_MATRIX