|
  
- UID
- 133
- 帖子
- 51
- 精华
- 1
- 积分
- 186
- 金币
- 55
- 威望
- 2
- 贡献
- 0

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
7 g7 @& a' ]( q7 t7 _7 D3 l
6 [; z( o9 I# |/ b x+ f" ` 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
4 P* ?4 H5 }8 w- L& x6 o
k! q; S0 H5 e' v# N 首先定义点结构如下:
! [+ n+ @' m! r
8 q' x+ Y% L+ e( [5 Z j! ~1 `! [以下是引用片段:5 w% G) O! b. @ S, o
/* Vertex structure */
& [% C, |1 l) O3 K" C' J2 M typedef struct . v0 Z" I' R6 E O- z8 a
{ 9 b, M) S( O8 W$ @3 A+ h
double x, y; # g# |+ F1 q4 A, [
} vertex_t; & G4 k- [0 ?- c5 C' J( E2 L. l( S
+ i% s$ } O9 z) a7 D6 q
* u J% B3 w+ ]4 W2 {1 R 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:) L* s6 J9 H( y) I6 {
& Z i- [9 }, u h/ z以下是引用片段:$ t' C- z# O$ M+ p* Z
/* Vertex list structure – polygon */
5 u+ J1 @( F! o& a typedef struct - E7 `" |$ G! @( N, I }
{
$ t# \+ F7 {. c' P. d int num_vertices; /* Number of vertices in list */ 0 t( O3 ]7 W7 q- f, i8 a
vertex_t *vertex; /* Vertex array pointer */
- x7 r2 E. B/ a1 m* V E) {- ]/ r8 E } vertexlist_t; - x) B) |9 r- E4 h
9 D8 a8 Z& y; |3 ^6 R! f) \2 T: |4 T6 } f
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:% P' Q2 @( v8 [6 w
8 c6 r6 W( [8 k! h ]/ g
以下是引用片段:5 l9 J K3 u) e2 w9 z
/* bounding rectangle type */ * i5 E9 j1 G. j% r# x! D
typedef struct 9 i6 C+ s, u" e% m/ s* F
{
+ `( y! n8 q! z+ z0 U8 d+ @ double min_x, min_y, max_x, max_y; * ^% ]7 P$ [* O' H. W2 A4 S
} rect_t;
( e& x7 K- o! C0 r7 E" Q /* gets extent of vertices */ 2 Q( T9 E ?" I+ o
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 9 e, ?% o( o/ H0 c( K% g3 c
rect_t* rc /* out extent*/ )
. Z2 p+ l# q: A+ H8 a; D/ z; I- p( { { , g/ R! u' Y' J% n
int i;
& |) L, Y. m T: m9 z- d if (np > 0){ 2 ]3 C1 [$ _. d, [6 b. G1 ?
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
7 ?8 P5 @* H* \1 b+ O }else{ 2 A( I' \# |: u/ O6 h; Q$ Z
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
# p9 u/ Q5 t: ?$ B/ W! F8 r }
* A6 _0 N* S. R+ T& {. F. g3 p for(i=1; i
8 _( u+ b/ v' M9 D { 3 j V( b. N! T8 t6 v& ~, A
if(vl.x < rc->min_x) rc->min_x = vl.x; $ F" ^" _( W" l' A
if(vl.y < rc->min_y) rc->min_y = vl.y; 9 h1 |2 B1 X4 j6 k
if(vl.x > rc->max_x) rc->max_x = vl.x;
+ ~0 o h9 H3 G; `( N2 C7 E if(vl.y > rc->max_y) rc->max_y = vl.y; 6 O' A, }" @( I+ _8 S/ j
} 3 m _3 O; C _' m' D F' j7 r8 y
}
) c( R* P4 ]: W3 P
# j4 c: F7 Y6 w& r9 E& t& M( j0 Q) V; H0 u z" J5 P( j# v
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。/ e/ ` J1 M) Y, B M& _4 w; c
+ O8 w' u/ n' M9 q$ H
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
. F- O' J+ Q# D4 Y
3 I/ P- y! s5 p (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
0 K Z( h0 }; T3 c6 A7 o
7 d0 g) m9 U' y (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
9 x; n- b2 f' ~* F, d
' [9 \1 w# L9 K' O& m以下是引用片段:
9 T. x$ n. X1 R( [7 j% S% } /* p, q is on the same of line l */
! W! V/ _, G- s2 P static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
- u* B' i: V' W( ]+ o! l const vertex_t* p, 5 {/ P- K& }3 T( N1 ?5 x7 D2 [, M
const vertex_t* q) & U3 y" f0 S+ ~9 u
{ 6 C5 O( v5 k; @4 ], I
double dx = l_end->x - l_start->x; , D8 l. q Z! J+ V/ Q; ]
double dy = l_end->y - l_start->y; 0 ~9 K x6 b' k- ]7 s& @
double dx1= p->x - l_start->x;
* G6 c7 B4 D$ T( K, c double dy1= p->y - l_start->y; : a! d; E$ l' S2 u) k2 s1 q
double dx2= q->x - l_end->x;
9 y+ j8 l3 g* A c double dy2= q->y - l_end->y; " B: O" O1 s' _; B! B
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
& n( e& W, [* a0 K9 _. M }
b5 _" c! q; ^, Q* i0 @ /* 2 line segments (s1, s2) are intersect? */
- m0 t# }0 Z4 W8 L6 Z. a static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, ) b' c. G& R/ L! R
const vertex_t* s2_start, const vertex_t* s2_end)
) p* y0 w* K z6 G1 k1 ` { + [3 w, j& H- ]5 s @, P# o! r
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && ! v+ H$ {- T( w5 r: }! N
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; ! K' J9 B) E$ O5 L" m4 D
} : _9 N: j6 J' |, D% C9 i! G
5 L8 d! s* F+ M% i
* ?2 g8 T9 m9 ^9 [. n5 A# ]! V 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
) B# M. m* s1 l6 N) x$ `7 E! M0 b6 |' u6 c
以下是引用片段:. @4 F) `3 O- T: V8 w! u" Y, k
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
t! \1 ~5 j0 w% x% {3 @( S2 M4 g const vertex_t* v)
. v0 C$ T6 `/ z2 v) N {
/ L" u0 S! h2 [* m# A7 @2 f, f int i, j, k1, k2, c;
3 s$ N q" O: m) t1 K rect_t rc;
, A, {& _7 ?) q J6 F/ u vertex_t w;
; }! C3 U! `5 J if (np < 3) * R. L+ i, u5 g% I5 ]
return 0; 5 t" E# w/ h" K' D0 t
vertices_get_extent(vl, np, &rc);
6 X( O' {) K( l7 Z, z" \" ~ if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
# Z' _7 x; D7 O4 L* T$ b& W return 0;
$ j( L2 p: h ^+ q /* Set a horizontal beam l(*v, w) from v to the ultra right */
5 z2 H A% k8 a; B. ~' F w.x = rc.max_x + DBL_EPSILON;
$ Z9 T0 b$ N2 r( @) K: a" Y w.y = v->y;
; M4 D6 B3 _+ G6 E6 [ c = 0; /* Intersection points counter */ 4 ^; U" I" i+ p
for(i=0; i
* h8 C b& ~' R# G( X* T {
" ]% G$ W4 S% ^ j = (i+1) % np;
: a1 S2 d; _, b8 }% I. z0 u if(is_intersect(vl+i, vl+j, v, &w))
& X. f$ ]( l3 e- c% J# u. H/ a { / i4 n6 [! x q) G+ e+ c2 G
C++; , P H! W0 X1 E( u, z! ]( P+ y
} 7 o; u; Y8 U) {& t- J
else if(vl.y==w.y) ) U3 i2 w- R9 C+ w$ B- H# d
{ : p5 D2 U. Q1 V& L8 m
k1 = (np+i-1)%np; + n, s6 J/ \6 j& x9 |
while(k1!=i && vl[k1].y==w.y)
8 s4 C1 V: Q: L8 G. s; } k1 = (np+k1-1)%np;
" {- p4 U: o8 f4 \* S7 G. U2 b& Y5 N k2 = (i+1)%np;
4 M1 y9 `, F1 t0 \! J7 @* x while(k2!=i && vl[k2].y==w.y)
C/ [) e4 [3 ]( o k2 = (k2+1)%np; ( b3 l$ |1 ^: Y3 H; b$ y
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
3 m1 m5 \4 ~0 j: c! U2 v C++; + L6 Z# s2 O2 V# Z; {( _7 U
if(k2 <= i)
4 W6 G$ B$ [5 k0 i) X break; ; C3 [/ Q' M& t3 X
i = k2;
1 u& Z3 C- l/ a' _) q }
7 I; @& J6 t; t4 f: J0 E } + W7 X8 j7 b% E- R( K. T# h
return c%2; 9 V4 X- [8 n& n8 P% H) w) {/ B7 x
}
3 t1 u5 F8 N! b5 l, `# z- D! M0 n! w: I5 \" m: w
5 s3 Q% H+ n/ G/ B0 A 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|