178 lines
7.7 KiB
C++
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);
|
|
}
|
|
}
|
|
};
|
|
}
|