点在三角形内——重心坐标

688 阅读1分钟

方法

对于三角形ABC所在的平面上一点P,有:

P = A + u(C-A) + v(B - A)

v_0 = C-Av_1 = B-Av_2=P-A,即:

v_2 = u  v_0 + v  v_1

方程两边同乘v_0和同乘v_1,得:

v_2 \cdot v_0 = u v_0\cdot v_0 + v v_1 \cdot v_0 \\
    v_2 \cdot v_1 = u v_0\cdot v_1 + v v_1 \cdot v_1 \\

矩阵形式:

\begin{bmatrix}
    v_0 \cdot v_0 & v_1 \cdot v_0 \\
    v_0 \cdot v_1 & v_1 \cdot v_1 
\end{bmatrix} \begin{bmatrix}
    u \\ v
\end{bmatrix} = \begin{bmatrix}
    v_2 \cdot v_0 \\ v_2 \cdot v_1
\end{bmatrix}

解:

u = \frac{(v_1\cdot v_1) (v_2\cdot v_0) - (v_1 \cdot v_0)(v_2\cdot v_1)}{(v_0 \cdot v_0)(v_1\cdot v_1) - (v_0 \cdot v_1)(v_1\cdot v_0)} \\
    v = \frac{(v_0\cdot v_0) (v_2\cdot v_1) - (v_1 \cdot v_0)(v_2\cdot v_0)}{(v_0 \cdot v_0)(v_1\cdot v_1) - (v_0 \cdot v_1)(v_1\cdot v_0)}
P = (1-u-v) A + uC + vB

实现

bool pointinTriangle(const Eigen::Vector3f &A, const Eigen::Vector3f &B,
    const Eigen::Vector3f &C, const Eigen::Vector3f &P)
{    
    Vector3f v0 = C - A;
    Vector3f v1 = B - A;
    Vector3f v2 = P - A;
    float dot00 = v0.dot(v0);
    float dot01 = v0.dot(v1);
    float dot02 = v0.dot(v2);
    float dot11 = v1.dot(v1);
    float dot12 = v1.dot(v2);

    Matrix2f ACoff;      
    ACoff<< dot00, dot01, 
            dot01, dot11;          
    Vector2f b(dot02, dot12);   
    Vector2f x = ACoff.lu().solve(b);

    if (x[0] < 0 || x[0] > 1) // u out of range
    {        
        return false;
    }

    if (x[1] < 0 || x[1] > 1) // v out of range
    {        
        return false;
    }
    
    return x[0] + x[1] <= 1;
}