Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inclusion of Shaft and Propeller classes with tests (basic version) #62

Merged
merged 4 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions bladex/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""
BladeX init
"""
__all__ = ['profilebase', 'profiles', 'blade', 'deform', 'params', 'ndinterpolator']
__all__ = ['profilebase', 'profiles', 'blade', 'shaft', 'propeller', 'deform', 'params', 'ndinterpolator']

from .profilebase import ProfileBase
from .profiles import CustomProfile, NacaProfile
from .blade import Blade
from .shaft import Shaft
from .propeller import Propeller
from .deform import Deformation
from .params import ParamFile
from .ndinterpolator import RBF, reconstruct_f, scipy_bspline
from .ndinterpolator import RBF, reconstruct_f, scipy_bspline
12 changes: 6 additions & 6 deletions bladex/blade.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,22 +226,22 @@ def _planar_to_cylindrical(self):
- :math:`y = r \\sin\\left( \\frac{y_i}{r} \\right) \\qquad
\\forall y_i \\in Y`

- :math:`z = -r \\cos\\left( \\frac{y_i}{r} \\right) \\qquad
- :math:`z = r \\cos\\left( \\frac{y_i}{r} \\right) \\qquad
\\forall y_i \\in Y`

After transformation, the method also fills the numpy.ndarray
"blade_coordinates_up" and "blade_coordinates_down" with the new
:math:`(X, Y, Z)` coordinates.
"""
for section, radius in zip(self.sections, self.radii):
for section, radius in zip(self.sections[::-1], self.radii[::-1]):
theta_up = section.yup_coordinates / radius
theta_down = section.ydown_coordinates / radius

y_section_up = radius * np.sin(theta_up)
y_section_down = radius * np.sin(theta_down)

z_section_up = -radius * np.cos(theta_up)
z_section_down = -radius * np.cos(theta_down)
z_section_up = radius * np.cos(theta_up)
z_section_down = radius * np.cos(theta_down)

self.blade_coordinates_up.append(
np.array([section.xup_coordinates, y_section_up, z_section_up]))
Expand Down Expand Up @@ -464,7 +464,7 @@ def plot(self, elev=None, azim=None, ax=None, outfile=None):
else:
fig = plt.figure()
ax = fig.gca(projection=Axes3D.name)
ax.set_aspect('equal')
ax.set_aspect('auto')

for i in range(self.n_sections):
ax.plot(self.blade_coordinates_up[i][0],
Expand All @@ -474,7 +474,7 @@ def plot(self, elev=None, azim=None, ax=None, outfile=None):
self.blade_coordinates_down[i][1],
self.blade_coordinates_down[i][2])

plt.axis('equal')
plt.axis('auto')
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('radii axis')
Expand Down
92 changes: 92 additions & 0 deletions bladex/propeller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Module for the propeller with shaft bottom-up parametrized construction.
"""
import os
import numpy as np
from bladex import Blade, Shaft
import OCC.Core.TopoDS
from OCC.Core.gp import gp_Dir, gp_Pnt, gp_Ax1, gp_Trsf
from OCC.Core.IGESControl import IGESControl_Reader, IGESControl_Writer
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_Transform, BRepBuilderAPI_Sewing
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCC.Extend.DataExchange import write_stl_file
from OCC.Display.SimpleGui import init_display

class Propeller(object):
ndem0 marked this conversation as resolved.
Show resolved Hide resolved
"""
Bottom-up parametrized propeller (including shaft) construction.

:param shaft.Shaft shaft: shaft to be added to the propeller
:param blade.Blade blade: blade of the propeller
:param int n_blades: number of blades componing the propeller
ndem0 marked this conversation as resolved.
Show resolved Hide resolved
"""

def __init__(self, shaft, blade, n_blades):
self.shaft_solid = shaft.generate_shaft_solid()
blade.apply_transformations(reflect=True)
blade_solid = blade.generate_blade_solid(max_deg=2,
display=False,
errors=None)
blades = []
blades.append(blade_solid)
for i in range(n_blades-1):
rot_dir = gp_Dir(1.0, 0.0, 0.0)
origin = gp_Pnt(0.0, 0.0, 0.0)
rot_axis = gp_Ax1(origin, rot_dir)
transf = gp_Trsf()
transf.SetRotation(rot_axis, float(i+1)*2.0*np.pi/float(n_blades));
transformer = BRepBuilderAPI_Transform(blade_solid, transf);
blades.append(transformer.Shape())
blades_combined = blades[0]
for i in range(len(blades)-1):
boolean_union = BRepAlgoAPI_Fuse(blades_combined, blades[i+1])
boolean_union.Build()
if not boolean_union.IsDone():
raise RuntimeError('Unsuccessful assembling of blade')
blades_combined = boolean_union.Shape()
boolean_union = BRepAlgoAPI_Fuse(self.shaft_solid, blades_combined)
boolean_union.Build()
result_compound = boolean_union.Shape()
section_edges = boolean_union.SectionEdges()
sewer = BRepBuilderAPI_Sewing(1e-2)
sewer.Add(result_compound)
sewer.Perform()
self.sewed_full_body = sewer.SewedShape()

def generate_propeller_iges(self, propeller_and_shaft, display=False):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generate_iges for the method name (no reason to be redundant with "propeller" since the object itself is called Propeller)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, thank you.

"""
Export and plot the .iges CAD for the propeller with shaft.
This method requires PythonOCC to be installed.

:raises RuntimeError: if the solid assembling of blades is not
completed successfully
:param string propeller_and_shaft: path where to store the .iges CAD
for the propeller and shaft
:param bool display: if True, then display the propeller with shaft.
Default value is False
"""
iges_writer = IGESControl_Writer()
iges_writer.AddShape(self.sewed_full_body)
iges_writer.Write(propeller_and_shaft + '.iges')
if display:
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(self.sewed_full_body, update=True)
start_display()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why display when exporting? It looks much better to me have a separate method to display the propeller like>

my_custom_propeller = Propeller(...)
my_custom_propeller.display()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change accordingly, thanks.


def generate_propeller_stl(self, propeller_and_shaft, display=False):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as before

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, thanks.

"""
Export and plot the .stl CAD for the propeller with shaft.
This method requires PythonOCC and numpy-stl to be installed.

:raises RuntimeError: if the solid assembling of blades is not
completed successfully
:param string propeller_and_shaft: path where to store the .stl CAD
for the propeller and shaft
:param bool display: if True, then display the propeller with shaft.
Default value is False
"""
write_stl_file(self.sewed_full_body, propeller_and_shaft + '.stl')
if display:
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(self.sewed_full_body, update=True)
start_display()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as before

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change accordingly, thanks.

47 changes: 47 additions & 0 deletions bladex/shaft.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os
from OCC.Core.IGESControl import IGESControl_Reader
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeSolid, BRepBuilderAPI_Sewing
import OCC.Core.TopoDS
from OCC.Display.SimpleGui import init_display

class Shaft(object):
ndem0 marked this conversation as resolved.
Show resolved Hide resolved
"""
Bottom-up parametrized shaft construction.

:param string shaft_path: path of a .iges file with stored shaft information.
:param bool display: if True, then display the shaft. Default value is False.
"""

def __init__(self, shaft_path, display=False):
self.shaft_path = shaft_path
self.display = display

def generate_shaft_solid(self):
Copy link
Member

@ndem0 ndem0 Apr 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generate_solid

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks.

"""
Generate an assembled solid shaft using the
BRepBuilderAPI_MakeSolid algorithm.
This method requires PythonOCC to be installed.

:raises RuntimeError: if the assembling of the solid shaft is not
completed successfully
:return: solid shaft
:rtype: OCC.Core.TopoDS.TopoDS_Solid
"""
iges_reader = IGESControl_Reader()
iges_reader.ReadFile(self.shaft_path)
iges_reader.TransferRoots()
shaft_compound = iges_reader.Shape()
sewer = BRepBuilderAPI_Sewing(1e-2)
sewer.Add(shaft_compound)
sewer.Perform()
result_sewed_shaft = sewer.SewedShape()
shaft_solid_maker = BRepBuilderAPI_MakeSolid()
shaft_solid_maker.Add(OCC.Core.TopoDS.topods_Shell(result_sewed_shaft))
if not shaft_solid_maker.IsDone():
raise RuntimeError('Unsuccessful assembling of solid shaft')
shaft_solid = shaft_solid_maker.Solid()
if self.display:
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(shaft_solid, update=True)
start_display()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as before

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change accordingly, thanks.

return shaft_solid
Loading