Skip to content

Commit 8f67b31

Browse files
ENH: Rocket.draw() initial commit
1 parent 711b9b3 commit 8f67b31

1 file changed

Lines changed: 177 additions & 1 deletion

File tree

rocketpy/plots/rocket_plots.py

Lines changed: 177 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import matplotlib.pyplot as plt
2-
import numpy as np
2+
3+
from rocketpy.rocket.aero_surface import Fins, NoseCone, Tail
34

45

56
class _RocketPlots:
@@ -104,6 +105,181 @@ def thrust_to_weight(self):
104105

105106
return None
106107

108+
def draw(self, vis_args=None):
109+
"""Draws the rocket in a matplotlib figure.
110+
111+
Parameters
112+
----------
113+
vis_args : dict, optional
114+
Determines the visual aspects when drawing the rocket. If None,
115+
default values are used. Default values are:
116+
{
117+
"background": "#EEEEEE",
118+
"tail": "black",
119+
"nose": "black",
120+
"body": "dimgrey",
121+
"fins": "black",
122+
"motor": "black",
123+
"buttons": "black",
124+
"line_width": 2.0,
125+
}
126+
A full list of color names can be found at:
127+
https://matplotlib.org/stable/gallery/color/named_colors
128+
"""
129+
if vis_args is None:
130+
vis_args = {
131+
"background": "#EEEEEE",
132+
"tail": "black",
133+
"nose": "black",
134+
"body": "dimgrey",
135+
"fins": "black",
136+
"motor": "black",
137+
"buttons": "black",
138+
"line_width": 2.0,
139+
}
140+
141+
# Create the figure and axis
142+
_, ax = plt.subplots(figsize=(10, 5))
143+
ax.set_aspect("equal")
144+
ax.set_facecolor(vis_args["background"])
145+
ax.grid(True, linestyle="--", linewidth=0.5)
146+
147+
csys = self.rocket._csys
148+
149+
# Draw rocket body
150+
reverse = csys == 1
151+
self.rocket.aerodynamic_surfaces.sort_by_position(reverse=reverse)
152+
y_tube, x_tube = [], []
153+
for surface, position in self.rocket.aerodynamic_surfaces:
154+
if isinstance(surface, (NoseCone, Tail)):
155+
# Append the x and y coordinates of the surface shape_vec to the respective lists
156+
x_tube.extend((-csys) * surface.shape_vec[0] + position)
157+
y_tube.extend(surface.shape_vec[1])
158+
if isinstance(surface, Fins):
159+
pass
160+
161+
# Negate each element in the y_tube list using a list comprehension
162+
y_tube_negated = [-y for y in y_tube]
163+
plt.plot(
164+
x_tube, y_tube, color=vis_args["body"], linewidth=vis_args["line_width"]
165+
)
166+
plt.plot(
167+
x_tube,
168+
y_tube_negated,
169+
color=vis_args["body"],
170+
linewidth=vis_args["line_width"],
171+
)
172+
173+
# Get nozzle position (kinda not working for EmptyMotor class)
174+
x_nozzle = self.rocket.motor_position + self.rocket.motor.nozzle_position
175+
176+
# Find the last point of the rocket
177+
idx = -1 if csys == 1 else 0
178+
surface, position = self.rocket.aerodynamic_surfaces[idx]
179+
length = surface.shape_vec[0][-1] - surface.shape_vec[0][0]
180+
x_last = position + (-1 * csys) * length
181+
y_last = surface.shape_vec[1][-1]
182+
183+
plt.plot(
184+
[x_nozzle, x_last],
185+
[0, y_last],
186+
color=vis_args["body"],
187+
linewidth=vis_args["line_width"],
188+
)
189+
plt.plot(
190+
[x_nozzle, x_last],
191+
[0, -y_last],
192+
color=vis_args["body"],
193+
linewidth=vis_args["line_width"],
194+
)
195+
196+
# Draw nosecone
197+
nosecones = self.rocket.aerodynamic_surfaces.get_tuple_by_type(NoseCone)
198+
for nose, position in nosecones:
199+
x_nosecone = -csys * nose.shape_vec[0] + position
200+
y_nosecone = nose.shape_vec[1]
201+
202+
plt.plot(
203+
x_nosecone,
204+
y_nosecone,
205+
color=vis_args["nose"],
206+
linewidth=vis_args["line_width"] - 0.05,
207+
)
208+
plt.plot(
209+
x_nosecone,
210+
-y_nosecone,
211+
color=vis_args["nose"],
212+
linewidth=vis_args["line_width"] - 0.05,
213+
)
214+
215+
# Draw transitions
216+
tails = self.rocket.aerodynamic_surfaces.get_tuple_by_type(Tail)
217+
for tail, position in tails:
218+
x_tail = -csys * tail.shape_vec[0] + position
219+
y_tail = tail.shape_vec[1]
220+
221+
plt.plot(
222+
x_tail,
223+
y_tail,
224+
color=vis_args["tail"],
225+
linewidth=vis_args["line_width"],
226+
)
227+
plt.plot(
228+
x_tail,
229+
-y_tail,
230+
color=vis_args["tail"],
231+
linewidth=vis_args["line_width"],
232+
)
233+
234+
# Draw fins
235+
fins = self.rocket.aerodynamic_surfaces.get_tuple_by_type(Fins)
236+
for fin, position in fins:
237+
x_fin = -csys * fin.shape_vec[0] + position
238+
y_fin = fin.shape_vec[1] + self.rocket.radius
239+
240+
plt.plot(
241+
x_fin,
242+
y_fin,
243+
color=vis_args["fins"],
244+
linewidth=vis_args["line_width"],
245+
)
246+
plt.plot(
247+
x_fin,
248+
-y_fin,
249+
color=vis_args["fins"],
250+
linewidth=vis_args["line_width"],
251+
)
252+
253+
# Draw rail buttons
254+
buttons, pos = self.rocket.rail_buttons[0]
255+
lower = pos
256+
upper = pos + buttons.buttons_distance * csys
257+
plt.scatter(
258+
lower, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=10
259+
)
260+
plt.scatter(
261+
upper, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=10
262+
)
263+
264+
# Draw center of mass and center of pressure
265+
cm = self.rocket.center_of_mass(0)
266+
plt.scatter(cm, 0, color="black", label="Center of Mass", s=30)
267+
plt.scatter(cm, 0, facecolors="none", edgecolors="black", s=100)
268+
269+
cp = self.rocket.cp_position
270+
plt.scatter(cp, 0, label="Center Of Pressure", color="red", s=30, zorder=10)
271+
plt.scatter(cp, 0, facecolors="none", edgecolors="red", s=100, zorder=10)
272+
273+
# Set plot attributes
274+
plt.title(f"Rocket Geometry")
275+
plt.ylim([-self.rocket.radius * 4, self.rocket.radius * 6])
276+
plt.xlabel("Position (m)")
277+
plt.ylabel("Radius (m)")
278+
plt.legend(loc="best")
279+
plt.tight_layout()
280+
plt.show()
281+
return None
282+
107283
def all(self):
108284
"""Prints out all graphs available about the Rocket. It simply calls
109285
all the other plotter methods in this class.

0 commit comments

Comments
 (0)