返回列表 发帖

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
" }8 N6 Y1 `+ ~( d- o0 t+ {& F& V( t  i2 |
  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。8 f- G, W7 J' w7 t# [

$ M! _8 |" }7 ]* T$ |  首先定义点结构如下:8 x% @! D7 ]+ t+ v
: j" G- o  g( |6 @* q
以下是引用片段:
, a  [: O% k9 g9 O  /* Vertex structure */
7 B6 |: g* ]2 V2 X' a! ~  T' {  typedef struct % N; P; T0 ^' g- O& I/ z
  { 4 O4 _" [% n2 }, C: E4 b4 [+ ~
  double x, y;
3 I5 @1 j. ?6 Z; n3 b8 p  } vertex_t; , r5 q8 j0 c0 X4 n% I0 B7 s

* T- s# o3 }3 N, }* @3 W; b, c6 i7 d% u7 y: e
  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
3 b# B1 z; J7 g" T
' u! R1 \  P' J* e) U& S( r  U以下是引用片段:
$ R" U4 ?; M  f6 E4 u  /* Vertex list structure – polygon */
- o1 T+ o2 L- L4 c  typedef struct
& c' j6 j) Z# Y' s5 u/ `' a  { % [* S( F% L( ?$ h( }1 F6 H. Y
  int num_vertices; /* Number of vertices in list */ 0 K" g: p; d( i1 R5 \
  vertex_t *vertex; /* Vertex array pointer */
) m" [9 n- m) y  } vertexlist_t;
+ W8 f0 e  P. P) ?  T+ k
# |- Z+ u; c& _- e; _0 M6 W) J- q6 _  L
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
$ V* T, F5 v6 k8 i# E  S
0 U. b" ?2 c7 l以下是引用片段:' T* {3 y: a& e. F9 X
  /* bounding rectangle type */ 8 A  e, O/ w6 \1 [4 w
  typedef struct - f+ J) V% e0 [6 N% f. j2 W$ c
  { - N3 Z/ w$ O- p; F$ J8 {9 d. G* x
  double min_x, min_y, max_x, max_y; & n1 V9 o, y3 ]
  } rect_t; 0 N+ }7 F, p' o; v- h) M$ N- S
  /* gets extent of vertices */
0 k/ D( \4 U' V* @  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
' B! P2 s9 O% w5 X  rect_t* rc /* out extent*/ ) 7 a4 U$ B$ `# X9 d* I) @& [9 F
  {   \: E( w; V6 E9 W! {) e1 i' P
  int i; : B5 L1 t% G8 ~1 r
  if (np > 0){ 7 A# }9 {( J) Y7 F4 u* e
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 7 X) l8 h. L, y; D6 L0 ]
  }else{ 7 R$ X" u4 K: [. y/ M: s
  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
8 N1 l, u/ t8 w1 ]/ y  }
, M- i0 \3 d$ g- T+ q  for(i=1; i  : e0 H* J' D% s- c$ X$ ^
  {
) C! x. q! v5 u* |7 |2 b  if(vl.x < rc->min_x) rc->min_x = vl.x;
% H# B) P: R$ j/ A  if(vl.y < rc->min_y) rc->min_y = vl.y; $ X2 Z9 d+ f7 Q8 _
  if(vl.x > rc->max_x) rc->max_x = vl.x; 0 d" T2 L' W* }' S
  if(vl.y > rc->max_y) rc->max_y = vl.y; + m$ g, p* i& ~. a
  }
$ l, V0 Y! s: U  } " r+ y5 b, c, \8 H) k

4 K0 i2 C! ~3 E+ b: b- K+ J) Y& B3 a8 m; O
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
; A7 n0 p, f- K% x- |; `+ b* {% @7 l) S$ ?( S0 @3 e
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
  `9 O- y6 h: i& v7 a$ W' I# x( {! L
/ M7 w: @. [9 w& ]0 f: G+ W  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;5 [9 F6 J  S+ Z5 \

- _# Y4 ^! h& M. u5 [% z: H  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
  c" Y9 p9 |$ W. X6 k; [, b
( O! X0 Y# q; h/ s/ G; n以下是引用片段:% G: ?3 d- q) j
  /* p, q is on the same of line l */ " {2 L9 C. ~6 f2 F. r
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
" U7 u; t4 I5 R1 f3 I8 c. a) F  const vertex_t* p, ) _" ?* @4 M) |3 R: B. d  \( H  p
  const vertex_t* q)
1 r# G1 [+ d' l& C7 c  h  {
$ q- Z3 p- w0 j5 k8 Y' \. T  double dx = l_end->x - l_start->x;
# _6 b) \. v, q) Z% o+ _  double dy = l_end->y - l_start->y;
) h9 h" u1 i- L) f1 l& v$ T  double dx1= p->x - l_start->x; ; k' _4 y( V' L* `
  double dy1= p->y - l_start->y;
9 ?6 z' n* x" k! Q5 C; X: z  double dx2= q->x - l_end->x;
+ I$ O/ b/ G5 _, d7 \* q0 E  double dy2= q->y - l_end->y; : R, \% ]6 w& M) H; O& _
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
+ i/ U4 P9 I8 I, w/ v0 D6 O" S) r  }
+ u. N6 v( O" o% t/ l2 `- }  /* 2 line segments (s1, s2) are intersect? */
/ S( |5 Q" J" j9 K# S0 K  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
+ M8 v) {8 R$ Q  const vertex_t* s2_start, const vertex_t* s2_end) ( b3 {  Y. u, F  `! P: n! M6 B/ d
  {
' `% ^! j6 u( }8 w1 S8 D4 ^  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
2 J) W8 \/ ^! D0 s# R# g5 h; m  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; $ x1 N. Y% |6 Y* O% Z' v1 w7 p+ S
  } ' r  p0 O; _: B1 L9 w; U6 [

4 Y. B, |# w" q( G  S
  e' f3 v0 u* k- T  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:6 @6 O" {* O! [+ M

3 K6 i1 c8 [% h3 O; P2 h以下是引用片段:
. U& J, r  Q6 q2 X& Q  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ & Q8 m8 G1 E/ E: `* R
  const vertex_t* v) 6 R+ a: y. {3 T! r
  {
4 c+ m6 d/ \; @" V  int i, j, k1, k2, c; / I& ^5 S: x, x0 x# ?- V
  rect_t rc;
8 o# {: G& s8 J  vertex_t w;
4 v8 c- R+ t( ]* V  if (np < 3)
' @3 E* B) G* q' Z. @! b  return 0;
* W0 v/ H( ]0 V, f* {, h  vertices_get_extent(vl, np, &rc);
" b% q2 i/ i( ^: [4 I  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) . i4 ^* U$ |+ f- i' H
  return 0;
+ I4 d' d& M0 p# \9 f) O  /* Set a horizontal beam l(*v, w) from v to the ultra right */
, i  D) T" J0 _& B# L/ a1 s3 ^6 Z2 X  w.x = rc.max_x + DBL_EPSILON;
5 B% f/ L: l; ?) H  w.y = v->y; * h4 \2 `/ H; H4 ]2 f  u- A
  c = 0; /* Intersection points counter */
6 C9 [/ p' u' }8 B  for(i=0; i  
2 Y4 H, M4 O9 `7 E; r  { 6 t, r: T" I0 J# m, D
  j = (i+1) % np; 9 Q: d; Y4 i- k
  if(is_intersect(vl+i, vl+j, v, &w)) 8 z, ]  x4 s. N: Z& |
  { 6 E9 m- Z* h4 r; r; i' f/ X
  C++;
, f) U+ q) a- t4 c$ ^& a9 j  } 4 n5 O. a- e% D
  else if(vl.y==w.y) # i: S: ^, v# _- X/ a9 B/ v5 H
  { . U4 @$ m/ Q! w0 p* s  U0 J/ M
  k1 = (np+i-1)%np; ; w, Q+ Q+ z* k4 h% b
  while(k1!=i && vl[k1].y==w.y)
' i7 \/ f5 P5 t. L5 x  k1 = (np+k1-1)%np; / A3 l5 Z( V  x, V* W# `
  k2 = (i+1)%np;
. m! n( ^- ]: A- T/ E' ]  while(k2!=i && vl[k2].y==w.y) 3 V0 @, S. x( N& U% N- F4 v2 Y: G
  k2 = (k2+1)%np; 0 F7 V# `, y( ]. l
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) . h: V, u( ?) f5 P( g
  C++; : h( I. l( Z. n( @- }) j7 q$ k
  if(k2 <= i) / h& G* h  [/ g
  break;   V# k- h$ j% C! y
  i = k2;
/ M% `$ T; Q" i+ ~5 k. u  }
; y9 O# b) \) y, x) i  }
+ x! D! P$ P- ~, {. a  return c%2; 2 T+ \4 s) i( a% L8 D
  } " S: o+ }0 `2 u

  q1 Q3 }3 o& {' G
1 ^: z" a1 N0 A; ]: Q( J( a# c  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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