1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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
#include<stdio.h> #include<math.h> //////////////////////////////////////////////////////////////////////////////////////////////// //Computes area of circle centered at (xb,yb) with radius rb which lies outside the circle centered at //(xa,ya) with radius ra. // You have to initialize pi with acos(-1.0). //////////////////////////////////////////////////////////////////////////////////////////////// double pi; #define EPS 1E-6 #define EQU(xa,xb) (((xb)-(xa)) <EPS && ((xa)-(xb)) <EPS) #define abs(x) x>0 ? (x):-(x); double outAr(double xa,double ya,double ra,double xb,double yb,double rb) { if(!((xb-xa) <EPS && (xa-xb) <EPS)) { double da,d; double a,b,c; double ld1,ld2,ld; bool c1=false,c3=false; a=2*(xb-xa); b=2*(yb-ya); c=ra*ra-rb*rb-xa*xa+xb*xb-ya*ya+yb*yb; ld1=a*xa+b*ya-c; ld1/=sqrt(a*a+b*b); ld1=abs(ld1); ld2=a*xb+b*yb-c; ld2/=sqrt(a*a+b*b); ld2=abs(ld2); b/=a; b=-b; c/=a; double b2,c2; double res,res1,res2; //a2=b*b-1; b2=2*(b*(c-xa)-ya); b2/=b*b+1; c2=(c-xa)*(c-xa)-ra*ra+ya*ya; c2/=b*b+1; d=b2*b2-4*c2; da=(xa-xb)*(xa-xb)+(ya-yb)*(ya-yb); ld=sqrt(da); if(EQU(ld,ld1+ld2)) c1=true; else if(EQU(ld,ld1-ld2)) c3=true; /* if(da>=ra*ra && da>=rb*rb) c1=true; else if(da>=ra*ra) c2=true;*/ if(d<=0 && da<(rb*rb) && rb > ra) { res=pi*rb*rb; res-=pi*ra*ra; return res; } else if(d<=0 && da<(ra*ra)) { return 0.0; } else if(d<=0) { res=pi*rb*rb; return res; } else if(c1) { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=asin(d/ra); theta2=asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } else if(!c3) { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=pi-asin(d/ra); theta2=asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } else { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=asin(d/ra); theta2=pi-asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } } else if(!((yb-ya) <EPS && (ya-yb) <EPS)) { double t1=xa; xa=ya; ya=t1; t1=xb; xb=yb; yb=t1; double da,d; double a,b,c; double ld1,ld2,ld; bool c1=false,c3=false; a=2*(xb-xa); b=2*(yb-ya); c=ra*ra-rb*rb-xa*xa+xb*xb-ya*ya+yb*yb; ld1=a*xa+b*ya-c; ld1/=sqrt(a*a+b*b); ld1=abs(ld1); ld2=a*xb+b*yb-c; ld2/=sqrt(a*a+b*b); ld2=abs(ld2); b/=a; b=-b; c/=a; double b2,c2; double res,res1,res2; //a2=b*b-1; b2=2*(b*(c-xa)-ya); b2/=b*b+1; c2=(c-xa)*(c-xa)-ra*ra+ya*ya; c2/=b*b+1; d=b2*b2-4*c2; da=(xa-xb)*(xa-xb)+(ya-yb)*(ya-yb); ld=sqrt(da); if(EQU(ld,ld1+ld2)) c1=true; else if(EQU(ld,ld1-ld2)) c3=true; /* if(da>=ra*ra && da>=rb*rb) c1=true; else if(da>=ra*ra) c2=true;*/ if(d<=0 && da<(rb*rb) && rb > ra) { res=pi*rb*rb; res-=pi*ra*ra; return res; } else if(d<=0 && da<(ra*ra)) { return 0.0; } else if(d<=0) { res=pi*rb*rb; return res; } else if(c1) { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=asin(d/ra); theta2=asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } else if(!c3) { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=pi-asin(d/ra); theta2=asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } else { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=asin(d/ra); theta2=pi-asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } } if(ra>rb) return 0.0; double res=pi*(ra+rb)*(rb-ra); return res; }
Refactorings
No refactoring yet !
Yaverot
November 6, 2007, November 06, 2007 15:55, permalink
It is not a complete refactoring, but you didn't include your unit tests for me to verify against. I've changed preprocessor use to language constructs. I've consolidated the last three elses of your if/else ladder, into a tiny if-if/else in the middle of that else's processing, the same could be done higher up, but without tests I'm afraid I'd break your if/else ladder. I've added const correctness, since a const is normally worth 10 unit tests. This method is still long, changing some variables to meaningful names & extracting methods would help with readability immensely.
I'm not familiar enough with the math to find your accuracy problem, maybe you need long doubles for the resolution you want.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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
//#include<stdio.h> #include<math.h> template<class T> inline T abs(const T x) { return (x<0 ? -x : x); } //////////////////////////////////////////////////////////////////////////////////////////////// //Computes area of circle centered at (xb,yb) with radius rb which lies outside the // circle centered at (xa,ya) with radius ra. // You have to initialize pi with acos(-1.0). //////////////////////////////////////////////////////////////////////////////////////////////// const double pi = M_PI; // gcc constant defined in math.h to riduclase number of places const double EPS = 1E-6; inline bool EQU (const double Left,const double Right) { return (abs(Left-Right) < EPS); } double outAr(double xa,double ya,double ra,double xb,double yb,double rb) { if( !(EQU(xa,xb)) ) { double da,d; double a,b,c; double ld1,ld2,ld; bool c1=false,c3=false; a=2*(xb-xa); b=2*(yb-ya); c=ra*ra-rb*rb-xa*xa+xb*xb-ya*ya+yb*yb; ld1=a*xa+b*ya-c; ld1/=sqrt(a*a+b*b); ld1=abs(ld1); ld2=a*xb+b*yb-c; ld2/=sqrt(a*a+b*b); ld2=abs(ld2); b/=a; b=-b; c/=a; double b2,c2; double res,res1,res2; //a2=b*b-1; b2=2*(b*(c-xa)-ya); b2/=b*b+1; c2=(c-xa)*(c-xa)-ra*ra+ya*ya; c2/=b*b+1; d=b2*b2-4*c2; da=(xa-xb)*(xa-xb)+(ya-yb)*(ya-yb); ld=sqrt(da); if(EQU(ld,ld1+ld2)) c1=true; else if(EQU(ld,ld1-ld2)) c3=true; /* if(da>=ra*ra && da>=rb*rb) c1=true; else if(da>=ra*ra) c2=true;*/ if(d<=0 && da<(rb*rb) && rb > ra) { res=pi*rb*rb; res-=pi*ra*ra; return res; } else if(d<=0 && da<(ra*ra)) { return 0.0; } else if(d<=0) { res=pi*rb*rb; return res; } else if(c1) { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=asin(d/ra); theta2=asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } else if(!c3) { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=pi-asin(d/ra); theta2=asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } else { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1,theta2; theta1=asin(d/ra); theta2=pi-asin(d/rb); double p,q,r,s; p=theta1*ra*ra; q=theta2*rb*rb; r=ra*ra*sin(2.0*theta1)/2.0; s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } } else if( !(EQU(ya,yb))) { double t1=xa; xa=ya; ya=t1; t1=xb; xb=yb; yb=t1; double da,d; double a,b,c; double ld1,ld2,ld; bool c1=false,c3=false; a=2*(xb-xa); b=2*(yb-ya); c=ra*ra-rb*rb-xa*xa+xb*xb-ya*ya+yb*yb; ld1=a*xa+b*ya-c; ld1/=sqrt(a*a+b*b); ld1=abs(ld1); ld2=a*xb+b*yb-c; ld2/=sqrt(a*a+b*b); ld2=abs(ld2); b/=a; b=-b; c/=a; double b2,c2; double res,res1,res2; //a2=b*b-1; b2=2*(b*(c-xa)-ya); b2/=b*b+1; c2=(c-xa)*(c-xa)-ra*ra+ya*ya; c2/=b*b+1; d=b2*b2-4*c2; da=(xa-xb)*(xa-xb)+(ya-yb)*(ya-yb); ld=sqrt(da); if(EQU(ld,ld1+ld2)) c1=true; else if(EQU(ld,ld1-ld2)) c3=true; /* if(da>=ra*ra && da>=rb*rb) c1=true; else if(da>=ra*ra) c2=true;*/ if(d<=0 && da<(rb*rb) && rb > ra) { res=pi*rb*rb; res-=pi*ra*ra; return res; } else if(d<=0 && da<(ra*ra)) { return 0.0; } else if(d<=0) { res=pi*rb*rb; return res; } else { d=sqrt(d)*(sqrt(b*b+1)); d/=2; double theta1=asin(d/ra); double theta2=asin(d/rb); if (!c1) { if(c3) { theta2=pi-theta2; } else { theta1=pi-theta1; } } double p=theta1*ra*ra; double q=theta2*rb*rb; double r=ra*ra*sin(2.0*theta1)/2.0; double s=rb*rb*sin(2.0*theta2)/2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; } } if(ra>rb) return 0.0; double res=pi*(ra+rb)*(rb-ra); return res; }
tanaeem
November 6, 2007, November 06, 2007 16:43, permalink
After searching internet I have found a better way to solve the problem.
And thanks Yaverot for your refactoring.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
// // Author: tanaeem // // Created on November 5, 2007, 10:57 PM // #include<stdio.h> #include<assert.h> #include<math.h> long double pi; #define EPS (long double) 1E-9 #define EQU(xa, xb) (((xb)-(xa)) <EPS && ((xa)-(xb)) <EPS) #define abs(x) x>0 ? (x):-(x); /** *Computes area of circle centered at (xb,yb) with radius rb which lies outside the circle centered at *(xa,ya) with radius ra. *You have to initialize pi with acos((long double)-1.0). *You may change all long double to double which would be 2X faster but the EPS should be changed to 1E-5 */ long double outAr(long double xa, long double ya, long double ra, long double xb, long double yb, long double rb) { if(EQU(ra, (long double) 0.0)) { return pi*rb*rb; } if(EQU(rb, (long double) 0.0)) return (long double) 0.0; long double dab, res; dab=sqrt((xa-xb)*(xa-xb)+(ya-yb)*(ya-yb)); if(dab>(ra+rb)) { res=pi*rb*rb; return res; } if(dab<(rb-ra)) { res=pi*rb*rb; res-=pi*ra*ra; return res; } if(dab<(ra-rb)) { return (long double) 0.0; } long double temp; temp=ra*ra+dab*dab-rb*rb; temp/=2*ra*dab; long double thetaa, thetab; thetaa=acos(temp); temp=rb*rb+dab*dab-ra*ra; temp/=2*rb*dab; thetab=acos(temp); long double p, q, r, s, res1, res2; p=thetaa*ra*ra; q=thetab*rb*rb; r=ra*ra*sin((long double)2.0*thetaa)/(long double)2.0; s=rb*rb*sin((long double)2.0*thetab)/(long double)2.0; res2=p+q-r-s; res1=pi*rb*rb; return res1-res2; }
It has some problem with precision ( large epsilon)