mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 14:15:21 -06:00
885 lines
32 KiB
C++
885 lines
32 KiB
C++
/******************************************************************************
|
|
* $Id: sdedataset.cpp 10804 2007-02-08 23:24:59Z hobu $
|
|
*
|
|
* Project: ESRI ArcSDE Raster reader
|
|
* Purpose: Rasterband implementaion for ESRI ArcSDE Rasters
|
|
* Author: Howard Butler, hobu@hobu.net
|
|
*
|
|
* This work was sponsored by the Geological Survey of Canada, Natural
|
|
* Resources Canada. http://gsc.nrcan.gc.ca/
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2007, Howard Butler <hobu@hobu.net>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
|
|
#include "sderasterband.h"
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* SDERasterBand implements a GDAL RasterBand for ArcSDE. This class */
|
|
/* carries around a pointer to SDE's internal band representation */
|
|
/* is of type SE_RASBANDINFO*. SDERasterBand provides the following */
|
|
/* capabilities: */
|
|
/* */
|
|
/* -- Statistics support - uses SDE's internal band statistics */
|
|
/* -- Colortable - translates SDE's internal colortable to GDAL's */
|
|
/* -- Block reading through IReadBlock */
|
|
/* -- Overview support */
|
|
/* -- NODATA support */
|
|
/* */
|
|
/* Instantiating a SDERasterBand is rather expensive because of all */
|
|
/* of the round trips to the database the SDE C API must make to */
|
|
/* calculate band information. This overhead hit is also taken in */
|
|
/* the case of grabbing an overview, because information between */
|
|
/* bands is not shared. It might be possible in the future to do */
|
|
/* do so, but it would likely make things rather complicated. */
|
|
/* In particular, the stream, constraint, and queryinfo SDE objects */
|
|
/* could be passed around from band to overview band without having */
|
|
/* to be instantiated every time. Stream creation has an especially */
|
|
/* large overhead. */
|
|
/* */
|
|
/* Once the band or overview band is established, querying raster */
|
|
/* blocks does not carry much more network overhead than that requied */
|
|
/* to actually download the bytes. */
|
|
/* */
|
|
/* Overview of internal methods: */
|
|
/* -- InitializeBand - does most of the work of construction */
|
|
/* of the band and communication with SDE. */
|
|
/* Calls InitializeConstraint and */
|
|
/* IntializeQuery. */
|
|
/* -- InitializeQuery - Initializes a SDE queryinfo object */
|
|
/* that contains information about which */
|
|
/* tables we are querying from. */
|
|
/* -- InitializeConstraint - Specifies block constraints (which */
|
|
/* are initially set to none in */
|
|
/* InitializeBand) as well as which */
|
|
/* band for SDE to query from. */
|
|
/* -- MorphESRIRasterType - translates SDE's raster type to GDAL*/
|
|
/* -- MorphESRIRasterDepth - calculates the bit depth from SDE */
|
|
/* -- ComputeColorTable - does the work of getting and */
|
|
/* translating the SDE colortable to GDAL. */
|
|
/* -- ComputeSDEBandNumber - returns the band # for SDE's */
|
|
/* internal representation of the band.*/
|
|
/* -- QueryRaster - Does the work of setting the constraint */
|
|
/* and preparing for querying tiles from SDE. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
|
|
/************************************************************************/
|
|
/* SDERasterBand() */
|
|
/************************************************************************/
|
|
|
|
SDERasterBand::SDERasterBand( SDEDataset *poDS,
|
|
int nBand,
|
|
int nOverview,
|
|
const SE_RASBANDINFO* band )
|
|
|
|
{
|
|
// Carry some of the data we were given at construction.
|
|
// If we were passed -1 for an overview at construction, reset it
|
|
// to 0 to ensure we get the zero'th level from SDE.
|
|
// The SE_RASBANDINFO* we were given is actually owned by the
|
|
// dataset. We want it around for convenience.
|
|
this->poDS = poDS;
|
|
this->nBand = nBand;
|
|
this->nOverview = nOverview;
|
|
this->poBand = band;
|
|
|
|
// Initialize our SDE opaque object pointers to NULL.
|
|
// The nOverviews private data member will be updated when
|
|
// GetOverviewCount is called and subsequently returned immediately in
|
|
// later calls if it has been set to anything other than 0.
|
|
this->hConstraint = NULL;
|
|
this->hQuery = NULL;
|
|
this->poColorTable = NULL;
|
|
|
|
if (this->nOverview == -1 || this->nOverview == 0)
|
|
this->nOverviews = GetOverviewCount();
|
|
else
|
|
this->nOverviews = 0;
|
|
|
|
if (nOverview == -1) {
|
|
this->papoOverviews = (GDALRasterBand**) CPLMalloc( nOverviews * sizeof(GDALRasterBand*) );
|
|
}
|
|
else {
|
|
this->papoOverviews = NULL;
|
|
}
|
|
this->eDataType = GetRasterDataType();
|
|
|
|
// nSDERasterType is set by GetRasterDataType
|
|
this->dfDepth = MorphESRIRasterDepth(nSDERasterType);
|
|
InitializeBand(this->nOverview);
|
|
|
|
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~SDERasterBand() */
|
|
/************************************************************************/
|
|
SDERasterBand::~SDERasterBand( void )
|
|
|
|
{
|
|
|
|
if (hQuery)
|
|
SE_queryinfo_free(hQuery);
|
|
|
|
if (hConstraint)
|
|
SE_rasconstraint_free(hConstraint);
|
|
|
|
if (papoOverviews)
|
|
for (int i=0; i < nOverviews; i++)
|
|
delete papoOverviews[i];
|
|
CPLFree(papoOverviews);
|
|
|
|
if (poColorTable != NULL)
|
|
delete poColorTable;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetColorTable() */
|
|
/************************************************************************/
|
|
GDALColorTable* SDERasterBand::GetColorTable(void)
|
|
{
|
|
|
|
if (SE_rasbandinfo_has_colormap(*poBand)) {
|
|
if (poColorTable == NULL)
|
|
ComputeColorTable();
|
|
return poColorTable;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetColorInterpretation() */
|
|
/************************************************************************/
|
|
GDALColorInterp SDERasterBand::GetColorInterpretation()
|
|
{
|
|
// Only return Paletted images when SDE has a colormap. Otherwise,
|
|
// just return gray, even in the instance where we have 3 or 4 band,
|
|
// imagery. Let the client be smart instead of trying to do too much.
|
|
if (SE_rasbandinfo_has_colormap(*poBand))
|
|
return GCI_PaletteIndex;
|
|
else
|
|
return GCI_GrayIndex;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverview() */
|
|
/************************************************************************/
|
|
GDALRasterBand* SDERasterBand::GetOverview( int nOverviewValue )
|
|
{
|
|
|
|
if (papoOverviews) {
|
|
return papoOverviews[nOverviewValue];
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverviewCount() */
|
|
/************************************************************************/
|
|
int SDERasterBand::GetOverviewCount( void )
|
|
{
|
|
// grab our existing overview count if we have already gotten it,
|
|
// otherwise request it from SDE and set our member data with it.
|
|
long nSDEErr;
|
|
BOOL bSkipLevel;
|
|
LONG nOvRet;
|
|
|
|
// return nothing if we were an overview band
|
|
if (nOverview != -1)
|
|
return 0;
|
|
|
|
nSDEErr = SE_rasbandinfo_get_max_level(*poBand, &nOvRet, &bSkipLevel);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasbandinfo_get_band_size" );
|
|
}
|
|
|
|
nOverviews = nOvRet;
|
|
|
|
return nOverviews;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetRasterDataType() */
|
|
/************************************************************************/
|
|
GDALDataType SDERasterBand::GetRasterDataType(void)
|
|
{
|
|
// Always ask SDE what it thinks our type is.
|
|
LONG nSDEErr;
|
|
|
|
nSDEErr = SE_rasbandinfo_get_pixel_type(*poBand, &nSDERasterType);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasbandinfo_get_pixel_type" );
|
|
return GDT_Byte;
|
|
}
|
|
|
|
return MorphESRIRasterType(nSDERasterType);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetStatistics() */
|
|
/************************************************************************/
|
|
|
|
CPLErr SDERasterBand::GetStatistics( int bApproxOK, int bForce,
|
|
double *pdfMin, double *pdfMax,
|
|
double *pdfMean, double *pdfStdDev )
|
|
{
|
|
// if SDE hasn't already cached our statistics, we'll depend on the
|
|
// GDALRasterBands's method for getting them.
|
|
bool bHasStats;
|
|
bHasStats = SE_rasbandinfo_has_stats (*poBand);
|
|
if (!bHasStats)
|
|
return GDALRasterBand::GetStatistics( bApproxOK,
|
|
bForce,
|
|
pdfMin,
|
|
pdfMax,
|
|
pdfMean,
|
|
pdfStdDev);
|
|
|
|
// bForce has no effect currently. We always go to SDE to get our
|
|
// stats if SDE has them.
|
|
|
|
// bApproxOK has no effect currently. If we're getting stats from
|
|
// SDE, we're hoping SDE calculates them in the way we want.
|
|
long nSDEErr;
|
|
nSDEErr = SE_rasbandinfo_get_stats_min(*poBand, pdfMin);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasbandinfo_get_stats_min" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nSDEErr = SE_rasbandinfo_get_stats_max(*poBand, pdfMax);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasbandinfo_get_stats_max" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nSDEErr = SE_rasbandinfo_get_stats_mean(*poBand, pdfMean);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasbandinfo_get_stats_mean" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nSDEErr = SE_rasbandinfo_get_stats_stddev(*poBand, pdfStdDev);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasbandinfo_get_stats_stddev" );
|
|
return CE_Fatal;
|
|
}
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMinimum() */
|
|
/************************************************************************/
|
|
|
|
double SDERasterBand::GetMinimum(int *pbSuccess)
|
|
{
|
|
double dfMin, dfMax, dfMean, dfStdDev;
|
|
CPLErr error = GetStatistics( TRUE, TRUE,
|
|
&dfMin,
|
|
&dfMax,
|
|
&dfMean,
|
|
&dfStdDev );
|
|
if (error == CE_None) {
|
|
*pbSuccess = TRUE;
|
|
return dfMin;
|
|
}
|
|
*pbSuccess = FALSE;
|
|
return 0.0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaximum() */
|
|
/************************************************************************/
|
|
|
|
double SDERasterBand::GetMaximum(int *pbSuccess)
|
|
{
|
|
double dfMin, dfMax, dfMean, dfStdDev;
|
|
CPLErr error = GetStatistics( TRUE, TRUE,
|
|
&dfMin,
|
|
&dfMax,
|
|
&dfMean,
|
|
&dfStdDev );
|
|
if (error == CE_None) {
|
|
*pbSuccess = TRUE;
|
|
return dfMax;
|
|
}
|
|
*pbSuccess = FALSE;
|
|
return 0.0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr SDERasterBand::IReadBlock( int nBlockXOff,
|
|
int nBlockYOff,
|
|
void * pImage )
|
|
|
|
{
|
|
// grab our Dataset to limit the casting we have to do.
|
|
SDEDataset *poGDS = (SDEDataset *) poDS;
|
|
|
|
|
|
// SDE manages the acquisition of raster data in "TileInfo" objects.
|
|
// The hTile is the only heap-allocated object in this method, and
|
|
// we should make sure to delete it at the end. Once we get the
|
|
// pixel data, we'll memcopy it back on to the pImage pointer.
|
|
|
|
SE_RASTILEINFO hTile;
|
|
long nSDEErr;
|
|
nSDEErr = SE_rastileinfo_create(&hTile);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rastileinfo_create" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
hConstraint = InitializeConstraint( (long*) &nBlockXOff, (long*) &nBlockYOff );
|
|
if (!hConstraint)
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"ConstraintInfo initialization failed");
|
|
|
|
CPLErr error = QueryRaster(hConstraint);
|
|
if (error != CE_None)
|
|
return error;
|
|
|
|
LONG level;
|
|
nSDEErr = SE_rastileinfo_get_level(hTile, &level);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rastileinfo_get_level" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nSDEErr = SE_stream_get_raster_tile(poGDS->hStream, hTile);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_stream_get_raster_tile" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
LONG row, column;
|
|
nSDEErr = SE_rastileinfo_get_rowcol(hTile, &row, &column);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rastileinfo_get_level" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
LONG length;
|
|
unsigned char* pixels;
|
|
nSDEErr = SE_rastileinfo_get_pixel_data(hTile, (void**) &pixels, &length);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rastileinfo_get_pixel_data" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
int bits_per_pixel = static_cast<int>(dfDepth * 8 + 0.0001);
|
|
int block_size = (nBlockXSize * bits_per_pixel + 7) / 8 * nBlockYSize;
|
|
int bitmap_size = (nBlockXSize * nBlockYSize + 7) / 8;
|
|
|
|
|
|
if (length == 0) {
|
|
// ArcSDE says the block has no data in it.
|
|
// Write 0's and be done with it
|
|
memset( pImage, 0,
|
|
nBlockXSize*nBlockYSize*GDALGetDataTypeSize(eDataType)/8);
|
|
return CE_None;
|
|
}
|
|
if ((length == block_size) || (length == (block_size + bitmap_size))) {
|
|
if (bits_per_pixel >= 8) {
|
|
memcpy(pImage, pixels, block_size);
|
|
} else {
|
|
GByte *p = reinterpret_cast<GByte*>(pImage);
|
|
int bit_mask = (2 << bits_per_pixel) - 1;
|
|
int i = 0;
|
|
for (int y = 0; y < nBlockYSize; ++y) {
|
|
for (int x = 0; x < nBlockXSize; ++x) {
|
|
*p++ = (pixels[i >> 3] >> (i & 7)) & bit_mask;
|
|
i += bits_per_pixel;
|
|
}
|
|
i = (i + 7) / 8 * 8;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Bit size calculation failed... "\
|
|
"SDE's length:%d With bitmap length: %d Without bitmap length: %d",
|
|
length, block_size + bitmap_size, block_size );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
SE_rastileinfo_free (hTile);
|
|
|
|
return CE_None ;
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------*/
|
|
/* Private Methods */
|
|
|
|
/************************************************************************/
|
|
/* ComputeColorTable() */
|
|
/************************************************************************/
|
|
void SDERasterBand::ComputeColorTable(void)
|
|
{
|
|
|
|
SE_COLORMAP_TYPE eCMap_Type;
|
|
SE_COLORMAP_DATA_TYPE eCMap_DataType;
|
|
|
|
LONG nCMapEntries;
|
|
void * phSDEColormapData;
|
|
|
|
unsigned char* puszSDECMapData;
|
|
unsigned short* pushSDECMapData;
|
|
|
|
long nSDEErr;
|
|
|
|
nSDEErr = SE_rasbandinfo_get_colormap( *poBand,
|
|
&eCMap_Type,
|
|
&eCMap_DataType,
|
|
&nCMapEntries,
|
|
&phSDEColormapData);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasbandinfo_get_colormap" );
|
|
}
|
|
|
|
// Assign both the short and char pointers
|
|
// to the void*, and we'll switch and read based
|
|
// on the eCMap_DataType
|
|
puszSDECMapData = (unsigned char*) phSDEColormapData;
|
|
pushSDECMapData = (unsigned short*) phSDEColormapData;
|
|
|
|
poColorTable = new GDALColorTable(GPI_RGB);
|
|
|
|
int red, green, blue, alpha;
|
|
|
|
CPLDebug("SDERASTER", "%d colormap entries specified", nCMapEntries);
|
|
switch (eCMap_DataType) {
|
|
case SE_COLORMAP_DATA_BYTE:
|
|
switch (eCMap_Type){
|
|
case SE_COLORMAP_RGB:
|
|
for (int i = 0; i < (nCMapEntries); i++) {
|
|
int j = i*3;
|
|
red = puszSDECMapData[j];
|
|
green = puszSDECMapData[j+1];
|
|
blue = puszSDECMapData[j+2];
|
|
GDALColorEntry sColor;
|
|
sColor.c1 = red;
|
|
sColor.c2 = green;
|
|
sColor.c3 = blue;
|
|
sColor.c4 = 255;
|
|
|
|
// sColor is copied
|
|
poColorTable->SetColorEntry(i,&sColor);
|
|
CPLDebug ("SDERASTER", "SE_COLORMAP_DATA_BYTE "\
|
|
"SE_COLORMAP_RGB Colormap Entry: %d %d %d",
|
|
red, blue, green);
|
|
}
|
|
break;
|
|
case SE_COLORMAP_RGBA:
|
|
for (int i = 0; i < (nCMapEntries); i++) {
|
|
int j = i*4;
|
|
red = puszSDECMapData[j];
|
|
green = puszSDECMapData[j+1];
|
|
blue = puszSDECMapData[j+2];
|
|
alpha = puszSDECMapData[j+3];
|
|
GDALColorEntry sColor;
|
|
sColor.c1 = red;
|
|
sColor.c2 = green;
|
|
sColor.c3 = blue;
|
|
sColor.c4 = alpha;
|
|
|
|
// sColor is copied
|
|
poColorTable->SetColorEntry(i,&sColor);
|
|
CPLDebug ("SDERASTER", "SE_COLORMAP_DATA_BYTE "\
|
|
"SE_COLORMAP_RGBA Colormap Entry: %d %d %d %d",
|
|
red, blue, green, alpha);
|
|
}
|
|
break;
|
|
case SE_COLORMAP_NONE:
|
|
break;
|
|
}
|
|
break;
|
|
case SE_COLORMAP_DATA_SHORT:
|
|
switch (eCMap_Type) {
|
|
case SE_COLORMAP_RGB:
|
|
for (int i = 0; i < (nCMapEntries); i++) {
|
|
int j = i*3;
|
|
red = pushSDECMapData[j];
|
|
green = pushSDECMapData[j+1];
|
|
blue = pushSDECMapData[j+2];
|
|
GDALColorEntry sColor;
|
|
sColor.c1 = red;
|
|
sColor.c2 = green;
|
|
sColor.c3 = blue;
|
|
sColor.c4 = 255;
|
|
|
|
// sColor is copied
|
|
poColorTable->SetColorEntry(i,&sColor);
|
|
CPLDebug ("SDERASTER", "SE_COLORMAP_DATA_SHORT "\
|
|
"SE_COLORMAP_RGB Colormap Entry: %d %d %d",
|
|
red, blue, green);
|
|
}
|
|
break;
|
|
case SE_COLORMAP_RGBA:
|
|
for (int i = 0; i < (nCMapEntries); i++) {
|
|
int j = i*4;
|
|
red = pushSDECMapData[j];
|
|
green = pushSDECMapData[j+1];
|
|
blue = pushSDECMapData[j+2];
|
|
alpha = pushSDECMapData[j+3];
|
|
GDALColorEntry sColor;
|
|
sColor.c1 = red;
|
|
sColor.c2 = green;
|
|
sColor.c3 = blue;
|
|
sColor.c4 = alpha;
|
|
|
|
// sColor is copied
|
|
poColorTable->SetColorEntry(i,&sColor);
|
|
CPLDebug ("SDERASTER", "SE_COLORMAP_DATA_SHORT "\
|
|
"SE_COLORMAP_RGBA Colormap Entry: %d %d %d %d",
|
|
red, blue, green, alpha);
|
|
}
|
|
break;
|
|
case SE_COLORMAP_NONE:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
SE_rasbandinfo_free_colormap(phSDEColormapData);
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* InitializeBand() */
|
|
/************************************************************************/
|
|
CPLErr SDERasterBand::InitializeBand( int nOverview )
|
|
|
|
{
|
|
|
|
SDEDataset *poGDS = (SDEDataset *) poDS;
|
|
|
|
long nSDEErr;
|
|
|
|
|
|
hConstraint = InitializeConstraint( NULL, NULL );
|
|
if (!hConstraint)
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"ConstraintInfo initialization failed");
|
|
|
|
if (!hQuery) {
|
|
hQuery = InitializeQuery();
|
|
if (!hQuery)
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"QueryInfo initialization failed");
|
|
}
|
|
|
|
nSDEErr = SE_stream_close(poGDS->hStream, 1);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_stream_close" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nSDEErr = SE_stream_query_with_info(poGDS->hStream, hQuery);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_stream_query_with_info" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nSDEErr = SE_stream_execute (poGDS->hStream);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_stream_execute" );
|
|
return CE_Fatal;
|
|
}
|
|
nSDEErr = SE_stream_fetch (poGDS->hStream);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_stream_fetch" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
|
|
CPLErr error = QueryRaster(hConstraint);
|
|
if (error != CE_None)
|
|
return error;
|
|
|
|
LONG nBXRet, nBYRet;
|
|
nSDEErr = SE_rasterattr_get_tile_size (poGDS->hAttributes,
|
|
&nBXRet, &nBYRet);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasterattr_get_tile_size" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nBlockXSize = nBXRet;
|
|
nBlockYSize = nBYRet;
|
|
|
|
LONG offset_x, offset_y, num_bands, nXSRet, nYSRet;
|
|
|
|
nSDEErr = SE_rasterattr_get_image_size_by_level (poGDS->hAttributes,
|
|
&nXSRet, &nYSRet,
|
|
&offset_x,
|
|
&offset_y,
|
|
&num_bands,
|
|
(nOverview == -1) ? (0): (nOverview));
|
|
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasterattr_get_image_size_by_level" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nRasterXSize = nXSRet;
|
|
nRasterYSize = nYSRet;
|
|
|
|
nBlockSize = nBlockXSize * nBlockYSize;
|
|
|
|
// We're the base level
|
|
if (nOverview == -1) {
|
|
for (int i = 0; i<this->nOverviews; i++) {
|
|
papoOverviews[i]= new SDERasterBand(poGDS, nBand, i, poBand);
|
|
|
|
}
|
|
}
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* InitializeConstraint() */
|
|
/************************************************************************/
|
|
SE_RASCONSTRAINT& SDERasterBand::InitializeConstraint( long* nBlockXOff,
|
|
long* nBlockYOff)
|
|
{
|
|
|
|
long nSDEErr;
|
|
|
|
if (!hConstraint) {
|
|
nSDEErr = SE_rasconstraint_create(&hConstraint);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasconstraint_create" );
|
|
}
|
|
|
|
nSDEErr = SE_rasconstraint_set_level(hConstraint, (nOverview == -1) ? (0): (nOverview));
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasconstraint_create" );
|
|
}
|
|
|
|
LONG nBandIn = nBand;
|
|
nSDEErr = SE_rasconstraint_set_bands(hConstraint, 1, &nBandIn);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasconstraint_set_bands" );
|
|
}
|
|
nSDEErr = SE_rasconstraint_set_interleave(hConstraint, SE_RASTER_INTERLEAVE_BSQ);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasconstraint_set_interleave" );
|
|
}
|
|
|
|
}
|
|
|
|
if (nBlockXSize != -1 && nBlockYSize != -1) { // we aren't initialized yet
|
|
if (nBlockXSize >= 0 && nBlockYSize >= 0) {
|
|
if (*nBlockXOff >= 0 && *nBlockYOff >= 0) {
|
|
long nMinX, nMinY, nMaxX, nMaxY;
|
|
|
|
nMinX = *nBlockXOff;
|
|
nMinY = *nBlockYOff;
|
|
nMaxX = *nBlockXOff;
|
|
nMaxY = *nBlockYOff;
|
|
|
|
nSDEErr = SE_rasconstraint_set_envelope (hConstraint,
|
|
nMinX,
|
|
nMinY,
|
|
nMaxX,
|
|
nMaxY);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_rasconstraint_set_envelope" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return hConstraint;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* InitializeQuery() */
|
|
/************************************************************************/
|
|
SE_QUERYINFO& SDERasterBand::InitializeQuery( void )
|
|
{
|
|
SDEDataset *poGDS = (SDEDataset *) poDS;
|
|
long nSDEErr;
|
|
|
|
nSDEErr = SE_queryinfo_create(&hQuery);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_queryinfo_create" );
|
|
}
|
|
|
|
nSDEErr = SE_queryinfo_set_tables(hQuery,
|
|
1,
|
|
(const char**) &(poGDS->pszLayerName),
|
|
NULL);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_queryinfo_set_tables" );
|
|
}
|
|
|
|
nSDEErr = SE_queryinfo_set_where_clause(hQuery, (const char*) "");
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_queryinfo_set_where" );
|
|
}
|
|
|
|
nSDEErr = SE_queryinfo_set_columns(hQuery,
|
|
1,
|
|
(const char**) &(poGDS->pszColumnName));
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_queryinfo_set_where" );
|
|
}
|
|
return hQuery;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* MorphESRIRasterDepth() */
|
|
/************************************************************************/
|
|
double SDERasterBand::MorphESRIRasterDepth(int gtype) {
|
|
|
|
switch (gtype) {
|
|
case SE_PIXEL_TYPE_1BIT:
|
|
return 0.125;
|
|
case SE_PIXEL_TYPE_4BIT:
|
|
return 0.5;
|
|
case SE_PIXEL_TYPE_8BIT_U:
|
|
return 1.0;
|
|
case SE_PIXEL_TYPE_8BIT_S:
|
|
return 1.0;
|
|
case SE_PIXEL_TYPE_16BIT_U:
|
|
return 2.0;
|
|
case SE_PIXEL_TYPE_16BIT_S:
|
|
return 2.0;
|
|
case SE_PIXEL_TYPE_32BIT_U:
|
|
return 4.0;
|
|
case SE_PIXEL_TYPE_32BIT_S:
|
|
return 4.0;
|
|
case SE_PIXEL_TYPE_32BIT_REAL:
|
|
return 4.0;
|
|
case SE_PIXEL_TYPE_64BIT_REAL:
|
|
return 8.0;
|
|
default:
|
|
return 2.0;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* MorphESRIRasterType() */
|
|
/************************************************************************/
|
|
GDALDataType SDERasterBand::MorphESRIRasterType(int gtype) {
|
|
|
|
switch (gtype) {
|
|
case SE_PIXEL_TYPE_1BIT:
|
|
return GDT_Byte;
|
|
case SE_PIXEL_TYPE_4BIT:
|
|
return GDT_Byte;
|
|
case SE_PIXEL_TYPE_8BIT_U:
|
|
return GDT_Byte;
|
|
case SE_PIXEL_TYPE_8BIT_S:
|
|
return GDT_Byte;
|
|
case SE_PIXEL_TYPE_16BIT_U:
|
|
return GDT_UInt16;
|
|
case SE_PIXEL_TYPE_16BIT_S:
|
|
return GDT_Int16;
|
|
case SE_PIXEL_TYPE_32BIT_U:
|
|
return GDT_UInt32;
|
|
case SE_PIXEL_TYPE_32BIT_S:
|
|
return GDT_Int32;
|
|
case SE_PIXEL_TYPE_32BIT_REAL:
|
|
return GDT_Float32;
|
|
case SE_PIXEL_TYPE_64BIT_REAL:
|
|
return GDT_Float64;
|
|
default:
|
|
return GDT_UInt16;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* QueryRaster() */
|
|
/************************************************************************/
|
|
CPLErr SDERasterBand::QueryRaster( SE_RASCONSTRAINT& constraint )
|
|
{
|
|
|
|
SDEDataset *poGDS = (SDEDataset *) poDS;
|
|
|
|
long nSDEErr;
|
|
|
|
|
|
|
|
nSDEErr = SE_stream_query_raster_tile(poGDS->hStream, constraint);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_stream_query_raster_tile" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
nSDEErr = SE_stream_get_raster (poGDS->hStream, 1, poGDS->hAttributes);
|
|
if( nSDEErr != SE_SUCCESS )
|
|
{
|
|
IssueSDEError( nSDEErr, "SE_stream_fetch" );
|
|
return CE_Fatal;
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
//T:\>gdal_translate -of GTiff SDE:nakina.gis.iastate.edu,5151,,geoservwrite,EsrI4ever,sde_master.geoservwrite.century foo.tif
|
|
//T:\>gdalinfo SDE:nakina.gis.iastate.edu,5151,,geoservwrite,EsrI4ever,sde_master.geoservwrite.century
|