@@ -114,6 +114,36 @@ Pwl::PerpType Pwl::Invert(Point const &xy, Point &perp, int &span,
return PerpType::None;
}
+Pwl Pwl::Inverse(bool *true_inverse, const double eps) const
+{
+ bool appended = false, prepended = false, neither = false;
+ Pwl inverse;
+
+ for (Point const &p : points_) {
+ if (inverse.Empty())
+ inverse.Append(p.y, p.x, eps);
+ else if (std::abs(inverse.points_.back().x - p.y) <= eps ||
+ std::abs(inverse.points_.front().x - p.y) <= eps)
+ /* do nothing */;
+ else if (p.y > inverse.points_.back().x) {
+ inverse.Append(p.y, p.x, eps);
+ appended = true;
+ } else if (p.y < inverse.points_.front().x) {
+ inverse.Prepend(p.y, p.x, eps);
+ prepended = true;
+ } else
+ neither = true;
+ }
+
+ // This is not a proper inverse if we found ourselves putting points
+ // onto both ends of the inverse, or if there were points that couldn't
+ // go on either.
+ if (true_inverse)
+ *true_inverse = !(neither || (appended && prepended));
+
+ return inverse;
+}
+
Pwl Pwl::Compose(Pwl const &other, const double eps) const
{
double this_x = points_[0].x, this_y = points_[0].y;
@@ -80,6 +80,9 @@ public:
};
PerpType Invert(Point const &xy, Point &perp, int &span,
const double eps = 1e-6) const;
+ // Compute the inverse function. Indicate if it is a proper (true)
+ // inverse, or only a best effort (e.g. input was non-monotonic).
+ Pwl Inverse(bool *true_inverse = nullptr, const double eps = 1e-6) const;
// Compose two Pwls together, doing "this" first and "other" after.
Pwl Compose(Pwl const &other, const double eps = 1e-6) const;
// Apply function to (x,y) values at every control point.