File indexing completed on 2024-05-12 04:06:24

0001 /*
0002     SPDX-FileCopyrightText: 2011 Stefan Majewsky <majewsky@gmx.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef PALAPELI_ENGINE_MATHTRICKS_H
0008 #define PALAPELI_ENGINE_MATHTRICKS_H
0009 
0010 #include <QtMath>
0011 
0012 namespace Palapeli
0013 {
0014     template<typename T> struct fastnorm_helper { typedef T fp; };
0015     template<> struct fastnorm_helper<int> { typedef qreal fp; };
0016 
0017     //Approximates sqrt(x^2 + y^2) with a maximum error of 4%.
0018     //Speedup on my machine is 30% for unoptimized and up to 50% for optimized builds.
0019     template<typename T> inline T fastnorm(T x, T y)
0020     {
0021         //need absolute values for distance measurement
0022         x = qAbs<T>(x); y = qAbs<T>(y);
0023         //There are two simple approximations to sqrt(x^2 + y^2):
0024         //  max(x, y) -> good for x >> y or x << y          (square-shaped unit circle)
0025         //  1/sqrt(2) * (x + y) -> good for x = y (approx.) (diamond-shaped unit circle)
0026         //The worse approximation is always bigger. By taking the maximum of both,
0027         //we get an octagon-shaped upper approximation of the unit circle. The
0028         //approximation can be refined by a prefactor (called a) below.
0029         typedef typename fastnorm_helper<T>::fp fp;
0030         static const fp a = (1 + sqrt(4 - 2 * qSqrt(2))) / 2;
0031         static const fp b = qSqrt(0.5);
0032         const T metricOne = qMax<T>(x, y);
0033         const T metricTwo = b * (x + y);
0034         return a * qMax(metricOne, metricTwo);
0035         //idea for this function from http://www.azillionmonkeys.com/qed/sqroot.html
0036         //(though the equations there have some errors at the time of this writing)
0037     }
0038 
0039     static inline int fastnorm(const QPoint& p)
0040     {
0041         return fastnorm<int>(p.x(), p.y());
0042     }
0043     static inline qreal fastnorm(const QPointF& p)
0044     {
0045         return fastnorm<qreal>(p.x(), p.y());
0046     }
0047 
0048     //Approximates cos(angle * M_2PI / 256) with quadratic functions.
0049     static inline qreal hexcos(int angle)
0050     {
0051         // project angle into [0, 255]
0052         angle = angle & 0xff;
0053         // project angle into [-64, 63] (where negative angles counter-intuitively
0054         // represent negative results)
0055         if (angle >= 128)
0056             angle = 255 - angle;
0057         if (angle >= 64)
0058             angle = angle-128;
0059         //approximate cosine arcs with parabola
0060         const qreal result = 1 - qreal(angle * angle) / (64.0 * 64.0);
0061         return angle < 0 ? -result : result;
0062     }
0063 }
0064 
0065 #endif // PALAPELI_ENGINE_MATHTRICKS_H