Quantcast
Channel: Manufacturing DevBlog
Viewing all 532 articles
Browse latest View live

Cannot load or reload add-in

$
0
0

By Adam Nagy

If you have issues with loading or reloading your add-in these might be the most likely issues. 

1) Issues with loading the add-in

This is the scenario when your add-in never gets loaded. 

Is your add-in found by Inventor?
- if your add-in is not listed in the Add-In Manager dialog then Inventor cannot even find your add-in. You should check that you placed your *.addin file in the right folder and that all the information in it is correct: http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=20143212

Addinloading

Does your add-in have a unique id?
- maybe your add-in was based on an existing add-in and so is using the same GUID as another one which gets loaded into Inventor. You can always list all the add-in GUIDs which are being loaded into Inventor and compare that to your add-in's GUID.    

Guid

Is the bitness of your add-in the same as Inventor's?
- check the project setting that it's 32 bit on a 32 bit OS and 64 bit on a 64 bitOS. In case of a .NET add-in the easiest is to use the "Any CPU" setting

Bitness

Is your add-in COM Visible?
- make sure that "Make assembly COM-Visible" setting is checked. Note: do not confuse it with the "Register for COM interop" setting which should be switched off as that would make the add-in use the old registration mechanism.

Comvisible

Still cannot load it?
- if you still cannot even step into the code inside the Activate() method then you might have some unresolved dependencies or you might have some issues inside the constructor of your ApplicationAddInServer implementation or maybe some global variables that error out. If there are any issues before reaching the Activate() method or inside that, your add-in will not get loaded. 

2) Issues with reloading add-in

This is the scenario when you could already load your add-in successfully, but within the same Inventor session, once you unloaded your add-in you could not get it loaded again.

Are you removing the controls you are creating?
- the most likely problem is that you are creating some control definitions and UI components, but you do not remove them inside the Deactivate() method when your add-in gets unloaded. So when you try to load your add-in again, since those components already exist, your code will error out and the loading of the add-in will be cancelled.   


Rename file referenced from assembly

$
0
0

By Adam Nagy

There is already an article on changing the file reference to another file using the Inventor API:
http://adndevblog.typepad.com/manufacturing/2012/08/replace-the-file-reference-by-inventor-api.html 

If you want to combine this with the renaming of a referenced file then you can do it like so. It might be a good idea to keep the original file until the reference has been replaced:

Sub ChangeFileNameReferencedFromAssembly()
  Dim asmDoc As AssemblyDocument
  Set asmDoc = ThisApplication.ActiveDocument
  Dim asmCompDef As AssemblyComponentDefinition
  Set asmCompDef = asmDoc.ComponentDefinition
  Dim asmOcc As ComponentOccurrence
  Set asmOcc = asmCompDef.Occurrences(1)
  Dim partDoc As PartDocument
  Set partDoc = asmOcc.Definition.Document
  Dim fileMgr As FileManager
  Set fileMgr = ThisApplication.FileManager
  Dim oldFileName As String
  oldFileName = partDoc.FullFileName' Create new file with new file name
  Dim newFileName As String
  newFileName = oldFileName + "_new.ipt"
  Call fileMgr.CopyFile(oldFileName, newFileName)' Change reference' The file you replace the reference to needs' to be the same file or one derived from the' original file
  Call asmOcc.ReferencedDocumentDescriptor. _
    ReferencedFileDescriptor.ReplaceReference(newFileName)' Delete the original file (if you want)
  Call fileMgr.DeleteFile(oldFileName)
End Sub

 

Differentiate Inventor documents

$
0
0

By Adam Nagy

When you create a new document then a new GUID will be assigned to its InternalName property. This will stay the same for the lifetime of the document no matter what modifications have been done in the document geometry or file properties. This property also remains the same when the file gets copied or renamed. So how to tell the difference between two copied documents once they got modified?

You can use the RevisionId and DatabaseRevisionId property for that depending on what kind of differences you are interested in:

RevisionId

Gets the GUID that represents the last saved revision of this file. Works as a stamp of the contents of this file.

DatabaseRevisionId

Gets the GUID that represents the last saved revision of database contained in this document. This revision id tracks modifications to the database (such as reference changes, geometry changes, etc.) but does not track file property changes.

If two documents have the same InternalName, then they were originally the same file but could have been modified in the meantime.

If their DatabaseRevisionId is the same, then their geometry and references are the same.

If their RevisionId is the same, then everything in the two files are the same.

Forge Accelerator is coming

Autodesk® Inventor® iLogic™ or Inventor API: Which Is the Right Tool for Me? (Autodesk University Session)

AcquireFiles() not fixing references of renamed files

$
0
0

By Wayne Brill

If files are renamed in Vault you may see that AcquireFiles() is not fixing the references. For AutoCAD this would be an XReference that was renamed and for Inventor it will be an ipt that was renamed.

A solution for AutoCAD files is to Add a Reference in your project to a dll named DWGDBXEngineWrapper.dll.  (Add it from this directory)
C:\Program Files\Autodesk\Vault Professional 2016\Explorer
 
Also add a using statement in your project:

image

 

For Inventor:

Apply the Vault 2016 Service pack   https://knowledge.autodesk.com/support/vault-products/downloads/caas/downloads/content/autodesk-vault-2016-service-pack-1.html?v=2016

Inventor API: Change Size of CC Component Placed as Custom

$
0
0

by Vladimir Ananyev

Q: I may use the Change Size command to change a key parameter for a Content Center part placed as a Custom component. But how can I do it programmatically?

Change Size command

Table View

A: If we talk about “Change Size as custom”, there is no existed API to support currently. There is a series of internal logic that are implemented in CC.

For example,

• Get the target CC table row

• Get all parameters you need to change

• Get the new values

• Batch Edit the parameters

• …

• Update Part

In this case Inventor changes existing part document via Parameters API and iProperties API directly – no new part, no file replacement. Of course, it is always better to have an appropriate API function, but in this particular case we are able to implement this workflow ourselves.

We access our CC custom component saved locally, then get its current row in the CC family table and suppose we know the new target row number.

User parameter’s names in the CC component are the same as the corresponding InternalNames of the ContentTableColumns in the ContentFamily. So we may read target parameter’s values from the cells in the target ContentTableRow and then update the user parameters in the file on disk.

We should also update several iProperties – the part number, stock number, MemberId and may be other iProperties as well. Finally we should rename component in the browser (name is usually based on part number) and then update both the part and assembly documents.

It is not easy to implement a general purpose utility that could work with any CC family, but fortunately in most cases you work with several particular families (e.g., structural shapes). This could simplify this specific implementation.

The attached VBA code demonstrates the workflow that mimics the “Change Size” UI command for the CC component placed as Custom. This code reads family data from the last component in the browser assuming that it is a CC member and asks the user to enter the new row number. New model parameters and iProperties values are applied to the member file on disk. New file is not created.

Download Mod_CC_4

As a ”proof of concept” this code contains a lot of debug printing and was tested with some structural profiles families only — angles, channels, and i-beams. Hope it could be modified to process other CC families.

Inventor Answer Day! :)


Customize iAssembly / iPart member creation

$
0
0

By Adam Nagy

I've seen a few posts on the forum about trying to use iLogic code inside iAssembly and iPart factories to customize the created member file to change e.g. some of its iProperties

So I thought it could be useful to talk about the internal process of member creation.

iAssembly

This is quite straight-forward. In this case when an iAssembly instance's row is changed in the containing assembly document then Inventor checks if the appropriate member file already exists. If it does, there is nothing to do. If it does not, then:
1) it copies the iAssemblyfactory file and names it according to the member name
2) updates the properties in the member file based on the iAssembly table row info
3) saves and closes the member file

So in this case if the iAssemblyfactory has a rule that fires on "Before Save Document" which modifies the document, then it basically modified the created member file - which is what you probably want.

iPart

This is more complicated. When an iPart instance's row is changed in the containing assembly document then Inventor checks if the appropriate member file already exists. If it does, there is nothing to do. If it does not, then:
1) it creates a new part file based on the active part file template and names it according to the member name 
2) in the factory file it starts a transaction which will be aborted later, so that the factory file does not get modified in the end
3) inside the transaction it changes the iPart row to the required one
4) stores all the info it will need later on for the member file: the generated geometry, iProperties, Parameters, etc
5) aborts the transaction
6) copies the previously stored info into the member file 
7) saves and closes the member file

So in this case if the iPart factory has a rule that fires on "Before Save Document" which modifies the document, then it has no effect on the created member file because the event is not firing inside the member file, but inside the factory. Also, inside member files most iLogic functionality, along with lots of other features as well, is disabled so it could not fire an event anyway (you could run a rule explicitly though).

Unfortunately, there are no events specific to member file generation steps that would fire e.g. before the information from the factory file gets saved.
We only have the ModelingEvents.OnGenerateMember (the closest to it in iLogic is "iPart or iAssembly Change Component" but that also fires if the member is already available) but that fires inside the assembly that contains the iPart/iAssemblymember instance, not inside the member or the factory.

Hooking into other events could achieve some results, but it might not be very robust.
E.g. if you have a rule in the iPartfactory that is set to fire on "Part Geometry Change" to modify some geometry and in it you also synchronously update the document to reflect the changes immediately (using Document.Update2()), then it can modify the geometry that gets copied into the created member file.
But e.g. if you try to modify there an iProperty (like Project>> Description) that will be too late. It seems by the time "Part Geometry Change" is fired those already got stored. Also, that seems to be the only event firing during member creation.
Note: the workaround in the following article only works when you modify the iPart table row explicitly when the factory file is open. It does not work if the row is changed as a result of a row change on a member instance inside an assembly: http://adndevblog.typepad.com/manufacturing/2015/12/no-iproperty-change-event-fired-for-ipart-row-change.html

Bottom line 

Best thing is to keep everything you want to drive inside the member files in the iPart/iAssembly table: the Parameters, the iProperties, etc. 
So if you want to drive e.g. the Project>> Description property, add that to the table:

IPartDescription

Since iParts and iAssemblies are driven by an Excel table, you can also use Excel functions to calculate things and set up relationships between cells:

IPartExcel

 

Keep selection between rule executions

$
0
0

By Adam Nagy

There is a blog post on selecting multiple components interactively from an iLogicRule, but it does not highlight the selected objects while the Rule is running in the Inventor versions I tested it in - something might have changed in the meantime. However, using a HighlightSet seems to work fine:

Dim oSet As HighlightSet' Check to make sure the active document is a part.
If ThisApplication.ActiveDocumentType <> 
DocumentTypeEnum.kPartDocumentObject Then	
  MsgBox("A part document must be open.")
  Exit Sub
End If' Set a reference to the active part document.
Dim oDoc As PartDocument
oDoc = ThisApplication.ActiveDocument

oSet = oDoc.CreateHighlightSet

While True
  Dim oFace As Object
    oFace = ThisApplication.CommandManager.Pick(
      SelectionFilterEnum.kPartFaceFilter, 
      "Select a face") ' If nothing gets selected then we're done	
    If IsNothing(oFace) Then Exit While
    oSet.AddItem(oFace)
End While

oSet.Clear()

When you run an iLogicRule it behaves as starting a command, which also means that the current selection will be cancelled. So we would need to store which entities were already selected inside our Rule and reselect them. In order to keep a list we would need to have a global static variable that could hold on to those entities. Even if we just kept them in a HighlightSet we would still need a global static object to keep a reference to the HighlightSet, because as soon as that goes out of scope it will be deleted and then highlighting will be gone. 

In case of VB.NET the way to create a global static variable is to use the Shared keyword. It is possible to add global variables to an iLogicRule by implementing the whole Rule class as shown in this article:
https://www.cadlinecommunity.co.uk/hc/en-us/articles/203491091-Inventor-2016-iLogic-Using-Global-Variables

Actually, because you can define the whole Rule class, you can also handle events in it if you want. That means you could even use the InteractionEvents class which enables you to do multi and window selections. However programmatically selecting entities inside a rule using SelectSet.Select or CommandManager.DoSelect does not seem to work well: the entities only get highlighted once the rule finished.

If we stick to HighlightSet then we could use it like this to do selection and re-selection of previously selected entities:

Class ThisRule' Keep track of selected entities
  Shared oSelectedEnts As ObjectCollection  

  Sub Main()
    Dim oSet As HighlightSet

    ' Check to make sure the active document is a part.
    If ThisApplication.ActiveDocumentType <> 
    DocumentTypeEnum.kPartDocumentObject Then	
      MsgBox("A part document must be open.")
      Exit Sub
    End If' Initialize the entity collection' If you want to keep track of the previously ' selected entitites then only initialize this variable' if it has not been initialized before
    If oSelectedEnts Is Nothing Then
      oSelectedEnts = ThisApplication.TransientObjects.CreateObjectCollection()
    End If  

    oDoc = ThisDoc.Document
    oSet = oDoc.CreateHighlightSet

    ' Show the previously selected entities
    For Each ent In oSelectedEnts
      oSet.AddItem(ent)
    Next
    While True
      Dim oFace As Object
      oFace = ThisApplication.CommandManager.Pick(
        SelectionFilterEnum.kPartFaceFilter, "Select a face") ' If nothing gets selected then we're done	
      If IsNothing(oFace) Then Exit While
      oSet.AddItem(oFace)
      oSelectedEnts.Add(oFace)
    End While
    oSet.Clear()
  End Sub
End Class

HighlightSet

 

RangeBox of components

$
0
0

By Adam Nagy

If you want to get the extents of a ComponentOccurrence then you can use its RangeBox for that.
This will provide the information in the coordinate system of the top assembly:

Sub AddPoints1( _
oCD As AssemblyComponentDefinition, oOcc As ComponentOccurrence)
  Dim pt1 As Point
  Set pt1 = oOcc.RangeBox.MinPoint
  Dim pt2 As Point
  Set pt2 = oOcc.RangeBox.MaxPoint
  Call oCD.WorkPoints.AddFixed(pt1)
  Call oCD.WorkPoints.AddFixed(pt2)
End Sub

Sub ComponentExtents1()
  Dim oDoc As AssemblyDocument
  Set oDoc = ThisApplication.ActiveDocument
  
  Dim oCD As AssemblyComponentDefinition
  Set oCD = oDoc.ComponentDefinition
  
  Dim oOcc As ComponentOccurrence
  For Each oOcc In oCD.Occurrences.AllLeafOccurrences
    Call AddPoints1(oCD, oOcc)
  Next
End Sub

Extents1

If you want to get the extents in the part's or subassembly's coordinate system instead then you just have to drill down to the ComponentDefinition used by the occurrence, which will also have a RangeBox property. Then to show those points in the top assemblies coordinate system, you just have to transform them based on the occurrence's Transformation property:

Sub AddPoints2( _
oCD As AssemblyComponentDefinition, oOcc As ComponentOccurrence)
  Dim oRB As Box
  Set oRB = oOcc.Definition.RangeBox
  Dim pt1 As Point
  Set pt1 = oRB.MinPoint
  Call pt1.TransformBy(oOcc.Transformation)
  Dim pt2 As Point
  Set pt2 = oRB.MaxPoint
  Call pt2.TransformBy(oOcc.Transformation)
  Call oCD.WorkPoints.AddFixed(pt1)
  Call oCD.WorkPoints.AddFixed(pt2)
End Sub

Sub ComponentExtents2()
  Dim oDoc As AssemblyDocument
  Set oDoc = ThisApplication.ActiveDocument
  
  Dim oCD As AssemblyComponentDefinition
  Set oCD = oDoc.ComponentDefinition
  
  Dim oOcc As ComponentOccurrence
  For Each oOcc In oCD.Occurrences.AllLeafOccurrences
    Call AddPoints2(oCD, oOcc)
  Next
End Sub

Extents2

You could also get the extents in an arbitrary coordinate system, e.g. one defined by a UserCoordinateSystem object placed inside the part document. In this case we can use TransientBRep to transform the SurfaceBodies of the parts as also shown in this forum thread:  

Sub GetRangePoints3( _
oOcc As ComponentOccurrence, pt1 As Point, pt2 As Point)
  Dim oUCS As UserCoordinateSystem
  On Error Resume Next
  Set oUCS = oOcc.Definition.UserCoordinateSystems("UCS")
  On Error GoTo 0' If the part does not have a UserCoordinateSystem object' named "UCS" then we just use the part's coordinate system
  If oUCS Is Nothing Then
    Set pt1 = oOcc.Definition.RangeBox.MinPoint
    Set pt2 = oOcc.Definition.RangeBox.MaxPoint
    Exit Sub
  End If
  Dim oTB As TransientBRep
  Set oTB = ThisApplication.TransientBRep
  Dim oUT As Matrix
  Set oUT = oUCS.Transformation
  Call oUT.Invert
  Dim oSB As SurfaceBody
  Dim oTSB As SurfaceBody
  Dim oRB As Box
  For Each oSB In oOcc.Definition.SurfaceBodies
    Set oTSB = oTB.Copy(oSB)
    Call oTB.Transform(oTSB, oUT)
    If oRB Is Nothing Then
      Set oRB = oTSB.RangeBox
    Else
      Call oRB.Extend(oTSB.RangeBox.MinPoint)
      Call oRB.Extend(oTSB.RangeBox.MaxPoint)
    End If
  Next' Transform points back to the part coordinate system
  Call oUT.Invert
  Set pt1 = oRB.MinPoint
  Call pt1.TransformBy(oUT)
  Set pt2 = oRB.MaxPoint
  Call pt2.TransformBy(oUT)
End Sub

Sub AddPoints3( _
oCD As AssemblyComponentDefinition, oOcc As ComponentOccurrence)
  Dim pt1 As Point
  Dim pt2 As Point
  Call GetRangePoints3(oOcc, pt1, pt2)
  
  Call pt1.TransformBy(oOcc.Transformation)
  Call pt2.TransformBy(oOcc.Transformation)
  
  Call oCD.WorkPoints.AddFixed(pt1)
  Call oCD.WorkPoints.AddFixed(pt2)
End Sub

Sub ComponentExtents3()
  Dim oDoc As AssemblyDocument
  Set oDoc = ThisApplication.ActiveDocument
  
  Dim oCD As AssemblyComponentDefinition
  Set oCD = oDoc.ComponentDefinition
  
  Dim oOcc As ComponentOccurrence
  For Each oOcc In oCD.Occurrences.AllLeafOccurrences
    Call AddPoints3(oCD, oOcc)
  Next
End Sub

Extents3

The following article might also come handy in understanding the component transformations:
http://adndevblog.typepad.com/manufacturing/2013/07/occurrences-contexts-definitions-proxies.html 

Use Excel API to export PartsList content

$
0
0

By Adam Nagy

In case PartsList.Export() does not do exactly what you need, you can take full control of what gets exported and how by using the Excel API directly. 

The following sample exports the content of the first PartsList of the active sheet. 

VBA

Sub ExportPartsListContent()
  Dim oExcel As Object
  Set oExcel = CreateObject("Excel.Application")' For debugging'oExcel.Visible = True
  Dim oWB As Object
  Set oWB = oExcel.Workbooks.Open("C:\temp\test.xlsm")
  Dim oWS As Object
  Set oWS = oWB.ActiveSheet
  Dim oDoc As DrawingDocument
  Set oDoc = ThisApplication.ActiveDocument
  Dim oSheet As Sheet
  Set oSheet = oDoc.ActiveSheet' Export the first PartsList
  Dim oPL As PartsList
  Set oPL = oSheet.PartsLists(1)' Export headers
  Dim iRow As Integer: iRow = 1
  Dim iCol As Integer: iCol = 1
  Dim oCol As PartsListColumn
  For Each oCol In oPL.PartsListColumns
    oWS.Cells(iRow, iCol).Value = oCol.Title
    iCol = iCol + 1
  Next
  iRow = iRow + 1' Export content
  Dim oRow As PartsListRow
  For Each oRow In oPL.PartsListRows
    iCol = 1
    Dim oCell As PartsListCell
    For Each oCell In oRow
      oWS.Cells(iRow, iCol).Value = oCell.Value
      iCol = iCol + 1
    Next
    iRow = iRow + 1
  Next' Save it' We disable the confirmation dialog' in case the file already exists and' needs to be overwritten
  oExcel.DisplayAlerts = False
  Call oWB.SaveAs("C:\temp\test2.xlsm")' Close excel
  Call oExcel.Quit
End Sub

iLogic

AddReference "Microsoft.Office.Interop.Excel"
Dim oExcel As New Microsoft.Office.Interop.Excel.Application' For debugging'oExcel.Visible = True

Dim oWB As Object
oWB = oExcel.Workbooks.Open("C:\temp\test.xlsm")

Dim oWS As Object
oWS = oWB.ActiveSheet

Dim oDoc As DrawingDocument
oDoc = ThisApplication.ActiveDocument

Dim oSheet As Sheet
oSheet = oDoc.ActiveSheet

' Export the first PartsList
Dim oPL As PartsList
oPL = oSheet.PartsLists(1)' Export headers
Dim iRow As Integer: iRow = 1
Dim iCol As Integer: iCol = 1
Dim oCol As PartsListColumn
For Each oCol In oPL.PartsListColumns
  oWS.Cells(iRow, iCol).Value = oCol.Title
  iCol = iCol + 1
Next
iRow = iRow + 1' Export content
Dim oRow As PartsListRow
For Each oRow In oPL.PartsListRows
  iCol = 1
  Dim oCell As PartsListCell
  For Each oCell In oRow
    oWS.Cells(iRow, iCol).Value = oCell.Value
    iCol = iCol + 1
  Next
  iRow = iRow + 1
Next' Save it' We disable the confirmation dialog' in case the file already exists and' needs to be overwritten
oExcel.DisplayAlerts = False
Call oWB.SaveAs("C:\temp\test2.xlsm")' Close excel
Call oExcel.Quit

PartsListExcel

 

Use HiddenCommands() in IExplorerExtension to Hide Vault Explorer commands

$
0
0

By Wayne Brill

You can use the HiddenCommands function to hide commands in Vault Explorer. If this function returns names of commands they will be hidden. To get the names of Vault commands you can use the CommandIds property of the IApplication that is passed into the OnLogOn function:

publicvoid OnLogOn(IApplication application)

{

    System.Collections.Generic.IEnumerable<string> cmds = application.CommandIds;

}

 

Here is an example that uses HiddenCommands() to hide the Checkout, CheckIn and Rename commands.

publicIEnumerable<string> HiddenCommands()

{

    IEnumerable<string> cmdsToHide = newstring[] { "QuickCheckOut", "CheckIn", "Rename" };

    return cmdsToHide;

}

To test this you can use the HelloWorld SDK sample:

C:\Program Files (x86)\Autodesk\Autodesk Vault 2016 SDK\vs12\CSharp\HelloWorld

See this post for an example code that you can use to display the command id (a string) every time you invoke a command in Vault explorer.

Modify "Create Tube & Pipe Run" dialog content

$
0
0

By Adam Nagy

When you switch to "Tube & Pipe" environment ...

Tube&Pipe1

... then before the "Create Tube & Pipe Run" dialog pops up, the OnPopulateFileMetadata event of the FileUIEvents object will be called, which we can handle:

' Code of clsEvents Class
Dim WithEvents oFE As FileUIEvents

Private Sub Class_Initialize()
  Set oFE = ThisApplication.FileUIEvents
End Sub

Private Sub oFE_OnPopulateFileMetadata( _
ByVal FileMetadataObjects As ObjectsEnumerator, _
ByVal Formulae As String, _
ByVal Context As NameValueMap, _
HandlingCode As HandlingCodeEnum)
  Dim fmd1 As FileMetadata
  Set fmd1 = FileMetadataObjects(1)
  fmd1.FullFileName = "C:\temp\myruns\runs.iam"
  Dim fmd2 As FileMetadata
  Set fmd2 = FileMetadataObjects(2)
  fmd2.FullFileName = "C:\temp\myruns\myrun1\run1.iam"
  HandlingCode = kEventHandled
End Sub

And this change will be reflected in the dialog:

Tube&Pipe3

If we click OK, we end up with a model like this:

Tube&Pipe4

 

Change MembersToInclude of a PartsList

$
0
0

By Adam Nagy

In the UI you can change which member of an iPart or iAssembly is included by double clicking the parts list and then clicking the "Member Selection" button:

MembersToInclude2

If you try to change the included member like this then you'll get an "Invalid procedure call or argument" error:

MembersToInclude

If something does not work then it's always good to try to do it through the UI and then check the results in the VBAWatches window:
http://adndevblog.typepad.com/manufacturing/2013/10/discover-object-model.html

If you did that then you'd find (as shown in the above image) that MembersToInclude stores an array of strings - so that's what you'd need to pass to it:

Sub ChangeMembersToInclude()' The PartsList needs to be selected in the UI
  Dim oPL As PartsList
  Set oPL = ThisApplication.ActiveDocument.SelectSet(1)' This works
  Dim members(0) As String
  members(0) = "iPart-02"
  oPL.MembersToInclude = members
End Sub

Get Reference Distance of Hole Feature

$
0
0

By Xiaodong Liang

When you create hole feature, Inventor allows you to set the distances with the reference  edges. This can be got by HoleFeature.PlacementDefinition.DistanceOne and HoleFeature.PlacementDefinition.DistanceTwo

111

If the reference  are not defined, you could iterate the edges of outer edge loop and  calculate the distance by Edge.Geometry.DistanceTo(point).  The following is an VBA code as a demo:

 

Sub getHolePlacement()'select a hole feature in advance
    Dim oHoleF As HoleFeature
    Set oHoleF = ThisApplication.ActiveDocument.SelectSet(1)'get HolePlacementDefinition
    Dim oPlaceDef As HolePlacementDefinition
    Set oPlaceDef = oHoleF.PlacementDefinition'reference are defined ?
    Dim oDisOne As Parameter
    Dim oDisTwo As Parameter
    On Error Resume Next
    Set oDisOne = oPlaceDef.DistanceOne
    If Err.Number > 0 Then'no distance defined'get plane the hole locates at
        Dim oPlane As Face
        Set oPlane = oPlaceDef.Plane'get out edge loop
        Dim oOutLoop As EdgeLoop
         Dim oEachLoop As EdgeLoop
         For Each oEachLoop In oPlane.EdgeLoops
            If oEachLoop.IsOuterEdgeLoop Then
                Set oOutLoop = oEachLoop
                Exit For
            End If
         Next'iterate each edge and filter out the linear lines
        Dim oEachEdge As Edge
        For Each oEachEdge In oOutLoop.Edges
            If TypeOf oEachEdge.Geometry Is LineSegment Then
                Dim oLine As LineSegment
                Set oLine = oEachEdge.Geometry'caculate the distance of hole center and the edge
                Dim oDis As Double
                oDis = oLine.DistanceTo(oHoleF.HoleCenterPoints(1))
                Dim oLineDir As UnitVector
                Set oLineDir = oLine.Direction
                Debug.Print "distance to the vector ("& oLineDir.X &","& oLineDir.Y &","& oLineDir.Z &") is: "& oDis
            End If
        Next
    Else'distance are defined
         Set oDisTwo = oPlaceDef.DistanceTwo
         Debug.Print "distance one: "& oDisOne.Value &"  distance two: "& oDisTwo.Value
    End If
    Err.Clear

End Sub

Read Parameter values using Apprentice

$
0
0

By Adam Nagy

Unfortunately, Apprentice cannot access the Parameters of an Inventor document. You would need to use Inventor for that.
If firing up an Inventor instance would be too slow or not feasible for e.g. licensing reasons, a workaround could be setting those Parameters to export to iProperties:

Params2

In that case a corresponding iProperty will be automatically created and kept up-to-date in the "Inventor User Defined Properties" (Custom) section:

Params3

The good news is that iProperties can be read not only through Apprentice, but also using Structured Storage API, which is completely independent of Inventor. Here is a view of our Inventor part file in a program called Structured Storage Viewer:

Params1

Here is a sample using Structured Storage API to get information from an Inventor file: 
http://adndevblog.typepad.com/manufacturing/2013/03/save-extra-data-in-inventor-file-3.html

If setting the "Export Parameter" option for the Parameters you are interested in is not an option, then maybe you could run a batch process that stores those parameters somewhere else (e.g. in a CSV file named the same but with a ".csv" extension) next to the Inventor file, or create an Add-In which does the same but as part of the OnSaveDocument event of the ApplicationEvents object.

Include Sketch from a Part multi-level deep

$
0
0

By Adam Nagy

We already have a blog post on Include sketches from sub-assemblies in a DrawingView using a sketch proxy, but it does not cover the scenario where the Document the Sketch resides in is multi-level deep in the assembly hierarchy - i.e. it's a SubOccurrence of an Occurrence.

As I mentioned in this blog post you have to make sure that you are getting objects in the right context. You can either do that by reaching objects only through Occurrences and SubOccurrences collections (never using Definition) or if you have to use Definition then get the object back into the right context using CreateGeometryProxy().
If you do not follow that correctly, like the below code, then your program won't work:

IncludeSketchFromPart

Whenever you use the property "Definition" you leave the current context and move into a lower one. As you can see the code only brings the oPrtSketch entity into the context of the MidAssembly.iam document. However, the DrawingView is referencing TopAssembly.iam, so that is the context the objects you pass to it should be in.  

The quickest fix to the above code is taking note of the occurrence of MidAssembly.iam inside TopAssembly.iam (oMidAsmOcc) and doing an extra call to CreateGeometryProxy to bring the object into the context of TopAssembly.iam. New code highlighted in red: 

Sub IncludeSketchFromPart()
Dim oDwg As DrawingDocument
Set oDwg = ThisApplication.ActiveDocument

Dim oView As DrawingView
Set oView = oDwg.ActiveSheet.DrawingViews(1)

Dim oTopAsm As AssemblyDocument
Set oTopAsm = oView.ReferencedDocumentDescriptor.ReferencedDocument

'Dim oMidAsmDef As AssemblyComponentDefinition'Set oMidAsmDef = oAssy.ComponentDefinition.Occurrences.ItemByName("MidAssembly:1").DefinitionDim oMidAsmOcc As ComponentOccurrence
Set oMidAsmOcc = oTopAsm.ComponentDefinition.Occurrences.ItemByName("MidAssembly:1")

Dim oMidAsmDef As AssemblyComponentDefinition
Set oMidAsmDef = oMidAsmOcc.Definition

Dim oPrtOcc As ComponentOccurrence
Set oPrtOcc = oMidAsmDef.Occurrences.ItemByName("PartWithSketch:1")

Dim oSketch As PlanarSketch
Set oSketch = oPrtOcc.Definition.Sketches("PartSketch")

Dim oSketchProxy As PlanarSketchProxy
' This will get it into context of "MidAssembly.iam"
Call oPrtOcc.CreateGeometryProxy(oSketch, oSketchProxy)' This will get it into context of "TopAssembly.iam"
Call oMidAsmOcc.CreateGeometryProxy(oSketchProxy, oSketchProxy)

Call oView.SetVisibility(oSketchProxy, True)
End Sub

Need to use a Proxy for commands when editing a part in an assembly

$
0
0

By Wayne Brill

In the VBA example below a work plane in a part document is accessed and then the AppLookAtCmd is run. (changes the view to look directly at that WorkPlane)

To get AppLookAtCmd to use that WorkPlane it needs to be selected using the SelectSet of the assembly. (not the part) To get the WorkPlane in the assembly space use a WorkPlaneProxy. To create the WorkPlaneProxy use the ActiveOccurrence property of the assembly to get the occurrence of the part that is being edited and then use the CreateGeometryProxy method of the occurrence.   

Before running this example place a part in an assembly and then right click on the part in the Model browser and select Edit.

Public Sub selectionTest()
     'Get the object currently being edited.
    Dim ActiveObject As Object
    Set ActiveObject = ThisApplication.ActiveEditObject
   
    'Determine if a the object being edited is a document
    If Not TypeOf ActiveObject Is PartDocument Then
        Exit Sub
    Else
       Dim oDoc As Inventor.PartDocument
       Set oDoc = ActiveObject
    End If
   
    'Get the XY Plane of the part being edited
    Dim oWorkPlane As WorkPlane
    Set oWorkPlane = oDoc.ComponentDefinition.WorkPlanes("XY Plane")
     
   'Get the active document (an assembly)
    Dim oAsm As AssemblyDocument
    Set oAsm = ThisApplication.ActiveDocument
   
    ' The part that is being edited will be an occurrence
    Dim oOccurrence As ComponentOccurrence
    Set oOccurrence = oAsm.ComponentDefinition.ActiveOccurrence
   
    ' create a WorkPlaneProxy from the work plane in the part
    Dim oWorkPlaneProxy As WorkPlaneProxy
    oOccurrence.CreateGeometryProxy oWorkPlane, oWorkPlaneProxy
   
   ' Select the WorkPlaneProxy in the assembly
    oAsm.SelectSet.Select oWorkPlaneProxy
    
    ' Run the command it will use the work plane (a WorkPlaneProxy)
    ThisApplication.CommandManager.ControlDefinitions.Item("AppLookAtCmd").Execute
End Sub

Use Apprentice from multi-threaded application

$
0
0

By Adam Nagy

I wrote about it already that you can use Apprentice in a side-thread, but that sample only showed a single instance doing it:
http://adndevblog.typepad.com/manufacturing/2014/09/apprentice-in-side-thread.html

Now here is a sample running multiple Apprentice instances in the same application on different threads. Each thread creates its own ApprenticeServerComponent - note that this object can only be used from the thread that created it, since it's not thread-safe.

Depending on how much calculation you're doing and how your app is structured, it could also be a good idea to migrate the Apprentice usage into a separate app which could be used from the main application.

This sample project shows both ways of doing things and allows you to switch between them through the "Use Apprentice in-process" check box.

ApprenticeMultiThread

Source: 
https://github.com/adamenagy/Apprentice-MultiThread

By the way, if you want to set the Output directory of a .NET project relative to the Solution directory, you can do that by editing the project file in a text editor:

SolutionDir

C# project : setting output directory to solution dir

Viewing all 532 articles
Browse latest View live