Coverage for /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/hypervehicle/hangar/refex.py: 96%
124 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-29 02:51 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-29 02:51 +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
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
23class ParametricReFEX(Generator):
24 """Parametric generator for mock-up of the DLR ReFEX.
26 Dimensions have been approximated based on vehicle's visual proportions.
28 References
29 ----------
30 https://www.dlr.de/irs/en/desktopdefault.aspx/tabid-15435/
31 """
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
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
53 # Below defines axial location of canards, referenced from base of nose cone
54 self.cannard_shift = Vector3(x=0.15, y=0)
56 # Complete initialisation
57 super().__init__(**kwargs)
59 def create_instance(self):
60 # Create vehicle object
61 refex = Vehicle()
62 refex.configure(name="ReFEX", verbosity=1)
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)
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)
84 body_line = Polyline([body_cap_line, body_top_line, base_line])
85 body_fuse = RevolvedComponent(revolve_line=body_line, stl_resolution=50)
87 # Add revolved surface
88 if self.generate_fuselage:
89 refex.add_component(body_fuse)
91 # Cannards
92 # --------------------------------------
93 # p1-----p2
94 # \ \
95 # \ \
96 # \ \
97 # p0_________p3
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)
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)
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)
135 # Wings
136 # --------------------------------------
137 wing_thickness = 3 * self.fin_thickness
138 flap_length = 0.1 * self.wing_length
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)
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)
147 B0B1 = Line(p0=B0, p1=B1)
148 B1TT = Line(p0=B1, p1=TT)
150 Line_B0TT = Polyline([B0B1, B1TT])
152 def wing2_tf_top(x, y, z=0):
153 return Vector3(x=0, y=0, z=self.h - wing_thickness)
155 def wing2_tf_bot(x, y, z=0):
156 return Vector3(x=0, y=0, z=self.h)
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")
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)
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)
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
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)
212 # Apply Cart3D transformation
213 refex.add_vehicle_transformations(CART3D)
215 return refex
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 )
236 cs1 = [n1, ReversedPath(e1), ReversedPath(s1), w1]
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 )
257 cs2 = [n2, ReversedPath(e2), ReversedPath(s2), w2]
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)
295 cs3 = [arc_n, ReversedPath(arc_e), ReversedPath(arc_s), west]
297 sections = [cs1, cs2, cs3]
298 body_transition = SweptComponent(
299 cross_sections=sections,
300 stl_resolution=20,
301 )
302 return body_transition
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")