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

Generated by: LCOV version 1.14