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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。$ E( ]" [( S6 T% N" Z7 L
9 D/ _- K: I2 {- L" d; {) G 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。" g7 D7 G2 k- @: N1 ]
& |" w! A0 B1 F6 a5 n" j. f0 X
首先定义点结构如下:
. \. s- g) I9 k6 u. M C/ r/ g& J8 g
以下是引用片段:
0 G9 M3 a0 y; J8 J2 a' ] /* Vertex structure */ 8 ]9 N& d9 G4 w) m$ {) x) R! x
typedef struct
# ?. x* Y9 o) p( T/ j! s! ~8 X2 S0 K { 9 v4 `. Q) F# T5 c+ ]( ?
double x, y;
# d# h6 z. x1 S/ X; S5 w } vertex_t;
9 o, k, y+ g: Z* m0 O, {6 s. n
+ ~1 |# @* j) |) K/ \; j8 B ~
! p; W$ ]$ F6 M$ M8 | 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:1 a0 a& i4 j3 I3 _! v
& x* ^* A" A: P1 k- p' u
以下是引用片段:
; v3 e3 `, V9 m0 U5 l$ W /* Vertex list structure – polygon */ 3 P+ V3 [+ u6 g7 Y
typedef struct / m( C7 s) b$ Y/ u9 Z- K
{ ( b) t/ g8 U, V
int num_vertices; /* Number of vertices in list */ / M! K2 J, }! R: q8 H
vertex_t *vertex; /* Vertex array pointer */ / \! h/ g8 D- ~6 g: y
} vertexlist_t;
: s8 M+ z) ?# t6 _% u8 y3 E7 J* o0 X
& T" o- m5 x P" v, ^8 B 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
. v( }# {2 p2 V; n7 p7 L6 G6 l5 }& Z" i2 X5 x3 u' G, q
以下是引用片段:4 \1 d" I/ q* c: s ?
/* bounding rectangle type */ & B0 d `4 g5 H
typedef struct " s/ m/ K5 T" m) u9 C4 Z
{ ) H5 o* M1 ]2 f
double min_x, min_y, max_x, max_y;
* ~) o: ? N' ~( u* b8 s } rect_t; 6 H( G4 B$ r. y) b! }
/* gets extent of vertices */
. _1 D9 Z' @+ t9 t: }6 G void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ 0 o2 |& d( g9 V5 ?8 Z9 K
rect_t* rc /* out extent*/ )
l3 c* r9 {$ d( z$ I/ l( d) w {
g; e7 ?. l6 E int i;
; n( C5 S6 s- f7 C0 i" e5 r if (np > 0){
! h8 u8 _" Y) P: w3 Y rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 8 |- f8 ?& J. D1 m: l; m0 t% J
}else{ ! S8 a3 k) c7 _
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ H' X% @$ c/ m2 n. _
} * e0 I9 V. Y# u6 A: b" m
for(i=1; i - Z+ o n$ C& r/ z; @* Q" I
{ 0 S# Y. s" g7 j- j- w# A# z0 y
if(vl.x < rc->min_x) rc->min_x = vl.x; ; e) G1 `! g( d8 g5 ]( E
if(vl.y < rc->min_y) rc->min_y = vl.y; V$ J4 z8 h; _
if(vl.x > rc->max_x) rc->max_x = vl.x; # m* H1 i# J; A2 ]" I g* A
if(vl.y > rc->max_y) rc->max_y = vl.y;
0 ?" v/ ]" ]. T. s }
Z, t$ L& M" U( D# g }
1 U5 J$ R9 Z- e" W& U' r* U" ]# x$ W& g' g
. V) H& D0 g5 |
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
2 K3 C$ v' O& J* j; x! t
) y! s: K0 a$ K6 x( }% g: M 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
: i. Z* I3 y% h2 I
; a- B0 C8 b# P# [) [ (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
) U; P& b/ W! V) |- ? ]; A( T' D1 @
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
# q( i) J1 b' f$ k1 J
4 D$ @ {* E. v/ C3 C$ j7 u7 s1 b以下是引用片段: G( I# a4 o0 _+ A
/* p, q is on the same of line l */
( N3 a# O$ t& | static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 0 F e7 Q8 z9 M0 T, Y
const vertex_t* p,
8 k& ^0 g( B% n const vertex_t* q)
4 n/ `. v; v4 W3 T7 V, Q { ( L6 P7 E& T; P$ Q9 o9 p% v0 C5 `
double dx = l_end->x - l_start->x; % |( a! g$ n" U' ~3 ]8 r' v' k
double dy = l_end->y - l_start->y;
3 t9 \9 s" M7 D# }# u double dx1= p->x - l_start->x;
, }9 p7 ]! P: S double dy1= p->y - l_start->y; 7 t# G# [" r/ u
double dx2= q->x - l_end->x;
5 s T: {3 w0 x: R( _5 B9 B double dy2= q->y - l_end->y;
- l+ [4 Z1 @7 x4 u0 J6 N( } return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
$ I: D$ s1 A9 B% x; f } * ?+ v: ]7 o* q# G! n9 m+ F3 `
/* 2 line segments (s1, s2) are intersect? */
7 p5 X4 U8 \9 h4 a* e& q; n4 l4 E static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
5 g0 I1 o0 z# P3 i; t9 m const vertex_t* s2_start, const vertex_t* s2_end) 6 r( X( b1 U: t/ ?2 g
{ 4 m# S3 ~; K* N; u2 B% o
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && 8 z1 i |! S8 m! e- v4 P, n/ T" ]
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
/ V' q, W6 r: u9 h } " o5 _; ~" x2 w% x' O/ M
; Q$ q( p3 ?% t' [5 `
2 E, y0 W% G5 _0 U. Q- s) P: C( a% H0 A 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
N; \5 k$ S& ?) Z' ^" x9 q
8 _6 l- J# `# s以下是引用片段:2 A( L3 T# E/ Z' b' j
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
3 [* H' } @% W; Q" `$ O9 V const vertex_t* v)
2 h; Z; Q4 u+ b3 v+ Z( G {
5 E& {/ g( h" w6 V$ j int i, j, k1, k2, c; 0 B& U" U+ ]: ~! z5 @
rect_t rc;
* s* H. Q4 v6 M6 o) Q1 T3 ^. f vertex_t w;
; Y( j+ U Y4 K6 n if (np < 3)
, [* M$ L" ~; V* J0 I$ x return 0; 2 @1 u7 y$ J# @% G0 o
vertices_get_extent(vl, np, &rc); 9 ^1 [, N4 Z8 H# u$ z
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y) * ?5 I4 J/ S+ t
return 0; * N+ I, l& _4 Y
/* Set a horizontal beam l(*v, w) from v to the ultra right */ 0 h% T* ]8 g9 s! V( L4 i
w.x = rc.max_x + DBL_EPSILON;
& S% x1 x8 ]1 V( m( d+ | w.y = v->y;
, n' x! R$ Q" a( h c = 0; /* Intersection points counter */ 9 q }! f4 ~% v
for(i=0; i
+ [: Q# a! o6 _( K0 z { ! V* a# \5 i( J9 _" K& I" \( O
j = (i+1) % np;
5 l) |+ C" o. \ if(is_intersect(vl+i, vl+j, v, &w))
5 d+ A" }# X7 y) ]" \- P {
5 w4 p/ a6 W% {" I; @ C++; " Y2 N2 z# D6 t
} : ?0 V* N1 [$ w; s! ?6 X7 ^
else if(vl.y==w.y)
- Q2 y/ m% ]8 ?5 e e( \ {
3 } B- k* e, d1 R+ W k1 = (np+i-1)%np; 3 ~5 m3 x9 n) @# a4 k" X; w
while(k1!=i && vl[k1].y==w.y) 8 F+ V, |/ R$ N! h2 {6 c; j+ ?
k1 = (np+k1-1)%np; 6 ~0 S' W" C7 X j& t, Q5 q, I. N
k2 = (i+1)%np; , M, U6 h, Z0 ?& l# z' n7 k
while(k2!=i && vl[k2].y==w.y) 3 j% I; x! z3 X
k2 = (k2+1)%np;
! v4 Q7 ]9 R9 J7 k if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0) . B1 i% h8 [2 H. j0 Y' H+ w
C++;
3 n s3 ?" ]) m6 W. `/ [ if(k2 <= i) 5 r& N' a2 A8 l7 X+ W; ?
break; 3 y) a! _; u+ p' l/ ]1 j( D
i = k2; 4 M3 N! R7 \ Q" b% e
} : [( A$ b3 ?- F7 j
}
% Z+ H9 ~0 k7 }5 u2 X3 G5 @2 ` return c%2;
% G1 e1 o1 M$ p$ I5 M }
0 f. }0 U+ X1 I, |. Q8 q0 d- Q/ U
0 t+ t! J7 U* I9 V' b5 P) J; i$ `3 a
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|