1from io import StringIO 2from fontTools.pens.pointInsidePen import PointInsidePen 3import unittest 4 5 6class PointInsidePenTest(unittest.TestCase): 7 def test_line(self): 8 def draw_triangles(pen): 9 pen.moveTo((0, 0)) 10 pen.lineTo((10, 5)) 11 pen.lineTo((10, 0)) 12 pen.moveTo((9, 1)) 13 pen.lineTo((4, 1)) 14 pen.lineTo((9, 4)) 15 pen.closePath() 16 17 self.assertEqual( 18 " *********" " ** *" " ** *" " * *" " *", 19 self.render(draw_triangles, even_odd=True), 20 ) 21 22 self.assertEqual( 23 " *********" " *******" " *****" " ***" " *", 24 self.render(draw_triangles, even_odd=False), 25 ) 26 27 def test_curve(self): 28 def draw_curves(pen): 29 pen.moveTo((0, 0)) 30 pen.curveTo((9, 1), (9, 4), (0, 5)) 31 pen.moveTo((10, 5)) 32 pen.curveTo((1, 4), (1, 1), (10, 0)) 33 pen.closePath() 34 35 self.assertEqual( 36 "*** ***" "**** ****" "*** ***" "**** ****" "*** ***", 37 self.render(draw_curves, even_odd=True), 38 ) 39 40 self.assertEqual( 41 "*** ***" "**********" "**********" "**********" "*** ***", 42 self.render(draw_curves, even_odd=False), 43 ) 44 45 def test_qCurve(self): 46 def draw_qCurves(pen): 47 pen.moveTo((0, 0)) 48 pen.qCurveTo((15, 2), (0, 5)) 49 pen.moveTo((10, 5)) 50 pen.qCurveTo((-5, 3), (10, 0)) 51 pen.closePath() 52 53 self.assertEqual( 54 "*** **" "**** ***" "*** ***" "*** ****" "** ***", 55 self.render(draw_qCurves, even_odd=True), 56 ) 57 58 self.assertEqual( 59 "*** **" "**********" "**********" "**********" "** ***", 60 self.render(draw_qCurves, even_odd=False), 61 ) 62 63 @staticmethod 64 def render(draw_function, even_odd): 65 result = StringIO() 66 for y in range(5): 67 for x in range(10): 68 pen = PointInsidePen(None, (x + 0.5, y + 0.5), even_odd) 69 draw_function(pen) 70 if pen.getResult(): 71 result.write("*") 72 else: 73 result.write(" ") 74 return result.getvalue() 75 76 def test_contour_no_solutions(self): 77 def draw_contour(pen): 78 pen.moveTo((969, 230)) 79 pen.curveTo((825, 348), (715, 184), (614, 202)) 80 pen.lineTo((614, 160)) 81 pen.lineTo((969, 160)) 82 pen.closePath() 83 84 piPen = PointInsidePen(None, (750, 295)) # this point is outside 85 draw_contour(piPen) 86 self.assertEqual(piPen.getWinding(), 0) 87 self.assertEqual(piPen.getResult(), False) 88 89 piPen = PointInsidePen(None, (835, 190)) # this point is inside 90 draw_contour(piPen) 91 self.assertEqual(piPen.getWinding(), 1) 92 self.assertEqual(piPen.getResult(), True) 93 94 def test_contour_square_closed(self): 95 def draw_contour(pen): 96 pen.moveTo((100, 100)) 97 pen.lineTo((-100, 100)) 98 pen.lineTo((-100, -100)) 99 pen.lineTo((100, -100)) 100 pen.closePath() 101 102 piPen = PointInsidePen(None, (0, 0)) # this point is inside 103 draw_contour(piPen) 104 self.assertEqual(piPen.getWinding(), 1) 105 self.assertEqual(piPen.getResult(), True) 106 107 def test_contour_square_opened(self): 108 def draw_contour(pen): 109 pen.moveTo((100, 100)) 110 pen.lineTo((-100, 100)) 111 pen.lineTo((-100, -100)) 112 pen.lineTo((100, -100)) 113 # contour not explicitly closed 114 115 piPen = PointInsidePen(None, (0, 0)) # this point is inside 116 draw_contour(piPen) 117 self.assertEqual(piPen.getWinding(), 1) 118 self.assertEqual(piPen.getResult(), True) 119 120 def test_contour_circle(self): 121 def draw_contour(pen): 122 pen.moveTo((0, 100)) 123 pen.curveTo((-55, 100), (-100, 55), (-100, 0)) 124 pen.curveTo((-100, -55), (-55, -100), (0, -100)) 125 pen.curveTo((55, -100), (100, -55), (100, 0)) 126 pen.curveTo((100, 55), (55, 100), (0, 100)) 127 128 piPen = PointInsidePen(None, (50, 50)) # this point is inside 129 draw_contour(piPen) 130 self.assertEqual(piPen.getResult(), True) 131 132 piPen = PointInsidePen(None, (50, -50)) # this point is inside 133 draw_contour(piPen) 134 self.assertEqual(piPen.getResult(), True) 135 136 def test_contour_diamond(self): 137 def draw_contour(pen): 138 pen.moveTo((0, 100)) 139 pen.lineTo((100, 0)) 140 pen.lineTo((0, -100)) 141 pen.lineTo((-100, 0)) 142 pen.closePath() 143 144 piPen = PointInsidePen(None, (-200, 0)) # this point is outside 145 draw_contour(piPen) 146 self.assertEqual(piPen.getWinding(), 0) 147 148 piPen = PointInsidePen(None, (-200, 100)) # this point is outside 149 draw_contour(piPen) 150 self.assertEqual(piPen.getWinding(), 0) 151 152 piPen = PointInsidePen(None, (-200, -100)) # this point is outside 153 draw_contour(piPen) 154 self.assertEqual(piPen.getWinding(), 0) 155 156 piPen = PointInsidePen(None, (-200, 50)) # this point is outside 157 draw_contour(piPen) 158 self.assertEqual(piPen.getWinding(), 0) 159 160 def test_contour_integers(self): 161 def draw_contour(pen): 162 pen.moveTo((728, 697)) 163 pen.lineTo((504, 699)) 164 pen.curveTo((487, 719), (508, 783), (556, 783)) 165 pen.lineTo((718, 783)) 166 pen.curveTo((739, 783), (749, 712), (728, 697)) 167 pen.closePath() 168 169 piPen = PointInsidePen(None, (416, 783)) # this point is outside 170 draw_contour(piPen) 171 self.assertEqual(piPen.getWinding(), 0) 172 173 def test_contour_decimals(self): 174 def draw_contour(pen): 175 pen.moveTo((727.546875, 697.0)) 176 pen.lineTo((504.375, 698.515625)) 177 pen.curveTo( 178 (487.328125, 719.359375), 179 (507.84375, 783.140625), 180 (555.796875, 783.140625), 181 ) 182 pen.lineTo((717.96875, 783.140625)) 183 pen.curveTo( 184 (738.890625, 783.140625), (748.796875, 711.5), (727.546875, 697.0) 185 ) 186 pen.closePath() 187 188 piPen = PointInsidePen(None, (416.625, 783.140625)) # this point is outside 189 draw_contour(piPen) 190 self.assertEqual(piPen.getWinding(), 0) 191 192 def test_contour2_integers(self): 193 def draw_contour(pen): 194 pen.moveTo((51, 22)) 195 pen.lineTo((51, 74)) 196 pen.lineTo((83, 50)) 197 pen.curveTo((83, 49), (82, 48), (82, 47)) 198 pen.closePath() 199 200 piPen = PointInsidePen(None, (21, 50)) # this point is outside 201 draw_contour(piPen) 202 self.assertEqual(piPen.getWinding(), 0) 203 204 def test_contour2_decimals(self): 205 def draw_contour(pen): 206 pen.moveTo((51.25, 21.859375)) 207 pen.lineTo((51.25, 73.828125)) 208 pen.lineTo((82.5, 50.0)) 209 pen.curveTo((82.5, 49.09375), (82.265625, 48.265625), (82.234375, 47.375)) 210 pen.closePath() 211 212 piPen = PointInsidePen(None, (21.25, 50.0)) # this point is outside 213 draw_contour(piPen) 214 self.assertEqual(piPen.getWinding(), 0) 215 216 217if __name__ == "__main__": 218 import sys 219 220 sys.exit(unittest.main()) 221