LCOV - code coverage report
Current view: directory - apps - gdaldem.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1140 827 72.5 %
Date: 2013-03-30 Functions: 53 33 62.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdaldem.cpp 25582 2013-01-29 21:13:43Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL DEM Utilities
       5                 :  * Purpose:  
       6                 :  * Authors:  Matthew Perry, perrygeo at gmail.com
       7                 :  *           Even Rouault, even dot rouault at mines dash paris dot org
       8                 :  *           Howard Butler, hobu.inc at gmail.com
       9                 :  *           Chris Yesson, chris dot yesson at ioz dot ac dot uk
      10                 :  *
      11                 :  ******************************************************************************
      12                 :  * Copyright (c) 2006, 2009 Matthew Perry 
      13                 :  * Copyright (c) 2009 Even Rouault
      14                 :  * Portions derived from GRASS 4.1 (public domain) See 
      15                 :  * http://trac.osgeo.org/gdal/ticket/2975 for more information regarding 
      16                 :  * history of this code
      17                 :  *
      18                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      19                 :  * copy of this software and associated documentation files (the "Software"),
      20                 :  * to deal in the Software without restriction, including without limitation
      21                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      22                 :  * and/or sell copies of the Software, and to permit persons to whom the
      23                 :  * Software is furnished to do so, subject to the following conditions:
      24                 :  *
      25                 :  * The above copyright notice and this permission notice shall be included
      26                 :  * in all copies or substantial portions of the Software.
      27                 :  *
      28                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      29                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      30                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      31                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      32                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      33                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      34                 :  * DEALINGS IN THE SOFTWARE.
      35                 :  ****************************************************************************
      36                 :  *
      37                 :  * Slope and aspect calculations based on original method for GRASS GIS 4.1
      38                 :  * by Michael Shapiro, U.S.Army Construction Engineering Research Laboratory
      39                 :  *    Olga Waupotitsch, U.S.Army Construction Engineering Research Laboratory
      40                 :  *    Marjorie Larson, U.S.Army Construction Engineering Research Laboratory
      41                 :  * as found in GRASS's r.slope.aspect module.
      42                 :  *
      43                 :  * Horn's formula is used to find the first order derivatives in x and y directions
      44                 :  * for slope and aspect calculations: Horn, B. K. P. (1981).
      45                 :  * "Hill Shading and the Reflectance Map", Proceedings of the IEEE, 69(1):14-47. 
      46                 :  *
      47                 :  * Other reference :
      48                 :  * Burrough, P.A. and McDonell, R.A., 1998. Principles of Geographical Information
      49                 :  * Systems. p. 190.
      50                 :  *
      51                 :  * Shaded relief based on original method for GRASS GIS 4.1 by Jim Westervelt,
      52                 :  * U.S. Army Construction Engineering Research Laboratory
      53                 :  * as found in GRASS's r.shaded.relief (formerly shade.rel.sh) module.
      54                 :  * ref: "r.mapcalc: An Algebra for GIS and Image Processing",
      55                 :  * by Michael Shapiro and Jim Westervelt, U.S. Army Construction Engineering
      56                 :  * Research Laboratory (March/1991)
      57                 :  *
      58                 :  * Color table of named colors and lookup code derived from src/libes/gis/named_colr.c
      59                 :  * of GRASS 4.1
      60                 :  *
      61                 :  * TRI - Terrain Ruggedness Index is as descibed in Wilson et al (2007)
      62                 :  * this is based on the method of Valentine et al. (2004)  
      63                 :  * 
      64                 :  * TPI - Topographic Position Index follows the description in Wilson et al (2007), following Weiss (2001)
      65                 :  * The radius is fixed at 1 cell width/height
      66                 :  * 
      67                 :  * Roughness - follows the definition in Wilson et al. (2007), which follows Dartnell (2000)
      68                 :  *
      69                 :  * References for TRI/TPI/Roughness:
      70                 :  * Dartnell, P. 2000. Applying Remote Sensing Techniques to map Seafloor 
      71                 :  *  Geology/Habitat Relationships. Masters Thesis, San Francisco State 
      72                 :  *  University, pp. 108.
      73                 :  * Valentine, P. C., S. J. Fuller, L. A. Scully. 2004. Terrain Ruggedness 
      74                 :  *  Analysis and Distribution of Boulder Ridges in the Stellwagen Bank National
      75                 :  *  Marine Sanctuary Region (poster). Galway, Ireland: 5th International 
      76                 :  *  Symposium on Marine Geological and Biological Habitat Mapping (GeoHAB), 
      77                 :  *  May 2004.
      78                 :  * Weiss, A. D. 2001. Topographic Positions and Landforms Analysis (poster), 
      79                 :  *  ESRI International User Conference, July 2001. San Diego, CA: ESRI.
      80                 :  * Wilson, M. F. J.; O'Connell, B.; Brown, C.; Guinan, J. C. & Grehan, A. J. 
      81                 :  *  Multiscale terrain analysis of multibeam bathymetry data for habitat mapping
      82                 :  *  on the continental slope Marine Geodesy, 2007, 30, 3-35
      83                 :  ****************************************************************************/
      84                 : 
      85                 : #include <stdlib.h>
      86                 : #include <math.h>
      87                 : 
      88                 : #include "cpl_conv.h"
      89                 : #include "cpl_string.h"
      90                 : #include "gdal.h"
      91                 : #include "gdal_priv.h"
      92                 : #include "commonutils.h"
      93                 : 
      94                 : CPL_CVSID("$Id: gdaldem.cpp 25582 2013-01-29 21:13:43Z rouault $");
      95                 : 
      96                 : #ifndef M_PI
      97                 : # define M_PI  3.1415926535897932384626433832795
      98                 : #endif
      99                 : 
     100                 : #define INTERPOL(a,b) ((bSrcHasNoData && (ARE_REAL_EQUAL(a, fSrcNoDataValue) || ARE_REAL_EQUAL(b, fSrcNoDataValue))) ? fSrcNoDataValue : 2 * (a) - (b))
     101                 : 
     102                 : /************************************************************************/
     103                 : /*                               Usage()                                */
     104                 : /************************************************************************/
     105                 : 
     106               0 : static void Usage(const char* pszErrorMsg = NULL)
     107                 : 
     108                 : {
     109                 :     printf( " Usage: \n"
     110                 :             " - To generate a shaded relief map from any GDAL-supported elevation raster : \n\n"
     111                 :             "     gdaldem hillshade input_dem output_hillshade \n"
     112                 :             "                 [-z ZFactor (default=1)] [-s scale* (default=1)] \n"
     113                 :             "                 [-az Azimuth (default=315)] [-alt Altitude (default=45)]\n"
     114                 :             "                 [-alg ZevenbergenThorne] [-combined]\n"
     115                 :             "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
     116                 :             "\n"
     117                 :             " - To generates a slope map from any GDAL-supported elevation raster :\n\n"
     118                 :             "     gdaldem slope input_dem output_slope_map \n"
     119                 :             "                 [-p use percent slope (default=degrees)] [-s scale* (default=1)]\n"
     120                 :             "                 [-alg ZevenbergenThorne]\n"
     121                 :             "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
     122                 :             "\n"
     123                 :             " - To generate an aspect map from any GDAL-supported elevation raster\n"
     124                 :             "   Outputs a 32-bit float tiff with pixel values from 0-360 indicating azimuth :\n\n"
     125                 :             "     gdaldem aspect input_dem output_aspect_map \n"
     126                 :             "                 [-trigonometric] [-zero_for_flat]\n"
     127                 :             "                 [-alg ZevenbergenThorne]\n"
     128                 :             "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
     129                 :             "\n"
     130                 :             " - To generate a color relief map from any GDAL-supported elevation raster\n"
     131                 :             "     gdaldem color-relief input_dem color_text_file output_color_relief_map\n"
     132                 :             "                 [-alpha] [-exact_color_entry | -nearest_color_entry]\n"
     133                 :             "                 [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
     134                 :             "     where color_text_file contains lines of the format \"elevation_value red green blue\"\n"
     135                 :             "\n"
     136                 :             " - To generate a Terrain Ruggedness Index (TRI) map from any GDAL-supported elevation raster\n"
     137                 :             "     gdaldem TRI input_dem output_TRI_map\n"
     138                 :             "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
     139                 :             "\n"
     140                 :             " - To generate a Topographic Position Index (TPI) map from any GDAL-supported elevation raster\n"
     141                 :             "     gdaldem TPI input_dem output_TPI_map\n"
     142                 :             "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
     143                 :             "\n"
     144                 :             " - To generate a roughness map from any GDAL-supported elevation raster\n"
     145                 :             "     gdaldem roughness input_dem output_roughness_map\n"
     146                 :             "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
     147                 :             "\n"
     148                 :             " Notes : \n"
     149                 :             "   Scale is the ratio of vertical units to horizontal\n"
     150               0 :             "    for Feet:Latlong use scale=370400, for Meters:LatLong use scale=111120 \n\n");
     151                 : 
     152               0 :     if( pszErrorMsg != NULL )
     153               0 :         fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
     154                 : 
     155               0 :     exit( 1 );
     156                 : }
     157                 : 
     158                 : /************************************************************************/
     159                 : /*                          ComputeVal()                                */
     160                 : /************************************************************************/
     161                 : 
     162                 : typedef float (*GDALGeneric3x3ProcessingAlg) (float* pafWindow, float fDstNoDataValue, void* pData);
     163                 : 
     164          109691 : static float ComputeVal(int bSrcHasNoData, float fSrcNoDataValue,
     165                 :                         float* afWin, float fDstNoDataValue,
     166                 :                         GDALGeneric3x3ProcessingAlg pfnAlg,
     167                 :                         void* pData,
     168                 :                         int bComputeAtEdges)
     169                 : {
     170          109691 :     if (bSrcHasNoData && ARE_REAL_EQUAL(afWin[4], fSrcNoDataValue))
     171                 :     {
     172               0 :         return fDstNoDataValue;
     173                 :     }
     174          109691 :     else if (bSrcHasNoData)
     175                 :     {
     176                 :         int k;
     177         1000870 :         for(k=0;k<9;k++)
     178                 :         {
     179          900783 :             if (ARE_REAL_EQUAL(afWin[k], fSrcNoDataValue))
     180                 :             {
     181               0 :                 if (bComputeAtEdges)
     182               0 :                     afWin[k] = afWin[4];
     183                 :                 else
     184               0 :                     return fDstNoDataValue;
     185                 :             }
     186                 :         }
     187                 :     }
     188                 : 
     189          109691 :     return pfnAlg(afWin, fDstNoDataValue, pData);
     190                 : }
     191                 : 
     192                 : /************************************************************************/
     193                 : /*                  GDALGeneric3x3Processing()                          */
     194                 : /************************************************************************/
     195                 : 
     196               6 : CPLErr GDALGeneric3x3Processing  ( GDALRasterBandH hSrcBand,
     197                 :                                    GDALRasterBandH hDstBand,
     198                 :                                    GDALGeneric3x3ProcessingAlg pfnAlg,
     199                 :                                    void* pData,
     200                 :                                    int bComputeAtEdges,
     201                 :                                    GDALProgressFunc pfnProgress,
     202                 :                                    void * pProgressData)
     203                 : {
     204                 :     CPLErr eErr;
     205                 :     float *pafThreeLineWin; /* 3 line rotating source buffer */
     206                 :     float *pafOutputBuf;     /* 1 line destination buffer */
     207                 :     int i, j;
     208                 : 
     209                 :     int bSrcHasNoData, bDstHasNoData;
     210               6 :     float fSrcNoDataValue = 0.0, fDstNoDataValue = 0.0;
     211                 : 
     212               6 :     int nXSize = GDALGetRasterBandXSize(hSrcBand);
     213               6 :     int nYSize = GDALGetRasterBandYSize(hSrcBand);
     214                 : 
     215               6 :     if (pfnProgress == NULL)
     216               0 :         pfnProgress = GDALDummyProgress;
     217                 : 
     218                 : /* -------------------------------------------------------------------- */
     219                 : /*      Initialize progress counter.                                    */
     220                 : /* -------------------------------------------------------------------- */
     221               6 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
     222                 :     {
     223               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     224               0 :         return CE_Failure;
     225                 :     }
     226                 : 
     227               6 :     pafOutputBuf = (float *) CPLMalloc(sizeof(float)*nXSize);
     228               6 :     pafThreeLineWin  = (float *) CPLMalloc(3*sizeof(float)*(nXSize+1));
     229                 : 
     230               6 :     fSrcNoDataValue = (float) GDALGetRasterNoDataValue(hSrcBand, &bSrcHasNoData);
     231               6 :     fDstNoDataValue = (float) GDALGetRasterNoDataValue(hDstBand, &bDstHasNoData);
     232               6 :     if (!bDstHasNoData)
     233               0 :         fDstNoDataValue = 0.0;
     234                 : 
     235                 :     // Move a 3x3 pafWindow over each cell 
     236                 :     // (where the cell in question is #4)
     237                 :     // 
     238                 :     //      0 1 2
     239                 :     //      3 4 5
     240                 :     //      6 7 8
     241                 : 
     242                 :     /* Preload the first 2 lines */
     243              18 :     for ( i = 0; i < 2 && i < nYSize; i++)
     244                 :     {
     245                 :         GDALRasterIO(   hSrcBand,
     246                 :                         GF_Read,
     247                 :                         0, i,
     248                 :                         nXSize, 1,
     249                 :                         pafThreeLineWin + i * nXSize,
     250                 :                         nXSize, 1,
     251                 :                         GDT_Float32,
     252              12 :                         0, 0);
     253                 :     }
     254                 :     
     255               7 :     if (bComputeAtEdges && nXSize >= 2 && nYSize >= 2)
     256                 :     {
     257             122 :         for (j = 0; j < nXSize; j++)
     258                 :         {
     259                 :             float afWin[9];
     260             121 :             int jmin = (j == 0) ? j : j - 1;
     261             121 :             int jmax = (j == nXSize - 1) ? j : j + 1;
     262                 : 
     263             121 :             afWin[0] = INTERPOL(pafThreeLineWin[jmin], pafThreeLineWin[nXSize + jmin]);
     264             121 :             afWin[1] = INTERPOL(pafThreeLineWin[j],    pafThreeLineWin[nXSize + j]);
     265             121 :             afWin[2] = INTERPOL(pafThreeLineWin[jmax], pafThreeLineWin[nXSize + jmax]);
     266             121 :             afWin[3] = pafThreeLineWin[jmin];
     267             121 :             afWin[4] = pafThreeLineWin[j];
     268             121 :             afWin[5] = pafThreeLineWin[jmax];
     269             121 :             afWin[6] = pafThreeLineWin[nXSize + jmin];
     270             121 :             afWin[7] = pafThreeLineWin[nXSize + j];
     271             121 :             afWin[8] = pafThreeLineWin[nXSize + jmax];
     272                 : 
     273             121 :             pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
     274                 :                                          afWin, fDstNoDataValue,
     275             121 :                                          pfnAlg, pData, bComputeAtEdges);
     276                 :         }
     277                 :         GDALRasterIO(hDstBand, GF_Write,
     278                 :                     0, 0, nXSize, 1,
     279               1 :                     pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
     280                 :     }
     281                 :     else
     282                 :     {
     283                 :         // Exclude the edges
     284             589 :         for (j = 0; j < nXSize; j++)
     285                 :         {
     286             584 :             pafOutputBuf[j] = fDstNoDataValue;
     287                 :         }
     288                 :         GDALRasterIO(hDstBand, GF_Write,
     289                 :                     0, 0, nXSize, 1,
     290               5 :                     pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
     291                 :     
     292               5 :         if (nYSize > 1)
     293                 :         {
     294                 :             GDALRasterIO(hDstBand, GF_Write,
     295                 :                         0, nYSize - 1, nXSize, 1,
     296               5 :                         pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
     297                 :         }
     298                 :     }
     299                 :     
     300               6 :     int nLine1Off = 0*nXSize;
     301               6 :     int nLine2Off = 1*nXSize;
     302               6 :     int nLine3Off = 2*nXSize;
     303                 : 
     304             699 :     for ( i = 1; i < nYSize-1; i++)
     305                 :     {
     306                 :         /* Read third line of the line buffer */
     307                 :         eErr = GDALRasterIO(   hSrcBand,
     308                 :                         GF_Read,
     309                 :                         0, i+1,
     310                 :                         nXSize, 1,
     311                 :                         pafThreeLineWin + nLine3Off,
     312                 :                         nXSize, 1,
     313                 :                         GDT_Float32,
     314             693 :                         0, 0);
     315             693 :         if (eErr != CE_None)
     316               0 :             goto end;
     317                 : 
     318             812 :         if (bComputeAtEdges && nXSize >= 2)
     319                 :         {
     320                 :             float afWin[9];
     321                 : 
     322             119 :             j = 0;
     323             119 :             afWin[0] = INTERPOL(pafThreeLineWin[nLine1Off + j], pafThreeLineWin[nLine1Off + j+1]);
     324             119 :             afWin[1] = pafThreeLineWin[nLine1Off + j];
     325             119 :             afWin[2] = pafThreeLineWin[nLine1Off + j+1];
     326             119 :             afWin[3] = INTERPOL(pafThreeLineWin[nLine2Off + j], pafThreeLineWin[nLine2Off + j+1]);
     327             119 :             afWin[4] = pafThreeLineWin[nLine2Off + j];
     328             119 :             afWin[5] = pafThreeLineWin[nLine2Off + j+1];
     329             119 :             afWin[6] = INTERPOL(pafThreeLineWin[nLine3Off + j], pafThreeLineWin[nLine3Off + j+1]);
     330             119 :             afWin[7] = pafThreeLineWin[nLine3Off + j];
     331             119 :             afWin[8] = pafThreeLineWin[nLine3Off + j+1];
     332                 : 
     333             119 :             pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
     334                 :                                          afWin, fDstNoDataValue,
     335             119 :                                          pfnAlg, pData, bComputeAtEdges);
     336             119 :             j = nXSize - 1;
     337                 : 
     338             119 :             afWin[0] = pafThreeLineWin[nLine1Off + j-1];
     339             119 :             afWin[1] = pafThreeLineWin[nLine1Off + j];
     340             119 :             afWin[2] = INTERPOL(pafThreeLineWin[nLine1Off + j], pafThreeLineWin[nLine1Off + j-1]);
     341             119 :             afWin[3] = pafThreeLineWin[nLine2Off + j-1];
     342             119 :             afWin[4] = pafThreeLineWin[nLine2Off + j];
     343             119 :             afWin[5] = INTERPOL(pafThreeLineWin[nLine2Off + j], pafThreeLineWin[nLine2Off + j-1]);
     344             119 :             afWin[6] = pafThreeLineWin[nLine3Off + j-1];
     345             119 :             afWin[7] = pafThreeLineWin[nLine3Off + j];
     346             119 :             afWin[8] = INTERPOL(pafThreeLineWin[nLine3Off + j], pafThreeLineWin[nLine3Off + j-1]);
     347                 : 
     348             119 :             pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
     349                 :                                          afWin, fDstNoDataValue,
     350             119 :                                          pfnAlg, pData, bComputeAtEdges);
     351                 :         }
     352                 :         else
     353                 :         {
     354                 :             // Exclude the edges
     355             574 :             pafOutputBuf[0] = fDstNoDataValue;
     356             574 :             if (nXSize > 1)
     357             574 :                 pafOutputBuf[nXSize - 1] = fDstNoDataValue;
     358                 :         }
     359                 : 
     360           81102 :         for (j = 1; j < nXSize - 1; j++)
     361                 :         {
     362                 :             float afWin[9];
     363           80409 :             afWin[0] = pafThreeLineWin[nLine1Off + j-1];
     364           80409 :             afWin[1] = pafThreeLineWin[nLine1Off + j];
     365           80409 :             afWin[2] = pafThreeLineWin[nLine1Off + j+1];
     366           80409 :             afWin[3] = pafThreeLineWin[nLine2Off + j-1];
     367           80409 :             afWin[4] = pafThreeLineWin[nLine2Off + j];
     368           80409 :             afWin[5] = pafThreeLineWin[nLine2Off + j+1];
     369           80409 :             afWin[6] = pafThreeLineWin[nLine3Off + j-1];
     370           80409 :             afWin[7] = pafThreeLineWin[nLine3Off + j];
     371           80409 :             afWin[8] = pafThreeLineWin[nLine3Off + j+1];
     372                 : 
     373           80409 :             pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
     374                 :                                          afWin, fDstNoDataValue,
     375           80409 :                                          pfnAlg, pData, bComputeAtEdges);
     376                 :         }
     377                 : 
     378                 :         /* -----------------------------------------
     379                 :          * Write Line to Raster
     380                 :          */
     381                 :         eErr = GDALRasterIO(hDstBand, GF_Write, 0, i, nXSize, 1,
     382             693 :                      pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
     383             693 :         if (eErr != CE_None)
     384               0 :             goto end;
     385                 : 
     386             693 :         if( !pfnProgress( 1.0 * (i+1) / nYSize, NULL, pProgressData ) )
     387                 :         {
     388               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     389               0 :             eErr = CE_Failure;
     390               0 :             goto end;
     391                 :         }
     392                 :         
     393             693 :         int nTemp = nLine1Off;
     394             693 :         nLine1Off = nLine2Off;
     395             693 :         nLine2Off = nLine3Off;
     396             693 :         nLine3Off = nTemp;
     397                 :     }
     398                 : 
     399               6 :     if (bComputeAtEdges && nXSize >= 2 && nYSize >= 2)
     400                 :     {
     401             122 :         for (j = 0; j < nXSize; j++)
     402                 :         {
     403                 :             float afWin[9];
     404             121 :             int jmin = (j == 0) ? j : j - 1;
     405             121 :             int jmax = (j == nXSize - 1) ? j : j + 1;
     406                 : 
     407             121 :             afWin[0] = pafThreeLineWin[nLine1Off + jmin];
     408             121 :             afWin[1] = pafThreeLineWin[nLine1Off + j];
     409             121 :             afWin[2] = pafThreeLineWin[nLine1Off + jmax];
     410             121 :             afWin[3] = pafThreeLineWin[nLine2Off + jmin];
     411             121 :             afWin[4] = pafThreeLineWin[nLine2Off + j];
     412             121 :             afWin[5] = pafThreeLineWin[nLine2Off + jmax];
     413             121 :             afWin[6] = INTERPOL(pafThreeLineWin[nLine2Off + jmin], pafThreeLineWin[nLine1Off + jmin]);
     414             121 :             afWin[7] = INTERPOL(pafThreeLineWin[nLine2Off + j],    pafThreeLineWin[nLine1Off + j]);
     415             121 :             afWin[8] = INTERPOL(pafThreeLineWin[nLine2Off + jmax], pafThreeLineWin[nLine1Off + jmax]);
     416                 : 
     417             121 :             pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
     418                 :                                          afWin, fDstNoDataValue,
     419             121 :                                          pfnAlg, pData, bComputeAtEdges);
     420                 :         }
     421                 :         GDALRasterIO(hDstBand, GF_Write,
     422                 :                      0, i, nXSize, 1,
     423               1 :                      pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
     424                 :     }
     425                 : 
     426               6 :     pfnProgress( 1.0, NULL, pProgressData );
     427               6 :     eErr = CE_None;
     428                 : 
     429                 : end:
     430               6 :     CPLFree(pafOutputBuf);
     431               6 :     CPLFree(pafThreeLineWin);
     432                 : 
     433               6 :     return eErr;
     434                 : }
     435                 : 
     436                 : 
     437                 : /************************************************************************/
     438                 : /*                         GDALHillshade()                              */
     439                 : /************************************************************************/
     440                 : 
     441                 : typedef struct
     442                 : {
     443                 :     double nsres;
     444                 :     double ewres;
     445                 :     double sin_altRadians;
     446                 :     double cos_altRadians_mul_z_scale_factor;
     447                 :     double azRadians;
     448                 :     double square_z_scale_factor;
     449                 :     double square_M_PI_2;
     450                 : } GDALHillshadeAlgData;
     451                 : 
     452                 : /* Unoptimized formulas are :
     453                 :     x = psData->z*((afWin[0] + afWin[3] + afWin[3] + afWin[6]) -
     454                 :         (afWin[2] + afWin[5] + afWin[5] + afWin[8])) /
     455                 :         (8.0 * psData->ewres * psData->scale);
     456                 : 
     457                 :     y = psData->z*((afWin[6] + afWin[7] + afWin[7] + afWin[8]) -
     458                 :         (afWin[0] + afWin[1] + afWin[1] + afWin[2])) /
     459                 :         (8.0 * psData->nsres * psData->scale);
     460                 : 
     461                 :     slope = M_PI / 2 - atan(sqrt(x*x + y*y));
     462                 : 
     463                 :     aspect = atan2(y,x);
     464                 : 
     465                 :     cang = sin(alt * degreesToRadians) * sin(slope) +
     466                 :            cos(alt * degreesToRadians) * cos(slope) *
     467                 :            cos(az * degreesToRadians - M_PI/2 - aspect);
     468                 : */
     469                 : 
     470           67208 : float GDALHillshadeAlg (float* afWin, float fDstNoDataValue, void* pData)
     471                 : {
     472           67208 :     GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
     473                 :     double x, y, aspect, xx_plus_yy, cang;
     474                 :     
     475                 :     // First Slope ...
     476          201624 :     x = ((afWin[0] + afWin[3] + afWin[3] + afWin[6]) -
     477          201624 :         (afWin[2] + afWin[5] + afWin[5] + afWin[8])) / psData->ewres;
     478                 : 
     479          201624 :     y = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) -
     480          201624 :         (afWin[0] + afWin[1] + afWin[1] + afWin[2])) / psData->nsres;
     481                 : 
     482           67208 :     xx_plus_yy = x * x + y * y;
     483                 : 
     484                 :     // ... then aspect...
     485           67208 :     aspect = atan2(y,x);
     486                 : 
     487                 :     // ... then the shade value
     488                 :     cang = (psData->sin_altRadians -
     489                 :            psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
     490                 :            sin(aspect - psData->azRadians)) /
     491           67208 :            sqrt(1 + psData->square_z_scale_factor * xx_plus_yy);
     492                 : 
     493           67208 :     if (cang <= 0.0) 
     494             416 :         cang = 1.0;
     495                 :     else
     496           66792 :         cang = 1.0 + (254.0 * cang);
     497                 :         
     498           67208 :     return (float) cang;
     499                 : }
     500                 : 
     501           14161 : float GDALHillshadeCombinedAlg (float* afWin, float fDstNoDataValue, void* pData)
     502                 : {
     503           14161 :     GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
     504                 :     double x, y, aspect, xx_plus_yy, cang;
     505                 :     
     506                 :     // First Slope ...
     507           42483 :     x = ((afWin[0] + afWin[3] + afWin[3] + afWin[6]) -
     508           42483 :         (afWin[2] + afWin[5] + afWin[5] + afWin[8])) / psData->ewres;
     509                 : 
     510           42483 :     y = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) -
     511           42483 :         (afWin[0] + afWin[1] + afWin[1] + afWin[2])) / psData->nsres;
     512                 : 
     513           14161 :     xx_plus_yy = x * x + y * y;
     514                 : 
     515                 :     // ... then aspect...
     516           14161 :     aspect = atan2(y,x);
     517           14161 :     double slope = xx_plus_yy * psData->square_z_scale_factor;
     518                 : 
     519                 :     // ... then the shade value
     520                 :     cang = acos((psData->sin_altRadians -
     521                 :            psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
     522                 :            sin(aspect - psData->azRadians)) /
     523           14161 :            sqrt(1 + slope));
     524                 : 
     525                 :     // combined shading
     526           14161 :     cang = 1 - cang * atan(sqrt(slope)) / psData->square_M_PI_2;
     527                 : 
     528           14161 :     if (cang <= 0.0) 
     529               0 :         cang = 1.0;
     530                 :     else
     531           14161 :         cang = 1.0 + (254.0 * cang);
     532                 :         
     533           14161 :     return (float) cang;
     534                 : }
     535                 : 
     536               0 : float GDALHillshadeZevenbergenThorneAlg (float* afWin, float fDstNoDataValue, void* pData)
     537                 : {
     538               0 :     GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
     539                 :     double x, y, aspect, xx_plus_yy, cang;
     540                 :     
     541                 :     // First Slope ...
     542               0 :     x = (afWin[3] - afWin[5]) / psData->ewres;
     543                 : 
     544               0 :     y = (afWin[7] - afWin[1]) / psData->nsres;
     545                 : 
     546               0 :     xx_plus_yy = x * x + y * y;
     547                 : 
     548                 :     // ... then aspect...
     549               0 :     aspect = atan2(y,x);
     550                 : 
     551                 :     // ... then the shade value
     552                 :     cang = (psData->sin_altRadians -
     553                 :            psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
     554                 :            sin(aspect - psData->azRadians)) /
     555               0 :            sqrt(1 + psData->square_z_scale_factor * xx_plus_yy);
     556                 : 
     557               0 :     if (cang <= 0.0) 
     558               0 :         cang = 1.0;
     559                 :     else
     560               0 :         cang = 1.0 + (254.0 * cang);
     561                 :         
     562               0 :     return (float) cang;
     563                 : }
     564                 : 
     565               0 : float GDALHillshadeZevenbergenThorneCombinedAlg (float* afWin, float fDstNoDataValue, void* pData)
     566                 : {
     567               0 :     GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
     568                 :     double x, y, aspect, xx_plus_yy, cang;
     569                 :     
     570                 :     // First Slope ...
     571               0 :     x = (afWin[3] - afWin[5]) / psData->ewres;
     572                 : 
     573               0 :     y = (afWin[7] - afWin[1]) / psData->nsres;
     574                 : 
     575               0 :     xx_plus_yy = x * x + y * y;
     576                 : 
     577                 :     // ... then aspect...
     578               0 :     aspect = atan2(y,x);
     579               0 :     double slope = xx_plus_yy * psData->square_z_scale_factor;
     580                 : 
     581                 :     // ... then the shade value
     582                 :     cang = acos((psData->sin_altRadians -
     583                 :            psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
     584                 :            sin(aspect - psData->azRadians)) /
     585               0 :            sqrt(1 + slope));
     586                 : 
     587                 :     // combined shading
     588               0 :     cang = 1 - cang * atan(sqrt(slope)) / psData->square_M_PI_2;
     589                 : 
     590               0 :     if (cang <= 0.0) 
     591               0 :         cang = 1.0;
     592                 :     else
     593               0 :         cang = 1.0 + (254.0 * cang);
     594                 :         
     595               0 :     return (float) cang;
     596                 : }
     597                 : 
     598               6 : void*  GDALCreateHillshadeData(double* adfGeoTransform,
     599                 :                                double z,
     600                 :                                double scale,
     601                 :                                double alt,
     602                 :                                double az,
     603                 :                                int bZevenbergenThorne)
     604                 : {
     605                 :     GDALHillshadeAlgData* pData =
     606               6 :         (GDALHillshadeAlgData*)CPLMalloc(sizeof(GDALHillshadeAlgData));
     607                 :         
     608               6 :     const double degreesToRadians = M_PI / 180.0;
     609               6 :     pData->nsres = adfGeoTransform[5];
     610               6 :     pData->ewres = adfGeoTransform[1];
     611               6 :     pData->sin_altRadians = sin(alt * degreesToRadians);
     612               6 :     pData->azRadians = az * degreesToRadians;
     613               6 :     double z_scale_factor = z / (((bZevenbergenThorne) ? 2 : 8) * scale);
     614                 :     pData->cos_altRadians_mul_z_scale_factor =
     615               6 :         cos(alt * degreesToRadians) * z_scale_factor;
     616               6 :     pData->square_z_scale_factor = z_scale_factor * z_scale_factor;
     617               6 :     pData->square_M_PI_2 = (M_PI*M_PI)/4;
     618               6 :     return pData;
     619                 : }
     620                 : 
     621                 : /************************************************************************/
     622                 : /*                         GDALSlope()                                  */
     623                 : /************************************************************************/
     624                 : 
     625                 : typedef struct
     626                 : {
     627                 :     double nsres;
     628                 :     double ewres;
     629                 :     double scale;
     630                 :     int    slopeFormat;
     631                 : } GDALSlopeAlgData;
     632                 : 
     633           14161 : float GDALSlopeHornAlg (float* afWin, float fDstNoDataValue, void* pData)
     634                 : {
     635           14161 :     const double radiansToDegrees = 180.0 / M_PI;
     636           14161 :     GDALSlopeAlgData* psData = (GDALSlopeAlgData*)pData;
     637                 :     double dx, dy, key;
     638                 :     
     639           42483 :     dx = ((afWin[0] + afWin[3] + afWin[3] + afWin[6]) - 
     640           42483 :           (afWin[2] + afWin[5] + afWin[5] + afWin[8]))/psData->ewres;
     641                 : 
     642           42483 :     dy = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) - 
     643           42483 :           (afWin[0] + afWin[1] + afWin[1] + afWin[2]))/psData->nsres;
     644                 : 
     645           14161 :     key = (dx * dx + dy * dy);
     646                 : 
     647           14161 :     if (psData->slopeFormat == 1) 
     648           14161 :         return (float) (atan(sqrt(key) / (8*psData->scale)) * radiansToDegrees);
     649                 :     else
     650               0 :         return (float) (100*(sqrt(key) / (8*psData->scale)));
     651                 : }
     652                 : 
     653               0 : float GDALSlopeZevenbergenThorneAlg (float* afWin, float fDstNoDataValue, void* pData)
     654                 : {
     655               0 :     const double radiansToDegrees = 180.0 / M_PI;
     656               0 :     GDALSlopeAlgData* psData = (GDALSlopeAlgData*)pData;
     657                 :     double dx, dy, key;
     658                 :     
     659               0 :     dx = (afWin[3] - afWin[5])/psData->ewres;
     660                 : 
     661               0 :     dy = (afWin[7] - afWin[1])/psData->nsres;
     662                 : 
     663               0 :     key = (dx * dx + dy * dy);
     664                 : 
     665               0 :     if (psData->slopeFormat == 1) 
     666               0 :         return (float) (atan(sqrt(key) / (2*psData->scale)) * radiansToDegrees);
     667                 :     else
     668               0 :         return (float) (100*(sqrt(key) / (2*psData->scale)));
     669                 : }
     670                 : 
     671               1 : void*  GDALCreateSlopeData(double* adfGeoTransform,
     672                 :                            double scale,
     673                 :                            int slopeFormat)
     674                 : {
     675                 :     GDALSlopeAlgData* pData =
     676               1 :         (GDALSlopeAlgData*)CPLMalloc(sizeof(GDALSlopeAlgData));
     677                 :         
     678               1 :     pData->nsres = adfGeoTransform[5];
     679               1 :     pData->ewres = adfGeoTransform[1];
     680               1 :     pData->scale = scale;
     681               1 :     pData->slopeFormat = slopeFormat;
     682               1 :     return pData;
     683                 : }
     684                 : 
     685                 : /************************************************************************/
     686                 : /*                         GDALAspect()                                 */
     687                 : /************************************************************************/
     688                 : 
     689                 : typedef struct
     690                 : {
     691                 :     int bAngleAsAzimuth;
     692                 : } GDALAspectAlgData;
     693                 : 
     694           14161 : float GDALAspectAlg (float* afWin, float fDstNoDataValue, void* pData)
     695                 : {
     696           14161 :     const double degreesToRadians = M_PI / 180.0;
     697           14161 :     GDALAspectAlgData* psData = (GDALAspectAlgData*)pData;
     698                 :     double dx, dy;
     699                 :     float aspect;
     700                 :     
     701           42483 :     dx = ((afWin[2] + afWin[5] + afWin[5] + afWin[8]) -
     702           42483 :           (afWin[0] + afWin[3] + afWin[3] + afWin[6]));
     703                 : 
     704           42483 :     dy = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) - 
     705           42483 :           (afWin[0] + afWin[1] + afWin[1] + afWin[2]));
     706                 : 
     707           14161 :     aspect = (float) (atan2(dy,-dx) / degreesToRadians);
     708                 : 
     709           18344 :     if (dx == 0 && dy == 0)
     710                 :     {
     711                 :         /* Flat area */
     712            4183 :         aspect = fDstNoDataValue;
     713                 :     } 
     714            9978 :     else if ( psData->bAngleAsAzimuth )
     715                 :     {
     716            9978 :         if (aspect > 90.0) 
     717            1243 :             aspect = 450.0f - aspect;
     718                 :         else
     719            8735 :             aspect = 90.0f - aspect;
     720                 :     }
     721                 :     else
     722                 :     {
     723               0 :         if (aspect < 0)
     724               0 :             aspect += 360.0;
     725                 :     }
     726                 : 
     727           14161 :     if (aspect == 360.0) 
     728               0 :         aspect = 0.0;
     729                 : 
     730           14161 :     return aspect;
     731                 : }
     732                 : 
     733               0 : float GDALAspectZevenbergenThorneAlg (float* afWin, float fDstNoDataValue, void* pData)
     734                 : {
     735               0 :     const double degreesToRadians = M_PI / 180.0;
     736               0 :     GDALAspectAlgData* psData = (GDALAspectAlgData*)pData;
     737                 :     double dx, dy;
     738                 :     float aspect;
     739                 :     
     740               0 :     dx = (afWin[5] - afWin[3]);
     741                 : 
     742               0 :     dy = (afWin[7] - afWin[1]);
     743                 : 
     744               0 :     aspect = (float) (atan2(dy,-dx) / degreesToRadians);
     745                 : 
     746               0 :     if (dx == 0 && dy == 0)
     747                 :     {
     748                 :         /* Flat area */
     749               0 :         aspect = fDstNoDataValue;
     750                 :     } 
     751               0 :     else if ( psData->bAngleAsAzimuth )
     752                 :     {
     753               0 :         if (aspect > 90.0) 
     754               0 :             aspect = 450.0f - aspect;
     755                 :         else
     756               0 :             aspect = 90.0f - aspect;
     757                 :     }
     758                 :     else
     759                 :     {
     760               0 :         if (aspect < 0)
     761               0 :             aspect += 360.0;
     762                 :     }
     763                 : 
     764               0 :     if (aspect == 360.0) 
     765               0 :         aspect = 0.0;
     766                 : 
     767               0 :     return aspect;
     768                 : }
     769               1 : void*  GDALCreateAspectData(int bAngleAsAzimuth)
     770                 : {
     771                 :     GDALAspectAlgData* pData =
     772               1 :         (GDALAspectAlgData*)CPLMalloc(sizeof(GDALAspectAlgData));
     773                 :         
     774               1 :     pData->bAngleAsAzimuth = bAngleAsAzimuth;
     775               1 :     return pData;
     776                 : }
     777                 : 
     778                 : /************************************************************************/
     779                 : /*                      GDALColorRelief()                               */
     780                 : /************************************************************************/
     781                 : 
     782                 : typedef struct
     783                 : {
     784                 :     double dfVal;
     785                 :     int nR;
     786                 :     int nG;
     787                 :     int nB;
     788                 :     int nA;
     789                 : } ColorAssociation;
     790                 : 
     791              88 : static int GDALColorReliefSortColors(const void* pA, const void* pB)
     792                 : {
     793              88 :     ColorAssociation* pC1 = (ColorAssociation*)pA;
     794              88 :     ColorAssociation* pC2 = (ColorAssociation*)pB;
     795                 :     return (pC1->dfVal < pC2->dfVal) ? -1 :
     796              88 :            (pC1->dfVal == pC2->dfVal) ? 0 : 1;
     797                 : }
     798                 : 
     799                 : typedef enum
     800                 : {
     801                 :     COLOR_SELECTION_INTERPOLATE,
     802                 :     COLOR_SELECTION_NEAREST_ENTRY,
     803                 :     COLOR_SELECTION_EXACT_ENTRY
     804                 : } ColorSelectionMode;
     805                 : 
     806          146410 : static int GDALColorReliefGetRGBA (ColorAssociation* pasColorAssociation,
     807                 :                                    int nColorAssociation,
     808                 :                                    double dfVal,
     809                 :                                    ColorSelectionMode eColorSelectionMode,
     810                 :                                    int* pnR,
     811                 :                                    int* pnG,
     812                 :                                    int* pnB,
     813                 :                                    int* pnA)
     814                 : {
     815                 :     int i;
     816          146410 :     int lower = 0;
     817          146410 :     int upper = nColorAssociation - 1;
     818                 :     int mid;
     819                 : 
     820                 :     /* Find the index of the first element in the LUT input array that */
     821                 :     /* is not smaller than the dfVal value. */
     822          320870 :     while(TRUE)
     823                 :     {
     824          467280 :         mid = (lower + upper) / 2;
     825          467280 :         if (upper - lower <= 1)
     826                 :         {
     827          146410 :             if (dfVal < pasColorAssociation[lower].dfVal)
     828               0 :                 i = lower;
     829          146410 :             else if (dfVal < pasColorAssociation[upper].dfVal)
     830           99650 :                 i = upper;
     831                 :             else
     832           46760 :                 i = upper + 1;
     833                 :             break;
     834                 :         }
     835          320870 :         else if (pasColorAssociation[mid].dfVal >= dfVal)
     836                 :         {
     837          192630 :             upper = mid;
     838                 :         }
     839                 :         else
     840                 :         {
     841          128240 :             lower = mid;
     842                 :         }
     843                 :     }
     844                 : 
     845          146410 :     if (i == 0)
     846                 :     {
     847               0 :         if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
     848                 :             pasColorAssociation[0].dfVal != dfVal)
     849                 :         {
     850               0 :             *pnR = 0;
     851               0 :             *pnG = 0;
     852               0 :             *pnB = 0;
     853               0 :             *pnA = 0;
     854               0 :             return FALSE;
     855                 :         }
     856                 :         else
     857                 :         {
     858               0 :             *pnR = pasColorAssociation[0].nR;
     859               0 :             *pnG = pasColorAssociation[0].nG;
     860               0 :             *pnB = pasColorAssociation[0].nB;
     861               0 :             *pnA = pasColorAssociation[0].nA;
     862               0 :             return TRUE;
     863                 :         }
     864                 :     }
     865          146410 :     else if (i == nColorAssociation)
     866                 :     {
     867               0 :         if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
     868               0 :             pasColorAssociation[i-1].dfVal != dfVal)
     869                 :         {
     870               0 :             *pnR = 0;
     871               0 :             *pnG = 0;
     872               0 :             *pnB = 0;
     873               0 :             *pnA = 0;
     874               0 :             return FALSE;
     875                 :         }
     876                 :         else
     877                 :         {
     878               0 :             *pnR = pasColorAssociation[i-1].nR;
     879               0 :             *pnG = pasColorAssociation[i-1].nG;
     880               0 :             *pnB = pasColorAssociation[i-1].nB;
     881               0 :             *pnA = pasColorAssociation[i-1].nA;
     882               0 :             return TRUE;
     883                 :         }
     884                 :     }
     885                 :     else
     886                 :     {
     887          146410 :         if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
     888               0 :             pasColorAssociation[i-1].dfVal != dfVal)
     889                 :         {
     890               0 :             *pnR = 0;
     891               0 :             *pnG = 0;
     892               0 :             *pnB = 0;
     893               0 :             *pnA = 0;
     894               0 :             return FALSE;
     895                 :         }
     896                 :         
     897          161051 :         if (eColorSelectionMode == COLOR_SELECTION_NEAREST_ENTRY &&
     898           14641 :             pasColorAssociation[i-1].dfVal != dfVal)
     899                 :         {
     900                 :             int index;
     901           19930 :             if (dfVal - pasColorAssociation[i-1].dfVal <
     902            9965 :                 pasColorAssociation[i].dfVal - dfVal)
     903            6716 :                 index = i -1;
     904                 :             else
     905            3249 :                 index = i;
     906                 : 
     907            9965 :             *pnR = pasColorAssociation[index].nR;
     908            9965 :             *pnG = pasColorAssociation[index].nG;
     909            9965 :             *pnB = pasColorAssociation[index].nB;
     910            9965 :             *pnA = pasColorAssociation[index].nA;
     911            9965 :             return TRUE;
     912                 :         }
     913                 :         
     914          136445 :         double dfRatio = (dfVal - pasColorAssociation[i-1].dfVal) /
     915          136445 :             (pasColorAssociation[i].dfVal - pasColorAssociation[i-1].dfVal);
     916          136445 :         *pnR = (int)(0.45 + pasColorAssociation[i-1].nR + dfRatio *
     917          136445 :                 (pasColorAssociation[i].nR - pasColorAssociation[i-1].nR));
     918          136445 :         if (*pnR < 0) *pnR = 0;
     919          136445 :         else if (*pnR > 255) *pnR = 255;
     920          136445 :         *pnG = (int)(0.45 + pasColorAssociation[i-1].nG + dfRatio *
     921          136445 :                 (pasColorAssociation[i].nG - pasColorAssociation[i-1].nG));
     922          136445 :         if (*pnG < 0) *pnG = 0;
     923          136445 :         else if (*pnG > 255) *pnG = 255;
     924          136445 :         *pnB = (int)(0.45 + pasColorAssociation[i-1].nB + dfRatio *
     925          136445 :                 (pasColorAssociation[i].nB - pasColorAssociation[i-1].nB));
     926          136445 :         if (*pnB < 0) *pnB = 0;
     927          136445 :         else if (*pnB > 255) *pnB = 255;
     928          136445 :         *pnA = (int)(0.45 + pasColorAssociation[i-1].nA + dfRatio *
     929          136445 :                 (pasColorAssociation[i].nA - pasColorAssociation[i-1].nA));
     930          136445 :         if (*pnA < 0) *pnA = 0;
     931          136445 :         else if (*pnA > 255) *pnA = 255;
     932                 :         
     933          136445 :         return TRUE;
     934                 :     }
     935                 : }
     936                 : 
     937                 : /* dfPct : percentage between 0 and 1 */
     938               0 : static double GDALColorReliefGetAbsoluteValFromPct(GDALRasterBandH hSrcBand,
     939                 :                                                    double dfPct)
     940                 : {
     941                 :     double dfMin, dfMax;
     942                 :     int bSuccessMin, bSuccessMax;
     943               0 :     dfMin = GDALGetRasterMinimum(hSrcBand, &bSuccessMin);
     944               0 :     dfMax = GDALGetRasterMaximum(hSrcBand, &bSuccessMax);
     945               0 :     if (!bSuccessMin || !bSuccessMax)
     946                 :     {
     947                 :         double dfMean, dfStdDev;
     948               0 :         fprintf(stderr, "Computing source raster statistics...\n");
     949                 :         GDALComputeRasterStatistics(hSrcBand, FALSE, &dfMin, &dfMax,
     950               0 :                                     &dfMean, &dfStdDev, NULL, NULL);
     951                 :     }
     952               0 :     return dfMin + dfPct * (dfMax - dfMin);
     953                 : }
     954                 : 
     955                 : typedef struct
     956                 : {
     957                 :     const char *name;
     958                 :     float r, g, b;
     959                 : } NamedColor;
     960                 : 
     961                 : static const NamedColor namedColors[] = {
     962                 :     { "white",  1.00, 1.00, 1.00 },
     963                 :     { "black",  0.00, 0.00, 0.00 },
     964                 :     { "red",    1.00, 0.00, 0.00 },
     965                 :     { "green",  0.00, 1.00, 0.00 },
     966                 :     { "blue",   0.00, 0.00, 1.00 },
     967                 :     { "yellow", 1.00, 1.00, 0.00 },
     968                 :     { "magenta",1.00, 0.00, 1.00 },
     969                 :     { "cyan",   0.00, 1.00, 1.00 },
     970                 :     { "aqua",   0.00, 0.75, 0.75 },
     971                 :     { "grey",   0.75, 0.75, 0.75 },
     972                 :     { "gray",   0.75, 0.75, 0.75 },
     973                 :     { "orange", 1.00, 0.50, 0.00 },
     974                 :     { "brown",  0.75, 0.50, 0.25 },
     975                 :     { "purple", 0.50, 0.00, 1.00 },
     976                 :     { "violet", 0.50, 0.00, 1.00 },
     977                 :     { "indigo", 0.00, 0.50, 1.00 },
     978                 : };
     979                 : 
     980                 : static
     981               0 : int GDALColorReliefFindNamedColor(const char *pszColorName, int *pnR, int *pnG, int *pnB)
     982                 : {
     983                 :     unsigned int i;
     984                 : 
     985               0 :     *pnR = *pnG = *pnB = 0;
     986               0 :     for (i = 0; i < sizeof(namedColors) / sizeof(namedColors[0]); i++)
     987                 :     {
     988               0 :         if (EQUAL(pszColorName, namedColors[i].name))
     989                 :         {
     990               0 :             *pnR = (int)(255. * namedColors[i].r);
     991               0 :             *pnG = (int)(255. * namedColors[i].g);
     992               0 :             *pnB = (int)(255. * namedColors[i].b);
     993               0 :             return TRUE;
     994                 :         }
     995                 :     }
     996               0 :     return FALSE;
     997                 : }
     998                 : 
     999                 : static
    1000               8 : ColorAssociation* GDALColorReliefParseColorFile(GDALRasterBandH hSrcBand,
    1001                 :                                                 const char* pszColorFilename,
    1002                 :                                                 int* pnColors)
    1003                 : {
    1004               8 :     VSILFILE* fpColorFile = VSIFOpenL(pszColorFilename, "rt");
    1005               8 :     if (fpColorFile == NULL)
    1006                 :     {
    1007               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s", pszColorFilename);
    1008               0 :         *pnColors = 0;
    1009               0 :         return NULL;
    1010                 :     }
    1011                 : 
    1012               8 :     ColorAssociation* pasColorAssociation = NULL;
    1013               8 :     int nColorAssociation = 0;
    1014                 : 
    1015               8 :     int bSrcHasNoData = FALSE;
    1016               8 :     double dfSrcNoDataValue = GDALGetRasterNoDataValue(hSrcBand, &bSrcHasNoData);
    1017                 : 
    1018                 :     const char* pszLine;
    1019               8 :     int bIsGMT_CPT = FALSE;
    1020              74 :     while ((pszLine = CPLReadLineL(fpColorFile)) != NULL)
    1021                 :     {
    1022              58 :         if (pszLine[0] == '#' && strstr(pszLine, "COLOR_MODEL"))
    1023                 :         {
    1024               1 :             if (strstr(pszLine, "COLOR_MODEL = RGB") == NULL)
    1025                 :             {
    1026               0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Only COLOR_MODEL = RGB is supported");
    1027               0 :                 CPLFree(pasColorAssociation);
    1028               0 :                 *pnColors = 0;
    1029               0 :                 return NULL;
    1030                 :             }
    1031               1 :             bIsGMT_CPT = TRUE;
    1032                 :         }
    1033                 : 
    1034                 :         char** papszFields = CSLTokenizeStringComplex(pszLine, " ,\t:", 
    1035              58 :                                                       FALSE, FALSE );
    1036                 :         /* Skip comment lines */
    1037              58 :         int nTokens = CSLCount(papszFields);
    1038             113 :         if (nTokens >= 1 && (papszFields[0][0] == '#' ||
    1039              55 :                              papszFields[0][0] == '/'))
    1040                 :         {
    1041               3 :             CSLDestroy(papszFields);
    1042               3 :             continue;
    1043                 :         }
    1044                 : 
    1045              58 :         if (bIsGMT_CPT && nTokens == 8)
    1046                 :         {
    1047                 :             pasColorAssociation =
    1048                 :                     (ColorAssociation*)CPLRealloc(pasColorAssociation,
    1049               3 :                            (nColorAssociation + 2) * sizeof(ColorAssociation));
    1050                 : 
    1051               3 :             pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[0]);
    1052               3 :             pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
    1053               3 :             pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
    1054               3 :             pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
    1055               3 :             pasColorAssociation[nColorAssociation].nA = 255;
    1056               3 :             nColorAssociation++;
    1057                 : 
    1058               3 :             pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[4]);
    1059               3 :             pasColorAssociation[nColorAssociation].nR = atoi(papszFields[5]);
    1060               3 :             pasColorAssociation[nColorAssociation].nG = atoi(papszFields[6]);
    1061               3 :             pasColorAssociation[nColorAssociation].nB = atoi(papszFields[7]);
    1062               3 :             pasColorAssociation[nColorAssociation].nA = 255;
    1063               3 :             nColorAssociation++;
    1064                 :         }
    1065              55 :         else if (bIsGMT_CPT && nTokens == 4)
    1066                 :         {
    1067                 :             /* The first token might be B (background), F (foreground) or N (nodata) */
    1068                 :             /* Just interested in N */
    1069               3 :             if (EQUAL(papszFields[0], "N") && bSrcHasNoData)
    1070                 :             {
    1071                 :                  pasColorAssociation =
    1072                 :                     (ColorAssociation*)CPLRealloc(pasColorAssociation,
    1073               1 :                            (nColorAssociation + 1) * sizeof(ColorAssociation));
    1074                 : 
    1075               1 :                 pasColorAssociation[nColorAssociation].dfVal = dfSrcNoDataValue;
    1076               1 :                 pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
    1077               1 :                 pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
    1078               1 :                 pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
    1079               1 :                 pasColorAssociation[nColorAssociation].nA = 255;
    1080               1 :                 nColorAssociation++;
    1081                 :             }
    1082                 :         }
    1083              49 :         else if (!bIsGMT_CPT && nTokens >= 2)
    1084                 :         {
    1085                 :             pasColorAssociation =
    1086                 :                     (ColorAssociation*)CPLRealloc(pasColorAssociation,
    1087              49 :                            (nColorAssociation + 1) * sizeof(ColorAssociation));
    1088              49 :             if (EQUAL(papszFields[0], "nv") && bSrcHasNoData)
    1089               0 :                 pasColorAssociation[nColorAssociation].dfVal = dfSrcNoDataValue;
    1090              49 :             else if (strlen(papszFields[0]) > 1 && papszFields[0][strlen(papszFields[0])-1] == '%')
    1091                 :             {
    1092               0 :                 double dfPct = atof(papszFields[0]) / 100.;
    1093               0 :                 if (dfPct < 0.0 || dfPct > 1.0)
    1094                 :                 {
    1095                 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1096               0 :                              "Wrong value for a percentage : %s", papszFields[0]);
    1097               0 :                     CSLDestroy(papszFields);
    1098               0 :                     VSIFCloseL(fpColorFile);
    1099               0 :                     CPLFree(pasColorAssociation);
    1100               0 :                     *pnColors = 0;
    1101               0 :                     return NULL;
    1102                 :                 }
    1103               0 :                 pasColorAssociation[nColorAssociation].dfVal =
    1104               0 :                         GDALColorReliefGetAbsoluteValFromPct(hSrcBand, dfPct);
    1105                 :             }
    1106                 :             else
    1107              49 :                 pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[0]);
    1108                 : 
    1109              49 :             if (nTokens >= 4)
    1110                 :             {
    1111              49 :                 pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
    1112              49 :                 pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
    1113              49 :                 pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
    1114              49 :                 pasColorAssociation[nColorAssociation].nA =
    1115              49 :                         (CSLCount(papszFields) >= 5 ) ? atoi(papszFields[4]) : 255;
    1116                 :             }
    1117                 :             else
    1118                 :             {
    1119                 :                 int nR, nG, nB;
    1120               0 :                 if (!GDALColorReliefFindNamedColor(papszFields[1], &nR, &nG, &nB))
    1121                 :                 {
    1122                 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1123               0 :                              "Unknown color : %s", papszFields[1]);
    1124               0 :                     CSLDestroy(papszFields);
    1125               0 :                     VSIFCloseL(fpColorFile);
    1126               0 :                     CPLFree(pasColorAssociation);
    1127               0 :                     *pnColors = 0;
    1128               0 :                     return NULL;
    1129                 :                 }
    1130               0 :                 pasColorAssociation[nColorAssociation].nR = nR;
    1131               0 :                 pasColorAssociation[nColorAssociation].nG = nG;
    1132               0 :                 pasColorAssociation[nColorAssociation].nB = nB;
    1133               0 :                             pasColorAssociation[nColorAssociation].nA =
    1134               0 :                     (CSLCount(papszFields) >= 3 ) ? atoi(papszFields[2]) : 255;
    1135                 :             }
    1136                 : 
    1137              49 :             nColorAssociation ++;
    1138                 :         }
    1139              55 :         CSLDestroy(papszFields);
    1140                 :     }
    1141               8 :     VSIFCloseL(fpColorFile);
    1142                 : 
    1143               8 :     if (nColorAssociation == 0)
    1144                 :     {
    1145                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1146               0 :                  "No color association found in %s", pszColorFilename);
    1147               0 :         *pnColors = 0;
    1148               0 :         return NULL;
    1149                 :     }
    1150                 : 
    1151                 :     qsort(pasColorAssociation, nColorAssociation,
    1152               8 :           sizeof(ColorAssociation), GDALColorReliefSortColors);
    1153                 : 
    1154               8 :     *pnColors = nColorAssociation;
    1155               8 :     return pasColorAssociation;
    1156                 : }
    1157                 : 
    1158                 : static
    1159               6 : GByte* GDALColorReliefPrecompute(GDALRasterBandH hSrcBand,
    1160                 :                                  ColorAssociation* pasColorAssociation,
    1161                 :                                  int nColorAssociation,
    1162                 :                                  ColorSelectionMode eColorSelectionMode,
    1163                 :                                  int* pnIndexOffset)
    1164                 : {
    1165               6 :     GDALDataType eDT = GDALGetRasterDataType(hSrcBand);
    1166               6 :     GByte* pabyPrecomputed = NULL;
    1167               6 :     int nIndexOffset = (eDT == GDT_Int16) ? 32768 : 0;
    1168               6 :     *pnIndexOffset = nIndexOffset;
    1169               6 :     int nXSize = GDALGetRasterBandXSize(hSrcBand);
    1170               6 :     int nYSize = GDALGetRasterBandXSize(hSrcBand);
    1171               6 :     if (eDT == GDT_Byte ||
    1172                 :         ((eDT == GDT_Int16 || eDT == GDT_UInt16) && nXSize * nYSize > 65536))
    1173                 :     {
    1174               0 :         int iMax = (eDT == GDT_Byte) ? 256: 65536;
    1175               0 :         pabyPrecomputed = (GByte*) VSIMalloc(4 * iMax);
    1176               0 :         if (pabyPrecomputed)
    1177                 :         {
    1178                 :             int i;
    1179               0 :             for(i=0;i<iMax;i++)
    1180                 :             {
    1181                 :                 int nR, nG, nB, nA;
    1182                 :                 GDALColorReliefGetRGBA  (pasColorAssociation,
    1183                 :                                          nColorAssociation,
    1184                 :                                          i - nIndexOffset,
    1185                 :                                          eColorSelectionMode,
    1186               0 :                                          &nR, &nG, &nB, &nA);
    1187               0 :                 pabyPrecomputed[4 * i] = (GByte) nR;
    1188               0 :                 pabyPrecomputed[4 * i + 1] = (GByte) nG;
    1189               0 :                 pabyPrecomputed[4 * i + 2] = (GByte) nB;
    1190               0 :                 pabyPrecomputed[4 * i + 3] = (GByte) nA;
    1191                 :             }
    1192                 :         }
    1193                 :     }
    1194               6 :     return pabyPrecomputed;
    1195                 : }
    1196                 : 
    1197                 : /************************************************************************/
    1198                 : /* ==================================================================== */
    1199                 : /*                       GDALColorReliefDataset                        */
    1200                 : /* ==================================================================== */
    1201                 : /************************************************************************/
    1202                 : 
    1203                 : class GDALColorReliefRasterBand;
    1204                 : 
    1205                 : class GDALColorReliefDataset : public GDALDataset
    1206                 : {
    1207                 :     friend class GDALColorReliefRasterBand;
    1208                 : 
    1209                 :     GDALDatasetH       hSrcDS;
    1210                 :     GDALRasterBandH    hSrcBand;
    1211                 :     int                nColorAssociation;
    1212                 :     ColorAssociation*  pasColorAssociation;
    1213                 :     ColorSelectionMode eColorSelectionMode;
    1214                 :     GByte*             pabyPrecomputed;
    1215                 :     int                nIndexOffset;
    1216                 :     float*             pafSourceBuf;
    1217                 :     int*               panSourceBuf;
    1218                 :     int                nCurBlockXOff;
    1219                 :     int                nCurBlockYOff;
    1220                 : 
    1221                 :   public:
    1222                 :                         GDALColorReliefDataset(GDALDatasetH hSrcDS,
    1223                 :                                             GDALRasterBandH hSrcBand,
    1224                 :                                             const char* pszColorFilename,
    1225                 :                                             ColorSelectionMode eColorSelectionMode,
    1226                 :                                             int bAlpha);
    1227                 :                        ~GDALColorReliefDataset();
    1228                 : 
    1229                 :     CPLErr      GetGeoTransform( double * padfGeoTransform );
    1230                 :     const char *GetProjectionRef();
    1231                 : };
    1232                 : 
    1233                 : /************************************************************************/
    1234                 : /* ==================================================================== */
    1235                 : /*                    GDALColorReliefRasterBand                       */
    1236                 : /* ==================================================================== */
    1237                 : /************************************************************************/
    1238                 : 
    1239                 : class GDALColorReliefRasterBand : public GDALRasterBand
    1240               6 : {
    1241                 :     friend class GDALColorReliefDataset;
    1242                 : 
    1243                 :     
    1244                 :   public:
    1245                 :                  GDALColorReliefRasterBand( GDALColorReliefDataset *, int );
    1246                 :     
    1247                 :     virtual CPLErr          IReadBlock( int, int, void * );
    1248                 :     virtual GDALColorInterp GetColorInterpretation();
    1249                 : };
    1250                 : 
    1251               2 : GDALColorReliefDataset::GDALColorReliefDataset(
    1252                 :                                      GDALDatasetH hSrcDS,
    1253                 :                                      GDALRasterBandH hSrcBand,
    1254                 :                                      const char* pszColorFilename,
    1255                 :                                      ColorSelectionMode eColorSelectionMode,
    1256               2 :                                      int bAlpha)
    1257                 : {
    1258               2 :     this->hSrcDS = hSrcDS;
    1259               2 :     this->hSrcBand = hSrcBand;
    1260               2 :     nColorAssociation = 0;
    1261                 :     pasColorAssociation =
    1262                 :             GDALColorReliefParseColorFile(hSrcBand, pszColorFilename,
    1263               2 :                                           &nColorAssociation);
    1264               2 :     this->eColorSelectionMode = eColorSelectionMode;
    1265                 :     
    1266               2 :     nRasterXSize = GDALGetRasterXSize(hSrcDS);
    1267               2 :     nRasterYSize = GDALGetRasterYSize(hSrcDS);
    1268                 :     
    1269                 :     int nBlockXSize, nBlockYSize;
    1270               2 :     GDALGetBlockSize( hSrcBand, &nBlockXSize, &nBlockYSize);
    1271                 :     
    1272               2 :     nIndexOffset = 0;
    1273                 :     pabyPrecomputed =
    1274                 :         GDALColorReliefPrecompute(hSrcBand,
    1275                 :                                   pasColorAssociation,
    1276                 :                                   nColorAssociation,
    1277                 :                                   eColorSelectionMode,
    1278               2 :                                   &nIndexOffset);
    1279                 :     
    1280                 :     int i;
    1281               8 :     for(i=0;i<((bAlpha) ? 4 : 3);i++)
    1282                 :     {
    1283               6 :         SetBand(i + 1, new GDALColorReliefRasterBand(this, i+1));
    1284                 :     }
    1285                 :     
    1286               2 :     pafSourceBuf = NULL;
    1287               2 :     panSourceBuf = NULL;
    1288               2 :     if (pabyPrecomputed)
    1289               0 :         panSourceBuf = (int *) CPLMalloc(sizeof(int)*nBlockXSize*nBlockYSize);
    1290                 :     else
    1291               2 :         pafSourceBuf = (float *) CPLMalloc(sizeof(float)*nBlockXSize*nBlockYSize);
    1292               2 :     nCurBlockXOff = -1;
    1293               2 :     nCurBlockYOff = -1;
    1294               2 : }
    1295                 : 
    1296               2 : GDALColorReliefDataset::~GDALColorReliefDataset()
    1297                 : {
    1298               2 :     CPLFree(pasColorAssociation);
    1299               2 :     CPLFree(pabyPrecomputed);
    1300               2 :     CPLFree(panSourceBuf);
    1301               2 :     CPLFree(pafSourceBuf);
    1302               2 : }
    1303                 : 
    1304               2 : CPLErr GDALColorReliefDataset::GetGeoTransform( double * padfGeoTransform )
    1305                 : {
    1306               2 :     return GDALGetGeoTransform(hSrcDS, padfGeoTransform);
    1307                 : }
    1308                 : 
    1309               2 : const char *GDALColorReliefDataset::GetProjectionRef()
    1310                 : {
    1311               2 :     return GDALGetProjectionRef(hSrcDS);
    1312                 : }
    1313                 : 
    1314               6 : GDALColorReliefRasterBand::GDALColorReliefRasterBand(
    1315               6 :                                     GDALColorReliefDataset * poDS, int nBand)
    1316                 : {
    1317               6 :     this->poDS = poDS;
    1318               6 :     this->nBand = nBand;
    1319               6 :     eDataType = GDT_Byte;
    1320               6 :     GDALGetBlockSize( poDS->hSrcBand, &nBlockXSize, &nBlockYSize);
    1321               6 : }
    1322                 : 
    1323             387 : CPLErr GDALColorReliefRasterBand::IReadBlock( int nBlockXOff,
    1324                 :                                               int nBlockYOff,
    1325                 :                                               void *pImage )
    1326                 : {
    1327             387 :     GDALColorReliefDataset * poGDS = (GDALColorReliefDataset *) poDS;
    1328                 :     int nReqXSize, nReqYSize;
    1329                 : 
    1330             387 :     if ((nBlockXOff + 1) * nBlockXSize >= nRasterXSize)
    1331              27 :         nReqXSize = nRasterXSize - nBlockXOff * nBlockXSize;
    1332                 :     else
    1333             360 :         nReqXSize = nBlockXSize;
    1334                 :         
    1335             387 :     if ((nBlockYOff + 1) * nBlockYSize >= nRasterYSize)
    1336             366 :         nReqYSize = nRasterYSize - nBlockYOff * nBlockYSize;
    1337                 :     else
    1338              21 :         nReqYSize = nBlockYSize;
    1339                 : 
    1340             387 :     if ( poGDS->nCurBlockXOff != nBlockXOff ||
    1341                 :          poGDS->nCurBlockYOff != nBlockYOff )
    1342                 :     {
    1343             371 :         poGDS->nCurBlockXOff = nBlockXOff;
    1344             371 :         poGDS->nCurBlockYOff = nBlockYOff;
    1345                 :         
    1346                 :         CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
    1347                 :                             GF_Read,
    1348                 :                             nBlockXOff * nBlockXSize,
    1349                 :                             nBlockYOff * nBlockYSize,
    1350                 :                             nReqXSize, nReqYSize,
    1351                 :                             (poGDS->panSourceBuf) ?
    1352                 :                                 (void*) poGDS->panSourceBuf :
    1353                 :                                 (void* )poGDS->pafSourceBuf,
    1354                 :                             nReqXSize, nReqYSize,
    1355                 :                             (poGDS->panSourceBuf) ? GDT_Int32 : GDT_Float32,
    1356             371 :                             0, 0);
    1357             371 :         if (eErr != CE_None)
    1358                 :         {
    1359               0 :             memset(pImage, 0, nBlockXSize * nBlockYSize);
    1360               0 :             return eErr;
    1361                 :         }
    1362                 :     }
    1363                 : 
    1364             387 :     int x, y, j = 0;
    1365             387 :     if (poGDS->panSourceBuf)
    1366                 :     {
    1367               0 :         for( y = 0; y < nReqYSize; y++ )
    1368                 :         {
    1369               0 :             for( x = 0; x < nReqXSize; x++ )
    1370                 :             {
    1371               0 :                 int nIndex = poGDS->panSourceBuf[j] + poGDS->nIndexOffset;
    1372               0 :                 ((GByte*)pImage)[y * nBlockXSize + x] = poGDS->pabyPrecomputed[4*nIndex + nBand-1];
    1373               0 :                 j++;
    1374                 :             }
    1375                 :         }
    1376                 :     }
    1377                 :     else
    1378                 :     {
    1379                 :         int anComponents[4];
    1380           44673 :         for( y = 0; y < nReqYSize; y++ )
    1381                 :         {
    1382          132132 :             for( x = 0; x < nReqXSize; x++ )
    1383                 :             {
    1384                 :                 GDALColorReliefGetRGBA  (poGDS->pasColorAssociation,
    1385                 :                                         poGDS->nColorAssociation,
    1386           87846 :                                         poGDS->pafSourceBuf[j],
    1387                 :                                         poGDS->eColorSelectionMode,
    1388                 :                                         &anComponents[0],
    1389                 :                                         &anComponents[1],
    1390                 :                                         &anComponents[2],
    1391          175692 :                                         &anComponents[3]);
    1392           87846 :                 ((GByte*)pImage)[y * nBlockXSize + x] = (GByte) anComponents[nBand-1];
    1393           87846 :                 j++;
    1394                 :             }
    1395                 :         }
    1396                 :     }
    1397                 :     
    1398             387 :     return CE_None;
    1399                 : }
    1400                 : 
    1401              12 : GDALColorInterp GDALColorReliefRasterBand::GetColorInterpretation()
    1402                 : {
    1403              12 :     return (GDALColorInterp)(GCI_RedBand + nBand - 1);
    1404                 : }
    1405                 : 
    1406                 : 
    1407               4 : CPLErr GDALColorRelief (GDALRasterBandH hSrcBand,
    1408                 :                         GDALRasterBandH hDstBand1,
    1409                 :                         GDALRasterBandH hDstBand2,
    1410                 :                         GDALRasterBandH hDstBand3,
    1411                 :                         GDALRasterBandH hDstBand4,
    1412                 :                         const char* pszColorFilename,
    1413                 :                         ColorSelectionMode eColorSelectionMode,
    1414                 :                         GDALProgressFunc pfnProgress,
    1415                 :                         void * pProgressData)
    1416                 : {
    1417                 :     CPLErr eErr;
    1418                 :     
    1419               4 :     if (hSrcBand == NULL || hDstBand1 == NULL || hDstBand2 == NULL ||
    1420                 :         hDstBand3 == NULL)
    1421               0 :         return CE_Failure;
    1422                 : 
    1423               4 :     int nColorAssociation = 0;
    1424                 :     ColorAssociation* pasColorAssociation =
    1425                 :             GDALColorReliefParseColorFile(hSrcBand, pszColorFilename,
    1426               4 :                                           &nColorAssociation);
    1427               4 :     if (pasColorAssociation == NULL)
    1428               0 :         return CE_Failure;
    1429                 : 
    1430               4 :     int nXSize = GDALGetRasterBandXSize(hSrcBand);
    1431               4 :     int nYSize = GDALGetRasterBandYSize(hSrcBand);
    1432                 : 
    1433               4 :     if (pfnProgress == NULL)
    1434               0 :         pfnProgress = GDALDummyProgress;
    1435                 :         
    1436               4 :     int nR = 0, nG = 0, nB = 0, nA = 0;
    1437                 :     
    1438                 : /* -------------------------------------------------------------------- */
    1439                 : /*      Precompute the map from values to RGBA quadruplets              */
    1440                 : /*      for GDT_Byte, GDT_Int16 or GDT_UInt16                           */
    1441                 : /* -------------------------------------------------------------------- */
    1442               4 :     int nIndexOffset = 0;
    1443                 :     GByte* pabyPrecomputed =
    1444                 :         GDALColorReliefPrecompute(hSrcBand,
    1445                 :                                   pasColorAssociation,
    1446                 :                                   nColorAssociation,
    1447                 :                                   eColorSelectionMode,
    1448               4 :                                   &nIndexOffset);
    1449                 : 
    1450                 : /* -------------------------------------------------------------------- */
    1451                 : /*      Initialize progress counter.                                    */
    1452                 : /* -------------------------------------------------------------------- */
    1453                 : 
    1454               4 :     float* pafSourceBuf = NULL;
    1455               4 :     int* panSourceBuf = NULL;
    1456               4 :     if (pabyPrecomputed)
    1457               0 :         panSourceBuf = (int *) CPLMalloc(sizeof(int)*nXSize);
    1458                 :     else
    1459               4 :         pafSourceBuf = (float *) CPLMalloc(sizeof(float)*nXSize);
    1460               4 :     GByte* pabyDestBuf1  = (GByte*) CPLMalloc( 4 * nXSize );
    1461               4 :     GByte* pabyDestBuf2  =  pabyDestBuf1 + nXSize;
    1462               4 :     GByte* pabyDestBuf3  =  pabyDestBuf2 + nXSize;
    1463               4 :     GByte* pabyDestBuf4  =  pabyDestBuf3 + nXSize;
    1464                 :     int i, j;
    1465                 : 
    1466               4 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
    1467                 :     {
    1468               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1469               0 :         eErr = CE_Failure;
    1470               0 :         goto end;
    1471                 :     }
    1472                 : 
    1473             488 :     for ( i = 0; i < nYSize; i++)
    1474                 :     {
    1475                 :         /* Read source buffer */
    1476                 :         eErr = GDALRasterIO(   hSrcBand,
    1477                 :                         GF_Read,
    1478                 :                         0, i,
    1479                 :                         nXSize, 1,
    1480                 :                         (panSourceBuf) ? (void*) panSourceBuf : (void* )pafSourceBuf,
    1481                 :                         nXSize, 1,
    1482                 :                         (panSourceBuf) ? GDT_Int32 : GDT_Float32,
    1483             484 :                         0, 0);
    1484             484 :         if (eErr != CE_None)
    1485               0 :             goto end;
    1486                 : 
    1487             484 :         if (panSourceBuf)
    1488                 :         {
    1489               0 :             for ( j = 0; j < nXSize; j++)
    1490                 :             {
    1491               0 :                 int nIndex = panSourceBuf[j] + nIndexOffset;
    1492               0 :                 pabyDestBuf1[j] = pabyPrecomputed[4 * nIndex];
    1493               0 :                 pabyDestBuf2[j] = pabyPrecomputed[4 * nIndex + 1];
    1494               0 :                 pabyDestBuf3[j] = pabyPrecomputed[4 * nIndex + 2];
    1495               0 :                 pabyDestBuf4[j] = pabyPrecomputed[4 * nIndex + 3];
    1496                 :             }
    1497                 :         }
    1498                 :         else
    1499                 :         {
    1500           59048 :             for ( j = 0; j < nXSize; j++)
    1501                 :             {
    1502                 :                 GDALColorReliefGetRGBA  (pasColorAssociation,
    1503                 :                                          nColorAssociation,
    1504           58564 :                                          pafSourceBuf[j],
    1505                 :                                          eColorSelectionMode,
    1506                 :                                          &nR,
    1507                 :                                          &nG,
    1508                 :                                          &nB,
    1509           58564 :                                          &nA);
    1510           58564 :                 pabyDestBuf1[j] = (GByte) nR;
    1511           58564 :                 pabyDestBuf2[j] = (GByte) nG;
    1512           58564 :                 pabyDestBuf3[j] = (GByte) nB;
    1513           58564 :                 pabyDestBuf4[j] = (GByte) nA;
    1514                 :             }
    1515                 :         }
    1516                 :         
    1517                 :         /* -----------------------------------------
    1518                 :          * Write Line to Raster
    1519                 :          */
    1520                 :         eErr = GDALRasterIO(hDstBand1,
    1521                 :                       GF_Write,
    1522                 :                       0, i, nXSize,
    1523             484 :                       1, pabyDestBuf1, nXSize, 1, GDT_Byte, 0, 0);
    1524             484 :         if (eErr != CE_None)
    1525               0 :             goto end;
    1526                 : 
    1527                 :         eErr = GDALRasterIO(hDstBand2,
    1528                 :                       GF_Write,
    1529                 :                       0, i, nXSize,
    1530             484 :                       1, pabyDestBuf2, nXSize, 1, GDT_Byte, 0, 0);
    1531             484 :         if (eErr != CE_None)
    1532               0 :             goto end;
    1533                 :             
    1534                 :         eErr = GDALRasterIO(hDstBand3,
    1535                 :                       GF_Write,
    1536                 :                       0, i, nXSize,
    1537             484 :                       1, pabyDestBuf3, nXSize, 1, GDT_Byte, 0, 0);
    1538             484 :         if (eErr != CE_None)
    1539               0 :             goto end;
    1540                 :             
    1541             484 :         if (hDstBand4)
    1542                 :         {
    1543                 :             eErr = GDALRasterIO(hDstBand4,
    1544                 :                         GF_Write,
    1545                 :                         0, i, nXSize,
    1546               0 :                         1, pabyDestBuf4, nXSize, 1, GDT_Byte, 0, 0);
    1547               0 :             if (eErr != CE_None)
    1548               0 :                 goto end;
    1549                 :         }
    1550                 : 
    1551             484 :         if( !pfnProgress( 1.0 * (i+1) / nYSize, NULL, pProgressData ) )
    1552                 :         {
    1553               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1554               0 :             eErr = CE_Failure;
    1555               0 :             goto end;
    1556                 :         }
    1557                 :     }
    1558               4 :     pfnProgress( 1.0, NULL, pProgressData );
    1559               4 :     eErr = CE_None;
    1560                 : 
    1561                 : end:
    1562               4 :     VSIFree(pabyPrecomputed);
    1563               4 :     CPLFree(pafSourceBuf);
    1564               4 :     CPLFree(panSourceBuf);
    1565               4 :     CPLFree(pabyDestBuf1);
    1566               4 :     CPLFree(pasColorAssociation);
    1567                 : 
    1568               4 :     return eErr;
    1569                 : }
    1570                 : 
    1571                 : /************************************************************************/
    1572                 : /*                     GDALGenerateVRTColorRelief()                     */
    1573                 : /************************************************************************/
    1574                 : 
    1575               2 : CPLErr GDALGenerateVRTColorRelief(const char* pszDstFilename,
    1576                 :                                GDALDatasetH hSrcDataset,
    1577                 :                                GDALRasterBandH hSrcBand,
    1578                 :                                const char* pszColorFilename,
    1579                 :                                ColorSelectionMode eColorSelectionMode,
    1580                 :                                int bAddAlpha)
    1581                 : {
    1582                 : 
    1583               2 :     int nColorAssociation = 0;
    1584                 :     ColorAssociation* pasColorAssociation =
    1585                 :             GDALColorReliefParseColorFile(hSrcBand, pszColorFilename,
    1586               2 :                                           &nColorAssociation);
    1587               2 :     if (pasColorAssociation == NULL)
    1588               0 :         return CE_Failure;
    1589                 : 
    1590               2 :     int nXSize = GDALGetRasterBandXSize(hSrcBand);
    1591               2 :     int nYSize = GDALGetRasterBandYSize(hSrcBand);
    1592                 : 
    1593               2 :     VSILFILE* fp = VSIFOpenL(pszDstFilename, "wt");
    1594               2 :     if (fp == NULL)
    1595                 :     {
    1596               0 :         CPLFree(pasColorAssociation);
    1597               0 :         return CE_Failure;
    1598                 :     }
    1599                 : 
    1600               2 :     VSIFPrintfL(fp, "<VRTDataset rasterXSize=\"%d\" rasterYSize=\"%d\">\n", nXSize, nYSize);
    1601               2 :     const char* pszProjectionRef = GDALGetProjectionRef(hSrcDataset);
    1602               2 :     if (pszProjectionRef && pszProjectionRef[0] != '\0')
    1603                 :     {
    1604               2 :         char* pszEscapedString = CPLEscapeString(pszProjectionRef, -1, CPLES_XML);
    1605               2 :         VSIFPrintfL(fp, "  <SRS>%s</SRS>\n", pszEscapedString);
    1606               2 :         VSIFree(pszEscapedString);
    1607                 :     }
    1608                 :     double adfGT[6];
    1609               2 :     if (GDALGetGeoTransform(hSrcDataset, adfGT) == CE_None)
    1610                 :     {
    1611                 :         VSIFPrintfL(fp, "  <GeoTransform> %.16g, %.16g, %.16g, "
    1612                 :                         "%.16g, %.16g, %.16g</GeoTransform>\n",
    1613               2 :                         adfGT[0], adfGT[1], adfGT[2], adfGT[3], adfGT[4], adfGT[5]);
    1614                 :     }
    1615               2 :     int nBands = 3 + (bAddAlpha ? 1 : 0);
    1616                 :     int iBand;
    1617                 : 
    1618                 :     int nBlockXSize, nBlockYSize;
    1619               2 :     GDALGetBlockSize(hSrcBand, &nBlockXSize, &nBlockYSize);
    1620                 :     
    1621                 :     int bRelativeToVRT;
    1622               2 :     CPLString osPath = CPLGetPath(pszDstFilename);
    1623                 :     char* pszSourceFilename = CPLStrdup(
    1624                 :         CPLExtractRelativePath( osPath.c_str(), GDALGetDescription(hSrcDataset), 
    1625               2 :                                 &bRelativeToVRT ));
    1626                 : 
    1627               8 :     for(iBand = 0; iBand < nBands; iBand++)
    1628                 :     {
    1629               6 :         VSIFPrintfL(fp, "  <VRTRasterBand dataType=\"Byte\" band=\"%d\">\n", iBand + 1);
    1630                 :         VSIFPrintfL(fp, "    <ColorInterp>%s</ColorInterp>\n",
    1631               6 :                     GDALGetColorInterpretationName((GDALColorInterp)(GCI_RedBand + iBand)));
    1632               6 :         VSIFPrintfL(fp, "    <ComplexSource>\n");
    1633                 :         VSIFPrintfL(fp, "      <SourceFilename relativeToVRT=\"%d\">%s</SourceFilename>\n",
    1634               6 :                         bRelativeToVRT, pszSourceFilename);
    1635               6 :         VSIFPrintfL(fp, "      <SourceBand>%d</SourceBand>\n", GDALGetBandNumber(hSrcBand));
    1636                 :         VSIFPrintfL(fp, "      <SourceProperties RasterXSize=\"%d\" "
    1637                 :                         "RasterYSize=\"%d\" DataType=\"%s\" "
    1638                 :                         "BlockXSize=\"%d\" BlockYSize=\"%d\"/>\n",
    1639                 :                         nXSize, nYSize,
    1640                 :                         GDALGetDataTypeName(GDALGetRasterDataType(hSrcBand)),
    1641               6 :                         nBlockXSize, nBlockYSize);
    1642                 :         VSIFPrintfL(fp, "      <SrcRect xOff=\"0\" yOff=\"0\" xSize=\"%d\" ySize=\"%d\"/>\n",
    1643               6 :                         nXSize, nYSize);
    1644                 :         VSIFPrintfL(fp, "      <DstRect xOff=\"0\" yOff=\"0\" xSize=\"%d\" ySize=\"%d\"/>\n",
    1645               6 :                         nXSize, nYSize);
    1646                 : 
    1647               6 :         VSIFPrintfL(fp, "      <LUT>");
    1648                 :         int iColor;
    1649                 : #define EPSILON 1e-8
    1650              48 :         for(iColor=0;iColor<nColorAssociation;iColor++)
    1651                 :         {
    1652              42 :             if (eColorSelectionMode == COLOR_SELECTION_NEAREST_ENTRY)
    1653                 :             {
    1654              21 :                 if (iColor > 1)
    1655              15 :                     VSIFPrintfL(fp, ",");
    1656                 :             }
    1657              21 :             else if (iColor > 0)
    1658              18 :                 VSIFPrintfL(fp, ",");
    1659                 : 
    1660              42 :             double dfVal = pasColorAssociation[iColor].dfVal;
    1661                 : 
    1662              42 :             if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY)
    1663                 :             {
    1664               0 :                 VSIFPrintfL(fp, "%.12g:0,", dfVal - EPSILON);
    1665                 :             }
    1666              42 :             else if (iColor > 0 &&
    1667                 :                      eColorSelectionMode == COLOR_SELECTION_NEAREST_ENTRY)
    1668                 :             {
    1669              18 :                 double dfMidVal = (dfVal + pasColorAssociation[iColor-1].dfVal) / 2;
    1670                 :                 VSIFPrintfL(fp, "%.12g:%d", dfMidVal - EPSILON,
    1671               6 :                         (iBand == 0) ? pasColorAssociation[iColor-1].nR :
    1672               6 :                         (iBand == 1) ? pasColorAssociation[iColor-1].nG :
    1673               6 :                         (iBand == 2) ? pasColorAssociation[iColor-1].nB :
    1674              36 :                                        pasColorAssociation[iColor-1].nA);
    1675                 :                 VSIFPrintfL(fp, ",%.12g:%d", dfMidVal ,
    1676               6 :                         (iBand == 0) ? pasColorAssociation[iColor].nR :
    1677               6 :                         (iBand == 1) ? pasColorAssociation[iColor].nG :
    1678               6 :                         (iBand == 2) ? pasColorAssociation[iColor].nB :
    1679              36 :                                        pasColorAssociation[iColor].nA);
    1680                 : 
    1681                 :             }
    1682                 : 
    1683              42 :             if (eColorSelectionMode != COLOR_SELECTION_NEAREST_ENTRY)
    1684                 :             {
    1685              21 :                 if (dfVal != (double)(int)dfVal)
    1686               0 :                     VSIFPrintfL(fp, "%.12g", dfVal);
    1687                 :                 else
    1688              21 :                     VSIFPrintfL(fp, "%d", (int)dfVal);
    1689                 :                 VSIFPrintfL(fp, ":%d",
    1690               7 :                             (iBand == 0) ? pasColorAssociation[iColor].nR :
    1691               7 :                             (iBand == 1) ? pasColorAssociation[iColor].nG :
    1692               7 :                             (iBand == 2) ? pasColorAssociation[iColor].nB :
    1693              42 :                                            pasColorAssociation[iColor].nA);
    1694                 :             }
    1695                 : 
    1696              42 :             if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY)
    1697                 :             {
    1698               0 :                 VSIFPrintfL(fp, ",%.12g:0", dfVal + EPSILON);
    1699                 :             }
    1700                 : 
    1701                 :         }
    1702               6 :         VSIFPrintfL(fp, "</LUT>\n");
    1703                 : 
    1704               6 :         VSIFPrintfL(fp, "    </ComplexSource>\n");
    1705               6 :         VSIFPrintfL(fp, "  </VRTRasterBand>\n");
    1706                 :     }
    1707                 : 
    1708               2 :     CPLFree(pszSourceFilename);
    1709                 : 
    1710               2 :     VSIFPrintfL(fp, "</VRTDataset>\n");
    1711                 : 
    1712               2 :     VSIFCloseL(fp);
    1713                 : 
    1714               2 :     CPLFree(pasColorAssociation);
    1715                 : 
    1716               2 :     return CE_None;
    1717                 : }
    1718                 : 
    1719                 : 
    1720                 : /************************************************************************/
    1721                 : /*                         GDALTRIAlg()                                 */
    1722                 : /************************************************************************/
    1723                 : 
    1724               0 : float GDALTRIAlg (float* afWin, float fDstNoDataValue, void* pData)
    1725                 : {
    1726                 :     // Terrain Ruggedness is average difference in height
    1727               0 :     return (fabs(afWin[0]-afWin[4]) +
    1728               0 :             fabs(afWin[1]-afWin[4]) +
    1729               0 :             fabs(afWin[2]-afWin[4]) +
    1730               0 :             fabs(afWin[3]-afWin[4]) +
    1731               0 :             fabs(afWin[5]-afWin[4]) +
    1732               0 :             fabs(afWin[6]-afWin[4]) +
    1733               0 :             fabs(afWin[7]-afWin[4]) +
    1734               0 :             fabs(afWin[8]-afWin[4]))/8;
    1735                 : }
    1736                 : 
    1737                 : 
    1738                 : /************************************************************************/
    1739                 : /*                         GDALTPIAlg()                                 */
    1740                 : /************************************************************************/
    1741                 : 
    1742               0 : float GDALTPIAlg (float* afWin, float fDstNoDataValue, void* pData)
    1743                 : {
    1744                 :     // Terrain Position is the difference between
    1745                 :     // The central cell and the mean of the surrounding cells
    1746               0 :     return afWin[4] - 
    1747               0 :             ((afWin[0]+
    1748               0 :               afWin[1]+
    1749               0 :               afWin[2]+
    1750               0 :               afWin[3]+
    1751               0 :               afWin[5]+
    1752               0 :               afWin[6]+
    1753               0 :               afWin[7]+
    1754               0 :               afWin[8])/8);
    1755                 : }
    1756                 : 
    1757                 : /************************************************************************/
    1758                 : /*                     GDALRoughnessAlg()                               */
    1759                 : /************************************************************************/
    1760                 : 
    1761               0 : float GDALRoughnessAlg (float* afWin, float fDstNoDataValue, void* pData)
    1762                 : {
    1763                 :     // Roughness is the largest difference
    1764                 :     //  between any two cells
    1765                 : 
    1766               0 :     float pafRoughnessMin = afWin[0];
    1767               0 :     float pafRoughnessMax = afWin[0];
    1768                 : 
    1769               0 :     for ( int k = 1; k < 9; k++)
    1770                 :     {
    1771               0 :         if (afWin[k] > pafRoughnessMax)
    1772                 :         {
    1773               0 :             pafRoughnessMax=afWin[k];
    1774                 :         }
    1775               0 :         if (afWin[k] < pafRoughnessMin)
    1776                 :         {
    1777               0 :             pafRoughnessMin=afWin[k];
    1778                 :         }
    1779                 :     }
    1780               0 :     return pafRoughnessMax - pafRoughnessMin;
    1781                 : }
    1782                 : 
    1783                 : /************************************************************************/
    1784                 : /* ==================================================================== */
    1785                 : /*                       GDALGeneric3x3Dataset                        */
    1786                 : /* ==================================================================== */
    1787                 : /************************************************************************/
    1788                 : 
    1789                 : class GDALGeneric3x3RasterBand;
    1790                 : 
    1791                 : class GDALGeneric3x3Dataset : public GDALDataset
    1792                 : {
    1793                 :     friend class GDALGeneric3x3RasterBand;
    1794                 : 
    1795                 :     GDALGeneric3x3ProcessingAlg pfnAlg;
    1796                 :     void*              pAlgData;
    1797                 :     GDALDatasetH       hSrcDS;
    1798                 :     GDALRasterBandH    hSrcBand;
    1799                 :     float*             apafSourceBuf[3];
    1800                 :     int                bDstHasNoData;
    1801                 :     double             dfDstNoDataValue;
    1802                 :     int                nCurLine;
    1803                 :     int                bComputeAtEdges;
    1804                 : 
    1805                 :   public:
    1806                 :                         GDALGeneric3x3Dataset(GDALDatasetH hSrcDS,
    1807                 :                                               GDALRasterBandH hSrcBand,
    1808                 :                                               GDALDataType eDstDataType,
    1809                 :                                               int bDstHasNoData,
    1810                 :                                               double dfDstNoDataValue,
    1811                 :                                               GDALGeneric3x3ProcessingAlg pfnAlg,
    1812                 :                                               void* pAlgData,
    1813                 :                                               int bComputeAtEdges);
    1814                 :                        ~GDALGeneric3x3Dataset();
    1815                 : 
    1816                 :     CPLErr      GetGeoTransform( double * padfGeoTransform );
    1817                 :     const char *GetProjectionRef();
    1818                 : };
    1819                 : 
    1820                 : /************************************************************************/
    1821                 : /* ==================================================================== */
    1822                 : /*                    GDALGeneric3x3RasterBand                       */
    1823                 : /* ==================================================================== */
    1824                 : /************************************************************************/
    1825                 : 
    1826                 : class GDALGeneric3x3RasterBand : public GDALRasterBand
    1827               2 : {
    1828                 :     friend class GDALGeneric3x3Dataset;
    1829                 :     int bSrcHasNoData;
    1830                 :     float fSrcNoDataValue;
    1831                 :     
    1832                 :     void                    InitWidthNoData(void* pImage);
    1833                 :     
    1834                 :   public:
    1835                 :                  GDALGeneric3x3RasterBand( GDALGeneric3x3Dataset *poDS,
    1836                 :                                            GDALDataType eDstDataType );
    1837                 :     
    1838                 :     virtual CPLErr          IReadBlock( int, int, void * );
    1839                 :     virtual double          GetNoDataValue( int* pbHasNoData );
    1840                 : };
    1841                 : 
    1842               2 : GDALGeneric3x3Dataset::GDALGeneric3x3Dataset(
    1843                 :                                      GDALDatasetH hSrcDS,
    1844                 :                                      GDALRasterBandH hSrcBand,
    1845                 :                                      GDALDataType eDstDataType,
    1846                 :                                      int bDstHasNoData,
    1847                 :                                      double dfDstNoDataValue,
    1848                 :                                      GDALGeneric3x3ProcessingAlg pfnAlg,
    1849                 :                                      void* pAlgData,
    1850               2 :                                      int bComputeAtEdges)
    1851                 : {
    1852               2 :     this->hSrcDS = hSrcDS;
    1853               2 :     this->hSrcBand = hSrcBand;
    1854               2 :     this->pfnAlg = pfnAlg;
    1855               2 :     this->pAlgData = pAlgData;
    1856               2 :     this->bDstHasNoData = bDstHasNoData;
    1857               2 :     this->dfDstNoDataValue = dfDstNoDataValue;
    1858               2 :     this->bComputeAtEdges = bComputeAtEdges;
    1859                 :     
    1860               2 :     CPLAssert(eDstDataType == GDT_Byte || eDstDataType == GDT_Float32);
    1861                 : 
    1862               2 :     nRasterXSize = GDALGetRasterXSize(hSrcDS);
    1863               2 :     nRasterYSize = GDALGetRasterYSize(hSrcDS);
    1864                 :     
    1865               2 :     SetBand(1, new GDALGeneric3x3RasterBand(this, eDstDataType));
    1866                 :     
    1867               2 :     apafSourceBuf[0] = (float *) CPLMalloc(sizeof(float)*nRasterXSize);
    1868               2 :     apafSourceBuf[1] = (float *) CPLMalloc(sizeof(float)*nRasterXSize);
    1869               2 :     apafSourceBuf[2] = (float *) CPLMalloc(sizeof(float)*nRasterXSize);
    1870                 : 
    1871               2 :     nCurLine = -1;
    1872               2 : }
    1873                 : 
    1874               2 : GDALGeneric3x3Dataset::~GDALGeneric3x3Dataset()
    1875                 : {
    1876               2 :     CPLFree(apafSourceBuf[0]);
    1877               2 :     CPLFree(apafSourceBuf[1]);
    1878               2 :     CPLFree(apafSourceBuf[2]);
    1879               2 : }
    1880                 : 
    1881               2 : CPLErr GDALGeneric3x3Dataset::GetGeoTransform( double * padfGeoTransform )
    1882                 : {
    1883               2 :     return GDALGetGeoTransform(hSrcDS, padfGeoTransform);
    1884                 : }
    1885                 : 
    1886               2 : const char *GDALGeneric3x3Dataset::GetProjectionRef()
    1887                 : {
    1888               2 :     return GDALGetProjectionRef(hSrcDS);
    1889                 : }
    1890                 : 
    1891               2 : GDALGeneric3x3RasterBand::GDALGeneric3x3RasterBand(GDALGeneric3x3Dataset *poDS,
    1892               2 :                                                    GDALDataType eDstDataType)
    1893                 : {
    1894               2 :     this->poDS = poDS;
    1895               2 :     this->nBand = 1;
    1896               2 :     eDataType = eDstDataType;
    1897               2 :     nBlockXSize = poDS->GetRasterXSize();
    1898               2 :     nBlockYSize = 1;
    1899                 : 
    1900               2 :     bSrcHasNoData = FALSE;
    1901                 :     fSrcNoDataValue = (float)GDALGetRasterNoDataValue(poDS->hSrcBand,
    1902               2 :                                                       &bSrcHasNoData);
    1903               2 : }
    1904                 : 
    1905               2 : void   GDALGeneric3x3RasterBand::InitWidthNoData(void* pImage)
    1906                 : {
    1907                 :     int j;
    1908               2 :     GDALGeneric3x3Dataset * poGDS = (GDALGeneric3x3Dataset *) poDS;
    1909               2 :     if (eDataType == GDT_Byte)
    1910                 :     {
    1911             244 :         for(j=0;j<nBlockXSize;j++)
    1912             242 :             ((GByte*)pImage)[j] = (GByte) poGDS->dfDstNoDataValue;
    1913                 :     }
    1914                 :     else
    1915                 :     {
    1916               0 :         for(j=0;j<nBlockXSize;j++)
    1917               0 :             ((float*)pImage)[j] = (float) poGDS->dfDstNoDataValue;
    1918                 :     }
    1919               2 : }
    1920                 : 
    1921             242 : CPLErr GDALGeneric3x3RasterBand::IReadBlock( int nBlockXOff,
    1922                 :                                              int nBlockYOff,
    1923                 :                                              void *pImage )
    1924                 : {
    1925                 :     int i, j;
    1926                 :     float fVal;
    1927             242 :     GDALGeneric3x3Dataset * poGDS = (GDALGeneric3x3Dataset *) poDS;
    1928                 : 
    1929             361 :     if (poGDS->bComputeAtEdges && nRasterXSize >= 2 && nRasterYSize >= 2)
    1930                 :     {
    1931             121 :         if (nBlockYOff == 0)
    1932                 :         {
    1933               3 :             for(i=0;i<2;i++)
    1934                 :             {
    1935                 :                 CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
    1936                 :                                     GF_Read,
    1937                 :                                     0, i, nBlockXSize, 1,
    1938               2 :                                     poGDS->apafSourceBuf[i+1],
    1939                 :                                     nBlockXSize, 1,
    1940                 :                                     GDT_Float32,
    1941               4 :                                     0, 0);
    1942               2 :                 if (eErr != CE_None)
    1943                 :                 {
    1944               0 :                     InitWidthNoData(pImage);
    1945               0 :                     return eErr;
    1946                 :                 }
    1947                 :             }
    1948               1 :             poGDS->nCurLine = 0;
    1949                 : 
    1950             122 :             for (j = 0; j < nRasterXSize; j++)
    1951                 :             {
    1952                 :                 float afWin[9];
    1953             121 :                 int jmin = (j == 0) ? j : j - 1;
    1954             121 :                 int jmax = (j == nRasterXSize - 1) ? j : j + 1;
    1955                 : 
    1956             121 :                 afWin[0] = INTERPOL(poGDS->apafSourceBuf[1][jmin], poGDS->apafSourceBuf[2][jmin]);
    1957             121 :                 afWin[1] = INTERPOL(poGDS->apafSourceBuf[1][j],    poGDS->apafSourceBuf[2][j]);
    1958             121 :                 afWin[2] = INTERPOL(poGDS->apafSourceBuf[1][jmax], poGDS->apafSourceBuf[2][jmax]);
    1959             121 :                 afWin[3] = poGDS->apafSourceBuf[1][jmin];
    1960             121 :                 afWin[4] = poGDS->apafSourceBuf[1][j];
    1961             121 :                 afWin[5] = poGDS->apafSourceBuf[1][jmax];
    1962             121 :                 afWin[6] = poGDS->apafSourceBuf[2][jmin];
    1963             121 :                 afWin[7] = poGDS->apafSourceBuf[2][j];
    1964             121 :                 afWin[8] = poGDS->apafSourceBuf[2][jmax];
    1965                 : 
    1966                 :                 fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
    1967                 :                                     afWin, (float) poGDS->dfDstNoDataValue,
    1968                 :                                     poGDS->pfnAlg,
    1969                 :                                     poGDS->pAlgData,
    1970             121 :                                     poGDS->bComputeAtEdges);
    1971                 : 
    1972             121 :                 if (eDataType == GDT_Byte)
    1973             121 :                     ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
    1974                 :                 else
    1975               0 :                     ((float*)pImage)[j] = fVal;
    1976                 :             }
    1977                 : 
    1978               1 :             return CE_None;
    1979                 :         }
    1980             120 :         else if (nBlockYOff == nRasterYSize - 1)
    1981                 :         {
    1982               1 :             if (poGDS->nCurLine != nRasterYSize - 2)
    1983                 :             {
    1984               0 :                 for(i=0;i<2;i++)
    1985                 :                 {
    1986                 :                     CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
    1987                 :                                         GF_Read,
    1988                 :                                         0, nRasterYSize - 2 + i, nBlockXSize, 1,
    1989               0 :                                         poGDS->apafSourceBuf[i+1],
    1990                 :                                         nBlockXSize, 1,
    1991                 :                                         GDT_Float32,
    1992               0 :                                         0, 0);
    1993               0 :                     if (eErr != CE_None)
    1994                 :                     {
    1995               0 :                         InitWidthNoData(pImage);
    1996               0 :                         return eErr;
    1997                 :                     }
    1998                 :                 }
    1999                 :             }
    2000                 : 
    2001             122 :             for (j = 0; j < nRasterXSize; j++)
    2002                 :             {
    2003                 :                 float afWin[9];
    2004             121 :                 int jmin = (j == 0) ? j : j - 1;
    2005             121 :                 int jmax = (j == nRasterXSize - 1) ? j : j + 1;
    2006                 : 
    2007             121 :                 afWin[0] = poGDS->apafSourceBuf[1][jmin];
    2008             121 :                 afWin[1] = poGDS->apafSourceBuf[1][j];
    2009             121 :                 afWin[2] = poGDS->apafSourceBuf[1][jmax];
    2010             121 :                 afWin[3] = poGDS->apafSourceBuf[2][jmin];
    2011             121 :                 afWin[4] = poGDS->apafSourceBuf[2][j];
    2012             121 :                 afWin[5] = poGDS->apafSourceBuf[2][jmax];
    2013             121 :                 afWin[6] = INTERPOL(poGDS->apafSourceBuf[2][jmin], poGDS->apafSourceBuf[1][jmin]);
    2014             121 :                 afWin[7] = INTERPOL(poGDS->apafSourceBuf[2][j],    poGDS->apafSourceBuf[1][j]);
    2015             121 :                 afWin[8] = INTERPOL(poGDS->apafSourceBuf[2][jmax], poGDS->apafSourceBuf[1][jmax]);
    2016                 : 
    2017                 :                 fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
    2018                 :                                     afWin, (float) poGDS->dfDstNoDataValue,
    2019                 :                                     poGDS->pfnAlg,
    2020                 :                                     poGDS->pAlgData,
    2021             121 :                                     poGDS->bComputeAtEdges);
    2022                 : 
    2023             121 :                 if (eDataType == GDT_Byte)
    2024             121 :                     ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
    2025                 :                 else
    2026               0 :                     ((float*)pImage)[j] = fVal;
    2027                 :             }
    2028                 : 
    2029               1 :             return CE_None;
    2030                 :         }
    2031                 :     }
    2032             121 :     else if ( nBlockYOff == 0 || nBlockYOff == nRasterYSize - 1)
    2033                 :     {
    2034               2 :         InitWidthNoData(pImage);
    2035               2 :         return CE_None;
    2036                 :     }
    2037                 : 
    2038             238 :     if ( poGDS->nCurLine != nBlockYOff )
    2039                 :     {
    2040             238 :         if (poGDS->nCurLine + 1 == nBlockYOff)
    2041                 :         {
    2042             237 :             float* pafTmp =  poGDS->apafSourceBuf[0];
    2043             237 :             poGDS->apafSourceBuf[0] = poGDS->apafSourceBuf[1];
    2044             237 :             poGDS->apafSourceBuf[1] = poGDS->apafSourceBuf[2];
    2045             237 :             poGDS->apafSourceBuf[2] = pafTmp;
    2046                 : 
    2047                 :             CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
    2048                 :                                     GF_Read,
    2049                 :                                     0, nBlockYOff + 1, nBlockXSize, 1,
    2050             237 :                                     poGDS->apafSourceBuf[2],
    2051                 :                                     nBlockXSize, 1,
    2052                 :                                     GDT_Float32,
    2053             474 :                                     0, 0);
    2054                 : 
    2055             237 :             if (eErr != CE_None)
    2056                 :             {
    2057               0 :                 InitWidthNoData(pImage);
    2058               0 :                 return eErr;
    2059                 :             }
    2060                 :         }
    2061                 :         else
    2062                 :         {
    2063               4 :             for(i=0;i<3;i++)
    2064                 :             {
    2065                 :                 CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
    2066                 :                                     GF_Read,
    2067                 :                                     0, nBlockYOff + i - 1, nBlockXSize, 1,
    2068               3 :                                     poGDS->apafSourceBuf[i],
    2069                 :                                     nBlockXSize, 1,
    2070                 :                                     GDT_Float32,
    2071               6 :                                     0, 0);
    2072               3 :                 if (eErr != CE_None)
    2073                 :                 {
    2074               0 :                     InitWidthNoData(pImage);
    2075               0 :                     return eErr;
    2076                 :                 }
    2077                 :             }
    2078                 :         }
    2079                 : 
    2080             238 :         poGDS->nCurLine = nBlockYOff;
    2081                 :     }
    2082                 : 
    2083             357 :     if (poGDS->bComputeAtEdges && nRasterXSize >= 2)
    2084                 :     {
    2085                 :         float afWin[9];
    2086                 : 
    2087             119 :         j = 0;
    2088             119 :         afWin[0] = INTERPOL(poGDS->apafSourceBuf[0][j], poGDS->apafSourceBuf[0][j+1]);
    2089             119 :         afWin[1] = poGDS->apafSourceBuf[0][j];
    2090             119 :         afWin[2] = poGDS->apafSourceBuf[0][j+1];
    2091             119 :         afWin[3] = INTERPOL(poGDS->apafSourceBuf[1][j], poGDS->apafSourceBuf[1][j+1]);
    2092             119 :         afWin[4] = poGDS->apafSourceBuf[1][j];
    2093             119 :         afWin[5] = poGDS->apafSourceBuf[1][j+1];
    2094             119 :         afWin[6] = INTERPOL(poGDS->apafSourceBuf[2][j], poGDS->apafSourceBuf[2][j+1]);
    2095             119 :         afWin[7] = poGDS->apafSourceBuf[2][j];
    2096             119 :         afWin[8] = poGDS->apafSourceBuf[2][j+1];
    2097                 : 
    2098                 :         fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
    2099                 :                                     afWin, (float) poGDS->dfDstNoDataValue,
    2100                 :                                     poGDS->pfnAlg,
    2101                 :                                     poGDS->pAlgData,
    2102             119 :                                     poGDS->bComputeAtEdges);
    2103                 : 
    2104             119 :         if (eDataType == GDT_Byte)
    2105             119 :             ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
    2106                 :         else
    2107               0 :             ((float*)pImage)[j] = fVal;
    2108                 : 
    2109             119 :         j = nRasterXSize - 1;
    2110                 : 
    2111             119 :         afWin[0] = poGDS->apafSourceBuf[0][j-1];
    2112             119 :         afWin[1] = poGDS->apafSourceBuf[0][j];
    2113             119 :         afWin[2] = INTERPOL(poGDS->apafSourceBuf[0][j], poGDS->apafSourceBuf[0][j-1]);
    2114             119 :         afWin[3] = poGDS->apafSourceBuf[1][j-1];
    2115             119 :         afWin[4] = poGDS->apafSourceBuf[1][j];
    2116             119 :         afWin[5] = INTERPOL(poGDS->apafSourceBuf[1][j], poGDS->apafSourceBuf[1][j-1]);
    2117             119 :         afWin[6] = poGDS->apafSourceBuf[2][j-1];
    2118             119 :         afWin[7] = poGDS->apafSourceBuf[2][j];
    2119             119 :         afWin[8] = INTERPOL(poGDS->apafSourceBuf[2][j], poGDS->apafSourceBuf[2][j-1]);
    2120                 : 
    2121                 :         fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
    2122                 :                                     afWin, (float) poGDS->dfDstNoDataValue,
    2123                 :                                     poGDS->pfnAlg,
    2124                 :                                     poGDS->pAlgData,
    2125             119 :                                     poGDS->bComputeAtEdges);
    2126                 : 
    2127             119 :         if (eDataType == GDT_Byte)
    2128             119 :             ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
    2129                 :         else
    2130               0 :             ((float*)pImage)[j] = fVal;
    2131                 :     }
    2132                 :     else
    2133                 :     {
    2134             119 :         if (eDataType == GDT_Byte)
    2135                 :         {
    2136             119 :             ((GByte*)pImage)[0] = (GByte) poGDS->dfDstNoDataValue;
    2137             119 :             if (nBlockXSize > 1)
    2138             119 :                 ((GByte*)pImage)[nBlockXSize - 1] = (GByte) poGDS->dfDstNoDataValue;
    2139                 :         }
    2140                 :         else
    2141                 :         {
    2142               0 :             ((float*)pImage)[0] = (float) poGDS->dfDstNoDataValue;
    2143               0 :             if (nBlockXSize > 1)
    2144               0 :                 ((float*)pImage)[nBlockXSize - 1] = (float) poGDS->dfDstNoDataValue;
    2145                 :         }
    2146                 :     }
    2147                 : 
    2148                 : 
    2149           28560 :     for(j=1;j<nBlockXSize - 1;j++)
    2150                 :     {
    2151                 :         float afWin[9];
    2152           28322 :         afWin[0] = poGDS->apafSourceBuf[0][j-1];
    2153           28322 :         afWin[1] = poGDS->apafSourceBuf[0][j];
    2154           28322 :         afWin[2] = poGDS->apafSourceBuf[0][j+1];
    2155           28322 :         afWin[3] = poGDS->apafSourceBuf[1][j-1];
    2156           28322 :         afWin[4] = poGDS->apafSourceBuf[1][j];
    2157           28322 :         afWin[5] = poGDS->apafSourceBuf[1][j+1];
    2158           28322 :         afWin[6] = poGDS->apafSourceBuf[2][j-1];
    2159           28322 :         afWin[7] = poGDS->apafSourceBuf[2][j];
    2160           28322 :         afWin[8] = poGDS->apafSourceBuf[2][j+1];
    2161                 : 
    2162                 :         fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
    2163                 :                                 afWin, (float) poGDS->dfDstNoDataValue,
    2164                 :                                 poGDS->pfnAlg,
    2165                 :                                 poGDS->pAlgData,
    2166           28322 :                                 poGDS->bComputeAtEdges);
    2167                 : 
    2168           28322 :         if (eDataType == GDT_Byte)
    2169           28322 :             ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
    2170                 :         else
    2171               0 :             ((float*)pImage)[j] = fVal;
    2172                 : 
    2173                 :     }
    2174                 : 
    2175             238 :     return CE_None;
    2176                 : }
    2177                 : 
    2178               8 : double GDALGeneric3x3RasterBand::GetNoDataValue( int* pbHasNoData )
    2179                 : {
    2180               8 :     GDALGeneric3x3Dataset * poGDS = (GDALGeneric3x3Dataset *) poDS;
    2181               8 :     if (pbHasNoData)
    2182               6 :         *pbHasNoData = poGDS->bDstHasNoData;
    2183               8 :     return poGDS->dfDstNoDataValue;
    2184                 : }
    2185                 : 
    2186                 : /************************************************************************/
    2187                 : /*                                main()                                */
    2188                 : /************************************************************************/
    2189                 : 
    2190                 : typedef enum
    2191                 : {
    2192                 :     HILL_SHADE,
    2193                 :     SLOPE,
    2194                 :     ASPECT,
    2195                 :     COLOR_RELIEF,
    2196                 :     TRI,
    2197                 :     TPI,
    2198                 :     ROUGHNESS
    2199                 : } Algorithm;
    2200                 : 
    2201                 : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
    2202                 :     do { if (i + nExtraArg >= argc) \
    2203                 :         Usage(CPLSPrintf("%s option requires %d argument(s)", argv[i], nExtraArg)); } while(0)
    2204                 : 
    2205              17 : int main( int argc, char ** argv )
    2206                 : 
    2207                 : {
    2208              17 :     Algorithm eUtilityMode = HILL_SHADE;
    2209              17 :     double z = 1.0;
    2210              17 :     double scale = 1.0;
    2211              17 :     double az = 315.0;
    2212              17 :     double alt = 45.0;
    2213                 :     // 0 = 'percent' or 1 = 'degrees'
    2214              17 :     int slopeFormat = 1; 
    2215              17 :     int bAddAlpha = FALSE;
    2216              17 :     int bZeroForFlat = FALSE;
    2217              17 :     int bAngleAsAzimuth = TRUE;
    2218              17 :     ColorSelectionMode eColorSelectionMode = COLOR_SELECTION_INTERPOLATE;
    2219                 :     
    2220              17 :     int nBand = 1;
    2221                 :     double  adfGeoTransform[6];
    2222                 : 
    2223              17 :     const char *pszSrcFilename = NULL;
    2224              17 :     const char *pszDstFilename = NULL;
    2225              17 :     const char *pszColorFilename = NULL;
    2226              17 :     const char *pszFormat = "GTiff";
    2227              17 :     int bFormatExplicitelySet = FALSE;
    2228              17 :     char **papszCreateOptions = NULL;
    2229                 :     
    2230              17 :     GDALDatasetH hSrcDataset = NULL;
    2231              17 :     GDALDatasetH hDstDataset = NULL;
    2232              17 :     GDALRasterBandH hSrcBand = NULL;
    2233              17 :     GDALRasterBandH hDstBand = NULL;
    2234              17 :     GDALDriverH hDriver = NULL;
    2235                 : 
    2236              17 :     GDALProgressFunc pfnProgress = GDALTermProgress;
    2237                 :     
    2238              17 :     int nXSize = 0;
    2239              17 :     int nYSize = 0;
    2240                 :     
    2241              17 :     int bComputeAtEdges = FALSE;
    2242              17 :     int bZevenbergenThorne = FALSE;
    2243              17 :     int bCombined = FALSE;
    2244              17 :     int bQuiet = FALSE;
    2245                 :     
    2246                 :     /* Check strict compilation and runtime library version as we use C++ API */
    2247              17 :     if (! GDAL_CHECK_VERSION(argv[0]))
    2248               0 :         exit(1);
    2249                 : 
    2250              17 :     argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
    2251              17 :     if( argc < 2 )
    2252                 :     {
    2253               0 :         Usage("Not enough arguments.");
    2254                 :     }
    2255                 : 
    2256              17 :     if( EQUAL(argv[1], "--utility_version") || EQUAL(argv[1], "--utility-version") )
    2257                 :     {
    2258                 :         printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
    2259               1 :                 argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
    2260               1 :         return 0;
    2261                 :     }
    2262              16 :     else if( EQUAL(argv[1],"--help") )
    2263               0 :         Usage();
    2264              22 :     else if ( EQUAL(argv[1], "shade") || EQUAL(argv[1], "hillshade") )
    2265                 :     {
    2266               6 :         eUtilityMode = HILL_SHADE;
    2267                 :     }
    2268              10 :     else if ( EQUAL(argv[1], "slope") )
    2269                 :     {
    2270               1 :         eUtilityMode = SLOPE;
    2271                 :     }
    2272               9 :     else if ( EQUAL(argv[1], "aspect") )
    2273                 :     {
    2274               1 :         eUtilityMode = ASPECT;
    2275                 :     }
    2276               8 :     else if ( EQUAL(argv[1], "color-relief") )
    2277                 :     {
    2278               8 :         eUtilityMode = COLOR_RELIEF;
    2279                 :     }
    2280               0 :     else if ( EQUAL(argv[1], "TRI") )
    2281                 :     {
    2282               0 :         eUtilityMode = TRI;
    2283                 :     }
    2284               0 :     else if ( EQUAL(argv[1], "TPI") )
    2285                 :     {
    2286               0 :         eUtilityMode = TPI;
    2287                 :     }
    2288               0 :     else if ( EQUAL(argv[1], "roughness") )
    2289                 :     {
    2290               0 :         eUtilityMode = ROUGHNESS;
    2291                 :     }
    2292                 :     else
    2293                 :     {
    2294               0 :         Usage("Missing valid sub-utility mention.");
    2295                 :     }
    2296                 : 
    2297                 : /* -------------------------------------------------------------------- */
    2298                 : /*      Parse arguments.                                                */
    2299                 : /* -------------------------------------------------------------------- */
    2300              82 :     for(int i = 2; i < argc; i++ )
    2301                 :     {
    2302             134 :         if( eUtilityMode == HILL_SHADE &&
    2303              62 :             (EQUAL(argv[i], "--z") || EQUAL(argv[i], "-z")))
    2304                 :         {
    2305               6 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    2306               6 :             z = atof(argv[++i]);
    2307                 :         }
    2308              60 :         else if ( eUtilityMode == SLOPE && EQUAL(argv[i], "-p"))
    2309                 :         {
    2310               0 :             slopeFormat = 0;
    2311                 :         }
    2312              90 :         else if ( (eUtilityMode == HILL_SHADE || eUtilityMode == SLOPE ||
    2313              30 :                    eUtilityMode == ASPECT) && EQUAL(argv[i], "-alg") )
    2314                 :         {
    2315               0 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    2316               0 :             i ++;
    2317               0 :             if (EQUAL(argv[i], "ZevenbergenThorne"))
    2318               0 :                 bZevenbergenThorne = TRUE;
    2319               0 :             else if (!EQUAL(argv[i], "Horn"))
    2320                 :             {
    2321               0 :                 Usage(CPLSPrintf("Wrong value for alg : %s.", argv[i]));
    2322                 :             }
    2323                 :         }
    2324              60 :         else if ( eUtilityMode == ASPECT && EQUAL(argv[i], "-trigonometric"))
    2325                 :         {
    2326               0 :             bAngleAsAzimuth = FALSE;
    2327                 :         }
    2328              60 :         else if ( eUtilityMode == ASPECT && EQUAL(argv[i], "-zero_for_flat"))
    2329                 :         {
    2330               0 :             bZeroForFlat = TRUE;
    2331                 :         }
    2332              60 :         else if ( eUtilityMode == COLOR_RELIEF && EQUAL(argv[i], "-exact_color_entry"))
    2333                 :         {
    2334               0 :             eColorSelectionMode = COLOR_SELECTION_EXACT_ENTRY;
    2335                 :         }
    2336              62 :         else if ( eUtilityMode == COLOR_RELIEF && EQUAL(argv[i], "-nearest_color_entry"))
    2337                 :         {
    2338               2 :             eColorSelectionMode = COLOR_SELECTION_NEAREST_ENTRY;
    2339                 :         }
    2340             283 :         else if( 
    2341              58 :             (EQUAL(argv[i], "--s") || 
    2342              58 :              EQUAL(argv[i], "-s") ||
    2343              51 :              EQUAL(argv[i], "--scale") ||
    2344              51 :              EQUAL(argv[i], "-scale"))
    2345                 :           )
    2346                 :         {
    2347               7 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    2348               7 :             scale = atof(argv[++i]);
    2349                 :         }
    2350             126 :         else if( eUtilityMode == HILL_SHADE &&
    2351              19 :             (EQUAL(argv[i], "--az") || 
    2352              19 :              EQUAL(argv[i], "-az") ||
    2353              18 :              EQUAL(argv[i], "--azimuth") ||
    2354              18 :              EQUAL(argv[i], "-azimuth"))
    2355                 :           )
    2356                 :         {
    2357               1 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    2358               1 :             az = atof(argv[++i]);
    2359                 :         }
    2360             122 :         else if( eUtilityMode == HILL_SHADE &&
    2361              18 :             (EQUAL(argv[i], "--alt") || 
    2362              18 :              EQUAL(argv[i], "-alt") ||
    2363              18 :              EQUAL(argv[i], "--alt") ||
    2364              18 :              EQUAL(argv[i], "-alt"))
    2365                 :           )
    2366                 :         {
    2367               0 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    2368               0 :             alt = atof(argv[++i]);
    2369                 :         }
    2370              86 :         else if( eUtilityMode == HILL_SHADE &&
    2371              18 :             (EQUAL(argv[i], "-combined") || 
    2372              17 :              EQUAL(argv[i], "--combined"))
    2373                 :           )
    2374                 :         {
    2375               1 :             bCombined = TRUE;
    2376                 :         }
    2377              77 :         else if( eUtilityMode == COLOR_RELIEF &&
    2378              28 :                  EQUAL(argv[i], "-alpha"))
    2379                 :         {
    2380               0 :             bAddAlpha = TRUE;
    2381                 :         }
    2382              72 :         else if( eUtilityMode != COLOR_RELIEF &&
    2383              21 :                  EQUAL(argv[i], "-compute_edges"))
    2384                 :         {
    2385               2 :             bComputeAtEdges = TRUE;
    2386                 :         }
    2387             109 :         else if( i + 1 < argc &&
    2388              31 :             (EQUAL(argv[i], "--b") || 
    2389              31 :              EQUAL(argv[i], "-b"))
    2390                 :           )
    2391                 :         {
    2392               0 :             nBand = atoi(argv[++i]);
    2393                 :         }
    2394              47 :         else if ( EQUAL(argv[i], "-q") || EQUAL(argv[i], "-quiet") )
    2395                 :         {
    2396               0 :             pfnProgress = GDALDummyProgress;
    2397               0 :             bQuiet = TRUE;
    2398                 :         }
    2399              47 :         else if( EQUAL(argv[i],"-co") )
    2400                 :         {
    2401               1 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    2402               1 :             papszCreateOptions = CSLAddString( papszCreateOptions, argv[++i] );
    2403                 :         }
    2404              46 :         else if( EQUAL(argv[i],"-of") )
    2405                 :         {
    2406               6 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    2407               6 :             pszFormat = argv[++i];
    2408               6 :             bFormatExplicitelySet = TRUE;
    2409                 :         }
    2410              40 :         else if( argv[i][0] == '-' )
    2411                 :         {
    2412               0 :             Usage(CPLSPrintf("Unkown option name '%s'", argv[i]));
    2413                 :         }
    2414              40 :         else if( pszSrcFilename == NULL )
    2415                 :         {
    2416              16 :             pszSrcFilename = argv[i];
    2417                 :         }
    2418              32 :         else if( eUtilityMode == COLOR_RELIEF && pszColorFilename == NULL )
    2419                 :         {
    2420               8 :             pszColorFilename = argv[i];
    2421                 :         }
    2422              16 :         else if( pszDstFilename == NULL )
    2423                 :         {
    2424              16 :             pszDstFilename = argv[i];
    2425                 :         }
    2426                 :         else
    2427               0 :             Usage("Too many command options.");
    2428                 :     }
    2429                 : 
    2430              16 :     if( pszSrcFilename == NULL )
    2431                 :     {
    2432               0 :         Usage("Missing source.");
    2433                 :     }
    2434              16 :     if ( eUtilityMode == COLOR_RELIEF && pszColorFilename == NULL )
    2435                 :     {
    2436               0 :         Usage("Missing color file.");
    2437                 :     }
    2438              16 :     if( pszDstFilename == NULL )
    2439                 :     {
    2440               0 :         Usage("Missing destination.");
    2441                 :     }
    2442                 : 
    2443              16 :     GDALAllRegister();
    2444                 : 
    2445                 :     // Open Dataset and get raster band
    2446              16 :     hSrcDataset = GDALOpen( pszSrcFilename, GA_ReadOnly );
    2447                 :     
    2448              16 :     if( hSrcDataset == NULL )
    2449                 :     {
    2450                 :         fprintf( stderr,
    2451                 :                  "GDALOpen failed - %d\n%s\n",
    2452               0 :                  CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
    2453               0 :         GDALDestroyDriverManager();
    2454               0 :         exit( 1 );
    2455                 :     }
    2456                 : 
    2457              16 :     nXSize = GDALGetRasterXSize(hSrcDataset);
    2458              16 :     nYSize = GDALGetRasterYSize(hSrcDataset);
    2459                 : 
    2460              16 :     if( nBand <= 0 || nBand > GDALGetRasterCount(hSrcDataset) )
    2461                 :     {
    2462                 :         fprintf( stderr,
    2463               0 :                  "Unable to fetch band #%d\n", nBand );
    2464               0 :         GDALDestroyDriverManager();
    2465               0 :         exit( 1 );
    2466                 :     }
    2467              16 :     hSrcBand = GDALGetRasterBand( hSrcDataset, nBand );
    2468                 : 
    2469              16 :     GDALGetGeoTransform(hSrcDataset, adfGeoTransform);
    2470                 : 
    2471              16 :     hDriver = GDALGetDriverByName(pszFormat);
    2472              16 :     if( hDriver == NULL 
    2473                 :         || (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL &&
    2474                 :             GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) == NULL))
    2475                 :     {
    2476                 :         int iDr;
    2477                 : 
    2478                 :         fprintf( stderr, "Output driver `%s' not recognised to have\n", 
    2479               0 :                  pszFormat );
    2480                 :         fprintf( stderr, "output support.  The following format drivers are configured\n"
    2481               0 :                 "and support output:\n" );
    2482                 : 
    2483               0 :         for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
    2484                 :         {
    2485               0 :             GDALDriverH hDriver = GDALGetDriver(iDr);
    2486                 : 
    2487               0 :             if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL ||
    2488                 :                 GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL )
    2489                 :             {
    2490                 :                 printf( "  %s: %s\n",
    2491                 :                         GDALGetDriverShortName( hDriver  ),
    2492               0 :                         GDALGetDriverLongName( hDriver ) );
    2493                 :             }
    2494                 :         }
    2495               0 :         GDALDestroyDriverManager();
    2496               0 :         exit( 1 );
    2497                 :     }
    2498                 : 
    2499              16 :     if (!bQuiet && !bFormatExplicitelySet)
    2500              10 :         CheckExtensionConsistency(pszDstFilename, pszFormat);
    2501                 : 
    2502              16 :     double dfDstNoDataValue = 0;
    2503              16 :     int bDstHasNoData = FALSE;
    2504              16 :     void* pData = NULL;
    2505              16 :     GDALGeneric3x3ProcessingAlg pfnAlg = NULL;
    2506                 : 
    2507              16 :     if (eUtilityMode == HILL_SHADE)
    2508                 :     {
    2509               6 :         dfDstNoDataValue = 0;
    2510               6 :         bDstHasNoData = TRUE;
    2511                 :         pData = GDALCreateHillshadeData   (adfGeoTransform,
    2512                 :                                            z,
    2513                 :                                            scale,
    2514                 :                                            alt,
    2515                 :                                            az,
    2516               6 :                                            bZevenbergenThorne);
    2517               6 :         if (bZevenbergenThorne)
    2518                 :         {
    2519               0 :             if(!bCombined)
    2520               0 :                 pfnAlg = GDALHillshadeZevenbergenThorneAlg;
    2521                 :             else
    2522               0 :                 pfnAlg = GDALHillshadeZevenbergenThorneCombinedAlg;
    2523                 :         }
    2524                 :         else
    2525                 :         {
    2526               6 :             if(!bCombined)
    2527               5 :                 pfnAlg = GDALHillshadeAlg;
    2528                 :             else
    2529               1 :                 pfnAlg = GDALHillshadeCombinedAlg;
    2530                 :         }
    2531                 :     }
    2532              10 :     else if (eUtilityMode == SLOPE)
    2533                 :     {
    2534               1 :         dfDstNoDataValue = -9999;
    2535               1 :         bDstHasNoData = TRUE;
    2536                 : 
    2537               1 :         pData = GDALCreateSlopeData(adfGeoTransform, scale, slopeFormat);
    2538               1 :         if (bZevenbergenThorne)
    2539               0 :             pfnAlg = GDALSlopeZevenbergenThorneAlg;
    2540                 :         else
    2541               1 :             pfnAlg = GDALSlopeHornAlg;
    2542                 :     }
    2543                 : 
    2544               9 :     else if (eUtilityMode == ASPECT)
    2545                 :     {
    2546               1 :         if (!bZeroForFlat)
    2547                 :         {
    2548               1 :             dfDstNoDataValue = -9999;
    2549               1 :             bDstHasNoData = TRUE;
    2550                 :         }
    2551                 : 
    2552               1 :         pData = GDALCreateAspectData(bAngleAsAzimuth);
    2553               1 :         if (bZevenbergenThorne)
    2554               0 :             pfnAlg = GDALAspectZevenbergenThorneAlg;
    2555                 :         else
    2556               1 :             pfnAlg = GDALAspectAlg;
    2557                 :     }
    2558               8 :     else if (eUtilityMode == TRI)
    2559                 :     {
    2560               0 :         dfDstNoDataValue = -9999;
    2561               0 :         bDstHasNoData = TRUE;
    2562               0 :         pfnAlg = GDALTRIAlg;
    2563                 :     }
    2564               8 :     else if (eUtilityMode == TPI)
    2565                 :     {
    2566               0 :         dfDstNoDataValue = -9999;
    2567               0 :         bDstHasNoData = TRUE;
    2568               0 :         pfnAlg = GDALTPIAlg;
    2569                 :     }
    2570               8 :     else if (eUtilityMode == ROUGHNESS)
    2571                 :     {
    2572               0 :         dfDstNoDataValue = -9999;
    2573               0 :         bDstHasNoData = TRUE;
    2574               0 :         pfnAlg = GDALRoughnessAlg;
    2575                 :     }
    2576                 :     
    2577                 :     GDALDataType eDstDataType = (eUtilityMode == HILL_SHADE ||
    2578                 :                                  eUtilityMode == COLOR_RELIEF) ? GDT_Byte :
    2579              16 :                                                                GDT_Float32;
    2580                 : 
    2581              16 :     if( EQUAL(pszFormat, "VRT") )
    2582                 :     {
    2583               2 :         if (eUtilityMode == COLOR_RELIEF)
    2584                 :         {
    2585                 :             GDALGenerateVRTColorRelief(pszDstFilename,
    2586                 :                                        hSrcDataset,
    2587                 :                                        hSrcBand,
    2588                 :                                        pszColorFilename,
    2589                 :                                        eColorSelectionMode,
    2590               2 :                                        bAddAlpha);
    2591               2 :             GDALClose(hSrcDataset);
    2592                 :         
    2593               2 :             CPLFree(pData);
    2594                 : 
    2595               2 :             GDALDestroyDriverManager();
    2596               2 :             CSLDestroy( argv );
    2597               2 :             CSLDestroy( papszCreateOptions );
    2598                 :         
    2599               2 :             return 0;
    2600                 :         }
    2601                 :         else
    2602                 :         {
    2603               0 :             fprintf(stderr, "VRT driver can only be used with color-relief utility\n");
    2604               0 :             GDALDestroyDriverManager();
    2605                 : 
    2606               0 :             exit(1);
    2607                 :         }
    2608                 :     }
    2609                 :     
    2610              14 :     if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL &&
    2611                 :         GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL)
    2612                 :     {
    2613                 :         GDALDatasetH hIntermediateDataset;
    2614                 :         
    2615               4 :         if (eUtilityMode == COLOR_RELIEF)
    2616                 :             hIntermediateDataset = (GDALDatasetH)
    2617                 :                 new GDALColorReliefDataset (hSrcDataset,
    2618                 :                                             hSrcBand,
    2619                 :                                             pszColorFilename,
    2620                 :                                             eColorSelectionMode,
    2621               2 :                                             bAddAlpha);
    2622                 :         else
    2623                 :             hIntermediateDataset = (GDALDatasetH)
    2624                 :                 new GDALGeneric3x3Dataset(hSrcDataset, hSrcBand,
    2625                 :                                           eDstDataType,
    2626                 :                                           bDstHasNoData,
    2627                 :                                           dfDstNoDataValue,
    2628                 :                                           pfnAlg,
    2629                 :                                           pData,
    2630               2 :                                           bComputeAtEdges);
    2631                 : 
    2632                 :         GDALDatasetH hOutDS = GDALCreateCopy(
    2633                 :                                  hDriver, pszDstFilename, hIntermediateDataset, 
    2634                 :                                  TRUE, papszCreateOptions, 
    2635               4 :                                  pfnProgress, NULL );
    2636                 : 
    2637               4 :         if( hOutDS != NULL )
    2638               4 :             GDALClose( hOutDS );
    2639               4 :         GDALClose(hIntermediateDataset);
    2640               4 :         GDALClose(hSrcDataset);
    2641                 :         
    2642               4 :         CPLFree(pData);
    2643                 : 
    2644               4 :         GDALDestroyDriverManager();
    2645               4 :         CSLDestroy( argv );
    2646               4 :         CSLDestroy( papszCreateOptions );
    2647                 :         
    2648               4 :         return 0;
    2649                 :     }
    2650                 : 
    2651                 :     int nDstBands;
    2652              10 :     if (eUtilityMode == COLOR_RELIEF)
    2653               4 :         nDstBands = (bAddAlpha) ? 4 : 3;
    2654                 :     else
    2655               6 :         nDstBands = 1;
    2656                 : 
    2657                 :     hDstDataset = GDALCreate(   hDriver,
    2658                 :                                 pszDstFilename,
    2659                 :                                 nXSize,
    2660                 :                                 nYSize,
    2661                 :                                 nDstBands,
    2662                 :                                 eDstDataType,
    2663              10 :                                 papszCreateOptions);
    2664                 : 
    2665              10 :     if( hDstDataset == NULL )
    2666                 :     {
    2667                 :         fprintf( stderr,
    2668                 :                  "Unable to create dataset %s %d\n%s\n", pszDstFilename,
    2669               0 :                  CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
    2670               0 :         GDALDestroyDriverManager();
    2671               0 :         exit( 1 );
    2672                 :     }
    2673                 :     
    2674              10 :     hDstBand = GDALGetRasterBand( hDstDataset, 1 );
    2675                 : 
    2676              10 :     GDALSetGeoTransform(hDstDataset, adfGeoTransform);
    2677              10 :     GDALSetProjection(hDstDataset, GDALGetProjectionRef(hSrcDataset));
    2678                 :     
    2679              10 :     if (eUtilityMode == COLOR_RELIEF)
    2680                 :     {
    2681                 :         GDALColorRelief (hSrcBand, 
    2682                 :                          GDALGetRasterBand(hDstDataset, 1),
    2683                 :                          GDALGetRasterBand(hDstDataset, 2),
    2684                 :                          GDALGetRasterBand(hDstDataset, 3),
    2685                 :                          (bAddAlpha) ? GDALGetRasterBand(hDstDataset, 4) : NULL,
    2686                 :                          pszColorFilename,
    2687                 :                          eColorSelectionMode,
    2688               4 :                          pfnProgress, NULL);
    2689                 :     }
    2690                 :     else
    2691                 :     {
    2692               6 :         if (bDstHasNoData)
    2693               6 :             GDALSetRasterNoDataValue(hDstBand, dfDstNoDataValue);
    2694                 :         
    2695                 :         GDALGeneric3x3Processing(hSrcBand, hDstBand,
    2696                 :                                  pfnAlg, pData,
    2697                 :                                  bComputeAtEdges,
    2698               6 :                                  pfnProgress, NULL);
    2699                 :                                     
    2700                 :     }
    2701                 : 
    2702              10 :     GDALClose(hSrcDataset);
    2703              10 :     GDALClose(hDstDataset);
    2704              10 :     CPLFree(pData);
    2705                 : 
    2706              10 :     GDALDestroyDriverManager();
    2707              10 :     CSLDestroy( argv );
    2708              10 :     CSLDestroy( papszCreateOptions );
    2709                 : 
    2710              10 :     return 0;
    2711                 : }
    2712                 : 

Generated by: LCOV version 1.7