ObjectARX(C++)-ADSRX和用户交互-用户交互的实现(UserIntereaction)

一,

(1)使用的ObjectARX向导创建新工程用户交互

 (2)编译,如果出现以下错误:

 错误C2338:/ RTCc拒绝符合代码,因此C ++标准库不支持它。删除此编译器选项,或定义_ALLOW_RTCc_IN_STL以确认您已收到此警告。

解决方法:

(3)新建一个常见的过滤器:右键 - “添加筛选器

(4)在普通文件夹中新建相互作用文件夹

 

(5)在交互文件夹中新建一个CGetInputUtil,用于获取用户的输入

(6)此时,将的.cpp文件拖入到筛选器中即可

 

打开项目的文件夹,发现头文件和源文件都在同一层级上,所以拖入到筛选器文件夹中不影响它的层级关系,筛选器文件夹只是给开发者起到一种分类作用

 (7)在其中新建一个成员函数GetPointReturnCode,指定基点的情况下提示用户拾取一个点,代码实现:

int CGetInputUtil::GetPointReturnCode(const AcGePoint3d &basePoint, const TCHAR* prompt, AcGePoint3d &point)
{
	//将基点转换为UCS坐标
	AcGePoint3d ucsBasePoint = CConvertUtil::WcsToUcsPoint(basePoint);

	int nReturn = acedGetPoint(asDblArray(ucsBasePoint), prompt, asDblArray(point));

	if (nReturn == RTNORM)
	{
		//acedGetPoint得到UCS坐标,转换为WCS
		point = CConvertUtil::UcsToWcsPoint(point);
	}

	return nReturn;
}

(8)其中的CConvertUtil类:

在CConvertUtil类中添加成员函数:AcGePoint3d WcsToUcsPoint(const AcGePoint3d&point); 实现代码:

AcGePoint3d CConvertUtil::WcsToUcsPoint( const AcGePoint3d &point )
{
	// 转换成世界坐标	
	AcGePoint3d pt;
	struct resbuf rbFrom, rbTo;
	rbFrom.restype = RTSHORT;
	rbFrom.resval.rint = 0; // from WCS
	rbTo.restype = RTSHORT;
	rbTo.resval.rint = 1; // to UCS
	
	acedTrans(asDblArray(point), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(pt));
	
	return pt;
}

注意,是静态静成员函数:

static AcGePoint3d WcsToUcsPoint(const AcGePoint3d &point);

(9)在GetInputUtil.cpp中添加头文件

#include "ConvertUtil.h"

(10)在CConvertUtil类中添加静态成员函数UcsToWcsPoint(const AcGePoint3d&point)

UcsToWcsPoint函数声明:

static AcGePoint3d UcsToWcsPoint(const AcGePoint3d &point);

UcsToWcsPoint函数实现: 

AcGePoint3d CConvertUtil::UcsToWcsPoint(const AcGePoint3d &point)
{
	// 转换成世界坐标	
	AcGePoint3d pt;
	struct resbuf rbFrom, rbTo;
	rbFrom.restype = RTSHORT;
	rbFrom.resval.rint = 1; // from UCS
	rbTo.restype = RTSHORT;
	rbTo.resval.rint = 0; // to WCS

	acedTrans(asDblArray(point), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(pt));

	return pt;
}

 (11)关于acedGetPoint函数:用于获取用户输入的一个点。

int acedGetPoint(
    const ads_point pt, 
    const ACHAR * prompt, 
    ads_point result
);

二,在CGetInputUtil类中新建一个函数用GetPoint,返回值为布尔

(1)用GetPoint函数声明

	static bool GetPoint(const AcGePoint3d &basePoint,
		const TCHAR* prompt, AcGePoint3d &point);

(2)用GetPoint函数实现

bool CGetInputUtil::GetPoint(const AcGePoint3d &basePoint,
	const TCHAR* prompt, AcGePoint3d &point)
{
	return (GetPointReturnCode(basePoint, prompt, point) == RTNORM);
}

三,在CGetInputUtil类中添加一个函数Ge​​tPointReturnCode,在不提供基点的情况下提示用户拾取一个点:

(1)实现的代码:

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

	return nReturn;
}

 (2)asDblArray函数:

这个内联函数返回VEC作为两个双精度的数组。

四,添加一个简化返回值的封装函数用GetPoint

实现代码:

bool CGetInputUtil::GetPoint(const TCHAR* prompt, AcGePoint3d &point)
{
	return (GetPointReturnCode(prompt, point) == RTNORM);
}

五,新建一个命令AddPolyBasic

(1)实现代码

static void AAAMyGroupAddPolyBasic() {
		// Put your command code here
		int index = 2;  //当前输入点的次数
		AcGePoint3d ptStart;
		if (!CGetInputUtil::GetPoint(TEXT("\n输入第一点:"), ptStart))
		{
			return;
		}

		AcGePoint3d ptPrevious, ptCurrent;//前一个参考点,当前拾取点
		ptPrevious = ptStart;
		AcDbObjectId polyId;  //多段线ID

		while (CGetInputUtil::GetPoint(ptPrevious, TEXT("\n输入下一点:"), ptCurrent))
		{
			if (index == 2)  //输入了第二个点,将多段线添加到模型空间
			{
				polyId = CPolylineUtil::Add(CConvertUtil::ToPoint2d(ptPrevious), CConvertUtil::ToPoint2d(ptCurrent));
			}
			else if (index > 2) //输入了更多的顶点,就向多段线添加一个顶点
			{
				AcDbPolyline *pPoly = NULL;
				if (acdbOpenObject(pPolyId, AcDb::kForWrite) == Acad::eOk)
				{
					pPoly->addVertexAt(index - 1, CConvertUtil::ToPoint2d(ptCurrent));
					pPoly->close();
				}
			}

			ptPrevious = ptCurrent;
			index++;
		}
	}

(2)添加一个类CPolylineUtil,

(3)添加2个成员函数

函数声明:

	// 创建优化多段线
	static AcDbObjectId Add(const AcGePoint2dArray &points, double width = 0);
	static AcDbObjectId Add(const AcGePoint2d &ptStart, const AcGePoint2d &ptEnd,
		double width = 0);

函数实现:

AcDbObjectId CPolylineUtil::Add(const AcGePoint2dArray &points, double width)
{
	int numVertices = points.length();
	AcDbPolyline *pPoly = new AcDbPolyline(numVertices);

	for (int i = 0; i < numVertices; i++)
	{
		pPoly->addVertexAt(i, points.at(i), 0, width, width);
	}

	AcDbObjectId polyId;
	polyId = CDwgDatabaseUtil::PostToModelSpace(pPoly);

	return polyId;
}

AcDbObjectId CPolylineUtil::Add(const AcGePoint2d &ptStart, const AcGePoint2d &ptEnd, double width)
{
	AcGePoint2dArray points;
	points.append(ptStart);
	points.append(ptEnd);

	return Add(points, width);
}

(4)创建类CDwgDatabaseUtil,添加成员函数PostToModelSpace

实现代码:

static void AAAMyGroupAddPolyBasic() {
		// Put your command code here
		int index = 2;  //当前输入点的次数
		AcGePoint3d ptStart;
		if (!CGetInputUtil::GetPoint(TEXT("\n输入第一点:"), ptStart))
		{
			return;
		}

		AcGePoint3d ptPrevious, ptCurrent;//前一个参考点,当前拾取点
		ptPrevious = ptStart;
		AcDbObjectId polyId;  //多段线ID

		while (CGetInputUtil::GetPoint(ptPrevious, TEXT("\n输入下一点:"), ptCurrent))
		{
			if (index == 2)  //输入了第二个点,将多段线添加到模型空间
			{
				polyId = CPolylineUtil::Add(CConvertUtil::ToPoint2d(ptPrevious), CConvertUtil::ToPoint2d(ptCurrent));
			}
			else if (index > 2) //输入了更多的顶点,就向多段线添加一个顶点
			{
				AcDbPolyline *pPoly = NULL;
				if (acdbOpenObject(pPoly,polyId, AcDb::kForWrite) == Acad::eOk)
				{
					pPoly->addVertexAt(index - 1, CConvertUtil::ToPoint2d(ptCurrent));
					pPoly->close();
				}
			}

			ptPrevious = ptCurrent;
			index++;
		}
	}

(5)在PolylineUtil.cpp中添加头文件

#include "DwgDatabaseUtil.h"

(6)在类CConvertUtil中添加成员函数ToPoint2d

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

需要注意的是,我们整个项目中所添加的函数都是静态成员函数,在函数声明中添加静态

(7)在acrxEntryPoint.cpp中添加头文件

#include "GetInputUtil.h"
#include "PolylineUtil.h"
#include "ConvertUtil.h"

(8)此时不妨加载程序,在AutoCAD的中输入命令AddPolyBasic

可以正确运行,并绘制多段线。 

六、注册新命令GetPointKeyword,用于实现在acedGetPoint函数中使用关键字的基本方法

(1)实现代码:

static void AAAMyGroupGetPointKeyword() {
		// Put your command code here

		int rc; //返回值
		TCHAR kword[20];  //关键字
		AcGePoint3d pt;
		acedInitGet(RSG_NONULL, TEXT("K W"));
		rc = CGetInputUtil::GetPointReturnCode(TEXT("\n输入一个点或[keyword1/keyword2]:"), pt);

		switch (rc)
		{
		case RTKWORD://输入了关键字
			if (acedGetInput(kword) != RTNORM)
			{
				return;
			}
			if (_tcscmp(kword, TEXT("K")) == 0)
			{
				acutPrintf(TEXT("\n选择的关键字是keyword1"));
			}
			else if (_tcscmp(kword, TEXT("W")) == 0)
			{
				acutPrintf(TEXT("\n选择的关键字是keyWord2!"));
			}
			break;
		case RTNORM:
			acutPrintf(TEXT("\n输入点的坐标是(%.2f,%.2f,%.2f)"),
				pt.x, pt.y, pt.z);
			break;
		default:
			break;
		}

	}

(2)acedInitGet(RSG_NONULL, TEXT("K W"))函数:

  初始化下一个对用户输入函数的调用所使用的选项,如acedGetXxx()、acedDragGen()、acedEntSel()、acedNEntSelP()或acedNEntSel()。

参数RSG_NONULL:控制位,支持或禁用某些输入值和输入样式。RSG_NONULL表示不允许空输入

参数TEXT("K W"):用户输入函数接受的可选的关键字列表;

(3)_tcscmp(kword, TEXT("K")):

如果两个字符串是相同的则返回零。

七、在acrxEntryPoint.cpp文件的static void AAAMyGroupAddPolyBasic()命令函数前面创建一个函数GetWidth,

用于获取用户输入的线宽。(若你的编译器为VC6,则是在UserInteractionCommands.app文件中添加)

实现代码:

	static ads_real GetWidth()
	{
		ads_real width = 0;
		if (acedGetReal(TEXT("\n输入线宽:"), &width) == RTNORM)
		{
			return width;
		}
		else
		{
			return 0;
		}
	}

八、GetWidth函数后面添加一个函数GetColorIndex,用于提示输入颜色索引值。注意添加static。

static int GetColorIndex()
	{
		int colorIndex = 0;
		if (acedGetInt(TEXT("\n输入颜色索引值(0~256):"), &colorIndex) != RTNORM)
		{
			return 0;
		}

		//处理颜色索引值无效的情况
		while (colorIndex < 0 || colorIndex > 256)
		{
			acedPrompt(TEXT("\n输入了无效的颜色索引值."));
			if (acedGetInt(TEXT("\n输入颜色索引值(0-256):"), &colorIndex) != RTNORM)
			{
				return 0;
			}
		}
		return colorIndex;
	}

九、注册一个新命令AddPoly,提示用户输入多段线的节点、线宽和颜色,完成多段线的创建。

实现代码为:

static void AAAMyGroupAddPoly() {
		// Put your command code here

		int colorIndex = 0; //颜色索引值
		ads_real width = 0; //多段线的线宽
		int index = 2; //当前输入点的次数

		//提示用户输入起点
		AcGePoint3d ptStart; //起点
		if (!CGetInputUtil::GetPoint(TEXT("\n输入第一点:"), ptStart))
		{
			return;
		}

		AcGePoint3d ptPrevious, ptCurrent;//前一个参考点,当前拾取点
		ptPrevious = ptStart;
		AcDbObjectId polyId;//多段线的Id

		//输入第二点
		acedInitGet(NULL, TEXT("W C O"));
		int rc = CGetInputUtil::GetPointReturnCode(ptPrevious,
			TEXT("\n输入下一点[宽度(W)/颜色(C)]<完成(O)>:"), ptCurrent);
		while (rc == RTNORM || rc == RTKWORD)
		{
			if (rc == RTKWORD) //如果用户输入了关键字
			{
				TCHAR kword[20];
				if (acedGetInput(kword) != RTNORM)
					return;

				if (_tcscmp(kword, TEXT("W")) == 0)
				{
					width = GetWidth();
				}
				else if (_tcscmp(kword, TEXT("C")) == 0)
				{
					colorIndex = GetColorIndex();
				}
				else if (_tcscmp(kword, TEXT("O")) == 0)
				{
					return;
				}
				else
				{
					acutPrintf(TEXT("\n无效的关键字."));
				}
			}
			else if (rc == RTNORM)//用户输入了点
			{
				if (index == 2)
				{
					//创建多段线
					polyId = CPolylineUtil::Add(CConvertUtil::ToPoint2d(ptPrevious), CConvertUtil::ToPoint2d(ptCurrent));
					AcDbPolyline *pPoly = NULL;
					if(acdbOpenObject(pPoly,polyId,AcDb::kForWrite) == Acad::eOk)
					{
						//修改多段线的颜色和线宽
						pPoly->setConstantWidth(width);
						pPoly->setColorIndex(colorIndex);
						pPoly->close();
					}
				}
				else if (index > 2)
				{
					//修改多段线,添加最后一个顶点
					AcDbPolyline *pPoly = NULL;
					if (acdbOpenObject(pPoly, polyId, AcDb::kForWrite) == Acad::eOk)
					{
						pPoly->addVertexAt(index - 1, CConvertUtil::ToPoint2d(ptCurrent));

						//修改多段线的颜色和线宽
						pPoly->setConstantWidth(width);
						pPoly->setColorIndex(colorIndex);

						pPoly->close();
					}
				}

				ptPrevious = ptCurrent;
				index++;
			}

			//提示用户输入新的节点
			acedInitGet(NULL, TEXT("W C O"));
			rc = CGetInputUtil::GetPointReturnCode(ptPrevious, TEXT("\n输入下一点[宽度(W)/颜色(C)]<完成(O)>"), ptCurrent);
		}
	}

 十、效果:

输入命令addpoly:

 

注意:宽度的关键字W 和 颜色关键字C 需要区分大小写

十一、项目UserIntereaction 的完整代码分享(开发环境:ObjectARX2018 + AutoCAD2018)

链接:https://pan.baidu.com/s/1qvbeEDP0-eMQb7vf4TncKQ 密码:osg6

参考资料:

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

猜你喜欢

转载自blog.csdn.net/qq_40416052/article/details/82077497