返回列表 发帖

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。6 S( @* G- @- X3 |4 Q3 j
) c2 I' \: R5 w2 b9 e  t) {
  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
5 k5 g' R* H# Z. Q) j, e' _0 g8 R
0 R4 x! D& N+ O+ m# V& n  首先定义点结构如下:5 Y, N& m2 i- ~, p! b4 u, S! d
# M% T( Q0 Z7 t! ]
以下是引用片段:
" u1 P6 O( t$ g# X: A  /* Vertex structure */
7 a7 m( `3 o/ x2 Z. M( L2 e  typedef struct
* N. n* L) H2 X1 {- L6 t  { , |* B% `7 }$ W# ^
  double x, y;
3 [) {( S9 ?* s% _7 I2 I  } vertex_t;
$ V  j4 B0 ~) D$ L+ n( [# T; s0 [2 u+ _" d  B

8 v& A5 G4 E* o' X3 j. t7 l- ~  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:5 M6 f+ l0 v* F, e
  e2 r9 ^% ^9 x/ |3 J
以下是引用片段:
. z" Y8 U. w; W" `  I  /* Vertex list structure – polygon */
9 v( o' H) m; i5 M7 [0 k* q, L  typedef struct & z- ^. X( S: \; W
  {
  p3 E2 _# R5 ]6 K; c  int num_vertices; /* Number of vertices in list */ 9 o& C4 [4 R% L
  vertex_t *vertex; /* Vertex array pointer */
, {4 ?' q, }$ q# [! @+ e  } vertexlist_t; $ k. W  c0 Y% L+ P

: d* k9 |1 @; i2 w/ m# z
1 Q8 r; s8 @, `2 g3 ^2 G  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
% T( O# I6 e( P, e7 G, G9 G3 c
0 T- S; F( D* G9 ^1 f4 Q2 \  `% b7 e以下是引用片段:
3 \1 S; Y/ N5 d) m5 h  V  /* bounding rectangle type */ 1 N: g8 E3 `! k
  typedef struct
4 f! Q. _. q" N  p  {   E$ I, O9 Y& U
  double min_x, min_y, max_x, max_y; 2 s$ z" P; l0 K
  } rect_t;
! Q9 a5 n3 z. p% g( m# o! u& Z  /* gets extent of vertices */   w1 N: @. i4 o% B& i. s
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
% j1 {1 u( ]; n+ J& L* v# \  rect_t* rc /* out extent*/ )
8 m: M3 a- u, @4 ?# u  {
8 O! Y: u9 t  q- q  int i; 8 l* v3 ^: W9 L' o/ D" U$ z
  if (np > 0){
  D+ ~& s4 {( a- W/ M, [  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 2 B  u$ M8 y1 T* h
  }else{ 2 [2 Y# W' q# V  }  |# s
  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ " }3 \2 o6 h( M3 }: Y( K; B4 T5 z
  }
4 O" Y* R% \$ G( c' t: F: r; Z  for(i=1; i    d$ w( k- S- X' ?& S
  {
* c& v( ?) V6 j  if(vl.x < rc->min_x) rc->min_x = vl.x; # D$ z# R  V# F" |2 {1 E
  if(vl.y < rc->min_y) rc->min_y = vl.y; - O& E2 ~( G0 x1 F3 G
  if(vl.x > rc->max_x) rc->max_x = vl.x; 3 t& ]3 D* A% b- z% v
  if(vl.y > rc->max_y) rc->max_y = vl.y;
  L! L% [- O9 z8 f. p2 g) d  } 2 x: v" g) D; Z% [8 e
  } ' q. }& f$ G: V& ^
9 `7 u) h9 \( u! l# A; f2 V( v

% s2 G, ^1 G' a  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。; ]4 Z, t6 B' J/ z

) Z* s' a/ F! Q" u. \9 ]" e. G  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:! _! }! ?* I3 t# q8 h% D
6 j$ y1 @  Y" B# C
  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;5 ~3 d# t$ A+ V% o# Z

. }/ @0 D6 {6 [9 D" Q( |6 c) u  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;, V8 o. V$ L& e% k) \: f& K
0 `$ O- m) d5 F$ T8 X' `
以下是引用片段:; {$ n8 g" A; _1 J5 M% r
  /* p, q is on the same of line l */
  B: j4 H2 ~  y  H/ H  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ ) R- x6 B6 o4 r; E; t) h  k
  const vertex_t* p,
1 H, f3 k6 k/ f% _& e- j$ _  const vertex_t* q)
) g& P( {4 y- S! r; ^" C7 S  { " N& H( F7 c: v3 I6 D3 D
  double dx = l_end->x - l_start->x;
6 ^3 a+ O  l' m6 H  double dy = l_end->y - l_start->y; # m. c1 x6 y* m
  double dx1= p->x - l_start->x; " x- d0 d; x1 q! J# j
  double dy1= p->y - l_start->y;
* \1 ?6 f& S# Z' c4 s  double dx2= q->x - l_end->x; : N/ B$ [9 u# }* j# K
  double dy2= q->y - l_end->y; # Q8 ^  p- U2 p1 g" `
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); : q2 a" y7 n' R- ^  G
  }
) o1 a3 w: y/ T" W  /* 2 line segments (s1, s2) are intersect? */
" @: S. v3 L) N" |8 e% r  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, ! o6 M% G- l3 U# g: R" H
  const vertex_t* s2_start, const vertex_t* s2_end)
* f3 ?) l9 ~; |# w  {
5 b' ?' r& U4 J, x; K1 W2 g" k4 U( D7 F  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && ' H' F# ^+ Q7 X2 d6 T# D$ o
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
. B/ `+ {- r, B8 G: H( k2 g3 e  }
% e7 m- V- J% v- t1 G. U8 t) q  K+ h  e+ E% |

' O2 X6 P  |+ O- A  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:) M2 M6 _2 `) w! Y

0 m$ c, z5 g4 W  Y, @* n* ?以下是引用片段:
2 S$ X" C" C" E) f  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
% z, X' g/ b5 v) d+ n6 E3 U& L  const vertex_t* v)
- p( G* k# H; _" O( _' u4 b  {
1 K  ?' s$ I5 m9 i' _  int i, j, k1, k2, c; 0 L  U' g( z: r' H5 u, {1 S
  rect_t rc;
/ n2 A) W/ K- M- @) P. X  vertex_t w;
  I& u0 f* m' w, y6 x4 s9 u  if (np < 3)
8 \% t6 ?) C" T  return 0; / C' s! f' v2 F2 n
  vertices_get_extent(vl, np, &rc);
8 _5 c$ w' J& m2 D( o. L  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
8 y) h3 |. j5 _, r  return 0; 3 z6 i) K1 ~1 u: B+ u
  /* Set a horizontal beam l(*v, w) from v to the ultra right */
, J1 {3 D9 G$ M  w.x = rc.max_x + DBL_EPSILON; 7 t1 A+ B5 D8 @; X$ E) ?4 p
  w.y = v->y; % @4 X- k% h0 c
  c = 0; /* Intersection points counter */ ( }2 {: k. w2 B! j; z7 A
  for(i=0; i  
- c4 j3 u0 Z& ?- ~$ g  {
' e5 M1 e4 a% c' Q8 y  j = (i+1) % np;
/ }3 f7 |/ h7 z  if(is_intersect(vl+i, vl+j, v, &w)) ' E* u) S3 U7 o$ d5 ]# O
  { ( z% a- W' z/ k, _5 t; T7 j
  C++; : c, f8 ?- u$ H! J' f/ B( Y' Z
  }
6 N; q) a- E3 z5 i+ r$ A( W5 L/ p  else if(vl.y==w.y)
) z( `4 O- P' E  {
, V1 a* G. T7 y: f$ A. }  k1 = (np+i-1)%np;
) c1 K7 g% U5 e% c  while(k1!=i && vl[k1].y==w.y)
# V) k5 [1 P- |0 c, L* s/ \  k1 = (np+k1-1)%np; " r! M9 @" r$ Q# G" J$ N+ d
  k2 = (i+1)%np; 1 v) V% G0 X0 E6 o  @$ }* N
  while(k2!=i && vl[k2].y==w.y) % u: C5 b( t% [2 l& s
  k2 = (k2+1)%np; % V7 [3 U2 n, R$ l6 M
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
# S# Y' A1 ~* G  b  C++;
3 C8 }3 T; Y" P3 k0 M4 x  if(k2 <= i)
' J6 u8 I2 \( p, g  break;
5 B7 ^4 j+ c9 @9 I  i = k2;
+ z7 }" A. A3 d* Z2 ^  } ; x0 B" b2 V$ V8 k# M. U
  }
. l1 p- ?' [) a  return c%2; 0 B1 P+ n" u1 B7 Y( H% g  ^
  }
# t& S" C  t, }; w4 w4 D3 x
; }& P2 q( ~$ t& T7 ]; g4 {  s; Z$ g4 o3 Q
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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