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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。# J7 l$ E3 j+ h" w! ?0 E' l% J
6 }2 A' J8 `( |( d3 J2 v 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。" |# E6 |# q9 M- T7 N# o
# t1 K- M4 v) }/ M' \2 o# P
首先定义点结构如下:
% F8 L# B7 h( C+ F8 `$ h% A5 _ M5 ^7 [- `9 R
以下是引用片段:
% T+ U2 u, Y" @+ h /* Vertex structure */
& G% I2 J% V6 } typedef struct ; @" X! n. }1 V, F& o
{ + F: @, i y: H! Y: s2 Y
double x, y;
7 {; O; c- c/ H# O# ~9 ~0 y } vertex_t; $ |! V C6 _& {3 w" v$ N" N
& n" [, M* f9 W5 C* V
" k; K( l9 I$ B% M0 {, `3 K 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:+ ]' m- ]8 S9 f, J F$ p8 ^. X
% l+ F; s& F% e( F3 h( [' h# T5 p3 J以下是引用片段:8 S6 I" V ~/ G' ?. O( q* L- X6 G
/* Vertex list structure – polygon */
1 b% N F" X$ ~* e+ r' T# O# B" i' \ typedef struct
" q; ~! y/ i+ c) J { # V# R& P5 T9 _7 o. V( g9 \( ~
int num_vertices; /* Number of vertices in list */ 6 V7 d1 S: B4 b# i1 Z3 U
vertex_t *vertex; /* Vertex array pointer */
4 o J: g, t, v } vertexlist_t; 9 |" K' M0 U$ t9 j2 u* X3 Y
) t: C6 |% f. l* s1 M
" [9 ?' R* G* r. W 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:* E+ H$ l5 ?" p2 t0 L) d: Z
9 k) y8 v8 [4 f1 A# n以下是引用片段:
" Q' p2 \7 h- d8 n /* bounding rectangle type */
3 P2 p4 q `7 N i, b5 k typedef struct
: H. ]% R0 v- [# h8 [ { $ Z# o d% Q/ Z( }- \7 K- A. Y
double min_x, min_y, max_x, max_y; & X! T4 d- L7 C6 \$ m5 \) A
} rect_t;
% w! v" {9 J+ q, O /* gets extent of vertices */ }6 z3 q# T! P1 j
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
6 d4 x2 Q# z) K. `4 x rect_t* rc /* out extent*/ ) ) c3 v2 R+ {4 D; i; F4 F
{
: P4 R( O' Q" h! a9 k. @ int i;
2 P7 p' _5 [' g- l) s if (np > 0){ 8 G5 c% v C0 w8 z4 K7 R7 T: c5 D$ P
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
C5 a# C* u; }" Z. \: ^/ a }else{
- _7 q! z4 {1 \! k# Z! E rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ * y- A# r2 C* v0 |" ?: r2 C
}
8 s) H; g4 L. }4 `' ^9 N for(i=1; i " W, c2 @) e( w7 P: l. K" |
{
1 m3 @: e2 _& {8 g8 ^ if(vl.x < rc->min_x) rc->min_x = vl.x; * T, O# y+ C6 K
if(vl.y < rc->min_y) rc->min_y = vl.y; 7 ^/ m' {' u3 N1 z; |5 r: |, H9 S
if(vl.x > rc->max_x) rc->max_x = vl.x;
5 |" M% I% N3 v2 n if(vl.y > rc->max_y) rc->max_y = vl.y; ( ?3 [* ^; P( e1 o
}
+ i, u% o! P# T1 P3 k" [ }
5 Q; E( {* z4 x8 s( s* J- I7 G5 |8 L R6 F& h2 B" s9 n
7 d: {5 Q# v7 O7 h+ U! W. K 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
# S1 V7 p& E+ g; \, R+ o
. N5 M% @) |7 d) ]0 r 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
% o9 N' ^" p4 J& X! y, s" b9 n5 i- `4 J7 O, x d
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
' j: T1 s1 {6 L( ?% c, p1 p( V& w5 M5 V% Z* j, a7 J
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;1 b- F9 b, \' ~! B% m
. v* `: i' C! G+ x9 b9 T- W, m8 R* Q以下是引用片段:4 r+ ]2 p7 K- m' G7 m/ c
/* p, q is on the same of line l */
9 s' j$ q0 C' Z2 E static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
0 W+ `1 A2 Z5 ~1 R0 _+ l$ u const vertex_t* p, 7 O _$ ^; Z+ t( L
const vertex_t* q)
5 N1 r- ]4 E. l- z { 9 o! ]) ^' a) K9 }1 |" s
double dx = l_end->x - l_start->x;
7 s0 o/ H" I# f: \) X double dy = l_end->y - l_start->y;
) X1 |, F# y# i# y double dx1= p->x - l_start->x;
& f$ c+ g! [; k8 o# O double dy1= p->y - l_start->y; $ z6 Y3 S, }0 t: Y0 q
double dx2= q->x - l_end->x;
6 [; T B5 c0 s: M: } double dy2= q->y - l_end->y;
$ S4 H6 M) r' L2 s return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
9 @+ d [0 I* }( ^ } ) M) D1 B. F- e3 M) {7 B! j3 o7 `
/* 2 line segments (s1, s2) are intersect? */ ( h; R3 ?, K9 I. A4 j
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, # L1 k2 f3 F- Q c/ i
const vertex_t* s2_start, const vertex_t* s2_end)
' R. m9 r5 Z y. O& M$ H {
& z! o8 [ s+ G) _: Z return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && / p5 }/ {& z* X6 Y2 ]# _* ?7 a& |9 G
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; ' Z; H C' i. @. s' m
} ) L$ i. Q8 D3 [: A: O6 J# H# n$ R7 J
6 j4 H- B+ R& a0 P3 W
) k( Q4 ` B9 A) C+ z& E
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
4 d, `1 `9 W8 Q6 O) P2 e7 |' t* M6 ~: E4 z% N$ X
以下是引用片段:
$ u8 G" B) u! c2 Q$ n0 H int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
. D% o" C8 [" q; q6 X7 ] const vertex_t* v)
/ O% ^2 r2 E& f4 x4 X/ {8 M {
) T! d8 m) B" ~8 b+ X int i, j, k1, k2, c;
4 u( E7 k. v/ Y1 [! u' ?! ]! [! n rect_t rc; - t' s- O3 \( x
vertex_t w; b1 i. e: T" @ `; R2 |: |
if (np < 3) 7 X8 u, x, d5 S
return 0; ( k, J W3 o8 ?# ^) \: Y
vertices_get_extent(vl, np, &rc); - H6 `" W q4 g: H7 ]
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
4 X8 V8 Q* T& d! P return 0;
! W( W' ^9 b" L6 J2 i7 k" s /* Set a horizontal beam l(*v, w) from v to the ultra right */
" m$ w7 X+ k% \' ?/ r w.x = rc.max_x + DBL_EPSILON;
, c% P0 k: W* t6 k2 Y! `, P' t w.y = v->y;
; @3 Y. F. B* x2 J1 m c = 0; /* Intersection points counter */ # Z" {# }- N( k1 t$ ]0 h1 M, Y
for(i=0; i
/ a- B& p% O- H# E1 f# _ { * ~$ p0 j9 @9 S2 I, I0 S
j = (i+1) % np; 9 r$ |- J4 R( s; K- g& _
if(is_intersect(vl+i, vl+j, v, &w)) / Z) d+ K0 ~" C/ Q
{
; O" K" w6 ~6 W' b C++; $ ~ b4 [& ]" B, y- t- ^* f# r
} * T' z3 I+ a. ]) B
else if(vl.y==w.y) 5 ^& g8 h- _9 p: ~
{
1 w% _4 G7 a. ?" U" { k1 = (np+i-1)%np;
`( F' @, e& `8 F- [+ _4 e( ` while(k1!=i && vl[k1].y==w.y)
2 [, n; w _" y" K7 D k1 = (np+k1-1)%np; ' H, Y& o" ^3 m- L9 l0 x
k2 = (i+1)%np; 8 j+ _/ {$ J3 O/ H. U
while(k2!=i && vl[k2].y==w.y)
8 \/ y* Q3 Z- R+ T9 Q# ] k2 = (k2+1)%np;
( h |1 |; V8 ^2 ?" k: ~ if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) 0 l* e+ u; t; H
C++; ; B; ]0 D7 F, }$ A7 g- E
if(k2 <= i)
. E) B/ A3 `% c- m. K+ t! U- S! s break;
4 U. ^2 q- {! c i = k2; , D7 u6 S1 K. b& p" q) L. H
} * D# k3 }% Q% u5 `- q
} ( P5 D" k0 V& a. w
return c%2; / D2 r" ?( [' L7 b
} . o$ r7 w$ ~( Z/ g) w. }
" }) X" u- o9 J* o1 e. f; z/ K/ ?9 |: i" b! u. e
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|