예제 #1
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_make_periodic(self):
        my_cps = np.array([[0, -1], [1, 0], [0, 1], [-1, 0], [0, -1]],
                          dtype=float)

        crv = Curve(BSplineBasis(2, [0, 0, 1, 2, 3, 4, 4]),
                    my_cps,
                    rational=False)
        crv = crv.make_periodic(0)
        cps = [[0, -1], [1, 0], [0, 1], [-1, 0]]
        self.assertAlmostEqual(np.linalg.norm(crv.controlpoints - cps), 0.0)

        crv = Curve(BSplineBasis(2, [0, 0, 1, 2, 3, 4, 4]),
                    my_cps,
                    rational=False)
        crv = crv.make_periodic(0)
        cps = [[0, -1], [1, 0], [0, 1], [-1, 0]]
        self.assertAlmostEqual(np.linalg.norm(crv.controlpoints - cps), 0.0)

        crv = Curve(BSplineBasis(3, [0, 0, 0, 1, 2, 3, 3, 3]),
                    my_cps,
                    rational=False)
        crv = crv.make_periodic(0)
        cps = [[0, -1], [1, 0], [0, 1], [-1, 0]]
        self.assertAlmostEqual(np.linalg.norm(crv.controlpoints - cps), 0.0)

        crv = Curve(BSplineBasis(3, [0, 0, 0, 1, 2, 3, 3, 3]),
                    my_cps,
                    rational=False)
        crv = crv.make_periodic(1)
        cps = [[-1, 0], [1, 0], [0, 1]]
        self.assertAlmostEqual(np.linalg.norm(crv.controlpoints - cps), 0.0)
예제 #2
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
예제 #3
0
    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)
        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.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')

        # check right dimensions of output
        self.assertEqual(surf.shape[0], 11) # 11 controlpoints in the circle segment
        self.assertEqual(surf.shape[1], 13) # 11 controlpoints in c4, +2 for C0-knot in c1
        self.assertEqual(surf.order(0), 3)
        self.assertEqual(surf.order(1), 4)

        # check that c1 edge conforms to surface edge
        u = np.linspace(0,1,7)
        c1.reparam()
        pts_surf = surf(u,0.0)
        pts_c1   = c1(u)
        for (xs,xc) in zip(pts_surf[:,0,:], pts_c1):
            self.assertTrue(np.allclose(xs, xc))

        # check that c2 edge conforms to surface edge
        v = np.linspace(0,1,7)
        c2.reparam()
        pts_surf = surf(1.0,v)
        pts_c2   = c2(v)
        for (xs,xc) in zip(pts_surf[:,0,:], pts_c2):
            self.assertTrue(np.allclose(xs, xc))
예제 #4
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)
예제 #5
0
def circle_segment(theta,
                   r=1,
                   center=(0, 0, 0),
                   normal=(0, 0, 1),
                   xaxis=(1, 0, 0)):
    """  Create a circle segment starting parallel to the rotated x-axis.

    :param float theta: Angle in radians
    :param float r: Radius
    :param array-like center: circle segment center
    :param array-like normal: normal vector to the plane that contains circle
    :param array-like xaxis: direction of the parametric start point t=0
    :return: A quadratic rational curve
    :rtype: Curve
    :raises ValueError: If radius is not positive
    :raises ValueError: If theta is not in the range *[-2pi, 2pi]*
    """
    # error test input
    if abs(theta) > 2 * pi:
        raise ValueError('theta needs to be in range [-2pi,2pi]')
    if r <= 0:
        raise ValueError('radius needs to be positive')
    if theta == 2 * pi:
        return circle(r, center, normal)

    # build knot vector
    knot_spans = int(ceil(abs(theta) / (2 * pi / 3)))
    knot = [0]
    for i in range(knot_spans + 1):
        knot += [i] * 2
    knot += [knot_spans]  # knot vector [0,0,0,1,1,2,2,..,n,n,n]
    knot = np.array(knot) / float(
        knot[-1]) * theta  # set parametric space to [0,theta]

    n = (knot_spans - 1) * 2 + 3  # number of control points needed
    cp = []
    t = 0  # current angle
    dt = float(theta) / knot_spans / 2  # angle step

    # build control points
    for i in range(n):
        w = 1 - (i % 2) * (1 - cos(dt)
                           )  # weights = 1 and cos(dt) every other i
        x = r * cos(t)
        y = r * sin(t)
        cp += [[x, y, w]]
        t += dt

    if theta < 0:
        cp.reverse()
        result = Curve(BSplineBasis(3, np.flip(knot, 0)), cp, True)
    else:
        result = Curve(BSplineBasis(3, knot), cp, True)
    result.rotate(rotate_local_x_axis(xaxis, normal))
    return flip_and_move_plane_geometry(result, center, normal)
예제 #6
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_constructor(self):
        # test 3D constructor
        crv = Curve(controlpoints=[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]])
        val = crv(0.5)
        self.assertEqual(val[0], 0.5)
        self.assertEqual(crv.dimension, 3)

        # test 2D constructor
        crv2 = Curve()
        val = crv(0.5)
        self.assertEqual(val[0], 0.5)
        self.assertEqual(crv2.dimension, 2)
예제 #7
0
def circle(r=1, center=(0,0,0), normal=(0,0,1), type='p2C0', xaxis=(1,0,0)):
    """  Create a circle.

    :param float r: Radius
    :param array-like center: local origin
    :param array-like normal: local normal
    :param string type: The type of parametrization ('p2C0' or 'p4C1')
    :param array-like xaxis: direction of sem, i.e. parametric start point t=0
    :return: A periodic, quadratic rational curve
    :rtype: Curve
    :raises ValueError: If radius is not positive
    """
    if r <= 0:
        raise ValueError('radius needs to be positive')

    if type == 'p2C0' or type == 'C0p2':
        w = 1.0 / sqrt(2)
        controlpoints = [[1, 0, 1],
                         [w, w, w],
                         [0, 1, 1],
                         [-w, w, w],
                         [-1, 0, 1],
                         [-w, -w, w],
                         [0, -1, 1],
                         [w, -w, w]]
        knot = np.array([-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5]) / 4.0 * 2 * pi

        result = Curve(BSplineBasis(3, knot, 0), controlpoints, True)
    elif type.lower() == 'p4c1' or type.lower() == 'c1p4':
        w = 2*sqrt(2)/3
        a = 1.0/2/sqrt(2)
        b = 1.0/6 * (4*sqrt(2)-1)
        controlpoints = [[ 1,-a, 1],
                         [ 1, a, 1],
                         [ b, b, w],
                         [ a, 1, 1],
                         [-a, 1, 1],
                         [-b, b, w],
                         [-1, a, 1],
                         [-1,-a, 1],
                         [-b,-b, w],
                         [-a,-1, 1],
                         [ a,-1, 1],
                         [ b,-b, w]]
        knot = np.array([ -1, -1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5]) / 4.0 * 2 * pi
        result = Curve(BSplineBasis(5, knot, 1), controlpoints, True)
    else:
        raise ValueError('Unkown type: %s' %(type))

    result *= r
    result.rotate(rotate_local_x_axis(xaxis, normal))
    return flip_and_move_plane_geometry(result, center, normal)
예제 #8
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_raise_order(self):
        # non-uniform knot vector of a squiggly quadratic n=5 curve in 3D
        controlpoints = [[0, 0, 0], [1, 1, 1], [2, -1, 0], [3, 0, -1],
                         [0, 0, -5]]
        crv = Curve(BSplineBasis(3, [0, 0, 0, .3, .4, 1, 1, 1]), controlpoints)

        evaluation_point1 = crv(0.37)
        crv.raise_order(2)
        evaluation_point2 = crv(0.37)

        # ensure that curve 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 curve has the right order
        self.assertEqual(crv.order(0), 5)

        # check integer type for argument
        with self.assertRaises(TypeError):
            crv.raise_order(0.5)

        # check logic error for negative argument
        with self.assertRaises(Exception):
            crv.raise_order(-1)
예제 #9
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]
예제 #10
0
파일: curve_test.py 프로젝트: yukoba/Splipy
    def test_derivative(self):
        # testing the parametrization x(t) = [.5*x^3 / ((1-x)^3+.5*x^3), 0]
        cp = [[0, 0, 1], [0, 0, 0], [0, 0, 0], [.5, 0, .5]]
        crv = Curve(BSplineBasis(4), cp, rational=True)

        def expect_derivative(x):
            return 6 * (1 - x)**2 * x**2 / (x**3 - 6 * x**2 + 6 * x - 2)**2

        def expect_derivative_2(x):
            return -12 * x * (x**5 - 3 * x**4 + 2 * x**3 + 4 * x**2 - 6 * x +
                              2) / (x**3 - 6 * x**2 + 6 * x - 2)**3

        # insert a few more knots to spice things up
        crv.insert_knot([.2, .71])

        self.assertAlmostEqual(
            crv.derivative(0.32, 1)[0], expect_derivative(0.32))
        self.assertAlmostEqual(crv.derivative(0.32, 1)[1], 0)
        self.assertAlmostEqual(
            crv.derivative(0.71, 1)[0], expect_derivative(0.71))

        self.assertAlmostEqual(
            crv.derivative(0.22, 2)[0], expect_derivative_2(0.22))
        self.assertAlmostEqual(crv.derivative(0.22, 2)[1], 0)
        self.assertAlmostEqual(
            crv.derivative(0.86, 2)[0], expect_derivative_2(0.86))
예제 #11
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_periodic_split(self):
        # non-uniform rational knot vector of a periodic cubic n=7 curve
        controlpoints = [[1, 0, 1], [1, 1, .7], [0, 1, .89], [-1, 1, 0.5],
                         [-1, 0, 1], [-1, -.5, 1], [1, -.5, 1]]
        basis = BSplineBasis(4,
                             [-3, -2, -1, 0, 1, 2, 2.5, 4, 5, 6, 7, 8, 9, 9.5],
                             2)
        crv = Curve(basis, controlpoints, rational=True)
        crv2 = crv.split(1)  # split at knot value
        crv3 = crv.split(6.5)  # split outside existing knot

        self.assertEqual(len(crv), 7)
        self.assertEqual(len(crv2), 10)
        self.assertEqual(len(crv3), 11)

        self.assertEqual(crv.periodic(), True)
        self.assertEqual(crv2.periodic(), False)
        self.assertEqual(crv3.periodic(), False)

        t = np.linspace(6.5, 8,
                        13)  # domain where all parameter values are the same
        pt = crv(t)
        pt2 = crv2(t)
        pt3 = crv3(t)

        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)
        self.assertAlmostEqual(np.linalg.norm(pt - pt3), 0.0)
예제 #12
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_torsion(self):
        # planar curves have zero torsion
        controlpoints = [[1, 0, 1], [1, 1, .7], [0, 1, .89], [-1, 1, 0.5],
                         [-1, 0, 1], [-1, -.5, 1], [1, -.5, 1]]
        basis = BSplineBasis(4,
                             [-3, -2, -1, 0, 1, 2, 2.5, 4, 5, 6, 7, 8, 9, 9.5],
                             2)
        crv = Curve(basis, controlpoints, rational=True)
        self.assertAlmostEqual(crv.torsion(.3), 0.0)

        # test multiple evaluation points
        t = np.linspace(0, 1, 10)
        k = crv.torsion(t)
        self.assertEqual(len(k.shape), 1)  # is vector
        self.assertEqual(k.shape[0], 10)  # length 10 vector
        self.assertTrue(np.allclose(k, 0.0))  # zero torsion for planar curves

        # test helix: [a*cos(t), a*sin(t), b*t]
        t = np.linspace(0, 6 * pi, 300)
        a = 3.0
        b = 2.0
        x = np.array([a * np.cos(t), a * np.sin(t), b * t])
        crv = cf.cubic_curve(x.T, t=t)
        t = np.linspace(0, 6 * pi, 10)
        k = crv.torsion(t)

        # this is a helix approximation, hence atol=1e-3
        self.assertTrue(np.allclose(k, b / (a**2 + b**2),
                                    atol=1e-3))  # helix have const. torsion
예제 #13
0
파일: Surface.py 프로젝트: luzpaz/Splipy
    def const_par_curve(self, knot, direction):
        """  Get a Curve representation of the parametric line of some constant
        knot value.
        :param float knot: The constant knot value to sample the surface
        :param int direction: The parametric direction for the constant value
        :return: curve on this surface
        :rtype: Curve
        """
        direction = check_direction(direction, 2)

        # clone basis since we need to augment this by knot insertion
        b = self.bases[direction].clone()

        # compute mapping matrix C which is the knotinsertion operator
        mult = min(b.continuity(knot), b.order - 1)
        C = np.identity(self.shape[direction])
        for i in range(mult):
            C = b.insert_knot(knot) @ C

        # at this point we have a C0 basis, find the right interpolating index
        i = max(bisect_left(b.knots, knot) - 1, 0)

        # compute the controlpoints and return Curve
        cp = np.tensordot(C[i, :], self.controlpoints, axes=(0, direction))
        return Curve(self.bases[1 - direction], cp, self.rational)
예제 #14
0
def bezier(pts, quadratic=False, relative=False):
    """  Generate a cubic or quadratic bezier curve from a set of control points

    :param [array-like] pts: list of control-points. In addition to a starting
        point we need three points per bezier interval for cubic splines and
        two points for quadratic splines
    :param bool quadratic: True if a quadratic spline is to be returned, False
        if a cubic spline is to be returned
    :param bool relative: If controlpoints are interpreted as relative to the
        previous one
    :return: Bezier curve
    :rtype: Curve

    """
    if quadratic:
        p = 3
    else:
        p = 4
    # compute number of intervals
    n = int((len(pts)-1)/(p-1))
    # generate uniform knot vector of repeated integers
    knot = list(range(n+1)) * (p-1) + [0, n]
    knot.sort()
    if relative:
        pts = copy.deepcopy(pts)
        for i in range(1, len(pts)):
            pts[i] = [x0 + x1 for (x0,x1) in zip(pts[i-1], pts[i])]
    return Curve(BSplineBasis(p, knot), pts)
예제 #15
0
def polygon(*points, **keywords):
    """  Create a linear interpolation between input points.

    :param [array-like] points: The points to interpolate
    :param bool relative: If controlpoints are interpreted as relative to the
        previous one
    :param [float] t: specify parametric interpolation points (the knot vector)
    :return: Linear curve through the input points
    :rtype: Curve
    """
    if len(points) == 1:
        points = points[0]

    knot = keywords.get('t', [])
    if len(knot) == 0: # establish knot vector based on eucledian length between points
        knot = [0, 0]
        prevPt = points[0]
        for pt in points[1:]:
            dist = 0
            for (x0, x1) in zip(prevPt, pt):  # loop over (x,y) and maybe z-coordinate
                dist += (x1 - x0)**2
            knot.append(knot[-1] + sqrt(dist))
            prevPt = pt
        knot.append(knot[-1])
    else: # use knot vector given as input argument
        knot = [knot[0]] + list(knot) + [knot[-1]]

    relative = keywords.get('relative', False)
    if relative:
        points = list(points)
        for i in range(1, len(points)):
            points[i] = [x0 + x1 for (x0,x1) in zip(points[i-1], points[i])]

    return Curve(BSplineBasis(2, knot), points)
예제 #16
0
def n_gon(n=5, r=1, center=(0,0,0), normal=(0,0,1)):
    """  Create a regular polygon of *n* equal sides centered at the origin.

    :param int n: Number of sides and vertices
    :param float r: Radius
    :param array-like center: local origin
    :param array-like normal: local normal
    :return: A linear, periodic, 2D curve
    :rtype: Curve
    :raises ValueError: If radius is not positive
    :raises ValueError: If *n* < 3
    """
    if r <= 0:
        raise ValueError('radius needs to be positive')
    if n < 3:
        raise ValueError('regular polygons need at least 3 sides')

    cp = []
    dt = 2 * pi / n
    knot = [-1]
    for i in range(n):
        cp.append([r * cos(i * dt), r * sin(i * dt)])
        knot.append(i)
    knot += [n, n+1]
    basis = BSplineBasis(2, knot, 0)

    result =  Curve(basis, cp)
    return flip_and_move_plane_geometry(result, center, normal)
예제 #17
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
예제 #18
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_center(self):
        # create the geometric mapping x(t) = t, y(t) = t^3,  t=[0,1]
        cp = [[0, 0], [1.0 / 3, 0], [2.0 / 3, 0], [1.0, 1]]
        basis = BSplineBasis(4)
        crv = Curve(basis, cp)
        center = crv.center()

        self.assertAlmostEqual(center[0], .5)
        self.assertAlmostEqual(center[1], .25)
예제 #19
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)
예제 #20
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_flip_parametrization(self):
        # non-uniform knot vector of a squiggly quadratic n=4 curve
        controlpoints = [[0, 0, 0], [1, 1, 0], [2, -1, 0], [3, 0, 0]]
        crv = Curve(BSplineBasis(3, [0, 0, 0, .3, 1, 1, 1]), controlpoints)

        p1 = crv(0.23)
        crv.reverse()
        p2 = crv(0.77)
        self.assertAlmostEqual(p1[0], p2[0])
        self.assertAlmostEqual(p1[1], p2[1])
        self.assertAlmostEqual(p1[2], p2[2])
예제 #21
0
    def test_thicken(self):
        c = Curve()  # 2D curve from (0,0) to (1,0)
        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))
        self.assertTupleEqual(s.bounding_box()[0], (0.0, 1.0))
        self.assertTupleEqual(s.bounding_box()[1], (-.5, .5))

        # 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 = sf.thicken(c, .5)
        self.assertTupleEqual(s.order(), (3, 2))
        self.assertTupleEqual(s.start(), (0, 0))
        self.assertTupleEqual(s.end(), (1, 1))
        self.assertTupleEqual(s.bounding_box()[0], (0.0, 1.0))
        self.assertTupleEqual(s.bounding_box()[1], (-.5, .5))

        def myThickness(t):
            return t**2

        c = Curve(BSplineBasis(3))
        s = sf.thicken(c, myThickness)
        self.assertTupleEqual(s.order(), (3, 2))
        self.assertTupleEqual(s.start(), (0, 0))
        self.assertTupleEqual(s.end(), (1, 1))
        self.assertTupleEqual(s.bounding_box()[0], (0.0, 1.0))
        self.assertTupleEqual(s.bounding_box()[1], (-1.0, 1.0))

        # test 3D geometry
        c = Curve()
        c.set_dimension(3)
        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)
                self.assertAlmostEqual(x[1]**2 + x[2]**2,
                                       1.0**2)  # distance to x-axis
                self.assertAlmostEqual(x[0],
                                       u)  # x coordinate should be linear
예제 #22
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_make_periodic_reconstruct(self):
        orig = Curve(
            BSplineBasis(4, [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7], 2),
            [[1, 1], [2, 2], [3, 3], [4, 4]],
            rational=True,
        )
        recons = orig.split(0).make_periodic(2)

        self.assertAlmostEqual(
            np.linalg.norm(orig.controlpoints - recons.controlpoints), 0.0)
        self.assertAlmostEqual(
            np.linalg.norm(orig.bases[0].knots - recons.bases[0].knots), 0.0)
예제 #23
0
def line(a, b, relative=False):
    """  Create a line between two points.

    :param array-like a: Start point
    :param array-like b: End point
    :param bool relative: Whether *b* is relative to *a*
    :return: Linear curve from *a* to *b*
    :rtype: Curve
    """
    if relative:
        b = tuple(ai + bi for ai, bi in zip(a, b))
    return Curve(controlpoints=[a, b])
예제 #24
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_append(self):
        crv = Curve(BSplineBasis(3), [[0, 0], [1, 0], [0, 1]])
        crv2 = Curve(BSplineBasis(4),
                     [[0, 1, 0], [0, 1, 1], [0, 2, 1], [0, 2, 2]])
        crv2.insert_knot(0.5)

        crv3 = crv.clone()
        crv3.append(crv2)

        expected_knot = [0, 0, 0, 0, 1, 1, 1, 1.5, 2, 2, 2, 2]
        self.assertEqual(crv3.order(direction=0), 4)
        self.assertEqual(crv3.rational, False)
        self.assertAlmostEqual(
            np.linalg.norm(crv3.knots(0, True) - expected_knot), 0.0)

        t = np.linspace(0, 1, 11)
        pt = np.zeros((11, 3))
        pt[:, :-1] = crv(t)
        pt2 = crv3(t)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)
        pt = crv2(t)
        pt2 = crv3(t + 1.0)
        self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)
예제 #25
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_evaluate(self):
        # create the mapping
        # x(t) = 2t + 1
        # y(t) = 2t(1-t)
        # z(t) = 0
        controlpoints = [[1, 0, 0], [2, 1, 0], [3, 0, 0]]
        crv = Curve(BSplineBasis(3), controlpoints)

        # startpoint evaluation
        val = crv(0.0)
        self.assertAlmostEqual(val[0], 1.0)
        self.assertAlmostEqual(val[1], 0.0)
        self.assertAlmostEqual(val[2], 0.0)

        # inner evaluation
        val = crv(0.4)
        self.assertAlmostEqual(val[0], 1.8)
        self.assertAlmostEqual(val[1], 0.48)
        self.assertAlmostEqual(val[2], 0.0)

        # endpoint evaluation
        val = crv(1.0)
        self.assertAlmostEqual(val[0], 3.0)
        self.assertAlmostEqual(val[1], 0.0)
        self.assertAlmostEqual(val[2], 0.0)

        # test evaluation at multiple points
        val = crv([0.0, 0.4, 0.8, 1.0])
        self.assertEqual(len(val.shape), 2)  # return matrix
        self.assertEqual(val.shape[0], 4)  # 4 evaluation points
        self.assertEqual(val.shape[1], 3)  # (x,y,z) results
        self.assertAlmostEqual(val[0, 0], 1.0)
        self.assertAlmostEqual(val[0, 1], 0.0)
        self.assertAlmostEqual(val[0, 2], 0.0)  # startpt evaluation
        self.assertAlmostEqual(val[1, 0], 1.8)
        self.assertAlmostEqual(val[1, 1], 0.48)
        self.assertAlmostEqual(val[1, 2], 0.0)  # inner evaluation
        self.assertAlmostEqual(val[3, 0], 3.0)
        self.assertAlmostEqual(val[3, 1], 0.0)
        self.assertAlmostEqual(val[3, 2], 0.0)  # endpt evaluation

        # test errors and exceptions
        with self.assertRaises(ValueError):
            val = crv(-10)  # evalaute outside parametric domain
        with self.assertRaises(ValueError):
            val = crv(+10)  # evalaute outside parametric domain
예제 #26
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_reparam(self):
        # non-uniform knot vector of a squiggly quadratic n=4 curve
        controlpoints = [[0, 0, 0], [1, 1, 0], [2, -1, 0], [3, 0, 0]]
        crv = Curve(BSplineBasis(3, [0, 0, 0, 1.32, 3, 3, 3]), controlpoints)

        # get some info on the initial curve
        knots1 = crv.knots(0)
        evaluation_point1 = crv(1.20)
        self.assertEqual(knots1[0], 0)
        self.assertEqual(knots1[-1], 3)

        # reparametrize
        crv.reparam((6.0, 9.0))

        # get some info on the reparametrized curve
        knots2 = crv.knots(0)
        evaluation_point2 = crv(7.20)
        self.assertEqual(knots2[0], 6)
        self.assertEqual(knots2[-1], 9)

        # ensure that curve 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])

        # normalize, i.e. set domain to [0,1]
        crv.reparam()

        # get some info on the normalized curve
        knots3 = crv.knots(0)
        evaluation_point3 = crv(0.40)
        self.assertEqual(knots3[0], 0)
        self.assertEqual(knots3[-1], 1)

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

        # test errors and exceptions
        with self.assertRaises(ValueError):
            crv.reparam((9, 3))
        with self.assertRaises(TypeError):
            crv.reparam(("one", "two"))
예제 #27
0
def least_square_fit(x, basis, t):
    """  Perform a least-square fit of a point cloud onto a spline basis

    :param matrix-like x: Matrix *X[i,j]* of interpolation points *xi* with
        components *j*. The number of points must be equal to or larger than
        the number of basis functions in *basis*
    :param BSplineBasis basis: Basis on which to interpolate
    :param array-like t: parametric values at evaluation points
    :return: Approximated curve
    :rtype: Curve
    """

    # evaluate all basis functions at evaluation points
    N = basis.evaluate(t)

    # solve interpolation problem
    controlpoints, _, _, _ = np.linalg.lstsq(N, x, rcond=None)

    return Curve(basis, controlpoints)
예제 #28
0
파일: threedm.py 프로젝트: SINTEF/Splipy
    def read_curve(self, ncrv):
        knots = [0]
        for i in ncrv.Knots:
            knots.append(i)
        knots[0] = knots[1]
        knots.append(knots[len(knots) - 1])
        basis = BSplineBasis(ncrv.Order, knots, -1)
        cpts = []

        cpts = np.ndarray((len(ncrv.Points), ncrv.Dimension + ncrv.IsRational))
        for u in range(0, len(ncrv.Points)):
            cpts[u, 0] = ncrv.Points[u].X
            cpts[u, 1] = ncrv.Points[u].Y
            if ncrv.Dimension > 2:
                cpts[u, 2] = ncrv.Points[u].Z
            if ncrv.IsRational:
                cpts[u, 3] = ncrv.Points[u].W

        return Curve(basis, cpts, ncrv.IsRational)
예제 #29
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    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
예제 #30
0
파일: curve_test.py 프로젝트: SINTEF/Splipy
    def test_force_rational(self):
        # non-uniform knot vector of a squiggly quadratic n=4 curve
        controlpoints = [[0, 0, 0], [1, 1, 0], [2, -1, 0], [3, 0, 0]]
        crv = Curve(BSplineBasis(3, [0, 0, 0, .3, 1, 1, 1]), controlpoints)

        evaluation_point1 = crv(0.23)
        control_point1 = crv[0]
        crv.force_rational()
        evaluation_point2 = crv(0.23)
        control_point2 = crv[0]
        # ensure that curve 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(crv.rational, True)