1 /* ----------------------------- MNI Header -----------------------------------
2 @NAME : image_conversion.c
3 @DESCRIPTION: File of functions to manipulate image conversion variables
4 (icv). These variables allow conversion of netcdf variables
5 (the MINC image variable, in particular) to a form more
6 convenient for a program.
7 @METHOD : Routines included in this file :
8 public :
9 miicv_create
10 miicv_free
11 miicv_setdbl
12 miicv_setint
13 miicv_setlong
14 miicv_setstr
15 miicv_inqdbl
16 miicv_inqint
17 miicv_inqlong
18 miicv_inqstr
19 miicv_ndattach
20 miicv_detach
21 miicv_get
22 miicv_put
23 semiprivate :
24 MI_icv_chkid
25 private :
26 MI_icv_get_type
27 MI_icv_get_vrange
28 MI_get_default_range
29 MI_icv_get_norm
30 MI_icv_access
31 MI_icv_zero_buffer
32 MI_icv_coords_tovar
33 MI_icv_calc_scale
34 @CREATED : July 27, 1992. (Peter Neelin, Montreal Neurological Institute)
35 @MODIFIED :
36 * $Log: image_conversion.c,v $
37 * Revision 6.17 2010-03-02 12:23:14 rotor
38 * * ported HDF calls to 1.8.x
39 * * Makefile.am: updated for minccmp
40 *
41 * Revision 6.16 2008/01/17 02:33:02 rotor
42 * * removed all rcsids
43 * * removed a bunch of ^L's that somehow crept in
44 * * removed old (and outdated) BUGS file
45 *
46 * Revision 6.15 2008/01/12 19:08:14 stever
47 * Add __attribute__ ((unused)) to all rcsid variables.
48 *
49 * Revision 6.14 2007/12/12 20:55:26 rotor
50 * * added a bunch of bug fixes from Claude.
51 *
52 * Revision 6.13 2004/12/14 23:53:46 bert
53 * Get rid of compilation warnings
54 *
55 * Revision 6.12 2004/10/15 13:45:28 bert
56 * Minor changes for Windows compatibility
57 *
58 * Revision 6.11 2004/04/27 15:40:22 bert
59 * Revised logging/error handling
60 *
61 * Revision 6.10 2003/09/18 16:17:00 bert
62 * Correctly cast double to nc_type
63 *
64 * Revision 6.9 2001/11/28 15:38:07 neelin
65 * Removed limit on number of icvs that can exist at one time.
66 *
67 * Revision 6.8 2001/11/13 21:00:24 neelin
68 * Modified icv scaling calculations for no normalization. When the icv
69 * type is double, normalization is always done, regardless of the
70 * normalization setting. When the external type is floating point,
71 * normalization to the slice real range is done (essentially a valid
72 * range scaling, but where the valid range for a float is the slice real
73 * range).
74 *
75 * Revision 6.7 2001/11/13 14:15:17 neelin
76 * Added functions miget_image_range and mivar_exists
77 *
78 * Revision 6.6 2001/08/20 13:16:53 neelin
79 * Removed extraneous variables from MI_icv_get_vrange.
80 *
81 * Revision 6.5 2001/08/16 19:24:11 neelin
82 * Fixes to the code handling valid_range values.
83 *
84 * Revision 6.4 2001/08/16 16:41:31 neelin
85 * Added library functions to handle reading of datatype, sign and valid range,
86 * plus writing of valid range and setting of default ranges. These functions
87 * properly handle differences between valid_range type and image type. Such
88 * difference can cause valid data to appear as invalid when double to float
89 * conversion causes rounding in the wrong direction (out of range).
90 * Modified voxel_loop, volume_io and programs to use these functions.
91 *
92 * Revision 6.3 2001/08/16 13:32:18 neelin
93 * Partial fix for valid_range of different type from image (problems
94 * arising from double to float conversion/rounding). NOT COMPLETE.
95 *
96 * Revision 6.2 2001/04/17 18:40:12 neelin
97 * Modifications to work with NetCDF 3.x
98 * In particular, changed NC_LONG to NC_INT (and corresponding longs to ints).
99 * Changed NC_UNSPECIFIED to NC_NAT.
100 * A few fixes to the configure script.
101 *
102 * Revision 6.1 1999/10/19 14:45:07 neelin
103 * Fixed Log subsitutions for CVS
104 *
105 * Revision 6.0 1997/09/12 13:24:54 neelin
106 * Release of minc version 0.6
107 *
108 * Revision 5.0 1997/08/21 13:25:53 neelin
109 * Release of minc version 0.5
110 *
111 * Revision 4.0 1997/05/07 20:07:52 neelin
112 * Release of minc version 0.4
113 *
114 * Revision 3.3 1997/04/21 17:32:04 neelin
115 * Fixed calculation of scale for icv so that values are not re-scaled
116 * from real values to file floating-point values.
117 *
118 * Revision 3.2 1997/04/10 19:22:18 neelin
119 * Removed redefinition of NULL and added pointer casts in appropriate places.
120 *
121 * Revision 3.1 1997/04/10 18:14:50 neelin
122 * Fixed handling of invalid data when icv scale is zero.
123 *
124 * Revision 3.0 1995/05/15 19:33:12 neelin
125 * Release of minc version 0.3
126 *
127 * Revision 2.3 1995/02/08 19:14:44 neelin
128 * More changes for irix 5 lint.
129 *
130 * Revision 2.2 1995/02/08 19:01:06 neelin
131 * Moved private function declarations from minc_routines.h to appropriate file.
132 *
133 * Revision 2.1 1994/12/09 09:12:30 neelin
134 * Added test in miicv_detach to make sure that icv is attached before
135 * detaching it.
136 *
137 * Revision 2.0 94/09/28 10:37:55 neelin
138 * Release of minc version 0.2
139 *
140 * Revision 1.18 94/09/28 10:37:06 neelin
141 * Pre-release
142 *
143 * Revision 1.17 93/08/11 12:59:31 neelin
144 * We need only increment the chunk pointer (see previous fix) if we are
145 * not doing dimension conversion (dimension conversion handles the
146 * offsets itself).
147 *
148 * Revision 1.16 93/08/11 11:49:36 neelin
149 * Added RCS logging in source.
150 * Fixed bug in MI_icv_access so that pointer to values buffer is incremented
151 * as we loop through the chunks. This affected calls to miicv_get/put that
152 * had MIimagemax/min varying over the values read in one call (ie. reading
153 * or writing a volume with MIimagemax/min varying over slices will give
154 * incorrect results if the volume is read with one call).
155 *
156 January 22, 1993 (P.N.)
157 - Modified handling of icv properties with miicv_set<type>.
158 Removed routine miicv_set. Use routines miicv_setdbl,
159 miicv_setint, miicv_setlong, miicv_setstr instead (this
160 gives type checking at compile time).
161 @COPYRIGHT :
162 Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre,
163 Montreal Neurological Institute, McGill University.
164 Permission to use, copy, modify, and distribute this
165 software and its documentation for any purpose and without
166 fee is hereby granted, provided that the above copyright
167 notice appear in all copies. The author and McGill University
168 make no representations about the suitability of this
169 software for any purpose. It is provided "as is" without
170 express or implied warranty.
171 ---------------------------------------------------------------------------- */
172
173 #include "minc_private.h"
174 #include "type_limits.h"
175
176 /* Private functions */
177 PRIVATE int MI_icv_get_type(mi_icv_type *icvp, int cdfid, int varid);
178 PRIVATE int MI_icv_get_vrange(mi_icv_type *icvp, int cdfid, int varid);
179 PRIVATE double MI_get_default_range(char *what, nc_type datatype, int sign);
180 PRIVATE int MI_icv_get_norm(mi_icv_type *icvp, int cdfid, int varid);
181 PRIVATE int MI_icv_access(int operation, mi_icv_type *icvp, long start[],
182 long count[], void *values);
183 PRIVATE int MI_icv_zero_buffer(mi_icv_type *icvp, long count[], void *values);
184 PRIVATE int MI_icv_coords_tovar(mi_icv_type *icvp,
185 long icv_start[], long icv_count[],
186 long var_start[], long var_count[]);
187 PRIVATE int MI_icv_calc_scale(int operation, mi_icv_type *icvp, long coords[]);
188
189 /* Array of pointers to image conversion structures */
190 static int minc_icv_list_nalloc = 0;
191 static mi_icv_type **minc_icv_list = NULL;
192
193 /* ----------------------------- MNI Header -----------------------------------
194 @NAME : miicv_create
195 @INPUT : (none)
196 @OUTPUT : (none)
197 @RETURNS : icv id or MI_ERROR when an error occurs
198 @DESCRIPTION: Creates an image conversion variable (icv) and returns
199 a handle to it.
200 @METHOD :
201 @GLOBALS :
202 @CALLS :
203 @CREATED : August 7, 1992 (Peter Neelin)
204 @MODIFIED :
205 ---------------------------------------------------------------------------- */
miicv_create()206 MNCAPI int miicv_create()
207 {
208 int new_icv; /* Id of newly created icv */
209 mi_icv_type *icvp; /* Pointer to new icv structure */
210 int idim;
211 int new_nalloc;
212
213 MI_SAVE_ROUTINE_NAME("miicv_create");
214
215 /* Look for free slot */
216 for (new_icv=0; new_icv<minc_icv_list_nalloc; new_icv++)
217 if (minc_icv_list[new_icv]==NULL) break;
218
219 /* If none, then extend the list */
220 if (new_icv>=minc_icv_list_nalloc) {
221
222 /* How much space will be needed? */
223 new_nalloc = minc_icv_list_nalloc + MI_MAX_NUM_ICV;
224
225 /* Check for first allocation */
226 if (minc_icv_list_nalloc == 0) {
227 minc_icv_list = MALLOC(new_nalloc, mi_icv_type *);
228 }
229 else {
230 minc_icv_list = REALLOC(minc_icv_list, new_nalloc, mi_icv_type *);
231 }
232
233 /* Check that the allocation was successful */
234 if (minc_icv_list == NULL) {
235 MI_LOG_SYS_ERROR1("miicv_create");
236 MI_RETURN(MI_ERROR);
237 }
238 /* Put in NULL pointers */
239 for (new_icv=minc_icv_list_nalloc; new_icv<new_nalloc; new_icv++)
240 minc_icv_list[new_icv] = NULL;
241
242 /* Use the first free slot and update the list length */
243 new_icv = minc_icv_list_nalloc;
244 minc_icv_list_nalloc = new_nalloc;
245
246 }
247
248 /* Allocate a new structure */
249 if ((minc_icv_list[new_icv]=MALLOC(1, mi_icv_type))==NULL) {
250 MI_LOG_SYS_ERROR1("miicv_create");
251 MI_RETURN(MI_ERROR);
252 }
253 icvp=minc_icv_list[new_icv];
254
255 /* Fill in defaults */
256
257 /* Stuff for calling MI_varaccess */
258 icvp->do_scale = FALSE;
259 icvp->do_dimconvert = FALSE;
260 icvp->do_fillvalue = FALSE;
261 icvp->fill_valid_min = -DBL_MAX;
262 icvp->fill_valid_max = DBL_MAX;
263
264 /* User defaults */
265 icvp->user_type = NC_SHORT;
266 icvp->user_typelen = nctypelen(icvp->user_type);
267 icvp->user_sign = MI_PRIV_SIGNED;
268 icvp->user_do_range = TRUE;
269 icvp->user_vmax = MI_get_default_range(MIvalid_max, icvp->user_type,
270 icvp->user_sign);
271 icvp->user_vmin = MI_get_default_range(MIvalid_min, icvp->user_type,
272 icvp->user_sign);
273 icvp->user_do_norm = FALSE;
274 icvp->user_user_norm = FALSE;
275 icvp->user_maxvar = strdup(MIimagemax);
276 icvp->user_minvar = strdup(MIimagemin);
277 icvp->user_imgmax = MI_DEFAULT_MAX;
278 icvp->user_imgmin = MI_DEFAULT_MIN;
279 icvp->user_do_dimconv = FALSE;
280 icvp->user_do_scalar = TRUE;
281 icvp->user_xdim_dir = MI_ICV_POSITIVE;
282 icvp->user_ydim_dir = MI_ICV_POSITIVE;
283 icvp->user_zdim_dir = MI_ICV_POSITIVE;
284 icvp->user_num_imgdims = 2;
285 icvp->user_keep_aspect = TRUE;
286 icvp->user_do_fillvalue = FALSE;
287 icvp->user_fillvalue = -DBL_MAX;
288 for (idim=0; idim<MI_MAX_IMGDIMS; idim++) {
289 icvp->user_dim_size[idim]=MI_ICV_ANYSIZE;
290 }
291
292 /* Variable values */
293 icvp->cdfid = MI_ERROR; /* Set so that we can recognise an */
294 icvp->varid = MI_ERROR; /* unattached icv */
295
296 /* Values that can be read by user */
297 icvp->derv_imgmax = MI_DEFAULT_MAX;
298 icvp->derv_imgmin = MI_DEFAULT_MIN;
299 for (idim=0; idim<MI_MAX_IMGDIMS; idim++) {
300 icvp->derv_dim_step[idim] = 0.0;
301 icvp->derv_dim_start[idim] = 0.0;
302 }
303
304 MI_RETURN(new_icv);
305 }
306
307 /* ----------------------------- MNI Header -----------------------------------
308 @NAME : miicv_free
309 @INPUT : icvid
310 @OUTPUT : (none)
311 @RETURNS : MI_ERROR if an error occurs
312 @DESCRIPTION: Frees the image conversion variable (icv)
313 @METHOD :
314 @GLOBALS :
315 @CALLS :
316 @CREATED : August 7, 1992 (Peter Neelin)
317 @MODIFIED :
318 ---------------------------------------------------------------------------- */
miicv_free(int icvid)319 MNCAPI int miicv_free(int icvid)
320 {
321 mi_icv_type *icvp;
322
323 MI_SAVE_ROUTINE_NAME("miicv_free");
324
325 /* Check icv id */
326 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
327
328 /* Detach the icv if it is attached */
329 if (icvp->cdfid != MI_ERROR) {
330 if (miicv_detach(icvid) < 0) {
331 MI_RETURN(MI_ERROR);
332 }
333 }
334
335 /* Free anything allocated at creation time */
336 FREE(icvp->user_maxvar);
337 FREE(icvp->user_minvar);
338
339 /* Free the structure */
340 FREE(icvp);
341 minc_icv_list[icvid]=NULL;
342
343 /* Delete entire structure if no longer in use. */
344 int new_icv;
345 for (new_icv=0; new_icv<minc_icv_list_nalloc; new_icv++)
346 if (minc_icv_list[new_icv]!=NULL) break;
347
348 if (new_icv>=minc_icv_list_nalloc) {
349 FREE(minc_icv_list);
350 minc_icv_list_nalloc=0;
351 }
352
353 MI_RETURN(MI_NOERROR);
354 }
355
356 /* ----------------------------- MNI Header -----------------------------------
357 @NAME : miicv_setdbl
358 @INPUT : icvid - icv id
359 icv_property - property of icv to set
360 value - value to set it to
361 @OUTPUT : (none)
362 @RETURNS : MI_ERROR if an error occurs
363 @DESCRIPTION: Sets a property of an icv to a given double value
364 Properties cannot be modified while the icv is attached to a
365 cdf file and variable (see miicv_attach and miicv_detach).
366 @METHOD :
367 @GLOBALS :
368 @CALLS :
369 @CREATED : August 7, 1992 (Peter Neelin)
370 @MODIFIED :
371 ---------------------------------------------------------------------------- */
miicv_setdbl(int icvid,int icv_property,double value)372 MNCAPI int miicv_setdbl(int icvid, int icv_property, double value)
373 {
374 int ival, idim;
375 mi_icv_type *icvp;
376
377 MI_SAVE_ROUTINE_NAME("miicv_setdbl");
378
379 /* Check icv id */
380 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
381
382 /* Check that the icv is not attached to a file */
383 if (icvp->cdfid != MI_ERROR) {
384 MI_LOG_ERROR(MI_MSG_ICVATTACHED);
385 MI_RETURN(MI_ERROR);
386 }
387
388 /* Set the property */
389 switch (icv_property) {
390 case MI_ICV_TYPE:
391 icvp->user_type = (nc_type) (int) value;
392 icvp->user_typelen= nctypelen(icvp->user_type);
393 icvp->user_vmax = MI_get_default_range(MIvalid_max, icvp->user_type,
394 icvp->user_sign);
395 icvp->user_vmin = MI_get_default_range(MIvalid_min, icvp->user_type,
396 icvp->user_sign);
397 break;
398 case MI_ICV_DO_RANGE:
399 icvp->user_do_range = value;
400 break;
401 case MI_ICV_VALID_MAX:
402 icvp->user_vmax = value;
403 break;
404 case MI_ICV_VALID_MIN:
405 icvp->user_vmin = value;
406 break;
407 case MI_ICV_DO_NORM:
408 icvp->user_do_norm = value;
409 break;
410 case MI_ICV_USER_NORM:
411 icvp->user_user_norm = value;
412 break;
413 case MI_ICV_IMAGE_MAX:
414 icvp->user_imgmax = value;
415 break;
416 case MI_ICV_IMAGE_MIN:
417 icvp->user_imgmin = value;
418 break;
419 case MI_ICV_DO_FILLVALUE:
420 icvp->user_do_fillvalue = value;
421 break;
422 case MI_ICV_FILLVALUE:
423 icvp->user_fillvalue = value;
424 break;
425 case MI_ICV_DO_DIM_CONV:
426 icvp->user_do_dimconv = value;
427 break;
428 case MI_ICV_DO_SCALAR:
429 icvp->user_do_scalar = value;
430 break;
431 case MI_ICV_XDIM_DIR:
432 ival = value;
433 icvp->user_xdim_dir = ((ival==MI_ICV_POSITIVE) ||
434 (ival==MI_ICV_NEGATIVE)) ? ival : MI_ICV_ANYDIR;
435 break;
436 case MI_ICV_YDIM_DIR:
437 ival = value;
438 icvp->user_ydim_dir = ((ival==MI_ICV_POSITIVE) ||
439 (ival==MI_ICV_NEGATIVE)) ? ival : MI_ICV_ANYDIR;
440 break;
441 case MI_ICV_ZDIM_DIR:
442 ival = value;
443 icvp->user_zdim_dir = ((ival==MI_ICV_POSITIVE) ||
444 (ival==MI_ICV_NEGATIVE)) ? ival : MI_ICV_ANYDIR;
445 break;
446 case MI_ICV_NUM_IMGDIMS:
447 ival = value;
448 if ((ival<0) || (ival>MI_MAX_IMGDIMS)) {
449 MI_LOG_ERROR(MI_MSG_BADPROP, _("MI_ICV_NUM_IMGDIMS out of range"));
450 MI_RETURN(MI_ERROR);
451 }
452 icvp->user_num_imgdims = ival;
453 break;
454 case MI_ICV_ADIM_SIZE:
455 icvp->user_dim_size[0] = value;
456 break;
457 case MI_ICV_BDIM_SIZE:
458 icvp->user_dim_size[1] = value;
459 break;
460 case MI_ICV_KEEP_ASPECT:
461 icvp->user_keep_aspect = value;
462 break;
463 case MI_ICV_SIGN:
464 case MI_ICV_MAXVAR:
465 case MI_ICV_MINVAR:
466 MI_LOG_ERROR(MI_MSG_BADPROP,
467 _("Can't store a number in a string value"));
468 MI_RETURN(MI_ERROR);
469 break;
470 default:
471 /* Check for image dimension properties */
472 if ((icv_property>=MI_ICV_DIM_SIZE) &&
473 (icv_property<MI_ICV_DIM_SIZE+MI_MAX_IMGDIMS)) {
474 idim = icv_property - MI_ICV_DIM_SIZE;
475 icvp->user_dim_size[idim] = value;
476 }
477 else {
478 MI_LOG_ERROR(MI_MSG_BADPROP, "Unknown code");
479 MI_RETURN(MI_ERROR);
480 }
481 break;
482 }
483
484 MI_RETURN(MI_NOERROR);
485 }
486
487 /* ----------------------------- MNI Header -----------------------------------
488 @NAME : miicv_setint
489 @INPUT : icvid - icv id
490 icv_property - property of icv to set
491 value - value to set it to
492 @OUTPUT : (none)
493 @RETURNS : MI_ERROR if an error occurs
494 @DESCRIPTION: Sets a property of an icv to a given integer value.
495 Properties cannot be modified while the icv is attached to a
496 cdf file and variable (see miicv_attach and miicv_detach).
497 @METHOD :
498 @GLOBALS :
499 @CALLS :
500 @CREATED : August 7, 1992 (Peter Neelin)
501 @MODIFIED : January 22, 1993 (P.N.)
502 - modified handling of icv properties
503 ---------------------------------------------------------------------------- */
miicv_setint(int icvid,int icv_property,int value)504 MNCAPI int miicv_setint(int icvid, int icv_property, int value)
505 {
506
507 MI_SAVE_ROUTINE_NAME("miicv_setint");
508
509 if (miicv_setdbl(icvid, icv_property, (double) value) < 0) {
510 MI_RETURN(MI_ERROR);
511 }
512
513 MI_RETURN(MI_NOERROR);
514 }
515
516 /* ----------------------------- MNI Header -----------------------------------
517 @NAME : miicv_setlong
518 @INPUT : icvid - icv id
519 icv_property - property of icv to set
520 value - value to set it to
521 @OUTPUT : (none)
522 @RETURNS : MI_ERROR if an error occurs
523 @DESCRIPTION: Sets a property of an icv to a given long integer value.
524 Properties cannot be modified while the icv is attached to a
525 cdf file and variable (see miicv_attach and miicv_detach).
526 @METHOD :
527 @GLOBALS :
528 @CALLS :
529 @CREATED : January 22, 1993 (Peter Neelin)
530 @MODIFIED :
531 ---------------------------------------------------------------------------- */
miicv_setlong(int icvid,int icv_property,long value)532 MNCAPI int miicv_setlong(int icvid, int icv_property, long value)
533 {
534
535 MI_SAVE_ROUTINE_NAME("miicv_setlong");
536
537 if (miicv_setdbl(icvid, icv_property, (double) value) < 0) {
538 MI_RETURN(MI_ERROR);
539 }
540
541 MI_RETURN(MI_NOERROR);
542 }
543
544 /* ----------------------------- MNI Header -----------------------------------
545 @NAME : miicv_setstr
546 @INPUT : icvid - icv id
547 icv_property - property of icv to set
548 value - value to set it to
549 @OUTPUT : (none)
550 @RETURNS : MI_ERROR if an error occurs
551 @DESCRIPTION: Sets a property of an icv to a given string value.
552 Properties cannot be modified while the icv is attached to a
553 cdf file and variable (see miicv_attach and miicv_detach).
554 @METHOD :
555 @GLOBALS :
556 @CALLS :
557 @CREATED : January 22, 1993 (Peter Neelin)
558 @MODIFIED :
559 ---------------------------------------------------------------------------- */
miicv_setstr(int icvid,int icv_property,const char * value)560 MNCAPI int miicv_setstr(int icvid, int icv_property, const char *value)
561 {
562 mi_icv_type *icvp;
563
564 MI_SAVE_ROUTINE_NAME("miicv_setstr");
565
566 /* Check icv id */
567 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
568
569 /* Check that the icv is not attached to a file */
570 if (icvp->cdfid != MI_ERROR) {
571 MI_LOG_ERROR(MI_MSG_ICVATTACHED);
572 MI_RETURN(MI_ERROR);
573 }
574
575 /* Set the property */
576 switch (icv_property) {
577 case MI_ICV_SIGN:
578 icvp->user_sign = MI_get_sign_from_string(icvp->user_type, value);
579 icvp->user_vmax = MI_get_default_range(MIvalid_max, icvp->user_type,
580 icvp->user_sign);
581 icvp->user_vmin = MI_get_default_range(MIvalid_min, icvp->user_type,
582 icvp->user_sign);
583 break;
584 case MI_ICV_MAXVAR:
585 if (value!=NULL) {
586 FREE(icvp->user_maxvar);
587 icvp->user_maxvar = strdup(value);
588 }
589 break;
590 case MI_ICV_MINVAR:
591 if (value!=NULL) {
592 FREE(icvp->user_minvar);
593 icvp->user_minvar = strdup(value);
594 }
595 break;
596 case MI_ICV_TYPE:
597 case MI_ICV_DO_RANGE:
598 case MI_ICV_VALID_MAX:
599 case MI_ICV_VALID_MIN:
600 case MI_ICV_DO_NORM:
601 case MI_ICV_USER_NORM:
602 case MI_ICV_IMAGE_MAX:
603 case MI_ICV_IMAGE_MIN:
604 case MI_ICV_DO_DIM_CONV:
605 case MI_ICV_DO_SCALAR:
606 case MI_ICV_XDIM_DIR:
607 case MI_ICV_YDIM_DIR:
608 case MI_ICV_ZDIM_DIR:
609 case MI_ICV_NUM_IMGDIMS:
610 case MI_ICV_ADIM_SIZE:
611 case MI_ICV_BDIM_SIZE:
612 case MI_ICV_KEEP_ASPECT:
613 MI_LOG_ERROR(MI_MSG_BADPROP, "Can't store a string in a numeric property");
614 MI_RETURN(MI_ERROR);
615 break;
616 default:
617 /* Check for image dimension properties */
618 if ((icv_property>=MI_ICV_DIM_SIZE) &&
619 (icv_property<MI_ICV_DIM_SIZE+MI_MAX_IMGDIMS)) {
620 MI_LOG_ERROR(MI_MSG_BADPROP, "Can't store a string in a numeric property");
621 MI_RETURN(MI_ERROR);
622 }
623 else {
624 MI_LOG_ERROR(MI_MSG_BADPROP, "Unknown code");
625 MI_RETURN(MI_ERROR);
626 }
627 break;
628 }
629
630 MI_RETURN(MI_NOERROR);
631 }
632
633 /* ----------------------------- MNI Header -----------------------------------
634 @NAME : miicv_inqdbl
635 @INPUT : icvid - icv id
636 icv_property - icv property to get
637 @OUTPUT : value - value returned
638 @RETURNS : MI_ERROR if an error occurs
639 @DESCRIPTION: Gets the value of an icv property
640 @METHOD :
641 @GLOBALS :
642 @CALLS :
643 @CREATED : January 22, 1993 (Peter Neelin)
644 @MODIFIED :
645 ---------------------------------------------------------------------------- */
miicv_inqdbl(int icvid,int icv_property,double * value)646 MNCAPI int miicv_inqdbl(int icvid, int icv_property, double *value)
647 {
648 int idim;
649 mi_icv_type *icvp;
650
651 MI_SAVE_ROUTINE_NAME("miicv_inqdbl");
652
653 /* Check icv id */
654 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
655
656 /* Set the property */
657 switch (icv_property) {
658 case MI_ICV_TYPE:
659 *value = icvp->user_type; break;
660 case MI_ICV_DO_RANGE:
661 *value = icvp->user_do_range; break;
662 case MI_ICV_VALID_MAX:
663 *value = icvp->user_vmax; break;
664 case MI_ICV_VALID_MIN:
665 *value = icvp->user_vmin; break;
666 case MI_ICV_DO_NORM:
667 *value = icvp->user_do_norm; break;
668 case MI_ICV_USER_NORM:
669 *value = icvp->user_user_norm; break;
670 case MI_ICV_IMAGE_MAX:
671 *value = icvp->user_imgmax; break;
672 case MI_ICV_IMAGE_MIN:
673 *value = icvp->user_imgmin; break;
674 case MI_ICV_NORM_MAX:
675 *value = icvp->derv_imgmax; break;
676 case MI_ICV_NORM_MIN:
677 *value = icvp->derv_imgmin; break;
678 case MI_ICV_DO_FILLVALUE:
679 *value = icvp->user_do_fillvalue; break;
680 case MI_ICV_FILLVALUE:
681 *value = icvp->user_fillvalue; break;
682 case MI_ICV_DO_DIM_CONV:
683 *value = icvp->user_do_dimconv; break;
684 case MI_ICV_DO_SCALAR:
685 *value = icvp->user_do_scalar; break;
686 case MI_ICV_XDIM_DIR:
687 *value = icvp->user_xdim_dir; break;
688 case MI_ICV_YDIM_DIR:
689 *value = icvp->user_ydim_dir; break;
690 case MI_ICV_ZDIM_DIR:
691 *value = icvp->user_zdim_dir; break;
692 case MI_ICV_NUM_IMGDIMS:
693 *value = icvp->user_num_imgdims; break;
694 case MI_ICV_NUM_DIMS:
695 *value = icvp->var_ndims;
696 if (icvp->var_is_vector && icvp->user_do_scalar) (*value)--;
697 break;
698 case MI_ICV_CDFID:
699 *value = icvp->cdfid; break;
700 case MI_ICV_VARID:
701 *value = icvp->varid; break;
702 case MI_ICV_ADIM_SIZE:
703 *value = icvp->user_dim_size[0]; break;
704 case MI_ICV_BDIM_SIZE:
705 *value = icvp->user_dim_size[1]; break;
706 case MI_ICV_ADIM_STEP:
707 *value = icvp->derv_dim_step[0]; break;
708 case MI_ICV_BDIM_STEP:
709 *value = icvp->derv_dim_step[1]; break;
710 case MI_ICV_ADIM_START:
711 *value = icvp->derv_dim_start[0]; break;
712 case MI_ICV_BDIM_START:
713 *value = icvp->derv_dim_start[1]; break;
714 case MI_ICV_KEEP_ASPECT:
715 *value = icvp->user_keep_aspect; break;
716 case MI_ICV_SIGN:
717 case MI_ICV_MAXVAR:
718 case MI_ICV_MINVAR:
719 MI_LOG_ERROR(MI_MSG_BADPROP,
720 _("Tried to get icv string property as a number"));
721 MI_RETURN(MI_ERROR);
722 break;
723 default:
724 /* Check for image dimension properties */
725 if ((icv_property>=MI_ICV_DIM_SIZE) &&
726 (icv_property<MI_ICV_DIM_SIZE+MI_MAX_IMGDIMS)) {
727 idim = icv_property - MI_ICV_DIM_SIZE;
728 *value = icvp->user_dim_size[idim];
729 }
730 else if ((icv_property>=MI_ICV_DIM_STEP) &&
731 (icv_property<MI_ICV_DIM_STEP+MI_MAX_IMGDIMS)) {
732 idim = icv_property - MI_ICV_DIM_STEP;
733 *value = icvp->derv_dim_step[idim];
734 }
735 else if ((icv_property>=MI_ICV_DIM_START) &&
736 (icv_property<MI_ICV_DIM_START+MI_MAX_IMGDIMS)) {
737 idim = icv_property - MI_ICV_DIM_START;
738 *value = icvp->derv_dim_start[idim];
739 }
740 else {
741 MI_LOG_ERROR(MI_MSG_BADPROP, _("Tried to get unknown icv property"));
742 MI_RETURN(MI_ERROR);
743 }
744 break;
745 }
746
747 MI_RETURN(MI_NOERROR);
748 }
749
750
751 /* ----------------------------- MNI Header -----------------------------------
752 @NAME : miicv_inqint
753 @INPUT : icvid - icv id
754 icv_property - icv property to get
755 @OUTPUT : value - value returned
756 @RETURNS : MI_ERROR if an error occurs
757 @DESCRIPTION: Gets the value of an icv property
758 @METHOD :
759 @GLOBALS :
760 @CALLS :
761 @CREATED : January 22, 1993 (Peter Neelin)
762 @MODIFIED :
763 ---------------------------------------------------------------------------- */
miicv_inqint(int icvid,int icv_property,int * value)764 MNCAPI int miicv_inqint(int icvid, int icv_property, int *value)
765 {
766 double dvalue;
767
768 MI_SAVE_ROUTINE_NAME("miicv_inqint");
769
770 if (miicv_inqdbl(icvid, icv_property, &dvalue) < 0) {
771 MI_RETURN(MI_ERROR);
772 }
773
774 *value = dvalue;
775
776 MI_RETURN(MI_NOERROR);
777 }
778
779
780 /* ----------------------------- MNI Header -----------------------------------
781 @NAME : miicv_inqlong
782 @INPUT : icvid - icv id
783 icv_property - icv property to get
784 @OUTPUT : value - value returned
785 @RETURNS : MI_ERROR if an error occurs
786 @DESCRIPTION: Gets the value of an icv property
787 @METHOD :
788 @GLOBALS :
789 @CALLS :
790 @CREATED : January 22, 1993 (Peter Neelin)
791 @MODIFIED :
792 ---------------------------------------------------------------------------- */
miicv_inqlong(int icvid,int icv_property,long * value)793 MNCAPI int miicv_inqlong(int icvid, int icv_property, long *value)
794 {
795 double dvalue;
796
797 MI_SAVE_ROUTINE_NAME("miicv_inqlong");
798
799 if (miicv_inqdbl(icvid, icv_property, &dvalue) < 0) {
800 MI_RETURN(MI_ERROR);
801 }
802
803 *value = dvalue;
804
805 MI_RETURN(MI_NOERROR);
806 }
807
808
809 /* ----------------------------- MNI Header -----------------------------------
810 @NAME : miicv_inqstr
811 @INPUT : icvid - icv id
812 icv_property - icv property to get
813 @OUTPUT : value - value returned. Caller must allocate enough
814 space for return string.
815 @RETURNS : MI_ERROR if an error occurs
816 @DESCRIPTION: Gets the value of an icv property
817 @METHOD :
818 @GLOBALS :
819 @CALLS :
820 @CREATED :
821 @MODIFIED :
822 ---------------------------------------------------------------------------- */
miicv_inqstr(int icvid,int icv_property,char * value)823 MNCAPI int miicv_inqstr(int icvid, int icv_property, char *value)
824 {
825 mi_icv_type *icvp;
826
827 MI_SAVE_ROUTINE_NAME("miicv_inqstr");
828
829 /* Check icv id */
830 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
831
832 /* Set the property */
833 switch (icv_property) {
834 case MI_ICV_SIGN:
835 if (icvp->user_sign==MI_PRIV_SIGNED)
836 (void) strcpy(value, MI_SIGNED);
837 else if (icvp->user_sign==MI_PRIV_UNSIGNED)
838 (void) strcpy(value, MI_UNSIGNED);
839 else
840 (void) strcpy(value, MI_EMPTY_STRING);
841 break;
842 case MI_ICV_MAXVAR:
843 (void) strcpy(value, icvp->user_maxvar);
844 break;
845 case MI_ICV_MINVAR:
846 (void) strcpy(value, icvp->user_minvar);
847 break;
848 case MI_ICV_TYPE:
849 case MI_ICV_DO_RANGE:
850 case MI_ICV_VALID_MAX:
851 case MI_ICV_VALID_MIN:
852 case MI_ICV_DO_NORM:
853 case MI_ICV_USER_NORM:
854 case MI_ICV_IMAGE_MAX:
855 case MI_ICV_IMAGE_MIN:
856 case MI_ICV_NORM_MAX:
857 case MI_ICV_NORM_MIN:
858 case MI_ICV_DO_DIM_CONV:
859 case MI_ICV_DO_SCALAR:
860 case MI_ICV_XDIM_DIR:
861 case MI_ICV_YDIM_DIR:
862 case MI_ICV_ZDIM_DIR:
863 case MI_ICV_NUM_IMGDIMS:
864 case MI_ICV_ADIM_SIZE:
865 case MI_ICV_BDIM_SIZE:
866 case MI_ICV_ADIM_STEP:
867 case MI_ICV_BDIM_STEP:
868 case MI_ICV_ADIM_START:
869 case MI_ICV_BDIM_START:
870 case MI_ICV_KEEP_ASPECT:
871 case MI_ICV_NUM_DIMS:
872 case MI_ICV_CDFID:
873 case MI_ICV_VARID:
874 MI_LOG_ERROR(MI_MSG_BADPROP,
875 _("Tried to get icv numeric property as a string"));
876 MI_RETURN(MI_ERROR);
877 break;
878 default:
879 /* Check for image dimension properties */
880 if (((icv_property>=MI_ICV_DIM_SIZE) &&
881 (icv_property<MI_ICV_DIM_SIZE+MI_MAX_IMGDIMS)) ||
882 ((icv_property>=MI_ICV_DIM_STEP) &&
883 (icv_property<MI_ICV_DIM_STEP+MI_MAX_IMGDIMS)) ||
884 ((icv_property>=MI_ICV_DIM_START) &&
885 (icv_property<MI_ICV_DIM_START+MI_MAX_IMGDIMS))) {
886 MI_LOG_ERROR(MI_MSG_BADPROP,
887 _("Tried to get icv numeric property as a string"));
888 MI_RETURN(MI_ERROR);
889 }
890 else {
891 MI_LOG_ERROR(MI_MSG_BADPROP,
892 _("Tried to get unknown icv property"));
893 MI_RETURN(MI_ERROR);
894 }
895 break;
896 }
897
898 MI_RETURN(MI_NOERROR);
899 }
900
901
902 /* ----------------------------- MNI Header -----------------------------------
903 @NAME : miicv_ndattach
904 @INPUT : icvid - icv id
905 cdfid - cdf file id
906 varid - cdf variable id
907 @OUTPUT : (none)
908 @RETURNS : MI_ERROR if an error occurs
909 @DESCRIPTION: Attaches an open cdf file and variable to an image conversion
910 variable for subsequent access through miicvget and miicvput.
911 File must be in data mode. This routine differs from
912 miicv_attach in that no dimension conversions will be made
913 on the variable (avoids linking in a significant amount
914 of code).
915 @METHOD :
916 @GLOBALS :
917 @CALLS : NetCDF routines
918 @CREATED : September 9, 1992 (Peter Neelin)
919 @MODIFIED :
920 ---------------------------------------------------------------------------- */
miicv_ndattach(int icvid,int cdfid,int varid)921 MNCAPI int miicv_ndattach(int icvid, int cdfid, int varid)
922 {
923 mi_icv_type *icvp; /* Pointer to icv structure */
924 int idim;
925
926 MI_SAVE_ROUTINE_NAME("miicv_ndattach");
927
928 /* Check icv id */
929 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
930
931 /* If the icv is attached, then detach it */
932 if (icvp->cdfid != MI_ERROR) {
933 if (miicv_detach(icvid) < 0) {
934 MI_RETURN(MI_ERROR);
935 }
936 }
937
938 /* Inquire about the variable's type, sign and number of dimensions */
939 if (MI_icv_get_type(icvp, cdfid, varid) < 0) {
940 MI_RETURN(MI_ERROR);
941 }
942
943 /* If not doing range calculations, just set derv_firstdim for
944 MI_icv_access, otherwise, call routines to calculate range and
945 normalization */
946 if (!icvp->user_do_range) {
947 icvp->derv_firstdim = -1;
948 }
949 else {
950 /* Get valid range */
951 if (MI_icv_get_vrange(icvp, cdfid, varid) < 0) {
952 MI_RETURN(MI_ERROR);
953 }
954
955 /* Get normalization info */
956 if (MI_icv_get_norm(icvp, cdfid, varid) < 0) {
957 MI_RETURN(MI_ERROR);
958 }
959 }
960
961 /* Set other fields to defaults */
962 icvp->var_is_vector = FALSE;
963 icvp->var_vector_size = 1;
964 icvp->derv_do_zero = FALSE;
965 icvp->derv_do_bufsize_step = FALSE;
966 icvp->derv_var_pix_off = NULL;
967 icvp->derv_usr_pix_off = NULL;
968 for (idim=0; idim<icvp->user_num_imgdims; idim++) {
969 icvp->derv_dim_flip[idim] = FALSE;
970 icvp->derv_dim_grow[idim] = TRUE;
971 icvp->derv_dim_scale[idim] = 1;
972 icvp->derv_dim_off[idim] = 0;
973 icvp->derv_dim_step[idim] = 0.0;
974 icvp->derv_dim_start[idim] = 0.0;
975 }
976
977 /* Set the do_scale and do_dimconvert fields of icv structure
978 We have to scale only if do_range is TRUE. If ranges don't
979 match, or we have to do user normalization, or if we are normalizing
980 and MIimagemax or MIimagemin vary over the variable. We don't have
981 to scale if input and output are both floating point. */
982
983 icvp->do_scale =
984 (icvp->user_do_range &&
985 ((icvp->user_vmax!=icvp->var_vmax) ||
986 (icvp->user_vmin!=icvp->var_vmin) ||
987 (icvp->user_do_norm && icvp->user_user_norm) ||
988 (icvp->user_do_norm && (icvp->derv_firstdim>=0))) );
989
990 if ((icvp->derv_usr_float && icvp->derv_var_float))
991 icvp->do_scale = FALSE;
992
993 icvp->do_dimconvert = FALSE;
994
995 /* Set the cdfid and varid fields */
996 icvp->cdfid = cdfid;
997 icvp->varid = varid;
998
999 MI_RETURN(MI_NOERROR);
1000 }
1001
1002
1003 /* ----------------------------- MNI Header -----------------------------------
1004 @NAME : MI_icv_get_type
1005 @INPUT : icvp - pointer to icv structure
1006 cdfid - cdf file id
1007 varid - variable id
1008 @OUTPUT : (none)
1009 @RETURNS : MI_ERROR if an error occurs
1010 @DESCRIPTION: Gets the type and sign of a variable for miicv_attach.
1011 @METHOD :
1012 @GLOBALS :
1013 @CALLS : NetCDF routines
1014 @CREATED : August 10, 1992 (Peter Neelin)
1015 @MODIFIED :
1016 ---------------------------------------------------------------------------- */
MI_icv_get_type(mi_icv_type * icvp,int cdfid,int varid)1017 PRIVATE int MI_icv_get_type(mi_icv_type *icvp, int cdfid, int varid)
1018 {
1019 int oldncopts; /* For saving value of ncopts */
1020 char stringa[MI_MAX_ATTSTR_LEN];
1021 char *string=stringa; /* String for sign info */
1022
1023 MI_SAVE_ROUTINE_NAME("MI_icv_get_type");
1024
1025 /* Inquire about the variable */
1026 if (ncvarinq(cdfid, varid, NULL, &(icvp->var_type),
1027 &(icvp->var_ndims), icvp->var_dim, NULL) < 0) {
1028 MI_RETURN(MI_ERROR);
1029 }
1030
1031 /* Check that the variable type is numeric */
1032 if (icvp->var_type==NC_CHAR) {
1033 MI_LOG_ERROR(MI_MSG_VARNOTNUM);
1034 MI_RETURN(MI_ERROR);
1035 }
1036
1037 /* Try to find out the sign of the variable using MIsigntype. */
1038 oldncopts =get_ncopts(); set_ncopts(0);
1039 string=miattgetstr(cdfid, varid, MIsigntype, MI_MAX_ATTSTR_LEN, string);
1040 set_ncopts(oldncopts);
1041 icvp->var_sign = MI_get_sign_from_string(icvp->var_type, string);
1042
1043 /* Get type lengths */
1044 icvp->var_typelen = nctypelen(icvp->var_type);
1045 icvp->user_typelen = nctypelen(icvp->user_type);
1046
1047 MI_RETURN(MI_NOERROR);
1048 }
1049
1050
1051 /* ----------------------------- MNI Header -----------------------------------
1052 @NAME : MI_icv_get_vrange
1053 @INPUT : icvp - pointer to icv structure
1054 cdfid - cdf file id
1055 varid - variable id
1056 @OUTPUT : (none)
1057 @RETURNS : MI_ERROR if an error occurs
1058 @DESCRIPTION: Gets the valid range of a variable
1059 @METHOD :
1060 @GLOBALS :
1061 @CALLS : NetCDF routines
1062 @CREATED : August 10, 1992 (Peter Neelin)
1063 @MODIFIED :
1064 ---------------------------------------------------------------------------- */
MI_icv_get_vrange(mi_icv_type * icvp,int cdfid,int varid)1065 PRIVATE int MI_icv_get_vrange(mi_icv_type *icvp, int cdfid, int varid)
1066 {
1067 double vrange[2]; /* Valid range buffer */
1068
1069 MI_SAVE_ROUTINE_NAME("MI_icv_get_vrange");
1070
1071 if (miget_valid_range(cdfid, varid, vrange) == MI_ERROR) {
1072 MI_RETURN(MI_ERROR);
1073 }
1074 icvp->var_vmin = vrange[0];
1075 icvp->var_vmax = vrange[1];
1076
1077 MI_RETURN(MI_NOERROR);
1078 }
1079
1080
1081 /* ----------------------------- MNI Header -----------------------------------
1082 @NAME : MI_get_default_range
1083 @INPUT : what - MIvalid_min means get default min, MIvalid_min means
1084 get default min
1085 datatype - type of variable
1086 sign - sign of variable
1087 @OUTPUT : (none)
1088 @RETURNS : default maximum or minimum for the datatype
1089 @DESCRIPTION: Return the defaults maximum or minimum for a given datatype
1090 and sign.
1091 @METHOD :
1092 @GLOBALS :
1093 @CALLS : NetCDF routines
1094 @CREATED : August 10, 1992 (Peter Neelin)
1095 @MODIFIED :
1096 ---------------------------------------------------------------------------- */
MI_get_default_range(char * what,nc_type datatype,int sign)1097 PRIVATE double MI_get_default_range(char *what, nc_type datatype, int sign)
1098 {
1099 double range[2];
1100
1101 MI_SAVE_ROUTINE_NAME("MI_get_default_range");
1102
1103 (void) miget_default_range(datatype, (sign == MI_PRIV_SIGNED), range);
1104
1105 if (STRINGS_EQUAL(what, MIvalid_max)) {
1106 MI_RETURN(range[1]);
1107 }
1108 else if (STRINGS_EQUAL(what, MIvalid_min)) {
1109 MI_RETURN(range[0]);
1110 }
1111 else {
1112 set_ncopts(NC_VERBOSE | NC_FATAL);
1113 MI_LOG_PKG_ERROR2(-1,"MINC bug - this line should never be printed");
1114 }
1115
1116 MI_RETURN(MI_DEFAULT_MIN);
1117 }
1118
1119
1120 /* ----------------------------- MNI Header -----------------------------------
1121 @NAME : MI_icv_get_norm
1122 @INPUT : icvp - pointer to icv structure
1123 cdfid - cdf file id
1124 varid - variable id
1125 @OUTPUT : (none)
1126 @RETURNS : MI_ERROR if an error occurs
1127 @DESCRIPTION: Gets the normalization info for a variable
1128 @METHOD :
1129 @GLOBALS :
1130 @CALLS : NetCDF routines
1131 @CREATED : August 10, 1992 (Peter Neelin)
1132 @MODIFIED :
1133 ---------------------------------------------------------------------------- */
MI_icv_get_norm(mi_icv_type * icvp,int cdfid,int varid)1134 PRIVATE int MI_icv_get_norm(mi_icv_type *icvp, int cdfid, int varid)
1135 /* ARGSUSED */
1136 {
1137 int oldncopts; /* For saving value of ncopts */
1138 int vid[2]; /* Variable ids for max and min */
1139 int ndims; /* Number of dimensions for image max and min */
1140 int dim[MAX_VAR_DIMS]; /* Dimensions */
1141 int imm; /* Counter for looping through max and min */
1142 double image_range[2];
1143 int idim, i;
1144
1145 MI_SAVE_ROUTINE_NAME("MI_icv_get_norm");
1146
1147 /* Check for floating point or double precision values for user or
1148 in variable - set flag to not do normalization if needed */
1149 icvp->derv_var_float = ((icvp->var_type == NC_DOUBLE) ||
1150 (icvp->var_type == NC_FLOAT));
1151 icvp->derv_usr_float = ((icvp->user_type == NC_DOUBLE) ||
1152 (icvp->user_type == NC_FLOAT));
1153
1154 /* Initialize first dimension over which MIimagemax or MIimagemin
1155 vary - assume that they don't vary at all */
1156 icvp->derv_firstdim=(-1);
1157
1158 /* Look for image max, image min variables */
1159 oldncopts=get_ncopts(); set_ncopts(0);
1160 icvp->imgmaxid=ncvarid(cdfid, icvp->user_maxvar);
1161 icvp->imgminid=ncvarid(cdfid, icvp->user_minvar);
1162 set_ncopts(oldncopts);
1163
1164 /* Check to see if normalization to variable max, min should be done */
1165 if (!icvp->user_do_norm) {
1166 icvp->derv_imgmax = MI_DEFAULT_MAX;
1167 icvp->derv_imgmin = MI_DEFAULT_MIN;
1168 }
1169 else {
1170
1171 /* Get the image min and max, either from the user definition or
1172 from the file. */
1173 if (icvp->user_user_norm) {
1174 icvp->derv_imgmax = icvp->user_imgmax;
1175 icvp->derv_imgmin = icvp->user_imgmin;
1176 }
1177 else {
1178 if (miget_image_range(cdfid, image_range) < 0) {
1179 MI_RETURN(MI_ERROR);
1180 }
1181 icvp->derv_imgmin = image_range[0];
1182 icvp->derv_imgmax = image_range[1];
1183 }
1184
1185 /* Check each of the dimensions of image-min/max variables to see
1186 which is the fastest varying dimension of the image variable. */
1187 vid[0]=icvp->imgminid;
1188 vid[1]=icvp->imgmaxid;
1189 if ((vid[0] != MI_ERROR) && (vid[1] != MI_ERROR)) {
1190 for (imm=0; imm < 2; imm++) {
1191 if (ncvarinq(cdfid, vid[imm], NULL, NULL, &ndims, dim, NULL) < 0) {
1192 MI_RETURN(MI_ERROR);
1193 }
1194 for (idim=0; idim<ndims; idim++) {
1195 for (i=0; i<icvp->var_ndims; i++) {
1196 if (icvp->var_dim[i]==dim[idim])
1197 icvp->derv_firstdim = MAX(icvp->derv_firstdim, i);
1198 }
1199 }
1200 }
1201 }
1202
1203 }
1204
1205 MI_RETURN(MI_NOERROR);
1206 }
1207
1208
1209 /* ----------------------------- MNI Header -----------------------------------
1210 @NAME : miicv_detach
1211 @INPUT : icvid - icv id
1212 @OUTPUT : (none)
1213 @RETURNS : MI_ERROR if an error occurs
1214 @DESCRIPTION: Detaches the cdf file and variable from the image conversion
1215 variable, allowing modifications to the icv.
1216 @METHOD :
1217 @GLOBALS :
1218 @CALLS : NetCDF routines
1219 @CREATED : August 10, 1992 (Peter Neelin)
1220 @MODIFIED :
1221 ---------------------------------------------------------------------------- */
miicv_detach(int icvid)1222 MNCAPI int miicv_detach(int icvid)
1223 {
1224 mi_icv_type *icvp;
1225 int idim;
1226
1227 MI_SAVE_ROUTINE_NAME("miicv_detach");
1228
1229 /* Check icv id */
1230 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
1231
1232 /* Check that the icv is in fact attached */
1233 if (icvp->cdfid == MI_ERROR)
1234 MI_RETURN(MI_NOERROR);
1235
1236 /* Free the pixel offset arrays */
1237 if (icvp->derv_var_pix_off != NULL) FREE(icvp->derv_var_pix_off);
1238 if (icvp->derv_usr_pix_off != NULL) FREE(icvp->derv_usr_pix_off);
1239
1240 /* Reset values that are read-only (and set when attached) */
1241 icvp->derv_imgmax = MI_DEFAULT_MAX;
1242 icvp->derv_imgmin = MI_DEFAULT_MIN;
1243 for (idim=0; idim<MI_MAX_IMGDIMS; idim++) {
1244 icvp->derv_dim_step[idim] = 0.0;
1245 icvp->derv_dim_start[idim] = 0.0;
1246 }
1247
1248 /* Set cdfid field to MI_ERROR to indicate that icv is detached */
1249 icvp->cdfid = MI_ERROR;
1250 icvp->varid = MI_ERROR;
1251
1252 MI_RETURN(MI_NOERROR);
1253 }
1254
1255
1256 /* ----------------------------- MNI Header -----------------------------------
1257 @NAME : miicv_get
1258 @INPUT : icvid - icv id
1259 start - coordinates of start of hyperslab (see ncvarget)
1260 count - size of hyperslab (see ncvarget)
1261 @OUTPUT : values - array of values returned
1262 @RETURNS : MI_ERROR if an error occurs
1263 @DESCRIPTION: Gets a hyperslab of values from a netcdf variable through
1264 the image conversion variable (icvid)
1265 @METHOD :
1266 @GLOBALS :
1267 @CALLS : NetCDF routines
1268 @CREATED : August 10, 1992 (Peter Neelin)
1269 @MODIFIED :
1270 ---------------------------------------------------------------------------- */
miicv_get(int icvid,long start[],long count[],void * values)1271 MNCAPI int miicv_get(int icvid, long start[], long count[], void *values)
1272 {
1273 mi_icv_type *icvp;
1274
1275 MI_SAVE_ROUTINE_NAME("miicv_get");
1276
1277 /* Check icv id */
1278 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
1279
1280 /* Get the data */
1281 if (MI_icv_access(MI_PRIV_GET, icvp, start, count, values) < 0) {
1282 MI_RETURN(MI_ERROR);
1283 }
1284
1285 MI_RETURN(MI_NOERROR);
1286 }
1287
1288
1289 /* ----------------------------- MNI Header -----------------------------------
1290 @NAME : miicv_put
1291 @INPUT : icvid - icv id
1292 start - coordinates of start of hyperslab (see ncvarput)
1293 count - size of hyperslab (see ncvarput)
1294 values - array of values to store
1295 @OUTPUT : (none)
1296 @RETURNS : MI_ERROR if an error occurs
1297 @DESCRIPTION: Stores a hyperslab of values in a netcdf variable through
1298 the image conversion variable (icvid)
1299 @METHOD :
1300 @GLOBALS :
1301 @CALLS : NetCDF routines
1302 @CREATED :
1303 @MODIFIED :
1304 ---------------------------------------------------------------------------- */
miicv_put(int icvid,long start[],long count[],void * values)1305 MNCAPI int miicv_put(int icvid, long start[], long count[], void *values)
1306 {
1307 mi_icv_type *icvp;
1308
1309 MI_SAVE_ROUTINE_NAME("miicv_put");
1310
1311 /* Check icv id */
1312 if ((icvp=MI_icv_chkid(icvid)) == NULL) MI_RETURN(MI_ERROR);
1313
1314
1315 if (MI_icv_access(MI_PRIV_PUT, icvp, start, count, values) < 0) {
1316 MI_RETURN(MI_ERROR);
1317 }
1318
1319 MI_RETURN(MI_NOERROR);
1320 }
1321
1322
1323 /* ----------------------------- MNI Header -----------------------------------
1324 @NAME : MI_icv_access
1325 @INPUT : operation - MI_PRIV_GET or MI_PRIV_PUT
1326 icvid - icv id
1327 start - coordinates of start of hyperslab (see ncvarput)
1328 count - size of hyperslab (see ncvarput)
1329 values - array of values to put
1330 @OUTPUT : values - array of values to get
1331 @RETURNS : MI_ERROR if an error occurs
1332 @DESCRIPTION: Does the work of getting or putting values from an icv.
1333 @METHOD :
1334 @GLOBALS :
1335 @CALLS : NetCDF routines
1336 @CREATED : August 11, 1992 (Peter Neelin)
1337 @MODIFIED :
1338 ---------------------------------------------------------------------------- */
MI_icv_access(int operation,mi_icv_type * icvp,long start[],long count[],void * values)1339 PRIVATE int MI_icv_access(int operation, mi_icv_type *icvp, long start[],
1340 long count[], void *values)
1341 {
1342 int *bufsize_step; /* Pointer to array giving increments
1343 for allocating variable buffer
1344 (NULL if we don't care) */
1345 long chunk_count[MAX_VAR_DIMS]; /* Number of elements to get for chunk */
1346 long chunk_start[MAX_VAR_DIMS]; /* Starting index for getting a chunk */
1347 long chunk_size; /* Size of chunk in bytes */
1348 void *chunk_values; /* Pointer to next chunk to get */
1349 long var_start[MAX_VAR_DIMS]; /* Coordinates of first var element */
1350 long var_count[MAX_VAR_DIMS]; /* Edge lengths in variable */
1351 long var_end[MAX_VAR_DIMS]; /* Coordinates of last var element */
1352 int firstdim;
1353 int idim, ndims;
1354
1355 MI_SAVE_ROUTINE_NAME("MI_icv_access");
1356
1357 /* Check that icv is attached to a variable */
1358 if (icvp->cdfid == MI_ERROR) {
1359 MI_LOG_ERROR(MI_MSG_ICVNOTATTACHED);
1360
1361 MI_RETURN(MI_ERROR);
1362 }
1363
1364 /* Zero the user's buffer if needed */
1365 if ((operation == MI_PRIV_GET) && (icvp->derv_do_zero))
1366 if (MI_icv_zero_buffer(icvp, count, values) < 0) {
1367 MI_RETURN(MI_ERROR);
1368 }
1369
1370 /* Translate icv coordinates to variable coordinates */
1371 if (MI_icv_coords_tovar(icvp, start, count, var_start, var_count) < 0) {
1372 MI_RETURN(MI_ERROR);
1373 }
1374
1375 /* Save icv coordinates for future reference (for dimension conversion
1376 routines) */
1377 ndims = icvp->var_ndims;
1378 if (icvp->var_is_vector && icvp->user_do_scalar)
1379 ndims--;
1380 for (idim=0; idim < ndims; idim++) {
1381 icvp->derv_icv_start[idim] = start[idim];
1382 icvp->derv_icv_count[idim] = count[idim];
1383 }
1384
1385 /* Do we care about getting variable in convenient increments ?
1386 Only if we are getting data and the icv structure wants it */
1387 if ((operation==MI_PRIV_GET) && (icvp->derv_do_bufsize_step))
1388 bufsize_step = icvp->derv_bufsize_step;
1389 else
1390 bufsize_step = NULL;
1391
1392 /* Set up variables for looping through variable. The biggest chunk that
1393 we can get in one call is determined by the subscripts of MIimagemax
1394 and MIimagemin. These must be constant over the chunk that we get if
1395 we are doing normalization. */
1396 for (idim=0; idim<icvp->var_ndims; idim++) {
1397 chunk_start[idim] = var_start[idim];
1398 var_end[idim]=var_start[idim]+var_count[idim];
1399 }
1400 (void) miset_coords(icvp->var_ndims, 1L, chunk_count);
1401 /* Get size of chunk in user's buffer. Dimension conversion routines
1402 don't need the buffer pointer incremented - they do it themselves */
1403 if (!icvp->do_dimconvert)
1404 chunk_size = nctypelen(icvp->user_type);
1405 else
1406 chunk_size = 0;
1407 for (idim=MAX(icvp->derv_firstdim+1,0); idim < icvp->var_ndims; idim++) {
1408 chunk_count[idim]=var_count[idim];
1409 chunk_size *= chunk_count[idim];
1410 }
1411 firstdim = MAX(icvp->derv_firstdim, 0);
1412
1413 /* Loop through variable */
1414 chunk_values = values;
1415 while (chunk_start[0] < var_end[0]) {
1416
1417 /* Set the do_fillvalue flag if the user wants it and we are doing
1418 a get. We must do it inside the loop since the scale factor
1419 calculation can change it if the scale is zero. (Fillvalue checking
1420 is always done if the the scale is zero.) */
1421 icvp->do_fillvalue =
1422 icvp->user_do_fillvalue && (operation == MI_PRIV_GET);
1423 icvp->fill_valid_min = icvp->var_vmin;
1424 icvp->fill_valid_max = icvp->var_vmax;
1425
1426 /* Calculate scale factor */
1427 if (icvp->do_scale) {
1428 if (MI_icv_calc_scale(operation, icvp, chunk_start) < 0) {
1429 MI_RETURN(MI_ERROR);
1430 }
1431 }
1432
1433 // fprintf(stderr, "Getting values at %p\n", chunk_start);
1434
1435 /* Get the values */
1436 if (MI_varaccess(operation, icvp->cdfid, icvp->varid,
1437 chunk_start, chunk_count,
1438 icvp->user_type, icvp->user_sign,
1439 chunk_values, bufsize_step, icvp) < 0) {
1440 MI_RETURN(MI_ERROR);
1441 }
1442
1443 /* Increment the start counter */
1444 chunk_start[firstdim] += chunk_count[firstdim];
1445 for (idim=firstdim;
1446 (idim>0) && (chunk_start[idim]>=var_end[idim]); idim--) {
1447 chunk_start[idim]=var_start[idim];
1448 chunk_start[idim-1]++;
1449 }
1450
1451 /* Increment the pointer to values */
1452 chunk_values = (void *) ((char *) chunk_values + (size_t) chunk_size);
1453
1454 }
1455
1456 MI_RETURN(MI_NOERROR);
1457 }
1458
1459
1460 /* ----------------------------- MNI Header -----------------------------------
1461 @NAME : MI_icv_zero_buffer
1462 @INPUT : icvp - icv structure pointer
1463 count - count vector
1464 values - pointer to user's buffer
1465 @OUTPUT :
1466 @RETURNS : MI_ERROR if an error occurs
1467 @DESCRIPTION: Zeros the user's buffer, with a size given by the vector count.
1468 @METHOD :
1469 @GLOBALS :
1470 @CALLS : NetCDF routines
1471 @CREATED : September 9, 1992 (Peter Neelin)
1472 @MODIFIED :
1473 ---------------------------------------------------------------------------- */
MI_icv_zero_buffer(mi_icv_type * icvp,long count[],void * values)1474 PRIVATE int MI_icv_zero_buffer(mi_icv_type *icvp, long count[], void *values)
1475 {
1476 double zeroval, zerobuf;
1477 void *zerostart;
1478 int zerolen, idim, ndims;
1479 char *bufptr, *bufend, *zeroptr, *zeroend;
1480 long buflen;
1481
1482 MI_SAVE_ROUTINE_NAME("MI_icv_zero_buffer");
1483
1484 /* Create a zero pixel and get its size */
1485 zerostart = (void *) (&zerobuf);
1486 if (icvp->do_scale)
1487 zeroval = icvp->offset;
1488 else
1489 zeroval = 0.0;
1490 {MI_FROM_DOUBLE(zeroval, icvp->user_type, icvp->user_sign, zerostart)}
1491 zerolen = icvp->user_typelen;
1492
1493 /* Get the buffer size */
1494 ndims = icvp->var_ndims;
1495 if (icvp->var_is_vector && icvp->user_do_scalar)
1496 ndims--;
1497 buflen = zerolen;
1498 for (idim=0; idim<ndims; idim++)
1499 buflen *= count[idim];
1500
1501 /* Loop through the buffer, copying the zero pixel */
1502 bufend = (char *) values + buflen;
1503 zeroend = (char *) zerostart + zerolen;
1504 for (bufptr = (char *) values, zeroptr = (char *) zerostart;
1505 bufptr < bufend; bufptr++, zeroptr++) {
1506 if (zeroptr >= zeroend)
1507 zeroptr = (char *) zerostart;
1508 *bufptr = *zeroptr;
1509 }
1510
1511 MI_RETURN(MI_NOERROR);
1512 }
1513
1514
1515 /* ----------------------------- MNI Header -----------------------------------
1516 @NAME : MI_icv_coords_tovar
1517 @INPUT : icvp - icv structure pointer
1518 icv_start - start vector for icv
1519 icv_count - count vector for icv
1520 @OUTPUT : var_start - start vector for variable
1521 var_count - count vector for variable
1522 @RETURNS : MI_ERROR if an error occurs
1523 @DESCRIPTION: Converts a start and count vector for referencing an icv
1524 to the corresponding vectors for referencing a NetCDF variable.
1525 @METHOD :
1526 @GLOBALS :
1527 @CALLS : NetCDF routines
1528 @CREATED : September 1, 1992 (Peter Neelin)
1529 @MODIFIED :
1530 ---------------------------------------------------------------------------- */
MI_icv_coords_tovar(mi_icv_type * icvp,long icv_start[],long icv_count[],long var_start[],long var_count[])1531 PRIVATE int MI_icv_coords_tovar(mi_icv_type *icvp,
1532 long icv_start[], long icv_count[],
1533 long var_start[], long var_count[])
1534 {
1535 int i, j;
1536 int num_non_img_dims;
1537 long coord, last_coord, icv_dim_size;
1538
1539 MI_SAVE_ROUTINE_NAME("MI_icv_coords_tovar");
1540
1541 /* Do we have to worry about dimension conversions? If not, then
1542 just copy the vectors and return. */
1543 if (!icvp->do_dimconvert) {
1544 for (i=0; i < icvp->var_ndims; i++) {
1545 var_count[i] = icv_count[i];
1546 var_start[i] = icv_start[i];
1547 }
1548 MI_RETURN(MI_NOERROR);
1549 }
1550
1551 /* Get the number of non image dimensions */
1552 num_non_img_dims=icvp->var_ndims-icvp->user_num_imgdims;
1553 if (icvp->var_is_vector)
1554 num_non_img_dims--;
1555
1556 /* Go through first, non-image dimensions */
1557 for (i=0; i < num_non_img_dims; i++) {
1558 var_count[i] = icv_count[i];
1559 var_start[i] = icv_start[i];
1560 }
1561
1562 /* Go through image dimensions */
1563 for (i=num_non_img_dims, j=icvp->user_num_imgdims-1;
1564 i < num_non_img_dims+icvp->user_num_imgdims; i++, j--) {
1565 /* Check coordinates. */
1566 icv_dim_size = (icvp->user_dim_size[j] > 0) ?
1567 icvp->user_dim_size[j] : icvp->var_dim_size[j];
1568 last_coord = icv_start[i] + icv_count[i] - 1;
1569 if ((icv_start[i]<0) || (icv_start[i]>=icv_dim_size) ||
1570 (last_coord<0) || (last_coord>=icv_dim_size) ||
1571 (icv_count[i]<0)) {
1572 MI_LOG_ERROR(MI_MSG_ICVCOORDS);
1573 MI_RETURN(MI_ERROR);
1574 }
1575 /* Remove offset */
1576 coord = icv_start[i]-icvp->derv_dim_off[j];
1577 /* Check for growing or shrinking */
1578 if (icvp->derv_dim_grow[j]) {
1579 var_count[i] = (icv_count[i]+icvp->derv_dim_scale[j]-1)
1580 /icvp->derv_dim_scale[j];
1581 coord /= icvp->derv_dim_scale[j];
1582 }
1583 else {
1584 var_count[i] = icv_count[i]*icvp->derv_dim_scale[j];
1585 coord *= icvp->derv_dim_scale[j];
1586 }
1587 /* Check for flipping */
1588 if (icvp->derv_dim_flip[j])
1589 coord = icvp->var_dim_size[j] - coord -
1590 ((icv_count!=NULL) ? var_count[i] : 0L);
1591 var_start[i] = coord;
1592 /* Check for indices out of variable bounds (but in icv bounds) */
1593 last_coord = var_start[i] + var_count[i];
1594 if ((var_start[i]<0) || (last_coord>=icvp->var_dim_size[j])) {
1595 if (var_start[i]<0) var_start[i] = 0;
1596 if (last_coord>=icvp->var_dim_size[j])
1597 last_coord = icvp->var_dim_size[j] - 1;
1598 /* Enforce similar bounds on var_start (bert) */
1599 if (var_start[i] >= icvp->var_dim_size[j])
1600 var_start[i] = icvp->var_dim_size[j] - 1;
1601 var_count[i] = last_coord - var_start[i] + 1;
1602 }
1603 }
1604
1605 /* Check for vector dimension */
1606 if (icvp->var_is_vector) {
1607 if (icvp->user_do_scalar) {
1608 var_count[icvp->var_ndims-1] = icvp->var_vector_size;
1609 var_start[icvp->var_ndims-1] = 0;
1610 }
1611 else {
1612 var_count[icvp->var_ndims-1] = icv_count[icvp->var_ndims-1];
1613 var_start[icvp->var_ndims-1] = icv_start[icvp->var_ndims-1];
1614 }
1615 }
1616
1617 MI_RETURN(MI_NOERROR);
1618 }
1619
1620
1621 /* ----------------------------- MNI Header -----------------------------------
1622 @NAME : MI_icv_calc_scale
1623 @INPUT : operation - MI_PRIV_GET or MI_PRIV_PUT
1624 icvp - icv structure pointer
1625 coords - coordinates of first value to get or put
1626 @OUTPUT : icvp - fields scale and offset set
1627 @RETURNS : MI_ERROR if an error occurs
1628 @DESCRIPTION: Calculates the scale and offset needed for getting or putting
1629 values, starting at index coords (assumes that scale is constant
1630 over that range).
1631 @METHOD :
1632 @GLOBALS :
1633 @CALLS : NetCDF routines
1634 @CREATED : August 10, 1992 (Peter Neelin)
1635 @MODIFIED :
1636 ---------------------------------------------------------------------------- */
MI_icv_calc_scale(int operation,mi_icv_type * icvp,long coords[])1637 PRIVATE int MI_icv_calc_scale(int operation, mi_icv_type *icvp, long coords[])
1638 {
1639 long mmcoords[MAX_VAR_DIMS]; /* Coordinates for max/min variable */
1640 double usr_imgmax, usr_imgmin;
1641 double var_imgmax, var_imgmin;
1642 double var_imgmax_true, var_imgmin_true;
1643 double usr_vmax, usr_vmin;
1644 double var_vmax, var_vmin;
1645 double slice_imgmax, slice_imgmin;
1646 double usr_scale;
1647 double denom;
1648
1649 MI_SAVE_ROUTINE_NAME("MI_icv_calc_scale");
1650
1651 /* Set variable valid range */
1652 var_vmax = icvp->var_vmax;
1653 var_vmin = icvp->var_vmin;
1654
1655 /* Set image max/min for user and variable values depending on whether
1656 normalization should be done or not. Whenever floating-point values
1657 are involved, some type of normalization is done. When the icv type
1658 is floating point, normalization is always done. When the file type
1659 is floating point and the icv type is integer, slices are normalized
1660 to the real range of the slice (or chunk being read). */
1661 if (!icvp->derv_var_float && !icvp->derv_usr_float && !icvp->user_do_norm) {
1662 usr_imgmax = var_imgmax = MI_DEFAULT_MAX;
1663 usr_imgmin = var_imgmin = MI_DEFAULT_MIN;
1664 }
1665 else {
1666
1667 /* Get the real range for the slice or chunk that is being examined */
1668 slice_imgmax = MI_DEFAULT_MAX;
1669 slice_imgmin = MI_DEFAULT_MIN;
1670 if ((!icvp->derv_var_float || !icvp->user_do_norm) &&
1671 (icvp->imgmaxid!=MI_ERROR) && (icvp->imgminid!=MI_ERROR)) {
1672 if (mitranslate_coords(icvp->cdfid, icvp->varid, coords,
1673 icvp->imgmaxid, mmcoords) == NULL)
1674 MI_RETURN(MI_ERROR);
1675 if (mivarget1(icvp->cdfid, icvp->imgmaxid, mmcoords,
1676 NC_DOUBLE, NULL, &slice_imgmax) < 0) {
1677 MI_RETURN(MI_ERROR);
1678 }
1679 if (mitranslate_coords(icvp->cdfid, icvp->varid, coords,
1680 icvp->imgminid, mmcoords) == NULL) {
1681 MI_RETURN(MI_ERROR);
1682 }
1683 if (mivarget1(icvp->cdfid, icvp->imgminid, mmcoords,
1684 NC_DOUBLE, NULL, &slice_imgmin) < 0) {
1685 MI_RETURN(MI_ERROR);
1686 }
1687 }
1688
1689 /* Get the user real range */
1690 if (icvp->user_do_norm) {
1691 usr_imgmax = icvp->derv_imgmax;
1692 usr_imgmin = icvp->derv_imgmin;
1693 }
1694 else {
1695 usr_imgmax = slice_imgmax;
1696 usr_imgmin = slice_imgmin;
1697 }
1698
1699 /* Get the file real range */
1700 if (icvp->derv_var_float) {
1701 var_imgmax = var_vmax;
1702 var_imgmin = var_vmin;
1703 }
1704 else {
1705 var_imgmax = slice_imgmax;
1706 var_imgmin = slice_imgmin;
1707 }
1708 }
1709
1710 /* Prevent scaling between file floats and real value */
1711 if (icvp->derv_var_float) {
1712 var_imgmax = var_vmax;
1713 var_imgmin = var_vmin;
1714 }
1715
1716 /* Get user valid range */
1717 if (icvp->derv_usr_float) {
1718 usr_vmax = usr_imgmax;
1719 usr_vmin = usr_imgmin;
1720 }
1721 else {
1722 usr_vmax = icvp->user_vmax;
1723 usr_vmin = icvp->user_vmin;
1724 }
1725
1726 /* Save real var_imgmin/max for fillvalue checking later */
1727 var_imgmax_true = var_imgmax;
1728 var_imgmin_true = var_imgmin;
1729
1730 /* Even though we have already carefully set the vmax/min and imgmax/min
1731 values to handle the floating point case, we can still have problems
1732 with the scale calculations (rounding errors) if full range max/min
1733 are used (-FLT_MAX to FLT_MAX). To avoid this, we just force the
1734 values to 0 and 1 which will give the correct scale. That is why
1735 we save the true values above. */
1736
1737 if (icvp->derv_usr_float) {
1738 usr_imgmax = usr_vmax = MI_DEFAULT_MAX;
1739 usr_imgmin = usr_vmin = MI_DEFAULT_MIN;
1740 }
1741 if (icvp->derv_var_float) {
1742 var_imgmax = var_vmax = MI_DEFAULT_MAX;
1743 var_imgmin = var_vmin = MI_DEFAULT_MIN;
1744 }
1745
1746 /* Calculate scale and offset for MI_PRIV_GET */
1747
1748 /* Scale */
1749 denom = usr_imgmax - usr_imgmin;
1750 if (denom!=0.0)
1751 usr_scale=(usr_vmax - usr_vmin) / denom;
1752 else
1753 usr_scale=0.0;
1754 denom = var_vmax - var_vmin;
1755 if (denom!=0.0)
1756 icvp->scale = usr_scale * (var_imgmax - var_imgmin) / denom;
1757 else
1758 icvp->scale = 0.0;
1759
1760 /* Offset */
1761 icvp->offset = usr_vmin - icvp->scale * var_vmin
1762 + usr_scale * (var_imgmin - usr_imgmin);
1763
1764 /* If we want a MI_PRIV_PUT, invert */
1765 if (operation==MI_PRIV_PUT) {
1766 if (icvp->scale!=0.0) {
1767 icvp->offset = (-icvp->offset) / icvp->scale;
1768 icvp->scale = 1.0/icvp->scale;
1769 }
1770 else {
1771 icvp->offset = var_vmin;
1772 icvp->scale = 0.0;
1773 }
1774 }
1775
1776 /* Do fill value checking if scale is zero */
1777 if (icvp->scale == 0.0) {
1778
1779 /* Check for floating point on both sides of conversion. We should
1780 not be doing scaling in this case, but we will check to be safe. */
1781 if (icvp->derv_var_float && icvp->derv_usr_float) {
1782 icvp->do_scale = FALSE;
1783 icvp->do_fillvalue = FALSE;
1784 }
1785
1786 else { /* Not pure floating point */
1787
1788 icvp->do_fillvalue = TRUE;
1789
1790 /* For output, set the range properly depending on whether the user
1791 type is floating point or not */
1792 if (operation == MI_PRIV_PUT) {
1793 if (icvp->derv_usr_float) {
1794 icvp->fill_valid_min = var_imgmin_true;
1795 icvp->fill_valid_max = var_imgmax_true;
1796 }
1797 else if (usr_scale != 0.0) {
1798 icvp->fill_valid_min =
1799 usr_vmin + (var_imgmin_true - usr_imgmin) / usr_scale;
1800 icvp->fill_valid_max =
1801 usr_vmin + (var_imgmax_true - usr_imgmin) / usr_scale;
1802 }
1803 else {
1804 icvp->fill_valid_min = usr_vmin;
1805 icvp->fill_valid_max = usr_vmax;
1806 }
1807 } /* If output operation */
1808
1809 } /* If not pure floating point */
1810
1811 } /* If scale == 0.0 */
1812
1813 MI_RETURN(MI_NOERROR);
1814 }
1815
1816
1817 /* ----------------------------- MNI Header -----------------------------------
1818 @NAME : MI_icv_chkid
1819 @INPUT : icvid - icv id
1820 @OUTPUT : (none)
1821 @RETURNS : Pointer to icv structure if it exists, otherwise NULL.
1822 @DESCRIPTION: Checks that an icv id is valid and returns a pointer to the
1823 structure.
1824 @METHOD :
1825 @GLOBALS :
1826 @CALLS : NetCDF routines
1827 @CREATED : August 7, 1992 (Peter Neelin)
1828 @MODIFIED :
1829 ---------------------------------------------------------------------------- */
MI_icv_chkid(int icvid)1830 SEMIPRIVATE mi_icv_type *MI_icv_chkid(int icvid)
1831 {
1832 MI_SAVE_ROUTINE_NAME("MI_icv_chkid");
1833
1834 /* Check icv id */
1835 if ((icvid<0) || (icvid>=minc_icv_list_nalloc) ||
1836 (minc_icv_list[icvid]==NULL)) {
1837 MI_LOG_ERROR(MI_MSG_BADICV);
1838 MI_RETURN((void *) NULL);
1839 }
1840
1841 MI_RETURN(minc_icv_list[icvid]);
1842 }
1843