发信人: RovingCloud (寻找当年的OI感觉), 信区: ACMICPC
标  题: 【原创】惊喜发现判断点在多边形内外的超简单算法
发信站: 逸仙时空 Yat-sen Channel (Wed Mar 28 01:27:19 2007)

今天学图形学的时候发现了一个求多边形内外的超简单算法,当时觉得非常惊喜,

后来晚上上完选修的时候在走廊遇到bug,bug也是很惊喜地感慨道:居然有甘简单既办法

都捻唔到!遂将其写下,供大家分享,希望不会太火星。

这个算法是源自《计算机图形学基础教程》(孙家广,清华大学出版社),在该书

的48-49页,名字可称为“改进的弧长法”。该算法只需O(1)的附加空间,时间复杂度为O

(n),但系数很小;最大的优点是具有很高的精度,只需做乘法和减法,若针对整数坐标则

完全没有精度问题。而且实现起来也非常简单,比转角法和射线法都要好写且不易出错。

首先从该收中摘抄一段弧长法的介绍:“弧长法要求多边形是有向多边形,一般规

定沿多边形的正向,边的左侧为多边形的内侧域。以被测点为圆心作单位圆,将全部有向

边向单位圆作径向投影,并计算其中单位圆上弧长的代数和。若代数和为0,则点在多边形

外部;若代数和为2π则点在多边形内部;若代数和为π,则点在多边形上。”

按书上的这个介绍,其实弧长法就是转角法。但它的改进方法比较厉害:将坐标原

点平移到被测点P,这个新坐标系将平面划分为4个象限,对每个多边形顶点P,只考虑

其所在的象限,然后按邻接顺序访问多边形的各个顶点P,分析P和P[i+1],有下列

三种情况:
   (1)P[i+1]在P的下一象限。此时弧长和加π/2;
   (2)P[i+1]在P的上一象限。此时弧长和减π/2;
   (3)P[i+1]在Pi的相对象限。首先计算f=y[i+1]*x-x[i+1]*y(叉积),若f=

0,则点在多边形上;若f<0,弧长和减π;若f>0,弧长和加π。

最后对算出的代数和和上述的情况一样判断即可。

实现的时候还有两点要注意,第一个是若P的某个坐标为0时,一律当正号处理;

第二点是若被测点和多边形的顶点重合时要特殊处理。

以上就是书上讲解的内容,其实还存在一个问题。那就是当多边形的某条边在坐标

轴上而且两个顶点分别在原点的两侧时会出错。如边(3,0)-(-3,0),按以上的处理,象限

分别是第一和第二,这样会使代数和加π/2,有可能导致最后结果是被测点在多边形外。

而实际上被测点是在多边形上(该边穿过该点)。

对于这点,我的处理办法是:每次算P和P[i+1]时,就计算叉积和点积,判断该

点是否在该边上,是则判断结束,否则继续上述过程。这样牺牲了时间,但保证了正确性

具体实现的时候,由于只需知道当前点和上一点的象限位置,所以附加空间只需O(

1)。实现的时候可以把上述的“π/2”改成1,“π”改成2,这样便可以完全使用整数进

行计算。不必考虑顶点的顺序,逆时针和顺时针都可以处理,只是最后的代数和符号不同

而已。整个算法编写起来非常容易。

针对以上算法,我写了一个代码,拿ZOJ 1081 Points Within进行测试,顺利Acce

pted。这证明该算法的正确性还是可以保障的。

   以下附上我的代码:

// ZOJ 1081 , 改进弧长法判点在形内形外
#include <stdio.h>
#include <math.h>
const int MAX = 101 ;
struct point { int x , y ; } p[MAX] ;

int main()
{
       int n , m , i , sum , t1 , t2 , f , prob = 0 ;
       point t ;
       while ( scanf( "%d" , &n ) , n )
       {
               if( prob ++ ) printf ( " " );
               printf ( "Problem %d: " , prob ) ;
               scanf ( "%d" , &m ) ;
               for ( i = 0 ; i < n ; i ++ ) scanf ( "%d%d" , &p.x , &p.y ) ;
               p[n] = p[0] ;
               while ( m -- )
               {
                       scanf ( "%d%d" , &t.x , &t.y );
                       for ( i = 0 ; i <= n ; i ++ ) p.x -= t.x , p.y -= t.y ;    // 坐标平移
                       t1 = p[0].x>=0 ? ( p[0].y>=0?0:3 ) : ( p[0].y>=0?1:2 );        // 计算象限
                       for ( sum = 0 , i = 1 ; i <= n ; i ++ )
                       {
                               if ( !p.x && !p.y ) break ;    // 被测点为多边形顶点
                               f = p.y * p[i-1].x - p.x * p[i-1].y ;     // 计算叉积
                               if ( !f && p[i-1].x*p.x <= 0 && p[i-1].y*p[i].y <= 0 ) break ;  // 点在边上
                               t2 = p.x>=0 ? ( p.y>=0?0:3 ) : ( p.y>=0?1:2 ) ;   // 计算象限
                               if ( t2 == ( t1 + 1 ) % 4 ) sum += 1 ;

// 情况1
                               else if ( t2 == ( t1 + 3 ) % 4 ) sum -= 1 ;

// 情况2
                               else if ( t2 == ( t1 + 2 ) % 4 )

// 情况3
                               {

if ( f > 0 ) sum += 2 ; else sum -= 2;
                               }
                               t1 = t2 ;
                       }
                       if ( i<=n || sum ) printf( "Within " ) ; else printf("Outside " ) ;
                       for ( i = 0 ; i <= n ; i ++ ) p.x += t.x , p.y += t.y ;       // 恢复坐标
               }
       }
       return 0;
}

判断点在多边形内外的简单算法相关推荐

  1. HDU1756(判断点在多边形内外)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1756 bool IsOnline(Point p,Segment s) /** 判断点p是否在线段s上 * ...

  2. opencv 判断点在多边形内外

    基于Python 和 OpenCV 画出多边形,以及判断某个点是不是在多边形内. 1.cv2.pointPolygonTest() 函数 函数定义:cv2.pointPolygonTest(conto ...

  3. JAVA 判断简单密码算法_十道简单算法题二【Java实现】

    前言 清明不小心就拖了两天没更了-- 这是十道算法题的第二篇了-上一篇回顾:十道简单算法题 最近在回顾以前使用C写过的数据结构和算法的东西,发现自己的算法和数据结构是真的薄弱,现在用Java改写一下, ...

  4. 点在多边形内外的判断【计算几何】

    点在多边形内外的判断有两种处理方法:射线法和转角法 一.射线法: 从这一点出发,引向无穷远点的一条射线,根据交点情况确定点的位置 特点:特殊情况不易处理 以要判断的点为起点,任做一条射线,计算该射线与 ...

  5. 辐角原理判断点和多边形的关系

    辐角判断点和多边形的关系 一.辐角原理 二.适用条件 三.算法效果 四.matlab代码实现 \qquad标题写的多边形,然而在现实情况中多边形只是该问题的一个子集:我们先讲点和连通域的关系,点和多边 ...

  6. Java平行线算法_多边形的平行线填充算法

    最近做的一个小算法,使用平行线填充一个多边形区域.用过 AutoCAD 的同学应该知道,可以选定一个区域,指定平行线的角度 α 和平行线之间的间距 spacing 就可以填充区域了. image 图 ...

  7. java判断回文字符串几种简单的实现

    11年it研发经验,从一个会计转行为算法工程师,学过C#,c++,java,android,php,go,js,python,CNN神经网络,四千多篇博文,三千多篇原创,只为与你分享,共同成长,一起进 ...

  8. java的简单算法题_[2]十道算法题【Java实现】

    前言 清明不小心就拖了两天没更了-- 这是十道算法题的第二篇了-上一篇回顾:十道简单算法题 最近在回顾以前使用C写过的数据结构和算法的东西,发现自己的算法和数据结构是真的薄弱,现在用Java改写一下, ...

  9. 学习笔记之15道简单算法题

    15道简单算法题 http://www.cnblogs.com/hlxs/archive/2014/06/06/3772333.html (●-●) | 剑指Offer_编程题_牛客网 http:// ...

最新文章

  1. 判别模型和生成模型的区别
  2. eclipce如何配置mysql_如何在eclipse配置mysql数据库
  3. 途牛订单的服务化演进
  4. golang signal 信号简介
  5. Paddle Detection
  6. VMware Workstation 网络连接配置
  7. java动效_Android 界面漩涡扭曲动效实现
  8. PAT (Advanced Level) 1007 Maximum Subsequence Sum(最大连续子段和)
  9. 【剑指offer】面试题61:扑克牌中的顺子(java)
  10. c均值聚类matlab程序_机器学习笔记-9-聚类
  11. * poj 3159 Candies 最短路 dijkstra堆优化
  12. Cisco无线mDNS
  13. 培养一个数据人才需要多少年?
  14. HTML:网页设计案例1
  15. 计算机连接网络是飞行模式怎么办,电脑wifi界面只有飞行模式怎么办
  16. 容斥原理在C语言中的应用,容斥原理在排列问题中的应用实例
  17. OpenLayers多源数据加载一:数据组织
  18. 大数据分析01——成都二手房(平均价格)
  19. Python input函数
  20. 机器视觉——视觉工程师需要知道的知识

热门文章

  1. java递归计算N!
  2. MeterSphere | 超好用的开源测试平台
  3. java abc排序_Java实现按照大小写字母顺序排序的方法
  4. matlab练习程序(随机粒子切换特效)
  5. 达芬奇调色 Blackmagic Design DaVinci Resolve Studio 17 中文版,整合剪辑、视觉特效、动态图形、调色和音频后期制作
  6. ipv6一致性(packet too big)测试
  7. 区块链(Blockchain)简介
  8. 生日快乐app(从无到有)
  9. css:图文效果(上面图片下面文字)
  10. Python的打包神器—Nuitka