Files
Renderive/render_2D/axis/Time_Axis.cpp
T
2026-08-12 00:06:44 +08:00

71 lines
2.8 KiB
C++

#include "Time_Axis.h"
#include "Axis_Format.h"
#include <algorithm>
#include <cmath>
namespace renderive::detail {
namespace {
Time_Axis_State time_state_from(const Time_Axis_Properties& properties) {
Time_Axis_State state;
static_cast<Time_Axis_Properties&>(state) = properties;
return state;
}
} // namespace
Time_Axis_Control::Time_Axis_Control(Plot_Core& plot, const Time_Axis_Properties& properties)
: Axis_State_Strategy(plot, time_state_from(properties)) {}
std::size_t Time_Axis_Control::time_point_count() const {
return read([](const Time_Axis_State& state) { return state.samples.size(); });
}
int Time_Axis_Control::append_time(Time_Of_Day time) {
int tick{};
update([&](Time_Axis_State& state) {
tick = state.next_tick++;
state.samples.emplace_back(tick, time);
const auto limit = static_cast<std::size_t>(std::max(512, state.visible_count.get() * 4));
while (state.samples.size() > limit)
state.samples.pop_front();
});
return tick;
}
Time_Of_Day Time_Axis_Control::tick_to_time(int tick) const {
return read([tick](const Time_Axis_State& state) {
const auto iterator = std::find_if(state.samples.begin(), state.samples.end(),
[tick](const auto& value) { return value.first == tick; });
return iterator == state.samples.end() ? Time_Of_Day{} : iterator->second;
});
}
Range Time_Axis_Control::coordinate_range(const Time_Axis_State& state) const noexcept {
const int latest = std::max(1, state.next_tick - 1);
const int earliest = std::max(0, latest - state.visible_count.get() + 1);
return state.newest_at_start ? Range{static_cast<double>(latest), static_cast<double>(earliest)}
: Range{static_cast<double>(earliest), static_cast<double>(latest)};
}
double Time_Axis_Control::calculate_tick_step(Range range, const Time_Axis_State& state) const {
const double available = static_cast<double>(state.pixel_length);
const double label_width = std::max(48.0, state.unit_text_font.size * 7.0);
const double label_count =
std::max(1.0, available / (label_width + state.tick_label_spacing_px.get()));
return std::max(1.0, std::ceil(range.size() / label_count));
}
std::string Time_Axis_Control::format_tick_label(double tick, const Time_Axis_State& state) const {
const int target = static_cast<int>(std::llround(tick));
const auto iterator = std::find_if(state.samples.begin(), state.samples.end(),
[target](const auto& value) { return value.first == target; });
return iterator == state.samples.end()
? std::string{}
: formatted_axis_time(iterator->second, state.format);
}
} // namespace renderive::detail