From be9d786ef9a6203569a0a69373a3fc2922399be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Thu, 23 Jun 2022 05:46:32 +0200 Subject: [PATCH] Ops, we need this back! :-( --- convert/UnitConvertor.php | 283 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 convert/UnitConvertor.php diff --git a/convert/UnitConvertor.php b/convert/UnitConvertor.php new file mode 100644 index 00000000..d7933a8f --- /dev/null +++ b/convert/UnitConvertor.php @@ -0,0 +1,283 @@ + | +// | Co-authored by : CVH, Chris Hansel | +// +----------------------------------------------------------------------+ +// +// $Id: UnitConvertor.php,v 1.00 2002/02/20 11:40:00 stasokhvat Exp $ + +/** +* UnitConvertor is able to convert between different units and currencies. +* +* @author Stanislav Okhvat +* @version $Id: UnitConvertor.php,v 1.00 2002/03/01 17:00:00 stasokhvat Exp $ +* @package UnitConvertor +* @access public +* @history 01.03.2002 Implemented the code for regular and offset-based +* conversions +* +* 13.12.2004 +* By Chris Hansel (CVH): changed getConvSpecs in order to have it look up +* intermediary conversions (also see comments in check_key). +* +* Intermediary conversions are useful when no conversion ratio is specified +* between two units when we calculate between the two. For example, we want +* to convert between Fahrenheit and Kelvin, and we have only +* specified how to convert Centigrade<->Fahrenheit and +* Centigrade<->Kelvin. While a direct (Fahrenheit->Kelvin) or +* reverse (Kelvin->Fahrenheit) lookups fail, looking for an intermediary +* unit linking the two (Centigrade) helps us do the conversion. +* +* 13.12.2004 +* Chris Hansel (CVH): $to_array argument of addConversion method can now +* contain units as 'unit1/unit2/unit3', when all units stand for the same +* thing. See examples in unitconv.php +*/ +class UnitConvertor +{ + /** + * Stores conversion ratios. + * + * @var array + * @access private + */ + var $conversion_table = array(); + + /** + * Decimal point character (default is "." - American - set in constructor). + * + * @var string + * @access private + */ + var $decimal_point; + + /** + * Thousands separator (default is "," - American - set in constructor). + * + * @var string + * @access private + */ + var $thousand_separator; + + /** + * For future use + * + * @var array + * @access private + */ + var $bases = array(); + + /** + * Constructor. Initializes the UnitConvertor object with the most important + * properties. + * + * @param string decimal point character + * @param string thousand separator character + * @return void + * @access public + */ + function UnitConvertor($dec_point = '.', $thousand_sep = ',') + { + $this->decimal_point = $dec_point; + $this->thousand_separator = $thousand_sep; + + } // end func UnitConvertor + + /** + * Adds a conversion ratio to the conversion table. + * + * @param string the name of unit from which to convert + * @param array array( + * "pound"=>array("ratio"=>'', "offset"=>'') + * ) + * "pound" - name of unit to set conversion ration to + * "ratio" - 'double' conversion ratio which, when + * multiplied by the number of $from_unit units produces + * the result + * "offset" - an offset from 0 which will be added to + * the result when converting (needed for temperature + * conversions and defaults to 0). + * @return boolean true if successful, false otherwise + * @access public + */ + function addConversion($from_unit, $to_array) + { + if (!isset($this->conversion_table[$from_unit])) { + while(list($key, $val) = each($to_array)) + { + if (strstr($key, '/')) + { + $to_units = explode('/', $key); + foreach ($to_units as $to_unit) + { + $this->bases[$from_unit][] = $to_unit; + + if (!is_array($val)) + { + $this->conversion_table[$from_unit."_".$to_unit] = array("ratio"=>$val, "offset"=>0); + } + else + { + $this->conversion_table[$from_unit."_".$to_unit] = + array( + "ratio"=>$val['ratio'], + "offset"=>(isset($val['offset']) ? $val['offset'] : 0) + ); + } + } + } + else + { + $this->bases[$from_unit][] = $key; + + if (!is_array($val)) + { + $this->conversion_table[$from_unit."_".$key] = array("ratio"=>$val, "offset"=>0); + } + else + { + $this->conversion_table[$from_unit."_".$key] = + array( + "ratio"=>$val['ratio'], + "offset"=>(isset($val['offset']) ? $val['offset'] : 0) + ); + } + } + } + return true; + } + return false; + + } // end func addConversion + + /** + * Converts from one unit to another using specified precision. + * + * @param double value to convert + * @param string name of the source unit from which to convert + * @param string name of the target unit to which we are converting + * @param integer double precision of the end result + * @return void + * @access public + */ + function convert($value, $from_unit, $to_unit, $precision) + { + if ($this->getConvSpecs($from_unit, $to_unit, $value, $converted )) + { + return number_format($converted , (int)$precision, $this->decimal_point, $this->thousand_separator); + } else { + return false; + } + } // end func + + /** + * CVH : changed this Function getConvSpecs in order to have it look up + * intermediary Conversions from the + * "base" unit being that one that has the highest hierarchical order in one + * "logical" Conversion_Array + * when taking $conv->addConversion('km', + * array('meter'=>1000, 'dmeter'=>10000, 'centimeter'=>100000, + * 'millimeter'=>1000000, 'mile'=>0.62137, 'naut.mile'=>0.53996, + * 'inch(es)/zoll'=>39370, 'ft/foot/feet'=>3280.8, 'yd/yard'=>1093.6)); + * "km" would be the logical base unit for all units of dinstance, thus, + * if the function fails to find a direct or reverse conversion in the table + * it is only logical to suspect that if there is a chance + * converting the value it only is via the "base" unit, and so + * there is not even a need for a recursive search keeping the perfomance + * acceptable and the ressource small... + * + * CVH check_key checks for a key in the Conversiontable and returns a value + */ + function check_key( $key) { + if ( array_key_exists ($key,$this->conversion_table)) { + if (! empty($this->conversion_table[$key])) { + return $this->conversion_table[$key]; + } + } + return false; + } + + /** + * Key function. Finds the conversion ratio and offset from one unit to another. + * + * @param string name of the source unit from which to convert + * @param string name of the target unit to which we are converting + * @param double conversion ratio found. Returned by reference. + * @param double offset which needs to be added (or subtracted, if negative) + * to the result to convert correctly. + * For temperature or some scientific conversions, + * i.e. Fahrenheit -> Celcius + * @return boolean true if ratio and offset are found for the supplied + * units, false otherwise + * @access private + */ + function getConvSpecs($from_unit, $to_unit, $value, &$converted) + { + $key = $from_unit."_".$to_unit; + $revkey = $to_unit."_".$from_unit; + $found = false; + if ($ct_arr = $this->check_key($key)) { + // Conversion Specs found directly + $ratio = (double)$ct_arr['ratio']; + $offset = $ct_arr['offset']; + $converted = (double)(($value * $ratio)+ $offset); + + return true; + } // not found in direct order, try reverse order + elseif ($ct_arr = $this->check_key($revkey)) { + $ratio = (double)(1/$ct_arr['ratio']); + $offset = -$ct_arr['offset']; + $converted = (double)(($value + $offset) * $ratio); + + return true; + } // not found test for intermediary conversion + else { + // return ratio = 1 if keyparts match + if ($key == $revkey) { + $ratio = 1; + $offset = 0; + $converted = $value; + return true; + } + // otherwise search intermediary + reset($this->conversion_table); + while (list($convk, $i1_value) = each($this->conversion_table)) { + // split the key into parts + $keyparts = preg_split("/_/",$convk); + // return ratio = 1 if keyparts match + + // Now test if either part matches the from or to unit + if ($keyparts[1] == $to_unit && ($i2_value = $this->check_key($keyparts[0]."_".$from_unit))) { + // an intermediary $keyparts[0] was found + // now let us put things together intermediary 1 and 2 + $converted = (double)(((($value - $i2_value['offset']) / $i2_value['ratio']) * $i1_value['ratio'])+ $i1_value['offset']); + + $found = true; + + } elseif ($keyparts[1] == $from_unit && ($i2_value = $this->check_key($keyparts[0]."_".$to_unit))) { + // an intermediary $keyparts[0] was found + // now let us put things together intermediary 2 and 1 + $converted = (double)(((($value - $i1_value['offset']) / $i1_value['ratio']) + $i2_value['offset']) * $i2_value['ratio']); + + $found = true; + } + } + return $found; + } + + } // end func getConvSpecs + +} // end class UnitConvertor +?> \ No newline at end of file