VBA CATIA Part Design – Geometrical Sets

VBA CATIA Part Design – Geometrical Sets

In this post we will build up on what we did last time with the introduction to VBA for CATIA. If we go back to the Automation.chm document we can navigate to the PartDocument object. Within which we can start to create Parameters, Relations, Geometrical Sets, Wireframe and Solid objects.

Last time we created a macro to create a new Part Document, Product Document and Drawing Document. We can reuse this to create a New Part Document which is the first Object shown above.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  Dim ioDocuments as Documents
  Set ioDocuments = ioCATIA.Documents
  
  Dim ioPartDocument as PartDocument
  Set ioPartDocument = ioDocuments.Add("Part")
End Sub

As we can see from the documentation we need to step down to the Part object before we can really do anything.

So just as before we need to Declare a space in memory with the correct Type in this case is Part. Then equate the space in memory to the Part object.

Dim ioPart As Part
Set ioPart = ioPartDocument.Part

Now we can have some fun…

Creating a New Geometrical Set

If we look in the documentation again we can find an object called HybidBodies, this has a plural name and is Yellow. This indicates that its a collection Object. All Collection Objects have an Add methos to add additional objects tot hat collection. If we don’t know what methods and property’s an object has all we have to do is select that object in the Automation.chm.

Here we can see that there are two Methods and no Property’s. There is an Add method and an Item method used to retrieve an object from the collection. Lets Start with the Add method.

The Add method is a Function meaning that it returns something unlike a subroutine which just does something. In the methods signature it shows after the parenthesis () As HybridBody. This means that the Add Method (Function) when called returns a HybridBody object.

Just as before we must create a space in memory for the HybridBodies (Geometrical Sets) Collection, as well as the new Hybridybody (Geometrical Set). Unlike before where we essentially walked down the object hierarchy, we don’t have a geometrical set to navigate to so we will use the Add() method to create a new Geometrical Set .

  Dim ioHybridBodies As HybridBodies
  Set ioHybridBodies = ioPart.HybridBodies
  
  Dim ioHybridBody as HybridBody
  Set ioHybridBody = ioHybridBodies.Add()

Now that we have a new geometrical set we can change its name again in the documentation we can see the Property’s and Methods for the HbyridyBody object.

In the Property’s for HybridBody we don’t see anything to do with Name. This is because the Name Property is inherited from a higher level object called AnyObject. The inheritance structure is shown at the top of the page. and everything originates from an object called IUnknown.

If we click on System.AnyObject we can now see the Name property.

Just like navigating the object structure we just need to use a period at the end of the Object to use the Name property. Since its a Property we need to equate the Name property to a value. If we click on the Name property to view the write up, we can see that its a CATBSTR otherwise known as a String Property and in programming when ever we deal with a String it must be enclosed in double quotes “” so that the compiler knows its a String an not some weird request.

ioHybridBody.Name = "My New Geometrical Set 12"

Import Geometrical Sets From a Text File

So this is cool but what if we wanted to create many geometrical sets maybe from a text file, so lets see how that would work.

We already know how to create a new geometrical set and change its name, so what missing is how to open a file, read it and then process the read data. This is where a little sleuthing is involved, we don’t know which object has a method that would allow us to read a file so lets start there.

If we look at the object hierarchy in the automation.chm, we can see a set of objects that might do what we want. If you don’t see anything take a best guess and navigate the structure looking at the Methods until you find what you need. Ultimately we will need to navigate the structure down to the object that has those methods and property’s we will use.

In this case we don’t have to go to far so lets start of by navigating down to the FileSystem object from the Application object.

Just as before we will need the default CATMain subroutine to start

Sub CATMain()
  
End Sub

Now we have that we can grab the Application object and equate it to CATIA

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
End Sub

To get from the Application object to the FileSystems object we need to create a space in memory of that type and then equate it to the required object.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  Dim ioFileSystem As FileSystem
  Set ioFileSystem = ioCATIA.FileSystem
End Sub

This is where it gets interesting. Some of the object types have not been exposed correctly, even though they appear in the Intellisense. IntelliSense in VBA is a feature that provides autocomplete for words that you’ve already started to type. You can access the Intellisense menu by using the following keyboard shortcuts:

  • Ctrl + Space: Shows the Intellisense menu
  • Ctrl + J: Used at different times than Ctrl + Space

I digress, you will find a few objects that will report this error, but there is a simple fix. We can either comment out the type declaration as shown below. This will force the compiler to see this as a Variant Type initially but will figure out the type at compile time otherwise known as late binding.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  Dim ioFileSystem 'As FileSystem
  Set ioFileSystem = ioCATIA.FileSystem
End Sub

Or we can declare it as a Variant type, which again is tantamount to not declaring a type since the compiler will again figure out the type at compile time. So which is better? In my mind its better to pre-declare the type for cleanliness. However there is a down side to this, the intellisence utilizes the declared type to help you write your code. If we leave it uncommented.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  Dim ioFileSystem As FileSystem
  Set ioFileSystem = ioCATIA.FileSystem
End Sub

Then intellisence will work but it wont compile or run. So what the solution, I declare both, so while I’m coding I comment out the Variant and uncomment the correct type, this way i can utilize the intellisence.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  Dim ioFileSystem As FileSystem
  'Dim ioFileSystem As Variant
  Set ioFileSystem = ioCATIA.FileSystem
End Sub

Lets keep going, if we take a look at the Property’s and Methods, we can see that there are a lot all to do with Files and Folders.

The one that I’m specifically interested in is the GetFile method, so lets click on that and see what it does. So it’s a Func (Function) which means it does something and returns something in this case an object of type File. But it also has something in-between the parenthesis. This means it requires something to be passed into the Function. In this case it a CATBSTR or string of the File Path. Below we can see and example.

So lets use this.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  'Dim ioFileSystem As FileSystem
  Dim ioFileSystem As Variant
  Set ioFileSystem = ioCATIA.FileSystem
  
  Dim ioFile As File
  Set ioFile = ioFileSystem.GetFile("C:\Users\me\Documents\GeoSetFile.txt")
End Sub

We now have the File object, we can follow the File Hyperlink to see what Property’s and Methods the File Object has.

The File object has a Method that we need called OpenAsTextStream so lets implement this into our code.

To do that lets click on the methods to see what it needs. Again its a Function and it needs a String to be passed in, for the Mode. This time the documentation tells us what the Three String Modes are: ForReading, ForWriting, and ForAppending. We will use the Reading mode.

Again we can see an example so lets implement it into our code. When we open the file into the text stream the file’s content is opened into a buffer.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  'Dim ioFileSystem As FileSystem
  Dim ioFileSystem As Variant
  Set ioFileSystem = ioCATIA.FileSystem
  
  Dim ioFile As File
  Set ioFile = ioFileSystem.GetFile("C:\Users\ma_je\Documents\GeoSetFile.txt")
  
  Dim ioTextStream As TextStream
  Set ioTextStream = ioFile.OpenAsTextStream("ForReading")
End Sub

Just as before we will follow the Hyperlinks to see what Methods and Property’s the object has.

Our File will contain many lines, each line will be a name of a geometrical set. Looking at the Property and Method descriptions i think we will need AtEndOfStream, ReadLine and Close. To implement the AtEndOfStream propertys we will need to use a Do While Loop.

The AtEndOfStream property returns a Boolean value True or False, so we want to keep processing the file while the value is False. We must also Close the Stream before the script ends.

Don’t Run this code it will loop for ever.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  'Dim ioFileSystem As FileSystem
  Dim ioFileSystem As Variant
  Set ioFileSystem = ioCATIA.FileSystem
  
  Dim ioFile As File
  Set ioFile = ioFileSystem.GetFile("C:\Users\ma_je\Documents\GeoSetFile.txt")
  
  Dim ioTextStream As TextStream
  Set ioTextStream = ioFile.OpenAsTextStream("ForReading")
  
  Do While ioTextStream.AtEndOfStream = False
  
  Loop
  
  ioTextStream.Close
End Sub

We must have something in the loop that will process the file enabling us to get to the end of the text stream. This is where we will create a new String variable and then read a line of the file. When a line is read, it is removed from the buffer until we reach the end of the stream.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  'Dim ioFileSystem As FileSystem
  Dim ioFileSystem As Variant
  Set ioFileSystem = ioCATIA.FileSystem
  
  Dim ioFile As File
  Set ioFile = ioFileSystem.GetFile("C:\Users\ma_je\Documents\GeoSetFile.txt")
  
  Dim ioTextStream As TextStream
  Set ioTextStream = ioFile.OpenAsTextStream("ForReading")
  
  Do While ioTextStream.AtEndOfStream = False
  
    Dim ioLineString As String
    ioLineString = ioTextStream.ReadLine
  
  Loop
  
  ioTextStream.Close
End Sub

Let’s add a few lines to the text file and run the code.

When the script is executed we can see each line being read.

Now that we have the geometrical sets name we can create each geometrical set intern, within the loop. So lets put it all together, the following script will create a new Part, Read the File then create all of the geometrical sets.

Sub CATMain()

  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  Dim ioDocuments As Documents
  Set ioDocuments = ioCATIA.Documents
  
  Dim ioPartDocument As PartDocument
  Set ioPartDocument = ioDocuments.Add("Part")
  
  Dim ioPart As Part
  Set ioPart = ioPartDocument.Part
  
  Dim ioHybridBodies As HybridBodies
  Set ioHybridBodies = ioPart.HybridBodies
  
  'Dim ioFileSystem As FileSystem
  Dim ioFileSystem As Variant
  Set ioFileSystem = ioCATIA.FileSystem
  
  Dim ioFile As File
  Set ioFile = ioFileSystem.GetFile("C:\Users\ma_je\Documents\GeoSetFile.txt")
  
  Dim ioTextStream As TextStream
  Set ioTextStream = ioFile.OpenAsTextStream("ForReading")
  
  Dim ioHybridBody As HybridBody
  
  Do While ioTextStream.AtEndOfStream = False
  
    Dim ioLineString As String
    ioLineString = ioTextStream.ReadLine
    
    Set ioHybridBody = ioHybridBodies.Add()
    ioHybridBody.Name = ioLineString
  
  Loop
  
  ioTextStream.Close
End Sub

Adding Structure to The Geometrical Sets

Having a flat structure is good, but not great, so let’s change the file structure so that each line is a comma separated variable.

We will process it the same way but we will need to do a few extra steps. Also we want to create a dictionary object using the numeric value as a unique key so we can grab the geometrical set from the dictionary quickly. to allow us to use dictionary’s in the code we have to add an additional reference into the code editor this reference is “Microsoft Scripting Runtime” to add the reference (Add using Tools->References from the VB menu).

Now we can add a new dictionary to our code, and we will do that at the top.

Sub CATMain()

  Dim dict As Scripting.Dictionary
  Set dict = New Scripting.Dictionary

So there is a lot goin on here, but lets walk through it slowly.

Do While ioTextStream.AtEndOfStream = False
  
    Dim ioLineString As String
    ioLineString = ioTextStream.ReadLine
    
    Dim ioArray() As String
    ioArray = Split(ioLineString, ",")
    
    If (ioArray(1) = "0") Then
        Set ioHybridBody = ioHybridBodies.Add()
        dict.Add ioArray(0), ioHybridBody
    Else
        Dim ioParentGeoSet As HybridBody
        Set ioParentGeoSet = dict.Item(ioArray(1))
        
        Set ioHybridBody = ioParentGeoSet.HybridBodies.Add()
        dict.Add ioArray(0), ioHybridBody
    End If
    
    ioHybridBody.Name = ioArray(2)
  
  Loop

Now that each line is a csv Comma Separated Variable we need to break it up into separate pieces. To do this we need to create an array, this is done by simply adding parenthesis to the end of the variable name, we don’t provide a size though for the array. Then we can use the Split function to split the string read by the text stream Readline method by the separator which is a comma.

    Dim ioArray() As String
    ioArray = Split(ioLineString, ",")

Next we check to see if the second value in the array is a “0” as this indicates that the geometrical set should be created at the Root of the Part. If it is created at the Root of the Part then we add the HybridBody as before, but this time we will also add the New HybridBody Object to the dictionary with the Key. If it’s not added to the Root, then we need to do something a little differently.

First we will create a new space in memory for the Parent HybridBody and then retrieve it from the Dictionary by its Key, then we can add the New Geometrical Set to the retrieved Parent and then again Add the New Geometrical Set the Dictionary.

If (ioArray(1) = "0") Then
        Set ioHybridBody = ioHybridBodies.Add()
        dict.Add ioArray(0), ioHybridBody
    Else
        Dim ioParentGeoSet As HybridBody
        Set ioParentGeoSet = dict.Item(ioArray(1))
        
        Set ioHybridBody = ioParentGeoSet.HybridBodies.Add()
        dict.Add ioArray(0), ioHybridBody
    End If

We can now create complex Geometrical Set structures from a text file like the one below, where there are two geometrical sets within the Points geometrical set which is below the Construction geometrical set.