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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。2 W6 | d5 G3 M" m* i7 e
/ ?1 q+ M0 P2 a3 ^ 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
2 j! E7 t y* J
$ F$ w3 z# x6 j# N1 Q( p 首先定义点结构如下:
' N2 h C. A, z" i1 l+ J
* {, C; y% H2 d4 G以下是引用片段:( }( ~/ u) Q! G5 {% g6 o! s% \
/* Vertex structure */
* I# D7 U6 ]: i1 R. d3 C typedef struct
% P+ G) x3 g* m* x1 ]/ j {
) n2 k6 A/ n3 t3 I/ P9 U( A4 T double x, y; & X5 J) O7 Q1 G. Z6 T9 \8 Z0 T
} vertex_t;
& t: \7 @% }( j* s! D( Q" |' w P' s& M# k- i! ?
1 h/ E* h5 d7 y x c+ l 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
! F- D+ _# l3 k9 | c
% i+ @0 [: U% ~$ s/ [( b9 Y7 l以下是引用片段:
7 W* C }+ c9 r) O1 X# f) | /* Vertex list structure – polygon */
% B5 O& H2 \: f5 j# f2 q typedef struct
: q* Y& v8 O# C* Y, R2 _: w; H. X; N/ q { 2 C1 o; J+ |+ P& j- W( N
int num_vertices; /* Number of vertices in list */ ; X( I6 A: `. b: \
vertex_t *vertex; /* Vertex array pointer */ . n6 @& B" a5 P6 d. B: q
} vertexlist_t;
7 O. c1 ^. u( x8 ]! Q# Y% o( K% |5 @. W
; Y- \, T1 M x- B- o C* S
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
+ D* O' T4 i J3 ]3 ]: Q0 P
' G2 N6 d @8 o1 n i) @6 h以下是引用片段:
7 L; \( O( J+ s* I /* bounding rectangle type */
! |- Q9 q" r, ]8 V2 S typedef struct
7 \4 b( H" }2 E) N {
% g! b P$ h6 k" ^& W double min_x, min_y, max_x, max_y;
0 @2 f( W& `7 J- A$ r } rect_t;
% J" g' w- G$ a /* gets extent of vertices */
1 W5 F" B4 s E5 Z' V void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
' n; Z) C& H1 F) a7 N rect_t* rc /* out extent*/ ) 5 _! ^; }8 w2 ~: j# J) t9 C2 \" Q
{ / ?3 l2 e: E- T3 U4 N
int i;
6 M) g L8 T n$ k4 u- _ if (np > 0){ r% C4 s1 C8 H- N8 ?" P# B
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 8 g9 E; A. k: {4 w) u: |& i6 \! W
}else{
: p" ]! q7 v' t5 S rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
2 ]8 k# N- S8 I } ' l8 j& m7 I: q7 _: b# B
for(i=1; i
. N5 i& p, t" v) J8 j7 q {
# `' o: o" Q9 M4 h& E if(vl.x < rc->min_x) rc->min_x = vl.x;
/ i0 ^3 }+ |# S" Y" o8 A/ U* T9 _ if(vl.y < rc->min_y) rc->min_y = vl.y;
/ d* X+ h4 z0 A+ V4 v( t if(vl.x > rc->max_x) rc->max_x = vl.x;
4 ?6 U L- r! |! S5 R# K- M) T if(vl.y > rc->max_y) rc->max_y = vl.y; W1 `3 `/ |* y1 n0 G) r$ `
}
' Z$ e9 f: M+ g4 ` } 3 H/ Y2 \0 S$ `0 ?" y1 F
6 c# z2 V A' \0 k; D L# a. j- n" t: k7 H* i; ]. I1 k
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。' T! ]; k0 P% q
. `0 Y4 T! j" L 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:6 `: @& Z0 H% I1 O$ W
$ \- O6 P: V- a3 B: x
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;" Q" q, p6 \! g$ t
. F- ] O" _8 n! d (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
! p. Z, ]3 v* W" Z8 r
% G9 k: a$ v8 G' B, t以下是引用片段:# w3 Z# L8 A& e2 c
/* p, q is on the same of line l */
5 {& w7 _( m$ @, a static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
# u; U5 b8 e4 x, S" X const vertex_t* p,
# i( p1 P* q5 w% i8 i: U- z7 ^ const vertex_t* q)
( Q3 S' J! m9 b# {& p% a/ v {
9 M: d7 |1 n B$ d6 N" B double dx = l_end->x - l_start->x;
: z3 M X J4 I7 N k1 j1 r double dy = l_end->y - l_start->y; t0 s! _9 n- {+ B' x
double dx1= p->x - l_start->x; / e& W: y. L" U6 _* _
double dy1= p->y - l_start->y; . k( L4 t4 y' B$ K `
double dx2= q->x - l_end->x;
* R9 H7 L: h) [# g2 E5 Y double dy2= q->y - l_end->y;
% ]* Z7 ?* k& Y3 Z; v( \ return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
$ X1 ?! i/ p3 p. M5 l8 y; c }
- s6 I9 i2 z9 a) i- {8 M /* 2 line segments (s1, s2) are intersect? */ ' ^4 a9 F0 }0 |; j# S' e0 b
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
) Q7 Z9 S8 e% M' y% ^ const vertex_t* s2_start, const vertex_t* s2_end)
; I2 i5 T) ^2 S8 g* n {
- n' [+ {- o, ^) O8 T: H- V return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
& A% s9 z) I+ D& m# a9 v is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
$ f; ~9 o6 Q3 D. H } # j# G' t+ T* {- f6 P0 {
p4 W# f8 ?! e1 R- V& m" g0 q2 g) T& a( t9 |
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
3 q" C: R# x, Q( A
% M9 F+ n5 P- J+ I0 W0 X2 h M, H以下是引用片段:
% \( N5 E! S( g! Z" h$ ^3 a! ~ int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
4 y: \7 _5 p; I4 x const vertex_t* v)
& |6 Z5 E# e1 ? {
! O, H& T5 R; E- A" q" D6 Z+ v+ ^ int i, j, k1, k2, c; 8 {0 i0 v/ j# t- u4 e5 W& K% x
rect_t rc; # m0 U- ]" n- s! h+ E
vertex_t w; # I# h9 ]1 L6 c: ]
if (np < 3)
) h" f3 p! w9 q4 y7 D$ T return 0;
. ~# [( s0 d8 C vertices_get_extent(vl, np, &rc);
- M# U/ e0 T* V( V7 e if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) 2 @8 G' n# C9 J+ t
return 0; 5 q( _& q0 @3 O
/* Set a horizontal beam l(*v, w) from v to the ultra right */ ' G, ~) ?5 S7 a
w.x = rc.max_x + DBL_EPSILON;
~- N& l3 P8 w+ M; J! P w.y = v->y;
) Q7 j1 Q, C# }5 \% a7 X# s c = 0; /* Intersection points counter */
2 e' |( g% ^" V' Y for(i=0; i
# k& y/ q( A# j { % \0 g H1 q+ f+ i9 w
j = (i+1) % np;
& R% d8 ?" |$ O+ r+ s5 @' B1 L if(is_intersect(vl+i, vl+j, v, &w))
/ O* j' B+ m0 c i4 x { + ]" ^/ E: R M' i1 X
C++; $ A0 [% m& l6 w$ m. k4 K
}
G. _8 |+ M& l, J* ? {; I else if(vl.y==w.y) - I% g& N+ F: ]! P
{ " J: z; V8 o. p$ m; R% k b
k1 = (np+i-1)%np;
# K: _$ J4 d) d while(k1!=i && vl[k1].y==w.y) ( B' d# f0 g7 y" I7 {7 w" u- l
k1 = (np+k1-1)%np; 3 ?: b5 U" ^5 f" w4 y: ]8 m* Y; Y
k2 = (i+1)%np; / W) M: G N! f
while(k2!=i && vl[k2].y==w.y) + w3 _8 G7 S! B! t2 m% c
k2 = (k2+1)%np; . T. ]- k, v- U
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) , u, _( J1 k* D9 \; c* h& {
C++; / I0 O# c9 f, \ G
if(k2 <= i)
& s. u- C) T; C break; x2 s! h7 J5 x1 V9 ~6 u" ?
i = k2; 6 J% J3 D8 [7 _, V8 e0 v
} 8 j. k6 N( A& H) ^/ e1 [
} : p# b; P' l- B6 f
return c%2; : F$ J- s; r( y( j$ _9 h3 L4 P
}
* j9 r, n; l( h: k# S, `( `2 G4 E5 |7 L: r) x4 `% y/ s; |4 r4 L
8 Y/ i" r1 ~4 ^2 X q 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|