三維幾何-平面

平面的表示

通常用點法式(p0,n)來描述一個平面。其中點p0是平面的一個點,向量n是平面的法向量。每個平面把空間分成了兩個部分,我們可以用點法式表示其中一個半空間。具體是哪一個呢?是這個法向量所背離的那一個(即法向量指向遠離半空間的方向)。

既然是法向量,n就垂直於平面上的所有直線。換句話說,平面上的任意點p滿足Dot(n,p-p0)=0.

設點p的座標爲(x,y,z),p0的座標爲(x0,y0,z0),向量n的座標表示爲(A,B,C),上述等式等價於

A(x-x0) + B(y-y0) + C(z-z0) = 0

整理得 Ax+By+Cz - (Ax0 + By0 + Cz0) = 0.如果令D=-(Ax0 + B0 + Cz0),我們就得到了平面的一般式:

Ax+By+Cz+D=0.

注意,當Ax+By+Cz+D>0時,上述點積大於0,即點(x,y,z)在半空間(p0,n)外。換句話說,Ax+By+Cz+D>0 表示的是一個半空間(half space),A,B,C,D乘-1得到翻轉後的平面。

平面: ax + by + cz = d

//平面 ax+by+cz=d
struct Plane
{
    double a, b, c, d;
};

過定點垂直於定直線的平面。平面的法向量就是這條直線,所以可以直接寫出所求平面的點法式。

直線與平面的夾角、兩平面的夾角、兩直線的夾角。注意到與平面的夾角可以轉化爲與法向量的夾角。兩平面的夾角等於這兩個平面的法線的夾角。

點到平面的距離。把向量p-p0投影到向量n上可得:p到平面的有向距離爲Dot(p-p0,n)/Length(n)。這是一個相當簡潔的結論。如果n是單位向量,甚至會更簡單。

點p到平面p0-n的距離。n必須爲單位向量

double DistancetoPlane(const Point3 &p, const Point3 &p0, const Vector3 &n)
{
    return fabs(Dot(p-p0, n));    //如果不取絕對值,得到的是有向距離
}

-點到平面的投影

有了距離,投影點本身就不難求了。設點p在平面(p0,n)上的投影爲p',則p'-p=dn,其中d就是p到平面的有向距離。

點p到平面p0-n的距離。n必須爲單位向量

注意此處的小技巧,求d的時候沒有取絕對值。因爲不確定p的位置。

Point3 getPlaneProjection(const Point3 &p, const Point3 &p0, const Vector3 &n)
{
    return p - n*Dot(p-p0, n);
}

直線與平面的交點。可以簡單的通過解方程得到。設平面方程爲Dot(n,p-p0)=0,過點p1和p2的直線的參數方程爲p=p1+t(p2-p1)

則與平面方程聯立解得:

t=Dot(n,p0-p1) / Dot(n,p2-p1)

其中分母爲0的情況對應於直線與平面平行,或者直線在平面上,如何區分?只要判斷p1或者p2是否在平面上即可。

直線p1-p2到平面p0-n的交點。假定交點唯一存在

Point3 LinePlaneIntersection(const Point3 &p1,const Point3 &p2, const Point3 &p0, const Vector3 &n)
{
    double t;
    Vector3 v;

    v = p2-p1;
    t = Dot(n, p0-p1) / Dot(n, v);         //判斷分母是否爲0
    return p1 + v*t;                      //如果是線段,判斷t是不是在0和1之間
}

順便提一下:如果平面用一般式Ax+By+Cz+D = 0,則聯立解出的表示式爲:

t= (Ax1 + By1 + Cz1 + D) / (A(x1-x2) + B(y1-y2) +C(z1-z2))

過不共線三點的平面。法向量爲Cross(p2-p0,p1-p0),任取一個點即可得到平面的點法式。

平面的旋轉。旋轉到水平平面,即法向量爲(0,0,sqrt(a*a + b*b +c*c))

首先繞z軸旋轉,得到(0, sqrt(a*a + b*b), c) 然後繞x軸旋轉 ,得到法向量(0,0,sqrt(a*a + b*b +c*c))

對點做旋轉

繞z軸旋轉: x' = xcosC - ysinC; y' = xsinC + ycosC; z' = z

繞x軸旋轉:x' = x;y' = ycosA - zsinA; z' =ysinA + zcosA

繞y軸旋轉: x' = zsinB + xcosB, y' = y; z' = zcosB - xsinB

其中角度爲平面法向量逆時針旋轉的角度,就等於平面上的點(一般對向量做旋轉,即點與原點相連形成的向量)所旋轉的角度。通過公式就可以得到旋轉後的點了。

void Rotation(Point3 *P, int n, const Plane &p)
{
    int i;
    double x, y, z, b, c, cosC, sinC;

    //繞z軸旋轉
    b = sqrt(p.a*p.a + p.b*p.b);
    if(dcmp(b) == 0)                        //已經水平,不需要旋轉了
        return;
    cosC = p.b / b;                         //向量逆時針旋轉角度的cos值
    sinC = p.a / b;                         //向量逆時針旋轉角度的sin值
    for(i = 0; i < n; i++)
    {
        x = P[i].x*cosC - P[i].y*sinC;
        y = P[i].x*sinC + P[i].y*cosC;
        z = P[i].z;
        P[i] = Point3(x, y, z);
    }
    //繞x軸旋轉
    c = sqrt(b*b + p.c*p.c);
    cosC = p.c / c;
    sinC = b / c;
    for(i = 0; i < n; i++)
    {
        x = P[i].x;
        y = P[i].y*cosC - P[i].z*sinC;
        z = P[i].y*sinC + P[i].z*cosC;
        P[i] = Point3(x, y, z);
    }
}

 

 

 

 

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