Files
Renderive/YSGraphic_Core/plottable/Spectrum_p.h
T
2026-07-23 12:27:06 +08:00

147 lines
6.1 KiB
C++

#pragma once
#include "../Axis/FrequentAxis.h"
#include "../RenderAble.h"
#include "../base/PerformanceShower_p.h"
#include "../base/Plot_p.h"
#include "HoverInfo.h"
#include "Spectrum.h"
#include "YSGraphic_Core/base/algorithm.hpp"
namespace YSG {
struct Marker {
Marker() = default;
Marker(double frequent, bool drawLine) : frequent(frequent), drawLine(drawLine) {
}
double frequent{};
bool drawLine = true;
bool operator==(const Marker &other) const {
return qFuzzyCompare(frequent, other.frequent) && drawLine == other.drawLine;
}
};
struct SpectrumInputData : InputData {
std::list<QVector<double>> mDataList;
void clear() override {
mDataList.clear();
}
};
struct SpectrumRenderState : RenderState, HoverInfoRenderState, Spectrum_PROP {
QVector<Marker> markerList;
int curSelectIndex = -1;
void unSelect() {
curSelectIndex = -1;
}
void selectNextMarker() {
if(markerList.empty()) return;
curSelectIndex = (curSelectIndex + 1) % markerList.size();
}
void selectPrevMarker() {
if(markerList.empty()) return;
curSelectIndex = (curSelectIndex - 1 + markerList.size()) % markerList.size();
}
void setSelectIndex(int index) {
if (index < 0 || index >= markerList.size()) {
qDebug() << "SpectrogramLineCache::setSelectIndex index out of range";
return;
}
curSelectIndex = index;
}
void setCurFrequent(double frequent) {
setFrequent(curSelectIndex, frequent);
}
void setFrequent(int index, double frequent) {
if (index < 0 || index >= markerList.size()) {
qDebug() << "SpectrogramLineCache::setSelectIndex index out of range";
return;
}
markerList[index].frequent = frequent;
}
void drawMarker(QPainter *painter, double key, double value, bool isLine = false, bool isSelected = false) {
double x = frequentAxis->coordToPixel(key, SRC::Render);
double y = powerAxis->coordToPixel(value, SRC::Render);
painter->setPen(isSelected ? selectMarkerPen : markerPen);
QString text1 = QString::number(key, 'f', 2) + frequentAxis->unitText();
QString text2 = QString::number(value, 'f', 2) + powerAxis->unitText();
QFontMetrics fm(painter->font());
int h = fm.height();
int w = qMax(fm.horizontalAdvance(text1), fm.horizontalAdvance(text2));
painter->drawText(QPointF(x - (double) w / 2, y - h * 2), text1);
painter->drawText(QPointF(x - (double) w / 2, y - h), text2);
if (!isLine) {
painter->drawEllipse(QPointF(x, y), 2, 2);
} else {
painter->drawLine(QPointF(x, powerAxis->y()), QPointF(x, powerAxis->pixelSize()));
}
}
void drawAxisRect(QPainter *painter, Range range, double middleX) const {
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(sweepRectBrush);
double pixelMin = frequentAxis->coordToPixel(range.lower, SRC::Render);
double pixelMax = frequentAxis->coordToPixel(range.upper, SRC::Render);
double pixelMiddle = frequentAxis->coordToPixel(middleX, SRC::Render);
Range r = powerAxis->coordRange();
double min = powerAxis->coordToPixel(r.lower, SRC::Render);
double max = powerAxis->coordToPixel(r.upper, SRC::Render);
painter->drawRect(QRectF(pixelMin, min, pixelMax - pixelMin, max - min));
painter->setPen(middleFrequentPen);
painter->setPen(QPen(QColor(255, 0, 0)));
painter->drawLine(QPointF(pixelMiddle, min), QPointF(pixelMiddle, max));
painter->restore();
}
};
struct SpectrumPrivate : RenderData {
D_Ptr_3(Spectrum)
Spectrum* q();
double minMarkerKey{};
double minMarkerValue{};
double maxMarkerKey{};
double maxMarkerValue{};
int cacheFrequentPointSize{};
Range cacheFrequentRange{};
QVector<double> frequents;
QVector<double> maxPowers, curPowers, minPowers;
void updateFrequentPointSize(int frequentPointSize, Range frequentRange);
void setFrequentData(const QVector<double>& lineData, const SpectrumRenderState* s);
[[nodiscard]] double getY(const double& x, bool& ok);
void drawLine(QPainter* painter, const SpectrumRenderState* s, const QVector<double>& ys, const QPen& pen, const QBrush& brush);
void drawSpectrum(QPainter* painter, SpectrumRenderState* s);
void draw(QPainter* painter) override;
void prepareData() override {
syncStatePipeline();
auto s = renderState();
if(cacheFrequentPointSize != s->frequentPointSize || cacheFrequentRange != s->frequentRange) {
updateFrequentPointSize(s->frequentPointSize, s->frequentRange);
}
auto input = renderInputData();
for(const QVector<double>& data : input->mDataList) {
setFrequentData(data, s);
}
clearRenderInput();
}
bool selectTest(const QPointF& pos) override {
auto sc = editState();
double frequent = sc->frequentAxis->pixelToCoord(pos.x(), SRC::Render);
bool ok;
double power = getY(frequent, ok);
if(!ok) return false;
return qAbs(power - sc->powerAxis->pixelToCoord(pos.y(), SRC::Render)) < 4;
}
void setHoverState(const QPoint& pos, bool active) override {
Triple_Buffer_Lease lease = mStateControl.wait_mark_use_role(State_Edit);
RenderEditGuard editGuard(this, lease);
SpectrumRenderState* sc = reinterpret_cast<SpectrumRenderState*>(stateByIndex(lease.index));
sc->hoverInfoPos = pos;
sc->hoverInfoActive = active;
}
};
}