Example #1
0
    def test_edge_surfaces(self):
        # test 3D surface vs 2D rational surface

        # more or less random 3D surface with p=[2,2] and n=[3,4]
        controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 1], [1, 0, .5], [1, 1, 1],
                         [2, 1, 1], [2, 2, .5], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]]
        basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        basis2 = BSplineBasis(3, [0, 0, 0, .64, 2, 2, 2])
        top = Surface(basis1, basis2, controlpoints)

        # more or less random 2D rational surface with p=[1,2] and n=[3,4]
        controlpoints = [[0, 0, 1], [-1, 1, .96], [0, 2, 1], [1, -1, 1], [1, 0, .8], [1, 1, 1],
                         [2, 1, .89], [2, 2, .9], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]]
        basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1])
        bottom = Surface(basis1, basis2, controlpoints, True)

        vol = vf.edge_surfaces(bottom, top)

        # set parametric domain to [0,1]^2 for easier comparison
        top.reparam()
        bottom.reparam()

        # verify on 7x7x2 evaluation grid
        for u in np.linspace(0, 1, 7):
            for v in np.linspace(0, 1, 7):
                for w in np.linspace(0, 1, 2):  # rational basis, not linear in w-direction
                    self.assertAlmostEqual(
                        vol(u, v, w)[0], bottom(u, v)[0] *
                        (1 - w) + top(u, v)[0] * w)  # x-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[1], bottom(u, v)[1] *
                        (1 - w) + top(u, v)[1] * w)  # y-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w)  # z-coordinate

        # test 3D surface vs 2D surface
        controlpoints = [[0, 0], [-1, 1], [0, 2], [1, -1], [1, 0], [1, 1], [2, 1], [2, 2], [2, 3],
                         [3, 0], [4, 1], [3, 2]]
        basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1])
        bottom = Surface(basis1, basis2, controlpoints)  # non-rational!

        vol = vf.edge_surfaces(bottom, top)  # also non-rational!

        # verify on 5x5x7 evaluation grid
        for u in np.linspace(0, 1, 5):
            for v in np.linspace(0, 1, 5):
                for w in np.linspace(0, 1, 7):  # include inner evaluation points
                    self.assertAlmostEqual(
                        vol(u, v, w)[0], bottom(u, v)[0] *
                        (1 - w) + top(u, v)[0] * w)  # x-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[1], bottom(u, v)[1] *
                        (1 - w) + top(u, v)[1] * w)  # y-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w)  # z-coordinate
Example #2
0
    def test_const_par_crv(self):
        # more or less random 2D surface with p=[2,2] and n=[4,3]
        controlpoints = [[0, 0], [-1, 1], [0, 2], [1, -1], [1, 0], [1, 1],
                         [2, 1], [2, 2], [2, 3], [3, 0], [4, 1], [3, 2]]
        basis1 = BSplineBasis(3, [0, 0, 0, .4, 1, 1, 1])
        basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        surf = Surface(basis1, basis2, controlpoints)
        surf.refine(1)

        # try general knot in u-direction
        crv = surf.const_par_curve(0.3, 'u')
        v = np.linspace(0, 1, 13)
        self.assertTrue(np.allclose(surf(0.3, v), crv(v)))

        # try existing knot in u-direction
        crv = surf.const_par_curve(0.4, 'u')
        v = np.linspace(0, 1, 13)
        self.assertTrue(np.allclose(surf(0.4, v), crv(v)))

        # try general knot in v-direction
        crv = surf.const_par_curve(0.3, 'v')
        u = np.linspace(0, 1, 13)
        self.assertTrue(np.allclose(surf(u, 0.3).reshape(13, 2), crv(u)))

        # try start-point
        crv = surf.const_par_curve(0.0, 'v')
        u = np.linspace(0, 1, 13)
        self.assertTrue(np.allclose(surf(u, 0.0).reshape(13, 2), crv(u)))

        # try end-point
        crv = surf.const_par_curve(1.0, 'v')
        u = np.linspace(0, 1, 13)
        self.assertTrue(np.allclose(surf(u, 1.0).reshape(13, 2), crv(u)))
Example #3
0
    def test_normal(self):
        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)

        xpts = surf(u, v, tensor=False)
        npts = surf.normal(u, v, tensor=False)

        self.assertEqual(npts.shape, (9, 3))

        # check that the normal is pointing out of the unit ball on a 9x9 evaluation grid
        for (x, n) in zip(xpts, npts):
            self.assertAlmostEqual(n[0], x[0])
            self.assertAlmostEqual(n[1], x[1])
            self.assertAlmostEqual(n[2], x[2])

        xpts = surf(u, v)
        npts = surf.normal(u, v)

        self.assertEqual(npts.shape, (9, 9, 3))

        # check that the normal is pointing out of the unit ball on a 9x9 evaluation grid
        for (i, j) in zip(xpts, npts):
            for (x, n) in zip(i, j):
                self.assertAlmostEqual(n[0], x[0])
                self.assertAlmostEqual(n[1], x[1])
                self.assertAlmostEqual(n[2], x[2])

        # check single value input
        n = surf.normal(0, 0)
        self.assertEqual(len(n), 3)

        # test 2D surface
        s = Surface()
        n = s.normal(.5, .5)
        self.assertEqual(len(n), 3)
        self.assertAlmostEqual(n[0], 0.0)
        self.assertAlmostEqual(n[1], 0.0)
        self.assertAlmostEqual(n[2], 1.0)
        n = s.normal([.25, .5], [.1, .2, .3, .4, .5, .6, .7, .8, .9])
        self.assertEqual(n.shape[0], 2)
        self.assertEqual(n.shape[1], 9)
        self.assertEqual(n.shape[2], 3)
        self.assertAlmostEqual(n[1, 4, 0], 0.0)
        self.assertAlmostEqual(n[1, 4, 1], 0.0)
        self.assertAlmostEqual(n[1, 4, 2], 1.0)

        n = s.normal([.25, .5, .75], [.3, .5, .9], tensor=False)
        self.assertEqual(n.shape, (3, 3))
        for i in range(3):
            for j in range(2):
                self.assertAlmostEqual(n[i, j], 0.0)
            self.assertAlmostEqual(n[i, 2], 1.0)

        # test errors
        s = Surface(BSplineBasis(3), BSplineBasis(3), [[0]] * 9)  # 1D-surface
        with self.assertRaises(RuntimeError):
            s.normal(.5, .5)
Example #4
0
def square(size=1, lower_left=(0, 0)):
    """  Create a square with parametric origin at *(0,0)*.

    :param float size: Size(s), either a single scalar or a tuple of scalars per axis
    :param array-like lower_left: local origin, the lower left corner of the square
    :return: A linear parametrized square
    :rtype: Surface
    """
    result = Surface()  # unit square
    result.scale(size)
    result += lower_left
    return result
Example #5
0
    def test_3d_self_connection(self):
        square = Surface() + [1, 0]
        square = square.rotate(np.pi / 2, (1, 0, 0))
        vol = volume_factory.revolve(square)
        vol = vol.split(vol.knots('w')[0], direction='w')  # break periodicity
        model = SplineModel(3, 3)
        model.add(vol, raise_on_twins=False)

        writer = IFEMWriter(model)
        expected = [IFEMConnection(1, 1, 5, 6, 0)]
        for connection, want in zip(writer.connections(), expected):
            self.assertEqual(connection, want)
Example #6
0
    def test_revolve(self):
        # square torus
        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.reparam()  # set parametric space to (0,1)^3
        u = np.linspace(0, 1, 7)
        v = np.linspace(0, 1, 7)
        w = np.linspace(0, 1, 7)
        x = vol.evaluate(u, v, w)
        V, U, W = np.meshgrid(v, u, w)
        R = np.sqrt(x[:, :, :, 0]**2 + x[:, :, :, 1]**2)

        self.assertEqual(np.allclose(R, U + 1), True)
        self.assertEqual(np.allclose(x[:, :, :, 2], V), True)
        self.assertAlmostEqual(vol.volume(), 2 * pi * 1.5, places=3)

        # test incomplete reolve
        vol = VolumeFactory.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)
        w = np.linspace(0, 1, 7)
        x = vol.evaluate(u, v, w)
        V, U, W = np.meshgrid(v, u, w)
        R = np.sqrt(x[:, :, :, 0]**2 + x[:, :, :, 1]**2)

        self.assertEqual(np.allclose(R, U + 1), True)
        self.assertEqual(np.allclose(x[:, :, :, 2], V), True)
        self.assertAlmostEqual(vol.volume(), 2 * pi * 1.5 / 6, places=3)
        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.reparam()  # set parametric space to (0,1)^3
        u = np.linspace(0, 1, 7)
        v = np.linspace(0, 1, 7)
        w = np.linspace(0, 1, 7)
        x = vol.evaluate(u, v, w)
        V, U, W = np.meshgrid(v, u, w)
        R = np.sqrt(x[:, :, :, 1]**2 + x[:, :, :, 2]**2)

        self.assertEqual(np.allclose(R, V + 1), True)
        self.assertEqual(np.allclose(x[:, :, :, 0], U + 1), True)
        self.assertTrue(np.all(x >= 0))  # completely contained in first octant
Example #7
0
def square(size=1, lower_left=(0,0)):
    """square([size=1])

    Create a square with parametric origin at *(0,0)*.

    :param size: Size(s), either a single scalar or a tuple of scalars per axis
    :type size: float or (float)
    :return: A linear parametrized square
    :rtype: Surface
    """
    result = Surface()  # unit square
    result.scale(size)
    result += lower_left
    return result
Example #8
0
 def test_multiplicity(self):
     surf = Surface()
     surf.refine(1)
     surf.raise_order(1)
     surf.refine(1)
     self.assertTrue(
         np.allclose(multiplicities(surf),
                     [[3, 1, 2, 1, 3], [3, 1, 2, 1, 3]]))
Example #9
0
def interpolate(x, bases, u=None):
    """  Interpolate a surface on a set of regular gridded interpolation points `x`.

    The points can be either a matrix (in which case the first index is
    interpreted as a flat row-first index of the interpolation grid) or a 3D
    tensor. In both cases the last index is the physical coordinates.

    :param numpy.ndarray x: Grid of interpolation points
    :param [BSplineBasis] bases: The basis to interpolate on
    :param [array-like] u: Parametric interpolation points, defaults to
        Greville points of the basis
    :return: Interpolated surface
    :rtype: Surface
    """
    surf_shape = [b.num_functions() for b in bases]
    dim = x.shape[-1]
    if len(x.shape) == 2:
        x = x.reshape(surf_shape + [dim])
    if u is None:
        u = [b.greville() for b in bases]
    N_all = [b(t) for b, t in zip(bases, u)]
    N_all.reverse()
    cp = x
    for N in N_all:
        cp = np.tensordot(np.linalg.inv(N), cp, axes=(1, 1))

    return Surface(bases[0], bases[1],
                   cp.transpose(1, 0, 2).reshape((np.prod(surf_shape), dim)))
Example #10
0
def least_square_fit(x, bases, u):
    """  Perform a least-square fit of a point cloud `x` onto a spline basis.

    The points can be either a matrix (in which case the first index is
    interpreted as a flat row-first index of the interpolation grid) or a 3D
    tensor. In both cases the last index is the physical coordinates.

    There must be at least as many points as basis functions.

    :param numpy.ndarray x: Grid of evaluation points
    :param [BSplineBasis] bases: Basis on which to interpolate
    :param [array-like] u: Parametric values at evaluation points
    :return: Approximated surface
    :rtype: Surface
    """
    surf_shape = [b.num_functions() for b in bases]
    dim = x.shape[-1]
    if len(x.shape) == 2:
        x = x.reshape(surf_shape + [dim])
    N_all = [b(t) for b, t in zip(bases, u)]
    N_all.reverse()
    cp = x
    for N in N_all:
        cp = np.tensordot(N.T, cp, axes=(1, 1))
    for N in N_all:
        cp = np.tensordot(np.linalg.inv(N.T @ N), cp, axes=(1, 1))

    return Surface(bases[0], bases[1],
                   cp.transpose(1, 0, 2).reshape((np.prod(surf_shape), dim)))
Example #11
0
    def read_surface(self, nsrf):
        knotsu = [0]
        for i in nsrf.KnotsU:
            knotsu.append(i)
        knotsu.append(knotsu[len(knotsu) - 1])
        knotsu[0] = knotsu[1]

        knotsv = [0]
        for i in nsrf.KnotsV:
            knotsv.append(i)
        knotsv.append(knotsv[len(knotsv) - 1])
        knotsv[0] = knotsv[1]

        basisu = BSplineBasis(nsrf.OrderU, knotsu, -1)
        basisv = BSplineBasis(nsrf.OrderV, knotsv, -1)
        cpts = []

        cpts = np.ndarray(
            (nsrf.Points.CountU * nsrf.Points.CountV, 3 + nsrf.IsRational))
        for v in range(0, nsrf.Points.CountV):
            for u in range(0, nsrf.Points.CountU):
                cpts[u + v * nsrf.Points.CountU, 0] = nsrf.Points[u, v].X
                cpts[u + v * nsrf.Points.CountU, 1] = nsrf.Points[u, v].Y
                cpts[u + v * nsrf.Points.CountU, 2] = nsrf.Points[u, v].Z
                if nsrf.IsRational:
                    cpts[u + v * nsrf.Points.CountU, 3] = nsrf.Points[u, v].W

        return Surface(basisu, basisv, cpts, nsrf.IsRational)
Example #12
0
def teapot():
    """  Generate the Utah teapot as 32 cubic bezier patches. This teapot has a
    rim, but no bottom. It is also self-intersecting making it unsuitable for
    perfect-match multipatch modeling.

    The data is picked from http://www.holmes3d.net/graphics/teapot/

    :return: The utah teapot
    :rtype: List of Surface
    """
    path = join(dirname(realpath(__file__)), 'templates', 'teapot.bpt')
    with open(path) as f:
        results = []
        numb_patches = int(f.readline())
        for i in range(numb_patches):
            p = np.fromstring(f.readline(), dtype=np.uint8, count=2, sep=' ')
            basis1 = BSplineBasis(p[0] + 1)
            basis2 = BSplineBasis(p[1] + 1)

            ncp = basis1.num_functions() * basis2.num_functions()
            cp = [
                np.fromstring(f.readline(), dtype=np.float, count=3, sep=' ')
                for j in range(ncp)
            ]
            results.append(Surface(basis1, basis2, cp))

    return results
Example #13
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 #14
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 = cf.circle_segment(pi / 2)
        c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]),
                   [[0, 1], [-1, 1], [-1, 0]])
        c3 = cf.circle_segment(pi / 2)
        c3.rotate(pi)
        c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]])

        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()
        c4.reverse()
        c1.reparam()
        c2.reparam()
        c3.reparam()
        c4.reparam()

        for u in np.linspace(0, 1, 7):
            self.assertAlmostEqual(surf(u, 0)[0],
                                   c1(u)[0])  # x-coord, bottom crv
            self.assertAlmostEqual(surf(u, 0)[1],
                                   c1(u)[1])  # y-coord, bottom crv
        for u in np.linspace(0, 1, 7):
            self.assertAlmostEqual(surf(u, 1)[0], c3(u)[0])  # x-coord, top crv
            self.assertAlmostEqual(surf(u, 1)[1], c3(u)[1])  # y-coord, top crv
        for v in np.linspace(0, 1, 7):
            self.assertAlmostEqual(surf(0, v)[0],
                                   c4(v)[0])  # x-coord, left crv
            self.assertAlmostEqual(surf(0, v)[1],
                                   c4(v)[1])  # y-coord, left crv
        for v in np.linspace(0, 1, 7):
            self.assertAlmostEqual(surf(1, v)[0],
                                   c2(v)[0])  # x-coord, right crv
            self.assertAlmostEqual(surf(1, v)[1],
                                   c2(v)[1])  # y-coord, right crv

        # add a case where opposing sites have mis-matching rationality
        crvs = Surface().edges()  # returned in order umin, umax, vmin, vmax
        crvs[0].force_rational()
        crvs[1].reverse()
        crvs[2].reverse()
        # input curves should be clockwise oriented closed loop
        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 = 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 = sf.edge_curves(crvs + (Curve(), ))  # 5 input curves
Example #15
0
    def read(self):
        lines = self.lines()

        version = next(lines).split()
        assert version[0] == 'C'
        assert version[3] == '0'  # No support for rational SPL yet
        pardim = int(version[1])
        physdim = int(version[2])

        orders = [int(k) for k in islice(lines, pardim)]
        ncoeffs = [int(k) for k in islice(lines, pardim)]
        totcoeffs = int(np.prod(ncoeffs))
        nknots = [a + b for a, b in zip(orders, ncoeffs)]

        next(lines)  # Skip spline accuracy

        knots = [[float(k) for k in islice(lines, nkts)] for nkts in nknots]
        bases = [BSplineBasis(p, kts, -1) for p, kts in zip(orders, knots)]

        cpts = np.array([float(k) for k in islice(lines, totcoeffs * physdim)])
        cpts = cpts.reshape(physdim, *(ncoeffs[::-1])).transpose()

        if pardim == 1:
            patch = Curve(*bases, controlpoints=cpts, raw=True)
        elif pardim == 2:
            patch = Surface(*bases, controlpoints=cpts, raw=True)
        elif pardim == 3:
            patch = Volume(*bases, controlpoints=cpts, raw=True)
        else:
            patch = SplineObject(bases, controlpoints=cpts, raw=True)

        return [patch]
Example #16
0
def poisson_patch(bottom, right, top, left):
    from nutils import version
    if version != '3.0':
        raise ImportError('Outdated nutils version detected, only v3.0 supported. Upgrade by \"pip install --upgrade nutils\"')

    from nutils import mesh, function as fn
    from nutils import _, log

    # error test input
    if left.rational or right.rational or top.rational or bottom.rational:
        raise RuntimeError('poisson_patch not supported for rational splines')

    # these are given as a oriented loop, so make all run in positive parametric direction
    top.reverse()
    left.reverse()

    # in order to add spline surfaces, they need identical parametrization
    Curve.make_splines_identical(top, bottom)
    Curve.make_splines_identical(left, right)

    # create computational (nutils) mesh
    p1 = bottom.order(0)
    p2 = left.order(0)
    n1 = len(bottom)
    n2 = len(left)
    dim= left.dimension
    k1 = bottom.knots(0)
    k2 = left.knots(0)
    m1 = [bottom.order(0) - bottom.continuity(k) - 1 for k in k1]
    m2 = [left.order(0)   - left.continuity(k)   - 1 for k in k2]
    domain, geom = mesh.rectilinear([k1, k2])
    basis = domain.basis('spline', [p1-1, p2-1], knotmultiplicities=[m1,m2])

    # assemble system matrix
    grad      = basis.grad(geom)
    outer     = fn.outer(grad,grad)
    integrand = outer.sum(-1)
    matrix = domain.integrate(integrand, geometry=geom, ischeme='gauss'+str(max(p1,p2)+1))

    # initialize variables
    controlpoints = np.zeros((n1,n2,dim))
    rhs           = np.zeros((n1*n2))
    constraints = np.array([[np.nan]*n2]*n1)

    # treat all dimensions independently
    for d in range(dim):
        # add boundary conditions
        constraints[ 0, :] = left[  :,d]
        constraints[-1, :] = right[ :,d]
        constraints[ :, 0] = bottom[:,d]
        constraints[ :,-1] = top[   :,d]

        # solve system
        lhs = matrix.solve(rhs, constrain=np.ndarray.flatten(constraints), solver='cg', tol=state.controlpoint_absolute_tolerance)

        # wrap results into splipy datastructures
        controlpoints[:,:,d] = np.reshape(lhs, (n1,n2), order='C')

    return Surface(bottom.bases[0], left.bases[0], controlpoints, bottom.rational, raw=True)
Example #17
0
    def test_revolve(self):
        # square torus
        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.reparam()  # set parametric space to (0,1)^3
        u = np.linspace(0, 1, 7)
        v = np.linspace(0, 1, 7)
        w = np.linspace(0, 1, 7)
        x = vol.evaluate(u,v,w)
        V,U,W = np.meshgrid(v,u,w)
        R = np.sqrt(x[:,:,:,0]**2 + x[:,:,:,1]**2)

        self.assertEqual(np.allclose(R, U+1), True)
        self.assertEqual(np.allclose(x[:,:,:,2], V), True)
        self.assertAlmostEqual(vol.volume(), 2*pi*1.5, places=3)
    def test_revolve(self):
        # square torus
        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.reparam()  # set parametric space to (0,1)^3
        u = np.linspace(0, 1, 7)
        v = np.linspace(0, 1, 7)
        w = np.linspace(0, 1, 7)
        x = vol.evaluate(u,v,w)
        V,U,W = np.meshgrid(v,u,w)
        R = np.sqrt(x[:,:,:,0]**2 + x[:,:,:,1]**2)

        self.assertEqual(np.allclose(R, U+1), True)
        self.assertEqual(np.allclose(x[:,:,:,2], V), True)
        self.assertAlmostEqual(vol.volume(), 2*pi*1.5, places=3)

        # test incomplete reolve
        vol = VolumeFactory.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)
        w = np.linspace(0, 1, 7)
        x = vol.evaluate(u,v,w)
        V,U,W = np.meshgrid(v,u,w)
        R = np.sqrt(x[:,:,:,0]**2 + x[:,:,:,1]**2)

        self.assertEqual(np.allclose(R, U+1), True)
        self.assertEqual(np.allclose(x[:,:,:,2], V), True)
        self.assertAlmostEqual(vol.volume(), 2*pi*1.5/6, places=3)
        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.reparam()  # set parametric space to (0,1)^3
        u = np.linspace(0, 1, 7)
        v = np.linspace(0, 1, 7)
        w = np.linspace(0, 1, 7)
        x = vol.evaluate(u,v,w)
        V,U,W = np.meshgrid(v,u,w)
        R = np.sqrt(x[:,:,:,1]**2 + x[:,:,:,2]**2)

        self.assertEqual(np.allclose(R, V+1), True)
        self.assertEqual(np.allclose(x[:,:,:,0], U+1), True)
        self.assertTrue(np.all(x >= 0)) # completely contained in first octant
Example #19
0
def coons_patch(bottom, right, top, left):
    # coons patch (https://en.wikipedia.org/wiki/Coons_patch)
    top.reverse()
    left.reverse()

    # create linear interpolation between opposing sides
    s1 = edge_curves(bottom, top)
    s2 = edge_curves(left, right)
    s2.swap()
    # create (linear,linear) corner parametrization
    linear = BSplineBasis(2)
    rat = s1.rational  # using control-points from top/bottom, so need to know if these are rational
    if rat:
        bottom = bottom.clone().force_rational() # don't mess with the input curve, make clone
        top.force_rational()                     # this is already a clone
    s3 = Surface(linear, linear, [bottom[0], bottom[-1], top[0], top[-1]], rat)

    # in order to add spline surfaces, they need identical parametrization
    Surface.make_splines_identical(s1, s2)
    Surface.make_splines_identical(s1, s3)
    Surface.make_splines_identical(s2, s3)

    result = s1
    result.controlpoints += s2.controlpoints
    result.controlpoints -= s3.controlpoints
    return result
Example #20
0
def revolve(curve, theta=2 * pi, axis=[0,0,1]):
    """revolve(curve, [theta=2pi], [axis=[0,0,1]])

    Revolve a surface by sweeping a curve in a rotational fashion around the
    *z* axis.

    :param Curve curve: Curve to revolve
    :param float theta: Angle to revolve, in radians
    :param vector-like axis: Axis of rotation
    :return: The revolved surface
    :rtype: Surface
    """
    curve = curve.clone()  # clone input curve, throw away input reference
    curve.set_dimension(3)  # add z-components (if not already present)
    curve.force_rational()  # add weight (if not already present)

    # align axis with the z-axis
    normal_theta = atan2(axis[1], axis[0])
    normal_phi   = atan2(sqrt(axis[0]**2 + axis[1]**2), axis[2])
    curve.rotate(-normal_theta, [0,0,1])
    curve.rotate(-normal_phi,   [0,1,0])

    circle_seg = CurveFactory.circle_segment(theta)

    n = len(curve)      # number of control points of the curve
    m = len(circle_seg) # number of control points of the sweep
    cp = np.zeros((m * n, 4))

    # loop around the circle and set control points by the traditional 9-point
    # circle curve with weights 1/sqrt(2), only here C0-periodic, so 8 points
    dt = 0
    t  = 0
    for i in range(m):
        x,y,w = circle_seg[i]
        dt  = atan2(y,x) - t
        t  += dt
        curve.rotate(dt)
        cp[i * n:(i + 1) * n, :]  = curve[:]
        cp[i * n:(i + 1) * n, 2] *= w
        cp[i * n:(i + 1) * n, 3] *= w
    result = Surface(curve.bases[0], circle_seg.bases[0], cp, True)
    # rotate it back again
    result.rotate(normal_phi,   [0,1,0])
    result.rotate(normal_theta, [0,0,1])
    return result
Example #21
0
    def test_make_identical(self):
        basis1 = BSplineBasis(4, [-1, -1, 0, 0, 1, 2, 9, 9, 10, 10, 11, 12],
                              periodic=1)
        basis2 = BSplineBasis(2, [0, 0, .25, 1, 1])
        cp = [[0, 0, 0, 1], [1, 0, 0, 1.1], [2, 0, 0, 1], [0, 1, 0, .7],
              [1, 1, 0, .8], [2, 1, 0, 1], [0, 2, 0, 1], [1, 2, 0, 1.2],
              [2, 2, 0, 1]]
        surf1 = Surface(BSplineBasis(3), BSplineBasis(3), cp,
                        True)  # rational 3D
        surf2 = Surface(basis1, basis2)  # periodic 2D
        surf1.insert_knot([0.25, .5, .75], direction='v')

        Surface.make_splines_identical(surf1, surf2)

        for s in (surf1, surf2):
            self.assertEqual(s.periodic(0), False)
            self.assertEqual(s.periodic(1), False)
            self.assertEqual(s.dimension, 3)
            self.assertEqual(s.rational, True)
            self.assertEqual(s.order(), (4, 3))

            self.assertAlmostEqual(len(s.knots(0, True)), 12)
            self.assertAlmostEqual(len(s.knots(1, True)), 10)

            self.assertEqual(s.bases[1].continuity(.25), 0)
            self.assertEqual(s.bases[1].continuity(.75), 1)
            self.assertEqual(s.bases[0].continuity(.2), 2)
            self.assertEqual(s.bases[0].continuity(.9), 1)
Example #22
0
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 == 'curve':
        return Curve(basis, rational=rational)
    elif spline == 'surface':
        return Surface(basis, basis, rational=rational)
    elif spline == 'volume':
        return Volume(basis, basis, basis, rational=rational)
    return None
Example #23
0
    def test_split(self):
        # test a rational 2D surface
        controlpoints = [[0, 0, 1], [-1, 1, .96], [0, 2, 1], [1, -1, 1],
                         [1, 0, .8], [1, 1, 1], [2, 1, .89], [2, 2, .9],
                         [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]]
        basis1 = BSplineBasis(3, [1, 1, 1, 1.4, 5, 5, 5])
        basis2 = BSplineBasis(3, [2, 2, 2, 7, 7, 7])
        surf = Surface(basis1, basis2, controlpoints, True)

        split_u_surf = surf.split([1.1, 1.6, 4], 0)
        split_v_surf = surf.split(3.1, 1)

        self.assertEqual(len(split_u_surf), 4)
        self.assertEqual(len(split_v_surf), 2)

        # check that the u-vector is properly split
        self.assertAlmostEqual(split_u_surf[0].start()[0], 1.0)
        self.assertAlmostEqual(split_u_surf[0].end()[0], 1.1)
        self.assertAlmostEqual(split_u_surf[1].start()[0], 1.1)
        self.assertAlmostEqual(split_u_surf[1].end()[0], 1.6)
        self.assertAlmostEqual(split_u_surf[2].start()[0], 1.6)
        self.assertAlmostEqual(split_u_surf[2].end()[0], 4.0)
        self.assertAlmostEqual(split_u_surf[3].start()[0], 4.0)
        self.assertAlmostEqual(split_u_surf[3].end()[0], 5.0)
        # check that the v-vectors remain unchanged
        self.assertAlmostEqual(split_u_surf[2].start()[1], 2.0)
        self.assertAlmostEqual(split_u_surf[2].end()[1], 7.0)
        # check that the v-vector is properly split
        self.assertAlmostEqual(split_v_surf[0].start()[1], 2.0)
        self.assertAlmostEqual(split_v_surf[0].end()[1], 3.1)
        self.assertAlmostEqual(split_v_surf[1].start()[1], 3.1)
        self.assertAlmostEqual(split_v_surf[1].end()[1], 7.0)
        # check that the u-vector remain unchanged
        self.assertAlmostEqual(split_v_surf[1].start()[0], 1.0)
        self.assertAlmostEqual(split_v_surf[1].end()[0], 5.0)

        # check that evaluations remain unchanged
        pt1 = surf(3.23, 2.12)

        self.assertAlmostEqual(split_u_surf[2].evaluate(3.23, 2.12)[0], pt1[0])
        self.assertAlmostEqual(split_u_surf[2].evaluate(3.23, 2.12)[1], pt1[1])

        self.assertAlmostEqual(split_v_surf[0].evaluate(3.23, 2.12)[0], pt1[0])
        self.assertAlmostEqual(split_v_surf[0].evaluate(3.23, 2.12)[1], pt1[1])
Example #24
0
def revolve(curve, theta=2 * pi, axis=(0,0,1)):
    """  Revolve a surface by sweeping a curve in a rotational fashion around
    the *z* axis.

    :param Curve curve: Curve to revolve
    :param float theta: Angle to revolve, in radians
    :param array-like axis: Axis of rotation
    :return: The revolved surface
    :rtype: Surface
    """
    curve = curve.clone()  # clone input curve, throw away input reference
    curve.set_dimension(3)  # add z-components (if not already present)
    curve.force_rational()  # add weight (if not already present)

    # align axis with the z-axis
    normal_theta = atan2(axis[1], axis[0])
    normal_phi   = atan2(sqrt(axis[0]**2 + axis[1]**2), axis[2])
    curve.rotate(-normal_theta, [0,0,1])
    curve.rotate(-normal_phi,   [0,1,0])

    circle_seg = CurveFactory.circle_segment(theta)

    n = len(curve)      # number of control points of the curve
    m = len(circle_seg) # number of control points of the sweep
    cp = np.zeros((m * n, 4))

    # loop around the circle and set control points by the traditional 9-point
    # circle curve with weights 1/sqrt(2), only here C0-periodic, so 8 points
    dt = 0
    t  = 0
    for i in range(m):
        x,y,w = circle_seg[i]
        dt  = atan2(y,x) - t
        t  += dt
        curve.rotate(dt)
        cp[i * n:(i + 1) * n, :]  = curve[:]
        cp[i * n:(i + 1) * n, 2] *= w
        cp[i * n:(i + 1) * n, 3] *= w
    result = Surface(curve.bases[0], circle_seg.bases[0], cp, True)
    # rotate it back again
    result.rotate(normal_phi,   [0,1,0])
    result.rotate(normal_theta, [0,0,1])
    return result
Example #25
0
 def test_repr(self):
     major, minor, patch = np.version.version.split('.')
     if int(major) <= 1 and int(minor) <= 13:
         self.assertEqual(
             repr(Surface()), 'p=2, [ 0.  0.  1.  1.]\n'
             'p=2, [ 0.  0.  1.  1.]\n'
             '[ 0.  0.]\n'
             '[ 1.  0.]\n'
             '[ 0.  1.]\n'
             '[ 1.  1.]\n')
Example #26
0
def loft(*curves):
    if len(curves) == 1:
        curves = curves[0]

    # clone input, so we don't change those references
    # make sure everything has the same dimension since we need to compute length
    curves = [c.clone().set_dimension(3) for c in curves]
    if len(curves)==2:
        return edge_curves(curves)
    elif len(curves)==3:
        # can't do cubic spline interpolation, so we'll do quadratic
        basis2 = BSplineBasis(3)
        dist  = basis2.greville()
    else:
        x = [c.center() for c in curves]

        # create knot vector from the euclidian length between the curves
        dist = [0]
        for (x1,x0) in zip(x[1:],x[:-1]):
            dist.append(dist[-1] + np.linalg.norm(x1-x0))

        # using "free" boundary condition by setting N'''(u) continuous at second to last and second knot
        knot = [dist[0]]*4 + dist[2:-2] + [dist[-1]]*4
        basis2 = BSplineBasis(4, knot)

    n = len(curves)
    for i in range(n):
        for j in range(i+1,n):
            Curve.make_splines_identical(curves[i], curves[j])

    basis1 = curves[0].bases[0]
    m      = basis1.num_functions()
    u      = basis1.greville() # parametric interpolation points
    v      = dist              # parametric interpolation points

    # compute matrices
    Nu     = basis1(u)
    Nv     = basis2(v)
    Nu_inv = np.linalg.inv(Nu)
    Nv_inv = np.linalg.inv(Nv)

    # compute interpolation points in physical space
    x      = np.zeros((m,n, curves[0][0].size))
    for i in range(n):
        x[:,i,:] = Nu * curves[i].controlpoints

    # solve interpolation problem
    cp = np.tensordot(Nv_inv, x,  axes=(1,1))
    cp = np.tensordot(Nu_inv, cp, axes=(1,1))

    # re-order controlpoints so they match up with Surface constructor
    cp = cp.transpose((1, 0, 2))
    cp = cp.reshape(n*m, cp.shape[2])

    return Surface(basis1, basis2, cp, curves[0].rational)
Example #27
0
    def test_edge_surfaces(self):
        # test 3D surface vs 2D rational surface

        # more or less random 3D surface with p=[2,2] and n=[3,4]
        controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 1], [1, 0, .5], [1, 1, 1],
                         [2, 1, 1], [2, 2, .5], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]]
        basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        basis2 = BSplineBasis(3, [0, 0, 0, .64, 2, 2, 2])
        top = Surface(basis1, basis2, controlpoints)

        # more or less random 2D rational surface with p=[1,2] and n=[3,4]
        controlpoints = [[0, 0, 1], [-1, 1, .96], [0, 2, 1], [1, -1, 1], [1, 0, .8], [1, 1, 1],
                         [2, 1, .89], [2, 2, .9], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]]
        basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1])
        bottom = Surface(basis1, basis2, controlpoints, True)

        vol = VolumeFactory.edge_surfaces(bottom, top)

        # set parametric domain to [0,1]^2 for easier comparison
        top.reparam()
        bottom.reparam()

        # verify on 7x7x2 evaluation grid
        for u in np.linspace(0, 1, 7):
            for v in np.linspace(0, 1, 7):
                for w in np.linspace(0, 1, 2):  # rational basis, not linear in w-direction
                    self.assertAlmostEqual(
                        vol(u, v, w)[0], bottom(u, v)[0] *
                        (1 - w) + top(u, v)[0] * w)  # x-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[1], bottom(u, v)[1] *
                        (1 - w) + top(u, v)[1] * w)  # y-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w)  # z-coordinate

        # test 3D surface vs 2D surface
        controlpoints = [[0, 0], [-1, 1], [0, 2], [1, -1], [1, 0], [1, 1], [2, 1], [2, 2], [2, 3],
                         [3, 0], [4, 1], [3, 2]]
        basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        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!

        # verify on 5x5x7 evaluation grid
        for u in np.linspace(0, 1, 5):
            for v in np.linspace(0, 1, 5):
                for w in np.linspace(0, 1, 7):  # include inner evaluation points
                    self.assertAlmostEqual(
                        vol(u, v, w)[0], bottom(u, v)[0] *
                        (1 - w) + top(u, v)[0] * w)  # x-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[1], bottom(u, v)[1] *
                        (1 - w) + top(u, v)[1] * w)  # y-coordinate
                    self.assertAlmostEqual(
                        vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w)  # z-coordinate
Example #28
0
    def test_evaluate(self):
        # knot vector [t_1, t_2, ... t_{n+p+1}]
        # polynomial degree p (order-1)
        # n basis functions N_i(t), for i=1...n
        # the power basis {1,t,t^2,t^3,...} can be expressed as:
        # 1     = sum         N_i(t)
        # t     = sum ts_i  * N_i(t)
        # t^2   = sum t2s_i * N_i(t)
        # ts_i  = sum_{j=i+1}^{i+p}   t_j / p
        # t2s_i = sum_{j=i+1}^{i+p-1} sum_{k=j+1}^{i+p} t_j*t_k / (p 2)
        # (p 2) = binomial coefficient

        # creating the mapping:
        #   x(u,v) = u^2*v + u(1-v)
        #   y(u,v) = v
        controlpoints = [[0, 0], [1.0 / 4, 0], [3.0 / 4, 0], [.75, 0], [0, 1],
                         [0, 1], [.5, 1], [1, 1]]
        basis1 = BSplineBasis(3, [0, 0, 0, .5, 1, 1, 1])
        basis2 = BSplineBasis(2, [0, 0, 1, 1])
        surf = Surface(basis1, basis2, controlpoints)

        # call evaluation at a 5x4 grid of points
        val = surf([0, .2, .5, .6, 1], [0, .2, .4, 1])
        self.assertEqual(len(val.shape),
                         3)  # result should be wrapped in 3-index tensor
        self.assertEqual(val.shape[0], 5)  # 5 evaluation points in u-direction
        self.assertEqual(val.shape[1], 4)  # 4 evaluation points in v-direction
        self.assertEqual(val.shape[2], 2)  # 2 coordinates (x,y)

        # check evaluation at (0,0)
        self.assertAlmostEqual(val[0][0][0], 0.0)
        self.assertAlmostEqual(val[0][0][1], 0.0)
        # check evaluation at (.2,0)
        self.assertAlmostEqual(val[1][0][0], 0.2)
        self.assertAlmostEqual(val[1][0][1], 0.0)
        # check evaluation at (.2,.2)
        self.assertAlmostEqual(val[1][1][0], 0.168)
        self.assertAlmostEqual(val[1][1][1], 0.2)
        # check evaluation at (.5,.4)
        self.assertAlmostEqual(val[2][2][0], 0.4)
        self.assertAlmostEqual(val[2][2][1], 0.4)
        # check evaluation at (.6,1)
        self.assertAlmostEqual(val[3][3][0], 0.36)
        self.assertAlmostEqual(val[3][3][1], 1)

        # test errors and exceptions
        with self.assertRaises(ValueError):
            val = surf(-10, .5)  # evalaute outside parametric domain
        with self.assertRaises(ValueError):
            val = surf(+10, .3)  # evalaute outside parametric domain
        with self.assertRaises(ValueError):
            val = surf(.5, -10)  # evalaute outside parametric domain
        with self.assertRaises(ValueError):
            val = surf(.5, +10)  # evalaute outside parametric domain
Example #29
0
    def test_edges(self):
        (umin, umax, vmin, vmax) = Surface().edges()
        # check controlpoints
        self.assertAlmostEqual(umin[0, 0], 0)
        self.assertAlmostEqual(umin[0, 1], 0)
        self.assertAlmostEqual(umin[1, 0], 0)
        self.assertAlmostEqual(umin[1, 1], 1)

        self.assertAlmostEqual(umax[0, 0], 1)
        self.assertAlmostEqual(umax[0, 1], 0)
        self.assertAlmostEqual(umax[1, 0], 1)
        self.assertAlmostEqual(umax[1, 1], 1)

        self.assertAlmostEqual(vmin[0, 0], 0)
        self.assertAlmostEqual(vmin[0, 1], 0)
        self.assertAlmostEqual(vmin[1, 0], 1)
        self.assertAlmostEqual(vmin[1, 1], 0)

        # check a slightly more general surface
        cp = [[0, 0], [.5, -.5], [1, 0], [-.6, 1], [1, 1], [2, 1.4], [0, 2],
              [.8, 3], [2, 2.4]]
        surf = Surface(BSplineBasis(3), BSplineBasis(3), cp)
        edg = surf.edges()
        u = np.linspace(0, 1, 9)
        v = np.linspace(0, 1, 9)

        pt = surf(0, v)
        pt2 = edg[0](v)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)

        pt = surf(1, v)
        pt2 = edg[1](v)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)

        pt = surf(u, 0).reshape(9, 2)
        pt2 = edg[2](u)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)

        pt = surf(u, 1).reshape(9, 2)
        pt2 = edg[3](u)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)
Example #30
0
    def test_force_rational(self):
        # more or less random 3D surface with p=[3,2] and n=[4,3]
        controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 1],
                         [1, 0, 1], [1, 1, 1], [2, 1, 1], [2, 2, 1], [2, 3, 1],
                         [3, 0, 1], [4, 1, 1], [3, 2, 1]]
        basis1 = BSplineBasis(4, [0, 0, 0, 0, 2, 2, 2, 2])
        basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        surf = Surface(basis1, basis2, controlpoints)

        evaluation_point1 = surf(0.23, .66)
        control_point1 = surf[0]
        surf.force_rational()
        evaluation_point2 = surf(0.23, .66)
        control_point2 = surf[0]
        # ensure that surface has not chcanged, by comparing evaluation of it
        self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0])
        self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1])
        self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2])
        # ensure that we include rational weights of 1
        self.assertEqual(len(control_point1), 3)
        self.assertEqual(len(control_point2), 4)
        self.assertEqual(control_point2[3], 1)
        self.assertEqual(surf.rational, True)
Example #31
0
def ifem_solve(root, mu, i):
    with open('case.xinp') as f:
        template = Template(f.read())
    with open(root / 'case.xinp', 'w') as f:
        f.write(template.render(geometry='square.g2', **mu))

    patch = Surface()
    patch.set_dimension(3)
    with G2(str(root / 'square.g2')) as g2:
        g2.write(patch)
        try:
            g2.fstream.close()
        except:
            pass

    result = run([
        '/home/eivind/repos/IFEM/Apps/Poisson/build/bin/Poisson', 'case.xinp',
        '-adap', '-hdf5'
    ],
                 cwd=root,
                 stdout=PIPE,
                 stderr=PIPE)
    result.check_returncode()

    with h5py.File(root / 'case.hdf5', 'r') as h5:
        final = str(len(h5) - 1)
        group = h5[final]['Poisson-1']
        patchbytes = group['basis']['1'][:].tobytes()
        geompatch = lr.LRSplineSurface(patchbytes)
        coeffs = group['fields']['u']['1'][:]
        solpatch = geompatch.clone()
        solpatch.controlpoints = coeffs.reshape(len(solpatch), -1)

        with open(f'poisson-mesh-single-{i}.ps', 'wb') as f:
            geompatch.write_postscript(f)

        return geompatch, solpatch
Example #32
0
    def test_swap(self):
        # more or less random 3D surface with p=[2,2] and n=[4,3]
        controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 1],
                         [1, 0, .5], [1, 1, 1], [2, 1, 1], [2, 2, .5],
                         [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]]
        basis1 = BSplineBasis(3, [0, 0, 0, .64, 2, 2, 2])
        basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1])
        surf = Surface(basis1, basis2, controlpoints)

        evaluation_point1 = surf(0.23, .56)
        control_point1 = surf[1]  # this is control point i=(1,0), when n=(4,3)
        surf.swap()
        evaluation_point2 = surf(0.56, .23)
        control_point2 = surf[3]  # this is control point i=(0,1), when n=(3,4)

        # ensure that surface has not chcanged, by comparing evaluation of it
        self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0])
        self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1])
        self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2])

        # check that the control points have re-ordered themselves
        self.assertEqual(control_point1[0], control_point2[0])
        self.assertEqual(control_point1[1], control_point2[1])
        self.assertEqual(control_point1[2], control_point2[2])
Example #33
0
    def test_reverse(self):
        basis1 = BSplineBasis(4, [2, 2, 2, 2, 3, 6, 7, 7, 7, 7])
        basis2 = BSplineBasis(3, [-3, -3, -3, 20, 30, 31, 31, 31])
        surf = Surface(basis1, basis2)
        surf2 = Surface(basis1, basis2)
        surf3 = Surface(basis1, basis2)

        surf2.reverse('v')
        surf3.reverse('u')

        for i in range(6):
            # loop over surf forward, and surf2 backward (in 'v'-direction)
            for (cp1, cp2) in zip(surf[i, :, :], surf2[i, ::-1, :]):
                self.assertAlmostEqual(cp1[0], cp2[0])
                self.assertAlmostEqual(cp1[1], cp2[1])

        for j in range(5):
            # loop over surf forward, and surf3 backward (in 'u'-direction)
            for (cp1, cp2) in zip(surf[:, j, :], surf3[::-1, j, :]):
                self.assertAlmostEqual(cp1[0], cp2[0])
                self.assertAlmostEqual(cp1[1], cp2[1])
Example #34
0
def edge_curves(*curves):
    """edge_curves(curves...)

    Create the surface defined by the region between the input curves.

    In case of four input curves, these must be given in an ordered directional
    closed loop around the resulting surface.

    :param [Curve] curves: Two or four edge curves
    :return: The enclosed surface
    :rtype: Surface
    :raises ValueError: If the length of *curves* is not two or four
    """
    if len(curves) == 1: # probably gives input as a list-like single variable
        curves = curves[0]
    if len(curves) == 2:
        crv1 = curves[0].clone()
        crv2 = curves[1].clone()
        Curve.make_splines_identical(crv1, crv2)
        (n, d) = crv1.controlpoints.shape  # d = dimension + rational

        controlpoints = np.zeros((2 * n, d))
        controlpoints[:n, :] = crv1.controlpoints
        controlpoints[n:, :] = crv2.controlpoints
        linear = BSplineBasis(2)

        return Surface(crv1.bases[0], linear, controlpoints, crv1.rational)
    elif len(curves) == 4:
        # coons patch (https://en.wikipedia.org/wiki/Coons_patch)
        bottom = curves[0]
        right  = curves[1]
        top    = curves[2].clone()
        left   = curves[3].clone()  # gonna change these two, so make copies
        top.reverse()
        left.reverse()
        # create linear interpolation between opposing sides
        s1 = edge_curves(bottom, top)
        s2 = edge_curves(left, right)
        s2.swap()
        # create (linear,linear) corner parametrization
        linear = BSplineBasis(2)
        rat = s1.rational  # using control-points from top/bottom, so need to know if these are rational
        s3 = Surface(linear, linear, [bottom[0], bottom[-1], top[0], top[-1]], rat)

        # in order to add spline surfaces, they need identical parametrization
        Surface.make_splines_identical(s1, s2)
        Surface.make_splines_identical(s1, s3)
        Surface.make_splines_identical(s2, s3)

        result = s1
        result.controlpoints += s2.controlpoints
        result.controlpoints -= s3.controlpoints
        return result
    else:
        raise ValueError('Requires two or four input curves')
Example #35
0
def extrude(curve, amount):
    """  Extrude a curve by sweeping it to a given height.

    :param Curve curve: Curve to extrude
    :param array-like amount: 3-component vector of sweeping amount and
                               direction
    :return: The extruded curve
    :rtype: Surface
    """
    curve = curve.clone()  # clone input curve, throw away input reference
    curve.set_dimension(3)  # add z-components (if not already present)
    n = len(curve)  # number of control points of the curve
    cp = np.zeros((2 * n, curve.dimension + curve.rational))
    cp[:n, :] = curve.controlpoints  # the first control points form the bottom
    curve += amount
    cp[n:, :] = curve.controlpoints  # the last control points form the top
    return Surface(curve.bases[0], BSplineBasis(2), cp, curve.rational)
Example #36
0
    def plane(self):
        dim        = int(     self.read_next_non_whitespace().strip())
        center     = np.array(next(self.fstream).split(), dtype=float)
        normal     = np.array(next(self.fstream).split(), dtype=float)
        x_axis     = np.array(next(self.fstream).split(), dtype=float)
        finite     =          next(self.fstream).strip() != '0'
        if finite:
            param_u= np.array(next(self.fstream).split(), dtype=float)
            param_v= np.array(next(self.fstream).split(), dtype=float)
        else:
            param_u= [-state.unlimited, +state.unlimited]
            param_v= [-state.unlimited, +state.unlimited]
        swap       =          next(self.fstream).strip() != '0'

        result = Surface() * [param_u[1]-param_u[0], param_v[1]-param_v[0]] + [param_u[0],param_v[0]]
        result.rotate(rotate_local_x_axis(x_axis, normal))
        result = flip_and_move_plane_geometry(result,center,normal)
        result.reparam(param_u, param_v)
        if(swap):
            result.swap()
        return result
Example #37
0
 def test_multiplicity(self):
     surf = Surface()
     surf.refine(1)
     surf.raise_order(1)
     surf.refine(1)
     self.assertTrue(np.allclose(multiplicities(surf), [[3, 1, 2, 1, 3], [3, 1, 2, 1, 3]]))
Example #38
0
def edge_surfaces(*surfaces):
    """  Create the volume defined by the region between the input surfaces.

    In case of six input surfaces, these must be given in the order: bottom,
    top, left, right, back, front. Opposing sides must be parametrized in the
    same directions.

    :param [Surface] surfaces: Two or six edge surfaces
    :return: The enclosed volume
    :rtype: Volume
    :raises ValueError: If the length of *surfaces* is not two or six
    """
    if len(surfaces) == 1: # probably gives input as a list-like single variable
        surfaces = surfaces[0]
    if len(surfaces) == 2:
        surf1 = surfaces[0].clone()
        surf2 = surfaces[1].clone()
        Surface.make_splines_identical(surf1, surf2)
        (n1, n2, d) = surf1.controlpoints.shape  # d = dimension + rational

        controlpoints = np.zeros((n1, n2, 2, d))
        controlpoints[:, :, 0, :] = surf1.controlpoints
        controlpoints[:, :, 1, :] = surf2.controlpoints

        # Volume constructor orders control points in a different way, so we
        # create it from scratch here
        result = Volume(surf1.bases[0], surf1.bases[1], BSplineBasis(2), controlpoints,
                         rational=surf1.rational, raw=True)

        return result
    elif len(surfaces) == 6:
        if any([surf.rational for surf in surfaces]):
            raise RuntimeError('edge_surfaces not supported for rational splines')

        # coons patch (https://en.wikipedia.org/wiki/Coons_patch)
        umin = surfaces[0]
        umax = surfaces[1]
        vmin = surfaces[2]
        vmax = surfaces[3]
        wmin = surfaces[4]
        wmax = surfaces[5]
        vol1 = edge_surfaces(umin,umax)
        vol2 = edge_surfaces(vmin,vmax)
        vol3 = edge_surfaces(wmin,wmax)
        vol4 = Volume(controlpoints=vol1.corners(order='F'), rational=vol1.rational)
        vol1.swap(0, 2)
        vol1.swap(1, 2)
        vol2.swap(1, 2)
        vol4.swap(1, 2)
        Volume.make_splines_identical(vol1, vol2)
        Volume.make_splines_identical(vol1, vol3)
        Volume.make_splines_identical(vol1, vol4)
        Volume.make_splines_identical(vol2, vol3)
        Volume.make_splines_identical(vol2, vol4)
        Volume.make_splines_identical(vol3, vol4)
        result                =   vol1.clone()
        result.controlpoints +=   vol2.controlpoints
        result.controlpoints +=   vol3.controlpoints
        result.controlpoints -= 2*vol4.controlpoints
        return result
    else:
        raise ValueError('Requires two or six input surfaces')
Example #39
0
def loft(*surfaces):
    if len(surfaces) == 1:
        surfaces = surfaces[0]

    # clone input, so we don't change those references
    # 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)
    elif len(surfaces)==3:
        # can't do cubic spline interpolation, so we'll do quadratic
        basis3 = BSplineBasis(3)
        dist  = basis3.greville()
    else:
        x = [s.center() for s in surfaces]

        # create knot vector from the euclidian length between the surfaces
        dist = [0]
        for (x1,x0) in zip(x[1:],x[:-1]):
            dist.append(dist[-1] + np.linalg.norm(x1-x0))

        # using "free" boundary condition by setting N'''(u) continuous at second to last and second knot
        knot = [dist[0]]*4 + dist[2:-2] + [dist[-1]]*4
        basis3 = BSplineBasis(4, knot)

    n = len(surfaces)
    for i in range(n):
        for j in range(i+1,n):
            Surface.make_splines_identical(surfaces[i], surfaces[j])

    basis1 = surfaces[0].bases[0]
    basis2 = surfaces[0].bases[1]
    m1     = basis1.num_functions()
    m2     = basis2.num_functions()
    dim    = len(surfaces[0][0])
    u      = basis1.greville() # parametric interpolation points
    v      = basis2.greville()
    w      = dist

    # compute matrices
    Nu     = basis1(u)
    Nv     = basis2(v)
    Nw     = basis3(w)
    Nu_inv = np.linalg.inv(Nu)
    Nv_inv = np.linalg.inv(Nv)
    Nw_inv = np.linalg.inv(Nw)

    # compute interpolation points in physical space
    x      = np.zeros((m1,m2,n, dim))
    for i in range(n):
        tmp        = np.tensordot(Nv, surfaces[i].controlpoints, axes=(1,1))
        x[:,:,i,:] = np.tensordot(Nu, tmp                      , axes=(1,1))

    # solve interpolation problem
    cp = np.tensordot(Nw_inv, x,  axes=(1,2))
    cp = np.tensordot(Nv_inv, cp, axes=(1,2))
    cp = np.tensordot(Nu_inv, cp, axes=(1,2))

    # re-order controlpoints so they match up with Surface constructor
    cp = np.reshape(cp.transpose((2, 1, 0, 3)), (m1*m2*n, dim))

    return Volume(basis1, basis2, basis3, cp, surfaces[0].rational)
Example #40
0
def sphere(r=1, center=(0,0,0), type='radial'):
    """  Create a solid sphere

    :param float r: Radius
    :param array-like center: Local origin of the sphere
    :param string type: The type of parametrization ('radial' or 'square')
    :return: A solid ball
    :rtype: Volume
    """
    if type == 'radial':
        shell    = SurfaceFactory.sphere(r, center)
        midpoint = shell*0 + center
        return edge_surfaces(shell, midpoint)
    elif type == 'square':
        # based on the work of James E.Cobb: "Tiling the Sphere with Rational Bezier Patches"
        # University of Utah, July 11, 1988. UUCS-88-009
        b = BSplineBasis(order=5)
        sr2 = sqrt(2)
        sr3 = sqrt(3)
        sr6 = sqrt(6)
        cp = [[      -4*(sr3-1),       4*(1-sr3),      4*(1-sr3),   4*(3-sr3)  ], # row 0
              [           -sr2 ,     sr2*(sr3-4),    sr2*(sr3-4), sr2*(3*sr3-2)],
              [              0 ,  4./3*(1-2*sr3), 4./3*(1-2*sr3),4./3*(5-sr3)  ],
              [            sr2 ,     sr2*(sr3-4),    sr2*(sr3-4), sr2*(3*sr3-2)],
              [       4*(sr3-1),       4*(1-sr3),      4*(1-sr3),   4*(3-sr3)  ],
              [    -sr2*(4-sr3),            -sr2,    sr2*(sr3-4), sr2*(3*sr3-2)], # row 1
              [    -(3*sr3-2)/2,     (2-3*sr3)/2,     -(sr3+6)/2,     (sr3+6)/2],
              [              0 , sr2*(2*sr3-7)/3,       -5*sr6/3, sr2*(sr3+6)/3],
              [     (3*sr3-2)/2,     (2-3*sr3)/2,     -(sr3+6)/2,     (sr3+6)/2],
              [     sr2*(4-sr3),            -sr2,    sr2*(sr3-4), sr2*(3*sr3-2)],
              [ -4./3*(2*sr3-1),               0, 4./3*(1-2*sr3),   4*(5-sr3)/3], # row 2
              [-sr2/3*(7-2*sr3),               0,       -5*sr6/3, sr2*(sr3+6)/3],
              [              0 ,               0,    4*(sr3-5)/3, 4*(5*sr3-1)/9],
              [ sr2/3*(7-2*sr3),               0,       -5*sr6/3, sr2*(sr3+6)/3],
              [  4./3*(2*sr3-1),               0, 4./3*(1-2*sr3),   4*(5-sr3)/3],
              [    -sr2*(4-sr3),             sr2,    sr2*(sr3-4), sr2*(3*sr3-2)], # row 3
              [    -(3*sr3-2)/2,    -(2-3*sr3)/2,     -(sr3+6)/2,     (sr3+6)/2],
              [              0 ,-sr2*(2*sr3-7)/3,       -5*sr6/3, sr2*(sr3+6)/3],
              [     (3*sr3-2)/2,    -(2-3*sr3)/2,     -(sr3+6)/2,     (sr3+6)/2],
              [     sr2*(4-sr3),             sr2,    sr2*(sr3-4), sr2*(3*sr3-2)],
              [      -4*(sr3-1),      -4*(1-sr3),      4*(1-sr3),   4*(3-sr3)  ], # row 4
              [           -sr2 ,    -sr2*(sr3-4),    sr2*(sr3-4), sr2*(3*sr3-2)],
              [              0 , -4./3*(1-2*sr3), 4./3*(1-2*sr3),4./3*(5-sr3)  ],
              [            sr2 ,    -sr2*(sr3-4),    sr2*(sr3-4), sr2*(3*sr3-2)],
              [       4*(sr3-1),      -4*(1-sr3),      4*(1-sr3),   4*(3-sr3)  ]]
        wmin = Surface(b,b,cp, rational=True)
        wmax = wmin.clone().mirror([0,0,1])
        vmax = wmin.clone().rotate(pi/2, [1,0,0])
        vmin = vmax.clone().mirror([0,1,0])
        umax = vmin.clone().rotate(pi/2, [0,0,1])
        umin = umax.clone().mirror([1,0,0])
        # ideally I would like to call edge_surfaces() now, but that function
        # does not work with rational surfaces, so we'll just manually try
        # and add some inner controlpoints
        cp   = np.zeros((5,5,5,4))
        cp[ :, :, 0,:] = wmin[:,:,:]
        cp[ :, :,-1,:] = wmax[:,:,:]
        cp[ :, 0, :,:] = vmin[:,:,:]
        cp[ :,-1, :,:] = vmax[:,:,:]
        cp[ 0, :, :,:] = umin[:,:,:]
        cp[-1, :, :,:] = umax[:,:,:]
        inner = np.linspace(-.5,.5, 3)
        Y, X, Z = np.meshgrid(inner,inner,inner)
        cp[1:4,1:4,1:4,0] = X
        cp[1:4,1:4,1:4,1] = Y
        cp[1:4,1:4,1:4,2] = Z
        cp[1:4,1:4,1:4,3] = 1
        ball = Volume(b,b,b,cp,rational=True, raw=True)
        return r*ball + center
    else:
        raise ValueError('invalid type argument')