diff --git a/Embedding.cc b/Embedding.cc index 94ff1d9ba97e861a42f4e508e3ee317b5f134875..19292e672ecf561ce8c01d897eb9b784c7301e8a 100644 --- a/Embedding.cc +++ b/Embedding.cc @@ -3,6 +3,9 @@ #include <QDebug> #include <random> +/*! + * \brief Embedding::Embedding + */ Embedding::Embedding() { qDebug() << "Start of MetaMesh ctor"; base_mesh_ = nullptr; @@ -10,6 +13,12 @@ Embedding::Embedding() { qDebug() << "Initialized MetaMesh"; } +/*! + * \brief Embedding::CopyInitialization initializes the meta mesh as a copy of the + * base mesh + * \param base_mesh + * \param meta_mesh + */ void Embedding::CopyInitialization(TriMesh &base_mesh, PolyMesh &meta_mesh) { qDebug() << "Copying the base mesh into the metamesh."; boundaries_ = false; @@ -92,7 +101,13 @@ void Embedding::CopyInitialization(TriMesh &base_mesh, PolyMesh &meta_mesh) { initial_triangulation_ = false; } -void Embedding::SelectionTriangulation(TriMesh& base_mesh, PolyMesh& meta_mesh, TraceType type) { +/*! + * \brief Embedding::SelectionTriangulation triangulate selected meta vertices + * \param base_mesh + * \param meta_mesh + * \param type + */ +void Embedding::SelectionTriangulation(TriMesh& base_mesh, PolyMesh& meta_mesh) { qDebug() << "Entering InitialTriangulation function."; boundaries_ = false; initial_triangulation_ = true; @@ -109,13 +124,21 @@ void Embedding::SelectionTriangulation(TriMesh& base_mesh, PolyMesh& meta_mesh, CopyInitialization(base_mesh, meta_mesh); return; } - TriangulationPipeline(meta_mesh_points, type); + TriangulationPipeline(meta_mesh_points); initial_triangulation_ = false; } -// 1 / ratio chance of a vertex being randomly selected as a meta vertex +/*! + * \brief Embedding::RandomTriangulation + * 1 / ratio chance of a vertex being randomly selected as a meta vertex + * \param base_mesh + * \param meta_mesh + * \param input + * \param rtype + * \param type + */ void Embedding::RandomTriangulation(TriMesh &base_mesh, PolyMesh &meta_mesh, double input, - RandomType rtype, TraceType type) { + RandomType rtype) { initial_triangulation_ = true; boundaries_ = false; base_mesh_ = &base_mesh; @@ -171,10 +194,10 @@ void Embedding::RandomTriangulation(TriMesh &base_mesh, PolyMesh &meta_mesh, dou } } else if (rtype == TOTAL) { while (meta_mesh_points.size()<input*10000) { - meta_mesh_points.push_back(base_mesh_->vertex_handle(dis1(gen))); + meta_mesh_points.push_back(base_mesh_->vertex_handle(static_cast<uint>(dis1(gen)))); } } - while (!TriangulationPipeline(meta_mesh_points, type)) { + while (!TriangulationPipeline(meta_mesh_points)) { meta_mesh_points.clear(); qDebug() << "Automatically remeshing"; meta_mesh_->clear(); @@ -185,19 +208,25 @@ void Embedding::RandomTriangulation(TriMesh &base_mesh, PolyMesh &meta_mesh, dou } } else if (rtype == TOTAL) { for (unsigned long i=0; i<input*10000; ++i) { - meta_mesh_points.push_back(base_mesh_->vertex_handle(dis1(gen))); + meta_mesh_points.push_back(base_mesh_->vertex_handle(static_cast<uint>(dis1(gen)))); } } } initial_triangulation_ = false; } +/*! + * \brief Embedding::TriangulationPipeline + * \param meta_mesh_points + * \param type + * \return + */ bool Embedding::TriangulationPipeline( - std::vector<OpenMesh::VertexHandle> meta_mesh_points, TraceType type) { + std::vector<OpenMesh::VertexHandle> meta_mesh_points) { debug_hard_stop_ = false; InitializeProperties(); CreateMetaMeshVertices(meta_mesh_points); - if (!TriangulateMetaMesh(type)) + if (!TriangulateMetaMesh()) return false; CleanUpBaseMesh(); TestHalfedgeConsistency(); @@ -205,6 +234,9 @@ bool Embedding::TriangulationPipeline( return true; } +/*! + * \brief Embedding::InitializeProperties + */ void Embedding::InitializeProperties() { base_mesh_->add_property(voronoiID_, "Voronoi area"); base_mesh_->add_property(bsplithandle_, "Vertex to collapse into, undefined if not introduced" @@ -219,6 +251,10 @@ void Embedding::InitializeProperties() { base_mesh_->add_property(halfedge_weight_, "Pointer from base he to meta heh"); } +/*! + * \brief Embedding::CreateMetaMeshVertices + * \param meta_mesh_points + */ void Embedding::CreateMetaMeshVertices(std::vector<OpenMesh::VertexHandle> meta_mesh_points) { qDebug() << "Start appointing BaseMesh properties:"; qDebug() << "is bv_connection_ valid? " << bv_connection_.is_valid(); @@ -246,7 +282,12 @@ void Embedding::CreateMetaMeshVertices(std::vector<OpenMesh::VertexHandle> meta_ qDebug() << "Finish appointing MetaMesh properties:"; } -bool Embedding::TriangulateMetaMesh(TraceType type) { +/*! + * \brief Embedding::TriangulateMetaMesh + * \param type + * \return + */ +bool Embedding::TriangulateMetaMesh() { OpenMesh::VPropHandleT<double> voronoidistance; OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh; OpenMesh::HPropHandleT<int> multiplicity_heh; @@ -254,30 +295,11 @@ bool Embedding::TriangulateMetaMesh(TraceType type) { base_mesh_->add_property(to_heh, "Incoming edge from the shortest path"); base_mesh_->add_property(multiplicity_heh, "Mark duplicate paths for elimination"); qDebug() << "Entering Delaunay:"; - if (!Delaunay(voronoidistance, to_heh, multiplicity_heh, type)) { + if (!Delaunay(voronoidistance, to_heh, multiplicity_heh)) { return false; } - switch (type) { - case IMPLICITDIJKSTRA : - qDebug() << "Entering Implicit Dijkstra Triangulation from Voronoi diagram"; - ImplicitDijkstra(voronoidistance, to_heh, multiplicity_heh); - //PreProcessEdges(); - //EliminateDuplicatePaths(voronoiID, multiplicity_heh); - break; - case A_STAR: - qDebug() << "Entering A* Triangulation:"; - A_StarTriangulation(type); - break; - case A_STAR_MIDPOINTS: - qDebug() << "Entering A* Triangulation with midpoints from Voronoi"; - A_StarTriangulation(type); - break; - } - - - // Finish implementing this later after trying a simpler base method - // EliminateDuplicatePaths(voronoiID, multiplicity_heh); + A_StarTriangulation(); base_mesh_->remove_property(voronoidistance); base_mesh_->remove_property(to_heh); @@ -285,6 +307,9 @@ bool Embedding::TriangulateMetaMesh(TraceType type) { return true; } +/*! + * \brief Embedding::PreProcessEdges global preprocessing + */ void Embedding::PreProcessEdges() { for (auto beh : base_mesh_->edges()) { auto bheh = base_mesh_->halfedge_handle(beh, 0); @@ -293,11 +318,19 @@ void Embedding::PreProcessEdges() { base_mesh_->update_normals(); } +/*! + * \brief Embedding::ProcessEdge local preprocessing + * \param meh + */ void Embedding::ProcessEdge(OpenMesh::EdgeHandle meh) { ProcessHalfedge(meta_mesh_->halfedge_handle(meh, 0)); ProcessHalfedge(meta_mesh_->halfedge_handle(meh, 1)); } +/*! + * \brief Embedding::ProcessVertex local preprocessing + * \param bvh + */ void Embedding::ProcessVertex(OpenMesh::VertexHandle bvh) { std::list<OpenMesh::HalfedgeHandle> splits; for (auto bvoheh : base_mesh_->voh_range(bvh)) { @@ -311,6 +344,10 @@ void Embedding::ProcessVertex(OpenMesh::VertexHandle bvh) { } } +/*! + * \brief Embedding::CleanupVertex perform legal base collapses around vertex bvh + * \param bvh + */ void Embedding::CleanupVertex(OpenMesh::VertexHandle bvh) { std::list<OpenMesh::VertexHandle> collapses; for (auto bvhit : base_mesh_->vv_range(bvh)) { @@ -327,6 +364,10 @@ void Embedding::CleanupVertex(OpenMesh::VertexHandle bvh) { } } +/*! + * \brief Embedding::CleanupFace cleans up the faces around mheh + * \param mheh + */ void Embedding::CleanupFace(OpenMesh::HalfedgeHandle mheh) { auto mhehiter = mheh; do { @@ -337,6 +378,10 @@ void Embedding::CleanupFace(OpenMesh::HalfedgeHandle mheh) { } while (mhehiter != mheh); } +/*! + * \brief Embedding::CleanupHalfedge cleans up mheh + * \param mheh + */ void Embedding::CleanupHalfedge(OpenMesh::HalfedgeHandle mheh) { auto linehalfedges = GetBaseHalfedges(mheh); auto mhehnext = meta_mesh_->next_halfedge_handle(mheh); @@ -365,6 +410,11 @@ void Embedding::CleanupHalfedge(OpenMesh::HalfedgeHandle mheh) { BaseGarbageCollection(); } +/*! + * \brief Embedding::ProcessNeighbors pre process the neighboring edges around mheh + * this is called before tracing + * \param meh + */ void Embedding::ProcessNeighbors(OpenMesh::EdgeHandle meh) { auto mheh0 = meta_mesh_->halfedge_handle(meh, 0); auto mheh1 = meta_mesh_->halfedge_handle(meh, 1); @@ -411,8 +461,12 @@ void Embedding::ProcessNeighbors(OpenMesh::EdgeHandle meh) { } } -// Iterate over the currently traced patch that mheh is part of and call pre-processing -// on all traversed meta halfedges +/*! + * \brief Embedding::ProcessFace + * Iterate over the currently traced patch that mheh is part of and call pre-processing + * on all traversed meta halfedges + * \param mheh + */ void Embedding::ProcessFace(OpenMesh::HalfedgeHandle mheh) { // Edge case: Trying to process the face of an mheh which has an adjacent valence 1 vertex // If mheh points towards that vertex there is no problem in the iteration @@ -425,11 +479,6 @@ void Embedding::ProcessFace(OpenMesh::HalfedgeHandle mheh) { // The previous solution works for edges next to valence 1 being traced but breaks face splits // so instead just find an adjacent traced edge and iterate from there; this works in both // cases. - /* - if (meta_mesh_->next_halfedge_handle(meta_mesh_->opposite_halfedge_handle(mheh)) == mheh) { - mheh = meta_mesh_->opposite_halfedge_handle(mheh); - } - */ auto mhehf = meta_mesh_->next_halfedge_handle(mheh); auto mhehb = meta_mesh_->next_halfedge_handle(meta_mesh_->opposite_halfedge_handle(mheh)); if (base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, mhehf))) { @@ -441,7 +490,6 @@ void Embedding::ProcessFace(OpenMesh::HalfedgeHandle mheh) { assert(initial_triangulation_); return; } - auto mhehtemp = mheh; do { if (base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, mhehtemp)) @@ -455,6 +503,10 @@ void Embedding::ProcessFace(OpenMesh::HalfedgeHandle mheh) { } while (mhehtemp != mheh); } +/*! + * \brief Embedding::ProcessHalfedge pre-process base halfedges around meta halfedge mheh + * \param mheh + */ void Embedding::ProcessHalfedge(OpenMesh::HalfedgeHandle mheh) { auto linehalfedges = GetBaseHalfedges(mheh); auto mhehnext = meta_mesh_->next_halfedge_handle(mheh); @@ -465,24 +517,22 @@ void Embedding::ProcessHalfedge(OpenMesh::HalfedgeHandle mheh) { for (auto blheh : linehalfedges) { for (auto bheh : LeftHalfCircle(blheh)) { ConditionalSplit(bheh); - /* - qDebug() << "Meta Halfedge: " << mheh.idx() << " -Base Halfedge: " << bheh.idx() - << " -FromVertex: " << base_mesh_->from_vertex_handle(bheh).idx() - << " -C: " - << base_mesh_->property(bv_connection_, base_mesh_->from_vertex_handle(bheh)).idx() - << " -ToVertex: " << base_mesh_->to_vertex_handle(bheh).idx() - << " -C: " - << base_mesh_->property(bv_connection_, base_mesh_->to_vertex_handle(bheh)).idx(); - */ } } } +/*! + * \brief Embedding::ConditionalSplit split bheh if permissible + * \param bheh + * \return + */ bool Embedding::ConditionalSplit(OpenMesh::HalfedgeHandle bheh) { // Don't split boundary halfedges for now since it is leading to crashes. // This could be enabled (I was in the middle of adding boundary split functionality) // But there is not enough time // TODO: remove this check and fix boundary splits in CollapseBaseHe and SplitBaseHe + // After testing quite a bit without splitting boundary halfedges this seems to be working quite + // well. Splitting boundary halfedges may not be necessary at all. if (base_mesh_->is_boundary(bheh) || base_mesh_->is_boundary(base_mesh_->opposite_halfedge_handle(bheh))) { return false; @@ -549,6 +599,12 @@ bool Embedding::ConditionalSplit(OpenMesh::HalfedgeHandle bheh) { return false; } +/*! + * \brief Embedding::LeftHalfCircle + * \param bheh + * \return the halfedges surrounding bheh in a left halfcircle and + * stopping when reaching a meta halfedge (used for preprocessing) + */ std::vector<OpenMesh::HalfedgeHandle> Embedding::LeftHalfCircle(OpenMesh::HalfedgeHandle bheh) { std::vector<OpenMesh::HalfedgeHandle> retval; retval.push_back(bheh); @@ -562,6 +618,11 @@ std::vector<OpenMesh::HalfedgeHandle> Embedding::LeftHalfCircle(OpenMesh::Halfed return retval; } +/*! + * \brief Embedding::GetBaseHalfedges + * \param mheh + * \return the base halfedges of meta halfedge mheh + */ std::vector<OpenMesh::HalfedgeHandle> Embedding::GetBaseHalfedges( OpenMesh::HalfedgeHandle mheh) { std::vector<OpenMesh::HalfedgeHandle> retval; @@ -576,15 +637,17 @@ std::vector<OpenMesh::HalfedgeHandle> Embedding::GetBaseHalfedges( return retval; } +/*! + * \brief Embedding::CleanUpBaseMesh collapses new bhehs where allowed and collects garbage it + * \param garbagecollection collect garbage if set to true + */ void Embedding::CleanUpBaseMesh(bool garbagecollection) { - //qDebug() << "Calling cleanup."; std::queue<OpenMesh::VertexHandle> hehqueue; for (auto bvh : base_mesh_->vertices()) { if (base_mesh_->is_valid_handle(bvh) && !base_mesh_->status(bvh).deleted() && base_mesh_->is_valid_handle(base_mesh_->property(bsplithandle_, bvh)) && !base_mesh_->status(base_mesh_->property(bsplithandle_, bvh)).deleted()) { - //qDebug() << "Cleanup loop bvh: " << bvh.idx(); auto bvhnew = ConditionalCollapse(bvh); if (base_mesh_->is_valid_handle(bvhnew)) { hehqueue.push(bvhnew); @@ -598,7 +661,6 @@ void Embedding::CleanUpBaseMesh(bool garbagecollection) { // this is tricky because there may be a few that _can't_ be merged no matter what unsigned long ctr = hehqueue.size()*2; while (!hehqueue.empty() && ctr > 0) { - //qDebug() << "hehqueue test " << ctr; auto bvh = hehqueue.front(); hehqueue.pop(); auto bvhnew = ConditionalCollapse(bvh); @@ -613,6 +675,12 @@ void Embedding::CleanUpBaseMesh(bool garbagecollection) { } } +/*! + * \brief Embedding::ConditionalCollapse collapse bvh into its bsplithandle_ halfedge + * if permissible + * \param bvh + * \return + */ OpenMesh::VertexHandle Embedding::ConditionalCollapse(OpenMesh::VertexHandle bvh) { auto bheh = base_mesh_->property(bsplithandle_, bvh); auto bheho = base_mesh_->opposite_halfedge_handle(bheh); @@ -722,9 +790,15 @@ OpenMesh::VertexHandle Embedding::ConditionalCollapse(OpenMesh::VertexHandle bv return OpenMesh::PolyConnectivity::InvalidVertexHandle; } -// Retain properties correctly while splitting halfedges and return the first half of the split -// edge, also marks new vertices introduced by the split with a handle to the vertex to collapse -// them into to undo the split. +/*! + * \brief Embedding::SplitBaseHe + * Retain properties correctly while splitting halfedges and return the first half of the split + * edge, also marks new vertices introduced by the split with a handle to the vertex to collapse + * them into to undo the split. + * \param bheh + * \return the halfedge starting at the from_vertex of bheh and pointing towards the new vertex + * resulting from the split. + */ OpenMesh::HalfedgeHandle Embedding::SplitBaseHe(OpenMesh::HalfedgeHandle bheh) { auto opp = base_mesh_->opposite_halfedge_handle(bheh); auto vertex_colors_pph = base_mesh_->vertex_colors_pph(); @@ -782,21 +856,14 @@ OpenMesh::HalfedgeHandle Embedding::SplitBaseHe(OpenMesh::HalfedgeHandle bheh) TriMesh::Point splitpoint = (base_mesh_->point(base_mesh_->from_vertex_handle(bheh)) + base_mesh_->point(base_mesh_->to_vertex_handle(bheh)) )/2.0; - //auto vh0 = base_mesh_->from_vertex_handle(bheh); - //auto vh1 = base_mesh_->to_vertex_handle(bheh); auto bvh = base_mesh_->split(base_mesh_->edge_handle(bheh), splitpoint); auto back = base_mesh_->next_halfedge_handle(prev); auto left = base_mesh_->next_halfedge_handle(back); auto front = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(left)); auto right = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(front)); - /* - qDebug() << vh.idx() << " - " << base_mesh_->to_vertex_handle(back).idx() - << " - " << base_mesh_->from_vertex_handle(bheh).idx() - << "=" << vh0.idx() - << " - " << base_mesh_->to_vertex_handle(bheh).idx() - << "=" << vh1.idx();*/ assert (bvh == base_mesh_->to_vertex_handle(back)); + if (lbound) { front = base_mesh_->next_halfedge_handle(back); right = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(front)); @@ -941,13 +1008,6 @@ OpenMesh::HalfedgeHandle Embedding::SplitBaseHe(OpenMesh::HalfedgeHandle bheh) if (!meta_mesh_->is_valid_handle(bhe_connection0)) { assert(!meta_mesh_->is_valid_handle(bhe_connection1)); - /* - qDebug() << "bv_connection_ valid: " << base_mesh_->is_valid_handle( - base_mesh_->property(bv_connection_, vh)); - for (auto voh_it : base_mesh_->voh_range(vh)) { - qDebug() << "voh: " << voh_it.idx() << " has a valid bhe_connection_: " << - base_mesh_->is_valid_handle(base_mesh_->property(bhe_connection_, voh_it)); - }*/ assert(!IsSectorBorder(bvh)); assert(ValidA_StarEdge(back, OpenMesh::PolyConnectivity::InvalidHalfedgeHandle)); @@ -980,7 +1040,6 @@ void Embedding::CollapseBaseHe(OpenMesh::HalfedgeHandle bheh) { assert(base_mesh_->is_valid_handle(bheh)); auto bvh0 = base_mesh_->from_vertex_handle(bheh); - auto bvh1 = base_mesh_->to_vertex_handle(bheh); auto bheho = base_mesh_->opposite_halfedge_handle(bheh); bool lbound = base_mesh_->is_boundary(bheh); @@ -1009,61 +1068,15 @@ void Embedding::CollapseBaseHe(OpenMesh::HalfedgeHandle bheh) { base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(bheho))); } if (debug_hard_stop_) return; - //qDebug() << "Calling base collapse"; - - // collapse - //LowLevelBaseCollapse(bheh); - /* Info dump - qDebug() << "Collapsing halfedge " << bheh.idx() << " from vertex " - << base_mesh_->from_vertex_handle(bheh).idx() << " is a meta vertex: " - << meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->from_vertex_handle(bheh))) << "; and to vertex " - << base_mesh_->to_vertex_handle(bheh).idx() << " is a meta vertex " - << meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->to_vertex_handle(bheh))) << "."; - */ base_mesh_->collapse(bheh); - - //BaseGarbageCollection(); - - // Tests, remove comment to test if needed later - /* - for (auto bhehit : base_mesh_->vih_range(bvh1)) { - assert(base_mesh_->is_valid_handle(bhehit)); - assert(!base_mesh_->status(bhehit).deleted()); - auto mheh = base_mesh_->property(bhe_connection_, bhehit); - if (meta_mesh_->is_valid_handle(mheh)) { - auto bhehc = meta_mesh_->property(mhe_connection_, mheh); - assert(base_mesh_->is_valid_handle(bhehc)); - if (base_mesh_->status(bhehc).deleted()) { - qDebug() << "Base halfedge" << bhehc.idx() << " is deleted."; - MarkVertex(base_mesh_->from_vertex_handle(bhehc)); - MarkVertex(base_mesh_->to_vertex_handle(bhehc)); - debug_hard_stop_=true; - return; - } - assert(!base_mesh_->status(bhehc).deleted()); - } - auto bhehn = base_mesh_->property(next_heh_, bhehit); - auto bhehno = base_mesh_->property(next_heh_, - base_mesh_->opposite_halfedge_handle(bhehit)); - if (base_mesh_->is_valid_handle(bhehn)) { - assert(!base_mesh_->status(bhehn).deleted()); - } - if (base_mesh_->is_valid_handle(bhehno)) { - assert(!base_mesh_->status(bhehno).deleted()); - assert(base_mesh_->is_valid_handle(base_mesh_->opposite_halfedge_handle(bhehno))); - assert(base_mesh_->is_valid_handle(base_mesh_->property(next_heh_, - base_mesh_->opposite_halfedge_handle(bhehno)))); - assert(!base_mesh_->status(base_mesh_->property(next_heh_, - base_mesh_->opposite_halfedge_handle(bhehno))).deleted()); - } - } - */ - //qDebug() << "Success"; } +/*! + * \brief Embedding::LowLevelBaseCollapse reimplemented collapse method on the base mesh, not sure + * if this is used at all? TODO: check if this needs deletion. + * \param bheh + */ void Embedding::LowLevelBaseCollapse(OpenMesh::HalfedgeHandle bheh) { // See PolyConnectivity::collapse and PolyConnectivity::collapse_edge OpenMesh::HalfedgeHandle h = bheh; @@ -1118,6 +1131,11 @@ void Embedding::LowLevelBaseCollapse(OpenMesh::HalfedgeHandle bheh) { // How to handle loops then? } +/*! + * \brief Embedding::AdjustPointersForBheCollapse lots of pointer operations to ensure a + * base collapse operation does not disrupt the embedding + * \param bheh + */ void Embedding::AdjustPointersForBheCollapse(OpenMesh::HalfedgeHandle bheh) { auto bheho = base_mesh_->opposite_halfedge_handle(bheh); @@ -1211,8 +1229,13 @@ void Embedding::AdjustPointersForBheCollapse(OpenMesh::HalfedgeHandle bheh) { assert(base_mesh_->property(bsplithandle_, base_mesh_->to_vertex_handle(bheh)) != bheho); } -// Takes two edges and transfers the properties of and pointers -// pointing to the first to the second if they're not empty. +/*! + * \brief Embedding::MergeProperties + * Takes two edges and transfers the properties of and pointers + * pointing to the first to the second if they're not empty. + * \param bheh0 + * \param bheh1 + */ void Embedding::MergeProperties(OpenMesh::HalfedgeHandle bheh0, OpenMesh::HalfedgeHandle bheh1) { auto bheh0o = base_mesh_->opposite_halfedge_handle(bheh0); @@ -1260,34 +1283,9 @@ void Embedding::MergeProperties(OpenMesh::HalfedgeHandle bheh0, base_mesh_->property(bhe_connection_, bheh1) = bhcprop0; base_mesh_->property(bhe_connection_, bheh1o) = bhcprop0o; - // faulty checks - /* - if (mhcprop0 == bheh0 && mhcprop0o == bheh0o) { - qDebug() << "This is not allowed to happen; a meta vertex is being collapsed away."; - assert(false); - } - */ - // check the sides if (!base_mesh_->is_valid_handle(nprop0o)) { assert(mhcprop0 == bheh0); - //assert(base_mesh_->is_valid_handle(nprop0)); - /* - if (!meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->from_vertex_handle(bheh0)))) { - debug_hard_stop_= true; - base_mesh_->status(bheh0).set_selected(true); - //base_mesh_->status(bheh1).set_selected(true); - qDebug() << "Error while merging properties; selecting edges bheh0 and bheh1. front"; - MarkVertex(base_mesh_->from_vertex_handle(bheh0)); - MarkVertex(base_mesh_->from_vertex_handle(bheh1)); - MarkVertex(base_mesh_->to_vertex_handle(bheh0)); - MarkVertex(base_mesh_->to_vertex_handle(bheh1)); - return; - } - */ - //assert(meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - // base_mesh_->from_vertex_handle(bheh0)))); meta_mesh_->property(mhe_connection_, bhcprop0) = bheh1; // if this is not the end of the edge fix the next_heh pointers } else { @@ -1302,23 +1300,6 @@ void Embedding::MergeProperties(OpenMesh::HalfedgeHandle bheh0, // repeat for the other side if (!base_mesh_->is_valid_handle(nprop0)) { assert(mhcprop0o == bheh0o); - //assert(base_mesh_->is_valid_handle(nprop0o)); - /* - if (!meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->to_vertex_handle(bheh0)))) { - debug_hard_stop_= true; - base_mesh_->status(bheh0).set_selected(true); - //base_mesh_->status(bheh1).set_selected(true); - qDebug() << "Error while merging properties; selecting edges bheh0 and bheh1. back"; - MarkVertex(base_mesh_->from_vertex_handle(bheh0)); - MarkVertex(base_mesh_->from_vertex_handle(bheh1)); - MarkVertex(base_mesh_->to_vertex_handle(bheh0)); - MarkVertex(base_mesh_->to_vertex_handle(bheh1)); - return; - } - */ - //assert(meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - // base_mesh_->from_vertex_handle(bheh0o)))); meta_mesh_->property(mhe_connection_, bhcprop0o) = bheh1o; } else { assert(base_mesh_->is_valid_handle(nprop0)); @@ -1338,8 +1319,8 @@ void Embedding::MergeProperties(OpenMesh::HalfedgeHandle bheh0, base_mesh_->property(bsplithandle_, base_mesh_->to_vertex_handle(bheh0)) = bheh1o; } - assert(wprop0 == wprop0o); - assert(wprop1 == wprop1o); + assert(static_cast<int>(wprop0) == static_cast<int>(wprop0o)); + assert(static_cast<int>(wprop1) == static_cast<int>(wprop1o)); base_mesh_->property(halfedge_weight_, bheh1) = std::min(wprop0, wprop1); base_mesh_->property(halfedge_weight_, bheh1o) = std::min(wprop0, wprop1); @@ -1402,10 +1383,17 @@ void Embedding::MergeProperties(OpenMesh::HalfedgeHandle bheh0, assert(!base_mesh_->status(bheh1o).deleted()); } +/*! + * \brief Embedding::Delaunay delaunay triangulation + * \param voronoidistance + * \param to_heh + * \param multiplicity_heh + * \param type + * \return true for success, false for failure + */ bool Embedding::Delaunay(OpenMesh::VPropHandleT<double> voronoidistance, OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::HPropHandleT<int> multiplicity_heh, - TraceType type) { + OpenMesh::HPropHandleT<int> multiplicity_heh) { for (auto bvh : base_mesh_->vertices()) { base_mesh_->property(voronoiID_, bvh) = OpenMesh::PolyConnectivity::InvalidVertexHandle; @@ -1438,34 +1426,20 @@ bool Embedding::Delaunay(OpenMesh::VPropHandleT<double> voronoidistance, auto metavh0 = base_mesh_->property(voronoiID_, vh0); auto metavh1 = base_mesh_->property(voronoiID_, vh1); auto metavh2 = base_mesh_->property(voronoiID_, vh2); - /* - uint boundaries = static_cast<uint>(base_mesh_->is_boundary( - meta_mesh_->property(mv_connection_, metavh0))); - boundaries += static_cast<uint>(base_mesh_->is_boundary( - meta_mesh_->property(mv_connection_, metavh1))); - boundaries += static_cast<uint>(base_mesh_->is_boundary( - meta_mesh_->property(mv_connection_, metavh2))); - */ if (metavh0 != metavh1 && metavh0 != metavh2 && metavh1 != metavh2) { - //qDebug() << "Adding a face"; auto mheh0 = FindHalfedge(bheh0); auto mheh1 = FindHalfedge(bheh1); auto mheh2 = FindHalfedge(bheh2); auto mf = AddFace({metavh0, metavh1, metavh2}, {mheh0, mheh1, mheh2}); - //qDebug() << "Done adding a face"; - SetFaceProperties(fh, mf, voronoidistance, to_heh, type); + SetFaceProperties(fh, mf); mheh0 = meta_mesh_->halfedge_handle(mf); mheh1 = meta_mesh_->next_halfedge_handle(mheh0); mheh2 = meta_mesh_->next_halfedge_handle(mheh1); - //qDebug() << "Calling Traverseborder"; SetBorderProperties(meta_mesh_->property(mhe_border_, mheh0), mheh0); - //qDebug() << "Calling Traverseborder"; SetBorderProperties(meta_mesh_->property(mhe_border_, mheh1), mheh1); - //qDebug() << "Calling Traverseborder"; SetBorderProperties(meta_mesh_->property(mhe_border_, mheh2), mheh2); } - //qDebug() << "Done setting new meta edge properties for current face."; } qDebug() << "Done adding all basic faces."; @@ -1478,7 +1452,6 @@ bool Embedding::Delaunay(OpenMesh::VPropHandleT<double> voronoidistance, << genus.at(static_cast<unsigned long>(mvh.idx())) << " perhaps you should choose different seed points."; return false; - //MarkVertex(meta_mesh_->property(mv_connection_, mvh)); } } } @@ -1487,7 +1460,6 @@ bool Embedding::Delaunay(OpenMesh::VPropHandleT<double> voronoidistance, qDebug() << "Collecting boundary faces."; for (auto mvh : meta_mesh_->vertices()) { if (base_mesh_->is_boundary(meta_mesh_->property(mv_connection_, mvh))) { - uint neighboringboundaries = 0; auto mheh = meta_mesh_->halfedge_handle(mvh); if (!meta_mesh_->is_valid_handle(mheh)) { TraverseBoundary(mvh); @@ -1538,12 +1510,14 @@ bool Embedding::Delaunay(OpenMesh::VPropHandleT<double> voronoidistance, if (boundaries_) { AddBoundaries(); } - return true; } -// Traverse a patch order and add all faces missed by the Voronoi triangulation to the -// meta mesh. +/*! + * \brief Embedding::TraverseBoundary traverse the boundary that mvh lies on and add faces + * along the boundary that were missed by the voronoi triangulation + * \param mvh + */ void Embedding::TraverseBoundary(OpenMesh::VertexHandle mvh) { assert(base_mesh_->is_boundary(meta_mesh_->property(mv_connection_, mvh))); OpenMesh::HalfedgeHandle bhehstart = OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; @@ -1601,17 +1575,31 @@ void Embedding::TraverseBoundary(OpenMesh::VertexHandle mvh) { } while (bhehcurr != bhehstart); } +/*! + * \brief Embedding::fact + * \param n + * \return n! + */ int Embedding::fact(int n) { return (n == 1 || n == 0) ? 1 : fact(n - 1) * n; } +/*! + * \brief Embedding::nCk + * \param n + * \param k + * \return nCk(n,k) + */ int Embedding::nCk(int n, int k) { return (fact(n)/(fact(k)*fact(n-k))); } -// V - E + F = g -// => g = V-E+F +/*! + * \brief Embedding::VoronoiGenus + * \return the vector with the geni (or euler characteristics? one of those) + * of the voronoi regions + */ std::vector<int> Embedding::VoronoiGenus() { // Initialize faces as 1 to make this work, disk topology std::vector<int> faces(meta_mesh_->n_vertices(), 0); @@ -1645,65 +1633,21 @@ std::vector<int> Embedding::VoronoiGenus() { for (unsigned long i=0; i<meta_mesh_->n_vertices(); ++i) { int g = vertices.at(i) - edges.at(i) + faces.at(i); genus.push_back(g); - /* - qDebug() << "Vertices: " << vertices.at(i) - << " Edges: " << edges.at(i) - << " Faces: " << faces.at(i) - << " Euler Characteristic: " << genus.at(i); - */ } return genus; } -int Embedding::FixMetaMeshConnectivity(OpenMesh::VertexHandle mvh) { - auto currmheh = meta_mesh_->halfedge_handle(mvh); - auto first = meta_mesh_->property(mhe_connection_, currmheh); - auto iter = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(first)); - int counter = 0; - std::vector<OpenMesh::HalfedgeHandle> borders; - do { - auto nextmheh = base_mesh_->property(bhe_connection_, iter); - if (meta_mesh_->is_valid_handle(nextmheh)) { - // If the meta connection does not correspond to the base connection, fix it. - if (nextmheh != meta_mesh_->opposite_halfedge_handle( - meta_mesh_->prev_halfedge_handle(currmheh))) { - meta_mesh_->set_next_halfedge_handle(meta_mesh_->opposite_halfedge_handle(nextmheh) - ,currmheh); - ++counter; - qDebug() << "Fixed connectivity of an edge"; - borders.push_back(meta_mesh_->opposite_halfedge_handle(nextmheh)); - } - currmheh = nextmheh; - } - iter = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(iter)); - } while (iter != first); - // Symmetry - //assert(counter%2 == 0); - //AddSelfEdges(borders, type); - - return counter/2; -} - -// In cases where a voronoi region has more than one border it needs edges from its meta -// vertex to itself for each pair of borders. Find and add those. -void Embedding::AddSelfEdges(std::vector<OpenMesh::HalfedgeHandle> borders) { - for (unsigned long i = 0; i < borders.size()/2; ++i) { - for (unsigned long j = 0; j<borders.size()-i-1; ++j) { - assert(meta_mesh_->to_vertex_handle(borders.at(j)) - == meta_mesh_->to_vertex_handle(borders.at(j+i+1))); - AddMetaEdge(borders.at(j), borders.at(j+i+1)); - borders.at(j) = base_mesh_->opposite_halfedge_handle( - base_mesh_->next_halfedge_handle(borders.at(j))); - } - } -} - +/*! + * \brief Embedding::SetFaceProperties link a base face with a meta face (connect their + * property handles etc.) + * \param bf + * \param mf + * \param voronoidistance + * \param to_heh + * \param type + */ void Embedding::SetFaceProperties(OpenMesh::FaceHandle bf, - OpenMesh::FaceHandle mf, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - TraceType type) { - //qDebug() << "Setting face properties"; + OpenMesh::FaceHandle mf) { auto bheh0 = base_mesh_->halfedge_handle(bf); auto bheh1 = base_mesh_->next_halfedge_handle(bheh0); auto bheh2 = base_mesh_->next_halfedge_handle(bheh1); @@ -1716,46 +1660,13 @@ void Embedding::SetFaceProperties(OpenMesh::FaceHandle bf, meta_mesh_->property(mhe_border_, mheh0) = bheh0; meta_mesh_->property(mhe_border_, mheh1) = bheh1; meta_mesh_->property(mhe_border_, mheh2) = bheh2; - - if (type == IMPLICITDIJKSTRA || type == A_STAR_MIDPOINTS) { - meta_mesh_->property(mhe_connection_, mheh0) = - FindMiddle(mheh0, voronoidistance, to_heh); - meta_mesh_->property(mhe_connection_, mheh1) = - FindMiddle(mheh1, voronoidistance, to_heh); - meta_mesh_->property(mhe_connection_, mheh2) = - FindMiddle(mheh2, voronoidistance, to_heh); - /* - meta_mesh_->property(mhe_connection_, meta_mesh_->opposite_halfedge_handle(mheh0)) - = base_mesh_->opposite_halfedge_handle( - meta_mesh_->property(mhe_connection_, mheh0)); - meta_mesh_->property(mhe_connection_, meta_mesh_->opposite_halfedge_handle(mheh1)) - = base_mesh_->opposite_halfedge_handle( - meta_mesh_->property(mhe_connection_, mheh1)); - meta_mesh_->property(mhe_connection_, meta_mesh_->opposite_halfedge_handle(mheh2)) - = base_mesh_->opposite_halfedge_handle( - meta_mesh_->property(mhe_connection_, mheh2)); - */ - } - - if (type == IMPLICITDIJKSTRA) { - base_mesh_->property(bhe_connection_, meta_mesh_->property(mhe_connection_, mheh0)) - = mheh0; - base_mesh_->property(bhe_connection_, base_mesh_->opposite_halfedge_handle( - meta_mesh_->property(mhe_connection_, mheh0))) - = meta_mesh_->opposite_halfedge_handle(mheh0); - base_mesh_->property(bhe_connection_, meta_mesh_->property(mhe_connection_, mheh1)) - = mheh1; - base_mesh_->property(bhe_connection_, base_mesh_->opposite_halfedge_handle( - meta_mesh_->property(mhe_connection_, mheh1))) - = meta_mesh_->opposite_halfedge_handle(mheh1); - base_mesh_->property(bhe_connection_, meta_mesh_->property(mhe_connection_, mheh2)) - = mheh2; - base_mesh_->property(bhe_connection_, base_mesh_->opposite_halfedge_handle( - meta_mesh_->property(mhe_connection_, mheh2))) - = meta_mesh_->opposite_halfedge_handle(mheh2); - } } +/*! + * \brief Embedding::CopyFaceProperties + * \param mfh + * \param boundaryborders + */ void Embedding::CopyFaceProperties(OpenMesh::FaceHandle mfh, std::vector<OpenMesh::HalfedgeHandle> boundaryborders) { auto mheh = meta_mesh_->halfedge_handle(mfh); @@ -1764,14 +1675,6 @@ void Embedding::CopyFaceProperties(OpenMesh::FaceHandle mfh, uint mfval = meta_mesh_->valence(mfh); for (uint i=0; i<boundaryborders.size(); ++i) { auto bhehb = boundaryborders.at(i); - /* - qDebug() << "mhehiter from: " << meta_mesh_->from_vertex_handle(mhehiter).idx() - << "to: " << meta_mesh_->to_vertex_handle(mhehiter).idx(); - qDebug() << "bb(" << i << ").vID from:" << base_mesh_->property(voronoiID_, - base_mesh_->from_vertex_handle(bhehb)).idx() << " to: " - << base_mesh_->property(voronoiID_, - base_mesh_->to_vertex_handle(bhehb)).idx(); - */ assert(meta_mesh_->from_vertex_handle(mhehiter) == base_mesh_->property(voronoiID_, base_mesh_->from_vertex_handle(bhehb))); assert(meta_mesh_->to_vertex_handle(mhehiter) @@ -1806,6 +1709,14 @@ void Embedding::CopyFaceProperties(OpenMesh::FaceHandle mfh, } while (mheh != mhehiter); } +/*! + * \brief Embedding::AddFace adds a meta face + * \param mvh vertices + * \param mheh halfedges, going mvh(i) -> mheh(i) -> mvh(i+1) + * Use the opposite halfedges of adjacent faces for these, or an invalid handle if they don't exist + * yet and in that case AddFace will make them. + * \return the facehandle + */ OpenMesh::FaceHandle Embedding::AddFace(std::vector<OpenMesh::VertexHandle> mvh, std::vector<OpenMesh::HalfedgeHandle> mheh) { assert(mvh.size() == mheh.size()); @@ -1814,14 +1725,6 @@ OpenMesh::FaceHandle Embedding::AddFace(std::vector<OpenMesh::VertexHandle> mvh, mheh.at(i) = meta_mesh_->new_edge(mvh.at(i), mvh.at((i+1)%mvh.size())); } } - /* - qDebug() << "Expected triangle: " << mvh0.idx() - << ", " << mvh1.idx() - << ", " << mvh2.idx() - << "Actual triangle: " << meta_mesh_->from_vertex_handle(mheh0).idx() - << ", " << meta_mesh_->from_vertex_handle(mheh1).idx() - << ", " << meta_mesh_->from_vertex_handle(mheh2).idx(); - */ for (uint i = 0; i<mheh.size(); ++i) { assert(meta_mesh_->from_vertex_handle(mheh.at(i)) == mvh.at(i)); assert(meta_mesh_->to_vertex_handle(mheh.at(i)) == mvh.at((i+1)%mvh.size())); @@ -1866,6 +1769,9 @@ OpenMesh::FaceHandle Embedding::AddFace(std::vector<OpenMesh::VertexHandle> mvh, return fnew; } +/*! + * \brief Embedding::AddBoundaries set meta properties and pointers for boundaries. + */ void Embedding::AddBoundaries() { for (auto mheh : meta_mesh_->halfedges()) { if (!meta_mesh_->is_valid_handle(meta_mesh_->next_halfedge_handle(mheh)) @@ -1879,6 +1785,12 @@ void Embedding::AddBoundaries() { } } +/*! + * \brief Embedding::FindHalfedge + * \param bheh bheh lying on a mheh + * \return the opposite meta halfedge of the meta halfedge bheh lies on, or nothing + * if this is invalid + */ OpenMesh::HalfedgeHandle Embedding::FindHalfedge(OpenMesh::HalfedgeHandle bheh) { auto oppmheh = base_mesh_->property(bhe_border_, base_mesh_->opposite_halfedge_handle(bheh)); if (!meta_mesh_->is_valid_handle(oppmheh)) { @@ -1888,6 +1800,9 @@ OpenMesh::HalfedgeHandle Embedding::FindHalfedge(OpenMesh::HalfedgeHandle bheh) } } +/*! + * \brief Embedding::VoronoiBorders iteration over all border regions + */ void Embedding::VoronoiBorders() { // Considering the inclusion of boundaries in the meta mesh a local border traversal // becomes more complicated since it would involve iterating around boundaries. @@ -1924,6 +1839,12 @@ void Embedding::VoronoiBorders() { } } +/*! + * \brief Embedding::SetBorderProperties iteration over one specific border region + * TODO: improve this for complex borders, those may break this function at the current state. + * \param bheh + * \param mheh + */ void Embedding::SetBorderProperties(OpenMesh::HalfedgeHandle bheh, OpenMesh::HalfedgeHandle mheh) { assert(base_mesh_->is_valid_handle(bheh)); @@ -1950,26 +1871,17 @@ void Embedding::SetBorderProperties(OpenMesh::HalfedgeHandle bheh, } } -void Embedding::ImplicitDijkstra(OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - qDebug() << "Starting implicit Dijkstra triangulation from Voronoi diagram"; - for (auto meh : meta_mesh_->edges()) { - auto mheh0 = meta_mesh_->halfedge_handle(meh, 0); - MarkPath(meta_mesh_->property(mhe_connection_, mheh0), mheh0, to_heh, - voronoidistance, multiplicity_heh); - } - base_mesh_->update_normals(); - qDebug() << "Finished implicit Dijkstra triangulation from Voronoi diagram"; -} - -void Embedding::A_StarTriangulation(TraceType type) { +/*! + * \brief Embedding::A_StarTriangulation + * \param type + */ +void Embedding::A_StarTriangulation() { for (auto mheh : meta_mesh_->halfedges()) { if (meta_mesh_->is_boundary(mheh) || meta_mesh_->is_boundary(meta_mesh_->opposite_halfedge_handle(mheh))) { if (debug_hard_stop_) return; - Trace(mheh, true, false, type); + Trace(mheh, true, false); } } for (auto mheh : meta_mesh_->halfedges()) { @@ -1981,7 +1893,7 @@ void Embedding::A_StarTriangulation(TraceType type) { && !meta_mesh_->is_boundary(meta_mesh_->to_vertex_handle(mheh))) { if (debug_hard_stop_) return; - Trace(mheh, true, false, type); + Trace(mheh, true, false); assert(base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, mheh))); } } @@ -2000,7 +1912,7 @@ void Embedding::A_StarTriangulation(TraceType type) { || meta_mesh_->is_boundary(meta_mesh_->to_vertex_handle(mheh))) { if (debug_hard_stop_) return; - Trace(mheh, false, false, type); + Trace(mheh, false, false); } } } @@ -2013,7 +1925,7 @@ void Embedding::A_StarTriangulation(TraceType type) { auto mheh1 = meta_mesh_->next_halfedge_handle(mheh0); while (mheh1 != mhehstart) { auto mhehnew = AddMetaEdge(mhehstart, mheh0); - Trace(mhehnew, false, false, type); + Trace(mhehnew, false, false); mheh0 = mheh1; mheh1 = meta_mesh_->next_halfedge_handle(mheh1); } @@ -2025,138 +1937,20 @@ void Embedding::A_StarTriangulation(TraceType type) { base_mesh_->update_normals(); } -OpenMesh::HalfedgeHandle Embedding::FindMiddle(OpenMesh::HalfedgeHandle metaheh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh) { - //qDebug() << "FindMiddle Start"; - auto baseheh = meta_mesh_->property(mhe_connection_, metaheh); - OpenMesh::HPropHandleT<bool> marked; - base_mesh_->add_property(marked, "Marked for Dijkstra traversal"); - - for (auto heh : base_mesh_->halfedges()) { - base_mesh_->property(marked, heh) = false; - } - - const double inf = std::numeric_limits<double>::infinity(); - double mindist = inf; - auto vid0 = meta_mesh_->from_vertex_handle(metaheh); - auto vid1 = meta_mesh_->to_vertex_handle(metaheh); - OpenMesh::HalfedgeHandle middleheh; - - assert (EligibleHalfedge(baseheh, vid0, vid1)); - while (base_mesh_->is_valid_handle(baseheh)) { - auto bvh0 = base_mesh_->from_vertex_handle(baseheh); - auto bvh1 = base_mesh_->to_vertex_handle(baseheh); - double newdistance = base_mesh_->property(voronoidistance, bvh0) - + base_mesh_->property(voronoidistance, bvh1) + base_mesh_->calc_edge_length(baseheh); - bool okayedge = true; - for (auto voheh : base_mesh_->voh_range(bvh0)) { - if (voheh != baseheh && - meta_mesh_->is_valid_handle(base_mesh_->property(bhe_connection_, voheh))) { - okayedge = false; - } - } - for (auto voheh : base_mesh_->voh_range(bvh1)) { - if (voheh != base_mesh_->opposite_halfedge_handle(baseheh) - && meta_mesh_->is_valid_handle(base_mesh_->property(bhe_connection_, voheh))) { - okayedge = false; - } - } - if (meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, bvh0)) || - meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, bvh1))) { - okayedge = true; - } - - if (okayedge && newdistance < mindist) { - mindist = newdistance; - middleheh = baseheh; - } - baseheh = DijkstraNextHeh(baseheh, vid0, vid1, marked); - } - - base_mesh_->remove_property(marked); - - // Since finding a middle halfedge separated from all other middle halfedges - // can't be easily dont in complex meshes simply create one in cases none exist - if (!base_mesh_->is_valid_handle(middleheh)) { - middleheh = CreateMiddle(meta_mesh_->property(mhe_connection_, metaheh) - ,voronoidistance, to_heh); - } - - assert(base_mesh_->is_valid_handle(middleheh)); - //qDebug() << "FindMiddle End"; - return middleheh; -} - -OpenMesh::HalfedgeHandle Embedding::CreateMiddle(OpenMesh::HalfedgeHandle bheh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh) { - - auto splitbheh0 = VoronoiSplit(bheh, to_heh, voronoidistance); - auto opp = base_mesh_->opposite_halfedge_handle(base_mesh_->next_halfedge_handle( - base_mesh_->opposite_halfedge_handle(base_mesh_->next_halfedge_handle(splitbheh0)))); - auto splitbheh1 = VoronoiSplit(opp, to_heh, voronoidistance); - auto newbheh = base_mesh_->next_halfedge_handle( - base_mesh_->opposite_halfedge_handle(base_mesh_->next_halfedge_handle(splitbheh1))); - - return newbheh; -} - -bool Embedding::EligibleHalfedge(OpenMesh::HalfedgeHandle baseheh, - OpenMesh::VertexHandle metavh0, - OpenMesh::VertexHandle metavh1) { - auto vid0 = base_mesh_->property(voronoiID_, base_mesh_->from_vertex_handle(baseheh)); - auto vid1 = base_mesh_->property(voronoiID_, base_mesh_->to_vertex_handle(baseheh)); - return (((vid0 == metavh0) && (vid1 == metavh1)) || ((vid0 == metavh1) && (vid1 == metavh0))); -} - -OpenMesh::HalfedgeHandle Embedding::DijkstraNextHeh(OpenMesh::HalfedgeHandle bheh, - OpenMesh::VertexHandle metavh0, - OpenMesh::VertexHandle metavh1, - OpenMesh::HPropHandleT<bool> marked) { - base_mesh_->property(marked, bheh) = true; - auto opp = base_mesh_->opposite_halfedge_handle(bheh); - base_mesh_->property(marked, opp) = true; - auto heh0 = base_mesh_->prev_halfedge_handle(bheh); - auto heh1 = base_mesh_->next_halfedge_handle(bheh); - auto heh2 = base_mesh_->prev_halfedge_handle(opp); - auto heh3 = base_mesh_->next_halfedge_handle(opp); - //qDebug() << EligibleHalfedge(bheh, metavh0, metavh1, voronoiID); - if (EligibleHalfedge(heh0, metavh0, metavh1) && - (base_mesh_->property(marked, heh0) == false)) { - //qDebug() << "1"; - return heh0; - } - if (EligibleHalfedge(heh1, metavh0, metavh1) && - (base_mesh_->property(marked, heh1) == false)) { - //qDebug() << "2"; - return heh1; - } - if (EligibleHalfedge(heh2, metavh0, metavh1) && - (base_mesh_->property(marked, heh2) == false)) { - //qDebug() << "3"; - return heh2; - } - if (EligibleHalfedge(heh3, metavh0, metavh1) && - (base_mesh_->property(marked, heh3) == false)) { - //qDebug() << "4"; - return heh3; - } - - return OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; -} - +/*! + * \brief Embedding::NaiveVoronoi build voronoi regions + * \param queue + * \param voronoidistance + * \param to_heh + */ void Embedding::NaiveVoronoi(std::queue<OpenMesh::VertexHandle> queue, OpenMesh::VPropHandleT<double> voronoidistance, OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh) { while (!queue.empty()) { auto vh = queue.front(); - //qDebug() << "Vertex ID: " << vh.idx(); - //qDebug() << "Voronoi ID: " << base_mesh_->property(voronoiID, vh).idx(); for (auto vvh : base_mesh_->vv_range(vh)){ if (!meta_mesh_->is_valid_handle(base_mesh_->property(voronoiID_, vvh))) { base_mesh_->property(voronoiID_, vvh) = base_mesh_->property(voronoiID_, vh); - //qDebug() << "Voronoi ID: " << base_mesh_->property(voronoiID, vh).idx(); base_mesh_->property(voronoidistance, vvh) = base_mesh_->property(voronoidistance, vh) + base_mesh_->calc_edge_length(base_mesh_->find_halfedge(vh,vvh)); base_mesh_->property(to_heh, vvh) = base_mesh_->find_halfedge(vh,vvh); @@ -2167,7 +1961,6 @@ void Embedding::NaiveVoronoi(std::queue<OpenMesh::VertexHandle> queue, if (newdist < base_mesh_->property(voronoidistance, vvh)) { base_mesh_->property(voronoidistance, vvh) = newdist; base_mesh_->property(voronoiID_, vvh) = base_mesh_->property(voronoiID_, vh); - //qDebug() << "Voronoi ID: " << base_mesh_->property(voronoiID, vh).idx(); base_mesh_->property(to_heh, vvh) = base_mesh_->find_halfedge(vh,vvh); queue.push(vvh); if (base_mesh_->property(voronoiID_, vvh) != base_mesh_->property(voronoiID_, vh)) { @@ -2179,329 +1972,14 @@ void Embedding::NaiveVoronoi(std::queue<OpenMesh::VertexHandle> queue, queue.pop(); } - /* Voronoi Triangulation Visualization with this - for (auto bvh : base_mesh_->vertices()) { - if (base_mesh_->is_valid_handle(base_mesh_->property(to_heh, bvh))) - base_mesh_->status(base_mesh_->property(to_heh, bvh)).set_selected(true); - } - */ - ColorizeVoronoiRegions(); } - -void Embedding::MarkPath(OpenMesh::HalfedgeHandle heh, OpenMesh::HalfedgeHandle metaeh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - - //qDebug() << "Entering MarkPathrecursive:"; - MarkPathRecursive(base_mesh_->from_vertex_handle(heh) - , base_mesh_->opposite_halfedge_handle(heh), metaeh, to_heh, - voronoidistance, multiplicity_heh); - - // middle halfedges are marked twice, avoid this - base_mesh_->property(multiplicity_heh, heh) -= 1; - base_mesh_->property(multiplicity_heh, base_mesh_->opposite_halfedge_handle(heh)) -= 1; - - //qDebug() << "Entering MarkPathrecursive:"; - MarkPathRecursive(base_mesh_->to_vertex_handle(heh), heh, - meta_mesh_->opposite_halfedge_handle(metaeh), to_heh, - voronoidistance, multiplicity_heh); -} - -void Embedding::MarkPathRecursive(OpenMesh::VertexHandle vh, OpenMesh::HalfedgeHandle toheh, - OpenMesh::HalfedgeHandle metaheh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - if (debug_hard_stop_) - return; - - if (NeedReadjusting(vh, to_heh)) { - ReadjustPath(vh, toheh, metaheh, to_heh, voronoidistance); - } - auto fromhehnext = base_mesh_->opposite_halfedge_handle(toheh); - - base_mesh_->property(multiplicity_heh, toheh) += 1; - base_mesh_->property(multiplicity_heh, fromhehnext) += 1; - - base_mesh_->property(bhe_connection_, toheh) = meta_mesh_->opposite_halfedge_handle(metaheh); - base_mesh_->property(bhe_connection_, fromhehnext) = metaheh; - if (base_mesh_->is_valid_handle((base_mesh_->property(bv_connection_, vh)))) { - //qDebug() << "Entering MarkPathrecursive if-statement:"; - base_mesh_->property(next_heh_, toheh) = OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; - meta_mesh_->property(mhe_connection_, metaheh) = fromhehnext; - } else { - //qDebug() << "Entering MarkPathrecursive else-statement:"; - // - // vh-1 -- fromheh --> vh -- fromhehnext --> vh1 - // vh-1 <-- tohehnext -- vh <-- toheh -- vh1 - // - // This covers everything except the last / first vertex and corresponding hes, - // those are covered in the if statement - // - auto fromheh = base_mesh_->property(to_heh, vh); - auto tohehnext = base_mesh_->opposite_halfedge_handle(fromheh); - base_mesh_->property(next_heh_, toheh) = tohehnext; - base_mesh_->property(next_heh_, fromheh) = fromhehnext; - auto nextvh = base_mesh_->to_vertex_handle(tohehnext); - MarkPathRecursive(nextvh, tohehnext, metaheh, to_heh, voronoidistance, multiplicity_heh); - } -} - -bool Embedding::NeedReadjusting(OpenMesh::VertexHandle bvh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh) { - //qDebug() << "1"; - // Case 1: Meta Vertex - if (meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, bvh))) { - return false; - } - - // This has to be the case given that bvh is not a meta vertex as checked in - // the previous if statement - assert(base_mesh_->is_valid_handle(base_mesh_->property(to_heh, bvh))); - - //qDebug() << "2"; - // Case 2: Points towards Meta Vertex - auto fromvh = base_mesh_->from_vertex_handle(base_mesh_->property(to_heh, bvh)); - if (meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, fromvh))) { - return false; - } - - //qDebug() << "3"; - // Case 3: Points towards Meta Edge - if (meta_mesh_->is_valid_handle(GetMetaEdge(fromvh))) - return true; - - // qDebug() << "4"; - // Case 4: Default - return false; -} - -void Embedding::ReadjustPath(OpenMesh::VertexHandle bvh, - OpenMesh::HalfedgeHandle toheh, - OpenMesh::HalfedgeHandle metaheh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance) { - //qDebug() << "ReadjustPath"; - const double inf = std::numeric_limits<double>::infinity(); - auto iter = base_mesh_->opposite_halfedge_handle(base_mesh_->property(to_heh, bvh)); - auto prevheh = base_mesh_->opposite_halfedge_handle(toheh); - auto newheh = iter; - int counter = 0; - auto region = base_mesh_->property(voronoiID_, bvh); - while (!meta_mesh_->is_valid_handle(base_mesh_->property(bhe_connection_, iter))) { - iter = base_mesh_->opposite_halfedge_handle(base_mesh_->next_halfedge_handle(iter)); - ++counter; - if (counter == 100) { - auto fromvh = base_mesh_->from_vertex_handle(base_mesh_->property(to_heh, bvh)); - qDebug() << "100 Loop iterations passed, likely stuck in endless loop."; - qDebug() << "Yet the vertex pointing towards bvh lies on a meta edge: " - << meta_mesh_->is_valid_handle(GetMetaEdge(fromvh)); - qDebug() << "bvh : " << bvh.idx() << " | toheh: " << toheh.idx() - << " ,marking the area in white."; - auto vertex_colors_pph = base_mesh_->vertex_colors_pph(); - base_mesh_->property(vertex_colors_pph, bvh) = ACG::Vec4f(0.0f, 0.0f, 0.0f, 1.0f); - for (auto vvh : base_mesh_->vv_range(bvh)) { - base_mesh_->property(vertex_colors_pph, vvh) = ACG::Vec4f(1.0f, 1.0f, 1.0f, 1.0f); - } - base_mesh_->status(toheh).set_selected(true); - debug_hard_stop_ = true; - return; - } - } - - auto meh = meta_mesh_->edge_handle(base_mesh_->property(bhe_connection_, iter)); - - // Edge case: Pointing towards the middle of a yet untraced meta edge during triangulation - // Such an edge will always lie between two voronoi regions and have meta->base connections - // but no base->meta connections. - // Simply evade this by finding the next best to_heh in the same region and rerunning - // readjustpath - if ((!base_mesh_->is_valid_handle(base_mesh_->property(next_heh_, iter)) - && !meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->to_vertex_handle(iter)))) - || (!base_mesh_->is_valid_handle(base_mesh_->property(next_heh_, - base_mesh_->opposite_halfedge_handle(iter))) - && !meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->from_vertex_handle(iter))))) { - qDebug() << "entering new if statement"; - double min = inf; - for (auto iheh : base_mesh_->vih_range(bvh)) { - if (base_mesh_->property(voronoiID_, base_mesh_->from_vertex_handle(iheh)) == region - && base_mesh_->property(voronoidistance, base_mesh_->from_vertex_handle(iheh)) < min - && GetMetaEdge(base_mesh_->from_vertex_handle(iter)) - != GetMetaEdge(base_mesh_->from_vertex_handle(iheh)) - && GetMetaEdge(base_mesh_->from_vertex_handle(iheh)) - != GetMetaEdge(base_mesh_->to_vertex_handle(iheh))) { - min = base_mesh_->property(voronoidistance, base_mesh_->from_vertex_handle(iheh)); - newheh = iheh; - } - } - base_mesh_->property(to_heh, bvh) = newheh; - ReadjustPath(bvh, toheh, metaheh, to_heh, voronoidistance); - return; - } - - // Edge case: Pointing towards itself - // This should only happen if the path has been previously readjusted, meaning there - // is a different edge nearby. Follow that edge instead and restart the function. - if (meh == GetMetaEdge(bvh)) { - qDebug() << "Edge pointing towards itself, readjusting."; - for (auto vvh : base_mesh_->vv_range(bvh)) { - auto beh = GetMetaEdge(vvh); - if (meta_mesh_->is_valid_handle(beh) && beh != meh) { - qDebug() << "Found a better edge"; - base_mesh_->property(to_heh, bvh) = base_mesh_->find_halfedge(vvh, bvh); - ReadjustPath(bvh, toheh, metaheh, to_heh, voronoidistance); - return; - } else { - qDebug() << "Couldn't find a better edge, this shouldn't happen"; - qDebug() << "Do nothing, look at the results, crash?"; - qDebug() << "bvh : " << bvh.idx() << " | toheh: " << toheh.idx() - << " ,marking the area in white."; - auto vertex_colors_pph = base_mesh_->vertex_colors_pph(); - base_mesh_->property(vertex_colors_pph, bvh) = ACG::Vec4f(0.0f, 0.0f, 0.0f, 1.0f); - for (auto vvh : base_mesh_->vv_range(bvh)) { - base_mesh_->property(vertex_colors_pph, vvh) = ACG::Vec4f(1.0f, 1.0f, 1.0f, 1.0f); - } - base_mesh_->status(toheh).set_selected(true); - debug_hard_stop_ = true; - return; - //assert(0); - } - } - } - - //assert(meh != GetMetaEdge(bvh)); - // If the blocking path is on the right - if (meta_mesh_->from_vertex_handle(base_mesh_->property(bhe_connection_, iter)) - == meta_mesh_->from_vertex_handle(metaheh)) { - //qDebug() << "Right Start"; - newheh = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(newheh)); - while (GetMetaEdge(base_mesh_->to_vertex_handle(newheh)) == meh - && newheh != prevheh) { - newheh = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(newheh)); - } - // Case: cornered by another edge, follow in between this edge itself and - // the cornering edge, then newheh = maxheh - - if (meta_mesh_->is_valid_handle(GetMetaEdge(base_mesh_->to_vertex_handle(newheh))) || - region != base_mesh_->property(voronoiID_, base_mesh_->to_vertex_handle(newheh))) { - //qDebug() << "Split"; - auto splitedge = base_mesh_->prev_halfedge_handle( - base_mesh_->opposite_halfedge_handle(newheh)); - newheh = VoronoiSplit(splitedge, to_heh, voronoidistance); - newheh = base_mesh_->next_halfedge_handle(newheh); - } else { - newheh = base_mesh_->opposite_halfedge_handle(newheh); - } - //qDebug() << "Right End"; - // If the blocking path is on the left - } else if (meta_mesh_->to_vertex_handle(base_mesh_->property(bhe_connection_, iter)) - == meta_mesh_->from_vertex_handle(metaheh)) { - //qDebug() << "Left Start"; - newheh = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(newheh)); - while (GetMetaEdge(base_mesh_->to_vertex_handle(newheh)) == meh - && newheh != prevheh) { - newheh = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(newheh)); - } - // Case: cornered by another edge, follow in between this edge itself and - // the cornering edge, then newheh = maxheh - - if (meta_mesh_->is_valid_handle(GetMetaEdge(base_mesh_->to_vertex_handle(newheh))) || - region != base_mesh_->property(voronoiID_, base_mesh_->to_vertex_handle(newheh))) { - //qDebug() << "Split"; - auto splitedge = base_mesh_->opposite_halfedge_handle( - base_mesh_->next_halfedge_handle(newheh)); - newheh = VoronoiSplit(splitedge, to_heh, voronoidistance); - newheh = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle( - base_mesh_->opposite_halfedge_handle(newheh))); - } else { - newheh = base_mesh_->opposite_halfedge_handle(newheh); - } - //qDebug() << "Left End"; - // The blocking path is neither left nor right. This can happen if it is not directly - // connected to the meta edge being triangulated. How to handle this? - // Should not happen anymore now that voronoiID is put into consideration - } else { - qDebug() << "TODO: Figure out what to do in this case"; - assert(base_mesh_->is_valid_handle(bvh)); - assert(base_mesh_->is_valid_handle(newheh)); - qDebug() << "Vertex: " << bvh.idx() << " Halfedge: " << newheh.idx() - << " ,marking the area in white."; - auto vertex_colors_pph = base_mesh_->vertex_colors_pph(); - base_mesh_->property(vertex_colors_pph, bvh) = ACG::Vec4f(0.0f, 0.0f, 0.0f, 1.0f); - for (auto vvh : base_mesh_->vv_range(bvh)) { - base_mesh_->property(vertex_colors_pph, vvh) = ACG::Vec4f(1.0f, 1.0f, 1.0f, 1.0f); - } - base_mesh_->status(iter).set_selected(true); - qDebug() << "Current Meta Edge going from vertices " - << base_mesh_->to_vertex_handle(metaheh).idx() - << " to " - << base_mesh_->from_vertex_handle(metaheh).idx(); - qDebug() << "Meta edge blocking the way going from vertices " - << meta_mesh_->to_vertex_handle(base_mesh_->property(bhe_connection_, iter)).idx() - << " to " - << meta_mesh_->from_vertex_handle(base_mesh_->property(bhe_connection_, iter)).idx(); - debug_hard_stop_ = true; - return; - } - if (base_mesh_->is_valid_handle(newheh)) { - base_mesh_->property(to_heh, bvh) = newheh; - //qDebug() << "Path Changed"; - } else { - qDebug() << "Invalid newheh, this should not happen."; - } -} - -OpenMesh::HalfedgeHandle Embedding::VoronoiSplit(OpenMesh::HalfedgeHandle bheh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance) { - //base_mesh_->property(voronoiID, base_mesh_->to_vertex_handle(splitbheh0)) - // = base_mesh_->property(voronoiID, base_mesh_->to_vertex_handle(bheh)); - auto bvh0 = base_mesh_->from_vertex_handle(bheh); - auto bvh1 = base_mesh_->to_vertex_handle(bheh); - bool change0 = false; - bool change1 = false; - auto bheh0 = base_mesh_->property(to_heh, bvh0); - auto bheh1 = base_mesh_->property(to_heh, bvh1); - if (bheh0 == base_mesh_->opposite_halfedge_handle(bheh)) { - change0 = true; - } - if (bheh1 == bheh) { - change1 = true; - } - - auto region = base_mesh_->property(voronoiID_, base_mesh_->from_vertex_handle(bheh)); - auto newbheh = SplitBaseHe(bheh); - - // abuse the to_heh property to point to the split edge regardless of shortest path - // similarly always take the voronoidistance of that direction - auto back = base_mesh_->opposite_halfedge_handle(newbheh); - base_mesh_->property(voronoidistance, base_mesh_->to_vertex_handle(newbheh)) - = base_mesh_->calc_edge_length(back) + - base_mesh_->property(voronoidistance, base_mesh_->to_vertex_handle(back)); - base_mesh_->property(voronoiID_, base_mesh_->to_vertex_handle(newbheh)) - = base_mesh_->property(voronoiID_, base_mesh_->to_vertex_handle(back)); - base_mesh_->property(to_heh, base_mesh_->to_vertex_handle(newbheh)) - = newbheh; - - base_mesh_->property(bv_connection_, base_mesh_->to_vertex_handle(newbheh)) - = OpenMesh::PolyConnectivity::InvalidVertexHandle; - - if (change0) { - base_mesh_->property(to_heh, bvh0) = base_mesh_->next_halfedge_handle( - base_mesh_->opposite_halfedge_handle(base_mesh_->next_halfedge_handle(newbheh))); - } - if (change1) { - base_mesh_->property(to_heh, bvh1) = base_mesh_->opposite_halfedge_handle(newbheh); - } - - return newbheh; -} - +/*! + * \brief Embedding::GetMetaEdge + * \param bvh + * \return the meta edge bvh lies on or InvalidHandle if it lies on none + */ OpenMesh::EdgeHandle Embedding::GetMetaEdge(OpenMesh::VertexHandle bvh) { if(meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, bvh))) { //qDebug() << "Called GetMetaEdge on a Meta Vertex"; @@ -2516,7 +1994,11 @@ OpenMesh::EdgeHandle Embedding::GetMetaEdge(OpenMesh::VertexHandle bvh) { return OpenMesh::PolyConnectivity::InvalidEdgeHandle; } -// Returns the log of the product of edge weights of the base halfedges in mheh +/*! + * \brief Embedding::MetaHalfedgeWeight + * \param mheh + * \return the log of the product of edge weights of the base halfedges in mheh + */ double Embedding::MetaHalfedgeWeight(OpenMesh::HalfedgeHandle mheh) { double weight = 0.0; std::vector<OpenMesh::HalfedgeHandle> hes = GetBaseHalfedges(mheh); @@ -2526,7 +2008,11 @@ double Embedding::MetaHalfedgeWeight(OpenMesh::HalfedgeHandle mheh) { return weight; } -// Vertex weight based on halfedge weight of outgoing base halfedges +/*! + * \brief Embedding::MetaVertexWeight + * \param mvh + * \return Vertex weight based on halfedge weight of outgoing base halfedges + */ double Embedding::MetaVertexWeight(OpenMesh::VertexHandle mvh) { double weight = 0.0; for (auto moh : meta_mesh_->voh_range(mvh)) { @@ -2536,6 +2022,11 @@ double Embedding::MetaVertexWeight(OpenMesh::VertexHandle mvh) { return weight; } +/*! + * \brief Embedding::CalculateEdgeLength + * \param mheh + * \return edge length of mheh + */ double Embedding::CalculateEdgeLength(OpenMesh::HalfedgeHandle mheh) { assert(meta_mesh_->is_valid_handle(mheh)); auto bheh = meta_mesh_->property(mhe_connection_, mheh); @@ -2549,14 +2040,24 @@ double Embedding::CalculateEdgeLength(OpenMesh::HalfedgeHandle mheh) { return length; } +/*! + * \brief Embedding::CalculateEdgeLength + * \param meh + * \return edge length of meh + */ double Embedding::CalculateEdgeLength(OpenMesh::EdgeHandle meh) { return CalculateEdgeLength(meta_mesh_->halfedge_handle(meh, 0)); } -// Calculates the length mheh has after rotation. -// This method is only safe if the incident faces of mheh are triangles -// mheh will also be retraced in the process (avoiding this would be difficult -// without changing a lot of code and removing base mesh cleanup operations) +/*! + * \brief Embedding::CalculateFlippedEdgeLength + * Calculates the length mheh has after rotation. + * This method is only safe if the incident faces of mheh are triangles + * mheh will also be retraced in the process (avoiding this would be difficult + * without changing a lot of code and removing base mesh cleanup operations) + * \param mheh + * \return length of flipped mheh + */ double Embedding::CalculateFlippedEdgeLength(OpenMesh::HalfedgeHandle mheh) { Rotate(meta_mesh_->edge_handle(mheh)); double length = CalculateEdgeLength(mheh); @@ -2565,11 +2066,21 @@ double Embedding::CalculateFlippedEdgeLength(OpenMesh::HalfedgeHandle mheh) { return length; } +/*! + * \brief Embedding::CalculateFlippedEdgeLength + * \param meh + * \return length of flipped mehs + */ double Embedding::CalculateFlippedEdgeLength(OpenMesh::EdgeHandle meh) { return CalculateFlippedEdgeLength(meta_mesh_->halfedge_handle(meh, 0)); } -// Delete all meta mesh face handles with valence <3 so that OpenFlipper can display it +/*! + * \brief Embedding::CleanMetaMesh + * Delete all meta mesh face handles with valence <3 so that OpenFlipper can display it + * Not recommended outside of debugging since behavior afterwards is undefined. This only + * serves for visualization of strange edge cases. + */ void Embedding::CleanMetaMesh() { for (auto mfh : meta_mesh_->faces()) { auto mheh = meta_mesh_->halfedge_handle(mfh); @@ -2593,6 +2104,12 @@ void Embedding::CleanMetaMesh() { } } +/*! + * \brief Embedding::MetaGarbageCollection + * \param vh_update + * \param heh_update + * \param fh_update + */ void Embedding::MetaGarbageCollection(std::vector<OpenMesh::VertexHandle*> vh_update, std::vector<OpenMesh::HalfedgeHandle*> heh_update, std::vector<OpenMesh::FaceHandle*> fh_update) @@ -2611,6 +2128,12 @@ void Embedding::MetaGarbageCollection(std::vector<OpenMesh::VertexHandle*> vh_up meta_mesh_->garbage_collection(vh_update, heh_update, fh_update); } +/*! + * \brief Embedding::BaseGarbageCollection + * \param vh_update + * \param heh_update + * \param fh_update + */ void Embedding::BaseGarbageCollection(std::vector<OpenMesh::VertexHandle*> vh_update, std::vector<OpenMesh::HalfedgeHandle*> heh_update, std::vector<OpenMesh::FaceHandle*> fh_update) @@ -2676,47 +2199,22 @@ void Embedding::BaseGarbageCollection(std::vector<OpenMesh::VertexHandle*> vh_up base_mesh_->remove_property(next_heh_temp); } -/* -void Embedding::EliminateDuplicatePaths( - OpenMesh::VPropHandleT<OpenMesh::VertexHandle> voronoiID, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - for (auto mheh : meta_mesh_->halfedges()) { - TraversePath(mheh, voronoiID, multiplicity_heh); - } -} - -void Embedding::TraversePath(OpenMesh::HalfedgeHandle mheh, - OpenMesh::VPropHandleT<OpenMesh::VertexHandle> voronoiID, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - auto bheh = meta_mesh_->property(mhe_connection_, mheh); - if (base_mesh_->property(multiplicity_heh, bheh) > 1) { - auto leftheh = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(bheh)); - auto rightheh = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(bheh)); - if (base_mesh_->property(multiplicity_heh, leftheh) <= 1) { - LeftTraversal(leftheh, bheh, mheh, voronoiID, multiplicity_heh); - } else if (base_mesh_->property(multiplicity_heh, rightheh) <= 1) { - RightTraversal(rightheh, bheh, mheh, voronoiID, multiplicity_heh); - } else { - BaseSplit(leftheh, bheh); - LeftTraversal(leftheh, bheh, mheh, voronoiID, multiplicity_heh); - } - } else { - auto nextbheh = base_mesh_->property(next_heh_, bheh); - MiddleTraversal(nextbheh, mheh, voronoiID, multiplicity_heh); - } -} -*/ - +/*! + * \brief Embedding::ColorizeMetaMesh + */ void Embedding::ColorizeMetaMesh() { - /*/ + /*/ enable this to mark all meta mesh vertices in the base mesh ColorizeMetaMeshVertices(); //*/ ColorizeMetaEdges(); - /*/ + /*/ enable this to mark all voronoi borders in the base mesh ColorizeBorders(); //*/ } +/*! + * \brief Embedding::ColorizeMetaMeshVertices + */ void Embedding::ColorizeMetaMeshVertices() { if (!debug_hard_stop_) { for (auto bvh : base_mesh_->vertices()) { @@ -2729,6 +2227,9 @@ void Embedding::ColorizeMetaMeshVertices() { } } +/*! + * \brief Embedding::ColorizeMetaEdges + */ void Embedding::ColorizeMetaEdges() { //* draw_.clear(); @@ -2761,7 +2262,7 @@ void Embedding::ColorizeMetaEdges() { } } } - /*/ + /*/ Alternative: selection instead of colorizing. for (auto bheh : base_mesh_->halfedges()) { base_mesh_->status(bheh).set_selected(false); } @@ -2772,7 +2273,9 @@ void Embedding::ColorizeMetaEdges() { //*/ } - +/*! + * \brief Embedding::ColorizeVoronoiRegions + */ void Embedding::ColorizeVoronoiRegions() { auto vertex_colors_pph = base_mesh_->vertex_colors_pph(); auto colorgenerator = new ACG::HaltonColors(); @@ -2789,8 +2292,11 @@ void Embedding::ColorizeVoronoiRegions() { } } +/*! + * \brief Embedding::ColorizeBorders + */ void Embedding::ColorizeBorders() { - /* + /* Comments: Switch the code to these to colorize with haltoncolors instead of selecting. auto halfedge_colors_pph = base_mesh_->halfedge_colors_pph(); auto colorgenerator = new ACG::HaltonColors(); */ @@ -2820,7 +2326,10 @@ void Embedding::ColorizeBorders() { } } - +/*! + * \brief Embedding::TestHalfedgeConsistency expensive test, will also only work in debug mode. + * Could probably be deleted but I'll leave it here just in case. + */ void Embedding::TestHalfedgeConsistency() { for (auto eh : base_mesh_->edges()) { auto heh0 = base_mesh_->halfedge_handle(eh, 0); @@ -2833,8 +2342,18 @@ void Embedding::TestHalfedgeConsistency() { } } +/*! + * \brief Embedding::Trace Most important function: Traces a meta edge into the base mesh + * \param mheh the meta edge to be traced + * \param cleanup switch: cleanup after tracing or not + * \param mark_trace switch: mark the trace or not + * \param facetype preprocessedface or not? Current implementation calls the pre-processing + * in Trace itself. UNPROCESSEDFACE should call a trace method that does its own base edge + * splits where needed: this is not implemented yet. + * TODO: Implement Advanced trace or remove the switch. + */ void Embedding::Trace(OpenMesh::HalfedgeHandle mheh, bool cleanup, bool mark_trace, - TraceType tracetype, TraceFaceAttr facetype) { + TraceFaceAttr facetype) { auto bheh = meta_mesh_->property(mhe_connection_, mheh); if (base_mesh_->is_valid_handle(bheh) && base_mesh_->property(bhe_connection_, bheh) == mheh) { @@ -2850,29 +2369,37 @@ void Embedding::Trace(OpenMesh::HalfedgeHandle mheh, bool cleanup, bool mark_tra AdvancedTrace(mheh); break; case PREPROCESSEDFACE : - //qDebug() << "Entering SimpleTrace"; - if (tracetype == A_STAR) { - SimpleTrace(mheh, cleanup, mark_trace); - } else if (tracetype == A_STAR_MIDPOINTS) { - SimpleMidpointTrace(mheh, mark_trace); - } + SimpleTrace(mheh, cleanup, mark_trace); break; } } } -// Retraces the given meta halfedge +/*! + * \brief Embedding::Retrace + * Retraces the given meta halfedge + * \param mheh + * \param cleanup + * \param mark_trace + * \param facetype + */ void Embedding::Retrace(OpenMesh::HalfedgeHandle mheh, bool cleanup, bool mark_trace, - TraceType tracetype, TraceFaceAttr facetype) { + TraceFaceAttr facetype) { if (!meta_mesh_->is_valid_handle(mheh) || meta_mesh_->status(mheh).deleted()) { qDebug() << "Invalid or deleted halfedge mheh cannot be retraced"; return; } RemoveMetaEdgeFromBaseMesh(mheh); - Trace(mheh, cleanup, mark_trace, tracetype, facetype); + Trace(mheh, cleanup, mark_trace, facetype); } +/*! + * \brief Embedding::BoundaryTrace Trace a boundary edge. This is a special case but also + * much easier since the meta edge must then also lie on the boundary by definition. + * \param mheh + * \param mark_trace + */ void Embedding::BoundaryTrace(OpenMesh::HalfedgeHandle mheh, bool mark_trace) { //qDebug() << "Tracing boundary halfedge mheh " << mheh.idx(); // align the edge along the boundary @@ -2895,10 +2422,16 @@ void Embedding::BoundaryTrace(OpenMesh::HalfedgeHandle mheh, bool mark_trace) { return; } + if (mark_trace) { + base_mesh_->status(bheh).set_selected(true); + } std::vector<OpenMesh::HalfedgeHandle> path = {bheh}; while (!meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, base_mesh_->to_vertex_handle(bheh)))) { bheh = base_mesh_->next_halfedge_handle(bheh); + if (mark_trace) { + base_mesh_->status(bheh).set_selected(true); + } assert(base_mesh_->is_boundary(bheh)); path.push_back(bheh); //base_mesh_->status(bheh).set_selected(true); @@ -2913,6 +2446,12 @@ void Embedding::BoundaryTrace(OpenMesh::HalfedgeHandle mheh, bool mark_trace) { } } +/*! + * \brief Embedding::SimpleTrace Trace function, traces mheh. + * \param mheh + * \param cleanup + * \param mark_trace + */ void Embedding::SimpleTrace(OpenMesh::HalfedgeHandle mheh, bool cleanup, bool mark_trace) { //qDebug() << "Entering A*"; ProcessFace(mheh); @@ -2938,31 +2477,30 @@ void Embedding::SimpleTrace(OpenMesh::HalfedgeHandle mheh, bool cleanup, bool ma //base_mesh_->update_normals(); } -void Embedding::SimpleMidpointTrace(OpenMesh::HalfedgeHandle mheh, bool mark_trace) { - auto midheh0 = meta_mesh_->property(mhe_connection_, mheh); - if (IsSectorBorder(base_mesh_->from_vertex_handle(midheh0))) { - SimpleTrace(mheh); - } else { - auto midheh1 = base_mesh_->next_halfedge_handle( - base_mesh_->opposite_halfedge_handle(midheh0)); - auto bheh = FindA_StarStartingHalfedges(mheh); - auto path0 = A_StarBidirectional(bheh.first, midheh0, mark_trace, mheh); - auto path1 = A_StarBidirectional(midheh1, bheh.second, mark_trace, mheh); - path0.insert(path0.end(), path1.begin(), path1.end()); - if (!path0.empty()) - InsertPath(mheh, path0); - ProcessEdge(meta_mesh_->edge_handle(mheh)); - base_mesh_->update_normals(); - } -} - +/*! + * \brief Embedding::AdvancedTrace + * Unimplemented method. This Trace method should handle all neccessary split operations + * inside the sector it traces in by itself. I will leave this here since implementing it + * used to be an idea, but there was no time left. + * TODO: Implement this + * \param mheh + */ void Embedding::AdvancedTrace(OpenMesh::HalfedgeHandle mheh) { - + meta_mesh_->status(mheh).deleted(); } -// See these: -// https://en.wikipedia.org/wiki/A*_search_algorithm -// https://www.cs.princeton.edu/courses/archive/spr06/cos423/Handouts/EPP%20shortest%20path%20algorithms.pdf +/*! + * \brief Embedding::A_StarBidirectional Bidirectional A* Algorithm to find the + * best path quickly, see these: + * https://en.wikipedia.org/wiki/A*_search_algorithm + * https://www.cs.princeton.edu/courses/archive/spr06/cos423/Handouts/EPP%20shortest%20path%20algorithms.pdf + * \param bheh0 Starting halfedge 0 found by FindA_StarStartingHalfedges + * \param bheh1 Starting halfedge 1 found by FindA_StarStartingHalfedges + * \param mark_trace mark the trace y/n? + * \param mheh meta halfedge to be traced + * \return a vector of ordered base halfedges representing the mheh. these still + * need to be input and their pointers adjusted afterwards. + */ std::vector<OpenMesh::HalfedgeHandle> Embedding::A_StarBidirectional( OpenMesh::HalfedgeHandle bheh0, OpenMesh::HalfedgeHandle bheh1, bool mark_trace, OpenMesh::HalfedgeHandle mheh) { @@ -2971,20 +2509,13 @@ std::vector<OpenMesh::HalfedgeHandle> Embedding::A_StarBidirectional( base_mesh_->status(bheh).set_selected(false); } } - //qDebug() << "A_Star Vertex 1: " << base_mesh_->from_vertex_handle(bheh0).idx(); - //qDebug() << "A_Star Vertex 2: " << base_mesh_->from_vertex_handle(bheh1).idx(); - //assert(!IsSectorBorder(base_mesh_->to_vertex_handle(bheh0))); - //assert(!IsSectorBorder(base_mesh_->to_vertex_handle(bheh1))); auto bvh0 = base_mesh_->from_vertex_handle(bheh0); auto bvh1 = base_mesh_->from_vertex_handle(bheh1); - //assert(IsSectorBorder(bvh0)); - //assert(IsSectorBorder(bvh1)); const double inf = std::numeric_limits<double>::infinity(); double shortest = inf; OpenMesh::VertexHandle middle; - // Heaps that always display the current vertex with lowest value from direction 0 and 1 // Heap data structure allows easy access for the next element needed in the algorithm struct cmp { @@ -3148,19 +2679,6 @@ std::vector<OpenMesh::HalfedgeHandle> Embedding::A_StarBidirectional( } } } - /* - if ((bvh0.idx() == 5854 && bvh1.idx() == 6969) - || (bvh1.idx() == 5854 && bvh0.idx() == 6969)) { - qDebug() << "foo\n"; - MarkVertex(bvh0); - MarkVertex(bvh1); - debug_hard_stop_ = true; - base_mesh_->remove_property(closed_set0); - base_mesh_->remove_property(closed_set1); - base_mesh_->remove_property(gscore0); - base_mesh_->remove_property(gscore1); - return A_StarReconstructPath(middle, predecessor0, predecessor1); - }*/ //qDebug() << "Finished A* Loop"; if (!base_mesh_->is_valid_handle(middle)) { debug_hard_stop_=true; @@ -3192,7 +2710,12 @@ std::vector<OpenMesh::HalfedgeHandle> Embedding::A_StarBidirectional( return A_StarReconstructPath(middle, predecessor0, predecessor1); } -// Distance between bvhf and bvhv +/*! + * \brief Embedding::Distance + * \param bvhf + * \param bvhv + * \return direct spatial distance between vertices bvhf and bvhv + */ double Embedding::Distance(OpenMesh::VertexHandle bvhf, OpenMesh::VertexHandle bvhv) { auto pf = base_mesh_->point(bvhf); auto pv = base_mesh_->point(bvhv); @@ -3202,15 +2725,22 @@ double Embedding::Distance(OpenMesh::VertexHandle bvhf, OpenMesh::VertexHandle b return distfv; } -// https://www.cs.princeton.edu/courses/archive/spr06/cos423/Handouts/EPP%20shortest%20path%20algorithms.pdf -// Averaging the distance heuristic from both sides makes it admissible and feasible -// Variables corresponding to page 4, Bidirectional A* Search -// p_f(v): 1/2(pi_f(v)-pi_r(v)) + (pi_r(t)/2) -// Distance(bvhf, bvhv) : pi_f(v) -// Distance(bvhr, bvhv) : pi_r(v) -// Distance(bvhr, bvhf) : pi_r(t) -// Then call it with flipped bvhf and bvhr for the opposite direction p_r(v). -// p_r(v): 1/2(pi_r(v)-pi_f(v)) + (pi_r(s)/2) +/*! + * \brief Embedding::A_StarHeuristic The heuristic used in A* here, detailed explanation: + * https://www.cs.princeton.edu/courses/archive/spr06/cos423/Handouts/EPP%20shortest%20path%20algorithms.pdf + * Averaging the distance heuristic from both sides makes it admissible and feasible + * Variables corresponding to page 4, Bidirectional A* Search + * p_f(v): 1/2(pi_f(v)-pi_r(v)) + (pi_r(t)/2) + * Distance(bvhf, bvhv) : pi_f(v) + * Distance(bvhr, bvhv) : pi_r(v) + * Distance(bvhr, bvhf) : pi_r(t) + * Then call it with flipped bvhf and bvhr for the opposite direction p_r(v). + * p_r(v): 1/2(pi_r(v)-pi_f(v)) + (pi_r(s)/2) + * \param bvhf + * \param bvhr + * \param bvhv + * \return heuristical values to sort the heaps by + */ double Embedding::A_StarHeuristic(OpenMesh::VertexHandle bvhf, OpenMesh::VertexHandle bvhr, OpenMesh::VertexHandle bvhv) { @@ -3218,7 +2748,15 @@ double Embedding::A_StarHeuristic(OpenMesh::VertexHandle bvhf, + (Distance(bvhr, bvhf) / 2); } -// Returns the VV_Neighborhood excluding vertices already closed by A* and border vertices +/*! + * \brief Embedding::A_StarNeighbors + * \param bvh + * \param mheh + * \param closed_set + * \param towardsbvh + * \param bheh + * \return the VV_Neighborhood excluding vertices already closed by A* and border vertices + */ std::vector<OpenMesh::VertexHandle> Embedding::A_StarNeighbors(OpenMesh::VertexHandle bvh, OpenMesh::HalfedgeHandle mheh, OpenMesh::VPropHandleT<bool> closed_set, @@ -3258,6 +2796,14 @@ std::vector<OpenMesh::VertexHandle> Embedding::A_StarNeighbors(OpenMesh::VertexH return neighbors; } +/*! + * \brief Embedding::ValidA_StarEdge + * \param bheh + * \param mheh + * \return whether bheh is a Valid edge for A* traversal based on the bhe_border_ + * properties. These properties describe voronoi regions, so this method is only + * really used during initial triangulation to ensure traces don't block each other. + */ bool Embedding::ValidA_StarEdge(OpenMesh::HalfedgeHandle bheh, OpenMesh::HalfedgeHandle mheh) { if (!initial_triangulation_) { @@ -3269,6 +2815,14 @@ bool Embedding::ValidA_StarEdge(OpenMesh::HalfedgeHandle bheh, meta_mesh_->opposite_halfedge_handle(mheh))); } +/*! + * \brief Embedding::A_StarReconstructPath reconstructs a meta halfedge based on the output + * of the A_StarBidirectional function + * \param middle the middle halfedge of mheh + * \param predecessor0 predecessor property in one direction from the middle + * \param predecessor1 predecessor property in the other direction from the middle + * \return An ordered vector of halfedges representing the meta edge that was traced + */ std::vector<OpenMesh::HalfedgeHandle> Embedding::A_StarReconstructPath( OpenMesh::VertexHandle middle, OpenMesh::VPropHandleT<OpenMesh::VertexHandle> predecessor0, @@ -3291,8 +2845,6 @@ std::vector<OpenMesh::HalfedgeHandle> Embedding::A_StarReconstructPath( total_path.push_back(curr); curr = base_mesh_->property(predecessor1, curr); } - //qDebug() << "Path reconstruction starting vertex: " << total_path.front().idx(); - //qDebug() << "Path reconstruction ending vertex: " << total_path.back().idx(); OpenMesh::VertexHandle vh0 = total_path.front(); OpenMesh::VertexHandle vh1; total_path.pop_front(); @@ -3305,20 +2857,16 @@ std::vector<OpenMesh::HalfedgeHandle> Embedding::A_StarReconstructPath( } base_mesh_->remove_property(predecessor0); base_mesh_->remove_property(predecessor1); - /* - if (!returnpath.empty()) { - if (base_mesh_->to_vertex_handle(returnpath.back()) - == base_mesh_->from_vertex_handle(returnpath.front())) { - qDebug() << "Finished A* Trace for an edge connecting vertex " - << base_mesh_->from_vertex_handle(returnpath.back()).idx() - << " with itself, using " - << returnpath.size() << " edges."; - } - } - */ return returnpath; } +/*! + * \brief Embedding::IsSectorBorder + * \param bvh + * \param exceptions + * \return true if bvh lies on a meta_mesh element (vertex or edge) which is NOT + * included in the list of exception + */ bool Embedding::IsSectorBorder(OpenMesh::VertexHandle bvh, std::list<OpenMesh::HalfedgeHandle> exceptions) { if (meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, bvh))) { @@ -3345,27 +2893,17 @@ bool Embedding::IsSectorBorder(OpenMesh::VertexHandle bvh, return false; } +/*! + * \brief Embedding::InsertPath Inserts a list of base halfedges saved in path into the mesh + * as meta halfedge mheh (called after A* triangulation) + * \param mheh + * \param path + */ void Embedding::InsertPath(OpenMesh::HalfedgeHandle mheh, std::vector<OpenMesh::HalfedgeHandle> path) { - /* - qDebug() << "Meta edge connected base vertex 1: " - << meta_mesh_->property(mv_connection_, meta_mesh_->from_vertex_handle(mheh)).idx(); - qDebug() << "Meta edge connected base vertex 2: " - << meta_mesh_->property(mv_connection_, meta_mesh_->to_vertex_handle(mheh)).idx(); - qDebug() << "Path starting vertex : " - << base_mesh_->from_vertex_handle(path.front()).idx(); - qDebug() << "Path ending vertex : " - << base_mesh_->to_vertex_handle(path.back()).idx(); - //*/ if (path.empty()) { qDebug() << "Couldn't insert empty path"; } else { - /* - assert(meta_mesh_->property(mv_connection_, meta_mesh_->from_vertex_handle(mheh)) - == base_mesh_->from_vertex_handle(path.front())); - assert(meta_mesh_->property(mv_connection_, meta_mesh_->to_vertex_handle(mheh)) - == base_mesh_->to_vertex_handle(path.back())); - */ auto opp = meta_mesh_->opposite_halfedge_handle(mheh); meta_mesh_->property(mhe_connection_, mheh) = path.front(); meta_mesh_->property(mhe_connection_, opp) = @@ -3388,6 +2926,16 @@ void Embedding::InsertPath(OpenMesh::HalfedgeHandle mheh, } } +/*! + * \brief Embedding::FindA_StarStartingHalfedges Find A* Starting halfedges through a series + * of halfedge pointer operations. This is more complicated than it first sounds because it has + * to handle an initial triangulation where edges are traced in an arbitrary order and some edges + * may already be traced while others arent. Traces starting in the wrong sectors will fail so + * the starting halfedges need to be right. + * \param mheh the halfedge to be traced. + * \param verbose + * \return Two starting halfedges for use in A* tracing. + */ std::pair<OpenMesh::HalfedgeHandle, OpenMesh::HalfedgeHandle> Embedding::FindA_StarStartingHalfedges(OpenMesh::HalfedgeHandle mheh, bool verbose) { std::pair<OpenMesh::HalfedgeHandle, OpenMesh::HalfedgeHandle> output; @@ -3488,8 +3036,6 @@ Embedding::FindA_StarStartingHalfedges(OpenMesh::HalfedgeHandle mheh, bool verbo auto bvcp2 = base_mesh_->property(bv_connection_, base_mesh_->from_vertex_handle(output.second)); assert(bvcp1 == mvh0); assert(bvcp2 == mvh1); - //base_mesh_->status(output.first).set_selected(true); - //base_mesh_->status(output.second).set_selected(true); if (verbose && meta_mesh_->from_vertex_handle(mheh) == meta_mesh_->to_vertex_handle(mheh)) { @@ -3501,148 +3047,11 @@ Embedding::FindA_StarStartingHalfedges(OpenMesh::HalfedgeHandle mheh, bool verbo return output; } -void Embedding::EliminateDuplicatePaths( - OpenMesh::HPropHandleT<int> multiplicity_heh) { - for (auto mheh : meta_mesh_->halfedges()) { - TraversePath(mheh, multiplicity_heh); - } -} - -void Embedding::TraversePath(OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - auto currbheh = meta_mesh_->property(mhe_connection_, mheh); - while (base_mesh_->is_valid_handle(currbheh)) { - if (base_mesh_->property(multiplicity_heh, currbheh) == 1) { - currbheh = base_mesh_->property(next_heh_, currbheh); - } else if (base_mesh_->property(multiplicity_heh, currbheh) > 1) { - Unravel(currbheh, mheh, multiplicity_heh); - currbheh = base_mesh_->property(next_heh_, currbheh); - } else { - qDebug() << "Multiplicity < 1 at Base Halfedge " << currbheh.idx() - << ", this should not happen."; - } - } - ProcessHalfedge(mheh); -} - -// Find the correct handles to split multiple overlayed meta halfedges -// For severely bundled up paths alternate between splitting them off left and right -// in order to make the result more visually appealing -void Embedding::Unravel(OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - SplitTraversal mode = LEFT; - while (base_mesh_->property(multiplicity_heh, bheh) > 1) { - if (mode == LEFT) { - OpenMesh::HalfedgeHandle mhehl = mheh; - OpenMesh::HalfedgeHandle bhehl = mheh; - if (meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->from_vertex_handle(bheh)))) { - while (meta_mesh_->property(mhe_connection_, - meta_mesh_->opposite_halfedge_handle(meta_mesh_->prev_halfedge_handle(mhehl))) - == bheh) { - mhehl = meta_mesh_->opposite_halfedge_handle(meta_mesh_->prev_halfedge_handle(mhehl)); - } - bhehl = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(bheh)); - meta_mesh_->property(mhe_connection_, mhehl) = bhehl; - base_mesh_->property(multiplicity_heh, bhehl) = 1; - base_mesh_->property(multiplicity_heh, base_mesh_->opposite_halfedge_handle(bhehl)) = 1; - } else { - auto iter = base_mesh_->prev_halfedge_handle(bheh); - while (meta_mesh_->is_valid_handle(base_mesh_->property(bhe_connection_, iter))) { - iter = base_mesh_->prev_halfedge_handle(base_mesh_->opposite_halfedge_handle(iter)); - } - mhehl = base_mesh_->property(bhe_connection_, iter); - bhehl = base_mesh_->opposite_halfedge_handle(base_mesh_->prev_halfedge_handle(iter)); - base_mesh_->property(multiplicity_heh, iter) = 0; - base_mesh_->property(multiplicity_heh, base_mesh_->opposite_halfedge_handle(iter)) = 0; - base_mesh_->property(next_heh_, iter) - = OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; - base_mesh_->property(next_heh_, base_mesh_->opposite_halfedge_handle(iter)) - = OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; - ReattachPredecessor(bheh); - auto prev = base_mesh_->opposite_halfedge_handle(base_mesh_->property(next_heh_, - base_mesh_->opposite_halfedge_handle(iter))); - base_mesh_->property(next_heh_, prev) = bhehl; - base_mesh_->property(next_heh_, base_mesh_->opposite_halfedge_handle(bhehl)) - = base_mesh_->opposite_halfedge_handle(prev); - base_mesh_->property(multiplicity_heh, bhehl) = - base_mesh_->property(multiplicity_heh, prev); - base_mesh_->property(multiplicity_heh, base_mesh_->opposite_halfedge_handle(bhehl)) = - base_mesh_->property(multiplicity_heh, prev); - } - LeftTraversal(bhehl, bheh, mhehl, multiplicity_heh); - mode = RIGHT; - } else if (mode == RIGHT) { - OpenMesh::HalfedgeHandle mhehr = mheh; - OpenMesh::HalfedgeHandle bhehr = mheh; - if (meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->from_vertex_handle(bheh)))) { - while (meta_mesh_->property(mhe_connection_, - meta_mesh_->next_halfedge_handle(meta_mesh_->opposite_halfedge_handle(mhehr))) - == bheh) { - mhehr = meta_mesh_->next_halfedge_handle(meta_mesh_->opposite_halfedge_handle(mhehr)); - } - bhehr = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(bheh)); - meta_mesh_->property(mhe_connection_, mhehr) = bhehr; - base_mesh_->property(multiplicity_heh, bhehr) = 1; - base_mesh_->property(multiplicity_heh, base_mesh_->opposite_halfedge_handle(bhehr)) = 1; - } else { - auto iter = base_mesh_->opposite_halfedge_handle( - base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(bheh))); - while (meta_mesh_->is_valid_handle(base_mesh_->property(bhe_connection_, iter))) { - iter = base_mesh_->opposite_halfedge_handle(base_mesh_->next_halfedge_handle(iter)); - } - mhehr = base_mesh_->property(bhe_connection_, iter); - bhehr = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(iter)); - base_mesh_->property(multiplicity_heh, iter) = 0; - base_mesh_->property(multiplicity_heh, base_mesh_->opposite_halfedge_handle(iter)) = 0; - base_mesh_->property(next_heh_, iter) - = OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; - base_mesh_->property(next_heh_, base_mesh_->opposite_halfedge_handle(iter)) - = OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; - ReattachPredecessor(bheh); - auto prev = base_mesh_->opposite_halfedge_handle(base_mesh_->property(next_heh_, - base_mesh_->opposite_halfedge_handle(iter))); - base_mesh_->property(next_heh_, prev) = bhehr; - base_mesh_->property(next_heh_, base_mesh_->opposite_halfedge_handle(bhehr)) - = base_mesh_->opposite_halfedge_handle(prev); - base_mesh_->property(multiplicity_heh, bhehr) = - base_mesh_->property(multiplicity_heh, prev); - base_mesh_->property(multiplicity_heh, base_mesh_->opposite_halfedge_handle(bhehr)) = - base_mesh_->property(multiplicity_heh, prev); - } - RightTraversal(bhehr, bheh, mhehr, multiplicity_heh); - mode = LEFT; - } - } -} - -void Embedding::DetachPath(OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - ReattachPredecessor(bheh); - auto currheh = bheh; - auto nextheh = base_mesh_->next_halfedge_handle(currheh); - while (base_mesh_->property(multiplicity_heh, nextheh) == 0 - && !meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, - base_mesh_->to_vertex_handle(currheh)))) { - nextheh = base_mesh_->next_halfedge_handle(base_mesh_->opposite_halfedge_handle(nextheh)); - } - - -} - -void Embedding::ReattachPredecessor(OpenMesh::HalfedgeHandle bheh) { - for(auto bvih_iter : base_mesh_->vih_range(base_mesh_->from_vertex_handle(bheh))) { - if (base_mesh_->property(next_heh_, bvih_iter) == bheh) { - base_mesh_->property(next_heh_, base_mesh_->opposite_halfedge_handle(bheh)) - = base_mesh_->opposite_halfedge_handle(bvih_iter); - return; - } - } -} - +/*! + * \brief Embedding::MarkVertex Marks a meta vertex in black while coloring its + * vv_neighborhood white, making it easy to see for visual debugging. + * \param bvh + */ void Embedding::MarkVertex(OpenMesh::VertexHandle bvh) { qDebug() << "Marking vertex: " << bvh.idx() << "in white."; auto vertex_colors_pph = base_mesh_->vertex_colors_pph(); @@ -3654,20 +3063,13 @@ void Embedding::MarkVertex(OpenMesh::VertexHandle bvh) { } } -void Embedding::LeftTraversal(OpenMesh::HalfedgeHandle leftheh, - OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - -} - -void Embedding::RightTraversal(OpenMesh::HalfedgeHandle rightheh, - OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh) { - -} - +/*! + * \brief Embedding::AddMetaEdge Adds a meta edge (it will still need to be traced + * into the base mesh) + * \param mheh0 the previous edge of mheh + * \param mheh1 the previous edge of the opposite edge of mheh + * \return a halfedge of the new edge, specifically the next halfedge of mheh0 + */ OpenMesh::HalfedgeHandle Embedding::AddMetaEdge(OpenMesh::HalfedgeHandle mheh0, OpenMesh::HalfedgeHandle mheh1) { auto mhehnew0 = meta_mesh_->new_edge(meta_mesh_->to_vertex_handle(mheh0), @@ -3718,28 +3120,26 @@ OpenMesh::HalfedgeHandle Embedding::AddMetaEdge(OpenMesh::HalfedgeHandle mheh0, return mhehnew0; } -void Embedding::Rotate(OpenMesh::EdgeHandle meh, TraceType type) { - //qDebug() << "Flip function called"; +/*! + * \brief Embedding::Rotate + * \param meh + */ +void Embedding::Rotate(OpenMesh::EdgeHandle meh) { if (!IsRotationOkay(meh)) { qDebug() << "Meta edge " << meh.idx() << " cannot be rotated"; - /* - MarkVertex(meta_mesh_->property(mv_connection_, - meta_mesh_->to_vertex_handle(meta_mesh_->halfedge_handle(meh, 0)))); - MarkVertex(meta_mesh_->property(mv_connection_, - meta_mesh_->to_vertex_handle(meta_mesh_->halfedge_handle(meh, 1)))); - */ } else { MetaRotation(meh); auto mheh = meta_mesh_->halfedge_handle(meh, 0); - //qDebug() << "RemoveMetaEdgeFromBaseMesh function called"; RemoveMetaEdgeFromBaseMesh(mheh); - //qDebug() << "RemoveMetaEdgeFromBaseMesh function finished"; - //qDebug() << "pre trace"; - Trace(mheh, true, false, type); - //qDebug() << "post trace"; + Trace(mheh, true, false); } } +/*! + * \brief Embedding::IsRotationOkay + * \param meh + * \return whether meh can be rotateds + */ bool Embedding::IsRotationOkay(OpenMesh::EdgeHandle meh) { auto mheh0 = meta_mesh_->halfedge_handle(meh, 0); auto mheh1 = meta_mesh_->halfedge_handle(meh, 1); @@ -3826,7 +3226,11 @@ void Embedding::MetaRotation(OpenMesh::EdgeHandle meh) { assert(meta_mesh_->to_vertex_handle(mheh1) == meta_mesh_->to_vertex_handle(mhehnext0)); } -// Input: Any base halfedge on a meta edge. Removes the meta edge from the base mesh +/*! + * \brief Embedding::RemoveMetaEdgeFromBaseMesh + * \param mheh meta halfedge to be removed from the basemesh (it stays in the meta mesh) + * \param cleanup + */ void Embedding::RemoveMetaEdgeFromBaseMesh(OpenMesh::HalfedgeHandle mheh, bool cleanup) { assert(meta_mesh_->is_valid_handle(mheh)); assert(base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, mheh))); @@ -3872,6 +3276,11 @@ void Embedding::RemoveMetaEdgeFromBaseMesh(OpenMesh::HalfedgeHandle mheh, bool c } } +/*! + * \brief Embedding::RemoveMetaEdgeFromMetaMesh + * \param mheh meta halfedge to be removed, from the meta mesh only (stays in the base mesh + * if not removed from there first which it usually should be) + */ void Embedding::RemoveMetaEdgeFromMetaMesh(OpenMesh::HalfedgeHandle mheh) { auto mheho = meta_mesh_->opposite_halfedge_handle(mheh); auto mhehn = meta_mesh_->next_halfedge_handle(mheh); @@ -3934,6 +3343,11 @@ void Embedding::RemoveMetaEdgeFromMetaMesh(OpenMesh::HalfedgeHandle mheh) { } } +/*! + * \brief Embedding::MiddleBvh + * \param meh + * \return the base vertex at the middle of meh (roughly since the embedding is discrete) + */ OpenMesh::VertexHandle Embedding::MiddleBvh(OpenMesh::EdgeHandle meh) { auto bhehleft = meta_mesh_->property(mhe_connection_, meta_mesh_->halfedge_handle(meh, 0)); auto bhehright = meta_mesh_->property(mhe_connection_, meta_mesh_->halfedge_handle(meh, 1)); @@ -3956,22 +3370,37 @@ OpenMesh::VertexHandle Embedding::MiddleBvh(OpenMesh::EdgeHandle meh) { return base_mesh_->to_vertex_handle(bhehleft); } +/*! + * \brief Embedding::MiddleBvh + * \param mheh + * \return the base vertex at the middle of mheh (roughly since the embedding is discrete) + */ OpenMesh::VertexHandle Embedding::MiddleBvh(OpenMesh::HalfedgeHandle mheh) { return MiddleBvh(meta_mesh_->edge_handle(mheh)); } +/*! + * \brief Embedding::EdgeSplit splits meh at bvh + * \param meh + * \param bvh + * \param verbose + */ void Embedding::EdgeSplit(OpenMesh::EdgeHandle meh, OpenMesh::VertexHandle bvh, bool verbose) { assert(meta_mesh_->is_valid_handle(meh)); if (!base_mesh_->is_valid_handle(bvh)) { bvh = MiddleBvh(meh); } - // Split the edge in the meta mesh + if (verbose) { + qDebug() << "Split the edge in the meta mesh"; + } MetaEdgeSplit(meh, bvh); auto mvh = base_mesh_->property(bv_connection_, bvh); auto start = meta_mesh_->halfedge_handle(mvh); auto iter = start; - // Trace the new edges in the base mesh + if (verbose) { + qDebug() << "Trace the new edges in the base mesh"; + } do { if (!base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, iter))) { Trace(iter); @@ -3981,6 +3410,11 @@ void Embedding::EdgeSplit(OpenMesh::EdgeHandle meh, OpenMesh::VertexHandle bvh, } while (iter != start); } +/*! + * \brief Embedding::MetaEdgeSplit the part of the split performed on the meta mesh + * \param meh + * \param bvh + */ void Embedding::MetaEdgeSplit(OpenMesh::EdgeHandle meh, OpenMesh::VertexHandle bvh) { OpenMesh::HalfedgeHandle mhehb; auto mheha = meta_mesh_->halfedge_handle(meh, 0); @@ -4076,8 +3510,14 @@ void Embedding::MetaEdgeSplit(OpenMesh::EdgeHandle meh, OpenMesh::VertexHandle b } } -// Overwrites the bhe_connection_ parameters of an embedded halfedge starting at bheh -// to correspond to meta halfedge mheh +/*! + * \brief Embedding::OverwriteHalfedgeConnection + * Overwrites the bhe_connection_ parameters of an embedded halfedge starting at bheh + * to correspond to meta halfedge mheh. + * This is useful for splits since it saves us two Trace calls. + * \param mheh + * \param bheh + */ void Embedding::OverwriteHalfedgeConnection(OpenMesh::HalfedgeHandle mheh, OpenMesh::HalfedgeHandle bheh) { assert(base_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, @@ -4110,18 +3550,30 @@ void Embedding::OverwriteHalfedgeConnection(OpenMesh::HalfedgeHandle mheh, == meta_mesh_->from_vertex_handle(meta_mesh_->opposite_halfedge_handle(mheh))); } +/*! + * \brief Embedding::FaceSplit Splits the meta face of mheh at base vertex bvhs + * \param bvh + * \param mheh + * \param verbose + */ void Embedding::FaceSplit(OpenMesh::VertexHandle bvh, OpenMesh::HalfedgeHandle mheh, bool verbose) { assert(!IsSectorBorder(bvh)); if (!meta_mesh_->is_valid_handle(mheh)) { mheh = FindFaceHalfedge(bvh); } - //qDebug() << "Meta Face split"; + if (verbose) { + qDebug() << "Meta Face split"; + } MetaFaceSplit(mheh, bvh); - //qDebug() << "Vertex processing"; + if (verbose) { + qDebug() << "Vertex processing"; + } ProcessVertex(bvh); auto mvh = base_mesh_->property(bv_connection_, bvh); - //qDebug() << "Face split loop"; + if (verbose) { + qDebug() << "Face split loop"; + } for (auto mvoheh : meta_mesh_->voh_range(mvh)) { if (!base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, mvoheh))) { Trace(mvoheh); @@ -4130,6 +3582,12 @@ void Embedding::FaceSplit(OpenMesh::VertexHandle bvh, OpenMesh::HalfedgeHandle m } } +/*! + * \brief Embedding::FindFaceHalfedge + * \param bvh + * \return a halfedge of the meta face bvh lies on. or InvalidHandle if bvh does not + * lie on a meta face. + */ OpenMesh::HalfedgeHandle Embedding::FindFaceHalfedge(OpenMesh::VertexHandle bvh) { std::queue<OpenMesh::VertexHandle> queue; OpenMesh::VPropHandleT<bool> marked; @@ -4163,6 +3621,11 @@ OpenMesh::HalfedgeHandle Embedding::FindFaceHalfedge(OpenMesh::VertexHandle bvh) return OpenMesh::PolyConnectivity::InvalidHalfedgeHandle; } +/*! + * \brief Embedding::MetaFaceSplit meta mesh part of the face split + * \param mheh + * \param bvh + */ void Embedding::MetaFaceSplit(OpenMesh::HalfedgeHandle mheh, OpenMesh::VertexHandle bvh) { // Add bvh into the meta mesh // try highlevel method, implement low level if this does not work @@ -4174,12 +3637,21 @@ void Embedding::MetaFaceSplit(OpenMesh::HalfedgeHandle mheh, OpenMesh::VertexHan base_mesh_->property(bv_connection_, bvh) = mvh; } -// Relocates mvh to bvh -// The lowlevel method is better for most purposes, but less robust to extreme edge cases -// If you are relocating a vertex with edges that cannot be traced properly regardless of order -// eg. a vertex with 3 self-edges in a genus 4 mesh, do not use the low level method -// the high level method is a concatenation of a split and a collapse and should thus always work -// but it doesnt clean the base mesh up nearly as well. +/*! + * \brief Embedding::Relocate + * Relocates mvh to bvh + * The lowlevel method is better for most purposes, but less robust to extreme edge cases + * If you are relocating a vertex with edges that cannot be traced properly regardless of order + * eg. a vertex with 3 self-edges in a genus 4 mesh, do not use the low level method + * the high level method is a concatenation of a split and a collapse and should thus always work + * but it doesnt clean the base mesh up nearly as well. + * \param mvh + * \param bvh + * \param verbose + * \param lowlevel enabled by default, but disable it where this fails. The low level method still + * needs a bit of work and I might not have enough time to make it handle all edge cases (some + * edge cases will remain impossible regardless) + */ void Embedding::Relocate(OpenMesh::VertexHandle mvh, OpenMesh::VertexHandle bvh, bool verbose, bool lowlevel) { if (!base_mesh_->is_valid_handle(bvh)) { @@ -4189,11 +3661,6 @@ void Embedding::Relocate(OpenMesh::VertexHandle mvh, OpenMesh::VertexHandle bvh, && !lowlevel) { return; } - /* - qDebug() << "Relocating meta vertex " << mvh.idx() << " which lies on base vertex" - << meta_mesh_->property(mv_connection_, mvh).idx() << " to base vertex" - << bvh.idx(); - */ // Disallow relocation of boundary vertices away from their boundary. if (meta_mesh_->is_boundary(mvh)) { auto mehb = GetMetaEdge(bvh); @@ -4216,8 +3683,14 @@ void Embedding::Relocate(OpenMesh::VertexHandle mvh, OpenMesh::VertexHandle bvh, } } -// Relocation as a lower level function than CompositeRelocate -// Fails if all edges around mvh are self-edges (eg. genus 4 object with 1 vertex) +/*! + * \brief Embedding::LowLevelRelocate + * Relocation as a lower level function than CompositeRelocate + * Fails if all edges around mvh are self-edges (eg. genus 4 object with 1 vertex) + * \param mvh + * \param bvh + * \param verbose + */ void Embedding::LowLevelRelocate(OpenMesh::VertexHandle mvh, OpenMesh::VertexHandle bvh, bool verbose) { // This method does not do edge splits, relocate only inside the patch. @@ -4377,7 +3850,13 @@ void Embedding::LowLevelRelocate(OpenMesh::VertexHandle mvh, OpenMesh::VertexHan meta_mesh_->remove_property(group_selected); } -// Traverses a group and marks its members +/*! + * \brief Embedding::TraverseGroup + * Traverses a patch border group and marks its members + * \param mvh + * \param moh + * \param groupselected + */ void Embedding::TraverseGroup(OpenMesh::VertexHandle mvh, OpenMesh::HalfedgeHandle moh, OpenMesh::VPropHandleT<bool> groupselected) { @@ -4396,7 +3875,13 @@ void Embedding::TraverseGroup(OpenMesh::VertexHandle mvh, } } -// Relocation as a composite of a split and a collapse +/*! + * \brief Embedding::CompositeRelocate + * Relocation as a composite of a split and a collapse + * \param mvh + * \param bvh + * \param verbose + */ void Embedding::CompositeRelocate(OpenMesh::VertexHandle mvh, OpenMesh::VertexHandle bvh, bool verbose) { if (!IsSectorBorder(bvh)) { @@ -4478,10 +3963,16 @@ void Embedding::CompositeRelocate(OpenMesh::VertexHandle mvh, } } -// Splits at point bvh; if it is on an edge performs an edge split otherwise -// a face split. mheh is an optional parameter for face splits denoting a -// half-edge of the nearest face. Use for optimization, otherwise the nearest -// half-edge is searched for from bvh. +/*! + * \brief Embedding::Split + * Splits at point bvh; if it is on an edge performs an edge split otherwise + * a face split. mheh is an optional parameter for face splits denoting a + * half-edge of the nearest face. Use for optimization, otherwise the nearest + * half-edge is searched for from bvh. + * \param bvh + * \param mheh + * \param verbose + */ void Embedding::Split(OpenMesh::VertexHandle bvh, OpenMesh::HalfedgeHandle mheh, bool verbose) { if (meta_mesh_->is_valid_handle(base_mesh_->property(bv_connection_, bvh))) { @@ -4495,8 +3986,13 @@ void Embedding::Split(OpenMesh::VertexHandle bvh, OpenMesh::HalfedgeHandle mheh, } } -// Collapses the FROM vertex into the TO vertex -void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose, TraceType type) { +/*! + * \brief Embedding::Collapse + * Collapses the FROM vertex into the TO vertex + * \param mheh + * \param verbose + */ +void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose) { if (debug_hard_stop_) return; //qDebug() << "Calling collapse"; @@ -4552,7 +4048,7 @@ void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose, TraceType && !meta_mesh_->status(mhehcurr).deleted()) { RemoveMetaEdgeFromBaseMesh(mhehcurr); if (debug_hard_stop_) return; - Trace(mhehcurr, true, false, type); + Trace(mhehcurr, true, false); if (debug_hard_stop_) return; } else { assert(!base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, mhehcurr))); @@ -4580,7 +4076,7 @@ void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose, TraceType && !meta_mesh_->status(mhehcurr).deleted()) { RemoveMetaEdgeFromBaseMesh(mhehcurr); if (debug_hard_stop_) return; - Trace(mhehcurr, true, false, type); + Trace(mhehcurr, true, false); if (debug_hard_stop_) return; } else { assert(!base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, mhehcurr))); @@ -4607,7 +4103,7 @@ void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose, TraceType if (meta_mesh_->next_halfedge_handle(meta_mesh_->next_halfedge_handle(mhehouter)) == mhehouter) { RemoveLoop(mhehouter); - Retrace(mhehouter, true, false, type); + Retrace(mhehouter, true, false); if (debug_hard_stop_) return; } } else if (mhehon == mhehp && mhehn == mheho) { @@ -4621,7 +4117,7 @@ void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose, TraceType if (meta_mesh_->next_halfedge_handle(meta_mesh_->next_halfedge_handle(mhehouter)) == mhehouter) { RemoveLoop(mhehouter); - Retrace(mhehouter, true, false, type); + Retrace(mhehouter, true, false); if (debug_hard_stop_) return; } } else { @@ -4648,7 +4144,7 @@ void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose, TraceType // Second pass : Retrace to look nicer for (auto mhehit : meta_mesh_->voh_range(mvh)) { if (!meta_mesh_->status(mhehit).deleted()) { - Retrace(mhehit, true, false, type); + Retrace(mhehit, true, false); if (debug_hard_stop_) return; } } @@ -4668,6 +4164,12 @@ void Embedding::Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose, TraceType //qDebug() << "Collapse finished"; } +/*! + * \brief Embedding::IsCollapseOkay + * \param mheh + * \param verbose + * \return whether mheh can be collapsed + */ bool Embedding::IsCollapseOkay(OpenMesh::HalfedgeHandle mheh, bool verbose) { if (!meta_mesh_->is_valid_handle(meta_mesh_->edge_handle(mheh))) { @@ -4725,10 +4227,6 @@ bool Embedding::IsCollapseOkay(OpenMesh::HalfedgeHandle mheh, bool verbose) { } return false; } - // The above does not work on locally, a global test like this is detrimental since - // it won't work on partitioned meshes - // TODO: make this local - // is vertex connected to itself? if (meta_mesh_->from_vertex_handle(mheh) == meta_mesh_->to_vertex_handle(mheh)) { @@ -4786,6 +4284,11 @@ bool Embedding::IsCollapseOkay(OpenMesh::HalfedgeHandle mheh, bool verbose) { return true; } +/*! + * \brief Embedding::BendMetaEdgeForwards + * A trick used in collapse, bending edges so as to always trace inside disk topology areas + * \param mheh + */ void Embedding::BendMetaEdgeForwards(OpenMesh::HalfedgeHandle mheh) { if (meta_mesh_->status(mheh).deleted()) { assert(meta_mesh_->from_vertex_handle(mheh) == meta_mesh_->to_vertex_handle(mheh)); @@ -4824,20 +4327,13 @@ void Embedding::BendMetaEdgeForwards(OpenMesh::HalfedgeHandle mheh) { // v - f meta_mesh_->set_face_handle(mhehnext, mfho); - - // Check if the edge is part of a loop; handle it - // This loop detection led to erroneus deletion of self edges when collapsing into a vertex - // of valence 1 with the self edge enclosing the collapsed edge. Bending the self-edge once - // causes a loop with the edge pending deletion that is then detected here. Handle loop - // detection later instead. - /* - if (meta_mesh_->next_halfedge_handle(meta_mesh_->next_halfedge_handle(mheh)) == mheh) { - RemoveLoop(meta_mesh_->next_halfedge_handle(mheh)); - return; - } - */ } +/*! + * \brief Embedding::BendMetaEdgeBackwards + * A trick used in collapse, bending edges so as to always trace inside disk topology areas + * \param mheh + */ void Embedding::BendMetaEdgeBackwards(OpenMesh::HalfedgeHandle mheh) { if (meta_mesh_->status(mheh).deleted()) { assert(meta_mesh_->from_vertex_handle(mheh) == meta_mesh_->to_vertex_handle(mheh)); @@ -4876,100 +4372,13 @@ void Embedding::BendMetaEdgeBackwards(OpenMesh::HalfedgeHandle mheh) { // v - f meta_mesh_->set_face_handle(mhehprev, mfho); - - // Check if the edge is part of a loop; handle it - // This loop detection led to erroneus deletion of self edges when collapsing into a vertex - // of valence 1 with the self edge enclosing the collapsed edge. Bending the self-edge once - // causes a loop with the edge pending deletion that is then detected here. Handle loop - // detection later instead. - /* - if (meta_mesh_->next_halfedge_handle(meta_mesh_->next_halfedge_handle(mheh)) == mheh) { - RemoveLoop(meta_mesh_->next_halfedge_handle(mheh)); - return; - } - */ -} - -void Embedding::MetaCollapse(OpenMesh::HalfedgeHandle mheh, bool swap) { - auto meh = meta_mesh_->edge_handle(mheh); - auto mhehn = meta_mesh_->next_halfedge_handle(mheh); - auto mhehp = meta_mesh_->prev_halfedge_handle(mheh); - auto mopp = meta_mesh_->opposite_halfedge_handle(mheh); - auto moppn = meta_mesh_->next_halfedge_handle(mopp); - auto moppp = meta_mesh_->prev_halfedge_handle(mopp); - auto fh = meta_mesh_->face_handle(mheh); - auto fo = meta_mesh_->face_handle(mopp); - OpenMesh::VertexHandle vh0, vh1; - if (!swap) { - vh0 = meta_mesh_->from_vertex_handle(mheh); - vh1 = meta_mesh_->to_vertex_handle(mheh); - } else { - vh1 = meta_mesh_->from_vertex_handle(mheh); - vh0 = meta_mesh_->to_vertex_handle(mheh); - meta_mesh_->set_point(vh1, meta_mesh_->point(vh0)); - } - - // halfedge -> vertex - for (auto miheh : meta_mesh_->vih_range(vh0)) { - meta_mesh_->set_vertex_handle(miheh, vh1); - if (meta_mesh_->from_vertex_handle(miheh) == vh0) { - meta_mesh_->set_vertex_handle(meta_mesh_->opposite_halfedge_handle(miheh), vh1); - } - } - - // halfedge -> halfedge - meta_mesh_->set_next_halfedge_handle(mhehp, mhehn); - meta_mesh_->set_next_halfedge_handle(moppp, moppn); - - // face -> halfedge - if (meta_mesh_->is_valid_handle(fh)) meta_mesh_->set_halfedge_handle(fh, mhehn); - if (meta_mesh_->is_valid_handle(fo)) meta_mesh_->set_halfedge_handle(fo, moppn); - - // vertex -> halfedge - if (meta_mesh_->halfedge_handle(vh1) == mopp) { - meta_mesh_->set_halfedge_handle(vh1, mhehn); - } - meta_mesh_->adjust_outgoing_halfedge(vh1); - meta_mesh_->set_isolated(vh0); - - // remove base->meta vertex connection - base_mesh_->property(bv_connection_, meta_mesh_->property(mv_connection_, vh0)) - = OpenMesh::PolyConnectivity::InvalidVertexHandle; - - // delete stuff - meta_mesh_->status(meh).set_deleted(true); - meta_mesh_->status(vh0).set_deleted(true); - if (meta_mesh_->has_halfedge_status()) { - meta_mesh_->status(mheh).set_deleted(true); - meta_mesh_->status(mopp).set_deleted(true); - } - - auto iter = meta_mesh_->halfedge_handle(vh1); - uint count = meta_mesh_->valence(vh1); - for (uint i=0; i<count; ++i) { - if (meta_mesh_->status(iter).deleted()) { - qDebug() << "Iterating over a deleted edge"; - debug_hard_stop_ = true; - } - if (meta_mesh_->status(meta_mesh_->next_halfedge_handle(iter)).deleted()) { - qDebug() << "Current edge is connected to a deleted edge"; - debug_hard_stop_ = true; - } - if (meta_mesh_->next_halfedge_handle(meta_mesh_->next_halfedge_handle(iter)) == iter) { - if (!base_mesh_->is_valid_handle(meta_mesh_->property(mhe_connection_, iter))) { - auto curr = iter; - iter = meta_mesh_->opposite_halfedge_handle(meta_mesh_->prev_halfedge_handle(iter)); - RemoveLoop(meta_mesh_->next_halfedge_handle(curr)); - } else { - RemoveLoop(iter); - } - } - iter = meta_mesh_->next_halfedge_handle(meta_mesh_->opposite_halfedge_handle(iter)); - } - //DumpMetaMeshHalfedgeInfo(); } -// removes a loop of edges AB->BA->AB.. +/*! + * \brief Embedding::RemoveLoop + * removes a loop of edges AB->BA->AB.. by deleting BA + * \param mheh is AB + */ void Embedding::RemoveLoop(OpenMesh::HalfedgeHandle mheh) { // make sure this is a loop if(meta_mesh_->next_halfedge_handle(meta_mesh_->next_halfedge_handle(mheh)) != mheh) { @@ -5041,6 +4450,11 @@ void Embedding::RemoveLoop(OpenMesh::HalfedgeHandle mheh) { assert(meta_mesh_->prev_halfedge_handle(meta_mesh_->next_halfedge_handle(mheh)) != mhehdelo); } +/*! + * \brief Embedding::RemoveSelfLoop + * removes a self loop mheh->mheh->mheh... + * \param mheh + */ void Embedding::RemoveSelfLoop(OpenMesh::HalfedgeHandle mheh) { // Avoid removing boundaries if (meta_mesh_->is_boundary(mheh) @@ -5078,7 +4492,11 @@ void Embedding::RemoveSelfLoop(OpenMesh::HalfedgeHandle mheh) { } } -// returns the euler characteristic of the 1-ring around mvh +/*! + * \brief Embedding::OneRingEuler + * \param mvh + * \return the euler characteristic of the 1-ring around mvh + */ int Embedding::OneRingEuler(OpenMesh::VertexHandle mvh) { auto mheh = meta_mesh_->halfedge_handle(mvh); // V - E + F = g @@ -5131,6 +4549,13 @@ int Embedding::OneRingEuler(OpenMesh::VertexHandle mvh) { return euler; } +/*! + * \brief Embedding::MetaSwap + * swaps all pointers and properties relevant to the embedding structure between mvh0 and mvh1 + * this is used in the composite relocation method to preserve vertex ids + * \param mvh0 + * \param mvh1 + */ void Embedding::MetaSwap(OpenMesh::VertexHandle mvh0, OpenMesh::VertexHandle mvh1) { // Store mvh0 into temp auto tempcolor = meta_mesh_->color(mvh0); @@ -5173,28 +4598,9 @@ void Embedding::MetaSwap(OpenMesh::VertexHandle mvh0, OpenMesh::VertexHandle mvh } } -/* -void Embedding::FindUnions(OpenMesh::VertexHandle mvha, OpenMesh::VertexHandle mvhb, - OpenMesh::VPropHandleT<int> group) { - Utils::UnionFind unionfind(meta_mesh_->n_vertices()); - for (auto moheh : meta_mesh_->voh_range(mvhb)) { - auto iter = meta_mesh_->next_halfedge_handle(moheh); - while (meta_mesh_->to_vertex_handle(iter) != mvhb) { - auto mvh0 = meta_mesh_->from_vertex_handle(iter); - auto mvh1 = meta_mesh_->to_vertex_handle(iter); - if (!(mvh0 == mvhb || mvh1 == mvhb) && !unionfind.equivalent(mvh0.idx(), mvh1.idx())) { - unionfind.merge(mvh0.idx(), mvh1.idx()); - } - iter = meta_mesh_->next_halfedge_handle(iter); - } - } - - for (auto mvh : meta_mesh_->vertices()) { - meta_mesh_->property(group, mvh) = unionfind.representative(mvh.idx()); - } -} -*/ - +/*! + * \brief Embedding::DumpMetaMeshHalfedgeInfo Infodump, useful for some debugging. + */ void Embedding::DumpMetaMeshHalfedgeInfo() { qDebug() << "The metamesh has " << meta_mesh_->n_halfedges() << " halfedges."; for (auto mheh : meta_mesh_->halfedges()) { diff --git a/Embedding.hh b/Embedding.hh index 1f3c9bd4e8aa0c94fa57ba144ddd0fb8b1b7e33c..6fb035b03c76fb76ac8b1e5b54e81cc3b585923a 100644 --- a/Embedding.hh +++ b/Embedding.hh @@ -15,26 +15,23 @@ public: ~Embedding() {} enum TraceFaceAttr {UNPROCESSEDFACE, PREPROCESSEDFACE}; - enum TraceType {IMPLICITDIJKSTRA, A_STAR, A_STAR_MIDPOINTS}; enum RandomType {RATIO, TOTAL}; void CopyInitialization(TriMesh& base_mesh, PolyMesh& meta_mesh); - void SelectionTriangulation(TriMesh& base_mesh, PolyMesh& meta_mesh, - TraceType type = IMPLICITDIJKSTRA); + void SelectionTriangulation(TriMesh& base_mesh, PolyMesh& meta_mesh); void RandomTriangulation(TriMesh& base_mesh, PolyMesh& meta_mesh, double ratio, - RandomType rtype, TraceType type = A_STAR); + RandomType rtype); void ColorizeMetaMesh(); void Trace(OpenMesh::HalfedgeHandle mheh, bool cleanup = true, - bool mark_trace = false, TraceType tracetype = A_STAR, + bool mark_trace = false, TraceFaceAttr facetype = PREPROCESSEDFACE); void Retrace(OpenMesh::HalfedgeHandle mheh, bool cleanup = true, - bool mark_trace = false, TraceType tracetype = A_STAR, + bool mark_trace = false, TraceFaceAttr facetype = PREPROCESSEDFACE); - void Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose = false, - TraceType type = A_STAR); + void Collapse(OpenMesh::HalfedgeHandle mheh, bool verbose = false); bool IsCollapseOkay(OpenMesh::HalfedgeHandle mheh, bool verbose = false); - void Rotate(OpenMesh::EdgeHandle meh, TraceType type = A_STAR); + void Rotate(OpenMesh::EdgeHandle meh); bool IsRotationOkay(OpenMesh::EdgeHandle meh); void Relocate(OpenMesh::VertexHandle mvh, OpenMesh::VertexHandle bvh, bool verbose = false, bool lowlevel = true); @@ -90,9 +87,9 @@ public: private: enum SplitTraversal {LEFT, RIGHT}; bool TriangulationPipeline( - std::vector<OpenMesh::VertexHandle> meta_mesh_points, TraceType type); + std::vector<OpenMesh::VertexHandle> meta_mesh_points); void InitializeProperties(); - bool TriangulateMetaMesh(TraceType type); + bool TriangulateMetaMesh(); void PreProcessEdges(); void ProcessHalfedge(OpenMesh::HalfedgeHandle mheh); void ProcessEdge(OpenMesh::EdgeHandle meh); @@ -114,19 +111,13 @@ private: void CreateMetaMeshVertices(std::vector<OpenMesh::VertexHandle> meta_mesh_points); bool Delaunay(OpenMesh::VPropHandleT<double> voronoidistance, OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::HPropHandleT<int> multiplicity_heh, - TraceType type); + OpenMesh::HPropHandleT<int> multiplicity_heh); void TraverseBoundary(OpenMesh::VertexHandle mvh); int fact(int n); int nCk(int n, int k); std::vector<int> VoronoiGenus(); - int FixMetaMeshConnectivity(OpenMesh::VertexHandle mvh); - void AddSelfEdges(std::vector<OpenMesh::HalfedgeHandle> borders); void SetFaceProperties(OpenMesh::FaceHandle bf, - OpenMesh::FaceHandle mf, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - TraceType type); + OpenMesh::FaceHandle mf); void CopyFaceProperties(OpenMesh::FaceHandle mfh, std::vector<OpenMesh::HalfedgeHandle> boundaryborders); OpenMesh::FaceHandle AddFace(std::vector<OpenMesh::VertexHandle> mvh, @@ -138,46 +129,11 @@ private: void SetBorderProperties(OpenMesh::HalfedgeHandle bheh, OpenMesh::HalfedgeHandle mheh); - void ImplicitDijkstra(OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::HPropHandleT<int> multiplicity_heh); - void A_StarTriangulation(TraceType type); + void A_StarTriangulation(); void NaiveVoronoi(std::queue<OpenMesh::VertexHandle> queue, OpenMesh::VPropHandleT<double> voronoidistance, OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh); - OpenMesh::HalfedgeHandle FindMiddle(OpenMesh::HalfedgeHandle metaheh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh); - OpenMesh::HalfedgeHandle CreateMiddle(OpenMesh::HalfedgeHandle bheh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh); - bool EligibleHalfedge(OpenMesh::HalfedgeHandle baseheh, - OpenMesh::VertexHandle metavh0, - OpenMesh::VertexHandle metavh1); - OpenMesh::HalfedgeHandle DijkstraNextHeh(OpenMesh::HalfedgeHandle bheh, - OpenMesh::VertexHandle metavh0, - OpenMesh::VertexHandle metavh1, - OpenMesh::HPropHandleT<bool> marked); - void MarkPath(OpenMesh::HalfedgeHandle heh, OpenMesh::HalfedgeHandle metaheh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::HPropHandleT<int> multiplicity_heh); - void MarkPathRecursive(OpenMesh::VertexHandle vh, OpenMesh::HalfedgeHandle toheh, - OpenMesh::HalfedgeHandle metaheh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance, - OpenMesh::HPropHandleT<int> multiplicity_heh); - bool NeedReadjusting(OpenMesh::VertexHandle bvh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh); - void ReadjustPath(OpenMesh::VertexHandle bvh, - OpenMesh::HalfedgeHandle toheh, - OpenMesh::HalfedgeHandle metaheh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance); - OpenMesh::HalfedgeHandle VoronoiSplit(OpenMesh::HalfedgeHandle bvh, - OpenMesh::VPropHandleT<OpenMesh::HalfedgeHandle> to_heh, - OpenMesh::VPropHandleT<double> voronoidistance); void ColorizeMetaMeshVertices(); void ColorizeMetaEdges(); @@ -189,7 +145,6 @@ private: void BoundaryTrace(OpenMesh::HalfedgeHandle mheh, bool mark_trace = false); void SimpleTrace(OpenMesh::HalfedgeHandle mheh, bool cleanup = true, bool mark_trace = false); - void SimpleMidpointTrace(OpenMesh::HalfedgeHandle mheh, bool mark_trace = false); void AdvancedTrace(OpenMesh::HalfedgeHandle mheh); std::vector<OpenMesh::HalfedgeHandle> A_StarBidirectional(OpenMesh::HalfedgeHandle bheh0, OpenMesh::HalfedgeHandle bheh1, bool mark_trace = false, @@ -237,7 +192,6 @@ private: // Collapse void BendMetaEdgeForwards(OpenMesh::HalfedgeHandle mheh); void BendMetaEdgeBackwards(OpenMesh::HalfedgeHandle mheh); - void MetaCollapse(OpenMesh::HalfedgeHandle mheh, bool swap = false); void RemoveLoop(OpenMesh::HalfedgeHandle mheh); void RemoveSelfLoop(OpenMesh::HalfedgeHandle mheh); int OneRingEuler(OpenMesh::VertexHandle mvh); @@ -252,32 +206,6 @@ private: bool verbose = false); void MetaSwap(OpenMesh::VertexHandle mvh0, OpenMesh::VertexHandle mvh1); - void EliminateDuplicatePaths(OpenMesh::HPropHandleT<int> multiplicity_heh); - void TraversePath(OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh); - void Unravel (OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh); - void DetachPath(OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh); - void ReattachPredecessor(OpenMesh::HalfedgeHandle bheh); - void LeftTraversal(OpenMesh::HalfedgeHandle leftheh, - OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh); - void RightTraversal(OpenMesh::HalfedgeHandle rightheh, - OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::HPropHandleT<int> multiplicity_heh); - /* - void MiddleTraversal(OpenMesh::HalfedgeHandle bheh, - OpenMesh::HalfedgeHandle mheh, - OpenMesh::VPropHandleT<OpenMesh::VertexHandle> voronoiID, - OpenMesh::HPropHandleT<int> multiplicity_heh); - void BaseSplit(OpenMesh::HalfedgeHandle leftheh, - OpenMesh::HalfedgeHandle bheh); - */ bool debug_hard_stop_ = false; bool initial_triangulation_ = false; bool boundaries_ = false; diff --git a/IsotropicRemesher.cc b/IsotropicRemesher.cc index b15f31fc77c9926dfd6df643f7ab6a297a867114..b2d481d11c25c37a10682791c814e19d32beb146 100644 --- a/IsotropicRemesher.cc +++ b/IsotropicRemesher.cc @@ -627,13 +627,24 @@ void IsotropicRemesher::SmoothVertexVWD(Embedding *embedding, } ++it; } - //qDebug() << "Relocating vertex " << mvh.idx(); - embedding->Relocate(mvh, bvhmin); + // The new, faster relocate method sadly cannot yet handle complex patches. + // Make sure to use the old method if a patch is complex, so check that here. + bool simple = true; + for (auto moh : meta_mesh->voh_range(mvh)) { + auto mvhit = meta_mesh->to_vertex_handle(moh); + if (mvhit == mvh) { + simple = false; + } + } + if (simple) { + embedding->Relocate(mvh, bvhmin); + } else { + embedding->Relocate(mvh, bvhmin, false); + } if (embedding->ErrStatus()) { qDebug() << "Relocation failed for vertex " << mih_list.front().idx(); debug_hard_stop_ = true; } - //qDebug() << "Relocation finished."; } /*! @@ -934,8 +945,7 @@ void IsotropicRemesher::Straightening(Embedding *embedding, StraighteningType st facetype ft = noselfedgesdisc; for (auto moh : meta_mesh->voh_range(mvh)) { auto mvhit = meta_mesh->to_vertex_handle(moh); - if (mvhit == mvh - || mvhit == meta_mesh->from_vertex_handle(moh)) { + if (mvhit == mvh) { ft = selfedgesorhighergenus; } if (meta_mesh->is_boundary(meta_mesh->to_vertex_handle(moh)) @@ -973,7 +983,9 @@ void IsotropicRemesher::Straightening(Embedding *embedding, StraighteningType st break; } case selfedgesorhighergenus: { - embedding->Relocate(mvh, meta_mesh->property(embedding->bv_connection_, mvh)); + for (auto moh : meta_mesh->voh_range(mvh)) { + embedding->Retrace(moh); + } break; } } diff --git a/IsotropicRemesher.hh b/IsotropicRemesher.hh index 95a57c134c5824f49df99f7db9036d035c4920ea..2c531f45bfe6374414132f0a4542ae14e2246d12 100644 --- a/IsotropicRemesher.hh +++ b/IsotropicRemesher.hh @@ -31,7 +31,7 @@ public: std::function<void (QString, QString, double, double)> screenshot = {}, bool limitflips = false, StraighteningType strtype = PATCHWISE, - CollapsingOrder corder = RANDOM); + CollapsingOrder corder = SPLITWEIGHT); bool DebugStopStatus() {return debug_hard_stop_;} private: diff --git a/MetaMeshPlugin.cc b/MetaMeshPlugin.cc index 93f9ffe658e84050a4183f54e54973ed75dfdbf6..a854c7a495302a5800084bc573da48e66c877174 100644 --- a/MetaMeshPlugin.cc +++ b/MetaMeshPlugin.cc @@ -8,6 +8,9 @@ #include <QDebug> +/*! + * \brief MetaMeshPlugin::initializePlugin + */ void MetaMeshPlugin::initializePlugin() { widget_ = new MetaMeshToolbox(); @@ -24,8 +27,8 @@ void MetaMeshPlugin::initializePlugin() connect(widget_->button_collapse_, SIGNAL(clicked()), this, SLOT(collapse())); connect(widget_->button_relocate_, SIGNAL(clicked()), this, SLOT(relocate())); connect(widget_->button_remesh_, SIGNAL(clicked()), this, SLOT(remesh())); - connect(widget_->button_insert_, SIGNAL(clicked()), this, SLOT(markmetaV())); - connect(widget_->button_delete_, SIGNAL(clicked()), this, SLOT(markmetaHE())); + connect(widget_->button_dummy1_, SIGNAL(clicked()), this, SLOT(DummySlotFunction1())); + connect(widget_->button_dummy2_, SIGNAL(clicked()), this, SLOT(DummySlotFunction2())); connect(widget_->button_next_, SIGNAL(clicked()), this, SLOT(nxt())); connect(widget_->button_opp_, SIGNAL(clicked()), this, SLOT(opp())); connect(widget_->button_prev_, SIGNAL(clicked()), this, SLOT(prv())); @@ -38,18 +41,20 @@ void MetaMeshPlugin::initializePlugin() printf("Created MetaMesh object\n"); } +/*! + * \brief MetaMeshPlugin::pluginsInitialized + */ void MetaMeshPlugin::pluginsInitialized() { printf("Plugins Initialized\n"); } +/*! + * \brief MetaMeshPlugin::slotObjectUpdated + * \param _identifier + */ void MetaMeshPlugin::slotObjectUpdated(int _identifier) { - /* - qDebug() << "updatedObject"; - qDebug() << "_identifier: " << _identifier << " base_mesh_id_: " << base_mesh_id_ - << " meta_mesh_id_: " << meta_mesh_id_; - */ if (_identifier == meta_mesh_id_ && !selection_mutex_ && widget_->checkbox_copy_markings_->checkState() == Qt::Checked) { selection_mutex_ = true; @@ -58,6 +63,10 @@ void MetaMeshPlugin::slotObjectUpdated(int _identifier) } } +/*! + * \brief MetaMeshPlugin::triangulate triangulates a meta mesh from marked vertices on the currently + * loaded mesh + */ void MetaMeshPlugin::triangulate() { qDebug() << "Triangulate Button pressed"; @@ -71,13 +80,7 @@ void MetaMeshPlugin::triangulate() TriMesh& base_mesh = *triMesh(o); qDebug() << "Call triangulation on MetaMesh in object loop"; - if (widget_->checkbox_implicit_dijkstra_->isChecked()) { - embedding_->SelectionTriangulation(base_mesh, *meta_mesh_, Embedding::IMPLICITDIJKSTRA); - } else if (widget_->checkbox_a_star_triangulation_->isChecked()) { - embedding_->SelectionTriangulation(base_mesh, *meta_mesh_, Embedding::A_STAR); - } else if (widget_->checkbox_a_star_midpoint_triangulation_->isChecked()) { - embedding_->SelectionTriangulation(base_mesh, *meta_mesh_, Embedding::A_STAR_MIDPOINTS); - } + embedding_->SelectionTriangulation(base_mesh, *meta_mesh_); meta_mesh_->update_normals(); embedding_->GetBaseMesh()->update_normals(); @@ -98,14 +101,24 @@ void MetaMeshPlugin::triangulate() emit updatedObject(meta_mesh_id_, UPDATE_ALL); } +/*! + * \brief MetaMeshPlugin::randomizetotal randomize an absolute number of vertices + */ void MetaMeshPlugin::randomizetotal() { randomize(Embedding::RandomType::TOTAL); } +/*! + * \brief MetaMeshPlugin::randomizeratio randomize a ratio of vertices + */ void MetaMeshPlugin::randomizeratio() { randomize(Embedding::RandomType::RATIO); } +/*! + * \brief MetaMeshPlugin::randomize randomize meta mesh vertices and triangulate + * \param type + */ void MetaMeshPlugin::randomize(Embedding::RandomType type) { using namespace PluginFunctions; for (auto* o : objects(TARGET_OBJECTS, DATA_TRIANGLE_MESH)) { @@ -117,19 +130,10 @@ void MetaMeshPlugin::randomize(Embedding::RandomType type) { TriMesh& base_mesh = *triMesh(o); qDebug() << "Call triangulation on MetaMesh in object loop"; - if (widget_->checkbox_implicit_dijkstra_->isChecked()) { - embedding_->RandomTriangulation(base_mesh, *meta_mesh_, - widget_->input_ratio_->value(), type, Embedding::IMPLICITDIJKSTRA); - } else if (widget_->checkbox_a_star_triangulation_->isChecked()) { - embedding_->RandomTriangulation(base_mesh, *meta_mesh_, - widget_->input_ratio_->value(), type, Embedding::A_STAR); - } else if (widget_->checkbox_a_star_midpoint_triangulation_->isChecked()) { - embedding_->RandomTriangulation(base_mesh, *meta_mesh_, - widget_->input_ratio_->value(), type, Embedding::A_STAR_MIDPOINTS); - } + embedding_->RandomTriangulation(base_mesh, *meta_mesh_, + widget_->input_ratio_->value(), type); meta_mesh_->update_normals(); embedding_->GetBaseMesh()->update_normals(); - //meta_mesh_->clear(); emit updatedObject(o->id(), UPDATE_ALL); qDebug() << "Exited InitialTriangulation function"; } @@ -142,6 +146,9 @@ void MetaMeshPlugin::randomize(Embedding::RandomType type) { emit updatedObject(meta_mesh_id_, UPDATE_ALL); } +/*! + * \brief MetaMeshPlugin::test_meta_mesh run selected test + */ void MetaMeshPlugin::test_meta_mesh() { using namespace PluginFunctions; if (embedding_->GetMetaMesh() == nullptr) { @@ -192,6 +199,10 @@ void MetaMeshPlugin::test_meta_mesh() { postoperation(UPDATE_ALL, UPDATE_ALL); } +/*! + * \brief MetaMeshPlugin::retrace retrace the selected meta edges / halfedges. None selected means + * everything will be retraced. + */ void MetaMeshPlugin::retrace() { using namespace PluginFunctions; preoperation(); @@ -213,6 +224,9 @@ void MetaMeshPlugin::retrace() { postoperation(UPDATE_ALL, UPDATE_TOPOLOGY); } +/*! + * \brief MetaMeshPlugin::rotate rotate all selected meta edges and halfedges + */ void MetaMeshPlugin::rotate() { using namespace PluginFunctions; preoperation(); @@ -226,6 +240,9 @@ void MetaMeshPlugin::rotate() { postoperation(UPDATE_ALL, UPDATE_TOPOLOGY); } +/*! + * \brief MetaMeshPlugin::split split faces and edges at selected base vertices + */ void MetaMeshPlugin::split() { using namespace PluginFunctions; preoperation(); @@ -240,6 +257,9 @@ void MetaMeshPlugin::split() { postoperation(UPDATE_TOPOLOGY, UPDATE_TOPOLOGY); } +/*! + * \brief MetaMeshPlugin::collapse collapse all selected meta edges and halfedges + */ void MetaMeshPlugin::collapse() { using namespace PluginFunctions; preoperation(); @@ -253,6 +273,9 @@ void MetaMeshPlugin::collapse() { postoperation(UPDATE_TOPOLOGY, UPDATE_TOPOLOGY); } +/*! + * \brief MetaMeshPlugin::relocate relocate selected meta vertex to selected non-meta vertex + */ void MetaMeshPlugin::relocate() { using namespace PluginFunctions; preoperation(); @@ -282,6 +305,9 @@ void MetaMeshPlugin::relocate() { postoperation(UPDATE_TOPOLOGY, UPDATE_TOPOLOGY); } +/*! + * \brief MetaMeshPlugin::remesh calls IsotropicRemesher::Remesh with menu selected parameters + */ void MetaMeshPlugin::remesh() { using namespace PluginFunctions; preoperation(); @@ -316,6 +342,9 @@ void MetaMeshPlugin::remesh() { postoperation(UPDATE_TOPOLOGY, UPDATE_TOPOLOGY); } +/*! + * \brief MetaMeshPlugin::calculateoffset calculate an offset to separate base and meta mesh. + */ void MetaMeshPlugin::calculateoffset() { const double inf = std::numeric_limits<double>::infinity(); ACG::Vec3d minCorner = {+inf, +inf, +inf}; @@ -328,6 +357,9 @@ void MetaMeshPlugin::calculateoffset() { meta_mesh_visualization_offset_[0] = (maxCorner[0]-minCorner[0])*1.3; } +/*! + * \brief MetaMeshPlugin::addoffset move the meta mesh away from the base mesh + */ void MetaMeshPlugin::addoffset() { for (auto mvh : embedding_->GetMetaMesh()->vertices()) { embedding_->GetMetaMesh()->point(mvh) += meta_mesh_visualization_offset_/2.0; @@ -337,6 +369,9 @@ void MetaMeshPlugin::addoffset() { } } +/*! + * \brief MetaMeshPlugin::removeoffset move the meta mesh back to the base mesh + */ void MetaMeshPlugin::removeoffset() { for (auto mvh : embedding_->GetMetaMesh()->vertices()) { embedding_->GetMetaMesh()->point(mvh) -= meta_mesh_visualization_offset_/2.0; @@ -346,21 +381,15 @@ void MetaMeshPlugin::removeoffset() { } } +/*! + * \brief MetaMeshPlugin::copyselection copy selected elements from the meta mesh + * into the base mesh (select the corresponding elements) + */ void MetaMeshPlugin::copyselection() { if (!metameshsanitychecks(false)) return; using namespace PluginFunctions; removeoffset(); - /* - for (auto bvh : embedding_->GetBaseMesh()->vertices()) { - embedding_->GetBaseMesh()->status(bvh).set_selected(false); - } - for (auto mvh : embedding_->GetMetaMesh()->vertices()) { - embedding_->GetBaseMesh()->status( - embedding_->GetMetaMesh()->property(embedding_->mv_connection_, mvh)).set_selected( - embedding_->GetMetaMesh()->status(mvh).selected()); - } - */ for (auto bheh : embedding_->GetBaseMesh()->halfedges()) { embedding_->GetBaseMesh()->status(bheh).set_selected(false); } @@ -382,28 +411,14 @@ void MetaMeshPlugin::copyselection() { auto bheh = embedding_->GetMetaMesh()->property(embedding_->mhe_connection_, embedding_->GetMetaMesh()->halfedge_handle(meh, 0)); auto beh = embedding_->GetBaseMesh()->edge_handle(bheh); - //*/ embedding_->GetBaseMesh()->status(beh).set_selected( embedding_->GetMetaMesh()->status(meh).selected()); - /*/ - embedding_->GetBaseMesh()->status(bheh).set_selected( - embedding_->GetMetaMesh()->status(meh).selected()); - embedding_->GetBaseMesh()->status( - embedding_->GetBaseMesh()->opposite_halfedge_handle(bheh)).set_selected( - embedding_->GetMetaMesh()->status(meh).selected()); - /*/ - while (embedding_->GetBaseMesh()->status(/*bheh*/beh).selected() && + while (embedding_->GetBaseMesh()->status(beh).selected() && embedding_->GetBaseMesh()->property(embedding_->next_heh_, bheh) != OpenMesh::PolyConnectivity::InvalidHalfedgeHandle) { bheh = embedding_->GetBaseMesh()->property(embedding_->next_heh_, bheh); auto beh = embedding_->GetBaseMesh()->edge_handle(bheh); - //*/ embedding_->GetBaseMesh()->status(beh).set_selected(true); - /*/ - embedding_->GetBaseMesh()->status(bheh).set_selected(true); - embedding_->GetBaseMesh()->status(embedding_->GetBaseMesh()-> - opposite_halfedge_handle(bheh)).set_selected(true); - /*/ } } @@ -412,10 +427,13 @@ void MetaMeshPlugin::copyselection() { addoffset(); emit updatedObject(base_mesh_id_, UPDATE_SELECTION); UpdateMetaMesh(UPDATE_SELECTION); - //emit updateView(); } -void MetaMeshPlugin::markmetaV() { +/*! + * \brief MetaMeshPlugin::DummySlotFunction1 function for the first dummy button, + * used to test various things on the mesh + */ +void MetaMeshPlugin::DummySlotFunction1() { using namespace PluginFunctions; for (auto bheh : embedding_->GetBaseMesh()->halfedges()) { if (embedding_->GetMetaMesh()->is_valid_handle( @@ -424,89 +442,28 @@ void MetaMeshPlugin::markmetaV() { embedding_->GetBaseMesh()->status(bheh).set_selected(true); } } - /* - for (auto* o : objects(TARGET_OBJECTS, DATA_POLY_MESH)) { - auto testmesh = polyMesh(o->id()); - for (auto heh : testmesh->halfedges()) { - testmesh->status(heh).set_selected(true); - if (testmesh->is_boundary(heh)) { - qDebug() << "Found boundary " << heh.idx(); - testmesh->status(heh).set_selected(true); - } - } - emit updatedObject(o->id(), UPDATE_SELECTION); - } - for (auto* o : objects(TARGET_OBJECTS, DATA_TRIANGLE_MESH)) { - auto testmesh = triMesh(o->id()); - for (auto heh : testmesh->halfedges()) { - testmesh->status(heh).set_selected(true); - if (testmesh->is_boundary(heh)) { - qDebug() << "Found boundary " << heh.idx(); - testmesh->status(heh).set_selected(true); - } - } - emit updatedObject(o->id(), UPDATE_SELECTION); - } - return; - */ - /* - for (auto bheh : embedding_->GetBaseMesh()->halfedges()) { - if (embedding_->GetBaseMesh()->is_boundary(bheh)) { - embedding_->GetBaseMesh()->status(bheh).set_selected(true); - } - } - */ - /* - for (auto bheh : embedding_->GetBaseMesh()->halfedges()) { - double w = embedding_->GetBaseMesh()->property(embedding_->halfedge_weight_, bheh); - if (w > 1.0) { - embedding_->GetBaseMesh()->status(bheh).set_selected(true); - } - if (w > 2.0) { - embedding_->GetBaseMesh()->status(embedding_->GetBaseMesh()->edge_handle(bheh)) - .set_selected(true); - } - } - */ - //emit updatedObject(meta_mesh_id_, UPDATE_SELECTION); emit updatedObject(base_mesh_id_, UPDATE_SELECTION); } -void MetaMeshPlugin::markmetaHE() { +/*! + * \brief MetaMeshPlugin::DummySlotFunction2 function for the first dummy button, + * used to test various things on the mesh + */ +void MetaMeshPlugin::DummySlotFunction2() { using namespace PluginFunctions; for (auto mheh : meta_mesh_->halfedges()) { if (meta_mesh_->is_boundary(mheh)) { meta_mesh_->status(mheh).set_selected(true); } } - /* - for (auto mheh : embedding_->GetMetaMesh()->halfedges()) { - if (embedding_->GetMetaMesh()->is_valid_handle(mheh) - && !embedding_->GetMetaMesh()->status(mheh).deleted() - && embedding_->GetMetaMesh()->is_boundary(mheh)) { - embedding_->GetMetaMesh()->status(mheh).set_selected(true); - } - } - */ - /* - for (auto bvh : embedding_->GetBaseMesh()->vertices()) { - auto mvh = embedding_->GetBaseMesh()->property(embedding_->bv_connection_, bvh); - if (embedding_->GetMetaMesh()->is_valid_handle(mvh)) { - embedding_->GetBaseMesh()->status(bvh).set_selected(true); - } - } - emit updatedObject(base_mesh_id_, UPDATE_SELECTION); - for (auto bheh : embedding_->GetBaseMesh()->halfedges()) { - auto mheh = embedding_->GetBaseMesh()->property(embedding_->bhe_connection_, bheh); - if (embedding_->GetMetaMesh()->is_valid_handle(mheh)) { - embedding_->GetBaseMesh()->status(bheh).set_selected(true); - } - } - */ emit updatedObject(meta_mesh_id_, UPDATE_SELECTION); emit updatedObject(base_mesh_id_, UPDATE_SELECTION); } +/*! + * \brief MetaMeshPlugin::nxt move all selections on meta halfedges forward to their + * next_halfedge_handle + */ void MetaMeshPlugin::nxt() { if (!metameshsanitychecks()) return; @@ -544,6 +501,10 @@ void MetaMeshPlugin::nxt() { UpdateMetaMesh(UPDATE_SELECTION_HALFEDGES); } +/*! + * \brief MetaMeshPlugin::opp move all selections of meta halfedges to + * their opposite_halfedge_handle + */ void MetaMeshPlugin::opp() { if (!metameshsanitychecks()) return; @@ -581,6 +542,10 @@ void MetaMeshPlugin::opp() { UpdateMetaMesh(UPDATE_SELECTION_HALFEDGES); } +/*! + * \brief MetaMeshPlugin::prv move all halfedge selections on the meta mesh + * to their prev_halfedge_handle + */ void MetaMeshPlugin::prv() { if (!metameshsanitychecks()) return; @@ -618,6 +583,12 @@ void MetaMeshPlugin::prv() { UpdateMetaMesh(UPDATE_SELECTION_HALFEDGES); } +/*! + * \brief MetaMeshPlugin::metameshsanitychecks checks a few conditions that make + * visualizing the meta_mesh_ unsafe (crashes the GPUoptimizer or other problems) + * \param verbose + * \return false if the meta mesh should not be virualized + */ bool MetaMeshPlugin::metameshsanitychecks(bool verbose) { if (meta_mesh_ == nullptr) { if (verbose) @@ -638,24 +609,39 @@ bool MetaMeshPlugin::metameshsanitychecks(bool verbose) { return true; } +/*! + * \brief MetaMeshPlugin::MetaMeshUpdateNormals + */ void MetaMeshPlugin::MetaMeshUpdateNormals() { if (metameshsanitychecks(false)) { meta_mesh_->update_normals(); } } +/*! + * \brief MetaMeshPlugin::EmbeddingGarbageCollection + */ void MetaMeshPlugin::EmbeddingGarbageCollection() { if (metameshsanitychecks(false)) { embedding_->MetaGarbageCollection(); } } +/*! + * \brief MetaMeshPlugin::UpdateMetaMesh + * \param _type + */ void MetaMeshPlugin::UpdateMetaMesh(const UpdateType &_type) { if (metameshsanitychecks(false)) { emit updatedObject(meta_mesh_id_, _type); } } +/*! + * \brief MetaMeshPlugin::GetHalfedgeSelection + * \return a list of selected meta halfedges (when they or their corresponding base + * halfedges are selected) + */ std::queue<OpenMesh::HalfedgeHandle> MetaMeshPlugin::GetHalfedgeSelection() { std::queue<OpenMesh::HalfedgeHandle> output; if (widget_->checkbox_copy_markings_->checkState() == Qt::Checked) { @@ -703,6 +689,14 @@ std::queue<OpenMesh::HalfedgeHandle> MetaMeshPlugin::GetHalfedgeSelection() { return output; } +/*! + * \brief MetaMeshPlugin::screenshot updates view and takes(saves) a screenshot + * this function will be handed over to IsotropicRemesher + * \param name filename + * \param dir directory + * \param width dimension X + * \param height dimension Y + */ void MetaMeshPlugin::screenshot(const QString& name, const QString& dir, const int& width, const int& height) { //qDebug() << "screenshotfunction"; @@ -728,12 +722,23 @@ void MetaMeshPlugin::screenshot(const QString& name, const QString& dir, removeoffset(); } -// Functions to be called before an operation changing the mesh +/*! + * \brief MetaMeshPlugin::preoperation functions to be called before operations on the + * mesh are performed. Currently only removes the meta mesh offset, but this wrapper + * is here for consistency with postoperation() + */ void MetaMeshPlugin::preoperation() { removeoffset(); } -// Functions to be called after an operation changing the mesh +/*! + * \brief MetaMeshPlugin::postoperation functions to be called after operations on the + * mesh are performed such as garbage collection, updating normals, adding an offset + * to the meta mesh, colorizing it etc. + * \param typem meta mesh update type eg. UPDATE_SELECTION + * \param typeb base mesh update type eg. UPDATE_TOPOLOGY + * \param verbose + */ void MetaMeshPlugin::postoperation(const UpdateType &typem, const UpdateType &typeb, bool verbose) { if (embedding_->ErrStatus() diff --git a/MetaMeshPlugin.hh b/MetaMeshPlugin.hh index 440a564451979a7f76602914dc97d59efbbfd405..3d109145648b099423ce61be515d75719f63b826 100644 --- a/MetaMeshPlugin.hh +++ b/MetaMeshPlugin.hh @@ -57,8 +57,8 @@ public slots: void remesh(); void togglecopy(); void copyselection(); - void markmetaV(); - void markmetaHE(); + void DummySlotFunction1(); + void DummySlotFunction2(); void nxt(); void opp(); void prv(); diff --git a/MetaMeshToolbox.cc b/MetaMeshToolbox.cc index e5d78a830053bdb6bf8142409e865cbf372f4d0c..0331249a350f9f0aa01263eb729c559fa11c6bdc 100644 --- a/MetaMeshToolbox.cc +++ b/MetaMeshToolbox.cc @@ -43,8 +43,8 @@ MetaMeshToolbox::MetaMeshToolbox(QWidget* parent) : QWidget(parent) button_split_ = new QPushButton("Split"); button_collapse_ = new QPushButton("Collapse"); button_relocate_ = new QPushButton("Relocate"); - button_insert_ = new QPushButton("Insert"); - button_delete_ = new QPushButton("Delete"); + button_dummy1_ = new QPushButton("Insert"); + button_dummy2_ = new QPushButton("Delete"); button_next_ = new QPushButton("nxt"); button_opp_ = new QPushButton("opp"); button_prev_ = new QPushButton("prv"); @@ -89,8 +89,8 @@ MetaMeshToolbox::MetaMeshToolbox(QWidget* parent) : QWidget(parent) layout->addWidget(button_split_, 7, 3, 1, 3); layout->addWidget(button_collapse_, 8, 0, 1, 3); layout->addWidget(button_relocate_, 8, 3, 1, 3); - layout->addWidget(button_insert_, 9, 0, 1, 3); - layout->addWidget(button_delete_, 9, 3, 1, 3); + layout->addWidget(button_dummy1_, 9, 0, 1, 3); + layout->addWidget(button_dummy2_, 9, 3, 1, 3); layout->addWidget(button_next_, 10, 0, 1, 2); layout->addWidget(button_opp_, 10, 2, 1, 2); layout->addWidget(button_prev_, 10, 4, 1, 2); diff --git a/MetaMeshToolbox.hh b/MetaMeshToolbox.hh index 0dbde2ce99bb203b2b7042da4feea78e36e97e90..ebe4ff06a974e5dc93a0e535918bdf871ea4f554 100644 --- a/MetaMeshToolbox.hh +++ b/MetaMeshToolbox.hh @@ -35,8 +35,8 @@ public: QPushButton* button_collapse_; QPushButton* button_relocate_; QPushButton* button_remesh_; - QPushButton* button_insert_; - QPushButton* button_delete_; + QPushButton* button_dummy1_; + QPushButton* button_dummy2_; QPushButton* button_next_; QPushButton* button_opp_; QPushButton* button_prev_; diff --git a/Stopwatch.cc b/Stopwatch.cc index fab696a3d5024b6daac0f47a4c026dc18e87ef53..af9d8b7b955414fc3b66f40db7c7a9ca868d30a3 100644 --- a/Stopwatch.cc +++ b/Stopwatch.cc @@ -1,10 +1,16 @@ #include "Stopwatch.hh" +/*! + * \brief Stopwatch::Stopwatch a simple stopwatch, starts timer when initialized + */ Stopwatch::Stopwatch() { Reset(); } -// Output the elapsed time since creation or the last reset +/*! + * \brief Stopwatch::Delta + * \return the time passed since the last timer reset + */ double Stopwatch::Delta() { auto end = std::chrono::time_point_cast< std::chrono::milliseconds>(std::chrono::system_clock::now()); @@ -12,7 +18,9 @@ double Stopwatch::Delta() { return delta; } -// Resets the stopwatch +/*! + * \brief Stopwatch::Reset reset the timer + */ void Stopwatch::Reset() { start_ = std::chrono::time_point_cast< std::chrono::milliseconds>(std::chrono::system_clock::now()); diff --git a/Testing.cc b/Testing.cc index b8477e42a8450f4e5b4dc0e49b2015683af0db12..b43bdb32b318fa034ac9d7fd5f082239f9f84979 100644 --- a/Testing.cc +++ b/Testing.cc @@ -6,10 +6,19 @@ #define BASE_MESH_ embedding_->base_mesh_ #define META_MESH_ embedding_->meta_mesh_ +/*! + * \brief Testing::Testing + * \param embedding + */ Testing::Testing(Embedding* embedding) : embedding_(embedding) { } +/*! + * \brief Testing::TriangulationTests tests the triangulation, however the bhe_border + * and mhe_border properties cannot be tested properly on meshes with boundaries, thus + * this test is deprecated and disabled for now. + */ void Testing::TriangulationTests() { ResetStop(); if (META_MESH_ == nullptr) { @@ -36,6 +45,10 @@ void Testing::TriangulationTests() { DisplayMeshInformation(); } +/*! + * \brief Testing::MeshTests Calls various tests on the mesh that should always pass. + * These tests do not change the meta mesh + */ void Testing::MeshTests() { ResetStop(); if (META_MESH_ == nullptr) { @@ -61,6 +74,10 @@ void Testing::MeshTests() { DisplayMeshInformation(); } +/*! + * \brief Testing::OperationTests Spams basic operations on the mesh and tests for + * inconsistencies. This will drastically change the meta mesh. + */ void Testing::OperationTests() { ResetStop(); if (META_MESH_ == nullptr) { @@ -84,6 +101,10 @@ void Testing::OperationTests() { qDebug() << "All tests passed, time elapsed: " << delta << "ms."; } +/*! + * \brief Testing::DisplayMeshInformation outputs various information on the meta mesh + * such as numbers of elements, avg. edge valence and standard deviation from it etc. + */ void Testing::DisplayMeshInformation() { unsigned long baseeuler = BASE_MESH_->n_vertices() - BASE_MESH_->n_edges() + BASE_MESH_->n_faces(); @@ -126,6 +147,9 @@ void Testing::DisplayMeshInformation() { << " deviation from 6: " << valencedeviation; } +/*! + * \brief Testing::TestVertices + */ void Testing::TestVertices() { if (META_MESH_->n_vertices() == 0) { qDebug() << "Meta Mesh has no vertices."; @@ -137,6 +161,9 @@ void Testing::TestVertices() { } } +/*! + * \brief Testing::TestHalfedges + */ void Testing::TestHalfedges() { if (META_MESH_->n_halfedges() == 0) { qDebug() << "Meta Mesh has no halfedges."; @@ -151,6 +178,9 @@ void Testing::TestHalfedges() { } } +/*! + * \brief Testing::TestHalfedgesInitialTriangulation + */ void Testing::TestHalfedgesInitialTriangulation() { if (META_MESH_->n_halfedges() == 0) { qDebug() << "Meta Mesh has no halfedges."; @@ -169,6 +199,9 @@ void Testing::TestHalfedgesInitialTriangulation() { } } +/*! + * \brief Testing::TestFaces + */ void Testing::TestFaces() { if (META_MESH_->n_faces() == 0) { qDebug() << "Meta Mesh has no faces."; @@ -180,6 +213,9 @@ void Testing::TestFaces() { } } +/*! + * \brief Testing::TestMetaMesh + */ void Testing::TestMetaMesh() { if (META_MESH_->n_faces() == 0) { qDebug() << "Meta Mesh has no faces."; @@ -191,8 +227,12 @@ void Testing::TestMetaMesh() { } } -// Test that each meta vertex is connected to a corresponding -// base vertex that is also connected to it + +/*! + * \brief Testing::TestVertexConnections + * Test that each meta vertex is connected to a corresponding + * base vertex that is also connected to it + */ void Testing::TestVertexConnections() { Stopwatch* swatch = new Stopwatch(); for (auto mvh : META_MESH_->vertices()) { @@ -210,24 +250,26 @@ void Testing::TestVertexConnections() { qDebug() << "TestVertexConnections passed, time elapsed: " << delta << "ms."; } -// Test that each meta halfedge is connected to a base halfedge that in turn -// is also connected to it and forms a chain of base half_edges connected via -// next_heh until it reaches the meta vertex. +/*! + * \brief Testing::TestHalfedgeConnections + * Test that each meta halfedge is connected to a base halfedge that in turn + * is also connected to it and forms a chain of base half_edges connected via + * next_heh until it reaches the meta vertex. + */ void Testing::TestHalfedgeConnections() { Stopwatch* swatch = new Stopwatch(); for (auto mheh : META_MESH_->halfedges()) { TestHalfedgeConnection(mheh); if (stop_) return; - /* use for retracing - for (auto bheh : BASE_MESH_->halfedges()) { - BASE_MESH_->status(bheh).set_selected(false); - }*/ } double delta = swatch->Delta(); qDebug() << "TestHalfedgeConnections passed, time elapsed: " << delta << "ms."; } -// TestHalfedgeConnections() for a single halfedge +/*! + * \brief Testing::TestHalfedgeConnection + * \param mheh + */ void Testing::TestHalfedgeConnection(OpenMesh::HalfedgeHandle mheh) { auto bheh = META_MESH_->property(embedding_->mhe_connection_, mheh); // Meta Halfedge has a valid connection that has not been deleted @@ -288,7 +330,9 @@ void Testing::TestHalfedgeConnection(OpenMesh::HalfedgeHandle mheh) { if (stop_) return; } -// Test if all halfedge properties are symmetrical +/*! + * \brief Testing::TestHalfedgeSymmetry + */ void Testing::TestHalfedgeSymmetry() { Stopwatch* swatch = new Stopwatch(); for (auto bheh : BASE_MESH_->halfedges()) { @@ -316,7 +360,9 @@ void Testing::TestHalfedgeSymmetry() { qDebug() << "TestHalfedgeSymmetry passed, time elapsed: " << delta << "ms."; } -// Test if all borders are symmetrical +/*! + * \brief Testing::TestVoronoiBorderSymmetry + */ void Testing::TestVoronoiBorderSymmetry() { Stopwatch* swatch = new Stopwatch(); for (auto bheh : BASE_MESH_->halfedges()) { @@ -344,8 +390,11 @@ void Testing::TestVoronoiBorderSymmetry() { qDebug() << "TestVoronoiBorderSymmetry passed, time elapsed: " << delta << "ms."; } -// Ensure the correctness and consistency of the voronoi borders, marked by the -// property handles bhe_border_ and mhe_border_ +/*! + * \brief Testing::TestVoronoiBorderConnectivity + * Ensure the correctness and consistency of the voronoi borders, marked by the + * property handles bhe_border_ and mhe_border_ + */ void Testing::TestVoronoiBorderConnectivity() { Stopwatch* swatch = new Stopwatch(); for (auto mheh : META_MESH_->halfedges()) { @@ -358,6 +407,11 @@ void Testing::TestVoronoiBorderConnectivity() { qDebug() << "TestVoronoiBorderConnectivity passed, time elapsed: " << delta << "ms."; } +/*! + * \brief Testing::TestBorderTraversal + * \param bheh + * \param mheh + */ void Testing::TestBorderTraversal(OpenMesh::HalfedgeHandle bheh, OpenMesh::HalfedgeHandle mheh) { // Test for existence @@ -402,7 +456,10 @@ void Testing::TestBorderTraversal(OpenMesh::HalfedgeHandle bheh, } } -// Make sure the meta mesh is a TriMesh by testing each face +/*! + * \brief Testing::TestTriMesh + * Make sure the meta mesh is a TriMesh by testing each face + */ void Testing::TestTriMesh() { Stopwatch* swatch = new Stopwatch(); for (auto mfh : META_MESH_->faces()) { @@ -419,6 +476,9 @@ void Testing::TestTriMesh() { qDebug() << "TestTriMesh passed, time elapsed: " << delta << "ms."; } +/*! + * \brief Testing::TestMetaMeshHalfedgeConnectivity + */ void Testing::TestMetaMeshHalfedgeConnectivity() { Stopwatch* swatch = new Stopwatch(); for (auto mheh : META_MESH_->halfedges()) { @@ -451,6 +511,10 @@ void Testing::TestMetaMeshHalfedgeConnectivity() { << delta << "ms."; } +/*! + * \brief Testing::TestFlips + * \param nostop + */ void Testing::TestFlips(bool nostop) { Stopwatch* swatch = new Stopwatch(); if (nostop) ResetStop(); @@ -475,6 +539,10 @@ void Testing::TestFlips(bool nostop) { qDebug() << "TestFlips passed, time elapsed: " << delta << "ms."; } +/*! + * \brief Testing::TestSplits + * \param nostop + */ void Testing::TestSplits(bool nostop) { Stopwatch* swatch = new Stopwatch(); if (nostop) ResetStop(); @@ -494,17 +562,13 @@ void Testing::TestSplits(bool nostop) { qDebug() << "TestSplits passed, time elapsed: " << delta << "ms."; } +/*! + * \brief Testing::TestCollapses + * \param nostop + */ void Testing::TestCollapses(bool nostop) { Stopwatch* swatch = new Stopwatch(); if (nostop) ResetStop(); - /* - for (auto mheh : META_MESH_->halfedges()) { - if (embedding_->IsCollapseOkay(mheh)) { - embedding_->Collapse(mheh); - embedding_->GarbageCollection(); - } - } - */ size_t n_e = META_MESH_->n_edges()+1; //qDebug() << "Number of edges: " << META_MESH_->n_edges(); while (n_e > META_MESH_->n_edges()) { @@ -528,11 +592,14 @@ void Testing::TestCollapses(bool nostop) { temp = META_MESH_->n_edges(); } } - //embedding_->CleanMetaMesh(); double delta = swatch->Delta(); qDebug() << "TestCollapses passed, time elapsed: " << delta << "ms."; } +/*! + * \brief Testing::TestRelocation + * \param nostop + */ void Testing::TestRelocation(bool nostop) { Stopwatch* swatch = new Stopwatch(); if (nostop) ResetStop(); @@ -548,6 +615,13 @@ void Testing::TestRelocation(bool nostop) { qDebug() << "TestRelocation passed, time elapsed: " << delta << "ms."; } +/*! + * \brief Testing::VisualAssert like an assert(), but doesn't crash the program. Instead + * stops ongoing tests and visually marks faulty parts in the mesh for visual debugging + * \param condition assert(condition), otherwise -> + * \param message output message if condition fails + * \param visualize visualization if condition fails + */ void Testing::VisualAssert(bool condition, std::string message, std::vector<OpenMesh::VertexHandle> visualize) { if (!condition) { @@ -559,6 +633,10 @@ void Testing::VisualAssert(bool condition, std::string message, } } +/*! + * \brief Testing::VisualizeVertex + * \param bvh vertex to be visualized + */ void Testing::VisualizeVertex(OpenMesh::VertexHandle bvh) { qDebug() << "Marking vertex: " << bvh.idx() << "in white."; auto vertex_colors_pph = BASE_MESH_->vertex_colors_pph();