Trying to generate workpoints using named geometry

Trying to generate workpoints using named geometry

jessey9X6M8
Enthusiast Enthusiast
4,464 Views
34 Replies
Message 1 of 35

Trying to generate workpoints using named geometry

jessey9X6M8
Enthusiast
Enthusiast

I am trying to use iLogic to generate an array of workpoints on the hull of a tugboat (to export heights to an Excel sheet indexed by x,y coordinates), but I keep getting the following error message:

Error in rule: Generate_WPoints, in document: Hull Shape.ipt

Unable to cast COM object of type 'System.__ComObject' to interface type 'Inventor.Face'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{5DF8608B-6B16-11D3-B794-0060B0F159EF}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

and under "More Info":

System.InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to interface type 'Inventor.Face'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{5DF8608B-6B16-11D3-B794-0060B0F159EF}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
   at ThisRule.Main()
   at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
   at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)

 

I think it has something to do with the named geometry I am trying to use.  I have a surface model of the hull, which includes 15 surfaces that I have named Hull0 - Hull14.  I have written one rule to generate a grid of vertical workplanes and another to generate work axes at the intersections of the workplanes, each guided by parameters for overall width and length, along with the desired mesh size.  That brings us to the code in question.  

 

	'Set up variables for the current part document and its components.
Dim oDoc As PartDocument = ThisApplication.ActiveDocument
Dim oDef As PartComponentDefinition = ThisDoc.Document.ComponentDefinition
	'This line is necessary to work with named geometry.
Dim oNames As NamedEntities = iLogicVb.Automation.GetNamedEntities(oDoc)
	'These variables are to intersect axes with surfaces to generate points.
Dim oPoint As WorkPoint
Dim oAxis As WorkAxis
Dim oHull As Face
	'Define and initialize incrementing variables starting at FWD Port corner.
Dim X, Y As Integer
X = 0
Y = -1 * Mesh * Floor(OAW / Mesh / 2) / (1 in)
	'Increment through all existing work axes.  Find which, if any, hull surface
	'each axis intersects with, create a workpoint there, and name it.
While Y <= OAW / (2 in)
	X = 0
	While X <= OAL / (1 in)
		oAxis = oDef.WorkAxes.Item("Axis_" & CStr(X) & "_" & CStr(Y))
		For k = 0 To 14
			oHull = oNames.FindEntity("Hull" & CStr(k))
			oPoint = oDef.WorkPoints.AddByCurveAndEntity(oHull, oAxis)
			oPoint.Name = "Point_" & CStr(X) & "_" & CStr(Y)
		Next
		X = X + Mesh / (1 in)
	End While
	Y = Y + Mesh / (1 in)
End While

 I would greatly appreciate the silver bullet for the error in this code.  However, I would just as heartily welcome any constructive suggestions improving my workflow.

0 Likes
Accepted solutions (1)
4,465 Views
34 Replies
Replies (34)
Message 2 of 35

WCrihfield
Mentor
Mentor

I take it this is a local rule (saved within the part file), and not an external rule right?

And that "Mesh" & "OAW" are local Parameters (within this part file)?

I'm not quite understanding some of your math.  Why would you divide any number by (1 in)?

Are you aware that all raw numbers within the code environment, that are representing measurements, are understood as centimeters?  If you are trying to use Inches, you will have to multiply your numbers by 2.54.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 3 of 35

jessey9X6M8
Enthusiast
Enthusiast

Correct.  This is a local rule.  OAL and OAW are driven paramaters for overall length and width, and Mesh is a user parameter. 

 

All parameters are measured in inches, so dividing by 1 inch serves to make the values dimensionless.  In the rules that generate workplanes and axes, the centimeter default is taken into account. 

 

The origin of the coordinate system is centered at the forward end of the vessel with a height that can be regarded as arbitrary but below the entire hull.

0 Likes
Message 4 of 35

WCrihfield
Mentor
Mentor

Maybe try defining oHull as a SurfaceBody instead of a Face, and see if that works.  You said the model had 15 surfaces.  Do you mean that at the top of the Model browser pane, there is a folder named Surface Bodies with a count of 15 in it?  If so, this change might work.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 5 of 35

jessey9X6M8
Enthusiast
Enthusiast

Unfortunately, the model has only 1 surface body, comprising 15 surface faces.

0 Likes
Message 6 of 35

jessey9X6M8
Enthusiast
Enthusiast

Again, I am fairly certain that the issue lies in referencing the named geometry.  I have not been able to find any conclusive documentation on the syntax dealing with this newish feature.  If anyone has some special insight into named geometry in iLogic, I am all ears.

0 Likes
Message 7 of 35

WCrihfield
Mentor
Mentor

Instead of oNames.FindEntity(), try oNames.Entities.Item("Hull" & CStr(k)), or oNames.Entities.Value("Hull" & CStr(k)).

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 8 of 35

WCrihfield
Mentor
Mentor

@jessey9X6M8 

And if that doesn't work, try just creating a simple local rule (to test with) and use the same first 3 lines of code to get the NamedEntities, then use one of those last suggestions, but instead of a combined string with the CStr(k), just type the whole name in, the way it should be.  Then just use a MsgBox() or something similar to display something about that specific item.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 35

Anonymous
Not applicable

As a pre-note the Inventor API says AddByCurveAndEntity doesn't currently work when creating workpoints in an assembly, not sure if this affects you or not.

 

Based on your error I think I may have a solution. The NamedEntities.FindEntity function returns a generic object while your oHull is defined as a Face.

Found here 

Your error basically says it can't make an Object into a Face, So I would suggest defining oHull as Object instead.

 

 

 

0 Likes
Message 10 of 35

jessey9X6M8
Enthusiast
Enthusiast

Fortunately, I am working in a part.  I checked the process manually before coding, and generating points in this way works.  I must admit, you gave me a bit of a scare for a moment.  That would have dead-ended my code.

 

I tried as an object, and it still erred.  Admittedly, the error is different, but it still won't run.

0 Likes
Message 11 of 35

jessey9X6M8
Enthusiast
Enthusiast

I tried what you suggested and it does not like any combination.  Honestly I have about come to the conclusion that named geometry is just not the way to go here.  Maybe I should just try a "for each" loop, if I can find where those faces exist.

0 Likes
Message 12 of 35

JhoelForshav
Mentor
Mentor

Hi @jessey9X6M8 

Could you attach your ipt? (or a similar example if the ipt in question is confidential) 🙂

0 Likes
Message 13 of 35

jessey9X6M8
Enthusiast
Enthusiast

I think it is sufficiently stripped down that we can work on it here.  Thanks.

 

The idea is to get a set of heights indexed by x and y that can be exported to a spreadsheet.

0 Likes
Message 14 of 35

JhoelForshav
Mentor
Mentor

Hi @jessey9X6M8 

Unfortunatley I'm still running Inventor 2020 at the time being, so I couldn't open your part properly with all the axes, parameters etc. I should have thought of that. I still think It's good though that the part is attached in the thread so other people can use it to debug your code 🙂

 

If I understand correctly you want a bunch of points representing your shape. Since I cannot see the axes you intend to use while creating these points I can't see the logic regarding their placement, so this suggestion might not at all be what you're looking for. But anyways, what are your thoughts on something like this?

 

Dim nrOfPoints As Integer = 3 'Nr of points/edge
Dim oDoc As PartDocument = ThisDoc.Document
For Each oSurf As WorkSurface In oDoc.ComponentDefinition.WorkSurfaces
	For Each oSurfBod As SurfaceBody In oSurf.SurfaceBodies
		For Each oEdge As Edge In oSurfBod.Edges
			oEvaluator = oEdge.Evaluator
			Dim oMinP, oMaxP As Double 
			oEvaluator.GetParamExtents(oMinP, oMaxP)

			Dim dLen As Double
			Call oEvaluator.GetLengthAtParam(oMinP, oMaxP, dLen)
			
			Dim dInc As Double
			dInc = dLen / nrOfPoints        
			
			Dim dLenInc As Double
			dLenInc = 0

			Dim dparams(0) As Double
			dparams(0) = oMinP
			
			Dim iCnt As Integer

			For iCnt = 0 To nrOfPoints
				Dim dParam As Double
				Call oEvaluator.GetParamAtLength(oMinP,
				dInc * iCnt,
				dParam)
				
				Dim dPts(1) As Double
				dparams(0) = dParam
				
				oEvaluator.GetPointAtParam(dparams, dPts)
				
				oDoc.ComponentDefinition.WorkPoints.AddFixed(ThisApplication.TransientGeometry.CreatePoint(dPts(0), dPts(1), dPts(2)))

			Next
		Next
	Next
Next

This code uses all the edges of the surfaces and creates a specified number of points evenly divided along each edge.

0 Likes
Message 15 of 35

JhoelForshav
Mentor
Mentor

The code I just posted creates a lot of duplicate points. This is better.

Dim nrOfPoints As Integer = 3
Dim oDoc As PartDocument = ThisDoc.Document
Dim oPoints As New List(Of String)
For Each oSurf As WorkSurface In oDoc.ComponentDefinition.WorkSurfaces
	For Each oSurfBod As SurfaceBody In oSurf.SurfaceBodies
		For Each oEdge As Edge In oSurfBod.Edges
			oEvaluator = oEdge.Evaluator
			Dim oMinP, oMaxP As Double
			oEvaluator.GetParamExtents(oMinP, oMaxP)

			Dim dLen As Double
			Call oEvaluator.GetLengthAtParam(oMinP, oMaxP, dLen)

			Dim dInc As Double
			dInc = dLen / nrOfPoints

			Dim dLenInc As Double
			dLenInc = 0

			Dim dparams(0) As Double
			dparams(0) = oMinP

			Dim iCnt As Integer

			For iCnt = 0 To nrOfPoints
				Dim dParam As Double
				Call oEvaluator.GetParamAtLength(oMinP,
				dInc * iCnt,
				dParam)

				Dim dPts(1) As Double
				dparams(0) = dParam

				oEvaluator.GetPointAtParam(dparams, dPts)
				If oPoints.Contains(String.Format("{0};{1};{2}", dPts(0).ToString, dpts(1).ToString, dpts(2).ToString)) = False
					oDoc.ComponentDefinition.WorkPoints.AddFixed(ThisApplication.TransientGeometry.CreatePoint(dPts(0), dPts(1), dPts(2)))
					oPoints.Add(String.Format("{0};{1};{2}", dPts(0).ToString, dpts(1).ToString, dpts(2).ToString))
				End If
			Next
		Next
	Next
Next
0 Likes
Message 16 of 35

jessey9X6M8
Enthusiast
Enthusiast

Thank you for your reply.  I tried your code.  As advertised, it generates points along the edges.  What I need is basically a projection of a rectangular grid of points from the XY Plane onto the hull surface.  Then I will measure the distance of each point to the hull, export the array of heights to Excel, and use it in another assembly.

 

By the way, I found an old copy of the hull in a 2019 format and rewrote the first couple of rules, if you are still interested.

0 Likes
Message 17 of 35

Anonymous
Not applicable

Can you share the error you got when you tried oHull as an object?

 

Also if we can't figure out how to get the faces from the NamedEntities, you should be able to define them from the surface body. Maybe something like this:

 

 

 

Dim oFaceCol as FaceCollection = oApp.TransientObjects.CreateFaceCollection
Dim oSurf as SurfaceBody = oDef.SurfaceBodies.Item(0)

For i = 0 to 14
Dim oFace as Face = oSurf.Faces.Item(i)
oFaceCol.Add(oFace)
Next

 

 

 

This is assuming the first 15 faces in the surface body are the ones you need. If not, I'm not really sure how to identify the index of the faces without some trial and error. But if this does work for you, you should just be able to plug it into your code. (I don't think using a FaceCollection is actually necessary, you could probably use List(Of...) instead, but it seems a bit simpler.)

 

 

 

For k = 0 To 14
			oHull = oFaceCol.Item(k)
			oPoint = oDef.WorkPoints.AddByCurveAndEntity(oHull, oAxis)
			oPoint.Name = "Point_" & CStr(X) & "_" & CStr(Y)
		Next

 

 

 

 

0 Likes
Message 18 of 35

jessey9X6M8
Enthusiast
Enthusiast

Error Message:

Error in rule: Test, in document: Hull Shape.ipt

The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))

More Info:

System.ArgumentException: The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
   at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
   at Inventor.WorkPoints.AddByCurveAndEntity(Object Curve, Object Entity, Object ProximityPoint, Boolean Construction)
   at ThisRule.Main()
   at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
   at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)

 

Also, I had a message box show me the number of surface bodies this model has, and it read 0.  The body is actually a non-parametric base feature.  If I can figure out how to reference it, I will probably just do a "for each" loop.

0 Likes
Message 19 of 35

Anonymous
Not applicable

Based on the error it seems the FindEntity isn't finding an entity with your parameters in the NamedEntities collection.

 

Can you try a couple tests in your code?

 

 

MsgBox(oName.Entities.Count)

MsgBox(oName.NameExists("Hull0"))

MsgBox(oName.Entities.Name(0))

 

 

0 Likes
Message 20 of 35

jessey9X6M8
Enthusiast
Enthusiast

917

True

Error:

 

Error in rule: Test, in document: Hull Shape.ipt

The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))

 

More Info:

 

System.ArgumentException: The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
   at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
   at Inventor.NameValueMap.get_Name(Int32 Index)
   at ThisRule.Main()
   at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
   at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)

 

Although replacing the 0 in your last entry with a 1 returned "Hull0".

 

0 Likes