Home > The CATIA Object Model > Efficiently navigating parameter collections

Efficiently navigating parameter collections


Many times over the years, I have seen a common problem posted in CATIA forums.  The problem is that some macro runs great on smaller parts or products, but it slows down tremendously on larger ones.  The programmer has noticed that the slowness happens when trying to retrieve a parameter from a parameters collection.  Fortunately, the problem is very easy to correct.  In this article I will show how to work with smaller parameter collections to boost performance and also show how to more reliably get at the specific parameters you need.

The problem

Before looking at the solution, lets clearly understand what the problem is here.  The slowness that you see when dealing with larger parts or products is simply caused by parameter collections that are also very large.  You may not realize it but every parametric feature typically has about one to ten parameters associated with it.  For example, every feature has an Activity parameter (allows it to be deactivated) as well as others that might control things like offset values, angles, tolerances, etc.  So, a part with 500 geometric features could easily have several thousand parameters in the root parameters collection!  Products can be even worse because their root parameter collection contains all parameters in the product itself as well as all parameters in all parts and products below them!

When you request a parameter from a parameter collection by name, the API has to go one by one through the entire collection and perform string comparisons to find a match.  That can be an expensive process, in terms of CPU time.

As a quick scripting exercise let us see how large the parameter count can be.  Open some different parts with many features or a product that has many parts below it (each with many features) then run the code below:

Sub CATMain()

     Dim strType As String
     Dim objParams As Parameters

     'Get at the root parameters collection based on the type of document
     strType = TypeName(CATIA.ActiveDocument)
     If strType = "ProductDocument" Then
          Set objParams = CATIA.ActiveDocument.Product.Parameters
     ElseIf strType = "PartDocument" Then
          Set objParams = CATIA.ActiveDocument.Part.Parameters
     End If

     'Display the parameter count
     MsgBox "The active document has " &objParams.Count &" parameters."

End Sub

The solution

The solution to the problem is to get creative and retrieve a only a subset of the total parameters, then get at a specific parameter in that smaller collection.  I usually accomplish this by one of two techniques depending on the situation.

Method 1: Access only parameters belonging to a parameter set

Parameter sets can be found inside many different CATIA documents and are easily recognized by a special node in the tree that looks like this:

Typically, this node will be located near the top of the tree for a particular document and will be called “Parameters” but it is also possible to make many parameter sets inside a single document.  They can be nested under one another to build a structured set of parameters and can even be nested within geometrical sets and bodies.  I utilize parameter sets often when making reusable template models in order to organize related parameters.

When you get at a parameter set, you have several options to access smaller collections of parameters within it.  You can either access all parameters, only the direct parameters or other parameter sets nested under the parameter set.  I will show all of these techniques in one simple example below.  In this scenario, there are many parameters with the same name (Radius) in different places.

I will assume a part is open in its own window and contains the objects shown in the tree above. Follow along by reading the comments in the code.

Sub CATMain()

     Dim objPart As Part
     Dim objParamSetRoot As ParameterSet
     Dim objParamSet As ParameterSet
     Dim objParams As Parameters
     Dim objParam As Parameter
     Dim intCount As Integer
     Dim intIndex As Integer
     Dim strName As String
     Dim strMsg As String

     'Get at the part object
     Set objPart = CATIA.ActiveDocument.Part

     'Get at all parameters in the part...
     'This collection could be very large in some cases and therefore slow
     'Could also be hard to get at a specific Radius parameter
     'since .Item("Radius") will always return only the first one found

     Set objParams = objPart.Parameters
     intCount = 0
     For intIndex = 1 To objParams.Count
          If objParams.Item(intIndex).Name = "Radius" Then 
               intCount = intCount + 1
          End If
     Next
     strMsg = "This part has " &objParams.Count & " total parameters" & vbCrLf
     strMsg = strMsg & "and has " & intCount & " parameters named ""Radius"""
     MsgBox strMsg, 0, "Test1"

     'Now get at the root parameter set and check its direct parameters
     'There will be none in this example because the root parameter set
     'only has other parameter sets below it but no parameters

     Set objParamSet = objParams.RootParameterSet
     intCount = objParamSet.DirectParameters.Count
     MsgBox "The root parameter set has " & intCount _
             & " parameters directly under it.", 0, "Test2"

     'Get at the root parameter set and retrieve all its parameters
     'There will be seven in this example
     'For this we will use the AllParameters method.
     'Note that IF we were sure there was ONLY ONE Radius Parameter
     'somewhere under this set, we could get it from this parameters collection
     'by using the .Item method

     Set objParamSet = objParams.RootParameterSet
     intCount = objParamSet.AllParameters.Count
     MsgBox "The root parameter set has " & intCount _
                     & " parameters under it (all levels).", 0, "Test3"

     'Get at just the Radius parameter in the "Holes" parameter set
     'For this we access a specific ParameterSet object and get its
     'DirectParameters
     Set objParamSet = objParams.RootParameterSet.ParameterSets.Item("Holes")
     Set objParam = objParamSet.DirectParameters.Item("Radius")
     strName = objParams.GetNameToUseInRelation(objParam)
     strMsg = "The full name of the radius param in the Holes param set is,"
     strMsg = strMsg & vbCrLf & strName
     MsgBox strMsg, 0, "Test4"

End Sub

Method 2: Access only the parameters aggregated under some object

This can be achieved with a call to the Sublist method which is provided by the Parameters object.  The general syntax looks like this:

Set Params2 = Params1.Sublist(iObject, iRecursively)

Params1

A Parameters object

iObject

The object whose child parameters should be retrieved

iRecursively

Boolean specifying whether to retrieve only the parameters directly under the object or also for all parameters nested under that object at all levels

Params2

The returned Parameters object containing the subset of parameters

Lets look back at the earlier example.  The Sublist method would be very useful to quickly get at that Radius parameter that is nested directly under Geometrical Set.1

Sub CATMain

     Dim objPart As Part
     Dim objGeoSet As HybridBody
     Dim objParams As Parameters
     Dim objParam As Parameter
     Dim strName As String
     Dim strMsg As String

     'Get at Geometrical Set.1
     Set objPart = CATIA.ActiveDocument.Part
     Set objGeoSet = objPart.HybridBodies.Item(“Geometrical Set.1”)

     'Get at ONLY the parameters aggregated directly under the geo set
     'by specifying False for the 2<sup>nd</sup> argument.  This will prevent
     'retrieving the Radius parameter under the circle
     Set objParams = objPart.Parameters.SubList(objGeoSet,False)

     'Get the radius parameter and display its full name
     Set objParam = objParams.Item("Radius")
     strName = objParams.GetNameToUseInRelation(objParam)
     strMsg = "The full name of the radius parameter directly " & vbCrLf
     strMsg = strMsg & "under Geometrical Set.1 is," & vbCrLf & strName
     MsgBox strMsg, 0, "Test5"

End Sub

Conclusions

The techniques shown above are very powerful ways to increase performance in your program and to get at specific parameters.  Even though I showed several examples above, this is really only the “tip of the iceberg”.  I have used these basic techniques in hundreds of different scenarios. You can even use these techniques to get at just the collection of parameters under a specific object object then create new parameters nested under it…I’ll let you experiment with that on your own.

Anyway, here are some general things to take away from this article.

  1. When you retrieve a parameter by name using the Item method, it will always return the first match it finds in the collection.
  2. If a parameter is inside a parameter set, first access a parent parameter set above the parameter you want then either use the AllParameters or DirectParameters method.
  3. If a parameter is aggregated under some other object use the SubList method. Remember to properly specify whether you want to retrieve parameters recursively.
  4. As mentioned earlier, when you retrieve the Parameters object for a product, it contains all parameters in the product itself as well as all parameters in all parts and products below it.  To get ONLY the parameters belonging to the product itself, get at its RootParameterSet then use either the AllParameters or DirectParameters method.

Please take a moment to rate this article…Just click the stars up near the title.

Add to: del.icio.us del.icio.us, StumbleUpon StumbleUpon, Digg Digg, Google Google

Advertisements
  1. Han JaeMyeong
    April 25, 2010 at 8:42 am

    Method 2 is very Good!!!
    Thank you!!! ^^

  2. Jon
    July 7, 2011 at 10:18 pm

    Thank you! I would have never figured out how to get at Direct Parameters.

  3. November 11, 2011 at 2:14 pm

    How do you get a parameter value located with in a part body? I have a part with mulitple bodies so let’s say I want to get the value for a parameter called “Part Description” located in the third body? body.parameters doesn’t seem to work. Any ideas?

  4. Ashok
    May 4, 2012 at 7:03 am

    Thank you… detailed article.

  5. MitchO
    June 28, 2012 at 12:52 pm

    Wow, this is exactly what I was looking for! This is going to make what I’m trying to do so much easier. Thank you so much!!

  6. July 19, 2012 at 7:31 am

    I have a little problem.
    In my case, I have to embed severeal data from a database server. I use parameter as a local storage.

    I have no problem to read and to write a parameter in an active document. But there is a problem whenever I need to write a parameter and its value into a part document while active document is a product document.

    For example:
    I run this script in the product document, and result is error with message: “Method ‘CreateInteger’ of Object ‘Parameters’ failed”

    Sub CATMain()

    ‘ the active document is a product document
    Dim productDocument1 As ProductDocument
    Set productDocument1 = CATIA.ActiveDocument

    Dim product1 As Product
    Set product1 = productDocument1.Product

    Dim products1 As Products
    Set products1 = product1.Products

    Dim product2 As Product
    Set product2 = products1.Item(“Part7.1”)

    ‘accessing existed parameter in a part
    Dim paramObj As Parameter
    Set paramObj = product2.Parameters.Item(“MaterialDetailId”)

    ‘the value successfully retrieved
    MsgBox paramObj.ValueAsString

    ‘create new parameter in the part
    ‘resulting a runtime error
    product2.Parameters.CreateInteger “Test”, 1

    ‘never reach this line
    Set paramObj = product2.Parameters.Item(“Test”)
    MsgBox paramObj.ValueAsString

    End Sub

    Can you figure how to resolve this?

    • July 25, 2012 at 9:39 pm

      So the product2 variable in your code is actually pointing at the instance of the part in the assembly. So my first question is do you really want to create a parameter there? If so my first guess is that you need to access the reference product of that instance like this:
      product2.ReferenceProduct.Parameters.CreateInteger “Test”, 1

      If you really intended to create the parameter inside the part itself, you might do something like this:
      Set objPart = product2.ReferenceProduct.Parent.Part
      objPart.Parameters.CreateInteger “Test”, 1

      Good luck…

  7. August 13, 2012 at 8:27 am

    Thank you for replying.

    My intention is to create the parameter inside the part itself.
    I post this comment as soon as I read your comment. I already have another workaroud but I think I need to try your workaround. I will report as soon as I try it.

    Btw, my workaroud is something like this:

    ‘PartNumber of the part/product object which needed to create the parameter inside itself.
    Dim strPartNumber as String
    strPartNumber = “PartXXX”

    Dim Docs as Documents
    Set Docs = CATIA.Application.Documents

    Dim objActiveDocument as Document
    set objActiveDocument = CATIA.ActiveDocument

    Dim vntDoc as Variant
    Dim objProduct as product

    for each vntDoc in Docs
    set objProduct = vntDoc.Product

    if objProduct.PartNumber = strPartNumber then
    vntDoc.Activate
    objProduct.Parameters.CreateInteger “Test”, 1

    ‘ Activate the original Active Document
    objActiveDocument.Activate
    Exit For
    end if

    next

    p.s. I’m not an native English speaker, I hope you can understand :)

  1. No trackbacks yet.

Leave a Reply to Han JaeMyeong Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: