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