[ObjectARX]-几何类的使用

打开VS2015,使用ObjectARX向导创建新工程,名为BaseGeometryClass。

(1)计算直线几何类和 圆弧几何类的交点。

注册命令InsertsetWith,实现代码:

static void AAAMyGroupIntersectWith() {
		// 计算所要计算交点的几何类对象
		AcGeCircArc2d geArc(AcGePoint2d::kOrigin, 50, 0, 6);
		        //AcGePoint2d::kOrigin返回一个坐标为(0,0)的点
		        //圆弧的圆心为(0,0),半径为50,起始角0;终止角6

		AcGeLine2d geLine(AcGePoint2d::kOrigin, AcGePoint2d(10, 10));
		        //构造一条穿过(0,0)和(10, 10)的无界线
		
		//计算并输出交点
		AcGePoint2d point1, point2;
		int num;
		if (geArc.intersectWith(geLine, num, point1, point2))//如果存在交点,intersectWith返回Adesk::kTrue
		{
			acutPrintf(TEXT("\\n直线和圆弧有%d个交点."), num);
			if (num > 0)
			{
				acutPrintf(TEXT("\\n交点1坐标:(%.4f,%.4f)."), point1.x, point1.y);
			}
			if (num > 1)
			{
				acutPrintf(TEXT("\\n交点2坐标:(%.4f,%.4f)."), point2.x, point2.y);
			}
		}

	}

效果:

  加载AutoCAD2018,执行命令IntersectWith:

快捷键Ctrl+F2 打开文本窗口:

直线和圆弧有2个交点.
交点1坐标:(35.3553,35.3553).
交点2坐标:(-35.3553,-35.3553).

(2)注册一个新命令LineDistance

  用于提示用户在图形窗口中选择两条直线,计算两条直线之间的最短距离,并在命令窗口中选择两条直线,计算两条直线之阿的最短距离并在命令窗口中输出:

static void AAAMyGroupLineDistance() {
		// 提示用户选择所要计算距离的两条直线
		AcDbObjectIdArray lineIds;
		if (CSelectUtil::PromptSelectEnts(TEXT("\\n选择两条直线:"), AcDbLine::desc(), lineIds))
		{

			if (lineIds.length() != 2)
			{
				acutPrintf(TEXT("\\n必须选择两条直线."));
				return;
			}

			//将直线转换成对应的几何类对象
			AcGeLineSeg2d geLine1 = GetGeLineObj(lineIds[0]);
			AcGeLineSeg2d geLine2 = GetGeLineObj(lineIds[1]);

			//计算并输出两者之间的最短距离
			double distance = geLine1.distanceTo(geLine2);
			acutPrintf(TEXT("\\n两条直线之间的最短距离为:%.4f."), distance);
		}
	}

其中,

GetGeLineObj函数的实现:

	//根据输入的实体ID获得相同参数的AcGeLineSeg2d对象
	static AcGeLineSeg2d GetGeLineObj(AcDbObjectId lineId)
	{
		AcGeLineSeg2d geLine; //AcGeLineSeg2d:在二维空间中表示一个有界的线段。
		AcDbLine *pLine = NULL;
		if (acdbOpenObject(pLine, lineId, AcDb::kForRead) == Acad::eOk)
			                         //指针pLine指向打开的对象lineId
		{
			geLine.set(ToPoint2d(pLine->startPoint()), 
				ToPoint2d(pLine->endPoint()));
			pLine->close();
		}
		return geLine;
	}

ToPoint2d函数的实现: 

	// 二维点和三维点之间的转换
	static AcGePoint2d ToPoint2d(const AcGePoint3d &point3d)
	{
		return AcGePoint2d(point3d.x, point3d.y);
	}

PromptSelectEnts函数的实现:

bool CSelectUtil::PromptSelectEnts(const TCHAR* prompt, AcRxClass* classDesc, AcDbObjectIdArray &entIds)
{
	std::vector<AcRxClass*> vecClassDesc;
	vecClassDesc.push_back(classDesc);

	return PromptSelectEnts(prompt, vecClassDesc, entIds);
}

bool CSelectUtil::PromptSelectEnts(const TCHAR* prompt, const std::vector<AcRxClass*> &classDescs, AcDbObjectIdArray &entIds)
{
	// 初始化
	entIds.setLogicalLength(0);

	// 提示用户选择实体
	ads_name sset;
	int result = 0;
	acutPrintf(prompt);
	result = acedSSGet(NULL, NULL, NULL, NULL, sset);

	if (result != RTNORM)
	{
		return false;
	}

	// 取得选择集的长度
	long length = 0;
	acedSSLength(sset, (Adesk::Int32 *)&length);

	// 遍历选择集
	Acad::ErrorStatus es;
	AcDbEntity* pEnt = NULL;
	for (long i = 0; i < length; i++)
	{
		ads_name ename;
		acedSSName(sset, i, ename);

		AcDbObjectId curEntId;
		es = acdbGetObjectId(curEntId, ename);
		if (es != Acad::eOk)
		{
			continue;
		}

		// 打开实体
		es = acdbOpenObject(pEnt, curEntId, AcDb::kForRead);
		if (es != Acad::eOk)
		{
			continue;
		}

		// 判断当前实体是否是指定的实体类型
		for (int j = 0; j < (int)classDescs.size(); j++)
		{
			if (pEnt->isKindOf(classDescs[j]))
			{
				entIds.append(pEnt->objectId());
				break;
			}
		}

		pEnt->close();	// 关闭实体
	}
	acedSSFree(sset);	// 释放选择集

	return (entIds.length() > 0);
}

效果:

在AutoCAD2018中创建两条直线,执行命令LineDistance,得到两直线的最短距离。

(3)注册新命令CurveBoolean

  用于获得两条曲线相交之后形成的边界线:

命令CurveBoolean 函数的实现:

//获得两条曲线相交之后形成的边界线
	static void AAAMyGroupCurveBoolean() {
		//选择所要操作的两条多段线
		AcDbObjectIdArray polyIds;
		if (CSelectUtil::PromptSelectEnts(TEXT("\\n选择两条多段线:"), 
			AcDbPolyline::desc(), polyIds))//获得polyIds,返回bool
		{
			if (polyIds.length() != 2)
			{
				acutPrintf(TEXT("\\n必须选择两条多段线."));
				return;
			}

			//获得两条多段线的交点
			bool bOk = false;
			AcDbPolyline *pPoly1 = NULL, *pPoly2 = NULL;
			if (acdbOpenObject(pPoly1, polyIds[0], AcDb::kForWrite) == Acad::eOk)
			{             //pPoly1指向打开的对象polyIds[0]

				if (acdbOpenObject(pPoly2, polyIds[1], AcDb::kForWrite) == 
					Acad::eOk)
				{
					AcGePoint3dArray intPoints;
					pPoly1->intersectWith(pPoly2, AcDb::kOnBothOperands,
						intPoints);//pPoly2:pPoly1实体将与之相交的实体
					//kOnBothOperands:不要扩展任何一个实体。这只会计算出两个实体
					//的几何相交的交点
					//intPoints:表示输出的交点

					if (intPoints.length() >= 2)
					{
						bOk = true;
					}
					else
					{
						acutPrintf(TEXT("\\n多段线之间交点少于2个,无法进行计算."));
					}

					//根据交点和参数值获得交点之间的曲线
					if (bOk)
					{
						GetCurveBetweenIntPoints(pPoly1, intPoints);
						GetCurveBetweenIntPoints(pPoly2, intPoints);

						pPoly2->erase(); //擦除对象
					}
					pPoly2->close(); //关闭对象,自从它被打开以来,对对象所做的所有更改
					                 //都被提交到数据库中

				}

				if (bOk)
				{
					pPoly1->erase();
				}

				pPoly1->close();
			}
		}

	}

其中:

GetCurveBetweenIntPoints函数的实现:

static void GetCurveBetweenIntPoints(AcDbPolyline *pPoly,
		const AcGePoint3dArray &intPoints)
	{
		AcDbVoidPtrArray curves;
		pPoly->getSplitCurves(intPoints, curves);
		    //在曲线上输入参数的数组intPoints
		    //返回到新创建的实体的指针curves,这些实体是原始的子曲线

		for (int i = 0; i < curves.length(); i++)
		{
			AcDbCurve *pCurve = static_cast<AcDbCurve*>(curves[i]);

			//删除首尾两条曲线,其他段的曲线添加到模型空间
			if (i == 0 || i == curves.length() - 1)
			{
				delete pCurve;
			}
			else
			{
				AcDbObjectId curveId = CDwgDatabaseUtil::PostToModelSpace(pCurve);
			}
		}
	}

 其中:

PostToModelSpace函数的声明:

	static AcDbObjectId PostToModelSpace(AcDbEntity *pEnt, 
               AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase());

PostToModelSpace函数的实现:

AcDbObjectId CDwgDatabaseUtil::PostToModelSpace(AcDbEntity *pEnt, AcDbDatabase *pDb)
{
	// 检查输入参数的有效性
	assert(pEnt);		// 等效于assert (pEnt != NULL);

						// 获得当前图形数据库的块表
	AcDbBlockTable *pBlkTbl = NULL;
	pDb->getBlockTable(pBlkTbl, AcDb::kForRead);

	// 获得模型空间对应的块表记录
	AcDbBlockTableRecord *pBlkTblRcd = NULL;
	pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForWrite);
	pBlkTbl->close();

	// 将实体添加到模型空间的块表记录
	AcDbObjectId entId;
	Acad::ErrorStatus es = pBlkTblRcd->appendAcDbEntity(entId, pEnt);
	if (es != Acad::eOk)
	{
		pBlkTblRcd->close();
		delete pEnt;	// 添加失败时,要delete
		pEnt = NULL;

		return AcDbObjectId::kNull;
	}

	// 关闭模型空间块表记录和实体
	pBlkTblRcd->close();
	pEnt->close();

	return entId;
}

效果:

绘制两条多段线,执行命令CurveBoolean:

项目完整代码:

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

参考资料:

  《AutoCAD ObjectARX(VC)开发基础与实例教程》

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片