1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
// Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
#include <stdlib.h>
#include "GmshGlobal.h"
#include "GModel.h"
#include "MTriangle.h"
#include "Numeric.h"
#include "Bubbles.h"
#include "OS.h"
StringXNumber BubblesOptions_Number[] = {
{GMSH_FULLRC, "ShrinkFactor", nullptr, 0.},
};
StringXString BubblesOptions_String[] = {
{GMSH_FULLRC, "OutputFile", nullptr, "bubbles.geo"}};
extern "C" {
GMSH_Plugin *GMSH_RegisterBubblesPlugin() { return new GMSH_BubblesPlugin(); }
}
std::string GMSH_BubblesPlugin::getHelp() const
{
return "Plugin(Bubbles) constructs a geometry consisting of "
"`bubbles' inscribed in the Voronoi of an input triangulation. "
"`ShrinkFactor' allows to change the size of the bubbles. "
"The plugin expects a triangulation in the `z = 0' plane to exist "
"in the current model.\n\n"
"Plugin(Bubbles) creates one `.geo' file.";
}
int GMSH_BubblesPlugin::getNbOptions() const
{
return sizeof(BubblesOptions_Number) / sizeof(StringXNumber);
}
StringXNumber *GMSH_BubblesPlugin::getOption(int iopt)
{
return &BubblesOptions_Number[iopt];
}
int GMSH_BubblesPlugin::getNbOptionsStr() const
{
return sizeof(BubblesOptions_String) / sizeof(StringXString);
}
StringXString *GMSH_BubblesPlugin::getOptionStr(int iopt)
{
return &BubblesOptions_String[iopt];
}
static double myangle(double c[3], double p[3])
{
double v[3] = {1, 0, 0};
double n[3] = {0, 0, 1};
if(fabs(c[0] - p[0]) < 1e-12 && fabs(c[1] - p[1]) < 1e-12 &&
fabs(c[2] - p[2]) < 1e-12)
return 0.;
return angle_plan(c, v, p, n);
}
class compareAngle {
private:
SPoint3 v;
public:
compareAngle(const SPoint3 &vv) : v(vv) {}
bool operator()(const SPoint3 &b1, const SPoint3 &b2)
{
double p1[3] = {b1.x(), b1.y(), b1.z()};
double p2[3] = {b2.x(), b2.y(), b2.z()};
double c[3] = {v.x(), v.y(), v.z()};
return myangle(c, p1) < myangle(c, p2);
}
};
PView *GMSH_BubblesPlugin::execute(PView *v)
{
double shrink = (double)BubblesOptions_Number[0].def;
std::string fileName = BubblesOptions_String[0].def;
FILE *fp = Fopen(fileName.c_str(), "w");
if(!fp) {
Msg::Error("Could not open output file '%s'", fileName.c_str());
return v;
}
GModel *m = GModel::current();
int p = m->getMaxElementaryNumber(0) + 1;
int l = m->getMaxElementaryNumber(1) + 1;
int s = m->getMaxElementaryNumber(2) + 1;
int ll = s, ps = 1;
SBoundingBox3d bbox = m->bounds();
double lc = norm(SVector3(bbox.max(), bbox.min())) / 100;
fprintf(fp, "lc = %g;\n", lc);
for(auto vit = m->firstVertex(); vit != m->lastVertex(); vit++)
(*vit)->writeGEO(fp, "lc");
for(auto eit = m->firstEdge(); eit != m->lastEdge(); eit++)
(*eit)->writeGEO(fp);
for(auto fit = m->firstFace(); fit != m->lastFace(); fit++) {
(*fit)->writeGEO(fp);
fprintf(fp, "Delete { Surface {%d}; }\n", (*fit)->tag());
int sbeg = s;
int llbeg = ll;
// compute vertex-to-triangle_barycenter map
std::map<MVertex *, std::vector<SPoint3> > v2t;
for(std::size_t i = 0; i < (*fit)->triangles.size(); i++)
for(int j = 0; j < 3; j++)
v2t[(*fit)->triangles[i]->getVertex(j)].push_back(
(*fit)->triangles[i]->barycenter());
// add boundary vertices in map to get cells "closer" to the boundary
for(auto it = v2t.begin(); it != v2t.end(); it++) {
MVertex *v = it->first;
if(v->onWhat() && v->onWhat()->dim() < 2)
it->second.push_back(
SPoint3(it->first->x(), it->first->y(), it->first->z()));
}
for(auto it = v2t.begin(); it != v2t.end(); it++) {
if(it->second.size() > 2) {
// get barycenter of cell boundary points and order them
SPoint3 bc;
for(std::size_t i = 0; i < it->second.size(); i++) bc += it->second[i];
bc *= 1. / (double)it->second.size();
compareAngle comp(bc);
std::sort(it->second.begin(), it->second.end(), comp);
// shrink cells
if(shrink) {
for(std::size_t i = 0; i < it->second.size(); i++) {
double dir[3] = {it->second[i].x() - bc.x(),
it->second[i].y() - bc.y(),
it->second[i].z() - bc.z()};
it->second[i][0] -= shrink * dir[0];
it->second[i][1] -= shrink * dir[1];
it->second[i][2] -= shrink * dir[2];
}
}
// create b-spline bounded surface for each cell
int nump = it->second.size();
for(int i = 0; i < nump; i++) {
SPoint3 &b(it->second[i]);
fprintf(fp, "Point(%d) = {%.16g, %.16g, %.16g, lc};\n", p++, b.x(),
b.y(), b.z());
}
fprintf(fp, "BSpline(%d) = {", l++);
for(int i = nump - 1; i >= 0; i--) fprintf(fp, "%d,", p - i - 1);
fprintf(fp, "%d};\n", p - nump);
fprintf(fp, "Line Loop(%d) = {%d};\n", ll++, l - 1);
fprintf(fp, "Plane Surface(%d) = {%d};\n", s++, ll - 1);
}
}
fprintf(fp, "Physical Surface(%d) = {%d:%d};\n", ps++, sbeg, s - 1);
fprintf(fp, "Plane Surface(%d) = {%d, %d:%d};\n", s++, (*fit)->tag(), llbeg,
ll - 1);
fprintf(fp, "Physical Surface(%d) = {%d};\n", ps++, s - 1);
}
fclose(fp);
return v;
}
|