The repository had no licence at all, so every source was all-rights-reserved by default. Add the verbatim MIT text at LICENSE (Copyright (c) 2026 Martino Ferrari) and a two-line SPDX header to each of the 113 first-party sources -- 48 include/plot, 26 src, 10 adapters, 5 examples, 21 tests, 3 tools -- so the grant travels with each file rather than relying on the root document alone. Scripts keep their shebang on line 1; the SPDX lines follow it. Genuinely vendored code is untouched: third_party/stb_truetype.h carries no header of ours. src/render/embedded_mono_font.cpp is generated, so tools/fonts/gen_atlas.py emit() now writes the two lines into its header comment and the file was regenerated -- gen_atlas.py --check passes and the regeneration adds only those comment lines to the previously committed file. README's provenance section now states MIT and links LICENSE. No code, test or public API change.
53 lines
1.9 KiB
C++
53 lines
1.9 KiB
C++
// SPDX-License-Identifier: MIT
|
|
// SPDX-FileCopyrightText: 2026 Martino Ferrari
|
|
|
|
#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.
|
|
//
|
|
// Both classes are built: the tick set is the only source of positions, and
|
|
// `Style::grid_*_visible` decides what the renderer stages from here, so a class
|
|
// is never filtered out of the tick set (that would be a second, geometry-side
|
|
// switch for the same behaviour, and the grid would then disagree with the tick
|
|
// list a caller can read).
|
|
if (vertical) {
|
|
for (const Tick& tick : x_ticks) {
|
|
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 (!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
|