# 点在多边形内算法的实现

7629人阅读 评论(17)

cheungmine
2007-9-22

/* Vertex structure */
typedef struct
{
double x, y;
} vertex_t;

/* Vertex list structure – polygon */
typedef struct
{
int                num_vertices;      /* Number of vertices in list */
vertex_t           *vertex;           /* Vertex array pointer */
} vertexlist_t;

/* bounding rectangle type */
typedef struct
{
double min_x, min_y, max_x, max_y;
} rect_t;

/* gets extent of vertices */
void vertices_get_extent (const vertex_t* vl, int np, /* in vertices */
rect_t*  rc /* out extent*/ )
{
int i;
if (np > 0){
rc->min_x = rc->max_x = vl[0].x; rc->min_y = rc->max_y = vl[0].y;
}else{
rc->min_x = rc->min_y = rc->max_x = rc->max_y = 0; /* =0 ? no vertices at all */
}

for(i=1; i<np; i++)
{
if(vl[i].x < rc->min_x) rc->min_x = vl[i].x;
if(vl[i].y < rc->min_y) rc->min_y = vl[i].y;
if(vl[i].x > rc->max_x) rc->max_x = vl[i].x;
if(vl[i].y > rc->max_y) rc->max_y = vl[i].y;
}
}

当点满足落在多边形外包矩形内的条件，要进一步判断点（v）是否在多边形（vl：np）内。本程序采用射线法，由待测试点（v）水平引出一条射线B（v，w），计算B与vl边线的交点数目，记为c，根据奇内偶外原则（c为奇数说明v在vl内，否则v不在vl内）判断点是否在多边形内。

1）is_same判断2（p、q）个点是（1）否（0）在直线l（l_start，l_end）的同侧；
2）is_intersect用来判断2条线段（不是直线）s1、s2是（1）否（0）相交；

/* p, q is on the same of line l */
static int is_same(const vertex_t* l_start, const vertex_t* l_end, /* line l */
const vertex_t* p,
const vertex_t* q)
{
double dx = l_end->x - l_start->x;
double dy = l_end->y - l_start->y;

double dx1= p->x - l_start->x;
double dy1= p->y - l_start->y;

double dx2= q->x - l_end->x;
double dy2= q->y - l_end->y;

return ((dx*dy1-dy*dx1)*(dx*dy2-dy*dx2) > 0? 1 : 0);
}

/* 2 line segments (s1, s2) are intersect? */
static int is_intersect(const vertex_t* s1_start, const vertex_t* s1_end,
const vertex_t* s2_start, const vertex_t* s2_end)
{
return (is_same(s1_start, s1_end, s2_start, s2_end)==0 &&
is_same(s2_start, s2_end, s1_start, s1_end)==0)? 1: 0;
}

int pt_in_poly (   const vertex_t* vl, int np,  /* polygon vl with np vertices  */
const vertex_t* v)
{
int i, j, k1, k2, c;
rect_t        rc;
vertex_t     w;
if (np < 3)
return 0;

vertices_get_extent(vl, np, &rc);
if (v->x < rc.min_x || v->x > rc.max_x || v->y < rc.min_y || v->y > rc.max_y)
return 0;

/* Set a horizontal beam l(*v, w) from v to the ultra right */
w.x = rc.max_x + DBL_EPSILON;
w.y = v->y;

c = 0;        /* Intersection points counter */
for(i=0; i<np; i++)
{
j = (i+1) % np;

if(is_intersect(vl+i, vl+j, v, &w))
{
c++;
}
else if(vl[i].y==w.y)
{
k1 = (np+i-1)%np;
while(k1!=i && vl[k1].y==w.y)
k1 = (np+k1-1)%np;

k2 = (i+1)%np;
while(k2!=i && vl[k2].y==w.y)
k2 = (k2+1)%np;

if(k1 != k2 && is_same(v, &w, vl+k1, vl+k2)==0)
c++;

if(k2 <= i)
break;

i = k2;
}
}

return   c%2;
}

#!/usr/bin/python
#-*- coding: UTF-8 -*-
#
# pip.py
#   point in polygon
#
# 2016-01-07
#
# point(pt) is inside polygon(poly)
########################################################################

# gets extent of vertices vl
#
def extent_vertices(vl):
min_x = 0.0
min_y = 0.0
max_x = 0.0
max_y = 0.0

i = 0

for (x, y) in vl:
if not i:
(min_x, min_y) = (x, y)
(max_x, max_y) = (x, y)
i = 1
else:
if x < min_x:
min_x = x
if y < min_y:
min_y = y
if x > max_x:
max_x = x
if y > max_y:
max_y = y

return (min_x, min_y, max_x, max_y)

# points p, q are on the same of line l
#
def same_side(l_start, l_end, p, q):
dx, dy = float(l_end[0] - l_start[0]), float(l_end[1] - l_start[1])
dx1, dy1 = float(p[0] - l_start[0]), float(p[1] - l_start[1])
dx2, dy2 = float(q[0] - l_end[0]), float(q[1] - l_end[1])

d = (dx * dy1 - dy * dx1) * (dx * dy2 - dy * dx2)

if d >= 0:
return 1
else:
return 0

# are line segments s1, s2 intersect ?
#
def intersect_segs(s1_start, s1_end, s2_start, s2_end):
if not same_side(s1_start, s1_end, s2_start, s2_end) and not same_side(s2_start, s2_end, s1_start, s1_end):
return 1
else:
return 0

# is point pt(x, y) in polygon poly
#   returns:
#     0 : not in
#     1 : in
def pt_in_poly(pt, poly):
np = len(poly)
if np < 3:
return 0

(x, y) = pt
(min_x, min_y, max_x, max_y) = extent_vertices(poly)

if x < min_x or x > max_x or y < min_y or y > max_y:
return 0

# set a horizontal beam line (pt, w) from pt to the ultra right
w = (max_x + max_x*0.1 + 1, y)

c = 0

for i in range(0, np):
j = (i+1) % np

if pt == poly[i]:
return 1
elif intersect_segs(poly[i], poly[j], pt, w):
c = c + 1
elif poly[i][1] == w[1]:
k1 = (np + i - 1) % np
while (k1 != i and poly[k1][1] == w[1]):
k1 = (np + k1 - 1) % np

k2 = (i+1) % np
while (k2 != i and poly[k2][1] == w[1]):
k2 = (k2 + 1) % np

if k1 != k2 and not same_side(pt, w, poly[k1], poly[k2]):
c = c + 1

if k2 <= i:
break

i = k2

return c % 2

epsilon = 0.0000001

assert pt_in_poly((0, 0), [(-1, -1), (-1, 1), (1, 1), (1, -1)]) == 1, "(1) appliaction error"
assert pt_in_poly((-1, -1), [(-1, -1), (-1, 1), (1, 1), (1, -1)]) == 1, "(2) appliaction error"
assert pt_in_poly((-1, 1), [(-1, -1), (-1, 1), (1, 1), (1, -1)]) == 1, "(3) appliaction error"
assert pt_in_poly((-1 - epsilon, -1), [(-1, -1), (-1, 1), (1, 1), (1, -1)]) == 0, "(4) appliaction error"
assert pt_in_poly((-1 + epsilon, -1 + epsilon), [(-1, -1), (-1, 1), (1, 1), (1, -1)]) == 1, "(5) appliaction error"
assert pt_in_poly((-1 + epsilon, -1 + epsilon), [(-1, -1), (-1, 1), (1, 1), (1, -1)]) == 1, "(6) appliaction error"
assert pt_in_poly((0, 0), [(-1, -1), (-1, 1), (1, 1), (1, 0), (2, -1)]) == 1, "(7) appliaction error"
assert pt_in_poly((0, 0), [(-1, -1), (-1, 1), (1, 1), (1, 0), (2, 1), (2, -1)]) == 1, "(8) appliaction error"
assert pt_in_poly((0, 0), [(-1, -1), (-1, 1), (1, 1), (1, 0), (2, 1), (2, 0), (2, -1)]) == 1, "(9) appliaction error"
assert pt_in_poly((0, 0), [(-1, -1), (-1, 1), (1, 1), (1, 0), (2, 0), (3, 0), (2, -1)]) == 1, "(10) appliaction error"
assert pt_in_poly((-2, 0), [(-1, -1), (-1, 1), (1, 1), (1, 0), (2, 0), (3, 0), (2, -1)]) == 0, "(11) appliaction error"
assert pt_in_poly((3, 0), [(-1, -1), (-1, 1), (1, 1), (1, 0), (2, 0), (3, 0), (2, -1)]) == 1, "(12) appliaction error"


0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：1344045次
• 积分：17306
• 等级：
• 排名：第580名
• 原创：286篇
• 转载：9篇
• 译文：16篇
• 评论：1230条
文章分类
最新评论
友情链接