Сохранение неграфической информации в .dwg-чертежах

в 12:28, , рубрики: .net, api, CAD/CAM, multicad, Блог компании Нанософт, метки: , ,

image

Каждый разработчик приложений САПР рано или поздно сталкивается с проблемой хранения в чертеже вспомогательной неграфической информации. Это могут быть атрибуты отдельных графических элементов, атрибуты отдельных листов, или же настройки всего чертежа. В отличие от атрибутов блока, эта информация не видна пользователю и применяется для программной обработки чертежей.

На сегодняшний день существует ряд традиционных способов решения задачи: это добавление XData к элементам чертежа, использование XRecord и создание собственных неграфических объектов.

По сравнению с традиционными, механизм создания и хранения неграфической информации в MultiCAD.NET API гораздо компактней и удобней в использовании. Кроме того, он универсален и может быть одинаково применен для различных типов данных в чертеже: графических элементов, листов или самого чертежа. В качестве дополнительной информации могут использоваться данные различных типов.

Как это работает и как применяется на практике, смотрите под катом.

Добавление собственных свойств графическим объектам

Для работы с собственными данными объектов используется свойство CustomProperties, доступное для всех потомков класса McPropertySource, которыми, в частности, являются все графические примитивы в базе данных (экземпляры класса McDbEntity). Свойство позволяет добавлять и читать данные в виде пар ключ-значение:

entity.DbEntity.CustomProperties["Property"] = Value;

В качестве значений свойств могут использоваться простые типы, а также массивы простых типов. На практике можно добавлять свойства любых типов, используя сериализацию объектов для записи данных в байтовый массив. Следующий пример демонстрирует пример сохранения словаря данных в качестве значения собственного свойства MyCustomProperty:

MemoryStream ms = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
Dictionary<String, Object> MyOptions = new Dictionary<String, Object>();
MyOptions.Add("param1", 10);
MyOptions.Add("param2", "Value");
try
{
  formatter.Serialize(ms, MyOptions);
}
catch (SerializationException e)
{
  Console.WriteLine("Failed to serialize. Reason: " + e.Message);
}
Byte[] binary = ms.GetBuffer();
entity.DbEntity.CustomProperties["MyCustomProperty"] = binary;

Чтение «сложных» данных происходит также в два этапа: получение байтового массива и дальнейшая десериализация. CustomProperties всегда возвращает содержимое массивов в виде List:

List<Byte> loadedBinary = entity.DbEntity.CustomProperties["MyCustomProperty "] as List<Byte>;
if (loadedBinary != null)
{
  ms = new MemoryStream(loadedBinary.ToArray());
  formatter = new BinaryFormatter();
  MyOptions = formatter.Deserialize(ms) as Dictionary<String, Object>;
  int val = (int)MyOptions["param1"];
  String str = MyOptions["param2"] as String;
} 

Рассмотрим применение данного метода на конкретном примере. Пусть .dwg-файл содержит схему водоснабжения, где трубопроводы горячей и холодной воды представлены с помощью полилиний. Добавим к отдельным полилиниям описание, которое будет содержать информацию о назначении трубопровода и диаметр трубы:

[Pipe type] = Cold Water
[Pipe diameter] = 20

Зарегистрируем команду, которая будет осуществлять пользовательский выбор объекта полилинии и добавление к нему пары ключ/значение:

[CommandMethod("WriteCustomProperties", CommandFlags.NoCheck | CommandFlags.NoPrefix)]
static public void writeCold50()
{
  McObjectId objId = McObjectManager.SelectObject("Select a polyline entity to write additional data to: ");
  if (objId.GetObject().IsKindOf(DbPolyline.TypeID))
  {
    McEntity ent = objId.GetObject();
    ent.DbEntity.CustomProperties["Pipe type"] = "Cold water";
    ent.DbEntity.CustomProperties["Pipe diameter"] = 50.0;        
  }
  else
  {
    MessageBox.Show("No polyline entity selected");
  }
}

Также, для всех потомков класса McPropertySource можно получить все доступные свойства определенного типа (Custom, Object, User и др.), используя метод GetProperties(). Следующая команда получает список всех custom-свойств для выбранного на чертеже примитива и выводит их названия на экран.

[CommandMethod("GetCustomProperties", CommandFlags.NoCheck | CommandFlags.NoPrefix)]
static public void getCustomProperties()
  {
    McObjectId objId = McObjectManager.SelectObject("Select an entity to get its custom property list: ");
    if (objId.IsNull)
    {
      MessageBox.Show("No entity selected");
      return;
    }
      
    String propertyString = null;
    List<McProperty> customPropertyNames = new List<McProperty>();
    McEntity ent = objId.GetObject();
    customPropertyNames = ent.DbEntity.GetProperties(McProperties.PropertyType.Custom).GetProps();
    foreach (McProperty property in customPropertyNames)
    {
      propertyString = propertyString + property.Name + ";n";
    }
    
   MessageBox.Show(propertyString, "Custom property list");
 }

Сохранение неграфической информации для документа

MultiCAD.NET позволяет хранить неграфическую информацию не только для примитивов, но также для всего документа и отдельных листов и блоков (поддокументов). Класс McDocument также наследует функциональность McPropertySource, а следовательно, можно использовать все то же свойство CustomProperties для задания собственных данных для документов различного уровня:

[CommandMethod("WriteCustomPropertiesToDoc", CommandFlags.NoCheck | CommandFlags.NoPrefix)]
static public void writeCustomPropertiesToDoc()
{
  McDocument currentLayout = McDocumentsManager.GetActiveSheet();
  currentLayout.CustomProperties["Layout Property 1"] = "Value";
  
  McDocument currentDocument = McDocumentsManager.GetActiveDoc();
  currentDocument.CustomProperties["Document Property 1"] = "Value";
}

Посмотрим, как это работает на конкретном примере. В одной из прошлых статей мы рассказывали о создании пользовательских примитивов с помощью MultiCAD.NET и имели дело с примитивом TextInBox, представляющий собой текст в прямоугольной рамке:

image

Используя собственные свойства документа, можно задать параметры и настройки этого документа. Например, в данном случае, установки цвета для рамки и текстовой строки для всех примитивов TextInBox, присутствующих в текущем документе:

McDocument currentDocument = McDocumentsManager.GetActiveDoc();
currentDocument.CustomProperties["BoxColor"] = "Blue";
currentDocument.CustomProperties["TextColor"] = "Green";

Перепишем функцию OnDraw() из примера, отвечающую за рисование пользовательского примитива, таким образом, чтобы цвет элементов читался из установленных свойств документа:

public override void OnDraw(GeometryBuilder dc)
{
  dc.Clear();
  dc.Color = Color.FromName(currentDocument.CustomProperties["BoxColor"] as String);
  dc.DrawPolyline(new Point3d[] { _pnt1, new Point3d(_pnt.X, _pnt2.Y, 0), 
                                  _pnt2, new Point3d(_pnt2.X, _pnt.Y, 0), 
                                  _pnt1});
  dc.TextHeight = 2.5 * DbEntity.Scale;	
  dc.Color = Color.FromName(currentDocument.CustomProperties["TextColor"] as String);
  dc.DrawMText(new Point3d((_pnt2.X + _pnt.X) / 2.0, (_pnt2.Y + _pnt.Y) / 2.0, 0), 
               Vector3d.XAxis, Text, HorizTextAlign.Center, VertTextAlign.Center);
}

Таким образом, все добавляемые примитивы TextInBox отображаются в соответствие с заданными свойствами текущего документа.

Автор: ISL

Источник

Поделиться

* - обязательные к заполнению поля