Files
Renderive/YSGraphic_Core/Axis/AbsAxis_p.h
T

156 lines
6.8 KiB
C++

#pragma once
#include "AbsAxis.h"
namespace YSG {
struct AbsAxisRenderState : RenderState, AbsAxis_Prop {
size_t pixelSize{};
int numberPrecision = 2;
double coordStart = 0;
double coordLength = 20;
void scaleRange(double factor, double center) {
coordStart = (coordStart - center) * factor + center;
coordLength *= factor;
}
};
struct AbsAxisTempData : TempData {};
struct AbsAxisPrivate : RenderData {
D_Ptr(AbsAxis)
int mTickCount = 2;
std::atomic<int> pixelStart{};
double getMantissa(double input, double *magnitude=nullptr);
[[nodiscard]] double cleanMantissa(double input);
[[nodiscard]] double pickClosest(double target, const QVector<double> &candidates);
void prepareData() override {
SpinLockGuard guard(&mBufferLock);
loadCache();
}
void draw(QPainter* painter) override {
AbsAxisRenderState* s = renderState();
pixelStart = s->orientation == Qt::Horizontal ? s->x : s->y;
Range range = {s->coordStart, s->coordStart + s->coordLength};
AbsAxis* q = this->q();
double tickStep = q->getTickStep(range);
QVector<double> ticks = q->createTickVector(tickStep, range);
int subTickCount = q->getSubTickCount(tickStep);
QVector<double> subTicks = q->createSubTickVector(subTickCount, ticks, range);
QVector<QString> labels = q->createLabelVector(ticks, SRC::Render);
while (!ticks.empty() && !range.contain(ticks.last())) {
ticks.removeLast();
}
while (!subTicks.empty() && !range.contain(subTicks.last())) {
subTicks.removeLast();
}
QFontMetrics fm(painter->font());
int h = fm.height();
painter->setPen(s->color);
if(s->orientation == Qt::Horizontal) {
painter->drawLine(s->x, s->y, s->x + s->pixelSize, s->y);
int n = ticks.size();
for(int i = 0; i < n; ++i) {
double tick = ticks[i];
double x = q->coordToPixel(tick, SRC::Render);
painter->drawLine((int)x, s->y, (int)x, s->y + s->tickLength);
const QString& label = labels[i];
QPoint start((int)x, s->y + s->tickLength);
painter->translate(start);
painter->rotate(s->rotate);
painter->drawText(0, 0, label);
painter->resetTransform();
}
for(double tick : subTicks) {
double x = q->coordToPixel(tick, SRC::Render);
painter->drawLine((int)x, s->y, (int)x, s->y + s->subTickLength);
}
} else if(s->orientation == Qt::Vertical) {
painter->drawLine(s->x, s->y, s->x, s->y + s->pixelSize);
int n = ticks.size();
for(int i = 0; i < n; ++i) {
double tick = ticks[i];
double y = q->coordToPixel(tick, SRC::Render);
const QString& label = labels[i];
painter->drawLine(s->x, (int)y, s->x + s->tickLength, (int)y);
QPoint start = QPoint(s->x + s->tickLength * 2, (int)y + h/2);
painter->translate(start);
painter->rotate(s->rotate);
painter->drawText(0, 0, label);
painter->resetTransform();
}
for(double tick : subTicks) {
double y = q->coordToPixel(tick, SRC::Render);
painter->drawLine(s->x, (int)y, s->x + s->subTickLength, (int)y);
}
} else {
qDebug() << "error s->mOrientation == " << s->orientation;
}
if(s->unitText.isEmpty()) return;
double w = fm.horizontalAdvance(s->unitText);
if(s->orientation == Qt::Horizontal) {
double x = pixelStart + s->pixelSize - w;
double y = s->y - h;
QRectF area(x, y, w, h);
painter->fillRect(area, s->unitTextBackgroundBrush);
painter->setPen(s->unitTextPen);
painter->setFont(s->unitTextFont);
painter->drawText(area, Qt::AlignCenter, s->unitText);
} else if (s->orientation == Qt::Vertical) {
double x = s->x;
double y = pixelStart;
QRectF area(x, y, w, h);
painter->fillRect(area, s->unitTextBackgroundBrush);
painter->setPen(s->unitTextPen);
painter->setFont(s->unitTextFont);
painter->drawText(area, Qt::AlignCenter, s->unitText);
}
}
protected:
[[nodiscard]] virtual double pixelToCoord(double pixel, SRC src) {
auto s = static_cast<AbsAxisRenderState*>(getState(src));
return s->coordStart + s->coordLength * (pixel - (double)pixelStart)/(double)s->pixelSize;
}
[[nodiscard]] virtual double coordToPixel(double coord, SRC src) {
auto s = static_cast<AbsAxisRenderState*>(getState(src));
return pixelStart + (double)s->pixelSize * (coord - s->coordStart)/s->coordLength;
}
virtual double getTickStep(const Range &range){
double exactStep = range.size()/double(mTickCount+1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers
return cleanMantissa(exactStep);
}
virtual int getSubTickCount(double tickStep);
virtual QVector<double> createTickVector(double tickStep, const Range &range);
virtual QVector<double> createSubTickVector(int subTickCount, const QVector<double> &ticks, const Range& range);
virtual QString getTickLabel(double tick, SRC);
virtual QVector<QString> createLabelVector(const QVector<double> &ticks, SRC);
};
template <typename That>
void AbsAxis::BuilderT<That>::set(AbsAxis* ret) {
ret->init(plot, layerName);
AbsAxisPrivate* pd = ret->d();
AbsAxisRenderState* sc = pd->renderStateCache();
sc->x = this->x;
sc->y = this->y;
sc->orientation = this->orientation;
sc->pixelSize = this->pixelSize;
sc->tickLength = this->tickLength;
sc->subTickLength = this->subTickLength;
sc->color = this->color;
sc->formatChar = this->formatChar;
sc->locale = this->locale;
sc->unitText = this->unitText;
sc->unitTextFont = this->unitTextFont;
sc->unitTextPen = this->unitTextPen;
sc->unitTextBackgroundBrush = this->unitTextBackgroundBrush;
sc->rotate = this->rotate;
}
}