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

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
$ V4 z8 ^% k8 K" K3 K1 N) U$ P! H) {) D( V
  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。5 v' b# ]; r6 c7 ^9 K$ U1 t1 c' q
" [2 i( ^# H7 ^* q, ?  M
  首先定义点结构如下:
7 `7 H- S- p) M# p
4 S! @0 z* C# R: q8 e$ o- `以下是引用片段:" E$ \% s2 ~% R& T
  /* Vertex structure */
% O' W! k# B6 ]  typedef struct
/ l; Q. K0 T7 e; ?; G$ J  {
# p9 j. t6 f8 v3 l9 M# P% h* {  double x, y;
0 q7 I' ?2 N% |  } vertex_t; * Q6 u7 h% Y: l1 I/ h% s/ e
  Z! c) n9 B4 n: J; E  a

7 z3 {  ?) Q& @: N) b# R  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
- b" a9 L0 E) G) r2 L/ h! G: m2 F. x+ ?" s0 v1 i1 ?
以下是引用片段:
1 O+ ?; Z  g! ^7 W+ N: A. J  /* Vertex list structure – polygon */   j5 `, I- c. M7 s3 S5 q
  typedef struct , {: h' f0 g5 @; \" D
  { + V7 S6 S: f, h. s
  int num_vertices; /* Number of vertices in list */ ( Z4 F7 i9 z2 B1 T& u& o8 O- T
  vertex_t *vertex; /* Vertex array pointer */ 8 @2 e+ o. W/ R" d/ D5 t$ c
  } vertexlist_t;
; B) D# [& ]! z! p
3 e3 g. v( v5 y& a6 |. z  Y( H6 i, s
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:$ y6 f4 S4 n% m8 |
, {; D) Q( D# p- }3 t
以下是引用片段:' C! D' |5 |" T" H
  /* bounding rectangle type */
7 y% i4 m5 t0 `  typedef struct
& a* Q: `& x0 w5 z  {
- p# h) D, L8 G  double min_x, min_y, max_x, max_y; 6 o+ o" w% _# P) n+ V
  } rect_t;
  S. w0 w. J0 ~* ~# Q( j+ U  /* gets extent of vertices */
- j% |" U3 w, T* y  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 7 _  s5 R! c3 Y" z5 ^4 m
  rect_t* rc /* out extent*/ )
. v9 {" V6 T) @, z) J! E7 z  {
1 j3 X, \* M3 t  int i;
: c) W% L- i& r8 L* b: [; Z2 n2 m  if (np > 0){ ! n) `* y* n- @6 T2 w: Z4 y
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
/ R/ j9 H; ~5 `8 D1 F$ t5 l2 j2 G  }else{
' _( d$ A; U/ z7 d5 a7 J! j% B  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
3 I# f5 p7 M, x4 M* b  } ! w% g3 b# D+ W
  for(i=1; i  ! H8 \/ m( D- n4 w% g5 R' L" ~
  {
, R2 o# O) [2 C  if(vl.x < rc->min_x) rc->min_x = vl.x;
$ y: R# y' ~0 e4 U+ j- C" {  if(vl.y < rc->min_y) rc->min_y = vl.y; 7 Y' }: J/ X/ e$ \9 m9 u% E8 A2 l
  if(vl.x > rc->max_x) rc->max_x = vl.x; 2 u4 r7 {2 P0 |& L' M% _
  if(vl.y > rc->max_y) rc->max_y = vl.y; . R: a' v6 U9 [2 P
  } & L2 K) n/ R( `2 l4 t7 ?* {+ l6 u0 O  x
  } / u7 i- X: B: ?2 N6 [* q
! e- A- z/ R; J( v" z

" Z1 j) F  |6 V& }, i" K% s( y/ s  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。: z% `# B) V3 W* r; h' P* T

0 e7 s+ r% C4 C1 \  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
% |; [/ o& s+ F' p4 h7 t4 t3 ]2 ~
% X. V; B- X  D- I/ \  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;, v$ D; F. @" t! W

- w/ E/ K# I$ T& M  j& f) v  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
7 h  N% F5 }2 M. m5 F; F) x
* o2 \+ u. h7 J. n) Z7 q以下是引用片段:7 I2 [5 R; E. d: K
  /* p, q is on the same of line l */ " d8 k+ X5 S9 H) h# n, o
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 6 W7 ]* s* Z; b4 w8 O0 f5 `
  const vertex_t* p, 2 P* Q1 g3 O( i3 X3 F# i' W- \
  const vertex_t* q) . A; N1 T$ z, @3 d
  {
4 M5 n; d! A% a$ ^% F  double dx = l_end->x - l_start->x;
( y7 u) |3 J% B  double dy = l_end->y - l_start->y; * I  A" C; a3 Z9 ]9 e1 W3 P5 h8 h1 |
  double dx1= p->x - l_start->x;
5 U" }* \3 t( T7 f3 l! S  double dy1= p->y - l_start->y;
6 e1 y" y2 G7 l, ]4 c  double dx2= q->x - l_end->x;
; O" {2 U) H2 h+ X- O  x  double dy2= q->y - l_end->y; 7 b" ~( n: X( m2 T) i) y+ b0 f/ _
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
9 R6 Z8 r) a2 r; T, Z  }
* B" V1 [/ i7 n' ]" Q) z+ [  /* 2 line segments (s1, s2) are intersect? */ 5 @$ ]. T5 i2 \
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
" O  m- G- d( e/ X  const vertex_t* s2_start, const vertex_t* s2_end) 3 O: v- {6 l8 Q$ p& g: G
  {
, J' t$ u* p1 w/ P+ u  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&   ~/ u' p5 T5 ^( z# U3 |9 ^; x' C
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
; M# g( Y: R8 ~, y" G. M  } ! }* A& u+ v$ y
8 w) q4 ~1 F" g
0 d8 D4 H6 ?  p/ \5 W7 A  o) K5 ?7 i
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:  H' B. ], a/ E4 v' P6 O
7 t  c6 d3 V2 U
以下是引用片段:7 \" ?5 C1 y$ W
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
/ m/ k2 H" T& ~9 N9 Y$ g  const vertex_t* v)
' J2 t8 q3 u" X% q  {
" _, v, [3 T% U1 e& U* X$ p  int i, j, k1, k2, c;
7 E- y& L4 }1 s( H7 Z9 t8 M6 U  rect_t rc;
! {  x/ s" a. D. j" B; w  vertex_t w; 6 ?4 m3 y8 `0 A7 B' V, d2 H4 s& q9 ^
  if (np < 3) " D. E1 P7 t1 F" y" V/ `6 b) n: `
  return 0;
' g2 T3 M" `! ?9 C( n  vertices_get_extent(vl, np, &rc); + ]1 m* Y! y$ f/ ?+ O( o
  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) + k  K1 l# ~' E- C: K
  return 0; 8 o& K7 U' d8 I$ R" u1 m. U
  /* Set a horizontal beam l(*v, w) from v to the ultra right */ $ f' f; y3 e# |+ H% K
  w.x = rc.max_x + DBL_EPSILON;
* N2 l' h( u; {% h  w.y = v->y; % K' Z8 f6 J+ i* y2 y2 ]
  c = 0; /* Intersection points counter */
+ ?; I  v) V1 u9 U  k" c  for(i=0; i  
  z, ^4 u: T$ W3 u" V* M' |/ A$ F  { ( r0 R( Y+ G7 W5 z
  j = (i+1) % np; 4 T8 D) B# O0 |2 Q% Q  [6 w
  if(is_intersect(vl+i, vl+j, v, &w))
- _9 {4 \4 V8 X4 r8 `+ v# c$ _  {
. Y$ t; }. b  Z" c  j, F, G  C++;
% @0 J" z( \  \* M% P- p  } 2 x) h7 E: q- y
  else if(vl.y==w.y) ' C+ |. u* J* G5 X# h; {, g
  {
# {/ e, Z5 a" c  k1 = (np+i-1)%np;
8 _8 Y4 ^/ V4 [' \1 H9 Q6 q9 i  while(k1!=i && vl[k1].y==w.y)
! `: n! {7 k  ^, }- V/ @  k1 = (np+k1-1)%np;
8 k+ ?& w. V4 D) f) c" f+ i  k2 = (i+1)%np; ! h! x0 l% f3 G+ G; c
  while(k2!=i && vl[k2].y==w.y) ; `0 s/ f2 n; V0 u9 [( D
  k2 = (k2+1)%np; 0 C, n5 n7 A7 Q9 H
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
. z- s6 [5 x3 ~& }  C++; 2 ~& d/ E9 U( v8 }+ j7 J7 z
  if(k2 <= i)
1 m* b. ]6 W' f; E8 `5 |# @  break; ! C* f$ H: K- F' P1 s
  i = k2; 8 G% L( V& S+ M  E( p' ~* a& R
  }
( w; V( }: f: R4 t0 ]8 l6 b  }
& t" b5 ]- c( S7 M  return c%2; ' c5 u% Z3 V1 Z" l7 B( W+ Y' j1 Z. Q
  }   w: t& I0 ^1 z7 g2 u9 O5 S; o

2 H+ |/ j! ~3 [& L* ?) q5 e
! q' Z! l5 M! @! m  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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