天气与日历 切换到窄版

 找回密码
 立即注册
中国膜结构网
十大进口膜材评选 十大国产膜材评选 十大膜结构设计评选 十大膜结构公司评选
楼主: admin1

ObjectArx块操作封装

[复制链接]

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
 楼主| 发表于 2024-5-4 11:02:07 | 显示全部楼层
ObjectARX中如何选择块参照中的对象

一、全局函数acedNEntSelP介绍
为了选中块参照中的实体,ObjectARX提供了一个接口:
int acedNEntSelP(
const ACHAR * str,
ads采用name entres,
ads采用point ptres,
int pickflag,
ads采用matrix xformres,
struct resbuf ** refstkres
);

const ACHAR * str:在选择块参照中实体时的提示语,如果为NULL,AutoCAD 显示默认的提示语。
ads采用name entres:选择实体的ads采用name名称。
ads采用point ptres:选择实体时点取的点。
int pickflag:指定acedNEntSelP是否用于和用户交互;如果为假,acedNEntSelP提示用户指定实体并忽略ptres;如果为真,使用ptres的初始值去选择实体。
ads采用matrix xformres:该4×4变换矩阵可以将实体的任意ECS坐标转换为WCS坐标。如果选择的实体不是嵌套实体,该值设为单位矩阵。利用这个矩阵,可以将选中的实体从ECS坐标系转换到WCS坐标系。
struct resbuf ** refstkres :包含嵌套实体的各级块参照。
注意,最后一个参数最为重要,它实际记录了选择对象的各级嵌套块参照。

二、实现方法介绍
利用acedNEntSelP参数中最后的链表参数,查看选择对象的各级嵌套块参照,并对块参照进行坐标变换,将其坐标转为当前图形的WCS坐标。
  1. BOOL SelectEntsFromBlock(CString csPrompt, PickSet &ssResult,AcGePoint3d& ptBase)
  2. {
  3.         ads采用name ent;
  4.         ads采用point pt;
  5.         ads采用matrix mat;
  6.         struct resbuf* pHead = NULL;
  7.         int iRet = acedNEntSelP(csPrompt, ent, pt, FALSE, mat, &pHead);
  8.         ads采用name entOuterBlock;
  9.         if (iRet == RTNORM)
  10.         {
  11.                 if (!pHead)
  12.                 {
  13.                         acutPrintf(采用T("这并不是一个块参照中的对象"));
  14.                         return FALSE;
  15.                 }
  16.                 ptBase.x = pt[0];
  17.                 ptBase.y = pt[1];
  18.                 ptBase.z = pt[2];
  19.                 //如果ent为块参照中的嵌套块参照对象,例如块参照A嵌套块参照B,块参照B嵌套块参照C,
  20.                 //用户点取了嵌套块C的某个实体,以下循环可以将ent修改为块参照B;并且获得最外层的块参照的ads采用name
  21.                 while (pHead && pHead->restype == RTENAME)
  22.                 {
  23.                         if (pHead && !pHead->rbnext)        //如果点取的是块参照中的非嵌套对象
  24.                         {
  25.                                 ads采用name采用set(pHead->resval.rlname, entOuterBlock);
  26.                                 break;
  27.                         }
  28.                         else if (pHead->rbnext && !pHead->rbnext->rbnext)        //如果点取的是块参照的嵌套对象
  29.                         {
  30.                                 ads采用name采用set(pHead->resval.rlname, ent);
  31.                                 ads采用name采用set(pHead->rbnext->resval.rlname, entOuterBlock);
  32.                                 break;
  33.                         }
  34.                         pHead = pHead->rbnext;
  35.                 }
  36.                 //求解块参照的变换矩阵
  37.                 AcGeMatrix3d matBlockRef;
  38.                 AcDbObjectId id;
  39.                 acdbGetObjectId(id, entOuterBlock);                //获取最外层块参照的ID
  40.                 AcDbBlockReference* pOuterBlockRef = NULL;
  41.                 if (Acad::eOk == acdbOpenObject(pOuterBlockRef, id, AcDb::kForRead))
  42.                 {
  43.                         if (pOuterBlockRef)
  44.                         {
  45.                                 //获取转换矩阵,从块表记录中的MCS坐标转为当前图形的WCS坐标
  46.                                 matBlockRef = pOuterBlockRef->blockTransform();
  47.                         }
  48.                         pOuterBlockRef->close();
  49.                 }
  50.                
  51.                 acdbGetObjectId(id, ent);        //获取用户选中实体的ID
  52.                 AcDbEntity* pEnt = NULL;
  53.                 AcDbEntity* pEntClone = NULL;
  54.                 if (Acad::eOk == acdbOpenObject(pEnt, id, AcDb::kForRead))
  55.                 {
  56.                         if (pEnt)
  57.                         {
  58.                                 pEntClone = (AcDbEntity*)pEnt->clone();
  59.                                 //此步骤是关键,复制出来实体以后,将实体从块参照自己的WCS坐标系转换为当前数据库的WCS
  60.                                 pEntClone->transformBy(matBlockRef);
  61.                                 AddToCurrentSpace(pEntClone, true);        //加入到当前数据库
  62.                         }
  63.                         pEnt->close();
  64.                 }
  65.                 //这里省略了对选择对象进行拖动的代码
  66.                 //...........
  67.                
  68.                 return TRUE;
  69.         }
  70.         else
  71.                 return FALSE;
  72. }
复制代码

 

 

 

 

ObjectArx块操作封装

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
 楼主| 发表于 2024-5-4 11:05:22 | 显示全部楼层
关于objectArx /CAD二次开发中“属性块”操作


objectArx /CAD二次开发中常见的“属性块”操作有
1.创建属性块
2.插入属性块
3.向现有的块参照中追加属性
4.读取块中属性值
5.修改块中属性值
6.判断块中是否包含某标识的属性
1.创建属性块
创建一个带属性的块定义时,可直观地将“属性”看成一个直线一样的“实体”,将其附加到块表记录中即可。下面函数演示的是创建包含两条直线,一个圆以及属性标志为“直径”,值为“20”的属性块定义。
  1. bool yBlock::createBlockWithAtt(CString blkName)
  2. {
  3.         // 获得当前图形数据库的块表
  4.         AcDbBlockTable *pBlkTbl = NULL;
  5.         acdbHostApplicationServices()->workingDatabase()
  6.                 ->getBlockTable(pBlkTbl, AcDb::kForWrite);
  7.         // 创建新的块表记录
  8.         AcDbBlockTableRecord *pBlkTblRcd ;
  9.         Acad::ErrorStatus es = pBlkTbl->getAt(blkName, pBlkTblRcd, AcDb::kForRead);
  10.         if (es == Acad::eOk)
  11.         {
  12.                 pBlkTbl->close();
  13.                 acutPrintf(采用T("记录已经存在"));
  14.                 return false;
  15.         }
  16.         pBlkTblRcd->setName(blkName);
  17.         // 将块表记录添加到块表中
  18.         AcDbObjectId blkDefId;
  19.         pBlkTbl->add(blkDefId, pBlkTblRcd);
  20.         pBlkTbl->close();
  21.         // 向块表记录中添加实体
  22.         AcGePoint3d ptStart(-10, 0, 0), ptEnd(10, 0, 0);
  23.         AcDbLine *pLine1 = new AcDbLine(ptStart, ptEnd);        // 创建一条直线
  24.         ptStart.set(0, -10, 0);
  25.         ptEnd.set(0, 10, 0);
  26.         AcDbLine *pLine2 = new AcDbLine(ptStart, ptEnd);        // 创建一条直线
  27.         AcGeVector3d vecNormal(0, 0, 1);
  28.         AcDbCircle *pCircle = new AcDbCircle(AcGePoint3d::kOrigin, vecNormal, 6);
  29.         // 创建一个属性  输入直径
  30.         AcDbAttributeDefinition *pAttDef = new AcDbAttributeDefinition(
  31.                 ptEnd, TEXT("20"), TEXT("直径"), TEXT("输入直径"));
  32.         AcDbObjectId entId;
  33.         pBlkTblRcd->appendAcDbEntity(entId, pLine1);
  34.         pBlkTblRcd->appendAcDbEntity(entId, pLine2);
  35.         pBlkTblRcd->appendAcDbEntity(entId, pCircle);
  36.         pBlkTblRcd->appendAcDbEntity(entId, pAttDef);
  37.         // 关闭实体和块表记录
  38.         pLine1->close();
  39.         pLine2->close();
  40.         pCircle->close();
  41.         pAttDef->close();
  42.         pBlkTblRcd->close();
  43.         return true;
  44. }
复制代码



2.插入属性块
当数据库内存在属性块时,插入属性块与插入普通快有较大区别,其过程可描述为:
1.插入一个普通的块参照
2.遍历块参照中对应的块表记录,如果找到的记录是属性定义,则创建一个属性,属性参数来自于块记录,最后附加到块参照中。
下面函数展示的是掺入一个属性块,参数idBlkDef(块定义ID),ptInsert(属性块插入位置),返回属性块参照。
  1. AcDbBlockReference* CreateAttBlkRef(const AcDbObjectId& idBlkDef, const AcGePoint3d& ptInsert)
  2. {
  3.         AcDbBlockReference* pBlkRef = new AcDbBlockReference(ptInsert, idBlkDef);
  4.         //判断指定的块表是否包含属性定义
  5.         AcDbBlockTableRecordPointer pBlkTblRcd(idBlkDef, AcDb::kForWrite);
  6.         if (Acad::eOk != pBlkTblRcd.openStatus())
  7.                 return pBlkRef;
  8.         if (!pBlkTblRcd->hasAttributeDefinitions())
  9.                 return pBlkRef;
  10.         //创建块表记录遍历器,用于访问块定义中的所有实体
  11.         AcDbBlockTableRecordIterator* pIter = NULL;
  12.         Acad::ErrorStatus es = pBlkTblRcd->newIterator(pIter);
  13.         if (Acad::eOk != es)
  14.                 return pBlkRef;
  15.         for (pIter->start(); !pIter->done(); pIter->step())
  16.         {
  17.                 AcDbEntity* pEnt = NULL;
  18.                 if (Acad::eOk != pIter->getEntity(pEnt, AcDb::kForRead))
  19.                         continue;
  20.                 //如果是属性定义,就向块参照添加属性
  21.                 AcDbAttributeDefinition* pAttDef = AcDbAttributeDefinition::cast(pEnt);
  22.                 if (pAttDef != NULL)
  23.                 {
  24.                         //创建一个新的属性对象
  25.                         AcDbAttribute* pAtt = new AcDbAttribute();
  26.                         //从属性定义获得属性对象的对象特征
  27.                         pAtt->setPropertiesFrom(pBlkRef);
  28.                         pAtt->setLayer(pBlkRef->layerId());
  29.                         //设置属性对象的其它特性
  30.                         pAtt->setInvisible(pAttDef->isInvisible());
  31.                         pAtt->setPosition(pAttDef->position());
  32.                         pAtt->setHeight(pAttDef->height());
  33.                         pAtt->setWidthFactor(pAttDef->widthFactor());
  34.                         pAtt->setRotation(pAttDef->rotation());
  35.                         pAtt->setHorizontalMode(pAttDef->horizontalMode());
  36.                         pAtt->setVerticalMode(pAttDef->verticalMode());
  37.                         pAtt->setAlignmentPoint(pAttDef->alignmentPoint());
  38.                         pAtt->setTextStyle(pAttDef->textStyle());
  39.                         pAtt->setAttributeFromBlock(pBlkRef->blockTransform());
  40.                         //获得属性对象的Tag、Prompt和TextString
  41.                         pAtt->setTag(pAttDef->tagConst());
  42.                         pAtt->setFieldLength(pAttDef->fieldLength());
  43.                         pAtt->setTextString(pAttDef->textStringConst());
  44.                         //设置颜色
  45.                         pAtt->setColorIndex(pAttDef->colorIndex());
  46.                         //向块参照追加属性对象
  47.                         pBlkRef->appendAttribute(pAtt);
  48.                         pAtt->close();
  49.                 }
  50.                 pEnt->close();
  51.         }
  52.         DEL(pIter);
  53.         return pBlkRef;
  54. }
复制代码



3.向现有的块参照中追加属性
当数据库中已经创建了块参照,而块参照中并无属性,以下函数展示了像现有的块参照中追加属性,注意,该块参照追加属性后,再插入一个新的同名块时,属性也存在块定义中了。
参数:blkRefId(块参照ID),ptPos(属性在块参照中的位置),strTag(属性标志)
prompt(属性提示字符串),strValue(属性值),textHeight(属性文字高度),textStyle(属性文字样式)
  1. bool AppendBlkAttribute(AcDbObjectId &blkRefId, AcGePoint3d ptPos, CString strTag, CString prompt, CString strValue,double textHeight, AcDbObjectId textStyle)
  2. {
  3.         if (!blkRefId.isValid())
  4.         {
  5.                 return false;
  6.         }
  7.         //
  8.         AcDbObjectPointer<AcDbBlockReference> pBlkRef(blkRefId, AcDb::kForWrite);
  9.         if (pBlkRef == NULL)
  10.         {
  11.                 return false;
  12.         }
  13.         AcDbObjectId blkTblRcdId = pBlkRef->blockTableRecord();
  14.         AcDbObjectPointer<AcDbBlockTableRecord> pBlkTblRcd(blkTblRcdId, AcDb::kForWrite);
  15.         AcDbBlockTableRecordIterator* pIter = NULL;
  16.         if (Acad::eOk != pBlkTblRcd->newIterator(pIter) || NULL == pIter)
  17.                 return false;
  18.         int nRs = 0;
  19.         for (pIter->start(); !pIter->done(); pIter->step())
  20.         {
  21.                 AcDbObjectId attId;
  22.                 if (Acad::eOk != pIter->getEntityId(attId))
  23.                         continue;
  24.                 AcDbObjectPointer<AcDbAttributeDefinition> pDef(attId, AcDb::kForRead);
  25.                 if (Acad::eOk != pDef.openStatus())
  26.                         continue;
  27.                 CString strText;
  28.                 CString strTagT = pDef->tagConst();
  29.                 if (strTagT.Compare(strTag) == 0)
  30.                 {
  31.                         //pDef->setPrompt(strPro);
  32.                         strText = pDef->textStringConst();
  33.                         return true;
  34.                 }
  35.         }
  36.         //添加属性
  37.         AcDbAttributeDefinition *pAttDef = new AcDbAttributeDefinition(ptPos, strValue, strTag,prompt);
  38.         pAttDef->setHeight(textHeight);
  39.         pAttDef->setInvisible(false);
  40.         pAttDef->setTextStyle(textStyle);
  41.         //pAttDef->setVisibility(AcDb::Visibility::kInvisible);
  42.         Acad::ErrorStatus es = pBlkTblRcd->appendAcDbEntity(pAttDef);
  43.         pAttDef->close();
  44.         if (es == Acad::eOk)
  45.         {
  46.                 AcDbAttribute *pAtt = new AcDbAttribute(ptPos, strValue, strTag);
  47.                 pAtt->setInvisible(false);
  48.                 pBlkRef->appendAttribute(pAtt);
  49.                 pAtt->close();
  50.         }
  51.         return false;
  52. }
复制代码


4.读取块中属性值
以下函数展示了获取块参照的属性标志以及对应的属性值
参数:idRef(块参照ID)
  1. std::map<CString, CString> GetAttInfoOnBlkRef(const AcDbObjectId& idRef)
  2. {
  3.         std::map<CString, CString> maptag;
  4.         AcDbObjectPointer<AcDbBlockReference> pBlkRef(idRef, AcDb::kForRead);
  5.         if (pBlkRef.openStatus() != Acad::eOk)
  6.                 return maptag;
  7.         AcDbObjectIterator* pIter = pBlkRef->attributeIterator();
  8.         if (!pIter)
  9.                 return maptag;
  10.         for (pIter->start(); !pIter->done(); pIter->step())
  11.         {
  12.                 AcDbObjectId attId = pIter->objectId();
  13.                 AcDbAttribute* pAtt = NULL;
  14.                 if (pBlkRef->openAttribute(pAtt, attId, AcDb::kForRead) != Acad::eOk)
  15.                         continue;
  16.                 maptag.insert(std::pair<CString, CString>(pAtt->tagConst(), pAtt->textStringConst()));
  17.                 pAtt->close();
  18.         }
  19.         DEL(pIter);
  20.         return maptag;
  21. }
复制代码


5.修改块中属性值
以下函数展示了设置属性块某个标志的值
参数:idRef(块参照ID),szTag(属性标志),szText(属性值)
  1. bool SetAttTextOnBlkRef(const AcDbObjectId& idRef, LPCTSTR szTag, LPCTSTR szText)
  2. {
  3.         AcDbObjectPointer<AcDbBlockReference> pBlkRef(idRef, AcDb::kForWrite);
  4.         if (pBlkRef.openStatus() != Acad::eOk)
  5.                 return false;
  6.         AcDbObjectIterator* pIter = pBlkRef->attributeIterator();
  7.         if (!pIter)
  8.                 return false;
  9.         bool bFlag = false;
  10.         for (pIter->start(); !pIter->done(); pIter->step())
  11.         {
  12.                 AcDbObjectId attId = pIter->objectId();
  13.                 AcDbAttribute* pAtt = NULL;
  14.                 if (pBlkRef->openAttribute(pAtt, attId, AcDb::kForWrite) != Acad::eOk)
  15.                         continue;
  16.                 CString strTempTag = pAtt->tagConst();
  17.                 if (采用tcsicmp(szTag, strTempTag) == 0)
  18.                 {
  19.                         pAtt->setTextString(szText);
  20.                         pAtt->close();
  21.                         bFlag = true;
  22.                         break;
  23.                 }
  24.                 pAtt->close();
  25.         }
  26.         DEL(pIter);
  27.         return bFlag;
  28. }
复制代码


6.判断块中是否包含某个标识的属性
以下函数展示了判断一个块中是否包含了标识为szTag的属性
参数:pBlkRef(块参照),szAttName(属性标志)
  1. bool IsExistAtt(AcDbBlockReference* pBlkRef, LPCTSTR szAttName)
  2. {
  3.         AcDbObjectIterator* pIter = pBlkRef->attributeIterator();
  4.         if (!pIter)
  5.                 return false;
  6.         for (pIter->start(); !pIter->done(); pIter->step())
  7.         {
  8.                 AcDbObjectId attId = pIter->objectId();
  9.                 AcDbAttribute* pAtt = NULL;
  10.                 if (pBlkRef->openAttribute(pAtt, attId, AcDb::kForRead) != Acad::eOk)
  11.                         continue;
  12.                 CString strTempTag = pAtt->tagConst();
  13.                 if (采用tcsicmp(szAttName, strTempTag) == 0)
  14.                 {
  15.                         pAtt->close();
  16.                         DEL(pIter);
  17.                         return true;
  18.                 }
  19.                 pAtt->close();
  20.         }
  21.         DEL(pIter);
  22.         return false;
  23. }
复制代码

 

 

 

 

ObjectArx块操作封装

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
 楼主| 发表于 2024-5-4 11:06:24 | 显示全部楼层
objectARX中如何插入动态块

最近遇到一个任务:提示用户选择一个动态块参照,然后复制这个块参照后提示用户插入到令一个地方。最开始,我将动态块参照复制到内存,然后插入到CAD图形数据库,发现动态属性都丢失了;后来,将块参照的blockTableRecord的ID找到,利用这个ID将块参照插入图形中,动态属性依然丢失。
后经反复验证,发现:
方法AcDbBlockReference::blockTableRecord返回的ID并不是动态块参照块定义的ID,只是图形中显示实体的块定义的ID;
方法AcDbDynBlockReference::dynamicBlockTableRecord()返回的才是动态块定义的ID。
  


代码实现
以下代码仅仅是插入了一个自定义属性为初始状态的动态块参照,如果需要修改动态块参照的自定义属性,可以通过AcDbDynBlockReference 类中的AcDbDynBlockReference::getBlockProperties获取相关属性,然后再利用自定义属性的方法对属性进行设置。
  1. void CopyDynBlockRef()
  2. {
  3.         //提示用户选择一个动态块
  4.         struct resbuf * rb = acutBuildList(RTDXF0, 采用T("INSERT"), RTNONE);
  5.         ads采用name ss;
  6.         CString arPrompt[2] = { 采用T("\n请选择一个块参照对象"),采用T("\n删除了一个块参照对象") };
  7.         if (RTNORM == acedSSGet(采用T(":S:$-M"), &arPrompt, NULL, rb, ss))
  8.         {
  9.                 //查看此块参照是否是动态块参照
  10.                 ads采用name ent;
  11.                 acedSSName(ss, 0, ent);
  12.                 AcDbObjectId idBlk;
  13.                 acdbGetObjectId(idBlk, ent);
  14.                 //查看是否为动态块参照
  15.                 AcDbDynBlockReference cDynBlkRef(idBlk);
  16.                 if (cDynBlkRef.isDynamicBlock())
  17.                 {
  18.                         //打开块参照对象
  19.                         AcGeMatrix3d mat;
  20.                         AcGePoint3d ptInset;
  21.                         AcDbEntity* pEnt = NULL;
  22.                         if (Acad::eOk != acdbOpenObject(pEnt, idBlk, AcDb::kForRead))
  23.                         {
  24.                                 acedSSFree(ss);
  25.                                 acutRelRb(rb);
  26.                                 return;
  27.                         }
  28.                         AcDbBlockReference* pRef = AcDbBlockReference::cast(pEnt);
  29.                         if (pRef)
  30.                         {
  31.                                 mat = pRef->blockTransform();
  32.                                 ptInset = pRef->position();
  33.                         }
  34.                         pEnt->close();
  35.                         //取出动态块定义的ID
  36.                         AcDbObjectId idBlkDef = AcDbObjectId::kNull;
  37.                         idBlkDef = cDynBlkRef.dynamicBlockTableRecord();
  38.                         if (idBlkDef)
  39.                         {
  40.                                 //插入新的动态块
  41.                                 AcDbBlockReference* pBlkRef = new AcDbBlockReference(AcGePoint3d(0, 0, 0), idBlkDef);
  42.                                 pBlkRef->transformBy(mat);
  43.                                 pBlkRef->setPosition(ptInset);
  44.                                 if (AcDbObjectId::kNull == AddToModelSpace(pBlkRef))
  45.                                 {
  46.                                         delete pBlkRef;
  47.                                         acedSSFree(ss);
  48.                                         acutRelRb(rb);
  49.                                         return;
  50.                                 }
  51.                                 //此处省略拖动代码
  52.                                 //.....
  53.                         }
  54.                 }
  55.                 acedSSFree(ss);
  56.         }
  57.         acutRelRb(rb);
  58. }
复制代码

 

 

 

 

ObjectArx块操作封装

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
 楼主| 发表于 2024-5-4 11:08:01 | 显示全部楼层
ObjectARX的对象引用关系以及深克隆(deepClone)
  1. https://blog.csdn.net/mary288267/article/details/128083520?ops采用request采用misc=%257B%2522request%255Fid%2522%253A%2522171479098616800185876283%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request采用id=171479098616800185876283&biz采用id=0&utm采用medium=distribute.pc采用search采用result.none-task-blog-2~blog~first采用rank采用ecpm采用v1~rank采用v31采用ecpm-15-128083520-null-null.nonecase&utm采用term=objectarx%20%20%E5%9D%97&spm=1018.2226.3001.4450
复制代码
  1. // THE FOLLOWING CODE APPEARS IN THE SDK DOCUMENT.
  2. // Class declarations
  3. //
  4. class AsdkOwnerDemo : public AcDbObject
  5. // This is a custom object class to demonstrate what is
  6. // necessary to create ownership trees.
  7. //
  8. // To keep it simple, this class has two data members: a
  9. // simple integer to represent normal data, and a hard
  10. // ownership ID data member to hold the object ID of an owned
  11. // object.
  12. //
  13. // Get and set functions are provided for both data members.
  14. //
  15. {
  16. public:
  17.     ACRX采用DECLARE采用MEMBERS(AsdkOwnerDemo);
  18.     AsdkOwnerDemo(): mIntval(0) {};
  19.     AsdkOwnerDemo(const Adesk::Int16& val): mIntval(val) {};
  20.     Adesk::Int16 intData();
  21.     Acad::ErrorStatus setIntData(const Adesk::Int16&);
  22.     AcDbHardOwnershipId idData();
  23.     Acad::ErrorStatus setIdData(const AcDbHardOwnershipId&);
  24.     Acad::ErrorStatus dwgInFields (AcDbDwgFiler*);
  25.     Acad::ErrorStatus dwgOutFields(AcDbDwgFiler*) const;
  26.     Acad::ErrorStatus dxfInFields (AcDbDxfFiler*);
  27.     Acad::ErrorStatus dxfOutFields(AcDbDxfFiler*) const;
  28. private:
  29.     Adesk::Int16 mIntval;
  30.     AcDbHardOwnershipId mObjId;
  31. };
  32. ACRX采用DXF采用DEFINE采用MEMBERS(AsdkOwnerDemo, AcDbObject,
  33. AcDb::kDHL采用CURRENT, AcDb::kMReleaseCurrent, 0,
  34.     ASDKOWNERDEMO, OWNERSHIP);
  35. // Gets the value of the integer data member.
  36. //
  37. Adesk::Int16 AsdkOwnerDemo::intData()
  38. {
  39.     assertReadEnabled();
  40.     return mIntval;
  41. }
  42. // Sets the value of the integer data member.
  43. //
  44. Acad::ErrorStatus AsdkOwnerDemo::setIntData(const Adesk::Int16& val)
  45. {
  46.     assertWriteEnabled();
  47.     mIntval = val;
  48.     return Acad::eOk;
  49. }
  50. // Returns a copy of the ownership ID data member.
  51. //
  52. AcDbHardOwnershipId AsdkOwnerDemo::idData()
  53. {
  54.     assertReadEnabled();
  55.     return mObjId;
  56. }
  57. // Sets the value of the ownership ID data member.
  58. //
  59. Acad::ErrorStatus AsdkOwnerDemo::setIdData(const AcDbHardOwnershipId& ownedId)
  60. {
  61.     if (ownedId.asOldId() == 0L) {
  62.         return Acad::eInvalidInput;
  63.     }
  64.     assertWriteEnabled();
  65.     mObjId = ownedId;
  66.     // Now set the backpointer.  A transaction is used for
  67.     // opening the object, so if the object is already
  68.     // open it won't prevent this setting from taking place.
  69.     //
  70.     AcDbObject *pObj;
  71.     AcTransaction *pTrans
  72.         = actrTransactionManager->startTransaction();
  73.     pTrans->getObject(pObj, ownedId, AcDb::kForWrite);
  74.     pObj->setOwnerId(objectId());
  75.     actrTransactionManager->endTransaction();
  76.     return Acad::eOk;
  77. }
  78. // Files data in from a DWG file.
  79. //
  80. Acad::ErrorStatus AsdkOwnerDemo::dwgInFields(AcDbDwgFiler* filer)
  81. {
  82.     assertWriteEnabled();
  83.     AcDbObject::dwgInFields(filer);
  84.     // For wblock filing we wrote out our owner as a hard
  85.     // pointer Id so now we need to read it in to keep things
  86.     // in sync.
  87.     //
  88.     if (filer->filerType() == AcDb::kWblockCloneFiler) {
  89.         AcDbHardPointerId id;
  90.         filer->readItem(&id);
  91.     }
  92.     filer->readItem(&mIntval);
  93.     filer->readItem(&mObjId);
  94.     return filer->filerStatus();
  95. }
  96. // Files data out to a DWG file.
  97. //
  98. Acad::ErrorStatus AsdkOwnerDemo::dwgOutFields(AcDbDwgFiler* filer) const
  99. {
  100.     assertReadEnabled();
  101.     AcDbObject::dwgOutFields(filer);
  102.     // Since objects of this class will be in the Named
  103.     // Objects Dictionary tree and may be hard referenced
  104.     // by some other object, to support wblock we need to
  105.     // file out our owner as a hard pointer Id so that it
  106.     // will be added to the list of objects to be wblocked
  107.     //
  108.     if (filer->filerType() == AcDb::kWblockCloneFiler)
  109.         filer->writeHardPointerId((AcDbHardPointerId)ownerId());
  110.     filer->writeItem(mIntval);
  111.     filer->writeItem(mObjId);
  112.     return filer->filerStatus();
  113. }
  114. // Files data in from a DXF file.
  115. //
  116. Acad::ErrorStatus AsdkOwnerDemo::dxfInFields(AcDbDxfFiler* filer)
  117. {
  118.     assertWriteEnabled();
  119.     Acad::ErrorStatus es;
  120.     if ((es = AcDbObject::dxfInFields(filer))
  121.         != Acad::eOk)
  122.     {
  123.         return es;
  124.     }
  125.     // Check if we're at the right subclass data marker.
  126.     //
  127.     if (!filer->atSubclassData(采用T("AsdkOwnerDemo"))) {
  128.         return Acad::eBadDxfSequence;
  129.     }
  130.     struct resbuf inbuf;
  131.     while (es == Acad::eOk) {
  132.         if ((es = filer->readItem(&inbuf)) == Acad::eOk) {
  133.             if (inbuf.restype == AcDb::kDxfInt16) {
  134.                 mIntval = inbuf.resval.rint;
  135.             } else if (inbuf.restype
  136.                 == AcDb::kDxfHardOwnershipId)
  137.             {
  138.                 acdbGetObjectId(mObjId,
  139.                     inbuf.resval.rlname);
  140.             }
  141.         }
  142.     }
  143.     return filer->filerStatus();
  144. }
  145. // Files data out to a DXF file.
  146. //
  147. Acad::ErrorStatus AsdkOwnerDemo::dxfOutFields(AcDbDxfFiler* filer) const
  148. {
  149.     assertReadEnabled();
  150.     AcDbObject::dxfOutFields(filer);
  151.     filer->writeItem(AcDb::kDxfSubclass, 采用T("AsdkOwnerDemo"));
  152.     filer->writeItem(AcDb::kDxfInt16, mIntval);
  153.     // Null object IDs are invalid: don't write them out.
  154.     //
  155.     if (mObjId.asOldId() != 0L) {
  156.         filer->writeItem(AcDb::kDxfHardOwnershipId, mObjId);
  157.     }
  158.     return filer->filerStatus();
  159. }
  160. // Creates an AsdkOwnerDemo object (pObjC) and adds data to
  161. // it.  Then, AsdkOwnerDemo pObjB is created and set to be
  162. // the owner of pObjC.  Next, AsdkOwnerDemo pObjA is created
  163. // and added to a dictionary in the named object dictionary.
  164. // Finally, pObjA is set to own pObjB. Technically, we could
  165. // just add pObjA to the named object dictionary itself, but
  166. // that's not appropriate because it would clutter up the
  167. // named object dictionary.
  168. //
  169. void createObjs()
  170. {
  171.     AcDbObjectId objIdA, objIdB, objIdC;
  172.     AcDbDictionary *pNamedobj;
  173.     AcDbDictionary *pDict = NULL;
  174.     AcDbDatabase *pCurDwg = acdbHostApplicationServices()->workingDatabase();
  175.     // Create object C with a dummy integer data value of 3.
  176.     //
  177.     AsdkOwnerDemo *pObjC = new AsdkOwnerDemo(3);
  178.     // Append object C to database without setting an owner.
  179.     //
  180.     pCurDwg->addAcDbObject(objIdC, pObjC);
  181.     pObjC->close();
  182.     // Create object B with a dummy integer data value of 2.
  183.     //
  184.     AsdkOwnerDemo *pObjB = new AsdkOwnerDemo(2);
  185.     // Append object B to the database without setting an owner.
  186.     //
  187.     pCurDwg->addAcDbObject(objIdB, pObjB);
  188.     // Now set up ownership for object C.  The
  189.     // AsdkOwnerDemo::setIdData() function takes the
  190.     // objectId parameter and copies it into the
  191.     // AcDbHardOwnershipId data member.  This places the
  192.     // object ID in a position to be filed out/in via the
  193.     // dwgInFields/dwgOutFields/dxfInFields/dxfOutFields
  194.     // member functions.  This constitutes primary
  195.     // "ownership."  The AsdkOwnerDemo::setIdData() function
  196.     // also calls each owned object's setOwnerId() member
  197.     // function to set the backpointer and establish the
  198.     // full two-way ownership link.
  199.     //
  200.     pObjB->setIdData(objIdC);
  201.     pObjB->close();
  202.     // Create object A with a dummy integer data value of 1.
  203.     //
  204.     AsdkOwnerDemo *pObjA = new AsdkOwnerDemo(1);
  205.     // Next, add objA to a dictionary in the named object
  206.     // dictionary.  This will establish ownership for objA,
  207.     // set the ownership backlink, and add it to the
  208.     // database.
  209.     //
  210.     pCurDwg->getNamedObjectsDictionary(pNamedobj,
  211.         AcDb::kForWrite);
  212.     // Get a pointer to the ASDK采用DICT dictionary.  If it
  213.     // doesn't exist, then create it and add it to the
  214.     // named object dictionary.
  215.     //
  216.     if (pNamedobj->getAt(采用T("ASDK采用DICT"), (AcDbObject*&) pDict,
  217.         AcDb::kForWrite) == Acad::eKeyNotFound)
  218.     {
  219.         pDict = new AcDbDictionary;
  220.         AcDbObjectId DictId;
  221.         pNamedobj->setAt(采用T("ASDK采用DICT"), pDict, DictId);
  222.     }
  223.     pNamedobj->close();
  224.     // add object A to the ASDK采用DICT dictionary
  225.     //
  226.     pDict->setAt(采用T("OBJA"), pObjA, objIdA);
  227.     pDict->close();
  228.     // Now set up ownership for object B.
  229.     //
  230.     pObjA->setIdData(objIdB);
  231.     pObjA->close();
  232. }
复制代码


  1. Acad::ErrorStatus AsdkOwnerDemo::dwgOutFields(AcDbDwgFiler* filer) const
  2. {
  3.     assertReadEnabled();
  4.     AcDbObject::dwgOutFields(filer);
  5.     // Since objects of this class will be in the Named
  6.     // Objects Dictionary tree and may be hard referenced
  7.     // by some other object, to support wblock we need to
  8.     // file out our owner as a hard pointer Id so that it
  9.     // will be added to the list of objects to be wblocked
  10.     //
  11.     if (filer->filerType() == AcDb::kWblockCloneFiler)
  12.         filer->writeHardPointerId((AcDbHardPointerId)ownerId());
  13.     filer->writeItem(mIntval);
  14.     filer->writeItem(mObjId);
  15.     return filer->filerStatus();
  16. }
复制代码

  1. Acad::ErrorStatus AsdkOwnerDemo::setIdData(const AcDbHardOwnershipId& ownedId)
  2. {
  3.     if (ownedId.asOldId() == 0L) {
  4.         return Acad::eInvalidInput;
  5.     }
  6.     assertWriteEnabled();
  7.     mObjId = ownedId;        //设置拥有对象的ID,硬拥有
  8.     // Now set the backpointer.  A transaction is used for
  9.     // opening the object, so if the object is already
  10.     // open it won't prevent this setting from taking place.
  11.     //现在,设置被拥有对象的拥有者是this指针指向对象的ID
  12.     AcDbObject *pObj;
  13.     AcTransaction *pTrans = actrTransactionManager->startTransaction();
  14.     pTrans->getObject(pObj, ownedId, AcDb::kForWrite);
  15.     pObj->setOwnerId(objectId());
  16.     actrTransactionManager->endTransaction();
  17.     return Acad::eOk;
  18. }
复制代码

 

 

 

 

ObjectArx块操作封装

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
 楼主| 发表于 2024-5-4 11:08:43 | 显示全部楼层
2 关于深克隆(Deep Clone)
2.1 深克隆基础
深克隆(deepClone)函数复制对象和它的的所有权引用,所有的指针引用会被忽略。而wBlock函数复制硬所有权引用以及硬指针引用,忽略软所有权引用和软指针引用。为了复制引用层次关系,所有的深克隆函数和wBlock函数同时处理对象和引用(包括所有权引用和指针引用),必要时将引用指向新的对象。
深克隆操作需要用到以后函数之一:

AcDbDatabase::deepCloneObjects()
AcDbDatabase::wblock()
AcDbDatabase::insert()

AcDbDatabase::deepCloneObjects()仅支持在一个数据库内克隆。如果你需要在数据库之间克隆对象,使用wblock()或insert()(比如,使用wblock()将对象复制到一个临时数据库,然后用insert() 将这个新数据库插入到目标数据库当中)。
通常情况下,你应当使用AcDbDatabase::deepCloneObjects(),AcDbDatabase::wblock(),AcDbDatabase::insert() ,你不需要知道如何生成ID映射,或者深复制的每个阶段详情。如果你创建了一个新类,并且你想要重载AcDbObject::deepClone() 或者AcDbObject::wblockClone(),你需要熟悉这些函数的细节。
在应用程序代码中,不应当直接调用对象的AcDbObject::deepClone() 和AcDbObject::wblockClone() 。他们仅仅作为更高层次克隆操作链中的一环。

2.2 clone() 和deepClone()
AcRxObject::clone() 函数仅仅克隆单一实体。AcDbObject::deepClone() 函数克隆该对象以及该对象拥有的其他对象。AcDbObject::deepClone()还会转换被克隆对象的引用关系。通常,deepClone函数更加安全。

2.3 关键概念
2.3.1 克隆和存档
深度克隆和wblock克隆操作都使用对象存档来复制(克隆)对象。创建一个新对象(即克隆对象)后,使用dwgOut()将原始对象存档到内存中。最后,使用dwgIn()将数据存到到到新的克隆对象中。

2.3.2 克隆和所有权
对象关系作为一个AcDbObjectId成员变量存在对象当中。在对象中存在四种不同关系类型——硬拥有者、软拥有者、硬指针、软指针。比如,如果你创建了一个需要文本样式的实体,这个实体对象应当会有一个AcDbObjectId类型的数据成员,指向某个AcDbTextStyleTableRecord对象;它应当会被作为硬指针被存档。这个AcDbObjectId成员被存档的方式决定了deepClone和wblock使用它的方式。
深克隆处理所有硬所有权和软所有权连接;wblock写块操作处理所有硬所有权和硬指针连接。


2.3.3 克隆和ID映射
ID映射是追踪克隆操作的一种机制。映射包含对象的ID对——源对象的ID(被称作"Key ID")和克隆对象或者目标对象ID(被称为"value ID")。ID映射也包含额外的ID对,在ID转换时需要这些非克隆的额外的ID。
当对某些对象调用deepCloneObjects()时,会克隆其他对象,因为这些对象与克隆对象的主集合具有所有权关系。您可以查看ID映射以查看克隆了哪些其他对象。

2.3.4 克隆和转换
深克隆和wblock克隆操作实际上包含两个步骤:克隆和转换。克隆步骤是调用dwgOut()和dwgIn()并复制对象的步骤。第二步是转换步骤,在这一步会使用ID映射来重新连接所有的对象,以反应新的对象引用关系。
在转换过程中,必须转换所有四种类型的对象ID。一些对象已克隆并位于ID映射中,而其他对象尚未克隆且不在映射中。在ID转换过程中,如果在ID映射中找不到与引用对应的ID对,则会发生以下两种情况之一。如果引用与引用它的对象位于同一数据库中,则不处理。否则,设置为NULL。

2.4 典型的deepClone操作
如何启动一个深克隆

获取所有需要克隆的对象集
将每个对象的ID放置于数组中(AcDbObjectIdArray)
创建一个新的ID映射(AcDbIdMapping),作为deepCloneObjects的输出参数
调用deepCloneObjects。
  1. void cloneSameOwnerObjects()
  2. {
  3.     // Step 1:  Obtain the set of objects to be cloned
  4.         // 步骤一:获取即将深克隆对象的集合
  5.     ads采用name sset;
  6.     if (acedSSGet(NULL, NULL, NULL, NULL, sset) != RTNORM) {
  7.         acutPrintf(采用T("\nNothing selected"));
  8.         return;
  9.     }
  10.     // Step 2: Add obtained objectIds to list of objects to be cloned
  11.         // 步骤二:将对象ID放置于容器中
  12.     AdInt32 length = 0;
  13.     acedSSLength(sset, &length);
  14.     AcDbObjectIdArray  objList;
  15.     AcDbObjectId ownerId = AcDbObjectId::kNull;
  16.     for (int i = 0; i < length; i++) {
  17.         ads采用name ent;
  18.         acedSSName(sset, i, ent);
  19.         AcDbObjectId objId;
  20.         acdbGetObjectId(objId, ent);
  21.         // check to be sure same owner as first object
  22.         AcDbObject *pObj;
  23.         acdbOpenObject(pObj, objId, AcDb::kForRead);
  24.         if (pObj->ownerId() == ownerId)
  25.             objList.append(objId);
  26.         else if (i == 0) {
  27.             ownerId = pObj->ownerId();
  28.             objList.append(objId);
  29.         }
  30.         pObj->close();
  31.     }
  32.     acedSSFree(sset);
  33.     // Step 3: Get the objectId of the desired owner for
  34.     // the cloned objects.  We'll use Model Space for
  35.     // this example.
  36.         //步骤三:获取这些复制后对象的新的拥有者ID,实际上就是模型空间
  37.     AcDbBlockTable *pBlockTable;
  38.     acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pBlockTable, AcDb::kForRead);
  39.     AcDbObjectId  modelSpaceId;
  40.     pBlockTable->getAt(ACDB采用MODEL采用SPACE, modelSpaceId);
  41.     pBlockTable->close();
  42.     // Step 4:  Create a new ID map
  43.     // 步骤4:新建一个ID映射
  44.     AcDbIdMapping idMap;
  45.     // Step 5: Call deepCloneObjects()
  46.     // 步骤4:调用deepCloneObjects
  47.     acdbHostApplicationServices()->workingDatabase()->deepCloneObjects(objList, modelSpaceId, idMap);
  48.     // Now we can go through the idMap and do whatever we'd
  49.     // like to the original and/or clone objects.
  50.     //
  51.     // For this example we'll print out the objectId's of
  52.     // the new objects resulting from the cloning process
  53.     // 现在,通过idMap,我们可以找到克隆后的对象了(AcDbIdPair中的key获取源对象ID,value获取克隆后的对象ID),然后对它任意操作。
  54.     AcDbIdMappingIter iter(idMap);
  55.     for (iter.start(); !iter.done(); iter.next()) {
  56.         AcDbIdPair idPair;
  57.         iter.getMap(idPair);
  58.         if (!idPair.isCloned())
  59.             continue;
  60.        
  61.         // 这里面有个有用的接口AcDbIdPair::isPrimary,用来判断ID对是否是主要对象(换句话说,不是因为被其他对象拥有才被克隆)。       
  62.         acutPrintf(采用T("\nObjectId is: %Ld"),
  63.             idPair.value().asOldId());
  64.     }
  65. }
复制代码


深克隆很有用处,比如复制动态块参照:一般的clone只会复制动态块转换而成的静态块;而deepClone则会原原本本的复制动态块参照。wblock写块操作用于数据库之间的数据写入,也非常有用。

 

 

 

 

ObjectArx块操作封装
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|中国膜结构网|中国膜结构协会|进口膜材|国产膜材|ETFE|PVDF|PTFE|设计|施工|安装|车棚|看台|污水池|中国膜结构网_中国空间膜结构协会

GMT+8, 2024-11-1 08:04 , Processed in 0.142500 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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