获得本站免费赞助空间请点这里
返回列表 发帖

C语言中显示 点在多边形内 算法

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。- z. c& w  r8 W; A

' f5 {0 C( i2 r4 n" o9 W  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。- B" S1 i  F( t
- X7 v( x/ _/ F& G- \7 B& V$ C
  首先定义点结构如下:
7 c& J! O/ D; D# E  p5 b: M
& W% C6 i3 d5 ~& Q8 o' Z" h) p以下是引用片段:& A8 k+ ^. ~& b/ p7 y4 l
  /* Vertex structure */
  U- T; N4 _. t/ x& l& O  typedef struct
" N( b; [7 C  R9 C' Q  { 9 s9 S1 D5 x2 z- n
  double x, y;
! g' b! [( x& B  } vertex_t; " N% z/ d3 `! s( ?2 W
; N0 u- D3 w$ e

' d8 ?$ n% u  v4 ?! `* h1 L, ?( ~  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
! x' D" e/ Z' b1 C, \; W9 U0 a8 m2 L) a# [6 }. ?0 G2 Y
以下是引用片段:
1 I: T7 \! f5 H! W9 r- T" j, Q7 R  /* Vertex list structure – polygon */ 6 r9 m, B$ A! H, \, k. o1 l" W3 N
  typedef struct
' V( n, {* R, @% V1 h. _# g  { . D) j1 K( L. M6 L+ S
  int num_vertices; /* Number of vertices in list */ 4 F5 t9 o6 d# d  a; M1 t2 `
  vertex_t *vertex; /* Vertex array pointer */
' [" }& X. x1 i% a$ F; x3 E+ _  } vertexlist_t; & N* Y* E: F$ v# m1 {" G1 a* x; C7 a

4 J* [) W+ x2 y$ J' [1 v$ a9 K0 P. M0 [2 `# b7 w; n
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:8 J2 w7 j, F  _9 H% P" A

. |- I. D7 S+ X+ e) i0 ?0 b+ z以下是引用片段:& n+ }3 B7 R; A  p! a
  /* bounding rectangle type */ - E8 _! X% h$ [
  typedef struct
; v* l! G. z2 m" C! F" n0 o$ _  { / Y5 k! B( ~  P6 A1 {
  double min_x, min_y, max_x, max_y;
- C( {! w. Q: S' e0 D/ t7 F  } rect_t;
2 J" l( d+ @9 q# R9 |  /* gets extent of vertices */   p+ H& r/ _! S( t
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ : J' w- w  ~0 q
  rect_t* rc /* out extent*/ )
$ y/ ~( R: b- |  {
$ h) R3 Z3 _0 A2 h1 n5 Y0 |  int i;
( Y# `5 X  `0 J: h/ s  if (np > 0){ 3 g1 E! _7 P1 j8 s
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; / M/ U8 Y  q' F( ]  a
  }else{   }+ _( |1 e# c; W: ^9 x" F4 w
  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
  W: |; N+ k9 f& G9 t  M9 }! n  }
5 m% N- p: Y& G3 V  for(i=1; i  
0 n2 R$ \/ |6 [. v7 p  { 6 f+ y1 z9 y$ x" Y& i, K) Y3 c$ Q4 @
  if(vl.x < rc->min_x) rc->min_x = vl.x;
. l+ G7 z7 a* z  if(vl.y < rc->min_y) rc->min_y = vl.y; ; u# N$ X9 V% L0 _  F. n
  if(vl.x > rc->max_x) rc->max_x = vl.x; % z' l0 d7 z; y) ]$ o5 o, F
  if(vl.y > rc->max_y) rc->max_y = vl.y; ) D3 ]0 Q' f) T. D
  } 4 g" [* k. E/ q; ^" g
  } ! ?9 F- A# z1 u

' F$ w, b* h2 d$ M
' g0 ?9 S& M' l! @+ z% p: K  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。- ^. ~3 d4 h7 Q

. r+ ~6 R0 h3 [% f  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
1 B. g- j4 V' x" U: P" U
. Y% r. G7 {( w! Q( P: E" |  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
* d5 L3 R* r9 v' b' Z  c, n2 X6 ~" b( X- z
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
% K+ J& T2 E$ a: E* ^9 x  S2 L" |' R' F/ T- H# j6 B0 m& z( L
以下是引用片段:+ t9 U+ a4 ?( [4 s
  /* p, q is on the same of line l */ 1 V+ _2 y( }4 U; G& w
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 6 L4 B! }. ^% q7 [: L
  const vertex_t* p,
6 [. r7 K4 s& |  const vertex_t* q)
8 B/ w$ @6 K, ?0 ?  { 4 x" q8 V9 O; V( v/ Q9 b
  double dx = l_end->x - l_start->x; 5 A% X/ U7 A! T0 P( G, j
  double dy = l_end->y - l_start->y;
& [5 i  r' x2 C' @) B6 k  double dx1= p->x - l_start->x;
  ?, V$ k& o7 O( |/ r5 w0 K  double dy1= p->y - l_start->y; . b0 A0 Z, |0 R
  double dx2= q->x - l_end->x;
" j) B) |& A( u4 k0 I  double dy2= q->y - l_end->y; & J4 J% p8 K$ t
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
: \1 x$ x) d" G2 G) t  } # p& m+ r, [% p# L
  /* 2 line segments (s1, s2) are intersect? */
; \. l9 h" D5 z/ z' Y9 @  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
8 z6 T: {* e  s& ?, l9 ]3 ^  const vertex_t* s2_start, const vertex_t* s2_end) ( ^. h5 u+ R+ {) R) E) t
  { 0 M( G2 h5 e; ~
  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 1 m  z3 W/ q4 i: u, c" ^( Q+ z% F
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
, s- C! f2 N" A5 o4 X  }
! f+ B5 w$ H1 [0 [2 u5 B2 O( z* P' A6 V( y4 l  O+ i! a: U

- |& X2 G" w. f. m! r/ v  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
2 q/ r) I  J/ H; U* @6 l& V( X  j3 d2 i/ E! Y
以下是引用片段:5 J6 i& I; ~- `  E. e
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
4 I$ C& `$ v2 [4 D  const vertex_t* v)
% A& ?* p! ^& t/ F6 _9 _  {
+ r4 N4 M$ F" I6 H+ e; {: c  int i, j, k1, k2, c; 5 W" l1 a2 h! e/ ~4 q1 [
  rect_t rc;
: Y" z% z6 K' t- R  vertex_t w;
, W4 _5 G4 Q8 ]4 Q  if (np < 3) & J1 L& O! C: G5 `! L- M6 S
  return 0;
* v( @5 Y- z* N9 X9 ]  vertices_get_extent(vl, np, &rc); ' U1 O0 O, T3 s  q
  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) 2 b& d5 E" f( R& G% |6 {" |) g
  return 0; 5 z& b/ h* B* B. G* e6 a) }
  /* Set a horizontal beam l(*v, w) from v to the ultra right */
' ?: h% B* L, L9 E  w.x = rc.max_x + DBL_EPSILON; & y% l; S) ^/ h# p. v
  w.y = v->y;
4 U2 C+ k+ a$ r4 K2 u  c- _* V- l  c = 0; /* Intersection points counter */ : s6 _0 P( t  E  N# e
  for(i=0; i  
2 v: e! G: d5 z2 C0 m# P) [  {
6 [" X( s; Q: W' a, @) m  j = (i+1) % np; * Z1 c4 k7 I+ X+ Q
  if(is_intersect(vl+i, vl+j, v, &w))
* u  G' a+ }$ B5 j! n2 B5 ?* ~  { 0 D1 H" u$ A* g7 x
  C++;
+ U4 r$ L& U" N" O6 R  }
) i( ^$ b8 j' F$ d  else if(vl.y==w.y)
. B7 |4 u% G: o6 k1 }; _  {
1 s, q5 M1 y# R8 X4 ?  k1 = (np+i-1)%np; 3 }+ p1 S2 v- Z
  while(k1!=i && vl[k1].y==w.y)
; w8 o: B# ^* ?: l$ y  k1 = (np+k1-1)%np;
' `# ]5 T  y6 }+ k( s* e  k2 = (i+1)%np; / ^, }; a" e: Q3 l0 e' m- H3 ]
  while(k2!=i && vl[k2].y==w.y) 2 u6 X+ i5 ]# n" `2 m
  k2 = (k2+1)%np;
7 P2 h: f4 z! m* G3 n* Q  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) 5 y$ y  S- Y2 t; F
  C++;
4 p: `  q7 T, }4 O) ~" }! k/ q  if(k2 <= i)
) x" D% n& u" U6 z  break;
3 d' C6 B2 D7 l3 P7 G, Z  i = k2; 8 X. m: a' L" n% s
  } % X9 d" n' _7 o& l2 `
  } ' g4 o7 E9 ]' S
  return c%2; % x* ~* d3 L# ^& \1 @3 n8 y
  } * N+ g/ m3 l( _" q9 e

- I, ?+ G- N9 Q2 T- q  E4 m; Q+ a1 n9 K6 j7 d/ E  D* Y' N" q1 D
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

返回列表
【捌玖网络】已经运行: