/***************************************************************************** * * * COMMON OCEANOGRAPHIC DATA ACCESS SYSTEM (CODAS) * * * * WRITTEN BY: RAMON CABRERA, ERIC FIRING, and JULIE RANADA * * JOINT INSTITUTE FOR MARINE AND ATMOSPHERIC RESEARCH * * 1000 POPE ROAD MSB 404 * * HONOLULU, HI 96822 * * * * VERSION: 3.00 * * * * DATE: APRIL 1989 * * * *****************************************************************************/ /* FILE: dblscale.c based on scale.c 2000/09/17 EF This could be enormously simplified, including elimination of the horrendous function array, by exclusive use of pointers plus value types. The double type is the intermediary in any case, so we could convert from anything to anything quite generally with a single function. Improvement over scale.c: by switching the first input argument to a void pointer, I eliminated the "initialization from incompatible..." warnings. EF 2000/09/19 */ /*----------------------------------------------------------------------------- FUNCTIONS: SCALE_FLOAT_TO_?? The scaling functions accept an array of floating point numbers and perform the inverse of the unscaling operations. The results are returned in an array of the specified data type. Note that the scaling and unscaling functions are defined to be inverse operations when called with the same arguments for offset and scale. Results: ??_array[i] = (float_array[i] - *offset) / *scale float_array[i] = *offset + *scale * ??_array[i] For example, for soundspeed the offset is 1500 m/s and the new scale is 1E-2 m/s. These functions can be used on single values by calling them with the addresses of the variables and setting npts to 1. PARAMETERS: ??_array = the array of data type specified by ??; for the scaling functions, this array is used to store the result of the scaling operation; float_array = the array of floating point numbers; for scaling, this contains the values that must be scaled and converted to some other data type; scale = pointer to the number by which a value must be factored in order to convert from the units in which it is expressed to some other unit. offset = pointer to the number by which a value must be reduced/increased in order to convert from the units in which it is expressed to some other unit. nv = pointer to the number of values to be scaled nbad = on exit, this contains the number of values in the resulting array that have been set to BAD?? because the scaling result was out of range. */ #define out_of_range(min, max) (fs < min || fs > max ? printf("\n WARNING: attempt to convert float out of range\n original float: %f\n scaled: %f", float_array[i], fs) : 0 ) /*---------------------------------------------------------------------------*/ #include #include "dbext.h" /* FLOAT, etc., MIN*, MAX*, BAD*, ZERO_SCALE */ #include "find_def.h" #include "ioserv.h" #include "dblscale.h" #include "dbglo.h" /* VALUE_SIZE */ extern NAME_LIST_ENTRY_TYPE VALUE_CODE[]; int SCALE_DOUBLE_TO_BYTE(void *byte_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; BYTE *byte_array = byte_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { byte_array[i] = BADBYTE; if (float_array[i] < ADJ_BADFLOAT) { fs = (int) round_val( (float_array[i] - *offset) / *scale ); if (!out_of_range(MINBYTE, MAXBYTE)) byte_array[i] = fs; else (*nbad)++; } } return(0); } /*---------------------------------------------------------------------------*/ int SCALE_DOUBLE_TO_UBYTE(void *ubyte_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; UBYTE *ubyte_array = ubyte_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { ubyte_array[i] = BADUBYTE; if (float_array[i] < ADJ_BADFLOAT) { fs = (int) round_val( (float_array[i] - *offset) / *scale ); if (!out_of_range((double)MINUBYTE, (double)MAXUBYTE)) ubyte_array[i] = fs; else (*nbad)++; } } return(0); } /*---------------------------------------------------------------------------*/ int SCALE_DOUBLE_TO_SHORT(void *short_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; SHORT *short_array = short_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { short_array[i] = BADSHORT; if (float_array[i] < ADJ_BADFLOAT) { fs = (long int) round_val( (float_array[i] - *offset) / *scale ); if (!out_of_range(MINSHORT, MAXSHORT)) short_array[i] = fs; else (*nbad)++; } } return(0); } /*---------------------------------------------------------------------------*/ int SCALE_DOUBLE_TO_USHORT (void *ushort_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; USHORT *ushort_array = ushort_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { ushort_array[i] = BADUSHORT; if (float_array[i] < ADJ_BADFLOAT) { fs = (unsigned long int) round_val( (float_array[i] - *offset) / *scale ); if (!out_of_range((double)MINUSHORT, (double)MAXUSHORT)) ushort_array[i] = fs; else (*nbad)++; } } return(0); } /*---------------------------------------------------------------------------*/ int SCALE_DOUBLE_TO_LONG(void *long_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; LONG *long_array = long_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { long_array[i] = BADLONG; if (float_array[i] < ADJ_BADFLOAT) { fs = round_val( (float_array[i] - *offset) / *scale ); if (!out_of_range((double)MINLONG, (double)MAXLONG)) long_array[i] = fs; else (*nbad)++; } } return(0); } /*---------------------------------------------------------------------------*/ int SCALE_DOUBLE_TO_ULONG(void *ulong_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; ULONG *ulong_array = ulong_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { ulong_array[i] = BADULONG; if (float_array[i] < ADJ_BADFLOAT) { fs = round_val( (float_array[i] - *offset) / *scale ); if (!out_of_range(MINULONG, MAXULONG)) ulong_array[i] = fs; else (*nbad)++; } } return(0); } /*---------------------------------------------------------------------------*/ int SCALE_DOUBLE_TO_FLOAT(void *float2_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; FLOAT *float2_array = float2_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { float2_array[i] = BADFLOAT; if (float_array[i] < ADJ_BADFLOAT) { fs = (float_array[i] - *offset) / *scale; if (!out_of_range(-MAXFLOAT, MAXFLOAT)) float2_array[i] = fs; else (*nbad)++; } } return(0); } /*---------------------------------------------------------------------------*/ int SCALE_DOUBLE_TO_DOUBLE(void *double_array_, DOUBLE float_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) { unsigned int i; double fs; DOUBLE *double_array = double_array_; if (*scale == 0.0) return(ZERO_SCALE); *nbad = 0; for (i = 0; i < *nv; i++) { double_array[i] = BADDOUBLE; if (float_array[i] < ADJ_BADFLOAT) { fs = (float_array[i] - *offset) / *scale; if (!out_of_range(-MAXDOUBLE, MAXDOUBLE)) double_array[i] = fs; else (*nbad)++; } } return(0); } int (*dblscale[])(void *out_array, DOUBLE in_array[], FLOAT *scale, FLOAT *offset, unsigned int *nv, unsigned int *nbad) = { SCALE_DOUBLE_TO_BYTE, SCALE_DOUBLE_TO_UBYTE, SCALE_DOUBLE_TO_UBYTE, /* CHAR is UBYTE */ SCALE_DOUBLE_TO_SHORT, SCALE_DOUBLE_TO_USHORT, SCALE_DOUBLE_TO_LONG, SCALE_DOUBLE_TO_ULONG, SCALE_DOUBLE_TO_FLOAT, SCALE_DOUBLE_TO_DOUBLE }; /*----------------------------------------------------------------------------- FUNCTION: dbl_struc ARGUMENTS: array = pointer to array of doubles structure = pointer to structure bytes name = pointer to structure name str_def = pointer to head of linked list of structure definitions RETURNS: 0 on error, size of structure in bytes on success */ int dbl_struc(double *array, char *structure, char *name, STRUCT_DEF_HDR_TYPE *str_def) { STRUCT_DEF_ENTRY_TYPE *str_def_ptr; char *data_ptr; unsigned int i, nelem, nc, ierr, nbad; float float_zero = 0.0, float_one = 1.0; if ((str_def == NULL) || ((str_def_ptr = (STRUCT_DEF_ENTRY_TYPE *) find_def(name, str_def)) == NULL)) /* NO STRUCTURE DEFINITION */ { fprintf(stderr, " Definition missing for %20s\n\n", name); return 0; /* error; fix error reporting later */ } data_ptr = structure; nelem = str_def_ptr->hdr.nelem; for (i = 0; i < nelem; i++) { str_def_ptr += 1; nc = str_def_ptr->elem.count; if (nc > 0) { if (str_def_ptr->elem.value_type == STRUCT_VALUE_CODE) { fprintf(stderr, "Recursion not yet implemented"); return 0; } else if (str_def_ptr->elem.value_type > DOUBLE_VALUE_CODE) { fprintf(stderr, "Type %d not supported.\n", str_def_ptr->elem.value_type); return 0; } else { ierr = (*dblscale[str_def_ptr->elem.value_type])( data_ptr, array, &float_one, &float_zero, &nc, &nbad); data_ptr += nc * VALUE_SIZE[str_def_ptr->elem.value_type]; array += nc; } } } return (data_ptr - structure); } #if 0 /* Test and example. */ int main(int argc, char **argv) { double array[20]; STRUCT_DEF_HDR_TYPE *struct_def; FORMAT_HDR_TYPE *formats; USHORT nentries; struct {SHORT e1, e2; CHAR e3[4];} test1a, test1 = { 1, 2, "abc"}; struct {DOUBLE e1; FLOAT e2[2];} test2a, test2 = { 5.43, {2.1, 1.2}}; int ierr, nbytes; ierr = load_structure_definition("teststruct.def", &struct_def, &nentries, &formats); printf("ierr = %d, nentries = %d\n", ierr, nentries); array[0] = 1; array[1] = 2; array[2] = 'a'; array[3] = 'b'; array[4] = 'c'; array[5] = 0; nbytes = dbl_struc(array, (char *)&test1a, "TEST1", struct_def); printf("nbytes = %d\n", nbytes); printf("\n%f %f %f %f %f %f\n", array[0], array[1], array[2], array[3], array[4], array[5]); printf("%d %d %s\n", test1a.e1, test1a.e2, test1a.e3); return 0; } #endif