ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
HTMLPurifier_UnitConverter Class Reference

Class for converting between different unit-lengths as specified by CSS. More...

+ Collaboration diagram for HTMLPurifier_UnitConverter:

Public Member Functions

 __construct ($output_precision=4, $internal_precision=10, $force_no_bcmath=false)
 convert ($length, $to_unit)
 Converts a length object of one unit into another unit.
 getSigFigs ($n)
 Returns the number of significant figures in a string number.

Data Fields

const ENGLISH = 1
const METRIC = 2
const DIGITAL = 3

Protected Attributes

 $outputPrecision
 Minimum bcmath precision for output.
 $internalPrecision
 Bcmath precision for internal calculations.

Static Protected Attributes

static $units
 Units information array.

Private Member Functions

 add ($s1, $s2, $scale)
 Adds two numbers, using arbitrary precision when available.
 mul ($s1, $s2, $scale)
 Multiples two numbers, using arbitrary precision when available.
 div ($s1, $s2, $scale)
 Divides two numbers, using arbitrary precision when available.
 round ($n, $sigfigs)
 Rounds a number according to the number of sigfigs it should have, using arbitrary precision when available.
 scale ($r, $scale)
 Scales a float to $scale digits right of decimal point, like BCMath.

Private Attributes

 $bcmath
 Whether or not BCMath is available.

Detailed Description

Class for converting between different unit-lengths as specified by CSS.

Definition at line 7 of file UnitConverter.php.

Constructor & Destructor Documentation

HTMLPurifier_UnitConverter::__construct (   $output_precision = 4,
  $internal_precision = 10,
  $force_no_bcmath = false 
)

Definition at line 53 of file UnitConverter.php.

{
$this->outputPrecision = $output_precision;
$this->internalPrecision = $internal_precision;
$this->bcmath = !$force_no_bcmath && function_exists('bcmul');
}

Member Function Documentation

HTMLPurifier_UnitConverter::add (   $s1,
  $s2,
  $scale 
)
private

Adds two numbers, using arbitrary precision when available.

Definition at line 188 of file UnitConverter.php.

References scale().

{
if ($this->bcmath) return bcadd($s1, $s2, $scale);
else return $this->scale($s1 + $s2, $scale);
}

+ Here is the call graph for this function:

HTMLPurifier_UnitConverter::convert (   $length,
  $to_unit 
)

Converts a length object of one unit into another unit.

Parameters
HTMLPurifier_Length$lengthInstance of HTMLPurifier_Length to convert. You must validate() it before passing it here!
string$to_unitUnit to convert to.
Note
About precision: This conversion function pays very special attention to the incoming precision of values and attempts to maintain a number of significant figure. Results are fairly accurate up to nine digits. Some caveats:
  • If a number is zero-padded as a result of this significant figure tracking, the zeroes will be eliminated.
  • If a number contains less than four sigfigs ($outputPrecision) and this causes some decimals to be excluded, those decimals will be added on.

Definition at line 77 of file UnitConverter.php.

References $log, $outputPrecision, $x, div(), getSigFigs(), mul(), and round().

{
if (!$length->isValid()) return false;
$n = $length->getN();
$unit = $length->getUnit();
if ($n === '0' || $unit === false) {
return new HTMLPurifier_Length('0', false);
}
$state = $dest_state = false;
foreach (self::$units as $k => $x) {
if (isset($x[$unit])) $state = $k;
if (isset($x[$to_unit])) $dest_state = $k;
}
if (!$state || !$dest_state) return false;
// Some calculations about the initial precision of the number;
// this will be useful when we need to do final rounding.
$sigfigs = $this->getSigFigs($n);
if ($sigfigs < $this->outputPrecision) $sigfigs = $this->outputPrecision;
// BCMath's internal precision deals only with decimals. Use
// our default if the initial number has no decimals, or increase
// it by how ever many decimals, thus, the number of guard digits
// will always be greater than or equal to internalPrecision.
$log = (int) floor(log(abs($n), 10));
$cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision
for ($i = 0; $i < 2; $i++) {
// Determine what unit IN THIS SYSTEM we need to convert to
if ($dest_state === $state) {
// Simple conversion
$dest_unit = $to_unit;
} else {
// Convert to the smallest unit, pending a system shift
$dest_unit = self::$units[$state][$dest_state][0];
}
// Do the conversion if necessary
if ($dest_unit !== $unit) {
$factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp);
$n = $this->mul($n, $factor, $cp);
$unit = $dest_unit;
}
// Output was zero, so bail out early. Shouldn't ever happen.
if ($n === '') {
$n = '0';
$unit = $to_unit;
break;
}
// It was a simple conversion, so bail out
if ($dest_state === $state) {
break;
}
if ($i !== 0) {
// Conversion failed! Apparently, the system we forwarded
// to didn't have this unit. This should never happen!
return false;
}
// Pre-condition: $i == 0
// Perform conversion to next system of units
$n = $this->mul($n, self::$units[$state][$dest_state][1], $cp);
$unit = self::$units[$state][$dest_state][2];
$state = $dest_state;
// One more loop around to convert the unit in the new system.
}
// Post-condition: $unit == $to_unit
if ($unit !== $to_unit) return false;
// Useful for debugging:
//echo "<pre>n";
//echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n</pre>\n";
$n = $this->round($n, $sigfigs);
if (strpos($n, '.') !== false) $n = rtrim($n, '0');
$n = rtrim($n, '.');
return new HTMLPurifier_Length($n, $unit);
}

+ Here is the call graph for this function:

HTMLPurifier_UnitConverter::div (   $s1,
  $s2,
  $scale 
)
private

Divides two numbers, using arbitrary precision when available.

Definition at line 204 of file UnitConverter.php.

References scale().

Referenced by convert().

{
if ($this->bcmath) return bcdiv($s1, $s2, $scale);
else return $this->scale($s1 / $s2, $scale);
}

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

HTMLPurifier_UnitConverter::getSigFigs (   $n)

Returns the number of significant figures in a string number.

Parameters
string$nDecimal number
Returns
int number of sigfigs

Definition at line 173 of file UnitConverter.php.

Referenced by convert().

{
$n = ltrim($n, '0+-');
$dp = strpos($n, '.'); // decimal position
if ($dp === false) {
$sigfigs = strlen(rtrim($n, '0'));
} else {
$sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character
if ($dp !== 0) $sigfigs--;
}
return $sigfigs;
}

+ Here is the caller graph for this function:

HTMLPurifier_UnitConverter::mul (   $s1,
  $s2,
  $scale 
)
private

Multiples two numbers, using arbitrary precision when available.

Definition at line 196 of file UnitConverter.php.

References scale().

Referenced by convert().

{
if ($this->bcmath) return bcmul($s1, $s2, $scale);
else return $this->scale($s1 * $s2, $scale);
}

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

HTMLPurifier_UnitConverter::round (   $n,
  $sigfigs 
)
private

Rounds a number according to the number of sigfigs it should have, using arbitrary precision when available.

Definition at line 213 of file UnitConverter.php.

References scale().

Referenced by convert(), and scale().

{
$new_log = (int) floor(log(abs($n), 10)); // Number of digits left of decimal - 1
$rp = $sigfigs - $new_log - 1; // Number of decimal places needed
$neg = $n < 0 ? '-' : ''; // Negative sign
if ($this->bcmath) {
if ($rp >= 0) {
$n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1);
$n = bcdiv($n, '1', $rp);
} else {
// This algorithm partially depends on the standardized
// form of numbers that comes out of bcmath.
$n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0);
$n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1);
}
return $n;
} else {
return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1);
}
}

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

HTMLPurifier_UnitConverter::scale (   $r,
  $scale 
)
private

Scales a float to $scale digits right of decimal point, like BCMath.

Definition at line 236 of file UnitConverter.php.

References round().

Referenced by add(), div(), mul(), and round().

{
if ($scale < 0) {
// The f sprintf type doesn't support negative numbers, so we
// need to cludge things manually. First get the string.
$r = sprintf('%.0f', (float) $r);
// Due to floating point precision loss, $r will more than likely
// look something like 4652999999999.9234. We grab one more digit
// than we need to precise from $r and then use that to round
// appropriately.
$precise = (string) round(substr($r, 0, strlen($r) + $scale), -1);
// Now we return it, truncating the zero that was rounded off.
return substr($precise, 0, -1) . str_repeat('0', -$scale + 1);
}
return sprintf('%.' . $scale . 'f', (float) $r);
}

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Field Documentation

HTMLPurifier_UnitConverter::$bcmath
private

Whether or not BCMath is available.

Definition at line 51 of file UnitConverter.php.

HTMLPurifier_UnitConverter::$internalPrecision
protected

Bcmath precision for internal calculations.

Definition at line 46 of file UnitConverter.php.

HTMLPurifier_UnitConverter::$outputPrecision
protected

Minimum bcmath precision for output.

Definition at line 41 of file UnitConverter.php.

Referenced by convert().

HTMLPurifier_UnitConverter::$units
staticprotected
Initial value:
array(
self::ENGLISH => array(
'px' => 3,
'pt' => 4,
'pc' => 48,
'in' => 288,
self::METRIC => array('pt', '0.352777778', 'mm'),
),
self::METRIC => array(
'mm' => 1,
'cm' => 10,
self::ENGLISH => array('mm', '2.83464567', 'pt'),
),
)

Units information array.

Units are grouped into measuring systems (English, Metric), and are assigned an integer representing the conversion factor between that unit and the smallest unit in the system. Numeric indexes are actually magical constants that encode conversion data from one system to the next, with a O(n^2) constraint on memory (this is generally not a problem, since the number of measuring systems is small.)

Definition at line 23 of file UnitConverter.php.

const HTMLPurifier_UnitConverter::DIGITAL = 3

Definition at line 12 of file UnitConverter.php.

const HTMLPurifier_UnitConverter::ENGLISH = 1

Definition at line 10 of file UnitConverter.php.

const HTMLPurifier_UnitConverter::METRIC = 2

Definition at line 11 of file UnitConverter.php.


The documentation for this class was generated from the following file: