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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。9 G, m; Q& Y1 I# y1 e
6 y) v2 N0 p: ?. _: S2 h 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。( e T5 L( x6 v" ]: [
: A& ~; a% q% e2 z: w 首先定义点结构如下:
; r# q% o+ s4 j# C, D' }3 Y" T0 ^; Z* Q/ O
以下是引用片段:
8 H5 K/ L. X2 W /* Vertex structure */
& c+ r S* f' e% R/ z' r1 F typedef struct
1 Y2 P5 M' ?) w, ^- {) Y" K# [2 w {
$ _8 |5 ^0 `; g/ G- Y8 V double x, y; * t. {5 j" w7 h6 h% ?
} vertex_t; 1 P' k8 `8 B! H' z$ R U
6 d6 B+ D( ^0 X( m
' n0 {7 ]/ [8 y6 Z, | 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:4 j8 a/ _; q0 Z. M; f- E$ ^; v% D
% r3 @( E8 |$ w
以下是引用片段:% P: Z' }0 O6 }" q4 P
/* Vertex list structure – polygon */ $ ?- g$ t6 D: r" h1 U
typedef struct
r2 n; U: d+ d, o3 x0 \ { * @) E& N- A/ g/ {$ k, g
int num_vertices; /* Number of vertices in list */
! g' D3 Y8 i4 I5 r vertex_t *vertex; /* Vertex array pointer */
: p) a2 r! u8 K) h6 N" y+ l$ C; a: { } vertexlist_t; 6 ^6 h M( d) r! D4 s
0 l+ D5 ]" J) @) O
, Q; o3 M$ s, s+ G 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
$ d% F% N6 U2 ]6 k9 T9 n- q) Z: Y5 h0 D& z# h
以下是引用片段:
* [5 r% e8 Y. U- Q0 z /* bounding rectangle type */ 5 g/ {+ S0 `6 n5 r
typedef struct # W* k4 W, j+ w2 h
{ ^ m% S1 H! ~9 w6 @/ r
double min_x, min_y, max_x, max_y;
% H1 h/ M% L1 \) t# @1 y: |3 h } rect_t; Y6 X$ n7 t0 Y5 W' ]
/* gets extent of vertices */ & n" z! V! a! j: Y
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ ) U: {# r- T; X" n& X: s% \$ G
rect_t* rc /* out extent*/ )
, ^) V/ t2 _) H% r3 Q a { }+ D+ @6 G- @6 r# t
int i;
+ A: `, E. [" x2 t% E T if (np > 0){ * V) w. \& A' q" R+ I2 C7 F
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
! w: Z2 e( S6 R/ H8 ~ }else{
; T0 J! e3 W, e+ I; v5 j rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ 7 R$ }/ n! h4 X+ `; S J
}
6 [% k3 n9 m6 g% I% ]: H- Q for(i=1; i ) R) z1 F4 b8 d) t t4 i
{ % f" a) b% M( H( m
if(vl.x < rc->min_x) rc->min_x = vl.x; 7 _* Z' Q" U3 A0 `
if(vl.y < rc->min_y) rc->min_y = vl.y; 7 P7 ], w- X- P0 v( v* n9 v
if(vl.x > rc->max_x) rc->max_x = vl.x; ]/ ~+ h3 I, h7 t/ @% A9 U
if(vl.y > rc->max_y) rc->max_y = vl.y; 6 E" R; L/ c, ]2 O
} $ ~4 j# n4 b, R7 A& ^- G+ H
} ; r9 P* `) p" u+ X* `) E& Q
7 ]% n6 A ~# S
`+ s6 v4 ~ l. |- e1 } 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。, f( X# i5 p" x" f6 G( d$ `
: C/ }+ A; Q- [8 H" | 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
* u! y: V7 i* R. F& L# j* {/ v, Q0 j% f
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;8 u( ]3 k: j/ e* m; \3 f
( O8 x' ?! y$ n! i8 T
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;* E3 t" i; M5 h- X9 z
7 A/ H! Y1 S4 x: f以下是引用片段:
, Q& d5 Q, w. J r! I /* p, q is on the same of line l */ ) i& Q% K! o- \# I6 u; ~2 A
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 2 |# ]% C, y: m0 U0 ~5 w' {
const vertex_t* p, # F; E# i1 j: V+ `, t# v: ^- G* i
const vertex_t* q)
0 U* q. o0 ]( G3 F; C! q {
1 ^+ @, B* A1 j% V7 J2 | double dx = l_end->x - l_start->x;
# P! H- |, O$ ^" N double dy = l_end->y - l_start->y;
0 W9 m" \" ~+ v9 L. e+ H double dx1= p->x - l_start->x;
& W \$ |0 G4 Z$ [; \! U7 k double dy1= p->y - l_start->y; - {" C7 c' x- D: M) y
double dx2= q->x - l_end->x; 9 y( [/ [* c: m5 ~9 A
double dy2= q->y - l_end->y; , R, Z, F5 W& p1 Q1 K2 k
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); 1 K: _5 _; p4 D( Y" n
} 5 ~7 a/ u3 H2 Q1 E6 J
/* 2 line segments (s1, s2) are intersect? */
1 H% C/ t# l4 a2 |' n! X static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
+ w; F2 q1 W, p& U3 u1 B const vertex_t* s2_start, const vertex_t* s2_end)
( ~) ]$ ]+ j$ x9 q {
/ {; L8 X$ i( U3 T return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && " o3 W( E+ {8 \" H! u ?
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; $ r& Q+ [- n" W& ~ W+ \
} / C) Q9 D6 y6 ^ v2 V( V3 p! K2 I
' d. J8 @7 a" L1 g# U# c' y; _+ d4 S
8 V5 U | S* I6 J1 S* }7 t
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
5 u1 G' O; K& B
4 P" k+ Z, {% [ ?/ s* X1 J以下是引用片段:+ d k" c. ~3 |: @
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 8 h- x7 h2 l$ n+ l( t
const vertex_t* v)
( a* I; }' f3 H% W6 y; } { . ~* w( ]0 `8 R0 f4 Q* V/ Y; N# e
int i, j, k1, k2, c; 7 e6 H( k" }: ^: B g( H& D
rect_t rc;
: ]% Z* r4 p& ?0 b# B' h7 F, E vertex_t w;
' S3 i- i5 N1 ]/ B. F- q if (np < 3) 9 h9 e2 w( @+ l* O! {
return 0; 2 r9 E9 B& d- [/ v
vertices_get_extent(vl, np, &rc);
" {6 g8 h, B+ J* z5 N1 ]: ~ if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) & _+ F4 b+ G2 c1 ~3 K! k5 d
return 0; + v# W# I8 |1 O' N0 l
/* Set a horizontal beam l(*v, w) from v to the ultra right */
# [) O' Q2 `# m5 @ w.x = rc.max_x + DBL_EPSILON;
z3 l) d5 O' B6 v: }5 m* w w.y = v->y;
' |9 K' g- c, O' |# F: O& G" P c = 0; /* Intersection points counter */ ) _1 c4 i( _3 H: H& Y h7 t
for(i=0; i
, ~6 E2 q1 U/ m9 w Y { 9 F* K: X' g3 c1 B. p7 I
j = (i+1) % np;
+ x: e; B9 a3 _! h5 z% y2 K if(is_intersect(vl+i, vl+j, v, &w))
7 h6 p; r* }+ J { 4 k, O2 k4 w8 _/ T3 E( d# V- B
C++; 3 a& h/ r) u1 k/ _
}
! g2 J2 x! C: J. I1 r else if(vl.y==w.y) . m+ @5 G+ ~3 I
{
( ^4 U% t _' O! G* p) A k1 = (np+i-1)%np;
) h! d. S# x. c" w6 ^ while(k1!=i && vl[k1].y==w.y)
$ I/ @. G1 i' Q( \/ \ k1 = (np+k1-1)%np;
$ V% u h2 A$ [& z0 `4 q/ X k2 = (i+1)%np; # r' ]3 b' }9 m; {. e
while(k2!=i && vl[k2].y==w.y)
# }9 J- y5 [7 |2 Q5 O" U! V k2 = (k2+1)%np; ( e; M5 ?0 w1 g: \0 s6 W O/ V
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
t( u) p, I* \$ t; f7 q- `' @ C++;
. S8 D( Q0 j# q0 I; T if(k2 <= i) , o$ }0 }* }1 g: X4 P
break;
- k- \/ Q0 S7 ~3 v% N i = k2; / V5 [. q5 R. |, u7 F0 y) ]1 E- C
}
" E% a2 Z3 M( B2 i2 z, V4 s } # }& T' k% `1 x5 U# g+ B
return c%2; ( Y8 D; X, q Q
}
5 D+ u8 p; ?5 n0 E
3 D) s; e N. b( Z# D. B; t6 S2 g' j' x: s4 f
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|