예제 #1
0
    def test_rational_derivative(self):
        # testing the parametrization x(u,v) = [.5*u^3*(1-v)^3 / ((1-v)^3*(1-u)^3 + .5*u^3*(1-v)^3), 0]
        # dx/du   =  (6*u^2*(u - 1)^2)/(u^3 - 6*u^2 + 6*u - 2)^2
        # d2x/du2 =  -(12*u*(u^5 - 3*u^4 + 2*u^3 + 4*u^2 - 6*u + 2))/(u^3 - 6*u^2 + 6*u - 2)^3
        # d3x/du3 =  (12*(3*u^8 - 12*u^7 + 10*u^6 + 48*u^5 - 156*u^4 + 176*u^3 - 72*u^2 + 4))/(u^3 - 6*u^2 + 6*u - 2)^4
        # dx/dv   =  0
        controlpoints = [[0, 0, 1], [0, 0, 0], [0, 0, 0], [.5, 0, .5],
                         [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
                         [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
                         [0, 0, 0], [0, 0, 0]]
        basis = BSplineBasis(4)
        surf = Surface(basis, basis, controlpoints, rational=True)

        def expect_derivative(u, v):
            return (6 * u**2 * (u - 1)**2) / (u**3 - 6 * u**2 + 6 * u - 2)**2

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

        def expect_derivative_3(u, v):
            return (12 * (3 * u**8 - 12 * u**7 + 10 * u**6 + 48 * u**5 -
                          156 * u**4 + 176 * u**3 - 72 * u**2 + 4)) / (
                              u**3 - 6 * u**2 + 6 * u - 2)**4

        # insert a few more knots to spice things up
        surf.insert_knot([.3, .51], 0)
        surf.insert_knot([.41, .53, .92], 1)

        # test first derivatives
        self.assertAlmostEqual(
            surf.derivative(0.32, 0.22, d=(1, 0))[0],
            expect_derivative(0.32, 0.22))
        self.assertAlmostEqual(surf.derivative(0.32, 0.22, d=(1, 0))[1], 0)
        self.assertAlmostEqual(
            surf.derivative(0.71, 0.22, d=(1, 0))[0],
            expect_derivative(0.71, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.71, 0.62, d=(1, 0))[0],
            expect_derivative(0.71, 0.62))

        # test second derivatives
        self.assertAlmostEqual(
            surf.derivative(0.32, 0.22, d=(2, 0))[0],
            expect_derivative_2(0.32, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.71, 0.22, d=(2, 0))[0],
            expect_derivative_2(0.71, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.71, 0.62, d=(2, 0))[0],
            expect_derivative_2(0.71, 0.62))

        # all cross derivatives vanish in this particular example
        self.assertAlmostEqual(surf.derivative(0.32, 0.22, d=(1, 1))[0], 0)
        self.assertAlmostEqual(surf.derivative(0.32, 0.22, d=(2, 1))[0], 0)
        self.assertAlmostEqual(surf.derivative(0.32, 0.22, d=(1, 2))[0], 0)

        # test third derivatives
        self.assertAlmostEqual(
            surf.derivative(0.32, 0.22, d=(3, 0))[0],
            expect_derivative_3(0.32, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.71, 0.22, d=(3, 0))[0],
            expect_derivative_3(0.71, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.71, 0.62, d=(3, 0))[0],
            expect_derivative_3(0.71, 0.62))

        # swapping u for v and symmetric logic
        surf.swap()
        self.assertAlmostEqual(
            surf.derivative(0.22, 0.32, d=(0, 2))[0],
            expect_derivative_2(0.32, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.22, 0.71, d=(0, 2))[0],
            expect_derivative_2(0.71, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.62, 0.71, d=(0, 2))[0],
            expect_derivative_2(0.71, 0.62))
        self.assertAlmostEqual(
            surf.derivative(0.22, 0.32, d=(0, 3))[0],
            expect_derivative_3(0.32, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.22, 0.71, d=(0, 3))[0],
            expect_derivative_3(0.71, 0.22))
        self.assertAlmostEqual(
            surf.derivative(0.62, 0.71, d=(0, 3))[0],
            expect_derivative_3(0.71, 0.62))
예제 #2
0
    def test_derivative(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.derivative([0, .2, .5, .6, 1], [0, .2, .4, 1], d=(1, 0))
        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)

        self.assertAlmostEqual(surf.derivative(.2, .2, d=(1, 0))[0],
                               .88)  # dx/du=2uv+(1-v)
        self.assertAlmostEqual(surf.derivative(.2, .2, d=(1, 0))[1],
                               0)  # dy/du=0
        self.assertAlmostEqual(surf.derivative(.2, .2, d=(0, 1))[0],
                               -.16)  # dx/dv=u^2-u
        self.assertAlmostEqual(surf.derivative(.2, .2, d=(0, 1))[1],
                               1)  # dy/dv=1
        self.assertAlmostEqual(surf.derivative(.2, .2, d=(1, 1))[0],
                               -.60)  # d2x/dudv=2u-1
        self.assertAlmostEqual(surf.derivative(.2, .2, d=(2, 0))[0],
                               0.40)  # d2x/dudu=2v
        self.assertAlmostEqual(surf.derivative(.2, .2, d=(3, 0))[0],
                               0.00)  # d3x/du3=0
        self.assertAlmostEqual(surf.derivative(.2, .2, d=(0, 2))[0],
                               0.00)  # d2y/dv2=0

        # test errors and exceptions
        with self.assertRaises(ValueError):
            val = surf.derivative(-10,
                                  .5)  # evalaute outside parametric domain
        with self.assertRaises(ValueError):
            val = surf.derivative(+10,
                                  .3)  # evalaute outside parametric domain
        with self.assertRaises(ValueError):
            val = surf.derivative(.5,
                                  -10)  # evalaute outside parametric domain
        with self.assertRaises(ValueError):
            val = surf.derivative(.5,
                                  +10)  # evalaute outside parametric domain