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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
' x' i' ?6 h, w8 s3 c7 e/ n+ E. @
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。- l* t! I, ^+ v3 ~- S# i) b
* t3 E/ Q; G* K$ Y1 x- W
首先定义点结构如下:
' Q) `0 ^; P6 O9 v% i8 H" ^) A3 w9 I: e* F6 [7 z
以下是引用片段:
. X4 }2 k+ ^) h /* Vertex structure */ 5 J5 ?9 a' ]" w4 s; L
typedef struct
* l" l2 B b: ]* p5 a4 ?1 B {
. S9 L$ Z- p5 Q e+ G double x, y; 2 O8 T! p- R+ `8 K
} vertex_t; * [3 ^' z8 Z2 D; _, I2 B8 [% j
2 H& a2 X) W! e: m7 I
1 D' J# C/ {; B4 p/ w. a- M. p
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
0 e; }3 ?8 V6 c/ Y1 M- q }' _6 d
1 M# A0 v: W) j以下是引用片段:
' e# S& {$ a5 u% x /* Vertex list structure – polygon */
* V6 ^- t( G+ E8 `6 } typedef struct . e P2 _; d2 H( b
{
7 M( p" A& ?" q/ P int num_vertices; /* Number of vertices in list */
! }" u' [; D$ g/ N+ p# ]* j vertex_t *vertex; /* Vertex array pointer */ 7 D. D6 B4 Q) r+ |
} vertexlist_t;
( k" M' _2 k- e, y
# I) r2 ?9 ~6 `, V
2 e% G9 M# D) `. H6 z) V, K 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下: ~3 n# Q+ U2 j% v8 f
8 l4 m1 k* o9 ? A; z, ^
以下是引用片段: Y8 D+ L' W2 E. q- `% \
/* bounding rectangle type */
( J- I j) W2 k0 a" A- J typedef struct
( {' R( B6 F% g. L$ Z { # G* |0 a0 N# H$ d8 E z
double min_x, min_y, max_x, max_y;
; U. A( c4 I! T) f% M2 r* x2 g } rect_t;
& b# s/ V) n( {1 | /* gets extent of vertices */
# ^) S9 x) Q: {4 n2 C9 a void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
6 D$ i3 q8 W0 {, c rect_t* rc /* out extent*/ ) $ o: _( r1 g3 y% d5 g5 \+ K
{
' x2 b4 o5 @0 G1 _$ k8 j int i;
! o4 a6 a5 k; i! ~% d. a0 O# s! R if (np > 0){
6 |: _3 H9 [% J0 h3 B8 ^% s rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
$ y1 c6 k* v( ?# X8 I }else{
! x* k( t$ w0 y9 X, c. G1 l rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
, y9 {0 ^8 K w5 b } 6 M. m: |' K1 T6 d% f0 z( z: e
for(i=1; i 7 J6 G( x/ h3 w% R3 s
{ * E9 w* m9 i; z. |7 `
if(vl.x < rc->min_x) rc->min_x = vl.x; ; J( p& a% S2 s! X; I. E+ h: G) X
if(vl.y < rc->min_y) rc->min_y = vl.y;
- O2 t g4 c6 L/ j8 t8 O if(vl.x > rc->max_x) rc->max_x = vl.x;
7 B- V7 p4 i r8 i { if(vl.y > rc->max_y) rc->max_y = vl.y;
2 n9 ]! b$ P1 S } + w( u/ q$ j; @% [" V
}
& W/ A( q$ k( c" B* }' u
8 G' J0 E/ }8 k6 t9 T
- i2 o: a) R( v! a+ w3 @) |9 A4 q 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
" \) `3 V6 ^. r8 @" V: X8 J! B" q1 i) s1 V4 [: f7 a
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:$ f) Z" O4 U& S" }' q
6 J6 e/ o. l6 Z- k! e
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;! W: c, g5 Y3 H
5 w4 W- `" i& T. ~. a6 R: U (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;. n/ I7 Q( l# D) W% Q6 w
j' z% F! V Z3 n5 V" l
以下是引用片段:
* _' I# b1 H7 y/ D9 T3 P& { /* p, q is on the same of line l */ 0 U C- h3 b2 G7 x
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ - ^( v* k, w; c8 T* H! ?
const vertex_t* p,
. Q9 O- f% A7 ~# X, \: l const vertex_t* q) , h0 S7 b5 g4 i" d- T* V( B# n/ _
{
3 M* F H* f' w$ k( D double dx = l_end->x - l_start->x; 1 u) g9 Y* s0 _* u% R
double dy = l_end->y - l_start->y; ! l3 o6 r3 G$ G8 L2 }
double dx1= p->x - l_start->x;
! O# r3 }$ S$ L/ ~6 L double dy1= p->y - l_start->y;
- K5 P2 y9 I. B; Z7 d- }" s double dx2= q->x - l_end->x; * h; h- @# C2 }! F
double dy2= q->y - l_end->y;
' ]( A. K6 A$ G return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0); X( c3 H' w5 K" y
}
/ Z/ j/ Y e3 g( N+ ~/ r" h /* 2 line segments (s1, s2) are intersect? */
]( j( c2 B( m- t3 A* K static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
, Y+ q {. u7 E' J const vertex_t* s2_start, const vertex_t* s2_end)
$ H4 `8 f6 @1 j { : e! ?; @; Q7 S
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
. Y- w! L( o+ D: A7 u( y* p is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
* H( K$ w4 J8 i& @: o w& H }
: Y% Q# Q( k: C/ c- y7 t2 x1 q1 Q: [% D/ u: A5 \: L d
" Y3 x+ U# Z: H' |$ n 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:- a8 u& @8 I. R4 q* D1 z
% J2 n4 ^; B% H4 c' J0 z
以下是引用片段:3 @$ d5 M; `+ G6 L8 ~$ E5 s
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ 0 M* s3 o9 J7 k* R: T0 F4 F
const vertex_t* v) & z4 J# P- y$ f% Y8 z
{
( ^" A" Y h& y q* z int i, j, k1, k2, c;
; I- m1 K0 f: w rect_t rc;
8 D% ~) O9 K! U( s F vertex_t w;
4 D8 J' Q' @7 A7 c3 @4 O$ p if (np < 3)
1 O% J6 a6 Q% k, _! n return 0;
7 e' N2 g0 G* I% ]: F; R0 d1 I vertices_get_extent(vl, np, &rc);
) b% i( P6 E$ t$ U if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
( P4 X4 C7 R0 f6 ]% J# N0 B# c return 0;
. K u6 b/ {& ~% y- T) s* ^ /* Set a horizontal beam l(*v, w) from v to the ultra right */ ! _" D. S# x% R+ F
w.x = rc.max_x + DBL_EPSILON; ) z- L x: [3 J" Q/ x; }: S
w.y = v->y;
$ |- | k/ E# k* W+ ~: S$ c. z c = 0; /* Intersection points counter */ 3 B9 P( w$ k A# V. D
for(i=0; i
4 v/ E# b' \- u! U. ] { - d, p Q4 \2 z
j = (i+1) % np;
& }9 d. e, `! Y. e if(is_intersect(vl+i, vl+j, v, &w)) * V- @$ ]# y L* y
{ % ]9 ]2 c* K& ~" D5 w
C++;
9 F# x8 |6 k+ u- z } , ~$ d; M4 t" f/ m" r$ h
else if(vl.y==w.y) ! _# J# q" a8 Q( q
{
. y1 D; e! G& p- P+ M! a7 _4 } k1 = (np+i-1)%np; ( ]0 w1 ?6 `% S3 r1 L
while(k1!=i && vl[k1].y==w.y) ; l8 W5 P* P5 R, e! v
k1 = (np+k1-1)%np;
9 `! r+ b, N- f \9 | k2 = (i+1)%np;
7 `! s9 o( t% Y2 B0 x while(k2!=i && vl[k2].y==w.y) " C8 x6 [2 M: y# b. @: p3 u* L; ~
k2 = (k2+1)%np; + [0 M! [' V& R% e$ M' @
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
' v4 ~$ h/ n8 p% T. d/ { C++; 7 C/ H; h* D+ O6 v4 o1 |) {
if(k2 <= i)
( c, F! ^) e* u# I! u y# k break;
: h: p9 [6 U( ~3 k1 M' L7 ^ i = k2;
* A" E" i) x) t/ Q" u6 x }
: P. o: p5 F+ \! A6 N } : t& Q L# D) C6 I& V# e9 [
return c%2; ! `3 h8 |/ E4 \0 K% ]2 f
}
& u* {/ l0 r* i9 N. T0 @% k) h7 `3 {! |3 {- J
8 g3 `8 L: A- b! x: t3 p; i 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|