找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 882|回复: 2

[每日一码] 使用智能指针创建块和块参照

[复制链接]

已领礼包: 13个

财富等级: 恭喜发财

发表于 2017-12-13 12:35:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在讲解如何创建块/块参照前,先普及下AutoCAD图形数据库的基本知识。
通常我们打开或新建的一张dwg图纸就是一个图形数据库(Graphic Database),这是一个实实在在的数据库,由表(Table)和记录(TableRecord)组成。大家用AutoCAD画图,除了画线画实体外,还几乎必须用到图层表、标注样式表和线型表等,这就是在直接操作AutoCAD图形数据库的各种表。
具体来说,AutoCAD图形数据库由 9 个符号表和一个命名字典构成,每个表(table)下面是一条一条的记录(record)。这 9 个表分别是:
[td]
符号表名符号表功能
AcDbViewTable(视图表)适用于 AcDbViewTableRecord 类,表示在数据库中存储的视图。视图与CAD的”VIEW”命令相关联
AcDbViewportTable(视口表)适用于 AcDbViewportTableRecord 类,表示在CAD中当前系统变量TILEMODE的值为1时的视口设置。视口配置由CAD的 VPORTS 命令创建。不要和 MVIEW 命令混淆,当系统变量 TILEMODE 的值为0是,该命令创建视口实体。
AcDbLinetypeTable(线性表)适用于 AcDbLinetypeTableRecord 类,表示图形数据库中的线性。
AcDbLayerTable(层表)适用于 AcDbLayerTableRecord类,表示图层。
AcDbTextStyleTable(文字样式表)适用于 AcDbTextStyleTable 类,表示文字样式。
AcDbUCSTable(用户坐标系表)适用于 AcDbUCSTableRecord 类,表示图形数据库中的存储的用户坐标系。
AcDbRegAppTable(应用程序名注册表)适用于 AcDbRegAppTableRecord 类,表示为图形数据库中对象的扩展实体数据而注册的应用程序名。
AcDbDimStyleTable(尺寸标注样式表)适用于 AcDbDimStyleTableRecord 类,表示图形数据库中的尺寸标注样式。
AcDbBlockTable(块表)适用于 AcDbDimStyleTableRecord 类,表示图形数据库中定义的块。此表含有两个非常重要的记录:模型空间和图纸空间。所有的实体(可见对象)均防御块表AcDbBlockTable中。
通常进行的绘图操作,从编程角度来说是这样一个流程:

打开表 --> 从表里找到记录或创建新的纪录 --> 往记录里面添加实体或者修改里面的实体
新建一个实体的过程基本都是这样一个流程:
创建一个新实体以读方式打开块表以写方式打开块表记录,并在其中查找 ACDB_MODEL_SPACE 或 ACDB_PAPER_SPACE 或一个布局关闭块表把实体添加到块表记录关闭块表记录关闭实体对象
今天要做的演示是:选择实体后创建一个命名块,然后利用这个块插入块参照。
程序流程如下:
  • 选择实体,得到一个选择集(SelectionSet)
  • new 一个块表记录指针(BlockTableRecord * pBlockRecord)
  • 提示用户输入块的名字,并赋给上面的块表记录
  • 把 块表记录 添加到块表(BlockTable)中,同时记下与块表记录关联的 ObjectID
  • 利用上面块表记录的ID(ObjectID),向块表记录中添加选择集中的实体(Entity)
  • 利用块表记录的ID随意创建一个块参照(BlockReference)
  • 提示用户输入块参照的插入位置,随后插入块参照
简化的源程序如下,完整程序请到我们的 Github 主页上获取。



[C++] 纯文本查看 复制代码
// 随便创建一些实体
static void SquareOfLines(AcDbVoidPtrArray &ents, double size)
{
	AcGePoint3dArray pts;
	pts.append(AcGePoint3d(-size, -size, 0));
	pts.append(AcGePoint3d(size, -size, 0));
	pts.append(AcGePoint3d(size, size, 0));
	pts.append(AcGePoint3d(-size, size, 0));

	size_t max = pts.length()-1;
	for (size_t i = 0; i <= max; i++) {
		int j = (i == max ? 0 : i + 1);
		ents.append(new AcDbLine(pts[i],pts[j]));
	}
}

/* 创建块:
 *   1. 提示用户输入要创建的块的名字
 *   2. 打开块表(BlockTable),new一个新的块表记录(BlockTableRecord),设置这个BlockTableRecord的属性(主要是名字)
 *   3. 把上面的BlockTableRecord添加到BlockTable中,同时记录下ID(ObjectID)
 *   4. 选择实体(或随便创建出一些实体)添加到BlockTableRecord中
 *   5. 关闭BlockTableRecord 和 BlockTable。
 *   这样就完成了块的创建,随后就可以在CAD里插入这个块的块参照了。
 */
void create_block()
{
	TCHAR blockName[133];    // buffer for our block name
	AcDbVoidPtrArray ents;   // buffer for holding entities 
	AcDbObjectId newBlockId; 

	//get an instance of the database
	AcDbDatabase *pDatabase = acdbHostApplicationServices()->workingDatabase();

	//get the name of our new block
	if(acedGetString(1,_T("\n为块创建名字: "),blockName) != Acad::eNormal){
		acutPrintf(_T("\nError: 获取块名字失败 "));
		return;
	}

	//validate the block name
	if(acdbSymUtil()->validateSymbolName(blockName,false) != Acad::eOk){
		acutPrintf(_T("\nError: 符号 %s 不符合CAD的规范"),blockName);
		return;
	}

	//Open the Block Table using a smart Pointer
	AcDbBlockTablePointer pBlockTable(pDatabase->blockTableId(),AcDb::kForWrite);
	if(pBlockTable.openStatus() != eOk){
		acutPrintf(_T("\nError: 打开块表失败"));
		return;
	}

	//test if our block name already exists
	if(pBlockTable->has(blockName)){
		acutPrintf(_T("\nError: 块名字 (%s) 已经存在"),blockName);
		return;
	}

	//create our block using a smart pointer
	AcDbBlockTableRecordPointer pNewBlockTableRecord;
	pNewBlockTableRecord.create();
	pNewBlockTableRecord->setName(blockName);

	//add the new block to the Block Table
	if(pBlockTable->add(newBlockId,pNewBlockTableRecord)!= Acad::eOk){
		acutPrintf(_T("\nError: 添加块 (%s) 失败"), blockName);
		return;
	}
	//make a few lines
	SquareOfLines(ents,5);

	//add the lines to our block
	for(size_t i = 0 ; i < ents.length();i++)
	{
		AcDbEntity *pTmp = (AcDbEntity*)ents[i];
		if(pNewBlockTableRecord->appendAcDbEntity(pTmp) != eOk)
			delete pTmp;
		else
			pTmp->close();
	}

	//create a reference of our block
	AcDbObjectPointer<AcDbBlockReference> pNewBlockReference;
	pNewBlockReference.create();
	pNewBlockReference->setPosition(AcGePoint3d::kOrigin);
	pNewBlockReference->setBlockTableRecord(newBlockId);

	//open up the btr of the current space
	AcDbBlockTableRecordPointer pSpace(pDatabase->currentSpaceId(),AcDb::kForWrite);
	if(pSpace.openStatus() != eOk)
	{
		acutPrintf(_T("\nError: 打开当前空间失败"));
		return;
	}

	//add the insert to the current space;
	if(pSpace->appendAcDbEntity(pNewBlockReference) != eOk)
	{
		acutPrintf(_T("\nError: 添加块参照失败"));
		return;
	}

	//smart pointer do their mojo here.
	//智能指针负责关闭数据库的游标、释放资源等
}

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 488个

财富等级: 日进斗金

发表于 2017-12-22 23:58:20 | 显示全部楼层
for(size_t i = 0 ; i < ents.length();i++)
    {
        AcDbEntity *pTmp = (AcDbEntity*)ents;
        if(pNewBlockTableRecord->appendAcDbEntity(pTmp) != eOk)
            delete pTmp;
        else
            pTmp->close();
    }

/////////////////////
AcDbEntity *   改成 AcDbEntityPointer 会不会自己关闭? 加入到acarray了以后应该也可以吧
AcArray<AcDbEntityPointer>  这么应该可以???被AcArray占用会自动关闭吗?
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-11-22 16:27 , Processed in 0.266948 second(s), 32 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表