📜 ⬆️ ⬇️

MultiCAD.NET API: Saving non-graphic information in .dwg-drawings

image

Each CAD application developer sooner or later faces the problem of storing non-graphic information in the drawing. These can be attributes of individual graphic elements, attributes of individual sheets, or settings for the entire drawing. Unlike block attributes, this information is not visible to the user and is used for software processing of drawings.

Today, there are a number of traditional ways to solve the problem: this is adding XData to drawing elements, using XRecord and creating your own non-graphic objects.
')
Compared to traditional ones, the mechanism for creating and storing non-graphic information in the MultiCAD.NET API is much more compact and easier to use. In addition, it is universal and can be equally applied to different types of data in a drawing: graphic elements, sheets, or the drawing itself. As additional information data of various types can be used.

How it works and how it is applied in practice, see under the cut.


Adding custom properties to graphic objects


To work with own data of objects, the CustomProperties property is CustomProperties , which is available for all descendants of the McPropertySource class, which, in particular, are all graphic primitives in the database (instances of the McDbEntity class). The property allows you to add and read data in the form of key-value pairs:

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

As property values, simple types can be used, as well as arrays of simple types. In practice, you can add properties of any type using object serialization to write data to a byte array. The following example shows an example of saving a data dictionary as the value of the MyCustomProperty property:

 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; 

Reading "complex" data also occurs in two stages: obtaining a byte array and further deserialization. CustomProperties always returns the contents of the arrays in the List view:

 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; } 

Consider the application of this method on a specific example. Let the .dwg file contain a water supply scheme, where hot and cold water pipelines are represented using polylines. Add a description to the individual polylines, which will contain information about the purpose of the pipeline and the diameter of the pipe:

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

Let's register a command that will make a user choice of a polyline object and add a key / value pair to it:

 [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"); } } 

Also, for all descendants of the McPropertySource class, McPropertySource can get all the available properties of a particular type (Custom, Object, User, etc.) using the GetProperties() method. The following command gets a list of all custom-properties for the selected primitive in the drawing and displays their names on the screen.

 [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"); } 

Saving non-graphic information for a document


MultiCAD.NET allows you to store non-graphical information not only for primitives, but also for the entire document and individual sheets and blocks (subdocuments). The McDocument class also inherits the functionality of McPropertySource , and therefore, you can use the same CustomProperties property to set your own data for documents at various levels:

 [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"; } 

Let's see how this works on a specific example. In one of the previous articles, we talked about creating custom primitives using MultiCAD.NET and dealt with the TextInBox primitive, which is a text in a rectangular frame:

image

Using your own document properties, you can set the parameters and settings for this document. For example, in this case, the color settings for the frame and the text string for all TextInBox primitives present in the current document:

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

Let's rewrite the OnDraw() function from the example , which is responsible for drawing the user primitive, so that the color of the elements is read from the specified properties of the document:

 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); } 

Thus, all TextInBox primitives added are mapped to the specified properties of the current document.

Discussion of the article is also available on our forum: forum.nanocad.ru/index.php?showtopic=6517 .
Translation of the article into English: MultiCAD.NET API: Saving non-graphical data in .dwg drawings .

Source: https://habr.com/ru/post/226563/


All Articles