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

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
- S( m2 E2 ]0 M2 V0 k; k
# b8 u4 x8 R$ M' z  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。1 Y' `8 s; g9 {/ |/ W

9 }$ ^' |7 W# b( x) D  首先定义点结构如下:
* }  Y0 U2 R! Y( i3 x; q% M4 G& j8 E& _, Y
以下是引用片段:  V! t, @" ^; j* E9 v+ F
  /* Vertex structure */ $ E& _! N7 [8 f% w! a7 l4 t
  typedef struct
' K% Z) \; J3 K4 }  { # Q2 m; u+ O# x* ?0 A
  double x, y;
$ v5 I0 t; X0 p% z  } vertex_t; 0 R3 q9 D2 W* ]3 b% w0 Z9 t
9 ^7 l$ t# p6 L

1 l' n$ {/ n( d) C9 Q  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:. k1 p/ X7 |4 m; Y3 e) i% r% }
# {4 Q3 G& F7 |  g+ S. s
以下是引用片段:
1 Z$ v6 ~" I' k  /* Vertex list structure – polygon */ 2 C2 a6 r$ ?/ u) M8 ]" @6 d
  typedef struct
# |" J' S. @9 \* \  {
  v; _* `! v4 G6 o  int num_vertices; /* Number of vertices in list */ 4 p5 F0 K+ V; t- U% F7 ?( x& |
  vertex_t *vertex; /* Vertex array pointer */ . Z: q5 [. ^3 [0 C, x9 R: R$ `
  } vertexlist_t;
5 S; I" V, l) ~7 o" \! p
. N# j6 p9 [, a" A( ~; M4 O, N3 p5 f. E8 K2 j) b
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
! a0 P* U; m. Y: a2 M4 L! {) |% l+ V. b
以下是引用片段:
6 @; v. z5 I# V1 S5 I; x) O' J$ ?' c  /* bounding rectangle type */ . F# t. I1 K; P2 }$ X$ `" ?
  typedef struct & M* \' y9 l0 H: Y$ ?+ v0 m/ _, X
  { & N5 A8 g' i) B) h2 \! d; ~
  double min_x, min_y, max_x, max_y;
* }1 Q9 l/ e) ~+ i' s0 A* u( S  } rect_t; ) O6 a& a$ X, N1 R* o: G! Q
  /* gets extent of vertices */
5 Y- h9 |  \  i( L  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
  G- r# J9 X. |! n% B) v* I! ]  rect_t* rc /* out extent*/ ) ! G$ d& E% b* n
  { 9 G" q9 Z7 n# [4 j% c3 i) s
  int i;
# z5 y# G! c& P$ r  if (np > 0){ 2 H: F1 y, }' F8 }4 f: d+ X7 o
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 0 A5 L, ^9 N% o: f- a5 T
  }else{
9 Y+ s4 `% x: F  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
  E/ D+ z9 N& B5 D  } ' R% ?/ m' o/ t& c
  for(i=1; i  , x: m3 m% D" z$ ^% `
  { + J8 }1 k4 {* R% S
  if(vl.x < rc->min_x) rc->min_x = vl.x; ; d' T; ?7 X5 W, f- U9 @
  if(vl.y < rc->min_y) rc->min_y = vl.y;
3 h  B# Z& t2 ~7 {: ~7 d8 I  if(vl.x > rc->max_x) rc->max_x = vl.x; % Z, L& F% E! [( ^( {( _( n
  if(vl.y > rc->max_y) rc->max_y = vl.y; . B; C- ~% R7 I9 v3 q& F6 n
  } , @: O/ e4 h8 }  }* R( t9 F3 p( I
  } ; Q3 \: i/ c5 u) a

: Q" L' [$ Z' |- D% b! Y5 X: V) f0 g+ l4 @
/ ~2 h2 w2 S6 _4 r5 M/ W  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
5 x0 @7 m5 D$ {
! z2 y4 o- I3 I7 Z, b3 K$ g  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
" @" h5 i& V" t( e
( w1 W* g7 a* J. P5 Z, S  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
( I# o4 i, _* `* |) R
  d3 N$ B4 t9 j+ Z  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;1 s; S1 c, I1 A
2 r; J- }7 H0 v. d8 f6 E% l
以下是引用片段:
* J9 f( ]# f. W) w  /* p, q is on the same of line l */
+ e+ G& \) k. I  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 6 \" Y3 x* H* H
  const vertex_t* p, / x4 d  m1 O' J3 W) l, i9 a
  const vertex_t* q)
: \) h9 @" x) @, t0 n: u+ Y  { & T& B4 n+ n1 C% S& [5 k, J& F
  double dx = l_end->x - l_start->x;
; E9 \" C  z1 O2 w  double dy = l_end->y - l_start->y;
7 d9 |" {* L) a) I% R5 m4 k2 i  double dx1= p->x - l_start->x; & G, F& z  O0 H9 [/ Z7 a  U
  double dy1= p->y - l_start->y;
! c% [6 K- {- E4 L& v& t  double dx2= q->x - l_end->x; . ?/ @# \  [3 L1 Z
  double dy2= q->y - l_end->y;
9 M1 [! N2 u+ K- V( N& J. v0 {; |  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); ) x8 i- [6 E. w# A/ i* e
  } " Z5 {" r$ T4 D- I) N
  /* 2 line segments (s1, s2) are intersect? */ # a5 b, a2 l- X; U( F0 H
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, 8 k, D7 @' M, B+ `) |" d4 ~
  const vertex_t* s2_start, const vertex_t* s2_end)
- ^! D7 s  t4 m1 D( w  {
+ w0 P: W. o. q& d2 d$ ^$ \+ T  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
9 z- Q" m5 w, [6 @  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; 1 z' q! Z2 V) O2 d' Z
  } 9 j+ I) p( x# z5 W1 E. P* P2 q
5 }  `4 h4 A6 X+ O( C: _5 `
' C6 |, {; t* X# U
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:( A7 v6 }$ Q4 M3 K! `# t

0 ?& U$ k( p4 P/ R4 o以下是引用片段:7 f) r% [  \1 ?. z( u! q- P4 N0 P
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
# f% x2 x: M6 X+ c& U0 E% w  const vertex_t* v) - h5 p3 x5 @& U+ a* `  |  l
  {
: A, m% f3 y# [" @8 f( R# l* T  int i, j, k1, k2, c; 5 s0 I- O, A: G) V5 d
  rect_t rc;
" W$ d( T, C- l4 t  vertex_t w;
( V! V& K& j3 W$ u  y2 A9 X' h4 U  if (np < 3) & z/ c1 ?/ e' j& x+ R) N6 h& O
  return 0;
8 Q4 Y1 m9 K1 W  vertices_get_extent(vl, np, &rc);
2 ?5 N* }4 g1 {" \: _  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
8 O  u& m6 @! g/ s/ Q  return 0;
: `5 W8 U% g* w1 s1 H9 }- s  /* Set a horizontal beam l(*v, w) from v to the ultra right */
) `! `7 ?7 d  B& t$ [/ H+ u7 \  w.x = rc.max_x + DBL_EPSILON;
3 Y$ {. L) x0 y  w.y = v->y; ; B) ~: R. }- E6 G. K0 g
  c = 0; /* Intersection points counter */ 3 ]+ o% X  D1 _, W+ C% {1 |* g
  for(i=0; i  
1 J. w" K* y3 \  o9 S! f; {3 A3 Z  { 5 l+ o: T9 V- V
  j = (i+1) % np; 3 H/ n, W& M3 R  X5 s
  if(is_intersect(vl+i, vl+j, v, &w))
# f0 ~0 l/ _3 E' t' a" J5 o4 j# @9 V  {
, E1 A8 J  [/ }  C++;
% M( n0 A0 X- Z4 `! D  } ; I( l$ v: W& H
  else if(vl.y==w.y)
# p& k$ o# ^# {! |+ W; _" d  {
  H8 I0 ~! ?6 g. E( U  k1 = (np+i-1)%np;
- @" e; f- f" {  while(k1!=i && vl[k1].y==w.y) 7 d* ]4 m' ?3 W' p- r! }+ K% ^- N* d
  k1 = (np+k1-1)%np;
) b* K( C# `8 |2 ~5 ?  k2 = (i+1)%np; 6 I  L& V8 x' h( g  Z$ D% q
  while(k2!=i && vl[k2].y==w.y) 3 f6 I1 m( a2 y0 O/ v7 g# x2 A8 y3 E
  k2 = (k2+1)%np;
" z2 p4 \, |6 u& B6 A, p  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) " b( Y5 s5 D5 N( y/ m
  C++; : U& |3 L# K% f) ?- Q6 |5 s  z
  if(k2 <= i)   F' h- T' e" f$ C0 _; T/ v
  break;
3 p# f" g8 ?8 M' C: @  i = k2;   |/ {/ Z! I9 a$ q$ {4 S
  } ! o  u2 ~% @! q6 x/ M$ B- T
  } + i# P! D5 {+ {( l
  return c%2; / T  ]7 F) v" }: @
  }
. d( n% @- v, J
9 f$ K7 x& b) Z: s9 A* Q7 l! L4 N# F2 F
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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