LCOV - code coverage report
Current view: top level - frmts/northwood - northwood.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 177 387 45.7 %
Date: 2025-01-18 12:42:00 Functions: 5 11 45.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GRC/GRD Reader
       4             :  * Purpose:  Northwood Format basic implementation
       5             :  * Author:   Perry Casson
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Waypoint Information Technology
       9             :  * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gdal_pam.h"
      15             : 
      16             : #include "northwood.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <cassert>
      20             : #include <limits>
      21             : #include <string>
      22             : 
      23          14 : int nwt_ParseHeader(NWT_GRID *pGrd, const unsigned char *nwtHeader)
      24             : {
      25             :     /* double dfTmp; */
      26             : 
      27          14 :     if (nwtHeader[4] == '1')
      28          12 :         pGrd->cFormat = 0x00;  // grd - surface type
      29           2 :     else if (nwtHeader[4] == '8')
      30           2 :         pGrd->cFormat = 0x80;  //  grc classified type
      31             : 
      32          14 :     pGrd->stClassDict = nullptr;
      33             : 
      34          14 :     memcpy(&pGrd->fVersion, &nwtHeader[5], sizeof(pGrd->fVersion));
      35          14 :     CPL_LSBPTR32(&pGrd->fVersion);
      36             : 
      37             :     unsigned short usTmp;
      38          14 :     memcpy(&usTmp, &nwtHeader[9], 2);
      39          14 :     CPL_LSBPTR16(&usTmp);
      40          14 :     pGrd->nXSide = static_cast<unsigned int>(usTmp);
      41          14 :     if (pGrd->nXSide == 0)
      42             :     {
      43           0 :         memcpy(&pGrd->nXSide, &nwtHeader[128], sizeof(pGrd->nXSide));
      44           0 :         CPL_LSBPTR32(&pGrd->nXSide);
      45             :     }
      46          14 :     if (pGrd->nXSide <= 1)
      47           0 :         return FALSE;
      48             : 
      49          14 :     memcpy(&usTmp, &nwtHeader[11], 2);
      50          14 :     CPL_LSBPTR16(&usTmp);
      51          14 :     pGrd->nYSide = static_cast<unsigned int>(usTmp);
      52          14 :     if (pGrd->nYSide == 0)
      53             :     {
      54           0 :         memcpy(&pGrd->nYSide, &nwtHeader[132], sizeof(pGrd->nYSide));
      55           0 :         CPL_LSBPTR32(&pGrd->nYSide);
      56             :     }
      57             : 
      58          14 :     memcpy(&pGrd->dfMinX, &nwtHeader[13], sizeof(pGrd->dfMinX));
      59          14 :     CPL_LSBPTR64(&pGrd->dfMinX);
      60          14 :     memcpy(&pGrd->dfMaxX, &nwtHeader[21], sizeof(pGrd->dfMaxX));
      61          14 :     CPL_LSBPTR64(&pGrd->dfMaxX);
      62          14 :     memcpy(&pGrd->dfMinY, &nwtHeader[29], sizeof(pGrd->dfMinY));
      63          14 :     CPL_LSBPTR64(&pGrd->dfMinY);
      64          14 :     memcpy(&pGrd->dfMaxY, &nwtHeader[37], sizeof(pGrd->dfMaxY));
      65          14 :     CPL_LSBPTR64(&pGrd->dfMaxY);
      66             : 
      67          14 :     assert(pGrd->nXSide > 1);
      68          14 :     pGrd->dfStepSize = (pGrd->dfMaxX - pGrd->dfMinX) / (pGrd->nXSide - 1);
      69             :     /* dfTmp = (pGrd->dfMaxY - pGrd->dfMinY) / (pGrd->nYSide - 1); */
      70             : 
      71          14 :     memcpy(&pGrd->fZMin, &nwtHeader[45], sizeof(pGrd->fZMin));
      72          14 :     CPL_LSBPTR32(&pGrd->fZMin);
      73          14 :     memcpy(&pGrd->fZMax, &nwtHeader[49], sizeof(pGrd->fZMax));
      74          14 :     CPL_LSBPTR32(&pGrd->fZMax);
      75          14 :     memcpy(&pGrd->fZMinScale, &nwtHeader[53], sizeof(pGrd->fZMinScale));
      76          14 :     CPL_LSBPTR32(&pGrd->fZMinScale);
      77          14 :     memcpy(&pGrd->fZMaxScale, &nwtHeader[57], sizeof(pGrd->fZMaxScale));
      78          14 :     CPL_LSBPTR32(&pGrd->fZMaxScale);
      79             : 
      80          14 :     memcpy(&pGrd->cDescription, &nwtHeader[61], sizeof(pGrd->cDescription));
      81          14 :     memcpy(&pGrd->cZUnits, &nwtHeader[93], sizeof(pGrd->cZUnits));
      82             : 
      83             :     int i;
      84          14 :     memcpy(&i, &nwtHeader[136], 4);
      85          14 :     CPL_LSBPTR32(&i);
      86             : 
      87          14 :     if (i == 1129336130)
      88             :     {  // BMPC
      89           0 :         if (nwtHeader[140] & 0x01)
      90             :         {
      91           0 :             pGrd->cHillShadeBrightness = nwtHeader[144];
      92           0 :             pGrd->cHillShadeContrast = nwtHeader[145];
      93             :         }
      94             :     }
      95             : 
      96          14 :     memcpy(&pGrd->cMICoordSys, &nwtHeader[256], sizeof(pGrd->cMICoordSys));
      97          14 :     pGrd->cMICoordSys[sizeof(pGrd->cMICoordSys) - 1] = '\0';
      98             : 
      99          14 :     pGrd->iZUnits = nwtHeader[512];
     100             : 
     101          14 :     if (nwtHeader[513] & 0x80)
     102           0 :         pGrd->bShowGradient = true;
     103             : 
     104          14 :     if (nwtHeader[513] & 0x40)
     105           0 :         pGrd->bShowHillShade = true;
     106             : 
     107          14 :     if (nwtHeader[513] & 0x20)
     108           0 :         pGrd->bHillShadeExists = true;
     109             : 
     110          14 :     memcpy(&pGrd->iNumColorInflections, &nwtHeader[516], 2);
     111          14 :     CPL_LSBPTR16(&pGrd->iNumColorInflections);
     112             : 
     113          14 :     if (pGrd->iNumColorInflections > 32)
     114             :     {
     115           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Corrupt header");
     116           0 :         pGrd->iNumColorInflections = 0;
     117           0 :         return FALSE;
     118             :     }
     119             : 
     120          68 :     for (i = 0; i < pGrd->iNumColorInflections; i++)
     121             :     {
     122          54 :         memcpy(&pGrd->stInflection[i].zVal, &nwtHeader[518 + (7 * i)], 4);
     123          54 :         CPL_LSBPTR32(&pGrd->stInflection[i].zVal);
     124          54 :         memcpy(&pGrd->stInflection[i].r, &nwtHeader[522 + (7 * i)], 1);
     125          54 :         memcpy(&pGrd->stInflection[i].g, &nwtHeader[523 + (7 * i)], 1);
     126          54 :         memcpy(&pGrd->stInflection[i].b, &nwtHeader[524 + (7 * i)], 1);
     127             :     }
     128             : 
     129          14 :     memcpy(&pGrd->fHillShadeAzimuth, &nwtHeader[966],
     130             :            sizeof(pGrd->fHillShadeAzimuth));
     131          14 :     CPL_LSBPTR32(&pGrd->fHillShadeAzimuth);
     132          14 :     memcpy(&pGrd->fHillShadeAngle, &nwtHeader[970],
     133             :            sizeof(pGrd->fHillShadeAngle));
     134          14 :     CPL_LSBPTR32(&pGrd->fHillShadeAngle);
     135             : 
     136          14 :     pGrd->cFormat += nwtHeader[1023];  // the msb for grd/grc was already set
     137             : 
     138             :     // there are more types than this - need to build other types for testing
     139          14 :     if (pGrd->cFormat & 0x80)
     140             :     {
     141           2 :         if (nwtHeader[1023] == 0)
     142           0 :             pGrd->nBitsPerPixel = 16;
     143             :         else
     144           2 :             pGrd->nBitsPerPixel = nwtHeader[1023] * 4;
     145             :     }
     146             :     else
     147          12 :         pGrd->nBitsPerPixel = nwtHeader[1023] * 8;
     148             : 
     149          14 :     if (pGrd->cFormat & 0x80)  // if is GRC load the Dictionary
     150             :     {
     151           2 :         vsi_l_offset nPixels =
     152           2 :             static_cast<vsi_l_offset>(pGrd->nXSide) * pGrd->nYSide;
     153           2 :         unsigned int nBytesPerPixel = pGrd->nBitsPerPixel / 8;
     154           4 :         if (nPixels > 0 &&
     155           2 :             (nBytesPerPixel >
     156           2 :                  std::numeric_limits<vsi_l_offset>::max() / nPixels ||
     157           2 :              nPixels * nBytesPerPixel >
     158           2 :                  std::numeric_limits<vsi_l_offset>::max() - 1024))
     159             :         {
     160           0 :             CPLError(CE_Failure, CPLE_FileIO,
     161             :                      "Invalid file dimension / bits per pixel");
     162           0 :             return FALSE;
     163             :         }
     164           2 :         VSIFSeekL(pGrd->fp, 1024 + nPixels * nBytesPerPixel, SEEK_SET);
     165             : 
     166           2 :         if (!VSIFReadL(&usTmp, 2, 1, pGrd->fp))
     167             :         {
     168           0 :             CPLError(CE_Failure, CPLE_FileIO, "Read failure, file short?");
     169           0 :             return FALSE;
     170             :         }
     171           2 :         CPL_LSBPTR16(&usTmp);
     172           2 :         pGrd->stClassDict = reinterpret_cast<NWT_CLASSIFIED_DICT *>(
     173           2 :             calloc(1, sizeof(NWT_CLASSIFIED_DICT)));
     174           2 :         if (!pGrd->stClassDict)
     175             :         {
     176           0 :             return FALSE;
     177             :         }
     178             : 
     179           2 :         pGrd->stClassDict->nNumClassifiedItems = usTmp;
     180             : 
     181           2 :         pGrd->stClassDict->stClassifiedItem =
     182             :             reinterpret_cast<NWT_CLASSIFIED_ITEM **>(
     183           2 :                 calloc(pGrd->stClassDict->nNumClassifiedItems + 1,
     184             :                        sizeof(NWT_CLASSIFIED_ITEM *)));
     185           2 :         if (!pGrd->stClassDict->stClassifiedItem)
     186             :         {
     187           0 :             pGrd->stClassDict->nNumClassifiedItems = 0;
     188           0 :             return FALSE;
     189             :         }
     190             : 
     191             :         // load the dictionary
     192           8 :         for (unsigned int iItem = 0;
     193           8 :              iItem < pGrd->stClassDict->nNumClassifiedItems; iItem++)
     194             :         {
     195             :             NWT_CLASSIFIED_ITEM *psItem =
     196           6 :                 pGrd->stClassDict->stClassifiedItem[iItem] =
     197             :                     reinterpret_cast<NWT_CLASSIFIED_ITEM *>(
     198           6 :                         calloc(1, sizeof(NWT_CLASSIFIED_ITEM)));
     199           6 :             if (!psItem)
     200             :             {
     201           0 :                 return FALSE;
     202             :             }
     203             : 
     204             :             unsigned char cTmp[256];
     205           6 :             if (!VSIFReadL(&cTmp, 9, 1, pGrd->fp))
     206             :             {
     207           0 :                 CPLError(CE_Failure, CPLE_FileIO, "Read failure, file short?");
     208           0 :                 return FALSE;
     209             :             }
     210           6 :             memcpy(&psItem->usPixVal, &cTmp[0], 2);
     211           6 :             CPL_LSBPTR16(&psItem->usPixVal);
     212           6 :             memcpy(&psItem->res1, &cTmp[2], 1);
     213           6 :             memcpy(&psItem->r, &cTmp[3], 1);
     214           6 :             memcpy(&psItem->g, &cTmp[4], 1);
     215           6 :             memcpy(&psItem->b, &cTmp[5], 1);
     216           6 :             memcpy(&psItem->res2, &cTmp[6], 1);
     217           6 :             memcpy(&psItem->usLen, &cTmp[7], 2);
     218           6 :             CPL_LSBPTR16(&psItem->usLen);
     219             : 
     220           6 :             if (psItem->usLen > sizeof(psItem->szClassName) - 1)
     221             :             {
     222           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     223             :                          "Unexpected long class name, %d characters long - "
     224             :                          "unable to read file.",
     225           0 :                          psItem->usLen);
     226           0 :                 return FALSE;
     227             :             }
     228             : 
     229             :             // 0-len class names are possible
     230           6 :             psItem->szClassName[0] = '\0';
     231          12 :             if (psItem->usLen > 0 &&
     232           6 :                 !VSIFReadL(&psItem->szClassName, psItem->usLen, 1, pGrd->fp))
     233           0 :                 return FALSE;
     234             :         }
     235             :     }
     236             : 
     237          14 :     return TRUE;
     238             : }
     239             : 
     240             : // Create a color gradient ranging from ZMin to Zmax using the color
     241             : // inflections defined in grid
     242          12 : int nwt_LoadColors(NWT_RGB *pMap, int mapSize, NWT_GRID *pGrd)
     243             : {
     244             :     int i;
     245             :     NWT_RGB sColor;
     246          12 :     int nWarkerMark = 0;
     247             : 
     248          12 :     createIP(0, 255, 255, 255, pMap, &nWarkerMark);
     249          12 :     if (pGrd->iNumColorInflections == 0)
     250           0 :         return 0;
     251             : 
     252             :     // If Zmin is less than the 1st inflection use the 1st inflections color to
     253             :     // the start of the ramp
     254          12 :     if (pGrd->fZMin <= pGrd->stInflection[0].zVal)
     255             :     {
     256          12 :         createIP(1, pGrd->stInflection[0].r, pGrd->stInflection[0].g,
     257          12 :                  pGrd->stInflection[0].b, pMap, &nWarkerMark);
     258             :     }
     259             :     // find what inflections zmin is between
     260          12 :     for (i = 1; i < pGrd->iNumColorInflections; i++)
     261             :     {
     262          12 :         if (pGrd->fZMin < pGrd->stInflection[i].zVal)
     263             :         {
     264             :             // then we must be between i and i-1
     265          12 :             linearColor(&sColor, &pGrd->stInflection[i - 1],
     266             :                         &pGrd->stInflection[i], pGrd->fZMin);
     267          12 :             createIP(1, sColor.r, sColor.g, sColor.b, pMap, &nWarkerMark);
     268          12 :             break;
     269             :         }
     270             :     }
     271             :     // the interesting case of zmin beig higher than the max inflection value
     272          12 :     if (i >= pGrd->iNumColorInflections)
     273             :     {
     274           0 :         createIP(1, pGrd->stInflection[pGrd->iNumColorInflections - 1].r,
     275           0 :                  pGrd->stInflection[pGrd->iNumColorInflections - 1].g,
     276           0 :                  pGrd->stInflection[pGrd->iNumColorInflections - 1].b, pMap,
     277             :                  &nWarkerMark);
     278           0 :         createIP(mapSize - 1,
     279           0 :                  pGrd->stInflection[pGrd->iNumColorInflections - 1].r,
     280           0 :                  pGrd->stInflection[pGrd->iNumColorInflections - 1].g,
     281           0 :                  pGrd->stInflection[pGrd->iNumColorInflections - 1].b, pMap,
     282             :                  &nWarkerMark);
     283             :     }
     284             :     else
     285             :     {
     286          12 :         int index = 0;
     287          54 :         for (; i < pGrd->iNumColorInflections; i++)
     288             :         {
     289          42 :             if (pGrd->fZMax < pGrd->stInflection[i].zVal)
     290             :             {
     291             :                 // then we must be between i and i-1
     292           0 :                 linearColor(&sColor, &pGrd->stInflection[i - 1],
     293             :                             &pGrd->stInflection[i], pGrd->fZMax);
     294           0 :                 index = mapSize - 1;
     295           0 :                 createIP(index, sColor.r, sColor.g, sColor.b, pMap,
     296             :                          &nWarkerMark);
     297           0 :                 break;
     298             :             }
     299             :             // save the inflections between zmin and zmax
     300          42 :             index =
     301          42 :                 static_cast<int>(((pGrd->stInflection[i].zVal - pGrd->fZMin) /
     302          42 :                                   (pGrd->fZMax - pGrd->fZMin)) *
     303             :                                  mapSize);
     304             : 
     305          42 :             if (index >= mapSize)
     306          12 :                 index = mapSize - 1;
     307          42 :             createIP(index, pGrd->stInflection[i].r, pGrd->stInflection[i].g,
     308          42 :                      pGrd->stInflection[i].b, pMap, &nWarkerMark);
     309             :         }
     310          12 :         if (index < mapSize - 1)
     311           0 :             createIP(mapSize - 1,
     312           0 :                      pGrd->stInflection[pGrd->iNumColorInflections - 1].r,
     313           0 :                      pGrd->stInflection[pGrd->iNumColorInflections - 1].g,
     314           0 :                      pGrd->stInflection[pGrd->iNumColorInflections - 1].b, pMap,
     315             :                      &nWarkerMark);
     316             :     }
     317          12 :     return 0;
     318             : }
     319             : 
     320             : // solve for a color between pIPLow and pIPHigh
     321          12 : void linearColor(NWT_RGB *pRGB, NWT_INFLECTION *pIPLow, NWT_INFLECTION *pIPHigh,
     322             :                  float fMid)
     323             : {
     324          12 :     if (fMid < pIPLow->zVal)
     325             :     {
     326           0 :         pRGB->r = pIPLow->r;
     327           0 :         pRGB->g = pIPLow->g;
     328           0 :         pRGB->b = pIPLow->b;
     329             :     }
     330          12 :     else if (fMid > pIPHigh->zVal)
     331             :     {
     332           0 :         pRGB->r = pIPHigh->r;
     333           0 :         pRGB->g = pIPHigh->g;
     334           0 :         pRGB->b = pIPHigh->b;
     335             :     }
     336             :     else
     337             :     {
     338          12 :         float scale = (fMid - pIPLow->zVal) / (pIPHigh->zVal - pIPLow->zVal);
     339          12 :         pRGB->r = static_cast<unsigned char>(scale * (pIPHigh->r - pIPLow->r) +
     340          12 :                                              pIPLow->r + 0.5);
     341          12 :         pRGB->g = static_cast<unsigned char>(scale * (pIPHigh->g - pIPLow->g) +
     342          12 :                                              pIPLow->g + 0.5);
     343          12 :         pRGB->b = static_cast<unsigned char>(scale * (pIPHigh->b - pIPLow->b) +
     344          12 :                                              pIPLow->b + 0.5);
     345             :     }
     346          12 : }
     347             : 
     348             : // insert IP's into the map filling as we go
     349          78 : void createIP(int index, unsigned char r, unsigned char g, unsigned char b,
     350             :               NWT_RGB *map, int *pnWarkerMark)
     351             : {
     352             :     int i;
     353             : 
     354          78 :     if (index == 0)
     355             :     {
     356          12 :         map[0].r = r;
     357          12 :         map[0].g = g;
     358          12 :         map[0].b = b;
     359          12 :         *pnWarkerMark = 0;
     360          12 :         return;
     361             :     }
     362             : 
     363          66 :     if (index <= *pnWarkerMark)
     364          12 :         return;
     365             : 
     366          54 :     int wm = *pnWarkerMark;
     367             : 
     368          54 :     float rslope =
     369          54 :         static_cast<float>(r - map[wm].r) / static_cast<float>(index - wm);
     370          54 :     float gslope =
     371          54 :         static_cast<float>(g - map[wm].g) / static_cast<float>(index - wm);
     372          54 :     float bslope =
     373          54 :         static_cast<float>(b - map[wm].b) / static_cast<float>(index - wm);
     374       49140 :     for (i = wm + 1; i < index; i++)
     375             :     {
     376       49086 :         map[i].r =
     377       49086 :             static_cast<unsigned char>(map[wm].r + ((i - wm) * rslope) + 0.5);
     378       49086 :         map[i].g =
     379       49086 :             static_cast<unsigned char>(map[wm].g + ((i - wm) * gslope) + 0.5);
     380       49086 :         map[i].b =
     381       49086 :             static_cast<unsigned char>(map[wm].b + ((i - wm) * bslope) + 0.5);
     382             :     }
     383          54 :     map[index].r = r;
     384          54 :     map[index].g = g;
     385          54 :     map[index].b = b;
     386          54 :     *pnWarkerMark = index;
     387          54 :     return;
     388             : }
     389             : 
     390           0 : void nwt_HillShade(unsigned char *r, unsigned char *g, unsigned char *b,
     391             :                    unsigned char *h)
     392             : {
     393             :     HLS hls;
     394             :     NWT_RGB rgb;
     395           0 :     rgb.r = *r;
     396           0 :     rgb.g = *g;
     397           0 :     rgb.b = *b;
     398           0 :     hls = RGBtoHLS(rgb);
     399           0 :     hls.l = static_cast<short>(hls.l + (*h) * HLSMAX / 256);
     400           0 :     rgb = HLStoRGB(hls);
     401             : 
     402           0 :     *r = rgb.r;
     403           0 :     *g = rgb.g;
     404           0 :     *b = rgb.b;
     405           0 :     return;
     406             : }
     407             : 
     408           0 : NWT_GRID *nwtOpenGrid(char *filename)
     409             : {
     410             :     unsigned char nwtHeader[1024];
     411           0 :     VSILFILE *fp = VSIFOpenL(filename, "rb");
     412             : 
     413           0 :     if (fp == nullptr)
     414             :     {
     415           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Can't open %s", filename);
     416           0 :         return nullptr;
     417             :     }
     418             : 
     419           0 :     if (!VSIFReadL(nwtHeader, 1024, 1, fp))
     420             :     {
     421           0 :         VSIFCloseL(fp);
     422           0 :         return nullptr;
     423             :     }
     424             : 
     425           0 :     if (nwtHeader[0] != 'H' || nwtHeader[1] != 'G' || nwtHeader[2] != 'P' ||
     426           0 :         nwtHeader[3] != 'C')
     427             :     {
     428           0 :         VSIFCloseL(fp);
     429           0 :         return nullptr;
     430             :     }
     431             : 
     432           0 :     NWT_GRID *pGrd = reinterpret_cast<NWT_GRID *>(calloc(1, sizeof(NWT_GRID)));
     433           0 :     if (!pGrd)
     434             :     {
     435           0 :         VSIFCloseL(fp);
     436           0 :         return nullptr;
     437             :     }
     438             : 
     439           0 :     if (nwtHeader[4] == '1')
     440           0 :         pGrd->cFormat = 0x00;  // grd - surface type
     441           0 :     else if (nwtHeader[4] == '8')
     442           0 :         pGrd->cFormat = 0x80;  //  grc classified type
     443             :     else
     444             :     {
     445           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     446           0 :                  "Unhandled Northwood format type = %0xd", nwtHeader[4]);
     447           0 :         VSIFCloseL(fp);
     448           0 :         free(pGrd);
     449           0 :         return nullptr;
     450             :     }
     451             : 
     452           0 :     strncpy(pGrd->szFileName, filename, sizeof(pGrd->szFileName));
     453           0 :     pGrd->szFileName[sizeof(pGrd->szFileName) - 1] = '\0';
     454           0 :     pGrd->fp = fp;
     455           0 :     nwt_ParseHeader(pGrd, nwtHeader);
     456             : 
     457           0 :     return pGrd;
     458             : }
     459             : 
     460             : // close the file and free the mem
     461          28 : void nwtCloseGrid(NWT_GRID *pGrd)
     462             : {
     463          30 :     if ((pGrd->cFormat & 0x80) &&
     464          28 :         pGrd->stClassDict)  // if is GRC - free the Dictionary
     465             :     {
     466           8 :         for (unsigned int i = 0; i < pGrd->stClassDict->nNumClassifiedItems;
     467             :              i++)
     468             :         {
     469           6 :             free(pGrd->stClassDict->stClassifiedItem[i]);
     470             :         }
     471           2 :         free(pGrd->stClassDict->stClassifiedItem);
     472           2 :         free(pGrd->stClassDict);
     473             :     }
     474          28 :     if (pGrd->fp)
     475           0 :         VSIFCloseL(pGrd->fp);
     476          28 :     free(pGrd);
     477          28 :     return;
     478             : }
     479             : 
     480           0 : void nwtPrintGridHeader(NWT_GRID *pGrd)
     481             : {
     482           0 :     if (pGrd->cFormat & 0x80)
     483             :     {
     484           0 :         printf("\n%s\n\nGrid type is Classified ", pGrd->szFileName); /*ok*/
     485           0 :         if (pGrd->cFormat == 0x81)
     486           0 :             printf("4 bit (Less than 16 Classes)"); /*ok*/
     487           0 :         else if (pGrd->cFormat == 0x82)
     488           0 :             printf("8 bit (Less than 256 Classes)"); /*ok*/
     489           0 :         else if (pGrd->cFormat == 0x84)
     490           0 :             printf("16 bit (Less than 65536 Classes)"); /*ok*/
     491             :         else
     492             :         {
     493           0 :             printf("GRC - Unhandled Format or Type %d", pGrd->cFormat); /*ok*/
     494           0 :             return;
     495             :         }
     496             :     }
     497             :     else
     498             :     {
     499           0 :         printf("\n%s\n\nGrid type is Numeric ", pGrd->szFileName); /*ok*/
     500           0 :         if (pGrd->cFormat == 0x00)
     501           0 :             printf("16 bit (Standard Precision)"); /*ok*/
     502           0 :         else if (pGrd->cFormat == 0x01)
     503           0 :             printf("32 bit (High Precision)"); /*ok*/
     504             :         else
     505             :         {
     506           0 :             printf("GRD - Unhandled Format or Type %d", pGrd->cFormat); /*ok*/
     507           0 :             return;
     508             :         }
     509             :     }
     510           0 :     printf("\nDim (x,y) = (%u,%u)", pGrd->nXSide, pGrd->nYSide);     /*ok*/
     511           0 :     printf("\nStep Size = %f", pGrd->dfStepSize);                    /*ok*/
     512           0 :     printf("\nBounds = (%f,%f) (%f,%f)", pGrd->dfMinX, pGrd->dfMinY, /*ok*/
     513             :            pGrd->dfMaxX, pGrd->dfMaxY);
     514           0 :     printf("\nCoordinate System = %s", pGrd->cMICoordSys); /*ok*/
     515             : 
     516           0 :     if (!(pGrd->cFormat & 0x80))  // print the numeric specific stuff
     517             :     {
     518           0 :         printf("\nMin Z = %f Max Z = %f Z Units = %d \"%s\"", /*ok*/
     519           0 :                pGrd->fZMin, pGrd->fZMax, pGrd->iZUnits, pGrd->cZUnits);
     520             : 
     521           0 :         printf("\n\nDisplay Mode ="); /*ok*/
     522           0 :         if (pGrd->bShowGradient)
     523           0 :             printf(" Color Gradient"); /*ok*/
     524             : 
     525           0 :         if (pGrd->bShowGradient && pGrd->bShowHillShade)
     526           0 :             printf(" and"); /*ok*/
     527             : 
     528           0 :         if (pGrd->bShowHillShade)
     529           0 :             printf(" Hill Shading"); /*ok*/
     530             : 
     531           0 :         for (int i = 0; i < pGrd->iNumColorInflections; i++)
     532             :         {
     533           0 :             printf("\nColor Inflection %d - %f (%d,%d,%d)", i + 1, /*ok*/
     534           0 :                    pGrd->stInflection[i].zVal, pGrd->stInflection[i].r,
     535           0 :                    pGrd->stInflection[i].g, pGrd->stInflection[i].b);
     536             :         }
     537             : 
     538           0 :         if (pGrd->bHillShadeExists)
     539             :         {
     540           0 :             printf("\n\nHill Shade Azumith = %.1f Inclination = %.1f " /*ok*/
     541             :                    "Brightness = %d Contrast = %d",
     542           0 :                    pGrd->fHillShadeAzimuth, pGrd->fHillShadeAngle,
     543           0 :                    pGrd->cHillShadeBrightness, pGrd->cHillShadeContrast);
     544             :         }
     545             :         else
     546           0 :             printf("\n\nNo Hill Shade Data"); /*ok*/
     547             :     }
     548             :     else  // print the classified specific stuff
     549             :     {
     550           0 :         printf("\nNumber of Classes defined = %u", /*ok*/
     551           0 :                pGrd->stClassDict->nNumClassifiedItems);
     552           0 :         for (int i = 0;
     553           0 :              i < static_cast<int>(pGrd->stClassDict->nNumClassifiedItems); i++)
     554             :         {
     555           0 :             printf("\n%s - (%d,%d,%d)  Raw = %d  %d %d", /*ok*/
     556           0 :                    pGrd->stClassDict->stClassifiedItem[i]->szClassName,
     557           0 :                    pGrd->stClassDict->stClassifiedItem[i]->r,
     558           0 :                    pGrd->stClassDict->stClassifiedItem[i]->g,
     559           0 :                    pGrd->stClassDict->stClassifiedItem[i]->b,
     560           0 :                    pGrd->stClassDict->stClassifiedItem[i]->usPixVal,
     561           0 :                    pGrd->stClassDict->stClassifiedItem[i]->res1,
     562           0 :                    pGrd->stClassDict->stClassifiedItem[i]->res2);
     563             :         }
     564             :     }
     565             : }
     566             : 
     567           0 : HLS RGBtoHLS(NWT_RGB rgb)
     568             : {
     569             :     /* get R, G, and B out of DWORD */
     570           0 :     short R = rgb.r;
     571           0 :     short G = rgb.g;
     572           0 :     short B = rgb.b;
     573             : 
     574             :     /* calculate lightness */
     575             :     unsigned char cMax =
     576           0 :         static_cast<unsigned char>(std::max(std::max(R, G), B));
     577             :     unsigned char cMin =
     578           0 :         static_cast<unsigned char>(std::min(std::min(R, G), B));
     579             :     HLS hls;
     580           0 :     hls.l = (((cMax + cMin) * HLSMAX) + RGBMAX) / (2 * RGBMAX);
     581             : 
     582             :     short Rdelta, Gdelta, Bdelta; /* intermediate value: % of spread from max */
     583           0 :     if (cMax == cMin)
     584             :     {                      /* r=g=b --> achromatic case */
     585           0 :         hls.s = 0;         /* saturation */
     586           0 :         hls.h = UNDEFINED; /* hue */
     587             :     }
     588             :     else
     589             :     { /* chromatic case */
     590             :         /* saturation */
     591           0 :         if (hls.l <= (HLSMAX / 2))
     592           0 :             hls.s = (((cMax - cMin) * HLSMAX) + ((cMax + cMin) / 2)) /
     593           0 :                     (cMax + cMin);
     594             :         else
     595           0 :             hls.s =
     596           0 :                 (((cMax - cMin) * HLSMAX) + ((2 * RGBMAX - cMax - cMin) / 2)) /
     597           0 :                 (2 * RGBMAX - cMax - cMin);
     598             : 
     599             :         /* hue */
     600           0 :         Rdelta =
     601           0 :             (((cMax - R) * (HLSMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin);
     602           0 :         Gdelta =
     603           0 :             (((cMax - G) * (HLSMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin);
     604           0 :         Bdelta =
     605           0 :             (((cMax - B) * (HLSMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin);
     606             : 
     607           0 :         if (R == cMax)
     608           0 :             hls.h = Bdelta - Gdelta;
     609           0 :         else if (G == cMax)
     610           0 :             hls.h = (HLSMAX / 3) + Rdelta - Bdelta;
     611             :         else /* B == cMax */
     612           0 :             hls.h = ((2 * HLSMAX) / 3) + Gdelta - Rdelta;
     613             : 
     614           0 :         if (hls.h < 0)
     615           0 :             hls.h += HLSMAX;
     616           0 :         if (hls.h > HLSMAX)
     617           0 :             hls.h -= HLSMAX;
     618             :     }
     619           0 :     return hls;
     620             : }
     621             : 
     622             : /* utility routine for HLStoRGB */
     623           0 : static short HueToRGB(short n1, short n2, short hue)
     624             : {
     625             :     /* range check: note values passed add/subtract thirds of range */
     626           0 :     if (hue < 0)
     627           0 :         hue += HLSMAX;
     628             : 
     629           0 :     if (hue > HLSMAX)
     630           0 :         hue -= HLSMAX;
     631             : 
     632             :     /* return r,g, or b value from this tridrant */
     633           0 :     if (hue < (HLSMAX / 6))
     634           0 :         return n1 + (((n2 - n1) * hue + (HLSMAX / 12)) / (HLSMAX / 6));
     635           0 :     if (hue < (HLSMAX / 2))
     636           0 :         return n2;
     637           0 :     if (hue < ((HLSMAX * 2) / 3))
     638           0 :         return n1 + (((n2 - n1) * (((HLSMAX * 2) / 3) - hue) + (HLSMAX / 12)) /
     639           0 :                      (HLSMAX / 6));
     640             :     else
     641           0 :         return n1;
     642             : }
     643             : 
     644           0 : NWT_RGB HLStoRGB(HLS hls)
     645             : {
     646             :     NWT_RGB rgb;
     647             : 
     648           0 :     if (hls.s == 0)
     649             :     { /* achromatic case */
     650           0 :         rgb.r = static_cast<unsigned char>((hls.l * RGBMAX) / HLSMAX);
     651           0 :         rgb.g = rgb.r;
     652           0 :         rgb.b = rgb.r;
     653           0 :         if (hls.h != UNDEFINED)
     654             :         {
     655             :             /* ERROR */
     656             :         }
     657             :     }
     658             :     else
     659             :     { /* chromatic case */
     660             :         /* set up magic numbers */
     661             :         short Magic1, Magic2; /* calculated magic numbers (really!) */
     662           0 :         if (hls.l <= (HLSMAX / 2))
     663           0 :             Magic2 = (hls.l * (HLSMAX + hls.s) + (HLSMAX / 2)) / HLSMAX;
     664             :         else
     665           0 :             Magic2 = hls.l + hls.s - ((hls.l * hls.s) + (HLSMAX / 2)) / HLSMAX;
     666           0 :         Magic1 = 2 * hls.l - Magic2;
     667             : 
     668             :         /* get RGB, change units from HLSMAX to RGBMAX */
     669           0 :         rgb.r = static_cast<unsigned char>(
     670           0 :             (HueToRGB(Magic1, Magic2, hls.h + (HLSMAX / 3)) * RGBMAX +
     671           0 :              (HLSMAX / 2)) /
     672             :             HLSMAX);
     673           0 :         rgb.g = static_cast<unsigned char>(
     674           0 :             (HueToRGB(Magic1, Magic2, hls.h) * RGBMAX + (HLSMAX / 2)) / HLSMAX);
     675           0 :         rgb.b = static_cast<unsigned char>(
     676           0 :             (HueToRGB(Magic1, Magic2, hls.h - (HLSMAX / 3)) * RGBMAX +
     677           0 :              (HLSMAX / 2)) /
     678             :             HLSMAX);
     679             :     }
     680             : 
     681           0 :     return rgb;
     682             : }

Generated by: LCOV version 1.14