判定一个点在平面几何体内部的方法
作者:learun
本文给出了判断一个点在椭圆、多边形(可以是凹边形)、矩形内部的解析方法
所有断定方法为: BOOL Contains(int x, int y), 代码为C++
一、椭园(也适用于园)
P1(x1, y1), P2(x2, y2) 定义椭园外接矩形(左上点与右下点)
CEllipse::CEllipse(int x1, int y1, int x2, int y2)
{
this->x1 = x1<x2?x1:x2;
this->y1 = y1<y2?y1:y2;
this->x2 = x2>=x1?x2:x1;
this->y2 = y2>=y1?y2:y1;
}
BOOL CEllipse::Contains(int x, int y) const
{
if (x < x1 || x > x2 || y < y1 || y > y2)
return FALSE;
// 椭圆的中心
int x0 = x1 + (x2 - x1)/2;
int y0 = y1 + (y2 - y1)/2;
// 平移变换
x -= x0;
y -= y0;
// 长/短半轴
int a = (x0 - x1);
int b = (y0 - y1);
BOOL r = FALSE;
if (a < b)
{
int tmp = a;
a = b; b = tmp;
r = TRUE;
}
// a > b > 0
a *= a;
b *= b;
x *= x;
y *= y;
if (r)
{
return x*a + y*b < a*b;
}
else
{
return x*b + y*a < a*b;
}
}
二、多边形(代码来自SUN JDK1.4)
#define MAX(x, y) (x > y? x: y)
#define MIN(x, y) (x < y? x: y)
CPolygon::CPolygon()
{
xpoints = new int[4];
ypoints = new int[4];
npoints = 4;
memset(xpoints, 0, sizeof(int)*4);
memset(ypoints, 0, sizeof(int)*4);
bounds = NULL;
CalculateBounds(xpoints, ypoints, npoints);
}
CPolygon::CPolygon(const int *xpoints, const int *ypoints, int points)
{
this->xpoints = new int[points];
this->ypoints = new int[points];
bounds = NULL;
memcpy(this->xpoints, xpoints, sizeof(int)*points);
memcpy(this->ypoints, ypoints, sizeof(int)*points);
this->npoints = points;
calculateBounds(this->xpoints, this->ypoints, points);
}
void CPolygon::CalculateBounds(int xpoints[], int ypoints[], int npoints)
{
int boundsMinX = 0x7fffffff;
int boundsMinY = 0x7fffffff;
int boundsMaxX = -1 * 0x7fffffff;
int boundsMaxY = -1 * 0x7fffffff;
for (int i = 0; i < npoints; i++)
{
int x = xpoints[i];
boundsMinX = MIN(boundsMinX, x);
boundsMaxX = MAX(boundsMaxX, x);
int y = ypoints[i];
boundsMinY = MIN(boundsMinY, y);
boundsMaxY = MAX(boundsMaxY, y);
}
bounds = new CRectangle(boundsMinX, boundsMinY,
boundsMaxX - boundsMinX,
boundsMaxY - boundsMinY);
}
CRectangle* CPolygon::GetBoundingBox() const
{
if (npoints == 0)
{
return NULL;
}
return bounds;
}
BOOL CPolygon::Contains(int x, int y) const
{
if (npoints <= 2 || !GetBoundingBox()->Contains(x, y))
{
return FALSE;
}
int hits = 0;
int lastx = xpoints[npoints - 1];
int lasty = ypoints[npoints - 1];
int curx, cury;
// Walk the edges of the polygon
for (int i = 0; i < npoints; lastx = curx, lasty = cury, i++)
{
curx = xpoints[i];
cury = ypoints[i];
if (cury == lasty)
{
continue;
}
int leftx;
if (curx < lastx)
{
if (x >= lastx)
{
continue;
}
leftx = curx;
}
else
{
if (x >= curx)
{
continue;
}
leftx = lastx;
}
double test1, test2;
if (cury < lasty)
{
if (y < cury || y >= lasty)
{
continue;
}
if (x < leftx)
{
hits++;
continue;
}
test1 = x - curx;
test2 = y - cury;
}
else
{
if (y < lasty || y >= cury)
{
continue;
}
if (x < leftx)
{
hits++;
continue;
}
test1 = x - lastx;
test2 = y - lasty;
}
if (test1 < (test2 / (lasty - cury) * (lastx - curx)))
{
hits++;
}
}
return ((hits & 1) != 0);
}
三、矩形
该类有四个属性:左上顶点(x,y),高度(height)与宽度(width)
CRectangle::CRectangle()
{
Init(0, 0, 0, 0);
}
CRectangle::CRectangle(RECT *rect)
{
Init(rect->left, rect->top, rect->right - rect->left + 1, rect->bottom - rect->top + 1);
}
void CRectangle::Init(int x, int y, int width, int height)
{
this->x = x;
this->y = y;
this->width = width;
this->height = height;
}
CRectangle::CRectangle(int x, int y, int width, int height)
{
init(x, y, width, height);
}
BOOL CRectangle::Contains(int x, int y) const
{
return Inside(x, y);
}
BOOL CRectangle::Inside(int X, int Y) const
{
int x2 = x + width - 1;
int y2 = y + height - 1;
int x1 = x <= x2? x:x2;
int y1 = y <= y2? y:y2;
int x3 = x > x2? x:x2;
int y3 = y > y2? y:y2;
return (X <= x3 && X >= x1 && Y <= y3 && Y >= y1);
}
原文:http://blog.youkuaiyun.com/learun/archive/2006/05/22/748457.aspx