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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
" }8 N6 Y1 `+ ~( d- o0 t+ {& F& V( t i2 |
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。8 f- G, W7 J' w7 t# [
$ M! _8 |" }7 ]* T$ | 首先定义点结构如下:8 x% @! D7 ]+ t+ v
: j" G- o g( |6 @* q
以下是引用片段:
, a [: O% k9 g9 O /* Vertex structure */
7 B6 |: g* ]2 V2 X' a! ~ T' { typedef struct % N; P; T0 ^' g- O& I/ z
{ 4 O4 _" [% n2 }, C: E4 b4 [+ ~
double x, y;
3 I5 @1 j. ?6 Z; n3 b8 p } vertex_t; , r5 q8 j0 c0 X4 n% I0 B7 s
* T- s# o3 }3 N, }* @3 W; b, c6 i7 d% u7 y: e
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
3 b# B1 z; J7 g" T
' u! R1 \ P' J* e) U& S( r U以下是引用片段:
$ R" U4 ?; M f6 E4 u /* Vertex list structure – polygon */
- o1 T+ o2 L- L4 c typedef struct
& c' j6 j) Z# Y' s5 u/ `' a { % [* S( F% L( ?$ h( }1 F6 H. Y
int num_vertices; /* Number of vertices in list */ 0 K" g: p; d( i1 R5 \
vertex_t *vertex; /* Vertex array pointer */
) m" [9 n- m) y } vertexlist_t;
+ W8 f0 e P. P) ? T+ k
# |- Z+ u; c& _- e; _0 M6 W) J- q6 _ L
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
$ V* T, F5 v6 k8 i# E S
0 U. b" ?2 c7 l以下是引用片段:' T* {3 y: a& e. F9 X
/* bounding rectangle type */ 8 A e, O/ w6 \1 [4 w
typedef struct - f+ J) V% e0 [6 N% f. j2 W$ c
{ - N3 Z/ w$ O- p; F$ J8 {9 d. G* x
double min_x, min_y, max_x, max_y; & n1 V9 o, y3 ]
} rect_t; 0 N+ }7 F, p' o; v- h) M$ N- S
/* gets extent of vertices */
0 k/ D( \4 U' V* @ void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
' B! P2 s9 O% w5 X rect_t* rc /* out extent*/ ) 7 a4 U$ B$ `# X9 d* I) @& [9 F
{ \: E( w; V6 E9 W! {) e1 i' P
int i; : B5 L1 t% G8 ~1 r
if (np > 0){ 7 A# }9 {( J) Y7 F4 u* e
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 7 X) l8 h. L, y; D6 L0 ]
}else{ 7 R$ X" u4 K: [. y/ M: s
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
8 N1 l, u/ t8 w1 ]/ y }
, M- i0 \3 d$ g- T+ q for(i=1; i : e0 H* J' D% s- c$ X$ ^
{
) C! x. q! v5 u* |7 |2 b if(vl.x < rc->min_x) rc->min_x = vl.x;
% H# B) P: R$ j/ A if(vl.y < rc->min_y) rc->min_y = vl.y; $ X2 Z9 d+ f7 Q8 _
if(vl.x > rc->max_x) rc->max_x = vl.x; 0 d" T2 L' W* }' S
if(vl.y > rc->max_y) rc->max_y = vl.y; + m$ g, p* i& ~. a
}
$ l, V0 Y! s: U } " r+ y5 b, c, \8 H) k
4 K0 i2 C! ~3 E+ b: b- K+ J) Y& B3 a8 m; O
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
; A7 n0 p, f- K% x- |; `+ b* {% @7 l) S$ ?( S0 @3 e
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
`9 O- y6 h: i& v7 a$ W' I# x( {! L
/ M7 w: @. [9 w& ]0 f: G+ W (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;5 [9 F6 J S+ Z5 \
- _# Y4 ^! h& M. u5 [% z: H (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
c" Y9 p9 |$ W. X6 k; [, b
( O! X0 Y# q; h/ s/ G; n以下是引用片段:% G: ?3 d- q) j
/* p, q is on the same of line l */ " {2 L9 C. ~6 f2 F. r
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
" U7 u; t4 I5 R1 f3 I8 c. a) F const vertex_t* p, ) _" ?* @4 M) |3 R: B. d \( H p
const vertex_t* q)
1 r# G1 [+ d' l& C7 c h {
$ q- Z3 p- w0 j5 k8 Y' \. T double dx = l_end->x - l_start->x;
# _6 b) \. v, q) Z% o+ _ double dy = l_end->y - l_start->y;
) h9 h" u1 i- L) f1 l& v$ T double dx1= p->x - l_start->x; ; k' _4 y( V' L* `
double dy1= p->y - l_start->y;
9 ?6 z' n* x" k! Q5 C; X: z double dx2= q->x - l_end->x;
+ I$ O/ b/ G5 _, d7 \* q0 E double dy2= q->y - l_end->y; : R, \% ]6 w& M) H; O& _
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
+ i/ U4 P9 I8 I, w/ v0 D6 O" S) r }
+ u. N6 v( O" o% t/ l2 `- } /* 2 line segments (s1, s2) are intersect? */
/ S( |5 Q" J" j9 K# S0 K static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
+ M8 v) {8 R$ Q const vertex_t* s2_start, const vertex_t* s2_end) ( b3 { Y. u, F `! P: n! M6 B/ d
{
' `% ^! j6 u( }8 w1 S8 D4 ^ return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
2 J) W8 \/ ^! D0 s# R# g5 h; m is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; $ x1 N. Y% |6 Y* O% Z' v1 w7 p+ S
} ' r p0 O; _: B1 L9 w; U6 [
4 Y. B, |# w" q( G S
e' f3 v0 u* k- T 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:6 @6 O" {* O! [+ M
3 K6 i1 c8 [% h3 O; P2 h以下是引用片段:
. U& J, r Q6 q2 X& Q int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ & Q8 m8 G1 E/ E: `* R
const vertex_t* v) 6 R+ a: y. {3 T! r
{
4 c+ m6 d/ \; @" V int i, j, k1, k2, c; / I& ^5 S: x, x0 x# ?- V
rect_t rc;
8 o# {: G& s8 J vertex_t w;
4 v8 c- R+ t( ]* V if (np < 3)
' @3 E* B) G* q' Z. @! b return 0;
* W0 v/ H( ]0 V, f* {, h vertices_get_extent(vl, np, &rc);
" b% q2 i/ i( ^: [4 I if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) . i4 ^* U$ |+ f- i' H
return 0;
+ I4 d' d& M0 p# \9 f) O /* Set a horizontal beam l(*v, w) from v to the ultra right */
, i D) T" J0 _& B# L/ a1 s3 ^6 Z2 X w.x = rc.max_x + DBL_EPSILON;
5 B% f/ L: l; ?) H w.y = v->y; * h4 \2 `/ H; H4 ]2 f u- A
c = 0; /* Intersection points counter */
6 C9 [/ p' u' }8 B for(i=0; i
2 Y4 H, M4 O9 `7 E; r { 6 t, r: T" I0 J# m, D
j = (i+1) % np; 9 Q: d; Y4 i- k
if(is_intersect(vl+i, vl+j, v, &w)) 8 z, ] x4 s. N: Z& |
{ 6 E9 m- Z* h4 r; r; i' f/ X
C++;
, f) U+ q) a- t4 c$ ^& a9 j } 4 n5 O. a- e% D
else if(vl.y==w.y) # i: S: ^, v# _- X/ a9 B/ v5 H
{ . U4 @$ m/ Q! w0 p* s U0 J/ M
k1 = (np+i-1)%np; ; w, Q+ Q+ z* k4 h% b
while(k1!=i && vl[k1].y==w.y)
' i7 \/ f5 P5 t. L5 x k1 = (np+k1-1)%np; / A3 l5 Z( V x, V* W# `
k2 = (i+1)%np;
. m! n( ^- ]: A- T/ E' ] while(k2!=i && vl[k2].y==w.y) 3 V0 @, S. x( N& U% N- F4 v2 Y: G
k2 = (k2+1)%np; 0 F7 V# `, y( ]. l
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) . h: V, u( ?) f5 P( g
C++; : h( I. l( Z. n( @- }) j7 q$ k
if(k2 <= i) / h& G* h [/ g
break; V# k- h$ j% C! y
i = k2;
/ M% `$ T; Q" i+ ~5 k. u }
; y9 O# b) \) y, x) i }
+ x! D! P$ P- ~, {. a return c%2; 2 T+ \4 s) i( a% L8 D
} " S: o+ }0 `2 u
q1 Q3 }3 o& {' G
1 ^: z" a1 N0 A; ]: Q( J( a# c 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|