Ejemplo n.º 1
0
def bilinear_surface(vtxs, overhang=0.0):
    """
    Returns B-spline surface of a bilinear surface given by 4 corner points:
    uv coords:
    We retun also list of UV coordinates of the given points.
    :param vtxs: List of tuples (X,Y,Z)
    :return: ( Surface, vtxs_uv )
    """
    assert len(vtxs) == 4, "n vtx: {}".format(len(vtxs))
    vtxs = np.array(vtxs)
    if overhang > 0.0:
        dv = np.roll(vtxs, -1, axis=0) - vtxs
        dv *= overhang
        vtxs += np.roll(dv, 1, axis=0) - dv

    def mid(*idx):
        return np.mean(vtxs[list(idx)], axis=0)

    # v - direction v0 -> v2
    # u - direction v0 -> v1
    poles = [[vtxs[0], mid(0, 3), vtxs[3]],
             [mid(0, 1), mid(0, 1, 2, 3),
              mid(2, 3)], [vtxs[1], mid(1, 2), vtxs[2]]]
    knots = 3 * [0.0 - overhang] + 3 * [1.0 + overhang]
    basis = bs.SplineBasis(2, knots)
    surface = bs.Surface((basis, basis), poles)
    #vtxs_uv = [ (0, 0), (1, 0), (1, 1), (0, 1) ]
    return surface
Ejemplo n.º 2
0
def test_bspline_io():
    def function(x):
        return np.sin(x[0] * 4) * np.cos(x[1] * 4)

    quad = np.array([[1., 3.5], [1., 2.], [2., 2.2], [2, 3.7]])
    poles = bs.make_function_grid(function, 4, 5)
    u_basis = bs.SplineBasis.make_equidistant(2, 2)
    v_basis = bs.SplineBasis.make_equidistant(2, 3)
    surface_func = bs.Surface((u_basis, v_basis), poles[:, :, [2]])
    surface = bs.Z_Surface(quad, surface_func)
    xy_map = [[0.1, 0.2, -2], [0.2, - 0.1, -1]]
    z_map = [2.0, 5.0]
    surface.transform(xy_map, z_map )

    surf_io = bspline_io.bs_zsurface_write(surface)
    surf_new = bspline_io.bs_zsurface_read(surf_io)

    assert np.allclose(xy_map, surf_new.get_transform()[0])
    assert np.allclose(z_map, surf_new.get_transform()[1])
    assert np.allclose( surface.center(), surf_new.center())

    surface.transform(xy_map)
    assert np.allclose(surface.center(), surf_new.center())

    xy_map = [[0.2, 0.3, -3], [0.3, - 0.2, -2]]
    z_map = [3, 6]
    surface.transform(xy_map)
    surf_new.transform(xy_map)
    assert np.allclose(surface.center(), surf_new.center())
Ejemplo n.º 3
0
def bs_zsurface_read(z_surface_io):
    io = z_surface_io
    u_basis = bs.SplineBasis(io.u_degree, io.u_knots)
    v_basis = bs.SplineBasis(io.v_degree, io.v_knots)

    z_surf = bs.Surface((u_basis, v_basis), io.poles, io.rational)
    surf = bs.Z_Surface(io.orig_quad, z_surf)
    surf.transform(io.xy_map, io.z_map)
    return surf
Ejemplo n.º 4
0
    def approx_chol(self):
        """
        This function tries to approximate terrain data with B-Spline surface patches
        using Cholesky decomposition
        :param terrain_data: matrix of 3D terrain data
        :param quad: points defining quadrangle area (array)
        :param u_knots: array of u knots
        :param v_knots: array of v knots
        :param sparse: if sparse matrix is used
        :param filter_thresh: threshold of filter
        :return: B-Spline patch
        """

        print('Transforming points to parametric space ...')
        start_time = time.time()
        points = self.grid_surf.points_xyz
        points_uv = self.grid_surf.xy_to_uv(points[:, 0:2])

        # remove points far from unit square
        eps = 1.0e-15
        cut_min = np.array([-eps, -eps])
        cut_max = np.array([1 + eps, 1 + eps])

        in_idx = np.all(np.logical_and(cut_min < points_uv,
                                       points_uv <= cut_max),
                        axis=1)
        points_uv = points_uv[in_idx]
        points_z = points[in_idx, 2][:, None]

        # snap to unit square
        points_uv = np.maximum(points_uv, np.array([0.0, 0.0]))
        points_uv = np.minimum(points_uv, np.array([1.0, 1.0]))

        self.grid_uvz = np.concatenate((points_uv, points_z), axis=1)
        end_time = time.time()
        print('Computed in {0} seconds.'.format(end_time - start_time))

        # Own computation of approximation
        print('Creating B matrix ...')
        start_time = time.time()
        b_mat, interval = self.build_ls_matrix()
        end_time = time.time()
        print('Computed in {0} seconds.'.format(end_time - start_time))

        print('Creating A matrix ...')
        start_time = time.time()
        a_mat = self.build_sparse_reg_matrix()
        end_time = time.time()
        print('Computed in {0} seconds.'.format(end_time - start_time))

        print('Computing B^T B matrix ...')
        start_time = time.time()
        bb_mat = b_mat.transpose() * b_mat

        end_time = time.time()
        print('Computed in {0} seconds.'.format(end_time - start_time))

        bb_norm = scipy.sparse.linalg.svds(bb_mat,
                                           k=1,
                                           ncv=10,
                                           tol=1e-4,
                                           which='LM',
                                           v0=None,
                                           maxiter=300,
                                           return_singular_vectors=False)
        a_norm = scipy.sparse.linalg.svds(a_mat,
                                          k=1,
                                          ncv=10,
                                          tol=1e-4,
                                          which='LM',
                                          v0=None,
                                          maxiter=300,
                                          return_singular_vectors=False)
        c_mat = bb_mat + self.regularization_weight * (bb_norm[0] /
                                                       a_norm[0]) * a_mat

        g_vec = self.grid_uvz[:, 2]
        b_vec = b_mat.transpose() * g_vec

        print('Computing Z coordinates ...')
        start_time = time.time()
        z_vec = scipy.sparse.linalg.spsolve(c_mat, b_vec)
        print(type(z_vec))
        end_time = time.time()
        print('Computed in {0} seconds.'.format(end_time - start_time))

        # print('Computing differences ...')
        # start_time = time.time()
        # diff = (numpy.matrix(b_mat * z_vec).transpose() - g_vec).tolist()
        # diff = [item[0] for item in diff]
        # end_time = time.time()
        # print('Computed in {0} seconds.'.format(end_time - start_time))

        # Construct Z-Surface
        poles_z = z_vec.reshape(self.u_basis.size, self.v_basis.size, 1)
        surface_z = bs.Surface((self.u_basis, self.v_basis), poles_z)
        z_surf = bs.Z_Surface(self.grid_surf.quad, surface_z)

        return z_surf
Ejemplo n.º 5
0
    def compute_approximation(self, **kwargs):
        """
        Compute approximation of the point set (given to constructor).
        Approximation parameters can be passed in through kwargs or set in the object before the call.
        :param quad: [(x1,y1), .. , (x4,y4)] Set vertices of different quad for the point set.
        :param nuv: (nu, nv) Set number of intervals of the resulting B-spline, in U and V direction
        :param regularization_wight: Default 0.001, is scaled by the max singular value of B.
        :return: B-Spline surface
        """

        self.quad = kwargs.get("quad", self.quad)
        self.nuv = kwargs.get("nuv", self.nuv)
        self.regularization_weight = kwargs.get("regularization_weight",
                                                self.regularization_weight)

        logging.info('Transforming points (n={}) ...'.format(self._n_points))
        start_time = time.time()
        if self.quad is None:
            self.compute_default_quad()
        if self.nuv is None:
            self.compute_default_nuv()

        # TODO: better logic, since this has to be recomputed only if quad is changed.
        self._compute_uv_points()

        logging.info("Using {} x {} B-spline approximation.".format(
            self.nuv[0], self.nuv[1]))
        self._u_basis = bs.SplineBasis.make_equidistant(2, self.nuv[0])
        self._v_basis = bs.SplineBasis.make_equidistant(2, self.nuv[1])

        end_time = time.time()
        logging.info('Computed in: {} s'.format(end_time - start_time))

        # Approximation itself
        logging.info('Creating B matrix ...')
        start_time = time.time()
        b_mat, interval = self._build_ls_matrix()
        end_time = time.time()
        logging.info('Computed in: {} s'.format(end_time - start_time))

        logging.info('Creating A matrix ...')
        start_time = time.time()
        a_mat = self._build_sparse_reg_matrix()
        end_time = time.time()
        logging.info('Computed in: {} s'.format(end_time - start_time))

        logging.info('Scaling + B^T B ...')
        start_time = time.time()
        g_vec = self._z_quad_points[:]
        if self._weights is not None:
            W = scipy.sparse.diags(self._w_quad_points, 0)
            wg_vec = np.dot(W, g_vec)
            wb_mat = np.dot(W, b_mat)
        else:
            wg_vec = g_vec
            wb_mat = b_mat
        b_vec = b_mat.transpose().dot(wg_vec)
        bb_mat = b_mat.transpose().dot(wb_mat)
        end_time = time.time()
        logging.info('Computed in: {} s'.format(end_time - start_time))

        logging.info('Computing A and B svds approximation ...')
        start_time = time.time()
        bb_norm = scipy.sparse.linalg.svds(bb_mat,
                                           k=1,
                                           ncv=10,
                                           tol=1e-2,
                                           which='LM',
                                           v0=None,
                                           maxiter=300,
                                           return_singular_vectors=False)
        a_norm = scipy.sparse.linalg.eigsh(a_mat,
                                           k=1,
                                           ncv=10,
                                           tol=1e-2,
                                           which='LM',
                                           maxiter=300,
                                           return_eigenvectors=False)
        c_mat = bb_mat + self.regularization_weight * (bb_norm[0] /
                                                       a_norm[0]) * a_mat
        end_time = time.time()
        logging.info('Computed in: {} s'.format(end_time - start_time))

        logging.info('Solving for Z coordinates ...')
        start_time = time.time()
        z_vec = scipy.sparse.linalg.spsolve(c_mat, b_vec)
        assert not np.isnan(
            np.sum(z_vec)), "Singular matrix for approximation."
        end_time = time.time()
        logging.info('Computed in: {} s'.format(end_time - start_time))

        logging.info('Computing error ...')
        start_time = time.time()
        self.diff = b_mat.dot(z_vec) - g_vec
        self.error = max_diff = np.max(np.abs(self.diff))
        logging.info("Approximation error (max norm): {}".format(max_diff))
        end_time = time.time()
        logging.info('Computed in: {} s'.format(end_time - start_time))

        # Construct Z-Surface
        poles_z = z_vec.reshape(self._v_basis.size, self._u_basis.size).T
        #poles_z *= self.grid_surf.z_scale
        #poles_z += self.grid_surf.z_shift
        surface_z = bs.Surface((self._u_basis, self._v_basis), poles_z[:, :,
                                                                       None])
        self.surface = bs.Z_Surface(self.quad[0:3], surface_z)

        return self.surface