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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。 M3 l8 y3 G5 E/ W" S( P/ r' ]' o
' t" D" V5 u. N1 T; `' N
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。* |. N' N7 z4 U9 V/ J
& q J' U) l% o& Q0 N0 t
首先定义点结构如下:; Y# L7 K8 c9 b# ~ ^& c
9 W1 T9 z7 A" j! K* f
以下是引用片段:- O) m( G8 e( z6 j" n/ v. F* F
/* Vertex structure */
6 h; j3 S. b4 d' n0 Q( X typedef struct
1 G" C: x' ?& q P* x$ m {
, Y# F: K, k& b1 ~ double x, y; " N4 [8 v% |$ f' w1 u8 _3 h
} vertex_t; ' @* K7 \( ]9 o% h* H
1 @# p9 K+ i$ i
" P. u1 q5 P( k1 _- @ 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:! r/ m4 `) l; B
+ i& e: P$ X8 X. N! I
以下是引用片段:
" K$ K X! V( l+ ^* Z9 N /* Vertex list structure – polygon */
% A; E4 s& C2 B$ @7 u; M typedef struct w+ @7 ]2 \" d2 H# f: i6 X' G3 x
{
2 f; ` w5 Q9 N/ s0 ?7 a, y int num_vertices; /* Number of vertices in list */
' W" t/ y: Z3 P7 H* k, r- u vertex_t *vertex; /* Vertex array pointer */ & |$ i9 O3 c8 a% e- K* b
} vertexlist_t;
; }0 X6 b0 @# ?! T3 x$ f" L: F! d0 U9 o# g0 q8 u! l
1 h1 g1 w) v/ E% E4 z+ Q
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:( i2 t0 ?+ F# o% Q
# K* c3 ]0 U$ Q0 u7 O. @
以下是引用片段:+ D( m' k& O0 Q7 l, N
/* bounding rectangle type */
. V# E d. v7 w0 r o8 T typedef struct
: [8 p% h, ?- L$ `4 \4 Y3 I { . w2 n6 j# Z+ y8 h6 l4 U
double min_x, min_y, max_x, max_y;
8 _% }! [0 @) F9 T } rect_t; / ~0 a9 |* S# _" d' T3 i# M: M; h
/* gets extent of vertices */ 5 T3 V$ b$ O- A0 C% t1 J
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 7 N1 q" L& `# S5 C! V# A
rect_t* rc /* out extent*/ )
" ^1 b4 k( C- }% l4 C: z { 1 J- T8 L9 L+ o9 M
int i; . \! S8 Z! J; `$ p8 R
if (np > 0){
* @( ^6 n# C& q/ ]5 t6 B rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
) T \- C# A, x# f. e }else{ 1 K( A& O8 K+ G5 S' A
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
- k. G8 F, @* S8 ^ }
# ]0 e8 s- Y: u. P for(i=1; i
( [( b+ T( H" l2 v3 w, B {
M/ s& O# [! d if(vl.x < rc->min_x) rc->min_x = vl.x; ) P& X+ K, Y% Q$ L, K( L; F
if(vl.y < rc->min_y) rc->min_y = vl.y;
$ L }7 E4 Y5 j if(vl.x > rc->max_x) rc->max_x = vl.x; " d# {& A4 u" d9 n9 O
if(vl.y > rc->max_y) rc->max_y = vl.y;
6 J7 z3 _5 ]" ?3 n6 w0 l } 4 { h0 ^- P7 z
} 5 i5 J* C7 l! `3 T
4 S) }- T( G# Q% |
4 B3 x. D4 B2 r, w& W; F3 h- A* i0 A3 ? 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。. s% D4 z9 f" V5 l* i) l
' l5 V B) Z) d B4 s4 ~1 }& W: q
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
3 U* ^( s4 x$ j
) n% Q( e) s$ P( D) X: N (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;, g. C& Y: e* J) n4 }$ v
6 `+ |3 M; ?- R9 s: d' }7 h) x
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;; m" n/ `; o! F6 z9 e$ [7 |: X+ y
+ a( t7 z1 N: k7 I+ ~
以下是引用片段:
2 m. q y) q, a3 N: | /* p, q is on the same of line l */
$ y& [0 ~4 P) K2 g0 T6 d static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ # g9 e/ c4 B3 {5 l
const vertex_t* p,
+ r$ E- T; J* V7 S3 c4 @( U const vertex_t* q)
4 Z: D; B2 w. s, x1 L { . B4 Q% {* q) {7 \# P
double dx = l_end->x - l_start->x;
* b: c& N1 a" _4 F( [! I double dy = l_end->y - l_start->y;
4 @) u) I. V6 e1 r9 F4 N double dx1= p->x - l_start->x; 8 ?% F3 s$ Z; F+ V% K
double dy1= p->y - l_start->y;
7 g9 s4 x4 U: K7 E. {/ h" d3 r* M double dx2= q->x - l_end->x;
" G3 u9 q, b3 H) J% d, H double dy2= q->y - l_end->y; 4 c* x" {4 y# s8 E: s/ v
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); 8 C" z; r% V/ S+ t
} " w$ y+ |0 k, r4 Q* G9 J6 W
/* 2 line segments (s1, s2) are intersect? */ 8 [& f2 x* S9 M( b) W5 r
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
0 Q: x2 u' V! |1 @( i const vertex_t* s2_start, const vertex_t* s2_end)
* ~1 X9 w4 b/ ^, U, J {
% |. z# e$ C3 q" R/ m) j return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 0 o6 `) ~2 i- l1 V. z
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
1 K: s: c! t$ j& K! b+ i" ` }
8 y% n; `/ W" _" P* r4 K
- V7 I9 K3 k# \$ [4 Z3 K4 \# ~5 B4 t/ l8 m# b
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:8 C9 f; e4 q# ?% E; ?1 @& L+ c
1 q* y6 W1 N/ }以下是引用片段:
: A# V% O, ^7 ~, W3 J int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 3 W- S, e& n" \: c
const vertex_t* v) 5 p: ~7 A4 w' L7 i6 N6 P
{ 2 b1 t) o% r- {
int i, j, k1, k2, c;
. y; W# B; o+ f- H7 L: a3 D) f/ O rect_t rc;
g: Z/ T: C1 y+ s vertex_t w; - \+ {2 K# u0 G" m1 P; t* x
if (np < 3)
! `0 o8 A* D! t6 i; b$ O5 [+ c return 0; % {* l: n" X; V' n- q1 _
vertices_get_extent(vl, np, &rc);
A$ D' j; }8 p if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
5 J0 @; X J, B9 E return 0;
( S5 @5 A! A, z9 z /* Set a horizontal beam l(*v, w) from v to the ultra right */
/ h. a- V# ?3 N/ R2 E F& H w.x = rc.max_x + DBL_EPSILON; / b' g u9 _" K$ d0 u/ C
w.y = v->y;
4 w( C5 x% Q4 k" M4 V& Z c = 0; /* Intersection points counter */
: u) ?; X: E$ O# _, G for(i=0; i
( n9 R( s9 |) E- n/ h { ' ]. S F$ J) o8 H' k4 n
j = (i+1) % np; * @4 m" i: D+ H, m
if(is_intersect(vl+i, vl+j, v, &w))
, u4 [/ Q6 A/ J F) u- E. _ {
( L8 d/ Q4 b( E5 h8 h7 Z9 E1 h C++;
# T, H, x: H1 |! X( }" k2 D; j } - p7 h' {; F: @( d1 M
else if(vl.y==w.y)
4 E# F6 h2 V5 F+ m9 U" [' _( \6 E {
& b v5 }, d q' v k1 = (np+i-1)%np; $ D4 i- J2 ~. s* \1 u
while(k1!=i && vl[k1].y==w.y) 2 \7 w* G! `8 p; n/ L
k1 = (np+k1-1)%np; # C. \" _+ W/ p1 E7 R: u; T; K# s
k2 = (i+1)%np; 1 L9 E& y9 ]% v; H3 o
while(k2!=i && vl[k2].y==w.y)
L( K. A7 k5 \0 c8 N% N+ { k2 = (k2+1)%np; ) x0 N; n0 S5 o
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
T; a5 ]7 k' x8 F C++; ?: P& P- I& n ]
if(k2 <= i) . ]2 T' X( |) |& F
break; , }9 r4 ?7 H$ S
i = k2; # w; r$ R, e" m4 ?8 m* E% u
}
2 v* l9 _- f9 G } ' t8 b9 W. ^" L
return c%2; ! K( h% M7 W Q9 o8 \+ b C; R. |
} - O J; ?0 b! M! h
- h3 W& N, Q9 i5 N' s; [7 T: ]
3 G1 q) h9 J% H 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|