Closed be5invis closed 5 years ago
Purposed data type:
interface VQ {
neutral: number;
variant: Array<[Region, number]>;
}
type Region = Array<[AxisTag, Tent]>;
interface Tent {
min: number;
peak: number;
max: number;
}
Old Region
type definition
type RegionOld = Map<AxisTag, Tent>;
Evaluation algorithm
function evalVQ(vq: VQ, instance: Map<AxisTag, number>){
let result = vq.neutral;
for(const [region, delta] of vq.variant) {
result += delta * weightRegion(region, instance);
}
return result;
}
function weightRegion(region: Region, instance: Map<AxisTag, number>) {
let weight = 1;
for(const [axis, tent] of region) {
weight *= weightTent(tent, instance.get(axis) || 0);
}
return weight;
}
function weightTent(t: Tent, coord: number) { ... }
Scaling algorithm.
function scale(scalar: number, vq: VQ) {
return {
neutral: vq.neutral * scalar,
variant: vq.variant.map(([region, delta]) => [region, delta * scalar])
};
}
Sum algorithm.
function add(a: VQ, b: VQ) {
return { neutral: a.neutral + b.neutral, variant: [...a.variant, ...b.variant] };
}
Multiplication algorithm.
function multiply(a: VQ, b: VQ) {
let variant : [Region, number][] = [];
for(const [r, d] of a.variant) variant.push([r, d * b.neutral]);
for(const [r, d] of b.variant) variant.push([r, d * a.neutral]);
for(const [ra, da] of a.variant) for(const [rb, db] of b.variant) {
variant.push([[...ra, ...rb], da * db]);
}
return { neutral: a.neutral * b.neutral, variant };
}
Close as AVAR
plus "duplicate axes" may partially solve this, and we may not need a real multiplication.
NOTE: To understand this you need basic abstract algebra knowledge.
Currently, point coordinates or metrics in a variable font (we call these values "Variable Quantity", abbr. VQ) can be proved forming a module, where you can define addition and scalar multiplication of VQs.
However, currently you cannot define multiplication of VQs (which means that VQs do not form a ring), which may cause problem when manipulating complex fonts.
However, by extending the current definition of variation region, we can achieve this and enable non-linear variations with minimal changes of the interpolation logic.
Status Quo
Mathematically, a VQ could be defined in this form:
where:
From the mathematical form we can easily prove that VQs form a module and we can define the addition and scalar multiplication as follows:
However we cannot define multiplication of VQs, since we may produce terms like in the product, and the old definiton of W does not support factors like this: in the original W definition, each region can only assign one "tent" to one axis.
Purposed change
We will change the definition of variation regions: each region will be able to associate multiple "tent"s to one region, the W function will be redefined as follows:
where:
Allowing multiple tents associated to one axis gives us the ability to define the product of two VQs:
where
DISCLAIMER: This is NOT a proposal from Microsoft, just from me.