CAD二次开发-ObjectARX(C++)-查找所有AcDbLine直线的交点

(1)使用ObjectARX向导创建一个项目LineIntersections

(2)首先,我们需要准备我们的CMap结构,以便能够将AcGePoint3d作为映射键来处理。我们的想法是对通过每个交叉点的所有线进行分组。

  CMap不支持AcGePoint3d,因为它不知道如何散列它以及如何将它作为密钥进行比较。为此,我们需要定义HasKey和CompareElements函数模板。

先定义在acrxEntryPoint.cpp文件的开头位置定义const常量(两点之间距离的最小容差)

const double _dTol = 0.0001;

(3)在acrxEntryPoint.cpp文件的开始处实现HashKey和函数

template<> 
UINT AFXAPI HashKey (AcGePoint3d key)
{CString sPoint;sPoint.Format(_T("%f,%f,%f"),key.x, key.y ,key.z);//将int类型的变量,转成CString类型UINT iHash = (NULL == &key) ? 0 : HashKey((LPCSTR)sPoint.GetBuffer());return iHash;
}

相关函数解析:

①template <> :表示T = void的显式特化

②函数HashKey:计算给定键的哈希值。

语法:

     template
AFX_INLINE UINT AFXAPI HashKey(ARG_KEY key 
);

参数:

ARG_KEY:模板参数,指定用于访问映射键的数据类型。

key:要计算哈希值的key。

返回值:

key的哈希值。

注释:

  此函数由CMap :: RemoveKey直接调用,间接由CMap :: Lookup和CMap :: Operator []调用。

  默认实现通过将键右移四个位置来创建哈希值。重写此函数,以便它返回适合您的应用程序的哈希值

(4)在acrxEntryPoint.cpp文件的开始处实现CompareElements函数

template<> BOOL AFXAPI CompareElements (const AcGePoint3d* pElement1, const AcGePoint3d* pElement2)
{if ((pElement1 == NULL) || (pElement2 == NULL))return false;AcGeTol gTol;gTol.setEqualPoint(_dTol); // Point comparison tolerancereturn (pElement1->isEqualTo(*pElement2,gTol));
}

相关解析:

①AcGeTol类:

描述:

这是一个可实例化的类,默认初始化为默认的公差。随后,可以根据特定的需要定制它的公差。例如,这个类的一个实例可能是专门用于在表面交集中使用的。

  类AcGeTol保留两个值,equalPoint和equal矢量,根据以下规则用于评估:

  Two points, p1 and p2, are equal if

(p1 - p2).length() <= equalPoint

注释:

  两行等于点集,如果在任何直线上的任意点,在第一点的点上,在另一条直线上有一个点。这意味着,在DIAM的建模空间中,有两条直线和平行方向向量的两条直线相等,如果只有公差equal向量被设置得比equalPoint更近。

②函数setEqualPoint

设置对值的相等的公差。

③函数isEqualTo:

语法:

bool isEqualTo(const AcGePoint3d& pnt, const AcGeTol& tol = AcGeContext::gTol
) const;

参数:

const AcGePoint3d& pnt 

输入点

const AcGeTol& tol = AcGeContext::gTol 

输入公差

描述:

检查这一点是否在从点pnt到.equalpoint()的距离内。公差等级的默认值是AcGeContext::gTol。

(5)注册一个命令LineInts

(6)接下来,在注册命令的函数体中,我们将在ModelSpace中收集AcDbLine实体

Acad::ErrorStatus es;AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();AcDbBlockTableRecordPointer pBTR(acdbSymUtil()->blockModelSpaceId(pDb), AcDb::kForWrite);AcDbBlockTableRecordIterator *pIter = NULL;pBTR->newIterator(pIter, true);AcDbObjectIdArray arrLines;while (!pIter->done()){AcDbEntity *pEnt = NULL;es = pIter->getEntity(pEnt, AcDb::kForRead);if (es == Acad::eOk){if (pEnt->isKindOf(AcDbLine::desc()))arrLines.append(pEnt->objectId());pEnt->close();}pIter->step(true);}delete pIter;pIter = NULL;if (arrLines.length() == 0){acutPrintf(_T("在模型空间中lines!\n"));return;}else{acutPrintf(_T("我们在模型空间中找到了 %d 条 lines!\n检查交叉点的容差 %f...\n"),arrLines.length(), _dTol);}

(7)接下来,通过收集的lines,我们将使用我们需要的信息构建我们的CMap: 

		CMap mapLines;acdbTransactionManager->startTransaction();for (int i = 0; igetObject((AcDbObject*&)pLineA, arrLines[i], AcDb::kForRead) == Acad::eOk){for (int j = i + 1; jgetObject((AcDbObject*&)pLineB, arrLines[j], AcDb::kForRead) == Acad::eOk){AcGePoint3dArray arrPts;if (pLineA->intersectWith(pLineB, AcDb::kOnBothOperands, arrPts) == Acad::eOk){if (arrPts.length() > 0){for (int p = 0; pobjectId()) == false)mapLines[arrPts[p]].append(pLineA->objectId());if (arrExist.contains(pLineB->objectId()) == false)mapLines[arrPts[p]].append(pLineB->objectId());}else{// New point...AcDbObjectIdArray arrNewEnts;arrNewEnts.append(pLineA->objectId());arrNewEnts.append(pLineB->objectId());mapLines.SetAt(arrPts[p], arrNewEnts);}}}}}}}}acdbTransactionManager->endTransaction();if (mapLines.GetCount() == 0){acutPrintf(_T("我们没有发现交点!\n"));return;}

相关函数解析:

①:函数startTransaction():

  创建一个新的AcTransaction对象,将这个新事务添加到当前交易的列表中,使之成为新的顶级交易,然后返回一个指向新的AcTransaction对象的指针。

②函数getObject( ):

语法:

virtual Acad::ErrorStatus getObject(AcDbObject*& obj, AcDbObjectId id, AcDb::OpenMode mode = AcDb::kForRead, bool openErasedObj = false
) = 0;

AcDbObject*& obj 

返回到获得对象的指针

AcDbObjectId id 

输入获得对象的id

AcDb::OpenMode mode = AcDb::kForRead 

输入获得的模式

bool openErasedObj = false 

输入布尔指示是否要获取被擦除的对象

 描述:

  这个函数调用top事务的getObject()函数,传递它所接收到的所有参数。对象只能在顶级事务中获得,因此这个函数省去了必须保存指针到顶部事务的麻烦,或者使用AcTransactionManager::topTransaction()函数来获得它。

③函数getObject( )

语法:

virtual Acad::ErrorStatus
AcDbEntity::intersectWith(const AcDbEntity* ent,AcDb::Intersect   intType,AcGePoint3dArray& points,int               thisGsMarker = 0,int               otherGsMarker = 0) const;

  函数返回一个实体与图中的另一个实体相交的点。这个函数的输入值是实体和交集类型,它可以是下面的一个:

  • kOnBothOperands (neither entity is extended) :两线交点
  • kExtendThis:两线中的一条线延长相交的点
  • kExtendArg
  • kExtendBoth:两线延长相交的点

(8)为了演示这些信息的使用,我们然后使用我们的CMap数据在ModeSpace上创建AcDbPoint实体,并在命令提示符下打印一个小报告:

POSITION pos = mapLines.GetStartPosition();while (pos){AcGePoint3d ptKey(0, 0, 0);AcDbObjectIdArray arrEnts;mapLines.GetNextAssoc(pos, ptKey, arrEnts);AcDbPoint* ptEnt = new AcDbPoint(ptKey);AcDbObjectId idPointEnt;pBTR->appendAcDbEntity(idPointEnt, ptEnt);ptEnt->close();CString sEnts;for (int e = 0; e

详细解析:

函数GetNextAssoc( ):

  此功能用于重复最有用通过所有元素都映射。 请注意放置顺序不一定是的与键值序列。

如果已检索的元素位于映射的最后,则 rNextPosition 的新值设置为 NULL

语法:

     void GetNextAssoc(POSITION& rNextPosition,KEY& rKey,VALUE& rValue 
) 

参数:

rNextPosition:指定对以前 GetNextAssoc 返回的 POSITION 值或 GetStartPosition 调用。

rKey:指定所检索元素的返回的键。

rValue:指定所检索的元素的返回值。

 

效果:

加载ObjectARX程序,然后在CAD中画几条lines,

在CAD命令行输入 ptype,选择一种交点的显示类型:

 输入命令:LineInts

按Ctrl + F2,得到相交点的坐标:

整个项目的完整代码:

   https://pan.baidu.com/s/1QVMfDGwmpYAS2wVxFLyugg

<本文完>

Note:

  本文的源代码主要参考:http://arxdummies.blogspot.com/

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部