Files
Renderive/render_2D/axis/Time_Axis.cpp
T
2026-08-11 23:17:03 +08:00

126 lines
4.0 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) {
return {
std::max(2, properties.visible_count),
std::max(0, properties.tick_label_spacing_px),
properties.format,
properties.newest_at_start,
0,
{}
};
}
} // namespace
Time_Axis_Control::Time_Axis_Control(Plot_Core& plot, const Time_Axis_Properties& properties)
: Abs_Axis(plot, properties), time_(time_state_from(properties)) {}
int Time_Axis_Control::visible_time_point_count() const {
return time_.get<&Time_Axis_State::visible_count>();
}
void Time_Axis_Control::set_visible_time_point_count(int value) {
time_.set<&Time_Axis_State::visible_count>(std::max(2, value));
changed();
}
int Time_Axis_Control::tick_label_spacing_px() const {
return time_.get<&Time_Axis_State::tick_label_spacing_px>();
}
void Time_Axis_Control::set_tick_label_spacing_px(int value) {
time_.set<&Time_Axis_State::tick_label_spacing_px>(std::max(0, value));
changed();
}
std::string Time_Axis_Control::time_format() const {
return time_.get<&Time_Axis_State::format>();
}
void Time_Axis_Control::set_time_format(std::string value) {
time_.set<&Time_Axis_State::format>(std::move(value));
changed();
}
Font Time_Axis_Control::font() const { return unit_text_font(); }
void Time_Axis_Control::set_font(Font value) { set_unit_text_font(value); }
bool Time_Axis_Control::newest_at_axis_start() const {
return time_.get<&Time_Axis_State::newest_at_start>();
}
void Time_Axis_Control::set_newest_at_axis_start(bool value) {
time_.set<&Time_Axis_State::newest_at_start>(value);
changed();
}
std::size_t Time_Axis_Control::time_point_count() const {
return time_.read([](const Time_Axis_State& state) { return state.samples.size(); });
}
int Time_Axis_Control::append_time(Time_Of_Day time) {
int tick{};
time_.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 * 4));
while (state.samples.size() > limit)
state.samples.pop_front();
});
changed();
return tick;
}
Time_Of_Day Time_Axis_Control::tick_to_time(int tick) const {
return time_.read([tick](const Time_Axis_State& state) {
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::coord_range() const {
return time_.read([](const Time_Axis_State& state) {
const int latest = std::max(1, state.next_tick - 1);
const int earliest = std::max(0, latest - state.visible_count + 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::tick_step(Range range) const {
const double available = static_cast<double>(pixel_length());
const double label_width = std::max(48.0, font().size * 7.0);
const double spacing = static_cast<double>(tick_label_spacing_px());
const double label_count = std::max(1.0, available / (label_width + spacing));
return std::max(1.0, std::ceil(range.size() / label_count));
}
std::string Time_Axis_Control::tick_label(double tick) const {
const Time_Of_Day time = tick_to_time(static_cast<int>(std::llround(tick)));
if (!time.valid())
return {};
return formatted_axis_time(time, time_format());
}
void Time_Axis_Control::publish() {
Abs_Axis::publish();
time_.publish();
}
std::uint64_t Time_Axis_Control::state_revision() const {
return Abs_Axis::state_revision() + time_.state_revision();
}
} // namespace renderive::detail