三维几何-平面

平面的表示

通常用点法式(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);
    }
}

 

 

 

 

    原文作者:算法
    原文地址: https://www.twblogs.net/a/5bd3a0592b717778ac209bf3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞