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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
- S( m2 E2 ]0 M2 V0 k; k
# b8 u4 x8 R$ M' z 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。1 Y' `8 s; g9 {/ |/ W
9 }$ ^' |7 W# b( x) D 首先定义点结构如下:
* } Y0 U2 R! Y( i3 x; q% M4 G& j8 E& _, Y
以下是引用片段: V! t, @" ^; j* E9 v+ F
/* Vertex structure */ $ E& _! N7 [8 f% w! a7 l4 t
typedef struct
' K% Z) \; J3 K4 } { # Q2 m; u+ O# x* ?0 A
double x, y;
$ v5 I0 t; X0 p% z } vertex_t; 0 R3 q9 D2 W* ]3 b% w0 Z9 t
9 ^7 l$ t# p6 L
1 l' n$ {/ n( d) C9 Q 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:. k1 p/ X7 |4 m; Y3 e) i% r% }
# {4 Q3 G& F7 | g+ S. s
以下是引用片段:
1 Z$ v6 ~" I' k /* Vertex list structure – polygon */ 2 C2 a6 r$ ?/ u) M8 ]" @6 d
typedef struct
# |" J' S. @9 \* \ {
v; _* `! v4 G6 o int num_vertices; /* Number of vertices in list */ 4 p5 F0 K+ V; t- U% F7 ?( x& |
vertex_t *vertex; /* Vertex array pointer */ . Z: q5 [. ^3 [0 C, x9 R: R$ `
} vertexlist_t;
5 S; I" V, l) ~7 o" \! p
. N# j6 p9 [, a" A( ~; M4 O, N3 p5 f. E8 K2 j) b
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
! a0 P* U; m. Y: a2 M4 L! {) |% l+ V. b
以下是引用片段:
6 @; v. z5 I# V1 S5 I; x) O' J$ ?' c /* bounding rectangle type */ . F# t. I1 K; P2 }$ X$ `" ?
typedef struct & M* \' y9 l0 H: Y$ ?+ v0 m/ _, X
{ & N5 A8 g' i) B) h2 \! d; ~
double min_x, min_y, max_x, max_y;
* }1 Q9 l/ e) ~+ i' s0 A* u( S } rect_t; ) O6 a& a$ X, N1 R* o: G! Q
/* gets extent of vertices */
5 Y- h9 | \ i( L void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
G- r# J9 X. |! n% B) v* I! ] rect_t* rc /* out extent*/ ) ! G$ d& E% b* n
{ 9 G" q9 Z7 n# [4 j% c3 i) s
int i;
# z5 y# G! c& P$ r if (np > 0){ 2 H: F1 y, }' F8 }4 f: d+ X7 o
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 0 A5 L, ^9 N% o: f- a5 T
}else{
9 Y+ s4 `% x: F rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
E/ D+ z9 N& B5 D } ' R% ?/ m' o/ t& c
for(i=1; i , x: m3 m% D" z$ ^% `
{ + J8 }1 k4 {* R% S
if(vl.x < rc->min_x) rc->min_x = vl.x; ; d' T; ?7 X5 W, f- U9 @
if(vl.y < rc->min_y) rc->min_y = vl.y;
3 h B# Z& t2 ~7 {: ~7 d8 I if(vl.x > rc->max_x) rc->max_x = vl.x; % Z, L& F% E! [( ^( {( _( n
if(vl.y > rc->max_y) rc->max_y = vl.y; . B; C- ~% R7 I9 v3 q& F6 n
} , @: O/ e4 h8 } }* R( t9 F3 p( I
} ; Q3 \: i/ c5 u) a
: Q" L' [$ Z' |- D% b! Y5 X: V) f0 g+ l4 @
/ ~2 h2 w2 S6 _4 r5 M/ W 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
5 x0 @7 m5 D$ {
! z2 y4 o- I3 I7 Z, b3 K$ g 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
" @" h5 i& V" t( e
( w1 W* g7 a* J. P5 Z, S (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
( I# o4 i, _* `* |) R
d3 N$ B4 t9 j+ Z (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;1 s; S1 c, I1 A
2 r; J- }7 H0 v. d8 f6 E% l
以下是引用片段:
* J9 f( ]# f. W) w /* p, q is on the same of line l */
+ e+ G& \) k. I static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 6 \" Y3 x* H* H
const vertex_t* p, / x4 d m1 O' J3 W) l, i9 a
const vertex_t* q)
: \) h9 @" x) @, t0 n: u+ Y { & T& B4 n+ n1 C% S& [5 k, J& F
double dx = l_end->x - l_start->x;
; E9 \" C z1 O2 w double dy = l_end->y - l_start->y;
7 d9 |" {* L) a) I% R5 m4 k2 i double dx1= p->x - l_start->x; & G, F& z O0 H9 [/ Z7 a U
double dy1= p->y - l_start->y;
! c% [6 K- {- E4 L& v& t double dx2= q->x - l_end->x; . ?/ @# \ [3 L1 Z
double dy2= q->y - l_end->y;
9 M1 [! N2 u+ K- V( N& J. v0 {; | return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); ) x8 i- [6 E. w# A/ i* e
} " Z5 {" r$ T4 D- I) N
/* 2 line segments (s1, s2) are intersect? */ # a5 b, a2 l- X; U( F0 H
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, 8 k, D7 @' M, B+ `) |" d4 ~
const vertex_t* s2_start, const vertex_t* s2_end)
- ^! D7 s t4 m1 D( w {
+ w0 P: W. o. q& d2 d$ ^$ \+ T return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
9 z- Q" m5 w, [6 @ is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; 1 z' q! Z2 V) O2 d' Z
} 9 j+ I) p( x# z5 W1 E. P* P2 q
5 } `4 h4 A6 X+ O( C: _5 `
' C6 |, {; t* X# U
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:( A7 v6 }$ Q4 M3 K! `# t
0 ?& U$ k( p4 P/ R4 o以下是引用片段:7 f) r% [ \1 ?. z( u! q- P4 N0 P
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
# f% x2 x: M6 X+ c& U0 E% w const vertex_t* v) - h5 p3 x5 @& U+ a* ` | l
{
: A, m% f3 y# [" @8 f( R# l* T int i, j, k1, k2, c; 5 s0 I- O, A: G) V5 d
rect_t rc;
" W$ d( T, C- l4 t vertex_t w;
( V! V& K& j3 W$ u y2 A9 X' h4 U if (np < 3) & z/ c1 ?/ e' j& x+ R) N6 h& O
return 0;
8 Q4 Y1 m9 K1 W vertices_get_extent(vl, np, &rc);
2 ?5 N* }4 g1 {" \: _ if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
8 O u& m6 @! g/ s/ Q return 0;
: `5 W8 U% g* w1 s1 H9 }- s /* Set a horizontal beam l(*v, w) from v to the ultra right */
) `! `7 ?7 d B& t$ [/ H+ u7 \ w.x = rc.max_x + DBL_EPSILON;
3 Y$ {. L) x0 y w.y = v->y; ; B) ~: R. }- E6 G. K0 g
c = 0; /* Intersection points counter */ 3 ]+ o% X D1 _, W+ C% {1 |* g
for(i=0; i
1 J. w" K* y3 \ o9 S! f; {3 A3 Z { 5 l+ o: T9 V- V
j = (i+1) % np; 3 H/ n, W& M3 R X5 s
if(is_intersect(vl+i, vl+j, v, &w))
# f0 ~0 l/ _3 E' t' a" J5 o4 j# @9 V {
, E1 A8 J [/ } C++;
% M( n0 A0 X- Z4 `! D } ; I( l$ v: W& H
else if(vl.y==w.y)
# p& k$ o# ^# {! |+ W; _" d {
H8 I0 ~! ?6 g. E( U k1 = (np+i-1)%np;
- @" e; f- f" { while(k1!=i && vl[k1].y==w.y) 7 d* ]4 m' ?3 W' p- r! }+ K% ^- N* d
k1 = (np+k1-1)%np;
) b* K( C# `8 |2 ~5 ? k2 = (i+1)%np; 6 I L& V8 x' h( g Z$ D% q
while(k2!=i && vl[k2].y==w.y) 3 f6 I1 m( a2 y0 O/ v7 g# x2 A8 y3 E
k2 = (k2+1)%np;
" z2 p4 \, |6 u& B6 A, p if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) " b( Y5 s5 D5 N( y/ m
C++; : U& |3 L# K% f) ?- Q6 |5 s z
if(k2 <= i) F' h- T' e" f$ C0 _; T/ v
break;
3 p# f" g8 ?8 M' C: @ i = k2; |/ {/ Z! I9 a$ q$ {4 S
} ! o u2 ~% @! q6 x/ M$ B- T
} + i# P! D5 {+ {( l
return c%2; / T ]7 F) v" }: @
}
. d( n% @- v, J
9 f$ K7 x& b) Z: s9 A* Q7 l! L4 N# F2 F
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|