(16)ObjectARX2015 + vs2012利用 Transform 实现复制、移动等操作

1. 说明

        对实体执行一些移动、旋转、镜像等操作,这种情况下可以直接使用 acedCommand 函数调用相关的 AutoCAD 内部命令,也可以使用 AcDbEntity 类的 transformBy 函数,对实体进行相应的变换操作。

        实际上使用第一种方法在某些特定的情况下有一个致命的问题。由于 AutoCAD 内部命令和 ObjectARX 注册的命令在不同的线程中执行,因此有可能导致使用 acedCommand 函数的命令执行过程发生错乱。

        本篇的程序介绍使用 transformBy 函数对实体进行几何变换,其中的一些方法使用ObjectARX 中提供的一些基于 COM(组件对象模型)的全局函数来实现。
2. 思路
(1)  使用 transformBy函数进行几何变换( transformBy 函数
        transformBy 是 AcDbEntity 类的一个成员函数,该函数使用一个 AcGeMatrix3d 参数对实
体进行相应的几何变换,所有 AcDbEntity 的派生类都实现了这个虚函数,因此所有的实体都可以使用这种方法进行几何变换。
        函数原型为:
virtual Acad::ErrorStatus transformBy(const AcGeMatrix3d& xform);
        AcGeMatrix3d是一个几何类,用于表示一个四维矩阵,基本形式如图:

                        AcGeMatrix3d 提供了一些很有用的成员函数:
                                 setToTranslation:生成一个移动对象的矩阵。
                                 setToRotation:生成旋转矩阵。
                                 setToScaling:生成比例缩放矩阵。
                                 setToMirroring:生成镜像矩阵。
(2)复制实体( clone 函数
        AcDbObject 类拥有一个 clone 函数,能否生成一个调用者的克隆对象,并返回指向克隆对象的指针。由于所有实体对应的类都间接继承于 AcDbObject 类( AcDbEntity 类从 AcDbObject 类继承),因此所有实体都可以用这种方法进行克隆。
        (克隆后把它 添加到模型 空间中
        clone 函数仅仅会生成对象的一个克隆,对于实体对象来说,这样还没有完成复制操作的全部。在创建实体时我们已经了解到, 创建实体仅仅是第一个步骤,还必须把它添加到模型空间中才能被显示出来 ,对于克隆得到的实体同样需要这样做。
(3) 使用 AcAxXXX 全局函数
        在 ObjectARX 中有一系列 AcAx 开头的全局函数,这些函数通过 COM 的方式来让
AutoCAD 完成一些操作,这一篇我们能使用
                        AcAxMove、AcAxRotate 、   AcAxScaleEntity 函数分别完成
                        移动、          旋转、             缩放实体              的操作。
3. 步骤
(1) 对实体进行移动:使用 transformBy 函数
        使用 transformBy 函数移动实体的关键在于构建符合要求的 AcGeMatrix3d 对象,
AcGeMatrix3d 类的 setToTranslation 函数用于完成这个功能,它所接受的参数是一个三维矢
量,因此先根据移动的基点和目的点构建了一个 AcGeVector3d 对象。
//移动实体:使用 transformBy 函数
static Acad::ErrorStatus MoveEnt(AcDbObjectId entId, const AcGePoint3d &ptFrom, const AcGePoint3d &ptTo);
//移动实体:使用 transformBy 函数
Acad::ErrorStatus CCreateEnt::MoveEnt(AcDbObjectId entId, const AcGePoint3d &ptFrom, const AcGePoint3d &ptTo) 
{ 
	// 构建用于实现移动实体的矩阵
	AcGeVector3d vec(ptTo[X] - ptFrom[X], ptTo[Y] - ptFrom[X], ptTo[Z] - ptFrom[Z]); 
	AcGeMatrix3d mat; 
	mat.setToTranslation(vec); 
	AcDbEntity *pEnt = NULL; 
	Acad::ErrorStatus es = acdbOpenObject(pEnt, entId, AcDb::kForWrite);
	if (es != Acad::eOk) 
		return es; 
	es = pEnt->transformBy(mat); 
	pEnt->close(); 
	return es; 
}

(2) 对实体的移动:使用 AcAxMove 全局函数
//对实体的移动:使用 AcAxMove 全局函数
BOOL AcMove(AcDbObjectId entId, const AcGePoint3d &ptFrom, const AcGePoint3d &ptTo); 
//对实体的移动:使用 AcAxMove 全局函数
BOOL CGeometryOper::AcMove(AcDbObjectId entId, const AcGePoint3d &ptFrom, const AcGePoint3d &ptTo) 
{ 
	// 将AcGePoint3d类型的点坐标进行类型转换 
	VARIANT *pvaFrom = Point3dToVARIANT(ptFrom); 
	VARIANT *pvaTo = Point3dToVARIANT(ptTo); 
	BOOL bRet = SUCCEEDED(AcAxMove(entId, *pvaFrom, *pvaTo)); 
	delete pvaFrom; 
	delete pvaTo; 
	return bRet; 
}
        Point3dToVARIANT 是一个自定义函数,能根据 AcGePoint3d 对象生成一个 VARIANT
类型的对象,并返回指向该对象的指针。
        Point3dToVARIANT 函数的定义为:
//Point3dToVARIANT函数自定义
static VARIANT* Point3dToVARIANT(const AcGePoint3d &point) 
{ 
	COleSafeArray *psa = new COleSafeArray(); 
	DOUBLE dblValues[] = {point[X], point[Y], point[Z]}; 
	psa->CreateOneDim(VT_R8, 3, dblValues); 
	return (LPVARIANT)(*psa); 
}

//static 关键字限制了 Point3dToVARIANT 函数的作用域,在该文件之外不能使用这个函数。
//在 C++编程中,应该给函数尽量小的作用域,全局函数更要尽量避免出现,
//使用 static函数限制函数的作用域是一个好的方法。

        由于 VARIANT COleSafeArray 都无法直接作为函数的返回值,它们的复制操作必须使用专门的函数,而不像 C++中的标准类型直接可以复制拷贝,也就是说,下面的函数返回值总是无效的。

static COleSafeArray Point3dToVARIANT(const AcGePoint3d &point) 
{ 
    COleSafeArray sa; 
    DOUBLE dblValues[] = {point[X], point[Y], point[Z]}; 
    sa.CreateOneDim(VT_R8, 3, dblValues); 
    return sa; 
}

        由于在 Point3dToVARIANT 函数中使用 new 关键字动态分配了内存,那么调用它的函数必须释放返回值的内存空间,在 AcMove 函数中就分别释放了 pvaFrom pvaTo 所指向变量的空间。

(3)移动实体:对给定 ID 的实体的一个克隆,并且按照 ptFrom 和 ptTo 生成的矢量移动生成的克隆对象
//移动实体:对给定 ID 的实体的一个克隆,并且按照 ptFrom 和 ptTo 生成的矢量移动生成的克隆对象,
BOOL CopyEnt(AcDbObjectId entId, const AcGePoint3d &ptFrom, const AcGePoint3d &ptTo);
//移动实体:对给定 ID 的实体的一个克隆,并且按照 ptFrom 和 ptTo 生成的矢量移动生成的克隆对象,
BOOL CGeometryOper::CopyEnt(AcDbObjectId entId, const AcGePoint3d &ptFrom, const AcGePoint3d &ptTo) 
{ 
	AcDbEntity *pEnt = NULL; 
	if (acdbOpenObject(pEnt, entId, AcDb::kForRead) != Acad::eOk) 
		return FALSE; 
	AcDbEntity *pCopyEnt = AcDbEntity::cast(pEnt->clone()); 
	AcDbObjectId copyEntId; 
	if (pCopyEnt) 
		copyEntId = PostToModelSpace(pCopyEnt); 

	MoveEnt(copyEntId, ptFrom, ptTo); 
	return TRUE; 
}
        clone 函数能够生成调用者的一个克隆,该函数是 AcDbObject 类的一个成员函数,其原
型为:
virtual AcRxObject* clone() const;

        由于函数的返回值不是 AcDbEntity 类型的指针,因此必须通过一个很常用的方法进行实体指针的升级:

AcDbEntity *pCopyEnt = AcDbEntity::cast(pEnt->clone());
        Copy 函数中, PostToModelSpace 函数用于将实体添加到模型空间,同样使用 static 关键
字来限制其名称的可见性:
static AcDbObjectId PostToModelSpace(AcDbEntity* pEnt)
{ 
	AcDbBlockTable *pBlockTable; 
	acdbHostApplicationServices()->workingDatabase() 
		->getBlockTable(pBlockTable, AcDb::kForRead); 

	AcDbBlockTableRecord *pBlockTableRecord; 
	pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, 
		AcDb::kForWrite); 

	AcDbObjectId entId; 
	pBlockTableRecord->appendAcDbEntity(entId, pEnt); 

	pBlockTable->close(); 
	pBlockTableRecord->close(); 
	pEnt->close(); 
	return entId; 
}

(5)旋转实体

//旋转实体
Acad::ErrorStatus Rotate(AcDbObjectId entId, const AcGePoint2d &ptBase, double angle) 
//旋转实体
Acad::ErrorStatus CGeometryOper::Rotate(AcDbObjectId entId, const AcGePoint2d &ptBase, double angle) 
{ 
	// 构建变换矩阵
	AcGeMatrix3d mat; 
	mat.setToRotation(angle, AcGeVector3d::kZAxis, 
		AcGePoint3d(ptBase[X], ptBase[Y], 0.)); 
	// 对实体进行变换
	AcDbEntity *pEnt = NULL; 
	Acad::ErrorStatus es = acdbOpenObject(pEnt, entId, 
		AcDb::kForWrite); 
	if (es != Acad::eOk) 
		return es; 
	es = pEnt->transformBy(mat); 
	pEnt->close();
	return es; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值