[varLib] Support extrapolation
Fixes https://github.com/fonttools/fonttools/issues/1252
This commit is contained in:
parent
fce82adba2
commit
bad70c68ef
@ -116,7 +116,7 @@ def normalizeLocation(location, axes):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def supportScalar(location, support, ot=True):
|
def supportScalar(location, support, ot=True, extrapolate=False):
|
||||||
"""Returns the scalar multiplier at location, for a master
|
"""Returns the scalar multiplier at location, for a master
|
||||||
with support. If ot is True, then a peak value of zero
|
with support. If ot is True, then a peak value of zero
|
||||||
for support of an axis means "axis does not participate". That
|
for support of an axis means "axis does not participate". That
|
||||||
@ -138,6 +138,10 @@ def supportScalar(location, support, ot=True):
|
|||||||
0.75
|
0.75
|
||||||
>>> supportScalar({'wght':2.5, 'wdth':.5}, {'wght':(0,2,4), 'wdth':(-1,0,+1)})
|
>>> supportScalar({'wght':2.5, 'wdth':.5}, {'wght':(0,2,4), 'wdth':(-1,0,+1)})
|
||||||
0.75
|
0.75
|
||||||
|
>>> supportScalar({'wght':4}, {'wght':(0,2,3)}, extrapolate=True)
|
||||||
|
2.0
|
||||||
|
>>> supportScalar({'wght':4}, {'wght':(0,2,2)}, extrapolate=True)
|
||||||
|
2.0
|
||||||
"""
|
"""
|
||||||
scalar = 1.0
|
scalar = 1.0
|
||||||
for axis, (lower, peak, upper) in support.items():
|
for axis, (lower, peak, upper) in support.items():
|
||||||
@ -155,9 +159,27 @@ def supportScalar(location, support, ot=True):
|
|||||||
v = location[axis]
|
v = location[axis]
|
||||||
if v == peak:
|
if v == peak:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if extrapolate:
|
||||||
|
if v < -1 and lower <= -1:
|
||||||
|
if peak <= -1 and peak < upper:
|
||||||
|
scalar *= (v - upper) / (peak - upper)
|
||||||
|
continue
|
||||||
|
elif -1 < peak:
|
||||||
|
scalar *= (v - lower) / (peak - lower)
|
||||||
|
continue
|
||||||
|
elif +1 < v and +1 <= upper:
|
||||||
|
if +1 <= peak and lower < peak:
|
||||||
|
scalar *= (v - lower) / (peak - lower)
|
||||||
|
continue
|
||||||
|
elif peak < +1:
|
||||||
|
scalar *= (v - upper) / (peak - upper)
|
||||||
|
continue
|
||||||
|
|
||||||
if v <= lower or upper <= v:
|
if v <= lower or upper <= v:
|
||||||
scalar = 0.0
|
scalar = 0.0
|
||||||
break
|
break
|
||||||
|
|
||||||
if v < peak:
|
if v < peak:
|
||||||
scalar *= (v - lower) / (peak - lower)
|
scalar *= (v - lower) / (peak - lower)
|
||||||
else: # v > peak
|
else: # v > peak
|
||||||
@ -169,7 +191,7 @@ class VariationModel(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
Locations must be in normalized space. Ie. base master
|
Locations must be in normalized space. Ie. base master
|
||||||
is at origin (0)::
|
is at origin (0).
|
||||||
|
|
||||||
>>> from pprint import pprint
|
>>> from pprint import pprint
|
||||||
>>> locations = [ \
|
>>> locations = [ \
|
||||||
@ -206,12 +228,14 @@ class VariationModel(object):
|
|||||||
{0: 1.0, 3: 0.75, 4: 0.25, 5: 0.6666666666666667}]
|
{0: 1.0, 3: 0.75, 4: 0.25, 5: 0.6666666666666667}]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, locations, axisOrder=None):
|
def __init__(self, locations, axisOrder=None, extrapolate=False):
|
||||||
|
|
||||||
if len(set(tuple(sorted(l.items())) for l in locations)) != len(locations):
|
if len(set(tuple(sorted(l.items())) for l in locations)) != len(locations):
|
||||||
raise VariationModelError("Locations must be unique.")
|
raise VariationModelError("Locations must be unique.")
|
||||||
|
|
||||||
self.origLocations = locations
|
self.origLocations = locations
|
||||||
self.axisOrder = axisOrder if axisOrder is not None else []
|
self.axisOrder = axisOrder if axisOrder is not None else []
|
||||||
|
self.extrapolate = extrapolate
|
||||||
|
|
||||||
locations = [{k: v for k, v in loc.items() if v != 0.0} for loc in locations]
|
locations = [{k: v for k, v in loc.items() if v != 0.0} for loc in locations]
|
||||||
keyFunc = self.getMasterLocationsSortKeyFunc(
|
keyFunc = self.getMasterLocationsSortKeyFunc(
|
||||||
@ -435,7 +459,8 @@ class VariationModel(object):
|
|||||||
return model.getDeltas(items, round=round), model.supports
|
return model.getDeltas(items, round=round), model.supports
|
||||||
|
|
||||||
def getScalars(self, loc):
|
def getScalars(self, loc):
|
||||||
return [supportScalar(loc, support) for support in self.supports]
|
return [supportScalar(loc, support, extrapolate=self.extrapolate)
|
||||||
|
for support in self.supports]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def interpolateFromDeltasAndScalars(deltas, scalars):
|
def interpolateFromDeltasAndScalars(deltas, scalars):
|
||||||
|
@ -36,6 +36,10 @@ def test_supportScalar():
|
|||||||
assert supportScalar({"wght": 0.2}, {}) == 1.0
|
assert supportScalar({"wght": 0.2}, {}) == 1.0
|
||||||
assert supportScalar({"wght": 0.2}, {"wght": (0, 2, 3)}) == 0.1
|
assert supportScalar({"wght": 0.2}, {"wght": (0, 2, 3)}) == 0.1
|
||||||
assert supportScalar({"wght": 2.5}, {"wght": (0, 2, 4)}) == 0.75
|
assert supportScalar({"wght": 2.5}, {"wght": (0, 2, 4)}) == 0.75
|
||||||
|
assert supportScalar({"wght": 4}, {"wght": (0, 2, 2)}) == 0.0
|
||||||
|
assert supportScalar({"wght": 4}, {"wght": (0, 2, 2)}, extrapolate=True) == 2.0
|
||||||
|
assert supportScalar({"wght": 4}, {"wght": (0, 2, 3)}, extrapolate=True) == 2.0
|
||||||
|
assert supportScalar({"wght": 2}, {"wght": (0, .75, 1)}, extrapolate=True) == -4.0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user