From 86e9d5436ee8e948aaad7b8e08ab4d3f77c2075e Mon Sep 17 00:00:00 2001 From: Eivind Fonn Date: Sat, 12 Dec 2020 17:53:45 +0100 Subject: [PATCH] Miscellaneous changes for CI - Use Extension class in setup.py - Use only relative imports within splipy itself - Do not import from the splipy root module, only from the source files - Module names that are different from the root module re-exports - Some cleanup of imports --- .github/workflows/python-package.yml | 2 +- .gitignore | 1 + setup.py | 16 ++- splipy/__init__.py | 31 ++---- splipy/{BSplineBasis.py => basis.py} | 10 +- splipy/bench_evaluation_test.py | 45 --------- splipy/{Curve.py => curve.py} | 12 ++- splipy/curve_factory.py | 17 ++-- splipy/io/g2.py | 38 ++++--- splipy/io/grdecl.py | 22 +++-- splipy/io/ofoam.py | 5 +- splipy/io/spl.py | 11 ++- splipy/io/stl.py | 11 ++- splipy/io/svg.py | 14 ++- splipy/{SplineModel.py => splinemodel.py} | 13 ++- splipy/{SplineObject.py => splineobject.py} | 11 ++- splipy/{Surface.py => surface.py} | 10 +- splipy/surface_factory.py | 31 +++--- .../{TrimmedSurface.py => trimmedsurface.py} | 15 ++- splipy/utils/NACA.py | 8 +- splipy/utils/image.py | 9 +- splipy/utils/nutils.py | 5 +- splipy/utils/refinement.py | 4 +- splipy/utils/smooth.py | 4 +- splipy/{Volume.py => volume.py} | 7 +- splipy/volume_factory.py | 24 ++--- test/benchmark_test.py | 6 +- test/curve_factory_test.py | 92 ++++++++--------- test/curve_test.py | 17 ++-- test/splinemodel_test.py | 2 +- test/surface_factory_test.py | 99 ++++++++++--------- test/surface_test.py | 15 +-- test/trimmed_surface_test.py | 26 ++--- test/volume_factory_test.py | 56 ++++++----- test/volume_test.py | 10 +- 35 files changed, 369 insertions(+), 330 deletions(-) rename splipy/{BSplineBasis.py => basis.py} (99%) delete mode 100644 splipy/bench_evaluation_test.py rename splipy/{Curve.py => curve.py} (98%) rename splipy/{SplineModel.py => splinemodel.py} (99%) rename splipy/{SplineObject.py => splineobject.py} (99%) rename splipy/{Surface.py => surface.py} (98%) rename splipy/{TrimmedSurface.py => trimmedsurface.py} (96%) rename splipy/{Volume.py => volume.py} (97%) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 31eb9cc2..43fb6624 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -30,7 +30,7 @@ jobs: pip install -r requirements.dev.txt - name: Install package run: | - pip install . + pip install -vvv . - name: Test with pytest run: | pytest --benchmark-skip diff --git a/.gitignore b/.gitignore index c9ea6ad3..62964336 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ doc/_templates /doc/html/ /doc/latex/ .dir-locals.el +/dist diff --git a/setup.py b/setup.py index b980823d..a10730d4 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -from setuptools import setup +from distutils.extension import Extension +from setuptools import setup, find_packages from Cython.Build import cythonize import numpy as np @@ -18,7 +19,7 @@ maintainer='Kjetil Andre Johannessen', maintainer_email='kjetijo@gmail.com', license='GNU public license v3', - packages=['splipy', 'splipy.utils', 'splipy.io'], + packages=find_packages(), package_data={ 'splipy': ['templates/*.bpt'], }, @@ -30,8 +31,15 @@ 'FiniteElement': ["nutils>=4.0"], 'Images': ["opencv-python>=4.0"], }, - ext_modules=cythonize("splipy/basis_eval.pyx"), - include_dirs=[np.get_include()], + # ext_modules=cythonize("splipy/basis_eval.pyx"), + ext_modules=cythonize([ + Extension( + 'splipy.basis_eval', + ['splipy/basis_eval.pyx'], + include_dirs=[np.get_include()], + ) + ]), + # include_dirs=[np.get_include()], classifiers=[ 'Development Status :: 4 - Beta', 'Topic :: Multimedia :: Graphics :: 3D Modeling', diff --git a/splipy/__init__.py b/splipy/__init__.py index ce4f7672..fa692e2b 100644 --- a/splipy/__init__.py +++ b/splipy/__init__.py @@ -1,26 +1,9 @@ -# -*- coding: utf-8 -*- - -from splipy.BSplineBasis import BSplineBasis -from splipy.SplineObject import SplineObject -from splipy.Curve import Curve -from splipy.Surface import Surface -from splipy.Volume import Volume -from splipy.TrimmedSurface import TrimmedSurface - -# SplineModel imports io.G2 which imports TrimmedSurface, -# so we must import SplineModel after TrimmedSurface -from splipy.SplineModel import SplineModel +from .basis import BSplineBasis +from .splineobject import SplineObject +from .curve import Curve +from .surface import Surface +from .volume import Volume +from .trimmedsurface import TrimmedSurface +from .splinemodel import SplineModel __version__ = '1.4.0' -__all__ = ['BSplineBasis', - 'SplineObject', - 'Curve', - 'Surface', - 'Volume', - 'SplineModel', - 'TrimmedSurface', - 'curve_factory', - 'surface_factory', - 'volume_factory', - 'utils', - 'io'] diff --git a/splipy/BSplineBasis.py b/splipy/basis.py similarity index 99% rename from splipy/BSplineBasis.py rename to splipy/basis.py index f67aa902..a341da8f 100644 --- a/splipy/BSplineBasis.py +++ b/splipy/basis.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- -from splipy.utils import ensure_listlike -import splipy.state as state from bisect import bisect_right, bisect_left -import numpy as np import copy -from splipy import basis_eval + +import numpy as np from scipy.sparse import csr_matrix +from .utils import ensure_listlike +from . import basis_eval, state + __all__ = ['BSplineBasis'] @@ -118,6 +119,7 @@ def evaluate(self, t, d=0, from_right=True, sparse=False): points *i* :rtype: numpy.array """ + # for single-value input, wrap it into a list so it don't crash on the loop below t = ensure_listlike(t) t = np.array(t, dtype=np.float64) diff --git a/splipy/bench_evaluation_test.py b/splipy/bench_evaluation_test.py deleted file mode 100644 index 3222869f..00000000 --- a/splipy/bench_evaluation_test.py +++ /dev/null @@ -1,45 +0,0 @@ -from splipy import BSplineBasis -import numpy as np -import unittest -import pytest - - -def evaluate_old(basis, nviz): - t = np.linspace(0, basis.end(), nviz) - basis.evaluate_old(t) - -def evaluate_cython(basis, nviz): - t = np.linspace(0, basis.end(), nviz) - basis.evaluate(t) - -def evaluate_dense(basis, nviz): - t = np.linspace(0, basis.end(), nviz) - basis.evaluate_old(t, sparse=False) - -def evaluate_sparse(basis, nviz): - t = np.linspace(0, basis.end(), nviz) - basis.evaluate_old(t, sparse=True) - -n = 100 -p = 4 - -@pytest.mark.benchmark(group="evaluate-basis") -def test_evaluate_old(benchmark): - basis = BSplineBasis(p, [0]*(p-1) + list(range(n-p+2)) + [n-p+1]*(p-1)) - benchmark(evaluate_old, basis, 1000) - -@pytest.mark.benchmark(group="evaluate-basis") -def test_evaluate_cython(benchmark): - basis = BSplineBasis(p, [0]*(p-1) + list(range(n-p+2)) + [n-p+1]*(p-1)) - benchmark(evaluate_cython, basis, 1000) - -@pytest.mark.benchmark(group="evaluate-basis") -def test_evaluate_dense(benchmark): - basis = BSplineBasis(p, [0]*(p-1) + list(range(n-p+2)) + [n-p+1]*(p-1)) - benchmark(evaluate_dense, basis, 1000) - -@pytest.mark.benchmark(group="evaluate-basis") -def test_evaluate_sparse(benchmark): - basis = BSplineBasis(p, [0]*(p-1) + list(range(n-p+2)) + [n-p+1]*(p-1)) - benchmark(evaluate_sparse, basis, 1000) - diff --git a/splipy/Curve.py b/splipy/curve.py similarity index 98% rename from splipy/Curve.py rename to splipy/curve.py index 0e985a80..74eb36af 100644 --- a/splipy/Curve.py +++ b/splipy/curve.py @@ -1,13 +1,15 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis -from splipy import SplineObject -from splipy.utils import ensure_listlike, is_singleton from itertools import chain from bisect import bisect_left, bisect_right + import numpy as np import scipy.sparse.linalg as splinalg +from .basis import BSplineBasis +from .splineobject import SplineObject +from .utils import ensure_listlike, is_singleton + __all__ = ['Curve'] @@ -414,9 +416,9 @@ def error(self, target): this curve and a target curve .. math:: ||\\boldsymbol{x_h}(t)-\\boldsymbol{x}(t)||_{L^2(t_1,t_2)}^2 = \\int_{t_1}^{t_2} - |\\boldsymbol{x_h}(t)-\\boldsymbol{x}(t)|^2 dt, \\quad \\forall \;\\text{knots}\;t_1 < t_2 + |\\boldsymbol{x_h}(t)-\\boldsymbol{x}(t)|^2 dt, \\quad \\forall \\;\\text{knots}\\;t_1 < t_2 - .. math:: ||\\boldsymbol{x_h}(t)-\\boldsymbol{x}(t)||_{L^\infty} = \\max_t |\\boldsymbol{x_h}(t)-\\boldsymbol{x}(t)| + .. math:: ||\\boldsymbol{x_h}(t)-\\boldsymbol{x}(t)||_{L^\\infty} = \\max_t |\\boldsymbol{x_h}(t)-\\boldsymbol{x}(t)| :param function target: callable function which takes as input a vector of evaluation points t and gives as output a matrix x where diff --git a/splipy/curve_factory.py b/splipy/curve_factory.py index 38dd0cec..c631f5c8 100644 --- a/splipy/curve_factory.py +++ b/splipy/curve_factory.py @@ -3,16 +3,19 @@ """Handy utilities for creating curves.""" from math import pi, cos, sin, sqrt, ceil, atan2 -from splipy import Curve, BSplineBasis -from splipy.utils import flip_and_move_plane_geometry, rotate_local_x_axis -from numpy.linalg import norm -import splipy.state as state -import scipy.sparse.linalg as splinalg -import numpy as np -import scipy.sparse as sp import copy import inspect +import numpy as np +from numpy.linalg import norm +import scipy.sparse as sp +import scipy.sparse.linalg as splinalg + +from .curve import Curve +from .basis import BSplineBasis +from .utils import flip_and_move_plane_geometry, rotate_local_x_axis +from . import state + __all__ = ['Boundary', 'line', 'polygon', 'n_gon', 'circle', 'ellipse', 'circle_segment_from_three_points', 'circle_segment', 'interpolate', 'least_square_fit', 'cubic_curve', 'bezier', 'manipulate', 'fit'] diff --git a/splipy/io/g2.py b/splipy/io/g2.py index 69a8bc34..f81e453b 100644 --- a/splipy/io/g2.py +++ b/splipy/io/g2.py @@ -1,13 +1,19 @@ -import numpy as np from itertools import chain, product -from splipy import Curve, Surface, Volume, SplineObject, BSplineBasis, TrimmedSurface -from splipy.utils import flip_and_move_plane_geometry, rotate_local_x_axis -from .master import MasterIO -import splipy.surface_factory as SurfaceFactory -import splipy.curve_factory as CurveFactory -import splipy.state as state + +import numpy as np from numpy import sqrt, pi, savetxt +from ..curve import Curve +from ..surface import Surface +from ..volume import Volume +from ..splineobject import SplineObject +from ..basis import BSplineBasis +from ..trimmedsurface import TrimmedSurface +from ..utils import flip_and_move_plane_geometry, rotate_local_x_axis +from .. import surface_factory, curve_factory, state + +from .master import MasterIO + class G2(MasterIO): @@ -26,7 +32,7 @@ def circle(self): param = np.array(next(self.fstream).split(), dtype=float) reverse = next(self.fstream).strip() != '0' - result = CurveFactory.circle(r=r, center=center, normal=normal, xaxis=xaxis) + result = curve_factory.circle(r=r, center=center, normal=normal, xaxis=xaxis) result.reparam(param) if reverse: result.reverse() @@ -42,7 +48,7 @@ def ellipse(self): param = np.array(next(self.fstream).split(), dtype=float) reverse = next(self.fstream).strip() != '0' - result = CurveFactory.ellipse(r1=r1, r2=r2, center=center, normal=normal, xaxis=xaxis) + result = curve_factory.ellipse(r1=r1, r2=r2, center=center, normal=normal, xaxis=xaxis) result.reparam(param) if reverse: result.reverse() @@ -61,7 +67,7 @@ def line(self): if not finite: param = [-state.unlimited, +state.unlimited] - result = CurveFactory.line(s+d*param[0], s+d*param[1]) + result = curve_factory.line(s+d*param[0], s+d*param[1]) if reverse: result.reverse() return result @@ -96,7 +102,7 @@ def cylinder(self): center = center + z_axis*param_v[0] h = param_v[1] - param_v[0] - result = SurfaceFactory.cylinder(r=r, center=center, xaxis=x_axis, axis=z_axis, h=h) + result = surface_factory.cylinder(r=r, center=center, xaxis=x_axis, axis=z_axis, h=h) result.reparam(param_u, param_v) if swap: result.swap() @@ -115,11 +121,11 @@ def disc(self): swap = next(self.fstream).strip() != '0' if degen: - result = SurfaceFactory.disc(r=r, center=center, xaxis=x_axis, normal=z_axis, type='radial') + result = surface_factory.disc(r=r, center=center, xaxis=x_axis, normal=z_axis, type='radial') else: if not(np.allclose(np.diff(angles), pi/2, atol=1e-10)): raise RuntimeError('Unknown square parametrization of disc elementary surface') - result = SurfaceFactory.disc(r=r, center=center, xaxis=x_axis, normal=z_axis, type='square') + result = surface_factory.disc(r=r, center=center, xaxis=x_axis, normal=z_axis, type='square') result.reparam(param_u, param_v) if swap: result.swap() @@ -159,7 +165,7 @@ def torus(self): param_v = np.array(next(self.fstream).split(), dtype=float) swap = next(self.fstream).strip() != '0' - result = SurfaceFactory.torus(minor_r=r1, major_r=r2, center=center, normal=z_axis, xaxis=x_axis) + result = surface_factory.torus(minor_r=r1, major_r=r2, center=center, normal=z_axis, xaxis=x_axis) result.reparam(param_u, param_v) if(swap): result.swap() @@ -175,7 +181,7 @@ def sphere(self): param_v = np.array(next(self.fstream).split(), dtype=float) swap = next(self.fstream).strip() != '0' - result = SurfaceFactory.sphere(r=r, center=center, xaxis=x_axis, zaxis=z_axis).swap() + result = surface_factory.sphere(r=r, center=center, xaxis=x_axis, zaxis=z_axis).swap() if swap: result.swap() result.reparam(param_u, param_v) @@ -210,7 +216,7 @@ def surface_of_linear_extrusion(self): param_v=[-state.unlimited, +state.unlimited] swap = next(self.fstream).strip() != '0' - result = SurfaceFactory.extrude(crv + normal*param_v[0], normal*(param_v[1]-param_v[0])) + result = surface_factory.extrude(crv + normal*param_v[0], normal*(param_v[1]-param_v[0])) result.reparam(param_u, param_v) if swap: diff --git a/splipy/io/grdecl.py b/splipy/io/grdecl.py index c5728f70..f5091230 100644 --- a/splipy/io/grdecl.py +++ b/splipy/io/grdecl.py @@ -1,17 +1,23 @@ -import numpy as np from itertools import product, chain -from splipy import Surface, Volume, SplineObject, BSplineBasis -from splipy import surface_factory, volume_factory, curve_factory -from splipy.io import G2 -from splipy.utils import ensure_listlike -from .master import MasterIO import re import warnings -from scipy.spatial import Delaunay -from scipy.spatial.qhull import QhullError + +import numpy as np from tqdm import tqdm import cv2 import h5py +from scipy.spatial import Delaunay +from scipy.spatial.qhull import QhullError + +from ..surface import Surface +from ..volume import Volume +from ..splineobject import SplineObject +from ..basis import BSplineBasis +from ..utils import ensure_listlike +from .. import surface_factory, curve_factory, volume_factory + +from .master import MasterIO +from .g2 import G2 class Box(object): diff --git a/splipy/io/ofoam.py b/splipy/io/ofoam.py index 581c48f9..5b45979a 100644 --- a/splipy/io/ofoam.py +++ b/splipy/io/ofoam.py @@ -1,10 +1,11 @@ from itertools import groupby -import numpy as np from operator import itemgetter from os.path import exists, isdir, join from os import makedirs -from splipy import SplineModel +import numpy as np + +from ..splinemodel import SplineModel class OpenFOAM(object): diff --git a/splipy/io/spl.py b/splipy/io/spl.py index 68ee4343..938cc8e1 100644 --- a/splipy/io/spl.py +++ b/splipy/io/spl.py @@ -1,6 +1,13 @@ -import numpy as np from itertools import islice -from splipy import Curve, Surface, Volume, SplineObject, BSplineBasis + +import numpy as np + +from ..curve import Curve +from ..surface import Surface +from ..volume import Volume +from ..splineobject import SplineObject +from ..basis import BSplineBasis + from .master import MasterIO diff --git a/splipy/io/stl.py b/splipy/io/stl.py index 22d9aaaf..2f4bd492 100644 --- a/splipy/io/stl.py +++ b/splipy/io/stl.py @@ -1,11 +1,17 @@ #coding:utf-8 import struct + import numpy as np -from splipy.utils import ensure_listlike -from splipy import SplineModel, Surface, Volume + +from ..surface import Surface +from ..volume import Volume +from ..utils import ensure_listlike +from ..splinemodel import SplineModel + from .master import MasterIO + ASCII_FACET = """facet normal 0 0 0 outer loop vertex {face[0][0]:.4f} {face[0][1]:.4f} {face[0][2]:.4f} @@ -18,6 +24,7 @@ BINARY_HEADER ="80sI" BINARY_FACET = "12fH" + class ASCII_STL_Writer(object): """ Export 3D objects build of 3 or 4 vertices as ASCII STL file. """ diff --git a/splipy/io/svg.py b/splipy/io/svg.py index a0aa63eb..068feef5 100644 --- a/splipy/io/svg.py +++ b/splipy/io/svg.py @@ -1,12 +1,18 @@ -from splipy import Curve, Surface, SplineObject, BSplineBasis -import splipy.curve_factory as curve_factory -import splipy.state as state import xml.etree.ElementTree as etree from xml.dom import minidom -import numpy as np import re + +import numpy as np + +from ..curve import Curve +from ..surface import Surface +from ..splineobject import SplineObject +from ..basis import BSplineBasis +from .. import curve_factory, state + from .master import MasterIO + def read_number_and_unit(mystring): unit = '' try: diff --git a/splipy/SplineModel.py b/splipy/splinemodel.py similarity index 99% rename from splipy/SplineModel.py rename to splipy/splinemodel.py index 720c6b13..9416d8e2 100644 --- a/splipy/SplineModel.py +++ b/splipy/splinemodel.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- -from splipy import SplineObject -from splipy.utils import check_section, sections, section_from_index, section_to_index, uniquify, is_right_hand -from splipy.io import G2 -import splipy.state as state -import numpy as np from collections import Counter, OrderedDict, namedtuple from itertools import chain, product, permutations, islice +import numpy as np + +from .splineobject import SplineObject +from .utils import check_section, sections, section_from_index, section_to_index, uniquify, is_right_hand +from . import state + try: from collections.abc import MutableMapping except ImportError: @@ -971,5 +972,7 @@ def write(self, filename): with open(filename + '-topologysets.xinp', 'wb') as f: f.write('\n'.join(lines).encode('utf-8') + b'\n') + # Import here to avoid circular dependencies + from .io import G2 with G2(filename + '.g2') as f: f.write([n.obj for n in self.nodes]) diff --git a/splipy/SplineObject.py b/splipy/splineobject.py similarity index 99% rename from splipy/SplineObject.py rename to splipy/splineobject.py index 4e25c9a6..d7132919 100644 --- a/splipy/SplineObject.py +++ b/splipy/splineobject.py @@ -5,10 +5,13 @@ from operator import attrgetter, methodcaller from itertools import chain, product from bisect import bisect_left -from splipy import BSplineBasis -from splipy.utils import reshape, rotation_matrix, is_singleton, ensure_listlike,\ - check_direction, ensure_flatlist, check_section, sections,\ - raise_order_1D + +from .basis import BSplineBasis +from .utils import ( + reshape, rotation_matrix, is_singleton, ensure_listlike, + check_direction, ensure_flatlist, check_section, sections, + raise_order_1D +) __all__ = ['SplineObject'] diff --git a/splipy/Surface.py b/splipy/surface.py similarity index 98% rename from splipy/Surface.py rename to splipy/surface.py index 012353ea..22b74b09 100644 --- a/splipy/Surface.py +++ b/splipy/surface.py @@ -1,13 +1,15 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis, Curve, SplineObject -from splipy.SplineObject import evaluate -from splipy.utils import is_singleton -from splipy.utils import ensure_listlike, check_direction, sections from bisect import bisect_left from itertools import chain + import numpy as np +from .basis import BSplineBasis +from .curve import Curve +from .splineobject import SplineObject, evaluate +from .utils import is_singleton, ensure_listlike, check_direction, sections + __all__ = ['Surface'] diff --git a/splipy/surface_factory.py b/splipy/surface_factory.py index 2e4a1c5d..f946f579 100644 --- a/splipy/surface_factory.py +++ b/splipy/surface_factory.py @@ -2,17 +2,20 @@ """Handy utilities for creating surfaces.""" -from splipy import BSplineBasis, Curve, Surface from math import pi, sqrt, atan2 -from splipy.utils import flip_and_move_plane_geometry, rotate_local_x_axis -from splipy.utils.nutils import controlpoints, multiplicities, degree -import splipy.curve_factory as CurveFactory -import splipy.state as state import inspect -import numpy as np import os from os.path import dirname, realpath, join +import numpy as np + +from .basis import BSplineBasis +from .curve import Curve +from .surface import Surface +from .utils import flip_and_move_plane_geometry, rotate_local_x_axis +from .utils.nutils import controlpoints, multiplicities, degree +from . import curve_factory, state + __all__ = ['square', 'disc', 'sphere', 'extrude', 'revolve', 'cylinder', 'torus', 'edge_curves', 'thicken', 'sweep', 'loft', 'interpolate', 'least_square_fit', 'teapot'] @@ -44,7 +47,7 @@ def disc(r=1, center=(0,0,0), normal=(0,0,1), type='radial', xaxis=(1,0,0)): :rtype: Surface """ if type == 'radial': - c1 = CurveFactory.circle(r, center=center, normal=normal, xaxis=xaxis) + c1 = curve_factory.circle(r, center=center, normal=normal, xaxis=xaxis) c2 = flip_and_move_plane_geometry(c1*0, center, normal) result = edge_curves(c2, c1) result.swap() @@ -78,7 +81,7 @@ def sphere(r=1, center=(0,0,0), zaxis=(0,0,1), xaxis=(1,0,0)): :return: The spherical shell :rtype: Surface """ - circle = CurveFactory.circle_segment(pi, r) + circle = curve_factory.circle_segment(pi, r) circle.rotate(-pi / 2) circle.rotate(pi / 2, (1, 0, 0)) # flip up into xz-plane result = revolve(circle) @@ -126,7 +129,7 @@ def revolve(curve, theta=2 * pi, axis=(0,0,1)): curve.rotate(-normal_theta, [0,0,1]) curve.rotate(-normal_phi, [0,1,0]) - circle_seg = CurveFactory.circle_segment(theta) + circle_seg = curve_factory.circle_segment(theta) n = len(curve) # number of control points of the curve m = len(circle_seg) # number of control points of the sweep @@ -162,7 +165,7 @@ def cylinder(r=1, h=1, center=(0,0,0), axis=(0,0,1), xaxis=(1,0,0)): :return: The cylinder shell :rtype: Surface """ - return extrude(CurveFactory.circle(r, center, axis, xaxis=xaxis), h*np.array(axis)) + return extrude(curve_factory.circle(r, center, axis, xaxis=xaxis), h*np.array(axis)) def torus(minor_r=1, major_r=3, center=(0,0,0), normal=(0,0,1), xaxis=(1,0,0)): @@ -177,7 +180,7 @@ def torus(minor_r=1, major_r=3, center=(0,0,0), normal=(0,0,1), xaxis=(1,0,0)): :return: A periodic torus :rtype: Surface """ - circle = CurveFactory.circle(minor_r) + circle = curve_factory.circle(minor_r) circle.rotate(pi / 2, (1, 0, 0)) # flip up into xz-plane circle.translate((major_r, 0, 0)) # move into position to spin around z-axis result = revolve(circle) @@ -611,12 +614,12 @@ def thicken(curve, amount): left_points[ :, 0] = x[:, 0] + v[:, 1] * amount # x at top left_points[ :, 1] = x[:, 1] - v[:, 0] * amount # y at top # perform interpolation on each side - right = CurveFactory.interpolate(right_points, curve.bases[0]) - left = CurveFactory.interpolate(left_points, curve.bases[0]) + right = curve_factory.interpolate(right_points, curve.bases[0]) + left = curve_factory.interpolate(left_points, curve.bases[0]) return edge_curves(right, left) else: # dimension=3, we will create a surrounding tube - return sweep(curve, CurveFactory.circle(r=amount)) + return sweep(curve, curve_factory.circle(r=amount)) def sweep(path, shape): """ Generate a surface by sweeping a shape along a path diff --git a/splipy/TrimmedSurface.py b/splipy/trimmedsurface.py similarity index 96% rename from splipy/TrimmedSurface.py rename to splipy/trimmedsurface.py index 5154f38c..f5d4a85b 100644 --- a/splipy/TrimmedSurface.py +++ b/splipy/trimmedsurface.py @@ -1,12 +1,17 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis, Surface, Curve, SplineObject -from splipy.utils import ensure_listlike, check_direction, sections -import splipy.state as state -from scipy.spatial import ConvexHull -import numpy as np from math import pi +import numpy as np +from scipy.spatial import ConvexHull + +from .basis import BSplineBasis +from .curve import Curve +from .surface import Surface +from .splineobject import SplineObject +from .utils import ensure_listlike, check_direction, sections +from . import state + __all__ = ['TrimmedSurface'] diff --git a/splipy/utils/NACA.py b/splipy/utils/NACA.py index d4e39097..5c9daead 100644 --- a/splipy/utils/NACA.py +++ b/splipy/utils/NACA.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- -from splipy import Curve, BSplineBasis -import splipy.surface_factory as SurfaceFactory import numpy as np +from ..curve import Curve +from ..basis import BSplineBasis +from .. import surface_factory + __all__ = ['camber', 'NACA'] @@ -85,7 +87,7 @@ def thickness(x): a4 = -0.1036 if closed else -0.1015 return T / 0.2 * (a0 * np.sqrt(x) + a1 * x + a2 * x**2 + a3 * x**3 + a4 * x**4) - surf = SurfaceFactory.thicken(center_line, thickness) + surf = surface_factory.thicken(center_line, thickness) _, _, top, btm = surf.edges() top.reverse() top.append(btm) diff --git a/splipy/utils/image.py b/splipy/utils/image.py index 2252977d..7028c6bf 100644 --- a/splipy/utils/image.py +++ b/splipy/utils/image.py @@ -2,12 +2,16 @@ __doc__ = 'Implementation of image based mesh generation.' -from splipy import BSplineBasis, curve_factory, surface_factory from math import sqrt -import numpy as np import sys import warnings +import numpy as np + +from ..basis import BSplineBasis +from .. import curve_factory, surface_factory + + def get_corners(X, L=50, R=30, D=15): """Detects corners of traced outlines using the SAM04 algorithm. @@ -283,4 +287,3 @@ def image_convex_surface(filename): corners = kinks[0:4] return surface_factory.edge_curves(crv.split(corners)) - diff --git a/splipy/utils/nutils.py b/splipy/utils/nutils.py index bd9d6fa9..04245e59 100644 --- a/splipy/utils/nutils.py +++ b/splipy/utils/nutils.py @@ -1,8 +1,11 @@ __doc__ = 'Implementation of convenience methods with respect to nutils integration.' -from splipy import Curve, Surface, Volume import numpy as np +from ..curve import Curve +from ..surface import Surface +from ..volume import Volume + def controlpoints(spline): """ Return controlpoints according to nutils ordering """ diff --git a/splipy/utils/refinement.py b/splipy/utils/refinement.py index da7560a1..0fc979f9 100644 --- a/splipy/utils/refinement.py +++ b/splipy/utils/refinement.py @@ -1,9 +1,11 @@ __doc__ = 'Implementation of various refinement schemes.' -from splipy.utils import ensure_listlike, check_direction from math import atan, pi, tan + import numpy as np +from . import ensure_listlike, check_direction + # TODO: put control over these tolerances somewhere. Modstate in splipy seems # to be the place for it, but we can't let splipy.utils influence the # structure of splipy. diff --git a/splipy/utils/smooth.py b/splipy/utils/smooth.py index d82c0933..84023982 100644 --- a/splipy/utils/smooth.py +++ b/splipy/utils/smooth.py @@ -2,7 +2,9 @@ from scipy import ndimage import numpy as np -from splipy.utils import check_direction + +from . import check_direction + def smooth(obj, comp=None): """Smooth an object by setting the interior control points to the average of diff --git a/splipy/Volume.py b/splipy/volume.py similarity index 97% rename from splipy/Volume.py rename to splipy/volume.py index 27351614..0d468196 100644 --- a/splipy/Volume.py +++ b/splipy/volume.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis, SplineObject -from splipy.utils import ensure_listlike, check_direction, sections from itertools import chain + import numpy as np +from .basis import BSplineBasis +from .splineobject import SplineObject +from .utils import ensure_listlike, check_direction, sections + __all__ = ['Volume'] diff --git a/splipy/volume_factory.py b/splipy/volume_factory.py index b2b39968..56799484 100644 --- a/splipy/volume_factory.py +++ b/splipy/volume_factory.py @@ -2,13 +2,15 @@ """Handy utilities for creating volumes.""" -from math import pi, sqrt -import numpy as np from math import pi, sqrt, atan2 -from splipy import Surface, Volume, BSplineBasis -from splipy.utils import flip_and_move_plane_geometry, rotate_local_x_axis -import splipy.curve_factory as CurveFactory -import splipy.surface_factory as SurfaceFactory + +import numpy as np + +from .basis import BSplineBasis +from .surface import Surface +from .volume import Volume +from .utils import flip_and_move_plane_geometry, rotate_local_x_axis +from . import curve_factory, surface_factory __all__ = ['cube', 'sphere', 'revolve', 'cylinder', 'extrude', 'edge_surfaces', 'loft', 'interpolate', 'least_square_fit'] @@ -38,7 +40,7 @@ def sphere(r=1, center=(0,0,0), type='radial'): :rtype: Volume """ if type == 'radial': - shell = SurfaceFactory.sphere(r, center) + shell = surface_factory.sphere(r, center) midpoint = shell*0 + center return edge_surfaces(shell, midpoint) elif type == 'square': @@ -121,7 +123,7 @@ def revolve(surf, theta=2 * pi, axis=(0,0,1)): surf.rotate(-normal_theta, [0,0,1]) surf.rotate(-normal_phi, [0,1,0]) - path = CurveFactory.circle_segment(theta=theta) + path = curve_factory.circle_segment(theta=theta) n = len(surf) # number of control points of the surface m = len(path) # number of control points of the sweep @@ -154,7 +156,7 @@ def torus(minor_r=1, major_r=3, center=(0,0,0), normal=(0,0,1), xaxis=(1,0,0), t :rtype: Volume """ - disc = SurfaceFactory.disc(minor_r, type=type) + disc = surface_factory.disc(minor_r, type=type) disc.rotate(pi / 2, (1, 0, 0)) # flip up into xz-plane disc.translate((major_r, 0, 0)) # move into position to spin around z-axis result = revolve(disc) @@ -174,7 +176,7 @@ def cylinder(r=1, h=1, center=(0,0,0), axis=(0,0,1), xaxis=(1,0,0), type='radial :return: The cylinder :rtype: Volume """ - return extrude(SurfaceFactory.disc(r, center, axis, xaxis=xaxis, type=type), h*np.array(axis)) + return extrude(surface_factory.disc(r, center, axis, xaxis=xaxis, type=type), h*np.array(axis)) def extrude(surf, amount): @@ -340,7 +342,7 @@ def loft(*surfaces): # make sure everything has the same dimension since we need to compute length surfaces = [s.clone().set_dimension(3) for s in surfaces] if len(surfaces)==2: - return SurfaceFactory.edge_curves(surfaces) + return surface_factory.edge_curves(surfaces) elif len(surfaces)==3: # can't do cubic spline interpolation, so we'll do quadratic basis3 = BSplineBasis(3) diff --git a/test/benchmark_test.py b/test/benchmark_test.py index 572efaed..9ce5b781 100644 --- a/test/benchmark_test.py +++ b/test/benchmark_test.py @@ -5,11 +5,11 @@ def get_spline(spline, n, p, rational=False): basis = BSplineBasis(p, [0]*(p-1) + list(range(n-p+2)) + [n-p+1]*(p-1)) - if spline is 'curve': + if spline == 'curve': return Curve(basis, rational=rational) - elif spline is 'surface': + elif spline == 'surface': return Surface(basis, basis, rational=rational) - elif spline is 'volume': + elif spline == 'volume': return Volume(basis, basis, basis, rational=rational) return None diff --git a/test/curve_factory_test.py b/test/curve_factory_test.py index 458187bb..f8976882 100644 --- a/test/curve_factory_test.py +++ b/test/curve_factory_test.py @@ -1,22 +1,26 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis, Curve -import splipy.curve_factory as CurveFactory from math import pi, sqrt, cos, sin +import unittest + import numpy as np from numpy.linalg import norm -import unittest + +from splipy import BSplineBasis, Curve +import splipy.curve_factory as cf + try: import nutils has_nutils = True except ImportError: has_nutils = False + class TestCurveFactory(unittest.TestCase): def test_line(self): # 2D line - c = CurveFactory.line([1, 1], [2, 0]) + c = cf.line([1, 1], [2, 0]) self.assertEqual(c.order(0), 2) # linear discretization self.assertEqual(len(c), 2) # two control points self.assertEqual(c.dimension, 2) @@ -26,14 +30,14 @@ def test_line(self): self.assertEqual(c[-1][1], 0) # 3D line - c = CurveFactory.line([1, 2, 3], [8, 7, 6]) + c = cf.line([1, 2, 3], [8, 7, 6]) self.assertEqual(c.order(0), 2) # linear discretization self.assertEqual(len(c), 2) # two control points self.assertEqual(c.dimension, 3) def test_n_gon(self): # test default 5 side n-gon - c = CurveFactory.n_gon() + c = cf.n_gon() self.assertEqual(len(c), 5) self.assertEqual(len(c.knots(0, True)), 8) self.assertEqual(c.order(0), 2) @@ -45,7 +49,7 @@ def test_n_gon(self): self.assertAlmostEqual(c.evaluate(c.end(0) / 5.0 * 4)[1], sin(2 * pi / 5 * 4)) # test a radius 3 septagon - c = CurveFactory.n_gon(n=7, r=3) + c = cf.n_gon(n=7, r=3) self.assertEqual(len(c), 7) # evaluate at third corner (clockwise from (1,0) ) self.assertAlmostEqual(c.evaluate(c.end(0) / 7.0)[0], 3 * cos(2 * pi / 7)) @@ -53,13 +57,13 @@ def test_n_gon(self): # test errors with self.assertRaises(ValueError): - c = CurveFactory.n_gon(r=-2.5) + c = cf.n_gon(r=-2.5) with self.assertRaises(ValueError): - c = CurveFactory.n_gon(n=1) + c = cf.n_gon(n=1) def test_polygon(self): pts = [[1,0], [1,1], [0,1], [0,2], [6,2]] - c = CurveFactory.polygon(pts) + c = cf.polygon(pts) expected_knots = [0,0,1,2,3,9,9] actual_knots = c.knots(0,True) @@ -68,7 +72,7 @@ def test_polygon(self): self.assertEqual(c.dimension, 2) self.assertAlmostEqual(norm(expected_knots - actual_knots), 0.0) - c = CurveFactory.polygon([0,0], [1,0], [0,1], [-1,0], relative=True) + c = cf.polygon([0,0], [1,0], [0,1], [-1,0], relative=True) self.assertEqual(len(c), 4) self.assertAlmostEqual(c[2][0], 1) self.assertAlmostEqual(c[2][1], 1) @@ -78,7 +82,7 @@ def test_polygon(self): def test_circle(self): # unit circle of radius 1 - c = CurveFactory.circle() + c = cf.circle() self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) # test evaluation at 25 points for radius=1 @@ -101,7 +105,7 @@ def test_circle(self): self.assertAlmostEqual(pt[1], 0.0) # circle of radius different from 1 - c = CurveFactory.circle(3) + c = cf.circle(3) # test evaluation at 25 points for radius=3, outside domain t = np.linspace(c.start(0) - 3, c.end(0) + 2, 25) x = c.evaluate(t) @@ -110,7 +114,7 @@ def test_circle(self): self.assertAlmostEqual(c.length(), 6*pi, places=3) # circle not at origin - c = CurveFactory.circle(1, center=(1,0,0), normal=(1,1,1)) + c = cf.circle(1, center=(1,0,0), normal=(1,1,1)) # test evaluation at 25 points t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) @@ -120,7 +124,7 @@ def test_circle(self): self.assertAlmostEqual(c.length(), 2*pi, places=3) # test alt circle - c = CurveFactory.circle(r=3, type='p4C1') + c = cf.circle(r=3, type='p4C1') t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) self.assertTrue(np.allclose(x[:,0]**2 + x[:,1]**2, 3.0**2)) @@ -128,7 +132,7 @@ def test_circle(self): self.assertEqual(c.continuity(k), 1) # test circle with different xaxis - c = CurveFactory.circle(xaxis=(1,1,0)) + c = cf.circle(xaxis=(1,1,0)) t = np.linspace(c.start(0), c.end(0), 5) x = c.evaluate(t) self.assertTrue(np.allclose(x[:,0]**2 + x[:,1]**2, 1.0**2)) @@ -136,7 +140,7 @@ def test_circle(self): self.assertTrue(np.allclose(x[1,:], [-1/sqrt(2), 1/sqrt(2)])) # test using all parameters (in x+y+z=1 plane) - c = CurveFactory.circle(r=sqrt(2), normal=(1,1,1), center=(1,0,0), xaxis=(-1,1,0)) + c = cf.circle(r=sqrt(2), normal=(1,1,1), center=(1,0,0), xaxis=(-1,1,0)) t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) self.assertTrue(np.allclose((x[:,0]-1)**2 + x[:,1]**2 + x[:,2]**2, 2.0)) @@ -145,12 +149,12 @@ def test_circle(self): # test errors and exceptions with self.assertRaises(ValueError): - c = CurveFactory.circle(-2.5) # negative radius + c = cf.circle(-2.5) # negative radius def test_circle_segment(self): # basic circle segment - c = CurveFactory.circle_segment(pi * 0.9) + c = cf.circle_segment(pi * 0.9) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) # test evaluation at 25 points for radius=1 @@ -160,7 +164,7 @@ def test_circle_segment(self): self.assertAlmostEqual(norm(pt, 2), 1.0) # check radius=1 # radius 7 circle segment - c = CurveFactory.circle_segment(pi * 1.87, 7) + c = cf.circle_segment(pi * 1.87, 7) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) # test evaluation at 25 points for radius=7 @@ -170,14 +174,14 @@ def test_circle_segment(self): self.assertAlmostEqual(norm(pt, 2), 7.0) # check radius=7 # negative theta - c = CurveFactory.circle_segment(-pi/2) + c = cf.circle_segment(-pi/2) self.assertEqual(c.rational, True) self.assertTrue(np.allclose(c(0), [1,0])) self.assertTrue(np.allclose(c(-pi/4), [1/sqrt(2),-1/sqrt(2)])) self.assertTrue(np.allclose(c(-pi/2), [0,-1])) # boundary case with one knot span circle segment - c = CurveFactory.circle_segment(2 * pi / 3) + c = cf.circle_segment(2 * pi / 3) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) self.assertEqual(len(c.knots(0)), 2) @@ -189,7 +193,7 @@ def test_circle_segment(self): self.assertAlmostEqual(norm(pt, 2), 1.0) # check radius=1 # boundary case with full circle - c = CurveFactory.circle_segment(2 * pi) + c = cf.circle_segment(2 * pi) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) self.assertEqual(len(c.knots(0)), 5) @@ -202,15 +206,15 @@ def test_circle_segment(self): # test errors and exceptions with self.assertRaises(ValueError): - c = CurveFactory.circle_segment(3 * pi) # outside domain + c = cf.circle_segment(3 * pi) # outside domain with self.assertRaises(ValueError): - c = CurveFactory.circle_segment(-3 * pi) # outside domain + c = cf.circle_segment(-3 * pi) # outside domain with self.assertRaises(ValueError): - c = CurveFactory.circle_segment(pi, -2) # negative radius + c = cf.circle_segment(pi, -2) # negative radius def test_circle_segment_from_three_points(self): # quarter circle (xy-plane) - c = CurveFactory.circle_segment_from_three_points([1,0], [1.0/sqrt(2), 1.0/sqrt(2)], [0,1]) + c = cf.circle_segment_from_three_points([1,0], [1.0/sqrt(2), 1.0/sqrt(2)], [0,1]) t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) self.assertEqual(c.dimension, 2) @@ -221,7 +225,7 @@ def test_circle_segment_from_three_points(self): self.assertTrue(np.allclose(c[-1], [0,1,1])) # quarter circle (x=y plane) - c = CurveFactory.circle_segment_from_three_points([1.0/sqrt(2), 1.0/sqrt(2),0], [.5, .5, 1/sqrt(2)], [0,0,1]) + c = cf.circle_segment_from_three_points([1.0/sqrt(2), 1.0/sqrt(2),0], [.5, .5, 1/sqrt(2)], [0,0,1]) t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) self.assertEqual(c.dimension, 3) @@ -232,7 +236,7 @@ def test_circle_segment_from_three_points(self): self.assertTrue(np.allclose(c[-1], [0,0,1,1])) # check endpoints # one-eight circle ([1,-1,0] normal, center in (0,0,0) ) - c = CurveFactory.circle_segment_from_three_points([.5, .5, 1/sqrt(2)], [2**(-3.0/2), 2**(-3.0/2), sqrt(3)/2], [0,0,1]) + c = cf.circle_segment_from_three_points([.5, .5, 1/sqrt(2)], [2**(-3.0/2), 2**(-3.0/2), sqrt(3)/2], [0,0,1]) t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): @@ -241,7 +245,7 @@ def test_circle_segment_from_three_points(self): self.assertTrue(np.allclose(c[-1], [0,0,1,1])) # check endpoints # one-eight circle ([1,-1,0] normal, center in (1,0,0)) - c = CurveFactory.circle_segment_from_three_points([1.5, .5, 1/sqrt(2)], [1+2**(-3.0/2), 2**(-3.0/2), sqrt(3)/2], [1,0,1]) + c = cf.circle_segment_from_three_points([1.5, .5, 1/sqrt(2)], [1+2**(-3.0/2), 2**(-3.0/2), sqrt(3)/2], [1,0,1]) t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): @@ -250,7 +254,7 @@ def test_circle_segment_from_three_points(self): self.assertTrue(np.allclose(c[-1], [1,0,1,1])) # check endpoints # theta > pi - c = CurveFactory.circle_segment_from_three_points([4,0], [0,4], [0,-4]) + c = cf.circle_segment_from_three_points([4,0], [0,4], [0,-4]) self.assertTrue(np.allclose(c[0], [4, 0, 1])) # check startpoint self.assertTrue(np.allclose(c[-1], [0,-4, 1])) # check endpoint t = (c.start(0)+c.end(0))/2.0 @@ -261,7 +265,7 @@ def test_circle_segment_from_three_points(self): self.assertAlmostEqual(norm(pt), 4.0) # check radius=4 # theta > pi in x=3/4 y plane (r=5), center=(4,3,0) - c = CurveFactory.circle_segment_from_three_points([4,3,-5], [8,6,0], [0,0,0]) + c = cf.circle_segment_from_three_points([4,3,-5], [8,6,0], [0,0,0]) self.assertTrue(np.allclose(c[0], [4, 3,-5, 1])) # check startpoint self.assertTrue(np.allclose(c[-1], [0, 0, 0, 1])) # check endpoint t = np.linspace(c.start(0), c.end(0), 25) @@ -281,7 +285,7 @@ def test_cubic_curve(self): # test PERIODIC curves x[:,0] = 16*t*t*(1-t)*(1-t) x[:,1] = 1-x[:,0] - crv = CurveFactory.cubic_curve(x, CurveFactory.Boundary.PERIODIC, t) + crv = cf.cubic_curve(x, cf.Boundary.PERIODIC, t) y = crv(s) # exact solution is t^4, cubic approximation gives t^3, needs atol self.assertTrue(np.allclose(y[:,0], 16*s*s*(1-s)*(1-s), atol=1e-2)) @@ -290,7 +294,7 @@ def test_cubic_curve(self): # test FREE boundary type x[:,0] = 12*t*t*t + 2*t x[:,1] = 12*t*t*t - 3*t*t - crv = CurveFactory.cubic_curve(x, CurveFactory.Boundary.FREE, t=t) + crv = cf.cubic_curve(x, cf.Boundary.FREE, t=t) y = crv(s) self.assertTrue(np.allclose(y[:,0], 12*s*s*s + 2*s)) self.assertTrue(np.allclose(y[:,1], 12*s*s*s - 3*s*s )) @@ -298,7 +302,7 @@ def test_cubic_curve(self): # test NATURAL boundary type (x''(t)=0 at the boundary) x[:,0] = t x[:,1] = 3 - crv = CurveFactory.cubic_curve(x, CurveFactory.Boundary.NATURAL, t=t) + crv = cf.cubic_curve(x, cf.Boundary.NATURAL, t=t) y = crv(s) self.assertTrue(np.allclose(y[:,0], s)) self.assertTrue(np.allclose(y[:,1], 3.0)) @@ -308,7 +312,7 @@ def test_cubic_curve(self): x[:,1] = 3*t*t - 3*t + 1 dx = [[2*t[ 0] + 1, 6*t[ 0]-3], [2*t[-1] + 1, 6*t[-1]-3]] - crv = CurveFactory.cubic_curve(x, CurveFactory.Boundary.TANGENT, t=t, tangents=dx) + crv = cf.cubic_curve(x, cf.Boundary.TANGENT, t=t, tangents=dx) y = crv(s) self.assertTrue(np.allclose(y[:,0], s*s + s - 1)) self.assertTrue(np.allclose(y[:,1], 3*s*s - 3*s + 1)) @@ -317,7 +321,7 @@ def test_cubic_curve(self): x[:,0] = t*t + t - 1 x[:,1] = 3*t*t - 3*t + 1 dx = np.vstack([[2*t + 1], [6*t-3]]).T - crv = CurveFactory.cubic_curve(x, CurveFactory.Boundary.HERMITE, t=t, tangents=dx) + crv = cf.cubic_curve(x, cf.Boundary.HERMITE, t=t, tangents=dx) y = crv(s) self.assertTrue(np.allclose(y[:,0], s*s + s - 1)) self.assertTrue(np.allclose(y[:,1], 3*s*s - 3*s + 1)) @@ -327,12 +331,12 @@ def test_cubic_curve_1D(self): t = np.linspace(0, 1, n_elems) x = (t**2).reshape(-1,1) - crv = CurveFactory.cubic_curve(x, CurveFactory.Boundary.FREE, t=t.tolist()) + crv = cf.cubic_curve(x, cf.Boundary.FREE, t=t.tolist()) self.assertEqual(crv.dimension, 1) self.assertFalse(crv.rational) def test_bezier(self): - crv = CurveFactory.bezier([[0,0], [0,1], [1,1], [1,0], [2,0], [2,1],[1,1]]) + crv = cf.bezier([[0,0], [0,1], [1,1], [1,0], [2,0], [2,1],[1,1]]) self.assertEqual(len(crv.knots(0)), 3) self.assertTrue(np.allclose(crv(0), [0,0])) t = crv.tangent(0) @@ -345,7 +349,7 @@ def test_bezier(self): self.assertTrue(crv.order(0), 4) # test the exact same curve, only with relative keyword - crv = CurveFactory.bezier([[0,0], [0,1], [1,0], [0,-1], [1,0], [0,1],[1,0]], relative=True) + crv = cf.bezier([[0,0], [0,1], [1,0], [0,-1], [1,0], [0,1],[1,0]], relative=True) self.assertEqual(len(crv.knots(0)), 3) self.assertTrue(np.allclose(crv(0), [0,0])) t = crv.tangent(0) @@ -359,21 +363,21 @@ def test_bezier(self): def test_ellipse(self): # test (x/1)^2 + (y/5)^2 = 1 - c = CurveFactory.ellipse(1,5) + c = cf.ellipse(1,5) t = np.linspace(c.start(0), c.end(0), 25) for pt in c.evaluate(t): x,y = pt self.assertAlmostEqual((x/1)**2 + (y/5)**2, 1) # test (x-.3/1)^2 + (y-6/5)^2 = 1 - c = CurveFactory.ellipse(1,5, center=(.3, 6)) + c = cf.ellipse(1,5, center=(.3, 6)) t = np.linspace(c.start(0), c.end(0), 25) for pt in c.evaluate(t): x,y = pt self.assertAlmostEqual(((x-.3)/1)**2 + ((y-6)/5)**2, 1) # test ellipse along x=y axis - c = CurveFactory.ellipse(1,2, xaxis=(1,1)) + c = cf.ellipse(1,2, xaxis=(1,1)) t = np.linspace(c.start(0), c.end(0), 25) for pt in c.evaluate(t): x,y = pt @@ -381,7 +385,7 @@ def test_ellipse(self): self.assertAlmostEqual(((s*x + s*y)/1)**2 + ((s*x - s*y)/2)**2, 1) # test ellipse in 3D - c = CurveFactory.ellipse(1,2, normal=(0,1,0), xaxis=(1,0,1)) + c = cf.ellipse(1,2, normal=(0,1,0), xaxis=(1,0,1)) t = np.linspace(c.start(0), c.end(0), 25) for pt in c.evaluate(t): x,y,z = pt diff --git a/test/curve_test.py b/test/curve_test.py index 16b3d01b..4b19a872 100644 --- a/test/curve_test.py +++ b/test/curve_test.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- -from splipy import SplineObject, Curve, BSplineBasis -import splipy.curve_factory as CurveFactory from math import sqrt, pi -import numpy as np import unittest +import numpy as np + +from splipy import SplineObject, Curve, BSplineBasis +import splipy.curve_factory as cf + + class TestCurve(unittest.TestCase): def test_constructor(self): # test 3D constructor @@ -129,7 +132,7 @@ def test_lower_order(self): interp_pts = basis.greville() x = [[t*(1-t), t**2] for t in interp_pts] - crv = CurveFactory.interpolate(x, basis) # function in space, exact representation kept + crv = cf.interpolate(x, basis) # function in space, exact representation kept crv2 = crv.lower_order(1) # still in space, crv2 is *also* exact @@ -398,7 +401,7 @@ def expect_derivative_3(x): self.assertAlmostEqual(crv.derivative(0.86, 3)[0], expect_derivative_3(0.86)) def test_tangent_and_normal(self): - crv = CurveFactory.circle() + crv = cf.circle() crv.set_dimension(3) t = np.linspace(crv.start(0), crv.end(0), 13) X = crv(t) @@ -506,7 +509,7 @@ def test_curvature(self): self.assertTrue(np.allclose(k, 0.0)) # test circle - crv = CurveFactory.circle(r=3) + [1,1] + crv = cf.circle(r=3) + [1,1] t = np.linspace(0,2*pi, 10) k = crv.curvature(t) self.assertTrue(np.allclose(k, 1.0/3.0)) # circles: k = 1/r @@ -535,7 +538,7 @@ def test_torsion(self): a = 3.0 b = 2.0 x = np.array([a*np.cos(t), a*np.sin(t), b*t]) - crv = CurveFactory.cubic_curve(x.T, t=t) + crv = cf.cubic_curve(x.T, t=t) t = np.linspace(0, 6*pi, 10) k = crv.torsion(t) diff --git a/test/splinemodel_test.py b/test/splinemodel_test.py index 0ce2458c..e2ad050a 100644 --- a/test/splinemodel_test.py +++ b/test/splinemodel_test.py @@ -2,7 +2,7 @@ from operator import itemgetter from splipy import Volume -from splipy.SplineModel import SplineModel, Orientation, IFEMWriter, IFEMConnection +from splipy.splinemodel import SplineModel, Orientation, IFEMWriter, IFEMConnection from splipy.io import G2 import unittest import numpy as np diff --git a/test/surface_factory_test.py b/test/surface_factory_test.py index 392f7fa2..58bfca83 100644 --- a/test/surface_factory_test.py +++ b/test/surface_factory_test.py @@ -1,21 +1,25 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis, Curve, Surface -import splipy.curve_factory as CurveFactory -import splipy.surface_factory as SurfaceFactory from math import pi, sqrt +import unittest + import numpy as np from numpy.linalg import norm -import unittest + +from splipy import BSplineBasis, Curve, Surface +import splipy.curve_factory as cf +import splipy.surface_factory as sf + try: import nutils has_nutils = True except ImportError: has_nutils = False + class TestSurfaceFactory(unittest.TestCase): def test_square(self): - surf = SurfaceFactory.square((4, 5)) + surf = sf.square((4, 5)) self.assertEqual(surf.dimension, 2) self.assertEqual(surf.rational, False) self.assertEqual(surf.order(), (2, 2)) @@ -28,7 +32,7 @@ def test_curve_interpolation(self): x_pts[:, 0] = t * t x_pts[:, 1] = 1 - t x_pts[:, 2] = t * t * t + 2 * t - crv = CurveFactory.interpolate(x_pts, basis) + crv = cf.interpolate(x_pts, basis) self.assertEqual(crv.order(0), 4) self.assertAlmostEqual(crv(.4)[0], .4**2) # x=t^2 self.assertAlmostEqual(crv(.4)[1], 1 - .4) # y=1-t @@ -39,7 +43,7 @@ def test_curve_interpolation(self): def test_disc(self): # radial disc - surf = SurfaceFactory.disc() + surf = sf.disc() x = surf.evaluate([0, 1], [0, pi / 4, pi / 2, pi]) self.assertTrue(np.allclose(x[0,0], [0,0])) self.assertTrue(np.allclose(x[1,0], [1,0])) @@ -48,7 +52,7 @@ def test_disc(self): self.assertAlmostEqual(surf.area(), pi, places=3) # radial disc of size different from 1 - surf = SurfaceFactory.disc(4) + surf = sf.disc(4) # test evaluation at 25 points for radius=4 v = np.linspace(surf.start('v'), surf.end('v'),25) u = np.linspace(surf.start('u'), surf.end('u'), 5) @@ -59,7 +63,7 @@ def test_disc(self): self.assertAlmostEqual(surf.area(), 4*4*pi, places=3) # square disc - surf = SurfaceFactory.disc(3, type='square') + surf = sf.disc(3, type='square') # evaluate on all 4 edges, 5 pts on each edge u = np.linspace(0, 1, 5) v = np.linspace(0, 1, 5) @@ -75,21 +79,21 @@ def test_disc(self): self.assertAlmostEqual(surf.area(), 3*3*pi, places=2) # test xaxis - surf = SurfaceFactory.disc(r=3, xaxis=(0,1,0)) + surf = sf.disc(r=3, xaxis=(0,1,0)) u = surf.end('u') self.assertTrue(np.allclose(surf(u,0), [0,3])) # test normal - surf = SurfaceFactory.disc(r=2, normal=(1,1,0), xaxis=(0,0,1)) + surf = sf.disc(r=2, normal=(1,1,0), xaxis=(0,0,1)) u = surf.end('u') self.assertTrue(np.allclose(surf(u,0), [0,0,2])) def test_revolve(self): # square torus - square = CurveFactory.n_gon(4) + square = cf.n_gon(4) square.rotate(pi / 2, (1, 0, 0)) square.translate((2, 0, 0)) # in xz-plane with corners at (3,0),(2,1),(1,0),(2,-1) - surf = SurfaceFactory.revolve(square) + surf = sf.revolve(square) surf.reparam() # set parametric space to (0,1)^2 v = np.linspace(0, 1, 13) x = surf.evaluate(0, v) # outer ring evaluation u=0 @@ -105,8 +109,8 @@ def test_revolve(self): self.assertAlmostEqual(pt[2], .5) # check height=0.5 # incomplete revolve - c = CurveFactory.line([1,0], [0,1], relative=True) - surf = SurfaceFactory.revolve(c, theta=4.2222, axis=[0,1,0]) + c = cf.line([1,0], [0,1], relative=True) + surf = sf.revolve(c, theta=4.2222, axis=[0,1,0]) surf.reparam() u = np.linspace(0,1,7) v = np.linspace(0,1,7) @@ -118,7 +122,7 @@ def test_revolve(self): def test_surface_torus(self): # default torus - surf = SurfaceFactory.torus(1, 3) + surf = sf.torus(1, 3) start = surf.start() end = surf.end() # check a 13 evaluation points of v-evaluation (around the z-axis) @@ -147,7 +151,7 @@ def test_surface_torus(self): def test_sphere(self): # unit ball - surf = SurfaceFactory.sphere() + surf = sf.sphere() # test 7x7 grid for radius = 1 for u in np.linspace(surf.start()[0], surf.end()[0], 7): for v in np.linspace(surf.start()[1], surf.end()[1], 7): @@ -157,7 +161,7 @@ def test_sphere(self): def test_cylinder_surface(self): # unit cylinder - surf = SurfaceFactory.cylinder() + surf = sf.cylinder() # test 7x7 grid for xy-radius = 1 and v=z for u in np.linspace(surf.start()[0], surf.end()[0], 7): for v in np.linspace(surf.start()[1], surf.end()[1], 7): @@ -167,7 +171,7 @@ def test_cylinder_surface(self): self.assertAlmostEqual(surf.area(), 2*pi, places=3) # cylinder with parameters - surf = SurfaceFactory.cylinder(r=2, h=5, center=(0,0,1), axis=(1,0,0)) + surf = sf.cylinder(r=2, h=5, center=(0,0,1), axis=(1,0,0)) for u in np.linspace(surf.start()[0], surf.end()[0], 7): for v in np.linspace(surf.start()[1], surf.end()[1], 7): x = surf(u, v) @@ -176,19 +180,19 @@ def test_cylinder_surface(self): self.assertAlmostEqual(surf.area(), 2*2*pi*5, places=3) # test xaxis - surf = SurfaceFactory.cylinder(r=sqrt(2), xaxis=(1,1,0)) + surf = sf.cylinder(r=sqrt(2), xaxis=(1,1,0)) self.assertTrue(np.allclose(surf(0,0), [1,1,0])) def test_edge_curves(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # mixes rational and non-rational curves with different parametrization spaces - c1 = CurveFactory.circle_segment(pi / 2) + c1 = cf.circle_segment(pi / 2) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) - c3 = CurveFactory.circle_segment(pi / 2) + c3 = cf.circle_segment(pi / 2) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]) - surf = SurfaceFactory.edge_curves(c1, c2, c3, c4) + surf = sf.edge_curves(c1, c2, c3, c4) # srf spits out parametric space (0,1)^2, so we sync these up to input curves c3.reverse() @@ -217,34 +221,34 @@ def test_edge_curves(self): crvs[1].reverse() crvs[2].reverse() # input curves should be clockwise oriented closed loop - srf = SurfaceFactory.edge_curves(crvs[0], crvs[3], crvs[1], crvs[2]) + srf = sf.edge_curves(crvs[0], crvs[3], crvs[1], crvs[2]) crvs[1].reverse() u = np.linspace(0,1,7) self.assertTrue(np.allclose(srf(u,0).reshape((7,2)), crvs[0](u))) self.assertTrue(np.allclose(srf(u,1).reshape((7,2)), crvs[1](u))) # test self-organizing curve ordering when they are not sequential - srf = SurfaceFactory.edge_curves(crvs[0], crvs[2].reverse(), crvs[3], crvs[1]) + srf = sf.edge_curves(crvs[0], crvs[2].reverse(), crvs[3], crvs[1]) u = np.linspace(0,1,7) self.assertTrue(np.allclose(srf(u,0).reshape((7,2)), crvs[0](u))) self.assertTrue(np.allclose(srf(u,1).reshape((7,2)), crvs[1](u))) # test error handling with self.assertRaises(ValueError): - srf = SurfaceFactory.edge_curves(crvs + (Curve(),)) # 5 input curves + srf = sf.edge_curves(crvs + (Curve(),)) # 5 input curves @unittest.skipIf(not has_nutils, "EdgeCurves with poisson solver requires nutils") def test_edge_curves_poisson(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # rebuild to avoid rational representations - c1 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) + c1 = cf.circle_segment(pi / 2).rebuild(3,11) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) - c3 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) + c3 = cf.circle_segment(pi / 2).rebuild(3,11) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]).rebuild(3,10) c4 = c4.rebuild(4,11) - surf = SurfaceFactory.edge_curves([c1, c2, c3, c4], type='poisson') + surf = sf.edge_curves([c1, c2, c3, c4], type='poisson') # check right dimensions of output self.assertEqual(surf.shape[0], 11) # 11 controlpoints in the circle segment @@ -278,14 +282,14 @@ def test_edge_curves_poisson(self): def test_edge_curves_elasticity(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # rebuild to avoid rational representations - c1 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) + c1 = cf.circle_segment(pi / 2).rebuild(3,11) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) - c3 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) + c3 = cf.circle_segment(pi / 2).rebuild(3,11) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]).rebuild(3,10) c4 = c4.rebuild(4,11) - surf = SurfaceFactory.edge_curves([c1, c2, c3, c4], type='elasticity') + surf = sf.edge_curves([c1, c2, c3, c4], type='elasticity') # check right dimensions of output self.assertEqual(surf.shape[0], 11) # 11 controlpoints in the circle segment @@ -313,14 +317,14 @@ def test_edge_curves_elasticity(self): def test_edge_curves_finitestrain(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # rebuild to avoid rational representations - c1 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) + c1 = cf.circle_segment(pi / 2).rebuild(3,11) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) - c3 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) + c3 = cf.circle_segment(pi / 2).rebuild(3,11) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]).rebuild(3,10) c4 = c4.rebuild(4,11) - surf = SurfaceFactory.edge_curves([c1, c2, c3, c4], type='finitestrain') + surf = sf.edge_curves([c1, c2, c3, c4], type='finitestrain') # check right dimensions of output self.assertEqual(surf.shape[0], 11) # 11 controlpoints in the circle segment @@ -353,16 +357,13 @@ def test_edge_curves_finitestrain(self): @unittest.skipIf(not has_nutils, "EdgeCurves with finitestrain solver requires nutils") def test_edge_curves_finitestrain_lshape(self): # Create an L-shape geometry with an interior 270-degree angle at the origin (u=.5, v=1) - c1 = CurveFactory.polygon([[-1, 1], [-1,-1], [1,-1]]) - c2 = CurveFactory.polygon([[ 1,-1], [ 1, 0]]) - c3 = CurveFactory.polygon([[ 1, 0], [ 0, 0], [0, 1]]) - c4 = CurveFactory.polygon([[ 0, 1], [-1, 1]]) + c1 = cf.polygon([[-1, 1], [-1,-1], [1,-1]]) + c2 = cf.polygon([[ 1,-1], [ 1, 0]]) + c3 = cf.polygon([[ 1, 0], [ 0, 0], [0, 1]]) + c4 = cf.polygon([[ 0, 1], [-1, 1]]) c1.refine(2).raise_order(1) c2.refine(2).raise_order(1) - surf = SurfaceFactory.edge_curves([c1, c2, c3, c4], type='finitestrain') - from splipy.io import G2 - with G2('out.g2') as myfile: - myfile.write(surf) + surf = sf.edge_curves([c1, c2, c3, c4], type='finitestrain') # the quickest way to check for self-intersecting geometry here is that # the normal is pointing the wrong way: down z-axis instead of up surf.reparam().set_dimension(3) @@ -372,7 +373,7 @@ def test_edge_curves_finitestrain_lshape(self): def test_thicken(self): c = Curve() # 2D curve from (0,0) to (1,0) - s = SurfaceFactory.thicken(c, .5) # extend to y=[-.5, .5] + s = sf.thicken(c, .5) # extend to y=[-.5, .5] self.assertTupleEqual(s.order(), (2,2)) self.assertTupleEqual(s.start(), (0,0)) self.assertTupleEqual(s.end(), (1,1)) @@ -381,7 +382,7 @@ def test_thicken(self): # test a case with vanishing velocity. x'(t)=0, y'(t)=0 for t=0 c = Curve(BSplineBasis(3), [[0,0],[0,0],[1,0]]) # x(t)=t^2, y(t)=0 - s = SurfaceFactory.thicken(c, .5) + s = sf.thicken(c, .5) self.assertTupleEqual(s.order(), (3,2)) self.assertTupleEqual(s.start(), (0,0)) self.assertTupleEqual(s.end(), (1,1)) @@ -391,7 +392,7 @@ def test_thicken(self): def myThickness(t): return t**2 c = Curve(BSplineBasis(3)) - s = SurfaceFactory.thicken(c, myThickness) + s = sf.thicken(c, myThickness) self.assertTupleEqual(s.order(), (3,2)) self.assertTupleEqual(s.start(), (0,0)) self.assertTupleEqual(s.end(), (1,1)) @@ -401,7 +402,7 @@ def myThickness(t): # test 3D geometry c = Curve() c.set_dimension(3) - s = SurfaceFactory.thicken(c, 1) # cylinder along x-axis with h=1, r=1 + s = sf.thicken(c, 1) # cylinder along x-axis with h=1, r=1 for u in np.linspace(s.start(0), s.end(0), 5): for v in np.linspace(s.start(1), s.end(1), 5): x = s(u, v) @@ -418,7 +419,7 @@ def test_interpolate(self): b1 = BSplineBasis(3, [0,0,0,.33,.66,.7, .8,1,1,1]) b2 = BSplineBasis(4, [0,0,0,0,.1, .2, .5,1,1,1,1]) - surf = SurfaceFactory.interpolate(x, [b1,b2], [t,t]) + surf = sf.interpolate(x, [b1,b2], [t,t]) t = np.linspace(0, 1, 13) V,U = np.meshgrid(t,t) x = surf(t,t) @@ -437,7 +438,7 @@ def test_l2(self): b1 = BSplineBasis(3, [0,0,0,.33,.66,.7, .8,1,1,1]) b2 = BSplineBasis(4, [0,0,0,0,.1, .2, .5,1,1,1,1]) - surf = SurfaceFactory.least_square_fit(x, [b1,b2], [t,t]) + surf = sf.least_square_fit(x, [b1,b2], [t,t]) t = np.linspace(0, 1, 13) V,U = np.meshgrid(t,t) x = surf(t,t) diff --git a/test/surface_test.py b/test/surface_test.py index 94707c6c..eb43f6b2 100644 --- a/test/surface_test.py +++ b/test/surface_test.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- -from splipy import Surface, BSplineBasis -import splipy.surface_factory as SurfaceFactory from math import pi -import numpy as np import unittest +import numpy as np + +from splipy import Surface, BSplineBasis +import splipy.surface_factory as sf + + class TestSurface(unittest.TestCase): def test_constructor(self): # test 3D constructor @@ -470,7 +473,7 @@ def test_reparam(self): def test_periodic_split(self): # create a double-periodic spline on the knot vector [-1,0,0,1,1,2,2,3,3,4,4,5]*pi/2 - surf = SurfaceFactory.torus() + surf = sf.torus() surf2 = surf.split( pi/2, 0) # split on existing knot surf3 = surf.split( 1.23, 1) # split between knots @@ -540,7 +543,7 @@ def test_make_identical(self): def test_center(self): # make an ellipse at (2,1) - surf = SurfaceFactory.disc(3) + surf = sf.disc(3) print(surf) surf.scale((3,1)) surf += (2,1) @@ -627,7 +630,7 @@ def test_edges(self): self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) def test_normal(self): - surf = SurfaceFactory.sphere(1) + surf = sf.sphere(1) surf.swap() u = np.linspace(surf.start(0) + 1e-3, surf.end(0) - 1e-3, 9) v = np.linspace(surf.start(1) + 1e-3, surf.end(1) - 1e-3, 9) diff --git a/test/trimmed_surface_test.py b/test/trimmed_surface_test.py index bf0ee2a2..5cfed01c 100644 --- a/test/trimmed_surface_test.py +++ b/test/trimmed_surface_test.py @@ -1,27 +1,29 @@ # -*- coding: utf-8 -*- -from splipy import TrimmedSurface, BSplineBasis -import splipy.surface_factory as SurfaceFactory -import splipy.curve_factory as CurveFactory from math import pi -import numpy as np import unittest +import numpy as np + +from splipy import TrimmedSurface, BSplineBasis +import splipy.curve_factory as cf + + class TestSurface(unittest.TestCase): def test_constructor(self): - trim_loop = [CurveFactory.line([.25,.25], [.75,.25]), - CurveFactory.line([.75,.25], [.75,.75]), - CurveFactory.line([.75,.75], [.25,.75]), - CurveFactory.line([.25,.75], [.25,.25])] + trim_loop = [cf.line([.25,.25], [.75,.25]), + cf.line([.75,.25], [.75,.75]), + cf.line([.75,.75], [.25,.75]), + cf.line([.25,.75], [.25,.25])] # error with non-closed trimming loop with self.assertRaises(RuntimeError): s = TrimmedSurface(loops=[trim_loop[:3]]) # error with trimming curves in 3D space with self.assertRaises(RuntimeError): - loop_3d = [CurveFactory.line([.25,.25,1], [.75,.25,1]), - CurveFactory.line([.75,.25,1], [.75,.75,1]), - CurveFactory.line([.75,.75,1], [.25,.75,1]), - CurveFactory.line([.25,.75,1], [.25,.25,1])] + loop_3d = [cf.line([.25,.25,1], [.75,.25,1]), + cf.line([.75,.25,1], [.75,.75,1]), + cf.line([.75,.75,1], [.25,.75,1]), + cf.line([.25,.75,1], [.25,.25,1])] s = TrimmedSurface(loops=[loop_3d]) s = TrimmedSurface(loops=[trim_loop]) diff --git a/test/volume_factory_test.py b/test/volume_factory_test.py index 4eee56a6..a991643c 100644 --- a/test/volume_factory_test.py +++ b/test/volume_factory_test.py @@ -1,24 +1,28 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis, Curve, Surface, Volume -import splipy.curve_factory as CurveFactory -import splipy.surface_factory as SurfaceFactory -import splipy.volume_factory as VolumeFactory from math import pi, sqrt +import unittest + import numpy as np from numpy.linalg import norm -import unittest + +from splipy import BSplineBasis, Curve, Surface, Volume +import splipy.curve_factory as cf +import splipy.surface_factory as sf +import splipy.volume_factory as vf + try: import nutils has_nutils = True except ImportError: has_nutils = False + class TestVolumeFactory(unittest.TestCase): def test_cylinder_volume(self): # unit cylinder - vol = VolumeFactory.cylinder() + vol = vf.cylinder() # test 5x5x5 grid for xy-radius = w and v=z for u in np.linspace(vol.start()[0], vol.end()[0], 5): for v in np.linspace(vol.start()[1], vol.end()[1], 5): @@ -30,7 +34,7 @@ def test_cylinder_volume(self): self.assertAlmostEqual(vol.volume(), pi, places=3) # cylinder with parameters - vol = VolumeFactory.cylinder(r=2, h=5, center=(0,0,1), axis=(1,0,0)) + vol = vf.cylinder(r=2, h=5, center=(0,0,1), axis=(1,0,0)) for u in np.linspace(vol.start()[0], vol.end()[0], 5): for v in np.linspace(vol.start()[1], vol.end()[1], 5): for w in np.linspace(vol.start()[2], vol.end()[2], 5): @@ -40,13 +44,13 @@ def test_cylinder_volume(self): self.assertAlmostEqual(vol.volume(), 2*2*pi*5, places=3) # test xaxis - vol = VolumeFactory.cylinder(r=sqrt(2), xaxis=(1,1,0)) + vol = vf.cylinder(r=sqrt(2), xaxis=(1,1,0)) u = vol.end('u') self.assertTrue(np.allclose(vol(u,0,0), [1,1,0])) def test_surface_torus(self): # default torus - vol = VolumeFactory.torus(1, 3) + vol = vf.torus(1, 3) start = vol.start() end = vol.end() # check a 13 evaluation points of v-evaluation (around the z-axis) @@ -95,7 +99,7 @@ def test_edge_surfaces(self): basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1]) bottom = Surface(basis1, basis2, controlpoints, True) - vol = VolumeFactory.edge_surfaces(bottom, top) + vol = vf.edge_surfaces(bottom, top) # set parametric domain to [0,1]^2 for easier comparison top.reparam() @@ -121,7 +125,7 @@ def test_edge_surfaces(self): basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1]) bottom = Surface(basis1, basis2, controlpoints) # non-rational! - vol = VolumeFactory.edge_surfaces(bottom, top) # also non-rational! + vol = vf.edge_surfaces(bottom, top) # also non-rational! # verify on 5x5x7 evaluation grid for u in np.linspace(0, 1, 5): @@ -146,7 +150,7 @@ def test_edge_surfaces_six_sides(self): edges = vol.faces() # edge_surface should give back the same unit cube - vol2 = VolumeFactory.edge_surfaces(edges) + vol2 = vf.edge_surfaces(edges) # check discretization self.assertEqual(vol2.order(0), 4) @@ -167,10 +171,10 @@ def test_edge_surfaces_six_sides(self): def test_surface_loft(self): crv1 = Curve(BSplineBasis(3, range(11), 1), [[1,-1], [1,0], [1,1], [-1,1], [-1,0], [-1,-1]]) - crv2 = CurveFactory.circle(2) + (0,0,1) + crv2 = cf.circle(2) + (0,0,1) crv3 = Curve(BSplineBasis(4, range(11), 2), [[1,-1,2], [1,1,2], [-1,1,2], [-1,-1,2]]) - crv4 = CurveFactory.circle(2) + (0,0,3) - surf = SurfaceFactory.loft(crv1, crv2, crv3, crv4) + crv4 = cf.circle(2) + (0,0,3) + surf = sf.loft(crv1, crv2, crv3, crv4) crv1.set_dimension(3) # for convenience when evaluating t = np.linspace( 0, 1, 13) @@ -197,17 +201,17 @@ def test_surface_loft(self): def test_volume_loft(self): crv1 = Curve(BSplineBasis(3, range(11), 1), [[1,-1], [1,0], [1,1], [-1,1], [-1,0], [-1,-1]]) - crv2 = CurveFactory.circle(2) + (0,0,1) + crv2 = cf.circle(2) + (0,0,1) crv3 = Curve(BSplineBasis(4, range(11), 2), [[1,-1,2], [1,1,2], [-1,1,2], [-1,-1,2]]) - crv4 = CurveFactory.circle(2) + (0,0,3) + crv4 = cf.circle(2) + (0,0,3) surf = [] for c in [crv1, crv2, crv3, crv4]: c2 = c.clone() c2.project('z') - surf.append(SurfaceFactory.edge_curves(c, c2)) + surf.append(sf.edge_curves(c, c2)) - vol = VolumeFactory.loft(surf) + vol = vf.loft(surf) surf[0].set_dimension(3) # for convenience when evaluating t = np.linspace( 0, 1, 9) @@ -242,7 +246,7 @@ def test_revolve(self): square = Surface() + (1,0) square.rotate(pi / 2, (1, 0, 0)) # in xz-plane with corners at (1,0),(2,0),(2,1),(1,1) - vol = VolumeFactory.revolve(square) + vol = vf.revolve(square) vol.reparam() # set parametric space to (0,1)^3 u = np.linspace(0, 1, 7) v = np.linspace(0, 1, 7) @@ -256,7 +260,7 @@ def test_revolve(self): self.assertAlmostEqual(vol.volume(), 2*pi*1.5, places=3) # test incomplete reolve - vol = VolumeFactory.revolve(square, theta=pi/3) + vol = vf.revolve(square, theta=pi/3) vol.reparam() # set parametric space to (0,1)^3 u = np.linspace(0, 1, 7) v = np.linspace(0, 1, 7) @@ -271,7 +275,7 @@ def test_revolve(self): self.assertTrue(np.all(x >= 0)) # completely contained in first octant # test axis revolve - vol = VolumeFactory.revolve(Surface()+(1,1), theta=pi/3, axis=(1,0,0)) + vol = vf.revolve(Surface()+(1,1), theta=pi/3, axis=(1,0,0)) vol.reparam() # set parametric space to (0,1)^3 u = np.linspace(0, 1, 7) v = np.linspace(0, 1, 7) @@ -295,7 +299,7 @@ def test_interpolate(self): b2 = BSplineBasis(4, [0,0,0,0,.5,1,1,1,1]) b3 = BSplineBasis(4, [0,0,0,0,.2,1,1,1,1]) - vol = VolumeFactory.interpolate(x, [b1,b2,b3], [t,t,t]) + vol = vf.interpolate(x, [b1,b2,b3], [t,t,t]) t = np.linspace(0, 1, 7) V,U,W = np.meshgrid(t,t,t) x = vol(t,t,t) @@ -315,7 +319,7 @@ def test_l2(self): b2 = BSplineBasis(4, [0,0,0,0,.5,1,1,1,1]) b3 = BSplineBasis(4, [0,0,0,0,.2,1,1,1,1]) - vol = VolumeFactory.least_square_fit(x, [b1,b2,b3], [t,t,t]) + vol = vf.least_square_fit(x, [b1,b2,b3], [t,t,t]) t = np.linspace(0, 1, 7) V,U,W = np.meshgrid(t,t,t) x = vol(t,t,t) @@ -326,7 +330,7 @@ def test_l2(self): def test_volume_sphere(self): # unit ball - ball = VolumeFactory.sphere(type='square') + ball = vf.sphere(type='square') # test 7x7 grid for radius = 1 for surf in ball.faces(): for u in np.linspace(surf.start(0), surf.end(0), 7): @@ -335,7 +339,7 @@ def test_volume_sphere(self): self.assertAlmostEqual(surf.area(), 4*pi/6, places=3) # unit ball - ball = VolumeFactory.sphere(type='radial') + ball = vf.sphere(type='radial') # test 7x7 grid for radius = 1 for u in np.linspace(surf.start(0), surf.end(0), 7): for v in np.linspace(surf.start(1), surf.end(1), 7): diff --git a/test/volume_test.py b/test/volume_test.py index 17412d63..cc07e786 100644 --- a/test/volume_test.py +++ b/test/volume_test.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- -from splipy import BSplineBasis, Volume -import splipy.volume_factory as VolumeFactory import unittest -import numpy as np from math import pi, sqrt +import numpy as np + +from splipy import BSplineBasis, Volume +import splipy.volume_factory as vf + class TestVolume(unittest.TestCase): def test_evaluate(self): @@ -152,7 +154,7 @@ def test_lower_order(self): cp[...,1] = X*X cp[...,2] = Z**2 + 2 - vol = VolumeFactory.interpolate(cp, [b,b,b]) + vol = vf.interpolate(cp, [b,b,b]) vol2 = vol.lower_order(1) # still in space, vol2 is *also* exact u = np.linspace(0,1, 5) v = np.linspace(0,1, 6)