| #ifndef GEODESIC_ALGORITHM_BASE |
| #define GEODESIC_ALGORITHM_BASE |
|
|
| #include "geodesic_algorithm_exact_elements.h" |
| #include "geodesic_constants_and_simple_functions.h" |
| #define hfid0 0 |
| #define hfid1 1 |
|
|
| namespace geodesic{ |
| class GeodesicAlgorithmBase |
| { |
| public: |
| vertex_pointer opposite_vertex(edge_pointer e, vertex_pointer v) |
| { |
| halfedge_handle hf0 = this->mesh()->halfedge_handle(e, hfid0); |
| if(this->mesh()->from_vertex_handle(hf0).idx()==v.idx()) |
| return this->mesh()->to_vertex_handle(hf0); |
| else |
| return this->mesh()->from_vertex_handle(hf0); |
| }; |
|
|
| vertex_pointer opposite_vertex(face_pointer f, edge_pointer e) |
| { |
| halfedge_handle hf = this->mesh()->halfedge_handle(e, hfid0); |
| hf = this->mesh()->face_handle(hf)==f? hf : this->mesh()->opposite_halfedge_handle(hf); |
| return this->mesh()->to_vertex_handle(this->mesh()->next_halfedge_handle(hf)); |
| }; |
|
|
| bool belongs_v(edge_pointer e, vertex_pointer v) |
| { |
| halfedge_handle hf = this->mesh()->halfedge_handle(e, hfid0); |
| return this->mesh()->from_vertex_handle(hf) == v || |
| this->mesh()->to_vertex_handle(hf) == v; |
| } |
|
|
| edge_pointer next_edge(face_pointer f, edge_pointer e, vertex_pointer v) |
| { |
|
|
| halfedge_handle hf = this->mesh()->halfedge_handle(e, hfid0); |
| hf = this->mesh()->face_handle(hf)==f? hf : this->mesh()->opposite_halfedge_handle(hf); |
| halfedge_handle next_hf; |
| if(this->mesh()->from_vertex_handle(hf)==v) |
| { |
| next_hf = this->mesh()->next_halfedge_handle(this->mesh()->next_halfedge_handle(hf)); |
| } |
| else if(this->mesh()->to_vertex_handle(hf)==v) |
| next_hf = this->mesh()->next_halfedge_handle(hf); |
| else |
| { |
| std::cout << "next_edge e and v has no connection" << std::endl; |
| exit(1); |
| } |
| return this->mesh()->edge_handle(next_hf); |
| }; |
|
|
| Scalar vertex_angle(face_pointer f, vertex_pointer v) |
| { |
| halfedge_handle hf0 = this->mesh()->halfedge_handle(f); |
| vertex_pointer v0 = this->mesh()->from_vertex_handle(hf0); |
| vertex_pointer v1 = this->mesh()->to_vertex_handle(hf0); |
| vertex_pointer v2 = this->mesh()->to_vertex_handle(this->mesh()->next_halfedge_handle(hf0)); |
| Scalar l1 = (this->mesh()->point(v0) - this->mesh()->point(v1)).norm(); |
| Scalar l2 = (this->mesh()->point(v1) - this->mesh()->point(v2)).norm(); |
| Scalar l3 = (this->mesh()->point(v2) - this->mesh()->point(v0)).norm(); |
| if(v0.idx()==v.idx()) |
| { |
| return angle_from_edges(l2, l3, l1); |
| } |
| if(v1.idx()==v.idx()) |
| { |
| return angle_from_edges(l3, l1, l2); |
| } |
| if(v2.idx()==v.idx()) |
| { |
| return angle_from_edges(l1, l2, l3); |
| } |
| }; |
|
|
| void update_edgelen() |
| { |
| for(auto eit = this->mesh()->edges_begin(); eit != this->mesh()->edges_end(); eit++) |
| { |
| halfedge_handle hf = this->mesh()->halfedge_handle(*eit, hfid0); |
| Vec3 v1 = this->mesh()->point(this->mesh()->from_vertex_handle(hf)); |
| Vec3 v2 = this->mesh()->point(this->mesh()->to_vertex_handle(hf)); |
| this->mesh()->data(*eit).length = (v1-v2).norm(); |
| } |
| }; |
|
|
| void build_adjacencies(); |
|
|
| edge_pointer opposite_edge(face_pointer f, vertex_pointer v) |
| { |
| for(auto e_it = this->mesh()->fe_begin(f); e_it != this->mesh()->fe_end(f); ++e_it) |
| { |
| edge_pointer e = *e_it; |
| if(!belongs_v(e, v)) |
| { |
| return e; |
| } |
| } |
| }; |
|
|
| face_pointer opposite_face(edge_pointer e, face_pointer f) |
| { |
| halfedge_handle hf = this->mesh()->halfedge_handle(e, hfid0); |
| return this->mesh()->face_handle(hf) == f? |
| this->mesh()->face_handle(this->mesh()->opposite_halfedge_handle(hf)) |
| :this->mesh()->face_handle(hf); |
| }; |
|
|
| void initialize(Mesh* mesh); |
|
|
| GeodesicAlgorithmBase(Mesh* mesh) |
| { |
| initialize(mesh); |
| }; |
|
|
| GeodesicAlgorithmBase(){m_mesh = NULL;}; |
|
|
| virtual ~GeodesicAlgorithmBase(){}; |
|
|
| virtual void print_statistics() |
| { |
| std::cout << "propagation step took " << m_time_consumed << " seconds " << std::endl; |
| }; |
|
|
| Mesh* mesh(){return m_mesh;}; |
|
|
| |
| bool compute_propagated_parameters(Scalar pseudo_x, |
| Scalar pseudo_y, |
| Scalar start, |
| Scalar end, |
| Scalar alpha, |
| Scalar L, |
| interval_pointer candidates, |
| Scalar d); |
|
|
| |
| Scalar compute_positive_intersection(Scalar start, |
| Scalar pseudo_x, |
| Scalar pseudo_y, |
| Scalar sin_alpha, |
| Scalar cos_alpha); |
|
|
| inline bool calculate_triangle_parameters(list_pointer &list, Triangle &Tri); |
|
|
| list_pointer interval_list_0(edge_pointer e) |
| { |
| return &m_edge_interval_lists_0[e.idx()]; |
| }; |
|
|
| list_pointer interval_list_1(edge_pointer e) |
| { |
| return &m_edge_interval_lists_1[e.idx()]; |
| }; |
|
|
|
|
| protected: |
|
|
| Mesh* m_mesh; |
|
|
| Triangle Tri; |
|
|
| IntervalList wl_left, wl_right; |
|
|
| std::vector<IntervalList> m_edge_interval_lists_0; |
| std::vector<IntervalList> m_edge_interval_lists_1; |
|
|
| }; |
|
|
| inline void GeodesicAlgorithmBase::initialize(Mesh* mesh) |
| { |
| m_mesh = mesh; |
| m_edge_interval_lists_0.resize(mesh->n_edges()); |
| m_edge_interval_lists_1.resize(mesh->n_edges()); |
|
|
| |
| m_queue_max_size = 0; |
| m_windows_propagation = 0; |
| m_windows_wavefront = 0; |
| m_windows_peak = 0; |
|
|
| |
| for (unsigned i = 0; i < m_edge_interval_lists_0.size(); ++i) |
| { |
| edge_pointer edge = mesh->edge_handle(i); |
| m_edge_interval_lists_0[i].initialize(edge); |
| m_edge_interval_lists_1[i].initialize(edge); |
| interval_list_0(edge)->start_vertex() = mesh->from_vertex_handle(mesh->halfedge_handle(edge, hfid0)); |
| interval_list_1(edge)->start_vertex() = mesh->from_vertex_handle(mesh->halfedge_handle(edge, hfid1)); |
| } |
| |
| for (unsigned i = 0; i < mesh->n_faces(); ++i) |
| { |
| face_pointer f = (mesh->face_handle(i)); |
| vertex_pointer v[3]; |
| size_t j = 0; |
| for (auto e_it = mesh->fe_begin(f); e_it != mesh->fe_end(f); ++e_it) |
| { |
| edge_pointer e = *e_it; |
| if (mesh->face_handle(mesh->halfedge_handle(e, hfid0)) == f) |
| v[j] = interval_list_0(e)->start_vertex(); |
| else |
| v[j] = interval_list_1(e)->start_vertex(); |
|
|
| if ((interval_list_0(e)->start_vertex().idx() < 0) || (interval_list_1(e)->start_vertex().idx() < 0)) |
| { |
| std::cout << "list link error" << std::endl; |
| exit(1); |
| } |
|
|
| if (interval_list_0(e)->start_vertex() == interval_list_1(e)->start_vertex()) |
| { |
| std::cout << "list link error" << std::endl; |
| exit(1); |
| } |
|
|
| if (!((belongs_v(e, interval_list_0(e)->start_vertex())) && |
| (belongs_v(e, interval_list_1(e)->start_vertex())))) |
| { |
| std::cout << "list link error" << std::endl; |
| exit(1); |
| } |
| j++; |
| } |
| if ((v[0].idx() >-1 && v[0] == v[1]) || (v[0].idx() >-1 && v[0] == v[2]) || (v[1].idx() >-1 && v[1] == v[2])) |
| { |
| std::cout << "list link error" << std::endl; |
| exit(1); |
| } |
| } |
| update_edgelen(); |
| build_adjacencies(); |
| }; |
|
|
| inline Scalar GeodesicAlgorithmBase::compute_positive_intersection(Scalar start, |
| Scalar pseudo_x, |
| Scalar pseudo_y, |
| Scalar sin_alpha, |
| Scalar cos_alpha) |
| { |
| |
| assert(pseudo_y <= 0); |
|
|
| Scalar denominator = sin_alpha*(pseudo_x - start) - cos_alpha*pseudo_y; |
| if (denominator < 0.0) |
| { |
| return -1.0; |
| } |
|
|
| Scalar numerator = -pseudo_y*start; |
|
|
| if (numerator < 1e-30) |
| { |
| return 0.0; |
| } |
|
|
| if (denominator < 1e-30) |
| { |
| return -1.0; |
| } |
|
|
| return numerator / denominator; |
| } |
|
|
| inline bool GeodesicAlgorithmBase::compute_propagated_parameters(Scalar pseudo_x, |
| Scalar pseudo_y, |
| Scalar begin, |
| Scalar end, |
| Scalar alpha, |
| Scalar L, |
| interval_pointer candidates, |
| Scalar d) |
| { |
| assert(pseudo_y <= 0.0); |
| assert(begin <= end); |
| assert(begin >= 0); |
|
|
| ++m_windows_propagation; |
|
|
| interval_pointer p = candidates; |
|
|
| Scalar sin_alpha = sin(alpha); |
| Scalar cos_alpha = cos(alpha); |
|
|
| |
| |
| Scalar L1 = compute_positive_intersection(begin, |
| pseudo_x, |
| pseudo_y, |
| sin_alpha, |
| cos_alpha); |
|
|
| if (L1 < 0 || L1 >= L) |
| return false; |
|
|
| Scalar L2 = compute_positive_intersection(end, |
| pseudo_x, |
| pseudo_y, |
| sin_alpha, |
| cos_alpha); |
|
|
| if (L2 < 0 || L2 >= L) |
| { |
| p->start() = L1; |
| p->stop() = L; |
| p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y; |
| p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y; |
| assert(p->pseudo_y() <= 0.0); |
|
|
| return true; |
| } |
| else |
| { |
| |
| p->start() = L1; |
| p->stop() = L2; |
| p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y; |
| p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y; |
| assert(p->pseudo_y() <= 0.0); |
|
|
| return true; |
| } |
| } |
|
|
| inline bool GeodesicAlgorithmBase::calculate_triangle_parameters(list_pointer &list, Triangle &Tri) |
| { |
| OpenMesh::HalfedgeHandle hf0 = this->mesh()->halfedge_handle(list->edge(), hfid0); |
| OpenMesh::HalfedgeHandle hf1 = this->mesh()->halfedge_handle(list->edge(), hfid1); |
| size_t adjface_size=0; |
| if(this->mesh()->face_handle(hf0).idx()>-1) |
| adjface_size++; |
| if(this->mesh()->face_handle(hf1).idx()>-1) |
| adjface_size++; |
|
|
| if (adjface_size > 1) |
| { |
| Tri.bottom_edge = list->edge(); |
|
|
| if (list == interval_list_0(Tri.bottom_edge)) |
| Tri.face = this->mesh()->face_handle(hf1); |
| else |
| Tri.face = this->mesh()->face_handle(hf0); |
|
|
| Tri.top_vertex = opposite_vertex(Tri.face, Tri.bottom_edge); |
| Tri.left_vertex = list->start_vertex(); |
| Tri.right_vertex = opposite_vertex(Tri.bottom_edge, Tri.left_vertex); |
|
|
| Tri.left_edge = next_edge(Tri.face, Tri.bottom_edge, Tri.left_vertex); |
| Tri.right_edge = next_edge(Tri.face, Tri.bottom_edge, Tri.right_vertex); |
|
|
| Tri.top_alpha = vertex_angle(Tri.face, Tri.top_vertex); |
| Tri.left_alpha = vertex_angle(Tri.face, Tri.left_vertex); |
| Tri.right_alpha = vertex_angle(Tri.face, Tri.right_vertex); |
|
|
| if (this->mesh()->face_handle(this->mesh()->halfedge_handle(Tri.left_edge, hfid0)) == Tri.face) |
| Tri.left_list = interval_list_0(Tri.left_edge); |
| else |
| Tri.left_list = interval_list_1(Tri.left_edge); |
|
|
| if (this->mesh()->face_handle(this->mesh()->halfedge_handle(Tri.right_edge, hfid0)) == Tri.face) |
| Tri.right_list = interval_list_0(Tri.right_edge); |
| else |
| Tri.right_list = interval_list_1(Tri.right_edge); |
|
|
| return false; |
| } |
| else |
| { |
| return true; |
| } |
| } |
|
|
|
|
| inline void GeodesicAlgorithmBase::build_adjacencies() |
| { |
| |
| std::vector<Scalar> total_vertex_angle(this->mesh()->n_vertices(), 0); |
| for(auto f_it = this->mesh()->faces_begin(); f_it != this->mesh()->faces_end(); ++f_it) |
| { |
| halfedge_handle hf0 = this->mesh()->halfedge_handle(*f_it); |
| vertex_pointer v0 = this->mesh()->from_vertex_handle(hf0); |
| vertex_pointer v1 = this->mesh()->to_vertex_handle(hf0); |
| vertex_pointer v2 = this->mesh()->to_vertex_handle(this->mesh()->next_halfedge_handle(hf0)); |
| Scalar l1 = (this->mesh()->point(v0) - this->mesh()->point(v1)).norm(); |
| Scalar l2 = (this->mesh()->point(v1) - this->mesh()->point(v2)).norm(); |
| Scalar l3 = (this->mesh()->point(v2) - this->mesh()->point(v0)).norm(); |
|
|
| total_vertex_angle[v0.idx()] += angle_from_edges(l2, l3, l1); |
| total_vertex_angle[v1.idx()] += angle_from_edges(l3, l1, l2); |
| total_vertex_angle[v2.idx()] += angle_from_edges(l1, l2, l3); |
| } |
|
|
| for(auto v_it = this->mesh()->vertices_begin(); v_it != this->mesh()->vertices_end(); ++v_it) |
| { |
| vertex_pointer v = *v_it; |
| this->mesh()->data(v).saddle_or_boundary = (total_vertex_angle[v.idx()] > 2.0*M_PI - 1e-5); |
| } |
|
|
| for(auto e_it = this->mesh()->edges_begin(); e_it != this->mesh()->edges_end(); ++e_it) |
| { |
| edge_pointer e = *e_it; |
| if(this->mesh()->is_boundary(e)) |
| { |
| halfedge_handle hf = this->mesh()->halfedge_handle(e, hfid0); |
| this->mesh()->data(this->mesh()->from_vertex_handle(hf)).saddle_or_boundary = true; |
| this->mesh()->data(this->mesh()->to_vertex_handle(hf)).saddle_or_boundary = true; |
| } |
| } |
| } |
|
|
|
|
| } |
|
|
| #endif |
|
|