- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Struggle with matrix
Hi,
I'm having trouble to get a rotation of a Occurrence.
I want to rotate it with 3 angles.
The thing that I can't figure out is how to combine three SetToRotation to get the specific rotation.
Let's say I first rotate around Z-axis 90 degrees. After that I want to rotate around my Occurrence new X-direction (the assemby Y-dir). And after that rotate around the Occurrence new Y-direction.
The only sultion I can create is the one that always rotates around the assembly axes.. But that is not what I want.
So is there someone how can guide me in the right direction to have an Occurrence to rotate around it's own axes and not the assembly axes?
Regards
Rikard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Yes.
You need to fetch the Axes from the occurrence in the context of the assembly by using a Proxy.
With this WorkAxisProxy, you can then do the necessary vector maths to rotate this peice.
Also, the settoRotation and rotate functions are weird. I was having issues trying to use them, so I just went back to straight vector/matrix math. Although it's a little more programming, it is easier to understand/control it seems.
'This is actually a tough one because it depends on what axis you rotate about first. Just think about it.
Sub Main()
Dim oFloorNormalSelected = "Y"
Dim oDoc As Document
oDoc = ThisApplication.ActiveDocument
Dim oOcc As ComponentOccurrence
Dim oSelectSet As SelectSet
oSelectSet = oDoc.SelectSet
If oSelectSet.Count = 1
oOcc = oSelectSet.Item(1)
Else
MsgBox("Invalid Selection Set!" & vbLf & vbLf & "Aborting rule!")
Exit Sub
End If
If oFloorNormalSelected = ""
r = InputBox("Set values of relative rotation of occurence in context of assembly:" & vbLf & "X:90 OR other format for reset", "Rotation", "X:0")
Try
Dim substring() As String = r.Split(":")
Call RotateOccurrence(oDoc, oOcc, substring(1), substring(0))
Catch
Call RotateOccurrence(oDoc, oOcc, 0, "")
End Try
Else
r = InputBox("Set values of relative rotation of occurence in context of assembly:" & vbLf & vbLf & "ie; 90" & vbLf & "or make blank for current rotations", "Rotation", "0")
Try
Call RotateOccurrence(oDoc, oOcc, r, oFloorNormalSelected)
Catch
GetCurrentRotation(oDoc, oOcc)
End Try
End If
End Sub
Sub RotateOccurrence(oAsmDoc As Document, oOcc As ComponentOccurrence, oRotationDeg As Double, oAxis As String)
Dim oTG As TransientGeometry = ThisApplication.TransientGeometry
Dim oRx As Matrix
oRx = oTG.CreateMatrix()
oRx.Cell(2,2) = Math.Cos(oRotationDeg*Math.PI/180)
oRx.Cell(2,3) = -Math.Sin(oRotationDeg*Math.PI/180)
oRx.Cell(3,2) = Math.Sin(oRotationDeg*Math.PI/180)
oRx.Cell(3,3) = Math.Cos(oRotationDeg*Math.PI/180)
Dim oRy As Matrix
oRy = oTG.CreateMatrix()
oRy.Cell(1,1) = Math.Cos(oRotationDeg*Math.PI/180)
oRy.Cell(1,3) = Math.Sin(oRotationDeg*Math.PI/180)
oRy.Cell(3,1) = -Math.Sin(oRotationDeg*Math.PI/180)
oRy.Cell(3,3) = Math.Cos(oRotationDeg*Math.PI/180)
Dim oRz As Matrix
oRz = oTG.CreateMatrix()
oRz.Cell(1,1) = Math.Cos(oRotationDeg*Math.PI/180)
oRz.Cell(1,2) = -Math.Sin(oRotationDeg*Math.PI/180)
oRz.Cell(2,1) = Math.Sin(oRotationDeg*Math.PI/180)
oRz.Cell(2,2) = Math.Cos(oRotationDeg*Math.PI/180)
Dim oOccTransform As Matrix = oOcc.Transformation
Dim oTransVec As Vector = oOccTransform.Translation
Select Case True
Case oAxis = "X"
oOccTransform.PreMultiplyBy(oRx)
Case oAxis = "Y"
oOccTransform.PreMultiplyBy(oRy)
Case oAxis = "Z"
oOccTransform.PreMultiplyBy(oRz)
Case Else
MsgBox("Error in rotating matrix; returning to identity")
oOccTransform.SetToIdentity
End Select
oOccTransform.SetTranslation(oTransVec, False)
oOcc.SetTransformWithoutConstraints(oOccTransform)
'PrintMatrix(oOccTransform)
End Sub
Sub PrintMatrix(oMatrix As Matrix)
For i = 4 To 1 Step -1
For j = 4 To 1 Step -1
oStr = oMatrix.Cell(i,j) & " " & oStr
Next
oStr = vbLf & oStr
Next
MsgBox(oStr)
End Sub
--------------------------------------
Did you find this reply helpful ? If so please use the 'Accept as Solution' or 'Like' button below.
Inventor 2018.2.3, Build 227 | Excel 2013+ VBA
ERP/CAD Communication | Custom Scripting
Machine Design | Process Optimization
iLogic/Inventor API: Autodesk Online Help | API Shortcut In Google Chrome | iLogic API Documentation
Vb.Net/VBA Programming: MSDN | Stackoverflow | Excel Object Model
Inventor API/VBA/Vb.Net Learning Resources: Forum Thread
Sample Solutions:Debugging in iLogic ( and Batch PDF Export Sample ) | API HasSaveCopyAs Issues |
BOM Export & Column Reorder | Reorient Skewed Part | Add Internal Profile Dogbones |
Run iLogic From VBA | Batch File Renaming| Continuous Pick/Rename Objects
Local Help: %PUBLIC%\Documents\Autodesk\Inventor 2018\Local Help
Ideas: Dockable/Customizable Property Browser | Section Line API/Thread Feature in Assembly/PartsList API Static Cells | Fourth BOM Type
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hy Mech,
I need a similar code, cane you change it for me?
Have to read out the Angles of each part, not set it.
I already have the code to iterate trough each part of an assembly and get the transformation in XYZ.
What i need is the piece of code which reads back the Angles of each part.
Before I struggle to rewrite and destroy your code, may you have a quick idea how to do that.
Thanks in advance
Simon
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi,
I think this is what you are looking for..
Regards
Rikard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi Rikard,
Thank you, I have found this piece before too.
Dos not work, I like to make it via iLogic.
I have an assembly, i iterate through each part and send each part his relative XYZ coordinates and save them in the part parameters. I will need them for a later operation.
So this works, but I will also need the Angles relative to the assembly origin, and here it starts to be complicated.
In the Forum I only can find posts dealing with the manipulation of this matrix, I "only" have to read em out.
So i my view the approach from @MechMachineMan is the most logical I have found so far, but it needs to be changed.
Thanks a lot
Simon
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello
How do you get the part position relativ to assembly space? If you've created a proxy object, then I think you can also get the angles from there. If you save data to part parameters, what about a part occurs multiple times in your assembly? Which position will be saved?
Can you try this iLogic version?
Sub Main
Dim oAssDoc As Inventor.AssemblyDocument = ThisDoc.Document
GetAngleOfOccurence(oAssDoc.ComponentDefinition.Occurrences)
End Sub
' a few helper functions...
Private Function Atan2(y As Double, x As Double)
' returned value is in radians
If x > 0 Then
Atan2 = Atan(y / x)
ElseIf (x < 0 And y >= 0) Then
Atan2 = Atan(y / x) + PI
ElseIf (x < 0 And y < 0) Then
Atan2 = Atan(y / x) - PI
ElseIf (x = 0 And y > 0) Then
Atan2 = PI / 2
ElseIf (x = 0 And y < 0) Then
Atan2 = -PI / 2
ElseIf (x = 0 And y = 0) Then
Atan2 = 0
End If
End Function
Private Function EulerThree(trans() As Double) As Double
' returned value is in radians
If (trans(8) <> 1 And trans(8) <> -1) Then
EulerThree = Atan2(trans(4) / Cos(Asin(trans(8))), trans(0) / Cos(Asin(trans(8))))
Else
EulerThree = 0
End If
End Function
Private Function EulerTwo(trans() As Double) As Double
' returned value is in radians
If (trans(8) <> 1 And trans(8) <> -1) Then
EulerTwo = -Asin(trans(8))
ElseIf (trans(8) = -1) Then
EulerTwo = PI / 2
Else
EulerTwo = -PI / 2
End If
End Function
Private Function EulerOne(trans() As Double) As Double
' returned value is in radians
If (trans(8) <> 1 And trans(8) <> -1) Then
EulerOne = Atan2(trans(9) / Cos(Asin(trans(8))), trans(10) / Cos(Asin(trans(8))))
ElseIf (trans(8) = -1) Then
EulerOne = Atan2(trans(1), trans(2))
Else
EulerOne = Atan2(-trans(1), -trans(2))
End If
End Function
Private Function EulerAngles(trans() As Double)
'convert from radian to degree
Dim eulers(2) As Double
eulers(0) = EulerOne(trans) * 180 / PI
eulers(1) = EulerTwo(trans) * 180 / PI
eulers(2) = EulerThree(trans) * 180 / PI
EulerAngles = eulers
End Function
'finally the function that retrieves the rotations:
Sub GetAngleOfOccurence(oOccs As ComponentOccurrences)
' Traverse all referenced occurences in the assembly
For Each oOcc As ComponentOccurrence In oOccs
Dim trans(16) As Double
Dim oMatrix As Matrix
'is occurrence part or subassembly?
If oOcc.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
GetAngleOfOccurence(oOcc.SubOccurrences)
ElseIf oOcc.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then
Dim oOccProxy As ComponentOccurrenceProxy
oOcc.CreateGeometryProxy(oOcc,oOccProxy)
oMatrix = oOccProxy.Transformation
' insert point is in the matrix:
Call oMatrix.GetMatrixData(trans) ' get the matrix as an Array
'test if we get an array..
If (Not trans Is Nothing And IsArray(trans)) Then
Logger.Debug("")
Logger.Debug(oOcc.Name)
Logger.Debug("Insert point (cm)")
Logger.Debug("X=: " & Round(trans(3),2))
Logger.Debug("Y=: " & Round(trans(7),2))
Logger.Debug("Z=: " & Round(trans(11),2))
End If
' invert matrix to get the parts transform in the assembly's coordinates
Call oMatrix.Invert
' be aware that retrieving the eulers from the matrix may not produce the result you would expect.
' you should keep to the matrix if you can.
Call oMatrix.GetMatrixData(trans) ' get the matrix as an Array
'test if we get an array..
If (Not trans Is Nothing And IsArray(trans)) Then
Dim result() As Double
result = EulerAngles(trans)
Logger.Debug( "Euler 1=: " & Round(result(0),2))
Logger.Debug ("Euler 2=: " & Round(result(1),2))
Logger.Debug ("Euler 3=: " & Round(result(2),2))
End If
End If
Next
End Sub
R. Krieg
RKW Solutions
www.rkw-solutions.com
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Don t work, The system did not recognize the "Logger" term.
Anyway thank you!
I try to implement your Sub:
Sub GetAngleOfOccurence(oOccs As ComponentOccurrences)
Into my code to see if it work this way
Iwait until @MechMachineMan gives me an update, his code seems much more logical to me and i can implement it.
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello
What do you mean with "not recognize"? The term prints out the data to the iLogic protocol window. If you set protocol level in iLogic Editor to "Debug" and make iLogic protocol window tab visible, you'll see the output.
I've tested this more than one time, it works.
R. Krieg
RKW Solutions
www.rkw-solutions.com
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello
This option is not avaiable?
R. Krieg
RKW Solutions
www.rkw-solutions.com
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report