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

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

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

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

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

Добавление собственных свойств графическим объектамДля работы с собственными данными объектов используется свойство CustomProperties, доступное для всех потомков класса McPropertySource, которыми, в частности, являются все графические примитивы в базе данных (экземпляры класса McDbEntity). Свойство позволяет добавлять и читать данные в виде пар ключ-значение: entity.DbEntity.CustomProperties[«Property»] = Value; В качестве значений свойств могут использоваться простые типы, а также массивы простых типов. На практике можно добавлять свойства любых типов, используя сериализацию объектов для записи данных в байтовый массив. Следующий пример демонстрирует пример сохранения словаря данных в качестве значения собственного свойства MyCustomProperty: MemoryStream ms = new MemoryStream (); BinaryFormatter formatter = new BinaryFormatter (); Dictionary MyOptions = new Dictionary(); 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 loadedBinary = entity.DbEntity.CustomProperties[«MyCustomProperty »] as List; if (loadedBinary!= null) { ms = new MemoryStream (loadedBinary.ToArray ()); formatter = new BinaryFormatter (); MyOptions = formatter.Deserialize (ms) as Dictionary; 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 customPropertyNames = new List(); 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 отображаются в соответствие с заданными свойствами текущего документа.

© Habrahabr.ru