Get coordinates of work point at assembly level

Get coordinates of work point at assembly level

Curtis_Waguespack
Consultant Consultant
1,973 Views
16 Replies
Message 1 of 17

Get coordinates of work point at assembly level

Curtis_Waguespack
Consultant
Consultant

I have a workpoint in a component file that is some unknown levels down in an assembly. I want to get the location of this workpoint relative to the top level assembly. What is the best way to get the coordinates?

 

Currently I am traversing the assembly and creating a proxy object, but this seems to only give me the correct coordinates down a couple of levels. 

 

My understanding is that a proxy object should get the entire path of the component all the way down the assembly structure, as stated here:

"...A proxy is a reference to an object that exists outside the top-level component, and the proxy defines the full path from the top-level down to the object. The path is made up of a list of occurrences, and the final item in the path is the object itself.  ..." quote from here:

https://forums.autodesk.com/t5/inventor-ilogic-and-vb-net-forum/difference-between-componentoccurren...

 

So it seems that because I am creating the proxy at the subassembly, at the the level in which I find it as I traverse the components, the proxy does not contain the full path and therefor  doesn't report the correct coordinates.

 

Thanks in advance.

Curtis

 

See attached example files ( Inv 2022) 

 

Here the point's coordinates are at 2.222, 1.866, 4.444 in the assembly as shown by the sketch dims

 

 

Curtis_Waguespack_0-1674419796693.png

 

Curtis_Waguespack_0-1674418694030.png

 

 

 

Public Sub Main()

	Dim oAsmDoc As AssemblyDocument
	oAsmDoc = ThisApplication.ActiveDocument
	Dim oAsmDef As AssemblyComponentDefinition
	oAsmDef = oAsmDoc.ComponentDefinition

	Dim oOccs As ComponentOccurrences = oAsmDoc.ComponentDefinition.Occurrences
	Call TraverseAssembly(oAsmDef, oOccs)

End Sub

Function TraverseAssembly(oAsmDef As AssemblyComponentDefinition, oOccs As ComponentOccurrences)

	Dim oWPProxy As WorkPointProxy 'Proxy


	Dim oOcc As ComponentOccurrence
	For Each oOcc In oOccs

		Dim oWP As WorkPoint
		For Each oWP In oOcc.Definition.WorkPoints

			If Not UCase(oWP.Name).Contains("TEST") Then Continue For

			Call oOcc.CreateGeometryProxy(oWP, oWPProxy)

			Dim xCoord, yCoord, zCoord As Double

			xCoord = oWPProxy.Point.X
			yCoord = oWPProxy.Point.Y
			zCoord = oWPProxy.Point.Z

			oLine = "X: " & Round(xCoord, 3) & vbLf & "Y: " & Round(yCoord, 3) & vbLf & "Z: " & Round(zCoord, 3)
			Logger.Info(oLine)

			MsgBox(oLine, ,  oWP.Name )

		Next

		If oOcc.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
			'step into subassembly
			oSubOccs = oOcc.Definition.Document.ComponentDefinition.Occurrences
			Call TraverseAssembly(oAsmDef, oSubOccs)
		End If
	Next
End Function

 

 

 

 

 

 

EESignature

0 Likes
Accepted solutions (2)
1,974 Views
16 Replies
Replies (16)
Message 2 of 17

Curtis_Waguespack
Consultant
Consultant

I also get the same results attempting to create a temporary workpoint from a component work point

 

Public Sub Main()

	Dim oAsmDoc As AssemblyDocument
	oAsmDoc = ThisApplication.ActiveDocument
	Dim oAsmDef As AssemblyComponentDefinition
	oAsmDef = oAsmDoc.ComponentDefinition

	Dim oOccs As ComponentOccurrences = oAsmDoc.ComponentDefinition.Occurrences
	Call TraverseAssembly(oAsmDef, oOccs)

End Sub

Function TraverseAssembly(oAsmDef As AssemblyComponentDefinition, oOccs As ComponentOccurrences)

	Dim oWPProxy As WorkPointProxy 'Proxy


	Dim oOcc As ComponentOccurrence
	For Each oOcc In oOccs

		Dim oWP As WorkPoint
		Dim oTempWP As WorkPoint
		For Each oWP In oOcc.Definition.WorkPoints

			If Not UCase(oWP.Name).Contains("TEST") Then Continue For

			oTempWP = ThisDoc.Document.ComponentDefinition.WorkPoints.AddFixed(oWP.Point)
			oTempWP.name = oWP.Name & "_TEMP"


			Dim xCoord, yCoord, zCoord As Double

			xCoord = oTempWP.Point.X
			yCoord = oTempWP.Point.Y
			zCoord = oTempWP.Point.Z

			oLine =  "X: " & Round(xCoord, 3) & vbLf & "Y: " & Round(yCoord, 3) & vbLf & "Z: " & Round(zCoord, 3)
		
			MsgBox(oLine, , oTempWP.Name)
			oTempWP.delete

		Next

		If oOcc.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
			'step into subassembly
			oSubOccs = oOcc.Definition.Document.ComponentDefinition.Occurrences
			Call TraverseAssembly(oAsmDef, oSubOccs)
		End If
	Next
End Function

EESignature

0 Likes
Message 3 of 17

JelteDeJong
Mentor
Mentor

I tried to open your zip file but it seems broken. can you send it again?

 

 

 

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

Message 4 of 17

JelteDeJong
Mentor
Mentor

I assume the work point is in a part file. You could search all leaf occurrences. that way you don't need to transfer all sub-assemblies. Something like this:

Dim doc As AssemblyDocument = ThisDoc.Document
Dim workPointProxy As WorkPointProxy

For Each occ As ComponentOccurrence In doc.ComponentDefinition.Occurrences.AllLeafOccurrences
	Try
		If (occ.Suppressed) Then Continue For
		For Each workPoint As WorkPoint In occ.Definition.WorkPoints

			If Not WorkPoint.Name.ToUpper().Contains("TEST") Then Continue For

			occ.CreateGeometryProxy(WorkPoint, workPointProxy)

			Dim xCoord = workPointProxy.Point.X
			Dim yCoord = workPointProxy.Point.Y
			Dim zCoord = workPointProxy.Point.Z

			Dim nl = System.Environment.NewLine

			Dim oLine = String.Format("X: {1}{0} Y: {2}{0} Z: {3}",
						nl, Math.Round(xCoord, 3), Math.Round(yCoord, 3), Math.Round(zCoord, 3))

			MsgBox(oLine)
		Next
	Catch ex As Exception
		MsgBox("exception on occurrence:" & occ.Name)
	End Try
Next

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

Message 5 of 17

mat_hijs
Collaborator
Collaborator

I believe you will have to create a proxy for each level of the assembly. So if you have a top level assembly containing a subassembly containing a part with the workpoint you'll have to create a proxy of the workpoint in the subassembly and then create a proxy of the proxy in the top level assembly.

Message 6 of 17

mat_hijs
Collaborator
Collaborator

I tried to create a little test to show what I meant and this location seems to be correct. The code I wrote is not elegant in any way and is also not recursive, but it does show how it works.

Here is the code:

 

Dim oAsmDoc As AssemblyDocument = ThisApplication.ActiveDocument
Dim oAsmCompDef As AssemblyComponentDefinition = oAsmDoc.ComponentDefinition
Dim oOccurrencesLevel2 As ComponentOccurrences = oAsmCompDef.Occurrences
Dim oOccurrenceLevel2 As ComponentOccurrence = oOccurrencesLevel2.Item(1)
Dim oOccurrencesLevel3 As ComponentOccurrences = oOccurrenceLevel2.Definition.Occurrences
Dim oOccurrenceLevel3 As ComponentOccurrence = oOccurrencesLevel3.Item(1)

Dim oWorkPointLevel3 As WorkPoint = oOccurrenceLevel3.Definition.WorkPoints.Item("WPT_Location")
Dim oWorkPointProxyLevel2 As WorkPointProxy
oOccurrenceLevel3.CreateGeometryProxy(oWorkPointLevel3, oWorkPointProxyLevel2)
Dim oWorkPointProxyLevel1 As WorkPointProxy
oOccurrenceLevel2.CreateGeometryProxy(oWorkPointProxyLevel2, oWorkPointProxyLevel1)

MsgBox("X: " & oWorkPointProxyLevel1.Point.X & ", Y: " & oWorkPointProxyLevel1.Point.Y & ", Z: " & oWorkPointProxyLevel1.Point.Z)

Message 7 of 17

Curtis_Waguespack
Consultant
Consultant

Hi @JelteDeJong 

 

Thank you for having a look.


I think I have fixed the zip file. I re-uploaded it and it seems to download properly for me now:

https://forums.autodesk.com/autodesk/attachments/autodesk/120/148090/4/WP%20location%202022.zip

 

Unfortunately, there could be workpoints that I am needing to retrieve in parts an/or assemblies, so All Leaf Occurrences will not work in this case.

 

Thanks again,
Curtis

 

EESignature

0 Likes
Message 8 of 17

Curtis_Waguespack
Consultant
Consultant

Hi @mat_hijs 

 

Thank you for your reply.

 

Creating a proxy for each level will be a challenge since I can not predict the number of levels. 

 

Maybe I can write something to get the level of each found workpoint and then loop and create proxies that many times to get back to the top level. It seems like there should be a cleaner way to do so though.

 

Thank again,
Curtis

EESignature

0 Likes
Message 9 of 17

Michael.Navara
Advisor
Advisor

You don't need to traverse assembly tree. Just use work point proxy to get coordinates in assembly context

Dim asm As AssemblyDocument = ThisDoc.Document

For Each occ As ComponentOccurrence In asm.ComponentDefinition.Occurrences.AllLeafOccurrences()
	Dim partDef As PartComponentDefinition = occ.Definition
	Dim wp As WorkPoint = partDef.WorkPoints("WP-TEST 55")
	Logger.Debug("Local coords: [{0:N3}, {1:N3}, {2:N3}]", wp.Point.X, wp.Point.Y, wp.Point.Z)

	Dim wpProxy As WorkPointProxy
	occ.CreateGeometryProxy(wp, wpProxy)
	Logger.Debug("Assy coords: [{0:N3}, {1:N3}, {2:N3}]", wpProxy.Point.X, wpProxy.Point.Y, wpProxy.Point.Z)

Next
Message 10 of 17

WCrihfield
Mentor
Mentor

Hi @Curtis_Waguespack.  I don't know if you have ever seen these code tools I have posted here on the forums before, but they can be quite useful in situations like this, where there may be an unknown number of levels of an assembly involved, and you need a reference to something deep within the assembly.

 

To start things off, here is a very simple little function for simply identifying if an object is a 'proxy' or not.  I use this technique in the following solutions.

 

Function IsProxy(oObj As Object) As Boolean
	If IsNothing(oObj) Then Return False
	If TypeName(oObj).EndsWith("Proxy") Then Return True
	Return False
End Function

 

 

Here is a tool for getting the true/native 'source' object from a top level proxy object, even if it represents something that is really many levels deep.

 

Function GetProxySource(oProxyObj As Object) As Object
	If IsNothing(oProxyObj) Then Return Nothing
	Dim oNativeObject As Object = Nothing
	If TypeName(oProxyObj).EndsWith("Proxy") = False Then
		oNativeObject = oProxyObj
	Else
		oNativeObject = GetProxySource(oProxyObj.NativeObject)
	End If
	Return oNativeObject
End Function

 

And here is a tool for the opposite direction.  You can input a lower level proxy object, that may be many levels own, then get its 'top level' proxy object in return.

 

Function GetTopLevelProxy(oInputObj As Object) As Object
	If IsNothing(oInputObj) Then Return Nothing
	'if it is not already a Proxy object, return original input object
	If TypeName(oInputObj).EndsWith("Proxy") = False Then Return oInputObj
	'possible input proxy objects
	'EdgeProxy, FaceProxy, VertexProxy
	'MeshEdgeProxy, MeshFaceProxy, MeshVertexProxy
	'WorkAxisProxy, WorkPlaneProxy, WorkPointProxy, WorkSurfaceProxy
	'Do all have a ContainingOccurrence property? - Yes
	'Do all have a Parent property, and if so, what do they return? - Yes
	' - EdgeProxy, FaceProxy, & VertexProxy Parent returns SurfaceBody
	' - All work features Parent returns ComponentDefinition
	'All do have the NativeObject property, which should be obvious. - Yes
	Dim oParentOcc As ComponentOccurrence = oInputObj.ContainingOccurrence
	Dim oNextLevelUpProxy As Object = Nothing
	oParentOcc.CreateGeometryProxy(oInputObj, oNextLevelUpProxy)
	If oParentOcc.ParentOccurrence Is Nothing Then 'it is top level component
		Return oNextLevelUpProxy
	Else 'this proxy's containing component is not a top level component
		GetTopLevelProxy(oNextLevelUpProxy)
	End If
End Function

 

 And finally, another little tool, that is not 'proxy' related, but could be useful in the same overall code solution.  When 'climbing the ladder' in an assembly structure, to get a reference to the 'proxy' of an object at the 'parent' level, you will need to know when you get to the top level, so you know when to stop the loop/cycle.  This is just a 1-liner embedded in a Function.

 

Function IsTopLevelComponent(oComp As ComponentOccurrence) As Boolean
	If IsNothing(oComp) Then Return False
	If oComp.ParentOccurrence Is Nothing Then Return True
	Return False
End Function

 

Maybe these tools will help with your challenge here.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 11 of 17

Curtis_Waguespack
Consultant
Consultant

Hi @Michael.Navara,

 

Thank you for the reply.

 

Unfortunately, I can't use All Leaf Occurrences because the workpoints might be in a subassemblies and/or parts. And I can not call the workpoints by name as they are unknown.

 

So I will need to traverse the assembly to find them, and then create the proxy. And therein lies the rub, in that the proxy get created at the level that the point is found.

 

Thanks again,
Curtis

 

 

EESignature

0 Likes
Message 12 of 17

Curtis_Waguespack
Consultant
Consultant

Hi @WCrihfield,

 

Thanks for taking a look.

 

I only had a brief look at the functions you provided for the moment. I'll give them a closer look later when I have time, but I think I might see a way to use one of these to round up all the proxies created as I traverse the assembly and then create proxies of them at the top level to get their location at the top. 

 

Thanks again,
Curtis

EESignature

0 Likes
Message 13 of 17

jjstr8
Collaborator
Collaborator
Accepted solution

@Curtis_Waguespack :  A quick test showed me that you need to traverse the occurrences tree solely, not occurrences in the definitions.  In other words, iterate Occurrences from the top level and SubOccurrences from each top level occurrence and sub-occurrences downward.  That will give you an occurrence that is in the context of the top level assembly.

Message 14 of 17

JelteDeJong
Mentor
Mentor

What about looping over all reference documents to find the document with the point? Then find the occurrence that belongs to the document. Something like this:

Dim doc As AssemblyDocument = ThisDoc.Document
Dim foundWorkPoint As WorkPoint
Dim foundDoc As Document

For Each refDoc As Document In doc.AllReferencedDocuments
	For Each workPoint As WorkPoint In refDoc.ComponentDefinition.WorkPoints

		If Not WorkPoint.Name.ToUpper().Contains("TEST") Then Continue For
		foundWorkPoint = WorkPoint
		foundDoc = refDoc
		Exit For
	Next
Next

Dim occs = doc.ComponentDefinition.Occurrences.AllReferencedOccurrences(foundDoc)
If (occs.Count > 1) Then
	MsgBox("Multiple docs found wit the workpoint!")
End If
Dim occ = occs.Item(1)

Dim workPointProxy As WorkPointProxy
occ.CreateGeometryProxy(foundWorkPoint, workPointProxy)

Dim xCoord = workPointProxy.Point.X
Dim yCoord = workPointProxy.Point.Y
Dim zCoord = workPointProxy.Point.Z

Dim nl = System.Environment.NewLine

Dim oLine = String.Format("X: {1}{0} Y: {2}{0} Z: {3}",
				nl, Math.Round(xCoord, 3), Math.Round(yCoord, 3), Math.Round(zCoord, 3))
MsgBox(oLine)

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

Message 15 of 17

JelteDeJong
Mentor
Mentor

After writing the last post I thought of this blog post "Universal occurrence search function" that I wrote some time ago and wanted to check if it would help you. But I came to the conclusion that it would not work. So I thought it would be cool to make a "Universal occurrence search function" that would work. Below is the result but I'm not so sure it's better.  What do you think?

Sub Main()
	Dim doc As AssemblyDocument = ThisDoc.Document

	Dim occs = FindAllWhere(doc, AddressOf HasWorkPointWithNameTest)

	If (occs.Count > 1) Then
		MsgBox("Multiple docs found wit the workpoint!")
	End If
	Dim occ = occs.First

	Dim workpoints As WorkPoints = occ.Definition.WorkPoints
	Dim filterdWorkpoints = workpoints.Cast(Of WorkPoint).
		Where(Function(wp) wp.Name.Contains("TEST"))

	If (filterdWorkpoints.Count > 1) Then
		MsgBox("Multiple workpoint found in occ!")
	End If

	Dim workPointProxy As WorkPointProxy
	occ.CreateGeometryProxy(filterdWorkpoints.First, workPointProxy)

	Dim xCoord = workPointProxy.Point.X
	Dim yCoord = workPointProxy.Point.Y
	Dim zCoord = workPointProxy.Point.Z

	Dim nl = System.Environment.NewLine

	Dim oLine = String.Format("X: {1}{0} Y: {2}{0} Z: {3}",
			nl, Math.Round(xCoord, 3), Math.Round(yCoord, 3), Math.Round(zCoord, 3))
	MsgBox(oLine)


End Sub

Public Function HasWorkPointWithNameTest(doc As Document) As Boolean
	Dim workpoints As WorkPoints = doc.ComponentDefinition.WorkPoints
	Dim points = workpoints.Cast(Of WorkPoint).Where(Function(wp) wp.Name.Contains("TEST"))
	Return (points.Count <> 0)
End Function


Public Function FindAllWhere(doc As AssemblyDocument,
			predicate As Func(Of Document, Boolean)) As IEnumerable(Of ComponentOccurrence)

	Dim docList As IEnumerable(Of Document) = doc.
		AllReferencedDocuments.Cast(Of Document).
		Where(predicate)

	Dim occList As New List(Of ComponentOccurrence)
	For Each refDoc As Document In docList
		Dim occs = doc.ComponentDefinition.Occurrences.AllReferencedOccurrences(refDoc).Cast(Of ComponentOccurrence).ToList()
		occList.AddRange(occs)
	Next

	Return occList
End Function

 

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

Message 16 of 17

Curtis_Waguespack
Consultant
Consultant
Accepted solution

@jjstr8 

 

That was it! 👍

 

Thanks!!!

 

 

 

Public Sub Main()
	Dim oAsmDoc As AssemblyDocument
	oAsmDoc = ThisApplication.ActiveDocument
	Dim oAsmDef As AssemblyComponentDefinition
	oAsmDef = oAsmDoc.ComponentDefinition
	Dim oOccs As ComponentOccurrences = oAsmDoc.ComponentDefinition.Occurrences
	Call TraverseAssembly(oAsmDef, oOccs)
End Sub

Function TraverseAssembly(oAsmDef As AssemblyComponentDefinition, oOccs As ComponentOccurrences)
	Dim oWPProxy As WorkPointProxy
	Dim oOcc As ComponentOccurrence
	For Each oOcc In oOccs
		Dim oWP As WorkPoint
		For Each oWP In oOcc.Definition.WorkPoints
			If Not UCase(oWP.Name).Contains("TEST") Then Continue For
			Call oOcc.CreateGeometryProxy(oWP, oWPProxy)
			Dim xCoord, yCoord, zCoord As Double
			xCoord = oWPProxy.Point.X
			yCoord = oWPProxy.Point.Y
			zCoord = oWPProxy.Point.Z
			oLine = "X: " & Round(xCoord, 3) & vbLf & "Y: " & Round(yCoord, 3) & vbLf & "Z: " & Round(zCoord, 3)
			MsgBox(oLine, , oWP.Name)
		Next
		If oOcc.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
			'step into subassembly
			oSubOccs = oOcc.SubOccurrences
			Call TraverseAssembly(oAsmDef, oSubOccs)
		End If
	Next
End Function

EESignature

Message 17 of 17

Curtis_Waguespack
Consultant
Consultant

@JelteDeJong 

 

Thanks those work really well!

EESignature

0 Likes