[colorLib.geometry] use math.isclose with relative tolerance to check circle inside-ness
Fixes rounding of radial gradient in 'SING OF THE HORNS' (medium-light skin tone) noto emoji 🤘🏼
This commit is contained in:
parent
69fc06a1af
commit
5558ccd3bb
@ -1,6 +1,6 @@
|
|||||||
"""Helpers for manipulating 2D points and vectors in COLR table."""
|
"""Helpers for manipulating 2D points and vectors in COLR table."""
|
||||||
|
|
||||||
from math import copysign, cos, hypot, pi
|
from math import copysign, cos, hypot, isclose, pi
|
||||||
from fontTools.misc.roundTools import otRound
|
from fontTools.misc.roundTools import otRound
|
||||||
|
|
||||||
|
|
||||||
@ -19,9 +19,7 @@ def _unit_vector(vec):
|
|||||||
return (vec[0] / length, vec[1] / length)
|
return (vec[0] / length, vec[1] / length)
|
||||||
|
|
||||||
|
|
||||||
# This is the same tolerance used by Skia's SkTwoPointConicalGradient.cpp to detect
|
_CIRCLE_INSIDE_TOLERANCE = 1e-4
|
||||||
# when a radial gradient's focal point lies on the end circle.
|
|
||||||
_NEARLY_ZERO = 1 / (1 << 12) # 0.000244140625
|
|
||||||
|
|
||||||
|
|
||||||
# The unit vector's X and Y components are respectively
|
# The unit vector's X and Y components are respectively
|
||||||
@ -64,10 +62,10 @@ class Circle:
|
|||||||
def round(self):
|
def round(self):
|
||||||
return Circle(_round_point(self.centre), otRound(self.radius))
|
return Circle(_round_point(self.centre), otRound(self.radius))
|
||||||
|
|
||||||
def inside(self, outer_circle):
|
def inside(self, outer_circle, tolerance=_CIRCLE_INSIDE_TOLERANCE):
|
||||||
dist = self.radius + hypot(*_vector_between(self.centre, outer_circle.centre))
|
dist = self.radius + hypot(*_vector_between(self.centre, outer_circle.centre))
|
||||||
return (
|
return (
|
||||||
abs(outer_circle.radius - dist) <= _NEARLY_ZERO
|
isclose(outer_circle.radius, dist, rel_tol=_CIRCLE_INSIDE_TOLERANCE)
|
||||||
or outer_circle.radius > dist
|
or outer_circle.radius > dist
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1747,6 +1747,16 @@ class TrickyRadialGradientTest:
|
|||||||
r1 = 260.0072
|
r1 = 260.0072
|
||||||
assert self.round_start_circle(c0, r0, c1, r1, inside=True) == ((386, 71), 0)
|
assert self.round_start_circle(c0, r0, c1, r1, inside=True) == ((386, 71), 0)
|
||||||
|
|
||||||
|
def test_noto_emoji_horns_sign_u1f918_1f3fc(self):
|
||||||
|
# This radial gradient is taken from noto-emoji's 'SIGNS OF THE HORNS'
|
||||||
|
# (1f918_1f3fc). We check that c0 is inside c1 both before and after rounding.
|
||||||
|
c0 = (-437.6789059060543, -2116.9237094478003)
|
||||||
|
r0 = 0.0
|
||||||
|
c1 = (-488.7330118252256, -1876.5036857045086)
|
||||||
|
r1 = 245.77147821915673
|
||||||
|
assert self.circle_inside_circle(c0, r0, c1, r1)
|
||||||
|
assert self.circle_inside_circle(c0, r0, c1, r1, rounded=True)
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"c0, r0, c1, r1, inside, expected",
|
"c0, r0, c1, r1, inside, expected",
|
||||||
[
|
[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user