1import fontTools.misc.bezierTools as bezierTools 2from fontTools.misc.bezierTools import ( 3 calcQuadraticBounds, calcCubicBounds, curveLineIntersections, 4 segmentPointAtT, splitLine, splitQuadratic, splitCubic, splitQuadraticAtT, 5 splitCubicAtT, solveCubic) 6import pytest 7 8 9def test_calcQuadraticBounds(): 10 assert calcQuadraticBounds( 11 (0, 0), (50, 100), (100, 0)) == (0, 0, 100, 50.0) 12 assert calcQuadraticBounds( 13 (0, 0), (100, 0), (100, 100)) == (0.0, 0.0, 100, 100) 14 15 16def test_calcCubicBounds(): 17 assert calcCubicBounds( 18 (0, 0), (25, 100), (75, 100), (100, 0)) == ((0, 0, 100, 75.0)) 19 assert calcCubicBounds( 20 (0, 0), (50, 0), (100, 50), (100, 100)) == (0.0, 0.0, 100, 100) 21 assert calcCubicBounds( 22 (50, 0), (0, 100), (100, 100), (50, 0) 23 ) == pytest.approx((35.566243, 0.000000, 64.433757, 75.000000)) 24 25 26def test_splitLine(): 27 assert splitLine( 28 (0, 0), (100, 100), where=50, isHorizontal=True 29 ) == [((0, 0), (50.0, 50.0)), ((50.0, 50.0), (100, 100))] 30 assert splitLine( 31 (0, 0), (100, 100), where=100, isHorizontal=True 32 ) == [((0, 0), (100, 100))] 33 assert splitLine( 34 (0, 0), (100, 100), where=0, isHorizontal=True 35 ) == [((0, 0), (0, 0)), ((0, 0), (100, 100))] 36 assert splitLine( 37 (0, 0), (100, 100), where=0, isHorizontal=False 38 ) == [((0, 0), (0, 0)), ((0, 0), (100, 100))] 39 assert splitLine( 40 (100, 0), (0, 0), where=50, isHorizontal=False 41 ) == [((100, 0), (50, 0)), ((50, 0), (0, 0))] 42 assert splitLine( 43 (0, 100), (0, 0), where=50, isHorizontal=True 44 ) == [((0, 100), (0, 50)), ((0, 50), (0, 0))] 45 assert splitLine( 46 (0, 100), (100, 100), where=50, isHorizontal=True 47 ) == [((0, 100), (100, 100))] 48 49 50def assert_curves_approx_equal(actual_curves, expected_curves): 51 assert len(actual_curves) == len(expected_curves) 52 for acurve, ecurve in zip(actual_curves, expected_curves): 53 assert len(acurve) == len(ecurve) 54 for apt, ept in zip(acurve, ecurve): 55 assert apt == pytest.approx(ept) 56 57 58def test_splitQuadratic(): 59 assert splitQuadratic( 60 (0, 0), (50, 100), (100, 0), where=150, isHorizontal=False 61 ) == [((0, 0), (50, 100), (100, 0))] 62 assert splitQuadratic( 63 (0, 0), (50, 100), (100, 0), where=50, isHorizontal=False 64 ) == [((0, 0), (25, 50), (50, 50)), 65 ((50, 50), (75, 50), (100, 0))] 66 assert splitQuadratic( 67 (0, 0), (50, 100), (100, 0), where=25, isHorizontal=False 68 ) == [((0, 0), (12.5, 25), (25, 37.5)), 69 ((25, 37.5), (62.5, 75), (100, 0))] 70 assert_curves_approx_equal( 71 splitQuadratic( 72 (0, 0), (50, 100), (100, 0), where=25, isHorizontal=True), 73 [((0, 0), (7.32233, 14.64466), (14.64466, 25)), 74 ((14.64466, 25), (50, 75), (85.3553, 25)), 75 ((85.3553, 25), (92.6777, 14.64466), (100, -7.10543e-15))]) 76 # XXX I'm not at all sure if the following behavior is desirable 77 assert splitQuadratic( 78 (0, 0), (50, 100), (100, 0), where=50, isHorizontal=True 79 ) == [((0, 0), (25, 50), (50, 50)), 80 ((50, 50), (50, 50), (50, 50)), 81 ((50, 50), (75, 50), (100, 0))] 82 83 84def test_splitCubic(): 85 assert splitCubic( 86 (0, 0), (25, 100), (75, 100), (100, 0), where=150, isHorizontal=False 87 ) == [((0, 0), (25, 100), (75, 100), (100, 0))] 88 assert splitCubic( 89 (0, 0), (25, 100), (75, 100), (100, 0), where=50, isHorizontal=False 90 ) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)), 91 ((50, 75), (68.75, 75), (87.5, 50), (100, 0))] 92 assert_curves_approx_equal( 93 splitCubic( 94 (0, 0), (25, 100), (75, 100), (100, 0), where=25, 95 isHorizontal=True), 96 [((0, 0), (2.293792, 9.17517), (4.798045, 17.5085), (7.47414, 25)), 97 ((7.47414, 25), (31.2886, 91.6667), (68.7114, 91.6667), 98 (92.5259, 25)), 99 ((92.5259, 25), (95.202, 17.5085), (97.7062, 9.17517), 100 (100, 1.77636e-15))]) 101 102 103def test_splitQuadraticAtT(): 104 assert splitQuadraticAtT( 105 (0, 0), (50, 100), (100, 0), 0.5 106 ) == [((0, 0), (25, 50), (50, 50)), 107 ((50, 50), (75, 50), (100, 0))] 108 assert splitQuadraticAtT( 109 (0, 0), (50, 100), (100, 0), 0.5, 0.75 110 ) == [((0, 0), (25, 50), (50, 50)), 111 ((50, 50), (62.5, 50), (75, 37.5)), 112 ((75, 37.5), (87.5, 25), (100, 0))] 113 114 115def test_splitCubicAtT(): 116 assert splitCubicAtT( 117 (0, 0), (25, 100), (75, 100), (100, 0), 0.5 118 ) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)), 119 ((50, 75), (68.75, 75), (87.5, 50), (100, 0))] 120 assert splitCubicAtT( 121 (0, 0), (25, 100), (75, 100), (100, 0), 0.5, 0.75 122 ) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)), 123 ((50, 75), (59.375, 75), (68.75, 68.75), (77.34375, 56.25)), 124 ((77.34375, 56.25), (85.9375, 43.75), (93.75, 25), (100, 0))] 125 126 127def test_solveCubic(): 128 assert solveCubic(1, 1, -6, 0) == [-3.0, -0.0, 2.0] 129 assert solveCubic(-10.0, -9.0, 48.0, -29.0) == [-2.9, 1.0, 1.0] 130 assert solveCubic(-9.875, -9.0, 47.625, -28.75) == [-2.911392, 1.0, 1.0] 131 assert solveCubic(1.0, -4.5, 6.75, -3.375) == [1.5, 1.5, 1.5] 132 assert solveCubic(-12.0, 18.0, -9.0, 1.50023651123) == [0.5, 0.5, 0.5] 133 assert solveCubic(9.0, 0.0, 0.0, -7.62939453125e-05) == [-0.0, -0.0, -0.0] 134 135 136_segmentPointAtT_testData = [ 137 ([(0, 10), (200, 100)], 0.0, (0, 10)), 138 ([(0, 10), (200, 100)], 0.5, (100, 55)), 139 ([(0, 10), (200, 100)], 1.0, (200, 100)), 140 ([(0, 10), (100, 100), (200, 50)], 0.0, (0, 10)), 141 ([(0, 10), (100, 100), (200, 50)], 0.5, (100, 65.0)), 142 ([(0, 10), (100, 100), (200, 50)], 1.0, (200, 50.0)), 143 ([(0, 10), (100, 100), (200, 100), (300, 0)], 0.0, (0, 10)), 144 ([(0, 10), (100, 100), (200, 100), (300, 0)], 0.5, (150, 76.25)), 145 ([(0, 10), (100, 100), (200, 100), (300, 0)], 1.0, (300, 0)), 146] 147 148 149@pytest.mark.parametrize("segment, t, expectedPoint", _segmentPointAtT_testData) 150def test_segmentPointAtT(segment, t, expectedPoint): 151 point = segmentPointAtT(segment, t) 152 assert expectedPoint == point 153 154 155def test_intersections_straight_line(): 156 curve = ((548, 183), (548, 289), (450, 366), (315, 366)) 157 line1 = ((330, 376), (330, 286)) 158 pt = curveLineIntersections(curve, line1)[0][0] 159 assert pt[0] == 330 160 line = (pt, (330, 286)) 161 pt2 = (330.0001018806911, 295.5635754579425) 162 assert bezierTools._line_t_of_pt(*line, pt2) > 0 163 s = (19, 0) 164 e = (110, 0) 165 pt = (109.05194805194802, 0.0) 166 assert bezierTools._line_t_of_pt(s, e, pt) == pytest.approx(0.98958184) 167