diff --git a/meshLoader/AneuMeshLoader.cpp b/meshLoader/AneuMeshLoader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a08b94058f76bbebffab737475945b5258c5a97 --- /dev/null +++ b/meshLoader/AneuMeshLoader.cpp @@ -0,0 +1,56 @@ +#include "AneuMeshLoader.h" +#include +#include + +void AneuMeshLoader::loadMesh(const std::string& p_fileName) { + std::ifstream file(p_fileName); + if (!file) { + throw FileNotFound(); + } + else std::cout << "File " << p_fileName << " was opened successfully." << std::endl; + + + //çàãðóçêà óçëîâ + int count; + file >> count; + file.ignore(std::numeric_limits::max(), '\n'); + Nodes.reserve(count); + for (int i = 0; i < count; ++i) { + Node temp; + file >> temp.m_coordinates[0] >> temp.m_coordinates[1] >> temp.m_coordinates[2]; + temp.m_vertexDot = false; + Nodes.insert({ m_nodeId.generateId(), std::move(temp) }); + } + + + //çàãðóçêà ÊÝ + file >> count; + file.ignore(std::numeric_limits::max(), '\n'); + FiniteElements.reserve(count); + for (int i = 0; i < count; ++i) { + int geometryAreaID; + file >> geometryAreaID; + std::vector idLst(Tetrahedron::m_size); + for (int j = 0; j < Tetrahedron::m_size; ++j) { + file >> idLst[j]; + } + Tetrahedron temp(geometryAreaID, idLst); + FiniteElements.insert({ m_finiteElementId.generateId(), std::move(temp) }); + } + + + //çàãðóçêà ãðàíè÷íûõ ÊÝ + file >> count; + file.ignore(std::numeric_limits::max(), '\n'); + BoundaryElements.reserve(count); + for (int i = 0; i < count; ++i) { + int geometryAreaID; + file >> geometryAreaID; + std::vector idLst(Triangle::m_size); + for (int j = 0; j < Triangle::m_size; ++j) { + file >> idLst[j]; + } + Triangle temp(geometryAreaID, idLst); + BoundaryElements.insert({ m_boundaryElementId.generateId(), std::move(temp) }); + } +} \ No newline at end of file diff --git a/meshLoader/AneuMeshLoader.h b/meshLoader/AneuMeshLoader.h new file mode 100644 index 0000000000000000000000000000000000000000..ce08b46f3ba93d2dd094ed668ea3d44e13775610 --- /dev/null +++ b/meshLoader/AneuMeshLoader.h @@ -0,0 +1,12 @@ +#pragma once +#include "MeshLoader.h" +#include "Components.h" +#include "Exceptions.h" +#include +#include + +class AneuMeshLoader : public MeshLoader { +private: +public: + void loadMesh(const std::string&) override; +}; \ No newline at end of file diff --git a/meshLoader/Components.cpp b/meshLoader/Components.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b07406f0f67a19b64515af162a0c73a100c8c9cd --- /dev/null +++ b/meshLoader/Components.cpp @@ -0,0 +1,90 @@ +#include "Components.h" +#include + + +Node::Node(const std::array& p_coordinates, bool p_VertexDot) : + m_coordinates(p_coordinates), m_vertexDot(p_VertexDot) {} + + + +//ôîðìàòèðîâàííûé âûâîä óçëà +std::ostream& operator<<(std::ostream& out, const Node& p_node) { + out << "Node coordinate: (" << p_node.m_coordinates[0] << ";" << p_node.m_coordinates[1] << ";" << p_node.m_coordinates[2] << ")\t"; + if (p_node.m_vertexDot) + out << "Node is a vertex\n"; + else + out << "Node is internal\n"; + out << std::endl; + return out; +} + + +std::ostream& operator<<(std::ostream& out, const std::unordered_map& p_node) { + int i = 1; + for (const auto& node : p_node) { + out << "Node ID: " << node.first << " " << node.second; + } + return out; +}; + + +FiniteElement::FiniteElement(int p_GeometryAreaID, const std::vector& p_NodeIDs) : + m_GeometryAreaID(p_GeometryAreaID), m_NodeIDs(p_NodeIDs) {} + + +//ôîðìàòèðîâàííûé âûâîä ÊÝ +std::ostream& operator<<(std::ostream& out, const Tetrahedron& p_Tetrahedron) { + out << "Geometry Area ID: " << p_Tetrahedron.m_GeometryAreaID << "\t"; + out << "Nodes of Finite Element: "; + for (auto& node : p_Tetrahedron.m_NodeIDs) { + out << node << " "; + } + out << "\n" << std::endl; + return out; +} + + +std::ostream& operator<<(std::ostream& out, const std::unordered_map& p_Tetrahedrons) { + for (const auto& elem : p_Tetrahedrons) + out << "Finite Element ID: " << elem.first << " " << elem.second; + return out; +} + + +std::ostream& operator<<(std::ostream& out, const Triangle& p_Triangle) { + out << "Geometry Area ID: " << p_Triangle.m_GeometryAreaID << "\t"; + out << "Nodes of Boundary Element: "; + for (auto& node : p_Triangle.m_NodeIDs) { + out << node << " "; + } + out << "\n" << std::endl; + return out; +} + + +std::ostream& operator<<(std::ostream& out, const std::unordered_map& p_Triangle) { + for (const auto& elem : p_Triangle) + out << "Boundary Element ID: " << elem.first << " " << elem.second; + return out; +} + + + +Edge::Edge(int p_firstNodeId, int p_secNodeId) + : m_edgeNodes({ p_firstNodeId, p_secNodeId }) {} + + +Edge& Edge::operator=(const Edge& p_edge) { + if (this != &p_edge) { + this->m_edgeNodes = p_edge.m_edgeNodes; + this->m_midNode = p_edge.m_midNode; + } + return *this; +} + + +bool Edge::operator==(const Edge& p_edge) const { + return ((m_edgeNodes.first == p_edge.m_edgeNodes.first) && + (m_edgeNodes.second == p_edge.m_edgeNodes.second)) || ((m_edgeNodes.first == p_edge.m_edgeNodes.second) && + (m_edgeNodes.second == p_edge.m_edgeNodes.first)); +} \ No newline at end of file diff --git a/meshLoader/Components.h b/meshLoader/Components.h new file mode 100644 index 0000000000000000000000000000000000000000..430d3ea88ca9d8ad852a7b74c8282afa64d386e9 --- /dev/null +++ b/meshLoader/Components.h @@ -0,0 +1,63 @@ +#pragma once +#include +#include +#include +#include + +class IdGenerator { +public: + IdGenerator() : currentId(1) {} + int generateId() { + return currentId++; + } +private: + int currentId; +}; + + +struct Node { + static constexpr int dim = 3; + std::array m_coordinates{}; + bool m_vertexDot; + + Node() = default; + Node(const std::array&, bool); + + friend std::ostream& operator<<(std::ostream&, const Node&); + friend std::ostream& operator<<(std::ostream&, const std::unordered_map&); +}; + + +struct FiniteElement { + int m_GeometryAreaID; + std::vector m_NodeIDs; + FiniteElement(int p_GeometryAreaID, const std::vector& p_NodeIDs); +}; + + +class Tetrahedron : public FiniteElement { +public: + static constexpr int m_size = 4; + Tetrahedron(int p_geomId, const std::vector& p_nodes) : FiniteElement(p_geomId, p_nodes) {}; + friend std::ostream& operator<<(std::ostream&, const Tetrahedron&); + friend std::ostream& operator<<(std::ostream&, const std::unordered_map&); +}; + + +class Triangle : public FiniteElement { +public: + static constexpr int m_size = 3; + Triangle(int p_geomId, const std::vector& p_nodes) : FiniteElement(p_geomId, p_nodes) {}; + friend std::ostream& operator<<(std::ostream&, const Triangle&); + friend std::ostream& operator<<(std::ostream&, const std::unordered_map&); +}; + + +struct Edge { + std::pair m_edgeNodes; + int m_midNode = -1; + Edge() = default; + Edge(int, int); + Edge& operator=(const Edge&); + bool operator==(const Edge&) const; +}; diff --git a/meshLoader/Exceptions.h b/meshLoader/Exceptions.h new file mode 100644 index 0000000000000000000000000000000000000000..5518f2486f0863ffc8ce33c906e4dc469f0a4e92 --- /dev/null +++ b/meshLoader/Exceptions.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include + +class FileNotFound : public std::exception +{ + std::string err; +public: + FileNotFound() { + err.assign("File wasn't found!"); + } + + const char* what() const noexcept override { + return err.c_str(); + } +}; + diff --git a/meshLoader/Hash.h b/meshLoader/Hash.h new file mode 100644 index 0000000000000000000000000000000000000000..8dbd1e8d864282d9bbe74eea135e4e7f96fefb7a --- /dev/null +++ b/meshLoader/Hash.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Components.h" + +inline void hashCombine(int& seed, unsigned int& val) { + seed ^= std::hash()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +}; + +inline int hashVal(const Edge& edge) { + int seed = 0; + unsigned int a = std::min(edge.m_edgeNodes.first, edge.m_edgeNodes.second); + unsigned int b = std::max(edge.m_edgeNodes.first, edge.m_edgeNodes.second); + hashCombine(seed, a); + hashCombine(seed, b); + return seed; +}; + +class Hash { +public: + int operator()(const Edge& edge) const { + return hashVal(edge); + } +}; \ No newline at end of file diff --git a/meshLoader/MeshLoader.cpp b/meshLoader/MeshLoader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..807fef24212e9465b121926875ba2e0478b9115d --- /dev/null +++ b/meshLoader/MeshLoader.cpp @@ -0,0 +1,262 @@ +#include +#include +#include +#include +#include "MeshLoader.h" +#include "Hash.h" +#include +#include + + +const std::unordered_map& MeshLoader::getNodes() { + return Nodes; +} + + +const std::unordered_map& MeshLoader::getFiniteElements() { + return FiniteElements; +} + + +const std::unordered_map& MeshLoader::getBoundaryElements() { + return BoundaryElements; +} + + +void MeshLoader::printNodes(const std::unordered_map& p_nodes) { + std::cout << p_nodes; +} + + +void MeshLoader::printFiniteElements(const std::unordered_map& p_elem) { + std::cout << p_elem; +} + + +void MeshLoader::printBoundaryElements(const std::unordered_map& p_elem) { + std::cout << p_elem; +} + + +//ïîëó÷àåò ID ÊÝ ïî òð¸ì óçëàì +std::unordered_set MeshLoader::getFiniteElementIDByNodesID(int p_id1, int p_id2, int p_id3) { + std::unordered_set res; + + for (const auto& pair : FiniteElements) { + const Tetrahedron& elem = pair.second; + if (std::find(elem.m_NodeIDs.begin(), elem.m_NodeIDs.end(), p_id1) != elem.m_NodeIDs.end() && + std::find(elem.m_NodeIDs.begin(), elem.m_NodeIDs.end(), p_id2) != elem.m_NodeIDs.end() && + std::find(elem.m_NodeIDs.begin(), elem.m_NodeIDs.end(), p_id3) != elem.m_NodeIDs.end()) { + res.insert(pair.first); + } + } + return res; +} + + +//ïîëó÷àåò ID ÊÝ ïî äâóì óçëàì(ðåáðó) +std::unordered_set MeshLoader::getFiniteElementIDByEdge(int p_id1, int p_id2) { + std::unordered_set res; + for (const auto& elementPair : FiniteElements) { + const Tetrahedron& element = elementPair.second; + if (std::find(element.m_NodeIDs.begin(), element.m_NodeIDs.end(), p_id1) != element.m_NodeIDs.end() && + std::find(element.m_NodeIDs.begin(), element.m_NodeIDs.end(), p_id2) != element.m_NodeIDs.end()) { + res.insert(elementPair.first); + } + } + return res; +} + + +//ïîëó÷àåò êîíòåéíåð ID óçëîâ ïî ID ãðàíèöû +std::unordered_set MeshLoader::getNodesIDByBorder(int p_id) { + std::unordered_set res; + for (const auto& elementPair : BoundaryElements) { + const Triangle& elem = elementPair.second; + if (elem.m_GeometryAreaID == p_id) { + for (const auto& nodeId : elem.m_NodeIDs) { + res.insert(nodeId); + } + } + } + return res; +} + + +//ïîëó÷àåò êîíòåéíåð ID ÊÝ ïî ID ïîâåðõíîñòè +std::unordered_set MeshLoader::getFiniteElementIdBySurface(int p_id) { + std::unordered_set res; + for (const auto& elementPair : FiniteElements) { + const int elementId = elementPair.first; + const Tetrahedron& element = elementPair.second; + if (element.m_GeometryAreaID == p_id) { + res.insert(elementId); + } + } + return res; +} + + +//ïîëó÷àåò êîíòåéíåð ID ãðàíè÷íîãî ÊÝ ïî ID ãðàíèöû +std::unordered_set MeshLoader::getBoundElementIDByBorder(int _id) { + std::unordered_set res; + for (const auto& pair : BoundaryElements) { + const int elementId = pair.first; + const Triangle& elem = pair.second; + if (elem.m_GeometryAreaID == _id) { + res.insert(elementId); + } + } + return res; +} + + +//ïîëó÷àåò ÊÝ ïî òð¸ì óçëàì +std::vector MeshLoader::getFiniteElementByNodesID(int p_id1, int p_id2, int p_id3) { + std::vector res; + + for (const auto& pair : FiniteElements) { + const Tetrahedron& elem = pair.second; + if (std::find(elem.m_NodeIDs.begin(), elem.m_NodeIDs.end(), p_id1) != elem.m_NodeIDs.end() && + std::find(elem.m_NodeIDs.begin(), elem.m_NodeIDs.end(), p_id2) != elem.m_NodeIDs.end() && + std::find(elem.m_NodeIDs.begin(), elem.m_NodeIDs.end(), p_id3) != elem.m_NodeIDs.end()) { + res.push_back(pair.second); + } + } + return res; +} + + +//ïîëó÷àåò ÊÝ ïî äâóì óçëàì(ðåáðó) +std::vector MeshLoader::getFiniteElementByEdge(int p_id1, int p_id2) { + std::vector res; + for (const auto& elementPair : FiniteElements) { + const Tetrahedron& element = elementPair.second; + if (std::find(element.m_NodeIDs.begin(), element.m_NodeIDs.end(), p_id1) != element.m_NodeIDs.end() && + std::find(element.m_NodeIDs.begin(), element.m_NodeIDs.end(), p_id2) != element.m_NodeIDs.end()) { + res.push_back(elementPair.second); + } + } + return res; +} + + +//ïîëó÷àåò êîíòåéíåð óçëîâ ïî ID ãðàíèöû +std::vector MeshLoader::getNodesByBorder(int p_id) { + std::vector res; + for (const auto& elementPair : BoundaryElements) { + const Triangle& elem = elementPair.second; + if (elem.m_GeometryAreaID == p_id) { + for (const auto& nodeId : elem.m_NodeIDs) { + res.push_back(Nodes[nodeId]); + } + } + } + return res; +} + + +//ïîëó÷àåò êîíòåéíåð ÊÝ ïî ID ïîâåðõíîñòè +std::vector MeshLoader::getFiniteElementBySurface(int p_id) { + std::vector res; + for (const auto& elementPair : FiniteElements) { + const Tetrahedron& elem = elementPair.second; + if (elem.m_GeometryAreaID == p_id) { + res.push_back(elem); + } + } + return res; +} + + +//ïîëó÷àåò êîíòåéíåð ãðàíè÷íûõ ÊÝ ïî ID ãðàíèöû +std::vector MeshLoader::getBoundElementByBorder(int _id) { + std::vector res; + for (const auto& pair : BoundaryElements) { + const Triangle& elem = pair.second; + if (elem.m_GeometryAreaID == _id) { + res.push_back(elem); + } + } + return res; +} + + +//âîçâðàùàåò âåêòîð ID ñîñåäíèõ óçëîâ +std::unordered_map> MeshLoader::createNeighborsMap() { + std::unordered_map> neighbors; + for (const auto& pair : BoundaryElements) { + const Triangle& elem = pair.second; + for (auto nodeId : elem.m_NodeIDs) { + for (auto anthNodeId : elem.m_NodeIDs) { + if (nodeId != anthNodeId) { + neighbors[nodeId].insert(anthNodeId); + } + } + } + } + + for (const auto& pair : neighbors) { + std::cout << "Neighbours of node " << pair.first << ": "; + for (const auto& neighborId : pair.second) { + std::cout << neighborId << " "; + } + std::cout << std::endl; + } + std::cout << std::endl; + + return neighbors; +} + + +// âñòàâêà óçëîâ â ñåðåäèíû ð¸áåð +Node MeshLoader::getMiddleNode(const Edge& edge) { + double MiddleX = (Nodes[edge.m_edgeNodes.first].m_coordinates[0] + + Nodes[edge.m_edgeNodes.second].m_coordinates[0]) / 2.0; + double MiddleY = (Nodes[edge.m_edgeNodes.first].m_coordinates[1] + + Nodes[edge.m_edgeNodes.second].m_coordinates[1]) / 2.0; + double MiddleZ = (Nodes[edge.m_edgeNodes.first].m_coordinates[2] + + Nodes[edge.m_edgeNodes.second].m_coordinates[2]) / 2.0; + Node newNode({ MiddleX, MiddleY, MiddleZ }, (Nodes[edge.m_edgeNodes.first].m_vertexDot && Nodes[edge.m_edgeNodes.first].m_vertexDot)); + return newNode; +} + + +void MeshLoader::insertNodeMid() { + std::unordered_set edges; + std::unordered_map edgeToMidNodeId; + + for (auto& elemPair : FiniteElements) { + Tetrahedron& elem = elemPair.second; + std::vector newMidNodeIDs; + for (int i = 0; i < elem.m_NodeIDs.size(); ++i) { + for (int j = i + 1; j < elem.m_NodeIDs.size(); ++j) { + Edge curEdge(elem.m_NodeIDs[i], elem.m_NodeIDs[j]); + if (edges.insert(curEdge).second) { + Node newNode = getMiddleNode(curEdge); + int newId = m_nodeId.generateId(); + Nodes[newId] = newNode; + edgeToMidNodeId[curEdge] = newId; + newMidNodeIDs.push_back(newId); + } + } + } + elem.m_NodeIDs.insert(elem.m_NodeIDs.end(), newMidNodeIDs.begin(), newMidNodeIDs.end()); + } + for (auto& belemPair : BoundaryElements) { + Triangle& belem = belemPair.second; + for (int i = 0; i < belem.m_NodeIDs.size(); ++i) { + for (int j = i + 1; j < belem.m_NodeIDs.size(); ++j) { + Edge curEdge(belem.m_NodeIDs[i], belem.m_NodeIDs[j]); + auto it = edgeToMidNodeId.find(curEdge); + if (it == edgeToMidNodeId.end()) { + curEdge = { curEdge.m_edgeNodes.second, curEdge.m_edgeNodes.first }; + it = edgeToMidNodeId.find(curEdge); + } + if (it != edgeToMidNodeId.end()) { + belem.m_NodeIDs.push_back(it->second); + } + } + } + } +} diff --git a/meshLoader/MeshLoader.h b/meshLoader/MeshLoader.h new file mode 100644 index 0000000000000000000000000000000000000000..07f7f1c6b0f09609b9153f1766176249a35625af --- /dev/null +++ b/meshLoader/MeshLoader.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include +#include +#include +#include "Components.h" +#include "unordered_set" +class MeshLoader { +private: + Node getMiddleNode(const Edge&); +protected: + IdGenerator m_nodeId; + IdGenerator m_finiteElementId; + IdGenerator m_boundaryElementId; + std::unordered_map Nodes; + std::unordered_map FiniteElements; + std::unordered_map BoundaryElements; +public: + virtual void loadMesh(const std::string&) = 0; + virtual ~MeshLoader() = default; + + const std::unordered_map& getNodes(); + const std::unordered_map& getFiniteElements(); + const std::unordered_map& getBoundaryElements(); + + std::unordered_set getFiniteElementIDByNodesID(int, int, int); + std::unordered_set getFiniteElementIDByEdge(int, int); + std::unordered_set getNodesIDByBorder(int); + std::unordered_set getFiniteElementIdBySurface(int); + std::unordered_set getBoundElementIDByBorder(int); + + std::vector getFiniteElementByNodesID(int, int, int); + std::vector getFiniteElementByEdge(int, int); + std::vector getNodesByBorder(int); + std::vector getFiniteElementBySurface(int); + std::vector getBoundElementByBorder(int); + + static void printNodes(const std::unordered_map&); + static void printFiniteElements(const std::unordered_map&); + static void printBoundaryElements(const std::unordered_map&); + + void insertNodeMid(); + + std::unordered_map> createNeighborsMap(); +}; + diff --git a/meshLoader/main.cpp b/meshLoader/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d3d227f0024fad81c23bbec942edae3f504f11b --- /dev/null +++ b/meshLoader/main.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "MeshLoader.h" +#include "AneuMeshLoader.h" +using namespace std; + +int main(int argc, char* argv[]) { + std::string filepath = "./cube.aneu"; + if (argc != 2) + std::cout << "Wrong number of arguments, using standard file PATH\n" << std::endl; + else { + std::cout << "Set file path to " << argv[1] << "\n" << std::endl; + filepath = argv[1]; + }; + + + MeshLoader* l = new AneuMeshLoader(); + try { + l->loadMesh(filepath); + } + catch (std::exception& er) { + std::cerr << er.what() << std::endl; + delete l; + return 0; + } + + + std::cout << "Nodes from file: \n" << std::endl; + l->printNodes(l->getNodes()); + + + std::cout << "Finite Elements from file: \n" << std::endl; + l->printFiniteElements(l->getFiniteElements()); + + + std::cout << "Bouundary Finite Elements from file: \n" << std::endl; + l->printBoundaryElements(l->getBoundaryElements()); + + + std::cout << "Neighbours of Nodes: \n" << std::endl; + l->createNeighborsMap(); + + + std::cout << "ID Finite elements by nodes (4,1,2)" << std::endl; + auto finelem_1 = l->getFiniteElementIDByNodesID(4, 1, 2); + for (int elem : finelem_1) { + std::cout << elem << " "; + } + std::cout << std::endl << "-----------------------------------" << std::endl; + + + std::cout << "ID Finite elements by Edge (4,7)" << std::endl; + auto finelem_2 = l->getFiniteElementIDByEdge(4, 7); + for (int elem : finelem_2) { + std::cout << elem << " "; + } + std::cout << std::endl << "-----------------------------------" << std::endl; + + + std::cout << "ID of Nodes by Geometry Area ID of Bounder element (3)" << std::endl; + auto finnode = l->getNodesIDByBorder(3); + for (int node : finnode) { + std::cout << node << " "; + } + std::cout << std::endl << "-----------------------------------" << std::endl; + + + std::cout << "ID Finite elements by surface ID (1)" << std::endl; + auto finelem_3 = l->getFiniteElementIdBySurface(1); + for (int elem : finelem_3) { + std::cout << elem << " "; + } + std::cout << std::endl << "-----------------------------------" << std::endl; + + + std::cout << "Boundary element ID by boundary ID (2)" << std::endl; + auto finelem_4 = l->getBoundElementIDByBorder(2); + for (int elem : finelem_4) { + std::cout << elem << " "; + } + std::cout << std::endl << "-----------------------------------" << std::endl; + + + std::cout << "inserting middle Elements: \n" << std::endl; + l->insertNodeMid(); + + + std::cout << "Nodes after inserting middle Element: \n" << std::endl; + l->printNodes(l->getNodes()); + + + std::cout << "Neighbours of new Nodes: \n" << std::endl; + l->createNeighborsMap(); + + + delete l; + return 0; +} \ No newline at end of file