ILIAS  release_4-4 Revision
All Data Structures Namespaces Files Functions Variables Modules 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. More...
 
 getSigFigs ($n)
 Returns the number of significant figures in a string number. More...
 

Data Fields

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

Protected Attributes

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

Static Protected Attributes

static $units
 Units information array. More...
 

Private Member Functions

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

Private Attributes

 $bcmath
 Whether or not BCMath is available. More...
 

Detailed Description

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

Definition at line 7 of file UnitConverter.php.

Constructor & Destructor Documentation

◆ __construct()

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

Definition at line 53 of file UnitConverter.php.

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

Member Function Documentation

◆ add()

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().

188  {
189  if ($this->bcmath) return bcadd($s1, $s2, $scale);
190  else return $this->scale($s1 + $s2, $scale);
191  }
scale($r, $scale)
Scales a float to $scale digits right of decimal point, like BCMath.
+ Here is the call graph for this function:

◆ convert()

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, $n, $outputPrecision, div(), getSigFigs(), mul(), and round().

77  {
78 
79  if (!$length->isValid()) return false;
80 
81  $n = $length->getN();
82  $unit = $length->getUnit();
83 
84  if ($n === '0' || $unit === false) {
85  return new HTMLPurifier_Length('0', false);
86  }
87 
88  $state = $dest_state = false;
89  foreach (self::$units as $k => $x) {
90  if (isset($x[$unit])) $state = $k;
91  if (isset($x[$to_unit])) $dest_state = $k;
92  }
93  if (!$state || !$dest_state) return false;
94 
95  // Some calculations about the initial precision of the number;
96  // this will be useful when we need to do final rounding.
97  $sigfigs = $this->getSigFigs($n);
98  if ($sigfigs < $this->outputPrecision) $sigfigs = $this->outputPrecision;
99 
100  // BCMath's internal precision deals only with decimals. Use
101  // our default if the initial number has no decimals, or increase
102  // it by how ever many decimals, thus, the number of guard digits
103  // will always be greater than or equal to internalPrecision.
104  $log = (int) floor(log(abs($n), 10));
105  $cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision
106 
107  for ($i = 0; $i < 2; $i++) {
108 
109  // Determine what unit IN THIS SYSTEM we need to convert to
110  if ($dest_state === $state) {
111  // Simple conversion
112  $dest_unit = $to_unit;
113  } else {
114  // Convert to the smallest unit, pending a system shift
115  $dest_unit = self::$units[$state][$dest_state][0];
116  }
117 
118  // Do the conversion if necessary
119  if ($dest_unit !== $unit) {
120  $factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp);
121  $n = $this->mul($n, $factor, $cp);
122  $unit = $dest_unit;
123  }
124 
125  // Output was zero, so bail out early. Shouldn't ever happen.
126  if ($n === '') {
127  $n = '0';
128  $unit = $to_unit;
129  break;
130  }
131 
132  // It was a simple conversion, so bail out
133  if ($dest_state === $state) {
134  break;
135  }
136 
137  if ($i !== 0) {
138  // Conversion failed! Apparently, the system we forwarded
139  // to didn't have this unit. This should never happen!
140  return false;
141  }
142 
143  // Pre-condition: $i == 0
144 
145  // Perform conversion to next system of units
146  $n = $this->mul($n, self::$units[$state][$dest_state][1], $cp);
147  $unit = self::$units[$state][$dest_state][2];
148  $state = $dest_state;
149 
150  // One more loop around to convert the unit in the new system.
151 
152  }
153 
154  // Post-condition: $unit == $to_unit
155  if ($unit !== $to_unit) return false;
156 
157  // Useful for debugging:
158  //echo "<pre>n";
159  //echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n</pre>\n";
160 
161  $n = $this->round($n, $sigfigs);
162  if (strpos($n, '.') !== false) $n = rtrim($n, '0');
163  $n = rtrim($n, '.');
164 
165  return new HTMLPurifier_Length($n, $unit);
166  }
mul($s1, $s2, $scale)
Multiples two numbers, using arbitrary precision when available.
getSigFigs($n)
Returns the number of significant figures in a string number.
div($s1, $s2, $scale)
Divides two numbers, using arbitrary precision when available.
$n
Definition: RandomTest.php:80
Represents a measurable length, with a string numeric magnitude and a unit.
Definition: Length.php:7
round($n, $sigfigs)
Rounds a number according to the number of sigfigs it should have, using arbitrary precision when ava...
$outputPrecision
Minimum bcmath precision for output.
+ Here is the call graph for this function:

◆ div()

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().

204  {
205  if ($this->bcmath) return bcdiv($s1, $s2, $scale);
206  else return $this->scale($s1 / $s2, $scale);
207  }
scale($r, $scale)
Scales a float to $scale digits right of decimal point, like BCMath.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getSigFigs()

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.

References $n.

Referenced by convert().

173  {
174  $n = ltrim($n, '0+-');
175  $dp = strpos($n, '.'); // decimal position
176  if ($dp === false) {
177  $sigfigs = strlen(rtrim($n, '0'));
178  } else {
179  $sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character
180  if ($dp !== 0) $sigfigs--;
181  }
182  return $sigfigs;
183  }
$n
Definition: RandomTest.php:80
+ Here is the caller graph for this function:

◆ mul()

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().

196  {
197  if ($this->bcmath) return bcmul($s1, $s2, $scale);
198  else return $this->scale($s1 * $s2, $scale);
199  }
scale($r, $scale)
Scales a float to $scale digits right of decimal point, like BCMath.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ round()

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 $n, and scale().

Referenced by convert(), and scale().

213  {
214  $new_log = (int) floor(log(abs($n), 10)); // Number of digits left of decimal - 1
215  $rp = $sigfigs - $new_log - 1; // Number of decimal places needed
216  $neg = $n < 0 ? '-' : ''; // Negative sign
217  if ($this->bcmath) {
218  if ($rp >= 0) {
219  $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1);
220  $n = bcdiv($n, '1', $rp);
221  } else {
222  // This algorithm partially depends on the standardized
223  // form of numbers that comes out of bcmath.
224  $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0);
225  $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1);
226  }
227  return $n;
228  } else {
229  return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1);
230  }
231  }
scale($r, $scale)
Scales a float to $scale digits right of decimal point, like BCMath.
$n
Definition: RandomTest.php:80
round($n, $sigfigs)
Rounds a number according to the number of sigfigs it should have, using arbitrary precision when ava...
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ scale()

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 $r, and round().

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

236  {
237  if ($scale < 0) {
238  // The f sprintf type doesn't support negative numbers, so we
239  // need to cludge things manually. First get the string.
240  $r = sprintf('%.0f', (float) $r);
241  // Due to floating point precision loss, $r will more than likely
242  // look something like 4652999999999.9234. We grab one more digit
243  // than we need to precise from $r and then use that to round
244  // appropriately.
245  $precise = (string) round(substr($r, 0, strlen($r) + $scale), -1);
246  // Now we return it, truncating the zero that was rounded off.
247  return substr($precise, 0, -1) . str_repeat('0', -$scale + 1);
248  }
249  return sprintf('%.' . $scale . 'f', (float) $r);
250  }
round($n, $sigfigs)
Rounds a number according to the number of sigfigs it should have, using arbitrary precision when ava...
$r
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Field Documentation

◆ $bcmath

HTMLPurifier_UnitConverter::$bcmath
private

Whether or not BCMath is available.

Definition at line 51 of file UnitConverter.php.

◆ $internalPrecision

HTMLPurifier_UnitConverter::$internalPrecision
protected

Bcmath precision for internal calculations.

Definition at line 46 of file UnitConverter.php.

◆ $outputPrecision

HTMLPurifier_UnitConverter::$outputPrecision
protected

Minimum bcmath precision for output.

Definition at line 41 of file UnitConverter.php.

Referenced by convert().

◆ $units

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.

◆ DIGITAL

const HTMLPurifier_UnitConverter::DIGITAL = 3

Definition at line 12 of file UnitConverter.php.

◆ ENGLISH

const HTMLPurifier_UnitConverter::ENGLISH = 1

Definition at line 10 of file UnitConverter.php.

◆ METRIC

const HTMLPurifier_UnitConverter::METRIC = 2

Definition at line 11 of file UnitConverter.php.


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