有没有一种简单的方法来确定一个点是否在三角形内?它是2D,而不是3D。
答案 0 :(得分:239)
一般来说,最简单(也是最优的)算法是检查点边缘所创建的半平面的哪一侧。
以下是topic on GameDev中的一些高质量信息,包括性能问题。
这里有一些代码可以帮助你入门:
float sign (fPoint p1, fPoint p2, fPoint p3)
{
return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
}
bool PointInTriangle (fPoint pt, fPoint v1, fPoint v2, fPoint v3)
{
float d1, d2, d3;
bool has_neg, has_pos;
d1 = sign(pt, v1, v2);
d2 = sign(pt, v2, v3);
d3 = sign(pt, v3, v1);
has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
return !(has_neg && has_pos);
}
答案 1 :(得分:157)
解决以下等式系统:
p = p0 + (p1 - p0) * s + (p2 - p0) * t
如果p
和0 <= s <= 1
以及0 <= t <= 1
,则s + t <= 1
点位于三角形内。
s
,t
和1 - s - t
被称为p
点的barycentric coordinates。
答案 2 :(得分:102)
我同意 Andreas Brinck ,重心坐标对此任务非常方便。请注意,每次都不需要求解方程系统:只需评估解析解。使用 Andreas '表示法,解决方案是:
s = 1/(2*Area)*(p0y*p2x - p0x*p2y + (p2y - p0y)*px + (p0x - p2x)*py);
t = 1/(2*Area)*(p0x*p1y - p0y*p1x + (p0y - p1y)*px + (p1x - p0x)*py);
其中Area
是三角形的(带符号)区域:
Area = 0.5 *(-p1y*p2x + p0y*(-p1x + p2x) + p0x*(p1y - p2y) + p1x*p2y);
只需评估s
,t
和1-s-t
。点p
位于三角形内部,当且仅当它们都是正数时。
编辑:请注意,该区域的上述表达式假定三角形节点编号是逆时针的。如果编号是顺时针方向,则此表达式将返回负区域(但具有正确的幅度)。但是,测试本身(s>0 && t>0 && 1-s-t>0
)不依赖于编号的方向,因为如果三角形节点方向发生变化,上面的表达式乘以1/(2*Area)
也会改变符号。
编辑2:为了获得更好的计算效率,请参阅下面的 coproc 注释(这表明如果事先知道三角形节点的方向(顺时针或逆时针),可以避免在2*Area
和s
的表达式中按t
划分。另请参阅 Andreas Brinck 的回答中的 Perro Azul 的jsfiddle代码。
答案 3 :(得分:39)
我在谷歌最后一次尝试之前编写了这段代码并找到了这个页面,所以我想我会分享它。它基本上是Kisielewicz答案的优化版本。我也研究了Barycentric方法,但从维基百科的文章来看,我很难看到它是如何更有效的(我猜有更深的等价)。无论如何,这种算法的优点是不使用除法;潜在的问题是边缘检测的行为取决于方向。
bool intpoint_inside_trigon(intPoint s, intPoint a, intPoint b, intPoint c)
{
int as_x = s.x-a.x;
int as_y = s.y-a.y;
bool s_ab = (b.x-a.x)*as_y-(b.y-a.y)*as_x > 0;
if((c.x-a.x)*as_y-(c.y-a.y)*as_x > 0 == s_ab) return false;
if((c.x-b.x)*(s.y-b.y)-(c.y-b.y)*(s.x-b.x) > 0 != s_ab) return false;
return true;
}
用语言来说,这个想法是这样的:点AB和AC的左边或右边是点吗?如果是真的,它不能在里面。如果为假,则至少在符合条件的“锥体”内。既然我们知道三角形(三角形)内的一个点必须与BC的同一侧(以及CA),我们检查它们是否不同。如果他们这样做,s不可能在里面,否则s必须在里面。
计算中的一些关键字是线半平面和行列式(2x2交叉乘积)。也许更教学的方式可能是将其视为内部的一个点,如果它与AB,BC和CA中的每条线的同一侧(左侧或右侧)。然而,上述方式似乎更适合某些优化。
答案 4 :(得分:25)
s
和t
具有相反的符号,则可以避免区域计算。我通过非常彻底的单元测试验证了正确的行为。
public static bool PointInTriangle(Point p, Point p0, Point p1, Point p2)
{
var s = p0.Y * p2.X - p0.X * p2.Y + (p2.Y - p0.Y) * p.X + (p0.X - p2.X) * p.Y;
var t = p0.X * p1.Y - p0.Y * p1.X + (p0.Y - p1.Y) * p.X + (p1.X - p0.X) * p.Y;
if ((s < 0) != (t < 0))
return false;
var A = -p1.Y * p2.X + p0.Y * (p2.X - p1.X) + p0.X * (p1.Y - p2.Y) + p1.X * p2.Y;
return A < 0 ?
(s <= 0 && s + t >= A) :
(s >= 0 && s + t <= A);
}
[编辑]
接受@Pierre的建议修改;见评论
答案 5 :(得分:11)
重心方法的Java版本:
class Triangle {
Triangle(double x1, double y1, double x2, double y2, double x3,
double y3) {
this.x3 = x3;
this.y3 = y3;
y23 = y2 - y3;
x32 = x3 - x2;
y31 = y3 - y1;
x13 = x1 - x3;
det = y23 * x13 - x32 * y31;
minD = Math.min(det, 0);
maxD = Math.max(det, 0);
}
boolean contains(double x, double y) {
double dx = x - x3;
double dy = y - y3;
double a = y23 * dx + x32 * dy;
if (a < minD || a > maxD)
return false;
double b = y31 * dx + x13 * dy;
if (b < minD || b > maxD)
return false;
double c = det - a - b;
if (c < minD || c > maxD)
return false;
return true;
}
private final double x3, y3;
private final double y23, x32, y31, x13;
private final double det, minD, maxD;
}
假设没有溢出,上面的代码将使用整数精确地工作。它也适用于顺时针和逆时针三角形。它不适用于共线三角形(但你可以通过测试det == 0来检查它。)
如果您要测试具有相同三角形的不同点,则重心版本是最快的。
重心版本在3个三角形点中不对称,因此由于浮点舍入误差,它可能不如Kornel Kisielewicz的边缘半平面版本一致。
信用:我从维基百科关于重心坐标的文章中提出了上述代码。
答案 6 :(得分:10)
一种简单的方法是:
找到连接的向量 指向三角形的三个 顶点和总和之间的角度 那些载体。如果总和了 角度是2 * pi然后点 在三角形里面。
两个解释替代品的好网站是:
答案 7 :(得分:7)
使用barycentric coordinates的分析解决方案(由 Andreas Brinck 指出)和:
可以最大限度地减少&#34; costy&#34;操作:
function ptInTriangle(p, p0, p1, p2) {
var dX = p.x-p2.x;
var dY = p.y-p2.y;
var dX21 = p2.x-p1.x;
var dY12 = p1.y-p2.y;
var D = dY12*(p0.x-p2.x) + dX21*(p0.y-p2.y);
var s = dY12*dX + dX21*dY;
var t = (p2.y-p0.y)*dX + (p0.x-p2.x)*dY;
if (D<0) return s<=0 && t<=0 && s+t>=D;
return s>=0 && t>=0 && s+t<=D;
}
(代码可以粘贴在 Perro Azul jsfiddle)
导致:
这与 Kornel Kisielewicz 解决方案相比(25次召回,1次存储,15次减法,6次乘法,5次比较),如果需要顺时针/逆时针检测,可能会更好(如 rhgb 所指出的那样,使用解析解决方案决定因素,需要6次召回,1次加法,2次减法,2次乘法和1次比较。
答案 8 :(得分:5)
我所做的是预先计算三面法线,
通过侧向量和面法向量的交叉乘积在3D中。
在2D中通过简单地交换组件并否定一个,
然后任何一方的内/外是当侧法线和点到点矢量的点积时,改变符号。重复其他两个(或更多)方。
优点:
对于同一个三角形上的多点测试,预计算得非常多。
早期拒绝比内部更多的常见案例。 (如果点数分布加权到一边,可以先测试那一边。)
答案 9 :(得分:4)
这是一个高效的Python实施:
def PointInsideTriangle2(pt,tri):
'''checks if point pt(2) is inside triangle tri(3x2). @Developer'''
a = 1/(-tri[1,1]*tri[2,0]+tri[0,1]*(-tri[1,0]+tri[2,0])+ \
tri[0,0]*(tri[1,1]-tri[2,1])+tri[1,0]*tri[2,1])
s = a*(tri[2,0]*tri[0,1]-tri[0,0]*tri[2,1]+(tri[2,1]-tri[0,1])*pt[0]+ \
(tri[0,0]-tri[2,0])*pt[1])
if s<0: return False
else: t = a*(tri[0,0]*tri[1,1]-tri[1,0]*tri[0,1]+(tri[0,1]-tri[1,1])*pt[0]+ \
(tri[1,0]-tri[0,0])*pt[1])
return ((t>0) and (1-s-t>0))
和示例输出:
答案 10 :(得分:3)
如果您正在寻找速度,这是一个可能对您有帮助的程序。
在纵坐标上对三角形顶点进行排序。这最糟糕的是三次比较。设Y0,Y1,Y2为三个排序值。通过绘制三个水平线,您可以将平面划分为两个半平面和两个平板。设Y是查询点的纵坐标。
if Y < Y1
if Y <= Y0 -> the point lies in the upper half plane, outside the triangle; you are done
else Y > Y0 -> the point lies in the upper slab
else
if Y >= Y2 -> the point lies in the lower half plane, outside the triangle; you are done
else Y < Y2 -> the point lies in the lower slab
再花费两次比较。如您所见,对于“边界板”之外的点,可以实现快速拒绝。
您可以选择在横坐标上进行测试,以便在左侧和右侧快速拒绝(X <= X0' or X >= X2'
)。这将同时实现快速边界框测试,但您也需要对横坐标进行排序。
最终,您需要根据划定相关板(上部或下部)的三角形的两边计算给定点的符号。测试的形式如下:
((X - Xi) * (Y - Yj) > (X - Xi) * (Y - Yj)) == ((X - Xi) * (Y - Yk) > (X - Xi) * (Y - Yk))
对i, j, k
组合的完整讨论(其中有六个,基于排序的结果)超出了本答案的范围,并“留给读者作为练习”;为了提高效率,它们应该是硬编码的。
如果您认为此解决方案很复杂,请注意它主要涉及简单的比较(其中一些可以预先计算),加上6次减法和4次乘法,以防边界框测试失败。后者的成本很难被击败,因为在最坏的情况下你无法避免将测试点与双方进行比较(其他答案中的方法没有成本较低,有些则更糟,如15次减法和6次乘法,有时是分裂)。 / p>
更新: 剪切变换更快
如上所述,您可以使用两个比较快速找到由三个顶点坐标分隔的四个水平带之一内的点。
您可以选择执行一个或两个额外的X测试来检查边界框(虚线)的内在性。
然后考虑X'= X - m Y, Y' = Y
给出的“剪切”变换,其中m
是最高边的斜率DX/DY
。此变换将使三角形的这一边垂直。既然您知道中间水平面的哪一侧,那么就可以根据三角形的一侧测试符号。
假设您预先计算了斜率m
,以及剪切三角形顶点的X'
和边的方程系数X = m Y + p
,您将需要最差的情况下
X' = X - m Y
; X >< m' Y + p'
。答案 11 :(得分:3)
如果您知道三个顶点的坐标和特定点的坐标,那么您可以得到完整三角形的面积。然后,计算三个三角形段的面积(一个点是给定的点,另外两个是三角形的任意两个顶点)。因此,您将获得三个三角形片段的面积。如果这些区域的总和等于总面积(您之前得到的),则该点应位于三角形内。否则,该点不在三角形内。这应该工作。如果有任何问题,请告诉我。谢谢。
答案 12 :(得分:3)
python 中的其他功能,比开发人员的方法(至少对我而言)更快,并受CédricDufour解决方案的启发:
def ptInTriang(p_test, p0, p1, p2):
dX = p_test[0] - p0[0]
dY = p_test[1] - p0[1]
dX20 = p2[0] - p0[0]
dY20 = p2[1] - p0[1]
dX10 = p1[0] - p0[0]
dY10 = p1[1] - p0[1]
s_p = (dY20*dX) - (dX20*dY)
t_p = (dX10*dY) - (dY10*dX)
D = (dX10*dY20) - (dY10*dX20)
if D > 0:
return ( (s_p >= 0) and (t_p >= 0) and (s_p + t_p) <= D )
else:
return ( (s_p <= 0) and (t_p <= 0) and (s_p + t_p) >= D )
您可以使用以下方法进行测试:
X_size = 64
Y_size = 64
ax_x = np.arange(X_size).astype(np.float32)
ax_y = np.arange(Y_size).astype(np.float32)
coords=np.meshgrid(ax_x,ax_y)
points_unif = (coords[0].reshape(X_size*Y_size,),coords[1].reshape(X_size*Y_size,))
p_test = np.array([0 , 0])
p0 = np.array([22 , 8])
p1 = np.array([12 , 55])
p2 = np.array([7 , 19])
fig = plt.figure(dpi=300)
for i in range(0,X_size*Y_size):
p_test[0] = points_unif[0][i]
p_test[1] = points_unif[1][i]
if ptInTriang(p_test, p0, p1, p2):
plt.plot(p_test[0], p_test[1], '.g')
else:
plt.plot(p_test[0], p_test[1], '.r')
绘制需要花费很多时间,但该网格在0.0195319652557秒内测试,而开发人员代码为0.0844349861145秒。
最后代码评论:
# Using barycentric coordintes, any point inside can be described as:
# X = p0.x * r + p1.x * s + p2.x * t
# Y = p0.y * r + p1.y * s + p2.y * t
# with:
# r + s + t = 1 and 0 < r,s,t < 1
# then: r = 1 - s - t
# and then:
# X = p0.x * (1 - s - t) + p1.x * s + p2.x * t
# Y = p0.y * (1 - s - t) + p1.y * s + p2.y * t
#
# X = p0.x + (p1.x-p0.x) * s + (p2.x-p0.x) * t
# Y = p0.y + (p1.y-p0.y) * s + (p2.y-p0.y) * t
#
# X - p0.x = (p1.x-p0.x) * s + (p2.x-p0.x) * t
# Y - p0.y = (p1.y-p0.y) * s + (p2.y-p0.y) * t
#
# we have to solve:
#
# [ X - p0.x ] = [(p1.x-p0.x) (p2.x-p0.x)] * [ s ]
# [ Y - p0.Y ] [(p1.y-p0.y) (p2.y-p0.y)] [ t ]
#
# ---> b = A*x ; ---> x = A^-1 * b
#
# [ s ] = A^-1 * [ X - p0.x ]
# [ t ] [ Y - p0.Y ]
#
# A^-1 = 1/D * adj(A)
#
# The adjugate of A:
#
# adj(A) = [(p2.y-p0.y) -(p2.x-p0.x)]
# [-(p1.y-p0.y) (p1.x-p0.x)]
#
# The determinant of A:
#
# D = (p1.x-p0.x)*(p2.y-p0.y) - (p1.y-p0.y)*(p2.x-p0.x)
#
# Then:
#
# s_p = { (p2.y-p0.y)*(X - p0.x) - (p2.x-p0.x)*(Y - p0.Y) }
# t_p = { (p1.x-p0.x)*(Y - p0.Y) - (p1.y-p0.y)*(X - p0.x) }
#
# s = s_p / D
# t = t_p / D
#
# Recovering r:
#
# r = 1 - (s_p + t_p)/D
#
# Since we only want to know if it is insidem not the barycentric coordinate:
#
# 0 < 1 - (s_p + t_p)/D < 1
# 0 < (s_p + t_p)/D < 1
# 0 < (s_p + t_p) < D
#
# The condition is:
# if D > 0:
# s_p > 0 and t_p > 0 and (s_p + t_p) < D
# else:
# s_p < 0 and t_p < 0 and (s_p + t_p) > D
#
# s_p = { dY20*dX - dX20*dY }
# t_p = { dX10*dY - dY10*dX }
# D = dX10*dY20 - dY10*dX20
答案 13 :(得分:1)
存在令人讨厌的边缘条件,其中一个点恰好位于两个相邻三角形的公共边缘上。该点不能同时存在于两者中,也不能同时存在于三角形中。您需要一种任意但一致的方式来分配点。例如,通过该点绘制一条水平线。如果该线与右侧三角形的另一侧相交,则该点被视为处于三角形内部。如果交叉点在左侧,则该点在外面。
如果点所在的线是水平的,请使用上方/下方。
如果该点位于多个三角形的公共顶点上,请使用三角形,其中心点形成最小角度。
更有趣:三个点可以是直线(零度),例如(0,0) - (0,10) - (0,5)。在三角测量算法中,“耳朵”(0,10)必须被剔除,生成的“三角形”是直线的退化情况。
答案 14 :(得分:1)
这是一个高效的python解决方案,已有文档证明,其中包含三个单元测试。它具有专业级的质量,可以按模块原样直接放入您的项目中。
import unittest
###############################################################################
def point_in_triangle(point, triangle):
"""Returns True if the point is inside the triangle
and returns False if it falls outside.
- The argument *point* is a tuple with two elements
containing the X,Y coordinates respectively.
- The argument *triangle* is a tuple with three elements each
element consisting of a tuple of X,Y coordinates.
It works like this:
Walk clockwise or counterclockwise around the triangle
and project the point onto the segment we are crossing
by using the dot product.
Finally, check that the vector created is on the same side
for each of the triangle's segments.
"""
# Unpack arguments
x, y = point
ax, ay = triangle[0]
bx, by = triangle[1]
cx, cy = triangle[2]
# Segment A to B
side_1 = (x - bx) * (ay - by) - (ax - bx) * (y - by)
# Segment B to C
side_2 = (x - cx) * (by - cy) - (bx - cx) * (y - cy)
# Segment C to A
side_3 = (x - ax) * (cy - ay) - (cx - ax) * (y - ay)
# All the signs must be positive or all negative
return (side_1 < 0.0) == (side_2 < 0.0) == (side_3 < 0.0)
###############################################################################
class TestPointInTriangle(unittest.TestCase):
triangle = ((22 , 8),
(12 , 55),
(7 , 19))
def test_inside(self):
point = (15, 20)
self.assertTrue(point_in_triangle(point, self.triangle))
def test_outside(self):
point = (1, 7)
self.assertFalse(point_in_triangle(point, self.triangle))
def test_border_case(self):
"""If the point is exactly on one of the triangle's edges,
we consider it is inside."""
point = (7, 19)
self.assertTrue(point_in_triangle(point, self.triangle))
###############################################################################
if __name__ == "__main__":
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestPointInTriangle)
unittest.TextTestRunner().run(suite)
上述算法还有一个可选的图形测试,以确认其有效性:
import random
from matplotlib import pyplot
from triangle_test import point_in_triangle
###############################################################################
# The area #
size_x = 64
size_y = 64
# The triangle #
triangle = ((22 , 8),
(12 , 55),
(7 , 19))
# Number of random points #
count_points = 10000
# Prepare the figure #
figure = pyplot.figure()
axes = figure.add_subplot(111, aspect='equal')
axes.set_title("Test the 'point_in_triangle' function")
axes.set_xlim(0, size_x)
axes.set_ylim(0, size_y)
# Plot the triangle #
from matplotlib.patches import Polygon
axes.add_patch(Polygon(triangle, linewidth=1, edgecolor='k', facecolor='none'))
# Plot the points #
for i in range(count_points):
x = random.uniform(0, size_x)
y = random.uniform(0, size_y)
if point_in_triangle((x,y), triangle): pyplot.plot(x, y, '.g')
else: pyplot.plot(x, y, '.b')
# Save it #
figure.savefig("point_in_triangle.pdf")
产生以下图形:
答案 15 :(得分:1)
我只是想用一些简单的矢量数学来解释安德烈斯给出的重心坐标解,这将更容易理解。
(1-S)的 | v0v2 | / | v0v2 | = tp | v0v1 | / | v0v1 |
我们得到1 - s = tp,然后1 = s + tp。如果有任何t> tp,其中1 < s + t在双虚线上,矢量在三角形之外,任何t <= tp,其中1> = s + t,其中在单虚线上,矢量在三角形内。
然后,如果我们在[0,1]中给出任何s,对应的t必须满足1> = s + t,对于三角形内的向量。
最后我们得到v = s * v02 + t * v01,v是条件s内的三角形,t,s + t属于[0,1]。然后转换为点,我们有
p - p0 = s *(p1 - p0)+ t *(p2 - p0),[0,1]中的s,t,s + t
这与安德烈斯解决方程式系统的解决方案相同 p = p0 + s *(p1-p0)+ t *(p2-p0),s,t,s + t属于[0,1]。
答案 16 :(得分:0)
最简单的方法是它适用于所有类型的三角形,只需确定P点A,B,C点角度的角度即可。如果任何角度大于180.0度那么它在外面,如果180.0然后它在圆周上并且如果acos欺骗你并且小于180.0然后它在里面。看看理解http://math-physics-psychology.blogspot.hu/2015/01/earlish-determination-that-point-is.html
答案 17 :(得分:0)
老实说它就像Simon P Steven's answer一样简单,但是通过这种方法,您无法确定是否要包含三角形边缘上的点。
我的方法有点不同但非常基本。考虑以下三角形;
为了得到三角形中的点,我们必须满足3个条件
在此方法中,您可以完全控制单独包含或排除边缘上的点。因此,您可以检查一个点是否在三角形中,仅包括| AC |例如,边缘。
所以我的JavaScript解决方案如下:
function isInTriangle(t,p){
function isInBorder(a,b,c,p){
var m = (a.y - b.y) / (a.x - b.x); // calculate the slope
return Math.sign(p.y - m*p.x + m*a.x - a.y) === Math.sign(c.y - m*c.x + m*a.x - a.y);
}
function findAngle(a,b,c){ // calculate the C angle from 3 points.
var ca = Math.hypot(c.x-a.x, c.y-a.y), // ca edge length
cb = Math.hypot(c.x-b.x, c.y-b.y), // cb edge length
ab = Math.hypot(a.x-b.x, a.y-b.y); // ab edge length
return Math.acos((ca*ca + cb*cb - ab*ab) / (2*ca*cb)); // return the C angle
}
var pas = t.slice(1)
.map(tp => findAngle(p,tp,t[0])), // find the angle between (p,t[0]) with (t[1],t[0]) & (t[2],t[0])
ta = findAngle(t[1],t[2],t[0]);
return pas[0] < ta && pas[1] < ta && isInBorder(t[1],t[2],t[0],p);
}
var triangle = [{x:3, y:4},{x:10, y:8},{x:6, y:10}],
point1 = {x:3, y:9},
point2 = {x:7, y:9};
console.log(isInTriangle(triangle,point1));
console.log(isInTriangle(triangle,point2));
&#13;
答案 18 :(得分:0)
bool isInside( float x, float y, float x1, float y1, float x2, float y2, float x3, float y3 ) {
float l1 = (x-x1)*(y3-y1) - (x3-x1)*(y-y1),
l2 = (x-x2)*(y1-y2) - (x1-x2)*(y-y2),
l3 = (x-x3)*(y2-y3) - (x2-x3)*(y-y3);
return (l1>0 && l2>0 && l3>0) || (l1<0 && l2<0 && l3<0);
}
它不能比这更有效!三角形的每一边可以具有独立的位置和方向,因此有三个计算:l1,l2和l3肯定需要每次涉及2次乘法。一旦知道了l1,l2和l3,结果只是一些基本的比较和布尔运算。
答案 19 :(得分:0)
据称我在JavaScript中修改了高性能代码(下面的文章):
function pointInTriangle (p, p0, p1, p2) {
return (((p1.y - p0.y) * (p.x - p0.x) - (p1.x - p0.x) * (p.y - p0.y)) | ((p2.y - p1.y) * (p.x - p1.x) - (p2.x - p1.x) * (p.y - p1.y)) | ((p0.y - p2.y) * (p.x - p2.x) - (p0.x - p2.x) * (p.y - p2.y))) >= 0;
}
pointInTriangle(p,p0,p1,p2) - 对于逆时针三角形
pointInTriangle(p,p0,p1,p2) - 对于顺时针三角形
查看jsFiddle(包括性能测试),还可以在单独的函数中进行检查 http://jsfiddle.net/z7x0udf7/3/
答案 20 :(得分:0)
由于没有JS回答,
顺时针&amp;逆时针解决方案:
function triangleContains(ax, ay, bx, by, cx, cy, x, y) {
let det = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax)
return det * ((bx - ax) * (y - ay) - (by - ay) * (x - ax)) > 0 &&
det * ((cx - bx) * (y - by) - (cy - by) * (x - bx)) > 0 &&
det * ((ax - cx) * (y - cy) - (ay - cy) * (x - cx)) > 0
}
编辑:有一个输入错误的计算错误(cy - ay
而不是cx - ax
),这是固定的。
答案 21 :(得分:0)
这是确定点是在三角形的内部还是外部或在三角形的手臂上的最简单概念。 Determination of a point is inside a tringle by determinants
最简单的工作代码: `
#-*- coding: utf-8 -*-
import numpy as np
tri_points = [(1,1),(2,3),(3,1)]
def pisinTri(point,tri_points):
Dx , Dy = point
A,B,C = tri_points
Ax, Ay = A
Bx, By = B
Cx, Cy = C
M1 = np.array([ [Dx - Bx, Dy - By, 0],
[Ax - Bx, Ay - By, 0],
[1 , 1 , 1]
])
M2 = np.array([ [Dx - Ax, Dy - Ay, 0],
[Cx - Ax, Cy - Ay, 0],
[1 , 1 , 1]
])
M3 = np.array([ [Dx - Cx, Dy - Cy, 0],
[Bx - Cx, By - Cy, 0],
[1 , 1 , 1]
])
M1 = np.linalg.det(M1)
M2 = np.linalg.det(M2)
M3 = np.linalg.det(M3)
print(M1,M2,M3)
if(M1 == 0 or M2 == 0 or M3 ==0):
print("Point: ",point," lies on the arms of Triangle")
elif((M1 > 0 and M2 > 0 and M3 > 0)or(M1 < 0 and M2 < 0 and M3 < 0)):
#if products is non 0 check if all of their sign is same
print("Point: ",point," lies inside the Triangle")
else:
print("Point: ",point," lies outside the Triangle")
print("Vertices of Triangle: ",tri_points)
points = [(0,0),(1,1),(2,3),(3,1),(2,2),(4,4),(1,0),(0,4)]
for c in points:
pisinTri(c,tri_points)
`
答案 22 :(得分:-1)
bool point2Dtriangle(double e,double f, double a,double b,double c, double g,double h,double i, double v, double w){
/* inputs: e=point.x, f=point.y
a=triangle.Ax, b=triangle.Bx, c=triangle.Cx
g=triangle.Ay, h=triangle.By, i=triangle.Cy */
v = 1 - (f * (b - c) + h * (c - e) + i * (e - b)) / (g * (b - c) + h * (c - a) + i * (a - b));
w = (f * (a - b) + g * (b - e) + h * (e - a)) / (g * (b - c) + h * (c - a) + i * (a - b));
if (*v > -0.0 && *v < 1.0000001 && *w > -0.0 && *w < *v) return true;//is inside
else return false;//is outside
return 0;
}
几乎完美的笛卡尔坐标从重心转换而来 在* v(x)和* w(y)内输出双倍。 在每种情况下,两个导出双精度都应该有* char,可能是:* v和* w 代码也可以用于四边形的另一个三角形。 签约时,签名只写了顺时针abcd四边形的三角形abc。
A---B
|..\\.o|
|....\\.|
D---C
o点在ABC三角形内
使用第二个三角形进行测试时调用此函数CDA方向,并且*v=1-*v;
和*w=1-*w;
之后的结果应该是正确的四边形
答案 23 :(得分:-1)
我需要点三角形检查&#34;可控环境&#34;当你完全确定三角形是顺时针方向时。所以,我采用了 Perro Azul 的jsfiddle,并按照 coproc 的建议修改了这些案例;还删除了冗余的0.5和2乘法,因为它们只是相互抵消。
http://jsfiddle.net/dog_funtom/H7D7g/
以下是Unity的等效C#代码:
public static bool IsPointInClockwiseTriangle(Vector2 p, Vector2 p0, Vector2 p1, Vector2 p2)
{
var s = (p0.y * p2.x - p0.x * p2.y + (p2.y - p0.y) * p.x + (p0.x - p2.x) * p.y);
var t = (p0.x * p1.y - p0.y * p1.x + (p0.y - p1.y) * p.x + (p1.x - p0.x) * p.y);
if (s <= 0 || t <= 0)
return false;
var A = (-p1.y * p2.x + p0.y * (-p1.x + p2.x) + p0.x * (p1.y - p2.y) + p1.x * p2.y);
return (s + t) < A;
}
答案 24 :(得分:-1)
one of the easiest ways to check if the area formed by the vertices of triangle
(x1,y1),(x2,y2),(x3,y3) is postive or not .
area can by calculated by the formula.
1/ 2 [x1(y2–y3) + x2 (y3–y1) + x3 (y1–y2)]
or python code can be written as:-
def triangleornot(p1,p2,p3):
return (1/ 2) [p1[0](p2[1]–p3[1]) + p2[0] (p3[1]–p1[1]) + p3[0] (p1[0]–p2[0])]