parent
9c037fc826
commit
81d84e6f85
@ -18,8 +18,8 @@ __all__ = [
|
|||||||
|
|
||||||
from fontTools.misc.arrayTools import calcBounds
|
from fontTools.misc.arrayTools import calcBounds
|
||||||
|
|
||||||
epsilonDigits = 12
|
epsilonDigits = 6
|
||||||
epsilon = 1e-12
|
epsilon = 1e-10
|
||||||
|
|
||||||
|
|
||||||
def calcQuadraticBounds(pt1, pt2, pt3):
|
def calcQuadraticBounds(pt1, pt2, pt3):
|
||||||
|
@ -11,12 +11,6 @@ from fontTools.misc.bezierTools import solveQuadratic, solveCubic
|
|||||||
__all__ = ["PointInsidePen"]
|
__all__ = ["PointInsidePen"]
|
||||||
|
|
||||||
|
|
||||||
# working around floating point errors
|
|
||||||
EPSILON = 1e-10
|
|
||||||
ONE_PLUS_EPSILON = 1 + EPSILON
|
|
||||||
ZERO_MINUS_EPSILON = 0 - EPSILON
|
|
||||||
|
|
||||||
|
|
||||||
class PointInsidePen(BasePen):
|
class PointInsidePen(BasePen):
|
||||||
|
|
||||||
"""This pen implements "point inside" testing: to test whether
|
"""This pen implements "point inside" testing: to test whether
|
||||||
@ -123,7 +117,7 @@ class PointInsidePen(BasePen):
|
|||||||
by = (y3 - y2) * 3.0 - cy
|
by = (y3 - y2) * 3.0 - cy
|
||||||
ay = y4 - dy - cy - by
|
ay = y4 - dy - cy - by
|
||||||
solutions = sorted(solveCubic(ay, by, cy, dy - y))
|
solutions = sorted(solveCubic(ay, by, cy, dy - y))
|
||||||
solutions = [t for t in solutions if ZERO_MINUS_EPSILON <= t <= ONE_PLUS_EPSILON]
|
solutions = [t for t in solutions if -0. <= t <= 1.]
|
||||||
if not solutions:
|
if not solutions:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -142,29 +136,30 @@ class PointInsidePen(BasePen):
|
|||||||
t3 = t2 * t
|
t3 = t2 * t
|
||||||
|
|
||||||
direction = 3*ay*t2 + 2*by*t + cy
|
direction = 3*ay*t2 + 2*by*t + cy
|
||||||
|
incomingGoingUp = outgoingGoingUp = direction > 0.0
|
||||||
if direction == 0.0:
|
if direction == 0.0:
|
||||||
direction = 6*ay*t + 2*by
|
direction = 6*ay*t + 2*by
|
||||||
|
outgoingGoingUp = direction > 0.0
|
||||||
|
incomingGoingUp = not outgoingGoingUp
|
||||||
if direction == 0.0:
|
if direction == 0.0:
|
||||||
direction = ay
|
direction = ay
|
||||||
goingUp = direction > 0.0
|
incomingGoingUp = outgoingGoingUp = direction > 0.0
|
||||||
|
|
||||||
xt = ax*t3 + bx*t2 + cx*t + dx
|
xt = ax*t3 + bx*t2 + cx*t + dx
|
||||||
if xt < x:
|
if xt < x:
|
||||||
above = goingUp
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if t == 0.0:
|
if t in (0.0, -0.0):
|
||||||
if not goingUp:
|
if not outgoingGoingUp:
|
||||||
self._addIntersection(goingUp)
|
self._addIntersection(outgoingGoingUp)
|
||||||
elif t == 1.0:
|
elif t == 1.0:
|
||||||
if not above:
|
if incomingGoingUp:
|
||||||
self._addIntersection(goingUp)
|
self._addIntersection(incomingGoingUp)
|
||||||
else:
|
else:
|
||||||
if above != goingUp:
|
if incomingGoingUp == outgoingGoingUp:
|
||||||
self._addIntersection(goingUp)
|
self._addIntersection(outgoingGoingUp)
|
||||||
#else:
|
#else:
|
||||||
# we're not really intersecting, merely touching the 'top'
|
# we're not really intersecting, merely touching
|
||||||
above = goingUp
|
|
||||||
|
|
||||||
def _qCurveToOne_unfinished(self, bcp, point):
|
def _qCurveToOne_unfinished(self, bcp, point):
|
||||||
# XXX need to finish this, for now doing it through a cubic
|
# XXX need to finish this, for now doing it through a cubic
|
||||||
|
@ -71,34 +71,6 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
"** ***",
|
"** ***",
|
||||||
self.render(draw_qCurves, even_odd=False))
|
self.render(draw_qCurves, even_odd=False))
|
||||||
|
|
||||||
def test_contour_integers(self):
|
|
||||||
def draw_contour(pen):
|
|
||||||
pen.moveTo( (728, 697) )
|
|
||||||
pen.curveTo( (723, 698) , (718, 699) , (713, 699) )
|
|
||||||
pen.lineTo( (504, 699) )
|
|
||||||
pen.curveTo( (487, 719) , (508, 783) , (556, 783) )
|
|
||||||
pen.lineTo( (718, 783) )
|
|
||||||
pen.curveTo( (739, 783) , (749, 712) , (728, 697) )
|
|
||||||
pen.closePath()
|
|
||||||
|
|
||||||
piPen = PointInsidePen(None, (416, 783)) # this point is outside
|
|
||||||
draw_contour(piPen)
|
|
||||||
self.assertEqual(piPen.getResult(), False)
|
|
||||||
|
|
||||||
def test_contour_decimals(self):
|
|
||||||
def draw_contour(pen):
|
|
||||||
pen.moveTo( (727.546875, 697.0) )
|
|
||||||
pen.curveTo( (722.953125, 697.953125), (718.109375, 698.515625), (712.9375, 698.515625) )
|
|
||||||
pen.lineTo( (504.375, 698.515625) )
|
|
||||||
pen.curveTo( (487.328125, 719.359375), (507.84375, 783.140625), (555.796875, 783.140625) )
|
|
||||||
pen.lineTo( (717.96875, 783.140625) )
|
|
||||||
pen.curveTo( (738.890625, 783.140625), (748.796875, 711.5), (727.546875, 697.0) )
|
|
||||||
pen.closePath()
|
|
||||||
|
|
||||||
piPen = PointInsidePen(None, (416.625, 783.140625)) # this point is outside
|
|
||||||
draw_contour(piPen)
|
|
||||||
self.assertEqual(piPen.getResult(), False)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def render(draw_function, even_odd):
|
def render(draw_function, even_odd):
|
||||||
result = BytesIO()
|
result = BytesIO()
|
||||||
@ -113,6 +85,56 @@ class PointInsidePenTest(unittest.TestCase):
|
|||||||
return tounicode(result.getvalue())
|
return tounicode(result.getvalue())
|
||||||
|
|
||||||
|
|
||||||
|
def test_contour_diamond(self):
|
||||||
|
def draw_contour(pen):
|
||||||
|
pen.moveTo( (0, 100) )
|
||||||
|
pen.lineTo( (100, 0) )
|
||||||
|
pen.lineTo( (0, -100) )
|
||||||
|
pen.lineTo( (-100, 0) )
|
||||||
|
pen.closePath()
|
||||||
|
|
||||||
|
piPen = PointInsidePen(None, (-200, 0)) # this point is outside
|
||||||
|
draw_contour(piPen)
|
||||||
|
self.assertEqual(piPen.intersectionCount, 0)
|
||||||
|
|
||||||
|
piPen = PointInsidePen(None, (-200, 100)) # this point is outside
|
||||||
|
draw_contour(piPen)
|
||||||
|
self.assertEqual(piPen.intersectionCount, 0)
|
||||||
|
|
||||||
|
piPen = PointInsidePen(None, (-200, -100)) # this point is outside
|
||||||
|
draw_contour(piPen)
|
||||||
|
self.assertEqual(piPen.intersectionCount, 0)
|
||||||
|
|
||||||
|
piPen = PointInsidePen(None, (-200, 50)) # this point is outside
|
||||||
|
draw_contour(piPen)
|
||||||
|
self.assertEqual(piPen.intersectionCount, 0)
|
||||||
|
|
||||||
|
def test_contour_integers(self):
|
||||||
|
def draw_contour(pen):
|
||||||
|
pen.moveTo( (728, 697) )
|
||||||
|
pen.lineTo( (504, 699) )
|
||||||
|
pen.curveTo( (487, 719) , (508, 783) , (556, 783) )
|
||||||
|
pen.lineTo( (718, 783) )
|
||||||
|
pen.curveTo( (739, 783) , (749, 712) , (728, 697) )
|
||||||
|
pen.closePath()
|
||||||
|
|
||||||
|
piPen = PointInsidePen(None, (416, 783)) # this point is outside
|
||||||
|
draw_contour(piPen)
|
||||||
|
self.assertEqual(piPen.intersectionCount, 0)
|
||||||
|
|
||||||
|
def test_contour_decimals(self):
|
||||||
|
def draw_contour(pen):
|
||||||
|
pen.moveTo( (727.546875, 697.0) )
|
||||||
|
pen.lineTo( (504.375, 698.515625) )
|
||||||
|
pen.curveTo( (487.328125, 719.359375), (507.84375, 783.140625), (555.796875, 783.140625) )
|
||||||
|
pen.lineTo( (717.96875, 783.140625) )
|
||||||
|
pen.curveTo( (738.890625, 783.140625), (748.796875, 711.5), (727.546875, 697.0) )
|
||||||
|
pen.closePath()
|
||||||
|
|
||||||
|
piPen = PointInsidePen(None, (416.625, 783.140625)) # this point is outside
|
||||||
|
draw_contour(piPen)
|
||||||
|
self.assertEqual(piPen.intersectionCount, 0)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user