Coverage for /opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/hypervehicle/hangar/refex.py: 96%

124 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-25 22:58 +0000

1import numpy as np 

2from hypervehicle import Vehicle 

3from hypervehicle.generator import Generator 

4from hypervehicle.transformations import CART3D 

5from hypervehicle.components.common import uniform_thickness_function, OgiveNose 

6from hypervehicle.components import Wing, RevolvedComponent, Fin, SweptComponent 

7from hypervehicle.geometry import Vector3, Line, Polyline, Arc, CoonsPatch, Bezier 

8from hypervehicle.geometry.geometry import ReversedPath 

9 

10 

11def leading_edge_width_function(r): 

12 temp = Bezier( 

13 [ 

14 Vector3(x=0.0, y=0.01), 

15 Vector3(x=0.5, y=0.05), 

16 Vector3(x=1.0, y=0.01), 

17 ] 

18 ) 

19 le_width = temp(r).y 

20 return le_width 

21 

22 

23class ParametricReFEX(Generator): 

24 """Parametric generator for mock-up of the DLR ReFEX. 

25 

26 Dimensions have been approximated based on vehicle's visual proportions. 

27 

28 References 

29 ---------- 

30 https://www.dlr.de/irs/en/desktopdefault.aspx/tabid-15435/ 

31 """ 

32 

33 def __init__(self, **kwargs) -> None: 

34 # STL Generation Toggles 

35 self.generate_fuselage = True 

36 self.generate_wings = True 

37 self.generate_canards = True 

38 self.generate_tail = True 

39 

40 # Inputs 

41 self.h = 0.225 # Ogive radial height (R) 

42 self.r_n = 0.075 # Nose radius 

43 self.r_o = 1.5 # Ogive radius 

44 self.L_o = 0.05 # Nose-body fairing 

45 self.L_b = 2.5 # Body length 

46 self.fin_thickness = 0.02 # Thickness of fin 

47 self.wing_length = 0.9 # Wing chord property 

48 self.wing_span = 0.35 # Wing span 

49 self.tail_height = 0.35 # Tail fin height 

50 self.tail_thickness = 0.02 # Tail fin thickness 

51 self.canard_angle = 0 # degrees 

52 

53 # Below defines axial location of canards, referenced from base of nose cone 

54 self.cannard_shift = Vector3(x=0.15, y=0) 

55 

56 # Complete initialisation 

57 super().__init__(**kwargs) 

58 

59 def create_instance(self): 

60 # Create vehicle object 

61 refex = Vehicle() 

62 refex.configure(name="ReFEX", verbosity=1) 

63 

64 # Ogive Nose 

65 # -------------------------------------- 

66 nose = OgiveNose( 

67 h=self.h, r_n=self.r_n, r_o=self.r_o, L_o=self.L_o, stl_resolution=50 

68 ) 

69 if self.generate_fuselage: 

70 refex.add_component(nose) 

71 

72 # Vehicle body 

73 # -------------------------------------- 

74 f1 = Vector3(0, self.h) - Vector3(self.L_o, 0) 

75 b00 = Vector3(0, 0) 

76 b0 = Vector3(0, f1.y) 

77 b1 = b0 - Vector3(self.L_b, 0) 

78 body_cap_line = Line(b00, b0) 

79 body_top_line = Line(b0, b1) 

80 bb0 = b1 # Bottom outside of body 

81 bb1 = Vector3(bb0.x, 0) # Body base axis point 

82 base_line = Line(bb0, bb1) 

83 

84 body_line = Polyline([body_cap_line, body_top_line, base_line]) 

85 body_fuse = RevolvedComponent(revolve_line=body_line, stl_resolution=50) 

86 

87 # Add revolved surface 

88 if self.generate_fuselage: 

89 refex.add_component(body_fuse) 

90 

91 # Cannards 

92 # -------------------------------------- 

93 # p1-----p2 

94 # \ \ 

95 # \ \ 

96 # \ \ 

97 # p0_________p3 

98 

99 fin_height = 1.3 * self.h 

100 fin_length = 1.3 * fin_height 

101 shift_in = Vector3(x=0, y=-0.02 * fin_height) 

102 

103 p0 = f1 - Vector3(x=fin_length, y=0) + shift_in + self.cannard_shift 

104 p1 = p0 + Vector3(x=0.0, y=fin_height) + shift_in 

105 p2 = p1 + Vector3(x=0.3 * fin_length, y=0) + shift_in 

106 p3 = f1 + shift_in + self.cannard_shift 

107 pivot_point = Vector3(x=0.5 * (p0.x + p3.x), y=p0.y) 

108 

109 if self.generate_canards: 

110 # Add canards 

111 for i in range(2): 

112 angle = np.deg2rad((i / 2) * 360) 

113 fin = Fin( 

114 p0=p0, 

115 p1=p1, 

116 p2=p2, 

117 p3=p3, 

118 fin_thickness=self.fin_thickness, 

119 fin_angle=angle, 

120 top_thickness_function=uniform_thickness_function( 

121 self.fin_thickness, "top" 

122 ), 

123 bot_thickness_function=uniform_thickness_function( 

124 self.fin_thickness, "bot" 

125 ), 

126 LE_wf=leading_edge_width_function, 

127 pivot_angle=np.deg2rad((-1) ** i * self.canard_angle), 

128 pivot_point=pivot_point, 

129 rudder_type="sharp", 

130 rudder_length=self.fin_thickness, 

131 stl_resolution=3, 

132 ) 

133 refex.add_component(fin) 

134 

135 # Wings 

136 # -------------------------------------- 

137 wing_thickness = 3 * self.fin_thickness 

138 flap_length = 0.1 * self.wing_length 

139 

140 A0 = Vector3(x=bb0.x + flap_length, y=0) 

141 TT = A0 + Vector3(x=self.wing_length, y=0) 

142 A1 = Vector3(x=0.5 * (A0.x + TT.x), y=0) 

143 

144 B0 = A0 + Vector3(x=0, y=self.wing_span + self.h) 

145 B1 = B0 + Vector3(x=0.5 * self.wing_length - flap_length, y=0) 

146 

147 B0B1 = Line(p0=B0, p1=B1) 

148 B1TT = Line(p0=B1, p1=TT) 

149 

150 Line_B0TT = Polyline([B0B1, B1TT]) 

151 

152 def wing2_tf_top(x, y, z=0): 

153 return Vector3(x=0, y=0, z=self.h - wing_thickness) 

154 

155 def wing2_tf_bot(x, y, z=0): 

156 return Vector3(x=0, y=0, z=self.h) 

157 

158 if self.generate_wings: 

159 wing = Wing( 

160 A0=A0, 

161 A1=A1, 

162 TT=TT, 

163 B0=B0, 

164 Line_B0TT=Line_B0TT, 

165 top_tf=wing2_tf_top, 

166 bot_tf=wing2_tf_bot, 

167 LE_wf=leading_edge_width_function, 

168 flap_length=flap_length, 

169 stl_resolution=3, 

170 ) 

171 refex.add_component(wing, reflection_axis="y") 

172 

173 # Wing-to-body transition 

174 # -------------------------------------- 

175 if self.generate_fuselage: 

176 body_transition = self._define_fuselage(x_ref=bb1.x) 

177 refex.add_component(body_transition) 

178 

179 # Tail rudder/fin 

180 # -------------------------------------- 

181 tail_length = 1.20 * self.tail_height 

182 rudder_length = self.tail_thickness 

183 shift_in = Vector3(x=0, y=-0.02 * self.tail_height) 

184 

185 t0 = bb0 + shift_in + Vector3(x=2 * rudder_length, y=0) 

186 t1 = t0 + Vector3(x=0, y=self.tail_height) + shift_in 

187 t2 = t1 + Vector3(x=0.4 * tail_length, y=0) + shift_in 

188 t3 = t0 + Vector3(x=tail_length, y=0) + shift_in 

189 

190 if self.generate_tail: 

191 # Add tail fin 

192 tail = Fin( 

193 p0=t0, 

194 p1=t1, 

195 p2=t2, 

196 p3=t3, 

197 fin_thickness=self.tail_thickness, 

198 fin_angle=np.deg2rad(-90), 

199 top_thickness_function=uniform_thickness_function( 

200 self.tail_thickness, "top" 

201 ), 

202 bot_thickness_function=uniform_thickness_function( 

203 self.tail_thickness, "bot" 

204 ), 

205 LE_wf=leading_edge_width_function, 

206 rudder_type="sharp", 

207 rudder_length=rudder_length, 

208 stl_resolution=3, 

209 ) 

210 refex.add_component(tail) 

211 

212 # Apply Cart3D transformation 

213 refex.add_vehicle_transformations(CART3D) 

214 

215 return refex 

216 

217 def _define_fuselage(self, x_ref: float): 

218 x1 = x_ref 

219 n1 = Line( 

220 p0=Vector3(x=x1, y=self.h, z=0.0), 

221 p1=Vector3(x=x1, y=self.h, z=self.h), 

222 ) 

223 s1 = Line( 

224 p0=Vector3(x=x1, y=-self.h, z=0.0), 

225 p1=Vector3(x=x1, y=-self.h, z=self.h), 

226 ) 

227 e1 = Line( 

228 p0=Vector3(x=x1, y=-self.h, z=self.h), 

229 p1=Vector3(x=x1, y=self.h, z=self.h), 

230 ) 

231 w1 = Line( 

232 p0=Vector3(x=x1, y=-self.h, z=0.0), 

233 p1=Vector3(x=x1, y=self.h, z=0.0), 

234 ) 

235 

236 cs1 = [n1, ReversedPath(e1), ReversedPath(s1), w1] 

237 

238 # x2 = -2.38 

239 x2 = x_ref + 0.9 * self.wing_length 

240 n2 = Line( 

241 p0=Vector3(x=x2, y=self.h, z=0.0), 

242 p1=Vector3(x=x2, y=self.h, z=self.h), 

243 ) 

244 s2 = Line( 

245 p0=Vector3(x=x2, y=-self.h, z=0.0), 

246 p1=Vector3(x=x2, y=-self.h, z=self.h), 

247 ) 

248 e2 = Line( 

249 p0=Vector3(x=x2, y=-self.h, z=self.h), 

250 p1=Vector3(x=x2, y=self.h, z=self.h), 

251 ) 

252 w2 = Line( 

253 p0=Vector3(x=x2, y=-self.h, z=0.0), 

254 p1=Vector3(x=x2, y=self.h, z=0.0), 

255 ) 

256 

257 cs2 = [n2, ReversedPath(e2), ReversedPath(s2), w2] 

258 

259 # x3 = -2. 

260 x3 = x_ref + 1.3 * self.wing_length 

261 centre = Vector3(x=x3, y=0, z=0) 

262 arc_s = Arc( 

263 a=Vector3(x=x3, y=-self.h, z=0), 

264 b=Vector3( 

265 x=x3, 

266 y=-self.h * np.cos(np.deg2rad(60)), 

267 z=self.h * np.sin(np.deg2rad(60)), 

268 ), 

269 c=centre, 

270 ) 

271 arc_e = Arc( 

272 a=Vector3( 

273 x=x3, 

274 y=-self.h * np.cos(np.deg2rad(60)), 

275 z=self.h * np.sin(np.deg2rad(60)), 

276 ), 

277 b=Vector3( 

278 x=x3, 

279 y=self.h * np.cos(np.deg2rad(60)), 

280 z=self.h * np.sin(np.deg2rad(60)), 

281 ), 

282 c=centre, 

283 ) 

284 arc_n = Arc( 

285 a=Vector3(x=x3, y=self.h, z=0), 

286 b=Vector3( 

287 x=x3, 

288 y=self.h * np.cos(np.deg2rad(60)), 

289 z=self.h * np.sin(np.deg2rad(60)), 

290 ), 

291 c=centre, 

292 ) 

293 west = Line(p0=arc_s.a, p1=arc_n.a) 

294 

295 cs3 = [arc_n, ReversedPath(arc_e), ReversedPath(arc_s), west] 

296 

297 sections = [cs1, cs2, cs3] 

298 body_transition = SweptComponent( 

299 cross_sections=sections, 

300 stl_resolution=20, 

301 ) 

302 return body_transition 

303 

304 

305if __name__ == "__main__": 

306 # To create the nominal geometry 

307 parametric_generator = ParametricReFEX() 

308 refex = parametric_generator.create_instance() 

309 refex.generate() 

310 refex.transform(transformations=CART3D) 

311 refex.to_stl(prefix="refex")