Monday, December 1, 2014

We're going to need a bigger box...

Wouldn't it be nice if every time you reached into your toolbox you could pull out the perfect tool for the job?  You never had to use a pair of pliers to remove a spark plug?  You never had to resort to hacking through that wire with dull scissors?

The Inventor iLogic integrated development environment, (IDE), provides an awesome set of tools for quickly crafting conditional automation code.  i.e. "If this hole increases in size by x, Then thicken they webbing member by y."

This conditional logic is in fact the central theme of this blog; if this happens, then do that.  Pretty simple right?

What happens when simple conditional logic or using the provided code snippets don't measure up to the task at hand?  Fear not!  There is a solution.  A solution that's not well documented or advertised but that's been available nearly since iLogic's inception.  "...pssst, you can use, (reference), other code libraries and frameworks within the iLogic IDE.

After you've made the reference, you can call into those libraries and execute publicly exposed functions just as if they were your own.  

You can add references in two ways, AddReference "System.Drawing.dll" or through the Imports statement, as in Imports System.IO.  Inventor iLogic automatically "includes" the following .NET framework libraries or namespaces:
  • System
  • System.Math
  • System.Collections
  • Microsoft.VisualBasic
  • Autodesk.iLogic.Interfaces
  • Autodesk.iLogic.Runtime
Hmmmmm, seems that iLogic is capable of  leveraging the Microsoft .NET framework.  Well isn't that handy.  More later...



Let's take a look at a simple example that checks to see if a file exists.

Imports System.IO

Sub Main()
    Dim fName As String = "C:\Temp\rt1.ipt"
    If file.Exists(fname) Then 
        MsgBox(fName & " exists!")
    End If
End Sub

If the file is really there, we get this result:


Let's try another:

Imports System.IO

Sub Main()
    Dim path As String = "C:\temp\text.txt"
    File.AppendAllText(path, "test message" + vbCr)
End Sub



The above code snippet can be very useful for adding entries to a "log file".

I've always been a firm believer that if you intend to use a block of code more than once it deserves to me its own method or function.  Let's look at some other ways to code this in a little more efficient and professional manner.

Option 1 (Method)

Imports System.IO

Sub Main()
    Dim path As String = "C:\temp\text.txt"
    Call LogWriter(path,"Message passed as argument")
End Sub

Private Sub LogWriter(ByVal path As String, ByVal msg as String)
    File.AppendAllText(path, msg + vbCr)
End Sub

Now whenever we need to write a new line to our log file we just pass the path and the message, and the Call keyword is optional.  

LogWriter(path,"Message passed from a method")

We don't "expect" anything to go wrong because the .AppendAllText will create the file if it doesn't exist.  Oh wait, what if I typed the folder path wrong?

Let's add some error handling.


Imports System.IO

    Sub Main()
        Dim path As String = "C:\temp\text.txt"
        LogWriter(path, "Message passed as argument")
    End Sub

    Private Sub LogWriter(ByVal path As String, ByVal msg As String)
        Try
            File.AppendAllText(path, msg + vbCr)
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Critical, "Something has gone horribly wrong!")
        End Try

    End Sub

The Try/Catch block is your friend.  Think of it as the modern-day equivalent of the old 
On Error Resume Next.  The concept is super simple, "Try" this block of code, "Catch and handle any errors."
You may also be interested in File.Move, File.Copy, File.Exists or File.Replace.  Check out all of the File Class methods or the entire.NET Framework Class collection.
In the coming weeks/months extend this post to include "methods vs. functions", linking to data sources and expanded form functionality.
If you've learned one new thing by reading this post I've achieved my goal.

Happy Trails!


Thursday, November 20, 2014

Generate Drawings using iLogic Webcast

Hey everyone,

Wanted to give everyone a heads up that our own Carl Smith will be hosting a webinar today and discussing using iLogic to generate Inventor drawings.

It's free and I'm sure you'll pick up at least one thing that will help you in all your automation endeavors.

Generate Drawings using iLogic Webcast

Thursday, November 20
11:00 AM Eastern Time

REGISTER NOW


In case the above link doesn't work:

http://www.imaginit.com/Events/Registration/eventid/a2w700000000FBJAA2

Thanks,
Randy

Monday, September 29, 2014

Drawing View Scale Part II

In my last post, I discussed one solution to get a drawing view scale.  That solution found the drawing view with the lowest numerical value as part of view name (VIEW1, VIEW5, etc.) and used it's scale as an iProperty of the drawing.


Another solution that my client wanted was to present all the view names and allow the user to select which view he/she wanted to represent the scale in the title block.


Like the first solution, we cycled through each sheet on the drawing and looked at the view name.  If the view name begins with "VIEW" then it was used to build a one dimensional array.  We also concatenated the view scale with the view name to satisfy the needs of seeing both the view name and the view scale.

'    Cycle thru each sheet.  Build array of View Name and View Scale.
     For Each oSheet In oSheets
         oViews = oSheet.DrawingViews
         For Each oView In oViews
             oViewName = oView.Name
             If Left(oViewName,4) = "VIEW" Then
                 oScale = oView.Scale
                 oConc = oViewName & ": @ " & oScale
                 oViewList.Add(oConc)
             End If
         Next
     Next

We then sorted the array and set a MultiValue list using that array.

'    Sort array
     oViewList.Sort

'    Set Multi-Value List from array
     MultiValue.List("ViewList") = oViewList

Next we presented an input box to the user using the MultiValue list.

'    Present Input Box for user selection
     selected = InputListBox("Select a view from the list", _
     MultiValue.List("ViewList"), oViewList.item(0), Title := "Views", _
     ListName := "View Name @ Scale")

Next we extracted the view name and view scale from the user selection.

'    Extract View Name and View Scale from user selection    
     delimpos = InStr(selected, "@")
     oSelectedView = Left(selected,delimpos - 1)
     oSelectedScale = Right(selected,Len(selected)-delimpos)

Finally, the view scale was pushed to a custom iProperty that was displayed in the drawing title block.

'    Set custom iProperty based on user selection
     iProperties.Value("Custom", "Scale") = RoundToFraction(oSelectedScale, 1/8, _
     RoundingMethod.Round) & ":1"

The full code is listed here:

'    Setting Variables
     Dim oDrawDoc As DrawingDocument = ThisDrawing.Document
     Dim oSheet As Sheet
     Dim oSheets As Sheets
     oSheets = oDrawDoc.Sheets
     Dim oView As DrawingView
     Dim oViews As DrawingViews
    
     Dim oScale As Double
     Dim oViewName As String
     Dim oConc as String
     Dim oSelectedView As String
     Dim oSelectedScale As String
     Dim oViewList As New ArrayList
    
'    Cycle thru each sheet.  Build array of View Name and View Scale.
     For Each oSheet In oSheets
         oViews = oSheet.DrawingViews
         For Each oView In oViews
             oViewName = oView.Name
             If Left(oViewName,4) = "VIEW" Then
                 oScale = oView.Scale
                 oConc = oViewName & ": @ " & oScale
                 oViewList.Add(oConc)
             End If
         Next
     Next

'    Sort array
     oViewList.Sort

'    Set Multi-Value List from array
     MultiValue.List("ViewList") = oViewList
    
'    Present Input Box for user selection
     selected = InputListBox("Select a view from the list", _
     MultiValue.List("ViewList"), oViewList.item(0), Title := "Views", _
     ListName := "View Name @ Scale")
    
'    Extract View Name and View Scale from user selection    
     delimpos = InStr(selected, "@")
     oSelectedView = Left(selected,delimpos - 1)
     oSelectedScale = Right(selected,Len(selected)-delimpos)

'    Set custom iProperty based on user selection
     iProperties.Value("Custom", "Scale") = RoundToFraction(oSelectedScale, 1/8, _
     RoundingMethod.Round) & ":1"
    
'    Update
     iLogicVb.UpdateWhenDone = True

PS - Sorry about the formatting.  I can't seem to get those extra spaces out of the sections where I've broken up the code.

Please leave a comment and let me know what you think.

Randy

"Opportunity is missed by most people because it is dressed in overalls and looks like work." - Thomas Edison

Tuesday, September 23, 2014

Drawing View Scale Part I

Even in today's CAD world, we often include and display the drawing scale in the title block.  In the past, this was more of a requirement than it is today.  Today someone on the manufacturing floor can just as easily (and more accurately) pull up the CAD model on their terminal and take measurements. There are many students in my training classes that don't even know what item is shown in the image below.

Engineer's Scale
It is a typical practice for Inventor users to display the scale of the first view created in the drawing title block.

I recently ran into a situation where the client wanted two methods to pull a drawing scale to include in the title block:

  1. Find the view name with the lowest numerical value and use its scale in the title block
  2. Present the user with all drawing views, and their scales, on a drawing and allow the user to select which view he/she wanted to represent the scale in the title block

I'll discuss the first solution in this blog post.  The solution included just a few steps.

We cycled through each sheet on the drawing and looked at each view name.  If the view name begins with "VIEW" then it was used to build an one dimensional array.  This step ensured we didn't pull views such as section or detail views.

'    Cycle thru each sheet.  Build array of View Name and View Scale.    
     For Each oSheet In oSheets
     oViews = oSheet.DrawingViews
         For Each oView In oViews    
            oViewName = oView.Name
            If Left(oViewName,4) = "VIEW" Then
                temp = Right(oViewName,1)
                oViewList.Add(temp)
            End If
         Next
     Next

We then sorted the array and pulled the view scale of the first index of the array.

'    Sort array
     oViewList.Sort
    
'    Get scale of lowest View
     oSelectedScale = ActiveSheet.View("VIEW" & oViewList(0)).Scale

The view scale was pushed to a custom iProperty that was displayed in the drawing title block.

'    Set custom iProperty based on user selection
     iProperties.Value("Custom", "Scale") = RoundToFraction(oSelectedScale, 1/8, _
     RoundingMethod.Round) & ":1"

The full code is listed here:

'    Setting Variables
     Dim oDrawDoc As DrawingDocument = ThisDrawing.Document
     Dim oSheet As Sheet
     Dim oSheets As Sheets
     oSheets = oDrawDoc.Sheets
     Dim oView As DrawingView
     Dim oViews As DrawingViews
    
     Dim oScale As Double
     Dim oViewName As String
     Dim oViewList As New ArrayList
    
'    Cycle thru each sheet.  Build array of View Name and View Scale.    
     For Each oSheet In oSheets
     oViews = oSheet.DrawingViews
         For Each oView In oViews    
            oViewName = oView.Name
            If Left(oViewName,4) = "VIEW" Then
                temp = Right(oViewName,1)
                oViewList.Add(temp)
            End If
         Next
     Next
    
'    Sort array
     oViewList.Sort
    
'    Get scale of lowest View
     oSelectedScale = ActiveSheet.View("VIEW" & oViewList(0)).Scale

'    Set custom iProperty based on user selection
     iProperties.Value("Custom", "Scale") = RoundToFraction(oSelectedScale, 1/8, _
     RoundingMethod.Round) & ":1"
    
'    Update
     iLogicVb.UpdateWhenDone = True

Next post I'll discuss the second option where we displayed the view names and scales and allowed the user to select which scale to use in the title block.

As always, leave a comment and let us know how this has helped you.

Randy

"The difference between try and triumph is a little umph." - Unknown

Friday, September 12, 2014

Searching Excel with iLogic II: Header Rows

A few blogs back, my partner in crime Carl Smith posted about searching Excel with iLogic as a means of gathering data for ever changing projects.  This has come in handy multiple times for me.


I recently had a case where a client had a very nice looking Excel file with data at the top.  This forced the column headers I was searching for down a few rows.  An example is shown to the right.

By default, the GoExcel.FindRow likes the Column that is searching for to be in Row 1 of the worksheet.

This can be changed by using GoExcel.TitleRow.  This will allow you to tell iLogic what row to start looking for column names.

Before your GoExcel.FindRow command, add:

GoExcel.TitleRow = X

Replace the X with the row your Column headings are located in.

Here is what the code section would look like:

GoExcel.TitleRow = 8
i = GoExcel.FindRow("SalesOrders.xlsx", "Header", "Part Number", "=", PartNumber)

Description = GoExcel.CurrentRowValue("Description")
Length = GoExcel.CurrentRowValue("Length")

Randy


"I have not failed. I've just found 10,000 ways that won't work.~Thomas A. Edison


Friday, June 20, 2014

Now Where Did I Put That Code? Ah, my Custom Snippets!

If you’re anything like me (and I’ll assume you are unless you randomly pick blogs to read) then you’ve been writing iLogic code for the past 3 years or so and have amassed a large amount of code.  All that code is probably sitting in various part, assembly or drawing files.

About a year ago I decided I needed to do some tidying up and figure out a way to store all my iLogic code in a manner that I could easily search, retrieve and copy the code I know I have somewhere…it does X…and I wrote it for client Y….I think.

I am still on my quest to find the perfect vehicle to do everything but I recently decided to take a closer look at the simple storage method that Autodesk already gives us, Custom Snippets.

Custom Snippets work the same as the System Snippets with the difference being they are your code.  They are an easy way to insert your own bits of code into your iLogic rule.  

Let’s say I've written a few lines of code that I’ll be using in a few different parts in my current project.

Now, there are multiple ways of getting this rule into parts.  I could put it in the template, I could use external rules, I could use the Code Injector (which is a lovely tool that you should check out if you don’t already use it).  I don’t want to argue the merits of each of these and just focus on Custom Snippets for now.

One decision to make is how you want to categorize your Custom Snippets.  You can create individual categories for specific projects, clients, code type, etc.  I prefer to create categories by either code type or client name and saving my snippets that way.

To insert a new Snippet category, right click in the Custom Snippets window and choose Insert Category.  Enter a category.  In this example I’ll be categorizing them using client names and call this one ACME.  Unfortunately you cannot create nested categories.


Once you’ve created a category, it’s time to start filling it up with all that helpful code you’ve already written.  Highlight the code in the Rule Editor that you want to save (I always select all the code, including empty spaces or tabs to the left so that they are captured), right click and choose Capture Snippet.  




You’ll be presented with the Edit Snippet dialog box.


  1. Title of the Snippet.  This shows in the Snippets listing.
  2. Which category would you like to store the Snippet?
  3. Text entered here will show up as a tooltip when hovering over the Snippet in the Snippet listing.  I prefer a short blurb rather than using the code as the tooltip.  The code is shown at the bottom of the tooltip by default.
  4. The code you highlighted will show up here.  You can edit here but I find it easier to edit in the Rules Editor.

As my favorite knigget said “That’s easy!” 

You insert a Custom Snippet the same way as inserting a System Snippet, simply double click on it to insert it into the Rule Editor and edit as required.

A few other helpful things about Custom Snippets:
  • When deleting a Snippet Category, you’ll get asked if you want to delete the rules inside that category or move them to a Default category.
  • You can drag and drop snippets from one category to another.
  • You can merge snippets from one file to another using the tool on top of the Custom Snippets tab.
  • If you create a category but don’t put a snippet inside of it, the category will not save.
  • Use the Save and Open buttons at top to make sure everyone on your design team is pointing at the same Custom Snippets file.

I am still on the lookout for other ways of storing iLogic rules.  Ideally, something that multiple users could access and easily search for keywords and tags.  If you have any suggestions that you’d like to share, please leave a comment below.

Randy

"Challenge yourself with something you know you could never do, and what you'll find is that you can overcome anything." - Anonymous


Monday, June 16, 2014

2015 Purge Unused Parameters & iLogic Rules

With the release of Inventor 2015, we finally have an easy built-in way of purging unused parameters in both assemblies and parts.  In the Parameters dialog box is the new Purge Unused command:



Warning
This command checks to see if a parameter is used in a feature.  It does not check to see if the parameter is only being used in an iLogic rule.

Hopefully this will save you from an OOPS.

Randy

"There are only two mistakes one can make along the road to truth; not going all the way, and not starting." - Buddha


Wednesday, June 11, 2014

Placeholders on iLogic Forms

I recently had a case where a colleague was setting a custom iProperty (Program Number) to either the file name or a custom field and he was using a boolean parameter to determine which of these to use to set it.

Here is his original code:
'********************************************************
'Set Program Name

If Set_Prog_Name = True Then
    iProperties.Value("Custom", "Program Number") = ThisDoc.FileName(False) 'without extension
Else
    iProperties.Value("Custom", "Program Number") = ""
End If

'********************************************************
We can see from the original code that when Set_Prog_Name = False that the Program Number will be set to <blank>.  He needed a way to allow the end user to enter a value in the Program Number field.

My immediate response wast to set up an input box but he preferred to not have an additional dialog box.

The end solution was one to add a placeholder iProperty, which I called Program_Name_Temp, on the form in place of the original Program Number and set the value of the Program Name iProperty equal to the placeholder when Set_Prog_Name = False.  As an additional bonus, I added a controlling parameter for Program_Name_Temp which is called Set_Prog_Name_Controls.

'********************************************************
'Set Program Name

If Set_Prog_Name = True Then
    Set_Prog_Name_Controls = False
    iProperties.Value("Custom", "UserInfo2") = ThisDoc.FileName(False) 'without extension
    Program_Name_Temp = iProperties.Value("Custom", "Program Name")
Else
    Set_Prog_Name_Controls = True
    iProperties.Value("Custom", "Program Name") = Program_Name_Temp
End If

'********************************************************

I hope this helps you on a future or current project.

Randy

"Even if you're on the right track, you'll get run over if you just sit there ." - Will Rogers

Monday, March 17, 2014

An iProp for the unique items

A request came in for a modification on the 'iProp For Everyone' post.  The post requested for the code to ignore additional instances of an occurrence.

One way of doing this is by using the AllReferencedDocuments.  There is only reference per file so this approach will take care of the unique item issue.  This differs from the original alternative approach I took where I looked at the ComponentOccurrences.

'   Get the active assembly. 
    Dim oAsmDoc As AssemblyDocument 
    oAsmDoc = ThisApplication.ActiveDocument
    
'   Get the PropertySets object. 
    Dim oPropSets As PropertySets 
    Dim oPropSet As PropertySet 
    
'   Iterate thru each referenced document
    Dim oDoc As Document 
    For Each oDoc In oAsmDoc.AllReferencedDocuments 
        oPropSets = oDoc.PropertySets
        oPropSet = oPropSets.Item("Inventor User Defined Properties")     

        Try                                                
        '    Push the required iProperties down to the documents
            oSONumiProp = oPropSet.Item("SO_Number")
            oSONumiProp.Value = Sales_Order_Number
            oCompanyiProp = oPropSet.Item("Company")
            oCompanyiProp.Value = Customer_Name
            oProjectiProp = oPropSet.Item("Project Description")
            oProjectiProp.Value = Project_Description
        Catch
        '    Do not raise or display an error.
        End Try
    Next 


Hopefully you see some benefit in the above solution.  Leave me a comment and let me know.

Randy

"The mind is everything. What you think you become." - Buddha

Thursday, January 30, 2014

Pictures are worth how many words?

iLogic Forms are how you interact with your iLogic models.  They are the user interface that you use to enter parameters, make selections and run rules that are necessary to complete your configuration.  The iLogic Form Editor is the tool that is used to layout and design those forms.  

The main sections of the Form Editor are:

  A) Parameters / Rules / iProperties
  B) Toolbox
  C) Form Design Tree
  D) Properties


The Form Editor uses drag and drop functionality to build a form.  You simply drag items from the Parameters / Rules / iProperties or Toolbox section and drop them on the Form Design Tree.  You then modify the properties of those items using the Properties section.

While it is not necessary to have any rules or parameters before creating a form, it is generally a better workflow to at least have the main parameters created so that you have something to work with.  I generally set the parameters that I’m going to use on my form as Key parameters and use the handy filter in the Form Editor dialog box to easily find them to layout my form (it's in the upper left).

There are a lot of resources for finding information on creating a basic form.  I’d like to focus on one of the tools that isn’t easily understood, Picture and the Picture Folder.
  

Picture

Pictures can be used to display image files such as a company logo.  Acceptable image formats are .bmp, .gif, .png, .jpg, .jpeg & .tiff.  To include a picture in your form, drag the Picture tool from the Toolbox and drop it on your Form Design Tree.  The properties available for a Picture are:
  • Label – This is the name of the image that shows on the Form Design Tree and on the form if you decide to show it.
  • Image – This is where you specify the image file to use.  Click in the Image property and then on the ellipse button to specify the image file.  (Image should be sized before assigning it to the property).
  • Show Label – This is a Boolean property that controls whether or not the Label property is displayed on the form.  If this is set to True then the Text Location property becomes available.
  • Text Location – Only available if the Show Label property is set to True.  This property controls the location of the label on the form.  You can choose from Left, Right, Top & Bottom.
  • Picture Parameter Name – This property is used in conjunction with the Picture Folder property.  Set this property to a Text user parameter with a multi-value list that will control which picture from the picture folder is displayed.
Note:  If the Picture Parameter Name property has a parameter, it will override the image that is selected in the Image property.

Picture Folder

An even better use for pictures is to have them change based upon selections your user makes in the form.  The Picture Folder is used in conjunction with the Picture tool and is used to display multiple images in this manner.  By default, the Picture Folder comes in with 2 possible images but can be increased by dragging more Picture tools into it (just as if you were dragging a Picture tool onto your form).  Each picture that is part of the Picture Folder has two properties to modify:
  • Label – Populate the label property with a possible value for the Text parameter that was used in the Picture Parameter Name property.  This is how you set the link between the property and which image to display. If the value of the Label property does not match a value in the Picture Parameter Name multi-value list, the image will display the text ‘No image data’.
  • Image - This is where you specify the image file to use.  Click in the Image property and then on the ellipse button to specify the image file.

Note:  If you’ve already specified an image file to use and would like to update it, you’ll need to specify it again.  The updated image will not reload automatically.

 
Using Pictures and the Picture folder to drive images based upon selections can really help clarify things for your end user.



In the examples to the left, the user has two different End Designs to choose from.  I'm showing him those different designs using a Picture Folder.









Pictures really are worth 1,000 words!






Bonus tip about using the Properties area of the Form Editor:  You can double click in the box to make it toggle through all available options.  It's sometimes easier and quicker than using the drop down box.



Randy

“We cannot direct the wind but we can adjust the sails.” — Author Unknown