gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
GFace.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 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 "GFace.h"
7 #include "Context.h"
8 #include "ExtrudeParams.h"
9 #include "GEdge.h"
10 #include "GModel.h"
11 #include "GaussLegendre1D.h"
12 #include "GmshConfig.h"
13 #include "GmshMessage.h"
14 #include "MElementCut.h"
15 #include "MQuadrangle.h"
16 #include "MTriangle.h"
17 #include "Numeric.h"
18 #include "OS.h"
19 #include "VertexArray.h"
20 #include "discreteEdge.h"
21 #include "discreteFace.h"
22 #include "fullMatrix.h"
23 #include <sstream>
24 
25 #if defined(HAVE_MESH)
26 #include "BackgroundMeshTools.h"
27 #include "Field.h"
28 #include "meshGFace.h"
30 #include "meshGFaceOptimize.h"
31 #endif
32 
33 #if defined(HAVE_ALGLIB)
34 #include <optimization.h>
35 #include <stdafx.h>
36 #endif
37 
38 #if defined(HAVE_QUADMESHINGTOOLS)
39 #include "cppUtils.h"
40 #include "qmtCrossField.h"
41 #include "qmtMeshUtils.h"
42 #endif
43 
44 GFace::GFace(GModel *model, int tag)
45  : GEntity(model, tag), r1(nullptr), r2(nullptr), va_geom_triangles(nullptr), compoundSurface(nullptr)
46 {
48  meshStatistics.refineAllEdges = false;
50 }
51 
53 {
54  for (auto ge : l_edges)
55  ge->delFace(this);
56 
58  delete va_geom_triangles;
59 
61 }
62 
64 {
65  if (meshAttributes.algorithm)
66  return meshAttributes.algorithm;
67  else
68  return CTX::instance()->mesh.algo2d;
69 }
70 
72 {
73  if (meshAttributes.meshSizeFromBoundary >= 0)
74  return meshAttributes.meshSizeFromBoundary;
75  else
77 }
78 
80 {
81  if (model()->getNumRegions())
82  return regions().empty();
83  return false;
84 }
85 
87 {
88  const auto found = std::find(l_edges.begin(), l_edges.end(), edge);
89 
90  if (found != l_edges.end())
91  {
92  l_edges.erase(found);
93  }
94 
95  const auto pos = std::distance(l_edges.begin(), found);
96 
97  if (l_dirs.empty())
98  {
99  return 0;
100  }
101 
102  if (l_dirs.size() < static_cast<std::size_t>(pos))
103  {
104  l_dirs.erase(std::prev(l_dirs.end()));
105  return 0;
106  }
107 
108  const auto orientation = l_dirs.at(pos);
109  l_dirs.erase(std::next(begin(l_dirs), pos));
110  return orientation;
111 }
112 
113 void GFace::setBoundEdges(const std::vector<int> &tagEdges)
114 {
115  std::vector<GEdge *> e;
116  for (std::size_t i = 0; i < tagEdges.size(); i++)
117  {
118  GEdge *ge = model()->getEdgeByTag(tagEdges[i]);
119  if (ge)
120  {
121  e.push_back(ge);
122  ge->addFace(this);
123  }
124  else
125  {
126  Msg::Error("Unknown curve %d in surface %d", tagEdges[i], tag());
127  }
128  }
129  GEdgeLoop el(e);
130  el.getEdges(l_edges);
131  el.getSigns(l_dirs);
132 }
133 
134 void GFace::setBoundEdges(const std::vector<int> &tagEdges, const std::vector<int> &signEdges)
135 {
136  if (signEdges.size() != tagEdges.size())
137  {
138  Msg::Error("Wrong number of curve signs in surface %d", tag());
139  setBoundEdges(tagEdges);
140  }
141  for (std::vector<int>::size_type i = 0; i < tagEdges.size(); i++)
142  {
143  GEdge *ge = model()->getEdgeByTag(tagEdges[i]);
144  if (ge)
145  {
146  if (std::find(l_edges.begin(), l_edges.end(), ge) == l_edges.end())
147  {
148  l_edges.push_back(ge);
149  l_dirs.push_back(signEdges[i]);
150  ge->addFace(this);
151  }
152  }
153  else
154  {
155  Msg::Error("Unknown curve %d in surface %d", tagEdges[i], tag());
156  }
157  }
158 }
159 
161 {
162  for (std::size_t i = 0; i < mesh_vertices.size(); i++)
163  delete mesh_vertices[i];
164  mesh_vertices.clear();
165  transfinite_vertices.clear();
166  for (std::size_t i = 0; i < triangles.size(); i++)
167  delete triangles[i];
168  triangles.clear();
169  for (std::size_t i = 0; i < quadrangles.size(); i++)
170  delete quadrangles[i];
171  quadrangles.clear();
172  for (std::size_t i = 0; i < polygons.size(); i++)
173  delete polygons[i];
174  polygons.clear();
175  correspondingVertices.clear();
179 }
180 
181 std::size_t GFace::getNumMeshElements() const
182 {
183  return triangles.size() + quadrangles.size() + polygons.size();
184 }
185 
186 std::size_t GFace::getNumMeshElementsByType(const int familyType) const
187 {
188  if (familyType == TYPE_TRI)
189  return triangles.size();
190  else if (familyType == TYPE_QUA)
191  return quadrangles.size();
192  else if (familyType == TYPE_POLYG)
193  return polygons.size();
194 
195  return 0;
196 }
197 
199 {
200  std::size_t n = 0;
201  for (std::size_t i = 0; i < polygons.size(); i++)
202  if (polygons[i]->ownsParent())
203  n++;
204  return n;
205 }
206 
207 void GFace::getNumMeshElements(unsigned *const c) const
208 {
209  c[0] += triangles.size();
210  c[1] += quadrangles.size();
211  c[2] += polygons.size();
212 }
213 
214 MElement *const *GFace::getStartElementType(int type) const
215 {
216  switch (type)
217  {
218  case 0:
219  if (triangles.empty())
220  return nullptr; // msvc would throw an exception
221  return reinterpret_cast<MElement *const *>(&triangles[0]);
222  case 1:
223  if (quadrangles.empty())
224  return nullptr; // msvc would throw an exception
225  return reinterpret_cast<MElement *const *>(&quadrangles[0]);
226  case 2:
227  if (polygons.empty())
228  return nullptr;
229  return reinterpret_cast<MElement *const *>(&polygons[0]);
230  }
231  return nullptr;
232 }
233 
234 MElement *GFace::getMeshElement(std::size_t index) const
235 {
236  if (index < triangles.size())
237  return triangles[index];
238  else if (index < triangles.size() + quadrangles.size())
239  return quadrangles[index - triangles.size()];
240  else if (index < triangles.size() + quadrangles.size() + polygons.size())
241  return polygons[index - triangles.size() - quadrangles.size()];
242  return nullptr;
243 }
244 
245 MElement *GFace::getMeshElementByType(const int familyType, const std::size_t index) const
246 {
247  if (familyType == TYPE_TRI)
248  return triangles[index];
249  else if (familyType == TYPE_QUA)
250  return quadrangles[index];
251  else if (familyType == TYPE_POLYG)
252  return polygons[index];
253 
254  return nullptr;
255 }
256 
258 {
259  meshAttributes.recombine = 0;
260  meshAttributes.recombineAngle = 45.;
262  meshAttributes.transfiniteArrangement = 0;
263  meshAttributes.transfiniteSmoothing = -1;
264  meshAttributes.extrude = nullptr;
265  meshAttributes.reverseMesh = false;
266  meshAttributes.meshSize = MAX_LC;
267  meshAttributes.meshSizeFactor = 1.;
268  meshAttributes.algorithm = 0;
269  meshAttributes.meshSizeFromBoundary = -1;
270  meshAttributes.transfinite3 = false;
271 }
272 
274 {
275  SBoundingBox3d res;
277  {
278  for (auto ge : l_edges)
279  {
280  res += ge->bounds(fast);
281  }
282  }
283  else
284  {
285  for (std::size_t i = 0; i < getNumMeshElements(); i++)
286  for (std::size_t j = 0; j < getMeshElement(i)->getNumVertices(); j++)
287  res += getMeshElement(i)->getVertex(j)->point();
288  }
289  return res;
290 }
291 
293 {
294  if (!_obb)
295  {
296  std::vector<SPoint3> vertices;
297  if (getNumMeshVertices() > 0)
298  {
299  int N = getNumMeshVertices();
300  for (int i = 0; i < N; i++)
301  {
302  MVertex *mv = getMeshVertex(i);
303  vertices.push_back(mv->point());
304  }
305  std::vector<GEdge *> const &eds = edges();
306  for (auto ed = eds.begin(); ed != eds.end(); ed++)
307  {
308  int N2 = (*ed)->getNumMeshVertices();
309  for (int i = 0; i < N2; i++)
310  {
311  MVertex *mv = (*ed)->getMeshVertex(i);
312  vertices.push_back(mv->point());
313  }
314  // Don't forget to add the first and last vertices...
315  if ((*ed)->getBeginVertex())
316  {
317  SPoint3 pt1((*ed)->getBeginVertex()->x(), (*ed)->getBeginVertex()->y(),
318  (*ed)->getBeginVertex()->z());
319  vertices.push_back(pt1);
320  }
321  if ((*ed)->getEndVertex())
322  {
323  SPoint3 pt2((*ed)->getEndVertex()->x(), (*ed)->getEndVertex()->y(), (*ed)->getEndVertex()->z());
324  vertices.push_back(pt2);
325  }
326  }
327  }
328  else if (buildSTLTriangulation())
329  {
331  }
332  else
333  {
334  // Fallback, if we can't make a STL triangulation of the surface, use its
335  // edges..
336  std::vector<GEdge *> const &b_edges = edges();
337  int N = 10;
338  for (auto b_edge = b_edges.begin(); b_edge != b_edges.end(); b_edge++)
339  {
340  Range<double> tr = (*b_edge)->parBounds(0);
341  for (int j = 0; j < N; j++)
342  {
343  double t = tr.low() + (double)j / (double)(N - 1) * (tr.high() - tr.low());
344  GPoint p = (*b_edge)->point(t);
345  SPoint3 pt(p.x(), p.y(), p.z());
346  vertices.push_back(pt);
347  }
348  }
349  }
351  }
352  return SOrientedBoundingBox(_obb);
353 }
354 
355 std::vector<GVertex *> GFace::getEmbeddedVertices(bool force) const
356 {
357  if (!force && compound.size())
358  return std::vector<GVertex *>();
359  return std::vector<GVertex *>(embedded_vertices.begin(), embedded_vertices.end());
360 }
361 
362 std::vector<GEdge *> GFace::getEmbeddedEdges(bool force) const
363 {
364  if (!force && compound.size())
365  return std::vector<GEdge *>();
366  return embedded_edges;
367 }
368 
369 std::vector<MVertex *> GFace::getEmbeddedMeshVertices(bool force) const
370 {
371  if (!force && compound.size())
372  return std::vector<MVertex *>();
373 
374  std::set<MVertex *> tmp;
375  for (auto it = embedded_edges.begin(); it != embedded_edges.end(); it++)
376  {
377  tmp.insert((*it)->mesh_vertices.begin(), (*it)->mesh_vertices.end());
378  if ((*it)->getBeginVertex())
379  tmp.insert((*it)->getBeginVertex()->mesh_vertices.begin(), (*it)->getBeginVertex()->mesh_vertices.end());
380  if ((*it)->getEndVertex())
381  tmp.insert((*it)->getEndVertex()->mesh_vertices.begin(), (*it)->getEndVertex()->mesh_vertices.end());
382  }
383  for (auto it = embedded_vertices.begin(); it != embedded_vertices.end(); it++)
384  {
385  tmp.insert((*it)->mesh_vertices.begin(), (*it)->mesh_vertices.end());
386  }
387  return std::vector<MVertex *>(tmp.begin(), tmp.end());
388 }
389 
390 std::vector<GVertex *> GFace::vertices() const
391 {
392  std::set<GVertex *, GEntityPtrLessThan> v;
393  for (auto ge : l_edges)
394  {
395  GVertex *const v1 = ge->getBeginVertex();
396  if (v1)
397  v.insert(v1);
398 
399  GVertex *const v2 = ge->getEndVertex();
400  if (v2)
401  v.insert(v2);
402  }
403  return std::vector<GVertex *>(v.begin(), v.end());
404 }
405 
406 void GFace::setVisibility(char val, bool recursive)
407 {
409  if (recursive)
410  {
411  for (auto e : l_edges)
412  e->setVisibility(val, recursive);
413  for (auto e : embedded_edges)
414  e->setVisibility(val, recursive);
415  for (auto v : embedded_vertices)
416  v->setVisibility(val);
417  }
418 }
419 
420 void GFace::setColor(unsigned int val, bool recursive)
421 {
422  GEntity::setColor(val);
423  if (recursive)
424  {
425  for (auto e : l_edges)
426  e->setColor(val, recursive);
427  for (auto e : embedded_edges)
428  e->setColor(val, recursive);
429  for (auto v : embedded_vertices)
430  v->setColor(val);
431  }
432 }
433 
434 std::string GFace::getAdditionalInfoString(bool multline)
435 {
436  std::ostringstream sstream;
437  if (l_edges.size() > 20)
438  {
439  sstream << "Boundary curves: " << l_edges.front()->tag() << ", ...," << l_edges.back()->tag();
440  if (multline)
441  sstream << "\n";
442  else
443  sstream << " ";
444  }
445  else if (l_edges.size())
446  {
447  sstream << "Boundary curves: ";
448  for (auto it = l_edges.begin(); it != l_edges.end(); ++it)
449  {
450  if (it != l_edges.begin())
451  sstream << ", ";
452  sstream << (*it)->tag();
453  }
454  if (multline)
455  sstream << "\n";
456  else
457  sstream << " ";
458  }
459 
460  if (r1 || r2)
461  {
462  sstream << "On boundary of volumes: ";
463  if (r1)
464  {
465  sstream << r1->tag();
466  if (r2)
467  sstream << ", ";
468  }
469  if (r2)
470  sstream << r2->tag();
471  if (multline)
472  sstream << "\n";
473  else
474  sstream << " ";
475  }
476 
477  if (embedded_edges.size())
478  {
479  sstream << "Embedded curves: ";
480  for (auto it = embedded_edges.begin(); it != embedded_edges.end(); ++it)
481  {
482  if (it != embedded_edges.begin())
483  sstream << ", ";
484  sstream << (*it)->tag();
485  }
486  if (multline)
487  sstream << "\n";
488  else
489  sstream << " ";
490  }
491 
492  if (embedded_vertices.size())
493  {
494  sstream << "Embedded points: ";
495  for (auto it = embedded_vertices.begin(); it != embedded_vertices.end(); ++it)
496  {
497  if (it != embedded_vertices.begin())
498  sstream << ", ";
499  sstream << (*it)->tag();
500  }
501  if (multline)
502  sstream << "\n";
503  else
504  sstream << " ";
505  }
506 
507  if (meshAttributes.recombine || meshAttributes.method == MESH_TRANSFINITE ||
508  (meshAttributes.extrude && meshAttributes.extrude->mesh.ExtrudeMesh) || meshAttributes.reverseMesh ||
509  (getMeshMaster() && getMeshMaster() != this))
510  {
511  sstream << "Mesh attributes:";
512  if (meshAttributes.recombine)
513  sstream << " recombined";
514  if (meshAttributes.method == MESH_TRANSFINITE)
515  sstream << " transfinite";
516  if (meshAttributes.extrude && meshAttributes.extrude->mesh.ExtrudeMesh)
517  sstream << " extruded";
518  if (meshAttributes.reverseMesh)
519  sstream << " reverse";
520  if (getMeshMaster() && getMeshMaster() != this)
521  sstream << " periodic copy of surface " << getMeshMaster()->tag();
522  }
523 
524  std::string str = sstream.str();
525  if (str.size() && (str[str.size() - 1] == '\n' || str[str.size() - 1] == ' '))
526  str.resize(str.size() - 1);
527  return str;
528 }
529 
530 void GFace::writeGEO(FILE *fp)
531 {
533  return;
534 
535  std::vector<GEdge *> const &edg = edges();
536  std::vector<int> const &dir = orientations();
537  if (edg.size() && dir.size() == edg.size())
538  {
539  std::vector<int> num, ori;
540  for (auto it = edg.begin(); it != edg.end(); it++)
541  num.push_back((*it)->tag());
542  for (auto it = dir.begin(); it != dir.end(); it++)
543  ori.push_back((*it) > 0 ? 1 : -1);
544  fprintf(fp, "Curve Loop(%d) = ", tag());
545  for (std::size_t i = 0; i < num.size(); i++)
546  {
547  if (i)
548  fprintf(fp, ", %d", num[i] * ori[i]);
549  else
550  fprintf(fp, "{%d", num[i] * ori[i]);
551  }
552  fprintf(fp, "};\n");
553  if (geomType() == GEntity::Plane)
554  {
555  fprintf(fp, "Plane Surface(%d) = {%d};\n", tag(), tag());
556  }
557  else if (edg.size() == 3 || edg.size() == 4)
558  {
559  fprintf(fp, "Surface(%d) = {%d};\n", tag(), tag());
560  }
561  else
562  {
563  Msg::Warning("Skipping surface %d in export", tag());
564  }
565  }
566 
567  for (auto it = embedded_edges.begin(); it != embedded_edges.end(); it++)
568  fprintf(fp, "Line {%d} In Surface {%d};\n", (*it)->tag(), tag());
569 
570  for (auto it = embedded_vertices.begin(); it != embedded_vertices.end(); it++)
571  fprintf(fp, "Point {%d} In Surface {%d};\n", (*it)->tag(), tag());
572 
573  if (meshAttributes.method == MESH_TRANSFINITE)
574  {
575  fprintf(fp, "Transfinite Surface {%d}", tag());
576  if (meshAttributes.corners.size())
577  {
578  fprintf(fp, " = {");
579  for (std::size_t i = 0; i < meshAttributes.corners.size(); i++)
580  {
581  if (i)
582  fprintf(fp, ",");
583  fprintf(fp, "%d", meshAttributes.corners[i]->tag());
584  }
585  fprintf(fp, "}");
586  }
587  fprintf(fp, ";\n");
588  }
589 
590  if (meshAttributes.recombine)
591  fprintf(fp, "Recombine Surface {%d};\n", tag());
592 
593  if (meshAttributes.reverseMesh)
594  fprintf(fp, "Reverse Surface {%d};\n", tag());
595 }
596 
597 void GFace::writePY(FILE *fp)
598 {
599  // This is by no means complete - merely a placeholder for a future
600  // implementation
601 
603  return;
604 
605  const char *factory = getNativeType() == OpenCascadeModel ? "occ" : "geo";
606 
607  std::size_t numcl = 0;
608  for (std::size_t i = 0; i < edgeLoops.size(); i++)
609  {
610  std::vector<GEdge *> edges;
611  std::vector<int> signs;
612  edgeLoops[i].getEdges(edges);
613  edgeLoops[i].getSigns(signs);
614  if (edges.size() && edges.size() == signs.size())
615  {
616  fprintf(fp, "s%d_cl%lu = gmsh.model.%s.addCurveLoop([", tag(), ++numcl, factory);
617  for (std::size_t j = 0; j < edges.size(); j++)
618  {
619  if (j)
620  fprintf(fp, ", ");
621  fprintf(fp, "%d", edges[j]->tag() * signs[j]);
622  }
623  fprintf(fp, "])\n");
624  }
625  }
626 
628  {
629  fprintf(fp, "gmsh.model.%s.addPlaneSurface([", factory);
630  for (std::size_t i = 0; i < numcl; i++)
631  {
632  if (i)
633  fprintf(fp, ", ");
634  fprintf(fp, "s%d_cl%lu", tag(), i + 1);
635  }
636  fprintf(fp, "], %d)\n", tag());
637  }
638  else
639  {
640  // TODO
641  Msg::Warning("Skipping surface %d in export", tag());
642  }
643 }
644 
646 {
647  std::vector<SPoint3> pts;
648 
649  if (geomType() == Plane)
650  {
651  // Special case for planar CAD surfaces: we first try to compute the
652  // parametrization in a way that is more robust with respect to
653  // perturbations of the boundary. This is crucial for sensitivity analyses
654  // and GFace::relocateMeshVertices(): after perturbation of the boundary, we
655  // want a parametrization of the surface that is "close" to the original
656  // one. If this fails, we fallback to the classical (SVD-based) algorithm.
657  std::vector<GEdge *> const &edg = edges();
658  for (auto e : edg)
659  {
660  if (e->geomType() == GEntity::DiscreteCurve || e->geomType() == GEntity::BoundaryLayerCurve)
661  {
662  pts.clear();
663  break;
664  }
665  Range<double> b = e->parBounds(0);
666  GPoint p1 = e->point(b.low() + 0.333 * (b.high() - b.low()));
667  pts.push_back(SPoint3(p1.x(), p1.y(), p1.z()));
668  GPoint p2 = e->point(b.low() + 0.666 * (b.high() - b.low()));
669  pts.push_back(SPoint3(p2.x(), p2.y(), p2.z()));
670  }
671  bool ok = false;
672  double res[4] = {0., 0., 0., 0.}, xm = 0., ym = 0., zm = 0.;
673  if (pts.size() >= 3)
674  {
675  SVector3 d01(pts[0], pts[1]);
676  for (std::size_t i = 2; i < pts.size(); i++)
677  {
678  SVector3 d0i(pts[0], pts[i]);
679  SVector3 n = crossprod(d01, d0i);
680  // if too small, the points are almost colinear; tolerance is relatively
681  // high so that we don't accept points on plane surfaces defined by
682  // lines that are not exactly co-planar
683  if (norm(n) > sqrt(CTX::instance()->geom.tolerance) * CTX::instance()->lc)
684  {
685  res[0] = n.x();
686  res[1] = n.y();
687  res[2] = n.z();
688  xm = pts[0].x();
689  ym = pts[0].y();
690  zm = pts[0].z();
691  ok = true;
692  break;
693  }
694  }
695  }
696  if (ok)
697  {
698  double ex[3], t1[3], t2[3];
699  ex[0] = ex[1] = ex[2] = 0.0;
700  if (res[0] == 0.)
701  ex[0] = 1.0;
702  else if (res[1] == 0.)
703  ex[1] = 1.0;
704  else
705  ex[2] = 1.0;
706  prodve(res, ex, t1);
707  norme(t1);
708  prodve(t1, res, t2);
709  norme(t2);
710  res[3] = (xm * res[0] + ym * res[1] + zm * res[2]);
711  fillMeanPlane(res, t1, t2, meanPlane);
712  return;
713  }
714  }
715 
716  std::vector<GVertex *> const &verts = vertices();
717  for (auto itv = verts.begin(); itv != verts.end(); itv++)
718  {
719  const GVertex *v = *itv;
720  pts.push_back(SPoint3(v->x(), v->y(), v->z()));
721  }
722 
723  bool colinear = (pts.size() < 3);
724  if (pts.size() > 2)
725  {
726  SVector3 d01(pts[0], pts[1]), d02(pts[0], pts[2]);
727  if (norm(crossprod(d01, d02)) < 1e-12)
728  colinear = true;
729  }
730 
731  if (colinear)
732  {
733  Msg::Debug("Adding curve points (%d) to compute mean plane of surface %d", pts.size(), tag());
734  std::vector<GEdge *> const &edg = edges();
735  for (auto e : edg)
736  {
737  if (e->mesh_vertices.size() > 1)
738  {
739  for (std::size_t i = 0; i < e->mesh_vertices.size(); i++)
740  pts.push_back(e->mesh_vertices[i]->point());
741  }
742  else
743  {
744  Range<double> b = e->parBounds(0);
745  GPoint p1 = e->point(b.low() + 0.333 * (b.high() - b.low()));
746  pts.push_back(SPoint3(p1.x(), p1.y(), p1.z()));
747  GPoint p2 = e->point(b.low() + 0.666 * (b.high() - b.low()));
748  pts.push_back(SPoint3(p2.x(), p2.y(), p2.z()));
749  }
750  }
751  }
752 
753  computeMeanPlane(pts);
754 }
755 
756 void GFace::computeMeanPlane(const std::vector<MVertex *> &points)
757 {
758  std::vector<SPoint3> pts;
759  for (std::size_t i = 0; i < points.size(); i++)
760  pts.push_back(SPoint3(points[i]->x(), points[i]->y(), points[i]->z()));
761  computeMeanPlane(pts);
762 }
763 
764 void GFace::computeMeanPlane(const std::vector<SPoint3> &points)
765 {
766  if (points.empty())
767  return;
768 
769  // The concept of a mean plane computed in the sense of least
770  // squares is fine for plane surfaces(!), but not really the best
771  // one for non-plane surfaces. Indeed, imagine a quarter of a circle
772  // extruded along a very small height: the mean plane will be in the
773  // plane of the circle... Until we implement something better, there
774  // is a test in this routine that checks the coherence of the
775  // computation for non-plane surfaces and reverts to a basic mean
776  // plane approximatation if the check fails.
777 
778  double xm = 0., ym = 0., zm = 0.;
779  int ndata = points.size();
780  int na = 3;
781  for (int i = 0; i < ndata; i++)
782  {
783  xm += points[i].x();
784  ym += points[i].y();
785  zm += points[i].z();
786  }
787  xm /= (double)ndata;
788  ym /= (double)ndata;
789  zm /= (double)ndata;
790 
791  fullMatrix<double> U(ndata, na), V(na, na);
792  fullVector<double> sigma(na);
793  for (int i = 0; i < ndata; i++)
794  {
795  U(i, 0) = points[i].x() - xm;
796  U(i, 1) = points[i].y() - ym;
797  U(i, 2) = points[i].z() - zm;
798  }
799  U.svd(V, sigma);
800  double res[4], svd[3];
801  svd[0] = sigma(0);
802  svd[1] = sigma(1);
803  svd[2] = sigma(2);
804  int min;
805  if (std::abs(svd[0]) < std::abs(svd[1]) && std::abs(svd[0]) < std::abs(svd[2]))
806  min = 0;
807  else if (std::abs(svd[1]) < std::abs(svd[0]) && std::abs(svd[1]) < std::abs(svd[2]))
808  min = 1;
809  else
810  min = 2;
811  res[0] = V(0, min);
812  res[1] = V(1, min);
813  res[2] = V(2, min);
814  norme(res);
815 
816  double ex[3], t1[3], t2[3];
817 
818  // check coherence of results for non-plane surfaces
820  {
821  double res2[3], c[3], sinc, angplan;
822  double eps = 1.e-3;
823 
824  GPoint v1 = point(0.5, 0.5);
825  GPoint v2 = point(0.5 + eps, 0.5);
826  GPoint v3 = point(0.5, 0.5 + eps);
827  t1[0] = v2.x() - v1.x();
828  t1[1] = v2.y() - v1.y();
829  t1[2] = v2.z() - v1.z();
830  t2[0] = v3.x() - v1.x();
831  t2[1] = v3.y() - v1.y();
832  t2[2] = v3.z() - v1.z();
833  norme(t1);
834  norme(t2);
835  // prodve(t1, t2, res2);
836  // WARNING: the rest of the code assumes res = t2 x t1, not t1 x t2 (WTF?)
837  prodve(t2, t1, res2);
838  norme(res2);
839 
840  prodve(res, res2, c);
841  double const cosc = prosca(res, res2);
842  sinc = std::sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]);
843  angplan = myatan2(sinc, cosc);
844  angplan = angle_02pi(angplan) * 180. / M_PI;
845  if ((angplan > 70 && angplan < 110) || (angplan > 260 && angplan < 280))
846  {
847  Msg::Info("SVD failed (angle=%g): using rough algo...", angplan);
848  res[0] = res2[0];
849  res[1] = res2[1];
850  res[2] = res2[2];
851  goto end;
852  }
853  }
854 
855  ex[0] = ex[1] = ex[2] = 0.0;
856  if (res[0] == 0.)
857  ex[0] = 1.0;
858  else if (res[1] == 0.)
859  ex[1] = 1.0;
860  else
861  ex[2] = 1.0;
862 
863  prodve(res, ex, t1);
864  norme(t1);
865  prodve(t1, res, t2);
866  norme(t2);
867 
868 end:
869  res[3] = (xm * res[0] + ym * res[1] + zm * res[2]);
870 
871  fillMeanPlane(res, t1, t2, meanPlane);
872 
873  Msg::Debug("Surface: %d", tag());
874  Msg::Debug("SVD : %g,%g,%g (min=%d)", svd[0], svd[1], svd[2], min);
875  Msg::Debug("Plane : (%g x + %g y + %g z = %g)", meanPlane.a, meanPlane.b, meanPlane.c, meanPlane.d);
876  Msg::Debug("Normal : (%g , %g , %g )", meanPlane.a, meanPlane.b, meanPlane.c);
877  Msg::Debug("t1 : (%g , %g , %g )", t1[0], t1[1], t1[2]);
878  Msg::Debug("t2 : (%g , %g , %g )", t2[0], t2[1], t2[2]);
879  Msg::Debug("pt : (%g , %g , %g )", meanPlane.x, meanPlane.y, meanPlane.z);
880 
881  // check coherence for plane surfaces
882  if (geomType() == Plane)
883  {
884  SBoundingBox3d bb = bounds();
885  double lc = norm(SVector3(bb.max(), bb.min()));
886  std::vector<GVertex *> const &verts = vertices();
887  for (auto itv = verts.begin(); itv != verts.end(); itv++)
888  {
889  const GVertex *v = *itv;
890  double const d = meanPlane.a * v->x() + meanPlane.b * v->y() + meanPlane.c * v->z() - meanPlane.d;
891  if (std::abs(d) > lc * 1.e-3)
892  {
893  Msg::Debug("Plane surface %d (%gx+%gy+%gz=%g) is not plane!", tag(), meanPlane.a, meanPlane.b,
895  Msg::Debug("Control point %d = (%g,%g,%g), val=%g", v->tag(), v->x(), v->y(), v->z(), d);
896  break;
897  }
898  }
899  }
900 }
901 
902 void GFace::getMeanPlaneData(double VX[3], double VY[3], double &x, double &y, double &z) const
903 {
904  VX[0] = meanPlane.plan[0][0];
905  VX[1] = meanPlane.plan[0][1];
906  VX[2] = meanPlane.plan[0][2];
907  VY[0] = meanPlane.plan[1][0];
908  VY[1] = meanPlane.plan[1][1];
909  VY[2] = meanPlane.plan[1][2];
910  x = meanPlane.x;
911  y = meanPlane.y;
912  z = meanPlane.z;
913 }
914 
915 void GFace::getMeanPlaneData(double plan[3][3]) const
916 {
917  for (int i = 0; i < 3; i++)
918  for (int j = 0; j < 3; j++)
919  plan[i][j] = meanPlane.plan[i][j];
920 }
921 
922 void GFace::computeMeshSizeFieldAccuracy(double &avg, double &max_e, double &min_e, int &nE, int &GS)
923 {
924 #if defined(HAVE_MESH)
925  std::set<MEdge, MEdgeLessThan> es;
926  for (std::size_t i = 0; i < getNumMeshElements(); i++)
927  {
928  MElement *e = getMeshElement(i);
929  for (int j = 0; j < e->getNumEdges(); j++)
930  es.insert(e->getEdge(j));
931  }
932 
933  avg = 0;
934  min_e = 1.e22;
935  max_e = 0;
936  nE = es.size();
937  GS = 0;
938  double oneoversqr2 = 1. / sqrt(2.);
939  double sqr2 = sqrt(2.);
940  for (auto it = es.begin(); it != es.end(); ++it)
941  {
942  double u1, v1, u2, v2;
943  MVertex *vert1 = it->getVertex(0);
944  vert1->getParameter(0, u1);
945  vert1->getParameter(1, v1);
946  MVertex *vert2 = it->getVertex(1);
947  vert2->getParameter(0, u2);
948  vert2->getParameter(1, v2);
949  double l1 = BGM_MeshSize(this, u1, v1, vert1->x(), vert1->y(), vert1->z());
950  double l2 = BGM_MeshSize(this, u2, v2, vert2->x(), vert2->y(), vert2->z());
951  double correctLC = 0.5 * (l1 + l2);
952  double lone = it->length() / correctLC;
953  if (lone > oneoversqr2 && lone < sqr2)
954  GS++;
955  avg += lone > 1 ? (1. / lone) - 1. : lone - 1.;
956  max_e = std::max(max_e, lone);
957  min_e = std::min(min_e, lone);
958  }
959 #endif
960 }
961 
962 double GFace::curvatureDiv(const SPoint2 &param) const
963 {
964  if (geomType() == Plane || geomType() == BoundaryLayerSurface)
965  return 0;
966 
967  // X=X(u,v) Y=Y(u,v) Z=Z(u,v)
968  // curv = div n = dnx/dx + dny/dy + dnz/dz
969  // dnx/dx = dnx/du du/dx + dnx/dv dv/dx
970 
971  const double eps = 1.e-5;
972 
973  Pair<SVector3, SVector3> der = firstDer(param);
974 
975  SVector3 du = der.first();
976  SVector3 dv = der.second();
977  SVector3 nml = crossprod(du, dv);
978 
979  double detJ = norm(nml);
980 
981  du.normalize();
982  dv.normalize();
983 
984  SVector3 n1, n2, n3, n4;
985  if (param.x() - eps < 0.0)
986  {
987  n1 = normal(SPoint2(param.x(), param.y()));
988  n2 = normal(SPoint2(param.x() + eps, param.y()));
989  }
990  else
991  {
992  n1 = normal(SPoint2(param.x() - eps, param.y()));
993  n2 = normal(SPoint2(param.x(), param.y()));
994  }
995  if (param.y() - eps < 0.0)
996  {
997  n3 = normal(SPoint2(param.x(), param.y()));
998  n4 = normal(SPoint2(param.x(), param.y() + eps));
999  }
1000  else
1001  {
1002  n3 = normal(SPoint2(param.x(), param.y() - eps));
1003  n4 = normal(SPoint2(param.x(), param.y()));
1004  }
1005 
1006  SVector3 dndu = 100000 * (n2 - n1);
1007  SVector3 dndv = 100000 * (n4 - n3);
1008 
1009  SVector3 dudu = SVector3();
1010  SVector3 dvdv = SVector3();
1011  SVector3 dudv = SVector3();
1012  secondDer(param, dudu, dvdv, dudv);
1013 
1014  double ddu = dot(dndu, du);
1015  double ddv = dot(dndv, dv);
1016 
1017  return (fabs(ddu) + fabs(ddv)) / detJ;
1018 }
1019 
1020 double GFace::curvatureMax(const SPoint2 &param) const
1021 {
1022  if (geomType() == Plane || geomType() == BoundaryLayerSurface)
1023  return 0.;
1024 
1025  double eigVal[2], eigVec[8];
1026  getMetricEigenVectors(param, eigVal, eigVec);
1027 
1028  return fabs(eigVal[1]);
1029 }
1030 
1031 double GFace::curvatures(const SPoint2 &param, SVector3 &dirMax, SVector3 &dirMin, double &curvMax,
1032  double &curvMin) const
1033 {
1034  Pair<SVector3, SVector3> D1 = firstDer(param);
1035 
1036  if (geomType() == Plane || geomType() == BoundaryLayerSurface)
1037  {
1038  dirMax = D1.first();
1039  dirMin = D1.second();
1040  curvMax = 0.;
1041  curvMin = 0.;
1042  return 0.;
1043  }
1044 
1045  if (geomType() == Sphere)
1046  {
1047  dirMax = D1.first();
1048  dirMin = D1.second();
1049  curvMax = curvatureDiv(param);
1050  curvMin = curvMax;
1051  return curvMax;
1052  }
1053 
1054  double eigVal[2], eigVec[8];
1055  getMetricEigenVectors(param, eigVal, eigVec);
1056 
1057  // curvatures and main directions
1058  curvMax = fabs(eigVal[1]);
1059  curvMin = fabs(eigVal[0]);
1060  dirMax = eigVec[1] * D1.first() + eigVec[3] * D1.second();
1061  dirMin = eigVec[0] * D1.first() + eigVec[2] * D1.second();
1062 
1063  return curvMax;
1064 }
1065 
1067 {
1068  Msg::Error("Metric eigenvalue is not implemented for this type of surface");
1069  return 0.;
1070 }
1071 
1072 // eigen values are absolute values and sorted from min to max of absolute
1073 // values eigen vectors are the corresponding COLUMNS of eigVec
1074 void GFace::getMetricEigenVectors(const SPoint2 &param, double eigVal[2], double eigVec[4]) const
1075 {
1076  // first derivatives
1077  Pair<SVector3, SVector3> D1 = firstDer(param);
1078  SVector3 du = D1.first();
1079  SVector3 dv = D1.second();
1080  SVector3 nor = crossprod(du, dv);
1081  nor.normalize();
1082 
1083  // second derivatives
1084  SVector3 dudu = SVector3();
1085  SVector3 dvdv = SVector3();
1086  SVector3 dudv = SVector3();
1087  secondDer(param, dudu, dvdv, dudv);
1088 
1089  // first form
1090  double form1[2][2];
1091  form1[0][0] = normSq(du);
1092  form1[1][1] = normSq(dv);
1093  form1[0][1] = form1[1][0] = dot(du, dv);
1094 
1095  // second form
1096  double form2[2][2];
1097  form2[0][0] = dot(nor, dudu);
1098  form2[1][1] = dot(nor, dvdv);
1099  form2[0][1] = form2[1][0] = dot(nor, dudv);
1100 
1101  // inverse of first form
1102  double inv_form1[2][2];
1103  double denom = (form1[0][0] * form1[1][1] - form1[1][0] * form1[0][1]);
1104  if (denom)
1105  {
1106  double inv_det_form1 = 1. / denom;
1107  inv_form1[0][0] = inv_det_form1 * form1[1][1];
1108  inv_form1[1][1] = inv_det_form1 * form1[0][0];
1109  inv_form1[1][0] = inv_form1[0][1] = -1 * inv_det_form1 * form1[0][1];
1110 
1111  // N = (inverse of form1) X (form2)
1112  fullMatrix<double> N(2, 2);
1113  N(0, 0) = inv_form1[0][0] * form2[0][0] + inv_form1[0][1] * form2[1][0];
1114  N(0, 1) = inv_form1[0][0] * form2[0][1] + inv_form1[0][1] * form2[1][1];
1115  N(1, 0) = inv_form1[1][0] * form2[0][0] + inv_form1[1][1] * form2[1][0];
1116  N(1, 1) = inv_form1[1][0] * form2[0][1] + inv_form1[1][1] * form2[1][1];
1117 
1118  // eigen values and vectors of N
1119  fullMatrix<double> vl(2, 2), vr(2, 2);
1120  fullVector<double> dr(2), di(2);
1121  if (N.eig(dr, di, vl, vr, true))
1122  {
1123  eigVal[0] = fabs(dr(0));
1124  eigVal[1] = fabs(dr(1));
1125  eigVec[0] = vr(0, 0);
1126  eigVec[2] = vr(1, 0);
1127  eigVec[1] = vr(0, 1);
1128  eigVec[3] = vr(1, 1);
1129  if (fabs(di(0)) > 1.e-12 || fabs(di(1)) > 1.e-12)
1130  {
1131  Msg::Warning("Imaginary eigenvalues in metric");
1132  }
1133  return;
1134  }
1135  }
1136 
1137  Msg::Warning("Could not compute metric eigenvectors");
1138  for (int i = 0; i < 2; i++)
1139  eigVal[i] = 0.;
1140  for (int i = 0; i < 4; i++)
1141  eigVec[i] = 0.;
1142 }
1143 
1144 void GFace::XYZtoUV(double X, double Y, double Z, double &U, double &V, double relax, bool onSurface,
1145  bool convTestXYZ) const
1146 {
1147  if (geomType() == BoundaryLayerSurface)
1148  return;
1149 
1150  const double Precision = onSurface ? 1.e-8 : 1.e-3;
1151  const int MaxIter = onSurface ? 25 : 10;
1152  const int NumInitGuess = 9;
1153  bool testXYZ = (convTestXYZ || CTX::instance()->mesh.NewtonConvergenceTestXYZ);
1154 
1155  double Unew = 0., Vnew = 0., err, err2;
1156  int iter;
1157  double mat[3][3], jac[3][3];
1158  double umin, umax, vmin, vmax;
1159  // don't use 0.9, 0.1 it fails with ruled surfaces
1160  double initu[NumInitGuess] = {0.5, 0.6, 0.4, 0.7, 0.3, 0.8, 0.2, 1.0, 0.0};
1161  double initv[NumInitGuess] = {0.5, 0.6, 0.4, 0.7, 0.3, 0.8, 0.2, 1.0, 0.0};
1162 
1163  Range<double> ru = parBounds(0);
1164  Range<double> rv = parBounds(1);
1165  umin = ru.low();
1166  umax = ru.high();
1167  vmin = rv.low();
1168  vmax = rv.high();
1169 
1170  const double tol = Precision * (std::pow(umax - umin, 2) + std::pow(vmax - vmin, 2));
1171  for (int i = 0; i < NumInitGuess; i++)
1172  {
1173  initu[i] = umin + initu[i] * (umax - umin);
1174  initv[i] = vmin + initv[i] * (vmax - vmin);
1175  }
1176 
1177  for (int i = 0; i < NumInitGuess; i++)
1178  {
1179  for (int j = 0; j < NumInitGuess; j++)
1180  {
1181  U = initu[i];
1182  V = initv[j];
1183  err = 1.0;
1184  iter = 1;
1185 
1186  GPoint P = point(U, V);
1187  err2 = std::sqrt(std::pow(X - P.x(), 2) + std::pow(Y - P.y(), 2) + std::pow(Z - P.z(), 2));
1188  if (err2 < 1.e-8 * CTX::instance()->lc)
1189  return;
1190 
1191  while (err > tol && iter < MaxIter)
1192  {
1193  P = point(U, V);
1195  mat[0][0] = der.left().x();
1196  mat[0][1] = der.left().y();
1197  mat[0][2] = der.left().z();
1198  mat[1][0] = der.right().x();
1199  mat[1][1] = der.right().y();
1200  mat[1][2] = der.right().z();
1201  mat[2][0] = 0.;
1202  mat[2][1] = 0.;
1203  mat[2][2] = 0.;
1204  invert_singular_matrix3x3(mat, jac);
1205 
1206  Unew = U + relax * (jac[0][0] * (X - P.x()) + jac[1][0] * (Y - P.y()) + jac[2][0] * (Z - P.z()));
1207  Vnew = V + relax * (jac[0][1] * (X - P.x()) + jac[1][1] * (Y - P.y()) + jac[2][1] * (Z - P.z()));
1208 
1209  // don't remove this test: it is important
1210  if ((Unew > umax + tol || Unew < umin - tol) && (Vnew > vmax + tol || Vnew < vmin - tol))
1211  break;
1212 
1213  err = std::pow(Unew - U, 2) + std::pow(Vnew - V, 2);
1214  err2 = std::sqrt(std::pow(X - P.x(), 2) + std::pow(Y - P.y(), 2) + std::pow(Z - P.z(), 2));
1215 
1216  iter++;
1217  U = Unew;
1218  V = Vnew;
1219  }
1220 
1221  if (iter < MaxIter && err <= tol && Unew <= umax && Vnew <= vmax && Unew >= umin && Vnew >= vmin)
1222  {
1223  if (onSurface && err2 > 1.e-4 * CTX::instance()->lc && !testXYZ)
1224  {
1225  Msg::Warning("Converged at iter. %d for initial guess (%d,%d) "
1226  "with uv error = %g, but xyz error = %g in point "
1227  "(%e, %e, %e) on surface %d",
1228  iter, i, j, err, err2, X, Y, Z, tag());
1229  }
1230  if (onSurface && err2 > 1.e-4 * CTX::instance()->lc && testXYZ)
1231  {
1232  // not converged in XYZ coordinates: try again
1233  }
1234  else
1235  {
1236  return;
1237  }
1238  }
1239  }
1240  }
1241 
1242  if (!onSurface)
1243  return;
1244 
1245  if (relax < 1.e-3)
1246  Msg::Warning("Inverse surface mapping could not converge");
1247  else
1248  {
1249  Msg::Info("Point %g %g %g: Relaxation factor = %g", X, Y, Z, 0.75 * relax);
1250  XYZtoUV(X, Y, Z, U, V, 0.75 * relax, onSurface, convTestXYZ);
1251  }
1252 }
1253 
1254 SPoint2 GFace::parFromPoint(const SPoint3 &p, bool onSurface, bool convTestXYZ) const
1255 {
1256  if (geomType() == BoundaryLayerSurface)
1257  return SPoint2();
1258 
1259  double U = 0., V = 0.;
1260  XYZtoUV(p.x(), p.y(), p.z(), U, V, 1.0, onSurface, convTestXYZ);
1261  return SPoint2(U, V);
1262 }
1263 
1264 #if defined(HAVE_ALGLIB)
1265 
1266 class data_wrapper
1267 {
1268  private:
1269  const GFace *gf;
1270  SPoint3 point;
1271 
1272  public:
1273  data_wrapper()
1274  {
1275  gf = nullptr;
1276  point = SPoint3();
1277  }
1278  ~data_wrapper()
1279  {
1280  }
1281  const GFace *get_face()
1282  {
1283  return gf;
1284  }
1285  void set_face(const GFace *face)
1286  {
1287  gf = face;
1288  }
1289  SPoint3 get_point()
1290  {
1291  return point;
1292  }
1293  void set_point(const SPoint3 &_point)
1294  {
1295  point = SPoint3(_point);
1296  }
1297 };
1298 
1299 // Callback function for ALGLIB
1300 void bfgs_callback(const alglib::real_1d_array &x, double &func, alglib::real_1d_array &grad, void *ptr)
1301 {
1302  auto *w = static_cast<data_wrapper *>(ptr);
1303  SPoint3 p = w->get_point();
1304  const GFace *gf = w->get_face();
1305 
1306  // Value of the objective
1307  GPoint pnt = gf->point(x[0], x[1]);
1308  func = 0.5 * (p.x() - pnt.x()) * (p.x() - pnt.x()) + (p.y() - pnt.y()) * (p.y() - pnt.y()) +
1309  (p.z() - pnt.z()) * (p.z() - pnt.z());
1310  // printf("func : %f\n", func);
1311 
1312  // Value of the gradient
1313  Pair<SVector3, SVector3> der = gf->firstDer(SPoint2(x[0], x[1]));
1314  grad[0] =
1315  -(p.x() - pnt.x()) * der.left().x() - (p.y() - pnt.y()) * der.left().y() - (p.z() - pnt.z()) * der.left().z();
1316  grad[1] = -(p.x() - pnt.x()) * der.right().x() - (p.y() - pnt.y()) * der.right().y() -
1317  (p.z() - pnt.z()) * der.right().z();
1318  // printf("func %22.15E Gradients %22.15E %22.15E der %g %g %g\n", func,
1319  // grad[0], grad[1],der.left().x(),der.left().y(),der.left().z());
1320 }
1321 #endif
1322 
1323 GPoint GFace::closestPoint(const SPoint3 &queryPoint, const double initialGuess[2]) const
1324 {
1325  if (geomType() == BoundaryLayerSurface)
1326  return GPoint();
1327 
1328 #if defined(HAVE_ALGLIB)
1329  // Test initial guess
1330  double min_u = initialGuess[0];
1331  double min_v = initialGuess[1];
1332  GPoint pnt = point(min_u, min_v);
1333  SPoint3 spnt(pnt.x(), pnt.y(), pnt.z());
1334  double min_dist = queryPoint.distance(spnt);
1335 
1336  // Try to find a better initial guess by sampling full parameter range
1337  const double nGuesses = 10.;
1338  const Range<double> uu = parBounds(0);
1339  const Range<double> vv = parBounds(1);
1340  const double ru = uu.high() - uu.low(), rv = vv.high() - vv.low();
1341  const double epsU = 1e-5 * ru, epsV = 1e-5 * rv;
1342  const double du = ru / nGuesses, dv = rv / nGuesses;
1343  for (double u = uu.low(); u <= uu.high() + epsU; u += du)
1344  {
1345  for (double v = vv.low(); v <= vv.high() + epsV; v += dv)
1346  {
1347  GPoint pnt = point(u, v);
1348  SPoint3 spnt(pnt.x(), pnt.y(), pnt.z());
1349  double dist = queryPoint.distance(spnt);
1350  if (dist < min_dist)
1351  {
1352  min_dist = dist;
1353  min_u = u;
1354  min_v = v;
1355  }
1356  }
1357  }
1358 
1359  try
1360  {
1361  // Set up optimisation problem
1362  alglib::ae_int_t dim = 2;
1363  alglib::ae_int_t corr = 2; // Num of corrections in the scheme in [3,7]
1364  alglib::minlbfgsstate state;
1365  alglib::real_1d_array x;
1366  const double initialCond[2] = {min_u, min_v};
1367  x.setcontent(dim, initialCond);
1368  minlbfgscreate(2, corr, x, state);
1369 
1370  // Set stopping criteria
1371  const double epsg = 1.e-12;
1372  const double epsf = 0.;
1373  const double epsx = 0.;
1374  const alglib::ae_int_t maxits = 500;
1375  minlbfgssetcond(state, epsg, epsf, epsx, maxits);
1376 
1377  // Solve problem
1378  data_wrapper w;
1379  w.set_point(queryPoint);
1380  w.set_face(this);
1381  minlbfgsoptimize(state, bfgs_callback, nullptr, &w);
1382 
1383  // Get results
1384  alglib::minlbfgsreport rep;
1385  minlbfgsresults(state, x, rep);
1386  GPoint pntF = point(x[0], x[1]);
1387  return pntF;
1388  }
1389  catch (...)
1390  {
1391  Msg::Warning("Closest point failed, computing from parametric coordinate");
1392  SPoint2 p = parFromPoint(queryPoint, false);
1393  return point(p);
1394  }
1395 
1396 #else
1397  Msg::Error("Closest point not implemented for this type of surface");
1398  SPoint2 p = parFromPoint(queryPoint, false);
1399  return point(p);
1400 #endif
1401 }
1402 
1404 {
1405  if (geomType() == BoundaryLayerSurface)
1406  return false;
1407 
1408  Range<double> uu = parBounds(0);
1409  Range<double> vv = parBounds(1);
1410  if ((pt.x() >= uu.low() && pt.x() <= uu.high()) && (pt.y() >= vv.low() && pt.y() <= vv.high()))
1411  return true;
1412  else
1413  return false;
1414 }
1415 
1416 SVector3 GFace::normal(const SPoint2 &param) const
1417 {
1418  if (geomType() == BoundaryLayerSurface)
1419  return SVector3();
1420 
1421  Pair<SVector3, SVector3> der = firstDer(param);
1422  SVector3 n = crossprod(der.first(), der.second());
1423  n.normalize();
1424  return n;
1425 }
1426 
1428 {
1429  if (cross[0].size())
1430  {
1431  if (force)
1432  {
1433  cross[0].clear();
1434  cross[1].clear();
1435  }
1436  else
1437  return true;
1438  }
1439 
1441  {
1442  // TODO if the surface has been reparametrized
1443  if (cross[0].empty())
1444  {
1445  cross[0].push_back(std::vector<SPoint3>());
1446  cross[0][0].push_back(bounds().center());
1447  }
1448  return false;
1449  }
1450 
1451  Range<double> ubounds = parBounds(0);
1452  Range<double> vbounds = parBounds(1);
1453  // try to compute something better for Gmsh surfaces
1454  if (getNativeType() == GmshModel && geomType() == Plane)
1455  {
1456  SBoundingBox3d bb;
1457  std::vector<GEdge *> ed = edges();
1458  for (auto it = ed.begin(); it != ed.end(); it++)
1459  {
1460  GEdge *ge = *it;
1461  if (ge->geomType() != DiscreteCurve && ge->geomType() != BoundaryLayerCurve)
1462  {
1463  Range<double> t_bounds = ge->parBounds(0);
1464  const int N = 5;
1465  double t0 = t_bounds.low(), dt = t_bounds.high() - t_bounds.low();
1466  for (int i = 0; i < N; i++)
1467  {
1468  double t = t0 + dt / (double)(N - 1) * i;
1469  GPoint p = ge->point(t);
1470  SPoint2 uv = parFromPoint(SPoint3(p.x(), p.y(), p.z()));
1471  bb += SPoint3(uv.x(), uv.y(), 0.);
1472  }
1473  }
1474  }
1475  if (!bb.empty())
1476  {
1477  ubounds = Range<double>(bb.min().x(), bb.max().x());
1478  vbounds = Range<double>(bb.min().y(), bb.max().y());
1479  }
1480  }
1481 
1482  bool tri = (geomType() == RuledSurface && getNativeType() == GmshModel && edges().size() == 3 &&
1484  double tol = 1e-8;
1485  double ud = (ubounds.high() - ubounds.low()) - 2 * tol;
1486  double vd = (vbounds.high() - vbounds.low()) - 2 * tol;
1487  double u2 = 0.5 * (ubounds.high() + ubounds.low());
1488  double v2 = 0.5 * (vbounds.high() + vbounds.low());
1489  int N = 100;
1490  for (int dir = 0; dir < 2; dir++)
1491  {
1492  cross[dir].push_back(std::vector<SPoint3>());
1493  for (int i = 0; i < N; i++)
1494  {
1495  double t = (double)i / (double)(N - 1);
1496  SPoint2 uv;
1497  if (!dir)
1498  {
1499  if (tri)
1500  uv.setPosition(u2 + u2 * t, vbounds.low() + tol + v2 * t);
1501  else
1502  uv.setPosition(ubounds.low() + tol + ud * t, v2);
1503  }
1504  else
1505  {
1506  if (tri)
1507  uv.setPosition(u2 + u2 * t, v2 - v2 * t);
1508  else
1509  uv.setPosition(u2, vbounds.low() + tol + vd * t);
1510  }
1511  GPoint p = point(uv);
1512  SPoint3 pt(p.x(), p.y(), p.z());
1513  bool inside = (geomType() == Plane) ? containsPoint(pt) : containsParam(uv);
1514  if (inside)
1515  {
1516  cross[dir].back().push_back(pt);
1517  }
1518  else
1519  {
1520  if (cross[dir].back().size())
1521  cross[dir].push_back(std::vector<SPoint3>());
1522  }
1523  }
1524  while (!cross[dir].empty() && cross[dir].back().empty())
1525  cross[dir].pop_back();
1526  }
1527 
1528  // draw additional small diamonds for plane surfaces, to make it easier to
1529  // select overlapping surfaces placed such that their crosses fully overlap
1530  // (e.g. when creating a hole centered in the middle of a surface, something
1531  // that happens quite often in practice)
1532  if (geomType() == Plane)
1533  {
1534  if (cross[0].size() > 0 && cross[0][0].size() > 1 && cross[1].size() > 0 && cross[1][0].size() > 1)
1535  {
1536  SVector3 v0(cross[0][0][0], cross[0][0][1]);
1537  SVector3 v1(cross[1][0][0], cross[1][0][1]);
1538  double l0 = v0.normalize();
1539  double l1 = v1.normalize();
1540  SPoint3 p[4] = {cross[0].front().front(), cross[0].back().back(), cross[1].front().front(),
1541  cross[1].back().back()};
1542  SVector3 vt[4] = {v0, -v0, v1, -v1};
1543  SVector3 vp[4] = {v1, -v1, v0, -v0};
1544  double l[4] = {l0, l0, l1, l1};
1545  for (int s = 0; s < 4; s++)
1546  {
1547  SPoint3 p0 = p[s];
1548  SPoint3 p1 = p0 + l[s] * vt[s];
1549  SPoint3 p2 = p1 + l[s] * vt[s] + l[s] * vp[s];
1550  SPoint3 p3 = p1 + 2 * l[s] * vt[s];
1551  SPoint3 p4 = p1 + l[s] * vt[s] - l[s] * vp[s];
1552  if (containsPoint(p1) && containsPoint(p3))
1553  {
1554  if (containsPoint(p2))
1555  {
1556  std::vector<SPoint3> c1 = {p1, p2};
1557  std::vector<SPoint3> c2 = {p2, p3};
1558  cross[0].push_back(c1);
1559  cross[0].push_back(c2);
1560  }
1561  if (containsPoint(p4))
1562  {
1563  std::vector<SPoint3> c1 = {p1, p4};
1564  std::vector<SPoint3> c2 = {p4, p3};
1565  cross[0].push_back(c1);
1566  cross[0].push_back(c2);
1567  }
1568  }
1569  }
1570  }
1571  }
1572 
1573  // if we couldn't determine a cross, add a single point (center of the
1574  // bounding box) so that we won't try again unless we force the recomputation,
1575  // but we will still have a point to draw e.g. the label
1576  if (cross[0].empty())
1577  {
1578  cross[0].push_back(std::vector<SPoint3>());
1579  cross[0][0].push_back(bounds().center());
1580  return false;
1581  }
1582  return true;
1583 }
1584 
1586 {
1587  if (stl_triangles.size() && !force)
1588  return true;
1589 
1590  stl_vertices_uv.clear();
1591  stl_vertices_xyz.clear();
1592  stl_triangles.clear();
1593 
1594  if (triangles.size())
1595  {
1596  // if a mesh exists, import it as the STL representation
1597  std::map<MVertex *, int, MVertexPtrLessThan> nodes;
1598  for (std::size_t i = 0; i < triangles.size(); i++)
1599  {
1600  for (int j = 0; j < 3; j++)
1601  {
1602  MVertex *v = triangles[i]->getVertex(j);
1603  if (!nodes.count(v))
1604  {
1605  stl_vertices_xyz.push_back(SPoint3(v->x(), v->y(), v->z()));
1606  nodes[v] = stl_vertices_xyz.size() - 1;
1607  }
1608  }
1609  }
1610  for (std::size_t i = 0; i < triangles.size(); i++)
1611  {
1612  for (int j = 0; j < 3; j++)
1613  {
1614  stl_triangles.push_back(nodes[triangles[i]->getVertex(j)]);
1615  }
1616  }
1617  return true;
1618  }
1619  else if (geomType() == ParametricSurface)
1620  {
1621  // build a simple triangulation for surfaces which we know are not trimmed
1622  const int nu = 64, nv = 64;
1623  Range<double> ubounds = parBounds(0);
1624  Range<double> vbounds = parBounds(1);
1625  double umin = ubounds.low(), umax = ubounds.high();
1626  double vmin = vbounds.low(), vmax = vbounds.high();
1627  for (int i = 0; i < nu; i++)
1628  {
1629  for (int j = 0; j < nv; j++)
1630  {
1631  double u = umin + (double)i / (double)(nu - 1) * (umax - umin);
1632  double v = vmin + (double)j / (double)(nv - 1) * (vmax - vmin);
1633  stl_vertices_uv.push_back(SPoint2(u, v));
1634  GPoint gp = point(u, v);
1635  stl_vertices_xyz.push_back(SPoint3(gp.x(), gp.y(), gp.z()));
1636  }
1637  }
1638  for (int i = 0; i < nu - 1; i++)
1639  {
1640  for (int j = 0; j < nv - 1; j++)
1641  {
1642  stl_triangles.push_back(i * nv + j);
1643  stl_triangles.push_back((i + 1) * nv + j);
1644  stl_triangles.push_back((i + 1) * nv + j + 1);
1645  stl_triangles.push_back(i * nv + j);
1646  stl_triangles.push_back((i + 1) * nv + j + 1);
1647  stl_triangles.push_back(i * nv + j + 1);
1648  }
1649  }
1650  return true;
1651  }
1652 
1653  return false;
1654 }
1655 
1656 bool GFace::fillVertexArray(bool force)
1657 {
1658  if (va_geom_triangles)
1659  {
1660  if (force)
1661  delete va_geom_triangles;
1662  else
1663  return true;
1664  }
1665 
1666  if (!buildSTLTriangulation(force))
1667  return false;
1668  if (stl_triangles.empty())
1669  return false;
1670 
1671  va_geom_triangles = new VertexArray(3, stl_triangles.size() / 3);
1672  unsigned int c = useColor() ? getColor() : CTX::instance()->color.geom.surface;
1673  unsigned int col[4] = {c, c, c, c};
1674  if (stl_vertices_xyz.size())
1675  {
1676  for (std::size_t i = 0; i < stl_triangles.size(); i += 3)
1677  {
1679  SPoint3 &p2(stl_vertices_xyz[stl_triangles[i + 1]]);
1680  SPoint3 &p3(stl_vertices_xyz[stl_triangles[i + 2]]);
1681  double x[3] = {p1.x(), p2.x(), p3.x()};
1682  double y[3] = {p1.y(), p2.y(), p3.y()};
1683  double z[3] = {p1.z(), p2.z(), p3.z()};
1684  if (stl_vertices_xyz.size() == stl_normals.size())
1685  {
1687  stl_normals[stl_triangles[i + 2]]};
1688  va_geom_triangles->add(x, y, z, n, col);
1689  }
1690  else
1691  {
1692  double nn[3];
1693  normal3points(x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2], nn);
1694  SVector3 n[3] = {SVector3(nn), SVector3(nn), SVector3(nn)};
1695  va_geom_triangles->add(x, y, z, n, col);
1696  }
1697  }
1698  }
1699  else if (stl_vertices_uv.size())
1700  {
1701  for (std::size_t i = 0; i < stl_triangles.size(); i += 3)
1702  {
1704  SPoint2 &p2(stl_vertices_uv[stl_triangles[i + 1]]);
1705  SPoint2 &p3(stl_vertices_uv[stl_triangles[i + 2]]);
1706  GPoint gp1 = point(p1);
1707  GPoint gp2 = point(p2);
1708  GPoint gp3 = point(p3);
1709  double x[3] = {gp1.x(), gp2.x(), gp3.x()};
1710  double y[3] = {gp1.y(), gp2.y(), gp3.y()};
1711  double z[3] = {gp1.z(), gp2.z(), gp3.z()};
1712  if (stl_vertices_uv.size() == stl_normals.size())
1713  {
1715  stl_normals[stl_triangles[i + 2]]};
1716  va_geom_triangles->add(x, y, z, n, col);
1717  }
1718  else
1719  {
1720  SVector3 n[3] = {normal(p1), normal(p2), normal(p3)};
1721  va_geom_triangles->add(x, y, z, n, col);
1722  }
1723  }
1724  }
1726  return true;
1727 }
1728 
1730 {
1731  // as the STL might be non-conforming, we make no effort to have a conformal
1732  // mesh - nodes will not be classified on boundaries, and not shared with
1733  // adjacent entities
1734  if (stl_vertices_xyz.size())
1735  {
1736  for (std::size_t i = 0; i < stl_vertices_xyz.size(); i++)
1737  {
1738  SPoint3 &p(stl_vertices_xyz[i]);
1739  mesh_vertices.push_back(new MVertex(p.x(), p.y(), p.z(), this));
1740  }
1741  }
1742  else if (stl_vertices_uv.size())
1743  {
1744  for (std::size_t i = 0; i < stl_vertices_uv.size(); i++)
1745  {
1746  SPoint2 &p(stl_vertices_uv[i]);
1747  GPoint gp = point(p);
1748  mesh_vertices.push_back(new MFaceVertex(gp.x(), gp.y(), gp.z(), this, p.x(), p.y()));
1749  }
1750  }
1751  else
1752  {
1753  return false;
1754  }
1755  for (std::size_t i = 0; i < stl_triangles.size(); i += 3)
1756  {
1758  mesh_vertices[stl_triangles[i + 2]]));
1759  }
1760  return true;
1761 }
1762 
1763 int GFace::genusGeom() const
1764 {
1765  int nSeams = 0;
1766  std::set<GEdge *> single_seams;
1767  for (auto it = l_edges.begin(); it != l_edges.end(); ++it)
1768  {
1769  if ((*it)->isSeam(this))
1770  {
1771  nSeams++;
1772  auto it2 = single_seams.find(*it);
1773  if (it2 != single_seams.end())
1774  single_seams.erase(it2);
1775  else
1776  single_seams.insert(*it);
1777  }
1778  }
1779  return nSeams - single_seams.size();
1780 }
1781 
1782 bool GFace::fillPointCloud(double maxDist, std::vector<SPoint3> *points, std::vector<SPoint2> *uvpoints,
1783  std::vector<SVector3> *normals)
1784 {
1785  if (!points)
1786  return false;
1787 
1788  if (buildSTLTriangulation())
1789  {
1790  if (stl_vertices_xyz.size())
1791  {
1792  for (std::size_t i = 0; i < stl_triangles.size(); i += 3)
1793  {
1795  SPoint3 &p1(stl_vertices_xyz[stl_triangles[i + 1]]);
1796  SPoint3 &p2(stl_vertices_xyz[stl_triangles[i + 2]]);
1797  double maxEdge = std::max(p0.distance(p1), std::max(p1.distance(p2), p2.distance(p0)));
1798  int N = std::max((int)(maxEdge / maxDist), 1);
1799  for (double u = 0.; u < 1.; u += 1. / N)
1800  {
1801  for (double v = 0.; v < 1 - u; v += 1. / N)
1802  {
1803  SPoint3 p = p0 * (1. - u - v) + p1 * u + p2 * v;
1804  points->push_back(p);
1805  }
1806  }
1807  }
1808  }
1809  else if (stl_vertices_uv.size())
1810  {
1811  for (std::size_t i = 0; i < stl_triangles.size(); i += 3)
1812  {
1814  SPoint2 &p1(stl_vertices_uv[stl_triangles[i + 1]]);
1815  SPoint2 &p2(stl_vertices_uv[stl_triangles[i + 2]]);
1816  GPoint gp0 = point(p0);
1817  GPoint gp1 = point(p1);
1818  GPoint gp2 = point(p2);
1819  double maxEdge = std::max(gp0.distance(gp1), std::max(gp1.distance(gp2), gp2.distance(gp0)));
1820  int N = std::max((int)(maxEdge / maxDist), 1);
1821  for (double u = 0.; u < 1.; u += 1. / N)
1822  {
1823  for (double v = 0.; v < 1 - u; v += 1. / N)
1824  {
1825  SPoint2 p = p0 * (1. - u - v) + p1 * u + p2 * v;
1826  GPoint gp(point(p));
1827  points->push_back(SPoint3(gp.x(), gp.y(), gp.z()));
1828  if (uvpoints)
1829  uvpoints->push_back(p);
1830  if (normals)
1831  normals->push_back(normal(p));
1832  }
1833  }
1834  }
1835  }
1836  }
1837  else
1838  {
1839  // uniform sampling of underlying parametric plane
1840  int N = std::max((int)(bounds().diag() / maxDist), 2);
1841  Range<double> b1 = parBounds(0);
1842  Range<double> b2 = parBounds(1);
1843  for (int i = 0; i < N; i++)
1844  {
1845  for (int j = 0; j < N; j++)
1846  {
1847  double u = (double)i / (N - 1);
1848  double v = (double)j / (N - 1);
1849  double t1 = b1.low() + u * (b1.high() - b1.low());
1850  double t2 = b2.low() + v * (b2.high() - b2.low());
1851  GPoint gp = point(t1, t2);
1852  points->push_back(SPoint3(gp.x(), gp.y(), gp.z()));
1853  if (uvpoints)
1854  uvpoints->push_back(SPoint2(t1, t2));
1855  if (normals)
1856  normals->push_back(normal(SPoint2(t1, t2)));
1857  }
1858  }
1859  }
1860  return true;
1861 }
1862 
1863 #if defined(HAVE_MESH)
1864 
1865 #if defined(HAVE_QUADMESHINGTOOLS)
1866 
1867 int buildBackgroundField(GModel *gm, const std::vector<MTriangle *> &global_triangles,
1868  const std::vector<std::array<double, 9>> &global_triangle_directions,
1869  const std::unordered_map<MVertex *, double> &global_size_map,
1870  const std::vector<std::array<double, 5>> &global_singularity_list,
1871  const std::string &viewName);
1872 int fillSizemapFromScalarBackgroundField(GModel *gm, const std::vector<MTriangle *> &triangles,
1873  std::unordered_map<MVertex *, double> &sizeMap);
1874 
1875 #endif
1876 
1877 static int meshCompoundMakeQuads(GFace *gf)
1878 {
1881  return 0;
1882 
1883  // recombineIntoQuads(gf, false, 2, true, .01);
1884 
1886  return 0;
1887 }
1888 
1889 static int meshCompoundComputeCrossFieldWithHeatEquation(GFace *gf)
1890 {
1893  return 0;
1894 
1895 #if defined(HAVE_QUADMESHINGTOOLS)
1896 
1897  std::vector<std::array<double, 3>> triEdgeTheta;
1898  std::vector<MLine *> lines;
1899  std::vector<GEdge *> edges = gf->edges();
1900  for (auto ge : edges)
1901  lines.insert(lines.end(), ge->lines.begin(), ge->lines.end());
1902 
1903  int scf = computeCrossFieldWithHeatEquation(4, gf->triangles, lines, triEdgeTheta);
1904 
1905  if (scf != 0)
1906  {
1907  Msg::Warning("- Face %i: failed to compute cross field", gf->tag());
1908  return scf;
1909  }
1910 
1911  std::vector<std::array<double, 9>> triangleDirections;
1912  int sc = convertToPerTriangleCrossFieldDirections(4, gf->triangles, triEdgeTheta, triangleDirections);
1913  if (sc != 0)
1914  {
1915  Msg::Warning("- Face %i: failed to resample cross field at triangle corners", gf->tag());
1916  }
1917 
1918  std::unordered_map<MVertex *, double> sizeMap;
1919 
1920  int sts = fillSizemapFromScalarBackgroundField(gf->model(), gf->triangles, sizeMap);
1921  if (sts != 0)
1922  {
1923  Msg::Warning("- Face %i: failed to fill size map from background field", gf->tag());
1924  }
1925 
1926  std::vector<std::array<double, 5>> singularityList;
1927 
1928  FieldManager *fields = gf->model()->getFields();
1929  fields->setBackgroundFieldId(0);
1930 
1931  int TEMP = CTX::instance()->mesh.algo2d;
1933 
1934  int sbf =
1935  buildBackgroundField(gf->model(), gf->triangles, triangleDirections, sizeMap, singularityList, "guiding_field");
1936 
1937  CTX::instance()->mesh.algo2d = TEMP;
1938 
1939  if (sbf != 0)
1940  {
1941  Msg::Warning("failed to build background guiding field");
1942  return -1;
1943  }
1944 
1945  return 0;
1946 #else
1947  return -1;
1948 #endif
1949 }
1950 
1951 static void meshCompound(GFace *gf, bool verbose)
1952 {
1953  discreteFace *df = dynamic_cast<discreteFace *>(gf->model()->getFaceByTag(gf->tag() + 100000));
1954  if (df)
1955  {
1956  df->deleteMesh();
1957  }
1958  else
1959  {
1960  df = new discreteFace(gf->model(), gf->tag() + 100000);
1961  gf->model()->add(df);
1962  }
1963 
1964  // reclassify the elements on the original surfaces? (This is nice but it will
1965  // perturb algorithms that depend on the parametrization after the mesh is
1966  // done)
1967  bool magic = (CTX::instance()->mesh.compoundClassify == 1);
1968 
1970  {
1971  df->meshAttributes.method = gf->meshAttributes.method;
1972  df->meshAttributes.transfiniteArrangement = gf->meshAttributes.transfiniteArrangement;
1973  df->meshAttributes.transfiniteSmoothing = gf->meshAttributes.transfiniteSmoothing;
1974  df->meshAttributes.algorithm = gf->meshAttributes.algorithm;
1975  }
1976 
1977  std::vector<GFace *> triangles_tag;
1978 
1979  std::set<GEdge *, GEntityPtrLessThan> bnd, emb1;
1980  std::set<GVertex *, GEntityPtrLessThan> emb0;
1981  std::set<int> phys;
1982  for (std::size_t i = 0; i < gf->compound.size(); i++)
1983  {
1984  auto *c = (GFace *)gf->compound[i];
1985  df->triangles.insert(df->triangles.end(), c->triangles.begin(), c->triangles.end());
1986  df->quadrangles.insert(df->quadrangles.end(), c->quadrangles.begin(), c->quadrangles.end());
1987  df->mesh_vertices.insert(df->mesh_vertices.end(), c->mesh_vertices.begin(), c->mesh_vertices.end());
1988  for (std::size_t j = 0; j < c->triangles.size(); j++)
1989  triangles_tag.push_back(c);
1990  std::vector<GEdge *> edges = c->edges();
1991  for (std::size_t j = 0; j < edges.size(); j++)
1992  {
1993  if (bnd.find(edges[j]) == bnd.end())
1994  bnd.insert(edges[j]);
1995  else
1996  bnd.erase(edges[j]);
1997  }
1998  // force retrieval of embedded entities
1999  std::vector<GVertex *> embv = c->getEmbeddedVertices(true);
2000  emb0.insert(embv.begin(), embv.end());
2001  std::vector<GEdge *> embe = c->getEmbeddedEdges(true);
2002  emb1.insert(embe.begin(), embe.end());
2003 
2004  if (magic)
2005  {
2006  c->triangles.clear();
2007  c->quadrangles.clear();
2008  c->mesh_vertices.clear();
2009  }
2010  c->compoundSurface = df;
2011  if (!magic)
2012  {
2013  phys.insert(c->physicals.begin(), c->physicals.end());
2014  c->physicals.clear();
2015  }
2016  }
2017 
2018  std::set<GEdge *, GEntityPtrLessThan> bndc;
2019  for (auto it = bnd.begin(); it != bnd.end(); it++)
2020  {
2021  GEdge *e = *it;
2022  if (e->compoundCurve)
2023  bndc.insert(e->compoundCurve);
2024  else
2025  bndc.insert(e);
2026  }
2027  std::vector<GEdge *> ed(bndc.begin(), bndc.end());
2028  df->set(ed);
2029 
2030  for (auto it = emb1.begin(); it != emb1.end(); it++)
2031  df->addEmbeddedEdge(*it);
2032 
2033  for (auto it = emb0.begin(); it != emb0.end(); it++)
2034  df->addEmbeddedVertex(*it);
2035 
2036  FieldManager *fields = gf->model()->getFields();
2037  int BGTAG = fields->getBackgroundField();
2038  Field *backgroundField = fields->get(BGTAG);
2039 
2040  if (df->createGeometry())
2041  {
2042  Msg::Error("Could not create geometry of discrete surface %d (check "
2043  "orientation of input triangulations)",
2044  df->tag());
2045  }
2046  else
2047  {
2048  int scf = meshCompoundComputeCrossFieldWithHeatEquation(df);
2049  if (scf != 0)
2050  {
2051  return;
2052  }
2053  }
2054 
2055  if (!magic)
2056  {
2057  df->triangles.clear();
2058  df->quadrangles.clear();
2059  df->mesh_vertices.clear();
2060  }
2061  df->mesh(verbose);
2062 
2063  meshCompoundMakeQuads(df);
2064 
2065  if (fields->getBackgroundField() > 0 && fields->getBackgroundField() != BGTAG)
2066  {
2067  fields->deleteField(fields->getBackgroundField());
2068  fields->setBackgroundField(backgroundField);
2069  }
2070 
2071  if (!magic)
2072  {
2073  df->physicals.clear();
2074  df->physicals.insert(df->physicals.end(), phys.begin(), phys.end());
2075  return;
2076  }
2077 
2078  for (std::size_t i = 0; i < df->mesh_vertices.size(); i++)
2079  {
2080  double u, v;
2081  df->mesh_vertices[i]->getParameter(0, u);
2082  df->mesh_vertices[i]->getParameter(1, v);
2083  double U, V;
2084  // search triangle in original mesh used to compute the parametrization
2085  int position = df->trianglePosition(u, v, U, V);
2086  if (position >= 0 && position < (int)triangles_tag.size())
2087  {
2088  triangles_tag[position]->mesh_vertices.push_back(df->mesh_vertices[i]);
2089  df->mesh_vertices[i]->setEntity(triangles_tag[position]);
2090  }
2091  else
2092  {
2093  gf->mesh_vertices.push_back(df->mesh_vertices[i]);
2094  gf->mesh_vertices[i]->setEntity(gf);
2095  }
2096  }
2097 
2098  for (std::size_t i = 0; i < df->triangles.size(); i++)
2099  {
2100  MTriangle *t = df->triangles[i];
2101  bool found = false;
2102  for (int i = 0; i < 3; i++)
2103  {
2104  if (t->getVertex(i)->onWhat()->dim() == 2)
2105  {
2106  ((GFace *)t->getVertex(i)->onWhat())->triangles.push_back(t);
2107  found = true;
2108  break;
2109  }
2110  }
2111  if (!found)
2112  {
2113  gf->triangles.push_back(t); // FIXME could be better!
2114  }
2115  }
2116 
2117  for (std::size_t i = 0; i < df->quadrangles.size(); i++)
2118  {
2119  MQuadrangle *q = df->quadrangles[i];
2120  bool found = false;
2121  for (int i = 0; i < 4; i++)
2122  {
2123  if (q->getVertex(i)->onWhat()->dim() == 2)
2124  {
2125  ((GFace *)q->getVertex(i)->onWhat())->quadrangles.push_back(q);
2126  found = true;
2127  break;
2128  }
2129  }
2130  if (!found)
2131  {
2132  gf->quadrangles.push_back(q); // FIXME could be better!
2133  }
2134  }
2135 
2136  df->triangles.clear();
2137  df->quadrangles.clear();
2138  df->mesh_vertices.clear();
2139 }
2140 #endif
2141 
2142 void GFace::mesh(bool verbose)
2143 {
2145  {
2146  meshStatistics.status = GFace::DONE;
2147  return;
2148  }
2149 
2150 #if defined(HAVE_MESH)
2151  if (compound.size())
2152  meshAttributes.meshSizeFactor = CTX::instance()->mesh.compoundLcFactor;
2153 
2154  meshGFace mesher;
2155  mesher(this, verbose);
2156 
2157  if (compound.size())
2158  { // Some faces are meshed together
2159  meshAttributes.meshSizeFactor = 1;
2160 
2161  orientMeshGFace orient;
2162  orient(this);
2163  if (compound[0] == this)
2164  { // I'm the one that makes the compound job
2165  bool ok = true;
2166  for (std::size_t i = 0; i < compound.size(); i++)
2167  {
2168  auto *gf = (GFace *)compound[i];
2169  ok &= (gf->meshStatistics.status == GFace::DONE);
2170  }
2171  if (!ok)
2172  {
2173  meshStatistics.status = GFace::PENDING;
2174  }
2175  else
2176  {
2177  meshCompound(this, verbose);
2178  meshStatistics.status = GFace::DONE;
2179  return;
2180  }
2181  }
2182  }
2183 #endif
2184 }
2185 
2187 {
2188  for (int i = 0; i < 2; i++)
2189  {
2190  if (periodic(i))
2191  {
2192  Range<double> range = parBounds(i);
2193  double tol = 1e-6 * (range.high() - range.low());
2194  if (pt[i] < range.low() - tol)
2195  pt[i] += period(i);
2196  if (pt[i] > range.high() + tol)
2197  pt[i] -= period(i);
2198  if (pt[i] < range.low())
2199  pt[i] = range.low();
2200  if (pt[i] > range.high())
2201  pt[i] = range.high();
2202  }
2203  }
2204 }
2205 
2207 {
2208  for (std::size_t i = 0; i < mesh_vertices.size(); i++)
2209  {
2210  MVertex *v = mesh_vertices[i];
2211  double u0 = 0., u1 = 0.;
2212  if (v->getParameter(0, u0) && v->getParameter(1, u1))
2213  {
2214  GPoint p = point(u0, u1);
2215  v->x() = p.x();
2216  v->y() = p.y();
2217  v->z() = p.z();
2218  }
2219  }
2220 }
2221 
2222 void GFace::setMeshMaster(GFace *master, const std::vector<double> &tfo)
2223 {
2224  Msg::Info("Setting mesh master using transformation");
2225 
2226  // points and curves
2227  std::set<GVertex *> l_vertices;
2228  std::multimap<std::pair<GVertex *, GVertex *>, GEdge *> l_vtxToEdge;
2229  for (auto eIter = l_edges.begin(); eIter != l_edges.end(); ++eIter)
2230  {
2231  GVertex *v0 = (*eIter)->getBeginVertex();
2232  GVertex *v1 = (*eIter)->getEndVertex();
2233  if (v0 && v1)
2234  {
2235  l_vertices.insert(v0);
2236  l_vertices.insert(v1);
2237  l_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
2238  }
2239  }
2240  for (auto eIter = embedded_edges.begin(); eIter != embedded_edges.end(); ++eIter)
2241  {
2242  GVertex *v0 = (*eIter)->getBeginVertex();
2243  GVertex *v1 = (*eIter)->getEndVertex();
2244  if (v0 && v1)
2245  {
2246  l_vertices.insert(v0);
2247  l_vertices.insert(v1);
2248  l_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
2249  }
2250  }
2251  l_vertices.insert(embedded_vertices.begin(), embedded_vertices.end());
2252 
2253  // master points and curves
2254  std::vector<GEdge *> const &m_edges = master->edges();
2255  std::set<GVertex *> m_vertices;
2256  std::multimap<std::pair<GVertex *, GVertex *>, GEdge *> m_vtxToEdge;
2257  for (auto eIter = m_edges.begin(); eIter != m_edges.end(); ++eIter)
2258  {
2259  GVertex *v0 = (*eIter)->getBeginVertex();
2260  GVertex *v1 = (*eIter)->getEndVertex();
2261  if (v0 && v1)
2262  {
2263  m_vertices.insert(v0);
2264  m_vertices.insert(v1);
2265  m_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
2266  }
2267  }
2268  std::vector<GEdge *> const &m_embedded_edges = master->embeddedEdges();
2269  for (auto eIter = m_embedded_edges.begin(); eIter != m_embedded_edges.end(); eIter++)
2270  {
2271  GVertex *v0 = (*eIter)->getBeginVertex();
2272  GVertex *v1 = (*eIter)->getEndVertex();
2273  if (v0 && v1)
2274  {
2275  m_vertices.insert(v0);
2276  m_vertices.insert(v1);
2277  m_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
2278  }
2279  }
2280  std::set<GVertex *, GEntityPtrLessThan> m_embedded_vertices = master->embeddedVertices();
2281  m_vertices.insert(m_embedded_vertices.begin(), m_embedded_vertices.end());
2282 
2283  // check topological correspondence
2284  if (l_vertices.size() != m_vertices.size())
2285  {
2286  Msg::Error("Different number of points (%d vs %d) for periodic correspondence "
2287  "between surfaces %d and %d",
2288  l_vertices.size(), m_vertices.size(), master->tag(), tag());
2289  return;
2290  }
2291  if (l_vtxToEdge.size() != m_vtxToEdge.size())
2292  {
2293  Msg::Error("Different number of curves (%d vs %d) for periodic correspondence "
2294  "between surfaces %d and %d",
2295  l_vtxToEdge.size(), m_vtxToEdge.size(), master->tag(), tag());
2296  return;
2297  }
2298 
2299  // compute corresponding vertices
2300  std::map<GVertex *, GVertex *> gVertexCounterparts;
2301  for (auto mvIter = m_vertices.begin(); mvIter != m_vertices.end(); ++mvIter)
2302  {
2303  GVertex *m_vertex = *mvIter;
2304 
2305  SPoint3 xyzTfo((*mvIter)->x(), (*mvIter)->y(), (*mvIter)->z());
2306  xyzTfo.transform(tfo);
2307 
2308  GVertex *l_vertex = nullptr;
2309 
2310  double dist_min = 1.e22;
2311  for (auto lvIter = l_vertices.begin(); lvIter != l_vertices.end(); ++lvIter)
2312  {
2313  SPoint3 xyz((*lvIter)->x(), (*lvIter)->y(), (*lvIter)->z());
2314  SVector3 dist = xyz - xyzTfo;
2315  dist_min = std::min(dist_min, dist.norm());
2316  if (dist.norm() < CTX::instance()->geom.tolerance * CTX::instance()->lc)
2317  {
2318  l_vertex = *lvIter;
2319  break;
2320  }
2321  }
2322 
2323  if (l_vertex == nullptr)
2324  {
2325  Msg::Error("No corresponding point %d for periodic connection of surface "
2326  "%d to %d (min. distance = %g, tolerance = %g)",
2327  m_vertex->tag(), master->tag(), tag(), dist_min,
2328  CTX::instance()->geom.tolerance * CTX::instance()->lc);
2329  return;
2330  }
2331  gVertexCounterparts[l_vertex] = m_vertex;
2332  }
2333 
2334  if (gVertexCounterparts.size() != m_vertices.size())
2335  {
2336  Msg::Error("Could not find all point correspondences for the periodic "
2337  "connection from surface %d to %d",
2338  master->tag(), tag());
2339  return;
2340  }
2341 
2342  // construct edge correspondence and update the edge masters
2343  std::map<GEdge *, std::pair<GEdge *, int>> gEdgeCounterparts;
2344 
2345  for (auto lv2eIter = l_vtxToEdge.begin(); lv2eIter != l_vtxToEdge.end(); lv2eIter++)
2346  {
2347  std::pair<GVertex *, GVertex *> lPair = lv2eIter->first;
2348  GEdge *localEdge = lv2eIter->second;
2349 
2350  std::pair<GVertex *, GVertex *> forward(gVertexCounterparts[lPair.first], gVertexCounterparts[lPair.second]);
2351  int numf = m_vtxToEdge.count(forward);
2352  std::pair<GVertex *, GVertex *> backward(forward.second, forward.first);
2353  int numb = m_vtxToEdge.count(backward);
2354  int sign = 0;
2355  GEdge *masterEdge = nullptr;
2356 
2357  // unique matches
2358  if (!masterEdge && numf == 1 && (numb == 0 || forward.first == forward.second))
2359  {
2360  masterEdge = m_vtxToEdge.find(forward)->second;
2361  sign = 1;
2362  }
2363  if (!masterEdge && numb == 1 && (numf == 0 || forward.first == forward.second))
2364  {
2365  masterEdge = m_vtxToEdge.find(backward)->second;
2366  sign = -1;
2367  }
2368 
2369  // if there are multiple matches (when several curves have the same
2370  // begin/end points), we must compare the geometry: mid-points (general) or
2371  // transformed bounding boxes as a fallback (ok for translations or
2372  // rotations by n*pi/2)
2373  SBoundingBox3d localbb = localEdge->bounds(true);
2374  double tol = localbb.diag() * 1e-3;
2375  Range<double> localr = localEdge->parBounds(0);
2376  GPoint localp = localEdge->point(0.5 * (localr.low() + localr.high()));
2377  if (!masterEdge && numf)
2378  {
2379  auto ret = m_vtxToEdge.equal_range(forward);
2380  for (auto it = ret.first; it != ret.second; it++)
2381  {
2382  GEdge *ge = it->second;
2383  Range<double> masterr = ge->parBounds(0);
2384  GPoint masterp = ge->point(0.5 * (masterr.low() + masterr.high()));
2385  if (localp.succeeded() && masterp.succeeded())
2386  {
2387  SPoint3 p1(localp.x(), localp.y(), localp.z());
2388  SPoint3 p2(masterp.x(), masterp.y(), masterp.z());
2389  p2.transform(tfo);
2390  if (p1.distance(p2) < tol)
2391  {
2392  masterEdge = ge;
2393  sign = 1;
2394  break;
2395  }
2396  }
2397  SBoundingBox3d masterbb = ge->bounds(true);
2398  masterbb.transform(tfo);
2399  if (masterbb.min().distance(localbb.min()) < tol && masterbb.max().distance(localbb.max()) < tol)
2400  {
2401  masterEdge = ge;
2402  sign = 1;
2403  break;
2404  }
2405  }
2406  }
2407  if (!masterEdge && numb)
2408  {
2409  auto ret = m_vtxToEdge.equal_range(backward);
2410  for (auto it = ret.first; it != ret.second; it++)
2411  {
2412  GEdge *ge = it->second;
2413  Range<double> masterr = ge->parBounds(0);
2414  GPoint masterp = ge->point(0.5 * (masterr.low() + masterr.high()));
2415  if (localp.succeeded() && masterp.succeeded())
2416  {
2417  SPoint3 p1(localp.x(), localp.y(), localp.z());
2418  SPoint3 p2(masterp.x(), masterp.y(), masterp.z());
2419  p2.transform(tfo);
2420  if (p1.distance(p2) < tol)
2421  {
2422  masterEdge = ge;
2423  sign = -1;
2424  break;
2425  }
2426  }
2427  SBoundingBox3d masterbb = ge->bounds(true);
2428  masterbb.transform(tfo);
2429  if (masterbb.min().distance(localbb.min()) < tol && masterbb.max().distance(localbb.max()) < tol)
2430  {
2431  masterEdge = ge;
2432  sign = -1;
2433  break;
2434  }
2435  }
2436  }
2437 
2438  if (!masterEdge)
2439  {
2440  Msg::Error("Could not find counterpart of curve %d with end points %d %d "
2441  "(corresponding to curve with end points %d %d) in surface %d",
2442  localEdge->tag(), lPair.first->tag(), lPair.second->tag(), forward.first->tag(),
2443  forward.second->tag(), master->tag());
2444  return;
2445  }
2446 
2447  if (masterEdge->getMeshMaster() != localEdge)
2448  {
2449  localEdge->setMeshMaster(masterEdge, tfo);
2450  Msg::Info("Setting curve master %d - %d", localEdge->tag(), masterEdge->tag());
2451  }
2452  gEdgeCounterparts[localEdge] = std::make_pair(masterEdge, sign);
2453  }
2454 
2455  // complete the information at the edge level
2456  edgeCounterparts = gEdgeCounterparts;
2457  vertexCounterparts = gVertexCounterparts;
2458  GEntity::setMeshMaster(master, tfo);
2459 }
2460 
2461 inline double myAngle(const SVector3 &a, const SVector3 &b, const SVector3 &d)
2462 {
2463  double const cosTheta = dot(a, b);
2464  double const sinTheta = dot(crossprod(a, b), d);
2465  return std::atan2(sinTheta, cosTheta);
2466 }
2467 
2468 struct myPlane
2469 {
2472  double a;
2473  // nx x + ny y + nz z + a = 0
2474  myPlane(const SPoint3 &_p, const SVector3 &_n) : p(_p), n(_n)
2475  {
2476  n.normalize();
2477  a = -(n.x() * p.x() + n.y() * p.y() + n.z() * p.z());
2478  }
2479  double eval(double x, double y, double z)
2480  {
2481  return n.x() * x + n.y() * y + n.z() * z + a;
2482  }
2483 };
2484 
2485 struct myLine
2486 {
2489  myLine() : p(0, 0, 0), t(0, 0, 1)
2490  {
2491  }
2493  {
2494  t = crossprod(p1.n, p2.n);
2495  if (t.norm() == 0.0)
2496  {
2497  Msg::Error("parallel planes do not intersect");
2498  }
2499  else
2500  t.normalize();
2501  // find a point, assume z = 0
2502  double a[2][2] = {{p1.n.x(), p1.n.y()}, {p2.n.x(), p2.n.y()}};
2503  double b[2] = {-p1.a, -p2.a}, x[2];
2504  if (!sys2x2(a, b, x))
2505  {
2506  // assume x = 0
2507  double az[2][2] = {{p1.n.y(), p1.n.z()}, {p2.n.y(), p2.n.z()}};
2508  double bz[2] = {-p1.a, -p2.a};
2509  if (!sys2x2(az, bz, x))
2510  {
2511  // assume y = 0
2512  double ay[2][2] = {{p1.n.x(), p1.n.z()}, {p2.n.x(), p2.n.z()}};
2513  double by[2] = {-p1.a, -p2.a};
2514  if (!sys2x2(ay, by, x))
2515  {
2516  Msg::Error("parallel planes do not intersect");
2517  }
2518  else
2519  {
2520  p = SPoint3(x[0], 0., x[1]);
2521  }
2522  }
2523  else
2524  {
2525  p = SPoint3(0., x[0], x[1]);
2526  }
2527  }
2528  else
2529  {
2530  p = SPoint3(x[0], x[1], 0.);
2531  }
2532  }
2534  {
2535  // (x - a) * t = 0 -->
2536  // x = p + u t --> (p + ut - a) * t = 0 --> u = (a-p) * t
2537  const double u = dot(a - p, t);
2538  return SPoint3(p.x() + t.x() * u, p.y() + t.y() * u, p.z() + t.z() * u);
2539  }
2540 };
2541 
2542 void GFace::setMeshMaster(GFace *master, const std::map<int, int> &edgeCopies)
2543 {
2544  std::map<GVertex *, GVertex *> vs2vt;
2545 
2546  for (auto it = l_edges.begin(); it != l_edges.end(); ++it)
2547  {
2548  // slave edge
2549  GEdge *le = *it;
2550 
2551  int sign = 1;
2552  auto adnksd = edgeCopies.find(le->tag());
2553  int source_e;
2554  if (adnksd != edgeCopies.end())
2555  source_e = adnksd->second;
2556  else
2557  {
2558  sign = -1;
2559  adnksd = edgeCopies.find(-(*it)->tag());
2560  if (adnksd != edgeCopies.end())
2561  source_e = adnksd->second;
2562  else
2563  {
2564  Msg::Error("Could not find curve counterpart %d in slave surface %d", (*it)->tag(), master->tag());
2565  return;
2566  }
2567  }
2568 
2569  // master edge
2570  GEdge *me = master->model()->getEdgeByTag(abs(source_e));
2571 
2572  if (le->getBeginVertex() && le->getEndVertex() && me->getBeginVertex() && me->getEndVertex())
2573  {
2574  if (source_e * sign > 0)
2575  {
2576  vs2vt[me->getBeginVertex()] = le->getBeginVertex();
2577  vs2vt[me->getEndVertex()] = le->getEndVertex();
2578  }
2579  else
2580  {
2581  vs2vt[me->getBeginVertex()] = le->getEndVertex();
2582  vs2vt[me->getEndVertex()] = le->getBeginVertex();
2583  }
2584  }
2585  }
2586 
2587  // --- find out the transformation
2588 
2589  bool translation = true;
2590  SVector3 DX;
2591 
2592  int count = 0;
2593  for (auto it = vs2vt.begin(); it != vs2vt.end(); ++it)
2594  {
2595  GVertex *vs = it->first;
2596  GVertex *vt = it->second;
2597  if (count == 0)
2598  DX = SVector3(vt->x() - vs->x(), vt->y() - vs->y(), vt->z() - vs->z());
2599  else
2600  {
2601  SVector3 DX2(vt->x() - vs->x(), vt->y() - vs->y(), vt->z() - vs->z());
2602  SVector3 DDX(DX2 - DX);
2603  if (DDX.norm() > DX.norm() * 1.e-5)
2604  translation = false;
2605  }
2606  count++;
2607  }
2608 
2609  std::vector<double> tfo(16);
2610 
2611  if (translation)
2612  {
2613  Msg::Info("Periodic mesh translation found between %d and %d: dx = (%g,%g,%g)", tag(), master->tag(), DX.x(),
2614  DX.y(), DX.z());
2615 
2616  for (size_t i = 0; i < 16; i++)
2617  tfo[i] = 0;
2618  for (size_t i = 0; i < 4; i++)
2619  tfo[i * 4 + i] = 1;
2620  tfo[3] = DX.x();
2621  tfo[7] = DX.y();
2622  tfo[11] = DX.z();
2623  }
2624 
2625  else
2626  {
2627  bool rotation = false;
2628  myLine LINE;
2629  double ANGLE = 0;
2630 
2631  count = 0;
2632  rotation = true;
2633  std::vector<SPoint3> mps, mpt;
2634  for (auto it = vs2vt.begin(); it != vs2vt.end(); ++it)
2635  {
2636  GVertex *vs = it->first;
2637  GVertex *vt = it->second;
2638  mps.push_back(SPoint3(vs->x(), vs->y(), vs->z()));
2639  mpt.push_back(SPoint3(vt->x(), vt->y(), vt->z()));
2640  }
2641  mean_plane mean_source, mean_target;
2642  computeMeanPlaneSimple(mps, mean_source);
2643  computeMeanPlaneSimple(mpt, mean_target);
2644 
2645  myPlane PLANE_SOURCE(SPoint3(mean_source.x, mean_source.y, mean_source.z),
2646  SVector3(mean_source.a, mean_source.b, mean_source.c));
2647  myPlane PLANE_TARGET(SPoint3(mean_target.x, mean_target.y, mean_target.z),
2648  SVector3(mean_target.a, mean_target.b, mean_target.c));
2649 
2650  LINE = myLine(PLANE_SOURCE, PLANE_TARGET);
2651 
2652  // LINE is the axis of rotation
2653  // let us compute the angle of rotation
2654  count = 0;
2655  for (auto it = vs2vt.begin(); it != vs2vt.end(); ++it)
2656  {
2657  GVertex *vs = it->first;
2658  GVertex *vt = it->second;
2659  // project both points on the axis: that should be the same point !
2660  SPoint3 ps = SPoint3(vs->x(), vs->y(), vs->z());
2661  SPoint3 pt = SPoint3(vt->x(), vt->y(), vt->z());
2662  SPoint3 p_ps = LINE.orthogonalProjection(ps);
2663  SPoint3 p_pt = LINE.orthogonalProjection(pt);
2664  SVector3 dist1 = ps - pt;
2665  SVector3 dist2 = p_ps - p_pt;
2666  if (dist1.norm() > CTX::instance()->geom.tolerance)
2667  {
2668  if (dist2.norm() > 1.e-8 * dist1.norm())
2669  {
2670  rotation = false;
2671  }
2672  SVector3 t1 = ps - p_ps;
2673  SVector3 t2 = pt - p_pt;
2674  if (t1.norm() > 1.e-8 * dist1.norm())
2675  {
2676  if (count == 0)
2677  ANGLE = myAngle(t1, t2, LINE.t);
2678  else
2679  {
2680  double ANGLE2 = myAngle(t1, t2, LINE.t);
2681  if (fabs(ANGLE2 - ANGLE) > 1.e-8)
2682  {
2683  rotation = false;
2684  }
2685  }
2686  count++;
2687  }
2688  }
2689  }
2690 
2691  if (rotation)
2692  {
2693  Msg::Info("Periodic mesh rotation found: axis (%g,%g,%g) point (%g %g "
2694  "%g) angle %g",
2695  LINE.t.x(), LINE.t.y(), LINE.t.z(), LINE.p.x(), LINE.p.y(), LINE.p.z(), ANGLE * 180 / M_PI);
2696 
2697  double ux = LINE.t.x();
2698  double uy = LINE.t.y();
2699  double uz = LINE.t.z();
2700 
2701  tfo[0 * 4 + 0] = cos(ANGLE) + ux * ux * (1. - cos(ANGLE));
2702  tfo[0 * 4 + 1] = ux * uy * (1. - cos(ANGLE)) - uz * sin(ANGLE);
2703  tfo[0 * 4 + 2] = ux * uz * (1. - cos(ANGLE)) + uy * sin(ANGLE);
2704 
2705  tfo[1 * 4 + 0] = ux * uy * (1. - cos(ANGLE)) + uz * sin(ANGLE);
2706  tfo[1 * 4 + 1] = cos(ANGLE) + uy * uy * (1. - cos(ANGLE));
2707  tfo[1 * 4 + 2] = uy * uz * (1. - cos(ANGLE)) - ux * sin(ANGLE);
2708 
2709  tfo[2 * 4 + 0] = ux * uz * (1. - cos(ANGLE)) - uy * sin(ANGLE);
2710  tfo[2 * 4 + 1] = uy * uz * (1. - cos(ANGLE)) + ux * sin(ANGLE);
2711  tfo[2 * 4 + 2] = cos(ANGLE) + uz * uz * (1. - cos(ANGLE));
2712 
2713  double origin[3] = {LINE.p.x(), LINE.p.y(), LINE.p.z()};
2714 
2715  for (int i = 0; i < 3; i++)
2716  tfo[i * 4 + 3] = origin[i];
2717  for (int i = 0; i < 3; i++)
2718  for (int j = 0; j < 3; j++)
2719  tfo[i * 4 + 3] -= tfo[i * 4 + j] * origin[j];
2720  for (int i = 0; i < 3; i++)
2721  tfo[12 + i] = 0;
2722  tfo[15] = 1;
2723  }
2724  else
2725  {
2726  Msg::Error("Only rotations or translations can currently be computed "
2727  "automatically for periodic surfaces: surface %d not meshed",
2728  tag());
2729  return;
2730  }
2731  }
2732 
2733  // --- now check and encode the transformation
2734  // --- including for edges and vertices
2735 
2736  setMeshMaster(master, tfo);
2737 }
2738 
2739 void GFace::addElement(int type, MElement *e)
2740 {
2741  switch (type)
2742  {
2743  case TYPE_TRI:
2744  addTriangle(reinterpret_cast<MTriangle *>(e));
2745  break;
2746  case TYPE_QUA:
2747  addQuadrangle(reinterpret_cast<MQuadrangle *>(e));
2748  break;
2749  case TYPE_POLYG:
2750  addPolygon(reinterpret_cast<MPolygon *>(e));
2751  break;
2752  default:
2753  Msg::Error("Trying to add unsupported element in surface %d", tag());
2754  }
2755 }
2756 
2757 void GFace::removeElement(int type, MElement *e)
2758 {
2759  switch (type)
2760  {
2761  case TYPE_TRI:
2762  {
2763  auto it = std::find(triangles.begin(), triangles.end(), reinterpret_cast<MTriangle *>(e));
2764  if (it != triangles.end())
2765  triangles.erase(it);
2766  }
2767  break;
2768  case TYPE_QUA:
2769  {
2770  auto it = std::find(quadrangles.begin(), quadrangles.end(), reinterpret_cast<MQuadrangle *>(e));
2771  if (it != quadrangles.end())
2772  quadrangles.erase(it);
2773  }
2774  break;
2775  case TYPE_POLYG:
2776  {
2777  auto it = std::find(polygons.begin(), polygons.end(), reinterpret_cast<MPolygon *>(e));
2778  if (it != polygons.end())
2779  polygons.erase(it);
2780  }
2781  break;
2782  default:
2783  Msg::Error("Trying to remove unsupported element in surface %d", tag());
2784  }
2785 }
2786 
2788 {
2789  switch (type)
2790  {
2791  case TYPE_TRI:
2792  triangles.clear();
2793  break;
2794  case TYPE_QUA:
2795  quadrangles.clear();
2796  break;
2797  case TYPE_POLYG:
2798  polygons.clear();
2799  break;
2800  default:
2801  Msg::Error("Trying to remove unsupported elements in surface %d", tag());
2802  }
2803 }
2804 
2805 bool GFace::reorder(const int elementType, const std::vector<std::size_t> &ordering)
2806 {
2807  if (triangles.size() != 0)
2808  {
2809  if (triangles.front()->getTypeForMSH() == elementType)
2810  {
2811  if (ordering.size() != triangles.size())
2812  return false;
2813 
2814  for (auto it = ordering.begin(); it != ordering.end(); ++it)
2815  {
2816  if (*it >= triangles.size())
2817  return false;
2818  }
2819 
2820  std::vector<MTriangle *> newTrianglesOrder(triangles.size());
2821  for (std::size_t i = 0; i < ordering.size(); i++)
2822  {
2823  newTrianglesOrder[i] = triangles[ordering[i]];
2824  }
2825  triangles = std::move(newTrianglesOrder);
2826  return true;
2827  }
2828  }
2829 
2830  if (quadrangles.size() != 0)
2831  {
2832  if (quadrangles.front()->getTypeForMSH() == elementType)
2833  {
2834  if (ordering.size() != quadrangles.size())
2835  return false;
2836 
2837  for (auto it = ordering.begin(); it != ordering.end(); ++it)
2838  {
2839  if (*it >= quadrangles.size())
2840  return false;
2841  }
2842 
2843  std::vector<MQuadrangle *> newQuadranglesOrder(quadrangles.size());
2844  for (std::size_t i = 0; i < ordering.size(); i++)
2845  {
2846  newQuadranglesOrder[i] = quadrangles[ordering[i]];
2847  }
2848  quadrangles = std::move(newQuadranglesOrder);
2849  return true;
2850  }
2851  }
2852 
2853  if (polygons.size() != 0)
2854  {
2855  if (polygons.front()->getTypeForMSH() == elementType)
2856  {
2857  if (ordering.size() != polygons.size())
2858  return false;
2859 
2860  for (auto it = ordering.begin(); it != ordering.end(); ++it)
2861  {
2862  if (*it >= polygons.size())
2863  return false;
2864  }
2865 
2866  std::vector<MPolygon *> newPolygonsOrder(polygons.size());
2867  for (std::size_t i = 0; i < ordering.size(); i++)
2868  {
2869  newPolygonsOrder[i] = polygons[ordering[i]];
2870  }
2871  polygons = std::move(newPolygonsOrder);
2872  return true;
2873  }
2874  }
2875 
2876  return false;
2877 }
2878 
2880 {
2881  GEntity *master = getMeshMaster();
2882 
2883  if (master != this)
2884  {
2885  std::set<MFace, MFaceLessThan> srcFaces;
2886 
2887  for (std::size_t i = 0; i < master->getNumMeshElements(); i++)
2888  {
2889  MElement *face = master->getMeshElement(i);
2890  std::vector<MVertex *> vtcs;
2891  vtcs.reserve(face->getNumVertices());
2892  for (std::size_t j = 0; j < face->getNumVertices(); j++)
2893  {
2894  vtcs.push_back(face->getVertex(j));
2895  }
2896  srcFaces.insert(MFace(vtcs));
2897  }
2898 
2899  for (std::size_t i = 0; i < getNumMeshElements(); i++)
2900  {
2901  MElement *face = getMeshElement(i);
2902  std::vector<MVertex *> vtcs;
2903  for (std::size_t j = 0; j < face->getNumVertices(); j++)
2904  {
2905  MVertex *tv = face->getVertex(j);
2906  auto cIter = correspondingVertices.find(tv);
2907  if (cIter != correspondingVertices.end())
2908  vtcs.push_back(cIter->second);
2909  }
2910 
2911  MFace mf(vtcs);
2912 
2913  auto sIter = srcFaces.find(mf);
2914 
2915  if (sIter == srcFaces.end())
2916  continue;
2917 
2918  MFace of = *sIter;
2919 
2920  int orientation;
2921  bool swap;
2922  mf.computeCorrespondence(of, orientation, swap);
2923 
2924  switch (face->getNumVertices())
2925  {
2926  case 3:
2927  {
2928  auto *tri = dynamic_cast<MTriangle *>(face);
2929  if (tri)
2930  tri->reorient(orientation, swap);
2931  break;
2932  }
2933  case 4:
2934  {
2935  auto *qua = dynamic_cast<MQuadrangle *>(face);
2936  if (qua)
2937  qua->reorient(orientation, swap);
2938  break;
2939  }
2940  }
2941  }
2942  }
2943 }
2944 
2946 {
2948  return false;
2949  auto *df = dynamic_cast<discreteFace *>(this);
2950  if (df && df->haveParametrization())
2951  return false;
2952  std::vector<GEdge *> e = edges();
2953  for (std::size_t i = 0; i < e.size(); i++)
2954  {
2955  if (e[i]->geomType() != GEntity::DiscreteCurve)
2956  return false;
2957  auto *de = dynamic_cast<discreteEdge *>(e[i]);
2958  if (de && de->haveParametrization())
2959  return false;
2960  }
2961  return true;
2962 }
GFace::getMeshElementByType
MElement * getMeshElementByType(const int familyType, const std::size_t index) const
Definition: GFace.cpp:245
contextGeometryOptions::copyMeshingMethod
int copyMeshingMethod
Definition: Context.h:107
crossprod
SVector3 crossprod(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:150
GEdge::setMeshMaster
void setMeshMaster(GEdge *master, const std::vector< double > &)
Definition: GEdge.cpp:89
GPoint::succeeded
bool succeeded() const
Definition: GPoint.h:63
MTriangle.h
GaussLegendre1D.h
meshGFaceBipartiteLabelling.h
myLine::t
SVector3 t
Definition: GFace.cpp:2488
GEntity::BoundaryLayerSurface
@ BoundaryLayerSurface
Definition: GEntity.h:116
contextGeometryOptions::tolerance
double tolerance
Definition: Context.h:99
SBoundingBox3d::diag
double diag() const
Definition: SBoundingBox3d.h:93
GFace::containsParam
virtual bool containsParam(const SPoint2 &pt)
Definition: GFace.cpp:1403
GFace::getOBB
virtual SOrientedBoundingBox getOBB()
Definition: GFace.cpp:292
GFace::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GFace.h:121
GFace::getMeshSizeFromBoundary
int getMeshSizeFromBoundary() const
Definition: GFace.cpp:71
mean_plane::d
double d
Definition: Numeric.h:35
GFace::status
GEntity::MeshGenerationStatus status
Definition: GFace.h:395
Field.h
GFace::firstDer
virtual Pair< SVector3, SVector3 > firstDer(const SPoint2 &param) const =0
GFace::embedded_edges
std::vector< GEdge * > embedded_edges
Definition: GFace.h:41
GFace::getMeshingAlgo
int getMeshingAlgo() const
Definition: GFace.cpp:63
GFace::addQuadrangle
void addQuadrangle(MQuadrangle *q)
Definition: GFace.h:440
GEntity::getColor
virtual unsigned int getColor()
Definition: GEntity.h:318
GFace::genusGeom
virtual int genusGeom() const
Definition: GFace.cpp:1763
dot
double dot(const SVector3 &a, const SMetric3 &m, const SVector3 &b)
Definition: STensor3.h:71
GFace::getNumMeshParentElements
std::size_t getNumMeshParentElements()
Definition: GFace.cpp:198
GEntity::correspondingHighOrderVertices
std::map< MVertex *, MVertex * > correspondingHighOrderVertices
Definition: GEntity.h:409
myLine::myLine
myLine(myPlane &p1, myPlane &p2)
Definition: GFace.cpp:2492
GFace::setBoundEdges
void setBoundEdges(const std::vector< int > &tagEdges)
Definition: GFace.cpp:113
CTX::color
struct CTX::@3 color
GVertex::z
virtual double z() const =0
GPoint::y
double y() const
Definition: GPoint.h:22
mean_plane::c
double c
Definition: Numeric.h:35
GFace.h
GFace::getStartElementType
MElement *const * getStartElementType(int type) const
Definition: GFace.cpp:214
distance
double distance(MVertex *v1, MVertex *v2)
Definition: MVertex.h:245
mean_plane::x
double x
Definition: Numeric.h:36
fullVector< double >
GEntity::getMeshVertex
MVertex * getMeshVertex(std::size_t index)
Definition: GEntity.h:379
contextMeshOptions::lcExtendFromBoundary
int lcExtendFromBoundary
Definition: Context.h:28
GFace::getEmbeddedVertices
std::vector< GVertex * > getEmbeddedVertices(bool force=false) const
Definition: GFace.cpp:355
GFace
Definition: GFace.h:33
GEntity::ParametricSurface
@ ParametricSurface
Definition: GEntity.h:112
GFace::triangles
std::vector< MTriangle * > triangles
Definition: GFace.h:428
MQuadrangle::getVertex
virtual MVertex * getVertex(int num)
Definition: MQuadrangle.h:64
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GEntity::model
GModel * model() const
Definition: GEntity.h:277
SPoint2
Definition: SPoint2.h:12
OS.h
GFace::delEdge
int delEdge(GEdge *edge)
Definition: GFace.cpp:86
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
contextMeshOptions::compoundLcFactor
double compoundLcFactor
Definition: Context.h:49
GFace::getMetricEigenVectors
virtual void getMetricEigenVectors(const SPoint2 &param, double eigVal[2], double eigVec[4]) const
Definition: GFace.cpp:1074
c
static double c(int i, int j, fullMatrix< double > &CA, const std::vector< SPoint3 > &P, const std::vector< SPoint3 > &Q)
Definition: discreteFrechetDistance.cpp:15
GFace::algorithm
int algorithm
Definition: GFace.h:363
MESH_TRANSFINITE
#define MESH_TRANSFINITE
Definition: GmshDefines.h:259
discreteEdge
Definition: discreteEdge.h:12
GFace::~GFace
virtual ~GFace()
Definition: GFace.cpp:52
MVertex
Definition: MVertex.h:24
GEntity::_obb
SOrientedBoundingBox * _obb
Definition: GEntity.h:52
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
GFace::relocateMeshVertices
void relocateMeshVertices()
Definition: GFace.cpp:2206
GEntity::OpenCascadeModel
@ OpenCascadeModel
Definition: GEntity.h:82
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
MVertex::z
double z() const
Definition: MVertex.h:62
GFace::transfiniteArrangement
int transfiniteArrangement
Definition: GFace.h:353
GFace::method
char method
Definition: GFace.h:348
GFace::cross
std::vector< std::vector< SPoint3 > > cross[2]
Definition: GFace.h:405
GFace::setVisibility
virtual void setVisibility(char val, bool recursive=false)
Definition: GFace.cpp:406
VertexArray.h
GFace::addPolygon
void addPolygon(MPolygon *p)
Definition: GFace.h:444
SPoint3
Definition: SPoint3.h:14
GModel::getFaceByTag
GFace * getFaceByTag(int n) const
Definition: GModel.cpp:326
GEdgeLoop::getEdges
void getEdges(std::vector< GEdge * > &edges) const
Definition: GEdgeLoop.cpp:100
ALGO_2D_PACK_PRLGRMS
#define ALGO_2D_PACK_PRLGRMS
Definition: GmshDefines.h:245
GFace::meshAttributes
struct GFace::@18 meshAttributes
SBoundingBox3d::min
SPoint3 min() const
Definition: SBoundingBox3d.h:90
GFace::orientations
virtual std::vector< int > const & orientations() const
Definition: GFace.h:114
Range::high
T high() const
Definition: Range.h:20
GFace::point
virtual GPoint point(double par1, double par2) const =0
SVector3
Definition: SVector3.h:16
SOrientedBoundingBox
Definition: SOrientedBoundingBox.h:33
TYPE_TRI
#define TYPE_TRI
Definition: GmshDefines.h:66
meshGFaceOptimize.h
VertexArray
Definition: VertexArray.h:151
GEntity::getNativeType
virtual ModelType getNativeType() const
Definition: GEntity.h:268
MTriangle::getVertex
virtual MVertex * getVertex(int num)
Definition: MTriangle.h:62
MVertex::onWhat
GEntity * onWhat() const
Definition: MVertex.h:82
GFace::getNumMeshElementsByType
std::size_t getNumMeshElementsByType(const int familyType) const
Definition: GFace.cpp:186
MVertex::point
SPoint3 point() const
Definition: MVertex.h:67
mean_plane::b
double b
Definition: Numeric.h:35
invert_singular_matrix3x3
void invert_singular_matrix3x3(double MM[3][3], double II[3][3])
Definition: Numeric.cpp:650
GModel::destroyMeshCaches
void destroyMeshCaches()
Definition: GModel.cpp:214
myPlane::n
SVector3 n
Definition: GFace.cpp:2471
GModel::getEdgeByTag
GEdge * getEdgeByTag(int n) const
Definition: GModel.cpp:336
GmshMessage.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
GEntity::GmshModel
@ GmshModel
Definition: GEntity.h:81
MAX_LC
#define MAX_LC
Definition: GEntity.h:19
Pair::left
L left() const
Definition: Pair.h:18
GEntity::containsPoint
virtual bool containsPoint(const SPoint3 &pt) const
Definition: GEntity.h:265
mean_plane
Definition: Numeric.h:33
GFace::dim
virtual int dim() const
Definition: GFace.h:175
GEntity
Definition: GEntity.h:31
GPoint
Definition: GPoint.h:13
GEntity::getNumMeshVertices
std::size_t getNumMeshVertices()
Definition: GEntity.h:376
GFace::closestPoint
virtual GPoint closestPoint(const SPoint3 &queryPoint, const double initialGuess[2]) const
Definition: GFace.cpp:1323
GFace::regions
std::list< GRegion * > regions() const
Definition: GFace.h:92
GEntity::getMeshMaster
GEntity * getMeshMaster() const
Definition: GEntity.h:291
debugSurface
int debugSurface
Definition: meshGFace.cpp:3150
meshGFace
Definition: meshGFace.h:21
MElement::getNumVertices
virtual std::size_t getNumVertices() const =0
GFace::l_dirs
std::vector< int > l_dirs
Definition: GFace.h:38
GFace::quadrangles
std::vector< MQuadrangle * > quadrangles
Definition: GFace.h:429
myLine
Definition: GFace.cpp:2486
GEntity::DiscreteCurve
@ DiscreteCurve
Definition: GEntity.h:104
GEdge::addFace
void addFace(GFace *f)
Definition: GEdge.cpp:200
GEntity::Plane
@ Plane
Definition: GEntity.h:105
GEntity::setColor
virtual void setColor(unsigned color, bool recursive=false)
Definition: GEntity.h:319
GPoint::z
double z() const
Definition: GPoint.h:23
GEntity::setVisibility
virtual void setVisibility(char val, bool recursive=false)
Definition: GEntity.h:308
GEntity::period
virtual double period(int dim) const
Definition: GEntity.h:245
GFace::vertices
virtual std::vector< GVertex * > vertices() const
Definition: GFace.cpp:390
GFace::getMetricEigenvalue
virtual double getMetricEigenvalue(const SPoint2 &)
Definition: GFace.cpp:1066
myPlane::p
SPoint3 p
Definition: GFace.cpp:2470
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
Pair::first
L first() const
Definition: Pair.h:22
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
GFace::stl_vertices_xyz
std::vector< SPoint3 > stl_vertices_xyz
Definition: GFace.h:409
SPoint3::x
double x(void) const
Definition: SPoint3.h:125
fullMatrix< double >
GFace::r1
GRegion * r1
Definition: GFace.h:39
GEntity::periodic
virtual bool periodic(int dim) const
Definition: GEntity.h:244
MElement::getEdge
virtual MEdge getEdge(int num) const =0
GEdge.h
MFace
Definition: MFace.h:20
GEdgeLoop
Definition: GEdgeLoop.h:36
GFace::embedded_vertices
std::set< GVertex *, GEntityPtrLessThan > embedded_vertices
Definition: GFace.h:42
myLine::orthogonalProjection
SPoint3 orthogonalProjection(SPoint3 &a)
Definition: GFace.cpp:2533
FieldManager::deleteField
void deleteField(int id)
Definition: Field.cpp:118
Range
Definition: Range.h:10
Pair::second
R second() const
Definition: Pair.h:23
myatan2
double myatan2(double a, double b)
Definition: Numeric.cpp:12
GFace::removeElements
void removeElements(int type)
Definition: GFace.cpp:2787
GFace::edgeLoops
std::vector< GEdgeLoop > edgeLoops
Definition: GFace.h:47
GFace::meshStatistics
struct GFace::@19 meshStatistics
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
GFace::secondDer
virtual void secondDer(const SPoint2 &param, SVector3 &dudu, SVector3 &dvdv, SVector3 &dudv) const =0
FieldManager::setBackgroundFieldId
void setBackgroundFieldId(int id)
Definition: Field.h:165
MElementCut.h
fillMeanPlane
void fillMeanPlane(double res[4], double t1[3], double t2[3], mean_plane &meanPlane)
Definition: Numeric.cpp:1412
GEntity::getNumMeshElements
virtual std::size_t getNumMeshElements() const
Definition: GEntity.h:348
GVertex
Definition: GVertex.h:23
myAngle
double myAngle(const SVector3 &a, const SVector3 &b, const SVector3 &d)
Definition: GFace.cpp:2461
CTX::lc
double lc
Definition: Context.h:234
SBoundingBox3d::empty
bool empty()
Definition: SBoundingBox3d.h:36
MESH_UNSTRUCTURED
#define MESH_UNSTRUCTURED
Definition: GmshDefines.h:260
swap
void swap(double &a, double &b)
Definition: meshTriangulation.cpp:27
myPlane::myPlane
myPlane(const SPoint3 &_p, const SVector3 &_n)
Definition: GFace.cpp:2474
myPlane::eval
double eval(double x, double y, double z)
Definition: GFace.cpp:2479
GFace::embeddedVertices
std::set< GVertex *, GEntityPtrLessThan > & embeddedVertices()
Definition: GFace.h:160
GEntity::useColor
virtual bool useColor()
Definition: GEntity.cpp:43
norm
void norm(const double *vec, double *norm)
Definition: gmshLevelset.cpp:202
GFace::polygons
std::vector< MPolygon * > polygons
Definition: GFace.h:430
Numeric.h
FieldManager::get
Field * get(int id)
Definition: Field.cpp:74
GFace::curvatureDiv
virtual double curvatureDiv(const SPoint2 &param) const
Definition: GFace.cpp:962
GModel
Definition: GModel.h:44
contextMeshOptions::compoundClassify
int compoundClassify
Definition: Context.h:48
GFace::addElement
void addElement(int type, MElement *e)
Definition: GFace.cpp:2739
GFace::fillVertexArray
bool fillVertexArray(bool force=false)
Definition: GFace.cpp:1656
GEntity::DONE
@ DONE
Definition: GEntity.h:130
GFace::isFullyDiscrete
virtual bool isFullyDiscrete()
Definition: GFace.cpp:2945
GFace::getMeanPlaneData
void getMeanPlaneData(double VX[3], double VY[3], double &x, double &y, double &z) const
Definition: GFace.cpp:902
BGM_MeshSize
double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double Z)
Definition: BackgroundMeshTools.cpp:255
GEdge::getBeginVertex
virtual GVertex * getBeginVertex() const
Definition: GEdge.h:63
ExtrudeParams.h
GFace::parFromPoint
virtual SPoint2 parFromPoint(const SPoint3 &, bool onSurface=true, bool convTestXYZ=false) const
Definition: GFace.cpp:1254
GFace::stl_normals
std::vector< SVector3 > stl_normals
Definition: GFace.h:410
FieldManager
Definition: Field.h:145
GEntity::geomType
virtual GeomType geomType() const
Definition: GEntity.h:238
MQuadrangle::reorient
virtual void reorient(int rotation, bool swap)
Definition: MQuadrangle.cpp:464
mean_plane::a
double a
Definition: Numeric.h:35
mean_plane::z
double z
Definition: Numeric.h:36
SVector3::norm
double norm() const
Definition: SVector3.h:33
SPoint3::y
double y(void) const
Definition: SPoint3.h:127
GFace::va_geom_triangles
VertexArray * va_geom_triangles
Definition: GFace.h:416
GEntity::compound
std::vector< GEntity * > compound
Definition: GEntity.h:59
prosca
double prosca(double const a[3], double const b[3])
Definition: Numeric.h:112
GFace::removeElement
void removeElement(int type, MElement *e)
Definition: GFace.cpp:2757
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
GFace::resetMeshAttributes
virtual void resetMeshAttributes()
Definition: GFace.cpp:257
GModel::getFields
FieldManager * getFields()
Definition: GModel.h:325
MElement
Definition: MElement.h:30
GFace::mesh
virtual void mesh(bool verbose)
Definition: GFace.cpp:2142
GFace::stl_triangles
std::vector< int > stl_triangles
Definition: GFace.h:412
GFace::bounds
virtual SBoundingBox3d bounds(bool fast=false)
Definition: GFace.cpp:273
GEntity::tag
int tag() const
Definition: GEntity.h:280
MFaceVertex
Definition: MVertex.h:168
GEntity::BoundaryLayerCurve
@ BoundaryLayerCurve
Definition: GEntity.h:103
discreteFace.h
Field
Definition: Field.h:103
fullMatrix::eig
bool eig(fullVector< double > &eigenValReal, fullVector< double > &eigenValImag, fullMatrix< scalar > &leftEigenVect, fullMatrix< scalar > &rightEigenVect, bool sortRealPart=false)
Definition: fullMatrix.h:727
GFace::fillPointCloud
bool fillPointCloud(double maxDist, std::vector< SPoint3 > *points, std::vector< SPoint2 > *uvpoints=nullptr, std::vector< SVector3 > *normals=nullptr)
Definition: GFace.cpp:1782
SPoint2::setPosition
void setPosition(double xx, double yy)
Definition: SPoint2.h:68
prodve
void prodve(double a[3], double b[3], double c[3])
Definition: Numeric.h:105
SVector3::x
double x(void) const
Definition: SVector3.h:30
CTX::geom
contextGeometryOptions geom
Definition: Context.h:311
GFace::deleteMesh
virtual void deleteMesh()
Definition: GFace.cpp:160
GEntity::parBounds
virtual Range< double > parBounds(int i) const
Definition: GEntity.h:259
GFace::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GFace.cpp:234
MTriangle
Definition: MTriangle.h:26
GEntity::DiscreteSurface
@ DiscreteSurface
Definition: GEntity.h:117
GFace::isOrphan
virtual bool isOrphan()
Definition: GFace.cpp:79
GVertex::x
virtual double x() const =0
LegendrePolynomials::df
void df(int n, double u, double *val)
Definition: orthogonalBasis.cpp:103
SPoint3::distance
double distance(const SPoint3 &p) const
Definition: SPoint3.h:176
FieldManager::getBackgroundField
int getBackgroundField()
Definition: Field.h:178
GFace::getEmbeddedEdges
std::vector< GEdge * > getEmbeddedEdges(bool force=false) const
Definition: GFace.cpp:362
b1
const double b1
Definition: GaussQuadratureHex.cpp:14
mean_plane::y
double y
Definition: Numeric.h:36
meshGFaceQuadrangulateBipartiteLabelling
void meshGFaceQuadrangulateBipartiteLabelling(int faceTag)
Definition: meshGFaceBipartiteLabelling.cpp:358
contextGeometryOptions::oldRuledSurface
int oldRuledSurface
Definition: Context.h:94
GEntity::PartitionSurface
@ PartitionSurface
Definition: GEntity.h:123
GVertex::y
virtual double y() const =0
TYPE_QUA
#define TYPE_QUA
Definition: GmshDefines.h:67
TYPE_POLYG
#define TYPE_POLYG
Definition: GmshDefines.h:72
MVertex::getParameter
virtual bool getParameter(int i, double &par) const
Definition: MVertex.h:97
GEdge::bounds
virtual SBoundingBox3d bounds(bool fast=false)
Definition: GEdge.cpp:212
meshGFace.h
myPlane
Definition: GFace.cpp:2469
SPoint2::x
double x(void) const
Definition: SPoint2.h:86
discreteEdge.h
SBoundingBox3d::transform
bool transform(const std::vector< double > &tfo)
Definition: SBoundingBox3d.h:132
GFace::getAdditionalInfoString
virtual std::string getAdditionalInfoString(bool multline=false)
Definition: GFace.cpp:434
Pair::right
R right() const
Definition: Pair.h:20
Context.h
sys2x2
int sys2x2(double mat[2][2], double b[2], double res[2])
Definition: Numeric.cpp:101
GEntity::getMeshElement
virtual MElement * getMeshElement(std::size_t index) const
Definition: GEntity.h:363
GFace::transfiniteSmoothing
int transfiniteSmoothing
Definition: GFace.h:355
myLine::p
SPoint3 p
Definition: GFace.cpp:2487
mean_plane::plan
double plan[3][3]
Definition: Numeric.h:34
GEdge::parBounds
virtual Range< double > parBounds(int i) const =0
SVector3::y
double y(void) const
Definition: SVector3.h:31
GFace::setColor
virtual void setColor(unsigned int val, bool recursive=false)
Definition: GFace.cpp:420
GFace::edgeCounterparts
std::map< GEdge *, std::pair< GEdge *, int > > edgeCounterparts
Definition: GFace.h:50
GFace::embeddedEdges
std::vector< GEdge * > & embeddedEdges()
Definition: GFace.h:156
z
const double z
Definition: GaussQuadratureQuad.cpp:56
GFace::curvatureMax
virtual double curvatureMax(const SPoint2 &param) const
Definition: GFace.cpp:1020
MQuadrangle.h
contextMeshOptions::algo2d
int algo2d
Definition: Context.h:29
GEdge::compoundCurve
GEdge * compoundCurve
Definition: GEdge.h:47
GFace::computeMeshSizeFieldAccuracy
void computeMeshSizeFieldAccuracy(double &avg, double &max_e, double &min_e, int &nE, int &GS)
Definition: GFace.cpp:922
GEdge::point
virtual GPoint point(double p) const =0
Pair
Definition: Pair.h:10
orientMeshGFace
Definition: meshGFace.h:42
GEdge
Definition: GEdge.h:26
SVector3::z
double z(void) const
Definition: SVector3.h:32
SOrientedBoundingBox::buildOBB
static SOrientedBoundingBox * buildOBB(std::vector< SPoint3 > &vertices)
Definition: SOrientedBoundingBox.cpp:150
GEntity::setMeshMaster
void setMeshMaster(GEntity *)
Definition: GEntity.cpp:128
GFace::meanPlane
mean_plane meanPlane
Definition: GFace.h:40
GFace::storeSTLAsMesh
bool storeSTLAsMesh()
Definition: GFace.cpp:1729
normal3points
void normal3points(double x0, double y0, double z0, double x1, double y1, double z1, double x2, double y2, double z2, double n[3])
Definition: Numeric.cpp:76
GFace::stl_vertices_uv
std::vector< SPoint2 > stl_vertices_uv
Definition: GFace.h:408
GFace::writePY
virtual void writePY(FILE *fp)
Definition: GFace.cpp:597
GFace::reorder
virtual bool reorder(const int elementType, const std::vector< std::size_t > &ordering)
Definition: GFace.cpp:2805
GEntity::vertexCounterparts
std::map< GVertex *, GVertex * > vertexCounterparts
Definition: GEntity.h:62
SPoint3::z
double z(void) const
Definition: SPoint3.h:129
GFace::buildSTLTriangulation
virtual bool buildSTLTriangulation(bool force=false)
Definition: GFace.cpp:1585
GFace::transfinite_vertices
std::vector< std::vector< MVertex * > > transfinite_vertices
Definition: GFace.h:420
VertexArray::finalize
void finalize()
Definition: VertexArray.cpp:138
contextMeshOptions::NewtonConvergenceTestXYZ
int NewtonConvergenceTestXYZ
Definition: Context.h:44
GFace::alignElementsWithMaster
void alignElementsWithMaster()
Definition: GFace.cpp:2879
BackgroundMeshTools.h
GFace::setMeshMaster
void setMeshMaster(GFace *master, const std::vector< double > &)
Definition: GFace.cpp:2222
MPolygon
Definition: MElementCut.h:198
myPlane::a
double a
Definition: GFace.cpp:2472
GModel.h
GFace::GFace
GFace(GModel *model, int tag)
Definition: GFace.cpp:44
normSq
double normSq(const SVector3 &v)
Definition: SVector3.h:148
MVertex::y
double y() const
Definition: MVertex.h:61
GPoint::distance
double distance(GPoint &p)
Definition: GPoint.h:56
GFace::normal
virtual SVector3 normal(const SPoint2 &param) const
Definition: GFace.cpp:1416
GEdge::getEndVertex
virtual GVertex * getEndVertex() const
Definition: GEdge.h:64
GFace::getEmbeddedMeshVertices
std::vector< MVertex * > getEmbeddedMeshVertices(bool force=false) const
Definition: GFace.cpp:369
Range::low
T low() const
Definition: Range.h:18
angle_02pi
double angle_02pi(double A3)
Definition: Numeric.cpp:255
MFace::computeCorrespondence
bool computeCorrespondence(const MFace &, int &, bool &) const
Definition: MFace.cpp:212
norme
double norme(double a[3])
Definition: Numeric.h:123
GFace::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GFace.cpp:181
VertexArray::add
void add(double *x, double *y, double *z, SVector3 *n, unsigned int *col, MElement *ele=nullptr, bool unique=true, bool boundary=false)
Definition: VertexArray.cpp:81
MTriangle::reorient
virtual void reorient(int rotation, bool swap)
Definition: MTriangle.cpp:382
GFace::l_edges
std::vector< GEdge * > l_edges
Definition: GFace.h:37
SBoundingBox3d::max
SPoint3 max() const
Definition: SBoundingBox3d.h:91
GFace::moveToValidRange
void moveToValidRange(SPoint2 &pt) const
Definition: GFace.cpp:2186
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
GFace::XYZtoUV
void XYZtoUV(double X, double Y, double Z, double &U, double &V, double relax, bool onSurface=true, bool convTestXYZ=false) const
Definition: GFace.cpp:1144
GFace::r2
GRegion * r2
Definition: GFace.h:39
GPoint::x
double x() const
Definition: GPoint.h:21
GEntity::Sphere
@ Sphere
Definition: GEntity.h:108
MElement::getNumEdges
virtual int getNumEdges() const =0
GEntity::correspondingVertices
std::map< MVertex *, MVertex * > correspondingVertices
Definition: GEntity.h:406
GEntity::PENDING
@ PENDING
Definition: GEntity.h:130
c1
const double c1
Definition: GaussQuadratureHex.cpp:16
myLine::myLine
myLine()
Definition: GFace.cpp:2489
GFace::curvatures
virtual double curvatures(const SPoint2 &param, SVector3 &dirMax, SVector3 &dirMin, double &curvMax, double &curvMin) const
Definition: GFace.cpp:1031
MQuadrangle
Definition: MQuadrangle.h:26
GEntity::deleteVertexArrays
void deleteVertexArrays()
Definition: GEntity.cpp:27
ALGO_2D_QUAD_QUASI_STRUCT
#define ALGO_2D_QUAD_QUASI_STRUCT
Definition: GmshDefines.h:247
SBoundingBox3d
Definition: SBoundingBox3d.h:21
SPoint3::transform
bool transform(const std::vector< double > &tfo)
Definition: SPoint3.h:78
fullMatrix.h
GFace::writeGEO
virtual void writeGEO(FILE *fp)
Definition: GFace.cpp:530
computeMeanPlaneSimple
void computeMeanPlaneSimple(const std::vector< SPoint3 > &points, mean_plane &meanPlane)
Definition: Numeric.cpp:1438
GFace::buildRepresentationCross
virtual bool buildRepresentationCross(bool force=false)
Definition: GFace.cpp:1427
GFace::computeMeanPlane
void computeMeanPlane()
Definition: GFace.cpp:645
GEntity::RuledSurface
@ RuledSurface
Definition: GEntity.h:111
MVertex::x
double x() const
Definition: MVertex.h:60
SVector3::normalize
double normalize()
Definition: SVector3.h:38
FieldManager::setBackgroundField
void setBackgroundField(Field *BGF)
Definition: Field.cpp:3224
discreteFace
Definition: discreteFace.h:18
GFace::addTriangle
void addTriangle(MTriangle *t)
Definition: GFace.h:436
SPoint2::y
double y(void) const
Definition: SPoint2.h:88
GEdgeLoop::getSigns
void getSigns(std::vector< int > &signs) const
Definition: GEdgeLoop.cpp:106