diff options
Diffstat (limited to 'src/cython/test-affine.py')
-rw-r--r-- | src/cython/test-affine.py | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/src/cython/test-affine.py b/src/cython/test-affine.py new file mode 100644 index 0000000..a020d73 --- /dev/null +++ b/src/cython/test-affine.py @@ -0,0 +1,249 @@ +import unittest +from math import pi, sqrt, sin, cos +from random import randint, uniform + +import cy2geom + +from cy2geom import Point, IntPoint +from cy2geom import Line, Ray, Rect + +from cy2geom import Rect + +from cy2geom import Affine +from cy2geom import Translate, Scale, Rotate, VShear, HShear, Zoom +from cy2geom import Eigen + +class TestPrimitives(unittest.TestCase): + def affine(self, A, B): + c0, c1, c2, c3, c4, c5 = A[0], A[1], A[2], A[3], A[4], A[5] + C = Affine(c0, c1, c2, c3, c4, c5) + self.assertEqual(C, A) + E = Affine.identity() + self.assertEqual(C, C*E) + self.assertEqual(E*B, B) + self.assertEqual(E.det(), 1) + + self.assertAlmostEqual(A.det(), c0*c3-c1*c2) + self.assertAlmostEqual(abs(A.det()), A.descrim2()) + self.assertAlmostEqual(abs(A.det())**0.5, A.descrim()) + #xor + self.assertFalse( A.flips() ^ (A.det() < 0) ) + + if A.is_singular(): + self.assertAlmostEqual(A.det(), 0) + else: + self.assertTrue( Affine.are_near (A*A.inverse(), E) ) + self.assertAlmostEqual(A.det(), 1/A.inverse().det()) + self.assertEqual( A.x_axis(), Point(c0, c1) ) + self.assertEqual( A.y_axis(), Point(c2, c3) ) + self.assertEqual( A.translation(), Point(c4, c5) ) + + self.assertAlmostEqual(A.expansion_X(), A.x_axis().length()) + self.assertAlmostEqual(A.expansion_Y(), A.y_axis().length()) + + if abs(A.expansion_X()) > 1e-7 and abs(A.expansion_Y()) > 1e-7: + A.set_expansion_X(2) + A.set_expansion_Y(3) + self.assertAlmostEqual(A.expansion_X(), 2) + self.assertAlmostEqual(A.expansion_Y(), 3) + + A.set_identity() + + self.assertTrue(A.is_identity()) + self.assertTrue(A.is_translation()) + self.assertFalse(A.is_nonzero_translation()) + self.assertTrue(A.is_scale()) + self.assertTrue(A.is_uniform_scale()) + self.assertFalse(A.is_nonzero_scale()) + self.assertFalse(A.is_nonzero_uniform_scale()) + self.assertTrue(A.is_rotation()) + self.assertFalse(A.is_nonzero_rotation()) + self.assertTrue(A.is_HShear()) + self.assertTrue(A.is_VShear()) + self.assertFalse(A.is_nonzero_HShear()) + self.assertFalse(A.is_nonzero_VShear()) + self.assertTrue(A.is_zoom()) + + self.assertTrue(A.preserves_area() and A.preserves_angles() and A.preserves_distances()) + + self.assertFalse( A.flips() ) + self.assertFalse( A.is_singular() ) + + A.set_X_axis(Point(c0, c1)) + A.set_Y_axis(Point(c2, c3)) + + self.assertEqual(A.without_translation(), A) + + A.set_translation(Point(c4, c5)) + self.assertEqual(C, A) + + self.assertAlmostEqual( (A*B).det(), A.det()*B.det() ) + + self.assertEqual( A.translation(), Point()*A ) + self.assertEqual( Point(1, 1)*A, Point( c0+c2+c4, c1+c3+c5 )) + + l = Line(Point(1, 1), 2) + self.assertEqual( (l.transformed(A)).origin(), l.origin()*A ) + self.assertTrue( Line.are_near( l.point_at(3)*A, l.transformed(A) ) ) + + r = Ray(Point(2, 3), 4) + self.assertEqual( (r.transformed(A)).origin(), r.origin()*A ) + self.assertTrue( Ray.are_near( r.point_at(3)*A, r.transformed(A) ) ) + + + + def test_affine(self): + al = [] + for i in range(10): + al.append(Affine( uniform(-10, 10), + uniform(-10, 10), + uniform(-10, 10), + uniform(-10, 10), + uniform(-10, 10), + uniform(-10, 10))) + for A in al: + for B in al: + self.affine(A, B) + + o = Point(2, 4) + v = Point(-1, 1)/sqrt(2) + l = Line.from_origin_and_versor(o, v) + + R = Affine.reflection(v, o) + for i in range(100): + p = Point(randint(0, 100), randint(0, 100)) + self.assertAlmostEqual(Line.distance(p, l), Line.distance(p*R, l)) + self.assertTrue( Affine.are_near( R, R.inverse() ) ) + + self.affine(R, R.inverse()) + + def test_translate(self): + T = Translate() + U = Translate(Point(2, 4)) + V = Translate(1, -9) + + self.assertTrue(Affine(T).is_translation()) + self.assertTrue(Affine(U).is_nonzero_translation()) + + self.assertEqual( (U*V).vector(), U.vector()+V.vector() ) + self.assertEqual( U.inverse().vector(), -U.vector() ) + self.assertEqual(T, Translate.identity()) + self.assertEqual( U.vector(), Point(U[0], U[1]) ) + + self.affine(Affine(V), Affine(U)) + self.affine(Affine(U), Affine(V)) + + r = Rect.from_points( Point(0, 2), Point(4, 8) ) + + self.assertEqual( ( r*(U*V) ).min(), r.min()+U.vector()+V.vector()) + + def test_scale(self): + S = Scale() + T = Scale( Point (3, 8) ) + U = Scale( -3, 1) + V = Scale(sqrt(2)) + + self.assertTrue( Affine(T).is_scale() ) + self.assertTrue( Affine(T).is_nonzero_scale() ) + self.assertTrue( Affine(V).is_nonzero_uniform_scale()) + + self.assertEqual( (T*V).vector(), T.vector()*sqrt(2) ) + self.assertEqual( (T*U)[0], T[0]*U[0] ) + self.assertAlmostEqual( 1/U.inverse()[1], U[1] ) + + r = Rect.from_points( Point(0, 2), Point(4, 8) ) + self.assertAlmostEqual((r*V).area(), 2*r.area()) + self.assertFalse(Affine(U).preserves_area()) + self.assertTrue(Affine(V).preserves_angles()) + + self.affine(Affine(T), Affine(U)) + self.affine(Affine(U), Affine(V)) + self.affine(Affine(V), Affine(T)) + + def test_rotate(self): + R = Rotate() + S = Rotate(pi/3) + T = Rotate(Point( 1, 1 )) + U = Rotate( -1, 1 ) + + self.assertTrue(S.vector(), Point(cos(pi/3), sin(pi/3)) ) + self.assertEqual( Point(T[0], T[1]), T.vector() ) + self.assertTrue( Affine.are_near( Rotate.from_degrees(60), S ) ) + self.assertEqual(R, Rotate.identity()) + self.assertTrue( Point.are_near( ( S * T ).vector(), + Point( cos( pi/3 + pi/4 ), sin( pi/3 + pi/4 ) ) ) ) + + self.affine( Affine(R), Affine(S)) + self.affine( Affine(S), Affine(T)) + self.affine( Affine(T), Affine(U)) + self.affine( Affine(U), Affine(R)) + + def test_shear(self): + H = HShear(2.98) + V = VShear(-sqrt(2)) + + self.assertAlmostEqual(H.factor(), 2.98) + self.assertAlmostEqual(V.inverse().factor(), sqrt(2)) + + G = HShear.identity() + H.set_factor(0) + self.assertEqual(G, H) + + G.set_factor(2) + H.set_factor(4) + self.assertAlmostEqual((G*H).factor(), G.factor()+H.factor()) + + W = VShear.identity() + V.set_factor(0) + self.assertEqual(W, V) + + W.set_factor(-2) + V.set_factor(3) + self.assertAlmostEqual((W*V).factor(), W.factor()+V.factor()) + + def test_zoom(self): + Z = Zoom(3) + Y = Zoom(translate=Translate(3,2)) + X = Zoom(sqrt(3), Translate(-1, 3)) + + self.assertEqual( + Zoom(Z.scale(), Translate(Y.translation())), + Y*Z ) + + Z.set_translation(Y.translation()) + Y.set_scale(Z.scale()) + self.assertEqual(Z, Y) + + self.assertEqual(Y.inverse().scale(), 1/Y.scale()) + + r = Rect.from_xywh( 1, 1, 3, 6) + q = Rect.from_xywh( 0, -1, 1, 2) + W = Zoom.map_rect(r, q) + + self.assertAlmostEqual(W.scale()*r.width(), q.width()) + self.assertTrue(Point.are_near( + r.min()+W.translation(), + q.min())) + def test_eigen(self): + #TODO looks like bug in eigen - (1, 0) should be eigenvector too + #~ S = Scale(1, 2) + #~ E_S = Eigen(S) + #~ print E_S.vectors, E_S.values + #~ print Affine(S) + #~ for i in E_S.vectors: + #~ print i, i*S, Point(1, 0) * S + + B = Affine(-2, 2, 2, 1, 0, 0) + G1 = Eigen(B) + G2 = Eigen( [[-2, 2], [2, 1]] ) + + self.assertAlmostEqual(min(G1.values), min(G2.values)) + self.assertAlmostEqual(max(G1.values), max(G2.values)) + + if Point.are_near( G1.vectors[0]*G1.values[0], G1.vectors[0]*B ): + self.assertTrue( Point.are_near( G1.vectors[1]*G1.values[1], G1.vectors[1]*B ) ) + else: + self.assertTrue( Point.are_near( G1.vectors[1]*G1.values[0], G1.vectors[1]*B ) ) + self.assertTrue( Point.are_near( G1.vectors[0]*G1.values[1], G1.vectors[0]*B ) ) + +unittest.main() |