Skip to content

Commit

Permalink
Merge 412e85f into 94cb314
Browse files Browse the repository at this point in the history
  • Loading branch information
ggurioli committed Apr 15, 2021
2 parents 94cb314 + 412e85f commit 9f2acc7
Show file tree
Hide file tree
Showing 10 changed files with 91,361 additions and 15 deletions.
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):
"""
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 composing the propeller
:cvar OCC.Core.TopoDS.TopoDS_Solid shaft_solid: solid shaft
:cvar OCC.Core.TopoDS.TopoDS_Shell sewed_full_body: propeller with shaft shell
"""

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
: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()
52 changes: 52 additions & 0 deletions bladex/shaft.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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):
"""
Bottom-up parametrized shaft construction.
:param string filename: path (with the file extension) of a .iges file with
stored shaft information.
:cvar string filename: path (with the file extension) of a .iges file with
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

0 comments on commit 9f2acc7

Please sign in to comment.