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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。) a P+ n# c2 ]7 e/ i
( K* N- m* f' q* w2 X" Q! | 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。! G, g- ~$ Y, A7 E* q
2 K* [/ Q1 p2 d, _ 首先定义点结构如下:
m: z( t6 ~: l/ U) J4 \/ i
( F5 B3 h0 z/ C+ M: {以下是引用片段:
$ e8 n: s4 p5 Y /* Vertex structure */ 0 P' X% M' q/ O# N: s
typedef struct
$ W3 a4 i: n# J { 2 J6 c4 H! { l# n/ C F% d9 y
double x, y; * d: n: B: B( y$ P- g- z
} vertex_t; 7 ?. K' @/ y" P. ^$ C J ?
* H, J( ~5 i9 L& ^- A1 d+ H, T
( C& |& P' h# M: @) x, a2 M 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下: a2 k1 P, q v4 I. B
9 H D6 Z: m" ^; @% s- ~0 C以下是引用片段:6 A8 E" T9 P- @( M
/* Vertex list structure – polygon */ ) ~( _# n4 V% ~1 Q1 l
typedef struct % k' k6 Y# T$ _; n4 B& s3 V" b
{
- z' }/ w8 S$ ^. K- m/ z' @( m int num_vertices; /* Number of vertices in list */
6 v% N- ]2 Z# g vertex_t *vertex; /* Vertex array pointer */
! G' ]6 t: ~1 ~5 G } vertexlist_t; / w0 h4 \ J9 ^0 ]4 \" d
1 z7 W* N( \# ^! U' J, w3 ^3 N0 ~) l" F) U( R- v3 U# B v
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
! j4 i; d8 ^5 p/ o
6 F) R/ \( l8 @5 G以下是引用片段:
# m2 g0 ~6 I" Z5 C /* bounding rectangle type */
& f; C& x- Y) N/ c* A typedef struct : K" W# F, @5 W& a
{ 6 [: e2 p) p7 c4 G) ?; ?4 \: R
double min_x, min_y, max_x, max_y; : D; y* O4 _6 I9 I
} rect_t;
8 |0 Q x) O4 T' G# p /* gets extent of vertices */
% q& U; u; y5 A3 q3 a# F void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 9 ~6 {* N0 |( y- q" ^( z
rect_t* rc /* out extent*/ )
/ j6 K$ F( g1 U, | {
3 ~2 P2 p( S5 p( C7 Z& k9 X int i;
% b/ e4 B0 l) B' h# U if (np > 0){
3 g% B/ K! R: c. w9 j& g' P rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 9 V& b, _( I; S3 r6 P7 {7 C& t/ [; {
}else{ 0 m; \- L; w$ |, |' ?
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
& P6 i( Y$ r! B# @8 N! r' X" d5 E }
* r7 ~ g d+ O/ l" P8 k5 T, x/ R: Y for(i=1; i 3 k* D+ p* R- }- _
{
+ C' x5 ]7 v1 V! Q5 f5 ]* i if(vl.x < rc->min_x) rc->min_x = vl.x;
6 b/ ^0 X! T8 t+ Z2 |) T6 I if(vl.y < rc->min_y) rc->min_y = vl.y; 3 M& J0 t4 v6 @1 u' N/ d# X
if(vl.x > rc->max_x) rc->max_x = vl.x;
* [( Q% W, G0 W( C, e0 a+ F: {0 S/ O if(vl.y > rc->max_y) rc->max_y = vl.y; 9 \8 h$ Z) z; h; b
}
* W9 D/ c2 ^" @7 J8 V- ~' H9 s }
& B- V4 R& f' e3 }' T0 `# _9 l5 p" [$ k
( z. V5 b, d, o( b% u 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
5 G1 K# c2 h/ h: x) E& w
0 n1 v4 W" |4 U' g& T 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:+ o2 K$ [$ h3 {
* K |: B, L. h Y+ B- k
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;; [. l( ` ^4 m( W# n# A2 d/ L# R7 I
0 T1 L8 e2 N; n0 ~8 I (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
0 g6 ^' b* R9 W, T W9 A
7 U- F* I1 M( l* s5 Q3 G- [以下是引用片段:
% T, n2 V# |* U' r8 O /* p, q is on the same of line l */ % k& S$ H; E: I4 p; i' F) t {
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
F' S: L6 g% @! m: }7 a const vertex_t* p,
! `" p; B% Z( C/ p: Q( p4 u4 B const vertex_t* q)
' w# h' D* F! {( x" K, M {
4 z1 G" ?8 k9 N0 r l double dx = l_end->x - l_start->x; & g H' @8 ?9 B' f. d7 U+ x2 }
double dy = l_end->y - l_start->y; - u0 k) Q) C( g& k, a
double dx1= p->x - l_start->x; / o7 r7 z/ s1 d/ i
double dy1= p->y - l_start->y; 1 M- D; a0 b( H% S1 y0 \$ c0 n
double dx2= q->x - l_end->x; - I, K4 G+ w# G; }2 o; S% ]( _4 B
double dy2= q->y - l_end->y;
2 `3 G/ ~# f8 H S; P# F3 n, x" I1 r return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); - l. i$ l+ V5 M$ U% g
} ( t6 _/ P9 n) d' d: r
/* 2 line segments (s1, s2) are intersect? */ 2 L) q& Z$ W) U4 a( D
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, " K8 z0 L: c2 Z0 Q& U2 n
const vertex_t* s2_start, const vertex_t* s2_end)
7 N5 R/ f) M5 o( x ~4 D' q3 U6 }% { {
2 V* `$ b3 e# T) {( _ return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 0 T" G U6 p+ H _! t/ k
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
- y9 D! G. V; p+ T* c }
' h& A( c1 f- W P: d/ B7 x: x& a6 q# x, Y% R; \8 R
! k. g! e3 q4 t3 J. u 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
+ a1 o& x* K# M" g; O
6 K4 O% w6 Y# l1 g以下是引用片段:! v) d, P, v+ [3 ]
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
* I8 x, Q! Y1 w( F/ K const vertex_t* v) ; c# V1 Z) b9 E; u
{ % @ w9 O& ]5 r# p7 o# ~3 B
int i, j, k1, k2, c; 2 v: P, Z3 G% I( e' {
rect_t rc; 2 y: }& U& [ h: M. a" o
vertex_t w;
5 V { y& d4 T9 s" P if (np < 3)
. G0 X0 K6 q% ?* H return 0; 7 \! [! U4 u6 G) j2 g! z4 S2 O8 e
vertices_get_extent(vl, np, &rc);
* t c" R U# T7 r/ `2 O if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) 7 X% l. b$ v2 a
return 0;
$ b6 j% q a( F6 t+ q /* Set a horizontal beam l(*v, w) from v to the ultra right */
7 b. {7 X5 T7 v" N1 J- A, [ w.x = rc.max_x + DBL_EPSILON;
7 S8 {( A$ h! F w.y = v->y;
# |& \' a) q+ u% \3 b! C/ i4 I c = 0; /* Intersection points counter */
& e5 v7 ]5 g a, K6 `/ q for(i=0; i
8 @3 L% Y# h; T" P { 0 W2 O8 X- C: R7 U
j = (i+1) % np;
. L( E1 S( d% f if(is_intersect(vl+i, vl+j, v, &w)) & ~. w1 U; m+ c8 l! M
{ 8 x, R0 q) a: C( T* @$ E
C++;
' G+ u5 Y6 B% P* M! G$ K }
! ?( d! ^6 T* g else if(vl.y==w.y)
! c* c! \7 [; [! q" _) U {
1 ?4 V% @, f K7 s k1 = (np+i-1)%np;
- y0 W0 d/ P6 ?' x! m% ?& k- I8 i while(k1!=i && vl[k1].y==w.y) " ~3 W# H, ~' d; ^, X# h- \4 ]
k1 = (np+k1-1)%np; 5 N! V! a* c1 x2 _4 N2 L' l+ z+ R8 w
k2 = (i+1)%np;
: }; Q/ g: q- G0 j$ _5 v4 ?6 r$ G while(k2!=i && vl[k2].y==w.y)
' q& P5 n: C P) v* ^ k2 = (k2+1)%np;
% U T. F' F! W) p if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
% S, f V- V6 ~# v C++; 4 \$ z. }2 P# T" {
if(k2 <= i)
* L6 X& p# _! b6 F R" O9 q P break;
I4 b7 Z- w; ] i = k2; - x% H0 O7 a4 {5 B; `* e6 X
} K* r; t4 H0 z: J9 ^, j( R
} h' O8 b; T2 P% K
return c%2; |/ R7 N! a6 x5 \* ?4 N E
} , T6 n( V- H" |/ b$ c+ O% d
0 C% x1 B: v n' Z' E: A
: R$ v4 {. c( S2 v" T 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|