1<?php 2 3namespace LesserPHP\Functions; 4 5use Exception; 6use LesserPHP\Constants; 7use LesserPHP\Utils\Asserts; 8use LesserPHP\Utils\Util; 9 10/** 11 * Implements the math functions for LESS 12 * 13 * @link https://lesscss.org/functions/#math-functions 14 */ 15class Math extends AbstractFunctionCollection 16{ 17 /** @inheritdoc */ 18 public function getFunctions(): array 19 { 20 return [ 21 'ceil' => [$this, 'ceil'], 22 'floor' => [$this, 'floor'], 23 'percentage' => [$this, 'percentage'], 24 'round' => [$this, 'round'], 25 'sqrt' => [$this, 'sqrt'], 26 'abs' => [$this, 'abs'], 27 'sin' => [$this, 'sin'], 28 'asin' => [$this, 'asin'], 29 'cos' => [$this, 'cos'], 30 'acos' => [$this, 'acos'], 31 'tan' => [$this, 'tan'], 32 'atan' => [$this, 'atan'], 33 'pi' => [$this, 'pi'], 34 'pow' => [$this, 'pow'], 35 'mod' => [$this, 'mod'], 36 'min' => [$this, 'min'], 37 'max' => [$this, 'max'], 38 ]; 39 } 40 41 42 /** 43 * Rounds up to the next highest integer 44 * 45 * @link https://lesscss.org/functions/#math-functions-ceil 46 * @throws Exception 47 */ 48 public function ceil(array $arg): array 49 { 50 $value = Asserts::assertNumber($arg); 51 return ['number', ceil($value), $arg[2]]; 52 } 53 54 /** 55 * Rounds down to the next lowest integer 56 * 57 * @link https://lesscss.org/functions/#math-functions-floor 58 * @throws Exception 59 */ 60 public function floor(array $arg): array 61 { 62 $value = Asserts::assertNumber($arg); 63 return ['number', floor($value), $arg[2]]; 64 } 65 66 /** 67 * Converts a floating point number into a percentage string 68 * 69 * @link https://lesscss.org/functions/#math-functions-percentage 70 * @throws Exception 71 */ 72 public function percentage(array $arg): array 73 { 74 $num = Asserts::assertNumber($arg); 75 return ['number', $num * 100, '%']; 76 } 77 78 /** 79 * Applies rounding 80 * 81 * @link https://lesscss.org/functions/#math-functions-round 82 * @throws Exception 83 */ 84 public function round(array $arg): array 85 { 86 if ($arg[0] != 'list') { 87 $value = Asserts::assertNumber($arg); 88 return ['number', round($value), $arg[2]]; 89 } else { 90 $value = Asserts::assertNumber($arg[2][0]); 91 $precision = Asserts::assertNumber($arg[2][1]); 92 return ['number', round($value, $precision), $arg[2][0][2]]; 93 } 94 } 95 96 /** 97 * Calculates square root of a number 98 * 99 * @link https://lesscss.org/functions/#math-functions-sqrt 100 * @throws Exception 101 */ 102 public function sqrt(array $num): float 103 { 104 return sqrt(Asserts::assertNumber($num)); 105 } 106 107 /** 108 * Calculates absolute value of a number. Keeps units as they are. 109 * 110 * @link https://lesscss.org/functions/#math-functions-abs 111 * @throws Exception 112 */ 113 public function abs(array $num): array 114 { 115 return ['number', abs(Asserts::assertNumber($num)), $num[2]]; 116 } 117 118 /** 119 * Calculates sine function 120 * 121 * @link https://lesscss.org/functions/#math-functions-sin 122 * @throws Exception 123 */ 124 public function sin(array $num): float 125 { 126 return sin(Asserts::assertNumber($num)); 127 } 128 129 /** 130 * Calculates arcsine function 131 * 132 * @link https://lesscss.org/functions/#math-functions-asin 133 * @throws Exception 134 */ 135 public function asin(array $num): array 136 { 137 $num = asin(Asserts::assertNumber($num)); 138 return ['number', $num, 'rad']; 139 } 140 141 /** 142 * Calculates cosine function 143 * 144 * @link https://lesscss.org/functions/#math-functions-cos 145 * @throws Exception 146 */ 147 public function cos(array $num): float 148 { 149 return cos(Asserts::assertNumber($num)); 150 } 151 152 /** 153 * Calculates arccosine function 154 * 155 * @link https://lesscss.org/functions/#math-functions-acos 156 * @throws Exception 157 */ 158 public function acos(array $num): array 159 { 160 $num = acos(Asserts::assertNumber($num)); 161 return ['number', $num, 'rad']; 162 } 163 164 /** 165 * Calculates tangent function 166 * 167 * @link https://lesscss.org/functions/#math-functions-tan 168 * @throws Exception 169 */ 170 public function tan(array $num): float 171 { 172 return tan(Asserts::assertNumber($num)); 173 } 174 175 /** 176 * Calculates arctangent function 177 * 178 * @link https://lesscss.org/functions/#math-functions-atan 179 * @throws Exception 180 */ 181 public function atan(array $num): array 182 { 183 $num = atan(Asserts::assertNumber($num)); 184 return ['number', $num, 'rad']; 185 } 186 187 /** 188 * Return the value of pi 189 * 190 * @link https://lesscss.org/functions/#math-functions-pi 191 */ 192 public function pi(): float 193 { 194 return pi(); 195 } 196 197 /** 198 * Returns the value of the first argument raised to the power of the second argument. 199 * 200 * @link https://lesscss.org/functions/#math-functions-pow 201 * @throws Exception 202 */ 203 public function pow(array $args): array 204 { 205 [$base, $exp] = Asserts::assertArgs($args, 2, 'pow'); 206 return ['number', Asserts::assertNumber($base) ** Asserts::assertNumber($exp), $args[2][0][2]]; 207 } 208 209 /** 210 * Returns the value of the first argument modulus second argument. 211 * 212 * @link https://lesscss.org/functions/#math-functions-mod 213 * @throws Exception 214 */ 215 public function mod(array $args): array 216 { 217 [$a, $b] = Asserts::assertArgs($args, 2, 'mod'); 218 return ['number', Asserts::assertNumber($a) % Asserts::assertNumber($b), $args[2][0][2]]; 219 } 220 221 /** 222 * Returns the lowest of one or more values 223 * 224 * @link https://lesscss.org/functions/#math-functions-min 225 * @throws Exception 226 */ 227 public function min(array $args): array 228 { 229 $values = Asserts::assertMinArgs($args, 1, 'min'); 230 231 $first_format = $values[0][2]; 232 233 $min_index = 0; 234 $min_value = $values[0][1]; 235 236 for ($a = 0; $a < sizeof($values); $a++) { 237 $converted = Util::convert($values[$a], $first_format); 238 239 if ($converted[1] < $min_value) { 240 $min_index = $a; 241 $min_value = $values[$a][1]; 242 } 243 } 244 245 return $values[$min_index]; 246 } 247 248 /** 249 * Returns the highest of one or more values 250 * 251 * @link https://lesscss.org/functions/#math-functions-max 252 * @throws Exception 253 */ 254 public function max(array $args): array 255 { 256 $values = Asserts::assertMinArgs($args, 1, 'max'); 257 258 $first_format = $values[0][2]; 259 260 $max_index = 0; 261 $max_value = $values[0][1]; 262 263 for ($a = 0; $a < sizeof($values); $a++) { 264 $converted = Util::convert($values[$a], $first_format); 265 266 if ($converted[1] > $max_value) { 267 $max_index = $a; 268 $max_value = $values[$a][1]; 269 } 270 } 271 272 return $values[$max_index]; 273 } 274} 275