判断点是否在三角形内。是画三角形的重要方法,尤其是做游戏的程序员,这种算法值得收纳。
实验环境:Win10
实验工具:CodeBlocks
补充知识
- 判断点B是否在直线AC上,首先只要满足↑BA×↑BC=0,点B就在直线上,其次如果↑BA·↑BC<0说明B在线段AC内部。如果允许B与端点重合,则只要↑BA·↑BC≤0.
- 判断点A是否在三角形BCD内部。只要满足↑AB×↑AC,↑AC×↑AD和↑AD×↑AB同号即可,相当于沿顺时针或者逆时针绕三角形一圈时,点A始终出现在同一侧。
- 点积:↑a·↑b=a1b1+a2b2+a3b3=|↑a|·|↑b|cosx,x为两向量夹角。
- a·b>0 两向量方向基本相同,夹角在0°到90°之间
- a·b=0 两向量正交,相互垂直
- a·b<0 两向量方向基本相反,夹角在90°到180°之间
- 叉积:↑a×↑b=(a2b3-a3b2)↑i+(a3b1-a1b3)↑j+(a1b2-a2b1)↑k=|↑a|·|↑b|sinx↑n,↑n为↑a×↑b方向。
- 内容取自《ACM国际大学生程序设计竞赛·知识与入门》P143
面积法
如果点P在三角形ABC内,那么,三角形ABC的面积可以分解为三个小三角形PAB,PBC,PAC的面积之和。
求三角形面积我推荐两种方法:
- 海伦公式法求面积:S=sqrt(p*(p-a)(p-b)(p-c))
公式说明:a,b,c分别为三角形三边长,p为半周长,S为三角形的面积。
如果已知的是三角形abc的坐标就要先取两点距离得边长。
- 两点之间距离公式:|AB|=sqrt((x1-x2)(x1-x2)-(y1-y2)(y1-y2)),其中A(x1,y1),B(x2,y2).
几何向量积法求面积:我们知道向量积的几何意义就是求得到的平行四边形的面积,而平行四边形的一半就是三角形的面积,通过这个原理就知道求三角形面积的方法。
- 公式S=(x2-x1)(y3-y2)-(x3-x2)(y2-y1),其中A(x1,y1),B(x2,y2),C(x3,y3).
注:在求面积的过程中,要注意精度问题。
以下面积法实验测试用的第二种算面积的公式实验效果图
实验代码
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
float CalSquar(int x1,int y1,int x2,int y2,int x3,int y3)
{
return fabs(((x2-x1)*(y3-y2)-(y2-y1)*(x3 - x2)))/ 2.0f;
}
bool IsInTri(int x1,int y1,int x2,int y2,int x3,int y3,int x,int y)
{
float S, S1, S2, S3;
S = CalSquar(x1,y1,x2,y2,x3,y3);
S1 = CalSquar(x1,y1,x,y,x2,y2);
S2 = CalSquar(x2,y2,x,y,x3,y3);
S3 = CalSquar(x1,y1,x,y,x3,y3);
float Sum = S1 + S2 + S3;
if ((-1e-5 < (S - Sum)) && ((S - Sum) < 1e-5))
return true;
else return false;
}
int main(){
int x1=1,y1=1;
int x2=3,y2=5;
int x3=5,y3=1;
int x,y;
for(int i=0;i<=10;i++){
for(int j=0;j<=10;j++){
x=i,y=j;
if(IsInTri(x1,y1,x2,y2,x3,y3,x,y)){
printf("x");
}else printf(" ");
}
printf("\n");
}
return 0;
}
同向法
- 通过上图,我们知道要想点在三角形内,就要有点P和C在直线AB同侧,直线P和A在直线BC同侧,直线P和B在直线AC同侧。当同时满足时,P在三角形ABC内。
- 如果判断是否在同侧呢?线性规划知识我们知道。
- 直线方程为 (y-y1)(x1-x2)-(y1-y2)(x-x1)=0
- 当 (y-y1)(x1-x2)-(y1-y2)(x-x1)>0时,点(x,y)在直线的右侧
- 当 (y-y1)(x1-x2)-(y1-y2)(x-x1)<0时,点(x,y)在直线的左侧
- 通过这个我们就知道如何判断是否同侧了。
实验效果图
实验代码
注:d*q要注意精度问题。视情况定,如果最大可能情况d*q>int_max,那么会判错
#include <cstdio>
#include <cstring>
using namespace std;
bool IsInTri(int x1,int y1,int x2,int y2,int x3,int y3,int x,int y)
{
int d=(y-y1)*(x2-x1)-(y2-y1)*(x-x1);
int q=(y3-y1)*(x2-x1)-(y2-y1)*(x3-x1);
if(d*q<0) return false;
d=(y-y2)*(x3-x2)-(y3-y2)*(x-x2);
q=(y1-y2)*(x3-x2)-(y3-y2)*(x1-x2);
if(d*q<0) return false;
d=(y-y3)*(x1-x3)-(y1-y3)*(x-x3);
q=(y2-y3)*(x1-x3)-(y1-y3)*(x2-x3);
if(d*q<0) return false;
return true;
}
int main(){
int x1=1,y1=1;
int x2=2,y2=2;
int x3=3,y3=1;
int x,y;
for(int i=0;i<=10;i++){
for(int j=0;j<=10;j++){
x=i,y=j;
if(IsInTri(x1,y1,x2,y2,x3,y3,x,y)){
printf("x");
}else printf(" ");
}
printf("\n");
}
return 0;
}