Files
Renderive/YSGraphic_Core/plottable/WaterFall_p.h
T
2026-07-23 11:10:17 +08:00

178 lines
7.7 KiB
C++

#pragma once
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <vector>
#include "Core/Base/RingBuffer.hpp"
#include "../Axis/FrequentAxis_p.h"
#include "../Axis/TimeAxis_p.h"
#include "../RenderAble.h"
#include "../base/Global.h"
#include "../base/PerformanceShower_p.h"
#include "../base/Plot.h"
#include "../base/Plot_p.h"
#include "WaterFall.h"
namespace YSG {
struct WaterFallData {
int mTick;
QVector<double> mFrequent;
};
struct WaterFallTempData : TempData {
std::list<WaterFallData> mDataList;
};
struct WaterFallRenderState : RenderState, HoverInfoRenderState, WaterFall_Prop {
};
struct WaterFallRingBuffer {
Psc::StreamRingBuffer_ST buffer;
std::vector<std::uint8_t> recordBuffer;
std::vector<std::uint8_t> snapshotBuffer;
std::vector<double> rowBuffer;
std::size_t recordByteSize{};
std::size_t rowByteSize{};
int rowCount{};
int colCount{};
int dataCount{};
bool match(int col, int row) const {
return colCount == col && rowCount == row && recordByteSize;
}
void resize(int col, int row) {
colCount = col;
rowCount = row;
dataCount = 0;
rowByteSize = sizeof(double) * colCount;
recordByteSize = rowByteSize + sizeof(int);
recordBuffer.resize(recordByteSize);
snapshotBuffer.resize(recordByteSize * rowCount);
rowBuffer.resize(colCount);
buffer.init(recordByteSize * rowCount);
}
void pushData(const double* data, int tick) {
if(dataCount == rowCount) {
buffer.skip(recordByteSize);
--dataCount;
}
std::memcpy(recordBuffer.data(), data, rowByteSize);
std::memcpy(recordBuffer.data() + rowByteSize, &tick, sizeof(tick));
buffer.write(recordBuffer.data(), recordByteSize);
++dataCount;
}
int snapshot() {
buffer.peek_best_effort(snapshotBuffer.data(), recordByteSize * dataCount);
return dataCount;
}
const double* frequentData(int row) {
std::memcpy(rowBuffer.data(), snapshotBuffer.data() + row * recordByteSize, rowByteSize);
return rowBuffer.data();
}
int tick(int row) const {
int value;
std::memcpy(&value, snapshotBuffer.data() + row * recordByteSize + rowByteSize, sizeof(value));
return value;
}
};
struct WaterFallPrivate : RenderData {
D_Ptr(WaterFall)
WaterFallRingBuffer ringBuffer;
QImage image;
bool selectTest(const QPointF& pos) override {return true;}
void setHoverState(const QPoint& pos, bool active) override {
SpinLockGuard guard(&mBufferLock);
RenderEditGuard editGuard(this);
WaterFallRenderState* sc = editState();
sc->hoverInfoPos = pos;
sc->hoverInfoActive = active;
}
void prepareData() override {
SpinLockGuard guard(&mBufferLock);
syncStatePipeline();
WaterFallTempData* data = renderTempData();
const WaterFallRenderState* s = renderState();
int colCount = s->frequentPointSize, rowCount = s->timeAxis->timePointSize();
if(!ringBuffer.match(colCount, rowCount)) {
ringBuffer.resize(colCount, rowCount);
}
for(WaterFallData& wd : data->mDataList) {
QVector<double>& frequentData = wd.mFrequent;
if(frequentData.size() != colCount) {
qDebug() << "WaterFall 舍弃数据 colCount == " << colCount <<
" dataSize == " << frequentData.size() <<
"s FrequentRectCount==" << s->frequentPointSize <<
"sc FrequentRectCount==" << editState()->frequentPointSize;
break;
}
ringBuffer.pushData(frequentData.data(), wd.mTick);
}
data->mDataList.clear();
}
void draw(QPainter* painter) override {
WaterFallRenderState* s = renderState();
PerformanceShower *shower = q()->mPlot->d->mShower;
if(shower) {
shower->mInfoMap["FrequentRectCount"] = PerformanceLine(QString("FrequentRectCount:%1 timePointSize: %2")
.arg(s->frequentPointSize).arg(s->timeAxis->timePointSize()));
}
WaterFallTempData* data = renderTempData();
AbsAxis *hAxis = s->frequentAxis;
TimeAxis *vAxis = s->timeAxis;
Range hRange = s->frequentRange, vRange = s->timeAxis->coordRange();
TimeTicker& maker = s->timeAxis->d()->mTimeTicker;
if(!maker.mStartCoordToEndCoord){
std::swap(vRange.lower, vRange.upper);
}
int colCount = s->frequentPointSize, rowCount = s->timeAxis->timePointSize();
if(image.width() != colCount || image.height() != rowCount) {
image = QImage(colCount, rowCount, QImage::Format_ARGB32_Premultiplied);
image.fill(q()->mPlot->backgroundColor());
PerformanceShower *shower = q()->mPlot->d->mShower;
if(shower) {
shower->mInfoMap["colCount, rowCount"] = PerformanceLine(QString("colCount:%1, rowCount:%2")
.arg(colCount).arg(rowCount));
}
}
double valueStartCoord = s->powerRange.lower;
double rate = 256.0 / s->powerRange.size();
int bufferDataCount = ringBuffer.snapshot();
QVector<QRgb>& mColorMap = Global::instance()->mColorMap;
{
Cacl c("waterfull setTime:%1", q()->mPlot->d->mShower);
int startTick = (int)s->timeAxis->startCoord();
for(int row = 0; row < bufferDataCount; ++row) {
int bufferRow = bufferDataCount - row - 1;
auto list = ringBuffer.frequentData(bufferRow);
int tick = ringBuffer.tick(bufferRow);
int tickOffset = tick - startTick;
if(tickOffset < 0 || tickOffset >= rowCount) continue;
QRgb* scanLine = reinterpret_cast<QRgb*>(image.scanLine(tickOffset));
for (int col = 0; col < colCount; ++col) {
int colorOffset = int((list[col] - valueStartCoord) * rate);
if (colorOffset < 0 || colorOffset > 255) {
qDebug() << "colorOffset:" << colorOffset << " value: " << list[col] << s->frequentRange;
}
scanLine[col] = mColorMap.at(clamp(colorOffset, 0, 255));
}
}
}
double x = hAxis->coordToPixel(hRange.lower, SRC::Render);
double y = vAxis->coordToPixel(vRange.lower, SRC::Render);
double w = hAxis->coordToPixel(hRange.upper, SRC::Render) - x;
double h = vAxis->coordToPixel(vRange.upper, SRC::Render) - y;
Range &&hAxisRange = hAxis->coordRange(), &&vAxisRange = vAxis->coordRange();
double hr = ((hAxisRange.lower < hAxisRange.upper) ^ (hRange.lower < hRange.upper)) ? -1 : 1;
double vr = ((vAxisRange.lower < vAxisRange.upper) ^ (vRange.lower < vRange.upper)) ? -1 : 1;
painter->save();
painter->scale(hr, vr);
painter->drawImage(QRectF(hr * x, vr * y, hr * w, vr * h), image);
painter->restore();
if(q()->hoverOK(q())) {
q()->drawHover(painter, s->frequentAxis, s->timeAxis);
}
}
};
}