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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。& C, Z! k; Y/ ^' F8 w
6 D# |" b4 H K
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。" P; S( O% f! f s7 c
2 \, g1 P* n3 G+ z' { 首先定义点结构如下:- [- ~/ e. E1 C* H& E/ ]
. n; |. M# O: }, C. ^9 T
以下是引用片段:& y3 G+ k* `7 \
/* Vertex structure */
3 G# \3 q: P9 k( a& p" Y* b typedef struct . L9 U6 }7 r% N
{ % J1 ^: O6 e: v5 g3 M
double x, y; 6 y- J# L1 V* y( C! _2 H5 E1 N
} vertex_t;
+ a) `* J2 e7 ]4 m0 C8 A, a9 k2 G- `# L4 T: K; d( i
. v: P; F9 t7 p% L 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:" f/ Y X0 L& k2 K: U
- y9 y( j: ?) _# i. ~" h
以下是引用片段:
: o3 g7 g, {; Q4 L0 z- n- L /* Vertex list structure – polygon */ 1 J R! W/ `/ y" `1 Z
typedef struct
+ C) i6 a4 c3 w {
8 \1 R; W3 x6 ^& h int num_vertices; /* Number of vertices in list */
5 L$ p: f- @; u, @ vertex_t *vertex; /* Vertex array pointer */
$ j- @, |8 E# \- k: ?" E" u } vertexlist_t; 8 P4 `, y( Q2 b3 i) D
, a2 M- q$ N: O- R9 z0 F9 H" z4 ^3 W* H2 C) N
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
8 R4 m! s2 n, }$ I0 O3 P# k* ]
/ ]5 L; E! K: A) G: O2 \以下是引用片段:8 u5 j) ~6 a4 U2 @
/* bounding rectangle type */ % W. A ~5 K& r9 Q# E
typedef struct 8 r. g- f m1 i9 ^3 g8 ?) H* Y
{
) ~) C1 y, p1 ^4 q; v1 I double min_x, min_y, max_x, max_y;
5 |# y9 B9 g& K) d% K) l0 w } rect_t; 5 B. v" u. x' E+ M! q' W9 d2 F
/* gets extent of vertices */
% @( y7 b i& e" K void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ ; k3 B+ A: V+ \2 G; o. m ~" U
rect_t* rc /* out extent*/ ) 1 m/ j) s% Z; }) ?6 F P4 U) c5 }
{ ( `3 G* ?: T, g3 @5 m: r7 K
int i;
f. K! u. N0 Y9 e if (np > 0){
" ~- k0 X6 V [- Q4 K' V4 b rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 9 u; s1 r( G j" f6 x9 l! I; n
}else{
) V9 u! W5 a) D/ B+ a2 l rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ 1 X: Y' C* N4 g. p+ k9 _0 n) f
} 1 P9 n4 J0 N2 ^7 c6 H3 k
for(i=1; i
! z$ d3 W( ^0 d {
5 V+ `' K4 q$ u& P. H4 j' g' x if(vl.x < rc->min_x) rc->min_x = vl.x; + G" m K$ M) w$ C
if(vl.y < rc->min_y) rc->min_y = vl.y;
& O, T2 G- }2 W' E0 @: {4 w) G if(vl.x > rc->max_x) rc->max_x = vl.x; : T( r# l' \% a3 n( @8 a
if(vl.y > rc->max_y) rc->max_y = vl.y;
8 v& _+ Q( d' s: F: ]9 X } " y% X) Z, @8 x+ ~2 b6 t
} / F- z* T1 Z3 N5 P: f5 C; A
* e" T5 d" \6 T
& r1 D' H$ k* x6 Q) Y 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
! I& @6 v( K/ M( [1 g5 m0 Q6 L
& V5 v' q$ \! d0 z' p7 Q 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:8 K2 H5 k! ^& l. F9 t
$ h9 a2 t p9 l5 W' a8 t
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;1 O; T0 N4 ?: T' J+ n3 c E) A2 p
* f" p% i/ h) q8 W
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
+ s. ^( B! |2 @5 }3 b
4 _6 w' ~$ k9 A* g7 q6 S以下是引用片段:
4 v: T& a# R( E! ~" v& K" K3 `8 U /* p, q is on the same of line l */ 2 s: t5 w; o/ e
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
0 t" J, ?8 t$ x6 X% R const vertex_t* p, & ?" f: V2 C7 V0 ~
const vertex_t* q)
$ ~# V& H; x U* Z7 O' X { 7 R: _( t* { v2 X
double dx = l_end->x - l_start->x;
) l' ]; k( l, i' B3 i double dy = l_end->y - l_start->y; 3 a1 s, X" w0 Y0 q
double dx1= p->x - l_start->x;
' [' ^" o# ?) r* L& H( E- _ i double dy1= p->y - l_start->y;
) R9 n7 H2 S. u8 \9 y double dx2= q->x - l_end->x;
z, T8 u; T& \5 }7 }2 a double dy2= q->y - l_end->y;
, Y# [# `% ]" l" h V return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); , p5 U2 ?8 h: }, H3 [+ c8 R
}
) c* Q* U7 Y- W# K6 X* G2 A /* 2 line segments (s1, s2) are intersect? */
9 ]" P9 Q( x! ^ f A static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
/ H, m# A: x# Q0 y const vertex_t* s2_start, const vertex_t* s2_end)
9 Y, u8 ?1 T- V* w# O* l: t. s { 5 e- K# `5 k, [! y
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && " A5 O u/ S6 R. p8 c* g6 x4 I
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; ' @) E5 z9 P7 Q" L
}
/ B/ A3 b/ J9 C! h. B! a, v3 z2 S% T! E O
. T) Z/ y# Q0 C, g0 w6 ^' B9 n8 M5 ?
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
# e* q t, k% r4 c( E1 ?9 {3 \! ]; p& c: _8 g9 Z2 j
以下是引用片段:
+ I8 w( k+ H; T/ E int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
& w+ M/ w# ^( F5 ?, L s4 _ const vertex_t* v)
$ M" {/ Q! b- T {
3 @: ^& ]- {0 w* S8 r( \ int i, j, k1, k2, c; ; C! J! W s: [7 d) b! S! V
rect_t rc; ' B* z ^% ~! d8 U" W
vertex_t w;
' o6 K f, c2 W( X V0 @ if (np < 3)
8 C6 o8 b: v/ n) [0 F4 i3 ` return 0;
5 k6 ]& G$ j2 a3 j8 b vertices_get_extent(vl, np, &rc); 2 U1 u4 A" r: d* Y: H# U8 c4 Z
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) ' g5 _8 S( V1 I7 x6 S
return 0; 2 ~, L* a7 v: w6 f6 `5 f8 G- z
/* Set a horizontal beam l(*v, w) from v to the ultra right */
6 ~* Z4 F7 N I w.x = rc.max_x + DBL_EPSILON; 2 l: V+ T8 c; A9 C# m
w.y = v->y;
6 y/ O# C+ T) x c = 0; /* Intersection points counter */ * u, \ _/ Q8 Y0 r( P6 e
for(i=0; i
8 z* O* P0 ]( s4 } { 5 }- o3 i% E+ Y( z* f
j = (i+1) % np;
) l( K8 O$ G" i( i9 f# ` if(is_intersect(vl+i, vl+j, v, &w)) / a; W2 B3 e; K
{ 8 Z" i: w$ P1 I- m/ q
C++;
7 S- T3 P: H9 b* m } + `8 B6 s2 A, n Q) k7 T
else if(vl.y==w.y) 7 O5 h) n+ o, E- r& c# `
{ ; |6 m/ n- x: f" U* p: I* I
k1 = (np+i-1)%np;
# X4 Z+ U" L8 o# _) p while(k1!=i && vl[k1].y==w.y) - O9 T9 W' J w6 k8 M5 [: f
k1 = (np+k1-1)%np; 9 d0 {- B& I' [& a! n
k2 = (i+1)%np; 2 }2 i ^5 M5 b( `" c/ V
while(k2!=i && vl[k2].y==w.y) - y0 j0 a$ v p% O3 q% y
k2 = (k2+1)%np; 8 y9 |2 g- J8 v2 ?8 i: _; G8 C' T
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
7 r6 R Q/ y7 ~' c C++;
8 {# g& F: J9 o* F; F if(k2 <= i) ' E9 U* Z% S' T8 ^9 t
break; # o0 Q% `2 v, N$ @! U1 H; b
i = k2; # t2 g/ h2 {2 Z* B
} 1 s; O: ?2 R& a% W5 S( ?
} ! Q4 x0 C" y+ O" K
return c%2; ' C8 u9 Z, u" j; y% ]+ a8 l+ @
} 4 {/ Z2 g( V/ q; R9 F9 M
; U' k' ]7 K) J4 X% x: W: `
1 ^4 o4 C2 v8 u
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|