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

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。  M3 l8 y3 G5 E/ W" S( P/ r' ]' o
' t" D" V5 u. N1 T; `' N
  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。* |. N' N7 z4 U9 V/ J
& q  J' U) l% o& Q0 N0 t
  首先定义点结构如下:; Y# L7 K8 c9 b# ~  ^& c
9 W1 T9 z7 A" j! K* f
以下是引用片段:- O) m( G8 e( z6 j" n/ v. F* F
  /* Vertex structure */
6 h; j3 S. b4 d' n0 Q( X  typedef struct
1 G" C: x' ?& q  P* x$ m  {
, Y# F: K, k& b1 ~  double x, y; " N4 [8 v% |$ f' w1 u8 _3 h
  } vertex_t; ' @* K7 \( ]9 o% h* H
1 @# p9 K+ i$ i

" P. u1 q5 P( k1 _- @  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:! r/ m4 `) l; B
+ i& e: P$ X8 X. N! I
以下是引用片段:
" K$ K  X! V( l+ ^* Z9 N  /* Vertex list structure – polygon */
% A; E4 s& C2 B$ @7 u; M  typedef struct   w+ @7 ]2 \" d2 H# f: i6 X' G3 x
  {
2 f; `  w5 Q9 N/ s0 ?7 a, y  int num_vertices; /* Number of vertices in list */
' W" t/ y: Z3 P7 H* k, r- u  vertex_t *vertex; /* Vertex array pointer */ & |$ i9 O3 c8 a% e- K* b
  } vertexlist_t;
; }0 X6 b0 @# ?! T3 x$ f" L: F! d0 U9 o# g0 q8 u! l
1 h1 g1 w) v/ E% E4 z+ Q
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:( i2 t0 ?+ F# o% Q
# K* c3 ]0 U$ Q0 u7 O. @
以下是引用片段:+ D( m' k& O0 Q7 l, N
  /* bounding rectangle type */
. V# E  d. v7 w0 r  o8 T  typedef struct
: [8 p% h, ?- L$ `4 \4 Y3 I  { . w2 n6 j# Z+ y8 h6 l4 U
  double min_x, min_y, max_x, max_y;
8 _% }! [0 @) F9 T  } rect_t; / ~0 a9 |* S# _" d' T3 i# M: M; h
  /* gets extent of vertices */ 5 T3 V$ b$ O- A0 C% t1 J
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 7 N1 q" L& `# S5 C! V# A
  rect_t* rc /* out extent*/ )
" ^1 b4 k( C- }% l4 C: z  { 1 J- T8 L9 L+ o9 M
  int i; . \! S8 Z! J; `$ p8 R
  if (np > 0){
* @( ^6 n# C& q/ ]5 t6 B  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
) T  \- C# A, x# f. e  }else{ 1 K( A& O8 K+ G5 S' A
  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
- k. G8 F, @* S8 ^  }
# ]0 e8 s- Y: u. P  for(i=1; i  
( [( b+ T( H" l2 v3 w, B  {
  M/ s& O# [! d  if(vl.x < rc->min_x) rc->min_x = vl.x; ) P& X+ K, Y% Q$ L, K( L; F
  if(vl.y < rc->min_y) rc->min_y = vl.y;
$ L  }7 E4 Y5 j  if(vl.x > rc->max_x) rc->max_x = vl.x; " d# {& A4 u" d9 n9 O
  if(vl.y > rc->max_y) rc->max_y = vl.y;
6 J7 z3 _5 ]" ?3 n6 w0 l  } 4 {  h0 ^- P7 z
  } 5 i5 J* C7 l! `3 T
4 S) }- T( G# Q% |

4 B3 x. D4 B2 r, w& W; F3 h- A* i0 A3 ?  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。. s% D4 z9 f" V5 l* i) l
' l5 V  B) Z) d  B4 s4 ~1 }& W: q
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
3 U* ^( s4 x$ j
) n% Q( e) s$ P( D) X: N  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;, g. C& Y: e* J) n4 }$ v
6 `+ |3 M; ?- R9 s: d' }7 h) x
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;; m" n/ `; o! F6 z9 e$ [7 |: X+ y
+ a( t7 z1 N: k7 I+ ~
以下是引用片段:
2 m. q  y) q, a3 N: |  /* p, q is on the same of line l */
$ y& [0 ~4 P) K2 g0 T6 d  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ # g9 e/ c4 B3 {5 l
  const vertex_t* p,
+ r$ E- T; J* V7 S3 c4 @( U  const vertex_t* q)
4 Z: D; B2 w. s, x1 L  { . B4 Q% {* q) {7 \# P
  double dx = l_end->x - l_start->x;
* b: c& N1 a" _4 F( [! I  double dy = l_end->y - l_start->y;
4 @) u) I. V6 e1 r9 F4 N  double dx1= p->x - l_start->x; 8 ?% F3 s$ Z; F+ V% K
  double dy1= p->y - l_start->y;
7 g9 s4 x4 U: K7 E. {/ h" d3 r* M  double dx2= q->x - l_end->x;
" G3 u9 q, b3 H) J% d, H  double dy2= q->y - l_end->y; 4 c* x" {4 y# s8 E: s/ v
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); 8 C" z; r% V/ S+ t
  } " w$ y+ |0 k, r4 Q* G9 J6 W
  /* 2 line segments (s1, s2) are intersect? */ 8 [& f2 x* S9 M( b) W5 r
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
0 Q: x2 u' V! |1 @( i  const vertex_t* s2_start, const vertex_t* s2_end)
* ~1 X9 w4 b/ ^, U, J  {
% |. z# e$ C3 q" R/ m) j  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 0 o6 `) ~2 i- l1 V. z
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
1 K: s: c! t$ j& K! b+ i" `  }
8 y% n; `/ W" _" P* r4 K
- V7 I9 K3 k# \$ [4 Z3 K4 \# ~5 B4 t/ l8 m# b
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:8 C9 f; e4 q# ?% E; ?1 @& L+ c

1 q* y6 W1 N/ }以下是引用片段:
: A# V% O, ^7 ~, W3 J  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 3 W- S, e& n" \: c
  const vertex_t* v) 5 p: ~7 A4 w' L7 i6 N6 P
  { 2 b1 t) o% r- {
  int i, j, k1, k2, c;
. y; W# B; o+ f- H7 L: a3 D) f/ O  rect_t rc;
  g: Z/ T: C1 y+ s  vertex_t w; - \+ {2 K# u0 G" m1 P; t* x
  if (np < 3)
! `0 o8 A* D! t6 i; b$ O5 [+ c  return 0; % {* l: n" X; V' n- q1 _
  vertices_get_extent(vl, np, &rc);
  A$ D' j; }8 p  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
5 J0 @; X  J, B9 E  return 0;
( S5 @5 A! A, z9 z  /* Set a horizontal beam l(*v, w) from v to the ultra right */
/ h. a- V# ?3 N/ R2 E  F& H  w.x = rc.max_x + DBL_EPSILON; / b' g  u9 _" K$ d0 u/ C
  w.y = v->y;
4 w( C5 x% Q4 k" M4 V& Z  c = 0; /* Intersection points counter */
: u) ?; X: E$ O# _, G  for(i=0; i  
( n9 R( s9 |) E- n/ h  { ' ]. S  F$ J) o8 H' k4 n
  j = (i+1) % np; * @4 m" i: D+ H, m
  if(is_intersect(vl+i, vl+j, v, &w))
, u4 [/ Q6 A/ J  F) u- E. _  {
( L8 d/ Q4 b( E5 h8 h7 Z9 E1 h  C++;
# T, H, x: H1 |! X( }" k2 D; j  } - p7 h' {; F: @( d1 M
  else if(vl.y==w.y)
4 E# F6 h2 V5 F+ m9 U" [' _( \6 E  {
& b  v5 }, d  q' v  k1 = (np+i-1)%np; $ D4 i- J2 ~. s* \1 u
  while(k1!=i && vl[k1].y==w.y) 2 \7 w* G! `8 p; n/ L
  k1 = (np+k1-1)%np; # C. \" _+ W/ p1 E7 R: u; T; K# s
  k2 = (i+1)%np; 1 L9 E& y9 ]% v; H3 o
  while(k2!=i && vl[k2].y==w.y)
  L( K. A7 k5 \0 c8 N% N+ {  k2 = (k2+1)%np; ) x0 N; n0 S5 o
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
  T; a5 ]7 k' x8 F  C++;   ?: P& P- I& n  ]
  if(k2 <= i) . ]2 T' X( |) |& F
  break; , }9 r4 ?7 H$ S
  i = k2; # w; r$ R, e" m4 ?8 m* E% u
  }
2 v* l9 _- f9 G  } ' t8 b9 W. ^" L
  return c%2; ! K( h% M7 W  Q9 o8 \+ b  C; R. |
  } - O  J; ?0 b! M! h
- h3 W& N, Q9 i5 N' s; [7 T: ]

3 G1 q) h9 J% H  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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