判断点在一个面域的内部

前言

作者在学习工作中,经常需要和几何相关内容打交道,因此分享自己在编程过程中遇到的一些问题和解决方法,也十分欢迎各位私信与我交流,另外如有不懂得地方也可以找我,在下会积极回复。

问题分析

通常来说,人眼能一眼就看出一个点是否处于面内,但是如何让计算机知道呢?

奇偶判断法

通过待判断点向任意方向发射一条射线,射线与面域相交的交点个数若为奇数,则判断该点在内部,反之则在外部。

相交判断

那么另一个问题来了,如何判断射线和一条直线是否相交呢

1.直线两端点应在射线两侧


如上图,第一步应保证端点a,b分别在射线两侧,而判断点在线的方位,常用叉积的办法。这可以通过分别计算向量a、b与射线方向向量的叉积,若两叉积异号则证明在两侧。

2.一条向量与射线向量在另一向量的同侧


通过第一步操作,我们能把射线区域限定在上述斜线区域,但是明显能观察到,只有在绿色区域才会与直线相交,因此我们需要继续增加约束,排除棕色区域。
例如上图绿色区域,向量b和射线向量都在向量a的下侧。

代码实现

C#

public static bool IsInterected(Point origin,Vector rayDirection,Line line)
{
    Point pointA = Line.FirstPoint;
    Point pointB = Line.LastPoint;
    //计算向量a,b
    Vector vectorA = pointA - origin;
    Vector vectorB = pointB - origin;
    //判断两端点在射线两侧
    double crossValueA = vectorA.crossProduct(rayDirection).Z;
    double crossValueB = vectorB.crossProduct(rayDirection).Z;
    if(crossValueA*crossValueB>0)
        return false;
    //判断B向量与射线向量是否在A向量的同侧
    double crossValueAB = vectorA.crossProduct(vectorB).Z;
    if(crossValueA*crossValueAB<0)
        return false;
    return true;
}
public static bool IsPointIn(Line[] face,Point point)
{
    //任取一个射线方向向量
    Vector rayDir = new Vector(1,1.21,0);
    //记录交点个数
    int intersectCount = 0;
    foreach(var item in face)
    {
        if(IsInterected)
            intersectCount++;

    }

    //奇偶判断
    if(intersectCount%2==0)
         return false;
    return true;
}