Автоматическое размещение объекта на нужном слое

Дата публикации: 10.10.2010
Дата изменения: 23.04.2014
Состояние: завершена

Задача

    Необходимо реализовать механизм, позволяющий управлять тем, объекты какого типа должны размещаться на каком слое с учётом локализации. Для начала создадим такой файл настроек нашего плагина (файл Settings.xml):

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <!--Разработчик: Андрей Бушман (СПб 2010)-->
   3:  <Settings>
   4:    <!--Локализация (для ресурсов), указанная пользователем к использованию-->
   5:    <CurrentResourcesLocalization>ru-RU</CurrentResourcesLocalization>
   6:  </Settings>

    Затем создадим файл Layers.xml и его локализованные версии (на этой странице сайта привожу содержимое только для файла Layers.xml - содержимое файлов Layers.ru-RU.xml и Layers.en-US.xml смотрите в полном варианте исходного кода). 


    Данный файл является конфигурационным файлом нашего приложения. В нём указывается, объекты каких команд следует помещать на какой слой. В зависимости от того, какая локализация указана в файле Settings.xml, слои будут создаваться на русском или на английском языке. При желании пользователь может добавить любую нужную ему локализацию по аналогии с Layer.xml - при этом не придётся перекомпилировать исходный код библиотеки.

    Содержимое файла Layers.xml такое:

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <!--Настройки слоёв-->
   3:  <!--
   4:  ****************************
   5:  Толщину линии, назначаемую слою, следует назначать в соответствии со следующим допустимым перечнем толщин:
   6:  ByLineWeightDefault,
   7:  ByBlock,
   8:  ByLayer,
   9:  LineWeight000,
  10:  LineWeight005,
  11:  LineWeight009,
  12:  LineWeight013,
  13:  LineWeight015,
  14:  LineWeight018,
  15:  LineWeight020,
  16:  LineWeight025,
  17:  LineWeight030,
  18:  LineWeight035,
  19:  LineWeight040,
  20:  LineWeight050,
  21:  LineWeight053,
  22:  LineWeight060,
  23:  LineWeight070,
  24:  LineWeight080,
  25:  LineWeight090,
  26:  LineWeight100,
  27:  LineWeight106,
  28:  LineWeight120,
  29:  LineWeight140,
  30:  LineWeight158,
  31:  LineWeight200,
  32:  LineWeight211,
  33:  ***************************
  34:  Наименования цветов следует назначать в соответствии со следующим допустимым набором имён цветов:
  35:  Transparent
  36:  AliceBlue
  37:  AntiqueWhite
  38:  Aqua
  39:  Aquamarine
  40:  Azure
  41:  Beige
  42:  Bisque
  43:  Black
  44:  BlanchedAlmond
  45:  Blue
  46:  BlueViolet
  47:  Brown
  48:  BurlyWood
  49:  CadetBlue
  50:  Chartreuse
  51:  Chocolate
  52:  Coral
  53:  CornflowerBlue
  54:  Cornsilk
  55:  Crimson
  56:  Cyan
  57:  DarkBlue
  58:  DarkCyan
  59:  DarkGoldenrod
  60:  DarkGray
  61:  DarkGreen
  62:  DarkKhaki
  63:  DarkMagenta
  64:  DarkOliveGreen
  65:  DarkOrange
  66:  DarkOrchid
  67:  DarkRed
  68:  DarkSalmon
  69:  DarkSeaGreen
  70:  DarkSlateBlue
  71:  DarkSlateGray
  72:  DarkTurquoise
  73:  DarkViolet
  74:  DeepPink
  75:  DeepSkyBlue
  76:  DimGray
  77:  DodgerBlue
  78:  Firebrick
  79:  FloralWhite
  80:  ForestGreen
  81:  Fuchsia
  82:  Gainsboro
  83:  GhostWhite
  84:  Gold
  85:  Goldenrod
  86:  Gray
  87:  Green
  88:  GreenYellow
  89:  Honeydew
  90:  HotPink
  91:  IndianRed
  92:  Indigo
  93:  Ivory
  94:  Khaki
  95:  Lavender
  96:  LavenderBlush
  97:  LawnGreen
  98:  LemonChiffon
  99:  LightBlue
 100:  LightCoral
 101:  LightCyan
 102:  LightGoldenrodYellow
 103:  LightGreen
 104:  LightGray
 105:  LightPink
 106:  LightSalmon
 107:  LightSeaGreen
 108:  LightSkyBlue
 109:  LightSlateGray
 110:  LightSteelBlue
 111:  LightYellow
 112:  Lime
 113:  LimeGreen
 114:  Linen
 115:  Magenta
 116:  Maroon
 117:  MediumAquamarine
 118:  MediumBlue
 119:  MediumOrchid
 120:  MediumPurple
 121:  MediumSeaGreen
 122:  MediumSlateBlue
 123:  MediumSpringGreen
 124:  MediumTurquoise
 125:  MediumVioletRed
 126:  MidnightBlue
 127:  MintCream
 128:  MistyRose
 129:  Moccasin
 130:  NavajoWhite
 131:  Navy
 132:  OldLace
 133:  Olive
 134:  OliveDrab
 135:  Orange
 136:  OrangeRed
 137:  Orchid
 138:  PaleGoldenrod
 139:  PaleGreen
 140:  PaleTurquoise
 141:  PaleVioletRed
 142:  PapayaWhip
 143:  PeachPuff
 144:  Peru
 145:  Pink
 146:  Plum
 147:  PowderBlue
 148:  Purple
 149:  Red
 150:  RosyBrown
 151:  RoyalBlue
 152:  SaddleBrown
 153:  Salmon
 154:  SandyBrown
 155:  SeaGreen
 156:  SeaShell
 157:  Sienna
 158:  Silver
 159:  SkyBlue
 160:  SlateBlue
 161:  SlateGray
 162:  Snow
 163:  SpringGreen
 164:  SteelBlue
 165:  Tan
 166:  Teal
 167:  Thistle
 168:  Tomato
 169:  Turquoise
 170:  Violet
 171:  Wheat
 172:  White
 173:  WhiteSmoke
 174:  Yellow
 175:  YellowGreen
 176:  ***************************
 177:  -->
 178:  <Layers>
 179:    <Layer Commands="DIMLINEAR;DIMALIGNED;DIMANGULAR;DIMARC;DIMRADIUS;DIMDIAMETER;DIMJOGLINE;DIMORDINATE">
 180:      <Name>Размеры</Name>
 181:      <LineWeight>LineWeight015</LineWeight>
 182:      <Color>Red</Color>
 183:      <Description>Слой для размещения размеров</Description>
 184:    </Layer>
 185:    <Layer Commands="TEXT;MTEXT">
 186:      <Name>Текст</Name>
 187:      <LineWeight>LineWeight020</LineWeight>
 188:      <Color>Blue</Color>
 189:      <Description>Слой для размещения текста</Description>
 190:    </Layer>
 191:    <Layer Commands="MLEADER">
 192:      <Name>Выноски</Name>
 193:      <LineWeight>LineWeight025</LineWeight>
 194:      <Color>Green</Color>
 195:      <Description>Слой для размещения выносок</Description>
 196:    </Layer>
 197:    <Layer Commands="HATCH">
 198:      <Name>Штриховка</Name>
 199:      <LineWeight>LineWeight030</LineWeight>
 200:      <Color>SeaShell</Color>
 201:      <Description>Слой для размещения штриховки</Description>
 202:    </Layer>
 203:    <Layer Commands="TABLE">
 204:      <Name>Таблицы</Name>
 205:      <LineWeight>LineWeight035</LineWeight>
 206:      <Color>Violet</Color>
 207:      <Description>Слой для размещения таблиц</Description>
 208:    </Layer>
 209:  </Layers>
 
    Далее собственно код:

ExtensionApplication.cs

   1:  // LayerSwitcher.dll
   2:  // © Andrey Bushman, 2010
   3:  // ExtensionApplication.cs
   4:  using System.Linq;
   5:  using System.Collections;
   6:  using System.Collections.Generic;
   7:  using System.Xml.Linq;
   8:  using System.IO;
   9:  using System;
  10:   
  11:  #if AUTOCAD
  12:  using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  13:  using Ap = Autodesk.AutoCAD.ApplicationServices;
  14:  using Db = Autodesk.AutoCAD.DatabaseServices;
  15:  using Rt = Autodesk.AutoCAD.Runtime;
  16:  using Clr = Autodesk.AutoCAD.Colors;
  17:  using System.Reflection;
  18:  #endif
  19:   
  20:  [assembly: Rt.ExtensionApplication(typeof(
  21:     Bushman.CAD.Layers.ExtensionApplication))]
  22:   
  23:  namespace Bushman.CAD.Layers {
  24:   
  25:    public class ExtensionApplication : Rt.IExtensionApplication {
  26:   
  27:      //Словарь, в котором каждой команде сопоставлен свой слой
  28:      static Dictionary<String, Db.LayerTableRecord> dict;
  29:      //Полное имя каталога, в котором находится данная сборка
  30:      static String currentDir;
  31:      //Имя слоя, который был текущим до того, как была выполнена команда
  32:      static String previousLayerName;
  33:   
  34:      public void Initialize() {
  35:        Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  36:        if (doc == null)
  37:          cad.DocumentManager.DocumentActivated += DocMng_DocumentActivated;
  38:        else
  39:          doc.Editor.WriteMessage("\n© Андрей Бушман, 2010\nСборка \"{0}\" " +
  40:            "загружена.\n", Assembly.GetExecutingAssembly().Location);
  41:   
  42:        currentDir = new FileInfo(this.GetType().Assembly.Location)
  43:           .DirectoryName;
  44:        XElement settings = XElement.Load(Path.Combine(currentDir,
  45:          "Settings.xml"));
  46:        String localization = settings.Element("CurrentResourcesLocalization")
  47:           .Value.Trim();
  48:        XElement layersInfo = localization == String.Empty ? XElement.Load(
  49:          Path.Combine(currentDir, "Layers.xml")) :
  50:          XElement.Load(Path.Combine(currentDir, String.Format(
  51:            "Layers.{0}.xml", localization)));
  52:        dict = new Dictionary<String, Db.LayerTableRecord>();
  53:   
  54:        foreach (XElement layer in layersInfo.Elements("Layer")) {
  55:          Db.LayerTableRecord lt = new Db.LayerTableRecord();
  56:          lt.Name = layer.Element("Name").Value.Trim();
  57:          lt.Description = layer.Element("Description").Value.Trim();
  58:          lt.LineWeight = (Db.LineWeight)Enum.Parse(typeof(Db.LineWeight),
  59:             layer.Element("LineWeight").Value.Trim());
  60:          Clr.Color color = Clr.Color.FromColor(System.Drawing.Color.FromName(
  61:             layer.Element("Color").Value.Trim()));
  62:          lt.Color = color;
  63:          dict.Add(layer.Attribute("Commands").Value.Trim(), lt);
  64:        }
  65:   
  66:        cad.DocumentManager.DocumentCreated +=
  67:           new Ap.DocumentCollectionEventHandler(DocMng_DocumentCreated);
  68:        MainMethod();
  69:      }
  70:   
  71:      void DocMng_DocumentActivated(Object sender,
  72:        Ap.DocumentCollectionEventArgs e) {
  73:        cad.DocumentManager.DocumentActivated -= DocMng_DocumentActivated;
  74:        e.Document.Editor.WriteMessage("\n© Андрей Бушман, 2010\nСборка \"{0}\" "
  75:          + "загружена.\n", Assembly.GetExecutingAssembly().Location);
  76:      }
  77:   
  78:      public void Terminate() {
  79:      }
  80:   
  81:      private void MainMethod() {
  82:        Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  83:        if (doc == null)
  84:          return;
  85:        Db.Database db = doc.Database;
  86:   
  87:        #region Подписка на события обработки команд
  88:        doc.CommandWillStart += new Ap.CommandEventHandler(acDoc_CmdWillStart);
  89:        doc.CommandCancelled += new Ap.CommandEventHandler(acDoc_CommandEFC);
  90:        doc.CommandEnded += new Ap.CommandEventHandler(acDoc_CommandEFC);
  91:        doc.CommandFailed += new Ap.CommandEventHandler(acDoc_CommandEFC);
  92:        #endregion
  93:   
  94:        using (Db.Transaction t = db.TransactionManager.StartTransaction()) {
  95:          Db.LayerTable layersTable = t.GetObject(db.LayerTableId,
  96:             Db.OpenMode.ForRead) as Db.LayerTable;
  97:          foreach (KeyValuePair<String, Db.LayerTableRecord> i in dict) {
  98:            if (!layersTable.Has(i.Value.Name)) {
  99:              layersTable.UpgradeOpen();
 100:              Db.SymbolTableRecord layer = Clone(i.Value);
 101:              layersTable.Add(layer);
 102:              t.AddNewlyCreatedDBObject(layer, true);
 103:            }
 104:          }
 105:          t.Commit();
 106:        }
 107:      }
 108:   
 109:      private Db.SymbolTableRecord Clone(Db.LayerTableRecord layerTableRecord) {
 110:        if (layerTableRecord == null)
 111:          throw new ArgumentNullException("layerTableRecord");
 112:        Db.LayerTableRecord result = new Db.LayerTableRecord();
 113:        result.Name = layerTableRecord.Name;
 114:        result.Description = layerTableRecord.Description;
 115:        result.LineWeight = layerTableRecord.LineWeight;
 116:        result.Color = layerTableRecord.Color;
 117:        return result;
 118:      }
 119:   
 120:      private void DocMng_DocumentCreated
 121:          (Object sender, Ap.DocumentCollectionEventArgs e) {
 122:        MainMethod();
 123:      }
 124:   
 125:      private void acDoc_CmdWillStart(Object sender, Ap.CommandEventArgs e) {
 126:        previousLayerName = (String)cad.GetSystemVariable("CLAYER");
 127:        foreach (KeyValuePair<String, Db.LayerTableRecord> item in dict) {
 128:          if (item.Key.Split(';').Contains(e.GlobalCommandName)) {
 129:            cad.SetSystemVariable("CLAYER", dict[item.Key].Name);
 130:            break;
 131:          }
 132:        }
 133:      }
 134:   
 135:      private void acDoc_CommandEFC(Object sender, Ap.CommandEventArgs e) {
 136:        foreach (KeyValuePair<String, Db.LayerTableRecord> item in dict) {
 137:          if (item.Key.Split(';').Contains(e.GlobalCommandName)) {
 138:            cad.SetSystemVariable("CLAYER", previousLayerName);
 139:            break;
 140:          }
 141:        }
 142:      }
 143:    }
 144:  }

Данный код протестирован на AutoCAD 2009 x86, с предустановленной библиотекой .Net Framework 3.5 SP1.


Исходный код проекта здесь.

    Указанный выше вариант решения будет неплохо работать в том случае, когда объекты создаются пользователем в процессе работы AutoCAD с помощью стандартных команд, или же с помощью функций AutoLisp, использующий команду "command". Однако если такие объекты создавать с помощью .Net или C++ (с использованием объектной модели), то в таких ситуациях объекты не будут переноситься на нужный слой (к сожалению). Для решения этой проблемы следует обрабатывать событие ObjectAppended класса Database - позже опубликую это решение (оно уже готово).

Comments