精华内容
下载资源
问答
  • 判断一个点在三角形内,通过矢量的叉积判断一个是不是在三角形内,判断准确
  • 如何判断一点在三角形内

    千次阅读 2011-03-22 23:40:00
    一点在三角形内

    假定在右手坐标系中的三角形3点坐标为A,B,C,判断P是否在ABC之内

     

    ( 主要来自 3D引擎研发QQ群(38224573 )的各位朋友的讨论 ,我仅仅算做个总结吧,特别感谢各位朋友的热情支持。 )

     

    方法1:三个Perplane的方法

               设AB,BC,AC边上的垂直平面为Perplane[3],垂直朝向内侧的法向为n[3]

              1)先根据任意两边叉出法向N

                   N = AB.CrossProduct(AC); 

                   N.Normalize();

                   D = A.DotProduct( N );

              2)如果P在三角形所在平面之外,可直接判定不在平面之内( 假定方程为 ax+by+cz+d = 0 )

                   if( P.DotProduct( N ) + D > 0 ) return false; 

              3)然后法向和各边叉出垂直平面的法向

                   n[0] = N.CrossProduct(AB); //朝向内侧

                   n[0].Normalize();

                   Perplane[0].dist = A.DotProduct(n[0]);

                   Perplane[0].normal = n[0];

                   同样方法求得Perplane[1],Perlane[2];

              3)因为三个Perplane都朝向三角形内侧,P在三角形内的条件是同时在三个Perplane前面;如果给定点P在任意一个垂直平面之后,那么可判定P在三角形外部

                   for( int i = 0;i<3;j++ )

                   {

                        if( P.DotProduct( Perplane[i].normal ) + Perplane[i].dist < 0 )

                             return false;

                   }

                   return true;//如果P没有在任意一条边的外面,可判断定在三角形之内,当然包括在边上的情况

     

    方法2:三个部分面积与总面积相等的方法

     

              S(PAB) + S(PAC) + S( PBC) = S(ABC) 则判定在三角形之内

              用矢量代数方法计算三角形的面积为

                   S = 1/2*|a|*|b|*sin(theta)

                      = 1/2*|a|*|b|*sqrt(1-cos^2(theta))

                      = 1/2*|a|*|b|*sqrt(1- (a.DotProduct(b)/(|a|*|b|))^2);

     

                   另一种计算面积的方法是 S = 1/2*|a.CrossProduct(b)|

     

                   比较一下,发现后者的精确度和效率都高于前者,因为前者需要开方和求矢量长度,矢量长度相当于一次点乘,三个点乘加一个开方,显然不如

                   后者一次叉乘加一次矢量长度(注,一次叉乘计算相当于2次点乘,一次矢量长度计算相当于一次点乘),后者又对又快。

                    

                   S(ABC)  = AB.CrossProduct(AC);//*0.5;

                   S(PAB)  = PA.CrossProduct(PB);//*0.5;

                   S(PBC)  = PB.CrossProduct(PC);//*0.5;

                   S(PAC)  = PC.CrossProduct(PA);//*0.5;

     

                   if( S(PAB) + S(PBC) + S(PAC) == S(ABC)  )

                        return true;

                   return false;

              

            另一种计算三角形面积的矢量方法是 1/2*a.CrossProdcuct(b) ,CrossProduct = ( y1*z2 - y2*z1 , x1*z2 - x2*z1, x1*y2 - x2*z1 )

                   可以看到CrossProduct 的计算要比DotProduct多3个乘法计算,效率没有上面的方法高


    方法3:三个向量归一化后相加为0

     

            这个方法很怪异,发现自http://flipcode.spaces.live.com/blog/cns!8e578e7901a88369!903.entry 下面的一个回帖

                   
                   

              如上图三角形ABC,P为AB外侧一点,N1,N2,N3 分别为BP,AP,CP的归一化矢量;NM为N1,N2夹角的角平分线

              可以看出角A-P-B是三角形内角,必然小于180度,那么角N1-P-N2等于A-P-B;NM是N1-P-N2的角平分线,那么角B-P-N等于角N-P-A,而CPN必然小于其中一个,

              即小于180/2 = 90度。结论是角N1,N2的合矢量方向与N3的夹角为锐角。所以N1,N2,N3的合向量模大于1.

              这里注意,N3不一定在N1,N2之间,不能假定N2-P-N3 和N3-P-N1这两个角一定是锐角

              同样可以推导出如果P在三角形内,N1+N2+N3必然小于0;若N1+N2+N3 = 0则P在三角形的边上。

              有没有更简单的推导方法?

              

              这个方法看起来很精巧,但是善于优化的朋友会立刻发现,三个矢量归一化,需要三个开方。迭代式开方太慢了,而快速开方有的时候又不满足精度要求。

                      

     方法4:重心坐标之和为1

     

             {

                   BaryCenter = ( S(PAB)/S(PABC),S(PBC)/S(PABC),S(PAC)/S(PABC)) // 点P在三角形内的重心坐标

              

                   if( BaryCenter.x + BaryCenter.y + BaryCenter.z >0.f )

                        return false

                   return true;

              }

     

              其中S(PAB),S(ABC),S(PBC),S(PBC) 用上述的方法二种提到的计算三角形面积方法计算。 

     

    综合比较

         方法1必须求叉乘,虽然可以通过首先排除不在平面内的点,但是后面仍要求三个叉乘和3个点乘(当然还可排除法优化)

         方法2看起来之需要求4个点乘,如果用叉乘方法计算面积,可能会导致效率低下

         方法3是看起来是最精巧的方法,但是效率也不能保证...3个开方

         方法4和方法2的效率差不多

    展开全文
  • 如何判断一个点在三角形内部

    万次阅读 2016-05-17 15:31:04
    如何判断一个点在三角形内部基本思路如图,P在三角形ABC内部,可以通过以下三个条件判断: P和C直线AB同侧 P和B直线AC同侧 P和A直线BC同侧 如果以上三个条件同时满足,则P在三角形ABC内部。...

    如何判断一个点在三角形内部

    基本思路

    三角示例

    如图,点P在三角形ABC内部,可以通过以下三个条件判断:

    1. 点P和点C在直线AB同侧
    2. 点P和点B在直线AC同侧
    3. 点P和点A在直线BC同侧

    如果以上三个条件同时满足,则点P在三角形ABC内部。

    下面将会用到叉乘这个数学工具来确定一个点在直线的哪一侧。

    判断点在直线的哪一侧

    叉乘是一个判断点在直线哪一侧的数学工具。先看一下叉乘的定义:

    a⃗ ×b⃗ =a⃗ b⃗ sinθn⃗ 

    其中, θ 为向量夹角, n⃗  是一个向量,与 a⃗  b⃗  都垂直,方向满足右手螺旋法则,即下图所示:

    右手螺旋法则

    于是,从第一个向量的方向看,如果第二个向量在左边,那个叉乘是正的,在右边,则是负的,在同一个方向上,则是0.叉乘的大小,则是两个向量组成的平行四边形的面积。

    那么叉乘具体如何计算呢?先将x、y、z轴方向的单位向量分别记为 i⃗  j⃗  k⃗  ,则如果有两个向量,分别为:

    u⃗ =u1i⃗ +u2j⃗ +u3k⃗ =(u1,u2,u3)v⃗ =v1i⃗ +v2j⃗ +v3k⃗ =(v1,v2,v3)

    则有:
    u⃗ ×v⃗ =(u2v3u3v2)i⃗ +(u3v1u1v3)j⃗ +(u1v2u2v1)k⃗ 

    可以用以下行列式来简记:
    u⃗ ×v⃗ =i⃗ u1v1j⃗ u2v2k⃗ u3v3

    如果叉乘的两个向量都是平面向量,则可以看作是第三个分量为0的三维向量。

    以下Processing程序可以验证叉乘用于点在直线哪一侧的判断的正确性:

    PVector a = new PVector(100, 200);
    PVector b = new PVector(300, 300);
    PVector c = PVector.sub(b, a);
    
    void setup() {
      size(400, 400);
      fill(0);
    }
    
    void draw() {
      background(255);
      line(a.x, a.y, b.x, b.y);
      PVector d = new PVector(mouseX - a.x, mouseY - a.y);
    
      String side;
      if (c.cross(d).z > 0)
        side = "left";
      else if (c.cross(d).z < 0)
        side = "right";
      else
        side = "on";
      text(side, 40, 40);
    }

    有兴趣的读者也可以把cross方法展开试试。

    算法实现

    现在算法已经很明显啦!其中有一点小技巧,三角形的三个顶点是转着来的,算一次就行了。比如,在上图中,点C在直线AB左侧,点B在直线CA的左侧,点A在直接BC的左侧。所以,第一步是先计算三角形的方向:

    float signOfTrig = (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);

    注意这样一下子写出来不太容易看明白,但是如果看成向量AB和向量AC叉乘之后的Z坐标就好懂的多了。

    再分别计算P在AB、CA、BC的哪一侧:

    float signOfAB = (b.x - a.x)*(p.y - a.y) - (b.y - a.y)*(p.x - a.x);
    float signOfCA = (a.x - c.x)*(p.y - c.y) - (a.y - c.y)*(p.x - c.x);
    float signOfBC = (c.x - b.x)*(p.y - c.y) - (c.y - b.y)*(p.x - c.x);

    最后判断它们是否在同一侧:

    boolean d1 = (signOfAB * signOfTrig > 0);
    boolean d2 = (signOfCA * signOfTrig > 0);
    boolean d3 = (signOfBC * signOfTrig > 0);
    println(d1 && d1 && d3);

    这就是所有的算法了!最后来个程序验证一下。

    验证程序

    PVector[] trig;
    float r = 150;
    float t = 0;
    float interval = 30;
    
    void setup() {
      size(500, 500);
      trig = new PVector[3];
      ellipseMode(CENTER);
    }
    
    void draw() {
      translate(width/2, height/2);
      updateTrig();
      background(0);
      stroke(255);
      line(trig[0].x, trig[0].y, trig[1].x, trig[1].y);
      line(trig[1].x, trig[1].y, trig[2].x, trig[2].y);
      line(trig[0].x, trig[0].y, trig[2].x, trig[2].y);
    
      noStroke();
      for (float i = -width/2 + interval/2; i < width/2; i += interval) {
        for (float j = -height/2 + interval/2; j < height/2; j += interval) {
          if (inTrig(i, j)) {
            fill(255, 0, 0);
          } else {
            fill(255);
          }
          ellipse(i, j, 2, 2);
        }
      }
      t += 0.5;
    }
    
    void updateTrig() {
      for (int i = 0; i < 3; i++)
        trig[i] = new PVector(r * cos(radians(i * 120 + t)), r * sin(radians(i * 120 + t)));
    }
    
    boolean inTrig(float x, float y) {
      PVector a = trig[0];
      PVector b = trig[1];
      PVector c = trig[2];
      PVector p = new PVector(x, y);
    
      float signOfTrig = (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);
      float signOfAB = (b.x - a.x)*(p.y - a.y) - (b.y - a.y)*(p.x - a.x);
      float signOfCA = (a.x - c.x)*(p.y - c.y) - (a.y - c.y)*(p.x - c.x);
      float signOfBC = (c.x - b.x)*(p.y - c.y) - (c.y - b.y)*(p.x - c.x);
    
      boolean d1 = (signOfAB * signOfTrig > 0);
      boolean d2 = (signOfCA * signOfTrig > 0);
      boolean d3 = (signOfBC * signOfTrig > 0);
    
      return d1 && d2 && d3;
    }
    

    效果如下:

    效果

    展开全文
  • 判断点在三角形内外

    2018-08-16 09:20:57
    点在平面内与三角形三个顶点中任意两构成三个三角形,可以通过计算这三个三角形的面积和与原三角形面积比较来判断是否在三角形内 设有三角形ABC,判断Q是否在三角形内(包含某条边上),则当: S(PAB)+S(PBC)+...

    点在平面内与三角形三个顶点中任意两点构成三个三角形,可以通过计算这三个三角形的面积和与原三角形面积比较来判断是否在三角形内

    设有三角形ABC,判断点Q是否在三角形内(包含在某条边上),则当:

    S(PAB)+S(PBC)+S(PAC)=S(ABC)

    三角形计算公式:S=1/2*|cross(a,b)|

    struct triangle{
        point a;
        point b;
        point c;
    };
    
    bool intriangle(triangle t,point p)
    {
        v ab,ac,pa,pb,pc;
        ab=b-a;
        ac=c-a;
        pa=a-p;
        pb=b-p;
        pc=c-p;
        double sabc=fabs(cross(ab,ac));
        double spab=fabs(cross(pa,pb));
        double spac=fabs(cross(pc,pa));
        double spbc=fabs(cross(pb,pc));
        if(sabc==spab+spac+spbc){
            return true;
        }else{
            return false;
        }
    }

     

    展开全文
  • 论述了平面判断点在三角形内外的同向法的两个注意

    1. 概述

    平面中判断点在三角形内外有很多中算法,文献1中提到了一种同向法,我认为是比较好的解法,兼顾了效率和可理解性。不过这个算法有两个要注意的地方。

    2. 详论

    2.1. 原理与实现

    同向法的具体算法摘录如下:

    imglink1

    关键的实现代码如下:

    //空间三角形
    //按照逆时针顺序插入值并计算法向量
    template <class T>
    class Triangle
    {
    public:
        Vec3<T> v0;
        Vec3<T> v1;
        Vec3<T> v2;
    
        Triangle()
        {
    
        }
    
        Triangle(Vec3<T> v0, Vec3<T> v1, Vec3<T> v2)
        {
            this->v0 = v0;
            this->v1 = v1;
            this->v2 = v2;     
        }
    
        // v1 = Cross(AB, AC)
        // v2 = Cross(AB, AP)
        // 判断矢量v1和v2是否同向
        bool SameSide(Vec3<T>& A, Vec3<T>& B, Vec3<T>& C, Vec3<T>& P)
        {
            Vec3<T> AB = B - A ;
            Vec3<T> AC = C - A ;
            Vec3<T> AP = P - A ;
    
            Vec3<T> v1 = AB ^ AC;
            Vec3<T> v2 = AB ^ AP;
    
            // v1 and v2 should point to the same direction
            return v1*v2 >= 0 ;
            //return v1 * v2 > 0 ;
        }
    
        // 判断平面点P是否在平面三角形内
        bool PointInTriangle2D(Vec3<T>& P)
        {
            Vec3<T> A(v0.x(), v0.y(), 0);
            Vec3<T> B(v1.x(), v1.y(), 0);
            Vec3<T> C(v2.x(), v2.y(), 0);
            return SameSide(A, B, C, P) && SameSide(B, C, A, P) && SameSide(C, A, B, P);
        }
    };
    

    2.2. 注意事项

    第一个要注意的是,为了方便表达出向量的叉积,使用了三维向量而不是二维向量。但是这个算法是针对的是平面而不是空间,也就是判断空间中点是否在三角形内是无效的。并且,传入的三维向量的第三分量最好都为0,否则,无法保证算法的有效性。

    第二是点是通过点积来判断是否同向:

    bool SameSide(Vec3<T>& A, Vec3<T>& B, Vec3<T>& C, Vec3<T>& P)
    {
        Vec3<T> AB = B - A ;
        Vec3<T> AC = C - A ;
        Vec3<T> AP = P - A ;
    
        Vec3<T> v1 = AB ^ AC;
        Vec3<T> v2 = AB ^ AP;
    
        // v1 and v2 should point to the same direction
        return v1*v2 >= 0 ;
        //return v1 * v2 > 0 ;
    }
    

    理论上,两点积等于0,说明两向量是直角。但是这里的>=0考虑的是零向量的问题,零向量点乘任何点向量还是0。那么什么时候会出现零向量呢?当点正好在三角形的边界上的时候(两个相同的向量的叉积为零向量)。也就是说,这里的=0可以判断点正好在三角形的边界或者顶点上,而>0才是判断点是否在三角形的内部。使用的时候可以灵活掌握。

    3. 参考

    1. 判断点是否在三角形内
    2. Point in triangle test
    3. 二维向量的叉积是标量还是向量?
    展开全文
  • ACM 计算几何模板 点在三角形内

    千次阅读 2015-08-07 23:08:16
    如何判断点在三角形内 使用叉乘判断 //b[l],a[i],a[j],a[k]构成的三角形内,则sum++ //前面已经判断了三点不共线,可以构成三角形 if (cross(a[j]-a[i],b[l]-a[i])*cross(a[k]-a[i],b[l]-a[i])) if (cross(a[i...
  • 统计有多少个点在三角形内(HDU4380) 先预处理,统计每条线段(直线)上方的,然后利用类似容斥的方法 技巧是先对按照横坐标排序大小,就避免了对三角形类型的讨论 注意1:直线ij,要统计[i,j)半开...
  • POJ 1569 Myacm Triangles(判定点在三角形内) http://poj.org/problem?id=1569 题意: ZOJ 1704  给你n个的坐标,要你找出面积最大的由3个构成的三角形,且该三角形的内部或边上不能有点. 点数 分析:  由于...
  • 首先假设三角形在同一平面,如果不同一平面,需要用其它方法先筛选。 常用的几种平面三角形位置关系判定方法有(以下算法执行必须先保证三角形位于同平面): 1.顺时针/逆时针判定法 该方法要求...
  • 如果点在三角形内部,则如果将三角形的三个顶点与这个相连所得的三个小三角形的面积之和与原三角形的面积相等 S(A,B,D) + S(A,C,D) + S(B,C,D) = S(A,B,C) 第二种方法:向量叉积法 判断P3是否向向P1P2的...
  • UVA 143 Orchard Trees(判断点在三角形内) http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=79 题意:  一个[0,100]坐标范围的二维平面中,任意给...
  • 本代码使用fortran语言基于面积法来判定给定的是否在三角形内,而且是判定N个给定的是否M个三角形网格中,而且输出那个网格中
  • 如何判断点在三角形内

    千次阅读 2011-12-09 10:55:02
    给定三角形ABC和一点P(x,y,z),判断P是否ABC。这是游戏设计中一个常见的问题。需要注意的是,这里假定点和三角形位于同一个平面。 内角和法 连接P和三角形的三个顶点得到三条线段PA,PB和PC,求出这...
  • 沿 △ABC 各有向边按一定方向走(顺时针或逆时针),判断 P 是否该边的某侧(右侧或左侧),若 P 三条边的同侧,则 P △ABC 。 实现: 分别计算向量 AB、BC、CA 与向量 AP、BP、CP 的向量积(叉乘)...
  • 右手坐标系中的三角形3坐标为A,B,C,判断P是否ABC之 方法1:三个Perplane的方法   设AB,BC,AC边上的垂直平面为Perplane[3],垂直朝向内侧的法向为n[3]   1)先根据任意两边叉出法...
  • 枚举三角形的三个顶点, 判断是否在三角形内再求三角形面积。 代码: //poj 1569 //sepNINE #include #include using namespace std; const int maxN=32; struct Point { char ids; int x,y; }p[32]; ...
  • 以BC为例,在三角形内必须与ABC的同侧 所以对于D(x,y) 在三角形内首先要满足fa(x,y)*fa(a1,a2)>0 其他边也同理 所以只要比较 fa(x,y)*fa(a1,a2) fb(x,y)*fb(b1,b2) fc(x,y)*fc(c1,c2) 这三个数的正负性 1...
  • 判断一个是否在三角形内部

    千次阅读 2020-02-05 14:39:13
    判断一个是否三角形内部 解法1:面积法 利用点在三角形内外侧的相对面积关系 根据海伦公式,使用三角形边长求出其面积 解法2:向量法 使用叉积判断的相对方位
  • 4.4 是否在三角形内

    2015-05-09 10:45:57
    题目:给定一个三角形和一个,判断这个是否在三角形内。。 第一种方法:面积相等法  如果点在三角形内部,则如果将三角形的三个顶点与这个相连所得的三个小三角形的面积之和与原三角形的面积相等 S(A,...
  • Java 判断一个是否一个三角形内

    万次阅读 多人点赞 2017-10-12 12:55:55
    题目描述:  如何判断一个是否一个三角形内。测试样例:自定义的POINT类:class POINT{ int x; int y; public POINT(int x,int y){ this.x = x; this.y = y; } }思路一:面积法:  如果一个点在三角形...
  • 利用C++,opencv2.2判断一点是否确定三点的三角形内
  • 判断一个是否在三角形内

    千次阅读 2019-02-23 18:01:51
    算法1:通过面积法判断P是否三角形ABC内,如果P点在三角形内,则Sabc = Sapc + Sapb + Spbc(S代表面积) Sabc = 向量AB ^ 向量AC / 2;//面积公式 ^ 代表叉乘 除以2 是得到三角形面积,否则得到四边形面积 ...
  • 判断是否在三角形内

    千次阅读 2015-11-05 15:42:30
    判断是否在三角形内概述给定三角形ABC和一点P(x,y),判断P是否ABC内。这是游戏设计中一个常见的问题。也是《算法竞赛入门经典(第一版)》中5.4.3节“果园中的树”中的问题。重心法该方法简单易懂,速度也快,...
  • 判定一个是否在三角形内部

    千次阅读 2017-01-09 15:37:34
    给定任意一个的坐标和一个三角形,判定这个是否在三角形内部。本文独立思考完成,没有参考别的资料,可能方法不是太简洁。基本思路:[0]:考虑点在三角形内部的特征:任何一条经过该的直线都一定会和这个三角形有...
  • 利用叉乘快速判断是否在三角形内 判断P是否三角形ABC内: 向量: pa = P - A, ca = C - A; ba = B - A; 如果向量 cross(ca, pa)与向量 cross(pa, cb)同向,则点在三角形内。 注意:向量求叉乘时,是按小于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,164
精华内容 24,065
关键字:

点在三角形内