Reset Component Position
When working with assembly files, moving components around in space, there may come a time when you want to reset a component to its absolute starting point; the position where it would appear when adding it with the "absolute position" option. There are various work-arounds in NX to get a component back to its absolute position, but out-of-the-box there is no one click solution - we'll have to make our own.
Component translations and rotations
The assembly file keeps track of each component's location and orientation. You can see how a component has been moved around at any time by using the "information -> object" command and selecting the component; in the information window, the translation and rotation will be reported. When you add a component with the "absolute origin" positioning option, the absolute coordinate system of the component part will align to the absolute coordinate system of the assembly part. If the component has not been moved, the component translation delta X, Y, and Z values will be zero, the X-axis vector rotation will be (1,0,0), the Y-axis vector rotation will be (0,1,0), and the Z-axis vector rotation will be (0,0,1) as shown below.
If you rotate the component by 30° about the X axis, the rotation vectors will be reported as shown below.
The delta X, Y, and Z values are easy enough to understand, but what's going on with the rotation vectors? The mathematicians in the crowd may recognize the previous values as the sine and cosine of a 30° angle. When you put the rotation angle vectors together, you get a rotation matrix. This rotation matrix is defined in terms of the sine and cosine values of the rotation angles. Defining the rotations in matrix notation this way has several advantages, most of which are beyond the scope of this article. For more information, the rotation matrix article on wikipedia is a great place to start.
The component's location and rotation information is easily accessible through the NXOpen API. With this information, it isn't too much trouble to move the component back to the absolute position. All we need to do is find a matrix that is the inverse of the current rotation matrix, rotate the component according to this new rotation matrix, then translate the component back to the origin. You may be thinking "matrix inverse? I'm outta here...", but wait a moment, because I see the mathematician smiling. Why is he smiling, does the thought of L-U decomposition get his blood racing? Well, possibly; but I think he knows a trick that will make this problem easier than it sounds...
Your rotation matrix contains 3 rows and 3 columns; this makes it a square matrix. One of the useful properties of a square matrix is that the inverse is the same as the transpose.
If the term "matrix inverse" made you instinctively reach for your favorite headache medicine, rest assured that performing a matrix transpose is much easier than finding the inverse. This property of square matrices will really come in handy for this journal. The transpose really is the trickiest part of this journal; it is not tricky in the sense of being difficult, but rather it is easy to make an error while typing which would result in a difficult to track down bug in our code.
To perform the transpose, we simply have to switch the row and column values in the matrix. So the following matrix:
1 2 3 4 5 6 7 8 9
1 4 7 2 5 8 3 6 9
You can see how the values in the first column (1, 4, 7) become the values in the first row. Repeat for the other two columns and you end up with the transpose, which in our case is also the matrix inverse.
Option Strict Off Imports System Imports NXOpen Imports NXOpen.UF Imports NXOpenUI Module componentOriginalPosition Dim theSession As Session = Session.GetSession() Dim workPart As Part = theSession.Parts.Work Sub Main() Dim selComp As NXOpen.Assemblies.Component = Nothing If SelectComponent(selComp) = Selection.Response.Cancel Then Exit Sub End If Dim myInterpartDelay As Boolean = theSession.UpdateManager.InterpartDelay Dim pt As Point3d Dim RotMat As Matrix3x3 Dim pt2 As Vector3d Dim RotMat2 As Matrix3x3 selComp.GetPosition(pt, RotMat) 'msgbox("Translation: " & pt.x & ", " & pt.y & ", " & pt.z) 'msgbox("Rotation: " & vbcrlf & _ ' RotMat.xx & ", " & RotMat.xy & ", " & RotMat.xz & vbcrlf & _ ' RotMat.yx & ", " & RotMat.yy & ", " & RotMat.yz & vbcrlf & _ ' RotMat.zx & ", " & RotMat.zy & ", " & RotMat.zz) 'no translation of component on first pass pt2.X = 0 pt2.Y = 0 pt2.Z = 0 'transpose of the rotation matrix, undo any rotations on the component RotMat2.Xx = RotMat.Xx RotMat2.Xy = RotMat.Yx RotMat2.Xz = RotMat.Zx RotMat2.Yx = RotMat.Xy RotMat2.Yy = RotMat.Yy RotMat2.Yz = RotMat.Zy RotMat2.Zx = RotMat.Xz RotMat2.Zy = RotMat.Yz RotMat2.Zz = RotMat.Zz 'avoid problems if the part contains wave links or other interpart data theSession.UpdateManager.InterpartDelay = True 'move the component back to the original rotation workPart.ComponentAssembly.MoveComponent(selComp, pt2, RotMat2) 'get the translation information again, now that the component has been rotated back to absolute selComp.GetPosition(pt, RotMat) 'negate the translations that have been applied to the component pt2.X = -pt.X pt2.Y = -pt.Y pt2.Z = -pt.Z 'set rotation matrix to identity matrix, we want no new rotations on the component 'or simply use RotMat returned from GetPosition, as it will be the identity matrix 'after the component has been rotated back to its original position RotMat2.Xx = 1 RotMat2.Xy = 0 RotMat2.Xz = 0 RotMat2.Yx = 0 RotMat2.Yy = 1 RotMat2.Yz = 0 RotMat2.Zx = 0 RotMat2.Zy = 0 RotMat2.Zz = 1 'translate component back to 0,0,0 workPart.ComponentAssembly.MoveComponent(selComp, pt2, RotMat2) 'reset interpart delay to original value theSession.UpdateManager.InterpartDelay = myInterpartDelay End Sub Function SelectComponent(ByRef selObj As TaggedObject) As Selection.Response Dim theUI As UI = UI.GetUI Dim message As String = "Select component to reset position" Dim title As String = "Select a Component" 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.AnyInAssembly Dim selectionMask_array(0) As Selection.MaskTriple With selectionMask_array(0) .Type = UFConstants.UF_component_type .Subtype = UFConstants.UF_all_subtype End With Dim resp As Selection.Response = theUI.SelectionManager.SelectTaggedObject(message, _ 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 GetUnloadOption = NXOpen.UF.UFConstants.UF_UNLOAD_IMMEDIATELY End Function End Module
In this article we looked at how to get the component's location and orientation information. We then used that information to move the component back to the absolute origin. You've also seen how to use the .MoveComponent method and how to temporarily turn off the interpart update option. Hopefully, these methods will come in handy when creating your own journals.
1) The code above is meant to be used on components that do not have constraints applied to them. If the journal is run on a component that has constraints applied to it, the component will move only insofar as the constraints allow.
2) The interpart update is turned off while moving the component because otherwise errors may occur during the move process if the component is involved in a wave link operation.