BWAPI
|
00001 // Copyright (c) 1999 Utrecht University (The Netherlands), 00002 // ETH Zurich (Switzerland), Freie Universitaet Berlin (Germany), 00003 // INRIA Sophia-Antipolis (France), Martin-Luther-University Halle-Wittenberg 00004 // (Germany), Max-Planck-Institute Saarbruecken (Germany), RISC Linz (Austria), 00005 // and Tel-Aviv University (Israel). All rights reserved. 00006 // 00007 // This file is part of CGAL (www.cgal.org); you can redistribute it and/or 00008 // modify it under the terms of the GNU Lesser General Public License as 00009 // published by the Free Software Foundation; version 2.1 of the License. 00010 // See the file LICENSE.LGPL distributed with CGAL. 00011 // 00012 // Licensees holding a valid commercial license may use this file in 00013 // accordance with the commercial license agreement provided with the software. 00014 // 00015 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 // 00018 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Kernel_23/include/CGAL/rational_rotation.h $ 00019 // $Id: rational_rotation.h 35581 2006-12-17 22:28:35Z afabri $ 00020 // 00021 // 00022 // Author(s) : Stefan Schirra 00023 00024 00025 #ifndef CGAL_RATIONAL_ROTATION_H 00026 #define CGAL_RATIONAL_ROTATION_H 00027 00028 #include <algorithm> 00029 00030 CGAL_BEGIN_NAMESPACE 00031 00032 template < class NT > 00033 void 00034 rational_rotation_approximation( const NT & dirx, // dir.x() 00035 const NT & diry, // dir.y() 00036 NT & sin_num, // return 00037 NT & cos_num, // return 00038 NT & denom, // return 00039 const NT & eps_num, // quality_bound 00040 const NT & eps_den ) 00041 { 00042 00043 const NT& n = eps_num; 00044 const NT& d = eps_den; 00045 const NT NT0 = NT(0) ; 00046 const NT NT1 = NT(1) ; 00047 CGAL_kernel_precondition( (dirx != NT0) || (diry != NT0)); 00048 CGAL_kernel_precondition( n > NT0 ); 00049 CGAL_kernel_precondition( d > NT0 ); 00050 NT & sin = sin_num; 00051 NT & cos = cos_num; 00052 NT & den = denom; 00053 NT dx = CGAL_NTS abs(dirx); 00054 NT dy = CGAL_NTS abs(diry); 00055 NT sq_hypotenuse = dx*dx + dy*dy; 00056 NT common_part; 00057 NT diff_part; 00058 NT rhs; 00059 bool lower_ok; 00060 bool upper_ok; 00061 00062 if (dy > dx) 00063 { 00064 std::swap (dx,dy); 00065 } 00066 // approximate sin = dy / sqrt(sq_hypotenuse) 00067 // if ( dy / sqrt(sq_hypotenuse) < n/d ) 00068 if (dy * dy * d * d < sq_hypotenuse * n * n) 00069 { 00070 cos = NT1; 00071 sin = NT0; 00072 den = NT1; 00073 } 00074 else 00075 { 00076 NT p; 00077 NT q; 00078 NT p0 = NT0; 00079 NT q0 = NT1; 00080 NT p1 = NT1; 00081 NT q1 = NT1; 00082 00083 for(;;) 00084 { 00085 p = p0 + p1; 00086 q = q0 + q1; 00087 sin = NT(2)*p*q; 00088 den = p*p + q*q; 00089 00090 // sanity check for approximation 00091 // sin/den < dy/sqrt(hypotenuse) + n/d 00092 // && sin/den > dy/sqrt(hypotenuse) - n/d 00093 // === sin/den - n/d < dy/sqrt(sq_hypotenuse) 00094 // && sin/den + n/d > dy/sqrt(sq_hypotenuse) 00095 // === (sin^2 d^2 + n^2 den^2)sq_hypotenuse - 2... < dy^2 d^2 den^2 00096 // && (sin^2 d^2 + n^2 den^2)sq_hypotenuse + 2... > dy^2 d^2 den^2 00097 00098 common_part = (sin*sin*d*d + n*n*den*den)*sq_hypotenuse; 00099 diff_part = NT(2)*n*sin*d*den*sq_hypotenuse; 00100 rhs = dy*dy*d*d*den*den; 00101 00102 upper_ok = (common_part - diff_part < rhs); 00103 lower_ok = (common_part + diff_part > rhs); 00104 00105 if ( lower_ok && upper_ok ) 00106 { 00107 // if ( (p*p)%2 + (q*q)%2 > NT1) 00108 // { 00109 // sin = p*q; 00110 // cos = (q*q - p*p)/2; // exact division 00111 // den = (p*p + q*q)/2; // exact division 00112 // } 00113 // else 00114 // { 00115 cos = q*q - p*p; 00116 // } 00117 00118 break; 00119 } 00120 else 00121 { 00122 // if ( dy/sqrt(sq_hypotenuse) < sin/den ) 00123 if ( dy*dy*den*den < sin*sin*sq_hypotenuse ) 00124 { 00125 p1 = p; 00126 q1 = q; 00127 } 00128 else 00129 { 00130 p0 = p; 00131 q0 = q; 00132 } 00133 } 00134 } // for(;;) 00135 } 00136 dx = dirx; 00137 dy = diry; 00138 00139 if (CGAL_NTS abs(dy) > CGAL_NTS abs(dx) ) { std::swap (sin,cos); } 00140 00141 if (dx < NT0) { cos = - cos; } 00142 00143 if (dy < NT0) { sin = - sin; } 00144 00145 sin_num = sin; 00146 cos_num = cos; 00147 denom = den; 00148 } 00149 00150 00151 template < class NT > 00152 void 00153 rational_rotation_approximation( const double& angle, 00154 NT & sin_num, // return 00155 NT & cos_num, // return 00156 NT & denom, // return 00157 const NT & eps_num, // quality_bound 00158 const NT & eps_den ) 00159 { 00160 00161 const NT& n = eps_num; 00162 const NT& d = eps_den; 00163 const NT NT0 = NT(0) ; 00164 const NT NT1 = NT(1) ; 00165 CGAL_kernel_precondition( n > NT0 ); 00166 CGAL_kernel_precondition( d > NT0 ); 00167 NT& isin = sin_num; 00168 NT& icos = cos_num; 00169 NT& iden = denom; 00170 double dsin = std::sin(angle); 00171 double dcos = std::cos(angle); 00172 double dn = CGAL::to_double(n); 00173 double dd = CGAL::to_double(d); 00174 double eps = dn / dd; 00175 dsin = CGAL_NTS abs( dsin); 00176 dcos = CGAL_NTS abs( dcos); 00177 NT common_part; 00178 NT diff_part; 00179 NT os; 00180 bool lower_ok; 00181 bool upper_ok; 00182 bool swapped = false; 00183 00184 if (dsin > dcos) 00185 { 00186 swapped = true; 00187 std::swap (dsin,dcos); 00188 } 00189 if ( dsin < eps ) 00190 { 00191 icos = NT1; 00192 isin = NT0; 00193 iden = NT1; 00194 } 00195 else 00196 { 00197 NT p; 00198 NT q; 00199 NT p0 = NT0; 00200 NT q0 = NT1; 00201 NT p1 = NT1; 00202 NT q1 = NT1; 00203 00204 for(;;) 00205 { 00206 p = p0 + p1; 00207 q = q0 + q1; 00208 isin = NT(2)*p*q; 00209 iden = p*p + q*q; 00210 00211 // XXX sanity check for approximation 00212 // sin/den < dsin + n/d 00213 // && sin/den > dsin - n/d 00214 // sin < dsin * den + n/d * den 00215 // && sin > dsin * den - n/d * den 00216 os = CGAL::to_double(isin); 00217 diff_part = eps * CGAL::to_double(iden); 00218 common_part = dsin * CGAL::to_double(iden); 00219 00220 upper_ok = (common_part - diff_part < os); 00221 lower_ok = (os < common_part + diff_part); 00222 00223 if ( lower_ok && upper_ok ) 00224 { 00225 // if ( (p*p)%2 + (q*q)%2 > NT1) 00226 // { 00227 // isin = p*q; 00228 // icos = (q*q - p*p)/2; // exact division 00229 // iden = (p*p + q*q)/2; // exact division 00230 // } 00231 // else 00232 // { 00233 icos = q*q - p*p; 00234 // } 00235 00236 break; 00237 } 00238 else 00239 { 00240 // XXX if ( dsin < sin/den ) 00241 if ( dsin * CGAL::to_double(iden) < CGAL::to_double(isin) ) 00242 { 00243 p1 = p; 00244 q1 = q; 00245 } 00246 else 00247 { 00248 p0 = p; 00249 q0 = q; 00250 } 00251 } 00252 } // for(;;) 00253 } 00254 00255 if ( swapped ) { std::swap (isin,icos); } 00256 00257 dsin = std::sin( angle); 00258 dcos = std::cos( angle); 00259 if (dcos < 0.0) { icos = - icos; } 00260 if (dsin < 0.0) { isin = - isin; } 00261 00262 sin_num = isin; 00263 cos_num = icos; 00264 denom = iden; 00265 } 00266 00267 CGAL_END_NAMESPACE 00268 00269 #endif // CGAL_RATIONAL_ROTATION_H