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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。& e) }( r# e5 I- ]. e' \5 |
- h. U$ p/ f" o$ ?5 Z 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
* P+ z* k# P h) {1 k K
, r4 a R4 a- f7 _$ v# b. _ 首先定义点结构如下:, d- m$ p; P+ o' _0 s
. v* |+ z7 W+ A) [2 K- ?. H/ o以下是引用片段:2 n- @ L: O8 A0 h$ T9 R: v
/* Vertex structure */ 8 v7 m& `2 k: Y" Q6 I
typedef struct ( W' i K; r: m* z. `
{
( h; o" R8 ~2 [+ P double x, y;
; [" b! O, ]; h/ Z9 @ ~$ \ } vertex_t;
8 I( i3 I7 l, `' w: H; _$ {2 M) t+ s8 p7 ]4 h* s E
& C! u% n* J' V+ r 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:8 E6 p# I- j! L( Q- ^1 Z! q
/ z5 G! w" |. ~8 S- B以下是引用片段:
6 S: Y0 v7 F5 l% }6 ?3 w /* Vertex list structure – polygon */
, M! q+ M$ V7 a) J: V0 r+ h B typedef struct $ b* Q: D7 _% J" v; w' F
{
$ m7 x; ^5 I' N1 C6 r int num_vertices; /* Number of vertices in list */ " P# z% L, }/ `! Q
vertex_t *vertex; /* Vertex array pointer */
( [" o: k" R1 v5 c# A2 {( V5 w1 R } vertexlist_t; 8 S3 Z1 c9 U' U
# o+ A, S) o1 s# U
$ V1 X- N8 i% V. @( e1 [6 p0 f& T* l 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:' @2 B$ W" N! S/ W8 o
( k4 w* ^6 Z" R
以下是引用片段:/ t4 C2 ~. B n) k; D6 ]- W7 j& ~
/* bounding rectangle type */
2 f D C& ?( C9 i( a, g) B0 J typedef struct , u) I8 y' b* }6 d5 h) h
{
: Q! p# p% k$ v4 Z# E+ i* A5 p double min_x, min_y, max_x, max_y; / P) c+ J5 [7 @/ d0 c( J3 _
} rect_t;
- x2 ^' x* N/ i, {+ l z; S /* gets extent of vertices */
4 v0 a- M }/ ~ void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ & J: Y& j9 W9 w9 K3 N1 j6 I
rect_t* rc /* out extent*/ ) : i, I5 l$ }$ E6 ^6 B. P
{
' K4 F5 f( k9 b int i;
0 X- I6 B8 N- I/ S" A6 H2 R9 r# C if (np > 0){
3 B! l4 G# T7 K( q rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
/ |+ R0 S& M" a w: {) S6 S }else{ . R' N5 {$ i* u
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
9 s7 G/ T; t0 g7 `% G" G } 8 }0 K6 u0 w' y$ O: _) H3 J
for(i=1; i " C: q" g* s4 E3 t w& L) X8 C
{
# T- U. c, F$ w* ]+ ?4 m1 {. O- M if(vl.x < rc->min_x) rc->min_x = vl.x;
$ Z% G, I4 u" x if(vl.y < rc->min_y) rc->min_y = vl.y;
" }. n1 r v" }2 v6 W! l8 K- l if(vl.x > rc->max_x) rc->max_x = vl.x;
$ |5 k% ?; M1 v8 M- K, J if(vl.y > rc->max_y) rc->max_y = vl.y; 4 x: P* D- X; h! r; V+ G
} # Y) S2 q6 q" q2 I4 e7 ?6 ~
}
( [: E; f @2 Q+ p& f
, B; E0 s& C* i$ {$ Z5 A
* p6 l, P, s& K 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
- k, Q8 ~* M# z6 I& G1 {: D, n7 d; Q
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:! R9 I. q: ?! n4 n- y1 f
+ Y& X6 S" o0 \! A (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
, N7 Y0 [: T2 P9 t& P9 w# M7 L" ~, r: w- o
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
- P# \9 z# N( V }6 e
' b4 o, ^7 P0 ?: c8 \以下是引用片段:8 a* X+ B0 \! q- M) O; {0 a1 |9 W+ g
/* p, q is on the same of line l */
1 U: Z& |, F; m static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
# y8 v6 }) G S" i const vertex_t* p, . w6 m4 G5 O/ i5 x8 L, Y L% D
const vertex_t* q)
: {8 f; D$ M8 K. G0 S { ) {3 ]6 R' t |% ?1 D' B
double dx = l_end->x - l_start->x;
- Z: G( L4 }8 l: s4 ?" s double dy = l_end->y - l_start->y; 4 V' F `* J( i% d
double dx1= p->x - l_start->x; + K5 z! d9 o" z) t5 j5 s
double dy1= p->y - l_start->y; 5 l) q# @: R) I J
double dx2= q->x - l_end->x;
, K# x3 J0 p: ]* ?) f double dy2= q->y - l_end->y;
# M N3 [. Q' |* ^4 ]$ W* m return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); / J& m4 S8 L! o( t/ P
} 8 ?3 k# K6 s( ]- g
/* 2 line segments (s1, s2) are intersect? */ 8 V4 V! i5 y; r: |
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
5 y: a: ]1 P3 _+ b const vertex_t* s2_start, const vertex_t* s2_end) ' F) Y* C z! \+ B3 T* R
{
" Q% ^* f p3 o0 W* U7 d return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
/ |& l$ J" e9 E2 [+ F is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
; ]! @( b9 k- X- U: ^ }
" w- l- g* U5 x* z) g9 Q1 P; h
1 W; K& }7 y8 D4 e. G
- }# o7 F, M7 N3 Q- s" x: T 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
! u' \: s( A$ N! f6 p7 w% G
% s4 U( f. \. c: R以下是引用片段:' I" N5 o5 U' K4 Z) S* H* n7 |
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
! G+ t3 N; c8 w9 r+ R const vertex_t* v)
! g! Q7 ~5 F8 h; c { % t6 B) ]( f. J7 b! S/ e
int i, j, k1, k2, c;
2 C! H+ `" z* p$ @2 @, N rect_t rc; % U0 i- K1 X9 e5 ?$ X. _1 M
vertex_t w; . e; x4 i) [2 z: C# T
if (np < 3)
7 q3 v" [1 a* @2 Y" ~+ W% H( \ return 0;
+ v h; G( z5 i4 J# q vertices_get_extent(vl, np, &rc); $ r) T+ ~' n" K" o4 o
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) $ R5 Z! d! b7 I
return 0; ' Z+ u: ]4 P5 c: f# r0 B+ r
/* Set a horizontal beam l(*v, w) from v to the ultra right */ 3 N [( m( H1 v8 f
w.x = rc.max_x + DBL_EPSILON; " `6 F1 l( B1 W- W& d
w.y = v->y;
4 @6 l9 m2 }' \3 @/ K8 O$ ^. f c = 0; /* Intersection points counter */ ' G; ]; p8 i( X7 J9 b ?$ i
for(i=0; i
; {8 w* w, k. S6 n9 d { ' c6 S# A, ?8 `+ R' j* G
j = (i+1) % np; . [1 u" L# [5 e2 R' @$ A+ y
if(is_intersect(vl+i, vl+j, v, &w)) 0 ?& V0 G6 g9 \' o2 P+ {2 C
{
9 d( C# }( v; h9 o8 e! `8 s) A C++;
( j# z, U, A+ Z) N0 Y }
% s/ E, G) d1 V2 k4 \' v2 X1 H else if(vl.y==w.y) 5 f2 x2 B( J" g0 x8 }7 a
{
7 x" ^* |. Y7 c2 \5 i k1 = (np+i-1)%np; ; m$ B/ |; p- f$ W8 v {
while(k1!=i && vl[k1].y==w.y)
' c/ [0 [+ d( o" D! P k1 = (np+k1-1)%np; ! L0 W/ l0 T5 {. p
k2 = (i+1)%np; . Z: b/ z- k- O1 S5 Z E4 z" k0 M
while(k2!=i && vl[k2].y==w.y)
- m2 M$ `; B8 Q1 n! J& t k2 = (k2+1)%np; / b, i6 L5 g2 e9 A& D+ r# q3 r
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) [3 O' U* y) }5 L
C++; * K6 p4 V* c( {; m5 ^5 I3 D
if(k2 <= i)
( e' ?+ o2 [) E" n7 l) ^6 |' a break;
& j2 S+ s+ U3 ]: M1 Y& w i = k2; 1 z4 i% W0 f0 A! N. l& h2 R
}
+ m9 Y3 F* y3 o& r } , X F8 i5 I$ J
return c%2;
. s; ?9 B4 l! _5 m } 0 `- z6 o& ~6 K+ T
3 W( D! M/ Q/ s3 @& W6 y0 z: g3 q# S5 X5 u/ ]1 I4 B. M8 _( M2 g
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|