summaryrefslogtreecommitdiff
path: root/apps/plugins/lua/include_lua/math_ex.lua
blob: bd4cc58765551c60faba733ca98976fedfebfc9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
--[[ Lua Missing Math functions
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2017 William Wilgus
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
]]

--[[ Exposed Functions

    _math.clamp
    _math.clamp_roll
    _math.d_sin
    _math.d_cos
    _math.d_tan
    _math.i_sqrt

]]

local _math = {} do

    -- internal constants
    local _NIL = nil -- _NIL placeholder

   -- clamps value to >= min and <= max
    local function clamp(iVal, iMin, iMax)
        if iMin > iMax then
            local swap = iMin
            iMin, iMax = iMax, swap
        end

        if iVal < iMin then
            return iMin
        elseif iVal < iMax then
            return iVal
        end

        return iMax
    end

   -- clamps value to >= min and <= max rolls over to opposite
    local function clamp_roll(iVal, iMin, iMax)
        if iMin > iMax then
            local swap = iMin
            iMin, iMax = iMax, swap
        end

        if iVal < iMin then
            iVal = iMax
        elseif iVal > iMax then
            iVal = iMin
        end

        return iVal
    end

    local function i_sqrt(n)
        -- Newtons square root approximation
        if n < 2 then return n end
        local g = n / 2
        local l = 1

        for c = 1, 25 do -- if l,g haven't converged after 25 iterations quit

            l = (n / g + g)/ 2
            g = (n / l + l)/ 2

            if g == l then return g end
        end

        -- check for period-two cycle between g and l
        if g - l == 1 then
            return l
        elseif l - g == 1 then
            return g
        end

        return _NIL
    end

    local function d_sin(iDeg, bExtraPrecision)
    --[[  values are returned multiplied by 10000
          II  |  I       180-90   | 90-0
         ---(--)---      -------(--)-------
         III |  IV       180-270 | 270-360

        sine is only positive in quadrants I , II => 0 - 180 degrees
        sine 180-360 degrees is a reflection of sine 0-180
        Bhaskara I's sine approximation formula isn't overly accurate
        but it is close enough for rough image work.
    ]]
        local sign, x
        -- no negative angles -10 degrees = 350 degrees
        if iDeg < 0 then
            x = 360 + (iDeg % 360)
        else --keep rotation in 0-360 range
            x = iDeg % 360
        end

        -- reflect II & I onto III & IV
        if x > 180 then
            sign = -1
            x = x % 180
        else
            sign = 1
        end

        local x1 = x * (180 - x)

        if bExtraPrecision then -- ~halves the largest errors
            if x <= 22 or x >= 158 then
                return sign * 39818 * x1 / (40497 - x1)
            elseif (x >= 40 and x <= 56) or (x > 124 and x < 140) then
                return sign * 40002 * x1 / (40450 - x1)
            elseif (x > 31 and x < 71) or (x > 109 and x < 150) then
                return sign * 40009 * x1 / (40470 - x1)
            end
        end

        --multiplied by 10000 so no decimal in results (RB LUA is integer only)
        return sign * 40000 * x1 / (40497 - x1)
    end

    local function d_cos(iDeg, bExtraPrecision)
        --cos is just sine shifed by 90 degrees CCW
        return d_sin(90 - iDeg, bExtraPrecision)
    end

    local function d_tan(iDeg, bExtraPrecision)
        --tan = sin0 / cos0
        return (d_sin(iDeg, bExtraPrecision) * 10000 / d_sin(90 - iDeg, bExtraPrecision))
    end

    --expose functions to the outside through _math table
    _math.clamp       = clamp
    _math.clamp_roll  = clamp_roll
    _math.i_sqrt      = i_sqrt
    _math.d_sin       = d_sin
    _math.d_cos       = d_cos
    _math.d_tan       = d_tan
end -- missing math functions

return _math