欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

程序员文章站 2022-05-22 10:19:38
...

(1)使用ObjectARX向导创建一个新项目,命名为BasicJig

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

developer symble随意填写:

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

选择:使用MFC共享DLL

必须使用MFC,否则后面会出现编译错误:

 fatal error C1189: #error:  WINDOWS.H already included.  MFC apps must not #include <windows.h>

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

 

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

(2)向工程中添加一个普通新类CDrawSquareJig,将它的父类修改为AcEdJig

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

然后为类添加几个函数头:

class CDrawSquareJig :
	public AcEdJig
{
public:
	CDrawSquareJig();

	virtual ~CDrawSquareJig();

	//外部调用的函数,一般用于Jig的初始化
	bool doIt(const AcGePoint3d &centerPoint,AcDbObjectId& polyId);

	//此函数将被drag函数调用以获得用户输入
	virtual AcEdJig::DragStatus sampler();

	//对需要在拖动过程中发生变化的实体进行修改
	virtual Adesk::Boolean update();

	//指定了Jig所操作的对象
	virtual AcDbEntity* entity() const;
}

 (3)添加三个私有的成员变量

private:
	AcDbPolyline* m_pPoly; //拖动过程中动态变化的实体
	AcGePoint3d m_curPoint;  //储存用户光标移动时临时点的临时位置
	AcGePoint3d m_centerPoint; //正方形的中心点

(4)在CDrawSquareJig类的构造函数中,需要对指针类型的成员变量进行初始化:

CDrawSquareJig::CDrawSquareJig()
{
	m_pPoly = NULL;
}

(5)添加doIt函数的实现代码:

bool CDrawSquareJig::doIt(const AcGePoint3d &centerPoint,
	AcDbObjectId &polyId)
{
	m_centerPoint = centerPoint;

	//拖动之前:将多段线创建出来
	m_pPoly = new AcDbPolyline();
	for (int i = 0; i < 4; i++) //将四个顶点连接,形成一个矩形
	{
		m_pPoly->addVertexAt(i, ToPoint2d(m_centerPoint));
	}
	m_pPoly->setClosed(Adesk::kTrue); //闭合顶点

	//进入拖动流程
	CString prompt = TEXT("\n指定标注插入点:"); 
	setDispPrompt(prompt); //使用一种dispPrompt 的拷贝作为后续的拖拽操作的新提示字符串。
	AcEdJig::DragStatus stat = drag();

	//拖动结束:函数返回部分
	if (stat == kNormal)
	{
		polyId = PostToModelSpace(m_pPoly);
		return true;
	}
	else
	{
		delete m_pPoly;
		return false;
	}

}

①注意:使用 CString,

CString prompt = TEXT("\n指定标注插入点:"); 

需要使用MFC,否则会出现下面的编译错误:

fatal error C1189: #error:  WINDOWS.H already included.  MFC apps must not #include <windows.h> 

②其中,ToPoint2d函数的实现:

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

③其中,PostToModelSpace函数的实现:

AcDbObjectId CDwgDatabaseUtil::PostToModelSpace( AcDbEntity *pEnt, AcDbDatabase *pDb )
{
	// 检查输入参数的有效性
	assert (pEnt);		// 等效于assert (pEnt != NULL);
	
	// 获得当前图形数据库的块表
	AcDbBlockTable *pBlkTbl = NULL;
	pDb->getBlockTable(pBlkTbl, AcDb::kForRead);
	
	// 获得模型空间对应的块表记录
	AcDbBlockTableRecord *pBlkTblRcd = NULL;
	pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForWrite);
	pBlkTbl->close();
	
	// 将实体添加到模型空间的块表记录
	AcDbObjectId entId;
	Acad::ErrorStatus es = pBlkTblRcd->appendAcDbEntity(entId, pEnt);
	if (es != Acad::eOk)
	{
		pBlkTblRcd->close();
		delete pEnt;	// 添加失败时,要delete
		pEnt = NULL;
		
		return AcDbObjectId::kNull;
	}
	
	// 关闭模型空间块表记录和实体
	pBlkTblRcd->close();
	pEnt->close();
	
	return entId;
}

(6)完成sampler函数的代码,他在拖动过程中收集用户信息并更新到成员变量:

//此函数将被drag函数调用以获得用户输入
AcEdJig::DragStatus CDrawSquareJig::sampler()
{
	setUserInputControls((UserInputControls)
		(AcEdJig::kAccept3dCoordinates
			| AcEdJig::kNoNegativeResponseAccepted
			| AcEdJig::kNullResponseAccepted));

	//一定要判断一下点是否发生了变化,否则update函数不停地被调用,实体反而不能被绘制出来
	static AcGePoint3d pointTemp;
	DragStatus stat = acquirePoint(m_curPoint);
	if (pointTemp != m_curPoint)
	{
		pointTemp = m_curPoint;
	}
	else if (stat == AcEdJig::kNormal)
	{
		return AcEdJig::kNoChange;
	}
	return stat;
	
}

关于setUserInputControls函数:

语法:

void setUserInputControls(
    AcEdJig::UserInputControls
);

描述:

设置用户输入控制属性。

控制属性:

AcEdJig::kAccept3dCoordinates 设置“接受Z坐标”模式。默认情况下,输入被限制为2d输入。
AcEdJig::kNoNegativeResponseAccepted 设置“不接受负值”模式。默认值接受负值。这适用于获取函数()和获取角()
AcEdJig::kNullResponseAccepted 设置用户输入请求包的“接受空输入”位。默认情况下btit是已知的,不接收null输入

(7)添加update函数实现代码

Adesk::Boolean CDrawSquareJig::update()
{
	//实现你的更新操作,在这里更新的是m_pPoly
	double dist = ToPoint2d(m_centerPoint).distanceTo(ToPoint2d(m_curPoint));
	for (int i = 0; i < 4; i++)
	{
		double angle = i * PI() * 0.5 + PI() *0.25;
		AcGePoint2d pt = PolarPoint(ToPoint2d(m_centerPoint), angle, dist);
		m_pPoly->setPointAt(i, pt);
	}

	return Adesk::kTrue;
}

 ①关于SetPointAt函数:

语法:

Acad::ErrorStatus setPointAt(
    Adesk::UInt16 idx, 
    const AcGePoint3d&
);

描述:

  这个函数把idx的值设置为pt.idx必须是0、1、2或3。pt必须在WCS坐标中。 

②PI()函数的实现:获得PI的值

double CDrawSquareJig::PI()
{
	return atan(1.0) * 4;
}

 

 ③PolarPoint函数的实现:根据极坐标的方式推算一个点的坐标

AcGePoint2d CDrawSquareJig::PolarPoint(const AcGePoint2d &basePoint, double angle, double length)
{
	double x = basePoint.x + length * cos(angle);
	double y = basePoint.y + length * sin(angle);

	return AcGePoint2d(x, y);
}

(8)添加entity函数的实现代码:

//指定了Jig所操作的对象
AcDbEntity* CDrawSquareJig::entity() const
{
	return m_pPoly;
}

(9)注册一个命令DrawSequareJig,

	static void AAAMyGroupSequareJig() {
		//提示用户输入中心点
		AcGePoint3d centerPoint;
		if (CDrawSquareJig::GetPoint(TEXT("\n指定正方形的中心点:"), centerPoint))
		{
			//进入拖动状态
			CDrawSquareJig jig;
			AcDbObjectId polyId;
			if (jig.doIt(centerPoint, polyId))
			{
				//成功创建之后,可以进行其他的修改
				CDrawSquareJig::SetColor(polyId, 1);
			}
			else
			{
				//用户取消,删除已经创建的实体
				CDrawSquareJig::Erase(polyId);
			}
		}

	}

其中,

①Erase函数实现:

	//删除已经被创建出来的实体
	static void Erase(AcDbObjectId entId);
void CDrawSquareJig::Erase(AcDbObjectId entId)
{
	AcDbEntity *pEnt = NULL;
	if (acdbOpenObject(pEnt, entId, AcDb::kForWrite) == Acad::eOk)
	{
		pEnt->erase();
		pEnt->close();
	}
}

②GetPoint函数的实现:

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

③GetPointReturnCode函数的实现:

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

	return nReturn;
}

 ④UcsToWcsPoint函数的实现:

static AcGePoint3d UcsToWcsPoint(const AcGePoint3d &point);
AcGePoint3d CDrawSquareJig::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;
}

⑤SetColor函数的实现:

static void CDrawSquareJig::SetColor(AcDbObjectId entId, int colorIndex);
void CDrawSquareJig::SetColor(AcDbObjectId entId, int colorIndex)
{
	// 检测参数的有效性
	assert(colorIndex >= 0 && colorIndex <= 256);

	AcDbEntity *pEnt = NULL;
	if (acdbOpenObject(pEnt, entId, AcDb::kForWrite) == Acad::eOk)
	{
		pEnt->setColorIndex(colorIndex);
		pEnt->close();
	}
}

整个项目的完整代码:

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

效果:

执行命令SequareJig,在CAD中选取一点为正方形的中心点,拖动鼠标,可得出下图所示图形:

【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

项目流程图:

 【CAD二次开发】-ObjectARX-JIG基本的拖动 BasicJig

参考资料:

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