1.利用三角形ABC面积,1/2*|A||B|Sin(a); 任意一点P,分别向三角形(A,B,C)三个顶点连线,形成三个三角形(PAB,PBC,PAC)。如果S(ABC)==S(PAB)+S(PBC)+S(PAC),则点在三角形内,反之,在三角形外
2.判断点是否在三条边的同一层
先说一下叉乘:
设矢量P = (x1,y1) ,Q = (x2,y2)
则矢量叉积定义为: P × Q = x1*y2 – x2*y1 得到的是一个标量
显然有性质 P × Q = – ( Q × P ) P × ( – Q ) = – ( P × Q )
如不加说明,下面所有的点都看作矢量,点的乘法看作矢量叉积;
叉乘的重要性质:
 若 P × Q > 0 , 则P 在Q的顺时针方向
 若 P × Q < 0 , 则P 在Q的逆时针方向
 若 P × Q = 0 , 则P 与Q共线,但可能同向也可能反向
我提出的算法中有一步要判断顺时针逆时针的方向,其实很简单。假设有两端连续的险段,其公共端点是P0,其他的两个端点是P1和P1,计算向量
<P0,P1> 和 <P0,P2> 的叉乘,如果若结果为正,则 <P0,P1> 在
<P0,P2> 的顺时针方向;若为0则 <P0,P1> <P0,P2> 共线(可能同向和反向);若为负则
<P0,P1> 在 <P0,P2>
的在逆时针方向。因此可以根据这个判断p0p1和p1p2在p1处是左转还是右转,只要求(p2-p0)*(p1-p0),若
<0则左转,> 0则右转,=0则共线。
下面的简单的函数可以计算叉乘。
#define infinity 1e20
#define EP 1e-10
struct TPoint {
float x,y;
};
struct TLineSeg {
TPoint a,b;
};
/******************************************************** *
* 返回(P1-P0)*(P2-P0)的叉积。
* 若结果为正,则 <P0,P1> 在 <P0,P2> 的顺时针方向;
* 若为0则 <P0,P1> <P0,P2> 共线;
* 若为负则 <P0,P1> 在 <P0,P2> 的在逆时针方向;
* 可以根据这个函数确定两条线段在交点处的转向,
* 比如确定p0p1和p1p2在p1处是左转还是右转,只要求
* (p2-p0)*(p1-p0),若 <0则左转,> 0则右转,=0则共线
*
\********************************************************/
float multiply(TPoint p1, TPoint p2, TPoint p0)
{
return ( ( p1.x - p0.x ) * ( p2.y -
p0.y ) - ( p2.x - p0.x ) * ( p1.y - p0.y )
);
}
叉乘还有很多用途,举例如下:
1。判断点在线段上
设点为Q,线段为P1P2 ,判断点Q在该线段上的依据是:
( Q – P1 ) × ( P2 – P1 ) = 0 且 Q 在以 P1,P2为对角顶点的矩形内
// 判断点p是否在线段l上
int online(TLineSeg l,TPoint p)
{
return( (multiply(l.b,p,l.a)==0)&&(
((p.x-l.a.x)*(p.x-l.b.x) <0 )||( (p.y-l.a.y)*(p.y-l.b.y) <0
)) );
}
2。判断两线段是否相交
我们分两步确定两条线段是否相交:
1.快速排斥试验
设以线段 P1P2 为对角线的矩形为R, 设以线段 Q1Q2 为对角线的矩形为T,如果R和T不相交,显然两线段不会相交;
2.跨立试验
如果两线段相交,则两线段必然相互跨立对方,如图1所示(可惜这里无法显示图:( )。在图1中,P1P2跨立Q1Q2 ,则矢量 (
P1 – Q1 ) 和( P2 – Q1 )位于矢量( Q2 – Q1 ) 的两侧,即
( P1 – Q1 ) × ( Q2 – Q1 ) * ( P2 – Q1 ) × ( Q2 – Q1 ) < 0
上式可改写成
( P1 – Q1 ) × ( Q2 – Q1 ) * ( Q2 – Q1 ) × ( P2 – Q1 ) > 0
当 ( P1 – Q1 ) × ( Q2 – Q1 ) = 0 时,说明 (
P1 – Q1 ) 和 ( Q2 – Q1 )共线,但是因为已经通过快速排斥试验,所以 P1
一定在线段 Q1Q2上;同理,( Q2 – Q1 ) ×( P2 – Q1 ) = 0
说明 P2 一定在线段 Q1Q2上。
所以判断P1P2跨立Q1Q2的依据是:
( P1 – Q1 ) × ( Q2 – Q1 ) * ( Q2 – Q1 ) × ( P2 – Q1 ) ≥ 0
同理判断Q1Q2跨立P1P2的依据是:
( Q1 – P1 ) × ( P2 – P1 ) * ( P2 – P1 ) × ( Q2 – P1 ) ≥ 0
至此已经完全解决判断线段是否相交的问题。
//确定两条线段是否相交
int intersect(TLineSeg u,TLineSeg v)
{
return( (max(u.a.x,u.b.x)> =min(v.a.x,v.b.x))&&
(max(v.a.x,v.b.x)> =min(u.a.x,u.b.x))&&
(max(u.a.y,u.b.y)> =min(v.a.y,v.b.y))&&
(max(v.a.y,v.b.y)> =min(u.a.y,u.b.y))&&
(multiply(v.a,u.b,u.a)*multiply(u.b,v.b,u.a)> =0)&&
(multiply(u.a,v.b,v.a)*multiply(v.b,u.b,v.a)> =0));
}