001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
035:
036:
037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083:
084:
085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
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:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:














































































































































































































































































































































































/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(OMNI_MATH_HPP)
#define OMNI_MATH_HPP 1

#include <omni/types/math_t.hpp>

namespace omni {
    namespace math {
        template < typename T >
        inline bool are_equal(T x, T y, T epsilon)
        {
            return std::fabs(x - y) <= epsilon;
        }

        template < typename T >
        inline bool are_equal(T x, T y)
        {
            return omni::math::are_equal(x, y, std::numeric_limits<T>::epsilon());
        }

        template <> inline bool are_equal<uint8_t>(uint8_t x, uint8_t y, uint8_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }
        template <> inline bool are_equal<int8_t>(int8_t x, int8_t y, int8_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }
        template <> inline bool are_equal<uint16_t>(uint16_t x, uint16_t y, uint16_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }
        template <> inline bool are_equal<int16_t>(int16_t x, int16_t y, int16_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }
        template <> inline bool are_equal<uint32_t>(uint32_t x, uint32_t y, uint32_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }
        template <> inline bool are_equal<int32_t>(int32_t x, int32_t y, int32_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }
        template <> inline bool are_equal<uint64_t>(uint64_t x, uint64_t y, uint64_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }
        template <> inline bool are_equal<int64_t>(int64_t x, int64_t y, int64_t epsilon) { OMNI_UNUSED(epsilon); return x == y; }

        template <> inline bool are_equal<bool>(bool x, bool y) { return x == y; }
        template <> inline bool are_equal<uint8_t>(uint8_t x, uint8_t y) { return x == y; }
        template <> inline bool are_equal<int8_t>(int8_t x, int8_t y) { return x == y; }
        template <> inline bool are_equal<uint16_t>(uint16_t x, uint16_t y) { return x == y; }
        template <> inline bool are_equal<int16_t>(int16_t x, int16_t y) { return x == y; }
        template <> inline bool are_equal<uint32_t>(uint32_t x, uint32_t y) { return x == y; }
        template <> inline bool are_equal<int32_t>(int32_t x, int32_t y) { return x == y; }
        template <> inline bool are_equal<uint64_t>(uint64_t x, uint64_t y) { return x == y; }
        template <> inline bool are_equal<int64_t>(int64_t x, int64_t y) { return x == y; }
        
        inline double rad_to_deg(double rad)
        {
            return rad * OMNI_180_PI; // degrees = radians * π / 180
        }

        inline double deg_to_rad(double deg)
        {
            return deg * OMNI_PI_180; // radians = degrees * 180 / π
        }

        template < typename T >
        inline T delta(const T& a, const T& b)
        {
            return a - b;
        }

        template < typename T >
        inline T delta_squared(const T& a, const T& b)
        {
            return (a - b) * (a - b);
        }

        template < typename T >
        inline double area_of_circle(T radius)
        {
            return OMNI_PI * static_cast<double>(radius) * static_cast<double>(radius);
        }

        template < typename T >
        inline double area_circle_sector(T radius, T degrees)
        {
            return (static_cast<double>(degrees) / 360.0) * omni::math::area_of_circle(radius);
        }

        template < typename T >
        inline double radius_from_area(T area)
        {
            return std::sqrt(static_cast<long double>(area) / OMNI_PI);
        }

        template < typename T >
        inline double distance_between_2_points(T start_x, T start_y, T end_x, T end_y)
        {
            return std::sqrt(
                static_cast<long double>(omni::math::delta_squared(start_x, end_x)) +
                static_cast<long double>(omni::math::delta_squared(start_y, end_y)));
        }

        template < typename T >
        inline double distance_between_2_points(T start_x, T start_y, T start_z, T end_x, T end_y, T end_z)
        {
            return std::sqrt(
                static_cast<long double>(omni::math::delta_squared(start_x, end_x)) +
                static_cast<long double>(omni::math::delta_squared(start_y, end_y)) +
                static_cast<long double>(omni::math::delta_squared(start_z, end_z)));
        }

        template < typename T >
        inline double distance_between_2_points(const omni::math::dimensional<T, 2>& start, const omni::math::dimensional<T, 2>& end)
        {
            return omni::math::distance_between_2_points(start[0], start[1], end[0], end[1]);
        }

        template < typename T >
        inline double distance_between_2_points(const omni::math::dimensional<T, 3>& start, const omni::math::dimensional<T, 3>& end)
        {
            return omni::math::distance_between_2_points(start[0], start[1], start[2], end[0], end[1], end[2]);
        }

        template < typename T >
        inline double lerp_y(T x1, T y1, T x2, T y2, T x)
        {
            return ((omni::math::delta(x, x1) * omni::math::delta(y2, y1) / omni::math::delta(x2, x1)) + y1);
        }

        template < typename T >
        inline double liner_interpolation_y(T x1, T y1, T x2, T y2, T x)
        {
            return omni::math::lerp_y<T>(x1, y1, x2, y2, x);
        }

        template < typename T >
        inline double lerp_y(const omni::math::dimensional<T, 2>& start, const omni::math::dimensional<T, 2>& end, T x)
        {
            return omni::math::lerp_y(start[0], start[1], end[0], end[1], x);
        }
        
        template < typename T >
        inline double liner_interpolation_y(const omni::math::dimensional<T, 2>& start, const omni::math::dimensional<T, 2>& end, T x)
        {
            return omni::math::lerp_y(start[0], start[1], end[0], end[1], x);
        }

        template < typename T >
        inline double lerp_x(T x1, T y1, T x2, T y2, T y)
        {
            return ((omni::math::delta(y, y1) * omni::math::delta(x2, x1) / omni::math::delta(y2, y1)) + x1);
        }

        template < typename T >
        inline double liner_interpolation_x(T x1, T y1, T x2, T y2, T y)
        {
            return omni::math::lerp_x<T>(x1, y1, x2, y2, y);
        }

        template < typename T >
        inline double lerp_x(const omni::math::dimensional<T, 2>& start, const omni::math::dimensional<T, 2>& end, T y)
        {
            return omni::math::lerp_x(start[0], start[1], end[0], end[1], y);
        }

        template < typename T >
        inline double liner_interpolation_x(const omni::math::dimensional<T, 2>& start, const omni::math::dimensional<T, 2>& end, T y)
        {
            return omni::math::lerp_x(start[0], start[1], end[0], end[1], y);
        }

        template < typename T >
        inline void midpoint(T start_x, T start_y, T end_x, T end_y, T& mid_x, T& mid_y)
        {
            mid_x = ((start_x + end_x) / 2);
            mid_y = ((start_y + end_y) / 2);
        }

        template < typename T >
        inline void midpoint3d(T start_x, T start_y, T start_z, T end_x, T end_y, T end_z, T& mid_x, T& mid_y, T& mid_z)
        {
            mid_x = ((start_x + end_x) / 2);
            mid_y = ((start_y + end_y) / 2);
            mid_z = ((start_z + end_z) / 2);
        }

        template < typename T >
        inline omni::math::dimensional<T, 2> midpoint(T start_x, T start_y, T end_x, T end_y)
        {
            omni::math::dimensional<T, 2> ret;
            omni::math::midpoint<T>(start_x, start_y, end_x, end_y, ret[0], ret[1]);
            return ret;
        }

        template < typename T >
        inline omni::math::dimensional<T, 2> midpoint(const omni::math::dimensional<T, 2>& start, const omni::math::dimensional<T, 2>& end)
        {
            omni::math::dimensional<T, 2> ret;
            omni::math::midpoint<T>(start[0], start[1], end[0], end[1], ret[0], ret[1]);
            return ret;
        }

        template < typename T >
        inline omni::math::dimensional<T, 3> midpoint3d(T start_x, T start_y, T start_z, T end_x, T end_y, T end_z)
        {
            omni::math::dimensional<T, 3> ret;
            omni::math::midpoint3d<T>(start_x, start_y, start_z, end_x, end_y, end_z, ret[0], ret[1], ret[2]);
            return ret;
        }

        template < typename T >
        inline omni::math::dimensional<T, 3> midpoint3d(const omni::math::dimensional<T, 3>& start, const omni::math::dimensional<T, 3>& end)
        {
            omni::math::dimensional<T, 3> ret;
            omni::math::midpoint3d<T>(start[0], start[1], start[2], end[0], end[1], end[2], ret[0], ret[1], ret[2]);
            return ret;
        }

        template < typename T >
        inline omni::math::ordinal_name octant(T x, T y, T z)
        {
            // x+ = 001000 = 8, x- = 000100 = 4
            // y+ = 000010 = 2, y- = 000001 = 1
            // z+ = 100000 = 32, z- = 010000 = 16
            switch (
                ((z > 0) ? (1<<5) : ((z < 0) ? (1<<4) : 0)) |
                ((x > 0) ? (1<<3) : ((x < 0) ? (1<<2) : 0)) |
                ((y > 0) ? (1<<1) : ((y < 0) ? 1 : 0))
            )
            {
                case 42: case 10: return omni::math::ordinal_name::I;     // +++ = 101010 = 42/10 = quad 1
                case 38: case 6: return omni::math::ordinal_name::II;    // -++ = 100110 = 38/6 = quad 2
                case 37: case 5: return omni::math::ordinal_name::III; // --+ = 100101 = 37/5 = quad 3
                case 41: case 9: return omni::math::ordinal_name::IV;    // +-+ = 101001 = 41/9 = quad 4
                case 26: return omni::math::ordinal_name::V;             // ++- = 011010 = 26 = quad 5
                case 22: return omni::math::ordinal_name::VI;             // -+- = 010110 = 22 = quad 6
                case 21: return omni::math::ordinal_name::VII;            // --- = 010101 = 21 = quad 7
                case 25: return omni::math::ordinal_name::VIII;         // +-- = 011001 = 25 = quad 8
                // x,0,z
                case 40: return omni::math::ordinal_name::I_IV;         // +0+ = 101000 = 40 = quads 1 & 4
                case 24: return omni::math::ordinal_name::V_VIII;         // +0- = 011000 = 24 = quads 5 & 8
                case 36: return omni::math::ordinal_name::II_III;         // -0+ = 100100 = 36 = quads 2 & 3
                case 20: return omni::math::ordinal_name::VI_VII;         // -0- = 010100 = 20 = quads 6 & 7
                // 0,y,z
                case 34: return omni::math::ordinal_name::I_II;         // 0++ = 100010 = 34 = quads 1 & 2
                case 18: return omni::math::ordinal_name::V_VI;         // 0+- = 010010 = 18 = quads 5 & 6
                case 33: return omni::math::ordinal_name::III_IV;         // 0-+ = 100001 = 33 = quads 3 & 4
                case 17: return omni::math::ordinal_name::VII_VIII;     // 0-- = 010001 = 17 = quads 7 & 8
                // 0,0,0
                case 8: case 4: return omni::math::ordinal_name::X_AXIS; // 001000/000100 = 8/4 = X
                case 2: case 1: return omni::math::ordinal_name::Y_AXIS; // 000010/000001 = 2/1 = Y
                case 32: case 16: return omni::math::ordinal_name::Z_AXIS;// 100000/010000 = 32/16 = Z
                default: break;
            }
            return omni::math::ordinal_name::ORIGIN;
        }

        template < typename T >
        inline omni::math::ordinal_name octant(const omni::math::dimensional<T, 3>& point)
        {
            return omni::math::octant<T>(point[0], point[1], point[2]);
        }

        template < typename T >
        inline void point_on_circle(T angle, T radius, T center_x, T center_y, T& out_x, T& out_y)
        {
            if (angle > static_cast<T>(360)) {
                OMNI_ERR_FW("angle cannot be greater than 360 degrees", omni::exceptions::overflow_error("angle cannot be greater than 360 degrees"))
            }
            out_x = OMNI_MATH_GET_POINT_X_FW(T, center_x, radius, angle);
            out_y = OMNI_MATH_GET_POINT_Y_FW(T, center_y, radius, angle);
        }

        template <> inline void point_on_circle<int64_t>(int64_t angle, int64_t radius, int64_t center_x, int64_t center_y, int64_t& out_x, int64_t& out_y) { OMNI_MATH_GET_POINT_INT_FW(int64_t, out_x, out_y, center_x, center_y, radius, angle); }
        template <> inline void point_on_circle<uint64_t>(uint64_t angle, uint64_t radius, uint64_t center_x, uint64_t center_y, uint64_t& out_x, uint64_t& out_y) { OMNI_MATH_GET_POINT_INT_FW(uint64_t, out_x, out_y, center_x, center_y, radius, angle); }
        template <> inline void point_on_circle<int32_t>(int32_t angle, int32_t radius, int32_t center_x, int32_t center_y, int32_t& out_x, int32_t& out_y) { OMNI_MATH_GET_POINT_INT_FW(int32_t, out_x, out_y, center_x, center_y, radius, angle); }
        template <> inline void point_on_circle<uint32_t>(uint32_t angle, uint32_t radius, uint32_t center_x, uint32_t center_y, uint32_t& out_x, uint32_t& out_y) { OMNI_MATH_GET_POINT_INT_FW(uint32_t, out_x, out_y, center_x, center_y, radius, angle); }
        template <> inline void point_on_circle<int16_t>(int16_t angle, int16_t radius, int16_t center_x, int16_t center_y, int16_t& out_x, int16_t& out_y) { OMNI_MATH_GET_POINT_INT_FW(int16_t, out_x, out_y, center_x, center_y, radius, angle); }
        template <> inline void point_on_circle<uint16_t>(uint16_t angle, uint16_t radius, uint16_t center_x, uint16_t center_y, uint16_t& out_x, uint16_t& out_y) { OMNI_MATH_GET_POINT_INT_FW(uint16_t, out_x, out_y, center_x, center_y, radius, angle); }
        template <> inline void point_on_circle<int8_t>(int8_t angle, int8_t radius, int8_t center_x, int8_t center_y, int8_t& out_x, int8_t& out_y) { out_x = OMNI_MATH_GET_POINT_X_INT_FW(int8_t, center_x, radius, angle); out_y = OMNI_MATH_GET_POINT_Y_INT_FW(int8_t, center_y, radius, angle); }
        template <> inline void point_on_circle<uint8_t>(uint8_t angle, uint8_t radius, uint8_t center_x, uint8_t center_y, uint8_t& out_x, uint8_t& out_y) { out_x = OMNI_MATH_GET_POINT_X_INT_FW(uint8_t, center_x, radius, angle); out_y = OMNI_MATH_GET_POINT_Y_INT_FW(uint8_t, center_y, radius, angle); }

        template < typename T >
        inline omni::math::ordinal_name quadrant(T x, T y)
        {
            // x+ = 1000 = 8, x- = 0100 = 4
            // y+ = 0010 = 2, y- = 0001 = 1
            switch (
                ((x > 0) ? (1<<3) : ((x < 0) ? (1<<2) : 0)) |
                ((y > 0) ? (1<<1) : ((y < 0) ? 1 : 0))
            )
            {
                case 10: return omni::math::ordinal_name::I; // ++ = 1010 = 10 = quad 1
                case 6: return omni::math::ordinal_name::II; // -+ = 0110 = 6 = quad 2
                case 5: return omni::math::ordinal_name::III; // -- = 0101 = 5 = quad 3
                case 9: return omni::math::ordinal_name::IV; // +- = 1001 = 9 = quad 4
                case 8: case 4: return omni::math::ordinal_name::X_AXIS; // 1000/0100 = 8/4 = X
                case 2: case 1: return omni::math::ordinal_name::Y_AXIS; // 0010/0001 = 2/1 = Y
                default: break;
            }
            return omni::math::ordinal_name::ORIGIN;
        }

        template < typename T >
        inline omni::math::ordinal_name quadrant(const omni::math::dimensional<T, 2>& point)
        {
            return omni::math::quadrant<T>(point[0], point[1]);
        }

        template < typename T >
        inline void quadratic(T a, T b, T c, T& x_plus, T& x_minus)
        {
            if (omni::math::are_equal(a, T(0))) {
                OMNI_ERR_FW("division by zero, a must not be 0", omni::exceptions::invalid_range("division by zero, a must not be 0"))
            }
            x_plus = ((-b) + std::sqrt(static_cast<long double>((b * b) - (4 * a * c)))) / (2 * a);
            x_minus = ((-b) - std::sqrt(static_cast<long double>((b * b) - (4 * a * c)))) / (2 * a);
        }

        template < typename T >
        inline omni::math::dimensional<T, 2> quadratic(T a, T b, T c)
        {
            omni::math::dimensional<T, 2> ret;
            omni::math::quadratic<T>(a, b, c, ret[0], ret[1]);
            return ret;
        }

        template < typename T >
        inline double slope(T start_x, T start_y, T end_x, T end_y)
        {
            if (omni::math::are_equal(start_x, end_x)) {
                OMNI_ERR_RETV_FW("division by zero, x values equal", omni::exceptions::invalid_range("division by zero, x values equal"), 0.0)
            }
            return static_cast<double>(end_y - start_y) / static_cast<double>(end_x - start_x);
        }

        template < typename T >
        inline double slope(const omni::math::dimensional<T, 2>& start, const omni::math::dimensional<T, 2>& end)
        {
            return omni::math::slope(start[0], start[1], end[0], end[1]);
        }

        template < typename T >
        inline T summation(T index, T end, const omni::delegate1<T, T>& sum)
        {
            T val;
            if (sum) {
                val = sum(index);
                for (T i = index+1; i <= end; ++i) {
                    val += sum(i);
                }
            } else {
                val = index;
                for (T i = index+1; i <= end; ++i) {
                    val += i;
                }
            }
            return val;
        }
    }
}

#endif // OMNI_MATH_HPP