LCOV - code coverage report
Current view: directory - frmts/postgisraster - postgisrasterrasterband.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 298 0 0.0 %
Date: 2012-12-26 Functions: 13 0 0.0 %

       1                 : /******************************************************************************
       2                 :  * File :    PostGISRasterRasterBand.cpp
       3                 :  * Project:  PostGIS Raster driver
       4                 :  * Purpose:  GDAL Raster Band implementation for PostGIS Raster driver 
       5                 :  * Author:   Jorge Arevalo, jorgearevalo@deimos-space.com
       6                 :  * 
       7                 :  * Last changes:
       8                 :  * $Id: $
       9                 :  *
      10                 :  ******************************************************************************
      11                 :  * Copyright (c) 2009 - 2011, Jorge Arevalo, jorge.arevalo@deimos-space.com
      12                 :  *
      13                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      14                 :  * copy of this software and associated documentation files (the "Software"),
      15                 :  * to deal in the Software without restriction, including without limitation
      16                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 :  * and/or sell copies of the Software, and to permit persons to whom the
      18                 :  * Software is furnished to do so, subject to the following conditions:
      19                 :  *
      20                 :  * The above copyright notice and this permission notice shall be included
      21                 :  * in all copies or substantial portions of the Software.
      22                 :  *
      23                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29                 :  * DEALINGS IN THE SOFTWARE.
      30                 :  ******************************************************************************/
      31                 : #include "postgisraster.h"
      32                 : #include "ogr_api.h"
      33                 : #include "ogr_geometry.h"
      34                 : #include "gdal_priv.h"
      35                 : #include "gdal.h"
      36                 : #include <string>
      37                 : #include "cpl_string.h"
      38                 : #include "gdal_vrt.h"
      39                 : #include "vrtdataset.h"
      40                 : #include "memdataset.h"
      41                 : 
      42                 : 
      43                 : /**
      44                 :  * \brief Constructor.
      45                 :  * Parameters:
      46                 :  *  - PostGISRasterDataset *: The Dataset this band belongs to
      47                 :  *  - int: the band number
      48                 :  *  - GDALDataType: The data type for this band
      49                 :  *  - double: The nodata value.  Could be any kind of data (GByte, GUInt16,
      50                 :  *          GInt32...) but the variable has the bigger type.
      51                 :  *  - GBool: if the data type is signed byte or not. If yes, the SIGNEDBYTE
      52                 :  *          metadata value is added to IMAGE_STRUCTURE domain
      53                 :  *  - int: The bit depth, to add NBITS as metadata value in IMAGE_STRUCTURE
      54                 :  *          domain.
      55                 :  *  TODO: Comment the rest of parameters
      56                 :  */
      57               0 : PostGISRasterRasterBand::PostGISRasterRasterBand(PostGISRasterDataset *poDS,
      58                 :         int nBand, GDALDataType hDataType, GBool bHasNoDataValue, double dfNodata, 
      59                 :         GBool bSignedByte,int nBitDepth, int nFactor, int nBlockXSize, int nBlockYSize,
      60               0 :         GBool bIsOffline, char * inPszSchema, char * inPszTable, char * inPszColumn)
      61                 : {
      62                 : 
      63                 :     /* Basic properties */
      64               0 :     this->poDS = poDS;
      65               0 :     this->nBand = nBand;
      66               0 :     this->bIsOffline = bIsOffline;
      67                 : 
      68               0 :     eAccess = poDS->GetAccess();
      69               0 :     eDataType = hDataType;
      70               0 :     this->bHasNoDataValue = bHasNoDataValue;
      71               0 :     dfNoDataValue = dfNodata;
      72                 : 
      73               0 :     if (poDS->nBands == 1) {
      74               0 :         eBandInterp = GCI_GrayIndex;
      75                 :     }
      76                 : 
      77               0 :     else if (poDS->nBands == 3) {
      78               0 :         if (nBand == 1)
      79               0 :             eBandInterp = GCI_RedBand;
      80               0 :         else if( nBand == 2 )
      81               0 :             eBandInterp = GCI_GreenBand;
      82               0 :         else if( nBand == 3 )
      83               0 :             eBandInterp = GCI_BlueBand;
      84                 :         else
      85               0 :             eBandInterp = GCI_Undefined;
      86                 :     }
      87                 : 
      88                 :     else {
      89               0 :         eBandInterp = GCI_Undefined;
      90                 :     }
      91                 : 
      92                 : 
      93                 : 
      94                 :     /**************************************************************************
      95                 :      * TODO: Set a non arbitrary blocksize. In case or regular blocking, this is 
      96                 :      * easy, otherwise, does it make any sense? Any single tile has its own 
      97                 :      * dimensions.
      98                 :      *************************************************************************/
      99               0 :     if (poDS->bRegularBlocking) {
     100                 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::Constructor: "
     101               0 :             "Band %d has regular blocking", nBand);
     102                 :     
     103               0 :         this->nBlockXSize = nBlockXSize;
     104               0 :         this->nBlockYSize = nBlockYSize;
     105                 :     }
     106                 : 
     107                 :     else {
     108                 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::Constructor: "
     109               0 :             "Band %d does not have regular blocking", nBand);
     110                 : 
     111                 :         /*
     112                 :         this->nBlockXSize = MIN(poDS->nRasterXSize, DEFAULT_BLOCK_X_SIZE); 
     113                 :         this->nBlockYSize = MIN(poDS->nRasterYSize, DEFAULT_BLOCK_Y_SIZE);
     114                 :         */
     115                 : 
     116               0 :         this->nBlockXSize = poDS->nRasterXSize;
     117               0 :         this->nBlockYSize = 1;
     118                 :     }
     119                 : 
     120                 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::Constructor: "
     121               0 :         "Block size (%dx%d)", this->nBlockXSize, this->nBlockYSize);
     122                 :         
     123                 :     // Add pixeltype to image structure domain
     124               0 :     if (bSignedByte == true) {
     125               0 :         SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
     126                 :     }
     127                 : 
     128                 :     // Add NBITS to metadata only for sub-byte types
     129               0 :     if (nBitDepth < 8)
     130                 :         SetMetadataItem("NBITS", CPLString().Printf( "%d", nBitDepth ),
     131               0 :             "IMAGE_STRUCTURE" );
     132                 : 
     133                 : 
     134               0 :     nOverviewFactor = nFactor;
     135                 : 
     136               0 :     this->pszSchema = (inPszSchema) ? inPszSchema : poDS->pszSchema; 
     137               0 :     this->pszTable = (inPszTable) ? inPszTable : poDS->pszTable; 
     138               0 :     this->pszColumn = (inPszColumn) ? inPszColumn : poDS->pszColumn; 
     139                 : 
     140                 :     /**********************************************************
     141                 :      * Check overviews. Query RASTER_OVERVIEWS table for
     142                 :      * existing overviews, only in case we are on level 0
     143                 :      * TODO: can we do this without querying RASTER_OVERVIEWS?
     144                 :      * How do we know the number of overviews? Is an inphinite
     145                 :      * loop...
     146                 :      **********************************************************/
     147               0 :     if (nOverviewFactor == 0) {    
     148                 : 
     149               0 :         CPLString osCommand;
     150               0 :         PGresult * poResult = NULL;
     151               0 :         int i = 0;
     152               0 :         int nFetchOvFactor = 0;
     153               0 :         char * pszOvSchema = NULL;
     154               0 :         char * pszOvTable = NULL;
     155               0 :         char * pszOvColumn = NULL;
     156                 : 
     157               0 :         nRasterXSize = poDS->GetRasterXSize();
     158               0 :         nRasterYSize = poDS->GetRasterYSize();
     159                 :  
     160                 :         osCommand.Printf("select o_table_name, overview_factor, o_raster_column, "
     161                 :                 "o_table_schema from raster_overviews where r_table_schema = "
     162                 :                 "'%s' and r_table_name = '%s' and r_raster_column = '%s'",
     163               0 :                 poDS->pszSchema, poDS->pszTable, poDS->pszColumn);
     164                 : 
     165               0 :         poResult = PQexec(poDS->poConn, osCommand.c_str());
     166               0 :         if (poResult != NULL && PQresultStatus(poResult) == PGRES_TUPLES_OK &&
     167                 :                 PQntuples(poResult) > 0) {
     168                 :             
     169                 :             /* Create overviews */
     170               0 :             nOverviewCount = PQntuples(poResult);           
     171                 :             papoOverviews = (PostGISRasterRasterBand **)VSICalloc(nOverviewCount,
     172               0 :                     sizeof(PostGISRasterRasterBand *));
     173               0 :             if (papoOverviews == NULL) {
     174                 :                 CPLError(CE_Warning, CPLE_OutOfMemory, "Couldn't create "
     175               0 :                         "overviews for band %d\n", nBand);              
     176               0 :                 PQclear(poResult);
     177                 :                 return;
     178                 :             }
     179                 :                        
     180               0 :             for(i = 0; i < nOverviewCount; i++) {
     181                 :         
     182                 :                 CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::Constructor: "
     183               0 :                     "Creating overview for band %d", nBand);
     184                 : 
     185               0 :                 nFetchOvFactor = atoi(PQgetvalue(poResult, i, 1));
     186               0 :                 pszOvSchema = CPLStrdup(PQgetvalue(poResult, i, 3));
     187               0 :                 pszOvTable = CPLStrdup(PQgetvalue(poResult, i, 0));
     188               0 :                 pszOvColumn = CPLStrdup(PQgetvalue(poResult, i, 2));
     189                 :  
     190                 :                 /**
     191                 :                  * NOTE: Overview bands are not considered to be a part of a
     192                 :                  * dataset, but we use the same dataset for all the overview
     193                 :                  * bands just for simplification (we'll need to access the table
     194                 :                  * and schema names). But in method GetDataset, NULL is return
     195                 :                  * if we're talking about an overview band
     196                 :                  */
     197               0 :                 papoOverviews[i] = new PostGISRasterRasterBand(poDS, nBand,
     198                 :                         hDataType, bHasNoDataValue, dfNodata, bSignedByte, nBitDepth,
     199                 :                         nFetchOvFactor, nBlockXSize, nBlockYSize, bIsOffline, pszOvSchema,
     200               0 :                         pszOvTable, pszOvColumn);
     201                 : 
     202                 :             }
     203                 : 
     204               0 :             PQclear(poResult);
     205                 : 
     206                 :         }
     207                 : 
     208                 :         else {
     209                 :             
     210                 :             CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::Constructor: "
     211               0 :                 "Band %d does not have overviews", nBand);
     212               0 :             nOverviewCount = 0;
     213               0 :             papoOverviews = NULL;
     214               0 :             if (poResult)
     215               0 :                 PQclear(poResult);
     216               0 :         }
     217                 :     }
     218                 : 
     219                 :     /************************************
     220                 :      * We are in an overview level. Set
     221                 :      * raster size to its value 
     222                 :      ************************************/
     223                 :     else {
     224                 : 
     225                 :         /* 
     226                 :          * No overviews inside an overview (all the overviews are from original
     227                 :          * band
     228                 :          */
     229               0 :         nOverviewCount = 0;
     230               0 :         papoOverviews = NULL;
     231                 : 
     232                 :         
     233               0 :         nRasterXSize = (int) floor((double)poDS->GetRasterXSize() / nOverviewFactor);
     234               0 :         nRasterYSize = (int) floor((double)poDS->GetRasterYSize() / nOverviewFactor);        
     235                 :     }
     236                 : 
     237                 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand constructor: Band "
     238               0 :             "created (srid = %d)", poDS->nSrid);
     239                 :     
     240                 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand constructor: Band "
     241               0 :             "size: (%d X %d)", nRasterXSize, nRasterYSize);
     242               0 : }
     243                 : 
     244                 : /***********************************************
     245                 :  * \brief: Band destructor
     246                 :  ***********************************************/
     247               0 : PostGISRasterRasterBand::~PostGISRasterRasterBand()
     248                 : {
     249                 :     int i;
     250                 : 
     251               0 :     if (papoOverviews) {
     252               0 :         for(i = 0; i < nOverviewCount; i++)
     253               0 :             delete papoOverviews[i];
     254                 : 
     255               0 :         CPLFree(papoOverviews);
     256                 :     }
     257               0 : }
     258                 :     
     259                 : 
     260                 : /**
     261                 :  *
     262                 :  **/
     263               0 : GDALDataType PostGISRasterRasterBand::TranslateDataType(const char * pszDataType)
     264                 : {
     265               0 :     if (EQUALN(pszDataType, "1BB", 3 * sizeof (char)) ||
     266                 :         EQUALN(pszDataType, "2BUI", 4 * sizeof (char)) ||
     267                 :         EQUALN(pszDataType, "4BUI", 4 * sizeof (char)) ||
     268                 :         EQUALN(pszDataType, "8BUI", 4 * sizeof (char)) ||
     269                 :         EQUALN(pszDataType, "8BSI", 4 * sizeof (char))) 
     270                 :         
     271               0 :         return GDT_Byte;
     272                 : 
     273               0 :     else if (EQUALN(pszDataType, "16BSI", 5 * sizeof (char)))
     274               0 :         return GDT_Int16;
     275                 : 
     276               0 :     else if (EQUALN(pszDataType, "16BUI", 5 * sizeof (char)))
     277               0 :         return GDT_UInt16;
     278                 :     
     279               0 :     else if (EQUALN(pszDataType, "32BSI", 5 * sizeof (char)))
     280               0 :         return GDT_Int32;
     281                 :     
     282               0 :     else if (EQUALN(pszDataType, "32BUI", 5 * sizeof (char)))
     283               0 :         return GDT_UInt32;
     284                 : 
     285               0 :     else if (EQUALN(pszDataType, "32BF", 4 * sizeof (char)))
     286               0 :         return GDT_Float32;
     287                 : 
     288               0 :     else if (EQUALN(pszDataType, "64BF", 4 * sizeof (char)))
     289               0 :         return GDT_Float64;
     290                 : 
     291                 :     else
     292               0 :         return GDT_Unknown;
     293                 : }
     294                 : 
     295                 : 
     296                 : 
     297                 : /**
     298                 :  * Read/write a region of image data for this band.
     299                 :  *
     300                 :  * This method allows reading a region of a PostGISRasterBanda into a buffer. 
     301                 :  * The write support is still under development
     302                 :  *
     303                 :  * The function fetches all the raster data that intersects with the region
     304                 :  * provided, and store the data in the GDAL cache.
     305                 :  *
     306                 :  * It automatically takes care of data type translation if the data type
     307                 :  * (eBufType) of the buffer is different than that of the PostGISRasterRasterBand.
     308                 :  *
     309                 :  * The nPixelSpace and nLineSpace parameters allow reading into from various 
     310                 :  * organization of buffers.
     311                 :  *
     312                 :  * @param eRWFlag Either GF_Read to read a region of data (GF_Write, to write
     313                 :  * a region of data, yet not supported)
     314                 :  *
     315                 :  * @param nXOff The pixel offset to the top left corner of the region of the
     316                 :  * band to be accessed. This would be zero to start from the left side.
     317                 :  *
     318                 :  * @param nYOff The line offset to the top left corner of the region of the band
     319                 :  * to be accessed. This would be zero to start from the top.
     320                 :  *
     321                 :  * @param nXSize The width of the region of the band to be accessed in pixels.
     322                 :  *
     323                 :  * @param nYSize The height of the region of the band to be accessed in lines.
     324                 :  *
     325                 :  * @param pData The buffer into which the data should be read, or from which it
     326                 :  * should be written. This buffer must contain at least
     327                 :  * nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized in
     328                 :  * left to right,top to bottom pixel order. Spacing is controlled by the
     329                 :  * nPixelSpace, and nLineSpace parameters.
     330                 :  *
     331                 :  * @param nBufXSize the width of the buffer image into which the desired region
     332                 :  * is to be read, or from which it is to be written.
     333                 :  *
     334                 :  * @param nBufYSize the height of the buffer image into which the desired region
     335                 :  * is to be read, or from which it is to be written.
     336                 :  *
     337                 :  * @param eBufType the type of the pixel values in the pData data buffer. The
     338                 :  * pixel values will automatically be translated to/from the
     339                 :  * PostGISRasterRasterBand data type as needed.
     340                 :  *
     341                 :  * @param nPixelSpace The byte offset from the start of one pixel value in pData
     342                 :  * to the start of the next pixel value within a scanline. If defaulted (0) the
     343                 :  * size of the datatype eBufType is used.
     344                 :  *
     345                 :  * @param nLineSpace The byte offset from the start of one scanline in pData to
     346                 :  * the start of the next. If defaulted (0) the size of the datatype
     347                 :  * eBufType * nBufXSize is used.
     348                 :  *
     349                 :  * @return CE_Failure if the access fails, otherwise CE_None.
     350                 :  */
     351                 : 
     352               0 : CPLErr PostGISRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     353                 :     int nXSize, int nYSize, void * pData, int nBufXSize, int nBufYSize,
     354                 :     GDALDataType eBufType, int nPixelSpace, int nLineSpace)
     355                 : {
     356                 :     double adfTransform[6];
     357                 :     double adfProjWin[8];
     358                 :     int ulx, uly, lrx, lry;
     359               0 :     CPLString osCommand;
     360               0 :     PGresult* poResult = NULL;
     361                 :     int iTuplesIndex;
     362               0 :     int nTuples = 0;
     363               0 :     GByte* pbyData = NULL;
     364               0 :     GByte** ppbyBandData = NULL;
     365               0 :     int nWKBLength = 0;
     366                 :     int nBandDataLength;
     367                 :     int nBandDataSize;
     368                 :     int nBufDataSize;
     369                 :     int nTileWidth;
     370                 :     int nTileHeight;
     371                 :     double dfTileScaleX;
     372                 :     double dfTileScaleY;
     373                 :     double dfTileUpperLeftX;
     374                 :     double dfTileUpperLeftY;
     375               0 :     char * pszDataType = NULL; 
     376                 :     GDALDataType eTileDataType;
     377                 :     int nTileDataTypeSize;
     378                 :     double dfTileBandNoDataValue;
     379                 :     VRTDatasetH vrtDataset;
     380                 :     GDALDataset ** memDatasets;
     381                 :     GDALRasterBandH memRasterBand;
     382                 :     GDALRasterBandH vrtRasterBand;
     383                 :     char szMemOpenInfo[100];
     384                 :     char szTmp[64];
     385                 :     char szTileWidth[64];
     386                 :     char szTileHeight[64];
     387                 :     CPLErr err;
     388               0 :     PostGISRasterDataset * poPostGISRasterDS = (PostGISRasterDataset*)poDS;
     389                 :     int nSrcXOff, nSrcYOff, nDstXOff, nDstYOff;
     390                 :     int nDstXSize, nDstYSize;
     391                 :     double xRes, yRes;
     392                 : 
     393                 :     /**
     394                 :      * TODO: Write support not implemented yet
     395                 :      **/
     396               0 :     if (eRWFlag == GF_Write) {
     397                 :         CPLError(CE_Failure, CPLE_NotSupported,
     398               0 :             "Writing through PostGIS Raster band not supported yet");
     399                 :         
     400               0 :         return CE_Failure;
     401                 :     }
     402                 :     
     403               0 :     nBandDataSize = GDALGetDataTypeSize(eDataType) / 8;
     404               0 :     nBufDataSize = GDALGetDataTypeSize( eBufType ) / 8;
     405                 :             
     406                 : 
     407                 :     /**************************************************************************
     408                 :      * Do we have overviews that would be appropriate to satisfy this request?                                                   
     409                 :      *************************************************************************/
     410               0 :     if( (nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0 ) {
     411                 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: "
     412                 :             "nBufXSize = %d, nBufYSize = %d, nXSize = %d, nYSize = %d "
     413               0 :             "- OverviewRasterIO call", nBufXSize, nBufYSize, nXSize, nYSize);
     414               0 :         if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, 
     415                 :             nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace ) == CE_None )
     416                 :                 
     417               0 :         return CE_None;
     418                 :     }
     419                 : 
     420                 :     /**************************************************************************
     421                 :      * Get all the raster rows that are intersected by the window requested
     422                 :      *************************************************************************/     
     423                 :     // We first construct a polygon to intersect with
     424               0 :     poPostGISRasterDS->GetGeoTransform(adfTransform);
     425               0 :     ulx = nXOff;
     426               0 :     uly = nYOff;
     427               0 :     lrx = nXOff + nXSize * nBandDataSize;
     428               0 :     lry = nYOff + nYSize * nBandDataSize;
     429                 : 
     430                 :     // Calculate right pixel resolution
     431                 :     xRes = (nOverviewFactor == 0) ? 
     432                 :         adfTransform[GEOTRSFRM_WE_RES] :
     433               0 :         adfTransform[GEOTRSFRM_WE_RES] * nOverviewFactor; 
     434                 :     
     435                 :     yRes = (nOverviewFactor == 0) ? 
     436                 :         adfTransform[GEOTRSFRM_NS_RES] :
     437               0 :         adfTransform[GEOTRSFRM_NS_RES] * nOverviewFactor; 
     438                 : 
     439               0 :     adfProjWin[0] = adfTransform[GEOTRSFRM_TOPLEFT_X] + 
     440                 :                     ulx * xRes + 
     441               0 :                     uly * adfTransform[GEOTRSFRM_ROTATION_PARAM1];
     442               0 :     adfProjWin[1] = adfTransform[GEOTRSFRM_TOPLEFT_Y] + 
     443               0 :                     ulx * adfTransform[GEOTRSFRM_ROTATION_PARAM2] + 
     444               0 :                     uly * yRes;
     445               0 :     adfProjWin[2] = adfTransform[GEOTRSFRM_TOPLEFT_X] + 
     446                 :                     lrx * xRes + 
     447               0 :                     uly * adfTransform[GEOTRSFRM_ROTATION_PARAM1];
     448               0 :     adfProjWin[3] = adfTransform[GEOTRSFRM_TOPLEFT_Y] + 
     449               0 :                     lrx * adfTransform[GEOTRSFRM_ROTATION_PARAM2] + 
     450               0 :                     uly * yRes;
     451               0 :     adfProjWin[4] = adfTransform[GEOTRSFRM_TOPLEFT_X] + 
     452                 :                     lrx * xRes + 
     453               0 :                     lry * adfTransform[GEOTRSFRM_ROTATION_PARAM1];
     454               0 :     adfProjWin[5] = adfTransform[GEOTRSFRM_TOPLEFT_Y] + 
     455               0 :                     lrx * adfTransform[GEOTRSFRM_ROTATION_PARAM2] + 
     456               0 :                     lry * yRes;
     457               0 :     adfProjWin[6] = adfTransform[GEOTRSFRM_TOPLEFT_X] + 
     458                 :                     ulx * xRes + 
     459               0 :                     lry * adfTransform[GEOTRSFRM_ROTATION_PARAM1];
     460               0 :     adfProjWin[7] = adfTransform[GEOTRSFRM_TOPLEFT_Y] + 
     461               0 :                     ulx * adfTransform[GEOTRSFRM_ROTATION_PARAM2] + 
     462               0 :                     lry * yRes;
     463                 : 
     464                 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: "
     465                 :         "Buffer size = (%d, %d), Region size = (%d, %d)",
     466               0 :         nBufXSize, nBufYSize, nXSize, nYSize);
     467                 : 
     468               0 :     if (poPostGISRasterDS->pszWhere == NULL) {
     469                 :         osCommand.Printf("SELECT st_band(%s, %d), st_width(%s), st_height(%s), st_bandpixeltype(%s, %d), "
     470                 :             "st_bandnodatavalue(%s, %d), st_scalex(%s), st_scaley(%s), st_upperleftx(%s), st_upperlefty(%s) "
     471                 :             "FROM %s.%s WHERE st_intersects(%s, st_polygonfromtext('POLYGON((%.17f %.17f, %.17f %.17f, "
     472                 :             "%.17f %.17f, %.17f %.17f, %.17f %.17f))', %d))", pszColumn, nBand, pszColumn, pszColumn, pszColumn, nBand, pszColumn, 
     473                 :             nBand, pszColumn, pszColumn, pszColumn, pszColumn, pszSchema, pszTable, pszColumn, 
     474                 :             adfProjWin[0], adfProjWin[1], adfProjWin[2], adfProjWin[3],  adfProjWin[4], adfProjWin[5], 
     475               0 :             adfProjWin[6], adfProjWin[7], adfProjWin[0], adfProjWin[1], poPostGISRasterDS->nSrid);
     476                 :     }
     477                 : 
     478                 :     else {
     479                 :         osCommand.Printf("SELECT st_band(%s, %d), st_width(%s), st_height(%s), st_bandpixeltype(%s, %d), "
     480                 :             "st_bandnodatavalue(%s, %d), st_scalex(%s), st_scaley(%s), st_upperleftx(%s), st_upperlefty(%s) "
     481                 :             "FROM %s.%s WHERE (%s) AND st_intersects(%s, st_polygonfromtext('POLYGON((%.17f %.17f, %.17f %.17f, "
     482                 :             "%.17f %.17f, %.17f %.17f, %.17f %.17f))', %d))", pszColumn, nBand, pszColumn, pszColumn, pszColumn, nBand, pszColumn, 
     483                 :             nBand, pszColumn, pszColumn, pszColumn, pszColumn, pszSchema, pszTable, poPostGISRasterDS->pszWhere, 
     484                 :             pszColumn, adfProjWin[0], adfProjWin[1], adfProjWin[2], adfProjWin[3], adfProjWin[4], adfProjWin[5], 
     485               0 :             adfProjWin[6], adfProjWin[7], adfProjWin[0], adfProjWin[1], poPostGISRasterDS->nSrid);
     486                 :     }
     487                 : 
     488               0 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): Query = %s", osCommand.c_str());
     489                 : 
     490               0 :     poResult = PQexec(poPostGISRasterDS->poConn, osCommand.c_str());
     491               0 :     if (poResult == NULL || PQresultStatus(poResult) != PGRES_TUPLES_OK || 
     492                 :         PQntuples(poResult) < 0) {
     493                 :         
     494               0 :         if (poResult)
     495               0 :             PQclear(poResult);
     496                 :  
     497               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Error retrieving raster data from database");
     498                 : 
     499                 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): %s", 
     500               0 :             PQerrorMessage(poPostGISRasterDS->poConn));
     501                 :         
     502               0 :         return CE_Failure;  
     503                 :     }
     504                 : 
     505                 :     /**
     506                 :      * No data. Return the buffer filled with nodata values
     507                 :      **/
     508               0 :     else if (PQntuples(poResult) == 0) {
     509               0 :         PQclear(poResult);
     510                 :         
     511               0 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): Null block");
     512                 : 
     513               0 :         memset(pData, dfNoDataValue, nBufDataSize * nBufXSize * nBufYSize);
     514                 : 
     515               0 :         return CE_None; 
     516                 :     }
     517                 :     
     518                 : 
     519               0 :     nTuples = PQntuples(poResult);
     520                 : 
     521                 :     /**************************************************************************
     522                 :      * Allocate memory for MEM dataset
     523                 :      * TODO: In case of memory error, provide a different alternative
     524                 :      *************************************************************************/
     525               0 :     memDatasets = (GDALDataset **)VSICalloc(nTuples, sizeof(GDALDataset *));
     526               0 :     if (!memDatasets) {
     527               0 :         PQclear(poResult);  
     528                 :         CPLError(CE_Failure, CPLE_AppDefined, "Memory error while trying to read band data "
     529               0 :             "from database");
     530                 : 
     531               0 :         return CE_Failure;
     532                 :     }
     533                 :     
     534                 : 
     535                 :     /**************************************************************************
     536                 :      * Create an empty in-memory VRT dataset
     537                 :      * TODO: In case of memory error, provide a different alternative
     538                 :      *************************************************************************/
     539               0 :     vrtDataset = VRTCreate(nXSize, nYSize);
     540               0 :     if (!vrtDataset) {
     541               0 :         PQclear(poResult);
     542               0 :         CPLFree(memDatasets);
     543                 : 
     544                 :         CPLError(CE_Failure, CPLE_AppDefined, "Memory error while trying to read band data "
     545               0 :             "from database");
     546                 : 
     547               0 :         return CE_Failure;
     548                 :     }
     549                 : 
     550                 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: VRT Dataset "
     551               0 :         "of (%d, %d) created", nXSize, nYSize);
     552                 :     
     553                 :     
     554                 :     // NOTE: Do NOT add a Dataset description, or the VRT file will be written to disk.
     555                 :     // This is a memory only dataset.
     556               0 :     GDALSetProjection(vrtDataset, GDALGetProjectionRef((GDALDatasetH)this->poDS));
     557               0 :     GDALSetGeoTransform(vrtDataset, adfTransform);
     558                 : 
     559                 : 
     560                 :     /**
     561                 :      * Create one VRT Raster Band. It will contain the same band of all tiles
     562                 :      * as Simple Sources
     563                 :      **/
     564               0 :     VRTAddBand(vrtDataset, eDataType, NULL);
     565               0 :     vrtRasterBand = GDALGetRasterBand(vrtDataset, 1);
     566                 :     
     567                 : 
     568                 :     /**
     569                 :      * Allocate memory for MEM data pointers
     570                 :      **/
     571               0 :     ppbyBandData = (GByte **)VSICalloc(nTuples, sizeof(GByte *));
     572               0 :     if (!ppbyBandData) {
     573               0 :         PQclear(poResult);
     574               0 :         CPLFree(memDatasets);
     575               0 :         GDALClose(vrtDataset);
     576                 : 
     577                 :         CPLError(CE_Failure, CPLE_AppDefined, "Memory error while trying to read band data "
     578               0 :             "from database");
     579                 :     
     580               0 :         return CE_Failure;
     581                 :     }
     582                 :     
     583                 :     /**************************************************************************
     584                 :      * Now, for each block, create a MEM dataset
     585                 :      * TODO: What if whe have a really BIG amount of data fetched from db? CURSORS
     586                 :      *************************************************************************/
     587               0 :     for(iTuplesIndex = 0; iTuplesIndex < nTuples; iTuplesIndex++) { 
     588                 :         /**
     589                 :          * Fetch data from result
     590                 :          **/
     591               0 :         pbyData = CPLHexToBinary(PQgetvalue(poResult, iTuplesIndex, 0), &nWKBLength);
     592               0 :         nTileWidth = atoi(PQgetvalue(poResult, iTuplesIndex, 1));
     593               0 :         nTileHeight = atoi(PQgetvalue(poResult, iTuplesIndex, 2));
     594               0 :         pszDataType = CPLStrdup(PQgetvalue(poResult, iTuplesIndex, 3));
     595               0 :         dfTileBandNoDataValue = atof(PQgetvalue(poResult, iTuplesIndex, 4));
     596               0 :         dfTileScaleX = atof(PQgetvalue(poResult, iTuplesIndex, 5));
     597               0 :         dfTileScaleY = atof(PQgetvalue(poResult, iTuplesIndex, 6));
     598               0 :         dfTileUpperLeftX = atof(PQgetvalue(poResult, iTuplesIndex, 7));
     599               0 :         dfTileUpperLeftY = atof(PQgetvalue(poResult, iTuplesIndex, 8));
     600                 : 
     601                 : 
     602                 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: Tile of "
     603                 :             "(%d, %d) px created. With pixel size of (%f, %f) and located at "
     604                 :             "(%f, %f)", nTileWidth, nTileHeight, dfTileScaleX, dfTileScaleY,
     605               0 :             dfTileUpperLeftX, dfTileUpperLeftY);
     606                 :             
     607                 :         /**
     608                 :          * Calculate some useful parameters
     609                 :          **/
     610               0 :         eTileDataType = TranslateDataType(pszDataType);
     611               0 :         nTileDataTypeSize = GDALGetDataTypeSize(eTileDataType) / 8;
     612                 :         
     613               0 :         nBandDataLength = nTileWidth * nTileHeight * nTileDataTypeSize;
     614               0 :         ppbyBandData[iTuplesIndex] = (GByte *)
     615               0 :             VSIMalloc(nBandDataLength * sizeof(GByte));
     616                 : 
     617               0 :         if (!ppbyBandData[iTuplesIndex]) {
     618                 :             CPLError(CE_Warning, CPLE_AppDefined, "Could not allocate memory for "
     619               0 :                 "MEMDataset, skipping. The result image may contain gaps");
     620               0 :             continue;
     621                 :         }
     622                 : 
     623                 :         /**
     624                 :          * Get the pointer to the band pixels
     625                 :          **/ 
     626               0 :         memcpy(ppbyBandData[iTuplesIndex], 
     627                 :             GET_BAND_DATA(pbyData, 1, nTileDataTypeSize, nBandDataLength),
     628               0 :             nBandDataLength);
     629                 :         
     630                 :         /**
     631                 :          * Create new MEM dataset, based on in-memory array, to hold the pixels.
     632                 :          * The dataset will only have 1 band
     633                 :          **/
     634               0 :         memset(szTmp, 0, sizeof(szTmp));
     635               0 :         CPLPrintPointer(szTmp, ppbyBandData[iTuplesIndex], sizeof(szTmp));
     636                 : 
     637               0 :         memset(szTileWidth, 0, sizeof(szTileWidth));
     638               0 :         CPLPrintInt32(szTileWidth, (GInt32)nTileWidth, sizeof(nTileWidth));
     639               0 :         memset(szTileHeight, 0, sizeof(szTileHeight));
     640               0 :         CPLPrintInt32(szTileHeight, (GInt32)nTileHeight, sizeof(nTileHeight));
     641                 :         
     642               0 :         memset(szMemOpenInfo, 0, sizeof(szMemOpenInfo));
     643                 :         sprintf(szMemOpenInfo, "MEM:::DATAPOINTER=%s,PIXELS=%d,LINES=%d,DATATYPE=%s",
     644               0 :             szTmp, nTileWidth, nTileHeight, GDALGetDataTypeName(eTileDataType));
     645                 :         
     646                 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: MEMDataset "
     647               0 :             "open info = %s", szMemOpenInfo);
     648                 : 
     649               0 :         GDALOpenInfo oOpenInfo(szMemOpenInfo, GA_ReadOnly, NULL);
     650                 :     
     651               0 :         memDatasets[iTuplesIndex] = MEMDataset::Open(&oOpenInfo);
     652               0 :         if (!memDatasets[iTuplesIndex]) {
     653                 :             CPLError(CE_Warning, CPLE_AppDefined, "Could not create MEMDataset, "
     654               0 :                 "skipping. The result image may contain gaps");
     655               0 :             continue;
     656                 :         }
     657                 :          
     658               0 :         GDALSetDescription(memDatasets[iTuplesIndex], szMemOpenInfo);
     659                 : 
     660                 :         /** 
     661                 :          * Get MEM raster band, to add it as simple source.
     662                 :          **/
     663               0 :         memRasterBand = (GDALRasterBandH)memDatasets[iTuplesIndex]->GetRasterBand(1);
     664               0 :         if (!memRasterBand) {
     665                 :             CPLError(CE_Warning, CPLE_AppDefined, "Could not get MEMRasterBand , "
     666               0 :                 "skipping. The result image may contain gaps");
     667               0 :             continue;
     668                 :         } 
     669                 :         
     670               0 :         ((MEMRasterBand *)memRasterBand)->SetNoDataValue(dfTileBandNoDataValue);
     671                 : 
     672                 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: Adding "
     673               0 :             "VRT Complex Source");
     674                 :         
     675                 :         /**
     676                 :          * Get source and destination windows for the simple source (first check source
     677                 :          * and destination bounding boxes match. Otherwise, skip this data)
     678                 :          **/ 
     679                 :         
     680               0 :         if (dfTileUpperLeftX + nTileWidth * dfTileScaleX < adfProjWin[0]) {
     681                 :             CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: "
     682                 :                 "dfTileUpperLeftX = %f, nTileWidth = %d, dfTileScaleX = %f, "
     683                 :                 "RasterDataset minx = %f", dfTileUpperLeftX, nTileWidth, dfTileScaleX,
     684               0 :                 adfProjWin[0]);
     685               0 :             continue;
     686                 :         }
     687                 : 
     688               0 :         if (dfTileUpperLeftX > adfProjWin[4]) {
     689                 :             CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: "
     690                 :                 "dfTileUpperLeftX = %f, RasterDataset maxx = %f", dfTileUpperLeftX, 
     691               0 :                 adfProjWin[4]);
     692               0 :             continue;
     693                 :         }   
     694                 : 
     695               0 :         if (dfTileUpperLeftY + nTileHeight * dfTileScaleY > adfProjWin[1]) {
     696                 :             CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: "
     697                 :                 "dfTileUpperLeftY = %f, nTileHeight = %d, ns res = %f, "
     698                 :                 "RasterDataset maxy = %f", dfTileUpperLeftY, nTileHeight, dfTileScaleY,
     699               0 :                 adfProjWin[1]);
     700               0 :             continue;
     701                 :         }
     702                 : 
     703               0 :         if (dfTileUpperLeftY < adfProjWin[5]) {
     704                 :             CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO: "
     705                 :                 "dfTileUpperLeftY = %f, RasterDataset miny = %f", dfTileUpperLeftY, 
     706               0 :                 adfProjWin[5]);
     707               0 :             continue;
     708                 :         }
     709                 :         
     710                 : 
     711               0 :         if (dfTileUpperLeftX < adfProjWin[0]) {
     712               0 :             nSrcXOff = (int)((adfProjWin[0] - dfTileUpperLeftX) / 
     713               0 :                 dfTileScaleX + 0.5);
     714               0 :             nDstXOff = 0;
     715                 :         }
     716                 : 
     717                 :         else {
     718               0 :             nSrcXOff = 0;
     719               0 :             nDstXOff = (int)(0.5 + (dfTileUpperLeftX - adfProjWin[0]) /     
     720               0 :                 xRes);
     721                 :         }
     722                 : 
     723               0 :         if (adfProjWin[1] < dfTileUpperLeftY) {
     724               0 :             nSrcYOff = (int)((dfTileUpperLeftY - adfProjWin[1]) / 
     725               0 :                 fabs(dfTileScaleY) + 0.5);
     726               0 :             nDstYOff = 0;
     727                 :         }
     728                 : 
     729                 :         else {
     730               0 :             nSrcYOff = 0;
     731               0 :             nDstYOff = (int)(0.5 + (adfProjWin[1] - dfTileUpperLeftY) / 
     732               0 :                 fabs(yRes));
     733                 :         }
     734                 : 
     735               0 :         nDstXSize = (int)(0.5 + nTileWidth * dfTileScaleX / xRes);
     736               0 :         nDstYSize = (int)(0.5 + nTileHeight * fabs(dfTileScaleY) / fabs(yRes));
     737                 :      
     738                 : 
     739                 :         /**
     740                 :          * Add the mem raster band as new complex source band (so, I can specify a nodata value)
     741                 :          **/
     742                 :         VRTAddComplexSource(vrtRasterBand, memRasterBand, nSrcXOff, nSrcYOff, nTileWidth, nTileHeight,
     743               0 :             nDstXOff, nDstYOff, nDstXSize, nDstYSize, 0, 1, dfTileBandNoDataValue);
     744                 : 
     745               0 :         CPLFree(pbyData);
     746               0 :         CPLFree(pszDataType);
     747                 :     
     748                 : 
     749               0 :         CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): VRT complex source added");
     750                 :     }
     751                 :  
     752               0 :     PQclear(poResult);
     753                 :     
     754               0 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): VRT dataset created");
     755                 : 
     756                 :     /**
     757                 :      * We've constructed the VRT Dataset based on the window requested. So, we always
     758                 :      * start from 0
     759                 :      **/
     760               0 :     nXOff = nYOff = 0;
     761                 : 
     762                 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): The window requested is "
     763                 :         "from (%d, %d) of size (%d, %d). Buffer of size (%d, %d)", nXOff, nYOff, 
     764               0 :         nXSize, nYSize, nBufXSize, nBufYSize);
     765                 : 
     766                 :     // Execute VRT RasterIO over the band
     767                 :     err = ((VRTRasterBand *)vrtRasterBand)->RasterIO(eRWFlag, nXOff, nYOff, nXSize, 
     768               0 :         nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace);
     769                 : 
     770               0 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): Data read");
     771                 : 
     772               0 :     GDALClose(vrtDataset);
     773                 :     
     774               0 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): VRTDataset released");
     775                 :     
     776                 :     // Free resources
     777               0 :     for(iTuplesIndex = 0; iTuplesIndex < nTuples; iTuplesIndex++) {
     778               0 :         if (ppbyBandData[iTuplesIndex])
     779               0 :             VSIFree(ppbyBandData[iTuplesIndex]);
     780               0 :         delete memDatasets[iTuplesIndex];
     781                 :         //GDALClose(memDatasets[iTuplesIndex]);
     782                 :     }
     783               0 :     VSIFree(ppbyBandData);
     784               0 :     VSIFree(memDatasets);
     785                 :     
     786               0 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IRasterIO(): MEMDatasets were released");
     787                 : 
     788               0 :     return err;
     789                 :         
     790                 : }
     791                 : 
     792                 : /**
     793                 :  * \brief Set the no data value for this band.
     794                 :  * Parameters:
     795                 :  *  - double: The nodata value
     796                 :  * Returns:
     797                 :  *  - CE_None.
     798                 :  */
     799               0 : CPLErr PostGISRasterRasterBand::SetNoDataValue(double dfNewValue) {
     800               0 :     dfNoDataValue = dfNewValue;
     801                 : 
     802               0 :     return CE_None;
     803                 : }
     804                 : 
     805                 : /**
     806                 :  * \brief Fetch the no data value for this band.
     807                 :  * Parameters:
     808                 :  *  - int *: pointer to a boolean to use to indicate if a value is actually
     809                 :  *          associated with this layer. May be NULL (default).
     810                 :  *  Returns:
     811                 :  *  - double: the nodata value for this band.
     812                 :  */
     813               0 : double PostGISRasterRasterBand::GetNoDataValue(int *pbSuccess) {
     814               0 :     if (pbSuccess != NULL)
     815               0 :         *pbSuccess = (int) bHasNoDataValue;
     816                 : 
     817               0 :     return dfNoDataValue;
     818                 : }
     819                 : 
     820                 : /***************************************************
     821                 :  * \brief Return the number of overview layers available
     822                 :  ***************************************************/
     823               0 : int PostGISRasterRasterBand::GetOverviewCount()
     824                 : {
     825                 :     return (nOverviewFactor) ?
     826                 :         0 :
     827               0 :         nOverviewCount;
     828                 : }
     829                 : 
     830                 : /**********************************************************
     831                 :  * \brief Fetch overview raster band object
     832                 :  **********************************************************/
     833               0 : GDALRasterBand * PostGISRasterRasterBand::GetOverview(int i)
     834                 : {
     835               0 :     return (i >= 0 && i < GetOverviewCount()) ? 
     836               0 :         (GDALRasterBand *)papoOverviews[i] : GDALRasterBand::GetOverview(i);
     837                 : }
     838                 : 
     839                 : /*****************************************************
     840                 :  * \brief Read a natural block of raster band data
     841                 :  *****************************************************/
     842               0 : CPLErr PostGISRasterRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void*
     843                 :         pImage)
     844                 : {
     845               0 :     int nPixelSize = GDALGetDataTypeSize(eDataType)/8;
     846                 :     int nReadXSize, nReadYSize;
     847                 : 
     848               0 :     if( (nBlockXOff+1) * nBlockXSize > GetXSize() )
     849               0 :         nReadXSize = GetXSize() - nBlockXOff * nBlockXSize;
     850                 :     else
     851               0 :         nReadXSize = nBlockXSize;
     852                 : 
     853               0 :     if( (nBlockYOff+1) * nBlockYSize > GetYSize() )
     854               0 :         nReadYSize = GetYSize() - nBlockYOff * nBlockYSize;
     855                 :     else
     856               0 :         nReadYSize = nBlockYSize;
     857                 : 
     858                 :     CPLDebug("PostGIS_Raster", "PostGISRasterRasterBand::IReadBlock: "
     859               0 :         "Calling to IRasterIO");
     860                 : 
     861                 :     return IRasterIO( GF_Read, 
     862                 :                       nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize, 
     863                 :                       nReadXSize, nReadYSize, 
     864                 :                       pImage, nReadXSize, nReadYSize, eDataType, 
     865               0 :                       nPixelSize, nPixelSize * nBlockXSize );
     866                 : }
     867                 : 
     868                 : /**
     869                 :  * \brief How should this band be interpreted as color?
     870                 :  * GCI_Undefined is returned when the format doesn't know anything about the 
     871                 :  * color interpretation. 
     872                 :  **/
     873               0 : GDALColorInterp PostGISRasterRasterBand::GetColorInterpretation()
     874                 : {
     875               0 :     return eBandInterp; 
     876                 : }

Generated by: LCOV version 1.7