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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。( }& `) {& n, V2 R) e
" p g* u7 R0 f& v* U2 o0 E 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。& W' z% i: X- e* R @
% i7 y/ X4 R: ?
首先定义点结构如下:
$ I( h0 L4 \$ B p. \( l4 Z8 I; V4 b, ^: S
以下是引用片段:8 e1 f6 i* ~6 n6 N2 c9 m4 T
/* Vertex structure */ , p1 l' k% X2 y5 z- |
typedef struct
. p7 f; ^* l% N& M& d# x { 8 K+ n1 U" d* |2 n. l
double x, y; ( ^. W9 _$ Q; b' B! X+ k) m
} vertex_t; ' m; }5 s* D- u! r% m
% ? k) J# Z" c- M7 u ]
: k& M% \( Y" F, K! r
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
) E. w: W E, n f7 c5 q; _; R" N5 K# [- ~# w* _! X
以下是引用片段:
6 L; l0 g' D+ q7 t4 m1 X; u /* Vertex list structure – polygon */ 1 U( ^4 {4 p" h2 l, I# h
typedef struct - I e6 u5 A) B8 _. x: G
{
8 y$ j; h/ g* B2 s5 S, } int num_vertices; /* Number of vertices in list */
3 J O, V2 h2 f3 n9 @4 \& l vertex_t *vertex; /* Vertex array pointer */ # W! J/ q, {* D+ R ^( f
} vertexlist_t; 0 G- `6 _+ a6 j3 u# b( w% L( J7 ]
: K8 J+ [; I- a+ A
4 L5 O6 r, {) D* l; s( }
为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:$ F* R( L* ?7 t+ ~
% G/ z3 H: o( S
以下是引用片段:7 | x2 J l) d% [3 }5 d" a' F$ L
/* bounding rectangle type */ # S7 |8 @2 g0 p1 x' t2 i
typedef struct ; E* T' q" Y$ i# m+ J5 l
{
4 ], Q# a9 T# N# Q4 i double min_x, min_y, max_x, max_y;
+ V& G$ p2 i7 e" _5 Q! [; P$ U" P0 c } rect_t; - w: t4 x$ T1 Z+ X+ x) h/ z4 @
/* gets extent of vertices */ * x3 s0 h- N% I/ B4 M) f, q
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
; o5 N2 C0 X# l8 X, t rect_t* rc /* out extent*/ )
$ B2 \, R3 ?- n3 n% R6 X { - C, o; M* G+ s4 a/ K/ R
int i; ) `* r; x" S" y- F$ a
if (np > 0){ 8 X# J$ f* y( r% Q1 X. r
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
* z! k" U1 P. h' ~2 `" b }else{
, @0 I; y4 b+ E: D9 w rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
5 ^5 A% O6 f7 y; j+ }- m' ~. } } : G5 U1 C4 N7 z) f
for(i=1; i
9 p5 D% j' g0 F1 u( x' u. Y {
3 g g5 H- Q& X, h% {' i8 ] if(vl.x < rc->min_x) rc->min_x = vl.x; & `1 [2 g$ M; ]* y
if(vl.y < rc->min_y) rc->min_y = vl.y; 4 I# v; X# a2 @) H6 x
if(vl.x > rc->max_x) rc->max_x = vl.x;
/ F i# ?4 T) u if(vl.y > rc->max_y) rc->max_y = vl.y; : O: l+ P" A- f8 J$ E% b' Y! W
}
4 b' `' O2 Q9 {2 y, W7 L% f }
! |+ U! \" e* s0 ?& b5 D6 x; A; p3 h& [ o& L3 f; m" L7 k
% A- K ~6 [; ]) q" [) V* C 当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。
2 |3 R5 E0 W5 O$ `$ G3 l0 s5 b) X, @$ L* ~9 N/ l# E' U1 D7 R- q1 k
具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:7 G2 K4 w+ A7 ^9 `6 D
& U4 c4 U' n; }+ ~& L1 G
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
1 i$ W2 x6 W: a& _9 u$ J
* M9 V J# d' @5 A W7 B (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
! m* b n; J- @
& m: k6 `# o5 d以下是引用片段:- q' W8 W3 W* }% x5 |
/* p, q is on the same of line l */
8 I: y8 J- \# C static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ " g2 l4 q1 L9 x/ h0 J3 j
const vertex_t* p,
& J$ f0 I0 | [, j# L$ V4 w const vertex_t* q) + ^$ K9 B% f1 k9 T
{
7 |- E0 D- Q' H double dx = l_end->x - l_start->x; . ~/ s, v3 z% `/ B( i$ U: @6 a
double dy = l_end->y - l_start->y; 6 `% m# b8 I5 R8 s& [
double dx1= p->x - l_start->x; 5 o- }% Y+ e' g" H
double dy1= p->y - l_start->y; ; A% o6 N4 o: o6 q+ m( G
double dx2= q->x - l_end->x;
+ w& q, }$ I9 c8 \ double dy2= q->y - l_end->y; R( p0 q2 n3 F
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
) H/ R4 r- o; D3 @8 p. m } : v$ e6 E+ S& F# R3 u e+ Z
/* 2 line segments (s1, s2) are intersect? */
/ a3 F* X9 J d5 V- w) s static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
( e7 |: v) F$ p; j* _' a) r const vertex_t* s2_start, const vertex_t* s2_end)
# R9 ^+ D% o- F9 ]# L4 f' x8 f { 7 ]9 l/ b$ e, z
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
8 a) X, C0 d, m is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; * x8 h' E* [. B% j1 N" _+ i
} 7 ~ s8 F8 N n1 V
$ G2 {9 ~) R, T8 g9 _) B
8 g0 z$ ~9 v: j; o* D) V% m7 k
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:. B0 ~8 k+ u. F! W
; N8 g1 g8 N% W, p' v以下是引用片段:: s( t* x! O: u# ` @# V4 a
int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ ; v, k J6 t' \) ]) a
const vertex_t* v)
! B: G0 l; G- p1 I z { % U! U) C5 k9 b" Q0 e9 A
int i, j, k1, k2, c; - c5 {, u+ o0 ^* V6 |; P V5 p! P
rect_t rc; " H9 o4 `4 D$ l* k; ]4 s& `2 ^% B
vertex_t w;
- s, j+ m8 F& H1 I, R* v if (np < 3)
2 \6 S @. U( e return 0; 0 d8 j8 F- T: X- ]3 d
vertices_get_extent(vl, np, &rc);
a- X( P# J) I* M if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
% ^7 k; s( R0 D& G) ^; z return 0;
4 ~* b" K( k- ]0 ^ /* Set a horizontal beam l(*v, w) from v to the ultra right */
! N, }, h! G d- O9 W$ y1 w1 N w.x = rc.max_x + DBL_EPSILON; 1 w$ C: F- a: ^4 i1 P
w.y = v->y; ! P$ c$ c! x+ s
c = 0; /* Intersection points counter */ 7 y! {5 v2 v4 S3 o8 N
for(i=0; i 5 Y4 f+ |( y/ [8 S/ }) \: i+ d% _
{
( k3 b# y( t4 p j = (i+1) % np; 0 {1 L6 ]' L2 l; d( T4 A
if(is_intersect(vl+i, vl+j, v, &w)) 4 g. b5 `" Z' M9 K9 k) ]- J, b, k* ^
{
0 ^. \& j6 a& ^& N! Y, Q5 T, d- j C++;
0 o* w& z/ O$ F }
' j' C% z1 s5 T- c else if(vl.y==w.y) 0 M/ z* j$ x+ ^3 f; E
{ 3 `: a+ } [2 n6 t+ `4 ^
k1 = (np+i-1)%np; $ V7 e, k" H- _3 G% E
while(k1!=i && vl[k1].y==w.y)
7 q! j, p5 L& c8 Z- r- P# G7 B) L( J k1 = (np+k1-1)%np;
1 ^ C V0 \. G, u; u k2 = (i+1)%np; 3 ~1 V6 L2 D0 F) }6 k
while(k2!=i && vl[k2].y==w.y)
2 `1 t7 U! m' Q8 X! P k2 = (k2+1)%np; , O8 Q% e4 G' K) D& H5 R' X9 g
if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
. }' B& E$ z, _) J; h4 f5 e; N3 [ C++; 7 y$ }' @0 \4 z1 w9 e4 u5 y
if(k2 <= i) ( h9 w' M m: U" A5 u- w% i" }
break;
( J* }* E& T" v# J N i = k2;
. s" E8 W/ h$ I' |/ M, B }
) D( W$ @0 h% l- h& Y }
6 K3 u" T; o8 q& ~% J$ P return c%2; 3 S" y) q! K* v1 o" _: F
}
) h7 q' L. y0 y
7 {1 x. G& x4 |+ j( B6 _% I% ?# v' R1 I# S2 `3 W1 B
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|