Get TypeName from DocumentType

Get TypeName from DocumentType

PolemEngineering
Advocate Advocate
793 Views
9 Replies
Message 1 of 10

Get TypeName from DocumentType

PolemEngineering
Advocate
Advocate

I like to use the settings "Option Explicit On" and "Option Strict On" in my code.
This helps me to catch any errors during the design phase.

Unfortunately, this sometimes also costs a lot of extra code (For example, to prevent Late Binding).

I try to avoid creating a Class myself (I know that the Class ThisRule is created at runtime anyway). But this helps to keep using IntelliSense. A Global Module with Shared variables is not possible because of this. Because of this I have to, among other things, pass everything ByVal or ByRef when calling Sub-routines.

 

I ensure the existence of (1) User Parameters and (2) custom iProperties (create if not existing). Then (3) I provide these Parameters with a specific format (and export settings) and (4) I provide iProperties (if different) with a calculated value, based on certain conditions. In (3) and (4) I walk through all States if FactoryDocument with ModelStates.Count >=1.

 

For this, I have an extensive iLogic rule (multiple subs and functions) for managing User Parameters and (Custom) iProperties. This Rule starts abstract, arranges some general matters (writeability, referencing factory document, etc.) and then executes some more explicit actions based on DocumentType.
For this I have to perform a type conversion on "oDoc" to AssemblyDocument, PartDocument or DrawingDocument in several places in my code.
Is it possible to get the TypeName of oDoc.DocumentType and use it as input for CType(oDoc, <here>)?

I want to call a series of subroutines with a "For Each oModelState as ModelState in oDoc.ModelStates". The code for Parts and Assemblies is the same in this respect.

The subroutines themselves further determine how they handle Parts and Assemblies.

 

 

René van der Starre

0 Likes
794 Views
9 Replies
Replies (9)
Message 2 of 10

PolemEngineering
Advocate
Advocate

I could use Shared Variables, if:
- I make sure they are removed when the Rule is finalized
- I am sure that, when multiple documents trigger the External Rule, they are still processed one by one (and document 2 does not continues with information from document 1).

René van der Starre

0 Likes
Message 3 of 10

hollypapp65
Advocate
Advocate
Dim oTempDoc As Inventor.DrawingDocument
Dim oDoc As Inventor.Document
Dim oDrawDoc As Inventor._DrawingDocument
Dim oPartDoc As Inventor.PartDocument
Dim oAssemDoc As Inventor.AssemblyDocument

oDoc = ThisApplication.ActiveDocument
Select Case oDoc.DocumentType 
Case DocumentTypeEnum.kDrawingDocumentObject
	oDrawDoc = TryCast(oDoc, Inventor._DrawingDocument)
	DrawingUpdate(oDrawDoc)
Case DocumentTypeEnum.kPartDocumentObject
	oPartDoc = TryCast(oDoc, Inventor.PartDocument)
	PartUpdate(oPartDoc)
Case DocumentTypeEnum.kAssemblyDocumentObject
	oAssemDoc = TryCast(oDoc, Inventor.AssemblyDocument)
	AssemUpdate(oAssemDoc)
End Select
0 Likes
Message 4 of 10

hollypapp65
Advocate
Advocate

I use:

 

Option Explicit On
Option Strict On
Option Infer Off

 

Also try to use pure VB code.

This keep intellisense working and no type error when late blinding failed.

0 Likes
Message 5 of 10

PolemEngineering
Advocate
Advocate

Of course, there are many roads that lead to Rome.

It is precisely the specific creation of variables such as oPartDoc, oAsmDoc etc. that makes the code less abstract.

I have now solved it by giving an extra argument ByRef to my GetFactoryDocument function. This is already working with the ModelStates object. Then it can also assign a reference to the ModelStates object.

Function GetFactoryDocument(ByRef oDoc As Document, ByRef oModelStates As ModelStates) As Document

	If (oDoc Is Nothing) Then Return Nothing

	Dim oDocType As DocumentTypeEnum = oDoc.DocumentType

	If Not ((oDocType = DocumentTypeEnum.kPartDocumentObject) Or (oDocType = DocumentTypeEnum.kAssemblyDocumentObject)) Then
		Return oDoc
	End If

	If (oDocType = DocumentTypeEnum.kPartDocumentObject) Then
		Dim oDef As PartComponentDefinition = TryCast(oDoc, PartDocument).ComponentDefinition
		oModelStates = oDef.ModelStates
		If (oDef.IsModelStateMember) Then
			Return oDef.FactoryDocument
		ElseIf (oDef.IsModelStateFactory) Then
			Return oDoc
		End If
	End If
	
	If (oDocType = DocumentTypeEnum.kAssemblyDocumentObject) Then
		Dim oDef As AssemblyComponentDefinition = TryCast(oDoc, AssemblyDocument).ComponentDefinition
		oModelStates = oDef.ModelStates
		If (oDef.IsModelStateMember) Then
			Return oDef.FactoryDocument
		ElseIf (oDef.IsModelStateFactory) Then
			Return oDoc
		End If
	End If
	'senseless
	Return oDoc
End Function

René van der Starre

0 Likes
Message 6 of 10

WCrihfield
Mentor
Mentor

Hi @PolemEngineering.  When it comes to checking document type in my codes, I have mostly switched over from using the Document.DocumentType property, and the DocumentTypeEnum Enum, to using the TypeOf Operator.  It seems to process faster, looks easier to read, and often takes a little less code, so typing it that way is also a bit faster.  Since you are already using TryCast Operator, which requires the a 'type name' (not a String), using the 'TypeOf' operator would be a very natural and logical adaptation to go along with it.  There are obviously more variations within the DocumentTypeEnum than there are 'type names' to check against with the 'TypeOf' operator, but 99% of the time I'm only checking for those 3 main types (drawing, part, assembly) anyways.  Sometimes, depending on the situation, I also like to just create my own set of Boolean type variables, which have their values set from those checks, as seen in my examples below.

 

I actually did some local testing using the System.Diagnostics.StopWatch, and found that the 'TypeOf' checks processed 2 to 3 times faster than the DocumentTypeEnum checks.  Below are two extremely basic iLogic rules you can test this theory with, as I did.

TypeOf checks test

Dim oDoc As Inventor.Document = ThisDoc.Document
Dim bIsDrawing, bIsPart, bIsAssembly As Boolean
Dim oSW As New System.Diagnostics.Stopwatch()
oSW.Start()
bIsDrawing = (TypeOf oDoc Is DrawingDocument)
bIsPart = (TypeOf oDoc Is PartDocument)
bIsAssembly = (TypeOf oDoc Is AssemblyDocument)
oSW.Stop()
Logger.Info("TypeOf Test Elapsed Ticks = " & oSW.ElapsedTicks.ToString)
oSW.Reset()

DocumentTypeEnum checks test

Dim oDoc As Inventor.Document = ThisDoc.Document
Dim bIsDrawing, bIsPart, bIsAssembly As Boolean
Dim oSW As New System.Diagnostics.Stopwatch()
oSW.Start()
bIsDrawing = (oDoc.DocumentType = DocumentTypeEnum.kDrawingDocumentObject)
bIsPart = (oDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject)
bIsAssembly = (oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject)
oSW.Stop()
Logger.Info("DocumentTypeEnum Test Elapsed Ticks = " & oSW.ElapsedTicks.ToString)
oSW.Reset()

If this solved your problem, or answered your question, please click ACCEPT SOLUTION .
Or, if this helped you, please click (LIKE or KUDOS) 👍.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 7 of 10

PolemEngineering
Advocate
Advocate

Wow, I didn't know it made that much of a difference. I'm going to make this habit my own.

René van der Starre

0 Likes
Message 8 of 10

WCrihfield
Mentor
Mentor

If taking the next logical step, and checking DocumentSubType, there are a couple other tips that you may find useful.

Most of us who have been writing code to automate Inventor for a while have come across the following common properties of the Document object, and attempted to use them.

Document.DocumentSubType 

Document.SubType 

That first one 'DocumentSubType' appears to now be 'retired', because we can no longer find any further information about how to check its value within the online help documentation, and the links to the value type it returns are now broken.  However, it seems as though Autodesk has chosen to continue supporting its functionality in the background, to keep from 'breaking' the functionality of 'legacy' solutions, for now.  It claims to return a value that is DocumentSubType Type (not a String or Enum), and when we look older code examples using it, they use it like this [Document.DocumentSubType.DocumentSubTypeID = ], which indicates that value Type was an object that had a property named 'DocumentSubTypeID, which had a String type value, which was one of those long GUID type, unreadable pattern of letters, numbers, & symbols.

The second one 'Document.SubType' actually returns the same value as 'Document.DocumentSubType.DocumentSubTypeID' did, and does so with far less code or complication.

However, both of them leave us with a value we can not directly read, or understand clearly.

And, there is yet another way to get that same value from a Document, through its standard iProperties, in its third PropertySet named 'Design Tracking Properties' (aka 'Project'), and its property at index 16, named 'Document SubType'.

 

However, if you want a value that you can actually read, and understand, we can use the very next iProperty in that same set, named 'Document SubType Name' (index 17).  If it is a regular part, it will return "Modeling" (for some reason), if a sheet metal part, it will contain "Sheet Metal" text, if regular assembly, it will contain "Assembly" text, if a weldment type assembly, it will contain "Weldment" text, and so on.  This same exact value can be seen within the standard iProperties dialog, on the Project tab, beside the label "File Subtype:" in every document.

 

The last year or two, I have mostly switched from checking SubType using any of the above mentioned ways, to using the 'TypeOf' operator on the ComponentDefinition object directly, instead.  It seems to require less code, and is equally easy to read and understand (at least for me).  This is because pretty much every SubType has a unique type of ComponentDefinition to match it, and then some.  ComponentDefinition is a base type, which has several other, more specific types derived from it, for special purposes/uses.  And some of those sub types even have other more specific sub types derived from them also.  At this point in my codes, I am usually about to declare a variable for the ComponentDefinition anyways, which usually requires me typing that TypeName anyways, so this is another relatively efficient and logical way to check it.

Below is a simple iLogic rule which extracts that same SubTypeID value from the Document object in all 3 ways that I know of, plus shows the 'readable' way I mentioned, but does not show the 'TypeOf' check on the ComponentDefinition, because it does not fit this situation very well.

Dim oDoc As Inventor.Document = ThisDoc.Document
Dim sSubType_ID_1 As String = oDoc.DocumentSubType.DocumentSubTypeID
Dim sSubType_ID_2 As String = oDoc.SubType
Dim sSubType_ID_3 As String = oDoc.PropertySets.Item(3).Item(16).Value
Dim sSubTypeName As String = oDoc.PropertySets.Item(3).Item(17).Value
MessageBox.Show("Document SubType Info:" & vbCrLf & _
"Document.DocumentSubType.DocumentSubTypeID = " & sSubType_ID_1 & vbCrLf & _
"Document.SubType = " & sSubType_ID_2 & vbCrLf & _
"'Document SubType' iProperty Value = " & sSubType_ID_3 & vbCrLf & _
"'Document SubType Name' iProperty Value = " & sSubTypeName, _
"This Document's SubType Info", MessageBoxButtons.OK, MessageBoxIcon.Information)

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 10

PolemEngineering
Advocate
Advocate

I was wondering about that too. How do you get the TypeOf variables? Logger.Info(TypeName(ThisDoc.Document)) after using it a few times it suddenly gives _DocumentClass.

 

For DocumentSubType I now use a standard piece of code.

Sub Main
...
	If Not SharedVariable.Exists("DocSubType") Then
		Dim ReadableDocSubType As Inventor.NameValueMap = ThisApplication.TransientObjects.CreateNameValueMap()
		SharedVariable.Value("DocSubType") = ReadableDocSubType
		Call AddDocSubTypes(ReadableDocSubType)
	End If
...
End Sub

 

Sub AddDocSubTypes(ByRef ReadableDocSubType As Inventor.NameValueMap)
	'[ Populate the ReadableDocSubType NameValueMap for easy translation later on...
	ReadableDocSubType.Add("{E60F81E1-49B3-11D0-93C3-7E0706000000}", "Assembly")
	ReadableDocSubType.Add("{BBF9FDF1-52DC-11D0-8C04-0800090BE8EC}", "Drawing")
	ReadableDocSubType.Add("{4D29B490-49B2-11D0-93C3-7E0706000000}", "Part")
	ReadableDocSubType.Add("{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}", "Sheet Metal Part")
	ReadableDocSubType.Add("{28EC8354-9024-440F-A8A2-0E0E55D635B0}", "Weldment")
	']
End Sub

 

 

René van der Starre

0 Likes
Message 10 of 10

WCrihfield
Mentor
Mentor

That's not a bad idea.  I also had the thought to create my own DocumentSubTypeEnum within an external rule, so I could reference it with 'AddVbFile' from other rules, but I don't recall if I ever finished that thought / idea, to be honest, because I am certainly not using it right now.

Below is a link to my Inventor Ideas post where I am asking Autodesk to add a DocumentSubTypeEnum, or something similar, to make that step easier.

https://forums.autodesk.com/t5/inventor-ideas/create-enum-for-documentsubtype-amp-or-document-subtyp... 

 

Checking TypeOf ComponentDefinition is not universal way of checking document sub type, but just another tool to keep in the tool belt.  I have found it very useful in some situations, but it might not be ideal for 100% of situations.  For instance drawings do not have one, and there are some types of ComponentDefinition that do not have a Document associated with them, even if they do have that Property named Document.  Below is just a generic sample code I just threw together, because I usually just use a single line in various rules and methods, in various places.

 

Dim oDoc As Inventor.Document = ThisDoc.Document
Dim oCD As ComponentDefinition = Nothing
Try : oCD = oDoc.ComponentDefinition : Catch : End Try
Dim bIsDrawing, bIsPart, bIsSheetMetal, bIsFlatPattern, bIsAssembly, bIsWeldment, bIsWelds, bIsVirtual As Boolean

'I do not know of any sub types of drawings, plus they do not have a ComponentDefinition
bIsDrawing = (TypeOf oDoc Is DrawingDocument)
'next one may be true for both regular parts and sheet metal, since sheet metal is derived from part
bIsPart = (oCD IsNot Nothing) AndAlso (TypeOf oCD Is PartComponentDefinition)
'this one is more specific
bIsSheetMetal = (oCD IsNot Nothing) AndAlso (TypeOf oCD Is SheetMetalComponentDefinition)
'this is similar, but not derived from sheet metal definition type
bIsFlatPattern = (oCD IsNot Nothing) AndAlso (TypeOf oCD Is FlatPattern)
'this one may be true for regular assembly and weldment, because weldment derived from assembly
bIsAssembly = (oCD IsNot Nothing) AndAlso (TypeOf oCD Is AssemblyComponentDefinition)
'this one is more specific
bIsWeldment = (oCD IsNot Nothing) AndAlso (TypeOf oCD Is WeldmentComponentDefinition)
'this is not derived from weldment type, and is just the welds in a weldment
bIsWelds = (oCD IsNot Nothing) AndAlso (TypeOf oCD Is WeldsComponentDefinition)
'no actual document, just for adding useful rows into BOM
bIsVirtual = (oCD IsNot Nothing) AndAlso (TypeOf oCD Is VirtualComponentDefinition)

MsgBox( _
"IsDrawing = " & bIsDrawing & vbCrLf & _
"IsPart = " & bIsPart & vbCrLf & _
"IsSheetMetal = " & bIsSheetMetal & vbCrLf & _
"IsFlatPattern = " & bIsFlatPattern & vbCrLf & _
"IsDrawing = " & bIsDrawing & vbCrLf & _
"IsAssembly = " & bIsAssembly & vbCrLf & _
"IsWeldment = " & bIsWeldment & vbCrLf & _
"IsWelds = " & bIsWelds & vbCrLf & _
"IsVirtual = " & bIsVirtual)

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes