wxWidgets/tests/graphics/affinematrix.cpp
Vadim Zeitlin fd5cfba711 Several fixes for wxAffineMatrix2D transformations.
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
2012-05-25 09:48:09 +00:00

252 lines
7.6 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: tests/graphics/affinetransform.cpp
// Purpose: Unit test for transformations implemented for wxAffineMatrix2D
// Author: Catalin Raceanu
// Created: 2011-04-14
// Copyright: (c) 2011 wxWidgets development team
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/graphics.h"
#include "wx/dcmemory.h"
#include "wx/affinematrix2d.h"
#include "wx/math.h"
#include "testimage.h"
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class AffineTransformTestCase : public CppUnit::TestCase
{
public:
AffineTransformTestCase()
{
wxImage::AddHandler(new wxJPEGHandler);
}
virtual void setUp();
private:
CPPUNIT_TEST_SUITE( AffineTransformTestCase );
CPPUNIT_TEST( InvertMatrix );
#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();
void InvertMatrix();
#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;
#endif // wxUSE_DC_TRANSFORM_MATRIX
DECLARE_NO_COPY_CLASS(AffineTransformTestCase)
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( AffineTransformTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( AffineTransformTestCase, "AffineTransformTestCase" );
void AffineTransformTestCase::setUp()
{
#if wxUSE_DC_TRANSFORM_MATRIX
m_imgOrig.LoadFile("horse.jpg");
CPPUNIT_ASSERT( m_imgOrig.IsOk() );
m_bmpOrig = wxBitmap(m_imgOrig);
#endif // wxUSE_DC_TRANSFORM_MATRIX
}
void AffineTransformTestCase::InvertMatrix()
{
wxAffineMatrix2D matrix1;
matrix1.Set(wxMatrix2D(2, 1, 1, 1), wxPoint2DDouble(1, 1));
wxAffineMatrix2D matrix2(matrix1);
matrix2.Invert();
wxMatrix2D m;
wxPoint2DDouble p;
matrix2.Get(&m, &p);
CPPUNIT_ASSERT_EQUAL( 1, (int)m.m_11 );
CPPUNIT_ASSERT_EQUAL( -1, (int)m.m_12 );
CPPUNIT_ASSERT_EQUAL( -1, (int)m.m_21 );
CPPUNIT_ASSERT_EQUAL( 2, (int)m.m_22 );
CPPUNIT_ASSERT_EQUAL( 0, (int)p.m_x );
CPPUNIT_ASSERT_EQUAL( -1, (int)p.m_y );
matrix2.Concat(matrix1);
CPPUNIT_ASSERT( matrix2.IsIdentity() );
}
#if wxUSE_DC_TRANSFORM_MATRIX
void AffineTransformTestCase::VMirrorAndTranslate()
{
wxBitmap bmpUsingMatrix(m_bmpOrig.GetWidth(), m_bmpOrig.GetHeight());
// build the mirrored image using the transformation matrix
{
wxMemoryDC dc(bmpUsingMatrix);
if ( !dc.CanUseTransformMatrix() )
return;
wxAffineMatrix2D matrix;
matrix.Mirror(wxVERTICAL);
matrix.Translate(0, -m_bmpOrig.GetHeight() + 1);
dc.SetTransformMatrix(matrix);
dc.DrawBitmap(m_bmpOrig, 0, 0);
}
CPPUNIT_ASSERT_EQUAL( bmpUsingMatrix.ConvertToImage(),
m_imgOrig.Mirror(false) );
}
void AffineTransformTestCase::Rotate90Clockwise()
{
wxBitmap bmpUsingMatrix(m_bmpOrig.GetHeight(), m_bmpOrig.GetWidth());
// build the rotated image using the transformation matrix
{
wxMemoryDC dc(bmpUsingMatrix);
if ( !dc.CanUseTransformMatrix() )
return;
wxAffineMatrix2D matrix;
matrix.Rotate(0.5 * M_PI);
matrix.Translate(0, -m_bmpOrig.GetHeight());
dc.SetTransformMatrix(matrix);
dc.DrawBitmap(m_bmpOrig, 0, 0);
}
CPPUNIT_ASSERT_EQUAL( bmpUsingMatrix.ConvertToImage(),
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