26constexpr double kPi = 3.1415926535897932384626433832795;
32int toByte(
double v)
noexcept
34 v = std::max(0.0, std::min(1.0, v));
35 return static_cast<int>(std::lround(v * 255.0));
43double applyGamma(
double normalizedValue,
double gamma)
noexcept
45 return std::pow(std::max(0.0, std::min(1.0, normalizedValue)), gamma);
54QRgb
signedColor(
double value,
double peakAbs,
double gamma)
noexcept
56 if (!(peakAbs > 0.0)) {
60 const double magnitude =
applyGamma(std::abs(value) / peakAbs, gamma);
61 const int c = toByte(magnitude);
80 double gamma)
noexcept
82 const double re =
static_cast<double>(v.real());
83 const double im =
static_cast<double>(v.imag());
84 const double amplitude = std::hypot(re, im);
86 if (!(peakAmplitude > 0.0) || !(amplitude > 0.0)) {
92 double hue = (std::atan2(im, re) + kPi) / (2.0 * kPi);
94 hue -= std::floor(hue);
96 const double value =
applyGamma(amplitude / peakAmplitude, gamma);
97 return QColor::fromHsvF(hue, 1.0, value).rgb();
106 if (!(options.
gamma > 0.0f) || !std::isfinite(
static_cast<double>(options.
gamma))) {
107 throw std::invalid_argument(
"WaveFunctionImageRenderer: gamma must be finite and positive");
116 for (std::size_t i = 0; i < field.size(); ++i) {
117 const auto &v = field.data()[i];
118 peak = std::max(peak,
119 std::hypot(
static_cast<double>(v.real()),
120 static_cast<double>(v.imag())));
128 for (std::size_t i = 0; i < field.size(); ++i) {
129 peak = std::max(peak, std::abs(
static_cast<double>(field.data()[i].real())));
137 for (std::size_t i = 0; i < field.size(); ++i) {
138 peak = std::max(peak, std::abs(
static_cast<double>(field.data()[i].imag())));
151 validateOptions(options);
163 const double gamma =
static_cast<double>(options.
gamma);
165 QImage image(
static_cast<int>(field.
width()),
166 static_cast<int>(field.
height()),
167 QImage::Format_RGB32);
169 for (std::size_t y = 0; y < field.
height(); ++y) {
170 const int imageY =
static_cast<int>(field.
height() - 1u - y);
171 QRgb *scanLine =
reinterpret_cast<QRgb *
>(image.scanLine(imageY));
173 for (std::size_t x = 0; x < field.
width(); ++x) {
174 const auto &v = field(x, y);
178 scanLine[x] = phaseColor(v, peakAmp, gamma);
181 scanLine[x] = signedColor(
static_cast<double>(v.real()), peakReal, gamma);
184 scanLine[x] = signedColor(
static_cast<double>(v.imag()), peakImag, gamma);
188 scanLine[x] = qRgb(0, 0, 0);
Owning Cartesian grid of complex scalar samples.
bool empty() const noexcept
Returns whether the field contains no samples.
std::size_t height() const noexcept
Returns the number of samples along Y.
std::complex< float > Value
std::size_t width() const noexcept
Returns the number of samples along X.
static QImage render(const ComplexField2D &field, const ProbabilityRenderOptions &options={})
Renders the component state.
static double peakAbsReal(const ComplexField2D &field) noexcept
Carries out peak abs real.
static double peakAbsImaginary(const ComplexField2D &field) noexcept
Carries out peak abs imaginary.
static double peakAmplitude(const ComplexField2D &field) noexcept
Carries out peak amplitude.
static QImage render(const ComplexField2D &field, WaveFunctionView view, const WaveFunctionRenderOptions &options={})
Renders the component state.
Declares the complex scalar field container representing two-dimensional wave functions.
double applyGamma(double normalizedValue, double gamma) noexcept
Applies gamma.
QRgb phaseColor(const ComplexField2D::Value &v, double peakAmplitude, double gamma) noexcept
Performs phase color.
QRgb signedColor(double value, double peakAbs, double gamma) noexcept
Performs signed color.
void validateOptions(const WaveFunctionRenderOptions &options)
Validates options.
WaveFunctionView
Enumerates the supported Wave Function View values.
Declares the probabilityimagerenderer visualization component used by QPE.
Configuration values for Probability Render Options.
Configuration values for Wave Function Render Options.
Declares the wavefunctionimagerenderer visualization component used by QPE.