Ejemplo n.º 1
0
    def execute(self, context):
        scene = context.scene

        stageProps=EDFLibrary.CalcStageBladeAngles(R=scene.reaction,\
                        phi=scene.flowCoefficient,\
                        psi=scene.stageLoading,\
                        radius=scene.meanLineRadius,
                        rpm = scene.rpm)
        print("")
        print("")
        print("Drawing 2D Rotor/Stator blades")
        print("")
        print("")

        chord = 1
        deltaBeta = (stageProps.beta2 - stageProps.beta1)
        camber = chord / 2 / math.sin(deltaBeta) - chord / 2 / math.tan(
            deltaBeta)
        print("beta " +
              str((stageProps.beta1 + stageProps.beta2) / 2 * 180 / math.pi))
        print("rotorcamber " + str(camber * 100))
        print("deltaBeta " + str(deltaBeta * 180 / math.pi))
        TurboMachLib.NACA4(name='rotor2D',\
                        camber_root=camber*100,\
                        camber_tip=camber*100,\
                        camber_position=35,\
                        thickness=6,\
                        bladeHeight=1,\
                        twistAngle=0,\
                        rootChord=1,\
                        tipChord=1,\
                        centerOfTwist=[0,0],\
                        nspan=1,\
                        npts=24)

        DLUtils.RotateObject(
            'rotor2D',
            mathutils.Euler([0, 0,
                             -(stageProps.beta2 + stageProps.beta1) / 2]))
        deltaAlpha = (stageProps.alpha2 - stageProps.alpha1)
        camber = chord / 2 / math.sin(deltaAlpha) - chord / 2 / math.tan(
            deltaAlpha)
        print("alpha " +
              str((stageProps.alpha1 + stageProps.alpha2) / 2 * 180 / math.pi))
        print("statorcamber " + str(camber * 100))
        print("deltaAlpha " + str(deltaAlpha * 180 / math.pi))
        TurboMachLib.NACA4(name='stator2D',\
                        camber_root=camber*100,\
                        camber_tip=camber*100,\
                        camber_position=35,\
                        thickness=6,\
                        bladeHeight=1,\
                        twistAngle=0,\
                        rootChord=1,\
                        tipChord=1,\
                        centerOfTwist=[0,0],\
                        nspan=1,\
                        npts=15)

        DLUtils.MoveObject('stator2D', mathutils.Vector([1, 0, 0]))
        DLUtils.RotateObject(
            'stator2D',
            mathutils.Euler(
                [0, 0, (stageProps.alpha2 + stageProps.alpha1) / 2]))

        #stageProps.GenerateReport("test.txt")

        return {'FINISHED'}
Ejemplo n.º 2
0
def NACA4Blade(name,camber_root,camber_tip,camber_position,\
        thickness,bladeHeight,twistAngle,rootChord,tipChord,\
        centerOfTwist,nspan,npts):

    #//////////////////////
    #//Inputs:
    #//	camber_max: %chord
    #//	camber_position: location of max camber %chord
    #//	thickness: max thickness of airfoil as %chord
    #//	bladeHeight: height of blade
    #//	twist: degrees/unit height
    #// centerOfTwist: %chord
    #//	nspan: number of span wise subdivisions
    #//	npts: number of pts used to discretise both the upper and lower airfoil profile surface.

    #Twist per unit length
    twist = math.radians(twistAngle) / bladeHeight

    mr = camber_root / 100
    mt = camber_tip / 100
    p = camber_position / 100
    t = thickness / 100
    centerOfTwist[0] = centerOfTwist[0] / 100
    centerOfTwist[1] /= 100

    x = []
    yt = []
    yc = []
    xu = []
    yu = []
    xl = []
    yl = []
    xuTwist = [0] * npts
    yuTwist = [0] * npts
    xlTwist = [0] * npts
    ylTwist = [0] * npts
    verts = []
    faces = []
    origin = (0, 0, 0)

    #Generate vertex coordinates with twist and scale along the span
    dspan = bladeHeight / nspan
    for j in range(0, nspan + 1):

        ### bad use of memory, Fix it.  Does this matter in Python?
        x = []
        yt = []
        yc = []
        xu = []
        xl = []
        yu = []
        yl = []

        m = (1 - j / (nspan)) * mr + j / nspan * mt

        #Generate vertex coordinates for unmodified airfoil shape
        for i in range(0, npts + 1):

            x.append(1 - math.cos(i * (math.pi / 2) / npts))
            yt.append(
                t / 0.2 *
                (0.2969 * math.pow(x[i], 0.5) - 0.126 * x[i] -
                 0.3516 * math.pow(x[i], 2) + 0.2843 * math.pow(x[i], 3) -
                 0.1015 * math.pow(x[i], 4)))
            if (x[i] < p):
                yc.append(m / pow(p, 2) * (2 * p * x[i] - pow(x[i], 2)))
                dycdx = 2 * m / pow(p, 2) * (p - x[i])
            else:
                yc.append(m / pow(1 - p, 2) *
                          (1 - 2 * p + 2 * p * x[i] - pow(x[i], 2)))
                dycdx = 2 * m / pow(1 - p, 2) * (p - x[i])

            #Shift foil to center of twist
            x[i] -= centerOfTwist[0]
            yc[i] -= centerOfTwist[1]

            xu.append(x[i] - yt[i] * (math.sin(math.atan(dycdx))))
            yu.append(yc[i] + yt[i] * (math.cos(math.atan(dycdx))))
            xl.append(x[i] + yt[i] * (math.sin(math.atan(dycdx))))
            yl.append(yc[i] - yt[i] * (math.cos(math.atan(dycdx))))

        #####

        angle = twist * j * dspan
        chord = rootChord - j * dspan * (rootChord - tipChord) / bladeHeight
        for i in range(0, npts):
            xuTwist[i] = xu[i] * math.cos(angle) - yu[i] * math.sin(angle)
            yuTwist[i] = xu[i] * math.sin(angle) + yu[i] * math.cos(angle)

            xuTwist[i] *= chord
            yuTwist[i] *= chord

            verts.append((xuTwist[i], yuTwist[i], j * dspan))
        for i in range(0, npts):
            xlTwist[i] = xl[i] * math.cos(angle) - yl[i] * math.sin(angle)
            ylTwist[i] = xl[i] * math.sin(angle) + yl[i] * math.cos(angle)

            xlTwist[i] *= chord
            ylTwist[i] *= chord

            verts.append((xlTwist[i], ylTwist[i], j * dspan))

    #Generate Polies from vertex IDs
    #Bottom Cap
    faces.append((0, 1, npts + 1))
    for i in range(0, npts - 1):
        faces.append((i, i + 1, npts + i + 1))
        faces.append((i, npts + i + 1, npts + i))

    #Middle
    nPerStage = npts * 2
    for j in range(0, nspan):
        for i in range(0, npts - 1):
            faces.append((nPerStage * j + i, nPerStage * (j + 1) + i,
                          nPerStage * (j + 1) + i + 1))
            faces.append((nPerStage * j + i, nPerStage * (j + 1) + i + 1,
                          nPerStage * j + i + 1))
        for i in range(0, npts - 1):
            faces.append(
                (nPerStage * j + i + npts, nPerStage * (j + 1) + i + 1 + npts,
                 nPerStage * (j + 1) + i + npts))
            faces.append(
                (nPerStage * j + i + npts, nPerStage * j + i + 1 + npts,
                 nPerStage * (j + 1) + i + 1 + npts))
        faces.append((nPerStage * j + npts - 1, nPerStage * (j + 1) + npts - 1,
                      nPerStage * (j + 1) + npts * 2 - 1))
        faces.append(
            (nPerStage * j + npts - 1, nPerStage * (j + 1) + npts * 2 - 1,
             nPerStage * (j) + npts * 2 - 1))
    #Top Cap
    faces.append((nPerStage * (nspan), nPerStage * (nspan) + 1,
                  nPerStage * (nspan) + npts + 1))
    for i in range(0, npts - 1):
        faces.append(
            (nPerStage * (nspan) + i, nPerStage * (nspan) + npts + i + 1,
             nPerStage * (nspan) + i + 1))
        faces.append((nPerStage * (nspan) + i, nPerStage * (nspan) + npts + i,
                      nPerStage * (nspan) + npts + i + 1))

    #Create Object
    ob1 = DLUtils.createMesh(name, origin, verts, [], faces)

    #reset Vars
    centerOfTwist[0] *= 100
    centerOfTwist[1] *= 100
def NACA4Blade(name,camber_root,camber_tip,camber_position,\
        thickness,bladeHeight,twistAngle,rootChord,tipChord,\
        centerOfTwist,nspan,npts):

    #//////////////////////
	#//Inputs:
	#//	camber_max: %chord
	#//	camber_position: location of max camber %chord
	#//	thickness: max thickness of airfoil as %chord
	#//	bladeHeight: height of blade
	#//	twist: degrees/unit height
	#// centerOfTwist: %chord
	#//	nspan: number of span wise subdivisions
	#//	npts: number of pts used to discretise both the upper and lower airfoil profile surface.

    #Twist per unit length
    twist=math.radians(twistAngle)/bladeHeight

    
    mr=camber_root/100
    mt=camber_tip/100
    p=camber_position/100
    t=thickness/100
    centerOfTwist[0]= centerOfTwist[0]/100
    centerOfTwist[1]/=100
    
    x=[]
    yt=[]
    yc=[]
    xu=[]
    yu=[]
    xl=[]
    yl=[]
    xuTwist=[0]*npts
    yuTwist=[0]*npts
    xlTwist=[0]*npts
    ylTwist=[0]*npts
    verts=[]
    faces=[]
    origin=(0,0,0)

    

    
    #Generate vertex coordinates with twist and scale along the span        
    dspan = bladeHeight/nspan
    for j in range(0,nspan+1): 
        
        ### bad use of memory, Fix it.  Does this matter in Python?
        x=[]
        yt=[]
        yc=[]
        xu=[]
        xl=[]
        yu=[]
        yl=[]
        
        m=(1-j/(nspan))*mr + j/nspan*mt
        
        #Generate vertex coordinates for unmodified airfoil shape
        for i in range(0,npts+1):
        
            x.append(1-math.cos(i*(math.pi/2)/npts))
            yt.append(t/0.2*(0.2969*math.pow(x[i],0.5)-0.126*x[i]-0.3516*math.pow(x[i],2)+0.2843*math.pow(x[i],3) - 0.1015*math.pow(x[i],4)))
            if(x[i]<p):
                yc.append(m/pow(p,2)*(2*p*x[i] - pow(x[i],2)))
                dycdx = 2*m/pow(p,2)*(p-x[i])
            else:
                yc.append(m/pow(1-p,2)*(1 - 2*p + 2*p*x[i] - pow(x[i],2)))
                dycdx = 2*m/pow(1-p,2)*(p-x[i])
                
            #Shift foil to center of twist
            x[i] -= centerOfTwist[0]
            yc[i] -= centerOfTwist[1]
                
            xu.append(x[i] - yt[i]*(math.sin(math.atan(dycdx))))
            yu.append(yc[i] + yt[i]*(math.cos(math.atan(dycdx))))
            xl.append(x[i] + yt[i]*(math.sin(math.atan(dycdx))))
            yl.append(yc[i] - yt[i]*(math.cos(math.atan(dycdx))))
            
            
        
        #####
           
        angle = twist*j*dspan
        chord = rootChord - j*dspan*(rootChord-tipChord)/bladeHeight	
        for i in range(0,npts):
            xuTwist[i] = xu[i]*math.cos(angle) -yu[i]*math.sin(angle)
            yuTwist[i] = xu[i]*math.sin(angle) +yu[i]*math.cos(angle)
            
            xuTwist[i] *= chord
            yuTwist[i] *= chord
            
            verts.append((xuTwist[i],yuTwist[i],j*dspan))
        for i in range(0,npts):
            xlTwist[i] = xl[i]*math.cos(angle) -yl[i]*math.sin(angle)
            ylTwist[i] = xl[i]*math.sin(angle) +yl[i]*math.cos(angle)
            
            xlTwist[i] *= chord
            ylTwist[i] *= chord
            
            verts.append((xlTwist[i],ylTwist[i],j*dspan))
    
    
    #Generate Polies from vertex IDs
    #Bottom Cap
    faces.append((0,1,npts+1))
    for i in range(0,npts-1):
        faces.append((i,i+1,npts+i+1))    
        faces.append((i,npts+i+1,npts+i))    

    #Middle
    nPerStage = npts*2
    for j in range(0,nspan):
        for i in range(0,npts-1):
            faces.append((nPerStage*j+i,nPerStage*(j+1)+i,nPerStage*(j+1)+i+1))
            faces.append((nPerStage*j+i,nPerStage*(j+1)+i+1,nPerStage*j+i+1))
        for i in range(0,npts-1):
            faces.append((nPerStage*j+i+npts,nPerStage*(j+1)+i+1+npts,nPerStage*(j+1)+i+npts))
            faces.append((nPerStage*j+i+npts,nPerStage*j+i+1+npts,nPerStage*(j+1)+i+1+npts))
        faces.append((nPerStage*j+npts-1,nPerStage*(j+1)+npts-1,nPerStage*(j+1)+npts*2-1))
        faces.append((nPerStage*j+npts-1,nPerStage*(j+1)+npts*2-1,nPerStage*(j)+npts*2-1))
    #Top Cap
    faces.append((nPerStage*(nspan),nPerStage*(nspan)+1,nPerStage*(nspan)+npts+1))
    for i in range(0,npts-1):
        faces.append((nPerStage*(nspan)+i,nPerStage*(nspan)+npts+i+1,nPerStage*(nspan)+i+1))    
        faces.append((nPerStage*(nspan)+i,nPerStage*(nspan)+npts+i,nPerStage*(nspan)+npts+i+1))    
    
    #Create Object    
    ob1 = DLUtils.createMesh(name, origin, verts, [], faces)
    
    #reset Vars
    centerOfTwist[0]*=100
    centerOfTwist[1]*=100
def Rotor(rotorName,hubDia,rotorDia,hubHeight,hubThickness,axleDia,\
        camber_root,camber_tip,camber_position,thickness,\
        bladeHeight,twistAngle,rootChord,\
        tipChord,clearance,centerOfTwist,nspan,\
        npts,rootAngle,nRotorBlades):

    res = 64
    
    #Delete any existing hubs
    # remove mesh Hub
    DLUtils.DeleteMesh(rotorName)
        
    #Generate Hub    
    bpy.ops.mesh.primitive_cylinder_add(vertices=res,radius=hubDia/2,depth=hubHeight,location=(0,0,0)) 
    cyl = bpy.data.objects["Cylinder"]
    cyl.name = rotorName
    cyl.data.name = rotorName
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    
     
    
    #Generate all Blades
    for i in range(0,nRotorBlades):
        
        
        #Generate blade
        TurboMachLib.NACA4Blade("RotorBlade"+str(i),camber_root,camber_tip,camber_position,thickness,	bladeHeight, twistAngle,rootChord,tipChord,	centerOfTwist, nspan,npts)
        
        #Grab the mesh
        me = bpy.data.meshes["RotorBlade"+str(i)]
        
        #We want to rotate the blades (twist angle of the root), so generate the rotation matrix
        R = mathutils.Matrix.Rotation(math.radians(rootAngle),3,(0,0,1))    
        
        #Shift and rotate the verts
        for v in me.vertices:
            v.co += mathutils.Vector((0,0,hubDia/2.5))
            v.co = R*v.co
        
        #Deselect all    
        bpy.ops.object.select_all(action='DESELECT')
        
        #Grab the blade object
        ob = bpy.data.objects["RotorBlade"+str(i)]
        ob.delta_location = [hubThickness/2,0,0]
       
        DLUtils.SelectOnly("RotorBlade"+str(i))
        
        #Remove doubles
        print("RemoveDoubles: RotorBlade"+str(i))  
        bpy.ops.object.editmode_toggle()
        bpy.ops.mesh.remove_doubles()
        bpy.ops.object.editmode_toggle()    
        
        #Rotate the blade to it's proper position    
        bpy.ops.transform.rotate(value=i*math.pi*2/nRotorBlades,axis=(1.0,0.0,0.0))
    
        #Boolean union the blades to the hub
        print("Boolean: RotorBlade"+str(i)) 
        DLUtils.BooleanMesh(rotorName,"RotorBlade"+str(i),"UNION",False)    

   
    #clean up!
    for n in range(0,nRotorBlades):
        DLUtils.DeleteMesh("RotorBlade"+str(n))    
     
     
    axelName = "AxleHole"
    DLUtils.DeleteMesh(axelName)

    rimThickness = 1.25
    rimDepth = 2

    #Hollow out hub 
    DLUtils.DrawCylinder("cutout",hubDia-hubThickness*2,0,hubHeight,res)
    bpy.data.objects["cutout"].delta_rotation_euler = [0,math.pi/2,0]
    bpy.data.objects["cutout"].delta_location = [hubThickness+(rimDepth+hubThickness),0,0]
    DLUtils.BooleanMesh(rotorName,"cutout","DIFFERENCE",True)

    DLUtils.DrawCylinder("cutout",hubDia-hubThickness*4,0,hubHeight,res)
    bpy.data.objects["cutout"].delta_rotation_euler = [0,math.pi/2,0]
    bpy.data.objects["cutout"].delta_location = [hubThickness,0,0]
    DLUtils.BooleanMesh(rotorName,"cutout","DIFFERENCE",True)


    #Generate axle hole extrusion
    DLUtils.DrawCylinder(axelName,axleDia+hubThickness*2,0,hubHeight-hubThickness*2,res)
    bpy.data.objects[axelName].delta_location = [-hubThickness*0.9,0,0]
    bpy.data.objects[axelName].delta_rotation_euler = [0,math.pi/2,0]
    DLUtils.BooleanMesh(rotorName,axelName,"UNION",True)   
    
    #Generate hole for axle
    DLUtils.DrawCylinder(axelName,axleDia,0,hubHeight*2,res)
    bpy.data.objects[axelName].delta_rotation_euler = [0,math.pi/2,0]
    DLUtils.BooleanMesh(rotorName,axelName,"DIFFERENCE",True)   
    
    #Trim Blades
    DLUtils.DrawCylinder("cutBlades",rotorDia-clearance*2,0,hubHeight*2,res)
    bpy.data.objects["cutBlades"].delta_rotation_euler = [0,math.pi/2,0]
    DLUtils.BooleanMesh(rotorName,"cutBlades","INTERSECT",True)   
    
    #Draw inside spokes
    ri= (axleDia+hubThickness*2)/2
    ro= hubDia/2
    nSpokes=7
    for i in range(0,nSpokes):
        DLUtils.DrawBox("spoke"+str(i),hubHeight-hubThickness*2.5,hubThickness,ro-ri)
        DLUtils.ShiftVerts("spoke"+str(i),mathutils.Vector((-hubThickness*0.9,0,(ri+(ro-ri)/2)*0.9)))
        
        #Rotate the spoke to it's proper position    
        bpy.ops.transform.rotate(value=i*math.pi*2/nSpokes,axis=(1.0,0.0,0.0))
        DLUtils.BooleanMesh(rotorName,"spoke"+str(i),"UNION",True)
        
    #Ream out the rim for the hub cone
    
    DLUtils.DrawCylinder("rimCut",hubDia+1,hubDia-2*rimThickness,rimDepth+1,res)
    bpy.data.objects["rimCut"].delta_rotation_euler = [0,math.pi/2,0]
    DLUtils.MoveObject("rimCut",mathutils.Vector([-(hubHeight/2-rimDepth/2),0,0]))
    
    #remove doubles to prevent errors
    DLUtils.SelectOnly("rimCut")
    bpy.ops.object.editmode_toggle()
    bpy.ops.mesh.remove_doubles()
    bpy.ops.object.editmode_toggle()    
    DLUtils.SelectOnly(rotorName)
    bpy.ops.object.editmode_toggle()
    bpy.ops.mesh.remove_doubles()
    bpy.ops.object.editmode_toggle()
    #ream it     
    DLUtils.BooleanMesh(rotorName,"rimCut","DIFFERENCE",True)      
def LEDHolder(LEDDia = 5.5,
				thick=1.5,
				tol = 0.5,
				L=15,
				W=20):
    
    
    od = LEDDia+4
    
    DLUtils.DeleteMesh("Sphere1")
    DLUtils.DeleteMesh("Sphere2")
    DLUtils.DeleteMesh("Base")
	
    DLUtils.DrawCylinder("LEDHole",LEDDia,0,10,64)
    DLUtils.MoveObject("LEDHole",mathutils.Vector((0,0,4.5)))
    DLUtils.DrawCylinder("LEDHole2",LEDDia+1,0,6,64)
    DLUtils.MoveObject("LEDHole2",mathutils.Vector((0,0,-3)))
    
    
    DLUtils.DrawBox("Base",L,1,W)
    DLUtils.MoveObject("Base",mathutils.Vector([0,-od/2,0]))
    DLUtils.DrawSphere("Sphere1",od,16)
    DLUtils.MoveObject("Sphere1",mathutils.Vector([0,0,L/4]))
    DLUtils.DrawSphere("Sphere2",od,32)
    DLUtils.MoveObject("Sphere2",mathutils.Vector([0,0,-L/4]))
    
    DLUtils.ConvexHull(["Sphere1","Sphere2","Base"])
    
    DLUtils.BooleanMesh("Convex Hull","LEDHole","DIFFERENCE",True)
    DLUtils.BooleanMesh("Convex Hull","LEDHole2","DIFFERENCE",True)
    DLUtils.DeleteMesh("Sphere1")
    DLUtils.DeleteMesh("Sphere2")
    DLUtils.DeleteMesh("Base")
def Stator(ductID=64,ductThickness=2,ductLength=60,res=64,\
            mountFaceXLoc=20,mountCanID=28.8,mountCanLength=20,\
            nBlades=1,rootAngle=0,camberRoot=6,camberTip=6,camber_position=50,\
            bladeThickness=6,bladeHeight=50,twistAngle=5,rootChord=10,\
            tipChord=10,centerOfTwist=[50,0],nspan=5,npts=25,screwHoleDia=2.6,screwHoleSpreadDia=16,shaftHoleDia=9):

    #Names we are going to use, we are going to clean up first
    ductName = "duct"
    mountName= "can"
    bladeName= "blade"
    
    DLUtils.DeleteMesh(ductName)
    DLUtils.DeleteMesh(mountName)
    DLUtils.DeleteMesh(mountName+"Inside")    
    for i in range(0,nBlades):
        DLUtils.DeleteMesh(bladeName+str(i))
        

    #Draw duct
    DLUtils.DrawCylinder(ductName,ductID+ductThickness*2,ductID,ductLength,res)
    DLUtils.SelectOnly(ductName)
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    
    #Draw duct tabs
    tabLength = 36.8
    tabWidth = 11
    tabHeight = 1.5
    DLUtils.DrawBox("tab1", tabLength,tabWidth,tabHeight)    
    DLUtils.DrawBox("tab2", tabLength,tabWidth,tabHeight)    
    DLUtils.MoveObject("tab1",mathutils.Vector([0,ductID/2+tabWidth/2 + ductThickness/2,0]))
    DLUtils.MoveObject("tab2",mathutils.Vector([0,-(ductID/2+tabWidth/2 + ductThickness/2),0]))
    DLUtils.BooleanMesh(ductName,"tab1","UNION",True)
    DLUtils.BooleanMesh(ductName,"tab2","UNION",True)
    
    #Draw mount can    
    DLUtils.DrawCylinder(mountName,mountCanID+ductThickness*2,0,mountCanLength,res)
    DLUtils.DrawCylinder(mountName+"Inside",mountCanID,0,mountCanLength,res)
    bpy.data.objects[mountName+"Inside"].delta_location = [0,0,ductThickness]
        
    #Cut out the can interior
    DLUtils.BooleanMesh(mountName,mountName+"Inside","DIFFERENCE",True)

    #Cut out mount and shaft holes
    DLUtils.DrawCylinder("shaftHole",shaftHoleDia,0,mountCanLength*2,res)
    bpy.data.objects["shaftHole"].delta_location = [0,0,0]
    DLUtils.BooleanMesh(mountName,"shaftHole","DIFFERENCE",True)
    #ewHoleDia=2.5,screwHoleSpreadDia=16,shaftHoleDia=8):
    for i in range(0,4):
        DLUtils.DrawCylinder("screwHole",screwHoleDia,0,mountCanLength*2,res)
        bpy.data.objects["screwHole"].delta_location = [screwHoleSpreadDia/2*math.cos(i*math.pi*2/4),screwHoleSpreadDia/2*math.sin(i*math.pi*2/4),0]
        DLUtils.BooleanMesh(mountName,"screwHole","DIFFERENCE",True)
    
        
    #Rotate the mount horizontally
    DLUtils.SelectOnly(mountName)
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    
    #Add box to cut out wire hole
    DLUtils.DrawBox("wireBox", 15,10,15)
    bpy.data.objects["wireBox"].delta_location = [mountCanLength/2-2,-mountCanID/2,0]
    #DLUtils.MoveObject("wireBox",mathutils.Vector([mountCanLength-7,-mountCanID/2,0]))
    DLUtils.BooleanMesh(mountName,"wireBox","DIFFERENCE",True)
    
         
    for i in range(0,nBlades):
        #Generate blade
        TurboMachLib.NACA4Blade(bladeName+str(i),camberRoot, camberTip,camber_position,bladeThickness,	bladeHeight, twistAngle,rootChord,tipChord,	centerOfTwist, nspan,npts)
        
        #Grab the mesh
        me = bpy.data.meshes[bladeName+str(i)]
        
        #We want to rotate the blades (twist angle of the root), so generate the rotation matrix
        R = mathutils.Matrix.Rotation(math.radians(rootAngle),3,(0,0,1))    
        
        #Shift and rotate the verts
        for v in me.vertices:
            v.co += mathutils.Vector((0,0,mountCanID/2))
            v.co = R*v.co
        
        #Deselect all    
        bpy.ops.object.select_all(action='DESELECT')
        
        #Grab the blade object
        ob = bpy.data.objects[bladeName+str(i)]
        ob.delta_location = [ductThickness/2,0,0]
        #ensure it is selected
        ob.select = True
        
        #Remove doubles
        print("RemoveDoubles: "+bladeName+str(i))  
        bpy.ops.object.editmode_toggle()
        bpy.ops.mesh.remove_doubles()
        bpy.ops.object.editmode_toggle()    
        
        #Rotate the blade to it's proper position    
        bpy.ops.transform.rotate(value=i*math.pi*2/nBlades,axis=(1.0,0.0,0.0))
    
        #Boolean union the blades to the hub
        print("Boolean: blade"+str(i)) 
        #DLUtils.BooleanMesh(ductName,bladeName+str(i),"UNION",False)        
    
    #Add inside blade cut
    DLUtils.DrawCylinder("bladeCut",mountCanID+ductThickness,0,mountCanLength,res)
    DLUtils.SelectOnly("bladeCut")
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
     
    for i in range(0,nBlades):
         DLUtils.BooleanMesh(bladeName+str(i),"bladeCut","DIFFERENCE",False)
         DLUtils.BooleanMesh(mountName,bladeName+str(i),"UNION",True)
       
    #Delete "BladeCut"
    DLUtils.DeleteMesh("bladeCut")
    
    #Add outside blade Cut
    DLUtils.DrawCylinder("bladeCut",ductID+ductThickness,0,ductLength,res)
    DLUtils.SelectOnly("bladeCut")
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    
    #cut the outside of the blades 
    DLUtils.BooleanMesh(mountName,"bladeCut","INTERSECT",True)
           
    
    #Move the can to the mountFaceXLoc 
    bpy.data.objects[mountName].delta_location = [mountCanLength/2-ductLength/2+mountFaceXLoc,0,0]
      
    #Union the can and the duct  
    DLUtils.BooleanMesh(ductName,mountName,"UNION",True)


    LEDHolder()
Ejemplo n.º 7
0
def Propeller(propName,propDia,pitch,\
        hubHeight,hubDia,axleDia,\
  PropellerProps,\
        bladeTransition,nspan,npts,nBlades):

    p = PropellerProps

    res = 64  #used to define cylinder resolution.

    #initialising arrays we'll need.
    verts = []
    tmpVerts = []
    tmpVert = [0, 0, 0]
    faces = []
    origin = (0, 0, 0)
    centerOfTwist = [0, 0]

    p.rootSlope *= math.pi / 180
    p.transitionSlope *= math.pi / 180
    p.tipSlope *= math.pi / 180

    p.rootSkewSlope *= math.pi / 180
    p.transitionSkewSlope *= math.pi / 180
    p.tipSkewSlope *= math.pi / 180

    #An array of the chord lengths at each span point
    chordArray = []
    #An array of the NACA4 digits at each span point.
    NACAArray = []
    #An array that holds the position along the blade span of the airfoil cross-sections
    sPos = []
    #An array that holds the amount of skew of each airfoil cross-section
    skew = []

    #Blade root will be at center of rotation.
    bladeHeight = propDia / 2
    bladeLen = bladeHeight - bladeTransition
    dSpan = bladeHeight / nspan

    lastI = 0
    for i in range(0, nspan + 1):

        span = i * dSpan

        if (span < bladeTransition):

            #Using cubic spline interpolation.
            t = span / bladeTransition
            tm1 = 1 - t

            #root to transition point interpolation
            y1 = p.rootChord
            y2 = p.rootChord + math.sin(p.rootSlope) * p.rootStrength
            y3 = p.transitionChord - math.sin(
                p.transitionSlope) * p.transitionStrengthRoot
            y4 = p.transitionChord

            chord = pow(tm1, 3) * y1 + 3 * pow(
                tm1, 2) * t * y2 + 3 * tm1 * pow(t, 2) * y3 + pow(t, 3) * y4

            chordArray.append(chord)

            x1 = 0
            x2 = math.cos(p.rootSlope) * p.rootStrength
            x3 = (bladeTransition -
                  math.cos(p.transitionSlope) * p.transitionStrengthRoot)
            x4 = bladeTransition

            x = pow(tm1, 3) * x1 + 3 * pow(tm1, 2) * t * x2 + 3 * tm1 * pow(
                t, 2) * x3 + pow(t, 3) * x4
            sPos.append(x)

            y1 = p.rootThick
            y2 = p.rootThick + math.sin(p.rootThickSlope) * p.rootThickStrength
            y3 = p.transitionThick - math.sin(
                p.transitionThickSlope) * p.transitionThickStrengthRoot
            y4 = p.transitionThick

            thickPt = pow(tm1, 3) * y1 + 3 * pow(
                tm1, 2) * t * y2 + 3 * tm1 * pow(t, 2) * y3 + pow(t, 3) * y4
            print(thickPt)
            NACAArray.append([
                5, 3,
                int(thickPt * 10),
                int(thickPt * 100 - int(thickPt * 10) * 10)
            ])

            y1 = p.rootSkew
            y2 = p.rootSkew + math.sin(p.rootSkewSlope) * p.rootSkewStrength
            y3 = p.transitionSkew - math.sin(
                p.transitionSkewSlope) * p.transitionSkewStrengthRoot
            y4 = p.transitionSkew

            skewPt = pow(tm1, 3) * y1 + 3 * pow(
                tm1, 2) * t * y2 + 3 * tm1 * pow(t, 2) * y3 + pow(t, 3) * y4
            skew.append(skewPt)
        else:

            #Using cubic spline interpolation.
            t = (span - bladeTransition) / bladeLen
            tm1 = 1 - t

            y1 = p.transitionChord
            y2 = p.transitionChord + math.sin(
                p.transitionSlope) * p.transitionStrengthTip
            y3 = p.tipChord - math.sin(p.tipSlope) * p.tipStrength
            y4 = p.tipChord

            chord = pow(tm1, 3) * y1 + 3 * pow(
                tm1, 2) * t * y2 + 3 * tm1 * pow(t, 2) * y3 + pow(t, 3) * y4

            chordArray.append(chord)

            x1 = 0
            x2 = math.cos(p.transitionSlope) * p.transitionStrengthTip
            x3 = (bladeLen - math.cos(p.tipSlope) * p.tipStrength)
            x4 = bladeLen

            x = pow(tm1, 3) * x1 + 3 * pow(tm1, 2) * t * x2 + 3 * tm1 * pow(
                t, 2) * x3 + pow(t, 3) * x4
            sPos.append(bladeTransition + x)

            y1 = p.transitionThick
            y2 = p.transitionThick + math.sin(
                p.rootThickSlope) * p.rootThickStrength
            y3 = p.tipThick - math.sin(
                p.transitionThickSlope) * p.transitionThickStrengthTip
            y4 = p.tipThick

            thickPt = pow(tm1, 3) * y1 + 3 * pow(
                tm1, 2) * t * y2 + 3 * tm1 * pow(t, 2) * y3 + pow(t, 3) * y4

            NACAArray.append([
                5, 3,
                int(thickPt * 10),
                int(thickPt * 100 - int(thickPt * 10) * 10)
            ])

            y1 = p.transitionSkew
            y2 = p.transitionSkew + math.sin(
                p.transitionSkewSlope) * p.transitionSkewStrengthTip
            y3 = p.tipSkew - math.sin(p.tipSkewSlope) * p.tipSkewStrength
            y4 = p.tipSkew

            skewPt = pow(tm1, 3) * y1 + 3 * pow(
                tm1, 2) * t * y2 + 3 * tm1 * pow(t, 2) * y3 + pow(t, 3) * y4
            skew.append(skewPt)

    #error check of inputs
    if (len(chordArray) != nspan or len(NACAArray) != nspan):
        print(
            "The size of the array of chord lengths or the array of airfoil NACA digits does not match the number of span points used to define the blade geometry."
        )

    #Delete any existing prop geoms
    DLUtils.DeleteMesh(propName)

    #Generate Hub
    DLUtils.DrawCylinder("Hub", hubDia, 0, hubHeight,
                         res)  #use a 0.001m tolerance which we'll trim off.
    cyl = bpy.data.objects["Hub"]
    cyl.name = propName
    cyl.data.name = propName
    DLUtils.SelectOnly(propName)
    bpy.ops.transform.rotate(value=math.radians(90), axis=(0.0, 1.0, 0.0))
    DLUtils.MoveObject(propName, [2.0, 0, 0])

    areaArray = []

    #Generate vertex coordinates with twist and scale along the span
    for i in range(0, nspan + 1):
        span = sPos[i]  #i*dSpan
        if (span == 0):
            twistAngle = 0
        elif (span < bladeTransition):
            twistAngle = math.atan(
                pitch / (2 * math.pi * span)) * span / bladeTransition
        else:
            twistAngle = math.atan(pitch / (2 * math.pi * span))

        #get the airfoil profile vertices
        tmpVerts = TurboMachLib.NACA4Profile(camber=NACAArray[i][0],
                                             thickness=NACAArray[i][2] * 10 +
                                             NACAArray[i][3],
                                             camberPos=NACAArray[i][1] * 10,
                                             chord=chordArray[i],
                                             npts=npts)
        areaArray.append(0)

        centerOfTwist[0] = chordArray[i] * skew[i]
        #centerOfTwist[1] = raiseFoil
        for v in range(0, len(tmpVerts)):

            #shift all verts for twisting
            tmpVerts[v][0] -= centerOfTwist[0]
            tmpVerts[v][1] -= centerOfTwist[1]

            #Twist the airfoil vertices.  First we shift them to get the desired center of rotation.
            tmpVert[0] = tmpVerts[v][0] * math.cos(
                twistAngle) - tmpVerts[v][1] * math.sin(twistAngle)
            tmpVert[1] = tmpVerts[v][0] * math.sin(
                twistAngle) + tmpVerts[v][1] * math.cos(twistAngle)

            #shift all verts to their proper span location in Z
            tmpVert[
                2] = span + 0.01 * bladeHeight  #Shift blade by 1% of blade height to prevent poor boolean ops

            #append the vert to the master vertex list
            verts.append((tmpVert[0], tmpVert[1], tmpVert[2]))

            if (v != 0):
                dx = abs(verts[len(verts) - 1][0] - verts[len(verts) - 2][0])
                dy = abs(verts[len(verts) - 1][1] +
                         verts[len(verts) - 2][1]) / 2
                areaArray[i] += dy * dx

    #Generate Polies from vertex IDs
    #Bottom Cap
    faces.append((0, 1, npts))
    for i in range(1, npts - 1):
        faces.append((i, i + 1, npts + i))
        faces.append((i, npts + i, npts + i - 1))

    #Middle
    nPerStage = npts * 2 - 1
    for j in range(0, nspan):
        #Top Side
        for i in range(0, npts - 1):
            faces.append((nPerStage * j + i, nPerStage * (j + 1) + i,
                          nPerStage * (j + 1) + i + 1))
            faces.append((nPerStage * j + i, nPerStage * (j + 1) + i + 1,
                          nPerStage * j + i + 1))

        #First strip for bottom side (hooks to verts from top side)
        faces.append(
            (nPerStage * j, nPerStage * (j + 1) + npts, nPerStage * (j + 1)))
        faces.append(
            (nPerStage * j, nPerStage * j + npts, nPerStage * (j + 1) + npts))

        #Rest of bottom side
        for i in range(0, npts - 2):
            faces.append(
                (nPerStage * j + i + npts, nPerStage * (j + 1) + i + npts + 1,
                 nPerStage * (j + 1) + i + npts))
            faces.append(
                (nPerStage * j + i + npts, nPerStage * j + i + npts + 1,
                 nPerStage * (j + 1) + i + npts + 1))

        #Back face
        faces.append((nPerStage * j + npts - 1, nPerStage * (j + 1) + npts - 1,
                      nPerStage * (j + 1) + npts * 2 - 2))
        faces.append(
            (nPerStage * j + npts - 1, nPerStage * (j + 1) + npts * 2 - 2,
             nPerStage * (j) + npts * 2 - 2))

    #Top Cap
    faces.append((nPerStage * (nspan), nPerStage * (nspan) + 1,
                  nPerStage * (nspan) + npts))
    for i in range(1, npts - 1):
        faces.append((nPerStage * (nspan) + i, nPerStage * (nspan) + npts + i,
                      nPerStage * (nspan) + i + 1))
        faces.append(
            (nPerStage * (nspan) + i, nPerStage * (nspan) + npts + i - 1,
             nPerStage * (nspan) + npts + i))

    #Create Blender object for the blade
    dAngle = 360.0 / nBlades

    for i in range(0, nBlades):
        print("Draw Blade_" + str(i))
        blade = DLUtils.createMesh("Blade_" + str(i), origin, verts, [], faces)
        DLUtils.SelectOnly("Blade_" + str(i))
        bpy.ops.transform.rotate(value=math.radians(90), axis=(0.0, 0.0, 1.0))
        bpy.ops.transform.rotate(value=math.radians(dAngle) * i,
                                 axis=(1.0, 0.0, 0.0))

    #Union the blades to the hub
    for i in range(0, nBlades):
        print("Union: Blade_" + str(i))
        DLUtils.BooleanMesh(propName, "Blade_" + str(i), "UNION", True)

    #trim the blades to hub height
    DLUtils.DrawBox("box", hubDia * 1.1, hubDia * 1.1, hubDia * 1.1)
    DLUtils.MoveObject("box", [propDia / 2 + hubHeight / 2 + 0.001, 0, 0])
    DLUtils.BooleanMesh(propName, "box", "DIFFERENCE", True)

    #cut the axle hole
    DLUtils.DrawCylinder("hole", axleDia, 0, hubHeight * 2, res)
    DLUtils.SelectOnly("hole")
    bpy.ops.transform.rotate(value=math.radians(90), axis=(0.0, 1.0, 0.0))
    DLUtils.BooleanMesh(propName, "hole", 'DIFFERENCE', True)

    #Cut room for the axle shive
    DLUtils.DrawCylinder("ShiveHole", (hubDia - axleDia) / 4 + axleDia, 0,
                         hubHeight / 1.5, res)
    DLUtils.SelectOnly("ShiveHole")
    bpy.ops.transform.rotate(value=math.radians(90), axis=(0.0, 1.0, 0.0))
    DLUtils.BooleanMesh(propName, "ShiveHole", 'DIFFERENCE', True)
    #DLUtils.MoveObject(propName,[2.0,0,0])

    #trim the blades to the proper dia
    DLUtils.DrawCylinder("BladeTrim", propDia, 0, propDia, 256)
    DLUtils.SelectOnly("BladeTrim")
    bpy.ops.transform.rotate(value=math.radians(90), axis=(0.0, 1.0, 0.0))
    DLUtils.BooleanMesh(propName, "BladeTrim", 'INTERSECT', True)

    #done!
    print((BladeAxialStress(sPos, areaArray, 40e6, 1300, 15000)))

    return
def Propeller(propName,propDia,pitch,\
        hubHeight,hubDia,axleDia,\
		PropellerProps,\
        bladeTransition,nspan,npts,nBlades):
		
    p=PropellerProps    
        
    res = 64  #used to define cylinder resolution.
    
    #initialising arrays we'll need.
    verts = []
    tmpVerts = []
    tmpVert = [0,0,0]
    faces = []
    origin=(0,0,0)
    centerOfTwist = [0,0]
    
    p.rootSlope *= math.pi/180
    p.transitionSlope *= math.pi/180
    p.tipSlope *= math.pi/180
    
    p.rootSkewSlope *= math.pi/180
    p.transitionSkewSlope *= math.pi/180
    p.tipSkewSlope *= math.pi/180
    
    #An array of the chord lengths at each span point
    chordArray = []
    #An array of the NACA4 digits at each span point.
    NACAArray = []
    #An array that holds the position along the blade span of the airfoil cross-sections
    sPos = []
    #An array that holds the amount of skew of each airfoil cross-section
    skew = []

   
    #Blade root will be at center of rotation.
    bladeHeight = propDia/2 
    bladeLen = bladeHeight - bladeTransition
    dSpan = bladeHeight/nspan
    
    lastI = 0;
    for i in range(0,nspan+1):

        span = i*dSpan
        
        if(span < bladeTransition):
                        
            #Using cubic spline interpolation.
            t = span/bladeTransition
            tm1 = 1-t
            
            #root to transition point interpolation
            y1 = p.rootChord
            y2 = p.rootChord + math.sin(p.rootSlope)*p.rootStrength
            y3 = p.transitionChord - math.sin(p.transitionSlope)*p.transitionStrengthRoot
            y4 = p.transitionChord
            
            chord = pow(tm1,3)*y1 + 3*pow(tm1,2)*t*y2 + 3*tm1*pow(t,2)*y3 + pow(t,3)*y4
            
            chordArray.append(chord)
            
            x1=0
            x2=math.cos(p.rootSlope)*p.rootStrength
            x3=(bladeTransition-math.cos(p.transitionSlope)*p.transitionStrengthRoot)
            x4=bladeTransition
            
            x = pow(tm1,3)*x1 + 3*pow(tm1,2)*t*x2 + 3*tm1*pow(t,2)*x3 + pow(t,3)*x4
            sPos.append(x)
            
            
            y1 = p.rootThick
            y2 = p.rootThick + math.sin(p.rootThickSlope)*p.rootThickStrength
            y3 = p.transitionThick - math.sin(p.transitionThickSlope)*p.transitionThickStrengthRoot
            y4 = p.transitionThick
            
            thickPt = pow(tm1,3)*y1 + 3*pow(tm1,2)*t*y2 + 3*tm1*pow(t,2)*y3 + pow(t,3)*y4
            print(thickPt)
            NACAArray.append([5,3,int(thickPt*10),int(thickPt*100-int(thickPt*10)*10)])
            
            y1 = p.rootSkew
            y2 = p.rootSkew + math.sin(p.rootSkewSlope)*p.rootSkewStrength
            y3 = p.transitionSkew - math.sin(p.transitionSkewSlope)*p.transitionSkewStrengthRoot
            y4 = p.transitionSkew
            
            skewPt = pow(tm1,3)*y1 + 3*pow(tm1,2)*t*y2 + 3*tm1*pow(t,2)*y3 + pow(t,3)*y4
            skew.append(skewPt);
        else:
                
            #Using cubic spline interpolation.
            t = (span-bladeTransition)/bladeLen
            tm1 = 1-t
            
            y1 = p.transitionChord
            y2 = p.transitionChord + math.sin(p.transitionSlope)*p.transitionStrengthTip
            y3 = p.tipChord - math.sin(p.tipSlope)*p.tipStrength
            y4 = p.tipChord
            
            chord = pow(tm1,3)*y1 + 3*pow(tm1,2)*t*y2 + 3*tm1*pow(t,2)*y3 + pow(t,3)*y4
            
            chordArray.append(chord)
            
            x1=0
            x2=math.cos(p.transitionSlope)*p.transitionStrengthTip
            x3=(bladeLen-math.cos(p.tipSlope)*p.tipStrength)
            x4=bladeLen
            
            x = pow(tm1,3)*x1 + 3*pow(tm1,2)*t*x2 + 3*tm1*pow(t,2)*x3 + pow(t,3)*x4
            sPos.append(bladeTransition+x)
            
            y1 = p.transitionThick
            y2 = p.transitionThick + math.sin(p.rootThickSlope)*p.rootThickStrength
            y3 = p.tipThick - math.sin(p.transitionThickSlope)*p.transitionThickStrengthTip
            y4 = p.tipThick
            
            thickPt = pow(tm1,3)*y1 + 3*pow(tm1,2)*t*y2 + 3*tm1*pow(t,2)*y3 + pow(t,3)*y4
            
            NACAArray.append([5,3,int(thickPt*10),int(thickPt*100-int(thickPt*10)*10)])
            
            y1 = p.transitionSkew
            y2 = p.transitionSkew+ math.sin(p.transitionSkewSlope)*p.transitionSkewStrengthTip
            y3 = p.tipSkew - math.sin(p.tipSkewSlope)*p.tipSkewStrength
            y4 = p.tipSkew
            
            skewPt = pow(tm1,3)*y1 + 3*pow(tm1,2)*t*y2 + 3*tm1*pow(t,2)*y3 + pow(t,3)*y4
            skew.append(skewPt);
        
         
    
    #error check of inputs
    if(len(chordArray) != nspan or len(NACAArray) != nspan):
        print("The size of the array of chord lengths or the array of airfoil NACA digits does not match the number of span points used to define the blade geometry.")
    
    #Delete any existing prop geoms
    DLUtils.DeleteMesh(propName)
	   
    #Generate Hub   
    DLUtils.DrawCylinder("Hub",hubDia,0,hubHeight,res)#use a 0.001m tolerance which we'll trim off.
    cyl = bpy.data.objects["Hub"]
    cyl.name = propName
    cyl.data.name = propName
    DLUtils.SelectOnly(propName)
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    DLUtils.MoveObject(propName,[2.0,0,0])
    
    areaArray = []
 
    #Generate vertex coordinates with twist and scale along the span        
    for i in range(0,nspan+1): 
        span = sPos[i] #i*dSpan
        if(span == 0):
            twistAngle = 0
        elif(span < bladeTransition):
             twistAngle = math.atan(pitch/(2*math.pi*span))*span/bladeTransition
        else:
            twistAngle = math.atan(pitch/(2*math.pi*span))
        
        
        #get the airfoil profile vertices
        tmpVerts = TurboMachLib.NACA4Profile(camber=NACAArray[i][0],thickness=NACAArray[i][2]*10+NACAArray[i][3],camberPos=NACAArray[i][1]*10,chord=chordArray[i],npts=npts) 
        areaArray.append(0);
        
        centerOfTwist[0] = chordArray[i]*skew[i]
        #centerOfTwist[1] = raiseFoil
        for v in range(0,len(tmpVerts)):
            
            #shift all verts for twisting
            tmpVerts[v][0] -= centerOfTwist[0]
            tmpVerts[v][1] -= centerOfTwist[1]
           
            #Twist the airfoil vertices.  First we shift them to get the desired center of rotation.
            tmpVert[0] = tmpVerts[v][0]*math.cos(twistAngle) -tmpVerts[v][1]*math.sin(twistAngle)
            tmpVert[1] = tmpVerts[v][0]*math.sin(twistAngle) +tmpVerts[v][1]*math.cos(twistAngle)
            
            #shift all verts to their proper span location in Z
            tmpVert[2] = span+0.01*bladeHeight #Shift blade by 1% of blade height to prevent poor boolean ops
             
            #append the vert to the master vertex list
            verts.append((tmpVert[0],tmpVert[1],tmpVert[2]))
     
            if(v != 0):
                dx = abs(verts[len(verts)-1][0] - verts[len(verts)-2][0])
                dy = abs(verts[len(verts)-1][1] + verts[len(verts)-2][1])/2
                areaArray[i] +=  dy*dx
                
            

    
    
    #Generate Polies from vertex IDs
    #Bottom Cap
    faces.append((0,1,npts))
    for i in range(1,npts-1):
        faces.append((i,i+1,npts+i))    
        faces.append((i,npts+i,npts+i-1))    
    
    #Middle
    nPerStage = npts*2-1
    for j in range(0,nspan):
        #Top Side
        for i in range(0,npts-1):
            faces.append((nPerStage*j+i,nPerStage*(j+1)+i,nPerStage*(j+1)+i+1))
            faces.append((nPerStage*j+i,nPerStage*(j+1)+i+1,nPerStage*j+i+1))
        
        #First strip for bottom side (hooks to verts from top side)
        faces.append((nPerStage*j,nPerStage*(j+1)+npts,nPerStage*(j+1)))
        faces.append((nPerStage*j,nPerStage*j+npts,nPerStage*(j+1)+npts))
    
        #Rest of bottom side
        for i in range(0,npts-2):
            faces.append((nPerStage*j+i+npts,nPerStage*(j+1)+i+npts+1,nPerStage*(j+1)+i+npts))
            faces.append((nPerStage*j+i+npts,nPerStage*j+i+npts+1,nPerStage*(j+1)+i+npts+1))
        
        #Back face
        faces.append((nPerStage*j+npts-1,nPerStage*(j+1)+npts-1,nPerStage*(j+1)+npts*2-2))
        faces.append((nPerStage*j+npts-1,nPerStage*(j+1)+npts*2-2,nPerStage*(j)+npts*2-2))
    
    #Top Cap
    faces.append((nPerStage*(nspan),nPerStage*(nspan)+1,nPerStage*(nspan)+npts))
    for i in range(1,npts-1):
        faces.append((nPerStage*(nspan)+i,nPerStage*(nspan)+npts+i,nPerStage*(nspan)+i+1))    
        faces.append((nPerStage*(nspan)+i,nPerStage*(nspan)+npts+i-1,nPerStage*(nspan)+npts+i))    
    
     
    #Create Blender object for the blade
    dAngle = 360.0/nBlades
    
    for i in range(0,nBlades):
        print("Draw Blade_" + str(i))
        blade = DLUtils.createMesh("Blade_"+str(i), origin, verts, [], faces)
        DLUtils.SelectOnly("Blade_"+str(i))
        bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,0.0,1.0))
        bpy.ops.transform.rotate(value=math.radians(dAngle)*i,axis=(1.0,0.0,0.0))
        
    #Union the blades to the hub
    for i in range(0,nBlades):
        print("Union: Blade_" +str(i))
        DLUtils.BooleanMesh(propName,"Blade_"+str(i),"UNION",True) 
        
    #trim the blades to hub height
    DLUtils.DrawBox("box", hubDia*1.1,hubDia*1.1,hubDia*1.1)
    DLUtils.MoveObject("box",[propDia/2+hubHeight/2+0.001,0,0])
    DLUtils.BooleanMesh(propName,"box","DIFFERENCE",True) 
    
    #cut the axle hole   
    DLUtils.DrawCylinder("hole",axleDia,0,hubHeight*2,res)
    DLUtils.SelectOnly("hole")
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    DLUtils.BooleanMesh(propName,"hole",'DIFFERENCE',True)
    
   
    #Cut room for the axle shive
    DLUtils.DrawCylinder("ShiveHole",(hubDia-axleDia)/4+axleDia,0,hubHeight/1.5,res)
    DLUtils.SelectOnly("ShiveHole")
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    DLUtils.BooleanMesh(propName,"ShiveHole",'DIFFERENCE',True)
    #DLUtils.MoveObject(propName,[2.0,0,0])
    
    #trim the blades to the proper dia
    DLUtils.DrawCylinder("BladeTrim",propDia,0,propDia,256)
    DLUtils.SelectOnly("BladeTrim")
    bpy.ops.transform.rotate(value=math.radians(90),axis=(0.0,1.0,0.0))
    DLUtils.BooleanMesh(propName,"BladeTrim",'INTERSECT',True)
    
    #done!
    print((BladeAxialStress(sPos,areaArray, 40e6, 1300,15000)))
    
    return