226 lines
5.6 KiB
C++
226 lines
5.6 KiB
C++
#include "RasterDataProvider.h"
|
|
#include <QString>
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QRegularExpression>
|
|
|
|
#if HPPA_HAVE_GDAL
|
|
#include <gdal_priv.h>
|
|
#include <cpl_conv.h>
|
|
#endif
|
|
|
|
RasterDataProvider::RasterDataProvider(const QString& uri)
|
|
: m_uri(uri), m_dataset(nullptr)
|
|
{
|
|
}
|
|
|
|
RasterDataProvider::~RasterDataProvider()
|
|
{
|
|
close();
|
|
}
|
|
|
|
bool RasterDataProvider::open()
|
|
{
|
|
#if HPPA_HAVE_GDAL
|
|
GDALAllRegister();
|
|
m_dataset = (GDALDataset*)GDALOpen((const char*)m_uri.toLocal8Bit().constData(), GA_ReadOnly);
|
|
if (!m_dataset) {
|
|
qWarning() << "RasterDataProvider: failed to open dataset:" << m_uri;
|
|
return false;
|
|
}
|
|
return true;
|
|
#else
|
|
Q_UNUSED(m_uri);
|
|
qWarning() << "RasterDataProvider: GDAL not available, open will fail.";
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void RasterDataProvider::close()
|
|
{
|
|
#if HPPA_HAVE_GDAL
|
|
if (m_dataset) {
|
|
GDALClose((GDALDatasetH)m_dataset);
|
|
m_dataset = nullptr;
|
|
}
|
|
#else
|
|
m_dataset = nullptr;
|
|
#endif
|
|
}
|
|
|
|
int RasterDataProvider::bandCount() const
|
|
{
|
|
#if HPPA_HAVE_GDAL
|
|
if (!m_dataset) return 0;
|
|
return m_dataset->GetRasterCount();
|
|
#else
|
|
Q_UNUSED(this);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int RasterDataProvider::width() const
|
|
{
|
|
#if HPPA_HAVE_GDAL
|
|
if (!m_dataset) return 0;
|
|
return m_dataset->GetRasterXSize();
|
|
#else
|
|
Q_UNUSED(this);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int RasterDataProvider::height() const
|
|
{
|
|
#if HPPA_HAVE_GDAL
|
|
if (!m_dataset) return 0;
|
|
return m_dataset->GetRasterYSize();
|
|
#else
|
|
Q_UNUSED(this);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
bool RasterDataProvider::isValidPixel(int x, int y) const
|
|
{
|
|
const int w = width();
|
|
const int h = height();
|
|
return x >= 0 && y >= 0 && x < w && y < h;
|
|
}
|
|
|
|
std::vector<double> RasterDataProvider::parseEnviHdrWavelengths() const
|
|
{
|
|
std::vector<double> res;
|
|
|
|
QFileInfo fi(m_uri);
|
|
QString hdrPath = fi.path() + "/" + fi.completeBaseName() + ".hdr";
|
|
QFile hdr(hdrPath);
|
|
if (!hdr.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
return res;
|
|
}
|
|
|
|
QString text = QString::fromLocal8Bit(hdr.readAll());
|
|
hdr.close();
|
|
|
|
QRegularExpression rx("wavelength\\s*=\\s*\\{([^}]*)\\}", QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption);
|
|
QRegularExpressionMatch m = rx.match(text);
|
|
if (!m.hasMatch()) {
|
|
return res;
|
|
}
|
|
|
|
const QString body = m.captured(1);
|
|
const QStringList parts = body.split(',', QString::SkipEmptyParts);
|
|
res.reserve(parts.size());
|
|
for (const QString& p : parts) {
|
|
bool ok = false;
|
|
double v = p.trimmed().toDouble(&ok);
|
|
if (ok) {
|
|
res.push_back(v);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
std::vector<double> RasterDataProvider::bandWavelengths() const
|
|
{
|
|
std::vector<double> res;
|
|
#if HPPA_HAVE_GDAL
|
|
if (!m_dataset) return res;
|
|
|
|
// 1) Try ENVI dataset-level metadata first: wavelength = { ... }
|
|
const char* dsWave = m_dataset->GetMetadataItem("wavelength", "ENVI");
|
|
if (!dsWave) dsWave = m_dataset->GetMetadataItem("Wavelength", "ENVI");
|
|
if (dsWave) {
|
|
QString dsWaveStr = QString::fromLocal8Bit(dsWave);
|
|
dsWaveStr.remove('{').remove('}');
|
|
const QStringList parts = dsWaveStr.split(',', QString::SkipEmptyParts);
|
|
res.reserve(parts.size());
|
|
for (const QString& p : parts) {
|
|
bool ok = false;
|
|
double v = p.trimmed().toDouble(&ok);
|
|
if (ok) res.push_back(v);
|
|
}
|
|
if (!res.empty()) return res;
|
|
}
|
|
|
|
// 2) Try per-band metadata
|
|
for (int i = 1; i <= m_dataset->GetRasterCount(); ++i) {
|
|
GDALRasterBand* band = m_dataset->GetRasterBand(i);
|
|
if (!band) continue;
|
|
const char* val = band->GetMetadataItem("Wavelength");
|
|
if (!val) val = band->GetMetadataItem("wavelength");
|
|
if (val) {
|
|
bool ok = false;
|
|
double v = QString::fromLocal8Bit(val).trimmed().toDouble(&ok);
|
|
res.push_back(ok ? v : -1.0);
|
|
} else {
|
|
res.push_back(-1.0);
|
|
}
|
|
}
|
|
if (!res.empty()) return res;
|
|
#endif
|
|
|
|
// 3) Fallback: parse ENVI .hdr directly
|
|
return parseEnviHdrWavelengths();
|
|
}
|
|
|
|
bool RasterDataProvider::readPixelSpectrum(int x, int y, std::vector<double>& outSpectrum) const
|
|
{
|
|
#if HPPA_HAVE_GDAL
|
|
outSpectrum.clear();
|
|
if (!m_dataset) return false;
|
|
if (!isValidPixel(x, y)) return false;
|
|
|
|
const int bands = m_dataset->GetRasterCount();
|
|
if (bands <= 0) return false;
|
|
|
|
outSpectrum.resize(bands);
|
|
for (int i = 0; i < bands; ++i) {
|
|
GDALRasterBand* band = m_dataset->GetRasterBand(i + 1);
|
|
if (!band) return false;
|
|
|
|
float value = 0.0f;
|
|
CPLErr err = band->RasterIO(
|
|
GF_Read,
|
|
x, y,
|
|
1, 1,
|
|
&value,
|
|
1, 1,
|
|
GDT_Float32,
|
|
0, 0);
|
|
|
|
if (err != CE_None) return false;
|
|
outSpectrum[i] = static_cast<double>(value);
|
|
}
|
|
|
|
return true;
|
|
#else
|
|
Q_UNUSED(x);
|
|
Q_UNUSED(y);
|
|
Q_UNUSED(outSpectrum);
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool RasterDataProvider::readBandAsFloat(int bandIndex, std::vector<float>& outBuffer) const
|
|
{
|
|
#if HPPA_HAVE_GDAL
|
|
if (!m_dataset) return false;
|
|
int bands = m_dataset->GetRasterCount();
|
|
if (bandIndex < 0 || bandIndex >= bands) return false;
|
|
GDALRasterBand* band = m_dataset->GetRasterBand(bandIndex + 1);
|
|
if (!band) return false;
|
|
int w = m_dataset->GetRasterXSize();
|
|
int h = m_dataset->GetRasterYSize();
|
|
outBuffer.assign(w * h, 0.0f);
|
|
CPLErr err = band->RasterIO(GF_Read, 0, 0, w, h, outBuffer.data(), w, h, GDT_Float32, 0, 0);
|
|
return err == CE_None;
|
|
#else
|
|
Q_UNUSED(bandIndex);
|
|
Q_UNUSED(outBuffer);
|
|
return false;
|
|
#endif
|
|
}
|