#include "Time_Axis.h" #include "Axis_Format.h" #include #include 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::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(latest), static_cast(earliest)} : Range{static_cast(earliest), static_cast(latest)}; }); } double Time_Axis_Control::tick_step(Range range) const { const double available = static_cast(pixel_length()); const double label_width = std::max(48.0, font().size * 7.0); const double spacing = static_cast(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(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