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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
+ K. _8 q0 H2 d `/ T1 |) o3 N
* w. b7 r+ ?, e) c. \5 A9 L: n 这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。# a; ?* l! _* Y- `$ ~
4 z! B- u. C' I% ^8 x3 J2 Z
首先定义点结构如下:, C$ V& E9 { u) l" E# u; K0 q/ O3 X
Z5 ?' e: s- B7 M! n7 T3 j4 B
以下是引用片段:3 ]6 ]2 J D/ L$ }) p$ A+ O
/* Vertex structure */
" @1 [1 ~- N3 R typedef struct
. u: H( ?: D" D/ _6 A) [/ M { 0 o- b6 N+ J& _0 B ]
double x, y;
& D- ?0 k7 q' b$ m. f0 I/ i8 | } vertex_t; ! r# V6 S- M5 G5 D9 t
" d, a0 T6 M, s2 h
; d% s: s% c" X" l( Q, w! p
本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:1 l- b' o. R! I* d: L0 p
- g: Y& G9 T2 u0 T2 K2 p以下是引用片段:
% k7 l0 R0 q$ n% n+ d /* Vertex list structure – polygon */
- `+ Q) q# L0 i1 N9 l. F typedef struct 7 c3 y7 t7 Q9 q, ~3 ~( A
{
+ A; R+ I1 _& ^9 u# L1 u8 D# n+ ` int num_vertices; /* Number of vertices in list */ 6 V! i' `' \5 t/ q, ?) m
vertex_t *vertex; /* Vertex array pointer */
' Q; t! E* K; T, | } vertexlist_t;
) k, w* ?6 u$ Z4 D# y, w+ ?$ d/ O$ W) a3 q7 J% K/ d
% U; l& S- D6 U1 A& m1 | 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
- n0 n3 N: c# g U; S w. Q7 [8 R
: E8 p0 X8 `+ K% {2 m x7 P1 n4 ~以下是引用片段:
. g! A4 C. |5 n8 C1 d9 T6 \2 z8 E' U /* bounding rectangle type */ $ r5 i' q+ ^ L# X5 u( M
typedef struct
8 G5 K! g" x4 ]0 t$ O, d { : L6 u! ~' Z) j b N4 G& n5 T3 Y' f9 {
double min_x, min_y, max_x, max_y; 2 ^7 [% z S2 U+ n4 n
} rect_t;
* i5 F5 u3 _. O" Y. T /* gets extent of vertices */ f' s/ T4 \5 J$ h
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
. B. P5 y1 ^! M3 \8 J1 B* E \) } rect_t* rc /* out extent*/ )
6 e+ p$ s! Q3 N- d { $ T: u- g5 ?) r- h
int i; - @/ E7 k8 M2 T) C' }! |
if (np > 0){
5 P N! W/ g' r! X/ o! B rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y; 1 ?. i* ]; _# P1 E& R6 G$ [4 n" M$ N' H
}else{
1 V0 @7 K8 b7 `- j/ \ rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
, `8 F8 L1 q, M: D2 @# l( m } ; o6 F; I- Q( k5 [
for(i=1; i
# ?) h; R0 Z- I# c( ?& L { ! }2 y) d& W/ K2 W+ [
if(vl.x < rc->min_x) rc->min_x = vl.x; " _- l0 c- u5 a* j6 Y% L% N
if(vl.y < rc->min_y) rc->min_y = vl.y;
& ?5 [* a5 A! |' C if(vl.x > rc->max_x) rc->max_x = vl.x; " Q! |/ V: ?0 @8 W
if(vl.y > rc->max_y) rc->max_y = vl.y; 5 _9 M7 ^8 \$ o9 F1 V+ S; H
} / [' S* O+ X" [$ ]
}
# d: _5 o1 x/ b4 _ `$ c2 i' b$ w4 B9 ^
6 O- U! l7 U4 I1 L! T8 F
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。/ X2 a$ A9 X D# F0 p2 d
- i$ v) m% G, L( H" l4 U 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:
; X. u# ^+ {% D% _4 l4 ], O8 D# ?$ r/ r9 P1 j
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;
, P' }: | s0 G+ j3 V8 ]0 q/ o) h3 u: j" G" |9 ]
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
8 k) o. L; O2 N$ R& b9 a7 w2 W( H, h7 Y0 X" U) O
以下是引用片段:9 @7 b4 g; f( Z( r8 o# n
/* p, q is on the same of line l */ 2 J0 J- v! v; [& }
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 2 r2 Q3 H6 @9 d( e: P1 f
const vertex_t* p, 4 _+ l3 l3 y6 T+ Y2 u3 q6 D
const vertex_t* q) ; f8 ?7 q" w* g9 I5 }
{ ; {( v6 E) R0 i0 A- R
double dx = l_end->x - l_start->x;
7 j" O9 Q" K4 Z5 l double dy = l_end->y - l_start->y;
4 H7 a# g# u P# I double dx1= p->x - l_start->x; 3 Z% t! y! N# @7 f! Z
double dy1= p->y - l_start->y;
# \3 b( i6 B, e' x Y+ H) }5 N double dx2= q->x - l_end->x;
% Y8 k) W2 i. z double dy2= q->y - l_end->y; " G" M' x0 u J1 Y4 e
return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
$ \7 A. w( Q3 z" Q* ~ } 0 D& ^7 i1 Z$ x: E
/* 2 line segments (s1, s2) are intersect? */
& _& G/ o& d5 `7 C static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end, . S1 Z& ^- Y$ U* r/ M4 `) u% Y
const vertex_t* s2_start, const vertex_t* s2_end) ( P+ v/ R2 d6 j8 C5 L/ L9 f2 b
{
) Y( W; C+ w# A5 J3 a- ^% N2 Z return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
* J+ e: U9 u) i& Q) Z/ H is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
$ ~& V% }% T$ T0 b& ?) i } + p7 B! k" p" X+ ]7 O
3 U8 A; ?' U ^$ {7 F0 V) t4 y/ y" E5 x
下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:/ u4 }" Z& Z9 ~. h+ X) S
. Y5 R! p9 p* t$ m& C) X: d
以下是引用片段:
. H W+ l& u3 a- t1 z* m int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */ ' o( ]% H2 o, ?5 {% E
const vertex_t* v) ; q- R. Z4 f3 C. f$ Q
{
C7 b/ x# L; W int i, j, k1, k2, c;
$ p1 a( F% b. z) B! q, @ rect_t rc;
2 G- |7 ?: z) u1 }2 f7 I5 `2 ]/ @$ H Z: X vertex_t w;
" `9 ]* J6 ^- j+ E if (np < 3) / q. |! ~, k8 m( _( N
return 0; ' m8 |; i" j& y4 n$ o3 J
vertices_get_extent(vl, np, &rc); # H$ g/ [2 M) {8 R2 R
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
4 D* u/ l* m! [ return 0;
, ~8 L- w2 d {5 a /* Set a horizontal beam l(*v, w) from v to the ultra right */
$ Q( Y% {* J: }- d$ U w.x = rc.max_x + DBL_EPSILON; 1 a m& k! m: f+ H9 x) T$ S* |
w.y = v->y; % P: u) Y' a8 `2 \! V$ |) v1 N5 L
c = 0; /* Intersection points counter */ 0 `: I6 {* f9 w: X h1 [
for(i=0; i
! Z! ~2 f" r- ]9 |2 g3 ^ V Z { / n: _/ I" d3 s7 [
j = (i+1) % np;
9 P- L8 t5 N7 X' N if(is_intersect(vl+i, vl+j, v, &w)) & G. p$ d. P: r! m; I/ r
{ 2 |& B+ D: o; b3 _2 n
C++;
- Y0 K9 w- V# [ e! y" J0 V }
/ A1 a4 T+ V% w' ?' s& T else if(vl.y==w.y) ' y2 M) |0 |0 j; x# D1 }
{
" Z2 j5 r: z' ?( {, o) m, a k1 = (np+i-1)%np; ) D9 }6 f# l. Q9 E7 f# W9 ]
while(k1!=i && vl[k1].y==w.y)
" a6 ?) J% ~$ G2 K9 v$ \1 x, S k1 = (np+k1-1)%np;
- ]6 _; x6 t4 u$ D k2 = (i+1)%np;
9 m+ c$ F" `6 B/ I3 X while(k2!=i && vl[k2].y==w.y)
5 {! s V' H% E k% D k2 = (k2+1)%np;
0 \' ]7 u" e) g1 {& K2 } if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
: Z+ s% n( I$ F6 x U, U/ ]( ] C++; 1 r W" E8 v; L6 m% {3 }
if(k2 <= i) 2 `2 t0 ^3 D+ p9 A/ ^
break;
* U2 d6 t0 ^+ U' |, Z% k l* p7 x3 e i = k2;
0 d$ _. z6 r- O3 d3 T# c9 s8 f }
! H1 {7 J0 U& J1 ^1 t } 3 G+ t! n" s5 N# o2 i5 ]6 P
return c%2; ) i! ?& u7 z% R3 b& ^& m1 k9 {2 q) y) i
} / V! S& P# w3 [5 Y
' A8 E4 d& B2 C, P6 G" ]. n) n9 ?' {+ l3 ~+ V5 B2 L
本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|