[instancer-solver] add renormalizeValue() and store axis->distances map

This commit is contained in:
Qunxin Liu 2023-07-17 09:46:03 -07:00
parent d92a7a58d8
commit 165f3e60ac
5 changed files with 80 additions and 8 deletions

View file

@ -228,6 +228,13 @@ struct AxisRecord
return defaultValue.to_float ();
}
TripleDistances get_triple_distances () const
{
float min, default_, max;
get_coordinates (min, default_, max);
return TripleDistances (min, default_, max);
}
public:
Tag axisTag; /* Tag identifying the design variation for the axis. */
protected:

View file

@ -392,8 +392,47 @@ static inline float normalizeValue (float v, const Triple &triple, bool extrapol
}
}
static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
{ return TripleDistances (v.positive, v.negative); }
float renormalizeValue (float v, const Triple &triple,
const TripleDistances &triple_distances, bool extrapolate)
{
float lower = triple.minimum, def = triple.middle, upper = triple.maximum;
assert (lower <= def && def <= upper);
if (!extrapolate)
v = hb_max (hb_min (v, upper), lower);
if (v == def)
return 0.f;
if (def < 0.f)
return -renormalizeValue (-v, _reverse_negate (triple),
_reverse_triple_distances (triple_distances), extrapolate);
/* default >= 0 and v != default */
if (v > def)
return (v - def) / (upper - def);
/* v < def */
if (lower >= 0.f)
return (v - def) / (def - lower);
/* lower < 0 and v < default */
float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
float v_distance;
if (v >= 0.f)
v_distance = (def - v) * triple_distances.positive;
else
v_distance = (-v) * triple_distances.negative + triple_distances.positive * def;
return (-v_distance) /total_distance;
}
result_t
rebase_tent (Triple tent, Triple axisLimit)
rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
{
assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f);
assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f);
@ -401,7 +440,7 @@ rebase_tent (Triple tent, Triple axisLimit)
result_t sols = _solve (tent, axisLimit);
auto n = [&axisLimit] (float v) { return normalizeValue (v, axisLimit, true); };
auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
result_t out;
for (auto &p : sols)

View file

@ -27,6 +27,21 @@
#include "hb.hh"
/* pre-normalized distances */
struct TripleDistances
{
TripleDistances (): negative (1.f), positive (1.f) {}
TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {}
TripleDistances (float min, float default_, float max)
{
negative = default_ - min;
positive = max - default_;
}
float negative;
float positive;
};
struct Triple {
Triple () :
@ -66,6 +81,7 @@ struct Triple {
return current;
}
float minimum;
float middle;
float maximum;
@ -74,6 +90,12 @@ struct Triple {
using result_item_t = hb_pair_t<float, Triple>;
using result_t = hb_vector_t<result_item_t>;
/* renormalize a normalized value v to the range of an axis,
* considering the prenormalized distances as well as the new axis limits.
* Ported from fonttools */
HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
const TripleDistances &triple_distances,
bool extrapolate = true);
/* Given a tuple (lower,peak,upper) "tent" and new axis limits
* (axisMin,axisDefault,axisMax), solves how to represent the tent
* under the new axis configuration. All values are in normalized
@ -85,6 +107,6 @@ using result_t = hb_vector_t<result_item_t>;
* If tent value is Triple{}, that is a special deltaset that should
* be always-enabled (called "gain").
*/
HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit);
HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances);
#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */

View file

@ -105,6 +105,8 @@ HB_SUBSET_PLAN_MEMBER (hb_vector_t<int>, normalized_coords)
//user specified axes range map
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), user_axes_location)
//axis->TripleDistances map (distances in the pre-normalized space)
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, TripleDistances>), axes_triple_distances)
//retained old axis index -> new axis index mapping in fvar axis array
HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map)

View file

@ -930,12 +930,14 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
new_axis_idx++;
}
if (plan->user_axes_location.has (axis_tag))
Triple *axis_range;
if (plan->user_axes_location.has (axis_tag, &axis_range))
{
Triple axis_range = plan->user_axes_location.get (axis_tag);
int normalized_min = axis.normalize_axis_value (axis_range.minimum);
int normalized_default = axis.normalize_axis_value (axis_range.middle);
int normalized_max = axis.normalize_axis_value (axis_range.maximum);
plan->axes_triple_distances.set (axis_tag, axis.get_triple_distances ());
int normalized_min = axis.normalize_axis_value (axis_range->minimum);
int normalized_default = axis.normalize_axis_value (axis_range->middle);
int normalized_max = axis.normalize_axis_value (axis_range->maximum);
if (has_avar && old_axis_idx < avar_axis_count)
{