Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Loft feature failed in API but works in UI

2 REPLIES 2
SOLVED
Reply
Message 1 of 3
pcajp96
334 Views, 2 Replies

Loft feature failed in API but works in UI

Hi everyone,

I am relatively new to Fusion API and am trying to use it to create a model of a propeller. The code I wrote creates a series of cross sections at several radial points of the blade. I would like to have my code loft those features together to create the whole model of the blade. When using loftFeature in code it produces an error but if I then go into the UI and edit the loft feature it created it will produce the model no problem. The part that is troubling me is at the end of the run function. Is there a way to get past this error?

 

Thanks in advance!

Peter

 

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

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        #define geometry
        PropOD = 17.78 # outer diameter of the whole propeller
        numSections = 20 # number of airfoil cross sections defined per blade
        heightVal = PropOD*.0486 #define the thickness of the hub as a percent of the Propeller diameter
        
        #roR = radius of cross section/propeller radius
        #coD = chord/propeller diameter
        #t0oc = max thickness/chord
        #f0oc = max camber/chord                
        roR =  [0.0675, 0.1407, 0.2134, 0.2852, 0.3557, 0.4243, 0.4908, 0.5547, 0.6156, 0.6731, 0.7269, 0.7766, 0.8219, 0.8626, 0.8984, 0.929, 0.9544, 0.9742, 0.9885, 0.9971, 1.0] 
        coD =  [0.0409, 0.0622, 0.0846, 0.1019, 0.1116, 0.1151, 0.1138, 0.1088, 0.1015, 0.0927, 0.0834, 0.0745, 0.0662, 0.058, 0.0518, 0.0486, 0.0416, 0.0315, 0.0208, 0.0102, 0.001] 
        t0oc =  [0.1157, 0.081, 0.0719, 0.0711, 0.071, 0.071, 0.0713, 0.0714, 0.0716, 0.0715, 0.0708, 0.0705, 0.0704, 0.0715, 0.0718, 0.0702, 0.072, 0.064, 0.0465, 0.0244, -0.0] 
        f0oc =  [0.3638, 0.2974, 0.1941, 0.1415, 0.1137, 0.098, 0.0888, 0.0838, 0.0817, 0.0815, 0.0825, 0.0838, 0.085, 0.0861, 0.0826, 0.077, 0.0737, 0.0716, 0.0704, 0.0697, 0.0695] 
        pitch =  [37.8052, 36.0376, 28.5569, 23.1935, 19.4709, 16.8137, 14.8683, 13.4188, 12.3222, 11.485, 10.836, 10.3208, 9.9027, 9.5636, 9.1906, 8.8226, 8.5587, 8.3667, 8.2378, 8.1642, 8.1403]
        #----------------------------------------------------------------------
        
        design = app.activeProduct # what's open at the time

        # Get the root component of the active design.
        rootComp = design.rootComponent 

        #create planes
        planes = rootComp.constructionPlanes
        planeInput = planes.createInput()
        
        R = PropOD/2 #propeller radius
        attackAngleList = pitch
        offsetVals = [] #create a list of values for the offset planes
        for i in range(0,numSections):
            offsetVal = adsk.core.ValueInput.createByReal(roR[i]*R)
            offsetVals.append(offsetVal)
            
        xSec0 = .4632*heightVal #define the radius of the initial cross section
        chordScale = [] #creat list of chord scaling
        attackAngleList_rad = [] #create list of attack angles in radians
        
        for i in range(0,len(roR)):
            attackAngleList_rad.append(attackAngleList[i]*math.pi/180) # make the angles into radians
            chordScale.append(coD[i]*PropOD)
       
        # Create a new sketch on the xy plane.
        sketches = rootComp.sketches #sketches comes from the object model(that big tree)
        xyPlane = rootComp.xYConstructionPlane # tell it to use xy plane
        sketch = sketches.add(xyPlane) #take sketches object and add it to the xy plane
        
        # add cross section 0 in here (the xy plane) the radius should be adjusted to reflect the height value
        circles = sketch.sketchCurves.sketchCircles
        circle1 = circles.addByCenterRadius(adsk.core.Point3D.create(0, 0, 0), xSec0)

        #get sketch profile
        profile = sketch.profiles.item(0)
        
        # Create loft feature input
        loftFeats = rootComp.features.loftFeatures
        loftInput = loftFeats.createInput(adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
        loftSectionsObj = loftInput.loftSections
        loftSectionsObj.add(profile)
        
        #create the second profile
        planeInput.setByOffset(xyPlane, offsetVals[0])
        Plane_1 = planes.add(planeInput)        
        sketches = rootComp.sketches #sketches comes from the object model(that big tree)
        sketch_2 = sketches.add(Plane_1) #take sketches object and add it to the PLane_1          
        circles = sketch.sketchCurves.sketchCircles
        circle2 = circles.addByCenterRadius(adsk.core.Point3D.create(0, 0, 0), xSec0)
        profile = sketch.profiles.item(0)
        loftSectionsObj.add(profile)

        for i in range(2,numSections): #create the cross sections for each point of the radius, starting from the 3rd radial point becasue the first two cross section wer too thin and had too much camber
            profile = crossSectionCreator(attackAngleList_rad[i],chordScale[i],PropOD,numSections,offsetVals[i],f0oc[i],t0oc[i])
            loftSectionsObj.add(profile)
            
        loftInput.isSolid = True        
        blade = loftFeats.add(loftInput)        
        
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


def crossSectionCreator(attackAngle,chord,PropOD,numSections,offset,f0oc,t0oc):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        design = app.activeProduct #what's open at the time
                
        # Get the root component of the active design.
        rootComp = design.rootComponent #sets up the top level component of the design in fusion
        xyPlane = rootComp.xYConstructionPlane # tell it to use xy plane
        
        #create 16 planes from 0 to R
        planes = rootComp.constructionPlanes
        planeInput = planes.createInput()
        
        planeInput.setByOffset(xyPlane, offset)
        Plane_1 = planes.add(planeInput)        
        
        # Create a new sketch on the work plane 1.
        sketches = rootComp.sketches #sketches comes from the object model(that big tree)
        sketch_1 = sketches.add(Plane_1) #take sketches object and add it to the PLane_1          
        
        pointsList_1 = [] #a list of all the points for the first cross section
        points_1 = adsk.core.ObjectCollection.create() #create the point collection for the first cross section
        xCoorList = [] #create a list of all x coordinates
        xCoordList = [0,.005,.0075,.0125,.025,.05,.075,.10,.15,.20,.25,.30,.35,.40,.45,.50,.55,.60,.65,.70,.75,.80,.85,.90,.95,1]
        yCoorList = []
        #toc is the thickness/chord at each x value
        toc = [0,.00765,.00928,.01183,.01623,.02182,.0265,.0304,.03658,.04127,.04483,.04742,.04912,.04995,.04983,.04863,.04632,.04304,.03899,.03432,.02912,.02352,.01771,.01188,.00604,.00021]
        t0oc_scale = t0oc/max(toc)
        toc = [i * t0oc_scale for i in toc]
        pointsList = [] # create an empty list to keep track of the points to plot the airfoil
        xyCoordList = [0,0]
        for i in range(0,len(xCoordList)-1): #run thru the list backwards to create negative y coor
            xCoord = xCoordList[len(xCoordList)-1-i]
            yCoord = (-(toc[len(toc)-1-i])/2)
            xyCoordList[0] = xCoord
            xyCoordList[1] = yCoord
            pointsList.append(xyCoordList[:])
        
        xyCoordList = [0,0]
        pointsList.append(xyCoordList[:])
        for i in range(1,len(xCoordList)):#run thru the list forward to create positive y coor
            xCoord = xCoordList[i]
            yCoord = ((toc[i])/2)
            xyCoordList[0] = xCoord
            xyCoordList[1] = yCoord
            pointsList.append(xyCoordList[:])
            
        #add camber
        fof0 = [0,0.0422424851726010,0.0593926061968285,0.0906323084802032,0.158483525134397,0.270931306877788,0.365394143890664,0.447811008675706,0.586552890627142,0.698817437077800,0.789957166562438,0.862944523603016,0.919556283803553,0.960850115191575,0.987381517219326,0.999299100103072,0.996365017088989,0.977907976432830,0.942682218138460,0.888536838448501,0.811548821711142,0.702243798510330,0.542003516481535,0.358366674805168,0.171113059574976,4.65743561188795e-11]
        yCoorMeanCamberLine = [] #this is f
        #dfof0dxoc is dimensionless slope of the mean camber line
        dfof0dxoc = [8.86648212455747,7.14348529861109,6.61217039234403,5.94005607895737,5.01947707446513,4.07954342980629,3.51284803126115,3.09821832429069,2.48609887456089,2.02135629339510,1.63380592532664,1.29146814418333,0.976460919354681,0.677114163075186,0.384630792942005,0.0912942925837331,-0.210851915769909,-0.531483751613063,-0.884477130569965,-1.29366100928359,-1.81194534231248,-2.70919436130699,-3.52064353360441,-3.76526230389796,-3.66538904077040,-3.00042531135620]        
        
        for i in range(0,len(fof0)): #loop for upper values
            yCoorMeanCamberLine.append(fof0[i]*f0oc)
            theta = math.atan(dfof0dxoc[i]*f0oc)
            yCoord = yCoorMeanCamberLine[i]+(toc[i]/2)*math.cos(theta)
            xCoord = pointsList[len(pointsList)-len(fof0)+i][0]-(toc[i]/2)*math.sin(theta)
            xyCoordList = [xCoord,yCoord]
            pointsList[len(pointsList)-len(fof0)+i] = (xyCoordList[:])
            
        for i in range(0,len(fof0)):#loop for lower values
            theta = math.atan(dfof0dxoc[len(dfof0dxoc)-1-i]*f0oc)
            yCoord = yCoorMeanCamberLine[len(yCoorMeanCamberLine)-1-i]-(toc[len(toc)-1-i]/2)*math.cos(theta)
            xCoord = pointsList[i][0]+(toc[len(toc)-1-i]/2)*math.sin(theta)
            xyCoordList = [xCoord,yCoord]
            pointsList[i] = xyCoordList[:]

        for i in range(0,len(pointsList)): #this loop will step through and manipulate each point
            #get the x and y point as a decimal
            xcoord = float(pointsList[i][0])
            ycoord = float(pointsList[i][1])
            
            if xcoord == 0 or ycoord == 0:#leave the point at 0,0 alone
                xcoord = xcoord
                ycoord = ycoord
            else:
                #scale the chord length of the cross section
                xcoord = xcoord*chord
                ycoord = ycoord*chord          
                #change the attack angle of the cross section
                s = (xcoord**2+ycoord**2)**(1/2) #length from origin to the point
                theta = attackAngle-math.atan(ycoord/xcoord)
                xcoord = s*math.cos(theta)
                ycoord = -s*math.sin(theta)
               
            # make a list of the x and y coordinates
            xCoorList.append(xcoord)
            yCoorList.append(ycoord)
            #save the coordinate in the list
            xy_1 = [xcoord,ycoord]
            pointsList_1.append(xy_1)
            
        for i in range(0,len(pointsList_1)): #move the the cross section to the middle now that its been scaled and twisted
            xcoord = float(pointsList_1[i][0])
            ycoord = float(pointsList_1[i][1])
            
            xcoord = xcoord-max(xCoorList)/2
            ycoord = ycoord-min(yCoorList)/2
            
            xy_1 = [xcoord,ycoord]
            pointsList_1[i] = xy_1
            
            points_1.add(adsk.core.Point3D.create(xcoord, ycoord, 0)) #add the new point to the collection
            
        lines = sketch_1.sketchCurves.sketchLines;
        # connect the end of the spline to complete the sketch
        lines.addByTwoPoints(adsk.core.Point3D.create(pointsList_1[0][0], pointsList_1[0][1], 0), adsk.core.Point3D.create(pointsList_1[i][0], pointsList_1[i][1], 0))
        sketch_1.sketchCurves.sketchFittedSplines.add(points_1) # create a spline curve connecting the points

        profile = sketch_1.profiles.item(0) #creates the profile to be lofted
        return profile # allow to profile to be accessed outside this function
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
2 REPLIES 2
Message 2 of 3
burzins
in reply to: pcajp96

Hi Peter,

 

Just changing sketch_2 to sketch under #create the second profile will allow the loft to be created.

 

Steve

Message 3 of 3
pcajp96
in reply to: burzins

That worked! Thank you so much!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report