diff --git a/Gui/DataView/MeshAnalysisDialog.cpp b/Gui/DataView/MeshAnalysisDialog.cpp index 8af9cd9175e304f9df81140e04541d10e0c6622f..dc9f794ae929216ec6590d8cbca6f9caa8b8f9fc 100644 --- a/Gui/DataView/MeshAnalysisDialog.cpp +++ b/Gui/DataView/MeshAnalysisDialog.cpp @@ -15,6 +15,7 @@ #include "MeshAnalysisDialog.h" #include "Mesh.h" #include "MeshQuality/MeshValidation.h" +#include "MeshEditing/MeshRevision.h" // ThirdParty/logog #include "logog/include/logog.hpp" @@ -41,7 +42,9 @@ void MeshAnalysisDialog::on_startButton_pressed() const MeshLib::Mesh* mesh (_mesh_vec[this->meshListBox->currentIndex()]); const std::vector<std::size_t> unusedNodesIdx (MeshLib::MeshValidation::removeUnusedMeshNodes(*const_cast<MeshLib::Mesh*>(mesh))); - this->nodesMsgOutput(unusedNodesIdx); + MeshLib::MeshRevision rev(*mesh); + const unsigned nCollapsableNodes (rev.getNCollapsableNodes()); + this->nodesMsgOutput(unusedNodesIdx, nCollapsableNodes); const std::vector<ElementErrorCode> element_error_codes (MeshLib::MeshValidation::testElementGeometry(*mesh)); //this->elementMsgOutput(element_error_codes); @@ -49,18 +52,20 @@ void MeshAnalysisDialog::on_startButton_pressed() this->elementsMsg->setText(elementMsgOutput); } -void MeshAnalysisDialog::nodesMsgOutput(const std::vector<std::size_t> &node_ids) +void MeshAnalysisDialog::nodesMsgOutput(const std::vector<std::size_t> &node_ids, unsigned nCollapsableNodes) { const std::size_t nNodeIds (node_ids.size()); QString nodes_output(""); if (node_ids.empty()) - nodes_output += "Nothing to report."; + nodes_output += "No unused nodes found."; else { (QString::number(nNodeIds) + " nodes are not part of any element:\n"); for (std::size_t i=0; i<nNodeIds; ++i) nodes_output += (QString::number(node_ids[i]) + ", "); } + + nodes_output += "\nFound " + QString::number(nCollapsableNodes) + " potentially collapsable nodes."; this->nodesMsg->setText(nodes_output); } diff --git a/Gui/DataView/MeshAnalysisDialog.h b/Gui/DataView/MeshAnalysisDialog.h index 35b594acaae4a3e8d5c416bcf57ad3f12ba38923..4fc4920b74a0b04a08c088dd2f344d3f903022f5 100644 --- a/Gui/DataView/MeshAnalysisDialog.h +++ b/Gui/DataView/MeshAnalysisDialog.h @@ -37,7 +37,7 @@ public: private: /// Prepares the output for the node message window - void nodesMsgOutput(const std::vector<std::size_t> &node_ids); + void nodesMsgOutput(const std::vector<std::size_t> &node_ids, unsigned nCollapsableNodes); const std::vector<MeshLib::Mesh*>& _mesh_vec; diff --git a/MeshLib/MeshEditing/MeshRevision.cpp b/MeshLib/MeshEditing/MeshRevision.cpp index 4a214a76ae151d37f862c53ee9045cede3df7677..b25a051df77d3ae7aa6f7aa24f518013e1ad4108 100644 --- a/MeshLib/MeshEditing/MeshRevision.cpp +++ b/MeshLib/MeshEditing/MeshRevision.cpp @@ -35,29 +35,43 @@ namespace MeshLib { -MeshRevision::MeshRevision(Mesh const*const mesh) : +MeshRevision::MeshRevision(const MeshLib::Mesh &mesh) : _mesh (mesh) {} MeshLib::Mesh* MeshRevision::collapseNodes(const std::string &new_mesh_name, double eps) { - std::vector<MeshLib::Node*> new_nodes = this->collapseNodeIndeces(eps); - const std::size_t nElems (this->_mesh->getNElements()); + std::vector<MeshLib::Node*> new_nodes = this->constructNewNodesArray(this->collapseNodeIndeces(eps)); + const std::size_t nElems (this->_mesh.getNElements()); std::vector<MeshLib::Element*> new_elements (nElems); - const std::vector<MeshLib::Element*> elements (this->_mesh->getElements()); + const std::vector<MeshLib::Element*> elements (this->_mesh.getElements()); for (std::size_t i=0; i<nElems; ++i) new_elements[i] = copyElement(elements[i], new_nodes); return new MeshLib::Mesh(new_mesh_name, new_nodes, new_elements); } +unsigned MeshRevision::getNCollapsableNodes(double eps) const +{ + std::vector<std::size_t> id_map (this->collapseNodeIndeces(eps)); + std::size_t nNodes (id_map.size()); + unsigned count (0); + for (std::size_t i=0; i<nNodes; ++i) + if (i != id_map[i]) + count++; + return count; +} + MeshLib::Mesh* MeshRevision::simplifyMesh(const std::string &new_mesh_name, double eps, unsigned min_elem_dim) { - std::vector<MeshLib::Node*> new_nodes = this->collapseNodeIndeces(eps); + const std::size_t nElems (this->_mesh.getNElements()); + if (nElems == 0) + return nullptr; + + std::vector<MeshLib::Node*> new_nodes = this->constructNewNodesArray(this->collapseNodeIndeces(eps)); std::vector<MeshLib::Element*> new_elements; - const std::size_t nElems (this->_mesh->getNElements()); - const std::vector<MeshLib::Element*> elements (this->_mesh->getElements()); + const std::vector<MeshLib::Element*> elements (this->_mesh.getElements()); for (std::size_t i=0; i<nElems; ++i) { unsigned n_unique_nodes (this->getNUniqueNodes(elements[i])); @@ -85,10 +99,10 @@ MeshLib::Mesh* MeshRevision::simplifyMesh(const std::string &new_mesh_name, doub return nullptr; } -std::vector<MeshLib::Node*> MeshRevision::collapseNodeIndeces(double eps) +std::vector<std::size_t> MeshRevision::collapseNodeIndeces(double eps) const { - const std::vector<MeshLib::Node*> nodes (_mesh->getNodes()); - const std::size_t nNodes (_mesh->getNNodes()); + const std::vector<MeshLib::Node*> nodes (_mesh.getNodes()); + const std::size_t nNodes (_mesh.getNNodes()); std::vector<std::size_t> id_map(nNodes); for (std::size_t k=0; k<nNodes; ++k) id_map[k]=k; @@ -124,13 +138,12 @@ std::vector<MeshLib::Node*> MeshRevision::collapseNodeIndeces(double eps) } } } - - return this->constructNewNodesArray(id_map); + return id_map; } std::vector<MeshLib::Node*> MeshRevision::constructNewNodesArray(const std::vector<std::size_t> &id_map) { - std::vector<MeshLib::Node*> nodes (_mesh->getNodes()); + std::vector<MeshLib::Node*> nodes (_mesh.getNodes()); const std::size_t nNodes (nodes.size()); std::vector<MeshLib::Node*> new_nodes; for (std::size_t k=0; k<nNodes; ++k) @@ -308,22 +321,22 @@ unsigned MeshRevision::subdivideHex(MeshLib::Element const*const hex, const std: { MeshLib::Node** prism1_nodes = new MeshLib::Node*[6]; prism1_nodes[0] = nodes[hex->getNode(0)->getID()]; - prism1_nodes[1] = nodes[hex->getNode(1)->getID()]; - prism1_nodes[2] = nodes[hex->getNode(2)->getID()]; + prism1_nodes[1] = nodes[hex->getNode(2)->getID()]; + prism1_nodes[2] = nodes[hex->getNode(1)->getID()]; prism1_nodes[3] = nodes[hex->getNode(4)->getID()]; - prism1_nodes[4] = nodes[hex->getNode(5)->getID()]; - prism1_nodes[5] = nodes[hex->getNode(6)->getID()]; + prism1_nodes[4] = nodes[hex->getNode(6)->getID()]; + prism1_nodes[5] = nodes[hex->getNode(5)->getID()]; MeshLib::Prism* prism1 (new MeshLib::Prism(prism1_nodes, hex->getValue())); this->subdividePrism(prism1, nodes, new_elements); delete prism1; MeshLib::Node** prism2_nodes = new MeshLib::Node*[6]; - prism2_nodes[0] = nodes[hex->getNode(0)->getID()]; - prism2_nodes[1] = nodes[hex->getNode(2)->getID()]; - prism2_nodes[2] = nodes[hex->getNode(3)->getID()]; - prism2_nodes[3] = nodes[hex->getNode(4)->getID()]; - prism2_nodes[4] = nodes[hex->getNode(6)->getID()]; - prism2_nodes[5] = nodes[hex->getNode(7)->getID()]; + prism2_nodes[0] = nodes[hex->getNode(4)->getID()]; + prism2_nodes[1] = nodes[hex->getNode(6)->getID()]; + prism2_nodes[2] = nodes[hex->getNode(7)->getID()]; + prism2_nodes[3] = nodes[hex->getNode(0)->getID()]; + prism2_nodes[4] = nodes[hex->getNode(2)->getID()]; + prism2_nodes[5] = nodes[hex->getNode(3)->getID()]; MeshLib::Prism* prism2 (new MeshLib::Prism(prism2_nodes, hex->getValue())); this->subdividePrism(prism2, nodes, new_elements); delete prism2; diff --git a/MeshLib/MeshEditing/MeshRevision.h b/MeshLib/MeshEditing/MeshRevision.h index 95e78f40d05b99655bc056157b89ce6286dc8dc3..7b86a99dfa8a8bddb22622165ffd920a8731b1eb 100644 --- a/MeshLib/MeshEditing/MeshRevision.h +++ b/MeshLib/MeshEditing/MeshRevision.h @@ -35,7 +35,7 @@ namespace MeshLib { class MeshRevision { public: /// Constructor - MeshRevision(Mesh const*const mesh); + MeshRevision(const MeshLib::Mesh &mesh); virtual ~MeshRevision() {}; @@ -47,17 +47,23 @@ public: */ MeshLib::Mesh* collapseNodes(const std::string &new_mesh_name, double eps); + /// Returns the number of potentially collapsable nodes + unsigned getNCollapsableNodes(double eps = std::numeric_limits<double>::epsilon()) const; + /** * Create a new mesh where all nodes with a distance < eps from each other are collapsed. - * Elements are adjusted accordingly. + * Elements are adjusted accordingly and elements with nonplanar faces are subdivided into + * geometrically correct elements. * @param eps Minimum distance for nodes not to be collapsed - * @param min_elem_dim Minimum dimension of elements to be inserted into new mesh (i.e. min_elem_dim=3 will prevent the new mesh to contain 2D elements) + * @param min_elem_dim Minimum dimension of elements to be inserted into new mesh (i.e. + * min_elem_dim=3 will prevent the new mesh to contain 2D elements) */ MeshLib::Mesh* simplifyMesh(const std::string &new_mesh_name, double eps, unsigned min_elem_dim = 1); + private: - /// Designates nodes to be collapsed by setting their ID to the index of the node they will get merged with. - std::vector<MeshLib::Node*> collapseNodeIndeces(double eps); + /// Designates nodes to be collapsed by setting their ID to the index of the node they will sget merged with. + std::vector<std::size_t> collapseNodeIndeces(double eps) const; /// Constructs a new node vector for the resulting mesh by removing all nodes whose ID indicates they need to be merged/removed. std::vector<MeshLib::Node*> constructNewNodesArray(const std::vector<std::size_t> &id_map); @@ -153,7 +159,7 @@ private: unsigned lutPrismThirdNode(unsigned id1, unsigned id2) const; /// The original mesh used for constructing the class - Mesh const*const _mesh; + const Mesh& _mesh; }; } diff --git a/MeshLib/MeshQuality/MeshValidation.cpp b/MeshLib/MeshQuality/MeshValidation.cpp index 7a966e4d36e7efd448923115a47de98845acadbb..7e56826657cbc0580928b5017e7c75fcdbaef13a 100644 --- a/MeshLib/MeshQuality/MeshValidation.cpp +++ b/MeshLib/MeshQuality/MeshValidation.cpp @@ -23,7 +23,7 @@ #include "Node.h" #include "Elements/Element.h" #include "MeshEditing/removeMeshNodes.h" - +#include "MeshEditing/MeshRevision.h" namespace MeshLib { @@ -31,6 +31,9 @@ MeshValidation::MeshValidation(MeshLib::Mesh &mesh) { INFO ("Mesh Quality Control:"); this->removeUnusedMeshNodes(mesh); + MeshRevision rev(mesh); + INFO ("Found %d potentially collapsable nodes.", rev.getNCollapsableNodes()); + const std::vector<ElementErrorCode> codes (this->testElementGeometry(mesh)); this->ElementErrorCodeOutput(codes); }