Coverage for /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/hypervehicle/hangar/hifire8.py: 96%
108 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.geometry import Vector3, Line, Polyline, Bezier
5from hypervehicle.components import (
6 Wing,
7 Fin,
8 RevolvedComponent,
9 CompositeComponent,
10 common,
11)
14def leading_edge_width_function(r):
15 temp = Bezier(
16 [
17 Vector3(x=0.0, y=0.01),
18 Vector3(x=0.5, y=0.1),
19 Vector3(x=1.0, y=0.01),
20 ]
21 )
22 le_width = temp(r).y
23 return le_width
26class ParametricHIFiRE8(Generator):
27 """Parametric generator for mock-up of the HIFiRE 8.
29 Dimensions have been approximated based on vehicle's visual proportions.
30 """
32 def __init__(self, **kwargs) -> None:
33 # Vehicle parameters
34 self.L = 1.2
35 self.R_base = 0.175
36 self.R_nose = 0.1
37 self.nozzle_length = 0.1
39 # Complete instantiation
40 super().__init__(**kwargs)
42 def create_instance(self) -> Vehicle:
43 # Instantiate hypervehicle and add all components
44 hifire8 = Vehicle()
45 hifire8.configure(
46 name="HIFiRE-8",
47 verbosity=1,
48 )
50 # Construct fuselage
51 # ====================
53 fuse_slope = np.arctan((self.R_base - self.R_nose) / self.L)
55 Xn = self.L
56 X1 = 1 * self.L
57 X2 = 0.0
58 X3 = -self.nozzle_length # Nozzle length
60 Rn = self.R_nose
61 R1 = self.R_base - X1 * np.tan(fuse_slope)
62 R2 = self.R_base - X2 * np.tan(fuse_slope)
63 R3 = R2 # R_base - X3*np.tan(fuse_slope)
65 fuse_line = Polyline(
66 [
67 Line(p0=Vector3(X1, R1), p1=Vector3(X2, R2)),
68 Line(p0=Vector3(X2, R2), p1=Vector3(X3, R3)),
69 Line(p0=Vector3(X3, R3), p1=Vector3(X3, 0)),
70 ]
71 )
72 fuselage_0 = RevolvedComponent(fuse_line)
74 fuse_base_line = Line(p0=Vector3(X1, 0), p1=Vector3(X1, R1))
75 fuselage_1 = RevolvedComponent(fuse_base_line)
77 # Create composite component for fuselage
78 fuselage = CompositeComponent(stl_resolution=8)
79 fuselage.add_component(fuselage_0)
80 fuselage.add_component(fuselage_1)
82 # Construct fins
83 # ====================
84 # |--p1-----p2
85 # | | \
86 # | | \
87 # | | \
88 # |--p0______________p3
90 fin_length = 0.4 # length from p0 to p3
91 fin_height = 0.4 * fin_length
92 fin_thickness = 0.02 * fin_length
93 fin_angle = np.deg2rad(90 - 45)
95 def eval_r_at_x(x):
96 """Returns the R value at a given x."""
97 return self.R_base - x * np.tan(fuse_slope)
99 p0 = Vector3(x=0, y=eval_r_at_x(0))
100 p1 = Vector3(x=0.2 * fin_length, y=eval_r_at_x(0.2 * fin_length) + fin_height)
101 p2 = Vector3(x=0.7 * fin_length, y=eval_r_at_x(0.7 * fin_length) + fin_height)
102 p3 = Vector3(x=fin_length, y=eval_r_at_x(fin_length))
104 fin1 = Fin(
105 p0=p0,
106 p1=p1,
107 p2=p2,
108 p3=p3,
109 fin_thickness=fin_thickness,
110 fin_angle=fin_angle,
111 top_thickness_function=common.uniform_thickness_function(
112 fin_thickness, "top"
113 ),
114 bot_thickness_function=common.uniform_thickness_function(
115 fin_thickness, "bot"
116 ),
117 LE_wf=leading_edge_width_function,
118 mirror=False,
119 stl_resolution=3,
120 )
122 # Copy for second fin
123 fin2 = Fin(
124 p0=p0,
125 p1=p1,
126 p2=p2,
127 p3=p3,
128 fin_thickness=fin_thickness,
129 fin_angle=fin_angle + np.deg2rad(90),
130 top_thickness_function=common.uniform_thickness_function(
131 fin_thickness, "top"
132 ),
133 bot_thickness_function=common.uniform_thickness_function(
134 fin_thickness, "bot"
135 ),
136 LE_wf=leading_edge_width_function,
137 mirror=False,
138 stl_resolution=3,
139 )
141 # Copy for third fin - this should be improved. Maybe
142 # make a fin geom func and modify fin height
143 fin3 = Fin(
144 p0=p0,
145 p1=0.5 * p1,
146 p2=0.5 * p2,
147 p3=p3,
148 fin_thickness=fin_thickness,
149 fin_angle=np.deg2rad(-90),
150 top_thickness_function=common.uniform_thickness_function(
151 fin_thickness, "top"
152 ),
153 bot_thickness_function=common.uniform_thickness_function(
154 fin_thickness, "bot"
155 ),
156 LE_wf=leading_edge_width_function,
157 mirror=False,
158 stl_resolution=3,
159 )
161 # Construct wing
162 # ====================
164 # |---B0-------B1__
165 # | | ----____
166 # | | ----_____
167 # | | B2-----------____B3
168 # |---A0-----------------------------A1---------------TT
169 #
170 # |------------------- wing_L ---------------------|
172 wing_L = 1.3
173 wing_thickness = 0.04
174 wing_width = 0.4
175 wing_origin = 0.2
176 flap_length = 0.2
178 # Required points
179 A0 = Vector3(x=wing_origin, y=0)
180 A1 = Vector3(x=A0.x + 0.5 * wing_L, y=0)
181 TT = Vector3(x=A0.x + wing_L, y=0)
182 B0 = Vector3(x=A0.x, y=wing_width)
184 # Construction points
185 B1 = Vector3(x=A0.x + 0.1 * wing_L, y=B0.y)
186 B2 = Vector3(x=A1.x, y=0.5 * wing_width)
187 B3 = Vector3(x=TT.x, y=0.13 * wing_width)
189 # Leading edge line
190 B0B1 = Line(p0=B0, p1=B1)
191 B1B2 = Line(p0=B1, p1=B2)
192 B2B3 = Line(p0=B2, p1=B3)
193 B3TT = Line(p0=B3, p1=TT)
194 Line_B0TT = Polyline([B0B1, B1B2, B2B3, B3TT])
196 wing = Wing(
197 A0=A0,
198 A1=A1,
199 TT=TT,
200 B0=B0,
201 Line_B0TT=Line_B0TT,
202 top_tf=common.uniform_thickness_function(wing_thickness, "top"),
203 bot_tf=common.uniform_thickness_function(wing_thickness, "bot"),
204 LE_wf=leading_edge_width_function,
205 flap_length=flap_length,
206 stl_resolution=4,
207 )
209 # Construct nose cap
210 # ====================
211 L_n = 0.5
212 r_b = eval_r_at_x(Xn)
213 t_n = 0.005
214 w_n = 0.15
216 # Side width angle
217 side_theta = np.arctan((r_b - 0.5 * w_n) / L_n)
219 # Points
220 A0n = Vector3(x=Xn, y=0)
221 A1n = Vector3(x=Xn + 0.5 * L_n, y=0)
222 TTn = Vector3(x=Xn + L_n, y=0)
224 B0n = Vector3(x=A0n.x, y=r_b)
225 B1n = Vector3(x=A1n.x, y=r_b - (A1n.x - Xn) * np.tan(side_theta))
226 B2n = Vector3(x=TTn.x, y=0.5 * w_n)
228 B0B1n = Line(p0=B0n, p1=B1n)
229 B1B2n = Line(p0=B1n, p1=B2n)
230 B2TTn = Line(p0=B2n, p1=TTn)
232 Line_B0TTn = Polyline([B0B1n, B1B2n, B2TTn])
234 def nose_tf_top(x, y, z=0):
235 # Calculate function weightings for linear blending
236 circular_weighting = 1 - (1 / L_n) * (x - Xn)
237 flat_weighting = 1 - circular_weighting
239 # Calculate functions at x
240 z_circle = np.sqrt(r_b**2 - y**2)
241 z_flat = t_n
242 # z_flat = t_n*np.sqrt(w_n - y**2)
244 # Weighted sum of function contributions
245 z = circular_weighting * z_circle + flat_weighting * z_flat
246 # z = t_n
247 return Vector3(x=0, y=0, z=-z)
249 def nose_tf_bot(x, y, z=0):
250 # Calculate function weightings for linear blending
251 circular_weighting = 1 - (1 / L_n) * (x - Xn)
252 flat_weighting = 1 - circular_weighting
254 # Calculate functions at x
255 z_circle = np.sqrt(r_b**2 - y**2)
256 z_flat = t_n
257 # z_flat = np.sqrt(w_n - y**2)
259 # Weighted sum of function contributions
260 z = circular_weighting * z_circle + flat_weighting * z_flat
261 # z = t_n
262 return Vector3(x=0, y=0, z=z)
264 nose = Wing(
265 A0=A0n,
266 A1=A1n,
267 TT=TTn,
268 B0=B0n,
269 Line_B0TT=Line_B0TTn,
270 top_tf=nose_tf_top,
271 bot_tf=nose_tf_bot,
272 LE_wf=leading_edge_width_function,
273 LE_type="FLAT",
274 stl_resolution=4,
275 )
277 # Add components
278 hifire8.add_component(fuselage, name="fuselage")
279 hifire8.add_component(wing, reflection_axis="y", name="wing")
280 hifire8.add_component(nose, reflection_axis="y", name="nose")
281 hifire8.add_component(fin1, name="fin1")
282 hifire8.add_component(fin2, name="fin2")
283 hifire8.add_component(fin3, name="fin3")
285 return hifire8
288if __name__ == "__main__":
289 # To create the nominal geometry
290 parametric_generator = ParametricHIFiRE8()
291 hifire8 = parametric_generator.create_instance()
292 hifire8.generate()
293 hifire8.to_stl()