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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
! Y4 G' k- J& C* c& n* z' P% g8 @
8 q0 ^/ q+ }3 A' L 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。' j' l* V2 G* z
" }; Y- O& P# W! v 首先定义点结构如下:
2 ?( T# ?2 e1 [. e5 ?! h% \( \# Y) B# T p! e8 ~+ A% l: M
以下是引用片段:
' G: u. w) v0 G7 T h+ M* } /* Vertex structure */
! _% O& `+ t; x% D typedef struct
# `5 L- X( X+ Q o' S" k { ( m; i. f0 ?# B; X8 G
double x, y; 9 _9 t/ E' P+ V. {. u
} vertex_t; / A: k2 s& x9 m$ o
3 s6 ?* t" O/ ?
( c. y7 H8 ~0 x. H 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
1 |, h0 X3 c" U. O! }( S" R. I" B6 `
以下是引用片段:& a+ B7 s0 y# m! z% I2 \$ H
/* Vertex list structure – polygon */ 2 ?, Q! d" L! V0 }
typedef struct - u* F5 G; a5 M9 x! D) x/ i
{ 8 o0 z, ]! E2 A# T. M+ P/ p0 q
int num_vertices; /* Number of vertices in list */
7 ]! b: b( `! [. r vertex_t *vertex; /* Vertex array pointer */
7 |) s! F, z$ \1 Q4 v0 k* \ } vertexlist_t; % B$ D. U. ~% m7 n
# g& \( L/ m) M4 u2 s7 v) [
6 B1 F, W6 I0 d$ D# @2 R" H
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:) h! z7 C. y( t5 S" J* J
1 v2 y3 x) i+ e* z$ w `* Y( m以下是引用片段:
( o" x# @! M6 }2 Y" ~/ O" K7 f /* bounding rectangle type */
$ _, c V/ L" l typedef struct ' c, F( u8 r5 x# k" @" |/ ]2 N
{ & O* p# A' d4 ~$ S$ P* f1 q% B9 N
double min_x, min_y, max_x, max_y;
& n I8 Y2 T# Q } rect_t;
7 M* Q$ U' z$ E; t- u# `2 Q5 R5 b' Y2 H /* gets extent of vertices */
" k/ H0 ?8 P, c6 s1 o; L6 b void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */ - [9 P4 L) ^9 O* A, M, c: u2 ?
rect_t* rc /* out extent*/ )
7 S4 z6 r/ m+ i+ Z$ {1 _ { $ O0 b6 t# U6 R1 w# W3 L {2 _7 g
int i; / w0 f$ ?& _7 i
if (np > 0){
. d5 m6 d. @) s2 E k rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
- G$ f* f+ S5 _: ] }else{
4 L: V% S0 z# P1 X9 q z rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */ * M6 Y' j+ K% P6 t5 z( y8 Y& U
} $ n& e% Y, n @( ] M2 X5 q
for(i=1; i ) B+ C; m1 d9 K' n6 s8 K
{
. a0 U* l. W% u! f7 c. N if(vl.x < rc->min_x) rc->min_x = vl.x; # `; w- W% | j; H+ q$ [
if(vl.y < rc->min_y) rc->min_y = vl.y;
4 x1 R' q( C3 g+ ?; W( k- }: V \- r; G if(vl.x > rc->max_x) rc->max_x = vl.x; ) w( P" I% h0 h& M/ i( E
if(vl.y > rc->max_y) rc->max_y = vl.y;
, L& u3 V3 c/ k6 y }
& D9 T! _) `- {. q3 P% n: D& K }
$ D, D6 z# ? ?8 e. [- L
* a9 D- }% X+ u! p; ~/ h0 y/ I& N- N
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。; X: e# L$ @) G: z
2 I2 k& X; Q7 g' P9 J) F3 k
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:, J" Y" S* C) c
8 v. u. J+ O3 o
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
] E8 v/ A1 q
) y/ e. P5 X1 j (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;: T/ K! T* k, ^$ l
2 o! `$ P+ i1 A' M1 r& _
以下是引用片段:
! K' S8 ?: b, G4 ^* r$ W$ V /* p, q is on the same of line l */
( `2 V1 N& ]7 G' B* m static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
( B) E" G1 h6 J; V# n' U' z$ k! w1 t const vertex_t* p, * B8 Z( J4 @2 M& d6 }
const vertex_t* q)
$ ]7 q' I [( ^) D+ e { 7 e! Y1 a) y9 G& x p! R& n
double dx = l_end->x - l_start->x;
" Z' F% ]3 e5 f0 W @! Y, S0 E+ K, ^ double dy = l_end->y - l_start->y; $ L! _; p% P& n" D( H$ I& b
double dx1= p->x - l_start->x; ; L$ G7 O9 D' N
double dy1= p->y - l_start->y;
, p7 Y8 ~; k6 ] double dx2= q->x - l_end->x;
- [! z# Z/ V' u! I: E# E4 x double dy2= q->y - l_end->y;
5 O0 ?. W# B4 j0 |5 r return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
3 y. G* |+ c2 r! J5 r1 Y( [. A } , V7 m5 `* o; |
/* 2 line segments (s1, s2) are intersect? */
) \/ e; B" n+ }) Y i static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, / G4 b6 j: u# |+ |- S
const vertex_t* s2_start, const vertex_t* s2_end)
# X* h( f x k. L, n j {
9 t2 A. o7 u$ h' T# c- u0 J return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
; Z5 ^) ^& v2 y; J3 j6 q2 Y: ^* s is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
4 z. U/ i' l( n* B8 S } 2 a- z3 D& n# ?9 \2 ?
) k6 X# H2 O3 s! G: V/ v [- k- I; s- F' H: {6 q+ V" d- G8 b
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
# p/ ]* T5 V3 P: x" R7 F& n
8 m5 B' n& v& w, q# M) x% U- Q- f以下是引用片段:0 M+ ~. n u) Z, U$ @6 _1 A
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
6 ]1 `; u! d6 h+ T0 |& ]$ t const vertex_t* v)
! g" a) x" I y2 ?8 M I( P { ! [0 J: \) n; c, R1 G) W9 \ |
int i, j, k1, k2, c;
) U4 t0 o8 E% V! Z% j rect_t rc;
; O( V) l! Z8 ^3 K: ? vertex_t w; 5 j& ^; M; `3 @
if (np < 3)
3 N. ?. n* R1 } return 0;
5 P5 ^% |( f) C$ X vertices_get_extent(vl, np, &rc);
; n5 z3 W" X; n. T+ H! s if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
{1 i; V. G: f# W- S return 0;
) @3 q( |$ F, z( M- t /* Set a horizontal beam l(*v, w) from v to the ultra right */
" U3 P! ^+ f% O. j w.x = rc.max_x + DBL_EPSILON; ' C0 c) ^8 e3 ` a
w.y = v->y;
/ F" {! {* p& p, O4 L/ H: h# K8 _ c = 0; /* Intersection points counter */ / S8 z! k0 N% c7 O- o7 E5 ^8 H
for(i=0; i % |- _0 `) E- C: R& h3 m( Q+ n( P' j
{
/ x7 ^. Q1 i: K9 I2 Y5 R j = (i+1) % np;
9 \2 @. i$ y& |: ` if(is_intersect(vl+i, vl+j, v, &w)) $ [. C F# o; c' \6 w
{
/ Q6 j6 e% \8 ]1 A( j) L C++;
8 q- u z# X- W9 X' R; q! J, G6 \ } . W4 P7 k0 f. L# e
else if(vl.y==w.y)
& G% z/ |3 _+ ?" O0 \9 A8 a {
9 K$ |5 [" Y( E7 `; |, { k1 = (np+i-1)%np; % ^( A. i+ U% X+ \
while(k1!=i && vl[k1].y==w.y) 3 K. S. v) J4 ~+ h$ b
k1 = (np+k1-1)%np;
6 J7 l+ M4 j, ]8 t# I k2 = (i+1)%np;
( t. O' p" \5 D+ R) P0 Y5 D while(k2!=i && vl[k2].y==w.y) 8 r7 o- \# F6 j. X# M- }
k2 = (k2+1)%np; ' d8 \, g5 _/ |" m, s
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
9 I( x2 V% b% [2 g3 h o: t C++;
1 [5 P! b6 \' r% ` if(k2 <= i) ( M8 N! A5 ^! t' y# @5 j; q
break; ( L/ `+ L+ f3 d! _* P# r
i = k2;
. H3 N- m5 T& d } 4 o% E7 ~4 F2 [5 j
}
. e2 |5 b3 D) R/ l) z$ f return c%2; ) w6 X7 u2 _. L* A& W
}
* R0 h: }! m* L" B/ T; T- |5 A4 G& g9 }/ D3 n) w
1 c% r3 @( Y$ h- {; O 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|