Coverage for /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/hypervehicle/hangar/d21.py: 95%
102 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 scipy.optimize import bisect
4from hypervehicle.generator import Generator
5from hypervehicle.components import Wing, Fin, RevolvedComponent
6from hypervehicle.geometry import Vector3, Bezier, Line, Polyline
9class ParametricD21(Generator):
10 """Parametric generator for mock-up of the Lockheed D-21 drone.
12 Dimensions have been approximated based on vehicle's visual proportions.
14 References
15 ----------
16 https://en.wikipedia.org/wiki/Lockheed_D-21
17 """
19 def __init__(self, **kwargs) -> None:
20 # Vehicle parameters
21 self.R_b = 1 # Body radius
22 self.L_b = 20 # Body length
23 self.L_w = 16 # Wing length
24 self.W_w = 5 # Wing width,
25 self.flap_angle = 0
27 # STL resolutions
28 self.wing_stl_res = 3
29 self.te_fin_stl_res = 3
31 # Complete instantiation
32 super().__init__(**kwargs)
34 def create_instance(self) -> Vehicle:
35 # Initialise
36 d21 = Vehicle()
37 d21.configure(
38 name="Lockhead Martin D-21",
39 verbosity=1,
40 )
42 # Construct fuselage
43 # ------------------------
44 n = Vector3(x=0, y=0)
45 b0 = Vector3(x=0, y=self.R_b)
46 b1 = b0 - Vector3(x=self.L_b, y=0)
47 b2 = b1 - Vector3(x=0, y=self.R_b)
48 bL0 = Line(n, b0)
49 bL1 = Line(b0, b1)
50 bL2 = Line(b1, b2)
52 fuseline = Polyline([bL0, bL1, bL2])
53 fuselage = RevolvedComponent(revolve_line=fuseline, stl_resolution=20)
54 d21.add_component(fuselage)
56 # Construct Aerospike nose
57 # --------------------------
58 shift = Vector3(x=-0.1, y=0.0)
59 tip = Vector3(x=0.15 * self.L_b, y=0) + shift
60 top = Vector3(x=0.0, y=1 * self.R_b) + shift
61 mid_cp = Vector3(x=0.0, y=0.3 * self.R_b) + shift
63 front_bz = Bezier([tip, mid_cp, top])
64 back_cap = Line(p0=top, p1=Vector3(x=-0.5, y=0.0) + shift)
66 noseline = Polyline([front_bz, back_cap])
67 nose = RevolvedComponent(revolve_line=noseline, stl_resolution=20)
68 d21.add_component(nose)
70 # Construct wings
71 # ------------------------
72 # --- |---B0------________________B1
73 # | | | ----____
74 # | | | ----_____
75 # | | | --____B2
76 # --- |---A0----------------------A1----------------------TT
77 #
78 # |------------------- L_w ---------------------|
80 wing_thickness = 0.15 * self.R_b
81 wing_span = self.W_w
82 flap_length = 0.1 * self.L_w
83 wing_LE_shift = Vector3(x=0.3, y=0)
85 # Required points
86 wing_tip = Vector3(x=0.0, y=0.0) # Tip of wing reference point
87 A0 = wing_tip - Vector3(x=self.L_w, y=0)
88 A1 = Vector3(x=A0.x + 0.6 * self.L_w, y=0)
89 TT = Vector3(x=A0.x + self.L_w, y=0) - wing_LE_shift
90 B0 = Vector3(x=A0.x, y=wing_span)
92 # Construction points
93 B1 = Vector3(x=A1.x, y=0.5 * B0.y)
94 B2 = Vector3(x=TT.x, y=0.15 * wing_span)
96 # Leading edge line
97 B0B1 = Line(p0=B0, p1=B1)
98 # B1B2 = Line(p0=B1, p1=B2)
100 # Create Bezier for front edge
101 a = B1
102 b = Vector3(x=0.5 * (B1.x + B2.x), y=B1.y)
103 c = B2
104 B1B2 = Bezier([a, b, c])
106 B2TT = Line(p0=B2, p1=TT)
107 Line_B0TT = Polyline([B0B1, B1B2, B2TT])
109 def local_ws(x):
110 """Calculates the local wingspan."""
111 func = lambda t: Line_B0TT(t).x - x
112 t = bisect(func, 0.0, 1.0)
113 return Line_B0TT(t).y
115 def wing_tf_top(x, y, z=0):
116 # Get the local wingspan
117 lws = local_ws(x)
118 if lws == 0:
119 lws = 1e-3
121 # Define a thickness scalar which
122 thickener = 0.5 * (1 - y / lws)
124 return Vector3(x=0, y=0, z=-wing_thickness / 2 - thickener)
126 def wing_tf_bot(x, y, z=0):
127 return Vector3(x=0, y=0, z=wing_thickness / 2)
129 wing = Wing(
130 A0=A0,
131 A1=A1,
132 TT=TT,
133 B0=B0,
134 Line_B0TT=Line_B0TT,
135 top_tf=wing_tf_top,
136 bot_tf=wing_tf_bot,
137 flap_length=flap_length,
138 flap_angle=np.deg2rad(self.flap_angle),
139 stl_resolution=self.wing_stl_res,
140 )
141 d21.add_component(wing, reflection_axis="y")
143 # Construct tail
144 # ------------------------
145 # |--p1-----p2
146 # | | \
147 # | | \
148 # | | \
149 # |--p0______________p3
151 fin_height = 0.15 * self.W_w
152 fin_thickness = wing_thickness
153 fin_length = self.L_b - self.L_w
155 p0 = b2
156 p1 = p0 + Vector3(x=0, y=fin_height)
157 p2 = p1 + Vector3(x=0.4 * fin_length, y=0)
158 p3 = p0 + Vector3(x=fin_length, y=0)
160 # Thickness functions
161 def fin_thickness_function_top(x, y, z=0):
162 return Vector3(x=0.0, y=0.0, z=-fin_thickness / 2)
164 def fin_thickness_function_bot(x, y, z=0):
165 return Vector3(x=0.0, y=0.0, z=fin_thickness / 2)
167 offset_func = lambda x, y, z: Vector3(x=0, y=0, z=-0.95 * self.R_b)
168 tail = Fin(
169 p0=p0,
170 p1=p1,
171 p2=p2,
172 p3=p3,
173 offset_func=offset_func,
174 fin_thickness=fin_thickness,
175 fin_angle=np.deg2rad(-90),
176 top_thickness_function=fin_thickness_function_top,
177 bot_thickness_function=fin_thickness_function_bot,
178 stl_resolution=self.te_fin_stl_res,
179 )
180 d21.add_component(tail)
182 # Construct trailing wings
183 # ------------------------
184 # Straight wings at base of vehicle
185 # Construct as rectangle fins
186 fin_height = 0.45 * self.W_w
187 fin_thickness = wing_thickness
188 fin_length = 1.3 * (self.L_b - self.L_w)
190 te_wing_o = b2
191 p0 = te_wing_o
192 p1 = p0 + Vector3(x=0, y=fin_height)
193 p2 = p1 + Vector3(x=fin_length, y=0)
194 p3 = p0 + Vector3(x=fin_length, y=0)
196 tew1 = Fin(
197 p0=p0,
198 p1=p1,
199 p2=p2,
200 p3=p3,
201 fin_thickness=fin_thickness,
202 fin_angle=np.deg2rad(0),
203 top_thickness_function=fin_thickness_function_top,
204 bot_thickness_function=fin_thickness_function_bot,
205 stl_resolution=self.te_fin_stl_res,
206 )
207 d21.add_component(tew1)
209 tew2 = Fin(
210 p0=p0,
211 p1=p1,
212 p2=p2,
213 p3=p3,
214 fin_thickness=fin_thickness,
215 fin_angle=np.deg2rad(180),
216 top_thickness_function=fin_thickness_function_top,
217 bot_thickness_function=fin_thickness_function_bot,
218 stl_resolution=self.te_fin_stl_res,
219 )
220 d21.add_component(tew2)
222 return d21
225if __name__ == "__main__":
226 # To create the nominal geometry
227 parametric_generator = ParametricD21()
228 d21 = parametric_generator.create_instance()
229 d21.generate()
230 d21.to_stl("d21")