00001 // 00002 // $Id: units.cpp 2 2008-03-01 20:58:50Z kulibali $ 00003 // 00004 // Copyright (c) 2008, The Periapsis Project. All rights reserved. 00005 // 00006 // Redistribution and use in source and binary forms, with or without 00007 // modification, are permitted provided that the following conditions are 00008 // met: 00009 // 00010 // * Redistributions of source code must retain the above copyright notice, 00011 // this list of conditions and the following disclaimer. 00012 // 00013 // * Redistributions in binary form must reproduce the above copyright 00014 // notice, this list of conditions and the following disclaimer in the 00015 // documentation and/or other materials provided with the distribution. 00016 // 00017 // * Neither the name of the The Periapsis Project nor the names of its 00018 // contributors may be used to endorse or promote products derived from 00019 // this software without specific prior written permission. 00020 // 00021 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 00022 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 00023 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00024 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 00025 // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00027 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00032 // 00033 00034 #include "math/units.hpp" 00035 #include "data/string.hpp" 00036 00037 #include <cmath> 00038 #include <cwctype> 00039 00040 namespace gsgl 00041 { 00042 00043 namespace math 00044 { 00045 00046 namespace units 00047 { 00048 00049 const gsgl::real_t METERS_PER_MILLIMETER = (gsgl::real_t) 0.001; 00050 const gsgl::real_t METERS_PER_CENTIMETER = (gsgl::real_t) 0.01; 00051 const gsgl::real_t METERS_PER_METER = (gsgl::real_t) 1.0; 00052 const gsgl::real_t METERS_PER_KILOMETER = (gsgl::real_t) 1000.0; 00053 const gsgl::real_t METERS_PER_AU = (gsgl::real_t) 149597870691.0; 00054 const gsgl::real_t METERS_PER_PARSEC = (gsgl::real_t) 3.08567758e16; 00055 00056 const gsgl::real_t KILOGRAMS_PER_MILLIGRAM = (gsgl::real_t) 0.000001; 00057 const gsgl::real_t KILOGRAMS_PER_GRAM = (gsgl::real_t) 0.001; 00058 const gsgl::real_t KILOGRAMS_PER_KILOGRAM = (gsgl::real_t) 1.0; 00059 00060 const gsgl::real_t SECONDS_PER_MILLISECOND = (gsgl::real_t) 0.001; 00061 const gsgl::real_t SECONDS_PER_SECOND = (gsgl::real_t) 1.0; 00062 const gsgl::real_t SECONDS_PER_MINUTE = (gsgl::real_t) 60.0; 00063 const gsgl::real_t SECONDS_PER_HOUR = (gsgl::real_t) 3600.0; 00064 const gsgl::real_t SECONDS_PER_DAY = (gsgl::real_t) 86400.0; 00065 const gsgl::real_t SECONDS_PER_YEAR = (gsgl::real_t) 31557600.0; 00066 00067 00068 00069 static gsgl::real_t get_numeric_part(const string & str, int start, int & next) 00070 { 00071 int len = str.size(); 00072 00073 gsgl::real_t sign = 1; 00074 gsgl::real_t res = 0; 00075 00076 int index = start; 00077 00078 // strip whitespace 00079 while (index < len && ::iswspace(str[index])) 00080 ++index; 00081 00082 // get sign 00083 if (index < len && str[index] == L'-') 00084 { 00085 sign = -1; 00086 ++index; 00087 } 00088 else if (index < len && str[index] == L'+') 00089 { 00090 sign = 1; 00091 ++index; 00092 } 00093 00094 // get whole part 00095 while (index < len && str[index] >= L'0' && str[index] <= L'9') 00096 { 00097 res = (res * 10) + (str[index] - L'0'); 00098 ++index; 00099 } 00100 00101 // get decimal part 00102 if (index < len && str[index] == L'.') 00103 { 00104 ++index; 00105 gsgl::real_t frac = 0; 00106 gsgl::real_t factor = 0.1f; 00107 00108 while (index < len && str[index] >= L'0' && str[index] <= L'9') 00109 { 00110 frac = frac + (factor * (str[index] - L'0')); 00111 00112 factor /= 10; 00113 ++index; 00114 } 00115 00116 res += frac; 00117 } 00118 00119 // get exponent 00120 if (index < len && str[index] == L'e' || str[index] == L'E') 00121 { 00122 gsgl::real_t exp_sign = 1; 00123 gsgl::real_t exp = 0; 00124 00125 if (len > index+2) 00126 { 00127 // sign of the exponent 00128 if (str[index+1] == L'-') 00129 { 00130 exp_sign = -1; 00131 ++index; 00132 } 00133 else if (str[index+1] == L'+') 00134 { 00135 exp_sign = 1; 00136 ++index; 00137 } 00138 00139 // number of the exponent 00140 if (index < len && str[index+1] >= L'0' && str[index+1] <= L'9') 00141 { 00142 ++index; 00143 00144 while (index < len && str[index] >= L'0' && str[index] <= L'9') 00145 { 00146 exp = (exp * 10) + (str[index] - L'0'); 00147 ++index; 00148 } 00149 } 00150 } 00151 00152 res = res * ::pow(10.0f, exp * exp_sign); 00153 } 00154 00155 // we're done 00156 next = index; 00157 return res * sign; 00158 } // get_numeric_part() 00159 00160 00161 static string get_units_part(const string & str, int start) 00162 { 00163 string res = str.substring(start); 00164 return res.trim().make_lower(); 00165 } // get_units_part() 00166 00167 00168 gsgl::real_t parse(const string & str) 00169 { 00170 gsgl::real_t res = 0; 00171 00172 // get numeric part 00173 int index = 0; 00174 res = get_numeric_part(str, 0, index); 00175 00176 // get units string 00177 string uname = get_units_part(str, index); 00178 00179 if (uname == L"mm") 00180 { 00181 res *= METERS_PER_MILLIMETER; 00182 } 00183 else if (uname == L"cm") 00184 { 00185 res *= METERS_PER_CENTIMETER; 00186 } 00187 else if (uname == L"m") 00188 { 00189 res *= METERS_PER_METER; 00190 } 00191 else if (uname == L"km") 00192 { 00193 res *= METERS_PER_KILOMETER; 00194 } 00195 else if (uname == L"au") 00196 { 00197 res *= METERS_PER_AU; 00198 } 00199 else if (uname == L"parsec") 00200 { 00201 res *= METERS_PER_PARSEC; 00202 } 00203 else if (uname == L"mg") 00204 { 00205 res *= KILOGRAMS_PER_MILLIGRAM; 00206 } 00207 else if (uname == L"g") 00208 { 00209 res *= KILOGRAMS_PER_GRAM; 00210 } 00211 else if (uname == L"kg") 00212 { 00213 res *= KILOGRAMS_PER_KILOGRAM; 00214 } 00215 else if (uname == L"ms") 00216 { 00217 res *= SECONDS_PER_MILLISECOND; 00218 } 00219 else if (uname == L"s") 00220 { 00221 res *= SECONDS_PER_SECOND; 00222 } 00223 else if (uname == L"min") 00224 { 00225 res *= SECONDS_PER_MINUTE; 00226 } 00227 else if (uname == L"h") 00228 { 00229 res *= SECONDS_PER_HOUR; 00230 } 00231 else if (uname == L"day") 00232 { 00233 res *= SECONDS_PER_DAY; 00234 } 00235 else if (uname == L"year") 00236 { 00237 res *= SECONDS_PER_YEAR; 00238 } 00239 00240 return res; 00241 } // parse() 00242 00243 } // namespace units 00244 00245 } // namespace math 00246 00247 } // namespace gsgl