在GIS中,我们会经常碰到最小外包矩形,MBR。最小外包矩形就是包围图元,并且平行于X轴和Y轴的最小外界矩形。到底这个矩形有什么用,设想一下,一个几何体有很多顶点,我们要判断一个图形是否包含另一个图形,就要一个个点点判断,这样为大大延长处理的时间。那如果是针对矩形的判断将会见的很多。又比如在空间索引中,作为几何体图形的近似可以加快索引处理的时间。在空间查询中,例如要查找离我当前位置周围最近的几个餐厅。如果没有做空间所以,当然也行,暴力法一个个测试,直到找出所有符合条件的餐厅。有了这个MBR作为索引数据的近似,那么查询的速度也会加快,只不过在创建索引的时候要花一些时间而已。
既然这个MBR如此重要,本人在之前的代码上不断改进,终于拿出一个比较稳定的版本的最小外包矩形的代码。在此奉献给大家,希望各位也能提出代码中的问题。
头文件如下:
/******************************************************************************* * 版权所有(C) 福建省空间信息工程研究中心 2012 * 文件名称 : GeoEnvelope.h * 当前版本 : 1.0.0.1 * 作 者 : 周旭光 ([email protected]) * 设计日期 : 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; }