`

[演示] 判断点是否处于三角形内的算法分析

阅读更多

http://bbs.wow8.org/thread-94298-1-1.html

 

由于某些特殊需求,有时候需要判断一个点是不是在某一个三角形内面.虽然这样的情况很少,而且不是必须的,但既然有人提到了,还是说说相应的解决方法.

在接触问题之前,有必要先复习一下初中的平面解析几何知识:直线的代数解析式.
(1)斜截式 y=Kx+b
(2)点斜式 y-y1=K(x-x1)
(3)两点式 y-y1=(y2-y1)/(x2-x1)*(x-x1)=(x-x1)*(y2-y1)/(x2-x1)   (x1!=x2) 
其中,在式(1)中,K代表直线的斜率,b代表直线在Y坐标轴上的截距,也就是直线与Y轴交点的纵坐标;
在式(2)中,(x1,y1)是直线经过的一个点,K是直线的斜率;
在式(2)中,(x1,y1)和(x2,y2)是直线经过的两个点,且x1不等于x2;

在平面解析几何中,常常要判断一点与一条直线的位置关系.说到位置关系,无外乎三种:在直线上,在直线上方,在直线下方.
在数学上,判断这种关系的方法是将点的坐标带入直线解析式,然后观察结果正负.
步骤(1):将直线解析式稍微做个变换,将所有项都移动到左边,例如: y-Kx+b=0; y-y1-K(x-x1)=0; y-y1-(x-x1)*(y2-y1)/(x2-x1)=0
步骤(2):将点的坐标值带入上面的式子,计算结果;
步骤(3):如果最终结果等于0,说明点在直线上;如果最终结果大于0,说明点在直线上方;如果最终结果小于0,说明点在直线下方;

在Jass中,上面的过程可以写成这样的函数(Lx1!=Lx2,之所以不考虑相等的情况,是因为用不上,而且考虑的话,情况会变得非常复杂):

 + Shingo Jass Highlighter 0.41

//参数意义: 
//(Lx1,Ly1),(Lx2,Ly2)是成对的,L前缀表示这是直线上的点的坐标,因为在WE中,我们很多情况都是通过点来确定直线的,直接使用斜率的相对较少 
//(checkX,checkY),顾名思义,这就是要检测的点的坐标值 

//判断是否在直线上 
function IsOn takes real Lx1, real Ly1, real Lx2, real Ly2, real checkX, real checkY returns boolean 
    if (checkY-Ly1-(checkX-Lx1)*(Ly2-Ly1)/(Lx2-Lx1))==0 then 
        return true 
    endif 
    return false 
endfunction 

//判断是否在函数上方 
function IsAbove takes real Lx1, real Ly1, real Lx2, real Ly2, real checkX, real checkY returns boolean 
    if (checkY-Ly1-(checkX-Lx1)*(Ly2-Ly1)/(Lx2-Lx1))>0 then 
        return true 
    endif 
    return false 
endfunction 

//判断是否在函数下方 
function IsBelow takes real Lx1, real Ly1, real Lx2, real Ly2, real checkX, real checkY returns boolean 
    if (checkY-Ly1-(checkX-Lx1)*(Ly2-Ly1)/(Lx2-Lx1))<0 then 
        return true 
    endif 
    return false 
endfunction


当然,真正用的时候,我们不可能写三个分散的函数,而是用一个代替: 

 + Shingo Jass Highlighter 0.41
function GetPositionRelation takes real Lx1, real Ly1, real Lx2, real Ly2, real checkX, real checkY returns integer 
    //为了避免误使用Lx1==Lx2来调用这个函数,我们对数据稍微做下改变 
    if Lx1==Lx2 then 
        set Lx2=Lx2+1       //偏移一下下,看不出来的 
    endif 

    if (checkY-Ly1-(checkX-Lx1)*(Ly2-Ly1)/(Lx2-Lx1))>0 then 
        return 1 
    elseif (checkY-Ly1-(checkX-Lx1)*(Ly2-Ly1)/(Lx2-Lx1))<0 then 
        return -1 
    else 
        return 0 
    endif 
endfunction


函数返回1,说明在直线上方,返回-1,说明在直线下方,返回0,说明在直线上. 

对于固定的一个三角形,要判断一个点在不在它里面很简单:将点的坐标带入三条边的代数解析式计算,然后根据结果正负值即可知其位置关系.但是若三角形不确定(可以自由旋转或者可以改变大小),那么再带入计算,你就会发现....需要考虑的情况太多了!!!

在一个平面上,任意两两相交的直线把平面分成7个区域,假设三个交点分别是(x1,y1),(x2,y2),(x3,y3),三条直线分别为L12,L23,L13.
假设有一个点是(x,y),我们设三个整数变量,分别等于

 + Shingo Jass Highlighter 0.41
local integer I12=GetPositionRelation(x,y,x1,y1,x2,y2) 
local integer I23=GetPositionRelation(x,y,x2,y2,x3,y3) 
local integer I13=GetPositionRelation(x,y,x1,y1,x3,y3)

 


那么I12*I23*I13的值也是三种情况:等于0,等于1,或者等于-1.
对于不同的三角形,不同的位置关系,这个值是不定的.
对于不同的三角形,即使位置关系相同,这个值也不一定相等,关键还得看三角形本身.
这样一来,通过F(x,y)=I12*I23*I13来确定点和三角形位置关系的想法破灭了,我们只能从长计议..
尽管如此,我们可以肯定的一点是:当一个点位于三角形三个角所对的区域时,函数F(x,y)的值等于点在三角形内时的值.
(很遗憾,由于某种不明的原因,我始终不能上传图片....也许这里有些地方讲得不是很清楚,你们还是自己在纸上画一下吧.)

下面结合一个具体的例子来讲讲我的两种解法:判断任意一个点是否在一个可以自由旋转角度和改变大小的等腰三角形里面.

困难在哪里:假如说这个三角形是等边三角形,原来有一个顶角竖直向上,底边与X轴平行.这时候来判断三角形内部的点的坐标的话,应该是在底边上方,而在两个侧边下方.如果将三角形绕底边的终点顺时针旋转45°,再来判断会是怎样的呢?囧了,这时候是底边和右侧边上方,左侧边下方了... 复杂之处不仅仅在这一个象限,如果将三角形的顶角转到指向第二象限,你会发现同样的情况,然后还有第三,第四象限....Oh,my god!!!越来越复杂了...

[ 本帖最后由 cctvfive 于 2009-3-27 20:05 编辑 ]

 

 

 

 

 

方法一:旋转法

对于一个等腰三角形,如果都能将其底边转到与X轴平行,而且顶角朝上,那么事情就变得简单了:点位于底边上方,两条侧边下方.下面就开始我们的旋转算法.

假设一点A(x,y),坐标原点为O,那么将向量OA(抱歉,没法画上面那个箭头)沿顺时针方向旋转α角度之后,新的A'点坐标为(x',y').

  1. L=(x*x+y*y)^0.5
  2. x=L*Cosθ
  3. y=L*Sinθ
  4. x'=L*Cos(θ-α)=L*Cosθ*Cosα+L*Sinθ*Sinα=x*Cosα+y*Sinα
  5. y'=L*Sin(θ-α)=L*Sinθ*Cosα-L*Cosθ*Sinα=y*Cosα-x*Sinα
复制代码


如果不是绕原点旋转的,那么上面的x和y都是相对坐标,使用时要切换到绝对坐标.
假设旋转中心坐标为M(Xm,Ym),旋转前点A坐标为(Ax,Ay),旋转后为B(Bx,By).
那么在上面的式子中,

  1. x=Ax-Mx
  2. y=Ay-My
  3. x'=Bx-Mx
  4. y'=By-My
  5. 于是有:
  6. Bx-Mx=(Ax-Mx)*Cosα+(Ay-My)*Sinα
  7. By-My =(Ay-My)*Cosα-(Ax-Mx)*Sinα
复制代码


看起来很复杂....不过还好,我们这里用的时候会化简..

 + Shingo Jass Highlighter 0.41
function IsInTriangle takes real startX, real startY, real face, real L, real H ,real checkX, real checkY returns boolean 
    local real angle=face-90       //要旋转的角度,旋转后三角形处于最容易分析的角度 
     
    //Left_Point 
    //Ax-Mx=-L*SinBJ(face) 
    //Ay-My= L*CosBJ(face) 
    //local real Leftx=startX-L*SinBJ(face) 
    //local real Lefty=startY+L*CosBJ(face) 
     
    local real Left_x=startX-L*SinBJ(face)*CosBJ(angle)+L*CosBJ(face)*SinBJ(angle) 
    local real Left_y=startY+L*CosBJ(face)*CosBJ(angle)+L*SinBJ(face)*SinBJ(angle) 
     
    //Right_Point 
    //Ax-Mx= L*SinBJ(face) 
    //Ay-My=-L*CosBJ(face) 
    //local real Rightx=startX+L*SinBJ(face) 
    //local real Righty=startX-L*CosBJ(face) 
     
    local real Right_x=startX+L*SinBJ(face)*CosBJ(angle)-L*CosBJ(face)*SinBJ(angle) 
    local real Right_y=startY-L*CosBJ(face)*CosBJ(angle)-L*SinBJ(face)*SinBJ(angle) 
     
    //Top_Point 
    //Ax-Mx=H*CosBJ(face) 
    //Ay-My=H*SinBJ(face) 
    //local real Topx=startX+H*CosBJ(face) 
    //local real Topy=startY+H*SinBJ(face) 
     
    local real Top_x=startX+H*CosBJ(face)*CosBJ(angle)+H*SinBJ(face)*SinBJ(angle) 
    local real Top_y=startY+H*SinBJ(face)*CosBJ(angle)-H*CosBJ(face)*SinBJ(angle) 
     
    //Check_Point 
    //Ax-Mx=checkX-startX 
    //Ay-My=checkY-startY 
    local real Check_x=startX+(checkX-startX)*CosBJ(angle)+(checkY-startY)*SinBJ(angle) 
    local real Check_y=startY+(checkY-startY)*CosBJ(angle)-(checkX-startX)*SinBJ(angle) 

    if GetPositionRelation(Left_x,Left_y,Right_x,Right_y,Check_x,Check_y)>=0 and GetPositionRelation(Left_x,Left_y,Top_x,Top_y,Check_x,Check_y)<=0 and GetPositionRelation(Right_x,Right_y,Top_x,Top_y,Check_x,Check_y)<=0 then 
        return true 
    endif 
    return false 
endfunction




方法二:未命名~~~

上面那个方法稍微有点复杂,下面介绍个更加简单的..

在等腰三角形的底边上的高上任取一点P,那么P点必定在三角形内面,这点毋庸质疑.如果给定一个点,它与点P处于三角形三条边的同侧,那么我们可以肯定,这个点也在三角形内部...基本思路就是这些,下面是函数实现方法,为了方便计算,我们取p为高的中点.
 + Shingo Jass Highlighter 0.41

//(Lx1,Ly1),(Lx2,Ly2)为直线通过的两个点的坐标,因为魔兽中使用直线都是通过点来确定的 
//(Px,Py)为要检测的点的坐标,返回值表示了该点与直线的位置关系 
function GetPositionRelation takes real Lx1, real Ly1, real Lx2, real Ly2, real Px, real Py returns integer 
    //为了防止误使用Lx1==Lx2的参数来调用这个函数,对这种情况的数值做个小小的处理 
    if Lx1==Lx2 then 
        set Lx2=Lx2+1.0     //微小的偏移在魔兽中感觉不出来 
    endif 

    if (Py-Ly1-(Px-Lx1)*(Ly2-Ly1)/(Lx2-Lx1))>0 then               //如果在直线上方,则返回1 
        return 1 
    elseif (Py-Ly1-(Px-Lx1)*(Ly2-Ly1)/(Lx2-Lx1))<0 then        //如果在直线下方,则返回1 
        return -1 
    else                                                                                  //如果在直线上,则返回0 
        return 0 
    endif 
endfunction 

//(Lx1,Ly1),(Lx2,Ly2)为直线通过的两个点的坐标,(Px1,Py1),(px2,Py2)是要判断的两个点 
//返回值为TRUE说明两个点在直线同侧,返回FALSE说明点在直线两侧(在直线上被划分到同侧的范围) 
function IsSameSide takes real Lx1, real Ly1, real Lx2, real Ly2, real Px1, real Py1, real Px2, real Py2 returns boolean 
    if Lx1==Lx2 then         //竖直方向的直线  
        if (Px1-Lx1)*(Px2-lx1)>=0 then    //直线同一侧  
            return true 
        endif 
        return false 
    endif 
    return GetPositionRelation(Lx1,Ly1,Lx2,Ly2,Px1,Py1)==GetPositionRelation(Lx1,Ly1,Lx2,Ly2,Px2,Py2) 
endfunction 

//(startX,startY)是三角形底边中点坐标,L是向两侧延伸的距离,也就是底边长度的一半,H是向前方延伸的距离,也就是底边上的高 
//(checkX,checkY)为要检测的点,函数返回TRUE说明点(checkX,checkY)在三角形内,返回FALSE说明在三角形之外 
//点在三角形上包含在之内 
function IsInTriangle takes real startX, real startY, real face, real L, real H ,real checkX, real checkY returns boolean 
    local real Mid_x     =startX+0.5*H*CosBJ(face) 
    local real Mid_y     =startY+0.5*H*SinBJ(face) 
    local real Left_x   =startX-L*SinBJ(face) 
    local real Left_y   =startY+L*CosBJ(face) 
    local real Right_x  =startX+L*SinBJ(face) 
    local real Right_y  =startY-L*CosBJ(face) 
    local real Top_x    =startX+H*CosBJ(face) 
    local real Top_y    =startY+H*SinBJ(face) 
    local boolean B12=IsSameSide(Left_x,Left_y,Right_x,Right_y,Mid_x,Mid_y,checkX,checkY) 
    local boolean B13=IsSameSide(Left_x,Left_y,Top_x,Top_y,Mid_x,Mid_y,checkX,checkY) 
    local boolean B12=IsSameSide(Right_x,Right_y,Top_x,Top_y,Mid_x,Mid_y,checkX,checkY) 
    return (B12 and b13 and B23)  
endfunction 

//简化参数,u是施法单位,L和H意义同上,testUnit为一任意单位,如果该单位在三角形内(或之上),返回TRUE,否则返回FALSE 
function IsUnitInUnitTriangle takes unit u, real L, real H, unit testUnit returns boolean 
    return  IsInTriangle(GetUnitX(u),GetUnitY(u),GetUnitFacing(u),L,H,GetUnitX(testUnit),GetUnitY(testUnit)) 
endfunction

 

 

 

 

方法还有几种,例如向量乘法,判断镜像点距离...考虑到Jass和编图者的承受能力,就不一一列出了.如果你还想到了更好更简便的方法,欢迎发上来大家一起交流.

附件的演示是对单位正前方三角形区域内

分享到:
评论

相关推荐

    判断点是否在给定三角形内的matlab程序

    本文详细介绍了MATLAB中判断点是否位于给定三角形内部的相关知识,包括MATLAB的基本概念、三角形内点判断算法的实现细节以及与Delaunay插值的关系。此外,还探讨了该算法的实际应用场景,并提供了一些测试案例的设计...

    判断该点是否在三角形内

    根据给定的信息,本文将详细解释一种用于判断一个点是否位于一个三角形内部的方法,并对提供的代码片段进行分析,进一步阐述其背后的逻辑和技术要点。 ### 标题:判断该点是否在三角形内 该标题明确指出了解决的...

    判断一点是否在三角形内

    在计算机图形学中,判断一个点是否位于一个三角形内部是一项基本任务,广泛应用于游戏开发、图像处理等领域。本主题将详细讲解如何使用C++和OpenCV 2.2库来实现这一功能。OpenCV(Open Source Computer Vision ...

    判断一个点是否在三角形之内 java版

    请判断该点是否在三角形内部 * * 输入格式:共2行数据,第一行是以空格为分隔符的数组,共6个元素,分别表示三个点的坐标。第二行是 以空格为分隔符的数组,共2个元素,表示另外点的坐标 * * 输出格式:共1行...

    判断点是否在三角形内

    6. **拓展应用**:这个算法不仅可以用于单个点的判断,还可以扩展到多点集,比如判断一个点集合是否全部位于三角形内部,或者用于三角剖分等更复杂的几何计算。 综上所述,通过理解几何原理并结合C#编程,我们可以...

    判断一个点是否在三角形内的几种算法(2D).

    总结来说,判断点在三角形内的两种2D算法分别基于三角形面积的计算和矢量叉积的性质。通过这些方法,我们可以高效地确定一个点是否属于给定的二维三角形。在实际应用中,这两种算法都可以用于图形处理、碰撞检测等...

    cocos2dx判断点是否在三角形内、点到线段的距离、线段和线段是否相交.zip

    在Cocos2dx游戏开发中,常常需要进行各种几何图形的操作,例如判断点是否在三角形内部、计算点到线段的距离以及判断两条线段是否相交。这些基础的数学运算对于构建游戏逻辑和碰撞检测至关重要。下面我们将详细讨论...

    判断平面上一点是否在三角形内

    在计算机图形学中,判断平面上的...总结一下,判断平面上一点是否在三角形内是一个基础但重要的计算机图形学问题,可以通过向量法或射线法来解决。理解并实现这样的算法有助于提升我们在几何计算和空间定位方面的技能。

    符号三角形(算法分析)c++

    这种算法分析有助于理解分治策略、递归、动态规划以及数组和循环的使用,是编程初学者和进阶者都需要掌握的重要技能。在实际项目中,这些基本概念和技巧会被广泛应用于各种算法设计和问题求解中。

    判断一个点在三角形内 vc

    ### 知识点:判断一个点是否位于三角形内部 #### 概述 在计算机图形学、游戏开发以及几何计算领域中,判断一个点是否位于一个三角形内部是一项常见的任务。这种判断通常用于碰撞检测、光线追踪算法以及地图编辑器...

    用java编写有关判断是否为三角形

    根据给定的信息,我们...通过以上分析,我们可以看到,给定的代码片段虽然尝试实现了三角形判断的功能,但在代码结构和逻辑处理上存在诸多问题。通过对Java基础知识的学习和理解,我们可以更好地理解和改进这段代码。

    jsp 判断是否能为三角形

    在这个特定的案例中,"jsp 判断是否能为三角形"是一个简单的JSP应用程序,它的目标是接收用户输入的三个数,并判断这些数是否可以构成一个三角形。 首先,我们需要理解构成三角形的基本条件。根据三角形的几何定义...

    9种三角形的算法,各式各样的三角形

    9种三角形的算法,方便程序的开发。9种三角形的算法,方便程序的开发。9种三角形的算法,方便程序的开发。

    判断一系列坐标点是否在封闭图形内

    本篇将详细讲解如何利用Matlab来实现这个功能,特别是判断一个点是否在三角形内的算法。 首先,我们需要理解基本的几何概念。一个封闭图形是由多个顶点(坐标点)通过线段连接形成的,如三角形、四边形等。在二维...

    判断三角形形状程序 判断三角形形状程序

    首先检查边长是否在合理的范围内(0至100之间),然后应用三角形的成立条件进行判断。最后,根据边长关系确定三角形的类型并输出结果。 ### 总结 该程序通过一系列的条件判断,有效地实现了对三角形类型的基本识别...

    判断三角形是什么样的三角形

    在计算机编程领域,判断三角形的类型是一项基础但重要的任务,尤其在图形学、几何算法以及游戏开发中有着广泛的应用。本主题将深入探讨如何通过编程来识别等腰三角形、直角三角形和等边三角形。我们将依据标题"判断...

    VB三角形判断 (if)

    在VB(Visual Basic)编程中,实现三角形的判断是一个基础但重要的概念,它涉及到条件语句、算术运算和几何知识。以下是对这个话题的详细讲解: 首先,要理解三角形的基本性质:任何三角形的任意两边之和必须大于第...

    基于三角形匹配的星图识别算法及优化

    星图识别算法中三角形算法应用最为成熟和广泛,但作为算法识别基元的三角形由于特征维数低,导致冗余匹配和错误识别几乎不可避免。鉴于传统三角形算法识别成功率较低,新算法对传统算法进行了针对性改进,增加了检测...

    java 根据三条边判断三角形的类型,并绘制出三角形

    在Java编程中,根据给定的三条边来判断三角形的类型并绘制三角形涉及到一些基本的几何概念和编程技巧。下面将详细讲解这个过程。 首先,我们需要理解三角形的基本性质。一个三角形是由三条边和三个角组成的图形。...

    aabb_三角形相交_网格快速判断_saildrp_三角形相交_AABB_

    3. `Intersect`函数:用于判断AABB与三角形是否相交。它可能会包括以下几个步骤: - 首先,计算三角形的边界框(也是AABB),并与目标AABB进行比较。如果它们没有重叠,那么可以立即返回不相交。 - 其次,考虑...

Global site tag (gtag.js) - Google Analytics