ultimatepp/bazaar/plugin/gdal/gdal.cpp
cxl 5c86036124 .reorganizing
git-svn-id: svn://ultimatepp.org/upp/trunk@9759 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-05-01 20:21:16 +00:00

445 lines
11 KiB
C++

#include "gdal.h"
#define uint8 tif_uint8
#define uint16 tif_uint16
#define int16 tif_int16
#define int32 tif_int32
#define uint32 tif_uint32
#include <gdal/gcore/gdal_priv.h>
#include <gdal/port/cpl_conv.h>
#undef uint8
#undef uint16
#undef int16
#undef int32
#undef uint32
/*
GDALDriver *CreateGTIFFDriver();
extern "C" TIFF* XTIFFOpen(const char* name, const char* mode)
{
return TIFFFileStreamOpen(name, mode);
}
GLOBAL_VARP(One<GDALDriver>, GTIFFDriver, = CreateGTIFFDriver());
EXITBLOCK {
VSICleanupFileManager();
}
*/
Gdal::Block::Block(Size size_, GDALDataType type_, byte pixel_bytes_)
: size(size_)
, type(type_)
, pixel_bytes(pixel_bytes_)
{
bytes.Alloc(pixel_bytes * size.cx * size.cy);
}
#define CONVERT_LOOP(type, src_convert) \
{ \
const type *src = (const type *)raw_src; \
const type *end = src + count; \
for(; src < end; src++, out++) \
*out = (src_convert); \
break; \
}
void Gdal::Block::GetInt(int *out, int x, int y, int count) const
{
ASSERT(x >= 0 && x + count <= size.cx);
ASSERT(y >= 0 && y < size.cy);
int offset = (x + y * size.cx) * pixel_bytes;
const byte *raw_src = &bytes[offset];
switch(type) {
case GDT_Byte: CONVERT_LOOP(byte, *src);
case GDT_UInt16: CONVERT_LOOP(uint16, *src);
case GDT_Int16: CONVERT_LOOP(int16, *src);
case GDT_UInt32: CONVERT_LOOP(uint32, (int)*src);
case GDT_Int32: CONVERT_LOOP(int32, (int)*src);
case GDT_Float32: CONVERT_LOOP(float, fround((double)*src));
case GDT_Float64: CONVERT_LOOP(double, fround(*src));
case GDT_CInt16: CONVERT_LOOP(Point16, src->x);
case GDT_CInt32: CONVERT_LOOP(Point, src->x);
case GDT_CFloat32: CONVERT_LOOP(Point_<float>, fround((double)src->x));
case GDT_CFloat64: CONVERT_LOOP(Pointf, fround(src->x));
default: {
Fill(out, out + count, (int)Null);
RLOG("unsupported GDAL data type: " << (int)type);
NEVER();
break;
}
}
}
void Gdal::Block::GetDouble(double *out, int x, int y, int count) const
{
ASSERT(x >= 0 && x + count <= size.cx);
ASSERT(y >= 0 && y < size.cy);
int offset = (x + y * size.cx) * pixel_bytes;
const byte *raw_src = &bytes[offset];
switch(type) {
case GDT_Byte: CONVERT_LOOP(byte, *src);
case GDT_UInt16: CONVERT_LOOP(uint16, *src);
case GDT_Int16: CONVERT_LOOP(int16, *src);
case GDT_UInt32: CONVERT_LOOP(uint32, (int)*src);
case GDT_Int32: CONVERT_LOOP(int32, (int)*src);
case GDT_Float32: CONVERT_LOOP(float, (double)*src);
case GDT_Float64: CONVERT_LOOP(double, *src);
case GDT_CInt16: CONVERT_LOOP(Point16, src->x);
case GDT_CInt32: CONVERT_LOOP(Point, src->x);
case GDT_CFloat32: CONVERT_LOOP(Point_<float>, (double)src->x);
case GDT_CFloat64: CONVERT_LOOP(Pointf, src->x);
default: {
Fill(out, out + count, (double)Null);
RLOG("unsupported GDAL data type: " << (int)type);
NEVER();
break;
}
}
}
Gdal::Band::Band(Gdal& owner_, GDALRasterBand *band_)
: owner(owner_), band(band_)
{
size.cx = band->GetXSize();
size.cy = band->GetYSize();
band->GetBlockSize(&block_size.cx, &block_size.cy);
block_count = idivceil(size, block_size);
type = band->GetRasterDataType();
pixel_bytes = (GDALGetDataTypeSize(type) + 7) >> 3;
complex = GDALDataTypeIsComplex(type);
int nodata_flag;
nodata_value = band->GetNoDataValue(&nodata_flag);
is_nodata = !!nodata_flag;
is_stat = false;
nodata_int = fround(nodata_value);
blocks.Alloc(block_count.cx * block_count.cy);
}
double Gdal::Band::GetMinimum() const
{
int success;
double min = band->GetMinimum(&success);
if(success)
return min;
CalcStatistics();
return stat_min;
}
double Gdal::Band::GetMaximum() const
{
int success;
double max = band->GetMaximum(&success);
if(success)
return max;
CalcStatistics();
return stat_max;
}
void Gdal::Band::GetInt(int *out, int x, int y, int count) const
{
int y_in_block = y % block_size.cy;
int block_y = y / block_size.cy;
int block_offset = block_y * block_count.cx;
int block_x_min = x / block_size.cx;
int block_x_max = (x + count - 1) / block_size.cx;
int x_in_block = x - block_size.cx * block_x_min;
for(int block_x = block_x_min; block_x <= block_x_max; block_x++) {
int fill_count = min(count, block_size.cx - x_in_block);
int block_index = block_x + block_offset;
if(!blocks[block_index])
LoadBlock(x, block_y);
if(blocks[block_index]) {
blocks[block_index]->GetInt(out, x_in_block, y_in_block, fill_count);
if(is_nodata) {
for(int *p = out, *e = out + fill_count; p < e; p++)
if(*p == nodata_int)
*p = Null;
}
}
else
Fill(out, out + fill_count, (int)Null);
x_in_block = 0;
count -= fill_count;
x += fill_count;
}
}
void Gdal::Band::GetDouble(double *out, int x, int y, int count) const
{
int y_in_block = y % block_size.cy;
int block_y = y / block_size.cy;
int block_offset = block_y * block_count.cx;
int block_x_min = x / block_size.cx;
int block_x_max = (x + count - 1) / block_size.cx;
int x_in_block = x - block_size.cx * block_x_min;
for(int block_x = block_x_min; block_x <= block_x_max; block_x++) {
int fill_count = min(count, block_size.cx - x_in_block);
int block_index = block_x + block_offset;
if(!blocks[block_index])
LoadBlock(block_x, block_y);
if(blocks[block_index]) {
blocks[block_index]->GetDouble(out, x_in_block, y_in_block, fill_count);
if(is_nodata) {
for(double *p = out, *e = out + fill_count; p < e; p++)
if(*p == nodata_value)
*p = Null;
}
}
else
Fill(out, out + fill_count, (double)Null);
x_in_block = 0;
count -= fill_count;
out += fill_count;
}
}
int Gdal::Band::GetInt(int x, int y) const
{
int out;
GetInt(&out, x, y, 1);
return out;
}
double Gdal::Band::GetDouble(int x, int y) const
{
double out;
GetDouble(&out, x, y, 1);
return out;
}
double Gdal::Band::GetIntAt(Pointf pt) const
{
Pointf src = pt * owner.GetInverseTransform();
int x = ffloor(src.x);
int y = ffloor(src.y);
if(x < 0 || x >= size.cx || y < 0 || y >= size.cy)
return Null;
return GetInt(x, y);
}
double Gdal::Band::GetDoubleAt(Pointf pt) const
{
Pointf src = pt * owner.GetInverseTransform();
int x = ffloor(src.x);
int y = ffloor(src.y);
if(x < 0 || x >= size.cx || y < 0 || y >= size.cy)
return Null;
return GetDouble(x, y);
}
void Gdal::Band::LoadBlock(int column, int row) const
{
ASSERT(column >= 0 && column < block_count.cx);
ASSERT(row >= 0 && row < block_count.cy);
int block_index = column + row * block_count.cx;
if(blocks[block_index])
return;
Point block_offset(block_size.cx * column, block_size.cy * row);
One<Block> new_block = new Block(block_size, type, pixel_bytes);
band->ReadBlock(column, row, new_block->bytes);
blocks[block_index] = pick(new_block);
}
void Gdal::Band::CalcStatistics() const
{
if(is_stat)
return;
is_stat = true;
stat_min = stat_max = Null;
bool done_stat = false;
Buffer<double> row(block_size.cx);
for(int by = 0; by < block_count.cy; by++)
for(int bx = 0; bx < block_count.cx; bx++) {
LoadBlock(bx, by);
Size valid_size = min(block_size, size - Size(bx, by) * block_size);
const One<Block>& block = blocks[bx + by * block_count.cx];
if(block)
for(int r = 0; r < valid_size.cy; r++) {
block->GetDouble(row, 0, r, valid_size.cx);
for(const double *p = row, *e = p + valid_size.cx; p < e; p++)
if(!done_stat) {
stat_min = stat_max = *p;
done_stat = true;
}
else {
if(*p < stat_min) stat_min = *p;
if(*p > stat_max) stat_max = *p;
}
}
}
}
Gdal::Gdal()
{
dataset = NULL;
}
Gdal::~Gdal()
{
Close();
}
bool Gdal::Open(const char *fn)
{
ONCELOCK {
MemoryIgnoreLeaksBegin();
// GDALRegister_GDB();
GDALRegister_GTiff();
GDALRegister_GXF();
// GDALRegister_OGDI();
GDALRegister_HFA();
GDALRegister_AAIGrid();
GDALRegister_AIGrid();
// GDALRegister_AIGrid2();
GDALRegister_CEOS();
GDALRegister_SAR_CEOS();
// GDALRegister_SDTS();
GDALRegister_ELAS();
GDALRegister_EHdr();
GDALRegister_GenBin();
GDALRegister_PAux();
GDALRegister_ENVI();
GDALRegister_DOQ1();
GDALRegister_DOQ2();
GDALRegister_DTED();
GDALRegister_MFF();
GDALRegister_HKV();
// GDALRegister_PNG();
GDALRegister_JPEG();
// GDALRegister_JPEG2000();
// GDALRegister_JP2KAK();
GDALRegister_MEM();
GDALRegister_JDEM();
// GDALRegister_GRASS();
GDALRegister_PNM();
GDALRegister_GIF();
GDALRegister_Envisat();
// GDALRegister_FITS();
// GDALRegister_ECW();
// GDALRegister_JP2ECW();
// GDALRegister_ECW_JP2ECW();
GDALRegister_FujiBAS();
GDALRegister_FIT();
GDALRegister_VRT();
GDALRegister_USGSDEM();
GDALRegister_FAST();
// GDALRegister_HDF4();
// GDALRegister_HDF4Image();
GDALRegister_L1B();
// GDALRegister_LDF();
GDALRegister_BSB();
GDALRegister_XPM();
GDALRegister_BMP();
GDALRegister_GSC();
GDALRegister_NITF();
GDALRegister_RPFTOC();
// GDALRegister_MrSID();
// GDALRegister_PCIDSK();
GDALRegister_BT();
// GDALRegister_DODS();
// GDALRegister_GMT();
// GDALRegister_netCDF();
GDALRegister_LAN();
GDALRegister_CPG();
GDALRegister_AirSAR();
GDALRegister_RS2();
GDALRegister_ILWIS();
GDALRegister_PCRaster();
GDALRegister_IDA();
GDALRegister_NDF();
GDALRegister_RMF();
// GDALRegister_HDF5();
// GDALRegister_HDF5Image();
// GDALRegister_MSGN();
// GDALRegister_MSG();
GDALRegister_RIK();
GDALRegister_Leveller();
GDALRegister_SGI();
GDALRegister_SRTMHGT();
GDALRegister_DIPEx();
GDALRegister_ISIS3();
GDALRegister_ISIS2();
GDALRegister_PDS();
// GDALRegister_IDRISI();
GDALRegister_Terragen();
GDALRegister_WCS();
// GDALRegister_WMS();
GDALRegister_HTTP();
// GDALRegister_SDE();
GDALRegister_GSAG();
GDALRegister_GSBG();
GDALRegister_GS7BG();
GDALRegister_GRIB();
GDALRegister_INGR();
GDALRegister_ERS();
GDALRegister_PALSARJaxa();
GDALRegister_DIMAP();
GDALRegister_GFF();
GDALRegister_COSAR();
GDALRegister_TSX();
// GDALRegister_ADRG();
GDALRegister_COASP();
GDALRegister_BLX();
GDALRegister_LCP();
// GDALRegister_PGCHIP();
// GDALRegister_TMS();
GDALRegister_EIR();
// GDALRegister_GEOR();
MemoryIgnoreLeaksEnd();
}
Close();
MemoryIgnoreLeaksBegin();
dataset = (GDALDataset *) GDALOpen(fn, GA_ReadOnly);
MemoryIgnoreLeaksEnd();
if(!dataset)
return false;
int nbands = dataset->GetRasterCount();
for(int i = 1; i <= nbands; i++)
bands.Add(new Band(*this, dataset->GetRasterBand(i)));
double affine[6];
dataset->GetGeoTransform(affine);
transform.a.x = affine[0];
transform.x.x = affine[1];
transform.y.x = affine[2];
transform.a.y = affine[3];
transform.x.y = affine[4];
transform.y.y = affine[5];
if(fabs(Determinant(transform)) <= 1e-10)
inverse_transform = Matrixf_1();
else
inverse_transform = MatrixfInverse(transform);
filename = fn;
return true;
}
void Gdal::Close()
{
bands.Clear();
if(dataset) {
GDALClose((GDALDatasetH) dataset);
dataset = NULL;
}
}
String Gdal::GetProjection() const
{
return dataset->GetProjectionRef();
}
Size Gdal::GetPixelSize() const
{
return Size(dataset->GetRasterXSize(), dataset->GetRasterYSize());
}
Rectf Gdal::GetExtent() const
{
return Rectf(Sizef(GetPixelSize())) * GetTransform();
}