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

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

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

- [" V4 ?5 z1 F; z9 {5 H$ r% t  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。# g( Y6 @2 ^0 T, h. l

" {0 f9 r# y- ^- [: E  首先定义点结构如下:: f) t, ^; Q* `( p* B: g9 d
" g4 T4 X/ f1 m6 ^
以下是引用片段:! `9 D5 @% Y' J
  /* Vertex structure */
2 c+ f$ |/ K7 w3 t! M: v  typedef struct , V2 \0 T7 d+ ?; C
  { ; S. b  {* H. l$ o0 o) x" x1 H
  double x, y;
$ r6 N/ n8 @. V  n! c1 n  } vertex_t; 8 }- [$ L) B. Z
! I6 ], m6 H" t3 u1 o) j: q
' n: h( s4 \2 G- E
  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:! [/ l- p  T. M0 \
. ~3 q! A! J0 t8 y9 }! f
以下是引用片段:
8 ^  Z; v- \9 @; b5 S  /* Vertex list structure – polygon */ 1 P+ t  F' \& x- n0 `& W1 h) Y0 A3 ^
  typedef struct / Q$ \% P+ B+ N% {6 K
  { ; w3 n/ a" z9 e7 M/ e) D, {
  int num_vertices; /* Number of vertices in list */
9 A) D' p6 j9 N3 d7 y- a: ~  vertex_t *vertex; /* Vertex array pointer */
$ V9 R0 C+ H% Q. c  } vertexlist_t; % m: s4 N) T# h
3 H, P) d* R3 |. F3 M5 T
& M& D6 I' L  ^+ \
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:+ G# o: v  D. M- n2 R

) {. A5 {7 @6 H以下是引用片段:
6 _( l3 Z( e+ M6 C9 W  /* bounding rectangle type */
) I4 a1 N3 R$ h0 r' x% L1 P  typedef struct
2 D+ h- F9 E0 D5 m  { ' f/ [1 H; @9 A6 s0 M+ M- w7 r
  double min_x, min_y, max_x, max_y; * I+ g5 m- n6 d7 U) l0 W" Z, \) M
  } rect_t; 5 u1 p# _0 p; N6 e; x/ l$ ]
  /* gets extent of vertices */
( |* l: v3 c+ v6 ?0 _) @- w  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
4 X7 }3 i9 ^- f1 S" ~; a  rect_t* rc /* out extent*/ ) $ }- t/ k" ]" |( ]
  { 8 l  Y! R' ?3 K4 ?
  int i; / Q7 s6 U8 x6 H8 J; ]
  if (np > 0){ % n" d0 l% n. W( I2 O1 A
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 6 r; q$ `& l/ N5 z+ i8 ~* f2 k* e3 {3 q
  }else{ . m1 V" r5 ^9 w
  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
7 E7 z, g" {4 O% M: x  }
/ {# D9 Q  D1 \  x, p  for(i=1; i  
  a; o* L' k' L* I* ]  { 0 Z9 y$ E4 x6 _5 @. Z, x
  if(vl.x < rc->min_x) rc->min_x = vl.x;
7 r, D: v( W: X. m) f/ H6 T  if(vl.y < rc->min_y) rc->min_y = vl.y; 9 L6 |- J1 z7 \# q# z5 k. A. o
  if(vl.x > rc->max_x) rc->max_x = vl.x;
6 v  z" y6 l" M' h) }  if(vl.y > rc->max_y) rc->max_y = vl.y;
/ X& l9 h# Q* E, ^( F( D- J" h7 t, |1 N' E  }
/ H+ G, e  I" T5 ]% \  } ! c9 T9 |' l! Y9 W
& v$ j/ c$ c: n6 u, ~

! n/ ?! s  }7 ^# O; O  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。& B5 ~: [& W" `4 Q! S
: d; Q3 S. }4 d; w2 B; |: @
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:4 a+ E4 @# K. }: }( q* s

) z. u7 b# h/ k# S" ~& S# M9 T  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
1 @  g6 [% e7 ?. e- J5 V1 ?- ~" Z3 d
  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;8 p) q4 P6 l4 t6 v3 c% r2 b, c) d

* I& ]' p6 n3 ^6 U" b- B# n/ I/ ?以下是引用片段:, ?" m8 {( }6 h% V" _  U; q8 I
  /* p, q is on the same of line l */ 2 I* J# p9 K- p, q, M& K" t, t
  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
9 N- H6 }9 m" s; ?( U  const vertex_t* p, ) v5 S# d6 c# o- e. ?5 B" t
  const vertex_t* q)
- s, M9 j$ N0 X" p2 ]  { 4 u$ y, D, N; i# _# |, c9 w
  double dx = l_end->x - l_start->x; 7 z9 s. k5 f6 }! a; a
  double dy = l_end->y - l_start->y; , U( Y4 d9 a$ I4 c: i  ?" E3 O2 W" f
  double dx1= p->x - l_start->x;
4 @0 R4 I/ B2 f, @* ?  double dy1= p->y - l_start->y;
5 d2 ^# j# m' B+ q: ?: D  double dx2= q->x - l_end->x; ) [* K. j+ V" p1 d1 N7 c
  double dy2= q->y - l_end->y;
- j5 j- F8 A0 u( ^; z% b/ E3 V  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
2 t$ ^+ Z1 \* E, C4 \! W& a+ A  }   U% M, |7 W7 w  q: k
  /* 2 line segments (s1, s2) are intersect? */ 0 f5 P. F7 r. T5 L* ]* {3 t! Z
  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, ; p" b7 T# |6 Q  u
  const vertex_t* s2_start, const vertex_t* s2_end)
2 r! N4 v/ X1 Z7 G& C& U6 e3 M  {
, _9 k+ @! S+ j) G7 r  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
/ g- k" M+ Z, Q# r# D1 l' Y  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
3 s/ A* r2 t1 @' g; K8 [, Z  } - |4 T! u4 \5 v% e! \' w+ Q
- g, v4 g5 v" G- P& I) i* U  H

9 w6 U% q/ D. \  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
+ C- X* L1 h, _# x& J& ^
) b% ^# w+ M4 z3 c8 {8 A8 h9 v4 m, m0 o7 H以下是引用片段:
/ `: x* S0 r1 g+ H4 d% K: t  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 3 }! D. |& j2 F! g
  const vertex_t* v)
* l: O% M9 M9 R' I1 N/ {7 k6 U. d% z1 Z  {
( ~6 _8 a+ S  [" p  x/ J  int i, j, k1, k2, c;
" q$ {+ i; A7 O$ z  rect_t rc; ' a' n2 a" r4 ~3 C: U, ^! _9 j, R! w
  vertex_t w; 0 ?& r5 m: g) n
  if (np < 3) $ `4 Y4 Y+ E! o3 `& O
  return 0;
8 x- a# S7 R8 g; b( K- @  vertices_get_extent(vl, np, &rc); 3 h( i2 ]+ `% V" i
  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) 6 d+ `0 x9 g* C+ h: J( L
  return 0;
4 K& T4 M. H' R! `# H  /* Set a horizontal beam l(*v, w) from v to the ultra right */ , x: T8 S8 ~+ ?+ b5 c& v
  w.x = rc.max_x + DBL_EPSILON;
/ F0 G/ R* d' ]; d0 g  w.y = v->y; $ h' a$ J, ?9 K" {
  c = 0; /* Intersection points counter */ * }2 K  @( F+ d% g  D2 l9 h
  for(i=0; i  
1 S6 w+ v- d; ~  { - l- ?7 T3 [, f4 E2 d+ [/ \$ d
  j = (i+1) % np; # u5 H) t7 ~! X% M% `
  if(is_intersect(vl+i, vl+j, v, &w)) / j6 _- I3 }9 M# c1 k
  {
* H8 M) e* W$ a8 {6 ~$ J) w" _  C++;
9 W& k! R, \3 U6 K+ Q3 R  }
' n' _3 x/ o5 s8 Z8 A7 G1 p  else if(vl.y==w.y)
/ m& H, D& M% B5 P; S  { 9 V/ \# l1 I4 ]0 m" m
  k1 = (np+i-1)%np; 9 q$ R: g1 l- @" w6 l! O! X7 s3 b
  while(k1!=i && vl[k1].y==w.y)
8 E' b! b. X) H/ z. @% y  k1 = (np+k1-1)%np; * C5 `$ y3 f. Q( j
  k2 = (i+1)%np;
- t8 ^$ \: y* s  while(k2!=i && vl[k2].y==w.y)
0 R6 P" F7 O5 t( n3 n2 M4 p3 J( |  k2 = (k2+1)%np; ( n, J1 z" f$ b  ^
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) 5 ^7 [' O/ O8 h  T
  C++;
' W8 K: d4 X1 F, |! K$ ~1 F  if(k2 <= i) 1 X9 }  `0 M: A# d# S7 C
  break;
1 ?: T' g6 D8 A) J, Y$ T  i = k2; ; c* L# c/ @' C- z7 l
  }
* i! e: m) @" n7 E. Q4 L7 ]' ^  } # b" ?' O6 M. U, M* M3 B$ l
  return c%2; 0 _& Z& S0 y( E* C
  } ; ?' N3 D1 V/ Y* W( j
; r+ T- ^5 D9 q5 e: v
! M' D2 J# v0 I  a  i4 Q
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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