标题:
C语言中显示 点在多边形内 算法
[打印本页]
作者:
zw2004
时间:
2008-1-21 17:20
标题:
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
& b, }0 ^" ]- Q% W8 c2 i
4 A& i# M# {+ d
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
0 _" O0 C0 H2 F8 F
& T$ t9 [. v3 v- k p" b
首先定义点结构如下:
/ q) G1 y, Y7 D3 ~$ u
$ `0 u P; R# l! E
以下是引用片段:
0 N& n$ ~1 L& w1 s, u- b
/* Vertex structure */
# H5 |! I5 A+ `
typedef struct
) p0 [. v* ] \* B; d l
{
/ G" m) d# _" g- f* o' B( Q. A7 d
double x, y;
( p6 D+ d6 q3 k& _( S
} vertex_t;
' W! X) D. U( z/ V
- S/ z. `8 M+ B6 f& [+ }
+ A& }# d3 p+ L" Z
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
) e: r8 M& c" d/ A
3 [1 _+ q) Z0 O1 M+ y: f9 ?2 o2 [
以下是引用片段:
0 X- P8 p6 V7 _) b
/* Vertex list structure – polygon */
, `: j/ _4 J5 f/ T# l5 `3 e, m
typedef struct
' U7 v& Q6 K8 S# F
{
# w& ?7 j; D4 }. _& ^( P9 B: C+ G
int num_vertices; /* Number of vertices in list */
5 ~* ]9 d4 D: ~% e9 z/ ]! N$ L( e, W
vertex_t *vertex; /* Vertex array pointer */
8 ]' Z3 s1 t" S8 l* J
} vertexlist_t;
7 D2 R) I3 d* r9 _# C$ Q# |3 H
* g, U$ n2 z) Q! z! ^
+ J0 t% O: P8 b+ S6 V7 T% }
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
( q+ F: H5 r- Y% s: n
6 }" b" V3 K+ |- n. q5 N
以下是引用片段:
, `4 ]0 t# O4 c, B& z3 V! Z# d
/* bounding rectangle type */
; P5 q. N5 c$ u
typedef struct
- ?4 f" h+ r# Z6 w( t
{
& z( k' Y+ D! D j( i
double min_x, min_y, max_x, max_y;
3 k6 Y6 b# u0 d
} rect_t;
: |: S# d* N' `4 m; T
/* gets extent of vertices */
/ u: v* \' I' t; u8 d f8 f
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
/ L* x$ ^7 A8 t
rect_t* rc /* out extent*/ )
* ?8 d& q# }$ j) G1 c- r& o" Z
{
7 r$ o* ~; Y( ~/ m
int i;
, Z7 L: P# v& g, @% ]* W$ r$ t
if (np > 0){
# i- a' W1 z6 _
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
% _$ V8 W: y3 ]6 ~, Y; k( r% y
}else{
- f7 m5 Y4 p, L/ B' ~( t
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
9 K1 _& Y% w( y g( B
}
4 ~1 X* @8 e9 A+ j3 i
for(i=1; i
+ \* R+ E+ a5 h' H
{
4 E0 X0 |1 D7 ]/ l
if(vl
.x < rc->min_x) rc->min_x = vl
.x;
5 \6 m# p0 O$ W; S
if(vl
.y < rc->min_y) rc->min_y = vl
.y;
: F' h' p9 L$ r/ i' M( J8 D
if(vl
.x > rc->max_x) rc->max_x = vl
.x;
0 P/ E! l& B0 s6 U1 }* ]& c
if(vl
.y > rc->max_y) rc->max_y = vl
.y;
; i8 j0 D6 d, x7 X. r! D
}
/ f# z5 Q! v A
}
A) F1 }- k2 X: d2 j5 E; G
( G+ y, n* {, U& F
6 T+ ~* p( N7 E
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
5 i) R4 ~/ M/ t9 G) a6 |
0 ]& S/ q R( \
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
& S: c( \6 v" v3 n9 i
- S) z* n, ?+ w7 }* ^$ J$ F
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
x. u2 e2 L/ |& F! e& L
% g0 D# _, Q- C; W6 B
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
) {5 T$ `3 c0 o5 J0 o- x
" L4 }. W# R# X$ K X9 q1 L" Z
以下是引用片段:
9 M; d+ {" g7 c# }
/* p, q is on the same of line l */
- C( y) g+ i+ X u a" o: h
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
2 {8 o9 I! @4 h1 Y d
const vertex_t* p,
3 h$ R. m' J# _% G
const vertex_t* q)
% D4 C0 K J8 P# i/ o. ? C9 w
{
% [/ H% |' l% t' s$ H
double dx = l_end->x - l_start->x;
7 J8 z8 x/ v* h8 M
double dy = l_end->y - l_start->y;
* _) R5 q" Y7 L. c
double dx1= p->x - l_start->x;
2 a& h% f) V `/ X. _/ W# u
double dy1= p->y - l_start->y;
. j' F) w% R4 k) J* T2 c3 ?
double dx2= q->x - l_end->x;
5 b" e h8 \: r: o; X2 Y
double dy2= q->y - l_end->y;
+ j6 S# W+ S" U0 O. ~' `- T
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
/ s3 {6 F0 G; J* }9 @1 ]. C: Z
}
+ L9 \: L; ]" x0 g' h
/* 2 line segments (s1, s2) are intersect? */
4 {/ i% W& w' @, S1 o
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
T! c' E/ B7 ^ }# s1 g, Y
const vertex_t* s2_start, const vertex_t* s2_end)
M4 h, L+ F$ I6 W! t7 [/ I9 d
{
5 E% A2 }6 Z. I2 p5 {
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
* P: Z1 J/ h z1 {- `+ c
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
: ~, w! l( E' _
}
1 l0 N$ _7 q+ K
+ _' ^* z8 r) k2 n
- T* M0 j8 m$ E
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
% Z) h4 ^( ^* t1 C
2 }/ Q% [) w( |
以下是引用片段:
. x1 S) Z) t" d7 b0 u
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
! W- Z5 W5 p2 U
const vertex_t* v)
) H$ Q$ [" x+ m1 O( ^2 \
{
# F3 m3 ?& A6 ~9 E. I# h0 y; L
int i, j, k1, k2, c;
7 K6 @0 E- ?. i- d$ b5 X( F9 F+ k
rect_t rc;
, }8 u- Y9 T4 [) V
vertex_t w;
! _8 Q5 A9 n5 I/ y, p& v* Z; p1 L
if (np < 3)
. ~1 ^" F9 \6 ^" d
return 0;
& p% t# L8 I7 V- H9 I- ^! e3 t
vertices_get_extent(vl, np, &rc);
4 ?8 A4 x+ e$ ^
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
* j9 J, O; W% R
return 0;
# F6 X7 L) N! k1 r2 M, N
/* Set a horizontal beam l(*v, w) from v to the ultra right */
* H; E! M5 u' E9 C0 l
w.x = rc.max_x + DBL_EPSILON;
: D* g; x2 R; w# l9 I
w.y = v->y;
6 `' C! T: \% e1 }( |
c = 0; /* Intersection points counter */
; @6 x* I% Q7 U4 ^
for(i=0; i
. H) s d2 c9 W1 B3 d9 `
{
- c) H$ v( N; B
j = (i+1) % np;
* }) x( r$ {; K6 o
if(is_intersect(vl+i, vl+j, v, &w))
2 F& a6 d6 w2 G" o5 J( E: |$ g7 X
{
; E( Q$ f3 H5 c, n1 _$ V
C++;
1 N) Y8 `- B$ w# P+ b* w# N: R' ~
}
5 P# p1 N' I# x9 P5 X
else if(vl
.y==w.y)
9 C1 n6 p4 Z/ p3 B% u9 T. F3 q
{
" D$ [5 z. I2 o7 f) q& v8 [
k1 = (np+i-1)%np;
1 z4 B6 l$ ]$ n( A, _
while(k1!=i && vl[k1].y==w.y)
1 _; D7 }8 Y& w6 a
k1 = (np+k1-1)%np;
$ P& h' {+ b) y1 o5 H9 X
k2 = (i+1)%np;
) [9 `' a$ Q/ ~
while(k2!=i && vl[k2].y==w.y)
: M) I4 p% X. }& J4 b
k2 = (k2+1)%np;
% v, w! [3 e- e" f, }
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
: l( I7 W9 Z" t
C++;
s% J# d1 t0 D6 ~
if(k2 <= i)
+ k, F+ b7 o. n3 k, O8 [
break;
^8 A$ L" J, l$ }! M( |1 ^
i = k2;
3 q: H2 W; d3 Q q) u1 @
}
" N8 b3 h q9 w3 ~8 B) I
}
0 Y3 l& ~+ ~& W" K: M
return c%2;
3 `, ` Z" i7 D1 d3 F1 v/ K
}
' u6 a$ r; r0 N
# G& M( y# o& o/ j4 Q0 c5 v6 h
3 r" g& F2 |" h( ]' h5 Q
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。
欢迎光临 捌玖网络工作室 (http://www.89w.org/)
Powered by Discuz! 7.2