网格索引在ARX开发中的使用
Arx编程对实体的基本操作

//// ObjectARX defined commands, created by [2010-9-30], ,#include "StdAfx.h"#include "StdArx.h"#include "dbents.h"#include "geassign.h"#include "dbpl.h"#define PI 3.141592653589793238462643383279502884197169399375105820974944592308 BOOL AddEntityToDBS(AcDbEntity *pEntity, AcDbObjectId &Id){//获取块表AcDbBlockTable *pBlockTable = NULL;if (acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable, AcDb::kForRead) != Acad::eOk){return FALSE;}//获取模型空间的快表记录AcDbBlockTableRecord *pBlkTabRec = NULL;if (pBlockTable->getAt(ACDB_MODEL_SPACE, pBlkTabRec, AcDb::kForWrite) != Acad::eOk){pBlockTable->close();return FALSE;}pBlkTabRec->appendAcDbEntity(Id, pEntity);pEntity->close();pBlockTable->close();pBlkTabRec->close();return TRUE;}//-----------绘制直线-----------------------------------------------------// This is command 'CLINE, by [2010-9-30], ,void EICADDrawCLine(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDrawCLine() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt0;ads_point pt;AcDbObjectId EntId;if (ads_getpoint(NULL, _T("\n请指定起始点:"), pt0) !=RTNORM) return;if (ads_getpoint(pt0, _T("\n请指定终点:"), pt) != RTNORM) return;AcDbLine *pLine = new AcDbLine(asPnt3d(pt0), asPnt3d(pt));AddEntityToDBS(pLine, EntId);pLine->close();}//-----------编辑直线起点-----------------------------------------------------// This is command 'EDITLSTARTPOINT, by [2010-9-30], ,void EICADDRA WEditlstartpoint(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDRAWEditlstartpoint() called."); #endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt0;ads_point pt;ads_name Ent;AcDbObjectId EntId;AcDbLine *pLine = NULL;if (ads_entsel(_T("\n请选择对象:"), Ent, pt0) != RTNORM) return;if (ads_getpoint(NULL, _T("\n请选择起点:"), pt) != RTNORM) return;if (acdbGetObjectId(EntId, Ent) != Acad::eOk) return;if (acdbOpenObject(pLine, EntId, AcDb::kForWrite) != Acad::eOk) return;pLine->setStartPoint(asPnt3d(pt));pLine->close();}//------------编辑直线终点------------------------------------------------------// This is command 'EDITLENDPOINT, by [2010-9-30], ,void EICADDRA Weditlendpoint(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDRA Weditlendpoint() called."); #endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt0;ads_point pt;ads_name Ent;AcDbObjectId EntId;AcDbLine *pLine = NULL;if (ads_entsel(_T("\n请选择对象:"), Ent, pt0) != RTNORM) return;if (ads_getpoint(NULL, _T("\n请选择终点:"), pt) != RTNORM) return;if (acdbGetObjectId(EntId, Ent) != Acad::eOk) return;if (acdbOpenObject(pLine, EntId, AcDb::kForWrite) != Acad::eOk) return;pLine->setEndPoint(asPnt3d(pt));pLine->close();}//----------绘制多段线------------------------------------------------------// This is command 'CPLINE, by [2010-9-30], ,void EICADDRA WCPLine(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDRAWCPLine() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt0 = {0.0};ads_point pt = {0.0};AcDbObjectId EntId;AcGePoint2d Gpt2d;AcDbPolyline *pPLine = new AcDbPolyline();if (ads_getpoint(NULL, _T("\n请指定起始点:"), pt0) != RTNORM) return;Gpt2d.set(pt0[X], pt0[Y]);if (pPLine->addV ertexAt(0, Gpt2d) != Acad::eOk){delete pPLine;return;}AddEntityToDBS(pPLine, EntId);pPLine = NULL;while (ads_getpoint(pt0, _T("\n请指定下一个点:"), pt) == RTNORM){Gpt2d.set(pt[X], pt[Y]);pt0[X] = pt[X];pt0[Y] = pt[Y];if (acdbOpenObject(pPLine, EntId, AcDb::kForWrite) != Acad::eOk) return;if (pPLine->addV ertexAt(pPLine->numV erts(), Gpt2d) != Acad::eOk){return;}pPLine->close();}AddEntityToDBS(pPLine, EntId);pPLine->close();}//-------------绘制圆(用户输入圆心和半径画圆)----------------------------------------------------- // This is command 'CCIRCLE, by [2010-9-30], ,void EICADDrawCCircle(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDrawCCircle() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt;ads_real pr;AcDbObjectId EntId;if (ads_getpoint(NULL, _T("\n请指定圆心:"), pt) != RTNORM) return;if (ads_getreal(_T("\n请输入半径:"), &pr) != RTNORM) return;AcDbCircle *pCircle = new AcDbCircle(asPnt3d(pt), AcGeV ector3d(0.0, 0.0, 1.0), pr);pCircle->setColorIndex(4);AddEntityToDBS(pCircle, EntId);pCircle->close();}//-------------编辑圆心------------------------------------------------------// This is command 'EDITCCENTER, by [2010-9-30], ,void EICADDRA WEditCCenter(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDRAWEditCCenter() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt;ads_point pt0;ads_name Ent;AcDbObjectId EntId;if (ads_entsel(_T("\n请选择对象:"), Ent, pt0) != RTNORM) return;if (ads_getpoint(NULL, _T("\n请选择圆心位置:"), pt) != RTNORM) return;AcDbCircle *pCircle = NULL;if (acdbGetObjectId(EntId, Ent) != Acad::eOk) return;if (acdbOpenObject(pCircle, EntId, AcDb::kForWrite) != Acad::eOk) return;pCircle->setCenter(asPnt3d(pt));pCircle->close();}//------------编辑圆半径-------------------------------------------------------// This is command 'EDITCRADIUS, by [2010-9-30], ,void EICADDRA WEditCRadius(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDRAWEditCRadius() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt;ads_name Ent;ads_real pr;AcDbObjectId EntId;AcDbCircle *pCircle = NULL;if (ads_entsel(_T("\n请选择对象:"), Ent, pt) != RTNORM) return;if (ads_getreal(_T("\n请指定半径:"), &pr) != RTNORM) return;if (acdbGetObjectId(EntId, Ent) != Acad::eOk) return;if (acdbOpenObject(pCircle, EntId, AcDb::kForWrite) != Acad::eOk) return;pCircle->setRadius(pr);pCircle->close();}//-------------编辑单行文本内容-----------------------------------------------------// This is command 'EDITTEXT, by [2010-9-30], ,void EICADDRA WEditText(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDRAWEditText() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt0;ads_name Ent;char pt[200];AcDbObjectId EntId;AcDbText *PText = NULL;if (ads_entsel(_T("\n请选择对象:"), Ent, pt0) != RTNORM) return;if (ads_getstring(1, _T("\n请输入内容:"), pt) != RTNORM) return;if (acdbGetObjectId(EntId, Ent) != Acad::eOk) return;if (acdbOpenObject(PText, EntId, AcDb::kForWrite) != Acad::eOk) return;PText->setTextString(pt);PText->setColorIndex(2);PText->close();}//--------------插入块参照--------------------------------------------------// This is command 'CBLKREF, by [2010-9-30], ,void EICADDrawCBlkRef(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDrawCBlkRef() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandAcDbBlockTable *pBlockTable = NULL;if (acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable, AcDb::kForRead) != Acad::eOk){return;}AcDbBlockTableRecord *pBlkTblRec = NULL;if (pBlockTable->getAt(_T("zfm"), pBlkTblRec, AcDb::kForRead) != Acad::eOk){pBlockTable->close();return;}AcDbObjectId BlkRefId = pBlkTblRec->objectId();AcDbObjectId EntId;AcDbBlockReference *pBlkRef = new AcDbBlockReference(AcGePoint3d(100.0, 100.0, 100.0), BlkRefId);AddEntityToDBS(pBlkRef, EntId);pBlkRef->close();pBlkTblRec->close();pBlockTable->close();}//------------绘制圆弧(输入圆心和半径)---------------------------------------------// This is command 'CARC, by [2010-9-30], ,void EICADDrawCArc(){#ifdef OARXWIZDEBUGacutPrintf ("\nOARXWIZDEBUG - EICADDrawCArc() called.");#endif // OARXWIZDEBUG// TODO: Implement the commandads_point pt0;ads_real pr;AcDbObjectId EntId;if (ads_getpoint(NULL, _T("\n请指定圆弧的圆心:"), pt0) != RTNORM) return;if (ads_getreal(_T("\n请输入圆弧的半径:"), &pr) != RTNORM) return;AcDbArc *pArc = new AcDbArc(asPnt3d(pt0), pr, PI/4, PI*1.2);pArc->setColorIndex(3);AddEntityToDBS(pArc, EntId);pArc->close();}。
a星算法栅格大小 -回复

a星算法栅格大小-回复A*算法栅格大小(Grid Size):优化路径规划问题的关键因素引言:在实际生活中,我们经常面临需要找到最优路径的问题,比如在城市中规划最短的驾驶路线,或者在机器人路径规划中找到最节省能量的路径。
为了解决这类问题,A*(A-star)算法被广泛应用。
而A*算法中栅格大小的选择,直接影响到算法的运行效率和结果的准确性。
本文将分步骤详细回答关于A*算法栅格大小问题,帮助读者更好地理解该算法并能灵活应用。
第一步:什么是A*算法?A*算法是一种启发式搜索算法,用于在图形地图或网络中寻找最短路径。
它综合考虑了路径长度和启发函数(估计距离)来选择下一步的移动方向,以达到更高的搜索效率。
第二步:A*算法中的栅格大小是什么意思?在应用A*算法时,地图或网络被划分成多个小方格,每个方格被称为一个栅格。
栅格的大小决定了图形地图或网络的分辨率,直接影响到A*算法的搜索过程和搜索结果。
第三步:如何选择合适的栅格大小?1. 如何确定栅格数:栅格数可以通过将地图或网络的长度和宽度除以栅格的大小得到。
例如,如果地图的长度为100米,宽度为100米,我们选择10x10米的栅格大小,则地图将被划分成10x10个栅格。
2. 如何选择合适的栅格大小:栅格大小的选择应该综合考虑以下几个因素:a. 地图或网络的规模:大地图或网络通常需要较大的栅格,以便更好地表示地图信息,并存储和处理更多的栅格数据。
b. 搜索的精度要求:如果需要精确计算最优路径的长度,应选择较小的栅格大小。
c. 计算资源限制:较大的栅格大小可能会导致更高的计算复杂性和更长的计算时间。
如果计算资源有限,可以选择较大的栅格来降低计算开销。
d. 环境特征:如果地图或网络中存在窄小的路径或拥挤的区域,应选择较小的栅格以更准确地表示这些细节。
第四步:栅格大小对A*算法的影响1. 增加栅格大小的优点:a. 减少计算开销:使用较大的栅格可以降低搜索空间的规模,从而减少计算开销,提高搜索效率。
空间索引使用的意义及网格索引和四叉树索引简单介绍 转

空间索引使用的意义及网格索引和四叉树索引简单介绍转空间索引使用的意义及网格索引和四叉树索引简单介绍转空间索引使用的意义及网格索引和四叉树索引简单介绍[转载]2010-09-27 07:40在介绍空间索引之前,先谈谈什么叫"索引"。
对一个数据集做"索引",是为了提高对这个数据集检索的效率。
书的"目录"就是这本书内容的"索引",当我们拿到一本新书,想查看感兴趣内容的时候,我们会先查看目录,确定感兴趣的内容会在哪些页里,直接翻到那些页,就OK了,而不是从第一章节开始翻,一个字一个字地找我们感兴趣的内容,直到找到为止,这种检索内容的效率也太低了,如果一本书没有目录,可以想象有多么不方便…可见书的目录有多重要,索引有多重要啊~现在大家对索引有了感性认识,那什么是"空间索引"呢?"空间索引"也是"索引",是对空间图形集合做的一个"目录",提高在这个图形集合中查找某个图形对象的效率。
比如说,我们在一个地图图层上进行矩形选择,确定这个图层上哪些图元被这个矩形所完全包含呢,在没有"空间索引"的情况下,我们会把这个图层上的所有图元,一一拿来与这个矩形进行几何上的包含判断,以确定到底哪些图元被完全包含在这个矩形内。
您是不是觉得这样做很合理呢?其实不然,我们先看一个网格索引的例子:我们对这个点图层作了网格索引,判断哪些点在这个矩形选择框内,是不需要把这个图层里所有的点都要与矩形进行几何包含运算的,只对a,b,c,d,e,f,g这七个点做了运算。
可以推想一下,如果一个点图层有十万个点,不建立空间索引,任何地图操作都将对整个图层的所有图元遍历一次,也就是要For循环10万次;建立索引将使得For循环的次数下降很多很多,效率自然提高很多~呵呵…想必大家都知道空间索引的好处了,也不知不觉向大家介绍了点图层的网格索引,还有哪些常用的空间索引呢?这些空间索引又该如何实现呢?带着这样的问题,下面介绍几种常用的空间索引。
索引的应用场景以及如何使用

索引的应⽤场景以及如何使⽤唯⼀的是什么?1. 索引列(字段)的所有值都只能出现⼀次,即必须唯⼀--------------------------------------------------------------------------------主键索引与唯⼀索引的区别1. 主键是⼀种约束,唯⼀索引是⼀种索引,两者在本质上是不同的。
2. 主键创建后⼀定包含⼀个唯⼀性索引,唯⼀性索引并不⼀定就是主键。
3. 唯⼀性索引列允许空值,⽽主键列不允许为空值。
4. 主键列在创建时,已经默认为空值 ++ 唯⼀索引了。
5. ⼀个表最多只能创建⼀个主键,但可以创建多个唯⼀索引。
6. 主键更适合那些不容易更改的唯⼀标识,如⾃动递增列、⾝份证号等。
7. 主键可以被其他表引⽤为外键,⽽唯⼀索引不能。
?--------------------------------------------------------------------------------复合索引1. ⽤户可以在多个列上建⽴索引,这种索引叫做复合索引(组合索引)。
2. 就是⼏个字段联合在⼀起组成⼀个索引.复合索引的创建⽅法与创建单⼀索引的⽅法完全⼀样。
3. 但复合索引在数据库操作期间所需的开销更⼩,可以代替多个单⼀索引。
4. 当表的⾏数远远⼤于索引键的数⽬时,使⽤这种⽅式可以明显加快表的查询速度。
--------------------------------------------------------------------------------(abc)(ab)(ac)(bc)(a)(b)(c)1. 复合索引⼜叫联合索引。
2. abc ab a ac 可以3. 对于复合索引:Mysql从左到右的使⽤索引中的字段,⼀个查询可以只使⽤索引中的⼀部份,但只能是最左侧部分。
4. 例如索引是key index (a,b,c). 可以⽀持a | a,b| a,b,c 3种组合进⾏查找,但不⽀持 b,c进⾏查找 ,当最左侧字段是常量引⽤时,索引就⼗分有效。
ArcGIS教程创建格网索引要素

ArcGIS教程创建格网索引要素
ArcGIS是一款功能强大的地理信息系统软件,可以用于创建、分析和可视化地理数据。
在处理大规模地理数据时,如何快速查找和管理数据是一个重要的问题。
创建格网索引要素就是一种常用的方法,它可以帮助用户更好地组织和管理数据。
本教程将介绍如何使用ArcGIS创建格网索引要素。
创建格网索引要素的步骤如下:
第一步:准备数据
在创建格网索引要素之前,首先需要准备好要索引的数据。
这些数据可以是地图、影像、矢量数据等。
确保数据已经加载到ArcGIS软件中。
第二步:打开“格网索引工具”
在ArcGIS软件中,打开“格网索引工具”。
可以通过在工具箱中“格网索引”来找到该工具。
第三步:选择要索引的数据
在“格网索引工具”中,选择要索引的数据。
可以选择整个数据集,也可以选择特定的数据范围。
选择完毕后,点击“确定”。
第四步:设置格网索引要素属性
设置完格网索引要素属性后,点击“生成”按钮,即可生成格网索引要素。
生成的格网索引要素将会显示在ArcGIS软件的地图视图中。
总结:。
数据库系统中的空间索引与范围查询

数据库系统中的空间索引与范围查询数据库系统中的空间索引与范围查询是如今大数据时代中非常重要的话题之一。
在处理地理信息、位置数据和空间数据时,使用空间索引和范围查询方法可以提高数据库系统的性能和查询效率。
空间索引是一种用于组织和加速空间数据检索的数据结构。
它在数据库系统中存储空间数据,并支持对这些数据进行查询和分析。
常见的空间索引方法包括R树、四叉树和网格索引等。
R树是最常用的空间索引方法之一。
它可以用于高效地处理范围查询操作,如矩形范围查询和k近邻查询。
R树通过递归地将空间数据划分为不同的节点,并将相邻的或相关的节点组合在一起。
这样一来,查询可以通过跳过不相关的节点而快速锁定需要的数据范围。
四叉树也是一种常见的空间索引方法。
它将空间数据递归地划分为四个象限,并将空间数据存储在对应的象限中。
与R树类似,四叉树可以用于范围查询和位置查询。
四叉树的优点是它的存储结构比较简单,查询效率较高。
另一种常见的空间索引方法是网格索引。
它将空间数据划分为规则网格,每个网格都包含一个或多个数据对象。
网格索引可以通过空间数据的坐标快速找到所在网格,从而进行范围查询和位置查询。
在数据库系统中,范围查询是一种常见的查询操作。
范围查询通过指定一个范围条件,从数据库中检索满足条件的记录。
在空间索引中,范围查询可以用于检索特定区域的地理信息或位置数据。
例如,假设我们有一个存储地理位置信息的数据库表。
该表包含经纬度信息和地理名称等字段。
我们希望检索出位于某个经纬度范围内的地理位置数据。
可以使用空间索引和范围查询来实现这个目标。
首先,我们需要为地理位置数据表创建空间索引。
假设我们使用R树作为空间索引方法。
我们可以执行以下SQL语句来创建R树空间索引:```sqlCREATE INDEX location_index ON location_data USING GIST (geometry); ```在上述SQL语句中,`location_data`是地理位置表的名称,`geometry`是存储地理位置数据的字段。
ARARX模型的辨识算法

ARARX模型的辨识算法ARARX模型由两部分组成:自回归(AR)模型和自适应(ARX)模型。
自回归模型是一种线性模型,用于描述自变量与因变量之间的关系。
自适应模型是一种非线性模型,用于描述因变量的动态行为。
ARARX模型通过将这两种模型结合起来,可以更好地描述非线性动态系统的行为。
1.数据预处理:对原始数据进行预处理,包括数据清洗、去噪、归一化等。
这些步骤旨在提高数据的质量,并减少辨识算法的误差。
2.模型结构选择:根据问题的要求和数据的特点,选择ARARX模型的结构。
通常包括选择自回归的阶数p、自适应的阶数k,以及非线性函数的形式。
3.参数估计:根据辨识算法的原理,对ARARX模型的参数进行估计。
这通常包括使用最小二乘法或极大似然法对线性参数进行估计,使用非线性优化算法对非线性参数进行估计。
4.辨识检验:对估计的模型进行检验,以评估模型的拟合能力和预测能力。
这通常包括对残差进行统计检验,以及对模型的预测误差进行评估。
5.模型验证:对辨识得到的模型进行验证,以验证模型在新数据上的适应能力。
通常会将部分数据用于辨识,然后将剩余的数据用于验证。
6.模型优化:根据模型验证的结果,对模型进行优化。
这可以包括调整模型的结构、调整参数的估计方法,以及调整模型的非线性函数等。
以上是ARARX模型的辨识算法的基本步骤。
在实际应用中,这些步骤通常会反复迭代,以得到更好的模型。
此外,对于一些复杂的系统,还可以采用基于遗传算法、粒子群算法等的优化方法来辨识模型。
综上所述,ARARX模型的辨识算法是一个综合应用统计学、数学优化和信号处理等方法的过程,用于构建非线性、非平稳系统的动态模型。
通过对数据的预处理、模型结构的选择、参数的估计和模型的检验等步骤,可以得到较好的模型,并用于系统的预测、控制和优化等任务中。
辨识算法的正确性和有效性对于ARARX模型的应用具有重要意义。
arx布局相关

AcApLayoutManager *sss;
sss=(AcApLayoutManager*)acdbHostApplicationServices()->layoutManager();
sss->updateLayoutTabs();
ARX布局操作方法
布局的信息都存储在一个词典内,可以通过下边的函数获得。
AcDbDictionary *lydi=NULL;
acdbHostApplicationServices()->workingDatabase()->getLayoutDictionary(lydi,kForWrite);
字典实际上是一个AcDbLayout的集合,我们可以通过上边获得的字典来获取里边的空间
例如,想要获取 边立柱 这个布局
AcDbObjectId ooid;
lydi->getAt(_T("边立柱"),ooid);
这样就把边立柱的布局所对应的AcDbLayout对象的objectid获得了
不知道可不可以,感觉应该行。
------------------------------------------------------------------------
删除布局
可以通过下边的方法
acdbHostApplicationServices()->layoutManager()->deleteLayout(_T("边立柱"));
非常简单
acdbHostApplicationServices()->layoutManager()返回的是一个指向当前数据库的AcDbLayoutManager指针,这个类型有好多命令,重命名啊,COPY啊,等等。自己看SDK吧。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
网格索引在ARX开发中的使用1.简介网格索引是GIS软件中经常使用的一种简单、高效的空间索引技术,例如著名的ESRI 公司的ArcSDE空间数据库系统就是采用了这种索引技术。
其原理非常简单,如“图1”所示,有6条直线段,被划分成了16(4x4)个网格,线段1到6分别占用了5(包括A3和B2)、2、1、3、2、2个网格。
其中B2网格同时被线段1、2、3占用,B3网格同时被线段线段1、2占用。
现在假设要对这6条线段两两求交,对于线段1来说,只有线段2、3和它有共用网格现象,所以只需和线段2、3进行计算,同理线段2只需和线段3计算即可,总共计算3次。
而如果不采用索引技术,需要计算5+4+3+2=14次。
图1而这仅仅是只有6条线段时的情况,其中的差别可想而知。
2.在ARX中使用网格索引分析网格索引技术,核心思想是把整个图形区域划分成MxN个矩形网格,每个网格都是一个数组,记录所有从中穿过的图形。
针对“图1”的情况,需要定义4X4=16个数组D[4][4],保存数据后,D[1][C]、D[1][D]中都保存了线段6,D[2][A]中保存了线段1,D[2][B]中保存了线段1、2、3,D[2][C]中保存了线段5,D[2][D]中保存了线段4,等等。
那么,在具体实现上,只需定义一个AcArray<AcDbIntArray, AcArrayObjectCopyReallocator<AcDbIntArray> >数组的数组即可,大小初始化为MXN。
下面用一个实例进行说明(假设图形都是直线段)。
2.1创建索引#define GRID_XCOUNT 100 //横向划分100个网格#define GRID_YCOUNT 100 //纵向划分100个网格void CreateSpatialIndex(const AcDbVoidPtrArray& lines,AcArray<AcDbIntArray, CArrayObjectCopyReallocator<AcDbIntArray> > &gridT oGeo, //返回空间索引AcGePoint2dArray &ptLBs, //返回每个图形的左下角AcGePoint2dArray &ptRTs, //返回每个图形的右上角AcGePoint2d &ptBase, //返回所有图形的左下角AcGeVector2d &gridSize //返回网格横、纵向尺寸){const AcDbLine* pLine;AcGePoint2d ptLB,ptRT;int i,nCount = lines.length();//计算每个图形的左下角、右上角坐标和全部图形的左下角、右上角坐标GetExtents(lines, ptLBs, ptRTs, ptBase, ptRT);//每个网格的横向和纵向尺寸(加1是处理精度问题)gridSize.x = (ptRT.x - ptBase.x)/GRID_XCOUNT + 1;gridSize.y = (ptRT.y - ptBase.y)/GRID_YCOUNT + 1;//初始化空间索引数组的内存gridToGeo.setLogicalLength(GRID_XCOUNT*GRID_YCOUNT);//创建索引int nGridXMin, nGridXMax, nGridYMin, nGridYMax;for(i=0; i<nCount; i++){//计算每个图形占用的网格(根据外包矩形简化处理)nGridXMin = (ptLBs.at(i).x - ptBase.x)/gridSize.x;nGridYMin = (ptLBs.at(i).y - ptBase.y)/gridSize.y;nGridXMax = (ptRTs.at(i).x - ptBase.x)/gridSize.x;nGridYMax = (ptRTs.at(i).y - ptBase.y)/gridSize.y;//在计算出的每个网格数组中添加当前图形的索引for(int j=nGridYMin; j<=nGridYMax; j++){for(int k=nGridXMin; k<=nGridXMax; k++){gridToGeo[j*GRID_XCOUNT+k].append(i);}}}}2.2使用索引void TestWithSpatialIndex(const AcDbVoidPtrArray& lines){AcArray<AcDbIntArray, AcArrayObjectCopyReallocator<AcDbIntArray> > gridToGeo; //索引AcGePoint2d ptBase; //图形范围左下角AcGeVector2d gridSize; //网格尺寸AcGePoint2dArray ptLBs, ptRTs; //每个图形的左下角,右上角坐标//创建空间索引CreateSpatialIndex(lines, gridToGeo, ptLBs, ptRTs, ptBase, gridSize);AcGePoint3dArray results;const AcDbLine *pLine1, *pLine2;int nGridXMin, nGridXMax, nGridYMin, nGridYMax, nIndex, nMaskBufferSize;//创建一个映射区标记计算过的图形(因为一个图形可能会被添加到多个网格中),每个图形占用1位。
nMaskBufferSize = (lines.length()+7)/8;BYTE *pMask = new BYTE[nMaskBufferSize];//两两求交for(int i=0; i<lines.length(); i++){pLine1 = (const AcDbLine*)lines.at(i);memset(pMask, 0, nMaskBufferSize); //映射区清零//计算当前图形占用的网格(根据外包矩形简化处理)nGridXMin = (ptLBs.at(i).x - ptBase.x)/gridSize.x;nGridYMin = (ptLBs.at(i).y - ptBase.y)/gridSize.y;nGridXMax = (ptRTs.at(i).x - ptBase.x)/gridSize.x;nGridYMax = (ptRTs.at(i).y - ptBase.y)/gridSize.y;//遍历占用的所有网格,和其中的图形求交for(int j=nGridYMin; j<=nGridYMax; j++){for(int k=nGridXMin; k<=nGridXMax; k++){//遍历一个网格中的所有图形for(int m=0; m<gridToGeo[j*GRID_XCOUNT+k].length(); m++){nIndex = gridToGeo[j*GRID_XCOUNT+k].at(m);if(nIndex <= i){continue; //已经计算过了}if( (pMask[nIndex/8] & (1<<(nIndex%8))) != 0 ){continue; //标记位已设,已经计算过了}//设标记位pMask[nIndex/8] |= (1<<(nIndex%8));if( (ptLBs[i].x > ptRTs[nIndex].x) ||(ptLBs[i].y > ptRTs[nIndex].y) ||(ptRTs[i].x < ptLBs[nIndex].x) ||(ptRTs[i].y < ptLBs[nIndex].y) ){continue; //两者外包矩形不相交}pLine2 = (const AcDbLine*)lines.at(nIndex);results.setLogicalLength(0);pLine1->intersectWith(pLine2, AcDb::kOnBothOperands, results);}}}}delete []pMask;}3.性能对比通过在一定范围内随机生成线段(限定长度在一定范围),对未采用空间索引和采用网格空间索引两种计算方法的性能进行对比,结果如下:图2 随机生成的图形可以发现,两者性能相差可达几十倍到100多倍,对于多于2万个图形的情况,采用网格索引后效果非常明显。
对比代码:void TestNoSpatialIndex(const AcDbVoidPtrArray& lines){int nCount = lines.length();const AcDbLine* pLine1, *pLine2;AcGePoint2dArray ptLBs, ptRTs;AcGePoint2d extentLB, extentRT;GetExtents(lines, ptLBs, ptRTs, extentLB, extentRT);AcGePoint3dArray results;//两两求交for(int i=0; i<nCount; i++){pLine1 = (const AcDbLine*)lines.at(i);for(int j=i+1; j<nCount; j++){pLine2 = (const AcDbLine*)lines.at(j);if( (ptLBs.at(i).x > ptRTs.at(j).x) ||(ptLBs.at(i).y > ptRTs.at(j).y) ||(ptRTs.at(i).x < ptLBs.at(j).x) ||(ptRTs.at(i).y < ptLBs.at(j).y) ){continue; //两者外包矩形不相交}results.setLogicalLength(0);pLine1->intersectWith(pLine2, AcDb::kOnBothOperands, results);}}}4.进一步优化从上一节中的性能对比表可以看到,图形数从1万升到10万时,采用网格索引时的耗时也升高了43倍,这是非常不利的现象。
这是因为第2节中的示例代码过于简化所致,这个问题可以通过以下几个环节进行优化处理。