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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
, l4 V1 q) N% s4 A' @
' u9 A* A$ g$ {0 I6 Z 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。& j$ `' ^" T5 N2 ]/ E" p) F
; _! x- E: {! K; s 首先定义点结构如下: ?$ }& C) e8 y; h H
$ M, q5 L# k9 E a4 _2 {# H6 O: i以下是引用片段:
2 M0 d: }& J- u6 V4 D /* Vertex structure */
9 {/ {' J# G0 [/ {' O typedef struct : [: p2 }( ~( Z' P7 J5 X
{
3 ^1 L& V, {1 U4 e9 T double x, y; 2 C: ^/ F8 P7 p G6 |: x
} vertex_t; * M; A7 Q/ \& K: K% g
% p* m& f, [8 p' }. p
) `. J% e1 }: b( f 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
0 r# V+ l4 S# M( e7 B% V
$ P' w5 w% {3 P7 f* v5 c6 e. x" ]以下是引用片段:
5 O+ n; e/ J; ^' U- r /* Vertex list structure – polygon */ - P* ]$ M. U' T- r
typedef struct
- d. Z0 K7 R: q& Z+ K7 v' k {
6 a/ g1 E1 `+ e# A+ k' u" f# c. z int num_vertices; /* Number of vertices in list */
+ x7 G+ A2 R/ W+ v+ v1 Y5 W vertex_t *vertex; /* Vertex array pointer */
. k$ X/ b5 x7 |9 i, ~" m4 h } vertexlist_t;
) W) K* N8 M' Z: {3 v3 e
6 H4 I3 { h+ `: j9 ?( O
) i, k, A/ ~5 G3 E8 v 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:* ~! ?; {, x" |) j+ p" }
! N# P9 j3 a% V
以下是引用片段:6 [7 ^; H/ C+ G) M8 ^9 S4 `
/* bounding rectangle type */
6 z9 h4 B8 I, s3 B: ^# X typedef struct
# k0 Z+ v$ J, H" e" P { ; J: T8 u G9 B5 D8 x# t
double min_x, min_y, max_x, max_y;
! I( _0 |- W# P3 A2 a( Q } rect_t;
3 t: A0 X% k. L. M, p& x% X /* gets extent of vertices */ 4 t/ r; w0 H/ }' p9 v7 Y+ X
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ ( `7 ?" c, i* ]" B! l1 G, X& M" [
rect_t* rc /* out extent*/ )
5 l; [! A) a6 [5 l: h { 1 c3 L. I, x) J* Z$ u3 [% b
int i; ! {9 U" Q* K! Y c0 `! E2 X
if (np > 0){
/ |3 I/ K5 V+ ~! o1 R2 w7 S2 b* _- h% C rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
6 g; C; ]5 Z8 A/ J' k6 s }else{
: t. W+ n+ t$ t- l/ E1 z5 w9 m rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
" N R5 @* q/ {. _ } ( ~. ]8 Y6 n1 a2 I. \
for(i=1; i
2 ~% l% w5 w8 h, n/ \- `/ G {
, q$ j0 L. _8 R" y! D) L' W# @ if(vl.x < rc->min_x) rc->min_x = vl.x; / N2 H1 Y7 W( v+ ^* X4 i
if(vl.y < rc->min_y) rc->min_y = vl.y; ; Q4 k' V8 o+ \0 H! j' N. T
if(vl.x > rc->max_x) rc->max_x = vl.x;
2 g2 Z- J) Y. S; w if(vl.y > rc->max_y) rc->max_y = vl.y;
1 t/ x# P& k4 s& M }
4 `' ?# N3 j- t- F7 ]" b/ ` } * F! Y. s- C- [) t: ^9 i
) W# w+ P2 S( l( j1 ?- l7 u b1 J% [/ {$ h# X! l8 {3 p$ U
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
$ p8 l, m9 F7 l
" ]( _5 X2 w9 r+ R0 A* t' X 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:5 H8 f G) J/ h
9 _" F+ H- c6 l+ x0 U (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
. V8 p7 G3 V3 C0 o4 m; u7 J: f2 R( j
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
% F- X6 V/ Q2 z% q7 j9 v0 t2 l
; D! ^- Z$ ~$ \0 T. u2 Q9 o- A以下是引用片段:
/ k9 c* u$ m- h1 t, s /* p, q is on the same of line l */
- M4 X/ ^+ [: H6 X/ g% o, i0 N$ G0 H static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
+ w2 f) H- ]4 ^" q const vertex_t* p,
7 B0 K2 }, H: H! d" X; P const vertex_t* q)
' c, f; @$ }: t0 f4 _* R { 4 e1 K3 H/ s5 A. T/ G. F+ d
double dx = l_end->x - l_start->x;
{" b$ ?7 C; k' B9 O+ K double dy = l_end->y - l_start->y; 5 J& d. d' b: ^7 p* [2 s0 c, ?3 d. E
double dx1= p->x - l_start->x;
/ B5 P6 V# e* {. N double dy1= p->y - l_start->y;
" C3 i% Y$ {/ Y# E, D double dx2= q->x - l_end->x; 8 }- O& { L! B4 l. U9 s8 h9 G
double dy2= q->y - l_end->y;
7 d8 I' f1 T$ ~7 d# k2 g7 O: N4 H return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
+ Z4 ?, l( | j1 Z }
8 s$ H$ J1 K7 E9 u2 H /* 2 line segments (s1, s2) are intersect? */ * V r, m6 i. M8 y: q$ G3 n( p
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
4 U$ G1 _( n. C3 C3 M. @) k$ s const vertex_t* s2_start, const vertex_t* s2_end)
! F) N4 U+ p$ A' P7 i { 7 ^3 E, r1 n4 \( ^ @/ F, @
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && o, {1 B* G$ W! O. u; K7 S/ `# ]
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
' J8 S# t9 O- g1 r }
; ^1 S1 W$ F6 |: G0 `/ r
+ b, v& n. N) m9 I# b; A
+ E' F# s2 Q Y8 i5 ?; K/ T 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
2 l% i R! ]* u* S5 J4 i
7 k( p% E& ]" r4 B2 |/ X以下是引用片段:9 c9 Z' `: @5 F# G2 r
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ ; B2 Z1 h. |( \; U: Y' W: e
const vertex_t* v)
- J, y! ]- d. T1 R/ O- L1 C { + d3 w6 V O2 |8 a8 m/ X
int i, j, k1, k2, c; 1 p2 N/ q: g& v, C
rect_t rc;
9 ?; j9 `! H9 Q, X vertex_t w;
% h' Z: w. z) B5 v if (np < 3) ; ]0 k2 x# i' B: B- B
return 0;
& S+ ]# e6 f( d+ \' r v vertices_get_extent(vl, np, &rc);
3 v5 T; d: `* J3 L6 f: g5 ~ if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) . T8 ]7 g% l9 [, C
return 0;
5 A( m# M( C* e: h& H; b8 U /* Set a horizontal beam l(*v, w) from v to the ultra right */
8 Q6 b1 h0 ^+ Y4 j7 {% ` w.x = rc.max_x + DBL_EPSILON;
& ]4 \" C/ M! [- m w.y = v->y; C* q6 h) \6 b6 L* f( L" r& o2 X
c = 0; /* Intersection points counter */ ; @" [ a+ d9 p( ^1 P$ n o
for(i=0; i 5 {. h' L3 }% w2 Q2 ~& Z' O( @0 r" j( \
{
; J; w: h0 N& K$ Z) H7 T5 ^ j = (i+1) % np; ( l8 j+ ^7 P V- F( x
if(is_intersect(vl+i, vl+j, v, &w))
% S& @0 ?8 q/ k2 E* P/ \8 K& j { + A& A" B2 S# ]
C++; , z! M' V% ~& F/ x
} 1 m% j7 M' l3 d+ [
else if(vl.y==w.y) , p- {/ v# l+ V1 b# h
{ / f J* N+ ?0 X
k1 = (np+i-1)%np; , f( `. \+ {" t, ]" f
while(k1!=i && vl[k1].y==w.y) # y8 M; J9 M0 U, V" r
k1 = (np+k1-1)%np;
# a# `( } I( W. f# D/ j# }) i1 W2 | k2 = (i+1)%np; 4 s6 f( n9 j8 d" K, c6 H% z
while(k2!=i && vl[k2].y==w.y) 4 H: f9 e; V% t1 |3 f. |
k2 = (k2+1)%np;
! G: \0 H9 t4 j9 b! Z- \1 N if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) 2 |9 k: Q ~: T- O
C++; " w3 L! U V; ]; m4 \& }
if(k2 <= i)
9 |) q- j! J. n7 C5 E S% h break; 6 G, W2 A/ B7 Q/ R A" \+ x- i
i = k2;
4 @1 G1 K8 y; q7 j3 L: u6 }: t } " Y/ T, W6 t% m, n9 ^- T" B9 u
}
8 |; t# ]1 w& O7 F" y* e return c%2; t8 N3 ]9 Q) N" R H
}
4 }( T3 m O. k6 R1 M4 J
5 f1 Z% O5 C, E' E2 H3 Z5 A" s) v. L, v
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|