From e66b73a9f65f696646e85fe4083e4c521e88480e Mon Sep 17 00:00:00 2001 From: Karsten Rink <karsten.rink@ufz.de> Date: Fri, 21 Feb 2014 14:33:41 +0100 Subject: [PATCH] added error code to mesh element geometry checks --- MeshLib/Elements/Element.h | 10 +++++----- MeshLib/Elements/TemplateHex.h | 2 +- MeshLib/Elements/TemplateHex.tpp | 13 ++++++------ MeshLib/Elements/TemplateLine.h | 3 ++- MeshLib/Elements/TemplateLine.tpp | 9 +++++---- MeshLib/Elements/TemplatePrism.h | 2 +- MeshLib/Elements/TemplatePrism.tpp | 16 ++++++++------- MeshLib/Elements/TemplatePyramid.h | 2 +- MeshLib/Elements/TemplatePyramid.tpp | 15 +++++++++----- MeshLib/Elements/TemplateQuad.h | 2 +- MeshLib/Elements/TemplateQuad.tpp | 22 ++++++++++----------- MeshLib/Elements/TemplateTet.h | 2 +- MeshLib/Elements/TemplateTet.tpp | 9 +++++---- MeshLib/Elements/TemplateTri.h | 3 ++- MeshLib/Elements/TemplateTri.tpp | 9 +++++---- MeshLib/MeshEnums.h | 13 ++++++++++++ MeshLib/MeshQuality/MeshQualityController.h | 2 +- 17 files changed, 79 insertions(+), 55 deletions(-) diff --git a/MeshLib/Elements/Element.h b/MeshLib/Elements/Element.h index 1f8fc4cb52d..f894809fcad 100644 --- a/MeshLib/Elements/Element.h +++ b/MeshLib/Elements/Element.h @@ -133,11 +133,14 @@ public: */ unsigned getValue() const { return _value; } + /// Returns true if these two indeces form an edge and false otherwise + virtual bool isEdge(unsigned i, unsigned j) const = 0; + /** - * Tests if the element is geometrically valid, i.e. convex with volume > 0. + * Tests if the element is geometrically valid. * @param check_zero_volume indicates if length/area/volume == 0 should be checked */ - virtual bool isValid(bool check_zero_volume = true) const = 0; + virtual ElementErrorCode isValid() const = 0; /** * Set the index value for external information. @@ -151,9 +154,6 @@ public: /// Destructor virtual ~Element(); - /// Returns true if these two indeces form an edge and false otherwise - virtual bool isEdge(unsigned i, unsigned j) const = 0; - /** * Method clone is a pure virtual method in the abstract base class Element. * It has to be implemented in the derived classes (for instance in class Hex). diff --git a/MeshLib/Elements/TemplateHex.h b/MeshLib/Elements/TemplateHex.h index bd3b6976f62..1f2704ad2b0 100644 --- a/MeshLib/Elements/TemplateHex.h +++ b/MeshLib/Elements/TemplateHex.h @@ -102,7 +102,7 @@ public: * Tests if the element is geometrically valid. * @param check_zero_volume indicates if volume == 0 should be checked */ - virtual bool isValid(bool check_zero_volume = true) const; + virtual ElementErrorCode isValid() const; /** * Method clone is inherited from class Element. It makes a deep copy of the Hex instance. diff --git a/MeshLib/Elements/TemplateHex.tpp b/MeshLib/Elements/TemplateHex.tpp index 508511f2d35..1a2cec24523 100644 --- a/MeshLib/Elements/TemplateHex.tpp +++ b/MeshLib/Elements/TemplateHex.tpp @@ -156,20 +156,19 @@ unsigned TemplateHex<NNODES,CELLHEXTYPE>::identifyFace(Node* nodes[3]) const } template <unsigned NNODES, CellType CELLHEXTYPE> -bool TemplateHex<NNODES,CELLHEXTYPE>::isValid(bool check_zero_volume) const +ElementErrorCode TemplateHex<NNODES,CELLHEXTYPE>::isValid() const { - if (check_zero_volume && this->_volume <= std::numeric_limits<double>::epsilon()) - return false; + ElementErrorCode error_code(ElementErrorCode::NoError); + if (this->_volume < std::numeric_limits<double>::epsilon()) + error_code = error_code | ElementErrorCode::ZeroVolume; for (unsigned i=0; i<6; ++i) { const MeshLib::Quad* quad (dynamic_cast<const MeshLib::Quad*>(this->getFace(i))); - const bool quad_is_valid (quad->isValid()); + error_code = error_code | quad->isValid(); delete quad; - if (!quad_is_valid) - return false; } - return true; + return error_code; } template <unsigned NNODES, CellType CELLHEXTYPE> diff --git a/MeshLib/Elements/TemplateLine.h b/MeshLib/Elements/TemplateLine.h index e570d6b7061..c21d1c860a7 100644 --- a/MeshLib/Elements/TemplateLine.h +++ b/MeshLib/Elements/TemplateLine.h @@ -75,8 +75,9 @@ public: /** * Tests if the element is geometrically valid. * @param check_zero_volume indicates if area == 0 should be checked + * @return error code (0 = okay, 1 = zero volume) */ - virtual bool isValid(bool check_zero_volume = true) const; + virtual ElementErrorCode isValid() const; /** * Method clone is inherited from class Element. It makes a deep copy of the TemplateLine instance. diff --git a/MeshLib/Elements/TemplateLine.tpp b/MeshLib/Elements/TemplateLine.tpp index c2b2031e2cd..1ebf309b1a4 100644 --- a/MeshLib/Elements/TemplateLine.tpp +++ b/MeshLib/Elements/TemplateLine.tpp @@ -48,11 +48,12 @@ TemplateLine<NNODES,CELLLINETYPE>::~TemplateLine() {} template <unsigned NNODES, CellType CELLLINETYPE> -bool TemplateLine<NNODES,CELLLINETYPE>::isValid(bool check_zero_volume) const +ElementErrorCode TemplateLine<NNODES,CELLLINETYPE>::isValid() const { - if (check_zero_volume) - return (this->_length > std::numeric_limits<double>::epsilon()); - return true; + ElementErrorCode error_code (ElementErrorCode::NoError); + if (this->_length < std::numeric_limits<double>::epsilon()) + error_code = error_code | ElementErrorCode::ZeroVolume; + return error_code; } } // namespace MeshLib diff --git a/MeshLib/Elements/TemplatePrism.h b/MeshLib/Elements/TemplatePrism.h index 3dd0b175586..f93fa301a0c 100644 --- a/MeshLib/Elements/TemplatePrism.h +++ b/MeshLib/Elements/TemplatePrism.h @@ -100,7 +100,7 @@ public: * Tests if the element is geometrically valid. * @param check_zero_volume indicates if volume == 0 should be checked */ - virtual bool isValid(bool check_zero_volume = true) const; + virtual ElementErrorCode isValid() const; /** * Method clone is inherited from class Element. It makes a deep copy of the diff --git a/MeshLib/Elements/TemplatePrism.tpp b/MeshLib/Elements/TemplatePrism.tpp index 9d9f4fed744..85ee56cfbfc 100644 --- a/MeshLib/Elements/TemplatePrism.tpp +++ b/MeshLib/Elements/TemplatePrism.tpp @@ -165,20 +165,22 @@ unsigned TemplatePrism<NNODES,CELLPRISMTYPE>::identifyFace(Node* nodes[3]) const } template <unsigned NNODES, CellType CELLPRISMTYPE> -bool TemplatePrism<NNODES,CELLPRISMTYPE>::isValid(bool check_zero_volume) const +ElementErrorCode TemplatePrism<NNODES,CELLPRISMTYPE>::isValid() const { - if (check_zero_volume && this->_volume <= std::numeric_limits<double>::epsilon()) - return false; + ElementErrorCode error_code(ElementErrorCode::NoError); + if (this->_volume < std::numeric_limits<double>::epsilon()) + error_code = error_code | ElementErrorCode::ZeroVolume; for (unsigned i=1; i<4; ++i) { const MeshLib::Quad* quad (dynamic_cast<const MeshLib::Quad*>(this->getFace(i))); - const bool quad_is_valid (quad->isValid()); + if (quad) + error_code = error_code | quad->isValid(); + else + error_code = error_code | ElementErrorCode::NodeOrder; delete quad; - if (!quad_is_valid) - return false; } - return true; + return error_code; } template <unsigned NNODES, CellType CELLPRISMTYPE> diff --git a/MeshLib/Elements/TemplatePyramid.h b/MeshLib/Elements/TemplatePyramid.h index f687476419b..bc4db2f0bbe 100644 --- a/MeshLib/Elements/TemplatePyramid.h +++ b/MeshLib/Elements/TemplatePyramid.h @@ -98,7 +98,7 @@ public: * Tests if the element is geometrically valid. * @param check_zero_volume indicates if volume == 0 should be checked */ - virtual bool isValid(bool check_zero_volume = true) const; + virtual ElementErrorCode isValid() const; /** * Method clone is inherited from class Element. It makes a deep copy of the diff --git a/MeshLib/Elements/TemplatePyramid.tpp b/MeshLib/Elements/TemplatePyramid.tpp index fe3e01b1a9d..d572550b265 100644 --- a/MeshLib/Elements/TemplatePyramid.tpp +++ b/MeshLib/Elements/TemplatePyramid.tpp @@ -167,15 +167,20 @@ unsigned TemplatePyramid<NNODES,CELLPYRAMIDTYPE>::identifyFace(Node* nodes[3]) c } template <unsigned NNODES, CellType CELLPYRAMIDTYPE> -bool TemplatePyramid<NNODES,CELLPYRAMIDTYPE>::isValid(bool check_zero_volume) const +ElementErrorCode TemplatePyramid<NNODES,CELLPYRAMIDTYPE>::isValid() const { - if (check_zero_volume && this->_volume <= std::numeric_limits<double>::epsilon()) - return false; + ElementErrorCode error_code(ElementErrorCode::NoError); + if (this->_volume < std::numeric_limits<double>::epsilon()) + error_code = error_code | ElementErrorCode::ZeroVolume; const MeshLib::Quad* base (dynamic_cast<const MeshLib::Quad*>(this->getFace(4))); - const bool base_is_valid (base->isValid()); + if (base) + error_code = error_code | base->isValid(); + else + error_code = error_code | ElementErrorCode::NodeOrder; delete base; - return base_is_valid; + + return error_code; } diff --git a/MeshLib/Elements/TemplateQuad.h b/MeshLib/Elements/TemplateQuad.h index b30fa029f50..9ae3f9120dd 100644 --- a/MeshLib/Elements/TemplateQuad.h +++ b/MeshLib/Elements/TemplateQuad.h @@ -101,7 +101,7 @@ public: * Tests if the element is geometrically valid. * @param check_zero_volume indicates if area == 0 should be checked */ - virtual bool isValid(bool check_zero_volume = true) const; + virtual ElementErrorCode isValid() const; /** * Method clone is inherited from class Element. It makes a deep copy of the TemplateQuad instance. diff --git a/MeshLib/Elements/TemplateQuad.tpp b/MeshLib/Elements/TemplateQuad.tpp index fbf45baaa6d..49fb74f5d8d 100644 --- a/MeshLib/Elements/TemplateQuad.tpp +++ b/MeshLib/Elements/TemplateQuad.tpp @@ -120,19 +120,19 @@ unsigned TemplateQuad<NNODES,CELLQUADTYPE>::identifyFace(Node* nodes[3]) const } template <unsigned NNODES, CellType CELLQUADTYPE> -bool TemplateQuad<NNODES,CELLQUADTYPE>::isValid(bool check_zero_volume) const +ElementErrorCode TemplateQuad<NNODES,CELLQUADTYPE>::isValid() const { - if (check_zero_volume && this->_area <= std::numeric_limits<double>::epsilon()) - return false; + ElementErrorCode error_code(ElementErrorCode::NoError); + if (this->_area < std::numeric_limits<double>::epsilon()) + error_code = error_code | ElementErrorCode::ZeroVolume; - if (GeoLib::pointsOnAPlane(*_nodes[0], *_nodes[1], *_nodes[2], *_nodes[3])) - { - // check if quad is convex - if (GeoLib::dividedByPlane(*_nodes[0], *_nodes[2], *_nodes[1], *_nodes[3]) && - GeoLib::dividedByPlane(*_nodes[1], *_nodes[3], *_nodes[0], *_nodes[2])) - return true; - } - return false; + if (!GeoLib::pointsOnAPlane(*_nodes[0], *_nodes[1], *_nodes[2], *_nodes[3])) + error_code = error_code | ElementErrorCode::NonCoplanar; + + if (!(GeoLib::dividedByPlane(*_nodes[0], *_nodes[2], *_nodes[1], *_nodes[3]) && + GeoLib::dividedByPlane(*_nodes[1], *_nodes[3], *_nodes[0], *_nodes[2]))) + error_code = error_code | ElementErrorCode::NonConvex; + return error_code; } template <unsigned NNODES, CellType CELLQUADTYPE> diff --git a/MeshLib/Elements/TemplateTet.h b/MeshLib/Elements/TemplateTet.h index cadd972d88c..f5030d0dd8b 100644 --- a/MeshLib/Elements/TemplateTet.h +++ b/MeshLib/Elements/TemplateTet.h @@ -97,7 +97,7 @@ public: * Tests if the element is geometrically valid. * @param check_zero_volume indicates if volume == 0 should be checked */ - virtual bool isValid(bool check_zero_volume = true) const; + virtual ElementErrorCode isValid() const; /** * Method clone is inherited from class Element. It makes a deep copy of the TemplateTet instance. diff --git a/MeshLib/Elements/TemplateTet.tpp b/MeshLib/Elements/TemplateTet.tpp index c2497161cdf..c83c65cddbc 100644 --- a/MeshLib/Elements/TemplateTet.tpp +++ b/MeshLib/Elements/TemplateTet.tpp @@ -145,11 +145,12 @@ unsigned TemplateTet<NNODES,CELLTETTYPE>::identifyFace(Node* nodes[3]) const } template <unsigned NNODES, CellType CELLTETTYPE> -bool TemplateTet<NNODES,CELLTETTYPE>::isValid(bool check_zero_volume) const +ElementErrorCode TemplateTet<NNODES,CELLTETTYPE>::isValid() const { - if (check_zero_volume) - return (this->_volume > std::numeric_limits<double>::epsilon()); - return true; + ElementErrorCode error_code(ElementErrorCode::NoError); + if (this->_volume < std::numeric_limits<double>::epsilon()) + error_code = error_code | ElementErrorCode::ZeroVolume; + return error_code; } template <unsigned NNODES, CellType CELLTETTYPE> diff --git a/MeshLib/Elements/TemplateTri.h b/MeshLib/Elements/TemplateTri.h index f352d144869..9cd9fc4c60b 100644 --- a/MeshLib/Elements/TemplateTri.h +++ b/MeshLib/Elements/TemplateTri.h @@ -97,8 +97,9 @@ public: /** * Tests if the element is geometrically valid * @param check_zero_volume indicates if area == 0 should be checked + * @return error code (0 = okay, 1 = zero volume) */ - virtual bool isValid(bool check_zero_volume = true) const; + virtual ElementErrorCode isValid() const; /** diff --git a/MeshLib/Elements/TemplateTri.tpp b/MeshLib/Elements/TemplateTri.tpp index 3d386395e87..ee7ecba68f6 100644 --- a/MeshLib/Elements/TemplateTri.tpp +++ b/MeshLib/Elements/TemplateTri.tpp @@ -81,11 +81,12 @@ bool TemplateTri<NNODES,CELLTRITYPE>::isPntInside(GeoLib::Point const& pnt, doub } template <unsigned NNODES, CellType CELLTRITYPE> -bool TemplateTri<NNODES,CELLTRITYPE>::isValid(bool check_zero_volume) const +ElementErrorCode TemplateTri<NNODES,CELLTRITYPE>::isValid() const { - if (check_zero_volume) - return (this->_area > std::numeric_limits<double>::epsilon()); - return true; + ElementErrorCode error_code (ElementErrorCode::NoError); + if (this->_area < std::numeric_limits<double>::epsilon()) + error_code = error_code | ElementErrorCode::ZeroVolume; + return error_code; } diff --git a/MeshLib/MeshEnums.h b/MeshLib/MeshEnums.h index 22412633746..28d2b83c680 100644 --- a/MeshLib/MeshEnums.h +++ b/MeshLib/MeshEnums.h @@ -68,6 +68,15 @@ enum class MeshQualityType EQUIANGLESKEW }; +enum ElementErrorCode +{ + NoError = 0x00, + ZeroVolume = 0x01, + NonCoplanar = 0x02, + NonConvex = 0x04, + NodeOrder = 0x08 +}; + /// Given a MeshElemType this returns the appropriate string. const std::string MeshElemType2String(const MeshElemType t); @@ -76,4 +85,8 @@ MeshElemType String2MeshElemType(const std::string &s); const std::string MeshQualityType2String(const MeshQualityType t); +inline ElementErrorCode operator|(ElementErrorCode a, ElementErrorCode b) +{return static_cast<ElementErrorCode>(static_cast<int>(a) | static_cast<int>(b));} + + #endif //MESHENUMS_H diff --git a/MeshLib/MeshQuality/MeshQualityController.h b/MeshLib/MeshQuality/MeshQualityController.h index 2a3d486e6bd..831624193e5 100644 --- a/MeshLib/MeshQuality/MeshQualityController.h +++ b/MeshLib/MeshQuality/MeshQualityController.h @@ -21,7 +21,7 @@ namespace MeshLib { class Mesh; /** - * \brief A set of methods for manipulating mesh element values + * \brief A collection of methods for testing mesh quality and correctness */ class MeshQualityController { -- GitLab