在GIS中,我们会经常碰到最小外包矩形,MBR。最小外包矩形就是包围图元,并且平行于X轴和Y轴的最小外界矩形。到底这个矩形有什么用,设想一下,一个几何体有很多顶点,我们要判断一个图形是否包含另一个图形,就要一个个点点判断,这样为大大延长处理的时间。那如果是针对矩形的判断将会见的很多。又比如在空间索引中,作为几何体图形的近似可以加快索引处理的时间。在空间查询中,例如要查找离我当前位置周围最近的几个餐厅。如果没有做空间所以,当然也行,暴力法一个个测试,直到找出所有符合条件的餐厅。有了这个MBR作为索引数据的近似,那么查询的速度也会加快,只不过在创建索引的时候要花一些时间而已。
既然这个MBR如此重要,本人在之前的代码上不断改进,终于拿出一个比较稳定的版本的最小外包矩形的代码。在此奉献给大家,希望各位也能提出代码中的问题。
头文件如下:
/*******************************************************************************
* 版权所有(C) 福建省空间信息工程研究中心 2012
* 文件名称 : GeoEnvelope.h
* 当前版本 : 1.0.0.1
* 作 者 : 周旭光 (zhouxuguang@126.com)
* 设计日期 : 2012年3月6日
* 内容摘要 : 地理空间矩形类,可以表达几何体的轴对齐最小外界矩形
* 修改记录 :
* 日 期 版 本 修改人 修改摘要
********************************************************************************/
#ifndef __GEOENVELOPE_H_E9CBC39A_81BD_4AC7_BD29_EB1D0D58CF03__
#define __GEOENVELOPE_H_E9CBC39A_81BD_4AC7_BD29_EB1D0D58CF03__
#include "GeoDefine.h"
class GeoCoordinate;
class GEOMETRY_API GeoEnvelope
{
public:
//默认构造函数
GeoEnvelope();
//带参数的构造函数
GeoEnvelope(double minX,double maxX,double minY,double maxY);
//拷贝构造函数
GeoEnvelope(const GeoEnvelope& envelope);
//重载赋值运算符
GeoEnvelope &operator=(const GeoEnvelope& other);
//用两个坐标点初始化
GeoEnvelope(GeoCoordinate *coord1,GeoCoordinate *coord2);
~GeoEnvelope(void);
//初始化矩形
void Init(double x1,double x2,double y1,double y2);
// 判断矩形是否为空
bool IsNull(void) const;
// 获取最小外包矩形的宽度
double GetWidth(void) const;
// 获取最小外界矩形的高度
double GetHeight(void) const;
// 获得矩形的中心点坐标
bool Center(GeoCoordinate &coord) const;
bool Center(double &x,double &y) const;
//测试是否包含另一个MBR
bool Contains(const GeoEnvelope &env) const;
//判断一个点是否在该矩形中
bool Contains(const GeoCoordinate &pt) const;
//是否包含这个点
bool Contains(double x, double y) const;
//判断一个点是否在矩形内
DEPRECATE_API bool IsPointInRect(double x,double y) const;
//计算两个矩形相交的部分
bool Intersection(const GeoEnvelope& env,GeoEnvelope &envResult) const;
//计算两个矩形是否相交
bool Intersects(const GeoEnvelope *pOther) const;
bool Intersects(const GeoEnvelope &env) const;
//矩形增长
void ExpandToInclude(double x, double y);
void ExpandToInclude(const GeoCoordinate &pt);
void ExpandToInclude(const GeoEnvelope &other);
void ExpandToInclude(const GeoEnvelope *other);
//计算到另一个MBR的距离
double DistanceTo(GeoEnvelope &env) const;
//计算面积
double GetArea() const;
//计算周长
double Perimeter() const;
//变换,平移
void Translate(double transX, double transY);
//静态函数
//判断p1,p2构成的矩形和q1,q2构成的矩形是否相交
static bool Intersects(const GeoCoordinate &p1, const GeoCoordinate &p2, const GeoCoordinate &q1, const GeoCoordinate &q2);
public:
double minX; //最小外包矩形的最小x值
double maxX; //最小外包矩形的最大x值
double minY; //最小外包矩形的最小y值
double maxY; //最小外包矩形的最大y值
};
#endif // end of __GEOENVELOPE_H_E9CBC39A_81BD_4AC7_BD29_EB1D0D58CF03__
源文件如下:
#include <math.h>
#include <algorithm>
#include "GeoEnvelope.h"
#include "GeoCoordinate.h"
GeoEnvelope::GeoEnvelope()
{
minX = 0;
minY = -2;
maxX = 0;
maxY = -2;
}
//带参数的构造函数
GeoEnvelope::GeoEnvelope(double minX,double maxX,double minY,double maxY)
{
//先要比较坐标大小,然后再进行判断
if (minX > maxX)
{
this->minX = maxX;
this->maxX = minX;
}
else
{
this->minX = minX;
this->maxX = maxX;
}
if (minY > maxY)
{
this->minY = maxY;
this->maxY = minY;
}
else
{
this->minY = minY;
this->maxY = maxY;
}
}
//拷贝构造函数
GeoEnvelope::GeoEnvelope(const GeoEnvelope& envelope)
{
this->minX = envelope.minX;
this->maxX = envelope.maxX;
this->minY = envelope.minY;
this->maxY = envelope.maxY;
}
GeoEnvelope &GeoEnvelope::operator =(const GeoEnvelope& other)
{
if ( &other != this ) // 自检测
{
minX = other.minX;
maxX = other.maxX;
minY = other.minY;
maxY = other.maxY;
}
return *this;
}
//用两个坐标点初始化
GeoEnvelope::GeoEnvelope(GeoCoordinate *coord1,GeoCoordinate *coord2)
{
if (coord1->x < coord2->x)
{
minX = coord1->x;
maxX = coord2->x;
}
else
{
minX = coord2->x;
maxX = coord1->x;
}
if (coord1->y < coord2->y)
{
minY = coord1->y;
maxY = coord2->y;
}
else
{
minY = coord2->y;
maxY = coord1->y;
}
}
//析构函数
GeoEnvelope::~GeoEnvelope(void)
{
}
void GeoEnvelope::Init(double x1,double x2,double y1,double y2)
{
if (x1 > x2)
{
minX = x2;
maxX = x1;
}
else
{
minX = x1;
maxX = x2;
}
if (y1 > y2)
{
minY = y2;
maxY = y1;
}
else
{
minY = y1;
maxY = y2;
}
}
bool GeoEnvelope::Intersects(const GeoEnvelope *otherEvp) const
{
//上下左右四个方向
//if (maxX < otherEvp.minX || minX > otherEvp.maxX ||
// maxY < otherEvp.minY || minY > otherEvp.maxY)
//{
// return 0;
//}
四个对角方向
//if (maxX < otherEvp.minX && maxY < otherEvp.minY)
//{
// return 0;
//}
//if (maxX < otherEvp.minX && minY > otherEvp.maxY)
//{
// return 0;
//}
在矩形内
//if (minX >= otherEvp.minX && maxX <= otherEvp.maxX &&
// minY >= otherEvp.minY && maxY <= otherEvp.maxY)
//{
// return 1;
//}
//
//return 1; //相交
if (NULL == otherEvp)
{
return false;
}
if ( IsNull() || otherEvp->IsNull() )
{
return false;
}
return !(otherEvp->minX > maxX ||
otherEvp->maxX < minX ||
otherEvp->minY > maxY ||
otherEvp->maxY < minY);
}
bool GeoEnvelope::Intersects(const GeoEnvelope &env) const
{
return Intersects(&env);
}
void GeoEnvelope::ExpandToInclude(double x, double y)
{
if (IsNull())
{
minX = x;
maxX = x;
minY = y;
maxY = y;
}
else
{
if (x < minX)
{
minX = x;
}
if (x > maxX)
{
maxX = x;
}
if (y < minY)
{
minY = y;
}
if (y > maxY)
{
maxY = y;
}
}
}
void GeoEnvelope::ExpandToInclude(const GeoCoordinate &pt)
{
ExpandToInclude(pt.x,pt.y);
}
void GeoEnvelope::ExpandToInclude(const GeoEnvelope *other)
{
if (NULL == other)
{
return;
}
if (other->IsNull())
{
return;
}
if (IsNull())
{
minX = other->minX;
maxX = other->maxX;
minY = other->minY;
maxY = other->maxY;
}
else
{
if (other->minX < minX)
{
minX = other->minX;
}
if (other->maxX > maxX)
{
maxX = other->maxX;
}
if (other->minY < minY)
{
minY = other->minY;
}
if (other->maxY > maxY)
{
maxY = other->maxY;
}
}
}
void GeoEnvelope::ExpandToInclude(const GeoEnvelope &other)
{
ExpandToInclude(&other);
}
// 判断矩形是否为空
/*inline*/ bool GeoEnvelope::IsNull(void) const
{
if (maxX < minX || maxY < minY)
{
return true;
}
return false;
}
// 获取最小外包矩形的宽度
double GeoEnvelope::GetWidth(void) const
{
if (IsNull())
{
return 0;
}
return fabs(maxX - minX);
}
// 获取最小外界矩形的高度
double GeoEnvelope::GetHeight(void) const
{
if (IsNull())
{
return 0;
}
return fabs(maxY - minY);
}
// 获得矩形的中心点坐标
bool GeoEnvelope::Center(GeoCoordinate &coord) const
{
if (IsNull())
{
return false;
}
coord.x = minX + GetWidth() / 2.0;
coord.y = minY + GetHeight() / 2.0;
return true;
}
bool GeoEnvelope::Center(double &x,double &y) const
{
if (IsNull())
{
return false;
}
x = minX + GetWidth() / 2.0;
y = minY + GetHeight() / 2.0;
return true;
}
//测试是否包含另一个MBR
bool GeoEnvelope::Contains(const GeoEnvelope &env) const
{
if (IsNull() || env.IsNull())
{
return false;
}
return env.minX > minX &&
env.maxX < maxX &&
env.minY > minY &&
env.maxY < maxY;
}
//判断一个点是否在该矩形中
bool GeoEnvelope::Contains(const GeoCoordinate &pt) const
{
if (IsNull())
{
return false;
}
if (pt.x > minX && pt.x < maxX && pt.y > minY && pt.y < maxY)
{
return 1;
}
return 0;
}
//在矩形外返回0,否则返回1
bool GeoEnvelope::IsPointInRect(double x,double y) const
{
if (IsNull())
{
return false;
}
if (x > minX && x < maxX && y > minY && y < maxY)
{
return 1;
}
return 0;
}
//计算两个矩形相交的部分
bool GeoEnvelope::Intersection(const GeoEnvelope& env,GeoEnvelope &envResult) const
{
if (IsNull() || env.IsNull() || ! Intersects(env))
{
return false;
}
double intMinX = minX > env.minX ? minX : env.minX;
double intMinY = minY > env.minY ? minY : env.minY;
double intMaxX = maxX < env.maxX ? maxX : env.maxX;
double intMaxY = maxY < env.maxY ? maxY : env.maxY;
envResult.Init(intMinX, intMaxX, intMinY, intMaxY);
return true;
}
//计算到另一个MBR的距离
double GeoEnvelope::DistanceTo(GeoEnvelope &env) const
{
//如果相交,距离则为0
if (Intersects(env))
{
return 0;
}
double dx = 0;
if (maxX < env.minX)
{
dx = env.minX - maxX;
}
if (minX > env.maxX)
{
dx = minX - env.maxX;
}
double dy = 0;
if (maxY < env.minY)
{
dy = env.minY - maxY;
}
if (minY > env.maxY)
{
dy = minY - env.maxY;
}
//如果其中之一为0,则计算水平或者垂直距离
if (0.0 == dx)
{
return dy;
}
if (0.0 == dy)
{
return dx;
}
return sqrt(dx*dx + dy*dy);
}
//计算面积
double GeoEnvelope::GetArea() const
{
if (IsNull())
{
return 0;
}
return GetHeight()*GetWidth();
}
//计算周长
double GeoEnvelope::Perimeter() const
{
if (IsNull())
{
return 0;
}
return GetWidth()*2 + GetHeight()*2;
}
void GeoEnvelope::Translate(double transX, double transY)
{
if (IsNull())
{
return;
}
minX += transX;
maxX += transX;
minY += transY;
maxY += transY;
}
//测试是否包含
bool GeoEnvelope::Contains(double x, double y) const
{
if (IsNull())
return false;
return x >= minX &&
x <= maxX &&
y >= minY &&
y <= maxY;
}
//判断p1,p2构成的矩形和q1,q2构成的矩形是否相交
bool GeoEnvelope::Intersects(const GeoCoordinate &p1, const GeoCoordinate &p2, const GeoCoordinate &q1, const GeoCoordinate &q2)
{
double minq = min(q1.x, q2.x);
double maxq = max(q1.x, q2.x);
double minp = min(p1.x, p2.x);
double maxp = max(p1.x, p2.x);
if( minp >= maxq )
return false;
if( maxp <= minq )
return false;
minq = min(q1.y, q2.y);
maxq = max(q1.y, q2.y);
minp = min(p1.y, p2.y);
maxp = max(p1.y, p2.y);
if( minp >= maxq )
return false;
if( maxp <= minq )
return false;
return true;
}
源码已经经过测试