Skip to content

Commit

Permalink
added cpp code and test
Browse files Browse the repository at this point in the history
  • Loading branch information
adityaranigaon committed Dec 12, 2024
1 parent 601516a commit aee6c8b
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
49 changes: 49 additions & 0 deletions cpp/open3d/t/geometry/TriangleMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <Eigen/Core>
#include <string>
#include <unordered_map>
#include <set>

#include "open3d/core/CUDAUtils.h"
#include "open3d/core/Device.h"
Expand Down Expand Up @@ -65,6 +66,54 @@ TriangleMesh::TriangleMesh(const core::Tensor &vertex_positions,
SetVertexPositions(vertex_positions);
SetTriangleIndices(triangle_indices);
}

std::pair<core::Tensor, core::Tensor> TriangleMesh::ComputeAdjacencyList() {

if (IsEmpty()) {
utility::LogWarning("TriangleMesh is empty. No attributes computed!");
return std::make_pair(core::Tensor(), core::Tensor());
}

if(!HasTriangleIndices()) {
utility::LogWarning("TriangleMesh has no Indices. No attributes computed!");
return std::make_pair(core::Tensor(), core::Tensor());
}

core::Tensor tris_cpu =
GetTriangleIndices().To(core::Device()).Contiguous();

std::unordered_map< size_t, std::set<size_t> > adjacencyList;
auto insertEdge = [&adjacencyList](size_t s, size_t t){
adjacencyList[s].insert(t);
};

for(int idx = 0; idx < tris_cpu.GetLength(); idx++){
auto triangle_tensor = tris_cpu[idx];
auto *triangle = triangle_tensor.GetDataPtr<int>();
insertEdge(triangle[0], triangle[1]);
insertEdge(triangle[1], triangle[2]);
insertEdge(triangle[2], triangle[0]);
}

int num_vertices = GetVertexPositions().GetLength();
core::Tensor adjst = core::Tensor::Zeros({num_vertices+1}, core::Dtype::Int64);

int num_edges = tris_cpu.GetLength() * 3;
core::Tensor adjv = core::Tensor::Zeros({num_edges}, core::Dtype::Int64);

long prev_nnz = 0;
for(int idx = 1; idx <= num_vertices; idx++){
adjst[idx] = adjst[idx-1] + static_cast<long>(adjacencyList[idx-1].size());

int i = 0;
for(auto x : adjacencyList[idx-1]){
adjv[ prev_nnz + i] = x;
i++;
}
prev_nnz += static_cast<long>(adjacencyList[idx-1].size());
}
return std::make_pair(adjv, adjst);
}

std::string TriangleMesh::ToString() const {
size_t num_vertices = 0;
Expand Down
2 changes: 2 additions & 0 deletions cpp/open3d/t/geometry/TriangleMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,8 @@ class TriangleMesh : public Geometry, public DrawableGeometry {
TriangleMesh BooleanDifference(const TriangleMesh &mesh,
double tolerance = 1e-6) const;

std::pair<core::Tensor, core::Tensor> ComputeAdjacencyList();

/// Create an axis-aligned bounding box from vertex attribute "positions".
AxisAlignedBoundingBox GetAxisAlignedBoundingBox() const;

Expand Down
64 changes: 64 additions & 0 deletions cpp/tests/t/geometry/TriangleMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,70 @@ INSTANTIATE_TEST_SUITE_P(TriangleMesh,
TriangleMeshPermuteDevices,
testing::ValuesIn(PermuteDevices::TestCases()));

TEST_P(TriangleMeshPermuteDevices, ComputeAdjacencyList_emptyMesh) {
//Test the interface and the case when mesh is empty

t::geometry::TriangleMesh empty_mesh;

auto listCSR = empty_mesh.ComputeAdjacencyList();

core::Tensor adjacent_vertex = listCSR.first;
core::Tensor adjacent_index_start = listCSR.second;
EXPECT_TRUE(adjacent_vertex.GetLength() == 0);
EXPECT_TRUE(adjacent_index_start.GetLength() == 0);
}

TEST_P(TriangleMeshPermuteDevices, ComputeAdjacencyList_matchValues) {
//Test the actual values computed in the function

core::Device device = GetParam();
core::Dtype float_dtype_custom = core::Float64;
core::Dtype int_dtype_custom = core::Int32;

t::geometry::TriangleMesh mesh =
t::geometry::TriangleMesh::CreateTetrahedron(
2, float_dtype_custom, int_dtype_custom, device);

auto listCSR = mesh.ComputeAdjacencyList();
core::Tensor adjv = listCSR.first;
core::Tensor adjst = listCSR.second;

EXPECT_TRUE( adjv.GetLength() > 0);
EXPECT_TRUE( adjst.GetLength() > 0);

core::Tensor csr_col = core::Tensor::Init<int64_t>(
{1, 2, 3, 0, 2, 3, 0, 1, 3, 0, 1, 2}, device);

core::Tensor csr_row_idx = core::Tensor::Init<int64_t>(
{0, 3, 6, 9, 12}, device);

EXPECT_EQ(adjv.GetLength(), csr_col.GetLength());
EXPECT_EQ(adjst.GetLength(), csr_row_idx.GetLength());
EXPECT_TRUE(adjv.AllEqual(csr_col));
EXPECT_TRUE(adjst.AllEqual(csr_row_idx));
}

TEST_P(TriangleMeshPermuteDevices, ComputeAdjacencyList_expectedBehaviour) {
//On a larger mesh, test the interface and few expected properties

core::Device device = GetParam();
core::Dtype float_dtype_custom = core::Float64;
core::Dtype int_dtype_custom = core::Int32;

t::geometry::TriangleMesh mesh =
t::geometry::TriangleMesh::CreateIcosahedron(
2, float_dtype_custom, int_dtype_custom, device);


auto listCSR = mesh.ComputeAdjacencyList();
core::Tensor adjv = listCSR.first;
core::Tensor adjst = listCSR.second;

EXPECT_TRUE( adjv.GetLength() > 0);
EXPECT_TRUE( adjst.GetLength() > 0);
EXPECT_EQ(adjst.ToFlatVector<int64_t>()[adjst.GetLength()-1], adjv.GetLength());
}

TEST_P(TriangleMeshPermuteDevices, DefaultConstructor) {
t::geometry::TriangleMesh mesh;

Expand Down

0 comments on commit aee6c8b

Please sign in to comment.