Hi All,
I would like a ilogic code so that it will move the center point or the origin point of the ipt and the iam file to the center of the body through move bodies command.
In other words I want to be able to design the part and once completed make it symmetrical about the origin coordinates.
Solved! Go to Solution.
Solved by MechMachineMan. Go to Solution.
Solved by MechMachineMan. Go to Solution.
Soooo liiiiikeeee
"Center of the part"?
- What about asymmetical features?
- are you thinking make the C.O.G. the origin?
- or are you thinking of making the origin the center of the envelope
- what if the part is rotated off? do you want to do the necessary functions/math to align the part with the principal axes?
- Again, what about a-symmetrical features?
- are you wanting to do this for parts AND assemblies?
- what if the part is bent and the center of the envelope/ COG is in space, and not located on the part?
etc.
Probably just better to revise your modelling standards and redo files as necessary instead of using a band-aid....
These codes will give me the height width and dept of a body now I would like to, somehow take this information and move my solid body so that the origin of the part is the center of the body.
SyntaxEditor Code Snippet
Measure.ExtentsLength Measure.ExtentsWidth Measure.ExtentsHeight
I can take these codes and divided them by 2. That will give me the center of the Body.
Now I would like to take another measurement from the origin point to the center of the body. Then move that body to match the center of the body to the origin of the file.
I'am more concerned about a .ipt file than an .iam file for now.
Thank you
Also the COG is pointless to me at this time. I would however be interested in rotating a part so that it is parallel with the origin planes.
There are some nice resources out there that should you how to use the bulk of the features.
http://help.autodesk.com/view/INVNTOR/2018/ENU/?guid=GUID-9FDC9B07-E66C-4E08-B764-7D4AD1F6B95B
So for a part, this code will move the FIRST Solid Body about the origin, and not rotate it.
Sub Main() Dim oDoc As PartDocument oDoc = ThisApplication.ActiveDocument If oDoc Is Nothing Then MsgBox("No part document!" & vbCrLf & "Please open a part with solids in it for this sample to run.", vbCritical, "Autodesk Inventor") Exit Sub End If Dim oCompDef As PartComponentDefinition oCompDef = oDoc.ComponentDefinition If oCompDef.SurfaceBodies.Count = 0 Then MsgBox("No solids to move!" & vbCrLf & "Please open a part with solids in it for this sample to run.", vbCritical, "Autodesk Inventor") Exit Sub End If Dim oBodies As ObjectCollection oBodies = ThisApplication.TransientObjects.CreateObjectCollection ' Specify a body to move. oBodies.Add(oCompDef.SurfaceBodies(1)) ' Create a MoveFeatureDefinition. Dim oMoveDef As MoveDefinition oMoveDef = oCompDef.Features.MoveFeatures.CreateMoveDefinition(oBodies) oRangeBox = oBodies.Item(1).RangeBox oMidX = (oRangeBox.MaxPoint.X + oRangeBox.MinPoint.X)/2 oMidY = (oRangeBox.MaxPoint.Y + oRangeBox.MinPoint.Y)/2 oMidZ = (oRangeBox.MaxPoint.Z + oRangeBox.MinPoint.Z)/2 ' the move operations onto the bodies. Dim oFreeDrag As FreeDragMoveOperation oFreeDrag = oMoveDef.AddFreeDrag(-1*oMidX, -1*oMidY, -1*oMidZ) 'Dim oMoveAlongRay As MoveAlongRayMoveOperation 'oMoveAlongRay = oMoveDef.AddMoveAlongRay(oCompDef.WorkAxes(2), True, 2) 'Dim oRotateAboutAxis As RotateAboutLineMoveOperation 'oRotateAboutAxis = oMoveDef.AddRotateAboutAxis(oCompDef.WorkAxes(3), True, 0.5) ' Create the move feature. Dim oMoveFeature As MoveFeature oMoveFeature = oCompDef.Features.MoveFeatures.Add(oMoveDef) End Sub
This works great now I find my self wanting to make this code go a bit further and rotate the body by selecting face of the part of my choosing to be parallel with a plane of my choosing
Thank you!
Having a reference face and a reference plane definitely makes it a lot easier to rotate the part. Although, you would probably end up wanting 2 faces and 2 reference planes so that you can properly align it with the first axis (ie; the one you are looking at) and then one to align it to (ie; making the rectangle parallel to the horiztonal plane instead of diamond shaped).
It might require some more complex matrix math to be able to make it work; haven't looked to much into the available methods, but I would think it's definitely doable.
SyntaxEditor Code Snippet
Sub Main() Dim oDoc As PartDocument oDoc = ThisApplication.ActiveDocument If oDoc Is Nothing Then MsgBox("No part document!" & vbCrLf & "Please open a part with solids in it for this sample to run.", vbCritical, "Autodesk Inventor") Exit Sub End If Dim oCompDef As PartComponentDefinition oCompDef = oDoc.ComponentDefinition If oCompDef.SurfaceBodies.Count = 0 Then MsgBox("No solids to move!" & vbCrLf & "Please open a part with solids in it for this sample to run.", vbCritical, "Autodesk Inventor") Exit Sub End If Dim oBodies As ObjectCollection oBodies = ThisApplication.TransientObjects.CreateObjectCollection ' Specify a body to move. oBodies.Add(oCompDef.SurfaceBodies(1)) ' Create a MoveFeatureDefinition. Dim oMoveDef As MoveDefinition oMoveDef = oCompDef.Features.MoveFeatures.CreateMoveDefinition(oBodies) oRangeBox = oBodies.Item(1).RangeBox oMidX = (oRangeBox.MaxPoint.X + oRangeBox.MinPoint.X)/2 oMidY = (oRangeBox.MaxPoint.Y + oRangeBox.MinPoint.Y)/2 oMidZ = (oRangeBox.MaxPoint.Z + oRangeBox.MinPoint.Z)/2 ' the move operations onto the bodies. Dim oFreeDrag As FreeDragMoveOperation oFreeDrag = oMoveDef.AddFreeDrag(-1*oMidX, -1*oMidY, -1*oMidZ) oRangeBox = oBodies.Item(2).RangeBox oPlane1 = (oRangeBox.ReferenceParameter.Name(ThisApplication.CommandManager.Pick(SelectionFilterEnum.kAllPlanarEntities, "Select Reference Plane 1:"))) oPlane2 = (oRangeBox.ReferenceParameter.Name(ThisApplication.CommandManager.Pick(SelectionFilterEnum.kAllPlanarEntities, "Select Reference Plane 2:"))) oFace1 = (oRangeBox.ReferenceParameter.Name(ThisApplication.CommandManager.Pick(SelectionFilterEnum.kAllPlanarEntities, "Select Reference Face 3:"))) oFace2 = (oRangeBox.ReferenceParameter.Name(ThisApplication.CommandManager.Pick(SelectionFilterEnum.kAllPlanarEntities, "Select Reference Face 3:"))) Dim oMoveAlongRay As MoveAlongRayMoveOperation oMoveAlongRay = oMoveDef.AddMoveAlongRay(oCompDef.WorkAxes(3), True, 2) Dim oRotateAboutAxis1 As RotateAboutLineMoveOperation oRotateAboutAxis1 = oMoveDef.AddRotateAboutAxis(oCompDef.WorkAxes(4), True, oPlane1+oFace1) Dim oRotateAboutAxis2 As RotateAboutLineMoveOperation oRotateAboutAxis2 = oMoveDef.AddRotateAboutAxis(oCompDef.WorkAxes(5), True, oPlane2+oFace2) ' Create the move feature. Dim oMoveFeature As MoveFeature oMoveFeature = oCompDef.Features.MoveFeatures.Add(oMoveDef) End Sub
receiving this error
Error in rule: Rule0, in document: Part5
The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
Not sure what wrong. but I think this is close to what I want.
Sounds like it's time for debugging!
Either convert it to vba so you can step through lines to debug,
Or start at line (1), write MsgBox("here"). Run code. if you see the message box, you know the error occurs below there.
Find what line gives you errors and report back.
Good luck!
Ok! I decided to try and simplify what I am trying to do I'm getting it to rotate, But when I use ilogic to measure the angle it spit out a CRAZY number.
I don't understand how it getting that number.
I know this is not exactly what I asked for but if I can get this to work exactly like I want it to its one step closer.
Here is the file I have 2 separate codes one moves the body and the other one put the measured angle in the description of the part witch is right but when I use the same code it when i rotate the part it come up with something completely different.
BTW sorry for the late response I have only been working on this on my free time.
1. Initialize + declare variables properly
Dim angle As Decimal angle = 0
OR
Dim angle As Double
angle = 0
'Do things
2. Ensure you are converting units properly from/to database units.
Inventor's database units for angles is: RADIANS. Therefore Angle (degrees) = Angle (radians) x (180/pi) This conversion factor is approximately 57.29578.
Further database unit reading:
http://help.autodesk.com/view/INVNTOR/2018/ENU/?guid=GUID-60CADB1E-DB85-4A7D-8380-7C4FFFE558D8
I have made a lot of progress however I don't understand what exactly its doing?
Thank you!
Yeah... The physics of it gets very convoluted when dealing with complex rotations, and your code doesn't handle that.
Either you need to create a 3rd axis that is perpendicular to the 2 planes that the normals lie on to use as your basis of rotation, or you need to use projects to establish exactly how much you need to rotate it about the specified origin axes.
There is definitely a lot more math to figure out than what you have currently, which is necessary for being able to get the code up and running properly.
Give this behemoth a whirl. Please note that it is a macro, so you will need to use the vba environment to run it.
From there you can add it to keyboard shortcuts to make it work, or run it from the Macro Menu.
What the rule does is force you to select 2 orthogonal faces and aligns the first one with the xy plane, and the 2nd one with the xz plane.
Sub Main() Dim oDoc As PartDocument Set oDoc = ThisApplication.ActiveDocument If oDoc Is Nothing Then MsgBox "No part document!" & vbCrLf & "Please open a part with solids in it for this sample to run.", vbCritical, "Autodesk Inventor" Exit Sub End If Dim oCompDef As PartComponentDefinition Set oCompDef = oDoc.ComponentDefinition If oCompDef.SurfaceBodies.Count = 0 Then MsgBox "No solids to move!" & vbCrLf & "Please open a part with solids in it for this sample to run.", vbCritical, "Autodesk Inventor" Exit Sub End If Dim oBodies As ObjectCollection Set oBodies = ThisApplication.TransientObjects.CreateObjectCollection ' Specify a body to move. oBodies.Add oCompDef.SurfaceBodies(1) Call RotatePart(oCompDef, oBodies) oBodies.Clear oBodies.Add oCompDef.SurfaceBodies(1) Call MovePart(oCompDef, oBodies) End Sub Sub RotatePart(ByVal oCompDef As ComponentDefinition, ByVal oBodies As ObjectCollection) 'http://adndevblog.typepad.com/manufacturing/2012/08/what-is-the-best-way-to-compute-a-normal-of-a-face-in-inventor-api.html ' Create a MoveFeatureDefinition. Dim oMoveDef As MoveDefinition Set oMoveDef = oCompDef.Features.MoveFeatures.CreateMoveDefinition(oBodies) Dim Face1 As Face Dim Face2 As Face Dim boolFace1IsPlane As Boolean boolFace1IsPlane = False Do Set Face1 = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFaceFilter, "Pick FACE to align with XY Plane (FRONT)") If (TypeOf Face1.Geometry Is Plane) Then boolFace1IsPlane = True End If Loop Until boolFace1IsPlane Dim oFace1Normal As Vector Set oFace1Normal = ThisApplication.TransientGeometry.CreateVector() Set oFace1Normal = GetFaceNormal(Face1) Dim boolFace2IsPlane As Boolean boolFace2IsPlane = False Dim boolPlanesat90 As Boolean boolPlanesat90 = False Dim oFace2Normal As Vector Set oFace2Normal = ThisApplication.TransientGeometry.CreateVector() Do boolFace2IsPlane = False Do Set Face2 = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFaceFilter, "Pick FACE to align with XZ Plane (TOP)") If (TypeOf Face2.Geometry Is Plane) Then boolFace1IsPlane = True End If Loop Until boolFace1IsPlane Set oFace2Normal = GetFaceNormal(Face2) 'Perpindicular vectors have dot product of zero. 'Need to handle round of errors in doing the large vectors maths If VBA.Round(oFace1Normal.DotProduct(oFace2Normal), 8) = 0 Then boolPlanesat90 = True End If Loop Until boolPlanesat90 Dim oYZPlane As WorkPlane Dim oXZPlane As WorkPlane Dim oXYPlane As WorkPlane Set oYZPlane = oCompDef.WorkPlanes.Item(1) Set oXZPlane = oCompDef.WorkPlanes.Item(2) Set oXYPlane = oCompDef.WorkPlanes.Item(3) Dim oXAxis As WorkAxis Set oXAxis = oCompDef.WorkAxes(1) Dim oYAxis As WorkAxis Set oYAxis = oCompDef.WorkAxes(2) Dim oZAxis As WorkAxis Set oZAxis = oCompDef.WorkAxes(3) 'Perform first rotation to align with coord system Dim oRotationAngle As Double oRotationAngle = GetRotationAngleAboutAxisToPlane(oFace1Normal, oXAxis, oXYPlane) 'oRotationAngle = GetRotationAngleAboutAxisToPlane(ThisApplication.TransientGeometry.CreateVector(oFace1Normal.X, oFace1Normal.Y, oFace1Normal.Z), oXAxis, oXYPlane) Dim oRotateAboutAxis As RotateAboutLineMoveOperation Set oRotateAboutAxis = oMoveDef.AddRotateAboutAxis(oXAxis, True, oRotationAngle) Dim oRes1Vector As Vector Set oRes1Vector = ThisApplication.TransientGeometry.CreateVector() Set oRes1Vector = RotateVectorAboutAnotherVector(oRotationAngle, oFace1Normal, ThisApplication.TransientGeometry.CreateVector(oXAxis.Line.Direction.X, oXAxis.Line.Direction.Y, oXAxis.Line.Direction.Z)) Dim oRes1UpVector As Vector Set oRes1UpVector = ThisApplication.TransientGeometry.CreateVector() Set oRes1UpVector = RotateVectorAboutAnotherVector(oRotationAngle, oFace2Normal, ThisApplication.TransientGeometry.CreateVector(oXAxis.Line.Direction.X, oXAxis.Line.Direction.Y, oXAxis.Line.Direction.Z)) 'Perform 2nd rotation to align with coord system 'oRotationAngle = GetRotationAngleAboutAxisToPlane(oFace1Normal, oYAxis, oXYPlane) oRotationAngle = GetRotationAngleAboutAxisToPlane(oRes1Vector, oYAxis, oXYPlane) Set oRotateAboutAxis = oMoveDef.AddRotateAboutAxis(oYAxis, True, oRotationAngle) Dim oRes2UpVector As Vector Set oRes2UpVector = ThisApplication.TransientGeometry.CreateVector() Set oRes2UpVector = RotateVectorAboutAnotherVector(oRotationAngle, oRes1UpVector, ThisApplication.TransientGeometry.CreateVector(oYAxis.Line.Direction.X, oYAxis.Line.Direction.Y, oYAxis.Line.Direction.Z)) 'Perform 3rd rotation to get Upvector oriented properly. oRotationAngle = GetRotationAngleAboutAxisToPlane(oRes2UpVector, oZAxis, oXZPlane) Set oRotateAboutAxis = oMoveDef.AddRotateAboutAxis(oZAxis, True, oRotationAngle) Dim oMoveFeature As MoveFeature Set oMoveFeature = oCompDef.Features.MoveFeatures.Add(oMoveDef) End Sub Function GetFaceNormal(ByVal oFace As Object) As Vector Dim oNormal As Vector Dim Params(1 To 2) As Double Dim Normals(1 To 3) As Double Params(1) = 0 Params(2) = 0 If TypeOf oFace Is WorkPlane Then Call oFace.Plane.Evaluator.GetNormal(Params, Normals) Set oNormal = ThisApplication.TransientGeometry.CreateVector(Normals(1), Normals(2), Normals(3)) Else If (TypeOf oFace.Geometry Is Plane) Then 'Dim oEvalFace As Face 'Set oEvalFace = oFace Call oFace.Evaluator.GetNormal(Params, Normals) Set oNormal = ThisApplication.TransientGeometry.CreateVector(Normals(1), Normals(2), Normals(3)) End If End If Set GetFaceNormal = oNormal End Function Function GetRotationAngleAboutAxisToPlane(ByVal oVector As Vector, ByVal oAxis As WorkAxis, ByVal oWorkPlane As WorkPlane) As Double ''http://onlinemschool.com/math/library/vector/angl/ 'This ProjectVectorToPlane removes the 1 of the 3 components in relation to the plane. 'IN this case, to the YZ plane, it essentially removes the X component and scales it slightly. 'Verified method below also works, but gives same results as the formulaic method. 'Dim AltProject As Vector 'Set AltProject = ThisApplication.TransientGeometry.CreateVector(0, oFace1Normal.Y, oFace1Normal.Z) 'Angle is insufficient as it doesn't have a direction. 'Use Cross product to find the angle and direction ' Length of this crossproduct is actually the area of the parallellogram of A & B ' The vector gives the direction 'If the vectors x component is positive, it means that we need to rotate 'it the same direction as the x axis (ie cw), and if its negative, we rotate it the negative direction Dim oLineDir As Variant Set oLineDir = oAxis.Line.Direction 'oLine.Direction (oCoords) Dim oAxisVector As Vector Set oAxisVector = ThisApplication.TransientGeometry.CreateVector(oLineDir.X, oLineDir.Y, oLineDir.Z) 'oRotationAngle = AltProject.AngleTo(oYVector) Dim oProjVec As Vector Set oProjVec = ThisApplication.TransientGeometry.CreateVector() 'Project to plane perpindicular to plane Set oProjVec = ProjectVectorToPerpindicularPlaneOfAnAxis(oVector, oAxisVector) 'Get the Dim oWorkPlaneNormal As Vector Set oWorkPlaneNormal = ThisApplication.TransientGeometry.CreateVector() Set oWorkPlaneNormal = GetFaceNormal(oWorkPlane) Dim oCrossProductVector As Vector Set oCrossProductVector = ThisApplication.TransientGeometry.CreateVector Set oCrossProductVector = oWorkPlaneNormal.CrossProduct(oProjVec) oAngle = ArcSin(oCrossProductVector.Length / (oWorkPlaneNormal.Length * oProjVec.Length)) rotdir = 1 If oAxisVector.DotProduct(oCrossProductVector) > 0 Then rotdir = -1 End If GetRotationAngleAboutAxisToPlane = rotdir * oAngle End Function Function ProjectVectorToPerpindicularPlaneOfAnAxis(ByVal oVector As Vector, ByVal oPlaneNormal As Vector) As Vector 'https://www.maplesoft.com/support/help/maple/view.aspx?path=MathApps%2FProjectionOfVectorOntoPlane 'Projected vector = orig vector(term1) - (dp(u*N)/mag(n)^2)*n Dim oByValVector As Vector Set oByValVector = ThisApplication.TransientGeometry.CreateVector(oVector.X, oVector.Y, oVector.Z) Dim oByValPlaneNormal As Vector Set oByValPlaneNormal = ThisApplication.TransientGeometry.CreateVector(oPlaneNormal.X, oPlaneNormal.Y, oPlaneNormal.Z) Dim oDotproductxun As Double oDotproductxun = oByValVector.DotProduct(oByValPlaneNormal) If oDotproductxun <> 0 Then Dim magxn As Double oMagxn = oByValPlaneNormal.Length Dim oScalarComponent As Double oScalarComponent = (oDotproductxun) / (oMagxn * oMagxn) Call oByValPlaneNormal.ScaleBy(oScalarComponent) Call oByValVector.SubtractVector(oByValPlaneNormal) End If Set ProjectVectorToPerpindicularPlaneOfAnAxis = oByValVector End Function Function ArcSin(ByVal X As Double) As Double 'http://cuinl.tripod.com/Tips/math9.htm ArcSin = Atn(X / Sqr(-X * X + 1)) End Function Function RotateVectorAboutAnotherVector(ByVal oTheta As Double, ByVal oRotatingVector As Vector, ByVal oStationaryVector As Vector) As Vector 'Let A be the rotating vector 'Let B be the stationary vector Dim oVectorA As Vector Dim oVectorB As Vector Set oVectorA = ThisApplication.TransientGeometry.CreateVector(oRotatingVector.X, oRotatingVector.Y, oRotatingVector.Z) Set oVectorB = ThisApplication.TransientGeometry.CreateVector(oStationaryVector.X, oStationaryVector.Y, oStationaryVector.Z) Dim oMatrix As Matrix Set oMatrix = ThisApplication.TransientGeometry.CreateMatrix Call oMatrix.SetToRotation(oTheta, oVectorB, ThisApplication.TransientGeometry.CreatePoint(0, 0, 0)) Call oVectorA.TransformBy(oMatrix) Set RotateVectorAboutAnotherVector = oVectorA End Function Sub MovePart(ByVal oCompDef As ComponentDefinition, ByVal oBodies As ObjectCollection) Dim oMoveDef As MoveDefinition Set oMoveDef = oCompDef.Features.MoveFeatures.CreateMoveDefinition(oBodies) Set oRangeBox = oBodies.Item(1).RangeBox oMidX = (oRangeBox.MaxPoint.X + oRangeBox.MinPoint.X) / 2 oMidY = (oRangeBox.MaxPoint.Y + oRangeBox.MinPoint.Y) / 2 oMidZ = (oRangeBox.MaxPoint.Z + oRangeBox.MinPoint.Z) / 2 Dim oFreeDrag As FreeDragMoveOperation Set oFreeDrag = oMoveDef.AddFreeDrag(-1 * oMidX, -1 * oMidY, -1 * oMidZ) Dim oMoveFeature As MoveFeature Set oMoveFeature = oCompDef.Features.MoveFeatures.Add(oMoveDef) End Sub
I stumbled across a reference to this thread in another that we both had responded to. My company regularly uses multisolid modeling (sometimes combined with Frame Generator) for designing steel weldments. Occasionally this involves some plates at awkward orientations, which cause trouble for some of our iLogic rules. Currently we use the Direct Edit tools to correct the orientation of such parts, which works just fine, but this macro will definitely save us some time.
One limitation I came across is that the macro can't handle a cylindrical body, since it requires two faces. The macro is certainly useful as-is, but if you have the desire to tinker with it further, adding an option that lets you select a face and an axis (instead of two faces) might be beneficial.
Other than that odd case, the macro seems to work very well, and is more thorough than we normally are when doing this manually (fixing not just the orientation, but actually centering the part at the origin). Nicely done.
I suggest temporarily exctruding a flat face on one of the round edges of the cylinder so it has a reference, then deleting the temporary extrude after (as the macro does all the calcs and inputs the rotations as a fixed value).
All joking aside - even though that workaround should technically work - thanks a bunch for testing it out and getting back to me on it! If there is more interest in the macro, I may review it in the future, but at least for now the bulk of it is out in the public realm for people to tweak and use as they want.
Can't find what you're looking for? Ask the community or share your knowledge.