实体发布到模型空间
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;
}