PageRenderTime 28ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/addon/convert/UnitConvertor.php

https://github.com/squidjam/friendika
PHP | 283 lines | 115 code | 21 blank | 147 comment | 18 complexity | 318e00af6eff5a3504905f77091cbc09 MD5 | raw file
  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP version 4.0 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2.0 of the PHP license, |
  8. // | that is bundled with this package in the file LICENSE, and is |
  9. // | available at through the world-wide-web at |
  10. // | http://www.php.net/license/2_02.txt. |
  11. // | If you did not receive a copy of the PHP license and are unable to |
  12. // | obtain it through the world-wide-web, please send a note to |
  13. // | license@php.net so we can mail you a copy immediately. |
  14. // +----------------------------------------------------------------------+
  15. // | Authors: Stanislav Okhvat <stanis@ngs.ru> |
  16. // | Co-authored by : CVH, Chris Hansel <chris@cpi-service.com> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: UnitConvertor.php,v 1.00 2002/02/20 11:40:00 stasokhvat Exp $
  20. /**
  21. * UnitConvertor is able to convert between different units and currencies.
  22. *
  23. * @author Stanislav Okhvat <stanis@sibfair.nsk.su, stanis@ngs.ru>
  24. * @version $Id: UnitConvertor.php,v 1.00 2002/03/01 17:00:00 stasokhvat Exp $
  25. * @package UnitConvertor
  26. * @access public
  27. * @history 01.03.2002 Implemented the code for regular and offset-based
  28. * conversions
  29. *
  30. * 13.12.2004
  31. * By Chris Hansel (CVH): changed getConvSpecs in order to have it look up
  32. * intermediary conversions (also see comments in check_key).
  33. *
  34. * Intermediary conversions are useful when no conversion ratio is specified
  35. * between two units when we calculate between the two. For example, we want
  36. * to convert between Fahrenheit and Kelvin, and we have only
  37. * specified how to convert Centigrade<->Fahrenheit and
  38. * Centigrade<->Kelvin. While a direct (Fahrenheit->Kelvin) or
  39. * reverse (Kelvin->Fahrenheit) lookups fail, looking for an intermediary
  40. * unit linking the two (Centigrade) helps us do the conversion.
  41. *
  42. * 13.12.2004
  43. * Chris Hansel (CVH): $to_array argument of addConversion method can now
  44. * contain units as 'unit1/unit2/unit3', when all units stand for the same
  45. * thing. See examples in unitconv.php
  46. */
  47. class UnitConvertor
  48. {
  49. /**
  50. * Stores conversion ratios.
  51. *
  52. * @var array
  53. * @access private
  54. */
  55. var $conversion_table = array();
  56. /**
  57. * Decimal point character (default is "." - American - set in constructor).
  58. *
  59. * @var string
  60. * @access private
  61. */
  62. var $decimal_point;
  63. /**
  64. * Thousands separator (default is "," - American - set in constructor).
  65. *
  66. * @var string
  67. * @access private
  68. */
  69. var $thousand_separator;
  70. /**
  71. * For future use
  72. *
  73. * @var array
  74. * @access private
  75. */
  76. var $bases = array();
  77. /**
  78. * Constructor. Initializes the UnitConvertor object with the most important
  79. * properties.
  80. *
  81. * @param string decimal point character
  82. * @param string thousand separator character
  83. * @return void
  84. * @access public
  85. */
  86. function UnitConvertor($dec_point = '.', $thousand_sep = ',')
  87. {
  88. $this->decimal_point = $dec_point;
  89. $this->thousand_separator = $thousand_sep;
  90. } // end func UnitConvertor
  91. /**
  92. * Adds a conversion ratio to the conversion table.
  93. *
  94. * @param string the name of unit from which to convert
  95. * @param array array(
  96. * "pound"=>array("ratio"=>'', "offset"=>'')
  97. * )
  98. * "pound" - name of unit to set conversion ration to
  99. * "ratio" - 'double' conversion ratio which, when
  100. * multiplied by the number of $from_unit units produces
  101. * the result
  102. * "offset" - an offset from 0 which will be added to
  103. * the result when converting (needed for temperature
  104. * conversions and defaults to 0).
  105. * @return boolean true if successful, false otherwise
  106. * @access public
  107. */
  108. function addConversion($from_unit, $to_array)
  109. {
  110. if (!isset($this->conversion_table[$from_unit])) {
  111. while(list($key, $val) = each($to_array))
  112. {
  113. if (strstr($key, '/'))
  114. {
  115. $to_units = explode('/', $key);
  116. foreach ($to_units as $to_unit)
  117. {
  118. $this->bases[$from_unit][] = $to_unit;
  119. if (!is_array($val))
  120. {
  121. $this->conversion_table[$from_unit."_".$to_unit] = array("ratio"=>$val, "offset"=>0);
  122. }
  123. else
  124. {
  125. $this->conversion_table[$from_unit."_".$to_unit] =
  126. array(
  127. "ratio"=>$val['ratio'],
  128. "offset"=>(isset($val['offset']) ? $val['offset'] : 0)
  129. );
  130. }
  131. }
  132. }
  133. else
  134. {
  135. $this->bases[$from_unit][] = $key;
  136. if (!is_array($val))
  137. {
  138. $this->conversion_table[$from_unit."_".$key] = array("ratio"=>$val, "offset"=>0);
  139. }
  140. else
  141. {
  142. $this->conversion_table[$from_unit."_".$key] =
  143. array(
  144. "ratio"=>$val['ratio'],
  145. "offset"=>(isset($val['offset']) ? $val['offset'] : 0)
  146. );
  147. }
  148. }
  149. }
  150. return true;
  151. }
  152. return false;
  153. } // end func addConversion
  154. /**
  155. * Converts from one unit to another using specified precision.
  156. *
  157. * @param double value to convert
  158. * @param string name of the source unit from which to convert
  159. * @param string name of the target unit to which we are converting
  160. * @param integer double precision of the end result
  161. * @return void
  162. * @access public
  163. */
  164. function convert($value, $from_unit, $to_unit, $precision)
  165. {
  166. if ($this->getConvSpecs($from_unit, $to_unit, $value, $converted ))
  167. {
  168. return number_format($converted , (int)$precision, $this->decimal_point, $this->thousand_separator);
  169. } else {
  170. return false;
  171. }
  172. } // end func
  173. /**
  174. * CVH : changed this Function getConvSpecs in order to have it look up
  175. * intermediary Conversions from the
  176. * "base" unit being that one that has the highest hierarchical order in one
  177. * "logical" Conversion_Array
  178. * when taking $conv->addConversion('km',
  179. * array('meter'=>1000, 'dmeter'=>10000, 'centimeter'=>100000,
  180. * 'millimeter'=>1000000, 'mile'=>0.62137, 'naut.mile'=>0.53996,
  181. * 'inch(es)/zoll'=>39370, 'ft/foot/feet'=>3280.8, 'yd/yard'=>1093.6));
  182. * "km" would be the logical base unit for all units of dinstance, thus,
  183. * if the function fails to find a direct or reverse conversion in the table
  184. * it is only logical to suspect that if there is a chance
  185. * converting the value it only is via the "base" unit, and so
  186. * there is not even a need for a recursive search keeping the perfomance
  187. * acceptable and the ressource small...
  188. *
  189. * CVH check_key checks for a key in the Conversiontable and returns a value
  190. */
  191. function check_key( $key) {
  192. if ( array_key_exists ($key,$this->conversion_table)) {
  193. if (! empty($this->conversion_table[$key])) {
  194. return $this->conversion_table[$key];
  195. }
  196. }
  197. return false;
  198. }
  199. /**
  200. * Key function. Finds the conversion ratio and offset from one unit to another.
  201. *
  202. * @param string name of the source unit from which to convert
  203. * @param string name of the target unit to which we are converting
  204. * @param double conversion ratio found. Returned by reference.
  205. * @param double offset which needs to be added (or subtracted, if negative)
  206. * to the result to convert correctly.
  207. * For temperature or some scientific conversions,
  208. * i.e. Fahrenheit -> Celcius
  209. * @return boolean true if ratio and offset are found for the supplied
  210. * units, false otherwise
  211. * @access private
  212. */
  213. function getConvSpecs($from_unit, $to_unit, $value, &$converted)
  214. {
  215. $key = $from_unit."_".$to_unit;
  216. $revkey = $to_unit."_".$from_unit;
  217. $found = false;
  218. if ($ct_arr = $this->check_key($key)) {
  219. // Conversion Specs found directly
  220. $ratio = (double)$ct_arr['ratio'];
  221. $offset = $ct_arr['offset'];
  222. $converted = (double)(($value * $ratio)+ $offset);
  223. return true;
  224. } // not found in direct order, try reverse order
  225. elseif ($ct_arr = $this->check_key($revkey)) {
  226. $ratio = (double)(1/$ct_arr['ratio']);
  227. $offset = -$ct_arr['offset'];
  228. $converted = (double)(($value + $offset) * $ratio);
  229. return true;
  230. } // not found test for intermediary conversion
  231. else {
  232. // return ratio = 1 if keyparts match
  233. if ($key == $revkey) {
  234. $ratio = 1;
  235. $offset = 0;
  236. $converted = $value;
  237. return true;
  238. }
  239. // otherwise search intermediary
  240. reset($this->conversion_table);
  241. while (list($convk, $i1_value) = each($this->conversion_table)) {
  242. // split the key into parts
  243. $keyparts = preg_split("/_/",$convk);
  244. // return ratio = 1 if keyparts match
  245. // Now test if either part matches the from or to unit
  246. if ($keyparts[1] == $to_unit && ($i2_value = $this->check_key($keyparts[0]."_".$from_unit))) {
  247. // an intermediary $keyparts[0] was found
  248. // now let us put things together intermediary 1 and 2
  249. $converted = (double)(((($value - $i2_value['offset']) / $i2_value['ratio']) * $i1_value['ratio'])+ $i1_value['offset']);
  250. $found = true;
  251. } elseif ($keyparts[1] == $from_unit && ($i2_value = $this->check_key($keyparts[0]."_".$to_unit))) {
  252. // an intermediary $keyparts[0] was found
  253. // now let us put things together intermediary 2 and 1
  254. $converted = (double)(((($value - $i1_value['offset']) / $i1_value['ratio']) + $i2_value['offset']) * $i2_value['ratio']);
  255. $found = true;
  256. }
  257. }
  258. return $found;
  259. }
  260. } // end func getConvSpecs
  261. } // end class UnitConvertor
  262. ?>