I was working on answering a question recently and put together a bit of code to make sure my answer was correct and thought it might be useful to some others so I want to share it here.
The initial question was a good one. The question was how to create an offset work plane in an assembly using the API. The obvious thing is to use the AddByPlaneAndOffset method of the WorkPlanes collection but if you try it, it will fail and if you look at the help it will tell you that it’s not supported in assemblies, but it also doesn’t say how to do it.
Assemblies and construction geometry are a bit strange. Working interactively with Inventor, work geometry seems to work just that same as when working in a part, but if you look close you’ll see a big difference. If you create an offset work plane using the UI in an assembly and then look at the result in the browser you’ll see the work plane in the browser just like you would in a part, except in an assembly the work plane browser node can be expanded and then you’ll see that there’s a flush constraint. Work geometry in a part has intelligence within itself to know what it’s related to and how it’s related so if that geometry is modified it can correctly re-compute itself. Work geometry in an assembly isn’t intelligent at all. It just exists in space and the intelligence to position it is done by adding constraints.
The assembly work geometry commands have a lot of intelligence in them and will create the work geometry and automatically add the needed constraints to get the desired behavior. The API doesn’t do this. You can create a work plane in space but then you need to add the flush constraint as a separate step. In an assembly, the only way you can create work geometry is to use the AddFixed methods on each of the work geometry collections.
Below is the VBA code I wrote to test this. It demonstrates getting a selected face and then creating a work plane on that face. I’m using an offset of 0, but any offset could be used. A fair amount of the code is just figuring out the orientation of the work plane. Although the orientation doesn’t really matter except for looks. To get a logical orientation it uses the longest linear edge on the selected face and if there aren’t any linear edges then it aligns it with one of the primary model axes. The UI command also does some additional work to size the created work plane to fit the geometry, which the API and this sample doesn’t do. The API does support setting the size of a work plane but I haven’t attempted that here.
Public Sub CreateWorkPlane() Dim asmDoc As AssemblyDocument Set asmDoc = ThisApplication.ActiveDocument Dim asmDef As AssemblyComponentDefinition Set asmDef = asmDoc.ComponentDefinition ' Have a planar face selected. Dim selFace As Face Set selFace = ThisApplication.CommandManager.Pick(kPartFacePlanarFilter, "Select planar face") ' Get the underlying plane geometry from the face. Dim facePlane As Plane Set facePlane = selFace.Geometry Dim tg As TransientGeometry Set tg = ThisApplication.TransientGeometry ' Find the longest linear edge on the face and use it as the X axis. Dim testEdge As Edge Dim longDir As UnitVector Dim longLength As Double longLength = 0 For Each testEdge In selFace.Edges If testEdge.GeometryType = kLineSegmentCurve Then Dim lengthVec As Vector Set lengthVec = testEdge.StartVertex.Point.VectorTo(testEdge.StopVertex.Point) If lengthVec.length > longLength Then longLength = lengthVec.length Set longDir = lengthVec.AsUnitVector End If End If Next Dim xVec As UnitVector Dim yVec As UnitVector Dim pi As Double pi = Atn(1) * 4 If Not longDir Is Nothing Then ' Use the longest edge as the x direction for the work plane. Set xVec = longDir Set yVec = facePlane.Normal.CrossProduct(xVec) Else ' No linear edges was found so calculate another axis to use as the x axis. ' Use the model x, y, or z axis depending on which one is closest to 90 deg from the normal. Dim angleDiff As Double Dim testVec As UnitVector Set testVec = tg.CreateUnitVector(1, 0, 0) angleDiff = Abs((pi / 2) - facePlane.Normal.AngleTo(testVec)) Set xVec = testVec Set testVec = tg.CreateUnitVector(0, 1, 0) If Abs((pi / 2) - facePlane.Normal.AngleTo(testVec)) < angleDiff Then angleDiff = Abs((pi / 2) - facePlane.Normal.AngleTo(testVec)) Set xVec = testVec End If Set testVec = tg.CreateUnitVector(0, 0, 1) If Abs((pi / 2) - facePlane.Normal.AngleTo(testVec)) < angleDiff Then angleDiff = Abs((pi / 2) - facePlane.Normal.AngleTo(testVec)) Set xVec = testVec End If Set yVec = facePlane.Normal.CrossProduct(xVec) Set xVec = yVec.CrossProduct(facePlane.Normal) End If ' Create the "fixed" work plane. Dim wp As WorkPlane Set wp = asmDef.WorkPlanes.AddFixed(facePlane.RootPoint, xVec, yVec) ' Create a flush constraint between the face and the workplane with an offset of 0. Dim flush As FlushConstraint Set flush = asmDef.Constrain
ts.AddFlushConstraint(selFace, wp, 0, facePlane.RootPoint, facePlane.RootPoint)End Sub
-Brian

Leave a Reply