Board logo

标题: C语言中显示 点在多边形内 算法 [打印本页]

作者: zw2004    时间: 2008-1-21 17:20     标题: C语言中显示 点在多边形内 算法

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
* h9 t9 q) l; J* ]3 ?% Y
0 E; l0 G0 [: g  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。! |" N' E! X: _

: h1 W% i- N; P: X" {  首先定义点结构如下:8 A$ Z% P& q7 a/ E" H* W

2 M' ~1 z. c$ n2 F以下是引用片段:. n5 Z0 Q, C: z6 i0 U+ n
  /* Vertex structure */ ; C. t7 F" D7 C* i, B4 @# e
  typedef struct : ]+ X1 k" k- W) t
  {
+ ?0 r# N, @( ~  double x, y;
9 E; s3 i# s/ s  } vertex_t; & G/ }) M7 P* W$ u# |+ @
  K% C/ k6 h0 H

6 Z# M; w! k  A! G) R9 y% [  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:5 D6 L4 ~/ v  G- v+ U1 j5 F# f- B

4 w, h# y  \. i2 w5 K, \* o以下是引用片段:
, p) o6 Y/ q% m8 C: u4 @  /* Vertex list structure – polygon */
3 ~, x! X  v7 E9 n- r( O; C  typedef struct 2 g, q( T9 \' _1 l% ?4 p
  {
5 p' T* h1 J9 e6 x6 B- h: W# ]  int num_vertices; /* Number of vertices in list */
6 }9 W/ w& F, i5 D( J3 x5 v  vertex_t *vertex; /* Vertex array pointer */ % m; u+ |! m( t) S
  } vertexlist_t; $ o- ^4 I7 {7 Z; ?1 ]' a2 q

- B0 o& k/ V! ]7 k( p* L. W8 F2 O+ t" D( r) Z- ]- V8 ?5 D5 S$ R
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:( _4 \3 m& D' I, y  a

3 t8 h" P  m" D" y8 ?以下是引用片段:6 x9 z. N/ A" O0 B/ g
  /* bounding rectangle type */ # G( e$ j' t  g* h0 B4 H/ E8 ^1 ^
  typedef struct
& l0 D4 h* A9 D7 Q) o  {
7 `5 q1 s# z% E- D& i; T: A, B  double min_x, min_y, max_x, max_y;   `, n' o# |. D0 x2 n& t
  } rect_t;
* C* `: h, w( G+ K* Y1 ~  /* gets extent of vertices */
4 p# T) q4 K, m- i  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ ; ^5 G) F0 `9 j! |3 w' A8 o
  rect_t* rc /* out extent*/ )
, `4 W- s. E2 f; D" f% `  {
; Y  x( |) S: |; h8 {4 g  int i;
: B* G# ?( n2 [: t4 @: j  if (np > 0){ ; [$ M) C" R0 q
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; ! T5 _& o+ o" c) y0 J7 |: T
  }else{
% o2 W% R: g; W% ?3 V% {  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ 2 M* c: V. G* G5 d, `
  } # B( \; ]* {/ T7 o5 u3 t1 D
  for(i=1; i  * `# B. x) z( n8 |
  {
  |6 f) x$ `9 a6 a0 X+ c) d  if(vl.x < rc->min_x) rc->min_x = vl.x; 4 N# T5 ~* @, c
  if(vl.y < rc->min_y) rc->min_y = vl.y;
+ `, Y7 H+ ~" v  if(vl.x > rc->max_x) rc->max_x = vl.x; ' ]; R4 T5 H1 ]! X
  if(vl.y > rc->max_y) rc->max_y = vl.y;
. I! c2 V6 I/ i  } % \0 \4 F+ s5 y8 Q3 O3 }
  }
$ v: A$ i. n; B* Z
7 E5 j0 z/ }7 q4 f8 `
5 T0 ?4 m  T2 m% S% ]  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
4 n3 E3 P' O/ ?* Z4 P+ U6 ~/ D. `4 `* }8 B
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:7 \# `; h2 W1 S" S0 N. F
$ E4 t' A% Q1 p" w) o7 r! D
  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
; l& `6 K, |* x7 w: Z$ H
! l- L$ X+ |, t& ?1 _& Z  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;5 J" ^, {0 F0 m5 B8 f( |7 }

/ H# {9 K8 \' K8 B* B以下是引用片段:
8 N9 g" {! i1 {9 y& q  /* p, q is on the same of line l */
4 l) Y& ]. k  M  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ & X( r$ z. k& S# q8 G+ \
  const vertex_t* p,
% f  m. R# E- E  const vertex_t* q)
1 N; e8 {+ J8 l$ C" b: A  {
( J! K2 g; `3 {2 M. g# P  }  double dx = l_end->x - l_start->x; # v% j& n& L) n; N$ a  q
  double dy = l_end->y - l_start->y;
  ~/ o0 J  ?; X  {8 r  double dx1= p->x - l_start->x; 9 f9 s% Y# m. R! J: l. c
  double dy1= p->y - l_start->y; - n' d! S3 [; P
  double dx2= q->x - l_end->x; 4 T9 v: ]" a- e: q' U4 g( \
  double dy2= q->y - l_end->y;
; l: D0 e5 G7 H1 \, p9 c+ f  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); . R1 t) N; R1 }$ F" o
  }
$ k( i5 _; Q6 G  v. j- W6 @6 v  /* 2 line segments (s1, s2) are intersect? */
) z$ T$ `7 ~8 [0 R( S9 X% u; z  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, + T7 W- Z8 h0 V# K
  const vertex_t* s2_start, const vertex_t* s2_end)
/ B' S. t% B. l( I* ^! J6 g( _  {
7 C1 T+ V, P8 Y$ q  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
  k5 q- ^" v. L  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
2 W; }8 g$ g2 J: h  }
  p1 H: m6 E8 o7 o! ^3 S( R- a$ Y" ?3 [3 z- A+ ^

- ]1 M7 `  \; |: g4 I  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
' G5 d( h) q4 h/ X" T0 U5 A. |8 ~6 b
以下是引用片段:& \/ @2 G( b9 n) D1 H! f) u
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 0 O8 ~$ ~2 K( f. e7 J
  const vertex_t* v)
1 o  a' [3 R, E' ]( }8 L( s4 \  {
& L/ `4 t5 W' a  W  k  int i, j, k1, k2, c; * t% R" n; f6 |) b4 M/ Y# F
  rect_t rc;
/ }+ {, T. j6 N3 ]' ?7 b! }  vertex_t w;
5 I% ]  h! ~7 w) O: F  if (np < 3) 3 A( G7 v$ }" j- g
  return 0; 4 A, l+ x. J0 `, G" t: L8 X
  vertices_get_extent(vl, np, &rc);
  y  G( ~  N0 T  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) # G9 |2 O9 V$ Z$ t, ~& w
  return 0;
$ S; c4 E; O2 a2 c6 u$ x; T* ]7 f1 V  /* Set a horizontal beam l(*v, w) from v to the ultra right */
5 S# f+ P  ~7 q  w.x = rc.max_x + DBL_EPSILON; ) ^+ v+ f* H% [  S
  w.y = v->y;
" `8 H) E6 d& }  Y8 \8 N( i  c = 0; /* Intersection points counter */
( ~& ?% D' s5 ]  for(i=0; i  - c( o  u2 M, A3 N; G4 V
  { 3 @& f( P2 N4 i4 x
  j = (i+1) % np; 9 ?& n1 a+ v4 t
  if(is_intersect(vl+i, vl+j, v, &w)) 2 z% B) Y7 }* g& p/ F7 J# u
  { 0 V' f; ]! u- M' Z0 x
  C++; : |9 A' K5 s- E, v0 j
  }
5 p7 b* C" U( D) ]  else if(vl.y==w.y) 5 C* H* T# c. X8 u$ J" f0 B
  {
6 e7 ^; {) W* r  O4 d- ]+ B  \  k1 = (np+i-1)%np;
/ ~+ @! D+ T# y$ n8 ?  while(k1!=i && vl[k1].y==w.y)
7 S+ o  R) [) j  J, z  k1 = (np+k1-1)%np;
* I  A. X9 s/ ~  k2 = (i+1)%np; 5 J- K  y" Z: T" |& ^2 }( T  ^0 @
  while(k2!=i && vl[k2].y==w.y)
& [/ j* g2 @2 ~' @1 {  k2 = (k2+1)%np; & ^6 t2 b: c! B  L% N. ^4 W
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) & h. {) P3 x- H/ P, r
  C++;
8 y2 \2 U* _. |0 h  if(k2 <= i) ! X2 l5 M: t# ]3 t8 U* f2 Z
  break; $ Y3 K2 {6 t  Z$ _  U9 s% s/ F
  i = k2;
! }; @0 d4 L+ n. C+ I+ ?: m  }
2 f7 O, Q  X# k% P( E! E; g  } " |. u; a2 C3 R: e9 s& ?
  return c%2;
. k4 j. c: ^! R8 O9 a  }
3 g, [3 W/ k, g+ L: G: \) b
  H0 \+ C* a; W$ _) u$ B
& ^( Y+ ^- o, H6 i' s" X  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。




欢迎光临 捌玖网络工作室 (http://www.89w.org/) Powered by Discuz! 7.2