There was a recent Inventor question posted on stackoverflow that I thought was interesting and decided to look at. The question involved being able to project points from a sketch onto a solid. Below is a picture of a sketch that contains many sketch center points. In this case they were created by patterning a point to get a grid of points but they could be created in any way. The goal is to project all of these points onto the solid. For my program I chose to project them in the direction that is perpendicular (normal) to the sketch plane.
Here’s the result where the intersection points are created as work points.
The sketch can be in any orientation in space, as shown in the picture below. In this case the results were created as points within a 3D sketch.
And here’s the VBA code that I came up with to do this. It asks for the selection of a sketch (which you need to pick in the browser) and for a body. The next section of code is the most confusing but it’s basically trying to determine where the selected sketch is relative to the selected body and then computing a value so that when it begins projecting the points, the point it projects is outside of the solid. That’s actually the largest chunk of the code. Towards the bottom of the macro you’ll see where the actual intersection work takes place. It then prompts the user to select how to display the results where they can choose one of three ways; as work points, points in a 3D sketch, or written to a csv file.
Public Sub ProjectPoints()
' Have the sketch that contains the points selected.
Dim sk As PlanarSketch
Set sk = ThisApplication.CommandManager.Pick(kSketchObjectFilter, _
"Select the sketch")
' Have the body to project onto selected.
Dim body As SurfaceBody
Set body = ThisApplication.CommandManager.Pick(kPartBodyFilter, _
"Select the body")
' Get the part component definition.
Dim compDef As PartComponentDefinition
Set compDef = body.Parent
' *** Determine the side of the solid the sketch is on and if the
' *** sketch is outside the solid.
' Get the normal vector of the selected sketch.
Dim skNormal As UnitVector
Set skNormal = sk.PlanarEntityGeometry.Normal
Dim skRootPoint As Point
Set skRootPoint = sk.PlanarEntityGeometry.RootPoint
' Get the corners of the range box.
Dim tg As TransientGeometry
Set tg = ThisApplication.TransientGeometry
Dim cornerPoints(7) As Point
Dim range As Box
Set range = body.RangeBox
Set cornerPoints(0) = range.MinPoint
Set cornerPoints(1) = tg.CreatePoint(range.MinPoint.x, range.MinPoint.y, _
range.MaxPoint.Z)
Set cornerPoints(2) = tg.CreatePoint(range.MinPoint.x, range.MaxPoint.y, _
range.MinPoint.Z)
Set cornerPoints(3) = tg.CreatePoint(range.MinPoint.x, range.MaxPoint.y, _
range.MaxPoint.Z)
Set cornerPoints(4) = range.MaxPoint
Set cornerPoints(5) = tg.CreatePoint(range.MaxPoint.x, range.MinPoint.y, _
range.MaxPoint.Z)
Set cornerPoints(6) = tg.CreatePoint(range.MaxPoint.x, range.MinPoint.y, _
range.MinPoint.Z)
Set cornerPoints(7) = tg.CreatePoint(range.MaxPoint.x, range.MaxPoint.y, _
range.MinPoint.Z)
' Construct a matrix where the X axis is along the sketch plane normal.
Dim xAxis As Vector
Set xAxis = skNormal.AsVector
Dim yAxis As Vector
Set yAxis = tg.CreateVector(xAxis.x + 1, xAxis.y + 1, xAxis.Z + 1)
Dim zAxis As Vector
Set zAxis = xAxis.CrossProduct(yAxis)
Set yAxis = zAxis.CrossProduct(xAxis)
xAxis.Normalize
yAxis.Normalize
zAxis.Normalize
Dim transform As Matrix
Set transform = tg.CreateMatrix
Call transform.SetCoordinateSystem(skRootPoint, xAxis, yAxis, zAxis)
transform.Invert
' Transform the range box points and compare them to sketch plane.
Dim i As Integer
Dim smallX As Double
For i = 0 To 7
Call cornerPoints(i).TransformBy(transform)
If i = 0 Then
smallX = cornerPoints(i).x
Else
If cornerPoints(i).x < smallX Then
smallX = cornerPoints(i).x
End If
End If
Next
' Determine the offset needed to position the points outside the solid.
Dim offset As Double
If smallX < 0 Then
offset = -(smallX + 10)
Dim tempNormal As Vector
Set tempNormal = skNormal.AsVector
Call tempNormal.ScaleBy(-1)
Set skNormal = tempNormal.AsUnitVector
Else
offset = 0
End If
Dim offsetVector As Vector
Set offsetVector = skNormal.AsVector
Call offsetVector.ScaleBy(offset)
' *** Perform the intersection calculation of every center point in the sketch.
Dim resultPoints As ObjectCollection
Set resultPoints = ThisApplication.TransientObjects.CreateObjectCollection
Dim skPoint As SketchPoint
For Each skPoint In sk.SketchPoints
' Check to see if the point is a center point.
If skPoint.HoleCenter Then
' Get the sketch point as a transient 3D point.
Dim pnt As Point
Set pnt = skPoint.Geometry3d
' Move the point outside the solid.
Call pnt.TranslateBy(offsetVector)
' Intersect the point with the solid.
Dim foundEnts As ObjectsEnumerator
Dim locPoints As ObjectsEnumerator
Call body.FindUsingRay(pnt, skNormal, 0.00001, foundEnts, locPoints, True)
' If an intersection was found, add it to the list.
If locPoints.count > 0 Then
Call resultPoints.Add(locPoints.Item(1))
End If
End If
Next
' Prompt the user for which type of output they want.
Dim result As String
result = InputBox("Enter choice for output:" & vbCrLf & "1 - Work points" & _
vbCrLf & "2 - 3D sketch" & vbCrLf & "3 - csv File", _
"Enter output type", 3)
If result = "1" Or result = "2" Then
' Start a transaction so that the creation is grouped in a single undo.
Dim trans As Transaction
Set trans = ThisApplication.TransactionManager.StartTransaction( _
ThisApplication.ActiveDocument, "Projected Points")
If result = "1" Then
' Create work points.
For i = 1 To resultPoints.count
Call compDef.WorkPoints.AddFixed(resultPoints.Item(i))
Next
End If
If result = "2" Then
' Create a 3D sketch and points in the sketch.
Dim sk3D As Sketch3D
Set sk3D = compDef.Sketches3D.Add()
For i = 1 To resultPoints.count
Call sk3D.SketchPoints3D.Add(resultPoints.Item(i))
Next
End If
trans.End
ElseIf result = "3" Then
' Write the points out to a file.
Open "C:\Temp\Points.csv" For Output As #1
For i = 1 To resultPoints.count
Print #1, Format(resultPoints.Item(i).x, "0.00000000") & "," & _
Format(resultPoints.Item(i).y, "0.00000000") & "," & _
Format(resultPoints.Item(i).Z, "0.00000000")
Next
Close #1
MsgBox "File written to ""C:\Temp\Points.csv"""
Else
MsgBox "Invalid Input"
End If
End Sub
Hopefully this is useful as a starting point for something you might want to do. It at least demonstrates a couple of interesting things.
This is all Inventor but for those of you using Fusion, Fusion doesn’t currently have the API functionality to fire a ray through the model so this can’t be done in the same way. I do expect that to be available at some point in the future though.
-Brian