xref: /aosp_15_r20/external/fonttools/Tests/pens/pointInsidePen_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
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