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

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

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

9 D/ _- K: I2 {- L" d; {) G  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。" g7 D7 G2 k- @: N1 ]
& |" w! A0 B1 F6 a5 n" j. f0 X
  首先定义点结构如下:
. \. s- g) I9 k6 u. M  C/ r/ g& J8 g
以下是引用片段:
0 G9 M3 a0 y; J8 J2 a' ]  /* Vertex structure */ 8 ]9 N& d9 G4 w) m$ {) x) R! x
  typedef struct
# ?. x* Y9 o) p( T/ j! s! ~8 X2 S0 K  { 9 v4 `. Q) F# T5 c+ ]( ?
  double x, y;
# d# h6 z. x1 S/ X; S5 w  } vertex_t;
9 o, k, y+ g: Z* m0 O, {6 s. n
+ ~1 |# @* j) |) K/ \; j8 B  ~
! p; W$ ]$ F6 M$ M8 |  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:1 a0 a& i4 j3 I3 _! v
& x* ^* A" A: P1 k- p' u
以下是引用片段:
; v3 e3 `, V9 m0 U5 l$ W  /* Vertex list structure – polygon */ 3 P+ V3 [+ u6 g7 Y
  typedef struct / m( C7 s) b$ Y/ u9 Z- K
  { ( b) t/ g8 U, V
  int num_vertices; /* Number of vertices in list */ / M! K2 J, }! R: q8 H
  vertex_t *vertex; /* Vertex array pointer */ / \! h/ g8 D- ~6 g: y
  } vertexlist_t;
: s8 M+ z) ?# t6 _% u8 y3 E7 J* o0 X

& T" o- m5 x  P" v, ^8 B  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
. v( }# {2 p2 V; n7 p7 L6 G6 l5 }& Z" i2 X5 x3 u' G, q
以下是引用片段:4 \1 d" I/ q* c: s  ?
  /* bounding rectangle type */ & B0 d  `4 g5 H
  typedef struct " s/ m/ K5 T" m) u9 C4 Z
  { ) H5 o* M1 ]2 f
  double min_x, min_y, max_x, max_y;
* ~) o: ?  N' ~( u* b8 s  } rect_t; 6 H( G4 B$ r. y) b! }
  /* gets extent of vertices */
. _1 D9 Z' @+ t9 t: }6 G  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 0 o2 |& d( g9 V5 ?8 Z9 K
  rect_t* rc /* out extent*/ )
  l3 c* r9 {$ d( z$ I/ l( d) w  {
  g; e7 ?. l6 E  int i;
; n( C5 S6 s- f7 C0 i" e5 r  if (np > 0){
! h8 u8 _" Y) P: w3 Y  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 8 |- f8 ?& J. D1 m: l; m0 t% J
  }else{ ! S8 a3 k) c7 _
  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */   H' X% @$ c/ m2 n. _
  } * e0 I9 V. Y# u6 A: b" m
  for(i=1; i  - Z+ o  n$ C& r/ z; @* Q" I
  { 0 S# Y. s" g7 j- j- w# A# z0 y
  if(vl.x < rc->min_x) rc->min_x = vl.x; ; e) G1 `! g( d8 g5 ]( E
  if(vl.y < rc->min_y) rc->min_y = vl.y;   V$ J4 z8 h; _
  if(vl.x > rc->max_x) rc->max_x = vl.x; # m* H1 i# J; A2 ]" I  g* A
  if(vl.y > rc->max_y) rc->max_y = vl.y;
0 ?" v/ ]" ]. T. s  }
  Z, t$ L& M" U( D# g  }
1 U5 J$ R9 Z- e" W& U' r* U" ]# x$ W& g' g
. V) H& D0 g5 |
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
2 K3 C$ v' O& J* j; x! t
) y! s: K0 a$ K6 x( }% g: M  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
: i. Z* I3 y% h2 I
; a- B0 C8 b# P# [) [  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
) U; P& b/ W! V) |- ?  ]; A( T' D1 @
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
# q( i) J1 b' f$ k1 J
4 D$ @  {* E. v/ C3 C$ j7 u7 s1 b以下是引用片段:  G( I# a4 o0 _+ A
  /* p, q is on the same of line l */
( N3 a# O$ t& |  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 0 F  e7 Q8 z9 M0 T, Y
  const vertex_t* p,
8 k& ^0 g( B% n  const vertex_t* q)
4 n/ `. v; v4 W3 T7 V, Q  { ( L6 P7 E& T; P$ Q9 o9 p% v0 C5 `
  double dx = l_end->x - l_start->x; % |( a! g$ n" U' ~3 ]8 r' v' k
  double dy = l_end->y - l_start->y;
3 t9 \9 s" M7 D# }# u  double dx1= p->x - l_start->x;
, }9 p7 ]! P: S  double dy1= p->y - l_start->y; 7 t# G# [" r/ u
  double dx2= q->x - l_end->x;
5 s  T: {3 w0 x: R( _5 B9 B  double dy2= q->y - l_end->y;
- l+ [4 Z1 @7 x4 u0 J6 N( }  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
$ I: D$ s1 A9 B% x; f  } * ?+ v: ]7 o* q# G! n9 m+ F3 `
  /* 2 line segments (s1, s2) are intersect? */
7 p5 X4 U8 \9 h4 a* e& q; n4 l4 E  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
5 g0 I1 o0 z# P3 i; t9 m  const vertex_t* s2_start, const vertex_t* s2_end) 6 r( X( b1 U: t/ ?2 g
  { 4 m# S3 ~; K* N; u2 B% o
  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 8 z1 i  |! S8 m! e- v4 P, n/ T" ]
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
/ V' q, W6 r: u9 h  } " o5 _; ~" x2 w% x' O/ M

; Q$ q( p3 ?% t' [5 `
2 E, y0 W% G5 _0 U. Q- s) P: C( a% H0 A  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
  N; \5 k$ S& ?) Z' ^" x9 q
8 _6 l- J# `# s以下是引用片段:2 A( L3 T# E/ Z' b' j
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
3 [* H' }  @% W; Q" `$ O9 V  const vertex_t* v)
2 h; Z; Q4 u+ b3 v+ Z( G  {
5 E& {/ g( h" w6 V$ j  int i, j, k1, k2, c; 0 B& U" U+ ]: ~! z5 @
  rect_t rc;
* s* H. Q4 v6 M6 o) Q1 T3 ^. f  vertex_t w;
; Y( j+ U  Y4 K6 n  if (np < 3)
, [* M$ L" ~; V* J0 I$ x  return 0; 2 @1 u7 y$ J# @% G0 o
  vertices_get_extent(vl, np, &rc); 9 ^1 [, N4 Z8 H# u$ z
  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) * ?5 I4 J/ S+ t
  return 0; * N+ I, l& _4 Y
  /* Set a horizontal beam l(*v, w) from v to the ultra right */ 0 h% T* ]8 g9 s! V( L4 i
  w.x = rc.max_x + DBL_EPSILON;
& S% x1 x8 ]1 V( m( d+ |  w.y = v->y;
, n' x! R$ Q" a( h  c = 0; /* Intersection points counter */ 9 q  }! f4 ~% v
  for(i=0; i  
+ [: Q# a! o6 _( K0 z  { ! V* a# \5 i( J9 _" K& I" \( O
  j = (i+1) % np;
5 l) |+ C" o. \  if(is_intersect(vl+i, vl+j, v, &w))
5 d+ A" }# X7 y) ]" \- P  {
5 w4 p/ a6 W% {" I; @  C++; " Y2 N2 z# D6 t
  } : ?0 V* N1 [$ w; s! ?6 X7 ^
  else if(vl.y==w.y)
- Q2 y/ m% ]8 ?5 e  e( \  {
3 }  B- k* e, d1 R+ W  k1 = (np+i-1)%np; 3 ~5 m3 x9 n) @# a4 k" X; w
  while(k1!=i && vl[k1].y==w.y) 8 F+ V, |/ R$ N! h2 {6 c; j+ ?
  k1 = (np+k1-1)%np; 6 ~0 S' W" C7 X  j& t, Q5 q, I. N
  k2 = (i+1)%np; , M, U6 h, Z0 ?& l# z' n7 k
  while(k2!=i && vl[k2].y==w.y) 3 j% I; x! z3 X
  k2 = (k2+1)%np;
! v4 Q7 ]9 R9 J7 k  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) . B1 i% h8 [2 H. j0 Y' H+ w
  C++;
3 n  s3 ?" ]) m6 W. `/ [  if(k2 <= i) 5 r& N' a2 A8 l7 X+ W; ?
  break; 3 y) a! _; u+ p' l/ ]1 j( D
  i = k2; 4 M3 N! R7 \  Q" b% e
  } : [( A$ b3 ?- F7 j
  }
% Z+ H9 ~0 k7 }5 u2 X3 G5 @2 `  return c%2;
% G1 e1 o1 M$ p$ I5 M  }
0 f. }0 U+ X1 I, |. Q8 q0 d- Q/ U
0 t+ t! J7 U* I9 V' b5 P) J; i$ `3 a
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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