171 lines
7.2 KiB
C++
171 lines
7.2 KiB
C++
#pragma once
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include "Core/Base/RingBuffer.hpp"
|
|
#include "../Axis/Frequent_Axis_p.h"
|
|
#include "../Axis/Time_Axis_p.h"
|
|
#include "../Renderable.h"
|
|
#include "../base/Global.h"
|
|
#include "../base/Performance_Shower_p.h"
|
|
#include "../base/Plot.h"
|
|
#include "../base/Plot_p.h"
|
|
#include "Waterfall.h"
|
|
namespace YSG {
|
|
struct WaterFallData {
|
|
int mTick;
|
|
QVector<double> mFrequent;
|
|
};
|
|
struct Waterfall_Input_Data : Input_Data {
|
|
std::list<WaterFallData> mDataList;
|
|
void clear() override {
|
|
mDataList.clear();
|
|
}
|
|
};
|
|
struct Waterfall_Render_State : Render_State, Hover_Info_Render_State, 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 push_data(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* frequent_data(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 Waterfall_Private : Typed_Render_Data<Waterfall, Waterfall_Render_State, Waterfall_Input_Data> {
|
|
friend class Waterfall;
|
|
WaterFallRingBuffer ringBuffer;
|
|
QImage image;
|
|
bool select_test(const QPointF& pos) override {
|
|
return true;
|
|
}
|
|
void set_hover_state(const QPoint& pos, bool active) override {
|
|
Render_Edit_Lease<Waterfall_Private, Waterfall_Render_State> edit(this);
|
|
edit->hover_info_pos = pos;
|
|
edit->hover_info_active = active;
|
|
}
|
|
void prepare_data() override {
|
|
sync_state_pipeline();
|
|
Waterfall_Input_Data* data = render_input_data();
|
|
const Waterfall_Render_State* s = render_state();
|
|
int colCount = s->frequent_point_size, rowCount = s->time_axis->time_point_size();
|
|
if (!ringBuffer.match(colCount, rowCount)) {
|
|
ringBuffer.resize(colCount, rowCount);
|
|
}
|
|
for (WaterFallData& wd : data->mDataList) {
|
|
QVector<double>& frequent_data = wd.mFrequent;
|
|
if (frequent_data.size() != colCount) {
|
|
qDebug() << "WaterFall 舍弃数据 colCount == " << colCount <<
|
|
" dataSize == " << frequent_data.size() <<
|
|
"s FrequentRectCount==" << s->frequent_point_size <<
|
|
"sc FrequentRectCount==" << edit_state()->frequent_point_size;
|
|
break;
|
|
}
|
|
ringBuffer.push_data(frequent_data.data(), wd.mTick);
|
|
}
|
|
clear_render_input();
|
|
}
|
|
void draw(QPainter* painter) override {
|
|
Waterfall_Render_State* s = render_state();
|
|
Performance_Shower* shower = q()->mPlot->d->mShower;
|
|
if (shower) {
|
|
shower->set_performance_line("FrequentRectCount", Performance_Line(QString("FrequentRectCount:%1 time_point_size: %2").arg(s->frequent_point_size).arg(s->time_axis->time_point_size())));
|
|
}
|
|
Abs_Axis* hAxis = s->frequent_axis;
|
|
Time_Axis* vAxis = s->time_axis;
|
|
Range hRange = s->frequent_range, vRange = s->time_axis->coord_range();
|
|
Time_Ticker& maker = s->time_axis->d()->mTimeTicker;
|
|
if (!maker.mStartCoordToEndCoord) {
|
|
std::swap(vRange.lower, vRange.upper);
|
|
}
|
|
int colCount = s->frequent_point_size, rowCount = s->time_axis->time_point_size();
|
|
if (image.width() != colCount || image.height() != rowCount) {
|
|
image = QImage(colCount, rowCount, QImage::Format_ARGB32_Premultiplied);
|
|
image.fill(q()->mPlot->background_color());
|
|
Performance_Shower* shower = q()->mPlot->d->mShower;
|
|
if (shower) {
|
|
shower->set_performance_line("colCount, rowCount", Performance_Line(QString("colCount:%1, rowCount:%2").arg(colCount).arg(rowCount)));
|
|
}
|
|
}
|
|
double valueStartCoord = s->power_range.lower;
|
|
double rate = 256.0 / s->power_range.size();
|
|
int bufferDataCount = ringBuffer.snapshot();
|
|
QVector<QRgb>& mColorMap = Global::instance()->mColorMap;
|
|
{
|
|
Cacl c("waterfull setTime:%1 SRTT:%2 RTTVAR:%3", q()->mPlot->d->mShower);
|
|
int startTick = (int)s->time_axis->start_coord();
|
|
for (int row = 0; row < bufferDataCount; ++row) {
|
|
int bufferRow = bufferDataCount - row - 1;
|
|
auto list = ringBuffer.frequent_data(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->frequent_range;
|
|
}
|
|
scanLine[col] = mColorMap.at(clamp(colorOffset, 0, 255));
|
|
}
|
|
}
|
|
}
|
|
double x = hAxis->coord_to_pixel(hRange.lower, SRC::Render);
|
|
double y = vAxis->coord_to_pixel(vRange.lower, SRC::Render);
|
|
double w = hAxis->coord_to_pixel(hRange.upper, SRC::Render) - x;
|
|
double h = vAxis->coord_to_pixel(vRange.upper, SRC::Render) - y;
|
|
Range &&hAxisRange = hAxis->coord_range(), &&vAxisRange = vAxis->coord_range();
|
|
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()->hover_ok(q())) {
|
|
q()->draw_hover(painter, s->frequent_axis, s->time_axis);
|
|
}
|
|
}
|
|
};
|
|
}
|