ADN Open CIS
Сообщество программистов Autodesk в СНГ

25/08/2015

Получение списка видимых примитивов в динамическом блоке

Членом ADN был задан следующий вопрос:

Как можно получить список видимых примитивов для конкретного состояния видимости динамического блока, содержащего параметр видимости?

Решение основывается на предложении Тони Танзилло из этого сообщения на форуме.

Решение:

К сожалению API динамических блоков ограничено и нет прямого пути для получения этой информации. Эта информация в словаре расширения динамического блока и требуется смотреть на свойства экземпляра класса "AcDbBlockVisibilityParameter" (это родной класс ObjectARX, но он недоступен через публичные API ни в C++, ни в .NET).

Так что требуется несколько больше работы для получения этой информации. Вот несколько шагов:

  1. Получаем BlockTableRecord для динамического блока.
  2. Получаем словарь расширения для BlockTableRecord.
  3. Получаем ObjectId для "ACAD_ENHANCEDBLOCK" в словаре расширения.
  4. Вызываем acdbEntGet() для ObjectId, полученном на шаге 3, которая возвращает ResultBuffer содержащий TypedValues.
  5. Проходим по всем TypedValue и ищем код группы 360, получаем ObjectId сохранённый в свойстве Value, затем смотрим свойство 'Name' свойства property ObjectClass этого ObjectId, и проверяем что оно равно строке "AcDbBlockVisibilityParameter".
  6. Как только мы нашли ObjectId объекта AcDbBlockVisibilityParameter - вызываем acdbEntGet() для него.
  7. Проходимся по всем TypedValue в ResultBuffer, который возвращает acdbEntGet(), смотрим на код группы 303.
  8. Получаем следующий элемент из ResultBuffer с кодом группы 94, значение которого – число следующих ObjectId, и считываем последовательно ObjectId в список – это и будет список ObjectId примитивов видимых в этом состоянии видимости.

Вот полный  C# code:

Код - C#: [Выделить]
  1. [CommandMethod("DynablockVisibilityStates")]
  2. public void DynablockVisibilityStates()
  3. {
  4.     Document doc = Application.DocumentManager.MdiActiveDocument;
  5.     Database db = doc.Database;
  6.     Editor ed = doc.Editor;
  7.  
  8.     PromptResult pr = ed.GetString("\nУкажите имя блока: ");
  9.  
  10.     if (pr.Status != PromptStatus.OK)
  11.         return;
  12.  
  13.     using (Transaction Tx = db.TransactionManager.StartTransaction())
  14.     {
  15.         BlockTable bt = Tx.GetObject(
  16.             db.BlockTableId,
  17.             OpenMode.ForRead)
  18.                 as BlockTable;
  19.  
  20.         if (!bt.Has(pr.StringResult))
  21.         {
  22.             ed.WriteMessage("\nТакого блока нет :(");
  23.             return;
  24.         }
  25.  
  26.         BlockTableRecord btr = Tx.GetObject(
  27.             bt[pr.StringResult],
  28.             OpenMode.ForRead)
  29.                 as BlockTableRecord;
  30.        
  31.         if (!btr.IsDynamicBlock)
  32.         {
  33.             ed.WriteMessage("\nЭто не динамический блок :(");
  34.             return;
  35.         }
  36.  
  37.         if (btr.ExtensionDictionary == null)
  38.         {
  39.             ed.WriteMessage("\nНет словаря расширения :(");
  40.             return;
  41.         }
  42.  
  43.         DBDictionary dico = Tx.GetObject(
  44.             btr.ExtensionDictionary,
  45.             OpenMode.ForRead)
  46.                 as DBDictionary;
  47.  
  48.         if (!dico.Contains("ACAD_ENHANCEDBLOCK"))
  49.         {
  50.             ed.WriteMessage(
  51.                 "\nНет записи ACAD_ENHANCEDBLOCK :(");
  52.  
  53.             return;
  54.         }
  55.  
  56.         ObjectId graphId = dico.GetAt("ACAD_ENHANCEDBLOCK");
  57.  
  58.         System.Collections.Generic.List<object> parameterIds =
  59.             acdbEntGetObjects(graphId, 360);
  60.  
  61.         foreach (object parameterId in parameterIds)
  62.         {
  63.             ObjectId id = (ObjectId)parameterId;
  64.  
  65.             if (id.ObjectClass.Name ==
  66.                 "AcDbBlockVisibilityParameter")
  67.             {
  68.                 System.Collections.Generic.List<TypedValue>
  69.                     visibilityParam = acdbEntGetTypedVals(id);
  70.  
  71.                 System.Collections.Generic.
  72.                     List<TypedValue>.Enumerator enumerator =
  73.                     visibilityParam.GetEnumerator();
  74.  
  75.                 while (enumerator.MoveNext())
  76.                 {
  77.                     if (enumerator.Current.TypeCode == 303)
  78.                     {
  79.                         string group =
  80.                             (string)enumerator.Current.Value;
  81.  
  82.                         enumerator.MoveNext();
  83.  
  84.                         int nbEntitiesInGroup =
  85.                             (int)enumerator.Current.Value;
  86.  
  87.                         ed.WriteMessage(
  88.                            "\n . Состояние видимости: " + group +
  89.                            " Число примитивов в группе: " +
  90.                            nbEntitiesInGroup);
  91.  
  92.                         for (int i = 0; i < nbEntitiesInGroup; ++i)
  93.                         {
  94.                             enumerator.MoveNext();
  95.                             ObjectId entityId =
  96.                                 (ObjectId)enumerator.Current.Value;
  97.  
  98.                             Entity entity = Tx.GetObject(
  99.                                 entityId,
  100.                                 OpenMode.ForRead)
  101.                                     as Entity;
  102.  
  103.                             ed.WriteMessage("\n    - " +
  104.                                 entity.ToString() + " " +
  105.                                 entityId.ToString());
  106.                         }
  107.                     }
  108.                 }
  109.                 break;
  110.             }
  111.         }
  112.  
  113.         Tx.Commit();
  114.     }
  115. }
  116.  
  117. public struct ads_name
  118. {
  119.     IntPtr a;
  120.     IntPtr b;
  121. };
  122.  
  123. [DllImport("acdb18.dll",
  124.     CallingConvention = CallingConvention.Cdecl,
  125.     EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z")]
  126. public static extern int acdbGetAdsName(
  127.     ref ads_name name, ObjectId objId);
  128.  
  129. [DllImport("acad.exe",
  130.     CharSet = CharSet.Ansi,
  131.     CallingConvention = CallingConvention.Cdecl,
  132.     EntryPoint = "acdbEntGet")]
  133. public static extern System.IntPtr acdbEntGet(ref ads_name ename);
  134.  
  135. private System.Collections.Generic.List<object>
  136.     acdbEntGetObjects(ObjectId id, short dxfcode)
  137. {
  138.     System.Collections.Generic.List<object> result =
  139.         new System.Collections.Generic.List<object>();
  140.  
  141.     ads_name name = new ads_name();
  142.  
  143.     int res = acdbGetAdsName(ref name, id);
  144.  
  145.     ResultBuffer rb = new ResultBuffer();
  146.  
  147.     Autodesk.AutoCAD.Runtime.Interop.AttachUnmanagedObject(
  148.         rb, acdbEntGet(ref name), true);
  149.  
  150.     ResultBufferEnumerator iter = rb.GetEnumerator();
  151.  
  152.     while (iter.MoveNext())
  153.     {
  154.         TypedValue typedValue = (TypedValue)iter.Current;
  155.  
  156.         if (typedValue.TypeCode == dxfcode)
  157.         {
  158.             result.Add(typedValue.Value);
  159.         }
  160.     }
  161.  
  162.     return result;
  163. }
  164.  
  165. private System.Collections.Generic.List<TypedValue>
  166.     acdbEntGetTypedVals(ObjectId id)
  167. {
  168.     System.Collections.Generic.List<TypedValue> result =
  169.         new System.Collections.Generic.List<TypedValue>();
  170.  
  171.     ads_name name = new ads_name();
  172.    
  173.     int res = acdbGetAdsName(ref name, id);
  174.  
  175.     ResultBuffer rb = new ResultBuffer();
  176.  
  177.     Autodesk.AutoCAD.Runtime.Interop.AttachUnmanagedObject(
  178.         rb, acdbEntGet(ref name), true);
  179.  
  180.     ResultBufferEnumerator iter = rb.GetEnumerator();
  181.  
  182.     while (iter.MoveNext())
  183.     {
  184.         result.Add((TypedValue)iter.Current);
  185.     }
  186.  
  187.     return result;
  188. }

 

Примечание: acdb18.dll – для AutoCAD 2010…2012, acdb19.dll – для AutoCAD 2013 и 2014 и acdb20.dll - для AutoCAD 2015 и 2016. Вместо acad.exe для версии AutoCAD 2013 и новее  следует использовать accore.dll. Так же следует учитывать разрядность AutoCAD.

Источник: http://adndevblog.typepad.com/autocad/2012/05/accessing-visible-entities-in-a-dynamic-block.html

Автор перевода: Александр Ривилис

Обсуждение: http://adn-cis.org/forum/index.php?topic=2941

Опубликовано 25.08.2015