File indexing completed on 2024-05-12 15:58:15
0001 /* 0002 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 * 0006 * adopted from here http://web.archive.org/web/20090728150504/http://www.snippetcenter.org/en/a-fast-atan2-function-s1868.aspx 0007 */ 0008 0009 #include "kis_fast_math.h" 0010 0011 #include <cmath> 0012 #include <cstdio> 0013 #include <cstdlib> 0014 #include <QtGlobal> 0015 #include <QGlobalStatic> 0016 0017 // Algorithm from http://web.archive.org/web/20090728150504/http://www.snippetcenter.org/en/a-fast-atan2-function-s1868.aspx 0018 const qreal MAX_SECOND_DERIV_IN_RANGE = 0.6495; 0019 0020 /// precision 0021 const qreal MAX_ERROR = 0.0001; 0022 0023 struct KisATanTable { 0024 0025 KisATanTable() { 0026 qreal nf = ::sqrt(MAX_SECOND_DERIV_IN_RANGE / (8 * MAX_ERROR)); 0027 NUM_ATAN_ENTRIES = int(nf) + 1; 0028 // Build table 0029 qreal y = 10.0; 0030 qreal x; 0031 ATanTable = new qreal[NUM_ATAN_ENTRIES + 1]; 0032 ATanTable[0] = 0.0; 0033 for (quint32 i = 1; i <= NUM_ATAN_ENTRIES; i++) { 0034 x = (y / i) * NUM_ATAN_ENTRIES; 0035 ATanTable[i] = (qreal)::atan2(y, x); 0036 } 0037 0038 } 0039 0040 ~KisATanTable() { 0041 delete [] ATanTable; 0042 } 0043 0044 quint32 NUM_ATAN_ENTRIES; 0045 qreal* ATanTable; 0046 }; 0047 0048 Q_GLOBAL_STATIC(KisATanTable, kisATanTable) 0049 0050 /// private functions 0051 0052 inline qreal interp(qreal r, qreal a, qreal b) 0053 { 0054 return r*(b - a) + a; 0055 } 0056 0057 inline qreal calcAngle(qreal x, qreal y) 0058 { 0059 static qreal af = kisATanTable->NUM_ATAN_ENTRIES; 0060 static int ai = kisATanTable->NUM_ATAN_ENTRIES; 0061 static qreal* ATanTable = kisATanTable->ATanTable; 0062 qreal di = (y / x) * af; 0063 int i = (int)(di); 0064 if (i >= ai) return ::atan2(y, x); 0065 return interp(di - i, ATanTable[i], ATanTable[i+1]); 0066 } 0067 0068 qreal KisFastMath::atan2(qreal y, qreal x) 0069 { 0070 0071 if (y == 0.0) { // the line is horizontal 0072 if (x >= 0.0) { // towards the right 0073 return(0.0);// the angle is 0 0074 } 0075 // toward the left 0076 return qreal(M_PI); 0077 } // we now know that y is not 0 check x 0078 if (x == 0.0) { // the line is vertical 0079 if (y > 0.0) { 0080 return M_PI_2; 0081 } 0082 return -M_PI_2; 0083 } 0084 // from here on we know that niether x nor y is 0 0085 if (x > 0.0) { 0086 // we are in quadrant 1 or 4 0087 if (y > 0.0) { 0088 // we are in quadrant 1 0089 // now figure out which side of the 45 degree line 0090 if (x > y) { 0091 return(calcAngle(x, y)); 0092 } 0093 return(M_PI_2 - calcAngle(y, x)); 0094 } 0095 // we are in quadrant 4 0096 y = -y; 0097 // now figure out which side of the 45 degree line 0098 if (x > y) { 0099 return(-calcAngle(x, y)); 0100 } 0101 return(-M_PI_2 + calcAngle(y, x)); 0102 } 0103 // we are in quadrant 2 or 3 0104 x = -x; 0105 // flip x so we can use it as a positive 0106 if (y > 0.0) { 0107 // we are in quadrant 2 0108 // now figure out which side of the 45 degree line 0109 if (x > y) { 0110 return(M_PI - calcAngle(x, y)); 0111 } return(M_PI_2 + calcAngle(y, x)); 0112 } 0113 // we are in quadrant 3 0114 y = -y; 0115 // flip y so we can use it as a positive 0116 // now figure out which side of the 45 degree line 0117 if (x > y) { 0118 return(-M_PI + calcAngle(x, y)); 0119 } return(-M_PI_2 - calcAngle(y, x)); 0120 }