From 00fbff37a4efad90ca1341397d30d39409137151 Mon Sep 17 00:00:00 2001 From: Nicola Demo Date: Thu, 4 Dec 2025 15:49:43 +0100 Subject: [PATCH 1/6] cylinder shaft, minimal test --- bladex/__init__.py | 1 + bladex/cylinder_shaft.py | 53 ++++++++++++++++++++++++++++++++++++ tests/test_cylinder_shaft.py | 9 ++++++ 3 files changed, 63 insertions(+) create mode 100644 bladex/cylinder_shaft.py create mode 100644 tests/test_cylinder_shaft.py diff --git a/bladex/__init__.py b/bladex/__init__.py index e527a59..127c8c6 100644 --- a/bladex/__init__.py +++ b/bladex/__init__.py @@ -16,3 +16,4 @@ from .params import ParamFile from .ndinterpolator import RBF, reconstruct_f, scipy_bspline from .reversepropeller import ReversePropeller +from .cylinder_shaft import CylinderShaft \ No newline at end of file diff --git a/bladex/cylinder_shaft.py b/bladex/cylinder_shaft.py new file mode 100644 index 0000000..ce9efe2 --- /dev/null +++ b/bladex/cylinder_shaft.py @@ -0,0 +1,53 @@ +import OCC.Core.TopoDS +from OCC.Display.SimpleGui import init_display +from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCylinder +from OCC.Core.gp import gp_Pnt, gp_Dir, gp_Ax2 + + +class CylinderShaft(object): + """ + Cylinder shaft construction. + + :param float radius: radius of the cylinder shaft. Defaults to 1.0. + :param float height: height of the cylinder shaft. Defaults to 1.0. + :param list orientation: orientation vector of the cylinder shaft. Defaults + to [1.0, 0.0, 0.0], so along X axis. + :param list origin: origin point of the cylinder shaft. Defaults to + [0.0, 0.0, 0.0]. + """ + + def __init__(self, radius=1.0, height=1.0, orientation=None, origin=None): + self.radius = radius + self.height = height + + if orientation is None: + self.orientation = [1.0, 0.0, 0.0] # default orientation along X + + if origin is None: + self.origin = [0.0, 0.0, 0.0] # default origin at (0,0,0) + + def generate_solid(self): + """ + Generate a cylindrical shaft using the BRepBuilderAPI_MakeCylinder + algorithm. This method requires PythonOCC to be installed. + + :return: solid shaft + :rtype: OCC.Core.TopoDS.TopoDS_Solid + """ + + origin = gp_Pnt(*self.origin) + orientation = gp_Dir(*self.orientation) + ax2 = gp_Ax2(origin, orientation) + + shape = BRepPrimAPI_MakeCylinder(ax2, self.radius, self.height).Shape() + + return shape + + def display(self): + """ + Display the shaft. + """ + shaft_solid = self.generate_solid() + display, start_display = init_display()[:2] + display.DisplayShape(shaft_solid, update=True) + start_display() \ No newline at end of file diff --git a/tests/test_cylinder_shaft.py b/tests/test_cylinder_shaft.py new file mode 100644 index 0000000..937283f --- /dev/null +++ b/tests/test_cylinder_shaft.py @@ -0,0 +1,9 @@ +from unittest import TestCase +from bladex import CylinderShaft +from OCC.Core.TopoDS import TopoDS_Solid + + +def test_generate_solid_01(): + sh = CylinderShaft() + shaft_solid = sh.generate_solid() + assert isinstance(shaft_solid, TopoDS_Solid) \ No newline at end of file From a5dcac1dd961c7346b814b730286a6fe373f08c9 Mon Sep 17 00:00:00 2001 From: Nicola Demo Date: Fri, 5 Dec 2025 16:07:50 +0100 Subject: [PATCH 2/6] pythonocc update, pyproject --- bladex/blade.py | 2 +- bladex/shaft.py | 2 +- pyproject.toml | 51 +++++++++++++++++++++++++++++++++++++++++ setup.py | 61 ------------------------------------------------- 4 files changed, 53 insertions(+), 63 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/bladex/blade.py b/bladex/blade.py index 39f1a98..d91f256 100644 --- a/bladex/blade.py +++ b/bladex/blade.py @@ -960,7 +960,7 @@ def generate_solid(self, sewer.Perform() result_shell = sewer.SewedShape() solid_maker = BRepBuilderAPI_MakeSolid() - solid_maker.Add(OCC.Core.TopoDS.topods_Shell(result_shell)) + solid_maker.Add(OCC.Core.TopoDS.topods.Shell(result_shell)) if not solid_maker.IsDone(): raise RuntimeError('Unsuccessful assembling of solid blade') result_solid = solid_maker.Solid() diff --git a/bladex/shaft.py b/bladex/shaft.py index eeae8b0..2677f90 100644 --- a/bladex/shaft.py +++ b/bladex/shaft.py @@ -44,7 +44,7 @@ def generate_solid(self): sewer.Perform() result_sewed_shaft = sewer.SewedShape() shaft_solid_maker = BRepBuilderAPI_MakeSolid() - shaft_solid_maker.Add(OCC.Core.TopoDS.topods_Shell(result_sewed_shaft)) + 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() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..863e78c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,51 @@ +[build-system] +requires = ["setuptools>=61", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "BladeX" +version = "0.1.0" +description = "Python Blade Morphing" +readme = { file = "README.md", content-type = "text/markdown" } +requires-python = ">=3.9" +license = { text = "MIT" } +authors = [ + { name = "Marco Tezzele", email = "marcotez@gmail.com" }, + { name = "Mahmoud Gadalla", email = "gadalla.mah@gmail.com" } +] +keywords = ["blade-generation", "propeller", "iges", "procal"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Mathematics" +] +dependencies = [ + "numpy", + "scipy", + "matplotlib", +] + +[project.optional-dependencies] +docs = [ + "Sphinx", + "sphinx_rtd_theme" +] +test = [ + "pytest", + "pytest-cov" +] + +[project.urls] +Homepage = "https://github.com/mathLab/BladeX" + +[tool.setuptools] +include-package-data = true + +[tool.setuptools.packages.find] +include = ["bladex*"] + diff --git a/setup.py b/setup.py deleted file mode 100644 index 2020cbe..0000000 --- a/setup.py +++ /dev/null @@ -1,61 +0,0 @@ -from setuptools import setup, find_packages - -meta = {} -with open("bladex/meta.py") as fp: - exec(fp.read(), meta) - -# Package meta-data. -NAME = meta['__title__'] -DESCRIPTION = 'Python Blade Morphing' -URL = 'https://github.com/mathLab/BladeX' -MAIL = meta['__mail__'] -AUTHOR = meta['__author__'] -VERSION = meta['__version__'] -KEYWORDS = 'blade-generation propeller iges procal' - -REQUIRED = [ - 'numpy', 'scipy', 'matplotlib', 'Sphinx', 'sphinx_rtd_theme', 'smithers' -] - -EXTRAS = { - 'docs': ['Sphinx==1.4', 'sphinx_rtd_theme'], - 'test': ['pytest', 'pytest-cov'], -} - -LDESCRIPTION = ( - "BladeX is a Python package for geometrical parametrization and bottom-up " - "construction of propeller blades. It allows to generate and deform a " - "blade based on the radial distribution of its parameters such as pitch, " - "rake, skew, and the sectional foils' parameters such as chord and " - "camber. The package is ideally suited for parametric simulations on " - "large number of blade deformations. It provides an automated procedure " - "for the CAD generation, hence reducing the time and effort required for " - "modelling. The main scope of BladeX is to deal with propeller blades, " - "however it can be flexible to be applied on further applications with " - "analogous geometrical structures such as aircraft wings, turbomachinery, " - "or wind turbine blades." -) - -setup( - name=NAME, - version=VERSION, - description=DESCRIPTION, - long_description=LDESCRIPTION, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3.6', - 'Intended Audience :: Science/Research', - 'Topic :: Scientific/Engineering :: Mathematics' - ], - keywords=KEYWORDS, - url=URL, - author=AUTHOR, - author_email=MAIL, - license='MIT', - packages=find_packages(), - install_requires=REQUIRED, - extras_require=EXTRAS, - include_package_data=True, - zip_safe=False -) From 32b4b8988753125222b496600956d2696c246810 Mon Sep 17 00:00:00 2001 From: Nicola Demo Date: Fri, 5 Dec 2025 16:50:00 +0100 Subject: [PATCH 3/6] Update Python versions in CI workflow --- .github/workflows/testing_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing_pr.yml b/.github/workflows/testing_pr.yml index 8221e4f..d416067 100644 --- a/.github/workflows/testing_pr.yml +++ b/.github/workflows/testing_pr.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [windows-latest, macos-latest, ubuntu-latest] - python-version: [3.8, 3.9] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v4 From 97c5df5482f2cb242e698a71e7c19dc23402ca5d Mon Sep 17 00:00:00 2001 From: Nicola Demo Date: Fri, 5 Dec 2025 16:54:20 +0100 Subject: [PATCH 4/6] Refactor CylinderShaft class and fix display call --- bladex/cylinder_shaft.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bladex/cylinder_shaft.py b/bladex/cylinder_shaft.py index ce9efe2..f424366 100644 --- a/bladex/cylinder_shaft.py +++ b/bladex/cylinder_shaft.py @@ -1,10 +1,10 @@ -import OCC.Core.TopoDS +""" Cylinder Shaft """ from OCC.Display.SimpleGui import init_display from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCylinder from OCC.Core.gp import gp_Pnt, gp_Dir, gp_Ax2 -class CylinderShaft(object): +class CylinderShaft: """ Cylinder shaft construction. @@ -50,4 +50,4 @@ def display(self): shaft_solid = self.generate_solid() display, start_display = init_display()[:2] display.DisplayShape(shaft_solid, update=True) - start_display() \ No newline at end of file + start_display() From a2a5cd1f536c16d4b195da1238a2d4562bf0b550 Mon Sep 17 00:00:00 2001 From: Nicola Demo Date: Fri, 5 Dec 2025 16:55:57 +0100 Subject: [PATCH 5/6] Add 'CylinderShaft' to __all__ exports --- bladex/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bladex/__init__.py b/bladex/__init__.py index 127c8c6..d70f4de 100644 --- a/bladex/__init__.py +++ b/bladex/__init__.py @@ -1,9 +1,12 @@ """ BladeX init """ -__all__ = ['ProfileInterface', 'NacaProfile', 'CustomProfile', - 'ReversePropeller', 'Blade', 'Shaft', 'Propeller', 'Deformation', - 'ParamFile', 'RBF', 'reconstruct_f', 'scipy_bspline'] +__all__ = [ + 'ProfileInterface', 'NacaProfile', 'CustomProfile', + 'ReversePropeller', 'Blade', 'Shaft', 'CylinderShaft', + 'Propeller', 'Deformation', 'ParamFile', 'RBF', + 'reconstruct_f', 'scipy_bspline' +] from .meta import * from .profile import ProfileInterface @@ -16,4 +19,4 @@ from .params import ParamFile from .ndinterpolator import RBF, reconstruct_f, scipy_bspline from .reversepropeller import ReversePropeller -from .cylinder_shaft import CylinderShaft \ No newline at end of file +from .cylinder_shaft import CylinderShaft From 3a249ce6de1dfb22b22b6bb2791243ae0c9213d5 Mon Sep 17 00:00:00 2001 From: Nicola Demo Date: Fri, 5 Dec 2025 17:05:31 +0100 Subject: [PATCH 6/6] Update Python compatibility requirement in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b88f68a..4cc9c3b 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,10 @@ See the [**Examples**](#examples) section below and the [**Tutorials**](tutorial ## Dependencies and installation **BladeX** requires `numpy`, `scipy`, `matplotlib`, `sphinx` (for the documentation), and `pytest` (for the local test). They can be easily installed using `pip`. -**BladeX** is compatible with Python 3.6. Moreover, some of the modules require `OCC` to be installed for the `.iges` or `.stl` CAD generation. This requirement cannot be satisfied through `pip`, but the precompiled binaries are available on `conda` using the command: +**BladeX** is compatible with Python>=3.9. Moreover, some of the modules require `OCC` to be installed for the `.iges` or `.stl` CAD generation. This requirement cannot be satisfied through `pip`, but the precompiled binaries are available on `conda` using the command: ```bash -> conda install -c conda-forge pythonocc-core=7.4.0 +> conda install -c conda-forge pythonocc-core ``` You can also refer to `pythonocc.org` or `github.com/tpaviot/pythonocc-core` for further instructions.