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 3 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
14 changes: 7 additions & 7 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 Expand Up @@ -862,7 +862,7 @@ def generate_iges(self,
display.DisplayShape(self.generated_root, update=True)
start_display()

def generate_blade_solid(self,
def generate_solid(self,
max_deg=1,
display=False,
errors=None):
Expand Down
85 changes: 85 additions & 0 deletions bladex/propeller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
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.
The constructor requires PythonOCC to be installed.

: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
:cvar OCC.Core.TopoDS.TopoDS_Solid shaft_solid: solid shaft
:cvar OCC.Core.TopoDS.TopoDS_Shell: propeller with shaft shell
Copy link
Contributor

Choose a reason for hiding this comment

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

missing name of the variable

"""

def __init__(self, shaft, blade, n_blades):
self.shaft_solid = shaft.generate_solid()
blade.apply_transformations(reflect=True)
blade_solid = blade.generate_solid(max_deg=2,
display=False,
errors=None)
blades = []
blades.append(blade_solid)
for i in range(n_blades-1):
blade.rotate(rad_angle=1.0*2.0*np.pi/float(n_blades))
blade_solid = blade.generate_solid(max_deg=2, display=False, errors=None)
blades.append(blade_solid)
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_iges(self, filename):
"""
Export the .iges CAD for the propeller with shaft.

:param string filename: path (with the file extension) where to store
the .iges CAD for the propeller and shaft
:raises RuntimeError: if the solid assembling of blades is not
completed successfully
"""
iges_writer = IGESControl_Writer()
iges_writer.AddShape(self.sewed_full_body)
iges_writer.Write(filename)

def generate_stl(self, filename):
"""
Export the .stl CAD for the propeller with shaft.

:param string filename: path (with the file extension) where to store
the .stl CAD for the propeller and shaft
Copy link
Contributor

Choose a reason for hiding this comment

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

I think a tab is missing. Please check the doc is properly generated

:raises RuntimeError: if the solid assembling of blades is not
completed successfully
"""
write_stl_file(self.sewed_full_body, filename)

def display(self):
"""
Display the propeller with shaft.
"""
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(self.sewed_full_body, update=True)
start_display()
50 changes: 50 additions & 0 deletions bladex/shaft.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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.

:cvar string filename: path (with the file extension) of a .iges file with
Copy link
Contributor

Choose a reason for hiding this comment

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

this is a param, not only a var

stored shaft information.
"""

def __init__(self, filename):
self.filename = filename

def generate_solid(self):
"""
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.filename)
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()
return shaft_solid

def display(self):
"""
Display the shaft.
"""
shaft_solid = self.generate_solid()
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(shaft_solid, update=True)
start_display()
12 changes: 6 additions & 6 deletions tests/test_blade.py
Original file line number Diff line number Diff line change
Expand Up @@ -776,28 +776,28 @@ def test_stl_smesh_export_exception(self):
with self.assertRaises(ValueError):
blade.generate_stl_smesh(min_length=1, max_length=10, outfile_stl=55)

def test_blade_solid_max_deg_exception(self):
def test_solid_max_deg_exception(self):
blade = create_sample_blade_NACA()
blade.apply_transformations()
with self.assertRaises(ValueError):
blade.generate_blade_solid(
blade.generate_solid(
max_deg=-1,
display=False,
errors=None)

def test_blade_solid_errors_exception(self):
def test_solid_errors_exception(self):
blade = create_sample_blade_NACA()
blade.apply_transformations()
with self.assertRaises(ValueError):
blade.generate_blade_solid(
blade.generate_solid(
max_deg=-1,
display=False,
errors='tests/test_datasets/errors')

def test_generate_blade_solid(self):
def test_generate_solid(self):
blade = create_sample_blade_NACA()
blade.apply_transformations()
blade_solid = blade.generate_blade_solid(max_deg=2, display=False,
blade_solid = blade.generate_solid(max_deg=2, display=False,
errors=None)
self.assertIsInstance(blade_solid, TopoDS_Solid)

Expand Down
Loading