VBA CATIA Part Design – HybridShapeFactory

VBA CATIA Part Design – HybridShapeFactory

In my last post we went through how to create geometrical sets, and how to navigate the documentation while writing code. In this post we will focus on creating basic wireframe using the HybridShapeFactory.

VBA Editor

There are lots of IDE Interactive Development Environments, sounds complex but its just an application that helps us write code. In reality if you have the documentation then you could use NotePad ++, Sublime Text, or another Text Editor. I use the VBA Editor that comes with CATIA, which also comes with most of the Microsoft Office products. This means once you understand how to write basic VBA you can do it with any of the Office products or other apps that provide VBA API. In addition you can write apps that talk to other apps for example you could write a Excel VBA app that talks to CATIA or a CATIA app that talks to Excel and PowerPoint.

To start the VBA Editor press Alt+F11 or Tools->Macro->Visual Basic Editor.

We should see a new Visual Basic Application Editor start. The first thing we have to do is create a new Macro Library, this is achieved by selecting File->Macro Libraries…

In the Macro Libraries Window select Create New Library, key in a Path into the Create a New VBA Project window, then select Ok and then Close.

In the VBA Editor we can now see the new Project.

Now we can Insert a New Module, this will store our code. We will investigate UserForm and Class Module’s another day.

Within the New Module lets start by adding in the standard default CATIA Main Sub-Routine.

Creating a New Part Document

Just as before in the last Post we want to create a new Part Document, but unlike the last post we want to only create a new PartDocument is the Current Active Document is not a PartDocument. So Lets Start of with the previous code.

Note:- In the Module within the VBA IDE just type in Sub CATMain and hit Enter. It will auto complete and add the End Sub automatically.

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

In the IDE we can just hit the Green Play button and the code will execute, and we will get a new PartDocument.

The problem is that every time we run the code we will get a new PartDocument. So lets address that first, if we look at the Application Objects Property’s and Methods we will find a Property called ActiveDocument. This will always return the ActiveDocument if there is one in the session. It doesn’t mean that its a PartDocument though it could be a Drawing or Product or something else.

It get around this we will equate a PartDocument object to the ActiveDocument, and then trap the error. If there is an error we know the Active Document is not a PartDocument and if there is no error then we know that the ActiveDocument is a PartDocument. To do this we will use two statements: On Error Resume Next, and On Error Goto 0.

On Error Resume Next, tells the compiler that if any line after this causes an Error ignore it and continue tot he next line.

On Error Goto 0, tells the compiler to stop ignoring Errors and reset the Error Code to 0, i.e. no error.

Sub CATMain()
  Dim ioCATIA As Application
  Set ioCATIA = CATIA
  
  On Error Resume Next
  
  	Dim ioPartDocument As PartDocument
  	Set ioPartDocument = ioCATIA.ActiveDocument
  
  On Error Goto 0
End Sub

We can now check the state of the Error handler by checking if the current Error Number is not Zero. If this is the case we will create a new PartDocument otherwise we know that we have successfully equated our variable PartDocument to an Active PartDocument in the session.

Sub CATMain()
    Dim ioCATIA As Application
    Set ioCATIA = CATIA
  
    On Error Resume Next
    
        Dim ioPartDocument As PartDocument
        Set ioPartDocument = ioCATIA.ActiveDocument
        
        If (Err.Number <> 0) Then
            Set ioPartDocument = ioCATIA.Documents.Add("Part")
        End If
    
    On Error GoTo 0
End Sub

Adding a New Geometrical Set

Similar to this we want to create a new geometrical set only if one does not already exist, that called “Points”. First we have to navigate to the Part object and then to the HybridBodies object, this can be seen in the last post.

Sub CATMain()
    Dim ioCATIA As Application
    Set ioCATIA = CATIA
  
    On Error Resume Next
    
        Dim ioPartDocument As PartDocument
        Set ioPartDocument = ioCATIA.ActiveDocument
        
        If (Err.Number <> 0) Then
            Set ioPartDocument = ioCATIA.Documents.Add("Part")
        End If
    
    On Error GoTo 0
    
    Dim ioPart As Part
    Set ioPart = ioPartDocument.Part
    
    Dim ioHybridBodies As HybridBodies
    Set ioHybridBodies = ioPart.HybridBodies
End Sub

We can use the same trick as before, by turning off the Error Handler trying to get a Geometrical Set called “Points” and then checking for an Error. If an Error occurs we know we need to create the Geometrical Set, other wise we know that our variable will be equated to an existing Geometrical Set called “Points”. Then we will reset the Error Handler and carry on.

    Dim ioPart As Part
    Set ioPart = ioPartDocument.Part
    
    Dim ioHybridBodies As HybridBodies
    Set ioHybridBodies = ioPart.HybridBodies
	On Error Resume Next
    
		Dim ioHybridBody As HybridBody
		Set ioHybridBody = ioHybridBodies.Item("Points")
        
        If (Err.Number <> 0) Then
  			Set ioHybridBody = ioHybridBodies.Add()
  			ioHybridBody.Name = "Points"
        End If
    
    On Error GoTo 0
End Sub

HybridShapeFactory

Within the Automartion.chm within the PartDocument object we can see all of the objects that can be navigated within the PartDocument. One of these objects is an Abstract Object called Factory and below this we can see associated to this are thee Factories: ShapeFactory, HybridShapeFactory and InstanceFactory. We don’t have to Navigate across an Abstract object this just shows us the Generic type that can be equated to anyone of the three Factory’s, this is why it’s called an Abstract object.

So lets start of by navigating down to the HybridShapeFactory.

        If (Err.Number <> 0) Then
            Set ioHybridBody = ioHybridBodies.Add()
            ioHybridBody.Name = "Points"
        End If
    
    On Error GoTo 0
    
    Dim ioHybridShapeFactory As HybridShapeFactory
    Set ioHybridShapeFactory = ioPart.HybridShapeFactory
End Sub

If we look at the Automation.chm and navigate into the HybridShapeFactory object we can see all of the Property’s and Methods and there are a lot. We can see that we can create nearly every type of wireframe element, but we will start of with Points, specifically PointCoordinate.

Again if we navigate into the hyperlink for this object, we can see that it is a Function and it returns a HybridShapePointCorrd object, and it requires three inputs for X, Y, and Z as Type Double. Double is just a numeric value.

Since its a Function and returns a specific object type we must declare a variable of this type (HybridShapePointCoord) just as before and then we can equate it by using the AddNewPointCoord method shown in the documentation.

	On Error GoTo 0
    
    Dim ioHybridShapeFactory As HybridShapeFactory
    Set ioHybridShapeFactory = ioPart.HybridShapeFactory
    
    Dim ioHybridShapePointCoord As HybridShapePointCoord
    Set ioHybridShapePointCoord = ioHybridShapeFactory.AddNewPointCoord(10, 20, 30)
End Sub

However if we run this code, the point does not show in the specification tree. That’s understandable we haven’t told it where in the specification tree it should go. First its advisable to Compute the new HybridShape and then add it to the Specification Tree, this way we don’t have to do an Update of the complete Part, but i will still show you how to do that.

The Compute method is hidden away at the MechModInterfaces.HybridShape object, so lets select on the Hyperlink at the Top of the HybridShapePointCoord documentation.

Here we can see the Compute Method, so again lets select the Hyperlink to view the documentation on the method.

This Method is just a Sub routine, and it does not require any inputs, so we can just simply call it to pre-update compute the hybridshape.

    Dim ioHybridShapeFactory As HybridShapeFactory
    Set ioHybridShapeFactory = ioPart.HybridShapeFactory
    
    Dim ioHybridShapePointCoord As HybridShapePointCoord
    Set ioHybridShapePointCoord = ioHybridShapeFactory.AddNewPointCoord(10, 20, 30)
    
    ioHybridShapePointCoord.Compute
End Sub

Now that’s out of the way we can add the point to the Specification tree, this is done by using a method associated to the HybridBody object AppendHybridShape. Let’s select the Methods Hyperlink to see if there is an example.

The Method is a Sub-Routine so it does not return anything we can simply use it. However, we have to pass the HybridShape that we want to append to the method.

Now the Point will display correctly in the specification tree within the geometrical set earlier created.

    Dim ioHybridShapePointCoord As HybridShapePointCoord
    Set ioHybridShapePointCoord = ioHybridShapeFactory.AddNewPointCoord(10, 20, 30)
    
    ioHybridShapePointCoord.Compute
    
    ioHybridBody.AppendHybridShape ioHybridShapePointCoord
End Sub

If the part requires an update, then we can use the Update method which is found on the Part object. However, this should not be necessary since the point was pre-computed.

    Dim ioHybridShapePointCoord As HybridShapePointCoord
    Set ioHybridShapePointCoord = ioHybridShapeFactory.AddNewPointCoord(10, 20, 30)
    
    ioHybridShapePointCoord.Compute
    
    ioHybridBody.AppendHybridShape ioHybridShapePointCoord

	ioPart.Update
End Sub

Importing Points From a CSV File

In the last post we read a text file and created a geometrical set structure. This time we will read a text file and create points and place them in the correct geometrical set.

Our file will have the following structure.

Geometrical Set Parent, Geometrical Set, X , Y , Z , Point Name.

So lets begin.

Based on the last post we know how to read a file, so lets get that code implemented.

Sub CATMain()
    Dim ioCATIA As Application
    Set ioCATIA = CATIA
  
    On Error Resume Next
    
        Dim ioPartDocument As PartDocument
        Set ioPartDocument = ioCATIA.ActiveDocument
        
        If (Err.Number <> 0) Then
            Set ioPartDocument = ioCATIA.Documents.Add("Part")
        End If
    
    On Error GoTo 0
    
    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
        
    Loop
  
  ioTextStream.Close
End Sub

Now we have the basic layout lets look at what the text file could look like.

First we will spit the comma separated string into an array.

	Do While ioTextStream.AtEndOfStream = False
  
        Dim ioLineString As String
        ioLineString = ioTextStream.ReadLine
        
        Dim ioArray() As String
        ioArray = Split(ioLineString, ",")
  
    Loop

Just as before we will use a Dictionary to keep track of the Geometrical Sets, so lets add that to the top of the VBA.

Sub CATMain()

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

Now we can work on the core logic, lets start of with the Geometrical Set logic. First we will check to see if the value of the Parental Geometrical Set is NULL. If it is then we have to add the New Geometrical Set tot he Root of the Part otherwise we will ahve to get the Parent Geometrical Set from the dictionary.

    Do While ioTextStream.AtEndOfStream = False
  
        Dim ioLineString As String
        ioLineString = ioTextStream.ReadLine
        
        Dim ioArray() As String
        ioArray = Split(ioLineString, ",")
        
        If (ioArray(0) = "NULL") Then
        
        Else
        
        End If
  
    Loop

Just as before in the last Post we will directly add the New HybridBody if the Parental Geometrical Set is NULL. Otherwise we will get the Parental Geometrical Set from the Dictionary and then Create the New HybridBody within the Parental Geometrical Set.

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

    Loop
  
  ioTextStream.Close
End Sub

Now we have the Geometrical Set Code taken care of we can create the point, first lets create an object for the HybridShapeFactory, and well do this before we get into the loop.

    Dim ioTextStream As TextStream
    Set ioTextStream = ioFile.OpenAsTextStream("ForReading")
    
    Dim ioHybridBody As HybridBody
    
    Dim ioHybridShaoeFactory As HybridShapeFactory
    Set ioHybridShaoeFactory = ioPart.HybridShapeFactory
    
    Do While ioTextStream.AtEndOfStream = False

Finally, we will check the three parts of the Array that contain the X, Y, Z values, to ensure that they are all Not NULL. Then we will ahve to convert the String Values to Doubles this is done with the CDbl function which takes in a string and returns a Double value. Then we can use these variables of Type Double to create the Point as we did above.

        ioHybridBody.Name = ioArray(1)
        
        If (ioArray(2) <> "NULL" And ioArray(3) <> "NULL" And ioArray(4) <> "NULL") Then
        
            Dim ioHybridShapePointCoord As HybridShapePointCoord
            Dim X, Y, Z As Double
            X = CDbl(ioArray(2))
            Y = CDbl(ioArray(3))
            Z = CDbl(ioArray(4))
            
            Set ioHybridShapePointCoord = ioHybridShaoeFactory.AddNewPointCoord(X, Y, Z)
            ioHybridShapePointCoord.Name = ioArray(5)
            ioHybridShapePointCoord.Compute
            
            ioHybridBody.AppendHybridShape ioHybridShapePointCoord
        End If
        
    Loop
  
  ioTextStream.Close
End Sub

Happy Coding.