How Can I Extrude a Cut from one part into another in an Assembly

How Can I Extrude a Cut from one part into another in an Assembly

CalvinDay
Enthusiast Enthusiast
810 Views
4 Replies
Message 1 of 5

How Can I Extrude a Cut from one part into another in an Assembly

CalvinDay
Enthusiast
Enthusiast

I have a vessel assembly with several nozzles. Using the API, I need to punch (cut-extrude) nozzle holes into vessel. I am unable to copy an existing circle from part (nozzle) onto the other part (vessel) .

CalvinDay_0-1664203926498.png

 

0 Likes
811 Views
4 Replies
Replies (4)
Message 2 of 5

WCrihfield
Mentor
Mentor

Hi @CalvinDay.  This is a fairly complex situation to write code for.  Do you intend to permanently change 'other' part document by adding the cut/extrude feature to that other part document, or do you intend for the feature to only exist within the main assembly?

 

I had an example assembly to test on, where a top part had a hole through it, top to bottom, and I wanted to extend that hole down through the bottom part that it was constrained to.  I wrote an iLogic rule to do that.  To make it easier for me, I edited both part documents by assigning names to geometry I was going to be working with.  I named the bottom edge of the hole in the top part "Bottom Hole Edge", and named the top face of the bottom part "Top Face".  This makes it much easier for me to find/get them by code.  And since I knew the exact names of the components I wanted to work with, I specified them by their names directly, instead of using Pick command or something else.  In the code, I dug down to the PartDocument object that each component represents, then used the NamedEntities interface to retrieve the named geometry from them.  Then accessed the proxy version of those geometries, which exists in the context of the main assembly's model space.  Then I entered into Edit Mode of the destination component, so that further edits would effect it.  Then I created a new PlanarSketch within the destination part, on the destination parts actual face.  Then I accessed that sketch's Proxy within the assembly, and used that to project the proxy source geometry to this proxy sketch.  That also creates the 'real' geometry within the 'real' sketch in the part, because I am in Edit Mode of the component.  Then, due to application options settings, where projected geometry is 'contruction' by default, I looped through the sketches geometry and changed all construction geometry to regular geometry, so that it can be used for an extrusion profile.  Then I generated the Profile object that the extrusion feature needs.  Then I created the extrusion definition, set its extent data, and created the extrude feature.  Then I update the destination part, exit Edit Mode of the component, and update the main assembly.

Here is the code I used in this example.  Hopefully this will help you reach your goal too.

Sub Main
	If ThisDoc.Document.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
		MsgBox("An Assembly Document must be active for this rule to work. Exiting.", vbCritical, "")
		Exit Sub
	End If
	Dim oADoc As AssemblyDocument = ThisDoc.Document
	Dim oADef As AssemblyComponentDefinition = oADoc.ComponentDefinition
	Dim oOccs As ComponentOccurrences = oADef.Occurrences
	Dim oAuto As IiLogicAutomation = iLogicVb.Automation
	
	'get source geometry (the named bottom edge of a round hole, in this example)
	Dim oSourceOcc As ComponentOccurrence = oOccs.ItemByName("Part1:1")
	Dim oSourceDef As PartComponentDefinition = oSourceOcc.Definition
	Dim oSourcePDoc As PartDocument = oSourceDef.Document
	Dim oSourceNEs As NamedEntities = oAuto.GetNamedEntities(oSourcePDoc)
	Dim oSourceCircleEdge As Edge = oSourceNEs.TryGetEntity("Bottom Hole Edge")
	If IsNothing(oSourceCircleEdge) Then
		MsgBox("Could not find named circle edge in source part.", vbCritical, "")
		Exit Sub
	End If
	Dim oSourceCircleEdgeProxy As EdgeProxy = Nothing
	'this sets a value to the oSourceCircleEdgeProxy variable (gets geometry in context of main assembly)
	oSourceOcc.CreateGeometryProxy(oSourceCircleEdge, oSourceCircleEdgeProxy)
	
	'get destination Face to transfer source geometry to (named Top Face of other part in this example)
	Dim oDestinationOcc As ComponentOccurrence = oOccs.ItemByName("TestPart1:1")
	Dim oDestinationDef As PartComponentDefinition = oDestinationOcc.Definition
	Dim oDestinationPDoc As PartDocument = oDestinationDef.Document
	Dim oDestinationNEs As NamedEntities = oAuto.GetNamedEntities(oDestinationPDoc)
	Dim oDestinationFace As Face = oDestinationNEs.TryGetEntity("Top Face")
	If IsNothing(oDestinationFace) Then
		MsgBox("Could not find named circle edge in source part.", vbCritical, "")
		Exit Sub
	End If
	Dim oDestinationFaceProxy As FaceProxy = Nothing
	'this sets a value to the oSourceCircleEdgeProxy variable (gets geometry in main assembly)
	oDestinationOcc.CreateGeometryProxy(oDestinationFace, oDestinationFaceProxy)
	'now transfer source geometry to destination face
	oDestinationOcc.Edit
	'create a sketch within the Part, on the destination face
	Dim oSketch As PlanarSketch = oDestinationDef.Sketches.Add(oDestinationFace, False)
	'get this sketch in the context of the main assembly
	Dim oSketchProxy As PlanarSketchProxy = Nothing
	oDestinationOcc.CreateGeometryProxy(oSketch, oSketchProxy)
	'now transfer the proxy edge geometry to the proxy sketch
	oSketchProxy.AddByProjectingEntity(oSourceCircleEdgeProxy)
	'need to make geometry non-construction, so it can be used for an Extrusion Feature
	For Each oSE As SketchEntity In oSketch.SketchEntities
		If oSE.Construction Then oSE.Construction = False
	Next
	Dim oProfile As Profile = oSketch.Profiles.AddForSolid()
	Dim oExtFeats As ExtrudeFeatures = oDestinationDef.Features.ExtrudeFeatures
	Dim oExtDef As ExtrudeDefinition = oExtFeats.CreateExtrudeDefinition(oProfile, PartFeatureOperationEnum.kCutOperation)
	oExtDef.SetThroughAllExtent(PartFeatureExtentDirectionEnum.kNegativeExtentDirection)
	Dim oExtFeat As ExtrudeFeature = oExtFeats.Add(oExtDef)
	If oDestinationPDoc.RequiresUpdate Then oDestinationPDoc.Update
	oDestinationOcc.ExitEdit(ExitTypeEnum.kExitToTop)
	If oADoc.RequiresUpdate Then oADoc.Update
End Sub

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 3 of 5

EngrSolutions
Participant
Participant

@WCrihfield One issue is that you cannot create a PlanarSketch on cylindrical face. If oDestinationFace is cylindrical, then the code will not work (at least I haven't found a way to do this manually or through the API...)

 

I altered your code so that it will create a sketch on the "Bottom Plane" of the nozzle in context with the cylinder. Not only will you need to name the edge of the nozzle ("Nozzle_OD" in my case), but you will need to make sure that "Bottom Plane" exists in the nozzle. Obviously you can alter "Bottom Plane" to fit the situation.

public static void DrillHole(AssemblyDocument oAssembly, ComponentOccurrence oOcc)
{
// oOcc is a nozzle being passed into this method
    try
    {
        AssemblyComponentDefinition oAssemblyCompDef = oAssembly.ComponentDefinition;
        Document oOccDoc = (Document)oOcc.Definition.Document;
        PartDocument oPartDoc = (PartDocument)oOcc.Definition.Document;

        foreach (ComponentOccurrence oOccurrence in oAssemblyCompDef.Occurrences.AllLeafOccurrences)
        {
            if (oOccurrence.Name == oOcc.Name)
            {
                // Create objects to hold Geometry Proxies
                object oEdgeObj;
                object WPProxy;
                object oSketchProx;

                // Get the source Edge from the nozzle
                // This is the profile of the cut that needs to be made in the cylinder
                object oEdge = GetNamedEntity(oOccDoc, "Nozzle_OD");
                // Cast Object to Edge
                Edge SourceEdge = (Edge)oEdge;
                // Create a proxy of the edge
                oOccurrence.CreateGeometryProxy(SourceEdge, out oEdgeObj);
                // Cast Object to EdgeProxy
                EdgeProxy oEdgeProxy = (EdgeProxy)oEdgeObj;

                // Get the ComponentOccurrence in oAssembly that has this ID
                ComponentOccurrence oDrillingOccurrence = GetComponent(oAssembly, 1576357277);
                
                // Check if Component was found
                if (oDrillingOccurrence == null)
                {
                    // If not return
                    return;
                }

                // Get the Definition object of the ComponentOccurrence
                PartComponentDefinition oDrillDef = (PartComponentDefinition)oDrillingOccurrence.Definition;
                // Get the Document object of the ComponentOccurrence
                Document oDrillOccDoc = (Document)oDrillingOccurrence.Definition.Document;

                // Get the Bottom Plane of the nozzle (oOcc)
                // This is the plane where we will start our sketch
                WorkPlane WP = oPartDoc.ComponentDefinition.WorkPlanes["Bottom Plane"];
                // Create a proxy plane
                oOccurrence.CreateGeometryProxy(WP, out WPProxy);
                // Cast object to WorkPlaneProxy
                WorkPlaneProxy WorkPlaneProxy = (WorkPlaneProxy)WPProxy;
                 
                // Edit the ComponentOccurrence that needs to be cut
                oDrillingOccurrence.Edit();
                // Create a new PlanarSketch on the WorkPlaneProxy
                PlanarSketch oSketch = oDrillDef.Sketches.Add(WorkPlaneProxy, false);
                // Create a Proxy for oSketch
                oDrillingOccurrence.CreateGeometryProxy(oSketch, out oSketchProx);
                // Cast object to PlanarSketchProxy
                PlanarSketchProxy oSketchProxy = (PlanarSketchProxy)oSketchProx;
                // Project the oEdgeProxy onto oSketchProxy
                // oEdgeProxy is the edge of the nozzle
                oSketchProxy.AddByProjectingEntity(oEdgeProxy);

                // Loop through every SketchEntity and make sure lines
                // are not construction lines.
                foreach (SketchEntity oSE in oSketch.SketchEntities)
                {
                    if (oSE.Construction)
                    {
                        oSE.Construction = false;
                    }
                }

                // Create a profile of the sketch
                Profile oProfile = oSketch.Profiles.AddForSolid();
                // Get the ExtrudeFeatures of oDrilling Component
                ExtrudeFeatures oExtFeats = oDrillDef.Features.ExtrudeFeatures;
                // Create an Extrusion based on oProfile and with a cutting operation
                ExtrudeDefinition oExtDef = oExtFeats.CreateExtrudeDefinition(oProfile, PartFeatureOperationEnum.kCutOperation);
                // Set the extents to be in the negative direction
                oExtDef.SetThroughAllExtent(PartFeatureExtentDirectionEnum.kNegativeExtentDirection);
                // Add this ExtrusionDefinition to the ExtrudeFeature
                ExtrudeFeature oExtFeat = oExtFeats.Add(oExtDef);
                // Exit from editing component
                oDrillingOccurrence.ExitEdit(ExitTypeEnum.kExitToTop);
            }
        }

    }
    catch (Exception e)
    {
    }

}

 

0 Likes
Message 4 of 5

ryan.rittenhouse
Advocate
Advocate

I recently had to solve almost this exact problem - creating holes in a cylinder based on geometry in other parts. You can do it without creating a plane by using the hole tool. I've cut down the prototype code I wrote so it should be decent proof of concept for you to use. Some of the functions are old and take the long way around, but it should help get you going.

 

Sub Main()
	
	'Get the cylinder component
	Dim stringer As ComponentOccurrence = Component.InventorComponent("Tube")
	
	'Get the "Outside" face - really rough code for GetFaceProxy below
	Dim stringerFace As FaceProxy = GetFaceProxy(stringer, "Outside")
	
	'Get the center axis from the part adjacent to the cylinder - code for GetProxy below
	Dim boltAxis As WorkAxisProxy = GetProxy(comp, comp.Definition.WorkAxes("Mount Axis"))
	Dim boltPlane As WorkPlaneProxy = GetProxy(comp, comp.Definition.WorkPlanes("Mount Plane"))
	
	'Find all the places where the boltAxis
	Dim foundPoints As ObjectsEnumerator = ThisApplication.TransientGeometry.CurveSurfaceIntersection(boltAxis.Line, stringerFace.Geometry)
	
	'Find the point closest to the boltPlane
	Dim closestPoint As Point = Nothing
	For Each oPoint As Point In foundPoints
		
		If closestPoint Is Nothing Then
			closestPoint = oPoint
		Else
			If Measure.MinimumDistance(oPoint, boltPlane) < Measure.MinimumDistance(closestPoint, boltPlane) Then closestPoint = oPoint
		End If				
	Next
	
	'Create Workpoint in stringer component
	Dim holePoint As WorkPoint = CreateWorkPointInComponent(stringer, closestPoint)			
	holePoint.Name = "BoltPoint"
	
	'Create perpendicular work axis
	Dim holeAxis As WorkAxis = stringer.Definition.WorkAxes.AddByNormalToSurface(stringerFace.NativeObject, holePoint)
	holeAxis.Name = "BoltAxis"
	
	Dim holePlacementDef As PointHolePlacementDefinition = stringer.Definition.Features.HoleFeatures.CreatePointPlacementDefinition(holePoint, holeAxis)
	Dim hFeature As HoleFeature = stringer.Definition.Features.HoleFeatures.AddDrilledByThroughAllExtent(holePlacementDef, holeDiameter * 2.54, holeDirection)
	hFeature.Name = "BoltHole"
	
End Sub 'Main

Function CreateWorkPointInComponent(comp As ComponentOccurrence, closestPoint As Point) As WorkPoint
	
	Dim oMatrix As Matrix = comp.Transformation.Copy
	oMatrix.Invert
	Dim oNewPoint As Point = closestPoint.Copy
	oNewPoint.TransformBy(oMatrix)
	Return comp.Definition.WorkPoints.AddFixed(oNewPoint)

End Function

''' <summary>
''' Given component occurrence and face name, returns face proxy if it exists
''' </summary>
''' <param name="comp">Component Occurrence</param>
''' <param name="faceName">Face Name</param>
''' <returns>FaceProxy</returns>
Public Function GetFaceProxy(comp As ComponentOccurrence, faceName As String) As FaceProxy
    
    For Each bod As SurfaceBody In comp.SurfaceBodies
        For Each faceProx As FaceProxy In bod.Faces
            Dim attSets = faceProx.NativeObject.AttributeSets
            If attSets.NameIsUsed("iLogicEntityNameSet") Then
                Dim attSet As AttributeSet = attSets.Item("iLogicEntityNameSet")
                For Each at As Attribute In attSet
                    If at.Name = "iLogicEntityName" Then
                        If at.Value = faceName Then
                            Return faceProx
                        End If
                    End If
                Next at
            End If
        Next faceProx
    Next bod
    
    Return Nothing
    
End Function 'GetFaceProxy

''' <summary>
''' Returns a top level proxy of the given thing in the given component occurrence
''' </summary>
''' <param name="comp">Component Occurrence</param>
''' <param name="thing">Object to create proxy from</param>
''' <returns>Object Proxy</returns>
Function GetProxy(comp As ComponentOccurrence, thing As Object) As Object

    Dim parentComp As ComponentOccurrence = comp.ParentOccurrence
    Dim curProxy As Object
    Dim prevProxy As Object
    
    comp.CreateGeometryProxy(thing, curProxy)
    
    While parentComp IsNot Nothing
        prevProxy = curProxy
        parentComp.CreateGeometryProxy(prevProxy, curProxy)
        parentComp = parentComp.ParentOccurrence
    End While
    
    Return curProxy

End Function 'GetProxy

 

 

If this solved your problem, or answered your question, please click Accept Solution.
Message 5 of 5

EngrSolutions
Participant
Participant

That's great! I hadn't thought about going that route. Thanks for sharing.

0 Likes