diff --git a/README.html b/README.html
index 6c13281..c163d77 100644
--- a/README.html
+++ b/README.html
@@ -343,7 +343,7 @@
Constant function approximation
Linear function approximation
-If we make make a slightly more appropriate assuming that in the neighborhood
+
If we make make a slightly more appropriate assumption that in the neighborhood
of the \(P_Y(\z₀)\) the surface \(Y\) is a plane, then we can improve this
approximation while keeping \(\f\) linear in \(\z\):
diff --git a/README.md b/README.md
index bce5dc2..ce58753 100644
--- a/README.md
+++ b/README.md
@@ -263,7 +263,7 @@ derived our gradients geometrically.
### Linear function approximation
-If we make make a slightly more appropriate assuming that in the neighborhood
+If we make make a slightly more appropriate assumption that in the neighborhood
of the $P_Y(\z₀)$ the surface $Y$ is a plane, then we can improve this
approximation while keeping $\f$ linear in $\z$:
diff --git a/src/closest_rotation.cpp b/src/closest_rotation.cpp
index 54403c1..0750f2f 100644
--- a/src/closest_rotation.cpp
+++ b/src/closest_rotation.cpp
@@ -1,9 +1,19 @@
#include "closest_rotation.h"
+#include
+#include
void closest_rotation(
const Eigen::Matrix3d & M,
Eigen::Matrix3d & R)
{
- // Replace with your code
- R = Eigen::Matrix3d::Identity();
+ Eigen::JacobiSVD svd(M, Eigen::DecompositionOptions::ComputeFullU | Eigen::DecompositionOptions::ComputeFullV);
+
+ Eigen::Matrix3d U = svd.matrixU();
+ Eigen::Matrix3d V = svd.matrixV();
+ Eigen::Matrix3d O;
+ O << 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, (U * V.transpose()).determinant();
+
+ R = U * O * V.transpose();
}
diff --git a/src/hausdorff_lower_bound.cpp b/src/hausdorff_lower_bound.cpp
index 8608964..10e0bc2 100644
--- a/src/hausdorff_lower_bound.cpp
+++ b/src/hausdorff_lower_bound.cpp
@@ -1,4 +1,7 @@
#include "hausdorff_lower_bound.h"
+#include "random_points_on_mesh.h"
+#include "point_mesh_distance.h"
+
double hausdorff_lower_bound(
const Eigen::MatrixXd & VX,
@@ -7,6 +10,15 @@ double hausdorff_lower_bound(
const Eigen::MatrixXi & FY,
const int n)
{
- // Replace with your code
- return 0;
+ Eigen::MatrixXd X;
+ random_points_on_mesh(n,VX,FX,X);
+
+ // Point to mesh distances from point cloud X to Y
+ Eigen::VectorXd D;
+ Eigen::MatrixXd P;
+ Eigen::MatrixXd N;
+ point_mesh_distance(X, VY, FY, D, P, N);
+
+ // Return the largest distance
+ return D.maxCoeff();
}
diff --git a/src/icp_single_iteration.cpp b/src/icp_single_iteration.cpp
index 1e8fda9..9b894bd 100644
--- a/src/icp_single_iteration.cpp
+++ b/src/icp_single_iteration.cpp
@@ -1,4 +1,8 @@
#include "icp_single_iteration.h"
+#include "random_points_on_mesh.h"
+#include "point_mesh_distance.h"
+#include "point_to_point_rigid_matching.h"
+#include "point_to_plane_rigid_matching.h"
void icp_single_iteration(
const Eigen::MatrixXd & VX,
@@ -10,7 +14,20 @@ void icp_single_iteration(
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
- // Replace with your code
- R = Eigen::Matrix3d::Identity();
- t = Eigen::RowVector3d::Zero();
+ // Sample source mesh
+ Eigen::MatrixXd X;
+ random_points_on_mesh(num_samples,VX,FX,X);
+
+ // Point to mesh distances from point cloud X to Y
+ Eigen::VectorXd D;
+ Eigen::MatrixXd P;
+ Eigen::MatrixXd N;
+ point_mesh_distance(X, VY, FY, D, P, N);
+
+
+ if (method == ICP_METHOD_POINT_TO_POINT){
+ point_to_point_rigid_matching(X,P,R,t);
+ } else {
+ point_to_plane_rigid_matching(X,P,N,R,t);
+ }
}
diff --git a/src/point_mesh_distance.cpp b/src/point_mesh_distance.cpp
index 2e6a070..c5c13b0 100644
--- a/src/point_mesh_distance.cpp
+++ b/src/point_mesh_distance.cpp
@@ -1,4 +1,6 @@
#include "point_mesh_distance.h"
+#include "point_triangle_distance.h"
+#include
void point_mesh_distance(
const Eigen::MatrixXd & X,
@@ -8,9 +10,34 @@ void point_mesh_distance(
Eigen::MatrixXd & P,
Eigen::MatrixXd & N)
{
- // Replace with your code
- P.resizeLike(X);
- N = Eigen::MatrixXd::Zero(X.rows(),X.cols());
- for(int i = 0;i::max();
+
+ for (int j = 0; j < FY.rows(); j++) {
+ const Eigen::RowVector3d x = X.row(i);
+
+ const Eigen::Vector3d a = VY.row(FY(j, 0));
+ const Eigen::Vector3d b = VY.row(FY(j, 1));
+ const Eigen::Vector3d c = VY.row(FY(j, 2));
+
+ double d_temp;
+ Eigen::RowVector3d p_temp;
+ point_triangle_distance(x, a, b, c, d_temp, p_temp);
+
+ if (d_temp < d) {
+ d = d_temp;
+ P.row(i) = p_temp;
+ N.row(i) = N_all.row(j);
+ }
+ }
+ }
+
+ D = (X - P).rowwise().norm();
}
diff --git a/src/point_to_plane_rigid_matching.cpp b/src/point_to_plane_rigid_matching.cpp
index 1978510..00e6895 100644
--- a/src/point_to_plane_rigid_matching.cpp
+++ b/src/point_to_plane_rigid_matching.cpp
@@ -1,4 +1,6 @@
#include "point_to_plane_rigid_matching.h"
+#include "closest_rotation.h"
+#include
void point_to_plane_rigid_matching(
const Eigen::MatrixXd & X,
@@ -7,7 +9,46 @@ void point_to_plane_rigid_matching(
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
- // Replace with your code
- R = Eigen::Matrix3d::Identity();
- t = Eigen::RowVector3d::Zero();
+ const int k = X.rows();
+
+ Eigen::MatrixXd A = Eigen::MatrixXd::Zero(3 * k, 6);
+
+ A.block(0, 1, k, 1) = X.col(2);
+ A.block(0, 2, k, 1) = -X.col(1);
+ A.block(0, 3, k, 1) = Eigen::MatrixXd::Ones(k, 1);
+ A.block(k, 0, k, 1) = -X.col(2);
+ A.block(k, 2, k, 1) = X.col(0);
+ A.block(k, 4, k, 1) = Eigen::MatrixXd::Ones(k, 1);
+ A.block(2 * k, 0, k, 1) = X.col(1);
+ A.block(2 * k, 1, k, 1) = -X.col(0);
+ A.block(2 * k, 5, k, 1) = Eigen::MatrixXd::Ones(k, 1);
+
+ Eigen::VectorXd x_minus_p(3 * k);
+ x_minus_p.segment(0, k) = X.col(0) - P.col(0);
+ x_minus_p.segment(k, k) = X.col(1) - P.col(1);
+ x_minus_p.segment(2 * k, k) = X.col(2) - P.col(2);
+
+ Eigen::MatrixXd diagN(k, 3*k);
+ diagN << Eigen::MatrixXd(N.col(0).asDiagonal()),
+ Eigen::MatrixXd(N.col(1).asDiagonal()),
+ Eigen::MatrixXd(N.col(2).asDiagonal());
+
+ A = diagN * A;
+ x_minus_p = diagN * x_minus_p;
+
+ Eigen::VectorXd u(6);
+ u = (A.transpose() * A).inverse() * (-A.transpose() * x_minus_p);
+
+ const double alpha = u(0);
+ const double beta = u(1);
+ const double gamma = u(2);
+
+ // This is different from the README; see issue #9
+ Eigen::Matrix3d M;
+ M << 1, gamma, -beta,
+ -gamma, 1, alpha,
+ beta, -alpha, 1;
+
+ closest_rotation(M, R);
+ t << u(3), u(4), u(5);
}
diff --git a/src/point_to_point_rigid_matching.cpp b/src/point_to_point_rigid_matching.cpp
index 079151f..52938e7 100644
--- a/src/point_to_point_rigid_matching.cpp
+++ b/src/point_to_point_rigid_matching.cpp
@@ -1,5 +1,8 @@
#include "point_to_point_rigid_matching.h"
-#include
+#include "closest_rotation.h"
+#include
+
+#include
void point_to_point_rigid_matching(
const Eigen::MatrixXd & X,
@@ -7,8 +10,39 @@ void point_to_point_rigid_matching(
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
- // Replace with your code
- R = Eigen::Matrix3d::Identity();
- t = Eigen::RowVector3d::Zero();
+ const int k = X.rows();
+
+ Eigen::MatrixXd A = Eigen::MatrixXd::Zero(3 * k, 6);
+
+ A.block(0, 1, k, 1) = X.col(2);
+ A.block(0, 2, k, 1) = -X.col(1);
+ A.block(0, 3, k, 1) = Eigen::MatrixXd::Ones(k, 1);
+ A.block(k, 0, k, 1) = -X.col(2);
+ A.block(k, 2, k, 1) = X.col(0);
+ A.block(k, 4, k, 1) = Eigen::MatrixXd::Ones(k, 1);
+ A.block(2 * k, 0, k, 1) = X.col(1);
+ A.block(2 * k, 1, k, 1) = -X.col(0);
+ A.block(2 * k, 5, k, 1) = Eigen::MatrixXd::Ones(k, 1);
+
+ Eigen::VectorXd x_minus_p(3 * k);
+ x_minus_p.segment(0, k) = X.col(0) - P.col(0);
+ x_minus_p.segment(k, k) = X.col(1) - P.col(1);
+ x_minus_p.segment(2 * k, k) = X.col(2) - P.col(2);
+
+ Eigen::VectorXd u(6);
+ u = (A.transpose() * A).inverse() * (-A.transpose() * x_minus_p);
+
+ const double alpha = u(0);
+ const double beta = u(1);
+ const double gamma = u(2);
+
+ // This is different from the README; see issue #9
+ Eigen::Matrix3d M;
+ M << 1, gamma, -beta,
+ -gamma, 1, alpha,
+ beta, -alpha, 1;
+
+ closest_rotation(M, R);
+ t << u(3), u(4), u(5);
}
diff --git a/src/point_triangle_distance.cpp b/src/point_triangle_distance.cpp
index 6405100..34d60a2 100644
--- a/src/point_triangle_distance.cpp
+++ b/src/point_triangle_distance.cpp
@@ -8,7 +8,8 @@ void point_triangle_distance(
double & d,
Eigen::RowVector3d & p)
{
- // Replace with your code
- d = 0;
- p = a;
+ Eigen::RowVector3d center = (a + b + c) / 3;
+
+ d = (center - x).norm();
+ p = c;
}
diff --git a/src/random_points_on_mesh.cpp b/src/random_points_on_mesh.cpp
index 6e85d75..4e59bf7 100644
--- a/src/random_points_on_mesh.cpp
+++ b/src/random_points_on_mesh.cpp
@@ -1,4 +1,8 @@
#include "random_points_on_mesh.h"
+#include
+#include
+
+#include
void random_points_on_mesh(
const int n,
@@ -6,8 +10,40 @@ void random_points_on_mesh(
const Eigen::MatrixXi & F,
Eigen::MatrixXd & X)
{
- // REPLACE WITH YOUR CODE:
- X.resize(n,3);
- for(int i = 0;i distribution(0.0, 1.0);
+
+ X.resize(n, 3);
+ for (int i = 0; i < X.rows(); i++) {
+
+ double gamma = distribution(generator);
+
+ int T=0;
+ while (C(T)/C(C.rows()-1) < gamma)
+ T++;
+
+ Eigen::Vector3d v1 = V.row(F(T, 0));
+ Eigen::Vector3d v2 = V.row(F(T, 1));
+ Eigen::Vector3d v3 = V.row(F(T, 2));
+
+ double alpha = distribution(generator);
+ double beta = distribution(generator);
+
+ if ((alpha + beta) > 1) {
+ alpha = 1 - alpha;
+ beta = 1 - beta;
+ }
+
+ Eigen::Vector3d x = v1 + alpha * (v2 - v1) + beta * (v3 - v1);
+ X.row(i) = x;
+ }
}