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 // Contributor(s):
7 //   Gaetan Bricteux
8 //
9 
10 #include <queue>
11 #include <stack>
12 #include <cmath>
13 #include "gmshLevelset.h"
14 #include "fullMatrix.h"
15 #include "GModel.h"
16 #include "OS.h"
17 #include "MElement.h"
18 #include "Numeric.h"
19 #include "cartesian.h"
20 #include "GmshConfig.h"
21 #include "mathEvaluator.h"
22 
23 #if defined(HAVE_ANN)
24 #include "ANN/ANN.h"
25 #endif
26 
27 std::set<gLevelset *, gLevelsetLessThan> gLevelset::all_;
28 int gLevelset::maxTag_ = 0;
29 
operator ()(const gLevelset * l1,const gLevelset * l2) const30 bool gLevelsetLessThan::operator()(const gLevelset *l1,
31                                    const gLevelset *l2) const
32 {
33   return l1->getTag() < l2->getTag();
34 }
35 
find(int tag)36 gLevelset *gLevelset::find(int tag)
37 {
38   gLevelset l(tag);
39   auto it = all_.find(&l);
40   if(it == all_.end()) return nullptr;
41   return *it;
42 }
43 
add(gLevelset * l)44 void gLevelset::add(gLevelset *l) { all_.insert(l); }
45 
insertActiveCells(double x,double y,double z,double rmax,cartesianBox<double> & box)46 void insertActiveCells(double x, double y, double z, double rmax,
47                        cartesianBox<double> &box)
48 {
49   int id1 = box.getCellContainingPoint(x - rmax, y - rmax, z - rmax);
50   int id2 = box.getCellContainingPoint(x + rmax, y + rmax, z + rmax);
51   int i1, j1, k1;
52   box.getCellIJK(id1, i1, j1, k1);
53   int i2, j2, k2;
54   box.getCellIJK(id2, i2, j2, k2);
55   for(int i = i1; i <= i2; i++)
56     for(int j = j1; j <= j2; j++)
57       for(int k = k1; k <= k2; k++)
58         box.insertActiveCell(box.getCellIndex(i, j, k));
59 }
60 
fillPointCloud(GEdge * ge,double sampling,std::vector<SPoint3> & points)61 void fillPointCloud(GEdge *ge, double sampling, std::vector<SPoint3> &points)
62 {
63   Range<double> t_bounds = ge->parBounds(0);
64   double t_min = t_bounds.low();
65   double t_max = t_bounds.high();
66   double length = ge->length(t_min, t_max, 20);
67   int N = length / sampling;
68   for(int i = 0; i < N; i++) {
69     double t = t_min + (double)i / (double)(N - 1) * (t_max - t_min);
70     GPoint p = ge->point(t);
71     points.push_back(SPoint3(p.x(), p.y(), p.z()));
72   }
73 }
74 
removeBadChildCells(cartesianBox<double> * parent)75 int removeBadChildCells(cartesianBox<double> *parent)
76 {
77   cartesianBox<double> *child = parent->getChildBox();
78   if(!child) return 0;
79   int I = parent->getNxi();
80   int J = parent->getNeta();
81   int K = parent->getNzeta();
82   for(int i = 0; i < I; i++)
83     for(int j = 0; j < J; j++)
84       for(int k = 0; k < K; k++) {
85         // remove children if they do not entirely fill parent, or if
86         // there is no parent on the boundary
87         int idx[8] = {child->getCellIndex(2 * i, 2 * j, 2 * k),
88                       child->getCellIndex(2 * i, 2 * j, 2 * k + 1),
89                       child->getCellIndex(2 * i, 2 * j + 1, 2 * k),
90                       child->getCellIndex(2 * i, 2 * j + 1, 2 * k + 1),
91                       child->getCellIndex(2 * i + 1, 2 * j, 2 * k),
92                       child->getCellIndex(2 * i + 1, 2 * j, 2 * k + 1),
93                       child->getCellIndex(2 * i + 1, 2 * j + 1, 2 * k),
94                       child->getCellIndex(2 * i + 1, 2 * j + 1, 2 * k + 1)};
95         bool exist[8], atLeastOne = false, butNotAll = false;
96         for(int ii = 0; ii < 8; ii++) {
97           exist[ii] = child->activeCellExists(idx[ii]);
98           if(exist[ii]) atLeastOne = true;
99           if(!exist[ii]) butNotAll = true;
100         }
101         if(atLeastOne &&
102            (butNotAll ||
103             (i != 0 &&
104              !parent->activeCellExists(parent->getCellIndex(i - 1, j, k))) ||
105             (i != I - 1 &&
106              !parent->activeCellExists(parent->getCellIndex(i + 1, j, k))) ||
107             (j != 0 &&
108              !parent->activeCellExists(parent->getCellIndex(i, j - 1, k))) ||
109             (j != J - 1 &&
110              !parent->activeCellExists(parent->getCellIndex(i, j + 1, k))) ||
111             (k != 0 &&
112              !parent->activeCellExists(parent->getCellIndex(i, j, k - 1))) ||
113             (k != K - 1 &&
114              !parent->activeCellExists(parent->getCellIndex(i, j, k + 1)))))
115           for(int ii = 0; ii < 8; ii++) child->eraseActiveCell(idx[ii]);
116       }
117   return removeBadChildCells(child);
118 }
119 
removeParentCellsWithChildren(cartesianBox<double> * box)120 void removeParentCellsWithChildren(cartesianBox<double> *box)
121 {
122   if(!box->getChildBox()) return;
123   for(int i = 0; i < box->getNxi(); i++)
124     for(int j = 0; j < box->getNeta(); j++)
125       for(int k = 0; k < box->getNzeta(); k++) {
126         if(box->activeCellExists(box->getCellIndex(i, j, k))) {
127           cartesianBox<double> *parent = box, *child;
128           int ii = i, jj = j, kk = k;
129           while((child = parent->getChildBox())) {
130             ii *= 2;
131             jj *= 2;
132             kk *= 2;
133             if(child->activeCellExists(child->getCellIndex(ii, jj, kk))) {
134               box->eraseActiveCell(box->getCellIndex(i, j, k));
135               break;
136             }
137             parent = child;
138           }
139         }
140       }
141   removeParentCellsWithChildren(box->getChildBox());
142 }
143 
computeLevelset(GModel * gm,cartesianBox<double> & box)144 void computeLevelset(GModel *gm, cartesianBox<double> &box)
145 {
146   std::vector<SPoint3> nodes;
147   std::vector<int> indices;
148   for(auto it = box.nodalValuesBegin(); it != box.nodalValuesEnd(); ++it) {
149     nodes.push_back(box.getNodeCoordinates(it->first));
150     indices.push_back(it->first);
151   }
152   // Msg::Info("  %d nodes in the grid at level %d", (int)nodes.size(),
153   // box.getLevel());
154   std::vector<double> dist, localdist;
155   std::vector<SPoint3> dummy;
156   for(auto fit = gm->firstFace(); fit != gm->lastFace(); fit++) {
157     if((*fit)->geomType() == GEntity::DiscreteSurface) {
158       for(std::size_t k = 0; k < (*fit)->getNumMeshElements(); k++) {
159         std::vector<double> iDistances;
160         std::vector<SPoint3> iClosePts;
161         std::vector<double> iDistancesE;
162         MElement *e = (*fit)->getMeshElement(k);
163         if(e->getType() == TYPE_TRI) {
164           MVertex *v1 = e->getVertex(0);
165           MVertex *v2 = e->getVertex(1);
166           MVertex *v3 = e->getVertex(2);
167           SPoint3 p1(v1->x(), v1->y(), v1->z());
168           SPoint3 p2(v2->x(), v2->y(), v2->z());
169           SPoint3 p3(v3->x(), v3->y(), v3->z());
170           // sign plus if in the direction of the normal
171           signedDistancesPointsTriangle(localdist, dummy, nodes, p2, p1, p3);
172         }
173         if(dist.empty())
174           dist = localdist;
175         else {
176           for(std::size_t j = 0; j < localdist.size(); j++) {
177             dist[j] =
178               (fabs(dist[j]) < fabs(localdist[j])) ? dist[j] : localdist[j];
179           }
180         }
181       }
182     }
183     else {
184       // we should use the STL here
185       Msg::Info("Levelset computation on CAD surface not implemented");
186     }
187   }
188 
189   for(std::size_t j = 0; j < dist.size(); j++)
190     box.setNodalValue(indices[j], dist[j]);
191 
192   if(box.getChildBox()) computeLevelset(gm, *box.getChildBox());
193 }
194 
det3(double d11,double d12,double d13,double d21,double d22,double d23,double d31,double d32,double d33)195 inline double det3(double d11, double d12, double d13, double d21, double d22,
196                    double d23, double d31, double d32, double d33)
197 {
198   return d11 * (d22 * d33 - d23 * d32) - d21 * (d12 * d33 - d13 * d32) +
199          d31 * (d12 * d23 - d13 * d22);
200 }
201 
norm(const double * vec,double * norm)202 inline void norm(const double *vec, double *norm)
203 {
204   double n = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
205   norm[0] = vec[0] / n;
206   norm[1] = vec[1] / n;
207   norm[2] = vec[2] / n;
208 }
209 
cross(const double * pt0,const double * pt1,const double * pt2,double * cross)210 inline void cross(const double *pt0, const double *pt1, const double *pt2,
211                   double *cross)
212 {
213   double v1[3] = {pt1[0] - pt0[0], pt1[1] - pt0[1], pt1[2] - pt0[2]};
214   double v2[3] = {pt2[0] - pt0[0], pt2[1] - pt0[1], pt2[2] - pt0[2]};
215   cross[0] = v1[1] * v2[2] - v2[1] * v1[2];
216   cross[1] = v2[0] * v1[2] - v1[0] * v2[2];
217   cross[2] = v1[0] * v2[1] - v2[0] * v1[1];
218 }
219 
isPlanar(const double * pt1,const double * pt2,const double * pt3,const double * pt4)220 inline bool isPlanar(const double *pt1, const double *pt2, const double *pt3,
221                      const double *pt4)
222 {
223   double c1[3];
224   cross(pt1, pt2, pt3, c1);
225   double c2[3];
226   cross(pt1, pt2, pt4, c2);
227   double n1[3];
228   norm(c1, n1);
229   double n2[3];
230   norm(c2, n2);
231   return (n1[0] == n2[0] && n1[1] == n2[1] && n1[2] == n2[2]);
232 }
233 
evalRadialFnDer(int p,int index,double dx,double dy,double dz,double ep)234 inline double evalRadialFnDer(int p, int index, double dx, double dy, double dz,
235                               double ep)
236 {
237   double r2 = dx * dx + dy * dy + dz * dz; // r^2
238   switch(index) {
239   case 0: // GA
240     switch(p) {
241     case 0: return exp(-ep * ep * r2);
242     case 1: return -2 * ep * ep * dx * exp(-ep * ep * r2); // _x
243     case 2: return -2 * ep * ep * dy * exp(-ep * ep * r2); // _y
244     case 3: return -2 * ep * ep * dz * exp(-ep * ep * r2); // _z
245     }
246   case 1: // MQ
247     switch(p) {
248     case 0: return sqrt(1 + ep * ep * r2);
249     case 1: return ep * ep * dx / sqrt(1 + ep * ep * r2);
250     case 2: return ep * ep * dy / sqrt(1 + ep * ep * r2);
251     case 3: return ep * ep * dz / sqrt(1 + ep * ep * r2);
252     }
253   }
254   return 0.;
255 }
256 
printNodes(fullMatrix<double> & myNodes,fullMatrix<double> & surf)257 inline void printNodes(fullMatrix<double> &myNodes, fullMatrix<double> &surf)
258 {
259   FILE *xyz = Fopen("myNodes.pos", "w");
260   if(xyz) {
261     fprintf(xyz, "View \"\"{\n");
262     for(int itv = 1; itv != myNodes.size1(); ++itv) {
263       fprintf(xyz, "SP(%g,%g,%g){%g};\n", myNodes(itv, 0), myNodes(itv, 1),
264               myNodes(itv, 2), surf(itv, 0));
265     }
266     fprintf(xyz, "};\n");
267     fclose(xyz);
268   }
269 }
270 
271 // extrude a list of the primitive levelsets with a "Level-order traversal
272 // sequence"
getPrimitives(std::vector<gLevelset * > & gLsPrimitives)273 void gLevelset::getPrimitives(std::vector<gLevelset *> &gLsPrimitives)
274 {
275   std::queue<gLevelset *> Q;
276   Q.push(this);
277   while(!Q.empty()) {
278     gLevelset *p = Q.front();
279     std::vector<gLevelset *> pp;
280     pp = p->getChildren();
281     if(pp.empty()) gLsPrimitives.push_back(p);
282     Q.pop();
283     if(!pp.empty()) {
284       for(int i = 0; i < (int)pp.size(); i++) Q.push(pp[i]);
285     }
286   }
287 }
288 
289 // extrude a list of the primitive levelsets with a "post-order traversal
290 // sequence"
getPrimitivesPO(std::vector<gLevelset * > & gLsPrimitives)291 void gLevelset::getPrimitivesPO(std::vector<gLevelset *> &gLsPrimitives)
292 {
293   std::stack<gLevelset *> S;
294   std::stack<gLevelset *> Sc; // levelset checked
295   S.push(this);
296   while(!S.empty()) {
297     gLevelset *p = S.top();
298     std::vector<gLevelset *> pp;
299     pp = p->getChildren();
300     if(pp.empty()) {
301       gLsPrimitives.push_back(p);
302       S.pop();
303     }
304     else {
305       if(Sc.empty() || p != Sc.top()) {
306         for(int i = 1; i < (int)pp.size(); i++) Sc.push(p);
307         for(int i = (int)pp.size() - 1; i >= 0; i--) {
308           S.push(pp[i]);
309           if(i > 1) S.push(p);
310         }
311       }
312       else { // levelset has been checked
313         S.pop();
314         Sc.pop();
315       }
316     }
317   }
318 }
319 
320 // return a list with the levelsets in a "Reverse Polish Notation"
getRPN(std::vector<gLevelset * > & gLsRPN)321 void gLevelset::getRPN(std::vector<gLevelset *> &gLsRPN)
322 {
323   std::stack<gLevelset *> S;
324   std::stack<gLevelset *> Sc; // levelset checked
325   S.push(this);
326   while(!S.empty()) {
327     gLevelset *p = S.top();
328     std::vector<gLevelset *> pp;
329     pp = p->getChildren();
330     if(pp.empty()) {
331       gLsRPN.push_back(p);
332       S.pop();
333     }
334     else {
335       if(Sc.empty() || p != Sc.top()) {
336         for(int i = 1; i < (int)pp.size(); i++) Sc.push(p);
337         for(int i = (int)pp.size() - 1; i >= 0; i--) {
338           S.push(pp[i]);
339           if(i > 1) S.push(p);
340         }
341       }
342       else { // levelset has been checked
343         S.pop();
344         Sc.pop();
345         gLsRPN.push_back(p);
346       }
347     }
348   }
349 }
350 
gLevelset(const gLevelset & lv)351 gLevelset::gLevelset(const gLevelset &lv) { tag_ = lv.tag_; }
352 
gLevelsetSphere(const double & x,const double & y,const double & z,const double & R,int tag)353 gLevelsetSphere::gLevelsetSphere(const double &x, const double &y,
354                                  const double &z, const double &R, int tag)
355   : gLevelsetPrimitive(tag), xc(x), yc(y), zc(z), r(R)
356 {
357   _hasDerivatives = true;
358 }
359 
gradient(double x,double y,double z,double & dfdx,double & dfdy,double & dfdz) const360 void gLevelsetSphere::gradient(double x, double y, double z, double &dfdx,
361                                double &dfdy, double &dfdz) const
362 {
363   const double xx = x - xc, yy = y - yc, zz = z - zc,
364                dist = sqrt(xx * xx + yy * yy + zz * zz);
365 
366   dfdx = xx / dist;
367   dfdy = yy / dist;
368   dfdz = zz / dist;
369 }
370 
hessian(double x,double y,double z,double & dfdxx,double & dfdxy,double & dfdxz,double & dfdyx,double & dfdyy,double & dfdyz,double & dfdzx,double & dfdzy,double & dfdzz) const371 void gLevelsetSphere::hessian(double x, double y, double z, double &dfdxx,
372                               double &dfdxy, double &dfdxz, double &dfdyx,
373                               double &dfdyy, double &dfdyz, double &dfdzx,
374                               double &dfdzy, double &dfdzz) const
375 {
376   const double xx = x - xc, yy = y - yc, zz = z - zc;
377   const double distSq = xx * xx + yy * yy, fact = 1. / (distSq * sqrt(distSq));
378 
379   dfdxx = (zz * zz + yy * yy) * fact;
380   dfdxy = -xx * yy * fact;
381   dfdxz = -xx * zz * fact;
382   dfdyx = dfdxy;
383   dfdyy = (xx * xx + zz * zz) * fact;
384   dfdyz = -yy * zz * fact;
385   dfdzx = dfdxz;
386   dfdzy = dfdyz;
387   dfdzz = (xx * xx + yy * yy) * fact;
388 }
389 
gLevelsetPlane(const std::vector<double> & pt,const std::vector<double> & norm,int tag)390 gLevelsetPlane::gLevelsetPlane(const std::vector<double> &pt,
391                                const std::vector<double> &norm, int tag)
392   : gLevelsetPrimitive(tag)
393 {
394   a = norm[0];
395   b = norm[1];
396   c = norm[2];
397   d = -a * pt[0] - b * pt[1] - c * pt[2];
398 }
399 
gLevelsetPlane(const double * pt,const double * norm,int tag)400 gLevelsetPlane::gLevelsetPlane(const double *pt, const double *norm, int tag)
401   : gLevelsetPrimitive(tag)
402 {
403   a = norm[0];
404   b = norm[1];
405   c = norm[2];
406   d = -a * pt[0] - b * pt[1] - c * pt[2];
407 }
408 
gLevelsetPlane(const double * pt1,const double * pt2,const double * pt3,int tag)409 gLevelsetPlane::gLevelsetPlane(const double *pt1, const double *pt2,
410                                const double *pt3, int tag)
411   : gLevelsetPrimitive(tag)
412 {
413   a = det3(1., pt1[1], pt1[2], 1., pt2[1], pt2[2], 1., pt3[1], pt3[2]);
414   b = det3(pt1[0], 1., pt1[2], pt2[0], 1., pt2[2], pt3[0], 1., pt3[2]);
415   c = det3(pt1[0], pt1[1], 1., pt2[0], pt2[1], 1., pt3[0], pt3[1], 1.);
416   d = -det3(pt1[0], pt1[1], pt1[2], pt2[0], pt2[1], pt2[2], pt3[0], pt3[1],
417             pt3[2]);
418 }
419 
gLevelsetPlane(const gLevelsetPlane & lv)420 gLevelsetPlane::gLevelsetPlane(const gLevelsetPlane &lv)
421   : gLevelsetPrimitive(lv)
422 {
423   a = lv.a;
424   b = lv.b;
425   c = lv.c;
426   d = lv.d;
427 }
428 
429 // level set defined by points (RBF interpolation)
430 fullMatrix<double>
generateRbfMat(int p,int index,const fullMatrix<double> & nodes1,const fullMatrix<double> & nodes2) const431 gLevelsetPoints::generateRbfMat(int p, int index,
432                                 const fullMatrix<double> &nodes1,
433                                 const fullMatrix<double> &nodes2) const
434 {
435   int m = nodes2.size1();
436   int n = nodes1.size1();
437   fullMatrix<double> rbfMat(m, n);
438 
439   double eps = 0.5 / delta;
440   for(int i = 0; i < m; i++) {
441     for(int j = 0; j < n; j++) {
442       double dx = nodes2(i, 0) - nodes1(j, 0);
443       double dy = nodes2(i, 1) - nodes1(j, 1);
444       double dz = nodes2(i, 2) - nodes1(j, 2);
445       rbfMat(i, j) = evalRadialFnDer(p, index, dx, dy, dz, eps);
446     }
447   }
448   return rbfMat;
449 }
450 
RbfOp(int p,int index,const fullMatrix<double> & cntrs,const fullMatrix<double> & nodes,fullMatrix<double> & D,bool isLocal) const451 void gLevelsetPoints::RbfOp(int p, int index, const fullMatrix<double> &cntrs,
452                             const fullMatrix<double> &nodes,
453                             fullMatrix<double> &D, bool isLocal) const
454 {
455   fullMatrix<double> rbfMatB = generateRbfMat(p, index, cntrs, nodes);
456 
457   fullMatrix<double> rbfInvA;
458   if(isLocal) {
459     rbfInvA = generateRbfMat(0, index, cntrs, cntrs);
460     rbfInvA.invertInPlace();
461   }
462   else {
463     rbfInvA = matAInv;
464   }
465 
466   D.resize(nodes.size1(), cntrs.size1());
467   D.gemm(rbfMatB, rbfInvA, 1.0, 0.0);
468 }
469 
evalRbfDer(int p,int index,const fullMatrix<double> & cntrs,const fullMatrix<double> & nodes,const fullMatrix<double> & fValues,fullMatrix<double> & fApprox,bool isLocal) const470 void gLevelsetPoints::evalRbfDer(int p, int index,
471                                  const fullMatrix<double> &cntrs,
472                                  const fullMatrix<double> &nodes,
473                                  const fullMatrix<double> &fValues,
474                                  fullMatrix<double> &fApprox,
475                                  bool isLocal) const
476 {
477   fApprox.resize(nodes.size1(), fValues.size2());
478   fullMatrix<double> D;
479   RbfOp(p, index, cntrs, nodes, D, isLocal);
480   fApprox.gemm(D, fValues, 1.0, 0.0);
481 }
482 
setup_level_set(const fullMatrix<double> & cntrs,fullMatrix<double> & level_set_nodes,fullMatrix<double> & level_set_funvals)483 void gLevelsetPoints::setup_level_set(const fullMatrix<double> &cntrs,
484                                       fullMatrix<double> &level_set_nodes,
485                                       fullMatrix<double> &level_set_funvals)
486 {
487   int numNodes = cntrs.size1();
488   int nTot = 3 * numNodes;
489   double normFactor;
490   level_set_nodes.resize(nTot, 3);
491   level_set_funvals.resize(nTot, 1);
492   fullMatrix<double> ONES(numNodes + 1, 1), sx(numNodes, 1), sy(numNodes, 1);
493   fullMatrix<double> sz(numNodes, 1), norms(numNodes, 3),
494     cntrsPlus(numNodes + 1, 3);
495 
496   // Computes the normal vectors to the surface at each node
497   double dist_min = 1.e6;
498   double dist_max = 1.e-6;
499   for(int i = 0; i < numNodes; ++i) {
500     ONES(i, 0) = 1.0;
501     cntrsPlus(i, 0) = cntrs(i, 0);
502     cntrsPlus(i, 1) = cntrs(i, 1);
503     cntrsPlus(i, 2) = cntrs(i, 2);
504     for(int j = i + 1; j < numNodes; j++) {
505       double dist =
506         sqrt((cntrs(i, 0) - cntrs(j, 0)) * (cntrs(i, 0) - cntrs(j, 0)) +
507              (cntrs(i, 1) - cntrs(j, 1)) * (cntrs(i, 1) - cntrs(j, 1)) +
508              (cntrs(i, 2) - cntrs(j, 2)) * (cntrs(i, 2) - cntrs(j, 2)));
509       if(dist < dist_min) dist_min = dist;
510       if(dist > dist_max) dist_max = dist;
511     }
512   }
513   ONES(numNodes, 0) = -1.0;
514   cntrsPlus(numNodes, 0) = cntrs(0, 0) + dist_max;
515   cntrsPlus(numNodes, 1) = cntrs(0, 1) + dist_max;
516   cntrsPlus(numNodes, 2) = cntrs(0, 2) + dist_max;
517 
518   delta = 0.23 * dist_min;
519   evalRbfDer(1, 1, cntrsPlus, cntrs, ONES, sx, true);
520   evalRbfDer(2, 1, cntrsPlus, cntrs, ONES, sy, true);
521   evalRbfDer(3, 1, cntrsPlus, cntrs, ONES, sz, true);
522   for(int i = 0; i < numNodes; ++i) {
523     normFactor =
524       sqrt(sx(i, 0) * sx(i, 0) + sy(i, 0) * sy(i, 0) + sz(i, 0) * sz(i, 0));
525     sx(i, 0) = sx(i, 0) / normFactor;
526     sy(i, 0) = sy(i, 0) / normFactor;
527     sz(i, 0) = sz(i, 0) / normFactor;
528     norms(i, 0) = sx(i, 0);
529     norms(i, 1) = sy(i, 0);
530     norms(i, 2) = sz(i, 0);
531   }
532 
533   for(int i = 0; i < numNodes; ++i) {
534     for(int j = 0; j < 3; ++j) {
535       level_set_nodes(i, j) = cntrs(i, j);
536       level_set_nodes(i + numNodes, j) = cntrs(i, j) - delta * norms(i, j);
537       level_set_nodes(i + 2 * numNodes, j) = cntrs(i, j) + delta * norms(i, j);
538     }
539     level_set_funvals(i, 0) = 0.0;
540     level_set_funvals(i + numNodes, 0) = -1;
541     level_set_funvals(i + 2 * numNodes, 0) = 1;
542   }
543 }
544 
gLevelsetPoints(fullMatrix<double> & centers,int tag)545 gLevelsetPoints::gLevelsetPoints(fullMatrix<double> &centers, int tag)
546   : gLevelsetPrimitive(tag)
547 {
548   int nbNodes = 3 * centers.size1();
549 
550   setup_level_set(centers, points, surf);
551   printNodes(points, surf);
552 
553   // build invA matrix for 3*n points
554   int indexRBF = 1;
555   matAInv.resize(nbNodes, nbNodes);
556   matAInv = generateRbfMat(0, indexRBF, points, points);
557   matAInv.invertInPlace();
558 }
559 
gLevelsetPoints(const gLevelsetPoints & lv)560 gLevelsetPoints::gLevelsetPoints(const gLevelsetPoints &lv)
561   : gLevelsetPrimitive(lv)
562 {
563   points = lv.points;
564 }
565 
operator ()(double x,double y,double z) const566 double gLevelsetPoints::operator()(double x, double y, double z) const
567 {
568   if(mapP.empty())
569     Msg::Info("Levelset Points : call computeLS() before calling operator()\n");
570 
571   SPoint3 sp(x, y, z);
572   auto it = mapP.find(sp);
573   if(it != mapP.end()) return it->second;
574   printf("Levelset Points : Point not found\n");
575   return 0;
576 
577   // fullMatrix<double> xyz_eval(1, 3), surf_eval(1,1);
578   // xyz_eval(0,0) = x;
579   // xyz_eval(0,1) = y;
580   // xyz_eval(0,2) = z;
581   // evalRbfDer(0, 1, points, xyz_eval, surf, surf_eval);
582   // return surf_eval(0,0);
583 }
584 
computeLS(std::vector<MVertex * > & vert)585 void gLevelsetPoints::computeLS(std::vector<MVertex *> &vert)
586 {
587   fullMatrix<double> xyz_eval(vert.size(), 3), surf_eval(vert.size(), 1);
588   for(std::size_t i = 0; i < vert.size(); i++) {
589     xyz_eval(i, 0) = vert[i]->x();
590     xyz_eval(i, 1) = vert[i]->y();
591     xyz_eval(i, 2) = vert[i]->z();
592   }
593   evalRbfDer(0, 1, points, xyz_eval, surf, surf_eval);
594   for(std::size_t i = 0; i < vert.size(); i++) {
595     mapP[SPoint3(vert[i]->x(), vert[i]->y(), vert[i]->z())] = surf_eval(i, 0);
596   }
597 }
598 
599 /*
600   assume a quadric
601   x^T A x + b^T x + c = 0
602 
603   typically, we add a rotation x -> R x
604   x^T (R^T A R) x + b^T R x + c = 0
605 
606   and a translation x -> x - t
607   x^T A x + [b^T - 2 A t] x + [c - b^T t + t^T A t ] = 0
608 */
609 
gLevelsetQuadric(const gLevelsetQuadric & lv)610 gLevelsetQuadric::gLevelsetQuadric(const gLevelsetQuadric &lv)
611   : gLevelsetPrimitive(lv)
612 {
613   for(int i = 0; i < 3; i++) {
614     B[i] = lv.B[i];
615     for(int j = 0; j < 3; j++) A[i][j] = lv.A[i][j];
616   }
617   C = lv.C;
618 }
619 
Ax(const double x[3],double res[3],double fact)620 void gLevelsetQuadric::Ax(const double x[3], double res[3], double fact)
621 {
622   for(int i = 0; i < 3; i++) {
623     res[i] = 0.;
624     for(int j = 0; j < 3; j++) { res[i] += A[i][j] * x[j] * fact; }
625   }
626 }
627 
xAx(const double x[3],double & res,double fact)628 void gLevelsetQuadric::xAx(const double x[3], double &res, double fact)
629 {
630   res = fact * (A[0][0] * x[0] * x[0] + A[1][1] * x[1] * x[1] +
631                 A[2][2] * x[2] * x[2] + A[1][0] * x[1] * x[0] * 2. +
632                 A[2][0] * x[2] * x[0] * 2. + A[1][2] * x[1] * x[2] * 2.);
633 }
634 
translate(const double transl[3])635 void gLevelsetQuadric::translate(const double transl[3])
636 {
637   double b;
638   xAx(transl, b, 1.0);
639   C += (-B[0] * transl[0] - B[1] * transl[1] - B[2] * transl[2] + b);
640 
641   double x[3];
642   Ax(transl, x, 2.0);
643   B[0] += -x[0];
644   B[1] += -x[1];
645   B[2] += -x[2];
646 }
647 
rotate(const double rotate[3][3])648 void gLevelsetQuadric::rotate(const double rotate[3][3])
649 {
650   double a11 = 0., a12 = 0., a13 = 0., a22 = 0., a23 = 0., a33 = 0.;
651   double b1 = 0., b2 = 0., b3 = 0.;
652   for(int i = 0; i < 3; i++) {
653     b1 += B[i] * rotate[i][0];
654     b2 += B[i] * rotate[i][1];
655     b3 += B[i] * rotate[i][2];
656     for(int j = 0; j < 3; j++) {
657       a11 += rotate[i][0] * A[i][j] * rotate[j][0];
658       a12 += rotate[i][0] * A[i][j] * rotate[j][1];
659       a13 += rotate[i][0] * A[i][j] * rotate[j][2];
660       a22 += rotate[i][1] * A[i][j] * rotate[j][1];
661       a23 += rotate[i][1] * A[i][j] * rotate[j][2];
662       a33 += rotate[i][2] * A[i][j] * rotate[j][2];
663     }
664   }
665   A[0][0] = a11;
666   A[0][1] = A[1][0] = a12;
667   A[0][2] = A[2][0] = a13;
668   A[1][1] = a22;
669   A[1][2] = A[2][1] = a23;
670   A[2][2] = a33;
671   B[0] = b1;
672   B[1] = b2;
673   B[2] = b3;
674 }
675 
676 // computes the rotation matrix of the rotation of the vector (0,0,1) to dir
computeRotationMatrix(const double dir[3],double t[3][3])677 void gLevelsetQuadric::computeRotationMatrix(const double dir[3],
678                                              double t[3][3])
679 {
680   double norm = sqrt(dir[0] * dir[0] + dir[1] * dir[1]);
681   double n[3] = {1., 0., 0.};
682   double ct = 1., st = 0.;
683   if(norm != 0.) {
684     double theta = atan(norm / dir[2]);
685     n[0] = dir[1] / norm;
686     n[1] = -dir[0] / norm;
687     ct = cos(theta);
688     st = sin(theta);
689   }
690   t[0][0] = n[0] * n[0] * (1. - ct) + ct;
691   t[0][1] = n[0] * n[1] * (1. - ct) - n[2] * st;
692   t[0][2] = n[0] * n[2] * (1. - ct) + n[1] * st;
693   t[1][0] = n[1] * n[0] * (1. - ct) + n[2] * st;
694   t[1][1] = n[1] * n[1] * (1. - ct) + ct;
695   t[1][2] = n[1] * n[2] * (1. - ct) - n[0] * st;
696   t[2][0] = n[2] * n[0] * (1. - ct) - n[1] * st;
697   t[2][1] = n[2] * n[1] * (1. - ct) + n[0] * st;
698   t[2][2] = n[2] * n[2] * (1. - ct) + ct;
699 }
700 
computeRotationMatrix(const double dir1[3],const double dir2[3],double t[3][3])701 void gLevelsetQuadric::computeRotationMatrix(const double dir1[3],
702                                              const double dir2[3],
703                                              double t[3][3])
704 {
705   double norm = sqrt((dir1[1] * dir2[2] - dir1[2] * dir2[1]) *
706                        (dir1[1] * dir2[2] - dir1[2] * dir2[1]) +
707                      (dir1[2] * dir2[0] - dir1[0] * dir2[2]) *
708                        (dir1[2] * dir2[0] - dir1[0] * dir2[2]) +
709                      (dir1[0] * dir2[1] - dir1[1] * dir2[0]) *
710                        (dir1[0] * dir2[1] - dir1[1] * dir2[0]));
711   double n[3] = {1., 0., 0.};
712   double ct = 1., st = 0.;
713   if(norm != 0.) {
714     st = norm / ((dir1[0] * dir1[0] + dir1[1] * dir1[1] + dir1[2] * dir1[2]) *
715                  (dir2[0] * dir2[0] + dir2[1] * dir2[1] + dir2[2] * dir2[2]));
716     n[0] = (dir1[1] * dir2[2] - dir1[2] * dir2[1]) / norm;
717     n[1] = (dir1[2] * dir2[0] - dir1[0] * dir2[2]) / norm;
718     n[2] = (dir1[0] * dir2[1] - dir1[1] * dir2[0]) / norm;
719     ct = cos(asin(st));
720   }
721   t[0][0] = n[0] * n[0] * (1. - ct) + ct;
722   t[0][1] = n[0] * n[1] * (1. - ct) - n[2] * st;
723   t[0][2] = n[0] * n[2] * (1. - ct) + n[1] * st;
724   t[1][0] = n[1] * n[0] * (1. - ct) + n[2] * st;
725   t[1][1] = n[1] * n[1] * (1. - ct) + ct;
726   t[1][2] = n[1] * n[2] * (1. - ct) - n[0] * st;
727   t[2][0] = n[2] * n[0] * (1. - ct) - n[1] * st;
728   t[2][1] = n[2] * n[1] * (1. - ct) + n[0] * st;
729   t[2][2] = n[2] * n[2] * (1. - ct) + ct;
730 }
731 
init()732 void gLevelsetQuadric::init()
733 {
734   for(int i = 0; i < 3; i++) {
735     B[i] = 0.;
736     for(int j = 0; j < 3; j++) A[i][j] = 0.;
737   }
738   C = 0.;
739 }
740 
operator ()(double x,double y,double z) const741 double gLevelsetQuadric::operator()(double x, double y, double z) const
742 {
743   return (A[0][0] * x * x + 2. * A[0][1] * x * y + 2. * A[0][2] * x * z +
744           A[1][1] * y * y + 2. * A[1][2] * y * z + A[2][2] * z * z + B[0] * x +
745           B[1] * y + B[2] * z + C);
746 }
747 
gLevelsetShamrock(double _xmid,double _ymid,double _zmid,double _a,double _b,int _c,int tag)748 gLevelsetShamrock::gLevelsetShamrock(double _xmid, double _ymid, double _zmid,
749                                      double _a, double _b, int _c, int tag)
750   : gLevelsetPrimitive(tag), xmid(_xmid), a(_a), b(_b), c(_c)
751 {
752   // creating the iso-zero
753   double angle = 0.;
754   double r;
755   while(angle <= 2. * M_PI) {
756     r = a + b * sin(c * angle);
757     iso_x.push_back(r * sin(angle) + xmid);
758     iso_y.push_back(r * cos(angle) + xmid);
759     angle += 2. * M_PI / 1000.;
760   }
761 }
762 
operator ()(double x,double y,double z) const763 double gLevelsetShamrock::operator()(double x, double y, double z) const
764 {
765   // computing distance to pre-defined (sampled) iso-zero
766   double dx, dy, xi, yi, d;
767   dx = x - iso_x[0];
768   dy = y - iso_y[0];
769   double distance = sqrt(dx * dx + dy * dy);
770   auto itx = iso_x.begin();
771   auto itxen = iso_x.end();
772   auto ity = iso_y.begin();
773   auto itminx = iso_x.begin();
774   auto itminy = iso_y.begin();
775   itx++;
776   ity++;
777   for(; itx != itxen; itx++, ity++) {
778     xi = *itx;
779     yi = *ity;
780     dx = x - xi;
781     dy = y - yi;
782     d = sqrt(dx * dx + dy * dy);
783     if(distance > d) {
784       distance = d;
785       itminx = itx;
786       itminy = ity;
787     }
788   }
789   // still need to find the LS sign... using vectorial prod with tangent vector
790   // if not, the LS gradient is discontinuous on iso-zero... oups !
791   SVector3 t, p;
792   p(0) = (*itminx) - x;
793   p(1) = (*itminy) - y;
794   if(itminx == (itxen - 1)) {
795     t(0) = iso_x[0] - (*itminx);
796     t(1) = iso_y[0] - (*itminy);
797   }
798   else {
799     t(0) = (*(itminx + 1)) - (*itminx);
800     t(1) = (*(itminy + 1)) - (*itminy);
801   }
802   double vectprod = (p(0) * t(1) - p(1) * t(0));
803   double sign = (vectprod < 0.) ? -1. : 1.;
804 
805   return sign * distance;
806 }
807 
gLevelsetPopcorn(double myxc,double myyc,double myzc,double myr0,double myA,double mysigma,int tag)808 gLevelsetPopcorn::gLevelsetPopcorn(double myxc, double myyc, double myzc,
809                                    double myr0, double myA, double mysigma,
810                                    int tag)
811   : gLevelsetPrimitive(tag)
812 {
813   A = myA;
814   sigma = mysigma;
815   r0 = myr0;
816   xc = myxc;
817   yc = myyc;
818   zc = myzc;
819 }
820 
operator ()(double x,double y,double z) const821 double gLevelsetPopcorn::operator()(double x, double y, double z) const
822 {
823   double s2 = sigma * sigma;
824   double r =
825     sqrt((x - xc) * (x - xc) + (y - yc) * (y - yc) + (z - zc) * (z - zc));
826   // printf("z=%g zc=%g r=%g \n", z, zc, r);
827   double val = r - r0;
828   for(int k = 0; k < 5; k++) {
829     double xk = r0 / sqrt(5.0) * (2. * cos(2 * k * M_PI / 5.0));
830     double yk = r0 / sqrt(5.0) * (2. * sin(2 * k * M_PI / 5.0));
831     double zk = r0 / sqrt(5.0);
832     val -=
833       A * exp(-((x - xc - xk) * (x - xc - xk) + (y - yc - yk) * (y - yc - yk) +
834                 (z - zc - zk) * (z - zc - zk)) /
835               s2);
836   }
837   for(int k = 5; k < 10; k++) {
838     double xk = r0 / sqrt(5.0) * (2. * cos((2. * (k - 5.) - 1.) * M_PI / 5.0));
839     double yk = r0 / sqrt(5.0) * (2. * sin((2. * (k - 5.) - 1.) * M_PI / 5.0));
840     double zk = -r0 / sqrt(5.0);
841     val -=
842       A * exp(-((x - xc - xk) * (x - xc - xk) + (y - yc - yk) * (y - yc - yk) +
843                 (z - zc - zk) * (z - zc - zk)) /
844               s2);
845   }
846   val -= A * exp(-((x - xc) * (x - xc) + (y - yc) * (y - yc) +
847                    (z - zc - r0) * (z - zc - r0)) /
848                  s2);
849   val -= A * exp(-((x - xc) * (x - xc) + (y - yc) * (y - yc) +
850                    (z - zc + r0) * (z - zc + r0)) /
851                  s2);
852   return val;
853 }
854 
gLevelsetMathEval(const std::string & f,int tag)855 gLevelsetMathEval::gLevelsetMathEval(const std::string &f, int tag)
856   : gLevelsetPrimitive(tag)
857 {
858   std::vector<std::string> expressions(1, f);
859   std::vector<std::string> variables(3);
860   variables[0] = "x";
861   variables[1] = "y";
862   variables[2] = "z";
863   _expr = new mathEvaluator(expressions, variables);
864 }
865 
~gLevelsetMathEval()866 gLevelsetMathEval::~gLevelsetMathEval()
867 {
868   if(_expr) delete _expr;
869 }
870 
operator ()(double x,double y,double z) const871 double gLevelsetMathEval::operator()(double x, double y, double z) const
872 {
873   std::vector<double> values(3), res(1);
874   values[0] = x;
875   values[1] = y;
876   values[2] = z;
877   if(_expr->eval(values, res)) return res[0];
878   return 1.;
879 }
880 
gLevelsetMathEvalAll(std::vector<std::string> expressions,int tag)881 gLevelsetMathEvalAll::gLevelsetMathEvalAll(std::vector<std::string> expressions,
882                                            int tag)
883   : gLevelsetPrimitive(tag)
884 {
885   _hasDerivatives = true;
886   std::vector<std::string> variables(3);
887   variables[0] = "x";
888   variables[1] = "y";
889   variables[2] = "z";
890   _expr = new mathEvaluator(expressions, variables);
891 }
892 
~gLevelsetMathEvalAll()893 gLevelsetMathEvalAll::~gLevelsetMathEvalAll()
894 {
895   if(_expr) delete _expr;
896 }
897 
operator ()(double x,double y,double z) const898 double gLevelsetMathEvalAll::operator()(double x, double y, double z) const
899 {
900   std::vector<double> values(3), res(13);
901   values[0] = x;
902   values[1] = y;
903   values[2] = z;
904   if(_expr->eval(values, res)) return res[0];
905   return 1.;
906 }
907 
gradient(double x,double y,double z,double & dfdx,double & dfdy,double & dfdz) const908 void gLevelsetMathEvalAll::gradient(double x, double y, double z, double &dfdx,
909                                     double &dfdy, double &dfdz) const
910 {
911   std::vector<double> values(3), res(13);
912   values[0] = x;
913   values[1] = y;
914   values[2] = z;
915   if(_expr->eval(values, res)) {
916     dfdx = res[1];
917     dfdy = res[2];
918     dfdz = res[3];
919   }
920 }
921 
hessian(double x,double y,double z,double & dfdxx,double & dfdxy,double & dfdxz,double & dfdyx,double & dfdyy,double & dfdyz,double & dfdzx,double & dfdzy,double & dfdzz) const922 void gLevelsetMathEvalAll::hessian(double x, double y, double z, double &dfdxx,
923                                    double &dfdxy, double &dfdxz, double &dfdyx,
924                                    double &dfdyy, double &dfdyz, double &dfdzx,
925                                    double &dfdzy, double &dfdzz) const
926 {
927   std::vector<double> values(3), res(13);
928   values[0] = x;
929   values[1] = y;
930   values[2] = z;
931   if(_expr->eval(values, res)) {
932     dfdxx = res[4];
933     dfdxy = res[5];
934     dfdxz = res[6];
935     dfdyx = res[7];
936     dfdyy = res[8];
937     dfdyz = res[9];
938     dfdzx = res[10];
939     dfdzy = res[11];
940     dfdzz = res[12];
941   }
942 }
943 
944 #if defined(HAVE_ANN)
gLevelsetDistMesh(GModel * gm,const std::string & physical,int nbClose,int tag)945 gLevelsetDistMesh::gLevelsetDistMesh(GModel *gm, const std::string &physical,
946                                      int nbClose, int tag)
947   : gLevelsetPrimitive(tag), _nbClose(nbClose)
948 {
949   std::map<int, std::vector<GEntity *> > groups[4];
950   gm->getPhysicalGroups(groups);
951   for(auto it = gm->firstPhysicalName(); it != gm->lastPhysicalName(); ++it) {
952     if(it->second == physical) {
953       _entities = groups[it->first.first][it->first.second];
954     }
955   }
956   if(_entities.size() == 0) {
957     Msg::Error(
958       "distanceToMesh: the physical name '%s' does not exist in the GModel",
959       physical.c_str());
960   }
961 
962   // setup
963   std::set<MVertex *> _all;
964   for(std::size_t i = 0; i < _entities.size(); i++) {
965     for(std::size_t k = 0; k < _entities[i]->getNumMeshElements(); k++) {
966       MElement *e = _entities[i]->getMeshElement(k);
967       for(std::size_t j = 0; j < e->getNumVertices(); j++) {
968         MVertex *v = _entities[i]->getMeshElement(k)->getVertex(j);
969         _all.insert(v);
970         _v2e.insert(std::make_pair(v, e));
971       }
972     }
973   }
974   ANNpointArray nodes;
975   nodes = annAllocPts(_all.size(), 3);
976   auto itp = _all.begin();
977   int ind = 0;
978   while(itp != _all.end()) {
979     MVertex *pt = *itp;
980     nodes[ind][0] = pt->x();
981     nodes[ind][1] = pt->y();
982     nodes[ind][2] = pt->z();
983     _vertices.push_back(pt);
984     itp++;
985     ind++;
986   }
987   _kdtree = new ANNkd_tree(nodes, _all.size(), 3);
988 }
989 
~gLevelsetDistMesh()990 gLevelsetDistMesh::~gLevelsetDistMesh()
991 {
992   if(_kdtree) {
993     ANNpointArray nodes = _kdtree->thePoints();
994     annDeallocPts(nodes);
995     delete _kdtree;
996   }
997 }
998 
operator ()(double x,double y,double z) const999 double gLevelsetDistMesh::operator()(double x, double y, double z) const
1000 {
1001   std::vector<ANNidx> index(_nbClose);
1002   std::vector<ANNdist> dist(_nbClose);
1003   double point[3] = {x, y, z};
1004   SPoint3 pt(x, y, z);
1005   _kdtree->annkSearch(point, _nbClose, &index[0],
1006                       &dist[0]); // squared distances
1007   std::set<MElement *> elements;
1008   int dimE = 1;
1009   for(int i = 0; i < _nbClose; i++) {
1010     int iVertex = index[i];
1011     MVertex *v = _vertices[iVertex];
1012     for(auto itm = _v2e.lower_bound(v); itm != _v2e.upper_bound(v); ++itm) {
1013       elements.insert(itm->second);
1014       dimE = itm->second->getDim();
1015     }
1016   }
1017   double minDistance = 1.e22;
1018   SPoint3 closestPoint;
1019   std::vector<MElement *> closestElements;
1020   for(auto it = elements.begin(); it != elements.end(); ++it) {
1021     double distance = 0.;
1022     MVertex *v1 = (*it)->getVertex(0);
1023     MVertex *v2 = (*it)->getVertex(1);
1024     SPoint3 p1(v1->x(), v1->y(), v1->z());
1025     SPoint3 p2(v2->x(), v2->y(), v2->z());
1026     SPoint3 closePt;
1027     if(dimE == 1) {
1028       signedDistancePointLine(p1, p2, pt, distance, closePt); // !! > 0
1029     }
1030     else if(dimE == 2) {
1031       MVertex *v3 = (*it)->getVertex(2);
1032       SPoint3 p3(v3->x(), v3->y(), v3->z());
1033       if(p1 == p2 || p1 == p3 || p2 == p3)
1034         distance = 1.e22;
1035       else
1036         signedDistancePointTriangle(p1, p2, p3, pt, distance, closePt);
1037     }
1038     else {
1039       Msg::Error("Cannot compute a distance to an entity of dimension %d\n",
1040                  dimE);
1041     }
1042     if(dimE == 1 && fabs(distance) < fabs(minDistance)) {
1043       minDistance = distance;
1044     }
1045     else if(dimE == 2) {
1046       if(fabs(distance) - fabs(minDistance) < 1.e-9) {
1047         closestElements.push_back(*it);
1048       }
1049       else if(fabs(distance) < fabs(minDistance)) {
1050         closestPoint = closePt;
1051         minDistance = distance;
1052         closestElements.clear();
1053         closestElements.push_back(*it);
1054       }
1055     }
1056   }
1057   if(closestElements.size() > 1) {
1058     SVector3 vd(closestPoint, pt);
1059     SVector3 meanNorm(0., 0., 0.); // angle weighted mean normal
1060     if(closestElements.size() == 2) { // closestPoint on edge
1061       meanNorm = closestElements[0]->getFace(0).normal() +
1062                  closestElements[1]->getFace(0).normal();
1063     }
1064     else { // closestPoint on vertex
1065       for(std::size_t i = 0; i < closestElements.size(); i++) {
1066         double alpha = 0.;
1067         SPoint3 p1;
1068         bool found = false;
1069         for(int j = 0; j < closestElements[i]->getNumEdges(); j++) {
1070           SPoint3 ep0 = closestElements[i]->getEdge(j).getVertex(0)->point();
1071           SPoint3 ep1 = closestElements[i]->getEdge(j).getVertex(1)->point();
1072           if(closestPoint == ep0) {
1073             if(!found) {
1074               p1 = ep1;
1075               found = true;
1076             }
1077             else {
1078               alpha =
1079                 angle(SVector3(closestPoint, p1), SVector3(closestPoint, ep1));
1080               break;
1081             }
1082           }
1083           if(closestPoint == ep1) {
1084             if(!found) {
1085               p1 = ep0;
1086               found = true;
1087             }
1088             else {
1089               alpha =
1090                 angle(SVector3(closestPoint, p1), SVector3(closestPoint, ep0));
1091               break;
1092             }
1093           }
1094         }
1095         meanNorm = meanNorm + alpha * closestElements[i]->getFace(0).normal();
1096       }
1097     }
1098     double dotDN = dot(vd, closestElements[0]->getFace(0).normal());
1099     double dotDE = dot(vd, meanNorm);
1100     if(dotDN * dotDE < 0.) minDistance *= -1.;
1101   }
1102 
1103   return -1.0 * minDistance;
1104 }
1105 #endif
1106 
1107 #if defined(HAVE_POST)
gLevelsetPostView(int index,int tag)1108 gLevelsetPostView::gLevelsetPostView(int index, int tag)
1109   : gLevelsetPrimitive(tag), _viewIndex(index)
1110 {
1111   if(_viewIndex >= 0 && _viewIndex < (int)PView::list.size()) {
1112     PView *view = PView::list[_viewIndex];
1113     _octree = new OctreePost(view);
1114   }
1115   else {
1116     Msg::Error("Unknown View[%d] in PostView levelset", _viewIndex);
1117     _octree = nullptr;
1118   }
1119 }
1120 
operator ()(double x,double y,double z) const1121 double gLevelsetPostView::operator()(double x, double y, double z) const
1122 {
1123   if(!_octree) return 1.;
1124   double val = 1.;
1125   _octree->searchScalar(x, y, z, &val, 0);
1126   return val;
1127 }
1128 #endif
1129 
gLevelsetGenCylinder(const double * pt,const double * dir,const double & R,int tag)1130 gLevelsetGenCylinder::gLevelsetGenCylinder(const double *pt, const double *dir,
1131                                            const double &R, int tag)
1132   : gLevelsetQuadric(tag)
1133 {
1134   A[0][0] = 1.;
1135   A[1][1] = 1.;
1136   C = -R * R;
1137   double rot[3][3];
1138   computeRotationMatrix(dir, rot);
1139   rotate(rot);
1140   translate(pt);
1141 }
1142 
gLevelsetGenCylinder(const gLevelsetGenCylinder & lv)1143 gLevelsetGenCylinder::gLevelsetGenCylinder(const gLevelsetGenCylinder &lv)
1144   : gLevelsetQuadric(lv)
1145 {
1146 }
1147 
gLevelsetEllipsoid(const double * pt,const double * dir,const double & a,const double & b,const double & c,int tag)1148 gLevelsetEllipsoid::gLevelsetEllipsoid(const double *pt, const double *dir,
1149                                        const double &a, const double &b,
1150                                        const double &c, int tag)
1151   : gLevelsetQuadric(tag)
1152 {
1153   A[0][0] = 1. / (a * a);
1154   A[1][1] = 1. / (b * b);
1155   A[2][2] = 1. / (c * c);
1156   C = -1.;
1157   double rot[3][3];
1158   computeRotationMatrix(dir, rot);
1159   rotate(rot);
1160   translate(pt);
1161 }
1162 
gLevelsetEllipsoid(const gLevelsetEllipsoid & lv)1163 gLevelsetEllipsoid::gLevelsetEllipsoid(const gLevelsetEllipsoid &lv)
1164   : gLevelsetQuadric(lv)
1165 {
1166 }
1167 
gLevelsetCone(const double * pt,const double * dir,const double & angle,int tag)1168 gLevelsetCone::gLevelsetCone(const double *pt, const double *dir,
1169                              const double &angle, int tag)
1170   : gLevelsetQuadric(tag)
1171 {
1172   A[0][0] = 1.;
1173   A[1][1] = 1.;
1174   A[2][2] = -tan(angle) * tan(angle);
1175   double rot[3][3];
1176   computeRotationMatrix(dir, rot);
1177   rotate(rot);
1178   translate(pt);
1179 }
1180 
gLevelsetCone(const gLevelsetCone & lv)1181 gLevelsetCone::gLevelsetCone(const gLevelsetCone &lv) : gLevelsetQuadric(lv) {}
1182 
gLevelsetGeneralQuadric(const double * pt,const double * dir,const double & x2,const double & y2,const double & z2,const double & z,const double & c,int tag)1183 gLevelsetGeneralQuadric::gLevelsetGeneralQuadric(
1184   const double *pt, const double *dir, const double &x2, const double &y2,
1185   const double &z2, const double &z, const double &c, int tag)
1186   : gLevelsetQuadric(tag)
1187 {
1188   A[0][0] = x2;
1189   A[1][1] = y2;
1190   A[2][2] = z2;
1191   B[2] = z;
1192   C = c;
1193   double rot[3][3];
1194   computeRotationMatrix(dir, rot);
1195   rotate(rot);
1196   translate(pt);
1197 }
1198 
gLevelsetGeneralQuadric(const gLevelsetGeneralQuadric & lv)1199 gLevelsetGeneralQuadric::gLevelsetGeneralQuadric(
1200   const gLevelsetGeneralQuadric &lv)
1201   : gLevelsetQuadric(lv)
1202 {
1203 }
1204 
gLevelsetTools(const gLevelsetTools & lv)1205 gLevelsetTools::gLevelsetTools(const gLevelsetTools &lv) : gLevelset(lv)
1206 {
1207   std::vector<gLevelset *> _children = lv.getChildren();
1208   unsigned siz = _children.size();
1209   children.resize(siz);
1210   for(unsigned i = 0; i < siz; ++i) children[i] = _children[i]->clone();
1211 }
1212 
gLevelsetYarn(int dim,int phys,double minA,double majA,int type,int tag)1213 gLevelsetYarn::gLevelsetYarn(int dim, int phys, double minA, double majA,
1214                              int type, int tag)
1215   : gLevelsetPrimitive(tag) //, minorAxis(minA), majorAxis(majA), typeLs(type)
1216 {
1217   std::map<int, std::vector<GEntity *> > groups;
1218   GModel::current()->getPhysicalGroups(dim, groups);
1219   entities = groups[phys];
1220   if(!entities.size())
1221     printf("No physical %d found for levelset yarn!\n", phys);
1222 }
1223 
operator ()(double x,double y,double z) const1224 double gLevelsetYarn::operator()(double x, double y, double z) const
1225 {
1226   double dist = 0.0;
1227   for(std::size_t i = 0; i < entities.size(); i++) {
1228     GEntity *g = entities[i];
1229     for(std::size_t j = 0; j < g->getNumMeshElements(); j++) {
1230       MElement *e = g->getMeshElement(j);
1231       MVertex *v1 = e->getVertex(0);
1232       MVertex *v2 = e->getVertex(1);
1233       SPoint3 p1(v1->x(), v1->y(), v1->z());
1234       SPoint3 p2(v2->x(), v2->y(), v2->z());
1235       /*if(e->getType() == TYPE_LIN){
1236         signedDistancesPointsEllipseLine(iDistances, iDistancesE, iIsInYarn,
1237       iClosePts, pts, p1, p2, majorAxis, minorAxis, majorAxis, minorAxis,
1238       typeLs);
1239       }
1240       else if(e->getType() == TYPE_TRI){
1241         MVertex *v3 = e->getVertex(2);
1242         SPoint3 p3(v3->x(),v3->y(),v3->z());
1243         signedDistancesPointsTriangle(iDistances, iClosePts, pts, p1, p2, p3);
1244       }*/
1245     }
1246   }
1247   return dist;
1248 }
1249 
gLevelsetImproved(const gLevelsetImproved & lv)1250 gLevelsetImproved::gLevelsetImproved(const gLevelsetImproved &lv)
1251   : gLevelset(lv)
1252 {
1253   Ls = lv.Ls->clone();
1254 }
1255 
gLevelsetBox(const double * pt,const double * dir1,const double * dir2,const double * dir3,const double & a,const double & b,const double & c,int tag)1256 gLevelsetBox::gLevelsetBox(const double *pt, const double *dir1,
1257                            const double *dir2, const double *dir3,
1258                            const double &a, const double &b, const double &c,
1259                            int tag)
1260   : gLevelsetImproved()
1261 {
1262   double dir1m[3] = {-dir1[0], -dir1[1], -dir1[2]};
1263   double dir2m[3] = {-dir2[0], -dir2[1], -dir2[2]};
1264   double dir3m[3] = {-dir3[0], -dir3[1], -dir3[2]};
1265   double n1[3];
1266   norm(dir1, n1);
1267   double n2[3];
1268   norm(dir2, n2);
1269   double n3[3];
1270   norm(dir3, n3);
1271   double pt2[3] = {pt[0] + a * n1[0] + b * n2[0] + c * n3[0],
1272                    pt[1] + a * n1[1] + b * n2[1] + c * n3[1],
1273                    pt[2] + a * n1[2] + b * n2[2] + c * n3[2]};
1274   std::vector<gLevelset *> p;
1275   p.push_back(new gLevelsetPlane(pt2, dir3, tag++));
1276   p.push_back(new gLevelsetPlane(pt, dir3m, tag++));
1277   p.push_back(new gLevelsetPlane(pt, dir2m, tag++));
1278   p.push_back(new gLevelsetPlane(pt2, dir2, tag++));
1279   p.push_back(new gLevelsetPlane(pt2, dir1, tag++));
1280   p.push_back(new gLevelsetPlane(pt, dir1m, tag));
1281   Ls = new gLevelsetIntersection(p);
1282 }
1283 
gLevelsetBox(const double * pt1,const double * pt2,const double * pt3,const double * pt4,const double * pt5,const double * pt6,const double * pt7,const double * pt8,int tag)1284 gLevelsetBox::gLevelsetBox(const double *pt1, const double *pt2,
1285                            const double *pt3, const double *pt4,
1286                            const double *pt5, const double *pt6,
1287                            const double *pt7, const double *pt8, int tag)
1288   : gLevelsetImproved()
1289 {
1290   if(!isPlanar(pt1, pt2, pt3, pt4) || !isPlanar(pt5, pt6, pt7, pt8) ||
1291      !isPlanar(pt1, pt2, pt5, pt6) || !isPlanar(pt3, pt4, pt7, pt8) ||
1292      !isPlanar(pt1, pt4, pt5, pt8) || !isPlanar(pt2, pt3, pt6, pt7))
1293     printf(
1294       "WARNING : faces of the box are not planar! %d, %d, %d, %d, %d, %d\n",
1295       isPlanar(pt1, pt2, pt3, pt4), isPlanar(pt5, pt6, pt7, pt8),
1296       isPlanar(pt1, pt2, pt5, pt6), isPlanar(pt3, pt4, pt7, pt8),
1297       isPlanar(pt1, pt4, pt5, pt8), isPlanar(pt2, pt3, pt6, pt7));
1298   std::vector<gLevelset *> p;
1299   p.push_back(new gLevelsetPlane(pt5, pt6, pt8, tag++));
1300   p.push_back(new gLevelsetPlane(pt1, pt4, pt2, tag++));
1301   p.push_back(new gLevelsetPlane(pt1, pt2, pt5, tag++));
1302   p.push_back(new gLevelsetPlane(pt3, pt4, pt7, tag++));
1303   p.push_back(new gLevelsetPlane(pt2, pt3, pt6, tag++));
1304   p.push_back(new gLevelsetPlane(pt1, pt5, pt4, tag));
1305   Ls = new gLevelsetIntersection(p);
1306 }
1307 
gLevelsetBox(const gLevelsetBox & lv)1308 gLevelsetBox::gLevelsetBox(const gLevelsetBox &lv) : gLevelsetImproved(lv) {}
1309 
gLevelsetCylinder(const std::vector<double> & pt,const std::vector<double> & dir,const double & R,const double & H,int tag)1310 gLevelsetCylinder::gLevelsetCylinder(const std::vector<double> &pt,
1311                                      const std::vector<double> &dir,
1312                                      const double &R, const double &H, int tag)
1313   : gLevelsetImproved()
1314 {
1315   double pt1[3] = {pt[0], pt[1], pt[2]};
1316   double dir1[3] = {dir[0], dir[1], dir[2]};
1317   double dir2[3] = {-dir1[0], -dir1[1], -dir1[2]};
1318   double n[3];
1319   norm(dir1, n);
1320   double pt2[3] = {pt1[0] + H * n[0], pt1[1] + H * n[1], pt1[2] + H * n[2]};
1321   std::vector<gLevelset *> p;
1322   p.push_back(new gLevelsetGenCylinder(pt1, dir1, R, tag++));
1323   p.push_back(new gLevelsetPlane(pt1, dir2, tag++));
1324   p.push_back(new gLevelsetPlane(pt2, dir1, tag));
1325   Ls = new gLevelsetIntersection(p);
1326 }
1327 
gLevelsetCylinder(const double * pt,const double * dir,const double & R,const double & H,int tag)1328 gLevelsetCylinder::gLevelsetCylinder(const double *pt, const double *dir,
1329                                      const double &R, const double &H, int tag)
1330   : gLevelsetImproved()
1331 {
1332   double dir2[3] = {-dir[0], -dir[1], -dir[2]};
1333   double n[3];
1334   norm(dir, n);
1335   double pt2[3] = {pt[0] + H * n[0], pt[1] + H * n[1], pt[2] + H * n[2]};
1336   std::vector<gLevelset *> p;
1337   p.push_back(new gLevelsetGenCylinder(pt, dir, R, tag++));
1338   p.push_back(new gLevelsetPlane(pt, dir2, tag++));
1339   p.push_back(new gLevelsetPlane(pt2, dir, tag));
1340   Ls = new gLevelsetIntersection(p);
1341 }
1342 
gLevelsetCylinder(const double * pt,const double * dir,const double & R,const double & r,const double & H,int tag)1343 gLevelsetCylinder::gLevelsetCylinder(const double *pt, const double *dir,
1344                                      const double &R, const double &r,
1345                                      const double &H, int tag)
1346   : gLevelsetImproved()
1347 {
1348   double dir2[3] = {-dir[0], -dir[1], -dir[2]};
1349   double n[3];
1350   norm(dir, n);
1351   double pt2[3] = {pt[0] + H * n[0], pt[1] + H * n[1], pt[2] + H * n[2]};
1352   std::vector<gLevelset *> p1;
1353   p1.push_back(new gLevelsetGenCylinder(pt, dir, R, tag++));
1354   p1.push_back(new gLevelsetPlane(pt, dir2, tag++));
1355   p1.push_back(new gLevelsetPlane(pt2, dir, tag++));
1356   std::vector<gLevelset *> p2;
1357   p2.push_back(new gLevelsetIntersection(p1));
1358   p2.push_back(new gLevelsetGenCylinder(pt, dir, r, tag));
1359   Ls = new gLevelsetCut(p2);
1360 }
1361 
gLevelsetCylinder(const gLevelsetCylinder & lv)1362 gLevelsetCylinder::gLevelsetCylinder(const gLevelsetCylinder &lv)
1363   : gLevelsetImproved(lv)
1364 {
1365 }
1366 
gLevelsetConrod(const double * pt,const double * dir1,const double * dir2,const double & H1,const double & H2,const double & H3,const double & R1,const double & r1,const double & R2,const double & r2,const double & L1,const double & L2,const double & E,int tag)1367 gLevelsetConrod::gLevelsetConrod(const double *pt, const double *dir1,
1368                                  const double *dir2, const double &H1,
1369                                  const double &H2, const double &H3,
1370                                  const double &R1, const double &r1,
1371                                  const double &R2, const double &r2,
1372                                  const double &L1, const double &L2,
1373                                  const double &E, int tag)
1374   : gLevelsetImproved()
1375 {
1376   double n1[3];
1377   norm(dir1, n1);
1378   double n2[3];
1379   norm(dir2, n2);
1380   double pt1[3] = {pt[0] - n2[0] * H1 / 2., pt[1] - n2[1] * H1 / 2.,
1381                    pt[2] - n2[2] * H1 / 2.};
1382   double pt2[3] = {pt[0] + n1[0] * E - n2[0] * H2 / 2.,
1383                    pt[1] + n1[1] * E - n2[1] * H2 / 2.,
1384                    pt[2] + n1[2] * E - n2[2] * H2 / 2.};
1385   double dir3[3];
1386   cross(pt1, pt2, pt, dir3);
1387   double n3[3];
1388   norm(dir3, n3);
1389   double pt31[3] = {pt[0] - n2[0] * H3 / 2. + n3[0] * L1 / 2.,
1390                     pt[1] - n2[1] * H3 / 2. + n3[1] * L1 / 2.,
1391                     pt[2] - n2[2] * H3 / 2. + n3[2] * L1 / 2.};
1392   double pt32[3] = {pt31[0] - n3[0] * L1, pt31[1] - n3[1] * L1,
1393                     pt31[2] - n3[2] * L1};
1394   double pt33[3] = {pt32[0] + n2[0] * H3, pt32[1] + n2[1] * H3,
1395                     pt32[2] + n2[2] * H3};
1396   double pt34[3] = {pt33[0] + n3[0] * L1, pt33[1] + n3[1] * L1,
1397                     pt33[2] + n3[2] * L1};
1398   double pt35[3] = {pt[0] + n1[0] * E - n2[0] * H3 / 2. + n3[0] * L2 / 2.,
1399                     pt[1] + n1[1] * E - n2[1] * H3 / 2. + n3[1] * L2 / 2.,
1400                     pt[2] + n1[2] * E - n2[2] * H3 / 2. + n3[2] * L2 / 2.};
1401   double pt36[3] = {pt35[0] - n3[0] * L2, pt35[1] - n3[1] * L2,
1402                     pt35[2] - n3[2] * L2};
1403   double pt37[3] = {pt36[0] + n2[0] * H3, pt36[1] + n2[1] * H3,
1404                     pt36[2] + n2[2] * H3};
1405   double pt38[3] = {pt37[0] + n3[0] * L2, pt37[1] + n3[1] * L2,
1406                     pt37[2] + n3[2] * L2};
1407   std::vector<gLevelset *> p1;
1408   p1.push_back(
1409     new gLevelsetBox(pt31, pt32, pt33, pt34, pt35, pt36, pt37, pt38, tag));
1410   p1.push_back(new gLevelsetCylinder(pt1, dir2, R1, H1, tag + 6));
1411   p1.push_back(new gLevelsetCylinder(pt2, dir2, R2, H2, tag + 9));
1412   std::vector<gLevelset *> p2;
1413   p2.push_back(new gLevelsetUnion(p1));
1414   p2.push_back(new gLevelsetGenCylinder(pt1, dir2, r1, tag + 12));
1415   p2.push_back(new gLevelsetGenCylinder(pt2, dir2, r2, tag + 13));
1416   Ls = new gLevelsetCut(p2);
1417 }
1418 
gLevelsetConrod(const gLevelsetConrod & lv)1419 gLevelsetConrod::gLevelsetConrod(const gLevelsetConrod &lv)
1420   : gLevelsetImproved(lv)
1421 {
1422 }
1423 
1424 // Level-set for NACA0012 airfoil, last coeff. modified for zero-thickness
1425 // trailing edge cf. http://en.wikipedia.org/wiki/NACA_airfoil
gLevelsetNACA00(double x0,double y0,double c,double t)1426 gLevelsetNACA00::gLevelsetNACA00(double x0, double y0, double c, double t)
1427   : _x0(x0), _y0(y0), _c(c), _t(t)
1428 {
1429   _hasDerivatives = true;
1430 }
1431 
getClosestBndPoint(double x,double y,double z,double & xb,double & yb,double & curvRad,bool & in) const1432 void gLevelsetNACA00::getClosestBndPoint(double x, double y, double z,
1433                                          double &xb, double &yb,
1434                                          double &curvRad, bool &in) const
1435 {
1436   static const int maxIter = 100;
1437   static const double tol = 1.e-10;
1438 
1439   const double tolr = tol / _c; // Tolerance (scaled bu chord)
1440   in = false; // Whether the point is inside the airfoil
1441 
1442   // Point translated according to airfoil origin and symmetry
1443   const double xt = x - _x0, yt = fabs(y - _y0);
1444 
1445   if(xt - _c > 1.21125 * _t * yt) {
1446     // Behind line normal to airfoil at trailing edge, closest boundary point is
1447     // trailing edge...
1448     xb = _x0 + _c;
1449     yb = _y0;
1450     curvRad = 0.;
1451   }
1452   else { // ...otherwise Newton-Raphson to find closest boundary point
1453     const double fact = 5. * _t * _c;
1454     double xtb = std::max(xt, tolr), ytb;
1455     double dyb, ddyb;
1456     for(int it = 0; it < maxIter; it++) {
1457       const double xbr = xtb / _c, sxbr = sqrt(xbr), xbr32 = xbr * sxbr,
1458                    xbr2 = xbr * xbr, xbr3 = xbr2 * xbr, xbr4 = xbr2 * xbr2;
1459       ytb = fact * (0.2969 * sxbr - 0.1260 * xbr - 0.3516 * xbr2 +
1460                     0.2843 * xbr3 - 0.1036 * xbr4);
1461       dyb = fact *
1462             (0.14845 / sxbr - 0.4144 * xbr3 + 0.8529 * xbr2 - 0.7032 * xbr -
1463              0.126) /
1464             _c;
1465       ddyb = fact *
1466              (-0.074225 / xbr32 - 1.2432 * xbr2 + 1.7058 * xbr - 0.7032) /
1467              (_c * _c);
1468       const double xx = xt - xtb, yy = yt - ytb;
1469       in = (xt > 0) && (yy < 0);
1470       const double dDistSq = -2. * (xx + dyb * yy);
1471       const double ddDistSq = 2. * (1. - ddyb * yy + dyb * dyb);
1472       const double mIncr = dDistSq / ddDistSq;
1473       if(fabs(mIncr) < tolr)
1474         break;
1475       else
1476         xtb -= mIncr;
1477       if(xtb < tolr) xtb = tolr;
1478       if(xtb > _c - tolr) xtb = _c - tolr;
1479     }
1480     xb = _x0 + xtb;
1481     yb = (y >= _y0) ? _y0 + ytb : _y0 - ytb;
1482     const double norm = sqrt(1. + dyb * dyb);
1483     curvRad = norm * norm * norm / fabs(ddyb);
1484   }
1485 }
1486 
operator ()(double x,double y,double z) const1487 double gLevelsetNACA00::operator()(double x, double y, double z) const
1488 {
1489   double xb, yb, curvRadb;
1490   bool in;
1491 
1492   getClosestBndPoint(x, y, z, xb, yb, curvRadb, in);
1493   const double xx = x - xb, yy = y - yb, distSq = xx * xx + yy * yy;
1494 
1495   return in ? -sqrt(distSq) : sqrt(distSq);
1496 }
1497 
gradient(double x,double y,double z,double & dfdx,double & dfdy,double & dfdz) const1498 void gLevelsetNACA00::gradient(double x, double y, double z, double &dfdx,
1499                                double &dfdy, double &dfdz) const
1500 {
1501   double xb, yb, curvRadb;
1502   bool in;
1503 
1504   getClosestBndPoint(x, y, z, xb, yb, curvRadb, in);
1505   const double xx = x - xb, yy = y - yb, distSq = xx * xx + yy * yy;
1506   const double dist = in ? -sqrt(distSq) : sqrt(distSq);
1507 
1508   dfdx = xx / dist;
1509   dfdy = yy / dist;
1510   dfdz = 0.;
1511 }
1512 
hessian(double x,double y,double z,double & dfdxx,double & dfdxy,double & dfdxz,double & dfdyx,double & dfdyy,double & dfdyz,double & dfdzx,double & dfdzy,double & dfdzz) const1513 void gLevelsetNACA00::hessian(double x, double y, double z, double &dfdxx,
1514                               double &dfdxy, double &dfdxz, double &dfdyx,
1515                               double &dfdyy, double &dfdyz, double &dfdzx,
1516                               double &dfdzy, double &dfdzz) const
1517 {
1518   double xb, yb, curvRadb;
1519   bool in;
1520 
1521   getClosestBndPoint(x, y, z, xb, yb, curvRadb, in);
1522 
1523   const double xx = x - xb, yy = y - yb, distSq = xx * xx + yy * yy;
1524   const double dist = in ? -sqrt(distSq) : sqrt(distSq);
1525   const double curvRad = curvRadb + dist,
1526                fact = 1. / (curvRad * curvRad * curvRad);
1527 
1528   dfdxx = yy * yy * fact;
1529   dfdxy = -xx * yy * fact;
1530   dfdxz = 0.;
1531   dfdyx = dfdxy;
1532   dfdyy = xx * xx * fact;
1533   dfdyz = 0.;
1534   dfdzx = 0.;
1535   dfdzy = 0.;
1536   dfdzz = 0.;
1537 }
1538