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

|
C语言中显示 点在多边形内 算法
本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
5 \6 ~3 B0 Q, L" M% U! v4 Y" f F
这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。- }) a6 a/ Z1 U
2 T3 b4 \, g& j9 D, ? j& f 首先定义点结构如下:
3 y& b* G @" E$ g9 m& U* p1 `3 |9 p) y" x) \
以下是引用片段:- S% r5 i$ B7 \
/* Vertex structure */
- S4 D8 C3 U! P% O* X& ` typedef struct
( a" R0 Z7 ^4 z9 g1 j {
3 c9 p1 w* t7 v- p" u- r double x, y;
! C& b/ d! n F6 ~& U+ \2 N4 g } vertex_t; : ?- \# v' a3 E7 c s
8 T/ w$ k6 H. K
' K- N. m' F' c, O 本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:2 ?, u+ U5 M9 n3 q% P# o+ n% y
$ @3 Z a3 c t: A$ J以下是引用片段:
6 l& @8 K) z# @; p& k, A& M! k5 t /* Vertex list structure – polygon */
- K2 Q/ P+ T( R! G typedef struct $ V/ p( q# m/ Q6 V9 i
{ . v/ h; o `, q: g- J8 a
int num_vertices; /* Number of vertices in list */ ! s" O/ u ?4 I) n& `6 w
vertex_t *vertex; /* Vertex array pointer */
0 p: m. y L+ t# z# F' { } vertexlist_t;
* @6 X! ]& W* k9 d
7 b: Q( ?/ F, \; y. p* B
) `/ P/ l, k/ x$ L 为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:
; H+ T' ^" i- [3 U, A2 j
3 B% `! M" v* d& c1 J5 J; ~以下是引用片段:) k2 D8 k8 C. J5 f
/* bounding rectangle type */
' e& z+ ]+ L! k9 r1 u7 M typedef struct
; H* e& p! x: E. r' o+ | { - M6 ^. V/ C t/ {; l; I: @/ H
double min_x, min_y, max_x, max_y;
6 n, A: \; R! \ I2 i6 n } rect_t; 0 a, B3 w% E) O \
/* gets extent of vertices */
' ]; |1 C3 T- o* ~( r0 J; s/ V& ` void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
+ w) r( \2 B0 X rect_t* rc /* out extent*/ )
( R* L1 r; t `4 j5 P) r {
$ s' m( J6 m* m3 _. Z$ a, X int i; 9 G% {/ a* `1 T: u3 K
if (np > 0){ 2 l! i, j0 Y3 Y$ E* \% z
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
1 G0 m, w' j5 ` Q. a }else{ & v: c! v8 q6 f' n# t( s/ e
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
( ]% @2 J2 O0 U0 s8 @ }
- A& f+ H( V7 A) j5 S5 F for(i=1; i , @5 Q' }/ y: a
{ q( V6 Q) v; P. q
if(vl.x < rc->min_x) rc->min_x = vl.x; 3 a) z: J8 G0 t, @9 C
if(vl.y < rc->min_y) rc->min_y = vl.y; 7 R& [2 x3 i" r/ Q3 T" {+ O
if(vl.x > rc->max_x) rc->max_x = vl.x; 7 C. S. T5 D4 m# h+ G
if(vl.y > rc->max_y) rc->max_y = vl.y;
8 D# @4 X: _) ?9 Q' l }
& m9 J X1 B& v: y } ) `% D8 c ], a" i" T
$ x. T* f1 N3 a* p b( x; ~. b( i* E+ \6 g' Q% j. c
当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。+ M5 J1 }6 C% }0 |9 p- O
* }0 O0 U6 O, X$ X* {" s8 e5 d 具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:, M4 U3 ^ K, A# h3 _8 ]
* x0 i- x! T! u
(1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;& H) [1 m; b' D: [
( i) W& c& z g# ~4 o8 I/ j/ ]4 R
(2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;
: D+ T5 x( X) w# `$ B$ h6 k; j' e; D! D
以下是引用片段:1 y( q$ I8 L+ n+ P% K
/* p, q is on the same of line l */ Z) j4 T0 Q2 g
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */ 3 P" B9 t9 {, f
const vertex_t* p, , s, r9 B4 P% n, V/ Q$ i2 [
const vertex_t* q) 0 F4 U% G+ R5 h! J8 v" p
{
3 t- B+ }) C. m% {+ h double dx = l_end->x - l_start->x; ) z# p. r2 ~0 W- L" Y
double dy = l_end->y - l_start->y; 1 M; F6 b- D" N; ]* o$ m
double dx1= p->x - l_start->x;
3 O5 T4 H0 e( [ double dy1= p->y - l_start->y;
3 `4 o4 k! u: v& [1 F2 T( r double dx2= q->x - l_end->x; $ U6 q7 ~0 ?5 v2 v. R
double dy2= q->y - l_end->y;
, H9 Z6 @1 I$ g return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
4 d0 \: A! h* s% q% X }
6 F) _' g. }/ g% L" q* @ /* 2 line segments (s1, s2) are intersect? */
. ~& k; ?5 i( n7 I static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
q0 h e* t8 N+ @; N; y0 t const vertex_t* s2_start, const vertex_t* s2_end) + H; E7 Q% L$ x6 y9 I* s, w3 z5 X
{ 4 o5 F* Y0 F7 T' ^: |# G3 w
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 && i( Y$ E, Q$ Z1 q/ i1 }
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0; " g3 N& b k. z/ T. j' v3 J" _
} $ D- s8 c% p! l5 g$ K+ s
: X- S! W N8 r& N. \- g+ R
0 E0 \$ z/ A2 `. J( T 下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:7 o. e1 b+ l6 \( A c: X6 c" k8 P
x. j% b3 F+ A: c! ~( a
以下是引用片段:
% Q+ Z; ~: v0 B int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
5 [6 L) A- p; | _% {( U4 {7 Q: u const vertex_t* v) . c; i2 b6 O2 r/ X" P
{
: P4 a! L& n8 F: z- j int i, j, k1, k2, c;
$ x, y; o- l4 Z1 J: b$ a' w0 u( s, W2 I rect_t rc; " n, c+ Y+ E. I2 q8 o
vertex_t w;
; G, u2 m, R" ]7 z2 K3 o5 Q if (np < 3)
2 H8 t% t4 c+ b! x: S# _& } return 0;
6 @& }; s2 B' t, g" X vertices_get_extent(vl, np, &rc); , \ I# L- U0 a Z: U/ h
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
9 M& U; H# A. M" M) s, c return 0;
, g. @' d& V" D0 P* L3 |: W /* Set a horizontal beam l(*v, w) from v to the ultra right */
/ F9 t* T$ W% N1 I8 W0 ~ w.x = rc.max_x + DBL_EPSILON;
- v& V' t7 N9 ]0 P6 g* O w.y = v->y; " O ?+ G9 l/ H# [- {, F ?
c = 0; /* Intersection points counter */
- e" g, N8 @4 Y for(i=0; i - E4 T8 q4 h* F9 {
{
% E) G2 V2 R- \% g& p# v& r$ { j = (i+1) % np; 3 b6 O9 _- s$ m3 V, e" E) ~
if(is_intersect(vl+i, vl+j, v, &w)) 2 [4 z; d- z6 n+ b. T O8 W9 `
{ ; e+ O# f) X; M5 N+ \3 g# v+ L; w
C++;
' K! Q% U: } P6 U5 g, X3 ^% ?+ } } ( u' j* H/ {2 u; U1 W" b2 I
else if(vl.y==w.y)
8 H9 @5 K( W0 f+ y { 5 g5 K7 K% r; m) O$ }
k1 = (np+i-1)%np; * l! r0 ?( d7 e( `* N
while(k1!=i && vl[k1].y==w.y)
/ _1 ^ G9 r& a+ H0 d k1 = (np+k1-1)%np;
* c Y7 X2 T8 M& i k2 = (i+1)%np;
, @9 t$ R) R; a2 G" w2 g. m while(k2!=i && vl[k2].y==w.y)
! `% {1 H+ W1 ^. O k2 = (k2+1)%np;
7 L2 m. X9 M+ ~! L, A" b$ X if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
. L% n1 s; j3 X b+ k5 R2 I) ~ C++; 2 B& r! b& Y( F1 D3 j2 c- V1 `
if(k2 <= i) * U# c) i& |# E6 e, t1 `- ~
break;
# B/ H& h- N6 `. A i = k2; 4 u, ~) `! ?' s) j
} # O! O9 q( D+ h- y! [* x
} 3 r3 O: N5 M- n {
return c%2;
2 o: w0 W' x7 w- q' N- F5 R } ) G+ ]" E% z$ z* P5 b
( R7 ?; O' ^ ? Y
# r" }8 _5 R& T! E7 ? 本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。 |
|