void SimpleInflator::generate_joint( const MatrixFr& pts, const VectorI& source_ids, size_t vertex_index) { const size_t dim = m_wire_network->get_dim(); ConvexHullEngine::Ptr convex_hull = ConvexHullEngine::create(dim, "qhull"); convex_hull->run(pts); MatrixFr vertices = convex_hull->get_vertices(); MatrixIr faces = convex_hull->get_faces(); VectorI index_map = convex_hull->get_index_map(); if (dim == 2) { // Need to triangulate the loop. const size_t num_vertices = vertices.rows(); TriangleWrapper tri(vertices, faces); tri.run(std::numeric_limits<Float>::max(), false, false, false); vertices = tri.get_vertices(); faces = tri.get_faces(); assert(vertices.rows() == num_vertices); } m_vertex_list.push_back(vertices); const size_t num_faces = faces.rows(); for (size_t i=0; i<num_faces; i++) { const auto& face = faces.row(i); if (dim == 3) { auto ori_indices = map_indices(face, index_map); if (belong_to_the_same_loop(ori_indices, source_ids)) continue; } m_face_list.push_back(face.array() + m_num_vertex_accumulated); m_face_source_list.push_back(vertex_index+1); } m_num_vertex_accumulated += vertices.rows(); }
void SimpleInflator::generate_end_loops() { const size_t num_edges = m_wire_network->get_num_edges(); const MatrixFr vertices = m_wire_network->get_vertices(); const MatrixIr edges = m_wire_network->get_edges(); const MatrixFr edge_thickness = get_edge_thickness(); for (size_t i=0; i<num_edges; i++) { const VectorI& edge = edges.row(i); const VectorF& v1 = vertices.row(edge[0]); const VectorF& v2 = vertices.row(edge[1]); Float edge_len = (v2 - v1).norm(); MatrixFr loop_1 = m_profile->place(v1, v2, m_end_loop_offsets[edge[0]], edge_thickness(i, 0), m_rel_correction, m_abs_correction, m_correction_cap, m_spread_const); assert(loop_is_valid(loop_1, v1, v2)); MatrixFr loop_2 = m_profile->place(v1, v2, edge_len - m_end_loop_offsets[edge[1]], edge_thickness(i, 1), m_rel_correction, m_abs_correction, m_correction_cap, m_spread_const); assert(loop_is_valid(loop_2, v1, v2)); m_end_loops.push_back(std::make_pair(loop_1, loop_2)); } }
void reorientate_triangles(const MatrixFr& vertices, MatrixIr& faces, const VectorF& n) { assert(vertices.cols() == 3); assert(faces.cols() == 3); const VectorI& f = faces.row(0); const Vector3F& v0 = vertices.row(f[0]); const Vector3F& v1 = vertices.row(f[1]); const Vector3F& v2 = vertices.row(f[2]); Float projected_area = (v1-v0).cross(v2-v0).dot(n); if (projected_area < 0) { faces.col(2).swap(faces.col(1)); } }
EdgeMap compute_edge_map(const MatrixIr& faces) { assert(faces.cols() == 3); EdgeMap result; const size_t num_faces = faces.rows(); for (size_t i=0; i<num_faces; i++) { const Vector3I& f = faces.row(i); Triplet e0(f[1], f[2]); Triplet e1(f[2], f[0]); Triplet e2(f[0], f[1]); result.insert(e0, i); result.insert(e1, i); result.insert(e2, i); } return result; }
std::vector<Box> get_triangle_bboxes( const SelfIntersection::Points& pts, const MatrixIr& faces) { const size_t num_faces = faces.rows(); std::vector<Box> boxes; boxes.reserve(num_faces); for (size_t i=0; i<num_faces; i++) { const Vector3I f = faces.row(i); const std::vector<SelfIntersection::Point_3> corners{ pts[f[0]], pts[f[1]], pts[f[2]] }; if (CGAL::collinear(pts[f[0]], pts[f[1]], pts[f[2]])) { // Triangle is degenerated. continue; } boxes.emplace_back(CGAL::bbox_3(corners.begin(), corners.end())); boxes.back().set_id(i); } return boxes; }
std::vector<bool> create_duplication_mask(const MatrixIr& edges) { const size_t num_edges = edges.rows(); std::unordered_set<Triplet, hash> unique_set; std::vector<bool> mask(num_edges, false); for (size_t i=0; i<num_edges; i++) { const auto& edge = edges.row(i); Triplet key(edge[0], edge[1]); auto itr = unique_set.find(key); if (itr == unique_set.end()) { unique_set.insert(key); } else { mask[i] = true; } } return mask; }
bool MeshValidation::face_source_is_valid( const MatrixFr& vertices, const MatrixIr& faces, const VectorI& face_sources) { const Float EPS = 1e-6; const size_t num_vertices = vertices.rows(); const size_t num_faces = faces.rows(); Vector3F bbox_min = vertices.colwise().minCoeff(); Vector3F bbox_max = vertices.colwise().maxCoeff(); bool result = true; for (size_t i=0; i<num_faces; i++) { const Vector3I& f = faces.row(i); const Vector3F& v0 = vertices.row(f[0]); const Vector3F& v1 = vertices.row(f[1]); const Vector3F& v2 = vertices.row(f[2]); if (fabs(v0[0] - bbox_min[0]) < EPS && fabs(v1[0] - bbox_min[0]) < EPS && fabs(v2[0] - bbox_min[0]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[1] - bbox_min[1]) < EPS && fabs(v1[1] - bbox_min[1]) < EPS && fabs(v2[1] - bbox_min[1]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[2] - bbox_min[2]) < EPS && fabs(v1[2] - bbox_min[2]) < EPS && fabs(v2[2] - bbox_min[2]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[0] - bbox_max[0]) < EPS && fabs(v1[0] - bbox_max[0]) < EPS && fabs(v2[0] - bbox_max[0]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[1] - bbox_max[1]) < EPS && fabs(v1[1] - bbox_max[1]) < EPS && fabs(v2[1] - bbox_max[1]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[2] - bbox_max[2]) < EPS && fabs(v1[2] - bbox_max[2]) < EPS && fabs(v2[2] - bbox_max[2]) < EPS) { result = result && (face_sources[i] == 0); continue; } result = result && (face_sources[i] != 0); if (!result) { std::cout << i << ": "; std::cout << face_sources[i] << std::endl; std::cout << v0.transpose() << std::endl; std::cout << v1.transpose() << std::endl; std::cout << v2.transpose() << std::endl; return result; } } return result; }
void LongEdgeRemoval::triangulate_chain( std::vector<VectorI>& faces, const std::vector<size_t>& chain, size_t v0_idx, size_t v1_idx, size_t v2_idx) { const size_t chain_size = chain.size(); auto next = [&](size_t i) { return (i+1) % chain_size; }; auto prev = [&](size_t i) { return (i+chain_size-1) % chain_size; }; auto length = [&](size_t vi, size_t vj) { return (m_vertices.row(vi) - m_vertices.row(vj)).norm(); }; MatrixIr visited = MatrixIr::Zero(chain_size, 3); visited(v0_idx, 0) = 1; visited(v1_idx, 1) = 1; visited(v2_idx, 2) = 1; MatrixIr candidates(3, 6); candidates << v0_idx, next(v0_idx), prev(v0_idx), 0, 0, 0, v1_idx, next(v1_idx), prev(v1_idx), 0, 0, 0, v2_idx, next(v2_idx), prev(v2_idx), 0, 0, 0; MatrixFr candidate_lengths(3, 2); const Float NOT_USED = std::numeric_limits<Float>::max(); candidate_lengths << length(chain[candidates(0, 1)], chain[candidates(0, 2)]), NOT_USED, length(chain[candidates(1, 1)], chain[candidates(1, 2)]), NOT_USED, length(chain[candidates(2, 1)], chain[candidates(2, 2)]), NOT_USED; auto index_comp = [&](size_t i, size_t j) { // Use greater than operator so the queue is a min heap. return candidate_lengths.row(i).minCoeff() > candidate_lengths.row(j).minCoeff(); }; std::priority_queue<size_t, std::vector<size_t>, decltype(index_comp)> Q(index_comp); Q.push(0); Q.push(1); Q.push(2); while (!Q.empty()) { size_t idx = Q.top(); Q.pop(); size_t selection; if (candidate_lengths(idx, 0) != NOT_USED && candidate_lengths(idx, 0) <= candidate_lengths(idx, 1)) { selection = 0; } else if (candidate_lengths(idx, 1) != NOT_USED && candidate_lengths(idx, 1) < candidate_lengths(idx, 0)){ selection = 1; } else { continue; } size_t base_v = candidates(idx, selection * 3 + 0); size_t right_v = candidates(idx, selection * 3 + 1); size_t left_v = candidates(idx, selection * 3 + 2); assert(visited(base_v, idx) >= 1); if (visited.row(base_v).sum() > 1 || visited(right_v, idx) > 1 || visited(left_v, idx) > 1) { candidate_lengths(idx, selection) = NOT_USED; Q.push(idx); continue; } visited(right_v, idx) = 1; visited(left_v, idx) = 1; visited(base_v, idx) = 2; faces.push_back(Vector3I(chain[base_v], chain[right_v], chain[left_v])); if (visited.row(right_v).sum() == 1) { size_t right_to_right = next(right_v); Float edge_len = length(chain[left_v], chain[right_to_right]); candidate_lengths(idx, 0) = edge_len; candidates.block(idx, 0, 1, 3) = Vector3I(right_v, right_to_right, left_v).transpose(); } else { candidate_lengths(idx, 0) = NOT_USED; } if (visited.row(left_v).sum() == 1) { size_t left_to_left = prev(left_v); Float edge_len = length(chain[right_v], chain[left_to_left]); candidate_lengths(idx, 1) = edge_len; candidates.block(idx, 3, 1, 3) = Vector3I(left_v, right_v, left_to_left).transpose(); } else { candidate_lengths(idx, 1) = NOT_USED; } Q.push(idx); } auto visited_sum = (visited.array() > 0).rowwise().count().eval(); if ((visited_sum.array() > 1).count() == 3) { Vector3I face; size_t count = 0; for (size_t i=0; i<chain_size; i++) { if (visited_sum[i] > 1) { assert(count < 3); face[count] = chain[i]; count++; } } faces.push_back(face); } }