1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include "GmshConfig.h"
7 #include "OctreePost.h"
8 #include "CutGrid.h"
9 #include "Context.h"
10 
11 #if defined(HAVE_OPENGL)
12 #include "drawContext.h"
13 #endif
14 
15 StringXNumber CutGridOptions_Number[] = {
16   {GMSH_FULLRC, "X0", GMSH_CutGridPlugin::callbackX0, 0.},
17   {GMSH_FULLRC, "Y0", GMSH_CutGridPlugin::callbackY0, 0.},
18   {GMSH_FULLRC, "Z0", GMSH_CutGridPlugin::callbackZ0, 0.},
19   {GMSH_FULLRC, "X1", GMSH_CutGridPlugin::callbackX1, 1.},
20   {GMSH_FULLRC, "Y1", GMSH_CutGridPlugin::callbackY1, 0.},
21   {GMSH_FULLRC, "Z1", GMSH_CutGridPlugin::callbackZ1, 0.},
22   {GMSH_FULLRC, "X2", GMSH_CutGridPlugin::callbackX2, 0.},
23   {GMSH_FULLRC, "Y2", GMSH_CutGridPlugin::callbackY2, 1.},
24   {GMSH_FULLRC, "Z2", GMSH_CutGridPlugin::callbackZ2, 0.},
25   {GMSH_FULLRC, "NumPointsU", GMSH_CutGridPlugin::callbackU, 20},
26   {GMSH_FULLRC, "NumPointsV", GMSH_CutGridPlugin::callbackV, 20},
27   {GMSH_FULLRC, "ConnectPoints", GMSH_CutGridPlugin::callbackConnect, 1},
28   {GMSH_FULLRC, "View", nullptr, -1.}};
29 
30 extern "C" {
GMSH_RegisterCutGridPlugin()31 GMSH_Plugin *GMSH_RegisterCutGridPlugin() { return new GMSH_CutGridPlugin(); }
32 }
33 
draw(void * context)34 void GMSH_CutGridPlugin::draw(void *context)
35 {
36 #if defined(HAVE_OPENGL)
37   glColor4ubv((GLubyte *)&CTX::instance()->color.fg);
38   double p[3];
39   drawContext *ctx = (drawContext *)context;
40 
41   getPoint(0, 0, p);
42   ctx->drawString("(X0, Y0, Z0)", p[0], p[1], p[2]);
43   if(getNbU() > 1) {
44     getPoint(getNbU() - 1, 0, p);
45     ctx->drawString("(X1, Y1, Z1)", p[0], p[1], p[2]);
46   }
47   if(getNbV() > 1) {
48     getPoint(0, getNbV() - 1, p);
49     ctx->drawString("(X2, Y2, Z2)", p[0], p[1], p[2]);
50   }
51 
52   if(CutGridOptions_Number[11].def) {
53     glBegin(GL_LINES);
54     for(int i = 0; i < getNbU(); ++i) {
55       getPoint(i, 0, p);
56       glVertex3d(p[0], p[1], p[2]);
57       getPoint(i, getNbV() - 1, p);
58       glVertex3d(p[0], p[1], p[2]);
59     }
60     for(int i = 0; i < getNbV(); ++i) {
61       getPoint(0, i, p);
62       glVertex3d(p[0], p[1], p[2]);
63       getPoint(getNbU() - 1, i, p);
64       glVertex3d(p[0], p[1], p[2]);
65     }
66     glEnd();
67   }
68   else {
69     for(int i = 0; i < getNbU(); ++i) {
70       for(int j = 0; j < getNbV(); ++j) {
71         getPoint(i, j, p);
72         ctx->drawSphere(CTX::instance()->pointSize, p[0], p[1], p[2], 1);
73       }
74     }
75   }
76 #endif
77 }
78 
callback(int num,int action,double value,double * opt,double step,double min,double max)79 double GMSH_CutGridPlugin::callback(int num, int action, double value,
80                                     double *opt, double step, double min,
81                                     double max)
82 {
83   switch(action) { // configure the input field
84   case 1: return step;
85   case 2: return min;
86   case 3: return max;
87   default: break;
88   }
89   *opt = value;
90   GMSH_Plugin::setDrawFunction(draw);
91   return 0.;
92 }
93 
callbackX0(int num,int action,double value)94 double GMSH_CutGridPlugin::callbackX0(int num, int action, double value)
95 {
96   return callback(num, action, value, &CutGridOptions_Number[0].def,
97                   CTX::instance()->lc / 100., CTX::instance()->min[0],
98                   CTX::instance()->max[0]);
99 }
100 
callbackY0(int num,int action,double value)101 double GMSH_CutGridPlugin::callbackY0(int num, int action, double value)
102 {
103   return callback(num, action, value, &CutGridOptions_Number[1].def,
104                   CTX::instance()->lc / 100., CTX::instance()->min[1],
105                   CTX::instance()->max[1]);
106 }
107 
callbackZ0(int num,int action,double value)108 double GMSH_CutGridPlugin::callbackZ0(int num, int action, double value)
109 {
110   return callback(num, action, value, &CutGridOptions_Number[2].def,
111                   CTX::instance()->lc / 100., CTX::instance()->min[2],
112                   CTX::instance()->max[2]);
113 }
114 
callbackX1(int num,int action,double value)115 double GMSH_CutGridPlugin::callbackX1(int num, int action, double value)
116 {
117   return callback(num, action, value, &CutGridOptions_Number[3].def,
118                   CTX::instance()->lc / 100., CTX::instance()->min[0],
119                   CTX::instance()->max[0]);
120 }
121 
callbackY1(int num,int action,double value)122 double GMSH_CutGridPlugin::callbackY1(int num, int action, double value)
123 {
124   return callback(num, action, value, &CutGridOptions_Number[4].def,
125                   CTX::instance()->lc / 100., CTX::instance()->min[1],
126                   CTX::instance()->max[1]);
127 }
128 
callbackZ1(int num,int action,double value)129 double GMSH_CutGridPlugin::callbackZ1(int num, int action, double value)
130 {
131   return callback(num, action, value, &CutGridOptions_Number[5].def,
132                   CTX::instance()->lc / 100., CTX::instance()->min[2],
133                   CTX::instance()->max[2]);
134 }
135 
callbackX2(int num,int action,double value)136 double GMSH_CutGridPlugin::callbackX2(int num, int action, double value)
137 {
138   return callback(num, action, value, &CutGridOptions_Number[6].def,
139                   CTX::instance()->lc / 100., CTX::instance()->min[0],
140                   CTX::instance()->max[0]);
141 }
142 
callbackY2(int num,int action,double value)143 double GMSH_CutGridPlugin::callbackY2(int num, int action, double value)
144 {
145   return callback(num, action, value, &CutGridOptions_Number[7].def,
146                   CTX::instance()->lc / 100., CTX::instance()->min[1],
147                   CTX::instance()->max[1]);
148 }
149 
callbackZ2(int num,int action,double value)150 double GMSH_CutGridPlugin::callbackZ2(int num, int action, double value)
151 {
152   return callback(num, action, value, &CutGridOptions_Number[8].def,
153                   CTX::instance()->lc / 100., CTX::instance()->min[2],
154                   CTX::instance()->max[2]);
155 }
156 
callbackU(int num,int action,double value)157 double GMSH_CutGridPlugin::callbackU(int num, int action, double value)
158 {
159   return callback(num, action, value, &CutGridOptions_Number[9].def, 1, 1, 200);
160 }
161 
callbackV(int num,int action,double value)162 double GMSH_CutGridPlugin::callbackV(int num, int action, double value)
163 {
164   return callback(num, action, value, &CutGridOptions_Number[10].def, 1, 1,
165                   200);
166 }
167 
callbackConnect(int num,int action,double value)168 double GMSH_CutGridPlugin::callbackConnect(int num, int action, double value)
169 {
170   return callback(num, action, value, &CutGridOptions_Number[11].def, 1, 0, 1);
171 }
172 
getHelp() const173 std::string GMSH_CutGridPlugin::getHelp() const
174 {
175   return "Plugin(CutGrid) cuts the view `View' with a "
176          "rectangular grid defined by the 3 points "
177          "(`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U) "
178          "and (`X2',`Y2',`Z2') (axis of V).\n\n"
179          "The number of points along U and V is set with the "
180          "options `NumPointsU' and `NumPointsV'.\n\n"
181          "If `ConnectPoints' is zero, the plugin creates points; "
182          "otherwise, the plugin generates quadrangles, lines or "
183          "points depending on the values of `NumPointsU' and "
184          "`NumPointsV'.\n\n"
185          "If `View' < 0, the plugin is run on the current view.\n\n"
186          "Plugin(CutGrid) creates one new list-based view.";
187 }
188 
getNbOptions() const189 int GMSH_CutGridPlugin::getNbOptions() const
190 {
191   return sizeof(CutGridOptions_Number) / sizeof(StringXNumber);
192 }
193 
getOption(int iopt)194 StringXNumber *GMSH_CutGridPlugin::getOption(int iopt)
195 {
196   return &CutGridOptions_Number[iopt];
197 }
198 
getNbU()199 int GMSH_CutGridPlugin::getNbU() { return (int)CutGridOptions_Number[9].def; }
200 
getNbV()201 int GMSH_CutGridPlugin::getNbV() { return (int)CutGridOptions_Number[10].def; }
202 
getPoint(int iU,int iV,double * X)203 void GMSH_CutGridPlugin::getPoint(int iU, int iV, double *X)
204 {
205   double u = getNbU() > 1 ? (double)iU / (double)(getNbU() - 1.) : 0.;
206   double v = getNbV() > 1 ? (double)iV / (double)(getNbV() - 1.) : 0.;
207   X[0] = CutGridOptions_Number[0].def +
208          u * (CutGridOptions_Number[3].def - CutGridOptions_Number[0].def) +
209          v * (CutGridOptions_Number[6].def - CutGridOptions_Number[0].def);
210   X[1] = CutGridOptions_Number[1].def +
211          u * (CutGridOptions_Number[4].def - CutGridOptions_Number[1].def) +
212          v * (CutGridOptions_Number[7].def - CutGridOptions_Number[1].def);
213   X[2] = CutGridOptions_Number[2].def +
214          u * (CutGridOptions_Number[5].def - CutGridOptions_Number[2].def) +
215          v * (CutGridOptions_Number[8].def - CutGridOptions_Number[2].def);
216 }
217 
addInView(int numsteps,int connect,int nbcomp,double *** pnts,double *** vals,std::vector<double> & P,int * nP,std::vector<double> & L,int * nL,std::vector<double> & Q,int * nQ)218 void GMSH_CutGridPlugin::addInView(int numsteps, int connect, int nbcomp,
219                                    double ***pnts, double ***vals,
220                                    std::vector<double> &P, int *nP,
221                                    std::vector<double> &L, int *nL,
222                                    std::vector<double> &Q, int *nQ)
223 {
224   if(!connect || (getNbU() == 1 && getNbV() == 1)) { // generate points
225 
226     for(int i = 0; i < getNbU(); ++i) {
227       for(int j = 0; j < getNbV(); ++j) {
228         P.push_back(pnts[i][j][0]);
229         P.push_back(pnts[i][j][1]);
230         P.push_back(pnts[i][j][2]);
231         (*nP)++;
232         for(int k = 0; k < numsteps; ++k) {
233           for(int l = 0; l < nbcomp; ++l)
234             P.push_back(vals[i][j][nbcomp * k + l]);
235         }
236       }
237     }
238   }
239   else { // generate lines or quads
240 
241     if(getNbU() == 1) {
242       for(int i = 0; i < getNbV() - 1; ++i) {
243         L.push_back(pnts[0][i][0]);
244         L.push_back(pnts[0][i + 1][0]);
245         L.push_back(pnts[0][i][1]);
246         L.push_back(pnts[0][i + 1][1]);
247         L.push_back(pnts[0][i][2]);
248         L.push_back(pnts[0][i + 1][2]);
249         (*nL)++;
250         for(int k = 0; k < numsteps; ++k) {
251           for(int l = 0; l < nbcomp; ++l)
252             L.push_back(vals[0][i][nbcomp * k + l]);
253           for(int l = 0; l < nbcomp; ++l)
254             L.push_back(vals[0][i + 1][nbcomp * k + l]);
255         }
256       }
257     }
258     else if(getNbV() == 1) {
259       for(int i = 0; i < getNbU() - 1; ++i) {
260         L.push_back(pnts[i][0][0]);
261         L.push_back(pnts[i + 1][0][0]);
262         L.push_back(pnts[i][0][1]);
263         L.push_back(pnts[i + 1][0][1]);
264         L.push_back(pnts[i][0][2]);
265         L.push_back(pnts[i + 1][0][2]);
266         (*nL)++;
267         for(int k = 0; k < numsteps; ++k) {
268           for(int l = 0; l < nbcomp; ++l)
269             L.push_back(vals[i][0][nbcomp * k + l]);
270           for(int l = 0; l < nbcomp; ++l)
271             L.push_back(vals[i + 1][0][nbcomp * k + l]);
272         }
273       }
274     }
275     else {
276       for(int i = 0; i < getNbU() - 1; ++i) {
277         for(int j = 0; j < getNbV() - 1; ++j) {
278           Q.push_back(pnts[i][j][0]);
279           Q.push_back(pnts[i + 1][j][0]);
280           Q.push_back(pnts[i + 1][j + 1][0]);
281           Q.push_back(pnts[i][j + 1][0]);
282           Q.push_back(pnts[i][j][1]);
283           Q.push_back(pnts[i + 1][j][1]);
284           Q.push_back(pnts[i + 1][j + 1][1]);
285           Q.push_back(pnts[i][j + 1][1]);
286           Q.push_back(pnts[i][j][2]);
287           Q.push_back(pnts[i + 1][j][2]);
288           Q.push_back(pnts[i + 1][j + 1][2]);
289           Q.push_back(pnts[i][j + 1][2]);
290           (*nQ)++;
291           for(int k = 0; k < numsteps; ++k) {
292             for(int l = 0; l < nbcomp; ++l)
293               Q.push_back(vals[i][j][nbcomp * k + l]);
294             for(int l = 0; l < nbcomp; ++l)
295               Q.push_back(vals[i + 1][j][nbcomp * k + l]);
296             for(int l = 0; l < nbcomp; ++l)
297               Q.push_back(vals[i + 1][j + 1][nbcomp * k + l]);
298             for(int l = 0; l < nbcomp; ++l)
299               Q.push_back(vals[i][j + 1][nbcomp * k + l]);
300           }
301         }
302       }
303     }
304   }
305 }
306 
GenerateView(PView * v1,int connect)307 PView *GMSH_CutGridPlugin::GenerateView(PView *v1, int connect)
308 {
309   if(getNbU() <= 0 || getNbV() <= 0) return v1;
310 
311   PViewData *data1 = getPossiblyAdaptiveData(v1);
312 
313   PView *v2 = new PView();
314   PViewDataList *data2 = getDataList(v2);
315 
316   OctreePost o(v1);
317 
318   int nbs = data1->getNumScalars();
319   int nbv = data1->getNumVectors();
320   int nbt = data1->getNumTensors();
321   int maxcomp = nbt ? 9 : (nbv ? 3 : 1);
322   int numsteps = data1->getNumTimeSteps();
323 
324   double ***pnts = new double **[getNbU()];
325   double ***vals = new double **[getNbU()];
326   for(int i = 0; i < getNbU(); i++) {
327     pnts[i] = new double *[getNbV()];
328     vals[i] = new double *[getNbV()];
329     for(int j = 0; j < getNbV(); j++) {
330       pnts[i][j] = new double[3];
331       vals[i][j] = new double[maxcomp * numsteps];
332       getPoint(i, j, pnts[i][j]);
333     }
334   }
335 
336   if(nbs) {
337     for(int i = 0; i < getNbU(); i++)
338       for(int j = 0; j < getNbV(); j++)
339         o.searchScalar(pnts[i][j][0], pnts[i][j][1], pnts[i][j][2], vals[i][j]);
340     addInView(numsteps, connect, 1, pnts, vals, data2->SP, &data2->NbSP,
341               data2->SL, &data2->NbSL, data2->SQ, &data2->NbSQ);
342   }
343 
344   if(nbv) {
345     for(int i = 0; i < getNbU(); i++)
346       for(int j = 0; j < getNbV(); j++)
347         o.searchVector(pnts[i][j][0], pnts[i][j][1], pnts[i][j][2], vals[i][j]);
348     addInView(numsteps, connect, 3, pnts, vals, data2->VP, &data2->NbVP,
349               data2->VL, &data2->NbVL, data2->VQ, &data2->NbVQ);
350   }
351 
352   if(nbt) {
353     for(int i = 0; i < getNbU(); i++)
354       for(int j = 0; j < getNbV(); j++)
355         o.searchTensor(pnts[i][j][0], pnts[i][j][1], pnts[i][j][2], vals[i][j]);
356     addInView(numsteps, connect, 9, pnts, vals, data2->TP, &data2->NbTP,
357               data2->TL, &data2->NbTL, data2->TQ, &data2->NbTQ);
358   }
359 
360   for(int i = 0; i < getNbU(); i++) {
361     for(int j = 0; j < getNbV(); j++) {
362       delete[] pnts[i][j];
363       delete[] vals[i][j];
364     }
365     delete[] pnts[i];
366     delete[] vals[i];
367   }
368   delete[] pnts;
369   delete[] vals;
370 
371   data2->setName(data1->getName() + "_CutGrid");
372   data2->setFileName(data1->getName() + "_CutGrid.pos");
373   data2->finalize();
374 
375   return v2;
376 }
377 
execute(PView * v)378 PView *GMSH_CutGridPlugin::execute(PView *v)
379 {
380   int connectPoints = (int)CutGridOptions_Number[11].def;
381   int iView = (int)CutGridOptions_Number[12].def;
382 
383   PView *v1 = getView(iView, v);
384   if(!v1) return v;
385 
386   return GenerateView(v1, connectPoints);
387 }
388