From ae01ee406306d859083c9e37134e936c3bd4a199 Mon Sep 17 00:00:00 2001 From: FloSewn Date: Mon, 1 Jul 2024 06:43:51 +0200 Subject: [PATCH] Put FontInitData into separate file - add \"is_fixed\" edge property --- src/algorithm/Domain.h | 1 + src/algorithm/Edge.h | 3 +- src/algorithm/Front.h | 255 ++++---------------------------- src/algorithm/FrontInitData.h | 270 ++++++++++++++++++++++++++++++++++ src/algorithm/FrontUpdate.h | 2 +- src/algorithm/MeshBuilder.h | 1 + src/algorithm/TQMesh.h | 1 + 7 files changed, 304 insertions(+), 229 deletions(-) create mode 100644 src/algorithm/FrontInitData.h diff --git a/src/algorithm/Domain.h b/src/algorithm/Domain.h index f39c52e..50b44fb 100644 --- a/src/algorithm/Domain.h +++ b/src/algorithm/Domain.h @@ -446,6 +446,7 @@ class Domain Edge& add_fixed_edge( Vertex& v1, Vertex& v2 ) { Edge& new_edge = fixed_edges_.add_edge(v1, v2, INTERIOR_EDGE_COLOR); + new_edge.add_property( EdgeProperty::is_fixed ); return new_edge; } // Domain::add_fixed_edge() diff --git a/src/algorithm/Edge.h b/src/algorithm/Edge.h index 5b0ee56..1be73d2 100644 --- a/src/algorithm/Edge.h +++ b/src/algorithm/Edge.h @@ -37,7 +37,8 @@ class EdgeList; enum class EdgeProperty : uint8_t { no_property = 0b00000000, on_boundary = 0b00000001, - is_ghost = 0b00000010, + is_fixed = 0b00000010, + is_ghost = 0b00000100, }; // Overloaded bitwise NOT operator diff --git a/src/algorithm/Front.h b/src/algorithm/Front.h index 760b128..2155dc3 100644 --- a/src/algorithm/Front.h +++ b/src/algorithm/Front.h @@ -15,234 +15,12 @@ #include "Vertex.h" #include "Domain.h" #include "Mesh.h" +#include "FrontInitData.h" namespace TQMesh { using namespace CppUtils; -/********************************************************************* -* This class is used to initialize a new advancing front structure -* from an already existing mesh -*********************************************************************/ -class FrontInitData -{ -public: - using IntVector = std::vector; - using BoolVector = std::vector; - using EdgeVector = std::vector; - using MeshVector = std::vector; - - /*------------------------------------------------------------------ - | Constructor / Destructor - ------------------------------------------------------------------*/ - FrontInitData(const Domain& domain, const MeshVector& meshes) - { collect_front_edges(domain, meshes); } - - FrontInitData(const Domain& domain) - { MeshVector dummy {}; collect_front_edges(domain, dummy); } - - ~FrontInitData() {}; - - /*------------------------------------------------------------------ - | Move operator - ------------------------------------------------------------------*/ - FrontInitData(FrontInitData&& f) - : edges_ { std::move(f.edges_) } - , colors_ { std::move(f.colors_) } - , is_twin_edge_ { std::move(f.is_twin_edge_) } - {} - - FrontInitData& operator=(FrontInitData&& f) - { - edges_ = std::move(f.edges_); - colors_ = std::move(f.colors_); - is_twin_edge_ = std::move(f.is_twin_edge_); - return *this; - } - - /*------------------------------------------------------------------ - | Getter - ------------------------------------------------------------------*/ - std::vector& edges() { return edges_; } - const std::vector& edges() const { return edges_; } - - std::vector& is_twin_edge() { return is_twin_edge_; } - const std::vector& is_twin_edge() const { return is_twin_edge_; } - - std::vector& colors() { return colors_; } - const std::vector& colors() const { return colors_; } - - std::size_t size() const { return edges_.size(); } - -private: - /*------------------------------------------------------------------ - | Traverses all boundaries of a given domain and collects the - | respective boundary edges, as well as their color and orientation. - | Additionally, the boundary edges of given meshes are also - | considered, if they overlap with the domain boundary. This - | is required to construct conformal grids. - | Edges which result from adjacent meshes are oriented in the - | opposite direction. This can be used to identify these edges - | from "normal" boundary edges (e.g. for the advancing front - | refinement). - ------------------------------------------------------------------*/ - void collect_front_edges(const Domain& domain, - const MeshVector& meshes) - { - for ( const auto& boundary : domain ) - { - EdgeVector edges {}; - IntVector colors {}; - BoolVector is_twin_edge {}; - - for ( const auto& e : boundary->edges() ) - { - EdgeVector nbr_edges = get_neighbor_mesh_edges(*e, meshes); - - // Add edges from adjacent mesh - if ( nbr_edges.size() > 0 ) - { - for ( Edge* nbr_e : nbr_edges ) - { - edges.push_back( nbr_e ); - is_twin_edge.push_back( true ); - colors.push_back( nbr_e->color() ); - } - } - // Add edges from domain boundary - else - { - edges.push_back( e.get() ) ; - is_twin_edge.push_back( false ); - colors.push_back( e->color() ); - } - } - - edges_.push_back( edges ); - is_twin_edge_.push_back( is_twin_edge ); - colors_.push_back( colors ); - } - - // **** ---------------------------------------------------------- - // **** Feature implementation: Fixed interior edges - // **** ---------------------------------------------------------- - // - Here we could add additional fixed interor edges that have been - // defined by the user - // - // - These edges must be added twice - in forward and backward - // direction - // - // - The problem with the former is, that this will cause these two - // interior edges to be added in the mesh structure - // -> FrontUpdate.advance_front() - FrontUpdate.h, line 126 - // although it should only be one single edge - // - // - Possible approaches to overcome this: - // > Track these double-edges and include only one of them. - // However, this will cause major changes in - // FrontUpdate.advance_front() - // > How to do this? Add further if-statement in - // FrontUpdate.h, line 126, where it is checked if the base - // is interior - // > We could add another function, that checks if the base is - // doubly defined - // > This would result in the definition of a new edge color, - // Additionally to INTERIOR_EDGE_COLOR, we could use - // INTERIOR_TWIN_EDGE, or something - // > Thus, when adding a fixed interior edge here, - // we should already give it a special color that can later - // on be used to indicate it (maybe the first one is a default - // interior front edge and the second one is a special - // INTERIOR_TWIN_EDGE - // - // - It is important, that we also use some kind of closed edgelist - // for these interior fixed edges, so that the upcoming methods - // of Front for adding vertices and edges can be used - // - Maybe the user passes a list of interior edges and these - // will be converted into some kind of an interior boundary - // - However, this would require some more thoughts about the - // user interface for interior fixed edges, in order to define - // multiple line segements - // > Instead of an "add_fixed_edge()" function, we should provide - // something like "add_fixed_edge_semgents()", where multiple - // fixed edges are passed at once by a list of vertices - // > Similar to boundaries, the Domain then requires an additional - // list of "interior_edge_segments_" - // - // - - } // FrontInitData::collect_front_edges() - - /*------------------------------------------------------------------ - | For a given domain boundary edge , - | search all boundary edges of a - | neighboring mesh, that are contained within . - | This function is used upon the initialization of the advancing - | front. - ------------------------------------------------------------------*/ - EdgeVector get_neighbor_mesh_edges(const Edge& e, - const MeshVector& meshes) - const - { - EdgeVector nbr_edges {}; - - const Vec2d& c = e.xy(); - double r = edge_overlap_range_ * e.length(); - - const Vec2d& v = e.v1().xy(); - const Vec2d& w = e.v2().xy(); - - for ( Mesh* m : meshes ) - { - ASSERT( m, "Neighbor mesh data structure is invalid." ); - - // Get edges in the vicinity of the given edge - EdgeVector edges_in_vicinity = m->get_bdry_edges(c, r); - - // Get all edges, that are actually located on the segment - // of the current domain boundary edge - for ( Edge* e_vicinity : edges_in_vicinity ) - { - const Vec2d& p = e_vicinity->v1().xy(); - const Vec2d& q = e_vicinity->v2().xy(); - - if ( in_on_segment(v,w,p) && in_on_segment(v,w,q) ) - nbr_edges.push_back( e_vicinity ); - } - - // In case edges have been found, sort them in - // ascending direction to the stating vertex - std::sort(nbr_edges.begin(), nbr_edges.end(), - [v](Edge* e1, Edge* e2) - { - double delta_1 = (e1->xy() - v).norm_sqr(); - double delta_2 = (e2->xy() - v).norm_sqr(); - return (delta_1 < delta_2); - }); - - // If edges have been located, terminate the search - // --> First come, first serve - //if ( nbr_edges.size() > 0 ) - // break; - } - - return std::move(nbr_edges); - - } // FrontInitData::get_neighbor_mesh_edges() - - - /*------------------------------------------------------------------ - | Attributes - ------------------------------------------------------------------*/ - std::vector edges_ {}; - std::vector colors_ {}; - std::vector is_twin_edge_ {}; - - double edge_overlap_range_ { 1.5 }; - -}; // FrontInitData - - /********************************************************************* * The advancing front - defined by a list of edges * > Must be defined counter-clockwise @@ -306,6 +84,30 @@ class Front : public EdgeList // Refine the front edges, but do not refine sub-edges! this->refine_front_edges(domain, mesh_vertices); + + + + // Add additional ghost edges that are opposed to + // interior fixed edges + for ( const auto& e_ptr : edges_ ) + { + if ( !e_ptr->is_fixed() ) + continue; + + Vertex& v1 = e_ptr->v1(); + Vertex& v2 = e_ptr->v2(); + Edge& e_new = this->insert_edge( e_ptr->pos(), + v2, v1, + e_ptr->color() ); + + e_new.add_property( EdgeProperty::is_fixed ); + e_new.add_property( EdgeProperty::is_ghost ); + } + + + + // Re-compute area of domain + compute_area(); } // Front::init_front() @@ -446,9 +248,6 @@ class Front : public EdgeList for ( auto cur_edge : edges_to_remove ) edges_.remove( *cur_edge ); - // Re-compute area of domain - compute_area(); - return ( edges_.size() - n_before ); } // Front::refine_front_edges() @@ -502,7 +301,9 @@ class Front : public EdgeList Vertex* v2 = new_vertices[i2]; Edge& e_new = this->add_edge( *v1, *v2, colors[i_edge] ); - e_new.add_property( EdgeProperty::on_boundary ); + + if ( !front_edges[i_edge]->is_ghost() ) + e_new.add_property( EdgeProperty::on_boundary ); new_edges.push_back(&e_new); } diff --git a/src/algorithm/FrontInitData.h b/src/algorithm/FrontInitData.h new file mode 100644 index 0000000..58698fa --- /dev/null +++ b/src/algorithm/FrontInitData.h @@ -0,0 +1,270 @@ +/* +* This source file is part of the tqmesh library. +* This code was written by Florian Setzwein in 2022, +* and is covered under the MIT License +* Refer to the accompanying documentation for details +* on usage and license. +*/ +#pragma once + +#include +#include "STLHeaders.h" +#include "CppUtils.h" + +#include "EdgeList.h" +#include "Vertex.h" +#include "Domain.h" +#include "Mesh.h" + +namespace TQMesh { + +using namespace CppUtils; + +/********************************************************************* +* This class is used to initialize a new advancing front structure +* from an already existing mesh +*********************************************************************/ +class FrontInitData +{ +public: + using IntVector = std::vector; + using BoolVector = std::vector; + using EdgeVector = std::vector; + using MeshVector = std::vector; + + /*------------------------------------------------------------------ + | Constructor / Destructor + ------------------------------------------------------------------*/ + FrontInitData(const Domain& domain, const MeshVector& meshes) + { collect_front_edges(domain, meshes); } + + FrontInitData(const Domain& domain) + { MeshVector dummy {}; collect_front_edges(domain, dummy); } + + ~FrontInitData() {}; + + /*------------------------------------------------------------------ + | Move operator + ------------------------------------------------------------------*/ + FrontInitData(FrontInitData&& f) + : edges_ { std::move(f.edges_) } + , colors_ { std::move(f.colors_) } + , is_twin_edge_ { std::move(f.is_twin_edge_) } + {} + + FrontInitData& operator=(FrontInitData&& f) + { + edges_ = std::move(f.edges_); + colors_ = std::move(f.colors_); + is_twin_edge_ = std::move(f.is_twin_edge_); + return *this; + } + + /*------------------------------------------------------------------ + | Getter + ------------------------------------------------------------------*/ + std::vector& edges() { return edges_; } + const std::vector& edges() const { return edges_; } + + std::vector& is_twin_edge() { return is_twin_edge_; } + const std::vector& is_twin_edge() const { return is_twin_edge_; } + + std::vector& colors() { return colors_; } + const std::vector& colors() const { return colors_; } + + std::size_t size() const { return edges_.size(); } + +private: + /*------------------------------------------------------------------ + | Traverses all boundaries of a given domain and collects the + | respective boundary edges, as well as their color and orientation. + | Additionally, the boundary edges of given meshes are also + | considered, if they overlap with the domain boundary. This + | is required to construct conformal grids. + | Edges which result from adjacent meshes are oriented in the + | opposite direction. This can be used to identify these edges + | from "normal" boundary edges (e.g. for the advancing front + | refinement). + ------------------------------------------------------------------*/ + void collect_front_edges(const Domain& domain, + const MeshVector& meshes) + { + // Collect advancing front edges that stem from exterior & interior + // domain boundary edges. + // If an exterior domain edge is adjacent to a neighbouring mesh, + // take that neighbor mesh edges to preserve mesh adjacency + for ( const auto& boundary : domain ) + { + EdgeVector edges {}; + IntVector colors {}; + BoolVector is_twin_edge {}; + + for ( const auto& e : boundary->edges() ) + { + EdgeVector nbr_edges = get_neighbor_mesh_edges(*e, meshes); + + // Add edges from adjacent mesh + if ( nbr_edges.size() > 0 ) + { + for ( Edge* nbr_e : nbr_edges ) + { + edges.push_back( nbr_e ); + is_twin_edge.push_back( true ); + colors.push_back( nbr_e->color() ); + } + } + // Add edges from domain boundary + else + { + edges.push_back( e.get() ) ; + is_twin_edge.push_back( false ); + colors.push_back( e->color() ); + } + } + + edges_.push_back( edges ); + is_twin_edge_.push_back( is_twin_edge ); + colors_.push_back( colors ); + } + + // Collect advancing front edges that stem from fixed interior + // edges of the given domain + // For every fixed edge, we a also create an additional ghost + // edge that is oriented in the opposite direction + // + // EdgeVector edges {}; + // IntVector colors {}; + // BoolVector is_twin_edge {}; + + // for ( const auto& e : domain.fixed_edges() ) + // { + // edges.push_back( e.get() ); + // is_twin_edge.push_back( false ); + // colors.push_back( e->color() ); + // } + + // edges_.push_back( edges ); + // is_twin_edge_.push_back( is_twin_edge ); + // colors_.push_back( colors ); + + // **** ---------------------------------------------------------- + // **** Feature implementation: Fixed interior edges + // **** ---------------------------------------------------------- + // - Here we could add additional fixed interor edges that have been + // defined by the user + // + // - These edges must be added twice - in forward and backward + // direction + // + // - The problem with the former is, that this will cause these two + // interior edges to be added in the mesh structure + // -> FrontUpdate.advance_front() - FrontUpdate.h, line 126 + // although it should only be one single edge + // + // - Possible approaches to overcome this: + // > Track these double-edges and include only one of them. + // However, this will cause major changes in + // FrontUpdate.advance_front() + // > How to do this? Add further if-statement in + // FrontUpdate.h, line 126, where it is checked if the base + // is interior + // > We could add another function, that checks if the base is + // doubly defined + // > This would result in the definition of a new edge color, + // Additionally to INTERIOR_EDGE_COLOR, we could use + // INTERIOR_TWIN_EDGE, or something + // > Thus, when adding a fixed interior edge here, + // we should already give it a special color that can later + // on be used to indicate it (maybe the first one is a default + // interior front edge and the second one is a special + // INTERIOR_TWIN_EDGE + // + // - It is important, that we also use some kind of closed edgelist + // for these interior fixed edges, so that the upcoming methods + // of Front for adding vertices and edges can be used + // - Maybe the user passes a list of interior edges and these + // will be converted into some kind of an interior boundary + // - However, this would require some more thoughts about the + // user interface for interior fixed edges, in order to define + // multiple line segements + // > Instead of an "add_fixed_edge()" function, we should provide + // something like "add_fixed_edge_semgents()", where multiple + // fixed edges are passed at once by a list of vertices + // > Similar to boundaries, the Domain then requires an additional + // list of "interior_edge_segments_" + // + // + + } // FrontInitData::collect_front_edges() + + /*------------------------------------------------------------------ + | For a given domain boundary edge , + | search all boundary edges of a + | neighboring mesh, that are contained within . + | This function is used upon the initialization of the advancing + | front. + ------------------------------------------------------------------*/ + EdgeVector get_neighbor_mesh_edges(const Edge& e, + const MeshVector& meshes) + const + { + EdgeVector nbr_edges {}; + + const Vec2d& c = e.xy(); + double r = edge_overlap_range_ * e.length(); + + const Vec2d& v = e.v1().xy(); + const Vec2d& w = e.v2().xy(); + + for ( Mesh* m : meshes ) + { + ASSERT( m, "Neighbor mesh data structure is invalid." ); + + // Get edges in the vicinity of the given edge + EdgeVector edges_in_vicinity = m->get_bdry_edges(c, r); + + // Get all edges, that are actually located on the segment + // of the current domain boundary edge + for ( Edge* e_vicinity : edges_in_vicinity ) + { + const Vec2d& p = e_vicinity->v1().xy(); + const Vec2d& q = e_vicinity->v2().xy(); + + if ( in_on_segment(v,w,p) && in_on_segment(v,w,q) ) + nbr_edges.push_back( e_vicinity ); + } + + // In case edges have been found, sort them in + // ascending direction to the stating vertex + std::sort(nbr_edges.begin(), nbr_edges.end(), + [v](Edge* e1, Edge* e2) + { + double delta_1 = (e1->xy() - v).norm_sqr(); + double delta_2 = (e2->xy() - v).norm_sqr(); + return (delta_1 < delta_2); + }); + + // If edges have been located, terminate the search + // --> First come, first serve + //if ( nbr_edges.size() > 0 ) + // break; + } + + return std::move(nbr_edges); + + } // FrontInitData::get_neighbor_mesh_edges() + + + /*------------------------------------------------------------------ + | Attributes + ------------------------------------------------------------------*/ + std::vector edges_ {}; + std::vector colors_ {}; + std::vector is_twin_edge_ {}; + + double edge_overlap_range_ { 1.5 }; + +}; // FrontInitData + + +} // namespace TQMesh diff --git a/src/algorithm/FrontUpdate.h b/src/algorithm/FrontUpdate.h index 3b0c2c1..ec9f55c 100644 --- a/src/algorithm/FrontUpdate.h +++ b/src/algorithm/FrontUpdate.h @@ -123,7 +123,7 @@ class FrontUpdate // If current base is not at the boundary, add it to the // interior edge list - if ( base.is_interior() ) + if ( base.is_interior() && !base.is_ghost() ) mesh_.add_interior_edge(base.v1(), base.v2()); // Remove base edge diff --git a/src/algorithm/MeshBuilder.h b/src/algorithm/MeshBuilder.h index b2304b2..4986055 100644 --- a/src/algorithm/MeshBuilder.h +++ b/src/algorithm/MeshBuilder.h @@ -14,6 +14,7 @@ #include "utils.h" #include "Domain.h" #include "Mesh.h" +#include "FrontInitData.h" #include "Front.h" #include "EntityChecks.h" diff --git a/src/algorithm/TQMesh.h b/src/algorithm/TQMesh.h index 8ec655a..cf9d961 100644 --- a/src/algorithm/TQMesh.h +++ b/src/algorithm/TQMesh.h @@ -25,6 +25,7 @@ #include "EntityChecks.h" #include "Mesh.h" +#include "FrontInitData.h" #include "Front.h" #include "FrontUpdate.h" #include "MeshCleanup.h"