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

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
9 C# p$ e3 O$ Q. m
: p$ j2 P, _; ]  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。5 o1 f% ^1 {, b1 h, a$ G* L
/ g6 a: g3 ^+ ?6 e% m1 r3 M2 P
  首先定义点结构如下:
3 h8 ]7 E; g! l7 }" D; G$ R; j1 x0 H2 k3 ?
以下是引用片段:3 Z/ v$ Y8 k: x
  /* Vertex structure */
" a6 {" b) t1 d& _1 c  typedef struct 7 [2 M+ A. A, c- d# I
  { . t: ^  S6 L* `, [& F
  double x, y; + b7 i/ W; h1 Y2 Q  n) I
  } vertex_t;
5 _: ^9 @# j; Y+ }% _( I! B$ C. F
8 g* A- c( p0 X
  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:& X# a+ F! r# D' k9 U- d
- ?7 i6 z' m$ C9 n$ L1 Z3 g5 J
以下是引用片段:
8 E" m# L6 E" h8 Y6 _  a; T! U" a# B  /* Vertex list structure – polygon */ ! [# P1 j! F+ ?. C( I9 j( g6 I
  typedef struct * Q' i! S1 h4 z$ r- k) Z( B/ C
  {
& e, L. @( A' R( z8 ^2 u2 ~% n: l  int num_vertices; /* Number of vertices in list */
" N2 \+ @4 k7 N6 L; Y" E/ Z$ Z1 s  vertex_t *vertex; /* Vertex array pointer */ % Z) l3 s8 d  @7 x" D# K
  } vertexlist_t;
2 W& `6 e% X! }& U! H' c8 x2 O: E
( K& k" L" G+ W8 C
; W; @. s9 `8 l% L; m1 ~  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
3 k* N, Y3 c% ~) P- l" v$ D5 ~+ {* e
/ ^/ H5 M$ A- S5 H1 e以下是引用片段:
9 f" Y1 x  r- M) n$ Z* M  /* bounding rectangle type */
8 N7 @! |! C$ i/ Y; h  typedef struct
4 b5 b) L3 F1 _# D$ T  {
" W7 R7 r/ i' q* Q  double min_x, min_y, max_x, max_y; ! f! t; s# T: V- m
  } rect_t;
5 _0 S; V. v6 C5 }" i  /* gets extent of vertices */
* h3 t% s& v1 B7 z3 a  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
7 v( h1 ^, V0 R: T1 B- q  rect_t* rc /* out extent*/ )
% K9 M* i# Y$ A- v  { . ?; O- Z! k4 S; L) C6 i& E
  int i;
: T9 h$ x1 g% B% ]9 g0 F; ~  u  if (np > 0){
  N( f3 ]6 O2 I  u- ]6 Q  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; % e% `5 w7 N6 e6 J4 C
  }else{
+ {3 y$ \( d- l$ V* E$ a1 {  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
" g& N% w! T& X1 o5 k, o4 t+ ^  }   }. D( G8 e( @6 }) ~! Y" V& M, {
  for(i=1; i  # f# K1 d( `+ n, j0 h
  { : w' [+ p" V4 e+ X" C4 i
  if(vl.x < rc->min_x) rc->min_x = vl.x; 7 w4 V# A0 Z/ o$ p3 |
  if(vl.y < rc->min_y) rc->min_y = vl.y; : D- L4 ]% \. ?0 k% ?0 y9 N
  if(vl.x > rc->max_x) rc->max_x = vl.x; 8 d- U0 M" O+ x  b% x
  if(vl.y > rc->max_y) rc->max_y = vl.y;
/ t+ d/ }. z7 x( ?2 `# v  }
' N4 b" g2 r3 ]- L+ y; _9 `  }
8 Q: b) A0 I. _" j
6 t( M0 {+ k. Q  t, h2 z, c; X% A$ h$ e1 z; I
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
. _/ O& R4 I+ |! S3 {' w/ A8 m3 x; Q: F9 l# v1 ~- b& b9 _
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
; e4 [6 Q4 l% g
- U! t$ g. Y. v  R  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;5 V; `4 r* `" D5 t
: }: D. W( Y) `6 w
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
# b# S( F6 ?8 x  D" Z9 `6 D
: r6 W% W9 Y; i5 e8 W' d* X9 w' D6 u以下是引用片段:
3 N6 e% H+ ?1 c+ @0 m  /* p, q is on the same of line l */
0 [. F3 f' Y8 k7 X  i3 [  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 0 H6 [, L1 R* l0 R3 }+ Z0 G% T& V
  const vertex_t* p, , \% l8 K4 H+ W+ A+ h! f  R  |
  const vertex_t* q) . t0 i) T; g' g8 f& A
  { $ [1 j" r: V( ]6 w. O( o4 ^
  double dx = l_end->x - l_start->x; & w* @5 F& {8 q
  double dy = l_end->y - l_start->y; 6 P/ e% n. N4 D, [, M1 y+ z$ o7 n
  double dx1= p->x - l_start->x; + d1 F9 b- Y5 x* @; h; n4 B
  double dy1= p->y - l_start->y;
5 {7 b4 J% f1 V' z  double dx2= q->x - l_end->x; " G5 B& P. e' ]
  double dy2= q->y - l_end->y; - b  `- I/ B7 x4 O
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
+ a! A  D# L' j  ^  } 5 o4 h3 F& a2 Y7 [' i$ e
  /* 2 line segments (s1, s2) are intersect? */ . v$ ~# Q  M' p; S$ R# \; H
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, $ a9 _, u. T: T, d: T+ E2 K: {
  const vertex_t* s2_start, const vertex_t* s2_end) # W3 x$ ?4 p  s
  { , i- _/ C  \  x% e: r( K
  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 0 Z: c" Q+ Z( a' D6 N
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
) c7 T: E' B9 s( ^  } " Q2 t7 x# u# d

% f+ v- X$ p1 u5 L& s) [& ]1 M8 U6 m: b, O; s$ Q. A$ }
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:- i; h1 w2 }5 G) D- t/ m) q
* J2 ?! R, t+ L$ H
以下是引用片段:0 p3 t% L1 F6 e: J
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ ( ~' Y' }+ ]! L/ q
  const vertex_t* v)
  D6 }7 i& O( X+ ?8 T8 S  { + i1 e- e$ {$ B# B
  int i, j, k1, k2, c; 7 }. X; h+ I9 M. n' N4 i
  rect_t rc;
( Y0 V7 _4 _) B1 [8 F5 w+ Z0 J  vertex_t w; . g5 R) _) ^; l* O/ F
  if (np < 3) % F' s9 s1 r# E
  return 0;   [  L2 X& ?, b4 {& P$ b
  vertices_get_extent(vl, np, &rc);
+ h- \2 l7 \; G  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
2 M; Y. b6 _5 f: z5 S/ r* S4 h  return 0;
. I) k4 @, a1 P4 r  /* Set a horizontal beam l(*v, w) from v to the ultra right */
# M2 ?, A6 A% r( j( k9 ~" [* C  w.x = rc.max_x + DBL_EPSILON;
4 e5 x! [  d% Y  w.y = v->y;
# P* ^( r# C7 @/ v9 p0 S+ T; v  c = 0; /* Intersection points counter */
! e- r6 M$ @6 P6 R  for(i=0; i  * g" t# u5 S! E9 W9 O: {  i" f( G
  { & d. H  J% ]/ c- q. B* p" I0 t- c
  j = (i+1) % np; & I  S* Z3 H+ d3 k; i9 o. I
  if(is_intersect(vl+i, vl+j, v, &w))
8 g1 l" W& T3 W. z/ ]( e  { * g4 M. K) n/ s( V* O
  C++; - x6 Z# R1 X) @) q' G
  }
3 Y3 q- R, }5 ~2 a- }9 G( |  else if(vl.y==w.y)
% R2 C; E2 E9 X! g  { ( o* B4 `* T- ^% u  w- `
  k1 = (np+i-1)%np;
! T5 S. \1 ]6 L% s  while(k1!=i && vl[k1].y==w.y)
( x6 u. d6 T/ ]  k1 = (np+k1-1)%np; ' d) h# T7 p$ P" O; a. w  D2 q, k* m- M
  k2 = (i+1)%np; . Y# @3 ~* T+ {( O4 s
  while(k2!=i && vl[k2].y==w.y) + C1 ^$ i9 H/ J* x
  k2 = (k2+1)%np; 1 I6 Z' o! w! ]- S1 u* I
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) * q5 ~+ Z$ d. K* h- D
  C++;
4 U# n1 }# Y, N0 y! u& `& _( P  if(k2 <= i) ! ~1 O" r! l1 W
  break;
! {1 T. P1 S8 d  i = k2; 9 I2 i" m% B7 |" K4 \
  }
" U+ l0 O8 [0 e' @% p, z9 N  } ; V# g2 @3 D2 w2 t, r
  return c%2; 1 \7 b* m0 O2 x" ]' O; F9 Z; P
  }
6 [  G. D  G. x" ?6 E' o9 R6 F. t  `  I1 Y3 D+ F
  Q/ Q9 s' }8 n$ w" F. ~% O4 S# A3 N
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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