From 476a87018137461563224816a4cb17426c25493e Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sun, 24 Sep 2023 23:36:26 -0300 Subject: [PATCH 1/8] ENH: improve some Components class methods --- rocketpy/rocket/components.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/rocketpy/rocket/components.py b/rocketpy/rocket/components.py index fe033dafe..1d1d33e56 100644 --- a/rocketpy/rocket/components.py +++ b/rocketpy/rocket/components.py @@ -25,7 +25,13 @@ def __init__(self): def __repr__(self): """Return a string representation of the Components instance.""" - return repr(self._components) + components_str = "\n".join( + [ + f"\tComponent: {str(c.component):80} Position: {c.position:>6.3f}" + for c in self._components + ] + ) + return f"Components:\n{components_str}" def __len__(self): """Return the number of components in the list of components.""" @@ -155,3 +161,19 @@ def clear(self): None """ self._components.clear() + + def sort_by_position(self, reverse=False): + """Sort the list of components by position. + + Parameters + ---------- + reverse : bool + If True, sort in descending order. If False, sort in ascending + order. + + Returns + ------- + None + """ + self._components.sort(key=lambda x: x.position, reverse=reverse) + return None From a66cd063674c89c55a0581f0df553387b7680369 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sun, 24 Sep 2023 23:38:12 -0300 Subject: [PATCH 2/8] MNT: Lose some relative imports to avoid bugs --- rocketpy/plots/__init__.py | 18 ------------------ rocketpy/rocket/__init__.py | 8 ++++---- rocketpy/rocket/rocket.py | 38 ++++++++++++++++++++++++++++++------- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/rocketpy/plots/__init__.py b/rocketpy/plots/__init__.py index 130d50aff..e69de29bb 100644 --- a/rocketpy/plots/__init__.py +++ b/rocketpy/plots/__init__.py @@ -1,18 +0,0 @@ -from .aero_surface_plots import ( - _EllipticalFinsPlots, - _FinsPlots, - _NoseConePlots, - _TailPlots, - _TrapezoidalFinsPlots, -) -from .compare import Compare, CompareFlights -from .environment_analysis_plots import _EnvironmentAnalysisPlots -from .environment_plots import _EnvironmentPlots -from .flight_plots import _FlightPlots -from .hybrid_motor_plots import _HybridMotorPlots -from .liquid_motor_plots import _LiquidMotorPlots -from .motor_plots import _MotorPlots -from .rocket_plots import _RocketPlots -from .solid_motor_plots import _SolidMotorPlots -from .tank_geometry_plots import _TankGeometryPlots -from .tank_plots import _TankPlots diff --git a/rocketpy/rocket/__init__.py b/rocketpy/rocket/__init__.py index 337fc9b7b..0fd8d27f0 100644 --- a/rocketpy/rocket/__init__.py +++ b/rocketpy/rocket/__init__.py @@ -1,4 +1,4 @@ -from .aero_surface import ( +from rocketpy.rocket.aero_surface import ( AeroSurface, EllipticalFins, Fins, @@ -7,6 +7,6 @@ Tail, TrapezoidalFins, ) -from .components import Components -from .parachute import Parachute -from .rocket import Rocket +from rocketpy.rocket.components import Components +from rocketpy.rocket.parachute import Parachute +from rocketpy.rocket.rocket import Rocket diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 0ebee9ae1..0c2589c07 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -2,11 +2,11 @@ import numpy as np -from ..mathutils.function import Function -from ..motors.motor import EmptyMotor -from ..plots.rocket_plots import _RocketPlots -from ..prints.rocket_prints import _RocketPrints -from .aero_surface import ( +from rocketpy.mathutils.function import Function +from rocketpy.motors.motor import EmptyMotor +from rocketpy.plots.rocket_plots import _RocketPlots +from rocketpy.prints.rocket_prints import _RocketPrints +from rocketpy.rocket.aero_surface import ( EllipticalFins, Fins, NoseCone, @@ -14,8 +14,8 @@ Tail, TrapezoidalFins, ) -from .components import Components -from .parachute import Parachute +from rocketpy.rocket.components import Components +from rocketpy.rocket.parachute import Parachute class Rocket: @@ -1183,6 +1183,30 @@ def add_thrust_eccentricity(self, x, y): # Return self return self + def draw(self, vis_args=None): + """Draws the rocket in a matplotlib figure. + + Parameters + ---------- + vis_args : dict, optional + Determines the visual aspects when drawing the rocket. If None, + default values are used. Default values are: + { + "background": "#EEEEEE", + "tail": "black", + "nose": "black", + "body": "dimgrey", + "fins": "black", + "motor": "black", + "buttons": "black", + "line_width": 2.0, + } + A full list of color names can be found at: + https://matplotlib.org/stable/gallery/color/named_colors + """ + self.plots.draw(vis_args) + return None + def info(self): """Prints out a summary of the data and graphs available about the Rocket. From 711b9b3e898378a78f095850ff1f44f705aeab6c Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sun, 24 Sep 2023 23:40:14 -0300 Subject: [PATCH 3/8] ENH: implement some more evaluate_shape() methods --- rocketpy/rocket/aero_surface.py | 46 ++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/rocketpy/rocket/aero_surface.py b/rocketpy/rocket/aero_surface.py index f285356b2..4a1a3243e 100644 --- a/rocketpy/rocket/aero_surface.py +++ b/rocketpy/rocket/aero_surface.py @@ -1,7 +1,6 @@ from abc import ABC, abstractmethod import warnings -import matplotlib.pyplot as plt import numpy as np from scipy.optimize import fsolve @@ -20,6 +19,7 @@ _TrapezoidalFinsPrints, ) +# TODO: all the evaluate_shape() methods need tests and documentation class AeroSurface(ABC): """Abstract class used to define aerodynamic surfaces.""" @@ -1215,6 +1215,30 @@ def evaluate_geometrical_parameters(self): self.roll_damping_interference_factor = roll_damping_interference_factor self.roll_forcing_interference_factor = roll_forcing_interference_factor + self.evaluate_shape() + return None + + def evaluate_shape(self): + if self.sweep_length: + points = [ + (0, 0), + (self.sweep_length, self.span), + (self.sweep_length + self.tip_chord, self.span), + (self.root_chord, 0), + ] + else: + points = [ + (0, 0), + (self.root_chord - self.tip_chord, self.span), + (self.root_chord, self.span), + (self.root_chord, 0), + ] + + x_array, y_array = zip(*points) + self.shape_vec = [np.array(x_array), np.array(y_array)] + + return None + def info(self): self.prints.geometry() self.prints.lift() @@ -1521,6 +1545,16 @@ def evaluate_geometrical_parameters(self): self.roll_damping_interference_factor = roll_damping_interference_factor self.roll_forcing_interference_factor = roll_forcing_interference_factor + self.evaluate_shape() + return None + + def evaluate_shape(self): + angles = np.arange(0, 360, 5) + x_array = self.root_chord / 2 + self.root_chord / 2 * np.cos(np.radians(angles)) + y_array = self.span * np.sin(np.radians(angles)) + self.shape_vec = [x_array, y_array] + return None + def info(self): self.prints.geometry() self.prints.lift() @@ -1675,6 +1709,16 @@ def evaluate_geometrical_parameters(self): self.surface_area = ( np.pi * self.slant_length * (self.top_radius + self.bottom_radius) ) + self.evaluate_shape() + return None + + def evaluate_shape(self): + # Assuming the tail is a cone, calculate the shape vector + self.shape_vec = [ + np.array([0, self.length]), + np.array([self.top_radius, self.bottom_radius]), + ] + return None def evaluate_lift_coefficient(self): """Calculates and returns tail's lift coefficient. From 8f67b315e40ad88ead34927c4a234885dab8e02d Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sun, 24 Sep 2023 23:40:49 -0300 Subject: [PATCH 4/8] ENH: Rocket.draw() initial commit --- rocketpy/plots/rocket_plots.py | 178 ++++++++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 1 deletion(-) diff --git a/rocketpy/plots/rocket_plots.py b/rocketpy/plots/rocket_plots.py index 9764eb467..73cf0cdb5 100644 --- a/rocketpy/plots/rocket_plots.py +++ b/rocketpy/plots/rocket_plots.py @@ -1,5 +1,6 @@ import matplotlib.pyplot as plt -import numpy as np + +from rocketpy.rocket.aero_surface import Fins, NoseCone, Tail class _RocketPlots: @@ -104,6 +105,181 @@ def thrust_to_weight(self): return None + def draw(self, vis_args=None): + """Draws the rocket in a matplotlib figure. + + Parameters + ---------- + vis_args : dict, optional + Determines the visual aspects when drawing the rocket. If None, + default values are used. Default values are: + { + "background": "#EEEEEE", + "tail": "black", + "nose": "black", + "body": "dimgrey", + "fins": "black", + "motor": "black", + "buttons": "black", + "line_width": 2.0, + } + A full list of color names can be found at: + https://matplotlib.org/stable/gallery/color/named_colors + """ + if vis_args is None: + vis_args = { + "background": "#EEEEEE", + "tail": "black", + "nose": "black", + "body": "dimgrey", + "fins": "black", + "motor": "black", + "buttons": "black", + "line_width": 2.0, + } + + # Create the figure and axis + _, ax = plt.subplots(figsize=(10, 5)) + ax.set_aspect("equal") + ax.set_facecolor(vis_args["background"]) + ax.grid(True, linestyle="--", linewidth=0.5) + + csys = self.rocket._csys + + # Draw rocket body + reverse = csys == 1 + self.rocket.aerodynamic_surfaces.sort_by_position(reverse=reverse) + y_tube, x_tube = [], [] + for surface, position in self.rocket.aerodynamic_surfaces: + if isinstance(surface, (NoseCone, Tail)): + # Append the x and y coordinates of the surface shape_vec to the respective lists + x_tube.extend((-csys) * surface.shape_vec[0] + position) + y_tube.extend(surface.shape_vec[1]) + if isinstance(surface, Fins): + pass + + # Negate each element in the y_tube list using a list comprehension + y_tube_negated = [-y for y in y_tube] + plt.plot( + x_tube, y_tube, color=vis_args["body"], linewidth=vis_args["line_width"] + ) + plt.plot( + x_tube, + y_tube_negated, + color=vis_args["body"], + linewidth=vis_args["line_width"], + ) + + # Get nozzle position (kinda not working for EmptyMotor class) + x_nozzle = self.rocket.motor_position + self.rocket.motor.nozzle_position + + # Find the last point of the rocket + idx = -1 if csys == 1 else 0 + surface, position = self.rocket.aerodynamic_surfaces[idx] + length = surface.shape_vec[0][-1] - surface.shape_vec[0][0] + x_last = position + (-1 * csys) * length + y_last = surface.shape_vec[1][-1] + + plt.plot( + [x_nozzle, x_last], + [0, y_last], + color=vis_args["body"], + linewidth=vis_args["line_width"], + ) + plt.plot( + [x_nozzle, x_last], + [0, -y_last], + color=vis_args["body"], + linewidth=vis_args["line_width"], + ) + + # Draw nosecone + nosecones = self.rocket.aerodynamic_surfaces.get_tuple_by_type(NoseCone) + for nose, position in nosecones: + x_nosecone = -csys * nose.shape_vec[0] + position + y_nosecone = nose.shape_vec[1] + + plt.plot( + x_nosecone, + y_nosecone, + color=vis_args["nose"], + linewidth=vis_args["line_width"] - 0.05, + ) + plt.plot( + x_nosecone, + -y_nosecone, + color=vis_args["nose"], + linewidth=vis_args["line_width"] - 0.05, + ) + + # Draw transitions + tails = self.rocket.aerodynamic_surfaces.get_tuple_by_type(Tail) + for tail, position in tails: + x_tail = -csys * tail.shape_vec[0] + position + y_tail = tail.shape_vec[1] + + plt.plot( + x_tail, + y_tail, + color=vis_args["tail"], + linewidth=vis_args["line_width"], + ) + plt.plot( + x_tail, + -y_tail, + color=vis_args["tail"], + linewidth=vis_args["line_width"], + ) + + # Draw fins + fins = self.rocket.aerodynamic_surfaces.get_tuple_by_type(Fins) + for fin, position in fins: + x_fin = -csys * fin.shape_vec[0] + position + y_fin = fin.shape_vec[1] + self.rocket.radius + + plt.plot( + x_fin, + y_fin, + color=vis_args["fins"], + linewidth=vis_args["line_width"], + ) + plt.plot( + x_fin, + -y_fin, + color=vis_args["fins"], + linewidth=vis_args["line_width"], + ) + + # Draw rail buttons + buttons, pos = self.rocket.rail_buttons[0] + lower = pos + upper = pos + buttons.buttons_distance * csys + plt.scatter( + lower, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=10 + ) + plt.scatter( + upper, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=10 + ) + + # Draw center of mass and center of pressure + cm = self.rocket.center_of_mass(0) + plt.scatter(cm, 0, color="black", label="Center of Mass", s=30) + plt.scatter(cm, 0, facecolors="none", edgecolors="black", s=100) + + cp = self.rocket.cp_position + plt.scatter(cp, 0, label="Center Of Pressure", color="red", s=30, zorder=10) + plt.scatter(cp, 0, facecolors="none", edgecolors="red", s=100, zorder=10) + + # Set plot attributes + plt.title(f"Rocket Geometry") + plt.ylim([-self.rocket.radius * 4, self.rocket.radius * 6]) + plt.xlabel("Position (m)") + plt.ylabel("Radius (m)") + plt.legend(loc="best") + plt.tight_layout() + plt.show() + return None + def all(self): """Prints out all graphs available about the Rocket. It simply calls all the other plotter methods in this class. From 8bb9fdbe89c462abcb29062d7248348c6884ba6c Mon Sep 17 00:00:00 2001 From: Lint Action Date: Mon, 25 Sep 2023 03:10:28 +0000 Subject: [PATCH 5/8] Fix code style issues with Black --- rocketpy/plots/rocket_plots.py | 2 +- rocketpy/rocket/aero_surface.py | 1 + rocketpy/rocket/rocket.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rocketpy/plots/rocket_plots.py b/rocketpy/plots/rocket_plots.py index 73cf0cdb5..c565c8183 100644 --- a/rocketpy/plots/rocket_plots.py +++ b/rocketpy/plots/rocket_plots.py @@ -107,7 +107,7 @@ def thrust_to_weight(self): def draw(self, vis_args=None): """Draws the rocket in a matplotlib figure. - + Parameters ---------- vis_args : dict, optional diff --git a/rocketpy/rocket/aero_surface.py b/rocketpy/rocket/aero_surface.py index 4a1a3243e..026ef26ea 100644 --- a/rocketpy/rocket/aero_surface.py +++ b/rocketpy/rocket/aero_surface.py @@ -21,6 +21,7 @@ # TODO: all the evaluate_shape() methods need tests and documentation + class AeroSurface(ABC): """Abstract class used to define aerodynamic surfaces.""" diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 0c2589c07..d350e51c1 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -1185,7 +1185,7 @@ def add_thrust_eccentricity(self, x, y): def draw(self, vis_args=None): """Draws the rocket in a matplotlib figure. - + Parameters ---------- vis_args : dict, optional From 3d0edf042f766433d4eabf22a7d6730e7dbb3c5a Mon Sep 17 00:00:00 2001 From: MateusStano Date: Mon, 2 Oct 2023 00:35:38 +0200 Subject: [PATCH 6/8] ENH: reestructure draw to better handle weird positions and diameter changes --- rocketpy/plots/rocket_plots.py | 320 ++++++++++++++++++++++----------- 1 file changed, 213 insertions(+), 107 deletions(-) diff --git a/rocketpy/plots/rocket_plots.py b/rocketpy/plots/rocket_plots.py index c565c8183..cd654500d 100644 --- a/rocketpy/plots/rocket_plots.py +++ b/rocketpy/plots/rocket_plots.py @@ -1,3 +1,4 @@ +import numpy as np import matplotlib.pyplot as plt from rocketpy.rocket.aero_surface import Fins, NoseCone, Tail @@ -105,7 +106,7 @@ def thrust_to_weight(self): return None - def draw(self, vis_args=None): + def draw2(self, vis_args=None): """Draws the rocket in a matplotlib figure. Parameters @@ -117,7 +118,7 @@ def draw(self, vis_args=None): "background": "#EEEEEE", "tail": "black", "nose": "black", - "body": "dimgrey", + "body": "black", "fins": "black", "motor": "black", "buttons": "black", @@ -131,144 +132,248 @@ def draw(self, vis_args=None): "background": "#EEEEEE", "tail": "black", "nose": "black", - "body": "dimgrey", + "body": "black", "fins": "black", "motor": "black", "buttons": "black", - "line_width": 2.0, + "line_width": 1.0, } # Create the figure and axis - _, ax = plt.subplots(figsize=(10, 5)) + _, ax = plt.subplots(figsize=(8, 5)) ax.set_aspect("equal") ax.set_facecolor(vis_args["background"]) ax.grid(True, linestyle="--", linewidth=0.5) csys = self.rocket._csys - - # Draw rocket body reverse = csys == 1 self.rocket.aerodynamic_surfaces.sort_by_position(reverse=reverse) - y_tube, x_tube = [], [] - for surface, position in self.rocket.aerodynamic_surfaces: - if isinstance(surface, (NoseCone, Tail)): - # Append the x and y coordinates of the surface shape_vec to the respective lists - x_tube.extend((-csys) * surface.shape_vec[0] + position) - y_tube.extend(surface.shape_vec[1]) - if isinstance(surface, Fins): - pass - - # Negate each element in the y_tube list using a list comprehension - y_tube_negated = [-y for y in y_tube] - plt.plot( - x_tube, y_tube, color=vis_args["body"], linewidth=vis_args["line_width"] - ) - plt.plot( - x_tube, - y_tube_negated, - color=vis_args["body"], - linewidth=vis_args["line_width"], - ) - # Get nozzle position (kinda not working for EmptyMotor class) - x_nozzle = self.rocket.motor_position + self.rocket.motor.nozzle_position - - # Find the last point of the rocket - idx = -1 if csys == 1 else 0 - surface, position = self.rocket.aerodynamic_surfaces[idx] - length = surface.shape_vec[0][-1] - surface.shape_vec[0][0] - x_last = position + (-1 * csys) * length - y_last = surface.shape_vec[1][-1] - - plt.plot( - [x_nozzle, x_last], - [0, y_last], - color=vis_args["body"], - linewidth=vis_args["line_width"], - ) - plt.plot( - [x_nozzle, x_last], - [0, -y_last], - color=vis_args["body"], - linewidth=vis_args["line_width"], - ) - - # Draw nosecone - nosecones = self.rocket.aerodynamic_surfaces.get_tuple_by_type(NoseCone) - for nose, position in nosecones: - x_nosecone = -csys * nose.shape_vec[0] + position - y_nosecone = nose.shape_vec[1] - - plt.plot( - x_nosecone, - y_nosecone, - color=vis_args["nose"], - linewidth=vis_args["line_width"] - 0.05, - ) - plt.plot( - x_nosecone, - -y_nosecone, - color=vis_args["nose"], - linewidth=vis_args["line_width"] - 0.05, - ) + # List of drawn surfaces with the position of points of interest + # and the radius of the rocket at that point + drawn_surfaces = [] - # Draw transitions - tails = self.rocket.aerodynamic_surfaces.get_tuple_by_type(Tail) - for tail, position in tails: - x_tail = -csys * tail.shape_vec[0] + position - y_tail = tail.shape_vec[1] + # Ideia is to get the shape of each aerodynamic surface in their own + # coordinate system and then plot them in the rocket coordinate system + # using the position of each surface + # For the tubes, the surfaces need to be checked in order to check for + # diameter changes. The final point of the last surface is the final + # point of the last tube - plt.plot( - x_tail, - y_tail, - color=vis_args["tail"], + for surface, position in self.rocket.aerodynamic_surfaces: + if isinstance(surface, NoseCone): + x_nosecone = -csys * surface.shape_vec[0] + position + y_nosecone = surface.shape_vec[1] + + ax.plot( + x_nosecone, + y_nosecone, + color=vis_args["nose"], + linewidth=vis_args["line_width"], + ) + ax.plot( + x_nosecone, + -y_nosecone, + color=vis_args["nose"], + linewidth=vis_args["line_width"], + ) + # close the nosecone + ax.plot( + [x_nosecone[-1], x_nosecone[-1]], + [y_nosecone[-1], -y_nosecone[-1]], + color=vis_args["nose"], + linewidth=vis_args["line_width"], + ) + + # Add the nosecone to the list of drawn surfaces + drawn_surfaces.append( + (surface, x_nosecone[-1], surface.rocket_radius, x_nosecone[-1]) + ) + + elif isinstance(surface, Tail): + x_tail = -csys * surface.shape_vec[0] + position + y_tail = surface.shape_vec[1] + + ax.plot( + x_tail, + y_tail, + color=vis_args["tail"], + linewidth=vis_args["line_width"], + ) + ax.plot( + x_tail, + -y_tail, + color=vis_args["tail"], + linewidth=vis_args["line_width"], + ) + # close above and below the tail + ax.plot( + [x_tail[-1], x_tail[-1]], + [y_tail[-1], -y_tail[-1]], + color=vis_args["tail"], + linewidth=vis_args["line_width"], + ) + ax.plot( + [x_tail[0], x_tail[0]], + [y_tail[0], -y_tail[0]], + color=vis_args["tail"], + linewidth=vis_args["line_width"], + ) + + # Add the tail to the list of drawn surfaces + drawn_surfaces.append( + (surface, position, surface.bottom_radius, x_tail[-1]) + ) + + # Draw fins + elif isinstance(surface, Fins): + num_fins = surface.n + x_fin = -csys * surface.shape_vec[0] + position + y_fin = surface.shape_vec[1] + surface.rocket_radius + + # Calculate the rotation angles for the other two fins (symmetrically) + rotation_angles = [2 * np.pi * i / num_fins for i in range(num_fins)] + + # Apply rotation transformations to get points for the other fins in 2D space + for angle in rotation_angles: + # Create a rotation matrix for the current angle around the x-axis + rotation_matrix = np.array([[1, 0], [0, np.cos(angle)]]) + + # Apply the rotation to the original fin points + rotated_points_2d = np.dot( + rotation_matrix, np.vstack((x_fin, y_fin)) + ) + + # Extract x and y coordinates of the rotated points + x_rotated, y_rotated = rotated_points_2d + + # Project points above the XY plane back into the XY plane (set z-coordinate to 0) + x_rotated = np.where( + rotated_points_2d[1] > 0, rotated_points_2d[0], x_rotated + ) + y_rotated = np.where( + rotated_points_2d[1] > 0, rotated_points_2d[1], y_rotated + ) + + # Plot the fins + ax.plot( + x_rotated, + y_rotated, + color=vis_args["fins"], + linewidth=vis_args["line_width"], + ) + + # Add the fin to the list of drawn surfaces + drawn_surfaces.append( + (surface, position, surface.rocket_radius, x_rotated[-1]) + ) + + # Draw tubes + for i, d_surface in enumerate(drawn_surfaces): + # Draw the tubes, from the end of the first surface to the beggining + # of the next surface, with the radius of the rocket at that point + surface, position, radius, last_x = d_surface + + if i == len(drawn_surfaces) - 1: + # If the last surface is a tail, do nothing + if isinstance(surface, Tail): + continue + # Else goes to the end of the surface + else: + x_tube = [position, last_x] + y_tube = [radius, radius] + y_tube_negated = [-radius, -radius] + else: + # If it is not the last surface, the tube goes to the beggining + # of the next surface + next_surface, next_position, next_radius, next_last_x = drawn_surfaces[ + i + 1 + ] + x_tube = [last_x, next_position] + y_tube = [radius, radius] + y_tube_negated = [-radius, -radius] + + ax.plot( + x_tube, + y_tube, + color=vis_args["body"], linewidth=vis_args["line_width"], ) - plt.plot( - x_tail, - -y_tail, - color=vis_args["tail"], + ax.plot( + x_tube, + y_tube_negated, + color=vis_args["body"], linewidth=vis_args["line_width"], ) - # Draw fins - fins = self.rocket.aerodynamic_surfaces.get_tuple_by_type(Fins) - for fin, position in fins: - x_fin = -csys * fin.shape_vec[0] + position - y_fin = fin.shape_vec[1] + self.rocket.radius - - plt.plot( - x_fin, - y_fin, - color=vis_args["fins"], - linewidth=vis_args["line_width"], - ) - plt.plot( - x_fin, - -y_fin, - color=vis_args["fins"], - linewidth=vis_args["line_width"], - ) + # TODO - Draw motor + nozzle_position = ( + self.rocket.motor_position + + self.rocket.motor.nozzle_position + * self.rocket._csys + * self.rocket.motor._csys + ) + ax.scatter( + nozzle_position, 0, label="Nozzle Outlet", color="brown", s=10, zorder=10 + ) + # Check if nozzle is beyond the last surface, if so draw a tube + # to it, with the radius of the last surface + if self.rocket._csys == 1: + if nozzle_position < last_x: + x_tube = [last_x, nozzle_position] + y_tube = [radius, radius] + y_tube_negated = [-radius, -radius] + + ax.plot( + x_tube, + y_tube, + color=vis_args["body"], + linewidth=vis_args["line_width"], + ) + ax.plot( + x_tube, + y_tube_negated, + color=vis_args["body"], + linewidth=vis_args["line_width"], + ) + else: # if self.rocket._csys == -1: + if nozzle_position > last_x: + x_tube = [last_x, nozzle_position] + y_tube = [radius, radius] + y_tube_negated = [-radius, -radius] + + ax.plot( + x_tube, + y_tube, + color=vis_args["body"], + linewidth=vis_args["line_width"], + ) + ax.plot( + x_tube, + y_tube_negated, + color=vis_args["body"], + linewidth=vis_args["line_width"], + ) # Draw rail buttons buttons, pos = self.rocket.rail_buttons[0] lower = pos upper = pos + buttons.buttons_distance * csys - plt.scatter( - lower, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=10 + ax.scatter( + lower, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=15 ) - plt.scatter( - upper, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=10 + ax.scatter( + upper, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=15 ) # Draw center of mass and center of pressure cm = self.rocket.center_of_mass(0) - plt.scatter(cm, 0, color="black", label="Center of Mass", s=30) - plt.scatter(cm, 0, facecolors="none", edgecolors="black", s=100) + ax.scatter(cm, 0, color="black", label="Center of Mass", s=30) + ax.scatter(cm, 0, facecolors="none", edgecolors="black", s=100) cp = self.rocket.cp_position - plt.scatter(cp, 0, label="Center Of Pressure", color="red", s=30, zorder=10) - plt.scatter(cp, 0, facecolors="none", edgecolors="red", s=100, zorder=10) + ax.scatter(cp, 0, label="Center Of Pressure", color="red", s=30, zorder=10) + ax.scatter(cp, 0, facecolors="none", edgecolors="red", s=100, zorder=10) # Set plot attributes plt.title(f"Rocket Geometry") @@ -278,6 +383,7 @@ def draw(self, vis_args=None): plt.legend(loc="best") plt.tight_layout() plt.show() + return None def all(self): From 1ce0c0dd32b563a86102e6e9db72fabf0203c773 Mon Sep 17 00:00:00 2001 From: MateusStano Date: Mon, 2 Oct 2023 00:39:40 +0200 Subject: [PATCH 7/8] BUG: draw method name --- rocketpy/plots/rocket_plots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpy/plots/rocket_plots.py b/rocketpy/plots/rocket_plots.py index cd654500d..1345b213d 100644 --- a/rocketpy/plots/rocket_plots.py +++ b/rocketpy/plots/rocket_plots.py @@ -106,7 +106,7 @@ def thrust_to_weight(self): return None - def draw2(self, vis_args=None): + def draw(self, vis_args=None): """Draws the rocket in a matplotlib figure. Parameters From de4e9ca0cbc39f02888e0ec13577349781dccc1b Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sat, 7 Oct 2023 19:04:23 -0300 Subject: [PATCH 8/8] BUG: doesn't draw very well without buttons --- rocketpy/plots/rocket_plots.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/rocketpy/plots/rocket_plots.py b/rocketpy/plots/rocket_plots.py index 1345b213d..27eee40c7 100644 --- a/rocketpy/plots/rocket_plots.py +++ b/rocketpy/plots/rocket_plots.py @@ -127,6 +127,7 @@ def draw(self, vis_args=None): A full list of color names can be found at: https://matplotlib.org/stable/gallery/color/named_colors """ + # TODO: we need to modularize this function, it is too big if vis_args is None: vis_args = { "background": "#EEEEEE", @@ -270,7 +271,7 @@ def draw(self, vis_args=None): # Draw tubes for i, d_surface in enumerate(drawn_surfaces): - # Draw the tubes, from the end of the first surface to the beggining + # Draw the tubes, from the end of the first surface to the beginning # of the next surface, with the radius of the rocket at that point surface, position, radius, last_x = d_surface @@ -284,7 +285,7 @@ def draw(self, vis_args=None): y_tube = [radius, radius] y_tube_negated = [-radius, -radius] else: - # If it is not the last surface, the tube goes to the beggining + # If it is not the last surface, the tube goes to the beginning # of the next surface next_surface, next_position, next_radius, next_last_x = drawn_surfaces[ i + 1 @@ -356,15 +357,18 @@ def draw(self, vis_args=None): ) # Draw rail buttons - buttons, pos = self.rocket.rail_buttons[0] - lower = pos - upper = pos + buttons.buttons_distance * csys - ax.scatter( - lower, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=15 - ) - ax.scatter( - upper, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=15 - ) + try: + buttons, pos = self.rocket.rail_buttons[0] + lower = pos + upper = pos + buttons.buttons_distance * csys + ax.scatter( + lower, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=15 + ) + ax.scatter( + upper, -self.rocket.radius, marker="s", color=vis_args["buttons"], s=15 + ) + except IndexError: + pass # Draw center of mass and center of pressure cm = self.rocket.center_of_mass(0)