返回列表 发帖

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

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

" p  g* u7 R0 f& v* U2 o0 E  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。& W' z% i: X- e* R  @
% i7 y/ X4 R: ?
  首先定义点结构如下:
$ I( h0 L4 \$ B  p. \( l4 Z8 I; V4 b, ^: S
以下是引用片段:8 e1 f6 i* ~6 n6 N2 c9 m4 T
  /* Vertex structure */ , p1 l' k% X2 y5 z- |
  typedef struct
. p7 f; ^* l% N& M& d# x  { 8 K+ n1 U" d* |2 n. l
  double x, y; ( ^. W9 _$ Q; b' B! X+ k) m
  } vertex_t; ' m; }5 s* D- u! r% m
% ?  k) J# Z" c- M7 u  ]
: k& M% \( Y" F, K! r
  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
) E. w: W  E, n  f7 c5 q; _; R" N5 K# [- ~# w* _! X
以下是引用片段:
6 L; l0 g' D+ q7 t4 m1 X; u  /* Vertex list structure – polygon */ 1 U( ^4 {4 p" h2 l, I# h
  typedef struct - I  e6 u5 A) B8 _. x: G
  {
8 y$ j; h/ g* B2 s5 S, }  int num_vertices; /* Number of vertices in list */
3 J  O, V2 h2 f3 n9 @4 \& l  vertex_t *vertex; /* Vertex array pointer */ # W! J/ q, {* D+ R  ^( f
  } vertexlist_t; 0 G- `6 _+ a6 j3 u# b( w% L( J7 ]
: K8 J+ [; I- a+ A
4 L5 O6 r, {) D* l; s( }
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:$ F* R( L* ?7 t+ ~
% G/ z3 H: o( S
以下是引用片段:7 |  x2 J  l) d% [3 }5 d" a' F$ L
  /* bounding rectangle type */ # S7 |8 @2 g0 p1 x' t2 i
  typedef struct ; E* T' q" Y$ i# m+ J5 l
  {
4 ], Q# a9 T# N# Q4 i  double min_x, min_y, max_x, max_y;
+ V& G$ p2 i7 e" _5 Q! [; P$ U" P0 c  } rect_t; - w: t4 x$ T1 Z+ X+ x) h/ z4 @
  /* gets extent of vertices */ * x3 s0 h- N% I/ B4 M) f, q
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
; o5 N2 C0 X# l8 X, t  rect_t* rc /* out extent*/ )
$ B2 \, R3 ?- n3 n% R6 X  { - C, o; M* G+ s4 a/ K/ R
  int i; ) `* r; x" S" y- F$ a
  if (np > 0){ 8 X# J$ f* y( r% Q1 X. r
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
* z! k" U1 P. h' ~2 `" b  }else{
, @0 I; y4 b+ E: D9 w  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
5 ^5 A% O6 f7 y; j+ }- m' ~. }  } : G5 U1 C4 N7 z) f
  for(i=1; i  
9 p5 D% j' g0 F1 u( x' u. Y  {
3 g  g5 H- Q& X, h% {' i8 ]  if(vl.x < rc->min_x) rc->min_x = vl.x; & `1 [2 g$ M; ]* y
  if(vl.y < rc->min_y) rc->min_y = vl.y; 4 I# v; X# a2 @) H6 x
  if(vl.x > rc->max_x) rc->max_x = vl.x;
/ F  i# ?4 T) u  if(vl.y > rc->max_y) rc->max_y = vl.y; : O: l+ P" A- f8 J$ E% b' Y! W
  }
4 b' `' O2 Q9 {2 y, W7 L% f  }
! |+ U! \" e* s0 ?& b5 D6 x; A; p3 h& [  o& L3 f; m" L7 k

% A- K  ~6 [; ]) q" [) V* C  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
2 |3 R5 E0 W5 O$ `$ G3 l0 s5 b) X, @$ L* ~9 N/ l# E' U1 D7 R- q1 k
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:7 G2 K4 w+ A7 ^9 `6 D
& U4 c4 U' n; }+ ~& L1 G
  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
1 i$ W2 x6 W: a& _9 u$ J
* M9 V  J# d' @5 A  W7 B  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
! m* b  n; J- @
& m: k6 `# o5 d以下是引用片段:- q' W8 W3 W* }% x5 |
  /* p, q is on the same of line l */
8 I: y8 J- \# C  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ " g2 l4 q1 L9 x/ h0 J3 j
  const vertex_t* p,
& J$ f0 I0 |  [, j# L$ V4 w  const vertex_t* q) + ^$ K9 B% f1 k9 T
  {
7 |- E0 D- Q' H  double dx = l_end->x - l_start->x; . ~/ s, v3 z% `/ B( i$ U: @6 a
  double dy = l_end->y - l_start->y; 6 `% m# b8 I5 R8 s& [
  double dx1= p->x - l_start->x; 5 o- }% Y+ e' g" H
  double dy1= p->y - l_start->y; ; A% o6 N4 o: o6 q+ m( G
  double dx2= q->x - l_end->x;
+ w& q, }$ I9 c8 \  double dy2= q->y - l_end->y;   R( p0 q2 n3 F
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
) H/ R4 r- o; D3 @8 p. m  } : v$ e6 E+ S& F# R3 u  e+ Z
  /* 2 line segments (s1, s2) are intersect? */
/ a3 F* X9 J  d5 V- w) s  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
( e7 |: v) F$ p; j* _' a) r  const vertex_t* s2_start, const vertex_t* s2_end)
# R9 ^+ D% o- F9 ]# L4 f' x8 f  { 7 ]9 l/ b$ e, z
  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
8 a) X, C0 d, m  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; * x8 h' E* [. B% j1 N" _+ i
  } 7 ~  s8 F8 N  n1 V
$ G2 {9 ~) R, T8 g9 _) B
8 g0 z$ ~9 v: j; o* D) V% m7 k
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:. B0 ~8 k+ u. F! W

; N8 g1 g8 N% W, p' v以下是引用片段:: s( t* x! O: u# `  @# V4 a
  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ ; v, k  J6 t' \) ]) a
  const vertex_t* v)
! B: G0 l; G- p1 I  z  { % U! U) C5 k9 b" Q0 e9 A
  int i, j, k1, k2, c; - c5 {, u+ o0 ^* V6 |; P  V5 p! P
  rect_t rc; " H9 o4 `4 D$ l* k; ]4 s& `2 ^% B
  vertex_t w;
- s, j+ m8 F& H1 I, R* v  if (np < 3)
2 \6 S  @. U( e  return 0; 0 d8 j8 F- T: X- ]3 d
  vertices_get_extent(vl, np, &rc);
  a- X( P# J) I* M  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
% ^7 k; s( R0 D& G) ^; z  return 0;
4 ~* b" K( k- ]0 ^  /* Set a horizontal beam l(*v, w) from v to the ultra right */
! N, }, h! G  d- O9 W$ y1 w1 N  w.x = rc.max_x + DBL_EPSILON; 1 w$ C: F- a: ^4 i1 P
  w.y = v->y; ! P$ c$ c! x+ s
  c = 0; /* Intersection points counter */ 7 y! {5 v2 v4 S3 o8 N
  for(i=0; i  5 Y4 f+ |( y/ [8 S/ }) \: i+ d% _
  {
( k3 b# y( t4 p  j = (i+1) % np; 0 {1 L6 ]' L2 l; d( T4 A
  if(is_intersect(vl+i, vl+j, v, &w)) 4 g. b5 `" Z' M9 K9 k) ]- J, b, k* ^
  {
0 ^. \& j6 a& ^& N! Y, Q5 T, d- j  C++;
0 o* w& z/ O$ F  }
' j' C% z1 s5 T- c  else if(vl.y==w.y) 0 M/ z* j$ x+ ^3 f; E
  { 3 `: a+ }  [2 n6 t+ `4 ^
  k1 = (np+i-1)%np; $ V7 e, k" H- _3 G% E
  while(k1!=i && vl[k1].y==w.y)
7 q! j, p5 L& c8 Z- r- P# G7 B) L( J  k1 = (np+k1-1)%np;
1 ^  C  V0 \. G, u; u  k2 = (i+1)%np; 3 ~1 V6 L2 D0 F) }6 k
  while(k2!=i && vl[k2].y==w.y)
2 `1 t7 U! m' Q8 X! P  k2 = (k2+1)%np; , O8 Q% e4 G' K) D& H5 R' X9 g
  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
. }' B& E$ z, _) J; h4 f5 e; N3 [  C++; 7 y$ }' @0 \4 z1 w9 e4 u5 y
  if(k2 <= i) ( h9 w' M  m: U" A5 u- w% i" }
  break;
( J* }* E& T" v# J  N  i = k2;
. s" E8 W/ h$ I' |/ M, B  }
) D( W$ @0 h% l- h& Y  }
6 K3 u" T; o8 q& ~% J$ P  return c%2; 3 S" y) q! K* v1 o" _: F
  }
) h7 q' L. y0 y
7 {1 x. G& x4 |+ j( B6 _% I% ?# v' R1 I# S2 `3 W1 B
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

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