46 lines
1.6 KiB
C++
46 lines
1.6 KiB
C++
#include <plot/plot/grid.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace plot {
|
|
namespace {
|
|
|
|
/// True when `v` lies in `r`, allowing the rounding slack a generated tick can
|
|
/// carry at the range's edge: a tick that is within 1e-9 relative of the edge is
|
|
/// the edge, and dropping it would leave the frame un-drawn.
|
|
bool inside(f64 v, Range r) noexcept {
|
|
const f64 tolerance = std::max(std::fabs(r.min), std::fabs(r.max)) * 1e-9 + 1e-12;
|
|
return v >= r.min - tolerance && v <= r.max + tolerance;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void Grid::build(const std::vector<Tick>& x_ticks, Range x_range,
|
|
const std::vector<Tick>& y_ticks, Range y_range) {
|
|
lines_.clear();
|
|
if (!std::isfinite(x_range.min) || !std::isfinite(x_range.max) ||
|
|
!std::isfinite(y_range.min) || !std::isfinite(y_range.max)) {
|
|
return;
|
|
}
|
|
|
|
// Segments stay in data space: the renderer applies the transform, so a pan or
|
|
// zoom needs no grid rebuild other than for a changed tick set.
|
|
if (vertical) {
|
|
for (const Tick& tick : x_ticks) {
|
|
if (!tick.major && !show_minor) continue;
|
|
if (!std::isfinite(tick.value) || !inside(tick.value, x_range)) continue;
|
|
lines_.push_back(GridLine{tick.value, y_range.min, tick.value, y_range.max, tick.major});
|
|
}
|
|
}
|
|
if (horizontal) {
|
|
for (const Tick& tick : y_ticks) {
|
|
if (!tick.major && !show_minor) continue;
|
|
if (!std::isfinite(tick.value) || !inside(tick.value, y_range)) continue;
|
|
lines_.push_back(GridLine{x_range.min, tick.value, x_range.max, tick.value, tick.major});
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace plot
|