简单地说就是,给定一个三角形ABC和任意一个点 $(x,y)$ ,这个点的坐标都可以用点ABC线性表示。且重心坐标的性质是:他们的系数之和为1。也就是说$(x, y)= a A + b B + c C, a+b+c=1$
至于这三个系数怎么求有点复杂,最容易理解的方法是用面积法。
但是有个结论很简洁,也是上面算法用到的:如果点在三角形内部,则三个系数属于(0,1)之间;如果点在三角形边上,则至少一个系数等于0或1;如果点在三角形外面,则至少有一个系数大于1或小于0。
判断点与三角形关系算法思想
贝塞尔坐标(也被称为重心坐标或三角形坐标)用于在三角形中描述一个点的位置。对于三角形的顶点 A, B, C 和内部或边界上的点 P,P 的贝塞尔坐标(u, v, w)可以通过以下公式得到:
首先,我们需要计算向量:
复制 Vector v0 = C - A
Vector v1 = B - A
Vector v2 = P - A
然后,我们计算以下点积:
复制 float dot00 = dot(v0, v0)
float dot01 = dot(v0, v1)
float dot02 = dot(v0, v2)
float dot11 = dot(v1, v1)
float dot12 = dot(v1, v2)
这些点积用于计算贝塞尔坐标的分母和分子。最后,我们计算 u 和 v:
复制 float invDenom = 1 / (dot00 * dot11 - dot01 * dot01)
float u = (dot11 * dot02 - dot01 * dot12) * invDenom
float v = (dot00 * dot12 - dot01 * dot02) * invDenom
其中,invDenom
它可以视为对角线乘积减去非对角线乘积的倒数,这是用来计算二维向量投影的公式的一部分。
至于 w,它可以由以下公式得到:
注意,u, v 和 w 的和总是等于 1,这是贝塞尔坐标的性质。而且,如果点 P 在三角形内部,那么 u、v 和 w 都在 0 和 1 之间。如果点 P 在三角形的边界上,那么 u、v 和 w 中至少有一个等于 0 或 1。如果点 P 在三角形的外部,那么 u、v 和 w 中至少有一个小于 0 或大于 1。
请注意这个计算方法对于退化的三角形(三个顶点在同一直线上)无效,因为此时分母 dot00 * dot11 - dot01 * dot01
会等于零,不能作为除数。
复制 static bool insideTriangle ( int x , int y , const Vector3f * _v)
{
// Compute vectors
Vector2f v0 = _v [ 2 ] . head < 2 > () - _v [ 0 ] . head < 2 > ();
Vector2f v1 = _v [ 1 ] . head < 2 > () - _v [ 0 ] . head < 2 > ();
Vector2f v2 = Vector2f (x , y) - _v [ 0 ] . head < 2 > ();
// Compute dot products
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);
// Compute barycentric coordinates
float invDenom = 1.0 f / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// Check if point is in triangle
return (u >= 0 ) && (v >= 0 ) && (u + v < 1 );
}
计算重心坐标的参数的方法
复制 static std :: tuple < float , float , float > computeBarycentric2D ( float x , float y , const Vector3f * v)
{
float c1 = (x*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*y + v[1].x()*v[2].y() - v[2].x()*v[1].y()) / (v[0].x()*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*v[0].y() + v[1].x()*v[2].y() - v[2].x()*v[1].y());
float c2 = (x*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*y + v[2].x()*v[0].y() - v[0].x()*v[2].y()) / (v[1].x()*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*v[1].y() + v[2].x()*v[0].y() - v[0].x()*v[2].y());
float c3 = (x*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*y + v[0].x()*v[1].y() - v[1].x()*v[0].y()) / (v[2].x()*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*v[2].y() + v[0].x()*v[1].y() - v[1].x()*v[0].y());
return {c1 , c2 , c3};
}