objectARX自用总结

实体发布到模型空间

AcDbObjectId CDwgDataBaseUtil::PostToModelSpace(AcDbEntity *pEnt, AcDbDatabase *pDb) {

	if (pEnt == NULL) {
		return AcDbObjectId::kNull;//空指针
	}
	AcDbBlockTable *pTable;//块表

	AcDbBlockTableRecord *blkTblRec;//模型空间记录

	AcDbObjectId objId;//对象ID

	pDb->getBlockTable(pTable, AcDb::OpenMode::kForRead);
	//从数据库pDb中获取块表(block table),并将其存储在变量pTable中。这个操作使用只读模式。
	pTable->getAt(ACDB_MODEL_SPACE, blkTblRec,AcDb::OpenMode::kForWrite);
	//在块表(block table)中获取模型空间的记录,并将其存储在变量blkTblRec中。这个操作使用写入模式。
	pTable->close();//关闭块表(block table)
	
	Acad::ErrorStatus status=blkTblRec->appendAcDbEntity(objId,pEnt);
	//在模型空间记录(block table record)中追加实体。如果操作成功,则返回状态码Acad::eOk;否则,返回其他状态码。
	if (status != Acad::eOk) {

		blkTblRec->close();
		
		delete pEnt;
		pEnt = NULL;

		return AcDbObjectId::kNull;

	}

	blkTblRec->close();
	pEnt->close();

	return objId;
}

 获取AutoCAD数据库中所有满足指定图层条件的实体对象ID

//获取AutoCAD数据库中所有满足指定图层条件的实体对象ID
AcDbObjectIdArray CDwgDataBaseUtil::GetAllEntityIds(const TCHAR* layerName, AcDbDatabase *pDb)
{
	AcDbObjectIdArray entIds;	// 满足条件的实体ID集合
	bool bFilterLayer = false;	// 是否需要过滤图层
	AcDbObjectId layerId; 
	if (layerName != NULL)//如果layerName不为NULL,则需要进行图层过滤
	{   // 获取层表->判断是否有该图层->获得层表id->设置过滤控制符
		AcDbLayerTable *pLayerTbl = NULL;//访问AutoCAD的图层表
		acdbHostApplicationServices()->workingDatabase()
		//调用ObjectARX函数获取工作数据库的符号表,并将其赋值给pLayerTbl。
			->getSymbolTable(pLayerTbl, AcDb::kForRead);
		if (!pLayerTbl->has(layerName))
		//检查指定的图层是否存在,如果存在,则获取该图层的ID,并将bFilterLayer设置为true
		{
			pLayerTbl->close();
			return entIds;
		}
		pLayerTbl->getAt(layerName, layerId);
		pLayerTbl->close();

		bFilterLayer = true;
	}

	// 获得块表
	AcDbBlockTable *pBlkTbl = NULL;
	pDb->getBlockTable(pBlkTbl, AcDb::kForRead);

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

	// 创建遍历器,依次访问模型空间的每一个实体
	AcDbBlockTableRecordIterator *it = NULL;
	pBlkTblRcd->newIterator(it);
	for (it->start(); !it->done(); it->step())
	{   // 如果过滤控制符为真,获得该层上所有实体的id
		AcDbEntity *pEnt = NULL;
		Acad::ErrorStatus es = it->getEntity(pEnt, AcDb::kForRead);
		//使用迭代器获取当前实体的指针,并检查获取操作是否成功。
		if (es == Acad::eOk)
		{
			if (bFilterLayer)	// 过滤图层
			{
				if (pEnt->layerId() == layerId)//检查当前实体是否属于指定的图层
				{
					entIds.append(pEnt->objectId());//将该实体的ID添加到entIds数组中
				}
			}
			else
			{
				entIds.append(pEnt->objectId());
			}

			pEnt->close();
		}
		else
		{
			acutPrintf(TEXT("\nCDwgDatabaseUtil::GetAllEntityIds中打开实体失败(错误代码:%d)."), (int)es);
		}
	}
	delete it;
	pBlkTblRcd->close();
	//释放资源,关闭打开的对象和迭代器
	return entIds; //返回满足条件的实体对象ID数组。
}

图层操作 

//从CAD的图层表中获取指定图层的ID(图层名称)
AcDbObjectId CLayerUtil::GetLayerId(const TCHAR * layerName)
{
	assert(layerName != NULL);
	AcDbLayerTable *lTable = NULL;//AcDbLayerTable是AutoCAD中存储图层信息的数据结构
	if (acdbHostApplicationServices()->workingDatabase()->getSymbolTable(lTable, AcDb::OpenMode::kForRead) != ErrorStatus::eOk)
		return AcDbObjectId::kNull;//打开工作数据库并将lTable指向它,以读取模式打开
	AcDbObjectId lId;//存储图层的ID
	//检查指定的图层名是否存在于图层表中
	if (lTable->has(layerName)) {
		lTable->getAt(layerName, lId);
    //如果指定的图层名存在于图层表中,这行代码将从图层表中获取该图层的ID,并将其存储在变量lId中
	}
	lTable->close();//关闭图层表,释放相关资源
	return lId;//返回存储在变量lId中的图层ID
}
//处理AutoCAD的图层(图层名称,颜色索引)
AcDbObjectId CLayerUtil::Add(const ACHAR* layerName, const int colorIndex)
{
	assert(layerName != NULL);//图层名称是否为空
	bool colorRight = (colorIndex >= 1 && colorIndex <= 255);
	assert(colorRight);//颜色索引是否在1到255的范围内
	if (!colorRight)
	{
		acutPrintf(_T("\n颜色索引值无效!"));
	}
	AcDbLayerTable* lTable = NULL;//AcDbLayerTable是AutoCAD中存储图层信息的数据结构。

	if (acdbHostApplicationServices()->workingDatabase()->getSymbolTable(lTable, AcDb::OpenMode::kForWrite) != ErrorStatus::eOk)
		return AcDbObjectId::kNull;
	if (lTable->has(layerName)) {
		//检查指定的图层名是否已经存在于图层表中
		lTable->close();
		acutPrintf(TEXT("已存在该层名\n"));
		return AcDbObjectId::kNull;
	}
	else {
		//新建图层
		AcDbLayerTableRecord* lRec = new AcDbLayerTableRecord();
		lRec->setName(layerName);
		//创建一个新的AcCmColor对象,并将其指针赋值给c。
		AcCmColor* c = new AcCmColor();
		//然后设置这个颜色的颜色索引为输入的colorIndex
		c->setColorIndex(colorIndex);
		lRec->setColor(*c);//将新图层的颜色设置为上一步创建的颜色的副本。
		AcDbObjectId  lId;//存储新图层的ID。
		lTable->add(lId, lRec);//将新图层添加到图层表中,并将新图层的ID存储在lId中
		lRec->close(); //关闭新创建的图层记录,释放其内存
		delete c;//删除创建的AcCmColor对象,释放其内存
		lTable->close();
		acutPrintf(TEXT("添加成功\n"));
		return lId;
	}
}
//设置指定图层的颜色(图层的名称,颜色索引)
bool CLayerUtil::SetColor(const TCHAR * layerName, const int colorIndex)
{   //将图层名称转换为图层ID,并将其赋值给lId
	AcDbObjectId lId = GetLayerId(layerName);
	assert(colorIndex >= 1 && colorIndex <= 255);
	if (lId.isNull()) {
		return false;
	}
	else
	{
		AcDbLayerTableRecord *lRec = NULL; // AutoCAD的图层表记录。
		if (acdbOpenObject(lRec, lId, AcDb::OpenMode::kForWrite) != ErrorStatus::eOk)
			return false;
		AcCmColor *color = new AcCmColor();
		color->setColorIndex(colorIndex);//设置新创建的颜色的颜色索引为输入的颜色索引
		lRec->setColor(*color);//将新创建的颜色应用到打开的图层记录
		delete color;
		lRec->close();
		return true;
	}
}
//获取AutoCAD图层表中所有图层的ID
void CLayerUtil::GetLayerList(AcDbObjectIdArray & lIds)
{
	AcDbLayerTable *lTable = NULL; //存储图层信息的数据
	acdbHostApplicationServices()->workingDatabase()->getSymbolTable(lTable, AcDb::OpenMode::kForRead);
	AcDbLayerTableIterator * lIter = NULL;//这个迭代器用于遍历图层表
	lTable->newIterator(lIter);//创建一个新的图层表迭代器,并将其赋值给lIter
	for (lIter->start(); !lIter->done();lIter->step())
		/*这是一个循环,开始于图层表的起始位置,当迭代器没有完成时
		(即还有更多的图层),循环会继续。每次迭代后,
		都会调用lIter->step()来前进到下一个图层。*/
	{   //使用迭代器的getRecordId方法获取当前图层的ID,并将其赋值给lId
		AcDbObjectId lId;
		lIter->getRecordId(lId);
		lIds.append(lId);//将当前图层的ID添加到输入参数lIds
	}
	delete lIter;//删除图层表迭代器,释放其占用的内存
}

 几何类(中心点,偏移,删除重复点等)

AcGePoint2d FymGeometry::GetMiddlePt(const AcGePoint2d& startPt, const AcGePoint2d& endPt)
{
	double x = (startPt.x + endPt.x) * 0.5;
	double y = (startPt.y + endPt.y) * 0.5;
	return AcGePoint2d(x, y);
}

AcGePoint3d FymGeometry::GetMiddlePt(const AcGePoint3d& startPt, const AcGePoint3d& endPt)
{
	double x = (startPt.x + endPt.x) * 0.5;
	double y = (startPt.y + endPt.y) * 0.5;
	double z = (startPt.z + endPt.z) * 0.5;
	return AcGePoint3d(x, y, z);
}

AcGePoint3d FymGeometry::Polar(const AcGePoint3d& basePoint, double angle, double length)
{
	double x = basePoint.x + length * cos(angle);
	double y = basePoint.y + length * sin(angle);
	return AcGePoint3d(x,y,basePoint.z);
}

AcGePoint3d FymGeometry::RelativePoint(const AcGePoint3d& Pt, double x, double y)
{
	AcGePoint3d ptReturn(Pt.x + x, Pt.y + y, Pt.z);
	return ptReturn;
}
//比较两个AcGePoint2d类型的点(即二维坐标点)是否相等,tol为公差
bool CGePointUtil::IsEqual(const AcGePoint2d & firstPoint, const AcGePoint2d & secondPoint, double tol)
{
	return (fabs(firstPoint.x - secondPoint.x) < tol&&
		fabs(firstPoint.y - secondPoint.y) < tol);
}
//比较两个AcGePoint3d类型的点(即三维坐标点)是否相等。
bool CGePointUtil::IsEqual(const AcGePoint3d & firstPoint, const AcGePoint3d & secondPoint, double tol)
{
	return (fabs(firstPoint.x - secondPoint.x) < tol&&
		fabs(firstPoint.y - secondPoint.y) < tol&&
		fabs(firstPoint.z - firstPoint.z) < tol);
}
//在给定的三维点数组points中查找一个特定的三维点point。如果找到了这个点,函数会返回这个点的索引值;如果没有找到,函数会返回-1。
int CGePointUtil::FindPoint(const AcGePoint3dArray & points, const AcGePoint3d & point, double tol)
{
	for (int i = 0; i < points.length(); i++)
	{

		if (IsEqual(points[i], point, tol)) {
			return i;
		}

	}
	return -1;
}
//在给定的二维点数组points中查找一个特定的二维点point。如果找到了这个点,函数会返回这个点的索引值;如果没有找到,函数会返回-1。
int CGePointUtil::FindPoint(const AcGePoint2dArray & points, const AcGePoint2d & point, double tol)
{
	for (int i = 0; i < points.length(); i++)
	{

		if (IsEqual(points[i], point, tol)) {
			return i;
		}

	}
	return -1;
}
//  过滤掉那些在给定的公差范围内的重复点。
void CGePointUtil::FilterEqualPoints(AcGePoint3dArray & points, double tol)
{
	for (int i = points.length() - 1; i > 0; i--) {
//  遍历数组中的每个点,从最后一个开始
		for (int j = 0; j < i; j++) {

			if (MathUtil::IsEqual(points[i].x, points[j].x, tol) &&
				MathUtil::IsEqual(points[i].y, points[j].y, tol)) {
				//检查当前点(i)和另一个点(j)的x和y坐标是否在给定的公差范围内是否相等。
				points.removeAt(i); //移除当前点(i),删除重复的点
				break;
			}

		}

	}

}
//遍历一个包含三维点的数组,并删除所有与给定的二维点距离在给定的公差范围内的三维点
void CGePointUtil::FilterEqualPoints(AcGePoint3dArray & points, const AcGePoint2d & pt, double tol)
{

	AcGePoint3dArray tempPoints; //存储过滤后的非重复三维点

	for (int i = 0; i < points.length(); i++)
	{
		//距离大于给定的公差tol,那么它将这个三维点添加到临时数组tempPoints中
		if (CConvertUtil::ToPoint2d(points[i]).distanceTo(pt)>tol) {

			tempPoints.append(points[i]);
		}
	}

	points = tempPoints;
	//这样输入数组points现在就只包含那些距离给定的二维点pt大于给定公差的非重复三维点
}

 点,角度等转换,整型,浮点型,字符型转换,坐标系转换

AcGePoint3d FymConverUtil::ToPoint3d(const AcGePoint2d& pt, double z)
{
	return AcGePoint3d(pt.x, pt.y, z);
}

AcGePoint2d FymConverUtil::ToPoint2d(const AcGePoint3d& pt)
{
	return AcGePoint2d(pt.x, pt.y);
}

double FymConverUtil::AngleToRadion(double angle)
{
	return angle * FymMathUtil::PI() / 180;
}

double FymConverUtil::RadionToAngle(double radius)
{
	return radius * 180 / FymMathUtil::PI();
}

CString FymConverUtil::ToString(int val)// 整型转字符串(需要支持MFC)
{
	CString str;
	str.Format(_T("%d"), val);//使用'Format'函数将整数'val'格式化为字符串,并存储在'str'中。'_T("%d")'是一个宏,用于生成一个包含'%d'的宽字符字符串,其中'%d'会被替换为'val'的值
	return str;
}

//将一个双精度浮点数转换为字符串。precision 参数指定了小数点后的位数,默认2
CString CConvertUtil::ToString(double value, int precision /*= 2*/)
{
	CString strFormat, str;
	strFormat.Format(TEXT("%%.%df"), precision);
	//使用 strFormat.Format() 函数将格式字符串 "%%.%df" 中的 %df 替换为 precision 参数的值
	str.Format(strFormat, value);
	//使用 str.Format() 函数将格式化的字符串和输入的浮点数 value 结合在一起,生成最终的字符串
	return str;
}
//将一个TCHAR类型的字符串转换为双精度浮点数。
double CConvertUtil::ToDouble(const TCHAR* str)
{
	TCHAR* pszStop = NULL;
	return _tcstod(str, &pszStop);
}/*_tcstod 函数将字符串转换为浮点数。
 _tcstod 是C++中用来将TCHAR类型的字符串转换为双精度浮点数的函数。
 它需要两个参数:要转换的字符串和用于存储转换结束位置的指针。
 在这里,我们没有用到 pszStop,所以它的值被设为 NULL。返回值就是转换后的浮点数。*/


AcGePoint3d FymConverUtil::WcsPointToDcsPoint(const AcGePoint3d& point)
{
	AcGePoint3d pt;
	struct resbuf rbFrom, rbTo;
	rbFrom.restype = RTSHORT;
	rbFrom.resval.rint = 0;
	rbTo.restype = RTSHORT;
	rbTo.resval.rint = 2;//对浮点数进行四舍五入
	// 坐标系转换函数:wcs坐标、wcs标识符(0)、dcs标识符(2)、类型为点(0)、dcs坐标
	acedTrans(asDblArray(point), &rbFrom, &rbTo, 0, asDblArray(pt));
	return pt;
	
}

AcGePoint3d FymConverUtil::UcsPointToWcsPoint(const AcGePoint3d& point)
{
	AcGePoint3d pt;
	struct resbuf rbFrom, rbTo;
	rbFrom.restype = RTSHORT;
	rbFrom.resval.rint = 1;
	rbTo.restype = RTSHORT;
	rbTo.resval.rint = 0;
	// 坐标系转换函数:ucs坐标、ucs标识符(1)、wcs标识符(0)、类型为点(0)、wcs坐标
	acedTrans(asDblArray(point), &rbFrom, &rbTo, 0, asDblArray(pt));
	return pt;
}

AcGePoint3d FymConverUtil::WcsPointToUcsPoint(const AcGePoint3d& point)
{
	AcGePoint3d pt;
	struct resbuf rbFrom, rbTo;
	rbFrom.restype = RTSHORT;
	rbFrom.resval.rint = 0;
	rbTo.restype = RTSHORT;
	rbTo.resval.rint = 1;
	// 坐标系转换函数:wcs坐标、ucs标识符(1)、wcs标识符(0)、类型为点(0)、ucs坐标
	acedTrans(asDblArray(point), &rbFrom, &rbTo, 0, asDblArray(pt));
	return pt;
}

通过用户交互界面获取输入

int CGetInputUtil::GetPointReturnCode(const AcGePoint3d & basePoint, const TCHAR * prompt, AcGePoint3d & point)
{
	AcGePoint3d ucsBasePoint = CConvertUtil::WcsToUcsPoint(basePoint);
	//basePoint从WCS(世界坐标系)转换为UCS(用户坐标系)
	int nReturn = acedGetPoint(asDblArray(ucsBasePoint), prompt, asDblArray(point));//asDblArray将pnt返回为三个双精度数组
	/*这一行代码调用AutoCAD的API函数acedGetPoint,获取用户输入的点。
	这个函数需要三个参数:一个点的数组(我们前面已经将basePoint转换为UCS,所以这里传入ucsBasePoint),
	一个提示字符串(prompt),和一个点的数组(用于存储用户输入的点,我们传入的是point)*/
	if (nReturn == RTNORM) {

		point = CConvertUtil::UcsToWcsPoint(point);
	}
	//如果返回值是RTNORM(这通常表示正常的结束状态),那么就将用户输入的点从UCS转换为WCS。
	return nReturn;


}

int CGetInputUtil::GetPointReturnCode(const TCHAR * prompt, AcGePoint3d & point)
{
	int nReturn = acedGetPoint(NULL, prompt, asDblArray(point));

	if (nReturn == RTNORM) {
		point = CConvertUtil::UcsToWcsPoint(point);
	}
	return nReturn;

}

bool CGetInputUtil::GetPoint(const AcGePoint3d & basePoint, const TCHAR * prompt, AcGePoint3d & point)
{
	if (GetPointReturnCode(basePoint, prompt, point) == RTNORM)
	{
		acutPrintf(_T("\n用户成功输入了一个点"))
			return true;
	}
	else
	{
		return false;
	}
}

bool CGetInputUtil::GetPoint(const TCHAR * prompt, AcGePoint3d & point)
{
	if (GetPointReturnCode(prompt, point) == RTNORM)
	{
		acutPrintf(_T("\n用户成功输入了一个点"))
			return true;
	}
	else
	{
		return false;
	}
}
//获取关键词的函数(提示字符串,关键词字符串,默认关键词字符串,默认关键词索引,指向整数的引用)
bool CGetInputUtil::GetKeyword(const TCHAR * prompt, const TCHAR * keywords, const TCHAR * firstDefault, int defaultKeyIndex, int & nRet)
{
	int rc;//整数变量rc,用于存储函数acedGetKword的返回值

	TCHAR kword[20];//字符数组kword,用于存储用户输入的关键词
	//firstDefault参数输入NULL表示不予许直接按ENTER键
	acedInitGet(firstDefault == NULL ? 1 : 0, keywords);
	//调用acedInitGet函数初始化获取关键词的环境。如果firstDefault为NULL,则第一个参数为1,否则为0。第二个参数是关键词字符串。
	CString strPrompt = prompt;

	if (firstDefault != NULL) {
		//在提示字符串后添加"<"、firstDefault和">:"
		strPrompt += L"<";
		strPrompt += firstDefault;
		strPrompt += ">:";

	}
	else {
		strPrompt += L":";
	}
	rc = acedGetKword(strPrompt, kword);
	// 调用acedGetKword函数获取用户输入的关键词,并存储在kword中
	switch (rc) {

	case RTCAN:
		return false;//按下esc

	case RTNONE://按enter
		nRet = defaultKeyIndex;
		return true;

	case RTNORM:
	{
		std::vector<CString>items;

		CStringUtil::Split(keywords, TEXT(" "), items);

		for (int i = 0; i < (int)items.size(); i++)
		{

			if (items[i].CompareNoCase(kword) == 0) {

				nRet = i;
				break;
			}
		}
		return true;
	}
	default:
		return false;

	}
}
//提示用户输入一个实数。如果用户输入了一个有效的实数,或者没有输入而直接按回车(即默认值),则函数返回true。否则,返回false
bool CGetInputUtil::GetReal(const TCHAR * prompt, double defaultVal, int precision, double & ret)
{//参数(提示用户输入的字符串,默认的实数值d,表示精度的整数,用于保存用户输入的实数的引用)
	CString strPrompt = prompt;
	strPrompt.TrimRight();//去掉字符串末尾的空格。
	strPrompt.TrimRight(TEXT(":"));// 去掉字符串末尾的冒号。
	CString strDefaultValue;// 创建一个新的CString对象strDefaultValue
	strDefaultValue.Format(TEXT("<%%.%df>:"), precision);
	/* 使用Format方法格式化字符串,其中<%%.%df>:是一个占位符,
	%d表示整数部分,%f表示小数部分,precision表示小数点后的位数。
	例如,如果精度为3,那么占位符将被替换为<%%.3f>。*/
	strPrompt.Format(strPrompt + strDefaultValue, defaultVal);//将格式化的默认值添加到提示字符串中。
	ret = defaultVal;//将默认值赋给函数的引用参数ret
	int rc = acedGetReal(strPrompt, &ret);//获取用户的实数输入,并将结果存储在变量rc中

	if (rc == RTNORM || rc == RTNONE) {

		return true;
	}
	else {
		return false;
	}

}

 获取模块(即当前正在运行的程序dll)的文件路径

//获取模块(即当前正在运行的程序dll)的文件路径
CString CAppDirectoryUtil::GetCurrentDirectory(HMODULE hInstance)
{
	TCHAR szPath[255];//存储模块的文件路径
	//获取当前模块的文件路径。这个函数将模块的完整路径存储在 szPath 数组中
	GetModuleFileName(hInstance, szPath, sizeof(szPath));
	//获取 szPath 中最后一个反斜杠(\\)的位置,并将该位置处的字符设置为 null 字符(\0)
	// ,从而截断字符串,得到应用程序的目录
	*(_tcsrchr(szPath, '\\')) = 0;
	CString strResult = szPath;//将截断后的路径存储在 strResult 中。
	return strResult;//返回应用程序的目录
}
//获取模块的父目录的绝对路径
CString CAppDirectoryUtil::GetParentDirectory(HMODULE hInstance)
{
	TCHAR szPath[256];
	GetModuleFileName(hInstance, szPath, sizeof(szPath));
	*(_tcsrchr(szPath, '\\')) = 0;
	*(_tcsrchr(szPath, '\\')) = 0;
	CString strResult = szPath;
	return strResult;
}

 数值计算

double MathUtil::PI()
{
	return atan(1.0) * 4;//常识,求π的高精度表示
	//tan π/4=1 所以 atan( 1 ) = π/4,PI = atan(1) * 4
}
// 判断两个双精度浮点数是否相等,因为浮点数都是近似存储
bool MathUtil::IsEqual(double a, double b, double tol)
{   // 当两个浮点数的差小于10E-7,则判定两个浮点数相等
	return (fabs(a - b) < tol);
}
//一位小数四舍五入
int MathUtil::Round(double a)
{
	return(int)(a + 0.5);
}
//圆整,四舍五入
double MathUtil::Round(double a, int precision)
{
	return (floor(a*pow(10.0, precision) + 0.5) / pow(10.0, precision));
	//a乘10 的 precision 次方加0.5,用floor向下取整,最后除以10的p次方,从而将小数点移回到原来的位置
}
//生成一个在指定范围minValue和maxValue之间的随机整数
int MathUtil::GetRand(int minValue, int maxValue)
{
	assert(maxValue - minValue);
	//使用assert宏来检查maxValue和minValue之间的差异。如果maxValue小于或等于minValue,那么assert宏将抛出一个断言错误
	int value = rand();//调用标准库中的rand()函数来生成一个随机整数,并将其赋值给变量value
	int rc=minValue+(
		(int)CMathUtil::Round(((double)value)/RAND_MAX*(maxValue - minValue)));
	/*这行代码首先将value强制转换为double类型,
	然后除以RAND_MAX(在标准库中,这是一个表示随机数生成器可以生成的最大值的常量)。
	这样做的目的是将生成的随机数缩放到[0, maxValue - minValue]的范围内。
	然后使用CMathUtil::Round函数对这个浮点数进行四舍五入,并转换回整数。
	最后,将结果加上minValue,以将生成的随机数转换回原始的范围[minValue, maxValue]。*/
	return rc;//最后,这行代码返回计算出的随机整数。
}

文件操作

//文件操作函数,将一系列字符串保存到一个文本文件中(字符串,保存的文件名;字符串的向量,写入文件的内容)
void TextFileUtil::Save(const TCHAR* fileName, const std::vector<CString> &lines)
{   // 以下是支持MFC才有的,相当于open函数功能
	CStdioFile file(fileName, CFile::modeCreate | CFile::modeWrite | CFile::typeText);
	for (int i = 0; i < (int)lines.size(); i++)
	{
		file.WriteString(lines[i]);//写入每个字符串并换行
		file.WriteString(_RXST("\n"));
	}
	file.Close();
}
//从指定的文本文件中读取所有行,并将它们存储在lines这个向量中(读取的文本文件的名称,保存读取到的文本文件的每一行)
bool TextFileUtil::Load(const TCHAR* fileName, std::vector<CString> &lines)
{
	// 纠错函数:如果文件不存在打印
	if (PathFileExists(fileName) != TRUE)
	{
		acutPrintf(_T("\n读取的文件不存在!"));
		return false;
	}
	else
	{
		lines.clear();

		CStdioFile file(fileName, CFile::modeRead | CFile::typeText);
		CString strLine;//用于保存从文件中读取的每一行
		while (file.ReadString(strLine))//尝试从打开的文件中读取一行文本,并将其保存在strLine变量中
		{
			lines.push_back(strLine);//将每一行(保存在strLine中)添加到lines向量中
		}
		return true;
	}
}
// 通过对话框选择获取文件绝对路径(多选):一些MFC语句,了解即可,重点看注释语句
bool TextFileUtil::SelectFilePath(CStringArray& fileNameArray)
{
	// 构建文件过滤器
	CNavFilter* filter;
	// 过滤的注释
	LPCTSTR filterDesc[] = { _T("可选文件格式"), NULL };

	// 过滤的后缀名:可以在null前增加后缀
	LPCTSTR filterDWG[] = { _T("*.dwg"),_T("*.dxf"), NULL };
	LPCTSTR* filterSpec[] = { filterDWG, NULL };

	CNavFilterArray gFilterArray;
	gFilterArray.RemoveAllData();

	int i = 0, j;
	while (filterSpec[i] != NULL)
	{
		filter = gFilterArray.AddData();
		if (filter != NULL)
		{
			filter->SetDescription(filterDesc[i]);
			j = 0;
			while (filterSpec[i][j] != NULL)
			{
				filter->Add(filterSpec[i][j]);
				j++;
			}
		}
		i++;
	}

	fileNameArray.RemoveAll();

	CNavDataArray gDataArray;
	while (true)
	{	// 获取autoCAD的窗口句柄
		HWND acadhandle = adsw_acadMainWnd();
		// 使句柄成为当前窗口
		::EnableWindow(acadhandle, true);
		// 设置焦点
		::SetFocus(acadhandle);
		// 获取MFC的主窗口
		CWnd* pWnd = CWnd::FromHandle(acadhandle);
		CAcUiNavDialog dlg(gDataArray, gFilterArray, 0, pWnd);
		// 开启多选模式
		dlg.SetMultiSelectAllowed(true);
		// 对话框标题
		dlg.SetDialogCaption(_T("多选对话框"));
		// 设置当前点选的文件可见缩略图
		dlg.SetPreviewPresent(true);
		dlg.SetPreviewVisible(true);

		// 如果点选了确认按钮
		if (dlg.DoModal() == IDOK)
		{
			for (int i = 0; i < gDataArray.GetCount(); i++)
			{
				LPITEMIDLIST id = gDataArray.GetAt(i)->GetID();

				// 获取并打印:每个选择到的 文件绝对路径 的 字符串
				fileNameArray.Add(gDataArray.GetAt(i)->GetText());
			}
		}
		// 跳出循环
		break;
	}
	if (fileNameArray.GetCount() > 0)
		return true;
	else
		return false;
}

字体,文本样式 

// 创建字体样式:字体样式名、字体文件名、大字体文件名(亚洲国家用)
AcDbObjectId FymTextStyle::Add(const ACHAR *name, const ACHAR *fontFileName, const ACHAR *bigfontFile)
{   // 获得字体样式表
	Acad::ErrorStatus es;
    AcDbTextStyleTable *pTextStyle = NULL;
    es = acdbHostApplicationServices()->workingDatabase()->getTextStyleTable(pTextStyle, AcDb::kForWrite);
	if (es != ErrorStatus::eOk)
	{
		acutPrintf(L"\n打开文字样式表失败");
		return AcDbObjectId::kNull;
	}
	// 创建字体样式表记录
	AcDbTextStyleTableRecord* pTextStyleRcd = new AcDbTextStyleTableRecord();
	// 字体样式表记录添加:名称、字体文件名、比例、
	pTextStyleRcd->setName(name);
	pTextStyleRcd->setBigFontFileName(bigfontFile);
	pTextStyleRcd->setFileName(fontFileName);
	pTextStyleRcd->setXScale(1.0);
	// 字体样式记录添加进字体样式表中
	pTextStyle->add(pTextStyleRcd);
	// 返回字体样式表记录id
	AcDbObjectId styleId = pTextStyleRcd->objectId();
	pTextStyleRcd->close();
	pTextStyle->close();
	return styleId;
}
// 从AutoCAD的文本样式表中获取指定名称的文本样式的ID:字体样式名称
AcDbObjectId FymTextStyle::GetStyleId(const ACHAR* styleName)
{
	AcDbObjectId textStyleId = AcDbObjectId::kNull;
	// 如果字体样式名非空
	if (_tcslen(styleName)>0)
	{
		AcDbTextStyleTable* pTextStyle = NULL;
		// 获得字体样式表指针
		Acad::ErrorStatus es;
		es = acdbHostApplicationServices()->workingDatabase()->getTextStyleTable(pTextStyle, AcDb::kForRead);
		// 获得字体样式记录id 并赋值textStyleId
		if (es != ErrorStatus::eOk) {
			acutPrintf(L"未能打开文本样式表");
			return AcDbObjectId::kNull;
		}
		AcDbObjectId styleId;
		if (pTextStyle->has(styleName)) {
			pTextStyle->getAt(styleName, textStyleId);
			pTextStyle->close();
			return textStyleId;// 若字体样式名为空,返回kNull
		}
		else {
			pTextStyle->close();
			return AcDbObjectId::kNull;
		}
	}
	else {
		acutPrintf(L"请输入文本样式的名称");
		return AcDbObjectId::kNull;
	}
}
//获取AutoCAD中所有文本样式的名称,并存储命名为styleNames,返回对象数组
AcDbObjectIdArray FymTextStyle::GetAll(std::vector<CString>& styleNames)
{
	AcDbObjectIdArray styleIds;
	styleNames.clear();
	AcDbTextStyleTable* pStyleTable = NULL;
	Acad::ErrorStatus es;
	es = acdbHostApplicationServices()->workingDatabase()->getTextStyleTable(pStyleTable, AcDb::kForRead);
	//获取当前工作数据库,调用getTextStyleTable方法来以只读方式获取文本样式表,并将其赋值给pStyleTable指针
	if (es != ErrorStatus::eOk) {
		acutPrintf(L"未能打开文本样式表");
		return styleIds;
	}
	AcDbTextStyleTableIterator* pItr = NULL;
	pStyleTable->newIterator(pItr);//创建一个新的文本样式表迭代器,并将其赋值给pItr指针
	for (pItr->start();!pItr->done();pItr->step())
	{// 从文本样式表的起始位置开始迭代,直到完成遍历
		AcDbTextStyleTableRecord* pRcd;
		pItr->getRecord(pRcd, AcDb::kForRead);// 获取当前迭代的文本样式表记录,并将其赋值给pRcd指针
		ACHAR* textStyleName;//存储文本样式的名称
		pRcd->getName(textStyleName);//获取文本样式的名称,并将其赋值给textStyleName指针
		if (_tcslen(textStyleName)>0)//检查textStyleName的长度是否大于0
		{
			styleNames.push_back(textStyleName);
			//将textStyleName添加到传递给方法的styleNames向量中
			styleIds.append(pRcd->objectId());//获取并添加文本样式记录的对象ID
		}
		acutDelString(textStyleName);//释放textStyleName的内存
		pRcd->close();//关闭当前迭代的文本样式表记录
	}
	delete pItr;//删除创建的文本样式表迭代器
	pStyleTable->close();//关闭文本样式表
}

 文字输入

//在AutoCAD的模型空间中创建一个新的文本对象(单行),并返回这个新对象的ID(三维插入点、文本字符串、文本样式、文本高度和旋转角度)
AcDbObjectId FymText::AddText(const AcGePoint3d& ptInsert, const ACHAR* text, AcDbObjectId style, double height, double rotation)
{   //创建一个新的AcDbText对象,即CAD中创建的文本
	AcDbText* pTxt = new AcDbText(ptInsert, text, style, height, rotation);
	return FymDatabase::PostToModelSpace(pTxt);
}
//CAD模型空间创建多行文本
AcDbObjectId FymText::AddMText(const AcGePoint3d& ptInsert, const ACHAR* text, AcDbObjectId style, double height, double width)
{
	AcDbMText* pMtext = new AcDbMText();
	pMtext->setTextStyle(style);//样式
	pMtext->setContents(text);//文本内容
	pMtext->setLocation(ptInsert);//插入点
	pMtext->setHeight(height);//文字高度
	pMtext->setWidth(width);//宽度
	pMtext->setAttachment(AcDbMText::kBottomLeft);//位置:左下角
	return FymDatabase::PostToModelSpace(pMtext);//返回ID并添加到模型空间
}

 字符串操作

void StringUtil::Split(const CString& text, const ACHAR* separator, std::vector<CString>& result, bool bAddEmptyStr)
{
	int prev = 0, current = 0;// 初始化两个指针,prev(前一个索引号)和current(当前索引号),都设置为0  
	CString strCopyTxT = text;// 创建一个text的副本,并去除其右边的空格  
	strCopyTxT.TrimRight(_T(" "));
	if (strCopyTxT.Find(separator,0)<0)//如果在副本中找不到分隔符,未找到返回-1,那么整个副本就是一个单独的字符串
	{
		if (strCopyTxT.GetLength()>0)
		{
			result.push_back(strCopyTxT);// 如果副本的长度大于0,则将其添加到字符串容器中  
		}
		// 如果传入的字符串长度为0,啥也不添加
		return;
	}
	// 以下为至少发现一个分隔符,获得字符串总长度
	int length = strCopyTxT.GetLength();// 初始化一个标志位,表示是否已经找到了所有的分隔符
	bool bExit = false;
	while (true)// 开启无限循环:注意循环中的break语句
	{
		current = strCopyTxT.Find(separator, prev); // 在副本中查找分隔符,从prev指针的位置开始查找 
		if (current == -1)// 到最后一组了
		{
			current = length;
			bExit = true;// 如果找不到分隔符,将整个字符串长度赋值current,标识退出变量为真
		}
		// 取最后一个分隔符到结尾的字符串,Mid见下注释
		CString item = strCopyTxT.Mid(prev, current - prev);
		
		if (bAddEmptyStr || item.GetLength()>0)
		{   // 添加进容器的条件:每个提取的子字符串是否过滤0长度
			result.push_back(item);// 如果bAddEmptyStr为true,或者子字符串的长度大于0,则将子字符串添加到结果列表中
		}
		if (bExit)
		{
			break;// 如果已经找到了所有的分隔符,那么跳出循环 
		}
		prev = current + int(_tcslen(separator)); // 将prev指针移动到当前分隔符的后面,以便在下一次循环中查找下一个分隔符  
	}
}
// 合并字符串:传入字符串容器、分隔符,返回合并的字符串
CString StringUtil::Join(const std::vector<CString>& items, const ACHAR *spearator)
{
	CString strResult;// 逐个拼接容器中的字符串
	for (int i = 0; i < items.size();i++)
	{
		strResult += items.at(i) + spearator;
	}// 删除右侧的空字符
	strResult.TrimRight(spearator);//调用'TrimRight'函数,从'strResult'的右侧删除所有的分隔符。这样做是为了避免在最后一个元素后面出现不必要的分隔符
	return strResult;// 返回拼接好的字符串
}

 实体的选中

//提示用户选择AutoCAD中的实体,并将所选择的实体的ID添加到一个AcDbObjectIdArray数组中。
bool CSelectUtil::PromptSelectEnts(const TCHAR * prompt, resbuf * rb,
	AcDbObjectIdArray & entIds)//(提示字符串,指向resbuf的指针,id数组引用entIds。返回类型为布尔值)
{
	ads_name selName;
	acutPrintf(prompt);//打印出传入的提示字符串
	int rc = acedSSGet(NULL, NULL, NULL, rb, selName);
	//提示用户选择实体。选择的结果存储在selName中,并返回一个整数rc作为结果代码
	if (rc == RTNORM) {//用户正常选择了实体
		int length;
		acedSSLength(selName, &length);// 获取用户选择实体的数量
		for (int i = 0; i < length; i++)//循环遍历每一个选择的实体
		{
			ads_name name;
			acedSSName(selName, i, name);//获取第i个选择实体的名称
			AcDbObjectId oId;
			if (acdbGetObjectId(oId, name) == ErrorStatus::eOk) {
				entIds.append(oId);//尝试获取实体的ID。如果成功将该ID添加到entIds数组中
			}
		}
		acedSSFree(selName);//释放与selName相关的内存
		return true;//如果用户正常选择了实体,则返回true
	}
	else {
		acedSSFree(selName);//释放与selName相关的内存
		acutPrintf(_T("\n用户没有选择任何实体或者发生了错误"));
		return false;
	}
}
//提示用户选择实体并获取选定实体ID(提示用户进行选择的消息,保存选择集,保存类描述,保存选定的实体ID)
bool CSelectUtil::PromptSelectEnts(const TCHAR * prompt, resbuf * rb, std::vector<AcRxClass*>& classDescs, AcDbObjectIdArray & entIds)
{
	ads_name selName;
	acutPrintf(prompt);//打印提示消息(prompt)
	int rc = acedSSGet(NULL, NULL, NULL, rb, selName);
	if (rc == RTNORM) {
		int length;
		acedSSLength(selName, &length);
		for (int i = 0; i < length; i++)
		{
			ads_name name;
			acedSSName(selName, i, name);
			AcDbObjectId oId;
			if (acdbGetObjectId(oId, name) == ErrorStatus::eOk) {
				AcDbEntity *ent = NULL;
				if (acdbOpenObject(ent, oId) != ErrorStatus::eOk) {
					continue;
				}
				for (int j = 0; j < (int)classDescs.size(); j++)
				{
					if (ent->isKindOf(classDescs[j])) {
						entIds.append(ent->objectId());
						break;
					}
				}
				ent->close();
			}
		}
	}
	acedSSFree(selName);
	return (entIds.length() > 0);
}

bool CSelectUtil::PromptSelectEnts(const TCHAR * prompt, resbuf * rb, AcRxClass *& classDescs, AcDbObjectIdArray & entIds)
{
	std::vector<AcRxClass*> vec;
	vec.push_back(classDescs);//将classDescs添加到了vec的尾部
	return CSelectUtil::PromptSelectEnts(prompt, rb, vec, entIds);
}
//提示用户选择一个实体,并检查所选实体是否符合一系列指定的类描述(...,包含类描述的向量,用于返回所选实体的引用,用于存储选择点的pickPoint,布尔值(决定打开实体的模式是只读还是可写)。
bool CSelectUtil::PromptSelectEntity(const TCHAR * prompt, std::vector<AcRxClass*>& classDescs, AcDbEntity *& pEnt, AcGePoint3d & pickPoint, bool bOpenForWrite)
{
	ads_name entName;
// 如果用户没有选择有效的实体(例如,取消了选择),代码会跳转到标签RETRY,重新提示用户进行选择。
RETRY:if (acedEntSel(prompt, entName, asDblArray(pickPoint)) == RTNORM) 
{
	AcDbObjectId oId;
	//尝试从AutoCAD的内部名称空间获取所选实体的对象ID。如果成功,它将返回ErrorStatus::eOk。
	if (acdbGetObjectId(oId, entName) == ErrorStatus::eOk) 
	//提示用户选择一个实体,并将所选实体的名称存储在entName中,同时将选择点存储在pickPoint中。
	{
		ErrorStatus es;
		if (bOpenForWrite) //决定是以写入模式还是读取模式打开所选实体
		{
			es = acdbOpenObject(pEnt, oId, AcDb::OpenMode::kForWrite);
		}
		else {
			es = acdbOpenObject(pEnt, oId, AcDb::OpenMode::kForRead);
		}
		//如果打开实体失败(例如,因为权限问题或实体不存在),函数会返回false。
		if (es != ErrorStatus::eOk) {
			pEnt = NULL;
			return false;
		}//否则,它会检查所选实体是否属于classDescs中的任何一个类
		else {
			bool ret = false;
			for (int i = 0; i < (int)classDescs.size(); i++)
			{   //检查所选实体是否属于指定的类
				if (pEnt->isKindOf(classDescs[i])) {
					ret = true;
					break;
				}
				else
				{
					pEnt = NULL;
					return false;
				}
			}
			if (ret)
				return true;
			else {
				pEnt->close();
				acutPrintf(L"\n选择的实体类型不符合要求,请再次选择...");
				goto RETRY;
			}
		}
	}
	else 
	{   //如果用户没有选择有效的实体(例如,取消了选择),这个调用会失败
		pEnt = NULL;
		return false;
	}
}

bool CSelectUtil::PromptSelectEntity(const TCHAR * prompt, AcRxClass *& classDescs, AcDbEntity *& pEnt, AcGePoint3d & pickPoint, bool bOpenForWrite)
{
	std::vector<AcRxClass*>vec;
	vec.push_back(classDescs);//将参数classDescs添加到向量vec中
	return CSelectUtil::PromptSelectEntity(prompt, vec, pEnt, pickPoint, bOpenForWrite);
}

 面域

#include "brbrep.h"
#include "brvtx.h"
#include "brface.h"
#include "bredge.h"
#include "brletrav.h"
#include "brbftrav.h"
#include "brfltrav.h"


AcDbObjectIdArray FymRegion::AddRegion(const AcDbObjectIdArray& objIds)//传入面域边界数据库对象id列表
{
	AcDbObjectIdArray regionArrs;//用于生成面域对象的数组
	AcDbVoidPtrArray curves;//指向面域曲线边界的指针列表
	AcDbVoidPtrArray regions;//指向新创建面域对象的指针列表
	AcDbEntity* pEnt = NULL;//关闭边界曲线实体对象的临时指针
	AcDbRegion* pRegion = NULL;//面域对象指针,用于将其添加到模型空间
	for (int i = 0; i < objIds.length(); i++)// 遍历边界对象
	{   // 提取每个边界对象的指针
		acdbOpenObject(pEnt, objIds.at(i), AcDb::kForRead);
		// 判断指针是否为曲线类的派生类(面域边界的必要条件)
		if (pEnt->isKindOf(AcDbCurve::desc()))
		{   // 将指针类型强制转换为曲线类对象
			AcDbCurve* pCurve = AcDbCurve::cast(pEnt);
			curves.append(pCurve);// 添加到指针列表中
		}
	}
	// 用AcDbRegion的方法创建面域:用指针列表curves创建面域
	Acad::ErrorStatus es = AcDbRegion::createFromCurves(curves, regions);
	if (es == Acad::eOk)
	{
		for (int i = 0; i < regions.length(); i++)
		{
			// pRegion = AcDbRegion::cast((AcDbRegion*)regions.at(i));
			pRegion = (AcDbRegion*)regions.at(i);
			pRegion->setDatabaseDefaults(); //重置pRegion对象的所有设置为默认值
			AcDbObjectId regId;
			regId = FymDatabase::PostToModelSpace(pRegion);
			regionArrs.append(regId);
		}
	}
	else
	{   // 如果创建失败,释放指针指向的内存空间
		for (int i = 0; i < regions.length(); i++)
		{
			delete(AcRxObject*)regions.at(i);
		}

	}
	// 关闭对象
	for (int i = 0; i < curves.length(); i++)
	{
		pEnt = (AcDbEntity*)curves.at(i);
		pEnt->close();
	}
	return regionArrs;
}

//通过遍历给定的面域的所有面和边,来获取面域中所有的点
void FymRegion::GetRegionPoints(AcDbRegion* pRegion, AcGePoint3dArray& points)
{
	AcBrBrep* pBrep = new AcBrBrep;
	pBrep->set(*pRegion);//数据复制
	AcBrBrepFaceTraverser brFaTrav;
	for (brFaTrav.setBrep(*pBrep); !brFaTrav.done(); brFaTrav.next())
		//使用brFaTrav遍历AcBrBrep的所有面
	{//在面遍历循环内部,创建AcBrFaceLoopTraverser对象并获取当前面的信息
		AcBrFaceLoopTraverser faLoTrav;
		AcBrFace face;
		brFaTrav.getFace(face);
		//使用faLoTrav遍历当前面的所有环。
		for (faLoTrav.setFace(face); !faLoTrav.done(); faLoTrav.next())
		{
			AcBrLoopEdgeTraverser loEdTrav;
			//在环遍历循环内部,创建AcBrLoopEdgeTraverser对象并尝试设置当前环
			// 。如果设置成功,进入下一轮循环。
			if (loEdTrav.setLoop(faLoTrav) == AcBr::eOk)
			{
				for (; !loEdTrav.done(); loEdTrav.next())
					//使用loEdTrav遍历环的所有边
				{
					AcBrEdge edge;
					loEdTrav.getEdge(edge);//获取当前边的信息
					AcBrVertex start;
					edge.getVertex1(start);//获取边的起始顶点
					AcGePoint3d pt;
					start.getPoint(pt);//获取起始顶点的坐标
					points.append(pt);//将该点的坐标添加到输出数组中
				}
			} // 否则就是一个孤立的循环    
		}
	}
	delete pBrep;
}

鼠标拖动 

DrawRecJig::DrawRecJig()
{
	pl = NULL;
}


DrawRecJig::~DrawRecJig()
{
}
//在拖动操作期间获取用户输入的点,并基于这个点以及拖动操作的状态来决定下一步的操作
AcEdJig::DragStatus DrawRecJig::sampler()
{
	setUserInputControls((AcEdJig::UserInputControls)(
		//这行代码设置了这个插件接受的用户输入控制。它接受三维坐标、不接受负响应以及接受空响应。
		AcEdJig::kAccept3dCoordinates |//接受z坐标
		AcEdJig::kNoNegativeResponseAccepted |//不接受负值
		AcEdJig::kNullResponseAccepted//空输入可接受
		));
	AcGePoint3d ptTemp;//临时存储拖动操作中的点
	//获取用户输入的点并存储在ptTemp中
	AcEdJig::DragStatus status = acquirePoint(ptTemp);
	if (ptTemp != ptCurrent) {
     //判断当前拖动的点是否与之前的点不同。如果不同,则更新ptCurrent为新的拖动点。
		ptCurrent= ptTemp;
	}
	else if (status == DragStatus::kNormal) {
	//如果拖动点的状态为正常(即没有特殊情况,例如无效输入或用户取消操作),
	// 则返回AcEdJig::kNoChange,表示没有发生改变
		return AcEdJig::kNoChange;
	}
	return status;


}
//绘图辅助,x型
bool DrawRecJig::update()
{
	double dist = CConvertUtil::ToPoint2d(ptCenter).distanceTo(CConvertUtil::ToPoint2d(ptCurrent));
	for (int i = 0; i < 4; i++)
	{
		double angle = i*MathUtil::PI()*0.5 + MathUtil::PI()*0.25;
		AcGePoint2d pt = FymGeometry::Polar(CConvertUtil::ToPoint2d(ptCenter), angle, dist);
		pl->setPointAt(i, pt);//将pt(在折线OCS坐标中)设置为索引顶点的位置,并储存在pl中
	}
	return true;
}

AcDbEntity * DrawRecJig::entity() const
{
	return pl;
}
//创建一个四边形多段线,并提示用户拖动它。如果用户按照提示操作,
// 该方法将把多段线发布到模型空间并返回成功;否则,它将删除多段线并返回失败
bool DrawRecJig::DoIt(AcGePoint3d & ptCenter, AcDbObjectId &plId)
{
	this->ptCenter = ptCenter;
	pl = new AcDbPolyline();
	for (int i = 0; i < 4; i++)
	{
		pl->addVertexAt(i, CConvertUtil::ToPoint2d(ptCenter));
	}
	pl->setClosed(true);

	setDispPrompt(L"请拖动鼠标:");

	if (drag()==kNormal) {

		plId=CDwgDataBaseUtil::PostToModelSpace(pl);

		return true;
	}
	else {
		delete pl;
		return false;

	}

}

 图形的复制,移动,旋转,对称,缩放

//根据给定的字符数组获取该实体的ID
//tips为acedEntSel()在暂停之前显示的可选字符串; 如果是空指针, AutoCAD将显示"选择对象"默认提示 
AcDbObjectId CTransUtil::GetId(const ACHAR *tips)
{
	ads_name entName; //存储AutoLISP实体名称
	ads_point pt; //存储点的坐标
	if (acedEntSel(tips, entName, pt) == RTNORM) {//选择AutoCAD中的实体
		AcDbObjectId oId;
		acdbGetObjectId(oId, entName);
		return oId;//根据给定的实体名称获取该实体的ID,并将该ID存储在变量oId中
	}
	else {
		return AcDbObjectId::kNull;
	}
}
//通过克隆给定的对象并返回新对象的ID
AcDbObjectId CTransUtil::MyClone(AcDbObjectId objId)
{
	if (objId == AcDbObjectId::kNull) 
	{
		return objId; 
	}
	else 
	{
		AcDbEntity *pEnt = NULL;
		//只读方式打开实体
		if (acdbOpenAcDbEntity(pEnt, objId, AcDb::OpenMode::kForRead) != ErrorStatus::eOk)
			return AcDbObjectId::kNull;
		AcDbEntity *copyEnt = AcDbEntity::cast(pEnt->clone());
		//克隆通过指针pEnt打开的实体,并将其转换为AcDbEntity类型的指针copyEnt
		AcDbObjectId copyId=CDwgDataBaseUtil::PostToModelSpace(copyEnt);
		//将克隆的实体发布到模型空间,并将返回的ID存储在变量copyId中。
		acutPrintf(TEXT("克隆成功!"));
		pEnt->close();
		return copyId;//关闭实体并返回新克隆实体的ID。
	}
}
//将指定的AutoCAD对象按照指定的移动点进行移动
void CTransUtil::Move(const AcGePoint3d & basePoint, const AcGePoint3d & movePoint, AcDbObjectId objId)
{
	AcDbEntity *pEnt = NULL;
	if (acdbOpenAcDbEntity(pEnt, objId, AcDb::OpenMode::kForWrite) != ErrorStatus::eOk)
		return;
	AcGeMatrix3d matrxMove;//3D变换矩阵,用于进行空间变换
	AcGeVector3d v = movePoint - basePoint;//从基础点到移动点的向量
	matrxMove.setTranslation(v);//使用向量v设置矩阵matrxMove的平移部分。这会使实体沿着这个向量移动。
	pEnt->transformBy(matrxMove);//使用矩阵matrxMove对实体进行变换。这会使实体沿着移动向量移动到新的位置。
	acutPrintf(TEXT("移动成功!"));
	pEnt->close();
}
//将指定的AutoCAD实体围绕指定的基点旋转指定的角度。
void CTransUtil::Rotate(const AcGePoint3d & basePoint, const double rotation, AcDbObjectId objId)
{
	AcDbEntity *pEnt = NULL;
	if (acdbOpenAcDbEntity(pEnt, objId, AcDb::OpenMode::kForWrite) != ErrorStatus::eOk)
		return;
	AcGeVector3d normal = AcGeVector3d(0, 0, 1);//旋转轴
	pEnt->transformBy(AcGeMatrix3d::rotation(rotation, normal, basePoint));
	/*使用基点、旋转角度和旋转轴对实体进行变换。这是通过调用transformBy方法实现的,
	该方法接受一个变换矩阵作为参数。在这个例子中,旋转矩阵是由AcGeMatrix3d::rotation函数生成的。*/
	acutPrintf(TEXT("旋转成功!"));
	pEnt->close();
}
//将指定的AutoCAD实体以指定的轴进行对称。
void CTransUtil::Mirrore(AcDbObjectId entId, const AcGeLine3d& line, double rotate)
{
	AcGeMatrix3d xform;//定义一个三维变换矩阵
	AcDbEntity *pEnt = NULL;
	if (acdbOpenAcDbEntity(pEnt, entId, AcDb::OpenMode::kForWrite) != ErrorStatus::eOk)
		return;
	pEnt->transformBy(AcGeMatrix3d::mirroring(line));
	acutPrintf(TEXT("对称成功!"));
	pEnt->close();
}

//将指定的AutoCAD实体以指定的基点缩放。
void CTransUtil::Scale(AcDbObjectId objId, double scale,AcGePoint3d &ptBase)
{
	AcDbEntity *pEnt = NULL;
	if (acdbOpenAcDbEntity(pEnt, objId, AcDb::OpenMode::kForWrite) != ErrorStatus::eOk)
		return;
	pEnt->transformBy(AcGeMatrix3d::scaling(scale, ptBase));
	//先调用AcGeMatrix3d::scaling函数创建一个表示缩放操作的矩阵,
	// 然后调用实体指针pEnt的transformBy方法,将这个矩阵应用于该实体。
	pEnt->close();
	acutPrintf(TEXT("缩放成功!"));
}

 图块的创建范例

void CreateBlock()
{
	AcDbBlockTable* pBlkTbl = NULL;//CAD中图块的表格
	acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlkTbl, AcDb::kForWrite);
	//从当前工作数据库中获取图块表,并将其设置为可写入的
	AcDbBlockTableRecord* pBlkRcd = new AcDbBlockTableRecord();
	//创建一个新的图块定义
	ACHAR blkName[40];//存储图块的名称
	if (acedGetString(Adesk::kFalse, _RXST("\n请输入图块名称:"), blkName) != RTNORM)
	{   //获取失败(例如用户取消输入),则关闭图块表和删除图块定义,并返回
		pBlkTbl->close();
		delete pBlkRcd;
		return;
	}
	pBlkRcd->setName(blkName);//设置图块的名称

	AcDbObjectId blkDefId;//存储图块定义的ID
	pBlkTbl->add(blkDefId, pBlkRcd);//将新的图块定义添加到图块表中
	pBlkTbl->close();//关闭图块表
	//以下定义了三个实体对象:一条线(pLine)、另一条线(pLine2)和一个圆(pCir)。这些对象代表了图块的实体
	AcGePoint3d ptStart(-10, 0, 0), ptEnd(10, 0, 0);
	AcDbLine* pLine = new AcDbLine(ptStart, ptEnd);
	ptStart.set(0, -10, 0);
	ptEnd.set(0, 10, 0);
	AcDbLine* pLine2 = new AcDbLine(ptStart, ptEnd);
	AcDbCircle* pCir = new AcDbCircle(AcGePoint3d::kOrigin, AcGeVector3d(0, 0, 1), 6);
	//使用appendAcDbEntity函数将这三个实体添加到图块定义中。注意,这里使用了entId,它应该是相同的ID,表示这些实体都属于同一个图块定义。
	AcDbObjectId entId;
	pBlkRcd->appendAcDbEntity(entId, pLine);
	pBlkRcd->appendAcDbEntity(entId, pLine2);
	pBlkRcd->appendAcDbEntity(entId, pCir);
	//关闭这些实体对象和图块定义。
	pLine->close();
	pLine2->close();
	pCir->close();
	pBlkRcd->close();
}

椭圆 

cDbObjectId FymEllipse::Add(const AcGePoint3d& ptCenter, const AcGeVector3d& vecNormal, const AcGeVector3d& majorAxis, double ratio)
{//缺省的两个参数为椭圆起始弧度与终止弧度,ratio为大半径与小半径比
	AcDbEllipse* pEllipse = new AcDbEllipse(ptCenter, vecNormal, majorAxis, ratio);
	return FymDatabase::PostToModelSpace(pEllipse);
}

AcDbObjectId FymEllipse::Add(const AcGePoint2d& pt1, const AcGePoint2d& pt2) {

	AcGePoint3d ptCenter;
	ptCenter = FymGeometry::GetMiddlePt(FymConverUtil::ToPoint3d(pt1), FymConverUtil::ToPoint3d(pt2));
	AcGeVector3d vecNormal(0, 0, 1);
	AcGeVector3d majorAxis(fabs(pt1.x - pt2.x) / 2, 0, 0);
	double ratio = fabs((pt1.y - pt2.y) / (pt1.x - pt2.x));
	return Add(ptCenter, vecNormal, majorAxis, ratio);
}

AcDbObjectId FymEllipse::Add(const AcGePoint2d& pt1, const AcGePoint2d& pt2, const AcGePoint2d& pt3)
{
	AcGePoint3d ptCenter;
	ptCenter = FymGeometry::GetMiddlePt(FymConverUtil::ToPoint3d(pt1), FymConverUtil::ToPoint3d(pt2));
	AcGeVector3d vecNormal(0, 0, 1);
	double ellipseAsq = pow(pt1.x - ptCenter.x, 2) + pow(pt1.y - ptCenter.y, 2);
	double ellipseBsq = pow(pt3.x - ptCenter.x, 2) + pow(pt3.y - ptCenter.y, 2);

	AcGeVector3d majorAxis;
	double ratio;
	if (ellipseAsq > ellipseBsq)
	{
		majorAxis = AcGeVector3d((ptCenter.x - pt1.x), (ptCenter.y - pt1.y), 0.0);
		ratio = sqrt(ellipseBsq/ellipseAsq);
	}
	else
	{
		majorAxis = AcGeVector3d((ptCenter.x - pt3.x), (ptCenter.y - pt3.y), 0.0);
		ratio = sqrt(ellipseAsq/ellipseBsq);
	}
	return Add(ptCenter, vecNormal, majorAxis, ratio);
}

 圆

AcDbObjectId FymCircle::Add(const AcGePoint3d& centerPt, const AcGeVector3d& normal, double radius)
{
	AcDbCircle* pcir = new AcDbCircle(centerPt, normal, radius);
	return FymDatabase::PostToModelSpace(pcir);
}

AcDbObjectId FymCircle::Add(const AcGePoint3d& centerPt, double radius)
{
	AcGeVector3d vec(0, 0, 1);//默认normal
	return Add(centerPt, vec, radius);
}

AcDbObjectId FymCircle::Add(const AcGePoint2d& point1, const AcGePoint2d& point2)//点在圆上
{
	AcGePoint2d center = FymGeometry::GetMiddlePt(point1, point2);
	AcGePoint3d center3d(center.x, center.y, 0.0);
	double radius = center.distanceTo(point1);//中点和点1距离
	return Add(center3d, radius);
}

AcDbObjectId FymCircle::AddByMath(const AcGePoint2d& point1, const AcGePoint2d& point2, const AcGePoint2d& point3)
{
	double xysm = 0, xyse = 0, xy = 0;
	AcGePoint3d ptCenter;
	double radius = 0;
	//sqrt为求平方根函数
	xy = pow(point1.x, 2) + pow(point2.y, 2);
	xyse = xy - pow(point3.x, 2) - pow(point3.y, 2);
	xysm = xy - pow(point2.x, 2) - pow(point2.y, 2);
	xy = (point1.x - point2.x) * (point1.y - point3.y) - (point1.x - point3.x) * (point1.y - point2.y);
	//fabs为绝对值函数
	if (fabs(xy) < 0.000001)
	{
		AfxMessageBox(_T("输入参数无效,不能创建图形!"));
		return AcDbObjectId::kNull;
	}
	ptCenter.x = (xysm * (point1.y - point3.y) - xyse * (point1.y - point2.y)) / (2 * xy);
	ptCenter.y = (xysm * (point1.x - point2.x) - xysm * (point1.x - point3.x)) / (2 * xy);
	ptCenter.z = 0.0;
	//sqrt为求平方根函数
	radius = sqrt((point1.x - ptCenter.x) * (point1.x - ptCenter.x) + (point1.y - ptCenter.y) * (point1.y - ptCenter.y));
	if (radius < 0.0000001)
	{
		AfxMessageBox(_T("半径过小!"));//在CAD界面弹出消息框
		return AcDbObjectId::kNull;
	}
	return Add(ptCenter, radius);
}

AcDbObjectId FymCircle::Add(const AcGePoint2d& point1, const AcGePoint2d& point2, const AcGePoint2d& point3)
{
	AcGeCircArc2d geArc(point1, point2, point3);
	AcGePoint3d center(geArc.center().x, geArc.center().y, 0.0);
	return Add(center, geArc.radius());
}

 多段线

AcDbObjectId FymPolyline::Add(const AcGePoint2dArray& points, double width, Adesk::Boolean isClosed)
{
	int numVerts = points.length();//计算输入点数组的长度
	AcDbPolyline* pPline = new AcDbPolyline(numVerts);
	for (int i = 0; i < points.length(); i++)
	{
		pPline->addVertexAt(i, points.at(i), 0, width, width, 0); //将每个点添加到多段线中
	}
	pPline->setClosed(isClosed);//为真,则多线段将被设置为闭合
	return FymDatabase::PostToModelSpace(pPline);
}

AcDbObjectId FymPolyline::Add(const AcGePoint2d& ptStart, const AcGePoint2d& ptEnd, double width)
{
	AcGePoint2dArray points;
	points.append(ptStart);
	points.append(ptEnd);
	return Add(points, width);
}
//2d多段线
AcDbObjectId FymPolyline::Add2dPolyline(const AcGePoint3dArray& points, double startWidth, double endWidth, Adesk::Boolean isClosed)
{
	AcGePoint3dArray verPoints = points;
	AcDb2dPolyline* pPline = new AcDb2dPolyline(AcDb::k2dSimplePoly, verPoints, 0, isClosed, startWidth, endWidth);
	return FymDatabase::PostToModelSpace(pPline);
}
//3d多段线
AcDbObjectId FymPolyline::Add3dPolyline(const AcGePoint3dArray& points)
{
	AcGePoint3dArray verPts = points;
	AcDb3dPolyline* pPline = new AcDb3dPolyline(AcDb::k3dSimplePoly, verPts);
	return FymDatabase::PostToModelSpace(pPline);
}
//正多边形,(rotation)为旋转角度
AcDbObjectId FymPolyline::Add3dPolyGon(const AcGePoint2d& ptCenter, int number, double radius, double rotation, double width)
{
	double angle = 2 * FymMathUtil::PI() / (double)number;//计算每个顶点与中心的夹角
	AcGePoint2dArray points;//存储多段线的所有顶点
	for (int i = 0; i < number; i++)
	{
		AcGePoint2d pt;
		pt.x = ptCenter.x + radius * cos(i * angle);
		pt.y = ptCenter.y + radius * sin(i * angle);
		points.append(pt);
	}
	AcDbObjectId polyId = Add(points, width, Adesk::kTrue);
	FymEditor::Rotate(polyId, ptCenter, rotation);
	return polyId;
}
//对角线矩形
AcDbObjectId FymPolyline::AddRectang(const AcGePoint2d& pt1, const AcGePoint2d& pt2, double width)
{
	double x1 = pt1.x, x2 = pt2.x;
	double y1 = pt1.y, y2 = pt2.y;
	AcGePoint2d ptLeftBottom(min(x1, x2), min(y1, y2));
	AcGePoint2d ptRightBottom(max(x1, x2), min(y1, y2));
	AcGePoint2d ptRightTop(max(x1, x2), max(y1, y2));
	AcGePoint2d ptLeftTop(min(x1, x2), max(y1, y2));

	AcGePoint2dArray points;
	points.append(ptLeftBottom);
	points.append(ptRightBottom);
	points.append(ptRightTop);
	points.append(ptLeftTop);

	return Add(points, width, Adesk::kTrue);
}
//测试:小爱心,bulge0.5为四分之一圆
AcDbObjectId FymPolyline::AddPolyCircle(const AcGePoint2d& ptCenter, double radius, double width)
{
	AcGePoint2d pt1, pt2, pt3, pt4;
	pt1.x = ptCenter.x + radius;
	pt1.y = ptCenter.y;
	pt2.x = ptCenter.x - radius;
	pt2.y = ptCenter.y;
	pt3.x = ptCenter.x ;
	pt3.y = ptCenter.y + radius;
	pt4.x = ptCenter.x;
	pt4.y = ptCenter.y - radius;

	AcDbPolyline* pPloy = new AcDbPolyline(4);
	pPloy->addVertexAt(0, pt1, 1, width, width);
	pPloy->addVertexAt(1, pt3, 1, width, width);
	pPloy->addVertexAt(2, pt2, 0.1, width, width);
	pPloy->addVertexAt(3, pt4, 0.1, width, width);
	pPloy->setClosed(Adesk::kTrue);

	return FymDatabase::PostToModelSpace(pPloy);
}

AcDbObjectId FymPolyline::SetWidth(const AcDbObjectId& polyId, ads_real width)
{
	AcDbPolyline* pPline = NULL;
	if (acdbOpenObject(pPline,polyId,AcDb::kForWrite)==Acad::eOk)
	{
		pPline->setConstantWidth(width);
		pPline->close();
	} 
	return FymDatabase::PostToModelSpace(pPline);

}

图案填充

//图案填充(ID,图案名称,图案缩放因子)
AcDbObjectId FymHatch::Add(const AcDbObjectIdArray& objIds, const ACHAR* patName, double patternScale)
{
	Acad::ErrorStatus es;
	//1创建空的填充对象
	AcDbHatch* pHatch = new AcDbHatch();
	//2设置填充平面
	AcGeVector3d normal(0, 0, 1);//法线
	pHatch->setNormal(normal);
	//设置图案的标高。首先设置为0,然后设置为true使图案在实体表面上方
	pHatch->setElevation(0);
	pHatch->setElevation(true);	//3设置关联性
	//设置填充图案类型为预定义,并指定图案名称为输入的 patName。
	pHatch->setPattern(AcDbHatch::kPreDefined, patName);
	//5添加填充边界
	es = pHatch->appendLoop(AcDbHatch::kExternal, objIds);
	//6显示填充对象
	es = pHatch->evaluateHatch();
	//7添加到模型空间
	AcDbObjectId hatchId = FymDatabase::PostToModelSpace(pHatch);
	//关联性填充,填充对象与边界进行绑定,使其能获得边界对象修改的通知
	if (acdbOpenObject(pHatch, hatchId, AcDb::kForRead) == Acad::eOk)
	{
		AcDbObjectIdArray assocEntids;
		pHatch->getAssocObjIds(assocEntids);
		//将与填充图案关联的所有对象的ID存储在assocEntids数组
		for (int i = 0; i < assocEntids.length(); i++)
		{
			AcDbEntity* pEnt = NULL;
			//以只写模式打开与当前关联对象ID对应的实体对象
			if (acdbOpenObject(pEnt, assocEntids.at(i), AcDb::kForWrite) == Acad::eOk)
			{
				pEnt->addPersistentReactor(hatchId);
				pEnt->close();
				/*如果成功打开了实体对象,这行代码将为该实体添加一个持久反应器(Reactor),
				该反应器的ID是当前的填充图案的ID(hatchId)。
				这意味着,每当该实体发生更改时,与其关联的填充图案也将被更新。*/
			}
		}
		pHatch->close();
	}
	return hatchId;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值