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

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

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。: U4 `' B+ z* B" v) W+ c
! T) f" \- X$ A4 W' l
  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。4 F4 ^1 _8 q5 F6 E) P

' |# P* C) `0 Y  首先定义点结构如下:
& L4 X% ~% {3 A6 o, e% B9 m& m+ k: b
以下是引用片段:
1 Z2 _/ H+ V" A- p! @2 G% P# Q  /* Vertex structure */
/ s, N) l# K; S" W3 Y  typedef struct
& v6 M1 O' z9 o" o' n# T- l# L  { # W) D! n: I/ r% m
  double x, y;
; c& F/ k: J0 S3 p1 K7 v  } vertex_t;
* d, u+ U" p5 [; i0 J! b6 ^
' h' L1 V$ |4 o# i% N
( ]. `% N0 ]( V5 y( Z  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:, D9 O9 h5 V2 U, X" o" w
: j/ {4 R4 p/ Q- j) C
以下是引用片段:
4 ]7 ]: a$ v. C1 ], X  /* Vertex list structure – polygon */
3 L% h# v, u9 l0 z! J! d  typedef struct 8 M0 L2 v4 C/ r
  { 0 {8 H2 G( I; R- E
  int num_vertices; /* Number of vertices in list */
( D2 ~9 |4 a. Y( C  c, E# x- T  vertex_t *vertex; /* Vertex array pointer */ % c8 I0 G" B8 s* F. r$ D% _
  } vertexlist_t; $ h2 u+ k& O6 u: Y3 e8 O  `5 `

& U* N; Z! g# j0 p( `' M
& r6 z; A0 z) L& q' o9 r  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
, Q- o! s" ]+ k3 r8 h7 p% Y8 P- j8 N+ o4 w3 Q) d
以下是引用片段:
& P1 R* y  Z' R* S- ?5 p7 t  /* bounding rectangle type */ 8 F( H) h# h. X# V2 k1 G0 ~
  typedef struct 8 v  V- `, d* E$ q* J% l: y
  { 4 D3 j* _7 t: G: F1 b- |
  double min_x, min_y, max_x, max_y; 2 H9 m; f; c! h+ O
  } rect_t;
4 g: o* b. h) c# a  /* gets extent of vertices */ $ B7 N+ J) u# f9 A9 U) B, e9 N
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 6 {% D8 ?0 U/ {6 z7 ?" v
  rect_t* rc /* out extent*/ )   b9 Q4 L& P  I6 w+ t
  {
5 U2 B$ z7 S8 f7 k. ^, u4 s  int i;
4 W9 K: H, F2 S  if (np > 0){ 6 H! N- F. u7 j# o; G# R
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; , R* [+ B2 L- |% O' C6 T( D
  }else{ : _0 c( S3 j4 {
  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ 0 J- e, h6 U- R) v/ [
  } ; i% C3 P: K( c
  for(i=1; i  
6 n  {2 e6 e7 S7 x5 p. P  { + G0 B2 u( S# C) @9 K  n9 z2 M
  if(vl.x < rc->min_x) rc->min_x = vl.x; 3 P, Y9 i* g" S! y4 E2 F
  if(vl.y < rc->min_y) rc->min_y = vl.y;
5 y1 }5 q- Z2 U5 B: }6 n  if(vl.x > rc->max_x) rc->max_x = vl.x;
  u$ Q' A& A% K  if(vl.y > rc->max_y) rc->max_y = vl.y; 2 M8 L$ M) {# e
  }
) A8 R$ {/ _1 t" E3 r7 s  } " m0 w5 b. Z3 l
, X# O/ ^$ X5 b5 @
* S9 g/ [6 g* I/ U) A( x* Y) ]
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。/ j0 j% `9 ]- Z. x$ U

6 F# ?6 `2 x) r" O( \: S, C) B  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
7 i6 Q: ^9 H2 U" F# \! u' X8 c
: M1 ^/ J, e5 B& e. W. Y% ~7 e, D  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
8 i2 Z) Z2 W3 \+ o
! d5 ]+ h, a" P# j  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;+ o% j' K( C% M. d+ H

- }/ A3 D( `' k7 V以下是引用片段:1 E, m4 m) b5 x9 f- ^" h3 @
  /* p, q is on the same of line l */
( U1 Y7 `, N2 k9 m7 k$ U' E  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 9 o$ z" ]# l2 d0 j( P) y
  const vertex_t* p,
- w- G% D, R2 @* w* o' [  const vertex_t* q)
! K; b  L. k. b  { 7 F2 b# B% `  s4 F+ z3 p% @
  double dx = l_end->x - l_start->x;
1 \' s% ?2 B6 E$ {' T" c$ u  double dy = l_end->y - l_start->y; 7 C; T! k& D& E) I/ I: M
  double dx1= p->x - l_start->x;
9 ?4 a) m- J. ]* b$ T  double dy1= p->y - l_start->y; - f, l& M4 \7 x) j: F5 \7 d
  double dx2= q->x - l_end->x; * I2 Y# y+ f' ~) F
  double dy2= q->y - l_end->y; / i$ [# P3 _* d7 B! F3 E
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
9 a* q' i' w! V7 H$ e  } ) Y2 X4 }4 O  e! P# p) ~+ i
  /* 2 line segments (s1, s2) are intersect? */ 1 g) o3 n1 s, w5 a% k
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, 6 P8 z% H* {1 B! Y
  const vertex_t* s2_start, const vertex_t* s2_end)
7 T! ^# `. w. V& q0 v: B6 g- r3 z  {
; _4 I; J% N! A; F2 {7 ^4 Q  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && # S8 b: _& m( L& f# h5 S
  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
# O* \! Y$ t  Z  O  }
, C3 m6 C+ K' r/ S3 e7 Q
6 Y4 ^2 p3 Z- D5 I% j( ?% n+ V1 N! p
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
- t; [! u. L5 ^" d$ S4 j4 T! m& Z$ M# r- k3 s  i
以下是引用片段:
: p/ X, Z/ G6 j! M9 Z. k; i  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ : J% M9 ?' L0 J  w( Z
  const vertex_t* v) 9 Q: A! g% g4 r* r; S# I
  {
. B; x% x' Z) u) h  int i, j, k1, k2, c;
2 R* N! {! Y4 D) c  rect_t rc;
! v" R" s% \: }  vertex_t w;
+ n4 T1 ~6 Z2 R/ C9 s# |  if (np < 3)
6 f- Q# K5 g0 g9 `  S; C- u  return 0;
7 o/ X$ C: s# p0 e3 [  a6 @  vertices_get_extent(vl, np, &rc); # K/ n$ V! }) S. B3 {# n7 D- ~
  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
$ E4 ^2 `: `# Q9 Y( f+ @: n/ K  return 0; ; Y8 e( j+ @7 X2 Q& @
  /* Set a horizontal beam l(*v, w) from v to the ultra right */
6 i. ~, X7 V7 A4 C! R  w.x = rc.max_x + DBL_EPSILON;
' j! C2 L" K% ~" h0 a$ a) |& e  w.y = v->y;
# Z" o7 V5 C3 W2 s' s  c = 0; /* Intersection points counter */
6 N. r' U6 w* D. N  for(i=0; i  
; a2 E6 G) h8 {  l  { 8 [$ G9 a; R) u$ Q6 x1 h
  j = (i+1) % np;
* M: S( w" S4 D' Z) J, K. O5 e  if(is_intersect(vl+i, vl+j, v, &w)) ' T0 g: _! U1 m: H0 f: ]
  { # b8 T+ e3 y+ R& Q# A# D$ {
  C++;
) R! ?7 ^% }5 @: |, k  }
2 E0 b2 g& k# O1 j2 I5 n; }1 @  else if(vl.y==w.y)
; Z2 T  E6 x2 t, q' a  {
$ {( y( e3 O; s  }$ _2 y+ M) ~  k1 = (np+i-1)%np; 1 S0 @  Y# J) c% x& H
  while(k1!=i && vl[k1].y==w.y) 2 f, M( x0 y: R) W. w- D
  k1 = (np+k1-1)%np; 1 ?1 n' Q5 Y1 m1 M7 k. p
  k2 = (i+1)%np; ' J8 l% g: s* ?$ [
  while(k2!=i && vl[k2].y==w.y)
! T) G: ^9 P1 d! H. |- t8 L! O! F% E  k2 = (k2+1)%np; 8 \0 Y9 p# |6 e7 D  r
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) ' S& X. w9 k, M9 C+ b5 m
  C++;
- p8 i* a; X! ]. u2 k  if(k2 <= i) 9 D3 g9 Y# x+ v( {' G# I
  break;
, |3 M7 g2 C1 h9 e  i = k2; ( E" h" E% a+ z) o. h  s( }# p
  }
& y- R. B" K% l+ ~1 a  }
/ S( R5 U/ `* Y9 y  return c%2; 5 l1 Q. N) X6 Y$ f! x
  } ' N8 U. ?+ O* d, C2 B8 C" D

5 ]" G" ]4 _8 I$ }2 r8 ?9 w; P
- j- r0 _4 T' j* h6 T  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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