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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。. j: C, }0 t3 J3 m) B% x) x
* _' N$ \; [5 p0 [# ?" q6 T: n
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。, J: C4 D- f. L
' ? S- q1 _! u) {; h7 p8 x 首先定义点结构如下:
- ~& x G4 i4 S |, c; F0 g! L( b" R1 M; G$ F
以下是引用片段:
9 H. A# A1 S+ e$ i /* Vertex structure */ . j" J4 x) D' z9 a7 l
typedef struct
9 |& y. ~8 L+ S, j1 h {
4 F1 W: ^, g" v% Z double x, y;
- T) z, i9 Q3 @ } vertex_t; 3 ^0 H! ] g! z3 @- u7 [$ \
+ t& k6 }! l: a2 K; k
$ r7 r9 @/ j6 V- | 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
6 @, ^9 D. |- t, v* l3 S# K
' c5 [' r& P' _& D# u以下是引用片段:
& J+ }) n3 A2 c% f0 y9 p: k7 v* ]1 X /* Vertex list structure – polygon */
! s9 v! K/ k5 k: y7 j7 q typedef struct
' I8 y+ |+ k; G e {
[" N9 ^+ Z) O6 @5 n! C+ e& M int num_vertices; /* Number of vertices in list */
$ V0 M. n5 L# t9 A' r vertex_t *vertex; /* Vertex array pointer */
. ~% ^4 e. t$ m9 g } vertexlist_t; & ?+ F& C: C* y) F, l" `: u7 B! t
# A, `9 V$ V" o+ P% z2 N* y+ C
% `! I% Y0 Q3 O5 m9 r( a1 j U e
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
8 V. F$ _8 H0 ]1 h% U9 ?& f! B Y- e9 P4 Q
以下是引用片段:
, B, H& h# O* I# ` /* bounding rectangle type */ & ]% z ~9 ?# r* u- W8 L
typedef struct : r9 X! V+ \+ u, \7 S1 w
{ 6 e1 F+ J' ?+ H; z; s
double min_x, min_y, max_x, max_y; % w3 v% p9 P7 E+ e! k
} rect_t;
$ Z& C0 c7 h& e7 m /* gets extent of vertices */
0 V/ g' }- }, P) c8 y9 N void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
- C' }/ @( q+ N# |' n rect_t* rc /* out extent*/ ) / y4 v" [; O+ d, W- Q
{
( D; q2 ]$ A" g& W2 t: ? int i;
0 w/ \; t8 D" c& R/ ] if (np > 0){
) Q% N' J; C$ h5 h$ S+ A: \/ {/ D4 k rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 0 |5 ]' ^ ?- H* f) Q
}else{
5 M5 K6 H- ^* Z! u rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
8 l) I3 F9 e7 ~7 c } " q7 ^- p' W& K. e' q
for(i=1; i
6 `4 U* T7 a! G0 L' z# l- { { 1 h; a: |4 z9 C
if(vl.x < rc->min_x) rc->min_x = vl.x;
2 ]# O% f, j3 K if(vl.y < rc->min_y) rc->min_y = vl.y; # u8 B% @. N0 q! |, Z
if(vl.x > rc->max_x) rc->max_x = vl.x;
+ ?# G; e. e! G/ F. ~7 T if(vl.y > rc->max_y) rc->max_y = vl.y; r3 B- _" y$ T$ @2 f0 p% B* F
} 8 J: E' J5 I9 S- {/ N1 j
}
, X; Z- {$ x' H+ E% E: O& X2 S6 V* b0 M0 Y9 `2 s, m
$ T2 x: e5 k5 u
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
3 v0 f* U" W. ^' U* Q8 I
" ~8 q1 N( M) Y: s: C 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
: n2 x; k# K& {
8 K _) c4 U r' o& g, [ (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
6 h4 z0 }! P; R& x3 F
& W$ y, ?1 O+ p$ }6 I; B (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
* }$ g5 m% s% k2 d' \) i( q
1 y7 l; }- ~/ \ N7 C以下是引用片段:1 P' Q6 p) _$ f7 d( L0 H1 f
/* p, q is on the same of line l */ # n) u6 h% P7 p
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
! ?% g7 A9 v4 J( P/ w% i const vertex_t* p,
4 H! j ]2 o, i' G, r+ q4 D! ]6 } const vertex_t* q) 9 b- _, h7 s1 m9 E$ K7 A
{ & {! m# I6 G; X: R
double dx = l_end->x - l_start->x;
5 t6 r e# q/ b4 q. o5 m8 ^ double dy = l_end->y - l_start->y;
# }& [0 ~6 [3 M' Q" ^" A double dx1= p->x - l_start->x;
+ ^0 u+ @( @: Y- j$ _ double dy1= p->y - l_start->y; / O/ i4 w. v X' b5 W; N9 W5 Y( _! d9 b2 ~
double dx2= q->x - l_end->x; : m4 M- @' P0 ?- w8 M) w9 H. |% ^
double dy2= q->y - l_end->y;
7 w# L8 z; X+ q5 o return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); ( n, E6 R: h' o& y/ B' q/ t
}
2 C* ^5 J, |+ g /* 2 line segments (s1, s2) are intersect? */ : C- g) E T$ F! ?7 C n. B& V/ d
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, * M0 M' r) l( Y( T/ O7 C
const vertex_t* s2_start, const vertex_t* s2_end) 6 |9 @3 p( C! {3 J
{
( F! Y( R8 E5 K+ b3 ^ return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
7 A. O8 s- T' G% n is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
" [4 C8 c: k/ r2 I }
$ U- n' w ]( y5 l2 A2 N. t$ W
. f' ^- O1 n# | L! v, { g" [
9 M" L/ i) u/ H; @7 ?! A 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
6 A5 Z7 W H5 q. c! P) n& j2 K
- v @: P1 l8 j, ?8 G/ O. u: e: ]: b以下是引用片段:
" [5 w4 w5 e( {5 n; ?& k( n; D int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
5 S* l, `$ Z2 W( i8 u const vertex_t* v)
' y; C- F9 |% \6 `6 T { $ o- W. [! h& D) x+ {0 N, S4 c
int i, j, k1, k2, c; & W4 a% w P: @# f9 o" u8 F! \# J8 P
rect_t rc;
7 F% j1 B' M' g! I- N! h% @ m' ` vertex_t w;
! [ J" x/ j) y5 t+ [ if (np < 3) ( s k' Q8 e8 y9 [3 ?( V9 ]
return 0;
0 V* L T+ `) }1 A/ u vertices_get_extent(vl, np, &rc); 2 F4 i8 u# Z- i- C9 ^
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
0 l! @( Z) d1 q, s9 |1 i return 0; ! M: d+ e/ U( V( n; L
/* Set a horizontal beam l(*v, w) from v to the ultra right */ % z# H0 P) W$ P
w.x = rc.max_x + DBL_EPSILON; + _3 g: `( P* F- a. j
w.y = v->y; 5 c" M3 h' {2 u$ D N9 {
c = 0; /* Intersection points counter */ ' R- @/ l+ R' v9 O4 m
for(i=0; i C: z7 |9 a+ b9 I3 I5 r
{ 9 Y0 R" G d3 X
j = (i+1) % np; ( G2 M3 g9 W2 L: F
if(is_intersect(vl+i, vl+j, v, &w)) : t8 U- k# z' g
{ , O# \' h6 M1 M. c
C++; . k* P; N" [$ s5 G5 B: r
} - I5 C5 [1 |: q0 t3 p% |0 L
else if(vl.y==w.y) # t! H3 s0 A: a3 d
{
8 L9 T7 w; b0 h1 _# m k1 = (np+i-1)%np;
2 X6 ^" @4 b. S( a while(k1!=i && vl[k1].y==w.y)
& E$ |9 r+ z! r5 y7 p8 U3 ? k1 = (np+k1-1)%np;
! K/ ^8 I* U4 z5 }9 U0 E6 S k2 = (i+1)%np; & E) @0 i& J. h8 a8 U e
while(k2!=i && vl[k2].y==w.y)
$ P! x; D1 T6 K0 N" s k2 = (k2+1)%np;
6 a* f! p- ?1 q" Q if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
- ^& A A# n- h0 w# e9 I: ]% s C++; . O6 [0 r+ x" A
if(k2 <= i)
, r( }3 ~5 p& N9 s# q' w break;
6 v) y) V3 b1 h; {( u1 q i = k2;
& z) m0 f# c4 `, L. i } ; ~. d& |- p8 r. K, o
}
% ] G G" x+ _ return c%2;
+ \ B+ o7 c6 m- y$ {9 M# a" g } 8 B( Q8 o! f' M; b1 F; I
. e9 g. N2 V2 }8 Q
0 g: c# E* D" v, ^+ \ 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|