Files
Renderive/Core/Axis/Abs_Axis.cpp
T
2026-08-01 20:09:45 +08:00

212 lines
7.7 KiB
C++

#include <cmath>
#include <algorithm>
#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<std::size_t>(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<double> Abs_Axis_Private::create_tick_vector(double tick_step, const Range& range) {
double tick_origin = render_state()->coord_start;
std::vector<double> result;
auto first_step = static_cast<std::int64_t>(std::floor(std::abs((range.origin - tick_origin) / tick_step)));
auto last_step = static_cast<std::int64_t>(std::ceil(std::abs(range.target - tick_origin) / tick_step));
int tick_count = static_cast<int>(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<std::string> Abs_Axis_Private::create_label_vector(const std::vector<double>& ticks, SRC src) {
std::vector<std::string> result;
result.reserve(ticks.size());
for (double tick_coord : ticks)
result.push_back(get_tick_label(tick_coord, src));
return result;
}
std::vector<double> Abs_Axis_Private::create_sub_tick_vector(int sub_tick_count, const std::vector<double>& ticks, const Range& range) {
std::vector<double> 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<double>& candidates) {
if (candidates.empty())
return target;
if (candidates.size() == 1)
return candidates.front();
std::vector<double>::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<Abs_Axis_Render_State*>(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<int>(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<int>(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<std::string> Abs_Axis::create_label_vector(const std::vector<double>& ticks) {
return d()->edit_label_vector(ticks);
}
std::vector<double> Abs_Axis::create_tick_vector(double tick_step, const Range& range) {
return d()->create_tick_vector(tick_step, range);
}
std::vector<double> Abs_Axis::create_sub_tick_vector(int sub_tick_count, const std::vector<double>& ticks, const Range& range) {
return d()->create_sub_tick_vector(sub_tick_count, ticks, range);
}
} // namespace renderive