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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。& Z' Y- {# |1 k1 A+ O
% H6 ]+ g$ x5 j1 U5 I 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。& c3 `( d& }" E' n) w
/ O# V0 `" `. \* V' r5 G7 K
首先定义点结构如下:
- q5 d# D. @% }9 j* B
1 e( z5 I8 ?1 |2 U: `以下是引用片段:
& |% K8 i# k* K, X& p /* Vertex structure */ i3 E9 k6 _; O4 {6 d
typedef struct V2 N4 S9 i8 f j* v- S
{
/ F& V! E+ X7 ~1 y double x, y;
' L9 \ R- p" w6 m; A2 H } vertex_t;
v6 H( ?* i1 q R# q+ M3 T$ Y9 w/ o/ {
/ U! t5 r5 L6 r; V7 m& X1 s 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
$ a5 ]3 q" n5 i, u; w! K2 d/ j/ Q
以下是引用片段:
( S: D8 h: u! A6 a; p /* Vertex list structure – polygon */ + {3 d) b; r' H3 w, R
typedef struct % U' ~* d; B; s! `* F" @# A( s. N
{ 7 M; U- d) I2 d& I4 J; c" f, i6 j" {
int num_vertices; /* Number of vertices in list */
& c7 j1 w6 i) P9 o4 b ]6 G( | vertex_t *vertex; /* Vertex array pointer */
* h) e8 S1 S, F% D2 u P# Z. |8 { } vertexlist_t; $ v5 K9 {6 u3 B$ ^5 o+ ^
% k4 I o. M9 Q1 }) O
: f7 g+ C* d( Y' A4 W. S+ w 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:: c9 @/ N8 h' Q J) Z2 Z$ v
4 I! U% V, {( s0 C5 ?+ ^
以下是引用片段:) A- e9 F- S" B0 B+ W% o+ K% |. r# R
/* bounding rectangle type */
1 B( q& ^/ {' D1 j& S' M+ A typedef struct 3 l$ c' C9 a5 K% y! n c
{
' D# p/ M6 Z. U% G" \5 V9 e% z/ I double min_x, min_y, max_x, max_y;
$ m. k& S/ b/ M& x F } rect_t; * y( D1 U [$ F/ f7 R
/* gets extent of vertices */ ) O! {3 d* p+ [: p
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 0 x, i3 R; o5 }1 W; Y
rect_t* rc /* out extent*/ )
6 o* b, c& k# `5 v, K { # s- b! S, O9 o# K
int i; 1 l; G3 n' i! T4 y& @) O1 P
if (np > 0){ + H$ r6 O! t: n3 D4 S6 L+ I& x
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
0 S! ?- ~& b" w) F* s( c6 G2 h }else{
: f: }: i: q6 _+ [( n' i7 u rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
! d/ O* Z, W6 r7 w% g4 o } / h* w$ V- n$ S! j
for(i=1; i ' B6 P# w4 W: K) Z( s2 K% L
{
" b j+ u9 r# V( l& H if(vl.x < rc->min_x) rc->min_x = vl.x; 4 C1 S! u0 U; X: n1 f. z x2 C% m
if(vl.y < rc->min_y) rc->min_y = vl.y;
) P% S$ Q) \' T; o, B if(vl.x > rc->max_x) rc->max_x = vl.x; 5 N2 A2 u7 y% b) D. u( s, E0 y
if(vl.y > rc->max_y) rc->max_y = vl.y; % k" x& F5 U ~% Y" _5 ^: v
}
4 l6 P) ?/ R. R W } - C7 Q+ H1 O2 ^+ H& m5 s# u3 M1 \
' e- r# ^7 X7 y+ e7 F. Y' c
/ Z6 Y6 n- g. a1 ~ 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。9 Y! c) k! l6 t* G$ p
2 M% E) H. o: X; T8 I6 k% H 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:4 t; L0 q7 X" g: d6 @8 \
7 y! W# n% F% q( l' H9 x (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;5 v9 M3 v) l( g1 K0 w& w
$ ~: J1 s5 N, h1 {: J& X# \8 u
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交; _6 f+ f6 Q+ Y0 O3 r2 c
4 D0 P$ }! P i ?9 S8 j
以下是引用片段:
, K( k( B2 z# i4 J* B b /* p, q is on the same of line l */ / R8 u8 ]. N: x+ i' H% [
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ X) R$ @# r0 q, c
const vertex_t* p, 5 Y8 m: ?( S C4 a
const vertex_t* q)
& K! r1 J' t5 j! }# u; | { + L5 X5 c; c6 u0 \5 R
double dx = l_end->x - l_start->x; . y: g" g8 ?: `1 U; Y- I
double dy = l_end->y - l_start->y; . W5 @3 u- M* D, l" N) m% p( Y
double dx1= p->x - l_start->x;
( `/ _) h: P3 L6 b# F% ?+ E double dy1= p->y - l_start->y; 9 t. {5 e2 f# a+ M
double dx2= q->x - l_end->x; ) T+ j* y; H- t$ w0 F1 N3 A
double dy2= q->y - l_end->y; & j# c$ J6 M( a& A+ c2 }
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); ' F G! s$ a6 p0 @& L
}
" ?0 A( w0 X9 S5 W% R' x. t /* 2 line segments (s1, s2) are intersect? */
/ \& o5 ^' t# [; H+ y0 I static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, % |/ k" N$ @. J; W+ |, s8 J: l
const vertex_t* s2_start, const vertex_t* s2_end) . E( E6 q2 ~' _
{
8 Y: l: m O. k return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
* g1 M% ^# u7 ?6 ~$ i is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
1 D0 A2 P K6 t } f0 N8 e( f! H7 @
R3 F# y# k! i+ U
' [1 c1 s! |3 o7 w, G 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
g- S9 f$ Y/ ]
: V4 S# y6 R* A: b以下是引用片段:
3 |! M. A0 j" Z! A int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 9 k& b5 I8 Y8 D0 }/ J* M4 f
const vertex_t* v)
$ f8 a1 l; K% z5 \6 _" b4 f0 w6 M {
( A! k) g# E, o% T/ `, F int i, j, k1, k2, c;
+ K6 b) b$ q* D# p. A rect_t rc; - E, q, T- v+ G( }% B: E
vertex_t w; # U9 _3 a" ]9 }1 M! s
if (np < 3)
+ X" G: V+ a$ z' G- E, I9 C return 0;
# O( d, {4 L2 p vertices_get_extent(vl, np, &rc); ' ~5 x' p+ b1 }* g/ L8 _
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
3 P& `0 ` `" f/ h return 0; ! M! W1 y+ \% A) h
/* Set a horizontal beam l(*v, w) from v to the ultra right */ + {4 {% l( F& a$ m; B: Z* x
w.x = rc.max_x + DBL_EPSILON;
# J- l2 [. A) ]$ A9 I T7 @1 T w.y = v->y; 7 l! O2 n6 U6 V2 F3 q" Q% J
c = 0; /* Intersection points counter */
1 A3 }, Y' A- F K2 j for(i=0; i $ t5 f( |' W }
{
" ~# H" s, t+ p& b( l j = (i+1) % np; + T) [1 p0 m5 k4 j
if(is_intersect(vl+i, vl+j, v, &w))
, U8 A+ t9 q* X {
6 D; H2 b& {/ _ C++; & }! S1 X' P% N/ D% ]$ y
}
. `3 x& R! q- E; ~' q else if(vl.y==w.y)
( L; b- F2 d7 s {
% n- g' s8 C' I7 T1 W k1 = (np+i-1)%np;
, v+ {( |) ^" _, c while(k1!=i && vl[k1].y==w.y) , d5 K. d) m* [- X8 s
k1 = (np+k1-1)%np; 2 ?5 r# O& D7 v1 q' [, C
k2 = (i+1)%np; + v. Q. H% r$ B0 w( p
while(k2!=i && vl[k2].y==w.y)
% U0 M2 {- x/ d9 @; |* z; ~ k2 = (k2+1)%np; & u1 V( h* L$ X5 I, ^2 d
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) $ W: C3 x- m7 e0 D
C++;
. Z7 ^9 _& G" p8 D2 F if(k2 <= i)
8 Z6 }# W( Q1 h7 s5 f7 L: T break;
* }' U! z- q5 R' z2 n! g3 M i = k2;
, N- ^" A. E2 B5 {3 L2 { }
$ y" i3 Z. T6 F4 `3 S7 d0 N% X } % J$ d" _! H7 c6 g! i7 l; F5 c
return c%2; / N8 ]- t0 ]$ z0 G
} 6 `# E% W5 {- O( A6 E* w
6 s p: F8 r) B9 j" y+ p7 x1 k. ?3 o) ^+ K& t
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|