Получение списка видимых примитивов в динамическом блоке
Членом ADN был задан следующий вопрос:
Как можно получить список видимых примитивов для конкретного состояния видимости динамического блока, содержащего параметр видимости?
Решение основывается на предложении Тони Танзилло из этого сообщения на форуме.
Решение:
К сожалению API динамических блоков ограничено и нет прямого пути для получения этой информации. Эта информация в словаре расширения динамического блока и требуется смотреть на свойства экземпляра класса "AcDbBlockVisibilityParameter" (это родной класс ObjectARX, но он недоступен через публичные API ни в C++, ни в .NET).
Так что требуется несколько больше работы для получения этой информации. Вот несколько шагов:
- Получаем BlockTableRecord для динамического блока.
- Получаем словарь расширения для BlockTableRecord.
- Получаем ObjectId для "ACAD_ENHANCEDBLOCK" в словаре расширения.
- Вызываем acdbEntGet() для ObjectId, полученном на шаге 3, которая возвращает ResultBuffer содержащий TypedValues.
- Проходим по всем TypedValue и ищем код группы 360, получаем ObjectId сохранённый в свойстве Value, затем смотрим свойство 'Name' свойства property ObjectClass этого ObjectId, и проверяем что оно равно строке "AcDbBlockVisibilityParameter".
- Как только мы нашли ObjectId объекта AcDbBlockVisibilityParameter - вызываем acdbEntGet() для него.
- Проходимся по всем TypedValue в ResultBuffer, который возвращает acdbEntGet(), смотрим на код группы 303.
- Получаем следующий элемент из ResultBuffer с кодом группы 94, значение которого – число следующих ObjectId, и считываем последовательно ObjectId в список – это и будет список ObjectId примитивов видимых в этом состоянии видимости.
Вот полный C# code:
- [CommandMethod("DynablockVisibilityStates")]
- public void DynablockVisibilityStates()
- {
- Document doc = Application.DocumentManager.MdiActiveDocument;
- Database db = doc.Database;
- Editor ed = doc.Editor;
- PromptResult pr = ed.GetString("\nУкажите имя блока: ");
- if (pr.Status != PromptStatus.OK)
- return;
- using (Transaction Tx = db.TransactionManager.StartTransaction())
- {
- BlockTable bt = Tx.GetObject(
- db.BlockTableId,
- OpenMode.ForRead)
- as BlockTable;
- if (!bt.Has(pr.StringResult))
- {
- ed.WriteMessage("\nТакого блока нет :(");
- return;
- }
- BlockTableRecord btr = Tx.GetObject(
- bt[pr.StringResult],
- OpenMode.ForRead)
- as BlockTableRecord;
- if (!btr.IsDynamicBlock)
- {
- ed.WriteMessage("\nЭто не динамический блок :(");
- return;
- }
- if (btr.ExtensionDictionary == null)
- {
- ed.WriteMessage("\nНет словаря расширения :(");
- return;
- }
- DBDictionary dico = Tx.GetObject(
- btr.ExtensionDictionary,
- OpenMode.ForRead)
- as DBDictionary;
- if (!dico.Contains("ACAD_ENHANCEDBLOCK"))
- {
- ed.WriteMessage(
- "\nНет записи ACAD_ENHANCEDBLOCK :(");
- return;
- }
- ObjectId graphId = dico.GetAt("ACAD_ENHANCEDBLOCK");
- System.Collections.Generic.List<object> parameterIds =
- acdbEntGetObjects(graphId, 360);
- foreach (object parameterId in parameterIds)
- {
- ObjectId id = (ObjectId)parameterId;
- if (id.ObjectClass.Name ==
- "AcDbBlockVisibilityParameter")
- {
- System.Collections.Generic.List<TypedValue>
- visibilityParam = acdbEntGetTypedVals(id);
- System.Collections.Generic.
- List<TypedValue>.Enumerator enumerator =
- visibilityParam.GetEnumerator();
- while (enumerator.MoveNext())
- {
- if (enumerator.Current.TypeCode == 303)
- {
- string group =
- (string)enumerator.Current.Value;
- enumerator.MoveNext();
- int nbEntitiesInGroup =
- (int)enumerator.Current.Value;
- ed.WriteMessage(
- "\n . Состояние видимости: " + group +
- " Число примитивов в группе: " +
- nbEntitiesInGroup);
- for (int i = 0; i < nbEntitiesInGroup; ++i)
- {
- enumerator.MoveNext();
- ObjectId entityId =
- (ObjectId)enumerator.Current.Value;
- Entity entity = Tx.GetObject(
- entityId,
- OpenMode.ForRead)
- as Entity;
- ed.WriteMessage("\n - " +
- entity.ToString() + " " +
- entityId.ToString());
- }
- }
- }
- break;
- }
- }
- Tx.Commit();
- }
- }
- public struct ads_name
- {
- IntPtr a;
- IntPtr b;
- };
- [DllImport("acdb18.dll",
- CallingConvention = CallingConvention.Cdecl,
- EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z")]
- public static extern int acdbGetAdsName(
- ref ads_name name, ObjectId objId);
- [DllImport("acad.exe",
- CharSet = CharSet.Ansi,
- CallingConvention = CallingConvention.Cdecl,
- EntryPoint = "acdbEntGet")]
- public static extern System.IntPtr acdbEntGet(ref ads_name ename);
- private System.Collections.Generic.List<object>
- acdbEntGetObjects(ObjectId id, short dxfcode)
- {
- System.Collections.Generic.List<object> result =
- new System.Collections.Generic.List<object>();
- ads_name name = new ads_name();
- int res = acdbGetAdsName(ref name, id);
- ResultBuffer rb = new ResultBuffer();
- Autodesk.AutoCAD.Runtime.Interop.AttachUnmanagedObject(
- rb, acdbEntGet(ref name), true);
- ResultBufferEnumerator iter = rb.GetEnumerator();
- while (iter.MoveNext())
- {
- TypedValue typedValue = (TypedValue)iter.Current;
- if (typedValue.TypeCode == dxfcode)
- {
- result.Add(typedValue.Value);
- }
- }
- return result;
- }
- private System.Collections.Generic.List<TypedValue>
- acdbEntGetTypedVals(ObjectId id)
- {
- System.Collections.Generic.List<TypedValue> result =
- new System.Collections.Generic.List<TypedValue>();
- ads_name name = new ads_name();
- int res = acdbGetAdsName(ref name, id);
- ResultBuffer rb = new ResultBuffer();
- Autodesk.AutoCAD.Runtime.Interop.AttachUnmanagedObject(
- rb, acdbEntGet(ref name), true);
- ResultBufferEnumerator iter = rb.GetEnumerator();
- while (iter.MoveNext())
- {
- result.Add((TypedValue)iter.Current);
- }
- return result;
- }
Примечание: 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