Salome HOME
Merge branch 'master' of https://codev-tuleap.cea.fr/plugins/git/salome/medcoupling
[tools/medcoupling.git] / src / INTERP_KERNEL / InterpKernelCellSimplify.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20
21 #include "InterpKernelCellSimplify.hxx"
22 #include "CellModel.hxx"
23
24 #include <algorithm>
25 #include <iterator>
26 #include <sstream>
27 #include <numeric>
28 #include <cstring>
29 #include <limits>
30 #include <vector>
31 #include <list>
32 #include <set>
33
34 using namespace INTERP_KERNEL;
35
36 /*!
37  * This method takes as input a cell with type 'type' and whose connectivity is defined by (conn,lgth)
38  * It retrieves the same cell with a potentially different type (in return) whose connectivity is defined by (retConn,retLgth)
39  * \b WARNING for optimization reason the arrays 'retConn' and 'conn' can overlapped !
40  */
41 INTERP_KERNEL::NormalizedCellType CellSimplify::simplifyDegeneratedCell(INTERP_KERNEL::NormalizedCellType type, const int *conn, int lgth, int *retConn, int& retLgth)
42 {
43   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
44   std::set<int> c(conn,conn+lgth);
45   c.erase(-1);
46   bool isObviousNonDegeneratedCell=((int)c.size()==lgth);
47   if((cm.getDimension()==3 && cm.isQuadratic()) || isObviousNonDegeneratedCell)
48     {//quadratic 3D, do nothing for the moment.
49       retLgth=lgth;
50       int *tmp=new int[lgth];//no direct std::copy ! overlapping of conn and retConn !
51       std::copy(conn,conn+lgth,tmp);
52       std::copy(tmp,tmp+lgth,retConn);
53       delete [] tmp;
54       return type;
55     }
56   if(cm.getDimension()==2)
57     {
58       int *tmp=new int[lgth];
59       int newPos=0;
60       if(!cm.isQuadratic())
61         {
62           for(int i = 0; i < lgth; i++)
63             if(conn[i] != conn[(i+1)%lgth])  // zip nul segments/arcs
64               tmp[newPos++] = conn[i];
65         }
66       else
67         {
68           int quadOff = lgth/2;
69           int *tmpQuad = new int[quadOff];
70           for(int i = 0; i < quadOff; i++)
71             if(conn[i] != conn[(i+1)%quadOff] || conn[i] != conn[i+quadOff])  // zip nul segments/arcs (quad point must match too)
72               {
73               tmp[newPos]=conn[i];
74               tmpQuad[newPos++]=conn[(i+quadOff)%lgth];
75               }
76           // Merge linear and quad points into tmp
77           std::copy(tmpQuad, tmpQuad+newPos, tmp+newPos);
78           delete [] tmpQuad;
79           newPos *= 2; // take in quad points in the final length
80         }
81       INTERP_KERNEL::NormalizedCellType ret=tryToUnPoly2D(cm.isQuadratic(),tmp,newPos,retConn,retLgth);
82       delete [] tmp;
83       return ret;
84     }
85   if(cm.getDimension()==3)
86     {
87       int nbOfFaces,lgthOfPolyhConn;
88       int *zipFullReprOfPolyh=getFullPolyh3DCell(type,conn,lgth,nbOfFaces,lgthOfPolyhConn);
89       INTERP_KERNEL::NormalizedCellType ret=tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,retConn,retLgth);
90       delete [] zipFullReprOfPolyh;
91       return ret;
92     }
93   throw INTERP_KERNEL::Exception("CellSimplify::simplifyDegeneratedCell : works only with 2D and 3D cell !");
94 }
95
96
97 /*!
98  * This static method tries to unpolygonize a cell whose connectivity is given by 'conn' and 'lgth'.
99  * Contrary to INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell method 'conn' and 'retConn' do not overlap. 
100  */
101 INTERP_KERNEL::NormalizedCellType CellSimplify::tryToUnPoly2D(bool isQuad, const int *conn, int lgth, int *retConn, int& retLgth)
102 {
103   retLgth=lgth;
104   std::copy(conn,conn+lgth,retConn);
105   if(!isQuad)
106     {
107       switch(lgth)
108         {
109         case 3:
110           return INTERP_KERNEL::NORM_TRI3;
111         case 4:
112           return INTERP_KERNEL::NORM_QUAD4;
113         default:
114           return INTERP_KERNEL::NORM_POLYGON;
115         }
116     }
117   else
118     {
119       switch(lgth)
120         {
121           case 6:
122             return INTERP_KERNEL::NORM_TRI6;
123           case 8:
124             return INTERP_KERNEL::NORM_QUAD8;
125           default:
126             return INTERP_KERNEL::NORM_QPOLYG;
127         }
128     }
129 }
130
131 /*!
132  * This method takes as input a 3D linear cell and put its representation in returned array. Warning the returned array has to be deallocated.
133  * The length of the returned array is specified by out parameter
134  * The format of output array is the following :
135  * 1,2,3,-1,3,4,2,-1,3,4,1,-1,1,2,4,NORM_TRI3,NORM_TRI3,NORM_TRI3 (faces type at the end of classical polyhedron nodal description)
136  */
137 int *CellSimplify::getFullPolyh3DCell(INTERP_KERNEL::NormalizedCellType type, const int *conn, int lgth,
138                                       int& retNbOfFaces, int& retLgth)
139 {
140   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
141   unsigned nbOfFaces=cm.getNumberOfSons2(conn,lgth);
142   int *tmp=new int[nbOfFaces*(lgth+1)];
143   int *work=tmp;
144   std::vector<int> faces;
145   for(unsigned j=0;j<nbOfFaces;j++)
146     {
147       INTERP_KERNEL::NormalizedCellType type2;
148       unsigned offset=cm.fillSonCellNodalConnectivity2(j,conn,lgth,work,type2);
149       //
150       int *tmp2=new int[offset];
151       tmp2[0]=work[0];
152       int newPos=1;
153       for(unsigned k=1;k<offset;k++)
154         if(std::find(tmp2,tmp2+newPos,work[k])==tmp2+newPos)
155           tmp2[newPos++]=work[k];
156       if(newPos<3)
157         {
158           delete [] tmp2;
159           continue;
160         }
161       int tmp3;
162       faces.push_back(tryToUnPoly2D(CellModel::GetCellModel(type2).isQuadratic(),tmp2,newPos,work,tmp3));
163       delete [] tmp2;
164       //
165       work+=newPos;
166       *work++=-1;
167     }
168   std::copy(faces.begin(),faces.end(),--work);
169   retNbOfFaces=(int)faces.size();
170   retLgth=(int)std::distance(tmp,work);
171   return tmp;
172 }
173
174 /*!
175  * This static method tries to unpolygonize a cell whose connectivity is given by 'conn' (format is the same as specified in
176  * method INTERP_KERNEL::CellSimplify::getFullPolyh3DCell ) and 'lgth'+'nbOfFaces'.
177  * Contrary to INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell method 'conn' and 'retConn' do not overlap. 
178  */
179 INTERP_KERNEL::NormalizedCellType CellSimplify::tryToUnPoly3D(const int *conn, int nbOfFaces, int lgth, int *retConn, int& retLgth)
180 {
181   std::set<int> nodes(conn,conn+lgth);
182   nodes.erase(-1);
183   int nbOfNodes=(int)nodes.size();
184   int magicNumber=100*nbOfNodes+nbOfFaces;
185   switch(magicNumber)
186     {
187     case 806:
188       return tryToUnPolyHex8(conn,nbOfFaces,lgth,retConn,retLgth);
189     case 1208:
190       return tryToUnPolyHexp12(conn,nbOfFaces,lgth,retConn,retLgth);
191     case 605:
192       return tryToUnPolyPenta6(conn,nbOfFaces,lgth,retConn,retLgth);
193     case 505:
194       return tryToUnPolyPyra5(conn,nbOfFaces,lgth,retConn,retLgth);
195     case 404:
196       return tryToUnPolyTetra4(conn,nbOfFaces,lgth,retConn,retLgth);
197     default:
198       retLgth=lgth;
199       std::copy(conn,conn+lgth,retConn);
200       return INTERP_KERNEL::NORM_POLYHED;
201     }
202 }
203
204 bool CellSimplify::orientOppositeFace(const int *baseFace, int *retConn, const int *sideFace, int lgthBaseFace)
205 {
206   std::vector<int> tmp2;
207   std::set<int> bases(baseFace,baseFace+lgthBaseFace);
208   std::set<int> sides(sideFace,sideFace+4);
209   std::set_intersection(bases.begin(),bases.end(),sides.begin(),sides.end(),std::back_insert_iterator< std::vector<int> >(tmp2));
210   if(tmp2.size()!=2)
211     return false;
212   std::vector< std::pair<int,int> > baseEdges(lgthBaseFace);
213   std::vector< std::pair<int,int> > oppEdges(lgthBaseFace);
214   std::vector< std::pair<int,int> > sideEdges(4);
215   for(int i=0;i<lgthBaseFace;i++)
216     {
217       baseEdges[i]=std::pair<int,int>(baseFace[i],baseFace[(i+1)%lgthBaseFace]);
218       oppEdges[i]=std::pair<int,int>(retConn[i],retConn[(i+1)%lgthBaseFace]);
219     }
220   for(int i=0;i<4;i++)
221     sideEdges[i]=std::pair<int,int>(sideFace[i],sideFace[(i+1)%4]);
222   std::vector< std::pair<int,int> > tmp;
223   std::set< std::pair<int,int> > baseEdgesS(baseEdges.begin(),baseEdges.end());
224   std::set< std::pair<int,int> > sideEdgesS(sideEdges.begin(),sideEdges.end());
225   std::set_intersection(baseEdgesS.begin(),baseEdgesS.end(),sideEdgesS.begin(),sideEdgesS.end(),std::back_insert_iterator< std::vector< std::pair<int,int> > >(tmp));
226   if(tmp.empty())
227     {
228       //reverse sideFace
229       for(int i=0;i<4;i++)
230         {
231           std::pair<int,int> p=sideEdges[i];
232           std::pair<int,int> r(p.second,p.first);
233           sideEdges[i]=r;
234         }
235       //end reverse sideFace
236       std::set< std::pair<int,int> > baseEdgesS2(baseEdges.begin(),baseEdges.end());
237       std::set< std::pair<int,int> > sideEdgesS2(sideEdges.begin(),sideEdges.end());
238       std::set_intersection(baseEdgesS2.begin(),baseEdgesS2.end(),sideEdgesS2.begin(),sideEdgesS2.end(),std::back_insert_iterator< std::vector< std::pair<int,int> > >(tmp));
239       if(tmp.empty())
240         return false;
241     }
242   if(tmp.size()!=1)
243     return false;
244   bool found=false;
245   std::pair<int,int> pInOpp;
246   for(int i=0;i<4 && !found;i++)
247     {//finding the pair(edge) in sideFace that do not include any node of tmp[0] edge
248       found=(tmp[0].first!=sideEdges[i].first && tmp[0].first!=sideEdges[i].second &&
249              tmp[0].second!=sideEdges[i].first && tmp[0].second!=sideEdges[i].second);
250       if(found)
251         {//found ! reverse it
252           pInOpp.first=sideEdges[i].second;
253           pInOpp.second=sideEdges[i].first;
254         }
255     }
256   if(!found)
257     return false;
258   int pos=(int)std::distance(baseEdges.begin(),std::find(baseEdges.begin(),baseEdges.end(),tmp[0]));
259   std::vector< std::pair<int,int> >::iterator it=std::find(oppEdges.begin(),oppEdges.end(),pInOpp);
260   if(it==oppEdges.end())//the opposite edge of side face is not found opposite face ... maybe problem of orientation of polyhedron
261     return false;
262   int pos2=(int)std::distance(oppEdges.begin(),it);
263   int offset=pos-pos2;
264   if(offset<0)
265     offset+=lgthBaseFace;
266   //this is the end copy the result
267   int *tmp3=new int[lgthBaseFace];
268   for(int i=0;i<lgthBaseFace;i++)
269     tmp3[(offset+i)%lgthBaseFace]=oppEdges[i].first;
270   std::copy(tmp3,tmp3+lgthBaseFace,retConn);
271   delete [] tmp3;
272   return true;
273 }
274
275 bool CellSimplify::isWellOriented(const int *baseFace, int *retConn, const int *sideFace, int lgthBaseFace)
276 {
277   return true;
278 }
279
280 /*!
281  * This method is trying to permute the connectivity of 'oppFace' face so that the k_th node of 'baseFace' is associated to the 
282  * k_th node in retConnOfOppFace. Excluded faces 'baseFace' and 'oppFace' all the other faces in 'conn' must be QUAD4 faces.
283  * If the arrangement process succeeds true is returned and retConnOfOppFace is filled.
284  */
285 bool CellSimplify::tryToArrangeOppositeFace(const int *conn, int lgth, int lgthBaseFace, const int *baseFace, const int *oppFace, int nbOfFaces, int *retConnOfOppFace)
286 {
287   retConnOfOppFace[0]=oppFace[0];
288   for(int j=1;j<lgthBaseFace;j++)
289     retConnOfOppFace[j]=oppFace[lgthBaseFace-j];
290   const int *curFace=conn;
291   int sideFace=0;
292   bool ret=true;
293   for(int i=0;i<nbOfFaces && ret;i++)
294     {
295       if(curFace!=baseFace && curFace!=oppFace)
296         {
297           if(sideFace==0)
298             ret=orientOppositeFace(baseFace,retConnOfOppFace,curFace,lgthBaseFace);
299           else
300             ret=isWellOriented(baseFace,retConnOfOppFace,curFace,lgthBaseFace);
301           sideFace++;
302         }
303       curFace=std::find(curFace,conn+lgth,-1);
304       curFace++;
305     }
306   return ret;
307 }
308
309 /*!
310  * Cell with 'conn' connectivity has been detected as a good candidate. Full check of this. If yes NORM_HEXA8 is returned.
311  * This method is only callable if in 'conn' there is 8 nodes and 6 faces.
312  * If fails a POLYHED is returned. 
313  */
314 INTERP_KERNEL::NormalizedCellType CellSimplify::tryToUnPolyHex8(const int *conn, int nbOfFaces, int lgth, int *retConn, int& retLgth)
315 {
316   if(std::find_if(conn+lgth,conn+lgth+nbOfFaces,std::bind2nd(std::not_equal_to<int>(),(int)INTERP_KERNEL::NORM_QUAD4))==conn+lgth+nbOfFaces)
317     {//6 faces are QUAD4.
318       int oppositeFace=-1;
319       std::set<int> conn1(conn,conn+4);
320       for(int i=1;i<6 && oppositeFace<0;i++)
321         {
322           std::vector<int> tmp;
323           std::set<int> conn2(conn+5*i,conn+5*i+4);
324           std::set_intersection(conn1.begin(),conn1.end(),conn2.begin(),conn2.end(),std::back_insert_iterator< std::vector<int> >(tmp));
325           if(tmp.empty())
326             oppositeFace=i;
327         }
328       if(oppositeFace>=1)
329         {//oppositeFace of face#0 found.
330           int tmp2[4];
331           if(tryToArrangeOppositeFace(conn,lgth,4,conn,conn+5*oppositeFace,6,tmp2))
332             {
333               std::copy(conn,conn+4,retConn);
334               std::copy(tmp2,tmp2+4,retConn+4);
335               retLgth=8;
336               return INTERP_KERNEL::NORM_HEXA8;
337             }
338         }
339     }
340   retLgth=lgth;
341   std::copy(conn,conn+lgth,retConn);
342   return INTERP_KERNEL::NORM_POLYHED;
343 }
344
345 INTERP_KERNEL::NormalizedCellType CellSimplify::tryToUnPolyHexp12(const int *conn, int nbOfFaces, int lgth, int *retConn, int& retLgth)
346 {
347   std::size_t nbOfHexagon=std::count(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_POLYGON);
348   std::size_t nbOfQuad=std::count(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_QUAD4);
349   if(nbOfQuad==6 && nbOfHexagon==2)
350     {
351       const int *hexag0=std::find(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_POLYGON);
352       std::size_t hexg0Id=std::distance(conn+lgth,hexag0);
353       const int *hexag1=std::find(hexag0+1,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_POLYGON);
354       std::size_t hexg1Id=std::distance(conn+lgth,hexag1);
355       const int *connHexag0=conn+5*hexg0Id;
356       std::size_t lgthH0=std::distance(connHexag0,std::find(connHexag0,conn+lgth,-1));
357       if(lgthH0==6)
358         {
359           const int *connHexag1=conn+5*hexg0Id+7+(hexg1Id-hexg0Id-1)*5;
360           std::size_t lgthH1=std::distance(connHexag1,std::find(connHexag1,conn+lgth,-1));
361           if(lgthH1==6)
362             {
363               std::vector<int> tmp;
364               std::set<int> conn1(connHexag0,connHexag0+6);
365               std::set<int> conn2(connHexag1,connHexag1+6);
366               std::set_intersection(conn1.begin(),conn1.end(),conn2.begin(),conn2.end(),std::back_insert_iterator< std::vector<int> >(tmp));
367               if(tmp.empty())
368                 {
369                   int tmp2[6];
370                   if(tryToArrangeOppositeFace(conn,lgth,6,connHexag0,connHexag1,8,tmp2))
371                     {
372                       std::copy(connHexag0,connHexag0+6,retConn);
373                       std::copy(tmp2,tmp2+6,retConn+6);
374                       retLgth=12;
375                       return INTERP_KERNEL::NORM_HEXGP12;
376                     }
377                 }
378             }
379         }
380     }
381   retLgth=lgth;
382   std::copy(conn,conn+lgth,retConn);
383   return INTERP_KERNEL::NORM_POLYHED;
384 }
385
386 /*!
387  * Cell with 'conn' connectivity has been detected as a good candidate. Full check of this. If yes NORM_PENTA6 is returned.
388  * If fails a POLYHED is returned. 
389  */
390 INTERP_KERNEL::NormalizedCellType CellSimplify::tryToUnPolyPenta6(const int *conn, int nbOfFaces, int lgth, int *retConn, int& retLgth)
391 {
392   std::size_t nbOfTriFace=std::count(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_TRI3);
393   std::size_t nbOfQuadFace=std::count(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_QUAD4);
394   if(nbOfTriFace==2 && nbOfQuadFace==3)
395     {
396       std::size_t tri3_0=std::distance(conn+lgth,std::find(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_TRI3));
397       std::size_t tri3_1=std::distance(conn+lgth,std::find(conn+lgth+tri3_0+1,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_TRI3));
398       const int *tri_0=0,*tri_1=0;
399       const int *w=conn;
400       for(std::size_t i=0;i<5;i++)
401         {
402           if(i==tri3_0)
403             tri_0=w;
404           if(i==tri3_1)
405             tri_1=w;
406           w=std::find(w,conn+lgth,-1);
407           w++;
408         }
409       std::vector<int> tmp;
410       std::set<int> conn1(tri_0,tri_0+3);
411       std::set<int> conn2(tri_1,tri_1+3);
412       std::set_intersection(conn1.begin(),conn1.end(),conn2.begin(),conn2.end(),std::back_insert_iterator< std::vector<int> >(tmp));
413       if(tmp.empty())
414         {
415           int tmp2[3];
416           if(tryToArrangeOppositeFace(conn,lgth,3,tri_0,tri_1,5,tmp2))
417             {
418               std::copy(tri_0,tri_0+3,retConn);
419               std::copy(tmp2,tmp2+3,retConn+3);
420               retLgth=6;
421               return INTERP_KERNEL::NORM_PENTA6;
422             }
423         }
424     }
425   retLgth=lgth;
426   std::copy(conn,conn+lgth,retConn);
427   return INTERP_KERNEL::NORM_POLYHED;
428 }
429
430 /*!
431  * Cell with 'conn' connectivity has been detected as a good candidate. Full check of this. If yes NORM_PYRA5 is returned.
432  * If fails a POLYHED is returned. 
433  */
434 INTERP_KERNEL::NormalizedCellType CellSimplify::tryToUnPolyPyra5(const int *conn, int nbOfFaces, int lgth, int *retConn, int& retLgth)
435 {
436   std::size_t nbOfTriFace=std::count(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_TRI3);
437   std::size_t nbOfQuadFace=std::count(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_QUAD4);
438   if(nbOfTriFace==4 && nbOfQuadFace==1)
439     {
440       std::size_t quad4_pos=std::distance(conn+lgth,std::find(conn+lgth,conn+lgth+nbOfFaces,(int)INTERP_KERNEL::NORM_QUAD4));
441       const int *quad4=0;
442       const int *w=conn;
443       for(std::size_t i=0;i<5 && quad4==0;i++)
444         {
445           if(i==quad4_pos)
446             quad4=w;
447           w=std::find(w,conn+lgth,-1);
448           w++;
449         }
450       std::set<int> quad4S(quad4,quad4+4);
451       w=conn;
452       bool ok=true;
453       int point=-1;
454       for(std::size_t i=0;i<5 && ok;i++)
455         {
456           if(i!=quad4_pos)
457             {
458               std::vector<int> tmp;
459               std::set<int> conn2(w,w+3);
460               std::set_intersection(conn2.begin(),conn2.end(),quad4S.begin(),quad4S.end(),std::back_insert_iterator< std::vector<int> >(tmp));
461               ok=tmp.size()==2;
462               tmp.clear();
463               std::set_difference(conn2.begin(),conn2.end(),quad4S.begin(),quad4S.end(),std::back_insert_iterator< std::vector<int> >(tmp));
464               ok=ok && tmp.size()==1;
465               if(ok)
466                 {
467                   if(point>=0)
468                     ok=point==tmp[0];
469                   else
470                     point=tmp[0];
471                 }
472             }
473           w=std::find(w,conn+lgth,-1);
474           w++;
475         }
476       if(ok && point>=0)
477         {
478           std::copy(quad4,quad4+4,retConn);
479           retConn[4]=point;
480           retLgth=5;
481           return INTERP_KERNEL::NORM_PYRA5;
482         }
483     }
484   retLgth=lgth;
485   std::copy(conn,conn+lgth,retConn);
486   return INTERP_KERNEL::NORM_POLYHED;
487 }
488
489 /*!
490  * Cell with 'conn' connectivity has been detected as a good candidate. Full check of this. If yes NORM_TETRA4 is returned.
491  * If fails a POLYHED is returned. 
492  */
493 INTERP_KERNEL::NormalizedCellType CellSimplify::tryToUnPolyTetra4(const int *conn, int nbOfFaces, int lgth, int *retConn, int& retLgth)
494 {
495   if(std::find_if(conn+lgth,conn+lgth+nbOfFaces,std::bind2nd(std::not_equal_to<int>(),(int)INTERP_KERNEL::NORM_TRI3))==conn+lgth+nbOfFaces)
496     {
497       std::set<int> tribase(conn,conn+3);
498       int point=-1;
499       bool ok=true;
500       for(int i=1;i<4 && ok;i++)
501         {
502           std::vector<int> tmp;
503           std::set<int> conn2(conn+i*4,conn+4*i+3);
504           std::set_intersection(conn2.begin(),conn2.end(),tribase.begin(),tribase.end(),std::back_insert_iterator< std::vector<int> >(tmp));
505           ok=tmp.size()==2;
506           tmp.clear();
507           std::set_difference(conn2.begin(),conn2.end(),tribase.begin(),tribase.end(),std::back_insert_iterator< std::vector<int> >(tmp));
508           ok=ok && tmp.size()==1;
509           if(ok)
510             {
511               if(point>=0)
512                 ok=point==tmp[0];
513               else
514                 point=tmp[0];
515             }
516         }
517       if(ok && point>=0)
518         {
519           std::copy(conn,conn+3,retConn);
520           retConn[3]=point;
521           retLgth=4;
522           return INTERP_KERNEL::NORM_TETRA4;
523         }
524     }
525   retLgth=lgth;
526   std::copy(conn,conn+lgth,retConn);
527   return INTERP_KERNEL::NORM_POLYHED;
528 }
529
530 /*!
531  * Tell whether a cell is exactly flat.
532  * For the moment only handle:
533  *  - fully degenerated polygons (polygon with 1 point, or 2 if quadratic)
534  *  - quad polygon with 2 points and two identical quad points
535  */
536 bool CellSimplify::isFlatCell(const int* conn, int pos, int lgth, NormalizedCellType type)
537 {
538   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
539   if ( lgth <= 2 ) // a polygon with a single, or two points has been returned. This check also captures degenerated quadratics
540     return true;
541   if (cm.isQuadratic() && lgth==4)  // test for flat quadratic polygon with 2 edges ...
542       if (conn[pos+1+lgth/2] == conn[pos+1+lgth/2+1])  // the only 2 quad points are equal
543         return true;
544   return false;
545 }