Пример #1
0
Reel Vecteur::norme() const
{
	// Pour éviter les erreurs numériques liées au calcul de la racine carrée au voisinage de 0
	// On commence par chercher le plus grand coefficient
	Reel max = maxCoeff();
	
	// Puis on calcule la norme
	Reel square = 0;
	for(int i=0 ; i<dim() ; i++)
	{
		square += (coord[i]/max)*(coord[i]/max); //On évite également l'overflow lié au carré
	}
	Reel norme = max * sqrt(square);
	return norme;
}
Пример #2
0
Scalar condition(Eigen::Matrix<Scalar, Rows, Cols>& matrix, Scalar maxWanted) {
  // TODO Separate case for self-adjoint matrices, which would be the case for
  // TODO covariance matrices.
  // TODO matrix.selfadjointView<Lower>().eigenvalues();
  auto values = matrix.eigenvalues().cwiseAbs();
  Scalar max = values.maxCoeff();
  Scalar min = values.minCoeff();
  // TODO Should I be using the signed min and max eigenvalues?
  // TODO I'm not sure how to deal generally with complex values if so.
  Scalar condition = max / min;

  if (condition > maxWanted) {
    // TODO If maxWanted is (near?) 1, then just set to identity?
    Scalar bonus = (max - min * maxWanted) / (maxWanted - 1);
    matrix.diagonal() = matrix.diagonal().array() + bonus;
  }

  return condition;
}
Пример #3
0
/*
 *  Vertex positioning is based on [Kobbelt et al, 2001]
 */
float Octree::findVertex(Evaluator* e)
{
    findIntersections(e);

    // Find the center of intersection positions
    glm::vec3 center = std::accumulate(
            intersections.begin(), intersections.end(), glm::vec3(),
            [](const glm::vec3& a, const Intersection& b)
                { return a + b.pos; }) / float(intersections.size());

    /*  The A matrix is of the form
     *  [n1x, n1y, n1z]
     *  [n2x, n2y, n2z]
     *  [n3x, n3y, n3z]
     *  ...
     *  (with one row for each Hermite intersection)
     */
    Eigen::MatrixX3f A(intersections.size(), 3);
    for (unsigned i=0; i < intersections.size(); ++i)
    {
        auto d = intersections[i].norm;
        A.row(i) << Eigen::Vector3f(d.x, d.y, d.z).transpose();
    }

    /*  The B matrix is of the form
     *  [p1 . n1]
     *  [p2 . n2]
     *  [p3 . n3]
     *  ...
     *  (with one row for each Hermite intersection)
     *
     *  Positions are pre-emtively shifted so that the center of the contoru
     *  is at 0, 0, 0 (since the least-squares fix minimizes distance to the
     *  origin); we'll unshift afterwards.
     */
    Eigen::VectorXf B(intersections.size(), 1);
    for (unsigned i=0; i < intersections.size(); ++i)
    {
        B.row(i) << glm::dot(intersections[i].norm,
                             intersections[i].pos - center);
    }

    // Use singular value decomposition to solve the least-squares fit.
    Eigen::JacobiSVD<Eigen::MatrixX3f> svd(A, Eigen::ComputeFullU |
                                              Eigen::ComputeFullV);

    // Truncate singular values below 0.1
    auto singular = svd.singularValues();
    svd.setThreshold(0.1 / singular.maxCoeff());
    rank = svd.rank();

    // Solve the equation and convert back to cell coordinates
    Eigen::Vector3f solution = svd.solve(B);
    vert = glm::vec3(solution.x(), solution.y(), solution.z()) + center;

    // Clamp vertex to be within the bounding box
    vert.x = std::min(X.upper(), std::max(vert.x, X.lower()));
    vert.y = std::min(Y.upper(), std::max(vert.y, Y.lower()));
    vert.z = std::min(Z.upper(), std::max(vert.z, Z.lower()));

    // Find and return QEF residual
    auto m = A * solution - B;
    return m.transpose() * m;
}
Пример #4
0
void Mesher::check_feature()
{
    auto contour = get_contour();
    const auto normals = get_normals(contour);

    // Find the largest cone and the normals that enclose
    // the largest angle as n0, n1.
    float theta = 1;
    Vec3f n0, n1;
    for (auto ni : normals)
    {
        for (auto nj : normals)
        {
            float dot = ni.dot(nj);
            if (dot < theta)
            {
                theta = dot;
                n0 = ni;
                n1 = nj;
            }
        }
    }

    // If there isn't a feature in this fan, then return immediately.
    if (theta > 0.9)
        return;

    // Decide whether this is a corner or edge feature.
    const Vec3f nstar = n0.cross(n1);
    float phi = 0;
    for (auto n : normals)
        phi = fmax(phi, fabs(nstar.dot(n)));
    bool edge = phi < 0.7;

    // Find the center of the contour.
    Vec3f center(0, 0, 0);
    for (auto c : contour)
        center += c;
    center /= contour.size();

    // Construct the matrices for use in our least-square fit.
    Eigen::MatrixX3d A(normals.size(), 3);
    {
        int i=0;
        for (auto n : normals)
            A.row(i++) << n.transpose();
    }

    // When building the second matrix, shift position values to be centered
    // about the origin (because that's what the least-squares fit will
    // minimize).
    Eigen::VectorXd B(normals.size(), 1);
    {
        auto n = normals.begin();
        auto c = contour.begin();
        int i=0;
        while (n != normals.end())
            B.row(i++) << (n++)->dot(*(c++) - center);
    }

    // Use singular value decomposition to solve the least-squares fit.
    Eigen::JacobiSVD<Eigen::MatrixX3d> svd(A, Eigen::ComputeFullU |
                                              Eigen::ComputeFullV);

    // Set the smallest singular value to zero to make fitting happier.
    if (edge)
    {
        auto singular = svd.singularValues();
        svd.setThreshold(singular.minCoeff() / singular.maxCoeff() * 1.01);
    }

    // Solve for the new point's position.
    const Vec3f new_pt = svd.solve(B) + center;

    // Erase this triangle fan, as we'll be inserting a vertex in the center.
    triangles.erase(fan_start, voxel_start);

    // Construct a new triangle fan.
    contour.push_back(contour.front());
    {
        auto p0 = contour.begin();
        auto p1 = contour.begin();
        p1++;
        while (p1 != contour.end())
            push_swappable_triangle(Triangle(*(p0++), *(p1++), new_pt));
    }
}
Пример #5
0
LanczosBounds<real_t> minmax_eigenvalues(SparseMatrixX<scalar_t> const& matrix,
                                         double precision_percent) {
    auto const precision = static_cast<real_t>(precision_percent / 100);
    auto const matrix_size = static_cast<int>(matrix.rows());

    auto left = VectorX<scalar_t>{VectorX<scalar_t>::Zero(matrix_size)};
    auto right_previous = VectorX<scalar_t>{VectorX<scalar_t>::Zero(matrix_size)};

    auto right = num::make_random<VectorX<scalar_t>>(matrix_size);
    right.normalize();

    // Alpha and beta are the diagonals of the tridiagonal matrix.
    // The final size is not known ahead of time, but it will be small.
    auto alpha = std::vector<real_t>();
    alpha.reserve(100);
    auto beta = std::vector<real_t>();
    beta.reserve(100);

    // Energy values from the previous iteration. Used to test convergence.
    // Initial values as far away from expected as possible.
    auto previous_min = std::numeric_limits<real_t>::max();
    auto previous_max = std::numeric_limits<real_t>::lowest();

    constexpr auto loop_limit = 1000;
    // This may iterate up to matrix_size, but since only the extreme eigenvalues are required it
    // will converge very quickly. Exceeding `loop_limit` would suggest something is wrong.
    for (int i = 0; i < loop_limit; ++i) {
        // PART 1: Calculate tridiagonal matrix elements a and b
        // =====================================================
        // left = h_matrix * right
        // matrix-vector multiplication (the most compute intensive part of each iteration)
        compute::matrix_vector_mul(matrix, right, left);

        auto const a = std::real(compute::dot_product(left, right));
        auto const b_prev = !beta.empty() ? beta.back() : real_t{0};

        // left -= a*right + b_prev*right_previous;
        compute::axpy(scalar_t{-a}, right, left);
        compute::axpy(scalar_t{-b_prev}, right_previous, left);
        auto const b = left.norm();

        right_previous.swap(right);
        right = (1/b) * left;

        alpha.push_back(a);
        beta.push_back(b);

        // PART 2: Check if the largest magnitude eigenvalues have converged
        // =================================================================
        auto const eigenvalues = compute::tridiagonal_eigenvalues(eigen_cast<ArrayX>(alpha),
                                                                  eigen_cast<ArrayX>(beta));
        auto const min = eigenvalues.minCoeff();
        auto const max = eigenvalues.maxCoeff();
        auto const is_converged_min = abs((previous_min - min) / min) < precision;
        auto const is_converged_max = abs((previous_max - max) / max) < precision;

        if (is_converged_min && is_converged_max) {
            return {min, max, i};
        }

        previous_min = min;
        previous_max = max;
    };

    throw std::runtime_error{"Lanczos algorithm did not converge for the min/max eigenvalues."};
}