Example #1
0
    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)
        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)

        crv1.set_dimension(3) # for convenience when evaluating
        t = np.linspace( 0, 1, 13)

        u = np.linspace(crv1.start(0), crv1.end(0), 13)
        pt  = crv1(u)
        pt2 = surf(t,0).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(crv2.start(0), crv2.end(0), 13)
        pt  = crv2(u)
        pt2 = surf(t,1).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(crv3.start(0), crv3.end(0), 13)
        pt  = crv3(u)
        pt2 = surf(t,2).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(crv4.start(0), crv4.end(0), 13)
        pt  = crv4(u)
        pt2 = surf(t,3).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
Example #2
0
    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 = 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 = 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)

        u = np.linspace(crv1.start(0), crv1.end(0), 13)
        pt  = crv1(u)
        pt2 = surf(t,0).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(crv2.start(0), crv2.end(0), 13)
        pt  = crv2(u)
        pt2 = surf(t,1).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(crv3.start(0), crv3.end(0), 13)
        pt  = crv3(u)
        pt2 = surf(t,2).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(crv4.start(0), crv4.end(0), 13)
        pt  = crv4(u)
        pt2 = surf(t,3).reshape(13,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
Example #3
0
    def test_circle(self):

        # unit circle of radius 1
        c = CurveFactory.circle()
        self.assertEqual(c.dimension, 2)
        self.assertEqual(c.rational, True)
        # test evaluation at 25 points for radius=1
        t = np.linspace(c.start(0), c.end(0), 25)
        x = c.evaluate(t)
        for pt in np.array(x):
            self.assertAlmostEqual(np.linalg.norm(pt), 1.0)  # check radius=1
        # test evaluation at key points
        pt = c.evaluate(0)  # evaluate at 0
        self.assertAlmostEqual(pt[0], 1.0)
        self.assertAlmostEqual(pt[1], 0.0)
        pt = c.evaluate(c.end(0) / 4)  # evaluate at pi/2
        self.assertAlmostEqual(pt[0], 0.0)
        self.assertAlmostEqual(pt[1], 1.0)
        pt = c.evaluate(c.end(0) / 2)  # evaluate at pi
        self.assertAlmostEqual(pt[0], -1.0)
        self.assertAlmostEqual(pt[1], 0.0)
        pt = c.evaluate(c.end(0) * 2)  # evaluate outside domain (test periodic)
        self.assertAlmostEqual(pt[0], 1.0)
        self.assertAlmostEqual(pt[1], 0.0)

        # circle of radius different from 1
        c = CurveFactory.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)
        for pt in np.array(x):
            self.assertAlmostEqual(np.linalg.norm(pt, 2), 3.0)  # check radius=3
        self.assertAlmostEqual(c.length(), 6*pi, places=3)

        # circle not at origin
        c = CurveFactory.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)
        for pt in np.array(x):
            self.assertAlmostEqual(np.linalg.norm(pt-[1,0,0], 2), 1.0)  # check radius=1
            self.assertAlmostEqual(pt[0]+pt[1]+pt[2] - 1, 0.0) # in plane x+y+z=1
        self.assertAlmostEqual(c.length(), 2*pi, places=3)

        # test alt circle
        c = CurveFactory.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))
        for k in c.knots(0):
            self.assertEqual(c.continuity(k), 1)


        # test errors and exceptions
        with self.assertRaises(ValueError):
            c = CurveFactory.circle(-2.5)  # negative radius
Example #4
0
def disc(r=1,
         center=(0, 0, 0),
         normal=(0, 0, 1),
         type='radial',
         xaxis=(1, 0, 0)):
    """  Create a circular disc. The *type* parameter distinguishes between
    different parametrizations.

    :param float r: Radius
    :param array-like center: local origin
    :param array-like normal: local normal
    :param string type: The type of parametrization ('radial' or 'square')
    :param array-like xaxis: direction of sem, i.e. parametric start point v=0
    :return: The disc
    :rtype: Surface
    """
    if type == 'radial':
        c1 = CurveFactory.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()
        result.reparam((0, r), (0, 2 * pi))
        return result
    elif type == 'square':
        w = 1 / sqrt(2)
        cp = [[-r * w, -r * w, 1], [0, -r, w], [r * w, -r * w, 1], [-r, 0, w],
              [0, 0, 1], [r, 0, w], [-r * w, r * w, 1], [0, r, w],
              [r * w, r * w, 1]]
        basis1 = BSplineBasis(3)
        basis2 = BSplineBasis(3)
        result = Surface(basis1, basis2, cp, True)
        return flip_and_move_plane_geometry(result, center, normal)
    else:
        raise ValueError('invalid type argument')
Example #5
0
def disc(r=1, center=(0,0,0), normal=(0,0,1), type='radial'):
    """disc([r=1], [type='radial'])

    Create a circular disc. The *type* parameter distinguishes between
    different parametrizations.

    :param float r: Radius
    :param string type: The type of parametrization ('radial' or 'square')
    :return: The disc
    :rtype: Surface
    """
    if type == 'radial':
        c1 = CurveFactory.circle(r)
        c2 = c1*0
        result = edge_curves(c2, c1)
        result.swap()
        result.reparam((0,r), (0,2*pi))
    elif type == 'square':
        w = 1 / sqrt(2)
        cp = [[-r * w, -r * w, 1],
              [0, -r, w],
              [r * w, -r * w, 1],
              [-r, 0, w],
              [0, 0, 1],
              [r, 0, w],
              [-r * w, r * w, 1],
              [0, r, w],
              [r * w, r * w, 1]]
        basis1 = BSplineBasis(3)
        basis2 = BSplineBasis(3)
        result = Surface(basis1, basis2, cp, True)
    else:
        raise ValueError('invalid type argument')

    return flip_and_move_plane_geometry(result, center, normal)
Example #6
0
    def test_3d_self_double_connection(self):
        c1 = curve_factory.circle(r=1, center=(3, 0, 0), normal=(0, 1, 0))
        c2 = curve_factory.circle(r=2, center=(3, 0, 0), normal=(0, 1, 0))
        ring = surface_factory.edge_curves(c1, c2)
        vol = volume_factory.revolve(ring)
        vol = vol.split(vol.knots('u')[0], direction='u')  # break periodicity
        vol = vol.split(vol.knots('w')[0], direction='w')
        model = SplineModel(3, 3)
        model.add(vol, raise_on_twins=False)

        writer = IFEMWriter(model)
        expected = [
            IFEMConnection(1, 1, 1, 2, 0),
            IFEMConnection(1, 1, 5, 6, 0)
        ]
        for connection, want in zip(writer.connections(), expected):
            self.assertEqual(connection, want)
Example #7
0
    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)
        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 = []
        for c in [crv1, crv2, crv3, crv4]:
            c2 = c.clone()
            c2.project('z')
            surf.append(SurfaceFactory.edge_curves(c, c2))

        vol = VolumeFactory.loft(surf)

        surf[0].set_dimension(3)  # for convenience when evaluating
        t = np.linspace(0, 1, 9)
        s = np.linspace(0, 1, 9)

        u = np.linspace(surf[0].start(0), surf[0].end(0), 9)
        v = np.linspace(surf[0].start(1), surf[0].end(1), 9)
        pt = surf[0](u, v)
        pt2 = vol(s, t, 0).reshape(9, 9, 3)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)

        u = np.linspace(surf[1].start(0), surf[1].end(0), 9)
        u = np.linspace(surf[1].start(1), surf[1].end(1), 9)
        pt = surf[1](u, v)
        pt2 = vol(s, t, 1).reshape(9, 9, 3)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)

        u = np.linspace(surf[2].start(0), surf[2].end(0), 9)
        v = np.linspace(surf[2].start(1), surf[2].end(1), 9)
        pt = surf[2](u, v)
        pt2 = vol(s, t, 2).reshape(9, 9, 3)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)

        u = np.linspace(surf[3].start(0), surf[3].end(0), 9)
        v = np.linspace(surf[3].start(1), surf[3].end(1), 9)
        pt = surf[3](u, v)
        pt2 = vol(s, t, 3).reshape(9, 9, 3)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)
Example #8
0
    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)
        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 = []
        for c in [crv1, crv2, crv3, crv4]:
            c2 = c.clone()
            c2.project('z')
            surf.append(SurfaceFactory.edge_curves(c, c2))

        vol = VolumeFactory.loft(surf)

        surf[0].set_dimension(3) # for convenience when evaluating
        t = np.linspace( 0, 1, 9)
        s = np.linspace( 0, 1, 9)

        u = np.linspace(surf[0].start(0), surf[0].end(0), 9)
        v = np.linspace(surf[0].start(1), surf[0].end(1), 9)
        pt  = surf[0](u,v)
        pt2 = vol(s,t,0).reshape(9,9,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(surf[1].start(0), surf[1].end(0), 9)
        u = np.linspace(surf[1].start(1), surf[1].end(1), 9)
        pt  = surf[1](u,v)
        pt2 = vol(s,t,1).reshape(9,9,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(surf[2].start(0), surf[2].end(0), 9)
        v = np.linspace(surf[2].start(1), surf[2].end(1), 9)
        pt  = surf[2](u,v)
        pt2 = vol(s,t,2).reshape(9,9,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)

        u = np.linspace(surf[3].start(0), surf[3].end(0), 9)
        v = np.linspace(surf[3].start(1), surf[3].end(1), 9)
        pt  = surf[3](u,v)
        pt2 = vol(s,t,3).reshape(9,9,3)
        self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
Example #9
0
def cylinder(r=1, h=1, center=(0,0,0), axis=(0,0,1), xaxis=(1,0,0)):
    """  Create a cylinder shell with no top or bottom

    :param float r: Radius
    :param float h: Height
    :param array-like center: The center of the bottom circle
    :param array-like axis: Cylinder axis
    :param array-like xaxis: direction of sem, i.e. parametric start point u=0
    :return: The cylinder shell
    :rtype: Surface
    """
    return extrude(CurveFactory.circle(r, center, axis, xaxis=xaxis), h*np.array(axis))
Example #10
0
def cylinder(r=1, h=1, center=(0,0,0), axis=(0,0,1)):
    """cylinder([r=1], [h=1], [center=(0,0,0)], [axis=(0,0,1)])

    Create a cylinder shell with no top or bottom 

    :param float r: Radius
    :param float h: Height
    :param point-like center: The center of the bottom circle
    :param vector-like axis: Cylinder axis
    :return: The cylinder shell
    :rtype: Surface
    """
    return extrude(CurveFactory.circle(r, center, axis), h*axis)
Example #11
0
    def circle(self):
        dim   = int(     self.read_next_non_whitespace().strip())
        r     = float(   next(self.fstream).strip())
        center= np.array(next(self.fstream).split(), dtype=float)
        normal= np.array(next(self.fstream).split(), dtype=float)
        xaxis = np.array(next(self.fstream).split(), dtype=float)
        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.reparam(param)
        if reverse:
            result.reverse()
        return result
Example #12
0
def torus(minor_r=1, major_r=3, center=(0,0,0)):
    """torus([minor_r=1], [major_r=3])

    Create a torus (doughnut) by revolving a circle of size *minor_r* around
    the *z* axis with radius *major_r*.

    :param float minor_r: The thickness of the torus (radius in the *xz* plane)
    :param float major_r: The size of the torus (radius in the *xy* plane)
    :param point-like center: Local origin of the torus
    :return: A periodic torus
    :rtype: Surface
    """
    circle = CurveFactory.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
    return revolve(circle) + center
Example #13
0
    def test_curvature(self):
        # linear curves have zero curvature
        crv = Curve()
        self.assertAlmostEqual(crv.curvature(.3), 0.0)
        # test multiple evaluation points
        t = np.linspace(0, 1, 10)
        k = crv.curvature(t)
        self.assertTrue(np.allclose(k, 0.0))

        # test circle
        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

        # test 3D (np.cross has different behaviour in 2D/3D)
        crv.set_dimension(3)
        k = crv.curvature(t)
        self.assertTrue(np.allclose(k, 1.0 / 3.0))  # circles: k = 1/r
Example #14
0
def torus(minor_r=1, major_r=3, center=(0,0,0), normal=(0,0,1), xaxis=(1,0,0)):
    """  Create a torus (doughnut) by revolving a circle of size *minor_r*
    around the *z* axis with radius *major_r*.

    :param float minor_r: The thickness of the torus (radius in the *xz* plane)
    :param float major_r: The size of the torus (radius in the *xy* plane)
    :param array-like center: Local origin of the torus
    :param array-like normal: Local origin of the torus
    :param array-like center: Local origin of the torus
    :return: A periodic torus
    :rtype: Surface
    """
    circle = CurveFactory.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)

    result.rotate(rotate_local_x_axis(xaxis, normal))
    return flip_and_move_plane_geometry(result, center, normal)
Example #15
0
    def test_tangent_and_normal(self):
        crv = cf.circle()
        crv.set_dimension(3)
        t = np.linspace(crv.start(0), crv.end(0), 13)
        X = crv(t)
        T = crv.tangent(t)
        B = crv.binormal(t)
        N = crv.normal(t)

        # check correct size
        self.assertEqual(len(B.shape), 2)  # returns a matrix
        self.assertEqual(B.shape[0], 13)
        self.assertEqual(B.shape[1], 3)

        # check all evaluation points
        for (x, t, b, n) in zip(X, T, B, N):
            # for the circle we have x*t=0 and x=-n
            self.assertAlmostEqual(np.dot(x, t), 0.0)
            self.assertTrue(np.allclose(x, -n))
            # for all curves we have that t,b,n are orthogonal
            self.assertAlmostEqual(np.dot(t, b), 0.0)
            self.assertAlmostEqual(np.dot(b, n), 0.0)
            self.assertAlmostEqual(np.dot(n, t), 0.0)
            # for planar (2D) curves, we have b=[0,0,1]
            self.assertTrue(np.allclose(b, [0, 0, 1]))

        # check that evaluations work for single-valued input
        t = crv.tangent(.23)
        b = crv.binormal(.23)
        n = crv.normal(.23)
        self.assertEqual(len(t.shape), 1)  # is a vector (not matrix)
        self.assertEqual(len(b.shape), 1)
        self.assertEqual(len(n.shape), 1)
        self.assertAlmostEqual(np.linalg.norm(t), 1.0)  # should be normalized
        self.assertAlmostEqual(np.linalg.norm(b), 1.0)
        self.assertAlmostEqual(np.linalg.norm(n), 1.0)
Example #16
0
def thicken(curve, amount):
    """  Generate a surface by adding thickness to a curve.

    - For 2D curves this will generate a 2D planar surface with the curve
      through the center.

    - For 3D curves this will generate a surface "tube" which is open at both
      ends (that is, for a straight line it will generate a cylinder shell).

    The resulting surface is an approximation generated by interpolating at the
    Greville points. It will use the same discretization as the input curve.
    It does not check for self-intersecting geometries.

    :param Curve curve: The generating curve
    :param amount: The amount of thickness, either constant or variable (if
        variable, the function must accept parameters named *x*, *y*, *z* and/or *t*)
    :return: Surrounding surface
    :rtype: Surface
    """
    # NOTES: There are several pitfalls with this function
    #  * self intersection:
    #     could be handled more gracefully, but is here ignored
    #  * choice of discretization:
    #     the offset curve is computed from the velocity (tangent) which is of
    #     one continuity less than the original curve. In particular C1
    #     quadratic curves will get very noticeable C0-kinks in them. Currently
    #     this is completely ignored and we keep the high continuity of the
    #     original curve.
    #  * width given by function input
    #     could produce wild behaviour. Original discretization might not
    #     produce a satisfactory result

    curve = curve.clone()  # clone input curve, throw away input reference
    t = curve.bases[0].greville()
    if curve.dimension == 2:
        # linear parametrization across domain
        n = len(curve)
        left_points = np.zeros((n, 2))
        right_points = np.zeros((n, 2))
        linear = BSplineBasis(2)

        x = curve.evaluate(t)  # curve at interpolation points
        v = curve.derivative(t)  # velocity at interpolation points
        l = np.sqrt(v[:, 0]**2 + v[:, 1]**2)  # normalizing factor for velocity
        for i in range(n):
            if l[i] < 1e-13:  # in case of zero velocity, use neighbour instead
                if i > 0:
                    v[i, :] = v[i - 1, :]
                else:
                    v[i, :] = v[i + 1, :]
            else:
                v[i, :] /= l[i]

        if inspect.isfunction(amount):
            arg_names = inspect.signature(amount).parameters
            argc = len(arg_names)
            argv = [0] * argc
            for i in range(n):
                # build up the list of arguments (in case not all of (x,y,t) are specified)
                for j, name in enumerate(arg_names):
                    if name == 'x':
                        argv[j] = x[i, 0]
                    elif name == 'y':
                        argv[j] = x[i, 1]
                    elif name == 'z':
                        argv[j] = 0.0
                    elif name == 't':
                        argv[j] = t[i]
                # figure out the distane at this particular point
                dist = amount(*argv)

                # store interpolation points
                right_points[i, 0] = x[i, 0] - v[i, 1] * dist  # x at bottom
                right_points[i, 1] = x[i, 1] + v[i, 0] * dist  # y at bottom
                left_points[i, 0] = x[i, 0] + v[i, 1] * dist  # x at top
                left_points[i, 1] = x[i, 1] - v[i, 0] * dist  # y at top
        else:
            right_points[:, 0] = x[:, 0] - v[:, 1] * amount  # x at bottom
            right_points[:, 1] = x[:, 1] + v[:, 0] * amount  # y at bottom
            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])
        return edge_curves(right, left)

    else:  # dimension=3, we will create a surrounding tube
        return sweep(curve, CurveFactory.circle(r=amount))
Example #17
0
path.append('../')

from splipy import curve_factory, surface_factory
from splipy.io import STL
from numpy import pi, cos, sin
import numpy as np


### create a parametric 3D-function
def trefoil(t):
    t = np.array(t)
    return np.array([sin(t) + 2*sin(2*t), cos(t) - 2*cos(2*t), -sin(3*t)]).T

### do an adaptive best cubic spline-fit of this function
path  = curve_factory.fit(trefoil, 0, 2*pi)

### since we know it is a closed curve, enforce this on the path
path  = path.make_periodic(0,0)

### create a sweeping curve (either a circle or square)
shape = curve_factory.circle(r=0.2)
# shape = 16*curve_factory.n_gon(4)

### sweep *shape along *path
srf = surface_factory.sweep(path, shape)

### 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))

Example #18
0
    def test_circle(self):

        # unit circle of radius 1
        c = cf.circle()
        self.assertEqual(c.dimension, 2)
        self.assertEqual(c.rational, True)
        # test evaluation at 25 points for radius=1
        t = np.linspace(c.start(0), c.end(0), 25)
        x = c.evaluate(t)
        for pt in np.array(x):
            self.assertAlmostEqual(norm(pt), 1.0)  # check radius=1
        # test evaluation at key points
        pt = c.evaluate(0)  # evaluate at 0
        self.assertAlmostEqual(pt[0], 1.0)
        self.assertAlmostEqual(pt[1], 0.0)
        pt = c.evaluate(c.end(0) / 4)  # evaluate at pi/2
        self.assertAlmostEqual(pt[0], 0.0)
        self.assertAlmostEqual(pt[1], 1.0)
        pt = c.evaluate(c.end(0) / 2)  # evaluate at pi
        self.assertAlmostEqual(pt[0], -1.0)
        self.assertAlmostEqual(pt[1], 0.0)
        pt = c.evaluate(c.end(0) *
                        2)  # evaluate outside domain (test periodic)
        self.assertAlmostEqual(pt[0], 1.0)
        self.assertAlmostEqual(pt[1], 0.0)

        # circle of radius different from 1
        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)
        for pt in np.array(x):
            self.assertAlmostEqual(norm(pt, 2), 3.0)  # check radius=3
        self.assertAlmostEqual(c.length(), 6 * pi, places=3)

        # circle not at origin
        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)
        for pt in np.array(x):
            self.assertAlmostEqual(norm(pt - [1, 0, 0], 2),
                                   1.0)  # check radius=1
            self.assertAlmostEqual(pt[0] + pt[1] + pt[2] - 1,
                                   0.0)  # in plane x+y+z=1
        self.assertAlmostEqual(c.length(), 2 * pi, places=3)

        # test alt circle
        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))
        for k in c.knots(0):
            self.assertEqual(c.continuity(k), 1)

        # test circle with different xaxis
        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))
        self.assertTrue(np.allclose(x[0, :], [1 / sqrt(2), 1 / sqrt(2)]))
        self.assertTrue(np.allclose(x[1, :], [-1 / sqrt(2), 1 / sqrt(2)]))

        # test using all parameters (in x+y+z=1 plane)
        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))
        self.assertTrue(np.allclose(c(0), [0, 1, 0]))
        self.assertTrue(np.allclose(c(pi), [2, -1, 0]))

        # test errors and exceptions
        with self.assertRaises(ValueError):
            c = cf.circle(-2.5)  # negative radius
Example #19
0
from splipy import curve_factory, surface_factory
from splipy.io import STL
from numpy import pi, cos, sin
import numpy as np


### create a parametric 3D-function
def trefoil(t):
    t = np.array(t)
    return np.array(
        [sin(t) + 2 * sin(2 * t),
         cos(t) - 2 * cos(2 * t), -sin(3 * t)]).T


### do an adaptive best cubic spline-fit of this function
path = curve_factory.fit(trefoil, 0, 2 * pi)

### since we know it is a closed curve, enforce this on the path
path = path.make_periodic(0, 0)

### create a sweeping curve (either a circle or square)
shape = curve_factory.circle(r=0.2)
# shape = 16*curve_factory.n_gon(4)

### sweep *shape along *path
srf = surface_factory.sweep(path, shape)

### 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))
# parametrization, and the acceleration vector is shown to be discontinuous.
#
# Author:    Kjetil Andre Johannessen
# Institute: Norwegian University of Science and Technology (NTNU)
# Date:      March 2016
#
from sys import path
path.append('../')
from splipy import *
import splipy.curve_factory as curves
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

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
x = c(t)                                 # physical (x,y)-coordinates, size (n,2)
v = c.derivative(t, 1)                   # velocity at all points
a = c.derivative(t, 2)                   # acceleration at all points

# plot the circle and get reference to the acceleration/velocity lines which we
# will update during animation
fig = plt.figure()
plt.plot(x[:,0], x[:,1], 'k-')
velocity,     = plt.plot([x[0,0], x[0,0]+v[0,0]], [x[0,1], x[0,1]+v[0,1]], 'r-', linewidth=2)
acceleration, = plt.plot([x[0,0], x[0,0]+a[0,0]], [x[0,1], x[0,1]+a[0,1]], 'b-', linewidth=3)
plt.axis('equal')
plt.legend(('NURBS Circle', 'Velocity', 'Acceleration'))

# update the velocity/acceleration lines for frame *i* in the animation