diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 9033e3b..1cd9560 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -28,12 +28,13 @@ jobs: run: | python -m pip install --upgrade pip wheel poetry make install + poetry run pip install matplotlib - name: Install package run: | poetry run pip install . - name: Test with pytest run: | - make test + make test-all build_wheels: name: Build wheels diff --git a/.gitignore b/.gitignore index 6296433..fa851f3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,14 @@ doc/_templates /doc/latex/ .dir-locals.el /dist + + +# Generated by example scripts +blade.stl +circle.gif +lissajous34.gif +reuleaux-1.png +reuleaux-2.png +torus.g2 +torus.stl +trefoil.stl diff --git a/Makefile b/Makefile index 2d20623..aa6aac8 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install mypy lint pytest test fmt fmtcheck doc +.PHONY: install mypy lint fmt fmtcheck doc install: poetry install --with=dev @@ -9,9 +9,6 @@ mypy: lint: poetry run ruff splipy -pytest: - poetry run pytest --benchmark-skip - bench: poetry run pytest --benchmark-only @@ -23,18 +20,43 @@ fmtcheck: poetry run black splipy --check poetry run isort splipy --check -test: pytest doc: $(MAKE) -C doc html +# Test targets + +.PHONY: pytest +pytest: + poetry run pytest --benchmark-skip + +.PHONY: examples +examples: + poetry run python examples/circle_animation.py --ci + poetry run python examples/lissajous.py --ci + poetry run python examples/loft.py + poetry run python examples/read.py + poetry run python examples/reuleaux.py --ci + poetry run python examples/trefoil.py + poetry run python examples/write.py + +.PHONY: test # most common test commands for everyday development +test: pytest + +.PHONY: test-all # run from CI: the whole kitchen sink +test-all: test examples + + # Build targets (used from CI) +.PHONY: sdist sdist: poetry build -f sdist +.PHONY: wheel wheel: poetry build -f wheel +.PHONY: build build: sdist wheel diff --git a/examples/circle_animation.py b/examples/circle_animation.py index 26d922d..fe907f0 100644 --- a/examples/circle_animation.py +++ b/examples/circle_animation.py @@ -5,14 +5,17 @@ # Institute: Norwegian University of Science and Technology (NTNU) # Date: March 2016 # -from sys import path -path.append('../') +from sys import argv from splipy import * import splipy.curve_factory as curves import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation + +INTERACTIVE = "--ci" not in argv[1:] + + n = 250 # number of evaluation points c = curves.circle() # create the NURBS circle t = np.linspace(c.start(0), c.end(0), n) # parametric evaluation points @@ -37,7 +40,9 @@ def animate(i): # create and show the animation ani = animation.FuncAnimation(fig, animate, np.arange(1,n), interval=24) -plt.show() -# save results as an animated gif for web display (PS: this function call is slow) -# ani.save('circle.gif', writer='imagemagick', fps=30); +if INTERACTIVE: + plt.show() +else: + # save results as an animated gif for web display (PS: this function call is slow) + ani.save('circle.gif', writer='imagemagick', fps=30); diff --git a/examples/lissajous.py b/examples/lissajous.py index 3c1223b..7103538 100644 --- a/examples/lissajous.py +++ b/examples/lissajous.py @@ -9,8 +9,7 @@ # -from sys import path -path.append('../') +from sys import argv from splipy import curve_factory from math import gcd import numpy as np @@ -18,22 +17,26 @@ import matplotlib.animation as animation from math import pi + +INTERACTIVE = "--ci" not in argv[1:] + + def lissajous(a, b, d): - # request a,b integers, so we have closed, periodic curves - n = gcd(a,b) - N = (a/n) * (b/n) # number of periods before looping + # request a,b integers, so we have closed, periodic curves + n = gcd(a,b) + N = (a/n) * (b/n) # number of periods before looping - # error test input - if N > 1e4: # non-integer (a,b) or otherwise too irregular - raise Exception('Non-periodic', 'a,b must be integers (of moderate size)') + # error test input + if N > 1e4: # non-integer (a,b) or otherwise too irregular + raise Exception('Non-periodic', 'a,b must be integers (of moderate size)') - # compute a set of interpolation points - numb_pts = max(3*N, 100) # using 3N interpolation points is decent enough - t = np.linspace(0,2*pi/n, numb_pts) - x = np.array([np.sin(a*t + d), np.sin(b*t)]) + # compute a set of interpolation points + numb_pts = max(3*N, 100) # using 3N interpolation points is decent enough + t = np.linspace(0,2*pi/n, numb_pts) + x = np.array([np.sin(a*t + d), np.sin(b*t)]) - # do a cubic curve interpolation with periodic boundary conditions - return curve_factory.cubic_curve(x.T, curve_factory.Boundary.PERIODIC) + # do a cubic curve interpolation with periodic boundary conditions + return curve_factory.cubic_curve(x.T, curve_factory.Boundary.PERIODIC) ### main program ### @@ -73,7 +76,9 @@ def animate(i): # create and show the animation ani = animation.FuncAnimation(fig, animate, np.arange(0,int(2*n/fps)), interval=10) -plt.show() -# save results as an animated gif for web display (PS: this function call is slow) -# ani.save('lissajous34.gif', writer='imagemagick', fps=30); +if INTERACTIVE: + plt.show() +else: + # save results as an animated gif for web display (PS: this function call is slow) + ani.save('lissajous34.gif', writer='imagemagick', fps=30); diff --git a/examples/loft.py b/examples/loft.py index d3ed7ba..108d866 100644 --- a/examples/loft.py +++ b/examples/loft.py @@ -5,11 +5,6 @@ # Date: February 2021 # -# This is simply to allow the example to run from the example -# folder without the need for splipy to be installed globally on the system -from sys import path -path.append('../') - # Slightly more interesting input geometries. Read more on NACA wing # profiles here: https://en.wikipedia.org/wiki/NACA_airfoil from splipy.utils.NACA import NACA diff --git a/examples/read.py b/examples/read.py index bde7ba3..e729847 100644 --- a/examples/read.py +++ b/examples/read.py @@ -5,18 +5,19 @@ # Date: October 2017 # -from sys import path -path.append('../') +from pathlib import Path from splipy.io import * # G2 files are native GoTools (http://www.sintef.no/projectweb/geometry-toolkits/gotools/) +path = str(Path(__file__).parent) + # Read a single NURBS patch from the file 'sphere.g2' -with G2('sphere.g2') as my_file: +with G2(f'{path}/sphere.g2') as my_file: my_sphere = my_file.read() # Read multiple NURBS patches from the file 'teapot.g2' -with G2('teapot.g2') as my_file: +with G2(f'{path}/teapot.g2') as my_file: my_teapot = my_file.read() print(type(my_teapot)) # diff --git a/examples/reuleaux.py b/examples/reuleaux.py index 49d9976..41b5c2b 100644 --- a/examples/reuleaux.py +++ b/examples/reuleaux.py @@ -6,8 +6,7 @@ # Date: March 2016 # -from sys import path -path.append('../') +from sys import argv from splipy import * import splipy.curve_factory as curves import splipy.surface_factory as surfaces @@ -16,6 +15,10 @@ from mpl_toolkits.mplot3d import Axes3D from math import pi, cos, sin + +INTERACTIVE = "--ci" not in argv[1:] + + # create the three sides of the triangle, each consisting of a circle segment c1 = curves.circle_segment(pi/3) c2 = c1.clone().rotate(2*pi/3) + [1,0] @@ -30,7 +33,11 @@ x = c(t) # evaluate (x,y)-coordinates plt.plot(x[:,0], x[:,1]) plt.axis('equal') -plt.show() + +if INTERACTIVE: + plt.show() +else: + plt.savefig('reuleaux-1.png') # split the triangle in two, and align this with the y-axis two_parts = c.split((c.start(0) + c.end(0)) / 2.0) @@ -45,4 +52,8 @@ x = surf(u,v) ax = plt.axes(projection='3d') ax.plot_wireframe(x[:,:,0], x[:,:,1], x[:,:,2]) -plt.show() + +if INTERACTIVE: + plt.show() +else: + plt.savefig('reuleaux-2.png') diff --git a/examples/trefoil.py b/examples/trefoil.py index 75d3b05..e641fbd 100644 --- a/examples/trefoil.py +++ b/examples/trefoil.py @@ -5,9 +5,6 @@ # Date: June 2017 # -from sys import path -path.append('../') - from splipy import curve_factory, surface_factory from splipy.io import STL from numpy import pi, cos, sin @@ -35,4 +32,3 @@ def trefoil(t): ### write results to file. Use meshlab (www.meshlab.net) to view stl-files with STL('trefoil.stl') as f: f.write(srf, n=(150,30)) - diff --git a/examples/write.py b/examples/write.py index b6a6884..90947bc 100644 --- a/examples/write.py +++ b/examples/write.py @@ -5,8 +5,6 @@ # Date: March 2016 # -from sys import path -path.append('../') from splipy.io import G2, STL import splipy.surface_factory as surfaces