判断点是否在三角形内

来源:互联网 发布:dnf辅助官网源码 编辑:程序博客网 时间:2024/06/05 04:28

判断点是否在三角形内。是画三角形的重要方法,尤其是做游戏的程序员,这种算法值得收纳。
实验环境: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;}
原创粉丝点击