Monthly Archives: September 2014

MultiCAD.NET API: Saving non-graphical data in .dwg drawings

customProps_en

Sooner or later every CAD application developer has to solve the problem of saving auxiliary non-graphical data in .dwg drawings. It can be attributes for a single graphical entity or layout or settings for a whole drawing.  Unlike block attributes, this data is hidden from a user and used for programmatic processing of drawings.

There are a number of ways to solve the problem, for example, adding XData objects to drawing’s entities, using XRecords objects, or creating custom non-graphical objects.

In comparison with the traditional approaches, the mechanism provided by MultiCAD.NET API is much more compact and easy-to-use. It is also unified and can be applied in the same way for different object types in a drawing: entities, layouts or a whole drawing. Using this mechanism you are able to create and save auxiliary information of any data type.

Adding custom properties to graphical objects

You can work with object custom data, using the CustomProperties property. The property is available for all child classes of McPropertySource, particularly, for all graphical entities in a database (which are instances of the McDbEntity class). CustomProperties allows writing and reading data as key-value pairs:

Data of a simple type or array of simple types can be used as a property value. However, in practice, you can add values of any type by serializing data to an array of bytes. The code below shows the example of writing a dictionary object as a value of the MyCustomProperty property:

Reading of “complex” data is also divided in two steps: reading a byte array and its subsequent deserialization. Note, that CustomProperties gets array as a List object:

Let’s look at how the method works for a real case. Assume that there is a .dwg-file with a power supply scheme where hot and cold water pipes are represented by polylines. We are going to add a description for lines selected by a user. The description contains the information about pipe type and its diameter:

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

Create a command that allows the user to select a polyline and then adds the key-value pairs to the selected one:

For all McPropertySource descendant classes you can also get properties of specific type (Custom, Object, User etc.) by using the GetProperties() method. The following command gets a complete list of custom properties for user selected entity and prints their names:

Adding non-graphical data to a document

The MultiCAD.NET API allows saving non-graphical data not only for entities, but also for the entire document, layouts and blocks (subdocuments). The McDocument class inherits the functionality of the base McPropertySource class and therefore you can use the same CustomProperties property to add your custom data to documents of different levels:

Let’s look at how it works. In one of the previous posts we talked about creating custom entities in MultiCAD.NET and dealt with the TextInBox entity that is a framed text string:

TextInBox_01_en
Applying custom properties to a document object, you can define its additional parameters and settings. For example, you can add properties that set colors of a frame and text string for all TextInBox entities present in the current drawing:

Overwrite the OnDraw() method from the example that is responsible for drawing an entity so that the element’s color is derived from the document custom properties:

Now all added TextInBox entities are drawn in compliance with the document’s properties.

Importing coordinates from a text file to a nanoCAD drawing using the MultiCAD.NET API

importcoords_02_en

In the previous post we talked about importing point coordinates from an external text file into a .dwg drawing using classic .NET API. This post is going to describe how easy this problem can be solved using the cross-platform MultiCAD API. Here you will find the specifics of building MultiCAD application and the simple steps to launch it in nanoCAD and AutoCAD without changing project settings and rebuilding.

Creating working project

The project should be created in MS Visual Studio in the same way as it was done for the previous example:

  • Project type: Visual C#
  • Template: Class Library

To set up the project you only need to add a reference to the mapimgd.dll library that is included in the nanoCAD SDK (starting from version 4.0). The project configuration remains the same for applications that run in nanoCAD as well as in other supported CAD programs, particularly in AutoCAD. This compares to the previous project that contains two configurations — Debug NCAD and Debug ACAD. This project will use the only Debug MultiCAD configuration for all cases.

Importing coordinates and adding point entities to the drawing’s database

The structure and common code for creating application form, preview organization, and importing text data from a file remains the same. Implementation of the Importer and Creator classes was dependent on the specific host program, so they will be rewritten to be platform-independent. For example, the Creator.createPoints() method, which creates point entities by the input array of coordinates, will look as follows:

Let’s recall how the point creating procedure looks in the previous example using classic .NET API:

You can see that the number of code lines required for implementing this method has been decreased significantly. With MultiCAD.NET creating point objects, setting their coordinates and adding them to the database requires only three code lines! This is an extra advantage in addition to cross-platform support, using the API you can make application code more compact. This is carried out by “embedding” auxiliary operations into the main functionality.

Let’s look briefly at point adding procedure (a full overview will be the subject of future posts). There are three levels of geometry for entities in the MultiCAD.NET API:

  1. level of clear “math” geometry,
  2. level of geometry with primitives properties: color, linetype, lineweight etc. and
  3. level of database object.

Here we have created a DbPoint object, set its position and used the DbEntity property to move to the database level and add the point entity to the drawing’s database. Note, there is no need to determine which working space is current, the AddToCurrentDocument() method automatically finds the active document and adds an entity to currently used space.

Loading application to nanoCAD and AutoCAD

After the code is built and an application .NET assembly is generated you can load it and run in the supported CAD-programs.

  • Loading applications to nanoCAD is performed by the standard NETLOAD and APPLOAD commands.
  • To load applications to other systems, the special application called Object Enabler should be used. For example, to load an application to AutoCAD, MultiCAD Enabler for AutoCAD should be loaded first, and then use the NETLOAD command for loading your application. This standard MultiCAD Enabler for AutoCAD can be downloaded from the nanoCAD Developers’ Club.

Source code of the project is available here.

Importing coordinates from a text file to a nanoCAD drawing using the classic .NET API

importcoords_en

One of the popular questions concerning writing programs for nanoCAD is the question “how to import points from a text file to nanoCAD?”. This programming problem isn’t difficult for software developers but it can be a struggle for design engineers. That’s why we decided to write this post for beginners who are doing the first steps into the nanoCAD programming world.

Importing point coordinates to a drawing can be done using any type of nanoCAD APIs. We’ve decided to choose the .NET APIs and compare both of them; the classic .NET API and cross-CAD-platform MultiCAD.NET API. This post is the first part of this comparison that describes the point import process with the classic .NET API.

Given: a text file that contains point x-, y-, z-coordinates, one point per line. Coordinates are delimited by spaces, and a period (.) is used as a decimal point.

Required: an application with the IMPORTCOORDS command that prompts the user for a filename, imports coordinates from an input file and creates DatabaseServices.DBPoint objects in current drawing space. Point coordinates must be converted into the current user coordinate system (UCS).

Creating and setting working project

The following tools are required for developing the application:

  • nanoCAD (version 3.5 and later),
  • Microsoft Visual Studio 2008 (nanoCAD 3.5 — nanoCAD 5.0 supports loading .NET application built with .NET Framework 3.5).

It is assumed that you have a little programming experience and you are slightly familiar with C# language. If not — you are welcome to the library.

Let’s start with creating a new Visual Studio project with the following options:

  • Project type: Visual C#
  • Template: Class Library

The application that can be loaded and run in nanoCAD is a common .NET assembly (DLL). That’s why we use this template.

In the Reference tab add the following DLLs from the nanoCAD SDK:

  • hostdbmgd.dll
  • hostmgd.dll

Now all preparations are complete and we are ready to get into code writing.

Code structure

The implementation can be divided into the following steps:

  1. Register the IMPORTCOORDS command.
  2. Get the database and command line editor of the current drawing.
  3. Prompt the name of the file that contains point coordinates.
  4. Open the file and read lines with coordinates.
  5. Create DBPoint objects by the given coordinates. Transform objects coordinates from the world coordinates system (WCS) to the current user-defined coordinate system (UCS).
  6. Add created objects to current drawing space: model space or paper space.

To register the command that runs the application in nanoCAD, use the CommandMethod attribute with a name of the command before defining the method that is to be invoked by this command. Note, that the command method must be a public method:

Before we proceed with the code, let’s discuss briefly what the “database of drawing” is. Internally, .dwg file is a database with the strict hierarchical structure, where the main container objects are so called Symbol Tables that hold all database objects. It’s not only graphical objects that you can see on the drawing (lines, arcs, points, etc.), but also non-graphical objects that define contents and settings of the drawing. For example, the Layer Table contains all drawing’s layers, the Linetype Table stores all line types defined in the drawing, the UCS Table is the container for all user defined coordinate systems for this drawing and so on. Thus “to create a new object in the drawing” means to create proper database object.

At the first step we need to determine from all opened drawings the active one and obtain its database. For this purpose we will get the manager for all opened documents and then use it for getting the drawing database.

To prompt for a file, get the Editor object and call the method that gets the user input result of a specific type (file name in our case):

It’s quite easy to parse the result and get coordinates by using the C# toolsets for reading text files and processing string data:

Now we are moving to creation of graphic primitives (entities). As mentioned above, to create an object (any object, not only graphical) in the drawing, this object must be added to the drawing’s database, into a proper container object. For example, all layers are stored as records in the Layer Table. The following image illustrates the general structure of a database:

database

As for graphic primitives, they exist in a database only within separate blocks which are stored as records in the Block Table. Such an approach is an efficient way to group a number of objects to named blocks and manipulate them as single units. In other words a container object for an entity is a separate Block Table record that belongs to its parent object — the Block Table. Note also model space and paper space in the drawing are also represented by specific blocks.

Since we process the database we need to talk about data integrity. We must guarantee that its structure won’t be damaged if something goes wrong during the runtime. For security purposes the transaction mechanism is used. A transaction encapsulates a number of operations and can be treated as an entire operation. If something goes wrong then the transaction is cancelled and all the objects that have been created within the transaction will not be added to the document. If all operations inside the transaction are completely done, the transaction is committed and all objects are added to the database.

Now with this knowledge base you are able to create point entities by coordinates derived from the file and add them to the current drawing space.

The job is already done. The only condition needing to be satisfied: point coordinates must be imported to the current user-defined coordinate system (UCS). It is important to note that all entities are created and stored in a database with WCS-coordinates. So now we need to transform coordinates from the current UCS to the WCS. To perform such transformation, the UCS matrix is used as a transformation matrix:

Now the application code is done. What is next?

Loading the application to nanoCAD

It’s time to talk about how to load the application to nanoCAD. We’ve created a working project with DLL type of generated output, therefore after compiling is completed you will get the .NET assembly with the name of the project. Open nanoCAD, input the NETLOAD command and choose the generated library. Note that unlike AutoCAD, nanoCAD uses the APPLOAD command for loading applications of different types including .NET. After the DLL is successfully loaded, run the IMPORTCOORDS command to launch the application.

Importing coordinates. Version 2.0

Let’s improve the application by adding useful functionality and GUI elements.

Whereas the first version can recognize coordinates delimited by spaces (with a period as a decimal point), the second version will be able to import coordinates delimited by one of the following symbols:

  • tab,
  • space,
  • semicolon.

As for a decimal point, a comma or a period can be used; coordinates will be imported in a culture-insensitive manner. The IMPORTCOORDS command will open a modal dialog so that the user can choose the input file and proper import settings.

The import mechanism needs to be only slightly changed. However, now it should be encapsulated by the form class, and the IMPORTCOORDS handler method will be used just for creating a form object and showing it as a modal dialog:

Application form

The application form contains the following controls:

  • an open file button,
  • an open file dialog,
  • a check boxes group for choosing delimiters: tab, space, semicolon,
  • a group of radio buttons for choosing decimal separator: comma or period,
  • a text field for result preview,
  • import button,
  • cancel button.

With these controls the user is able to set all required import settings, preview import result and run coordinate import process.

ImportForm_02

Both project versions are available here.

Compatibility with AutoCAD

An application developed for nanoCAD can be easily recompiled for running in AutoCAD as well. The following steps are required:

  • Add references for the ObjectARX libraries:
    • AcDbMgd.dll
    • AcMgd.dll
  • Add the following preprocessor directives for conditional compilation:
  • Replace namespaces in the code with the proper alias defined above: Platform and PlatformDb.
  • Use the #define ACAD directive to define AutoCAD as a target platform, nanoCAD is defined by default.