#include #include "Abs_Axis_p.h" namespace YSG { using AbsAxis_Binding = Renderable_Binding; Abs_Axis::Abs_Axis() { AbsAxis_Binding::init(this, "AbsAxis"); } Abs_Axis_Private* Abs_Axis::d() { return AbsAxis_Binding::d(this); } Render_Data* Abs_Axis::create_render_data() { return AbsAxis_Binding::create_render_data(); } Render_State* Abs_Axis::create_render_state() { return AbsAxis_Binding::create_render_state(); } Input_Data* Abs_Axis::create_input_data() { return AbsAxis_Binding::create_input_data(); } int Abs_Axis::x(SRC src) { return d()->state_value(&Abs_Axis_Render_State::x, src); } void Abs_Axis::set_x(int value) { d()->set_state_value(&Abs_Axis_Render_State::x, value); } int Abs_Axis::y(SRC src) { return d()->state_value(&Abs_Axis_Render_State::y, src); } void Abs_Axis::set_y(int value) { d()->set_state_value(&Abs_Axis_Render_State::y, value); } Qt::Orientation Abs_Axis::orientation(SRC src) { return d()->state_value(&Abs_Axis_Render_State::orientation, src); } void Abs_Axis::set_orientation(Qt::Orientation value) { d()->set_state_value(&Abs_Axis_Render_State::orientation, value); } size_t Abs_Axis::pixel_size(SRC src) { return d()->state_value(&Abs_Axis_Render_State::pixel_size, src); } void Abs_Axis::set_pixel_size(size_t value) { d()->set_state_value(&Abs_Axis_Render_State::pixel_size, value); } int Abs_Axis::tick_length(SRC src) { return d()->state_value(&Abs_Axis_Render_State::tick_length, src); } void Abs_Axis::set_tick_length(int value) { d()->set_state_value(&Abs_Axis_Render_State::tick_length, value); } int Abs_Axis::sub_tick_length(SRC src) { return d()->state_value(&Abs_Axis_Render_State::sub_tick_length, src); } void Abs_Axis::set_sub_tick_length(int value) { d()->set_state_value(&Abs_Axis_Render_State::sub_tick_length, value); } QColor Abs_Axis::color(SRC src) { return d()->state_value(&Abs_Axis_Render_State::color, src); } void Abs_Axis::set_color(QColor value) { d()->set_state_value(&Abs_Axis_Render_State::color, std::move(value)); } QChar Abs_Axis::format_char(SRC src) { return d()->state_value(&Abs_Axis_Render_State::format_char, src); } void Abs_Axis::set_format_char(QChar value) { d()->set_state_value(&Abs_Axis_Render_State::format_char, std::move(value)); } QLocale Abs_Axis::locale(SRC src) { return d()->state_value(&Abs_Axis_Render_State::locale, src); } void Abs_Axis::set_locale(QLocale value) { d()->set_state_value(&Abs_Axis_Render_State::locale, std::move(value)); } QString Abs_Axis::unit_text(SRC src) { return d()->state_value(&Abs_Axis_Render_State::unit_text, src); } void Abs_Axis::set_unit_text(QString value) { d()->set_state_value(&Abs_Axis_Render_State::unit_text, std::move(value)); } QFont Abs_Axis::unit_text_font(SRC src) { return d()->state_value(&Abs_Axis_Render_State::unit_text_font, src); } void Abs_Axis::set_unit_text_font(QFont value) { d()->set_state_value(&Abs_Axis_Render_State::unit_text_font, std::move(value)); } QPen Abs_Axis::unit_text_pen(SRC src) { return d()->state_value(&Abs_Axis_Render_State::unit_text_pen, src); } void Abs_Axis::set_unit_text_pen(QPen value) { d()->set_state_value(&Abs_Axis_Render_State::unit_text_pen, std::move(value)); } QBrush Abs_Axis::unit_text_background_brush(SRC src) { return d()->state_value(&Abs_Axis_Render_State::unit_text_background_brush, src); } void Abs_Axis::set_unit_text_background_brush(QBrush value) { d()->set_state_value(&Abs_Axis_Render_State::unit_text_background_brush, std::move(value)); } int Abs_Axis::rotate(SRC src) { return d()->state_value(&Abs_Axis_Render_State::rotate, src); } void Abs_Axis::set_rotate(int value) { d()->set_state_value(&Abs_Axis_Render_State::rotate, value); } double Abs_Axis::pixel_to_coord(double pixel, SRC src) { return d()->pixel_to_coord(pixel, src); } double Abs_Axis::coord_to_pixel(double coord, SRC src) { return d()->coord_to_pixel(coord, src); } QVector Abs_Axis_Private::create_tick_vector(double tickStep, const Range& range) { double mTickOrigin = render_state()->coord_start; QVector result; // Generate tick positions according to tickStep: // do not use qFloor here, or we'll lose 64 bit precision // qDebug() << "tickStep:" << tickStep; // auto firstStep = qint64(floor(qAbs((range.lower - mTickOrigin) / tickStep))); auto lastStep = qint64(ceil((qAbs(range.upper - mTickOrigin) / tickStep))); int tickcount = int(qAbs(lastStep - firstStep) + 1); if (tickcount < 0) tickcount = 0; if (range.lower > range.upper) tickStep = -tickStep; result.resize(tickcount); for (int i = 0; i < tickcount; ++i) { result[i] = mTickOrigin + (double)(firstStep + i) * tickStep; } // while (!result.empty() && !range.contain(result.last())) { // result.removeLast(); // } return result; } QVector Abs_Axis_Private::create_label_vector(const QVector& ticks, SRC src) { QVector result; result.reserve(ticks.size()); foreach(double tickCoord, ticks) result.append(get_tick_label(tickCoord, src)); return result; } QVector Abs_Axis_Private::create_sub_tick_vector(int subTickCount, const QVector& ticks, const Range& range) { QVector result; if (subTickCount <= 0 || ticks.size() < 2) return result; result.reserve((ticks.size() - 1) * subTickCount); for (int i = 1; i < ticks.size(); ++i) { double subTickStep = (ticks.at(i) - ticks.at(i - 1)) / double(subTickCount + 1); for (int k = 1; k <= subTickCount; ++k) result.append(ticks.at(i - 1) + k * subTickStep); } while (!result.empty() && !range.contain(result.last())) { result.removeLast(); } return result; } int Abs_Axis_Private::get_sub_tick_count(double tickStep) { int result = 1; // default to 1, if no proper value can be found // separate integer and fractional part of mantissa: double epsilon = 0.01; double intPartf; int intPart; double fracPart = modf(getMantissa(tickStep), &intPartf); intPart = int(intPartf); // handle cases with (almost) integer mantissa: if (fracPart < epsilon || 1.0 - fracPart < epsilon) { if (1.0 - fracPart < epsilon) ++intPart; switch (intPart) { case 1: result = 4; break; // 1.0 -> 0.2 substep case 2: result = 3; break; // 2.0 -> 0.5 substep case 3: result = 2; break; // 3.0 -> 1.0 substep case 4: result = 3; break; // 4.0 -> 1.0 substep case 5: result = 4; break; // 5.0 -> 1.0 substep case 6: result = 2; break; // 6.0 -> 2.0 substep case 7: result = 6; break; // 7.0 -> 1.0 substep case 8: result = 3; break; // 8.0 -> 2.0 substep case 9: result = 2; break; // 9.0 -> 3.0 substep } } else { // handle cases with significantly fractional mantissa: if (qAbs(fracPart - 0.5) < epsilon) // *.5 mantissa { switch (intPart) { case 1: result = 2; break; // 1.5 -> 0.5 substep case 2: result = 4; break; // 2.5 -> 0.5 substep case 3: result = 4; break; // 3.5 -> 0.7 substep case 4: result = 2; break; // 4.5 -> 1.5 substep case 5: result = 4; break; // 5.5 -> 1.1 substep (won't occur with default get_tick_step from here on) case 6: result = 4; break; // 6.5 -> 1.3 substep case 7: result = 2; break; // 7.5 -> 2.5 substep case 8: result = 4; break; // 8.5 -> 1.7 substep case 9: result = 4; break; // 9.5 -> 1.9 substep } } // if mantissa fraction isn't 0.0 or 0.5, don't bother finding good sub tick marks, leave default } return result; } double Abs_Axis_Private::getMantissa(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 = getMantissa(input, &magnitude); return pickClosest(mantissa, QVector() << 1.0 << 2.0 << 2.5 << 5.0 << 10.0) * magnitude; } double Abs_Axis_Private::pickClosest(double target, const QVector& candidates) { if (candidates.size() == 1) return candidates.first(); QVector::const_iterator it = std::lower_bound(candidates.constBegin(), candidates.constEnd(), target); if (it == candidates.constEnd()) return *(it - 1); else if (it == candidates.constBegin()) return *it; else return target - *(it - 1) < *it - target ? *(it - 1) : *it; } QString Abs_Axis_Private::get_tick_label(double tick, SRC src) { auto render_state = reinterpret_cast(state(src)); return render_state->locale.toString(tick, render_state->format_char.toLatin1(), render_state->number_precision); } double Abs_Axis::start_coord(SRC src) { auto render_state = d()->state_data(src); return render_state->coord_start; } double Abs_Axis::end_coord(SRC src) { auto render_state = d()->state_data(src); return render_state->coord_start + render_state->coord_length; } Range Abs_Axis::coord_range(SRC src) { auto render_state = d()->state_data(src); return {render_state->coord_start, render_state->coord_start + render_state->coord_length}; } int Abs_Axis::get_pixel_point_size(Range range, SRC src) { auto render_state = d()->state_data(src); return static_cast(qAbs(range.length() / coord_range(src).length()) * render_state->pixel_size); } int Abs_Axis::get_pixel_point_size(SRC src) { auto render_state = d()->state_data(src); return qAbs(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 tickStep) { return d()->get_sub_tick_count(tickStep); } QString Abs_Axis::get_tick_label(double tick, SRC src) { return d()->get_tick_label(tick, src); } QVector Abs_Axis::create_label_vector(const QVector& ticks, SRC src) { return d()->create_label_vector(ticks, src); } QVector Abs_Axis::create_tick_vector(double tickStep, const Range& range) { return d()->create_tick_vector(tickStep, range); } QVector Abs_Axis::create_sub_tick_vector(int subTickCount, const QVector& ticks, const Range& range) { return d()->create_sub_tick_vector(subTickCount, ticks, range); } }