1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
|
/* ----------------------------- MNI Header -----------------------------------
@NAME : value_conversion.c
@DESCRIPTION: File of functions for converting values. These routines
are for use by other MINC routines only.
@METHOD : Routines included in this file :
semiprivate : (public but destined only for this package)
MI_varaccess
MI_var_loop
MI_get_sign_from_string
MI_convert_type
private :
MI_get_sign
MI_var_action
@CREATED : July 27, 1992. (Peter Neelin, Montreal Neurological Institute)
@MODIFIED :
* $Log: value_conversion.c,v $
* Revision 6.8 2008-01-17 02:33:02 rotor
* * removed all rcsids
* * removed a bunch of ^L's that somehow crept in
* * removed old (and outdated) BUGS file
*
* Revision 6.7 2008/01/12 19:08:14 stever
* Add __attribute__ ((unused)) to all rcsid variables.
*
* Revision 6.6 2004/10/15 13:45:28 bert
* Minor changes for Windows compatibility
*
* Revision 6.5 2004/04/27 15:49:51 bert
* Use new logging, gettext preparation
*
* Revision 6.4 2003/11/14 16:52:24 stever
* More last-minute fixes.
*
* Revision 6.3 2003/09/18 16:17:23 bert
* Use fabs instead of ABS
*
* Revision 6.2 2001/04/17 18:40:14 neelin
* Modifications to work with NetCDF 3.x
* In particular, changed NC_LONG to NC_INT (and corresponding longs to ints).
* Changed NC_UNSPECIFIED to NC_NAT.
* A few fixes to the configure script.
*
* Revision 6.1 1999/10/19 14:45:12 neelin
* Fixed Log subsitutions for CVS
*
* Revision 6.0 1997/09/12 13:24:54 neelin
* Release of minc version 0.6
*
* Revision 5.0 1997/08/21 13:25:53 neelin
* Release of minc version 0.5
*
* Revision 4.0 1997/05/07 20:07:52 neelin
* Release of minc version 0.4
*
* Revision 3.1 1997/04/10 18:14:50 neelin
* Fixed handling of invalid data when icv scale is zero.
*
* Revision 3.0 1995/05/15 19:33:12 neelin
* Release of minc version 0.3
*
* Revision 2.2 1995/02/08 19:14:44 neelin
* More changes for irix 5 lint.
*
* Revision 2.1 1995/02/08 19:01:06 neelin
* Moved private function declarations from minc_routines.h to appropriate file.
*
* Revision 2.0 1994/09/28 10:38:21 neelin
* Release of minc version 0.2
*
* Revision 1.9 94/09/28 10:37:22 neelin
* Pre-release
*
* Revision 1.8 93/11/05 09:18:08 neelin
* Improved epsilon calculation for valid range checking.
*
* Revision 1.7 93/10/28 15:12:06 neelin
* Fixed fillvalue checking stuff in MI_convert_type.
*
* Revision 1.6 93/10/28 10:19:16 neelin
* Added an epsilon for fillvalue checking in routine MI_convert_type (for
* reading through an icv).
*
* Revision 1.5 93/08/11 12:06:32 neelin
* Added RCS logging in source.
*
@COPYRIGHT :
Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre,
Montreal Neurological Institute, McGill University.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies. The author and McGill University
make no representations about the suitability of this
software for any purpose. It is provided "as is" without
express or implied warranty.
---------------------------------------------------------------------------- */
#include "minc_private.h"
#include <math.h>
#include "type_limits.h"
/* Private functions */
PRIVATE int MI_var_action(int ndims, long var_start[], long var_count[],
long nvalues, void *var_buffer, void *caller_data);
PRIVATE int MI_get_sign(nc_type datatype, int sign);
/* ----------------------------- MNI Header -----------------------------------
@NAME : MI_varaccess
@INPUT : operation - either MI_PRIV_GET or MI_PRIV_PUT, indicating
whether the routine should get or put data from/to a
cdf file
cdfid - cdf file id
varid - variable id
start - vector of coordinates of corner of hyperslab
count - vector of edge lengths of hyperslab
datatype - type that calling routine wants (one of the valid
netcdf data types, excluding NC_CHAR)
sign - sign that the calling routine wants (one of
MI_PRIV_SIGNED, MI_PRIV_UNSIGNED, MI_PRIV_DEFAULT).
bufsize_step - vector of buffer size steps wanted by
caller (MI_var_loop will try, but no guarantees); if
NULL, then 1 is assumed. For the first index that cannot be
read in one piece, the allocated buffer will tend to have
the count of as a multiple of the corresponding value in
this vector.
icvp - pointer to icv structure (image conversion variable)
If NULL, then icvp->do_scale and icvp->do_dimconvert are
assumed to be FALSE.
icvp->do_scale - boolean indicating whether scaling
should be done. If so, then
outvalue = icvp->scale * (double) invalue + icvp->offset
icvp->scale - (see do_scale)
icvp->offset - (see do_scale)
icvp->do_dimconvert - boolean indicating whether the
dimension conversion routine should be called
icvp->dimconvert_func - dimension conversion routine
values - values to store in variable (for put)
@OUTPUT : values - values to get from variable (for get)
@RETURNS : MI_ERROR (=-1) when an error occurs
@DESCRIPTION: Routine to do work for getting/putting and converting
the type of variable values. Similar to routine ncvarget/
ncvarput but the calling routine specifies the form in
which data should be returned/passed (datatype), as well as
the sign. The datatype can only be a numeric type. If the
variable in the file is of type NC_CHAR, then an error is
returned. Values can optionally be scaled (for image
conversion routines) by setting icvp->do_scale to TRUE and
using icvp->scale and icvp->offset. Dimensional conversion
can be done be setting icvp->do_dimconvert to TRUE and
passing a function to be called (icvp->dimconvert_func).
@METHOD :
@GLOBALS :
@CALLS : NetCDF and MINC routines
@CREATED : July 29, 1992 (Peter Neelin)
@MODIFIED :
---------------------------------------------------------------------------- */
SEMIPRIVATE int MI_varaccess(int operation, int cdfid, int varid,
long start[], long count[],
nc_type datatype, int sign, void *values,
int *bufsize_step, mi_icv_type *icvp)
{
mi_varaccess_type strc; /* Structure of values for functions */
int ndims; /* Number of variable dimensions */
char stringa[MI_MAX_ATTSTR_LEN]; /* String for attribute value */
char *string = stringa;
int oldncopts; /* Save old value of ncopts */
MI_SAVE_ROUTINE_NAME("MI_varaccess");
/* Check to see if ivc structure was passed and set variables
needed by this routine */
if (icvp == NULL) {
strc.do_scale = FALSE;
strc.do_dimconvert = FALSE;
strc.do_fillvalue = FALSE;
}
else {
strc.do_scale = icvp->do_scale;
strc.do_dimconvert = icvp->do_dimconvert;
strc.do_fillvalue = icvp->do_fillvalue;
}
/* Inquire about the variable */
MI_CHK_ERR(ncvarinq(cdfid, varid, NULL, &(strc.var_type),
&ndims, NULL, NULL))
/* Check that the variable type is numeric */
if ((datatype==NC_CHAR) || (strc.var_type==NC_CHAR)) {
milog_message(MI_MSG_VARNOTNUM);
MI_RETURN(MI_ERROR);
}
/* Try to find out the sign of the variable using MIsigntype.
To avoid programs dying unexpectedly, we must change ncopts,
then restore it */
oldncopts = ncopts;
ncopts = 0;
string=miattgetstr(cdfid, varid, MIsigntype, MI_MAX_ATTSTR_LEN, string);
ncopts = oldncopts;
/* Get the signs */
strc.var_sign = MI_get_sign_from_string(strc.var_type, string);
strc.call_sign = MI_get_sign(datatype, sign);
/* Check to see if the type requested is the same as the variable type,
the signs are the same and no dimension conversion is needed. If so,
just get/put the values */
if ((datatype == strc.var_type) && (strc.call_sign == strc.var_sign) &&
!strc.do_scale && !strc.do_dimconvert && !strc.do_fillvalue) {
switch (operation) {
case MI_PRIV_GET:
MI_CHK_ERR(ncvarget(cdfid, varid, start, count, values))
break;
case MI_PRIV_PUT:
MI_CHK_ERR(ncvarput(cdfid, varid, start, count, values))
break;
default:
milog_message(MI_MSG_BADOP);
MI_RETURN(MI_ERROR);
}
MI_RETURN(MI_NOERROR);
}
/* Otherwise, we have to loop through data. Set up structure
and call MI_var_loop */
strc.operation=operation;
strc.cdfid=cdfid;
strc.varid=varid;
strc.call_type=datatype;
strc.var_value_size=nctypelen(strc.var_type);
strc.call_value_size=nctypelen(strc.call_type);
strc.icvp=icvp;
strc.start=start;
strc.count=count;
strc.values=values;
MI_CHK_ERR( MI_var_loop(ndims, start, count,
strc.var_value_size, bufsize_step,
MI_MAX_VAR_BUFFER_SIZE,
(void *) &strc, MI_var_action) )
MI_RETURN(MI_NOERROR);
}
/* ----------------------------- MNI Header -----------------------------------
@NAME : MI_var_action
@INPUT : ndims - number of dimensions
var_start - coordinate vector of corner of hyperslab
var_count - vector of edge lengths of hyperslab
nvalues - number of values in hyperslab
var_buffer - pointer to variable buffer
caller_data - pointer to data from MI_varaccess
@OUTPUT : (none)
@RETURNS : MI_ERROR if an error occurs
@DESCRIPTION: Buffer action routine to be called by MI_var_loop, for
use by MI_varaccess.
@METHOD :
@GLOBALS :
@CALLS : NetCDF and MINC routines
@CREATED : July 30, 1992 (Peter Neelin)
@MODIFIED :
---------------------------------------------------------------------------- */
PRIVATE int MI_var_action(int ndims, long var_start[], long var_count[],
long nvalues, void *var_buffer, void *caller_data)
/* ARGSUSED */
{
mi_varaccess_type *ptr; /* Pointer to data from MI_varaccess */
int status; /* Status returned by function call */
MI_SAVE_ROUTINE_NAME("MI_var_action");
ptr=(mi_varaccess_type *) caller_data;
/* Get/put values and do conversions, etc. */
switch (ptr->operation) {
case MI_PRIV_GET:
status=ncvarget(ptr->cdfid, ptr->varid, var_start, var_count,
var_buffer);
if (status != MI_ERROR) {
/* If doing dimension conversion, let dimconvert function do all the
work, including type conversion */
if (!ptr->do_dimconvert) {
status=MI_convert_type(nvalues,
ptr->var_type, ptr->var_sign, var_buffer,
ptr->call_type, ptr->call_sign, ptr->values,
ptr->icvp);
}
else {
status=(*(ptr->icvp->dimconvert_func))(ptr->operation, ptr->icvp,
ptr->start, ptr->count, ptr->values,
var_start, var_count, var_buffer);
}
}
break;
case MI_PRIV_PUT:
/* If doing dimension conversion, let dimconvert function do all the
work, including type conversion */
if (!ptr->do_dimconvert) {
status=MI_convert_type(nvalues,
ptr->call_type, ptr->call_sign, ptr->values,
ptr->var_type, ptr->var_sign, var_buffer,
ptr->icvp);
}
else {
status=(*(ptr->icvp->dimconvert_func))(ptr->operation, ptr->icvp,
ptr->start, ptr->count, ptr->values,
var_start, var_count, var_buffer);
}
if (status != MI_ERROR) {
status=ncvarput(ptr->cdfid, ptr->varid, var_start, var_count,
var_buffer);
}
break;
default:
milog_message(MI_MSG_BADOP);
status=MI_ERROR;
}
/* Check for an error */
MI_CHK_ERR(status)
/* Increment the values pointer */
if (!ptr->do_dimconvert) {
ptr->values = (void *) ((char *) ptr->values +
nvalues*ptr->call_value_size);
}
MI_RETURN(MI_NOERROR);
}
/* ----------------------------- MNI Header -----------------------------------
@NAME : MI_var_loop
@INPUT : ndims - number of dimensions in variable
start - vector of coordinates of corner of hyperslab
count - vector of edge lengths of hyperslab
value_size - size (in bytes) of each value to be buffered
bufsize_step - vector of buffer size steps wanted by
caller (MI_var_loop will try, but no guarantees); if
NULL, then 1 is assumed. For the first index that cannot be
read in one piece, the allocated buffer will tend to have
the count of as a multiple of the corresponding value in
this vector.
max_buffer_size - maximum size (in bytes) of buffer
caller_data - pointer to a structure of data to pass to
functions
action_func - function to do something with each buffer
@OUTPUT : (none)
@RETURNS : MI_ERROR (=-1) when an error occurs
@DESCRIPTION: Routine to loop through a variable's indices, getting data
into a buffer and doing something to it. A function pointer
is passed that will perform these functions on each buffer.
@METHOD :
@GLOBALS :
@CALLS : NetCDF and MINC routines
@CREATED : July 29, 1992 (Peter Neelin)
@MODIFIED :
---------------------------------------------------------------------------- */
SEMIPRIVATE int MI_var_loop(int ndims, long start[], long count[],
int value_size, int *bufsize_step,
long max_buffer_size,
void *caller_data,
int (*action_func) (int, long [], long [],
long, void *, void *))
{
long nvalues, newnvalues; /* Number of values in fastest varying dims.
Note that any dimensional subscript variables
should be long */
int firstdim; /* First dimension that doesn't fit in buffer */
long ntimes; /* Number of firstdim elements that fit in buf */
void *var_buffer; /* Pointer to buffer for variable data */
long var_count[MAX_VAR_DIMS]; /* Count, start and end coordinate */
long var_start[MAX_VAR_DIMS]; /* vectors for getting buffers */
long var_end[MAX_VAR_DIMS];
int i; /* Looping variable - only used for dimension
number, not dimension subscript */
MI_SAVE_ROUTINE_NAME("MI_var_loop");
/* Find out how much space we need and then allocate a buffer.
To do this we find out how many dimensions will fit in our
maximum buffer size. firstdim is the index of the first dimension
that won't fit. nvalues is the number of values in the first dimensions
that do fit in the buffer. ntimes is the number of times that the first
dimensions fit in the buffer. To make things simpler, dimension 0 is
always considered to not fit, even if it does. */
nvalues=newnvalues=1;
for (firstdim=ndims-1; firstdim>=1; firstdim--) {
newnvalues *= count[firstdim];
if (newnvalues*value_size > max_buffer_size) break;
nvalues = newnvalues;
}
if (firstdim<0) { /* Check for 0-dim variable */
firstdim=0;
ntimes=1;
}
else {
ntimes = MIN(MI_MAX_VAR_BUFFER_SIZE/(nvalues*value_size),
count[firstdim]);
/* Try to make ntimes an convenient multiple for the caller */
if ((ntimes != count[firstdim]) && (bufsize_step != NULL)) {
ntimes = MAX(1, ntimes - (ntimes % bufsize_step[firstdim]));
}
}
/* Allocate space for variable values */
if ((var_buffer = MALLOC(ntimes*nvalues*value_size, char))
== NULL) {
milog_message(MI_MSG_OUTOFMEM);
MI_RETURN(MI_ERROR);
}
/* Create a count variable for the var buffer, with 1s for dimensions
that vary slower than firstdim and count[i] for dimensions that
vary faster. Set a start variable for the var buffer, equal to start.
Set an end variable for the var buffer. */
if (ndims <= 0) { /* Handle zero-dimension variable */
var_start[0]=0; var_end[0]=1; var_count[0]=1;
}
for (i=0; i<ndims; i++) {
var_count[i] = (i>firstdim) ? count[i] :
(i==firstdim) ? ntimes : 1;
var_start[i] = start[i];
var_end[i] = start[i] + count[i];
}
/* Loop through the dimensions, copying buffers, etc.
Exit when the slowest varying dimension reaches its limit. */
while (var_start[0] < var_end[0]) {
var_count[firstdim] =
MIN(ntimes, var_end[firstdim] - var_start[firstdim]);
/* Do the stuff on the buffer */
if ((*action_func)(ndims, var_start, var_count,
var_count[firstdim]*nvalues, var_buffer,
caller_data) == MI_ERROR) {
FREE(var_buffer);
MI_RETURN_ERROR(MI_ERROR);
}
/* Increment the start counters */
var_start[firstdim] += var_count[firstdim];
i=firstdim;
while ( (i>0) && (var_start[i] >= var_end[i])) {
var_start[i] = start[i];
i--;
var_start[i]++;
}
}
/* Free the buffer and return */
FREE(var_buffer);
MI_RETURN(MI_NOERROR);
}
/* ----------------------------- MNI Header -----------------------------------
@NAME : MI_get_sign_from_string
@INPUT : type - type of value
sign - sign of value (one of
MI_EMPTY_STRING, MI_SIGNED or MI_UNSIGNED)
@OUTPUT : (none)
@RETURNS : either MI_PRIV_SIGNED or MI_PRIV_UNSIGNED
@DESCRIPTION: Converts sign string to either MI_PRIV_SIGNED or
MI_PRIV_UNSIGNED, as appropriate, by calling MI_get_sign.
@METHOD :
@GLOBALS : (none)
@CALLS : MI_get_sign
@CREATED : July 30, 1992 (Peter Neelin)
@MODIFIED :
---------------------------------------------------------------------------- */
SEMIPRIVATE int MI_get_sign_from_string(nc_type datatype, char *sign)
{
MI_SAVE_ROUTINE_NAME("MI_get_sign_from_string");
MI_RETURN(MI_get_sign(datatype,
(sign == NULL) || (*sign == '\0') ? MI_PRIV_DEFSIGN :
(STRINGS_EQUAL(sign, MI_SIGNED)) ? MI_PRIV_SIGNED :
(STRINGS_EQUAL(sign, MI_UNSIGNED)) ? MI_PRIV_UNSIGNED :
MI_PRIV_DEFSIGN));
}
/* ----------------------------- MNI Header -----------------------------------
@NAME : MI_get_sign
@INPUT : type - type of value
sign - sign of value (one of
MI_PRIV_DEFSIGN, MI_PRIV_SIGNED or MI_PRIV_UNSIGNED)
@OUTPUT : (none)
@RETURNS : either MI_PRIV_SIGNED or MI_PRIV_UNSIGNED
@DESCRIPTION: Converts sign variable to either MI_PRIV_SIGNED or
MI_PRIV_UNSIGNED, as appropriate, if its value is
MI_PRIV_DEFSIGN, otherwise the value of sign is returned
as is. The default signs are
byte : unsigned
short : signed
int : signed
float : signed
double : signed
@METHOD :
@GLOBALS :
@CALLS :
@CREATED : July 27, 1992 (Peter Neelin)
@MODIFIED :
---------------------------------------------------------------------------- */
PRIVATE int MI_get_sign(nc_type datatype, int sign)
{
MI_SAVE_ROUTINE_NAME("MI_get_sign");
MI_RETURN( ((datatype==NC_FLOAT) ||
(datatype==NC_DOUBLE)) ? MI_PRIV_SIGNED :
((sign==MI_PRIV_SIGNED) ||
(sign==MI_PRIV_UNSIGNED)) ? sign :
(datatype==NC_BYTE) ? MI_PRIV_UNSIGNED :
(datatype==NC_SHORT) ? MI_PRIV_SIGNED :
(datatype==NC_INT) ? MI_PRIV_SIGNED :
MI_PRIV_SIGNED );
}
/* ----------------------------- MNI Header -----------------------------------
@NAME : MI_convert_type
@INPUT : number_of_values - number of values to copy
intype - type of input values
insign - sign of input values (one of
MI_PRIV_DEFSIGN, MI_PRIV_SIGNED or MI_PRIV_UNSIGNED)
invalues - vector of values
outtype - type of output values
outsign - sign of output values
icvp - pointer to icv structure (if NULL,
then icvp->do_scale is assumed to be FALSE)
icvp->do_scale - boolean indicating whether scaling
should be done. If so, then
outvalue = icvp->scale * (double) invalue + icvp->offset
icvp->scale - (see do_scale)
icvp->offset - (see do_scale)
@OUTPUT : outvalues - output values
@RETURNS : MI_ERROR if an error occurs
@DESCRIPTION: Converts the invalues to outvalues according to their type.
Types must be numeric. Values out of range are truncated
to the nearest value in range. The sign of integer values
is given by insign and outsign, which must have values
MI_PRIV_DEFSIGN, MI_PRIV_SIGNED or MI_PRIV_UNSIGNED.
If it is MI_PRIV_DEFSIGN then the default signs are
used (from MI_get_sign) :
byte : unsigned
short : signed
int : signed
Note that if a conversion must take place, then all input
values are converted to double. Values can be scaled through
icvp->scale and icvp->offset by setting icvp->do_scale to TRUE.
@METHOD :
@GLOBALS :
@CALLS :
@CREATED : July 27, 1992 (Peter Neelin)
@MODIFIED : August 28, 1992 (P.N.)
- replaced type conversions with macros
---------------------------------------------------------------------------- */
SEMIPRIVATE int MI_convert_type(long number_of_values,
nc_type intype, int insign, void *invalues,
nc_type outtype, int outsign, void *outvalues,
mi_icv_type *icvp)
{
int inincr, outincr; /* Pointer increments for arrays */
int insgn, outsgn; /* Signs for input and output */
long i;
double dvalue=0.0; /* Temporary double for conversion */
void *inptr, *outptr; /* Pointers to input and output values */
int do_scale; /* Should scaling be done? */
int do_fillvalue; /* Should fillvalue checking be done? */
double fillvalue; /* Value to fill with */
double dmax, dmin; /* Range of legal values */
double epsilon; /* Epsilon for legal values comparisons */
MI_SAVE_ROUTINE_NAME("MI_convert_type");
/* Check to see if icv structure was passed and set variables needed */
if (icvp == NULL) {
do_scale=FALSE;
do_fillvalue = FALSE;
dmax = dmin = 0.0;
fillvalue = 0.0;
}
else {
do_scale=icvp->do_scale;
do_fillvalue=icvp->do_fillvalue;
fillvalue = icvp->user_fillvalue;
dmax = icvp->fill_valid_max;
dmin = icvp->fill_valid_min;
epsilon = (dmax - dmin) * FILLVALUE_EPSILON;
epsilon = fabs(epsilon);
dmax += epsilon;
dmin -= epsilon;
}
/* Check the types and get their size */
if ((intype==NC_CHAR) || (outtype==NC_CHAR)) {
milog_message(MI_MSG_VARNOTNUM);
MI_RETURN(MI_ERROR);
}
if (((inincr =nctypelen(intype ))==MI_ERROR) ||
((outincr=nctypelen(outtype))==MI_ERROR)) {
MI_RETURN(MI_ERROR);
}
/* Get the sign of input and output values */
insgn = MI_get_sign(intype, insign);
outsgn = MI_get_sign(outtype, outsign);
/* Check to see if a conversion needs to be made.
If not, just copy the memory */
if ((intype==outtype) && (insgn==outsgn) && !do_scale && !do_fillvalue) {
(void) memcpy(outvalues, invalues,
(size_t) number_of_values*inincr);
}
/* Otherwise, loop through */
else {
/* Step through values */
inptr=invalues;
outptr=outvalues;
for (i=0 ; i<number_of_values; i++) {
/* Convert the input value */
{MI_TO_DOUBLE(dvalue, intype, insgn, inptr)}
/* Check the value for range and scale the value if necessary */
if (do_fillvalue && ((dvalue < dmin) || (dvalue > dmax))) {
dvalue = fillvalue;
}
else if (do_scale) {
dvalue = icvp->scale * dvalue + icvp->offset;
}
/* Truncate if necessary and assign the value */
{MI_FROM_DOUBLE(dvalue, outtype, outsgn, outptr)}
inptr = (void *) ((char *)inptr + inincr);
outptr = (void *) ((char *)outptr + outincr);
} /* End of for loop */
} /* End of else */
MI_RETURN(MI_NOERROR);
}
|