Files
HPPA/HPPA/imageControl.cpp
2026-05-22 16:21:41 +08:00

350 lines
9.8 KiB
C++

#include "imageControl.h"
#include "RasterImageLayer.h"
#include <algorithm>
#include <cmath>
ImageControl::ImageControl(QWidget* parent)
: QDialog(parent)
{
ui.setupUi(this);
ui.sliderRed->setPageStep(0);
ui.sliderGreen->setPageStep(0);
ui.sliderBlue->setPageStep(0);
ui.sliderRed->setSingleStep(0);
ui.sliderGreen->setSingleStep(0);
ui.sliderBlue->setSingleStep(0);
// Spinbox valueChanged: only sync the paired slider (no render)
connect(ui.spinRed, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ImageControl::onSpinRedValueChanged);
connect(ui.spinGreen, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ImageControl::onSpinGreenValueChanged);
connect(ui.spinBlue, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ImageControl::onSpinBlueValueChanged);
// Spinbox editingFinished: commit on Enter key / focus lost (trigger render)
connect(ui.spinRed, &QDoubleSpinBox::editingFinished, this, &ImageControl::onSpinRedEditingFinished);
connect(ui.spinGreen, &QDoubleSpinBox::editingFinished, this, &ImageControl::onSpinGreenEditingFinished);
connect(ui.spinBlue, &QDoubleSpinBox::editingFinished, this, &ImageControl::onSpinBlueEditingFinished);
// Slider valueChanged: only sync the paired spinbox (no render)
// Slider now represents band index (0 .. N-1)
connect(ui.sliderRed, &QSlider::valueChanged, this, &ImageControl::onSliderRedValueChanged);
connect(ui.sliderGreen, &QSlider::valueChanged, this, &ImageControl::onSliderGreenValueChanged);
connect(ui.sliderBlue, &QSlider::valueChanged, this, &ImageControl::onSliderBlueValueChanged);
// Slider sliderReleased: commit on mouse release (trigger render)
connect(ui.sliderRed, &QSlider::sliderReleased, this, &ImageControl::onSliderRedReleased);
connect(ui.sliderGreen, &QSlider::sliderReleased, this, &ImageControl::onSliderGreenReleased);
connect(ui.sliderBlue, &QSlider::sliderReleased, this, &ImageControl::onSliderBlueReleased);
// Connect preset buttons
connect(ui.btnTrueColor, &QPushButton::clicked, this, &ImageControl::onTrueColorClicked);
connect(ui.btnColorInfrared, &QPushButton::clicked, this, &ImageControl::onColorInfraredClicked);
// Spinbox only commits on Enter, not on every keystroke
ui.spinRed->setKeyboardTracking(false);
ui.spinGreen->setKeyboardTracking(false);
ui.spinBlue->setKeyboardTracking(false);
ui.groupAdjustments->setStyleSheet(R"(
QDoubleSpinBox {
border: 1px solid #999;
border-radius: 4px;
padding: 2px 20px 2px 6px; /* 右侧留空间给按钮 */
background: #0e1c4c;
selection-background-color: #0078d7;
font-size: 12px;
color:#ACCDFF ;
}
QDoubleSpinBox::up-button {
subcontrol-origin: border;
subcontrol-position: top right;
width: 16px;
border-left: 1px solid #ccc;
}
QDoubleSpinBox::down-button {
subcontrol-origin: border;
subcontrol-position: bottom right;
width: 16px;
border-left: 1px solid #ccc;
}
QDoubleSpinBox::up-arrow {
image: url(:/svg/resources/icons/svg/arrow_up.svg);
width: 10px;
height: 10px;
}
QDoubleSpinBox::down-arrow {
image: url(:/svg/resources/icons/svg/arrow_down.svg);
width: 10px;
height: 10px;
}
QDoubleSpinBox::up-button:hover,
QDoubleSpinBox::down-button:hover {
background: #e6f2ff;
}
QDoubleSpinBox::up-button:pressed,
QDoubleSpinBox::down-button:pressed {
background: #cce4ff;
}
)");
}
ImageControl::~ImageControl()
{
}
void ImageControl::setActiveLayer(RasterImageLayer* layer)
{
m_activeLayer = layer;
if (!layer) {
setEnabled(false);
m_wavelengths.clear();
return;
}
setEnabled(true);
// Get band wavelengths from the underlying RasterLayer's header
m_wavelengths = layer->layer()->bandWavelengths();
std::sort(m_wavelengths.begin(), m_wavelengths.end());
if (m_wavelengths.empty()) {
setEnabled(false);
return;
}
m_minWave = m_wavelengths.front();
m_maxWave = m_wavelengths.back();
// Compute spinbox step as the average wavelength interval between adjacent bands
double step = 1.0;
if (m_wavelengths.size() >= 2) {
step = (m_maxWave - m_minWave) / (m_wavelengths.size() - 1);
}
blockAllSignals(true);
// Configure spinbox ranges and step
ui.spinRed->setMinimum(m_minWave);
ui.spinRed->setMaximum(m_maxWave);
ui.spinRed->setSingleStep(step);
ui.spinGreen->setMinimum(m_minWave);
ui.spinGreen->setMaximum(m_maxWave);
ui.spinGreen->setSingleStep(step);
ui.spinBlue->setMinimum(m_minWave);
ui.spinBlue->setMaximum(m_maxWave);
ui.spinBlue->setSingleStep(step);
// Slider now represents band index (0 .. N-1), step = 1
int maxIdx = static_cast<int>(m_wavelengths.size()) - 1;
ui.sliderRed->setMinimum(0);
ui.sliderRed->setMaximum(maxIdx);
ui.sliderGreen->setMinimum(0);
ui.sliderGreen->setMaximum(maxIdx);
ui.sliderBlue->setMinimum(0);
ui.sliderBlue->setMaximum(maxIdx);
// Set current values from layer's render params (multiband)
auto params = layer->multibandParams();
int rIdx = nearestBandIndex(params.rWave);
int gIdx = nearestBandIndex(params.gWave);
int bIdx = nearestBandIndex(params.bWave);
ui.spinRed->setValue(m_wavelengths[rIdx]);
ui.spinGreen->setValue(m_wavelengths[gIdx]);
ui.spinBlue->setValue(m_wavelengths[bIdx]);
ui.sliderRed->setValue(rIdx);
ui.sliderGreen->setValue(gIdx);
ui.sliderBlue->setValue(bIdx);
blockAllSignals(false);
}
RasterImageLayer* ImageControl::activeLayer() const
{
return m_activeLayer;
}
int ImageControl::nearestBandIndex(double wave) const
{
if (m_wavelengths.empty()) return 0;
int best = 0;
double bestDiff = std::abs(m_wavelengths[0] - wave);
for (int i = 1; i < static_cast<int>(m_wavelengths.size()); ++i) {
double d = std::abs(m_wavelengths[i] - wave);
if (d < bestDiff) {
bestDiff = d;
best = i;
}
}
return best;
}
void ImageControl::setControlsToBandIndex(QDoubleSpinBox* spin, QSlider* slider, int idx)
{
if (idx < 0 || idx >= static_cast<int>(m_wavelengths.size())) return;
double wv = m_wavelengths[idx];
spin->blockSignals(true);
spin->setValue(wv);
spin->blockSignals(false);
slider->blockSignals(true);
slider->setValue(idx);
slider->blockSignals(false);
}
// --- Spinbox valueChanged: snap to nearest band, sync slider, no render ---
void ImageControl::onSpinRedValueChanged(double val)
{
int idx = nearestBandIndex(val);
ui.sliderRed->blockSignals(true);
ui.sliderRed->setValue(idx);
ui.sliderRed->blockSignals(false);
}
void ImageControl::onSpinGreenValueChanged(double val)
{
int idx = nearestBandIndex(val);
ui.sliderGreen->blockSignals(true);
ui.sliderGreen->setValue(idx);
ui.sliderGreen->blockSignals(false);
}
void ImageControl::onSpinBlueValueChanged(double val)
{
int idx = nearestBandIndex(val);
ui.sliderBlue->blockSignals(true);
ui.sliderBlue->setValue(idx);
ui.sliderBlue->blockSignals(false);
}
// --- Slider valueChanged: map band index to wavelength, sync spinbox, no render ---
void ImageControl::onSliderRedValueChanged(int val)
{
if (val < 0 || val >= static_cast<int>(m_wavelengths.size())) return;
ui.spinRed->blockSignals(true);
ui.spinRed->setValue(m_wavelengths[val]);
ui.spinRed->blockSignals(false);
}
void ImageControl::onSliderGreenValueChanged(int val)
{
if (val < 0 || val >= static_cast<int>(m_wavelengths.size())) return;
ui.spinGreen->blockSignals(true);
ui.spinGreen->setValue(m_wavelengths[val]);
ui.spinGreen->blockSignals(false);
}
void ImageControl::onSliderBlueValueChanged(int val)
{
if (val < 0 || val >= static_cast<int>(m_wavelengths.size())) return;
ui.spinBlue->blockSignals(true);
ui.spinBlue->setValue(m_wavelengths[val]);
ui.spinBlue->blockSignals(false);
}
// --- Spinbox editingFinished: snap to nearest band wavelength, then commit ---
void ImageControl::onSpinRedEditingFinished()
{
int idx = nearestBandIndex(ui.spinRed->value());
setControlsToBandIndex(ui.spinRed, ui.sliderRed, idx);
emitBandChange();
}
void ImageControl::onSpinGreenEditingFinished()
{
int idx = nearestBandIndex(ui.spinGreen->value());
setControlsToBandIndex(ui.spinGreen, ui.sliderGreen, idx);
emitBandChange();
}
void ImageControl::onSpinBlueEditingFinished()
{
int idx = nearestBandIndex(ui.spinBlue->value());
setControlsToBandIndex(ui.spinBlue, ui.sliderBlue, idx);
emitBandChange();
}
// --- Slider sliderReleased: commit on mouse release ---
void ImageControl::onSliderRedReleased()
{
emitBandChange();
}
void ImageControl::onSliderGreenReleased()
{
emitBandChange();
}
void ImageControl::onSliderBlueReleased()
{
emitBandChange();
}
// --- Preset buttons ---
void ImageControl::onTrueColorClicked()
{
blockAllSignals(true);
int rIdx = nearestBandIndex(665.0);
int gIdx = nearestBandIndex(560.0);
int bIdx = nearestBandIndex(490.0);
setControlsToBandIndex(ui.spinRed, ui.sliderRed, rIdx);
setControlsToBandIndex(ui.spinGreen, ui.sliderGreen, gIdx);
setControlsToBandIndex(ui.spinBlue, ui.sliderBlue, bIdx);
blockAllSignals(false);
emitBandChange();
}
void ImageControl::onColorInfraredClicked()
{
blockAllSignals(true);
int rIdx = nearestBandIndex(800.0);
int gIdx = nearestBandIndex(665.0);
int bIdx = nearestBandIndex(560.0);
setControlsToBandIndex(ui.spinRed, ui.sliderRed, rIdx);
setControlsToBandIndex(ui.spinGreen, ui.sliderGreen, gIdx);
setControlsToBandIndex(ui.spinBlue, ui.sliderBlue, bIdx);
blockAllSignals(false);
emitBandChange();
}
void ImageControl::emitBandChange()
{
double r = ui.spinRed->value();
double g = ui.spinGreen->value();
double b = ui.spinBlue->value();
// Update active layer's stored render params (multiband)
if (m_activeLayer) {
auto params = m_activeLayer->multibandParams();
params.rWave = r;
params.gWave = g;
params.bWave = b;
m_activeLayer->setMultibandParams(params);
}
emit bandSelectionChanged(r, g, b);
}
void ImageControl::blockAllSignals(bool block)
{
ui.spinRed->blockSignals(block);
ui.spinGreen->blockSignals(block);
ui.spinBlue->blockSignals(block);
ui.sliderRed->blockSignals(block);
ui.sliderGreen->blockSignals(block);
ui.sliderBlue->blockSignals(block);
}