12 #include "GmshConfig.h"
25 #if defined(HAVE_MESH)
33 #if defined(HAVE_ALGLIB)
34 #include <optimization.h>
38 #if defined(HAVE_QUADMESHINGTOOLS)
40 #include "qmtCrossField.h"
41 #include "qmtMeshUtils.h"
45 :
GEntity(model, tag), r1(nullptr), r2(nullptr), va_geom_triangles(nullptr), compoundSurface(nullptr)
81 if (
model()->getNumRegions())
88 const auto found = std::find(
l_edges.begin(),
l_edges.end(), edge);
102 if (
l_dirs.size() <
static_cast<std::size_t
>(pos))
108 const auto orientation =
l_dirs.at(pos);
115 std::vector<GEdge *> e;
116 for (std::size_t i = 0; i < tagEdges.size(); i++)
126 Msg::Error(
"Unknown curve %d in surface %d", tagEdges[i],
tag());
136 if (signEdges.size() != tagEdges.size())
138 Msg::Error(
"Wrong number of curve signs in surface %d",
tag());
141 for (std::vector<int>::size_type i = 0; i < tagEdges.size(); i++)
149 l_dirs.push_back(signEdges[i]);
155 Msg::Error(
"Unknown curve %d in surface %d", tagEdges[i],
tag());
166 for (std::size_t i = 0; i <
triangles.size(); i++)
169 for (std::size_t i = 0; i <
quadrangles.size(); i++)
172 for (std::size_t i = 0; i <
polygons.size(); i++)
201 for (std::size_t i = 0; i <
polygons.size(); i++)
280 res += ge->bounds(fast);
300 for (
int i = 0; i < N; i++)
305 std::vector<GEdge *>
const &eds =
edges();
306 for (
auto ed = eds.begin(); ed != eds.end(); ed++)
308 int N2 = (*ed)->getNumMeshVertices();
309 for (
int i = 0; i < N2; i++)
311 MVertex *mv = (*ed)->getMeshVertex(i);
315 if ((*ed)->getBeginVertex())
317 SPoint3 pt1((*ed)->getBeginVertex()->x(), (*ed)->getBeginVertex()->y(),
318 (*ed)->getBeginVertex()->z());
321 if ((*ed)->getEndVertex())
323 SPoint3 pt2((*ed)->getEndVertex()->x(), (*ed)->getEndVertex()->y(), (*ed)->getEndVertex()->z());
336 std::vector<GEdge *>
const &b_edges =
edges();
338 for (
auto b_edge = b_edges.begin(); b_edge != b_edges.end(); b_edge++)
341 for (
int j = 0; j < N; j++)
343 double t = tr.
low() + (double)j / (
double)(N - 1) * (tr.
high() - tr.
low());
344 GPoint p = (*b_edge)->point(t);
358 return std::vector<GVertex *>();
365 return std::vector<GEdge *>();
372 return std::vector<MVertex *>();
374 std::set<MVertex *> tmp;
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());
385 tmp.insert((*it)->mesh_vertices.begin(), (*it)->mesh_vertices.end());
387 return std::vector<MVertex *>(tmp.begin(), tmp.end());
392 std::set<GVertex *, GEntityPtrLessThan> v;
395 GVertex *
const v1 = ge->getBeginVertex();
399 GVertex *
const v2 = ge->getEndVertex();
403 return std::vector<GVertex *>(v.begin(), v.end());
412 e->setVisibility(val, recursive);
414 e->setVisibility(val, recursive);
416 v->setVisibility(val);
426 e->setColor(val, recursive);
428 e->setColor(val, recursive);
436 std::ostringstream sstream;
439 sstream <<
"Boundary curves: " <<
l_edges.front()->tag() <<
", ...," <<
l_edges.back()->tag();
447 sstream <<
"Boundary curves: ";
452 sstream << (*it)->tag();
462 sstream <<
"On boundary of volumes: ";
465 sstream <<
r1->
tag();
470 sstream <<
r2->
tag();
479 sstream <<
"Embedded curves: ";
484 sstream << (*it)->tag();
494 sstream <<
"Embedded points: ";
499 sstream << (*it)->tag();
511 sstream <<
"Mesh attributes:";
513 sstream <<
" recombined";
515 sstream <<
" transfinite";
517 sstream <<
" extruded";
519 sstream <<
" reverse";
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);
535 std::vector<GEdge *>
const &edg =
edges();
537 if (edg.size() && dir.size() == edg.size())
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++)
548 fprintf(fp,
", %d", num[i] * ori[i]);
550 fprintf(fp,
"{%d", num[i] * ori[i]);
555 fprintf(fp,
"Plane Surface(%d) = {%d};\n",
tag(),
tag());
557 else if (edg.size() == 3 || edg.size() == 4)
559 fprintf(fp,
"Surface(%d) = {%d};\n",
tag(),
tag());
568 fprintf(fp,
"Line {%d} In Surface {%d};\n", (*it)->tag(),
tag());
571 fprintf(fp,
"Point {%d} In Surface {%d};\n", (*it)->tag(),
tag());
575 fprintf(fp,
"Transfinite Surface {%d}",
tag());
591 fprintf(fp,
"Recombine Surface {%d};\n",
tag());
594 fprintf(fp,
"Reverse Surface {%d};\n",
tag());
607 std::size_t numcl = 0;
608 for (std::size_t i = 0; i <
edgeLoops.size(); i++)
610 std::vector<GEdge *>
edges;
611 std::vector<int> signs;
614 if (
edges.size() &&
edges.size() == signs.size())
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++)
621 fprintf(fp,
"%d",
edges[j]->
tag() * signs[j]);
629 fprintf(fp,
"gmsh.model.%s.addPlaneSurface([", factory);
630 for (std::size_t i = 0; i < numcl; i++)
634 fprintf(fp,
"s%d_cl%lu",
tag(), i + 1);
636 fprintf(fp,
"], %d)\n",
tag());
647 std::vector<SPoint3> pts;
657 std::vector<GEdge *>
const &edg =
edges();
667 pts.push_back(
SPoint3(p1.
x(), p1.
y(), p1.
z()));
669 pts.push_back(
SPoint3(p2.
x(), p2.
y(), p2.
z()));
672 double res[4] = {0., 0., 0., 0.}, xm = 0., ym = 0., zm = 0.;
676 for (std::size_t i = 2; i < pts.size(); i++)
698 double ex[3], t1[3], t2[3];
699 ex[0] = ex[1] = ex[2] = 0.0;
702 else if (res[1] == 0.)
710 res[3] = (xm * res[0] + ym * res[1] + zm * res[2]);
716 std::vector<GVertex *>
const &verts =
vertices();
717 for (
auto itv = verts.begin(); itv != verts.end(); itv++)
720 pts.push_back(
SPoint3(v->
x(), v->
y(), v->
z()));
723 bool colinear = (pts.size() < 3);
726 SVector3 d01(pts[0], pts[1]), d02(pts[0], pts[2]);
733 Msg::Debug(
"Adding curve points (%d) to compute mean plane of surface %d", pts.size(),
tag());
734 std::vector<GEdge *>
const &edg =
edges();
737 if (e->mesh_vertices.size() > 1)
739 for (std::size_t i = 0; i < e->mesh_vertices.size(); i++)
740 pts.push_back(e->mesh_vertices[i]->point());
746 pts.push_back(
SPoint3(p1.
x(), p1.
y(), p1.
z()));
748 pts.push_back(
SPoint3(p2.
x(), p2.
y(), p2.
z()));
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()));
778 double xm = 0., ym = 0., zm = 0.;
779 int ndata = points.size();
781 for (
int i = 0; i < ndata; i++)
793 for (
int i = 0; i < ndata; i++)
795 U(i, 0) = points[i].x() - xm;
796 U(i, 1) = points[i].y() - ym;
797 U(i, 2) = points[i].z() - zm;
800 double res[4], svd[3];
805 if (std::abs(svd[0]) < std::abs(svd[1]) && std::abs(svd[0]) < std::abs(svd[2]))
807 else if (std::abs(svd[1]) < std::abs(svd[0]) && std::abs(svd[1]) < std::abs(svd[2]))
816 double ex[3], t1[3], t2[3];
821 double res2[3],
c[3], sinc, angplan;
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();
841 double const cosc =
prosca(res, res2);
842 sinc = std::sqrt(
c[0] *
c[0] +
c[1] *
c[1] +
c[2] *
c[2]);
845 if ((angplan > 70 && angplan < 110) || (angplan > 260 && angplan < 280))
847 Msg::Info(
"SVD failed (angle=%g): using rough algo...", angplan);
855 ex[0] = ex[1] = ex[2] = 0.0;
858 else if (res[1] == 0.)
869 res[3] = (xm * res[0] + ym * res[1] + zm * res[2]);
874 Msg::Debug(
"SVD : %g,%g,%g (min=%d)", svd[0], svd[1], svd[2], min);
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]);
886 std::vector<GVertex *>
const &verts =
vertices();
887 for (
auto itv = verts.begin(); itv != verts.end(); itv++)
891 if (std::abs(d) > lc * 1.e-3)
895 Msg::Debug(
"Control point %d = (%g,%g,%g), val=%g", v->
tag(), v->
x(), v->
y(), v->
z(), d);
917 for (
int i = 0; i < 3; i++)
918 for (
int j = 0; j < 3; j++)
924 #if defined(HAVE_MESH)
925 std::set<MEdge, MEdgeLessThan> es;
938 double oneoversqr2 = 1. / sqrt(2.);
939 double sqr2 = sqrt(2.);
940 for (
auto it = es.begin(); it != es.end(); ++it)
942 double u1, v1, u2, v2;
943 MVertex *vert1 = it->getVertex(0);
946 MVertex *vert2 = it->getVertex(1);
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)
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);
971 const double eps = 1.e-5;
979 double detJ =
norm(nml);
985 if (param.
x() - eps < 0.0)
995 if (param.
y() - eps < 0.0)
1006 SVector3 dndu = 100000 * (n2 - n1);
1007 SVector3 dndv = 100000 * (n4 - n3);
1014 double ddu =
dot(dndu, du);
1015 double ddv =
dot(dndv, dv);
1017 return (fabs(ddu) + fabs(ddv)) / detJ;
1025 double eigVal[2], eigVec[8];
1028 return fabs(eigVal[1]);
1032 double &curvMin)
const
1038 dirMax = D1.
first();
1047 dirMax = D1.
first();
1054 double eigVal[2], eigVec[8];
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();
1068 Msg::Error(
"Metric eigenvalue is not implemented for this type of surface");
1091 form1[0][0] =
normSq(du);
1092 form1[1][1] =
normSq(dv);
1093 form1[0][1] = form1[1][0] =
dot(du, dv);
1097 form2[0][0] =
dot(nor, dudu);
1098 form2[1][1] =
dot(nor, dvdv);
1099 form2[0][1] = form2[1][0] =
dot(nor, dudv);
1102 double inv_form1[2][2];
1103 double denom = (form1[0][0] * form1[1][1] - form1[1][0] * form1[0][1]);
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];
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];
1121 if (N.
eig(dr, di, vl, vr,
true))
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)
1138 for (
int i = 0; i < 2; i++)
1140 for (
int i = 0; i < 4; i++)
1144 void GFace::XYZtoUV(
double X,
double Y,
double Z,
double &U,
double &V,
double relax,
bool onSurface,
1145 bool convTestXYZ)
const
1150 const double Precision = onSurface ? 1.e-8 : 1.e-3;
1151 const int MaxIter = onSurface ? 25 : 10;
1152 const int NumInitGuess = 9;
1155 double Unew = 0., Vnew = 0., err, err2;
1157 double mat[3][3], jac[3][3];
1158 double umin, umax, vmin, vmax;
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};
1170 const double tol = Precision * (std::pow(umax - umin, 2) + std::pow(vmax - vmin, 2));
1171 for (
int i = 0; i < NumInitGuess; i++)
1173 initu[i] = umin + initu[i] * (umax - umin);
1174 initv[i] = vmin + initv[i] * (vmax - vmin);
1177 for (
int i = 0; i < NumInitGuess; i++)
1179 for (
int j = 0; j < NumInitGuess; j++)
1187 err2 = std::sqrt(std::pow(X - P.
x(), 2) + std::pow(Y - P.
y(), 2) + std::pow(Z - P.
z(), 2));
1191 while (err > tol && iter < MaxIter)
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();
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()));
1210 if ((Unew > umax + tol || Unew < umin - tol) && (Vnew > vmax + tol || Vnew < vmin - tol))
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));
1221 if (iter < MaxIter && err <= tol && Unew <= umax && Vnew <= vmax && Unew >= umin && Vnew >= vmin)
1223 if (onSurface && err2 > 1.e-4 *
CTX::instance()->lc && !testXYZ)
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());
1230 if (onSurface && err2 > 1.e-4 *
CTX::instance()->lc && testXYZ)
1246 Msg::Warning(
"Inverse surface mapping could not converge");
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);
1259 double U = 0., V = 0.;
1260 XYZtoUV(p.
x(), p.
y(), p.
z(), U, V, 1.0, onSurface, convTestXYZ);
1264 #if defined(HAVE_ALGLIB)
1281 const GFace *get_face()
1285 void set_face(
const GFace *face)
1293 void set_point(
const SPoint3 &_point)
1300 void bfgs_callback(
const alglib::real_1d_array &x,
double &func, alglib::real_1d_array &grad,
void *ptr)
1302 auto *w =
static_cast<data_wrapper *
>(ptr);
1304 const GFace *gf = w->get_face();
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());
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();
1328 #if defined(HAVE_ALGLIB)
1330 double min_u = initialGuess[0];
1331 double min_v = initialGuess[1];
1334 double min_dist = queryPoint.
distance(spnt);
1337 const double nGuesses = 10.;
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)
1345 for (
double v = vv.
low(); v <= vv.
high() + epsV; v += dv)
1349 double dist = queryPoint.
distance(spnt);
1350 if (dist < min_dist)
1362 alglib::ae_int_t
dim = 2;
1363 alglib::ae_int_t corr = 2;
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);
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);
1379 w.set_point(queryPoint);
1381 minlbfgsoptimize(state, bfgs_callback,
nullptr, &w);
1384 alglib::minlbfgsreport rep;
1385 minlbfgsresults(state, x, rep);
1391 Msg::Warning(
"Closest point failed, computing from parametric coordinate");
1397 Msg::Error(
"Closest point not implemented for this type of surface");
1410 if ((pt.
x() >= uu.
low() && pt.
x() <= uu.
high()) && (pt.
y() >= vv.
low() && pt.
y() <= vv.
high()))
1429 if (
cross[0].size())
1443 if (
cross[0].empty())
1445 cross[0].push_back(std::vector<SPoint3>());
1457 std::vector<GEdge *> ed =
edges();
1458 for (
auto it = ed.begin(); it != ed.end(); it++)
1465 double t0 = t_bounds.
low(), dt = t_bounds.
high() - t_bounds.
low();
1466 for (
int i = 0; i < N; i++)
1468 double t = t0 + dt / (double)(N - 1) * i;
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());
1490 for (
int dir = 0; dir < 2; dir++)
1492 cross[dir].push_back(std::vector<SPoint3>());
1493 for (
int i = 0; i < N; i++)
1495 double t = (double)i / (
double)(N - 1);
1516 cross[dir].back().push_back(pt);
1520 if (
cross[dir].back().size())
1521 cross[dir].push_back(std::vector<SPoint3>());
1524 while (!
cross[dir].empty() &&
cross[dir].back().empty())
1525 cross[dir].pop_back();
1534 if (
cross[0].size() > 0 &&
cross[0][0].size() > 1 &&
cross[1].size() > 0 &&
cross[1][0].size() > 1)
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++)
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];
1556 std::vector<SPoint3>
c1 = {p1, p2};
1557 std::vector<SPoint3> c2 = {p2, p3};
1559 cross[0].push_back(c2);
1563 std::vector<SPoint3>
c1 = {p1, p4};
1564 std::vector<SPoint3> c2 = {p4, p3};
1566 cross[0].push_back(c2);
1576 if (
cross[0].empty())
1578 cross[0].push_back(std::vector<SPoint3>());
1597 std::map<MVertex *, int, MVertexPtrLessThan> nodes;
1598 for (std::size_t i = 0; i <
triangles.size(); i++)
1600 for (
int j = 0; j < 3; j++)
1603 if (!nodes.count(v))
1610 for (std::size_t i = 0; i <
triangles.size(); i++)
1612 for (
int j = 0; j < 3; j++)
1622 const int nu = 64, nv = 64;
1625 double umin = ubounds.
low(), umax = ubounds.
high();
1626 double vmin = vbounds.
low(), vmax = vbounds.
high();
1627 for (
int i = 0; i < nu; i++)
1629 for (
int j = 0; j < nv; j++)
1631 double u = umin + (double)i / (
double)(nu - 1) * (umax - umin);
1632 double v = vmin + (double)j / (
double)(nv - 1) * (vmax - vmin);
1638 for (
int i = 0; i < nu - 1; i++)
1640 for (
int j = 0; j < nv - 1; j++)
1673 unsigned int col[4] = {
c,
c,
c,
c};
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()};
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()};
1766 std::set<GEdge *> single_seams;
1769 if ((*it)->isSeam(
this))
1772 auto it2 = single_seams.find(*it);
1773 if (it2 != single_seams.end())
1774 single_seams.erase(it2);
1776 single_seams.insert(*it);
1779 return nSeams - single_seams.size();
1783 std::vector<SVector3> *normals)
1798 int N = std::max((
int)(maxEdge / maxDist), 1);
1799 for (
double u = 0.; u < 1.; u += 1. / N)
1801 for (
double v = 0.; v < 1 - u; v += 1. / N)
1803 SPoint3 p = p0 * (1. - u - v) + p1 * u + p2 * v;
1804 points->push_back(p);
1820 int N = std::max((
int)(maxEdge / maxDist), 1);
1821 for (
double u = 0.; u < 1.; u += 1. / N)
1823 for (
double v = 0.; v < 1 - u; v += 1. / N)
1825 SPoint2 p = p0 * (1. - u - v) + p1 * u + p2 * v;
1827 points->push_back(
SPoint3(gp.x(), gp.y(), gp.z()));
1829 uvpoints->push_back(p);
1831 normals->push_back(
normal(p));
1840 int N = std::max((
int)(
bounds().diag() / maxDist), 2);
1843 for (
int i = 0; i < N; i++)
1845 for (
int j = 0; j < N; j++)
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());
1852 points->push_back(
SPoint3(gp.x(), gp.y(), gp.z()));
1854 uvpoints->push_back(
SPoint2(t1, t2));
1863 #if defined(HAVE_MESH)
1865 #if defined(HAVE_QUADMESHINGTOOLS)
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);
1877 static int meshCompoundMakeQuads(
GFace *gf)
1889 static int meshCompoundComputeCrossFieldWithHeatEquation(
GFace *gf)
1895 #if defined(HAVE_QUADMESHINGTOOLS)
1897 std::vector<std::array<double, 3>> triEdgeTheta;
1898 std::vector<MLine *> lines;
1900 for (
auto ge :
edges)
1901 lines.insert(lines.end(), ge->lines.begin(), ge->lines.end());
1903 int scf = computeCrossFieldWithHeatEquation(4, gf->
triangles, lines, triEdgeTheta);
1911 std::vector<std::array<double, 9>> triangleDirections;
1912 int sc = convertToPerTriangleCrossFieldDirections(4, gf->
triangles, triEdgeTheta, triangleDirections);
1915 Msg::Warning(
"- Face %i: failed to resample cross field at triangle corners", gf->
tag());
1918 std::unordered_map<MVertex *, double> sizeMap;
1920 int sts = fillSizemapFromScalarBackgroundField(gf->
model(), gf->
triangles, sizeMap);
1923 Msg::Warning(
"- Face %i: failed to fill size map from background field", gf->
tag());
1926 std::vector<std::array<double, 5>> singularityList;
1935 buildBackgroundField(gf->
model(), gf->
triangles, triangleDirections, sizeMap, singularityList,
"guiding_field");
1941 Msg::Warning(
"failed to build background guiding field");
1951 static void meshCompound(
GFace *gf,
bool verbose)
1977 std::vector<GFace *> triangles_tag;
1979 std::set<GEdge *, GEntityPtrLessThan> bnd, emb1;
1980 std::set<GVertex *, GEntityPtrLessThan> emb0;
1982 for (std::size_t i = 0; i < gf->
compound.size(); 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++)
1993 if (bnd.find(
edges[j]) == bnd.end())
1994 bnd.insert(
edges[j]);
1996 bnd.erase(
edges[j]);
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());
2006 c->triangles.clear();
2007 c->quadrangles.clear();
2008 c->mesh_vertices.clear();
2010 c->compoundSurface =
df;
2013 phys.insert(
c->physicals.begin(),
c->physicals.end());
2014 c->physicals.clear();
2018 std::set<GEdge *, GEntityPtrLessThan> bndc;
2019 for (
auto it = bnd.begin(); it != bnd.end(); it++)
2027 std::vector<GEdge *> ed(bndc.begin(), bndc.end());
2030 for (
auto it = emb1.begin(); it != emb1.end(); it++)
2031 df->addEmbeddedEdge(*it);
2033 for (
auto it = emb0.begin(); it != emb0.end(); it++)
2034 df->addEmbeddedVertex(*it);
2038 Field *backgroundField = fields->
get(BGTAG);
2040 if (
df->createGeometry())
2042 Msg::Error(
"Could not create geometry of discrete surface %d (check "
2043 "orientation of input triangulations)",
2048 int scf = meshCompoundComputeCrossFieldWithHeatEquation(
df);
2057 df->triangles.clear();
2058 df->quadrangles.clear();
2059 df->mesh_vertices.clear();
2063 meshCompoundMakeQuads(
df);
2073 df->physicals.clear();
2074 df->physicals.insert(
df->physicals.end(), phys.begin(), phys.end());
2078 for (std::size_t i = 0; i <
df->mesh_vertices.size(); i++)
2081 df->mesh_vertices[i]->getParameter(0, u);
2082 df->mesh_vertices[i]->getParameter(1, v);
2085 int position =
df->trianglePosition(u, v, U, V);
2086 if (position >= 0 && position < (
int)triangles_tag.size())
2088 triangles_tag[position]->mesh_vertices.push_back(
df->mesh_vertices[i]);
2089 df->mesh_vertices[i]->setEntity(triangles_tag[position]);
2098 for (std::size_t i = 0; i <
df->triangles.size(); i++)
2102 for (
int i = 0; i < 3; i++)
2117 for (std::size_t i = 0; i <
df->quadrangles.size(); i++)
2121 for (
int i = 0; i < 4; i++)
2136 df->triangles.clear();
2137 df->quadrangles.clear();
2138 df->mesh_vertices.clear();
2150 #if defined(HAVE_MESH)
2155 mesher(
this, verbose);
2166 for (std::size_t i = 0; i <
compound.size(); i++)
2177 meshCompound(
this, verbose);
2188 for (
int i = 0; i < 2; i++)
2193 double tol = 1e-6 * (range.
high() - range.
low());
2194 if (pt[i] < range.
low() - tol)
2196 if (pt[i] > range.
high() + tol)
2198 if (pt[i] < range.
low())
2199 pt[i] = range.
low();
2200 if (pt[i] > range.
high())
2201 pt[i] = range.
high();
2211 double u0 = 0., u1 = 0.;
2224 Msg::Info(
"Setting mesh master using transformation");
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)
2231 GVertex *v0 = (*eIter)->getBeginVertex();
2232 GVertex *v1 = (*eIter)->getEndVertex();
2235 l_vertices.insert(v0);
2236 l_vertices.insert(v1);
2237 l_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
2242 GVertex *v0 = (*eIter)->getBeginVertex();
2243 GVertex *v1 = (*eIter)->getEndVertex();
2246 l_vertices.insert(v0);
2247 l_vertices.insert(v1);
2248 l_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
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)
2259 GVertex *v0 = (*eIter)->getBeginVertex();
2260 GVertex *v1 = (*eIter)->getEndVertex();
2263 m_vertices.insert(v0);
2264 m_vertices.insert(v1);
2265 m_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
2268 std::vector<GEdge *>
const &m_embedded_edges = master->
embeddedEdges();
2269 for (
auto eIter = m_embedded_edges.begin(); eIter != m_embedded_edges.end(); eIter++)
2271 GVertex *v0 = (*eIter)->getBeginVertex();
2272 GVertex *v1 = (*eIter)->getEndVertex();
2275 m_vertices.insert(v0);
2276 m_vertices.insert(v1);
2277 m_vtxToEdge.insert(std::make_pair(std::make_pair(v0, v1), *eIter));
2280 std::set<GVertex *, GEntityPtrLessThan> m_embedded_vertices = master->
embeddedVertices();
2281 m_vertices.insert(m_embedded_vertices.begin(), m_embedded_vertices.end());
2284 if (l_vertices.size() != m_vertices.size())
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());
2291 if (l_vtxToEdge.size() != m_vtxToEdge.size())
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());
2300 std::map<GVertex *, GVertex *> gVertexCounterparts;
2301 for (
auto mvIter = m_vertices.begin(); mvIter != m_vertices.end(); ++mvIter)
2305 SPoint3 xyzTfo((*mvIter)->x(), (*mvIter)->y(), (*mvIter)->z());
2310 double dist_min = 1.e22;
2311 for (
auto lvIter = l_vertices.begin(); lvIter != l_vertices.end(); ++lvIter)
2313 SPoint3 xyz((*lvIter)->x(), (*lvIter)->y(), (*lvIter)->z());
2315 dist_min = std::min(dist_min, dist.
norm());
2323 if (l_vertex ==
nullptr)
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,
2331 gVertexCounterparts[l_vertex] = m_vertex;
2334 if (gVertexCounterparts.size() != m_vertices.size())
2336 Msg::Error(
"Could not find all point correspondences for the periodic "
2337 "connection from surface %d to %d",
2343 std::map<GEdge *, std::pair<GEdge *, int>> gEdgeCounterparts;
2345 for (
auto lv2eIter = l_vtxToEdge.begin(); lv2eIter != l_vtxToEdge.end(); lv2eIter++)
2347 std::pair<GVertex *, GVertex *> lPair = lv2eIter->first;
2348 GEdge *localEdge = lv2eIter->second;
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);
2355 GEdge *masterEdge =
nullptr;
2358 if (!masterEdge && numf == 1 && (numb == 0 || forward.first == forward.second))
2360 masterEdge = m_vtxToEdge.find(forward)->second;
2363 if (!masterEdge && numb == 1 && (numf == 0 || forward.first == forward.second))
2365 masterEdge = m_vtxToEdge.find(backward)->second;
2374 double tol = localbb.
diag() * 1e-3;
2377 if (!masterEdge && numf)
2379 auto ret = m_vtxToEdge.equal_range(forward);
2380 for (
auto it = ret.first; it != ret.second; it++)
2382 GEdge *ge = it->second;
2387 SPoint3 p1(localp.
x(), localp.
y(), localp.
z());
2388 SPoint3 p2(masterp.
x(), masterp.
y(), masterp.
z());
2407 if (!masterEdge && numb)
2409 auto ret = m_vtxToEdge.equal_range(backward);
2410 for (
auto it = ret.first; it != ret.second; it++)
2412 GEdge *ge = it->second;
2417 SPoint3 p1(localp.
x(), localp.
y(), localp.
z());
2418 SPoint3 p2(masterp.
x(), masterp.
y(), masterp.
z());
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());
2450 Msg::Info(
"Setting curve master %d - %d", localEdge->
tag(), masterEdge->
tag());
2452 gEdgeCounterparts[localEdge] = std::make_pair(masterEdge, sign);
2463 double const cosTheta =
dot(a, b);
2465 return std::atan2(sinTheta, cosTheta);
2479 double eval(
double x,
double y,
double z)
2481 return n.
x() * x +
n.
y() * y +
n.
z() *
z +
a;
2495 if (
t.
norm() == 0.0)
2497 Msg::Error(
"parallel planes do not intersect");
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];
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};
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};
2516 Msg::Error(
"parallel planes do not intersect");
2537 const double u =
dot(a -
p,
t);
2544 std::map<GVertex *, GVertex *> vs2vt;
2552 auto adnksd = edgeCopies.find(le->
tag());
2554 if (adnksd != edgeCopies.end())
2555 source_e = adnksd->second;
2559 adnksd = edgeCopies.find(-(*it)->tag());
2560 if (adnksd != edgeCopies.end())
2561 source_e = adnksd->second;
2564 Msg::Error(
"Could not find curve counterpart %d in slave surface %d", (*it)->tag(), master->
tag());
2574 if (source_e * sign > 0)
2589 bool translation =
true;
2593 for (
auto it = vs2vt.begin(); it != vs2vt.end(); ++it)
2598 DX =
SVector3(vt->
x() - vs->
x(), vt->
y() - vs->
y(), vt->
z() - vs->
z());
2601 SVector3 DX2(vt->
x() - vs->
x(), vt->
y() - vs->
y(), vt->
z() - vs->
z());
2603 if (DDX.
norm() > DX.
norm() * 1.e-5)
2604 translation =
false;
2609 std::vector<double> tfo(16);
2613 Msg::Info(
"Periodic mesh translation found between %d and %d: dx = (%g,%g,%g)",
tag(), master->
tag(), DX.
x(),
2616 for (
size_t i = 0; i < 16; i++)
2618 for (
size_t i = 0; i < 4; i++)
2627 bool rotation =
false;
2633 std::vector<SPoint3> mps, mpt;
2634 for (
auto it = vs2vt.begin(); it != vs2vt.end(); ++it)
2638 mps.push_back(
SPoint3(vs->
x(), vs->
y(), vs->
z()));
2639 mpt.push_back(
SPoint3(vt->
x(), vt->
y(), vt->
z()));
2646 SVector3(mean_source.
a, mean_source.
b, mean_source.
c));
2648 SVector3(mean_target.
a, mean_target.
b, mean_target.
c));
2650 LINE =
myLine(PLANE_SOURCE, PLANE_TARGET);
2655 for (
auto it = vs2vt.begin(); it != vs2vt.end(); ++it)
2668 if (dist2.
norm() > 1.e-8 * dist1.
norm())
2674 if (t1.
norm() > 1.e-8 * dist1.
norm())
2680 double ANGLE2 =
myAngle(t1, t2, LINE.
t);
2681 if (fabs(ANGLE2 - ANGLE) > 1.e-8)
2693 Msg::Info(
"Periodic mesh rotation found: axis (%g,%g,%g) point (%g %g "
2695 LINE.
t.
x(), LINE.
t.
y(), LINE.
t.
z(), LINE.
p.
x(), LINE.
p.
y(), LINE.
p.
z(), ANGLE * 180 / M_PI);
2697 double ux = LINE.
t.
x();
2698 double uy = LINE.
t.
y();
2699 double uz = LINE.
t.
z();
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);
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);
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));
2713 double origin[3] = {LINE.
p.
x(), LINE.
p.
y(), LINE.
p.
z()};
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++)
2726 Msg::Error(
"Only rotations or translations can currently be computed "
2727 "automatically for periodic surfaces: surface %d not meshed",
2753 Msg::Error(
"Trying to add unsupported element in surface %d",
tag());
2783 Msg::Error(
"Trying to remove unsupported element in surface %d",
tag());
2801 Msg::Error(
"Trying to remove unsupported elements in surface %d",
tag());
2809 if (
triangles.front()->getTypeForMSH() == elementType)
2811 if (ordering.size() !=
triangles.size())
2814 for (
auto it = ordering.begin(); it != ordering.end(); ++it)
2820 std::vector<MTriangle *> newTrianglesOrder(
triangles.size());
2821 for (std::size_t i = 0; i < ordering.size(); i++)
2823 newTrianglesOrder[i] =
triangles[ordering[i]];
2825 triangles = std::move(newTrianglesOrder);
2832 if (
quadrangles.front()->getTypeForMSH() == elementType)
2837 for (
auto it = ordering.begin(); it != ordering.end(); ++it)
2843 std::vector<MQuadrangle *> newQuadranglesOrder(
quadrangles.size());
2844 for (std::size_t i = 0; i < ordering.size(); i++)
2846 newQuadranglesOrder[i] =
quadrangles[ordering[i]];
2855 if (
polygons.front()->getTypeForMSH() == elementType)
2857 if (ordering.size() !=
polygons.size())
2860 for (
auto it = ordering.begin(); it != ordering.end(); ++it)
2866 std::vector<MPolygon *> newPolygonsOrder(
polygons.size());
2867 for (std::size_t i = 0; i < ordering.size(); i++)
2869 newPolygonsOrder[i] =
polygons[ordering[i]];
2871 polygons = std::move(newPolygonsOrder);
2885 std::set<MFace, MFaceLessThan> srcFaces;
2890 std::vector<MVertex *> vtcs;
2896 srcFaces.insert(
MFace(vtcs));
2902 std::vector<MVertex *> vtcs;
2908 vtcs.push_back(cIter->second);
2913 auto sIter = srcFaces.find(mf);
2915 if (sIter == srcFaces.end())
2928 auto *tri =
dynamic_cast<MTriangle *
>(face);
2950 if (
df &&
df->haveParametrization())
2952 std::vector<GEdge *> e =
edges();
2953 for (std::size_t i = 0; i < e.size(); i++)
2958 if (de && de->haveParametrization())