在GIS中,我们会经常碰到最小外包矩形,MBR。最小外包矩形就是包围图元,平且平行于X轴和Y轴的最小外界矩形。到底这个矩形有什么用,设想一下,一个几何体有很多顶点,我们要判断一个图形是否包含另一个图形,就要一个个点点判断,这样为大大延长处理的时间。那如果是针对矩形的判断将会见的很多。又比如在空间索引中,作为几何体图形的近似可以加快索引处理的时间。在空间查询中,例如要查找离我当前位置周围最近的几个餐厅。如果没有做空间所以,当然也行,暴力法一个个测试,直到找出所有符合条件的餐厅。有了这个MBR作为索引数据的近似,那么查询的速度也会加快,只不过在创建索引的时候要花一些时间而已。
既然这个MBR如此重要,本人在之前的代码上不断改进,终于拿出一个比较稳定的版本的最小外包矩形的代码。在此奉献给大家,希望各位也能提出代码中的问题。
头文件如下:
#include <math.h> #include <algorithm> using namespace std; class GEOMETRY_API GeoEnvelope { public: //默认构造函数 GeoEnvelope(); //带参数的构造函数 GeoEnvelope(double minX,double maxX,double minY,double maxY); //拷贝构造函数 GeoEnvelope(const GeoEnvelope& envelope); //用两个坐标点初始化 GeoEnvelope(GeoCoordinate *coord1,GeoCoordinate *coord2); virtual ~GeoEnvelope(void); //判断两个最小外包矩形是否相交(计算出在内还在外) int InterSects(const GeoEnvelope & otherEvp); // 判断矩形是否为空 bool IsNull(void) const; // 获取最小外包矩形的宽度 double GetWidth(void); // 获取最小外界矩形的高度 double GetHeight(void); // 获得矩形的中心点坐标 GeoCoordinate * Center() const; //测试是否包含另一个MBR bool Contains(const GeoEnvelope &env); //判断一个点是否在该矩形中 bool Contains(const GeoCoordinate &pt); //判断一个点是否在矩形内 bool IsPointInRect(double x,double y); //计算两个矩形相交的部分 GeoEnvelope* Intersection(const GeoEnvelope& env); //计算到另一个MBR的距离 double DistanceTo(GeoEnvelope &env); //计算面积 double Area(); //计算周长 double Perimeter(); //是否包含这个点 bool Contains(double x, double y) const; //静态函数 //判断p1,p2构成的矩形和q1,q2构成的矩形是否相交 static bool Intersects(GeoCoordinate &p1, GeoCoordinate &p2, GeoCoordinate &q1, GeoCoordinate &q2); public: double minX; //最小外包矩形的最小x值 double maxX; //最小外包矩形的最大x值 double minY; //最小外包矩形的最小y值 double maxY; //最小外包矩形的最大y值 };
实现文件如下所示:
#include "GeoEnvelope.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(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) { } int GeoEnvelope::InterSects(const GeoEnvelope & otherEvp) { //上下左右四个方向 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 2; //相交 } // 判断矩形是否为空 bool GeoEnvelope::IsNull(void) const { if (maxX < minX || maxY < minY) { return false; } return true; } // 获取最小外包矩形的宽度 double GeoEnvelope::GetWidth(void) { if (IsNull()) { return 0; } return fabs(maxX - minX); } // 获取最小外界矩形的高度 double GeoEnvelope::GetHeight(void) { if (IsNull()) { return 0; } return fabs(maxY - minY); } // 获得矩形的中心点坐标 GeoCoordinate * GeoEnvelope::Center() const { if (IsNull()) { return NULL; } return new GeoCoordinate((minX+maxX)/2, (minY+maxY)/2); } //测试是否包含另一个MBR bool GeoEnvelope::Contains(const GeoEnvelope &env) { 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) { 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) { if (IsNull()) { return false; } if (x > minX && x < maxX && y > minY && y < maxY) { return 1; } return 0; } //计算两个矩形相交的部分 GeoEnvelope* GeoEnvelope::Intersection(const GeoEnvelope& env) { if (IsNull() || env.IsNull() || ! InterSects(env)) return new GeoEnvelope(); 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; return new GeoEnvelope(intMinX, intMaxX, intMinY, intMaxY); } //计算到另一个MBR的距离 double GeoEnvelope::DistanceTo(GeoEnvelope &env) { //如果相交,距离则为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::Area() { if (IsNull()) { return 0; } return GetHeight()*GetWidth(); } //计算周长 double GeoEnvelope::Perimeter() { if (IsNull()) { return 0; } return GetWidth()*2 + GetHeight()*2; } //测试是否包含 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(GeoCoordinate &p1, GeoCoordinate &p2, GeoCoordinate &q1, 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; }
代码经过测试,希望对大家有用。
系统版本:win7 64位 旗舰版
软件环境:
jdk-7u21-windows-i586.exe
apache-ant-1.9.1-bin
报错过程:首先在master端构建,一切正常。将改任务改为slave 端实现报错,报错内容:
主要现象是svn代码检出部分文件后报错。网上搜查无果,最后在群scmeye 尴尬哥的提醒下"检查jvm"。安装的是32位的jdk,虽然java的功能都能用,但是会报错。
重装为64位的jdk。问题解决构建成功
Started by user anonymous Building remotely on zero in workspace c:\jenkins\workspace\test Checking out a fresh workspace because there's no workspace at C:\jenkins\workspace\test Cleaning local Directory . Checking out http://www.test.cn/svn/00900003/trunk/编码/源代码/statsvn at revision '2013-06-03T16:04:24.539 +0800' ERROR: Failed to check out http://www.test.cn/svn/00900003/trunk/编码/源代码/statsvn org.tmatesoft.svn.core.SVNException: svn: E175002: REPORT /svn/00900003/!svn/vcc/default failed at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:379) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:364) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:352) at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.performHttpRequest(DAVConnection.java:708) at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.doReport(DAVConnection.java:335) at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.runReport(DAVRepository.java:1289) at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.update(DAVRepository.java:837) at org.tmatesoft.svn.core.internal.wc16.SVNUpdateClient16.update(SVNUpdateClient16.java:507) at org.tmatesoft.svn.core.internal.wc16.SVNUpdateClient16.doCheckout(SVNUpdateClient16.java:915) at org.tmatesoft.svn.core.internal.wc2.old.SvnOldCheckout.run(SvnOldCheckout.java:19) at org.tmatesoft.svn.core.internal.wc2.old.SvnOldCheckout.run(SvnOldCheckout.java:8) at org.tmatesoft.svn.core.internal.wc2.SvnOperationRunner.run(SvnOperationRunner.java:20) at org.tmatesoft.svn.core.wc2.SvnOperationFactory.run(SvnOperationFactory.java:1235) at org.tmatesoft.svn.core.wc2.SvnOperation.run(SvnOperation.java:291) at org.tmatesoft.svn.core.wc.SVNUpdateClient.doCheckout(SVNUpdateClient.java:777) at hudson.scm.subversion.CheckoutUpdater$1.perform(CheckoutUpdater.java:99) at hudson.scm.subversion.WorkspaceUpdater$UpdateTask.delegateTo(WorkspaceUpdater.java:153) at hudson.scm.subversion.WorkspaceUpdater$UpdateTask.delegateTo(WorkspaceUpdater.java:161) at hudson.scm.subversion.UpdateUpdater$TaskImpl.perform(UpdateUpdater.java:121) at hudson.scm.subversion.WorkspaceUpdater$UpdateTask.delegateTo(WorkspaceUpdater.java:153) at hudson.scm.SubversionSCM$CheckOutTask.perform(SubversionSCM.java:903) at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:884) at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:867) at hudson.FilePath$FileCallableWrapper.call(FilePath.java:2387) at hudson.remoting.UserRequest.perform(UserRequest.java:118) at hudson.remoting.UserRequest.perform(UserRequest.java:48) at hudson.remoting.Request$2.run(Request.java:326) at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72) at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at hudson.remoting.Engine$1$1.run(Engine.java:58) at java.lang.Thread.run(Unknown Source) Caused by: svn: E175002: REPORT /svn/00900003/!svn/vcc/default failed at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:208) at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:154) at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:97) ... 34 more Caused by: org.tmatesoft.svn.core.SVNException: svn: E155009: REPORT request failed on '/svn/00900003/!svn/vcc/default' svn: E155009: Error processing command 'cp-and-translate' in 'C:\jenkins\workspace\test\site\images' at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:64) at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:51) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:748) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:373) ... 33 more Caused by: svn: E155009: REPORT request failed on '/svn/00900003/!svn/vcc/default' at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:208) at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:154) at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:97) at org.tmatesoft.svn.core.SVNErrorMessage.wrap(SVNErrorMessage.java:407) ... 35 more Caused by: svn: E155009: Error processing command 'cp-and-translate' in 'C:\jenkins\workspace\test\site\images' at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:208) at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:189) at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:141) at org.tmatesoft.svn.core.internal.wc.admin.SVNLogRunner.runCommand(SVNLogRunner.java:476) at org.tmatesoft.svn.core.internal.wc.admin.SVNLog.run(SVNLog.java:303) at org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea.runLogs(SVNAdminArea.java:586) at org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea.runLogs(SVNAdminArea.java:569) at org.tmatesoft.svn.core.internal.wc.SVNUpdateEditor15$SVNDirectoryInfo.runLogs(SVNUpdateEditor15.java:1609) at org.tmatesoft.svn.core.internal.wc.SVNUpdateEditor15.closeDir(SVNUpdateEditor15.java:507) at org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor.closeDir(SVNCancellableEditor.java:102) at org.tmatesoft.svn.core.internal.io.dav.handlers.DAVEditorHandler.endElement(DAVEditorHandler.java:475) at org.tmatesoft.svn.core.internal.io.dav.handlers.BasicDAVHandler.endElement(BasicDAVHandler.java:103) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.readData(HTTPConnection.java:869) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.readData(HTTPConnection.java:834) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.dispatch(HTTPRequest.java:218) at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:460) ... 34 more A qalab.xml A .classpath A project.properties A .project A devdoc A devdoc\how-to-digg.txt A devdoc\svnlog.xsd A devdoc\log.dtd A site A site\style A site\style\maven-objectlabkit.css A site\news.rss A site\dev-forum.xml A site\demo A site\demo\index.xml A site\demo\navigation.xml A site\images AU site\images\chartExplanation.png AU site\images\lavablast.png FATAL: null java.lang.NullPointerException at java.util.ArrayList.addAll(Unknown Source) at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:843) at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:781) at hudson.model.AbstractProject.checkout(AbstractProject.java:1369) at hudson.model.AbstractBuild$AbstractBuildExecution.defaultCheckout(AbstractBuild.java:676) at jenkins.scm.SCMCheckoutStrategy.checkout(SCMCheckoutStrategy.java:88) at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:581) at hudson.model.Run.execute(Run.java:1576) at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46) at hudson.model.ResourceController.execute(ResourceController.java:88) at hudson.model.Executor.run(Executor.java:241)
GDAL六参坐标转换是一种二维坐标转换的参数,常在GDALDataset 类中的CPLErr SetGeoTransform( double* padfTransform )使用;下面让我们先来谈论一下二维的仿射变换。
仿射变换变换公式:
展开形式:
x’,y’为目标坐标,x,y为原始坐标,dx,dy为平移参数。A为存储用于绕(dx,dy)旋转,和x,y方向的拉伸比例参数。
与GDAL坐标转换六参的对应:
double *dfGeoTransform = new double[6];
dfGeoTransform[0] = dx;
dfGeoTransform[1] = a11;
dfGeoTransform[2] = a12;
dfGeoTransform[3] = dy;
dfGeoTransform[4] = a21;
dfGeoTransform[5] = a22;
初始化时,A为2×2的单位矩阵,dx = dy = 0.0;
即dfGeoTransform[] = {0.0,1.0,0.0,0.0,0.0,1.0};
坐标平移:
dx = dx + xtranslation;
dy = dy + xtranslation;
坐标旋转:
坐标缩放:
下面来个示例:
#include "ogrsf_frmts.h" #include "stdio.h" #include <iostream> #include <string> using namespace std; // 定义坐标转换器 class GeoTransform { public: GeoTransform() { // 初始化六参数 dfGeoTransform[0] = 0.0; dfGeoTransform[1] = 1.0; dfGeoTransform[2] = 0.0; dfGeoTransform[3] = 0.0; dfGeoTransform[4] = 0.0; dfGeoTransform[5] = 1.0; } ~GeoTransform() { } // 设置平移 void SetTranslate(const double dx, const double dy) { dfGeoTransform[0] += dx; dfGeoTransform[3] += dy; } // 设置旋转角度 void SetRotate(const double dangle) { dfGeoTransform[1] = dfGeoTransform[1] * cos(dangle) + dfGeoTransform[2] * sin(dangle); dfGeoTransform[2] = - dfGeoTransform[1] * sin(dangle) + dfGeoTransform[2] * cos(dangle); dfGeoTransform[4] = dfGeoTransform[4] * cos(dangle) + dfGeoTransform[5] * sin(dangle); dfGeoTransform[5] = - dfGeoTransform[4] * sin(dangle) + dfGeoTransform[5] * cos(dangle); } // 设置x,y方向缩放比例 void SetScale(const double xScale, const double yScale) { dfGeoTransform[1] = dfGeoTransform[1] * xScale; dfGeoTransform[2] = dfGeoTransform[2] * yScale; dfGeoTransform[4] = dfGeoTransform[4] * xScale; dfGeoTransform[5] = dfGeoTransform[5] * yScale; } // 转换坐标 OGRPoint Transform(const double dx, const double dy) { double x, y; x = dfGeoTransform[0] + dx * dfGeoTransform[1] + dy * dfGeoTransform[2]; y = dfGeoTransform[3] + dx * dfGeoTransform[4] + dy * dfGeoTransform[5]; return OGRPoint(x,y); } private: double dfGeoTransform[6]; }; int main() { const char *pszDriverName = "DXF"; OGRSFDriver *poDriver; RegisterOGRDXF(); CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); CPLSetConfigOption("GDAL_DATA", "G:/gdal-1.9.2/data"); poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName( pszDriverName ); if( poDriver == NULL ) { printf( "%s driver not available.\n", pszDriverName ); exit( 1 ); } OGRDataSource *poDS; poDS = poDriver->CreateDataSource( "out.dxf", NULL ); if( poDS == NULL ) { printf( "Creation of output file failed.\n" ); exit( 1 ); } OGRLayer *poLayer; poLayer = poDS->CreateLayer( "out", NULL, wkbUnknown, NULL ); if( poLayer == NULL ) { printf( "Layer creation failed.\n" ); exit( 1 ); } OGRFeature *poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() ); // 原始矩形 OGRLinearRing oSquare; oSquare.addPoint(2.0,2.0); oSquare.addPoint(4.0,2.0); oSquare.addPoint(4.0,3.0); oSquare.addPoint(2.0,3.0); oSquare.closeRings(); poFeature->SetGeometry( &oSquare ); if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE ) { printf( "Failed to create feature in dxffile.\n" ); exit( 1 ); } // 定义转换器 GeoTransform geoTransform; // 平移 geoTransform.SetTranslate(2.0,3.0); // 旋转 geoTransform.SetRotate(0.5); // 缩放比例 geoTransform.SetScale(2.0,3.0); // 转换坐标之后的矩形 OGRLinearRing oSquare2; oSquare2.addPoint(&geoTransform.Transform(2.0,2.0)); oSquare2.addPoint(&geoTransform.Transform(4.0,2.0)); oSquare2.addPoint(&geoTransform.Transform(4.0,3.0)); oSquare2.addPoint(&geoTransform.Transform(2.0,3.0)); oSquare2.closeRings(); poFeature->SetGeometry( &oSquare2 ); if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE ) { printf( "Failed to create feature in dxffile.\n" ); exit( 1 ); } OGRFeature::DestroyFeature( poFeature ); OGRDataSource::DestroyDataSource( poDS ); }
效果: