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

25/06/2014

Итерация системных переменных AutoCAD через .NET, часть 2

В предыдущей части был предоставлен код, показывающий реализацию двух доступных механизмов итерации по системным переменным AutoCAD: SystemObects.Variables и новый класс SystemVariableEnumerator.

Сегодня мы посмотрим внимательнее на оба эти механизма, кратко сопоставив их возможности и результаты работы. За основу взят код из предыдущей части статьи. Код упрощен, удалены "проходы" по БД чертежа - все для улучшения сопоставимости результатов.

Ниже представлен код C# с обновленными вариантами команд ESV и ESV2, которые создают соответствующие txt-файлы в каталоге c:\temp. Это получается быстрее, чем вывод в командную строку Windows. Кроме того, игнорируется информация Primary/SecondaryType - все только ради того, чтобы получить сопоставимые результаты.
Код - C#: [Выделить]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.ApplicationServices.Core;
  3. using Autodesk.AutoCAD.Geometry;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Text;
  9.  
  10. namespace SystemVariableEnumeration
  11. {
  12.   public class Commands
  13.   {
  14.     public void MeasureTime(
  15.       Document doc, Func func, string name
  16.     )
  17.     {
  18.       // Get the name of the running command(s)
  19.       // (might also have queried the CommandMethod attribute
  20.       // via reflection, but that would be a lot more work)
  21.       var cmd = (string)Application.GetSystemVariable("CMDNAMES");
  22.       // Start a Stopwatch to time the execution
  23.       var sw = new Stopwatch();
  24.       sw.Start();
  25.       // Run the function, getting back the count of the results
  26.       var cnt = func();
  27.       // Stop the Stopwatch and print the results to the command-line
  28.       sw.Stop();
  29.       doc.Editor.WriteMessage(
  30.         "\n{0} found {1} {2} in {3}.", cmd, cnt, name, sw.Elapsed
  31.       );
  32.     }
  33.  
  34.     [CommandMethod("ESV")]
  35.     public void EnumerateSysVars()
  36.     {
  37.       var doc = Application.DocumentManager.MdiActiveDocument;
  38.       if (doc == null)
  39.         return;
  40.       MeasureTime(
  41.         doc,
  42.         () =>
  43.         {
  44.           int numVars = 0;
  45.           using (var sw = new StreamWriter("c:\\temp\\esv.txt"))
  46.           {
  47.             // Use the existing SystemObjects iteration mechanism
  48.             foreach (var v in SystemObjects.Variables)
  49.             {
  50.               sw.WriteLine(GetVariableInfo(v));
  51.               numVars++;
  52.             }
  53.           }
  54.           return numVars;
  55.         },
  56.         "variables"
  57.       );
  58.     }
  59.  
  60.     [CommandMethod("ESV2")]
  61.     public void EnumerateSysVars2()
  62.     {
  63.       var doc = Application.DocumentManager.MdiActiveDocument;
  64.       if (doc == null)
  65.         return;
  66.       MeasureTime(
  67.         doc,
  68.         () =>
  69.         {
  70.           int numVars = 0;
  71.           using (var sw = new StreamWriter("c:\\temp\\esv2.txt"))
  72.           {
  73.             // Use the new system variable enumerator
  74.             var sve = new SystemVariableEnumerator();
  75.             while (sve.MoveNext())
  76.             {
  77.               var v = sve.Current;
  78.               if (v != null)
  79.               {
  80.                 sw.WriteLine(GetVariableInfo(v));
  81.                 numVars++;
  82.               }
  83.             }
  84.           }
  85.           return numVars;
  86.         },
  87.         "variables"
  88.       );
  89.     }
  90.  
  91.     // Helper function to get the information for a particular
  92.     // variable
  93.     private static string GetVariableInfo(Variable v)
  94.     {
  95.       var t = GetType(v.PrimaryType);
  96.       var sb = new StringBuilder();
  97.       sb.AppendFormat(
  98.         "{0} ({1}): {2}", // Skip the additional type info
  99.         v.Name,
  100.         t == null ? "null" : t.Name,
  101.         /*v.PrimaryType, v.SecondaryType,*/ v.TypeFlags
  102.       );
  103.  
  104.       if (v.Range != null)
  105.       {
  106.         sb.AppendFormat(
  107.           " [{0}...{1}]",
  108.           v.Range.LowerBound, v.Range.UpperBound
  109.         );
  110.       }
  111.       return sb.ToString();
  112.     }
  113.  
  114.     // Determine the type of a system variable based on
  115.     // the internal representation
  116.     private static System.Type GetType(short v)
  117.     {
  118.       Type ret = null;
  119.       switch (v)
  120.       {
  121.         case 1:
  122.         case 5001: // RTREAL real number
  123.           {
  124.             ret = typeof(Double);
  125.             break;
  126.           }
  127.         case 2:
  128.         case 5002: // RTPOINT: 2D point X and Y only
  129.           {
  130.             ret = typeof(Point2d);
  131.             break;
  132.           }
  133.         case 3:
  134.         case 5003: // RTSHORT: short integer
  135.           {
  136.             ret = typeof(Int16);
  137.             break;
  138.           }
  139.         case 4:
  140.         case 5004: // RTANG: angle
  141.           {
  142.             ret = null; // Angle
  143.             break;
  144.           }
  145.         case 5:
  146.         case 5005: // RTSTR: string
  147.           {
  148.             ret = typeof(String);
  149.             break;
  150.           }
  151.         case 6:
  152.         case 5006: // RTENAME: entity name
  153.           {
  154.             ret = null;
  155.             break;
  156.           }
  157.         case 7:
  158.         case 5007: // RTPICKS: pick set
  159.           {
  160.             ret = null;
  161.             break;
  162.           }
  163.         case 8:
  164.         case 5008: // RTORIENT: orientation
  165.           {
  166.             ret = null; // Orientation
  167.             break;
  168.           }
  169.         case 9:
  170.         case 5009: // RT3DPOINT: 3D point - X, Y and Z
  171.           {
  172.             ret = typeof(Point3d);
  173.             break;
  174.           }
  175.         case 10:
  176.         case 5010: // RTLONG: long integer
  177.           {
  178.             ret = typeof(Int32);
  179.             break;
  180.           }
  181.         case 11:
  182.         case 5011: // 2D extents of some kind
  183.           {
  184.             ret = typeof(Point2d);
  185.             break;
  186.           }
  187.       }
  188.       return ret;
  189.     }
  190.   }
  191. }
После запуска кода мы увидим, что команда ESV (использующая SystemObject.Variables) отработала быстрее, но нашла только 274 (при установленном SP1 для AutoCAD 2015 будет найдено 275 - включая CURSORBADGE) системные переменные. В то же время ESV2 обнаружит 912 (соответственно при установленном SP1 - 913) за сопоставимое время. Так что вопрос производительности можно сбросить со счетов.

Весьма интересно (и, можно сказать, даже обнадеживает), что новый механизм находит настолько больше системных переменных. С одной стороны, старый механизм (SystemObjects.Variables) позволяет менять значение системной переменной через возвращаемый объект:
Код - C#: [Выделить]
  1. [CommandMethod("TOGCB")]
  2. public void ToggleCursorBadge()
  3. {
  4.   var doc = Application.DocumentManager.MdiActiveDocument;
  5.   if (doc == null)
  6.     return;
  7.   var ed = doc.Editor;
  8.   const string curbadge = "CURSORBADGE";
  9.   // Get our CURSORBADGE system variable object
  10.   var cb = SystemObjects.Variables[curbadge];
  11.   // Report its initial value
  12.   ed.WriteMessage(
  13.     "\nInitial value of {0} is {1}.", curbadge, cb.Value
  14.   );
  15.  
  16.   // Set the new value, toggling between 1 & 2
  17.   // (with too many casts for my liking, but hey)
  18.   cb.Value = (short)((short)cb.Value == 1 ? 2 : 1);
  19.   // And report the new value to make sure it worked
  20.   ed.WriteMessage(
  21.     "\nNew value of {0} is {1}.", curbadge, cb.Value
  22.   );
  23. }
Но, с другой стороны, это работает только для подмножества системных переменных (и пока автор еще не выяснил, какие именно... Известно, что новый счетчик пропускает анонимные системные переменные, и все равно находит втрое больше переменных).

Если есть желание, можно рассмотреть подробнее результаты работы как команды ESV, так и команды ESV2.

Источник: http://through-the-interface.typepad.com/...-system-variables-using-net-part-2.html
Перевел: Алексей Кулик

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

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