/* Steven Andrews, 2/17/06 Simple routines for 1D, 2D, and 3D geometry See documentation called Geometry_doc.doc and Geometry_doc.pdf */ /* Copyright 2003 by Steven Andrews. Permission is granted for non-commercial use of and modifications to the code. */ #include #include #include "Geometry.h" #include "math2.h" /***************** ... Normal **************/ double Geo_LineNormal(double *pt1,double *pt2,double *ans) { double dx,dy,len; dx=pt2[0]-pt1[0]; dy=pt2[1]-pt1[1]; len=sqrt(dx*dx+dy*dy); if(len>0) { ans[0]=dy/len; ans[1]=-dx/len; } else { ans[0]=1; ans[1]=0; } return len; } double Geo_LineNormal3D(double *pt1,double *pt2,double *point,double *ans) { double dot,line[3]; line[0]=pt2[0]-pt1[0]; line[1]=pt2[1]-pt1[1]; line[2]=pt2[2]-pt1[2]; dot=line[0]*line[0]+line[1]*line[1]+line[2]*line[2]; if(dot==0) { // pt1 == pt2 ans[0]=point[0]-pt1[0]; ans[1]=point[1]-pt1[1]; ans[2]=point[2]-pt1[2]; dot=ans[0]*ans[0]+ans[1]*ans[1]+ans[2]*ans[2]; if(dot==0) { // pt1 == pt2 and point == pt1 so return unit x ans[0]=1; ans[1]=0; ans[2]=0; return 0; } dot=sqrt(dot); // pt1 == pt2 so return normalized point ans[0]/=dot; ans[1]/=dot; ans[2]/=dot; return dot; } dot=sqrt(dot); line[0]/=dot; line[1]/=dot; line[2]/=dot; ans[0]=point[0]-pt1[0]; ans[1]=point[1]-pt1[1]; ans[2]=point[2]-pt1[2]; dot=ans[0]*line[0]+ans[1]*line[1]+ans[2]*line[2]; ans[0]-=dot*line[0]; ans[1]-=dot*line[1]; ans[2]-=dot*line[2]; dot=ans[0]*line[0]+ans[1]*line[1]+ans[2]*line[2]; ans[0]-=dot*line[0]; ans[1]-=dot*line[1]; ans[2]-=dot*line[2]; dot=ans[0]*ans[0]+ans[1]*ans[1]+ans[2]*ans[2]; if(dot==0) { // point is on line if(line[0]==0&&line[1]==0) { // line parallel to z so return unit x ans[0]=1; ans[1]=0; ans[2]=0; return 0; } ans[0]=line[1]; // return right side perpendicular in x,y plane ans[1]=-line[0]; ans[2]=0; dot=sqrt(ans[0]*ans[0]+ans[1]*ans[1]+ans[2]*ans[2]); ans[0]/=dot; ans[1]/=dot; ans[2]/=dot; return 0; } dot=sqrt(dot); ans[0]/=dot; ans[1]/=dot; ans[2]/=dot; return dot; } double Geo_TriNormal(double *pt1,double *pt2,double *pt3,double *ans) { double dx1,dy1,dz1,dx2,dy2,dz2,area; dx1=pt2[0]-pt1[0]; dy1=pt2[1]-pt1[1]; dz1=pt2[2]-pt1[2]; dx2=pt3[0]-pt2[0]; dy2=pt3[1]-pt2[1]; dz2=pt3[2]-pt2[2]; ans[0]=dy1*dz2-dz1*dy2; // v1 cross v2 ans[1]=-dx1*dz2+dz1*dx2; ans[2]=dx1*dy2-dy1*dx2; area=sqrt(ans[0]*ans[0]+ans[1]*ans[1]+ans[2]*ans[2]); if(area>0) { ans[0]/=area; ans[1]/=area; ans[2]/=area; } else { Geo_LineNormal(pt1,pt2,ans); ans[2]=0; } return area/2; } /********* Point In ... ***********/ int Geo_PtInTriangle(double *pt1,double *pt2,double *pt3,double *norm,double *test) { double dx1,dy1,dz1,dx2,dy2,dz2,crss[3],dot; dx1=pt2[0]-pt1[0]; dy1=pt2[1]-pt1[1]; dz1=pt2[2]-pt1[2]; dx2=test[0]-pt2[0]; dy2=test[1]-pt2[1]; dz2=test[2]-pt2[2]; crss[0]=dy1*dz2-dz1*dy2; crss[1]=-dx1*dz2+dz1*dx2; crss[2]=dx1*dy2-dy1*dx2; dot=crss[0]*norm[0]+crss[1]*norm[1]+crss[2]*norm[2]; if(dot<0) return 0; dx1=pt3[0]-pt2[0]; dy1=pt3[1]-pt2[1]; dz1=pt3[2]-pt2[2]; dx2=test[0]-pt3[0]; dy2=test[1]-pt3[1]; dz2=test[2]-pt3[2]; crss[0]=dy1*dz2-dz1*dy2; crss[1]=-dx1*dz2+dz1*dx2; crss[2]=dx1*dy2-dy1*dx2; dot=crss[0]*norm[0]+crss[1]*norm[1]+crss[2]*norm[2]; if(dot<0) return 0; dx1=pt1[0]-pt3[0]; dy1=pt1[1]-pt3[1]; dz1=pt1[2]-pt3[2]; dx2=test[0]-pt1[0]; dy2=test[1]-pt1[1]; dz2=test[2]-pt1[2]; crss[0]=dy1*dz2-dz1*dy2; crss[1]=-dx1*dz2+dz1*dx2; crss[2]=dx1*dy2-dy1*dx2; dot=crss[0]*norm[0]+crss[1]*norm[1]+crss[2]*norm[2]; if(dot<0) return 0; return 1; } int Geo_PtInSlab(double *pt1,double *pt2,double *test,int dim) { double dot; int d; dot=0; for(d=0;drad*rad?0:1; } /*************** To Rect ****************/ void Geo_Semic2Rect(double *cent,double rad,double *outvect,double *r1,double *r2,double *r3) { r1[0]=cent[0]+rad*outvect[1]; r1[1]=cent[1]-rad*outvect[0]; r2[0]=cent[0]-rad*outvect[1]; r2[1]=cent[1]+rad*outvect[0]; r3[0]=cent[0]+rad*outvect[1]-rad*outvect[0]; r3[1]=cent[1]-rad*outvect[0]-rad*outvect[1]; return; } void Geo_Hemis2Rect(double *cent,double rad,double *outvect,double *r1,double *r2,double *r3,double *r4) { double v1[3],v2[3]; v2[0]=v2[1]=v2[2]=0; Geo_LineNormal3D(v2,outvect,v2,v1); v2[0]=v1[1]*outvect[2]-v1[2]*outvect[1]; // v2 = v1 x outvect v2[1]=v1[2]*outvect[0]-v1[0]*outvect[2]; v2[2]=v1[0]*outvect[1]-v1[1]*outvect[0]; r1[0]=cent[0]+rad*(-v1[0]-v2[0]); r1[1]=cent[1]+rad*(-v1[1]-v2[1]); r1[2]=cent[2]+rad*(-v1[2]-v2[2]); r2[0]=cent[0]+rad*(+v1[0]-v2[0]); r2[1]=cent[1]+rad*(+v1[1]-v2[1]); r2[2]=cent[2]+rad*(+v1[2]-v2[2]); r3[0]=cent[0]+rad*(-v1[0]+v2[0]); r3[1]=cent[1]+rad*(-v1[1]+v2[1]); r3[2]=cent[2]+rad*(-v1[2]+v2[2]); r4[0]=cent[0]+rad*(-v1[0]-v2[0]-outvect[0]); r4[1]=cent[1]+rad*(-v1[1]-v2[1]-outvect[1]); r4[2]=cent[2]+rad*(-v1[2]-v2[2]-outvect[2]); return; } void Geo_Cyl2Rect(double *pt1,double *pt2,double rad,double *r1,double *r2,double *r3,double *r4) { double v1[3],v2[3]; Geo_LineNormal3D(pt1,pt2,pt1,v1); v2[0]=v1[1]*(pt2[2]-pt1[2])-v1[2]*(pt2[1]-pt1[1]); // v2 = v1 x (pt2 - pt1) v2[1]=v1[2]*(pt2[0]-pt1[0])-v1[0]*(pt2[2]-pt1[2]); v2[2]=v1[0]*(pt2[1]-pt1[1])-v1[1]*(pt2[0]-pt1[0]); r1[0]=pt1[0]+rad*(-v1[0]-v2[0]); r1[1]=pt1[1]+rad*(-v1[1]-v2[1]); r1[2]=pt1[2]+rad*(-v1[2]-v2[2]); r2[0]=pt1[0]+rad*(+v1[0]-v2[0]); r2[1]=pt1[1]+rad*(+v1[1]-v2[1]); r2[2]=pt1[2]+rad*(+v1[2]-v2[2]); r3[0]=pt1[0]+rad*(-v1[0]+v2[0]); r3[1]=pt1[1]+rad*(-v1[1]+v2[1]); r3[2]=pt1[2]+rad*(-v1[2]+v2[2]); r4[0]=pt2[0]+rad*(-v1[0]-v2[0]); r4[1]=pt2[1]+rad*(-v1[1]-v2[1]); r4[2]=pt2[2]+rad*(-v1[2]-v2[2]); return; } /**************** ...X... ***************/ double Geo_LineXLine(double *l1p1,double *l1p2,double *l2p1,double *l2p2,double *crss2ptr) { double rxcx,rycy,sxrx,syry,dxcx,dycy,cross; rxcx=l2p1[0]-l1p1[0]; // rx-cx rycy=l2p1[1]-l1p1[1]; // ry-cy sxrx=l2p2[0]-l2p1[0]; // sx-rx syry=l2p2[1]-l2p1[1]; // sy-ry dxcx=l1p2[0]-l1p1[0]; // dx-cx dycy=l1p2[1]-l1p1[1]; // dy-cy cross=(rxcx*syry-rycy*sxrx)/(dxcx*syry-dycy*sxrx); if(crss2ptr) *crss2ptr=(rxcx*dycy-rycy*dxcx)/(dxcx*syry-dycy*sxrx); return cross; } double Geo_LineXSphs(double *pt1,double *pt2,double *cent,double rad,int dim,double *crss2ptr) { double a,b,c,cross,cross2; int d; a=b=c=0; for(d=0;d=0&&cross<=1) { if(crss2ptr) *crss2ptr=cross2; return cross; } if(cross2>=0&&cross2<=1) { if(crss2ptr) *crss2ptr=cross; return cross2; } if(crss2ptr) *crss2ptr=cross2; return cross; } double Geo_LineXCyl2s(double *pt1,double *pt2,double *cp1,double *cp2,double *norm,double rad,double *crss2ptr) { double edge0[2],edge1[2],crossl,crossr; edge0[0]=cp1[0]+norm[0]*rad; edge0[1]=cp1[1]+norm[1]*rad; edge1[0]=cp2[0]+norm[0]*rad; edge1[1]=cp2[1]+norm[1]*rad; crossr=Geo_LineXLine(pt1,pt2,edge0,edge1,NULL); edge0[0]=cp1[0]-norm[0]*rad; edge0[1]=cp1[1]-norm[1]*rad; edge1[0]=cp2[0]-norm[0]*rad; edge1[1]=cp2[1]-norm[1]*rad; crossl=Geo_LineXLine(pt1,pt2,edge0,edge1,NULL); if(0<=crossr&&crossr<=1&&(crossrbpt2[0]&&pt2[0]>bpt2[0]) return 0; if(pt1[1]bpt2[1]&&pt2[1]>bpt2[1]) return 0; cmp=norm[0]*pt1[0]+norm[1]*pt1[1]; b1=norm[0]*bpt1[0]+norm[1]*bpt1[1]; b2=norm[0]*bpt1[0]+norm[1]*bpt2[1]; b3=norm[0]*bpt2[0]+norm[1]*bpt1[1]; b4=norm[0]*bpt2[0]+norm[1]*bpt2[1]; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp) return 0; return 1; } int Geo_TriXaabb3(double *pt1,double *pt2,double *pt3,double *norm,double *bpt1,double *bpt2) { double cmp,b1,b2,b3,b4,b5,b6,b7,b8; if(pt1[0]bpt2[0]&&pt2[0]>bpt2[0]&&pt3[0]>bpt2[0]) return 0; if(pt1[1]bpt2[1]&&pt2[1]>bpt2[1]&&pt3[1]>bpt2[1]) return 0; if(pt1[2]bpt2[2]&&pt2[2]>bpt2[2]&&pt3[2]>bpt2[2]) return 0; cmp=norm[0]*pt1[0]+norm[1]*pt1[1]+norm[2]*pt1[2]; b1=norm[0]*bpt1[0]+norm[1]*bpt1[1]+norm[2]*bpt1[2]; b2=norm[0]*bpt1[0]+norm[1]*bpt1[1]+norm[2]*bpt2[2]; b3=norm[0]*bpt1[0]+norm[1]*bpt2[1]+norm[2]*bpt1[2]; b4=norm[0]*bpt1[0]+norm[1]*bpt2[1]+norm[2]*bpt2[2]; b5=norm[0]*bpt2[0]+norm[1]*bpt1[1]+norm[2]*bpt1[2]; b6=norm[0]*bpt2[0]+norm[1]*bpt1[1]+norm[2]*bpt2[2]; b7=norm[0]*bpt2[0]+norm[1]*bpt2[1]+norm[2]*bpt1[2]; b8=norm[0]*bpt2[0]+norm[1]*bpt2[1]+norm[2]*bpt2[2]; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp&&b5>cmp&&b6>cmp&&b7>cmp&&b8>cmp) return 0; return 1; } int Geo_RectXaabb2(double *r1,double *r2,double *r3,double *bpt1,double *bpt2) { double v1[2],cmp,b1,b2,b3,b4; v1[0]=r2[0]+r3[0]-r1[0]; // point 4 v1[1]=r2[1]+r3[1]-r1[1]; if(r1[0]bpt2[0]&&r2[0]>bpt2[0]&&r3[0]>bpt2[0]&&v1[0]>bpt2[0]) return 0; if(r1[1]bpt2[1]&&r2[1]>bpt2[1]&&r3[1]>bpt2[1]&&v1[1]>bpt2[1]) return 0; v1[0]=r2[0]-r1[0]; // side 1,2 v1[1]=r2[1]-r1[1]; cmp=v1[0]*r1[0]+v1[1]*r1[1]; b1=v1[0]*bpt1[0]+v1[1]*bpt1[1]; b2=v1[0]*bpt1[0]+v1[1]*bpt2[1]; b3=v1[0]*bpt2[0]+v1[1]*bpt1[1]; b4=v1[0]*bpt2[0]+v1[1]*bpt2[1]; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp) return 0; v1[0]=r3[0]-r1[0]; // side 2,3 v1[1]=r3[1]-r1[1]; cmp=v1[0]*r1[0]+v1[1]*r1[1]; b1=v1[0]*bpt1[0]+v1[1]*bpt1[1]; b2=v1[0]*bpt1[0]+v1[1]*bpt2[1]; b3=v1[0]*bpt2[0]+v1[1]*bpt1[1]; b4=v1[0]*bpt2[0]+v1[1]*bpt2[1]; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp) return 0; return 1; } int Geo_RectXaabb3(double *r1,double *r2,double *r3,double *r4,double *bpt1,double *bpt2) { double r5[3],r6[3],r7[3],r8[3],v1[3],b1,b2,b3,b4,b5,b6,b7,b8,cmp; r5[0]=r2[0]+r4[0]-r1[0]; r5[1]=r2[1]+r4[1]-r1[1]; r5[2]=r2[2]+r4[2]-r1[2]; r6[0]=r3[0]+r4[0]-r1[0]; r6[1]=r3[1]+r4[1]-r1[1]; r6[2]=r3[2]+r4[2]-r1[2]; r7[0]=r2[0]+r3[0]-r1[0]; r7[1]=r2[1]+r3[1]-r1[1]; r7[2]=r2[2]+r3[2]-r1[2]; r8[0]=r7[0]+r4[0]-r1[0]; r8[1]=r7[1]+r4[1]-r1[1]; r8[2]=r7[2]+r4[2]-r1[2]; if(r1[0]bpt2[0]&&r2[0]>bpt2[0]&&r3[0]>bpt2[0]&&r4[0]>bpt2[0]&&r5[0]>bpt2[0]&&r6[0]>bpt2[0]&&r7[0]>bpt2[0]) return 0; if(r1[1]bpt2[1]&&r2[1]>bpt2[1]&&r3[1]>bpt2[1]&&r4[1]>bpt2[1]&&r5[1]>bpt2[1]&&r6[1]>bpt2[1]&&r7[1]>bpt2[1]) return 0; if(r1[2]bpt2[2]&&r2[2]>bpt2[2]&&r3[2]>bpt2[2]&&r4[2]>bpt2[2]&&r5[2]>bpt2[2]&&r6[2]>bpt2[2]&&r7[2]>bpt2[2]) return 0; v1[0]=r2[0]-r1[0]; // side 1,2 v1[1]=r2[1]-r1[1]; v1[2]=r2[2]-r1[2]; cmp=v1[0]*r1[0]+v1[1]*r1[1]+v1[2]*r1[2]; b1=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; b2=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; b3=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; b4=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; b5=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; b6=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; b7=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; b8=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp&&b5>cmp&&b6>cmp&&b7>cmp&&b8>cmp) return 0; v1[0]=r3[0]-r1[0]; // side 1,3 v1[1]=r3[1]-r1[1]; v1[2]=r3[2]-r1[2]; cmp=v1[0]*r1[0]+v1[1]*r1[1]+v1[2]*r1[2]; b1=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; b2=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; b3=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; b4=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; b5=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; b6=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; b7=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; b8=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp&&b5>cmp&&b6>cmp&&b7>cmp&&b8>cmp) return 0; v1[0]=r4[0]-r1[0]; // side 1,4 v1[1]=r4[1]-r1[1]; v1[2]=r4[2]-r1[2]; cmp=v1[0]*r1[0]+v1[1]*r1[1]+v1[2]*r1[2]; b1=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; b2=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; b3=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; b4=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; b5=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; b6=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; b7=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; b8=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp&&b5>cmp&&b6>cmp&&b7>cmp&&b8>cmp) return 0; return 1; } int Geo_CircleXaabb2(double *cent,double rad,double *bpt1,double *bpt2) { double min,max,d2,r2; if(cent[0]+radbpt2[0]) return 0; if(cent[1]+radbpt2[1]) return 0; r2=rad*rad; // find closest, farthest corners d2=(bpt1[0]-cent[0])*(bpt1[0]-cent[0])+(bpt1[1]-cent[1])*(bpt1[1]-cent[1]); min=max=d2; d2=(bpt1[0]-cent[0])*(bpt1[0]-cent[0])+(bpt2[1]-cent[1])*(bpt2[1]-cent[1]); if(d2max) max=d2; d2=(bpt2[0]-cent[0])*(bpt2[0]-cent[0])+(bpt1[1]-cent[1])*(bpt1[1]-cent[1]); if(d2max) max=d2; d2=(bpt2[0]-cent[0])*(bpt2[0]-cent[0])+(bpt2[1]-cent[1])*(bpt2[1]-cent[1]); if(d2max) max=d2; if(r2>max) return 0; // box totally inside circle if(r2>=min) return 1; // at least 1 corner inside, but not all if(cent[0]>=bpt1[0]&¢[0]<=bpt2[0]) return 1; // circle crosses box side if(cent[1]>=bpt1[1]&¢[1]<=bpt2[1]) return 1; return 0; } // circle near box corner, not crossing int Geo_SphsXaabb3(double *cent,double rad,double *bpt1,double *bpt2) { double min,max,d2,r2; if(cent[0]+radbpt2[0]) return 0; if(cent[1]+radbpt2[1]) return 0; if(cent[2]+radbpt2[2]) return 0; r2=rad*rad; d2=(bpt1[0]-cent[0])*(bpt1[0]-cent[0])+(bpt1[1]-cent[1])*(bpt1[1]-cent[1])+(bpt1[2]-cent[2])*(bpt1[2]-cent[2]); min=max=d2; d2=(bpt1[0]-cent[0])*(bpt1[0]-cent[0])+(bpt1[1]-cent[1])*(bpt1[1]-cent[1])+(bpt2[2]-cent[2])*(bpt2[2]-cent[2]); if(d2max) max=d2; d2=(bpt1[0]-cent[0])*(bpt1[0]-cent[0])+(bpt2[1]-cent[1])*(bpt2[1]-cent[1])+(bpt1[2]-cent[2])*(bpt1[2]-cent[2]); if(d2max) max=d2; d2=(bpt1[0]-cent[0])*(bpt1[0]-cent[0])+(bpt2[1]-cent[1])*(bpt2[1]-cent[1])+(bpt2[2]-cent[2])*(bpt2[2]-cent[2]); if(d2max) max=d2; d2=(bpt2[0]-cent[0])*(bpt2[0]-cent[0])+(bpt1[1]-cent[1])*(bpt1[1]-cent[1])+(bpt1[2]-cent[2])*(bpt1[2]-cent[2]); if(d2max) max=d2; d2=(bpt2[0]-cent[0])*(bpt2[0]-cent[0])+(bpt1[1]-cent[1])*(bpt1[1]-cent[1])+(bpt2[2]-cent[2])*(bpt2[2]-cent[2]); if(d2max) max=d2; d2=(bpt2[0]-cent[0])*(bpt2[0]-cent[0])+(bpt2[1]-cent[1])*(bpt2[1]-cent[1])+(bpt1[2]-cent[2])*(bpt1[2]-cent[2]); if(d2max) max=d2; d2=(bpt2[0]-cent[0])*(bpt2[0]-cent[0])+(bpt2[1]-cent[1])*(bpt2[1]-cent[1])+(bpt2[2]-cent[2])*(bpt2[2]-cent[2]); if(d2max) max=d2; if(r2>max) return 0; if(r2>=min) return 1; if(cent[0]>=bpt1[0]&¢[0]<=bpt2[0]) return 1; if(cent[1]>=bpt1[1]&¢[1]<=bpt2[1]) return 1; if(cent[2]>=bpt1[2]&¢[2]<=bpt2[2]) return 1; return 1; } int Geo_CylisXaabb3(double *pt1,double *pt2,double rad,double *bpt1,double *bpt2) { double v1[3],v2[3],v3[3]; double cent[2],ab1[2],ab2[2],ab3[2],ab4[2],ab5[2],ab6[2],ab7[2],ab8[2]; double nrm,b1,b2,b3,b4,b5,b6,b7,b8,cmp,r2,d2,min,max,crss1,crss2; int sgn; Geo_LineNormal3D(pt1,pt2,pt1,v1); // v1 and v2 are normalized and perp. to cyl. axis v3[0]=pt2[0]-pt1[0]; v3[1]=pt2[1]-pt1[1]; v3[2]=pt2[2]-pt1[2]; nrm=sqrt(v3[0]*v3[0]+v3[1]*v3[1]+v3[2]*v3[2]); if(!nrm) return 0; v3[0]/=nrm; v3[1]/=nrm; v3[2]/=nrm; v2[0]=v3[1]*v1[2]-v3[2]*v1[1]; v2[1]=v3[2]*v1[0]-v3[0]*v1[2]; v2[2]=v3[0]*v1[1]-v3[1]*v1[0]; cent[0]=v1[0]*pt1[0]+v1[1]*pt1[1]+v1[2]*pt1[2]; cent[1]=v2[0]*pt1[0]+v2[1]*pt1[1]+v2[2]*pt1[2]; ab1[0]=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; // ab are box pts in 2-D ab1[1]=v2[0]*bpt1[0]+v2[1]*bpt1[1]+v2[2]*bpt1[2]; ab2[0]=v1[0]*bpt1[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; ab2[1]=v2[0]*bpt1[0]+v2[1]*bpt1[1]+v2[2]*bpt2[2]; ab3[0]=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; ab3[1]=v2[0]*bpt1[0]+v2[1]*bpt2[1]+v2[2]*bpt1[2]; ab4[0]=v1[0]*bpt1[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; ab4[1]=v2[0]*bpt1[0]+v2[1]*bpt2[1]+v2[2]*bpt2[2]; ab5[0]=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt1[2]; ab5[1]=v2[0]*bpt2[0]+v2[1]*bpt1[1]+v2[2]*bpt1[2]; ab6[0]=v1[0]*bpt2[0]+v1[1]*bpt1[1]+v1[2]*bpt2[2]; ab6[1]=v2[0]*bpt2[0]+v2[1]*bpt1[1]+v2[2]*bpt2[2]; ab7[0]=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt1[2]; ab7[1]=v2[0]*bpt2[0]+v2[1]*bpt2[1]+v2[2]*bpt1[2]; ab8[0]=v1[0]*bpt2[0]+v1[1]*bpt2[1]+v1[2]*bpt2[2]; ab8[1]=v2[0]*bpt2[0]+v2[1]*bpt2[1]+v2[2]*bpt2[2]; v1[0]=ab2[0]-ab1[0]; // do SAT on the three box axes v1[1]=ab2[1]-ab1[1]; nrm=sqrt(v1[0]*v1[0]+v1[1]*v1[1]); v1[0]/=nrm; v1[1]/=nrm; b1=v1[0]*ab1[0]+v1[1]*ab1[1]; b2=v1[0]*ab2[0]+v1[1]*ab2[1]; b3=v1[0]*ab3[0]+v1[1]*ab3[1]; b4=v1[0]*ab4[0]+v1[1]*ab4[1]; b5=v1[0]*ab5[0]+v1[1]*ab5[1]; b6=v1[0]*ab6[0]+v1[1]*ab6[1]; b7=v1[0]*ab7[0]+v1[1]*ab7[1]; b8=v1[0]*ab8[0]+v1[1]*ab8[1]; cmp=v1[0]*cent[0]+v1[1]*cent[1]-rad; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp&&b5>cmp&&b6>cmp&&b7>cmp&&b8>cmp) return 0; v1[0]=ab3[0]-ab1[0]; v1[1]=ab3[1]-ab1[1]; nrm=sqrt(v1[0]*v1[0]+v1[1]*v1[1]); v1[0]/=nrm; v1[1]/=nrm; b1=v1[0]*ab1[0]+v1[1]*ab1[1]; b2=v1[0]*ab2[0]+v1[1]*ab2[1]; b3=v1[0]*ab3[0]+v1[1]*ab3[1]; b4=v1[0]*ab4[0]+v1[1]*ab4[1]; b5=v1[0]*ab5[0]+v1[1]*ab5[1]; b6=v1[0]*ab6[0]+v1[1]*ab6[1]; b7=v1[0]*ab7[0]+v1[1]*ab7[1]; b8=v1[0]*ab8[0]+v1[1]*ab8[1]; cmp=v1[0]*cent[0]+v1[1]*cent[1]-rad; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp&&b5>cmp&&b6>cmp&&b7>cmp&&b8>cmp) return 0; v1[0]=ab5[0]-ab1[0]; v1[1]=ab5[1]-ab1[1]; nrm=sqrt(v1[0]*v1[0]+v1[1]*v1[1]); v1[0]/=nrm; v1[1]/=nrm; b1=v1[0]*ab1[0]+v1[1]*ab1[1]; b2=v1[0]*ab2[0]+v1[1]*ab2[1]; b3=v1[0]*ab3[0]+v1[1]*ab3[1]; b4=v1[0]*ab4[0]+v1[1]*ab4[1]; b5=v1[0]*ab5[0]+v1[1]*ab5[1]; b6=v1[0]*ab6[0]+v1[1]*ab6[1]; b7=v1[0]*ab7[0]+v1[1]*ab7[1]; b8=v1[0]*ab8[0]+v1[1]*ab8[1]; cmp=v1[0]*cent[0]+v1[1]*cent[1]-rad; if(b1cmp&&b2>cmp&&b3>cmp&&b4>cmp&&b5>cmp&&b6>cmp&&b7>cmp&&b8>cmp) return 0; r2=rad*rad; // check corners inside circle d2=(ab1[0]-cent[0])*(ab1[0]-cent[0])+(ab1[1]-cent[1])*(ab1[1]-cent[1]); min=max=d2; d2=(ab2[0]-cent[0])*(ab2[0]-cent[0])+(ab2[1]-cent[1])*(ab2[1]-cent[1]); if(d2max) max=d2; d2=(ab3[0]-cent[0])*(ab3[0]-cent[0])+(ab3[1]-cent[1])*(ab3[1]-cent[1]); if(d2max) max=d2; d2=(ab4[0]-cent[0])*(ab4[0]-cent[0])+(ab4[1]-cent[1])*(ab4[1]-cent[1]); if(d2max) max=d2; d2=(ab5[0]-cent[0])*(ab5[0]-cent[0])+(ab5[1]-cent[1])*(ab5[1]-cent[1]); if(d2max) max=d2; d2=(ab6[0]-cent[0])*(ab6[0]-cent[0])+(ab6[1]-cent[1])*(ab6[1]-cent[1]); if(d2max) max=d2; d2=(ab7[0]-cent[0])*(ab7[0]-cent[0])+(ab7[1]-cent[1])*(ab7[1]-cent[1]); if(d2max) max=d2; d2=(ab8[0]-cent[0])*(ab8[0]-cent[0])+(ab8[1]-cent[1])*(ab8[1]-cent[1]); if(d2max) max=d2; if(r2>max) return 0; if(r2>=min) return 1; if((crss1=Geo_LineXSphs(ab1,ab2,cent,rad,2,NULL))>=0&&crss1<=1) return 1; // check edge crossing if((crss1=Geo_LineXSphs(ab2,ab4,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab4,ab3,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab3,ab1,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab1,ab5,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab2,ab6,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab3,ab7,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab4,ab8,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab5,ab6,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab6,ab8,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab8,ab7,cent,rad,2,NULL))>=0&&crss1<=1) return 1; if((crss1=Geo_LineXSphs(ab7,ab5,cent,rad,2,NULL))>=0&&crss1<=1) return 1; v1[0]=cent[0]+1; // check wholly inside vs. wholly outside v1[1]=cent[1]; sgn=0; crss1=Geo_LineXLine(cent,v1,ab1,ab2,&crss2); if(crss2>=0&&crss2<=1) sgn=sign(crss1); crss1=Geo_LineXLine(cent,v1,ab2,ab4,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab4,ab3,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab3,ab1,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab1,ab5,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab2,ab6,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab3,ab7,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab4,ab8,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab5,ab6,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab6,ab8,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab8,ab7,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } crss1=Geo_LineXLine(cent,v1,ab7,ab5,&crss2); if(crss2>=0&&crss2<=1) { if(!sgn) sgn=sign(crss1); else if(sgn!=sign(crss1)) return 1; } return 0; } /******************** approx. Xaabb ************/ int Geo_SemicXaabb2(double *cent,double rad,double *outvect,double *bpt1,double *bpt2) { double r1[2],r2[2],r3[2]; if(!Geo_CircleXaabb2(cent,rad,bpt1,bpt2)) return 0; Geo_Semic2Rect(cent,rad,outvect,r1,r2,r3); return Geo_RectXaabb2(r1,r2,r3,bpt1,bpt2); } int Geo_HemisXaabb3(double *cent,double rad,double *outvect,double *bpt1,double *bpt2) { double r1[3],r2[3],r3[3],r4[3]; if(!Geo_SphsXaabb3(cent,rad,bpt1,bpt2)) return 0; Geo_Hemis2Rect(cent,rad,outvect,r1,r2,r3,r4); return Geo_RectXaabb3(r1,r2,r3,r4,bpt1,bpt2); } int Geo_CylsXaabb3(double *pt1,double *pt2,double rad,double *bpt1,double *bpt2) { double r1[3],r2[3],r3[3],r4[3]; if(!Geo_CylisXaabb3(pt1,pt2,rad,bpt1,bpt2)) return 0; Geo_Cyl2Rect(pt1,pt2,rad,r1,r2,r3,r4); return Geo_RectXaabb3(r1,r2,r3,r4,bpt1,bpt2); } /******************** volumes ****************/ double Geo_SphVolume(double rad,int dim) { double vol; if(dim==0) vol=1; else if(dim==1) vol=2*rad; else if(dim==2) vol=PI*rad*rad; else if(dim==3) vol=4.0/3.0*PI*rad*rad*rad; else vol=2.0/(dim*exp(gammaln(dim/2.0)))*intpower(SQRTPI*rad,dim); return vol; } double Geo_SphOLSph(double *cent1,double *cent2,double r1,double r2,int dim) { double ol,dist; int d; dist=0; for(d=0;d=r1+r2) ol=0; else if(dist+r2<=r1) ol=Geo_SphVolume(r2,dim); else if(dist+r1<=r2) ol=Geo_SphVolume(r1,dim); else { if(dim==1) ol=r1+r2-dist; else if(dim==2) ol=r1*r1*acos((dist*dist+r1*r1-r2*r2)/(2*dist*r1))+r2*r2*acos((dist*dist+r2*r2-r1*r1)/(2*dist*r2))-0.5*sqrt((-dist+r1+r2)*(dist+r1-r2)*(dist-r1+r2)*(dist+r1+r2)); else if(dim==3) ol=PI*(r2+r1-dist)*(r2+r1-dist)*(dist*dist+2*dist*r1-3*r1*r1+2*dist*r2+6*r1*r2-3*r2*r2)/(12*dist); else ol=-1; } return ol; }