summaryrefslogtreecommitdiffstats
path: root/share/extensions/tests/test_inkex_transforms.py
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions/tests/test_inkex_transforms.py')
-rw-r--r--share/extensions/tests/test_inkex_transforms.py567
1 files changed, 567 insertions, 0 deletions
diff --git a/share/extensions/tests/test_inkex_transforms.py b/share/extensions/tests/test_inkex_transforms.py
new file mode 100644
index 0000000..07224ca
--- /dev/null
+++ b/share/extensions/tests/test_inkex_transforms.py
@@ -0,0 +1,567 @@
+# coding=utf-8
+"""
+Test Inkex transformational logic.
+"""
+from math import sqrt, pi
+from inkex.transforms import (
+ Vector2d, ImmutableVector2d, BoundingBox, BoundingInterval, Transform, DirectedLineSegment
+)
+from inkex.utils import PY3
+from inkex.tester import TestCase
+import pytest
+
+class ImmutableVector2dTest(TestCase):
+ """Test the ImmutableVector2d object"""
+ def test_vector_creation(self):
+ """Test ImmutableVector2d creation"""
+ vec0 = ImmutableVector2d(15, 22)
+ self.assertEqual(vec0.x, 15)
+ self.assertEqual(vec0.y, 22)
+
+ vec1 = ImmutableVector2d()
+ self.assertEqual(vec1.x, 0)
+ self.assertEqual(vec1.y, 0)
+
+ vec2 = ImmutableVector2d((17, 32))
+ self.assertEqual(vec2.x, 17)
+ self.assertEqual(vec2.y, 32)
+
+ vec3 = ImmutableVector2d(vec0)
+ self.assertEqual(vec3.x, 15)
+ self.assertEqual(vec3.y, 22)
+
+ self.assertRaises(ValueError, ImmutableVector2d, (1))
+ self.assertRaises(ValueError, ImmutableVector2d, (1, 2, 3))
+
+ def test_binary_operators(self):
+ """Test binary operators for vector2d"""
+ vec1 = ImmutableVector2d(15, 22)
+ vec2 = ImmutableVector2d(5, 3)
+
+ self.assertTrue((vec1 - vec2).is_close((10, 19)))
+ self.assertTrue((vec1 - (5, 3)).is_close((10, 19)))
+ self.assertTrue(((15, 22) - vec2).is_close((10, 19)))
+ self.assertTrue((vec1 + vec2).is_close((20, 25)))
+ self.assertTrue((vec1 + (5, 3)).is_close((20, 25)))
+ self.assertTrue(((15, 22) + vec2).is_close((20, 25)))
+ self.assertTrue((vec1 * 2).is_close((30, 44)))
+ self.assertTrue((2 * vec1).is_close((30, 44)))
+ self.assertTrue((vec1 / 2).is_close((7.5, 11)))
+ self.assertTrue((vec1.__div__(2)).is_close((7.5, 11)))
+ self.assertTrue((vec1 // 2).is_close((7.5, 11)))
+
+ def test_ioperators(self):
+ """Test operators for vector2d"""
+ vec0 = vec = ImmutableVector2d(15, 22)
+ vec += (1, 1)
+ vec = ImmutableVector2d(vec)
+ self.assertTrue(vec.is_close((16, 23)))
+ vec -= (10, 20)
+ vec = ImmutableVector2d(vec)
+ self.assertTrue(vec.is_close((6, 3)))
+ vec *= 5
+ vec = ImmutableVector2d(vec)
+ self.assertTrue(vec.is_close((30, 15)))
+ vec /= 90
+ vec = ImmutableVector2d(vec)
+ self.assertTrue(vec.is_close((1.0/3, 1.0/6)))
+ vec //= 1.0/3
+ vec = ImmutableVector2d(vec)
+ self.assertTrue(vec.is_close((1, 0.5)))
+ self.assertTrue(vec0.is_close((15, 22)))
+ self.assertFalse(vec0.is_close(vec))
+
+ def test_unary_operators(self):
+ """Test unary operators"""
+ vec = ImmutableVector2d(1, 2)
+ self.assertTrue((-vec).is_close((-1, -2)))
+ self.assertTrue((+vec).is_close(vec))
+ self.assertTrue(+vec is not vec) # returned value is a copy
+
+ def test_representations(self):
+ """Test ImmutableVector2d Repr"""
+ self.assertEqual(str(ImmutableVector2d(1, 2)), "1, 2")
+ self.assertEqual(repr(ImmutableVector2d(1, 2)), "Vector2d(1, 2)")
+ self.assertEqual(ImmutableVector2d(1, 2).to_tuple(), (1, 2))
+
+ def test_assign(self):
+ """Test ImmutableVector2d assignement"""
+ vec = ImmutableVector2d(10, 20)
+ with pytest.raises(AttributeError):
+ vec.assign(5, 10)
+
+ def test_getitem(self):
+ """Test getitem for ImmutableVector2d"""
+ vec = ImmutableVector2d(10, 20)
+ self.assertEqual(len(vec), 2)
+ self.assertEqual(vec[0], 10)
+ self.assertEqual(vec[1], 20)
+
+
+class Vector2dTest(TestCase):
+ """Test the Vector2d object"""
+ def test_vector_creation(self):
+ """Test Vector2D creation"""
+ vec0 = Vector2d(15, 22)
+ self.assertEqual(vec0.x, 15)
+ self.assertEqual(vec0.y, 22)
+
+ vec1 = Vector2d()
+ self.assertEqual(vec1.x, 0)
+ self.assertEqual(vec1.y, 0)
+
+ vec2 = Vector2d((17, 32))
+ self.assertEqual(vec2.x, 17)
+ self.assertEqual(vec2.y, 32)
+
+ vec3 = Vector2d(vec0)
+ self.assertEqual(vec3.x, 15)
+ self.assertEqual(vec3.y, 22)
+
+ self.assertRaises(ValueError, Vector2d, (1))
+ self.assertRaises(ValueError, Vector2d, (1, 2, 3))
+
+ def test_binary_operators(self):
+ """Test binary operators for vector2d"""
+ vec1 = Vector2d(15, 22)
+ vec2 = Vector2d(5, 3)
+
+ self.assertTrue((vec1 - vec2).is_close((10, 19)))
+ self.assertTrue((vec1 - (5, 3)).is_close((10, 19)))
+ self.assertTrue(((15, 22) - vec2).is_close((10, 19)))
+ self.assertTrue((vec1 + vec2).is_close((20, 25)))
+ self.assertTrue((vec1 + (5, 3)).is_close((20, 25)))
+ self.assertTrue(((15, 22) + vec2).is_close((20, 25)))
+ self.assertTrue((vec1 * 2).is_close((30, 44)))
+ self.assertTrue((2 * vec1).is_close((30, 44)))
+ self.assertTrue((vec1 / 2).is_close((7.5, 11)))
+ self.assertTrue((vec1.__div__(2)).is_close((7.5, 11)))
+ self.assertTrue((vec1 // 2).is_close((7.5, 11)))
+
+ def test_ioperators(self):
+ """Test operators for vector2d"""
+ vec0 = vec = Vector2d(15, 22)
+ vec += (1, 1)
+ self.assertTrue(vec.is_close((16, 23)))
+ vec -= (10, 20)
+ self.assertTrue(vec.is_close((6, 3)))
+ vec *= 5
+ self.assertTrue(vec.is_close((30, 15)))
+ vec /= 90
+ self.assertTrue(vec.is_close((1.0/3, 1.0/6)))
+ vec //= 1.0/3
+ self.assertTrue(vec.is_close((1, 0.5)))
+ self.assertFalse(vec0.is_close((15, 22)))
+ self.assertTrue(vec0.is_close(vec))
+
+ def test_unary_operators(self):
+ """Test unary operators"""
+ vec = Vector2d(1, 2)
+ self.assertTrue((-vec).is_close((-1, -2)))
+ self.assertTrue((+vec).is_close(vec))
+ self.assertTrue(+vec is not vec) # returned value is a copy
+
+ def test_representations(self):
+ """Test Vector2D Repr"""
+ self.assertEqual(str(Vector2d(1, 2)), "1, 2")
+ self.assertEqual(repr(Vector2d(1, 2)), "Vector2d(1, 2)")
+ self.assertEqual(Vector2d(1, 2).to_tuple(), (1, 2))
+
+ def test_assign(self):
+ """Test vector2d assignement"""
+ vec = Vector2d(10, 20)
+ vec.assign(5, 10)
+ self.assertAlmostTuple(vec, (5, 10))
+ vec.assign((7, 11))
+ self.assertAlmostTuple(vec, (7, 11))
+
+ def test_getitem(self):
+ """Test getitem for Vector2D"""
+ vec = Vector2d(10, 20)
+ self.assertEqual(len(vec), 2)
+ self.assertEqual(vec[0], 10)
+ self.assertEqual(vec[1], 20)
+
+
+class TransformTest(TestCase):
+ """Test transformation API and calculations"""
+
+ def test_new_empty(self):
+ """Create a transformation from two triplets matrix"""
+ self.assertEqual(Transform(), ((1, 0, 0), (0, 1, 0)))
+
+ def test_new_from_triples(self):
+ """Create a transformation from two triplets matrix"""
+ self.assertEqual(Transform(((1, 2, 3), (4, 5, 6))), ((1, 2, 3), (4, 5, 6)))
+
+ def test_new_from_sextlet(self):
+ """Create a transformation from a list of six numbers"""
+ self.assertEqual(Transform((1, 2, 3, 4, 5, 6)), ((1, 3, 5), (2, 4, 6)))
+
+ def test_new_from_matrix_str(self):
+ """Create a transformation from a list of six numbers"""
+ self.assertEqual(Transform('matrix(1, 2, 3, 4, 5, 6)'), ((1, 3, 5), (2, 4, 6)))
+
+ def test_new_from_scale(self):
+ """Create a scale based transformation"""
+ self.assertEqual(Transform('scale(10)'), ((10, 0, 0), (0, 10, 0)))
+ self.assertEqual(Transform('scale(10, 3.3)'), ((10, 0, 0), (0, 3.3, 0)))
+
+ def test_new_from_translate(self):
+ """Create a translate transformation"""
+ self.assertEqual(Transform('translate(12)'), ((1, 0, 12), (0, 1, 0)))
+ self.assertEqual(Transform('translate(12, 14)'), ((1, 0, 12), (0, 1, 14)))
+
+ def test_new_from_rotate(self):
+ """Create a rotational transformation"""
+ self.assertEqual(str(Transform('rotate(90)')), 'rotate(90)')
+ self.assertEqual(str(Transform('rotate(90 10 12)')),
+ 'matrix(6.12323e-17 1 -1 6.12323e-17 22 2)')
+
+ def test_new_from_skew(self):
+ """Create skew x/y transformations"""
+ self.assertEqual(str(Transform('skewX(10)')), 'matrix(1 0 0.176327 1 0 0)')
+ self.assertEqual(str(Transform('skewY(10)')), 'matrix(1 0.176327 0 1 0 0)')
+
+ def test_invalid_creation_string(self):
+ """Test creating invalid transforms"""
+ self.assertEqual(Transform('boo(4)'), ((1, 0, 0), (0, 1, 0)))
+
+ def test_invalid_creation_matrix(self):
+ """Test creating invalid transforms"""
+ self.assertRaises(ValueError, Transform, 0.0)
+ self.assertRaises(ValueError, Transform, (0.0,))
+ self.assertRaises(ValueError, Transform, (0.0, 0.0, 0.0))
+
+ def test_repr(self):
+ """Test repr string"""
+ self.assertEqual(repr(Transform()), 'Transform(((1, 0, 0), (0, 1, 0)))')
+
+ def test_matrix_inversion(self):
+ """Test the negative of a transformation"""
+ self.assertEqual(-Transform('rotate(45)'), Transform('rotate(-45)'))
+ self.assertEqual(-Transform('translate(12, 10)'), Transform('translate(-12, -10)'))
+ self.assertEqual(-Transform('scale(4)'), Transform('scale(0.25)'))
+
+ def test_apply_to_point(self):
+ """Test applying the transformation to a point"""
+ trans = Transform('translate(10, 10)')
+ self.assertEqual(trans.apply_to_point((10, 10)).to_tuple(), (20, 20))
+ self.assertRaises(ValueError, trans.apply_to_point, '')
+
+ def test_translate(self):
+ """Test making translate specific items"""
+ self.assertEqual(str(Transform(translate=(10.6, 99.9))), "translate(10.6, 99.9)")
+
+ def test_scale(self):
+ """Test making scale specific items"""
+ self.assertEqual(str(Transform(scale=(1.0, 2.2))), "scale(1, 2.2)")
+
+ def test_rotate(self):
+ """Test making rotate specific items"""
+ self.assertEqual(str(Transform(rotate=45)), "rotate(45)")
+ self.assertEqual(str(Transform(rotate=(45, 10, 10))), "matrix(0.707107 0.707107 -0.707107 0.707107 10 -4.14214)")
+
+ def test_add_transform(self):
+ """Quickly add known transforms"""
+ tr1 = Transform()
+ tr1.add_scale(5.0, 1.0)
+ self.assertEqual(str(tr1), 'scale(5, 1)')
+ tr1.add_translate(10, 10)
+ self.assertEqual(str(tr1), 'matrix(5 0 0 1 50 10)')
+
+ def test_is_unity(self):
+ unity = Transform()
+ self.assertTrue(unity.is_rotate())
+ self.assertTrue(unity.is_scale())
+ self.assertTrue(unity.is_translate())
+
+ def test_is_rotation(self):
+ rot1 = Transform(rotate=21)
+ rot2 = Transform(rotate=35)
+ rot3 = Transform(rotate=53)
+
+ self.assertFalse(Transform(translate=1e-9).is_rotate(exactly=True))
+ self.assertFalse(Transform(scale=1+1e-9).is_rotate(exactly=True))
+ self.assertFalse(Transform(skewx=1e-9).is_rotate(exactly=True))
+ self.assertFalse(Transform(skewy=1e-9).is_rotate(exactly=True))
+
+ self.assertTrue(Transform(translate=1e-9).is_rotate(exactly=False))
+ self.assertTrue(Transform(scale=1+1e-9).is_rotate(exactly=False))
+ self.assertTrue(Transform(skewx=1e-9).is_rotate(exactly=False))
+ self.assertTrue(Transform(skewy=1e-9).is_rotate(exactly=False))
+
+ self.assertTrue(rot1.is_rotate())
+ self.assertTrue(rot2.is_rotate())
+ self.assertTrue(rot3.is_rotate())
+
+ self.assertFalse(rot1.is_translate())
+ self.assertFalse(rot2.is_translate())
+ self.assertFalse(rot3.is_translate())
+
+ self.assertFalse(rot1.is_scale())
+ self.assertFalse(rot2.is_scale())
+ self.assertFalse(rot3.is_scale())
+
+ self.assertTrue((rot1 * rot1).is_rotate())
+ self.assertTrue((rot1 * rot2).is_rotate())
+ self.assertTrue((rot1 * rot2 * rot3 * rot2 * rot1).is_rotate())
+
+ def test_is_translate(self):
+ tr1 = Transform(translate=(1.1,))
+ tr2 = Transform(translate=(1.3, 2.7))
+ tr3 = Transform(translate=(sqrt(2) / 2, pi))
+
+ self.assertFalse(Transform(rotate=1e-9).is_translate(exactly=True))
+ self.assertFalse(Transform(scale=1+1e-9).is_translate(exactly=True))
+ self.assertFalse(Transform(skewx=1e-9).is_translate(exactly=True))
+ self.assertFalse(Transform(skewy=1e-9).is_translate(exactly=True))
+
+ self.assertTrue(Transform(rotate=1e-9).is_translate(exactly=False))
+ self.assertTrue(Transform(scale=1+1e-9).is_translate(exactly=False))
+ self.assertTrue(Transform(skewx=1e-9).is_translate(exactly=False))
+ self.assertTrue(Transform(skewy=1e-9).is_translate(exactly=False))
+
+ self.assertTrue(tr1.is_translate())
+ self.assertTrue(tr2.is_translate())
+ self.assertTrue(tr3.is_translate())
+ self.assertFalse(tr1.is_rotate())
+ self.assertFalse(tr2.is_rotate())
+ self.assertFalse(tr3.is_rotate())
+ self.assertFalse(tr1.is_scale())
+ self.assertFalse(tr2.is_scale())
+ self.assertFalse(tr3.is_scale())
+
+ self.assertTrue((tr1 * tr1).is_translate())
+ self.assertTrue((tr1 * tr2).is_translate())
+ self.assertTrue((tr1 * tr2 * tr3 * tr2 * tr1).is_translate())
+ self.assertFalse(tr1 * tr2 * tr3 * -tr1 * -tr2 * -tr3) # is almost unity
+
+ def test_is_scale(self):
+ s1 = Transform(scale=(1.1,))
+ s2 = Transform(scale=(1.3, 2.7))
+ s3 = Transform(scale=(sqrt(2) / 2, pi))
+
+ self.assertFalse(Transform(translate=1e-9).is_scale(exactly=True))
+ self.assertFalse(Transform(rotate=1e-9).is_scale(exactly=True))
+ self.assertFalse(Transform(skewx=1e-9).is_scale(exactly=True))
+ self.assertFalse(Transform(skewy=1e-9).is_scale(exactly=True))
+
+ self.assertTrue(Transform(translate=1e-9).is_scale(exactly=False))
+ self.assertTrue(Transform(rotate=1e-9).is_scale(exactly=False))
+ self.assertTrue(Transform(skewx=1e-9).is_scale(exactly=False))
+ self.assertTrue(Transform(skewy=1e-9).is_scale(exactly=False))
+
+ self.assertFalse(s1.is_translate())
+ self.assertFalse(s2.is_translate())
+ self.assertFalse(s3.is_translate())
+ self.assertFalse(s1.is_rotate())
+ self.assertFalse(s2.is_rotate())
+ self.assertFalse(s3.is_rotate())
+ self.assertTrue(s1.is_scale())
+ self.assertTrue(s2.is_scale())
+ self.assertTrue(s3.is_scale())
+
+ def test_rotation_degrees(self):
+ self.assertAlmostEqual(Transform(rotate=30).rotation_degrees(), 30)
+ self.assertAlmostEqual(Transform(translate=(10, 20)).rotation_degrees(), 0)
+ self.assertAlmostEqual(Transform(scale=(1, 1)).rotation_degrees(), 0)
+
+ self.assertAlmostEqual(Transform(rotate=35, translate=(10, 20)).rotation_degrees(), 35)
+ self.assertAlmostEqual(Transform(rotate=35, translate=(10, 20), scale=5).rotation_degrees(), 35)
+ self.assertAlmostEqual(Transform(rotate=35, translate=(10, 20), scale=(5, 5)).rotation_degrees(), 35)
+
+ def rotation_degrees(**kwargs):
+ return Transform(**kwargs).rotation_degrees()
+
+ self.assertRaises(ValueError, rotation_degrees, rotate=35, skewx=1)
+ self.assertRaises(ValueError, rotation_degrees, rotate=35, skewy=1)
+ self.assertRaises(ValueError, rotation_degrees, rotate=35, scale=(10, 11))
+ self.assertRaises(ValueError, rotation_degrees, rotate=35, scale=(10, 11))
+
+ def test_construction_order(self):
+ """Test transform kwargs construction order"""
+ if not PY3:
+ self.skipTest("Construction order is known to fail on python2 (by design).")
+ return
+
+ self.assertEqual(str(Transform(scale=2.0, translate=(5, 6))),
+ 'matrix(2 0 0 2 5 6)')
+ self.assertEqual(str(Transform(scale=2.0, rotate=45)),
+ 'matrix(1.41421 1.41421 -1.41421 1.41421 0 0)')
+
+ x, y, angle = 5, 7, 31
+ rotation = Transform(rotate=angle)
+ translation = Transform(translate=(x, y))
+
+ rotation_then_translation = translation * rotation
+ translation_then_rotation = rotation * translation
+
+ tr1 = Transform(rotate=angle, translate=(x, y))
+ tr2 = Transform(translate=(x, y), rotate=angle)
+
+ self.assertNotEqual(tr1, tr2)
+ self.assertDeepAlmostEqual(tr1.matrix, rotation_then_translation.matrix)
+ self.assertDeepAlmostEqual(tr2.matrix, translation_then_rotation.matrix)
+
+ def test_interpolate(self):
+ """Test interpolate with other transform"""
+ t1 = Transform((0,0,0,0,0,0))
+ t2 = Transform((1,1,1,1,1,1))
+ val = t1.interpolate(t2, 0.5)
+ assert all(getattr(val, a) == pytest.approx(0.5, 1e-3) for a in 'abcdef')
+
+
+
+class ScaleTest(TestCase):
+ """Test scale class"""
+
+ def test_creation(self):
+ """Creating scales"""
+ self.assertEqual(BoundingInterval(0, 0), (0, 0))
+ self.assertEqual(BoundingInterval(1), (1, 1))
+ self.assertEqual(BoundingInterval(10), (10, 10))
+ self.assertEqual(BoundingInterval(10, 20), (10, 20))
+ self.assertEqual(BoundingInterval((2, 50)), (2, 50))
+ self.assertEqual(repr(BoundingInterval((5, 10))), 'BoundingInterval(5, 10)')
+
+ def test_center(self):
+ """Center of a scale"""
+ self.assertEqual(BoundingInterval(0, 0).center, 0)
+ self.assertEqual(BoundingInterval(0, 10).center, 5)
+ self.assertEqual(BoundingInterval(-10, 10).center, 0)
+
+ def test_neg(self):
+ """-Span(...)"""
+ self.assertEqual(tuple(-BoundingInterval(-10, 10)), (-10, 10))
+ self.assertEqual(tuple(-BoundingInterval(-15, 2)), (-2, 15))
+ self.assertEqual(tuple(-BoundingInterval(100, 110)), (-110, -100))
+ self.assertEqual(tuple(-BoundingInterval(-110, -100)), (100, 110))
+
+ def test_size(self):
+ """Size of the scale"""
+ self.assertEqual(BoundingInterval(0, 0).size, 0)
+ self.assertEqual(BoundingInterval(10, 30).size, 20)
+ self.assertEqual(BoundingInterval(-10, 10).size, 20)
+ self.assertEqual(BoundingInterval(-30, -10).size, 20)
+
+ def test_combine(self):
+ """Combine scales together"""
+ self.assertEqual(BoundingInterval(9, 10) + BoundingInterval(4, 5), (4, 10))
+ self.assertEqual(sum([BoundingInterval(4), BoundingInterval(3), BoundingInterval(10)], None), (3, 10))
+ self.assertEqual(BoundingInterval(2, 2) * 2, (4, 4))
+
+ def test_errors(self):
+ """Expected errors"""
+ self.assertRaises(ValueError, BoundingInterval, 'foo')
+
+
+class BoundingBoxTest(TestCase):
+ """Test bounding box calculations"""
+
+ def test_bbox(self):
+ """Creating bounding boxes"""
+ self.assertEqual(tuple(BoundingBox(1, 3)), ((1, 1), (3, 3)))
+ self.assertEqual(tuple(BoundingBox((1, 2), 3)), ((1, 2), (3, 3)))
+ self.assertEqual(tuple(BoundingBox(1, (3, 4))), ((1, 1), (3, 4)))
+ self.assertEqual(tuple(BoundingBox((1, 2), (3, 4))), ((1, 2), (3, 4)))
+ self.assertEqual(repr(BoundingBox((1, 2), (3, 4))), 'BoundingBox((1, 2),(3, 4))')
+
+ def test_bbox_sum(self):
+ """Test adding bboxes together"""
+ self.assertEqual(tuple(BoundingBox((0, 10), (0, 10)) + BoundingBox((-10, 0), (-10, 0))), ((-10, 10), (-10, 10)))
+ ret = sum([
+ BoundingBox((-5, 0), (0, 0)),
+ BoundingBox((0, 5), (0, 0)),
+ BoundingBox((0, 0), (-5, 0)),
+ BoundingBox((0, 0), (0, 5))], None)
+ self.assertEqual(tuple(ret), ((-5, 5), (-5, 5)))
+ self.assertEqual(tuple(BoundingBox(-10, 2) + ret), ((-10, 5), (-5, 5)))
+ self.assertEqual(tuple(ret + BoundingBox(1, -10)), ((-5, 5), (-10, 5)))
+
+ def test_bbox_neg(self):
+ self.assertEqual(tuple(-BoundingBox(-10, 2)), ((10, 10), (-2, -2)))
+ self.assertEqual(tuple(-BoundingBox((-10, 15), (2, 10))), ((-15, 10), (-10, -2)))
+
+ def test_bbox_scale(self):
+ """Bounding Boxes can be scaled"""
+ self.assertEqual(tuple(BoundingBox(1, 3) * 2), ((2, 2), (6, 6)))
+
+ def test_bbox_anchor_left_right(self):
+ """Bunding box anchoring (left to right)"""
+ bbox = BoundingBox((-1, 1), (10, 20))
+ self.assertEqual([
+ bbox.get_anchor('l', 't', 'lr'),
+ bbox.get_anchor('m', 't', 'lr'),
+ bbox.get_anchor('r', 't', 'lr'),
+ bbox.get_anchor('l', 't', 'rl'),
+ bbox.get_anchor('m', 't', 'rl'),
+ bbox.get_anchor('r', 't', 'rl'),
+ ], [-1, 0.0, 1, 1, -0.0, -1])
+
+ def test_bbox_anchor_top_bottom(self):
+ """Bunding box anchoring (top to bottom)"""
+ bbox = BoundingBox((10, 20), (-1, 1))
+ self.assertEqual([
+ bbox.get_anchor('l', 't', 'tb'),
+ bbox.get_anchor('l', 'm', 'tb'),
+ bbox.get_anchor('l', 'b', 'tb'),
+ bbox.get_anchor('l', 't', 'bt'),
+ bbox.get_anchor('l', 'm', 'bt'),
+ bbox.get_anchor('l', 'b', 'bt'),
+ ], [-1, 0.0, 1, 1, -0.0, -1])
+
+ def test_bbox_anchor_custom(self):
+ """Bounding box anchoring custom angle"""
+ bbox = BoundingBox((10, 10), (5, 5))
+ self.assertEqual([
+ bbox.get_anchor('l', 't', 0),
+ bbox.get_anchor('l', 't', 90),
+ bbox.get_anchor('l', 't', 180),
+ bbox.get_anchor('l', 't', 270),
+ bbox.get_anchor('l', 't', 45),
+ ], [10, -5, -10, 5, 3.5355339059327378])
+
+ def test_bbox_anchor_radial(self):
+ """Bounding box anchoring radial in/out"""
+ bbox = BoundingBox((10, 10), (5, 5))
+ self.assertRaises(ValueError, bbox.get_anchor, 'm', 'm', 'ro')
+ selbox = BoundingBox((100, 100), (100, 100))
+ self.assertEqual(int(bbox.get_anchor('m', 'm', 'ro', selbox)), 130)
+
+class SegmentTest(TestCase):
+ """Test special Segments"""
+
+ def test_segment_creation(self):
+ """Test segments"""
+ self.assertEqual(DirectedLineSegment((1, 2), (3, 4)), (1, 3, 2, 4))
+ self.assertEqual(repr(DirectedLineSegment((1, 2), (3, 4))), 'DirectedLineSegment((1, 2), (3, 4))')
+
+ def test_segment_maths(self):
+ """Segments have calculations"""
+ self.assertEqual(DirectedLineSegment((0, 0), (10, 0)).angle, 0)
+
+
+class ExtremaTest(TestCase):
+ """Test school formula implementation"""
+
+ def test_cubic_extrema_1(self):
+ from inkex.transforms import cubic_extrema
+ a, b, c, d = 14.644651000000003194,-4.881549508464541276,-4.8815495084645448287,14.644651000000003194
+ cmin, cmax = cubic_extrema(a, b, c, d)
+ self.assertAlmostEqual(cmin, 0, delta=1e-6)
+ self.assertAlmostEqual(cmax, a, delta=1e-6)
+
+ def test_quadratic_extrema_1(self):
+ from inkex.transforms import quadratic_extrema
+ a, b = 5.0, 12.0
+ cmin, cmax = quadratic_extrema(a, b, a)
+ self.assertAlmostEqual(cmin, 5, delta=1e-6)
+ self.assertAlmostEqual(cmax, 8.5, delta=1e-6)
+
+ def test_quadratic_extrema_2(self):
+ from inkex.transforms import quadratic_extrema
+ a = 5.0
+ cmin, cmax = quadratic_extrema(a,a,a)
+ self.assertAlmostEqual(cmin, a, delta=1e-6)
+ self.assertAlmostEqual(cmax, a, delta=1e-6)