1<?php
2
3namespace LesserPHP\Utils;
4
5use Exception;
6use LesserPHP\Constants;
7
8/**
9 * Miscelaneous utility methods
10 */
11class Util
12{
13    /**
14     * Clamps a value between a minimum and maximum value.
15     *
16     * This function takes a value and two boundary values (maximum and minimum).
17     * It ensures that the provided value does not exceed the boundaries.
18     * If the value is less than the minimum, the minimum is returned.
19     * If the value is greater than the maximum, the maximum is returned.
20     * Otherwise, the original value is returned.
21     */
22    public static function clamp(float $v, float $max = 1, float $min = 0): float
23    {
24        return min($max, max($min, $v));
25    }
26
27    /**
28     * Quote a string for use in a regular expression
29     */
30    public static function pregQuote(string $what): string
31    {
32        return preg_quote($what, '/');
33    }
34
35    /**
36     * Return a boolean type
37     *
38     * @param mixed $a
39     */
40    public static function toBool($a): array
41    {
42        if ($a) return Constants::TRUE;
43        return Constants::FALSE;
44    }
45
46    /**
47     * Converts numbers between different types of units
48     *
49     * @throws Exception
50     */
51    public static function convert($number, $to): array
52    {
53        $value = Asserts::assertNumber($number);
54        $from = $number[2];
55
56        // easy out
57        if ($from == $to)
58            return $number;
59
60        // check if the from value is a length
61        if (($from_index = array_search($from, Constants::LENGTH_UNITS)) !== false) {
62            // make sure to value is too
63            if (in_array($to, Constants::LENGTH_UNITS)) {
64                // do the actual conversion
65                $to_index = array_search($to, Constants::LENGTH_UNITS);
66                $px = $value * Constants::LENGTH_BASES[$from_index];
67                $result = $px * (1 / Constants::LENGTH_BASES[$to_index]);
68
69                $result = round($result, 8);
70                return ['number', $result, $to];
71            }
72        }
73
74        // do the same check for times
75        if (in_array($from, Constants::TIME_UNITS)) {
76            if (in_array($to, Constants::TIME_UNITS)) {
77                // currently only ms and s are valid
78                if ($to == 'ms')
79                    $result = $value * 1000;
80                else $result = $value / 1000;
81
82                $result = round($result, 8);
83                return ['number', $result, $to];
84            }
85        }
86
87        // lastly check for an angle
88        if (in_array($from, Constants::ANGLE_UNITS)) {
89            // convert whatever angle it is into degrees
90            switch ($from) {
91                case 'rad':
92                    $deg = rad2deg($value);
93                    break;
94                case 'turn':
95                    $deg = $value * 360;
96                    break;
97                case 'grad':
98                    $deg = $value / (400 / 360);
99                    break;
100                default:
101                    $deg = $value;
102                    break;
103            }
104
105            // Then convert it from degrees into desired unit
106            switch ($to) {
107                case 'rad':
108                    $result = deg2rad($deg);
109                    break;
110                case 'turn':
111                    $result = $deg / 360;
112                    break;
113                case 'grad':
114                    $result = $deg * (400 / 360);
115                    break;
116                default:
117                    $result = $deg;
118                    break;
119            }
120
121            $result = round($result, 8);
122            return ['number', $result, $to];
123        }
124
125        // we don't know how to convert these
126        throw new Exception("Cannot convert $from to $to");
127    }
128}
129