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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。$ L$ b3 Y; [) {3 ?
" ?8 A$ f Z) Q# |; _
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。: e9 g/ J x/ ^; r
; D8 c( u H6 M& k
首先定义点结构如下:
5 q- p' f# a3 q( T; o0 A8 U$ V/ d- I
以下是引用片段:$ x' a8 n7 \* l* W2 [% ~
/* Vertex structure */
; x2 C9 A+ s4 ^5 Q: x+ G typedef struct 8 N0 P3 ^4 K; D8 r) ]" U( H
{ ( b" S* q A: @7 H
double x, y; 6 _5 y, M- D% V E, s7 V* o
} vertex_t;
$ h7 n3 N( I* k3 h& ]7 C7 u2 O! }4 `' O0 u: ~
% f3 |8 x8 x1 `- G# W5 W7 ~ 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:& h* G, v+ _+ g
9 m! ^6 e& V) A6 M: k
以下是引用片段:
! T8 ~: P/ p, n5 q$ V" T0 |, }' {" T3 ]5 { /* Vertex list structure – polygon */
0 B, c8 M( [- I' E& b, E typedef struct : j! F! F i+ w) s: Q. F
{ 5 c; w2 L" k$ ~( V @
int num_vertices; /* Number of vertices in list */ ) Q9 I! n4 k3 E p
vertex_t *vertex; /* Vertex array pointer */
; i# \ \) k0 t0 E8 g } vertexlist_t;
/ w1 w! X' l* W9 h
0 P) z1 f* |) `
0 b: t0 F$ [* y5 y; T$ l 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
/ R% k( V9 {8 j2 `- J6 p$ R
: Q/ z% \! U! ]- h* u' a以下是引用片段:7 a, p: }" O7 ~, ~7 E; X, m; d. W
/* bounding rectangle type */ 1 ~3 r" A2 S8 k" L
typedef struct ; d4 F7 ^ m7 \0 @6 @
{ % i- F7 D( T9 q' p
double min_x, min_y, max_x, max_y; 6 @1 d- G( O7 @; I. q) N! B
} rect_t; ) G" o* L1 ]+ e0 u
/* gets extent of vertices */ - D( W! _. S$ N5 P6 P
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ ' n" o: y i. B- q- y
rect_t* rc /* out extent*/ )
( e1 @7 x, z. Q {
2 l+ R7 c4 r! Z1 Q5 V' a int i;
6 d3 V2 ^; t- V+ L, N if (np > 0){ 5 o2 A" J( K6 D/ E
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
% N! o( |* q% ]. ?6 z }else{ 4 b t) F7 {5 M6 A
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ ! c6 Z% g2 V3 `+ g2 n5 _
}
7 W# J6 N+ V3 `+ z for(i=1; i
: y3 \% I% E6 [& H7 U* T7 M {
( K6 P0 _8 c4 U% W4 O if(vl.x < rc->min_x) rc->min_x = vl.x; % F& E0 m3 u" {; k
if(vl.y < rc->min_y) rc->min_y = vl.y;
6 G' m* v+ ]( B) B% h; y2 Q- W6 c if(vl.x > rc->max_x) rc->max_x = vl.x;
- i* [+ ^5 W- ?/ X9 b if(vl.y > rc->max_y) rc->max_y = vl.y; ( Z' V+ |! {# |1 f% T3 N' G ]
}
$ @) T5 B3 c; N$ y' I } # `5 p5 t# _1 |9 ?4 F* [; K: L# O
2 K+ s( N" d7 i( L! ^8 ~! s" [
' x2 e6 j' d6 v7 J, s 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。8 y, H) |: Y- F9 U
) \* P: m- q/ d' q/ r8 D. D; n 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
: c, |+ Z( `5 z/ N. f7 R6 }2 M; u& D
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;% [/ h5 v% Q2 x! P# c
" B" J! ?* v0 j, ^' T1 x
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;/ z$ b' k. I7 ^9 {
- g4 v ]6 J" s以下是引用片段:7 D1 }' y0 r# G2 R2 i2 D d0 v5 C
/* p, q is on the same of line l */
Q, G0 H& [; {' R# P- Q# e static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
# x" T" k. O% ~; m3 E+ R const vertex_t* p,
: b& N4 `2 G2 C9 X9 K% }4 p const vertex_t* q)
/ T; u! Y2 a! Q, e% R7 t% ]( a { 0 }: H( m! }1 m" F5 V
double dx = l_end->x - l_start->x; " [* z P' w2 u
double dy = l_end->y - l_start->y; $ W4 k5 D6 ~! l8 D4 L r2 U4 U
double dx1= p->x - l_start->x; $ k9 S* N4 w# a* m6 L/ d2 N4 M
double dy1= p->y - l_start->y;
2 G+ G" S3 J+ @8 N+ h/ j0 | double dx2= q->x - l_end->x; - u% M: k% n1 e$ j/ `. o1 m
double dy2= q->y - l_end->y; ' u+ f: i: i/ D9 b9 w
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); 1 `7 [9 @+ ?8 F6 A1 `& y. j
} + i" T1 [' e6 k4 J: Q5 D" v
/* 2 line segments (s1, s2) are intersect? */ / ?0 E2 A* b1 W# M9 m' S4 s
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
4 a5 \6 {8 u* _/ J- }# S3 w const vertex_t* s2_start, const vertex_t* s2_end) 3 R* q6 O! \: S$ n5 g, Y8 U" J
{
# e, ]. b" D3 x( p+ } return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
; s- Y; I& J, U9 t! F- S0 ^- m is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
|. o2 P* `* l5 D }
9 I) B4 H. M% u( T
{1 m( g% g! v. W0 s5 |
; g2 x! z8 K6 w+ r+ q& a 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:+ ?. b% n# |$ M$ A
/ G9 @. w! M4 z" V# S. N以下是引用片段:3 k+ `7 @: H% t6 j8 Z
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
" Z; g% u9 p+ ]0 P' [+ ~) s$ S const vertex_t* v) 5 ]1 N% b& m# `$ J, b, W0 E
{ / e. K: `+ B- [: k/ S) L* y$ Z
int i, j, k1, k2, c; 3 P0 \! G- Q, B
rect_t rc;
+ t* I6 O' c% ?8 ^) Q# Y% p5 V' k vertex_t w; 1 Y9 T3 r8 o7 v/ ^9 ]
if (np < 3) 6 D9 u- J) m: f
return 0; # E3 J/ J$ v# E, Q+ T: A
vertices_get_extent(vl, np, &rc);
# A# C$ j5 D$ `, { if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
# _4 T0 g, w: ]! Z return 0;
) E7 `$ Q2 Z$ `0 S( B8 V /* Set a horizontal beam l(*v, w) from v to the ultra right */ 2 G. v8 L. g6 I! {7 Y
w.x = rc.max_x + DBL_EPSILON; 4 g% A. J4 _6 o2 Q' r+ N6 N5 ?
w.y = v->y;
% ~( y+ |4 s# Z+ x7 }, v c = 0; /* Intersection points counter */
; o7 R* M1 m k% s* H6 j7 | for(i=0; i + `& L0 m T/ {* c. M: _7 E
{ 7 D+ J8 y% P& e, w
j = (i+1) % np;
, ?4 ?2 X0 S( ], S) I% C5 d* T if(is_intersect(vl+i, vl+j, v, &w))
3 F/ y! [( [1 w- b, ~: X8 l { ; U2 S# l- D/ U$ v+ b) ?
C++;
- K8 \ o' r, I7 z% o0 a } % F- {2 P% ^2 J% W Q8 t
else if(vl.y==w.y) ( p+ U( R$ {% {# Y$ j+ D; @1 }% w3 b
{
) S% u& n5 t6 g6 ?$ V k1 = (np+i-1)%np;
0 y0 K; v4 ]/ N& M& ] while(k1!=i && vl[k1].y==w.y) ' Q7 t y) b" L% V" C V
k1 = (np+k1-1)%np; 9 x5 i. a( l7 |( O( |
k2 = (i+1)%np; % f3 W1 c9 {; f% H* W9 o8 m( v
while(k2!=i && vl[k2].y==w.y) # x" e* X2 m, h. B
k2 = (k2+1)%np;
( ]; }: }8 B9 K- P. P0 u. a2 z if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) ; P* S; S4 h5 I1 q+ _
C++; 4 j! ~8 n! j; M
if(k2 <= i)
\' s) x2 h- H. n a' ^ break; # E1 v4 g0 p: {" ~# B( M) x
i = k2; 2 Y8 Z5 a+ m% a' r( S, `8 V( o
} / g% [% M- k& q2 U! @
}
2 ~7 e3 g" A% v# z5 T B7 S V9 Z return c%2; ; \" B8 e, R- S- x
}
: g8 P& l+ o! }4 y/ V5 e5 D3 h& P
. |0 p. W- b4 T W6 A' h9 L2 e
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|