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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
$ Q2 J/ P- [% i( W ]
' Y2 J. ]* b; |' \& B4 ] 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
8 |: t7 o5 R8 Y+ U1 g1 p9 e2 X/ U( H
首先定义点结构如下:& Q! V* y4 ~3 e; w+ w; b. e
! l1 o0 f* W7 S$ [/ Z0 d以下是引用片段:5 C. ]" o1 i9 J+ {( A
/* Vertex structure */
7 C1 r$ A2 A% _/ {3 Q typedef struct , c4 D6 `* M4 h. q* {/ ?! n
{ / \3 {' E3 Y" z/ Q7 A) z. S2 F
double x, y; " N9 j& e7 L) M. u2 q, j" x
} vertex_t;
) s7 `# \4 p" [
+ \# A: A0 @1 s- R5 ^+ ^/ ]8 `* F2 L0 \3 d/ y2 Z6 F B) Y& W3 Q$ g
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:9 d) w: k# n a: H$ G
3 J" u0 ]6 i7 L以下是引用片段:" e' y, B$ d% T7 n$ T0 M
/* Vertex list structure – polygon */ 2 y+ _* Q0 m5 N! ?3 e! U! _: h4 m$ h
typedef struct ( K5 u; N: T: j1 N# f
{ 6 x% Z6 _5 F8 Y' {% L
int num_vertices; /* Number of vertices in list */
. s& a9 ?, f; R+ Q* A4 b vertex_t *vertex; /* Vertex array pointer */
. Z+ S, ], q7 R } vertexlist_t;
& _4 J% U* P- N
5 x# k, t& x) b& ]4 y8 g; A: I0 |& |. M- w/ Y
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:) G- B8 M8 W: m$ o8 W; D9 Z
D7 _& H" L& p2 G
以下是引用片段:
, z# t5 S' c) u5 g' r /* bounding rectangle type */ + A$ x2 O7 F) O( F9 V2 ]& U% D- J
typedef struct
8 ^0 c( v3 G2 {- H ] V0 O {
* ^0 `1 W# {; e double min_x, min_y, max_x, max_y;
0 J3 x, C$ L1 Y2 D9 G5 f5 z; s. q } rect_t;
$ C7 [: I8 i) \; { /* gets extent of vertices */
- v' I/ D1 C; `' m( o void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ - {/ p3 J1 B7 E$ J( j4 {; T: t( ]6 {+ d& W
rect_t* rc /* out extent*/ )
% G4 x& y. z5 S/ c c9 c { & H5 x" N i) v+ S7 _
int i; 2 e& _" A4 f$ J6 r0 i: v
if (np > 0){
0 j% y, P0 p0 L6 W% |1 A rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 2 N% u, L* N% q+ v! z) P7 p$ S$ O
}else{
* }9 ]' W/ v* K. _ rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ * G" L3 s& t( q7 s6 J9 ]
} 4 u4 ~) L- J# P) a+ e4 p
for(i=1; i
8 ~2 s8 s: K" c9 P- D! f { + w4 e/ C8 D8 h( ?
if(vl.x < rc->min_x) rc->min_x = vl.x;
; l8 ?* W2 s4 W if(vl.y < rc->min_y) rc->min_y = vl.y; 6 s! ?' x, |7 R" O! i' a* _
if(vl.x > rc->max_x) rc->max_x = vl.x;
# [# b9 J; g- q$ z, g. j" j" ] if(vl.y > rc->max_y) rc->max_y = vl.y;
1 x- F0 p9 v$ O F. r } # b. `9 ^: L4 r$ F* A6 ?
} . l9 } K. I: M; _
1 B" G* K! y8 A/ l
, q H" p- D U' P 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。& K4 V2 t1 W/ ]) ~- l9 B+ i
! I1 G! b) b p; p 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:7 n6 b+ w% x5 D, d' _' A, q6 g6 U% Q# A
" w2 N- ?: g4 y. l (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
7 X/ q7 V9 M7 ^. k5 w A( ]% }1 q
0 r! ~! g6 x6 ~4 p (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
; o+ q7 y7 q# r7 j) D! p* w) k* Y2 {6 t- A! a: |% R4 B, O7 k
以下是引用片段:
1 @( m6 ` M4 ]: i /* p, q is on the same of line l */ ! N v* u* J. q% k; b
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
9 W; f6 Y `" O5 _$ G0 ]3 g- _ g6 J const vertex_t* p, 4 o! U u3 K: P5 }
const vertex_t* q)
( p+ t: ^- }4 r# f1 @: J; [ {
: ?; [7 q2 q9 d double dx = l_end->x - l_start->x;
) C3 [% _7 x L7 Z double dy = l_end->y - l_start->y;
6 s* o" r/ R: I5 o8 \7 ~ double dx1= p->x - l_start->x; # t0 P1 a0 ?$ @( E9 Q0 x
double dy1= p->y - l_start->y;
9 y5 d6 q* d, v: v$ @2 ?1 Z# c double dx2= q->x - l_end->x; % e8 n# @1 \# ]) S; a9 _/ ]4 |* w, L. C
double dy2= q->y - l_end->y;
9 W4 x# ~" g/ R" R H return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
9 R+ O! k! ?1 ^$ ]' ~" S } " f2 X, Z7 W- }+ C
/* 2 line segments (s1, s2) are intersect? */ 1 ]4 g$ o7 A( ?7 w% \
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, 5 o" Y( h3 U! s" u
const vertex_t* s2_start, const vertex_t* s2_end) $ i+ z2 p& A7 Q
{ 1 D* u9 ?- u+ F' E
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && : _* ]8 ~# n* A6 [
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; 8 d0 i2 L, _$ i* G0 T
}
' W3 }3 ~& \; Z
0 o( x9 x0 P: [( v8 d- t5 \& q! _6 V4 ]
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
) p, W9 w' @: c: w/ L% e5 |$ Q' X5 i& I& Y; L
以下是引用片段:1 t1 P( m, i# e! I2 Q
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 7 Z0 k- E! q+ C( E& E2 l, k0 @5 K3 `
const vertex_t* v)
4 E' v2 w9 o4 p) Y2 Y {
2 v7 w7 |- L' j" X5 F/ K int i, j, k1, k2, c; 9 \0 r j6 `0 T% r: ]# T( Q- K
rect_t rc;
& O h" c0 i: T( b5 ^2 R! T vertex_t w; ; O$ m D7 T' E1 J
if (np < 3)
- `3 H# E# |5 {4 @& s& X. E3 C# } return 0;
1 S! R+ E' ^% t; R m: X vertices_get_extent(vl, np, &rc);
0 {1 m" B8 e! }/ D if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
2 P8 E. f, k$ A7 f3 ?7 _ return 0; + {0 ]' M8 j" V0 M' w
/* Set a horizontal beam l(*v, w) from v to the ultra right */
+ I! m+ o: d: d( F$ g* K w.x = rc.max_x + DBL_EPSILON;
h; x* _( H9 y m9 _ w.y = v->y;
8 N0 U5 _9 ^, z3 g c = 0; /* Intersection points counter */
+ t3 H7 o @' e" J& i; y& I7 } for(i=0; i " g8 }7 O; t+ r
{
7 }% q- Q8 y$ P. @- K2 d9 J" G j = (i+1) % np; " \& w9 S( L s& f8 ^& [
if(is_intersect(vl+i, vl+j, v, &w))
9 X9 c9 w& S7 U* @0 A- L+ a( V% B {
J* y. v* o7 y6 L0 l C++;
4 K( X4 m- B( T }
' T" r% T4 j4 Y. I% j else if(vl.y==w.y)
0 W8 R) s& W1 } @* @8 w { 6 ~/ [ [& q5 V" }( {/ z6 ^
k1 = (np+i-1)%np;
& l& h% y: \. E' P( k& O' r5 c while(k1!=i && vl[k1].y==w.y) $ W* D0 I) G2 p7 g+ H
k1 = (np+k1-1)%np;
1 N$ Y* V/ } R. O! [8 ~ k2 = (i+1)%np;
6 o* N# q; `) ~& c/ c8 ^7 u. a3 S while(k2!=i && vl[k2].y==w.y) 9 r' i+ L0 }1 a( h: A
k2 = (k2+1)%np;
& A" d0 r& [( k9 `. I+ A+ g# U if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
- F+ B& v5 O; b( ~ C++;
) B. o5 J$ y6 P" Y- N _ if(k2 <= i)
! F4 N+ c; ]2 j- P2 n) ~ break;
5 @4 f9 M+ H2 \# f0 p- ?" K4 v3 v; c i = k2;
4 d. ^7 r* u3 d' t- d& g7 e+ w }
: P% s+ u/ E/ T, W9 T! n } 5 I$ U5 P6 y, d, T& T
return c%2; 4 b* S+ x; U L1 u2 r( }6 E
} 2 n. G% O: M4 U: V- b2 m! M( b
$ d D, B; I6 m# H) q3 G2 ^
: p* p/ d' R/ j1 O- j5 x
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|