diff --git a/Plugin/SpanningTree.cpp b/Plugin/SpanningTree.cpp index 4323d6addac2411e147599290e35c9eb8e2a0454..d9b2f09d12ab43b0087f296fafac188760ddc7bf 100644 --- a/Plugin/SpanningTree.cpp +++ b/Plugin/SpanningTree.cpp @@ -4,57 +4,71 @@ // issues on https://gitlab.onelab.info/gmsh/gmsh/issues. // Contributed by Nicolas Marsic. +#include <sstream> +#include <algorithm> + #include "SpanningTree.h" #include "GModel.h" #include "MLine.h" #include "OS.h" +using namespace std; + StringXNumber SpanningTreeOptions_Number[] = { - {GMSH_FULLRC, "PhysicalGroup", NULL, -1}, - {GMSH_FULLRC, "StartingOn", NULL, -1}, {GMSH_FULLRC, "OutputPhysical", NULL, -1}, }; +StringXString SpanningTreeOptions_String[] = { + {GMSH_FULLRC, "PhysicalVolumes", NULL, ""}, + {GMSH_FULLRC, "PhysicalSurfaces", NULL, ""}, + {GMSH_FULLRC, "PhysicalCurves", NULL, ""}, +}; + extern "C" { -GMSH_Plugin *GMSH_RegisterSpanningTreePlugin(void) -{ - return new GMSH_SpanningTreePlugin(); -} + GMSH_Plugin *GMSH_RegisterSpanningTreePlugin(void) + { + return new GMSH_SpanningTreePlugin(); + } } GMSH_SpanningTreePlugin::GMSH_SpanningTreePlugin(void) {} -std::string GMSH_SpanningTreePlugin::getName(void) const +string GMSH_SpanningTreePlugin::getName(void) const { return "SpanningTree"; } -std::string GMSH_SpanningTreePlugin::getShortHelp(void) const +string GMSH_SpanningTreePlugin::getShortHelp(void) const { return "Builds a tree spanning every vertex of a mesh"; } -std::string GMSH_SpanningTreePlugin::getHelp(void) const +string GMSH_SpanningTreePlugin::getHelp(void) const { - return "Plugin(SpanningTree) builds a tree spanning every vertex of a mesh.\n" - "Optionally, this tree can be built by starting on a specific part.\n" - "The generated tree is stored directly in the model.\n" + return "Plugin(SpanningTree) builds a tree spanning every vertex of a mesh " + "and stores it directly in the model.\n" + "The tree is constructed by starting first on the curves, " + "then on the surfaces and finally on the volumes.\n" "\n" "Parameters\n" - "- PhysicalGroup: physical group upon which the tree must be built " - "(-1 means the whole mesh).\n" - "- StartingOn: physical group used to start the tree construction " - "(-1 deactivates this feature).\n" + "- PhysicalVolumes: list of the physical volumes " + "upon which the tree must be built.\n" + "- PhysicalSurfaces: list of the physical surfaces " + "upon which the tree must be built.\n" + "- PhysicalCurves: list of the physical curves " + "upon which the tree must be built.\n" "- OutputPhysical: physical tag of the generated tree " "(-1 will select a new tag automatically).\n" "\n" + "Note - Lists must be comma separated integers " + "and spaces are ignored.\n" "Remark - This plugin does not overwrite a physical group." "Therefore, if an existing physical tag is used in OutputPhysical, " "the edges of the tree will be /added/ to the specified group.\n" "Limitation - Unknown behaviour with curved meshes."; } -std::string GMSH_SpanningTreePlugin::getAuthor(void) const +string GMSH_SpanningTreePlugin::getAuthor(void) const { return "N. Marsic"; } @@ -69,45 +83,66 @@ StringXNumber *GMSH_SpanningTreePlugin::getOption(int iopt) return &SpanningTreeOptions_Number[iopt]; } +int GMSH_SpanningTreePlugin::getNbOptionsStr() const +{ + return sizeof(SpanningTreeOptions_String) / sizeof(StringXString); +} + +StringXString *GMSH_SpanningTreePlugin::getOptionStr(int iopt) +{ + return &SpanningTreeOptions_String[iopt]; +} + void GMSH_SpanningTreePlugin::run(void) { // Get data - double time = Cpu(); - int physical = (int)SpanningTreeOptions_Number[0].def; - int startOn = (int)SpanningTreeOptions_Number[1].def; - int output = (int)SpanningTreeOptions_Number[2].def; + double time = Cpu(); + int output = (int)SpanningTreeOptions_Number[0].def; + string volume = SpanningTreeOptions_String[0].def; + string surface = SpanningTreeOptions_String[1].def; + string curve = SpanningTreeOptions_String[2].def; + + // Parse physical tags + vector<list<int> > physical(3); + curve = parse(curve, physical[0]); + surface = parse(surface, physical[1]); + volume = parse(volume, physical[2]); + + // Dimensions + int dim[3] = {1, 2, 3}; // Get model GModel *model = GModel::current(); - // Get all elements in physical - ElementSet element; - getAllMElement(*model, physical, element); - - // Get all elements in startOn (if defined) - ElementSet elementStartOn; - if(startOn >= 0) getAllMElement(*model, startOn, elementStartOn); + // Get all elements in physicals for each dimension + vector<ElementSet> element(3); + for(int i = 0; i < 3; i++) + for(list<int>::iterator j = physical[i].begin(); j!= physical[i].end(); j++) + getAllMElement(*model, *j, dim[i], element[i]); // Check if we have something - if(element.empty() && elementStartOn.empty()) { - Msg::Warning("No elements found in physcial %d: abording!", physical); + if(element[0].empty() && element[1].empty() && element[2].empty()) { + Msg::Warning("No elements found in the given physcials: abording!"); return; } - // Get all edges from elements - EdgeSet edge; - getAllMEdge(element, edge); + // Display physicals (as [poorly] parsed) // + Msg::Info("--> PhysicalVolumes: %s", volume.c_str()); + Msg::Info("--> PhysicalSurfaces: %s", surface.c_str()); + Msg::Info("--> PhysicalCurves: %s", curve.c_str()); + Msg::Info("--> OutputPhysical: %d", output); - // Get all edges from startOn (if defined) - EdgeSet edgeStartOn; - if(startOn >= 0) getAllMEdge(elementStartOn, edgeStartOn); + // Get all edges from elements for each dimension + vector<EdgeSet> edge(3); + for(int i = 0; i < 3; i++) + getAllMEdge(element[i], edge[i]); - // Build spanning tree and save into the model (begin with startOn if defined) + // Build spanning tree (in ascending dimension order) and save into the model DSU vertex(model->getNumMeshVertices()); Tree tree; - if(startOn >= 0) spanningTree(edgeStartOn, vertex, tree); + for(int i = 0; i < 3; i++) + spanningTree(edge[i], vertex, tree); - spanningTree(edge, vertex, tree); addToModel(*model, tree, output); // Done @@ -132,21 +167,48 @@ void GMSH_SpanningTreePlugin::spanningTree(EdgeSet &edge, DSU &vertex, } } +string GMSH_SpanningTreePlugin::parse(string str, list<int>& physical) +{ + // Remove spaces // + str.erase(remove(str.begin(), str.end(), ' '), str.end()); + + // Replace commas by spaces // + replace(str.begin(), str.end(), ',', ' '); + + // Init string stream // + stringstream stream; + stream << str; + + // Parse stream for integers // + int tag; + string tmp; + while(!stream.eof()){ + stream >> tmp; // Take next 'word' + if(sscanf(tmp.c_str(), "%d", &tag) > 0) + physical.push_back(tag); + } + + // Return modified string // + return str; +} + void GMSH_SpanningTreePlugin::getAllMElement(GModel &model, int physical, - ElementSet &element) + int dim, ElementSet &element) { - std::vector<GEntity *> entities; + std::map<int, std::vector<GEntity*> > group; + std::map<int, std::vector<GEntity*> >::iterator entity; - if(physical == -1) { model.getEntities(entities, -1); } - else { - std::map<int, std::vector<GEntity *> > groups; - model.getPhysicalGroups(-1, groups); - entities = groups[physical]; - } + // Get groups // + model.getPhysicalGroups(dim, group); + + // Get entities, if any // + entity = group.find(physical); + if(entity == group.end()) + return; - for(size_t i = 0; i < entities.size(); i++) - for(size_t j = 0; j < entities[i]->getNumMeshElements(); j++) - element.insert(entities[i]->getMeshElement(j)); + for(size_t i = 0; i < entity->second.size(); i++) + for(size_t j = 0; j < entity->second[i]->getNumMeshElements(); j++) + element.insert(entity->second[i]->getMeshElement(j)); } void GMSH_SpanningTreePlugin::getAllMEdge(ElementSet &element, EdgeSet &edge) diff --git a/Plugin/SpanningTree.h b/Plugin/SpanningTree.h index 2c6c1f5232e73cba5f2b86707b1b373982adb0dc..8d0467561d79023b77e118da57b70d6afd709f9b 100644 --- a/Plugin/SpanningTree.h +++ b/Plugin/SpanningTree.h @@ -25,10 +25,10 @@ private: std::vector<int> rank; public: - DSU(size_t n); + DSU(size_t n); ~DSU(void); - int find(int a); + int find(int a); void join(int a, int b); }; @@ -37,9 +37,9 @@ private: const std::pair<int, int> &b) const; }; - typedef std::set<const MElement *, MElementPtrLessThan> ElementSet; - typedef std::set<std::pair<int, int>, Sort> EdgeSet; - typedef std::list<std::pair<int, int> > Tree; + typedef std::set<const MElement *, MElementPtrLessThan> ElementSet; + typedef std::set<std::pair<int, int>, Sort> EdgeSet; + typedef std::list<std::pair<int, int> > Tree; public: GMSH_SpanningTreePlugin(void); @@ -52,12 +52,17 @@ public: int getNbOptions(void) const; StringXNumber *getOption(int iopt); + int getNbOptionsStr() const; + StringXString *getOptionStr(int iopt); + void run(void); private: static void spanningTree(EdgeSet &edge, DSU &vertex, Tree &tree); - static void getAllMElement(GModel &model, int physical, ElementSet &element); + static std::string parse(std::string str, std::list<int>& physical); + static void getAllMElement(GModel &model, int physical, + int dim, ElementSet &element); static void getAllMEdge(ElementSet &element, EdgeSet &edge); static void addToModel(GModel &model, Tree &tree, int tag);