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

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

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

% f' o$ X4 y: O6 F5 S  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
- K( m/ i$ L0 w: q1 E
. Q2 P8 C2 \+ c1 i  首先定义点结构如下:+ |+ }0 F' J9 q
! J$ Y! \" Z2 k2 p7 k
以下是引用片段:6 y. c1 f1 e6 s3 }+ u" a
  /* Vertex structure */
# j2 W( `0 u( I4 f% a  T! g! y  typedef struct
( e  c  o2 e; S. F7 e7 d+ Q  {
5 A* x6 `9 q) Z9 E% c  double x, y; 3 I) N' P2 U# h7 [$ D
  } vertex_t; - w  g% P# |6 V$ e+ O8 \) K7 R7 d
% n/ e% X4 r2 R. \" m1 d; b
9 x6 q8 f) ~: P& Y8 S. y/ o% u) B: T
  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:7 h4 G- Z! A1 K+ Y1 N/ I+ Y, ]
' F7 X" e( P5 s- ~  g! |! U$ h
以下是引用片段:5 j7 u. M1 b; e. \$ K
  /* Vertex list structure – polygon */
1 m+ s1 }/ _0 F) w2 s3 q6 U  typedef struct : s7 \# s+ x* a4 B/ K+ r* [
  { % N8 O! K# Q$ _0 L
  int num_vertices; /* Number of vertices in list */   ^6 U+ }( ^* J. \
  vertex_t *vertex; /* Vertex array pointer */
" N1 C6 \7 A" e  } vertexlist_t; ) t: C2 C$ o  s1 Q( p2 q) {/ O- L
; f& ^/ t5 w* a- e' \" y

1 x! G" R: n9 i# S: J& z2 R3 L  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
5 B2 M1 k" S6 }+ @' W- d
8 f3 r5 j% @6 [2 |% e; _以下是引用片段:
0 S; v1 N, N0 A  ?0 A* O  /* bounding rectangle type */ ) i- @8 o1 j3 ^9 N/ A. Z
  typedef struct . k, ^) j% b: l- x
  { 2 h( G, B" ^! }+ l8 m0 u9 }
  double min_x, min_y, max_x, max_y; . d/ [. J7 N2 |! R! U2 \* F0 A
  } rect_t;
- Z" @+ ^# M1 N. x3 c7 G! N6 L  /* gets extent of vertices */
$ P6 t/ ~# J: N# {3 e  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */   n" V. f. L: W  ]$ \! r; |; T+ c: Y- b3 U
  rect_t* rc /* out extent*/ ) " n* n! P- m! X" [% ?
  { 8 e4 {0 U- `% i9 U
  int i; 4 `5 H- S% ~8 o* v
  if (np > 0){
, j, x* }, D6 r7 F1 w- w# N4 R  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
: X: o5 @, d0 ~: m% U( \, x6 w% i+ r  }else{
! I, I4 r# b/ X, \! ]" M  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
( n/ {9 f' ^/ s+ i  }
2 Y: q/ V5 f8 v$ H5 w8 C% j  for(i=1; i  
$ {* B9 I. c- O7 F; f5 z  { . j& @7 S/ q& e* ]
  if(vl.x < rc->min_x) rc->min_x = vl.x;
' ~( C( O8 `" W, s$ o- [5 [7 _. s9 Z  if(vl.y < rc->min_y) rc->min_y = vl.y; + I/ N+ u1 l& |" E
  if(vl.x > rc->max_x) rc->max_x = vl.x;
7 e; ^* n) r+ X% y$ @  if(vl.y > rc->max_y) rc->max_y = vl.y; $ x: j9 T8 Z- j1 B6 y; a4 F, T+ b
  }
; E8 B( U' O* ^  } 8 U) n/ k( G3 i5 J; w
& E, U# t  v* m2 g3 P# I
) n3 B% A3 O- @7 _8 r$ f7 s
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。0 c, R# T" R0 R' ]. p
, H$ I1 b6 W- j, W
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
* i" s6 Q. _$ E3 B/ u9 `$ W8 z* @& U  j8 C" y9 S& Q7 Q
  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
7 m2 S" P# ~: N7 ?' h( a% S3 `8 T; @2 @" w! V& B$ C7 a" d
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;+ W- g+ f7 O+ w* `& S

6 g  _3 g4 ]- i# N7 G3 n以下是引用片段:0 _4 Y9 _( M$ \! A# S1 M
  /* p, q is on the same of line l */ 8 ^. e$ S  L0 ?! {' R0 z8 c
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
7 P; \1 r1 {; _2 n1 h  const vertex_t* p,
/ K! S9 R) I. n6 t$ h% e  const vertex_t* q)
& r; y/ B% r. V  { 7 }+ J3 U3 d/ b) C8 Q. ^
  double dx = l_end->x - l_start->x;
# S+ \5 L* C9 n+ w& Y: C6 X( J  double dy = l_end->y - l_start->y; % B: ~6 Y! d' t3 Y1 v6 |
  double dx1= p->x - l_start->x; 3 u* i* i) N. |! @
  double dy1= p->y - l_start->y;
9 c9 O0 `2 X; {# V/ J# o  double dx2= q->x - l_end->x; , a! Y3 |/ C9 G! L& A: p
  double dy2= q->y - l_end->y;
+ `* {+ l& d$ v/ Z0 s  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
- J4 X( e/ ~7 r( r' @; O* T* d# ^  }
" G3 m3 ^! c# ]7 f* q. q  /* 2 line segments (s1, s2) are intersect? */ & [, Q" Q7 x& y  S4 j$ L( V9 C- u" a
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, 5 R! R+ T0 V; z) d  u
  const vertex_t* s2_start, const vertex_t* s2_end)
# l" W- K7 h5 }+ S5 }0 a  { / |% |: s- o3 i% ~! G
  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
/ V( W" V+ H/ A6 c  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; 5 p+ @# O# S7 F3 c7 K7 |
  } ' `: K1 ?& O" J) b4 j

. f0 s7 X; B: R- W7 y! A6 V9 t# J7 p. [* {' o
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
# S6 P3 [  O# P# l3 ^6 h) K/ {
5 S9 I3 z# h9 g6 N以下是引用片段:
1 o; O8 F/ @) Q" H8 j  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */   u4 z. [2 G6 }
  const vertex_t* v) 9 E& @7 Q9 B8 c) n8 J  e
  { " @+ J6 P0 L- G/ i
  int i, j, k1, k2, c;
/ G; s0 U( z. F: Q* ~# z6 L  rect_t rc; 7 _1 v8 ~) x( H( X" Y0 ^# g! h
  vertex_t w; ' ]6 e/ p( z- D5 h& M
  if (np < 3) " _- L( u  b% Q3 i; f0 i, h
  return 0;
, y# z" Y' n) s5 ?  vertices_get_extent(vl, np, &rc); * L$ i# Z- y) Q, _
  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
' g  e' G1 `* `/ s, Q* R; X  return 0;
. ^4 q2 K9 s2 E$ O, x) k  /* Set a horizontal beam l(*v, w) from v to the ultra right */
* X. b0 Q# }. ^$ M5 d  w.x = rc.max_x + DBL_EPSILON; ! W: S  m+ c/ Z& ^
  w.y = v->y;
( [3 ]) k4 @' e$ _+ z  J2 r  c = 0; /* Intersection points counter */
  w2 U" a0 V' L  ]  for(i=0; i  
2 x* [4 m) B$ |* L; e3 P  {
9 R  A# N  t/ C/ g8 z8 @& P1 i" }  j = (i+1) % np; 3 v  r* C: T3 ^- p9 I% c
  if(is_intersect(vl+i, vl+j, v, &w))
) Z5 c, A7 K1 J- _& v9 O0 W  { 0 M( c! a/ G( c0 Z6 H
  C++; ; i$ v1 t8 C: m8 f6 X5 D
  } ! L) g: r+ i+ m/ d8 B
  else if(vl.y==w.y) ; }: r' d, N5 B6 L
  { 4 `: \% d' F: b1 |2 l- D7 B& I
  k1 = (np+i-1)%np;
( H. E6 w+ U6 E/ n, R# W6 I1 `+ a  while(k1!=i && vl[k1].y==w.y)
# D+ s- O# P6 t- J$ K9 ]" e  k1 = (np+k1-1)%np;
3 K6 a4 X& s- [- y; `  k2 = (i+1)%np;
3 t) _% x) R" ?  while(k2!=i && vl[k2].y==w.y) ' ^9 E4 b/ t! f% X# H5 \- R
  k2 = (k2+1)%np;
8 @9 G! Z, t; t* b  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
5 Q8 Y5 [6 L) G  C++;
1 i  B, s' ^% W/ `8 L) `9 `  if(k2 <= i) # C, p# u( v1 {/ h, h
  break; & g& @, n% o6 e& f3 S9 p0 N
  i = k2;
1 u1 }$ ]1 d6 f- X2 j! \  }
. r( t9 d- m- v  r  z3 \- ^  }
$ _* ?9 }5 U, A& t$ t% r  return c%2;
3 _$ c/ h1 G: q( |+ t  } + Y6 q8 A$ Q* D
' s' v: D. @7 A0 ?. D
5 Z9 k# S; m6 S( [# k
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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