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.
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 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)
A Parameters object
The object whose child parameters should be retrieved
Boolean specifying whether to retrieve only the parameters directly under the object or also for all parameters nested under that object at all levels
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
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.
- When you retrieve a parameter by name using the Item method, it will always return the first match it finds in the collection.
- 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.
- If a parameter is aggregated under some other object use the SubList method. Remember to properly specify whether you want to retrieve parameters recursively.
- 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.