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
|
# http://graphics.cs.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html
|
||||||
# I extended the principles outlined on that page to curves.
|
# 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)
|
BasePen.__init__(self, glyphSet)
|
||||||
self.setTestPoint(testPoint, evenOdd)
|
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."""
|
"""Set the point to test. Call this _before_ the outline gets drawn."""
|
||||||
self.testPoint = testPoint
|
self.testPoint = testPoint
|
||||||
self.evenOdd = evenOdd
|
self.evenOdd = evenOdd
|
||||||
self.firstPoint = None
|
self.firstPoint = None
|
||||||
self.intersectionCount = 0
|
self.intersectionCount = 0
|
||||||
|
|
||||||
def getResult(self):
|
def getWinding(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.
|
|
||||||
"""
|
|
||||||
if self.firstPoint is not None:
|
if self.firstPoint is not None:
|
||||||
# always make sure the sub paths are closed; the algorithm only works
|
# always make sure the sub paths are closed; the algorithm only works
|
||||||
# for closed paths.
|
# for closed paths.
|
||||||
self.closePath()
|
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:
|
if self.evenOdd:
|
||||||
result = self.intersectionCount % 2
|
result = winding % 2
|
||||||
else:
|
else: # non-zero
|
||||||
result = self.intersectionCount
|
result = self.intersectionCount != 0
|
||||||
return not not result
|
return not not result
|
||||||
|
|
||||||
def _addIntersection(self, goingUp):
|
def _addIntersection(self, goingUp):
|
||||||
|
@ -95,12 +95,12 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (750, 295)) # this point is outside
|
piPen = PointInsidePen(None, (750, 295)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
self.assertEqual(piPen.getResult(), False)
|
self.assertEqual(piPen.getResult(), False)
|
||||||
|
|
||||||
piPen = PointInsidePen(None, (835, 190)) # this point is inside
|
piPen = PointInsidePen(None, (835, 190)) # this point is inside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 1)
|
self.assertEqual(piPen.getWinding(), 1)
|
||||||
self.assertEqual(piPen.getResult(), True)
|
self.assertEqual(piPen.getResult(), True)
|
||||||
|
|
||||||
def test_contour_square_closed(self):
|
def test_contour_square_closed(self):
|
||||||
@ -113,7 +113,7 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (0, 0)) # this point is inside
|
piPen = PointInsidePen(None, (0, 0)) # this point is inside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 1)
|
self.assertEqual(piPen.getWinding(), 1)
|
||||||
self.assertEqual(piPen.getResult(), True)
|
self.assertEqual(piPen.getResult(), True)
|
||||||
|
|
||||||
def test_contour_square_opened(self):
|
def test_contour_square_opened(self):
|
||||||
@ -126,8 +126,8 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (0, 0)) # this point is inside
|
piPen = PointInsidePen(None, (0, 0)) # this point is inside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0) # value is different from square_closed
|
self.assertEqual(piPen.getWinding(), 1)
|
||||||
self.assertEqual(piPen.getResult(), True) # "is inside" still True
|
self.assertEqual(piPen.getResult(), True)
|
||||||
|
|
||||||
def test_contour_circle(self):
|
def test_contour_circle(self):
|
||||||
def draw_contour(pen):
|
def draw_contour(pen):
|
||||||
@ -155,19 +155,19 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (-200, 0)) # this point is outside
|
piPen = PointInsidePen(None, (-200, 0)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
piPen = PointInsidePen(None, (-200, 100)) # this point is outside
|
piPen = PointInsidePen(None, (-200, 100)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
piPen = PointInsidePen(None, (-200, -100)) # this point is outside
|
piPen = PointInsidePen(None, (-200, -100)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
piPen = PointInsidePen(None, (-200, 50)) # this point is outside
|
piPen = PointInsidePen(None, (-200, 50)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
def test_contour_integers(self):
|
def test_contour_integers(self):
|
||||||
def draw_contour(pen):
|
def draw_contour(pen):
|
||||||
@ -180,7 +180,7 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (416, 783)) # this point is outside
|
piPen = PointInsidePen(None, (416, 783)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
def test_contour_decimals(self):
|
def test_contour_decimals(self):
|
||||||
def draw_contour(pen):
|
def draw_contour(pen):
|
||||||
@ -193,7 +193,7 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (416.625, 783.140625)) # this point is outside
|
piPen = PointInsidePen(None, (416.625, 783.140625)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
def test_contour2_integers(self):
|
def test_contour2_integers(self):
|
||||||
def draw_contour(pen):
|
def draw_contour(pen):
|
||||||
@ -205,7 +205,7 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (21, 50)) # this point is outside
|
piPen = PointInsidePen(None, (21, 50)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
def test_contour2_decimals(self):
|
def test_contour2_decimals(self):
|
||||||
def draw_contour(pen):
|
def draw_contour(pen):
|
||||||
@ -217,7 +217,7 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
|
|
||||||
piPen = PointInsidePen(None, (21.25, 50.0)) # this point is outside
|
piPen = PointInsidePen(None, (21.25, 50.0)) # this point is outside
|
||||||
draw_contour(piPen)
|
draw_contour(piPen)
|
||||||
self.assertEqual(piPen.intersectionCount, 0)
|
self.assertEqual(piPen.getWinding(), 0)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user