diff --git a/Plugin/CMakeLists.txt b/Plugin/CMakeLists.txt index 8ed250915f82ed5d37b428fe0ef880c261e82fb5..b93ce557b7ed5973db18ef7ee3a390a6a5ed1c9b 100644 --- a/Plugin/CMakeLists.txt +++ b/Plugin/CMakeLists.txt @@ -31,7 +31,7 @@ set(SRC Scal2Vec.cpp CutMesh.cpp NewView.cpp - SimplePartition.cpp + SimplePartition.cpp Crack.cpp ) file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) diff --git a/Plugin/Crack.cpp b/Plugin/Crack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6468d4dee7e0dce46e650a0d627bf9c3fe4ce730 --- /dev/null +++ b/Plugin/Crack.cpp @@ -0,0 +1,243 @@ +// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to the public mailing list <gmsh@geuz.org>. + +#include "Crack.h" +#include "GModel.h" +#include "partitionFace.h" +#include "partitionEdge.h" +#include "MElement.h" +#include "MLine.h" +#include "MTriangle.h" +#include "MQuadrangle.h" +#include "MFace.h" +#include "MEdge.h" +#include "mathEvaluator.h" +#if defined(HAVE_MESH) +#include "meshPartition.h" +#endif + +StringXNumber CrackOptions_Number[] = { + {GMSH_FULLRC, "Dimension", NULL, 1.}, + {GMSH_FULLRC, "PhysicalGroup", NULL, 1.}, +}; + +extern "C" +{ + GMSH_Plugin *GMSH_RegisterCrackPlugin() + { + return new GMSH_CrackPlugin(); + } +} + +std::string GMSH_CrackPlugin::getHelp() const +{ + return "Plugin(Crack) creates a crack around the physical group"; +} + +int GMSH_CrackPlugin::getNbOptions() const +{ + return sizeof(CrackOptions_Number) / sizeof(StringXNumber); +} + +StringXNumber *GMSH_CrackPlugin::getOption(int iopt) +{ + return &CrackOptions_Number[iopt]; +} + +class EdgeData{ +public: + EdgeData(MEdge e) : edge(e) {} + MEdge edge; + std::vector<MVertex*> data; +}; + +struct Less_EdgeData : public std::binary_function<EdgeData, EdgeData, bool> { + bool operator()(const EdgeData &e1, const EdgeData &e2) const + { + if(e1.edge.getMinVertex() < e2.edge.getMinVertex()) return true; + if(e1.edge.getMinVertex() > e2.edge.getMinVertex()) return false; + if(e1.edge.getMaxVertex() < e2.edge.getMaxVertex()) return true; + return false; + } +}; + +PView *GMSH_CrackPlugin::execute(PView *view) +{ + int dim = (int)CrackOptions_Number[0].def; + int physical = (int)CrackOptions_Number[1].def; + + if(dim != 1 && dim != 2){ + Msg::Error("Crack dimension should be 1 or 2"); + return view; + } + + GModel *m = GModel::current(); + std::map<int, std::vector<GEntity*> > groups[4]; + m->getPhysicalGroups(groups); + std::vector<GEntity*> entities = groups[dim][physical]; + + if(entities.empty()){ + Msg::Error("Physical group %d (dimension %d) is empty", physical, dim); + return view; + } + + // get crack elements + std::vector<MElement*> crackElements; + for(unsigned int i = 0; i < entities.size(); i++) + for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++) + crackElements.push_back(entities[i]->getMeshElement(j)); + + // get internal crack vertices + std::set<MVertex*> crackVertices, bndVertices; + if(dim == 1){ + for(unsigned int i = 0; i < crackElements.size(); i++){ + for(int j = 0; j < crackElements[i]->getNumVertices(); j++){ + MVertex *v = crackElements[i]->getVertex(j); + crackVertices.insert(v); + if(bndVertices.find(v) == bndVertices.end()) + bndVertices.insert(v); + else + bndVertices.erase(v); + } + } + } + else{ + std::set<EdgeData, Less_EdgeData> bnd; + for(unsigned int i = 0; i < crackElements.size(); i++){ + for(int j = 0; j < crackElements[i]->getNumVertices(); j++){ + MVertex *v = crackElements[i]->getVertex(j); + crackVertices.insert(v); + } + for(int j = 0; j < crackElements[i]->getNumEdges(); j++){ + EdgeData ed(crackElements[i]->getEdge(j)); + if(bnd.find(ed) == bnd.end()){ + crackElements[i]->getEdgeVertices(j, ed.data); + bnd.insert(ed); + } + else + bnd.erase(ed); + } + } + for(std::set<EdgeData>::iterator it = bnd.begin(); it != bnd.end(); it++) + bndVertices.insert(it->data.begin(), it->data.end()); + } + for(std::set<MVertex*>::iterator it = bndVertices.begin(); + it != bndVertices.end(); it++) + crackVertices.erase(*it); + + // compute smoothed normals on crack vertices + std::map<MVertex*, std::vector<MElement*> > vxe; + for(unsigned int i = 0; i < crackElements.size(); i++){ + MElement *e = crackElements[i]; + for(int k = 0; k < e->getNumVertices(); k++) + vxe[e->getVertex(k)].push_back(e); + } + std::map<MVertex*, SVector3> vxn; + for(std::map<MVertex*, std::vector<MElement*> >::iterator it = vxe.begin(); + it != vxe.end(); it++){ + SVector3 n; + for(unsigned int i = 0; i < it->second.size(); i++){ + if(dim == 1) + n += it->second[i]->getEdge(0).normal(); + else + n += it->second[i]->getFace(0).normal(); + } + n.normalize(); + vxn[it->first] = n; + } + + // compute elements on one side of the crack + vxe.clear(); + std::vector<GEntity*> allentities; + m->getEntities(allentities); + for(unsigned int ent = 0; ent < allentities.size(); ent++){ + if(allentities[ent]->dim() != dim + 1) continue; + for(int i = 0; i < allentities[ent]->getNumMeshElements(); i++){ + MElement *e = allentities[ent]->getMeshElement(i); + for(int j = 0; j < e->getNumVertices(); j++){ + MVertex *v = e->getVertex(j); + if(crackVertices.find(v) != crackVertices.end()){ + MVertex *vclose = 0; + double d = 1e22; + SVector3 dv; + for(std::set<MVertex*>::iterator it = crackVertices.begin(); + it != crackVertices.end(); it++){ + MVertex *v = *it; + double d2 = v->point().distance(e->barycenter()); + if(d2 < d){ + d = d2; + vclose = v; + dv = SVector3(e->barycenter(), vclose->point()); + } + } + if(dot(vxn[vclose], dv) < 0) + vxe[v].push_back(e); + } + } + } + } + + // create new crack entity + GEdge *crackEdge = 0; + GFace *crackFace = 0; + if(dim == 1){ + crackEdge = new discreteEdge(m, m->getMaxElementaryNumber(1) + 1, 0, 0); + m->add(crackEdge); + } + else{ + crackFace = new discreteFace(m, m->getMaxElementaryNumber(2) + 1); + m->add(crackFace); + } + GEntity *crackEntity = crackEdge ? (GEntity*)crackEdge : (GEntity*)crackFace; + crackEntity->physicals.push_back(physical); + + // duplicate crack vertices + std::map<MVertex *, MVertex*> vxv; + for(std::set<MVertex*>::iterator it = crackVertices.begin(); + it != crackVertices.end(); it++){ + MVertex *v = *it; + MVertex *newv = new MVertex(v->x(), v->y(), v->z(), crackEntity); + crackEntity->mesh_vertices.push_back(newv); + vxv[v] = newv; + } + + // duplicate crack elements + for(unsigned int i = 0; i < crackElements.size(); i++){ + MElement *e = crackElements[i]; + std::vector<MVertex*> verts; + e->getVertices(verts); + for(unsigned int j = 0; j < verts.size(); j++){ + if(vxv.count(verts[j])) + verts[j] = vxv[verts[j]]; + } + MElementFactory f; + MElement *newe = f.create(e->getTypeForMSH(), verts, 0, e->getPartition()); + if(crackEdge && newe->getType() == TYPE_LIN) + crackEdge->lines.push_back((MLine*)newe); + else if(crackFace && newe->getType() == TYPE_TRI) + crackFace->triangles.push_back((MTriangle*)newe); + else if(crackFace && newe->getType() == TYPE_QUA) + crackFace->quadrangles.push_back((MQuadrangle*)newe); + } + + // replace vertices in elements on one side of the crack + std::set<MElement*> eles; + for(std::map<MVertex*, std::vector<MElement*> >::iterator it = vxe.begin(); + it != vxe.end(); it++){ + for(unsigned int i = 0; i < it->second.size(); i++) + eles.insert(it->second[i]); + } + for(std::set<MElement*>::iterator it = eles.begin(); it != eles.end(); it++){ + MElement *e = *it; + for(int i = 0; i < e->getNumVertices(); i++){ + if(vxv.count(e->getVertex(i))) + e->setVertex(i, vxv[e->getVertex(i)]); + } + } + + CTX::instance()->mesh.changed = ENT_ALL; + + return view; +} diff --git a/Plugin/Crack.h b/Plugin/Crack.h new file mode 100644 index 0000000000000000000000000000000000000000..6ce6c8a59e3bb8e1876f2cf8a4d51d08ff5e64ad --- /dev/null +++ b/Plugin/Crack.h @@ -0,0 +1,31 @@ +// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to the public mailing list <gmsh@geuz.org>. + +#ifndef _CRACK_H_ +#define _CRACK_H_ + +#include "Plugin.h" + +extern "C" +{ + GMSH_Plugin *GMSH_RegisterCrackPlugin(); +} + +class GMSH_CrackPlugin : public GMSH_PostPlugin +{ + public: + GMSH_CrackPlugin(){} + std::string getName() const { return "Crack"; } + std::string getShortHelp() const + { + return "Crack generator"; + } + std::string getHelp() const; + int getNbOptions() const; + StringXNumber* getOption(int iopt); + PView *execute(PView *); +}; + +#endif diff --git a/Plugin/PluginManager.cpp b/Plugin/PluginManager.cpp index 58512784be0df258118c6ddcf5368bc65b086b3a..b1acc9510150b52e004247f1ae5df4471a5b5560 100644 --- a/Plugin/PluginManager.cpp +++ b/Plugin/PluginManager.cpp @@ -23,6 +23,7 @@ #include "MathEval.h" #include "ExtractElements.h" #include "SimplePartition.h" +#include "Crack.h" #include "HarmonicToTime.h" #include "ModulusPhase.h" #include "Integrate.h" @@ -242,6 +243,8 @@ void PluginManager::registerDefaultPlugins() ("NewView", GMSH_RegisterNewViewPlugin())); allPlugins.insert(std::pair<std::string, GMSH_Plugin*> ("SimplePartition", GMSH_RegisterSimplePartitionPlugin())); + allPlugins.insert(std::pair<std::string, GMSH_Plugin*> + ("Crack", GMSH_RegisterCrackPlugin())); #if defined(HAVE_TETGEN) allPlugins.insert(std::pair<std::string, GMSH_Plugin*> ("Tetrahedralize", GMSH_RegisterTetrahedralizePlugin())); diff --git a/doc/VERSIONS.txt b/doc/VERSIONS.txt index 0ca581f4b65340af3a39de830b8e28592c57d011..7c0206f385cb97bfdb5cbcc2928d96ff9cc41b4b 100644 --- a/doc/VERSIONS.txt +++ b/doc/VERSIONS.txt @@ -1,6 +1,6 @@ -?: new single-window GUI, with dynamically customizable widget tree; faster -STEP/BRep import; arbitrary size image export; faster 2D Delaunay/Frontal -algorithms; full option viewer/editor; random bug fixes. +2.7.0 (?): new single-window GUI, with dynamically customizable widget tree; +faster STEP/BRep import; arbitrary size image export; faster 2D Delaunay/Frontal +algorithms; full option viewer/editor; many bug fixes. 2.6.1 (July 15, 2012): minor improvements and bug fixes.