#include #include #include "Abs_Axis_p.h" namespace renderive { RENDERIVE_DEFINE_RENDERABLE_BINDING(Abs_Axis, Abs_Axis_Private, Abs_Axis_Render_State, Abs_Axis_Input_Data, "AbsAxis") RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, x) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, y) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Orientation, orientation) size_t Abs_Axis::pixel_size() { return d()->edit_state_value(&Abs_Axis_Render_State::pixel_size); } void Abs_Axis::set_pixel_size(size_t value) { d()->set_state_value(&Abs_Axis_Render_State::pixel_size, std::max(1, value)); } RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, tick_length) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, sub_tick_length) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Color, color) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Number_Locale, locale) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, std::string, unit_text) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Font, unit_text_font) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Pen, unit_text_pen) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Brush, unit_text_background_brush) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, rotate) double Abs_Axis::pixel_to_coord(double pixel) { return d()->edit_pixel_to_coord(pixel); } double Abs_Axis::coord_to_pixel(double coord) { return d()->edit_coord_to_pixel(coord); } std::vector Abs_Axis_Private::create_tick_vector(double tick_step, const Range& range) { double tick_origin = render_state()->coord_start; std::vector result; auto first_step = static_cast(std::floor(std::abs((range.origin - tick_origin) / tick_step))); auto last_step = static_cast(std::ceil(std::abs(range.target - tick_origin) / tick_step)); int tick_count = static_cast(std::abs(last_step - first_step) + 1); if (tick_count < 0) tick_count = 0; if (range.origin > range.target) tick_step = -tick_step; result.resize(tick_count); for (int i = 0; i < tick_count; ++i) { result[i] = tick_origin + (double)(first_step + i) * tick_step; } return result; } std::vector Abs_Axis_Private::create_label_vector(const std::vector& ticks, SRC src) { std::vector result; result.reserve(ticks.size()); for (double tick_coord : ticks) result.push_back(get_tick_label(tick_coord, src)); return result; } std::vector Abs_Axis_Private::create_sub_tick_vector(int sub_tick_count, const std::vector& ticks, const Range& range) { std::vector result; if (sub_tick_count <= 0 || ticks.size() < 2) return result; result.reserve((ticks.size() - 1) * sub_tick_count); for (int i = 1; i < ticks.size(); ++i) { double sub_tick_step = (ticks.at(i) - ticks.at(i - 1)) / double(sub_tick_count + 1); for (int k = 1; k <= sub_tick_count; ++k) result.push_back(ticks.at(i - 1) + k * sub_tick_step); } while (!result.empty() && !range.contain(result.back())) { result.pop_back(); } return result; } int Abs_Axis_Private::get_sub_tick_count(double tick_step) { int result = 1; double epsilon = 0.01; double int_partf; int int_part; double frac_part = modf(get_mantissa(tick_step), &int_partf); int_part = int(int_partf); if (frac_part < epsilon || 1.0 - frac_part < epsilon) { if (1.0 - frac_part < epsilon) ++int_part; switch (int_part) { case 1: result = 4; break; case 2: result = 3; break; case 3: result = 2; break; case 4: result = 3; break; case 5: result = 4; break; case 6: result = 2; break; case 7: result = 6; break; case 8: result = 3; break; case 9: result = 2; break; } } else { if (std::abs(frac_part - 0.5) < epsilon) { switch (int_part) { case 1: result = 2; break; case 2: result = 4; break; case 3: result = 4; break; case 4: result = 2; break; case 5: result = 4; break; case 6: result = 4; break; case 7: result = 2; break; case 8: result = 4; break; case 9: result = 4; break; } } } return result; } double Abs_Axis_Private::get_mantissa(double input, double* magnitude) { const double mag = std::pow(10.0, std::floor(std::log10(input))); if (magnitude) *magnitude = mag; return input / mag; } double Abs_Axis_Private::clean_mantissa(double input) { double magnitude; const double mantissa = get_mantissa(input, &magnitude); return pick_closest(mantissa, {1.0, 2.0, 2.5, 5.0, 10.0}) * magnitude; } double Abs_Axis_Private::pick_closest(double target, const std::vector& candidates) { if (candidates.empty()) return target; if (candidates.size() == 1) return candidates.front(); std::vector::const_iterator it = std::lower_bound(candidates.cbegin(), candidates.cend(), target); if (it == candidates.cend()) return *(it - 1); else if (it == candidates.cbegin()) return *it; else return target - *(it - 1) < *it - target ? *(it - 1) : *it; } std::string Abs_Axis_Private::get_tick_label(double tick, SRC src) { auto render_state = reinterpret_cast(state(src)); return format_number(tick, Number_Format{.precision = render_state->number_precision}); } double Abs_Axis::start_coord() { return d()->edit_axis_state()->coord_start; } double Abs_Axis::end_coord() { auto render_state = d()->edit_axis_state(); return render_state->coord_start + render_state->coord_length; } Range Abs_Axis::coord_range() { auto render_state = d()->edit_axis_state(); return {render_state->coord_start, render_state->coord_start + render_state->coord_length}; } int Abs_Axis::get_pixel_point_size(Range range) { auto render_state = d()->edit_axis_state(); double length = coord_range().length(); if (length == 0.0) return 0; return static_cast(std::abs(range.length() / length) * render_state->pixel_size); } int Abs_Axis::get_pixel_point_size() { auto render_state = d()->edit_axis_state(); return static_cast(render_state->pixel_size); } double Abs_Axis::get_tick_step(const Range& range) { return d()->get_tick_step(range); } int Abs_Axis::get_sub_tick_count(double tick_step) { return d()->get_sub_tick_count(tick_step); } std::string Abs_Axis::get_tick_label(double tick) { return d()->edit_tick_label(tick); } std::vector Abs_Axis::create_label_vector(const std::vector& ticks) { return d()->edit_label_vector(ticks); } std::vector Abs_Axis::create_tick_vector(double tick_step, const Range& range) { return d()->create_tick_vector(tick_step, range); } std::vector Abs_Axis::create_sub_tick_vector(int sub_tick_count, const std::vector& ticks, const Range& range) { return d()->create_sub_tick_vector(sub_tick_count, ticks, range); } } // namespace renderive