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

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。& Z' Y- {# |1 k1 A+ O

% H6 ]+ g$ x5 j1 U5 I  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。& c3 `( d& }" E' n) w
/ O# V0 `" `. \* V' r5 G7 K
  首先定义点结构如下:
- q5 d# D. @% }9 j* B
1 e( z5 I8 ?1 |2 U: `以下是引用片段:
& |% K8 i# k* K, X& p  /* Vertex structure */   i3 E9 k6 _; O4 {6 d
  typedef struct   V2 N4 S9 i8 f  j* v- S
  {
/ F& V! E+ X7 ~1 y  double x, y;
' L9 \  R- p" w6 m; A2 H  } vertex_t;
  v6 H( ?* i1 q  R# q+ M3 T$ Y9 w/ o/ {

/ U! t5 r5 L6 r; V7 m& X1 s  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
$ a5 ]3 q" n5 i, u; w! K2 d/ j/ Q
以下是引用片段:
( S: D8 h: u! A6 a; p  /* Vertex list structure – polygon */ + {3 d) b; r' H3 w, R
  typedef struct % U' ~* d; B; s! `* F" @# A( s. N
  { 7 M; U- d) I2 d& I4 J; c" f, i6 j" {
  int num_vertices; /* Number of vertices in list */
& c7 j1 w6 i) P9 o4 b  ]6 G( |  vertex_t *vertex; /* Vertex array pointer */
* h) e8 S1 S, F% D2 u  P# Z. |8 {  } vertexlist_t; $ v5 K9 {6 u3 B$ ^5 o+ ^

% k4 I  o. M9 Q1 }) O
: f7 g+ C* d( Y' A4 W. S+ w  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:: c9 @/ N8 h' Q  J) Z2 Z$ v
4 I! U% V, {( s0 C5 ?+ ^
以下是引用片段:) A- e9 F- S" B0 B+ W% o+ K% |. r# R
  /* bounding rectangle type */
1 B( q& ^/ {' D1 j& S' M+ A  typedef struct 3 l$ c' C9 a5 K% y! n  c
  {
' D# p/ M6 Z. U% G" \5 V9 e% z/ I  double min_x, min_y, max_x, max_y;
$ m. k& S/ b/ M& x  F  } rect_t; * y( D1 U  [$ F/ f7 R
  /* gets extent of vertices */ ) O! {3 d* p+ [: p
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 0 x, i3 R; o5 }1 W; Y
  rect_t* rc /* out extent*/ )
6 o* b, c& k# `5 v, K  { # s- b! S, O9 o# K
  int i; 1 l; G3 n' i! T4 y& @) O1 P
  if (np > 0){ + H$ r6 O! t: n3 D4 S6 L+ I& x
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
0 S! ?- ~& b" w) F* s( c6 G2 h  }else{
: f: }: i: q6 _+ [( n' i7 u  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
! d/ O* Z, W6 r7 w% g4 o  } / h* w$ V- n$ S! j
  for(i=1; i  ' B6 P# w4 W: K) Z( s2 K% L
  {
" b  j+ u9 r# V( l& H  if(vl.x < rc->min_x) rc->min_x = vl.x; 4 C1 S! u0 U; X: n1 f. z  x2 C% m
  if(vl.y < rc->min_y) rc->min_y = vl.y;
) P% S$ Q) \' T; o, B  if(vl.x > rc->max_x) rc->max_x = vl.x; 5 N2 A2 u7 y% b) D. u( s, E0 y
  if(vl.y > rc->max_y) rc->max_y = vl.y; % k" x& F5 U  ~% Y" _5 ^: v
  }
4 l6 P) ?/ R. R  W  } - C7 Q+ H1 O2 ^+ H& m5 s# u3 M1 \
' e- r# ^7 X7 y+ e7 F. Y' c

/ Z6 Y6 n- g. a1 ~  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。9 Y! c) k! l6 t* G$ p

2 M% E) H. o: X; T8 I6 k% H  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:4 t; L0 q7 X" g: d6 @8 \

7 y! W# n% F% q( l' H9 x  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;5 v9 M3 v) l( g1 K0 w& w
$ ~: J1 s5 N, h1 {: J& X# \8 u
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;  _6 f+ f6 Q+ Y0 O3 r2 c
4 D0 P$ }! P  i  ?9 S8 j
以下是引用片段:
, K( k( B2 z# i4 J* B  b  /* p, q is on the same of line l */ / R8 u8 ]. N: x+ i' H% [
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */   X) R$ @# r0 q, c
  const vertex_t* p, 5 Y8 m: ?( S  C4 a
  const vertex_t* q)
& K! r1 J' t5 j! }# u; |  { + L5 X5 c; c6 u0 \5 R
  double dx = l_end->x - l_start->x; . y: g" g8 ?: `1 U; Y- I
  double dy = l_end->y - l_start->y; . W5 @3 u- M* D, l" N) m% p( Y
  double dx1= p->x - l_start->x;
( `/ _) h: P3 L6 b# F% ?+ E  double dy1= p->y - l_start->y; 9 t. {5 e2 f# a+ M
  double dx2= q->x - l_end->x; ) T+ j* y; H- t$ w0 F1 N3 A
  double dy2= q->y - l_end->y; & j# c$ J6 M( a& A+ c2 }
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); ' F  G! s$ a6 p0 @& L
  }
" ?0 A( w0 X9 S5 W% R' x. t  /* 2 line segments (s1, s2) are intersect? */
/ \& o5 ^' t# [; H+ y0 I  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, % |/ k" N$ @. J; W+ |, s8 J: l
  const vertex_t* s2_start, const vertex_t* s2_end) . E( E6 q2 ~' _
  {
8 Y: l: m  O. k  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
* g1 M% ^# u7 ?6 ~$ i  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
1 D0 A2 P  K6 t  }   f0 N8 e( f! H7 @

  R3 F# y# k! i+ U
' [1 c1 s! |3 o7 w, G  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
  g- S9 f$ Y/ ]
: V4 S# y6 R* A: b以下是引用片段:
3 |! M. A0 j" Z! A  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 9 k& b5 I8 Y8 D0 }/ J* M4 f
  const vertex_t* v)
$ f8 a1 l; K% z5 \6 _" b4 f0 w6 M  {
( A! k) g# E, o% T/ `, F  int i, j, k1, k2, c;
+ K6 b) b$ q* D# p. A  rect_t rc; - E, q, T- v+ G( }% B: E
  vertex_t w; # U9 _3 a" ]9 }1 M! s
  if (np < 3)
+ X" G: V+ a$ z' G- E, I9 C  return 0;
# O( d, {4 L2 p  vertices_get_extent(vl, np, &rc); ' ~5 x' p+ b1 }* g/ L8 _
  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
3 P& `0 `  `" f/ h  return 0; ! M! W1 y+ \% A) h
  /* Set a horizontal beam l(*v, w) from v to the ultra right */ + {4 {% l( F& a$ m; B: Z* x
  w.x = rc.max_x + DBL_EPSILON;
# J- l2 [. A) ]$ A9 I  T7 @1 T  w.y = v->y; 7 l! O2 n6 U6 V2 F3 q" Q% J
  c = 0; /* Intersection points counter */
1 A3 }, Y' A- F  K2 j  for(i=0; i  $ t5 f( |' W  }
  {
" ~# H" s, t+ p& b( l  j = (i+1) % np; + T) [1 p0 m5 k4 j
  if(is_intersect(vl+i, vl+j, v, &w))
, U8 A+ t9 q* X  {
6 D; H2 b& {/ _  C++; & }! S1 X' P% N/ D% ]$ y
  }
. `3 x& R! q- E; ~' q  else if(vl.y==w.y)
( L; b- F2 d7 s  {
% n- g' s8 C' I7 T1 W  k1 = (np+i-1)%np;
, v+ {( |) ^" _, c  while(k1!=i && vl[k1].y==w.y) , d5 K. d) m* [- X8 s
  k1 = (np+k1-1)%np; 2 ?5 r# O& D7 v1 q' [, C
  k2 = (i+1)%np; + v. Q. H% r$ B0 w( p
  while(k2!=i && vl[k2].y==w.y)
% U0 M2 {- x/ d9 @; |* z; ~  k2 = (k2+1)%np; & u1 V( h* L$ X5 I, ^2 d
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) $ W: C3 x- m7 e0 D
  C++;
. Z7 ^9 _& G" p8 D2 F  if(k2 <= i)
8 Z6 }# W( Q1 h7 s5 f7 L: T  break;
* }' U! z- q5 R' z2 n! g3 M  i = k2;
, N- ^" A. E2 B5 {3 L2 {  }
$ y" i3 Z. T6 F4 `3 S7 d0 N% X  } % J$ d" _! H7 c6 g! i7 l; F5 c
  return c%2; / N8 ]- t0 ]$ z0 G
  } 6 `# E% W5 {- O( A6 E* w

6 s  p: F8 r) B9 j" y+ p7 x1 k. ?3 o) ^+ K& t
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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