From 15ba6a294515e696dbf8b4f30d19f80fc6972adc Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Sat, 7 Oct 2023 10:25:16 -0400 Subject: [PATCH 1/2] made tri/tet operations return data instead of a tuple --- src/wmtk/Mesh.hpp | 17 -- src/wmtk/PointMesh.hpp | 2 - src/wmtk/TetMesh.cpp | 16 +- src/wmtk/TetMesh.hpp | 13 +- src/wmtk/TetMeshOperationExecutor.cpp | 14 +- src/wmtk/TetMeshOperationExecutor.hpp | 125 +------------ src/wmtk/TriMesh.cpp | 17 +- src/wmtk/TriMesh.hpp | 7 +- src/wmtk/TriMeshOperationExecutor.cpp | 166 ++---------------- src/wmtk/TriMeshOperationExecutor.hpp | 68 +------ src/wmtk/operations/tri_mesh/EdgeCollapse.cpp | 3 +- src/wmtk/operations/tri_mesh/EdgeSplit.cpp | 3 +- tests/test_2d_operations.cpp | 36 ++-- 13 files changed, 90 insertions(+), 397 deletions(-) diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index 0b330b29cc..e4e2236251 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -76,23 +76,6 @@ class Mesh : public std::enable_shared_from_this void clean(); - // Split and collapse are the two atomic operations we want to support for each type of mesh. - // These functions are intended to be called within an single Operation and - // not on their own and the semantics between each derived Mesh class and - // its SplitEdge and CollapseEdge operations should be treated as internal - // implementation deatils. - // - // As such, the split_edge and collapse_edge functions JUST implement the - // updates to topological updates and any precondition / postcondition checks - // should be implemented by the user. - // - // These functions take in a single tuple, referring to the edge being - // operated on, and return a single tuple that refers to the new topology. - // This returned tuple has specific meaning for each derived Mesh class - - virtual Tuple split_edge(const Tuple& t, Accessor& hash_accessor) = 0; - virtual Tuple collapse_edge(const Tuple& t, Accessor& hash_accessor) = 0; - template MeshAttributeHandle register_attribute( const std::string& name, diff --git a/src/wmtk/PointMesh.hpp b/src/wmtk/PointMesh.hpp index b4ba947c3f..a98f416611 100644 --- a/src/wmtk/PointMesh.hpp +++ b/src/wmtk/PointMesh.hpp @@ -30,8 +30,6 @@ class PointMesh : public Mesh bool is_valid(const Tuple& tuple, ConstAccessor& hash_accessor) const override; - Tuple split_edge(const Tuple&, Accessor&) override { return {}; } - Tuple collapse_edge(const Tuple&, Accessor&) override { return {}; } bool is_connectivity_valid() const override { return true; } protected: diff --git a/src/wmtk/TetMesh.cpp b/src/wmtk/TetMesh.cpp index f1f01f5117..867eb4dca8 100644 --- a/src/wmtk/TetMesh.cpp +++ b/src/wmtk/TetMesh.cpp @@ -226,7 +226,8 @@ Tuple TetMesh::tuple_from_id(const PrimitiveType type, const long gid) const } } -Tuple TetMesh::split_edge(const Tuple& t, Accessor& hash_accessor) +auto TetMesh::split_edge(const Tuple& t, Accessor& hash_accessor) + -> operations::tet_mesh::EdgeOperationData { // prototype // Executor exec; @@ -234,14 +235,17 @@ Tuple TetMesh::split_edge(const Tuple& t, Accessor& hash_accessor) // exec.populate_faces(); // exec.run_split(); - TetMesh::TetMeshOperationExecutor executor(*this, t, hash_accessor); - return executor.split_edge(); + TetMeshOperationExecutor executor(*this, t, hash_accessor); + executor.split_edge(); + return executor; } -Tuple TetMesh::collapse_edge(const Tuple& t, Accessor& hash_accessor) +auto TetMesh::collapse_edge(const Tuple& t, Accessor& hash_accessor) + -> operations::tet_mesh::EdgeOperationData { - TetMesh::TetMeshOperationExecutor executor(*this, t, hash_accessor); - return executor.collapse_edge(); + TetMeshOperationExecutor executor(*this, t, hash_accessor); + executor.collapse_edge(); + return executor; } long TetMesh::id(const Tuple& tuple, PrimitiveType type) const diff --git a/src/wmtk/TetMesh.hpp b/src/wmtk/TetMesh.hpp index 0b34e413f5..cec294f628 100644 --- a/src/wmtk/TetMesh.hpp +++ b/src/wmtk/TetMesh.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include "Mesh.hpp" namespace wmtk { @@ -12,8 +13,12 @@ class TetMesh : public Mesh TetMesh& operator=(const TetMesh& o); TetMesh& operator=(TetMesh&& o); - Tuple split_edge(const Tuple& t, Accessor& hash_accessor) override; - Tuple collapse_edge(const Tuple& t, Accessor& hash_accessor) override; + operations::tet_mesh::EdgeOperationData split_edge( + const Tuple& t, + Accessor& hash_accessor); + operations::tet_mesh::EdgeOperationData collapse_edge( + const Tuple& t, + Accessor& hash_accessor); PrimitiveType top_simplex_type() const override { return PrimitiveType::Tetrahedron; } Tuple switch_tuple(const Tuple& tuple, PrimitiveType type) const override; bool is_ccw(const Tuple& tuple) const override; @@ -62,6 +67,7 @@ class TetMesh : public Mesh // private: protected: + class TetMeshOperationExecutor; MeshAttributeHandle m_vt_handle; MeshAttributeHandle m_et_handle; MeshAttributeHandle m_ft_handle; @@ -75,9 +81,6 @@ class TetMesh : public Mesh Tuple edge_tuple_from_id(long id) const; Tuple face_tuple_from_id(long id) const; Tuple tet_tuple_from_id(long id) const; - - // internal structure that encapsulations the actual execution of split and collapse - class TetMeshOperationExecutor; }; } // namespace wmtk diff --git a/src/wmtk/TetMeshOperationExecutor.cpp b/src/wmtk/TetMeshOperationExecutor.cpp index 9acd02dbfd..b3707dd75a 100644 --- a/src/wmtk/TetMeshOperationExecutor.cpp +++ b/src/wmtk/TetMeshOperationExecutor.cpp @@ -140,8 +140,8 @@ TetMesh::TetMeshOperationExecutor::TetMeshOperationExecutor( , ft_accessor(m.create_accessor(m.m_ft_handle)) , hash_accessor(hash_acc) , m_mesh(m) - , m_operating_tuple(operating_tuple) { + m_operating_tuple = operating_tuple; // store ids of edge and incident vertices m_operating_edge_id = m_mesh.id_edge(m_operating_tuple); m_spine_vids[0] = m_mesh.id_vertex(m_operating_tuple); @@ -241,7 +241,7 @@ void TetMesh::TetMeshOperationExecutor::update_ear_connectivity( ft_accessor.index_access().scalar_attribute(common_fid) = ear_tid; } -Tuple TetMesh::TetMeshOperationExecutor::split_edge() +void TetMesh::TetMeshOperationExecutor::split_edge() { simplex_ids_to_delete = get_split_simplices_to_delete(m_operating_tuple, m_mesh); @@ -653,13 +653,11 @@ Tuple TetMesh::TetMeshOperationExecutor::split_edge() assert(return_local_eid > -1); assert(return_local_fid > -1); const long return_tet_hash = hash_accessor.index_access().scalar_attribute(return_tid); - Tuple ret = + m_output_tuple = Tuple(return_local_vid, return_local_eid, return_local_fid, return_tid, return_tet_hash); - - return ret; } -Tuple TetMesh::TetMeshOperationExecutor::collapse_edge() +void TetMesh::TetMeshOperationExecutor::collapse_edge() { simplex_ids_to_delete = get_collapse_simplices_to_delete(m_operating_tuple, m_mesh); @@ -895,10 +893,8 @@ Tuple TetMesh::TetMeshOperationExecutor::collapse_edge() const long return_tet_hash = hash_accessor.index_access().scalar_attribute(return_tid); - Tuple ret = + m_output_tuple = Tuple(return_local_vid, return_local_eid, return_local_fid, return_tid, return_tet_hash); - - return ret; } std::vector TetMesh::TetMeshOperationExecutor::request_simplex_indices( diff --git a/src/wmtk/TetMeshOperationExecutor.hpp b/src/wmtk/TetMeshOperationExecutor.hpp index 85aa85ebc0..43a31d7204 100644 --- a/src/wmtk/TetMeshOperationExecutor.hpp +++ b/src/wmtk/TetMeshOperationExecutor.hpp @@ -1,10 +1,11 @@ #pragma once +#include #include #include "SimplicialComplex.hpp" #include "TetMesh.hpp" #include "Tuple.hpp" namespace wmtk { -class TetMesh::TetMeshOperationExecutor +class TetMesh::TetMeshOperationExecutor : public operations::tet_mesh::EdgeOperationData { public: TetMeshOperationExecutor(TetMesh& m, const Tuple& operating_tuple, Accessor& hash_acc); @@ -21,107 +22,6 @@ class TetMesh::TetMeshOperationExecutor Accessor ft_accessor; Accessor& hash_accessor; - // - // E --------------- C --------------- F - // \-_ / | \ _-/ - // \ EarTet / | \ EarTet / - // \ tid1 / | \ tid2 / - // \ -_/fid1|fid2\_- / - // \ / --_ | _-- \ / - // \ / __- D -__ \ / - // \ /_-- --_\ / - // A ================= B - // operating edge - // - - /** - * An EarTet is a neighbor of a tet to be deleted in the split/collapse operation - * - */ - struct EarTet - { - long tid = -1; // global tid of the ear, -1 if it doesn't exist - long fid = -1; // global fid of the ear, -1 if it doesn't exist - }; - - /** - * Data on the incident tets of the operating edge - */ - struct IncidentTetData - { - long tid = -1; - std::array ears; - }; - - /** - * @brief structs for split (to be merge with collapse) - * - */ - - struct FaceSplitData - { - long fid_old = -1; - long fid_new_1 = -1; - long fid_new_2 = -1; - long eid_spine_old = -1; - long eid_spine_1 = -1; - long eid_spine_2 = -1; - long eid_split = -1; - }; - - /* - v3 - /\\ - ear1 / \ \ ear2 - / \ \ - / \ \ - / \ \ - / \ \ - / \ _\ v4 - /______________\_ - - v1 e12 v2 - */ - - struct TetSplitData - { - long tid_old = -1; - long tid_new_1 = -1; - long tid_new_2 = -1; - long fid_split = -1; - long v1; - long v2; - long v3; - long v4; - long e12; - long e13; - long e14; - long e23; - long e24; - long e34; - - EarTet ear_tet_1; // switch edge switch face - EarTet ear_tet_2; // switch vertex switch edge switch face - std::array new_face_data; - }; - - struct TetCollapseData - { - long tid_old = -1; - long v1; - long v2; - long v3; - long v4; - long e12; - long e13; - long e14; - long e23; - long e24; - long e34; - - EarTet ear_tet_1; // switch edge switch face - EarTet ear_tet_2; // switch vertex switch edge switch face - }; - /** * @brief gather all simplices that are deleted in a split @@ -155,10 +55,6 @@ class TetMesh::TetMeshOperationExecutor const long old_tid, const long common_fid); - const std::array& incident_vids() const { return m_spine_vids; } - - const long operating_edge_id() const { return m_operating_edge_id; } - /* @@ -184,7 +80,7 @@ class TetMesh::TetMeshOperationExecutor * tet. In the illustration it will return Tuple(v1, v1-v_new, v1-v_new-v4, v1-v_new-v4-v3) * */ - Tuple split_edge(); + void split_edge(); /** * @brief split edge v1-v2 @@ -204,27 +100,14 @@ class TetMesh::TetMeshOperationExecutor * link condition user level? *should return a invalid tuple if no ears?*). * */ - Tuple collapse_edge(); + void collapse_edge(); std::vector request_simplex_indices(const PrimitiveType type, long count); - std::array, 4> simplex_ids_to_delete; - std::vector cell_ids_to_update_hash; TetMesh& m_mesh; - Tuple m_operating_tuple; - private: - // common simplices - std::array m_spine_vids; // two endpoints of the edge - long m_operating_edge_id; - long m_operating_face_id; - long m_operating_tet_id; - - // simplices required per-tet - std::vector m_incident_tet_datas; - IncidentTetData get_incident_tet_data(Tuple t); diff --git a/src/wmtk/TriMesh.cpp b/src/wmtk/TriMesh.cpp index 30039d4aab..a5d6fdf46b 100644 --- a/src/wmtk/TriMesh.cpp +++ b/src/wmtk/TriMesh.cpp @@ -21,17 +21,22 @@ TriMesh::TriMesh(TriMesh&& o) = default; TriMesh& TriMesh::operator=(const TriMesh& o) = default; TriMesh& TriMesh::operator=(TriMesh&& o) = default; -Tuple TriMesh::split_edge(const Tuple& t, Accessor& hash_accessor) +auto TriMesh::split_edge(const Tuple& t, Accessor& hash_accessor) -> + + operations::tri_mesh::EdgeOperationData { // TODO record the deleted simplices topology attributes - TriMesh::TriMeshOperationExecutor executor(*this, t, hash_accessor); - return executor.split_edge(); + TriMeshOperationExecutor executor(*this, t, hash_accessor); + executor.split_edge(); + return executor; } -Tuple TriMesh::collapse_edge(const Tuple& t, Accessor& hash_accessor) +auto TriMesh::collapse_edge(const Tuple& t, Accessor& hash_accessor) + -> operations::tri_mesh::EdgeOperationData { - TriMesh::TriMeshOperationExecutor executor(*this, t, hash_accessor); - return executor.collapse_edge(); + TriMeshOperationExecutor executor(*this, t, hash_accessor); + executor.collapse_edge(); + return executor; } long TriMesh::id(const Tuple& tuple, PrimitiveType type) const diff --git a/src/wmtk/TriMesh.hpp b/src/wmtk/TriMesh.hpp index f245520978..b7a4d32b81 100644 --- a/src/wmtk/TriMesh.hpp +++ b/src/wmtk/TriMesh.hpp @@ -2,6 +2,7 @@ #include "Mesh.hpp" #include "Tuple.hpp" +#include #include @@ -23,7 +24,7 @@ class TriMesh : public Mesh * The returned tuple contains the new vertex. The face lies in the region where the input tuple * face was, and the edge is oriented in the same direction as in the input. */ - Tuple split_edge(const Tuple& t, Accessor& hash_accessor) override; + operations::tri_mesh::EdgeOperationData split_edge(const Tuple& t, Accessor& hash_accessor); /** * @brief collapse edge t * @@ -32,7 +33,7 @@ class TriMesh : public Mesh * collapsed. The face is chosen such that the orientation of the tuple is the same as in the * input. If this is not possible due to a boundary, the opposite face is chosen. */ - Tuple collapse_edge(const Tuple& t, Accessor& hash_accessor) override; + operations::tri_mesh::EdgeOperationData collapse_edge(const Tuple& t, Accessor& hash_accessor); Tuple switch_tuple(const Tuple& tuple, PrimitiveType type) const override; @@ -97,7 +98,7 @@ class TriMesh : public Mesh Tuple edge_tuple_from_id(long id) const; Tuple face_tuple_from_id(long id) const; - // internal structure that encapsulations the actual execution of split and collapse + class TriMeshOperationExecutor; static Tuple with_different_cid(const Tuple& t, long cid); }; diff --git a/src/wmtk/TriMeshOperationExecutor.cpp b/src/wmtk/TriMeshOperationExecutor.cpp index d9875c85fb..52c158669b 100644 --- a/src/wmtk/TriMeshOperationExecutor.cpp +++ b/src/wmtk/TriMeshOperationExecutor.cpp @@ -3,8 +3,7 @@ namespace wmtk { -TriMesh::TriMeshOperationExecutor::IncidentFaceData -TriMesh::TriMeshOperationExecutor::get_incident_face_data(Tuple t) +auto TriMesh::TriMeshOperationExecutor::get_incident_face_data(Tuple t) -> IncidentFaceData { // / \ // ear1 / \ ear2 @@ -63,9 +62,9 @@ TriMesh::TriMeshOperationExecutor::TriMeshOperationExecutor( , ef_accessor(m.create_accessor(m.m_ef_handle)) , hash_accessor(hash_acc) , m_mesh(m) - , m_operating_tuple(operating_tuple) { + m_operating_tuple = operating_tuple; // store ids of edge and incident vertices m_operating_edge_id = m_mesh.id_edge(m_operating_tuple); m_spine_vids[0] = m_mesh.id_vertex(m_operating_tuple); @@ -223,11 +222,11 @@ void TriMesh::TriMeshOperationExecutor::connect_faces_across_spine() // find the local eid of the spine of the two side of faces assert(m_incident_face_datas.size() == 2); const long f_old_top = m_incident_face_datas[0].fid; - const long f0_top = m_incident_face_datas[0].split_f0; - const long f1_top = m_incident_face_datas[0].split_f1; + const long f0_top = m_incident_face_datas[0].split_f[0]; + const long f1_top = m_incident_face_datas[0].split_f[1]; const long f_old_bottom = m_incident_face_datas[1].fid; - const long f0_bottom = m_incident_face_datas[1].split_f0; - const long f1_bottom = m_incident_face_datas[1].split_f1; + const long f0_bottom = m_incident_face_datas[1].split_f[0]; + const long f1_bottom = m_incident_face_datas[1].split_f[1]; auto ff_old_top = ff_accessor.index_access().vector_attribute(f_old_top); auto ff_old_bottom = ff_accessor.index_access().vector_attribute(f_old_bottom); assert(m_mesh.capacity(PrimitiveType::Face) > f0_top); @@ -266,8 +265,8 @@ void TriMesh::TriMeshOperationExecutor::replace_incident_face( std::vector new_fids = this->request_simplex_indices(PrimitiveType::Face, 2); assert(new_fids.size() == 2); - face_data.split_f0 = new_fids[0]; - face_data.split_f1 = new_fids[1]; + face_data.split_f[0] = new_fids[0]; + face_data.split_f[1] = new_fids[1]; std::vector splitting_edges = this->request_simplex_indices(PrimitiveType::Edge, 1); assert(splitting_edges[0] > -1); // TODO: is this assert reasonable at all? @@ -394,102 +393,12 @@ TriMesh::TriMeshOperationExecutor::prepare_operating_tuples_for_child_meshes() c return vec_t_child; } -Tuple TriMesh::TriMeshOperationExecutor::split_edge() +void TriMesh::TriMeshOperationExecutor::split_edge() { - return split_edge_single_mesh(); - /* - if (!m_mesh.multi_mesh_manager.is_parent_mesh()) { - return split_edge_single_mesh(); - } else { - std::vector> vec_t_child = prepare_operating_tuples_for_child_meshes(); - - // do split on parent_mesh - Tuple ret_tuple = split_edge_single_mesh(); - - for (auto child_mesh_ptr : m_mesh.multi_mesh_manager.child_meshes) { - long child_id = child_mesh_ptr->multi_mesh_manager.child_id(); - if (child_mesh_ptr->top_simplex_type() == PrimitiveType::Face) { - // this child_mesh is a TriMesh - TriMesh& child_tri_mesh = *std::static_pointer_cast(child_mesh_ptr); - - std::vector> child_new_cell_ids; - for (long i = 0; i < long(m_incident_face_datas.size()); ++i) { - Tuple t_child = vec_t_child[i][child_id]; - if (t_child.is_null()) { - if (child_new_cell_ids.size() <= i) child_new_cell_ids.emplace_back(-1, -1); - continue; - } - auto child_hash_acc = child_tri_mesh.get_cell_hash_accessor(); - TriMesh::TriMeshOperationExecutor executor_child( - child_tri_mesh, - t_child, - child_hash_acc); - executor_child.split_edge(); - for (auto child_incident_face_data : executor_child.m_incident_face_datas) { - child_new_cell_ids.emplace_back( - child_incident_face_data.split_f0, - child_incident_face_data.split_f1); - } - } - - assert(child_new_cell_ids.size() == m_incident_face_datas.size()); - - // update_hash on new cells - for (long i = 0; i < long(m_incident_face_datas.size()); i++) { - const auto& split_fs_child = child_new_cell_ids[i]; - long split_f0_child = split_fs_child.first; - long split_f1_child = split_fs_child.second; - - const auto& incident_face_data = m_incident_face_datas[i]; - long split_f0_parent = incident_face_data.split_f0; - long split_f1_parent = incident_face_data.split_f1; - - Tuple tuple_child = (split_f0_child == -1) - ? Tuple() - : child_tri_mesh.face_tuple_from_id(split_f0_child); - Tuple tuple_parent = m_mesh.face_tuple_from_id(split_f0_parent); - - if (!tuple_child.is_null()) { - MultiMeshManager::write_tuple_map_attribute( - child_tri_mesh.multi_mesh_manager.map_to_parent_handle, - child_tri_mesh, - tuple_child, - tuple_parent); - } - MultiMeshManager::write_tuple_map_attribute( - m_mesh.multi_mesh_manager.map_to_child_handles[child_id], - m_mesh, - tuple_parent, - tuple_child); - - tuple_child = (split_f1_child == -1) - ? Tuple() - : child_tri_mesh.face_tuple_from_id(split_f1_child); - tuple_parent = m_mesh.face_tuple_from_id(split_f1_parent); - if (!tuple_child.is_null()) { - MultiMeshManager::write_tuple_map_attribute( - child_tri_mesh.multi_mesh_manager.map_to_parent_handle, - child_tri_mesh, - tuple_child, - tuple_parent); - } - MultiMeshManager::write_tuple_map_attribute( - m_mesh.multi_mesh_manager.map_to_child_handles[child_id], - m_mesh, - tuple_parent, - tuple_child); - } - - // update_hash on neighboring cells - update_hash_in_map(child_tri_mesh); - } - } - return ret_tuple; - } -*/ + split_edge_single_mesh(); } -Tuple TriMesh::TriMeshOperationExecutor::split_edge_single_mesh() +void TriMesh::TriMeshOperationExecutor::split_edge_single_mesh() { simplex_ids_to_delete = get_split_simplices_to_delete(m_operating_tuple, m_mesh); @@ -513,8 +422,8 @@ Tuple TriMesh::TriMeshOperationExecutor::split_edge_single_mesh() update_cell_hash(); delete_simplices(); // return Tuple new_fid, new_vid that points - const long new_tuple_fid = m_incident_face_datas[0].split_f1; - Tuple ret = m_mesh.edge_tuple_from_id(new_eids[1]); + const long new_tuple_fid = m_incident_face_datas[0].split_f[1]; + Tuple& ret = m_output_tuple = m_mesh.edge_tuple_from_id(new_eids[1]); if (m_mesh.id_vertex(ret) != v_new) { ret = m_mesh.switch_vertex(ret); } @@ -522,9 +431,6 @@ Tuple TriMesh::TriMeshOperationExecutor::split_edge_single_mesh() ret = m_mesh.switch_face(ret); } assert(m_mesh.is_valid_slow(ret)); - - return ret; - // return m_mesh.with_different_cid(m_operating_tuple, m_incident_face_datas[0].split_f0); } void TriMesh::TriMeshOperationExecutor::update_hash_in_map(TriMesh& child_mesh) @@ -568,49 +474,13 @@ void TriMesh::TriMeshOperationExecutor::update_hash_in_map(TriMesh& child_mesh) */ } -Tuple TriMesh::TriMeshOperationExecutor::collapse_edge() +void TriMesh::TriMeshOperationExecutor::collapse_edge() { - return collapse_edge_single_mesh(); - /* - if (!m_mesh.multi_mesh_manager.is_parent_mesh()) { - return collapse_edge_single_mesh(); - } else { - std::vector> vec_t_child = prepare_operating_tuples_for_child_meshes(); - - // do collapse on parent_mesh - Tuple ret_tuple = collapse_edge_single_mesh(); - - for (auto child_mesh_ptr : m_mesh.multi_mesh_manager.child_meshes) { - long child_id = child_mesh_ptr->multi_mesh_manager.child_id(); - - if (child_mesh_ptr->top_simplex_type() == PrimitiveType::Face) { - // this child_mesh is a TriMesh - TriMesh& child_tri_mesh = *std::static_pointer_cast(child_mesh_ptr); - - for (long i = 0; i < long(m_incident_face_datas.size()); ++i) { - Tuple t_child = vec_t_child[i][child_id]; - if (t_child.is_null()) { - continue; - } - auto child_hash_acc = child_tri_mesh.get_cell_hash_accessor(); - TriMesh::TriMeshOperationExecutor executor_child( - child_tri_mesh, - t_child, - child_hash_acc); - executor_child.collapse_edge(); - } - // update_hash - update_hash_in_map(child_tri_mesh); - } - } - - return ret_tuple; - } - */ + collapse_edge_single_mesh(); } -Tuple TriMesh::TriMeshOperationExecutor::collapse_edge_single_mesh() +void TriMesh::TriMeshOperationExecutor::collapse_edge_single_mesh() { simplex_ids_to_delete = get_collapse_simplices_to_delete(m_operating_tuple, m_mesh); @@ -646,7 +516,7 @@ Tuple TriMesh::TriMeshOperationExecutor::collapse_edge_single_mesh() update_cell_hash(); delete_simplices(); - Tuple ret = m_mesh.edge_tuple_from_id(ret_eid); + Tuple& ret = m_output_tuple = m_mesh.edge_tuple_from_id(ret_eid); if (m_mesh.id_vertex(ret) != ret_vid) { ret = m_mesh.switch_vertex(ret); } @@ -658,8 +528,6 @@ Tuple TriMesh::TriMeshOperationExecutor::collapse_edge_single_mesh() assert(m_mesh.is_valid_slow(ret)); - return ret; - // return a ccw tuple from left ear if it exists, otherwise return a ccw tuple from right ear // return m_mesh.tuple_from_id(PrimitiveType::Vertex, v1); } diff --git a/src/wmtk/TriMeshOperationExecutor.hpp b/src/wmtk/TriMeshOperationExecutor.hpp index da0b2fe376..5a89cfe291 100644 --- a/src/wmtk/TriMeshOperationExecutor.hpp +++ b/src/wmtk/TriMeshOperationExecutor.hpp @@ -1,10 +1,13 @@ #pragma once +#include #include #include "SimplicialComplex.hpp" #include "TriMesh.hpp" #include "Tuple.hpp" namespace wmtk { -class TriMesh::TriMeshOperationExecutor + + +class TriMesh::TriMeshOperationExecutor : public operations::tri_mesh::EdgeOperationData { public: TriMeshOperationExecutor(TriMesh& m, const Tuple& operating_tuple, Accessor& hash_acc); @@ -20,44 +23,6 @@ class TriMesh::TriMeshOperationExecutor Accessor& hash_accessor; - // C - // / \ . - // F1 / \ F2 - // / \ . - // / \ . - // A----------B - // \ / - // \ / - // F1' \ / F2' - // \ / - // C' - // the neighbors are stored in the order of A, B, C, D if they exist - // vid, ear fid (-1 if it doesn't exit), ear eid - - /** - * An ear is a face that is adjacent to a face that is incident to the edge on which the - * operation is performed. In other words, the ears are the neighboring faces to the ones that - * will be deleted by the operation. - */ - struct EarFace - { - long fid = -1; // global fid of the ear, -1 if it doesn't exist - long eid = -1; // global eid of the ear, -1 if it doesn't exist - }; - - /** - * Data on the incident face relevant for performing operations. - */ - struct IncidentFaceData - { - long opposite_vid = -1; // opposing vid - long fid = -1; // the face that will be deleted - long split_f0 = -1; - long split_f1 = -1; - Tuple local_operating_tuple; // the copy of edge m_operating_tuple in face(fid) - std::array ears; // ear - }; - /** * @brief gather all simplices that are deleted in a split * @@ -78,11 +43,6 @@ class TriMesh::TriMeshOperationExecutor const Tuple& tuple, const TriMesh& m); - std::vector& incident_face_datas() { return m_incident_face_datas; } - - const std::array& incident_vids() const { return m_spine_vids; } - - long operating_edge_id() const { return m_operating_edge_id; } void update_ids_in_ear( const long ear_fid, @@ -92,10 +52,10 @@ class TriMesh::TriMeshOperationExecutor void connect_ears(); - Tuple split_edge(); - Tuple collapse_edge(); - Tuple split_edge_single_mesh(); - Tuple collapse_edge_single_mesh(); + void split_edge(); + void collapse_edge(); + void split_edge_single_mesh(); + void collapse_edge_single_mesh(); /** * @brief @@ -111,23 +71,13 @@ class TriMesh::TriMeshOperationExecutor void connect_faces_across_spine(); std::vector request_simplex_indices(const PrimitiveType type, long count); - std::array, 3> simplex_ids_to_delete; - std::vector cell_ids_to_update_hash; TriMesh& m_mesh; - Tuple m_operating_tuple; - -private: std::vector> prepare_operating_tuples_for_child_meshes() const; void update_hash_in_map(TriMesh& child_mesh); - // common simplicies - std::array m_spine_vids; // V_A_id, V_B_id; - long m_operating_edge_id; - - // simplices required per-face - std::vector m_incident_face_datas; IncidentFaceData get_incident_face_data(Tuple t); }; + } // namespace wmtk diff --git a/src/wmtk/operations/tri_mesh/EdgeCollapse.cpp b/src/wmtk/operations/tri_mesh/EdgeCollapse.cpp index 1a4083192c..7d59bac317 100644 --- a/src/wmtk/operations/tri_mesh/EdgeCollapse.cpp +++ b/src/wmtk/operations/tri_mesh/EdgeCollapse.cpp @@ -56,7 +56,8 @@ EdgeCollapse::EdgeCollapse( bool EdgeCollapse::execute() { - m_output_tuple = mesh().collapse_edge(input_tuple(), hash_accessor()); + auto data = mesh().collapse_edge(input_tuple(), hash_accessor()); + m_output_tuple = data.m_output_tuple; return true; } diff --git a/src/wmtk/operations/tri_mesh/EdgeSplit.cpp b/src/wmtk/operations/tri_mesh/EdgeSplit.cpp index 45030efe66..fad19d1340 100644 --- a/src/wmtk/operations/tri_mesh/EdgeSplit.cpp +++ b/src/wmtk/operations/tri_mesh/EdgeSplit.cpp @@ -38,7 +38,8 @@ EdgeSplit::EdgeSplit(Mesh& m, const Tuple& t, const OperationSettings bool EdgeSplit::execute() { // move vertex to center of old vertices - m_output_tuple = mesh().split_edge(input_tuple(), hash_accessor()); + auto data = mesh().split_edge(input_tuple(), hash_accessor()); + m_output_tuple = data.m_output_tuple; // for(const acc: tri_accessors) { // ConstACcessor old_tri_acc(acc, checkpoint); diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 511c37ddca..bc9d48dbb3 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -431,7 +431,7 @@ TEST_CASE("hash_update", "[operations][2D]") Accessor hash_accessor = m.get_cell_hash_accessor(); auto executor = m.get_tmoe(edge, hash_accessor); - //auto& ha = executor.hash_accessor; + // auto& ha = executor.hash_accessor; CHECK(m.get_cell_hash_slow(0) == 0); @@ -448,7 +448,7 @@ TEST_CASE("hash_update", "[operations][2D]") Accessor hash_accessor = m.get_cell_hash_accessor(); auto executor = m.get_tmoe(edge, hash_accessor); - //auto& ha = executor.hash_accessor; + // auto& ha = executor.hash_accessor; CHECK(m.get_cell_hash_slow(0) == 0); CHECK(m.get_cell_hash_slow(1) == 0); @@ -490,10 +490,10 @@ TEST_CASE("connect_faces_across_spine", "[operations][split][2D]") REQUIRE(executor.incident_face_datas().size() == 2); const auto new_fids = executor.request_simplex_indices(PF, 4); - long& f0_top = incident_face_datas[0].split_f0; - long& f1_top = incident_face_datas[0].split_f1; - long& f0_bottom = incident_face_datas[1].split_f0; - long& f1_bottom = incident_face_datas[1].split_f1; + long& f0_top = incident_face_datas[0].split_f[0]; + long& f1_top = incident_face_datas[0].split_f[1]; + long& f0_bottom = incident_face_datas[1].split_f[0]; + long& f1_bottom = incident_face_datas[1].split_f[1]; f0_top = new_fids[0]; f1_top = new_fids[2]; f0_bottom = new_fids[1]; @@ -540,8 +540,8 @@ TEST_CASE("replace_incident_face", "[operations][split][2D]") } REQUIRE(incident_face_datas.size() == 1); - const long& f0 = incident_face_datas[0].split_f0; - const long& f1 = incident_face_datas[0].split_f1; + const long& f0 = incident_face_datas[0].split_f[0]; + const long& f1 = incident_face_datas[0].split_f[1]; const long& se0 = spine_eids[0]; const long& se1 = spine_eids[1]; const long& ee0 = incident_face_datas[0].ears[0].eid; @@ -633,8 +633,8 @@ TEST_CASE("replace_incident_face", "[operations][split][2D]") // top { - const long& f0 = incident_face_datas[0].split_f0; - const long& f1 = incident_face_datas[0].split_f1; + const long& f0 = incident_face_datas[0].split_f[0]; + const long& f1 = incident_face_datas[0].split_f[1]; const long& ee0 = incident_face_datas[0].ears[0].eid; const long& ee1 = incident_face_datas[0].ears[1].eid; @@ -675,8 +675,8 @@ TEST_CASE("replace_incident_face", "[operations][split][2D]") } // bottom { - const long& f0 = incident_face_datas[1].split_f0; - const long& f1 = incident_face_datas[1].split_f1; + const long& f0 = incident_face_datas[1].split_f[0]; + const long& f1 = incident_face_datas[1].split_f[1]; const long& ee0 = incident_face_datas[1].ears[0].eid; const long& ee1 = incident_face_datas[1].ears[1].eid; @@ -872,7 +872,7 @@ TEST_CASE("split_return_tuple", "[operations][split][2D]") const Tuple edge = m.edge_tuple_between_v1_v2(1, 2, 0); Accessor hash_accessor = m.get_cell_hash_accessor(); - const Tuple ret = m.split_edge(edge, hash_accessor); + const Tuple ret = m.split_edge(edge, hash_accessor).m_output_tuple; REQUIRE(m.is_connectivity_valid()); REQUIRE(m.is_valid_slow(ret)); CHECK(m.id(ret, PV) == 3); @@ -886,7 +886,7 @@ TEST_CASE("split_return_tuple", "[operations][split][2D]") const Tuple edge = m.edge_tuple_between_v1_v2(2, 1, 0); Accessor hash_accessor = m.get_cell_hash_accessor(); - const Tuple ret = m.split_edge(edge, hash_accessor); + const Tuple ret = m.split_edge(edge, hash_accessor).m_output_tuple; REQUIRE(m.is_connectivity_valid()); REQUIRE(m.is_valid_slow(ret)); CHECK(m.id(ret, PV) == 3); @@ -900,7 +900,7 @@ TEST_CASE("split_return_tuple", "[operations][split][2D]") const Tuple edge = m.edge_tuple_between_v1_v2(2, 1, 1); Accessor hash_accessor = m.get_cell_hash_accessor(); - const Tuple ret = m.split_edge(edge, hash_accessor); + const Tuple ret = m.split_edge(edge, hash_accessor).m_output_tuple; REQUIRE(m.is_connectivity_valid()); REQUIRE(m.is_valid_slow(ret)); CHECK(m.id(ret, PV) == 6); @@ -1065,7 +1065,7 @@ TEST_CASE("collapse_return_tuple", "[operations][collapse][2D]") REQUIRE(m.is_connectivity_valid()); const Tuple edge = m.edge_tuple_between_v1_v2(4, 5, 2); - const Tuple ret = m.collapse_edge(edge, hash_accessor); + const Tuple ret = m.collapse_edge(edge, hash_accessor).m_output_tuple; REQUIRE(m.is_valid_slow(ret)); REQUIRE(m.is_connectivity_valid()); // CHECK(op.is_return_tuple_from_left_ear() == false); @@ -1079,7 +1079,7 @@ TEST_CASE("collapse_return_tuple", "[operations][collapse][2D]") REQUIRE(m.is_connectivity_valid()); const Tuple edge = m.edge_tuple_between_v1_v2(3, 4, 0); - const Tuple ret = m.collapse_edge(edge, hash_accessor); + const Tuple ret = m.collapse_edge(edge, hash_accessor).m_output_tuple; REQUIRE(m.is_connectivity_valid()); // CHECK(op.is_return_tuple_from_left_ear() == false); @@ -1092,7 +1092,7 @@ TEST_CASE("collapse_return_tuple", "[operations][collapse][2D]") REQUIRE(m.is_connectivity_valid()); const Tuple edge = m.edge_tuple_between_v1_v2(4, 3, 0); - const Tuple ret = m.collapse_edge(edge, hash_accessor); + const Tuple ret = m.collapse_edge(edge, hash_accessor).m_output_tuple; REQUIRE(m.is_connectivity_valid()); CHECK(m.id(ret, PV) == 3); From 3f240ebf7d09dd752a188af88720a438ec5fa131 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Sat, 7 Oct 2023 10:30:29 -0400 Subject: [PATCH 2/2] adding missing structs for edge op data --- .../operations/tet_mesh/EdgeOperationData.hpp | 134 ++++++++++++++++++ .../operations/tri_mesh/EdgeOperationData.hpp | 73 ++++++++++ 2 files changed, 207 insertions(+) create mode 100644 src/wmtk/operations/tet_mesh/EdgeOperationData.hpp create mode 100644 src/wmtk/operations/tri_mesh/EdgeOperationData.hpp diff --git a/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp b/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp new file mode 100644 index 0000000000..140ddc1f64 --- /dev/null +++ b/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp @@ -0,0 +1,134 @@ +#pragma once +#include +#include +#include + +namespace wmtk::operations::tet_mesh { +struct EdgeOperationData +{ + + // + // E --------------- C --------------- F + // \-_ / | \ _-/ + // \ EarTet / | \ EarTet / + // \ tid1 / | \ tid2 / + // \ -_/fid1|fid2\_- / + // \ / --_ | _-- \ / + // \ / __- D -__ \ / + // \ /_-- --_\ / + // A ================= B + // operating edge + // + + /** + * An EarTet is a neighbor of a tet to be deleted in the split/collapse operation + * + */ + struct EarTet + { + long tid = -1; // global tid of the ear, -1 if it doesn't exist + long fid = -1; // global fid of the ear, -1 if it doesn't exist + }; + + /** + * Data on the incident tets of the operating edge + */ + struct IncidentTetData + { + long tid = -1; + std::array ears; + }; + + /** + * @brief structs for split (to be merge with collapse) + * + */ + + struct FaceSplitData + { + long fid_old = -1; + long fid_new_1 = -1; + long fid_new_2 = -1; + long eid_spine_old = -1; + long eid_spine_1 = -1; + long eid_spine_2 = -1; + long eid_split = -1; + }; + + /* + v3 + /\\ + ear1 / \ \ ear2 + / \ \ + / \ \ + / \ \ + / \ \ + / \ _\ v4 + /______________\_ - + v1 e12 v2 + */ + + struct TetSplitData + { + long tid_old = -1; + long tid_new_1 = -1; + long tid_new_2 = -1; + long fid_split = -1; + long v1; + long v2; + long v3; + long v4; + long e12; + long e13; + long e14; + long e23; + long e24; + long e34; + + EarTet ear_tet_1; // switch edge switch face + EarTet ear_tet_2; // switch vertex switch edge switch face + std::array new_face_data; + }; + + struct TetCollapseData + { + long tid_old = -1; + long v1; + long v2; + long v3; + long v4; + long e12; + long e13; + long e14; + long e23; + long e24; + long e34; + + EarTet ear_tet_1; // switch edge switch face + EarTet ear_tet_2; // switch vertex switch edge switch face + }; + + const std::array& incident_vids() const { return m_spine_vids; } + + long operating_edge_id() const { return m_operating_edge_id; } + + + + std::array, 4> simplex_ids_to_delete; + std::vector cell_ids_to_update_hash; + + Tuple m_operating_tuple; + + Tuple m_output_tuple; + +protected: + // common simplices + std::array m_spine_vids; // two endpoints of the edge + long m_operating_edge_id; + long m_operating_face_id; + long m_operating_tet_id; + + // simplices required per-tet + std::vector m_incident_tet_datas; +}; +} diff --git a/src/wmtk/operations/tri_mesh/EdgeOperationData.hpp b/src/wmtk/operations/tri_mesh/EdgeOperationData.hpp new file mode 100644 index 0000000000..e39355c8f0 --- /dev/null +++ b/src/wmtk/operations/tri_mesh/EdgeOperationData.hpp @@ -0,0 +1,73 @@ +#pragma once +#include +#include +#include + +namespace wmtk::operations::tri_mesh { +struct EdgeOperationData +{ + EdgeOperationData() = default; + EdgeOperationData(const EdgeOperationData&) = default; + EdgeOperationData(EdgeOperationData&&) = default; + + EdgeOperationData& operator=(const EdgeOperationData&) = default; + EdgeOperationData& operator=(EdgeOperationData&&) = default; + // C + // / \ . + // F1 / \ F2 + // / \ . + // / \ . + // A----------B + // \ / + // \ / + // F1' \ / F2' + // \ / + // C' + // the neighbors are stored in the order of A, B, C, D if they exist + // vid, ear fid (-1 if it doesn't exit), ear eid + + /** + * An ear is a face that is adjacent to a face that is incident to the edge on which the + * operation is performed. In other words, the ears are the neighboring faces to the ones + * that will be deleted by the operation. + */ + struct EarFace + { + long fid = -1; // global fid of the ear, -1 if it doesn't exist + long eid = -1; // global eid of the ear, -1 if it doesn't exist + }; + + /** + * Data on the incident face relevant for performing operations. + */ + struct IncidentFaceData + { + long opposite_vid = -1; // opposing vid + long fid = -1; // the face that will be deleted + std::array split_f = std::array{{-1, -1}}; + Tuple local_operating_tuple; // the copy of edge m_operating_tuple in face(fid) + std::array ears; // ear + }; + + std::vector& incident_face_datas() { return m_incident_face_datas; } + + const std::array& incident_vids() const { return m_spine_vids; } + + long operating_edge_id() const { return m_operating_edge_id; } + + + std::array, 3> simplex_ids_to_delete; + std::vector cell_ids_to_update_hash; + + Tuple m_operating_tuple; + + Tuple m_output_tuple; // reference tuple for either operation + + // common simplicies + std::array m_spine_vids; // V_A_id, V_B_id; + long m_operating_edge_id; + + // simplices required per-face + std::vector m_incident_face_datas; +}; +} // namespace wmtk::operations::tri_mesh