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 <cmath>
7 #include "GmshConfig.h"
8 #include "OctreePost.h"
9 #include "CutParametric.h"
10 #include "Context.h"
11 #include "mathEvaluator.h"
12 
13 #if defined(HAVE_OPENGL)
14 #include "drawContext.h"
15 #endif
16 
17 StringXNumber CutParametricOptions_Number[] = {
18   {GMSH_FULLRC, "MinU", GMSH_CutParametricPlugin::callbackMinU, 0.},
19   {GMSH_FULLRC, "MaxU", GMSH_CutParametricPlugin::callbackMaxU, 2 * 3.1416},
20   {GMSH_FULLRC, "NumPointsU", GMSH_CutParametricPlugin::callbackNU, 180.},
21   {GMSH_FULLRC, "MinV", GMSH_CutParametricPlugin::callbackMinV, 0.},
22   {GMSH_FULLRC, "MaxV", GMSH_CutParametricPlugin::callbackMaxV, 2 * 3.1416},
23   {GMSH_FULLRC, "NumPointsV", GMSH_CutParametricPlugin::callbackNV, 180.},
24   {GMSH_FULLRC, "ConnectPoints", GMSH_CutParametricPlugin::callbackConnect, 0.},
25   {GMSH_FULLRC, "View", nullptr, -1.}};
26 
27 StringXString CutParametricOptions_String[] = {
28   {GMSH_FULLRC, "X", GMSH_CutParametricPlugin::callbackX,
29    "2 * Cos(u) * Sin(v)"},
30   {GMSH_FULLRC, "Y", GMSH_CutParametricPlugin::callbackY,
31    "4 * Sin(u) * Sin(v)"},
32   {GMSH_FULLRC, "Z", GMSH_CutParametricPlugin::callbackZ,
33    "0.1 + 0.5 * Cos(v)"}};
34 
35 extern "C" {
GMSH_RegisterCutParametricPlugin()36 GMSH_Plugin *GMSH_RegisterCutParametricPlugin()
37 {
38   return new GMSH_CutParametricPlugin();
39 }
40 }
41 
getU(int i)42 static double getU(int i)
43 {
44   double minU = CutParametricOptions_Number[0].def;
45   double maxU = CutParametricOptions_Number[1].def;
46   int nbU = (int)CutParametricOptions_Number[2].def;
47 
48   if(nbU == 1)
49     return minU;
50   else
51     return minU + (double)(i) / (double)(nbU - 1) * (maxU - minU);
52 }
53 
getV(int i)54 static double getV(int i)
55 {
56   double minV = CutParametricOptions_Number[3].def;
57   double maxV = CutParametricOptions_Number[4].def;
58   int nbV = (int)CutParametricOptions_Number[5].def;
59 
60   if(nbV == 1)
61     return minV;
62   else
63     return minV + (double)(i) / (double)(nbV - 1) * (maxV - minV);
64 }
65 
66 int GMSH_CutParametricPlugin::recompute = 1;
67 std::vector<double> GMSH_CutParametricPlugin::x;
68 std::vector<double> GMSH_CutParametricPlugin::y;
69 std::vector<double> GMSH_CutParametricPlugin::z;
70 
fillXYZ()71 int GMSH_CutParametricPlugin::fillXYZ()
72 {
73   std::vector<std::string> expressions(3), variables(2);
74   for(int i = 0; i < 3; i++)
75     expressions[i] = CutParametricOptions_String[i].def;
76   variables[0] = "u";
77   variables[1] = "v";
78   mathEvaluator f(expressions, variables);
79   if(expressions.empty()) return 0;
80 
81   int nbU = (int)CutParametricOptions_Number[2].def;
82   int nbV = (int)CutParametricOptions_Number[5].def;
83   x.resize(nbU * nbV);
84   y.resize(nbU * nbV);
85   z.resize(nbU * nbV);
86   std::vector<double> val(2), res(3);
87   for(int i = 0; i < nbU; ++i) {
88     val[0] = getU(i);
89     for(int j = 0; j < nbV; ++j) {
90       val[1] = getV(j);
91       if(f.eval(val, res)) {
92         x[i * nbV + j] = res[0];
93         y[i * nbV + j] = res[1];
94         z[i * nbV + j] = res[2];
95       }
96     }
97   }
98   return 1;
99 }
100 
draw(void * context)101 void GMSH_CutParametricPlugin::draw(void *context)
102 {
103 #if defined(HAVE_OPENGL)
104   if(recompute) {
105     fillXYZ();
106     recompute = 0;
107   }
108   glColor4ubv((GLubyte *)&CTX::instance()->color.fg);
109   int nbU = CutParametricOptions_Number[2].def;
110   int nbV = CutParametricOptions_Number[5].def;
111   if(CutParametricOptions_Number[6].def && x.size() > 1) {
112     if(nbU == 1 || nbV == 1) {
113       glBegin(GL_LINES);
114       for(std::size_t i = 1; i < x.size(); ++i) {
115         glVertex3d(x[i - 1], y[i - 1], z[i - 1]);
116         glVertex3d(x[i], y[i], z[i]);
117       }
118       glEnd();
119     }
120     else {
121       glBegin(GL_TRIANGLES);
122       for(int i = 0; i < nbU - 1; ++i) {
123         for(int j = 0; j < nbV - 1; ++j) {
124           int v = i * nbV + j;
125           glVertex3d(x[v], y[v], z[v]);
126           glVertex3d(x[v + 1], y[v + 1], z[v + 1]);
127           glVertex3d(x[v + 1 + nbV], y[v + 1 + nbV], z[v + 1 + nbV]);
128 
129           glVertex3d(x[v], y[v], z[v]);
130           glVertex3d(x[v + nbV], y[v + nbV], z[v + nbV]);
131           glVertex3d(x[v + 1 + nbV], y[v + 1 + nbV], z[v + 1 + nbV]);
132         }
133       }
134       glEnd();
135     }
136   }
137   else {
138     drawContext *ctx = (drawContext *)context;
139     for(std::size_t i = 0; i < x.size(); ++i)
140       ctx->drawSphere(CTX::instance()->pointSize, x[i], y[i], z[i], 1);
141   }
142 #endif
143 }
144 
callback(int num,int action,double value,double * opt,double step,double min,double max)145 double GMSH_CutParametricPlugin::callback(int num, int action, double value,
146                                           double *opt, double step, double min,
147                                           double max)
148 {
149   switch(action) { // configure the input field
150   case 1: return step;
151   case 2: return min;
152   case 3: return max;
153   default: break;
154   }
155   *opt = value;
156   recompute = 1;
157   GMSH_Plugin::setDrawFunction(draw);
158   return 0.;
159 }
160 
callbackStr(int num,int action,const std::string & value,std::string & opt)161 std::string GMSH_CutParametricPlugin::callbackStr(int num, int action,
162                                                   const std::string &value,
163                                                   std::string &opt)
164 {
165   opt = value;
166   recompute = 1;
167   GMSH_Plugin::setDrawFunction(draw);
168   return opt;
169 }
170 
callbackMinU(int num,int action,double value)171 double GMSH_CutParametricPlugin::callbackMinU(int num, int action, double value)
172 {
173   return callback(num, action, value, &CutParametricOptions_Number[0].def, 0.01,
174                   0., 10.);
175 }
176 
callbackMaxU(int num,int action,double value)177 double GMSH_CutParametricPlugin::callbackMaxU(int num, int action, double value)
178 {
179   return callback(num, action, value, &CutParametricOptions_Number[1].def, 0.01,
180                   0., 10.);
181 }
182 
callbackNU(int num,int action,double value)183 double GMSH_CutParametricPlugin::callbackNU(int num, int action, double value)
184 {
185   return callback(num, action, value, &CutParametricOptions_Number[2].def, 1, 1,
186                   1000);
187 }
188 
callbackMinV(int num,int action,double value)189 double GMSH_CutParametricPlugin::callbackMinV(int num, int action, double value)
190 {
191   return callback(num, action, value, &CutParametricOptions_Number[3].def, 0.01,
192                   0., 10.);
193 }
194 
callbackMaxV(int num,int action,double value)195 double GMSH_CutParametricPlugin::callbackMaxV(int num, int action, double value)
196 {
197   return callback(num, action, value, &CutParametricOptions_Number[4].def, 0.01,
198                   0., 10.);
199 }
200 
callbackNV(int num,int action,double value)201 double GMSH_CutParametricPlugin::callbackNV(int num, int action, double value)
202 {
203   return callback(num, action, value, &CutParametricOptions_Number[5].def, 1, 1,
204                   1000);
205 }
206 
callbackConnect(int num,int action,double value)207 double GMSH_CutParametricPlugin::callbackConnect(int num, int action,
208                                                  double value)
209 {
210   return callback(num, action, value, &CutParametricOptions_Number[6].def, 1, 0,
211                   1);
212 }
213 
callbackX(int num,int action,const std::string & value)214 std::string GMSH_CutParametricPlugin::callbackX(int num, int action,
215                                                 const std::string &value)
216 {
217   return callbackStr(num, action, value, CutParametricOptions_String[0].def);
218 }
219 
callbackY(int num,int action,const std::string & value)220 std::string GMSH_CutParametricPlugin::callbackY(int num, int action,
221                                                 const std::string &value)
222 {
223   return callbackStr(num, action, value, CutParametricOptions_String[1].def);
224 }
225 
callbackZ(int num,int action,const std::string & value)226 std::string GMSH_CutParametricPlugin::callbackZ(int num, int action,
227                                                 const std::string &value)
228 {
229   return callbackStr(num, action, value, CutParametricOptions_String[2].def);
230 }
231 
getHelp() const232 std::string GMSH_CutParametricPlugin::getHelp() const
233 {
234   return "Plugin(CutParametric) cuts the view `View' with "
235          "the parametric function (`X'(u,v), `Y'(u,v), `Z'(u,v)), "
236          "using `NumPointsU' values of the parameter u in "
237          "[`MinU', `MaxU'] and `NumPointsV' values of the parameter v in "
238          "[`MinV', `MaxV'].\n\n"
239          "If `ConnectPoints' is set, the plugin creates surface or line "
240          "elements; otherwise, the plugin generates points.\n\n"
241          "If `View' < 0, the plugin is run on the current view.\n\n"
242          "Plugin(CutParametric) creates one new list-based view.";
243 }
244 
getNbOptions() const245 int GMSH_CutParametricPlugin::getNbOptions() const
246 {
247   return sizeof(CutParametricOptions_Number) / sizeof(StringXNumber);
248 }
249 
getOption(int iopt)250 StringXNumber *GMSH_CutParametricPlugin::getOption(int iopt)
251 {
252   return &CutParametricOptions_Number[iopt];
253 }
254 
getNbOptionsStr() const255 int GMSH_CutParametricPlugin::getNbOptionsStr() const
256 {
257   return sizeof(CutParametricOptions_String) / sizeof(StringXString);
258 }
259 
getOptionStr(int iopt)260 StringXString *GMSH_CutParametricPlugin::getOptionStr(int iopt)
261 {
262   return &CutParametricOptions_String[iopt];
263 }
264 
addInView(int connect,int i,int nbcomp,int nbtime,double x0,double y0,double z0,double * res0,double x,double y,double z,double * res,std::vector<double> & P,int * nP,std::vector<double> & L,int * nL)265 static void addInView(int connect, int i, int nbcomp, int nbtime, double x0,
266                       double y0, double z0, double *res0, double x, double y,
267                       double z, double *res, std::vector<double> &P, int *nP,
268                       std::vector<double> &L, int *nL)
269 {
270   if(connect) {
271     if(i) {
272       L.push_back(x0);
273       L.push_back(x);
274       L.push_back(y0);
275       L.push_back(y);
276       L.push_back(z0);
277       L.push_back(z);
278       for(int k = 0; k < nbtime; ++k) {
279         for(int l = 0; l < nbcomp; ++l) L.push_back(res0[nbcomp * k + l]);
280         for(int l = 0; l < nbcomp; ++l) L.push_back(res[nbcomp * k + l]);
281       }
282       (*nL)++;
283     }
284   }
285   else {
286     P.push_back(x);
287     P.push_back(y);
288     P.push_back(z);
289     for(int k = 0; k < nbtime; ++k)
290       for(int l = 0; l < nbcomp; ++l) P.push_back(res[nbcomp * k + l]);
291     (*nP)++;
292   }
293 }
294 
addInView(int nbcomp,int nbtime,double x0,double y0,double z0,double * res0,double x1,double y1,double z1,double * res1,double x2,double y2,double z2,double * res2,double x3,double y3,double z3,double * res3,std::vector<double> & Q,int * nQ)295 static void addInView(int nbcomp, int nbtime, double x0, double y0, double z0,
296                       double *res0, double x1, double y1, double z1,
297                       double *res1, double x2, double y2, double z2,
298                       double *res2, double x3, double y3, double z3,
299                       double *res3, std::vector<double> &Q, int *nQ)
300 {
301   Q.push_back(x0);
302   Q.push_back(x1);
303   Q.push_back(x2);
304   Q.push_back(x3);
305   Q.push_back(y0);
306   Q.push_back(y1);
307   Q.push_back(y2);
308   Q.push_back(y3);
309   Q.push_back(z0);
310   Q.push_back(z1);
311   Q.push_back(z2);
312   Q.push_back(z3);
313   for(int k = 0; k < nbtime; ++k) {
314     for(int l = 0; l < nbcomp; ++l) Q.push_back(res0[nbcomp * k + l]);
315     for(int l = 0; l < nbcomp; ++l) Q.push_back(res1[nbcomp * k + l]);
316     for(int l = 0; l < nbcomp; ++l) Q.push_back(res2[nbcomp * k + l]);
317     for(int l = 0; l < nbcomp; ++l) Q.push_back(res3[nbcomp * k + l]);
318   }
319   (*nQ)++;
320 }
321 
execute(PView * v)322 PView *GMSH_CutParametricPlugin::execute(PView *v)
323 {
324   int iView = (int)CutParametricOptions_Number[7].def;
325 
326   PView *v1 = getView(iView, v);
327   if(!v1) return v;
328 
329   if(!fillXYZ()) return v;
330 
331   PViewData *data1 = getPossiblyAdaptiveData(v1);
332 
333   int numSteps = data1->getNumTimeSteps();
334   int nbU = (int)CutParametricOptions_Number[2].def;
335   int nbV = (int)CutParametricOptions_Number[5].def;
336   int connect = (int)CutParametricOptions_Number[6].def;
337   if(nbU < 2 && nbV < 2) connect = 0;
338 
339   OctreePost o(v1);
340 
341   PView *v2 = new PView();
342   PViewDataList *data2 = getDataList(v2);
343 
344   double *res0 = new double[9 * numSteps];
345   double *res1 = new double[9 * numSteps];
346   double *res2 = new double[9 * numSteps];
347   double *res3 = new double[9 * numSteps];
348   double x0 = 0., y0 = 0., z0 = 0., x1 = 0., y1 = 0., z1 = 0.;
349   double x2 = 0., y2 = 0., z2 = 0., x3 = 0., y3 = 0., z3 = 0.;
350 
351   for(int k = 0; k < 9 * numSteps; ++k) res0[k] = res1[k] = 0.;
352 
353   if(nbU == 1 || nbV == 1 || !connect) {
354     for(std::size_t i = 0; i < x.size(); ++i) {
355       if(i && connect) {
356         x0 = x1;
357         y0 = y1;
358         z0 = z1;
359         for(int k = 0; k < 9 * numSteps; ++k) res0[k] = res1[k];
360       }
361 
362       x1 = x[i];
363       y1 = y[i];
364       z1 = z[i];
365 
366       if(data1->getNumScalars()) {
367         o.searchScalar(x1, y1, z1, res1);
368         addInView(connect, i, 1, numSteps, x0, y0, z0, res0, x1, y1, z1, res1,
369                   data2->SP, &data2->NbSP, data2->SL, &data2->NbSL);
370       }
371       if(data1->getNumVectors()) {
372         o.searchVector(x1, y1, z1, res1);
373         addInView(connect, i, 3, numSteps, x0, y0, z0, res0, x1, y1, z1, res1,
374                   data2->VP, &data2->NbVP, data2->VL, &data2->NbVL);
375       }
376       if(data1->getNumTensors()) {
377         o.searchTensor(x1, y1, z1, res1);
378         addInView(connect, i, 9, numSteps, x0, y0, z0, res0, x1, y1, z1, res1,
379                   data2->TP, &data2->NbTP, data2->TL, &data2->NbTL);
380       }
381     }
382   }
383   else {
384     for(int i = 0; i < nbU - 1; ++i) {
385       for(int j = 0; j < nbV - 1; ++j) {
386         int v = i * nbV + j;
387         x0 = x[v];
388         y0 = y[v];
389         z0 = z[v];
390         x1 = x[v + 1];
391         y1 = y[v + 1];
392         z1 = z[v + 1];
393         x2 = x[v + nbV + 1];
394         y2 = y[v + nbV + 1];
395         z2 = z[v + nbV + 1];
396         x3 = x[v + nbV];
397         y3 = y[v + nbV];
398         z3 = z[v + nbV];
399 
400         if(data1->getNumScalars()) {
401           o.searchScalar(x0, y0, z0, res0);
402           o.searchScalar(x1, y1, z1, res1);
403           o.searchScalar(x2, y2, z2, res2);
404           o.searchScalar(x3, y3, z3, res3);
405           addInView(1, numSteps, x0, y0, z0, res0, x1, y1, z1, res1, x2, y2, z2,
406                     res2, x3, y3, z3, res3, data2->SQ, &data2->NbSQ);
407         }
408         if(data1->getNumVectors()) {
409           o.searchVector(x0, y0, z0, res0);
410           o.searchVector(x1, y1, z1, res1);
411           o.searchVector(x2, y2, z2, res2);
412           o.searchVector(x3, y3, z3, res3);
413           addInView(3, numSteps, x0, y0, z0, res0, x1, y1, z1, res1, x2, y2, z2,
414                     res2, x3, y3, z3, res3, data2->VQ, &data2->NbVQ);
415         }
416         if(data1->getNumTensors()) {
417           o.searchTensor(x0, y0, z0, res0);
418           o.searchTensor(x1, y1, z1, res1);
419           o.searchTensor(x2, y2, z2, res2);
420           o.searchTensor(x3, y3, z3, res3);
421           addInView(9, numSteps, x0, y0, z0, res0, x1, y1, z1, res1, x2, y2, z2,
422                     res2, x3, y3, z3, res3, data2->TQ, &data2->NbTQ);
423         }
424       }
425     }
426   }
427 
428   delete[] res0;
429   delete[] res1;
430   delete[] res2;
431   delete[] res3;
432 
433   data2->setName(data1->getName() + "_CutParametric");
434   data2->setFileName(data1->getName() + "_CutParametric.pos");
435   data2->finalize();
436 
437   return v2;
438 }
439