12Region::BBox compute_bbox(
const AxisTransform& primary,
const BoundaryCurve& b_lo,
const BoundaryCurve& b_hi)
noexcept {
13 const auto lo_bounds = b_lo.bounds();
14 const auto hi_bounds = b_hi.bounds();
15 return {primary.a_lo, primary.a_hi, lo_bounds.first, hi_bounds.second};
28 secondary_scale_(secondary_scale),
29 b_lo_(std::move(b_lo)),
30 b_hi_(std::move(b_hi)),
31 bbox_((b_lo_ && b_hi_) ? compute_bbox(primary_, *b_lo_, *b_hi_) :
kEmptyBBox) {
32 if (!b_lo_ || !b_hi_) {
33 throw std::invalid_argument(
"Region: b_lo and b_hi BoundaryCurves must be non-null");
40 throw std::invalid_argument(
"Region: secondary axis scale must be LINEAR or LOG");
45 : primary_(other.primary_),
46 secondary_scale_(other.secondary_scale_),
47 b_lo_(std::move(other.b_lo_)),
48 b_hi_(std::move(other.b_hi_)),
55 primary_ = other.primary_;
56 secondary_scale_ = other.secondary_scale_;
57 b_lo_ = std::move(other.b_lo_);
58 b_hi_ = std::move(other.b_hi_);
72 const double b_lo_val = b_lo_->eval_fast(a);
73 const double b_hi_val = b_hi_->eval_fast(a);
74 return b >= b_lo_val && b <= b_hi_val;
78 const double xi = primary_.forward(a);
79 const double b_lo_val = b_lo_->eval(a);
80 const double b_hi_val = b_hi_->eval(a);
86 const double gb = (secondary_scale_ ==
AxisScale::LOG) ? std::log(b) : b;
87 const double g_lo = (secondary_scale_ ==
AxisScale::LOG) ? std::log(b_lo_val) : b_lo_val;
88 const double g_hi = (secondary_scale_ ==
AxisScale::LOG) ? std::log(b_hi_val) : b_hi_val;
89 const double span = g_hi - g_lo;
95 const double tol = std::numeric_limits<double>::epsilon() * (1.0 + std::abs(g_lo) + std::abs(g_hi));
96 const double eta = (std::abs(span) <= tol) ? std::numeric_limits<double>::quiet_NaN() : ((gb - g_lo) / span);
101 const double a = primary_.inverse(xi);
102 const double b_lo_val = b_lo_->eval(a);
103 const double b_hi_val = b_hi_->eval(a);
110 const double g_lo = std::log(b_lo_val);
111 const double g_hi = std::log(b_hi_val);
112 b = std::exp(g_lo + eta * (g_hi - g_lo));
114 b = b_lo_val + eta * (b_hi_val - b_lo_val);