units.c

Go to the documentation of this file.
00001 /*                         U N I T S . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1990-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup bu_log */
00023 /*@{*/
00024 
00025 /** @file units.c
00026  *  Module of libbu to handle units conversion between strings and mm.
00027  *
00028  *  @author
00029  *      Michael John Muuss
00030  *
00031  *  @par Source -
00032  *      SECAD/VLD Computing Consortium, Bldg 394
00033  * @n   The U. S. Army Ballistic Research Laboratory
00034  * @n   Aberdeen Proving Ground, Maryland  21005-5066
00035  *
00036  */
00037 /*@}*/
00038 
00039 #ifndef lint
00040 static const char libbu_units_RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbu/units.c,v 14.12 2006/08/31 23:16:39 lbutler Exp $ (BRL)";
00041 #endif
00042 
00043 #include "common.h"
00044 
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #include <ctype.h>
00048 
00049 #ifdef HAVE_STRING_H
00050 #  include <string.h>
00051 #else
00052 #  include <strings.h>
00053 #endif
00054 
00055 #include "machine.h"
00056 #include "bu.h"
00057 
00058 static const struct cvt_tab {
00059         double  val;
00060         char    name[32];
00061 } bu_units_tab[] = {
00062         {0.0,           "none"},
00063         {1.0e-7,        "angstrom"},
00064         {1.0e-7,        "decinanometer"},
00065         {1.0e-6,        "nm"},
00066         {1.0e-6,        "nanometer"},
00067         {1.0e-3,        "um"},
00068         {1.0e-3,        "micrometer"},
00069         {1.0e-3,        "micron"},
00070         {1.0,           "mm"},
00071         {1.0,           "millimeter"},
00072         {10.0,          "cm"},
00073         {10.0,          "centimeter"},
00074         {1000.0,        "m"},
00075         {1000.0,        "meter"},
00076         {1000000.0,     "km"},
00077         {1000000.0,     "kilometer"},
00078         {25.4,          "in"},
00079         {25.4,          "inch"},
00080         {25.4,          "inche"},               /* for plural */
00081         {304.8,         "ft"},
00082         {304.8,         "foot"},
00083         {304.8,         "feet"},
00084         {456.2,         "cubit"},
00085         {914.4,         "yd"},
00086         {914.4,         "yard"},
00087         {5029.2,        "rd"},
00088         {5029.2,        "rod"},
00089         {1609344.0,     "mi"},
00090         {1609344.0,     "mile"},
00091         {1852000.0,     "nmile"},
00092         {1852000.0,     "nautical mile"},
00093         {1.495979e+14,  "AU"},
00094         {1.495979e+14,  "astronomical unit"},
00095         {9.460730e+18,  "lightyear"},
00096         {3.085678e+19,  "pc"},
00097         {3.085678e+19,  "parsec"},
00098         {0.0,           ""}                     /* LAST ENTRY */
00099 };
00100 #define BU_UNITS_TABLE_SIZE (sizeof(bu_units_tab) / sizeof(struct cvt_tab) - 1)
00101 
00102 /**
00103  *                      B U _ U N I T S _ C O N V E R S I O N
00104  *
00105  *  Given a string representation of a unit of distance (eg, "feet"),
00106  *  return the multiplier which will convert that unit into millimeters.
00107  *
00108  *  Returns -
00109  *      0.0     error
00110  *      >0.0    success
00111  */
00112 double
00113 bu_units_conversion(const char *str)
00114 {
00115         register char   *ip;
00116         register int    c;
00117         register const struct cvt_tab   *tp;
00118         char            ubuf[256];
00119         int             len;
00120 
00121         strncpy( ubuf, str, sizeof(ubuf)-1 );
00122         ubuf[sizeof(ubuf)-1] = '\0';
00123 
00124         /* Copy the given string, making it lower case */
00125         ip = ubuf;
00126         while( (c = *ip) )  {
00127                 if( !isascii(c) )
00128                         *ip++ = '_';
00129                 else if( isupper(c) )
00130                         *ip++ = tolower(c);
00131                 else
00132                         ip++;
00133         }
00134 
00135         /* Remove any trailing "s" (plural) */
00136         len = strlen(ubuf);
00137         if( ubuf[len-1] == 's' )  ubuf[len-1] = '\0';
00138 
00139         /* Search for this string in the table */
00140         for( tp=bu_units_tab; tp->name[0]; tp++ )  {
00141                 if( ubuf[0] != tp->name[0] )  continue;
00142                 if( strcmp( ubuf, tp->name ) != 0 )  continue;
00143                 return( tp->val );
00144         }
00145         return(0.0);            /* Unable to find it */
00146 }
00147 
00148 /**
00149  *                      B U _ U N I T S _ S T R I N G
00150  *
00151  *  Given a conversion factor to mm, search the table to find
00152  *  what unit this represents.
00153  *  To accomodate floating point fuzz, a "near miss" is allowed.
00154  *  The algorithm depends on the table being sorted small-to-large.
00155  *
00156  *  Returns -
00157  *      char*   units string
00158  *      NULL    No known unit matches this conversion factor.
00159  */
00160 const char *
00161 bu_units_string(register const double mm)
00162 {
00163         register const struct cvt_tab   *tp;
00164 
00165         if( mm <= 0 )  return (char *)NULL;
00166 
00167         /* Search for this string in the table */
00168         for( tp=bu_units_tab; tp->name[0]; tp++ )  {
00169                 fastf_t diff, bigger;
00170                 if( mm == tp->val )  return tp->name;
00171 
00172                 /* Check for near-miss */
00173                 if( mm > tp->val )  {
00174                         bigger = mm;
00175                         diff = mm - tp->val;
00176                 }  else  {
00177                         bigger = tp->val;
00178                         diff = tp->val - mm;
00179                 }
00180 
00181                 /* Absolute difference less than 0.1 angstrom */
00182                 if( diff < 1.0e-8 )  return tp->name;
00183 
00184                 /* Relative difference less than 1 part per billion */
00185                 if( diff < 0.000000001 * bigger )  return tp->name;
00186         }
00187         return (char *)NULL;
00188 }
00189 
00190 /**
00191  *                      B U _ M M _ V A L U E
00192  *
00193  * Given a string of the form "25cm" or "5.2ft" returns the
00194  * corresponding distance in mm.
00195  *
00196  *  Returns -
00197  *      -1      on error
00198  *      >0      on success
00199  */
00200 double
00201 bu_mm_value(const char *s)
00202 {
00203         double v;
00204         char *ptr;
00205         register const struct cvt_tab   *tp;
00206 
00207         v = strtod(s, &ptr);
00208 
00209         if (ptr == s)  {
00210                 /* No number could be found, unity is implied */
00211                 /* e.g. interprept "ft" as "1ft" */
00212                 v = 1.0;
00213         }
00214         if ( ! *ptr)  {
00215                 /* There are no characters following the scaned number */
00216                 return v;
00217         }
00218 
00219         for (tp=bu_units_tab; tp->name[0]; tp++ )  {
00220                 if( *ptr != tp->name[0] )  continue;
00221                 if( strcmp( ptr, tp->name ) == 0 ) {
00222                         v *= tp->val;
00223                         return v;
00224                 }
00225         }
00226 
00227         /* A string was seen, but not found in the table.  Signal error */
00228         return -1;
00229 }
00230 
00231 /**     B U _ M M _ C V T
00232  *
00233  *  Used primarily as a hooked function for bu_structparse tables
00234  *  to allow input of floating point values in other units.
00235  */
00236 void
00237 bu_mm_cvt(register const struct bu_structparse *sdp, register const char *name, char *base, const char *value)
00238                                                 /* structure description */
00239                                                 /* struct member name */
00240                                                 /* begining of structure */
00241                                                 /* string containing value */
00242 {
00243         register double *p = (double *)(base+sdp->sp_offset);
00244 
00245         /* reconvert with optional units */
00246         *p = bu_mm_value(value);
00247 }
00248 /*@}*/
00249 /*
00250  * Local Variables:
00251  * mode: C
00252  * tab-width: 8
00253  * c-basic-offset: 4
00254  * indent-tabs-mode: t
00255  * End:
00256  * ex: shiftwidth=4 tabstop=8
00257  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6