REMOVEALLPROXY

Автор Тема: REMOVEALLPROXY  (Прочитано 115375 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
REMOVEALLPROXY
« : 31-10-2014, 10:02:07 »
Добрый день. Скорее всего вопрос к Александру.
Хочу вызвать данную команду через acedCmdLookup но она требует параметр (Очистить список масштабов? [Да/Нет] <Да>: Д)
Как можно это обойти или только пересобирать библиотеку?
Спасибо.

Код - C# [Выбрать]
  1.         public delegate void AcRxFunctionPtr();
  2.  
  3.         [StructLayoutAttribute(LayoutKind.Sequential)]
  4.         public struct AcEdCommandStruc
  5.         {
  6.             public AcRxFunctionPtr fcnAddr;
  7.             public int flags;
  8.             public System.IntPtr app;
  9.             public System.IntPtr hResHandle;
  10.             public System.IntPtr cmd;
  11.         }
  12.  
  13.         [StructLayoutAttribute(LayoutKind.Sequential)]
  14.         public struct HINSTANCE__
  15.         {
  16.             public int unused;
  17.         }
  18.  
  19.         [DllImportAttribute("acad.exe", EntryPoint = "acedCmdLookup")]
  20.         public static extern int acedCmdLookup([InAttribute()][MarshalAsAttribute(UnmanagedType.LPWStr)] string cmdStr,
  21.             int globalLookup,
  22.             ref AcEdCommandStruc retStruc,
  23.             int skipUndef);
  24.  
  25.         public  static bool LookupCommand(string command)
  26.         {
  27.             AcEdCommandStruc cs = new AcEdCommandStruc();
  28.             int res = acedCmdLookup(command, 1, ref cs, 1);
  29.  
  30.             if (res != 0)
  31.                 cs.fcnAddr.Invoke();
  32.             else
  33.                 return false;
  34.  
  35.             return true;
  36.         }
  37.  
« Последнее редактирование: 31-10-2014, 14:48:27 от Александр Ривилис »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #1 : 31-10-2014, 15:02:42 »
Приветствую на форуме!
Хочу вызвать данную команду через acedCmdLookup
Зачем? Есть куча других способов для этого. Кстати, команда _REMOVEALLPROXY - модальная, работающая только с текущим/активным чертежом, по этой причине не блокирует его и соответственно прямым вызовом может вызываться только из определенных контекстов.
Почему не вызвать её через Editor.RunCommand (или P/Invoke acedCmd) в версиях до 2014 и Editor.Command в версиях начиная с 2015?
Самый же радикальный способ переписать её с чистого ObjectARX на AutoCAD .NET API, что вполне возможно. Если хочешь, я выложу исходник на C++ и дам комментарии как его переделать на C#. Там со всеми обработками ошибок около сотни строк. Ну и если ты обязуешься выложить соответствующий исходник на C#. :) 
« Последнее редактирование: 31-10-2014, 16:05:39 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #2 : 31-10-2014, 15:59:02 »
Цитировать
Есть куча других способов для этого?
Возможно :)

Ее конкретно возможно и можно но есть другие команды которые я не могу использовать через RunCommand так как он не ждет окончания, acedCmd не работает с CommandFlags.Session
Если переводить на .Net тогда и EXPLODEALLPROXY нужно.
А перевести можно и исходники выложить. Буду ждать. Спасибо.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #3 : 31-10-2014, 18:33:40 »
но есть другие команды которые я не могу использовать через RunCommand так как он не ждет окончания
Ждет. Ты путаешь RunCommand с SendCommand. RunCommand - это непубличный метод класса Editor, который нужно вызвать хитрым способом.
Код - C# [Выбрать]
  1. // (c) 2013  Tony Tanzillo
  2. public static class EditorInputExtensionMethods
  3. {
  4.    public static PromptStatus Command( this Editor editor, params object[] args )
  5.    {
  6.       if( editor == null )
  7.          throw new ArgumentNullException( "editor" );
  8.       return runCommand( editor, args );
  9.    }
  10.  
  11.    static Func<Editor, object[], PromptStatus> runCommand = GenerateRunCommand();
  12.  
  13.    static Func<Editor, object[], PromptStatus> GenerateRunCommand()
  14.    {
  15.       MethodInfo method = typeof( Editor ).GetMethod( "RunCommand",
  16.          BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public );
  17.       var instance = Expression.Parameter( typeof( Editor ), "instance" );
  18.       var args = Expression.Parameter( typeof( object[] ), "args" );
  19.       return Expression.Lambda<Func<Editor, object[], PromptStatus>>(
  20.          Expression.Call( instance, method, args ), instance, args )
  21.             .Compile();
  22.    }
  23. }
  24. // Пример использования:
  25. //  var doc = Application.DocumentManager.MdiActiveDocument;
  26. //  var ed = doc.Editor;
  27. //  ed.Command("_REMOVEALLPROXY","_Y");

acedCmd не работает с CommandFlags.Session
Мне не очень понятно зачем тебе запускать команду из контекста приложения. Но если даже это и нужно, то делается это просто: делаешь фиктивную команду с флагом Modal, которую запускаешь из контекста приложения через AcadDocument.SendCommand или Document.SendStringToExecute. А все остальные действия выполняешь именно в этой команде.


« Последнее редактирование: 05-11-2014, 12:55:04 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #4 : 31-10-2014, 18:41:49 »
А перевести можно и исходники выложить. Буду ждать. Спасибо.
Код - C++ [Выбрать]
  1. typedef void __cdecl ACEDRESETSCALELIST(bool,bool,class AcDbDatabase *);
  2. static void RemoveAllProxy(void)
  3. {
  4.   Acad::ErrorStatus es;
  5.   AcDbDatabase *pDb = acdbCurDwg(); // Текущая база
  6.   AcDbHandle firstHandle = pDb->blockTableId().handle(); // Первая метка объекта - метка таблицы блоков
  7.   AcDbHandle lastHandle = pDb->handseed(); // Следующая после последней метки
  8.   int nObjects = pDb->approxNumObjects(); // Приблизительное количество объектов в базе
  9.   ACHAR buf[256],buf1[256]; lastHandle.getIntoAsciiBuffer(buf);
  10.   __int64 iLast = 0; swscanf(buf,_T("%I64x"),&iLast);
  11.   firstHandle.getIntoAsciiBuffer(buf1);
  12.   __int64 iFirst = 0; swscanf(buf1,_T("%I64x"),&iFirst);
  13.   __int64 nProxyTotal = 0, nProxyEntityTotal = 0;
  14.   acutPrintf(_T("\nПервая метка объекта: <%s>, последняя метка объекта: <%s>"),buf1,buf);
  15.   AcDbObjectIdArray ids;
  16.   // Массив меток заблокированных слоёв - их придётся временно разблокировать
  17.   AcDbObjectIdArray idsLockedLayers;
  18.  
  19.  for (__int64 i = iFirst; i < iLast && nObjects > 0; i++) {
  20.     AcDbHandle h(i);
  21.     AcDbObjectId id = AcDbObjectId::kNull;
  22.     if ((es = pDb->getAcDbObjectId(id,false,h)) == Acad::eOk) { // Получаем ObjectId по Handle
  23.       AcDbObjectPointer<AcDbObject> pObj(id,AcDb::kForRead);
  24.       if (pObj.openStatus() == Acad::eOk && pObj->isAProxy()) {
  25.         nProxyTotal++;
  26.         ids.append(id);
  27.         AcDbEntity *pEnt = AcDbEntity::cast(pObj.object());
  28.         if (pEnt) {
  29.           nProxyEntityTotal++;
  30.           AcDbObjectId idLayer = pEnt->layerId();
  31.           if (!idsLockedLayers.contains(idLayer)) {
  32.             AcDbLayerTableRecordPointer pLayer(idLayer,AcDb::kForWrite);
  33.             if (pLayer.openStatus() == Acad::eOk) {
  34.               if (pLayer->isLocked()) {
  35.                 pLayer->setIsLocked(false);
  36.                 idsLockedLayers.append(idLayer);
  37.               }
  38.             }
  39.           }
  40.         }
  41.       }
  42.       nObjects--;
  43.     }
  44.   }
  45.  
  46.  wsprintf(buf,_T("\nВсего найдено proxy-объектов: %I64d. Из них proxy-примитивов: %I64d."),nProxyTotal,nProxyEntityTotal); acutPrintf(_T("%s"),buf);
  47.  
  48.  ACEDRESETSCALELIST *acedResetScaleList = NULL;
  49.  HMODULE hAcad = LoadLibraryA("accore.dll");
  50.  if (!hAcad) hAcad = LoadLibraryA("acad.exe");
  51.  
  52.  if (hAcad != NULL) {
  53.  #ifdef _WIN64
  54.    acedResetScaleList = (ACEDRESETSCALELIST *)GetProcAddress(hAcad,"?acedResetScaleList@@YAX_N0PEAVAcDbDatabase@@@Z");
  55.  #else // _WIN64
  56.    acedResetScaleList = (ACEDRESETSCALELIST *)GetProcAddress(hAcad,"?acedResetScaleList@@YAX_N0PAVAcDbDatabase@@@Z");
  57.  #endif
  58.    if (acedResetScaleList) {
  59.      ACHAR res[256];
  60.      acedInitGet(0,_T("Да Нет Yes No _ Yes No Yes No"));
  61.      int rc = acedGetKword(_T("\nОчистить список масштабов? [Да/Нет] <Да>: "),res);
  62.      if (rc == RTNONE || (rc == RTNORM && !wcsicmp(res,_T("Yes")))) {
  63.        acedResetScaleList(true,false,acdbCurDwg());
  64.      }
  65.    }
  66.    FreeLibrary(hAcad);
  67.  }
  68.  
  69.   int nProxyDeleted = 0;
  70.   int nProxyEntityDeleted = 0;
  71.   for (int j=0; j < ids.length(); j++) {
  72.     AcDbObjectPointer<AcDbObject> pObj(ids[j],AcDb::kForWrite);
  73.     if (pObj.openStatus() == Acad::eOk) {
  74.       if (pObj->erase(true) == Acad::eOk) {
  75.         nProxyDeleted++;
  76.         if (AcDbEntity::cast(pObj.object())) {
  77.           nProxyEntityDeleted++;
  78.         }
  79.       } else {
  80.         AcDbObject *ppObj; pObj.release(ppObj);
  81.         if (AcDbEntity::cast(ppObj)) {
  82.           AcDbLine *pRep = new AcDbLine();
  83.           if (ppObj->handOverTo(pRep,false,false) == Acad::eObjectToBeDeleted) {
  84.             pRep->erase(); pRep->close();
  85.             delete ppObj;
  86.             nProxyDeleted++;
  87.             nProxyEntityDeleted++;
  88.           } else {
  89.             delete pRep;
  90.           }
  91.         } else {
  92.           AcDbDictionary *pRep = new AcDbDictionary();
  93.           if (ppObj->handOverTo(pRep,false,false) == Acad::eObjectToBeDeleted) {
  94.             pRep->erase(); pRep->close();
  95.             delete ppObj;
  96.             nProxyDeleted++;
  97.           } else {
  98.             delete pRep;
  99.           }
  100.         }
  101.       }
  102.     }
  103.   }
  104.  
  105.   for (int i = 0; i < idsLockedLayers.length(); i++)  {
  106.     AcDbLayerTableRecordPointer pLayer(idsLockedLayers[i],AcDb::kForWrite);
  107.     if (pLayer.openStatus() == Acad::eOk) {
  108.       pLayer->setIsLocked(true);
  109.     }
  110.   }
  111.   acutPrintf(_T("\nВсего удалено proxy-объектов: %d. Из них proxy-примитивов: %d."),nProxyDeleted,nProxyEntityDeleted);
  112.   acutPrintf(_T("\nДля проверки ошибок выполните команду _AUDIT"));
  113. }
« Последнее редактирование: 06-11-2014, 01:23:11 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #5 : 31-10-2014, 18:55:52 »
Код - C++ [Выбрать]
  1. enum ExplodeStatus {
  2.   success   =  0,
  3.   parmerr   = -1,
  4.   openerr   = -2,
  5.   explerr   = -3,
  6.   appenderr = -4,
  7.   eraseerr  = -5
  8. };
  9. static int ExplodeProxyInBTR(AcDbObjectId blkId, long &proxy, long &exploded);
  10. static void ExplodeAllProxy(void)
  11. {
  12.   AcDbObjectIdArray idsLockedLayers;
  13.   {
  14.     AcDbLayerTablePointer pTblBlk(acdbCurDwg()->layerTableId(),AcDb::kForRead);
  15.     AcDbLayerTableIterator *pIter = NULL;
  16.     if (pTblBlk->newIterator(pIter) == Acad::eOk && pIter) {
  17.       for (pIter->start(); !pIter->done(); pIter->step()) {
  18.         AcDbObjectId layId;
  19.         if (pIter->getRecordId(layId) == Acad::eOk) {
  20.           AcDbLayerTableRecordPointer pLayer(layId,AcDb::kForWrite);
  21.           if (pLayer.openStatus() == Acad::eOk) {
  22.             if (pLayer->isLocked()) {
  23.               pLayer->setIsLocked(false);
  24.               idsLockedLayers.append(layId);
  25.             }
  26.           }
  27.         }
  28.       }
  29.       delete pIter;
  30.     }
  31.   }
  32.  
  33.   AcDbBlockTablePointer pTblBlk(acdbCurDwg()->blockTableId(),AcDb::kForRead);
  34.   if (pTblBlk.openStatus() == Acad::eOk) {
  35.     AcDbBlockTableIterator *pIter = NULL;
  36.     if (pTblBlk->newIterator(pIter) == Acad::eOk && pIter) {
  37.       AcDbObjectIdArray blkIds;
  38.       for (pIter->start(); !pIter->done(); pIter->step()) {
  39.         AcDbObjectId blkId;
  40.         if (pIter->getRecordId(blkId) == Acad::eOk) {
  41.           blkIds.append(blkId);
  42.         }
  43.       }
  44.       delete pIter;
  45.       pTblBlk->close();
  46.       long exploded = 0, proxy = 0;
  47.       for (int i=0; i < blkIds.length(); i++) {
  48.         if (ExplodeProxyInBTR(blkIds[i],proxy,exploded) != success) {
  49.           acutPrintf(_T("\nОшибка расчленения ACAD_PROXY_ENTITY!"));
  50.         }
  51.       }
  52.       acutPrintf(_T("\nУдалено Proxy: %d Новых объектов: %d"), proxy, exploded);
  53.     } else {
  54.       acutPrintf(_T("\nНе могу создать итератор для таблицы блоков!"));
  55.     }
  56.   } else {
  57.     acutPrintf(_T("\nНе могу открыть таблицу блоков!"));
  58.   }
  59.   {
  60.     for (int i = 0; i < idsLockedLayers.length(); i++) {
  61.       AcDbLayerTableRecordPointer pLayer(idsLockedLayers[i],AcDb::kForWrite);
  62.       if (pLayer.openStatus() == Acad::eOk) {
  63.         pLayer->setIsLocked(true);
  64.       }
  65.     }
  66.   }
  67. }
  68. static int ExplodeProxyInBTR(AcDbObjectId blkId, long &proxy, long &exploded)
  69. {
  70.   Acad::ErrorStatus es = Acad::eOk;
  71.   AcDbBlockTableRecordIterator *pBlkIter = NULL;
  72.  
  73.   // Массив в который добавляются расчлененные proxy
  74.   AcDbVoidPtrArray aExplProxy;
  75.  
  76.   if (!blkId.isNull()) {
  77.     AcDbBlockTableRecordPointer pBtr(blkId,AcDb::kForRead);
  78.     if (pBtr.openStatus() != Acad::eOk) {
  79.       return openerr;
  80.     }
  81.     if (pBtr->newIterator(pBlkIter) != Acad::eOk || !pBlkIter) {
  82.       return openerr;
  83.     }
  84.  
  85.     for (pBlkIter->start(); !pBlkIter->done(); pBlkIter->step()) {
  86.       AcDbEntity *pEnt = NULL;
  87.       if (pBlkIter->getEntity(pEnt,AcDb::kForWrite) == Acad::eOk && pEnt) {
  88.         AcDbProxyEntity *pProxy = AcDbProxyEntity::cast(pEnt);
  89.         if (pProxy && (pProxy->graphicsMetafileType() == AcDbProxyEntity::kFullGraphics ||
  90.                        pProxy->graphicsMetafileType() == AcDbProxyEntity::kBoundingBox)) {
  91.           if (pProxy->graphicsMetafileType() == AcDbProxyEntity::kFullGraphics) {
  92.             pProxy->explode(aExplProxy);
  93.             proxy++;
  94.             if (pProxy->erase() != Acad::eOk) {
  95.               AcDbLine *pLine = new AcDbLine();
  96.               if (pProxy->handOverTo(pLine,false,false) == Acad::eObjectToBeDeleted) {
  97.                 pLine->erase(); pLine->close();
  98.                 delete pProxy;
  99.                 continue;
  100.               }
  101.             }
  102.           } else {
  103.             AcDbExtents ext;
  104.             if (pProxy->getGeomExtents(ext) == Acad::eOk) {
  105.               AcGePoint3dArray arr;
  106.               arr.append(ext.minPoint());
  107.               arr.append(AcGePoint3d(ext.minPoint().x,ext.maxPoint().y,ext.minPoint().z));
  108.               arr.append(AcGePoint3d(ext.maxPoint().x,ext.maxPoint().y,ext.minPoint().z));
  109.               arr.append(AcGePoint3d(ext.maxPoint().x,ext.minPoint().y,ext.minPoint().z));
  110.               AcDb3dPolyline *pPline = new AcDb3dPolyline(AcDb::k3dSimplePoly,arr,Adesk::kTrue);
  111.               aExplProxy.append(pPline);
  112.               pPline->setLayer(pProxy->layerId());
  113.               pPline->setLinetype(pProxy->linetypeId());
  114.               pPline->setColor(pProxy->color());
  115.             }
  116.             proxy++;
  117.             if (pProxy->erase() != Acad::eOk) {
  118.               AcDbLine *pLine = new AcDbLine();
  119.               if (pProxy->handOverTo(pLine,false,false) == Acad::eObjectToBeDeleted) {
  120.                 pLine->erase(); pLine->close();
  121.                 delete pProxy;
  122.                 continue;
  123.               }
  124.             }
  125.           }
  126.         }
  127.         pEnt->close();
  128.       }
  129.     }
  130.     exploded += aExplProxy.length();
  131.     delete pBlkIter;
  132.     AcDbObjectIdArray idsRef;
  133.     pBtr->getBlockReferenceIds(idsRef);
  134.  
  135.     if (aExplProxy.length() > 0) {
  136.       es = pBtr->upgradeOpen();
  137.       if (es == Acad::eOk || es == Acad::eWasOpenForWrite) {
  138.         for (int i=0; i < aExplProxy.length(); i++) {
  139.           AcDbEntity *pEnt = static_cast<AcDbEntity *>(aExplProxy[i]);
  140.           if (pEnt) {
  141.             Acad::ErrorStatus es_curr;
  142.             es_curr = pBtr->appendAcDbEntity(pEnt);
  143.             if (es_curr != Acad::eOk) {
  144.               delete (AcDbEntity *)aExplProxy[i];
  145.             } else {
  146.               pEnt->close();
  147.             }
  148.           }
  149.         }
  150.       }
  151.  
  152.       pBtr->close();
  153.  
  154.       for (int i=0; i < idsRef.length(); i++) {
  155.         AcDbObjectPointer<AcDbBlockReference> pRef(idsRef[i],AcDb::kForWrite);
  156.         if (pRef.openStatus() == Acad::eOk) {
  157.           pRef->recordGraphicsModified();
  158.         }
  159.       }
  160.     }
  161.     return success;
  162.   } else {
  163.     return openerr;
  164.   }
  165. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #6 : 05-11-2014, 14:45:08 »
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. #if CORE
  7. using AcAp = Autodesk.AutoCAD.ApplicationServices.Core;
  8. #else
  9. using AcAp = Autodesk.AutoCAD.ApplicationServices;
  10. #endif
  11. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  12. using AcEd = Autodesk.AutoCAD.EditorInput;
  13. using AcGe = Autodesk.AutoCAD.Geometry;
  14. using Autodesk.AutoCAD.DatabaseServices;
  15. using Autodesk.AutoCAD.Geometry;
  16.  
  17. namespace ImplementLink
  18. {
  19.     public static class Acad
  20.     {
  21.         #region Static Properties
  22.  
  23.         public static Autodesk.AutoCAD.ApplicationServices.Document Document
  24.         {
  25.             get { return AcAp.Application.DocumentManager.MdiActiveDocument; }
  26.         }
  27.  
  28.         public static AcDb.Database Database
  29.         {
  30.             get { return AcAp.Application.DocumentManager.MdiActiveDocument.Database; }
  31.         }
  32.  
  33.         public static AcEd.Editor Editor
  34.         {
  35.             get { return AcAp.Application.DocumentManager.MdiActiveDocument.Editor; }
  36.         }
  37.  
  38.         public static AcDb.TransactionManager TransactionManager
  39.         {
  40.             get { return AcAp.Application.DocumentManager.MdiActiveDocument.TransactionManager; }
  41.         }
  42.  
  43.         #endregion
  44.  
  45.         #region Transactional Methods
  46.  
  47.         public static T Read<T>(this AcDb.ObjectId objectId, bool openErased = false, bool forceOpenOnLockedLayer = true)
  48.             where T : AcDb.DBObject
  49.         {
  50.             return objectId.GetObject(AcDb.OpenMode.ForRead, openErased, forceOpenOnLockedLayer) as T;
  51.         }
  52.  
  53.         public static T Write<T>(this AcDb.ObjectId objectId, bool openErased = false, bool forceOpenOnLockedLayer = true)
  54.             where T : AcDb.DBObject
  55.         {
  56.             return objectId.GetObject(AcDb.OpenMode.ForWrite, openErased, forceOpenOnLockedLayer) as T;
  57.         }
  58.  
  59.         #endregion
  60.     }
  61. }
  62.  

Код - C# [Выбрать]
  1. #if CORE
  2.         public const string ACAD = "accore.dll";
  3.         public const string ACDB = "acdb19.dll";
  4. #else
  5.         public const string ACAD = "acad.exe";
  6.         public const string ACDB = "acdb18.dll";
  7. #endif
  8.  
  9. #if WIN32
  10.         [DllImport(ACAD, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedResetScaleList@@YAX_N0PAVAcDbDatabase@@@Z")]
  11.         public static extern void acedResetScaleList(bool b1, bool b2, IntPtr db);
  12. #else
  13.         [DllImport(ACAD, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedResetScaleList@@YAX_N0PEAVAcDbDatabase@@@Z")]
  14.         public static extern void acedResetScaleList(bool b1, bool b2, IntPtr db);
  15. #endif
  16.  
  17.         private static int PurgeDatabase(Database db)
  18.         {
  19.             int idCount = 0;
  20.             using (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument())
  21.             using (var tr = Acad.Database.TransactionManager.StartTransaction())
  22.             {
  23.                 ObjectIdCollection idsToPurge = new ObjectIdCollection();
  24.                 RegAppTable rat = (RegAppTable)tr.GetObject(db.RegAppTableId, OpenMode.ForRead);
  25.  
  26.                 foreach (ObjectId raId in rat)
  27.                 {
  28.                     if (raId.IsValid)
  29.                     {
  30.                         idsToPurge.Add(raId);
  31.                     }
  32.                 }
  33.  
  34.                 db.Purge(idsToPurge);
  35.  
  36.                 foreach (ObjectId id in idsToPurge)
  37.                 {
  38.                     DBObject obj = tr.GetObject(id, OpenMode.ForWrite);
  39.                     obj.Erase();
  40.                 }
  41.  
  42.                 idCount = idsToPurge.Count;
  43.                 tr.Commit();
  44.             }
  45.             return idCount;
  46.         }
  47.  

Код - C# [Выбрать]
  1.         [CommandMethod("REMOVEALLPROXY", CommandFlags.Modal)]
  2.         public static void RemoveAllProxy()
  3.         {
  4.             Database db = Acad.Database;                  // Текущая база
  5.             Handle firstHandle = db.BlockTableId.Handle;  // Первая метка объекта - метка таблицы блоков
  6.             Handle lastHandle = db.Handseed;              // Следующая после последней метки
  7.             int nObjects = db.ApproxNumObjects;           // Приблизительное количество объектов в базе
  8.  
  9.             string bufferLast = lastHandle.ToString();
  10.             string bufferFirst = firstHandle.ToString();
  11.             Int64 iLast = Int64.Parse(bufferLast, System.Globalization.NumberStyles.HexNumber);
  12.             Int64 iFirst = Int64.Parse(bufferFirst, System.Globalization.NumberStyles.HexNumber); ;
  13.  
  14.             Acad.Editor.WriteMessage(
  15.                 string.Format("\nПервая метка объекта: <{0}>, последняя метка объекта: <{1}>",
  16.                 bufferFirst,
  17.                 bufferLast));
  18.  
  19.             Int64 nProxyTotal = 0;
  20.             Int64 nProxyEntityTotal = 0;
  21.             ObjectIdCollection ids = new ObjectIdCollection();
  22.             // Массив меток заблокированных слоёв - их придётся временно разблокировать
  23.             ObjectIdCollection idsLockedLayers = new ObjectIdCollection();
  24.  
  25.             using (AcAp.Application.DocumentManager.MdiActiveDocument.LockDocument())
  26.             using (var tr = Acad.TransactionManager.StartTransaction())
  27.             {
  28.                 LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
  29.  
  30.                 for (Int64 i = iFirst; i < iLast && nObjects > 0; i++)
  31.                 {
  32.                     Handle h = new Handle(i);
  33.                     ObjectId id = ObjectId.Null;
  34.                     if (db.TryGetObjectId(h, out id))
  35.                     {
  36.                         try
  37.                         {
  38.                             DBObject dbObj = tr.GetObject(id, OpenMode.ForRead, true, true);
  39.                             if (dbObj != null && !dbObj.IsErased && dbObj.IsAProxy)
  40.                             {
  41.                                 nProxyTotal++;
  42.                                 ids.Add(id);
  43.                                 Entity entity = dbObj as Entity;
  44.                                 if (entity != null && entity.IsAProxy)
  45.                                 {
  46.                                     nProxyEntityTotal++;
  47.                                     ObjectId idLayer = entity.LayerId;
  48.                                     if (!idsLockedLayers.Contains(idLayer))
  49.                                     {
  50.                                         LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(idLayer, OpenMode.ForRead);
  51.                                         if (ltr.IsLocked)
  52.                                         {
  53.                                             ltr.IsLocked = false;
  54.                                             idsLockedLayers.Add(idLayer);
  55.                                         }
  56.                                     }
  57.                                 }
  58.                             }
  59.                             nObjects--;
  60.                         }
  61.                         catch { }
  62.                     }
  63.                 }
  64.  
  65.                 tr.Commit();
  66.  
  67.             }
  68.  
  69.             Acad.Editor.WriteMessage(string.Format("\nВсего найдено proxy-объектов: {0}. Из них proxy-примитивов: {1}.",
  70.                 nProxyTotal,
  71.                 nProxyEntityTotal));
  72.  
  73.             PromptKeywordOptions pko = new PromptKeywordOptions("\nОчистить список масштабов? ");
  74.             pko.Keywords.Add("Yes", "Д", "Да", true, true);
  75.             pko.Keywords.Add("No", "Н", "Нет", true, true);
  76.             pko.Keywords.Default = "Yes";
  77.             PromptResult pr = Acad.Editor.GetKeywords(pko);
  78.             if (pr.Status == PromptStatus.OK && pr.StringResult == "Yes")
  79.             {
  80.                 acedResetScaleList(false, true, db.UnmanagedObject);
  81.             }
  82.  
  83.             int nProxyDeleted = 0;
  84.             int nProxyEntityDeleted = 0;
  85.  
  86.             using (AcAp.Application.DocumentManager.MdiActiveDocument.LockDocument())
  87.             {
  88.                 for (int j = 0; j < ids.Count; j++)
  89.                 {
  90.  
  91.                     using (DBObject dbObj = ids[j].Open(OpenMode.ForWrite, false))
  92.                     {
  93.                         try
  94.                         {
  95.                             dbObj.Erase(true);
  96.                             if (dbObj.IsErased)
  97.                             {
  98.                                 nProxyDeleted++;
  99.                                 Entity entity = dbObj as Entity;
  100.                                 if (entity != null)
  101.                                 {
  102.                                     nProxyEntityDeleted++;
  103.                                 }
  104.                             }
  105.                         }
  106.                         catch
  107.                         {
  108.                             Entity entity = dbObj as Entity;
  109.                             DBObject tmpObj = null;
  110.                             if (entity != null)
  111.                             {
  112.                                 tmpObj = new Line();
  113.                             }
  114.                             else
  115.                             {
  116.                                 tmpObj = new DBDictionary();
  117.                             }
  118.                             dbObj.HandOverTo(tmpObj, false, false);
  119.                             nProxyDeleted++;
  120.                             tmpObj.Erase(true);
  121.                             tmpObj.Close();
  122.                             tmpObj.Dispose();
  123.                         }
  124.                     }
  125.                 }
  126.  
  127.                 using (var tr = Acad.TransactionManager.StartTransaction())
  128.                 {
  129.                     LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
  130.                     for (int i = 0; i < idsLockedLayers.Count; i++)
  131.                     {
  132.                         LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(idsLockedLayers[i], OpenMode.ForWrite);
  133.                         ltr.IsLocked = true;
  134.                     }
  135.  
  136.                     tr.Commit();
  137.                 }
  138.  
  139.                 idsLockedLayers.Dispose();
  140.  
  141.                 Acad.Editor.WriteMessage(
  142.                     string.Format("\nВсего удалено proxy-объектов: {0}. Из них proxy-примитивов: {1}.",
  143.                     nProxyDeleted,
  144.                     nProxyEntityDeleted));
  145.             }
  146.  
  147.             Autodesk.AutoCAD.Interop.AcadApplication app = (Autodesk.AutoCAD.Interop.AcadApplication)AcAp.Application.AcadApplication;
  148.             app.ActiveDocument.AuditInfo(true);
  149.             PurgeDatabase(db);
  150.         }
  151.  

Код - C# [Выбрать]
  1.         [CommandMethod("EXPLODEALLPROXY", CommandFlags.Modal)]
  2.         public static void ExplodeAllProxy()
  3.         {
  4.             Database db = Acad.Database;
  5.             ObjectIdCollection idsLockedLayers = new ObjectIdCollection();
  6.  
  7.             using (AcAp.Application.DocumentManager.MdiActiveDocument.LockDocument())
  8.             {
  9.                 using (var tr = Acad.TransactionManager.StartTransaction())
  10.                 {
  11.                     LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
  12.  
  13.                     foreach (var layerId in lt)
  14.                     {
  15.                         LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(layerId, OpenMode.ForWrite);
  16.                         if (ltr.IsLocked)
  17.                         {
  18.                             ltr.IsLocked = false;
  19.                             idsLockedLayers.Add(layerId);
  20.                         }
  21.                     }
  22.  
  23.                     tr.Commit();
  24.                 }
  25.  
  26.                 long exploded = 0;
  27.                 long proxy = 0;
  28.                 ObjectIdCollection ids = new ObjectIdCollection();
  29.                 using (var tr = Acad.TransactionManager.StartTransaction())
  30.                 {
  31.                     BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
  32.                     ids = new ObjectIdCollection(bt.OfType<ObjectId>().ToArray());
  33.  
  34.                     bt.Close();
  35.                 }
  36.  
  37.                 foreach (ObjectId currentId in ids)
  38.                 {
  39.                     if (!ExplodeProxyInBTR(currentId, ref proxy, ref exploded))
  40.                     {
  41.                         Acad.Editor.WriteMessage(
  42.                             string.Format("\nОшибка расчленения ACAD_PROXY_ENTITY!",
  43.                             currentId));
  44.                     }
  45.                 }
  46.  
  47.                 Acad.Editor.WriteMessage(string.Format("\nУдалено Proxy: {0} Новых объектов: {1}", proxy, exploded));
  48.  
  49.  
  50.                 using (var tr = Acad.TransactionManager.StartTransaction())
  51.                 {
  52.                     LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
  53.                     for (int i = 0; i < idsLockedLayers.Count; i++)
  54.                     {
  55.                         LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(idsLockedLayers[i], OpenMode.ForWrite);
  56.                         ltr.IsLocked = true;
  57.                     }
  58.  
  59.                     tr.Commit();
  60.                 }
  61.             }
  62.         }
  63.  
  64.         public static bool ExplodeProxyInBTR(ObjectId blkId, ref long proxy, ref long exploded)
  65.         {
  66.             if (blkId == ObjectId.Null)
  67.             {
  68.                 return false;
  69.             }
  70.  
  71.             DBObjectCollection aExplProxy = new DBObjectCollection();
  72.             ObjectIdCollection proxyEntities = new ObjectIdCollection();
  73.  
  74.             using (var tr = Acad.TransactionManager.StartTransaction())
  75.             {
  76.                 using (BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blkId, OpenMode.ForRead))
  77.                 {
  78.                     foreach (var item in btr)
  79.                     {
  80.                         ProxyEntity proxyEntity = tr.GetObject(item, OpenMode.ForWrite) as ProxyEntity;
  81.                         if (proxyEntity != null)
  82.                         {
  83.                             proxyEntities.Add(item);
  84.                             proxyEntity.Close();
  85.                             System.Diagnostics.Debug.WriteLine(item.ObjectClass.Name);
  86.                         }
  87.                     }
  88.                 }
  89.             }
  90.  
  91.             for (int i = 0; i < proxyEntities.Count; i++)
  92.             {
  93.                 ProxyEntity proxyEntity = proxyEntities[i].Open(OpenMode.ForWrite, false, false) as ProxyEntity;
  94.                 switch (proxyEntity.GraphicsMetafileType)
  95.                 {
  96.                     case GraphicsMetafileType.BoundingBox:
  97.                         {
  98.                             Extents3d ext = proxyEntity.GeometricExtents;
  99.                             if (ext != null)
  100.                             {
  101.                                 Point3dCollection arr = new Point3dCollection();
  102.                                 arr.Add(ext.MinPoint);
  103.                                 arr.Add(new Point3d(ext.MinPoint.X, ext.MaxPoint.Y, ext.MinPoint.Z));
  104.                                 arr.Add(new Point3d(ext.MaxPoint.X, ext.MaxPoint.Y, ext.MinPoint.Z));
  105.                                 arr.Add(new Point3d(ext.MaxPoint.X, ext.MinPoint.Y, ext.MinPoint.Z));
  106.  
  107.                                 Polyline3d pLine = new Polyline3d(Poly3dType.SimplePoly, arr, true);
  108.                                 pLine.LayerId = proxyEntity.LayerId;
  109.                                 pLine.LinetypeId = proxyEntity.LinetypeId;
  110.                                 pLine.Color = proxyEntity.Color;
  111.  
  112.                                 aExplProxy.Add(pLine);
  113.                             }
  114.  
  115.                             proxy++;
  116.                             proxyEntity.Erase(true);
  117.  
  118.                             Line line = new Line();
  119.                             proxyEntity.HandOverTo(line, false, false);
  120.                             line.Dispose();
  121.                         }
  122.                         break;
  123.                     case GraphicsMetafileType.FullGraphics:
  124.                         {
  125.                             proxyEntity.Explode(aExplProxy);
  126.                             if (aExplProxy.Count > 0)
  127.                             {
  128.                                 try
  129.                                 {
  130.                                     proxy++;
  131.                                     proxyEntity.Erase(true);
  132.  
  133.                                     Line line = new Line();
  134.                                     proxyEntity.HandOverTo(line, false, false);
  135.                                     line.Dispose();
  136.                                 }
  137.                                 catch{}
  138.                             }
  139.                             else
  140.                             {
  141.                                 //System.Diagnostics.Debug.WriteLine(proxyEntity.ObjectId.ToString());
  142.                             }
  143.                         }
  144.                         break;
  145.                     case GraphicsMetafileType.NoMetafile:
  146.                         break;
  147.                     default:
  148.                         break;
  149.                 }
  150.  
  151.                 proxyEntity.Dispose();
  152.             }
  153.             proxyEntities.Dispose();
  154.  
  155.             using (var tr = Acad.TransactionManager.StartTransaction())
  156.             {
  157.                 using (BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blkId, OpenMode.ForRead))
  158.                 {
  159.                     exploded += aExplProxy.Count;
  160.                     ObjectIdCollection idsRef = btr.GetBlockReferenceIds(true, true);
  161.  
  162.                     if (aExplProxy.Count > 0)
  163.                     {
  164.                         for (int i = 0; i < aExplProxy.Count; i++)
  165.                         {
  166.                             btr.UpgradeOpen();
  167.                             Entity entity = aExplProxy[i] as Entity;
  168.                             btr.AppendEntity(entity);
  169.                             tr.AddNewlyCreatedDBObject(entity, true);
  170.                             entity.Close();
  171.                         }
  172.                     }
  173.  
  174.                     for (int i = 0; i < idsRef.Count; i++)
  175.                     {
  176.                         BlockReference br = (BlockReference)tr.GetObject(idsRef[i], OpenMode.ForWrite);
  177.                         br.RecordGraphicsModified(true);
  178.                         br.Close();
  179.                     }
  180.  
  181.                     idsRef.Dispose();
  182.                     btr.Close();
  183.                 }
  184.             }
  185.  
  186.             aExplProxy.Dispose();
  187.  
  188.             return true;
  189.         }
  190.  
« Последнее редактирование: 21-11-2014, 12:19:40 от T72 »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #7 : 05-11-2014, 18:54:59 »
Несколько замечаний по коду. Строка 93 третьей части кода:
Код - C# [Выбрать]
  1. DBObject dbObj = ids[j].Open(OpenMode.ForWrite, false);
Ты открываешь это объект, но нигде не закрываешь его. Если dbObj.Erase(true) выполнилось успешно, то нужно вызвать dbObj.Close(). Если возникло исключение и мы пользуемся для удаления
Код - C# [Выбрать]
  1. dbObj.HandOverTo(tmpObj, false, false);
то нужно выполнить dbObj.Dispose() и tmpObj.Close()
Поэтому (я не тестировал код) лучше использовать конструкцию:
Код - C# [Выбрать]
  1. using (DBObject dbObj = ids[j].Open(OpenMode.ForWrite, false))
  2. {
  3. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #8 : 05-11-2014, 22:28:10 »
Еще одно замечание. Можно конечно использовать и условную компиляцию, т.е. в зависимости от версии и в зависимости от разрядности AutoCAD компилировать отдельные dll-файлы. А можно проверить и то и другое динамически и динамически вызвать нужную функцию. Тогда в отличие от arx-файла, который всегда нужно делать для каждой разрядности AutoCAD, можно сделать (в 95% случаев) dll-файл независящий от разрядности AutoCAD.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #9 : 06-11-2014, 01:21:18 »
T72, ну и спасибо тебе за то, что навёл меня на баг в моей версии. В версиях начиная с 2013 список масштабов в команде REMOVEALLPROXY не чистился. Причина банальная - перенос функции acedResetScaleList в accore.dll. Подправил свои исходники и выложил исправленные arx-файлы.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #10 : 06-11-2014, 07:52:59 »
Несколько замечаний по коду. Строка 93 третьей части кода:
Код - C#: [Выделить]

    DBObject dbObj = ids[j].Open(OpenMode.ForWrite, false);

Ты открываешь это объект, но нигде не закрываешь его. Если dbObj.Erase(true) выполнилось успешно, то нужно вызвать dbObj.Close(). Если возникло исключение и мы пользуемся для удаления
Спасибо. Close там был но потом я его при рефакторинге случайно удалил, а вот то, что Dispose нужен не знал, учту.
По поводу 95% в данном случае действительно можно сделать так.


Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #11 : 06-11-2014, 14:16:00 »
Добавил EXPLODEALLPROXY.
Пришлось немного поменять из-за несовместимости транзакций и HandOverTo.
Еще хочу обратить внимание на момент с расчленением прокси. Если explode возвращает 0 примитивов то выполнять proxy++ не стоит (по моему мнению), т.к. данный ACAD_PROXY_ENTITY исчезает из быстрого выбора, но в чертеже содержится и при следующем открытии будет снова доступен.
Спасибо.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #12 : 06-11-2014, 21:21:49 »
Если explode возвращает 0 примитивов то выполнять proxy++ не стоит (по моему мнению), т.к. данный ACAD_PROXY_ENTITY исчезает из быстрого выбора, но в чертеже содержится и при следующем открытии будет снова доступен.
Эту мысль я что-то не понял.  В моём коде вне зависимости от того что возвращает explode сам примитив потом удаляется и поэтому proxy++ справедливо.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #13 : 06-11-2014, 22:30:34 »
Эта конструкция в корне неправильна:
Код - C# [Выбрать]
  1. proxyEntity.Explode(aExplProxy);
  2. if (aExplProxy.Count > 0)
  3. {
  4.     proxy++;
  5.     proxyEntity.Erase(true);
  6.  
  7.     Line line = new Line();
  8.     proxyEntity.HandOverTo(line, false, false);
  9.     line.Close();
  10.     line.Dispose();
  11. }
1. Ты сначала удаляешь  proxyEntity, и не проверив удачно ли это получилось выполняешь повторное удаление при помощи HandOverTo
2. После HandOverTo ты делаешь line.Close() - это правильно, т.к. теперь line - это примитив в базе. А где же line.Erase() ?
3. Нужно делать не line.Dispose(), а proxyEntity.Dispose()
Мы тут уже на форуме это обсуждали, что если объект/примитив AutoCAD содержится в базе (т.е. его ObjectId отличен от 0), то метод Dispose() для него эквивалентен методу Close(), а если примитив не содержится в базе (т.е. его ObjectId равен 0), то метод Dispose эквивалентен освобождению памяти этого примитива.
Таким образом  line.Close(); и  line.Dispose();  -  эквивалентны, зато нет освобождения памяти proxyEntity
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #14 : 06-11-2014, 22:36:17 »
Цитата: T72 от 06-11-2014, 14:16:00

    Если explode возвращает 0 примитивов то выполнять proxy++ не стоит (по моему мнению), т.к. данный ACAD_PROXY_ENTITY исчезает из быстрого выбора, но в чертеже содержится и при следующем открытии будет снова доступен.

Эту мысль я что-то не понял.  В моём коде вне зависимости от того что возвращает explode сам примитив потом удаляется и поэтому proxy++ справедливо.
Данная функция для разбиения прокси на примитивы - значит если не получилось разбить то не стоит удалять, для этого есть другая функция.

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1111
  • Карма: 173
Re: REMOVEALLPROXY
« Ответ #15 : 06-11-2014, 22:43:51 »
ну и спасибо тебе за то, что навёл меня на баг в моей версии. В версиях начиная с 2013 список масштабов в команде REMOVEALLPROXY не чистился. Причина банальная - перенос функции acedResetScaleList в accore.dll. Подправил свои исходники и выложил исправленные arx-файлы.
Александр, а можно сделать "финт ушами"? То есть сделать по 2 arx-модуля: с чисткой масштабов и без оной? Честно говоря, я был безумно рад, что запроса по чистке масштабов не стало...
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #16 : 06-11-2014, 23:03:31 »
Данная функция для разбиения прокси на примитивы - значит если не получилось разбить то не стоит удалять, для этого есть другая функция.
Ага. С этой логикой я согласен.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #17 : 06-11-2014, 23:06:43 »
Александр, а можно сделать "финт ушами"?
Запросто. Тем более что теперь на форуме выложены даже два варианта кода: и ObjectARX, и .NET API. Так что можешь для себя сделать любую сборку. :)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #18 : 07-11-2014, 07:34:14 »
Эта конструкция в корне неправильна:
Код - C#: [Выделить]

    proxyEntity.Explode(aExplProxy);
    if (aExplProxy.Count > 0)
    {
        proxy++;
        proxyEntity.Erase(true);
     
        Line line = new Line();
        proxyEntity.HandOverTo(line, false, false);
        line.Close();
        line.Dispose();
    }

1. Ты сначала удаляешь  proxyEntity, и не проверив удачно ли это получилось выполняешь повторное удаление при помощи HandOverTo
2. После HandOverTo ты делаешь line.Close() - это правильно, т.к. теперь line - это примитив в базе. А где же line.Erase() ?
3. Нужно делать не line.Dispose(), а proxyEntity.Dispose()
Мы тут уже на форуме это обсуждали, что если объект/примитив AutoCAD содержится в базе (т.е. его ObjectId отличен от 0), то метод Dispose() для него эквивалентен методу Close(), а если примитив не содержится в базе (т.е. его ObjectId равен 0), то метод Dispose эквивалентен освобождению памяти этого примитива.
Таким образом  line.Close(); и  line.Dispose();  -  эквивалентны, зато нет освобождения памяти proxyEntity

Про эквивалентности и нюансы с памятью не знал, спасибо учту.
« Последнее редактирование: 07-11-2014, 09:36:32 от T72 »

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #19 : 12-11-2014, 20:01:39 »
Александр, а можно сделать "финт ушами"? То есть сделать по 2 arx-модуля: с чисткой масштабов и без оной? Честно говоря, я был безумно рад, что запроса по чистке масштабов не стало...
Два варианта не нужны. Просто на уровне API нужно отделять мух от котлет: отдельные команды по работе с proxy и отдельные по работе со списком аннотативных масштабов. Затем различные комбинации этих методов заворачиваются в виде команд CAD системы. Т.е. отдельные команды для взрыва и удаления proxy и отдельная для очистки списка аннотативных масштабов.  Я себе это оформил в виде методов со следующими сигнатурами:

Код - C# [Выбрать]
  1. public static Db.ObjectIdCollection GetFreeAnnotativeScaleIds(Db.Database db);
  2.  
  3. public static void ClearAnnotativeScalesList(Db.Database db);
  4.  
  5. public static void GetProxyIds(Db.Database db, out Db.ObjectIdCollection proxyObjectIds, out Db.ObjectIdCollection proxyEntityIds, out Db.ObjectIdCollection proxyLockedLayerIds, Boolean unlockLayers);
  6.  
  7. public static void ExplodeAllProxy(Db.Database db, out StringBuilder sb);
  8.  
  9. public static ExplodeStatus ExplodeProxyInBTR(Db.ObjectId btrId, out Int64 proxy, out Int64 exploded);
  10.  
  11. public static void RemoveAllProxy(Db.Database db, out Int64 proxyNotEntityErased, out Int64 proxyEntityErased);
  12.  

P.S.
По коду Александра Наумовича завтра выложу замечания\вопросы. Код T72 мне не понравился, поэтому написал свою альтернативу. Выложу его после тестирования.

P.S.2
Кстати, список аннотативных масштабов я чищу "родными" средствами .NET API, не прибегая к вызову неуправляемых функций. Делаю это за счёт обработки контекста коллекции "ACDB_ANNOTATIONSCALES".

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #20 : 12-11-2014, 21:53:44 »
Зачем вы выполняете двойную проверку?

Код - C++ [Выбрать]
  1. for (__int64 i = iFirst; i < iLast && nObjects > 0; i++) {

разве не достаточно проверять i < iLast?

вы полагаете, что может оказаться существенная разница между разностью (iLast - iFirst) и значением nObjects и тем самым решили добавить дополнительную проверку, дабы максимально сократить цикл?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #21 : 12-11-2014, 22:46:17 »
вы полагаете, что может оказаться существенная разница между разностью (iLast - iFirst) и значением nObjects и тем самым решили добавить дополнительную проверку, дабы максимально сократить цикл?
Да. Я сталкивался с такой ситуацией несколько раз. Если мне не изменяет память я тебе рассказывал, что в изначальном коде iFirst был равен 0, но оказалось, что бывают чертежи у которых первая "живая" метка имеет очень большой номер и программа может очень длительное время перебирать метки (минутами, если не часами). Аналогично и с iLast. Достаточно просто сохранить чертеж в DXF-формате, изменить значение системной переменной $HANDSEED на какое-то очень большое и потом снова пересохранить в dwg-формат. Аналогичная ситуация возможна при получении чертежа из программ, которые генерируют DXF-файлы, если они не корректно вычисляют $HANDSEED.
« Последнее редактирование: 13-11-2014, 09:38:16 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #22 : 13-11-2014, 09:30:56 »
Код T72 мне не понравился
Что так? В основном T72 переводил мой код с C++ на C# (по мере возможности) без изменений. Мой код тоже не блещет изяществом. Первая версия его писалась > 15 лет назад и с годами просто адаптировалась к новым версиям без существенной переработки.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #23 : 13-11-2014, 11:05:27 »
Что так? В основном T72 переводил мой код с C++ на C# (по мере возможности) без изменений.
Именно поэтому, ведь C# это всё же не C++.
Код - C++ [Выбрать]
  1. Мой код тоже не блещет изяществом.
Идеал вряд ли достижим. Тем не менее, к нему всегда стоит стремиться (имхо) :) Собственный вариант "переписи на C#" мне ближе в виду того, что он более похож на C#, чем на C++.
Цитата: Александр Ривилис
Если мне не изменяет память я тебе рассказывал...
Я такого не помню.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #24 : 13-11-2014, 12:24:43 »
На мой взгляд, конструкцию

Код - C++ [Выбрать]
  1. if (pProxy && (pProxy->graphicsMetafileType() == AcDbProxyEntity::kFullGraphics ||
  2.                            pProxy->graphicsMetafileType() == AcDbProxyEntity::kFullGraphics)) {
  3.                            
  4.   if (pProxy->graphicsMetafileType() == AcDbProxyEntity::kFullGraphics) {
  5.         ...
  6.   } else {
  7.         ...
  8.   }
  9. }

можно было бы заменить более компактным вариантом:

Код - C++ [Выбрать]
  1. if (pProxy && (pProxy->graphicsMetafileType() == AcDbProxyEntity::kFullGraphics) {                         
  2.         ...
  3. }
  4. else if (pProxy && (pProxy->graphicsMetafileType() == AcDbProxyEntity::kBoundingBox) {                     
  5.         ...
  6. }
« Последнее редактирование: 13-11-2014, 12:51:18 от Андрей Бушман »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #25 : 13-11-2014, 12:38:08 »
Я такого не помню.
Склероз у тебя. :-) Это было тогда, когда я поделился с тобой алгоритмом прохода по всем Handle в чертеже. Если помнишь, ты еще проверял какой из алгоритмов быстрее позволяет получить ObjectId по Handle. Были варианты: 1) Database.GetObjectId 2) P/Invoke для AcDbDatabase::getAcDbObjectId и 3) Database.TryGetObjectId - самый быстрый.
можно было бы заменить более компактным вариантом:
Он несколько компактнее по форме записи, но требует дополнительной проверки на неравенство нулю proxy в каждом операторе if. Так что тут дело вкуса. Тем более я не могу предугадать как этот код оптимизирует компилятор C++.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #26 : 13-11-2014, 12:48:00 »
требует дополнительной проверки на неравенство нулю proxy в каждом операторе if.
Но ведь вас не смутила двойная проверка на равенство AcDbProxyEntity::kFullGraphics. :)
Код - C++ [Выбрать]
  1. if(pProxy){
  2.         if (pProxy->graphicsMetafileType() == AcDbProxyEntity::kFullGraphics) {                        
  3.                         ...
  4.         }
  5.         else if (pProxy->graphicsMetafileType() == AcDbProxyEntity::kBoundingBox) {                    
  6.                         ...
  7.         }
  8. }
Цитировать
Это было тогда, когда я поделился с тобой алгоритмом прохода по всем Handle в чертеже. Если помнишь, ты еще проверял какой из алгоритмов быстрее позволяет получить ObjectId по Handle.
Я помню, что вы поделились, равно как и помню эти сравнения. Однако про дополнительную проверку за счёт уменьшения значения approxNumObjects() информации всё же не помню (возможно прослушал). Мой код, который вы упомянули, не использовал эту проверку (здесь, в коде строка 87).

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #27 : 13-11-2014, 13:01:28 »
Однако про дополнительную проверку за счёт уменьшения значения approxNumObjects() информации всё же не помню (возможно прослушал).
Ты невнимательно прочитал. Я напоминал тебе про старый разговор о стартовом номере, т.е. что Handle нужно начинать не с 0, а с db.BlockTableId.Handle. Про конечный номер мы не тогда не говорили, но с ним аналогично - дополнительная проверка не помешает.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: REMOVEALLPROXY
« Ответ #28 : 15-11-2014, 14:31:55 »
Ух начилось....
Где мой попкорн...
А давайте еще я свой вариант напишу - шутка не буду.
Александр, Андрей - я уверен что считать строки и байты - это немножко не ваш уровень.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #29 : 15-11-2014, 15:52:07 »
Александр, Андрей - я уверен что считать строки и байты - это немножко не ваш уровень.
Ты в данном случае про какие байты?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: REMOVEALLPROXY
« Ответ #30 : 15-11-2014, 18:51:52 »
На которые код стал "лучше".

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #31 : 15-11-2014, 21:02:40 »
На которые код стал "лучше".
А! Я думаю что ты прав и мы не будем обсуждать стили программирования, а будем обсуждать существо программы. Например, я уже много лет собираюсь, но так и не реализовал такую интересную штуку, которая касается ExplodeAllProxy. Метод Explode далеко не всегда возвращает то, что соотвествует тому, что видно на экране. Достаточно часто изображение сдвинуто, повернуто и т.д. Чтобы получить реальное изображение proxy-примитива нужно:
1) создать свой класс унаследованный от AcGiWorldDraw и создать экземпляр этого класса (назовем его ProxyWorldDraw *wd)
2) вызвать метод worldDraw() нашего proxy-примитива, передав ему в качестве параметра wd
3) на основе того, что будет передано в wd создаём примитивы и помещаем их в базу данных.
Это очень упрощенная схема, но частично она реализована в ARXDBG в команде ArxDbgTestWorldDraw. Боюсь, что аналог в AutoCAD .NET API невозможен.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #32 : 16-11-2014, 08:37:37 »
На мой взгляд, стоит забыть уже про высказывания о качестве кода, стили разные, да и обращать внимание на попытку сконцентрировать внимание на if-е, человеком который уже несколько раз просрочил завтра тоже не стоит (Андрей, если ты ратуешь за качество и производительность то должен знать, что switch намного быстрее if-а при перечислениях т.к позволит компилятору сделать хэш-меп и сразу выбрать значение). Нужно развивать идею с AcGiWorldDraw  или закрывать тему.

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1111
  • Карма: 173
Re: REMOVEALLPROXY
« Ответ #33 : 16-11-2014, 16:29:51 »
На мой взгляд, стоит забыть уже про высказывания о качестве кода, стили разные, да и обращать внимание на попытку сконцентрировать внимание на if-е, человеком который уже несколько раз просрочил завтра тоже не стоит (Андрей, если ты ратуешь за качество и производительность то должен знать, что switch намного быстрее if-а при перечислениях т.к позволит компилятору сделать хэш-меп и сразу выбрать значение). Нужно развивать идею с AcGiWorldDraw  или закрывать тему.
Чего? Я несколько раз перечитал текст, но так ничего внятного и не понял.
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #34 : 16-11-2014, 16:39:31 »
Чего? Я несколько раз перечитал текст, но так ничего внятного и не понял.
Я подозреваю, что это реакция на это:
Код T72 мне не понравился, поэтому написал свою альтернативу.
Надеюсь, что до виртуального рукоприкладства дело не дойдет. Иначе придётся принимать меры, а делать это мне очень не хочется.

Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: REMOVEALLPROXY
« Ответ #35 : 16-11-2014, 18:16:11 »
Цитата: Алексей Кулик от 16-11-2014, 16:29:51

    Чего? Я несколько раз перечитал текст, но так ничего внятного и не понял.

Я подозреваю, что это реакция на это:
Цитата: Андрей Бушман от 12-11-2014, 20:01:39

    Код T72 мне не понравился, поэтому написал свою альтернативу.

Надеюсь, что до виртуального рукоприкладства дело не дойдет. Иначе придётся принимать меры, а делать это мне очень не хочется.
Да ну бросьте, если бы мне хотелось с кем то спорить и что-то доказывать то я отреагировал бы сразу после того поста. А так просто уже от темы в сторону стали уходить, поэтому я и написал, что стоит дальше развивать идею с "правильным" расчленением объектов или закрывать ее.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #36 : 16-11-2014, 21:13:03 »
Надеюсь, что до виртуального рукоприкладства дело не дойдет. Иначе придётся принимать меры, а делать это мне очень не хочется.
Я игнорирую, так что не дойдёт. :)

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: REMOVEALLPROXY
« Ответ #37 : 16-11-2014, 21:52:22 »
T72, я хотел бы уточнить (так как не тестировал твой код). Твой код после всех исправлений на форуме сейчас работает нормально, т.е. можно считать, что это полностью работоспособный вариант или нужно его править?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #38 : 19-11-2014, 13:34:33 »
В ниже предоставленном коде я отделяю "мух от котлет": предоставляю API для работы с proxy (и не только), на основе которого можно создавать различные команды в CAD системе (пример одной такой команды так же приведён ниже). Итак, мой вариант выглядит следующим образом:

Код - C# [Выбрать]
  1. // © Andrey Bushman, 2014
  2. // LayerLockingSwitcher.cs
  3.  
  4. using System;
  5.  
  6. #if AUTOCAD
  7. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  8. using Ap = Autodesk.AutoCAD.ApplicationServices;
  9. using Db = Autodesk.AutoCAD.DatabaseServices;
  10. using Ed = Autodesk.AutoCAD.EditorInput;
  11. using Rt = Autodesk.AutoCAD.Runtime;
  12. using Gm = Autodesk.AutoCAD.Geometry;
  13. #endif
  14.  
  15. namespace Bushman.CAD {
  16.     public sealed class LayerLockingSwitcher : IDisposable {
  17.  
  18.         static readonly Rt.RXClass layerRXType = Rt.RXClass.GetClass(typeof(
  19.                 Db.LayerTableRecord));
  20.         Db.ObjectId layerId = Db.ObjectId.Null;
  21.         Boolean oldValue = false;
  22.  
  23.         public LayerLockingSwitcher(Db.ObjectId id) {
  24.             // Check argument
  25.             if (null == id)
  26.                 throw new ArgumentNullException("null == id");
  27.             if (id.IsNull)
  28.                 throw new ArgumentException("id.IsNull == true");
  29.             if (id.IsErased)
  30.                 throw new ArgumentException("id.IsErased == true");
  31.             if (null == id.Database)
  32.                 throw new ArgumentException("null == id.Database");
  33.             if (id.Database.IsDisposed)
  34.                 throw new ArgumentException("id.Database.IsDisposed == true");
  35.  
  36.             if (!id.ObjectClass.IsDerivedFrom(layerRXType))
  37.                 throw new ArgumentException(
  38.                     "id.ObjectClass.IsDerivedFrom(layerRXType) != true");
  39.  
  40.             // -----------------            
  41.             layerId = id;
  42.             Db.Database db = layerId.Database;
  43.  
  44.             using (Db.Transaction tr = db.TransactionManager
  45.                 .StartOpenCloseTransaction()) {
  46.                 Db.LayerTableRecord layer = tr.GetObject(layerId,
  47.                     Db.OpenMode.ForRead) as Db.LayerTableRecord;
  48.                 oldValue = layer.IsLocked;
  49.                 if (oldValue) {
  50.                     layer.UpgradeOpen();
  51.                     layer.IsLocked = false;
  52.                 }
  53.                 tr.Commit();
  54.             }
  55.         }
  56.         public void Dispose() {
  57.             if (layerId.IsErased || !oldValue) {
  58.                 return;
  59.             }
  60.             Db.Database db = layerId.Database;
  61.             using (Db.Transaction tr = db.TransactionManager
  62.                 .StartOpenCloseTransaction()) {
  63.                 Db.LayerTableRecord layer = tr.GetObject(layerId,
  64.                     Db.OpenMode.ForWrite) as Db.LayerTableRecord;
  65.                 layer.IsLocked = true;
  66.                 tr.Commit();
  67.             }
  68.         }
  69.     }
  70. }

Код - C# [Выбрать]
  1. // © Andrey Bushman, 2014
  2. // ExtensionMethods.cs
  3. // This code partially based on Alexander Rivilis's code (ARX version):
  4. // http://adn-cis.org/forum/index.php?topic=1060.msg4983#msg4983
  5.  
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9.  
  10. #if AUTOCAD
  11. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  12. using Ap = Autodesk.AutoCAD.ApplicationServices;
  13. using Db = Autodesk.AutoCAD.DatabaseServices;
  14. using Ed = Autodesk.AutoCAD.EditorInput;
  15. using Rt = Autodesk.AutoCAD.Runtime;
  16. using Gm = Autodesk.AutoCAD.Geometry;
  17. #endif
  18.  
  19. namespace Bushman.CAD {
  20.     public static class ExtensionMethods {
  21.  
  22.         static Rt.RXClass proxyObjectRXType = Rt.RXClass.GetClass(typeof(
  23.             Db.ProxyObject));
  24.  
  25.         static Rt.RXClass proxyEntityRXType = Rt.RXClass.GetClass(typeof(
  26.             Db.ProxyEntity));
  27.  
  28.         public static Db.ObjectId[] GetDBObjectIds(this Db.Database db) {
  29.             Db.ObjectId[] ids = GetDBObjectIds(db, (n => true));
  30.             return ids;
  31.         }
  32.  
  33.         public static Db.ObjectId[] GetDBObjectIds(this Db.Database db,
  34.             Func<Db.ObjectId, Boolean> filter) {
  35.  
  36.             // Check arguments
  37.             if (null == db)
  38.                 throw new ArgumentNullException("null == db");
  39.             if (null == filter)
  40.                 throw new ArgumentNullException("null == filter");
  41.             if (db.IsDisposed)
  42.                 throw new ArgumentException("true == db.IsDisposed");
  43.  
  44.             // -------------------
  45.             Int32 approxNum = db.ApproxNumObjects;
  46.             List<Db.ObjectId> ids = new List<Db.ObjectId>();
  47.  
  48.             for (Int64 i = db.BlockTableId.Handle.Value; i < db.Handseed.Value
  49.                 && approxNum > 0; ++i) {
  50.  
  51.                 Db.Handle h = new Db.Handle(i);
  52.                 Db.ObjectId id = Db.ObjectId.Null;
  53.  
  54.                 Boolean parseResult = db.TryGetObjectId(h, out id);
  55.  
  56.                 if (parseResult) {
  57.                     --approxNum;
  58.                     if (filter(id)) {
  59.                         ids.Add(id);
  60.                     }
  61.                 }
  62.             }
  63.             return ids.ToArray();
  64.         }
  65.  
  66.         public static Db.ObjectId[] GetEntityIds(this Db.Database db) {
  67.             Db.ObjectId[] ids = GetEntityIds(db, (n => true));
  68.             return ids;
  69.         }
  70.  
  71.         public static Db.ObjectId[] GetEntityIds(this Db.Database db,
  72.             Func<Db.ObjectId, Boolean> filter) {
  73.  
  74.             // Check arguments
  75.             if (null == db)
  76.                 throw new ArgumentNullException("null == db");
  77.             if (null == filter)
  78.                 throw new ArgumentNullException("null == filter");
  79.             if (db.IsDisposed)
  80.                 throw new ArgumentException("true == db.IsDisposed");
  81.  
  82.             // -------------------
  83.             List<Db.ObjectId> ids = new List<Db.ObjectId>();
  84.             // Entity items can be located in the BlockTableRecord instances
  85.             // only.
  86.             using (Db.Transaction tr = db.TransactionManager.StartTransaction()
  87.                 ) {
  88.                 Db.BlockTable bt = tr.GetObject(db.BlockTableId,
  89.                     Db.OpenMode.ForRead) as Db.BlockTable;
  90.  
  91.                 // Skip erased BlockTableRecord instances.
  92.                 IEnumerable<Db.ObjectId> btrIds = bt.Cast<Db.ObjectId>()
  93.                     .Where(n => !n.IsErased);
  94.  
  95.                 foreach (Db.ObjectId btrId in btrIds) {
  96.                     Db.BlockTableRecord btr = tr.GetObject(btrId,
  97.                         Db.OpenMode.ForRead) as Db.BlockTableRecord;
  98.                     foreach (Db.ObjectId id in btr) {
  99.                         if (filter(id)) {
  100.                             ids.Add(id);
  101.                         }
  102.                     }
  103.                 }
  104.                 tr.Commit();
  105.             }
  106.             return ids.ToArray();
  107.         }
  108.  
  109.         public static Db.ObjectId[] ExplodeProxyEntity(
  110.             Db.ObjectId proxyEntityId) {
  111.  
  112.             // Check arguments
  113.             if (null == proxyEntityId)
  114.                 throw new ArgumentException("null == proxyEntityId");
  115.             if (proxyEntityId.IsErased)
  116.                 throw new ArgumentException("true == proxyEntityId.IsErased");
  117.             if (null == proxyEntityId.Database)
  118.                 throw new ArgumentException("null == proxyEntityId.Database");
  119.             if (proxyEntityId.Database.IsDisposed)
  120.                 throw new ArgumentException(
  121.                     "true == proxyEntityId.Database.IsDisposed");
  122.             if (!proxyEntityId.ObjectClass.IsDerivedFrom(proxyEntityRXType))
  123.                 throw new ArgumentException("false == proxyEntityId." +
  124.                     "ObjectClass.IsDerivedFrom(proxyEntityRXType)");
  125.  
  126.             // -------------------
  127.             using (Db.DBObjectCollection newDBObjects =
  128.                 new Db.DBObjectCollection()) {
  129.                 Db.Database db = proxyEntityId.Database;
  130.  
  131.                 using (Db.Transaction tr = db.TransactionManager
  132.                     .StartOpenCloseTransaction()) {
  133.                     Db.ProxyEntity proxyEntity = tr.GetObject(
  134.                         proxyEntityId, Db.OpenMode.ForRead)
  135.                         as Db.ProxyEntity;
  136.  
  137.                     using (new LayerLockingSwitcher(proxyEntity.LayerId)) {
  138.  
  139.                         proxyEntity.UpgradeOpen();
  140.  
  141.                         if (proxyEntity.GraphicsMetafileType ==
  142.                             Db.GraphicsMetafileType.FullGraphics) {
  143.  
  144.                             proxyEntity.Explode(newDBObjects);
  145.                         }
  146.                         else if (proxyEntity.GraphicsMetafileType ==
  147.                             Db.GraphicsMetafileType.BoundingBox) {
  148.  
  149.                             Db.Extents3d ext = proxyEntity.GeometricExtents;
  150.                             Gm.Point3dCollection arr =
  151.                                 new Gm.Point3dCollection();
  152.  
  153.                             arr.Add(ext.MinPoint);
  154.                             arr.Add(new Gm.Point3d(ext.MinPoint.X,
  155.                                 ext.MaxPoint.Y, ext.MinPoint.Z));
  156.                             arr.Add(new Gm.Point3d(ext.MaxPoint.X,
  157.                                 ext.MaxPoint.Y, ext.MinPoint.Z));
  158.                             arr.Add(new Gm.Point3d(ext.MaxPoint.X,
  159.                                 ext.MinPoint.Y, ext.MinPoint.Z));
  160.  
  161.                             Db.Polyline3d pline = new Db.Polyline3d(
  162.                                 Db.Poly3dType.SimplePoly, arr, true);
  163.  
  164.                             pline.LayerId = proxyEntity.LayerId;
  165.                             pline.LinetypeId = proxyEntity.LinetypeId;
  166.                             pline.Color = proxyEntity.Color;
  167.  
  168.                             newDBObjects.Add(pline);
  169.                         }
  170.  
  171.                         try {
  172.                             proxyEntity.Erase();
  173.                         }
  174.                         catch {
  175.                             if (!proxyEntity.IsErased) {
  176.                                 using (Db.Line rep = new Db.Line()) {
  177.                                     proxyEntity.HandOverTo(rep, false, false);
  178.                                     rep.Erase();
  179.                                     rep.Close();
  180.                                     proxyEntity.Dispose();
  181.                                 }
  182.                             }
  183.                         }
  184.  
  185.                         Db.BlockTableRecord btr = tr.GetObject(
  186.                             proxyEntity.BlockId, Db.OpenMode.ForWrite, false)
  187.                             as Db.BlockTableRecord;
  188.  
  189.                         if (newDBObjects.Count > 0) {
  190.                             foreach (Db.DBObject item in newDBObjects) {
  191.                                 if (item is Db.Entity) {
  192.                                     Db.Entity _ent = item as Db.Entity;
  193.                                     btr.AppendEntity(_ent);
  194.                                     tr.AddNewlyCreatedDBObject(item, true);
  195.                                 }
  196.                             }
  197.                         }
  198.                         Db.ObjectIdCollection idsRef =
  199.                             btr.GetBlockReferenceIds(true, true);
  200.                         foreach (Db.ObjectId id in idsRef) {
  201.                             Db.BlockReference br = tr.GetObject(id,
  202.                                 Db.OpenMode.ForWrite, false)
  203.                                 as Db.BlockReference;
  204.                             br.RecordGraphicsModified(true);
  205.                         }
  206.                         tr.Commit();
  207.                     }
  208.                 }
  209.                 return newDBObjects.Cast<Db.DBObject>().Select(n => n.ObjectId)
  210.                     .ToArray();
  211.             }
  212.         }
  213.  
  214.         public static void RemoveDBObject(Db.ObjectId id) {
  215.  
  216.             // Check arguments
  217.             if (null == id)
  218.                 throw new ArgumentException("null == id");
  219.             if (id.IsErased)
  220.                 throw new ArgumentException("true == id.IsErased");
  221.             if (null == id.Database)
  222.                 throw new ArgumentException("null == id.Database");
  223.             if (id.Database.IsDisposed)
  224.                 throw new ArgumentException("true == id.Database.IsDisposed");
  225.  
  226.             // -------------------
  227.             Db.Database db = id.Database;
  228.  
  229.             using (Db.Transaction tr = db.TransactionManager
  230.                 .StartOpenCloseTransaction()) {
  231.                 Db.DBObject obj = tr.GetObject(id, Db.OpenMode.ForRead);
  232.                 if (obj is Db.Entity) {
  233.                     Db.Entity ent = obj as Db.Entity;                    
  234.                     using (new LayerLockingSwitcher(ent.LayerId)) {
  235.                         ent.UpgradeOpen();
  236.                         EraseDBObject(obj);
  237.                     }
  238.                 }
  239.                 else {
  240.                     obj.UpgradeOpen();
  241.                     EraseDBObject(obj);
  242.                 }
  243.                 tr.Commit();
  244.             }
  245.         }
  246.  
  247.         private static void EraseDBObject(Db.DBObject obj) {
  248.  
  249.             // Check argument
  250.             if (null == obj)
  251.                 throw new ArgumentNullException("null == obj");
  252.             if (obj.IsErased)
  253.                 throw new ArgumentException("true == obj.IsErased");
  254.             if (obj.IsDisposed)
  255.                 throw new ArgumentException("true == obj.IsDisposed");
  256.             if (null == obj.Database)
  257.                 throw new ArgumentException("null == obj.Database");
  258.             if (obj.Database.IsDisposed)
  259.                 throw new ArgumentException("true == obj.Database.IsDisposed");
  260.  
  261.             // ----------------
  262.             try {
  263.                 obj.Erase(true);
  264.             }
  265.             catch {
  266.                 if (!obj.IsErased) {
  267.                     using (Db.DBObject rep = obj is Db.Entity ?
  268.                         (Db.DBObject)new Db.Line() :
  269.                         new Db.DBDictionary()) {
  270.                         obj.HandOverTo(rep, false, false);
  271.                         rep.Erase(true);
  272.                         rep.Close();
  273.                         obj.Dispose();
  274.                     }
  275.                 }
  276.             }
  277.         }
  278.  
  279.         public static Db.ObjectId[] GetFreeAnnotativeScaleIds(
  280.             this Db.Database db) {
  281.  
  282.             // Check argument
  283.             if (null == db)
  284.                 throw new ArgumentNullException("null == db");
  285.             if (db.IsDisposed)
  286.                 throw new ArgumentException("true == db.IsDisposed");
  287.  
  288.             // ----------------
  289.             using (Db.ObjectIdCollection ids = new Db.ObjectIdCollection()) {
  290.                 Db.ObjectContextManager ocMng = db.ObjectContextManager;
  291.                 if (null != ocMng) {
  292.                     Db.ObjectContextCollection ocItems =
  293.                         ocMng.GetContextCollection("ACDB_ANNOTATIONSCALES");
  294.                     if (null != ocItems) {
  295.                         foreach (Db.ObjectContext item in ocItems) {
  296.                             if (item is Db.AnnotationScale)
  297.                                 ids.Add(new Db.ObjectId(item.UniqueIdentifier));
  298.                         }
  299.                         db.Purge(ids);
  300.                     }
  301.                 }
  302.                 return ids.Cast<Db.ObjectId>().ToArray();
  303.             }
  304.         }
  305.  
  306.         public static void RemoveFreeAnnotativeScales(this Db.Database db) {
  307.  
  308.             // Check argument
  309.             if (null == db)
  310.                 throw new ArgumentNullException("null == db");
  311.             if (db.IsDisposed)
  312.                 throw new ArgumentException("true == db.IsDisposed");
  313.  
  314.             // -----------------
  315.             Db.ObjectId[] ids = db.GetFreeAnnotativeScaleIds();
  316.  
  317.             using (Db.Transaction tr = db.TransactionManager.StartTransaction()
  318.                 ) {
  319.                 foreach (Db.ObjectId id in ids) {
  320.                     try {
  321.                         Db.DBObject obj = tr.GetObject(id, Db.OpenMode
  322.                             .ForWrite, false);
  323.                         obj.Erase();
  324.                     }
  325.                     catch { }
  326.                 }
  327.                 tr.Commit();
  328.             }
  329.         }
  330.     }
  331. }

Ну и теперь, собственно, пример использования:
Код - C# [Выбрать]
  1. // © Andrey Bushman, 2014
  2. // Commands.cs
  3.  
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7.  
  8. #if AUTOCAD
  9. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  10. using Ap = Autodesk.AutoCAD.ApplicationServices;
  11. using Db = Autodesk.AutoCAD.DatabaseServices;
  12. using Ed = Autodesk.AutoCAD.EditorInput;
  13. using Rt = Autodesk.AutoCAD.Runtime;
  14. using Gm = Autodesk.AutoCAD.Geometry;
  15. #endif
  16.  
  17. [assembly: Rt.ExtensionApplication(typeof(Bushman.CAD.ExtensionApplication))]
  18. [assembly: Rt.CommandClass(typeof(Bushman.CAD.Commands))]
  19.  
  20. namespace Bushman.CAD {
  21.     public sealed class Commands {
  22.  
  23.         [Rt.CommandMethod("Test", Rt.CommandFlags.Modal)]
  24.         public void Command_Test() {
  25.  
  26.             Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  27.             Ed.Editor ed = doc.Editor;
  28.             Db.Database db = doc.Database;
  29.  
  30.             // Get ids for unerased objects only
  31.             Db.ObjectId[] ids = db.GetDBObjectIds(n => !n.IsErased);
  32.             ed.WriteMessage("DBObjects count before: {0}.\n", ids.Length
  33.                 .ToString());
  34.  
  35.             Rt.RXClass proxyObjectRXType = Rt.RXClass.GetClass(typeof(
  36.                 Db.ProxyObject));
  37.             Rt.RXClass proxyEntityRXType = Rt.RXClass.GetClass(typeof(
  38.                 Db.ProxyEntity));
  39.  
  40.             Func<Db.ObjectId, Boolean> proxyEntityFilter = n => !n.IsErased &&
  41.                 n.ObjectClass.IsDerivedFrom(proxyEntityRXType);
  42.  
  43.             Func<Db.ObjectId, Boolean> proxyObjectFilter = n => !n.IsErased &&
  44.                 n.ObjectClass.IsDerivedFrom(proxyObjectRXType);
  45.  
  46.             Db.ObjectId[] proxyEntityIds = db.GetEntityIds(proxyEntityFilter);
  47.             ed.WriteMessage("including ProxyEntity items count: {0};\n",
  48.                 proxyEntityIds.Length.ToString());
  49.  
  50.             Db.ObjectId[] proxyObjectIds = db.GetDBObjectIds(proxyObjectFilter);
  51.             ed.WriteMessage("including ProxyObject items count: {0};\n\n",
  52.                 proxyObjectIds.Length.ToString());
  53.  
  54.             Int64 newEntityCount = 0;
  55.  
  56.             foreach (Db.ObjectId id in proxyEntityIds) {
  57.                 Db.ObjectId[] newEntityIds = ExtensionMethods
  58.                     .ExplodeProxyEntity(id);
  59.                 newEntityCount += newEntityIds.Length;
  60.             }
  61.  
  62.             foreach (Db.ObjectId id in proxyObjectIds) {
  63.                 ExtensionMethods.RemoveDBObject(id);
  64.             }
  65.  
  66.             ed.WriteMessage("All ProxyEntity items exploded.\nNew DBObjects " +
  67.                 "count: {0}.\n", newEntityCount.ToString());
  68.             ed.WriteMessage("All ProxyObject items removed.\n\n");
  69.  
  70.             Db.ObjectId[] freeAnnotScaleIds = db.GetFreeAnnotativeScaleIds();
  71.  
  72.             ed.WriteMessage("Unused annotation scales count: {0}.\n",
  73.                 freeAnnotScaleIds.Length.ToString());
  74.  
  75.             db.RemoveFreeAnnotativeScales();
  76.             ed.WriteMessage("Unused annotation scales removed.\n\n");
  77.  
  78.             ids = db.GetDBObjectIds(n => !n.IsErased);
  79.             ed.WriteMessage("DBObjects count after: {0}.\n\n" +
  80.                 "Run the _AUDIT command with the _Y option, please.\n",
  81.                 ids.Length.ToString());
  82.         }
  83.     }
  84. }

В результате работы команы в консоль CAD системы выводится отчёт о проделанной работе. Для сравнения (дабы можно было сравнить количество обработанных объектов), ниже для того же DWG файла приведён лог, выводимый в консоль командами ExplodeAllProxy и RemoveAllProxy, написанными Р.А.Н.:

Цитата: CAD console output (R.A.N.)
Command: explodeallproxy
Удалено Proxy: 230 Новых объектов: 3834

Command: removeallproxy
Первая метка объекта: <1>, последняя метка объекта: <34A9>
Всего найдено proxy-объектов: 4609. Из них proxy-примитивов: 0.
Всего удалено proxy-объектов: 4609. Из них proxy-примитивов: 0.
Для проверки ошибок выполните команду _AUDIT

Цитата: CAD console output (Bushman)
Command: test
DBObjects count before: 5565.
including ProxyEntity items count: 230;
including ProxyObject items count: 4609;

All ProxyEntity items exploded.
New DBObjects count: 3834.
All ProxyObject items removed.

Unused annotation scales count: 24.
Unused annotation scales removed.

DBObjects count after: 4869.

Run the _AUDIT command with the _Y option, please.

Конструктивная критика и замечания приветствуются.

P.S. Код тестировался в AutoCAD 2009 Enu SP3 x64.
« Последнее редактирование: 19-11-2014, 15:29:17 от Андрей Бушман »

Оффлайн German

  • ADN Club
  • **
  • Сообщений: 84
  • Карма: 13
Re: REMOVEALLPROXY
« Ответ #39 : 19-11-2014, 14:11:19 »
замечания приветствуются
Заметил по отчету, что DBObjects count меняется не "арифметически":
(5565 - 230 + 3834 - 4609 - 24) != 4869
Оставшиеся ведь и не удаленные, и валидные. Это нормально?

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #40 : 19-11-2014, 14:59:16 »
Это нормально?
Нужно будет поразбираться, почему не бьётся сумма.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: REMOVEALLPROXY
« Ответ #41 : 20-11-2014, 12:42:19 »
За счёт добавления проверки ProxyFlags удалось избавиться от блоков try\catch, что в свою очередь позволило существенно увеличить скорость работы. В виду этого появился смысл переписать класс LayoutLockingSwitcher и внести изменения в ряд методов класса ExtensionMethods, что и было сделано. В статический класс ExtensionMethods добавлен метод GetLockedLayerIds. Изменены сигнатуры методов ExplodeProxyEntity, EraseDBObject и RemoveDBObject - добавлена возможность вести подсчёт количества вызовов HandOverTo. Подумав, добавил в фильтрах, обозначенных в коде команды, проверку на не уничтоженность владельцев в иерархии владения объектами (свойство IsEffectivelyErased).

В виду переработки LayoutLockingSwitcher, внесены соответствующие изменения в код тестовой команды. Дополнительно в коде команды добавлена некоторая информация, отправляемая в консоль.
Код - C# [Выбрать]
  1. // © Andrey Bushman, 2014
  2. // LayerLockingSwitcher.cs
  3.  
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7.  
  8. #if AUTOCAD
  9. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  10. using Ap = Autodesk.AutoCAD.ApplicationServices;
  11. using Db = Autodesk.AutoCAD.DatabaseServices;
  12. using Ed = Autodesk.AutoCAD.EditorInput;
  13. using Rt = Autodesk.AutoCAD.Runtime;
  14. using Gm = Autodesk.AutoCAD.Geometry;
  15. #endif
  16.  
  17. namespace Bushman.CAD {
  18.     public sealed class LayerLockingSwitcher : IDisposable {
  19.  
  20.         static readonly Rt.RXClass layerRXType = Rt.RXClass.GetClass(typeof(
  21.                 Db.LayerTableRecord));
  22.         List<Db.ObjectId> layerIds = null;
  23.  
  24.         public LayerLockingSwitcher(Db.ObjectId[] layer_ids) {
  25.  
  26.             // Check argument
  27.             if (null == layer_ids)
  28.                 throw new ArgumentNullException("null == ids");
  29.             if (0 == layer_ids.Length)
  30.                 return;
  31.             if (layer_ids.Select(n => n.Database).Distinct().Count() > 1)
  32.                 throw new ArgumentException("All items must to have the " +
  33.                     "same 'Database' property value.");
  34.  
  35.             // -----------------            
  36.             layerIds = new List<Db.ObjectId>();
  37.             Db.Database db = layer_ids[0].Database;
  38.  
  39.             using (Db.Transaction tr = db.TransactionManager
  40.                 .StartOpenCloseTransaction()) {
  41.                 foreach (Db.ObjectId id in layer_ids) {
  42.                     if (!id.IsNull &&
  43.                         !id.IsErased &&
  44.                         !id.IsEffectivelyErased &&
  45.                         null != id.Database &&
  46.                         !id.Database.IsDisposed &&
  47.                         id.ObjectClass.IsDerivedFrom(layerRXType)) {
  48.  
  49.                         Db.LayerTableRecord layer = tr.GetObject(id,
  50.                     Db.OpenMode.ForRead) as Db.LayerTableRecord;
  51.                         if (layer.IsLocked) {
  52.                             layer.UpgradeOpen();
  53.                             layer.IsLocked = false;
  54.                             layerIds.Add(id);
  55.                         }
  56.                     }
  57.                 }
  58.                 tr.Commit();
  59.             }
  60.         }
  61.         public void Dispose() {
  62.             if (layerIds.Count == 0)
  63.                 return;
  64.  
  65.             Db.Database db = layerIds[0].Database;
  66.             using (Db.Transaction tr = db.TransactionManager
  67.                 .StartOpenCloseTransaction()) {
  68.                 foreach (Db.ObjectId id in layerIds) {
  69.                     Db.LayerTableRecord layer = tr.GetObject(id,
  70.                         Db.OpenMode.ForWrite) as Db.LayerTableRecord;
  71.                     layer.IsLocked = true;
  72.                 }
  73.                 tr.Commit();
  74.             }
  75.         }
  76.     }
  77. }

Код - C# [Выбрать]
  1. // © Andrey Bushman, 2014
  2. // ExtensionMethods.cs
  3. // This code partially based on Alexander Rivilis's code (ARX version):
  4. // http://adn-cis.org/forum/index.php?topic=1060.msg4983#msg4983
  5.  
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9.  
  10. #if AUTOCAD
  11. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  12. using Ap = Autodesk.AutoCAD.ApplicationServices;
  13. using Db = Autodesk.AutoCAD.DatabaseServices;
  14. using Ed = Autodesk.AutoCAD.EditorInput;
  15. using Rt = Autodesk.AutoCAD.Runtime;
  16. using Gm = Autodesk.AutoCAD.Geometry;
  17. #endif
  18.  
  19. namespace Bushman.CAD {
  20.     public static class ExtensionMethods {
  21.  
  22.         static Rt.RXClass proxyObjectRXType = Rt.RXClass.GetClass(typeof(
  23.             Db.ProxyObject));
  24.  
  25.         static Rt.RXClass proxyEntityRXType = Rt.RXClass.GetClass(typeof(
  26.             Db.ProxyEntity));
  27.  
  28.         public static Db.ObjectId[] GetDBObjectIds(this Db.Database db) {
  29.             Db.ObjectId[] ids = GetDBObjectIds(db, (n => true));
  30.             return ids;
  31.         }
  32.  
  33.         public static Db.ObjectId[] GetDBObjectIds(this Db.Database db,
  34.             Func<Db.ObjectId, Boolean> filter) {
  35.  
  36.             // Check arguments
  37.             if (null == db)
  38.                 throw new ArgumentNullException("null == db");
  39.             if (null == filter)
  40.                 throw new ArgumentNullException("null == filter");
  41.             if (db.IsDisposed)
  42.                 throw new ArgumentException("true == db.IsDisposed");
  43.  
  44.             // -------------------
  45.             Int32 approxNum = db.ApproxNumObjects;
  46.             List<Db.ObjectId> ids = new List<Db.ObjectId>();
  47.  
  48.             for (Int64 i = db.BlockTableId.Handle.Value; i < db.Handseed.Value
  49.                 && approxNum > 0; ++i) {
  50.  
  51.                 Db.Handle h = new Db.Handle(i);
  52.                 Db.ObjectId id = Db.ObjectId.Null;
  53.  
  54.                 Boolean parseResult = db.TryGetObjectId(h, out id);
  55.  
  56.                 if (parseResult) {
  57.                     --approxNum;
  58.                     if (filter(id)) {
  59.                         ids.Add(id);
  60.                     }
  61.                 }
  62.             }
  63.             return ids.ToArray();
  64.         }
  65.  
  66.         public static Db.ObjectId[] GetEntityIds(this Db.Database db) {
  67.             Db.ObjectId[] ids = GetEntityIds(db, (n => true));
  68.             return ids;
  69.         }
  70.  
  71.         public static Db.ObjectId[] GetEntityIds(this Db.Database db,
  72.             Func<Db.ObjectId, Boolean> filter) {
  73.  
  74.             // Check arguments
  75.             if (null == db)
  76.                 throw new ArgumentNullException("null == db");
  77.             if (null == filter)
  78.                 throw new ArgumentNullException("null == filter");
  79.             if (db.IsDisposed)
  80.                 throw new ArgumentException("true == db.IsDisposed");
  81.  
  82.             // -------------------
  83.             List<Db.ObjectId> ids = new List<Db.ObjectId>();
  84.             // Entity items can be located in the BlockTableRecord instances
  85.             // only.
  86.             using (Db.Transaction tr = db.TransactionManager.StartTransaction()
  87.                 ) {
  88.                 Db.BlockTable bt = tr.GetObject(db.BlockTableId,
  89.                     Db.OpenMode.ForRead) as Db.BlockTable;
  90.  
  91.                 // Skip erased BlockTableRecord instances.
  92.                 IEnumerable<Db.ObjectId> btrIds = bt.Cast<Db.ObjectId>()
  93.                     .Where(n => !n.IsErased);
  94.  
  95.                 foreach (Db.ObjectId btrId in btrIds) {
  96.                     Db.BlockTableRecord btr = tr.GetObject(btrId,
  97.                         Db.OpenMode.ForRead) as Db.BlockTableRecord;
  98.                     foreach (Db.ObjectId id in btr) {
  99.                         if (filter(id)) {
  100.                             ids.Add(id);
  101.                         }
  102.                     }
  103.                 }
  104.                 tr.Commit();
  105.             }
  106.             return ids.ToArray();
  107.         }
  108.  
  109.         public static Db.ObjectId[] ExplodeProxyEntity(
  110.             Db.ObjectId proxyEntityId, out Boolean handOverTo_called) {
  111.  
  112.             // Check arguments
  113.             if (null == proxyEntityId)
  114.                 throw new ArgumentException("null == proxyEntityId");
  115.             if (proxyEntityId.IsErased)
  116.                 throw new ArgumentException("true == proxyEntityId.IsErased");
  117.             if (null == proxyEntityId.Database)
  118.                 throw new ArgumentException("null == proxyEntityId.Database");
  119.             if (proxyEntityId.Database.IsDisposed)
  120.                 throw new ArgumentException(
  121.                     "true == proxyEntityId.Database.IsDisposed");
  122.             if (!proxyEntityId.ObjectClass.IsDerivedFrom(proxyEntityRXType))
  123.                 throw new ArgumentException("false == proxyEntityId." +
  124.                     "ObjectClass.IsDerivedFrom(proxyEntityRXType)");
  125.  
  126.             // -------------------
  127.             using (Db.DBObjectCollection newDBObjects =
  128.                 new Db.DBObjectCollection()) {
  129.                 Db.Database db = proxyEntityId.Database;
  130.  
  131.                 using (Db.Transaction tr = db.TransactionManager
  132.                     .StartOpenCloseTransaction()) {
  133.                     Db.ProxyEntity proxyEntity = tr.GetObject(
  134.                         proxyEntityId, Db.OpenMode.ForWrite)
  135.                         as Db.ProxyEntity;
  136.  
  137.                     if (proxyEntity.GraphicsMetafileType ==
  138.                         Db.GraphicsMetafileType.FullGraphics) {
  139.  
  140.                         proxyEntity.Explode(newDBObjects);
  141.                     }
  142.                     else if (proxyEntity.GraphicsMetafileType ==
  143.                         Db.GraphicsMetafileType.BoundingBox) {
  144.  
  145.                         Db.Extents3d ext = proxyEntity.GeometricExtents;
  146.                         Gm.Point3dCollection arr =
  147.                             new Gm.Point3dCollection();
  148.  
  149.                         arr.Add(ext.MinPoint);
  150.                         arr.Add(new Gm.Point3d(ext.MinPoint.X,
  151.                             ext.MaxPoint.Y, ext.MinPoint.Z));
  152.                         arr.Add(new Gm.Point3d(ext.MaxPoint.X,
  153.                             ext.MaxPoint.Y, ext.MinPoint.Z));
  154.                         arr.Add(new Gm.Point3d(ext.MaxPoint.X,
  155.                             ext.MinPoint.Y, ext.MinPoint.Z));
  156.  
  157.                         Db.Polyline3d pline = new Db.Polyline3d(
  158.                             Db.Poly3dType.SimplePoly, arr, true);
  159.  
  160.                         pline.LayerId = proxyEntity.LayerId;
  161.                         pline.LinetypeId = proxyEntity.LinetypeId;
  162.                         pline.Color = proxyEntity.Color;
  163.  
  164.                         newDBObjects.Add(pline);
  165.                     }
  166.  
  167.                     // ----------------
  168.                     Boolean canBeErased = (proxyEntity.ProxyFlags & 0x1) != 0;
  169.  
  170.                     if (canBeErased) {
  171.                         proxyEntity.Erase();
  172.                         handOverTo_called = false;
  173.                     }
  174.                     else {
  175.                         using (Db.Line tmp = new Db.Line()) {
  176.                             proxyEntity.HandOverTo(tmp, false, false);
  177.                             tmp.Erase();
  178.                             proxyEntity.Dispose();
  179.                             handOverTo_called = true;
  180.                         }
  181.                     }
  182.  
  183.                     Db.BlockTableRecord btr = tr.GetObject(
  184.                         proxyEntity.BlockId, Db.OpenMode.ForWrite, false)
  185.                         as Db.BlockTableRecord;
  186.  
  187.                     if (newDBObjects.Count > 0) {
  188.                         foreach (Db.DBObject item in newDBObjects) {
  189.                             if (item is Db.Entity) {
  190.                                 Db.Entity _ent = item as Db.Entity;
  191.                                 btr.AppendEntity(_ent);
  192.                                 tr.AddNewlyCreatedDBObject(item, true);
  193.                             }
  194.                         }
  195.                     }
  196.                     Db.ObjectIdCollection idsRef =
  197.                         btr.GetBlockReferenceIds(true, true);
  198.                     foreach (Db.ObjectId id in idsRef) {
  199.                         Db.BlockReference br = tr.GetObject(id,
  200.                             Db.OpenMode.ForWrite, false)
  201.                             as Db.BlockReference;
  202.                         br.RecordGraphicsModified(true);
  203.                     }
  204.                     tr.Commit();
  205.                 }
  206.                 return newDBObjects.Cast<Db.DBObject>().Select(n => n.ObjectId)
  207.                     .ToArray();
  208.             }
  209.         }
  210.  
  211.         public static void RemoveDBObject(Db.ObjectId id,
  212.             out Boolean handOverTo_called) {
  213.  
  214.             // Check arguments
  215.             if (null == id)
  216.                 throw new ArgumentException("null == id");
  217.             if (id.IsErased)
  218.                 throw new ArgumentException("true == id.IsErased");
  219.             if (null == id.Database)
  220.                 throw new ArgumentException("null == id.Database");
  221.             if (id.Database.IsDisposed)
  222.                 throw new ArgumentException("true == id.Database.IsDisposed");
  223.  
  224.             // -------------------
  225.             Db.Database db = id.Database;
  226.  
  227.             using (Db.Transaction tr = db.TransactionManager
  228.                 .StartOpenCloseTransaction()) {
  229.                 Db.DBObject obj = tr.GetObject(id, Db.OpenMode.ForWrite);
  230.                 EraseDBObject(obj, out handOverTo_called);
  231.                 tr.Commit();
  232.             }
  233.         }
  234.  
  235.         private static void EraseDBObject(Db.DBObject obj,
  236.             out Boolean handOverTo_called) {
  237.  
  238.             // Check argument
  239.             if (null == obj)
  240.                 throw new ArgumentNullException("null == obj");
  241.             if (obj.IsErased)
  242.                 throw new ArgumentException("true == obj.IsErased");
  243.             if (obj.IsDisposed)
  244.                 throw new ArgumentException("true == obj.IsDisposed");
  245.             if (null == obj.Database)
  246.                 throw new ArgumentException("null == obj.Database");
  247.             if (obj.Database.IsDisposed)
  248.                 throw new ArgumentException("true == obj.Database.IsDisposed");
  249.  
  250.             // ----------------
  251.             Boolean canBeErased = true;
  252.  
  253.             // AcDbProxyEntity::kEraseAllowed = 0x1
  254.             if (obj is Db.ProxyObject) {
  255.                 Db.ProxyObject proxy = obj as Db.ProxyObject;
  256.                 canBeErased = (proxy.ProxyFlags & 0x1) != 0;
  257.             }
  258.             else if (obj is Db.ProxyEntity) {
  259.                 Db.ProxyEntity proxy = obj as Db.ProxyEntity;
  260.                 canBeErased = (proxy.ProxyFlags & 0x1) != 0;
  261.             }
  262.