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 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 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 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