12 #include "GmshConfig.h"
30 #if defined(HAVE_MESH)
35 #if defined(HAVE_SOLVER)
41 #if defined(HAVE_MESH)
44 getModelEdge(
GModel *gm, std::vector<GFace *> &gfs,
45 std::vector<std::pair<
GEdge *, std::vector<GFace *> > > &newEdges,
48 if(gfs.size() == 2 && gfs[0] == gfs[1])
return nullptr;
49 for(
size_t i = 0; i < newEdges.size(); i++) {
50 if(gfs.size() == newEdges[i].second.size()) {
52 for(
size_t j = 0; j < newEdges[i].second.size(); j++)
53 if(std::find(gfs.begin(), gfs.end(), newEdges[i].second[j]) ==
58 if(found)
return newEdges[i].first;
63 newEdges.push_back(std::make_pair(ge, gfs));
71 for(
int i = 0; i < 3; i++) {
73 auto it = tris.find(e);
74 if(it == tris.end()) {
75 std::vector<MTriangle *> v;
80 it->second.push_back(t);
88 if(threshold >= M_PI - 1e-12)
return false;
89 if(threshold <= 0)
return true;
92 double a =
angle(v1, v2);
93 if((a > threshold && a < M_PI - threshold) ||
94 (a > M_PI + threshold && a < 2 * M_PI - threshold)) {
95 Msg::Debug(
"Breaking curve for angle = %g", a);
105 #if defined(HAVE_MESH)
114 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
115 if(gf->
triangles[i]->getPolynomialOrder() > 1) {
123 Msg::Warning(
"Reverting to first order mesh for classification");
129 std::set<MLine *, MLinePtrLessThan> lines;
130 std::vector<GEdge *> edgesToRemove;
132 for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
133 lines.insert((*it)->lines[i]);
135 edgesToRemove.push_back(*it);
137 for(std::size_t i = 0; i < edgesToRemove.size(); ++i) {
138 gm->
remove(edgesToRemove[i]);
142 std::vector<GVertex *> pointsToRemove;
144 pointsToRemove.push_back(*it);
146 for(std::size_t i = 0; i < pointsToRemove.size(); ++i) {
147 gm->
remove(pointsToRemove[i]);
151 std::map<MTriangle *, GFace *> reverse_old;
152 std::map<MEdge, std::vector<MTriangle *>,
MEdgeLessThan> tris;
153 std::set<MTriangle *, MElementPtrLessThan> touched;
156 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
165 if(touched.empty()) {
166 Msg::Warning(
"No triangles to reclassify in surface mesh");
171 for(
auto it = touched.begin(); it != touched.end(); it++) {
172 for(std::size_t j = 0; j < (*it)->getNumVertices(); j++)
173 (*it)->getVertex(j)->setEntity(
nullptr);
176 std::map<MTriangle *, GFace *> reverse;
177 std::multimap<GFace *, GFace *> replacedBy;
178 std::list<GFace *> newf;
181 while(!touched.empty()) {
182 std::stack<MTriangle *> st;
183 st.push(*(touched.begin()));
184 touched.erase(touched.begin());
191 for(
int i = 0; i < 3; i++) {
193 auto it = tris.find(e);
194 if(it == tris.end()) {
195 Msg::Error(
"Could not find triangle linked to edge");
199 auto itl = lines.find(&ll);
200 if(itl == lines.end()) {
201 MTriangle *tt = it->second[0] == t ? it->second[1] : it->second[0];
202 auto it2 = touched.find(tt);
203 if(it2 != touched.end()) {
213 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
214 replacedBy.insert(std::make_pair(reverse_old[gf->
triangles[i]], gf));
218 Msg::Info(
"Found %d model surfaces", newf.size());
223 std::vector<GFace *> _xfaces = (*rit)->faces();
224 std::set<GFace *, GEntityPtrLessThan> _newFaces;
225 for(
auto itf = _xfaces.begin(); itf != _xfaces.end(); ++itf) {
226 auto itLow = replacedBy.lower_bound(*itf);
227 auto itUp = replacedBy.upper_bound(*itf);
229 for(; itLow != itUp; ++itLow) _newFaces.insert(itLow->second);
231 (*rit)->set(std::vector<GFace *>(_newFaces.begin(), _newFaces.end()));
234 std::vector<std::pair<GEdge *, std::vector<GFace *> > > newEdges;
236 auto it = tris.begin();
237 for(; it != tris.end(); ++it) {
238 MLine ml(it->first.getVertex(0), it->first.getVertex(1));
239 auto itl = lines.find(&ml);
240 if(itl != lines.end()) {
241 std::vector<GFace *>
faces;
242 for(
size_t i = 0; i < it->second.size(); ++i)
243 faces.push_back(reverse[it->second[i]]);
244 GEdge *ge = getModelEdge(gm,
faces, newEdges, MAX1);
245 if(ge) ge->
lines.push_back(*itl);
249 Msg::Info(
"Found %d model curves", newEdges.size());
255 std::map<MVertex *, GVertex *> modelVertices;
257 for(
auto ite = newEdges.begin(); ite != newEdges.end(); ++ite) {
258 std::vector<MEdge> allEdges;
260 for(std::size_t i = 0; i < ite->first->lines.size(); i++) {
261 allEdges.push_back(
MEdge(ite->first->lines[i]->getVertex(0),
262 ite->first->lines[i]->getVertex(1)));
263 delete ite->first->lines[i];
265 ite->first->lines.clear();
266 std::vector<std::vector<MVertex *> > vs_;
270 std::vector<std::vector<MVertex *> > vs;
271 for(
size_t i = 0; i < vs_.size(); i++) {
272 bool periodic = (vs_[i][vs_[i].size() - 1] == vs_[i][0]);
274 for(
size_t j = 0; j < vs_[i].size() - 1; j++) {
275 MVertex *v0 = vs_[i][j == 0 ? (vs_[i].size() - 2) : (j - 1)];
278 if(breakForLargeAngle(v0, v1, v2, curveAngleThreshold)) {
279 std::vector<MVertex *> temp;
280 for(
size_t k = j; k < vs_[i].size() + j; k++) {
281 temp.push_back(vs_[i][k % vs_[i].size()]);
289 std::vector<size_t> cuts_;
291 for(
size_t j = 1; j < vs_[i].size() - 1; j++) {
295 if(breakForLargeAngle(v0, v1, v2, curveAngleThreshold))
298 cuts_.push_back(vs_[i].size() - 1);
300 MVertex *first = vs_[i][cuts_[0]];
301 for(
size_t k = 1; k < cuts_.size(); k++) {
302 std::vector<MVertex *> vv_;
303 for(
size_t j = cuts_[k - 1]; j <= cuts_[k]; j++) {
304 if(j == cuts_[k - 1] || vs_[i][j] != vs_[i][j - 1]) {
305 vv_.push_back(vs_[i][j]);
308 if(periodic && k == cuts_.size() - 1 && cuts_.size() > 2) {
309 vv_.push_back(first);
315 for(
size_t i = 0; i < vs.size(); i++) {
317 MVertex *vE = vs[i][vs[i].size() - 1];
319 auto itMV = modelVertices.find(vB);
320 if(itMV == modelVertices.end()) {
327 modelVertices[vB] = newGv;
329 itMV = modelVertices.find(vE);
330 if(itMV == modelVertices.end()) {
337 modelVertices[vE] = newGv;
343 for(
size_t j = 1; j < vs[i].size(); j++) {
349 for(
size_t j = 0; j < newGe->
lines.size(); j++) {
358 for(
size_t K = 0; K < ite->second.size(); K++) {
360 if(gf1) newFaceTopology[gf1].push_back(newGe->
tag());
365 for(
auto itFT = newFaceTopology.begin(); itFT != newFaceTopology.end();
370 for(
auto ite = newEdges.begin(); ite != newEdges.end(); ++ite) {
371 GEdge *ge = ite->first;
377 std::set<GFace *, GEntityPtrLessThan> fac = gm->
getFaces();
378 for(
auto fit = fac.begin(); fit != fac.end(); ++fit) {
379 std::set<MVertex *, MVertexPtrLessThan> verts;
380 (*fit)->mesh_vertices.clear();
381 for(std::size_t i = 0; i < (*fit)->triangles.size(); i++) {
382 for(
int j = 0; j < 3; j++) {
383 if(!(*fit)->triangles[i]->getVertex(j)->onWhat()) {
384 (*fit)->triangles[i]->getVertex(j)->setEntity(*fit);
385 verts.insert((*fit)->triangles[i]->getVertex(j));
389 if((*fit)->triangles.size())
390 (*fit)->mesh_vertices.insert((*fit)->mesh_vertices.begin(), verts.begin(),
399 bool forParametrization,
double curveAngleThreshold)
401 #if defined(HAVE_MESH)
405 angleThreshold * 180. / M_PI);
408 std::vector<MElement *> elements;
410 elements.insert(elements.end(), (*it)->triangles.begin(),
411 (*it)->triangles.end());
412 elements.insert(elements.end(), (*it)->quadrangles.begin(),
413 (*it)->quadrangles.end());
421 std::vector<edge_angle> edges_detected, edges_lonely;
423 for(std::size_t i = 0; i < edges_detected.size(); i++) {
425 if(ea.
angle <= angleThreshold)
break;
428 if(includeBoundary) {
429 for(std::size_t i = 0; i < edges_lonely.size(); i++) {
436 if(forParametrization)
455 Msg::StatusBar(
true,
"Done classifying surfaces (Wall %gs, CPU %gs)", w2 -
w1,
458 Msg::Error(
"Surface classification requires the mesh module");
464 std::map<MVertex *, std::pair<SVector3, SVector3> > &C = gm->
getCurvatures();
468 std::map<MVertex *, int> nodeIndex;
469 std::vector<SPoint3> nodes;
470 std::vector<int> tris;
471 std::vector<std::pair<SVector3, SVector3> > curv;
472 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
474 for(
int j = 0; j < 3; j++) {
476 if(nodeIndex.find(v) == nodeIndex.end()) {
477 int idx = nodes.size();
479 nodes.push_back(v->
point());
483 tris.push_back(nodeIndex[v]);
488 for(
auto itv = nodeIndex.begin(); itv != nodeIndex.end(); itv++) {
489 C[itv->first] = curv[itv->second];
496 std::vector<MVertex *> &nodes,
497 std::vector<SPoint2> &stl_vertices_uv,
498 std::vector<SPoint3> &stl_vertices_xyz,
499 std::vector<int> &stl_triangles)
501 stl_vertices_uv.clear();
502 stl_vertices_xyz.clear();
503 stl_triangles.clear();
506 if(triangles.empty())
return false;
509 std::map<MVertex *, int> nodeIndex;
511 for(std::size_t i = 0; i < triangles.size(); i++) {
513 for(
int j = 0; j < 3; j++) {
515 if(nodeIndex.find(v) == nodeIndex.end()) {
516 nodeIndex[v] = nodes.size();
524 std::vector<MEdge> es;
525 for(
auto it =
edges.begin(); it !=
edges.end(); ++it) {
526 if(it->second.size() == 1) {
527 es.push_back(it->first);
529 else if(it->second.size() == 2) {
532 Msg::Error(
"Wrong topology of triangulation for parametrization: one "
533 "edge is incident to %d triangles",
538 std::vector<std::vector<MVertex *> > vs;
540 Msg::Error(
"Wrong topology of boundary mesh for parametrization");
543 if(vs.empty() || vs[0].size() < 2) {
544 Msg::Error(
"Invalid exterior boundary mesh for parametrization");
548 Msg::Debug(
"Parametrisation of surface with %lu triangles, %lu edges and "
550 triangles.size(),
edges.size(), vs.size() - 1);
555 for(std::size_t i = 0; i < vs.size(); i++) {
557 for(std::size_t j = 1; j < vs[i].size(); j++) {
558 l += vs[i][j]->point().distance(vs[i][j - 1]->point());
568 MEdge ref(vs[loop][0], vs[loop][1]);
569 for(std::size_t i = 0; i < triangles.size(); i++) {
571 for(
int j = 0; j < 3; j++) {
581 if(reverse) { std::reverse(vs[0].begin(), vs[0].end()); }
583 std::vector<double> u(nodes.size(), 0.), v(nodes.size(), 0.);
586 std::vector<bool> bc(nodes.size(),
false);
587 double currentLength = 0;
588 int index = nodeIndex[vs[loop][0]];
592 for(std::size_t i = 1; i < vs[loop].size() - 1; i++) {
593 currentLength += vs[loop][i]->point().distance(vs[loop][i - 1]->point());
594 double angle = 2 * M_PI * currentLength / longest;
595 index = nodeIndex[vs[loop][i]];
597 u[index] = cos(
angle);
598 v[index] = sin(
angle);
602 #if defined(HAVE_SOLVER)
603 #if defined(HAVE_PETSC)
605 std::string options =
"-ksp_type preonly -pc_type lu ";
606 #if defined(PETSC_HAVE_MUMPS)
607 options +=
"-pc_factor_mat_solver_type mumps";
608 #elif defined(PETSC_HAVE_MKL_PARDISO)
609 options +=
"-pc_factor_mat_solver_type mkl_pardiso";
610 #elif defined(PETSC_HAVE_UMFPACK) || defined(PETSC_HAVE_SUITESPARSE)
611 options +=
"-pc_factor_mat_solver_type umfpack";
615 #elif defined(HAVE_GMM)
623 #if defined(HAVE_PETSC)
624 for(
auto it =
edges.begin(); it !=
edges.end(); ++it) {
625 for(
int i = 0; i < 2; i++) {
626 for(
int j = 0; j < 2; j++) {
628 nodeIndex[it->first.getVertex(j)]);
634 for(
auto it =
edges.begin(); it !=
edges.end(); ++it) {
635 for(
int ij = 0; ij < 2; ij++) {
636 MVertex *v0 = it->first.getVertex(ij);
637 int index0 = nodeIndex[v0];
638 if(bc[index0])
continue;
639 MVertex *v1 = it->first.getVertex(1 - ij);
640 int index1 = nodeIndex[v1];
643 if(vLeft == v0 || vLeft == v1) vLeft = tLeft->
getVertex(1);
644 if(vLeft == v0 || vLeft == v1) vLeft = tLeft->
getVertex(2);
645 double e[3] = {v1->
x() - v0->
x(), v1->
y() - v0->
y(), v1->
z() - v0->
z()};
646 double ne = sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);
647 double a[3] = {vLeft->
x() - v0->
x(), vLeft->
y() - v0->
y(),
648 vLeft->
z() - v0->
z()};
649 double na = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
651 acos((a[0] * e[0] + a[1] * e[1] + a[2] * e[2]) / (na * ne));
653 if(it->second.size() == 2) {
656 if(vRight == v0 || vRight == v1) vRight = tRight->
getVertex(1);
657 if(vRight == v0 || vRight == v1) vRight = tRight->
getVertex(2);
658 double b[3] = {vRight->
x() - v0->
x(), vRight->
y() - v0->
y(),
659 vRight->
z() - v0->
z()};
660 double nb = sqrt(b[0] * b[0] + b[1] * b[1] + b[2] * b[2]);
661 thetaR = acos((b[0] * e[0] + b[1] * e[1] + b[2] * e[2]) / (nb * ne));
663 double c = (tan(.5 * thetaL) + tan(.5 * thetaR)) / ne;
668 for(std::size_t i = 0; i < vs[loop].size() - 1; i++) {
669 int row = nodeIndex[vs[loop][i]];
674 for(std::size_t i = 0; i < vs[loop].size() - 1; i++) {
675 int row = nodeIndex[vs[loop][i]];
679 for(std::size_t i = 0; i < nodes.size(); i++) lsys->
getFromSolution(i, u[i]);
682 for(std::size_t i = 0; i < vs[loop].size() - 1; i++) {
683 int row = nodeIndex[vs[loop][i]];
687 for(std::size_t i = 0; i < nodes.size(); i++) lsys->
getFromSolution(i, v[i]);
692 stl_vertices_uv.resize(nodes.size());
693 stl_vertices_xyz.resize(nodes.size());
694 for(std::size_t i = 0; i < nodes.size(); i++) {
695 stl_vertices_uv[i] =
SPoint2(u[i], v[i]);
696 stl_vertices_xyz[i] = nodes[i]->point();
698 stl_triangles.resize(3 * triangles.size());
699 for(std::size_t i = 0; i < triangles.size(); i++) {
700 stl_triangles[3 * i + 0] = nodeIndex[triangles[i]->getVertex(0)];
701 stl_triangles[3 * i + 1] = nodeIndex[triangles[i]->getVertex(1)];
702 stl_triangles[3 * i + 2] = nodeIndex[triangles[i]->getVertex(2)];
709 static void debugTriangulation(
const std::vector<MTriangle *> &triangles,
710 const std::string &label)
712 FILE *fp =
Fopen(
"debug.pos",
"w");
714 fprintf(fp,
"View\"%s\"{\n", label.c_str());
715 for(
auto t : triangles) t->
writePOS(fp,
false,
true,
false,
false,
false,
false);
723 int Nmax, std::ostringstream &why)
725 if(Nmax > 1 && (
int)t.size() > Nmax) {
726 int np = t.size() / (Nmax - 1) + 1;
728 why <<
"too many triangles (" << t.size() <<
" vs. " << Nmax <<
")";
733 std::set<MVertex *> v;
734 std::map<MEdge, int, MEdgeLessThan> e;
735 for(std::size_t i = 0; i < t.size(); ++i) {
736 for(
int j = 0; j < 3; j++) {
737 v.insert(t[i]->getVertex(j));
738 auto it = e.find(t[i]->getEdge(j));
740 e[t[i]->getEdge(j)] = 1;
745 std::vector<MEdge> bnd;
746 for(
auto it = e.begin(); it != e.end(); ++it) {
747 if(it->second == 1) bnd.push_back(it->first);
750 why <<
"poincare characteristic 2 is not 0";
755 std::vector<std::vector<MVertex *> > vs;
757 why <<
"boundary not manifold";
761 std::size_t poincare =
762 t.size() - (2 * (v.size() - 1) - bnd.size() + 2 * (vs.size() - 1));
764 why <<
"poincare characteristic " << poincare <<
" is not 0";
768 std::vector<MVertex *> nodes;
769 std::vector<SPoint2> stl_nodes_uv;
770 std::vector<SPoint3> stl_nodes_xyz;
771 std::vector<int> stl_triangles;
773 for(std::size_t i = 0; i < stl_triangles.size(); i += 3) {
774 double u0 = stl_nodes_uv[stl_triangles[i + 0]].x();
775 double v0 = stl_nodes_uv[stl_triangles[i + 0]].y();
776 double u1 = stl_nodes_uv[stl_triangles[i + 1]].x();
777 double v1 = stl_nodes_uv[stl_triangles[i + 1]].y();
778 double u2 = stl_nodes_uv[stl_triangles[i + 2]].x();
779 double v2 = stl_nodes_uv[stl_triangles[i + 2]].y();
780 double det = fabs((u1 - u0) * (v2 - v0) - (v1 - v0) * (u2 - u0));
782 why <<
"parametrized triangles are too small (" << det <<
")";
792 v.erase(std::unique(v.begin(), v.end(),
MLinePtrEqual()), v.end());
801 if(t ==
t1)
return t2;
802 if(t ==
t2)
return t1;
809 std::vector<std::vector<MTriangle *> > &ts)
811 std::map<MEdge, twoT, MEdgeLessThan>
conn;
812 for(std::size_t i = 0; i < t.size(); i++) {
813 for(
int j = 0; j < 3; j++) {
814 MEdge e = t[i]->getEdge(j);
815 auto it =
conn.find(e);
818 conn.insert(std::make_pair(e, twt));
820 it->second.t2 = t[i];
825 std::stack<MTriangle *> _s;
827 std::set<MTriangle *, MElementPtrLessThan> touch;
832 for(
int j = 0; j < 3; j++) {
834 auto it =
conn.find(e);
837 if(tt && touch.find(tt) == touch.end()) _s.push(tt);
841 std::vector<MTriangle *> _part;
842 _part.insert(_part.begin(), touch.begin(), touch.end());
844 std::vector<MTriangle *> update;
845 for(std::size_t i = 0; i < t.size(); i++)
846 if(touch.find(t[i]) == touch.end()) update.push_back(t[i]);
853 int max_elems_per_cut)
855 Msg::Info(
"Splitting triangulations to make them parametrizable:");
859 if((*it)->triangles.empty())
continue;
860 std::vector<MVertex *> verts = (*it)->mesh_vertices;
861 std::map<MTriangle *, int, MElementPtrLessThan>
global;
862 std::map<MEdge, int, MEdgeLessThan> cuts;
863 std::stack<std::vector<MTriangle *> > partitions;
864 std::stack<int> _levels;
865 partitions.push((*it)->triangles);
867 (*it)->triangles.clear();
869 while(!partitions.empty()) {
870 int level = _levels.top();
872 (*it)->triangles = partitions.top();
873 (*it)->mesh_vertices.clear();
874 std::set<MVertex *, MVertexPtrLessThan> vs;
875 for(std::size_t i = 0; i < (*it)->triangles.size(); ++i) {
876 for(std::size_t j = 0; j < 3; ++j)
877 vs.insert((*it)->triangles[i]->getVertex(j));
879 (*it)->mesh_vertices.insert((*it)->mesh_vertices.begin(), vs.begin(),
882 std::ostringstream why;
886 Msg::Info(
" - Level %d partition with %d triangles split in %d "
888 level, (*it)->triangles.size(), np, why.str().c_str());
891 Msg::Error(
"Could not create parametrization (check orientation of "
892 "input triangulations)");
896 for(std::size_t i = 0; i < (*it)->triangles.size(); i++)
897 global[(*it)->triangles[i]] = part;
901 #if defined(HAVE_MESH)
903 std::vector<std::vector<MTriangle *> > t(np);
904 for(std::size_t i = 0; i < (*it)->triangles.size(); i++) {
905 int p = (*it)->triangles[i]->getPartition();
907 t[p].push_back((*it)->triangles[i]);
911 for(std::size_t i = 0; i < t.size(); i++) {
912 std::vector<std::vector<MTriangle *> > ts;
914 Msg::Warning(
"Could not make partition simply connected");
917 for(std::size_t j = 0; j < ts.size(); j++) {
918 _levels.push(level + 1);
919 partitions.push(ts[j]);
924 Msg::Error(
"Partitioning surface requires Mesh module");
928 (*it)->triangles.clear();
929 for(
auto it2 =
global.begin(); it2 !=
global.end(); ++it2) {
931 (*it)->triangles.push_back(t);
932 for(
int i = 0; i < 3; i++) {
934 auto it3 = cuts.find(ed);
935 if(it3 == cuts.end())
936 cuts[ed] = it2->second;
938 if(it3->second != it2->second)
943 (*it)->mesh_vertices = verts;
951 std::map<MEdge, int, MEdgeLessThan> m;
953 for(std::size_t i = 0; i < (*it)->triangles.size(); i++) {
954 for(
int j = 0; j < 3; j++) {
955 auto it2 = m.find((*it)->triangles[i]->getEdge(j));
957 m[(*it)->triangles[i]->getEdge(j)] = 1;
964 int countNM = 0, countBND = 0;
966 for(; it != m.end(); ++it) {
969 new MLine(it->first.getVertex(0), it->first.getVertex(1)));
972 if(addBoundary && it->second == 1) {
974 new MLine(it->first.getVertex(0), it->first.getVertex(1)));
978 if(countNM + countBND > 0)
980 "Model has %d non manifold mesh edges and %d boundary mesh edges",