Hi,
I recently got help with writing iLogic code for a part file that takes user input and calculates Area, Ix, and Iy values,
and modifies an existing iProperty. To begin, the user has to run the code, pick a planar face, and then the calculations are made and the values are saved as custom iProperties. Then, in my drawing file template, I specified the custom iProperties as text parameters in the Format Text dialog box so that the values automatically appear once a view of the part is loaded.
My question is, what I can do to improve my iLogic code and make it more robust? Is there anything that might make it stop working or "crash"? Are there any potential issues with my code that anyone sees? I am new to iLogic, so I'm not sure what I can do to make sure my code runs well without issues. I've posted a view of my code below.
Thanks.
My Code:
Solved! Go to Solution.
Solved by philip1009. Go to Solution.
Solved by philip1009. Go to Solution.
Try crash it yourself.
ie try select non-plane. Try a part with non-flat surface.
Run iLogic without part in file.
If the code keeps running consistently without issues, then there's really no reason to change it. There are conditions that you can put in to make sure that:
1) The code is run in a part file, although really only necessary if it's an external rule.
2) Make sure there is a solid body in the part file.
3) Make sure there is a flat face available for selection.
4) Make sure that selected face is part of the solid body instead of something else like a work plane.
If ThisApplication.ActiveDocument.DocumentType <> DocumentTypeEnum.kPartDocumentObject Then MsgBox("Part File must be Active.") Exit Sub End If If ThisApplication.ActiveDocument.ComponentDefinition.SurfaceBodies.Count = 0 Then MsgBox("Part File must contain a body.") Exit Sub End If blnPlanarFaceCheck = False For Each objSurfaceBody As SurfaceBody In ThisApplication.ActiveDocument.ComponentDefinition.SurfaceBodies For Each objFace As Face In objSurfaceBody.Faces If objFace.SurfaceType = SurfaceTypeEnum.kPlaneSurface Then blnPlanarFaceCheck = True GoTo jmpFaceCheck End If Next Next jmpFaceCheck : If blnPlanarFaceCheck = False Then MsgBox("There must be a flat face for selection.") Exit Sub End If jmpFaceSelection : objFaceSelection = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFacePlanarFilter, "Select Planer Face to Calculate Area, Ix, and Iy Properties.") If objFaceSelection.ObjectType <> Inventor.ObjectTypeEnum.kFaceObject Then MsgBox("A surface face must be selected.") GoTo jmpFaceSelection End If
I left the full code threads in so you can make your own shorthands or use ones you've already made. ThisApplication.ActiveDocument is meant more for running in an external rule, if your code is going to be a rule attached to your part file template then ThisDoc.Document will work just fine and there'll be no need for the first part of the code to make sure it's running from a part document.
One other thing I noticed is your method of undoing the face sketch for calculation, it assumes it takes 4 undo methods every time to get back to where you were at the beginning of the code. I suggest you implement code that controls the Transaction Manager so that the number of undo methods is irrelevant.
oTransaction = ThisApplication.TransactionManager.StartTransaction(doc, "Inertia Calculation") oSK = oCD.Sketches.Add(oFace) oSK.Edit oCommandMgr.ControlDefinitions("SketchProjectCutEdgesCmd").Execute oProfile = oSK.Profiles.AddForSolid dArea = oProfile.RegionProperties.Area Dim adPrincipalMoments(2) As Double oProfile.RegionProperties.PrincipalMomentsofInertia(adPrincipalMoments(0), adPrincipalMoments(1), adPrincipalMoments(2)) oTransaction.Abort
This will undo your sketch operations but the adPrincipalMoments will still be in code memory to calculate and copy to your iProperties.
The last thing I recommend is to turn off screen updating, as it currently is, your computer is spending time updating the screen to show exactly what's happening during the sketch operations. Before you do the sketch operations, just put in the line ThisApplication.ScreenUpdating = False, then turn that back to True at the end of your code. This isn't necessary but it may speed your code up a bit.
Thank you for your suggestions. I made changes to my code based on what you had, and I have a couple of questions.
1. In the fifth line of my original code, I define "oFace = ...", which is used later in the code you wrote. This line has the text "Select Planar Face to...", and so does the last chunk of code from the first snapshot you gave me:
jmpFaceSelection : objFaceSelection = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFacePlanarFilter, "Select Planer Face to Calculate Area, Ix, and Iy Properties.")
If objFaceSelection.ObjectType <> Inventor.ObjectTypeEnum.kFaceObject Then
MsgBox("A surface face must be selected.")
GoTo jmpFaceSelection
End If
How could I change my code? When I run it I have to choose the planar face twice, which doesn't seem right.
2. Also, I get the error "Public member 'ObjectType' on type 'Face' not found." I'm still looking into figuring out what this means so I can find out how to fix this error.
Thank you for your help.
Sorry, that chunk was meant to check the face after it's been selected, and if the selection isn't a face from a surface it jumps back into the selection method for the user to try again. Change my objFaceSelection to the oFace you're using and remove the first "oFace = oCommandMgr.Pick" line. As for the error, I simply forgot the correct way to check object types. The fixed code example is below
Dim doc = ThisDoc.Document
oCD = doc.ComponentDefinition
'Implement the first checks to make sure it's a part document with a solid body that has planar faces available for selection.
Dim oCommandMgr As CommandManager =ThisApplication.CommandManager
jmpFaceSelection : oFace = oCommandMgr.Pick(SelectionFilterEnum.kPartFacePlanarFilter, "Select Planar Face to Calculate Area, Ix, and Iy Properties")
If oFace.Type <> ObjectTypeEnum.kFaceObject Then
MsgBox("A surface face must be selected.")
Goto jmpFaceSelection
End If
'Then continue with the rest of your code.
Thank you for your help with this, I appreciate it. I understand what you're saying. Now the only issue with my code seems to be that I defined "jmpFaceSelection" twice in my code, once in the beginning, and once later in my code:
jmpFaceSelection : oFace = oCommandMgr.Pick(SelectionFilterEnum.kPartFacePlanarFilter, "Select planar face to calculate area, Ix, and Iy properties")
jmpFaceSelection : oFace = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFacePlanarFilter, "Select planar face to calculate area, Ix, and Iy properties")
A view of my current code is below:
Remove the face selection on top since we don't want to select a face until we get past the other checks. Is this going to be for an External Rule or a rule attached to a part file? Once I know that I can go through your code and clean it up.
Alright, here's the code cleaned up a bit, I also divided the code into different sections using brackets, it also allows you to collapse and expand those sections, you can remove them if you don't like it.
'['Objects App = ThisApplication doc = ThisDoc.Document oCD = doc.ComponentDefinition oBodies = oCD.SurfaceBodies oCommandMgr = App.CommandManager Dim oFace As Face'] '['Check for Bodies If oBodies.Count = 0 Then MsgBox("Part File must containt a body.") Exit Sub End If'] '['Check for Planar Faces blnPlanarFaceCheck = False For Each oSurfaceBody As SurfaceBody In oBodies For Each oFace In oSurfaceBody.Faces If oFace.SurfaceType = SurfaceTypeEnum.kPlaneSurface Then blnPlanarFaceCheck = True GoTo jmpFaceCheck End If Next Next jmpFaceCheck : If blnPlanarFaceCheck = False Then MsgBox("There must be a flat face for selection.") Exit Sub End If'] '['Select Face jmpFaceSelection : oFace = oCommandMgr.Pick(SelectionFilterEnum.kPartFacePlanarFilter, "Select planar face to calculate area, Ix, and Iy properties.") If oFace.Type <> ObjectTypeEnum.kFaceObject Then MsgBox("A surface face must be selected.") GoTo jmpFaceSelection End If'] '['Calculate Intertia oTransaction = App.TransactionManager.StartTransaction(doc, "Inertia Calculation") App.ScreenUpdating = False oSK = oCD.Sketches.Add(oFace) oSK.Edit oCommandMgr.ControlDefinitions("SketchProjectCutEdgesCmd").Execute oProfile = oSK.Profiles.AddForSolid oRegProps = oProfile.RegionProperties dArea = oRegProps.Area Dim adPrincipalMoments(2) As Double oRegProps.PrincipalMomentsofInertia(adPrincipalMoments(0), adPrincipalMoments(1), adPrincipalMoments(2)) App.ScreenUpdating = True oTransaction.Abort'] '['Copy to iProperties iProperties.Value("Custom", "Area") = Format(dArea / 6.542, ".000") iProperties.Value("Custom", "Ix") = Format(adPrincipalMoments(0) / 41.623, ".000") iProperties.Value("Custom", "Iy") = Format(adPrincipalMoments(1) / 41.623, ".000") iProperties.Value("Custom", "Mass") = Format(iProperties.Mass, ".000")'] InventorVb.DocumentUpdate
The code works great, although after running the rule, the part file is in sketch mode. What code should I add to exit sketch mode?
Thank you.
That is strange that the transaction abort doesn't undo the sketch edit line. In between the "oRegProps.PrincipalMomentsofIntertia" and the "App.ScreenUpdating = True" lines add "oSK.ExitEdit" like below:
oRegProps.PrincipalMomentsofInertia(adPrincipalMoments(0), adPrincipalMoments(1), adPrincipalMoments(2))
oSK.ExitEdit App.ScreenUpdating = True
Hi,
Adding the extra line of code worked. Thank you so much for your help with this.
I have a question about this code. How exactly are the area, Ix, and Iy properties calculated?
To test my code, I made a part in Inventor with two separate components (see a view of that part below). Based on the values it calculates, it seems like you can pick either of the faces of those components, and it will calculate values for the entire cross section, including both profiles. It seems like you just have to pick a surface, and Inventor will take into account all the profiles in the entire plane you select, and then make calculations. Am I on the right track? Can you explain more about how that part of the code works?
Thanks.
Inventor part:
Is it possible for you to attach that part sample or something similar for me to test the code with? Is it only extruded profiles you're dealing with?
Hi,
I've attached a sample part to test with, and it has the updated iLogic code. I'm only dealing with extruded profiles.
Thanks.
The code is doing what it's been asked to do so far, it makes a sketch on the plane you selected and then this line:
oCommandMgr.ControlDefinitions("SketchProjectCutEdgesCmd").Execute
It projects every single solid edge that it finds, if you remove one of the sketch profiles from the extrusion the numbers do change. I'll see if I can find a way that it only projects the edges of the selected face or I recommend that only there only be a single extrusion per part file and you use assemblies to make arrangements of multiple separate extrusions.
I'm about to leave for the day so I'll give you what I have so far:
Replace this line:
oCommandMgr.ControlDefinitions("SketchProjectCutEdgesCmd").Execute
With these lines:
For Each oEdge As Edge In oFace.Edges oSK.AddByProjectingEntity(oEdge) Next
That will only project the edges of the selected face in the planar sketch. That seems to get you the correct Area, Ix, and Iy. However, Mass is currently getting pulled from iProperties and it measures every solid no matter what face is selected.
I noticed that you're checking to make sure the extruded length is always 12 inches, if you know for sure that the length is always 12, and assuming it's completely solid the whole way, then you can just multiply with the area to give you the volume and then multiply with the material density to give you the mass:
iProperties.Value("Custom", "Mass") = Format(iProperties.Value("Custom", "Area") * 12 * (iProperties.Mass / iProperties.Volume), ".000")
Can't find what you're looking for? Ask the community or share your knowledge.