Files
Renderive/Core/plottable/Afterglow.cpp
T
2026-08-02 03:43:39 +08:00

180 lines
7.5 KiB
C++

#include <utility>
#include "Afterglow_p.h"
#include "../base/Frame_Memory.h"
#include "../base/Memory.h"
namespace renderive {
RENDERIVE_DEFINE_RENDERABLE_BINDING(Afterglow, Afterglow_Private, Afterglow_Render_State, Afterglow_Input_Data, "Afterglow")
std::shared_ptr<Frequency_Axis> Afterglow::frequency_axis() {
return d()->edit_state_value(&Afterglow_Render_State::frequency_axis).lock();
}
void Afterglow::set_frequency_axis(std::shared_ptr<Frequency_Axis> value) {
d()->set_state_value(&Afterglow_Render_State::frequency_axis, std::weak_ptr<Frequency_Axis>(value));
}
std::shared_ptr<Axis> Afterglow::power_axis() {
return d()->edit_state_value(&Afterglow_Render_State::power_axis).lock();
}
void Afterglow::set_power_axis(std::shared_ptr<Axis> value) {
d()->set_state_value(&Afterglow_Render_State::power_axis, std::weak_ptr<Axis>(value));
}
Range Afterglow::frequency_range() {
return d()->edit_state_value(&Afterglow_Render_State::frequency_range);
}
void Afterglow::set_frequency_range(Range value) {
if (value.length() == 0.0)
return;
d()->set_state_value(&Afterglow_Render_State::frequency_range, std::move(value));
}
Range Afterglow::power_range() {
return d()->edit_state_value(&Afterglow_Render_State::color_scale).range();
}
void Afterglow::set_power_range(Range value) {
if (value.size() == 0.0)
return;
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(d());
edit->color_scale.set_range(value);
}
int Afterglow::frequency_point_size() {
return d()->edit_state_value(&Afterglow_Render_State::frequency_bin_count);
}
int Afterglow::power_point_size() {
return d()->edit_state_value(&Afterglow_Render_State::power_bin_count);
}
bool Afterglow::interpolate() {
return d()->edit_state_value(&Afterglow_Render_State::interpolate_power_bins);
}
void Afterglow::set_interpolate(bool value) {
d()->set_state_value(&Afterglow_Render_State::interpolate_power_bins, value);
}
double Afterglow::attenuation_rate() {
return d()->edit_state_value(&Afterglow_Render_State::decay_rate);
}
void Afterglow::set_attenuation_rate(double value) {
d()->set_state_value(&Afterglow_Render_State::decay_rate, std::clamp(value, 0.0, 1.0));
}
int Afterglow::init_strong_value() {
return d()->edit_state_value(&Afterglow_Render_State::initial_intensity_threshold);
}
void Afterglow::set_init_strong_value(int value) {
d()->set_state_value(&Afterglow_Render_State::initial_intensity_threshold, std::max(1, value));
}
Color_Map Afterglow::color_map() {
return d()->edit_state_value(&Afterglow_Render_State::color_scale).color_map();
}
void Afterglow::set_color_map(Color_Map value) {
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(d());
edit->color_scale.set_color_map(std::move(value));
}
std::shared_ptr<Color_Bar> Afterglow::color_bar() const {
return const_cast<Afterglow*>(this)->d()->color_bar.lock();
}
void Afterglow::set_frequency_point_size(int t) {
Afterglow_Private* pd = d();
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(pd);
edit->frequency_bin_count = std::max(1, t);
edit->power_bin_count = std::max(1, edit->power_bin_count);
}
void Afterglow::set_power_point_size(int t) {
Afterglow_Private* pd = d();
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(pd);
edit->frequency_bin_count = std::max(1, edit->frequency_bin_count);
edit->power_bin_count = std::max(1, t);
}
Afterglow::Builder::Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Frequency_Axis> frequency_axis, std::shared_ptr<Axis> power_axis) {
init(parent, frequency_axis, power_axis);
}
std::shared_ptr<Afterglow> Afterglow::Builder::build() {
auto ret = renderive::make_shared<Afterglow>();
set(ret.get());
return ret;
}
void Afterglow::append_spectrum(std::span<const double> power_range_data) {
if (!ok())
return;
Afterglow_Private* pd = d();
int frequency_point_size{};
{
Render_State_Lease<Afterglow_Private, Afterglow_Render_State> state(pd);
frequency_point_size = state->frequency_bin_count;
}
if (power_range_data.size() != frequency_point_size)
return;
Render_Input_Lease<Afterglow_Private, Afterglow_Input_Data> input(pd);
input->pending_spectra.push(power_range_data, Afterglow_Input_Data::Max_Pending_Frame_Count);
}
void Afterglow::append_spectrum(std::pmr::vector<double>&& power_range_data) {
if (!ok())
return;
Afterglow_Private* pd = d();
int frequency_point_size{};
{
Render_State_Lease<Afterglow_Private, Afterglow_Render_State> state(pd);
frequency_point_size = state->frequency_bin_count;
}
if (power_range_data.size() != frequency_point_size)
return;
Render_Input_Lease<Afterglow_Private, Afterglow_Input_Data> input(pd);
input->pending_spectra.push(std::move(power_range_data), Afterglow_Input_Data::Max_Pending_Frame_Count);
}
void Afterglow_Private::push_data(std::span<const double> power_range_data, const Afterglow_Render_State* s, const Color_Scale_Snapshot& color_scale) {
if (power_range_data.size() != s->frequency_bin_count ||
s->initial_intensity_threshold <= 0 ||
color_scale.range.size() == 0.0 ||
s->frequency_bin_count <= 0 ||
s->power_bin_count <= 0)
return;
std::pmr::vector<int> index_list(s->frequency_bin_count, frame_memory_resource());
double rate = (double)s->power_bin_count / color_scale.range.size();
for (int i = 0; i < s->frequency_bin_count; ++i) {
int line_index = (int)((power_range_data[i] - color_scale.range.origin) * rate);
if (line_index < 0)
line_index = 0;
if (line_index > s->power_bin_count - 1)
line_index = s->power_bin_count - 1;
index_list[i] = line_index;
}
if (!s->interpolate_power_bins) {
for (int i = 0; i < s->frequency_bin_count; ++i) {
int index = index_list[i] * s->frequency_bin_count + i;
current_intensity_grid[index]++;
}
}
else {
int last_lower = -1, last_upper = -1;
for (int i = 0; i < s->frequency_bin_count; ++i) {
int y = index_list[i];
current_intensity_grid[y * s->frequency_bin_count + i]++;
if (y - last_upper >= 2) {
for (int cur_y = last_upper + 1; cur_y < y; ++cur_y) {
current_intensity_grid[cur_y * s->frequency_bin_count + i]++;
}
last_upper = y;
last_lower = last_lower + 1;
continue;
}
if (last_lower - y >= 2) {
for (int cur_y = y + 1; cur_y < last_lower; ++cur_y) {
current_intensity_grid[cur_y * s->frequency_bin_count + i]++;
}
last_upper = last_lower - 1;
last_lower = y;
continue;
}
last_upper = y;
last_lower = y;
}
}
current_history_index++;
if (current_history_index < s->initial_intensity_threshold)
return;
current_history_index = 0;
double old_remain = s->decay_rate == 1.0 ? 1.0 : 1.0 - s->decay_rate;
double cache_remain = s->decay_rate / (double)s->initial_intensity_threshold;
for (int i = 0; i < cached_cell_count; ++i) {
merged_intensity_grid[i] = old_remain * previous_intensity_grid[i] + cache_remain * current_intensity_grid[i];
current_intensity_grid[i] = 0;
}
previous_intensity_grid = merged_intensity_grid;
image_dirty = true;
}
} // namespace renderive