11 assert(
dim_ ==
V.cols());
12 const int n_verts =
V.rows();
14 Eigen::VectorXd min =
V.colwise().minCoeff();
15 Eigen::VectorXd max =
V.colwise().maxCoeff();
16 Eigen::VectorXd scale_ = max - min;
22 const double eps = 1e-4 * scale_.maxCoeff();
23 Eigen::VectorXi boundary_indices;
25 Eigen::VectorXi boundary_mask1 = ((
V.rowwise() - min.transpose()).rowwise().minCoeff().array() < eps).select(Eigen::VectorXi::Ones(
V.rows()), Eigen::VectorXi::Zero(
V.rows()));
26 Eigen::VectorXi boundary_mask2 = ((
V.rowwise() - max.transpose()).rowwise().maxCoeff().array() > -eps).select(Eigen::VectorXi::Ones(
V.rows()), Eigen::VectorXi::Zero(
V.rows()));
27 Eigen::VectorXi boundary_mask = boundary_mask1.array() + boundary_mask2.array();
29 boundary_indices.setZero(boundary_mask.sum());
30 for (
int i = 0, j = 0; i < boundary_mask.size(); i++)
32 boundary_indices[j++] = i;
36 Eigen::MatrixXd V_boundary =
V(boundary_indices, Eigen::all);
37 for (
int d = 0; d <
dim_; d++)
39 Eigen::VectorXi mask1 = (V_boundary.col(d).array() < min(d) + eps).select(Eigen::VectorXi::Ones(V_boundary.rows()), Eigen::VectorXi::Zero(V_boundary.rows()));
40 Eigen::VectorXi mask2 = (V_boundary.col(d).array() > max(d) - eps).select(Eigen::VectorXi::Ones(V_boundary.rows()), Eigen::VectorXi::Zero(V_boundary.rows()));
42 for (
int i = 0; i < mask1.size(); i++)
47 bool found_target =
false;
48 for (
int j = 0; j < mask2.size(); j++)
53 RowVectorNd projected_diff = V_boundary.row(j) - V_boundary.row(i);
54 projected_diff(d) = 0;
55 if (projected_diff.norm() < eps)
58 std::array<int, 2> pair = {{boundary_indices[i], boundary_indices[j]}};
65 log_and_throw_error(
"Periodic mesh failed to find corresponding node for {} in {} direction!", V_boundary.row(i), (std::vector<char>{
'X',
'Y',
'Z'})[d]);
70 for (
int d = 0; d <
dim_; d++)
75 Eigen::VectorXi reduce_map;