點、線、面相關的算法(2)

可用射線法來判斷一個點是否在多邊形的內部:

射線法就是以這個要判斷的點作一射線(爲了方便,直接作一水平向右的射線),數一下線段與
多邊形邊的交點數,奇數時就是在多邊形內,偶數時就是在多邊形外。

/* 判斷線段是否在簡單多邊形內(注意:如果多邊形是凸多邊形,下面的算法可以化簡)
     原理:
必要條件一:線段的兩個端點都在多邊形內;
必要條件二:線段和多邊形的所有邊都不內交;
用途:1. 判斷折線是否在簡單多邊形內
        2. 判斷簡單多邊形是否在另一個簡單多邊形內
*/
bool LinesegInsidePolygon(int vcount,POINT polygon[],LINESEG l)
{
// 判斷線端l的端點是否不都在多邊形內
if(!insidepolygon(vcount,polygon,l.s)||!insidepolygon(vcount,polygon,l.e))
return false;
int top=0,i,j;
POINT PointSet[MAXV],tmp;
LINESEG s;

for(i=0;i<vcount;i++)
{
s.s=polygon[i];
s.e=polygon[(i+1)%vcount];
if(online(s,l.s)) //線段l的起始端點在線段s上
PointSet[top++]=l.s;
else if(online(s,l.e)) //線段l的終止端點在線段s上
PointSet[top++]=l.e;
else
{
if(online(l,s.s)) //線段s的起始端點在線段l上
PointSet[top++]=s.s;
else if(online(l,s.e)) // 線段s的終止端點在線段l上
PointSet[top++]=s.e;
else
{
if(intersect(l,s)) // 這個時候如果相交,肯定是內交,返回false
return false;
}
}
}

for(i=0;i<top-1;i++) /* 冒泡排序,x座標小的排在前面;x座標相同者,
y座標小的排在前面 */
{
for(j=i+1;j<top;j++)
{
if( PointSet[i].x>PointSet[j].x || fabs(PointSet[i].x-PointSet[j].x)<EP && PointSet[i].y>PointSet[j].y )
     {
tmp=PointSet[i];
PointSet[i]=PointSet[j];
PointSet[j]=tmp;
}
}
}

for(i=0;i<top-1;i++)
{
tmp.x=(PointSet[i].x+PointSet[i+1].x)/2; //得到兩個相鄰交點的中點
tmp.y=(PointSet[i].y+PointSet[i+1].y)/2;
if(!insidepolygon(vcount,polygon,tmp))
return false;
}
return true;
}

/* 求任意簡單多邊形polygon的重心
需要調用下面幾個函數:
void AddPosPart(); 增加右邊區域的面積
void AddNegPart(); 增加左邊區域的面積
void AddRegion(); 增加區域面積
在使用該程序時,如果把xtr,ytr,wtr,xtl,ytl,wtl設成全局變量就可以使這些函數的形式得到化簡,但要注意函數的聲明和調用要做相應變化
*/
void AddPosPart(double x, double y, double w, double &xtr, double &ytr, double &wtr)
{
if (abs(wtr + w)<1e-10 ) return; // detect zero regions
xtr = ( wtr*xtr + w*x ) / ( wtr + w );
ytr = ( wtr*ytr + w*y ) / ( wtr + w );
wtr = w + wtr;
return;
}
void AddNegPart(double x, ouble y, double w, double &xtl, double &ytl, double &wtl)
{
if ( abs(wtl + w)<1e-10 )
return; // detect zero regions

xtl = ( wtl*xtl + w*x ) / ( wtl + w );
ytl = ( wtl*ytl + w*y ) / ( wtl + w );
wtl = w + wtl;
return;
}

void AddRegion ( double x1, double y1, double x2, double y2, double &xtr, double &ytr,
double &wtr, double &xtl, double &ytl, double &wtl )
{
if ( abs (x1 - x2)< 1e-10 )
return;

if ( x2 > x1 )
     {
AddPosPart ((x2+x1)/2, y1/2, (x2-x1) * y1,xtr,ytr,wtr); /* rectangle 全局
變量變化處 */
AddPosPart ((x1+x2+x2)/3, (y1+y1+y2)/3, (x2-x1)*(y2-y1)/2,xtr,ytr,wtr);    
// triangle 全局變量變化處
     }
     else
     {
AddNegPart ((x2+x1)/2, y1/2, (x2-x1) * y1,xtl,ytl,wtl);  
// rectangle 全局變量變化處
AddNegPart ((x1+x2+x2)/3, (y1+y1+y2)/3, (x2-x1)*(y2-y1)/2,xtl,ytl,wtl);  
// triangle    全局變量變化處
     }
}

POINT cg_simple(int vcount,POINT polygon[])
{
     double xtr,ytr,wtr,xtl,ytl,wtl;        
//注意: 如果把xtr,ytr,wtr,xtl,ytl,wtl改成全局變量後這裏要刪去
     POINT p1,p2,tp;
     xtr = ytr = wtr = 0.0;
     xtl = ytl = wtl = 0.0;
     for(int i=0;i<vcount;i++)
{
p1=polygon[i];
p2=polygon[(i+1)%vcount];
AddRegion(p1.x,p1.y,p2.x,p2.y,xtr,ytr,wtr,xtl,ytl,wtl); //全局變量變化處
}
tp.x = (wtr*xtr + wtl*xtl) / (wtr + wtl);
tp.y = (wtr*ytr + wtl*ytl) / (wtr + wtl);
return tp;
}

// 求凸多邊形的重心,要求輸入多邊形按逆時針排序
POINT gravitycenter(int vcount,POINT polygon[])
{
POINT tp;
double x,y,s,x0,y0,cs,k;
x=0;y=0;s=0;
for(int i=1;i<vcount-1;i++)
{
x0=(polygon[0].x+polygon[i].x+polygon[i+1].x)/3;
y0=(polygon[0].y+polygon[i].y+polygon[i+1].y)/3; //求當前三角形的重心
cs=multiply(polygon[i],polygon[i+1],polygon[0])/2;
//三角形面積可以直接利用該公式求解
if(abs(s)<1e-20)
{
x=x0;y=y0;s+=cs;continue;
}
k=cs/s; //求面積比例
x=(x+k*x0)/(1+k);
y=(y+k*y0)/(1+k);
s += cs;
}
tp.x=x;
tp.y=y;
return tp;
}

/* 給定一簡單多邊形,找出一個肯定在該多邊形內的點
定理1:每個多邊形至少有一個凸頂點
定理2:頂點數>=4的簡單多邊形至少有一條對角線
結論: x座標最大,最小的點肯定是凸頂點
         y座標最大,最小的點肯定是凸頂點            
*/
POINT a_point_insidepoly(int vcount,POINT polygon[])
{
     POINT v,a,b,r;
     int i,index;
     v=polygon[0];
     index=0;
     for(i=1;i<vcount;i++) //尋找一個凸頂點
{
if(polygon[i].y<v.y)
{
v=polygon[i];
index=i;
}
}
a=polygon[(index-1+vcount)%vcount]; //得到v的前一個頂點
b=polygon[(index+1)%vcount]; //得到v的後一個頂點
POINT tri[3],q;
tri[0]=a;tri[1]=v;tri[2]=b;
double md=INF;
int in1=index;
bool bin=false;
for(i=0;i<vcount;i++) //尋找在三角形avb內且離頂點v最近的頂點q
{
if(i == index)continue;
if(i == (index-1+vcount)%vcount)continue;
if(i == (index+1)%vcount)continue;
if(!InsideConvexPolygon(3,tri,polygon[i]))continue;
bin=true;
if(dist(v,polygon[i])<md)
{
q=polygon[i];
md=dist(v,q);
}
}
if(!bin) //沒有頂點在三角形avb內,返回線段ab中點
{
r.x=(a.x+b.x)/2;
r.y=(a.y+b.y)/2;
return r;
}
r.x=(v.x+q.x)/2; //返回線段vq的中點
r.y=(v.y+q.y)/2;
return r;
}

/* 求從多邊形外一點p出發到一個簡單多邊形的切線,如果存在返回切點,其中rp點是右切點,lp是左切點
注意:p點一定要在多邊形外
輸入頂點序列是逆時針排列
原 理:如果點在多邊形內肯定無切線;凸多邊形有唯一的兩個切點,凹多邊形就可能有多於兩個的切點;
如果polygon是凸多邊形,切點只有兩個只要找到就可以,可以化簡此算法
如果是凹多邊形還有一種算法可以求解:先求凹多邊形的凸包,然後求凸包的切線
*/
void pointtangentpoly(int vcount,POINT polygon[],POINT p,POINT &rp,POINT &lp)
{
LINESEG ep,en;
bool blp,bln;
rp=polygon[0];
lp=polygon[0];
for(int i=1;i<vcount;i++)
{
ep.s=polygon[(i+vcount-1)%vcount];
ep.e=polygon[i];
en.s=polygon[i];
en.e=polygon[(i+1)%vcount];
blp=multiply(ep.e,p,ep.s)>=0;                  // p is to the left of pre edge
bln=multiply(en.e,p,en.s)>=0;                  // p is to the left of next edge
          if(!blp&&bln)
{
if(multiply(polygon[i],rp,p)>0)             // polygon[i] is above rp
rp=polygon[i];
}
if(blp&&!bln)
{
if(multiply(lp,polygon[i],p)>0)             // polygon[i] is below lp
lp=polygon[i];
}
}
return ;
}

// 如果多邊形polygon的核存在,返回true,返回核上的一點p.頂點按逆時針方向輸入  
bool core_exist(int vcount,POINT polygon[],POINT &p)
{
int i,j,k;
LINESEG l;
LINE lineset[MAXV];
for(i=0;i<vcount;i++)
{
lineset[i]=makeline(polygon[i],polygon[(i+1)%vcount]);
}
for(i=0;i<vcount;i++)
{
for(j=0;j<vcount;j++)
{
if(i == j)continue;
if(lineintersect(lineset[i],lineset[j],p))
{
for(k=0;k<vcount;k++)
{
l.s=polygon[k];
l.e=polygon[(k+1)%vcount];
if(multiply(p,l.e,l.s)>0)      
//多邊形頂點按逆時針方向排列,核肯定在每條邊的左側或邊上
break;
}
if(k == vcount)               //找到了一個核上的點
break;
}
}
if(j<vcount)
break;
}
if(i<vcount)
return true;
else
return false;
}



/*************************\
* *
* 圓的基本運算 *
* *
\*************************/


/* 返回值: 點p在圓內(包括邊界)時,返回true
用途: 因爲圓爲凸集,所以判斷點集,折線,多邊形是否在圓內時,只需要逐一判斷點是否在圓內即可。
*/
bool point_in_circle(POINT o,double r,POINT p)
{
double d2=(p.x-o.x)*(p.x-o.x)+(p.y-o.y)*(p.y-o.y);
double r2=r*r;
return d2<r2||abs(d2-r2)<EP;
}


/* 用 途:求不共線的三點確定一個圓
輸 入:三個點p1,p2,p3
返回值:如果三點共線,返回false;反之,返回true。圓心由q返回,半徑由r返回
*/
bool cocircle(POINT p1,POINT p2,POINT p3,POINT &q,double &r)
{
double x12=p2.x-p1.x;
double y12=p2.y-p1.y;
double x13=p3.x-p1.x;
double y13=p3.y-p1.y;
double z2=x12*(p1.x+p2.x)+y12*(p1.y+p2.y);
double z3=x13*(p1.x+p3.x)+y13*(p1.y+p3.y);
double d=2.0*(x12*(p3.y-p2.y)-y12*(p3.x-p2.x));
if(abs(d)<EP) //共線,圓不存在
return false;
q.x=(y13*z2-y12*z3)/d;
q.y=(x12*z3-x13*z2)/d;
r=dist(p1,q);
return true;
}
int line_circle(LINE l,POINT o,double r,POINT &p1,POINT &p2)
{



return true;
}


/**************************\
* *
* 矩形的基本運算 *
* *
\**************************/


/*
說明:因爲矩形的特殊性,常用算法可以化簡:
1.判斷矩形是否包含點
只要判斷該點的橫座標和縱座標是否夾在矩形的左右邊和上下邊之間。
2.判斷線段、折線、多邊形是否在矩形中
因爲矩形是個凸集,所以只要判斷所有端點是否都在矩形中就可以了。
3.判斷圓是否在矩形中
圓在矩形中的充要條件是:圓心在矩形中且圓的半徑小於等於圓心到矩形四邊的距離的最小值。
*/
// 已知矩形的三個頂點(a,b,c),計算第四個頂點d的座標. 注意:已知的三個頂點可以是無序的
POINT rect4th(POINT a,POINT b,POINT c)
{
POINT d;
if(abs(dotmultiply(a,b,c))<EP) // 說明c點是直角拐角處
{
d.x=a.x+b.x-c.x;
d.y=a.y+b.y-c.y;
}
if(abs(dotmultiply(a,c,b))<EP) // 說明b點是直角拐角處
{
d.x=a.x+c.x-b.x;
d.y=a.y+c.y-b.x;
}
if(abs(dotmultiply(c,b,a))<EP) // 說明a點是直角拐角處
{
d.x=c.x+b.x-a.x;
d.y=c.y+b.y-a.y;
}
return d;
}



/*************************\
* *
* 常用算法的描述 *
* *
\*************************/

/* 尚未實現的算法:
1. 求包含點集的最小圓
2. 求多邊形的交
3. 簡單多邊形的三角剖分
4. 尋找包含點集的最小矩形
5. 折線的化簡
6. 判斷矩形是否在矩形中
7. 判斷矩形能否放在矩形中
8. 矩形並的面積與周長
9. 矩形並的輪廓
10.矩形並的閉包
11.矩形的交
12.點集中的最近點對
13.多邊形的並
14.圓的交與並
15.直線與圓的關係
16.線段與圓的關係
17.求多邊形的核監視攝象機
18.求點集中不相交點對 railwai
*/

/* 尋找包含點集的最小矩形
原理:該矩形至少一條邊與點集的凸殼的某條邊共線
First take the convex hull of the points. Let the resulting convex
polygon be P. It has been known for some time that the minimum
area rectangle enclosing P must have one rectangle side flush with
(i.e., collinear with and overlapping) one edge of P. This geometric
fact was used by Godfried Toussaint to develop the "rotating calipers"
algorithm in a hard-to-find 1983 paper, "Solving Geometric Problems
with the Rotating Calipers" (Proc. IEEE MELECON). The algorithm
rotates a surrounding rectangle from one flush edge to the next,
keeping track of the minimum area for each edge. It achieves O(n)
time (after hull computation). See the "Rotating Calipers Homepage"
http://www.cs.mcgill.ca/~orm/rotcal.frame.html for a description
and applet.
*/

/* 折線的化簡 僞碼如下:
Input: tol = the approximation tolerance
L = {V0,V1,...,Vn-1} is any n-vertex polyline

Set start = 0;
Set k = 0;
Set W0 = V0;
for each vertex Vi (i=1,n-1)
{
if Vi is within tol from Vstart
then ignore it, and continue with the next vertex

Vi is further than tol away from Vstart
so add it as a new vertex of the reduced polyline
Increment k++;
Set Wk = Vi;
Set start = i; as the new initial vertex
}

Output: W = {W0,W1,...,Wk-1} = the k-vertex simplified polyline
*/





/********************\
* *
* 補充 *
* *
\********************/

兩圓關係:

/* 兩圓:
相離: return 1;
外切: return 2;
相交: return 3;
內切: return 4;
內含: return 5;
*/
int CircleRelation(POINT p1, double r1, POINT p2, double r2)
{
double d = sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) );


if( fabs(d-r1-r2) < EP ) // 必須保證前兩個if先被判定!
return 2;
if( fabs(d-fabs(r1-r2)) < EP )
return 4;
if( d > r1+r2 )
        return 1;
     if( d < fabs(r1-r2) )
return 5;
if( fabs(r1-r2) < d && d < r1+r2 )
return 3;
return 0; // indicate an error!
}


判斷圓是否在矩形內:

// 判定圓是否在矩形內,是就返回true(設矩形水平,且其四個頂點由左上開始按順時針排列)
// 調用ptoldist函數,在第4頁
bool CircleRecRelation(POINT pc, double r, POINT pr1, POINT pr2, POINT pr3, POINT pr4)
{
if( pr1.x < pc.x && pc.x < pr2.x && pr3.y < pc.y && pc.y < pr2.y )
{
LINESEG line1(pr1, pr2);
LINESEG line2(pr2, pr3);
LINESEG line3(pr3, pr4);
LINESEG line4(pr4, pr1);
if( r<ptoldist(pc,line1) && r<ptoldist(pc,line2) &&
r<ptoldist(pc,line3) && r<ptoldist(pc,line4) )
return true;
}
return false;
}


點到平面的距離:

// 點到平面的距離,平面用一般式表示ax+by+cz+d=0
double P2planeDist(double x, double y, double z, double a, double b, double c, double d)
{
return fabs(a*x+b*y+c*z+d) / sqrt(a*a+b*b+c*c);
}


點是否在直線同側:

// 兩個點是否在直線同側,是則返回true
bool SameSide(POINT p1, POINT p2, LINE line)
{
return (line.a * p1.x + line.b * p1.y + line.c) *
(line.a * p2.x + line.b * p2.y + line.c) > 0;
}


鏡面反射線:

// 已知入射線、鏡面,求反射線。
// a1,b1,c1爲鏡面直線方程(a1 x + b1 y + c1 = 0 ,下同)係數;  
a2,b2,c2爲入射光直線方程係數;  
a,b,c爲反射光直線方程係數.
// 光是有方向的,使用時注意:入射光向量:<-b2,a2>;反射光向量:<b,-a>.
// 不要忘記結果中可能會有"negative zeros"

void reflect(double a1,double b1,double c1,double a2,double b2,double c2,double &a,double &b,double &c)
{
     double n,m;
     double tpb,tpa;
     tpb=b1*b2+a1*a2;
     tpa=a2*b1-a1*b2;
     m=(tpb*b1+tpa*a1)/(b1*b1+a1*a1);
     n=(tpa*b1-tpb*a1)/(b1*b1+a1*a1);
     if(fabs(a1*b2-a2*b1)<1e-20)
{
a=a2;b=b2;c=c2;
return;
}
double xx,yy; //(xx,yy)是入射線與鏡面的交點。
xx=(b1*c2-b2*c1)/(a1*b2-a2*b1);
yy=(a2*c1-a1*c2)/(a1*b2-a2*b1);
a=n;
b=-m;
c=m*yy-xx*n;
}


矩形包含:

bool r2inr1(double A,double B,double C,double D) // 矩形2(C,D)是否在1(A,B)內
{
double X,Y,L,K,DMax;
if (A < B)
{
double tmp = A;
A = B;
B = tmp;
}
if (C < D)
{
double tmp = C;
C = D;
D = tmp;
}

if (A > C && B > D)                   // trivial case  
        return true;
      else
        if (D >= B)
          return false;
        else
        {
          X = sqrt(A * A + B * B);           // outer rectangle's diagonal  
          Y = sqrt(C * C + D * D);           // inner rectangle's diagonal  
          if (Y < B) // check for marginal conditions
return true; // the inner rectangle can freely rotate inside
else
if (Y > X)
              return false;
            else
            {
              L = (B - sqrt(Y * Y - A * A)) / 2;
              K = (A - sqrt(Y * Y - B * B)) / 2;
              DMax = sqrt(L * L + K * K);
              if (D >= DMax)
                return false;
              else
                return true;
            }
        }
}

兩圓交點:

// 兩圓已經相交(相切)
void    c2point(POINT p1,double r1,POINT p2,double r2,POINT &rp1,POINT &rp2)
{
double a,b,r;
a=p2.x-p1.x;
b=p2.y-p1.y;
r=(a*a+b*b+r1*r1-r2*r2)/2;
if(a==0&&b!=0)
{
rp1.y=rp2.y=r/b;
rp1.x=sqrt(r1*r1-rp1.y*rp1.y);
rp2.x=-rp1.x;
}
else if(a!=0&&b==0)
{
rp1.x=rp2.x=r/a;
rp1.y=sqrt(r1*r1-rp1.x*rp2.x);
rp2.y=-rp1.y;
}
else if(a!=0&&b!=0)
{
double delta;
delta=b*b*r*r-(a*a+b*b)*(r*r-r1*r1*a*a);
rp1.y=(b*r+sqrt(delta))/(a*a+b*b);
rp2.y=(b*r-sqrt(delta))/(a*a+b*b);
rp1.x=(r-b*rp1.y)/a;
rp2.x=(r-b*rp2.y)/a;
}

rp1.x+=p1.x;
rp1.y+=p1.y;
rp2.x+=p1.x;
rp2.y+=p1.y;
}


兩圓公共面積:

// 必須保證相交
double c2area(POINT p1,double r1,POINT p2,double r2)
{
POINT rp1,rp2;
c2point(p1,r1,p2,r2,rp1,rp2);

if(r1>r2) //保證r2>r1
{
swap(p1,p2);
swap(r1,r2);
}
double a,b,rr;
a=p1.x-p2.x;
b=p1.y-p2.y;
rr=sqrt(a*a+b*b);

double dx1,dy1,dx2,dy2;
double sita1,sita2;
dx1=rp1.x-p1.x;
dy1=rp1.y-p1.y;
dx2=rp2.x-p1.x;
dy2=rp2.y-p1.y;
sita1=acos((dx1*dx2+dy1*dy2)/r1/r1);

dx1=rp1.x-p2.x;
dy1=rp1.y-p2.y;
dx2=rp2.x-p2.x;
dy2=rp2.y-p2.y;
sita2=acos((dx1*dx2+dy1*dy2)/r2/r2);
double s=0;
if(rr<r2) //相交弧爲優弧
s=r1*r1*(PI-sita1/2+sin(sita1)/2)+r2*r2*(sita2-sin(sita2))/2;
else //相交弧爲劣弧
s=(r1*r1*(sita1-sin(sita1))+r2*r2*(sita2-sin(sita2)))/2;

return s;
}

圓和直線關係:

//0----相離 1----相切 2----相交
int clpoint(POINT p,double r,double a,double b,double c,POINT &rp1,POINT &rp2)
{
int res=0;

c=c+a*p.x+b*p.y;
double tmp;
if(a==0&&b!=0)
{
tmp=-c/b;
if(r*r<tmp*tmp)
res=0;
else if(r*r==tmp*tmp)
{
res=1;
rp1.y=tmp;
rp1.x=0;
}
else
{
res=2;
rp1.y=rp2.y=tmp;
rp1.x=sqrt(r*r-tmp*tmp);
rp2.x=-rp1.x;
}
}
else if(a!=0&&b==0)
{
tmp=-c/a;
if(r*r<tmp*tmp)
res=0;
else if(r*r==tmp*tmp)
{
res=1;
rp1.x=tmp;
rp1.y=0;
}
else
{
res=2;
rp1.x=rp2.x=tmp;
rp1.y=sqrt(r*r-tmp*tmp);
rp2.y=-rp1.y;
}
}
else if(a!=0&&b!=0)
{
double delta;
delta=b*b*c*c-(a*a+b*b)*(c*c-a*a*r*r);
if(delta<0)
res=0;
else if(delta==0)
{
res=1;
rp1.y=-b*c/(a*a+b*b);
rp1.x=(-c-b*rp1.y)/a;
}
else
{
res=2;
rp1.y=(-b*c+sqrt(delta))/(a*a+b*b);
rp2.y=(-b*c-sqrt(delta))/(a*a+b*b);
rp1.x=(-c-b*rp1.y)/a;
rp2.x=(-c-b*rp2.y)/a;
}
}
rp1.x+=p.x;
rp1.y+=p.y;
rp2.x+=p.x;
rp2.y+=p.y;
return res;
}


內切圓:

void incircle(POINT p1,POINT p2,POINT p3,POINT &rp,double &r)
{
double dx31,dy31,dx21,dy21,d31,d21,a1,b1,c1;
dx31=p3.x-p1.x;
dy31=p3.y-p1.y;
dx21=p2.x-p1.x;
dy21=p2.y-p1.y;

d31=sqrt(dx31*dx31+dy31*dy31);
d21=sqrt(dx21*dx21+dy21*dy21);
a1=dx31*d21-dx21*d31;
b1=dy31*d21-dy21*d31;
c1=a1*p1.x+b1*p1.y;

double dx32,dy32,dx12,dy12,d32,d12,a2,b2,c2;
dx32=p3.x-p2.x;
dy32=p3.y-p2.y;
dx12=-dx21;
dy12=-dy21;

d32=sqrt(dx32*dx32+dy32*dy32);
d12=d21;
a2=dx12*d32-dx32*d12;
b2=dy12*d32-dy32*d12;
c2=a2*p2.x+b2*p2.y;

rp.x=(c1*b2-c2*b1)/(a1*b2-a2*b1);
rp.y=(c2*a1-c1*a2)/(a1*b2-a2*b1);
r=fabs(dy21*rp.x-dx21*rp.y+dx21*p1.y-dy21*p1.x)/d21;
}


求切點:

// p---圓心座標, r---圓半徑, sp---圓外一點, rp1,rp2---切點座標
void cutpoint(POINT p,double r,POINT sp,POINT &rp1,POINT &rp2)
{
POINT p2;
p2.x=(p.x+sp.x)/2;
p2.y=(p.y+sp.y)/2;

double dx2,dy2,r2;
dx2=p2.x-p.x;
dy2=p2.y-p.y;
r2=sqrt(dx2*dx2+dy2*dy2);
c2point(p,r,p2,r2,rp1,rp2);
}


線段的左右旋:

/* l2在l1的左/右方向(l1爲基準線)
返回 0: 重合;
返回 1: 右旋;
返回 –1: 左旋;
*/
int rotat(LINESEG l1,LINESEG l2)
{
double dx1,dx2,dy1,dy2;
dx1=l1.s.x-l1.e.x;
dy1=l1.s.y-l1.e.y;
dx2=l2.s.x-l2.e.x;
dy2=l2.s.y-l2.e.y;

double d;
d=dx1*dy2-dx2*dy1;
if(d==0)
return 0;
else if(d>0)
        return -1;
     else
        return 1;
}


公式:

球座標公式:
直角座標爲 P(x, y, z) 時,對應的球座標是(rsinφcosθ, rsinφsinθ, rcosφ),其中φ是向量OP與Z軸的夾角,範圍[0,π];是OP在XOY面上的投影到X軸的旋角,範圍[0,2π]  

直線的一般方程轉化成向量方程:
ax+by+c=0
x-x0       y-y0
     ------ = ------- // (x0,y0)爲直線上一點,m,n爲向量
m          n
轉換關係:
a=n;b=-m;c=m·y0-n·x0;
m=-b; n=a;

三點平面方程:
三點爲P1,P2,P3
設向量    M1=P2-P1; M2=P3-P1;
平面法向量:    M=M1 x M2 ()
平面方程:      M.i(x-P1.x)+M.j(y-P1.y)+M.k(z-P1.z)=0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章