140 lines
6.3 KiB
C++
140 lines
6.3 KiB
C++
#pragma once
|
|
#include <algorithm>
|
|
#include <limits>
|
|
#include "../Axis/Frequent_Axis.h"
|
|
#include "../Axis/Frequent_Axis_p.h"
|
|
#include "../architecture/Bounded_Input_Buffer.h"
|
|
#include "../architecture/Plot_p.h"
|
|
#include "../base/Global.h"
|
|
#include "Afterglow.h"
|
|
#include "Performance_Shower_p.h"
|
|
namespace YSG {
|
|
struct Afterglow_Render_State : Render_State, Afterglow_Prop {};
|
|
struct Afterglow_Input_Data : Input_Data {
|
|
Bounded_Vector_Double_Input_Buffer mDataList;
|
|
void clear() override {
|
|
mDataList.clear();
|
|
}
|
|
std::uint64_t pending_count() const override {
|
|
return mDataList.pending_count();
|
|
}
|
|
std::uint64_t dropped_count() const override {
|
|
return mDataList.dropped_count();
|
|
}
|
|
std::uint64_t pushed_count() const override {
|
|
return mDataList.pushed_count();
|
|
}
|
|
};
|
|
struct Afterglow_Private : Typed_Render_Data<Afterglow, Afterglow_Render_State, Afterglow_Input_Data> {
|
|
friend class Afterglow;
|
|
QImage image;
|
|
bool cacheImageDirty = false;
|
|
int curIndex = 0;
|
|
int cacheFrequentPointSize{};
|
|
int cachePowerPointSize{};
|
|
int cacheBufferSize{};
|
|
QVector<double> cachedPowerData;
|
|
QVector<double> oldCachePowerData;
|
|
QVector<double> mergedPowerData;
|
|
[[nodiscard]] int strength_value(const Afterglow_Render_State* s) const {
|
|
if (s->attenuation_rate == 1.0)
|
|
return std::numeric_limits<int>::max();
|
|
return (int)((double)s->init_strong_value / (1.0 - s->attenuation_rate));
|
|
}
|
|
void update_cache_size(int frequent_point_size, int power_point_size) {
|
|
cacheFrequentPointSize = frequent_point_size;
|
|
cachePowerPointSize = power_point_size;
|
|
cacheBufferSize = frequent_point_size * power_point_size;
|
|
cachedPowerData.resize(cacheBufferSize);
|
|
cachedPowerData.fill(0);
|
|
oldCachePowerData.resize(cacheBufferSize);
|
|
oldCachePowerData.fill(0);
|
|
mergedPowerData.resize(cacheBufferSize);
|
|
mergedPowerData.fill(0);
|
|
curIndex = 0;
|
|
}
|
|
void push_data(const QVector<double>& powerRangeData, const Afterglow_Render_State* s);
|
|
void draw(QPainter* painter) override {
|
|
Afterglow_Render_State* s = render_state();
|
|
Performance_Shower* shower = q()->mPlot->d->mShower;
|
|
if (shower) {
|
|
shower->set_performance_line("colCount, rowCount", Performance_Line(QString("colCount:%1, rowCount:%2").arg(s->frequent_point_size).arg(s->power_point_size)));
|
|
}
|
|
Abs_Axis *hAxis = s->frequent_axis, *vAxis = s->power_axis, *value_axis = s->power_axis;
|
|
Range &hRange = s->frequent_range, &vRange = s->power_range;
|
|
int colCount = s->frequent_point_size, rowCount = s->power_point_size;
|
|
if (image.width() != colCount || image.height() != rowCount) {
|
|
image = QImage(colCount, rowCount, QImage::Format_ARGB32_Premultiplied);
|
|
image.fill(0);
|
|
}
|
|
{
|
|
if (cacheImageDirty) {
|
|
QVector<QRgb>& mColorMap = Global::instance()->mColorMap;
|
|
Cacl c("Afterglow setTime:%1 SRTT:%2 RTTVAR:%3", q()->mPlot->d->mShower);
|
|
for (int row = 0; row < rowCount; ++row) {
|
|
QRgb* scanLine = reinterpret_cast<QRgb*>(image.scanLine(row));
|
|
double* list = oldCachePowerData.data() + row * colCount;
|
|
for (int col = 0; col < colCount; ++col) {
|
|
int colorOffset = (int)(list[col] * 255);
|
|
if (colorOffset < 0 || colorOffset > 255) {
|
|
qDebug() << "colorOffset:" << colorOffset << " value: " << list[col]
|
|
<< " start_coord:" << value_axis->start_coord() << " end_coord:" << value_axis->end_coord();
|
|
}
|
|
scanLine[col] = mColorMap.at(std::clamp(colorOffset, 0, 255));
|
|
}
|
|
// std::cout << std::endl;
|
|
}
|
|
cacheImageDirty = false;
|
|
}
|
|
}
|
|
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();
|
|
}
|
|
void prepare_data() override {
|
|
sync_state_pipeline();
|
|
Afterglow_Render_State* s = render_state();
|
|
if (cacheFrequentPointSize != s->frequent_point_size || cachePowerPointSize != s->power_point_size) {
|
|
update_cache_size(s->frequent_point_size, s->power_point_size);
|
|
}
|
|
Afterglow_Input_Data* input = render_input_data();
|
|
input->mDataList.read_all([this, s](const QVector<double>& data) {
|
|
push_data(data, s);
|
|
});
|
|
clear_render_input();
|
|
}
|
|
};
|
|
template <typename That>
|
|
void Afterglow::BuilderT<That>::init(Frequent_Axis* frequent_axis, Axis* power_axis) {
|
|
ASSERT(frequent_axis->mPlot != nullptr, "Afterglow build error! frequent_axis->mPlot == nullptr");
|
|
ASSERT(frequent_axis->mPlot == power_axis->mPlot, "Afterglow build error! frequent_axis->mPlot != power_axis->mPlot");
|
|
plot = frequent_axis->mPlot;
|
|
static_cast<That*>(this)->frequent_axis = frequent_axis;
|
|
static_cast<That*>(this)->power_axis = power_axis;
|
|
}
|
|
template <typename That>
|
|
void Afterglow::BuilderT<That>::set(Afterglow* ret) {
|
|
ret->init(plot, layerName);
|
|
Afterglow_Private* pd = ret->d();
|
|
Afterglow_Render_State* sc = reinterpret_cast<Afterglow_Render_State*>(pd->state(State_Edit));
|
|
PROP_RT(FrequentAxis*, frequent_axis)
|
|
PROP_RT(Axis*, power_axis)
|
|
PROP_RT(Range, frequent_range)
|
|
PROP_RT(Range, power_range)
|
|
PROP_RT(int, frequent_point_size)
|
|
PROP_RT(int, power_point_size)
|
|
PROP_RT(int, buffer_size)
|
|
PROP_RT(bool, interpolate)
|
|
PROP_RT(double, attenuation_rate)
|
|
PROP_RT(int, init_strong_value)
|
|
}
|
|
} // namespace YSG
|