def walk_curve_from_front(self, curve, xstart, target_dist): #print "walk from " + str(xstart) + " dist of " + str(target_dist) n = len(curve) dist = 0 cur = ( xstart, self.simple_interp(curve, xstart) ) next_index = spline.binsearch(curve, xstart) + 1 if next_index < n: dist_to_next = self.dist_2d(cur, curve[next_index]) else: # ran out of points return cur[0] #print "idx = " + str(next_index) + " dist_to_next = " + str(dist_to_next) while dist + dist_to_next < target_dist: dist += dist_to_next cur = curve[next_index] next_index += 1 if next_index < n: dist_to_next = self.dist_2d(cur, curve[next_index]) else: # ran out of points return cur[0] rem = target_dist - dist pct = rem / dist_to_next dx = curve[next_index][0] - cur[0] return cur[0] + dx * pct
def walk_curve_from_back(self, curve, xend, target_dist): print "walk from " + str(xend) + " dist of " + str(target_dist) n = len(curve) print "curve is " + str(n) + " points" dist = 0 cur = ( xend, self.simple_interp(curve, xend) ) prior_index = spline.binsearch(curve, xend) print "prior_index = " + str(prior_index) if prior_index >= 0: dist_to_prior = self.dist_2d(cur, curve[prior_index]) else: # ran out of points return cur[0] print "idx = " + str(prior_index) + " dist_to_prior = " + str(dist_to_prior) while dist + dist_to_prior < target_dist: dist += dist_to_prior cur = curve[prior_index] prior_index -= 1 if prior_index >= 0: dist_to_prior = self.dist_2d(cur, curve[prior_index]) else: # ran out of points return cur[0] rem = target_dist - dist pct = rem / dist_to_prior dx = cur[0] - curve[prior_index][0] return cur[0] - dx * pct
def walk_curve_from_back(self, curve, xend, target_dist): print "walk from " + str(xend) + " dist of " + str(target_dist) n = len(curve) print "curve is " + str(n) + " points" dist = 0 cur = (xend, self.simple_interp(curve, xend)) prior_index = spline.binsearch(curve, xend) print "prior_index = " + str(prior_index) if prior_index >= 0: dist_to_prior = self.dist_2d(cur, curve[prior_index]) else: # ran out of points return cur[0] print "idx = " + str(prior_index) + " dist_to_prior = " + str( dist_to_prior) while dist + dist_to_prior < target_dist: dist += dist_to_prior cur = curve[prior_index] prior_index -= 1 if prior_index >= 0: dist_to_prior = self.dist_2d(cur, curve[prior_index]) else: # ran out of points return cur[0] rem = target_dist - dist pct = rem / dist_to_prior dx = cur[0] - curve[prior_index][0] return cur[0] - dx * pct
def walk_curve_from_front(self, curve, xstart, target_dist): #print "walk from " + str(xstart) + " dist of " + str(target_dist) n = len(curve) dist = 0 cur = (xstart, self.simple_interp(curve, xstart)) next_index = spline.binsearch(curve, xstart) + 1 if next_index < n: dist_to_next = self.dist_2d(cur, curve[next_index]) else: # ran out of points return cur[0] #print "idx = " + str(next_index) + " dist_to_next = " + str(dist_to_next) while dist + dist_to_next < target_dist: dist += dist_to_next cur = curve[next_index] next_index += 1 if next_index < n: dist_to_next = self.dist_2d(cur, curve[next_index]) else: # ran out of points return cur[0] rem = target_dist - dist pct = rem / dist_to_next dx = curve[next_index][0] - cur[0] return cur[0] + dx * pct
def get_slope(self, surf="top", xpos=0.0): if surf == "top": curve = list(self.top) else: curve = list(self.bottom) slopes = spline.derivative1(curve) index = spline.binsearch(curve, xpos) slope = slopes[index] return slope
def resample(self, xdivs, use_spline): self.top = [] self.bottom = [] n = len(self.parax) totaldist = self.parax[n-1][0] # print "total surface dist = " + str(totaldist) # extract the top surface step = self.nosedist / xdivs parax_y2 = spline.derivative2( self.parax ) paray_y2 = spline.derivative2( self.paray ) for i in range(0, xdivs+1): d = i * step if use_spline: index = spline.binsearch(self.parax, d) x = spline.spline(self.parax, parax_y2, index, d) y = spline.spline(self.paray, paray_y2, index, d) else: x = self.simple_interp(self.parax, d ) y = self.simple_interp(self.paray, d ) if x >= 0.0: #print str(x) + " " + str(y) self.top.append( (x, y) ) self.top.reverse() # extract the bottom surface step = (totaldist - self.nosedist) / xdivs for i in range(0, xdivs+1): d = i * step + self.nosedist if use_spline: index = spline.binsearch(self.parax, d) x = spline.spline(self.parax, parax_y2, index, d) y = spline.spline(self.paray, paray_y2, index, d) else: x = self.simple_interp(self.parax, d ) y = self.simple_interp(self.paray, d ) if x < 0.0: x = 0.0 self.bottom.append( (x, y) )
def resample(self, xdivs, use_spline): self.top = [] self.bottom = [] n = len(self.parax) totaldist = self.parax[n - 1][0] # print "total surface dist = " + str(totaldist) # extract the top surface step = self.nosedist / xdivs parax_y2 = spline.derivative2(self.parax) paray_y2 = spline.derivative2(self.paray) for i in range(0, xdivs + 1): d = i * step if use_spline: index = spline.binsearch(self.parax, d) x = spline.spline(self.parax, parax_y2, index, d) y = spline.spline(self.paray, paray_y2, index, d) else: x = self.simple_interp(self.parax, d) y = self.simple_interp(self.paray, d) if x >= 0.0: #print str(x) + " " + str(y) self.top.append((x, y)) self.top.reverse() # extract the bottom surface step = (totaldist - self.nosedist) / xdivs for i in range(0, xdivs + 1): d = i * step + self.nosedist if use_spline: index = spline.binsearch(self.parax, d) x = spline.spline(self.parax, parax_y2, index, d) y = spline.spline(self.paray, paray_y2, index, d) else: x = self.simple_interp(self.parax, d) y = self.simple_interp(self.paray, d) if x < 0.0: x = 0.0 self.bottom.append((x, y))
def simple_interp(points, v): index = spline.binsearch(points, v) n = len(points) - 1 if index < n: xrange = points[index + 1][0] - points[index][0] yrange = points[index + 1][1] - points[index][1] # print(" xrange = $xrange\n") if xrange > 0.0001: percent = (v - points[index][0]) / xrange # print(" percent = $percent\n") return points[index][1] + percent * yrange else: return points[index][1] else: return points[index][1]
def simple_interp(self, points, v): index = spline.binsearch(points, v) n = len(points) - 1 if index < n: xrange = points[index+1][0] - points[index][0] yrange = points[index+1][1] - points[index][1] # print(" xrange = $xrange\n") if xrange > 0.0001: percent = (v - points[index][0]) / xrange # print(" percent = $percent\n") return points[index][1] + percent * yrange else: return points[index][1] else: return points[index][1]
#!/usr/bin/env python try: import spline except ImportError: # if airfoil is not 'installed' append parent dir of __file__ to sys.path import sys, os sys.path.insert(0, os.path.abspath(os.path.split(os.path.abspath(__file__))[0]+'/../lib')) import spline points = ((0.0, 9.0), (5.0, 11.0), (10, 11.0), (30.0, 6.0)) y2 = spline.derivative2( points ) for x in range(0, 31, 1): index = spline.binsearch(points, x) y = spline.spline(points, y2, index, x) print str(x) + " " + str(y)
def build(self): if len(self.stations) < 2: print "Must define at least 2 stations to build a wing" return sweep_y2 = spline.derivative2( self.sweep.top ) taper_y2 = spline.derivative2( self.taper.top ) # make the base ribs at each defined station for index, station in enumerate(self.stations): percent = station / self.span # generate airfoil if not self.tip: af = self.root else: af = airfoil.blend(self.root, self.tip, percent) # compute placement parameters lat_dist = station twist = self.twist * percent # compute chord if self.taper: sp_index = spline.binsearch(self.taper.top, lat_dist) chord = spline.spline(self.taper.top, taper_y2, sp_index, lat_dist) else: print "Cannot build a wing with no chord defined!" return print "building station @ " + str(lat_dist) \ + " chord = " + str(chord) # compute sweep offset pos if a sweep function provided if self.sweep: sw_index = spline.binsearch(self.sweep.top, lat_dist) sweep_dist = spline.spline(self.sweep.top, sweep_y2, sw_index, \ lat_dist) else: sweep_dist = 0.0 # make the rib (cutouts will be handled later) label = 'WR' + str(index+1) right_rib = self.make_raw_rib(af, chord, lat_dist, sweep_dist, \ twist, label) right_rib.side = "right" if percent < 0.001: right_rib.nudge = -right_rib.thickness * 0.5 elif percent > 0.999: right_rib.nudge = right_rib.thickness * 0.5 self.right_ribs.append(right_rib) label = 'WL' + str(index+1) left_rib = self.make_raw_rib(af, chord, -lat_dist, sweep_dist, \ twist, label) left_rib.side = "left" if percent < 0.001: left_rib.nudge = right_rib.thickness * 0.5 elif percent > 0.999: left_rib.nudge = -right_rib.thickness * 0.5 self.left_ribs.append(left_rib) # make the control surface ribs. Instead of dividing the # original base ribs into two parts, we make copies of the # base ribs and then trim off the parts we don't want. This # makes a bit of sense considering we need double ribs at the # cutout edges. We do this in one pass per side, stepping # through each rib and seeing if it matches a control surface # cutout and if it's an inner, outer, or mid rib. new_ribs = [] for rib in self.right_ribs: for flap in self.flaps: if self.match_station(flap.start_station, flap.start_station, rib.pos[0]): #print "start station = " + str(rib.pos[0]) newrib = copy.deepcopy(rib) rib.nudge = rib.thickness * 0.5 newrib.nudge = -rib.thickness * 1.0 flap.start_bot_str_pos = newrib.trim_front_wedge(flap.pos, flap.angle) newrib.part = "flap" newrib.has_le = False new_ribs.append(newrib) elif self.match_station(flap.end_station, flap.end_station, rib.pos[0]): #print "end station = " + str(rib.pos[0]) newrib = copy.deepcopy(rib) rib.nudge = -rib.thickness * 0.5 newrib.nudge = rib.thickness * 1.0 flap.end_bot_str_pos = newrib.trim_front_wedge(flap.pos, flap.angle) newrib.part = "flap" newrib.has_le = False new_ribs.append(newrib) elif self.match_station(flap.start_station, flap.end_station, rib.pos[0]): #print "match flap at mid station " + str(rib.pos[0]) newrib = copy.deepcopy(rib) newrib.trim_front_wedge(flap.pos, flap.angle) newrib.part = "flap" newrib.has_le = False new_ribs.append(newrib) rib.trim_rear(flap.pos) rib.has_te = False for rib in new_ribs: self.right_ribs.append(rib) new_ribs = [] for rib in self.left_ribs: for flap in self.flaps: if self.match_station(flap.start_station, flap.start_station, rib.pos[0]): #print "start station = " + str(rib.pos[0]) newrib = copy.deepcopy(rib) rib.nudge = -rib.thickness * 0.5 newrib.nudge = rib.thickness * 1.0 flap.start_bot_str_pos = newrib.trim_front_wedge(flap.pos, flap.angle) newrib.part = "flap" newrib.has_le = False new_ribs.append(newrib) elif self.match_station(flap.end_station, flap.end_station, rib.pos[0]): #print "end station = " + str(rib.pos[0]) newrib = copy.deepcopy(rib) rib.nudge = rib.thickness * 0.5 newrib.nudge = -rib.thickness * 1.0 flap.end_bot_str_pos = newrib.trim_front_wedge(flap.pos, flap.angle) newrib.part = "flap" newrib.has_le = False new_ribs.append(newrib) elif self.match_station(flap.start_station, flap.end_station, rib.pos[0]): #print "left match flap at station " + str(rib.pos[0]) newrib = copy.deepcopy(rib) newrib.trim_front_wedge(flap.pos, flap.angle) newrib.part = "flap" newrib.has_le = False new_ribs.append(newrib) rib.trim_rear(flap.pos) rib.has_te = False #rib.contour.trim(surf="top", discard="rear", cutpos=flap.pos) #rib.contour.trim(surf="bottom", discard="rear", cutpos=flap.pos) for rib in new_ribs: self.left_ribs.append(rib) # now place the leading edge bottom stringer for each flap. # This is left until now because this can be very dynamic # depending on the wing layout and control surface blending. for flap in self.flaps: if flap.start_bot_str_pos != None and flap.end_bot_str_pos != None \ and flap.edge_stringer_size != None: xdist = flap.end_station - flap.start_station if math.fabs(xdist) > 0.0001: atstation = flap.start_station ydist = flap.end_bot_str_pos - flap.start_bot_str_pos slope = ydist / xdist half_offset = flap.edge_stringer_size[0] * 0.5 if flap.side == "left": atstation *= -1.0 slope *= -1.0 cutpos = contour.Cutpos(xpos=flap.start_bot_str_pos, \ atstation=atstation, \ slope=slope) cutpos.move(half_offset) cutout = contour.Cutout(surf="bottom", \ orientation="tangent", \ cutpos=cutpos, \ xsize=flap.edge_stringer_size[0], \ ysize=flap.edge_stringer_size[1] ) print "making bottom stringer: " + str(flap.start_station) + " - " + str(flap.end_station) stringer = Stringer( cutout, flap.start_station, flap.end_station, "flap" ) stringer.side = flap.side self.stringers.append( stringer ) else: print "skipped building a flap bottom stringer" print str(flap.start_bot_str_pos) print str(flap.end_bot_str_pos) print str(flap.edge_stringer_size) # do all the cutouts now at the end after we've made and # positioned all the ribs for the wing and the control # surfaces for rib in self.right_ribs: self.make_rib_cuts(rib) for rib in self.left_ribs: self.make_rib_cuts(rib) # a quick pass to update labels on "flap" parts after the # cutouts so there is half a chance the label ends up on the # part itself for rib in self.right_ribs: if rib.part == "flap": rib.relabel_flap() for rib in self.left_ribs: if rib.part == "flap": rib.relabel_flap()
def project_contour(self, surf="top", xstart=0, xend=None, xdist=None, ysize=0): #print "xstart=" + str(xstart) + " xend=" + str(xend) + " xdist=" + str(xdist) curve = [] #print "surf == " + surf if surf == "top": curve = list(self.top) else: curve = list(self.bottom) #print str(curve) n = len(curve) slopes = spline.derivative1(curve) shape = [] # make the exact sweep base line dist = 0.0 xpos = xstart #print 'xpos:', xpos, 'curve:', curve ypos = self.simple_interp(curve, xstart) if ypos: shape.append((xpos, ypos)) index = spline.binsearch(curve, xpos) if curve[index][0] <= xpos: index += 1 next_dist = 0 done = False #while index < n and dist + next_dist <= xdist: while index < n and not done: nextpt = curve[index] next_dist = self.dist_2d((xpos, ypos), nextpt) if (xdist and dist + next_dist <= xdist) or \ (xend and nextpt[0] <= xend): dist += next_dist xpos = nextpt[0] ypos = nextpt[1] if ypos: shape.append((xpos, ypos)) index += 1 else: done = True # add the final point of the curve (if needed) if index < n and xdist and dist < xdist: rem = xdist - dist #print "rem = " + str(rem) pct = rem / next_dist #print "pct of next step = " + str(pct) dx = nextpt[0] - xpos xpos += dx * pct ypos = self.simple_interp(curve, xpos) if ypos: shape.append((xpos, ypos)) elif index < n and xend and xpos < xend: xpos = xend ypos = self.simple_interp(curve, xpos) if ypos: shape.append((xpos, ypos)) # project the sweep line at the specified thickness result = [] #print 'shape:', shape for p in shape: index = spline.binsearch(curve, p[0]) slope = slopes[index] #print 'p:', p proj = self.project_point(p, ysize, surf, slope) result.append(proj) return result
def project_contour(self, surf="top", \ xstart=0, xend=None, xdist=None, \ ysize=0): #print "xstart=" + str(xstart) + " xend=" + str(xend) + " xdist=" + str(xdist) curve = [] #print "surf == " + surf if surf == "top": curve = list(self.top) else: curve = list(self.bottom) #print str(curve) n = len(curve) slopes = spline.derivative1(curve) shape = [] # make the exact sweep base line dist = 0.0 xpos = xstart ypos = self.simple_interp(curve, xstart) shape.append( (xpos, ypos) ) index = spline.binsearch(curve, xpos) if curve[index][0] <= xpos: index += 1 next_dist = 0 done = False #while index < n and dist + next_dist <= xdist: while index < n and not done: nextpt = curve[index] next_dist = self.dist_2d( (xpos, ypos), nextpt ) if (xdist and dist + next_dist <= xdist) or \ (xend and nextpt[0] <= xend): dist += next_dist xpos = nextpt[0] ypos = nextpt[1] shape.append( (xpos, ypos) ) index += 1 else: done = True # add the final point of the curve (if needed) if index < n and xdist and dist < xdist: rem = xdist - dist #print "rem = " + str(rem) pct = rem / next_dist #print "pct of next step = " + str(pct) dx = nextpt[0] - xpos xpos += dx * pct ypos = self.simple_interp(curve, xpos) shape.append( (xpos, ypos) ) elif index < n and xend and xpos < xend: xpos = xend ypos = self.simple_interp(curve, xpos) shape.append( (xpos, ypos) ) # project the sweep line at the specified thickness result = [] for p in shape: index = spline.binsearch(curve, p[0]) slope = slopes[index] proj = self.project_point(p, ysize, surf, slope) result.append(proj) return result
def build(self): if len(self.stations) < 2: print "Must define at least 2 stations to build a wing" return sweep_y2 = spline.derivative2(self.sweep.top) taper_y2 = spline.derivative2(self.taper.top) # make the base ribs at each defined station for index, station in enumerate(self.stations): percent = station / self.span # generate airfoil if not self.tip: af = self.root else: af = airfoil.blend(self.root, self.tip, percent) # compute placement parameters lat_dist = station twist = self.twist * percent # compute chord if self.taper: sp_index = spline.binsearch(self.taper.top, lat_dist) chord = spline.spline(self.taper.top, taper_y2, sp_index, lat_dist) else: print "Cannot build a wing with no chord defined!" return print "building station @ " + str(lat_dist) \ + " chord = " + str(chord) # compute sweep offset pos if a sweep function provided if self.sweep: sw_index = spline.binsearch(self.sweep.top, lat_dist) sweep_dist = spline.spline(self.sweep.top, sweep_y2, sw_index, lat_dist) else: sweep_dist = 0.0 # make the rib (cutouts will be handled later) label = 'WR' + str(index + 1) right_rib = self.make_raw_rib(af, chord, lat_dist, sweep_dist, twist, label) right_rib.side = "right" if percent < 0.001: right_rib.nudge = -right_rib.thickness * 0.5 elif percent > 0.999: right_rib.nudge = right_rib.thickness * 0.5 self.right_ribs.append(right_rib) label = 'WL' + str(index + 1) left_rib = self.make_raw_rib(af, chord, -lat_dist, sweep_dist, twist, label) left_rib.side = "left" if percent < 0.001: left_rib.nudge = right_rib.thickness * 0.5 elif percent > 0.999: left_rib.nudge = -right_rib.thickness * 0.5 self.left_ribs.append(left_rib) # at the ends of each control surface we need a full length # rib to cap off the space, so we need to create copies of the # ribs at these points. self.right_ribs = self.make_new_ribs_for_flaps(self.right_ribs, 'right') self.left_ribs = self.make_new_ribs_for_flaps(self.left_ribs, 'left') for rib in self.right_ribs: rib_pos = rib.pos[0] - rib.nudge for flap in self.flaps: if self.match_station(flap.start_station, flap.end_station, rib_pos): if rib.part == "flap": if rib.type == "inner": pos = rib.trim_front_wedge(flap.pos, flap.angle) flap.start_bot_str_pos = pos print "flap start bot = " + str(pos) elif rib.type == "outer": pos = rib.trim_front_wedge(flap.pos, flap.angle) flap.end_bot_str_pos = pos print "flap end bot = " + str(pos) elif rib.type == "inner-shared": #pos = rib.find_flap_bottom_front(flap.pos, flap.angle) pos = rib.trim_front_wedge(flap.pos, flap.angle) flap.start_bot_str_pos = pos print "flap start bot = " + str(pos) elif rib.type == "outer-shared": pos = rib.find_flap_bottom_front( flap.pos, flap.angle) flap.end_bot_str_pos = pos print "flap end bot = " + str(pos) else: # add cut lines rib.add_wedge_cut_lines(flap.pos, flap.angle) else: print "skipping rear trim" # rib.trim_rear(flap.pos) for rib in self.left_ribs: rib_pos = rib.pos[0] - rib.nudge for flap in self.flaps: if self.match_station(flap.start_station, flap.end_station, rib_pos): if rib.part == "flap": if rib.type == "inner": pos = rib.trim_front_wedge(flap.pos, flap.angle) flap.start_bot_str_pos = pos print "flap start bot = " + str(pos) elif rib.type == "outer": pos = rib.trim_front_wedge(flap.pos, flap.angle) flap.end_bot_str_pos = pos print "flap end bot = " + str(pos) elif rib.type == "inner-shared": pos = rib.find_flap_bottom_front( flap.pos, flap.angle) pos = rib.trim_front_wedge(flap.pos, flap.angle) flap.start_bot_str_pos = pos print "flap start bot = " + str(pos) elif rib.type == "outer-shared": pos = rib.find_flap_bottom_front( flap.pos, flap.angle) flap.end_bot_str_pos = pos print "flap end bot = " + str(pos) else: # add cut lines rib.add_wedge_cut_lines(flap.pos, flap.angle) else: print "skipping rear trim" # rib.trim_rear(flap.pos) # now place the leading edge bottom stringer for each flap. # This is left until now because this can be very dynamic # depending on the wing layout and control surface blending. for flap in self.flaps: if flap.start_bot_str_pos != None and flap.end_bot_str_pos != None \ and flap.edge_stringer_size != None: xdist = flap.end_station - flap.start_station if math.fabs(xdist) > 0.0001: atstation = flap.start_station ydist = flap.end_bot_str_pos - flap.start_bot_str_pos slope = ydist / xdist half_offset = flap.edge_stringer_size[0] * 0.5 if flap.side == "left": atstation *= -1.0 slope *= -1.0 cutpos = contour.Cutpos(xpos=flap.start_bot_str_pos, \ atstation=atstation, \ slope=slope) cutpos.move(half_offset) cutout = contour.Cutout(surf="bottom", \ orientation="tangent", \ cutpos=cutpos, \ xsize=flap.edge_stringer_size[0], \ ysize=flap.edge_stringer_size[1] ) print "making bottom stringer: " + str( flap.start_station) + " - " + str(flap.end_station) stringer = Stringer(cutout, flap.start_station, flap.end_station, "flap") stringer.side = flap.side self.stringers.append(stringer) else: print "skipped building a flap bottom stringer" print str(flap.start_bot_str_pos) print str(flap.end_bot_str_pos) print str(flap.edge_stringer_size) # do all the cutouts now at the end after we've made and # positioned all the ribs for the wing and the control # surfaces for rib in self.right_ribs: self.make_rib_cuts(rib) for rib in self.left_ribs: self.make_rib_cuts(rib) # a quick pass to update labels on "flap" parts after the # cutouts so there is half a chance the label ends up on the # part itself for rib in self.right_ribs: if rib.part == "flap": rib.relabel_flap() for rib in self.left_ribs: if rib.part == "flap": rib.relabel_flap()