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

19/05/2015

Как найти все поля (Field) в чертеже?

Словарь именованных объектов (NOD) в базе данных содержит запись “ACAD_FIELDLIST” если чертеж содержит хотя бы одно поле. Эта запись содержит записи класса “AcDbFieldList”, который к сожалению не доступен ни в ObjectARX, ни в .NET API.

Каждый объект AcDbField обычно доступен из словаря расширения (Extension Dictionary). Например, если мы создаём MText содержащий поле, мы можем получить доступ к MTextyou и посмотреть AcDbField в его ExtensionDictionary.

Чтобы получить все поля непосредственно – единственный путь получить все TypedValue (DxfCode – пары значений) из нашего AcDbFieldList, пройдя по ним по всем и отобрав все, у которых код = 330 и тип AcDbField.

Нам придётся положится на старый добрый вызов P/Invoked для arx-методов, так что код становится зависимым от версии AutoCAD. Пример ниже ориентирован на R19 (т.е. AutoCAD 2013 и 2014). Для AutoCAD 2015 и 2016 потребуется замена "acdb19.dll" на "acdb20.dll"

Код - C#: [Выделить]
  1. class ImportsR19
  2. {
  3.     public struct ads_name
  4.     {
  5.         public IntPtr a;
  6.         public IntPtr b;
  7.     };
  8.  
  9.     [DllImport("acdb19.dll",
  10.         CallingConvention = CallingConvention.Cdecl,
  11.         EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z")]
  12.     public static extern int acdbGetAdsName32(
  13.         ref ads_name name,
  14.         ObjectId objId);
  15.  
  16.     [DllImport("acdb19.dll",
  17.         CallingConvention = CallingConvention.Cdecl,
  18.         EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")]
  19.     public static extern int acdbGetAdsName64(
  20.         ref ads_name name,
  21.         ObjectId objId);
  22.  
  23.     public static int acdbGetAdsName(
  24.         ref ads_name name,
  25.         ObjectId objId)
  26.     {
  27.         if (Marshal.SizeOf(IntPtr.Zero) > 4)
  28.             return acdbGetAdsName64(ref name, objId);
  29.  
  30.         return acdbGetAdsName32(ref name, objId);
  31.     }
  32.  
  33.     [DllImport("accore.dll",
  34.         CharSet = CharSet.Unicode,
  35.         CallingConvention = CallingConvention.Cdecl,
  36.         EntryPoint = "acdbEntGet")]
  37.     public static extern System.IntPtr acdbEntGet(
  38.         ref ads_name ename);
  39.  
  40.     public static System.Collections.Generic.List<TypedValue>
  41.         acdbEntGetTypedValues(ObjectId id)
  42.     {
  43.         System.Collections.Generic.List<TypedValue> result =
  44.             new System.Collections.Generic.List<TypedValue>();
  45.  
  46.         ads_name name = new ads_name();
  47.  
  48.         int res = acdbGetAdsName(ref name, id);
  49.  
  50.         ResultBuffer rb = new ResultBuffer();
  51.         Autodesk.AutoCAD.Runtime.Interop.AttachUnmanagedObject(
  52.             rb,
  53.             acdbEntGet(ref name),
  54.             true);
  55.  
  56.         ResultBufferEnumerator iter = rb.GetEnumerator();
  57.  
  58.         while (iter.MoveNext())
  59.         {
  60.             result.Add((TypedValue)iter.Current);
  61.         }
  62.  
  63.         return result;
  64.     }
  65. }
  66.        
  67. [CommandMethod("FieldList")]
  68. public void FieldList()
  69. {
  70.     Document doc = Application.DocumentManager.MdiActiveDocument;
  71.     Database db = doc.Database;
  72.     Editor ed = doc.Editor;
  73.  
  74.     using (var tx = db.TransactionManager.StartTransaction())
  75.     {
  76.         var nod = tx.GetObject(
  77.             db.NamedObjectsDictionaryId,
  78.             OpenMode.ForRead) as DBDictionary;
  79.  
  80.         if (!nod.Contains("ACAD_FIELDLIST"))
  81.         {
  82.             ed.WriteMessage("\nВ чертеже нет полей...");
  83.             return;
  84.         }
  85.  
  86.         var id = nod.GetAt("ACAD_FIELDLIST");
  87.  
  88.         List<TypedValue> dxf = ImportsR19.acdbEntGetTypedValues(id);
  89.  
  90.         foreach (var entry in dxf)
  91.         {
  92.             if (entry.TypeCode == 330)
  93.             {
  94.                 ObjectId objId = (ObjectId)entry.Value;
  95.  
  96.                 if (objId.ObjectClass.Name == "AcDbField")
  97.                 {
  98.                     Field field = tx.GetObject(
  99.                         objId,
  100.                         OpenMode.ForWrite) as Field;
  101.  
  102.                     field.Evaluate();
  103.  
  104.                     ed.WriteMessage(
  105.                      "\n - Формат: " + field.Format +
  106.                      " Значение: " +
  107.                      field.GetStringValue());                        
  108.                 }
  109.             }
  110.         }
  111.     }
  112. }

Источник: http://adndevblog.typepad.com/autocad/2014/07/how-to-find-all-fields-in-a-drawing.html

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

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

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