LCOV - code coverage report
Current view: directory - alg - gdalcutline.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 103 92 89.3 %
Date: 2010-01-09 Functions: 3 3 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdalcutline.cpp 17041 2009-05-17 22:35:15Z warmerdam $
       3                 :  *
       4                 :  * Project:  High Performance Image Reprojector
       5                 :  * Purpose:  Implement cutline/blend mask generator.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2008, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdalwarper.h"
      31                 : #include "gdal_alg.h"
      32                 : #include "ogr_api.h"
      33                 : #include "ogr_geos.h"
      34                 : #include "ogr_geometry.h"
      35                 : #include "cpl_string.h"
      36                 : 
      37                 : CPL_CVSID("$Id: gdalcutline.cpp 17041 2009-05-17 22:35:15Z warmerdam $");
      38                 : 
      39                 : /************************************************************************/
      40                 : /*                         BlendMaskGenerator()                         */
      41                 : /************************************************************************/
      42                 : 
      43                 : static CPLErr
      44               1 : BlendMaskGenerator( int nXOff, int nYOff, int nXSize, int nYSize, 
      45                 :                     GByte *pabyPolyMask, float *pafValidityMask,
      46                 :                     OGRGeometryH hPolygon, double dfBlendDist )
      47                 : 
      48                 : {
      49                 : #ifndef HAVE_GEOS 
      50                 :     CPLError( CE_Failure, CPLE_AppDefined, 
      51                 :               "Blend distance support not available without the GEOS library.");
      52                 :     return CE_Failure;
      53                 : 
      54                 : #else /* HAVE_GEOS */
      55                 : 
      56                 : /* -------------------------------------------------------------------- */
      57                 : /*      Convert the polygon into a collection of lines so that we       */
      58                 : /*      measure distance from the edge even on the inside.              */
      59                 : /* -------------------------------------------------------------------- */
      60                 :     OGRGeometry *poLines
      61                 :         = OGRGeometryFactory::forceToMultiLineString( 
      62               1 :             ((OGRGeometry *) hPolygon)->clone() );
      63                 : 
      64                 : /* -------------------------------------------------------------------- */
      65                 : /*      Prepare a clipping polygon a bit bigger than the area of        */
      66                 : /*      interest in the hopes of simplifying the cutline down to        */
      67                 : /*      stuff that will be relavent for this area of interest.          */
      68                 : /* -------------------------------------------------------------------- */
      69               1 :     CPLString osClipRectWKT;
      70                 : 
      71                 :     osClipRectWKT.Printf( "POLYGON((%g %g,%g %g,%g %g,%g %g,%g %g))", 
      72                 :                           nXOff - (dfBlendDist+1), 
      73                 :                           nYOff - (dfBlendDist+1), 
      74                 :                           nXOff + nXSize + (dfBlendDist+1), 
      75                 :                           nYOff - (dfBlendDist+1), 
      76                 :                           nXOff + nXSize + (dfBlendDist+1), 
      77                 :                           nYOff + nYSize + (dfBlendDist+1), 
      78                 :                           nXOff - (dfBlendDist+1), 
      79                 :                           nYOff + nYSize + (dfBlendDist+1), 
      80                 :                           nXOff - (dfBlendDist+1), 
      81               1 :                           nYOff - (dfBlendDist+1) );
      82                 :     
      83               1 :     OGRPolygon *poClipRect = NULL;
      84               1 :     char *pszWKT = (char *) osClipRectWKT.c_str();
      85                 :     
      86                 :     OGRGeometryFactory::createFromWkt( &pszWKT, NULL, 
      87               1 :                                        (OGRGeometry**) (&poClipRect) );
      88                 : 
      89               1 :     if( poClipRect )
      90                 :     {
      91                 :         OGRGeometry *poClippedLines = 
      92               1 :             poLines->Intersection( poClipRect );
      93               1 :         delete poLines;
      94               1 :         poLines = poClippedLines;
      95               1 :         delete poClipRect;
      96                 :     }
      97                 : 
      98                 : /* -------------------------------------------------------------------- */
      99                 : /*      Convert our polygon into GEOS format, and compute an            */
     100                 : /*      envelope to accelerate later distance operations.               */
     101                 : /* -------------------------------------------------------------------- */
     102               1 :     OGREnvelope sEnvelope;
     103                 :     int iXMin, iYMin, iXMax, iYMax;
     104                 :     GEOSGeom poGEOSPoly;
     105                 : 
     106               1 :     poGEOSPoly = poLines->exportToGEOS();
     107               1 :     OGR_G_GetEnvelope( hPolygon, &sEnvelope );
     108                 : 
     109               1 :     delete poLines;
     110                 : 
     111               1 :     if( sEnvelope.MinY - dfBlendDist > nYOff+nYSize 
     112                 :         || sEnvelope.MaxY + dfBlendDist < nYOff 
     113                 :         || sEnvelope.MinX - dfBlendDist > nXOff+nXSize
     114                 :         || sEnvelope.MaxX + dfBlendDist < nXOff )
     115               0 :         return CE_None;
     116                 :     
     117               1 :     iXMin = MAX(0,(int) floor(sEnvelope.MinX - dfBlendDist - nXOff));
     118               1 :     iXMax = MIN(nXSize, (int) ceil(sEnvelope.MaxX + dfBlendDist - nXOff));
     119               1 :     iYMin = MAX(0,(int) floor(sEnvelope.MinY - dfBlendDist - nYOff));
     120               1 :     iYMax = MIN(nYSize, (int) ceil(sEnvelope.MaxY + dfBlendDist - nYOff));
     121                 : 
     122                 : /* -------------------------------------------------------------------- */
     123                 : /*      Loop over potential area within blend line distance,            */
     124                 : /*      processing each pixel.                                          */
     125                 : /* -------------------------------------------------------------------- */
     126                 :     int iY, iX;
     127                 :     double dfLastDist;
     128                 :     
     129             101 :     for( iY = 0; iY < nYSize; iY++ )
     130                 :     {
     131             100 :         dfLastDist = 0.0;
     132                 : 
     133             100 :         for( iX = 0; iX < nXSize; iX++ )
     134                 :         {
     135           10000 :             if( iX < iXMin || iX >= iXMax
     136                 :                 || iY < iYMin || iY > iYMax
     137                 :                 || dfLastDist > dfBlendDist + 1.5 )
     138                 :             {
     139            7944 :                 if( pabyPolyMask[iX + iY * nXSize] == 0 )
     140            7784 :                     pafValidityMask[iX + iY * nXSize] = 0.0;
     141                 : 
     142            7944 :                 dfLastDist -= 1.0;
     143            7944 :                 continue;
     144                 :             }
     145                 :             
     146                 :             double dfDist, dfRatio;
     147            2056 :             CPLString osPointWKT;
     148                 :             GEOSGeom poGEOSPoint;
     149                 : 
     150            2056 :             osPointWKT.Printf( "POINT(%d.5 %d.5)", iX + nXOff, iY + nYOff );
     151            2056 :             poGEOSPoint = GEOSGeomFromWKT( osPointWKT );
     152                 : 
     153            2056 :             GEOSDistance( poGEOSPoly, poGEOSPoint, &dfDist );
     154            2056 :             GEOSGeom_destroy( poGEOSPoint );
     155                 : 
     156            2056 :             dfLastDist = dfDist;
     157                 : 
     158            2056 :             if( dfDist > dfBlendDist )
     159                 :             {
     160             584 :                 if( pabyPolyMask[iX + iY * nXSize] == 0 )
     161             366 :                     pafValidityMask[iX + iY * nXSize] = 0.0;
     162                 : 
     163             584 :                 continue;
     164                 :             }
     165                 : 
     166            1472 :             if( pabyPolyMask[iX + iY * nXSize] == 0 )
     167                 :             {
     168                 :                 /* outside */
     169             850 :                 dfRatio = 0.5 - (dfDist / dfBlendDist) * 0.5;
     170                 :             }
     171                 :             else 
     172                 :             {
     173                 :                 /* inside */
     174             622 :                 dfRatio = 0.5 + (dfDist / dfBlendDist) * 0.5;
     175                 :             }                
     176                 : 
     177            1472 :             pafValidityMask[iX + iY * nXSize] *= dfRatio;
     178                 :         }
     179                 :     }
     180                 : 
     181                 : /* -------------------------------------------------------------------- */
     182                 : /*      Cleanup                                                         */
     183                 : /* -------------------------------------------------------------------- */
     184               1 :     GEOSGeom_destroy( poGEOSPoly );
     185                 : 
     186               1 :     return CE_None;
     187                 : 
     188                 : #endif /* HAVE_GEOS */
     189                 : }
     190                 : 
     191                 : /************************************************************************/
     192                 : /*                         CutlineTransformer()                         */
     193                 : /*                                                                      */
     194                 : /*      A simple transformer for the cutline that just offsets          */
     195                 : /*      relative to the current chunk.                                  */
     196                 : /************************************************************************/
     197                 : 
     198               6 : static int CutlineTransformer( void *pTransformArg, int bDstToSrc, 
     199                 :                                int nPointCount, 
     200                 :                                double *x, double *y, double *z, 
     201                 :                                int *panSuccess )
     202                 : 
     203                 : {
     204               6 :     int nXOff = ((int *) pTransformArg)[0];
     205               6 :     int nYOff = ((int *) pTransformArg)[1];       
     206                 :     int i;
     207                 : 
     208               6 :     if( bDstToSrc )
     209                 :     {
     210               0 :         nXOff *= -1;
     211               0 :         nYOff *= -1;
     212                 :     }
     213                 : 
     214              43 :     for( i = 0; i < nPointCount; i++ )
     215                 :     {
     216              37 :         x[i] -= nXOff;
     217              37 :         y[i] -= nYOff;
     218                 :     }
     219                 :     
     220               6 :     return TRUE;
     221                 : }
     222                 : 
     223                 : 
     224                 : /************************************************************************/
     225                 : /*                       GDALWarpCutlineMasker()                        */
     226                 : /*                                                                      */
     227                 : /*      This function will generate a source mask based on a            */
     228                 : /*      provided cutline, and optional blend distance.                  */
     229                 : /************************************************************************/
     230                 : 
     231                 : CPLErr 
     232               6 : GDALWarpCutlineMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
     233                 :                        int nXOff, int nYOff, int nXSize, int nYSize,
     234                 :                        GByte ** /*ppImageData */,
     235                 :                        int bMaskIsFloat, void *pValidityMask )
     236                 : 
     237                 : {
     238               6 :     GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
     239               6 :     float *pafMask = (float *) pValidityMask;
     240                 :     CPLErr eErr;
     241                 :     GDALDriverH hMemDriver;
     242                 : 
     243               6 :     if( nXSize < 1 || nYSize < 1 )
     244               0 :         return CE_None;
     245                 : 
     246                 : /* -------------------------------------------------------------------- */
     247                 : /*      Do some minimal checking.                                       */
     248                 : /* -------------------------------------------------------------------- */
     249               6 :     if( !bMaskIsFloat )
     250                 :     {
     251                 :         CPLAssert( FALSE );
     252               0 :         return CE_Failure;
     253                 :     }
     254                 : 
     255               6 :     if( psWO == NULL || psWO->hCutline == NULL )
     256                 :     {
     257                 :         CPLAssert( FALSE );
     258               0 :         return CE_Failure;
     259                 :     }
     260                 : 
     261               6 :     hMemDriver = GDALGetDriverByName("MEM");
     262               6 :     if (hMemDriver == NULL)
     263                 :     {
     264               0 :         CPLError(CE_Failure, CPLE_AppDefined, "GDALWarpCutlineMasker needs MEM driver");
     265               0 :         return CE_Failure;
     266                 :     }
     267                 : 
     268                 : /* -------------------------------------------------------------------- */
     269                 : /*      Check the polygon.                                              */
     270                 : /* -------------------------------------------------------------------- */
     271               6 :     OGRGeometryH hPolygon = (OGRGeometryH) psWO->hCutline;
     272               6 :     OGREnvelope  sEnvelope;
     273                 : 
     274               6 :     if( wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbPolygon
     275                 :         && wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbMultiPolygon )
     276                 :     {
     277                 :         CPLAssert( FALSE );
     278               0 :         return CE_Failure;
     279                 :     }
     280                 : 
     281               6 :     OGR_G_GetEnvelope( hPolygon, &sEnvelope );
     282               6 :     if( sEnvelope.MaxX + psWO->dfCutlineBlendDist < nXOff
     283                 :         || sEnvelope.MinX - psWO->dfCutlineBlendDist > nXOff + nXSize
     284                 :         || sEnvelope.MaxY + psWO->dfCutlineBlendDist < nYOff
     285                 :         || sEnvelope.MinY - psWO->dfCutlineBlendDist > nYOff + nYSize )
     286                 :     {
     287                 :         // We are far from the blend line - everything is masked to zero.
     288                 :         // It would be nice to realize no work is required for this whole
     289                 :         // chunk!
     290               0 :         memset( pafMask, 0, sizeof(float) * nXSize * nYSize );
     291               0 :         return CE_None;
     292                 :     }
     293                 : 
     294                 : /* -------------------------------------------------------------------- */
     295                 : /*      Create a byte buffer into which we can burn the                 */
     296                 : /*      mask polygon and wrap it up as a memory dataset.                */
     297                 : /* -------------------------------------------------------------------- */
     298               6 :     GByte *pabyPolyMask = (GByte *) CPLCalloc( nXSize, nYSize );
     299                 :     GDALDatasetH hMemDS;
     300               6 :     double adfGeoTransform[6] = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
     301                 : 
     302                 :     char szDataPointer[100];
     303               6 :     char *apszOptions[] = { szDataPointer, NULL };
     304                 : 
     305               6 :     memset( szDataPointer, 0, sizeof(szDataPointer) );
     306               6 :     sprintf( szDataPointer, "DATAPOINTER=" );
     307                 :     CPLPrintPointer( szDataPointer+strlen(szDataPointer), 
     308                 :                     pabyPolyMask, 
     309               6 :                      sizeof(szDataPointer) - strlen(szDataPointer) );
     310                 : 
     311                 :     hMemDS = GDALCreate( hMemDriver, "warp_temp", 
     312               6 :                          nXSize, nYSize, 0, GDT_Byte, NULL );
     313               6 :     GDALAddBand( hMemDS, GDT_Byte, apszOptions );
     314               6 :     GDALSetGeoTransform( hMemDS, adfGeoTransform );
     315                 : 
     316                 : /* -------------------------------------------------------------------- */
     317                 : /*      Burn the polygon into the mask with 1.0 values.                 */
     318                 : /* -------------------------------------------------------------------- */
     319               6 :     int nTargetBand = 1;
     320               6 :     double dfBurnValue = 255.0;
     321                 :     int    anXYOff[2];
     322               6 :     char   **papszRasterizeOptions = NULL;
     323                 :     
     324                 : 
     325               6 :     if( CSLFetchBoolean( psWO->papszWarpOptions, "CUTLINE_ALL_TOUCHED", FALSE ))
     326                 :         papszRasterizeOptions = 
     327               1 :             CSLSetNameValue( papszRasterizeOptions, "ALL_TOUCHED", "TRUE" );
     328                 : 
     329               6 :     anXYOff[0] = nXOff;
     330               6 :     anXYOff[1] = nYOff;
     331                 : 
     332                 :     eErr = 
     333                 :         GDALRasterizeGeometries( hMemDS, 1, &nTargetBand, 
     334                 :                                  1, &hPolygon, 
     335                 :                                  CutlineTransformer, anXYOff, 
     336                 :                                  &dfBurnValue, papszRasterizeOptions, 
     337               6 :                                  NULL, NULL );
     338                 : 
     339               6 :     CSLDestroy( papszRasterizeOptions );
     340                 : 
     341                 :     // Close and ensure data flushed to underlying array.
     342               6 :     GDALClose( hMemDS );
     343                 : 
     344                 : /* -------------------------------------------------------------------- */
     345                 : /*      In the case with no blend distance, we just apply this as a     */
     346                 : /*      mask, zeroing out everything outside the polygon.               */
     347                 : /* -------------------------------------------------------------------- */
     348               6 :     if( psWO->dfCutlineBlendDist == 0.0 )
     349                 :     {
     350                 :         int i;
     351                 : 
     352           50005 :         for( i = nXSize * nYSize - 1; i >= 0; i-- )
     353                 :         {
     354           50000 :             if( pabyPolyMask[i] == 0 )
     355           41931 :                 ((float *) pValidityMask)[i] = 0.0;
     356                 :         }
     357                 :     }
     358                 :     else
     359                 :     {
     360                 :         eErr = BlendMaskGenerator( nXOff, nYOff, nXSize, nYSize, 
     361                 :                                    pabyPolyMask, (float *) pValidityMask,
     362               1 :                                    hPolygon, psWO->dfCutlineBlendDist );
     363                 :     }
     364                 : 
     365                 : /* -------------------------------------------------------------------- */
     366                 : /*      Clean up.                                                       */
     367                 : /* -------------------------------------------------------------------- */
     368               6 :     CPLFree( pabyPolyMask );
     369                 : 
     370               6 :     return eErr;
     371                 : }
     372                 : 

Generated by: LCOV version 1.7