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