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