|
拖动效果在AutoCAD中被广泛应用, 他在创建/修改实体时具有所见即所得的特点.本节介绍AutoCAD提供的最基本的Jig实现, 采用的例子是用拖动的方式来创建一个正方形.
2. 思路
实现Jig效果的核心是创建AcedJig类的一个子类,重写其中的几个虚函数sampler、update 和 entity,以及实现自己需要的效果,他们的作用如下:
(1) sampler(取样器): 将被AcEd::drag() 函数调用以获得用户输入(用户输入点、角度等).
(2) update: 更新实体,以反映在用户输入变换的过程中,图形中的实体需要发生怎样的变化.
(3) entity: 返回一个实体的指针,告诉AutoCAD哪个实体在被改变.
除此之外,一般会在子类中添加一个成员函数doIt(函数名称和变量都根据你的需求来确定),这个函数将被命令实现的函数所调用,对Jig对象进行初始化.
3. 步骤
(1) 创建一个新类 CDrawSquierJig ,父类设置为 ACEdJig
class CDrawSquareJig : public AcEdJig
{
public:
CDrawSquareJig(void);
virtual ~CDrawSquareJig(void);
public:
// 外部调用的函数,一般用于 Jig 的初始化
bool doIt();
// 此函数将被 drag 函数调用以获得用户输入
virtual AcEdJig::DragStatus sampler();
// 对需要在拖动过程中发生变化的实体进行修改
virtual Adesk::Boolean update();
// 指定了Jig 所操作的对象
virtual AcDbEntity* entity() const;
};
(2) 分析Jig的行为, 添加需要的成员变量. 先添加两个必须的成员变量, m_pPoly, m_curPoint, 考虑到在拖动过程中需要连续变化的是正方形的大小, 但是他的中心点是固定不变的, 因此还需要一个成员变量m_centerPoint, 并且他的值需要通过 doIt 函数传递进来,由此, 在类的头文件中需要添加三个私有成员变量, 并且完善了 doIt函数的声明部分.
class CDrawSquareJig : public AcEdJig
{
public:
CDrawSquareJig(void);
virtual ~CDrawSquareJig(void);
public:
// 外部调用的函数,一般用于 Jig 的初始化
bool doIt(const AcGePoint3d ¢erPoint, AcDbObjectId &polyId));
// 此函数将被 drag 函数调用以获得用户输入
virtual AcEdJig::DragStatus sampler();
// 对需要在拖动过程中发生变化的实体进行修改
virtual Adesk::Boolean update();
// 指定了Jig 所操作的对象
virtual AcDbEntity* entity() const;
private:
AcDbPolyline* m_pPoly; // 拖动过程中动态变化的实体
AcGePoint3d m_curPoint; // 存储用户光标移动时点的临时位置
AcGePoint3d m_centerPoint; // 正方形的中心点
};
(3) 在 CDrawSquierJig 类的构造函数中,需要对指针类型的成员变量进行初始化;
CDrawSquareJig::CDrawSquareJig(void)
{
m_pPoly = NULL; //初始化
}
(4) 添加 doIt 函数的实现代码
doIt 体现了拖动操作的三个步骤:
A. 拖动开始之前,创建拖动需要的实体和成员变量
B. 显示命令行提示,执行那个drag函数进行拖动流程
C. 拖动完成,函数在退出之前进行特定的操作
// 外部调用的函数,一般用于 Jig 的初始化
bool CDrawSquareJig::doIt(const AcGePoint3d ¢erPoint, 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 = _T("\n指定标注插入点: ");
setDispPrompt(prompt); //使用一种dispPrompt 的拷贝作为后续的拖拽操作的新提示字符串。
AcEdJig::DragStatus stat = drag();
// 拖动结束: 函数返回部分
CCreateEnt m_createEnt;
if (stat == kNormal)
{
polyId = m_createEnt.PostToModelSpace(m_pPoly);
return true;
}
else
{
delete m_pPoly;
return false;
}
}
// 转换为二维点
AcGePoint2d CDrawSquareJig::ToPoint2d(const AcGePoint3d &point3d)
{
return AcGePoint2d(point3d.x, point3d.y);
}
(5) sampler()函数: 他在拖动过程中收集用户输入信息并更新到成员变量
在用户移动光标的过程中,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输入
(6) update()函数
// 在sampler函数后被调用,他才是真正的更新实体的地方
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 * CGeometryOper::PI() * 0.5 + CGeometryOper::PI() *0.25;
AcGePoint2d pt = CGeometryOper::PolarPoint(ToPoint2d(m_centerPoint), angle, dist);
m_pPoly->setPointAt(i, pt);
}
return Adesk::kTrue;
}
重载极坐标函数
static AcGePoint2d PolarPoint(const AcGePoint2d& basePoint, double angle, double length); //重载极坐标
//根据相对极坐标来确定一个点的位置
AcGePoint2d CGeometryOper::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);
}
(7) entity() 函数
// 告诉AutoCAD哪个实体发生了变化,这里发生变化的是m_pPoly对象
AcDbEntity* CDrawSquareJig::entity() const
{
return m_pPoly;
}
(8) 实现绘制
// 实现绘制
static void DrawSequareJig();
void CDrawSquareJig::DrawSequareJig()
{
//提示用户输入中心点
AcGePoint3d centerPoint;
if (CDrawSquareJig::GetPoint(_T("\n指定正方形的中心点:"), centerPoint))
{
//进入拖动状态
CDrawSquareJig jig;
AcDbObjectId polyId;
if (jig.doIt(centerPoint, polyId))
{
//成功创建之后,可以进行其他的修改
CDrawSquareJig::SetColor(polyId, 1);
}
else
{
//用户取消,删除已经创建的实体
CDrawSquareJig::Erase(polyId);
}
}
用到的函数
static bool GetPoint(const TCHAR* prompt, AcGePoint3d &point);
static int GetPointReturnCode(const TCHAR* prompt, AcGePoint3d &point);
static AcGePoint3d UcsToWcsPoint(const AcGePoint3d &point);
static void CDrawSquareJig::SetColor(AcDbObjectId entId, int colorIndex);
//删除已经被创建出来的实体
static void Erase(AcDbObjectId entId);
// 如果Jig中用户取消了操作,就要删除已经被创建出来的实体
void CDrawSquareJig::Erase(AcDbObjectId entId)
{
AcDbEntity *pEnt = NULL;
if (acdbOpenObject(pEnt, entId, AcDb::kForWrite) == Acad::eOk)
{
pEnt->erase();
pEnt->close();
}
}
bool CDrawSquareJig::GetPoint(const TCHAR* prompt, AcGePoint3d &point)
{
return (GetPointReturnCode(prompt, point) == RTNORM);
}
int CDrawSquareJig::GetPointReturnCode(const TCHAR* prompt, AcGePoint3d &point)
{
int nReturn = acedGetPoint(NULL, prompt, asDblArray(point));
if (nReturn == RTNORM)
{
point = CDrawSquareJig::UcsToWcsPoint(point);
}
return nReturn;
}
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;
}
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();
}
}
(9) 在acrxEntryPoint.cpp中
ACED_ARXCOMMAND_ENTRY_AUTO(CArxConfigApp, MidasMyGroup, MyDrawSequareJig, MyDrawSequareJig, ACRX_CMD_MODAL, NULL) //选择实体
//当前项目中注册命令 DrawSequareJig(添加多个实体)
static void MidasMyGroupMyDrawSequareJig()
{
CDrawSquareJig::DrawSequareJig();
}
|
|