Foil Design ProjectΒΆ
Project to extend a (hydro-) foil profile over a wing span outline.
#from __future__ import unicode_literals
from FreeCAD import Vector
import Draft # for Draft.makeWire
import Part, math
import os
class foil():
class profile():
def __init__(self, profileDAT, doc = None, source = None):
self.profileDAT = profileDAT
self.doc = doc
self.source = source
class LeadTrail():
def __init__(self, leadingEdge, trailingEdge, doc = None, source = None):
self.leadingEdge = leadingEdge
self.trailingEdge = trailingEdge
self.doc = doc
self.source = source
class construction():
def __init__(self, profileList, rotation, leadingEdgeBspline, tailingEdgeBspline):
self.profileList = profileList
self.rotation = rotation
self.leadingEdgeBspline = leadingEdgeBspline
self.tailingEdgeBspline = tailingEdgeBspline
def __init__(self, file_profile = None, file_LeadTrail = None,
profile = None, LeadTrail = None, foil = None, maxDegree=1):
"""
Define a foil object with source file and construction information.
The init method can specify source files file_profile, file_LeadTrail
in which case they are loaded then constuction and foil are calculated.
Otherwise ...
"""
# if not (-90 <= lat <= 90):
# raise ValueError("must have -90 <= latitude <= 90")
if file_profile is not None:
self.loadProfileDAT(file_profile)
else:
self.profile = profile #CLASS IS NOT EXTERNAL
#self.profile(profileDAT, doc = profile_doc, source = file_profile)
if file_LeadTrail is not None:
self.loadLeadTrail(file_LeadTrail)
else:
self.profile = profile #CLASS IS NOT EXTERNAL
#self.LeadTrail= self.LeadTrail(leadingEdge, trailingEdge,
# doc = LeadTrail_doc, source = file_LeadTrail)
# Tried to use Part.BSplineCurve on the LeadingEdge and then makePipeShell
# self.foil = Part.Wire(
# self.construction.leadingEdgeBspline).makePipeShell(
# self.construction.profileList, True, False) #makeSolid, isFrenet)
# but it gives twists and ripples in the trailing edge.
# Just lofting the profiles seems to work better.
#print("making traj wire.")
#traj = Part.BSplineCurve()
#traj.interpolate(self.LeadTrail.leadingEdge)
#leadingEdgeBspline = Part.Wire(traj.toShape())
def scaledBspline(dat, sc):
z = [Vector(v[0]*sc, v[1]*sc, v[2]*sc) for v in dat]
prof=Part.BSplineCurve()
prof.interpolate(z)
prof=Part.Wire(prof.toShape())
return prof
print("calculating aprox. tangent (rotation) of the leading edge.")
#angle adjustment Position is at leadingEndge rotate around cord.
# The angle from X-Y plane determined by angle between tangent to
# leadingEdgeBspline and Z axis
# this should really be the projection of the tangent onto the
# plane defined by the cord being its normal. but for foils with the
# cord aproximately in the direction of the X axis this will be aprox Dy/Dz.
# Ends are one-sided tangent aprox, interior points use two adjacent
Z = Vector(0, 0, 1)
e = self.LeadTrail.leadingEdge
ln = len(e)
rotation = [ Z.getAngle(e[1] - e[0])*180/math.pi ]
for i in range(ln - 2):
rotation.append(Z.getAngle(e[i+2] - e[i])*180/math.pi)
rotation.append(Z.getAngle(e[ln-1] - e[ln-2])*180/math.pi)
print("building profileList.")
profileList = []
for ld, tr, r in zip(self.LeadTrail.leadingEdge,
self.LeadTrail.trailingEdge, rotation):
# zero case at tip cause scaling and rotation problems
sc = ld.distanceToPoint(tr)
if sc < 1e-2 :
sc = 1e-2
r = 0.0
p = scaledBspline(self.profile.profileDAT, sc)
print("scaled profile " + str(sc))
p.translate(Vector(ld))
#angle adjustment
# ld - tr or tr - ld reverse rotationBase.
#FreeCADError: Unknown C++ exception
print("ld, tr - ld, -r " + str(ld) + "," + str(tr - ld) + "," + str(-r))
if (r != 0.0 ): p.rotate(ld, tr - ld, -r)
profileList.append(p)
print("rotated profile " + str(sc))
print("making EdgeBsplines.")
tj = Part.BSplineCurve()
tj.interpolate(self.LeadTrail.leadingEdge)
leadingEdgeBspline = Part.Wire(tj.toShape())
tj = Part.BSplineCurve()
tj.interpolate(self.LeadTrail.trailingEdge)
trailingEdgeBspline = Part.Wire(tj.toShape())
self.construction = self.construction(profileList, rotation,
leadingEdgeBspline, trailingEdgeBspline)
print("making foil.")
# Part.makeLoft(profileList, solid, ruled, closed, maxDegree)
# The default maxDegree 5, and even 3, puts extra wabbles in straight edges,
# unless there are many profiles. 1 seems enough for simple foil shapes.
# It could be increased or made a parameter for more twisted shapes.
self.foil = Part.makeLoft(profileList, True, False, False, maxDegree)
def foil(self) :
"""Extract the foil FreeCAD object."""
return(self.foil)
def profileDAT(self) :
"""Extract profileDAT."""
return(self.profile.profileDAT)
def profileList(self) :
"""Extract profileList."""
return(self.construction.profileList)
def rotation(self) :
"""Extract rotation."""
return(self.construction.rotation)
def leadingEdgeBspline(self) :
"""Extract leadingEdgeBspline."""
return(self.construction.leadingEdgeBspline)
def trailingEdgeBspline(self) :
"""Extract trailingEdgeBspline."""
return(self.construction.trailingEdgeBspline)
def showProfiles(self) :
"""FreeCAD plot of profileList."""
for p in self.construction.profileList: Part.show(p)
return None
def showfoil(self) :
"""FreeCAD plot of foil."""
Part.show(self.foil)
return None
def showfoil2(self) :
"""FreeCAD plot of foil."""
Part.show(self.foil2)
return None
def show(self) :
"""FreeCAD plot of foil, spline, and profiles."""
self.showProfiles()
self.showfoil()
return None
def loadProfileDAT(self, source):
"""read profile from a dat file and return it."""
doc = []
profileDAT = []
Z = 0.0
print("loading profile.")
with open(source) as f:
for i in f.readlines():
ln = i.split()
ln = [b.strip() for b in ln]
#print(ln)
try :
X = float(ln[0])
Y = float(ln[1])
#print(X, Y)
profileDAT.append(Vector(X, Y, Z))
except :
doc.append(ln)
self.profile = self.profile(profileDAT, doc=doc, source=source)
def loadLeadTrail(self, source="test.sweepPath"):
"""read Lead and Trailing edge data from file and return it."""
doc = []
leadingEdge = []
trailingEdge = []
print("loading leading and trailing edges.")
with open(source) as f:
for i in f.readlines():
ln = i.split()
ln = [b.strip() for b in ln]
#print(ln)
try :
X = float(ln[0])
Y = float(ln[1])
Z = float(ln[2])
leadingEdge.append(Vector(X, Y, Z))
X = float(ln[3])
Y = float(ln[4])
Z = float(ln[5])
trailingEdge.append(Vector(X, Y, Z))
except :
doc.append(ln)
self.LeadTrail = self.LeadTrail(leadingEdge,trailingEdge, doc=doc, source=source)
BREAK THE NEXT UP INTO PIECES AND CLEAN UP.
SRC = 'source/Projects/foil/'
z = foil(file_profile = SRC + "H105Coord.dat",
file_LeadTrail = SRC + "test.sweepPath")
z.show()
#z.showfoil()
#z.showProfiles()
#z.showBspline()
z2 = foil(file_profile = SRC + "H105Coord.dat",
file_LeadTrail = SRC + "test2.sweepPath")
z2.show()
z3 = foil(file_profile = SRC + "H105Coord.dat",
file_LeadTrail = SRC + "test3.sweepPath",
maxDegree=3)
z3.show()
# intersection of line and a plane
Z = Vector( 0, 0, 1)
p1 = Vector( 100, 0, 1)
p2 = Vector(0, 100, 1)
p3 = Vector(-100, 0, 1)
p4 = Vector(0, -100, 1)
# p is a surface (plane but bounded by points p*) because face=True
p = Draft.makeWire([p1, p2, p3, p4], closed=True, face = True)
zzz = Part.makeLine(Vector(1,0, 0), Vector(1,0, 10))
dist,point,geom=zzz.distToShape(p.Shape)
dist
point
geom
# project vector onto spline
Z = Vector( 0, 0, 1)
sp = z3.leadingEdgeBspline()
# CLEAN THIS UP
# no zzz = Z.project(sp)
zzzz = sp.project(Z)
sp = z3.leadingEdgeBspline()
zd = sp.discretize(20)
loading profile.
loading leading and trailing edges.
calculating aprox. tangent (rotation) of the leading edge.
building profileList.
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 0.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 3.0),Vector (2.0, 0.0, 0.0),-5.7105931375
rotated profile 2.0
scaled profile 1.0
ld, tr - ld, -r Vector (0.5, 0.0, 5.0),Vector (1.0, 0.0, 0.0),-20.5560452196
rotated profile 1.0
scaled profile 0.01
ld, tr - ld, -r Vector (1.5, 0.0, 7.0),Vector (0.0, 0.0, 0.0),-0.0
rotated profile 0.01
making EdgeBsplines.
making foil.
loading profile.
loading leading and trailing edges.
calculating aprox. tangent (rotation) of the leading edge.
building profileList.
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 0.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 3.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 4.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 5.0),Vector (2.0, 0.0, 0.0),-5.7105931375
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.2, 6.0),Vector (2.0, 0.0, 0.0),-14.0362434679
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.5, 7.0),Vector (2.0, 0.0, 0.0),-16.699244234
rotated profile 2.0
making EdgeBsplines.
making foil.
loading profile.
loading leading and trailing edges.
calculating aprox. tangent (rotation) of the leading edge.
building profileList.
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 0.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 1.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 2.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 3.0),Vector (2.0, 0.0, 0.0),-0.0
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.0, 4.0),Vector (2.0, 0.0, 0.0),-2.86240522611
rotated profile 2.0
scaled profile 2.0
ld, tr - ld, -r Vector (0.0, 0.1, 5.0),Vector (2.0, 0.0, 0.0),-16.2539170582
rotated profile 2.0
scaled profile 1.7
ld, tr - ld, -r Vector (0.3, 0.5, 6.0),Vector (1.7, 0.0, 0.0),-35.3242998776
rotated profile 1.7
scaled profile 1.3
ld, tr - ld, -r Vector (0.7, 0.9, 6.5),Vector (1.3, 0.0, 0.0),-68.3222184824
rotated profile 1.3
scaled profile 0.05
ld, tr - ld, -r Vector (1.9, 1.5, 6.75),Vector (0.050000000000000044, 0.0, 0.0),-79.4446195339
rotated profile 0.05
making EdgeBsplines.
making foil.
NOT SURE WHY NEXT IS HERE.
def tube(r, w, h, a ):
'''
Generate a (partial) tube with
r outside radius
w wall thickness
h length (height)
a angle of sweep (360 is full circle)
e.g.
b = tube(6, 2, 10, 90)
'''
b = Part.makeCylinder(r, h, Vector(0,0,0), Vector(0,0,1), a)
b = b.cut(Part.makeCylinder(r-w, h, Vector(0,0,0), Vector(0,0,1), a))
return(b)
PUT SOME TEXT IN HERE SOMEWHERE