#pragma once #include #include #include #include #include #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 mFrequent; }; struct WaterFallInputData : InputData { std::list mDataList; void clear() override { mDataList.clear(); } }; struct WaterFallRenderState : RenderState, HoverInfoRenderState, WaterFall_Prop { }; struct WaterFallRingBuffer { Psc::StreamRingBuffer_ST buffer; std::vector recordBuffer; std::vector snapshotBuffer; std::vector 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 { Triple_Buffer_Lease lease = mStateControl.wait_mark_use_role(State_Edit); RenderEditGuard editGuard(this, lease); WaterFallRenderState* sc = reinterpret_cast(stateByIndex(lease.index)); sc->hoverInfoPos = pos; sc->hoverInfoActive = active; } void prepareData() override { syncStatePipeline(); WaterFallInputData* data = renderInputData(); 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& 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); } clearRenderInput(); } void draw(QPainter* painter) override { WaterFallRenderState* s = renderState(); PerformanceShower *shower = q()->mPlot->d->mShower; if(shower) { shower->setPerformanceLine("FrequentRectCount", PerformanceLine(QString("FrequentRectCount:%1 timePointSize: %2").arg(s->frequentPointSize).arg(s->timeAxis->timePointSize()))); } 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->setPerformanceLine("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& mColorMap = Global::instance()->mColorMap; { Cacl c("waterfull setTime:%1 SRTT:%2 RTTVAR:%3", 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(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); } } }; }