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

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。. |( @8 W; p" R
$ ?: D: ]% x: R; h- u! o
  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。% o; m& N+ G+ V3 v/ @0 b) h

7 `8 ?2 _3 R# J: @1 U  首先定义点结构如下:
+ H0 o$ Q" ?! j
: S+ o' u) q& C0 T' T& D0 N. s以下是引用片段:- k: C4 [( C, ]  s. d: N+ _
  /* Vertex structure */ 4 b3 [5 D( o- r: I( p3 t
  typedef struct
1 y5 }7 d. r' @8 N7 h7 K  {
9 g$ }1 `9 U' T$ V  double x, y; 9 p' ~! y: Q: ^! _* R' s: ]
  } vertex_t;
6 a. h% q  x3 X* A2 E" c- {7 p9 [& s: C" n3 d4 Q

0 @! O! D; N% k. ?) q' S" J' o1 E  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:; Y% d: ]2 ~( l, H8 J+ j9 t
) V2 Z* q; d( M3 y1 u
以下是引用片段:
+ z$ L: g% i6 H7 ?  /* Vertex list structure – polygon */
% f9 U% \! j. g$ W  typedef struct 1 k# X) [$ x# p) M; X
  {
6 r6 \3 f8 [) c* W7 l9 `' B  int num_vertices; /* Number of vertices in list */
! L% ]) g; Y' o0 A  vertex_t *vertex; /* Vertex array pointer */
, O( g, i: N" U$ Q& X7 }; q  } vertexlist_t;
# Y0 T' K/ T$ K4 B* c% Y
2 H1 W4 g; [0 x1 Q( s1 s: c1 M1 V, i6 v9 u6 Q
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:, `$ d- A  F6 u  g
- I: N5 |. z# H8 q4 S  ~* ]
以下是引用片段:
- t7 r& R, ^/ h. I/ b  /* bounding rectangle type */ 3 |, d3 P* t$ E& R# }0 ^5 ]
  typedef struct 7 h+ C- K" U. w/ A2 W' S
  {
1 V, D8 z/ q4 ?( x  double min_x, min_y, max_x, max_y;
. a& N/ t! H# F: X) J1 q  } rect_t;
3 Q' R6 E: r4 X5 g9 d  `6 N  /* gets extent of vertices */
" G4 k7 g" R4 L# u8 b' n  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
& q1 X; C- }* p; W  rect_t* rc /* out extent*/ )
* d  ^" _' i7 \. p  {
' G6 G. m) _% p+ y* a$ R- k  int i; + c% }1 v: Q. X) g9 r0 ]
  if (np > 0){
! V0 ^$ S% X1 l9 n- _2 T; f  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 4 w) B5 ^; m. V9 r8 E% g. _$ {
  }else{
! U) _  b4 `& @( \8 E  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ ' l& l' O8 G, a* S) v* D0 Z0 e. Q" [0 V
  } : N$ i7 K+ A& a% o; h3 _0 D8 S6 g
  for(i=1; i  
! g" ^7 f0 p$ G+ T  {
9 k' R0 c) B& V' u* K3 n0 k' u  if(vl.x < rc->min_x) rc->min_x = vl.x;
: o) n8 M1 ]" E  w) h  if(vl.y < rc->min_y) rc->min_y = vl.y;
" i' I6 ]3 Q- d! w- O; n  if(vl.x > rc->max_x) rc->max_x = vl.x;
7 n8 s  J. @) R5 A% N* v! ~: |  if(vl.y > rc->max_y) rc->max_y = vl.y; 1 s$ A/ S1 r; Z0 w/ ~8 p! ]
  } 3 Q9 B: L' ^, I7 c9 y8 p4 c; S) x- z
  }
& f7 u4 Y0 x  v1 W  Z* {4 \. J" R
6 Y1 P4 `! S; G6 M) B" E: h+ S5 `. p' \1 k" \, N
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
/ a* P6 O' X1 O/ t- D, `6 ^$ A+ z: Q! t* A8 T  D) c
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
( c) ]1 M9 [' A4 E$ m' s' e6 m9 z3 v: c' n. z( }1 o: ?
  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;& t) @$ g3 q8 s! }2 X
" |+ B" t7 N6 D  m1 i
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;, F% U8 W8 X. U: r; F. d

  V! Y1 q6 }0 m: s0 o8 p以下是引用片段:
5 F6 l& g% m# V+ j5 q( N( ]& ]  /* p, q is on the same of line l */ 7 J6 \4 `0 q' G6 r3 ~; Q
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
5 l  E" {; c8 v8 Y2 G( D! n1 ]0 r1 o  const vertex_t* p,
) ~/ `  y4 O. P8 M% m, L  const vertex_t* q) , ?+ U' B  O% n
  {   e, B0 |  J. }" ^$ ~, r9 U5 ]
  double dx = l_end->x - l_start->x; - ~* \1 @  H9 m. {$ M
  double dy = l_end->y - l_start->y;   d# B, J6 E% G* l6 f
  double dx1= p->x - l_start->x; 5 W, X( l& y* x) o1 G
  double dy1= p->y - l_start->y; ! }3 Z: n- Q3 Z  w2 E2 O
  double dx2= q->x - l_end->x; 8 h; o* c& L: Q1 ]
  double dy2= q->y - l_end->y;
8 `4 D) @' G& P+ `  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); 5 |" Q/ z* l: b* a" U8 g: d9 ?4 ^
  } - z, B* j+ b& N  K
  /* 2 line segments (s1, s2) are intersect? */
/ n: f+ q: ]. {: |$ D" w* S5 q  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, . e7 I# e- k; s* {" h
  const vertex_t* s2_start, const vertex_t* s2_end)
. S' @6 \& [8 ^$ q  {
! I$ ^* q9 y& u9 [  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && ' G: ^$ X5 @7 J
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; . X: X  p, n; W' t# v7 X
  }
, Q9 R5 S9 b/ A# Z: P
8 y% I0 a0 h- n( U* l
. V/ B$ O! P7 o/ Y6 B% t  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
4 ]# F3 m$ v- _4 n
. Y: B+ v% n& Z& ~5 L以下是引用片段:
3 s+ c2 }' c" W, k- |3 n+ ?  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 5 Q6 {8 j4 [9 a) l- n( h( q
  const vertex_t* v) ' p( j0 o% w& Y  }# K2 |
  {
# Z- |* |4 A3 Y+ o  Q  int i, j, k1, k2, c; ' Z/ B) R  q$ W/ _
  rect_t rc;
0 X+ w9 R8 H8 \# l( s7 F+ c  vertex_t w; , ]6 e+ V1 j0 D4 f
  if (np < 3) , y2 U# X% j( V
  return 0;
4 {" m& \0 N, S. F. B0 L2 u  vertices_get_extent(vl, np, &rc);
% a, a- o% k' P& k( L. H- e  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) # T' e: I6 Q% B1 r# Y3 g
  return 0;
# m( |3 p8 `  b: v7 c1 l4 j( L  /* Set a horizontal beam l(*v, w) from v to the ultra right */ . z" w( Z' K; ^2 @) d+ y
  w.x = rc.max_x + DBL_EPSILON; 3 |  A" d6 e! Z" [' c) I
  w.y = v->y; + T4 m- H4 w" O; {
  c = 0; /* Intersection points counter */
, l" L% q( p# Z  o7 T" T$ g! _" |9 B  for(i=0; i  ) p2 k5 _( l( b3 Y7 o
  {
% G# |9 B* W% ^  j = (i+1) % np;
# b  p! Z, y4 v  m( R% ?  if(is_intersect(vl+i, vl+j, v, &w))
# Y( L% V- j, m8 q  {
9 X5 X5 s4 G) `+ `: o  C++; 2 l7 d& n/ k" |" T: P
  }
6 m6 z1 V+ y2 q% j! x  else if(vl.y==w.y)
, T% i4 e* ?% n5 t' S" l( ~  {
5 A, W  w2 u8 I2 x2 b0 U* k, M  k1 = (np+i-1)%np;
7 ]* R8 I+ m9 Z$ L9 \  while(k1!=i && vl[k1].y==w.y)
; E. |, R9 N1 v9 b, N- o) N9 X  k1 = (np+k1-1)%np;
; R. P/ R( T' `  k2 = (i+1)%np;
: G7 C. B; w; \6 f1 k! @, D  while(k2!=i && vl[k2].y==w.y)
' g: I7 O7 I9 u4 A& G; R0 J  k2 = (k2+1)%np; ; x0 X, j$ ^3 r0 o$ s
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
5 z# X$ X& s3 Y4 |9 d2 P  C++;   Z( U( o+ Q1 m) F- v5 f) I
  if(k2 <= i) 6 e+ p! A& k* p. y
  break;
" O) T9 `, [$ F: Y5 A  i = k2;
1 E, a" x. ]9 N7 @. T) d  } 8 }4 h- _+ A; Q6 M: T
  } 0 v0 T" L4 q6 E3 h. l
  return c%2; 2 U: ^/ J2 ]% S+ }
  }
, F1 O7 s8 m$ I# n8 w1 R' @  ^7 i" G  M  H! ?6 T4 m' f/ ^! X/ r

" |1 w9 y9 G; i9 I& p$ o' [! z  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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