1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5
6 #include "GmshConfig.h"
7 #include "GModel.h"
8 #include "discreteEdge.h"
9 #include "meshGEdge.h"
10 #include "GEdge.h"
11 #include "MLine.h"
12 #include "BackgroundMeshTools.h"
13 #include "boundaryLayersData.h"
14 #include "Numeric.h"
15 #include "GmshMessage.h"
16 #include "Context.h"
17 #include "STensor3.h"
18 #include "Field.h"
19 #include "OS.h"
20
21 typedef struct {
22 int Num;
23 // t is the local coordinate of the point
24 // lc is x'(t)/h(x(t))
25 // p is the value of the primitive
26 // xp is the norm of the tangent vector
27 double t, lc, p, xp;
28 } IntPoint;
29
smoothPrimitive(GEdge * ge,double alpha,std::vector<IntPoint> & Points)30 static double smoothPrimitive(GEdge *ge, double alpha,
31 std::vector<IntPoint> &Points)
32 {
33 int ITER = 0;
34 while(1) {
35 int count1 = 0;
36 int count2 = 0;
37
38 // use a gauss-seidel iteration; iterate forward and then backward;
39 // convergence is usually very fast
40 for(std::size_t i = 1; i < Points.size(); i++) {
41 double dh =
42 (Points[i].xp / Points[i].lc - Points[i - 1].xp / Points[i - 1].lc);
43 double dt = Points[i].t - Points[i - 1].t;
44 double dhdt = dh / dt;
45 if(dhdt / Points[i].xp > (alpha - 1.) * 1.01) {
46 double hnew =
47 Points[i - 1].xp / Points[i - 1].lc + dt * (alpha - 1) * Points[i].xp;
48 Points[i].lc = Points[i].xp / hnew;
49 count1++;
50 }
51 }
52
53 for(int i = Points.size() - 1; i > 0; i--) {
54 double dh =
55 (Points[i - 1].xp / Points[i - 1].lc - Points[i].xp / Points[i].lc);
56 double dt = std::abs(Points[i - 1].t - Points[i].t);
57 double dhdt = dh / dt;
58 if(dhdt / Points[i - 1].xp > (alpha - 1.) * 1.01) {
59 double hnew =
60 Points[i].xp / Points[i].lc + dt * (alpha - 1) * Points[i].xp;
61 Points[i - 1].lc = Points[i - 1].xp / hnew;
62 count2++;
63 }
64 }
65
66 ++ITER;
67 if(ITER > 2000) break;
68 if(!(count1 + count2)) break;
69 }
70
71 // recompute the primitive
72 for(std::size_t i = 1; i < Points.size(); i++) {
73 IntPoint &pt2 = Points[i];
74 IntPoint &pt1 = Points[i - 1];
75 pt2.p = pt1.p + (pt2.t - pt1.t) * 0.5 * (pt2.lc + pt1.lc);
76 }
77 return Points[Points.size() - 1].p;
78 }
79
80 struct F_LcB {
operator ()F_LcB81 double operator()(GEdge *ge, double t)
82 {
83 GPoint p = ge->point(t);
84 return BGM_MeshSize(ge, t, 0, p.x(), p.y(), p.z());
85 }
86 };
87
88 struct F_Lc {
operator ()F_Lc89 double operator()(GEdge *ge, double t)
90 {
91 GPoint p = ge->point(t);
92 Range<double> bounds = ge->parBounds(0);
93 double t_begin = bounds.low();
94 double t_end = bounds.high();
95 double lc_here = 1.e22;
96 if(t == t_begin && ge->getBeginVertex())
97 lc_here = BGM_MeshSize(ge->getBeginVertex(), t, 0, p.x(), p.y(), p.z());
98 else if(t == t_end && ge->getEndVertex())
99 lc_here = BGM_MeshSize(ge->getEndVertex(), t, 0, p.x(), p.y(), p.z());
100
101 lc_here = std::min(lc_here, BGM_MeshSize(ge, t, 0, p.x(), p.y(), p.z()));
102 SVector3 der = ge->firstDer(t);
103 return norm(der) / lc_here;
104 }
105 };
106
107 struct F_Lc_aniso {
operator ()F_Lc_aniso108 double operator()(GEdge *ge, double t)
109 {
110 GPoint p = ge->point(t);
111 SMetric3 lc_here;
112
113 Range<double> bounds = ge->parBounds(0);
114 double t_begin = bounds.low();
115 double t_end = bounds.high();
116
117 if(t == t_begin && ge->getBeginVertex())
118 lc_here = BGM_MeshMetric(ge->getBeginVertex(), t, 0, p.x(), p.y(), p.z());
119 else if(t == t_end && ge->getEndVertex())
120 lc_here = BGM_MeshMetric(ge->getEndVertex(), t, 0, p.x(), p.y(), p.z());
121 else
122 lc_here = BGM_MeshMetric(ge, t, 0, p.x(), p.y(), p.z());
123
124 FieldManager *fields = ge->model()->getFields();
125 for(int i = 0; i < fields->getNumBoundaryLayerFields(); ++i) {
126 Field *bl_field = fields->get(fields->getBoundaryLayerField(i));
127 if(bl_field == nullptr) continue;
128 BoundaryLayerField *blf = dynamic_cast<BoundaryLayerField *>(bl_field);
129 if(blf->isEdgeBL(ge->tag())) break;
130 SMetric3 lc_bgm;
131 blf->computeFor1dMesh(p.x(), p.y(), p.z(), lc_bgm);
132 lc_here = intersection_conserveM1(lc_here, lc_bgm);
133 }
134
135 SVector3 der = ge->firstDer(t);
136 return std::sqrt(dot(der, lc_here, der));
137 }
138 };
139
140 // static double dfbeta2 (double t, double beta){
141 // double ratio = (1+beta)/(beta-1);
142 // double zlog = log(ratio);
143 // return 1.-acosh(beta*zlog/t - 1.0)/zlog;
144 // return beta*zlog / (1+cosh(zlog*(1-t)));
145 //}
146
dfbeta(double t,double beta)147 static double dfbeta(double t, double beta)
148 {
149 double ratio = (1 + beta) / (beta - 1);
150 double zlog = log(ratio);
151 return 2 * beta / ((1 + beta - t) * (-1 + beta + t) * zlog);
152 }
153
154 struct F_Transfinite {
operator ()F_Transfinite155 double operator()(GEdge *ge, double t_)
156 {
157 double length = ge->length();
158 if(length == 0.0) {
159 Msg::Error("Zero-length curve %d in transfinite mesh", ge->tag());
160 return 1.;
161 }
162
163 SVector3 der = ge->firstDer(t_);
164 double d = norm(der);
165 double coef = ge->meshAttributes.coeffTransfinite;
166 int type = ge->meshAttributes.typeTransfinite;
167 int atype = std::abs(type);
168 int nbpt = ge->meshAttributes.nbPointsTransfinite;
169
170 if(CTX::instance()->mesh.flexibleTransfinite &&
171 CTX::instance()->mesh.lcFactor)
172 nbpt /= CTX::instance()->mesh.lcFactor;
173
174 Range<double> bounds = ge->parBounds(0);
175 double t_begin = bounds.low();
176 double t_end = bounds.high();
177 double t = (t_ - t_begin) / (t_end - t_begin);
178
179 double val;
180
181 if(coef <= 0.0 || coef == 1.0 || (atype == 3 && coef < 1.)) {
182 // coef < 0 should never happen
183 val = d * coef / ge->length();
184 }
185 else {
186 switch(atype) {
187 case 1: {
188 // geometric progression ar^i; Sum of n terms = length = a (r^n-1)/(r-1)
189 double r = (gmsh_sign(type) >= 0) ? coef : 1. / coef;
190 double a = length * (r - 1.) / (std::pow(r, nbpt - 1.) - 1.);
191 int i = (int)(std::log(t * length / a * (r - 1.) + 1.) / std::log(r));
192 val = d / (a * std::pow(r, (double)i));
193 } break;
194
195 case 2: {
196 // "bump"
197 double a;
198 if(coef > 1.0) {
199 a = -4. * std::sqrt(coef - 1.) *
200 std::atan2(1.0, std::sqrt(coef - 1.)) / ((double)nbpt * length);
201 }
202 else {
203 a = 2. * std::sqrt(1. - coef) *
204 std::log(std::abs((1. + 1. / std::sqrt(1. - coef)) /
205 (1. - 1. / std::sqrt(1. - coef)))) /
206 ((double)nbpt * length);
207 }
208 double b = -a * length * length / (4. * (coef - 1.));
209 val = d / (-a * std::pow(t * length - (length)*0.5, 2) + b);
210 break;
211 }
212 case 3: {
213 // "beta" law
214 if(type < 0)
215 val = dfbeta(1. - t, coef);
216 else
217 val = dfbeta(t, coef);
218 break;
219 }
220 case 4: {
221 // standard boundary layer progression: TODO
222 val = d / (length * t);
223 break;
224 }
225 default:
226 Msg::Warning("Unknown case in Transfinite Line mesh");
227 val = 1.;
228 break;
229 }
230 }
231 return val;
232 }
233 };
234
235 struct F_One {
operator ()F_One236 double operator()(GEdge *ge, double t)
237 {
238 SVector3 der = ge->firstDer(t);
239 return norm(der);
240 }
241 };
242
trapezoidal(IntPoint * const P1,IntPoint * const P2)243 static double trapezoidal(IntPoint *const P1, IntPoint *const P2)
244 {
245 return 0.5 * (P1->lc + P2->lc) * (P2->t - P1->t);
246 }
247
248 template <typename function>
RecursiveIntegration(GEdge * ge,IntPoint * from,IntPoint * to,function f,std::vector<IntPoint> & Points,double Prec,int * depth)249 static void RecursiveIntegration(GEdge *ge, IntPoint *from, IntPoint *to,
250 function f, std::vector<IntPoint> &Points,
251 double Prec, int *depth)
252 {
253 IntPoint P, p1;
254
255 (*depth)++;
256
257 P.t = 0.5 * (from->t + to->t);
258 P.lc = f(ge, P.t);
259
260 double const val1 = trapezoidal(from, to);
261 double const val2 = trapezoidal(from, &P);
262 double const val3 = trapezoidal(&P, to);
263 double const err = std::abs(val1 - val2 - val3);
264
265 if(((err < Prec) && (*depth > 6)) || (*depth > 25)) {
266 p1 = Points.back();
267 P.p = p1.p + val2;
268 Points.push_back(P);
269
270 p1 = Points.back();
271 to->p = p1.p + val3;
272 Points.push_back(*to);
273 }
274 else {
275 RecursiveIntegration(ge, from, &P, f, Points, Prec, depth);
276 RecursiveIntegration(ge, &P, to, f, Points, Prec, depth);
277 }
278
279 (*depth)--;
280 }
281
282 template <typename function>
Integration(GEdge * ge,double t1,double t2,function f,std::vector<IntPoint> & Points,double Prec)283 static double Integration(GEdge *ge, double t1, double t2, function f,
284 std::vector<IntPoint> &Points, double Prec)
285 {
286 IntPoint from, to;
287
288 int depth = 0;
289
290 from.t = t1;
291 from.lc = f(ge, from.t);
292 from.p = 0.0;
293 Points.push_back(from);
294
295 to.t = t2;
296 to.lc = f(ge, to.t);
297
298 RecursiveIntegration(ge, &from, &to, f, Points, Prec, &depth);
299
300 return Points.back().p;
301 }
302
transform(MVertex * vsource,const std::vector<double> & tfo)303 static SPoint3 transform(MVertex *vsource, const std::vector<double> &tfo)
304 {
305 double ps[4] = {vsource->x(), vsource->y(), vsource->z(), 1.};
306 double res[4] = {0., 0., 0., 0.};
307 int idx = 0;
308 for(int i = 0; i < 4; i++)
309 for(int j = 0; j < 4; j++) res[i] += tfo[idx++] * ps[j];
310
311 return SPoint3(res[0], res[1], res[2]);
312 }
313
copyMesh(GEdge * from,GEdge * to,int direction)314 static void copyMesh(GEdge *from, GEdge *to, int direction)
315 {
316 if(!from->getBeginVertex() || !from->getEndVertex() ||
317 !to->getBeginVertex() || !to->getEndVertex()) {
318 Msg::Error("Cannot copy mesh on curves without begin/end points");
319 return;
320 }
321
322 Range<double> u_bounds = from->parBounds(0);
323 double u_min = u_bounds.low();
324 double u_max = u_bounds.high();
325
326 Range<double> to_u_bounds = to->parBounds(0);
327 double to_u_min = to_u_bounds.low();
328
329 // include begin and end point to avoid conflicts when realigning
330 MVertex *vt0 = to->getBeginVertex()->mesh_vertices[0];
331 MVertex *vt1 = to->getEndVertex()->mesh_vertices[0];
332 MVertex *vs0 = from->getBeginVertex()->mesh_vertices[0];
333 MVertex *vs1 = from->getEndVertex()->mesh_vertices[0];
334
335 to->correspondingVertices[vt0] = direction > 0 ? vs0 : vs1;
336 to->correspondingVertices[vt1] = direction > 0 ? vs1 : vs0;
337
338 for(std::size_t i = 0; i < from->mesh_vertices.size(); i++) {
339 int index = (direction < 0) ? (from->mesh_vertices.size() - 1 - i) : i;
340 MVertex *v = from->mesh_vertices[index];
341 GPoint gp;
342 double newu;
343 if(to->affineTransform.size() < 16) {
344 // assume identical parametrisations (dangerous...)
345 double u;
346 v->getParameter(0, u);
347 newu = (direction > 0) ? (u - u_min + to_u_min) : (u_max - u + to_u_min);
348 gp = to->point(newu);
349 }
350 else {
351 SPoint3 p = transform(v, to->affineTransform);
352 // for non-exact periodic curves we could use closestPoint; just use
353 // Mesh.HighOrderPeriodic=2, which will do that
354 newu = to->parFromPoint(p);
355 gp = to->point(newu);
356 // gp = to->closestPoint(p, newu);
357 }
358 MEdgeVertex *vv = new MEdgeVertex(gp.x(), gp.y(), gp.z(), to, newu);
359 to->mesh_vertices.push_back(vv);
360 to->correspondingVertices[vv] = v;
361 }
362 for(std::size_t i = 0; i < to->mesh_vertices.size() + 1; i++) {
363 MVertex *v0 = (i == 0) ? to->getBeginVertex()->mesh_vertices[0] :
364 to->mesh_vertices[i - 1];
365 MVertex *v1 = (i == to->mesh_vertices.size()) ?
366 to->getEndVertex()->mesh_vertices[0] :
367 to->mesh_vertices[i];
368 to->lines.push_back(new MLine(v0, v1));
369 }
370 }
371
operator ()(GEdge * ge)372 void deMeshGEdge::operator()(GEdge *ge)
373 {
374 if(ge->isFullyDiscrete()) return;
375 ge->deleteMesh();
376 ge->meshStatistics.status = GEdge::PENDING;
377 }
378
379 /*
380 static void printFandPrimitive(int tag, std::vector<IntPoint> &Points)
381 {
382 char name[256];
383 sprintf(name, "line%d.dat", tag);
384 FILE *f = Fopen(name, "w");
385 if(!f) return;
386 double l = 0;
387 for (std::size_t i = 0; i < Points.size(); i++){
388 const IntPoint &P = Points[i];
389 if(i) l += (P.t - Points[i-1].t) * P.xp;
390 fprintf(f, "%g %g %g %g %g\n", P.t, P.xp/P.lc, P.p, P.lc, l);
391 }
392 fclose(f);
393 }
394 */
395
396 // new algo for recombining + splitting
increaseN(int N)397 static int increaseN(int N)
398 {
399 if(((N + 1) / 2 - 1) % 2 != 0) return N + 2;
400 return N;
401 }
402
403 // ensure not to have points that are too close to each other.
404 // can be caused by a coarse 1D mesh or by a noisy curve
filterPoints(GEdge * ge,int nMinimumPoints)405 static void filterPoints(GEdge *ge, int nMinimumPoints)
406 {
407 if(ge->mesh_vertices.empty()) return;
408 if(ge->meshAttributes.method == MESH_TRANSFINITE) return;
409
410 bool forceOdd = false;
411 if((ge->meshAttributes.method != MESH_TRANSFINITE ||
412 CTX::instance()->mesh.flexibleTransfinite) &&
413 CTX::instance()->mesh.algoRecombine != 0) {
414 if(CTX::instance()->mesh.recombineAll) { forceOdd = true; }
415 }
416
417 if(!ge->getBeginVertex() || !ge->getEndVertex()) return;
418
419 MVertex *v0 = ge->getBeginVertex()->mesh_vertices[0];
420 std::vector<std::pair<double, MVertex *> > lengths;
421 for(std::size_t i = 0; i < ge->mesh_vertices.size(); i++) {
422 MEdgeVertex *v = dynamic_cast<MEdgeVertex *>(ge->mesh_vertices[i]);
423 if(!v) {
424 Msg::Error("Node not classified on curve in 1D mesh filtering");
425 return;
426 }
427 double d = distance(v, v0);
428 double t;
429 v->getParameter(0, t);
430 if(i != 0) {
431 double t0;
432 if(v0->onWhat()->dim() == 0) {
433 // Vertex is begin point
434 t0 = ge->parFromPoint(SPoint3(v0->x(), v0->y(), v0->z()));
435 }
436 else
437 v0->getParameter(0, t0);
438
439 t = 0.5 * (t + t0);
440 }
441 double lc = F_LcB()(ge, t);
442 // double lc = v->getLc();
443 if(d < lc * .3) { lengths.push_back(std::make_pair(lc / d, v)); }
444 else
445 v0 = v;
446 }
447 std::sort(lengths.begin(), lengths.end());
448 int last = lengths.size();
449 if(forceOdd) {
450 while(last % 2 != 0) last--;
451 }
452 /*
453 if(CTX::instance()->mesh.algoRecombine == 2){
454 if(last < 4) last = 0;
455 while (last %4 != 0)last--;
456 }
457 else{
458 while (last %2 != 0)last--;
459 }
460 }
461 */
462
463 bool filteringObservesMinimumN =
464 (((int)ge->mesh_vertices.size() - last) >= nMinimumPoints);
465 if(filteringObservesMinimumN) {
466 for(int i = 0; i < last; i++) {
467 auto it = std::find(ge->mesh_vertices.begin(), ge->mesh_vertices.end(),
468 lengths[i].second);
469
470 if(it != ge->mesh_vertices.end()) { ge->mesh_vertices.erase(it); }
471 delete lengths[i].second;
472 }
473 }
474 }
475
createPoints(GVertex * gv,GEdge * ge,BoundaryLayerField * blf,std::vector<MVertex * > & v,const SVector3 & dir)476 static void createPoints(GVertex *gv, GEdge *ge, BoundaryLayerField *blf,
477 std::vector<MVertex *> &v, const SVector3 &dir)
478 {
479 if(!ge->getBeginVertex() || !ge->getEndVertex()) return;
480
481 const double hWall = blf->hWall(gv->tag());
482 double L = hWall;
483 double LEdge = distance(ge->getBeginVertex()->mesh_vertices[0],
484 ge->getEndVertex()->mesh_vertices[0]);
485
486 if(blf->betaLaw) {
487 std::vector<double> t(blf->nb_divisions);
488 double zlog = log((1 + blf->beta) / (blf->beta - 1));
489 for(int i = 0; i < blf->nb_divisions; i++) {
490 const double eta = (double)(i + 1) / blf->nb_divisions;
491 const double power = exp(zlog * (1. - eta));
492 const double ratio = (1. - power) / (1. + power);
493 t[i] = 1.0 + blf->beta * ratio;
494 }
495 for(int i = 0; i < blf->nb_divisions; i++) {
496 double L = hWall * t[i] / t[0];
497 SPoint3 p(gv->x() + dir.x() * L, gv->y() + dir.y() * L, 0.0);
498 v.push_back(new MEdgeVertex(p.x(), p.y(), p.z(), ge, ge->parFromPoint(p),
499 0, blf->hFar));
500 }
501 }
502 else {
503 while(1) {
504 if(L > blf->thickness || L > LEdge * .4) { break; }
505
506 SPoint3 p(gv->x() + dir.x() * L, gv->y() + dir.y() * L, 0.0);
507 v.push_back(new MEdgeVertex(p.x(), p.y(), p.z(), ge, ge->parFromPoint(p),
508 0, blf->hFar));
509 int ith = v.size();
510 L += hWall * std::pow(blf->ratio, ith);
511 }
512 }
513 }
514
addBoundaryLayerPoints(GEdge * ge,double & t_begin,double & t_end,std::vector<MVertex * > & _addBegin,std::vector<MVertex * > & _addEnd)515 static void addBoundaryLayerPoints(GEdge *ge, double &t_begin, double &t_end,
516 std::vector<MVertex *> &_addBegin,
517 std::vector<MVertex *> &_addEnd)
518 {
519 _addBegin.clear();
520 _addEnd.clear();
521
522 // t_begin/t_end may change the left/right parameter of the interval
523 // _addBegin/_addEnd : additional points @ left/right
524 FieldManager *fields = ge->model()->getFields();
525 int n = fields->getNumBoundaryLayerFields();
526
527 if(n == 0) return;
528
529 if(!ge->getBeginVertex() || !ge->getEndVertex()) return;
530
531 // Check if edge is a BL edge
532 for(int i = 0; i < n; ++i) {
533 Field *bl_field = fields->get(fields->getBoundaryLayerField(i));
534 if(bl_field == nullptr) continue;
535 BoundaryLayerField *blf = dynamic_cast<BoundaryLayerField *>(bl_field);
536 if(blf->isEdgeBL(ge->tag())) return;
537 }
538
539 SVector3 dir(ge->getEndVertex()->x() - ge->getBeginVertex()->x(),
540 ge->getEndVertex()->y() - ge->getBeginVertex()->y(),
541 ge->getEndVertex()->z() - ge->getBeginVertex()->z());
542 dir.normalize();
543 GVertex *gvb = ge->getBeginVertex();
544 GVertex *gve = ge->getEndVertex();
545
546 // Check if extremity nodes are BL node
547 for(int i = 0; i < n; ++i) {
548 Field *bl_field = fields->get(fields->getBoundaryLayerField(i));
549 if(bl_field == nullptr) continue;
550 BoundaryLayerField *blf = dynamic_cast<BoundaryLayerField *>(bl_field);
551 blf->setupFor1d(ge->tag());
552
553 if(blf->isEndNode(gvb->tag())) {
554 if(ge->geomType() != GEntity::Line) {
555 Msg::Error("Boundary layer end point %d should lie on a straight line",
556 gvb->tag());
557 return;
558 }
559 if(_addBegin.size()) {
560 Msg::Error("Different boundary layers cannot touch each other");
561 return;
562 }
563 createPoints(gvb, ge, blf, _addBegin, dir);
564 if(!_addBegin.empty())
565 _addBegin[_addBegin.size() - 1]->getParameter(0, t_begin);
566 }
567 if(blf->isEndNode(gve->tag())) {
568 if(ge->geomType() != GEntity::Line) {
569 Msg::Error("Boundary layer end point %d should lie on a straight line",
570 gve->tag());
571 return;
572 }
573 if(_addEnd.size()) {
574 Msg::Error("Different boundary layers cannot touch each other");
575 return;
576 }
577 createPoints(gve, ge, blf, _addEnd, dir * -1.0);
578 if(!_addEnd.empty()) _addEnd[_addEnd.size() - 1]->getParameter(0, t_end);
579 }
580 }
581 }
582
meshGEdgeProcessing(GEdge * ge,const double t_begin,double t_end,int & N,std::vector<IntPoint> & Points,double & a,int & filterMinimumN)583 int meshGEdgeProcessing(GEdge *ge, const double t_begin, double t_end, int &N,
584 std::vector<IntPoint> &Points, double &a,
585 int &filterMinimumN)
586 {
587 if(ge->geomType() == GEntity::BoundaryLayerCurve) return 0;
588 if(ge->meshAttributes.method == MESH_NONE) return 0;
589 if(CTX::instance()->mesh.meshOnlyVisible && !ge->getVisibility()) return 0;
590 if(CTX::instance()->mesh.meshOnlyEmpty && ge->getNumMeshElements()) return 0;
591
592 // first compute the length of the curve by integrating one
593 double length;
594 Points.clear();
595 if(ge->geomType() == GEntity::Line && ge->getBeginVertex() &&
596 ge->getBeginVertex() == ge->getEndVertex() &&
597 // do not consider closed lines as degenerated
598 (ge->position(0.5) - ge->getBeginVertex()->xyz()).norm() <
599 CTX::instance()->geom.tolerance)
600 length = 0.0; // special case to avoid infinite loop in integration
601 else
602 length = Integration(ge, t_begin, t_end, F_One(), Points,
603 CTX::instance()->mesh.lcIntegrationPrecision *
604 CTX::instance()->lc);
605 ge->setLength(length);
606 Points.clear();
607
608 if(length < CTX::instance()->mesh.toleranceEdgeLength) {
609 ge->setTooSmall(true);
610 }
611
612 // Integrate detJ/lc du
613 filterMinimumN = 1;
614 if(length == 0. && CTX::instance()->mesh.toleranceEdgeLength == 0.) {
615 Msg::Debug("Curve %d has a zero length", ge->tag());
616 a = 0.;
617 N = 1;
618 }
619 else if(ge->degenerate(0)) {
620 Msg::Debug("Curve %d is degenerated", ge->tag());
621 a = 0.;
622 N = 1;
623 }
624 else if(ge->meshAttributes.method == MESH_TRANSFINITE &&
625 ge->meshAttributes.typeTransfinite == 4) {
626 // Transfinite (prescribed number of edges) but the points are positioned
627 // according to the standard size constraints (size map, etc)
628 a = Integration(ge, t_begin, t_end, F_Lc(), Points,
629 CTX::instance()->mesh.lcIntegrationPrecision);
630 N = ge->meshAttributes.nbPointsTransfinite;
631 }
632 else if(ge->meshAttributes.method == MESH_TRANSFINITE) {
633 a = Integration(ge, t_begin, t_end, F_Transfinite(), Points,
634 CTX::instance()->mesh.lcIntegrationPrecision);
635 N = ge->meshAttributes.nbPointsTransfinite;
636 if(CTX::instance()->mesh.flexibleTransfinite &&
637 CTX::instance()->mesh.lcFactor)
638 N /= CTX::instance()->mesh.lcFactor;
639 }
640 else {
641 if(CTX::instance()->mesh.algo2d == ALGO_2D_BAMG /* || blf*/) {
642 a = Integration(ge, t_begin, t_end, F_Lc_aniso(), Points,
643 CTX::instance()->mesh.lcIntegrationPrecision);
644 }
645 else {
646 a = Integration(ge, t_begin, t_end, F_Lc(), Points,
647 CTX::instance()->mesh.lcIntegrationPrecision);
648 }
649
650 // we should maybe provide an option to disable the smoothing
651 for(std::size_t i = 0; i < Points.size(); i++) {
652 IntPoint &pt = Points[i];
653 SVector3 der = ge->firstDer(pt.t);
654 pt.xp = der.norm();
655 }
656 if(CTX::instance()->mesh.algo2d != ALGO_2D_BAMG)
657 a = smoothPrimitive(ge, std::sqrt(CTX::instance()->mesh.smoothRatio),
658 Points);
659 filterMinimumN = ge->minimumMeshSegments() + 1;
660 N = std::max(filterMinimumN, (int)(a + 1.99));
661 }
662
663 // force odd number of points if blossom is used for recombination
664 if((ge->meshAttributes.method != MESH_TRANSFINITE ||
665 CTX::instance()->mesh.flexibleTransfinite) &&
666 CTX::instance()->mesh.algoRecombine != 0) {
667 std::vector<GFace *> const &faces = ge->faces();
668 if(CTX::instance()->mesh.recombineAll && faces.size()) {
669 if(N % 2 == 0) N++;
670 if(CTX::instance()->mesh.algoRecombine == 2 ||
671 CTX::instance()->mesh.algoRecombine == 4)
672 N = increaseN(N);
673 }
674 else {
675 for(auto it = faces.begin(); it != faces.end(); it++) {
676 if((*it)->meshAttributes.recombine) {
677 if(N % 2 == 0) N++;
678 if(CTX::instance()->mesh.algoRecombine == 2 ||
679 CTX::instance()->mesh.algoRecombine == 4)
680 N = increaseN(N);
681 break;
682 }
683 }
684 }
685 }
686
687 return N;
688 }
689
operator ()(GEdge * ge)690 void meshGEdge::operator()(GEdge *ge)
691 {
692 // debug stuff
693 if(CTX::instance()->debugSurface > 0) {
694 std::vector<GFace *> f = ge->faces();
695 bool found = false;
696 for(size_t i = 0; i < f.size(); i++) {
697 if(f[i]->tag() == CTX::instance()->debugSurface) { found = true; }
698 }
699 if(!found) return;
700 }
701
702 ge->model()->setCurrentMeshEntity(ge);
703
704 if(ge->degenerate(1)) {
705 ge->meshStatistics.status = GEdge::DONE;
706 return;
707 }
708
709 if(ge->geomType() == GEntity::BoundaryLayerCurve) return;
710 if(ge->meshAttributes.method == MESH_NONE) return;
711 if(CTX::instance()->mesh.meshOnlyVisible && !ge->getVisibility()) return;
712 if(CTX::instance()->mesh.meshOnlyEmpty && ge->getNumMeshElements()) return;
713
714 // destroy the mesh if it exists
715 deMeshGEdge dem;
716 dem(ge);
717
718 if(MeshExtrudedCurve(ge)) return;
719
720 if(ge->getMeshMaster() != ge) {
721 GEdge *gef = dynamic_cast<GEdge *>(ge->getMeshMaster());
722 if(gef->meshStatistics.status == GEdge::PENDING) return;
723 Msg::Info("Meshing curve %d (%s) as a copy of curve %d", ge->tag(),
724 ge->getTypeString().c_str(), ge->getMeshMaster()->tag());
725 copyMesh(gef, ge, ge->masterOrientation);
726 ge->meshStatistics.status = GEdge::DONE;
727 return;
728 }
729
730 Msg::Info("Meshing curve %d (%s)", ge->tag(), ge->getTypeString().c_str());
731
732 // compute bounds
733 Range<double> bounds = ge->parBounds(0);
734 double t_begin = bounds.low();
735 double t_end = bounds.high();
736
737 // if a BL is ending at one of the ends, then create specific points
738 std::vector<MVertex *> _addBegin, _addEnd;
739 addBoundaryLayerPoints(ge, t_begin, t_end, _addBegin, _addEnd);
740
741 // integration to get length, number of points, etc
742 int N;
743 std::vector<IntPoint> Points;
744 double a;
745 int filterMinimumN;
746 meshGEdgeProcessing(ge, t_begin, t_end, N, Points, a, filterMinimumN);
747
748 // printFandPrimitive(ge->tag(),Points);
749
750 // if the curve is periodic and if the begin vertex is identical to
751 // the end vertex and if this vertex has only one model curve
752 // adjacent to it, then the vertex is not connecting any other
753 // curve. So, the mesh vertex and its associated geom vertex are not
754 // necessary at the same location
755
756 // look if we are doing the STL triangulation
757 std::vector<MVertex *> &mesh_vertices = ge->mesh_vertices;
758
759 GPoint beg_p, end_p;
760 if(!ge->getBeginVertex() || !ge->getEndVertex()) {
761 Msg::Warning("Skipping curve with no begin or end point");
762 return;
763 }
764 else if(ge->getBeginVertex() == ge->getEndVertex() &&
765 ge->getBeginVertex()->edges().size() == 1) {
766 end_p = beg_p = ge->point(t_begin);
767 Msg::Debug("Meshing periodic closed curve (tag %i, %i points)", ge->tag(),
768 N);
769 }
770 else {
771 MVertex *v0 = ge->getBeginVertex()->mesh_vertices[0];
772 MVertex *v1 = ge->getEndVertex()->mesh_vertices[0];
773 beg_p = GPoint(v0->x(), v0->y(), v0->z());
774 end_p = GPoint(v1->x(), v1->y(), v1->z());
775 }
776
777 // do not consider the first and the last vertex (those are not
778 // classified on this mesh edge)
779 if(N > 1) {
780 const double b = a / static_cast<double>(N - 1);
781 int count = 1, NUMP = 1;
782 IntPoint P1, P2;
783 mesh_vertices.resize(N - 2);
784
785 while(NUMP < N - 1) {
786 P1 = Points[count - 1];
787 P2 = Points[count];
788 const double d = (double)NUMP * b;
789 if((std::abs(P2.p) >= std::abs(d)) && (std::abs(P1.p) < std::abs(d))) {
790 double const dt = P2.t - P1.t;
791 double const dlc = P2.lc - P1.lc;
792 double const dp = P2.p - P1.p;
793 double const t = P1.t + dt / dp * (d - P1.p);
794 SVector3 der = ge->firstDer(t);
795 const double d = norm(der);
796 double lc = d / (P1.lc + dlc / dp * (d - P1.p));
797 GPoint V = ge->point(t);
798 mesh_vertices[NUMP - 1] =
799 new MEdgeVertex(V.x(), V.y(), V.z(), ge, t, 0, lc);
800 NUMP++;
801 }
802 else {
803 count++;
804 }
805 }
806 mesh_vertices.resize(NUMP - 1);
807 }
808
809 // Boundary Layer points are added
810 {
811 std::vector<MVertex *> vv;
812 vv.insert(vv.end(), _addBegin.begin(), _addBegin.end());
813 vv.insert(vv.end(), mesh_vertices.begin(), mesh_vertices.end());
814 for(std::size_t i = 0; i < _addEnd.size(); i++)
815 vv.push_back(_addEnd[_addEnd.size() - 1 - i]);
816 mesh_vertices = vv;
817 }
818
819 if(CTX::instance()->mesh.algo2d != ALGO_2D_BAMG &&
820 CTX::instance()->mesh.algo2d != ALGO_2D_QUAD_QUASI_STRUCT &&
821 CTX::instance()->mesh.algo2d != ALGO_2D_PACK_PRLGRMS)
822 if(_addBegin.empty() && _addEnd.empty())
823 filterPoints(ge, filterMinimumN - 2);
824
825 std::vector<MLine *> &lines = ge->lines;
826
827 for(std::size_t i = 0; i <= mesh_vertices.size(); i++) {
828 MVertex *v0 =
829 (i == 0) ? ge->getBeginVertex()->mesh_vertices[0] : mesh_vertices[i - 1];
830
831 MVertex *v1 = (i == mesh_vertices.size()) ?
832 ge->getEndVertex()->mesh_vertices[0] :
833 mesh_vertices[i];
834 lines.push_back(new MLine(v0, v1));
835 }
836
837 if(ge->getBeginVertex() == ge->getEndVertex() &&
838 ge->getBeginVertex()->edges().size() == 1) {
839 MVertex *v0 = ge->getBeginVertex()->mesh_vertices[0];
840 v0->x() = beg_p.x();
841 v0->y() = beg_p.y();
842 v0->z() = beg_p.z();
843 }
844
845 Msg::Debug("Meshing curve %d (%s): %li interior vertices", ge->tag(),
846 ge->getTypeString().c_str(), ge->mesh_vertices.size());
847
848 ge->meshStatistics.status = GEdge::DONE;
849 }
850
operator ()(GEdge * ge)851 void orientMeshGEdge::operator()(GEdge *ge)
852 {
853 // apply user-specified mesh orientation constraints
854 if(ge->meshAttributes.reverseMesh)
855 for(std::size_t k = 0; k < ge->getNumMeshElements(); k++)
856 ge->getMeshElement(k)->reverse();
857 }
858
meshGEdgeTargetNumberOfPoints(GEdge * ge)859 int meshGEdgeTargetNumberOfPoints(GEdge *ge)
860 {
861 Range<double> bounds = ge->parBounds(0);
862 double t_begin = bounds.low();
863 double t_end = bounds.high();
864
865 int N = 0;
866 std::vector<IntPoint> Points;
867 double a = 0.;
868 int filterMinimumN = 1;
869 meshGEdgeProcessing(ge, t_begin, t_end, N, Points, a, filterMinimumN);
870 return N;
871 }
872