diff --git a/MathLib/MathTools.cpp b/MathLib/MathTools.cpp index 469c3ab0c033277b4801001d51c403e2bb701f45..5d7017408e0e27d0471fc812588c52c4f8b96509 100644 --- a/MathLib/MathTools.cpp +++ b/MathLib/MathTools.cpp @@ -20,12 +20,10 @@ namespace MathLib double calcProjPntToLineAndDists(Point3d const& pp, Point3d const& pa, Point3d const& pb, double& lambda, double& d0) { - auto const a = - Eigen::Map<Eigen::Vector3d>(const_cast<double*>(pa.getCoords())); - auto const b = - Eigen::Map<Eigen::Vector3d>(const_cast<double*>(pb.getCoords())); - auto const p = - Eigen::Map<Eigen::Vector3d>(const_cast<double*>(pp.getCoords())); + auto const a = Eigen::Map<Eigen::Vector3d const>(pa.getCoords()); + auto const b = Eigen::Map<Eigen::Vector3d const>(pb.getCoords()); + auto const p = Eigen::Map<Eigen::Vector3d const>(pp.getCoords()); + // g(lambda) = a + lambda v, v = b-a Eigen::Vector3d const v = b - a; @@ -42,13 +40,17 @@ double calcProjPntToLineAndDists(Point3d const& pp, Point3d const& pa, return (p - proj_pnt).norm(); } -double getAngle (const double p0[3], const double p1[3], const double p2[3]) +double getAngle(Point3d const& p0, Point3d const& p1, Point3d const& p2) { - const double v0[3] = {p0[0]-p1[0], p0[1]-p1[1], p0[2]-p1[2]}; - const double v1[3] = {p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]}; + auto const a = Eigen::Map<Eigen::Vector3d const>(p0.getCoords()); + auto const b = Eigen::Map<Eigen::Vector3d const>(p1.getCoords()); + auto const c = Eigen::Map<Eigen::Vector3d const>(p2.getCoords()); + Eigen::Vector3d const v0 = a - b; + Eigen::Vector3d const v1 = c - b; // apply Cauchy Schwarz inequality - return std::acos (scalarProduct<double,3> (v0,v1) / (std::sqrt(scalarProduct<double,3>(v0,v0)) * sqrt(scalarProduct<double,3>(v1,v1)))); + return std::acos( + (v0.transpose() * v1 / (v0.norm() * v1.norm()))(0, 0)); } double scalarTriple(Eigen::Vector3d const& u, Eigen::Vector3d const& v, diff --git a/MathLib/MathTools.h b/MathLib/MathTools.h index 6018091a454ec1fa979adb89e82e32935504f0eb..699d3ff7225ed3ea8c2368d25c29b90ad54060d2 100644 --- a/MathLib/MathTools.h +++ b/MathLib/MathTools.h @@ -90,7 +90,7 @@ double calcProjPntToLineAndDists(MathLib::Point3d const& pp, * @param p2 end point of edge 1 * @return the angle between the edges */ -double getAngle (const double p0[3], const double p1[3], const double p2[3]); +double getAngle(Point3d const& p0, Point3d const& p1, Point3d const& p2); /// Calculates the scalar triple (u x v) . w double scalarTriple(Eigen::Vector3d const& u, Eigen::Vector3d const& v, diff --git a/MeshLib/MeshQuality/AngleSkewMetric.cpp b/MeshLib/MeshQuality/AngleSkewMetric.cpp index d5f927d99f9f21fbb1a6d6121ea96a49ea6f00da..ac8e9d75abced59108b51d17a0767999ff3f9b60 100644 --- a/MeshLib/MeshQuality/AngleSkewMetric.cpp +++ b/MeshLib/MeshQuality/AngleSkewMetric.cpp @@ -25,190 +25,156 @@ using namespace boost::math::double_constants; namespace MeshLib { -AngleSkewMetric::AngleSkewMetric(Mesh const& mesh) : - ElementQualityMetric(mesh) -{} -void AngleSkewMetric::calculateQuality () +namespace { - const std::vector<MeshLib::Element*>& elements(_mesh.getElements()); - const std::size_t nElements (_mesh.getNumberOfElements()); +template <unsigned long N> +std::tuple<double, double> getMinMaxAngle( + std::array<MeshLib::Node, N> const& nodes) +{ + double min_angle(two_pi); + double max_angle(0.0); - for (std::size_t k(0); k < nElements; k++) + for (decltype(N) i = 0; i < N; ++i) { - Element const& elem (*elements[k]); - switch (elem.getGeomType()) - { - case MeshElemType::LINE: - _element_quality_metric[k] = -1.0; - break; - case MeshElemType::TRIANGLE: - _element_quality_metric[k] = checkTriangle (elem); - break; - case MeshElemType::QUAD: - _element_quality_metric[k] = checkQuad (elem); - break; - case MeshElemType::TETRAHEDRON: - _element_quality_metric[k] = checkTetrahedron (elem); - break; - case MeshElemType::HEXAHEDRON: - _element_quality_metric[k] = checkHexahedron (elem); - break; - case MeshElemType::PRISM: - _element_quality_metric[k] = checkPrism (elem); - break; - default: - break; - } + const double angle(MathLib::getAngle(nodes[i], nodes[(i + 1) % N], + nodes[(i + 2) % N])); + min_angle = std::min(angle, min_angle); + max_angle = std::max(angle, max_angle); } + return {min_angle, max_angle}; } -double AngleSkewMetric::checkTriangle (Element const& elem) const +double checkTriangle(Element const& elem) { - double const* const node0 (elem.getNode(0)->getCoords()); - double const* const node1 (elem.getNode(1)->getCoords()); - double const* const node2 (elem.getNode(2)->getCoords()); - - double min_angle(two_pi); - double max_angle(0.0); - getMinMaxAngleFromTriangle (node0, node1, node2, min_angle, max_angle); - + std::array const nodes = {*elem.getNode(0), *elem.getNode(1), + *elem.getNode(2)}; + auto const& [min_angle, max_angle] = getMinMaxAngle(nodes); return std::max((max_angle - third_pi) / two_thirds_pi, (third_pi - min_angle) / third_pi); } -double AngleSkewMetric::checkQuad (Element const& elem) const +double checkQuad(Element const& elem) { - double const* const node0 (elem.getNode(0)->getCoords()); - double const* const node1 (elem.getNode(1)->getCoords()); - double const* const node2 (elem.getNode(2)->getCoords()); - double const* const node3 (elem.getNode(3)->getCoords()); - - double min_angle (two_pi); - double max_angle (0.0); - - getMinMaxAngleFromQuad (node0, node1, node2, node3, min_angle, max_angle); + std::array const nodes = {*elem.getNode(0), *elem.getNode(1), + *elem.getNode(2), *elem.getNode(3)}; + auto const& [min_angle, max_angle] = getMinMaxAngle(nodes); return std::max((max_angle - half_pi) / half_pi, (half_pi - min_angle) / half_pi); } -double AngleSkewMetric::checkTetrahedron (Element const& elem) const +double checkTetrahedron(Element const& elem) { - double const* const node0 (elem.getNode(0)->getCoords()); - double const* const node1 (elem.getNode(1)->getCoords()); - double const* const node2 (elem.getNode(2)->getCoords()); - double const* const node3 (elem.getNode(3)->getCoords()); - - double min_angle (two_pi); - double max_angle (0.0); - - // first triangle (0,1,2) - getMinMaxAngleFromTriangle(node0, node1, node2, min_angle, max_angle); - // second triangle (0,1,3) - getMinMaxAngleFromTriangle(node0, node1, node3, min_angle, max_angle); - // third triangle (0,2,3) - getMinMaxAngleFromTriangle(node0, node2, node3, min_angle, max_angle); - // fourth triangle (1,2,3) - getMinMaxAngleFromTriangle(node1, node2, node3, min_angle, max_angle); + std::array<double, 4> min; + std::array<double, 4> max; + for (auto face_number = 0; face_number < 4; ++face_number) + { + auto const& face = *elem.getFace(face_number); + std::array const nodes = {*face.getNode(0), *face.getNode(1), + *face.getNode(2)}; + std::tie(min[face_number], max[face_number]) = getMinMaxAngle(nodes); + } + + double const min_angle = *std::min_element(min.begin(), min.end()); + double const max_angle = *std::max_element(max.begin(), max.end()); return std::max((max_angle - third_pi) / two_thirds_pi, (third_pi - min_angle) / third_pi); } -double AngleSkewMetric::checkHexahedron (Element const& elem) const +double checkHexahedron(Element const& elem) { - double const* const node0 (elem.getNode(0)->getCoords()); - double const* const node1 (elem.getNode(1)->getCoords()); - double const* const node2 (elem.getNode(2)->getCoords()); - double const* const node3 (elem.getNode(3)->getCoords()); - double const* const node4 (elem.getNode(4)->getCoords()); - double const* const node5 (elem.getNode(5)->getCoords()); - double const* const node6 (elem.getNode(6)->getCoords()); - double const* const node7 (elem.getNode(7)->getCoords()); - - double min_angle (two_pi); - double max_angle (0.0); - - // first surface (0,1,2,3) - getMinMaxAngleFromQuad (node0, node1, node2, node3, min_angle, max_angle); - // second surface (0,3,7,4) - getMinMaxAngleFromQuad (node0, node3, node7, node4, min_angle, max_angle); - // third surface (4,5,6,7) - getMinMaxAngleFromQuad (node4, node5, node6, node7, min_angle, max_angle); - // fourth surface (5,1,2,6) - getMinMaxAngleFromQuad (node5, node1, node2, node6, min_angle, max_angle); - // fifth surface (5,1,0,4) - getMinMaxAngleFromQuad (node5, node1, node0, node4, min_angle, max_angle); - // sixth surface (6,2,3,7) - getMinMaxAngleFromQuad (node6, node2, node3, node7, min_angle, max_angle); + std::array<double, 6> min; + std::array<double, 6> max; + for (auto face_number = 0; face_number < 6; ++face_number) + { + auto const& face = *elem.getFace(face_number); + std::array const nodes = {*face.getNode(0), *face.getNode(1), + *face.getNode(2), *face.getNode(3)}; + std::tie(min[face_number], max[face_number]) = getMinMaxAngle(nodes); + } + + double const min_angle = *std::min_element(min.begin(), min.end()); + double const max_angle = *std::max_element(max.begin(), max.end()); return std::max((max_angle - half_pi) / half_pi, (half_pi - min_angle) / half_pi); } -double AngleSkewMetric::checkPrism (Element const& elem) const +double checkPrism(Element const& elem) { - double const* const node0 (elem.getNode(0)->getCoords()); - double const* const node1 (elem.getNode(1)->getCoords()); - double const* const node2 (elem.getNode(2)->getCoords()); - double const* const node3 (elem.getNode(3)->getCoords()); - double const* const node4 (elem.getNode(4)->getCoords()); - double const* const node5 (elem.getNode(5)->getCoords()); + // face 0: triangle (0,1,2) + auto const& f0 = *elem.getFace(0); + std::array const nodes_f0 = {*f0.getNode(0), *f0.getNode(1), + *f0.getNode(2)}; + auto const& [min_angle_tri0, max_angle_tri0] = getMinMaxAngle(nodes_f0); - double min_angle_tri (two_pi); - double max_angle_tri (0.0); + // face 4: triangle (3,4,5) + auto const& f4 = *elem.getFace(4); + std::array const nodes_f4 = {*f4.getNode(0), *f4.getNode(1), + *f4.getNode(2)}; + auto const& [min_angle_tri1, max_angle_tri1] = getMinMaxAngle(nodes_f4); - // first triangle (0,1,2) - getMinMaxAngleFromTriangle (node0, node1, node2, min_angle_tri, max_angle_tri); - // second surface (3,4,5) - getMinMaxAngleFromTriangle (node3, node4, node5, min_angle_tri, max_angle_tri); + auto const min_angle_tri = std::min(min_angle_tri0, min_angle_tri1); + auto const max_angle_tri = std::max(max_angle_tri0, max_angle_tri1); double const tri_criterion( std::max((max_angle_tri - third_pi) / two_thirds_pi, (third_pi - min_angle_tri) / third_pi)); - double min_angle_quad (two_pi); - double max_angle_quad (0.0); - // surface (0,3,4,1) - getMinMaxAngleFromQuad (node0, node3, node4, node1, min_angle_quad, max_angle_quad); - // surface (2,5,3,0) - getMinMaxAngleFromQuad (node2, node5, node3, node0, min_angle_quad, max_angle_quad); - // surface (1,2,5,4) - getMinMaxAngleFromQuad (node1, node2, node5, node4, min_angle_quad, max_angle_quad); + std::array<double, 3> min; + std::array<double, 3> max; + for (int i = 1; i < 4; ++i) + { + auto const& f = *elem.getFace(i); + std::array const nodes = {*f.getNode(0), *f.getNode(1), *f.getNode(2), + *f.getNode(3)}; + std::tie(min[i - 1], max[i - 1]) = getMinMaxAngle(nodes); + } + + double const min_angle_quad = *std::min_element(min.begin(), min.end()); + double const max_angle_quad = *std::max_element(max.begin(), max.end()); double const quad_criterion(std::max((max_angle_quad - half_pi) / half_pi, (half_pi - min_angle_quad) / half_pi)); - return std::min (tri_criterion, quad_criterion); + return std::min(tri_criterion, quad_criterion); } -void AngleSkewMetric::getMinMaxAngleFromQuad ( - double const* const n0, double const* const n1, - double const* const n2, double const* const n3, - double &min_angle, double &max_angle) const -{ - const double* nodes[4] = {n0, n1, n2, n3}; - for (unsigned i=0; i<4; ++i) - { - const double angle (MathLib::getAngle (nodes[i], nodes[(i+1)%4], nodes[(i+2)%4])); - min_angle = std::min(angle, min_angle); - max_angle = std::max(angle, max_angle); - } -} +} // end unnamed namespace + +AngleSkewMetric::AngleSkewMetric(Mesh const& mesh) : + ElementQualityMetric(mesh) +{} -void AngleSkewMetric::getMinMaxAngleFromTriangle(double const* const n0, - double const* const n1, - double const* const n2, - double &min_angle, - double &max_angle) const +void AngleSkewMetric::calculateQuality() { - const double* nodes[3] = {n0, n1, n2}; - for (unsigned i=0; i<3; ++i) + for (auto const e : _mesh.getElements()) { - const double angle (MathLib::getAngle (nodes[i], nodes[(i+1)%3], nodes[(i+2)%3])); - min_angle = std::min(angle, min_angle); - max_angle = std::max(angle, max_angle); + switch (e->getGeomType()) + { + case MeshElemType::LINE: + _element_quality_metric[e->getID()] = -1.0; + break; + case MeshElemType::TRIANGLE: + _element_quality_metric[e->getID()] = checkTriangle(*e); + break; + case MeshElemType::QUAD: + _element_quality_metric[e->getID()] = checkQuad(*e); + break; + case MeshElemType::TETRAHEDRON: + _element_quality_metric[e->getID()] = checkTetrahedron(*e); + break; + case MeshElemType::HEXAHEDRON: + _element_quality_metric[e->getID()] = checkHexahedron(*e); + break; + case MeshElemType::PRISM: + _element_quality_metric[e->getID()] = checkPrism(*e); + break; + default: + break; + } } } diff --git a/MeshLib/MeshQuality/AngleSkewMetric.h b/MeshLib/MeshQuality/AngleSkewMetric.h index c2765b2cf25b2075feda80f9fd771c21f1c9bf72..b93fd9bcc91fa95bd4c8a47464d00f35c0bbe9f1 100644 --- a/MeshLib/MeshQuality/AngleSkewMetric.h +++ b/MeshLib/MeshQuality/AngleSkewMetric.h @@ -28,19 +28,5 @@ public: explicit AngleSkewMetric(Mesh const& mesh); void calculateQuality() override; - -private: - double checkTriangle(Element const& elem) const; - double checkQuad(Element const& elem) const; - double checkTetrahedron(Element const& elem) const; - double checkHexahedron(Element const& elem) const; - double checkPrism (Element const& elem) const; - void getMinMaxAngleFromQuad(double const* const n0, - double const* const n1, double const* const n2, - double const* const n3, double &min_angle, - double &max_angle) const; - void getMinMaxAngleFromTriangle(double const* const n0, - double const* const n1, double const* const n2, - double &min_angle, double &max_angle) const; }; } // namespace MeshLib