博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
判断点是否在多边形内(包括在多边形上)
阅读量:5775 次
发布时间:2019-06-18

本文共 6431 字,大约阅读时间需要 21 分钟。

/** 检查某点是否包含在多边形的范围内(只用与判断在多边形内部,不包含点在多边形边上的情况)~ */

- (BOOL) checkPointWithinPolygon:(PolyVerticesWrapper*)pvw point:(b2Vec2)point {

     int verticesCount = [pvw verticesCount];

     b2Vec2 *ptPolygon = [pvw vertices];

    

     int nCross = 0;

     for (int i =  0; i < verticesCount; ++ i) {

         float j = ptPolygon[i].x;

         float k = ptPolygon[i].y;

         float m = ptPolygon[(i + 1) % verticesCount].x;

         float n = ptPolygon[(i + 1) % verticesCount].y;

         b2Vec2p1(j, k);

         b2Vec2p2(m, n);

    

       //求解 y=p.y与 p1 p2 的交点

         if ( p1.y == p2.y ) {  // p1p2与 y=p0.y平行

             continue;

        }

         if ( point.y <  fminf(p1.y, p2.y) ) {

//交点在p1p2延长线上 

             continue;             

        }

         if ( point.y >  fmaxf(p1.y, p2.y) ) {

//交点在p1p2延长线上 

             continue;

        }

       //求交点的 X坐标

         double x = (double)(point.y – p1.y) * (double)(p2.x – p1.x) / (double)(p2.y – p1.y) + p1.x;

 

         if ( x > point.x ) {  // 只统计单边交点 

            nCross++;            

        }

    }

     if(nCross%2 != 0) {   //单边交点为偶数,点在多边形之外

         returnYES;

    }  else {

         returnNO; 

    }

}

原文地址:http://blog.csdn.net/yang3wei/article/details/6840560

 

 

之前在工作面试时碰到一道题目就是如何判断一个点是否处于多边形内部。对于游戏程序员,应该是很初级的问题。

当时我给的答案是用那个点连接所有的多边形顶点,然后将两边夹角加起来,如果和等于360度,则说明点处于多边形内部,否则就不在。

后来在网上看到一种判断方法是,如果点在多边形内部,则该点对于所有的边线,应该都处于同一个边。 (仅讨论凸多边形)

 

double value = (p.x - polygon[j].x) * (polygon[i].y - polygon[j].y) - (p.y - polygon[j].y) * (polygon[i].x - polygon[j].x);

当时是用上面这个计算式是否大于零来判断处于那一侧的,当时没看懂。 今天突然想起这个问题,明白了一些。

 

假设P0为要判断的点,P1、P2为多边形的一条边线的起点和终点,我们用P1Po (x0 - x1, y0 - y1)叉乘P1P2 (x2 - x1, y2 - y1),结果的第三个分量大于零说明两者夹角小于180,小于零则说明两者夹角小于180度。

第三个分量的值为 (x0 - x1)(y2 - y1)  - (y0 - y1)(x2 - x1)

 

 

  

转载自:

 

再经典不过的算法了:

// 功能:判断点是否在多边形内 

// 方法:求解通过该点的水平线与多边形各边的交点 
// 结论:单边交点为奇数,成立!

//参数: 

// POINT p 指定的某个点 
// LPPOINT ptPolygon 多边形的各个顶点坐标(首末点可以不一致) 
// int nCount 多边形定点的个数

BOOL PtInPolygon (POINT p, LPPOINT ptPolygon, int nCount) 
  int nCross = 0;

  for (int i = 0; i < nCount; i++) 

  { 
    POINT p1 = ptPolygon[i]; 
    POINT p2 = ptPolygon[(i + 1) % nCount];

    // 求解 y=p.y 与 p1p2 的交点

    if ( p1.y == p2.y ) // p1p2 与 y=p0.y平行 

      continue;

    if ( p.y < min(p1.y, p2.y) ) // 交点在p1p2延长线上 

      continue; 
    if ( p.y >= max(p1.y, p2.y) ) // 交点在p1p2延长线上 
      continue;

    // 求交点的 X 坐标 -------------------------------------------------------------- 

    double x = (double)(p.y - p1.y) * (double)(p2.x - p1.x) / (double)(p2.y - p1.y) + p1.x;

    if ( x > p.x ) 

      nCross++; // 只统计单边交点 
  }

   // 单边交点为偶数,点在多边形之外 --- 

   return (nCross % 2 == 1); 
}

 

 

经历了三个版本,虽然都是小改动,但是表现出的效果还是相差蛮大

第一版是移植的别人的

(试用之后我发现点相交于多边形的边上效果不是很好)

第二版改善了点相交于多边形边上的判断

(改善之后效果比较明显,但还是会偶发判断失准)

第三版增加了数量级的判断,将偶发性的判断失准再降下一个台阶

(数值计算误差是不可避免的,所以在判断相等的时候,必得要确定一个可容忍的误差数量级)

下面上三版的相关代码,第二版带Ex,第三版带ExII

 

 

 

/** 检查多边形的包围盒是否相交~ */  -(BOOL) isBoundingBoxIntersect:(BoundingBox)bb1 bb2:(BoundingBox)bb2 {      if(bb1.maxX>=bb2.minX && bb2.maxX>=bb1.minX &&          bb1.maxY>=bb2.minY && bb2.maxY>=bb1.minY) {          return YES;      }      return NO;  }    /** 检查某点是否包含在多边形的范围内~ */  -(BOOL) isPolygonContainsPoint:(BYPolygon*)poly point:(b2Vec2)p {      int verticesCount = [poly verticesCount];      b2Vec2 *ptPolygon = [poly vertices];            int nCross = 0;      for (int i = 0; i < verticesCount; ++ i) {          b2Vec2 p1 = ptPolygon[i];          b2Vec2 p2 = ptPolygon[(i + 1) % verticesCount];                    // 求解 y = p.y 与 p1-p2 的交点~          if (p1.y == p2.y) {   // p1-p2 与 y = p0.y 平行~              continue;          }          if (p.y < fminf(p1.y, p2.y)) { // 交点在 p1-p2 延长线上~              continue;          }          if (p.y > fmaxf(p1.y, p2.y)) { // 交点在 p1-p2 延长线上~              continue;          }                    // 求交点的 X 坐标~          double x = (double)(p.y-p1.y)*(double)(p2.x-p1.x)/(double)(p2.y-p1.y)+p1.x;                    // 只统计单边交点~          if (x > p.x) {              nCross ++;          }      }            // 单边交点为偶数,点在多边形之外~      if(nCross%2 == 1) {          return YES;      } else {          return NO;      }  }      /** 对某点正好被包含在多边形的边上具有更好的适用性~ */  -(BOOL) isPolygonContainsPointEx:(BYPolygon*)poly point:(b2Vec2)p {      int verticesCount = [poly verticesCount];      b2Vec2 *ptPolygon = [poly vertices];      /** added on 2011.10.02.15.21,是否正好相交在边上~ */      bool isIntersectOnSection = false;            int nCross = 0;      for (int i = 0; i < verticesCount; ++ i) {          b2Vec2 p1 = ptPolygon[i];          b2Vec2 p2 = ptPolygon[(i + 1) % verticesCount];                    // 求解 y=p.y 与 p1 p2 的交点          if (p1.y == p2.y) {   // p1p2 与 y=p0.y平行              continue;          }          if (p.y < fminf(p1.y, p2.y)) { // 交点在p1p2延长线上              continue;          }          if (p.y > fmaxf(p1.y, p2.y)) { // 交点在p1p2延长线上              continue;          }          // 求交点的 X 坐标          double x = (double)(p.y-p1.y)*(double)(p2.x-p1.x)/(double)(p2.y-p1.y)+p1.x;                    /** added on 2011.10.02.15.21,是否正好相交在边上~ */          if (x == p.x) {  //            NSLog(@"点正好相交在多边形的边上~");              isIntersectOnSection = true;              break;          }          if (x > p.x) { // 只统计单边交点              nCross ++;          }      }      if(isIntersectOnSection || nCross%2==1) {    // 单边交点为偶数,点在多边形之外          return YES;      } else {          return NO;      }  }    /** 对某点正好被包含在多边形的边上具有更好的适用性~ */  -(BOOL) isPolygonContainsPointExII:(BYPolygon*)poly point:(b2Vec2)p {      int verticesCount = [poly verticesCount];      b2Vec2 *ptPolygon = [poly vertices];      /** added on 2011.10.02.15.21,是否正好相交在边上~ */      bool isIntersectOnSection = false;            int nCross = 0;      for (int i = 0; i < verticesCount; ++ i) {          b2Vec2 p1 = ptPolygon[i];          b2Vec2 p2 = ptPolygon[(i + 1) % verticesCount];                    // 求解 y=p.y 与 p1 p2 的交点          if (p1.y == p2.y) {   // p1p2 与 y=p0.y平行              continue;          }          if (p.y < fminf(p1.y, p2.y)) { // 交点在p1p2延长线上              continue;          }          if (p.y > fmaxf(p1.y, p2.y)) { // 交点在p1p2延长线上              continue;          }          // 求交点的 X 坐标          double x = (double)(p.y-p1.y)*(double)(p2.x-p1.x)/(double)(p2.y-p1.y)+p1.x;                    /** added on 2011.10.02.15.21,是否正好相交在边上~ */  //        NSLog(@" —— x=%f, p.x=%f", x, p.x);          if (fabs(x - p.x) < 10e-4) {  //            NSLog(@"点正好相交在多边形的边上~");              isIntersectOnSection = true;              break;          }          if (x > p.x) { // 只统计单边交点              nCross ++;          }      }      if(isIntersectOnSection || nCross%2==1) {    // 单边交点为偶数,点在多边形之外          return YES;      } else {          return NO;      }  }

转载于:https://www.cnblogs.com/pengyingh/articles/2486880.html

你可能感兴趣的文章
RAC实践采坑指北
查看>>
runtime运行时 isa指针 SEL方法选择器 IMP函数指针 Method方法 runtime消息机制 runtime的使用...
查看>>
LeetCode36.有效的数独 JavaScript
查看>>
Scrapy基本用法
查看>>
PAT A1030 动态规划
查看>>
自制一个 elasticsearch-spring-boot-starter
查看>>
软件开发学习的5大技巧,你知道吗?
查看>>
java入门第二季--封装--什么是java中的封装
查看>>
【人物志】美团前端通道主席洪磊:一位产品出身、爱焊电路板的工程师
查看>>
一份关于数据科学家应该具备的技能清单
查看>>
机器学习实战_一个完整的程序(一)
查看>>
Web框架的常用架构模式(JavaScript语言)
查看>>
如何用UPA优化性能?先读懂这份报告!
查看>>
这些Java面试题必须会-----鲁迅
查看>>
Linux 常用命令
查看>>
NodeJS 工程师必备的 8 个工具
查看>>
CSS盒模型
查看>>
ng2路由延时加载模块
查看>>
使用GitHub的十个最佳实践
查看>>
脱离“体验”和“安全”谈盈利的游戏运营 都是耍流氓
查看>>