判定一个点在平面几何体内部的方法

来源:互联网 发布:淘淘搜软件 编辑:程序博客网 时间:2024/05/17 08:36

判定一个点在平面几何体内部的方法

本文给出了判断一个点在椭圆、多边形(可以是凹边形)、矩形内部的解析方法
所有断定方法为: 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);
}