11import platform
22import re
3+ from collections import namedtuple
34
45import numpy as np
5-
66from numpy .testing import assert_array_equal
77import pytest
88
@@ -88,25 +88,27 @@ def test_contains_points_negative_radius():
8888 np .testing .assert_equal (result , [True , False , False ])
8989
9090
91- _test_paths = [
91+ _ExampleCurve = namedtuple ('ExampleCurve' , ['path' , 'extents' , 'area' ])
92+ _test_curves = [
9293 # interior extrema determine extents and degenerate derivative
93- Path ([[0 , 0 ], [1 , 0 ], [1 , 1 ], [0 , 1 ]],
94- [Path .MOVETO , Path .CURVE4 , Path .CURVE4 , Path .CURVE4 ]),
95- # a quadratic curve
96- Path ([[0 , 0 ], [0 , 1 ], [1 , 0 ]], [Path .MOVETO , Path .CURVE3 , Path .CURVE3 ]),
94+ _ExampleCurve (Path ([[0 , 0 ], [1 , 0 ], [1 , 1 ], [0 , 1 ]],
95+ [Path .MOVETO , Path .CURVE4 , Path .CURVE4 , Path .CURVE4 ]),
96+ extents = (0. , 0. , 0.75 , 1. ), area = 0.6 ),
97+ # a quadratic curve, clockwise
98+ _ExampleCurve (Path ([[0 , 0 ], [0 , 1 ], [1 , 0 ]],
99+ [Path .MOVETO , Path .CURVE3 , Path .CURVE3 ]),
100+ extents = (0. , 0. , 1. , 0.5 ), area = - 1 / 3 ),
97101 # a linear curve, degenerate vertically
98- Path ([[0 , 1 ], [1 , 1 ]], [Path .MOVETO , Path .LINETO ]),
102+ _ExampleCurve (Path ([[0 , 1 ], [1 , 1 ]], [Path .MOVETO , Path .LINETO ]),
103+ extents = (0. , 1. , 1. , 1. ), area = 0. ),
99104 # a point
100- Path ([[1 , 2 ]], [Path .MOVETO ]),
105+ _ExampleCurve (Path ([[1 , 2 ]], [Path .MOVETO ]), extents = (1. , 2. , 1. , 2. ),
106+ area = 0. ),
101107]
102108
103109
104- _test_path_extents = [(0. , 0. , 0.75 , 1. ), (0. , 0. , 1. , 0.5 ), (0. , 1. , 1. , 1. ),
105- (1. , 2. , 1. , 2. )]
106-
107-
108- @pytest .mark .parametrize ('path, extents' , zip (_test_paths , _test_path_extents ))
109- def test_exact_extents (path , extents ):
110+ @pytest .mark .parametrize ('precomputed_curve' , _test_curves )
111+ def test_exact_extents (precomputed_curve ):
110112 # notice that if we just looked at the control points to get the bounding
111113 # box of each curve, we would get the wrong answers. For example, for
112114 # hard_curve = Path([[0, 0], [1, 0], [1, 1], [0, 1]],
@@ -116,6 +118,7 @@ def test_exact_extents(path, extents):
116118 # the way out to the control points.
117119 # Note that counterintuitively, path.get_extents() returns a Bbox, so we
118120 # have to get that Bbox's `.extents`.
121+ path , extents = precomputed_curve .path , precomputed_curve .extents
119122 assert np .all (path .get_extents ().extents == extents )
120123
121124
@@ -129,6 +132,28 @@ def test_extents_with_ignored_codes(ignored_code):
129132 assert np .all (path .get_extents ().extents == (0. , 0. , 1. , 1. ))
130133
131134
135+ @pytest .mark .parametrize ('precomputed_curve' , _test_curves )
136+ def test_signed_area (precomputed_curve ):
137+ path , area = precomputed_curve .path , precomputed_curve .area
138+ assert np .isclose (path .signed_area (), area )
139+ # now flip direction, sign of *signed_area* should flip
140+ rcurve = Path (path .vertices [::- 1 ], path .codes )
141+ assert np .isclose (rcurve .signed_area (), - area )
142+
143+
144+ def test_signed_area_unit_rectangle ():
145+ rect = Path .unit_rectangle ()
146+ assert np .isclose (rect .signed_area (), 1 )
147+
148+
149+ def test_signed_area_unit_circle ():
150+ circ = Path .unit_circle ()
151+ # Not a "real" circle, just an approximation of a circle made out of bezier
152+ # curves. The actual value is 3.1415935732517166, which is close enough to
153+ # pass here.
154+ assert np .isclose (circ .signed_area (), np .pi )
155+
156+
132157def test_point_in_path_nan ():
133158 box = np .array ([[0 , 0 ], [1 , 0 ], [1 , 1 ], [0 , 1 ], [0 , 0 ]])
134159 p = Path (box )
0 commit comments