Hey everyone!
I've been trying my best to get familiar with the Autodesk Inventor COM API for the purpose of integrating a new 3D input device (the Keyglove) for intuitive control. I have worked through the "My first plugin" example, and I have basic COM integration working using VB.NET in Visual Studio 2010. I've been able to rotate the camera's view around a single axis by applying a rotation matrix transform to the camera's UpVector property:
Dim Pi As Double = 3.14159265358979
Dim appInventor As Inventor.Application
Dim oCamera As Inventor.Camera
Dim oRotAxis As Inventor.Vector
Dim oRotMatrix As Inventor.Matrix
Dim oUpVector As Inventor.UnitVector
Try
appInventor = System.Runtime.InteropServices.Marshal.GetActiveObject("Inventor.Application")
oCamera = appInventor.ActiveView.Camera
oRotMatrix = appInventor.TransientGeometry.CreateMatrix
Catch ex As Exception
appInventor = Nothing
MsgBox("Unable to locate running Autodesk Inventor instance: " & ex.Message)
End Try
If Not appInventor Is Nothing Then
' apply rotation around camera's Z axis
oUpVector = oCamera.UpVector
oRotAxis = appInventor.TransientGeometry.CreateVector(oCamera.Target.X - oCamera.Eye.X, oCamera.Target.Y - oCamera.Eye.Y, oCamera.Target.Z - oCamera.Eye.Z)
Call oRotMatrix.SetToRotation(Pi / 4, oRotAxis, oCamera.Eye)
Call oUpVector.TransformBy(oRotMatrix)
oCamera.UpVector = oUpVector
oCamera.ApplyWithoutTransition()
End If
...and I've been able to rotate around the other two axes by using the Camera.ComputeWIthMouseInput() method:
' apply rotation around camera's X and Y axes
oCamera.ComputeWithMouseInput(appInventor.TransientGeometry.CreatePoint2d(0, 0), appInventor.TransientGeometry.CreatePoint2d(5, 5), 0, Inventor.ViewOperationTypeEnum.kRotateViewOperation)
But I cannot for the life of me figure out how to achieve what I'm really after: a programmatic equivalent to the "Orbit" action that is done on all three rotational axes at once. I would ultimately like to reproduce all aspects of the Full Navigation Wheel through the COM API, but right now I'll settle for 3D orbiting. The pan and zoom operations seem to be doable through the ComputeWithMouseInput() method, though I'd imagine there's a better, more direct way to do that with raw camera eye/target transformation as well.
When using the Orbit tool on the Full Navigation Wheel, the mouse X/Y axes control orientation about the Y and X axes respectively, centered around the pivot point. If you hold down shift to enable "roll" mode, the mouse Y axis is ignored, and the mouse X axis controls orientation about the Z axis. The Keyglove provides angular rotation data on all three axes at once, so there is no need to toggle between X/Y control and Z control; it should be easily possible to do them all at the same time. I can't figure out how though.
Has anyone done this kind of thing before, or can you provide any pointers? I feel like I'm really close, but lacking in familiarity with the COM API and/or the ability to visualize and code the correct spatial geometry calculations.
Solved! Go to Solution.
Solved by adam.nagy. Go to Solution.
Reading some more of the API Help reference docs, I think I understand at least why my previous efforts at rotating the up vector by different axes didn't work right. As stated in the API Help, "Setting the up vector does not change the eye or target points, but rotates the camera about the vector defined by the eye and target points." So, it's totally impossible to do anything except rotate around the relative forward/backward Z axis of the camera by changing the up vector.
It seems then that the correct approach to mimic the Orbit tool would be to keep the camera target the same, keep the distance from the eye to the target the same, and rotate the eye around the target on all three axes. This is probably close enough to what I'm going for, but it isn't a true Orbit operation, since the Orbit tool rotates around a movable point that may not be the camera target. API control that is a true interface to the Orbit tool would be preferable.
In the mean time, I'll see if I can make any headway on these rotations. I am guessing that the calculations will go something like this:
Something like that. I may have missed something. As always, any help is appreciated.
Okay, so I've got ALMOST what I'm after, but it's missing a key feature. I got the camera to orbit around all three axes as described in my previous post, but while it mimics the mouse-controlled orbit feature, it's missing an intuitive advantage of a true 3D input device, namely this:
While orbiting with the mouse (not in "Roll" mode, i.e. without holding down Shift), moving the mouse left and right ALWAYS rotates around the vertical axis through the pivot point, and moving the mouse up and down ALWAYS rotates around the horizontal axis through the pivot point perpendicular to the camera's Up vector. So, it rolls "forward" or "backward" relative to the direction you are looking.
So, while orbiting with all three dimensions using gyro rotational values using a wearable device (not just a rotating, spinnable trackball or something), the axes themselves should maintain their rotations as long as the orbit is active. That is to say, tilting "forward" from the initial state should do as the regular orbit tool does (roll the object "forward"), but rotating around the Y axis 90 degrees and THEN tilting the Keyglove forward should actually rotate the object left (since the relative "front" of the object will have been rotated to face left). I cannot figure out how to adjust the rotational axes correctly to make that happen.
Here is my current code. The x/y/zPersistTransform matrices are what I am attempting to use to maintain the right rotation. Notice that when rotating around the X axis, the Y and Z axes are themselves rotated, and a simliar thing happens when rotating around the Y and Z axes. This almost seems to work, but it isn't right. If you take out the x/y/zPersistTransform stuff, it works like the regular Orbit tool...but that's not what I need.
Any pointers?
Dim oCamera As Inventor.Camera = appInventor.ActiveView.Camera
Dim oEye As Inventor.Point = oCamera.Eye
Dim axisTransform As Inventor.Matrix
If xPersistTransform Is Nothing Then
xPersistTransform = appInventor.TransientGeometry.CreateMatrix
yPersistTransform = appInventor.TransientGeometry.CreateMatrix
zPersistTransform = appInventor.TransientGeometry.CreateMatrix
End If
' setup Z axis (from camera eye to camera target)
Dim zAxis As Inventor.Vector = oCamera.Target.VectorTo(oEye)
' setup Y axis (through camera target, vertically perpendicular to Z axis)
axisTransform = appInventor.TransientGeometry.CreateMatrix
Call axisTransform.SetTranslation(zAxis)
Dim yAxis As Inventor.UnitVector = oCamera.UpVector
Call yAxis.TransformBy(axisTransform)
' setup X axis (through camera target, horizontally perpendicular to Z axis)
Dim xAxis As Inventor.UnitVector = oCamera.UpVector
Call xAxis.TransformBy(axisTransform)
axisTransform = appInventor.TransientGeometry.CreateMatrix
Call axisTransform.SetToRotation(Pi / 2, zAxis, oEye)
Call xAxis.TransformBy(axisTransform)
' rotate to maintain our existing rotation
Call xAxis.TransformBy(xPersistTransform)
Call xAxis.TransformBy(yPersistTransform)
Call xAxis.TransformBy(zPersistTransform)
Call yAxis.TransformBy(xPersistTransform)
Call yAxis.TransformBy(yPersistTransform)
Call yAxis.TransformBy(zPersistTransform)
Call zAxis.TransformBy(xPersistTransform)
Call zAxis.TransformBy(yPersistTransform)
Call zAxis.TransformBy(zPersistTransform)
Dim oRotMatrix As Inventor.Matrix
' rotate camera "up" vector around Z axis (position stays the same, but camera rotates)
oRotMatrix = appInventor.TransientGeometry.CreateMatrix
Dim oUpVector As Inventor.UnitVector = oCamera.UpVector
Call oRotMatrix.SetToRotation(gyroZ * Pi / 7200, zAxis, oCamera.Target)
Call oUpVector.TransformBy(oRotMatrix)
Call oRotMatrix.SetToRotation(-gyroZ * Pi / 7200, zAxis, oCamera.Target)
Call xAxis.TransformBy(oRotMatrix)
Call xPersistTransform.TransformBy(oRotMatrix)
Call yAxis.TransformBy(oRotMatrix)
Call yPersistTransform.TransformBy(oRotMatrix)
oCamera.UpVector = oUpVector
' rotate camera eye around X axis (camera eye moves around target point)
oRotMatrix = appInventor.TransientGeometry.CreateMatrix
Call oRotMatrix.SetToRotation(gyroX * Pi / 7200, xAxis.AsVector, oCamera.Target)
Call oEye.TransformBy(oRotMatrix)
Call oRotMatrix.SetToRotation(-gyroX * Pi / 7200, xAxis.AsVector, oCamera.Target)
Call yAxis.TransformBy(oRotMatrix)
Call yPersistTransform.TransformBy(oRotMatrix)
Call zAxis.TransformBy(oRotMatrix)
Call zPersistTransform.TransformBy(oRotMatrix)
' rotate camera eye around Y axis (camera eye moves around target point)
oRotMatrix = appInventor.TransientGeometry.CreateMatrix
Call oRotMatrix.SetToRotation(gyroY * Pi / 7200, yAxis.AsVector, oCamera.Target)
Call oEye.TransformBy(oRotMatrix)
Call oRotMatrix.SetToRotation(-gyroY * Pi / 7200, yAxis.AsVector, oCamera.Target)
Call xAxis.TransformBy(oRotMatrix)
Call xPersistTransform.TransformBy(oRotMatrix)
Call zAxis.TransformBy(oRotMatrix)
Call zPersistTransform.TransformBy(oRotMatrix)
oCamera.Eye = oEye
oCamera.ApplyWithoutTransition()
Hi there,
I think this is what you are trying to do. When you start rotating then you want to rotate round the screen X, Y and Z, and you want to keep rotating around those even if the model got transformed by the rotation.
So I think you just need to store the screen axes:
<code>
PublicClass Form1
PrivateConst unit AsDouble = 0.1
Private Sub left_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles left.Click
ChangeView(unit, 0, 0)
EndSub
Private Sub up_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles up.Click
ChangeView(0, unit, 0)
EndSub
Private Sub right_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles right.Click
ChangeView(-unit, 0, 0)
EndSub
Private Sub down_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles down.Click
ChangeView(0, -unit, 0)
EndSub
Private Sub rotate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rotate.Click
ChangeView(0, 0, unit)
EndSub
Private screenX As Inventor.Vector
Private screenY As Inventor.Vector
Private screenZ As Inventor.Vector
PrivateSub ChangeView(ByVal gyroY AsDouble, ByVal gyroX AsDouble, ByVal gyroZ AsDouble)
Dim appInventor As Inventor.Application = System.Runtime.InteropServices.Marshal.GetActiveObject("Inventor.Application")
Dim oCamera As Inventor.Camera = appInventor.ActiveView.Camera
Dim oGeom As Inventor.TransientGeometry = appInventor.TransientGeometry
' Get screen vectors
If screenX IsNothingThen
screenZ = oCamera.Target.VectorTo(oCamera.Eye)
screenZ.Normalize
screenY = oCamera.UpVector.AsVector
screenX = screenY.CrossProduct(screenZ)
EndIf
' Transform around those axes
Dim rotX As Inventor.Matrix = oGeom.CreateMatrix
rotX.SetToRotation(gyroX, screenX, oCamera.Target)
Dim rotY As Inventor.Matrix = oGeom.CreateMatrix
rotY.SetToRotation(gyroY, screenY, oCamera.Target)
Dim rotZ As Inventor.Matrix = oGeom.CreateMatrix
rotZ.SetToRotation(gyroZ, screenZ, oCamera.Target)
Dim rot As Inventor.Matrix = oGeom.CreateMatrix
rot = rotX
rot.PostMultiplyBy(rotY)
rot.PostMultiplyBy(rotZ)
Dim newEye As Inventor.Point = oCamera.Eye
newEye.TransformBy(rot)
Dim newUp As Inventor.UnitVector = oCamera.UpVector
newUp.TransformBy(rot)
oCamera.Eye = newEye
oCamera.UpVector = newUp
oCamera.ApplyWithoutTransition()
EndSub
Private Sub clear_Click( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles clear.Click
screenX = Nothing
screenY = Nothing
screenZ = Nothing
EndSub
EndClass
</code>
In this sample you click "Clear" once the rotation is finished.
I hope this helps.
______________________________________________________________
If my post answers your question, please click the "Accept as Solution"
button. This helps everyone find answers more quickly!
Brilliant solution, Adam! Far simpler than mine, and it actually works (now that I've had a chance to implement it two weeks later). I really appreciate your expertise. Thanks!
Can't find what you're looking for? Ask the community or share your knowledge.