1*e1fe3e4aSElliott Hughesfrom fontTools.varLib.models import ( 2*e1fe3e4aSElliott Hughes normalizeLocation, 3*e1fe3e4aSElliott Hughes supportScalar, 4*e1fe3e4aSElliott Hughes VariationModel, 5*e1fe3e4aSElliott Hughes VariationModelError, 6*e1fe3e4aSElliott Hughes) 7*e1fe3e4aSElliott Hughesimport pytest 8*e1fe3e4aSElliott Hughes 9*e1fe3e4aSElliott Hughes 10*e1fe3e4aSElliott Hughesdef test_normalizeLocation(): 11*e1fe3e4aSElliott Hughes axes = {"wght": (100, 400, 900)} 12*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 400}, axes) == {"wght": 0.0} 13*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 100}, axes) == {"wght": -1.0} 14*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 900}, axes) == {"wght": 1.0} 15*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 650}, axes) == {"wght": 0.5} 16*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 1000}, axes) == {"wght": 1.0} 17*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 0}, axes) == {"wght": -1.0} 18*e1fe3e4aSElliott Hughes 19*e1fe3e4aSElliott Hughes axes = {"wght": (0, 0, 1000)} 20*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 0}, axes) == {"wght": 0.0} 21*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": -1}, axes) == {"wght": 0.0} 22*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 1000}, axes) == {"wght": 1.0} 23*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 500}, axes) == {"wght": 0.5} 24*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 1001}, axes) == {"wght": 1.0} 25*e1fe3e4aSElliott Hughes 26*e1fe3e4aSElliott Hughes axes = {"wght": (0, 1000, 1000)} 27*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 0}, axes) == {"wght": -1.0} 28*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": -1}, axes) == {"wght": -1.0} 29*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 500}, axes) == {"wght": -0.5} 30*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 1000}, axes) == {"wght": 0.0} 31*e1fe3e4aSElliott Hughes assert normalizeLocation({"wght": 1001}, axes) == {"wght": 0.0} 32*e1fe3e4aSElliott Hughes 33*e1fe3e4aSElliott Hughes 34*e1fe3e4aSElliott Hughes@pytest.mark.parametrize( 35*e1fe3e4aSElliott Hughes "axes, location, expected", 36*e1fe3e4aSElliott Hughes [ 37*e1fe3e4aSElliott Hughes # lower != default != upper 38*e1fe3e4aSElliott Hughes ({"wght": (100, 400, 900)}, {"wght": 1000}, {"wght": 1.2}), 39*e1fe3e4aSElliott Hughes ({"wght": (100, 400, 900)}, {"wght": 900}, {"wght": 1.0}), 40*e1fe3e4aSElliott Hughes ({"wght": (100, 400, 900)}, {"wght": 650}, {"wght": 0.5}), 41*e1fe3e4aSElliott Hughes ({"wght": (100, 400, 900)}, {"wght": 400}, {"wght": 0.0}), 42*e1fe3e4aSElliott Hughes ({"wght": (100, 400, 900)}, {"wght": 250}, {"wght": -0.5}), 43*e1fe3e4aSElliott Hughes ({"wght": (100, 400, 900)}, {"wght": 100}, {"wght": -1.0}), 44*e1fe3e4aSElliott Hughes ({"wght": (100, 400, 900)}, {"wght": 25}, {"wght": -1.25}), 45*e1fe3e4aSElliott Hughes # lower == default != upper 46*e1fe3e4aSElliott Hughes ( 47*e1fe3e4aSElliott Hughes {"wght": (400, 400, 900), "wdth": (100, 100, 150)}, 48*e1fe3e4aSElliott Hughes {"wght": 1000, "wdth": 200}, 49*e1fe3e4aSElliott Hughes {"wght": 1.2, "wdth": 2.0}, 50*e1fe3e4aSElliott Hughes ), 51*e1fe3e4aSElliott Hughes ( 52*e1fe3e4aSElliott Hughes {"wght": (400, 400, 900), "wdth": (100, 100, 150)}, 53*e1fe3e4aSElliott Hughes {"wght": 25, "wdth": 25}, 54*e1fe3e4aSElliott Hughes {"wght": -0.75, "wdth": -1.5}, 55*e1fe3e4aSElliott Hughes ), 56*e1fe3e4aSElliott Hughes # lower != default == upper 57*e1fe3e4aSElliott Hughes ( 58*e1fe3e4aSElliott Hughes {"wght": (100, 400, 400), "wdth": (50, 100, 100)}, 59*e1fe3e4aSElliott Hughes {"wght": 700, "wdth": 150}, 60*e1fe3e4aSElliott Hughes {"wght": 1.0, "wdth": 1.0}, 61*e1fe3e4aSElliott Hughes ), 62*e1fe3e4aSElliott Hughes ( 63*e1fe3e4aSElliott Hughes {"wght": (100, 400, 400), "wdth": (50, 100, 100)}, 64*e1fe3e4aSElliott Hughes {"wght": -50, "wdth": 25}, 65*e1fe3e4aSElliott Hughes {"wght": -1.5, "wdth": -1.5}, 66*e1fe3e4aSElliott Hughes ), 67*e1fe3e4aSElliott Hughes # degenerate case with lower == default == upper, normalized location always 0 68*e1fe3e4aSElliott Hughes ({"wght": (400, 400, 400)}, {"wght": 100}, {"wght": 0.0}), 69*e1fe3e4aSElliott Hughes ({"wght": (400, 400, 400)}, {"wght": 400}, {"wght": 0.0}), 70*e1fe3e4aSElliott Hughes ({"wght": (400, 400, 400)}, {"wght": 700}, {"wght": 0.0}), 71*e1fe3e4aSElliott Hughes ], 72*e1fe3e4aSElliott Hughes) 73*e1fe3e4aSElliott Hughesdef test_normalizeLocation_extrapolate(axes, location, expected): 74*e1fe3e4aSElliott Hughes assert normalizeLocation(location, axes, extrapolate=True) == expected 75*e1fe3e4aSElliott Hughes 76*e1fe3e4aSElliott Hughes 77*e1fe3e4aSElliott Hughesdef test_supportScalar(): 78*e1fe3e4aSElliott Hughes assert supportScalar({}, {}) == 1.0 79*e1fe3e4aSElliott Hughes assert supportScalar({"wght": 0.2}, {}) == 1.0 80*e1fe3e4aSElliott Hughes assert supportScalar({"wght": 0.2}, {"wght": (0, 2, 3)}) == 0.1 81*e1fe3e4aSElliott Hughes assert supportScalar({"wght": 2.5}, {"wght": (0, 2, 4)}) == 0.75 82*e1fe3e4aSElliott Hughes assert supportScalar({"wght": 3}, {"wght": (0, 2, 2)}) == 0.0 83*e1fe3e4aSElliott Hughes assert ( 84*e1fe3e4aSElliott Hughes supportScalar( 85*e1fe3e4aSElliott Hughes {"wght": 3}, 86*e1fe3e4aSElliott Hughes {"wght": (0, 2, 2)}, 87*e1fe3e4aSElliott Hughes extrapolate=True, 88*e1fe3e4aSElliott Hughes axisRanges={"wght": (0, 2)}, 89*e1fe3e4aSElliott Hughes ) 90*e1fe3e4aSElliott Hughes == 1.5 91*e1fe3e4aSElliott Hughes ) 92*e1fe3e4aSElliott Hughes assert ( 93*e1fe3e4aSElliott Hughes supportScalar( 94*e1fe3e4aSElliott Hughes {"wght": -1}, 95*e1fe3e4aSElliott Hughes {"wght": (0, 2, 2)}, 96*e1fe3e4aSElliott Hughes extrapolate=True, 97*e1fe3e4aSElliott Hughes axisRanges={"wght": (0, 2)}, 98*e1fe3e4aSElliott Hughes ) 99*e1fe3e4aSElliott Hughes == -0.5 100*e1fe3e4aSElliott Hughes ) 101*e1fe3e4aSElliott Hughes assert ( 102*e1fe3e4aSElliott Hughes supportScalar( 103*e1fe3e4aSElliott Hughes {"wght": 3}, 104*e1fe3e4aSElliott Hughes {"wght": (0, 1, 2)}, 105*e1fe3e4aSElliott Hughes extrapolate=True, 106*e1fe3e4aSElliott Hughes axisRanges={"wght": (0, 2)}, 107*e1fe3e4aSElliott Hughes ) 108*e1fe3e4aSElliott Hughes == -1.0 109*e1fe3e4aSElliott Hughes ) 110*e1fe3e4aSElliott Hughes assert ( 111*e1fe3e4aSElliott Hughes supportScalar( 112*e1fe3e4aSElliott Hughes {"wght": -1}, 113*e1fe3e4aSElliott Hughes {"wght": (0, 1, 2)}, 114*e1fe3e4aSElliott Hughes extrapolate=True, 115*e1fe3e4aSElliott Hughes axisRanges={"wght": (0, 2)}, 116*e1fe3e4aSElliott Hughes ) 117*e1fe3e4aSElliott Hughes == -1.0 118*e1fe3e4aSElliott Hughes ) 119*e1fe3e4aSElliott Hughes assert ( 120*e1fe3e4aSElliott Hughes supportScalar( 121*e1fe3e4aSElliott Hughes {"wght": 2}, 122*e1fe3e4aSElliott Hughes {"wght": (0, 0.75, 1)}, 123*e1fe3e4aSElliott Hughes extrapolate=True, 124*e1fe3e4aSElliott Hughes axisRanges={"wght": (0, 1)}, 125*e1fe3e4aSElliott Hughes ) 126*e1fe3e4aSElliott Hughes == -4.0 127*e1fe3e4aSElliott Hughes ) 128*e1fe3e4aSElliott Hughes with pytest.raises(TypeError): 129*e1fe3e4aSElliott Hughes supportScalar( 130*e1fe3e4aSElliott Hughes {"wght": 2}, {"wght": (0, 0.75, 1)}, extrapolate=True, axisRanges=None 131*e1fe3e4aSElliott Hughes ) 132*e1fe3e4aSElliott Hughes 133*e1fe3e4aSElliott Hughes 134*e1fe3e4aSElliott Hughesdef test_model_extrapolate(): 135*e1fe3e4aSElliott Hughes locations = [{}, {"a": 1}, {"b": 1}, {"a": 1, "b": 1}] 136*e1fe3e4aSElliott Hughes model = VariationModel(locations, extrapolate=True) 137*e1fe3e4aSElliott Hughes masterValues = [100, 200, 300, 400] 138*e1fe3e4aSElliott Hughes testLocsAndValues = [ 139*e1fe3e4aSElliott Hughes ({"a": -1, "b": -1}, -200), 140*e1fe3e4aSElliott Hughes ({"a": -1, "b": 0}, 0), 141*e1fe3e4aSElliott Hughes ({"a": -1, "b": 1}, 200), 142*e1fe3e4aSElliott Hughes ({"a": -1, "b": 2}, 400), 143*e1fe3e4aSElliott Hughes ({"a": 0, "b": -1}, -100), 144*e1fe3e4aSElliott Hughes ({"a": 0, "b": 0}, 100), 145*e1fe3e4aSElliott Hughes ({"a": 0, "b": 1}, 300), 146*e1fe3e4aSElliott Hughes ({"a": 0, "b": 2}, 500), 147*e1fe3e4aSElliott Hughes ({"a": 1, "b": -1}, 0), 148*e1fe3e4aSElliott Hughes ({"a": 1, "b": 0}, 200), 149*e1fe3e4aSElliott Hughes ({"a": 1, "b": 1}, 400), 150*e1fe3e4aSElliott Hughes ({"a": 1, "b": 2}, 600), 151*e1fe3e4aSElliott Hughes ({"a": 2, "b": -1}, 100), 152*e1fe3e4aSElliott Hughes ({"a": 2, "b": 0}, 300), 153*e1fe3e4aSElliott Hughes ({"a": 2, "b": 1}, 500), 154*e1fe3e4aSElliott Hughes ({"a": 2, "b": 2}, 700), 155*e1fe3e4aSElliott Hughes ] 156*e1fe3e4aSElliott Hughes for loc, expectedValue in testLocsAndValues: 157*e1fe3e4aSElliott Hughes assert expectedValue == model.interpolateFromMasters(loc, masterValues) 158*e1fe3e4aSElliott Hughes 159*e1fe3e4aSElliott Hughes 160*e1fe3e4aSElliott Hughes@pytest.mark.parametrize( 161*e1fe3e4aSElliott Hughes "numLocations, numSamples", 162*e1fe3e4aSElliott Hughes [ 163*e1fe3e4aSElliott Hughes pytest.param(127, 509, marks=pytest.mark.slow), 164*e1fe3e4aSElliott Hughes (31, 251), 165*e1fe3e4aSElliott Hughes ], 166*e1fe3e4aSElliott Hughes) 167*e1fe3e4aSElliott Hughesdef test_modeling_error(numLocations, numSamples): 168*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/issues/2213 169*e1fe3e4aSElliott Hughes locations = [{"axis": float(i) / numLocations} for i in range(numLocations)] 170*e1fe3e4aSElliott Hughes masterValues = [100.0 if i else 0.0 for i in range(numLocations)] 171*e1fe3e4aSElliott Hughes 172*e1fe3e4aSElliott Hughes model = VariationModel(locations) 173*e1fe3e4aSElliott Hughes 174*e1fe3e4aSElliott Hughes for i in range(numSamples): 175*e1fe3e4aSElliott Hughes loc = {"axis": float(i) / numSamples} 176*e1fe3e4aSElliott Hughes scalars = model.getScalars(loc) 177*e1fe3e4aSElliott Hughes 178*e1fe3e4aSElliott Hughes deltas_float = model.getDeltas(masterValues) 179*e1fe3e4aSElliott Hughes deltas_round = model.getDeltas(masterValues, round=round) 180*e1fe3e4aSElliott Hughes 181*e1fe3e4aSElliott Hughes expected = model.interpolateFromDeltasAndScalars(deltas_float, scalars) 182*e1fe3e4aSElliott Hughes actual = model.interpolateFromDeltasAndScalars(deltas_round, scalars) 183*e1fe3e4aSElliott Hughes 184*e1fe3e4aSElliott Hughes err = abs(actual - expected) 185*e1fe3e4aSElliott Hughes assert err <= 0.5, (i, err) 186*e1fe3e4aSElliott Hughes 187*e1fe3e4aSElliott Hughes # This is how NOT to round deltas. 188*e1fe3e4aSElliott Hughes # deltas_late_round = [round(d) for d in deltas_float] 189*e1fe3e4aSElliott Hughes # bad = model.interpolateFromDeltasAndScalars(deltas_late_round, scalars) 190*e1fe3e4aSElliott Hughes # err_bad = abs(bad - expected) 191*e1fe3e4aSElliott Hughes # if err != err_bad: 192*e1fe3e4aSElliott Hughes # print("{:d} {:.2} {:.2}".format(i, err, err_bad)) 193*e1fe3e4aSElliott Hughes 194*e1fe3e4aSElliott Hughes 195*e1fe3e4aSElliott HugheslocationsA = [{}, {"wght": 1}, {"wdth": 1}] 196*e1fe3e4aSElliott HugheslocationsB = [{}, {"wght": 1}, {"wdth": 1}, {"wght": 1, "wdth": 1}] 197*e1fe3e4aSElliott HugheslocationsC = [ 198*e1fe3e4aSElliott Hughes {}, 199*e1fe3e4aSElliott Hughes {"wght": 0.5}, 200*e1fe3e4aSElliott Hughes {"wght": 1}, 201*e1fe3e4aSElliott Hughes {"wdth": 1}, 202*e1fe3e4aSElliott Hughes {"wght": 1, "wdth": 1}, 203*e1fe3e4aSElliott Hughes] 204*e1fe3e4aSElliott Hughes 205*e1fe3e4aSElliott Hughes 206*e1fe3e4aSElliott Hughesclass VariationModelTest(object): 207*e1fe3e4aSElliott Hughes @pytest.mark.parametrize( 208*e1fe3e4aSElliott Hughes "locations, axisOrder, sortedLocs, supports, deltaWeights", 209*e1fe3e4aSElliott Hughes [ 210*e1fe3e4aSElliott Hughes ( 211*e1fe3e4aSElliott Hughes [ 212*e1fe3e4aSElliott Hughes {"wght": 0.55, "wdth": 0.0}, 213*e1fe3e4aSElliott Hughes {"wght": -0.55, "wdth": 0.0}, 214*e1fe3e4aSElliott Hughes {"wght": -1.0, "wdth": 0.0}, 215*e1fe3e4aSElliott Hughes {"wght": 0.0, "wdth": 1.0}, 216*e1fe3e4aSElliott Hughes {"wght": 0.66, "wdth": 1.0}, 217*e1fe3e4aSElliott Hughes {"wght": 0.66, "wdth": 0.66}, 218*e1fe3e4aSElliott Hughes {"wght": 0.0, "wdth": 0.0}, 219*e1fe3e4aSElliott Hughes {"wght": 1.0, "wdth": 1.0}, 220*e1fe3e4aSElliott Hughes {"wght": 1.0, "wdth": 0.0}, 221*e1fe3e4aSElliott Hughes ], 222*e1fe3e4aSElliott Hughes ["wght"], 223*e1fe3e4aSElliott Hughes [ 224*e1fe3e4aSElliott Hughes {}, 225*e1fe3e4aSElliott Hughes {"wght": -0.55}, 226*e1fe3e4aSElliott Hughes {"wght": -1.0}, 227*e1fe3e4aSElliott Hughes {"wght": 0.55}, 228*e1fe3e4aSElliott Hughes {"wght": 1.0}, 229*e1fe3e4aSElliott Hughes {"wdth": 1.0}, 230*e1fe3e4aSElliott Hughes {"wdth": 1.0, "wght": 1.0}, 231*e1fe3e4aSElliott Hughes {"wdth": 1.0, "wght": 0.66}, 232*e1fe3e4aSElliott Hughes {"wdth": 0.66, "wght": 0.66}, 233*e1fe3e4aSElliott Hughes ], 234*e1fe3e4aSElliott Hughes [ 235*e1fe3e4aSElliott Hughes {}, 236*e1fe3e4aSElliott Hughes {"wght": (-1.0, -0.55, 0)}, 237*e1fe3e4aSElliott Hughes {"wght": (-1.0, -1.0, -0.55)}, 238*e1fe3e4aSElliott Hughes {"wght": (0, 0.55, 1.0)}, 239*e1fe3e4aSElliott Hughes {"wght": (0.55, 1.0, 1.0)}, 240*e1fe3e4aSElliott Hughes {"wdth": (0, 1.0, 1.0)}, 241*e1fe3e4aSElliott Hughes {"wdth": (0, 1.0, 1.0), "wght": (0, 1.0, 1.0)}, 242*e1fe3e4aSElliott Hughes {"wdth": (0, 1.0, 1.0), "wght": (0, 0.66, 1.0)}, 243*e1fe3e4aSElliott Hughes {"wdth": (0, 0.66, 1.0), "wght": (0, 0.66, 1.0)}, 244*e1fe3e4aSElliott Hughes ], 245*e1fe3e4aSElliott Hughes [ 246*e1fe3e4aSElliott Hughes {}, 247*e1fe3e4aSElliott Hughes {0: 1.0}, 248*e1fe3e4aSElliott Hughes {0: 1.0}, 249*e1fe3e4aSElliott Hughes {0: 1.0}, 250*e1fe3e4aSElliott Hughes {0: 1.0}, 251*e1fe3e4aSElliott Hughes {0: 1.0}, 252*e1fe3e4aSElliott Hughes {0: 1.0, 4: 1.0, 5: 1.0}, 253*e1fe3e4aSElliott Hughes { 254*e1fe3e4aSElliott Hughes 0: 1.0, 255*e1fe3e4aSElliott Hughes 3: 0.7555555555555555, 256*e1fe3e4aSElliott Hughes 4: 0.24444444444444444, 257*e1fe3e4aSElliott Hughes 5: 1.0, 258*e1fe3e4aSElliott Hughes 6: 0.66, 259*e1fe3e4aSElliott Hughes }, 260*e1fe3e4aSElliott Hughes { 261*e1fe3e4aSElliott Hughes 0: 1.0, 262*e1fe3e4aSElliott Hughes 3: 0.7555555555555555, 263*e1fe3e4aSElliott Hughes 4: 0.24444444444444444, 264*e1fe3e4aSElliott Hughes 5: 0.66, 265*e1fe3e4aSElliott Hughes 6: 0.43560000000000004, 266*e1fe3e4aSElliott Hughes 7: 0.66, 267*e1fe3e4aSElliott Hughes }, 268*e1fe3e4aSElliott Hughes ], 269*e1fe3e4aSElliott Hughes ), 270*e1fe3e4aSElliott Hughes ( 271*e1fe3e4aSElliott Hughes [ 272*e1fe3e4aSElliott Hughes {}, 273*e1fe3e4aSElliott Hughes {"bar": 0.5}, 274*e1fe3e4aSElliott Hughes {"bar": 1.0}, 275*e1fe3e4aSElliott Hughes {"foo": 1.0}, 276*e1fe3e4aSElliott Hughes {"bar": 0.5, "foo": 1.0}, 277*e1fe3e4aSElliott Hughes {"bar": 1.0, "foo": 1.0}, 278*e1fe3e4aSElliott Hughes ], 279*e1fe3e4aSElliott Hughes None, 280*e1fe3e4aSElliott Hughes [ 281*e1fe3e4aSElliott Hughes {}, 282*e1fe3e4aSElliott Hughes {"bar": 0.5}, 283*e1fe3e4aSElliott Hughes {"bar": 1.0}, 284*e1fe3e4aSElliott Hughes {"foo": 1.0}, 285*e1fe3e4aSElliott Hughes {"bar": 0.5, "foo": 1.0}, 286*e1fe3e4aSElliott Hughes {"bar": 1.0, "foo": 1.0}, 287*e1fe3e4aSElliott Hughes ], 288*e1fe3e4aSElliott Hughes [ 289*e1fe3e4aSElliott Hughes {}, 290*e1fe3e4aSElliott Hughes {"bar": (0, 0.5, 1.0)}, 291*e1fe3e4aSElliott Hughes {"bar": (0.5, 1.0, 1.0)}, 292*e1fe3e4aSElliott Hughes {"foo": (0, 1.0, 1.0)}, 293*e1fe3e4aSElliott Hughes {"bar": (0, 0.5, 1.0), "foo": (0, 1.0, 1.0)}, 294*e1fe3e4aSElliott Hughes {"bar": (0.5, 1.0, 1.0), "foo": (0, 1.0, 1.0)}, 295*e1fe3e4aSElliott Hughes ], 296*e1fe3e4aSElliott Hughes [ 297*e1fe3e4aSElliott Hughes {}, 298*e1fe3e4aSElliott Hughes {0: 1.0}, 299*e1fe3e4aSElliott Hughes {0: 1.0}, 300*e1fe3e4aSElliott Hughes {0: 1.0}, 301*e1fe3e4aSElliott Hughes {0: 1.0, 1: 1.0, 3: 1.0}, 302*e1fe3e4aSElliott Hughes {0: 1.0, 2: 1.0, 3: 1.0}, 303*e1fe3e4aSElliott Hughes ], 304*e1fe3e4aSElliott Hughes ), 305*e1fe3e4aSElliott Hughes ( 306*e1fe3e4aSElliott Hughes [ 307*e1fe3e4aSElliott Hughes {}, 308*e1fe3e4aSElliott Hughes {"foo": 0.25}, 309*e1fe3e4aSElliott Hughes {"foo": 0.5}, 310*e1fe3e4aSElliott Hughes {"foo": 0.75}, 311*e1fe3e4aSElliott Hughes {"foo": 1.0}, 312*e1fe3e4aSElliott Hughes {"bar": 0.25}, 313*e1fe3e4aSElliott Hughes {"bar": 0.75}, 314*e1fe3e4aSElliott Hughes {"bar": 1.0}, 315*e1fe3e4aSElliott Hughes ], 316*e1fe3e4aSElliott Hughes None, 317*e1fe3e4aSElliott Hughes [ 318*e1fe3e4aSElliott Hughes {}, 319*e1fe3e4aSElliott Hughes {"bar": 0.25}, 320*e1fe3e4aSElliott Hughes {"bar": 0.75}, 321*e1fe3e4aSElliott Hughes {"bar": 1.0}, 322*e1fe3e4aSElliott Hughes {"foo": 0.25}, 323*e1fe3e4aSElliott Hughes {"foo": 0.5}, 324*e1fe3e4aSElliott Hughes {"foo": 0.75}, 325*e1fe3e4aSElliott Hughes {"foo": 1.0}, 326*e1fe3e4aSElliott Hughes ], 327*e1fe3e4aSElliott Hughes [ 328*e1fe3e4aSElliott Hughes {}, 329*e1fe3e4aSElliott Hughes {"bar": (0.0, 0.25, 1.0)}, 330*e1fe3e4aSElliott Hughes {"bar": (0.25, 0.75, 1.0)}, 331*e1fe3e4aSElliott Hughes {"bar": (0.75, 1.0, 1.0)}, 332*e1fe3e4aSElliott Hughes {"foo": (0.0, 0.25, 1.0)}, 333*e1fe3e4aSElliott Hughes {"foo": (0.25, 0.5, 1.0)}, 334*e1fe3e4aSElliott Hughes {"foo": (0.5, 0.75, 1.0)}, 335*e1fe3e4aSElliott Hughes {"foo": (0.75, 1.0, 1.0)}, 336*e1fe3e4aSElliott Hughes ], 337*e1fe3e4aSElliott Hughes [ 338*e1fe3e4aSElliott Hughes {}, 339*e1fe3e4aSElliott Hughes {0: 1.0}, 340*e1fe3e4aSElliott Hughes {0: 1.0, 1: 0.3333333333333333}, 341*e1fe3e4aSElliott Hughes {0: 1.0}, 342*e1fe3e4aSElliott Hughes {0: 1.0}, 343*e1fe3e4aSElliott Hughes {0: 1.0, 4: 0.6666666666666666}, 344*e1fe3e4aSElliott Hughes {0: 1.0, 4: 0.3333333333333333, 5: 0.5}, 345*e1fe3e4aSElliott Hughes {0: 1.0}, 346*e1fe3e4aSElliott Hughes ], 347*e1fe3e4aSElliott Hughes ), 348*e1fe3e4aSElliott Hughes ( 349*e1fe3e4aSElliott Hughes [ 350*e1fe3e4aSElliott Hughes {}, 351*e1fe3e4aSElliott Hughes {"foo": 0.25}, 352*e1fe3e4aSElliott Hughes {"foo": 0.5}, 353*e1fe3e4aSElliott Hughes {"foo": 0.75}, 354*e1fe3e4aSElliott Hughes {"foo": 1.0}, 355*e1fe3e4aSElliott Hughes {"bar": 0.25}, 356*e1fe3e4aSElliott Hughes {"bar": 0.75}, 357*e1fe3e4aSElliott Hughes {"bar": 1.0}, 358*e1fe3e4aSElliott Hughes ], 359*e1fe3e4aSElliott Hughes None, 360*e1fe3e4aSElliott Hughes [ 361*e1fe3e4aSElliott Hughes {}, 362*e1fe3e4aSElliott Hughes {"bar": 0.25}, 363*e1fe3e4aSElliott Hughes {"bar": 0.75}, 364*e1fe3e4aSElliott Hughes {"bar": 1.0}, 365*e1fe3e4aSElliott Hughes {"foo": 0.25}, 366*e1fe3e4aSElliott Hughes {"foo": 0.5}, 367*e1fe3e4aSElliott Hughes {"foo": 0.75}, 368*e1fe3e4aSElliott Hughes {"foo": 1.0}, 369*e1fe3e4aSElliott Hughes ], 370*e1fe3e4aSElliott Hughes [ 371*e1fe3e4aSElliott Hughes {}, 372*e1fe3e4aSElliott Hughes {"bar": (0, 0.25, 1.0)}, 373*e1fe3e4aSElliott Hughes {"bar": (0.25, 0.75, 1.0)}, 374*e1fe3e4aSElliott Hughes {"bar": (0.75, 1.0, 1.0)}, 375*e1fe3e4aSElliott Hughes {"foo": (0, 0.25, 1.0)}, 376*e1fe3e4aSElliott Hughes {"foo": (0.25, 0.5, 1.0)}, 377*e1fe3e4aSElliott Hughes {"foo": (0.5, 0.75, 1.0)}, 378*e1fe3e4aSElliott Hughes {"foo": (0.75, 1.0, 1.0)}, 379*e1fe3e4aSElliott Hughes ], 380*e1fe3e4aSElliott Hughes [ 381*e1fe3e4aSElliott Hughes {}, 382*e1fe3e4aSElliott Hughes {0: 1.0}, 383*e1fe3e4aSElliott Hughes {0: 1.0, 1: 0.3333333333333333}, 384*e1fe3e4aSElliott Hughes {0: 1.0}, 385*e1fe3e4aSElliott Hughes {0: 1.0}, 386*e1fe3e4aSElliott Hughes {0: 1.0, 4: 0.6666666666666666}, 387*e1fe3e4aSElliott Hughes {0: 1.0, 4: 0.3333333333333333, 5: 0.5}, 388*e1fe3e4aSElliott Hughes {0: 1.0}, 389*e1fe3e4aSElliott Hughes ], 390*e1fe3e4aSElliott Hughes ), 391*e1fe3e4aSElliott Hughes ], 392*e1fe3e4aSElliott Hughes ) 393*e1fe3e4aSElliott Hughes def test_init(self, locations, axisOrder, sortedLocs, supports, deltaWeights): 394*e1fe3e4aSElliott Hughes model = VariationModel(locations, axisOrder=axisOrder) 395*e1fe3e4aSElliott Hughes 396*e1fe3e4aSElliott Hughes assert model.locations == sortedLocs 397*e1fe3e4aSElliott Hughes assert model.supports == supports 398*e1fe3e4aSElliott Hughes assert model.deltaWeights == deltaWeights 399*e1fe3e4aSElliott Hughes 400*e1fe3e4aSElliott Hughes def test_init_duplicate_locations(self): 401*e1fe3e4aSElliott Hughes with pytest.raises(VariationModelError, match="Locations must be unique."): 402*e1fe3e4aSElliott Hughes VariationModel( 403*e1fe3e4aSElliott Hughes [ 404*e1fe3e4aSElliott Hughes {"foo": 0.0, "bar": 0.0}, 405*e1fe3e4aSElliott Hughes {"foo": 1.0, "bar": 1.0}, 406*e1fe3e4aSElliott Hughes {"bar": 1.0, "foo": 1.0}, 407*e1fe3e4aSElliott Hughes ] 408*e1fe3e4aSElliott Hughes ) 409*e1fe3e4aSElliott Hughes 410*e1fe3e4aSElliott Hughes @pytest.mark.parametrize( 411*e1fe3e4aSElliott Hughes "locations, axisOrder, masterValues, instanceLocation, expectedValue, masterScalars", 412*e1fe3e4aSElliott Hughes [ 413*e1fe3e4aSElliott Hughes ( 414*e1fe3e4aSElliott Hughes [ 415*e1fe3e4aSElliott Hughes {}, 416*e1fe3e4aSElliott Hughes {"axis_A": 1.0}, 417*e1fe3e4aSElliott Hughes {"axis_B": 1.0}, 418*e1fe3e4aSElliott Hughes {"axis_A": 1.0, "axis_B": 1.0}, 419*e1fe3e4aSElliott Hughes {"axis_A": 0.5, "axis_B": 1.0}, 420*e1fe3e4aSElliott Hughes {"axis_A": 1.0, "axis_B": 0.5}, 421*e1fe3e4aSElliott Hughes ], 422*e1fe3e4aSElliott Hughes ["axis_A", "axis_B"], 423*e1fe3e4aSElliott Hughes [ 424*e1fe3e4aSElliott Hughes 0, 425*e1fe3e4aSElliott Hughes 10, 426*e1fe3e4aSElliott Hughes 20, 427*e1fe3e4aSElliott Hughes 70, 428*e1fe3e4aSElliott Hughes 50, 429*e1fe3e4aSElliott Hughes 60, 430*e1fe3e4aSElliott Hughes ], 431*e1fe3e4aSElliott Hughes { 432*e1fe3e4aSElliott Hughes "axis_A": 0.5, 433*e1fe3e4aSElliott Hughes "axis_B": 0.5, 434*e1fe3e4aSElliott Hughes }, 435*e1fe3e4aSElliott Hughes 37.5, 436*e1fe3e4aSElliott Hughes [0.25, 0.0, 0.0, -0.25, 0.5, 0.5], 437*e1fe3e4aSElliott Hughes ), 438*e1fe3e4aSElliott Hughes ], 439*e1fe3e4aSElliott Hughes ) 440*e1fe3e4aSElliott Hughes def test_interpolation( 441*e1fe3e4aSElliott Hughes self, 442*e1fe3e4aSElliott Hughes locations, 443*e1fe3e4aSElliott Hughes axisOrder, 444*e1fe3e4aSElliott Hughes masterValues, 445*e1fe3e4aSElliott Hughes instanceLocation, 446*e1fe3e4aSElliott Hughes expectedValue, 447*e1fe3e4aSElliott Hughes masterScalars, 448*e1fe3e4aSElliott Hughes ): 449*e1fe3e4aSElliott Hughes model = VariationModel(locations, axisOrder=axisOrder) 450*e1fe3e4aSElliott Hughes 451*e1fe3e4aSElliott Hughes interpolatedValue = model.interpolateFromMasters(instanceLocation, masterValues) 452*e1fe3e4aSElliott Hughes assert interpolatedValue == expectedValue 453*e1fe3e4aSElliott Hughes 454*e1fe3e4aSElliott Hughes assert masterScalars == model.getMasterScalars(instanceLocation) 455*e1fe3e4aSElliott Hughes 456*e1fe3e4aSElliott Hughes assert model.interpolateFromValuesAndScalars( 457*e1fe3e4aSElliott Hughes masterValues, masterScalars 458*e1fe3e4aSElliott Hughes ) == pytest.approx(interpolatedValue) 459*e1fe3e4aSElliott Hughes 460*e1fe3e4aSElliott Hughes @pytest.mark.parametrize( 461*e1fe3e4aSElliott Hughes "masterLocations, location, expected", 462*e1fe3e4aSElliott Hughes [ 463*e1fe3e4aSElliott Hughes (locationsA, {"wght": 0, "wdth": 0}, [1, 0, 0]), 464*e1fe3e4aSElliott Hughes ( 465*e1fe3e4aSElliott Hughes locationsA, 466*e1fe3e4aSElliott Hughes {"wght": 0.5, "wdth": 0}, 467*e1fe3e4aSElliott Hughes [0.5, 0.5, 0], 468*e1fe3e4aSElliott Hughes ), 469*e1fe3e4aSElliott Hughes (locationsA, {"wght": 1, "wdth": 0}, [0, 1, 0]), 470*e1fe3e4aSElliott Hughes ( 471*e1fe3e4aSElliott Hughes locationsA, 472*e1fe3e4aSElliott Hughes {"wght": 0, "wdth": 0.5}, 473*e1fe3e4aSElliott Hughes [0.5, 0, 0.5], 474*e1fe3e4aSElliott Hughes ), 475*e1fe3e4aSElliott Hughes (locationsA, {"wght": 0, "wdth": 1}, [0, 0, 1]), 476*e1fe3e4aSElliott Hughes (locationsA, {"wght": 1, "wdth": 1}, [-1, 1, 1]), 477*e1fe3e4aSElliott Hughes ( 478*e1fe3e4aSElliott Hughes locationsA, 479*e1fe3e4aSElliott Hughes {"wght": 0.5, "wdth": 0.5}, 480*e1fe3e4aSElliott Hughes [0, 0.5, 0.5], 481*e1fe3e4aSElliott Hughes ), 482*e1fe3e4aSElliott Hughes ( 483*e1fe3e4aSElliott Hughes locationsA, 484*e1fe3e4aSElliott Hughes {"wght": 0.75, "wdth": 0.75}, 485*e1fe3e4aSElliott Hughes [-0.5, 0.75, 0.75], 486*e1fe3e4aSElliott Hughes ), 487*e1fe3e4aSElliott Hughes ( 488*e1fe3e4aSElliott Hughes locationsB, 489*e1fe3e4aSElliott Hughes {"wght": 1, "wdth": 1}, 490*e1fe3e4aSElliott Hughes [0, 0, 0, 1], 491*e1fe3e4aSElliott Hughes ), 492*e1fe3e4aSElliott Hughes ( 493*e1fe3e4aSElliott Hughes locationsB, 494*e1fe3e4aSElliott Hughes {"wght": 0.5, "wdth": 0}, 495*e1fe3e4aSElliott Hughes [0.5, 0.5, 0, 0], 496*e1fe3e4aSElliott Hughes ), 497*e1fe3e4aSElliott Hughes ( 498*e1fe3e4aSElliott Hughes locationsB, 499*e1fe3e4aSElliott Hughes {"wght": 1, "wdth": 0.5}, 500*e1fe3e4aSElliott Hughes [0, 0.5, 0, 0.5], 501*e1fe3e4aSElliott Hughes ), 502*e1fe3e4aSElliott Hughes ( 503*e1fe3e4aSElliott Hughes locationsB, 504*e1fe3e4aSElliott Hughes {"wght": 0.5, "wdth": 0.5}, 505*e1fe3e4aSElliott Hughes [0.25, 0.25, 0.25, 0.25], 506*e1fe3e4aSElliott Hughes ), 507*e1fe3e4aSElliott Hughes ( 508*e1fe3e4aSElliott Hughes locationsC, 509*e1fe3e4aSElliott Hughes {"wght": 0.5, "wdth": 0}, 510*e1fe3e4aSElliott Hughes [0, 1, 0, 0, 0], 511*e1fe3e4aSElliott Hughes ), 512*e1fe3e4aSElliott Hughes ( 513*e1fe3e4aSElliott Hughes locationsC, 514*e1fe3e4aSElliott Hughes {"wght": 0.25, "wdth": 0}, 515*e1fe3e4aSElliott Hughes [0.5, 0.5, 0, 0, 0], 516*e1fe3e4aSElliott Hughes ), 517*e1fe3e4aSElliott Hughes ( 518*e1fe3e4aSElliott Hughes locationsC, 519*e1fe3e4aSElliott Hughes {"wght": 0.75, "wdth": 0}, 520*e1fe3e4aSElliott Hughes [0, 0.5, 0.5, 0, 0], 521*e1fe3e4aSElliott Hughes ), 522*e1fe3e4aSElliott Hughes ( 523*e1fe3e4aSElliott Hughes locationsC, 524*e1fe3e4aSElliott Hughes {"wght": 0.5, "wdth": 1}, 525*e1fe3e4aSElliott Hughes [-0.5, 1, -0.5, 0.5, 0.5], 526*e1fe3e4aSElliott Hughes ), 527*e1fe3e4aSElliott Hughes ( 528*e1fe3e4aSElliott Hughes locationsC, 529*e1fe3e4aSElliott Hughes {"wght": 0.75, "wdth": 1}, 530*e1fe3e4aSElliott Hughes [-0.25, 0.5, -0.25, 0.25, 0.75], 531*e1fe3e4aSElliott Hughes ), 532*e1fe3e4aSElliott Hughes ], 533*e1fe3e4aSElliott Hughes ) 534*e1fe3e4aSElliott Hughes def test_getMasterScalars(self, masterLocations, location, expected): 535*e1fe3e4aSElliott Hughes model = VariationModel(masterLocations) 536*e1fe3e4aSElliott Hughes assert model.getMasterScalars(location) == expected 537