MultiCAD.NET API: Inserting blocks with block attributes

In this post we will talk about inserting blocks using MultiCAD.NET API – one of the most frequently asked questions on our forum.

Let us assume there is a drawing that has block definitions for inserting water supply elements, for example, the blocks that represent valves of different types.

01

Each block definition contains two attributes for providing some extra information about elements.

  • NAME – the element’s name (for example, “Ball”),
  • LABEL – the element’s label (for example, “PC585-70”).

To represent block inserts in the drawing, MiltiCAD.NET provides the McBlockRef class. All you need to do is to create an insert object and assign the name of the block to the BlockName field.

In MultiCAD.NET, block attributes are stored as common object properties. Therefore in order to insert a block with desired attributes values; it takes only getting an access to them using DbEntity.ObjectProperties:

The McDocument class has a method that displays a dialog with a list of all existing block definitions for choosing a block to insert.

02_en

The command below inserts the selected block with given attributes values to the drawing. To input values, the command line is used.

 

Porting C++ applications to nanoCAD: using project property pages

title

In one of the previous articles we wrote about porting ObjectARX applications to nanoCAD. In this article we will introduce a more comfortable and simple way to do this: using project property pages.

Let us remind that to build an NRX application having an existing ObjectARX application, a new project configuration should be created, from scratch or by copying an existing configuration, and then headers and libraries paths, and conditional compilation constants should be set. The complete procedure is described in the nanoCAD SDK.

In this article we describe the tips that are not in the developer documentation yet. With pre-configured property pages, the minimal number of changes in the project is needed to build the application for both nanoCAD and AutoCAD, and source files, .h, and .cpp files will remain unchanged.

Let’s start with an environment variable that points to the location of the nanoCAD SDK. The variable can be system-wide, or it can be set in the .bat file before starting the Visual Studio 2008.

StartVS90_NCadSDK.bat:

Since the project is opened in Visual Studio, create a new configuration of the project. Configurations can be created from scratch or copied from an existing one. For example, the Release configuration can be copied to the new Release NCAD configuration.
01
In order to go without manual configuring the compiler and linker settings, connect the property page from the .vsprops file which already contains all necessary settings. Property pages are added in the Property Manager window (View -> Property manager).
02

The SDK includes property pages for debug and release configurations:

  • rxsdk_debugcfg.vsprops – properties for the debug configuration of the project;
  • rxsdk_releasecfg.vsprops – configuration properties for the release version of the project;

They are located in the directory <ncadsdk_path>\include\arxgate. In order to ensure the maximum compatibility, the property page and header files in the arxgate directory have the same names as the similar files in the ObjectARX.
After the property page is added to the configuration the inherited settings appear in the project:

 

03

04
That’s all you need to do to port a simple application. The built NRX module is loaded into nanoCAD by the APPLOAD command. To automatically load the application, you can add it to the “Startup Suite”, which is located in the same place, in the APPLOAD command dialog window.

06_en

MultiCAD.NET: Calculating the total length of lines

mainPicture

One of the frequently asked questions to our technical support is “How to calculate the sum of line lengths (pipeline sections, elements of wire diagram etc.) in a drawing?” There are many ways to solve this problem, and today we will consider an implementation of the MultiCAD.NET application that sums line lengths in nanoCAD, AutoCAD and ZWCAD. As an example we will calculate the sum of pipe lengths in the water supply scheme with two options to select elements for calculating: user selection and selection by the object filter.

Calculating the length of lines selected by user

Before we set to work, we need to know what a line in MultiCAD.NET is. The line is a standard primitive like circle, text, spline etc. To represent a line within the drawing database, the DbLine class from the Multicad.DatabaseServices.StandardObjects namespace is used.
A DbLine object has properties that store the first and second points of the line but does not contain the length information. Surely, we could calculate the length by the points coordinates, however it is more efficient to access the line’s geometric representation. The geometry data is stored in the LineSeg3d class object that can be accessed through the DbLine.Line property and has the Length property to get the length:

Now let’s consider the first option when the user selects a number of lines for calculating the total length. To provide the user with an ability to select objects the SelectObjects method of the McObjectManager class is used:

The method prompts the user to select entities on the drawing and writes the IDs of selected objects into the array. But we need to make sure the user has selected only entities of desired type. That is why we filter out only IDs that belong to DbLine entities from the set, then get length of each of them and increment the result. Below is the command that implements this procedure:

The same approach works also for polylines that consists of one or more line (or arc) segments. The length of a polyline can be derived similarly to a line by using the geometrical representation class Polyline3d that can be accessed for every DbPolyline object through the Polyline property:

Automatic calculation of the total lines length

When the drawing contains many elements, it makes sense to select object automatically to avoid user input errors. For this purpose an object filter is used. It selects objects that obey the filter criteria: search area (sheets, layers, documents, regions) and object types.
For example, to filter all lines on the specific layer, the filter with specified layer name is used:

In practice automatic line length calculation is applied commonly for creating a report with a list of pipe types on a water supply scheme. Here is the example scheme:

pipeline_en

In our example there are two types of water pipes: of PVC and stainless steel. Each type is drawn with lines or polylines on a separate layer: Circuit1 or Circuit2.
The command below creates a text report with listing layer names and total pipe lengths for each of them.

Calculation of the total line lengths and filling up the report are performed in the getLengthSumByLayer() method:

As the result of command execution the following report will be added on the drawing:

pipeline_report_en

The step-by-step guidance of how to load MultiCAD.NET applications you can find in the post MultiCAD Enabler for AutoCAD and ZWCAD.

Smart grips of custom object in MultiCAD.NET

smartGrips_withframe

When it comes to creating or modifying objects in a drawing, usability becomes a key characteristic for CAD software.  One of the essential features for efficient manipulating and modifying graphic objects is grips. Grips are markers in the key object points that allow the user to modify an object by mouse and without using the menu or command line.

While embedded CAD primitives are already supplied with grips, custom objects must implement this feature by themselves. The post is intended to describe how to create grips for custom objects using MultiCAD.NET.

The grip management mechanism in MultiCAD.NET permits the user to work with grips of simple and smart types. We have already talked about simple grips in the previous post and in this post will discuss how to work with smart grips. Unlike simple grips, smart grips can have different shapes (circle, triangle, rhombus etc), change specific object parameters, display pop-up menu or perform a set of actions defined in the handler. The smart grips API uses a new unified approach that makes it possible to create simple grips as well.

McSmartGrip class

For representing smart grips in the MultiCAD.NET API the McSmartGrip<T> class is used. This class contains different constructor signatures and handlers of events that are generated by user actions:

  • MoveGrip — used when a grip has been moved,
  • MouseMove — used when a grip of interactive type has been moved,
  • GetContextMenu — used when a grip of the GripType.PopupMenu type has been clicked,
  • OnCommand — used when a grip of the GripType.Button type has been clicked or when a context menu item has been chosen.

For example, to create a simple grip that moves the object, the following constructor can be used:

This constructor takes a MoveGrip delegate as a parameter. In this example we have used a lambda expression (http://msdn.microsoft.com/en-us/library/bb397687.aspx) to implement MoveGrip that just moves the object position by the offset value.

Adding grips

For adding grips to a custom object, the AppendGrip()of the GripPointsInfo class is used:

The GripPointsInfo class is used as the parameter of the GetGripPoints() method which is used for getting grips whenever the object is drawn:

The following code creates and adds the same simple grip:

As you can see the procedure is very compact and requires only one code line. This was the simplest case of grips – simple grips. Let’s see what grip types are supported in the MultiCAD.NET API and discuss specifics of each of them.

Grip types

With MulitiCAD.NET you are able to create grips of the following types:

  • Simple — simple grip. Grip movements are handled in MoveGrip.
  • PopupMenu — grip that displays a popup menu. Handling is performed by OnCommand.
  • Button — grip that represents a button. Actions that can be called by pressing the button are defined in OnCommand.
  • Interactive — the grip type that is similar to Simple, but can be used with object snaps. Unlike Simple grip, Interactive grip uses MouseMove for handling grip movements.

Grip Appearance

One custom object can have grips of different types, in order to distinguish all of them, you can set the specific appearance to each one defining grip shape and color.
Variety of grip shapes are defined by the McBaseGrip.GripAppearance enumeration. Here are some  available shapes:

gripTypes

You can also set the desired grip color from the color set defined in the GripColors class or using standard  System.Drawing.Color.
Let’s look how it works on practice and create several  smart grips of different types for the TextInBox primitive that was described in the previous post.

Simple grip

We have already mentioned this grip type above, and as follows from the name it is used for simple action such as moving points of the object. The code below adds a simple grip for moving a corner point of the entity:

The following picture demonstrates how this grip works:

01

Button grip

Now we will add a button grip that will control displaying the frame around the text. To create the button, we use the constructor signature that takes the grip type (McBaseGrip.GripType.Button) and the color (GripColors.Base ) of the grip as parameters.  If the button is pressed, the handler OnCommand will change the state of the _show_frame indicator to opposite and the button appearance will be changed from the “On” state to “Off” or vice versa. We will set the “On” appearance by default.

Also a registered command can be called as a reaction to button pressing:

02

Menu grip

One more grip type that can be created in MultiCAD.NET is a grip for displaying a context menu. This type is used for example, when the user needs to choose a desired value from the list of object parameters. A menu grip can be created by the grip constructor with passing the McBaseGrip.GripType.PopupMenu grip type and the McBaseGrip.GripAppearance.PopupMenu grip appearance as parameters. To enable the menu, the following delegates should be implemented:

  • GetContextMenu — displays the menu if the grip is clicked,
  • OnCommand — handles selecting menu items.

The following code creates a menu grip that enables a context menu with one item:

03

Interactive grip

And the last grip type in our overview is an interactive grip. The main specific of this grip is that it can use the information about the objects which the grip is snapped to and change its behavior depending on this information.

For example, we will add one interactive grip that can replace the text of our TextInBox primitive with the name of a selected object. Depending on the object type, the grip will change its color: default color will be GripColors.Base, if the grip snaps to the parent object the color will be changed to Color.Red, and if it snaps to any other object that supports snap the color will become Color.Green.

An interactive grip can be created using a grip constructor with passing the McBaseGrip.GripType.Interactive grip type. Handling of grip movement is implemented in the  MouseMove delegate (unlike simple grip, that uses MoveGrip).

Below is the illustration of how this grip works, the «Text field» string is replaced with «MultiCAD.Samples.TextInBox»:

04

So, we have overviewed the basic types of smart grips, that allow development of an efficient and usable interface for working with custom objects created in MultiCAD.NET. The API documentation set is delivered with the nanoCAD SDK which is available in the nanoCAD Developer’s Club (registration is required).

Managing serialization of custom objects in MultiCAD.NET

serialization

In the previous post we discussed the approach used for serializing custom objects in the MultiCAD.NET API. We talked about concepts of using that approach for providing object version compatibility and considered the simplest case when a new version of an object is derived from a previous one by adding additional fields of data. Today we are going to discuss the case of deep changes of the object’s structure such as removing, renaming  or retyping fields.

Assume that a new version of the object has renamed some fields and changed their types. Let’s take, for example, the CrossMark object that is already familiar to us from the previous post:

CrossMark entity

CrossMark entity

The object of the previous version had the following structure:

Let’s assume that  in the new version the corner points are required to be defined by vectors (instead of 3d-points), and the radius field remains unchanged:

Obviously objects of the new version will not be compatible with older objects after such changes.

In order to allow the new version to be able to recognize the older ones, it is required to implement the mechanism for reading desired fields and converting the old data format to the new one. To solve this problem with MultiCAD.NET, the standard ISerializable interface can be used .

The interface allows an object to control its own serialization and deserialization and requires an implementation of two methods:

  • public void GetObjectData(SerializationInfo info, StreamingContext context) — used to serialize the target object,
  • public CrossMark(SerializationInfo info, StreamingContext ctx) — the special constructor used to deserialize values.

In our case the methods should be as follows:

 

So, now the object has two constructors: one (the default) is used for creating and inserting the object into the drawing, and another – when the object is being read (deserialized) from the drawing.
The deserialization process has been divided into two parts: data from the object of the current version is read regularly, while the data of the previous version is read and converted to the current format inside the catch block for handling SerializationException. This exception will be thrown when the application tries to deserialize the nonexistent fields from the previous version.
If you plan to continue developing new versions of the object, then you can also serialize the version number to a new special field and customize the deserialization process depending on this value:

So we’ve discussed the basic cases of custom object serialization with different types of changes in their structure while moving from one version to another. Using the described approaches, you are able to provide your application with a flexible mechanism for managing objects version compatibility.
Serialization questions are very popular, that is why we will soon continue talking about the implementation of this mechanism in MultiCAD.NET and publish some posts regarding the subject. For example, we will discuss the problem of object data exchange between applications by serializing data to external databases and answer other frequently asked questions.

Serializing objects in MultiCAD.NET. Managing drawings compatibility and proxy objects

serialization_04

Creating custom objects using a traditional C++ API (NRX in NanoCAD and ObjectARX in AutoCAD) presupposes to implement serialization and deserialization processes of each field to allow objects to be writable and readable. The MultiCAD.NET API provides a simple and compact descriptive approach based on the standard .NET serialization that is more usual for .NET developers.

The version tolerance serialization features (VTS) provides developers with a mechanism for managing object versions compatibility which is more flexible than the traditional C++ API approach that allows reading of previous object versions (backward compatibility) but not reading files “from the future” (forward compatibility).

When newer object versions are being defined in MultiCAD.NET, newly created fields can be marked as optional fields so that the drawing saved in a new format version can be read in the previous version also. Of course, the API contains an ability to create proxy objects (cached graphics data of the objects) if the drawing is being loaded to the previous version of the application.

In this post we are going to discuss how to ensure compatibility of two object versions and how to provide the traditional level of compatibility when newer versions of the application can read older drawings but older versions are unable to read new drawings.

Let’s consider how MultiCAD.NET uses both these approaches (VTS and proxy objects mechanism) for providing the versions compatibility features. We will use two versions of the “cross mark” entity for demonstration:

serialization_05

The initial class version

The definition of the CrossMark entity class is listed below:

We are not going to focus on the basics of creating custom objects; it has already been discussed in the previous post. The entire code is available here. After the application is compiled and loaded, it can be launched by the “crossmark” command. The following entity will be added to the drawing:

serialization_02

Save the drawing. Now let’s change the class by adding an extra functionality to it.

The second version of the class and providing versions compatibility

We are going to change the entity’s geometry in the second version by adding a circle at the center of the cross mark. Add a field for the radius of the circle and use the [OptionalField] attribute to mark it as an optional field for correct deserialization of the previous version. Also specify the new version number in the VersionAdded property:

Set the proper value of the radius in the constructor and add a public property for accessing the field:

To initialize the radius field with the custom value after deserialization, the method OnDeserialized with the [OnDeserialized] attribute can be used:

In that way applications that work with new versions of object can also process objects of older versions. Also VTS solves the problem of forward compatibility, i.e. applications that work with old object versions are able to read new versions as well: fields marked as optional are ignored and the object is deserialized properly.
So, we have provided full compatibility between both versions of the CrossMark class. The only thing that should be done is to add a code for drawing the circle component to the OnDraw() method:

The full code of the second version of the application is also available in this archive. Compile the project, load the built assembly to nanoCAD and launch the application by the “crossmark” command. Since you specify the insertion point, the new version of the crossmark entity is drawn at this point:

serialization_03

Save the drawing with a new name.

Testing and results

We have two drawings with two versions of the entity. Let’s make sure that both versions are compatible.
Run nanoCAD, load the second version of the assembly and open the first file. The file is successfully opened and the primitive of the first version is displayed. Once object redrawing is called (for example while you are moving object) the object is redrawn in the new version with the circle component of the proper radius. Object redrawing can also be initialized by the REGENOBJ command.
Close the file. Load the first version of the assembly and open the second file. The file is also successfully opened and the primitive of the second version is displayed as it was originally saved in the drawing (with the circle component). After selecting the REGENOBJ command (or any user actions that cause updating) the cross mark geometry will be updated and displayed as it was defined in the first version.

The traditional approach. Proxy objects

The VTS mechanism, which allows forward compatibility, is not always applicable. For example, when not all data specific for new versions, can be considered as insignificant and you want to prevent changing new objects while opening in an older version of the application.
As mentioned above the class definition contains the [CustomEntity] attribute with a set of properties:

The majorVersion property defines the major version number within which the objects can be compatible. If new objects constructed with a majorVersion value, that is greater than the previous one, are being opened in the older application version, the eMakeMeProxy code is returned. In this case such objects will be displayed as proxy objects That precludes them from changing and being editable.
For example, the second version of the cross mark object should be defined with a majorVersion value equal 2:

Conclusion

In this post we have discussed an example of providing compatibility between two versions of the custom object in the simplest case when the new version is created from the previous one by adding new fields. In one of the future posts we will talk about managing compatibility in the case of deeper changes such as deleting, renaming object fields or changing their types.

MultiCAD Enabler for AutoCAD and ZWCAD

puzzles1

Applications developed with MultiCAD.NET are cross-CAD-platform and can be run in all supported CAD programs without recompiling.  The MultiCAD.NET API is built into nanoCAD and applications are loaded by the standard NETLOAD or APPLOAD commands. To run MultiCAD.NET applications in AutoCAD and ZWCAD the special application called MultiCAD Object Enabler is needed.

In this walkthrough we will load a MultiCAD.NET sample application into nanoCAD, AutoCAD, ZWCAD and edit the drawing created with the application in these three CAD platforms.

Loading a MultiCAD.NET application into nanoCAD

Let’s start with nanoCAD as the native platform for MultiCAD.NET to create the example drawing. You can use free nanoCAD 5.0 or paid nanoCAD Plus 6.0 in Demo mode, both can be downloaded from http://nanocad.com. As the sample application we will use the application that creates TextInBox custom entities described in this post.

  1. Download and unpack the TextInBoxSample.zip archive to the local drive.
  2. Be sure that the assembly file TextInBoxSample.dll is unblocked after downloading (right click the file -> Properties -> General -> Unblock).
  3. Load the TextInBoxSample.dll  into nanoCAD by the NETLOAD or APPLOAD command.
  4. Create a new drawing.
  5. Run the TextInBox command and create a TextInBox Entity.
  6. Save drawing to the TextInBox.dwg file.

TextInBox_NCAD

Loading the MultiCAD.NET application into AutoCAD

Now we are going to AutoCAD 2010-2014 (32- or 64-bit) to open and edit the drawing.

  1. Download and unpack the MultiCAD_Enabler_1603.zip archive with a set of MultiCAD object enablers.
  2. Load ALoader.arx (the enabler application for AutoCAD) from the corresponding subfolder using the AutoCAD APPLOAD command:
    • mg9/mg9x64 (for AutoCAD 2010-2012),
    • mg10/mg10x64 (for AutoCAD 2012-2014).
  3. NETLOAD TextInBoxSample.dll (please note that is the same binary .dll module for all CAD platforms, whether it is nanoCAD, AutoCAD, ZWCAD and it is 32- or 64-bit).
  4. Open drawing TextInBox.dwg.
  5. Select the entity and change its text string in the Properties window.

    TextInBox_ACAD_02

  6. Move and resize the created entity with grips.
  7. Save the drawing.

TextInBox_ACAD_01

Loading the MultiCAD.NET application into ZWCAD

Now we continue editing the drawing in ZWCAD 2014, build 2014.06.25(24082).

  1. APPLOAD ZLoader.arx (the enabler application for ZWCAD) from the mg10 subfolder.
  2. NETLOAD TextInBoxSample.dll.
  3. Open the TextInBox.dwg file.
  4. Run the TextInBox command and create a TextInBox Entity.
  5. Select the new entity and change its text in the Properties window.

    TextInBox_ZWCAD_01

  6. Save the drawing.

    TextInBox_ZWCAD_03

  7. Now we are back in nanoCAD (this time we will use nanoCAD x64 Plus 6 as the latest nanoCAD version).
  8. Start nanoCAD x64 Plus 6 in the demo mode and NETLOAD the TextInBoxSample.dll.
  9. Open the TextInBox.dwg and edit the entities.
  10. Run the TextInBoxEdit command, select entities and see that texts are updated. Actually the command change texts to “New text”, but for demonstrating we show you entities with other text string:

    TextInBox_NCAD_plus

As you see a MultiCAD.NET application can create a drawing populated with objects which can be opened, edited and saved by all supported CAD programs with providing full set of object functionality.

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.