返回列表 发帖

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
$ Q2 J/ P- [% i( W  ]
' Y2 J. ]* b; |' \& B4 ]  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
8 |: t7 o5 R8 Y+ U1 g1 p9 e2 X/ U( H
  首先定义点结构如下:& Q! V* y4 ~3 e; w+ w; b. e

! l1 o0 f* W7 S$ [/ Z0 d以下是引用片段:5 C. ]" o1 i9 J+ {( A
  /* Vertex structure */
7 C1 r$ A2 A% _/ {3 Q  typedef struct , c4 D6 `* M4 h. q* {/ ?! n
  { / \3 {' E3 Y" z/ Q7 A) z. S2 F
  double x, y; " N9 j& e7 L) M. u2 q, j" x
  } vertex_t;
) s7 `# \4 p" [
+ \# A: A0 @1 s- R5 ^+ ^/ ]8 `* F2 L0 \3 d/ y2 Z6 F  B) Y& W3 Q$ g
  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:9 d) w: k# n  a: H$ G

3 J" u0 ]6 i7 L以下是引用片段:" e' y, B$ d% T7 n$ T0 M
  /* Vertex list structure – polygon */ 2 y+ _* Q0 m5 N! ?3 e! U! _: h4 m$ h
  typedef struct ( K5 u; N: T: j1 N# f
  { 6 x% Z6 _5 F8 Y' {% L
  int num_vertices; /* Number of vertices in list */
. s& a9 ?, f; R+ Q* A4 b  vertex_t *vertex; /* Vertex array pointer */
. Z+ S, ], q7 R  } vertexlist_t;
& _4 J% U* P- N
5 x# k, t& x) b& ]4 y8 g; A: I0 |& |. M- w/ Y
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:) G- B8 M8 W: m$ o8 W; D9 Z
  D7 _& H" L& p2 G
以下是引用片段:
, z# t5 S' c) u5 g' r  /* bounding rectangle type */ + A$ x2 O7 F) O( F9 V2 ]& U% D- J
  typedef struct
8 ^0 c( v3 G2 {- H  ]  V0 O  {
* ^0 `1 W# {; e  double min_x, min_y, max_x, max_y;
0 J3 x, C$ L1 Y2 D9 G5 f5 z; s. q  } rect_t;
$ C7 [: I8 i) \; {  /* gets extent of vertices */
- v' I/ D1 C; `' m( o  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ - {/ p3 J1 B7 E$ J( j4 {; T: t( ]6 {+ d& W
  rect_t* rc /* out extent*/ )
% G4 x& y. z5 S/ c  c9 c  { & H5 x" N  i) v+ S7 _
  int i; 2 e& _" A4 f$ J6 r0 i: v
  if (np > 0){
0 j% y, P0 p0 L6 W% |1 A  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 2 N% u, L* N% q+ v! z) P7 p$ S$ O
  }else{
* }9 ]' W/ v* K. _  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ * G" L3 s& t( q7 s6 J9 ]
  } 4 u4 ~) L- J# P) a+ e4 p
  for(i=1; i  
8 ~2 s8 s: K" c9 P- D! f  { + w4 e/ C8 D8 h( ?
  if(vl.x < rc->min_x) rc->min_x = vl.x;
; l8 ?* W2 s4 W  if(vl.y < rc->min_y) rc->min_y = vl.y; 6 s! ?' x, |7 R" O! i' a* _
  if(vl.x > rc->max_x) rc->max_x = vl.x;
# [# b9 J; g- q$ z, g. j" j" ]  if(vl.y > rc->max_y) rc->max_y = vl.y;
1 x- F0 p9 v$ O  F. r  } # b. `9 ^: L4 r$ F* A6 ?
  } . l9 }  K. I: M; _

1 B" G* K! y8 A/ l
, q  H" p- D  U' P  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。& K4 V2 t1 W/ ]) ~- l9 B+ i

! I1 G! b) b  p; p  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:7 n6 b+ w% x5 D, d' _' A, q6 g6 U% Q# A

" w2 N- ?: g4 y. l  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
7 X/ q7 V9 M7 ^. k5 w  A( ]% }1 q
0 r! ~! g6 x6 ~4 p  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
; o+ q7 y7 q# r7 j) D! p* w) k* Y2 {6 t- A! a: |% R4 B, O7 k
以下是引用片段:
1 @( m6 `  M4 ]: i  /* p, q is on the same of line l */ ! N  v* u* J. q% k; b
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
9 W; f6 Y  `" O5 _$ G0 ]3 g- _  g6 J  const vertex_t* p, 4 o! U  u3 K: P5 }
  const vertex_t* q)
( p+ t: ^- }4 r# f1 @: J; [  {
: ?; [7 q2 q9 d  double dx = l_end->x - l_start->x;
) C3 [% _7 x  L7 Z  double dy = l_end->y - l_start->y;
6 s* o" r/ R: I5 o8 \7 ~  double dx1= p->x - l_start->x; # t0 P1 a0 ?$ @( E9 Q0 x
  double dy1= p->y - l_start->y;
9 y5 d6 q* d, v: v$ @2 ?1 Z# c  double dx2= q->x - l_end->x; % e8 n# @1 \# ]) S; a9 _/ ]4 |* w, L. C
  double dy2= q->y - l_end->y;
9 W4 x# ~" g/ R" R  H  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
9 R+ O! k! ?1 ^$ ]' ~" S  } " f2 X, Z7 W- }+ C
  /* 2 line segments (s1, s2) are intersect? */ 1 ]4 g$ o7 A( ?7 w% \
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, 5 o" Y( h3 U! s" u
  const vertex_t* s2_start, const vertex_t* s2_end) $ i+ z2 p& A7 Q
  { 1 D* u9 ?- u+ F' E
  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && : _* ]8 ~# n* A6 [
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; 8 d0 i2 L, _$ i* G0 T
  }
' W3 }3 ~& \; Z
0 o( x9 x0 P: [( v8 d- t5 \& q! _6 V4 ]
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
) p, W9 w' @: c: w/ L% e5 |$ Q' X5 i& I& Y; L
以下是引用片段:1 t1 P( m, i# e! I2 Q
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 7 Z0 k- E! q+ C( E& E2 l, k0 @5 K3 `
  const vertex_t* v)
4 E' v2 w9 o4 p) Y2 Y  {
2 v7 w7 |- L' j" X5 F/ K  int i, j, k1, k2, c; 9 \0 r  j6 `0 T% r: ]# T( Q- K
  rect_t rc;
& O  h" c0 i: T( b5 ^2 R! T  vertex_t w; ; O$ m  D7 T' E1 J
  if (np < 3)
- `3 H# E# |5 {4 @& s& X. E3 C# }  return 0;
1 S! R+ E' ^% t; R  m: X  vertices_get_extent(vl, np, &rc);
0 {1 m" B8 e! }/ D  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
2 P8 E. f, k$ A7 f3 ?7 _  return 0; + {0 ]' M8 j" V0 M' w
  /* Set a horizontal beam l(*v, w) from v to the ultra right */
+ I! m+ o: d: d( F$ g* K  w.x = rc.max_x + DBL_EPSILON;
  h; x* _( H9 y  m9 _  w.y = v->y;
8 N0 U5 _9 ^, z3 g  c = 0; /* Intersection points counter */
+ t3 H7 o  @' e" J& i; y& I7 }  for(i=0; i  " g8 }7 O; t+ r
  {
7 }% q- Q8 y$ P. @- K2 d9 J" G  j = (i+1) % np; " \& w9 S( L  s& f8 ^& [
  if(is_intersect(vl+i, vl+j, v, &w))
9 X9 c9 w& S7 U* @0 A- L+ a( V% B  {
  J* y. v* o7 y6 L0 l  C++;
4 K( X4 m- B( T  }
' T" r% T4 j4 Y. I% j  else if(vl.y==w.y)
0 W8 R) s& W1 }  @* @8 w  { 6 ~/ [  [& q5 V" }( {/ z6 ^
  k1 = (np+i-1)%np;
& l& h% y: \. E' P( k& O' r5 c  while(k1!=i && vl[k1].y==w.y) $ W* D0 I) G2 p7 g+ H
  k1 = (np+k1-1)%np;
1 N$ Y* V/ }  R. O! [8 ~  k2 = (i+1)%np;
6 o* N# q; `) ~& c/ c8 ^7 u. a3 S  while(k2!=i && vl[k2].y==w.y) 9 r' i+ L0 }1 a( h: A
  k2 = (k2+1)%np;
& A" d0 r& [( k9 `. I+ A+ g# U  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
- F+ B& v5 O; b( ~  C++;
) B. o5 J$ y6 P" Y- N  _  if(k2 <= i)
! F4 N+ c; ]2 j- P2 n) ~  break;
5 @4 f9 M+ H2 \# f0 p- ?" K4 v3 v; c  i = k2;
4 d. ^7 r* u3 d' t- d& g7 e+ w  }
: P% s+ u/ E/ T, W9 T! n  } 5 I$ U5 P6 y, d, T& T
  return c%2; 4 b* S+ x; U  L1 u2 r( }6 E
  } 2 n. G% O: M4 U: V- b2 m! M( b
$ d  D, B; I6 m# H) q3 G2 ^
: p* p/ d' R/ j1 O- j5 x
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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