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 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 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()
Beispiel #4
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