From 5fa82b0f8519b1cddb648a8b31346ff77e12166c Mon Sep 17 00:00:00 2001
From: Dmitri Naumov <github@naumov.de>
Date: Fri, 14 Jul 2023 22:59:13 +0200
Subject: [PATCH] [MeL] Extract common TetRule subclass

---
 MeshLib/Elements/TetRule.cpp  | 38 +++++++++++++++++
 MeshLib/Elements/TetRule.h    | 80 +++++++++++++++++++++++++++++++++++
 MeshLib/Elements/TetRule10.h  | 13 ++++--
 MeshLib/Elements/TetRule4.cpp | 47 --------------------
 MeshLib/Elements/TetRule4.h   | 49 +++++----------------
 5 files changed, 137 insertions(+), 90 deletions(-)
 create mode 100644 MeshLib/Elements/TetRule.cpp
 create mode 100644 MeshLib/Elements/TetRule.h

diff --git a/MeshLib/Elements/TetRule.cpp b/MeshLib/Elements/TetRule.cpp
new file mode 100644
index 00000000000..8f5682f5b32
--- /dev/null
+++ b/MeshLib/Elements/TetRule.cpp
@@ -0,0 +1,38 @@
+/**
+ * \file
+ * \copyright
+ * Copyright (c) 2012-2023, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ */
+
+#include "TetRule.h"
+
+#include "MathLib/GeometricBasics.h"
+#include "MeshLib/Node.h"
+
+namespace MeshLib
+{
+double TetRule::computeVolume(Node const* const* _nodes)
+{
+    return MathLib::calcTetrahedronVolume(*_nodes[0], *_nodes[1], *_nodes[2],
+                                          *_nodes[3]);
+}
+
+bool TetRule::isPntInElement(Node const* const* nodes,
+                             MathLib::Point3d const& pnt, double eps)
+{
+    return MathLib::isPointInTetrahedron(pnt, *nodes[0], *nodes[1], *nodes[2],
+                                         *nodes[3], eps);
+}
+
+ElementErrorCode TetRule::validate(const Element* e)
+{
+    ElementErrorCode error_code;
+    error_code[ElementErrorFlag::ZeroVolume] = hasZeroVolume(*e);
+    error_code[ElementErrorFlag::NodeOrder] = !e->testElementNodeOrder();
+    return error_code;
+}
+
+}  // end namespace MeshLib
diff --git a/MeshLib/Elements/TetRule.h b/MeshLib/Elements/TetRule.h
new file mode 100644
index 00000000000..159b4a71a16
--- /dev/null
+++ b/MeshLib/Elements/TetRule.h
@@ -0,0 +1,80 @@
+/**
+ * \file
+ * \copyright
+ * Copyright (c) 2012-2023, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include "CellRule.h"
+#include "Element.h"
+#include "MeshLib/MeshEnums.h"
+
+namespace MeshLib
+{
+
+class TetRule : public CellRule
+{
+public:
+    /// Constant: The number of base nodes for this element
+    static const unsigned n_base_nodes = 4u;
+
+    /// Constant: The geometric type of the element
+    static const MeshElemType mesh_elem_type = MeshElemType::TETRAHEDRON;
+
+    /// Constant: The number of faces
+    static const unsigned n_faces = 4;
+
+    /// Constant: The number of edges
+    static const unsigned n_edges = 6;
+
+    /// Constant: The number of neighbors
+    static const unsigned n_neighbors = 4;
+
+    /**
+     * \copydoc MeshLib::Element::isPntInElement()
+     * \param nodes the nodes of the element.
+     */
+    static bool isPntInElement(Node const* const* nodes,
+                               MathLib::Point3d const& pnt, double eps);
+
+    /**
+     * Tests if the element is geometrically valid.
+     */
+    static ElementErrorCode validate(const Element* e);
+
+    /// Calculates the volume of the element
+    static double computeVolume(Node const* const* _nodes);
+
+protected:
+    template <std::size_t N>
+    static unsigned identifyFace(Node const* const* _nodes,
+                                 Node const* nodes[3],
+                                 unsigned const face_nodes[4][N])
+    {
+        for (unsigned i = 0; i < 4; i++)
+        {
+            unsigned flag(0);
+            for (unsigned j = 0; j < 3; j++)
+            {
+                for (unsigned k = 0; k < 3; k++)
+                {
+                    if (_nodes[face_nodes[i][j]] == nodes[k])
+                    {
+                        flag++;
+                    }
+                }
+            }
+            if (flag == 3)
+            {
+                return i;
+            }
+        }
+        return std::numeric_limits<unsigned>::max();
+    }
+};
+}  // namespace MeshLib
diff --git a/MeshLib/Elements/TetRule10.h b/MeshLib/Elements/TetRule10.h
index 3b7a31adbfd..263540b16a0 100644
--- a/MeshLib/Elements/TetRule10.h
+++ b/MeshLib/Elements/TetRule10.h
@@ -10,10 +10,9 @@
 
 #pragma once
 
-#include "MeshLib/MeshEnums.h"
-#include "Element.h"
 #include "EdgeReturn.h"
-#include "TetRule4.h"
+#include "Element.h"
+#include "TetRule.h"
 
 namespace MeshLib
 {
@@ -39,7 +38,7 @@ namespace MeshLib
  *
  * \endcode
  */
-class TetRule10 : public TetRule4
+class TetRule10 : public TetRule
 {
 public:
     /// Constant: The number of all nodes for this element
@@ -60,6 +59,12 @@ public:
     /// Returns the i-th face of the element.
     static const Element* getFace(const Element* e, unsigned i);
 
+    /// Returns the ID of a face given an array of nodes.
+    static unsigned identifyFace(Node const* const* _nodes,
+                                 Node const* nodes[3])
+    {
+        return TetRule::identifyFace(_nodes, nodes, face_nodes);
+    }
 }; /* class */
 
 }  // namespace MeshLib
diff --git a/MeshLib/Elements/TetRule4.cpp b/MeshLib/Elements/TetRule4.cpp
index 6f9ef0aa6fa..58e65f52861 100644
--- a/MeshLib/Elements/TetRule4.cpp
+++ b/MeshLib/Elements/TetRule4.cpp
@@ -13,8 +13,6 @@
 #include <array>
 
 #include "BaseLib/Logging.h"
-#include "Line.h"
-#include "MathLib/GeometricBasics.h"
 #include "MeshLib/Node.h"
 #include "Tri.h"
 
@@ -50,49 +48,4 @@ const Element* TetRule4::getFace(const Element* e, unsigned i)
     ERR("Error in MeshLib::Element::getFace() - Index {:d} does not exist.", i);
     return nullptr;
 }
-
-double TetRule4::computeVolume(Node const* const* _nodes)
-{
-    return MathLib::calcTetrahedronVolume(*_nodes[0], *_nodes[1], *_nodes[2],
-                                          *_nodes[3]);
-}
-
-bool TetRule4::isPntInElement(Node const* const* nodes,
-                              MathLib::Point3d const& pnt, double eps)
-{
-    return MathLib::isPointInTetrahedron(pnt, *nodes[0], *nodes[1], *nodes[2],
-                                         *nodes[3], eps);
-}
-
-unsigned TetRule4::identifyFace(Node const* const* _nodes, Node const* nodes[3])
-{
-    for (unsigned i = 0; i < 4; i++)
-    {
-        unsigned flag(0);
-        for (unsigned j = 0; j < 3; j++)
-        {
-            for (unsigned k = 0; k < 3; k++)
-            {
-                if (_nodes[face_nodes[i][j]] == nodes[k])
-                {
-                    flag++;
-                }
-            }
-        }
-        if (flag == 3)
-        {
-            return i;
-        }
-    }
-    return std::numeric_limits<unsigned>::max();
-}
-
-ElementErrorCode TetRule4::validate(const Element* e)
-{
-    ElementErrorCode error_code;
-    error_code[ElementErrorFlag::ZeroVolume] = hasZeroVolume(*e);
-    error_code[ElementErrorFlag::NodeOrder] = !e->testElementNodeOrder();
-    return error_code;
-}
-
 }  // end namespace MeshLib
diff --git a/MeshLib/Elements/TetRule4.h b/MeshLib/Elements/TetRule4.h
index b5fbd63b3c0..de806f568bb 100644
--- a/MeshLib/Elements/TetRule4.h
+++ b/MeshLib/Elements/TetRule4.h
@@ -10,17 +10,16 @@
 
 #pragma once
 
-#include "MeshLib/MeshEnums.h"
-#include "Element.h"
 #include "EdgeReturn.h"
-#include "CellRule.h"
+#include "Element.h"
+#include "TetRule.h"
 
 namespace MeshLib
 {
 
 /**
- * This class represents a 3d tetrahedron element. The following sketch shows
- * the node and edge numbering.
+ * This class represents a 3d tetrahedron element with 4 nodes.
+ * The following sketch shows the node and edge numbering.
  * \anchor Tetrahedron4NodeAndEdgeNumbering
  * \code
  *          3
@@ -39,30 +38,15 @@ namespace MeshLib
  *
  * \endcode
  */
-class TetRule4 : public CellRule
+class TetRule4 : public TetRule
 {
 public:
-    /// Constant: The number of base nodes for this element
-    static const unsigned n_base_nodes = 4u;
-
     /// Constant: The number of all nodes for this element
     static const unsigned n_all_nodes = 4u;
 
-    /// Constant: The geometric type of the element
-    static const MeshElemType mesh_elem_type = MeshElemType::TETRAHEDRON;
-
     /// Constant: The FEM type of the element
     static const CellType cell_type = CellType::TET4;
 
-    /// Constant: The number of faces
-    static const unsigned n_faces = 4;
-
-    /// Constant: The number of edges
-    static const unsigned n_edges = 6;
-
-    /// Constant: The number of neighbors
-    static const unsigned n_neighbors = 4;
-
     /// Constant: Local node index table for faces
     static const unsigned face_nodes[4][3];
 
@@ -75,25 +59,12 @@ public:
     /// Returns the i-th face of the element.
     static const Element* getFace(const Element* e, unsigned i);
 
-    /**
-     * \copydoc MeshLib::Element::isPntInElement()
-     * \param nodes the nodes of the element.
-     */
-    static bool isPntInElement(Node const* const* nodes,
-                               MathLib::Point3d const& pnt, double eps);
-
-    /**
-     * Tests if the element is geometrically valid.
-     */
-    static ElementErrorCode validate(const Element* e);
-
     /// Returns the ID of a face given an array of nodes.
-    static unsigned identifyFace(Node const* const* /*_nodes*/,
-                                 Node const* nodes[3]);
-
-    /// Calculates the volume of the element
-    static double computeVolume(Node const* const* _nodes);
-
+    static unsigned identifyFace(Node const* const* _nodes,
+                                 Node const* nodes[3])
+    {
+        return TetRule::identifyFace(_nodes, nodes, face_nodes);
+    }
 }; /* class */
 
 }  // namespace MeshLib
-- 
GitLab