23 #if defined(HAVE_SOLVER)
32 static const int NBANN = 2;
44 Msg::Error(
"Maximum number of threads (%d) exceeded in background mesh",
77 : _octree(
nullptr), uv_kdtree(
nullptr), nodes(
nullptr), angle_nodes(
nullptr),
82 Msg::Debug(
"Building cross field using closest distance");
83 propagateCrossFieldByDistance(_gf);
91 std::set<SPoint2> myBCNodes;
92 for(std::size_t i = 0; i < _gf->
triangles.size(); i++) {
95 for(
int j = 0; j < 3; j++) {
97 auto it = _3Dto2D.find(v);
99 if(it == _3Dto2D.end()) {
103 _vertices.push_back(newv);
106 if(v->
onWhat()->
dim() < 2) myBCNodes.insert(p);
113 _triangles.push_back(T2D);
116 #if defined(HAVE_ANN)
117 index =
new ANNidx[2];
118 dist =
new ANNdist[2];
119 nodes = annAllocPts(myBCNodes.size(), 3);
120 auto itp = myBCNodes.begin();
122 while(itp != myBCNodes.end()) {
124 nodes[ind][0] = pt.
x();
125 nodes[ind][1] = pt.
y();
130 uv_kdtree =
new ANNkd_tree(nodes, myBCNodes.size(), 3);
137 if(
CTX::instance()->mesh.lcFromPoints) { propagate1dMesh(_gf); }
139 auto itv2 = _2Dto3D.begin();
140 for(; itv2 != _2Dto3D.end(); ++itv2) {
148 propagateCrossField(_gf);
159 #if defined(HAVE_ANN)
160 if(uv_kdtree)
delete uv_kdtree;
161 if(angle_kdtree)
delete angle_kdtree;
162 if(nodes) annDeallocPts(nodes);
163 if(angle_nodes) annDeallocPts(angle_nodes);
170 std::map<MVertex *, double> &dirichlet,
172 bool in_parametric_plane =
false)
174 #if defined(HAVE_SOLVER)
175 #if defined(HAVE_PETSC)
177 #elif defined(HAVE_GMM)
186 auto itv = dirichlet.begin();
187 for(; itv != dirichlet.end(); ++itv) {
188 myAssembler.
fixVertex(itv->first, 0, 1, itv->second);
192 std::set<MVertex *> vs;
193 for(std::size_t k = 0; k < _gf->
triangles.size(); k++)
194 for(
int j = 0; j < 3; j++) vs.insert(_gf->
triangles[k]->getVertex(j));
195 for(std::size_t k = 0; k < _gf->
quadrangles.size(); k++)
196 for(
int j = 0; j < 4; j++) vs.insert(_gf->
quadrangles[k]->getVertex(j));
198 std::map<MVertex *, SPoint3> theMap;
199 if(in_parametric_plane) {
200 for(
auto it = vs.begin(); it != vs.end(); ++it) {
203 theMap[*it] =
SPoint3((*it)->x(), (*it)->y(), (*it)->z());
204 (*it)->setXYZ(p.
x(), p.
y(), 0.0);
208 for(
auto it = vs.begin(); it != vs.end(); ++it)
213 for(std::size_t k = 0; k < _gf->
triangles.size(); k++) {
223 for(
auto it = vs.begin(); it != vs.end(); ++it) {
224 myAssembler.
getDofValue(*it, 0, 1, dirichlet[*it]);
227 if(in_parametric_plane) {
228 for(
auto it = vs.begin(); it != vs.end(); ++it) {
230 (*it)->setXYZ(p.
x(), p.
y(), p.
z());
239 std::vector<GEdge *>
const &e = _gf->
edges();
241 std::map<MVertex *, double> sizes;
243 for(; it != e.end(); ++it) {
244 if(!(*it)->isSeam(_gf)) {
245 for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
246 MVertex *v1 = (*it)->lines[i]->getVertex(0);
247 MVertex *v2 = (*it)->lines[i]->getVertex(1);
249 double d = sqrt((v1->
x() - v2->
x()) * (v1->
x() - v2->
x()) +
250 (v1->
y() - v2->
y()) * (v1->
y() - v2->
y()) +
251 (v1->
z() - v2->
z()) * (v1->
z() - v2->
z()));
252 for(
int k = 0; k < 2; k++) {
253 MVertex *v = (*it)->lines[i]->getVertex(k);
254 auto itv = sizes.find(v);
255 if(itv == sizes.end())
258 itv->second = 0.5 * (itv->second + log(d));
269 for(; itv2 !=
_2Dto3D.end(); ++itv2) {
272 _sizes[v_2D] = exp(sizes[v_3D]);
281 Msg::Warning(
"cannot reparametrize a point in crossField");
293 std::vector<GEdge *>
const &e = _gf->
edges();
295 std::map<MVertex *, double> _cosines4, _sines4;
296 std::map<MVertex *, SPoint2> _param;
298 for(; it != e.end(); ++it) {
299 if(!(*it)->isSeam(_gf)) {
300 for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
302 v[0] = (*it)->lines[i]->getVertex(0);
303 v[1] = (*it)->lines[i]->getVertex(1);
309 SVector3 t2(v[1]->x() - v[0]->x(), v[1]->y() - v[0]->y(),
310 v[1]->
z() - v[0]->
z());
313 double _angle =
angle(t1, t2);
316 for(
int i = 0; i < 2; i++) {
317 auto itc = _cosines4.find(v[i]);
318 auto its = _sines4.find(v[i]);
319 if(itc != _cosines4.end()) {
320 itc->second = 0.5 * (itc->second + cos(4 * _angle));
321 its->second = 0.5 * (its->second + sin(4 * _angle));
324 _param[v[i]] = (i == 0) ? p1 : p2;
325 _cosines4[v[i]] = cos(4 * _angle);
326 _sines4[v[i]] = sin(4 * _angle);
333 #if defined(HAVE_ANN)
334 index =
new ANNidx[NBANN];
335 dist =
new ANNdist[NBANN];
336 angle_nodes = annAllocPts(_cosines4.size(), 3);
337 auto itp = _cosines4.begin();
341 while(itp != _cosines4.end()) {
343 double c = itp->second;
345 double s = _sines4[v];
346 angle_nodes[ind][0] = pt.
x();
347 angle_nodes[ind][1] = pt.
y();
348 angle_nodes[ind][2] = 0.0;
354 angle_kdtree =
new ANNkd_tree(angle_nodes, _cosines4.size(), 3);
360 double cosTheta =
dot(a, b);
362 return atan2(sinTheta, cosTheta);
378 double a[3] = {cos(4 * i0->second), cos(4 * i1->second), cos(4 * i2->second)};
379 double b[3] = {sin(4 * i0->second), sin(4 * i1->second), sin(4 * i2->second)};
382 const double gradcos = sqrt(
f[0] *
f[0] +
f[1] *
f[1] +
f[2] *
f[2]);
386 return (gradcos ) * h;
400 double a[3] = {cos(4 * i0->second), cos(4 * i1->second), cos(4 * i2->second)};
401 double b[3] = {sin(4 * i0->second), sin(4 * i1->second), sin(4 * i2->second)};
404 const double gradcos = sqrt(
f[0] *
f[0] +
f[1] *
f[1] +
f[2] *
f[2]);
408 return (gradcos ) * h;
420 for(std::size_t i = 0; i < _gf->
triangles.size(); i++) {
422 double val = smoothness < .5 ? 1.0 : 1.e-3;
430 if(++ITER > 0)
break;
435 sprintf(name,
"cross-%d-%d.pos", _gf->
tag(), ITER);
437 sprintf(name,
"smooth-%d-%d.pos", _gf->
tag(), ITER);
451 std::map<MVertex *, double> _cosines4, _sines4;
452 std::vector<GEdge *>
const &e = _gf->
edges();
454 for(; it != e.end(); ++it) {
455 if(!(*it)->isSeam(_gf)) {
456 for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
458 v[0] = (*it)->lines[i]->getVertex(0);
459 v[1] = (*it)->lines[i]->getVertex(1);
467 SVector3 d1(v[1]->x() - v[0]->x(), v[1]->y() - v[0]->y(),
468 v[1]->
z() - v[0]->
z());
471 double _angle =
myAngle(t1, d1, n);
473 for(
int i = 0; i < 2; i++) {
474 auto itc = _cosines4.find(v[i]);
475 auto its = _sines4.find(v[i]);
476 if(itc != _cosines4.end()) {
477 itc->second = 0.5 * (itc->second + cos(4 * _angle));
478 its->second = 0.5 * (its->second + sin(4 * _angle));
481 _cosines4[v[i]] = cos(4 * _angle);
482 _sines4[v[i]] = sin(4 * _angle);
496 for(; itv2 !=
_2Dto3D.end(); ++itv2) {
499 double angle = atan2(_sines4[v_3D], _cosines4[v_3D]) / 4.0;
507 auto itv =
_sizes.begin();
508 for(; itv !=
_sizes.end(); ++itv) {
524 itv->second = std::min(lc, itv->second);
531 std::set<MEdge, MEdgeLessThan>
edges;
532 for(std::size_t i = 0; i <
_triangles.size(); i++) {
533 for(
int j = 0; j <
_triangles[i]->getNumEdges(); j++) {
537 const double _beta = 1.3;
538 for(
int i = 0; i < 3; i++) {
539 auto it =
edges.begin();
540 for(; it !=
edges.end(); ++it) {
541 MVertex *v0 = it->getVertex(0);
542 MVertex *v1 = it->getVertex(1);
545 auto s0 =
_sizes.find(V0);
546 auto s1 =
_sizes.find(V1);
554 if(s0->second < s1->second)
555 s1->second = std::min(s1->second, _beta * s0->second);
557 s0->second = std::min(s0->second, _beta * s1->second);
574 double uv[3] = {u, v, w};
578 #if defined(HAVE_ANN)
579 if(uv_kdtree->nPoints() < 2)
return -1000.;
580 double pt[3] = {u, v, 0.0};
581 #pragma omp critical // just to avoid crash (still incorrect) - should use nanoflann
582 uv_kdtree->annkSearch(pt, 2, index, dist);
583 SPoint3 p1(nodes[index[0]][0], nodes[index[0]][1], nodes[index[0]][2]);
584 SPoint3 p2(nodes[index[1]][0], nodes[index[1]][1], nodes[index[1]][2]);
591 Msg::Error(
"BGM octree: cannot find UVW=%g %g %g", u, v, w);
599 return itv1->second * (1 - uv2[0] - uv2[1]) + itv2->second * uv2[0] +
600 itv3->second * uv2[1];
608 #if defined(HAVE_ANN)
610 if(angle_kdtree->nPoints() >= NBANN) {
611 double pt[3] = {u, v, 0.0};
612 #pragma omp critical // just to avoid crash (still incorrect) - should use nanoflann
613 angle_kdtree->annkSearch(pt, NBANN, index, dist);
614 double SINE = 0.0, COSINE = 0.0;
615 for(
int i = 0; i < NBANN; i++) {
616 SINE += _sin[index[i]];
617 COSINE += _cos[index[i]];
619 angle = atan2(SINE, COSINE) / 4.0;
636 double uv[3] = {u, v, w};
640 #if defined(HAVE_ANN)
641 if(uv_kdtree->nPoints() < 2)
return -1000.0;
642 double pt[3] = {u, v, 0.0};
643 #pragma omp critical // just to avoid crash (still incorrect) - should use nanoflann
644 uv_kdtree->annkSearch(pt, 2, index, dist);
645 SPoint3 p1(nodes[index[0]][0], nodes[index[0]][1], nodes[index[0]][2]);
646 SPoint3 p2(nodes[index[1]][0], nodes[index[1]][1], nodes[index[1]][2]);
653 Msg::Error(
"BGM octree angle: cannot find UVW=%g %g %g", u, v, w);
662 double cos4 = cos(4 * itv1->second) * (1 - uv2[0] - uv2[1]) +
663 cos(4 * itv2->second) * uv2[0] + cos(4 * itv3->second) * uv2[1];
664 double sin4 = sin(4 * itv1->second) * (1 - uv2[0] - uv2[1]) +
665 sin(4 * itv2->second) * uv2[0] + sin(4 * itv3->second) * uv2[1];
666 double angle = atan2(sin4, cos4) / 4.0;
673 const std::map<MVertex *, double> &_whatToPrint,
676 FILE *
f =
Fopen(filename.c_str(),
"w");
678 Msg::Error(
"Could not open file '%s'", filename.c_str());
681 fprintf(
f,
"View \"Background Mesh\"{\n");
683 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
688 fprintf(
f,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n", v1->
x(),
689 v1->
y(), v1->
z(), v2->
x(), v2->
y(), v2->
z(), v3->
x(), v3->
y(),
694 for(std::size_t i = 0; i <
_triangles.size(); i++) {
698 auto itv1 = _whatToPrint.find(v1);
699 auto itv2 = _whatToPrint.find(v2);
700 auto itv3 = _whatToPrint.find(v3);
702 fprintf(
f,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n", v1->
x(),
703 v1->
y(), v1->
z(), v2->
x(), v2->
y(), v2->
z(), v3->
x(), v3->
y(),
704 v3->
z(), itv1->second, itv2->second, itv3->second);
710 fprintf(
f,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n", p1.
x(),
711 p1.
y(), p1.
z(), p2.
x(), p2.
y(), p2.
z(), p3.
x(), p3.
y(), p3.
z(),
712 itv1->second, itv2->second, itv3->second);
724 Msg::Debug(
"Rebuilding BackgroundMesh element octree");
753 Msg::Debug(
"GlobalBackgroundMesh destructor call");
765 bool overwriteExisting)
767 Msg::Debug(
"GlobalBackgroundMesh: import GModel mesh ...");
771 Msg::Debug(
"- delete existing mesh (for overwrite)");
783 std::unordered_map<MVertex *, MVertex *> old2new;
785 std::set<GVertex *, GEntityPtrLessThan> vertices =
gm->
getVertices();
788 for(
GVertex *e : gf->embeddedVertices()) vertices.insert(e);
789 for(
GEdge *e : gf->embeddedEdges())
edges.insert(e);
795 for(
size_t i = 0; i < gv->mesh_vertices.size(); ++i) {
796 MVertex *v = gv->mesh_vertices[i];
797 auto it = old2new.find(v);
798 if(it == old2new.end()) {
811 for(
size_t i = 0; i < ge->mesh_vertices.size(); ++i) {
812 MVertex *v = ge->mesh_vertices[i];
815 auto it = old2new.find(v);
816 if(it == old2new.end()) {
821 bm.
lines.reserve(ge->lines.size());
822 for(
size_t i = 0; i < ge->lines.size(); ++i) {
826 if(v0 == NULL || v1 == NULL) {
827 Msg::Error(
"GlobalBackgroundMesh: failed to import mesh (1)");
843 for(
size_t i = 0; i < gf->mesh_vertices.size(); ++i) {
844 MVertex *v = gf->mesh_vertices[i];
845 auto it = old2new.find(v);
846 if(it == old2new.end()) {
857 bm.
triangles.reserve(gf->triangles.size() + 2 * gf->quadrangles.size());
859 for(
size_t i = 0; i < gf->triangles.size(); ++i) {
864 if(v0 == NULL || v1 == NULL || v2 == NULL) {
865 Msg::Error(
"GlobalBackgroundMesh: failed to import mesh (2)");
874 if(gf->quadrangles.size() > 0) {
875 for(
size_t i = 0; i < gf->quadrangles.size(); ++i) {
881 if(v0 == NULL || v1 == NULL || v2 == NULL || v3 == NULL) {
882 Msg::Error(
"GlobalBackgroundMesh: failed to import mesh (3)");
893 Msg::Debug(
"- imported: %li vertices, %li lines, %li triangles",
894 old2new.size(), nlines, ntris);