获得本站免费赞助空间请点这里
返回列表 发帖

C语言中显示 点在多边形内 算法

本文是采用射线法判断点是否在多边形内的C语言程序。多年前,我自己实现了这样一个算法。但是随着时间的推移,我决定重写这个代码。参考周培德的《计算几何》一书,结合我的实践和经验,我相信,在这个算法的实现上,这是你迄今为止遇到的最优的代码。
  M1 j2 x$ ~% Q! |) A3 _. g# d0 t- x! |3 g& c2 }
  这是个C语言的小算法的实现程序,本来不想放到这里。可是,当我自己要实现这样一个算法的时候,想在网上找个现成的,考察下来竟然一个符合需要的也没有。我对自己大学读书时写的代码没有信心,所以,决定重新写一个,并把它放到这里,以飨读者。也增加一下BLOG的点击量。
$ I4 D& n2 Y6 x8 k
% C# K$ h6 f! k8 m6 Y  首先定义点结构如下:
6 I3 t# I$ q! g
# s! c# n% U2 l' x, D9 Q0 ?1 T以下是引用片段:
7 `, `* v6 z/ f, U+ V# D* U7 U' N( e  /* Vertex structure */   [: a3 M# [3 h) N
  typedef struct
1 t' q, e2 F$ D6 l4 k6 K* Y  {   x) G% C" [8 L4 e
  double x, y;
# r  ^' Z' p7 p# c6 P  } vertex_t;
- H2 }$ @3 d$ t2 W0 g# G; s9 F8 v5 N: p: Q7 b: @, V0 Y. f

. X* B- L0 @* ~8 u. @4 F. S  本算法里所指的多边形,是指由一系列点序列组成的封闭简单多边形。它的首尾点可以是或不是同一个点(不强制要求首尾点是同一个点)。这样的多边形可以是任意形状的,包括多条边在一条绝对直线上。因此,定义多边形结构如下:
% w1 P# h4 d3 o% U- C
& b* ^* u8 V# I) ~$ z4 `以下是引用片段:
- @8 _3 k2 k, f2 `( [0 e  /* Vertex list structure – polygon */
4 P$ \, E3 {  Q: x  m  typedef struct 9 F7 q; T& L# ]* n# y0 p# f& ^
  {
6 O2 x$ c) n: L7 l3 K  int num_vertices; /* Number of vertices in list */ , B* Z( M/ o  K8 h% T6 x
  vertex_t *vertex; /* Vertex array pointer */
% U, r7 f, ~( Q: Z% G  } vertexlist_t; 7 J2 X( T/ A8 }8 t& _0 s

' z( V5 Y% b5 ?1 F. V$ Q+ J- W$ M4 k- O& W6 s& Q( o- @
  为加快判别速度,首先计算多边形的外包矩形(rect_t),判断点是否落在外包矩形内,只有满足落在外包矩形内的条件的点,才进入下一步的计算。为此,引入外包矩形结构rect_t和求点集合的外包矩形内的方法vertices_get_extent,代码如下:7 H6 [6 U4 T( E+ o* ?' o' Y
: o7 P1 h! }# z9 y0 v" p
以下是引用片段:
1 _' J$ D8 e! U+ i  /* bounding rectangle type */ $ G' H- f+ J9 @* C6 f
  typedef struct ) [4 \" P2 d2 u: J( i. g
  { + l- k& M& ~* V, p3 \- i$ m$ }
  double min_x, min_y, max_x, max_y;
  f# q# O. ]0 {% j: \1 _2 G  } rect_t;
' B6 @( d' H: V' h$ E  /* gets extent of vertices */ 9 O( h4 I2 G% r0 S
  void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
. g7 U* S  ~; }1 ?# g; c  rect_t* rc /* out extent*/ ) 2 ]. @& Z' T% B5 ?- f
  {
6 N0 P8 |( ?! @, ^) ]8 f2 C  int i;
4 S8 M; Z) c# U8 p  if (np > 0){ % E) k/ {* k1 I- E
  rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
- u, c" B7 N1 a# G" W9 s& z/ l  }else{
0 Y$ \" K2 p) W4 _3 G  rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
. h. D$ q- P% t* T% W  }
& `  `$ H0 x2 N: }, a0 }  for(i=1; i  6 P' I, M2 R3 D* j
  {
. l! D3 b) q  J* O" H& k  if(vl.x < rc->min_x) rc->min_x = vl.x;
; `1 F9 ?& H6 x* ?  if(vl.y < rc->min_y) rc->min_y = vl.y; ( A) V9 |1 e$ Q; [7 H; p
  if(vl.x > rc->max_x) rc->max_x = vl.x; # s( W9 e2 C4 r' d  A) ?, d" B
  if(vl.y > rc->max_y) rc->max_y = vl.y;
0 Z, G& c0 b: c9 M  c  } ' y" G7 _. b9 U
  } / Q& C' d  k1 }2 l- D7 b' z! h$ U) ^

6 {0 v% B# X9 P5 m* T6 ~9 j" k# r- }5 v( G1 d
  当点满足落在多边形外包矩形内的条件,要进一步判断点(v)是否在多边形(vl:np)内。本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计算B与vl边线的交点数目,记为c,根据奇内偶外原则(c为奇数说明v在vl内,否则v不在vl内)判断点是否在多边形内。' Z# d3 I' F9 Y9 s" q+ z
8 Z3 ^) p2 A' b0 F; Z4 N
  具体原理就不多说。为计算线段间是否存在交点,引入下面的函数:9 U/ Y$ x: J" n9 j

8 G$ W- e( B2 L) }- b  (1)is_same判断2(p、q)个点是(1)否(0)在直线l(l_start,l_end)的同侧;" F) R9 g' Q. C7 Z9 C( T

/ j4 v1 Y  f! I! p3 y: q  (2)is_intersect用来判断2条线段(不是直线)s1、s2是(1)否(0)相交;1 k. x7 T4 B" q0 Y( g

, O+ R8 v7 u2 J+ n. g4 p, i# V$ m: ?以下是引用片段:
9 f' v4 f( a5 ~) p  /* p, q is on the same of line l */
: c: ~7 D, k5 h  static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
. n7 R: w8 d! z* Y  const vertex_t* p, # E6 v: `2 j& v8 U3 b9 z0 R
  const vertex_t* q)
0 i; H' ^  e6 d& W8 ?9 A( V8 g  { 2 C- z' L. m' S" {( L. Z) A
  double dx = l_end->x - l_start->x; / R1 V* E  {; V. O# m. ~' q: {
  double dy = l_end->y - l_start->y;
8 Z/ P- u1 a5 ^/ b, R% Z  double dx1= p->x - l_start->x;
0 n. F/ Q2 B5 D6 `  double dy1= p->y - l_start->y;
/ _9 H* P% N- T2 S% K, A  double dx2= q->x - l_end->x;
  k# R# ~) `  m- Z/ j  double dy2= q->y - l_end->y; # [5 n/ ~! n: t6 L: \& f" {
  return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
4 \* V$ L7 v# q/ Z$ U! m- `3 @7 d  }
  }: [. T5 s8 u! q& o  /* 2 line segments (s1, s2) are intersect? */
1 ~8 K( W! X& z2 C/ G  static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
5 S& }7 n) y' ^% e9 b  _9 l  const vertex_t* s2_start, const vertex_t* s2_end)
* O) v& U' |% k, m3 I  {
. o( L' h0 ~% p$ }/ X% ]  return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
, x3 w( o' Z, T' i# i7 X  is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
& `" @1 B& c* u! R* n  } 9 y" }* r9 c% s. W( t' d1 Q

) [2 U2 I% s; X) D& A% B8 ?7 {0 w' ?, {$ S
  下面的函数pt_in_poly就是判断点(v)是(1)否(0)在多边形(vl:np)内的程序:
4 \- q$ c! p% B: D9 i2 I6 Q+ \+ o" J8 K/ V/ S3 V' O
以下是引用片段:
  o4 }! ^/ S  d: J( A, V5 @  int pt_in_poly ( const vertex_t* vl, int np, /* polygon vl with np vertices */
% @" Y5 G) ~2 f  const vertex_t* v)
" f; ~, P; V+ p  {
" c. {1 S: m1 c: z  int i, j, k1, k2, c; + `: e& e0 U- @% W
  rect_t rc;
3 b/ J5 _6 n2 A; d  vertex_t w;
8 |, I# }1 C- e. k% N  if (np < 3) 5 J& L& Y8 S. ^( |) @' o) t
  return 0;
7 M+ W" N3 j& O5 i- q" O2 z+ X  vertices_get_extent(vl, np, &rc);
$ o5 ~# N! }! w6 m% a  if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)   U2 g2 {6 j" F
  return 0;
8 x- O: q$ _  f9 ?: s3 R& H  /* Set a horizontal beam l(*v, w) from v to the ultra right */
5 y+ k8 Q: r& i$ v4 {* A4 z  w.x = rc.max_x + DBL_EPSILON;
7 o7 @% S2 j! [  w.y = v->y; : @, ^' w" ]* R  U  C( o
  c = 0; /* Intersection points counter */ " |% V1 t" ?3 _: a8 r" e* O+ C/ o
  for(i=0; i  
7 {0 P, @% W& |2 x2 E" d# _  {
& e% f' C$ }/ P2 F  j = (i+1) % np; % t+ v$ F+ {( ]* P9 G% Y
  if(is_intersect(vl+i, vl+j, v, &w))
' O/ n# h  y5 z4 c) K4 D% w1 l  {
" n& q) I1 S; q! O' l6 J  C++;
& Z" a$ g! l- l9 D4 R( T" s$ N  } 4 d* P& D. |" T' B
  else if(vl.y==w.y) ) ~8 u4 r8 z% h. ^/ k; _# N( @' m
  {
, H. q$ Z; ~2 \8 p# E  k1 = (np+i-1)%np; / v, n) e# z# A5 Q2 \! e# B: h
  while(k1!=i && vl[k1].y==w.y) % W: @( O' B6 c) |  [
  k1 = (np+k1-1)%np; : M! T* n7 |  B3 }: n& T4 A- c
  k2 = (i+1)%np;
8 i6 }0 }5 F' f7 \  while(k2!=i && vl[k2].y==w.y) ; R2 C# ?& V) A+ N0 k$ M
  k2 = (k2+1)%np;
6 Z1 D3 d# [0 U3 P( \" P+ C  if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
" h& o# i5 N! `( |7 c6 F  C++;
  v: s6 L! j, n: L0 n  if(k2 <= i) $ |: u* n7 \8 d8 r# ]
  break; 7 B5 Y4 {0 S. ]) L' w2 W
  i = k2;
8 i+ v  @. ?3 D' a3 J, h0 F  } . r- O* T; ~4 s* ]
  } 3 I! l- E# v3 R* S/ z$ z0 X
  return c%2; ) B" R% V3 H# {- }7 k0 I5 C
  } 9 D; B% J6 e' T, S9 u8 F' e
8 E1 k# R, n' m6 v
; F9 e3 v1 K+ c7 g7 f
  本想配些插图说明问题,但是,CSDN的文章里放图片我还没用过。以后再试吧!实践证明,本程序算法的适应性极强。但是,对于点正好落在多边形边上的极端情形,有可能得出2种不同的结果。

返回列表
【捌玖网络】已经运行: