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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。! L4 ]+ E; {4 T+ h( k) f8 _
3 o* R/ [0 w% l2 Y. P
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。+ k* P/ k3 O: \% Y! w
" o" b3 |, A. w; @" ?" _4 O 首先定义点结构如下:7 H1 K8 v- Q) r% o
) c$ s; f% K4 }
以下是引用片段:0 M; |- W0 l# m4 }5 `" e6 Z
/* Vertex structure */ 9 h0 j" j( p7 w. T6 t
typedef struct
+ c. g5 v5 s( z: j$ e {
/ ~6 I& M; Z, h* H; l/ o: ? double x, y;
# v- O: M6 D/ v3 t+ p) M } vertex_t; , P8 C3 P# q- W) r& D1 O2 ^
( W" O5 |; ~- o! N7 s6 T& F# j9 R4 h+ d( |) q, \! k8 }9 A, z
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:- b6 @! z4 N; Z7 l( U$ S# d8 X
3 X3 P b* ]& Z
以下是引用片段:2 \8 o6 T1 r5 n. m: H$ m5 t
/* Vertex list structure – polygon */ # ]; w! ^1 d0 @% I- T
typedef struct
0 E) ?/ T; }2 D3 t8 R, O# z {
$ D4 J5 p+ |+ @8 w" X int num_vertices; /* Number of vertices in list */ * q- d* V- }& o% | N
vertex_t *vertex; /* Vertex array pointer */ 5 F! [# q& a2 p1 b# D6 L ?/ I
} vertexlist_t; $ E2 g6 E, Q6 ?( V% U# J6 }
- q4 L& F% ` l$ o
+ \3 V; z( l! B; k5 A
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:: z7 C: F- t* P3 v$ M0 |% F
* u8 ?+ G' h) S4 W
以下是引用片段:
2 s) l# l' i) Q$ n5 m$ I/ e /* bounding rectangle type */ ' y( K: e. Q- _, O/ U7 h
typedef struct
& l' u6 `0 s a9 b. _. }7 d {
6 {+ l* H' j0 {% R( a6 Q double min_x, min_y, max_x, max_y; ; b, c2 I) L1 y9 ~. D
} rect_t;
+ \* X! c/ t s* d /* gets extent of vertices */ 5 T, m* E6 f% a4 w- H1 H/ r) f' f
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
/ c* m/ z9 x. y. q rect_t* rc /* out extent*/ ) # g/ n' O& l. y$ [5 h
{ * z' c7 w# v. \2 |
int i; 8 Y5 ~& C; u4 N! P2 ]. U) b' X
if (np > 0){
. b, @* T$ }8 |. K rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
e* L+ k0 n2 p0 e }else{
; N8 D) @* z2 t f rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
) _) W0 n7 H; b# }' | S }
1 k! a; Z0 Y% A% f- @, [# T- { for(i=1; i & G! U2 X! L2 n; u+ c* B# G( S
{
& W8 ?1 g% B6 \1 \! k" I8 X. w% d if(vl.x < rc->min_x) rc->min_x = vl.x; " G0 U% |7 J# R$ w: o/ S( k8 @
if(vl.y < rc->min_y) rc->min_y = vl.y;
1 z7 J7 e* j3 e if(vl.x > rc->max_x) rc->max_x = vl.x;
# d! X* Q" L3 e2 E* m9 T if(vl.y > rc->max_y) rc->max_y = vl.y; 7 C. R( J, P% [3 A$ d8 n
} ; _: b" n+ F( m( d. R
} 6 |3 C/ q' i4 r' s/ v
6 f0 G2 P( ~" h, q7 x X! O/ T, Y F1 e+ b; r
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。+ X* s$ J3 u1 {( x
; s' _7 ~% e% Q% j; {! n, l
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:& O* t% _- j% G3 C
' j0 E v( S& t
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;, Z9 v- n' [3 _: W9 G2 T
" @' {& [8 B( w! [8 L
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
7 j1 r, k( Y- j
1 ], U; s$ ~2 h# V以下是引用片段:
& k+ X, L u! B! u3 I /* p, q is on the same of line l */
- W1 x/ J4 J! Y static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 6 C/ ^: z+ b+ Q0 m5 j
const vertex_t* p, h# [3 t% i: q% h. J
const vertex_t* q) 6 R/ F' j2 T% L; u6 T
{ % ~. Z8 X) P$ R) m3 }
double dx = l_end->x - l_start->x;
" L: E6 g, K$ K double dy = l_end->y - l_start->y;
, Z' v# u/ L/ G# M$ N double dx1= p->x - l_start->x; 1 z6 e U+ `: T* l3 N3 A& U# s% Y
double dy1= p->y - l_start->y; 7 W8 W j9 L9 T3 r; ~: ^9 O
double dx2= q->x - l_end->x; ?) J* U) A' w/ H
double dy2= q->y - l_end->y;
+ n$ l9 ^/ F0 { return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); 2 `* k6 U6 ]& l4 b
} + Y" U n# h" z0 G* f0 a
/* 2 line segments (s1, s2) are intersect? */
% Z2 Z: i. a3 `: z( O% p+ L static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, ( F9 }; R/ Y. K T! B& J9 m3 U' [
const vertex_t* s2_start, const vertex_t* s2_end)
9 J; k& I0 U$ X {
- t7 _8 A& x/ }) W- I! R8 Y return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 2 t. X2 R' M6 Q; @7 e( B" s
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
6 b$ ^* t5 y" f! X& A }
) d0 k% j$ {6 U
3 f3 b2 W) I! t {3 s- X6 O3 F6 B# g4 D; {/ G. M
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:' x7 \% O: S- s& o; a
+ J; r$ s0 u6 b# J' y2 C
以下是引用片段:
- W) [7 g$ Y9 `: _/ q) J: w int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
" h8 r1 Q# l" {% y9 A! y' O3 R const vertex_t* v)
0 a+ S9 W+ e3 j0 f% j { - q1 F2 N2 \ Z' }( e
int i, j, k1, k2, c;
) x% k7 Y- [. [* V' O* W$ d rect_t rc; 6 N, n; Q0 Z7 d6 B
vertex_t w; 0 ^( }4 \7 T! G) C0 G
if (np < 3) / t( b. Q- g1 B
return 0;
- ~% @. z+ n; y3 Z vertices_get_extent(vl, np, &rc);
, k8 h+ B: a, G7 P if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) ) s9 G; q3 h3 C# j
return 0; 8 Q8 i5 F" C% }6 R0 J
/* Set a horizontal beam l(*v, w) from v to the ultra right */ 0 @+ \3 J: V8 X, U- L' e- y, A
w.x = rc.max_x + DBL_EPSILON; 6 Z2 Y$ Z& G2 W* r
w.y = v->y;
0 `( O2 Q1 x ~ c = 0; /* Intersection points counter */
3 ?2 K0 v" b/ c" ~: F. z for(i=0; i
4 l& M. H( h1 S7 f5 v" t5 a0 q: X { 4 a# z) o6 {9 a& ]9 q
j = (i+1) % np; % r! T2 k7 j/ o, G! L7 v2 E
if(is_intersect(vl+i, vl+j, v, &w))
! J/ m( z s. F: @8 \3 Q5 F8 W { ( y# s: F( }! d7 g) }) u8 j5 K
C++;
3 q. F( C/ F3 x7 N1 E }
: U9 s# h5 V3 S; P7 D else if(vl.y==w.y) # C/ Z" j' R# w9 b0 W
{ 8 q7 W. y; s- @0 L# i' ^8 Y1 B
k1 = (np+i-1)%np; * L. F" a% M' P, x1 S6 ?2 U
while(k1!=i && vl[k1].y==w.y) % m" S3 l4 H/ P; N6 F
k1 = (np+k1-1)%np; " h% R" Y: {" @/ l- q
k2 = (i+1)%np; ! u h. f1 x# \' |; @
while(k2!=i && vl[k2].y==w.y)
6 P# M, I4 L/ M k2 = (k2+1)%np; [$ k6 E8 U) S
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
; ?! l+ o0 K0 s" b) Y, T C++;
( ^; I3 c6 \: ^1 `/ g if(k2 <= i)
2 r( s& n- a! w/ A, O7 H% r- L break;
( M1 t/ t( I2 w. { i = k2;
. i2 i o* j8 F" { @" ] }
X& m1 k' Y9 N( Z } 7 a0 F. T8 [6 @. ^3 P
return c%2;
6 L! Z& ~4 k+ T5 }8 i }
3 V! e, Q5 Q1 H* _- r) h& l1 |* Y# p1 o/ Y" d
* c. c4 S4 W% H 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|