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> ¢ers, 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