Program Listing for File MeshHelper.hpp

Return to documentation for file (include\Polylidar\Mesh\MeshHelper.hpp)

#ifndef MESHHELPER
#define MESHHELPER
#include <vector>
#include <array>

#include <unordered_map>
#include <parallel_hashmap/phmap.h>

#include "Polylidar/Types.hpp"
#include "Polylidar/UtilityMath.hpp"

#if defined(_OPENMP)
#include <omp.h>
#define PL_OMP_MAX_THREAD_DEPTH_TO_PC 8
#endif

namespace Polylidar {

namespace MeshHelper {

#ifdef PL_USE_STD_UNORDERED_MAP
template <typename T, typename G>
using unordered_map = std::unordered_map<T, G>;
#else
template <typename T, typename G>
using unordered_map = phmap::flat_hash_map<T, G>;
#endif

using MatX2I = std::vector<std::array<size_t, 2>>;
class HalfEdgeTriangulation
{

  public:
    Matrix<double> vertices;
    Matrix<size_t> triangles;
    Matrix<size_t> halfedges;
    Matrix<double> triangle_normals;
    Matrix<uint8_t> vertex_classes;
    bool counter_clock_wise;

    HalfEdgeTriangulation();

    HalfEdgeTriangulation& operator=(const HalfEdgeTriangulation& other) = default;
    HalfEdgeTriangulation(HalfEdgeTriangulation&& other) = default;
    HalfEdgeTriangulation(const Matrix<double>& in_vertices);
    HalfEdgeTriangulation(Matrix<double>&& in_vertices);
    HalfEdgeTriangulation(Matrix<double>&& in_vertices, Matrix<size_t>&& in_triangles);
    HalfEdgeTriangulation(Matrix<double>&& in_vertices, Matrix<size_t>&& in_triangles, Matrix<size_t>&& in_halfedges);
    HalfEdgeTriangulation(Matrix<double>&& in_vertices, Matrix<size_t>&& in_triangles, Matrix<size_t>&& in_halfedges,
                          Matrix<double>&& in_triangle_normals);
    void SetTriangleNormals(const Matrix<double>& in_triangle_normals);
    void SetVertexClasses(const Matrix<uint8_t>& in_vertex_classes, bool copy=true);
    void ComputeTriangleNormals();

  private:
};

inline size_t CantorMapping(const size_t k1, const size_t k2)
{
    auto dk1 = static_cast<double>(k1);
    auto dk2 = static_cast<double>(k2);
    auto mapping = static_cast<size_t>(((dk1 + dk2) * (dk1 + dk2 + 1)) / 2.0 + dk2);
    return mapping;
}

inline std::vector<size_t> ExtractHalfEdges(const std::vector<size_t>& triangles)
{
    // auto before = std::chrono::high_resolution_clock::now();
    size_t max_limit = std::numeric_limits<size_t>::max();

    std::vector<size_t> halfedges(triangles.size(), max_limit);
    MatX2I halfedges_pi(triangles.size());
    unordered_map<size_t, size_t> vertex_indices_to_half_edge_index;
    vertex_indices_to_half_edge_index.reserve(triangles.size());

    for (size_t triangle_index = 0; triangle_index < triangles.size(); triangle_index += 3)
    {
        const size_t* triangle = &triangles[triangle_index];
        size_t& num_half_edges = triangle_index;

        size_t he_0_index = num_half_edges;
        size_t he_1_index = num_half_edges + 1;
        size_t he_2_index = num_half_edges + 2;
        size_t he_0_mapped = CantorMapping(triangle[0], triangle[1]);
        size_t he_1_mapped = CantorMapping(triangle[1], triangle[2]);
        size_t he_2_mapped = CantorMapping(triangle[2], triangle[0]);

        std::array<size_t, 2>& he_0 = halfedges_pi[he_0_index];
        std::array<size_t, 2>& he_1 = halfedges_pi[he_1_index];
        std::array<size_t, 2>& he_2 = halfedges_pi[he_2_index];

        he_0[0] = triangle[0];
        he_0[1] = triangle[1];
        he_1[0] = triangle[1];
        he_1[1] = triangle[2];
        he_2[0] = triangle[2];
        he_2[1] = triangle[0];

        // Check for Non Manifold Mesh?
        vertex_indices_to_half_edge_index[he_0_mapped] = he_0_index;
        vertex_indices_to_half_edge_index[he_1_mapped] = he_1_index;
        vertex_indices_to_half_edge_index[he_2_mapped] = he_2_index;
    }

    for (size_t this_he_index = 0; this_he_index < halfedges.size(); this_he_index++)
    {
        size_t& that_he_index = halfedges[this_he_index];
        std::array<size_t, 2>& this_he = halfedges_pi[this_he_index];
        size_t that_he_mapped = CantorMapping(this_he[1], this_he[0]);
        if (that_he_index == max_limit &&
            vertex_indices_to_half_edge_index.find(that_he_mapped) != vertex_indices_to_half_edge_index.end())
        {
            size_t twin_he_index = vertex_indices_to_half_edge_index[that_he_mapped];
            halfedges[this_he_index] = twin_he_index;
            halfedges[twin_he_index] = this_he_index;
        }
    }
    return halfedges;
}

inline void ExtractHalfEdgesMatrix(const Matrix<size_t>& triangles, Matrix<size_t>& halfedges)
{
    auto& triangles_vec = triangles.data;
    // Extract half edges as a vector
    auto halfedges_vec = ExtractHalfEdges(triangles_vec);
    halfedges.data = std::move(halfedges_vec);
    // Update the ptr to the new data, set rows and columns
    halfedges.UpdatePtrFromData(triangles.rows, triangles.cols);
}

void ComputeTriangleNormalsFromMatrix(const Matrix<double>& vertices, const Matrix<size_t>& triangles,
                                      Matrix<double>& triangle_normals_mat, const bool flip_normals = false);

void ComputeTriangleNormals(const Matrix<double>& vertices, const std::vector<size_t>& triangles,
                            std::vector<double>& triangle_normals, const bool flip_normals = false);

HalfEdgeTriangulation CreateTriMeshFromVectors(std::vector<double>&& vertices, std::vector<size_t>&& triangles,
                                               std::vector<size_t>&& halfedges);


void LaplacianFilterVertices(HalfEdgeTriangulation& mesh, int iterations, double lambda);

void BilateralFilterNormals(HalfEdgeTriangulation& mesh, int iterations, double sigma_length, double sigma_angle);
// TriMesh CreateTriMeshCopy(const double* vertices_ptr, size_t num_vertices, const size_t* triangles_ptr,
//                           size_t num_triangles);
// TriMesh CreateTriMeshCopy(const double* vertices_ptr, size_t num_vertices, const int* triangles_ptr,
//                           size_t num_triangles);

std::vector<double> ExtractPointCloudFromFloatDepth(const Matrix<float>& im, const Matrix<double>& intrinsics,
                                                    const Matrix<double>& extrinsics, const size_t stride);

std::tuple<std::vector<double>, std::vector<size_t>, std::vector<size_t>>
ExtractUniformMeshFromFloatDepth(const Matrix<float>& im, const Matrix<double>& intrinsics,
                                 const Matrix<double>& extrinsics, const size_t stride);

HalfEdgeTriangulation ExtractTriMeshFromFloatDepth(const Matrix<float>& im, const Matrix<double>& intrinsics,
                                                   const Matrix<double>& extrinsics, const size_t stride,
                                                   const bool calc_normals = PL_DEFAULT_CALC_NORMALS);

std::tuple<HalfEdgeTriangulation, VUI> ExtractTriMeshFromOrganizedPointCloud(Matrix<double>& points_2D,
                                                                             const size_t rows, const size_t cols,
                                                                             const size_t stride,
                                                                             const bool calc_normals);
HalfEdgeTriangulation CreateTriMeshCopy(Matrix<double>& vertices, Matrix<int>& triangles,
                                        const bool calc_normals = true);

} // namespace MeshHelper
} // namespace Polylidar

#endif