1 /*******************************************************************************
2 QuadTriExtruded3D.cpp
3 
4 The code in this file was written by Dr. Trevor S. Strickler.
5 email: <trevor.strickler@gmail.com>
6 
7 This file is part of the QuadTri contribution to Gmsh. QuadTri allows the
8 conformal interface of quadrangle faces to triangle faces using pyramids and
9 other mesh elements.
10 
11 Trevor S. Strickler hereby transfers copyright of QuadTri files to Christophe
12 Geuzaine and J.-F. Remacle with the understanding that his contribution shall be
13 cited appropriately. See the README.txt file for license information.
14 ********************************************************************************/
15 
16 #include "QuadTriExtruded3D.h"
17 
18 // By Geuzaine, Remacle...
addTetrahedron(MVertex * v1,MVertex * v2,MVertex * v3,MVertex * v4,GRegion * to,MElement * source)19 static void addTetrahedron(MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4,
20                            GRegion *to, MElement *source)
21 {
22   MTetrahedron *newElem = new MTetrahedron(v1, v2, v3, v4);
23   to->tetrahedra.push_back(newElem);
24 }
25 
26 // By Geuzaine, Remacle...
addPyramid(MVertex * v1,MVertex * v2,MVertex * v3,MVertex * v4,MVertex * v5,GRegion * to,MElement * source)27 static void addPyramid(MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4,
28                        MVertex *v5, GRegion *to, MElement *source)
29 {
30   MPyramid *newElem = new MPyramid(v1, v2, v3, v4, v5);
31   to->pyramids.push_back(newElem);
32 }
33 
34 // By Geuzaine, Remacle...
addPrism(MVertex * v1,MVertex * v2,MVertex * v3,MVertex * v4,MVertex * v5,MVertex * v6,GRegion * to,MElement * source)35 static void addPrism(MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4,
36                      MVertex *v5, MVertex *v6, GRegion *to, MElement *source)
37 {
38   MPrism *newElem = new MPrism(v1, v2, v3, v4, v5, v6);
39   to->prisms.push_back(newElem);
40 }
41 
42 // By Geuzaine, Remacle...
addHexahedron(MVertex * v1,MVertex * v2,MVertex * v3,MVertex * v4,MVertex * v5,MVertex * v6,MVertex * v7,MVertex * v8,GRegion * to,MElement * source)43 static void addHexahedron(MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4,
44                           MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8,
45                           GRegion *to, MElement *source)
46 {
47   MHexahedron *newElem = new MHexahedron(v1, v2, v3, v4, v5, v6, v7, v8);
48   to->hexahedra.push_back(newElem);
49 }
50 
51 // Does the pair of MVertex pointers v1 and v2 exist in the set 'edges'?
edgeExists(MVertex * v1,MVertex * v2,std::set<std::pair<MVertex *,MVertex * >> & edges)52 static int edgeExists(MVertex *v1, MVertex *v2,
53                       std::set<std::pair<MVertex *, MVertex *> > &edges)
54 {
55   std::pair<MVertex *, MVertex *> p(std::min(v1, v2), std::max(v1, v2));
56   return edges.count(p);
57 }
58 
59 // Create the pair of MVertex pointers v1 and v2 exist in the set 'edges.'
createEdge(MVertex * v1,MVertex * v2,std::set<std::pair<MVertex *,MVertex * >> & edges)60 static void createEdge(MVertex *v1, MVertex *v2,
61                        std::set<std::pair<MVertex *, MVertex *> > &edges)
62 {
63   std::pair<MVertex *, MVertex *> p(std::min(v1, v2), std::max(v1, v2));
64   edges.insert(p);
65 }
66 
67 // Create the entry for a forbidden edge in forbidden_edges (note that all four
68 // verts are forbidden, but only store two, using lowest vertex pointer
69 // diagonal).
70 static void
createForbidden(std::vector<MVertex * > v,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges)71 createForbidden(std::vector<MVertex *> v,
72                 std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges)
73 {
74   if(v.size() != 4) {
75     Msg::Error("In createForbidden(), number of vertices not equal 4.");
76     return;
77   }
78   int ind_low = 0;
79   if(v[1] < v[ind_low]) ind_low = 1;
80   if(v[2] < v[ind_low]) ind_low = 2;
81   if(v[3] < v[ind_low]) ind_low = 3;
82 
83   std::pair<MVertex *, MVertex *> p(v[ind_low], v[(ind_low + 2) % 4]);
84   forbidden_edges.insert(p);
85 }
86 
87 // Is the given vector of quad vertices forbidden to diagonalize (it is in
88 // forbidden_edges)?
89 static int
forbiddenExists(std::vector<MVertex * > v,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges)90 forbiddenExists(std::vector<MVertex *> v,
91                 std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges)
92 {
93   if(v.size() != 4) {
94     Msg::Error(
95       "forbiddenExists() was passed a vector argument that was not of size 4.");
96     return 0;
97   }
98 
99   int ind_low = 0;
100   if(v[1] < v[ind_low]) ind_low = 1;
101   if(v[2] < v[ind_low]) ind_low = 2;
102   if(v[3] < v[ind_low]) ind_low = 3;
103 
104   std::pair<MVertex *, MVertex *> pair(v[ind_low], v[(ind_low + 2) % 4]);
105   return forbidden_edges.count(pair);
106 }
107 
108 // delete a pair of vertex pointers v1 and v2 from 'edges.'
deleteEdge(MVertex * v1,MVertex * v2,std::set<std::pair<MVertex *,MVertex * >> & edges)109 static void deleteEdge(MVertex *v1, MVertex *v2,
110                        std::set<std::pair<MVertex *, MVertex *> > &edges)
111 {
112   std::pair<MVertex *, MVertex *> p(std::min(v1, v2), std::max(v1, v2));
113   edges.erase(p);
114 }
115 
116 // Get the two mesh vertices extruded from vertices v0 and v1 on a lateral face
117 // at layer j, element k.  Added 2010-01-26
118 static std::vector<MVertex *>
getExtrudedLateralVertices(MVertex * v0,MVertex * v1,GEntity * entity,unsigned int j,unsigned int k,ExtrudeParams * loop_ep,MVertexRTree & pos)119 getExtrudedLateralVertices(MVertex *v0, MVertex *v1, GEntity *entity,
120                            unsigned int j, unsigned int k,
121                            ExtrudeParams *loop_ep, MVertexRTree &pos)
122 {
123   std::vector<MVertex *> verts;
124   double x[4] = {v0->x(), v1->x(), v0->x(), v1->x()};
125   double y[4] = {v0->y(), v1->y(), v0->y(), v1->y()};
126   double z[4] = {v0->z(), v1->z(), v0->z(), v1->z()};
127   for(int p = 0; p < 2; p++) {
128     loop_ep->Extrude(j, k, x[p], y[p], z[p]);
129     loop_ep->Extrude(j, k + 1, x[p + 2], y[p + 2], z[p + 2]);
130   }
131   for(int p = 0; p < 4; p++) {
132     MVertex *tmp = pos.find(x[p], y[p], z[p]);
133     if(!tmp) {
134       Msg::Error("Could not find extruded vertex (%.16g, %.16g, %.16g) in "
135                  "geometrical entity %d",
136                  x[p], y[p], z[p], entity->tag());
137       verts.clear();
138       return verts;
139     }
140     verts.push_back(tmp);
141   }
142 
143   return verts;
144 }
145 
146 // Get the extruded vertices from MElement *elem at layer j, element k.  Added
147 // 2010-01-26
get2DExtrudedVertices(MElement * elem,ExtrudeParams * ep,unsigned int j,unsigned int k,MVertexRTree & pos,std::vector<MVertex * > & verts)148 static int get2DExtrudedVertices(MElement *elem, ExtrudeParams *ep,
149                                  unsigned int j, unsigned int k,
150                                  MVertexRTree &pos,
151                                  std::vector<MVertex *> &verts)
152 {
153   std::vector<MVertex *> source_verts;
154   elem->getVertices(source_verts);
155 
156   int sz = source_verts.size();
157   std::vector<double> x(sz), y(sz), z(sz);
158   for(int p = 0; p < sz; p++) {
159     x[p] = source_verts[p]->x();
160     y[p] = source_verts[p]->y();
161     z[p] = source_verts[p]->z();
162   }
163   for(int p = 0; p < sz; p++) {
164     ep->Extrude(j, k, x[p], y[p], z[p]);
165     MVertex *tmp = pos.find(x[p], y[p], z[p]);
166     if(!tmp) {
167       Msg::Error("Could not find extruded vertex (%.16g, %.16g, %.16g).", x[p],
168                  y[p], z[p]);
169       verts.clear();
170       return verts.size();
171     }
172     verts.push_back(tmp);
173   }
174 
175   return verts.size();
176 }
177 
178 // Copied from meshGRegionExtruded.cpp, By Geuzaine, Remacle...  Extrudes a set
179 // of source vertices in 3D added 2010-01-18
getExtrudedVertices(MElement * ele,ExtrudeParams * ep,int j,int k,MVertexRTree & pos,std::vector<MVertex * > & verts)180 static int getExtrudedVertices(MElement *ele, ExtrudeParams *ep, int j, int k,
181                                MVertexRTree &pos, std::vector<MVertex *> &verts)
182 {
183   double x[8], y[8], z[8];
184   int n = ele->getNumVertices();
185   for(int p = 0; p < n; p++) {
186     MVertex *v = ele->getVertex(p);
187     x[p] = x[p + n] = v->x();
188     y[p] = y[p + n] = v->y();
189     z[p] = z[p + n] = v->z();
190   }
191   for(int p = 0; p < n; p++) {
192     ep->Extrude(j, k, x[p], y[p], z[p]);
193     ep->Extrude(j, k + 1, x[p + n], y[p + n], z[p + n]);
194   }
195   for(int p = 0; p < 2 * n; p++) {
196     MVertex *tmp = pos.find(x[p], y[p], z[p]);
197     if(!tmp)
198       Msg::Error("Could not find extruded vertex (%.16g, %.16g, %.16g)", x[p],
199                  y[p], z[p]);
200     else
201       verts.push_back(tmp);
202   }
203   return verts.size();
204 }
205 
206 // Determines whether the region is a valid QuadToTri region.  Performs some
207 // basic checks, including whether there is a valid top, valid source, and that
208 // the surfaces serving as laterals are structured Added 2010-12-30
IsValidQuadToTriRegion(GRegion * region,bool * allNonGlobalSharedLaterals)209 bool IsValidQuadToTriRegion(GRegion *region, bool *allNonGlobalSharedLaterals)
210 {
211   ExtrudeParams *ep = region->meshAttributes.extrude;
212 
213   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) return false;
214 
215   GModel *model = region->model();
216 
217   // find source face
218   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
219   if(!reg_source) {
220     Msg::Error("In IsValidQuadToTriRegion(), could not find source face "
221                "%d for region %d.",
222                std::abs(ep->geo.Source), region->tag());
223     return false;
224   }
225 
226   bool is_toroidal = IsInToroidalQuadToTri(reg_source);
227   GFace *root = findRootSourceFaceForFace(reg_source);
228 
229   // Find a source surface. Then find a COPIED_ENTITY that is the top surface.
230   // Then determine if all the laterals are either all quad or all triangle.  If
231   // shared laterals are all static (quad or non subdivide triangles), set the
232   // allNonGlobalSharedLaterals argument to true.  If any lateral is
233   // unstructured, error.
234 
235   bool foundTop = false, foundSource = false, foundNoStruct = false,
236        foundRoot = false;
237 
238   std::vector<GFace *> faces = region->faces();
239   std::vector<GFace *>::iterator it = faces.begin();
240 
241   (*allNonGlobalSharedLaterals) = true;
242 
243   for(it = faces.begin(); it != faces.end(); it++) {
244     ExtrudeParams *face_tmp_ep = (*it)->meshAttributes.extrude;
245     if((*it) == root) foundRoot = true;
246     if((*it) == reg_source)
247       foundSource = true;
248     else if(face_tmp_ep && face_tmp_ep->geo.Mode == COPIED_ENTITY) {
249       GFace *top_source_tmp =
250         model->getFaceByTag(std::abs(face_tmp_ep->geo.Source));
251       if(!top_source_tmp) {
252         Msg::Error("In IsValidQuadToTriRegion(), could not find source face "
253                    "%d for copied surface %d of region %d.",
254                    std::abs(face_tmp_ep->geo.Source), (*it)->tag(),
255                    region->tag());
256         return false;
257       }
258       else if(top_source_tmp == reg_source &&
259               !IsSurfaceALateralForRegion(region, *it))
260         foundTop = true;
261     }
262     // This is a check to see if there are lateral surface triangles that need
263     // to be edged globally in subdivide operation
264     else if(IsSurfaceALateralForRegion(region, *it)) {
265       std::vector<GRegion *> neighbors;
266       if((*allNonGlobalSharedLaterals) && (*it)->triangles.size() &&
267          !(*it)->quadrangles.size() &&
268          GetNeighborRegionsOfFace(*it, neighbors) > 1) {
269         GRegion *other_region =
270           neighbors[0] != region ? neighbors[0] : neighbors[1];
271         ExtrudeParams *oth_ep = other_region->meshAttributes.extrude;
272         if((ep && ep->mesh.ExtrudeMesh && !ep->mesh.Recombine) ||
273            (oth_ep && oth_ep->mesh.ExtrudeMesh && !oth_ep->mesh.Recombine &&
274             IsSurfaceALateralForRegion(other_region, *it)))
275           (*allNonGlobalSharedLaterals) = false;
276       }
277     }
278     else if(!is_toroidal)
279       foundNoStruct = true;
280   }
281 
282   // if didn't find the copied entity, maybe this is toroidal and the top has
283   // been replaced
284   if(is_toroidal && !foundTop && foundRoot && root != reg_source)
285     foundTop = true;
286 
287   // test for errors
288   bool detectConflict = false;
289   if(!foundTop) {
290     Msg::Error("In IsValidQuadToTriRegion(), could not find top face "
291                "of region %d.",
292                region->tag());
293     detectConflict = true;
294   }
295   if(!foundSource) {
296     Msg::Error("In IsValidQuadToTriRegion(), source "
297                "face %d of region %d was not found in region.",
298                region->tag());
299     detectConflict = true;
300   }
301   if(foundNoStruct) {
302     Msg::Error("In IsValidQuadToTriRegion(), found unstructured "
303                "lateral in QuadToTri region %d.",
304                region->tag());
305     detectConflict = true;
306   }
307 
308   if(detectConflict) return false;
309 
310   // no errors, return true
311   return true;
312 }
313 
314 // This function returns a vector of integer values, each of which are codes for
315 // the status of each face of an undivided prism or hexahedron (including
316 // degenerate versions): 0 = degenerate line, 1 = single triangle, 2 =
317 // recombined quad, 3 = fixed diagonal, 4 = adjustable diagonal, 5 = totally
318 // free to diagonalize or not. Ordering of faces starts with the lateral face
319 // containing verts[0] and verts[1], then goes in order of increasing vertex
320 // index around element. Finally, the bottom, then the top. Added 2010-01-21
getFaceTypes(GRegion * gr,MElement * elem,int j,int k,std::vector<MVertex * > & verts,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::vector<bool> & vert_bnd,std::vector<int> & nfix1,std::vector<int> & nfix2,std::vector<int> & nadj1,std::vector<int> & nadj2,std::vector<int> & free_flag)321 static std::map<std::string, std::vector<int> > getFaceTypes(
322   GRegion *gr, MElement *elem, int j, int k, std::vector<MVertex *> &verts,
323   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
324   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
325   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
326   std::vector<bool> &vert_bnd, std::vector<int> &nfix1, std::vector<int> &nfix2,
327   std::vector<int> &nadj1, std::vector<int> &nadj2, std::vector<int> &free_flag)
328 {
329   std::map<std::string, std::vector<int> > face_types;
330   ExtrudeParams *ep = gr->meshAttributes.extrude;
331 
332   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
333     Msg::Error("In getFaceTypes(), invalid extrusion "
334                "in region %d for performing QuadToTri mesh generation.",
335                gr->tag());
336     return face_types;
337   }
338 
339   // get the starting indices of the top quadToTri layer
340   int j_top_start = 0, k_top_start = 0;
341   j_top_start = ep->mesh.NbLayer - 1;
342   k_top_start = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1;
343 
344   // check nature of each face
345   int n_lat_tmp = 0;
346   if(verts.size() == 6)
347     n_lat_tmp = 3;
348   else if(verts.size() == 8)
349     n_lat_tmp = 4;
350   else {
351     Msg::Error(
352       "In getFaceTypes(), size of verts vector was not 6 or 8 (region %d).",
353       gr->tag());
354     return face_types;
355   }
356 
357   const int n_lat = n_lat_tmp;
358 
359   // set defaults for the nfix, nadj vectors that store the nodes for each fixed
360   // or adjustable diagonal And set the defaults for free_flag which tells
361   // whether a face is free (0)
362   nfix1.clear();
363   nfix1.assign(n_lat + 2, 0);
364   nfix2.clear();
365   nfix2.assign(n_lat + 2, 0);
366   nadj1.clear();
367   nadj1.assign(n_lat + 2, 0);
368   nadj2.clear();
369   nadj2.assign(n_lat + 2, 0);
370   free_flag.clear();
371   free_flag.assign(n_lat + 2, 0);
372   for(int p = 0; p < n_lat + 2; p++) {
373     nfix1[p] = -p * p - p - 1;
374     nfix2[p] = -p * p - p - 2;
375     nadj1[p] = -p * p - p - 1;
376     nadj2[p] = -p * p - p - 2;
377     free_flag[p] = 0;
378   }
379 
380   // create an array that holds info about whether a face touches a boundary
381   std::vector<int> touch_bnd(n_lat);
382 
383   fill_touch_bnd(&touch_bnd[0], vert_bnd, n_lat);
384 
385   // Classify the laterals of each little mesh volume:
386 
387   for(int p = 0; p < n_lat; p++) {
388     int p2 = (p + 1) % n_lat;
389     std::vector<MVertex *> v_face;
390     v_face.assign(4, (MVertex *)(0));
391     v_face[0] = verts[p];
392     v_face[1] = verts[p2];
393     v_face[2] = verts[p2 + n_lat];
394     v_face[3] = verts[p + n_lat];
395 
396     // is the face a degenerate line:
397     if(verts[p] == verts[n_lat + p] && verts[p2] == verts[n_lat + p2]) {
398       face_types["degen"].push_back(p);
399     }
400     // is face a single triangle?
401     else if((verts[p] == verts[n_lat + p] && verts[p2] != verts[n_lat + p2]) ||
402             (verts[p] != verts[n_lat + p] && verts[p2] == verts[n_lat + p2])) {
403       face_types["single_tri"].push_back(p);
404     }
405     // is face a recombined quad?
406     else if(forbiddenExists(v_face, forbidden_edges))
407       face_types["recomb"].push_back(p);
408 
409     // Does face contain a fixed diagonal edge?
410     else if(edgeExists(verts[p], verts[p2 + n_lat], quadToTri_edges)) {
411       nfix1[p] = p;
412       nfix2[p] = p2 + n_lat;
413       face_types["fixed_diag"].push_back(p);
414     }
415     else if(edgeExists(verts[n_lat + p], verts[p2], quadToTri_edges)) {
416       nfix1[p] = p + n_lat;
417       nfix2[p] = p2;
418       face_types["fixed_diag"].push_back(p);
419     }
420 
421     // Does the face have an adjustable but required diagonal?
422     // ( this else if requires that the previous one about fixed diagonals
423     //  comes FIRST )
424     else if(edgeExists(verts[p], verts[p2 + n_lat], lat_tri_diags)) {
425       nadj1[p] = p;
426       nadj2[p] = p2 + n_lat;
427       face_types["adj_diag"].push_back(p);
428     }
429     else if(edgeExists(verts[n_lat + p], verts[p2], lat_tri_diags)) {
430       nadj1[p] = p + n_lat;
431       nadj2[p] = p2;
432       face_types["adj_diag"].push_back(p);
433     }
434 
435     // If no previous option was true, then this face is an internal face.
436 
437     // If this face has NO vertices on a lateral surface, and is a triangle or
438     //  not in the top quadToTri layer:
439     // then the face is a recombined quad (QuadToTri only used in recombined
440     // extrusions).
441     else if(!touch_bnd[p] &&
442             (j < j_top_start || (j == j_top_start && k < k_top_start)))
443       face_types["recomb"].push_back(p);
444 
445     // Face is possibly free...will need to do tests after this loop is complete
446     // to finalize that. But, for now....
447     else {
448       face_types["free"].push_back(p);
449       free_flag[p] = 1;
450     }
451   }
452 
453   // set the bottom:
454   if(n_lat == 3)
455     face_types["single_tri"].push_back(3);
456 
457   else {
458     std::vector<MVertex *> v_bot;
459     v_bot.assign(4, (MVertex *)(0));
460     v_bot[0] = verts[0];
461     v_bot[1] = verts[1];
462     v_bot[2] = verts[2];
463     v_bot[3] = verts[3];
464     // is forbidden?
465     if((j == 0 && k == 0) || forbiddenExists(v_bot, forbidden_edges))
466       face_types["recomb"].push_back(4);
467     else if(edgeExists(verts[0], verts[2], quadToTri_edges)) {
468       nfix1[4] = 0;
469       nfix2[4] = 2;
470       face_types["fixed_diag"].push_back(4);
471     }
472     else if(edgeExists(verts[1], verts[3], quadToTri_edges)) {
473       nfix1[4] = 1;
474       nfix2[4] = 3;
475       face_types["fixed_diag"].push_back(4);
476     }
477     // Does the face have an adjustable but required diagonal?
478     // ( this else if requires that the previous one about fixed diagonals
479     //  comes FIRST )
480     // NOTE: THIS SITUATION SHOULD NEVER HAPPEN ON THIS FACE
481     else if(edgeExists(verts[0], verts[2], lat_tri_diags)) {
482       nadj1[4] = 0;
483       nadj2[4] = 2;
484       face_types["adj_diag"].push_back(4);
485     }
486     else if(edgeExists(verts[1], verts[3], lat_tri_diags)) {
487       nadj1[4] = 1;
488       nadj2[4] = 3;
489       face_types["adj_diag"].push_back(4);
490     }
491     else {
492       face_types["free"].push_back(4);
493       free_flag[4] = 1;
494     }
495   }
496 
497   // set the top:
498   if(n_lat == 3) face_types["single_tri"].push_back(4);
499   // if a hexahedron:
500   else {
501     std::vector<MVertex *> v_top;
502     v_top.assign(4, (MVertex *)(0));
503     v_top[0] = verts[4];
504     v_top[1] = verts[5];
505     v_top[2] = verts[6];
506     v_top[3] = verts[7];
507     // is forbidden ?
508     if(forbiddenExists(v_top, forbidden_edges))
509       face_types["recomb"].push_back(5);
510     // search for a fixed edge:
511     else if(edgeExists(verts[4], verts[6], quadToTri_edges)) {
512       nfix1[5] = 4;
513       nfix2[5] = 6;
514       face_types["fixed_diag"].push_back(5);
515     }
516     else if(edgeExists(verts[5], verts[7], quadToTri_edges)) {
517       nfix1[5] = 5;
518       nfix2[5] = 7;
519       face_types["fixed_diag"].push_back(5);
520     }
521     // Does the face have an adjustable but required diagonal?
522     // ( this else if requires that the previous one about fixed diagonals
523     //  comes FIRST )
524     // NOTE: THIS SITUATION SHOULD NEVER HAPPEN ON THIS FACE
525     else if(edgeExists(verts[4], verts[6], lat_tri_diags)) {
526       nadj1[5] = 4;
527       nadj2[5] = 6;
528       face_types["adj_diag"].push_back(5);
529     }
530     else if(edgeExists(verts[5], verts[7], lat_tri_diags)) {
531       nadj1[5] = 5;
532       nadj2[5] = 7;
533       face_types["adj_diag"].push_back(5);
534     }
535     else {
536       face_types["free"].push_back(5);
537       free_flag[5] = 1;
538     }
539   }
540 
541   // now return face_types
542   return face_types;
543 }
544 
545 // Generate face diagonals used to subdivide prisms by BRUTE FORCE...NOT
546 // RECOMMENDED for general use, but it is required for some elements which have
547 // all vertices on an external region boundary. Added 2010-01-29
bruteForceEdgeQuadToTriPrism(GRegion * gr,MElement * elem,int j,int k,std::vector<MVertex * > verts,std::map<std::string,std::vector<int>> & face_types,std::set<std::pair<MVertex *,MVertex * >> & edges_new,std::set<std::pair<MVertex *,MVertex * >> & forbidden_new,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::vector<int> nfix1,std::vector<int> nfix2,std::vector<int> nadj1,std::vector<int> nadj2,std::vector<int> free_flag)548 static void bruteForceEdgeQuadToTriPrism(
549   GRegion *gr, MElement *elem, int j, int k, std::vector<MVertex *> verts,
550   std::map<std::string, std::vector<int> > &face_types,
551   std::set<std::pair<MVertex *, MVertex *> > &edges_new,
552   std::set<std::pair<MVertex *, MVertex *> > &forbidden_new,
553   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
554   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
555   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
556   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
557     &problems_new,
558   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
559     &problems,
560   std::vector<int> nfix1, std::vector<int> nfix2, std::vector<int> nadj1,
561   std::vector<int> nadj2, std::vector<int> free_flag)
562 {
563   ExtrudeParams *ep = gr->meshAttributes.extrude;
564 
565   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
566     Msg::Error("In bruteForceEdgeQuadToTriPrism(), invalid extrusion "
567                "in region %d for performing QuadToTri mesh generation.",
568                gr->tag());
569     return;
570   }
571 
572   GModel *model = gr->model();
573   if(!model) {
574     Msg::Error("In bruteForceEdgeQuadToTriPrism(), invalid model for region "
575                "%d.",
576                gr->tag());
577     return;
578   }
579 
580   // now find and verify the source of region
581 
582   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
583   if(!reg_source) {
584     Msg::Error(
585       "In bruteForceEdgeQuadToTriPrism(), invalid source face for region "
586       "%d.",
587       gr->tag());
588     return;
589   }
590 
591   // verify number of vertices
592   // int n_lat;
593   if(verts.size() != 6) {
594     Msg::Error(
595       "In bruteForceEdgeQuadToTriPrism(), number of vertices not equal "
596       "6.");
597     return;
598   }
599   // else
600   // n_lat = 3;
601 
602   // NOTE THAT FACES ARE NUMBERED CONSECUTIVELY FROM 0, starting from vertex 0
603   // and moving around laterally. Hence, the face after vertex 0 is face 0, and
604   // so forth.  The bottom and top faces are numbered (number of laterals + 1)
605   // and (number of laterals + 2), respectively.
606 
607   // numbers of each type of face
608   int num_degen = face_types["degen"].size();
609   int num_single_tri = face_types["single_tri"].size();
610   int num_recomb = face_types["recomb"].size();
611   int num_fixed_diag = face_types["fixed_diag"].size();
612   int num_adj_diag = face_types["adj_diag"].size();
613   int num_free = face_types["free"].size();
614 
615   // Make sure all faces marked forbidden in face_types have all diagonals in
616   // forbidden_edges;
617   for(int p = 0; p < num_recomb; p++) {
618     int ind = face_types["recomb"][p];
619     std::vector<MVertex *> v;
620     v.push_back(verts[ind]);
621     v.push_back(verts[(ind + 1) % 3]);
622     v.push_back(verts[(ind + 1) % 3 + 3]);
623     v.push_back(verts[ind + 3]);
624     createForbidden(v, forbidden_new);
625     createForbidden(v, forbidden_edges);
626   }
627 
628   // following must be true if this is a triangle extrusion
629   if(find(face_types["single_tri"].begin(), face_types["single_tri"].end(),
630           3) == face_types["single_tri"].end() ||
631      find(face_types["single_tri"].begin(), face_types["single_tri"].end(),
632           4) == face_types["single_tri"].end()) {
633     Msg::Error(
634       "In bruteForceEdgeQuadToTriPrism(), invalid face code for top and/or "
635       "bottom (region %d).",
636       gr->tag());
637     return;
638   }
639 
640   // Take care of the trivial case: tetrahedron:
641   if(num_single_tri == 4 && num_degen == 1) return;
642 
643   // Pyramid also very easy:
644 
645   else if(num_single_tri == 4) {
646     int ind = 0;
647     if(num_adj_diag) {
648       ind = face_types["adj_diag"][0];
649       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
650       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
651     }
652     return;
653   }
654 
655   // A PRISM IS MORE DIFFICULT:
656 
657   // First case, if exactly two laterals are forbidden to diagonalize:
658   if(num_recomb == 2) {
659     if(num_free) {
660       for(int p = 0; p < num_free; p++) {
661         int ind = face_types["free"][p];
662         std::vector<MVertex *> v;
663         v.push_back(verts[ind]);
664         v.push_back(verts[(ind + 1) % 3]);
665         v.push_back(verts[(ind + 1) % 3 + 3]);
666         v.push_back(verts[ind + 3]);
667         createForbidden(v, forbidden_new);
668         createForbidden(v, forbidden_edges);
669       }
670     }
671     else {
672       if(num_adj_diag) {
673         int ind = face_types["adj_diag"][0];
674         createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
675         createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
676       }
677       std::pair<unsigned int, unsigned int> jkpair(j, k);
678       problems[elem].insert(jkpair);
679       problems_new[elem].insert(jkpair);
680     }
681     return;
682   }
683 
684   // If 1 lateral is forbidden to diagonalize and two free, diagonalize to
685   // lowest point vector on free edge:
686   if(num_recomb == 1 && num_free == 2) {
687     int p_recomb = face_types["recomb"][0];
688     int p_free = (p_recomb + 2) % 3;
689     int ind_low = verts[p_free] < verts[p_free + 3] ? p_free : p_free + 3;
690     int add = ind_low < 3 ? 0 : 3;
691     createEdge(verts[ind_low], verts[(ind_low - add + 1) % 3 + 3 - add],
692                quadToTri_edges);
693     createEdge(verts[ind_low], verts[(ind_low - add + 1) % 3 + 3 - add],
694                edges_new);
695     createEdge(verts[ind_low], verts[(ind_low - add + 2) % 3 + 3 - add],
696                quadToTri_edges);
697     createEdge(verts[ind_low], verts[(ind_low - add + 2) % 3 + 3 - add],
698                edges_new);
699 
700     return;
701   }
702 
703   // If all faces are free, then diagonalize TWO faces based on smallest vertex
704   // pointer
705   if(num_free >= 3) {
706     int ind_low;
707     ind_low = 0;
708     for(int p = 1; p < 6; p++) {
709       if(verts[ind_low] > verts[p]) ind_low = p;
710     }
711 
712     int add = ind_low < 3 ? 0 : 3;
713 
714     createEdge(verts[ind_low], verts[(ind_low - add + 1) % 3 + 3 - add],
715                quadToTri_edges);
716     createEdge(verts[ind_low], verts[(ind_low - add + 1) % 3 + 3 - add],
717                edges_new);
718     createEdge(verts[ind_low], verts[(ind_low - add + 2) % 3 + 3 - add],
719                quadToTri_edges);
720     createEdge(verts[ind_low], verts[(ind_low - add + 2) % 3 + 3 - add],
721                edges_new);
722 
723     return;
724   }
725 
726   // If reach this point, then go through the loop of progressively permitting
727   // more face types to be considered for diagonalization.  This loop could be
728   // slow, that's why previous special cases were tried first. t=0, fixed and
729   // preferred diagonals only. t=1, allow preferred diagonals to be meshed with
730   // lowest vertex pointer in diagonal t=2, allow free faces to be meshed with
731   // lowest vertex pointer in diagonal t=3, allow any diagonal that works
732   bool valid_division = false;
733   int face_done[2] = {
734     0, 0}; // holds the face numbers for the two faces that are done
735   for(int t = 0; t < 4; t++) {
736     // variables that hold the face diagonal nodes.
737     int n1[3], n2[3];
738 
739     // if the face is completely free (t==3), face_is_free = true;
740     bool face_is_free[3];
741 
742     // set default values of the n variables
743     // to unique negative numbers; bool to false.
744     for(int p = 0; p < 3; p++) {
745       n1[p] = -p * p - p - 1;
746       n2[p] = -p * p - p - 2;
747       face_is_free[p] = false;
748     }
749 
750     for(int p = 0; p < 3; p++) {
751       // fixed diagonals
752       if(nfix1[p] >= 0) {
753         n1[p] = nfix1[p];
754         n2[p] = nfix2[p];
755       }
756       // preferred adjustable diagonals
757       else if(!t && nadj1[p] >= 0) {
758         n1[p] = nadj1[p];
759         n2[p] = nadj2[p];
760       }
761       // choose lowest vertex for t < 3, any vertex for t == 3
762       else if((t >= 1 && t < 3 && nadj1[p] >= 0) || (t == 2 && free_flag[p])) {
763         if((verts[p] < verts[(p + 1) % 3] && verts[p] < verts[p + 3]) ||
764            (verts[(p + 1) % 3 + 3] < verts[(p + 1) % 3] &&
765             verts[(p + 1) % 3 + 3] < verts[p + 3])) {
766           n1[p] = p;
767           n2[p] = (p + 1) % 3 + 3;
768         }
769         else {
770           n1[p] = p + 3;
771           n2[p] = (p + 1) % 3;
772         }
773       }
774       else if((t == 3 && (nadj1[p] >= 0)) || free_flag[p])
775         face_is_free[p] = true;
776     }
777 
778     // search for two faces that have diagonals which meet at a vertex
779     for(int p = 0; p < 3; p++) {
780       // if both faces are free, fix one by using lowest vertex pointer
781       if(face_is_free[p] && face_is_free[(p + 1) % 3]) {
782         face_is_free[p] = false;
783         if(verts[(p + 1) % 3] < verts[(p + 1) % 3 + 3]) {
784           n1[p] = p + 3;
785           n2[p] = (p + 1) % 3;
786         }
787         else {
788           n1[p] = p;
789           n2[p] = (p + 1) % 3 + 3;
790         }
791       }
792       // if first face is free and the other has a definite diagonal
793       if(face_is_free[p] && n1[(p + 1) % 3] >= 0) {
794         valid_division = true;
795         face_done[0] = p;
796         face_done[1] = (p + 1) % 3;
797         if(n1[(p + 1) % 3] == (p + 1) % 3 || n2[(p + 1) % 3] == (p + 1) % 3) {
798           n1[p] = p + 3;
799           n2[p] = (p + 1) % 3;
800         }
801         else {
802           n1[p] = p;
803           n2[p] = (p + 1) % 3 + 3;
804         }
805       }
806       // if second face is free and the other has a definite diagonal
807       else if(face_is_free[(p + 1) % 3] && n1[p] >= 0) {
808         valid_division = true;
809         face_done[0] = p;
810         face_done[1] = (p + 1) % 3;
811         if(n2[p] == (p + 1) % 3 || n1[p] == (p + 1) % 3) {
812           n1[(p + 1) % 3] = (p + 1) % 3;
813           n2[(p + 1) % 3] = (p + 2) % 3 + 3;
814         }
815         else {
816           n1[(p + 1) % 3] = (p + 1) % 3 + 3;
817           n2[(p + 1) % 3] = (p + 2) % 3;
818         }
819       }
820       // if both faces had definite diagonals
821       else if(n2[p] == n1[(p + 1) % 3] || n2[p] == n2[(p + 1) % 3] ||
822               n1[p] == n1[(p + 1) % 3] || n1[p] == n2[(p + 1) % 3]) {
823         valid_division = true;
824         face_done[0] = p;
825         face_done[1] = (p + 1) % 3;
826       }
827 
828       if(valid_division) {
829         createEdge(verts[n1[p]], verts[n2[p]], quadToTri_edges);
830         createEdge(verts[n1[p]], verts[n2[p]], edges_new);
831         createEdge(verts[n1[(p + 1) % 3]], verts[n2[(p + 1) % 3]],
832                    quadToTri_edges);
833         createEdge(verts[n1[(p + 1) % 3]], verts[n2[(p + 1) % 3]], edges_new);
834         break;
835       }
836     }
837 
838     // At this point, can break out if valid_division... OR if there is NO valid
839     // division AND if num_fixed_diag == 3, or 2 and a recomb break out of loop.
840     // This will need an internal vertex.
841     if(valid_division || (!valid_division && num_fixed_diag + num_recomb == 3))
842       break;
843 
844   } // end of outer t-loop
845 
846   // create adjustable but required diagonals that weren't yet added
847   for(int s = 0; s < num_adj_diag; s++) {
848     int ind = face_types["adj_diag"][s];
849     if(ind != face_done[0] && ind != face_done[1]) {
850       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
851       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
852     }
853   }
854 
855   if(!valid_division) {
856     std::pair<unsigned int, unsigned int> jk_pair(j, k);
857     problems[elem].insert(jk_pair);
858     problems_new[elem].insert(jk_pair);
859   }
860 
861   return;
862 }
863 
864 // Divide hexahedron degenerated at two points (degenerate face is a line) by
865 // brute force
addEdgesForQuadToTriTwoPtDegenHexa(GRegion * gr,MElement * elem,ExtrudeParams * ep,int j,int k,std::vector<MVertex * > verts,std::map<std::string,std::vector<int>> & face_types,std::set<std::pair<MVertex *,MVertex * >> & edges_new,std::set<std::pair<MVertex *,MVertex * >> & forbidden_new,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::vector<int> nfix1,std::vector<int> nfix2,std::vector<int> nadj1,std::vector<int> nadj2,std::vector<int> free_flag)866 static void addEdgesForQuadToTriTwoPtDegenHexa(
867   GRegion *gr, MElement *elem, ExtrudeParams *ep, int j, int k,
868   std::vector<MVertex *> verts,
869   std::map<std::string, std::vector<int> > &face_types,
870   std::set<std::pair<MVertex *, MVertex *> > &edges_new,
871   std::set<std::pair<MVertex *, MVertex *> > &forbidden_new,
872   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
873   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
874   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
875   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
876     &problems_new,
877   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
878     &problems,
879   std::vector<int> nfix1, std::vector<int> nfix2, std::vector<int> nadj1,
880   std::vector<int> nadj2, std::vector<int> free_flag)
881 {
882   if(!ep) return;
883 
884   // numbers of each type of face
885   // int num_degen = face_types["degen"].size();
886   // int num_single_tri = face_types["single_tri"].size();
887   // int num_recomb = face_types["recomb"].size();
888   // int num_fixed_diag = face_types["fixed_diag"].size();
889   // int num_adj_diag = face_types["adj_diag"].size();
890   int num_free = face_types["free"].size();
891 
892   int degen_face = face_types["degen"][0];
893 
894   // If all faces are free, then diagonalize TWO faces based on smallest vertex
895   // pointer
896   if(num_free >= 3) {
897     int ind_low;
898     ind_low = 0;
899     for(int p = 1; p < 8; p++) {
900       if(verts[ind_low] > verts[p]) ind_low = p;
901     }
902 
903     int add = ind_low < 4 ? 0 : 4;
904 
905     if(verts[ind_low - add] == verts[ind_low + 4 - add]) {
906       createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4],
907                  quadToTri_edges);
908       createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4], edges_new);
909       createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4 + 4],
910                  quadToTri_edges);
911       createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4 + 4], edges_new);
912     }
913     else {
914       createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4 + 4 - add],
915                  quadToTri_edges);
916       createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4 + 4 - add],
917                  edges_new);
918       int ind2;
919       if(verts[(ind_low - add + 1) % 4] == verts[(ind_low - add + 1) % 4 + 4])
920         ind2 = (ind_low - add + 3) % 4 + 4 - add;
921       else
922         ind2 = (ind_low - add + 1) % 4 + 4 - add;
923       createEdge(verts[ind_low], verts[ind2], quadToTri_edges);
924       createEdge(verts[ind_low], verts[ind2], edges_new);
925     }
926 
927     return;
928   }
929 
930   // If faces of prism not all free, look for a way to diagonalize and
931   // subdivide. t = 0, fixed and preferred adjustable diagonals t >= 1 < 3,
932   // lowest pointer on adjustables t = 2, include free faces, lowest vertex
933   // pointer diagonal on adjustable and free t = 3, not lowest vertex pointer
934   // diagonal on adjustable and free
935 
936   int face_done[2];
937   face_done[0] = -1;
938   face_done[1] = -2;
939 
940   // valid_division tells whether a valid division was found
941   bool valid_division = false;
942 
943   for(int t = 0; t < 4; t++) {
944     // these variables hold the faces and their diagonal nodes in (n1,n2)
945     int p_top = 5, n1_top = -2, n2_top = -3;
946     bool p_top_is_free = false;
947     int p_bot = 4, n1_bot = -4, n2_bot = -5;
948     bool p_bot_is_free = false;
949     int p_lat = (degen_face + 2) % 4, n1_lat = -10, n2_lat = -11;
950     bool p_lat_is_free = false;
951     for(int s = 0; s < 3; s++) {
952       int p_tmp = 0, *n1_tmp = 0, *n2_tmp = 0;
953       bool *p_is_free_tmp = 0;
954       if(!s) {
955         p_tmp = p_bot;
956         n1_tmp = &n1_bot;
957         n2_tmp = &n2_bot;
958         p_is_free_tmp = &p_bot_is_free;
959       }
960       if(s == 1) {
961         p_tmp = p_top;
962         n1_tmp = &n1_top;
963         n2_tmp = &n2_top;
964         p_is_free_tmp = &p_top_is_free;
965       }
966       if(s == 2) {
967         p_tmp = p_lat;
968         n1_tmp = &n1_lat;
969         n2_tmp = &n2_lat;
970         p_is_free_tmp = &p_lat_is_free;
971       }
972 
973       // fixed diagonals
974       if(nfix1[p_tmp] >= 0) {
975         *n1_tmp = nfix1[p_tmp];
976         *n2_tmp = nfix2[p_tmp];
977       }
978       // preferred adjustable diagonals
979       else if(!t && nadj1[p_tmp] >= 0) {
980         *n1_tmp = nadj1[p_tmp];
981         *n2_tmp = nadj2[p_tmp];
982       }
983       // choose lowest vertex for t < 3, non-lowest vertex for t == 3
984       else if((t >= 1 && t < 3 && nadj1[p_tmp] >= 0) ||
985               (t == 2 && free_flag[p_tmp])) {
986         if(p_tmp < 4) {
987           if((verts[p_tmp] < verts[(p_tmp + 1) % 4] &&
988               verts[p_tmp] < verts[p_tmp + 4]) ||
989              (verts[(p_tmp + 1) % 4 + 4] < verts[(p_tmp + 1) % 4] &&
990               verts[(p_tmp + 1) % 4 + 4] < verts[p_tmp + 4])) {
991             *n1_tmp = p_tmp;
992             *n2_tmp = (p_tmp + 1) % 4 + 4;
993           }
994           else {
995             *n1_tmp = p_tmp + 4;
996             *n2_tmp = (p_tmp + 1) % 4;
997           }
998         }
999         else {
1000           int add = p_tmp == 4 ? 0 : 4;
1001           if((verts[0 + add] < verts[1 + add] &&
1002               verts[0 + add] < verts[3 + add]) ||
1003              (verts[2 + add] < verts[1 + add] &&
1004               verts[2 + add] < verts[3 + add])) {
1005             *n1_tmp = 0 + add;
1006             *n2_tmp = 2 + add;
1007           }
1008           else {
1009             *n1_tmp = 1 + add;
1010             *n2_tmp = 3 + add;
1011           }
1012         }
1013       }
1014       else if(t == 3 && (nadj1[p_tmp] >= 0 || free_flag[p_tmp]))
1015         *p_is_free_tmp = true;
1016     }
1017 
1018     // Find any diagonals that meet at a vertex:
1019 
1020     // start with top surface and bottom surface
1021     if((n1_top >= 0 || p_top_is_free) && (n1_bot >= 0 || p_bot_is_free)) {
1022       if(p_top_is_free && p_bot_is_free) {
1023         if((verts[4] < verts[5] && verts[4] < verts[7]) ||
1024            (verts[6] < verts[5] && verts[6] < verts[7])) {
1025           n1_top = 4;
1026           n2_top = 6;
1027         }
1028         else {
1029           n1_top = 5;
1030           n2_top = 7;
1031         }
1032         n1_bot = n1_top - 4;
1033         n2_bot = n2_top - 4;
1034       }
1035       else if(n1_top >= 0 && p_bot_is_free) {
1036         n1_bot = n1_top - 4;
1037         n2_bot = n2_top - 4;
1038       }
1039       else if(n1_bot >= 0 && p_top_is_free) {
1040         n1_top = n1_bot + 4;
1041         n2_top = n2_bot + 4;
1042       }
1043       if(verts[n1_top] == verts[n1_bot] || verts[n1_top] == verts[n2_bot] ||
1044          verts[n2_top] == verts[n1_bot] || verts[n2_top] == verts[n2_bot]) {
1045         valid_division = true;
1046         face_done[0] = p_top;
1047         face_done[1] = p_bot;
1048         createEdge(verts[n1_top], verts[n2_top], quadToTri_edges);
1049         createEdge(verts[n1_top], verts[n2_top], edges_new);
1050         createEdge(verts[n1_bot], verts[n2_bot], quadToTri_edges);
1051         createEdge(verts[n1_bot], verts[n2_bot], edges_new);
1052       }
1053     }
1054 
1055     // Top surface and lateral surface
1056     if(!valid_division && (n1_top >= 0 || p_top_is_free) &&
1057        (n1_lat >= 0 || p_lat_is_free)) {
1058       if(p_top_is_free && p_lat_is_free) {
1059         if((verts[4] < verts[5] && verts[4] < verts[7]) ||
1060            (verts[6] < verts[5] && verts[6] < verts[7])) {
1061           n1_top = 4;
1062           n2_top = 6;
1063         }
1064         else {
1065           n1_top = 5;
1066           n2_top = 7;
1067         }
1068         if(n1_top == (degen_face + 2) % 4 + 4 ||
1069            n2_top == (degen_face + 2) % 4 + 4) {
1070           n1_lat = (degen_face + 2) % 4 + 4;
1071           n2_lat = (n1_lat - 4 + 1) % 4;
1072         }
1073         else {
1074           n1_lat = (degen_face + 3) % 4 + 4;
1075           n2_lat = (n1_lat - 4 + 3) % 4;
1076         }
1077       }
1078       else if(n1_top >= 0 && p_lat_is_free) {
1079         if(n1_top == (degen_face + 2) % 4 + 4 ||
1080            n2_top == (degen_face + 2) % 4 + 4) {
1081           n1_lat = (degen_face + 2) % 4 + 4;
1082           n2_lat = (n1_lat - 4 + 1) % 4;
1083         }
1084         else {
1085           n1_lat = (degen_face + 3) % 4 + 4;
1086           n2_lat = (n1_lat - 4 + 3) % 4;
1087         }
1088       }
1089       else if(n1_lat >= 0 && p_top_is_free) {
1090         if(n1_lat == (degen_face + 2) % 4 + 4 ||
1091            n2_lat == (degen_face + 2) % 4 + 4) {
1092           n1_top = (degen_face + 2) % 4 + 4;
1093           n2_top = (n1_top - 4 + 2) % 4 + 4;
1094         }
1095         else {
1096           n1_top = (degen_face + 3) % 4 + 4;
1097           n2_top = (n1_top - 4 + 2) % 4 + 4;
1098         }
1099       }
1100       if(verts[n1_top] == verts[n1_lat] || verts[n1_top] == verts[n2_lat] ||
1101          verts[n2_top] == verts[n1_lat] || verts[n2_top] == verts[n2_lat]) {
1102         valid_division = true;
1103         face_done[0] = p_top;
1104         face_done[1] = p_lat;
1105         createEdge(verts[n1_top], verts[n2_top], quadToTri_edges);
1106         createEdge(verts[n1_top], verts[n2_top], edges_new);
1107         createEdge(verts[n1_lat], verts[n2_lat], quadToTri_edges);
1108         createEdge(verts[n1_lat], verts[n2_lat], edges_new);
1109       }
1110     }
1111 
1112     // Bottom surface and lateral surface
1113     if(!valid_division && (n1_bot >= 0 || p_bot_is_free) &&
1114        (n1_lat >= 0 || p_lat_is_free)) {
1115       if(p_bot_is_free && p_lat_is_free) {
1116         if((verts[0] < verts[1] && verts[0] < verts[3]) ||
1117            (verts[2] < verts[1] && verts[2] < verts[3])) {
1118           n1_bot = 0;
1119           n2_bot = 2;
1120         }
1121         else {
1122           n1_bot = 1;
1123           n2_bot = 3;
1124         }
1125         if(n1_bot == (degen_face + 2) % 4 || n2_bot == (degen_face + 2) % 4) {
1126           n1_lat = (degen_face + 2) % 4;
1127           n2_lat = (n1_lat + 1) % 4 + 4;
1128         }
1129         else {
1130           n1_lat = (degen_face + 3) % 4;
1131           n2_lat = (n1_lat + 3) % 4 + 4;
1132         }
1133       }
1134       else if(n1_bot >= 0 && p_lat_is_free) {
1135         if(n1_bot == (degen_face + 2) % 4 || n2_bot == (degen_face + 2) % 4) {
1136           n1_lat = (degen_face + 2) % 4;
1137           n2_lat = (n1_lat + 1) % 4 + 4;
1138         }
1139         else {
1140           n1_lat = (degen_face + 3) % 4;
1141           n2_lat = (n1_lat + 3) % 4 + 4;
1142         }
1143       }
1144       else if(n1_lat >= 0 && p_bot_is_free) {
1145         if(n1_lat == (degen_face + 2) % 4 || n2_lat == (degen_face + 2) % 4) {
1146           n1_bot = (degen_face + 2) % 4;
1147           n2_bot = (n1_bot + 2) % 4;
1148         }
1149         else {
1150           n1_bot = (degen_face + 3) % 4;
1151           n2_bot = (n1_bot + 2) % 4;
1152         }
1153       }
1154       if(verts[n1_bot] == verts[n1_lat] || verts[n1_bot] == verts[n2_lat] ||
1155          verts[n2_bot] == verts[n1_lat] || verts[n2_bot] == verts[n2_lat]) {
1156         valid_division = true;
1157         face_done[0] = p_bot;
1158         face_done[1] = p_lat;
1159         createEdge(verts[n1_bot], verts[n2_bot], quadToTri_edges);
1160         createEdge(verts[n1_bot], verts[n2_bot], edges_new);
1161         createEdge(verts[n1_lat], verts[n2_lat], quadToTri_edges);
1162         createEdge(verts[n1_lat], verts[n2_lat], edges_new);
1163       }
1164     }
1165 
1166     if(valid_division) break;
1167 
1168   } // end of t-loop (outer loop)
1169 
1170   // take care of any adjustable but required diagonals not yet added
1171   for(unsigned int s = 0; s < face_types["adj_diag"].size(); s++) {
1172     int ind = face_types["adj_diag"][s];
1173     if(ind != face_done[0] && ind != face_done[1]) {
1174       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
1175       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
1176     }
1177   }
1178 
1179   // if no division top found, need internal vertex.
1180   if(!valid_division) {
1181     std::pair<unsigned int, unsigned int> jkpair(j, k);
1182     problems[elem].insert(jkpair);
1183     problems_new[elem].insert(jkpair);
1184   }
1185 
1186   return;
1187 }
1188 
1189 // Divide a hexahedron degenerate at one point (one degenerate corner) by brute
1190 // force.
addEdgesForQuadToTriOnePtDegenHexa(GRegion * gr,MElement * elem,ExtrudeParams * ep,int j,int k,std::vector<MVertex * > verts,std::map<std::string,std::vector<int>> & face_types,std::set<std::pair<MVertex *,MVertex * >> & edges_new,std::set<std::pair<MVertex *,MVertex * >> & forbidden_new,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::vector<int> nfix1,std::vector<int> nfix2,std::vector<int> nadj1,std::vector<int> nadj2,std::vector<int> free_flag)1191 static void addEdgesForQuadToTriOnePtDegenHexa(
1192   GRegion *gr, MElement *elem, ExtrudeParams *ep, int j, int k,
1193   std::vector<MVertex *> verts,
1194   std::map<std::string, std::vector<int> > &face_types,
1195   std::set<std::pair<MVertex *, MVertex *> > &edges_new,
1196   std::set<std::pair<MVertex *, MVertex *> > &forbidden_new,
1197   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
1198   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
1199   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
1200   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
1201     &problems_new,
1202   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
1203     &problems,
1204   std::vector<int> nfix1, std::vector<int> nfix2, std::vector<int> nadj1,
1205   std::vector<int> nadj2, std::vector<int> free_flag)
1206 {
1207   if(!ep) return;
1208 
1209   // numbers of each type of face
1210   // int num_degen = face_types["degen"].size();
1211   // int num_single_tri = face_types["single_tri"].size();
1212   // int num_recomb = face_types["recomb"].size();
1213   // int num_fixed_diag = face_types["fixed_diag"].size();
1214   // int num_adj_diag = face_types["adj_diag"].size();
1215   int num_free = face_types["free"].size();
1216 
1217   // index of the degenerate corner
1218   int degen_ind = verts[face_types["single_tri"][0]] ==
1219                       verts[face_types["single_tri"][0] + 4] ?
1220                     face_types["single_tri"][0] :
1221                     face_types["single_tri"][1];
1222 
1223   // If all faces are free, slice from degen corner top and bottom. done.
1224   if(num_free >= 4) {
1225     createEdge(verts[degen_ind], verts[(degen_ind + 2) % 4], quadToTri_edges);
1226     createEdge(verts[degen_ind], verts[(degen_ind + 2) % 4], edges_new);
1227     createEdge(verts[degen_ind], verts[(degen_ind + 2) % 4 + 4],
1228                quadToTri_edges);
1229     createEdge(verts[degen_ind], verts[(degen_ind + 2) % 4 + 4], edges_new);
1230     return;
1231   }
1232 
1233   // If faces of degenerated hexahedron are not all free,
1234   // look for a way to diagonalize and subdivide.
1235   // t = 0, fixed and preferred adjustable diagonals
1236   // t >= 1 < 3, lowest pointer on adjustables
1237   // t = 2, include free faces, lowest vertex pointer diagonal on adjustable and
1238   // free t = 3, not lowest vertex pointer diagonal on adjustable and free
1239   int face_done[3];
1240   face_done[0] = -1;
1241   face_done[1] = -2;
1242   face_done[2] = -3;
1243   bool valid_division = false;
1244   for(int t = 0; t < 4; t++) {
1245     // first test for top bottom parallel diagonals (g=0), then pyramid with
1246     // top on corner opposite degen corner (g=1), then pyramid with top on a
1247     // corner NOT opposite to the degenerate corner (g=2), then test for
1248     // non-adjoining lateral face diagonals (g=3).
1249     int p_top = 5, n1_top = -2, n2_top = -3;
1250     bool p_top_is_free = false;
1251     int p_bot = 4, n1_bot = -4, n2_bot = -5;
1252     bool p_bot_is_free = false;
1253     int p_lat1 = (degen_ind + 1) % 4, n1_lat1 = -10, n2_lat1 = -11;
1254     bool p_lat1_is_free = false;
1255     int p_lat2 = (degen_ind + 2) % 4, n1_lat2 = -12, n2_lat2 = -13;
1256     bool p_lat2_is_free = false;
1257 
1258     // get diagonals:
1259     for(int s = 0; s < 4; s++) {
1260       int *n1_tmp, *n2_tmp, p_tmp;
1261       bool *p_tmp_is_free;
1262       if(!s) {
1263         p_tmp = p_top;
1264         n1_tmp = &n1_top;
1265         n2_tmp = &n2_top;
1266         p_tmp_is_free = &p_top_is_free;
1267       }
1268       else if(s == 1) {
1269         p_tmp = p_bot;
1270         n1_tmp = &n1_bot;
1271         n2_tmp = &n2_bot;
1272         p_tmp_is_free = &p_bot_is_free;
1273       }
1274       else if(s == 2) {
1275         p_tmp = p_lat1;
1276         n1_tmp = &n1_lat1;
1277         n2_tmp = &n2_lat1;
1278         p_tmp_is_free = &p_lat1_is_free;
1279       }
1280       else {
1281         p_tmp = p_lat2;
1282         n1_tmp = &n1_lat2;
1283         n2_tmp = &n2_lat2;
1284         p_tmp_is_free = &p_lat2_is_free;
1285       }
1286       // fixed diagonals
1287       if(nfix1[p_tmp] >= 0) {
1288         *n1_tmp = nfix1[p_tmp];
1289         *n2_tmp = nfix2[p_tmp];
1290       }
1291       // preferred adjustable diagonals
1292       else if(!t && nadj1[p_tmp] >= 0) {
1293         *n1_tmp = nadj1[p_tmp];
1294         *n2_tmp = nadj2[p_tmp];
1295       }
1296       // choose lowest vertex for t < 3, any vertex for t == 3
1297       else if((t >= 1 && t < 3 && nadj1[p_tmp] >= 0) ||
1298               (t == 2 && free_flag[p_tmp])) {
1299         if(p_tmp < 4) {
1300           if((verts[p_tmp] < verts[(p_tmp + 1) % 4] &&
1301               verts[p_tmp] < verts[p_tmp + 4]) ||
1302              (verts[(p_tmp + 1) % 4 + 4] < verts[(p_tmp + 1) % 4] &&
1303               verts[(p_tmp + 1) % 4 + 4] < verts[p_tmp + 4])) {
1304             *n1_tmp = p_tmp;
1305             *n2_tmp = (p_tmp + 1) % 4 + 4;
1306           }
1307           else {
1308             *n1_tmp = p_tmp + 4;
1309             *n2_tmp = (p_tmp + 1) % 4;
1310           }
1311         }
1312         else {
1313           int add = p_tmp == 4 ? 0 : 4;
1314           if((verts[0 + add] < verts[1 + add] &&
1315               verts[0 + add] < verts[3 + add]) ||
1316              (verts[2 + add] < verts[1 + add] &&
1317               verts[2 + add] < verts[3 + add])) {
1318             *n1_tmp = 0 + add;
1319             *n2_tmp = 2 + add;
1320           }
1321           else {
1322             *n1_tmp = 1 + add;
1323             *n2_tmp = 3 + add;
1324           }
1325         }
1326       }
1327       else if(t == 3 && (nadj1[p_tmp] >= 0 || free_flag[p_tmp]))
1328         *p_tmp_is_free = true;
1329     }
1330 
1331     // Look for valid diagonalizations
1332 
1333     // look for aligned top and bottom diags.
1334     if(!valid_division) {
1335       // assign diagonals to the 'free' faces from above
1336       if(p_top_is_free && p_bot_is_free) {
1337         if((verts[0] < verts[1] && verts[0] < verts[3]) ||
1338            (verts[2] < verts[1] && verts[2] < verts[3])) {
1339           n1_bot = 0;
1340           n2_bot = 2;
1341         }
1342         else {
1343           n1_bot = 1;
1344           n2_bot = 3;
1345         }
1346         n1_top = n1_bot + 4;
1347         n2_top = n2_bot + 4;
1348       }
1349       else if(p_top_is_free && n1_bot >= 0) {
1350         n1_top = n1_bot + 4;
1351         n2_top = n2_bot + 4;
1352       }
1353       else if(p_bot_is_free && n1_top >= 0) {
1354         n1_bot = n1_top - 4;
1355         n2_bot = n2_top - 4;
1356       }
1357       // test for valid division
1358       if(n1_top - 4 == n1_bot || n2_top - 4 == n1_bot || n1_top - 4 == n2_bot ||
1359          n2_top - 4 == n2_bot) {
1360         valid_division = true;
1361         face_done[0] = 4;
1362         face_done[1] = 5;
1363         createEdge(verts[n1_top], verts[n2_top], quadToTri_edges);
1364         createEdge(verts[n1_top], verts[n2_top], edges_new);
1365         createEdge(verts[n1_bot], verts[n2_bot], quadToTri_edges);
1366         createEdge(verts[n1_bot], verts[n2_bot], edges_new);
1367       }
1368     }
1369 
1370     // pyramid with top opposite degenerate corner
1371     if(!valid_division) {
1372       if((n1_top == (degen_ind + 2) % 4 + 4 ||
1373           n2_top == (degen_ind + 2) % 4 + 4 || p_top_is_free) &&
1374          (n2_lat1 == (degen_ind + 2) % 4 + 4 || p_lat1_is_free) &&
1375          (n1_lat2 == (degen_ind + 2) % 4 + 4 || p_lat2_is_free)) {
1376         valid_division = true;
1377         if(p_top_is_free) {
1378           n1_top = degen_ind + 4;
1379           n2_top = (degen_ind + 2) % 4 + 4;
1380         }
1381         if(p_lat1_is_free) {
1382           n1_lat1 = (degen_ind + 1) % 4;
1383           n2_lat1 = (degen_ind + 2) % 4 + 4;
1384         }
1385         if(p_lat2_is_free) {
1386           n1_lat2 = (degen_ind + 2) % 4 + 4;
1387           n2_lat2 = (degen_ind + 3) % 4;
1388         }
1389         face_done[0] = 5;
1390         face_done[1] = (degen_ind + 1) % 4;
1391         face_done[2] = (degen_ind + 2) % 4;
1392         createEdge(verts[n1_top], verts[n2_top], quadToTri_edges);
1393         createEdge(verts[n1_top], verts[n2_top], edges_new);
1394       }
1395       else if((n1_bot == (degen_ind + 2) % 4 || n2_bot == (degen_ind + 2) % 4 ||
1396                p_bot_is_free) &&
1397               (n2_lat1 == (degen_ind + 2) % 4 || p_lat1_is_free) &&
1398               (n1_lat2 == (degen_ind + 2) % 4 || p_lat2_is_free)) {
1399         valid_division = true;
1400         if(p_bot_is_free) {
1401           n1_bot = degen_ind;
1402           n2_bot = (degen_ind + 2) % 4;
1403         }
1404         if(p_lat1_is_free) {
1405           n1_lat1 = (degen_ind + 1) % 4 + 4;
1406           n2_lat1 = (degen_ind + 2) % 4;
1407         }
1408         if(p_lat2_is_free) {
1409           n1_lat2 = (degen_ind + 2) % 4;
1410           n2_lat2 = (degen_ind + 3) % 4 + 4;
1411         }
1412         face_done[0] = 4;
1413         face_done[1] = (degen_ind + 1) % 4;
1414         face_done[2] = (degen_ind + 2) % 4;
1415         createEdge(verts[n1_bot], verts[n2_bot], quadToTri_edges);
1416         createEdge(verts[n1_bot], verts[n2_bot], edges_new);
1417       }
1418 
1419       if(valid_division) {
1420         createEdge(verts[n1_lat1], verts[n2_lat1], quadToTri_edges);
1421         createEdge(verts[n1_lat1], verts[n2_lat1], edges_new);
1422         createEdge(verts[n1_lat2], verts[n2_lat2], quadToTri_edges);
1423         createEdge(verts[n1_lat2], verts[n2_lat2], edges_new);
1424       }
1425     }
1426 
1427     // Pyramid top on corner NOT opposite to degenerate corner
1428     if(!valid_division) {
1429       // pyramid top on top face
1430       if((n1_top >= 0 && n1_top != (degen_ind + 2) % 4 + 4 &&
1431           n2_top != (degen_ind + 2) % 4 + 4) ||
1432          p_top_is_free) {
1433         if(n1_lat1 == (degen_ind + 1) % 4 + 4 || p_lat1_is_free) {
1434           valid_division = true;
1435           face_done[0] = (degen_ind + 1) % 4;
1436           if(p_lat1_is_free) {
1437             n1_lat1 = (degen_ind + 1) % 4 + 4;
1438             n2_lat1 = (degen_ind + 2) % 4;
1439           }
1440           createEdge(verts[n1_lat1], verts[n2_lat1], quadToTri_edges);
1441           createEdge(verts[n1_lat1], verts[n2_lat1], edges_new);
1442         }
1443         else if(n2_lat2 == (degen_ind + 3) % 4 + 4 || p_lat2_is_free) {
1444           valid_division = true;
1445           face_done[0] = (degen_ind + 2) % 4;
1446           if(p_lat2_is_free) {
1447             n1_lat2 = (degen_ind + 2) % 4;
1448             n2_lat2 = (degen_ind + 3) % 4 + 4;
1449           }
1450           createEdge(verts[n1_lat2], verts[n2_lat2], quadToTri_edges);
1451           createEdge(verts[n1_lat2], verts[n2_lat2], edges_new);
1452         }
1453         if(valid_division) {
1454           face_done[1] = 5;
1455           if(p_top_is_free) {
1456             n1_top = (degen_ind + 1) % 4 + 4;
1457             n2_top = (degen_ind + 3) % 4 + 4;
1458           }
1459           createEdge(verts[n1_top], verts[n2_top], quadToTri_edges);
1460           createEdge(verts[n1_top], verts[n2_top], edges_new);
1461         }
1462       }
1463       // pyramid top on bottom face
1464       if((!valid_division && n1_bot >= 0 && n1_bot != (degen_ind + 2) % 4 &&
1465           n2_bot != (degen_ind + 2) % 4) ||
1466          p_bot_is_free) {
1467         if(n1_lat1 == (degen_ind + 1) % 4 || p_lat1_is_free) {
1468           valid_division = true;
1469           face_done[0] = (degen_ind + 1) % 4;
1470           if(p_lat1_is_free) {
1471             n1_lat1 = (degen_ind + 1) % 4;
1472             n2_lat1 = (degen_ind + 2) % 4 + 4;
1473           }
1474           createEdge(verts[n1_lat1], verts[n2_lat1], quadToTri_edges);
1475           createEdge(verts[n1_lat1], verts[n2_lat1], edges_new);
1476         }
1477         else if(n2_lat2 == (degen_ind + 3) % 4 || p_lat2_is_free) {
1478           valid_division = true;
1479           face_done[0] = (degen_ind + 2) % 4;
1480           if(p_lat2_is_free) {
1481             n1_lat2 = (degen_ind + 2) % 4 + 4;
1482             n2_lat2 = (degen_ind + 3) % 4;
1483           }
1484           createEdge(verts[n1_lat2], verts[n2_lat2], quadToTri_edges);
1485           createEdge(verts[n1_lat2], verts[n2_lat2], edges_new);
1486         }
1487         if(valid_division) {
1488           face_done[1] = 4;
1489           if(p_bot_is_free) {
1490             n1_bot = (degen_ind + 1) % 4;
1491             n2_bot = (degen_ind + 3) % 4;
1492           }
1493           createEdge(verts[n1_bot], verts[n2_bot], quadToTri_edges);
1494           createEdge(verts[n1_bot], verts[n2_bot], edges_new);
1495         }
1496       }
1497     }
1498     // see if the lateral diagonals have non-adjoining diagonals
1499     if(!valid_division) {
1500       if((n1_lat1 == (degen_ind + 1) % 4 || p_lat1_is_free) &&
1501          (n1_lat2 == (degen_ind + 2) % 4 || p_lat2_is_free)) {
1502         valid_division = true;
1503         n1_lat1 = (degen_ind + 1) % 4;
1504         n2_lat1 = (degen_ind + 2) % 4 + 4;
1505         n1_lat2 = (degen_ind + 2) % 4;
1506         n2_lat2 = (degen_ind + 3) % 4 + 4;
1507       }
1508       else if((n1_lat1 == (degen_ind + 1) % 4 + 4 || p_lat1_is_free) &&
1509               (n1_lat2 == (degen_ind + 2) % 4 + 4 || p_lat2_is_free)) {
1510         valid_division = true;
1511         n1_lat1 = (degen_ind + 1) % 4 + 4;
1512         n2_lat1 = (degen_ind + 2) % 4;
1513         n1_lat2 = (degen_ind + 2) % 4 + 4;
1514         n2_lat2 = (degen_ind + 3) % 4;
1515       }
1516       if(valid_division) {
1517         face_done[0] = (degen_ind + 1) % 4;
1518         face_done[1] = (degen_ind + 2) % 4;
1519         createEdge(verts[n1_lat1], verts[n2_lat1], quadToTri_edges);
1520         createEdge(verts[n1_lat1], verts[n2_lat1], edges_new);
1521         createEdge(verts[n1_lat2], verts[n2_lat2], quadToTri_edges);
1522         createEdge(verts[n1_lat2], verts[n2_lat2], edges_new);
1523       }
1524     }
1525 
1526     if(valid_division) break;
1527   }
1528 
1529   // if no subdivisiion, still take care of any adjustable but required
1530   // diagonals not yet added
1531   for(unsigned int s = 0; s < face_types["adj_diag"].size(); s++) {
1532     int ind = face_types["adj_diag"][s];
1533     if(ind != face_done[0] && ind != face_done[1] && ind != face_done[2]) {
1534       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
1535       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
1536     }
1537   }
1538 
1539   // if no division top found, need internal vertex.
1540   if(!valid_division) {
1541     std::pair<unsigned int, unsigned int> jkpair(j, k);
1542     problems[elem].insert(jkpair);
1543     problems_new[elem].insert(jkpair);
1544   }
1545 }
1546 
1547 // Divide a fully non-degenerate hexahedron by brute force.
addEdgesForQuadToTriFullHexa(GRegion * gr,MElement * elem,ExtrudeParams * ep,int j,int k,std::vector<MVertex * > verts,std::map<std::string,std::vector<int>> & face_types,std::set<std::pair<MVertex *,MVertex * >> & edges_new,std::set<std::pair<MVertex *,MVertex * >> & forbidden_new,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::vector<int> nfix1,std::vector<int> nfix2,std::vector<int> nadj1,std::vector<int> nadj2,std::vector<int> free_flag)1548 static void addEdgesForQuadToTriFullHexa(
1549   GRegion *gr, MElement *elem, ExtrudeParams *ep, int j, int k,
1550   std::vector<MVertex *> verts,
1551   std::map<std::string, std::vector<int> > &face_types,
1552   std::set<std::pair<MVertex *, MVertex *> > &edges_new,
1553   std::set<std::pair<MVertex *, MVertex *> > &forbidden_new,
1554   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
1555   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
1556   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
1557   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
1558     &problems_new,
1559   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
1560     &problems,
1561   std::vector<int> nfix1, std::vector<int> nfix2, std::vector<int> nadj1,
1562   std::vector<int> nadj2, std::vector<int> free_flag)
1563 {
1564   // There are 4 main possibilities for minimum diags to guarantee slice:
1565   // 1. Three diagonals at a corner
1566   // 2. One PAIR of opposite diagonals, ABSOLUTELY ALL OTHER FACES FORBIDDEN
1567   // 2. Two PAIRS of opposite diags
1568   // 3. One PAIR of opposite diags PLUS a vertex with two ADDITIONAL diags
1569   // meeting on it.
1570 
1571   if(!ep) return;
1572 
1573   // numbers of each type of face
1574   // int num_degen = face_types["degen"].size();
1575   // int num_single_tri = face_types["single_tri"].size();
1576   // int num_recomb = face_types["recomb"].size();
1577   int num_fixed_diag = face_types["fixed_diag"].size();
1578   int num_adj_diag = face_types["adj_diag"].size();
1579   int num_free = face_types["free"].size();
1580 
1581   // If all faces are free, then diagonalize the three faces adjacent to vertex
1582   // with
1583   //  smallest vertex pointer
1584   if(num_free >= 6) {
1585     int ind_low = getIndexForLowestVertexPointer(verts);
1586     int add = ind_low < 4 ? 0 : 4;
1587 
1588     createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4 + add],
1589                quadToTri_edges);
1590     createEdge(verts[ind_low], verts[(ind_low - add + 2) % 4 + add], edges_new);
1591     createEdge(verts[ind_low], verts[(ind_low - add + 1) % 4 + 4 - add],
1592                quadToTri_edges);
1593     createEdge(verts[ind_low], verts[(ind_low - add + 1) % 4 + 4 - add],
1594                edges_new);
1595     createEdge(verts[ind_low], verts[(ind_low - add + 3) % 4 + 4 - add],
1596                quadToTri_edges);
1597     createEdge(verts[ind_low], verts[(ind_low - add + 3) % 4 + 4 - add],
1598                edges_new);
1599     return;
1600   }
1601 
1602   // Start the loop to progressively become more permissive in what diagonals to
1603   // allow for subdivision. On t-loop, select types of diagonals to look for. t
1604   // = 0, fixed and preferred adjustables. t = 1, include non-preferred
1605   // adjustables with lowest vertex. t = 2, include free face diagonal, lowest
1606   // vertex. t = 3, on adjustable or free faces, take any diagonal that works.
1607 
1608   // this variable records the faces selected for diagonalization
1609   int face_done[4];
1610   for(int p = 0; p < 4; p++) face_done[p] = -1 - p;
1611 
1612   // if find just two diagonals that could slice a prism with no other diags,
1613   // remember ('hold') those diagonals until end of loop in the following 'hold'
1614   // variables. Might have to resort to forbidding free surfaces and cutting two
1615   // prisms only. don't really want to forbid surfaces, though...that's why two
1616   // prisms are not immediately cut when found.
1617   int p1_hold = -1,
1618       p2_hold = -2; // if found two opposite diags that could work alone
1619   int n1_hold[2] = {0, 0},
1620       n2_hold[2] = {0, 0}; // hold diag nodes for p1_hold, p2_hold.
1621   bool valid_division = false;
1622 
1623   for(int t = 0; t < 4; t++) {
1624     // variables that hold the face diagonal nodes.
1625     int n1[6], n2[6];
1626 
1627     // if the face is completely free (t==3), face_is_free = true;
1628     bool face_is_free[6];
1629 
1630     // set default values of the n variables
1631     // to unique negative numbers; bool to false.
1632     for(int p = 0; p < 6; p++) {
1633       n1[p] = -p * p - p - 1;
1634       n2[p] = -p * p - p - 2;
1635       face_is_free[p] = false;
1636     }
1637 
1638     for(int p = 0; p < 6; p++) {
1639       // fixed diagonals
1640       if(nfix1[p] >= 0) {
1641         n1[p] = nfix1[p];
1642         n2[p] = nfix2[p];
1643       }
1644       // preferred adjustable diagonals
1645       else if(!t && nadj1[p] >= 0) {
1646         n1[p] = nadj1[p];
1647         n2[p] = nadj2[p];
1648       }
1649       // choose lowest vertex for t < 3, any vertex for t == 3
1650       else if((t >= 1 && t < 3 && nadj1[p] >= 0) || (t == 2 && free_flag[p])) {
1651         if(p < 4) {
1652           if((verts[p] < verts[(p + 1) % 4] && verts[p] < verts[p + 4]) ||
1653              (verts[(p + 1) % 4 + 4] < verts[(p + 1) % 4] &&
1654               verts[(p + 1) % 4 + 4] < verts[p + 4])) {
1655             n1[p] = p;
1656             n2[p] = (p + 1) % 4 + 4;
1657           }
1658           else {
1659             n1[p] = p + 4;
1660             n2[p] = (p + 1) % 4;
1661           }
1662         }
1663         else {
1664           int add = p == 4 ? 0 : 4;
1665           if((verts[0 + add] < verts[1 + add] &&
1666               verts[0 + add] < verts[3 + add]) ||
1667              (verts[2 + add] < verts[1 + add] &&
1668               verts[2 + add] < verts[3 + add])) {
1669             n1[p] = 0 + add;
1670             n2[p] = 2 + add;
1671           }
1672           else {
1673             n1[p] = 1 + add;
1674             n2[p] = 3 + add;
1675           }
1676         }
1677       }
1678       else if(t == 3 && (nadj1[p] >= 0 || free_flag[p]))
1679         face_is_free[p] = true;
1680     }
1681 
1682     // Now perform the tests to find the valid subdivision
1683 
1684     // first, do the test to find opposite aligned diagonals for "prism slice
1685     // through" Not verified, but I believe this gives better quality elements
1686     // than 3-diag corners
1687     if(!valid_division) {
1688       for(int p = 0; p < 3; p++) {
1689         int p1 = -1, p2 = -2;
1690         // prism slicing faces
1691         if(p > 1) {
1692           p1 = 4;
1693           p2 = 5;
1694         }
1695         else {
1696           p1 = p;
1697           p2 = (p + 2) % 4;
1698         }
1699 
1700         // if these two faces do not work for opposite aligned diagonals,
1701         // continue
1702         if((n1[p1] < 0 && !face_is_free[p1]) ||
1703            (n1[p2] < 0 && !face_is_free[p2]))
1704           continue;
1705         if(n1[p1] >= 0 && n1[p2] >= 0) {
1706           if(p1 < 4) {
1707             if(((n1[p1] == p1 || n2[p1] == p1) && n1[p2] != p2 + 4 &&
1708                 n2[p2] != p2 + 4) ||
1709                ((n1[p1] == p1 + 4 || n2[p1] == p1 + 4) && n1[p2] != p2 &&
1710                 n2[p2] != p2))
1711               continue;
1712           }
1713           else {
1714             int add = p1 == 4 ? 4 : -4;
1715             if(n1[p1] + add != n1[p2] && n2[p1] + add != n1[p2]) continue;
1716           }
1717         }
1718 
1719         // if TWO faces are free, set one to the lowest pointer
1720         if(face_is_free[p1] && face_is_free[p2]) {
1721           face_is_free[p1] = false;
1722           if(p1 < 4) {
1723             if((verts[p1] < verts[p1 + 4] && verts[p1] < verts[(p1 + 1) % 4]) ||
1724                (verts[(p1 + 1) % 4 + 4] < verts[p1 + 4] &&
1725                 verts[(p1 + 1) % 4 + 4] < verts[(p1 + 1) % 4])) {
1726               n1[p1] = p1;
1727               n2[p1] = (p1 + 1) % 4 + 4;
1728             }
1729             else {
1730               n1[p1] = (p1 + 4);
1731               n2[p1] = (p1 + 1) % 4;
1732             }
1733           }
1734           else {
1735             int add = p1 == 4 ? 0 : 4;
1736             if((verts[0 + add] < verts[1 + add] &&
1737                 verts[0 + add] < verts[3 + add]) ||
1738                (verts[2 + add] < verts[1 + add] &&
1739                 verts[2 + add] < verts[3 + add])) {
1740               n1[p1] = 0 + add;
1741               n2[p1] = 2 + add;
1742             }
1743             else {
1744               n1[p1] = 1 + add;
1745               n2[p1] = 3 + add;
1746             }
1747           }
1748         }
1749 
1750         // if one and ONLY one face is free, go ahead and set it to match the
1751         // other now.
1752         if(n1[p1] >= 0 && face_is_free[p2]) {
1753           if(p1 < 4) {
1754             if(n1[p1] == p1 || n2[p1] == p1) {
1755               n1[p2] = p2 + 4;
1756               n2[p2] = (p2 + 1) % 4;
1757             }
1758             else {
1759               n1[p2] = p2;
1760               n2[p2] = (p2 + 1) % 4 + 4;
1761             }
1762           }
1763           else {
1764             int add = p1 == 4 ? 4 : -4;
1765             n1[p2] = n1[p1] + add;
1766             n2[p2] = n2[p1] + add;
1767           }
1768           face_is_free[p2] = false;
1769         }
1770         else if(n1[p2] >= 0 && face_is_free[p1]) {
1771           if(p1 < 4) {
1772             if(n1[p2] == p2 || n2[p2] == p2) {
1773               n1[p1] = p1 + 4;
1774               n2[p1] = (p1 + 1) % 4;
1775             }
1776             else {
1777               n1[p1] = p1;
1778               n2[p1] = (p1 + 1) % 4 + 4;
1779             }
1780           }
1781           else {
1782             int add = p2 == 4 ? 4 : -4;
1783             n1[p1] = n1[p2] + add;
1784             n2[p1] = n2[p2] + add;
1785           }
1786           face_is_free[p1] = false;
1787         }
1788 
1789         // In case the whole loop finishes and
1790         // cannot make further diagonalizations on any faces to make the prism
1791         // slice work, AND if there are no oter required diagonals other than
1792         // among these two diagonals, then it will be possible to come back to
1793         // these two opposing diagonals to make a simple two-prism slice.  So,
1794         // if there are no other diags, hold these two valid opposing diagonals
1795         // in case we want to come back to them later to just have two opposing
1796         // diagonals with the other faces forbidden.
1797         if(p1_hold < 0 || p2_hold < 0) {
1798           int required_diag_count = 0;
1799           if(nfix1[p1] >= 0 || nadj1[p1] >= 0) required_diag_count++;
1800           if(nfix1[p2] >= 0 || nadj1[p2] >= 0) required_diag_count++;
1801           if(p1_hold < 0 &&
1802              num_fixed_diag + num_adj_diag <= required_diag_count) {
1803             p1_hold = p1;
1804             p2_hold = p2;
1805             n1_hold[0] = n1[p1];
1806             n2_hold[0] = n2[p1];
1807             n1_hold[1] = n1[p2];
1808             n2_hold[1] = n2[p2];
1809           }
1810         }
1811 
1812         // Two tests to see if this prism slice-through will work:
1813         // 1: if there is another set of opposing faces with aligned diagonals.
1814         // 2: if two diagonals on one of the remaining 4 faces meet, valid.
1815 
1816         // Test 1: Another set of opposite, aligned diagonals.
1817         for(int s = 0; s < 3; s++) {
1818           if(s == p1 || (s > 1 && (p1 == 4 || p1 == 5))) continue;
1819           int s1, s2;
1820           if(s > 1) {
1821             s1 = 4;
1822             s2 = 5;
1823           }
1824           else {
1825             s1 = s;
1826             s2 = (s + 2) % 4;
1827           }
1828           // if these two faces do not work for opposite aligned diagonals,
1829           // continue
1830           if((n1[s1] < 0 && !face_is_free[s1]) ||
1831              (n1[s2] < 0 && !face_is_free[s2]))
1832             continue;
1833           if(n1[s1] >= 0 && n1[s2] >= 0) {
1834             if(s1 < 4) {
1835               if(((n1[s1] == s1 || n2[s1] == s1) && n1[s2] != s2 + 4 &&
1836                   n2[s2] != s2 + 4) ||
1837                  ((n1[s1] == s1 + 4 || n2[s1] == s1 + 4) && n1[s2] != s2 &&
1838                   n2[s2] != s2))
1839                 continue;
1840             }
1841             else {
1842               int add = s1 == 4 ? 4 : -4;
1843               if(n1[s1] + add != n1[s2] && n2[s1] + add != n1[s2]) continue;
1844             }
1845           }
1846 
1847           valid_division = true;
1848           face_done[0] = p1;
1849           face_done[1] = p2;
1850           face_done[2] = s1;
1851           face_done[3] = s2;
1852 
1853           // if TWO faces are free, set one to the lowest pointer
1854           if(face_is_free[s1] && face_is_free[s2]) {
1855             face_is_free[s1] = false;
1856             if(s1 < 4) {
1857               if((verts[s1] < verts[s1 + 4] &&
1858                   verts[s1] < verts[(s1 + 1) % 4]) ||
1859                  (verts[(s1 + 1) % 4 + 4] < verts[s1 + 4] &&
1860                   verts[(s1 + 1) % 4 + 4] < verts[(s1 + 1) % 4])) {
1861                 n1[s1] = s1;
1862                 n2[s1] = (s1 + 1) % 4 + 4;
1863               }
1864               else {
1865                 n1[s1] = (s1 + 4);
1866                 n2[s1] = (s1 + 1) % 4;
1867               }
1868             }
1869             else {
1870               int add = s1 == 4 ? 0 : 4;
1871               if((verts[0 + add] < verts[1 + add] &&
1872                   verts[0 + add] < verts[3 + add]) ||
1873                  (verts[2 + add] < verts[1 + add] &&
1874                   verts[2 + add] < verts[3 + add])) {
1875                 n1[s1] = 0 + add;
1876                 n2[s1] = 2 + add;
1877               }
1878               else {
1879                 n1[s1] = 1 + add;
1880                 n2[s1] = 3 + add;
1881               }
1882             }
1883           }
1884 
1885           // if ONLY one face is free, go ahead and set it to match the other
1886           // now.
1887           if(n1[s1] >= 0 && face_is_free[s2]) {
1888             if(s1 < 4) {
1889               if(n1[s1] == s1 || n2[s1] == s1) {
1890                 n1[s2] = s2 + 4;
1891                 n2[s2] = (s2 + 1) % 4;
1892               }
1893               else {
1894                 n1[s2] = s2;
1895                 n2[s2] = (s2 + 1) % 4 + 4;
1896               }
1897             }
1898             else {
1899               int add = s1 == 4 ? 4 : -4;
1900               n1[s2] = n1[s1] + add;
1901               n2[s2] = n2[s1] + add;
1902             }
1903             face_is_free[s2] = false;
1904           }
1905           else if(n1[s2] >= 0 && face_is_free[s1]) {
1906             if(s1 < 4) {
1907               if(n1[s2] == s2 || n2[s2] == s2) {
1908                 n1[s1] = s1 + 4;
1909                 n2[s1] = (s1 + 1) % 4;
1910               }
1911               else {
1912                 n1[s1] = s1;
1913                 n2[s1] = (s1 + 1) % 4 + 4;
1914               }
1915             }
1916             else {
1917               int add = s2 == 4 ? 4 : -4;
1918               n1[s1] = n1[s2] + add;
1919               n2[s1] = n2[s2] + add;
1920             }
1921             face_is_free[s1] = false;
1922           }
1923 
1924           if(valid_division) break;
1925         }
1926 
1927         // Test 2: any vertex has two diagonals meeting at it, NOT including the
1928         // diagonals on p1, p2;
1929         if(!valid_division) {
1930           for(int s = 0; s < 8; s++) { // looping over vertices now, be careful
1931             int add = s < 4 ? 0 : 4;
1932             std::vector<int> faces;
1933             faces.assign(2, -1);
1934             int third_face = s < 4 ? 4 : 5;
1935             int count_diags = 0;
1936             if(s - add != p1 && s - add != p2 &&
1937                (n1[(s - add)] == s || n2[(s - add)] == s ||
1938                 face_is_free[(s - add)])) {
1939               faces[count_diags] = s - add;
1940               count_diags++;
1941             }
1942             if((s - add + 3) % 4 != p1 && (s - add + 3) % 4 != p2 &&
1943                (n1[(s - add + 3) % 4] == s || n2[(s - add + 3) % 4] == s ||
1944                 face_is_free[(s - add + 3) % 4])) {
1945               faces[count_diags] = (s - add + 3) % 4;
1946               count_diags++;
1947             }
1948             if(count_diags < 2 && third_face != p1 && third_face != p2 &&
1949                (n1[third_face] == s || n2[third_face] == s ||
1950                 face_is_free[third_face])) {
1951               faces[count_diags] = third_face;
1952               count_diags++;
1953             }
1954 
1955             // if valid subdivision NOT found
1956             if(count_diags < 2) continue;
1957 
1958             // if valid subdivision found
1959 
1960             valid_division = true;
1961 
1962             face_done[0] = p1;
1963             face_done[1] = p2;
1964             face_done[2] = faces[0];
1965             face_done[3] = faces[1];
1966 
1967             if(face_is_free[s - add]) {
1968               n1[s - add] = s;
1969               n2[s - add] = (s - add + 1) % 4 + 4 - add;
1970             }
1971             if(face_is_free[(s - add + 3) % 4]) {
1972               n1[(s - add + 3) % 4] = s;
1973               n2[(s - add + 3) % 4] = (s - add + 3) % 4 + 4 - add;
1974             }
1975             if(face_is_free[third_face]) {
1976               n1[third_face] = s;
1977               n2[third_face] = (s - add + 2) % 4 + add;
1978             }
1979 
1980             if(valid_division) break;
1981           }
1982         } // end of test 2
1983 
1984         if(valid_division) {
1985           createEdge(verts[n1[face_done[0]]], verts[n2[face_done[0]]],
1986                      quadToTri_edges);
1987           createEdge(verts[n1[face_done[0]]], verts[n2[face_done[0]]],
1988                      edges_new);
1989           createEdge(verts[n1[face_done[1]]], verts[n2[face_done[1]]],
1990                      quadToTri_edges);
1991           createEdge(verts[n1[face_done[1]]], verts[n2[face_done[1]]],
1992                      edges_new);
1993           createEdge(verts[n1[face_done[2]]], verts[n2[face_done[2]]],
1994                      quadToTri_edges);
1995           createEdge(verts[n1[face_done[2]]], verts[n2[face_done[2]]],
1996                      edges_new);
1997           createEdge(verts[n1[face_done[3]]], verts[n2[face_done[3]]],
1998                      quadToTri_edges);
1999           createEdge(verts[n1[face_done[3]]], verts[n2[face_done[3]]],
2000                      edges_new);
2001           break;
2002         }
2003       } // end of p loop over first set of opposite faces
2004     }
2005 
2006     // Test for 3 diagonals on a corner.
2007     if(!valid_division) {
2008       for(int p = 0; p < 8; p++) { // looping over vertices now, be careful
2009         int add = p < 4 ? 0 : 4;
2010         int third_face = p < 4 ? 4 : 5;
2011         if((n1[(p - add)] == p || n2[(p - add)] == p ||
2012             face_is_free[(p - add)]) &&
2013            (n1[(p - add + 3) % 4] == p || n2[(p - add + 3) % 4] == p ||
2014             face_is_free[(p - add + 3) % 4]) &&
2015            (n1[third_face] == p || n2[third_face] == p ||
2016             face_is_free[third_face])) {
2017           valid_division = true;
2018           if(face_is_free[p - add]) {
2019             n1[p - add] = p;
2020             n2[p - add] = (p - add + 1) % 4 + 4 - add;
2021           }
2022           if(face_is_free[(p - add + 3) % 4]) {
2023             n1[(p - add + 3) % 4] = p;
2024             n2[(p - add + 3) % 4] = (p - add + 3) % 4 + 4 - add;
2025           }
2026           if(face_is_free[third_face]) {
2027             n1[third_face] = p;
2028             n2[third_face] = (p - add + 2) % 4 + add;
2029           }
2030 
2031           face_done[0] = (p - add);
2032           face_done[1] = (p - add + 3) % 4;
2033           face_done[2] = third_face;
2034 
2035           createEdge(verts[n1[(p - add)]], verts[n2[(p - add)]],
2036                      quadToTri_edges);
2037           createEdge(verts[n1[(p - add)]], verts[n2[(p - add)]], edges_new);
2038           createEdge(verts[n1[(p - add + 3) % 4]], verts[n2[(p - add + 3) % 4]],
2039                      quadToTri_edges);
2040           createEdge(verts[n1[(p - add + 3) % 4]], verts[n2[(p - add + 3) % 4]],
2041                      edges_new);
2042           createEdge(verts[n1[third_face]], verts[n2[third_face]],
2043                      quadToTri_edges);
2044           createEdge(verts[n1[third_face]], verts[n2[third_face]], edges_new);
2045           break;
2046         }
2047       }
2048     }
2049 
2050     if(valid_division) break;
2051 
2052   } // end of t loop (outer loop)
2053 
2054   // If no valid division yet but yet there were two opposite faces once
2055   // ( if this won't work, should be the case that p1_hold < 0 here )
2056   if(!valid_division && p1_hold >= 0) {
2057     valid_division = true;
2058     face_done[0] = p1_hold;
2059     face_done[1] = p2_hold;
2060     createEdge(verts[n1_hold[0]], verts[n2_hold[0]], quadToTri_edges);
2061     createEdge(verts[n1_hold[0]], verts[n2_hold[0]], edges_new);
2062     createEdge(verts[n1_hold[1]], verts[n2_hold[1]], quadToTri_edges);
2063     createEdge(verts[n1_hold[1]], verts[n2_hold[1]], edges_new);
2064 
2065     // create forbidden faces
2066     for(unsigned int s = 0; s < face_types["free"].size(); s++) {
2067       int s_tmp = face_types["free"][s];
2068       std::vector<MVertex *> v_free;
2069       if(s_tmp == p1_hold || s_tmp == p2_hold) continue;
2070       if(s_tmp < 4) {
2071         v_free.push_back(verts[s_tmp]);
2072         v_free.push_back(verts[(s_tmp + 1) % 4]);
2073         v_free.push_back(verts[(s_tmp + 1) % 4 + 4]);
2074         v_free.push_back(verts[s_tmp + 4]);
2075       }
2076       else {
2077         int add = s_tmp == 4 ? 0 : 4;
2078         v_free.push_back(verts[add]);
2079         v_free.push_back(verts[add + 1]);
2080         v_free.push_back(verts[add + 2]);
2081         v_free.push_back(verts[add + 3]);
2082       }
2083       createForbidden(v_free, forbidden_edges);
2084       createForbidden(v_free, forbidden_new);
2085     }
2086   }
2087 
2088   // take care of any adjustable but required diagonals not yet added
2089   for(unsigned int s = 0; s < face_types["adj_diag"].size(); s++) {
2090     int ind = face_types["adj_diag"][s];
2091     if(ind == face_done[0] || ind == face_done[1] || ind == face_done[2] ||
2092        ind == face_done[3])
2093       continue;
2094     createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
2095     createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
2096   }
2097 
2098   // if no valid division found, problematic.
2099   if(!valid_division) {
2100     std::pair<unsigned int, unsigned int> jkpair(j, k);
2101     problems[elem].insert(jkpair);
2102     problems_new[elem].insert(jkpair);
2103   }
2104 }
2105 
2106 // Generate face diagonals to subdivide hexahedra by BRUTE FORCE.  Not
2107 // recommended for general use, but it is required for some elements which have
2108 // all vertices on an external region boundary. Added 2010-01-29
bruteForceEdgeQuadToTriHexa(GRegion * gr,MElement * elem,int j,int k,std::vector<MVertex * > verts,std::map<std::string,std::vector<int>> & face_types,std::set<std::pair<MVertex *,MVertex * >> & edges_new,std::set<std::pair<MVertex *,MVertex * >> & forbidden_new,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,const std::vector<int> & nfix1,const std::vector<int> & nfix2,std::vector<int> nadj1,std::vector<int> nadj2,const std::vector<int> & free_flag)2109 static void bruteForceEdgeQuadToTriHexa(
2110   GRegion *gr, MElement *elem, int j, int k, std::vector<MVertex *> verts,
2111   std::map<std::string, std::vector<int> > &face_types,
2112   std::set<std::pair<MVertex *, MVertex *> > &edges_new,
2113   std::set<std::pair<MVertex *, MVertex *> > &forbidden_new,
2114   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
2115   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
2116   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
2117   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
2118     &problems_new,
2119   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
2120     &problems,
2121   const std::vector<int> &nfix1, const std::vector<int> &nfix2,
2122   std::vector<int> nadj1, std::vector<int> nadj2,
2123   const std::vector<int> &free_flag)
2124 {
2125   ExtrudeParams *ep = gr->meshAttributes.extrude;
2126 
2127   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
2128     Msg::Error("In bruteForceEdgeQuadToTriHexa(), invalid extrusion "
2129                "in region %d for performing QuadToTri mesh generation.",
2130                gr->tag());
2131     return;
2132   }
2133 
2134   GModel *model = gr->model();
2135   if(!model) {
2136     Msg::Error("In bruteForceEdgeQuadToTriHexa(), invalid model for region "
2137                "%d.",
2138                gr->tag());
2139     return;
2140   }
2141 
2142   // now find and verify the source and the top of region
2143 
2144   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
2145   if(!reg_source) {
2146     Msg::Error(
2147       "In bruteForceEdgeQuadToTriHexa(), invalid source face for region "
2148       "%d.",
2149       gr->tag());
2150     return;
2151   }
2152 
2153   // verify number of vertices
2154   // int n_lat;
2155   if(verts.size() != 8) {
2156     Msg::Error(
2157       "In bruteForceEdgeQuadToTriHexa(), number of vertices not equal 8.");
2158     return;
2159   }
2160   // else
2161   // n_lat = 4;
2162 
2163   // numbers of each type of face
2164   // int num_degen = face_types["degen"].size();
2165   // int num_single_tri = face_types["single_tri"].size();
2166   int num_recomb = face_types["recomb"].size();
2167   // int num_fixed_diag = face_types["fixed_diag"].size();
2168   int num_adj_diag = face_types["adj_diag"].size();
2169   // int num_free = face_types["free"].size();
2170 
2171   // Make sure all faces marked forbidden in face_types have all diagonals in
2172   // forbidden_edges;
2173   for(int p = 0; p < num_recomb; p++) {
2174     int ind = face_types["recomb"][p];
2175     std::vector<MVertex *> v;
2176     if(ind == 4 || ind == 5) {
2177       int add = (ind == 4) ? 0 : 4;
2178       v.push_back(verts[0 + add]);
2179       v.push_back(verts[1 + add]);
2180       v.push_back(verts[2 + add]);
2181       v.push_back(verts[3 + add]);
2182     }
2183     else {
2184       v.push_back(verts[ind]);
2185       v.push_back(verts[(ind + 1) % 4]);
2186       v.push_back(verts[(ind + 1) % 4 + 4]);
2187       v.push_back(verts[ind + 4]);
2188     }
2189 
2190     createForbidden(v, forbidden_new);
2191     createForbidden(v, forbidden_edges);
2192   }
2193 
2194   // If this element is marked problematic, make all the adjustable diags (none
2195   // should exist if it's already marked as a problem, but just make sure) and
2196   // return.
2197   std::pair<unsigned int, unsigned int> jkpair(j, k);
2198   if(problems.find(elem) != problems.end() && problems[elem].count(jkpair)) {
2199     for(int s = 0; s < num_adj_diag; s++) {
2200       int ind = face_types["adj_diag"][s];
2201       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
2202       createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
2203     }
2204     return;
2205   }
2206 
2207   // test for right number of triangles with degenerate edges
2208   if((face_types["single_tri"].size() != 0 &&
2209       face_types["single_tri"].size() != 2) ||
2210      (face_types["degen"].size() && face_types["single_tri"].size() != 2)) {
2211     Msg::Error("In bruteForceEdgeQuadToTriHexa(), bad degenerated extrusion "
2212                "encountered.");
2213     std::pair<unsigned int, unsigned int> jkpair(j, k);
2214     problems[elem].insert(jkpair);
2215     problems_new[elem].insert(jkpair);
2216     if(num_adj_diag) {
2217       int ind = face_types["adj_diag"][0];
2218       if(nadj1[ind] >= 0) {
2219         createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
2220         createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
2221       }
2222     }
2223     return;
2224   }
2225 
2226   // if there are not enough diagonals:
2227   if(6 - face_types["single_tri"].size() - face_types["recomb"].size() < 2) {
2228     // Can't be meshed without internal vertex
2229     if(face_types["adj_diag"].size() + face_types["fixed_diag"].size()) {
2230       std::pair<unsigned int, unsigned int> jkpair(j, k);
2231       problems[elem].insert(jkpair);
2232       problems_new[elem].insert(jkpair);
2233       for(unsigned int s = 0; s < face_types["adj_diag"].size(); s++) {
2234         int ind = face_types["adj_diag"][s];
2235         createEdge(verts[nadj1[ind]], verts[nadj2[ind]], quadToTri_edges);
2236         createEdge(verts[nadj1[ind]], verts[nadj2[ind]], edges_new);
2237       }
2238     }
2239     // set the (at most) one free surface to forbidden and return
2240     else if(face_types["free"].size()) {
2241       int p_tmp = face_types["free"][0];
2242       std::vector<MVertex *> v_free;
2243       if(p_tmp < 4) {
2244         v_free.push_back(verts[p_tmp]);
2245         v_free.push_back(verts[(p_tmp + 1) % 4]);
2246         v_free.push_back(verts[(p_tmp + 1) % 4 + 4]);
2247         v_free.push_back(verts[p_tmp + 4]);
2248       }
2249       else {
2250         int add = p_tmp == 4 ? 0 : 4;
2251         v_free.push_back(verts[add]);
2252         v_free.push_back(verts[add + 1]);
2253         v_free.push_back(verts[add + 2]);
2254         v_free.push_back(verts[add + 3]);
2255       }
2256       createForbidden(v_free, forbidden_edges);
2257       createForbidden(v_free, forbidden_new);
2258     }
2259     return;
2260   }
2261 
2262   // Start looking at the different shape possibilities:
2263 
2264   // First shape: A PRISM
2265   // Only two possibilities.  Either the bottom can be divided along same
2266   // diagonal as the top, or the one quad side can be divided joining the top
2267   // diagonal. Otherwise, problem.
2268   if(face_types["degen"].size()) {
2269     addEdgesForQuadToTriTwoPtDegenHexa(
2270       gr, elem, ep, j, k, verts, face_types, edges_new, forbidden_new,
2271       quadToTri_edges, forbidden_edges, lat_tri_diags, problems_new, problems,
2272       nfix1, nfix2, nadj1, nadj2, free_flag);
2273     return;
2274   }
2275 
2276   // Second shape type: DEGENERATED HEXAHEDRON
2277   // Since this shape can be divided to create legitimate tets and/or pyramids,
2278   // let us try it.
2279   if(!face_types["degen"].size() && face_types["single_tri"].size() == 2) {
2280     addEdgesForQuadToTriOnePtDegenHexa(
2281       gr, elem, ep, j, k, verts, face_types, edges_new, forbidden_new,
2282       quadToTri_edges, forbidden_edges, lat_tri_diags, problems_new, problems,
2283       nfix1, nfix2, nadj1, nadj2, free_flag);
2284     return;
2285   }
2286 
2287   // Third SHAPE: FULL HEXAHEDRON
2288   // There are 4 main possibilities for minimum diags to guarantee slice:
2289   // 1. Three diagonals at a corner
2290   // 2. One PAIR of opposite diagonals, ABSOLUTELY ALL OTHER FACES FORBIDDEN
2291   // 2. Two PAIRS of opposite diags
2292   // 3. One PAIR of opposite diags PLUS a vertex with two ADDITIONAL diags
2293   // meeting on it.
2294   if(!face_types["single_tri"].size() && !face_types["degen"].size()) {
2295     addEdgesForQuadToTriFullHexa(
2296       gr, elem, ep, j, k, verts, face_types, edges_new, forbidden_new,
2297       quadToTri_edges, forbidden_edges, lat_tri_diags, problems_new, problems,
2298       nfix1, nfix2, nadj1, nadj2, free_flag);
2299     return;
2300   }
2301 }
2302 
2303 // This is a shortcut function to simply copy face diagonals all the way up a
2304 // vertical column of extruded elements. This function may not save very many
2305 // operations, but it is going to stay...
ExtrudeDiags(GRegion * gr,std::vector<MVertex * > v,unsigned int j_start,unsigned int k_start,unsigned int j_top,unsigned int k_top,MElement * elem,ExtrudeParams * loop_ep,std::set<std::pair<MVertex *,MVertex * >> & edges_new,std::set<std::pair<MVertex *,MVertex * >> & forbidden_new,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,MVertexRTree & pos)2306 static int ExtrudeDiags(
2307   GRegion *gr, std::vector<MVertex *> v, unsigned int j_start,
2308   unsigned int k_start, unsigned int j_top, unsigned int k_top, MElement *elem,
2309   ExtrudeParams *loop_ep, std::set<std::pair<MVertex *, MVertex *> > &edges_new,
2310   std::set<std::pair<MVertex *, MVertex *> > &forbidden_new,
2311   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
2312   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
2313   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
2314     &problems_new,
2315   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
2316     &problems,
2317   MVertexRTree &pos)
2318 {
2319   if(!loop_ep || !loop_ep->mesh.QuadToTri || !loop_ep->mesh.ExtrudeMesh) {
2320     Msg::Error("In ExtrudeDiags(), invalid extrusion "
2321                "in region %d for performing QuadToTri mesh generation.",
2322                gr->tag());
2323     return 0;
2324   }
2325 
2326   GModel *model = gr->model();
2327   if(!model) {
2328     Msg::Error("In ExtrudeDiags(), invalid model for region "
2329                "%d.",
2330                gr->tag());
2331     return 0;
2332   }
2333 
2334   int elem_size = elem->getNumVertices();
2335   if(!((v.size() == 6 && elem_size == 3) ||
2336        (v.size() == 8 && elem_size == 4))) {
2337     Msg::Error("In ExtrudeDiags(), vertex number mismatch "
2338                "between 2D source element and extruded volume.");
2339     return 0;
2340   }
2341 
2342   // first add the forbidden edges, then the new quadToTri_edges
2343   // w = 0 forbidden, w = 1 quadToTri_edges (fixed)
2344   for(int w = 0; w < 2; w++) {
2345     std::set<std::pair<MVertex *, MVertex *> >::iterator it;
2346     std::set<std::pair<MVertex *, MVertex *> >::iterator it_start;
2347     std::set<std::pair<MVertex *, MVertex *> >::iterator it_end;
2348     it_start = (!w) ? forbidden_new.begin() : edges_new.begin();
2349     it_end = (!w) ? forbidden_new.end() : edges_new.end();
2350 
2351     for(it = it_start; it != it_end; it++) {
2352       MVertex *v1, *v2;
2353       v1 = (*it).first;
2354       v2 = (*it).second;
2355       // find indices in v vector
2356       int ind1 = -1, ind2 = -1;
2357       for(unsigned int p = 0; p < v.size(); p++) {
2358         if(v[p] == v1) ind1 = p;
2359         if(v[p] == v2) ind2 = p;
2360       }
2361       if(ind1 < 0 || ind2 < 0) {
2362         Msg::Error("Error in ExtrudeDiags(): could not find vertex indices.");
2363         return 0;
2364       }
2365       // source verts:
2366       MVertex *sv1 = (ind1 < elem_size) ? elem->getVertex(ind1) :
2367                                           elem->getVertex(ind1 - elem_size);
2368       MVertex *sv2 = (ind2 < elem_size) ? elem->getVertex(ind2) :
2369                                           elem->getVertex(ind2 - elem_size);
2370       // extrude these two verts
2371       for(unsigned int j = j_start; j <= j_top; j++) {
2372         int k_start_tmp = (j == j_start) ? k_start + 1 : 0;
2373         int k_stop = (j == j_top) ? k_top : loop_ep->mesh.NbElmLayer[j];
2374         for(int k = k_start_tmp; k < k_stop; k++) {
2375           std::vector<MVertex *> v_extr =
2376             getExtrudedLateralVertices(sv1, sv2, gr, j, k, loop_ep, pos);
2377           if(v_extr.size() != 4) return 0;
2378           if(!w) {
2379             // reorder v_ext
2380             MVertex *tmp = v_extr[2];
2381             v_extr[2] = v_extr[3];
2382             v_extr[3] = tmp;
2383             createForbidden(v_extr, forbidden_edges);
2384           }
2385           else {
2386             MVertex *v_final_1 = (ind1 < elem_size) ? v_extr[0] : v_extr[2];
2387             MVertex *v_final_2 = (ind2 < elem_size) ? v_extr[1] : v_extr[3];
2388             createEdge(v_final_1, v_final_2, quadToTri_edges);
2389           }
2390         }
2391       }
2392     }
2393   }
2394 
2395   // add problem elements
2396   std::pair<unsigned int, unsigned int> jk_start(j_start, k_start);
2397   std::map<MElement *,
2398            std::set<std::pair<unsigned int, unsigned int> > >::iterator itprob;
2399 
2400   if(problems_new.size()) {
2401     for(itprob = problems_new.begin(); itprob != problems_new.end(); itprob++) {
2402       for(unsigned int j = j_start; j <= j_top; j++) {
2403         int k_start_tmp = (j == j_start) ? k_start + 1 : 0;
2404         int k_stop = (j == j_top) ? k_top : loop_ep->mesh.NbElmLayer[j];
2405         for(int k = k_start_tmp; k < k_stop; k++) {
2406           std::pair<unsigned int, unsigned int> pair_tmp(j, k);
2407           problems[(*itprob).first].insert(pair_tmp);
2408         }
2409       }
2410     }
2411   }
2412 
2413   return 1;
2414 }
2415 
2416 // Get set of locally fixed edges, forbidden edges, and all lateral surface
2417 // diagonals. Fixed edges include top surface diagonals and any lateral surface
2418 // diagonals that cannot be swapped. Added 2010-01-24
QuadToTriGetRegionDiags(GRegion * gr,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,MVertexRTree & pos)2419 static bool QuadToTriGetRegionDiags(
2420   GRegion *gr, std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
2421   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
2422   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags, MVertexRTree &pos)
2423 {
2424   ExtrudeParams *ep = gr->meshAttributes.extrude;
2425 
2426   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) return false;
2427 
2428   GModel *model = gr->model();
2429 
2430   // find source face
2431   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
2432   if(!reg_source) {
2433     Msg::Error("In QuadToTriGetRegionDiags(), could not find source face "
2434                "%d for region %d.",
2435                std::abs(ep->geo.Source), gr->tag());
2436     return false;
2437   }
2438 
2439   // Find a source surface, find a COPIED_ENTITY that is the top surface, or if
2440   // toroidal, find what is now the top
2441 
2442   bool foundSource = false, foundTop = false, foundRoot = false;
2443   GFace *reg_top = NULL;
2444   GFace *root_face = NULL;
2445   std::vector<GFace *> faces = gr->faces();
2446   std::vector<GFace *>::iterator it = faces.begin();
2447 
2448   // top faces in toroidal quadtri need special treatment
2449   bool is_toroidal = IsInToroidalQuadToTri(reg_source);
2450   if(is_toroidal) root_face = findRootSourceFaceForFace(reg_source);
2451 
2452   for(it = faces.begin(); it != faces.end(); it++) {
2453     ExtrudeParams *face_tmp_ep = (*it)->meshAttributes.extrude;
2454     if((*it) == root_face) foundRoot = true;
2455     if((*it) == reg_source)
2456       foundSource = true;
2457     else if(face_tmp_ep && face_tmp_ep->geo.Mode == COPIED_ENTITY) {
2458       GFace *top_source_tmp =
2459         model->getFaceByTag(std::abs(face_tmp_ep->geo.Source));
2460       if(!top_source_tmp) {
2461         Msg::Error("In QuadToTriGetRegionDiags(), could not find source face "
2462                    "%d for copied surface %d of region %d.",
2463                    std::abs(face_tmp_ep->geo.Source), (*it)->tag(), gr->tag());
2464       }
2465       else if(top_source_tmp == reg_source) {
2466         foundTop = true;
2467         reg_top = (*it);
2468       }
2469     }
2470   }
2471 
2472   if(!foundTop && is_toroidal && foundRoot && root_face != reg_source) {
2473     foundTop = true;
2474     reg_top = root_face;
2475   }
2476   if(!foundTop)
2477     Msg::Warning("In QuadToTriGetRegionDiags(), could not find top face "
2478                  "for region %d.",
2479                  gr->tag());
2480 
2481   if(!foundSource) {
2482     Msg::Error("In QuadToTriGetRegionDiags(), source face "
2483                "for region %d is not found in region face list.",
2484                gr->tag());
2485     return false;
2486   }
2487 
2488   // Get Fixed and adjustable lateral diagonal element edges
2489   int counter = 0;
2490   for(it = faces.begin(); it != faces.end(); it++) {
2491     counter++;
2492     // true if surface is a lateral...
2493     // ...The conditional is redundant for a reason.
2494     if((*it) != reg_top && (*it) != reg_source &&
2495        IsSurfaceALateralForRegion(gr, *it)) {
2496       // take care of forbidden edges
2497       // test whether this surface is a lateral bounded by two quadtri regions.
2498       // if so, and the other is not already meshed,
2499       // then don't make these forbidden.  This is worked out in a
2500       // lateral remesh later
2501       std::vector<GRegion *> adj_regions;
2502       int numNeighbors = 0;
2503       numNeighbors = GetNeighborRegionsOfFace((*it), adj_regions);
2504       int ind_notcurrent = adj_regions[0] == gr ? 1 : 0;
2505       if(!(numNeighbors == 2 && adj_regions[0]->meshAttributes.extrude &&
2506            adj_regions[1]->meshAttributes.extrude &&
2507            adj_regions[0]->meshAttributes.extrude->mesh.ExtrudeMesh &&
2508            adj_regions[1]->meshAttributes.extrude->mesh.ExtrudeMesh &&
2509            adj_regions[0]->meshAttributes.extrude->geo.Mode ==
2510              EXTRUDED_ENTITY &&
2511            adj_regions[1]->meshAttributes.extrude->geo.Mode ==
2512              EXTRUDED_ENTITY &&
2513            adj_regions[0]->meshAttributes.extrude->mesh.QuadToTri &&
2514            adj_regions[1]->meshAttributes.extrude->mesh.QuadToTri &&
2515            IsSurfaceALateralForRegion(adj_regions[ind_notcurrent], *it) &&
2516            !adj_regions[ind_notcurrent]->getNumMeshElements())) {
2517         for(unsigned int i = 0; i < (*it)->quadrangles.size(); i++) {
2518           std::vector<MVertex *> v;
2519           (*it)->quadrangles[i]->getVertices(v);
2520           createForbidden(v, forbidden_edges);
2521         }
2522       }
2523 
2524       // at this point, if there are no triangles, continue
2525       if(!(*it)->triangles.size()) continue;
2526 
2527       ExtrudeParams *face_ep_tmp = (*it)->meshAttributes.extrude;
2528       // If face is shared with a neighbor region that ALREADY has elements,
2529       // if face is the source of the neighbor, if the neighbor is TRANSFINITE,
2530       // or if the face is not an EXTRUDED_ENTITY, then these edges are fixed.
2531       std::vector<GRegion *> neighbors;
2532       GetNeighborRegionsOfFace(*it, neighbors);
2533       GRegion *other_region = NULL;
2534       ExtrudeParams *oth_ep = NULL;
2535       ExtrudeParams *face_ep = (*it)->meshAttributes.extrude;
2536       if(neighbors.size() > 1) {
2537         other_region = neighbors[0] != gr ? neighbors[0] : neighbors[1];
2538         oth_ep = other_region->meshAttributes.extrude;
2539       }
2540       bool is_fixed = false;
2541 
2542       // see if neighbor has already been meshed
2543       if(other_region &&
2544          (other_region->pyramids.size() || other_region->tetrahedra.size() ||
2545           other_region->hexahedra.size() || other_region->prisms.size() ||
2546           other_region->polyhedra.size() ||
2547           other_region->getNumMeshElements())) {
2548         is_fixed = true;
2549       }
2550       // see if the diagonals are fixed for other reasons
2551       if(!(face_ep_tmp && face_ep_tmp->mesh.ExtrudeMesh &&
2552            face_ep_tmp->geo.Mode == EXTRUDED_ENTITY) ||
2553          (other_region && oth_ep && oth_ep->mesh.ExtrudeMesh &&
2554           (*it) == model->getFaceByTag(std::abs(oth_ep->geo.Source))) ||
2555          (other_region &&
2556           other_region->meshAttributes.method == MESH_TRANSFINITE)) {
2557         is_fixed = true;
2558       }
2559 
2560       // Now extrude all vertices and find diagonal edges.
2561       // NOTE: This seems like the "hard way" because it is written to work
2562       // even if the original lateral for the region is replaced by another
2563       // structured surface. (first find common edge between source and this
2564       // lateral)
2565       std::vector<GEdge *> const &source_edges = reg_source->edges();
2566       std::vector<GEdge *> const &face_edges = (*it)->edges();
2567       std::vector<GEdge *>::const_iterator itse;
2568       GEdge *common = NULL;
2569       int common_count = 0;
2570       for(itse = source_edges.begin(); itse != source_edges.end(); itse++) {
2571         if(std::find(face_edges.begin(), face_edges.end(), (*itse)) !=
2572            face_edges.end()) {
2573           common = (*itse);
2574           common_count++;
2575         }
2576       }
2577       if(!common || common_count != 1)
2578         Msg::Error(
2579           "In QuadToTriGetRegionDiags(), lateral surface and "
2580           "source surface of region %d do not share one and only one edge.",
2581           gr->tag());
2582 
2583       // now find face source edge, if it exists:
2584       GEdge *face_source = NULL;
2585       if(face_ep && face_ep->mesh.ExtrudeMesh &&
2586          face_ep->geo.Mode == EXTRUDED_ENTITY) {
2587         face_source = model->getEdgeByTag(std::abs(face_ep->geo.Source));
2588         if(!face_source) {
2589           Msg::Error("In QuadToTriGetRegionDiags(), extruded face %d "
2590                      "has invalid source.",
2591                      (*it)->tag());
2592         }
2593       }
2594       // set up vertex finding loops according to whether this surface
2595       // is extruded or not (alternative to extruded is unrecombined transfinite
2596       // surf with vertices coincidentally in the right place).
2597       unsigned int num_lines = 0;
2598       std::vector<MLine *> *source_lines = NULL;
2599       ExtrudeParams *loop_ep = NULL;
2600       if(face_source) {
2601         num_lines = face_source->lines.size();
2602         source_lines = &face_source->lines;
2603         loop_ep = face_ep;
2604       }
2605       else {
2606         num_lines = common->lines.size();
2607         source_lines = &common->lines;
2608         loop_ep = ep;
2609       }
2610       unsigned int index_guess = 0;
2611 
2612       for(unsigned int i = 0; i < num_lines; i++) {
2613         MVertex *v0 = (*source_lines)[i]->getVertex(0);
2614         MVertex *v1 = (*source_lines)[i]->getVertex(1);
2615 
2616         std::vector<MVertex *> verts;
2617         // test to see if this is a degenerate quad as triangle. If so,
2618         // continue.
2619         verts = getExtrudedLateralVertices(v0, v1, (*it), 0, 0, loop_ep, pos);
2620         if(verts[0] == verts[2] || verts[1] == verts[3]) {
2621           for(int p = 0; p < loop_ep->mesh.NbLayer; p++)
2622             index_guess += loop_ep->mesh.NbElmLayer[p];
2623           continue;
2624         }
2625         for(int j = 0; j < loop_ep->mesh.NbLayer; j++) {
2626           for(int k = 0; k < loop_ep->mesh.NbElmLayer[j]; k++) {
2627             verts.clear();
2628             verts =
2629               getExtrudedLateralVertices(v0, v1, (*it), j, k, loop_ep, pos);
2630 
2631             // Find diagonal:
2632 
2633             std::pair<int, int> diag(0, 0);
2634             diag = FindDiagonalEdgeIndices(verts, (*it), true, index_guess);
2635             if(diag.first || diag.second) {
2636               int add = diag.first < 2 ? 1 : -1;
2637               // have to test if conflicting edge already exists in
2638               // quadToTri_edges in case of global subdivide
2639               if(!edgeExists(verts[diag.first + add], verts[diag.second - add],
2640                              quadToTri_edges)) {
2641                 createEdge(verts[diag.first], verts[diag.second],
2642                            lat_tri_diags);
2643                 if(is_fixed)
2644                   createEdge(verts[diag.first], verts[diag.second],
2645                              quadToTri_edges);
2646               }
2647               else
2648                 createEdge(verts[diag.first + add], verts[diag.second - add],
2649                            lat_tri_diags);
2650             }
2651             else if(!(*it)->quadrangles.size())
2652               Msg::Error("In QuadToTriGetRegionDiags(), failed to find a "
2653                          "diagonal in lateral surface %d.",
2654                          (*it)->tag());
2655 
2656             index_guess += 2;
2657             /*
2658 
2659              std::vector<MVertex*> vface;
2660              vface.push_back(verts[0]);
2661              vface.push_back(verts[1]);
2662              vface.push_back(verts[3]);
2663              vface.push_back(verts[2]);
2664              if( k==2 && ( counter == 3 || counter == 3) ){
2665                if( k==0 || k ){
2666                  createEdge( verts[1], verts[2], lat_tri_diags );
2667                  createEdge( verts[1], verts[2], quadToTri_edges );
2668                }
2669                else{
2670                  createEdge( verts[0], verts[3], lat_tri_diags );
2671                  createEdge( verts[0], verts[3], quadToTri_edges );
2672                }
2673              }
2674              else if( k==2 && (counter == 5 || counter == 4 || counter == 6 ) ){
2675                createEdge( verts[0], verts[3], lat_tri_diags );
2676                createEdge( verts[0], verts[3], quadToTri_edges );
2677              }
2678              else if( k<2 )
2679                createForbidden(vface, forbidden_edges);
2680              else
2681                createEdge( elemEdge_tmp.first, elemEdge_tmp.second,
2682              lat_tri_diags );
2683              */
2684           }
2685         }
2686       }
2687     }
2688   }
2689 
2690   // Insert diagonals of the top surface into quadToTri_edges;
2691   unsigned int index_guess = reg_source->triangles.size();
2692   if(reg_top->quadrangles.size() && !is_toroidal) {
2693     Msg::Error("In QuadToTriGetRegionDiags(), top surface of region "
2694                "%d has quads in a non-toroidal QuadToTri extrusion.",
2695                gr->tag());
2696     return false;
2697   }
2698 
2699   for(unsigned int i = 0; i < reg_source->quadrangles.size(); i++) {
2700     int j_top = ep->mesh.NbLayer - 1;
2701     int k_top = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1];
2702     MElement *elem = reg_source->quadrangles[i];
2703     std::vector<MVertex *> verts;
2704     get2DExtrudedVertices(elem, ep, j_top, k_top, pos, verts);
2705     if(verts.size() != 4) break;
2706     if(!is_toroidal) {
2707       // Find diagonal:
2708       std::pair<int, int> diag(0, 0);
2709       diag = FindDiagonalEdgeIndices(verts, reg_top, false, index_guess);
2710       if(diag.first || diag.second)
2711         createEdge(verts[diag.first], verts[diag.second], quadToTri_edges);
2712       else
2713         Msg::Error("In QuadToTriGetRegionDiags(), failed to find a diagonal on "
2714                    "top surface %d, but should have.",
2715                    reg_top->tag());
2716       index_guess += 2;
2717     }
2718     else
2719       createForbidden(verts, forbidden_edges);
2720   }
2721   return true;
2722 }
2723 
2724 // For use in QuadToTriEdgeGenerator:  Controls BRUTE FORCE edging of elements
2725 // with ALL vertices on a lateral boundary surface. Added 04/08/2011
makeEdgesForElemsWithAllVertsOnBnd(GRegion * gr,bool is_addverts,CategorizedSourceElements & cat_src_elems,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,MVertexRTree & pos)2726 static int makeEdgesForElemsWithAllVertsOnBnd(
2727   GRegion *gr, bool is_addverts, CategorizedSourceElements &cat_src_elems,
2728   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
2729   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
2730   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
2731   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
2732     &problems,
2733   MVertexRTree &pos)
2734 {
2735   ExtrudeParams *ep = gr->meshAttributes.extrude;
2736 
2737   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
2738     Msg::Error("In makeEdgesForElemsWithAllVertsOnBnd(), invalid extrusion "
2739                "in region %d for performing QuadToTri mesh generation.",
2740                gr->tag());
2741     return 0;
2742   }
2743 
2744   GModel *model = gr->model();
2745   if(!model) {
2746     Msg::Error(
2747       "In makeEdgesForElemsWithAllVertsOnBnd(), invalid model for region "
2748       "%d.",
2749       gr->tag());
2750     return 0;
2751   }
2752 
2753   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
2754   if(!reg_source) {
2755     Msg::Error(
2756       "In makeEdgesForElemsWithAllVertsOnBnd(), invalid source face for region "
2757       "%d.",
2758       gr->tag());
2759     return 0;
2760   }
2761 
2762   if(gr != cat_src_elems.region || reg_source != cat_src_elems.source_face) {
2763     Msg::Error(
2764       "In makeEdgesForElemsWithAllVertsOnBnd(), too many elements in the "
2765       "CategorizedSourceElements structure for given source face %d.",
2766       reg_source->tag());
2767     return 0;
2768   }
2769 
2770   // find edge verts of source face
2771   MVertexRTree pos_src_edge(CTX::instance()->geom.tolerance *
2772                             CTX::instance()->lc);
2773   QuadToTriInsertFaceEdgeVertices(reg_source, pos_src_edge);
2774 
2775   // while Loop to diagonalize 3-boundary point triangles and 4-boundary point
2776   // quadrangles:
2777   bool finish_all_tri = false;
2778   // can afford temporary copies since these sets should be relatively small for
2779   // all cases.
2780   std::set<unsigned int> tri_tmp, quad_tmp;
2781   tri_tmp = cat_src_elems.three_bnd_pt_tri;
2782   // if is_addverts, then don't track the quads
2783   if(!is_addverts) quad_tmp = cat_src_elems.four_bnd_pt_quad;
2784 
2785   while(tri_tmp.size() || quad_tmp.size()) {
2786     std::set<unsigned int>::iterator it;
2787     std::vector<unsigned int> done;
2788     // 3 bnd point triangle and 4 bnd point quad loop
2789     // s = 0 for triangles, s = 1 for quads
2790     for(int s = 0; s < 2; s++) {
2791       std::set<unsigned int> *set_elems;
2792       std::set<std::pair<MVertex *, MVertex *> > edges_new, forbidden_new;
2793       std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
2794         problems_new;
2795       if(!s)
2796         set_elems = &tri_tmp;
2797       else
2798         set_elems = &quad_tmp;
2799 
2800       for(it = set_elems->begin(); it != set_elems->end(); it++) {
2801         MElement *elem;
2802         if(!s)
2803           elem = reg_source->triangles[(*it)];
2804         else
2805           elem = reg_source->quadrangles[(*it)];
2806 
2807         // int elem_size = elem->getNumVertices();
2808 
2809         std::vector<bool> vert_bnd;
2810         if(!s)
2811           vert_bnd.insert(vert_bnd.begin(),
2812                           cat_src_elems.tri_bool.begin() + (4 * (*it) + 1),
2813                           cat_src_elems.tri_bool.begin() + (4 * (*it) + 4));
2814         else
2815           vert_bnd.insert(vert_bnd.begin(),
2816                           cat_src_elems.quad_bool.begin() + (5 * (*it) + 1),
2817                           cat_src_elems.quad_bool.begin() + (5 * (*it) + 5));
2818         int j_start, k_start;
2819 
2820         // if has lat_tri_diags or is a rotation with quads (may have to do the
2821         // one point bnd quads to get rid of degenerate hexahedra...they are
2822         // invalid mesh volumes.
2823         if(lat_tri_diags.size() ||
2824            (reg_source->quadrangles.size() &&
2825             (ep->geo.Type == ROTATE || ep->geo.Type == TRANSLATE_ROTATE))) {
2826           j_start = 0;
2827           k_start = 0;
2828         }
2829         else {
2830           j_start = ep->mesh.NbLayer - 1;
2831           k_start = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1;
2832         }
2833 
2834         int num_levels = 0;
2835         if(lat_tri_diags.size() ||
2836            (reg_source->quadrangles.size() &&
2837             (ep->geo.Type == ROTATE || ep->geo.Type == TRANSLATE_ROTATE))) {
2838           for(int p = 0; p < ep->mesh.NbLayer; p++)
2839             num_levels += ep->mesh.NbElmLayer[p];
2840         }
2841         else
2842           num_levels = 1;
2843 
2844         int num_edged = 0;
2845 
2846         // before starting extrusion loop, get the node numbers for the diagonal
2847         // in the region's top surface extruded from this source element
2848         // (will need this below)
2849         std::vector<MVertex *> verts_top;
2850         int ntop1 = -1, ntop2 = -2;
2851         getExtrudedVertices(elem, ep, ep->mesh.NbLayer - 1,
2852                             ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1, pos,
2853                             verts_top);
2854         if(edgeExists(verts_top[4], verts_top[6], quadToTri_edges)) {
2855           ntop1 = 4;
2856           ntop2 = 6;
2857         }
2858         else if(edgeExists(verts_top[5], verts_top[7], quadToTri_edges)) {
2859           ntop1 = 5;
2860           ntop2 = 7;
2861         }
2862 
2863         // start extrusion loop
2864         for(int j = j_start; j < ep->mesh.NbLayer; j++) {
2865           int k_start_tmp, k_stop;
2866           if(j == j_start)
2867             k_start_tmp = k_start;
2868           else
2869             k_start_tmp = 0;
2870           k_stop = ep->mesh.NbElmLayer[j];
2871           for(int k = k_start_tmp; k < k_stop; k++) {
2872             std::vector<MVertex *> verts;
2873             std::map<std::string, std::vector<int> > face_types;
2874             std::vector<int> nfix1, nfix2, nadj1, nadj2, free_flag;
2875             int vert_num = getExtrudedVertices(elem, ep, j, k, pos, verts);
2876             // if just starting and there is no diagonal on the bottom edge,
2877             // forbid it (this prevents some conflicts)
2878             if(vert_num == 8 && j == j_start && k == k_start &&
2879                !edgeExists(verts[0], verts[2], quadToTri_edges) &&
2880                !edgeExists(verts[1], verts[3], quadToTri_edges)) {
2881               std::vector<MVertex *> v_bot;
2882               v_bot.assign(4, (MVertex *)(0));
2883               v_bot[0] = verts[0];
2884               v_bot[1] = verts[1];
2885               v_bot[2] = verts[2];
2886               v_bot[3] = verts[3];
2887               createForbidden(v_bot, forbidden_edges);
2888               createForbidden(v_bot, forbidden_new);
2889             }
2890 
2891             if(!s) {
2892               face_types = getFaceTypes(
2893                 gr, elem, j, k, verts, quadToTri_edges, forbidden_edges,
2894                 lat_tri_diags, vert_bnd, nfix1, nfix2, nadj1, nadj2, free_flag);
2895 
2896               if(finish_all_tri ||
2897                  face_types["free"].size() + face_types["adj_diag"].size() <
2898                    2) {
2899                 bruteForceEdgeQuadToTriPrism(
2900                   gr, elem, j, k, verts, face_types, edges_new, forbidden_new,
2901                   quadToTri_edges, forbidden_edges, lat_tri_diags, problems_new,
2902                   problems, nfix1, nfix2, nadj1, nadj2, free_flag);
2903                 // IMPORTANT
2904                 num_edged++;
2905               }
2906             }
2907             else if(s) {
2908               // a loop to try to force the top diagonal to align with the
2909               // diagonal in the region's top surface above this element.
2910               bool changed_diag = false;
2911               for(int g = 0; g < 2; g++) {
2912                 // on first step, see if can put in the aligned top diagonal
2913                 if(g == 0 && ntop1 >= 0 && ntop2 >= 0 &&
2914                    !edgeExists(verts[4], verts[6], quadToTri_edges) &&
2915                    !edgeExists(verts[5], verts[7], quadToTri_edges)) {
2916                   std::vector<MVertex *> v_top;
2917                   v_top.assign(4, (MVertex *)(0));
2918                   v_top[0] = verts[4];
2919                   v_top[1] = verts[5];
2920                   v_top[2] = verts[6];
2921                   v_top[3] = verts[7];
2922                   if(!forbiddenExists(v_top, forbidden_edges)) {
2923                     changed_diag = true;
2924                     createEdge(verts[ntop1], verts[ntop2], quadToTri_edges);
2925                   }
2926                 }
2927                 // on second step, see if a problem was created from inserting
2928                 // aligned diagonal if so, remove it and try again.
2929                 std::pair<unsigned int, unsigned int> jk_pair(j, k);
2930                 if(g == 1 && changed_diag &&
2931                    problems[elem].find(jk_pair) != problems[elem].end()) {
2932                   problems[elem].erase(jk_pair);
2933                   if(!problems[elem].size()) problems.erase(elem);
2934                   deleteEdge(verts[ntop1], verts[ntop2], quadToTri_edges);
2935                 }
2936                 else if(g == 1) {
2937                   if(!problems[elem].size()) problems.erase(elem);
2938                   break;
2939                 }
2940                 face_types =
2941                   getFaceTypes(gr, elem, j, k, verts, quadToTri_edges,
2942                                forbidden_edges, lat_tri_diags, vert_bnd, nfix1,
2943                                nfix2, nadj1, nadj2, free_flag);
2944 
2945                 bruteForceEdgeQuadToTriHexa(
2946                   gr, elem, j, k, verts, face_types, edges_new, forbidden_new,
2947                   quadToTri_edges, forbidden_edges, lat_tri_diags, problems_new,
2948                   problems, nfix1, nfix2, nadj1, nadj2, free_flag);
2949               }
2950               // IMPORTANT
2951               num_edged++;
2952             }
2953           }
2954         }
2955 
2956         // IMPORTANT
2957         if(num_edged == num_levels) done.push_back((*it));
2958 
2959         // If quads, break ( only do quads one at a time so can keep 3 bnd point
2960         // triangles from being trapped so that they can't be meshed without an
2961         // internal vertex)
2962         if(s) break;
2963 
2964       } // end loop over set of element indices (tri or quad)
2965 
2966       // remove elements that are done from list
2967       if(done.size()) {
2968         for(unsigned int i = 0; i < done.size(); i++) set_elems->erase(done[i]);
2969         done.clear();
2970       }
2971 
2972       // skip over quads on this iteration if some modifications were made to
2973       // triangle extrusion elements ( need to make sure no triangles left with
2974       // only one adjustable or free face or else
2975       //   meshing a quad might trap them so they can't be meshed without
2976       //   internal vertex ).
2977       if(!s && (edges_new.size() || problems_new.size())) s = -1;
2978 
2979       // if quads are done, finish all triangles
2980       if(!quad_tmp.size()) finish_all_tri = true;
2981 
2982     } // end of s-loop to choose between tri or quad
2983 
2984   } // end of while
2985 
2986   return 1;
2987 }
2988 
2989 // For use in QuadToTriEdgeGenerator:  Does the edging of prisms with some but
2990 // not all vertices on a lateral boundary surface. Added 04/08/2011
makeEdgesForOtherBndPrisms(GRegion * gr,bool is_addverts,CategorizedSourceElements & cat_src_elems,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,MVertexRTree & pos)2991 static int makeEdgesForOtherBndPrisms(
2992   GRegion *gr, bool is_addverts, CategorizedSourceElements &cat_src_elems,
2993   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
2994   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
2995   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
2996   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
2997     &problems,
2998   MVertexRTree &pos)
2999 {
3000   ExtrudeParams *ep = gr->meshAttributes.extrude;
3001 
3002   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
3003     Msg::Error("In makeEdgesForOtherBndPrisms(), invalid extrusion "
3004                "in region %d for performing QuadToTri mesh generation.",
3005                gr->tag());
3006     return 0;
3007   }
3008 
3009   GModel *model = gr->model();
3010   if(!model) {
3011     Msg::Error("In makeEdgesForOtherBndPrisms(), invalid model for region "
3012                "%d.",
3013                gr->tag());
3014     return 0;
3015   }
3016 
3017   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
3018   if(!reg_source) {
3019     Msg::Error(
3020       "In makeEdgesForOtherBndPrisms(), invalid source face for region "
3021       "%d.",
3022       gr->tag());
3023     return 0;
3024   }
3025 
3026   if(gr != cat_src_elems.region || reg_source != cat_src_elems.source_face) {
3027     Msg::Error("In makeEdgesForOtherBndPrisms(), CatergorizedSourceElements "
3028                "structure data "
3029                " does not correspond to region %d.",
3030                reg_source->tag());
3031     return 0;
3032   }
3033 
3034   std::set<unsigned int>::iterator it;
3035 
3036   // skip the whole thing if this is true...NO reason to divide!!
3037   if(!lat_tri_diags.size() && !reg_source->quadrangles.size()) return 1;
3038 
3039   // edge other_bnd triangles loop
3040   // (draw from boundaries up toward interior)
3041   for(it = cat_src_elems.other_bnd_tri.begin();
3042       it != cat_src_elems.other_bnd_tri.end(); it++) {
3043     std::set<std::pair<MVertex *, MVertex *> > edges_new, forbidden_new;
3044     std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
3045       problems_new;
3046     std::vector<MVertex *> verts;
3047     std::vector<bool> vert_bnd;
3048     MElement *elem = reg_source->triangles[(*it)];
3049     int elem_size = elem->getNumVertices();
3050 
3051     vert_bnd.insert(vert_bnd.begin(),
3052                     cat_src_elems.tri_bool.begin() + (4 * (*it) + 1),
3053                     cat_src_elems.tri_bool.begin() + (4 * (*it) + 4));
3054 
3055     int j_start, k_start;
3056     // if has lat_tri_diags or is a rotation with quads (may have to do the one
3057     // point bnd quads to get rid of degenerate hexahedra...they are invalid
3058     // mesh volumes.
3059     if(lat_tri_diags.size() ||
3060        (reg_source->quadrangles.size() &&
3061         (ep->geo.Type == ROTATE || ep->geo.Type == TRANSLATE_ROTATE))) {
3062       j_start = 0;
3063       k_start = 0;
3064     }
3065     else {
3066       j_start = ep->mesh.NbLayer - 1;
3067       k_start = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1;
3068     }
3069 
3070     // add edges
3071     for(int j = j_start; j < ep->mesh.NbLayer; j++) {
3072       int k_start_tmp, k_stop;
3073       if(j == j_start)
3074         k_start_tmp = k_start;
3075       else
3076         k_start_tmp = 0;
3077       k_stop = ep->mesh.NbElmLayer[j];
3078       for(int k = k_start_tmp; k < k_stop; k++) {
3079         std::vector<MVertex *> verts;
3080         getExtrudedVertices(elem, ep, j, k, pos, verts);
3081         // NOTE: bnd_face might not really be a bnd_face, but the code takes
3082         // that into account below.
3083         for(int p = 0; p < elem_size; p++) {
3084           if(vert_bnd[p]) {
3085             bool degen = false;
3086             int p2 = (p + 1) % elem_size;
3087             int p3 = (p + elem_size - 1) % elem_size;
3088             // test for degeneracy
3089             if(verts[p] == verts[p + elem_size]) degen = true;
3090             if(!degen && !vert_bnd[p2]) {
3091               createEdge(verts[p], verts[p2 + elem_size], quadToTri_edges);
3092               createEdge(verts[p], verts[p2 + elem_size], edges_new);
3093             }
3094             if(!degen && !vert_bnd[p3]) {
3095               createEdge(verts[p], verts[p3 + elem_size], quadToTri_edges);
3096               createEdge(verts[p], verts[p3 + elem_size], edges_new);
3097             }
3098 
3099             // make the adjustable diag (if it exists)
3100             // Note: p might not really be a bnd face, but this takes that into
3101             // account
3102             if(edgeExists(verts[p], verts[p2 + elem_size], lat_tri_diags) &&
3103                !edgeExists(verts[p + elem_size], verts[p2], quadToTri_edges))
3104               createEdge(verts[p], verts[p2 + elem_size], quadToTri_edges);
3105             else if(edgeExists(verts[p + elem_size], verts[p2],
3106                                lat_tri_diags) &&
3107                     !edgeExists(verts[p], verts[p2 + elem_size],
3108                                 quadToTri_edges))
3109               createEdge(verts[p + elem_size], verts[p2], quadToTri_edges);
3110           }
3111         }
3112       }
3113     }
3114 
3115   } // end of boundary triangles loop
3116 
3117   return 1;
3118 }
3119 
3120 // For use in QuadToTriEdgeGenerator:  Does the edging of hexahedra with some
3121 // but not all vertices on a lateral boundary surface. Added 04/08/2011
makeEdgesForOtherBndHexa(GRegion * gr,bool is_addverts,CategorizedSourceElements & cat_src_elems,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,MVertexRTree & pos)3122 static int makeEdgesForOtherBndHexa(
3123   GRegion *gr, bool is_addverts, CategorizedSourceElements &cat_src_elems,
3124   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
3125   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
3126   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
3127   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
3128     &problems,
3129   MVertexRTree &pos)
3130 {
3131   // Edge creation for extruded quadrangles with some but not all vertices on a
3132   // boundary. (draw from boundaries up toward interior) If no lat_tri_diags,
3133   // just do the top layer. Follow these instructions: For 2 pts on boundary:
3134   //  Below top level, draw top diags only if there are lat_tri_diags touching
3135   //  elemnt or if element is not adjacent to any boundary (only touching it)
3136   //  Order of precedence in top edging decisions:
3137   //   a. if bottom diag exists, align top diagonal to it.
3138   //   b. if bnd vertices are on diametrically opposite corners, draw top diag
3139   //   NOT on them. c. if lateral surface diagonals touch element, connect to
3140   //   one at some vertex. d. otherwise, don't draw top diagonal.
3141   //  In any case, draw the lateral edges up from bottom boundary vertices
3142   //  toward interior. At top level, top diagonals should already be done in 2D
3143   //  mesh step.
3144   // For 3 pts on boundary:
3145   //  Draw the top diag from corner inward.  Draw laterals up from bottom
3146   //  boundary vertices.
3147   // For 1 point on boundary:
3148   //  Draw lateral diagonals up from bottom boundary verts, draw top diagonal
3149   //  completely off the boundary. Draw diagonals toward the "pivot vertex",
3150   //  which is the vertex in the top element face diametrically opposite to the
3151   //  top face vertex on the boundary. Actually, this is only done in the first
3152   //  two extrusion layers, if those layers are not in the top layer. In first
3153   //  layer, draw diags to the top vertex diametrically opposite bnd vert, in
3154   //  the second layer, draw them down to the bottom such vertex.  Same vertex
3155   //  for both layers.  This is done to ensure that a one pt boundary quad in an
3156   //  unstructured surface can be divided without dividing the entire bottom
3157   //  layer. If two pivot vertices share an edge and these rules would conflict,
3158   //  just give precedence to the first pivot vertex encountered in the edging
3159   //  loop (this works, yes). Also, the internal elements touching this pivot
3160   //  vertex should have diagonals drawn to pivot vertex as well (done in
3161   //  different function, with same precedence).
3162 
3163   ExtrudeParams *ep = gr->meshAttributes.extrude;
3164 
3165   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
3166     Msg::Error("In makeEdgesForOtherBndHexa(), invalid extrusion "
3167                "in region %d for performing QuadToTri mesh generation.",
3168                gr->tag());
3169     return 0;
3170   }
3171 
3172   GModel *model = gr->model();
3173   if(!model) {
3174     Msg::Error("In makeEdgesForOtherBndHexa(), invalid model for region "
3175                "%d.",
3176                gr->tag());
3177     return 0;
3178   }
3179 
3180   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
3181   if(!reg_source) {
3182     Msg::Error("In makeEdgesForOtherBndHexa(), invalid source face for region "
3183                "%d.",
3184                gr->tag());
3185     return 0;
3186   }
3187 
3188   if(gr != cat_src_elems.region || reg_source != cat_src_elems.source_face) {
3189     Msg::Error("In makeEdgesForOtherBndHexa(), CatergorizedSourceElements "
3190                "structure data "
3191                " does not correspond to region %d.",
3192                reg_source->tag());
3193     return 0;
3194   }
3195 
3196   std::set<unsigned int>::iterator it;
3197 
3198   for(it = cat_src_elems.other_bnd_quad.begin();
3199       it != cat_src_elems.other_bnd_quad.end(); it++) {
3200     MElement *elem = reg_source->quadrangles[(*it)];
3201     const int elem_size = elem->getNumVertices();
3202 
3203     std::vector<bool> vert_bnd;
3204     vert_bnd.insert(vert_bnd.begin(),
3205                     cat_src_elems.quad_bool.begin() + (5 * (*it) + 1),
3206                     cat_src_elems.quad_bool.begin() + (5 * (*it) + 5));
3207 
3208     // these locally hold each added edge/problem element temporarily
3209     std::set<std::pair<MVertex *, MVertex *> > edges_new;
3210     std::set<std::pair<MVertex *, MVertex *> > forbidden_new;
3211     std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
3212       problems_new;
3213 
3214     // Get a count of bnd verts. If one point, that index will be in
3215     // one_point_ind. For 3 bnd vert quads  record the empty spot in 'skip.'
3216     int bnd_count = 0, skip = 0, one_point_ind = 0;
3217     for(int s = 0; s < elem_size; s++) {
3218       if(vert_bnd[s]) {
3219         bnd_count++;
3220         one_point_ind = s;
3221       }
3222       else
3223         skip = s;
3224     }
3225 
3226     int j_start, k_start;
3227 
3228     // if has lat_tri_diags or is a rotation with quads (may have to do the one
3229     // point bnd quads to get rid of degenerate hexahedra...they are invalid
3230     // mesh volumes.
3231     if(lat_tri_diags.size() ||
3232        (reg_source->quadrangles.size() &&
3233         (ep->geo.Type == ROTATE || ep->geo.Type == TRANSLATE_ROTATE))) {
3234       j_start = 0;
3235       k_start = 0;
3236     }
3237     else {
3238       j_start = ep->mesh.NbLayer - 1;
3239       k_start = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1;
3240     }
3241 
3242     // start of top layer
3243     int j_top_start = ep->mesh.NbLayer - 1;
3244     int k_top_start = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1;
3245 
3246     // add edges:
3247 
3248     // lateral diags in any case
3249     for(int j = j_start; j < ep->mesh.NbLayer; j++) {
3250       int k_start_tmp, k_stop;
3251       if(j == j_start)
3252         k_start_tmp = k_start;
3253       else
3254         k_start_tmp = 0;
3255       k_stop = ep->mesh.NbElmLayer[j];
3256       for(int k = k_start_tmp; k < k_stop; k++) {
3257         std::vector<MVertex *> verts;
3258         getExtrudedVertices(elem, ep, j, k, pos, verts);
3259         // int bnd_face = -1;
3260         // NOTE: bnd_face might not really be a bnd_face, but don't worry--it
3261         // won't be diagonalized if not
3262         for(int p = 0; p < elem_size; p++) {
3263           int p2 = (p + 1) % elem_size;
3264           int p3 = (p + elem_size - 1) % elem_size;
3265           if(vert_bnd[p]) {
3266             bool degen = false;
3267             // test for degeneracy
3268             if(verts[p] == verts[p + elem_size]) degen = true;
3269             if(!degen && !vert_bnd[p2])
3270               createEdge(verts[p], verts[p2 + elem_size], quadToTri_edges);
3271             if(!degen && !vert_bnd[p3])
3272               createEdge(verts[p], verts[p3 + elem_size], quadToTri_edges);
3273 
3274             // make the adjustable diag
3275             if(edgeExists(verts[p], verts[p2 + elem_size], lat_tri_diags) &&
3276                !edgeExists(verts[p + elem_size], verts[p2], quadToTri_edges))
3277               createEdge(verts[p], verts[p2 + elem_size], quadToTri_edges);
3278             else if(edgeExists(verts[p + elem_size], verts[p2],
3279                                lat_tri_diags) &&
3280                     !edgeExists(verts[p], verts[p2 + elem_size],
3281                                 quadToTri_edges))
3282               createEdge(verts[p + elem_size], verts[p2], quadToTri_edges);
3283           }
3284           // if face not on boundary and in top layer...make an internal lateral
3285           else if(j == j_top_start && k == k_top_start && !vert_bnd[p2]) {
3286             int ind_low, ind2;
3287             if(verts[p + elem_size] < verts[p2 + elem_size]) {
3288               ind_low = p + elem_size;
3289               ind2 = p2;
3290             }
3291             else {
3292               ind_low = p2 + elem_size;
3293               ind2 = p;
3294             }
3295             createEdge(verts[ind_low], verts[ind2], quadToTri_edges);
3296           }
3297         }
3298       }
3299     }
3300 
3301     // Add top diags for 2-bnd point quads, below top layer
3302     // If there is a lateral diagonal, connect to it.  If this is a two boundary
3303     // point quad that is not adjacent to a boundary (it is possible), draw
3304     // diagonal completely off boundary. If neither of the above, don't make the
3305     // top diagonal. IF degenerate, be careful.
3306     if(bnd_count == 2) {
3307       for(int j = j_start; j < ep->mesh.NbLayer; j++) {
3308         int k_start_tmp, k_stop;
3309         if(j == j_start)
3310           k_start_tmp = k_start;
3311         else
3312           k_start_tmp = 0;
3313         k_stop = ep->mesh.NbElmLayer[j];
3314         if(j == ep->mesh.NbLayer - 1) k_stop--; // dont go to top elements
3315         for(int k = k_start_tmp; k < k_stop; k++) {
3316           std::vector<MVertex *> verts;
3317           getExtrudedVertices(elem, ep, j, k, pos, verts);
3318           int p1 = -1, p2 = -1;
3319           for(int p = 0; p < elem_size; p++) {
3320             if(vert_bnd[p]) {
3321               p1 = p;
3322               int p2_tmp = (p + 1) % elem_size;
3323               int p3_tmp = (p + elem_size - 1) % elem_size;
3324               if(vert_bnd[p2_tmp]) {
3325                 p1 = p;
3326                 p2 = p2_tmp;
3327               }
3328               else if(vert_bnd[p3_tmp]) {
3329                 p1 = p3_tmp;
3330                 p2 = p;
3331               }
3332               break;
3333             }
3334           }
3335           if(p2 < 0 && p1 < 0) {
3336             Msg::Error(
3337               "In makeEdgesForOtherBndHexa(), error finding boundary points on "
3338               "2-boundary point quadrangle.");
3339             break;
3340           }
3341 
3342           // First, if bottom diagonal exists, align top diagonal to it,
3343           // OTHERWISE:
3344           //   if bnd verts oppose each other, draw top diagonal off boundary
3345           //   otherwise, connect to any existing lateral diagonal either
3346           //   totally ON boundary or totally OFF, but ONLY draw top diag if
3347           //   such a lateral exists
3348           // NOTE: since laterals were added first, any lat_tri_diag here is in
3349           // quadToTri_edges already
3350           if(edgeExists(verts[0], verts[2], quadToTri_edges))
3351             createEdge(verts[4], verts[6], quadToTri_edges);
3352           else if(edgeExists(verts[1], verts[3], quadToTri_edges))
3353             createEdge(verts[5], verts[7], quadToTri_edges);
3354           else if(p2 < 0 && p1 >= 0)
3355             createEdge(verts[(p1 + 1) % elem_size + elem_size],
3356                        verts[(p1 + elem_size - 1) % elem_size + elem_size],
3357                        quadToTri_edges);
3358           else if(p1 >= 0 &&
3359                   edgeExists(verts[p1], verts[p2 + elem_size], quadToTri_edges))
3360             createEdge(verts[p2 + elem_size],
3361                        verts[(p2 + 2) % elem_size + elem_size],
3362                        quadToTri_edges);
3363           else if(p1 >= 0 &&
3364                   edgeExists(verts[p1 + elem_size], verts[p2], quadToTri_edges))
3365             createEdge(verts[p1 + elem_size],
3366                        verts[(p1 + 2) % elem_size + elem_size],
3367                        quadToTri_edges);
3368         }
3369       }
3370     }
3371 
3372     // top diags on corner quad  ( I *think* this always works for non-degen
3373     // stuff, even for free wall spanning cases )
3374     else if(bnd_count == 3 &&
3375             (j_start < j_top_start || k_start < k_top_start)) {
3376       std::vector<MVertex *> verts;
3377       getExtrudedVertices(elem, ep, j_start, k_start, pos, verts);
3378       problems_new.clear();
3379       forbidden_new.clear();
3380       edges_new.clear();
3381       createEdge(verts[skip + elem_size],
3382                  verts[(skip + 2) % elem_size + elem_size], quadToTri_edges);
3383       createEdge(verts[skip + elem_size],
3384                  verts[(skip + 2) % elem_size + elem_size], edges_new);
3385       // copies the diags in edges_new on up the extrusion but NOT on the top
3386       // surface
3387       ExtrudeDiags(gr, verts, j_start, k_start, j_top_start, k_top_start, elem,
3388                    ep, edges_new, forbidden_new, quadToTri_edges,
3389                    forbidden_edges, problems_new, problems, pos);
3390     }
3391 
3392     // finally, top diagonal and other two laterals for 1 bnd point quad
3393     else if(bnd_count == 1 &&
3394             (j_start < j_top_start || k_start < k_top_start)) {
3395       std::vector<MVertex *> verts;
3396       getExtrudedVertices(elem, ep, j_start, k_start, pos, verts);
3397       int p = one_point_ind;
3398 
3399       // to determine if there is a second level above the start but not in top
3400       // layer
3401       int j_next, k_next;
3402       bool divide_next = false;
3403       std::vector<MVertex *> verts_next;
3404       if(ep->mesh.NbElmLayer[0] > 1) {
3405         j_next = 0;
3406         k_next = 1;
3407       }
3408       else {
3409         j_next = std::min(ep->mesh.NbLayer - 1, 1);
3410         k_next = 0;
3411       }
3412       if(j_next < j_top_start || k_next < k_top_start) {
3413         divide_next = true;
3414         getExtrudedVertices(elem, ep, j_next, k_next, pos, verts_next);
3415       }
3416 
3417       problems_new.clear();
3418       forbidden_new.clear();
3419       edges_new.clear();
3420 
3421       // Create the laterals that run up to the "pivot vertex" for this 1 bnd pt
3422       // quad Other internal elements have diagonals converging on the pivot
3423       // index. Only create it if there is NO conflicting diagonal in place,
3424       // though--this CAN happen, but this approach still give no conflicts.
3425       // NOTE THAT THESE ARE NOT PROPAGATED UP THE ENTIRE EXTRUSION.
3426       int p2 = (p + 1) % elem_size;
3427       int p3 = (p + 2) % elem_size;
3428       int p4 = (p + elem_size - 1) % elem_size;
3429       if(!edgeExists(verts[p2 + elem_size], verts[p3], quadToTri_edges))
3430         createEdge(verts[p2], verts[p3 + elem_size], quadToTri_edges);
3431       if(!edgeExists(verts[p4 + elem_size], verts[p3], quadToTri_edges))
3432         createEdge(verts[p4], verts[p3 + elem_size], quadToTri_edges);
3433 
3434       // if there is a second extrusion level not on the top layer, add the
3435       // 'reverse' of the previous two diagonals
3436       if(divide_next && !edgeExists(verts_next[p2], verts_next[p3 + elem_size],
3437                                     quadToTri_edges))
3438         createEdge(verts_next[p2 + elem_size], verts_next[p3], quadToTri_edges);
3439       if(divide_next && !edgeExists(verts_next[p4], verts_next[p3 + elem_size],
3440                                     quadToTri_edges))
3441         createEdge(verts_next[p4 + elem_size], verts_next[p3], quadToTri_edges);
3442 
3443       // If this quad has degenerate vertex on boundary and the pivot laterals
3444       // run to the top pivot vertex and there is no pre-existing top diagonal
3445       // on other two vertices, draw diagonal out to the pivot_vertex.
3446       // Otherwise, draw it on the other two verts
3447       if(verts[p] == verts[p + elem_size] &&
3448          (edgeExists(verts[p2], verts[p3 + elem_size], quadToTri_edges) ||
3449           verts[p2] == verts[p2 + elem_size]) &&
3450          (edgeExists(verts[p4], verts[p3 + elem_size], quadToTri_edges) ||
3451           verts[p4] == verts[p4 + elem_size]) &&
3452          !edgeExists(verts[p2 + elem_size], verts[p4 + elem_size],
3453                      quadToTri_edges)) {
3454         createEdge(verts[p + elem_size], verts[p3 + elem_size],
3455                    quadToTri_edges);
3456         createEdge(verts[p + elem_size], verts[p3 + elem_size], edges_new);
3457       }
3458       else {
3459         createEdge(verts[p2 + elem_size], verts[p4 + elem_size],
3460                    quadToTri_edges);
3461         createEdge(verts[p2 + elem_size], verts[p4 + elem_size], edges_new);
3462       }
3463       // copies the top diag in edges_new up the extrusion but NOT to the top
3464       // surface of region.
3465       ExtrudeDiags(gr, verts, 0, 0, j_top_start, k_top_start, elem, ep,
3466                    edges_new, forbidden_new, quadToTri_edges, forbidden_edges,
3467                    problems_new, problems, pos);
3468     }
3469 
3470   } // end of boundary quadrangles loop
3471 
3472   return 1;
3473 }
3474 
3475 // For use in QuadToTriEdgeGenerator:  Does the lateral edging of internal
3476 // elements that touch a pivot vertex of a hexahedral element that has ONE
3477 // SOURCE vertex on a lateral boundary surface. See inside function for a
3478 // definition of the "pivot vertex." Added 04/08/2011
makeEdgesForElemsTouchPivotVert(GRegion * gr,bool is_addverts,CategorizedSourceElements & cat_src_elems,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::set<std::pair<MVertex *,MVertex * >> & forbidden_edges,MVertexRTree & pos)3479 static int makeEdgesForElemsTouchPivotVert(
3480   GRegion *gr, bool is_addverts, CategorizedSourceElements &cat_src_elems,
3481   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
3482   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
3483   std::set<std::pair<MVertex *, MVertex *> > &forbidden_edges,
3484   MVertexRTree &pos)
3485 {
3486   //  Draw diagonals toward the "pivot vertex" of a hexahedron whose source quad
3487   //  has only one vertex on a lateral boundary. Actually, this is only done in
3488   //  the first two extrusion layers, if those layers are not in the top layer.
3489   //  The pivot vertex is the vertex in the top face of the element that is
3490   //  diametrically opposite the top vertex on the lateral boundary of the
3491   //  region. In first layer, draw diags up from bottom to the pivot vertex, in
3492   //  the second layer, draw them down to pivot vertex.  Same vertex for both
3493   //  layers.  This is done to ensure that a one pt boundary quad in an
3494   //  unstructured surface can be divided without dividing the entire bottom
3495   //  layer. If two pivot vertices share an edge and these rules would conflict,
3496   //  just give precedence to the first pivot vertex encountered in the edging
3497   //  loop (this works, yes).
3498 
3499   ExtrudeParams *ep = gr->meshAttributes.extrude;
3500 
3501   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
3502     Msg::Error("In makeEdgesForElemsTouchPivotVert(), invalid extrusion "
3503                "in region %d for performing QuadToTri mesh generation.",
3504                gr->tag());
3505     return 0;
3506   }
3507 
3508   GModel *model = gr->model();
3509   if(!model) {
3510     Msg::Error("In makeEdgesForElemsTouchPivotVert(), invalid model for region "
3511                "%d.",
3512                gr->tag());
3513     return 0;
3514   }
3515 
3516   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
3517   if(!reg_source) {
3518     Msg::Error(
3519       "In makeEdgesForForElemsTouchPivotVert(), invalid source face for region "
3520       "%d.",
3521       gr->tag());
3522     return 0;
3523   }
3524 
3525   if(gr != cat_src_elems.region || reg_source != cat_src_elems.source_face) {
3526     Msg::Error("In makeEdgesForElemsTouchPivotVert(), "
3527                "CatergorizedSourceElements structure data "
3528                " does not correspond to region %d.",
3529                reg_source->tag());
3530     return 0;
3531   }
3532 
3533   // return if there are no lateral surface diagonals and if not a rotation with
3534   // quadrangles.
3535   if(!lat_tri_diags.size() &&
3536      (!reg_source->quadrangles.size() ||
3537       (ep->geo.Type != ROTATE && ep->geo.Type != TRANSLATE_ROTATE)))
3538     return 1;
3539 
3540   // Return if there is only one extrude layer!!!!
3541   // (everything gets taken care of because all elements in top layer are
3542   // divided) ( in fact, this will cause problems if performed )
3543   if(ep->mesh.NbLayer <= 1 && ep->mesh.NbElmLayer[0] <= 1) return 1;
3544 
3545   int j_top_start, k_top_start;
3546   j_top_start = ep->mesh.NbLayer - 1;
3547   k_top_start = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1;
3548 
3549   // s = 0 for triangles; s = 1 for quadrangles
3550   // These diags are all repeated identically up the extrusion.
3551   for(int s = 0; s < 2; s++) {
3552     std::set<unsigned int> *set_elems;
3553     std::set<unsigned int>::iterator it;
3554 
3555     if(!s)
3556       set_elems = &cat_src_elems.internal_tri_touch_one_bnd_pt_quad;
3557     else
3558       set_elems = &cat_src_elems.internal_quad_touch_one_bnd_pt_quad;
3559 
3560     for(it = set_elems->begin(); it != set_elems->end(); it++) {
3561       MElement *elem;
3562       if(!s)
3563         elem = reg_source->triangles[(*it)];
3564       else
3565         elem = reg_source->quadrangles[(*it)];
3566 
3567       int elem_size = elem->getNumVertices();
3568 
3569       // find pivot vertex index
3570       int v_index;
3571       bool v_index_found = false;
3572       for(int p = 0; p < elem_size; p++) {
3573         if(!s && cat_src_elems.tri_bool[4 * (*it) + 1 + p]) {
3574           v_index = p;
3575           v_index_found = true;
3576           break;
3577         }
3578         else if(s && cat_src_elems.quad_bool[5 * (*it) + 1 + p]) {
3579           v_index = p;
3580           v_index_found = true;
3581           break;
3582         }
3583       }
3584       if(!v_index_found) {
3585         Msg::Error("In makeEdgesForElemsTouchPivotVert(), could not find the "
3586                    "pivot vertex for an element touching "
3587                    "a quad with one vertex on a face edge boundary in region "
3588                    "%d. Skipping...",
3589                    gr->tag());
3590         continue;
3591       }
3592 
3593       std::vector<MVertex *> verts;
3594       getExtrudedVertices(elem, ep, 0, 0, pos, verts);
3595 
3596       // determine the j, k for the next layer above 0,0 so that the elements
3597       // directly above the base elements can divided AND higher layers may be
3598       // closed off (no need to divide the elements all the way up)
3599       int j_next, k_next;
3600       bool divide_next = false;
3601       std::vector<MVertex *> verts_next;
3602       if(ep->mesh.NbElmLayer[0] > 1) {
3603         j_next = 0;
3604         k_next = 1;
3605       }
3606       else {
3607         j_next = std::min(ep->mesh.NbLayer - 1, 1);
3608         k_next = 0;
3609       }
3610       if(j_next < j_top_start || k_next < k_top_start) {
3611         divide_next = true;
3612         getExtrudedVertices(elem, ep, j_next, k_next, pos, verts_next);
3613       }
3614 
3615       // add the lateral diagonals (skip faces that are already diagonalized)
3616       // note these are created in two layers, mirrored about the plane
3617       // separating the layers
3618       int p2 = (v_index + 1) % elem_size;
3619       int p3 = (v_index + elem_size - 1) % elem_size;
3620       if(!edgeExists(verts[v_index], verts[p2 + elem_size], quadToTri_edges)) {
3621         createEdge(verts[v_index + elem_size], verts[p2], quadToTri_edges);
3622         if(divide_next)
3623           createEdge(verts_next[v_index], verts_next[p2 + elem_size],
3624                      quadToTri_edges);
3625       }
3626       if(!edgeExists(verts[v_index], verts[p3 + elem_size], quadToTri_edges)) {
3627         createEdge(verts[v_index + elem_size], verts[p3], quadToTri_edges);
3628         if(divide_next)
3629           createEdge(verts_next[v_index], verts_next[p3 + elem_size],
3630                      quadToTri_edges);
3631       }
3632       // make top diagonals for quads -- note: can't just draw to the preferred
3633       // pivot because it can touch two and the other might have laterals drawn
3634       // to it already.  have to find the one with two lateral diagonals drawn
3635       // to it.
3636       if(s == 1 && verts[v_index + elem_size] != verts[v_index] &&
3637          !edgeExists(verts[p2 + elem_size], verts[p3 + elem_size],
3638                      quadToTri_edges))
3639         createEdge(verts[v_index + elem_size],
3640                    verts[(v_index + 2) % elem_size + elem_size],
3641                    quadToTri_edges);
3642     }
3643   }
3644 
3645   // Now revisit the boundary quads that touched a one boundary point quad
3646   // pivot.  These MAY have had edges added and now need a top diagonal
3647   std::set<unsigned int>::iterator it;
3648   for(it = cat_src_elems.two_bnd_pt_quad_touch_one_bnd_pt_quad.begin();
3649       it != cat_src_elems.two_bnd_pt_quad_touch_one_bnd_pt_quad.end(); it++) {
3650     MElement *elem = reg_source->quadrangles[(*it)];
3651     int elem_size = elem->getNumVertices();
3652     std::vector<bool> vert_bnd;
3653     vert_bnd.insert(vert_bnd.begin(),
3654                     cat_src_elems.quad_bool.begin() + (5 * (*it) + 1),
3655                     cat_src_elems.quad_bool.begin() + (5 * (*it) + 5));
3656     // find num boundary points
3657     int bnd_count = 0;
3658     for(int s = 0; s < elem_size; s++) {
3659       if(vert_bnd[s]) bnd_count++;
3660     }
3661     if(bnd_count != 2) continue;
3662 
3663     std::vector<MVertex *> verts;
3664     getExtrudedVertices(elem, ep, 0, 0, pos, verts);
3665     int p1 = -1, p2 = -1;
3666     for(int p = 0; p < elem_size; p++) {
3667       if(vert_bnd[p]) {
3668         p1 = p;
3669         int p2_tmp = (p + 1) % elem_size;
3670         int p3_tmp = (p + elem_size - 1) % elem_size;
3671         if(vert_bnd[p2_tmp]) {
3672           p1 = p;
3673           p2 = p2_tmp;
3674         }
3675         else if(vert_bnd[p3_tmp]) {
3676           p1 = p3_tmp;
3677           p2 = p;
3678         }
3679         break;
3680       }
3681     }
3682     if(p2 < 0 && p1 < 0) {
3683       Msg::Error("In makeEdgesForElemsTouchPivotVert(), error finding boundary "
3684                  "points on "
3685                  "2-boundary point quadrangle.");
3686       break;
3687     }
3688 
3689     // find lateral boundary or internal lateral diagonals. If found, add top
3690     // diagonal
3691     std::set<std::pair<MVertex *, MVertex *> > edges_new;
3692     std::set<std::pair<MVertex *, MVertex *> > forbidden_new;
3693     std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
3694       problems, problems_new;
3695     if(p1 >= 0 && p2 >= 0 &&
3696        edgeExists(verts[(p1 + 2) % elem_size],
3697                   verts[(p1 + elem_size - 1) % elem_size + elem_size],
3698                   quadToTri_edges) &&
3699        !edgeExists(verts[p1 + elem_size],
3700                    verts[(p1 + 2) % elem_size + elem_size], quadToTri_edges)) {
3701       createEdge(verts[(p1 + 1) % elem_size + elem_size],
3702                  verts[(p1 + elem_size - 1) % elem_size + elem_size],
3703                  quadToTri_edges);
3704       createEdge(verts[(p1 + 1) % elem_size + elem_size],
3705                  verts[(p1 + elem_size - 1) % elem_size + elem_size],
3706                  edges_new);
3707     }
3708     else if(p1 >= 0 && p2 >= 0 &&
3709             edgeExists(verts[(p1 + 2) % elem_size + elem_size],
3710                        verts[(p1 + elem_size - 1) % elem_size],
3711                        quadToTri_edges) &&
3712             !edgeExists(verts[(p1 + 1) % elem_size + elem_size],
3713                         verts[(p1 + elem_size - 1) % elem_size + elem_size],
3714                         quadToTri_edges)) {
3715       createEdge(verts[p1 + elem_size], verts[(p1 + 2) % elem_size + elem_size],
3716                  quadToTri_edges);
3717       createEdge(verts[p1 + elem_size], verts[(p1 + 2) % elem_size + elem_size],
3718                  edges_new);
3719     }
3720 
3721     if(edges_new.size()) {
3722       ExtrudeDiags(gr, verts, 0, 0, j_top_start, k_top_start, elem, ep,
3723                    edges_new, forbidden_new, quadToTri_edges, forbidden_edges,
3724                    problems_new, problems, pos);
3725     }
3726   }
3727 
3728   return 1;
3729 }
3730 
3731 // For use in QuadToTriEdgeGenerator:  Does the lateral edging of internal
3732 // elements in the top extrusion layer by lowest vertex pointer value in TOP
3733 // FACE. Added 04/08/2011
makeEdgesInternalTopLayer(GRegion * gr,bool is_addverts,CategorizedSourceElements & cat_src_elems,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,MVertexRTree & pos)3734 static int makeEdgesInternalTopLayer(
3735   GRegion *gr, bool is_addverts, CategorizedSourceElements &cat_src_elems,
3736   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
3737   MVertexRTree &pos)
3738 {
3739   ExtrudeParams *ep = gr->meshAttributes.extrude;
3740 
3741   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
3742     Msg::Error("In makeEdgesInternalTopLayer(), invalid extrusion "
3743                "in region %d for performing QuadToTri mesh generation.",
3744                gr->tag());
3745     return 0;
3746   }
3747 
3748   GModel *model = gr->model();
3749   if(!model) {
3750     Msg::Error("In makeEdgesInternalTopLayer(), invalid model for region "
3751                "%d.",
3752                gr->tag());
3753     return 0;
3754   }
3755 
3756   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
3757   if(!reg_source) {
3758     Msg::Error(
3759       "In makeEdgesForInternalTopLayer(), invalid source face for region "
3760       "%d.",
3761       gr->tag());
3762     return 0;
3763   }
3764 
3765   if(gr != cat_src_elems.region || reg_source != cat_src_elems.source_face) {
3766     Msg::Error("In makeEdgesInternalTopLayer(), CatergorizedSourceElements "
3767                "structure data "
3768                " does not correspond to region %d.",
3769                reg_source->tag());
3770     return 0;
3771   }
3772 
3773   // s = 0 for triangles; s = 1 for quadrangles
3774   for(int s = 0; s < 2; s++) {
3775     // no need to do this if there are no quads!!!
3776     if(!reg_source->quadrangles.size()) break;
3777 
3778     std::set<unsigned int> *set_elems;
3779     std::set<unsigned int>::iterator it;
3780 
3781     if(!s)
3782       set_elems = &cat_src_elems.internal_tri;
3783     else
3784       set_elems = &cat_src_elems.internal_quad;
3785 
3786     for(it = set_elems->begin(); it != set_elems->end(); it++) {
3787       MElement *elem;
3788       if(!s)
3789         elem = reg_source->triangles[(*it)];
3790       else
3791         elem = reg_source->quadrangles[(*it)];
3792       int elem_size = elem->getNumVertices();
3793       std::vector<MVertex *> verts;
3794       int j = ep->mesh.NbLayer - 1;
3795       int k = ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1] - 1;
3796 
3797       getExtrudedVertices(elem, ep, j, k, pos, verts);
3798 
3799       // do this by lowest pointer value IN THE TOP SURFACE
3800       for(int p = 0; p < elem_size; p++) {
3801         int ind1, ind2, ind_low, ind_low_2;
3802         ind1 = p + elem_size;
3803         ind2 = (p + 1) % elem_size + elem_size;
3804         if(verts[ind1] < verts[ind2]) {
3805           ind_low = ind1;
3806           ind_low_2 = ind2 - elem_size;
3807         }
3808         else {
3809           ind_low = ind2;
3810           ind_low_2 = ind1 - elem_size;
3811         }
3812 
3813         if(!edgeExists(verts[ind_low - elem_size], verts[ind_low_2 + elem_size],
3814                        quadToTri_edges))
3815           createEdge(verts[ind_low], verts[ind_low_2], quadToTri_edges);
3816       }
3817     }
3818   }
3819 
3820   return 1;
3821 }
3822 
3823 // Generate the set of QuadToTri diagonal edges to subdivide elements,
3824 // and records problematic elements that need to be subvided with an internal
3825 // vertex. Added 2010-01-19
QuadToTriEdgeGenerator(GRegion * gr,CategorizedSourceElements & cat_src_elems,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,MVertexRTree & pos)3826 int QuadToTriEdgeGenerator(
3827   GRegion *gr, CategorizedSourceElements &cat_src_elems,
3828   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
3829   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
3830   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
3831     &problems,
3832   MVertexRTree &pos)
3833 {
3834   ExtrudeParams *ep = gr->meshAttributes.extrude;
3835 
3836   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) {
3837     Msg::Error("In QuadToTriEdgeGenerator(), invalid extrusion "
3838                "in region %d for performing QuadToTri mesh generation.",
3839                gr->tag());
3840     return 0;
3841   }
3842 
3843   GModel *model = gr->model();
3844   if(!model) {
3845     Msg::Error("In QuadToTriEdgeGenerator(), invalid model for region "
3846                "%d.",
3847                gr->tag());
3848     return 0;
3849   }
3850 
3851   // number of extrusion layers
3852   int num_layers = 0;
3853   for(int p = 0; p < ep->mesh.NbLayer; p++)
3854     num_layers += ep->mesh.NbElmLayer[p];
3855 
3856   // is this a valid 'add internal vertex' extrusion?
3857   bool is_addverts = false;
3858   if(ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1 ||
3859      ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1_RECOMB)
3860     is_addverts = true;
3861 
3862   // now find and verify the source and the top of region
3863 
3864   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
3865   if(!reg_source) {
3866     Msg::Error("In QuadToTriEdgeGenerator(), invalid source face for region "
3867                "%d.",
3868                gr->tag());
3869     return 0;
3870   }
3871 
3872   // need for toroidal loop extrusions...top layer treated specially
3873   bool is_toroidal = IsInToroidalQuadToTri(reg_source);
3874 
3875   std::vector<GFace *> reg_faces = gr->faces();
3876   std::vector<GFace *>::iterator itf = reg_faces.begin();
3877 
3878   // find top surface of extrusion and first root dependency of source
3879   GFace *reg_top = NULL;
3880   GFace *root = findRootSourceFaceForFace(reg_source);
3881   bool foundRoot = false;
3882   for(itf = reg_faces.begin(); itf != reg_faces.end(); itf++) {
3883     ExtrudeParams *face_ep = (*itf)->meshAttributes.extrude;
3884     if(face_ep && face_ep->geo.Mode == COPIED_ENTITY &&
3885        reg_source == model->getFaceByTag(std::abs(face_ep->geo.Source))) {
3886       reg_top = (*itf);
3887     }
3888     if((*itf) == root) foundRoot = true;
3889     if(reg_top && (foundRoot || !is_toroidal)) break;
3890   }
3891 
3892   if(is_toroidal && !reg_top && foundRoot && root != reg_source) reg_top = root;
3893   if(!reg_top) {
3894     Msg::Error("In QuadToTriEdgeGenerator(), invalid top surface for region "
3895                "%d.",
3896                gr->tag());
3897     return 0;
3898   }
3899 
3900   // list of forbidden edges and boundary verts that are in triangles
3901   std::set<std::pair<MVertex *, MVertex *> > forbidden_edges;
3902 
3903   // insert ALL fixed edges into quadToTri_edges, all forbidden edges on
3904   // recombined quads into forbidden_edges, and insert into lat_tri_diags ALL
3905   // lateral diagonal edges.
3906   QuadToTriGetRegionDiags(gr, quadToTri_edges, forbidden_edges, lat_tri_diags,
3907                           pos);
3908   /*unsigned int Rnum = gr->tag()-1;
3909   std::vector<MVertex*> verts;
3910   MElement *elem;
3911   elem = reg_source->triangles[0];
3912   int vert_num = getExtrudedVertices(elem, ep, 0, 0, pos, verts);
3913   const int elem_size = verts.size() == 8 ? 4 : 3;
3914   for( int p = 0; p < elem_size; p++ ){
3915     int state = Rnum / std::pow(3,(elem_size-1-p));
3916     Rnum -= state*std::pow(3,(elem_size-1-p));
3917     if( p < elem_size ){
3918       if( verts[p] == verts[p+elem_size] || verts[(p+1)%elem_size] ==
3919   verts[(p+1)%elem_size+elem_size] ) continue; if( state == 1 ){
3920         //createEdge( verts[p], verts[(p+1)%elem_size+elem_size],
3921   quadToTri_edges ); createEdge( verts[p], verts[(p+1)%elem_size+elem_size],
3922   lat_tri_diags );
3923       }
3924       else if( state == 2 ){
3925         //createEdge( verts[p+elem_size], verts[(p+1)%elem_size],
3926   quadToTri_edges ); createEdge( verts[p+elem_size], verts[(p+1)%elem_size],
3927   lat_tri_diags );
3928       }
3929       else if( state == 0 ){
3930         std::vector<MVertex *> v_face;
3931         v_face.assign(4, (MVertex*)(NULL) );
3932         v_face[0] = verts[p]; v_face[1] = verts[(p+1)%elem_size];
3933         v_face[2] = verts[(p+1)%elem_size+elem_size];
3934         v_face[3] = verts[p+elem_size];
3935          createForbidden(v_face, forbidden_edges);
3936       }
3937       else if( state != 0 )
3938         Msg::Error("Failed in finding all combos...state = %d.", state);
3939     }
3940     else{
3941       int add = (p==4) ? 0 : 4;
3942       if( state == 1 )
3943         createEdge( verts[0+add], verts[2+add], quadToTri_edges );
3944       else if( state == 2 )
3945         createEdge( verts[1+add], verts[3+add], quadToTri_edges );
3946       else if( state == 0 ){
3947         std::vector<MVertex *> v_face;
3948         v_face.assign(4, (MVertex*)(NULL) );
3949         v_face[0] = verts[0+add]; v_face[1] = verts[1+add];
3950         v_face[2] = verts[2+add]; v_face[3] = verts[3+add];
3951         createForbidden(v_face, forbidden_edges);
3952       }
3953       else
3954         Msg::Error("Failed in finding all combos...state = %d.", state);
3955     }
3956   }*/
3957 
3958   // if this is an' add internal vertex' extrusion, don't need adjustable
3959   // lateral edges, so put all lat_tri_diags into quadToTri_edges
3960   if(is_addverts)
3961     quadToTri_edges.insert(lat_tri_diags.begin(), lat_tri_diags.end());
3962 
3963   // If there are no lat_tri_diags and no quads, there is nothing  left to do
3964   if(!lat_tri_diags.size() && !reg_source->quadrangles.size()) return 1;
3965 
3966   // can return now if this is an 'add internal vertex' extrusion...nothing left
3967   // to do
3968   if(is_addverts) return 1;
3969 
3970   // BRUTE FORCE diagonalization of elements with all vertices on a lateral
3971   // boundary of region: This has to be done for all cases with such elements if
3972   if(!makeEdgesForElemsWithAllVertsOnBnd(gr, is_addverts, cat_src_elems,
3973                                          quadToTri_edges, lat_tri_diags,
3974                                          forbidden_edges, problems, pos)) {
3975     Msg::Error("In QuadToTriEdgeGenerator(), failed to make edges for the "
3976                "elements in region %d "
3977                "with all vertices on a lateral boundary",
3978                gr->tag());
3979     return 0;
3980   }
3981 
3982   // now do the "elegant" diagonalization of all the rest of the surface
3983   // elements....
3984 
3985   // Extrude source triangles that are on the source boundary edges and find any
3986   // diagonals
3987   if(!makeEdgesForOtherBndPrisms(gr, is_addverts, cat_src_elems,
3988                                  quadToTri_edges, lat_tri_diags,
3989                                  forbidden_edges, problems, pos)) {
3990     Msg::Error(
3991       "In QuadToTriEdgeGenerator(), failed to make edges for the prism "
3992       "extrusions in region %d with "
3993       "source triangles having some but not all vertices on the boundary",
3994       gr->tag());
3995     return 0;
3996   }
3997 
3998   // For a region with a structured all-quad source surface, none of the
3999   // previous edging will be executed, so this is the first place a region with
4000   // a structured quad source surface starts getting edges.
4001 
4002   // The rest of this function is only necessary for a single layer quadToTri
4003   // method extrusions:
4004 
4005   // Edge creation for extruded quadrangles with some but not all vertices on a
4006   // boundary.
4007   if(!makeEdgesForOtherBndHexa(gr, is_addverts, cat_src_elems, quadToTri_edges,
4008                                lat_tri_diags, forbidden_edges, problems, pos)) {
4009     Msg::Error("In QuadToTriEdgeGenerator(), failed to make edges for the "
4010                "hexahedral extrusions in region %d with "
4011                "source quads having some but not all vertices on the boundary",
4012                gr->tag());
4013     return 0;
4014   }
4015 
4016   // Find diagonals for elements touching a "pivot vertex" of a hexa element
4017   // that has a source quad with only one vertex on a lateral boundary (see
4018   // inside makeEdgesForOtherBndHexa() and makeEdgesForElemsTouchingPivotVert()
4019   // for details of "pivot vertex".
4020   if(!makeEdgesForElemsTouchPivotVert(gr, is_addverts, cat_src_elems,
4021                                       quadToTri_edges, lat_tri_diags,
4022                                       forbidden_edges, pos)) {
4023     Msg::Error("In QuadToTriEdgeGenerator(), failed to make edges for "
4024                "the elements in region %d touching a \'pivot vertex\' of a "
4025                "hexa element with source quad having one vertex on a boundary.",
4026                gr->tag());
4027     return 0;
4028   }
4029 
4030   // Mesh internal elements in the top layer (just add lateral diagonals for the
4031   // Do this by lowest pointer in top surface
4032   if(!is_toroidal && !makeEdgesInternalTopLayer(gr, is_addverts, cat_src_elems,
4033                                                 quadToTri_edges, pos)) {
4034     Msg::Error("In QuadToTriEdgeGenerator(), failed to make internal edges "
4035                "in top extrusion layer of region %d.",
4036                gr->tag());
4037     return 0;
4038   }
4039 
4040   return 1;
4041 }
4042 
4043 // Remesh the lateral 2D faces of QuadToTri regions using edges in
4044 // quadToTri_edges as constraints Added 2010-01-24
QuadToTriLateralRemesh(GRegion * gr,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges)4045 static bool QuadToTriLateralRemesh(
4046   GRegion *gr, std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges)
4047 {
4048   ExtrudeParams *ep = gr->meshAttributes.extrude;
4049 
4050   if(!ep || !ep->mesh.QuadToTri || !ep->mesh.ExtrudeMesh) return false;
4051 
4052   GModel *model = gr->model();
4053 
4054   // find source face
4055   GFace *reg_source = model->getFaceByTag(std::abs(ep->geo.Source));
4056   if(!reg_source) {
4057     Msg::Error("In QuadToTriLateralRemesh(), could not find source face "
4058                "%d for region %d.",
4059                std::abs(ep->geo.Source), gr->tag());
4060     return false;
4061   }
4062 
4063   // Find a source surface, find a COPIED_ENTITY that is the top surface,
4064   // If shared laterals are all static (quad or non subdivide triangles),
4065   // set the allStaticSharedLaterals argument to true.
4066   // If any lateral is unstructured, error.
4067 
4068   bool is_toroidal = IsInToroidalQuadToTri(reg_source);
4069   GFace *root = findRootSourceFaceForFace(reg_source);
4070 
4071   bool foundTop = false, foundRoot = false;
4072   GFace *reg_top = NULL;
4073   std::vector<GFace *> faces = gr->faces();
4074   std::vector<GFace *>::iterator it = faces.begin();
4075 
4076   for(it = faces.begin(); it != faces.end(); it++) {
4077     ExtrudeParams *face_tmp_ep = (*it)->meshAttributes.extrude;
4078     if((*it) == root) foundRoot = true;
4079     if(face_tmp_ep && face_tmp_ep->geo.Mode == COPIED_ENTITY) {
4080       GFace *top_source_tmp =
4081         model->getFaceByTag(std::abs(face_tmp_ep->geo.Source));
4082       if(!top_source_tmp) {
4083         Msg::Error("In QuadToTriLateralRemesh(), could not find source face "
4084                    "%d for copied surface %d of region %d.",
4085                    std::abs(face_tmp_ep->geo.Source), (*it)->tag(), gr->tag());
4086       }
4087       else if(top_source_tmp == reg_source) {
4088         foundTop = true;
4089         reg_top = (*it);
4090       }
4091     }
4092   }
4093 
4094   // if didn't find the copied entity, maybe this is toroidal and the top has
4095   // been replaced
4096   if(is_toroidal && !foundTop && foundRoot && root != reg_source)
4097     foundTop = true;
4098 
4099   if(!foundTop)
4100     Msg::Warning("In QuadToTriLateralRemesh(), could not find top face "
4101                  "for region %d.",
4102                  gr->tag());
4103 
4104   Msg::Info("Remeshing lateral surfaces for QuadToTri region %d.", gr->tag());
4105 
4106   // now loop through faces again, remeshing all laterals that need it.
4107   for(it = faces.begin(); it != faces.end(); it++) {
4108     if((*it) != reg_top && (*it) != reg_source &&
4109        IsSurfaceALateralForRegion(gr, *it)) {
4110       // *** JUST REMESH EVERY SURFACE AGAIN TO BE SURE ***
4111 
4112       for(unsigned int i = 0; i < (*it)->triangles.size(); i++)
4113         delete(*it)->triangles[i];
4114       (*it)->triangles.clear();
4115       for(unsigned int i = 0; i < (*it)->quadrangles.size(); i++)
4116         delete(*it)->quadrangles[i];
4117       (*it)->quadrangles.clear();
4118       MeshExtrudedSurface((*it), &quadToTri_edges);
4119     }
4120   }
4121   return foundTop;
4122 }
4123 
4124 // Adds the face- or body-center vertices needed for some QuadToTri elements
addBodyCenteredVertices(GRegion * to,CategorizedSourceElements & c,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,bool is_addverts,unsigned int lat_tri_diags_size,MVertexRTree & pos)4125 static bool addBodyCenteredVertices(
4126   GRegion *to, CategorizedSourceElements &c,
4127   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
4128   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4129     &problems,
4130   bool is_addverts, unsigned int lat_tri_diags_size, MVertexRTree &pos)
4131 {
4132   ExtrudeParams *ep = to->meshAttributes.extrude;
4133   if(!ep || !ep->mesh.ExtrudeMesh || !ep->mesh.QuadToTri) return false;
4134 
4135   GModel *model = to->model();
4136   GFace *from = model->getFaceByTag(std::abs(ep->geo.Source));
4137   if(!from) return false;
4138 
4139   // find number of layers;
4140   unsigned int num_layer = 0;
4141   for(int p = 0; p < ep->mesh.NbLayer; p++) num_layer += ep->mesh.NbElmLayer[p];
4142 
4143   // create reserve capacity for the temp vector of new vertices:
4144   unsigned int cap_add = 0;
4145   if(!is_addverts) {
4146     std::map<MElement *,
4147              std::set<std::pair<unsigned int, unsigned int> > >::iterator itmap;
4148     for(itmap = problems.begin(); itmap != problems.end(); itmap++)
4149       cap_add += itmap->second.size();
4150   }
4151   else {
4152     unsigned int NbBndElems = c.four_bnd_pt_quad.size() +
4153                               c.three_bnd_pt_tri.size() +
4154                               c.other_bnd_quad.size() + c.other_bnd_tri.size();
4155     unsigned int NbSourceElems =
4156       from->triangles.size() + from->quadrangles.size();
4157     if(findRootSourceFaceForFace(from) ==
4158        from) // if extruded back on the source in a ring
4159       cap_add = NbBndElems * num_layer;
4160     else
4161       cap_add = NbSourceElems + NbBndElems * (num_layer - 1);
4162   }
4163   to->mesh_vertices.reserve(to->mesh_vertices.size() + cap_add);
4164 
4165   // first the !is_addverts case
4166   if(problems.size() && !is_addverts) {
4167     std::map<MElement *,
4168              std::set<std::pair<unsigned int, unsigned int> > >::iterator itmap;
4169     for(itmap = problems.begin(); itmap != problems.end(); itmap++) {
4170       MElement *elem = itmap->first;
4171       std::set<std::pair<unsigned int, unsigned int> >::iterator itpairs;
4172       for(itpairs = itmap->second.begin(); itpairs != itmap->second.end();
4173           itpairs++) {
4174         std::vector<MVertex *> verts;
4175         int j = (*itpairs).first;
4176         int k = (*itpairs).second;
4177         getExtrudedVertices(elem, ep, j, k, pos, verts);
4178         QtMakeCentroidVertex(verts, &(to->mesh_vertices), to, pos);
4179       }
4180     }
4181   }
4182 
4183   if(!is_addverts) return 1;
4184 
4185   // The rest of the function works for is_addverts
4186 
4187   // Holds the new vertices...put them in to->mesh_vertices only at the end
4188   std::vector<MVertex *> v_tmp;
4189   v_tmp.reserve(cap_add);
4190 
4191   // triangles and quadrangles
4192   // t =0 triangles, t=1 quadrangles
4193   std::vector<MVertex *> verts3D;
4194   for(int t = 0; t < 2; t++) {
4195     for(int s = 0; s < 3; s++) {
4196       std::set<unsigned int> *set_elems;
4197       if(!t) {
4198         if(!s)
4199           set_elems = &c.three_bnd_pt_tri;
4200         else if(s == 1)
4201           set_elems = &c.other_bnd_tri;
4202         else
4203           set_elems = &c.internal_tri;
4204       }
4205       else {
4206         if(!s)
4207           set_elems = &c.four_bnd_pt_quad;
4208         else if(s == 1)
4209           set_elems = &c.other_bnd_quad;
4210         else
4211           set_elems = &c.internal_quad;
4212       }
4213       std::set<unsigned int>::iterator itset;
4214       for(itset = set_elems->begin(); itset != set_elems->end(); itset++) {
4215         MElement *elem;
4216         if(!t)
4217           elem = from->triangles[(*itset)];
4218         else
4219           elem = from->quadrangles[(*itset)];
4220         int elem_size = elem->getNumVertices();
4221         // see if this element is on a boundary with lat_tri_diags or a
4222         // degenerated hexahedron (always divide those)
4223         bool found_diags = false;
4224         bool degen_hex = false;
4225         verts3D.resize(0);
4226         getExtrudedVertices(elem, ep, 0, 0, pos, verts3D);
4227         for(int p = 0; p < elem_size; p++) {
4228           // always look for degen hex
4229           if(t && verts3D[p] == verts3D[p + elem_size] &&
4230              verts3D[(p + 1) % elem_size] !=
4231                verts3D[(p + 1) % elem_size + elem_size] &&
4232              verts3D[(p + elem_size - 1) % elem_size] !=
4233                verts3D[(p + elem_size - 1) % elem_size + elem_size]) {
4234             degen_hex = true;
4235             break;
4236           }
4237           // skip the rest if no lat_tri_diags or if not on lateral boundary
4238           if(!lat_tri_diags_size || s >= 2) continue;
4239           // if a triangle face, skip it
4240           if(verts3D[p] == verts3D[p + elem_size] ||
4241              verts3D[(p + 1) % elem_size] ==
4242                verts3D[(p + 1) % elem_size + elem_size])
4243             continue;
4244           else if(edgeExists(verts3D[p],
4245                              verts3D[(p + 1) % elem_size + elem_size],
4246                              quadToTri_edges))
4247             found_diags = true;
4248           else if(edgeExists(verts3D[p + elem_size],
4249                              verts3D[(p + 1) % elem_size], quadToTri_edges))
4250             found_diags = true;
4251         }
4252         // triangle extrusions don't need body centered verts if NO diags found
4253         // or if not on lateral boundary
4254         if(!t && (!found_diags || s == 2)) continue;
4255 
4256         int j_start, k_start;
4257         if((s < 2 && found_diags) || degen_hex) {
4258           j_start = 0;
4259           k_start = 0;
4260         }
4261         else { // only non-bnd quads or columns with no lateral diags and not
4262                // extruded into degen hexa should execute this
4263           j_start = ep->mesh.NbLayer - 1;
4264           k_start = ep->mesh.NbElmLayer[j_start] - 1;
4265         }
4266         std::vector<MVertex *> verts;
4267         for(int j = j_start; j < ep->mesh.NbLayer; j++) {
4268           int k_stop = ep->mesh.NbElmLayer[j];
4269           for(int k = k_start; k < k_stop; k++) {
4270             verts.resize(0);
4271             getExtrudedVertices(elem, ep, j, k, pos, verts);
4272             QtMakeCentroidVertex(verts, &v_tmp, to, pos);
4273           }
4274         }
4275       }
4276     }
4277   }
4278   // Don't forget to add v_tmp to to->mesh_vertices!!!
4279   to->mesh_vertices.reserve(to->mesh_vertices.size() + v_tmp.size());
4280   for(unsigned int p = 0; p < v_tmp.size(); p++)
4281     to->mesh_vertices.push_back(v_tmp[p]);
4282   return 1;
4283 }
4284 
4285 // Meshes either a prism or a hexahedral set of mesh vertices with an internal
4286 // vertex created here in the function. Added 2010-03-30
MeshWithInternalVertex(GRegion * to,MElement * source,std::vector<MVertex * > v,std::vector<int> n1,std::vector<int> n2,MVertexRTree & pos)4287 static void MeshWithInternalVertex(GRegion *to, MElement *source,
4288                                    std::vector<MVertex *> v,
4289                                    std::vector<int> n1, std::vector<int> n2,
4290                                    MVertexRTree &pos)
4291 {
4292   int v_size = v.size();
4293   int n_lat_tmp;
4294   if(v_size == 6)
4295     n_lat_tmp = 3;
4296   else if(v_size == 8)
4297     n_lat_tmp = 4;
4298   else {
4299     Msg::Error("In MeshWithInternalVertex(), number of element vertices does "
4300                "not equal 6 or 8.");
4301     return;
4302   }
4303 
4304   const int n_lat = n_lat_tmp;
4305 
4306   if((n_lat == 3 && n1.size() != 3) || (n_lat == 4 && n2.size() != 6)) {
4307     Msg::Error("In MeshWithInternalVertex(), size of diagonal node vectors is "
4308                "not does not equal 3 or 6.");
4309     return;
4310   }
4311 
4312   // find the internal vertex
4313   std::vector<double> centroid = QtFindVertsCentroid(v);
4314 
4315   // it's too dangerous to use the 'new' command in here even with body-centered
4316   // vertices.
4317 
4318   MVertex *tmp = pos.find(centroid[0], centroid[1], centroid[2]);
4319   if(!tmp) {
4320     Msg::Error("Could not find extruded vertex (%.16g, %.16g, %.16g) in "
4321                "geometrical entity %d",
4322                centroid[0], centroid[1], centroid[2], to->tag());
4323     Msg::Error("MeshWithInternalVertex() failed to find body-centered vertex.");
4324     return;
4325   }
4326 
4327   MVertex *v_int = tmp;
4328 
4329   // build all pyramids/tetra
4330   for(int p = 0; p < n_lat; p++) {
4331     int p2 = (p + 1) % n_lat;
4332     if(v[p] == v[p + n_lat] && v[p2] == v[p2 + n_lat])
4333       continue;
4334     else if(v[p] == v[p + n_lat] || v[p2] == v[p2 + n_lat]) {
4335       MVertex *v_dup = (v[p] == v[p + n_lat]) ? v[p] : v[p2];
4336       MVertex *v_non_dup = (v_dup == v[p]) ? v[p2] : v[p];
4337       MVertex *v_non_dup2 = (v_non_dup == v[p]) ? v[p + n_lat] : v[p2 + n_lat];
4338       addTetrahedron(v_dup, v_non_dup, v_non_dup2, v_int, to, source);
4339     }
4340     else if(n1[p] == p || n2[p] == p) {
4341       addTetrahedron(v[p], v[p2], v[p2 + n_lat], v_int, to, source);
4342       addTetrahedron(v[p], v[p2 + n_lat], v[p + n_lat], v_int, to, source);
4343     }
4344     else if(n1[p] == p + n_lat || n2[p] == p + n_lat) {
4345       addTetrahedron(v[p], v[p2], v[p + n_lat], v_int, to, source);
4346       addTetrahedron(v[p2], v[p2 + n_lat], v[p + n_lat], v_int, to, source);
4347     }
4348     else
4349       addPyramid(v[p], v[p2], v[p2 + n_lat], v[p + n_lat], v_int, to, source);
4350   }
4351 
4352   if(n_lat == 3) {
4353     // bottom and top
4354     addTetrahedron(v[0], v[1], v[2], v_int, to, source);
4355     addTetrahedron(v[3], v[5], v[4], v_int, to, source);
4356   }
4357   else if(n_lat == 4) {
4358     for(int p = 4; p < 6; p++) {
4359       int add = (p == 4) ? 0 : 4;
4360       if(n1[p] == 0 + add || n2[p] == 0 + add) {
4361         addTetrahedron(v[add], v[1 + add], v[2 + add], v_int, to, source);
4362         addTetrahedron(v[add], v[2 + add], v[3 + add], v_int, to, source);
4363       }
4364       else if(n1[p] == 1 + add || n2[p] == 1 + add) {
4365         addTetrahedron(v[1 + add], v[2 + add], v[3 + add], v_int, to, source);
4366         addTetrahedron(v[1 + add], v[3 + add], v[add], v_int, to, source);
4367       }
4368       else
4369         addPyramid(v[add], v[1 + add], v[2 + add], v[3 + add], v_int, to,
4370                    source);
4371     }
4372   }
4373 }
4374 
4375 // Construct the elements that subdivide a prism (or degenerated prism)  in a
4376 // QuadToTri interface; Added 2010-01-24
QuadToTriPriPyrTet(std::vector<MVertex * > & v,GRegion * to,int j,int k,MElement * source,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,unsigned int lat_tri_diags_size,bool bnd_elem,bool is_addverts,bool diag_search,MVertexRTree & pos)4377 static inline void QuadToTriPriPyrTet(
4378   std::vector<MVertex *> &v, GRegion *to, int j, int k, MElement *source,
4379   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
4380   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4381     &problems,
4382   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4383     &problems_new,
4384   unsigned int lat_tri_diags_size, bool bnd_elem, bool is_addverts,
4385   bool diag_search, MVertexRTree &pos)
4386 {
4387   int dup[3];
4388   int m = 0;
4389   for(int i = 0; i < 3; i++)
4390     if(v[i] == v[i + 3]) dup[m++] = i;
4391 
4392   bool is_problem = false;
4393   if(!is_addverts) {
4394     std::pair<unsigned int, unsigned int> jk_pair(j, k);
4395     std::map<MElement *,
4396              std::set<std::pair<unsigned int, unsigned int> > >::iterator
4397       itprob;
4398     itprob = problems.find(source);
4399     if(itprob != problems.end()) {
4400       if((*itprob).second.find(jk_pair) != (*itprob).second.end())
4401         is_problem = true;
4402     }
4403   }
4404 
4405   if(m && is_problem) {
4406     Msg::Error("In QuadToTriPriPyrTet(), non-prismatic extrusion of triangle "
4407                "in region %d "
4408                "marked as needing internal vertex to complete. Skipping....",
4409                to->tag());
4410     return;
4411   }
4412 
4413   // BAD SHAPE
4414   if(m > 2 || m < 0) {
4415     Msg::Error("In QuadToTriPriPyrTet(), bad number of degenerate corners.");
4416     return;
4417   }
4418 
4419   // find vertex node indices for diagonalized faces
4420   std::vector<int> n1, n2;
4421   bool found_diags = false;
4422   n1.assign(3, -1);
4423   n2.assign(3, -2);
4424   if(diag_search) {
4425     for(int p = 0; p < 3; p++) {
4426       n1[p] = -p * p - p - 1;
4427       n2[p] = -p * p - p - 2;
4428       if(v[p] == v[p + 3] || v[(p + 1) % 3] == v[(p + 1) % 3 + 3])
4429         continue;
4430       else if(edgeExists(v[p], v[(p + 1) % 3 + 3], quadToTri_edges)) {
4431         n1[p] = p;
4432         n2[p] = (p + 1) % 3 + 3;
4433         found_diags = true;
4434       }
4435       else if(edgeExists(v[p + 3], v[(p + 1) % 3], quadToTri_edges)) {
4436         n1[p] = p + 3;
4437         n2[p] = (p + 1) % 3;
4438         found_diags = true;
4439       }
4440     }
4441   }
4442 
4443   // mesh with added internal body centered vertex
4444   // is this prism part of a QuadToTri internal vertex extrusion and does it
4445   // need to be extruded as such?
4446   if(is_addverts && bnd_elem && found_diags) {
4447     MeshWithInternalVertex(to, source, v, n1, n2, pos);
4448     return;
4449   }
4450 
4451   // The rest are for 'no new vertex' extrusions or degenerate prisms:
4452 
4453   // tetrahedron
4454   if(m == 2 && !is_problem) {
4455     int dup_face = (dup[0] + 1) % 3 == dup[1] ? dup[0] : dup[1];
4456     addTetrahedron(v[dup_face], v[(dup_face + 1) % 3], v[(dup_face + 2) % 3],
4457                    v[(dup_face + 2) % 3 + 3], to, source);
4458     return;
4459   }
4460   // pyramid
4461   else if(m == 1 && !is_problem) {
4462     int p = (dup[0] + 1) % 3;
4463     // determine if the pyramid is sliced into two tetrahedra
4464     if(n1[p] >= 0) {
4465       int add = n1[p] < 3 ? 3 : -3;
4466       addTetrahedron(v[n1[p]], v[n2[p]], v[n1[p] + add], v[dup[0]], to, source);
4467       addTetrahedron(v[n1[p]], v[n2[p] - add], v[n2[p]], v[dup[0]], to, source);
4468     }
4469     else // pyramid
4470       addPyramid(v[p], v[p + 3], v[(p + 1) % 3 + 3], v[(p + 1) % 3], v[dup[0]],
4471                  to, source);
4472 
4473     return;
4474   }
4475 
4476   // Full prism: Start looking for a diagonal on a lateral.
4477   else if(m == 0 && !is_problem) {
4478     if(!found_diags) {
4479       addPrism(v[0], v[1], v[2], v[3], v[4], v[5], to, source);
4480       return;
4481     }
4482     else {
4483       for(int p = 0; p < 3; p++) {
4484         if(n1[p] >= 0 && n2[p] == n1[(p + 1) % 3]) {
4485           int add = n2[p] < 3 ? 3 : -3;
4486           int tet_top = n2[p] + add;
4487           int pyr_top = n2[p];
4488           int base = (p + 2) % 3;
4489           addTetrahedron(v[n1[p]], v[n2[p]], v[n2[(p + 1) % 3]], v[tet_top], to,
4490                          source);
4491           if(n1[(p + 2) % 3] >= 0) {
4492             int add_2 = n1[base] < 3 ? 3 : -3;
4493             addTetrahedron(v[n1[base]], v[n2[base]], v[n1[base] + add_2],
4494                            v[pyr_top], to, source);
4495             addTetrahedron(v[n1[base]], v[n2[base]], v[n2[base] - add_2],
4496                            v[pyr_top], to, source);
4497           }
4498           else
4499             addPyramid(v[base], v[base + 3], v[(base + 1) % 3 + 3],
4500                        v[(base + 1) % 3], v[pyr_top], to, source);
4501           return;
4502         }
4503       }
4504     }
4505   }
4506 
4507   // At this point, if the function has not returned, element must be meshed
4508   // with an additional vertex
4509 
4510   if(!is_problem) {
4511     Msg::Error(
4512       "In QuadToTriPriPyrTet(), Extruded prism needs subdivision, but cannot "
4513       " be divided without internal vertex, but was not previously detected as "
4514       "such. "
4515       " This is a bug. Please Report.");
4516     Msg::Error("j: %d, k: %d", j, k);
4517     QtMakeCentroidVertex(v, &(to->mesh_vertices), to, pos);
4518     std::pair<unsigned int, unsigned int> jk_pair(j, k);
4519     problems_new[source].insert(jk_pair);
4520     is_problem = true;
4521   }
4522 
4523   if(is_problem) {
4524     MeshWithInternalVertex(to, source, v, n1, n2, pos);
4525     return;
4526   }
4527 }
4528 
4529 // Construct the elements that subdivde a two-point degenerated hexahedron
4530 // (prism).
createTwoPtDegenHexElems(std::vector<MVertex * > & v,GRegion * to,ExtrudeParams * ep,int j,int k,int dup[],MElement * source,std::vector<int> n1,std::vector<int> n2,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,unsigned int lat_tri_diags_size,bool bnd_elem,bool is_addverts,bool found_diags)4531 static inline bool createTwoPtDegenHexElems(
4532   std::vector<MVertex *> &v, GRegion *to, ExtrudeParams *ep, int j, int k,
4533   int dup[], MElement *source, std::vector<int> n1, std::vector<int> n2,
4534   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
4535   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4536     &problems,
4537   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4538     &problems_new,
4539   unsigned int lat_tri_diags_size, bool bnd_elem, bool is_addverts,
4540   bool found_diags)
4541 {
4542   if(!ep) return 0;
4543 
4544   // first find out what is the degenerate face
4545   int degen_face = (dup[0] + 1) % 4 == dup[1] ? dup[0] : dup[1];
4546 
4547   // if no diags found, make a prism and return
4548   if(!found_diags) {
4549     addPrism(v[degen_face], v[(degen_face + 3) % 4],
4550              v[(degen_face + 3) % 4 + 4], v[(degen_face + 1) % 4],
4551              v[(degen_face + 2) % 4], v[(degen_face + 2) % 4 + 4], to, source);
4552     return 1;
4553   }
4554 
4555   int tet_top = -1;
4556   int pyr_top = -2;
4557 
4558   // if faces 4 and 5 can make a slice
4559   if(n1[4] >= 0 && (n1[4] + 4 == n1[5] || n2[4] + 4 == n1[5])) {
4560     if(n1[4] == degen_face || n2[4] == degen_face) {
4561       pyr_top = degen_face;
4562       tet_top = (degen_face + 1) % 4;
4563     }
4564     else {
4565       pyr_top = (degen_face + 1) % 4;
4566       tet_top = degen_face;
4567     }
4568     addTetrahedron(v[pyr_top], v[(pyr_top + 2) % 4], v[(pyr_top + 2) % 4 + 4],
4569                    v[tet_top], to, source);
4570 
4571     int base = (degen_face + 2) % 4;
4572     if(n1[base] >= 0) {
4573       int add = n1[base] > 3 ? -4 : 4;
4574       addTetrahedron(v[n1[base]], v[n2[base]], v[n1[base] + add], v[pyr_top],
4575                      to, source);
4576       addTetrahedron(v[n1[base]], v[n2[base] - add], v[n2[base]], v[pyr_top],
4577                      to, source);
4578     }
4579     else
4580       addPyramid(v[base], v[base + 4], v[(base + 1) % 4 + 4], v[(base + 1) % 4],
4581                  v[pyr_top], to, source);
4582 
4583     return 1;
4584   }
4585 
4586   // if faces 4 and (degen_face+2)%4 make a slice
4587   if(tet_top < 0 && n1[4] >= 0 &&
4588      (n1[4] == n1[(degen_face + 2) % 4] || n2[4] == n1[(degen_face + 2) % 4] ||
4589       n1[4] == n2[(degen_face + 2) % 4] || n2[4] == n2[(degen_face + 2) % 4])) {
4590     pyr_top = n1[(degen_face + 2) % 4] < 4 ? n1[(degen_face + 2) % 4] :
4591                                              n2[(degen_face + 2) % 4];
4592     tet_top = pyr_top == (degen_face + 2) % 4 ? (degen_face + 3) % 4 :
4593                                                 (degen_face + 2) % 4;
4594 
4595     addTetrahedron(v[pyr_top], v[tet_top + 4], v[(pyr_top + 2) % 4], v[tet_top],
4596                    to, source);
4597 
4598     int base = 5;
4599     if(n1[base] >= 0) {
4600       addTetrahedron(v[n1[base]], v[n2[base]], v[(n1[base] - 4 + 1) % 4 + 4],
4601                      v[pyr_top], to, source);
4602       addTetrahedron(v[n1[base]], v[n2[base]], v[(n1[base] - 4 + 3) % 4 + 4],
4603                      v[pyr_top], to, source);
4604     }
4605     else
4606       addPyramid(v[4], v[5], v[6], v[7], v[pyr_top], to, source);
4607 
4608     return 1;
4609   }
4610 
4611   // if faces 5 and (degen_face+2)%4 make a slice
4612   if(tet_top < 0 && n1[5] >= 0 &&
4613      (n1[5] == n1[(degen_face + 2) % 4] || n2[5] == n1[(degen_face + 2) % 4] ||
4614       n1[5] == n2[(degen_face + 2) % 4] || n2[5] == n2[(degen_face + 2) % 4])) {
4615     pyr_top = n1[(degen_face + 2) % 4] < 4 ? n2[(degen_face + 2) % 4] :
4616                                              n1[(degen_face + 2) % 4];
4617     tet_top = pyr_top == (degen_face + 2) % 4 + 4 ? (degen_face + 3) % 4 + 4 :
4618                                                     (degen_face + 2) % 4 + 4;
4619 
4620     addTetrahedron(v[pyr_top], v[(pyr_top - 4 + 2) % 4 + 4], v[tet_top - 4],
4621                    v[tet_top], to, source);
4622 
4623     int base = 4;
4624     if(n1[base] >= 0) {
4625       addTetrahedron(v[n1[base]], v[n2[base]], v[(n1[base] + 1) % 4],
4626                      v[pyr_top], to, source);
4627       addTetrahedron(v[n1[base]], v[n2[base]], v[(n1[base] + 3) % 4],
4628                      v[pyr_top], to, source);
4629     }
4630     else
4631       addPyramid(v[0], v[1], v[2], v[3], v[pyr_top], to, source);
4632 
4633     return 1;
4634   }
4635 
4636   return 0;
4637 }
4638 
4639 // Construct the elements that subdivide a one-point degenerated hexahedron
4640 // extrusion
createOnePtDegenHexElems(std::vector<MVertex * > & v,GRegion * to,ExtrudeParams * ep,int j,int k,int dup[],MElement * source,std::vector<int> n1,std::vector<int> n2,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,unsigned int lat_tri_diags_size,bool bnd_elem,bool is_addverts,bool found_diags)4641 static inline bool createOnePtDegenHexElems(
4642   std::vector<MVertex *> &v, GRegion *to, ExtrudeParams *ep, int j, int k,
4643   int dup[], MElement *source, std::vector<int> n1, std::vector<int> n2,
4644   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
4645   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4646     &problems,
4647   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4648     &problems_new,
4649   unsigned int lat_tri_diags_size, bool bnd_elem, bool is_addverts,
4650   bool found_diags)
4651 {
4652   if(!ep) return 0;
4653 
4654   // if no diags, then just make the degenerate hexahedron and be done
4655   if(!found_diags) {
4656     addHexahedron(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], to, source);
4657     Msg::Error("Degenerated hexahedron in extrusion of volume %d", to->tag());
4658     return 1;
4659   }
4660   // test for top and bottom diagonals parallel and incident on degen vertex
4661   else if((n1[4] == dup[0] || n2[4] == dup[0]) &&
4662           (n1[5] == dup[0] + 4 || n2[5] == dup[0] + 4)) {
4663     // first pyramid / tet set
4664     if(n1[(dup[0] + 1) % 4] >= 0) {
4665       if(n1[(dup[0] + 1) % 4] == (dup[0] + 1) % 4) {
4666         addTetrahedron(v[(dup[0] + 1) % 4], v[(dup[0] + 1) % 4 + 4],
4667                        v[(dup[0] + 2) % 4 + 4], v[dup[0]], to, source);
4668         addTetrahedron(v[(dup[0] + 1) % 4], v[(dup[0] + 2) % 4 + 4],
4669                        v[(dup[0] + 2) % 4], v[dup[0]], to, source);
4670       }
4671       else if(n1[(dup[0] + 1) % 4] == (dup[0] + 1) % 4 + 4) {
4672         addTetrahedron(v[(dup[0] + 1) % 4 + 4], v[(dup[0] + 2) % 4],
4673                        v[(dup[0] + 1) % 4], v[dup[0]], to, source);
4674         addTetrahedron(v[(dup[0] + 1) % 4 + 4], v[(dup[0] + 2) % 4 + 4],
4675                        v[(dup[0] + 2) % 4], v[dup[0]], to, source);
4676       }
4677       else
4678         Msg::Error("1: In QuadToTriHexPri(), badly subdivided degenerate "
4679                    "hexahedron. Mesh for region %d has errors.",
4680                    to->tag());
4681     }
4682     else
4683       addPyramid(v[(dup[0] + 1) % 4], v[(dup[0] + 1) % 4 + 4],
4684                  v[(dup[0] + 2) % 4 + 4], v[(dup[0] + 2) % 4], v[dup[0]], to,
4685                  source);
4686     // second pyramid / tet set
4687     if(n1[(dup[0] + 2) % 4] >= 0) {
4688       if(n1[(dup[0] + 2) % 4] == (dup[0] + 2) % 4) {
4689         addTetrahedron(v[(dup[0] + 2) % 4], v[(dup[0] + 2) % 4 + 4],
4690                        v[(dup[0] + 3) % 4 + 4], v[dup[0]], to, source);
4691         addTetrahedron(v[(dup[0] + 2) % 4], v[(dup[0] + 3) % 4 + 4],
4692                        v[(dup[0] + 3) % 4], v[dup[0]], to, source);
4693       }
4694       else if(n1[(dup[0] + 2) % 4] == (dup[0] + 2) % 4 + 4) {
4695         addTetrahedron(v[(dup[0] + 2) % 4 + 4], v[(dup[0] + 3) % 4],
4696                        v[(dup[0] + 2) % 4], v[dup[0]], to, source);
4697         addTetrahedron(v[(dup[0] + 2) % 4 + 4], v[(dup[0] + 3) % 4 + 4],
4698                        v[(dup[0] + 3) % 4], v[dup[0]], to, source);
4699       }
4700       else
4701         Msg::Error("2: In QuadToTriHexPri(), badly subdivided degenerate "
4702                    "hexahedron. Mesh for region %d has errors.",
4703                    to->tag());
4704     }
4705     else
4706       addPyramid(v[(dup[0] + 2) % 4], v[(dup[0] + 2) % 4 + 4],
4707                  v[(dup[0] + 3) % 4 + 4], v[(dup[0] + 3) % 4], v[dup[0]], to,
4708                  source);
4709     return 1;
4710   }
4711 
4712   // test for top and bottom diagonals parallel and NOT on degen vertex
4713   else if((n1[4] == (dup[0] + 1) % 4 || n2[4] == (dup[0] + 1) % 4) &&
4714           (n1[5] == (dup[0] + 1) % 4 + 4 || n2[5] == (dup[0] + 1) % 4 + 4)) {
4715     // See if the prism section has to be divided and if it requires the inner
4716     // surface to be cut
4717 
4718     int tet_top = -1;
4719     int n_inner[2];
4720     n_inner[0] = -1;
4721     n_inner[1] = -2;
4722     if(n1[(dup[0] + 1) % 4] >= 0 &&
4723        n1[(dup[0] + 2) % 4] != n2[(dup[0] + 1) % 4]) {
4724       tet_top = n1[(dup[0] + 1) % 4];
4725       n_inner[0] = n1[(dup[0] + 1) % 4];
4726       int add = n_inner[0] > 3 ? 0 : 4;
4727       n_inner[1] = (dup[0] + 3) % 4 + add;
4728     }
4729     else if(n1[(dup[0] + 2) % 4] >= 0 &&
4730             n1[(dup[0] + 2) % 4] != n2[(dup[0] + 1) % 4]) {
4731       tet_top = n2[(dup[0] + 2) % 4];
4732       n_inner[1] = n2[(dup[0] + 2) % 4];
4733       int add = n_inner[1] > 3 ? 0 : 4;
4734       n_inner[0] = (dup[0] + 1) % 4 + add;
4735     }
4736     else if(n1[(dup[0] + 1) % 4] >= 0)
4737       tet_top = n2[(dup[0] + 1) % 4];
4738 
4739     if(tet_top >= 0) {
4740       int add = tet_top > 3 ? 0 : 4;
4741       addTetrahedron(v[(dup[0] + 1) % 4 + add], v[(dup[0] + 2) % 4 + add],
4742                      v[(dup[0] + 3) % 4 + add], v[tet_top], to, source);
4743       if(n_inner[0] < 0)
4744         addPyramid(v[(dup[0] + 1) % 4], v[(dup[0] + 1) % 4 + 4],
4745                    v[(dup[0] + 3) % 4 + 4], v[(dup[0] + 3) % 4], v[tet_top], to,
4746                    source);
4747       else {
4748         int base = tet_top - 4 + add == (dup[0] + 1) % 4 ? (dup[0] + 2) % 4 :
4749                                                            (dup[0] + 1) % 4;
4750         if(n1[base] < 0)
4751           addPyramid(v[base], v[base + 4], v[(base + 1) % 4 + 4],
4752                      v[(base + 1) % 4], v[tet_top], to, source);
4753         else {
4754           int add_2 = n1[base] > 3 ? -4 : 4;
4755           addTetrahedron(v[n1[base]], v[n1[base] + add_2], v[n2[base]],
4756                          v[tet_top], to, source);
4757           addTetrahedron(v[n1[base]], v[n2[base]], v[n2[base] - add_2],
4758                          v[tet_top], to, source);
4759         }
4760       }
4761     }
4762     else
4763       addPrism(v[(dup[0] + 1) % 4], v[(dup[0] + 2) % 4], v[(dup[0] + 3) % 4],
4764                v[(dup[0] + 1) % 4 + 4], v[(dup[0] + 2) % 4 + 4],
4765                v[(dup[0] + 3) % 4 + 4], to, source);
4766     // add the pyramid or tets that include the degen vertex
4767     if(n_inner[0] < 0)
4768       addPyramid(v[(dup[0] + 1) % 4], v[(dup[0] + 1) % 4 + 4],
4769                  v[(dup[0] + 3) % 4 + 4], v[(dup[0] + 3) % 4], v[dup[0]], to,
4770                  source);
4771     else {
4772       int add = n_inner[0] > 3 ? -4 : 4;
4773       addTetrahedron(v[n_inner[0]], v[n_inner[0] + add], v[n_inner[1]],
4774                      v[dup[0]], to, source);
4775       addTetrahedron(v[n_inner[0]], v[n_inner[1]], v[n_inner[1] - add],
4776                      v[dup[0]], to, source);
4777     }
4778     return 1;
4779   }
4780 
4781   // see if there is a way to divide non-parallel top and bottom verts
4782   else if(n1[(dup[0] + 1) % 4] >= 0 || n1[(dup[0] + 2) % 4] >= 0) {
4783     // parameters for a pyramid (that may or may not be divided into tets)
4784     int base = -1, top = -2;
4785     // if corner opposite degen corner has two diagonals meeting on it:
4786     if(n2[(dup[0] + 1) % 4] >= 0 &&
4787        n1[(dup[0] + 2) % 4] == n2[(dup[0] + 1) % 4]) {
4788       if(n1[4] == n1[(dup[0] + 2) % 4] || n2[4] == n1[(dup[0] + 2) % 4]) {
4789         top = n1[(dup[0] + 2) % 4];
4790         base = 5;
4791       }
4792       else if(n1[5] == n1[(dup[0] + 2) % 4] || n2[5] == n1[(dup[0] + 2) % 4]) {
4793         top = n1[(dup[0] + 2) % 4];
4794         base = 4;
4795       }
4796     }
4797     // if a side corner not opposite the degenerate vertex has two diagonals
4798     // meeting
4799     if(base < 0 && n2[(dup[0] + 2) % 4] >= 0) {
4800       if(n2[(dup[0] + 2) % 4] == (dup[0] + 3) % 4 + 4 &&
4801          (n1[5] == (dup[0] + 3) % 4 + 4 || n2[5] == (dup[0] + 3) % 4 + 4)) {
4802         top = (dup[0] + 3) % 4 + 4;
4803         base = 4;
4804       }
4805       else if(n2[(dup[0] + 2) % 4] == (dup[0] + 3) % 4 &&
4806               (n1[4] == (dup[0] + 3) % 4 || n2[4] == (dup[0] + 3) % 4)) {
4807         top = (dup[0] + 3) % 4;
4808         base = 5;
4809       }
4810     }
4811     if(base < 0 && n1[(dup[0] + 1) % 4] >= 0) {
4812       if(n1[(dup[0] + 1) % 4] == (dup[0] + 1) % 4 + 4 &&
4813          (n1[5] == (dup[0] + 1) % 4 + 4 || n2[5] == (dup[0] + 1) % 4 + 4)) {
4814         top = (dup[0] + 1) % 4 + 4;
4815         base = 4;
4816       }
4817       else if(n1[(dup[0] + 1) % 4] == (dup[0] + 1) % 4 &&
4818               (n1[4] == (dup[0] + 1) % 4 || n2[4] == (dup[0] + 1) % 4)) {
4819         top = (dup[0] + 1) % 4;
4820         base = 5;
4821       }
4822     }
4823 
4824     // if 4-corner lateral faces have diagonals that don't meet...
4825     if(base < 0 && n1[(dup[0] + 1) % 4] >= 0 && n1[(dup[0] + 2) % 4] >= 0 &&
4826        n1[(dup[0] + 2) % 4] != n2[(dup[0] + 1) % 4]) {
4827       top = n1[(dup[0] + 1) % 4];
4828       base = (top < 4) ? 5 : 4;
4829     }
4830 
4831     // if there is a valid top and base, make the element
4832     if(base >= 0 && top >= 0) {
4833       // if pyramid top is NOT opposite degen vertex
4834       if(top == n1[(dup[0] + 1) % 4] || top == n2[(dup[0] + 2) % 4]) {
4835         int add = base == 4 ? 0 : 4;
4836         if(n1[base] < 0) {
4837           addPyramid(v[0 + add], v[1 + add], v[2 + add], v[3 + add], v[top], to,
4838                      source);
4839         }
4840         else {
4841           addTetrahedron(v[n1[base]], v[(n1[base] - add + 1) % 4 + add],
4842                          v[n2[base]], v[top], to, source);
4843           addTetrahedron(v[n1[base]], v[n2[base]],
4844                          v[(n1[base] - add + 3) % 4 + add], v[top], to, source);
4845         }
4846         int base2 = -1;
4847         if(base == 4 && (n1[5] == top || n2[5] == top)) {
4848           base2 =
4849             top == (dup[0] + 1) % 4 + 4 ? (dup[0] + 2) % 4 : (dup[0] + 1) % 4;
4850         }
4851         else if(base == 5 && (n1[4] == top || n2[4] == top)) {
4852           base2 = top == (dup[0] + 1) % 4 ? (dup[0] + 2) % 4 : (dup[0] + 1) % 4;
4853         }
4854         else
4855           base2 = base == 5 ? 4 : 5;
4856 
4857         if(base2 != 4 && base2 != 5) {
4858           addTetrahedron(v[top], v[(top - 4 + add + 2) % 4],
4859                          v[(top - 4 + add + 2) % 4 + 4], v[dup[0]], to, source);
4860           if(n1[base2] >= 0) {
4861             int add_base2 = n1[base2] < 4 ? 4 : -4;
4862             addTetrahedron(v[n1[base2]], v[n1[base2] + add_base2], v[n2[base2]],
4863                            v[top], to, source);
4864             addTetrahedron(v[n1[base2]], v[n2[base2]], v[n2[base2] - add_base2],
4865                            v[top], to, source);
4866           }
4867           else
4868             addPyramid(v[base2], v[(base2 + 4)], v[(base2 + 1) % 4 + 4],
4869                        v[(base2 + 1) % 4], v[top], to, source);
4870         }
4871         else {
4872           int top2 = (top - 4 + add + 2) % 4 + add;
4873           if(n1[base2] >= 0) {
4874             addTetrahedron(v[n1[base2]],
4875                            v[(n1[base2] - 4 + add + 1) % 4 + 4 - add],
4876                            v[n2[base2]], v[top2], to, source);
4877             addTetrahedron(v[n1[base2]],
4878                            v[(n1[base2] - 4 + add + 3) % 4 + 4 - add],
4879                            v[n2[base2]], v[top2], to, source);
4880           }
4881           else
4882             addPyramid(v[0 + 4 - add], v[1 + 4 - add], v[2 + 4 - add],
4883                        v[3 + 4 - add], v[top2], to, source);
4884 
4885           int tet_base = top2 - add == (dup[0] + 1) % 4 ? (dup[0] + 1) % 4 :
4886                                                           (dup[0] + 2) % 4;
4887           if(tet_base == (dup[0] + 1) % 4) {
4888             int add_tet_base = n2[tet_base] > 3 ? -4 : 4;
4889             addTetrahedron(v[n1[tet_base]], v[n2[tet_base]],
4890                            v[n2[tet_base] + add_tet_base], v[top], to, source);
4891           }
4892           else {
4893             int add_tet_base = n1[tet_base] > 3 ? -4 : 4;
4894             addTetrahedron(v[n1[tet_base]], v[n2[tet_base]],
4895                            v[n1[tet_base] + add_tet_base], v[top], to, source);
4896           }
4897         }
4898         return 1;
4899       }
4900 
4901       // if pyramid top is opposite degenerate vertex
4902       else if(top == (dup[0] + 2) % 4 || top == (dup[0] + 2) % 4 + 4) {
4903         int add = base == 4 ? 0 : 4;
4904         if(n1[base] >= 0) {
4905           addTetrahedron(v[n1[base]], v[(n1[base] - add + 1) % 4 + add],
4906                          v[n2[base]], v[top], to, source);
4907           addTetrahedron(v[n1[base]], v[(n1[base] - add + 3) % 4 + add],
4908                          v[n2[base]], v[top], to, source);
4909         }
4910         else
4911           addPyramid(v[0 + add], v[1 + add], v[2 + add], v[3 + add], v[top], to,
4912                      source);
4913 
4914         addTetrahedron(v[dup[0]], v[(dup[0] + 1) % 4], v[(dup[0] + 1) % 4 + 4],
4915                        v[top], to, source);
4916         addTetrahedron(v[dup[0]], v[(dup[0] + 3) % 4], v[(dup[0] + 3) % 4 + 4],
4917                        v[top], to, source);
4918         return 1;
4919       }
4920       else
4921         Msg::Error("3: In createOnePtDegenHexElems(), badly subdivided "
4922                    "degenerate hexahedron. Mesh for region %d has errors.",
4923                    to->tag());
4924     }
4925   }
4926 
4927   return 0;
4928 }
4929 
4930 // Construct the elements that subdivide a full hexahedron extrusion.
createFullHexElems(std::vector<MVertex * > & v,GRegion * to,ExtrudeParams * ep,int j,int k,int dup[],MElement * source,std::vector<int> n1,std::vector<int> n2,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,unsigned int lat_tri_diags_size,bool bnd_elem,bool is_addverts,bool found_diags)4931 static inline bool createFullHexElems(
4932   std::vector<MVertex *> &v, GRegion *to, ExtrudeParams *ep, int j, int k,
4933   int dup[], MElement *source, std::vector<int> n1, std::vector<int> n2,
4934   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
4935   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4936     &problems,
4937   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
4938     &problems_new,
4939   unsigned int lat_tri_diags_size, bool bnd_elem, bool is_addverts,
4940   bool found_diags)
4941 {
4942   if(!ep) return 0;
4943 
4944   // First: does this hexa have ANY dividing diagonals? If no, return
4945   if(!found_diags) {
4946     addHexahedron(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], to, source);
4947     return 1;
4948   }
4949 
4950   // First test: Try to identify a corner with three diagonals converging on it
4951   // This is second because first test gives better quality...i think.
4952 
4953   int pyramid_top = -1, base_face_1 = -1;
4954 
4955   // variables to hold pyramid base corners and diagonal node indices:
4956   /*int b1_diag[2], b2_diag[2], b3_diag[2];
4957   for( int p = 0; p < 2; p++ ){
4958     b1_diag[p] = -1-p; b2_diag[p] = -2-p; b3_diag[p] = -3-p;
4959   }*/
4960 
4961   // find a 3-diag corner
4962   for(int s = 0; s < 2; s++) {
4963     int p = !s ? 4 : 5;
4964     if(n1[p] >= 0) {
4965       int add = !s ? 0 : 4;
4966       int p1 = n1[p] - add, p2 = (n1[p] - add + 3) % 4;
4967       if(n1[p1] >= 0 && n1[p2] >= 0 && (n1[p] == n1[p1] || n1[p] == n2[p1]) &&
4968          (n1[p] == n1[p2] || n1[p] == n2[p2])) {
4969         pyramid_top = n1[p];
4970         base_face_1 = !s ? 5 : 4;
4971         break;
4972       }
4973       p1 = n2[p] - add;
4974       p2 = (n2[p] - add + 3) % 4;
4975       if(n1[p1] >= 0 && n1[p2] >= 0 && (n2[p] == n1[p1] || n2[p] == n2[p1]) &&
4976          (n2[p] == n1[p2] || n2[p] == n2[p2])) {
4977         pyramid_top = n2[p];
4978         base_face_1 = !s ? 5 : 4;
4979         break;
4980       }
4981     }
4982   }
4983 
4984   // If pyramid top (3-diag corner) is found, then check for diagonal division
4985   // of bases:
4986 
4987   if(pyramid_top >= 0) {
4988     // ( base of first pyramid always the hexa's top or bottom )
4989     int add = pyramid_top < 4 ? 0 : 4;
4990     int base_face_2 = (pyramid_top - add + 1) % 4;
4991     int base_face_3 = (pyramid_top - add + 2) % 4;
4992 
4993     // Now construct shapes.
4994     for(int p = 0; p < 3; p++) {
4995       int b[4], bn1, bn2;
4996       if(!p) {
4997         int add = base_face_1 == 4 ? 0 : 4;
4998         b[0] = 0 + add;
4999         b[1] = 1 + add;
5000         b[2] = 2 + add;
5001         b[3] = 3 + add;
5002         bn1 = n1[base_face_1];
5003         bn2 = n2[base_face_1];
5004       }
5005       else if(p == 1) {
5006         b[0] = base_face_2;
5007         b[1] = b[0] + 4;
5008         b[2] = (b[0] + 1) % 4 + 4;
5009         b[3] = (b[0] + 1) % 4;
5010         bn1 = n1[base_face_2];
5011         bn2 = n2[base_face_3];
5012       }
5013       else {
5014         b[0] = base_face_3;
5015         b[1] = b[0] + 4;
5016         b[2] = (b[0] + 1) % 4 + 4;
5017         b[3] = (b[0] + 1) % 4;
5018         bn1 = n1[base_face_3];
5019         bn2 = n2[base_face_3];
5020       }
5021 
5022       if(bn1 < 0)
5023         addPyramid(v[b[0]], v[b[1]], v[b[2]], v[b[3]], v[pyramid_top], to,
5024                    source);
5025       else {
5026         if(bn1 == b[0] || bn2 == b[0]) {
5027           addTetrahedron(v[b[0]], v[b[1]], v[b[2]], v[pyramid_top], to, source);
5028           addTetrahedron(v[b[0]], v[b[2]], v[b[3]], v[pyramid_top], to, source);
5029         }
5030         else {
5031           addTetrahedron(v[b[0]], v[b[1]], v[b[3]], v[pyramid_top], to, source);
5032           addTetrahedron(v[b[1]], v[b[2]], v[b[3]], v[pyramid_top], to, source);
5033         }
5034       }
5035     }
5036     // return if successful
5037     return 1;
5038   }
5039 
5040   // Second full hexa division possibility  (two prisms, possibly subdivided):
5041 
5042   // YES, THIS IS HORRIBLE!!!!
5043 
5044   // Diagram of prism-centric coordinates:
5045   /*   ___________  p5
5046       |\         /|\
5047       | \      /  | \
5048       |  \   /    |  \
5049       |   \/______|___\
5050       |  / |      |   /|p2
5051    p3 |/___|___p4_| /  |
5052        \   |      /\   | prism 1,
5053         \  |    /   \  | external face 2 (side)
5054          \ |  /      \ |
5055           \|/_________\|
5056           p0           p1
5057                 prism 1,
5058                 external face 1 (bottom)
5059 
5060        NOTE: for Prism 2, the prism coords MIRROR the coords for
5061              prism 1 about the internal shared face.
5062   */
5063 
5064   // prism_v holds prism-centric indices of vertices--new coords!!!
5065   int prism_v[2][6], prism_face[2][2];
5066   // t_prism arrays for tet verts...p_prism arrays for pyramid verts (if any)
5067   int t_prism[2][3][4], p_prism[2][5];
5068   for(int s = 0; s < 2; s++) {
5069     for(int t = 0; t < 5; t++) p_prism[s][t] = -2 * s - 2;
5070     for(int t = 0; t < 3; t++) {
5071       for(int w = 0; w < 4; w++) t_prism[s][t][w] = -2 * s * t * w - 2;
5072     }
5073   }
5074 
5075   int prism_slice_valid = false; // set to true when found a valid slicing
5076 
5077   // find valid prism slicing
5078   for(int p_ind = 0; p_ind < 3; p_ind++) {
5079     int p = p_ind;
5080     if(p_ind == 2) p = 4; // move to the top-to-bottom slicing
5081 
5082     prism_slice_valid = false;
5083 
5084     // n_div1, n_div2 are indices of the vertice in the first diagonal
5085     int n_div1 = -1, n_div2 = -2;
5086     if(p < 4) {
5087       if((n1[p] == p || n2[p] == p) && (n1[(p + 2) % 4] == (p + 2) % 4 + 4 ||
5088                                         n2[(p + 2) % 4] == (p + 2) % 4 + 4)) {
5089         n_div1 = p;
5090         n_div2 = (p + 1) % 4 + 4;
5091       }
5092       if((n1[p] == p + 4 || n2[p] == p + 4) &&
5093          (n1[(p + 2) % 4] == (p + 2) % 4 || n2[(p + 2) % 4] == (p + 2) % 4)) {
5094         n_div1 = p + 4;
5095         n_div2 = (p + 1) % 4;
5096       }
5097     }
5098     else {
5099       if((n1[4] == 0 || n2[4] == 0) && (n1[5] == 4 || n2[5] == 4)) {
5100         n_div1 = 0;
5101         n_div2 = 2;
5102       }
5103       if((n1[4] == 1 || n2[4] == 1) && (n1[5] == 5 || n2[5] == 5)) {
5104         n_div1 = 1;
5105         n_div2 = 3;
5106       }
5107     }
5108 
5109     if(n_div1 < 0) continue;
5110 
5111     // There are two prisms.  Find the vertices of any external and internal
5112     // prism
5113     //  face diagonals.
5114     int ext_diag[2][2][2], intern_diag[2];
5115     for(int s = 0; s < 2; s++) {
5116       intern_diag[s] = -5 - s * s - s;
5117       for(int t = 0; t < 2; t++) {
5118         ext_diag[s][t][0] = -1 - t * t - t;
5119         ext_diag[s][t][1] = -2 - t * t - t;
5120       }
5121     }
5122 
5123     // Create arrays of verts of both prisms in prism-centric coords (see ascii
5124     // diagram above) to keep sanity. p0 always refereces a vertex position on a
5125     // slicing diagonal (see ascii diagram above again.
5126     int p0;
5127     if((n_div1 > 3 && n_div2 < 4) || (n_div1 < 4 && n_div2 > 3)) {
5128       p0 = n_div1 < 4 ? p : (p + 2) % 4;
5129       prism_v[0][0] = p0;
5130       prism_v[0][1] = (p0 + 1) % 4;
5131       prism_v[0][2] = (p0 + 1) % 4 + 4;
5132       prism_v[0][3] = (p0 + 3) % 4;
5133       prism_v[0][4] = (p0 + 2) % 4;
5134       prism_v[0][5] = (p0 + 2) % 4 + 4;
5135       prism_v[1][0] = p0;
5136       prism_v[1][1] = p0 + 4;
5137       prism_v[1][2] = (p0 + 1) % 4 + 4;
5138       prism_v[1][3] = (p0 + 3) % 4;
5139       prism_v[1][4] = (p0 + 3) % 4 + 4;
5140       prism_v[1][5] = (p0 + 2) % 4 + 4;
5141       prism_face[0][0] = 4;
5142       prism_face[0][1] = (p0 + 1) % 4;
5143       prism_face[1][0] = (p0 + 3) % 4;
5144       prism_face[1][1] = 5;
5145     }
5146     else {
5147       p0 = n_div1;
5148       prism_v[0][0] = p0;
5149       prism_v[0][1] = (p0 + 1) % 4;
5150       prism_v[0][2] = (p0 + 2) % 4;
5151       prism_v[0][3] = p0 + 4;
5152       prism_v[0][4] = (p0 + 1) % 4 + 4;
5153       prism_v[0][5] = (p0 + 2) % 4 + 4;
5154       prism_v[1][0] = p0;
5155       prism_v[1][1] = (p0 + 3) % 4;
5156       prism_v[1][2] = (p0 + 2) % 4;
5157       prism_v[1][3] = p0 + 4;
5158       prism_v[1][4] = (p0 + 3) % 4 + 4;
5159       prism_v[1][5] = (p0 + 2) % 4 + 4;
5160       prism_face[0][0] = p0;
5161       prism_face[0][1] = (p0 + 1) % 4;
5162       prism_face[1][0] = (p0 + 3) % 4;
5163       prism_face[1][1] = (p0 + 2) % 4;
5164     }
5165 
5166     // 3 ways this prism slice can work:
5167     // 1. Two additional diagonals which meet at a vertex.
5168     // 2. Two additional opposing aligned diagonals
5169     // 3. No more diagonals, just two prisms
5170 
5171     // get external diagonals for first and second prism
5172     for(int s = 0; s < 2; s++) {
5173       if(n1[prism_face[s][0]] == prism_v[s][1] ||
5174          n2[prism_face[s][0]] == prism_v[s][1]) {
5175         ext_diag[s][0][0] = 1;
5176         ext_diag[s][0][1] = 3;
5177       }
5178       else if(n1[prism_face[s][0]] == prism_v[s][4] ||
5179               n2[prism_face[s][0]] == prism_v[s][4]) {
5180         ext_diag[s][0][0] = 4;
5181         ext_diag[s][0][1] = 0;
5182       }
5183       if(n1[prism_face[s][1]] == prism_v[s][1] ||
5184          n2[prism_face[s][1]] == prism_v[s][1]) {
5185         ext_diag[s][1][0] = 1;
5186         ext_diag[s][1][1] = 5;
5187       }
5188       else if(n1[prism_face[s][1]] == prism_v[s][4] ||
5189               n2[prism_face[s][1]] == prism_v[s][4]) {
5190         ext_diag[s][1][0] = 4;
5191         ext_diag[s][1][1] = 2;
5192       }
5193     }
5194 
5195     // if first prism needs the internal diagonal
5196     if(ext_diag[0][0][0] >= 0 && ext_diag[0][1][0] != ext_diag[0][0][0]) {
5197       intern_diag[0] = ext_diag[0][0][1];
5198       if(ext_diag[0][0][1] == 0)
5199         intern_diag[1] = 5;
5200       else
5201         intern_diag[1] = 2;
5202     }
5203     else if(ext_diag[0][1][0] >= 0 && ext_diag[0][0][0] != ext_diag[0][1][0]) {
5204       intern_diag[0] = ext_diag[0][1][1];
5205       if(ext_diag[0][1][1] == 2)
5206         intern_diag[1] = 3;
5207       else
5208         intern_diag[1] = 0;
5209     }
5210 
5211     // if 2nd prism needs the internal diagonal to work, check to see if the
5212     // internal diagonal exists and, if so, if it is consistent.  If it doesn't
5213     // exist, make it
5214     if((ext_diag[1][0][0] != ext_diag[1][1][0] ||
5215         (ext_diag[1][0][0] < 0 && ext_diag[1][1][0] < 0)) &&
5216        intern_diag[0] >= 0 && intern_diag[0] != ext_diag[1][0][1] &&
5217        intern_diag[0] != ext_diag[1][1][1] &&
5218        intern_diag[1] != ext_diag[1][0][1] &&
5219        intern_diag[1] != ext_diag[1][1][1]) {
5220       continue;
5221     }
5222     // add internal diagonal if needed
5223     else if(intern_diag[0] < 0 && ext_diag[1][0][0] >= 0 &&
5224             ext_diag[1][1][0] != ext_diag[1][0][0]) {
5225       intern_diag[0] = ext_diag[1][0][1];
5226       if(ext_diag[1][0][1] == 0)
5227         intern_diag[1] = 5;
5228       else
5229         intern_diag[1] = 2;
5230     }
5231     else if(intern_diag[0] < 0 && ext_diag[1][1][0] >= 0 &&
5232             ext_diag[1][0][0] != ext_diag[1][1][0]) {
5233       intern_diag[0] = ext_diag[1][1][1];
5234       if(ext_diag[1][1][1] == 2)
5235         intern_diag[1] = 3;
5236       else
5237         intern_diag[1] = 0;
5238     }
5239 
5240     // this check sees if the internal shared prism face is diagonalized, but
5241     // one prism has no other diags
5242     if(intern_diag[0] >= 0 &&
5243        ((ext_diag[0][0][0] < 0 && ext_diag[0][1][0] < 0) ||
5244         (ext_diag[1][0][0] < 0 && ext_diag[1][1][0] < 0))) {
5245       continue;
5246     }
5247 
5248     // if make it to here, prism slice is valid
5249     prism_slice_valid = true;
5250 
5251     // make arrays of vertices for making the polyhedra
5252     if(prism_slice_valid) {
5253       for(int s = 0; s < 2; s++) {
5254         if(ext_diag[s][0][0] < 0 && ext_diag[s][1][0] < 0)
5255           continue;
5256         else if(ext_diag[s][0][0] >= 0 &&
5257                 ext_diag[s][0][0] == ext_diag[s][1][0]) {
5258           int add = (ext_diag[s][0][0] < 3) ? 3 : -3;
5259           t_prism[s][0][0] = ext_diag[s][0][0];
5260           t_prism[s][0][1] = ext_diag[s][0][1];
5261           t_prism[s][0][2] = ext_diag[s][1][1];
5262           t_prism[s][0][3] = ext_diag[s][0][0] + add;
5263           if(intern_diag[0] < 0) {
5264             p_prism[s][0] = 0;
5265             p_prism[s][1] = 2;
5266             p_prism[s][2] = 5;
5267             p_prism[s][3] = 3;
5268             p_prism[s][4] = ext_diag[s][0][0];
5269           }
5270           else {
5271             int v_tmp1 = (intern_diag[0] == 0 || intern_diag[1] == 0) ? 2 : 0;
5272             int v_tmp2 = (intern_diag[0] == 0 || intern_diag[1] == 0) ? 3 : 5;
5273 
5274             t_prism[s][1][0] = intern_diag[0];
5275             t_prism[s][1][1] = intern_diag[1];
5276             t_prism[s][1][2] = v_tmp1;
5277             t_prism[s][1][3] = ext_diag[s][0][0];
5278             t_prism[s][2][0] = intern_diag[0];
5279             t_prism[s][2][1] = intern_diag[1];
5280             t_prism[s][2][2] = v_tmp2;
5281             t_prism[s][2][3] = ext_diag[s][0][0];
5282           }
5283         }
5284         else if(intern_diag[0] >= 0) {
5285           int p_tet_start =
5286             (ext_diag[s][0][0] >= 0) ? ext_diag[s][0][0] : ext_diag[s][1][0];
5287           int p_pyr_top = (p_tet_start == ext_diag[s][0][0]) ?
5288                             ext_diag[s][0][1] :
5289                             ext_diag[s][1][1];
5290           int p_tet_top;
5291           if(p_tet_start == ext_diag[s][0][0])
5292             p_tet_top = (ext_diag[s][0][1] == 3) ? 0 : 3;
5293           else
5294             p_tet_top = (ext_diag[s][1][1] == 5) ? 2 : 5;
5295 
5296           t_prism[s][0][0] = p_tet_start;
5297           t_prism[s][0][1] = intern_diag[0];
5298           t_prism[s][0][2] = intern_diag[1];
5299           t_prism[s][0][3] = p_tet_top;
5300 
5301           if(p_tet_start == ext_diag[s][0][0]) {
5302             if(ext_diag[s][1][0] < 0) {
5303               p_prism[s][0] = 1;
5304               p_prism[s][1] = 2;
5305               p_prism[s][2] = 5;
5306               p_prism[s][3] = 4;
5307               p_prism[s][4] = p_pyr_top;
5308             }
5309             else {
5310               t_prism[s][1][0] = ext_diag[s][1][0];
5311               t_prism[s][1][1] = ext_diag[s][1][1];
5312               t_prism[s][1][2] = (ext_diag[s][1][0] == 4) ? 1 : 4;
5313               t_prism[s][1][3] = p_pyr_top;
5314               t_prism[s][2][0] = ext_diag[s][1][0];
5315               t_prism[s][2][1] = ext_diag[s][1][1];
5316               t_prism[s][2][2] = (ext_diag[s][1][0] == 4) ? 5 : 2;
5317               t_prism[s][2][3] = p_pyr_top;
5318             }
5319           }
5320           else {
5321             if(ext_diag[s][0][0] < 0) {
5322               p_prism[s][0] = 0;
5323               p_prism[s][1] = 1;
5324               p_prism[s][2] = 4;
5325               p_prism[s][3] = 3;
5326               p_prism[s][4] = p_pyr_top;
5327             }
5328             else {
5329               t_prism[s][1][0] = ext_diag[s][0][0];
5330               t_prism[s][1][1] = ext_diag[s][0][1];
5331               t_prism[s][1][2] = (ext_diag[s][0][0] == 4) ? 3 : 4;
5332               t_prism[s][1][3] = p_pyr_top;
5333               t_prism[s][2][0] = ext_diag[s][0][0];
5334               t_prism[s][2][1] = ext_diag[s][0][1];
5335               t_prism[s][2][2] = (ext_diag[s][0][0] == 4) ? 1 : 0;
5336               t_prism[s][2][3] = p_pyr_top;
5337             }
5338           }
5339         }
5340         // translate arrays to 'real' vertex coordinates
5341         for(int t = 0; t < 3; t++) {
5342           for(int w = 0; w < 4; w++)
5343             t_prism[s][t][w] = (t_prism[s][t][w] >= 0) ?
5344                                  prism_v[s][t_prism[s][t][w]] :
5345                                  t_prism[s][t][w];
5346         }
5347         for(int t = 0; t < 5; t++)
5348           p_prism[s][t] =
5349             (p_prism[s][t] >= 0) ? prism_v[s][p_prism[s][t]] : p_prism[s][t];
5350       }
5351 
5352       // Now construct shapes for prism slice through configuration
5353       for(int s = 0; s < 2; s++) {
5354         if(t_prism[s][0][0] < 0 && p_prism[s][0] < 0) {
5355           addPrism(v[prism_v[s][0]], v[prism_v[s][1]], v[prism_v[s][2]],
5356                    v[prism_v[s][3]], v[prism_v[s][4]], v[prism_v[s][5]], to,
5357                    source);
5358         }
5359         else {
5360           for(int t = 0; t < 3; t++) {
5361             if(t_prism[s][t][0] >= 0)
5362               addTetrahedron(v[t_prism[s][t][0]], v[t_prism[s][t][1]],
5363                              v[t_prism[s][t][2]], v[t_prism[s][t][3]], to,
5364                              source);
5365           }
5366           if(p_prism[s][0] >= 0)
5367             addPyramid(v[p_prism[s][0]], v[p_prism[s][1]], v[p_prism[s][2]],
5368                        v[p_prism[s][3]], v[p_prism[s][4]], to, source);
5369         }
5370       }
5371       // return now
5372       return 1;
5373 
5374     } // end of "if prism_slice_valid" statement
5375   } // end of p_ind loop over opposite pairs of diagonals
5376 
5377   return 0; // if exhaust possibilities, default to this
5378 }
5379 
5380 // Overall function that creates the elements that subdivide any whole element
5381 // extruded from a quadrangle.
QuadToTriHexPri(std::vector<MVertex * > & v,GRegion * to,int j,int k,MElement * source,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems_new,unsigned int lat_tri_diags_size,bool bnd_elem,bool is_addverts,bool diag_search,MVertexRTree & pos)5382 static inline void QuadToTriHexPri(
5383   std::vector<MVertex *> &v, GRegion *to, int j, int k, MElement *source,
5384   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
5385   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
5386     &problems,
5387   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
5388     &problems_new,
5389   unsigned int lat_tri_diags_size, bool bnd_elem, bool is_addverts,
5390   bool diag_search, MVertexRTree &pos)
5391 {
5392   int dup[4];
5393   int m = 0;
5394   for(int i = 0; i < 4; i++)
5395     if(v[i] == v[i + 4]) dup[m++] = i;
5396 
5397   bool is_problem = false;
5398 
5399   // is element marked as needing internal vertex?
5400   if(!is_addverts) {
5401     std::pair<unsigned int, unsigned int> jk_pair(j, k);
5402     std::map<MElement *,
5403              std::set<std::pair<unsigned int, unsigned int> > >::iterator
5404       itprob;
5405     itprob = problems.find(source);
5406     if(itprob != problems.end()) {
5407       if((*itprob).second.find(jk_pair) != (*itprob).second.end())
5408         is_problem = true;
5409     }
5410   }
5411 
5412   ExtrudeParams *ep = to->meshAttributes.extrude;
5413 
5414   // variables to hold of each faces's diagonal vertex nodes
5415   bool found_diags = false;
5416   std::vector<int> n1, n2;
5417   n1.assign(6, -3);
5418   n2.assign(6, -4);
5419   if(diag_search) {
5420     for(int p = 0; p < 6; p++) {
5421       n1[p] = -p * p - p - 1;
5422       n2[p] = -p * p - p - 2; // unique negative numbers
5423       if(p < 4) {
5424         if(edgeExists(v[p], v[(p + 1) % 4 + 4], quadToTri_edges)) {
5425           n1[p] = p;
5426           n2[p] = (p + 1) % 4 + 4;
5427           found_diags = true;
5428         }
5429         else if(edgeExists(v[(p + 1) % 4], v[p + 4], quadToTri_edges)) {
5430           n1[p] = (p + 4);
5431           n2[p] = (p + 1) % 4;
5432           found_diags = true;
5433         }
5434       }
5435       else {
5436         int add = (p == 4) ? 0 : 4;
5437         if(edgeExists(v[0 + add], v[2 + add], quadToTri_edges)) {
5438           n1[p] = 0 + add;
5439           n2[p] = 2 + add;
5440           found_diags = true;
5441         }
5442         else if(edgeExists(v[1 + add], v[3 + add], quadToTri_edges)) {
5443           n1[p] = 1 + add;
5444           n2[p] = 3 + add;
5445           found_diags = true;
5446         }
5447       }
5448     }
5449   }
5450 
5451   // BAD SHAPE
5452   if(m > 2 || m < 0) {
5453     Msg::Error("In QuadToTriHexPri(), bad number of degenerate corners.");
5454     return;
5455   }
5456 
5457   // Divide by new internal vertex extrusion method?
5458   if(is_addverts && (found_diags || m == 1)) {
5459     MeshWithInternalVertex(to, source, v, n1, n2, pos);
5460     return;
5461   }
5462 
5463   // The of the possibilites are for a 'no new vertex' extrusion
5464 
5465   // PRISM
5466   else if(m == 2 && !is_problem) {
5467     if(createTwoPtDegenHexElems(
5468          v, to, ep, j, k, dup, source, n1, n2, quadToTri_edges, problems,
5469          problems_new, lat_tri_diags_size, bnd_elem, is_addverts, found_diags))
5470       return;
5471   }
5472 
5473   // DEGENERATE HEXAHEDRON
5474   else if(m == 1 && !is_problem) {
5475     if(createOnePtDegenHexElems(
5476          v, to, ep, j, k, dup, source, n1, n2, quadToTri_edges, problems,
5477          problems_new, lat_tri_diags_size, bnd_elem, is_addverts, found_diags))
5478       return;
5479   }
5480 
5481   // FULL HEXAHEDRON
5482   else if(!is_problem) {
5483     if(createFullHexElems(v, to, ep, j, k, dup, source, n1, n2, quadToTri_edges,
5484                           problems, problems_new, lat_tri_diags_size, bnd_elem,
5485                           is_addverts, found_diags))
5486       return;
5487   }
5488 
5489   // now take care of unexpected failure to divide without internal vertex
5490   if(!is_problem) {
5491     Msg::Error(
5492       "In QuadToTriHexPri(), Extruded hexahedron needs subdivision, but cannot "
5493       " be divided without internal vertex, and was not previously detected as "
5494       "such. "
5495       " This is a bug. Please Report.");
5496     Msg::Error("j: %d, k: %d", j, k);
5497     QtMakeCentroidVertex(v, &(to->mesh_vertices), to, pos);
5498     std::pair<unsigned int, unsigned int> jk_pair(j, k);
5499     problems_new[source].insert(jk_pair);
5500     is_problem = true;
5501   }
5502 
5503   // Mesh with internal vertex
5504   if(is_problem) {
5505     MeshWithInternalVertex(to, source, v, n1, n2, pos);
5506     return;
5507   }
5508 }
5509 
5510 // reserves approximately the right amount of memory for quadToTri extrusions
5511 // in the element vectors in the region 'to'
5512 // *** STILL EXPERIMENTAL -- It *kind* of works to limit memory footprint of
5513 // vectors.
5514 /*
5515 static void reserveQuadToTriCapacityForRegion( GRegion *to, GFace *from,  bool
5516 is_addverts, unsigned int num_layers, unsigned int lat_tri_diags_size,
5517 CategorizedSourceElements *c, std::map<MElement*, std::set<std::pair<unsigned
5518 int, unsigned int> > > *problems )
5519 {
5520 
5521   ExtrudeParams *ep = to->meshAttributes.extrude;
5522   if( !ep )
5523     return;
5524 
5525   std::map<MElement*, std::set<std::pair<unsigned int, unsigned int> >
5526 >::iterator itprob; unsigned int num_prob_tri = 0, num_prob_quad = 0; for(
5527 itprob = problems->begin(); itprob != problems->end(); itprob++ ){ if(
5528 itprob->first->getType() == TYPE_TRI ) num_prob_tri += itprob->second.size();
5529     else
5530       num_prob_quad += itprob->second.size();
5531   }
5532   // unsigned int num_bnd_tri = c->three_bnd_pt_tri.size() +
5533 c->other_bnd_tri.size();
5534   // unsigned int num_bnd_quad = c->four_bnd_pt_quad.size() +
5535 c->other_bnd_quad.size();
5536   // unsigned int num_int_tri = c->internal_tri.size();
5537   // unsigned int num_int_quad = c->internal_quad.size();
5538   unsigned int num_tri = from->triangles.size();
5539   unsigned int num_quad = from->quadrangles.size();
5540   // in case !ep->Recombine is ever allowed...
5541   if( !ep->mesh.Recombine )
5542     to->tetrahedra.reserve( num_layers*(3*num_tri + 6*num_quad + 8*num_prob_tri
5543 + 12*num_prob_quad) ); else if( !is_addverts ){
5544     //to->tetrahedra.reserve( (6*num_quad + 3*num_tri +2*lat_tri_diags_size +
5545 8*num_prob_tri + 12*num_prob_quad) ); to->prisms.reserve( num_tri*num_layers );
5546     to->hexahedra.reserve( num_quad*(num_layers-1) );
5547   }
5548   else{
5549     unsigned int extra_verts = to->mesh_vertices.size() -
5550 from->mesh_vertices.size()*(num_layers-1); to->hexahedra.reserve(
5551 num_quad*(num_layers-1) ); to->prisms.reserve( num_tri*num_layers );
5552     to->pyramids.reserve( num_prob_quad + num_prob_tri + extra_verts*4 +
5553 num_quad ); to->tetrahedra.reserve( num_prob_quad + num_prob_tri + extra_verts
5554 );
5555   }
5556 
5557 }
5558 */
5559 
5560 // displays for the user a list of the body centered vertices created for
5561 // problem elements.
listBodyCenteredVertices(GRegion * to,bool is_addverts,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> * problems,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> * problems_new,MVertexRTree * pos)5562 static void listBodyCenteredVertices(
5563   GRegion *to, bool is_addverts,
5564   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
5565     *problems,
5566   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
5567     *problems_new,
5568   MVertexRTree *pos)
5569 {
5570   ExtrudeParams *ep = to->meshAttributes.extrude;
5571 
5572   if(!ep) return;
5573 
5574   if(problems->size() || problems_new->size()) {
5575     std::map<MElement *,
5576              std::set<std::pair<unsigned int, unsigned int> > >::iterator
5577       it_begin;
5578     std::map<MElement *,
5579              std::set<std::pair<unsigned int, unsigned int> > >::iterator
5580       it_end;
5581     std::map<MElement *,
5582              std::set<std::pair<unsigned int, unsigned int> > >::iterator itmap;
5583 
5584     // insert all of problems_new into problems
5585     for(itmap = problems_new->begin(); itmap != problems_new->end(); itmap++)
5586       (*problems)[itmap->first].insert(itmap->second.begin(),
5587                                        itmap->second.end());
5588 
5589     if(is_addverts) {
5590       it_begin = problems_new->begin();
5591       it_end = problems_new->end();
5592     }
5593     else {
5594       it_begin = problems->begin();
5595       it_end = problems->end();
5596     }
5597 
5598     unsigned int int_verts_count = 0;
5599     for(itmap = it_begin; itmap != it_end; itmap++) {
5600       if(itmap->second.size()) int_verts_count += itmap->second.size();
5601     }
5602 
5603     if(int_verts_count) {
5604       if(int_verts_count == 1)
5605         Msg::Warning("QuadToTri meshed %d element in region %d "
5606                      "with a body-centered internal vertex.",
5607                      int_verts_count, to->tag());
5608       else
5609         Msg::Warning("QuadToTri meshed %d elements in region %d "
5610                      "with body-centered internal vertices.",
5611                      int_verts_count, to->tag());
5612       Msg::Warning("( Mesh *should* still conformal, but the user should be "
5613                    "aware of these internal vertices. )");
5614 
5615       unsigned int int_verts_count2 = 0;
5616 
5617       for(itmap = it_begin; itmap != it_end; itmap++) {
5618         if(itmap->second.size()) {
5619           std::set<std::pair<unsigned int, unsigned int> >::iterator itset;
5620           for(itset = itmap->second.begin(); itset != itmap->second.end();
5621               itset++) {
5622             std::vector<MVertex *> verts;
5623             getExtrudedVertices(itmap->first, ep, (*itset).first,
5624                                 (*itset).second, (*pos), verts);
5625             // find centroid
5626             std::vector<double> centroid = QtFindVertsCentroid(verts);
5627             int_verts_count2++;
5628             Msg::Warning("Internal Vertex %d at (x,y,z) = (%g, %g, %g).",
5629                          int_verts_count2, centroid[0], centroid[1],
5630                          centroid[2]);
5631           }
5632         }
5633       }
5634     }
5635   }
5636 }
5637 
5638 // Function that makes all the elements in a QuadToTri region, both
5639 // the divided elements and the whole elements, using already-created
5640 // subdivision edges.
QuadToTriCreateElements(GRegion * to,CategorizedSourceElements & cat_src_elems,std::set<std::pair<MVertex *,MVertex * >> & quadToTri_edges,std::set<std::pair<MVertex *,MVertex * >> & lat_tri_diags,std::map<MElement *,std::set<std::pair<unsigned int,unsigned int>>> & problems,MVertexRTree & pos)5641 bool QuadToTriCreateElements(
5642   GRegion *to, CategorizedSourceElements &cat_src_elems,
5643   std::set<std::pair<MVertex *, MVertex *> > &quadToTri_edges,
5644   std::set<std::pair<MVertex *, MVertex *> > &lat_tri_diags,
5645   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
5646     &problems,
5647   MVertexRTree &pos)
5648 {
5649   ExtrudeParams *ep = to->meshAttributes.extrude;
5650   if(!ep || !ep->mesh.ExtrudeMesh || !ep->mesh.QuadToTri) return false;
5651 
5652   GModel *model = to->model();
5653   GFace *from = model->getFaceByTag(std::abs(ep->geo.Source));
5654   if(!from) return false;
5655 
5656   // set lat_tri_diags_size
5657   unsigned int lat_tri_diags_size = lat_tri_diags.size();
5658 
5659   // number of element layers
5660   unsigned int num_layers = 0;
5661   for(int j = 0; j < ep->mesh.NbLayer; j++)
5662     num_layers += ep->mesh.NbElmLayer[j];
5663 
5664   // Is this a valid 'add internal vertex' extrusion?
5665   bool is_addverts = false;
5666   if(ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1 ||
5667      ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1_RECOMB)
5668     is_addverts = true;
5669 
5670   // Find where top divided layer starts
5671   /*int j_top_start = 0, k_top_start = 0;
5672   if( is_addverts ){  // second from top
5673     if( ep->mesh.NbElmLayer[ep->mesh.NbLayer-1] > 1 ){
5674       j_top_start = ep->mesh.NbLayer-1;
5675       k_top_start = ep->mesh.NbElmLayer[j_top_start]-2;
5676     }
5677     else{
5678       j_top_start = std::max(ep->mesh.NbLayer-2, 0);
5679       k_top_start = ep->mesh.NbElmLayer[j_top_start]-1;
5680     }
5681   }
5682   else{ // first from top
5683     j_top_start = ep->mesh.NbLayer-1;
5684     k_top_start = ep->mesh.NbElmLayer[j_top_start]-1;
5685   }*/
5686 
5687   // for one point bd quads
5688   /*int j_second_from_bottom = ep->mesh.NbLayer-1,
5689       k_second_from_bottom = ep->mesh.NbElmLayer[ep->mesh.NbLayer-1]-1;
5690   if( ep->mesh.NbElmLayer[0] > 1 ){
5691     j_second_from_bottom = 0;
5692     k_second_from_bottom = 1;
5693   }
5694   else if( ep->mesh.NbLayer > 1 ){
5695     j_second_from_bottom = 1;
5696     k_second_from_bottom = 0;
5697   }*/
5698 
5699   // a container for new problem elements (if such new problems are found,
5700   // there's a bug)
5701   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
5702     problems_new;
5703 
5704   // Make the extra vertices needed for Some QuadToTri elements
5705   if(!addBodyCenteredVertices(to, cat_src_elems, quadToTri_edges, problems,
5706                               is_addverts, lat_tri_diags_size, pos)) {
5707     Msg::Error("QuadToTriCreateElements() could not add face or body vertices "
5708                "for QuadToTri region %d.",
5709                to->tag());
5710     return false;
5711   }
5712 
5713   // reserve enough capacity for all possible elements, try to find combination
5714   // of simplicity and memory efficiency.
5715   //  *** EXPERIMENTAL ***
5716   // reserveQuadToTriCapacityForRegion( to, from, is_addverts, num_layers,
5717   // lat_tri_diags_size, &cat_src_elems, &problems );
5718 
5719   // create elements:
5720 
5721   /*  std::vector<MElement*> elem_vec;
5722   elem_vec.reserve(num_layers);
5723   */
5724   // triangles
5725   for(int s = 0; s < 3; s++) {
5726     std::vector<MVertex *> verts;
5727     verts.reserve(3);
5728     bool bnd_elem = s < 2 ? true : false;
5729     std::set<unsigned int> *set_elems;
5730     std::set<unsigned int>::iterator itset;
5731     if(!s)
5732       set_elems = &cat_src_elems.three_bnd_pt_tri;
5733     else if(s == 1)
5734       set_elems = &cat_src_elems.other_bnd_tri;
5735     else
5736       set_elems = &cat_src_elems.internal_tri;
5737     for(itset = set_elems->begin(); itset != set_elems->end(); itset++) {
5738       /* // *** SPEED IMPROVEMENT ***
5739       unsigned int hex, pyr, pri, tet;
5740       hex = to->hexahedra.size();
5741       pyr = to->pyramids.size();
5742       pri = to->prisms.size();
5743       tet = to->tetrahedra.size();
5744       // keeps old allocation
5745       elem_vec.resize(0);
5746       */
5747       MElement *elem = from->triangles[(*itset)];
5748       for(int j = 0; j < ep->mesh.NbLayer; j++) {
5749         for(int k = 0; k < ep->mesh.NbElmLayer[j]; k++) {
5750           // keeps old allocation
5751           verts.resize(0);
5752           if(getExtrudedVertices(elem, ep, j, k, pos, verts) == 6) {
5753             QuadToTriPriPyrTet(verts, to, j, k, elem, quadToTri_edges, problems,
5754                                problems_new, lat_tri_diags_size, bnd_elem,
5755                                is_addverts, 1, pos);
5756           }
5757         }
5758       }
5759       /*// *** SPEED IMPROVEMENT ***
5760       elem_vec.insert(elem_vec.end(), to->hexahedra.begin()+hex,
5761       to->hexahedra.end() ); elem_vec.insert(elem_vec.end(),
5762       to->tetrahedra.begin()+tet, to->tetrahedra.end() );
5763       elem_vec.insert(elem_vec.end(), to->prisms.begin()+pri, to->prisms.end()
5764       ); elem_vec.insert(elem_vec.end(), to->pyramids.begin()+pyr,
5765       to->pyramids.end() );
5766       */
5767     }
5768   }
5769 
5770   if(from->quadrangles.size() && !ep->mesh.Recombine) {
5771     Msg::Error("In QuadToTriCreateElements(), cannot extrude quadrangles "
5772                "without Recombine");
5773     return false;
5774   }
5775   else {
5776     std::vector<MVertex *> verts;
5777     verts.reserve(4);
5778     for(int s = 0; s < 3; s++) {
5779       bool bnd_elem = s < 2 ? true : false;
5780       std::set<unsigned int> *set_elems;
5781       std::set<unsigned int>::iterator itset;
5782       if(!s)
5783         set_elems = &cat_src_elems.four_bnd_pt_quad;
5784       else if(s == 1)
5785         set_elems = &cat_src_elems.other_bnd_quad;
5786       else
5787         set_elems = &cat_src_elems.internal_quad;
5788 
5789       for(itset = set_elems->begin(); itset != set_elems->end(); itset++) {
5790         /*// *** SPEED IMPROVEMENT ***
5791         unsigned int hex, pyr, pri, tet;
5792         hex = to->hexahedra.size();
5793         pyr = to->pyramids.size();
5794         pri = to->prisms.size();
5795         tet = to->tetrahedra.size();
5796 
5797         // keeps old allocation
5798         elem_vec.resize(0);
5799         */
5800         MElement *elem = from->quadrangles[(*itset)];
5801         for(int j = 0; j < ep->mesh.NbLayer; j++) {
5802           for(int k = 0; k < ep->mesh.NbElmLayer[j]; k++) {
5803             // keeps old allocation
5804             verts.resize(0);
5805             if(getExtrudedVertices(elem, ep, j, k, pos, verts) == 8) {
5806               QuadToTriHexPri(verts, to, j, k, elem, quadToTri_edges, problems,
5807                               problems_new, lat_tri_diags_size, bnd_elem,
5808                               is_addverts, 1, pos);
5809             }
5810           }
5811         }
5812         /*// *** SPEED IMPROVEMENT ***
5813         elem_vec.insert(elem_vec.end(), to->hexahedra.begin()+hex,
5814         to->hexahedra.end() ); elem_vec.insert(elem_vec.end(),
5815         to->tetrahedra.begin()+tet, to->tetrahedra.end() );
5816         elem_vec.insert(elem_vec.end(), to->prisms.begin()+pri, to->prisms.end()
5817         ); elem_vec.insert(elem_vec.end(), to->pyramids.begin()+pyr,
5818         to->pyramids.end() );
5819         */
5820       }
5821     }
5822   }
5823 
5824   // List for the user any elements with internal vertices:
5825   listBodyCenteredVertices(to, is_addverts, &problems, &problems_new, &pos);
5826 
5827   // Now revert any elements that have positive  volume.
5828   // Does this even need to be done?
5829   // *** KEEP THIS COMMENTED OUT UNLESS IT IS NEEDED ***
5830   /*for( int i = 0; i < to->tetrahedra.size(); i++ ){
5831     if( to->tetrahedra[i]->getVolumeSign() > 0 )
5832       to->tetrahedra[i]->reverse();
5833 
5834   }
5835   for( int i = 0; i < to->prisms.size(); i++ ){
5836     if( to->prisms[i]->getVolumeSign() > 0 )
5837       to->prisms[i]->reverse();
5838   }
5839   for( int i = 0; i < to->pyramids.size(); i++ ){
5840     if( to->pyramids[i]->getVolumeSign() > 0 )
5841       to->pyramids[i]->reverse();
5842   }
5843   */
5844 
5845   // ***THE FOLLOWING COMMENTED OUT LINES ARE FOR DEBUGGING PURPOSES ONLY AND
5846   // WON'T WORK WITHOUT
5847   //   A SPECIAL INCLUDE FILE.  THESE ARE USELESS WITHOUT THE DEBUG INCLUDE. ***
5848   /*GModel::riter rit;
5849   if( std::abs(to->tag() ) == 4  ){
5850     for( rit = model->firstRegion(); rit != model->lastRegion(); rit++ ){
5851       double total_volume = RegionVolByElems( (*rit) );
5852       Msg::Error( "Region %3d Volume = %14.7f.", (*rit)->tag(), total_volume );
5853     }
5854     for( rit = model->firstRegion(); rit != model->lastRegion(); rit++ ){
5855       unsigned int num_nonconformal = TestRegionConformality( (*rit) );
5856       //      if( num_nonconformal )
5857         Msg::Error( "Region %3d Noncomformal faces = %d.", (*rit)->tag(),
5858   num_nonconformal );
5859     }
5860 
5861   }*/
5862 
5863   return true;
5864 }
5865 
5866 // Mesh QuadToTri region from extrudeMesh() in meshGRegionExtruded.cpp
5867 // Added 04/08/2011:
meshQuadToTriRegion(GRegion * gr,MVertexRTree & pos)5868 int meshQuadToTriRegion(GRegion *gr, MVertexRTree &pos)
5869 {
5870   // Perform some checks to see if this is a valid QuadToTri region.
5871   // If so, a decision has to be made: if this surface is NOT laterally adjacent
5872   // to any subdivided extrusion, then it may be meshed here without worrying
5873   // about a global subdivide operation.
5874   // If the region has a lateral shared with a subdivide region, then it should
5875   // be part of the subdivide operation later...so just let the default methods
5876   // here create the vertices and quit. Otherwise, engage in the meshing here.
5877 
5878   ExtrudeParams *ep = gr->meshAttributes.extrude;
5879 
5880   if(!ep || !ep->mesh.ExtrudeMesh || !ep->mesh.QuadToTri || !ep->mesh.Recombine)
5881     return 0;
5882 
5883   // QuadToTri validity check:
5884   bool validQuadToTriReg = false;
5885   // if any laterals are shared with a subdivided region or an region that
5886   // otherwise should not have it's lateral diags changed,
5887   // IsValidQuadToTriRegion will set following to 'false.'
5888   bool allNonGlobalSharedLaterals = true; // IsValidQuadToTriRegion will set
5889                                           // this properly regardless of initial
5890                                           // value
5891   validQuadToTriReg = IsValidQuadToTriRegion(gr, &allNonGlobalSharedLaterals);
5892 
5893   if(!validQuadToTriReg && ep->mesh.QuadToTri)
5894     Msg::Error("Mesh of QuadToTri region %d likely has errors.", gr->tag());
5895 
5896   if(!allNonGlobalSharedLaterals) {
5897     Msg::Info("Delaying mesh of QuadToTri Region %d until after global "
5898               "subdivide operation....",
5899               gr->tag());
5900     return 0;
5901   }
5902 
5903   // mesh quadToTri even if validQuadToTri is false. Try it anyway!
5904   if(allNonGlobalSharedLaterals) {
5905     std::set<std::pair<MVertex *, MVertex *> > quadToTri_edges;
5906     std::set<std::pair<MVertex *, MVertex *> > lat_tri_diags;
5907     std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
5908       problems;
5909 
5910     // first thing is first
5911     // data structure for boundary status-categorized source elements,
5912     // (member data containers defined in .h file)
5913     CategorizedSourceElements cat_src_elems(gr);
5914     if(!cat_src_elems.valid) {
5915       Msg::Error("In meshQuadToTriRegion(), failed to classify QuadToTri "
5916                  "region %d's source face elements "
5917                  "according to boundary status.",
5918                  gr->tag());
5919       return 0;
5920     }
5921 
5922     if(!QuadToTriEdgeGenerator(gr, cat_src_elems, quadToTri_edges,
5923                                lat_tri_diags, problems, pos)) {
5924       Msg::Error(
5925         "In meshQuadToTriRegion(), failed to create edges for QuadToTri "
5926         "region %d.",
5927         gr->tag());
5928       return 0;
5929     }
5930     if(!QuadToTriCreateElements(gr, cat_src_elems, quadToTri_edges,
5931                                 lat_tri_diags, problems, pos)) {
5932       Msg::Error(
5933         "In meshQuadToTriRegion, failed to create elements for QuadToTri "
5934         "region %d.",
5935         gr->tag());
5936       return 0;
5937     }
5938 
5939     QuadToTriLateralRemesh(gr, quadToTri_edges);
5940 
5941     return 1;
5942   }
5943 
5944   return 0;
5945 }
5946 
5947 // The function that is called from meshGRegionExtruded.cpp to mesh QuadToTri
5948 // regions that are adjacent to subdivided regions, after the global Subdivide
5949 // command is called. Added 04/08/11.
meshQuadToTriRegionAfterGlobalSubdivide(GRegion * gr,std::set<std::pair<MVertex *,MVertex * >> * edges,MVertexRTree & pos)5950 int meshQuadToTriRegionAfterGlobalSubdivide(
5951   GRegion *gr, std::set<std::pair<MVertex *, MVertex *> > *edges,
5952   MVertexRTree &pos)
5953 {
5954   ExtrudeParams *ep = gr->meshAttributes.extrude;
5955 
5956   if(!ep || !ep->mesh.ExtrudeMesh || !ep->mesh.QuadToTri || !ep->mesh.Recombine)
5957     return 0;
5958 
5959   // QuadToTri validity check:
5960   bool validQuadToTriReg = false;
5961   // if any laterals are shared with a subdivided region or any region that
5962   // should not have its lateral diags swapped, IsValidQuadToTriRegion() will
5963   // set following to 'false.'
5964   bool allNonGlobalSharedLaterals = true; // IsValidQuadToTriRegion will set
5965                                           // this properly regardless of initial
5966                                           // value
5967   validQuadToTriReg = IsValidQuadToTriRegion(gr, &allNonGlobalSharedLaterals);
5968 
5969   if(!validQuadToTriReg && ep->mesh.QuadToTri)
5970     Msg::Error("Mesh of QuadToTri region %d likely has errors.", gr->tag());
5971 
5972   // If all lateral edges were non-global, skip. (Region should already be
5973   // meshed properly).
5974   if(allNonGlobalSharedLaterals) return 0;
5975 
5976   Msg::Info("Meshing Region %d (extruded).", gr->tag());
5977 
5978   GFace *gr_src_face = gr->model()->getFaceByTag(std::abs(ep->geo.Source));
5979   if(!gr_src_face) {
5980     Msg::Error("In meshQuadToTriRegionAfterGlobalSubdivide(), no source face "
5981                "for QuadToTri region %d.",
5982                gr->tag());
5983     return 0;
5984   }
5985 
5986   for(unsigned int i = 0; i < gr->hexahedra.size(); i++)
5987     delete gr->hexahedra[i];
5988   gr->hexahedra.clear();
5989   for(unsigned int i = 0; i < gr->prisms.size(); i++) delete gr->prisms[i];
5990   gr->prisms.clear();
5991   for(unsigned int i = 0; i < gr->pyramids.size(); i++) delete gr->pyramids[i];
5992   gr->pyramids.clear();
5993   for(unsigned int i = 0; i < gr->tetrahedra.size(); i++)
5994     delete gr->tetrahedra[i];
5995   gr->tetrahedra.clear();
5996 
5997   std::set<std::pair<MVertex *, MVertex *> > quadToTri_edges;
5998   std::set<std::pair<MVertex *, MVertex *> > lat_tri_diags;
5999   std::map<MElement *, std::set<std::pair<unsigned int, unsigned int> > >
6000     problems;
6001 
6002   // add edges to quadToTri_edges
6003   quadToTri_edges.insert(edges->begin(), edges->end());
6004 
6005   // categorize source face elements
6006   CategorizedSourceElements cat_src_elems(gr);
6007 
6008   if(!cat_src_elems.valid) {
6009     Msg::Error("In meshQuadToTriRegionAfterGlobalSubdivide(), "
6010                "Failed to classify QuadToTri region %d's source face elements "
6011                "according to boundary status.",
6012                gr->tag());
6013     return 0;
6014   }
6015 
6016   // Mesh quadToTri
6017   if(!QuadToTriEdgeGenerator(gr, cat_src_elems, quadToTri_edges, lat_tri_diags,
6018                              problems, pos)) {
6019     Msg::Error("In meshQuadToTriRegionAfterGlobalSubdivide(), edge generation "
6020                "failed for QuadToTri "
6021                "region %d.",
6022                gr->tag());
6023     return 0;
6024   }
6025   if(!QuadToTriCreateElements(gr, cat_src_elems, quadToTri_edges, lat_tri_diags,
6026                               problems, pos)) {
6027     Msg::Error("In meshQuadToTriRegionAfterGlobalSubdivide(), element creation "
6028                "failed for QuadToTri "
6029                "region %d.",
6030                gr->tag());
6031     return 0;
6032   }
6033 
6034   QuadToTriLateralRemesh(gr, quadToTri_edges);
6035 
6036   return 1;
6037 }
6038