How Does Inventor Assign Edges To A DrawingCurvesEnumerator.Item() Array?

How Does Inventor Assign Edges To A DrawingCurvesEnumerator.Item() Array?

vfantiniSE63W
Contributor Contributor
2,368 Views
7 Replies
Message 1 of 8

How Does Inventor Assign Edges To A DrawingCurvesEnumerator.Item() Array?

vfantiniSE63W
Contributor
Contributor

Greetings everyone,

 

Would anyone happen to know the method behind the madness in which Inventor assigns the Item Numbers of a component's DrawingCurves to the .Item() array within its DrawingCurvesEnumerator object?  To put it another way, what governs the order in which Inventor assigns each visible edge of a component within a DrawingView to its associated DrawingCurvesEnumerator.Item() array?  Allow me to elaborate by explaining how I wish to apply this knowledge...

 

I'm working on developing an automated shop drawing template for a "Crate Generator" tool that I've put together, and I've recently figured out how to auto-generate Leader Notes to the common components within my assembly model.  By using the DrawingCurvesEnumerator.Item() object, I've identified the desired edges that my Leader Notes are anchored to when they're generated.  Figuring out the .Item() numbers for each component's Leader Note edge was a tedious task that involved lots of trial & error.  But as you'll see below, it doesn't look half-bad.  (For the next bit of my explanation, let's focus on the CMLU024-082.1250 (TYP.) Leader Note at the bottom of this image...)

In this side view, you can see the auto-generated Leader Notes pointing to specific edges of each component.In this side view, you can see the auto-generated Leader Notes pointing to specific edges of each component.

 

So let's throw a wrench into the gears of this feature.  What happens when some unforeseen obstacle is obscuring one or more of these preset components?  Well, if a component is completely obscured, its Leader Notes simply don't get generated.  But if a component is partially obscured, then things get weird (see image below)...

When partially obscured, the edges' .Item() numbers within the DrawingCurvesEnumerator() object get changed up, making the Leader Note arrows point to unintended edges.When partially obscured, the edges' .Item() numbers within the DrawingCurvesEnumerator() object get changed up, making the Leader Note arrows point to unintended edges.

 

As you can see, things are all sorts of goofed up.  If you look again at the CMLU024-082.1250 (TYP.) Leader Note at the bottom of this second image, you'll notice that two of its three arrows are no longer pointing at the bottom edges of the horizontal components that it's annotating.  Instead, those two arrows are pointing at the shorter edges to the right of these components.

 

What I have figured out is that Inventor only assigns visible & partially visible edges of a component to that component's DrawingCurvesEnumerator.Item() array.  Any edge that's completely hidden by another component will not be part of the .Item() array.  This all makes sense; if only three out of four edges of a component are visible, then the .Item() array will only contain three elements instead of four elements.

 

In our example above, the CMLU024-082.1250 (TYP.) Leader Note is instructed to point to Edge #2 (i.e. DrawingCurvesEnumerator.Item(2)) of each component that it's associated with, which happens to be their bottom-most edges (see first image).  This edge was selected with the assumption that all four edges of these components are always visible.  But when one of those edges is completely obscured, there's only three edges left visible.  As we can see in the second image, the edges associated with DrawingCurvesEnumerator.Item(2) for the lower horizontal components refers to their shorter right-hand edges, rather than the bottom edges like in the first image.

 

What I'm trying to figure out is exactly how Inventor goes about assigning the visible edges of a component to its DrawingCurvesEnumerator.Item() array.  Does Inventor manage this assignment based on the order in which it renders each edge?  Does Inventor start at the lower-left point of the component and then assign each edge in a counter-clockwise manner?  What about when a component is shown in an isometric viewing angle; does Inventor use another method of assigning a component's edges???  I've tried figuring this out on my own, but I haven't really discerned any noticeable pattern that Inventor follows when assigning a component's edges in this fashion.  And it's driving me nuts!!!

 

My ultimate goal is to always have a Leader Note arrow pointed at a specific edge on a component in all scenarios (in the example above, I'd like for the CMLU024-082.1250 (TYP.) Leader Note's arrow heads to always point at the bottom-most edges of its horizontal components).  I'm not quite sure if this is possible, and it's all because I can't figure out how Inventor goes about assigning edges to the DrawingCurvesEnumerator.Item() array.

 

If anyone has any insight into how Inventor works its magic, please enlighten me.  It'd really help me out in fine-tuning this tool of mine so that it's as adaptable as possible.  Thanks in advance, and I hope to hear from you guys soon!

 

- Sincerely,

Vinny

Accepted solutions (2)
2,369 Views
7 Replies
Replies (7)
Message 2 of 8

vfantiniSE63W
Contributor
Contributor

Alright, my curiosity was eating at me, so I decided to do a study of this issue in hopes of gaining a glimpse on how Inventor decides to assign these .Item() numbers to a component's edges.  And hoo boy...  It's a confusing-looking mess.  I'm sure that there's a rhyme and reason to it (there has to be, otherwise Inventor would likely get stuck trying to decide which edge to render first), but I'm not picking up on it.  I figured I'd post some of my findings for others to see.  Perhaps one of you can help me figure out what's going on here.

 

To start off, I've put together a set of procedures to dynamically generate Leader Notes on any component that I specify by name (i.e. as it appears in the Model Tree) within a specified View on my drawing.  These procedures will find the named component, and then attach a Leader Note to each of its visible edges; each Leader Note will specify which edge number is assigned to each edge within that component's DrawingCurveEnumerator.Item() array:

Public Sub AnnotateComponentEdges()
' This procedure's purpose is to simply annotate every visible edge of a specified component with Leader Notes; each Leader Note will
' specify the .Item() number of each edge contained within the specified component's DrawingCurvesEnumerator.Item() array.
' This procedure will allow me to study how Inventor goes about assigning a component's edges to this array in hopes of figuring out
' the method behind Inventor's madness, as it'd greatly help me to better predict which edges to attach auto-generated Leader Notes to.
    
    ' Set a reference to the drawing document.
    Dim oDrawDoc As Inventor.DrawingDocument
    Set oDrawDoc = ThisApplication.ActiveDocument
       
    ' Set a reference to the active sheet.
    Dim oSheet As Inventor.Sheet
    Set oSheet = oDrawDoc.ActiveSheet
       
    ' Set a reference to all drawing views.
    Dim oViews As DrawingViews
    Set oViews = oSheet.DrawingViews
    
    ' This variable will specify which DrawingView we're referencing.
    Dim iViewNum As Integer
'    iViewNum = 1 ' sets oView to "VIEW1."
'    iViewNum = 5 ' sets oView to "VIEW5."
'    iViewNum = 6 ' sets oView to "VIEW6."
    iViewNum = 8
    
    ' Set a reference to the specified drawing view (iViewNum).
    Dim oView As Inventor.DrawingView
    Set oView = oViews.Item(iViewNum)
    
    ' Set a reference to the assembly document.
    Dim oAssyDoc As Inventor.AssemblyDocument
    Set oAssyDoc = oView.ReferencedDocumentDescriptor.ReferencedDocument
    
    ' Readies code for creation of reference points for dimension placement.
    Dim oTG As TransientGeometry
    Set oTG = ThisApplication.TransientGeometry

    ' This variable will fetch the parameters from the Crate Assembly Model.
    Dim oCrateParams As Parameters
    Set oCrateParams = oAssyDoc.ComponentDefinition.Parameters
    
    ' This variable will fetch the Crate Assembly Model's "unit_slot_count" parameter value.
    Dim oCrateUnitSlotCount As Parameter
    Set oCrateUnitSlotCount = oCrateParams.Item("unit_slot_count") ' returns 1, 2, 3 or 4.
    
    ' Set a reference to the Crate Assembly Model's component definition.
    Dim oCrateCompDef As AssemblyComponentDefinition
    Set oCrateCompDef = oAssyDoc.ComponentDefinition

    ' This variable will be used to reference an occurrence of oCrateCompDef.
    Dim oCrateCompOcc As Inventor.ComponentOccurrence
    
    ' This variable will be used to retrieve all of the rendered DrawingCurves of the current oCrateCompOcc component.
    Dim oDrawingCurvesEnum As DrawingCurvesEnumerator
    
    ' This variable will be set to the pre-selected DrawingCurve of the current oCrateCompOcc component that we'll be attaching a Leader Note to.
    Dim oDrawingCurve As DrawingCurve
'---------------------------------------------------------------------
    
    ' This String variable will contain the name of the component that we want to cover in Leader Notes.
    Dim sCompName As String
'    sCompName = "bracing_block_4r"
'    sCompName = "block_1b_us1"
'    sCompName = "block_1b_us4"
'    sCompName = "block_1t_us4"
'    sCompName = "top_cap_1"
    sCompName = "test_block_1A"
    
    ' First, we must locate the component occurrence of our named component (sCompName).  Once found, we can then assign the DrawingCurvesEnumerator
    ' of the named component to oDrawingCurvesEnum, which will allow us to then annotate the named component's edges.
    For Each oCrateCompOcc In oCrateCompDef.Occurrences
        ' We'll skip over all suppressed components, as well as components with no visible SurfaceBodies.
        If oCrateCompOcc.Suppressed = False And oCrateCompOcc.SurfaceBodies.Count > 0 Then
            ' If the current oCrateCompOcc's name matches sCompName, then we've found our component!  We assign the current component occurrence to
            ' oDrawingCurvesEnum, and then exit this For-Each loop.
            If oCrateCompOcc.Name = sCompName Then
                Set oDrawingCurvesEnum = oView.DrawingCurves(oCrateCompOcc)
                Exit For
            End If
        End If
    Next
    
    ' This variable will keep count of each DrawingCurve edge number as we iterate through them in the For-Each loop below.
    Dim iEdgeNum As Integer
    iEdgeNum = 1
    
    ' Now that we've assigned oDrawingCurvesEnum to our named component's DrawingCurves, we will create a For-Each loop to annotate each visible edge
    ' with a Leader Note.
    For Each oDrawingCurve In oDrawingCurvesEnum
        Call GenerateTestLeaderNote(iViewNum, oDrawDoc, oAssyDoc, oDrawingCurve, iEdgeNum)
        iEdgeNum = iEdgeNum + 1
    Next
End Sub

Public Sub GenerateTestLeaderNote(iViewNum, oDrawDoc, oAssyDoc, oDrawingCurve, iEdgeNum)
' This procedure's purpose is for testing purposes only, and is only to be used by the AnnotateComponentEdges() procedure.
' This procedure will generate a Leader Note on the rendered component edge within the specified View provided by AnnotateComponentEdges().

    ' Set a reference to the active sheet.
    Dim oSheet As Sheet
    Set oSheet = oDrawDoc.ActiveSheet

    ' Set a reference to all drawing views.
    Dim oViews As DrawingViews
    Set oViews = oSheet.DrawingViews

    ' Set a reference to the specified drawing view (iViewNum).
    Dim oView As Inventor.DrawingView
    Set oView = oViews.Item(iViewNum)
    
    ' This variable will contain the text that the Leader Note will display.
    Dim sLNText As String
    sLNText = "Edge #" & iEdgeNum

    ' Get the mid point of the selected curve, assuming that the selected curve is linear.
    Dim oMidPoint As Point2d
    Set oMidPoint = oDrawingCurve.MidPoint

    ' Set a reference to the TransientGeometry object.
    Dim oTG As TransientGeometry
    Set oTG = ThisApplication.TransientGeometry
    
    ' Create a reference to a TransientObjects' ObjectCollection.
    Dim oLeaderPoints As ObjectCollection
    Set oLeaderPoints = ThisApplication.TransientObjects.CreateObjectCollection
    
    ' This variable will be used for adding attribute values to each created dimension.
    Dim oDim1Att As AttributeSet

    ' Create a leader point that marks where the "elbow" of the Leader Note should be placed in relation to the arrow head's location
    ' (which is the MidPoint of our specified DrawingCurve).
    Call oLeaderPoints.Add(oTG.CreatePoint2d(oMidPoint.X + 1.5, oMidPoint.Y + 1.5))

    ' Create an intent and add to the leader points collection.
    ' This is the geometry that the leader text will attach to.
    Dim oGeometryIntent As GeometryIntent
    Set oGeometryIntent = oSheet.CreateGeometryIntent(oDrawingCurve, oMidPoint)

    Call oLeaderPoints.Add(oGeometryIntent)

    ' Generate the actual Leader Note on the drawing.
    Dim oLeaderNote As LeaderNote
    Set oLeaderNote = oSheet.DrawingNotes.LeaderNotes.Add(oLeaderPoints, sLNText)

    ' Now to give our oLeaderNote some custom attribute sets to allow us to delete only these auto-generated Leader Notes.
    Set oDim1Att = oLeaderNote.AttributeSets.Add("iLogic_Created")
    Set oDim1Att = oLeaderNote.AttributeSets.Add("ID")
End Sub

 

Let's start off with something simple - a 6-in. long 2x4 piece of lumber (I'll refer to this as our test block), oriented in three different positions.  When "flat-viewed" so that we can only see a single face of our test block at a time, the edge numbering seems to be rather consistent no matter how the visible face is oriented (see image below).  No matter how the visible face is rotated, the edge numbers appear to be consistent.

Each column of images here shows a single face of the test block.  From top to bottom, we see each chosen face in its default orientation, then rotated 90°, and then rotated 135° from its original orientation.Each column of images here shows a single face of the test block. From top to bottom, we see each chosen face in its default orientation, then rotated 90°, and then rotated 135° from its original orientation.

 

So what about when our test block is viewed isometrically?  Well, it takes what we've established thus far and throws it out the window (see image below).  I placed leader notes on the test blocks at the top of each "column" of the image above.  But as you can see here, the edge numbers in these isometric views don't relate at all to the edge numbers that were assigned in the "flat" views shown above.

NOTE:  Each image shown here correlates to the orientations seen at the top of each "column" within the previous image.NOTE: Each image shown here correlates to the orientations seen at the top of each "column" within the previous image.

 

Alright, well what if we look at one of these test blocks isometrically with its hidden edges shown?  Is there any consistency between the hidden & not-hidden isometric views?  Why, yes there is, apparently (see image below)!  Edges #1 - #9 are the same edges in both of these isometric views.  Edges #10 - #12 are the hidden edges.

Edges #1 - #9 are consistent between these two isometric views of the same testing block.Edges #1 - #9 are consistent between these two isometric views of the same testing block.

 

Alright, let's throw a curve ball at this study and see what we get when we try this out with the following custom block:

Here's the part drawing for the custom block that we'll see shortly...Here's the part drawing for the custom block that we'll see shortly...

So here's what we get when we run those procedures on this custom block:

The numerical order that the edges have is consistent for a bit, but the hidden edges throw off the sequence.The numerical order that the edges have is consistent for a bit, but the hidden edges throw off the sequence.

..Welp.  Apparently Edges #1 - #7 are consistent between both of these isometric views, but then the hidden lines cut into the sequence.  And here I was thinking that maybe hidden lines got the lower prioritization and were counted after all of the visible lines were numbered first.  Ugh...

 

I've some fuzzy guesses that perhaps the edges are numbered based on how a component is created, and its orientation to its local origin point.  But I've no actual proof of anything like that at this time.  I think that at this point I'm just going to stop looking into this myself, and hope that an Inventor developer happens to come along and sate my curiosity about this subject.  If anyone else has any clue how this works, please feel free to post about it.

 

 

Message 3 of 8

MechMachineMan
Advisor
Advisor
Accepted solution

I would think you would have a hard time regardless whether trying to go with internal edge collection or hard-coding.

 

 A potential option might be assigning assets to faces and then labeling them in the drawing by fetching the asset associated with the faces the edge is connected to.

 

Or use a straight up geometric algorithm to assign the notes in a specific pattern/


--------------------------------------
Did you find this reply helpful ? If so please use the 'Accept as Solution' or 'Like' button below.

Justin K
Inventor 2018.2.3, Build 227 | Excel 2013+ VBA
ERP/CAD Communication | Custom Scripting
Machine Design | Process Optimization


iLogic/Inventor API: Autodesk Online Help | API Shortcut In Google Chrome | iLogic API Documentation
Vb.Net/VBA Programming: MSDN | Stackoverflow | Excel Object Model
Inventor API/VBA/Vb.Net Learning Resources: Forum Thread

Sample Solutions:Debugging in iLogic ( and Batch PDF Export Sample ) | API HasSaveCopyAs Issues |
BOM Export & Column Reorder | Reorient Skewed Part | Add Internal Profile Dogbones |
Run iLogic From VBA | Batch File Renaming| Continuous Pick/Rename Objects

Local Help: %PUBLIC%\Documents\Autodesk\Inventor 2018\Local Help

Ideas: Dockable/Customizable Property Browser | Section Line API/Thread Feature in Assembly/PartsList API Static Cells | Fourth BOM Type
Message 4 of 8

vfantiniSE63W
Contributor
Contributor

Yeah, I kinda figured that I'm biting into something that's more than I can chew.  My curiosity is what draws me to pushing these kinds of limits, though, so I don't see myself stopping pursuits like this until I hit the figurative brick wall.

 

Speaking of which, these potential options that you've mentioned...  I haven't heard of this concept of assigning assets to faces before.  Would you happen to have any documentation and/or examples of the implementation of something like this?  My google powers seem to be lacking the proper keywords to find something that sounds like what you're talking about.

 

As for this idea of using a geometric algorithm to assign leader notes in a specific pattern, I'm curious if you could also elaborate on what you're suggesting here.  Do you mean an algorithm that would simply go through a list of components and attach leader notes in some kind of an encircling pattern around the entire assembly model?  I'm trying to envision what you're suggesting, and it might just be the mid-afternoon brain farts that are preventing me from interpreting you more clearly.

 

I wish there was an easy way of identifying the number of edges that are present for a given component, and then attaching a leader note to an edge that's oriented in a specific direction from some kind of reference point.  For example, let's say that I'd always want the lower-left edge of a particular component in a specific View to be annotated with an auto-generated leader note.  I'd want to write some kind of procedure that'd tally up the number of visible edges for the specified component, and then determine which edge number is positioned towards the lower-left corner of its View window.  Once that edge number is identified, the procedure would then call on another procedure to attach the leader note to that edge.  Hm...

 

I'm just thinking out loud here, but I think that maybe a procedure that compares the X & Y coordinates of each edge to identify their relative positions might be a way to approach the problem.  But then again, perhaps I'm making a mountain out of a mole hill here; I might be making this more complicated than it needs to be.  I dunno just yet.  I'll stew on it over the weekend.

Message 5 of 8

MechMachineMan
Advisor
Advisor

I meant attributesets instead of assets. My bad!

 

http://help.autodesk.com/view/INVNTOR/2019/ENU/?guid=GUID-FDF0E44C-32A8-4D45-9023-D1D63007F227

 

Your 4th and 5th points are exactly what I was referring to when i said geometry based.


--------------------------------------
Did you find this reply helpful ? If so please use the 'Accept as Solution' or 'Like' button below.

Justin K
Inventor 2018.2.3, Build 227 | Excel 2013+ VBA
ERP/CAD Communication | Custom Scripting
Machine Design | Process Optimization


iLogic/Inventor API: Autodesk Online Help | API Shortcut In Google Chrome | iLogic API Documentation
Vb.Net/VBA Programming: MSDN | Stackoverflow | Excel Object Model
Inventor API/VBA/Vb.Net Learning Resources: Forum Thread

Sample Solutions:Debugging in iLogic ( and Batch PDF Export Sample ) | API HasSaveCopyAs Issues |
BOM Export & Column Reorder | Reorient Skewed Part | Add Internal Profile Dogbones |
Run iLogic From VBA | Batch File Renaming| Continuous Pick/Rename Objects

Local Help: %PUBLIC%\Documents\Autodesk\Inventor 2018\Local Help

Ideas: Dockable/Customizable Property Browser | Section Line API/Thread Feature in Assembly/PartsList API Static Cells | Fourth BOM Type
Message 6 of 8

vfantiniSE63W
Contributor
Contributor
Accepted solution

I think that I may have come up with my solution (though I've yet to implement it, as that'll take a bit of time).  However, I've come up with the following code block that allowed me to find a new way to approach my problem!  I'll share what I've come up with, as I'm sure it could be useful for others who may be trying to automate their shop drawing processes.

 

This is a geometric pattern algorithm that takes a component's name (as it appears in the drawing's Model Tree) within a specified DrawingView, and then takes a specified cardinal direction (top, bottom, left, right, lower-left, lower-right, upper-left, upper-right).  The IdentifyDirEdges() procedure will then scan through the assembly model until it finds the specified component.

 

Once the component is found, this procedure will scan through its visible edges, and it'll use each edge's MidPoint values to determine which edge is furthest in the specified cardinal direction.  This procedure will then take that edge's DrawingCurve object, as well as the specified cardinal direction, and pass them along to the GenerateTestLeaderNote() procedure.

 

The GenerateTestLeaderNote() procedure will generate a Leader Note that's pointing to the selected edge, and it will label it with its edge number (a.k.a. its element number within the DrawingCurvesEnumerator.Item() array).  Not only that, but it will position the Leader Note's text flag in the same cardinal direction as specified by the sTargetEdgeDirection variable.

 

Public Sub IdentifyDirEdges()
' This procedure will scan through the positions of a specified component's visible edges, and then determine which edge is closest to the specified
' cardinal direction (top, bottom, left, right, upper-right, upper-left, lower-right, lower-left) of the View that it exists within.  Once found,
' this procedure will pass along the selected edge and the specified cardinal direction to the GenerateTestLeaderNote() procedure, which will generate
' a Leader Note for the selected edge.

    ' Set a reference to the drawing document.
    Dim oDrawDoc As Inventor.DrawingDocument
    Set oDrawDoc = ThisApplication.ActiveDocument
       
    ' Set a reference to the active sheet.
    Dim oSheet As Inventor.Sheet
    Set oSheet = oDrawDoc.ActiveSheet
       
    ' Set a reference to all drawing views.
    Dim oViews As DrawingViews
    Set oViews = oSheet.DrawingViews
    
    ' This variable will specify which DrawingView we're referencing.
    Dim iViewNum As Integer
    iViewNum = 1 ' sets oView to "VIEW1."
    
    ' Set a reference to the specified drawing view (iViewNum).
    Dim oView As Inventor.DrawingView
    Set oView = oViews.Item(iViewNum)
    
    ' Set a reference to the assembly document.
    Dim oAssyDoc As Inventor.AssemblyDocument
    Set oAssyDoc = oView.ReferencedDocumentDescriptor.ReferencedDocument
    
    ' Readies code for creation of reference points for dimension placement.
    Dim oTG As TransientGeometry
    Set oTG = ThisApplication.TransientGeometry

    ' This variable will fetch the parameters from the Crate Assembly Model.
    Dim oCrateParams As Parameters
    Set oCrateParams = oAssyDoc.ComponentDefinition.Parameters
    
    ' This variable will fetch the Crate Assembly Model's "unit_slot_count" parameter value.
    Dim oCrateUnitSlotCount As Parameter
    Set oCrateUnitSlotCount = oCrateParams.Item("unit_slot_count") ' returns 1, 2, 3 or 4.
'---------------------------------------------------------------------
    
    ' Set a reference to the Crate Assembly Model's component definition.
    Dim oCrateCompDef As AssemblyComponentDefinition
    Set oCrateCompDef = oAssyDoc.ComponentDefinition

    ' This variable will be used to reference an occurrence of oCrateCompDef.
    Dim oCrateCompOcc As Inventor.ComponentOccurrence
    
    ' This variable will be used to retrieve all of the rendered DrawingCurves of the current oCrateCompOcc component.
    Dim oDrawingCurvesEnum As DrawingCurvesEnumerator
'    Set oDrawingCurvesEnum = oView.DrawingCurves(bracing_block_4r)
'    MsgBox ("oDrawingCurvesEnum.Count = " & oDrawingCurvesEnum.Count) ' Returns "7"
    
    ' This variable will be set to the pre-selected DrawingCurve of the current oCrateCompOcc component that we'll be attaching a Leader Note to.
    Dim oDrawingCurve As DrawingCurve
'    Set oDrawingCurve = oDrawingCurvesEnum.Item(1)
'    MsgBox ("oDrawingCurve.Parent.Name = " & oDrawingCurve.Parent.Name) ' Returns "VIEW1"

    ' This variable will be used to store the left-most edge of the named component.
    Dim oTargetDwgCurve As DrawingCurve
'---------------------------------------------------------------------
    
    ' This String variable will contain the name of the component that we want to cover in Leader Notes.
    Dim sCompName As String
    sCompName = "block_1t_us4"
    
    ' This variable will be referenced to determine which direction the target edge should be in.  The acceptable values are as follows:
    ' top
    ' bottom
    ' left
    ' right
    ' upper-left
    ' upper-right
    ' lower-left
    ' lower-right
    Dim sTargetEdgeDirection As String
    sTargetEdgeDirection = "lower-left"
    
    ' First, we must locate the component occurrence of our named component (sCompName).  Once found, we can then assign the DrawingCurvesEnumerator
    ' of the named component to oDrawingCurvesEnum, which will allow us to then annotate the named component's edges.
    For Each oCrateCompOcc In oCrateCompDef.Occurrences
        ' We'll skip over all suppressed components, as well as components with no visible SurfaceBodies.
        If oCrateCompOcc.Suppressed = False And oCrateCompOcc.SurfaceBodies.Count > 0 Then
            ' If the current oCrateCompOcc's name matches sCompName, then we've found our component!  We assign the current component occurrence to
            ' oDrawingCurvesEnum, and then exit this For-Each loop.
            If oCrateCompOcc.Name = sCompName Then
                Set oDrawingCurvesEnum = oView.DrawingCurves(oCrateCompOcc)
                Exit For
            End If
        End If
    Next
    
    ' This variable will keep count of each DrawingCurve edge number as we iterate through them in the For-Each loop below.
    Dim iEdgeNum As Integer
    iEdgeNum = 1
    
    ' The following two variables will be used to compare and store each edge's X&Y coordinates.  The edge that's furthest to the left will be determined
    ' through the use of these two Double variables.
    Dim dXCoord As Double
    dXCoord = oDrawingCurvesEnum.Item(iEdgeNum).MidPoint.X
    
    Dim dYCoord As Double
    dYCoord = oDrawingCurvesEnum.Item(iEdgeNum).MidPoint.Y
    
    Set oTargetDwgCurve = oDrawingCurvesEnum.Item(iEdgeNum)
    
    ' This variable will be used to identify the target edge number that's furthest to the left.
    Dim iTargetEdgeNum As Integer
    iTargetEdgeNum = iEdgeNum
    
    ' Now that we've assigned oDrawingCurvesEnum to our named component's DrawingCurves, we will create a For-Each loop to cycle through each visible
    ' edge of the named component and compare their MidPoints' X&Y coordinates.  When the left-most edge has been identified, it'll be passed on to the
    ' GenerateTestLeaderNote() procedure to label this edge with a Leader Note.
    For Each oDrawingCurve In oDrawingCurvesEnum
        Select Case sTargetEdgeDirection
            Case "top"
                If oDrawingCurve.MidPoint.Y > dYCoord Then
                    dYCoord = oDrawingCurve.MidPoint.Y
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
            
            Case "bottom"
                If oDrawingCurve.MidPoint.Y < dYCoord Then
                    dYCoord = oDrawingCurve.MidPoint.Y
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
            
            Case "left"
                If oDrawingCurve.MidPoint.X < dXCoord Then
                    dXCoord = oDrawingCurve.MidPoint.X
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
                
            Case "right"
                If oDrawingCurve.MidPoint.X > dXCoord Then
                    dXCoord = oDrawingCurve.MidPoint.X
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
            
            Case "upper-left"
                If oDrawingCurve.MidPoint.X < dXCoord And oDrawingCurve.MidPoint.Y > dYCoord Then
                    dXCoord = oDrawingCurve.MidPoint.X
                    dYCoord = oDrawingCurve.MidPoint.Y
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
            
            Case "upper-right"
                If oDrawingCurve.MidPoint.X > dXCoord And oDrawingCurve.MidPoint.Y > dYCoord Then
                    dXCoord = oDrawingCurve.MidPoint.X
                    dYCoord = oDrawingCurve.MidPoint.Y
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
            
            Case "lower-left"
                If oDrawingCurve.MidPoint.X < dXCoord And oDrawingCurve.MidPoint.Y < dYCoord Then
                    dXCoord = oDrawingCurve.MidPoint.X
                    dYCoord = oDrawingCurve.MidPoint.Y
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
                
            Case "lower-right"
                If oDrawingCurve.MidPoint.X > dXCoord And oDrawingCurve.MidPoint.Y < dYCoord Then
                    dXCoord = oDrawingCurve.MidPoint.X
                    dYCoord = oDrawingCurve.MidPoint.Y
                    iTargetEdgeNum = iEdgeNum
                    Set oTargetDwgCurve = oDrawingCurve
                End If
            
            Case Else
                MsgBox ("ERROR:  Incorrect value for sTargetEdgeDirection (" & sTargetEdgeDirection & ").")
                Exit Sub
        End Select
        
        iEdgeNum = iEdgeNum + 1
    Next
    
    ' Now that we've identified the left-most edge for the named component, we'll annotate it with a Leader Note.
    Call GenerateTestLeaderNote(iViewNum, oDrawDoc, oAssyDoc, oTargetDwgCurve, iTargetEdgeNum, sTargetEdgeDirection)
End Sub

Public Sub GenerateTestLeaderNote(iViewNum, oDrawDoc, oAssyDoc, oDrawingCurve, iTargetEdgeNum, sTargetEdgeDirection)
' This procedure will generate a Leader Note on the rendered component edge within the specified View provided by AnnotateComponentEdges().
' The Leader Note's text flag will be positioned in the same direction as the cardinal direction specified by sTargetEdgeDirection.

    ' Set a reference to the active sheet.
    Dim oSheet As Sheet
    Set oSheet = oDrawDoc.ActiveSheet

    ' Set a reference to all drawing views.
    Dim oViews As DrawingViews
    Set oViews = oSheet.DrawingViews

    ' Set a reference to the specified drawing view (iViewNum).
    Dim oView As Inventor.DrawingView
    Set oView = oViews.Item(iViewNum)
    
    ' This variable will contain the text that the Leader Note will display.
    Dim sLNText As String
    sLNText = "Edge #" & iTargetEdgeNum

    ' Get the mid point of the selected curve
    ' assuming that the selected curve is linear
    Dim oMidPoint As Point2d
    Set oMidPoint = oDrawingCurve.MidPoint

    ' Set a reference to the TransientGeometry object.
    Dim oTG As TransientGeometry
    Set oTG = ThisApplication.TransientGeometry
    
    ' Create a reference to a TransientObjects' ObjectCollection.
    Dim oLeaderPoints As ObjectCollection
    Set oLeaderPoints = ThisApplication.TransientObjects.CreateObjectCollection
    
    ' This variable will be used for adding attribute values to each created dimension.
    Dim oDim1Att As AttributeSet
'--------------------------------------------------------------------------------------
    
    ' These variables will be used to offset the text flag of the auto-generated Leader Note based on which edge it's to be pointed at.
    Dim dXOffset As Double
    dXOffset = 0
    
    Dim dYOffset As Double
    dYOffset = 0
    
    ' This Select-Case block will assign the appropriate offset values to dXOffset & dYOffset.  These variables will then assist in
    ' positioning the Leader Note's text flag in a position according to the cardinal direction specified by sTargetEdgeDirection.
    Select Case sTargetEdgeDirection
        Case "top"
                dXOffset = 0
                dYOffset = 1.5
                
            Case "bottom"
                dXOffset = 0
                dYOffset = -1.5
            
            Case "left"
                dXOffset = -1.5
                dYOffset = 0
                
            Case "right"
                dXOffset = 1.5
                dYOffset = 0
            
            Case "upper-left"
                dXOffset = -1.5
                dYOffset = 1.5
            
            Case "upper-right"
                dXOffset = 1.5
                dYOffset = 1.5
            
            Case "lower-left"
                dXOffset = -1.5
                dYOffset = -1.5
                
            Case "lower-right"
                dXOffset = 1.5
                dYOffset = -1.5
            
            Case Else
                MsgBox ("ERROR:  Incorrect value for sTargetEdgeDirection (" & sTargetEdgeDirection & ").")
                Exit Sub
        End Select

    ' Create a leader point that marks where the "elbow" of the Leader Note should be placed in relation to the arrow head's location
    ' (which is the MidPoint of our specified DrawingCurve).
    Call oLeaderPoints.Add(oTG.CreatePoint2d(oMidPoint.X + dXOffset, oMidPoint.Y + dYOffset))

    ' Create an intent and add to the leader points collection.
    ' This is the geometry that the leader text will attach to.
    Dim oGeometryIntent As GeometryIntent
    Set oGeometryIntent = oSheet.CreateGeometryIntent(oDrawingCurve, oMidPoint)

    Call oLeaderPoints.Add(oGeometryIntent)

    ' Generate the actual Leader Note on the drawing.
    Dim oLeaderNote As LeaderNote
    Set oLeaderNote = oSheet.DrawingNotes.LeaderNotes.Add(oLeaderPoints, sLNText)

    ' Now to give our oLeaderNote some custom attribute sets to allow us to delete only these auto-generated Leader Notes.
    Set oDim1Att = oLeaderNote.AttributeSets.Add("iLogic_Created")
    Set oDim1Att = oLeaderNote.AttributeSets.Add("ID")
End Sub

 

Here are some images of the results of these test procedures.  I've executed these test procedures on each component multiple times, specifying each of the cardinal directions in every execution.

Success!!!Success!!!  It's a little wonky with oddly-shaped components, but still gets the job done.It's a little wonky with oddly-shaped components, but still gets the job done.  Here's a non-isometric view of the same wonky part.  These test procedures still do relatively well!Here's a non-isometric view of the same wonky part. These test procedures still do relatively well!

 

To implement these procedures into my Crate Generator tool, I'll need to come up with some lists of pre-selected cardinal directions for the key components that I wish to annotate with leader notes.  If this works out as beautifully as I believe it will, then I'll come back and accept your reply as my solution, MechMachineMan.

 

Thanks again for inspiring me to approach my problem from a different direction, MechMachineMan!  I was definitely looking at the problem from the most difficult perspective; trying to get super-deep into the workings of Inventor is a headache-inducing endeavor.  This helped pull me out of the deep end and approach the problem from a simpler direction.  Here's hoping that this works out as I believe it should!

 

Message 7 of 8

BrianEkins
Mentor
Mentor

For most of the collections returned from the API, you should never rely on the order of the objects in the collection and just make the assumption they're in a random order.  There are a few exceptions to this and they should be documented.  For example, the occurrences are returned in the same order as they appear in the browser.  The same is true for work features so you can rely on the first work plane in the collection being the YZ plane, the second being the XZ plane and the third the XY plane. 

 

Even if you find there does seem to be some kind of logical order it's still not good to rely on it because it's possible it could change based on other settings or even from release to release.

 

The best approach is to somehow match up the drawing curve with the geometry in the model.  Either by first getting the desired edge in the model and getting the associated drawing curve or starting with the drawing curve and getting the model curve.

 

Going from the drawing curve is very easy because the ModelGeometry property of the DrawingCurve object will return the Edge in the model.  To go the other way you use the DrawingCurves property and pass in the model geometry as its optional argument.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 8 of 8

vfantiniSE63W
Contributor
Contributor

Thanks for the suggestions, Brian!  I'll have to set aside some time to explore the DrawingCurve.ModelGeometry property and see if it might make things easier than my current solution.

 

Yeah, it was a hard lesson in figuring out that relying on the order of objects in a collection is a madman's quest.  But as long as I'm learning something useful in the process, and especially if I can walk away from it with a more efficient way of solving the problem, then it's all worth it.

 

Thanks for your help, everyone!