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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。1 o; {( `* W! W
, r% x% S8 H% s* Q+ N 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。+ w: _* B( \/ V2 k, R
' ^9 M2 O9 J! I& }* `1 P 首先定义点结构如下: p$ ?2 h/ P1 a7 b2 \8 k) _. O% K
( M3 u/ ^6 M& F8 V4 `! y1 H
以下是引用片段:
: \) X ^" `) e /* Vertex structure */ ; Z8 n; G% g- V% h; C! P; s4 f
typedef struct
# v$ c% b$ P. h! F! W {
% k8 M# _ a- W, s2 A double x, y; + @+ j5 d# g8 H2 n
} vertex_t; 8 T; x1 a* F7 e% t
+ c3 J* }, | ?
/ M: R/ L# Y. D& K X9 [6 I: w
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:& y3 t' K# d2 y
" I* U# |/ J9 u% I
以下是引用片段:! q; Z6 D$ f, H& M7 F2 Y
/* Vertex list structure – polygon */
. d, Q* W: O9 l5 k6 m0 J typedef struct C- |) p. M: y- y6 T" V/ z6 _5 _
{ [) Y$ f+ l7 F9 Z0 l
int num_vertices; /* Number of vertices in list */
/ A& |$ [. [2 a% z9 E4 F& _ vertex_t *vertex; /* Vertex array pointer */
1 ]: L! ~& l5 R5 x! t } vertexlist_t;
5 x% m! Z" O& V# |- u( V/ t; _( B& p: a; m: F# f* w) ]
6 |4 d, s$ f# D( b6 ^" l" t; C) I 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
1 a8 I$ u2 X! D: M( J* a- X' E* K
7 } @( }9 ?" X' x! h& F以下是引用片段:0 A. A: h/ R1 Q/ U7 M
/* bounding rectangle type */ - G" \ N: y* s4 \" Y" d3 f" o7 i
typedef struct ; r8 e7 h7 f- F% S% l6 d
{ ' t. L) v) N8 p" W; V8 L% s+ a
double min_x, min_y, max_x, max_y; 3 E" R7 e9 t- m+ b6 c
} rect_t; ( d; H ~' G( O# R! t2 k% }0 [
/* gets extent of vertices */
5 }& E& C+ \1 q7 U8 @; { void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ ) ]: f4 K9 k) f O: q8 w
rect_t* rc /* out extent*/ ) 3 }% _5 p# u1 Q6 J; N! T9 S; v# j
{
; v- H: v: T+ ?) B. ~8 Y5 h6 E int i; $ F5 r( W% k/ A5 c7 {0 t
if (np > 0){
( ]. E3 G% Y5 T* ^ rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 8 {. k7 a9 R. O3 n9 U- S8 e! n- W
}else{ 3 u4 \! P- W1 V, }
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ " R) u( z* F! g* h8 s+ z
} : M9 r. {0 Z3 d* m" n
for(i=1; i
/ r0 v, x7 ^* x: g z. ^ {
( W% ~% I: ~& r if(vl.x < rc->min_x) rc->min_x = vl.x;
( j% W6 M: T' H- ]8 o if(vl.y < rc->min_y) rc->min_y = vl.y; m( B; R& l) N: D
if(vl.x > rc->max_x) rc->max_x = vl.x; : Q: w" r. j, ^" |
if(vl.y > rc->max_y) rc->max_y = vl.y;
- ^6 V# I) T& @3 m5 N4 B- B; `2 y1 X- g- H } 1 w3 _9 \' b; }6 d+ d5 F# [
} / \' I; b* f' o4 s
" N5 K1 y g+ t0 c/ h( {+ j
6 x2 U2 ?: A. B& j& [ 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。9 }; f& z4 H2 Z0 O. P% M0 a
& N; l4 W6 Z, `5 Y9 @- ?, _4 I% {
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
4 F! l6 K- n5 o9 _
8 V9 F& z0 k3 F) [& N. e (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;: M" f. B1 O& \3 l. V) z6 s
A) z; c, n' h+ v; l (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;0 W5 `- {* A: x2 }7 L
d! D/ Q+ X: `% k以下是引用片段:7 v0 E" Q1 L* g% u4 s9 r" l
/* p, q is on the same of line l */ % y: D- I' Q! X+ y X2 {( w
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ / ?4 j9 I, q5 I& W7 v
const vertex_t* p,
9 r8 _ @3 y" x$ ~- H const vertex_t* q) 5 u, P! `) p6 g5 H, w& P" r6 j4 c
{
0 L4 |/ A; j9 `* M& i2 J) O; N double dx = l_end->x - l_start->x; ! z7 Q4 f4 m" P' E; P+ ]' O7 G
double dy = l_end->y - l_start->y;
0 g& o0 Q5 E- D3 P$ R7 z$ Y) p double dx1= p->x - l_start->x;
' W6 ^6 n" V3 H+ |* V* j double dy1= p->y - l_start->y; 7 y! D) n7 O" u
double dx2= q->x - l_end->x;
/ l) ~& f6 k" j/ @( y2 ~ double dy2= q->y - l_end->y;
9 V+ t7 P; d& y( o1 Y return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); r2 Q% B4 \ F0 e# d& H" E# R
}
/ m. O. V( Q4 o& p2 L4 U7 q /* 2 line segments (s1, s2) are intersect? */ ( I n$ y% m3 x4 p4 ^5 I8 {
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, 3 i3 c4 F& l/ [
const vertex_t* s2_start, const vertex_t* s2_end) & Z+ h+ ?; m. l6 I% f* A$ u
{
% M8 e! s( H! q( e return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
) G$ }: R$ I5 E3 t' ? is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
4 [8 v' M0 h. J k } ! R9 R& [8 Z! J; c
$ k& C' b8 ^7 L7 z* `3 c" t# B Y3 P1 [( X6 C6 i) B
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
) Z9 F6 C% \+ `) F C- ^3 n7 @* t7 @% x5 z4 ~5 w! b( x
以下是引用片段:
5 d! q t6 v: B0 { int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ ( O6 b9 h* A) b) K! q, s! e$ ?
const vertex_t* v)
6 v* K# C/ A; ~9 r {
! t5 P N$ P# w7 ]9 [ int i, j, k1, k2, c; / l0 G" x: c) ]' \ u
rect_t rc;
h' k6 q! E8 v vertex_t w;
# m! {4 N1 U+ g- z if (np < 3) ' u* r* |7 \8 Y5 N
return 0; , W/ ~& J/ w% q- G9 u( w5 B
vertices_get_extent(vl, np, &rc); + \' [3 e& d+ R, C/ x( t+ c) l
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
5 n. ?* ~3 q/ o( G. a return 0;
& P; L9 g8 T9 H% i. _6 ^- O /* Set a horizontal beam l(*v, w) from v to the ultra right */
0 @; i1 H. d8 C* | w.x = rc.max_x + DBL_EPSILON;
# n: T1 b3 k, Q5 O T w.y = v->y;
; b$ h- B4 b9 v9 ]0 \ c = 0; /* Intersection points counter */
+ T/ j* P8 ^6 B. z( v8 W% G) L6 ^ for(i=0; i 1 a/ D$ q4 A9 }5 S. P) `
{ 3 r2 ]: C S7 l/ ?
j = (i+1) % np;
1 U$ e4 y9 H+ e" j2 q- u% e if(is_intersect(vl+i, vl+j, v, &w))
* ]$ ?7 g2 [6 t: b% a1 b/ ]4 {3 f) p { + t, o3 F4 n+ Q( }. X
C++; . J% W0 f ^" v5 y6 U
} # y+ o- F, X7 z5 B
else if(vl.y==w.y) # \) H8 |- R; A1 _& K& ~- @! P
{ ; H' S( N0 ~1 b# {3 U
k1 = (np+i-1)%np;
4 L' X6 C- u8 Q6 M# q" P while(k1!=i && vl[k1].y==w.y)
7 v' g3 T. F5 I' U s- l/ a k1 = (np+k1-1)%np; + ?$ Y) T/ X: q# E' z) n+ u0 H( N
k2 = (i+1)%np; 5 H. T( ^0 T1 B9 E& G
while(k2!=i && vl[k2].y==w.y) % t" ~8 Y6 v R! w5 Z% l( H+ G8 M
k2 = (k2+1)%np;
1 f$ X/ {* X5 m, J5 f if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) " H8 m! e8 l( G3 f2 f( i
C++; # Z& @8 _) R6 r" _# _- \' E4 {/ ~9 K' m
if(k2 <= i) ! T4 m) ]$ n4 ?6 q$ I+ d. J6 `
break; # A3 T* |& v! o- [7 `' b( _
i = k2;
& e* t4 o& S n( [; d) | } & D/ l, Y1 T8 _' f, w% L& @/ F
} # ~1 P+ [$ z/ ]; o- T
return c%2;
0 G4 G0 H- n9 f# U; o3 j/ l } + P' z3 D0 S ?6 o% }: p* |+ B
6 b2 J/ B& j, Y$ N8 h) A
; j- K( \$ \* r 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|