Create 3d spline that is tangent to edge of brep surface

thomasL7NS5
Explorer

Create 3d spline that is tangent to edge of brep surface

thomasL7NS5
Explorer
Explorer

I am trying to create a script through python API that allows a user to select the bottom left vertex of "body 1" then the bottom right vertex of "body 2". The script will then generate a 3d spline between these vertices. The script should then add a tangent relationship between the edge adjacent to the bottom right vertex of "body 2" as seen in the screenshot attached. Creating this tangent relationship is causing difficulties. If anyone has some tips about how to achieve this that would be great. Thanks in advance. 

 

#Author-
#Description-

import adsk.core, adsk.fusion, adsk.cam, traceback

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        root = design.rootComponent

#####################################Create the 3d spline sketch#####################################
        #use select bottom left vertex of right body
        VertexSel1 = ui.selectEntity('Select bottom left vertex of right body', 'Vertices ')
        if VertexSel1:
            vertex1 = VertexSel1.entity
        BNMR1coord = vertex1.geometry

        #User select bottom right vertex of left body
        VertexSel5 = ui.selectEntity('Select bottom right vertex of left body', 'Vertices ')
        if VertexSel5:
            vertex5 = VertexSel5.entity
        BNMR5coord = vertex5.geometry

        #Initialize the active sketch for BNMR 
        sketches = root.sketches
        sketchBNMR = sketches.add(root.xYConstructionPlane)
        sketchBNMR.name = 'Bottom Sketch'

        #create needed variables
        BNMRheight = BNMR5coord.y - BNMR1coord.y
        BNMRdepth = BNMR5coord.z - BNMR1coord.z
        BNMRwidth = BNMR5coord.x - BNMR1coord.x

        #Find all of the z values of the middle coordinates
        BNMR2_z = BNMR1coord.z + 0.23*BNMRdepth
        BNMR3_z = BNMR1coord.z + 0.57*BNMRdepth
        BNMR4_z = BNMR1coord.z + 0.82*BNMRdepth

        #find all of the x values of the middle coordinates
        BNMR2_x = BNMR5coord.x - 0.69*BNMRwidth
        BNMR3_x = BNMR5coord.x - 0.45*BNMRwidth
        BNMR4_x = BNMR5coord.x - 0.21*BNMRwidth

        #find all of the y values of the middle coordinates
        BNMR2_y = BNMR1coord.y + 0.28*BNMRheight
        BNMR3_y = BNMR1coord.y + 0.75*BNMRheight
        BNMR4_y = BNMR1coord.y + 0.92*BNMRheight

        #List the points that will be used to create the spline
        BNMR1 = adsk.core.Point3D.create(BNMR1coord.x, BNMR1coord.y, BNMR1coord.z)
        BNMR2 = adsk.core.Point3D.create(BNMR2_x, BNMR2_y, BNMR2_z)
        BNMR3 = adsk.core.Point3D.create(BNMR3_x, BNMR3_y, BNMR3_z)
        BNMR4 = adsk.core.Point3D.create(BNMR4_x, BNMR4_y, BNMR4_z)
        BNMR5 = adsk.core.Point3D.create(BNMR5coord.x, BNMR5coord.y, BNMR5coord.z)

        #Define a datastruct of points for the spline
        BNMRSketchPoints = adsk.core.ObjectCollection.create()
        BNMRSketchPoints.add(BNMR1)
        BNMRSketchPoints.add(BNMR2)
        BNMRSketchPoints.add(BNMR3)
        BNMRSketchPoints.add(BNMR4)
        BNMRSketchPoints.add(BNMR5)
    
        #sketch the splines
        spline1 = sketchBNMR.sketchCurves.sketchFittedSplines.add(BNMRSketchPoints)
        
        #Add a tangent relationship to the spline at vertex 5 and horizontal at vertex 1
        face1 = vertex1.faces.item(0) #Get the face attached to the vertex for the forehead
        edge1 = face1.edges.item(0) #get the edge
        tanline1 = spline1.activateTangentHandle(spline1.startSketchPoint) #use to make tanline horizontal
        sketchBNMR.geometricConstraints.addHorizontal(tanline1) #use to make tanline vertical or horizontal
        
        tangent_constraint1 = sketchBNMR.geometricConstraints.addTangent(spline1, edge1)


    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

 

0 Likes
Reply
Accepted solutions (1)
764 Views
6 Replies
Replies (6)

MichaelT_123
Advisor
Advisor

Hi Mr ThomasL7NS5,

 

The first issue... from docs:

returnValue = geometricConstraints_var.addTangent(curveOne, curveTwo)

The second issue ... as per your f3d and png files.

What is 3D curve tangent to 3D surface? At a given (non-singular) point on Riemann's surface, an infinite number of straight lines pass through it ( and even greater curvy ones).

So, you have to decide the plane where the tangential relation of two curves is established. Like in the real life, the tangent plane relationship will be defined naturally … in the case of 3D rigid surfaces.

Judging by the code you presented, it should not be a significant hurdle for you; an edge projection might help.

 

The third issue ... regarding the API documentation of the function.

Would it be helpful to clarify that the (curveOne, curveTwo) arguments should be of 2D kind or a least have coplanar with sketch plane tangent vectors at a tangent point?

 

Regards

MichaelT 

MichaelT
1 Like

thomasL7NS5
Explorer
Explorer

Hi @MichaelT_123,

 

Thank you for the reply!

 

A projection of the edge does work well when the spline is on the same plane, for example with all of the same z-coordinates. However, through the UI I am able to apply a tangent relationship of the 3d spline sketch. Please see the attached video that will hopefully clarify what I am trying to achieve through the API. If the .addTagnent(curveone, curve2) is constrained to 2d, this may not be possible? 

0 Likes

BrianEkins
Mentor
Mentor
Accepted solution

I don't believe it matters if the curve lie on the X-Y plane of the sketch or not. Here's a version of your program that finds the edges of the faces that the selected vertices are connected to. It then does some logic to determine which of the two edges to use and then includes that edge into the sketch. Now it can create a tangent constraint between the included sketch curve and the spline. The code that determines the edge can probably be cleaner, but this does seem to work.

BrianEkins_1-1690566216292.png

 

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        root = design.rootComponent

#####################################Create the 3d spline sketch#####################################
        #use select bottom left vertex of right body
        VertexSel1 = ui.selectEntity('Select bottom left vertex of right body', 'Vertices ')
        if VertexSel1:
            vertex1: adsk.fusion.BRepVertex = VertexSel1.entity
        BNMR1coord = vertex1.geometry

        #User select bottom right vertex of left body
        VertexSel5 = ui.selectEntity('Select bottom right vertex of left body', 'Vertices ')
        if VertexSel5:
            vertex5: adsk.fusion.BRepVertex = VertexSel5.entity
        BNMR5coord = vertex5.geometry

        #Initialize the active sketch for BNMR 
        sketches = root.sketches
        sketchBNMR = sketches.add(root.xYConstructionPlane)
        sketchBNMR.name = 'Bottom Sketch'

        #create needed variables
        BNMRheight = BNMR5coord.y - BNMR1coord.y
        BNMRdepth = BNMR5coord.z - BNMR1coord.z
        BNMRwidth = BNMR5coord.x - BNMR1coord.x

        #Find all of the z values of the middle coordinates
        BNMR2_z = BNMR1coord.z + 0.23*BNMRdepth
        BNMR3_z = BNMR1coord.z + 0.57*BNMRdepth
        BNMR4_z = BNMR1coord.z + 0.82*BNMRdepth

        #find all of the x values of the middle coordinates
        BNMR2_x = BNMR5coord.x - 0.69*BNMRwidth
        BNMR3_x = BNMR5coord.x - 0.45*BNMRwidth
        BNMR4_x = BNMR5coord.x - 0.21*BNMRwidth

        #find all of the y values of the middle coordinates
        BNMR2_y = BNMR1coord.y + 0.28*BNMRheight
        BNMR3_y = BNMR1coord.y + 0.75*BNMRheight
        BNMR4_y = BNMR1coord.y + 0.92*BNMRheight

        #List the points that will be used to create the spline
        BNMR1 = adsk.core.Point3D.create(BNMR1coord.x, BNMR1coord.y, BNMR1coord.z)
        BNMR2 = adsk.core.Point3D.create(BNMR2_x, BNMR2_y, BNMR2_z)
        BNMR3 = adsk.core.Point3D.create(BNMR3_x, BNMR3_y, BNMR3_z)
        BNMR4 = adsk.core.Point3D.create(BNMR4_x, BNMR4_y, BNMR4_z)
        BNMR5 = adsk.core.Point3D.create(BNMR5coord.x, BNMR5coord.y, BNMR5coord.z)

        #Define a datastruct of points for the spline
        BNMRSketchPoints = adsk.core.ObjectCollection.create()
        BNMRSketchPoints.add(BNMR1)
        BNMRSketchPoints.add(BNMR2)
        BNMRSketchPoints.add(BNMR3)
        BNMRSketchPoints.add(BNMR4)
        BNMRSketchPoints.add(BNMR5)
    
        #sketch the splines
        spline1 = sketchBNMR.sketchCurves.sketchFittedSplines.add(BNMRSketchPoints)

        # Find the edge connected to vertex one that is somewhat in the X direction.
        vert1Edge1 = vertex1.edges[0]
        vert1Edge2 = vertex1.edges[1]
        edge1Dir = vert1Edge1.startVertex.geometry.vectorTo(vert1Edge1.endVertex.geometry)
        edge2Dir = vert1Edge2.startVertex.geometry.vectorTo(vert1Edge2.endVertex.geometry)
        xVec = adsk.core.Vector3D.create(1,0,0)
       
        angle1 = edge1Dir.angleTo(xVec)
        if angle1 > math.pi / 2:
            angle1 = math.pi - angle1
        angle2 = edge2Dir.angleTo(xVec)
        if angle2 > math.pi / 2:
            angle2 = math.pi - angle2
        if angle1 < angle2:
            edge1 = vert1Edge1
        else:
            edge1 = vert1Edge2

        # Find the edge connected to vertex tow that is somewhat in the X direction.
        vert2Edge1 = vertex5.edges[0]
        vert2Edge2 = vertex5.edges[1]
        edge1Dir = vert2Edge1.startVertex.geometry.vectorTo(vert2Edge1.endVertex.geometry)
        edge2Dir = vert2Edge2.startVertex.geometry.vectorTo(vert2Edge2.endVertex.geometry)
       
        angle1 = edge1Dir.angleTo(xVec)
        if angle1 > math.pi / 2:
            angle1 = math.pi - angle1
        angle2 = edge2Dir.angleTo(xVec)
        if angle2 > math.pi / 2:
            angle2 = math.pi - angle2
        if angle1 < angle2:
            edge2 = vert2Edge1
        else:
            edge2 = vert2Edge2

        curve1 = sketchBNMR.include(edge1).item(0)
        curve2 = sketchBNMR.include(edge2).item(0)

        sketchBNMR.geometricConstraints.addTangent(curve1, spline1)
        sketchBNMR.geometricConstraints.addTangent(curve2, spline1)
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

  

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
0 Likes

thomasL7NS5
Explorer
Explorer

Hi @BrianEkins,

 

That did seem to do the trick. Thanks for the insight!

 

Thomas

0 Likes

Jorge_Jaramillo
Collaborator
Collaborator

@Jorge_Jaramillo - this post is being edited to remove PII.

 

Hi @thomasL7NS5 ,

 

I didn't have the time to finish it sooner, but below is what I did to try to solve your problem.

 

I choose to select the edges instead of the vertices, then selecting the pair of vertices that are nearest to each other, also an optimization to the spline points calculation, and finally constraining the spline with the previously selected edges (based on @BrianEkins implementation).

 

 

 

def spline_tangent_to_two_edges():
    try:
        app = adsk.core.Application.get()
        root = des.rootComponent
        ui = app.userInterface

#####################################Create the 3d spline sketch#####################################
        # use select first edge
        selection = ui.selectEntity('Select first edge ...', 'Edges')
        if selection:
            edge1: adsk.fusion.BRepEdge = selection.entity
        # User select second edge
        selection = ui.selectEntity('Select second edge ...', 'Edges')
        if selection:
            edge2: adsk.fusion.BRepEdge = selection.entity
        # select neartest vertices between edges
        (vertex1, vertex5) = sorted([(i,j) for i in [edge1.startVertex, edge1.endVertex]
                                           for j in [edge2.startVertex, edge2.endVertex]],
                                     key=lambda p: p[0].geometry.distanceTo(p[1].geometry))[0]

        spline_factors = [(0.00, 0.00, 0.00),
                          (0.31, 0.28, 0.23),
                          (0.55, 0.75, 0.57),
                          (0.79, 0.92, 0.82),
                          (1.00, 1.00, 1.00)]
        spline_points = [ adsk.core.Point3D.create(
                            vertex1.geometry.x * (1 - kx) + kx * vertex5.geometry.x,
                            vertex1.geometry.y * (1 - ky) + ky * vertex5.geometry.y,
                            vertex1.geometry.z * (1 - kz) + kz * vertex5.geometry.z,
                          ) for (kx, ky, kz) in spline_factors]

        #Initialize the active sketch for BNMR 
        sketches = root.sketches
        sketchBNMR = sketches.add(root.xYConstructionPlane)
        sketchBNMR.name = 'Bottom Sketch'
        spline1 = sketchBNMR.sketchCurves.sketchFittedSplines.add(adsk.core.ObjectCollection.createWithArray(spline_points))

        curve1 = sketchBNMR.include(edge1).item(0)
        curve2 = sketchBNMR.include(edge2).item(0)

        sketchBNMR.geometricConstraints.addTangent(curve1, spline1)
        sketchBNMR.geometricConstraints.addTangent(curve2, spline1)
    except:
        app.log('Failed:\n{}'.format(traceback.format_exc()))

 

 

 

I hope it could help you.

 

Regards,

Jorge Jaramillo

 

0 Likes

MichaelT_123
Advisor
Advisor

 Hi Mr BrianEkins,

 

### I don't believe it matters if the curve lie on the X-Y plane of the sketch or not ###

 

If I can trust my memory (while its level is steadily declining), I recall some problems with applying tangent constraints in F360 via straight API.

 

The API "tangencing" always has been like swimming in murky water full of sharks. I wonder how many drafters have lost their virtual limbs? I personally have lost quite a few … they have since regrown😏.

 

I am pleased that the 'only 2D constraints' limitation has been somehow tempered, perhaps with the recent addition of the new sketch's curves functionality – blend. The script you presented shows that it is now possible to establish tangential relations between spline ends, even if they are of a 3D kind.

However, such functionality can't be applied to the spline interiors (or their inside fit points).

Well,… at least I was not able to do this in the simple UI-driven experiment. Besides splines, F360 offers other curve types: circles (3D), ellipses, conics,….

 

How about them?

Has the murky water been filtered, and sharks underwent dental procedures?  ... for them.

 

If not, the third issue I raised in my previous post still stands. It would be beneficial to clarify a very brief and, in my opinion… too optimistic description of the addTangent() function.

 

Regards

MichaelT

MichaelT
0 Likes