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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。- z. c& w r8 W; A
' f5 {0 C( i2 r4 n" o9 W 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。- B" S1 i F( t
- X7 v( x/ _/ F& G- \7 B& V$ C
首先定义点结构如下:
7 c& J! O/ D; D# E p5 b: M
& W% C6 i3 d5 ~& Q8 o' Z" h) p以下是引用片段:& A8 k+ ^. ~& b/ p7 y4 l
/* Vertex structure */
U- T; N4 _. t/ x& l& O typedef struct
" N( b; [7 C R9 C' Q { 9 s9 S1 D5 x2 z- n
double x, y;
! g' b! [( x& B } vertex_t; " N% z/ d3 `! s( ?2 W
; N0 u- D3 w$ e
' d8 ?$ n% u v4 ?! `* h1 L, ?( ~ 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
! x' D" e/ Z' b1 C, \; W9 U0 a8 m2 L) a# [6 }. ?0 G2 Y
以下是引用片段:
1 I: T7 \! f5 H! W9 r- T" j, Q7 R /* Vertex list structure – polygon */ 6 r9 m, B$ A! H, \, k. o1 l" W3 N
typedef struct
' V( n, {* R, @% V1 h. _# g { . D) j1 K( L. M6 L+ S
int num_vertices; /* Number of vertices in list */ 4 F5 t9 o6 d# d a; M1 t2 `
vertex_t *vertex; /* Vertex array pointer */
' [" }& X. x1 i% a$ F; x3 E+ _ } vertexlist_t; & N* Y* E: F$ v# m1 {" G1 a* x; C7 a
4 J* [) W+ x2 y$ J' [1 v$ a9 K0 P. M0 [2 `# b7 w; n
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:8 J2 w7 j, F _9 H% P" A
. |- I. D7 S+ X+ e) i0 ?0 b+ z以下是引用片段:& n+ }3 B7 R; A p! a
/* bounding rectangle type */ - E8 _! X% h$ [
typedef struct
; v* l! G. z2 m" C! F" n0 o$ _ { / Y5 k! B( ~ P6 A1 {
double min_x, min_y, max_x, max_y;
- C( {! w. Q: S' e0 D/ t7 F } rect_t;
2 J" l( d+ @9 q# R9 | /* gets extent of vertices */ p+ H& r/ _! S( t
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ : J' w- w ~0 q
rect_t* rc /* out extent*/ )
$ y/ ~( R: b- | {
$ h) R3 Z3 _0 A2 h1 n5 Y0 | int i;
( Y# `5 X `0 J: h/ s if (np > 0){ 3 g1 E! _7 P1 j8 s
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; / M/ U8 Y q' F( ] a
}else{ }+ _( |1 e# c; W: ^9 x" F4 w
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
W: |; N+ k9 f& G9 t M9 }! n }
5 m% N- p: Y& G3 V for(i=1; i
0 n2 R$ \/ |6 [. v7 p { 6 f+ y1 z9 y$ x" Y& i, K) Y3 c$ Q4 @
if(vl.x < rc->min_x) rc->min_x = vl.x;
. l+ G7 z7 a* z if(vl.y < rc->min_y) rc->min_y = vl.y; ; u# N$ X9 V% L0 _ F. n
if(vl.x > rc->max_x) rc->max_x = vl.x; % z' l0 d7 z; y) ]$ o5 o, F
if(vl.y > rc->max_y) rc->max_y = vl.y; ) D3 ]0 Q' f) T. D
} 4 g" [* k. E/ q; ^" g
} ! ?9 F- A# z1 u
' F$ w, b* h2 d$ M
' g0 ?9 S& M' l! @+ z% p: K 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。- ^. ~3 d4 h7 Q
. r+ ~6 R0 h3 [% f 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
1 B. g- j4 V' x" U: P" U
. Y% r. G7 {( w! Q( P: E" | (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
* d5 L3 R* r9 v' b' Z c, n2 X6 ~" b( X- z
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
% K+ J& T2 E$ a: E* ^9 x S2 L" |' R' F/ T- H# j6 B0 m& z( L
以下是引用片段:+ t9 U+ a4 ?( [4 s
/* p, q is on the same of line l */ 1 V+ _2 y( }4 U; G& w
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 6 L4 B! }. ^% q7 [: L
const vertex_t* p,
6 [. r7 K4 s& | const vertex_t* q)
8 B/ w$ @6 K, ?0 ? { 4 x" q8 V9 O; V( v/ Q9 b
double dx = l_end->x - l_start->x; 5 A% X/ U7 A! T0 P( G, j
double dy = l_end->y - l_start->y;
& [5 i r' x2 C' @) B6 k double dx1= p->x - l_start->x;
?, V$ k& o7 O( |/ r5 w0 K double dy1= p->y - l_start->y; . b0 A0 Z, |0 R
double dx2= q->x - l_end->x;
" j) B) |& A( u4 k0 I double dy2= q->y - l_end->y; & J4 J% p8 K$ t
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
: \1 x$ x) d" G2 G) t } # p& m+ r, [% p# L
/* 2 line segments (s1, s2) are intersect? */
; \. l9 h" D5 z/ z' Y9 @ static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
8 z6 T: {* e s& ?, l9 ]3 ^ const vertex_t* s2_start, const vertex_t* s2_end) ( ^. h5 u+ R+ {) R) E) t
{ 0 M( G2 h5 e; ~
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 1 m z3 W/ q4 i: u, c" ^( Q+ z% F
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
, s- C! f2 N" A5 o4 X }
! f+ B5 w$ H1 [0 [2 u5 B2 O( z* P' A6 V( y4 l O+ i! a: U
- |& X2 G" w. f. m! r/ v 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
2 q/ r) I J/ H; U* @6 l& V( X j3 d2 i/ E! Y
以下是引用片段:5 J6 i& I; ~- ` E. e
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
4 I$ C& `$ v2 [4 D const vertex_t* v)
% A& ?* p! ^& t/ F6 _9 _ {
+ r4 N4 M$ F" I6 H+ e; {: c int i, j, k1, k2, c; 5 W" l1 a2 h! e/ ~4 q1 [
rect_t rc;
: Y" z% z6 K' t- R vertex_t w;
, W4 _5 G4 Q8 ]4 Q if (np < 3) & J1 L& O! C: G5 `! L- M6 S
return 0;
* v( @5 Y- z* N9 X9 ] vertices_get_extent(vl, np, &rc); ' U1 O0 O, T3 s q
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) 2 b& d5 E" f( R& G% |6 {" |) g
return 0; 5 z& b/ h* B* B. G* e6 a) }
/* Set a horizontal beam l(*v, w) from v to the ultra right */
' ?: h% B* L, L9 E w.x = rc.max_x + DBL_EPSILON; & y% l; S) ^/ h# p. v
w.y = v->y;
4 U2 C+ k+ a$ r4 K2 u c- _* V- l c = 0; /* Intersection points counter */ : s6 _0 P( t E N# e
for(i=0; i
2 v: e! G: d5 z2 C0 m# P) [ {
6 [" X( s; Q: W' a, @) m j = (i+1) % np; * Z1 c4 k7 I+ X+ Q
if(is_intersect(vl+i, vl+j, v, &w))
* u G' a+ }$ B5 j! n2 B5 ?* ~ { 0 D1 H" u$ A* g7 x
C++;
+ U4 r$ L& U" N" O6 R }
) i( ^$ b8 j' F$ d else if(vl.y==w.y)
. B7 |4 u% G: o6 k1 }; _ {
1 s, q5 M1 y# R8 X4 ? k1 = (np+i-1)%np; 3 }+ p1 S2 v- Z
while(k1!=i && vl[k1].y==w.y)
; w8 o: B# ^* ?: l$ y k1 = (np+k1-1)%np;
' `# ]5 T y6 }+ k( s* e k2 = (i+1)%np; / ^, }; a" e: Q3 l0 e' m- H3 ]
while(k2!=i && vl[k2].y==w.y) 2 u6 X+ i5 ]# n" `2 m
k2 = (k2+1)%np;
7 P2 h: f4 z! m* G3 n* Q if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) 5 y$ y S- Y2 t; F
C++;
4 p: ` q7 T, }4 O) ~" }! k/ q if(k2 <= i)
) x" D% n& u" U6 z break;
3 d' C6 B2 D7 l3 P7 G, Z i = k2; 8 X. m: a' L" n% s
} % X9 d" n' _7 o& l2 `
} ' g4 o7 E9 ]' S
return c%2; % x* ~* d3 L# ^& \1 @3 n8 y
} * N+ g/ m3 l( _" q9 e
- I, ?+ G- N9 Q2 T- q E4 m; Q+ a1 n9 K6 j7 d/ E D* Y' N" q1 D
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|