instancer: convert item to tuple varstore to reuse same partial istancing code
This commit is contained in:
parent
4a7ab3fee2
commit
8aa57fef81
@ -12,10 +12,12 @@ NOTE: The module is experimental and both the API and the CLI *will* change.
|
||||
"""
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.misc.fixedTools import floatToFixedToFloat, otRound
|
||||
from fontTools.misc.fixedTools import floatToFixedToFloat
|
||||
from fontTools.varLib.models import supportScalar, normalizeValue, piecewiseLinearMap
|
||||
from fontTools.ttLib import TTFont
|
||||
from fontTools.ttLib.tables.TupleVariation import TupleVariation
|
||||
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
|
||||
from fontTools.varLib import builder
|
||||
from fontTools.varLib.mvar import MVAR_ENTRIES
|
||||
import collections
|
||||
from copy import deepcopy
|
||||
@ -150,13 +152,12 @@ def setMvarDeltas(varfont, deltaArray):
|
||||
tableTag, itemName = MVAR_ENTRIES[mvarTag]
|
||||
varDataIndex = rec.VarIdx >> 16
|
||||
itemIndex = rec.VarIdx & 0xFFFF
|
||||
deltaRow = deltaArray[varDataIndex][itemIndex]
|
||||
delta = sum(deltaRow)
|
||||
delta = deltaArray[varDataIndex][itemIndex]
|
||||
if delta != 0:
|
||||
setattr(
|
||||
varfont[tableTag],
|
||||
itemName,
|
||||
getattr(varfont[tableTag], itemName) + otRound(delta),
|
||||
getattr(varfont[tableTag], itemName) + delta,
|
||||
)
|
||||
|
||||
|
||||
@ -178,116 +179,111 @@ def instantiateMvar(varfont, location):
|
||||
del varfont["MVAR"]
|
||||
|
||||
|
||||
def _getVarRegionAxes(region, fvarAxes):
|
||||
# map fvar axes tags to VarRegionAxis in VarStore region, excluding axes that
|
||||
# don't participate (peak == 0)
|
||||
axes = {}
|
||||
assert len(fvarAxes) == len(region.VarRegionAxis)
|
||||
for fvarAxis, regionAxis in zip(fvarAxes, region.VarRegionAxis):
|
||||
if regionAxis.PeakCoord != 0:
|
||||
axes[fvarAxis.axisTag] = regionAxis
|
||||
return axes
|
||||
class _TupleVarStoreAdapter(object):
|
||||
def __init__(self, regions, axisOrder, tupleVarData, itemCounts):
|
||||
self.regions = regions
|
||||
self.axisOrder = axisOrder
|
||||
self.tupleVarData = tupleVarData
|
||||
self.itemCounts = itemCounts
|
||||
|
||||
|
||||
def _getVarRegionScalar(location, regionAxes):
|
||||
# compute partial product of per-axis scalars at location, excluding the axes
|
||||
# that are not pinned
|
||||
pinnedAxes = {
|
||||
axisTag: (axis.StartCoord, axis.PeakCoord, axis.EndCoord)
|
||||
for axisTag, axis in regionAxes.items()
|
||||
if axisTag in location
|
||||
}
|
||||
return supportScalar(location, pinnedAxes)
|
||||
|
||||
|
||||
def _scaleVarDataDeltas(varData, regionScalars):
|
||||
# multiply all varData deltas in-place by the corresponding region scalar
|
||||
varRegionCount = len(varData.VarRegionIndex)
|
||||
scalars = [regionScalars[regionIndex] for regionIndex in varData.VarRegionIndex]
|
||||
for item in varData.Item:
|
||||
assert len(item) == varRegionCount
|
||||
item[:] = [delta * scalar for delta, scalar in zip(item, scalars)]
|
||||
|
||||
|
||||
def _getVarDataDeltasForRegions(varData, regionIndices, rounded=False):
|
||||
# Get only the deltas that correspond to the given regions (optionally, rounded).
|
||||
# Returns: list of lists of float
|
||||
varRegionIndices = varData.VarRegionIndex
|
||||
deltaSets = []
|
||||
for item in varData.Item:
|
||||
deltaSets.append(
|
||||
[
|
||||
delta if not rounded else otRound(delta)
|
||||
for regionIndex, delta in zip(varRegionIndices, item)
|
||||
if regionIndex in regionIndices
|
||||
]
|
||||
)
|
||||
return deltaSets
|
||||
|
||||
|
||||
def _subsetVarStoreRegions(varStore, regionIndices):
|
||||
# drop regions not in regionIndices
|
||||
for varData in varStore.VarData:
|
||||
if regionIndices.isdisjoint(varData.VarRegionIndex):
|
||||
# empty VarData subtable if we remove all the regions referenced by it
|
||||
varData.Item = [[] for _ in range(varData.ItemCount)]
|
||||
varData.VarRegionIndex = []
|
||||
varData.VarRegionCount = varData.NumShorts = 0
|
||||
continue
|
||||
|
||||
# only retain delta-set columns that correspond to the given regions
|
||||
varData.Item = _getVarDataDeltasForRegions(varData, regionIndices, rounded=True)
|
||||
varData.VarRegionIndex = [
|
||||
ri for ri in varData.VarRegionIndex if ri in regionIndices
|
||||
@classmethod
|
||||
def fromItemVarStore(cls, itemVarStore, fvarAxes):
|
||||
axisOrder = [axis.axisTag for axis in fvarAxes]
|
||||
regions = [
|
||||
region.get_support(fvarAxes) for region in itemVarStore.VarRegionList.Region
|
||||
]
|
||||
varData.VarRegionCount = len(varData.VarRegionIndex)
|
||||
tupleVarData = []
|
||||
itemCounts = []
|
||||
for varData in itemVarStore.VarData:
|
||||
variations = []
|
||||
varDataRegions = (regions[i] for i in varData.VarRegionIndex)
|
||||
for axes, coordinates in zip(varDataRegions, zip(*varData.Item)):
|
||||
variations.append(TupleVariation(axes, list(coordinates)))
|
||||
tupleVarData.append(variations)
|
||||
itemCounts.append(varData.ItemCount)
|
||||
return cls(regions, axisOrder, tupleVarData, itemCounts)
|
||||
|
||||
# recalculate NumShorts, reordering columns as necessary
|
||||
varData.optimize()
|
||||
def dropAxes(self, axes):
|
||||
prunedRegions = (
|
||||
frozenset(
|
||||
(axisTag, support)
|
||||
for axisTag, support in region.items()
|
||||
if axisTag not in axes
|
||||
)
|
||||
for region in self.regions
|
||||
)
|
||||
# dedup regions while keeping original order
|
||||
uniqueRegions = collections.OrderedDict.fromkeys(prunedRegions)
|
||||
self.regions = [dict(items) for items in uniqueRegions if items]
|
||||
# TODO(anthrotype) uncomment this once we support subsetting fvar axes
|
||||
# self.axisOrder = [
|
||||
# axisTag for axisTag in self.axisOrder if axisTag not in axes
|
||||
# ]
|
||||
|
||||
# remove unused regions from VarRegionList
|
||||
varStore.prune_regions()
|
||||
def instantiate(self, location):
|
||||
defaultDeltaArray = []
|
||||
for variations, itemCount in zip(self.tupleVarData, self.itemCounts):
|
||||
defaultDeltas = instantiateTupleVariationStore(variations, location)
|
||||
if not defaultDeltas:
|
||||
defaultDeltas = [0] * itemCount
|
||||
defaultDeltaArray.append(defaultDeltas)
|
||||
|
||||
# remove pinned axes from all the regions
|
||||
self.dropAxes(location.keys())
|
||||
|
||||
return defaultDeltaArray
|
||||
|
||||
def asItemVarStore(self):
|
||||
regionOrder = [frozenset(axes.items()) for axes in self.regions]
|
||||
varDatas = []
|
||||
for variations, itemCount in zip(self.tupleVarData, self.itemCounts):
|
||||
if variations:
|
||||
assert len(variations[0].coordinates) == itemCount
|
||||
varRegionIndices = [
|
||||
regionOrder.index(frozenset(var.axes.items())) for var in variations
|
||||
]
|
||||
varDataItems = list(zip(*(var.coordinates for var in variations)))
|
||||
varDatas.append(
|
||||
builder.buildVarData(varRegionIndices, varDataItems, optimize=False)
|
||||
)
|
||||
else:
|
||||
varDatas.append(
|
||||
builder.buildVarData([], [[] for _ in range(itemCount)])
|
||||
)
|
||||
regionList = builder.buildVarRegionList(self.regions, self.axisOrder)
|
||||
itemVarStore = builder.buildVarStore(regionList, varDatas)
|
||||
return itemVarStore
|
||||
|
||||
|
||||
def instantiateItemVariationStore(varStore, fvarAxes, location):
|
||||
regions = [
|
||||
_getVarRegionAxes(reg, fvarAxes) for reg in varStore.VarRegionList.Region
|
||||
]
|
||||
# for each region, compute the scalar support of the axes to be pinned at the
|
||||
# desired location, and scale the deltas accordingly
|
||||
regionScalars = [_getVarRegionScalar(location, axes) for axes in regions]
|
||||
for varData in varStore.VarData:
|
||||
_scaleVarDataDeltas(varData, regionScalars)
|
||||
def instantiateItemVariationStore(itemVarStore, fvarAxes, location):
|
||||
""" Compute deltas at partial location, and update varStore in-place.
|
||||
|
||||
# disable the pinned axes by setting PeakCoord to 0
|
||||
for axes in regions:
|
||||
for axisTag, axis in axes.items():
|
||||
if axisTag in location:
|
||||
axis.StartCoord, axis.PeakCoord, axis.EndCoord = (0, 0, 0)
|
||||
# If all axes in a region are pinned, its deltas are added to the default instance
|
||||
defaultRegionIndices = {
|
||||
regionIndex
|
||||
for regionIndex, axes in enumerate(regions)
|
||||
if all(axis.PeakCoord == 0 for axis in axes.values())
|
||||
}
|
||||
# Collect the default deltas into a two-dimension array, with outer/inner indices
|
||||
# corresponding to a VarData subtable and a deltaset row within that table.
|
||||
defaultDeltaArray = [
|
||||
_getVarDataDeltasForRegions(varData, defaultRegionIndices)
|
||||
for varData in varStore.VarData
|
||||
]
|
||||
Remove regions in which all axes were instanced, and scale the deltas of
|
||||
the remaining regions where only some of the axes were instanced.
|
||||
|
||||
# drop default regions, or those whose influence at the pinned location is 0
|
||||
newRegionIndices = {
|
||||
regionIndex
|
||||
for regionIndex in range(len(varStore.VarRegionList.Region))
|
||||
if regionIndex not in defaultRegionIndices and regionScalars[regionIndex] != 0
|
||||
}
|
||||
_subsetVarStoreRegions(varStore, newRegionIndices)
|
||||
Args:
|
||||
varStore: An otTables.VarStore object (Item Variation Store)
|
||||
fvarAxes: list of fvar's Axis objects
|
||||
location: Dict[str, float] mapping axis tags to normalized axis coordinates.
|
||||
May not specify coordinates for all the fvar axes.
|
||||
|
||||
if varStore.VarRegionList.Region:
|
||||
Returns:
|
||||
defaultDeltaArray: the deltas to be added to the default instance (list of list
|
||||
of integers, indexed by outer/inner VarIdx)
|
||||
varIndexMapping: a mapping from old to new VarIdx after optimization (None if
|
||||
varStore was fully instanced thus left empty).
|
||||
"""
|
||||
tupleVarStore = _TupleVarStoreAdapter.fromItemVarStore(itemVarStore, fvarAxes)
|
||||
defaultDeltaArray = tupleVarStore.instantiate(location)
|
||||
newItemVarStore = tupleVarStore.asItemVarStore()
|
||||
|
||||
itemVarStore.VarRegionList = newItemVarStore.VarRegionList
|
||||
assert itemVarStore.VarDataCount == newItemVarStore.VarDataCount
|
||||
itemVarStore.VarData = newItemVarStore.VarData
|
||||
|
||||
if itemVarStore.VarRegionList.Region:
|
||||
# optimize VarStore, and get a map from old to new VarIdx after optimization
|
||||
varIndexMapping = varStore.optimize()
|
||||
varIndexMapping = itemVarStore.optimize()
|
||||
else:
|
||||
varIndexMapping = None # VarStore is empty
|
||||
|
||||
|
@ -133,8 +133,11 @@ def VarData_addItem(self, deltas):
|
||||
ot.VarData.addItem = VarData_addItem
|
||||
|
||||
def VarRegion_get_support(self, fvar_axes):
|
||||
return {fvar_axes[i].axisTag: (reg.StartCoord,reg.PeakCoord,reg.EndCoord)
|
||||
for i,reg in enumerate(self.VarRegionAxis)}
|
||||
return {
|
||||
fvar_axes[i].axisTag: (reg.StartCoord,reg.PeakCoord,reg.EndCoord)
|
||||
for i, reg in enumerate(self.VarRegionAxis)
|
||||
if reg.PeakCoord != 0
|
||||
}
|
||||
|
||||
ot.VarRegion.get_support = VarRegion_get_support
|
||||
|
||||
|
@ -2,6 +2,7 @@ from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools import ttLib
|
||||
from fontTools.ttLib.tables import _f_v_a_r
|
||||
from fontTools.ttLib.tables.TupleVariation import TupleVariation
|
||||
from fontTools.varLib import instancer
|
||||
from fontTools.varLib.mvar import MVAR_ENTRIES
|
||||
from fontTools.varLib import builder
|
||||
@ -24,6 +25,21 @@ def optimize(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fvarAxes():
|
||||
wght = _f_v_a_r.Axis()
|
||||
wght.axisTag = Tag("wght")
|
||||
wght.minValue = 100
|
||||
wght.defaultValue = 400
|
||||
wght.maxValue = 900
|
||||
wdth = _f_v_a_r.Axis()
|
||||
wdth.axisTag = Tag("wdth")
|
||||
wdth.minValue = 70
|
||||
wdth.defaultValue = 100
|
||||
wdth.maxValue = 100
|
||||
return [wght, wdth]
|
||||
|
||||
|
||||
def _get_coordinates(varfont, glyphname):
|
||||
# converts GlyphCoordinates to a list of (x, y) tuples, so that pytest's
|
||||
# assert will give us a nicer diff
|
||||
@ -256,118 +272,17 @@ class InstantiateMvarTest(object):
|
||||
|
||||
|
||||
class InstantiateItemVariationStoreTest(object):
|
||||
def test_getVarRegionAxes(self):
|
||||
def test_VarRegion_get_support(self):
|
||||
axisOrder = ["wght", "wdth", "opsz"]
|
||||
regionAxes = {"wdth": (-1.0, -1.0, 0.0), "wght": (0.0, 1.0, 1.0)}
|
||||
region = builder.buildVarRegion(regionAxes, axisOrder)
|
||||
fvarAxes = [SimpleNamespace(axisTag=tag) for tag in axisOrder]
|
||||
|
||||
result = instancer._getVarRegionAxes(region, fvarAxes)
|
||||
assert len(region.VarRegionAxis) == 3
|
||||
assert region.VarRegionAxis[2].PeakCoord == 0
|
||||
|
||||
assert {
|
||||
axisTag: (axis.StartCoord, axis.PeakCoord, axis.EndCoord)
|
||||
for axisTag, axis in result.items()
|
||||
} == regionAxes
|
||||
fvarAxes = [SimpleNamespace(axisTag=axisTag) for axisTag in axisOrder]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"location, regionAxes, expected",
|
||||
[
|
||||
({"wght": 0.5}, {"wght": (0.0, 1.0, 1.0)}, 0.5),
|
||||
({"wght": 0.5}, {"wght": (0.0, 1.0, 1.0), "wdth": (-1.0, -1.0, 0.0)}, 0.5),
|
||||
(
|
||||
{"wght": 0.5, "wdth": -0.5},
|
||||
{"wght": (0.0, 1.0, 1.0), "wdth": (-1.0, -1.0, 0.0)},
|
||||
0.25,
|
||||
),
|
||||
({"wght": 0.5, "wdth": -0.5}, {"wght": (0.0, 1.0, 1.0)}, 0.5),
|
||||
({"wght": 0.5}, {"wdth": (-1.0, -1.0, 1.0)}, 1.0),
|
||||
],
|
||||
)
|
||||
def test_getVarRegionScalar(self, location, regionAxes, expected):
|
||||
varRegionAxes = {
|
||||
axisTag: builder.buildVarRegionAxis(support)
|
||||
for axisTag, support in regionAxes.items()
|
||||
}
|
||||
|
||||
assert instancer._getVarRegionScalar(location, varRegionAxes) == expected
|
||||
|
||||
def test_scaleVarDataDeltas(self):
|
||||
regionScalars = [0.0, 0.5, 1.0]
|
||||
varData = builder.buildVarData(
|
||||
[1, 0], [[100, 200], [-100, -200]], optimize=False
|
||||
)
|
||||
|
||||
instancer._scaleVarDataDeltas(varData, regionScalars)
|
||||
|
||||
assert varData.Item == [[50, 0], [-50, 0]]
|
||||
|
||||
def test_getVarDataDeltasForRegions(self):
|
||||
varData = builder.buildVarData(
|
||||
[1, 0], [[33.5, 67.9], [-100, -200]], optimize=False
|
||||
)
|
||||
|
||||
assert instancer._getVarDataDeltasForRegions(varData, {1}) == [[33.5], [-100]]
|
||||
assert instancer._getVarDataDeltasForRegions(varData, {0}) == [[67.9], [-200]]
|
||||
assert instancer._getVarDataDeltasForRegions(varData, set()) == [[], []]
|
||||
assert instancer._getVarDataDeltasForRegions(varData, {1}, rounded=True) == [
|
||||
[34],
|
||||
[-100],
|
||||
]
|
||||
|
||||
def test_subsetVarStoreRegions(self):
|
||||
regionList = builder.buildVarRegionList(
|
||||
[
|
||||
{"wght": (0, 0.5, 1)},
|
||||
{"wght": (0.5, 1, 1)},
|
||||
{"wdth": (-1, -1, 0)},
|
||||
{"wght": (0, 0.5, 1), "wdth": (-1, -1, 0)},
|
||||
{"wght": (0.5, 1, 1), "wdth": (-1, -1, 0)},
|
||||
],
|
||||
["wght", "wdth"],
|
||||
)
|
||||
varData1 = builder.buildVarData([0, 1, 2, 4], [[0, 1, 2, 3], [4, 5, 6, 7]])
|
||||
varData2 = builder.buildVarData([2, 3, 1], [[8, 9, 10], [11, 12, 13]])
|
||||
varStore = builder.buildVarStore(regionList, [varData1, varData2])
|
||||
|
||||
instancer._subsetVarStoreRegions(varStore, {0, 4})
|
||||
|
||||
assert (
|
||||
varStore.VarRegionList.RegionCount
|
||||
== len(varStore.VarRegionList.Region)
|
||||
== 2
|
||||
)
|
||||
axis00 = varStore.VarRegionList.Region[0].VarRegionAxis[0]
|
||||
assert (axis00.StartCoord, axis00.PeakCoord, axis00.EndCoord) == (0, 0.5, 1)
|
||||
axis01 = varStore.VarRegionList.Region[0].VarRegionAxis[1]
|
||||
assert (axis01.StartCoord, axis01.PeakCoord, axis01.EndCoord) == (0, 0, 0)
|
||||
axis10 = varStore.VarRegionList.Region[1].VarRegionAxis[0]
|
||||
assert (axis10.StartCoord, axis10.PeakCoord, axis10.EndCoord) == (0.5, 1, 1)
|
||||
axis11 = varStore.VarRegionList.Region[1].VarRegionAxis[1]
|
||||
assert (axis11.StartCoord, axis11.PeakCoord, axis11.EndCoord) == (-1, -1, 0)
|
||||
|
||||
assert varStore.VarDataCount == len(varStore.VarData) == 2
|
||||
assert varStore.VarData[0].VarRegionCount == 2
|
||||
assert varStore.VarData[0].VarRegionIndex == [0, 1]
|
||||
assert varStore.VarData[0].Item == [[0, 3], [4, 7]]
|
||||
assert varStore.VarData[0].NumShorts == 0
|
||||
assert varStore.VarData[1].VarRegionCount == 0
|
||||
assert varStore.VarData[1].VarRegionIndex == []
|
||||
assert varStore.VarData[1].Item == [[], []]
|
||||
assert varStore.VarData[1].NumShorts == 0
|
||||
|
||||
@pytest.fixture
|
||||
def fvarAxes(self):
|
||||
wght = _f_v_a_r.Axis()
|
||||
wght.axisTag = Tag("wght")
|
||||
wght.minValue = 100
|
||||
wght.defaultValue = 400
|
||||
wght.maxValue = 900
|
||||
wdth = _f_v_a_r.Axis()
|
||||
wdth.axisTag = Tag("wdth")
|
||||
wdth.minValue = 70
|
||||
wdth.defaultValue = 100
|
||||
wdth.maxValue = 100
|
||||
return [wght, wdth]
|
||||
assert region.get_support(fvarAxes) == regionAxes
|
||||
|
||||
@pytest.fixture
|
||||
def varStore(self):
|
||||
@ -395,25 +310,13 @@ class InstantiateItemVariationStoreTest(object):
|
||||
@pytest.mark.parametrize(
|
||||
"location, expected_deltas, num_regions",
|
||||
[
|
||||
({"wght": 0}, [[[0, 0, 0], [0, 0, 0]], [[], []]], 1),
|
||||
({"wght": 0.25}, [[[0, 50, 0], [0, 50, 0]], [[], []]], 2),
|
||||
({"wdth": 0}, [[[], []], [[0], [0]]], 3),
|
||||
({"wdth": -0.75}, [[[], []], [[75], [75]]], 6),
|
||||
(
|
||||
{"wght": 0, "wdth": 0},
|
||||
[[[0, 0, 0], [0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]],
|
||||
0,
|
||||
),
|
||||
(
|
||||
{"wght": 0.25, "wdth": 0},
|
||||
[[[0, 50, 0], [0, 50, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]],
|
||||
0,
|
||||
),
|
||||
(
|
||||
{"wght": 0, "wdth": -0.75},
|
||||
[[[0, 0, 0], [0, 0, 0]], [[75, 0, 0, 0], [75, 0, 0, 0]]],
|
||||
0,
|
||||
),
|
||||
({"wght": 0}, [[0, 0], [0, 0]], 1),
|
||||
({"wght": 0.25}, [[50, 50], [0, 0]], 1),
|
||||
({"wdth": 0}, [[0, 0], [0, 0]], 3),
|
||||
({"wdth": -0.75}, [[0, 0], [75, 75]], 3),
|
||||
({"wght": 0, "wdth": 0}, [[0, 0], [0, 0]], 0),
|
||||
({"wght": 0.25, "wdth": 0}, [[50, 50], [0, 0]], 0),
|
||||
({"wght": 0, "wdth": -0.75}, [[0, 0], [75, 75]], 0),
|
||||
],
|
||||
)
|
||||
def test_instantiate_default_deltas(
|
||||
@ -425,3 +328,152 @@ class InstantiateItemVariationStoreTest(object):
|
||||
|
||||
assert defaultDeltas == expected_deltas
|
||||
assert varStore.VarRegionList.RegionCount == num_regions
|
||||
|
||||
|
||||
class TupleVarStoreAdapterTest(object):
|
||||
def test_instantiate(self):
|
||||
regions = [
|
||||
{"wght": (-1.0, -1.0, 0)},
|
||||
{"wght": (0.0, 1.0, 1.0)},
|
||||
{"wdth": (-1.0, -1.0, 0)},
|
||||
{"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)},
|
||||
{"wght": (0, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)},
|
||||
]
|
||||
axisOrder = ["wght", "wdth"]
|
||||
tupleVarData = [
|
||||
[
|
||||
TupleVariation({"wght": (-1.0, -1.0, 0)}, [10, 70]),
|
||||
TupleVariation({"wght": (0.0, 1.0, 1.0)}, [30, 90]),
|
||||
TupleVariation(
|
||||
{"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)}, [-40, -100]
|
||||
),
|
||||
TupleVariation(
|
||||
{"wght": (0, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)}, [-60, -120]
|
||||
),
|
||||
],
|
||||
[
|
||||
TupleVariation({"wdth": (-1.0, -1.0, 0)}, [5, 45]),
|
||||
TupleVariation(
|
||||
{"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)}, [-15, -55]
|
||||
),
|
||||
TupleVariation(
|
||||
{"wght": (0, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)}, [-35, -75]
|
||||
),
|
||||
],
|
||||
]
|
||||
adapter = instancer._TupleVarStoreAdapter(
|
||||
regions, axisOrder, tupleVarData, itemCounts=[2, 2]
|
||||
)
|
||||
|
||||
defaultDeltaArray = adapter.instantiate({"wght": 0.5})
|
||||
|
||||
assert defaultDeltaArray == [[15, 45], [0, 0]]
|
||||
assert adapter.regions == [{"wdth": (-1.0, -1.0, 0)}]
|
||||
assert adapter.tupleVarData == [
|
||||
[TupleVariation({"wdth": (-1.0, -1.0, 0)}, [-30, -60])],
|
||||
[TupleVariation({"wdth": (-1.0, -1.0, 0)}, [-12, 8])],
|
||||
]
|
||||
|
||||
def test_dropAxes(self):
|
||||
regions = [
|
||||
{"wght": (-1.0, -1.0, 0)},
|
||||
{"wght": (0.0, 1.0, 1.0)},
|
||||
{"wdth": (-1.0, -1.0, 0)},
|
||||
{"opsz": (0.0, 1.0, 1.0)},
|
||||
{"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)},
|
||||
{"wght": (0, 0.5, 1.0), "wdth": (-1.0, -1.0, 0)},
|
||||
{"wght": (0.5, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)},
|
||||
]
|
||||
axisOrder = ["wght", "wdth", "opsz"]
|
||||
adapter = instancer._TupleVarStoreAdapter(regions, axisOrder, [], itemCounts=[])
|
||||
|
||||
adapter.dropAxes({"wdth"})
|
||||
|
||||
assert adapter.regions == [
|
||||
{"wght": (-1.0, -1.0, 0)},
|
||||
{"wght": (0.0, 1.0, 1.0)},
|
||||
{"opsz": (0.0, 1.0, 1.0)},
|
||||
{"wght": (0.0, 0.5, 1.0)},
|
||||
{"wght": (0.5, 1.0, 1.0)},
|
||||
]
|
||||
|
||||
adapter.dropAxes({"wght", "opsz"})
|
||||
|
||||
assert adapter.regions == []
|
||||
|
||||
def test_roundtrip(self, fvarAxes):
|
||||
regions = [
|
||||
{"wght": (-1.0, -1.0, 0)},
|
||||
{"wght": (0, 0.5, 1.0)},
|
||||
{"wght": (0.5, 1.0, 1.0)},
|
||||
{"wdth": (-1.0, -1.0, 0)},
|
||||
{"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)},
|
||||
{"wght": (0, 0.5, 1.0), "wdth": (-1.0, -1.0, 0)},
|
||||
{"wght": (0.5, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)},
|
||||
]
|
||||
axisOrder = [axis.axisTag for axis in fvarAxes]
|
||||
|
||||
itemVarStore = builder.buildVarStore(
|
||||
builder.buildVarRegionList(regions, axisOrder),
|
||||
[
|
||||
builder.buildVarData(
|
||||
[0, 1, 2, 4, 5, 6],
|
||||
[[10, -20, 30, -40, 50, -60], [70, -80, 90, -100, 110, -120]],
|
||||
),
|
||||
builder.buildVarData(
|
||||
[3, 4, 5, 6], [[5, -15, 25, -35], [45, -55, 65, -75]]
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
adapter = instancer._TupleVarStoreAdapter.fromItemVarStore(
|
||||
itemVarStore, fvarAxes
|
||||
)
|
||||
|
||||
assert adapter.tupleVarData == [
|
||||
[
|
||||
TupleVariation({"wght": (-1.0, -1.0, 0)}, [10, 70]),
|
||||
TupleVariation({"wght": (0, 0.5, 1.0)}, [-20, -80]),
|
||||
TupleVariation({"wght": (0.5, 1.0, 1.0)}, [30, 90]),
|
||||
TupleVariation(
|
||||
{"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)}, [-40, -100]
|
||||
),
|
||||
TupleVariation(
|
||||
{"wght": (0, 0.5, 1.0), "wdth": (-1.0, -1.0, 0)}, [50, 110]
|
||||
),
|
||||
TupleVariation(
|
||||
{"wght": (0.5, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)}, [-60, -120]
|
||||
),
|
||||
],
|
||||
[
|
||||
TupleVariation({"wdth": (-1.0, -1.0, 0)}, [5, 45]),
|
||||
TupleVariation(
|
||||
{"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)}, [-15, -55]
|
||||
),
|
||||
TupleVariation(
|
||||
{"wght": (0, 0.5, 1.0), "wdth": (-1.0, -1.0, 0)}, [25, 65]
|
||||
),
|
||||
TupleVariation(
|
||||
{"wght": (0.5, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)}, [-35, -75]
|
||||
),
|
||||
],
|
||||
]
|
||||
assert adapter.itemCounts == [data.ItemCount for data in itemVarStore.VarData]
|
||||
assert adapter.regions == regions
|
||||
assert adapter.axisOrder == axisOrder
|
||||
|
||||
itemVarStore2 = adapter.asItemVarStore()
|
||||
|
||||
assert [
|
||||
reg.get_support(fvarAxes)
|
||||
for reg in itemVarStore2.VarRegionList.Region
|
||||
] == regions
|
||||
|
||||
assert itemVarStore2.VarDataCount == 2
|
||||
assert itemVarStore2.VarData[0].VarRegionIndex == [0, 1, 2, 4, 5, 6]
|
||||
assert itemVarStore2.VarData[0].Item == [
|
||||
[10, -20, 30, -40, 50, -60],
|
||||
[70, -80, 90, -100, 110, -120],
|
||||
]
|
||||
assert itemVarStore2.VarData[1].VarRegionIndex == [3, 4, 5, 6]
|
||||
assert itemVarStore2.VarData[1].Item == [[5, -15, 25, -35], [45, -55, 65, -75]]
|
||||
|
Loading…
x
Reference in New Issue
Block a user