pointInsidePen: add getWinding()
Resolves https://github.com/behdad/fonttools/issues/621#issuecomment-234764830 Although, leaving contours left open is out of protocol behavior IMO.
This commit is contained in:
parent
5cd0a55635
commit
f3ff2f8881
@ -40,29 +40,33 @@ class PointInsidePen(BasePen):
|
||||
# http://graphics.cs.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html
|
||||
# I extended the principles outlined on that page to curves.
|
||||
|
||||
def __init__(self, glyphSet, testPoint, evenOdd=0):
|
||||
def __init__(self, glyphSet, testPoint, evenOdd=False):
|
||||
BasePen.__init__(self, glyphSet)
|
||||
self.setTestPoint(testPoint, evenOdd)
|
||||
|
||||
def setTestPoint(self, testPoint, evenOdd=0):
|
||||
def setTestPoint(self, testPoint, evenOdd=False):
|
||||
"""Set the point to test. Call this _before_ the outline gets drawn."""
|
||||
self.testPoint = testPoint
|
||||
self.evenOdd = evenOdd
|
||||
self.firstPoint = None
|
||||
self.intersectionCount = 0
|
||||
|
||||
def getResult(self):
|
||||
"""After the shape has been drawn, getResult() returns True if the test
|
||||
point lies within the (black) shape, and False if it doesn't.
|
||||
"""
|
||||
def getWinding(self):
|
||||
if self.firstPoint is not None:
|
||||
# always make sure the sub paths are closed; the algorithm only works
|
||||
# for closed paths.
|
||||
self.closePath()
|
||||
return self.intersectionCount
|
||||
|
||||
def getResult(self):
|
||||
"""After the shape has been drawn, getResult() returns True if the test
|
||||
point lies within the (black) shape, and False if it doesn't.
|
||||
"""
|
||||
winding = self.getWinding()
|
||||
if self.evenOdd:
|
||||
result = self.intersectionCount % 2
|
||||
else:
|
||||
result = self.intersectionCount
|
||||
result = winding % 2
|
||||
else: # non-zero
|
||||
result = self.intersectionCount != 0
|
||||
return not not result
|
||||
|
||||
def _addIntersection(self, goingUp):
|
||||
|
@ -95,12 +95,12 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (750, 295)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
self.assertEqual(piPen.getResult(), False)
|
||||
|
||||
piPen = PointInsidePen(None, (835, 190)) # this point is inside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 1)
|
||||
self.assertEqual(piPen.getWinding(), 1)
|
||||
self.assertEqual(piPen.getResult(), True)
|
||||
|
||||
def test_contour_square_closed(self):
|
||||
@ -113,7 +113,7 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (0, 0)) # this point is inside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 1)
|
||||
self.assertEqual(piPen.getWinding(), 1)
|
||||
self.assertEqual(piPen.getResult(), True)
|
||||
|
||||
def test_contour_square_opened(self):
|
||||
@ -126,8 +126,8 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (0, 0)) # this point is inside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0) # value is different from square_closed
|
||||
self.assertEqual(piPen.getResult(), True) # "is inside" still True
|
||||
self.assertEqual(piPen.getWinding(), 1)
|
||||
self.assertEqual(piPen.getResult(), True)
|
||||
|
||||
def test_contour_circle(self):
|
||||
def draw_contour(pen):
|
||||
@ -155,19 +155,19 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (-200, 0)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
piPen = PointInsidePen(None, (-200, 100)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
piPen = PointInsidePen(None, (-200, -100)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
piPen = PointInsidePen(None, (-200, 50)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
def test_contour_integers(self):
|
||||
def draw_contour(pen):
|
||||
@ -180,7 +180,7 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (416, 783)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
def test_contour_decimals(self):
|
||||
def draw_contour(pen):
|
||||
@ -193,7 +193,7 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (416.625, 783.140625)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
def test_contour2_integers(self):
|
||||
def draw_contour(pen):
|
||||
@ -205,7 +205,7 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (21, 50)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
def test_contour2_decimals(self):
|
||||
def draw_contour(pen):
|
||||
@ -217,7 +217,7 @@ class PointInsidePenTest(unittest.TestCase):
|
||||
|
||||
piPen = PointInsidePen(None, (21.25, 50.0)) # this point is outside
|
||||
draw_contour(piPen)
|
||||
self.assertEqual(piPen.intersectionCount, 0)
|
||||
self.assertEqual(piPen.getWinding(), 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user