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

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

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

& M1 z3 \  Z4 c  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
. ~; N! l* }7 z) o) ^1 O4 C" }5 S3 {# x* b* b/ I$ K& C% b1 q8 Z1 S
  首先定义点结构如下:
' O7 u+ p0 u+ L( }' s% h3 X
9 A6 a" O* a+ ^* K5 r; S以下是引用片段:5 R6 @3 Z! g! q9 d
  /* Vertex structure */
5 \5 ^, T+ t2 @* `4 d" G  typedef struct
" Y+ X) P1 ]8 b; d+ j% f  { 0 Z1 Y# Y0 E7 }, M/ _
  double x, y; # y4 G' `5 Z2 Z8 k" _# i* y
  } vertex_t; ) r% b* X. J" n, k: `
( b2 z% R. ~; e" q: ^4 H: o
$ x( \4 F- r8 x9 u% {3 V4 b0 X
  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:4 e* A% W! ^% c: B1 |. n$ Z7 G
8 N" T. E: o8 f9 F
以下是引用片段:
  `. X7 Q; P1 Y& A: B  /* Vertex list structure – polygon */ ' D5 M" n5 a( l( L, r. d
  typedef struct
% [; N/ K1 S0 ^! b! c; L  {
: i; H" o& f: ^; I% Q  int num_vertices; /* Number of vertices in list */ * f& P/ m: H5 [8 t
  vertex_t *vertex; /* Vertex array pointer */
3 s7 ?6 E$ k% \/ z# g  } vertexlist_t; ! v; w8 H2 W$ C) p5 Y
( F$ v5 f/ Z1 i4 {

; n9 f+ o; M, i; U9 V$ V  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
. Q6 u8 Q- ?% W6 z0 i% q
. v# \; H. ^# G" e, j4 A以下是引用片段:
! U+ E7 G4 U# a9 q4 r5 s$ H  /* bounding rectangle type */ 4 r; G' p* z4 N: ?) s0 s
  typedef struct ( _# g; p! |. q& f
  {
# m& |. Z8 ?$ q  double min_x, min_y, max_x, max_y;
2 X7 h. r, ^9 v5 A/ ~* R' y- N  } rect_t; 1 [, I( _  r. J+ n4 `" p2 {4 N
  /* gets extent of vertices */ ! B) f2 j2 F; T* Y
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
9 ?1 q) r. k4 R  rect_t* rc /* out extent*/ )
4 @; n* @/ C, v* h+ r  {
6 G- x( L; c+ F$ I0 q9 l/ D2 T  int i; * }( X+ l0 g) \. u
  if (np > 0){ 2 ^2 q" j8 I1 _: h; E
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; ! @0 p# z, e+ O" H4 j
  }else{
: i8 _# z( r; [1 }; L( z  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
) N$ E6 m  T% _) }: ?; P/ f& Z  } 4 U1 B; f) p1 n- N  ~3 o; {4 t0 l0 u
  for(i=1; i  2 D* z% u% ^6 _! S6 T% G
  { * ?! R! u( |3 Q) B1 a: M: l% R
  if(vl.x < rc->min_x) rc->min_x = vl.x; 1 P" k# j3 K8 T$ D
  if(vl.y < rc->min_y) rc->min_y = vl.y; 6 @2 d1 ~' v9 ]+ Z$ ~
  if(vl.x > rc->max_x) rc->max_x = vl.x; 4 k* O' @5 b' D8 ?+ ?
  if(vl.y > rc->max_y) rc->max_y = vl.y;
3 ~0 h: b7 b/ X4 h* V  } $ a4 x0 r! z9 f2 l8 u
  } * L4 G+ e# R5 y
+ e) T6 Q  g. S' [8 z
6 I4 F0 K& r4 b
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。. V6 N8 _& p, E
' C7 @; p. G6 K- M' q4 O+ ^
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
. H2 m" |: J% W0 s" d: O* n6 e) C1 `% k* M% E* Q& z0 K$ D% f, p
  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
  J: n& T) ~- d/ A1 t. r" g+ o; k
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
/ f7 h* V2 W1 ~0 l8 K1 O( p0 l3 V; x  Z' x/ R4 y* E
以下是引用片段:
- D  e( }' a% e/ H  w  J# V  /* p, q is on the same of line l */ + Z% G0 |9 ?7 @+ Z/ L! W
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ ; g6 W' K7 ?2 |0 }' E# G9 N
  const vertex_t* p,   c+ R: n* s5 e# a
  const vertex_t* q)
3 `6 I( X4 o4 S' C! y  { 6 b) _( T7 R2 a
  double dx = l_end->x - l_start->x; " Q6 ?. o/ m& k: n1 O
  double dy = l_end->y - l_start->y;
: M4 Y% E; q9 D) _  double dx1= p->x - l_start->x; + o0 K  j$ d6 w, U9 L% m" e6 R; Q
  double dy1= p->y - l_start->y; $ {* y  y6 e2 O
  double dx2= q->x - l_end->x;
! D' h1 ^+ v4 `; k0 }; K: P  w  double dy2= q->y - l_end->y;
0 T0 ]+ O( o# U4 L( j: a  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); - `4 v; C( B, O; t
  } 4 }, R! R9 U6 d/ Q
  /* 2 line segments (s1, s2) are intersect? */
* u6 m& Q' O2 _* L1 P  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, , Q' K  B! Z0 O7 \# t' d, D
  const vertex_t* s2_start, const vertex_t* s2_end)
5 w4 A* G4 U! D1 ?  { 9 Z" X" V( n& b+ I& y" Q
  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && - F& H+ Y/ D% b; m" p. ?
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; 0 j, e8 ^- _2 U) l. c
  } ! i8 {! r% Y: Y: y

& \: c2 r$ {: H
% E* u8 N1 A" D* |2 g, S  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
& w; I: c0 r9 N$ w0 p6 G% Y9 H2 K! s3 o! y; L# i) V; X7 J2 S% Q
以下是引用片段:) L+ N* p% B  {: D% Y
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 0 O. W0 p' o' i
  const vertex_t* v) - g0 G# @: J" X# ^3 U
  { ! q+ Z- j: q6 h
  int i, j, k1, k2, c;
9 F0 r3 \" z& }7 E+ W  rect_t rc; / T. {4 A  A, F! I$ F+ s
  vertex_t w; 8 F3 M2 Z& O# f; q! x- w
  if (np < 3) " u  A2 m$ C# O# f, |& O
  return 0; . V. C; K  O, Z3 l. {* \- t, c6 [
  vertices_get_extent(vl, np, &rc);
1 B( k: S/ o* Z* y# k1 Q  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) ' I" r7 l6 I# j: S# I4 H
  return 0; 1 {$ t1 t4 H# ~; g
  /* Set a horizontal beam l(*v, w) from v to the ultra right */
# R& {0 \4 N" Q1 D0 w2 {4 g* j  w.x = rc.max_x + DBL_EPSILON; 2 g9 e  o; |, e* p
  w.y = v->y; 5 t# W; a2 n1 @! b  A
  c = 0; /* Intersection points counter */
, M* p% X* \' Y% ?  for(i=0; i  
; C$ u; W; J$ G  P0 A* \8 V$ o4 U* N  {
5 F( C) ^1 i" i5 `5 ^8 e5 Y2 T  j = (i+1) % np; ( @6 W4 E( I* o+ K7 J
  if(is_intersect(vl+i, vl+j, v, &w))
( |& Z& c1 x4 ~/ }  {
3 Z% n. I7 ~" l8 f9 E7 S3 h# @1 H  C++; / q# @" h5 x7 f3 r
  }
' N3 |0 M" Y! B& m' V  else if(vl.y==w.y) ( j/ ?( a# K% {+ s" S& S
  {
% _6 E2 O" }. ]1 c) e  k1 = (np+i-1)%np;
. F" h- O* e* X/ \, y7 _  while(k1!=i && vl[k1].y==w.y)
+ u) j# w5 r2 D8 s' H  \2 O$ N  k1 = (np+k1-1)%np;
6 K6 q+ N$ y! H' n  k2 = (i+1)%np;
& u. d6 B4 e8 E9 P" h" ^3 I2 N. r  while(k2!=i && vl[k2].y==w.y)
- Z2 f. P/ U( A. N1 j  k2 = (k2+1)%np; 8 g- R  ~/ K+ B. G% Q  M; Y
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
8 g  D8 S+ \0 i1 R  C++;
/ U- n- a4 t2 c% O0 O/ u  if(k2 <= i) . ?" Q) y2 p- q. q4 U, H6 ~( m
  break;
5 q0 R- _# N. h& G  i = k2;
9 n0 U/ m7 U5 n. B% h7 o) g  }
8 l- _* K% |$ g) p4 i! F/ T4 S  }
# y) a$ N$ e  \( u* S. }4 b) L  return c%2; 4 k. |! E# b* _6 b5 a
  }
/ K: j4 x( ?% v7 j2 B; r8 S, [" V) \/ w

# ~& q0 v6 W' q+ y# l/ S, F  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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