Measure Bodies

Hello, I am wondering if somebody can help me to create a journal to measure bodies in NX. Specifically what I am trying to do is, create a journal that will measure each assembly in the model and for each assembly save the information window on the Hard drive. This would greatly help to speed up my work flow. I am somewhat knowledgeable of VBA, and have tried recording journals and altering the code from there, but I have not had any success. I need to be able to do this with any model, not just one particular model. Any help would be greatly appreciated, thank you.

What version of NX?

You want to: "measure each assembly in the model"
Does this mean that you want the journal to measure and report each body in the assembly individually, or do you only want the total result for the given assembly?

I think I was not quite clear on exactly the results I was looking for. Can somebody at least get me started and show me how to measure bodies in VBA. Perhaps show me how to use measure bodies on certain model parts as well so I can customize my own journals. Also I am running TeamCenter 10.1.2.1 and I know sometimes that affects the code in different ways. Not sure if it does in this instance or not, but I thought it would be helpful information. I am using NX 9.0.3.4.

Below is one method to measure bodies. This way does not create a measure body feature in the part navigator, it only reports selected values.

Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UF

Module Module1

Sub Main()

Dim theSession As Session = Session.GetSession()
If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If

Dim workPart As Part = theSession.Parts.Work
Dim lw As ListingWindow = theSession.ListingWindow
lw.Open()

Const undoMarkName As String = "NXJ journal"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, undoMarkName)

Dim theBody As Body
If SelectBody("select a body", theBody) = Selection.Response.Cancel Then
Return
End If

Dim theBodies(0) As Body
theBodies(0) = theBody

Dim myMeasure As MeasureManager = theSession.Parts.Display.MeasureManager()
Dim massUnits(4) As Unit
massUnits(0) = theSession.Parts.Display.UnitCollection.GetBase("Area")
massUnits(1) = theSession.Parts.Display.UnitCollection.GetBase("Volume")
massUnits(2) = theSession.Parts.Display.UnitCollection.GetBase("Mass")
massUnits(3) = theSession.Parts.Display.UnitCollection.GetBase("Length")

Dim mb As MeasureBodies = Nothing
'.NewMassProperties(array of units, accuracy parameter, array of bodies to measure)
mb = myMeasure.NewMassProperties(massUnits, 0.99, theBodies)
mb.InformationUnit = MeasureBodies.AnalysisUnit.PoundFoot

lw.WriteLine("volume: " & mb.Volume.ToString & " ft^3")
lw.WriteLine("surface area: " & mb.Area.ToString & " ft^2")
lw.WriteLine("centroid: " & mb.Centroid.ToString & " (coordinates in feet)")

lw.Close()

End Sub

Function SelectBody(ByVal prompt As String, ByRef selObj As TaggedObject) As Selection.Response

Dim theUI As UI = UI.GetUI
Dim title As String = "Select a solid body"
Dim includeFeatures As Boolean = False
Dim keepHighlighted As Boolean = False
Dim selAction As Selection.SelectionAction = Selection.SelectionAction.ClearAndEnableSpecific
Dim cursor As Point3d
Dim scope As Selection.SelectionScope = Selection.SelectionScope.WorkPart
Dim selectionMask_array(0) As Selection.MaskTriple

With selectionMask_array(0)
.Type = UFConstants.UF_solid_type
.SolidBodySubtype = UFConstants.UF_UI_SEL_FEATURE_SOLID_BODY
End With

Dim resp As Selection.Response = theUI.SelectionManager.SelectTaggedObject(prompt, _
title, scope, selAction, _
includeFeatures, keepHighlighted, selectionMask_array, _
selobj, cursor)
If resp = Selection.Response.ObjectSelected OrElse resp = Selection.Response.ObjectSelectedByName Then
Return Selection.Response.Ok
Else
Return Selection.Response.Cancel
End If

End Function

Public Function GetUnloadOption(ByVal dummy As String) As Integer

'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately

End Function

End Module

So I guess the only way to use Measure Bodies is to actually select the model parts? I was hoping I could just run a script so it would measure every model part on the fly, and then save the resulting information windows on my hard drive in a specified folder. I was trying to avoid having to select each model part individually. The code didn't actually work, for some reason when the listing window pops up waiting for user input, nothing happens when you select a solid body. So I thought maybe typing in the name of the model part would work but it did not. It says "no selectable object of that name found".

The code above is meant to be run in a part file (not an assembly) and is only meant to illustrate one method of measuring a body. I posted a quick example in response to your request: "Can somebody at least get me started and show me how to measure bodies in VBA". To modify the code to work in an assembly context, change the scope in the SelectBody function:

Dim scope As Selection.SelectionScope = Selection.SelectionScope.AnyInAssembly

You can process the bodies in the part by iterating through the part's .Bodies collection, or if you are working with an assembly, you can access all the bodies in the component's used reference set. No user interaction is required.

To further extend the code, you can process every component in an assembly with the code found here:
http://nxjournaling.com/content/creating-subroutine-process-all-componen...

And instructions on how to write to a text file can be found here:
http://nxjournaling.com/content/write-text-file

Thank you for clarifying. These are great resources, thanks a lot!

Hi, when the prompt comes up to select the body, I can only select one body and the code moves onto the next file. What I'd like to do is drag a selection box and select everything inside that box. Is there a way to change the code to this effect??

The code in this thread uses the .SelectTaggedObject function which allows selection of only one object. You can change this to use the .SelectTaggedObjects function (notice the "s" at the end) to allow selection of multiple objects. See the following article for more information:

http://nxjournaling.com/content/using-mask-triples-selectobject-routine

The code in the article is a bit outdated in that it refers to the deprecated .SelectObject and .SelectObjects functions, but the replacements (.SelectTaggedObject and .SelectTaggedObjects) are nearly identical in use.

The link provided was exactly what I needed to select multiple bodies in one file. I now wish to measure this array of bodies as to get a combined result; rather than measure each body individually. Is there a way to do this with ".NewMassProperties" as it seems to be only able to process an individual body???

The .NewMassProperties method in the code above accepts an array of bodies, but only 1 body is analyzed in the code above. I'm fairly sure it will return results for multiple bodies if you edit the code and pass in the array of bodies you are interested in.

EDIT: Everything I need to know about units is right here:
http://www.nxjournaling.com/content/units

Specifically for volume, but this could be applied to any of the other units. If I always wanted to get the results in cubic inches regardless of what the base unit is for the part file. Is the base unit the default in which that file was built? Do I just change the mass units to find specifically what I want?


Dim massUnits1(4) As Unit
massUnits1(0) = CType(wrkPrt.UnitCollection.FindObject("SquareInch"), Unit)
massUnits1(1) = CType(wrkPrt.UnitCollection.FindObject("CubicInch"), Unit)
massUnits1(2) = CType(wrkPrt.UnitCollection.FindObject("PoundMass"), Unit)
massUnits1(3) = CType(wrkPrt.UnitCollection.FindObject("Inch"), Unit)
massUnits1(4) = CType(wrkPrt.UnitCollection.FindObject("PoundForce"), Unit)

Everything you

DHuskic
Nx 9 VB

"Is the base unit the default in which that file was built?"
Yes. A metric file will default to mm for length and kg for mass; imperial will default to inch for length and lbm for mass.

"Do I just change the mass units to find specifically what I want?"
Good question. I'll need to test this (when I find some time) to give a more definitive answer. However, in the journal code further up the thread, it uses the base part units but always displays the results in pounds and feet by setting the .InformationUnit property:

Dim myMeasure As MeasureManager = theSession.Parts.Display.MeasureManager()
Dim massUnits(4) As Unit
massUnits(0) = theSession.Parts.Display.UnitCollection.GetBase("Area")
massUnits(1) = theSession.Parts.Display.UnitCollection.GetBase("Volume")
massUnits(2) = theSession.Parts.Display.UnitCollection.GetBase("Mass")
massUnits(3) = theSession.Parts.Display.UnitCollection.GetBase("Length")

Dim mb As MeasureBodies = Nothing
'.NewMassProperties(array of units, accuracy parameter, array of bodies to measure)
mb = myMeasure.NewMassProperties(massUnits, 0.99, theBodies)
mb.InformationUnit = MeasureBodies.AnalysisUnit.PoundFoot

I've played around with the code a bit more; as far as I can tell, the type of the unit passed in to the measure body object sadly has no effect on the results.

I managed to get it to function by changing this line of code:

Before:
mb.InformationUnit = MeasureBodies.AnalysisUnit.poundfoot

After:
mb.InformationUnit = MeasureBodies.AnalysisUnit.poundinch

Dim mb As MeasureBodies = Nothing
'.NewMassProperties(array of units, accuracy parameter, array of bodies to measure)
mb = myMeasure.NewMassProperties(massUnits1, 0.99, theBodies)
mb.InformationUnit = MeasureBodies.AnalysisUnit.poundinch

DHuskic
Nx 9 VB

I see a lot of code like this:

Dim bodyArray(0) As Body
bodyArray(0) = theBody

I guess people copy this from recorded journals, where it is a common construct. Personally, I think the code is much tidier and easier to read if you write

Dim bodyArray As Body() = { theBody }

If you're writing your own functions, it's easy to allow them to receive either an array of items or a list of individual items. You use the ParamArray keyword to do this. NX/Open functions are never designed this way. They can't be, because they have to work with multiple languages. But the ParamArray idea is very common in SNAP functions, and often makes them easier to call.

There's a similar construct in C#; you use the params keyword.

I think he is trying to convert one body to array. Since the measure bodies requires array of bodies as input. In this case selection response will close with one input. So its good to go. Anyhow for standard practice and ease of reading your input will be good.

Dim Bodyarray() As Body ={}

Regards,

Joe

Didn't know about the ParamArray keyword mentioned by ciao

https://msdn.microsoft.com/en-us/library/538f81ec.aspx

Thanks
Regards