diff --git a/src/per_corner_normals.cpp b/src/per_corner_normals.cpp index 54aa9cb..34e4f11 100644 --- a/src/per_corner_normals.cpp +++ b/src/per_corner_normals.cpp @@ -2,7 +2,6 @@ #include "triangle_area_normal.h" // Hint: #include "vertex_triangle_adjacency.h" -#include void per_corner_normals( const Eigen::MatrixXd & V, @@ -11,7 +10,30 @@ void per_corner_normals( Eigen::MatrixXd & N) { N = Eigen::MatrixXd::Zero(F.rows()*3,3); - //////////////////////////////////////////////////////////////////////////// - // Add your code here: - //////////////////////////////////////////////////////////////////////////// + Eigen::VectorXi count = Eigen::VectorXi::Zero(F.rows()*3); + std::vector> VF; + + vertex_triangle_adjacency(F, V.rows(), VF); + + double cos_threshold = std::cos(corner_threshold * M_PI / 180.0); + + /* Compute the area-weighted average of normals of faces with normals that deviate less than threshold. */ + for (int i = 0; i < F.rows(); i++) { /* For each face */ + Eigen::RowVector3d face_area_normal = triangle_area_normal(V.row(F(i,0)), V.row(F(i,1)), V.row(F(i,2))); + for (int j = 0; j < 3; j++) { /* For each corner of the face */ + for (int g = 0; g < VF[F(i,j)].size(); g++) { /* For each face neighboring the corner */ + int face = VF[F(i, j)][g]; + Eigen::RowVector3d neighbor_area_normal = triangle_area_normal(V.row(F(face,0)), V.row(F(face,1)), V.row(F(face,2))); + double dot = neighbor_area_normal.normalized().dot(face_area_normal.normalized()); + if (std::max(-1.0, std::min(1.0, dot)) > cos_threshold) { + N.row(i * 3 + j) += neighbor_area_normal; + count(i * 3 + j)++; + } + } + } + } + /* Normalize the sum of the normals by the number of faces neighboring each corner. */ + for (int i = 0; i < N.rows(); i++) { + N.row(i) = (N.row(i) / count(i)).normalized(); + } } diff --git a/src/per_face_normals.cpp b/src/per_face_normals.cpp index 8ec82cd..9ab3b3b 100644 --- a/src/per_face_normals.cpp +++ b/src/per_face_normals.cpp @@ -6,8 +6,9 @@ void per_face_normals( const Eigen::MatrixXi & F, Eigen::MatrixXd & N) { - //////////////////////////////////////////////////////////////////////////// - // Replace with your code: - N = Eigen::MatrixXd::Zero(F.rows(),3); - //////////////////////////////////////////////////////////////////////////// + N = Eigen::MatrixXd::Zero(F.rows(), 3); + + for (int i = 0; i < F.rows(); i++) { + N.row(i) = triangle_area_normal(V.row(F(i, 0)), V.row(F(i, 1)), V.row(F(i, 2))).normalized(); + } } diff --git a/src/per_vertex_normals.cpp b/src/per_vertex_normals.cpp index 040311e..856b789 100644 --- a/src/per_vertex_normals.cpp +++ b/src/per_vertex_normals.cpp @@ -1,5 +1,6 @@ #include "per_vertex_normals.h" #include "triangle_area_normal.h" +#include "vertex_triangle_adjacency.h" /* Why not use the method that does exactly what we want to do (but faster)? */ void per_vertex_normals( const Eigen::MatrixXd & V, @@ -7,7 +8,20 @@ void per_vertex_normals( Eigen::MatrixXd & N) { N = Eigen::MatrixXd::Zero(V.rows(),3); - //////////////////////////////////////////////////////////////////////////// - // Add your code here: - //////////////////////////////////////////////////////////////////////////// + Eigen::VectorXi count = Eigen::VectorXi::Zero(V.rows()); + std::vector> VF; + + vertex_triangle_adjacency(F, V.rows(), VF); + + /* Calculate the product of the area and the normal of each face neighboring each vertex. */ + for (int i = 0; i < V.rows(); i++) { + for (int j = 0; j < VF[i].size(); j++) { + N.row(i) += triangle_area_normal(V.row(F(VF[i][j],0)), V.row(F(VF[i][j],1)), V.row(F(VF[i][j],2))); + count(i)++; + } + } + /* Normalize the sum of the normals by the number of faces neighboring each vertex. */ + for (int i = 0; i < V.rows(); i++) { + N.row(i) = (N.row(i) / count (i)).normalized(); + } } diff --git a/src/triangle_area_normal.cpp b/src/triangle_area_normal.cpp index 4ecad22..6486eae 100644 --- a/src/triangle_area_normal.cpp +++ b/src/triangle_area_normal.cpp @@ -6,8 +6,7 @@ Eigen::RowVector3d triangle_area_normal( const Eigen::RowVector3d & b, const Eigen::RowVector3d & c) { - //////////////////////////////////////////////////////////////////////////// - // Replace with your code: - //////////////////////////////////////////////////////////////////////////// - return Eigen::RowVector3d(0,0,0); + Eigen::RowVector3d normal = (b - a).cross(c - a); + double area = 0.5 * normal.norm(); /* https://en.wikipedia.org/wiki/Cross_product#Geometric_meaning */ + return normal.normalized() * area; } diff --git a/src/vertex_triangle_adjacency.cpp b/src/vertex_triangle_adjacency.cpp index faa8bb6..4b002fb 100644 --- a/src/vertex_triangle_adjacency.cpp +++ b/src/vertex_triangle_adjacency.cpp @@ -6,8 +6,11 @@ void vertex_triangle_adjacency( std::vector > & VF) { VF.resize(num_vertices); - //////////////////////////////////////////////////////////////////////////// - // Add your code here: - //////////////////////////////////////////////////////////////////////////// + + for (int i = 0; i < F.rows(); i++) { + for (int j = 0; j < F.cols(); j++) { + VF[F(i, j)].emplace_back(i); + } + } }